1885 lines
44 KiB
NASM
1885 lines
44 KiB
NASM
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
|
||
|
||
|