You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1885 lines
44 KiB
1885 lines
44 KiB
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
|
|
|
|
|