]>
wirehaze git hosting - MS-DOS.git/blob - v1.25/source/COMMAND.ASM
3 ; This version of COMMAND is divided into three distinct parts. First
4 ; is the resident portion, which includes handlers for interrupts
5 ; 22H (terminate), 23H (Cntrl-C), 24H (fatal error), and 27H (stay
6 ; resident); it also has code to test and, if necessary, reload the
7 ; transient portion. Following the resident is the init code, which is
8 ; overwritten after use. Then comes the transient portion, which
9 ; includes all command processing (whether internal or external).
10 ; The transient portion loads at the end of physical memory, and it may
11 ; be overlayed by programs that need as much memory as possible. When
12 ; the resident portion of command regains control from a user program,
13 ; a checksum is performed on the transient portion to see if it must be
14 ; reloaded. Thus programs which do not need maximum memory will save
15 ; the time required to reload COMMAND when they terminate.
17 ;Use the following booleans to set assembly flags
21 IBMVER EQU FALSE
;Switch to build IBM version of Command
22 MSVER EQU TRUE
;Switch to build MS-DOS version of Command
24 HIGHMEM EQU TRUE
;Run resident part above transient (high memory)
70 ;The following are all of the segments used in the load order
90 TRANSPACE
SEGMENT BYTE
93 RESGROUP GROUP CODERES
,DATARES
,INIT
,TAIL
94 TRANGROUP GROUP TRANCODE
,TRANDATA
,TRANSPACE
96 ;Data for resident portion
101 MESBAS
DW OFFSET RESGROUP
:ERR0
102 DW OFFSET RESGROUP
:ERR2
103 DW OFFSET RESGROUP
:ERR4
104 DW OFFSET RESGROUP
:ERR6
105 DW OFFSET RESGROUP
:ERR8
106 DW OFFSET RESGROUP
:ERR10
107 DW OFFSET RESGROUP
:ERR12
108 ERR0
DB "Write protect$"
112 ERR8
DB "Sector not found$"
113 ERR10
DB "Write fault$"
122 REQUEST
DB "Abort, Retry, Ignore? $"
123 BADFAT
DB 13,10,"File allocation table bad,$"
124 COMBAD
DB 13,10,"Invalid COMMAND.COM"
125 NEEDCOM
DB 13,10,"Insert DOS disk in "
131 PROMPT
DB 13,10,"and strike any key when ready",13,10,"$"
132 NEEDBAT
DB 13,10,"Insert disk with batch file$"
133 ENDBATMES
DB 13,10,"Terminate batch job (Y/N)? $"
135 BATFCB
DB 1,"AUTOEXECBAT"
138 DW 0 ;Initialize RR field to zero
139 PARMTAB
DW 10 DUP(-1) ;No parameters initially
140 BATCH
DB 1 ;Assume batch mode initially
141 COMFCB
DB COMDRV
,"COMMAND COM"
143 TRANS
DW OFFSET TRANGROUP
:COMMAND
149 RESDATASIZE EQU
$-ZERO
152 ;Data for transient portion
154 TRANDATA
SEGMENT BYTE
157 BADNAM
DB "Bad command or file name",13,10,"$"
158 MISNAM
DB "Missing file name$"
159 RENERR
DB "Duplicate file name or "
160 NOTFND
DB "File not found$"
161 EXEBAD
DB "Error in EXE file$"
162 NOSPACE
DB "Insufficient disk space",13,10,"$"
163 FULDIR
DB "File creation error",13,10,"$"
164 OVERWR
DB "File cannot be copied onto itself",13,10,"$"
165 LOSTERR
DB "Content of destination lost before copy",13,10,"$"
166 COPIED
DB " File(s) copied$"
167 DIRMES
DB " File(s)$"
168 TOOBIG
DB "Program too big to fit in memory$"
169 BADDRV
DB "Invalid drive specification$"
170 PAUSMES
DB "Strike a key when ready . . . $"
171 BADSWT
DB "Illegal switch",13,10,"$"
172 WEEKTAB
DB "SunMonTueWedThuFriSat"
173 BADDAT
DB 13,10,"Invalid date$"
174 CURDAT
DB "Current date is $"
175 NEWDAT
DB 13,10,"Enter new date: $"
176 BADTIM
DB 13,10,"Invalid time$"
177 CURTIM
DB "Current time is $"
178 NEWTIM
DB 13,10,"Enter new time: $"
179 SUREMES
DB "Are you sure (Y/N)? $"
182 DW OFFSET TRANGROUP
:CATALOG
184 DW OFFSET TRANGROUP
:RENAME
186 DW OFFSET TRANGROUP
:RENAME
188 DW OFFSET TRANGROUP
:ERASE
190 DW OFFSET TRANGROUP
:ERASE
192 DW OFFSET TRANGROUP
:TYPEFIL
194 DW OFFSET TRANGROUP
:COMMAND
196 DW OFFSET TRANGROUP
:COPY
198 DW OFFSET TRANGROUP
:PAUSE
200 DW OFFSET TRANGROUP
:DATE
202 DW OFFSET TRANGROUP
:TIME
203 DB 0 ;Terminate command table
207 TRANDATASIZE EQU
$-ZERO
210 ;Uninitialized transient data
211 TRANSPACE
SEGMENT BYTE
238 DESTNAME
DB 11 DUP(?
)
243 ;Header variables for EXE file load
244 ;These are overlapped with COPY variables, below
260 RUNVARSIZ EQU
$-RUNVAR
265 PRETRLEN EQU
$-ZERO
;Used later to compute TRNLEN
267 ORG RUNVAR
-ZERO
;Overlaps EXE variables
276 TRANSPACESIZE EQU
$-ZERO
280 ;START OF RESIDENT PORTION
283 ASSUME
CS:RESGROUP
,DS:RESGROUP
,ES:RESGROUP
,SS:RESGROUP
295 LTPA
DW 0 ;WILL STORE TPA SEGMENT HERE
296 MYSEG
DW 0 ;Put our own segment here
302 MOV SP,OFFSET RESGROUP
:RSTACK
306 INT 33 ;Reset disks in case files were open
310 MOV DX,OFFSET RESGROUP
:ENDBATMES
324 MOV SP,OFFSET RESGROUP
:RSTACK
340 MOV SI,OFFSET RESGROUP
:LTPA
341 MOV DI,OFFSET TRANGROUP
:TPA
344 MOVSW ;Move TPA segment to transient storage
345 MOVSW ;Move resident segment too
347 MOV WORD PTR ES:[2],AX
348 JMP DWORD PTR [TRANS
]
353 SHR DX,CL ;Number of paragraphs of new addition
357 JMP DWORD PTR DS:[80H
] ;Pretend user executed INT 20H
360 ;******************************************************
361 ; THIS IS THE DEFAULT DISK ERROR HANDLING CODE
362 ; AVAILABLE TO ALL USERS IF THEY DO NOT TRY TO
363 ; INTERCEPT INTERRUPT 24H.
364 ;******************************************************
368 POP DS ;Set up local data segment
372 ADD AL,"A" ;Compute drive letter
374 TEST AH,80H
;Check if hard disk error
376 MOV SI,OFFSET RESGROUP
:READ
379 MOV SI,OFFSET RESGROUP
:WRITE
382 MOV WORD PTR [IOTYP
],AX
384 MOV WORD PTR [IOTYP
+2],AX
390 MOV DI,WORD PTR [DI+MESBAS
] ;Get pointer to error message
391 XCHG DI,DX ;May need DX later
393 INT 33 ;Print error type
394 MOV DX,OFFSET RESGROUP
:ERRMES
399 MOV DX,OFFSET RESGROUP
:REQUEST
405 OR AL,20H
;Convert to lower case
406 MOV AH,0 ;Return code for ignore
422 MOV DX,OFFSET RESGROUP
:BADFAT
425 MOV DX,OFFSET RESGROUP
:DRVNUM
432 MOV DX,OFFSET RESGROUP
:NEEDCOM
435 MOV AX,0C07H ;Get char without testing or echo
440 MOV DX,OFFSET RESGROUP
:NEWLIN
454 MOV DX,OFFSET RESGROUP
:COMFCB
456 INT 33 ;Open COMMAND.COM
459 MOV DX,OFFSET RESGROUP
:NEEDCOM
463 MOV AX,0C07H ;Get char without testing or echo
467 MOV WORD PTR[COMFCB
+RR
],OFFSET RESGROUP
:TRANSTART
469 MOV WORD PTR[COMFCB
+RR
+2],AX
470 MOV [COMFCB
],AL ;Use default drive
472 MOV WORD PTR[COMFCB
+RECLEN
],AX
474 MOV DX,OFFSET RESGROUP
:COMFCB
480 MOV DX,OFFSET RESGROUP
:COMBAD
499 MOV DX,OFFSET RESGROUP
:LODCOM
500 MOV AX,2522H
;Set Terminate address
502 MOV DX,OFFSET RESGROUP
:CONTC
503 MOV AX,2523H
;Set Ctrl-C address
505 MOV DX,OFFSET RESGROUP
:DSKERR
506 MOV AX,2524H
;Set Hard Disk Error address
508 MOV DX,OFFSET RESGROUP
:RESIDENT
509 MOV AX,2527H
;Set Terminate and Stay Resident address
512 RESCODESIZE EQU
$-ZERO
515 ;*******************************************************************
516 ;START OF INIT PORTION
517 ;This code is overlayed the first time the TPA is used.
524 MOV SP,OFFSET RESGROUP
:RSTACK
527 MOV AX,WORD PTR DS:[2]
528 SUB AX,((RESCODESIZE
+RESDATASIZE
)+15)/16 ;Subtract size of resident
529 MOV WORD PTR DS:[2],AX
533 MOV CX,((RESCODESIZE
+RESDATASIZE
)-100H
+1)/2 ;Length of resident in words
534 REP MOVSW ;Move to end of memory
541 ADD AX,((RESCODESIZE
+RESDATASIZE
)+15)/16 ;Compute segment of TPA
543 MOV AX,WORD PTR DS:[2]
548 SUB AX,TRNLEN
;Subtract size of transient
561 MOV DX,OFFSET RESGROUP
:HEADER
569 MOV DX,OFFSET RESGROUP
:BATFCB
571 INT 33 ;See if AUTOEXEC.BAT exists
572 MOV WORD PTR[BATFCB
+RECLEN
],1 ;Set record length to 1
573 OR AL,AL ;Zero means file found
575 MOV [BATCH
],0 ;Not found--turn off batch job
576 MOV AX,OFFSET TRANGROUP
:DATINIT
577 MOV WORD PTR[INITADD
],AX
579 MOV WORD PTR[INITADD
+2],AX
580 CALL DWORD PTR DS:[INITADD
]
583 MOV DX,OFFSET RESGROUP
:HEADER
593 HEADER
DB 13,10,"Command v. 1.17"
601 HEADER
DB 13,10,13,10,"The IBM Personal Computer DOS",13,10
602 DB "Version 1.10 (C)Copyright IBM Corp 1981, 1982",13,10,"$"
603 DB "Licensed Material - Program Property of IBM"
609 ;This TAIL segment is used to produce a PARA aligned label in the resident
610 ; group which is the location where the transient segments will be loaded
618 ;********************************************************************
619 ;START OF TRANSIENT PORTION
620 ;This code is loaded at the end of memory and may be overwritten by
621 ;memory-intensive user programs.
623 TRANCODE
SEGMENT PARA
624 ASSUME
CS:TRANGROUP
,DS:TRANGROUP
,ES:TRANGROUP
,SS:TRANGROUP
626 WSWITCH EQU
1 ;Wide display during DIR
627 PSWITCH EQU
2 ;Pause (or Page) mode during DIR
628 VSWITCH EQU
4 ;Verify during COPY
629 ASWITCH EQU
8 ;ASCII mode during COPY
630 BSWITCH EQU 10H
;Binary mode during COPY
635 ORG 100H
;Allow for 100H parameter area
644 MOV SP,OFFSET TRANGROUP
:STACK
650 INT 33 ;Turn off verify after write
651 MOV AX,CS ;Get segment we're in
652 SUB AX,[TPA
] ;AX=size ot TPA in paragraphs
654 MUL DX ;DX:AX=size of TPA in bytes
655 OR DX,DX ;See if over 64K
657 MOV AX,-1 ;If so, limit to 65535 bytes
659 MOV [BYTCNT
],AX ;Max no. of bytes that can be buffered
666 CALL OUT ;Print letter for default drive
669 MOV DS,[RESSEG
] ;All batch work must use resident seg.
674 POP DS ;Need local segment to point to buffer
676 MOV DX,OFFSET TRANGROUP
:COMBUF
678 INT 21H
;Get a command
681 ;All batch proccessing has DS set to segment of resident portion
685 CMP AL,"%" ;Check for two consecutive %
687 CMP AL,13 ;Check for end-of-line
690 JB RDBAT
;Ignore parameter reference if invalid
695 SHL SI,1 ;Two bytes per entry
696 MOV SI,[SI+OFFSET RESGROUP
:PARMTAB
] ;Get pointer to corresponding parameter
697 CMP SI,-1 ;Check if parameter exists
698 JZ RDBAT
;Ignore if it doesn't
701 LODSB ;From resident segment
702 CMP AL,0DH ;Check for end of parameter
704 STOSB ;To transient segment
706 INT 33 ;Display paramters too
711 MOV DX,OFFSET RESGROUP
:NEEDBAT
712 INT 33 ;Prompt for batch file
714 MOV DX,OFFSET RESGROUP
:PROMPT
723 MOV DX,OFFSET RESGROUP
:BATFCB
725 INT 33 ;Make sure batch file still exists
727 JNZ PROMPTBAT
;If OPEN fails, prompt for disk
728 MOV WORD PTR [BATFCB
+RECLEN
],1
729 MOV DX,OFFSET RESGROUP
:BATBYT
732 MOV DI,OFFSET TRANGROUP
:COMBUF
+2
735 CMP AL,"%" ;Check for parameter
739 CALL OUT ;Display batched command line
742 SUB DI,OFFSET TRANGROUP
:COMBUF
+3
744 MOV ES:[COMBUF
+1],AL ;Set length of line
745 CALL GETBATBYT
;Eat linefeed
747 POP DS ;Go back to local segment
750 ;All segments are local for command line processing
753 MOV SI,OFFSET TRANGROUP
:COMBUF
+2
754 MOV DI,OFFSET TRANGROUP
:IDLEN
755 MOV AX,2901H
;Make FCB with blank scan-off
757 CMP AL,1 ;Check for ambiguous command name
758 JZ BADCOMJ1
;Ambiguous commands not allowed
768 REPNE SCASB ;Count no. of letters in command name
777 STOSB ;Move command tail to 80H
781 MOV BYTE PTR DS:[80H
],CL
783 ;If the command has 0 parameters must check here for
784 ;any switches that might be present.
785 ;SI -> first character after the command.
786 MOV [FLAGER
],0 ;Set error flag before any calls to switch
787 CALL SWITCH
;Is the next character a "/"
792 MOV [PARM1
],AL ;Save result of parse
797 INT 21H
;Parse file name
798 MOV [PARM2
],AL ;Save result
803 OR DL,DL ;Check if drive was specified
806 OK: DEC AL ;Check for null command
811 XCHG AX,BX ;Put switches in AX
815 XOR BX,BX ;Initialize - no switches set
817 CALL SCANOFF
;Skip any delimiters
818 CMP AL,"/" ;Is it a switch specifier?
819 JNZ RETSW
;No -- we're finished
820 INC SI ;Skip over "/"
823 ;Convert lower case input to upper case
828 SUB AL,20H
;Lower-case changed to upper-case
830 MOV DI,OFFSET TRANGROUP
:SWLIST
832 REPNE SCASB ;Look for matching switch
835 SHL AX,CL ;Set a bit for the switch
840 MOV [FLAGER
],1 ;Record error in switch
847 MOV DX,OFFSET TRANGROUP
:BADDRV
851 MOV SI,OFFSET TRANGROUP
:COMTAB
;Prepare to search command table
854 MOV DI,OFFSET TRANGROUP
:IDLEN
859 ADD SI,CX ;Bump to next position without affecting flags
861 LODSB ;Get flag for drive check
863 LODSW ;Get address of command
869 OR AL,[PARM2
] ;Check if either parm. had invalid drive
881 DEC DL ;Adjust for correct drive number
882 DEC AL ;Check if anything else is on line
887 MOV WORD PTR[COM
],4F00H
+"C" ;"CO"
888 MOV BYTE PTR[COM
+2],"M"
889 MOV DX,OFFSET TRANGROUP
:IDLEN
891 INT 33 ;Check if command to be executed
892 MOV [FILTYP
],AL ;0 for COM files, -1 for EXE files
895 MOV WORD PTR[COM
],5800H
+"E" ;"EX"
896 MOV BYTE PTR[COM
+2],"E"
897 INT 33 ;Check for EXE file
900 MOV WORD PTR[COM
],4100H
+"B" ;"BA"
901 MOV BYTE PTR[COM
+2],"T"
902 INT 33 ;Check if batch file to be executed
906 ;Batch parameters are read with ES set to segment of resident part
909 MOV DI,OFFSET RESGROUP
:PARMTAB
912 REP STOSW ;Zero parameter pointer table
913 MOV SI,OFFSET TRANGROUP
:COMBUF
+2
914 MOV DI,OFFSET RESGROUP
:PARMBUF
915 MOV BX,OFFSET RESGROUP
:PARMTAB
920 MOV ES:[BX],DI ;Set pointer table to point to actual parameter
926 JZ ENDPARM
;Check for end of parameter
933 STOSB ;End-of-parameter marker
934 CMP BX,OFFSET RESGROUP
:PARMTAB
+20 ;Maximum number of parameters?
937 MOV SI,OFFSET TRANGROUP
:IDLEN
938 MOV DI,OFFSET RESGROUP
:BATFCB
940 REP MOVSW ;Move into private batch FCB
943 POP DS ;Simply batch FCB setup
945 MOV WORD PTR[BATFCB
+RR
],AX
946 MOV WORD PTR[BATFCB
+RR
+2],AX ;Zero RR field
948 MOV WORD PTR[BATFCB
+RECLEN
],AX ;Set record length to 1 byte
949 MOV [BATCH
],AL ;Flag batch job in progress
951 ASSUME
DS:TRANGROUP
,ES:TRANGROUP
954 MOV AX,WORD PTR[IDLEN
+16]
955 OR AX,WORD PTR[IDLEN
+18] ;See if zero length
956 JZ BADCOM
;If so, error
958 MOV WORD PTR[IDLEN
+RR
],AX
959 MOV WORD PTR[IDLEN
+RR
+2],AX ;Set RR field to zero
961 MOV WORD PTR[IDLEN
+RECLEN
],AX ;Set record length field to 1
966 TEST [FILTYP
],-1 ;Check if file is COM or EXE
977 MOV DX,OFFSET TRANGROUP
:IDLEN
981 MOV DX,OFFSET TRANGROUP
:TOOBIG
983 ;Set up exit conditions
991 SUB CX,100H
;Allow some stack space
1002 MOV DX,OFFSET TRANGROUP
:BADNAM
1011 MOV DX,OFFSET TRANGROUP
:NOTFND
1015 ;Make sure last line ends with CR/LF
1017 CMP AL,[LINCNT
] ;Will be equal if just had CR/LF
1024 MOV DX,OFFSET TRANGROUP
:DIRMES
1030 MOV AL,"?" ;*.* is default file spec.
1037 MOV AX,41*100H
+0DH ;Parse with default name and extension
1040 ;Begin by processing any switches that may have been specified.
1041 ;BITS will contain any information about switches that was
1042 ;found when the command line was parsed.
1045 MOV AX,[COMSW
] ;Get switches from command
1046 OR AX,[ARG1S
] ;OR in switches from first parameter
1048 MOV BYTE PTR[FULLSCR
],LINPERPAG
1049 TEST AL,1 ;Look for /W
1054 MOV [LINLEN
],AL ;Set number of entries per line
1056 MOV [FILECNT
],0 ;Keep track of how many files found
1057 MOV DX,OFFSET TRANGROUP
:DIRBUF
;Set Disk transfer address
1062 MOV DX,5
CH ;DX -> Unopened FCB
1063 INT 21H
;Search for a file to match FCB
1064 INC AL ;FF = file not found
1065 JNZ AGAIN
;Either an error or we are finished
1068 INC [FILECNT
] ;Keep track of how many we find
1069 MOV SI,OFFSET TRANGROUP
:DIRBUF
+1 ;SI -> information returned by sys call
1071 TEST BYTE PTR[BITS
],1 ;/W set?
1072 JNZ NEXENT
;If so, no size, date, or time
1073 CALL DISPSIZE
;Print size of file
1075 MOV AX,WORD PTR[DIRBUF
+25] ;Get date
1077 JZ NEXENT
;Skip if no date
1080 SHR AX,CL ;Align month
1082 MOV BH,"0"-" " ;Enable zero suppression
1087 AND AL,1FH
;Mask to day
1092 SHR AL,1 ;Align year
1093 ADD AX,80 ;Relative 1980
1099 MOV BX,WORD PTR[DIRBUF
+23] ;Get time
1100 OR BX,BX ;Time field present?
1107 SHR BL,1 ;Hours in BH, minutes in BL
1109 MOV DH,"a" ;Assume A.M.
1110 CMP AL,12 ;In the afternoon?
1114 SUB AL,12 ;Keep it to 12 hours or less
1116 OR AL,AL ;Before 1 am?
1120 MOV BH,"0"-" " ;Enable zero suppression
1124 MOV AL,BL ;Output minutes
1126 MOV AL,DH ;Get "a" or "p"
1135 TEST BYTE PTR[BITS
],2 ;/P switch present?
1136 JZ SCROLL
;If not, just continue
1137 DEC BYTE PTR[FULLSCR
]
1139 MOV BYTE PTR[FULLSCR
],LINPERPAG
1141 MOV DX,OFFSET TRANGROUP
:PAUSMES
1143 MOV AX,0C08H ;Wait for any character to be typed
1151 MOV AL,9 ;Output a tab
1179 MOV SI,WORD PTR[DIRBUF
+29]
1180 MOV DI,WORD PTR[DIRBUF
+31]
1182 ;Prints the 32-bit number DI:SI on the console in decimal. Uses a total
1183 ;of 9 digit positions with leading blanks.
1199 ; Conversion complete. Print 9-digit number.
1200 MOV CX,1810H
;Allow leading zero blanking for 8 digits
1253 MOV DX,OFFSET TRANGROUP
:SUREMES
;"Are you sure (Y/N)?"
1267 MOV BX,OFFSET TRANGROUP
:NOTFND
1268 CMP BYTE PTR DS:[FCB
+1]," " ;Check if parameter exists
1272 MOV BX,OFFSET TRANGROUP
:RENERR
1273 CMP BYTE PTR DS:[FCB
+16+1]," " ;Check if parameter exists
1275 MOV DX,OFFSET TRANGROUP
:MISNAM
1276 JZ ERRJ
;Error if missing parameter
1295 MOV DX,OFFSET TRANGROUP
:NOTFND
1298 MOV WORD PTR DS:[FCB
+RR
],AX ;Set RR field
1299 MOV WORD PTR DS:[FCB
+RR
+2],AX
1301 MOV WORD PTR DS:[FCB
+RECLEN
],AX ;Set record length
1309 XOR SI,SI ;Start at 0 in TPA
1311 LODS BYTE PTR ES:[SI] ;In TPA segment
1320 RET30: RET ;Need a nearby RET
1324 MOV [PLUS
],AL ;Will keep track of "+"s
1326 MOV SI,81H
;Point to input line
1327 CALL SWITCH
;Skip over switches on command
1330 CALL PARSNAM
;Scan first source
1331 MOV [PARM1
],DL ;Save ambiguous flag
1332 MOV [SRCPT
],SI ;Save pointer to command line
1333 ;Parse each name to find destination and check for /V switch
1338 MOV DI,OFFSET TRANGROUP
:DEST
1339 MOV BX,BP ;Remeber switches so far
1340 XOR BP,BP ;Must have dest. swtiches alone
1342 MOV [ARG2S
],BP ;Remember switches on destination
1343 JNZ HAVDESTNAM
;File name present?
1344 INC DI ;Point to file name spot
1345 MOV AL,"?" ;Substitute *.*
1349 OR BX,BP ;BX = all switches combined
1350 AND BL,VSWITCH
;Verify requested?
1352 MOV AX,46*100H
+1 ;Set verify
1356 MOV DI,OFFSET TRANGROUP
:DESTNAME
1357 MOV SI,OFFSET TRANGROUP
:DEST
+1
1359 CALL BUILDNAME
;See if we can make it unambiguous
1360 MOV DI,OFFSET TRANGROUP
:DESTNAME
1363 REPNE SCASB ;Scan for "?" to see if ambiguous
1364 MOV AL,1 ;Flag if ambig.
1366 DEC AX ;AL=0 if unambig.
1369 MOV AH,[PLUS
] ;1=found "+"
1370 XOR AL,1 ;0=ambig, 1=unambig destination
1371 AND AL,[PARM1
] ;Source ambig. AND dest unambig.
1372 OR AL,AH ;OR found "+" means concatenation
1373 MOV [ASCII
],AL ;Concatenation implies ASCII mode
1374 MOV [INEXACT
],AL ;ASCII implies inexact copy
1376 OR AL,DL ;Combine multiple and concat flags
1378 MOV AL,BYTE PTR[COMSW
]
1379 CALL SETASC
;Check /A,/B on command
1380 MOV AL,BYTE PTR[ARG1S
]
1381 CALL SETASC
;Check for ASCII on first filename
1382 MOV BYTE PTR[COMSW
],AL ;Save starting switch values
1384 CALL SEARCH
;Search for first source name
1386 JZ FIRSTSRC
;Find a first source name?
1387 TEST [PARM2
],1 ;If multiple, we're done
1391 MOV [CFLAG
],AL ;Flag nothing read yet
1395 CALL PARSESRC
;Parse next file name into FCB
1396 MOV [PARM1
],DL ;Remember if it's ambiguous
1400 CALL SEARCH
;Search for new file name
1401 JNZ NEXTSNG
;If none, skip it and move to next name
1405 CALL SEARCHNEXT
;See if any more of this name
1415 MOV DX,OFFSET TRANGROUP
:COPIED
1418 JMP COMMAND
;Stack could be messed up
1421 MOV SI,OFFSET TRANGROUP
:DIRBUF
+1
1422 MOV DI,OFFSET TRANGROUP
:SOURCE
1424 REP MOVSB ;Copy first source name to SOURCE
1425 MOV SI,OFFSET TRANGROUP
:DESTNAME
1426 MOV DI,OFFSET TRANGROUP
:DEST
+1
1427 MOV BX,OFFSET TRANGROUP
:SOURCE
1428 CALL BUILDNAME
;Build destination name
1434 TEST [PARM2
],1 ;Multiple destinations?
1436 MOV SI,OFFSET TRANGROUP
:DIRBUF
+1
1437 CALL SHONAME
;If so, show first source
1440 CALL COMPNAME
;Source and dest. the same?
1441 JNZ DOREAD
;If not, read source in
1442 TEST [PARM2
],2 ;Concatenation?
1443 MOV DX,OFFSET TRANGROUP
:OVERWR
1444 JZ COPERRJ
;If not, overwrite error
1445 MOV [APPEND
],1 ;Set physical append
1447 MOV DX,OFFSET TRANGROUP
:DEST
1448 INT 33 ;Open (existing) destination
1449 CMP [ASCII
],0 ;ASCII flag set?
1451 ;ASCII append. Must find logical EOF, then seek there with dest. FCB
1453 CALL READIN
;Find EOF
1454 CALL FLSHFIL
;Seek there
1456 CALL FLSHFIL
;Truncate file
1459 SNGLOOPJ:JMP SNGLOOP
1464 MOV WORD PTR[DEST
+RECLEN
],1 ;Set record length to 1
1465 MOV SI,OFFSET TRANGROUP
:DEST
+16 ;Point to file size
1466 MOV DI,OFFSET TRANGROUP
:DEST
+RR
1468 MOVSW ;Seek to end of file
1474 TEST [PARM2
],1 ;Single or multiple destinations?
1481 MOV SI,OFFSET TRANGROUP
:DIRBUF
+1
1483 MOV BX,OFFSET TRANGROUP
:SOURCE
1490 MOV AL,BYTE PTR[COMSW
]
1491 MOV [ASCII
],AL ;Restore ASCII flag
1496 MOV DI,OFFSET TRANGROUP
:DIRBUF
1501 MOV [PLUS
],1 ;Keep track of "+" signs
1502 INC SI ;Skip over it
1505 INT 33 ;Parse file name
1507 MOV DX,OFFSET TRANGROUP
:BADDRV
1509 XCHG AX,DX ;Save parse flag in DL
1510 MOV AL,BYTE PTR[DI] ;Get drive number
1511 OR AL,AL ;Is it default?
1513 MOV AL,[CURDRV
] ;Substitute actual drive
1519 CALL SWITCH
;Process switches
1520 OR BP,AX ;Combine all switches
1521 CALL SETASC
;Check for /A or /B
1524 CMP BYTE PTR[DI+1]," " ;Did we even get a file name?
1532 MOV AL,[PARM1
] ;Is name ambiguous?
1534 JNZ RET35
;Don't perform search if not
1539 MOV DX,OFFSET TRANGROUP
:DIRBUF
1540 INT 33 ;Put result of search in DIRBUF
1541 POP AX ;Restore search first/next command
1543 INT 33 ;Do the search
1548 ;Given switch vector in AX,
1549 ; Set ASCII switch if /A is set
1550 ; Clear ASCII switch if /B is set
1551 ; Leave ASCII unchanged if neither or both are set
1552 ; Also sets INEXACT if ASCII is ever set. AL = ASCII on exit, flags set
1553 AND AL,ASWITCH
+BSWITCH
1554 JPE LOADSW
;PE means both or neither are set
1564 ; [SI] = Ambiguous input file name
1565 ; [BX] = Source of replacement characters
1566 ; [DI] = Destination
1567 ; File name is copied from [SI] to [DI]. If "?"s are encountered,
1568 ; they are replaced with the character in the same position at [BX].
1582 MOV SI,OFFSET TRANGROUP
:DEST
1583 MOV DI,OFFSET TRANGROUP
:DIRBUF
1589 ;Read file in (with READIN) if not identical to destination
1590 CALL COMPNAME
;See if source and destination the same
1592 CMP [APPEND
],0 ;If physical append, it's OK
1594 MOV DX,OFFSET TRANGROUP
:LOSTERR
;Tell him he's not going to get it
1600 ;Open source file and read it in. If memory fills up, flush it out to
1601 ;destination and keep reading. If /A switch set, chop file at first ^Z.
1603 ; [NXTADD] has current pointer in buffer
1604 ; [CFLAG] <>0 if destination has been created
1606 MOV DX,OFFSET TRANGROUP
:DIRBUF
1609 OR AL,AL ;Successful open?
1610 JNZ RET40
;If not, just ignore it
1612 MOV WORD PTR[DIRBUF
+RR
],AX
1613 MOV WORD PTR[DIRBUF
+RR
+2],AX
1615 MOV WORD PTR[DIRBUF
+RECLEN
],AX
1624 SUB CX,DX ;Compute available space
1625 MOV DX,OFFSET TRANGROUP
:DIRBUF
1626 MOV AH,RDBLK
;Read in source file
1636 REPNE SCASB ;Scan for EOF
1646 CMP CX,[BYTCNT
] ;Is buffer full?
1647 JB RET40
;If not, we must have found EOF
1654 OR AL,AH ;See if any data is loaded
1655 OR AL,[CFLAG
] ; or file was created
1656 JZ RET50
;Don't close or count if not created
1657 MOV AL,BYTE PTR[ARG2S
]
1658 CALL SETASC
;Check for /B or /A on destination
1660 CMP BX,[BYTCNT
] ;Is memory full?
1662 CALL FLSHFIL
;Empty it to make room for 1 lousy byte
1667 MOV WORD PTR[BX],1
AH ;Add End-of-file mark (Ctrl-Z)
1672 CMP [INEXACT
],0 ;Copy not exact?
1673 JNZ NODATE
;If so, don't copy date & time
1674 MOV SI,OFFSET TRANGROUP
:DIRBUF
+OFFDATE
1675 MOV DI,OFFSET TRANGROUP
:DEST
+OFFDATE
;Make date & time same as original
1679 MOV DX,OFFSET TRANGROUP
:DEST
1686 ;Write out any data remaining in memory.
1688 ; [NXTADD] = No. of bytes to write
1689 ; [CFLAG] <>0 if file has been created
1698 JNZ SKPMAK
;Don't actually create if NOWRITE set
1699 MOV DX,OFFSET TRANGROUP
:DEST
1702 MOV DX,OFFSET TRANGROUP
:FULDIR
1707 MOV WORD PTR[DEST
+RR
],AX
1708 MOV WORD PTR[DEST
+RR
+2],AX
1710 MOV WORD PTR[DEST
+RECLEN
],AX
1714 CMP [NOWRITE
],0 ;If NOWRITE set, just seek CX bytes
1722 MOV DX,OFFSET TRANGROUP
:DEST
1727 MOV DX,OFFSET TRANGROUP
:DEST
1732 MOV DX,OFFSET TRANGROUP
:NOSPACE
1739 ADD WORD PTR[DEST
+RR
],CX
1740 ADC WORD PTR[DEST
+RR
+2],0 ;Propagate carry
1744 ;Get one byte from the batch file and return it in AL. End-of-file
1745 ;returns <CR> and ends batch mode. DS must be set to resident segment.
1746 ;AH, CX, DX destroyed.
1748 MOV DX,OFFSET RESGROUP
:BATFCB
1751 INT 33 ;Get one more byte from batch file
1757 MOV AL,0DH ;If end-of-file, then end of line
1758 MOV [BATCH
],0 ;And turn off batch mode
1766 DEC SI ;Point to first non-delimiter
1776 CMP AL,9 ;Check for TAB character
1780 MOV DX,OFFSET TRANGROUP
:PAUSMES
1783 MOV AX,0C00H+INCHAR
;Get character with KB buffer flush
1787 ;Date and time are set during initialization and use
1788 ;this routines since they need to do a long return
1792 PUSH DS ;Going to use the previous stack
1793 MOV AX,CS ;Set up the appropriate segment registers
1796 MOV WORD PTR DS:[81H
],13 ;Want to prompt for date during initialization
1805 ; DATE - Gets and sets the time
1808 MOV SI,81H
;Accepting argument for date inline
1812 MOV BX,2F00H
+"-" ;"/-"
1817 MOV DX,OFFSET TRANGROUP
:CURDAT
1819 INT 33 ;Print "Current date is "
1821 INT 33 ;Get date in CX:DX
1826 ADD SI,OFFSET TRANGROUP
:WEEKTAB
1841 MOV DX,OFFSET TRANGROUP
:NEWDAT
1842 MOV BX,2F00H
+"-" ;"/-" in BX
1874 MOV DX,OFFSET TRANGROUP
:BADDAT
1879 ; TIME gets and sets the time
1882 MOV SI,81H
;Accepting argument for time inline
1891 MOV DX,OFFSET TRANGROUP
:CURTIM
1893 INT 33 ;Print "Current time is "
1895 INT 33 ;Get time in CX:DX
1899 XOR CX,CX ;Initialize hours and minutes to zero
1900 MOV DX,OFFSET TRANGROUP
:NEWTIM
1903 COMTIM: JZ RET100
;If no time present, don't change it
1915 MOV DH,AH ;Position seconds
1931 JZ RET100
;Error in time?
1933 MOV DX,OFFSET TRANGROUP
:BADTIM
1935 INT 33 ;Print error message
1936 JMP GETTIM
;Try again
1940 INT 33 ;Print "Enter new date: "
1942 MOV DX,OFFSET TRANGROUP
:COMBUF
1943 INT 33 ;Get input line
1945 MOV SI,OFFSET TRANGROUP
:COMBUF
+2
1946 CMP BYTE PTR[SI],13 ;Check if new date entered
1949 CALL GETNUM
;Get one or two digit number
1951 MOV DH,AH ;Put in position
1955 CMP BL,":" ;Is it a date seperator?
1959 RET100: RET ;Time may have only an hour specified
1965 MOV DL,AH ;Put in position
1971 MOV AH,AL ;Save first digit
1972 CALL INDIG
;Another digit?
1974 AAD ;Convert unpacked BCD to decimal
1992 MOV BH,"0"-" " ;Enable leading zero suppression
2002 CMP BL,":" ;Are we outputting time?
2007 OUT2: ;Output binary number as two ASCII digits
2008 AAM ;Convert binary to unpacked BCD
2010 OR AX,3030H
;Add "0" bias to both digits
2011 CMP AL,"0" ;Is MSD zero?
2013 SUB AL,BH ;Suppress leading zero if enabled
2015 MOV BH,0 ;Disable zero suppression
2019 ;Print char in AL without affecting registers
2031 MOV [EXEEND
],AX ;Store in EXEEND
2032 MOV DX,OFFSET TRANGROUP
:RUNVAR
;Read header in here
2035 MOV CX,RUNVARSIZ
;Amount of header info we need
2036 MOV DX,OFFSET TRANGROUP
:EXEFCB
2038 INT 33 ;Read in header
2040 JNZ BADEXE
;Must not reach EOF
2041 MOV AX,[HEADSIZ
] ;Size of header in paragraphs
2042 ;Convert header size to 512-byte pages by multiplying by 32 & rounding up
2043 ADD AX,31 ;Round up first
2045 SHR AX,CL ;Multiply by 32
2046 MOV [EXEFCB
+RR
],AX ;Position in file of program
2047 MOV WORD PTR[EXEFCB
+RECLEN
],512 ;Set record size
2048 ADD BX,10H
;First paragraph above parameter area
2049 MOV DX,[PAGES
] ;Total size of file in 512-byte pages
2050 SUB DX,AX ;Size of program in pages
2052 SHL DX,CL ;Convert pages back to paragraphs
2054 ADD DX,BX ;Size + start = minimum memory (paragr.)
2055 MOV CX,[EXEEND
] ;Get memory size in paragraphs
2056 CMP DX,CX ;Enough memory?
2065 ADD DX,BX ;Adjusted value of SP
2066 CMP DX,CX ;Is it valid?
2068 CMP [LOADLOW
],-1 ;Load low or high?
2069 JZ LOAD ;If low, load at segment BX
2070 SUB CX,AX ;Memory size - program size = load addr.
2073 MOV BP,BX ;Save load segment
2075 LOADSEG EQU
(LOAD1
-ZERO
)/16
2078 XOR DX,DX ;Address 0 in segment
2080 INT 33 ;Set load address
2082 MOV CX,[PSIZE
] ;Number of records to read
2083 MOV DX,OFFSET TRANGROUP
:EXEFCB
2085 INT 33 ;Read in up to 64K
2086 SUB [PSIZE
],CX ;Decrement count by amount read
2087 JZ HAVEXE
;Did we get it all?
2088 TEST AL,1 ;Check return code if not
2089 JNZ BADEXE
;Must be zero if more to come
2090 ADD BX,1000H
-20H
;Bump data segment 64K minus one record
2091 JMP SHORT LOAD1
;Get next 64K block
2094 MOV DX,OFFSET TRANGROUP
:EXEBAD
2098 MOV DX,OFFSET TRANGROUP
:TOOBIG
2102 MOV AX,[RELTAB
] ;Get position of table
2103 MOV [EXEFCB
+RR
],AX ;Set in random record field
2104 MOV WORD PTR[EXEFCB
+RECLEN
],1 ;Set one-byte record
2105 MOV DX,OFFSET TRANGROUP
:RELPT
;4-byte buffer for relocation address
2112 MOV DX,OFFSET TRANGROUP
:EXEFCB
2114 INT 33 ;Read in one relocation pointer
2115 OR AL,AL ;Check return code
2117 MOV DI,[RELPT
] ;Get offset of relocation pointer
2118 MOV AX,[RELSEG
] ;Get segment
2119 ADD AX,BP ;Bias segment with actual load segment
2121 ADD WORD PTR ES:[DI],BP ;Relocate
2122 DEC [RELCNT
] ;Count off
2124 ;Set up exit conditions
2129 MOV SS,AX ;Initialize SS
2133 MOV AX,[TPA
] ;Get pointer to parameter area
2134 MOV CX,[BYTCNT
] ;Size of TPA segment
2136 MOV DS,AX ;Set segment registers to point to it
2138 JMP DWORD PTR CS:[INITIP
] ;Long jump to program
2141 AND CL,0F0H ;Adjust to even paragraph boundary
2142 MOV AX,WORD PTR DS:[6] ;Get current memory size
2143 SUB AX,CX ;Find out how much we're changing it
2144 MOV WORD PTR DS:[6],CX
2146 SAR AX,CL ;Convert to a segment address
2147 ADD WORD PTR DS:[8],AX ;Adjust long jump to go to same place
2150 INT 33 ;Set default disk transfer address
2151 MOV AX,WORD PTR CS:[PARM1
] ;Pass on info about FCBs
2153 MOV DX,CX ;Assume no batch file
2155 TEST CS:[BATCH
],-1 ;Batch file in progress?
2157 JZ RET120
;If not, all set up
2159 MOV DX,OFFSET RESGROUP
:BATFCB
;CX:DX points to batch FCB
2161 TRANCODESIZE EQU
$-ZERO
2163 COMLEN EQU TRANDATASIZE
+TRANCODESIZE
-102H
;End of COMMAND load. ZERO Needed to make COMLEN absolute
2164 TRNLEN EQU
(PRETRLEN
+TRANCODESIZE
+TRANDATASIZE
+15)/16 ;Length of transient in paragraphs