title EDLIN for MSDOS 2.0 ;-----------------------------------------------------------------------; ; REVISION HISTORY: ; ; ; ; V1.02 ; ; ; ; V2.00 9/13/82 M.A. Ulloa ; ; Modified to use Pathnames in command line file ; ; specification, modified REPLACE to use an empty ; ; string intead of the old replace string when this ; ; is missing, and search and replace now start from ; ; first line of buffer (like old version of EDLIN) ; ; instead than current+1 line. Also added the U and ; ; V commands that search (replace) starting from the ; ; current+1 line. ; ; ; ; 9/15/82 M.A. Ulloa ; ; Added the quote character (^V). ; ; ; ; 9/16/82 M.A. Ulloa ; ; Corrected bug about use of quote char when going ; ; into default insert mode. Also corrected the problem ; ; with ^Z being the end of file marker. End of file is ; ; reached when an attempt to read returns less chars ; ; than requested. ; ; ; ; 9/17/82 M.A. Ulloa ; ; Corrected bug about boundaries for Copy ; ; ; ; 10/4/82 Rev. 1 M.A. Ulloa ; ; The IBM version now does NOT have the U and V ; ; commands. The MSDOS version HAS the U and V commands. ; ; Added the B switch, and modified the effect of ; ; the quote char. ; ; ; ; 10/7/82 Rev. 2 M.A. Ulloa ; ; Changed the S and R commands to start from the ; ; current line+1 (as U and V did). Took away U and V in ; ; all versions. ; ; ; ; 10/13/82 Rev. 3 M.A. Ulloa ; ; Now if parameter1 < 1 then parameter1 = 1 ; ; ; ; 10/15/82 Rev. 4 M.A. Ulloa ; ; Param4 if specified must be an absolute number that ; ; reprecents the count. ; ; ; ; 10/18/82 Rev. 5 M.A. Ulloa ; ; Fixed problem with trying to edit files with the ; ; same name as directories. Also, if the end of file is ; ; reached it checks that a LF is the last character, ; ; otherwise it inserts a CRLF pair at the end. ; ; ; ; 10/20/82 Rev. 6 M.A.Ulloa ; ; Changed the text of some error messages for IBM and ; ; rewrite PAGE. ; ; ; ; 10/25/82 Rev. 7 M.A.Ulloa ; ; Made all messages as in the IBM vers. ; ; ; ; 10/28/82 Rev. 8 M.A.Ulloa ; ; Corrected problem with parsing for options. ; ; ; ; Rev. 9 Aaron Reynolds ; ; Made error messages external. ; ; ; ; 12/08/82 Rev. 10 M.A. Ulloa ; ; Corrected problem arising with having to restore ; ; the old directory in case of a file name error. ; ; ; ; 12/17/82 Rev. 11 M.A. Ulloa ; ; Added the ROPROT equate for R/O file protection. ; ; It causes only certain operations (L,P,S,W,A, and Q) ; ; to be allowed on read only files. ; ; ; ; 12/29/82 Rev. 12 M.A. Ulloa : ; Added the creation error message. ; ; ; ; 4/14/83 Rev. 13 N.Panners ; ; Fixed bug in Merge which lost char if not ^Z. ; ; Fixed bug in Copy to correctly check ; ; for full buffers. ; ; ; ; ; ; 7/23/83 Rev. 14 N.Panners ; ; Split EDLIN into two seperate modules to ; ; allow assembly of sources on an IBM PC ; ; EDLIN and EDLPROC ; ; ; ;-----------------------------------------------------------------------; FALSE EQU 0 TRUE EQU NOT FALSE KANJI EQU FALSE roprot equ true ;set to TRUE if protection to r/o files ; desired. FCB EQU 5CH Comand_Line_Length equ 128 quote_char equ 16h ;quote character = ^V PAGE .xlist INCLUDE DOSSYM.ASM .list SUBTTL Contants and Data areas PAGE PROMPT EQU "*" STKSIZ EQU 80H CODE SEGMENT PUBLIC CODE ENDS CONST SEGMENT PUBLIC WORD CONST ENDS DATA SEGMENT PUBLIC WORD DATA ENDS DG GROUP CODE,CONST,DATA CONST SEGMENT PUBLIC WORD EXTRN BADDRV:BYTE,NDNAME:BYTE,bad_vers_err:BYTE,opt_err:BYTE EXTRN NOBAK:BYTE,BADCOM:BYTE,NEWFIL:BYTE,DEST:BYTE,MRGERR:BYTE EXTRN NODIR:BYTE,DSKFUL:BYTE,MEMFUL:BYTE,FILENM:BYTE EXTRN NOSUCH:BYTE,TOOLNG:BYTE,EOF:BYTE,ro_err:byte,bcreat:byte PUBLIC TXT1,TXT2,FUDGE,USERDIR,HARDCH BAK DB "BAK" make db "***MAUlloa/Microsoft/V20***" rev db "14" if roprot ;***** R/O ***** roflag db 0 ; =1 if file is r/o endif fourth db 0 ;fourth parameter flag loadmod db 0 ;Load mode flag, 0 = ^Z marks the ; end of a file, 1 = viceversa. hardch dd ? the_root db 0 ;root directory flag fudge db 0 ;directory changed flag user_drive db 0 optchar db "-" dirchar db "/",0 userdir db "/",0 db (dirstrlen) dup(0) fname_buffer db Comand_Line_Length dup(0) ;-----------------------------------------------------------------------; TXT1 DB 0,80H DUP (?) TXT2 DB 0,80H DUP (?) DELFLG DB 0 CONST ENDS DATA SEGMENT PUBLIC WORD PUBLIC QFLG,FCB2,OLDLEN,PARAM1,PARAM2,OLDDAT,SRCHFLG PUBLIC COMLINE,NEWLEN,SRCHMOD,CURRENT,LSTFND,NUMPOS PUBLIC LSTNUM,SRCHCNT,POINTER,START,ENDTXT,USER_DRIVE ;-----------------------------------------------------------------------; ; Be carefull when adding parameters, they have to follow the ; order in which they apperar here. (this is a table, ergo it ; is indexed thru a pointer, and random additions will cause the ; wrong item to be accessed). Also param4 is known to be the ; count parameter, and known to be the fourth entry in the table ; so it receives special treatment. (See GETNUM) PARAM1 DW 1 DUP (?) PARAM2 DW 1 DUP (?) PARAM3 DW 1 DUP (?) PARAM4 DW 1 DUP (?) ;-----------------------------------------------------------------------; PTR_1 DW 1 DUP (?) PTR_2 DW 1 DUP (?) PTR_3 DW 1 DUP (?) COPYSIZ DW 1 DUP (?) OLDLEN DW 1 DUP (?) NEWLEN DW 1 DUP (?) LSTFND DW 1 DUP (?) LSTNUM DW 1 DUP (?) NUMPOS DW 1 DUP (?) SRCHCNT DW 1 DUP (?) CURRENT DW 1 DUP (?) POINTER DW 1 DUP (?) ONE4TH DW 1 DUP (?) THREE4TH DW 1 DUP (?) LAST DW 1 DUP (?) ENDTXT DW 1 DUP (?) COMLINE DW 1 DUP (?) LASTLIN DW 1 DUP (?) COMBUF DB 82H DUP (?) EDITBUF DB 258 DUP (?) EOL DB 1 DUP (?) FCB2 DB 37 DUP (?) FCB3 DB 37 DUP (?) fake_fcb db 37 dup (?) ;fake for size figuring QFLG DB 1 DUP (?) HAVEOF DB 1 DUP (?) ENDING DB 1 DUP (?) SRCHFLG DB 1 DUP (?) amnt_req dw 1 dup (?) ;ammount of bytes requested to read olddat db 1 dup (?) ;Used in replace and search, ; replace by old data flag (1=yes) srchmod db 1 dup (?) ;Search mode: 1=from current+1 to ; end of buffer, 0=from beg. of ; buffer to the end (old way). MOVFLG DB 1 DUP (?) DB STKSIZ DUP (?) STACK LABEL BYTE START LABEL WORD DATA ENDS SUBTTL Main Body PAGE CODE SEGMENT PUBLIC ASSUME CS:DG,DS:DG,SS:DG,ES:DG EXTRN QUIT:NEAR,QUERY:NEAR,FNDFIRST:NEAR,FNDNEXT:NEAR EXTRN UNQUOTE:NEAR,LF:NEAR,CRLF:NEAR,OUT:NEAR EXTRN REST_DIR:NEAR,KILL_BL:NEAR,INT_24:NEAR EXTRN FINDLIN:NEAR,SHOWNUM:NEAR,SCANLN:NEAR if Kanji EXTRN TESTKANJ:NEAR endif PUBLIC CHKRANGE ORG 100H EDLIN: JMP SIMPED edl_pad db 0e00h dup (?) HEADER DB "Vers 2.14" NONAME: MOV DX,OFFSET DG:NDNAME ERRJ: JMP xERROR SIMPED: MOV BYTE PTR [ENDING],0 MOV SP,OFFSET DG:STACK ;Code to print header ; PUSH AX ; MOV DX,OFFSET DG:HEADER ; MOV AH,STD_CON_STRING_OUTPUT ; INT 21H ; POP AX ;----- Check Version Number --------------------------------------------; push ax mov ah,Get_Version int 21h cmp al,2 jae vers_ok ; version >= 2, enter editor mov dx,offset dg:bad_vers_err jmp short errj ;-----------------------------------------------------------------------; vers_ok: ;----- Process Pathnames -----------------------------------------------; mov ax,(char_oper shl 8) ;get switch character int 21h cmp dl,"/" jnz slashok ;if not / , then not PC mov [dirchar],"\" ;in PC, dir separator = \ mov [userdir],"\" mov [optchar],"/" ;in PC, option char = / slashok: mov si,81h ;point to cammand line call kill_bl cmp al,13 ;A carriage return? je noname ;yes, file name missing mov di,offset dg:fname_buffer xor cx,cx ;zero pathname length next_char: stosb ;put patname in buffer inc cx lodsb cmp al,' ' je xx1 cmp al,13 ; a CR ? je name_copied cmp al,[optchar] ; an option character? je an_option jmp short next_char xx1: dec si call kill_bl cmp al,[optchar] jne name_copied an_option: lodsb ;get the option cmp al,'B' je b_opt cmp al,'b' je b_opt mov dx,offset dg:opt_err ;bad option specified jmp xerror b_opt: mov [loadmod],1 name_copied: mov byte ptr dg:[di],0 ;nul terminate the pathname if roprot ;***** R/O ***** ;----- Check that file is not R/O --------------------------------------; push cx ;save character count mov dx,offset dg:fname_buffer mov al,0 ;get attributes mov ah,chmod int 21h jc attr_are_ok and cl,00000001b ;mask all but: r/o jz attr_are_ok ;if all = 0 then file ok to edit, mov dg:[roflag],01h ;otherwise: Error (GONG!!!) attr_are_ok: pop cx ;restore character count endif ;----- Scan for directory ----------------------------------------------; dec di ;adjust to the end of the pathname IF KANJI mov dx,offset dg: fname_buffer PUSH DX PUSH DI MOV BX,DI MOV DI,DX DELLOOP: CMP DI,BX Jae GOTDELE MOV AL,[DI] INC DI CALL TESTKANJ JZ NOTKANJ11 INC DI JMP DELLOOP NOTKANJ11: cmp al,dg:[dirchar] JNZ DELLOOP MOV DX,DI ;Point to char after '/' DEC DX DEC DX ;Point to char before '/' JMP DELLOOP GOTDELE: MOV DI,DX POP AX ;Initial DI POP DX SUB AX,DI ;Distance moved SUB CX,AX ;Set correct CX CMP DX,DI JB sj1 ;Found a pathsep JA sj2 ;Started with a pathsep, root MOV AX,[DI] CALL TESTKANJ JNZ same_dirj XCHG AH,AL cmp al,dg:[dirchar] jz sj1 ;One character directory same_dirj: ELSE mov al,dg:[dirchar] ;get directory separator character std ;scan backwards repnz scasb ;(cx has the pathname length) cld ;reset direction, just in case jz sj1 ENDIF jmp same_dir ;no dir separator char. found, the ; file is in the current directory ; of the corresponding drive. Ergo, ; the FCB contains the data already. sj1: jcxz sj2 ;no more chars left, it refers to root cmp byte ptr [di],':' ;is the prvious character a disk def? jne not_root sj2: mov dg:[the_root],01h ;file is in the root not_root: inc di ;point to dir separator char. mov al,0 stosb ;nul terminate directory name pop ax push di ;save pointer to file name mov dg:[fudge],01h ;remember that the current directory ; has been changed. ;----- Save current directory for exit ---------------------------------; mov ah,get_default_drive ;save current drive int 21h mov dg:[user_drive],al mov dl,byte ptr ds:[fcb] ;get specified drive if any or dl,dl ;default disk? jz same_drive dec dl ;adjust to real drive (a=0,b=1,...) mov ah,set_default_drive ;change disks int 21h cmp al,-1 ;error? jne same_drive mov dx,offset dg:baddrv jmp xerror same_drive: mov ah,get_default_dpb int 21h assume ds:nothing cmp al,-1 ;bad drive? (should always be ok) jne drvisok mov dx,offset dg:baddrv jmp xerror drvisok: cmp [bx.dpb_current_dir],0 je curr_is_root mov si,bx add si,dpb_dir_text mov di,offset dg:userdir + 1 dir_save_loop: lodsb stosb or al,al jnz dir_save_loop curr_is_root: push cs pop ds assume ds:dg ;----- Change directories ----------------------------------------------; cmp [the_root],01h mov dx,offset dg:[dirchar] ;assume the root je sj3 mov dx,offset dg:[fname_buffer] sj3: mov ah,chdir ;change directory int 21h mov dx,offset dg:baddrv jnc no_errors jmp xerror no_errors: ;----- Set Up int 24 intercept -----------------------------------------; mov ax,(get_interrupt_vector shl 8) or 24h int 21h mov word ptr [hardch],bx mov word ptr [hardch+2],es mov ax,(set_interrupt_vector shl 8) or 24h mov dx,offset dg:int_24 int 21h push cs pop es ;----- Parse filename to FCB -------------------------------------------; pop si mov di,fcb mov ax,(parse_file_descriptor shl 8) or 1 int 21h push ax ;-----------------------------------------------------------------------; same_dir: pop ax OR AL,AL MOV DX,OFFSET DG:BADDRV jz sj4 jmp xerror sj4: CMP BYTE PTR DS:[FCB+1]," " jnz sj5 jmp noname sj5: MOV SI,OFFSET DG:BAK MOV DI,FCB+9 MOV CX,3 ;File must not have .BAK extension REPE CMPSB JZ NOTBAK ;Open input file MOV AH,FCB_OPEN MOV DX,FCB INT 21H MOV [HAVEOF],AL OR AL,AL JZ HAVFIL ;----- Check that file is not a directory ------------ mov ah,fcb_create mov dx,fcb int 21h or al,al jz sj50 ;no error found mov dx,offset dg:bcreat ;creation error jmp xerror sj50: mov ah,fcb_close ;no error, close the file mov dx,fcb int 21h mov ah,fcb_delete ;delete the file mov dx,fcb int 21h ;----------------------------------------------------- MOV DX,OFFSET DG:NEWFIL MOV AH,STD_CON_STRING_OUTPUT INT 21H HAVFIL: MOV SI,FCB MOV DI,OFFSET DG:FCB2 MOV CX,9 REP MOVSB MOV AL,"$" STOSB STOSB STOSB MAKFIL: ;Create .$$$ file to make sure directory has room MOV DX,OFFSET DG:FCB2 MOV AH,FCB_CREATE INT 21H OR AL,AL JZ SETUP CMP BYTE PTR [DELFLG],0 JNZ NOROOM CALL DELBAK JMP MAKFIL NOROOM: MOV DX,OFFSET DG:NODIR JMP xERROR NOTBAK: MOV DX,OFFSET DG:NOBAK JMP xERROR SETUP: XOR AX,AX MOV WORD PTR DS:[FCB+fcb_RR],AX ;Set RR field to zero MOV WORD PTR DS:[FCB+fcb_RR+2],AX MOV WORD PTR [FCB2+fcb_RR],AX MOV WORD PTR [FCB2+fcb_RR+2],AX INC AX MOV WORD PTR DS:[FCB+fcb_RECSIZ],AX ;Set record length to 1 MOV WORD PTR [FCB2+fcb_RECSIZ],AX MOV DX,OFFSET DG:START MOV DI,DX MOV AH,SET_DMA INT 21H MOV CX,DS:[6] DEC CX MOV [LAST],CX TEST BYTE PTR [HAVEOF],-1 JNZ SAVEND SUB CX,OFFSET DG:START ;Available memory SHR CX,1 ;1/2 of available memory MOV AX,CX SHR CX,1 ;1/4 of available memory MOV [ONE4TH],CX ;Save amount of 1/4 full ADD CX,AX ;3/4 of available memory MOV DX,CX ADD DX,OFFSET DG:START MOV [THREE4TH],DX ;Save pointer to 3/4 full ;Read in input file MOV DX,FCB MOV AH,FCB_RANDOM_READ_BLOCK mov [amnt_req],cx ;save ammount of chars requested INT 21H CALL SCANEOF ADD DI,CX ;Point to last byte SAVEND: CLD MOV BYTE PTR [DI],1AH MOV [ENDTXT],DI MOV BYTE PTR [COMBUF],128 MOV BYTE PTR [EDITBUF],255 MOV BYTE PTR [EOL],10 MOV [POINTER],OFFSET DG:START MOV [CURRENT],1 MOV [PARAM1],1 TEST BYTE PTR [HAVEOF],-1 JNZ COMMAND CALL APPEND COMMAND: MOV SP, OFFSET DG:STACK MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H MOV DX,OFFSET DG:ABORTCOM INT 21H MOV AL,PROMPT CALL OUT MOV DX,OFFSET DG:COMBUF MOV AH,STD_CON_STRING_INPUT INT 21H MOV [COMLINE],OFFSET DG:COMBUF + 2 MOV AL,10 CALL OUT PARSE: MOV [PARAM2],0 MOV [PARAM3],0 MOV [PARAM4],0 mov [fourth],0 ;reset the fourth parameter flag MOV BYTE PTR [QFLG],0 MOV SI,[COMLINE] MOV BP,OFFSET DG:PARAM1 XOR DI,DI CHKLP: CALL GETNUM MOV [BP+DI],DX INC DI INC DI CALL SKIP1 CMP AL,"," JNZ CHKNXT INC SI CHKNXT: DEC SI CMP DI,8 JB CHKLP CALL SKIP CMP AL,"?" JNZ DISPATCH MOV [QFLG],AL CALL SKIP DISPATCH: CMP AL,5FH JBE UPCASE AND AL,5FH UPCASE: MOV DI,OFFSET DG:COMTAB MOV CX,NUMCOM REPNE SCASB JNZ COMERR MOV BX,CX MOV AX,[PARAM2] OR AX,AX JZ PARMOK CMP AX,[PARAM1] JB COMERR ;Param. 2 must be >= param 1 PARMOK: MOV [COMLINE],SI if roprot ;***** R/O ***** cmp [roflag],01 ;file r/o? jne paramok2 cmp byte ptr [bx+rotable],01 ;operation allowed? je paramok2 mov dx,offset dg:ro_err ;error jmp short comerr1 paramok2: endif SHL BX,1 CALL [BX+TABLE] COMOVER: MOV SI,[COMLINE] CALL SKIP CMP AL,0DH JZ COMMANDJ CMP AL,1AH JZ DELIM CMP AL,";" JNZ NODELIM DELIM: INC SI NODELIM: DEC SI MOV [COMLINE],SI JMP PARSE COMMANDJ: JMP COMMAND SKIP: LODSB SKIP1: CMP AL," " JZ SKIP RET1: RET CHKRANGE: CMP [PARAM2],0 JZ RET1 CMP BX,[PARAM2] JBE RET1 COMERR: MOV DX,OFFSET DG:BADCOM COMERR1: MOV AH,STD_CON_STRING_OUTPUT INT 21H JMP COMMAND GETNUM: CALL SKIP cmp di,6 ;Is this the fourth parameter? jne sk1 mov [fourth],1 ;yes, set the flag sk1: CMP AL,"." JZ CURLIN CMP AL,"#" JZ MAXLIN CMP AL,"+" JZ FORLIN CMP AL,"-" JZ BACKLIN MOV DX,0 MOV CL,0 ;Flag no parameter seen yet NUMLP: CMP AL,"0" JB NUMCHK CMP AL,"9" JA NUMCHK CMP DX,6553 ;Max line/10 JAE COMERR ;Ten times this is too big MOV CL,1 ;Parameter digit has been found SUB AL,"0" MOV BX,DX SHL DX,1 SHL DX,1 ADD DX,BX SHL DX,1 CBW ADD DX,AX LODSB JMP SHORT NUMLP NUMCHK: CMP CL,0 JZ RET1 OR DX,DX JZ COMERR ;Don't allow zero as a parameter RET CURLIN: cmp [fourth],1 ;the fourth parameter? je comerra ;yes, an error MOV DX,[CURRENT] LODSB RET MAXLIN: cmp [fourth],1 ;the fourth parameter? je comerra ;yes, an error MOV DX,-2 LODSB RET FORLIN: cmp [fourth],1 ;the fourth parameter? je comerra ;yes, an error CALL GETNUM ADD DX,[CURRENT] RET BACKLIN: cmp [fourth],1 ;the fourth parameter? je comerra ;yes, an error CALL GETNUM MOV BX,[CURRENT] SUB BX,DX jns sk2 ;if below beg of buffer then default to the mov bx,1 ; beg of buffer (line1) sk2: MOV DX,BX RET comerra: jmp comerr COMTAB DB "QTCMWASRDLPIE;",13 NUMCOM EQU $-COMTAB ;-----------------------------------------------------------------------; ; Carefull changing the order of the next two tables. They are ; linked and chnges should be be to both. TABLE DW NOCOM ;No command--edit line DW NOCOM DW ENDED DW INSERT DW PAGE DW LIST DW DELETE dw replac_from_curr ;replace from current+1 line dw search_from_curr ;search from current+1 line DW APPEND DW EWRITE DW MOVE DW COPY DW MERGE if roprot ;***** R/O ***** DW QUIT1 else DW QUIT endif if roprot ;***** R/O ***** ;-----------------------------------------------------------------------; ; If = 1 then the command can be executed with a file that ; is r/o. If = 0 the command can not be executed, and error. ROTABLE db 0 ;NOCOM db 0 ;NOCOM db 0 ;ENDED db 0 ;INSERT db 1 ;PAGE db 1 ;LIST db 0 ;DELETE db 0 ;replac_from_curr db 1 ;search_from_curr db 1 ;APPEND db 1 ;EWRITE db 0 ;MOVE db 0 ;COPY db 0 ;MERGE db 1 ;QUIT ;-----------------------------------------------------------------------; endif if roprot ;***** R/O ***** quit1: cmp [roflag],01 ;are we in r/o mode? jne q3 ;no query.... MOV DX,OFFSET DG:FCB2 ;yes, quit without query. MOV AH,FCB_CLOSE INT 21H MOV AH,FCB_DELETE INT 21H call rest_dir ;restore directory if needed INT 20H q3: call quit endif SCANEOF: cmp [loadmod],0 je sj52 ;----- Load till physical end of file cmp cx,word ptr[amnt_req] jb sj51 xor al,al inc al ;reset zero flag ret sj51: jcxz sj51b push di ;get rid of any ^Z at the end of the file add di,cx dec di ;points to last char cmp byte ptr [di],1ah pop di jne sj51b dec cx sj51b: xor al,al ;set zero flag call check_end ;check that we have a CRLF pair at the end ret ;----- Load till first ^Z is found sj52: PUSH DI PUSH CX MOV AL,1AH or cx,cx jz not_found ;skip with zero flag set REPNE SCASB ;Scan for end of file mark jnz not_found LAHF ;Save flags momentarily inc cx ;include the ^Z SAHF ;Restore flags not_found: mov di,cx ;not found at the end POP CX LAHF ;Save flags momentarily SUB CX,DI ;Reduce byte count if EOF found SAHF ;Restore flags POP DI call check_end ;check that we have a CRLF pair at the end RET2: RET ;----------------------------------------------------------------------- ; If the end of file was found, then check that the last character ; in the file is a LF. If not put a CRLF pair in. check_end: jnz not_end ;end was not reached pushf ;save return flag push di ;save pointer to buffer add di,cx ;points to one past end on text dec di ;points to last character cmp di,offset dg:start je check_no cmp byte ptr[di],0ah ;is a LF the last character? je check_done ;yes, exit check_no: mov byte ptr[di+1],0dh ;no, put a CR inc cx ;one more char in text mov byte ptr[di+2],0ah ;put a LF inc cx ;another character at the end check_done: pop di popf not_end: ret NOMOREJ:JMP NOMORE APPEND: TEST BYTE PTR [HAVEOF],-1 JNZ NOMOREJ MOV DX,[ENDTXT] CMP [PARAM1],0 ;See if parameter is missing JNZ PARMAPP CMP DX,[THREE4TH] ;See if already 3/4ths full JAE RET2 ;If so, then done already PARMAPP: MOV DI,DX MOV AH,SET_DMA INT 21H MOV CX,[LAST] SUB CX,DX ;Amount of memory available jnz sj53 jmp memerr sj53: MOV DX,FCB mov [amnt_req],cx ;save ammount of chars requested MOV AH,FCB_RANDOM_READ_BLOCK INT 21H ;Fill memory with file data MOV [HAVEOF],AL PUSH CX ;Save actual byte count CALL SCANEOF JNZ NOTEND MOV BYTE PTR [HAVEOF],1 ;Set flag if 1AH found in file NOTEND: XOR DX,DX MOV BX,[PARAM1] OR BX,BX JNZ COUNTLN MOV AX,DI ADD AX,CX ;First byte after loaded text CMP AX,[THREE4TH] ;See if we made 3/4 full JBE COUNTLN MOV DI,[THREE4TH] MOV CX,AX SUB CX,DI ;Length remaining over 3/4 MOV BX,1 ;Look for one more line COUNTLN: CALL SCANLN ;Look for BX lines CMP [DI-1],AL ;Check for full line JZ FULLN STD DEC DI MOV CX,[LAST] REPNE SCASB ;Scan backwards for last line INC DI INC DI DEC DX CLD FULLN: POP CX ;Actual amount read MOV WORD PTR [DI],1AH ;Place EOF after last line SUB CX,DI XCHG DI,[ENDTXT] ADD DI,CX ;Amount of file read but not used SUB WORD PTR DS:[FCB+fcb_RR],DI ;Adjust RR field in case end of file SBB WORD PTR DS:[FCB+fcb_RR+2],0 ; was not reached CMP BX,DX JNZ EOFCHK MOV BYTE PTR [HAVEOF],0 RET NOMORE: MOV DX,OFFSET DG:EOF MOV AH,STD_CON_STRING_OUTPUT INT 21H RET3: RET EOFCHK: TEST BYTE PTR [HAVEOF],-1 JNZ NOMORE TEST BYTE PTR [ENDING],-1 JNZ RET3 ;Suppress memory error during End JMP MEMERR EWRITE: MOV BX,[PARAM1] OR BX,BX JNZ WRT MOV CX,[ONE4TH] MOV DI,[ENDTXT] SUB DI,CX ;Write everything in front of here JBE RET3 CMP DI,OFFSET DG:START ;See if there's anything to write JBE RET3 XOR DX,DX MOV BX,1 ;Look for one more line CALL SCANLN JMP SHORT WRTADD WRT: INC BX CALL FINDLIN WRTADD: CMP BYTE PTR [DELFLG],0 JNZ WRTADD1 PUSH DI CALL DELBAK ;Want to delete the .BAK file ;as soon as the first write occurs POP DI WRTADD1: MOV CX,DI MOV DX,OFFSET DG:START SUB CX,DX ;Amount to write JZ RET3 MOV AH,SET_DMA INT 21H MOV DX,OFFSET DG:FCB2 MOV AH,FCB_RANDOM_WRITE_BLOCK INT 21H OR AL,AL JNZ WRTERR MOV SI,DI MOV DI,OFFSET DG:START MOV [POINTER],DI MOV CX,[ENDTXT] SUB CX,SI INC CX ;Amount of text remaining REP MOVSB DEC DI ;Point to EOF MOV [ENDTXT],DI MOV [CURRENT],1 RET WRTERR: MOV AH,FCB_CLOSE INT 21H MOV DX,OFFSET DG:DSKFUL xERROR: MOV AH,STD_CON_STRING_OUTPUT INT 21H ;----------------------------------------------------------------------- call rest_dir ;restore to the proper directory ;----------------------------------------------------------------------- INT 32 RET$5: RET PAGE: xor bx,bx ;get last line in the buffer call findlin mov [lastlin],dx mov bx,[param1] or bx,bx ;was it specified? jnz frstok ;yes, use it mov bx,[current] cmp bx,1 ;if current line =1 start from there je frstok inc bx ;start from current+1 line frstok: cmp bx,[lastlin] ;check that we are in the buffer ja ret$5 ;if not just quit infile: mov dx,[param2] or dx,dx ;was param2 specified? jnz scndok ;yes,.... mov dx,bx ;no, take the end line to be the add dx,22 ; start line + 23 scndok: inc dx cmp dx,[lastlin] ;check that we are in the buffer jbe infile2 mov dx,[lastlin] ;we are not, take the last line as end infile2: cmp dx,bx ;is param1 < param2 ? jbe ret$5 ;yes, no backwards listing, quit push dx ;save the end line push bx ;save start line mov bx,dx ;set the current line dec bx call findlin mov [pointer],di mov [current],dx pop bx ;restore start line call findlin ;get pointer to start line mov si,di ;save pointer pop di ;get end line sub di,bx ;number of lines jmp short display LIST: MOV BX,[PARAM1] OR BX,BX JNZ CHKP2 MOV BX,[CURRENT] SUB BX,11 JA CHKP2 MOV BX,1 CHKP2: CALL FINDLIN JNZ RET7 MOV SI,DI MOV DI,[PARAM2] INC DI SUB DI,BX JA DISPLAY MOV DI,23 JMP SHORT DISPLAY DISPONE: MOV DI,1 DISPLAY: ; Inputs: ; BX = Line number ; SI = Pointer to text buffer ; DI = No. of lines ; Function: ; Ouputs specified no. of line to terminal, each ; with leading line number. ; Outputs: ; BX = Last line output. ; All registers destroyed. MOV CX,[ENDTXT] SUB CX,SI JZ RET7 MOV BP,[CURRENT] DISPLN: PUSH CX CALL SHOWNUM POP CX OUTLN: LODSB CMP AL," " JAE SEND CMP AL,10 JZ SEND CMP AL,13 JZ SEND CMP AL,9 JZ SEND PUSH AX MOV AL,"^" CALL OUT POP AX OR AL,40H SEND: CALL OUT CMP AL,10 LOOPNZ OUTLN JCXZ RET7 INC BX DEC DI JNZ DISPLN DEC BX RET7: RET LOADBUF: MOV DI,2 + OFFSET DG:EDITBUF MOV CX,255 MOV DX,-1 LOADLP: LODSB STOSB INC DX CMP AL,13 LOOPNZ LOADLP MOV [EDITBUF+1],DL JZ RET7 TRUNCLP: LODSB INC DX CMP AL,13 JNZ TRUNCLP DEC DI STOSB RET NOTFNDJ:JMP NOTFND replac_from_curr: mov byte ptr [srchmod],1 ;search from curr+1 line jmp short sj6 REPLAC: mov byte ptr [srchmod],0 ;search from beg of buffer sj6: MOV BYTE PTR [SRCHFLG],0 CALL FNDFIRST JNZ NOTFNDJ REPLP: MOV SI,[NUMPOS] CALL LOADBUF ;Count length of line SUB DX,[OLDLEN] MOV CX,[NEWLEN] ADD DX,CX ;Length of new line CMP DX,254 JA TOOLONG MOV BX,[LSTNUM] PUSH DX CALL SHOWNUM POP DX MOV CX,[LSTFND] MOV SI,[NUMPOS] SUB CX,SI ;Get no. of char on line before change DEC CX CALL OUTCNT ;Output first part of line PUSH SI MOV SI,1+ OFFSET DG:TXT2 MOV CX,[NEWLEN] CALL OUTCNT ;Output change POP SI ADD SI,[OLDLEN] ;Skip over old stuff in line MOV CX,DX ;DX=no. of char left in line ADD CX,2 ;Include CR/LF CALL OUTCNT ;Output last part of line CALL QUERY ;Check if change OK JNZ REPNXT CALL PUTCURS MOV DI,[LSTFND] DEC DI MOV SI,1+ OFFSET DG:TXT2 MOV DX,[OLDLEN] MOV CX,[NEWLEN] DEC CX ADD [LSTFND],CX ;Bump pointer beyond new text INC CX DEC DX SUB [SRCHCNT],DX ;Old text will not be searched JAE SOMELEFT MOV [SRCHCNT],0 SOMELEFT: INC DX CALL REPLACE REPNXT: CALL FNDNEXT JNZ RET8 JMP REPLP OUTCNT: JCXZ RET8 OUTLP: LODSB CALL OUT DEC DX LOOP OUTLP RET8: RET TOOLONG: MOV DX,OFFSET DG:TOOLNG JMP SHORT PERR search_from_curr: mov byte ptr [srchmod],1 ;search from curr+1 line jmp short sj7 SEARCH: mov byte ptr [srchmod],0 ;search from beg of buffer sj7: MOV BYTE PTR [SRCHFLG],1 CALL FNDFIRST JNZ NOTFND SRCH: MOV BX,[LSTNUM] MOV SI,[NUMPOS] CALL DISPONE MOV DI,[LSTFND] MOV CX,[SRCHCNT] MOV AL,10 REPNE SCASB JNZ NOTFND MOV [LSTFND],DI MOV [NUMPOS],DI MOV [SRCHCNT],CX INC [LSTNUM] CALL QUERY JZ PUTCURS CALL FNDNEXT JZ SRCH NOTFND: MOV DX,OFFSET DG:NOSUCH PERR: MOV AH,STD_CON_STRING_OUTPUT INT 21H RET PUTCURS: MOV BX,[LSTNUM] DEC BX ;Current <= Last matched line CALL FINDLIN MOV [CURRENT],DX MOV [POINTER],DI RET9: RET DELETE: MOV BX,[PARAM1] OR BX,BX JNZ DELFIN1 MOV BX,[CURRENT] CALL CHKRANGE DELFIN1: CALL FINDLIN JNZ RET9 PUSH BX PUSH DI MOV BX,[PARAM2] OR BX,BX JNZ DELFIN2 MOV BX,DX DELFIN2: INC BX CALL FINDLIN MOV DX,DI POP DI SUB DX,DI JBE COMERRJ POP [CURRENT] MOV [POINTER],DI XOR CX,CX JMP SHORT REPLACE COMERRJ:JMP COMERR NOCOM: DEC [COMLINE] MOV BX,[PARAM1] OR BX,BX JNZ HAVLIN MOV BX,[CURRENT] INC BX ;Default is current line plus one CALL CHKRANGE HAVLIN: CALL FINDLIN MOV SI,DI MOV [CURRENT],DX MOV [POINTER],SI jz sj12 ret sj12: CMP SI,[ENDTXT] JZ RET12 CALL LOADBUF MOV [OLDLEN],DX MOV SI,[POINTER] CALL DISPONE CALL SHOWNUM MOV AH,STD_CON_STRING_INPUT ;Get input buffer MOV DX,OFFSET DG:EDITBUF INT 21H MOV AL,10 CALL OUT MOV CL,[EDITBUF+1] MOV CH,0 JCXZ RET12 MOV DX,[OLDLEN] MOV SI,2 + OFFSET DG:EDITBUF ;----------------------------------------------------------------------- call unquote ;scan for quote chars if any ;----------------------------------------------------------------------- MOV DI,[POINTER] REPLACE: ; Inputs: ; CX = Length of new text ; DX = Length of original text ; SI = Pointer to new text ; DI = Pointer to old text in buffer ; Function: ; New text replaces old text in buffer and buffer ; size is adjusted. CX or DX may be zero. ; CX, SI, DI all destroyed. No other registers affected. CMP CX,DX JZ COPYIN PUSH SI PUSH DI PUSH CX MOV SI,DI ADD SI,DX ADD DI,CX MOV AX,[ENDTXT] SUB AX,DX ADD AX,CX CMP AX,[LAST] JAE MEMERR XCHG AX,[ENDTXT] MOV CX,AX SUB CX,SI CMP SI,DI JA DOMOV ADD SI,CX ADD DI,CX STD DOMOV: INC CX REP MOVSB CLD POP CX POP DI POP SI COPYIN: REP MOVSB RET12: RET MEMERR: MOV DX,OFFSET DG:MEMFUL MOV AH,STD_CON_STRING_OUTPUT INT 21H JMP COMMAND MOVERR: MOV DX,OFFSET DG:BADCOM ERRORJ: JMP COMERR MOVE: MOV BYTE PTR [MOVFLG],1 JMP SHORT BLKMOVE COPY: MOV BYTE PTR [MOVFLG],0 BLKMOVE: MOV BX,[PARAM3] ;Third parameter must be specified OR BX,BX MOV DX,OFFSET DG:DEST JZ ERRORJ MOV BX,[PARAM1] ;Get the first parameter OR BX,BX ;Not specified? JNZ NXTARG MOV BX,[CURRENT] ;Defaults to the current line CALL CHKRANGE MOV [PARAM1],BX ;Save it since current line may change NXTARG: CALL FINDLIN ;Get a pointer to the line MOV [PTR_1],DI ;Save it MOV BX,[PARAM2] ;Get the second parameter OR BX,BX ;Not specified? JNZ HAVARGS MOV BX,[CURRENT] ;Defaults to the current line MOV [PARAM2],BX ;Save it since current line may change HAVARGS: ;Parameters must not overlap MOV DX,[PARAM3] CMP DX,[PARAM1] JBE NOERROR CMP DX,[PARAM2] JBE MOVERR NOERROR: INC BX ;Get pointer to line Param2+1 CALL FINDLIN MOV SI,DI MOV [PTR_2],SI ;Save it MOV CX,DI MOV DI,[PTR_1] ;Restore pointer to line Param1 SUB CX,DI ;Calculate number of bytes to copy MOV [COPYSIZ],CX ;Save in COPYSIZ PUSH CX ;And on the stack MOV AX,[PARAM4] ;Is count specified? OR AX,AX JZ MEM_CHECK MUL [COPYSIZ] OR DX,DX JZ COPYSIZ_OK JMP MEMERR COPYSIZ_OK: MOV CX,AX MOV [COPYSIZ],CX MEM_CHECK: MOV AX,[ENDTXT] MOV DI,[LAST] SUB DI,AX CMP DI,CX JAE HAV_ROOM JMP MEMERR HAV_ROOM: MOV BX,[PARAM3] PUSH BX CALL FINDLIN MOV [PTR_3],DI MOV CX,[ENDTXT] SUB CX,DI INC CX MOV SI,[ENDTXT] MOV DI,SI ADD DI,[COPYSIZ] MOV [ENDTXT],DI STD REP MOVSB CLD POP BX CMP BX,[PARAM1] JB GET_PTR_2 MOV SI,[PTR_1] JMP SHORT COPY_TEXT GET_PTR_2: MOV SI,[PTR_2] COPY_TEXT: MOV BX,[PARAM4] MOV DI,[PTR_3] POP CX MOV [COPYSIZ],CX COPY_TEXT_1: REP MOVSB DEC BX CMP BX,0 JLE MOV_CHK MOV [PARAM4],BX SUB SI,[COPYSIZ] MOV CX,[COPYSIZ] JMP SHORT COPY_TEXT_1 MOV_CHK: CMP BYTE PTR[MOVFLG],0 JZ COPY_DONE MOV DI,[PTR_1] MOV SI,[PTR_2] MOV BX,[PARAM3] CMP BX,[PARAM1] JAE DEL_TEXT ADD DI,[COPYSIZ] ADD SI,[COPYSIZ] DEL_TEXT: MOV CX,[ENDTXT] SUB CX,SI REP MOVSB MOV [ENDTXT],DI MOV CX,[PARAM2] SUB CX,[PARAM1] MOV BX,[PARAM3] SUB BX,CX JNC MOVE_DONE COPY_DONE: MOV BX,[PARAM3] MOVE_DONE: CALL FINDLIN MOV [POINTER],DI MOV [CURRENT],BX RET MOVEFILE: MOV CX,[ENDTXT] ;Get End-of-text marker MOV SI,CX SUB CX,DI ;Calculate number of bytes to copy INC CX MOV DI,DX STD REP MOVSB ;Copy CX bytes XCHG SI,DI CLD INC DI MOV BP,SI SETPTS: MOV [POINTER],DI ;Current line is first free loc MOV [CURRENT],BX ; in the file MOV [ENDTXT],BP ;End-of-text is last free loc before RET NAMERR: JMP COMERR1 MERGE: MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 1 MOV DI,OFFSET DG:FCB3 INT 21H OR AL,AL MOV DX,OFFSET DG:BADDRV JNZ NAMERR MOV [COMLINE],SI MOV DX,OFFSET DG:FCB3 MOV AH,FCB_OPEN INT 21H OR AL,AL MOV DX,OFFSET DG:FILENM JNZ NAMERR MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H MOV DX,OFFSET DG:ABORTMERGE INT 21H MOV BX,[PARAM1] OR BX,BX JNZ MRG MOV BX,[CURRENT] CALL CHKRANGE MRG: CALL FINDLIN MOV BX,DX MOV DX,[LAST] CALL MOVEFILE ;Set DMA address for reading in new file MOV DX,[POINTER] MOV AH,SET_DMA INT 21H XOR AX,AX MOV WORD PTR DS:[FCB3+fcb_RR],AX MOV WORD PTR DS:[FCB3+fcb_RR+2],AX INC AX MOV WORD PTR DS:[FCB3+fcb_RECSIZ],AX MOV DX,OFFSET DG:FCB3 MOV CX,[ENDTXT] SUB CX,[POINTER] MOV AH,FCB_RANDOM_READ_BLOCK INT 21H CMP AL,1 JZ FILEMRG MOV DX,OFFSET DG:MRGERR MOV AH,STD_CON_STRING_OUTPUT INT 21H MOV CX,[POINTER] JMP SHORT RESTORE FILEMRG: ADD CX,[POINTER] MOV SI,CX DEC SI LODSB CMP AL,1AH JNZ RESTORE DEC CX RESTORE: MOV DI,CX MOV SI,[ENDTXT] INC SI MOV CX,[LAST] SUB CX,SI REP MOVSB MOV [ENDTXT],DI MOV BYTE PTR [DI],1AH MOV DX,OFFSET DG:FCB3 MOV AH,FCB_CLOSE INT 21H MOV DX,OFFSET DG:START MOV AH,SET_DMA INT 21H RET INSERT: MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H ;Set vector 23H MOV DX,OFFSET DG:ABORTINS INT 21H MOV BX,[PARAM1] OR BX,BX JNZ INS MOV BX,[CURRENT] CALL CHKRANGE INS: CALL FINDLIN MOV BX,DX MOV DX,[LAST] CALL MOVEFILE INLP: CALL SETPTS ;Update the pointers into file CALL SHOWNUM MOV DX,OFFSET DG:EDITBUF MOV AH,STD_CON_STRING_INPUT INT 21H CALL LF MOV SI,2 + OFFSET DG:EDITBUF CMP BYTE PTR [SI],1AH JZ ENDINS ;----------------------------------------------------------------------- call unquote ;scan for quote chars if any ;----------------------------------------------------------------------- MOV CL,[SI-1] MOV CH,0 MOV DX,DI INC CX ADD DX,CX JC MEMERRJ1 JZ MEMERRJ1 CMP DX,BP JB MEMOK MEMERRJ1: CALL END_INS JMP MEMERR MEMOK: REP MOVSB MOV AL,10 STOSB INC BX JMP SHORT INLP ABORTMERGE: MOV DX,OFFSET DG:START MOV AH,SET_DMA INT 21H ABORTINS: MOV AX,CS ;Restore segment registers MOV DS,AX MOV ES,AX MOV SS,AX MOV SP,OFFSET DG:STACK STI CALL CRLF CALL ENDINS JMP COMOVER ENDINS: CALL END_INS RET END_INS: MOV BP,[ENDTXT] MOV DI,[POINTER] MOV SI,BP INC SI MOV CX,[LAST] SUB CX,BP REP MOVSB DEC DI MOV [ENDTXT],DI MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H MOV DX,OFFSET DG:ABORTCOM INT 21H RET FILLBUF: MOV [PARAM1],-1 ;Read in max. no of lines CALL APPEND ENDED: ;Write text out to .$$$ file MOV BYTE PTR [ENDING],1 ;Suppress memory errors MOV BX,-1 ;Write max. no of lines CALL WRT TEST BYTE PTR [HAVEOF],-1 JZ FILLBUF MOV DX,[ENDTXT] MOV AH,SET_DMA INT 21H MOV CX,1 MOV DX,OFFSET DG:FCB2 MOV AH,FCB_RANDOM_WRITE_BLOCK INT 21H ;Write end-of-file byte ;Close .$$$ file MOV AH,FCB_CLOSE INT 21H MOV SI,FCB LEA DI,[SI+fcb_FILSIZ] MOV DX,SI MOV CX,9 REP MOVSB MOV SI,OFFSET DG:BAK MOVSW MOVSB ;Rename original file .BAK MOV AH,FCB_RENAME INT 21H MOV SI,FCB MOV DI,OFFSET DG:FCB2 + fcb_FILSIZ MOV CX,6 REP MOVSW ;Rename .$$$ file to original name MOV DX,OFFSET DG:FCB2 INT 21H call rest_dir ;restore directory if needed INT 20H ABORTCOM: MOV AX,CS MOV DS,AX MOV ES,AX MOV SS,AX MOV SP,OFFSET DG:STACK STI CALL CRLF JMP COMMAND DELBAK: MOV BYTE PTR [DELFLG],1 MOV DI,9+OFFSET DG:FCB2 MOV SI,OFFSET DG:BAK MOVSW MOVSB ;Delete old backup file (.BAK) MOV AH,FCB_DELETE MOV DX,OFFSET DG:FCB2 INT 21H MOV DI,9+OFFSET DG:FCB2 MOV AL,"$" STOSB STOSB STOSB RET CODE ENDS END EDLIN