|
|
PAGE 60,132; TITLE EDLIN ;/* ; * Microsoft Confidential ; * Copyright (C) Microsoft Corporation 1991 ; * All Rights Reserved. ; */
;======================= START OF SPECIFICATIONS ========================= ; ; MODULE NAME: EDLIN.SAL ; ; DESCRIPTIVE NAME: LINE TEXT EDITOR ; ; FUNCTION: EDLIN IS A SIMPLE, LINE ORIENTED TEXT EDITOR. IT PROVIDES ; USERS OF DOS THE ABILITY TO CREATE AND EDIT TEXT FILES. ; ; ENTRY POINT: EDLIN ; ; INPUT: DOS COMMAND LINE ; EDLIN COMMANDS ; TEXT ; ; EXIT NORMAL: NA ; ; EXIT ERROR: NA ; ; INTERNAL REFERENCES: ; ; EXTERNAL REFERENCES: ; ; ROUTINE: EDLCMD1 - CONTAINS ROUTINES CALLED BY EDLIN ; EDLCMD1 - CONTAINS ROUTINES CALLED BY EDLIN ; EDLMES - CONTAINS ROUTINES CALLED BY EDLIN ; ; LINK EDLIN+EDLCMD1+EDLCMD2+EDLMES+EDLPARSE ; ; REVISION HISTORY: ; ; AN000 VERSION 4.00 - REVISIONS MADE RELATE TO THE FOLLOWING: ; ; - IMPLEMENT SYSPARSE ; - IMPLEMENT MESSAGE RETRIEVER ; - IMPLEMENT DBCS ENABLING ; - ENHANCED VIDEO SUPPORT ; - EXTENDED OPENS ; - SCROLLING ERROR ; ; COPYRIGHT: "MS DOS EDLIN UTILITY" ; "VERSION 4.00 (C) COPYRIGHT 1988 Microsoft" ; "LICENSED MATERIAL - PROPERTY OF Microsoft" ; ; ; MICROSOFT REVISION HISTORY: ; ; ; V1.02 ; ; ; ; V2.00 9/13/82 M.A.U ; ; ; ; 2/23/82 Rev. 13 N. P ; ; Changed to 2.0 system calls. ; ; Added an error message for READ-ONLY files ; ; ; ; 11/7/83 Rev. 14 N. P ; ; Changed to .EXE format and added Printf ; ; ; ; V2.50 11/15/83 Rev. 1 M.A. U ; ; Official dos 2.50 version. Some random bug ; ; fixes and message changes. ; ; ; ; 11/30/83 Rev. 2 MZ ; ; Close input file before rename. ; ; Jmp to replace after line edit ; ; ; ; 02/01/84 Rev. 3 M.A. U ; ; Now it is called 3.00 dos. Repaired problem ; ; with using printf and having %'s as data. ; ; ; ; 02/15/84 MZ make out of space a fatal error with output; ; ; ; 03/28/84 MZ fixes bogus (totally) code in MOVE/COPY ; ; ; ; 04/02/84 MZ fixes DELETE and changes MOVE/COPY/EDIT ; ; ; ; V3.20 08/29/86 Rev. 1 S.M. G ; ; ; ; 08/29/86 M001 MSKK TAR 593, TAB MOVEMENT ; ; ; ; 08/29/86 M002 MSKK TAR 157, BLKMOVE 1,1,1m, 1,3,1m ; ; ; ; 08/29/86 M003 MSKK TAR 476, EDLCMD2,MAKECAPS,kana char ; ; ; ; 08/29/86 M004 MSKK TAR 191, Append load size ; ; ; ; 08/29/86 M005 IBMJ TAR Transfer Load command ; ; ; ; 04/17/90 c-PaulB ; ; Added /? switch to display options ; ; Files changed: edlin.asm, edlparse.asm, edlmes.asm, ; ; edlin.skl. ; ; ; ;======================= END OF SPECIFICATIONS =========================== ;
include version.inc include intnat.inc include syscall.inc include edlequ.asm
SUBTTL Contants and Data areas PAGE extrn parser_command:near ;an000;SYSPARSE
CODE SEGMENT PUBLIC CODE ENDS
CONST SEGMENT PUBLIC WORD CONST ENDS
cstack segment stack cstack ends
DATA SEGMENT PUBLIC WORD DATA ENDS
DG GROUP CODE,CONST,cstack,DATA
CONST SEGMENT PUBLIC WORD
public bak,$$$file,delflg,loadmod,txt1,txt2
EXTRN BADDRV:abs,NDNAME:abs EXTRN opt_err_ptr:word,NOBAK:abs,BADCOM:abs EXTRN NEWFIL:abs,DEST:abs,MRGERR:abs EXTRN NODIR:abs,FILENM_ptr:word,ro_err:abs EXTRN bcreat:abs,msg_too_many:abs,msg_lf:abs EXTRN prompt:abs,MemFul_Ptr:word,simple_msg:word extrn dsp_options:abs extrn dsp_help:abs,num_help_msgs:abs
BAK DB ".BAK",0
$$$FILE DB ".$$$",0
fourth db 0 ;fourth parameter flag
loadmod db 0 ;Load mode flag, 0 = ^Z marks the ; end of a file, 1 = viceversa. optchar db "-"
TXT1 DB 0,80H DUP (?) TXT2 DB 0,80H DUP (?) DELFLG DB 0 fNew DB 0 ; old file HAVEOF DB 0
CONST ENDS
cstack segment stack db stksiz dup (?) cstack ends
DATA SEGMENT PUBLIC WORD
extrn arg_buf_ptr:word ;an000; extrn line_num_buf_ptr:word ;an000;
public path_name,ext_ptr,start,line_num,line_flag public arg_buf,wrt_handle,temp_path public current,pointer,qflg,editbuf,amnt_req,fname_len,delflg,lastlin public olddat,oldlen,newlen,srchflg,srchmod public comline,lstfnd,numpos,lstnum,last_mem,srchcnt public rd_handle,haveof,ending,three4th,one4th
public lc_adj ;an000;page length adj. factor public lc_flag ;an000;display cont. flag public pg_count ;an000;lines left on screen public Disp_Len ;an000;display length public Disp_Width ;an000;display width public continue ;an000;boolean T/F public temp_path ;an000;pointer to filespec buf
Video_Buffer label word ;an000;buffer for video attr db 0 ;an000;dms; db 0 ;an000;dms; dw 14 ;an000;dms; dw 0 ;an000;dms; db ? ;an000;dms; db 0 ;an000;dms; dw ? ;an000;dms;# of colors dw ? ;an000;dms;# of pixels in width dw ? ;an000;dms;# of pixels in len. dw ? ;an000;dms;# of chars in width dw ? ;an000;dms;# of chars in length
video_org db ? ;an000;original video mode on ; entry to EDLIN. lc_adj db ? ;an000;page length adj. factor lc_flag db ? ;an000;display cont. flag pg_count db ? ;an000;lines left on screen Disp_Len db ? ;an000;display length Disp_Width db ? ;an000;display width continue db ? ;an000;boolean T/F
;-----------------------------------------------------------------------; ; This is a table that is sequentially filled via GetNum. Any additions to it ; must be placed in the correct position. Currently Param4 is known to be a ; count and thus is treated specially.
public param1,param2,Param3,param4,ParamCt PARAM1 DW ? PARAM2 DW ? PARAM3 DW ? PARAM4 DW ? ParamCt DW ? ; count of passed parameters ifdef DBCS ; Used in TESTKANJ: LBTbl dd ? ; long pointer to lead byte table endif ; in the dos (from syscall 63H)
;-----------------------------------------------------------------------;
PUBLIC PTR_1, PTR_2, PTR_3, OLDLEN, NEWLEN, LSTFND, LSTNUM, NUMPOS, SRCHCNT PUBLIC CURRENT, POINTER, ONE4TH, THREE4TH, LAST_MEM, ENDTXT, COPYSIZ PUBLIC COMLINE, LASTLIN, COMBUF, EDITBUF, EOL, QFLG, ENDING, SRCHFLG PUBLIC PATH_NAME, FNAME_LEN, RD_HANDLE, TEMP_PATH, WRT_HANDLE, EXT_PTR PUBLIC MRG_PATH_NAME, MRG_HANDLE, amnt_req, olddat, srchmod, MOVFLG, org_ds ifdef DBCS public lbtbl endif
; ; These comprise the known state of the internal buffer. All editing ; functions must preserve these values. ; CURRENT DW ? ; the 1-based index of the current line POINTER DW ? ; pointer to the current line ENDTXT DW ? ; pointer to end of buffer. (at ^Z) LAST_MEM DW ? ; offset of last byte of memory ; ; The label Start is the beginning of the in-core buffer. ;
; ; Internal temporary pointers ; PTR_1 DW ? PTR_2 DW ? PTR_3 DW ?
QFLG DB ? ; TRUE => query for replacement OLDLEN DW ? NEWLEN DW ? LSTFND DW ? LSTNUM DW ? NUMPOS DW ? SRCHCNT DW ? ONE4TH DW ? THREE4TH DW ? COPYSIZ DW ? ; total length to copy COPYLEN DW ? ; single copy length COMLINE DW ? LASTLIN DW ? COMBUF DB 82H DUP (?) EDITBUF DB 258 DUP (?) EOL DB ? ENDING DB ? SRCHFLG DB ? PATH_NAME DB 128 DUP(0) FNAME_LEN DW ? RD_HANDLE DW ? TEMP_PATH DB 128 DUP(?) WRT_HANDLE DW ? EXT_PTR DW ? MRG_PATH_NAME DB 128 DUP(?) MRG_HANDLE DW ? amnt_req dw ? ; amount of bytes requested to read olddat db ? ; Used in replace and search, replace ; by old data flag (1=yes) srchmod db ? ; Search mode: 1=from current+1 to ; end of buffer, 0=from beg. of ; buffer to the end (old way). MOVFLG DB ? org_ds dw ? ;Orginal ds points to header block
arg_buf db 258 dup (?)
EA_Flag db False ;an000; dms;set to false
EA_Buffer_Size dw ? ;an000; dms;EA buffer's size
EA_Parm_List label word ;an000; dms;EA parms dd dg:Start ;an000; dms;ptr to EA's dw 0001h ;an000; dms;additional parms db 06h ;an000; dms; dw 0002h ;an000; dms;iomode
line_num dw ?
line_flag db ?,0 EVEN ;align on word boundaries ; ; Byte before start of data buffer must be < 40H !!!!!! ; dw 0 ;we scan backwards looking for ;a character which can't be part ;of a two-byte seqence. This ;double byte sequence will cause the back ;scan to stop here. START LABEL WORD
DATA ENDS
CODE SEGMENT PUBLIC
ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:CStack
extrn pre_load_message:near ;an000;message loader extrn disp_fatal:near ;an000;fatal message extrn printf:near ;an000;new PRINTF routine
extrn findlin:near,shownum:near,loadbuf:near,crlf:near,lf:near extrn abortcom:near,delbak:near,unquote:near,kill_bl:near extrn make_caps:near,dispone:near,display:near,query:near extrn quit:near,make_cntrl:near,scanln:near,scaneof:near extrn fndfirst:near,fndnext:near,replace:near,memerr:near extrn xerror:near extrn zerror:near extrn bad_read:near,append:near extrn nocom:near,pager:near,list:near,search_from_curr:near extrn replac_from_curr:near,ewrite:near,wrt:near,delete:near
extrn filespec:byte ;an000;parser's filespec extrn parse_switch_b:byte ;an000;result of switch scan extrn parse_switch_?:byte ; result of switch scan
public std_printf,command,chkrange,comerr public display_message ; exit from EDLIN
IFDEF DBCS extrn testkanj:near ENDIF
EDLIN: JMP SHORT SIMPED
std_printf proc near ;ac000;convert to proc
push dx call printf pop dx ;an000;balance the push ret
std_printf endp ;ac000;end proc
Break <Dispatch Table>
;-----------------------------------------------------------------------; ; Careful changing the order of the next two tables. They are linked and ; changes should be be to both.
COMTAB DB 13,";ACDEILMPQRSTW" NUMCOM EQU $-COMTAB
TABLE DW BLANKLINE ; Blank line DW NOCOM ; ; DW APPEND ; A(ppend) DW COPY ; C(opy) DW DELETE ; D(elete) DW ENDED ; E(xit) DW INSERT ; I(nsert) DW LIST ; L(ist) DW MOVE ; M(ove) DW PAGER ; P(age) DW QUIT ; Q(uit) dw replac_from_curr ; R(eplace) dw search_from_curr ; S(earch) DW MERGE ; T(merge) DW EWRITE ; W(rite)
Break <Initialization Code>
NONAME: mov ax,NDNAME jmp zerror
SIMPED: mov org_ds,DS push ax ;ac000;save for drive compare
push cs ;an000;exchange cs/es pop es ;an000;
push cs ;an000;exchange cs/ds pop ds ;an000; assume ds:dg,es:dg ;an000;establish addressibility
MOV dg:ENDING,0 mov sp,stack call EDLIN_DISP_GET ;an000;get current video ; mode & set it to ; text
;========================================================================= ; invoke PRE_LOAD_MESSAGE here. If the messages were not loaded we will ; exit with an appropriate error message. ; ; Date : 6/14/87 ;=========================================================================
call PRE_LOAD_MESSAGE ;an000;invoke SYSLOADMSG ; $if c ;an000;if the load was unsuccessful JNC $$IF1 mov ah,exit ;an000;exit EDLIN. PRE_LOAD_MESSAGE ; has said why we are exiting mov al,00h ;an000 int 21h ;an000;exit ; $endif ;an000; $$IF1:
VERS_OK: ;----- Check for valid drive specifier --------------------------------;
pop ax OR AL,AL JZ get_switch_char mov ax,BADDRV jmp zerror get_switch_char: MOV AX,(CHAR_OPER SHL 8) ;GET SWITCH CHARACTER INT 21H CMP DL,"/" JNZ CMD_LINE ;IF NOT / , THEN NOT PC MOV OPTCHAR,"/" ;IN PC, OPTION CHAR = /
IFDEF DBCS push ds ; SAVE! all regs destroyed on this push es push si ; call !! mov ax,(ECS_call shl 8) or 00h ; get kanji lead tbl int 21h assume ds:nothing assume es:nothing mov word ptr [LBTbl],si mov word ptr [LBTbl+2],ds pop si pop es pop ds assume ds:dg assume es:dg ENDIF
CMD_LINE: push cs pop es ASSUME ES:DG
;----- Process any options ------------------------------------------;
;========================================================================= ; The system parser, called through PARSER_COMMAND, parses external ; command lines. In the case of EDLIN we are looking for two parameters ; on the command line. ; ; Parameter 1 - Filespec (REQUIRED) ; Parameter 2 - \B switch (OPTIONAL) ; ; PARSER_COMMAND - exit_normal : ffffh ; exit_error : not = ffffh ;=========================================================================
call PARSER_COMMAND ;an000;invoke sysparse ; DMS:6/11/87
; Check for /? switch. ; If so, display the options ; and exit. ; ; This is done first so that if the user typed ; /? along with unknown commands, they can get ; a coherent message without being over-errored. ; ; 4/17/90 c-PaulB
cmp [parse_switch_?], true ; is the /? switch on? jne CheckOptionsDone ; skip the rest of this if not
mov ax,dsp_options call display_message
mov al, 0 ; get an okay exit code mov ah, exit ; and int 21h ; bail out.
CheckOptionsDone:
cmp ax,nrm_parse_exit ;an000;was it a good parse ; $if z ;an000;it was a good parse JNZ $$IF3 call EDLIN_COMMAND ;an000;interface results ; into EDLIN ; $else ;an000; JMP SHORT $$EN3 $$IF3: cmp ax,too_many ;an000;too many operands ; $if z ;an000;we have too many JNZ $$IF5 jmp short badopt ;an000;say why and exit ; $endif $$IF5:
cmp ax,op_missing ;an000;required parm missing ; $if z ;an000;missing parm JNZ $$IF7 ifdef DBCS jmp noname ;an000;say why and exit else jmp short noname ;an000;say why and exit endif ; $endif ;an000; $$IF7:
cmp ax,sw_missing ;an000;is it an invalid switch ; $if z ;an000;invalid switch JNZ $$IF9 jmp short badopt ;an000;say why and exit ; $endif ;an000; $$IF9:
; $endif ;an000; $$EN3:
;========================================================================= ;======================= begin .BAK check ================================ ; Check for .BAK extension on the filename
push ds ;an000;save reg. push cs ;an000;set up addressibility pop ds ;an000; assume ds:dg ;an000;
push ax ;an000;save reg. mov ax,offset dg:path_name ;an000;point to path_name add ax,[fname_len] ;an000;calculate end of path_name mov si,ax ;an000;point to end of path_name pop ax ;an000;restore reg.
MOV CX,4 ;compare 4 bytes SUB SI,4 ;Point 4th to last char MOV DI,OFFSET DG:BAK ;Point to string ".BAK" REPE CMPSB ;Compare the two strings pop ds ASSUME DS:NOTHING JNZ NOTBAK JMP HAVBAK
;======================= end .BAK check ==================================
;======================= begin NOTBAK ==================================== ; we have a file without a .BAK extension, try to open it
NOTBAK: push ds push cs pop ds ASSUME DS:DG
;========================================================================= ; implement EXTENDED OPEN ;=========================================================================
push es ;an000;save reg. mov bx,RW ;an000;open for read/write mov cx,ATTR ;an000;file attributes mov dx,RW_FLAG ;an000;action to take on open mov di,0ffffh ;an000;nul parm list
call EXT_OPEN1 ;an000;open for R/W;DMS:6/10/87 pop es ;an000;restore reg.
;========================================================================= pop ds ASSUME DS:NOTHING JC CHK_OPEN_ERR ;an open error occurred MOV RD_HANDLE,AX ;Save the handle
Jmp HavFil ;work with the opened file
;======================= end NOTBAK ======================================
Badopt: MOV DX,OFFSET DG:OPT_ERR_ptr;Bad option specified JMP XERROR
;========================================================================= ; ; The open of the file failed. We need to figure out why and report the ; correct message. The circumstances we can handle are: ; ; open returns pathnotfound => bad drive or file name ; open returns toomanyopenfiles => too many open files ; open returns access denied => ; chmod indicates read-only => cannot edit read only file ; else => file creation error ; open returns filenotfound => ; creat ok => close, delete, new file ; creat fails => file creation error ; else => file cre ;
CHK_OPEN_ERR: cmp ax,error_path_not_found jz BadDriveError cmp ax,error_too_many_open_files jz TooManyError cmp ax,error_access_denied jnz CheckFNF push ds push cs pop ds assume ds:dg mov ax,(chmod shl 8) MOV DX,OFFSET DG:PATH_NAME int 21h jc FileCreationError test cx,attr_read_only jz FileCreationError jmp short ReadOnlyError
CheckFNF: cmp ax,error_file_not_found jnz FileCreationError ; ; Try to create the file to see if it is OK. ; push ds push cs pop ds assume ds:dg ;========================================================================= ; implement EXTENDED OPEN ;=========================================================================
mov bx,RW ;an000;open for read/write mov cx,ATTR ;an000;file attributes mov dx,CREAT_FLAG ;an000;action to take on open mov di,0ffffh ;an000;null parm list call EXT_OPEN1 ;an000;create file;DMS:6/10/87
;=========================================================================
pop ds assume ds:nothing jc CreateCheck mov bx,ax mov ah,close int 21h push ds push cs pop ds assume ds:dg mov ah,unlink MOV DX,OFFSET DG:PATH_NAME int 21h pop ds assume ds:nothing jc FileCreationError ; This should NEVER be taken!!! MOV HAVEOF,0FFH ; Flag from a system 1.xx call MOV fNew,-1 JMP short HAVFIL
CreateCheck: cmp ax,error_access_denied jnz BadDriveError DiskFull: mov ax,NODIR jmp zerror
FileCreationError: mov ax,bcreat jmp zerror
ReadOnlyError: mov ax,RO_ERR jmp zerror
BadDriveError: mov ax,BADDRV jmp zerror
TooManyError: mov ax,msg_too_many jmp zerror
CREAT_ERR: CMP DELFLG,0 JNZ DiskFull push cs pop ds CALL DELBAK JMP short MAKFIL
HAVBAK: mov ax,NOBAK jmp zerror
HAVFIL: push cs pop ds ASSUME DS:DG CMP fNew,0 JZ MakeBak mov ax,newfil call display_message MakeBak: MOV SI,OFFSET DG:PATH_NAME MOV CX,[FNAME_LEN] PUSH CX MOV DI,OFFSET DG:TEMP_PATH REP MOVSB DEC DI MOV DX,DI POP CX MOV AL,"." STD REPNE SCASB JZ FOUND_EXT MOV DI,DX ;Point to last char in filename FOUND_EXT: CLD INC DI MOV [EXT_PTR],DI MOV SI,OFFSET DG:$$$FILE MOV CX,5 REP MOVSB
;Create .$$$ file to make sure directory has room MAKFIL:
;========================================================================= ; implement EXTENDED OPEN ;=========================================================================
mov bx,RW ;an000;open for read/write mov cx,ATTR ;an000;file attributes mov dx,Creat_Open_Flag ;an000;action to take on open cmp EA_Flag,True ;an000;EA_Buffer used? ; $if e ;an000;yes JNE $$IF12 mov di,offset dg:EA_Parm_List ;an000; point to buffer ; $else ;an000; JMP SHORT $$EN12 $$IF12: mov di,0ffffh ;an000;nul parm list ; $endif ;an000; $$EN12: call EXT_OPEN2 ;an000;create file;DMS:6/10/87
;=========================================================================
JC CREAT_ERR MOV [WRT_HANDLE],AX ; ; We determine the size of the available memory. Use the word in the PDB at ; [2] to determine the number of paragraphs. Then truncate this to 64K at ; most. ; push ds ;save ds for size calc mov ds,[org_ds] MOV CX,DS:[2] MOV DI,CS SUB CX,DI CMP CX,1000h JBE GotSize MOV CX,0FFFh GotSize: SHL CX,1 SHL CX,1 SHL CX,1 SHL CX,1 pop ds ;restore ds after size calc DEC CX MOV [LAST_MEM],CX MOV DI,OFFSET DG:START TEST fNew,-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 MOV DX,OFFSET DG:START 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 ParamCt,1 MOV [PARAM1],0 ;M004 Leave room in memory, was -1 TEST fNew,-1 JNZ COMMAND ; ; The above setting of PARAM1 to -1 causes this call to APPEND to try to read ; in as many lines that will fit, BUT.... What we are doing is simulating ; the user issuing an APPEND command, and if the user asks for more lines ; than we get then an "Insufficient memory" error occurs. In this case we ; DO NOT want this error, we just want as many lines as possible read in. ; The twiddle of ENDING suppresses the memory error ; MOV BYTE PTR [ENDING],1 ;Suppress memory errors CALL APPEND MOV ENDING,0 ; restore correct initial value
Break <Main command loop>
; ; Main read/parse/execute loop. We reset the stack all the time as there ; are routines that JMP back here. Don't blame me; Tim Paterson write this. ; COMMAND: push cs ;an000;set up addressibility pop ds ;an000; push cs ;an000; pop es ;an000; assume ds:dg,es:dg ;an000;
MOV SP, STACK MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H MOV DX,OFFSET DG:ABORTCOM INT 21H mov ax,prompt call display_message
MOV DX,OFFSET DG:COMBUF MOV AH,STD_CON_STRING_INPUT INT 21H MOV [COMLINE],OFFSET DG:COMBUF + 2
mov ax,msg_lf call display_message
PARSE: MOV [PARAM2],0 MOV [PARAM3],0 MOV [PARAM4],0 mov [fourth],0 ;reset the fourth parameter flag MOV QFLG,0 MOV SI,[COMLINE] MOV BP,OFFSET DG:PARAM1 XOR DI,DI CHKLP: CALL GETNUM ; ; AL has first char after arg ; MOV ds:[BP+DI],DX ADD DI,2
MOV ParamCt,DI ; set up count of parameters SHR ParamCt,1 ; convert to index (1-based)
CALL SKIP1 ; skip to next parameter CMP AL,"," ; is there a comma? jnz NOT_COMMA ; if not, then done with arguments
cmp di,8 ; **** maximum size of PARAM array! jb CHKLP ; continue scanning if <4 PARAMS jmp short COMERR
NOT_COMMA: DEC SI ; point at char next CALL Kill_BL ; skip all blanks CMP AL,"?" ; is there a ? JNZ DISPATCH ; no, got command letter MOV QFLG,-1 ; signal query CALL Kill_BL DISPATCH: CMP AL,5FH JBE UPCASE cmp al,"z" ja upcase AND AL,5FH UPCASE: MOV DI,OFFSET DG:COMTAB mov cx,NUMCOM REPNE SCASB JNZ COMERR
SUB DI,1+OFFSET DG:COMTAB ; convert to index MOV BX,DI MOV AX,[PARAM2] OR AX,AX JZ PARMOK CMP AX,[PARAM1] JB COMERR ; Param. 2 must be >= param 1 PARMOK: MOV [COMLINE],SI SHL BX,1 CALL [BX+TABLE] COMOVER: MOV SI,[COMLINE] CALL Kill_BL 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
SKIP1: DEC SI CALL Kill_BL ret1: return
Break <Range Checking and argument parsing>
; ; People call here. we need to reset the stack. ; Inputs: BX has param1 ; Outputs: Returns if BX <= Param2 ;
CHKRANGE: CMP [PARAM2],0 retz CMP BX,[PARAM2] JBE RET1 POP DX ; clean up return address COMERR: mov ax,BADCOM zcomerr1: call display_message jmp command
COMERR1: call std_printf JMP COMMAND
; ; GetNum parses off 1 argument from the command line. Argument forms are: ; nnn a number < 65536 ; +nnn current line + number ; -nnn current line - number ; . current line ; # lastline + 1 ; ;
GETNUM: CALL Kill_BL 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 retz OR DX,DX JZ COMERR ;Don't allow zero as a parameter return
CURLIN: cmp [fourth],1 ;the fourth parameter? je comerra ;yes, an error MOV DX,[CURRENT] LODSB return MAXLIN: cmp [fourth],1 ;the fourth parameter? je comerra ;yes, an error MOV DX,1 MOV AL,0Ah PUSH DI MOV DI,OFFSET DG:START MOV CX,EndTxt SUB CX,DI MLoop: JCXZ MDone REPNZ SCASB JNZ MDone INC DX JMP MLoop MDone: POP DI LODSB return FORLIN: cmp [fourth],1 ;the fourth parameter? je comerra ;yes, an error CALL GETNUM ADD DX,[CURRENT] return BACKLIN: cmp [fourth],1 ;the fourth parameter? je comerra ;yes, an error CALL GETNUM MOV BX,[CURRENT] SUB BX,DX JA OkLin ; if negative or zero MOV BX,1 ; use first line OkLin: MOV DX,BX return
comerra: jmp comerr
ERRORJ: JMP COMERR ERROR1J: JMP zcomerr1
BLANKLINE: cmp QFLG,0 jnz SHOWHELP ; if ? at front of blank line, do HELP jmp NOCOM ; ignore blank line otherwise
SHOWHELP: dec [COMLINE] ; point back to <cr> mov cx,num_help_msgs-1 mov ax,dsp_help SHOWHELP1: call display_message inc ax loop SHOWHELP1
; fall into display_message for last message and return
;========================================================================= ; display_message : Displays a simple common message through the ; ; message retriever, using a common parameter ; ; block.
; Inputs : ax = message number to display ; ;=========================================================================
display_message proc near
mov dg:[simple_msg],ax mov dx,offset dg:simple_msg jmp printf ; display it
display_message endp
Break <Move and Copy commands>
PUBLIC MOVE MOVE: CMP ParamCt,3 JNZ ERRORJ MOV BYTE PTR [MOVFLG],1 JMP SHORT BLKMOVE
PUBLIC COPY COPY: CMP ParamCt,3 JB ERRORJ MOV BYTE PTR [MOVFLG],0 ; ; We are to move/copy a number of lines from one range to another. ; ; Memory looks like this: ; ; START: line 1 ; ... ; pointer-> line n Current has n in it ; ... ; line m ; endtxt-> ^Z ; ; The algoritm is: ; ; Bounds check on args. ; set ptr1 and ptr2 to range before move ; set copysiz to number to move ; open up copysize * count for destination ; if destination is before ptr1 then ; add copysize * count to both ptrs ; while count > 0 do ; move from ptr1 to destination for copysize bytes ; count -- ; if moving then ; move from ptr2 through end to ptr1 ; set endtxt to last byte moved. ; set current, pointer to original destination ;
BLKMOVE: ; ; Make sure that all correct arguments are specified. ; MOV BX,[PARAM3] ; get destination of move/copy OR BX,BX ; must be specified (non-0) mov ax,DEST JZ ERROR1J ; is 0 => error ; ; get arg 1 (defaulting if necessary) and range check it. ; MOV BX,[PARAM1] ; get first argument OR BX,BX ; do we default it? JNZ NXTARG ; no, assume it is OK. MOV BX,[CURRENT] ; Defaults to the current line CALL CHKRANGE ; Make sure it is good. MOV [PARAM1],BX ; set it NXTARG: CALL FINDLIN ; find first argument line JNZ ErrorJ ; line not found MOV [PTR_1],DI ; ; get arg 2 (defaulting if necessary) and range check it. ; MOV BX,[PARAM2] ; Get the second parameter OR BX,BX ; do we default it too? JNZ HAVARGS ; Nope. MOV BX,[CURRENT] ; Defaults to the current line MOV [PARAM2],BX ; Stash it away HAVARGS: CALL FindLin JNZ ErrorJ ; line not found MOV BX,Param2 INC BX ;Get pointer to line Param2+1 CALL FINDLIN MOV [PTR_2],DI ;Save it ; ; We now have true line number arguments and pointers to the relevant places. ; ptr_1 points to beginning of region and ptr_2 points to first byte beyond ; that region. ; ; Check args for correct ordering of first two arguments ; mov dx,[param1] cmp dx,[param2] jbe havargs1 ; first must be <= second jmp comerr havargs1: ; ; make sure that the third argument is not contained in the first range ; MOV DX,[PARAM3] CMP DX,[PARAM1] ; third must be <= first or JBE NOERROR CMP DX,[PARAM2] JA NoError ; third must be > last JMP ComErr NOERROR: ; ; Determine number to move ; MOV CX,Ptr_2 SUB CX,Ptr_1 ; Calculate number of bytes to copy MOV CopySiz,CX MOV CopyLen,CX ; Save for individual move. MOV AX,[PARAM4] ; Was count defaulted? OR AX,AX JZ SizeOk ; yes, CX has correct value MUL [COPYSIZ] ; convert to true size MOV CX,AX ; move to count register OR DX,DX ; overflow? JZ SizeOK ; no JMP MEMERR ; yes, bomb. SizeOK: MOV [COPYSIZ],CX ; ; Check to see that we have room to grow by copysiz ; MOV AX,[ENDTXT] ; get pointer to last byte MOV DI,[LAST_MEM] ; get offset of last location in memory SUB DI,AX ; remainder of space CMP DI,CX ; is there at least copysiz room? JAE HAV_ROOM ; yes JMP MEMERR HAV_ROOM: ; ; Find destination of move/copy ; MOV BX,[PARAM3] CALL FINDLIN MOV [PTR_3],DI ; ; open up copysiz bytes of space at destination ; ; move (p3, p3+copysiz, endtxt-p3); ; MOV SI,EndTxt ; get source pointer to end MOV CX,SI SUB CX,DI ; number of bytes from here to end INC CX ; remember ^Z at end MOV DI,SI ; destination starts at end ADD DI,[COPYSIZ] ; plus size we are opening MOV [ENDTXT],DI ; new end point STD ; go backwards REP MOVSB ; and store everything CLD ; go forward ; ; relocate ptr_1 and ptr_2 if we moved them ; MOV BX,Ptr_3 CMP BX,Ptr_1 ; was dest before source? JA NoReloc ; no, above. no relocation MOV BX,CopySiz ADD Ptr_1,BX ADD Ptr_2,BX ; relocate pointers NoReloc: ; ; Now we copy for count times copylen bytes from ptr_1 to ptr_3 ; ; move (ptr_1, ptr_3, copylen); ; MOV BX,Param4 ; count (0 and 1 are both 1) MOV DI,Ptr_3 ; destination CopyText: MOV CX,CopyLen ; number to move MOV SI,Ptr_1 ; start point REP MOVSB ; move the bytes SUB BX,1 ; exhaust count? JG CopyText ; no, go for more ; ; If we are moving ; CMP BYTE PTR MovFlg,0 JZ CopyDone ; ; Delete the source text between ptr_1 and ptr_2 ; ; move (ptr_2, ptr_1, endtxt-ptr_2); ; MOV DI,Ptr_1 ; destination MOV SI,Ptr_2 ; source MOV CX,EndTxt ; pointer to end SUB CX,SI ; number of bytes to move CLD ; forwards REP MOVSB MOV BYTE PTR ES:[DI],1Ah ; remember ^Z terminate MOV EndTxt,DI ; new end of file ; ; May need to relocate current line (parameter 3). ; MOV BX,Param3 ; get new current line CMP BX,Param1 ; do we need to relocate JBE CopyDone ; no, current line is before removed M002 ADD BX,Param1 ; add in first SUB BX,Param2 ; current += first-last - 1; DEC BX MOV Param3,BX CopyDone: ; ; we are done. Make current line the destination ; MOV BX,Param3 ; set parameter 3 to be current CALL FINDLIN MOV [POINTER],DI MOV [CURRENT],BX return
Break <MoveFile - open up a hole in the internal file>
; ; MoveFile moves the text in the buffer to create a hole ; ; Inputs: DX is spot in buffer for destination ; DI is spot in buffer for source MOVEFILE: MOV CX,[ENDTXT] ;Get End-of-text marker MOV SI,CX SUB CX,DI ;Calculate number of bytes to copy INC CX ; remember ^Z 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 return
NAMERR: cmp ax,error_file_not_found jne otherMergeErr MOV DX,OFFSET DG:FILENM_ptr JMP COMERR1
otherMergeErr: mov ax,BADDRV jmp zcomerr1
PUBLIC MERGE MERGE: CMP ParamCt,1 JZ MergeOK JMP Comerr MergeOK: CALL KILL_BL DEC SI MOV DI,OFFSET DG:MRG_PATH_NAME XOR CX,CX CLD MRG1: LODSB CMP AL," " JE MRG2 CMP AL,9 JE MRG2 CMP AL,CR JE MRG2 CMP AL,";" JE MRG2 STOSB JMP SHORT MRG1 MRG2: MOV BYTE PTR[DI],0 DEC SI MOV [COMLINE],SI
;========================================================================= ; implement EXTENDED OPEN ;=========================================================================
push es ;an000;save reg. mov bx,ext_read ;an000;open for read mov cx,ATTR ;an000;file attributes mov dx,OPEN_FLAG ;an000;action to take on open mov di,0ffffh ;an000;null parm list call EXT_OPEN3 ;an000;create file;DMS:6/10/87 pop es ;an000;restore reg.
;=========================================================================
JC NAMERR
MOV [MRG_HANDLE],AX 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_MEM] CALL MOVEFILE MOV DX,[POINTER] MOV CX,[ENDTXT] SUB CX,[POINTER] PUSH CX MOV BX,[MRG_HANDLE] MOV AH,READ INT 21H POP DX MOV CX,AX CMP DX,CX JA FILEMRG ; M005 mov ax,mrgerr call display_message MOV CX,[POINTER] JMP SHORT RESTORE_Z FILEMRG: ADD CX,[POINTER] MOV SI,CX dec si LODSB CMP AL,1AH JNZ RESTORE_Z dec cx RESTORE_Z: MOV DI,CX MOV SI,[ENDTXT] INC SI MOV CX,[LAST_MEM] SUB CX,SI inc cx ; remember ^Z REP MOVSB dec di ; unremember ^Z MOV [ENDTXT],DI MOV BX,[MRG_HANDLE] MOV AH,CLOSE INT 21H return
PUBLIC INSERT INSERT: CMP ParamCt,1 JBE OKIns JMP ComErr OKIns: 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_MEM] 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 AX,CSTACK MOV SS,AX MOV SP,STACK STI CALL CRLF CALL ENDINS JMP COMOVER
ENDINS: CALL END_INS return
END_INS: MOV BP,[ENDTXT] MOV DI,[POINTER] MOV SI,BP INC SI MOV CX,[LAST_MEM] 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 return
FILLBUF: MOV [PARAM1],-1 ;Read in max. no of lines MOV ParamCt,1 CALL APPEND MOV Param1,0 PUBLIC ENDED ENDED:
;Write text out to .$$$ file
CMP ParamCt,1 JZ ENDED1 CERR: JMP ComErr Ended1: CMP Param1,0 JNZ Cerr 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 CX,1 MOV BX,[WRT_HANDLE] MOV AH,WRITE INT 21H ;Write end-of-file byte
;Close input file ; MZ 11/30 ; MZ 11/30 MOV BX,[RD_HANDLE] ; MZ 11/30 MOV AH,CLOSE ; MZ 11/30 INT 21H ; MZ 11/30
;Close .$$$ file
MOV BX,[WRT_HANDLE] MOV AH,CLOSE INT 21H
;Rename original file .BAK
MOV DI,[EXT_PTR] MOV SI,OFFSET DG:BAK MOVSW MOVSW MOVSB MOV DX,OFFSET DG:PATH_NAME MOV DI,OFFSET DG:TEMP_PATH MOV AH,RENAME INT 21H MOV DI,[EXT_PTR] MOV SI,OFFSET DG:$$$FILE MOVSW MOVSW MOVSB
;Rename .$$$ file to original name
MOV DX,OFFSET DG:TEMP_PATH MOV DI,OFFSET DG:PATH_NAME MOV AH,RENAME INT 21H ; mode mov ah,exit xor al,al int 21h
;========================================================================= ; EDLIN_DISP_GET: This routine will give us the attributes of the ; current display, which are to be used to restore the screen ; back to its original state on exit from EDLIN. We also ; set the screen to a text mode here with an 80 X 25 color ; format. ; ; Inputs : VIDEO_GET - 0fH (get current video mode) ; VIDEO_SET - 00h (set video mode) ; VIDEO_TEXT- 03h (80 X 25 color mode) ; ; Outputs : VIDEO_ORG - Original video attributes on entry to EDLIN ; ;=========================================================================
EDLIN_DISP_GET proc near ;an000;video attributes
push ax ;an000;save affected regs. push bx ;an000; push cx ;an000; push dx ;an000; push si ;an000; push ds ;an000;
push cs ;an000;exchange cs/ds pop ds ;an000;
mov ax,440Ch ;an000;generic ioctl mov bx,Std_Out ;an000;Console mov cx,(Display_Attr shl 8) or Get_Display ;an000;get display mov dx,offset dg:Video_Buffer ;an000;buffer for video attr. int 21h ;an000; ; $if nc ;an000;function returned a JC $$IF15 ; buffer mov si,dx ;an000;get pointer mov ax,word ptr dg:[si].Display_Length_Char ;an000;get video len. dec ax ;an000;allow room for message mov dg:Disp_Len,al ;an000;put it into var. mov ax,word ptr dg:[si].Display_Width_Char ;an000;get video width mov dg:Disp_Width,al ;an000;put it into var. ; $else ;an000;function failed use JMP SHORT $$EN15 $$IF15: ; default values mov al,Def_Disp_Len ;an000;get default length dec al ;an000;leave room for messages mov dg:Disp_Len,al ;an000;use default length mov dg:Disp_Width,Def_Disp_Width;an000;use default width ; $endif ;an000; $$EN15:
pop ds ;an000;restore affected regs. pop si ;an000; pop dx ;an000; pop cx ;an000; pop bx ;an000; pop ax ;an000;
ret ;an000;return to caller
EDLIN_DISP_GET endp ;an000;end proc.
;========================================================================= ; EXT_OPEN1 : This routine opens a file for read/write access. If the file ; if not present for opening the open will fail and return with a ; carry set. ; ; Inputs : BX - Open mode ; CX - File attributes ; DX - Open action ; ; Outputs: CY - If error ; ; Date : 6/10/87 ;=========================================================================
EXT_OPEN1 proc near ;an000;open for R/W
assume ds:dg push ds ;an000;save regs push si ;an000;
mov ah,ExtOpen ;an000;extended open mov al,0 ;an000;reserved by system mov si,offset dg:path_name ;an000;point to PATH_NAME
int 21h ;an000;invoke function pop si ;an000;restore regs pop ds ;an000;
ret ;an000;return to caller
EXT_OPEN1 endp ;an000;end proc.
;========================================================================= ; EXT_OPEN2 : This routine will attempt to create a file for read/write ; access. If the files exists the create will fail and return ; with the carry set. ; ; Inputs : BX - Open mode ; CX - File attributes ; DX - Open action ; ; Outputs: CY - If error ; ; Date : 6/10/87 ;=========================================================================
EXT_OPEN2 proc near ;an000;create a file
assume ds:dg push ds ;an000;save regs push si ;an000;
mov ah,ExtOpen ;an000;extended open mov al,0 ;an000;reserved by system mov si,offset dg:temp_path ;an000;point to TEMP_PATH
int 21h ;an000;invoke function
pop si ;an000;restore regs pop ds ;an000;
ret ;an000;return to caller
EXT_OPEN2 endp ;an000;end proc.
;========================================================================= ; EXT_OPEN3 : This routine will attempt to create a file for read ; access. If the files exists the create will fail and return ; with the carry set. ; ; Inputs : BX - Open mode ; CX - File attributes ; DX - Open action ; ; Outputs: CY - If error ; ; Date : 6/10/87 ;=========================================================================
EXT_OPEN3 proc near ;an000;create a file
assume ds:dg push ds ;an000;save regs push si ;an000;
mov ah,ExtOpen ;an000;extended open mov al,0 ;an000;reserved by system mov si,offset dg:mrg_path_name ;an000;point to mrg_path_name
int 21h ;an000;invoke function
pop si ;an000;restore regs pop ds ;an000;
ret ;an000;return to caller
EXT_OPEN3 endp ;an000;end proc.
;========================================================================= ; EDLIN_COMMAND : This routine provides an interface between the new ; parser and the existing logic of EDLIN. We will be ; interfacing the parser with three existing variables. ; ; Inputs : FILESPEC - Filespec entered by the user and passed by ; the parser. ; ; PARSE_SWITCH_B - Contains the result of the parse for the ; /B switch. This is passed by the parser. ; ; Outputs: PATH_NAME - Filespec ; LOADMOD - Flag for /B switch ; FNAME_LEN - Length of filespec ; ; Date : 6/11/87 ;=========================================================================
EDLIN_COMMAND proc near ;an000;interface parser
push ax ;an000;save regs. push cx ;an000; push di ;an000 push si ;an000;
mov si,offset dg:filespec ;an000;get its offset mov di,offset dg:path_name ;an000;get its offset
mov cx,00h ;an000;cx will count filespec ; length cmp parse_switch_b,true ;an000;do we have /B switch ; $if z ;an000;we have the switch JNZ $$IF18 mov [LOADMOD],01h ;an000;signal switch found ; $endif ;an000 $$IF18:
; $do ;an000;while we have filespec $$DO20: lodsb ;an000;move byte to al cmp al,nul ;an000;see if we are at ; the end of the ; filespec ; $leave e ;an000;exit while loop JE $$EN20 stosb ;an000;move byte to path_name inc cx ;an000;increment the length ; of the filespec ; $enddo ;an000;end do while JMP SHORT $$DO20 $$EN20:
mov [FNAME_LEN],cx ;an000;save filespec's length
pop si ;an000; restore regs pop di ;an000; pop cx ;an000; pop ax ;an000;
ret ;an000;return to caller
EDLIN_COMMAND endp ;an000;end proc
;========================================================================= ; Calc_Memory_Avail : This routine will calculate the memory ; available for use by EDLIN. ; ; Inputs : ORG_DS - DS of PSP ; ; Outputs : DX - paras available ;=========================================================================
Calc_Memory_Avail proc near ;an000; dms;
push ds ;save ds for size calc push cx ;an000; dms; push di ;an000; dms;
mov ds,cs:[org_ds] MOV CX,DS:[2] MOV DI,CS SUB CX,DI mov dx,cx ;an000; dms;put paras in DX
pop di ;an000; dms; pop cx ;an000; dms; pop ds ;an000; dms;
ret ;an000; dms;
Calc_Memory_Avail endp ;an000; dms;
;========================================================================= ; EA_Fail_Exit : This routine tells the user that there was ; Insufficient memory and exits EDLIN. ; ; Inputs : MemFul_Ptr - "Insufficient memory" ; ; Outputs : message ;=========================================================================
EA_Fail_Exit proc near ;an000; dms;
mov dx,offset dg:MemFul_Ptr ;an000; dms;"Insufficient
push cs ;an000; dms;xchange ds/cs pop ds ;an000; dms; ; memory" call Std_Printf ;an000; dms;print message mov ah,exit ;an000; dms;exit xor al,al ;an000; dms;clear al int 21h ;an000; dms; ret ;an000; dms;
EA_Fail_Exit endp ;an000; dms;
CODE ENDS END EDLIN
|