]> wirehaze git hosting - MS-DOS.git/blob - v1.25/source/COMMAND.ASM

wirehaze git hosting

add README.md for Thai language
[MS-DOS.git] / v1.25 / source / COMMAND.ASM
1 ; COMMAND version 1.17
2 ;
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.
16
17 ;Use the following booleans to set assembly flags
18 FALSE EQU 0
19 TRUE EQU NOT FALSE
20
21 IBMVER EQU FALSE ;Switch to build IBM version of Command
22 MSVER EQU TRUE ;Switch to build MS-DOS version of Command
23
24 HIGHMEM EQU TRUE ;Run resident part above transient (high memory)
25
26 LINPERPAG EQU 23
27 NORMPERLIN EQU 1
28 WIDEPERLIN EQU 5
29
30 IF IBMVER
31 SYM EQU ">"
32 COMDRV EQU 1
33 ENDIF
34
35 IF MSVER
36 SYM EQU ":"
37 COMDRV EQU 0
38 ENDIF
39
40 FCB EQU 5CH
41 DSKRESET EQU 13
42 SETBASE EQU 38
43 SRCHFRST EQU 17
44 SRCHNXT EQU 18
45 RENAM EQU 23
46 INCHAR EQU 1
47 GETFAT EQU 27
48 OPEN EQU 15
49 CLOSE EQU 16
50 MAKE EQU 22
51 DELETE EQU 19
52 RDBLK EQU 39
53 WRBLK EQU 40
54 SETDMA EQU 26
55 SELDRV EQU 14
56 GETDRV EQU 25
57 PRINTBUF EQU 9
58 OUTCH EQU 2
59 INBUF EQU 10
60 GETDATE EQU 2AH
61 SETDATE EQU 2BH
62 GETTIME EQU 2CH
63 SETTIME EQU 2DH
64 RR EQU 33
65 RECLEN EQU 14
66 FILLEN EQU 16
67 OFFDATE EQU 20
68
69
70 ;The following are all of the segments used in the load order
71
72 CODERES SEGMENT
73 CODERES ENDS
74
75 DATARES SEGMENT BYTE
76 DATARES ENDS
77
78 INIT SEGMENT BYTE
79 INIT ENDS
80
81 TAIL SEGMENT PARA
82 TAIL ENDS
83
84 TRANCODE SEGMENT PARA
85 TRANCODE ENDS
86
87 TRANDATA SEGMENT BYTE
88 TRANDATA ENDS
89
90 TRANSPACE SEGMENT BYTE
91 TRANSPACE ENDS
92
93 RESGROUP GROUP CODERES,DATARES,INIT,TAIL
94 TRANGROUP GROUP TRANCODE,TRANDATA,TRANSPACE
95
96 ;Data for resident portion
97
98 DATARES SEGMENT BYTE
99 ORG 0
100 ZERO = $
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$"
109 ERR2 DB "Not ready$"
110 ERR4 DB "Data$"
111 ERR6 DB "Seek$"
112 ERR8 DB "Sector not found$"
113 ERR10 DB "Write fault$"
114 ERR12 DB "Disk$"
115 READ DB "read$"
116 WRITE DB "writ$"
117 ERRMES DB " error "
118 IOTYP DB "writing"
119 DRVNUM DB " drive "
120 DRVLET DB "A"
121 NEWLIN DB 13,10,"$"
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 "
126 IF IBMVER
127 DB "drive A"
128 ELSE
129 DB "default drive"
130 ENDIF
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)? $"
134 LOADING DB 0
135 BATFCB DB 1,"AUTOEXECBAT"
136 DB 21 DUP(?)
137 DW 0
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"
142 DB 25 DUP(?)
143 TRANS DW OFFSET TRANGROUP:COMMAND
144 TRNSEG DW ?
145 BATBYT DB ?
146 MEMSIZ DW ?
147 SUM DW ?
148 INITADD DB 4 DUP(?)
149 RESDATASIZE EQU $-ZERO
150 DATARES ENDS
151
152 ;Data for transient portion
153
154 TRANDATA SEGMENT BYTE
155 ORG 0
156 ZERO EQU $
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)? $"
180
181 COMTAB DB 4,"DIR",1
182 DW OFFSET TRANGROUP:CATALOG
183 DB 7,"RENAME",1
184 DW OFFSET TRANGROUP:RENAME
185 DB 4,"REN",1
186 DW OFFSET TRANGROUP:RENAME
187 DB 6,"ERASE",1
188 DW OFFSET TRANGROUP:ERASE
189 DB 4,"DEL",1
190 DW OFFSET TRANGROUP:ERASE
191 DB 5,"TYPE",1
192 DW OFFSET TRANGROUP:TYPEFIL
193 DB 4,"REM",1
194 DW OFFSET TRANGROUP:COMMAND
195 DB 5,"COPY",1
196 DW OFFSET TRANGROUP:COPY
197 DB 6,"PAUSE",1
198 DW OFFSET TRANGROUP:PAUSE
199 DB 5,"DATE",0
200 DW OFFSET TRANGROUP:DATE
201 DB 5,"TIME",0
202 DW OFFSET TRANGROUP:TIME
203 DB 0 ;Terminate command table
204
205 COMBUF DB 128,1,13
206
207 TRANDATASIZE EQU $-ZERO
208 TRANDATA ENDS
209
210 ;Uninitialized transient data
211 TRANSPACE SEGMENT BYTE
212 ORG 0
213 ZERO = $
214 DB 128 DUP(?)
215 TPA DW 1 DUP(?)
216 RESSEG DW 1 DUP(?)
217 CHKDRV DB 1 DUP(?)
218 FILTYP DB 1 DUP(?)
219 CURDRV DB 1 DUP(?)
220 PARM1 DB 1 DUP(?)
221 PARM2 DB 1 DUP(?)
222 COMSW DW 1 DUP(?)
223 ARG1S DW 1 DUP(?)
224 ARG2S DW 1 DUP(?)
225 FLAGER DB 1 DUP(?)
226 CFLAG DB 1 DUP(?)
227 SPECDRV DB 1 DUP(?)
228 BYTCNT DW 1 DUP(?)
229 NXTADD DW 1 DUP(?)
230 LINCNT DB 1 DUP(?)
231 LINLEN DB 1 DUP(?)
232 FILECNT DW 1 DUP(?)
233 EXEFCB LABEL WORD
234 IDLEN DB 1 DUP(?)
235 ID DB 8 DUP(?)
236 COM DB 3 DUP(?)
237 DEST DB 37 DUP(?)
238 DESTNAME DB 11 DUP(?)
239 DIRBUF DB 37 DUP(?)
240 BITS DW 1 DUP(?)
241 FULLSCR DW 1 DUP(?)
242 EXEEND DW 1 DUP(?)
243 ;Header variables for EXE file load
244 ;These are overlapped with COPY variables, below
245 RUNVAR LABEL WORD
246 RELPT DW 1 DUP(?)
247 RELSEG DW 1 DUP(?)
248 PSIZE LABEL WORD
249 PAGES DW 1 DUP(?)
250 RELCNT DW 1 DUP(?)
251 HEADSIZ DW 1 DUP(?)
252 DW 1 DUP(?)
253 LOADLOW DW 1 DUP(?)
254 INITSS DW 1 DUP(?)
255 INITSP DW 1 DUP(?)
256 DW 1 DUP(?)
257 INITIP DW 1 DUP(?)
258 INITCS DW 1 DUP(?)
259 RELTAB DW 1 DUP(?)
260 RUNVARSIZ EQU $-RUNVAR
261
262 DB 80H DUP(?)
263 STACK LABEL WORD
264
265 PRETRLEN EQU $-ZERO ;Used later to compute TRNLEN
266
267 ORG RUNVAR-ZERO ;Overlaps EXE variables
268
269 SRCPT DW 1 DUP(?)
270 INEXACT DB 1 DUP(?)
271 APPEND DB 1 DUP(?)
272 NOWRITE DB 1 DUP(?)
273 ASCII DB 1 DUP(?)
274 PLUS DB 1 DUP(?)
275 SOURCE DB 11 DUP(?)
276 TRANSPACESIZE EQU $-ZERO
277 TRANSPACE ENDS
278
279
280 ;START OF RESIDENT PORTION
281
282 CODERES SEGMENT
283 ASSUME CS:RESGROUP,DS:RESGROUP,ES:RESGROUP,SS:RESGROUP
284 ORG 0
285 ZERO = $
286 PARMBUF LABEL WORD
287
288 ORG 100H
289
290 RSTACK LABEL WORD
291
292 PROGSTART:
293 JMP CONPROC
294
295 LTPA DW 0 ;WILL STORE TPA SEGMENT HERE
296 MYSEG DW 0 ;Put our own segment here
297
298 CONTC:
299 MOV AX,CS
300 MOV DS,AX
301 MOV SS,AX
302 MOV SP,OFFSET RESGROUP:RSTACK
303 STI
304 CALL SETVECT
305 MOV AH,DSKRESET
306 INT 33 ;Reset disks in case files were open
307 TEST [BATCH],-1
308 JZ LODCOM
309 ASKEND:
310 MOV DX,OFFSET RESGROUP:ENDBATMES
311 MOV AH,PRINTBUF
312 INT 33
313 MOV AX,0C00H+INCHAR
314 INT 33
315 AND AL,5FH
316 CMP AL,"N"
317 JZ LODCOM
318 CMP AL,"Y"
319 JNZ ASKEND
320 MOV [BATCH],0
321 LODCOM:
322 MOV AX,CS
323 MOV SS,AX
324 MOV SP,OFFSET RESGROUP:RSTACK
325 MOV DS,AX
326 CALL SETVECT
327 CALL CHKSUM
328 CMP DX,[SUM]
329 JZ HAVCOM
330 MOV [LOADING],1
331 CALL LOADCOM
332 CHKSAME:
333 CALL CHKSUM
334 CMP DX,[SUM]
335 JZ HAVCOM
336 CALL WRONGCOM
337 JMP SHORT CHKSAME
338 HAVCOM:
339 MOV [LOADING],0
340 MOV SI,OFFSET RESGROUP:LTPA
341 MOV DI,OFFSET TRANGROUP:TPA
342 MOV ES,[TRNSEG]
343 CLD
344 MOVSW ;Move TPA segment to transient storage
345 MOVSW ;Move resident segment too
346 MOV AX,[MEMSIZ]
347 MOV WORD PTR ES:[2],AX
348 JMP DWORD PTR [TRANS]
349
350 RESIDENT:
351 ADD DX,15
352 MOV CL,4
353 SHR DX,CL ;Number of paragraphs of new addition
354 ADD CS:[LTPA],DX
355 XOR AX,AX
356 MOV DS,AX
357 JMP DWORD PTR DS:[80H] ;Pretend user executed INT 20H
358
359 DSKERR:
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 ;******************************************************
365 STI
366 PUSH DS
367 PUSH CS
368 POP DS ;Set up local data segment
369 PUSH DX
370 CALL CRLF
371 POP DX
372 ADD AL,"A" ;Compute drive letter
373 MOV [DRVLET],AL
374 TEST AH,80H ;Check if hard disk error
375 JNZ FATERR
376 MOV SI,OFFSET RESGROUP:READ
377 TEST AH,1
378 JZ SAVMES
379 MOV SI,OFFSET RESGROUP:WRITE
380 SAVMES:
381 LODSW
382 MOV WORD PTR [IOTYP],AX
383 LODSW
384 MOV WORD PTR [IOTYP+2],AX
385 AND DI,0FFH
386 CMP DI,12
387 JBE HAVCOD
388 MOV DI,12
389 HAVCOD:
390 MOV DI,WORD PTR [DI+MESBAS] ;Get pointer to error message
391 XCHG DI,DX ;May need DX later
392 MOV AH,PRINTBUF
393 INT 33 ;Print error type
394 MOV DX,OFFSET RESGROUP:ERRMES
395 INT 33
396 CMP [LOADING],0
397 JNZ GETCOMDSK
398 ASK:
399 MOV DX,OFFSET RESGROUP:REQUEST
400 MOV AH,PRINTBUF
401 INT 33
402 MOV AX,0C00H+INCHAR
403 INT 33 ;Get response
404 CALL CRLF
405 OR AL,20H ;Convert to lower case
406 MOV AH,0 ;Return code for ignore
407 CMP AL,"i" ;Ignore?
408 JZ EXIT
409 INC AH
410 CMP AL,"r" ;Retry?
411 JZ EXIT
412 INC AH
413 CMP AL,"a" ;Abort?
414 JNZ ASK
415 EXIT:
416 MOV AL,AH
417 MOV DX,DI
418 POP DS
419 IRET
420
421 FATERR:
422 MOV DX,OFFSET RESGROUP:BADFAT
423 MOV AH,PRINTBUF
424 INT 33
425 MOV DX,OFFSET RESGROUP:DRVNUM
426 INT 33
427 MOV AL,2 ;Abort
428 POP DS
429 IRET
430
431 GETCOMDSK:
432 MOV DX,OFFSET RESGROUP:NEEDCOM
433 MOV AH,PRINTBUF
434 INT 33
435 MOV AX,0C07H ;Get char without testing or echo
436 INT 33
437 JMP LODCOM
438
439 CRLF:
440 MOV DX,OFFSET RESGROUP:NEWLIN
441 PUSH AX
442 MOV AH,PRINTBUF
443 INT 33
444 POP AX
445 RET10: RET
446
447 LOADCOM:
448 PUSH DS
449 MOV DS,[TRNSEG]
450 MOV DX,100H
451 MOV AH,SETDMA
452 INT 33
453 POP DS
454 MOV DX,OFFSET RESGROUP:COMFCB
455 MOV AH,OPEN
456 INT 33 ;Open COMMAND.COM
457 OR AL,AL
458 JZ READCOM
459 MOV DX,OFFSET RESGROUP:NEEDCOM
460 PROMPTCOM:
461 MOV AH,PRINTBUF
462 INT 33
463 MOV AX,0C07H ;Get char without testing or echo
464 INT 33
465 JMP SHORT LOADCOM
466 READCOM:
467 MOV WORD PTR[COMFCB+RR],OFFSET RESGROUP:TRANSTART
468 XOR AX,AX
469 MOV WORD PTR[COMFCB+RR+2],AX
470 MOV [COMFCB],AL ;Use default drive
471 INC AX
472 MOV WORD PTR[COMFCB+RECLEN],AX
473 MOV CX,COMLEN
474 MOV DX,OFFSET RESGROUP:COMFCB
475 MOV AH,RDBLK
476 INT 33
477 OR AL,AL
478 JZ RET10
479 WRONGCOM:
480 MOV DX,OFFSET RESGROUP:COMBAD
481 JMP SHORT PROMPTCOM
482
483 CHKSUM:
484 CLD
485 PUSH DS
486 MOV DS,[TRNSEG]
487 MOV SI,100H
488 MOV CX,COMLEN
489 SHR CX,1
490 XOR DX,DX
491 CHK:
492 LODSW
493 ADD DX,AX
494 LOOP CHK
495 POP DS
496 RET
497
498 SETVECT:
499 MOV DX,OFFSET RESGROUP:LODCOM
500 MOV AX,2522H ;Set Terminate address
501 INT 21H
502 MOV DX,OFFSET RESGROUP:CONTC
503 MOV AX,2523H ;Set Ctrl-C address
504 INT 21H
505 MOV DX,OFFSET RESGROUP:DSKERR
506 MOV AX,2524H ;Set Hard Disk Error address
507 INT 33
508 MOV DX,OFFSET RESGROUP:RESIDENT
509 MOV AX,2527H ;Set Terminate and Stay Resident address
510 INT 33
511 RET
512 RESCODESIZE EQU $-ZERO
513 CODERES ENDS
514
515 ;*******************************************************************
516 ;START OF INIT PORTION
517 ;This code is overlayed the first time the TPA is used.
518
519 INIT SEGMENT BYTE
520
521 ORG 0
522 ZERO = $
523 CONPROC:
524 MOV SP,OFFSET RESGROUP:RSTACK
525
526 IF HIGHMEM
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
530 MOV ES,AX
531 MOV SI,100H
532 MOV DI,SI
533 MOV CX,((RESCODESIZE+RESDATASIZE)-100H+1)/2 ;Length of resident in words
534 REP MOVSW ;Move to end of memory
535 MOV DS,AX
536 MOV [LTPA],CS
537 ENDIF
538
539 IF NOT HIGHMEM
540 MOV AX,CS
541 ADD AX,((RESCODESIZE+RESDATASIZE)+15)/16 ;Compute segment of TPA
542 MOV [LTPA],AX
543 MOV AX,WORD PTR DS:[2]
544 ENDIF
545
546 MOV [MYSEG],DS
547 MOV [MEMSIZ],AX
548 SUB AX,TRNLEN ;Subtract size of transient
549 MOV [TRNSEG],AX
550 CALL SETVECT
551 CALL LOADCOM
552 CALL CHKSUM
553 MOV [SUM],DX
554
555 IF MSVER
556 IF HIGHMEM
557 PUSH DS
558 PUSH CS
559 POP DS
560 ENDIF
561 MOV DX,OFFSET RESGROUP:HEADER
562 MOV AH,PRINTBUF
563 INT 33
564 IF HIGHMEM
565 POP DS
566 ENDIF
567 ENDIF
568
569 MOV DX,OFFSET RESGROUP:BATFCB
570 MOV AH,OPEN
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
574 JZ DRV0
575 MOV [BATCH],0 ;Not found--turn off batch job
576 MOV AX,OFFSET TRANGROUP:DATINIT
577 MOV WORD PTR[INITADD],AX
578 MOV AX,[TRNSEG]
579 MOV WORD PTR[INITADD+2],AX
580 CALL DWORD PTR DS:[INITADD]
581
582 IF IBMVER
583 MOV DX,OFFSET RESGROUP:HEADER
584 MOV AH,PRINTBUF
585 INT 33
586 ENDIF
587
588 DRV0:
589 JMP HAVCOM
590
591
592 IF MSVER
593 HEADER DB 13,10,"Command v. 1.17"
594 IF HIGHMEM
595 DB "H"
596 ENDIF
597 DB 13,10,"$"
598 ENDIF
599
600 IF IBMVER
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"
604 ENDIF
605
606 INITSIZE EQU $-ZERO
607 INIT ENDS
608
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
611 ; initialy.
612
613 TAIL SEGMENT PARA
614 ORG 0
615 TRANSTART LABEL WORD
616 TAIL ENDS
617
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.
622
623 TRANCODE SEGMENT PARA
624 ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP,SS:TRANGROUP
625
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
631
632 ORG 0
633 ZERO = $
634
635 ORG 100H ;Allow for 100H parameter area
636
637 SETDRV:
638 MOV AH,SELDRV
639 INT 21H
640 COMMAND:
641 CLD
642 MOV AX,CS
643 MOV SS,AX
644 MOV SP,OFFSET TRANGROUP:STACK
645 MOV ES,AX
646 MOV DS,AX
647 STI
648 MOV AX,46*100H
649 MOV DL,0
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
653 MOV DX,16
654 MUL DX ;DX:AX=size of TPA in bytes
655 OR DX,DX ;See if over 64K
656 JZ SAVSIZ ;OK if not
657 MOV AX,-1 ;If so, limit to 65535 bytes
658 SAVSIZ:
659 MOV [BYTCNT],AX ;Max no. of bytes that can be buffered
660 CALL CRLF2
661 GETCOM:
662 MOV AH,GETDRV
663 INT 21H
664 MOV [CURDRV],AL
665 ADD AL,"A"
666 CALL OUT ;Print letter for default drive
667 MOV AL,SYM
668 CALL OUT
669 MOV DS,[RESSEG] ;All batch work must use resident seg.
670 ASSUME DS:RESGROUP
671 TEST [BATCH],-1
672 JNZ READBAT
673 PUSH CS
674 POP DS ;Need local segment to point to buffer
675 ASSUME DS:TRANGROUP
676 MOV DX,OFFSET TRANGROUP:COMBUF
677 MOV AH,INBUF
678 INT 21H ;Get a command
679 JMP DOCOM
680
681 ;All batch proccessing has DS set to segment of resident portion
682 ASSUME DS:RESGROUP
683 NEEDPARM:
684 CALL GETBATBYT
685 CMP AL,"%" ;Check for two consecutive %
686 JZ SAVBATBYT
687 CMP AL,13 ;Check for end-of-line
688 JZ SAVBATBYT
689 SUB AL,"0"
690 JB RDBAT ;Ignore parameter reference if invalid
691 CMP AL,9
692 JA RDBAT
693 CBW
694 MOV SI,AX
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
699 MOV AH,OUTCH
700 RDPARM:
701 LODSB ;From resident segment
702 CMP AL,0DH ;Check for end of parameter
703 JZ RDBAT
704 STOSB ;To transient segment
705 MOV DL,AL
706 INT 33 ;Display paramters too
707 JMP SHORT RDPARM
708
709 PROMPTBAT:
710 MOV AH,PRINTBUF
711 MOV DX,OFFSET RESGROUP:NEEDBAT
712 INT 33 ;Prompt for batch file
713 MOV AH,PRINTBUF
714 MOV DX,OFFSET RESGROUP:PROMPT
715 INT 33
716 MOV AX,0C00H+INCHAR
717 INT 33
718 JMP COMMAND
719
720 BADCOMJ1:JMP BADCOM
721
722 READBAT:
723 MOV DX,OFFSET RESGROUP:BATFCB
724 MOV AH,OPEN
725 INT 33 ;Make sure batch file still exists
726 OR AL,AL
727 JNZ PROMPTBAT ;If OPEN fails, prompt for disk
728 MOV WORD PTR [BATFCB+RECLEN],1
729 MOV DX,OFFSET RESGROUP:BATBYT
730 MOV AH,SETDMA
731 INT 33
732 MOV DI,OFFSET TRANGROUP:COMBUF+2
733 RDBAT:
734 CALL GETBATBYT
735 CMP AL,"%" ;Check for parameter
736 JZ NEEDPARM
737 SAVBATBYT:
738 STOSB
739 CALL OUT ;Display batched command line
740 CMP AL,0DH
741 JNZ RDBAT
742 SUB DI,OFFSET TRANGROUP:COMBUF+3
743 MOV AX,DI
744 MOV ES:[COMBUF+1],AL ;Set length of line
745 CALL GETBATBYT ;Eat linefeed
746 PUSH CS
747 POP DS ;Go back to local segment
748 ASSUME DS:TRANGROUP
749 DOCOM:
750 ;All segments are local for command line processing
751 MOV AL,10
752 CALL OUT
753 MOV SI,OFFSET TRANGROUP:COMBUF+2
754 MOV DI,OFFSET TRANGROUP:IDLEN
755 MOV AX,2901H ;Make FCB with blank scan-off
756 INT 21H
757 CMP AL,1 ;Check for ambiguous command name
758 JZ BADCOMJ1 ;Ambiguous commands not allowed
759 CMP AL,-1
760 JNZ DRVGD
761 JMP DRVBAD
762 DRVGD:
763 MOV AL,[DI]
764 MOV [SPECDRV],AL
765 MOV AL," "
766 MOV CX,9
767 INC DI
768 REPNE SCASB ;Count no. of letters in command name
769 MOV AL,9
770 SUB AL,CL
771 MOV [IDLEN],AL
772 MOV DI,81H
773 MOV CX,0
774 PUSH SI
775 COMTAIL:
776 LODSB
777 STOSB ;Move command tail to 80H
778 CMP AL,13
779 LOOPNZ COMTAIL
780 NOT CL
781 MOV BYTE PTR DS:[80H],CL
782 POP SI
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 "/"
788 MOV [COMSW],AX
789 MOV DI,FCB
790 MOV AX,2901H
791 INT 21H
792 MOV [PARM1],AL ;Save result of parse
793 CALL SWITCH
794 MOV [ARG1S],AX
795 MOV DI,FCB+10H
796 MOV AX,2901H
797 INT 21H ;Parse file name
798 MOV [PARM2],AL ;Save result
799 CALL SWITCH
800 MOV [ARG2S],AX
801 MOV AL,[IDLEN]
802 MOV DL,[SPECDRV]
803 OR DL,DL ;Check if drive was specified
804 JZ OK
805 JMP DRVCHK
806 OK: DEC AL ;Check for null command
807 JNZ FNDCOM
808 JMP GETCOM
809
810 RETSW:
811 XCHG AX,BX ;Put switches in AX
812 RET
813
814 SWITCH:
815 XOR BX,BX ;Initialize - no switches set
816 SWLOOP:
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 "/"
821 CALL SCANOFF
822 INC SI
823 ;Convert lower case input to upper case
824 CMP AL,"a"
825 JB SAVCHR
826 CMP AL,"z"
827 JA SAVCHR
828 SUB AL,20H ;Lower-case changed to upper-case
829 SAVCHR:
830 MOV DI,OFFSET TRANGROUP:SWLIST
831 MOV CX,SWCOUNT
832 REPNE SCASB ;Look for matching switch
833 JNZ BADSW
834 MOV AX,1
835 SHL AX,CL ;Set a bit for the switch
836 OR BX,AX
837 JMP SHORT SWLOOP
838
839 BADSW:
840 MOV [FLAGER],1 ;Record error in switch
841 JMP SHORT SWLOOP
842
843 SWLIST DB "BAVPW"
844 SWCOUNT EQU $-SWLIST
845
846 DRVBAD:
847 MOV DX,OFFSET TRANGROUP:BADDRV
848 JMP ERROR
849
850 FNDCOM:
851 MOV SI,OFFSET TRANGROUP:COMTAB ;Prepare to search command table
852 MOV CH,0
853 FINDCOM:
854 MOV DI,OFFSET TRANGROUP:IDLEN
855 MOV CL,[SI]
856 JCXZ EXTERNAL
857 REPE CMPSB
858 LAHF
859 ADD SI,CX ;Bump to next position without affecting flags
860 SAHF
861 LODSB ;Get flag for drive check
862 MOV [CHKDRV],AL
863 LODSW ;Get address of command
864 JNZ FINDCOM
865 MOV DX,AX
866 CMP [CHKDRV],0
867 JZ NOCHECK
868 MOV AL,[PARM1]
869 OR AL,[PARM2] ;Check if either parm. had invalid drive
870 CMP AL,-1
871 JZ DRVBAD
872 NOCHECK:CALL DX
873 COMJMP: JMP COMMAND
874
875 BADCOMJ:JMP BADCOM
876
877 SETDRV1:
878 JMP SETDRV
879
880 DRVCHK:
881 DEC DL ;Adjust for correct drive number
882 DEC AL ;Check if anything else is on line
883 JZ SETDRV1
884 EXTERNAL:
885 MOV AL,[SPECDRV]
886 MOV [IDLEN],AL
887 MOV WORD PTR[COM],4F00H+"C" ;"CO"
888 MOV BYTE PTR[COM+2],"M"
889 MOV DX,OFFSET TRANGROUP:IDLEN
890 MOV AH,OPEN
891 INT 33 ;Check if command to be executed
892 MOV [FILTYP],AL ;0 for COM files, -1 for EXE files
893 OR AL,AL
894 JZ EXECUTE
895 MOV WORD PTR[COM],5800H+"E" ;"EX"
896 MOV BYTE PTR[COM+2],"E"
897 INT 33 ;Check for EXE file
898 OR AL,AL
899 JZ EXECUTE
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
903 OR AL,AL
904 JNZ BADCOMJ
905 BATCOM:
906 ;Batch parameters are read with ES set to segment of resident part
907 MOV ES,[RESSEG]
908 ASSUME ES:RESGROUP
909 MOV DI,OFFSET RESGROUP:PARMTAB
910 MOV AX,-1
911 MOV CX,10
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
916 EACHPARM:
917 CALL SCANOFF
918 CMP AL,0DH
919 JZ HAVPARM
920 MOV ES:[BX],DI ;Set pointer table to point to actual parameter
921 INC BX
922 INC BX
923 MOVPARM:
924 LODSB
925 CALL DELIM
926 JZ ENDPARM ;Check for end of parameter
927 STOSB
928 CMP AL,0DH
929 JZ HAVPARM
930 JMP SHORT MOVPARM
931 ENDPARM:
932 MOV AL,0DH
933 STOSB ;End-of-parameter marker
934 CMP BX,OFFSET RESGROUP:PARMTAB+20 ;Maximum number of parameters?
935 JB EACHPARM
936 HAVPARM:
937 MOV SI,OFFSET TRANGROUP:IDLEN
938 MOV DI,OFFSET RESGROUP:BATFCB
939 MOV CX,16
940 REP MOVSW ;Move into private batch FCB
941 XOR AX,AX
942 PUSH ES
943 POP DS ;Simply batch FCB setup
944 ASSUME DS:RESGROUP
945 MOV WORD PTR[BATFCB+RR],AX
946 MOV WORD PTR[BATFCB+RR+2],AX ;Zero RR field
947 INC AX
948 MOV WORD PTR[BATFCB+RECLEN],AX ;Set record length to 1 byte
949 MOV [BATCH],AL ;Flag batch job in progress
950 JMP COMMAND
951 ASSUME DS:TRANGROUP,ES:TRANGROUP
952
953 EXECUTE:
954 MOV AX,WORD PTR[IDLEN+16]
955 OR AX,WORD PTR[IDLEN+18] ;See if zero length
956 JZ BADCOM ;If so, error
957 XOR AX,AX
958 MOV WORD PTR[IDLEN+RR],AX
959 MOV WORD PTR[IDLEN+RR+2],AX ;Set RR field to zero
960 INC AX
961 MOV WORD PTR[IDLEN+RECLEN],AX ;Set record length field to 1
962 MOV DX,[TPA]
963 MOV BX,DX
964 MOV AH,SETBASE
965 INT 21H
966 TEST [FILTYP],-1 ;Check if file is COM or EXE
967 JZ COMLOAD
968 JMP EXELOAD
969 COMLOAD:PUSH DS
970 MOV DS,DX
971 MOV DX,100H
972 MOV AH,SETDMA
973 INT 21H
974 POP DS
975 MOV CX,[BYTCNT]
976 SUB CX,100H
977 MOV DX,OFFSET TRANGROUP:IDLEN
978 MOV AH,RDBLK
979 INT 21H
980 DEC AL
981 MOV DX,OFFSET TRANGROUP:TOOBIG
982 JNZ ERROR
983 ;Set up exit conditions
984 MOV CX,[BYTCNT]
985 MOV DS,BX
986 MOV ES,BX
987 CLI
988 MOV SS,BX
989 MOV SP,CX
990 STI
991 SUB CX,100H ;Allow some stack space
992 XOR AX,AX
993 PUSH AX
994 MOV AX,100H
995 PUSH BX
996 PUSH AX
997 CALL SETUP
998 XXX PROC FAR
999 RET
1000 XXX ENDP
1001 BADCOM:
1002 MOV DX,OFFSET TRANGROUP:BADNAM
1003 ERROR:
1004 MOV AH,PRINTBUF
1005 INT 21H
1006 JMP COMMAND
1007
1008 CHKCNT:
1009 TEST [FILECNT],-1
1010 JNZ ENDDIR
1011 MOV DX,OFFSET TRANGROUP:NOTFND
1012 JMP ERROR
1013
1014 ENDDIR:
1015 ;Make sure last line ends with CR/LF
1016 MOV AL,[LINLEN]
1017 CMP AL,[LINCNT] ;Will be equal if just had CR/LF
1018 JZ MESSAGE
1019 CALL CRLF2
1020 MESSAGE:
1021 MOV SI,[FILECNT]
1022 XOR DI,DI
1023 CALL DISP32BITS
1024 MOV DX,OFFSET TRANGROUP:DIRMES
1025 MOV AH,PRINTBUF
1026 INT 21H
1027 RET
1028
1029 CATALOG:
1030 MOV AL,"?" ;*.* is default file spec.
1031 MOV DI,5DH
1032 MOV CX,11
1033 REP STOSB
1034 MOV SI,81H
1035 CALL SWITCH
1036 MOV DI,5CH
1037 MOV AX,41*100H+0DH ;Parse with default name and extension
1038 INT 33
1039
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.
1043
1044 SETSWT:
1045 MOV AX,[COMSW] ;Get switches from command
1046 OR AX,[ARG1S] ;OR in switches from first parameter
1047 MOV [BITS],AX
1048 MOV BYTE PTR[FULLSCR],LINPERPAG
1049 TEST AL,1 ;Look for /W
1050 MOV AL,NORMPERLIN
1051 JZ DIR
1052 MOV AL,WIDEPERLIN
1053 DIR:
1054 MOV [LINLEN],AL ;Set number of entries per line
1055 MOV [LINCNT],AL
1056 MOV [FILECNT],0 ;Keep track of how many files found
1057 MOV DX,OFFSET TRANGROUP:DIRBUF ;Set Disk transfer address
1058 MOV AH,SETDMA
1059 INT 21H
1060 MOV AH,SRCHFRST
1061 SHOWDIR:
1062 MOV DX,5CH ;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
1066 JMP CHKCNT
1067 AGAIN:
1068 INC [FILECNT] ;Keep track of how many we find
1069 MOV SI,OFFSET TRANGROUP:DIRBUF+1 ;SI -> information returned by sys call
1070 CALL SHONAME
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
1074 CALL TWOSPC
1075 MOV AX,WORD PTR[DIRBUF+25] ;Get date
1076 OR AX,AX
1077 JZ NEXENT ;Skip if no date
1078 MOV DX,AX
1079 MOV CL,5
1080 SHR AX,CL ;Align month
1081 AND AL,0FH
1082 MOV BH,"0"-" " ;Enable zero suppression
1083 CALL OUT2
1084 MOV AL,"-"
1085 CALL OUT
1086 MOV AL,DL
1087 AND AL,1FH ;Mask to day
1088 CALL OUT2
1089 MOV AL,"-"
1090 CALL OUT
1091 MOV AL,DH
1092 SHR AL,1 ;Align year
1093 ADD AX,80 ;Relative 1980
1094 CMP AL,100
1095 JB MILLENIUM
1096 SUB AL,100
1097 MILLENIUM:
1098 CALL OUT2
1099 MOV BX,WORD PTR[DIRBUF+23] ;Get time
1100 OR BX,BX ;Time field present?
1101 JZ NEXENT
1102 CALL TWOSPC
1103 SHR BX,1
1104 SHR BX,1
1105 SHR BX,1
1106 SHR BL,1
1107 SHR BL,1 ;Hours in BH, minutes in BL
1108 MOV AL,BH
1109 MOV DH,"a" ;Assume A.M.
1110 CMP AL,12 ;In the afternoon?
1111 JB MORN
1112 MOV DH,"p"
1113 JE MORN
1114 SUB AL,12 ;Keep it to 12 hours or less
1115 MORN:
1116 OR AL,AL ;Before 1 am?
1117 JNZ SHOHOURS
1118 MOV AL,12
1119 SHOHOURS:
1120 MOV BH,"0"-" " ;Enable zero suppression
1121 CALL OUT2
1122 MOV AL,":"
1123 CALL OUT
1124 MOV AL,BL ;Output minutes
1125 CALL OUT2
1126 MOV AL,DH ;Get "a" or "p"
1127 CALL OUT
1128 NEXENT:
1129 DEC [LINCNT]
1130 JNZ SAMLIN
1131 NEXLIN:
1132 MOV AL,[LINLEN]
1133 MOV [LINCNT],AL
1134 CALL CRLF2
1135 TEST BYTE PTR[BITS],2 ;/P switch present?
1136 JZ SCROLL ;If not, just continue
1137 DEC BYTE PTR[FULLSCR]
1138 JNZ SCROLL
1139 MOV BYTE PTR[FULLSCR],LINPERPAG
1140 MOV AH,PRINTBUF
1141 MOV DX,OFFSET TRANGROUP:PAUSMES
1142 INT 33
1143 MOV AX,0C08H ;Wait for any character to be typed
1144 INT 21H
1145 CALL CRLF2
1146 SCROLL:
1147 MOV AH,SRCHNXT
1148 JMP SHOWDIR
1149
1150 SAMLIN:
1151 MOV AL,9 ;Output a tab
1152 CALL OUT
1153 JMP SHORT SCROLL
1154
1155 SHONAME:
1156 MOV CX,8
1157 CALL OUTCNT
1158 CALL ONESPC
1159 MOV CX,3
1160 OUTCNT:
1161 LODSB
1162 CALL OUT
1163 LOOP OUTCNT
1164 RET
1165
1166 TWOSPC:
1167 CALL ONESPC
1168 ONESPC:
1169 MOV AL," "
1170 JMP OUT
1171
1172 CRLF2:
1173 MOV AL,13
1174 CALL OUT
1175 MOV AL,10
1176 JMP OUT
1177
1178 DISPSIZE:
1179 MOV SI,WORD PTR[DIRBUF+29]
1180 MOV DI,WORD PTR[DIRBUF+31]
1181 DISP32BITS:
1182 ;Prints the 32-bit number DI:SI on the console in decimal. Uses a total
1183 ;of 9 digit positions with leading blanks.
1184 XOR AX,AX
1185 MOV BX,AX
1186 MOV BP,AX
1187 MOV CX,32
1188 CONVLP:
1189 SHL SI,1
1190 RCL DI,1
1191 XCHG AX,BP
1192 CALL CONVWRD
1193 XCHG AX,BP
1194 XCHG AX,BX
1195 CALL CONVWRD
1196 XCHG AX,BX
1197 ADC AL,0
1198 LOOP CONVLP
1199 ; Conversion complete. Print 9-digit number.
1200 MOV CX,1810H ;Allow leading zero blanking for 8 digits
1201 XCHG DX,AX
1202 CALL DIGIT
1203 XCHG AX,BX
1204 CALL OUTWORD
1205 XCHG AX,BP
1206 OUTWORD:
1207 PUSH AX
1208 MOV DL,AH
1209 CALL OUTBYTE
1210 POP DX
1211 OUTBYTE:
1212 MOV DH,DL
1213 SHR DL,1
1214 SHR DL,1
1215 SHR DL,1
1216 SHR DL,1
1217 CALL DIGIT
1218 MOV DL,DH
1219 DIGIT:
1220 AND DL,0FH
1221 JZ BLANKZER
1222 MOV CL,0
1223 BLANKZER:
1224 DEC CH
1225 AND CL,CH
1226 OR DL,30H
1227 SUB DL,CL
1228 MOV AH,OUTCH
1229 INT 21H
1230 RET
1231
1232 CONVWRD:
1233 ADC AL,AL
1234 DAA
1235 XCHG AL,AH
1236 ADC AL,AL
1237 DAA
1238 XCHG AL,AH
1239 RET20: RET
1240
1241 ERASE:
1242 MOV CX,11
1243 MOV SI,FCB+1
1244 AMBSPEC:
1245 LODSB
1246 CMP AL,"?"
1247 JNZ ALLFIL
1248 LOOP AMBSPEC
1249 ALLFIL:
1250 CMP CX,0
1251 JNZ NOPRMPT
1252 ASKAGN:
1253 MOV DX,OFFSET TRANGROUP:SUREMES ;"Are you sure (Y/N)?"
1254 MOV AH,PRINTBUF
1255 INT 21H
1256 MOV AX,0C00H+INCHAR
1257 INT 21H
1258 AND AL,5FH
1259 CMP AL,"N"
1260 JZ RET20
1261 CMP AL,"Y"
1262 CALL CRLF2
1263 JZ NOPRMPT
1264 JMP SHORT ASKAGN
1265 NOPRMPT:
1266 MOV AH,DELETE
1267 MOV BX,OFFSET TRANGROUP:NOTFND
1268 CMP BYTE PTR DS:[FCB+1]," " ;Check if parameter exists
1269 JMP SHORT OPFILE
1270 RENAME:
1271 MOV AH,RENAM
1272 MOV BX,OFFSET TRANGROUP:RENERR
1273 CMP BYTE PTR DS:[FCB+16+1]," " ;Check if parameter exists
1274 OPFILE:
1275 MOV DX,OFFSET TRANGROUP:MISNAM
1276 JZ ERRJ ;Error if missing parameter
1277 MOV DX,FCB
1278 INT 21H
1279 INC AL
1280 JNZ RET20
1281 MOV DX,BX
1282 ERRJ: JMP ERROR
1283
1284 TYPEFIL:
1285 MOV DS,[TPA]
1286 XOR DX,DX
1287 MOV AH,SETDMA
1288 INT 21H
1289 PUSH CS
1290 POP DS
1291 MOV DX,FCB
1292 MOV AH,OPEN
1293 INT 21H
1294 OR AL,AL
1295 MOV DX,OFFSET TRANGROUP:NOTFND
1296 JNZ ERRJ
1297 XOR AX,AX
1298 MOV WORD PTR DS:[FCB+RR],AX ;Set RR field
1299 MOV WORD PTR DS:[FCB+RR+2],AX
1300 INC AX
1301 MOV WORD PTR DS:[FCB+RECLEN],AX ;Set record length
1302 MOV ES,[TPA]
1303 TYPELP:
1304 MOV DX,FCB
1305 MOV CX,[BYTCNT]
1306 MOV AH,RDBLK
1307 INT 21H
1308 JCXZ RET30
1309 XOR SI,SI ;Start at 0 in TPA
1310 OUTLP:
1311 LODS BYTE PTR ES:[SI] ;In TPA segment
1312 CMP AL,1AH
1313 JZ RET30
1314 MOV AH,OUTCH
1315 MOV DL,AL
1316 INT 21H
1317 LOOP OUTLP
1318 JMP SHORT TYPELP
1319
1320 RET30: RET ;Need a nearby RET
1321
1322 COPY:
1323 XOR AX,AX
1324 MOV [PLUS],AL ;Will keep track of "+"s
1325 MOV [FILECNT],AX
1326 MOV SI,81H ;Point to input line
1327 CALL SWITCH ;Skip over switches on command
1328 MOV BP,AX
1329 MOV DI,FCB
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
1334 SCANNAM:
1335 CALL PARSE
1336 JNZ SCANNAM
1337 GETDEST:
1338 MOV DI,OFFSET TRANGROUP:DEST
1339 MOV BX,BP ;Remeber switches so far
1340 XOR BP,BP ;Must have dest. swtiches alone
1341 CALL PARSNAM
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 *.*
1346 MOV CX,11
1347 REP STOSB
1348 HAVDESTNAM:
1349 OR BX,BP ;BX = all switches combined
1350 AND BL,VSWITCH ;Verify requested?
1351 JZ NOVER
1352 MOV AX,46*100H+1 ;Set verify
1353 MOV DL,0
1354 INT 33
1355 NOVER:
1356 MOV DI,OFFSET TRANGROUP:DESTNAME
1357 MOV SI,OFFSET TRANGROUP:DEST+1
1358 MOV BX,FCB+1
1359 CALL BUILDNAME ;See if we can make it unambiguous
1360 MOV DI,OFFSET TRANGROUP:DESTNAME
1361 MOV AL,"?"
1362 MOV CX,11
1363 REPNE SCASB ;Scan for "?" to see if ambiguous
1364 MOV AL,1 ;Flag if ambig.
1365 JZ AMBIG
1366 DEC AX ;AL=0 if unambig.
1367 AMBIG:
1368 MOV DL,AL
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
1375 SHL AL,1
1376 OR AL,DL ;Combine multiple and concat flags
1377 MOV [PARM2],AL
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
1383 MOV AH,SRCHFRST
1384 CALL SEARCH ;Search for first source name
1385 MULTDEST:
1386 JZ FIRSTSRC ;Find a first source name?
1387 TEST [PARM2],1 ;If multiple, we're done
1388 JNZ ENDCOPY
1389 XOR AX,AX
1390 MOV [NXTADD],AX
1391 MOV [CFLAG],AL ;Flag nothing read yet
1392 NEXTSNG:
1393 MOV DI,FCB
1394 MOV SI,[SRCPT]
1395 CALL PARSESRC ;Parse next file name into FCB
1396 MOV [PARM1],DL ;Remember if it's ambiguous
1397 MOV [SRCPT],SI
1398 JZ SNGCLOS
1399 MOV AH,SRCHFRST
1400 CALL SEARCH ;Search for new file name
1401 JNZ NEXTSNG ;If none, skip it and move to next name
1402 READSNG:
1403 CALL CHECKREAD
1404 SNGLOOP:
1405 CALL SEARCHNEXT ;See if any more of this name
1406 JZ READSNG
1407 JMP SHORT NEXTSNG
1408
1409 SNGCLOS:
1410 CALL CLOSEFIL
1411 ENDCOPY:
1412 MOV SI,[FILECNT]
1413 XOR DI,DI
1414 CALL DISP32BITS
1415 MOV DX,OFFSET TRANGROUP:COPIED
1416 MOV AH,PRINTBUF
1417 INT 21H
1418 JMP COMMAND ;Stack could be messed up
1419
1420 FIRSTSRC:
1421 MOV SI,OFFSET TRANGROUP:DIRBUF+1
1422 MOV DI,OFFSET TRANGROUP:SOURCE
1423 MOV CX,11
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
1429 XOR AX,AX
1430 MOV [NXTADD],AX
1431 MOV [CFLAG],AL
1432 MOV [APPEND],AL
1433 MOV [NOWRITE],AL
1434 TEST [PARM2],1 ;Multiple destinations?
1435 JZ NOPRT
1436 MOV SI,OFFSET TRANGROUP:DIRBUF+1
1437 CALL SHONAME ;If so, show first source
1438 CALL CRLF2
1439 NOPRT:
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
1446 MOV AH,OPEN
1447 MOV DX,OFFSET TRANGROUP:DEST
1448 INT 33 ;Open (existing) destination
1449 CMP [ASCII],0 ;ASCII flag set?
1450 JZ BINARYAPP
1451 ;ASCII append. Must find logical EOF, then seek there with dest. FCB
1452 MOV [NOWRITE],1
1453 CALL READIN ;Find EOF
1454 CALL FLSHFIL ;Seek there
1455 MOV [NOWRITE],0
1456 CALL FLSHFIL ;Truncate file
1457 JMP SHORT SNGLCHK
1458
1459 SNGLOOPJ:JMP SNGLOOP
1460
1461 COPERRJ:JMP COPERR
1462
1463 BINARYAPP:
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
1467 MOVSW
1468 MOVSW ;Seek to end of file
1469 MOV [CFLAG],1
1470 JMP SHORT SNGLCHK
1471 DOREAD:
1472 CALL READIN
1473 SNGLCHK:
1474 TEST [PARM2],1 ;Single or multiple destinations?
1475 JZ SNGLOOPJ
1476 MOV SI,[SRCPT]
1477 MULTAPP:
1478 CALL PARSE
1479 JZ MULTCLOS
1480 PUSH SI
1481 MOV SI,OFFSET TRANGROUP:DIRBUF+1
1482 MOV DI,SI
1483 MOV BX,OFFSET TRANGROUP:SOURCE
1484 CALL BUILDNAME
1485 CALL CHECKREAD
1486 POP SI
1487 JMP SHORT MULTAPP
1488 MULTCLOS:
1489 CALL CLOSEFIL
1490 MOV AL,BYTE PTR[COMSW]
1491 MOV [ASCII],AL ;Restore ASCII flag
1492 CALL SEARCHNEXT
1493 JMP MULTDEST
1494
1495 PARSE:
1496 MOV DI,OFFSET TRANGROUP:DIRBUF
1497 PARSESRC:
1498 CALL SCANOFF
1499 CMP AL,"+"
1500 JNZ RETZF
1501 MOV [PLUS],1 ;Keep track of "+" signs
1502 INC SI ;Skip over it
1503 PARSNAM:
1504 MOV AX,2901H
1505 INT 33 ;Parse file name
1506 CMP AL,-1 ;Illegal?
1507 MOV DX,OFFSET TRANGROUP:BADDRV
1508 JZ COPERRJ
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?
1512 JNZ PARSW
1513 MOV AL,[CURDRV] ;Substitute actual drive
1514 INC AX
1515 MOV BYTE PTR[DI],AL
1516 PARSW:
1517 PUSH BX
1518 PUSH DI
1519 CALL SWITCH ;Process switches
1520 OR BP,AX ;Combine all switches
1521 CALL SETASC ;Check for /A or /B
1522 POP DI
1523 POP BX
1524 CMP BYTE PTR[DI+1]," " ;Did we even get a file name?
1525 RET
1526
1527 RETZF:
1528 XOR AX,AX
1529 RET35: RET
1530
1531 SEARCHNEXT:
1532 MOV AL,[PARM1] ;Is name ambiguous?
1533 DEC AL
1534 JNZ RET35 ;Don't perform search if not
1535 MOV AH,SRCHNXT
1536 SEARCH:
1537 PUSH AX
1538 MOV AH,SETDMA
1539 MOV DX,OFFSET TRANGROUP:DIRBUF
1540 INT 33 ;Put result of search in DIRBUF
1541 POP AX ;Restore search first/next command
1542 MOV DX,FCB
1543 INT 33 ;Do the search
1544 OR AL,AL
1545 RET
1546
1547 SETASC:
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
1555 AND AL,ASWITCH
1556 MOV [ASCII],AL
1557 OR [INEXACT],AL
1558 LOADSW:
1559 MOV AL,[ASCII]
1560 OR AL,AL
1561 RET
1562
1563 BUILDNAME:
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].
1569 MOV CX,11
1570 BUILDNAM:
1571 LODSB
1572 CMP AL,"?"
1573 JNZ NOTAMBIG
1574 MOV AL,BYTE PTR[BX]
1575 NOTAMBIG:
1576 STOSB
1577 INC BX
1578 LOOP BUILDNAM
1579 RET
1580
1581 COMPNAME:
1582 MOV SI,OFFSET TRANGROUP:DEST
1583 MOV DI,OFFSET TRANGROUP:DIRBUF
1584 MOV CX,6
1585 REPE CMPSW
1586 RET
1587
1588 CHECKREAD:
1589 ;Read file in (with READIN) if not identical to destination
1590 CALL COMPNAME ;See if source and destination the same
1591 JNZ READIN
1592 CMP [APPEND],0 ;If physical append, it's OK
1593 JNZ RET40
1594 MOV DX,OFFSET TRANGROUP:LOSTERR ;Tell him he's not going to get it
1595 MOV AH,PRINTBUF
1596 INT 33
1597 RET40: RET
1598
1599 READIN:
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.
1602 ; Inputs/Outputs:
1603 ; [NXTADD] has current pointer in buffer
1604 ; [CFLAG] <>0 if destination has been created
1605
1606 MOV DX,OFFSET TRANGROUP:DIRBUF
1607 MOV AH,OPEN
1608 INT 21H
1609 OR AL,AL ;Successful open?
1610 JNZ RET40 ;If not, just ignore it
1611 XOR AX,AX
1612 MOV WORD PTR[DIRBUF+RR],AX
1613 MOV WORD PTR[DIRBUF+RR+2],AX
1614 INC AX
1615 MOV WORD PTR[DIRBUF+RECLEN],AX
1616 COPYLP:
1617 MOV DX,[NXTADD]
1618 MOV AH,SETDMA
1619 PUSH DS
1620 MOV DS,[TPA]
1621 INT 33
1622 POP DS
1623 MOV CX,[BYTCNT]
1624 SUB CX,DX ;Compute available space
1625 MOV DX,OFFSET TRANGROUP:DIRBUF
1626 MOV AH,RDBLK ;Read in source file
1627 INT 21H
1628 JCXZ RET40
1629 CMP [ASCII],0
1630 JZ BINREAD
1631 MOV DX,CX
1632 MOV DI,[NXTADD]
1633 MOV AL,1AH
1634 PUSH ES
1635 MOV ES,[TPA]
1636 REPNE SCASB ;Scan for EOF
1637 POP ES
1638 JNZ USEALL
1639 INC CX
1640 USEALL:
1641 SUB DX,CX
1642 MOV CX,DX
1643 BINREAD:
1644 ADD CX,[NXTADD]
1645 MOV [NXTADD],CX
1646 CMP CX,[BYTCNT] ;Is buffer full?
1647 JB RET40 ;If not, we must have found EOF
1648 CALL FLSHFIL
1649 JMP SHORT COPYLP
1650
1651 CLOSEFIL:
1652 MOV AX,[NXTADD]
1653 MOV BX,AX
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
1659 JZ BINCLOS
1660 CMP BX,[BYTCNT] ;Is memory full?
1661 JNZ PUTZ
1662 CALL FLSHFIL ;Empty it to make room for 1 lousy byte
1663 XOR BX,BX
1664 PUTZ:
1665 PUSH DS
1666 MOV DS,[TPA]
1667 MOV WORD PTR[BX],1AH ;Add End-of-file mark (Ctrl-Z)
1668 POP DS
1669 INC [NXTADD]
1670 BINCLOS:
1671 CALL FLSHFIL
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
1676 MOVSW ;Copy date
1677 MOVSW ;Copy time
1678 NODATE:
1679 MOV DX,OFFSET TRANGROUP:DEST
1680 MOV AH,CLOSE
1681 INT 21H
1682 INC [FILECNT]
1683 RET50: RET
1684
1685 FLSHFIL:
1686 ;Write out any data remaining in memory.
1687 ; Inputs:
1688 ; [NXTADD] = No. of bytes to write
1689 ; [CFLAG] <>0 if file has been created
1690 ; Outputs:
1691 ; [NXTADD] = 0
1692
1693 MOV AL,1
1694 XCHG [CFLAG],AL
1695 OR AL,AL
1696 JNZ EXISTS
1697 CMP [NOWRITE],0
1698 JNZ SKPMAK ;Don't actually create if NOWRITE set
1699 MOV DX,OFFSET TRANGROUP:DEST
1700 MOV AH,MAKE
1701 INT 21H
1702 MOV DX,OFFSET TRANGROUP:FULDIR
1703 OR AL,AL
1704 JNZ COPERR
1705 SKPMAK:
1706 XOR AX,AX
1707 MOV WORD PTR[DEST+RR],AX
1708 MOV WORD PTR[DEST+RR+2],AX
1709 INC AX
1710 MOV WORD PTR[DEST+RECLEN],AX
1711 EXISTS:
1712 XOR CX,CX
1713 XCHG CX,[NXTADD]
1714 CMP [NOWRITE],0 ;If NOWRITE set, just seek CX bytes
1715 JNZ SEEKEND
1716 XOR DX,DX
1717 PUSH DS
1718 MOV DS,[TPA]
1719 MOV AH,SETDMA
1720 INT 33
1721 POP DS
1722 MOV DX,OFFSET TRANGROUP:DEST
1723 MOV AH,WRBLK
1724 INT 21H
1725 OR AL,AL
1726 JZ RET60
1727 MOV DX,OFFSET TRANGROUP:DEST
1728 MOV AH,CLOSE
1729 INT 21H
1730 MOV AH,DELETE
1731 INT 33
1732 MOV DX,OFFSET TRANGROUP:NOSPACE
1733 COPERR:
1734 MOV AH,9
1735 INT 21H
1736 JMP ENDCOPY
1737
1738 SEEKEND:
1739 ADD WORD PTR[DEST+RR],CX
1740 ADC WORD PTR[DEST+RR+2],0 ;Propagate carry
1741 RET60: RET
1742
1743 GETBATBYT:
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.
1747 ASSUME DS:RESGROUP
1748 MOV DX,OFFSET RESGROUP:BATFCB
1749 MOV AH,RDBLK
1750 MOV CX,1
1751 INT 33 ;Get one more byte from batch file
1752 JCXZ BATEOF
1753 MOV AL,[BATBYT]
1754 CMP AL,1AH
1755 JNZ RET70
1756 BATEOF:
1757 MOV AL,0DH ;If end-of-file, then end of line
1758 MOV [BATCH],0 ;And turn off batch mode
1759 RET70: RET
1760 ASSUME DS:TRANGROUP
1761
1762 SCANOFF:
1763 LODSB
1764 CALL DELIM
1765 JZ SCANOFF
1766 DEC SI ;Point to first non-delimiter
1767 RET
1768
1769 DELIM:
1770 CMP AL," "
1771 JZ RET80
1772 CMP AL,"="
1773 JZ RET80
1774 CMP AL,","
1775 JZ RET80
1776 CMP AL,9 ;Check for TAB character
1777 RET80: RET
1778
1779 PAUSE:
1780 MOV DX,OFFSET TRANGROUP:PAUSMES
1781 MOV AH,PRINTBUF
1782 INT 33
1783 MOV AX,0C00H+INCHAR ;Get character with KB buffer flush
1784 INT 33
1785 RET90: RET
1786
1787 ;Date and time are set during initialization and use
1788 ;this routines since they need to do a long return
1789
1790 DATINIT:
1791 PUSH ES
1792 PUSH DS ;Going to use the previous stack
1793 MOV AX,CS ;Set up the appropriate segment registers
1794 MOV ES,AX
1795 MOV DS,AX
1796 MOV WORD PTR DS:[81H],13 ;Want to prompt for date during initialization
1797 CALL DATE
1798 CALL TIME
1799 POP DS
1800 POP ES
1801 YYY PROC FAR
1802 RET
1803 YYY ENDP
1804
1805 ; DATE - Gets and sets the time
1806
1807 DATE:
1808 MOV SI,81H ;Accepting argument for date inline
1809 CALL SCANOFF
1810 CMP AL,13
1811 JZ PRMTDAT
1812 MOV BX,2F00H+"-" ;"/-"
1813 CALL INLINE
1814 JMP COMDAT
1815
1816 PRMTDAT:
1817 MOV DX,OFFSET TRANGROUP:CURDAT
1818 MOV AH,PRINTBUF
1819 INT 33 ;Print "Current date is "
1820 MOV AH,GETDATE
1821 INT 33 ;Get date in CX:DX
1822 CBW
1823 MOV SI,AX
1824 SHL SI,1
1825 ADD SI,AX ;SI=AX*3
1826 ADD SI,OFFSET TRANGROUP:WEEKTAB
1827 MOV BX,CX
1828 MOV CX,3
1829 CALL OUTCNT
1830 MOV AL," "
1831 CALL OUT
1832 MOV AX,BX
1833 MOV CX,DX
1834 MOV DL,100
1835 DIV DL
1836 XCHG AL,AH
1837 XCHG AX,DX
1838 MOV BL,"-"
1839 CALL SHOW
1840 GETDAT:
1841 MOV DX,OFFSET TRANGROUP:NEWDAT
1842 MOV BX,2F00H+"-" ;"/-" in BX
1843 CALL GETBUF
1844 COMDAT: JZ RET90
1845 JC DATERR
1846 LODSB
1847 CMP AL,BL
1848 JZ SEPGD
1849 CMP AL,BH
1850 JNZ DATERR
1851 SEPGD: CALL GETNUM
1852 JC DATERR
1853 MOV CX,1900
1854 CMP BYTE PTR[SI],13
1855 JZ BIAS
1856 MOV AL,100
1857 MUL AH
1858 MOV CX,AX
1859 CALL GETNUM
1860 JC DATERR
1861 BIAS:
1862 MOV AL,AH
1863 MOV AH,0
1864 ADD CX,AX
1865 LODSB
1866 CMP AL,13
1867 JNZ DATERR
1868 MOV AH,SETDATE
1869 INT 33
1870 OR AL,AL
1871 JNZ DATERR
1872 JMP RET90
1873 DATERR:
1874 MOV DX,OFFSET TRANGROUP:BADDAT
1875 MOV AH,PRINTBUF
1876 INT 33
1877 JMP GETDAT
1878
1879 ; TIME gets and sets the time
1880
1881 TIME:
1882 MOV SI,81H ;Accepting argument for time inline
1883 CALL SCANOFF
1884 CMP AL,13
1885 JZ PRMTTIM
1886 MOV BX,3A00H+":"
1887 CALL INLINE
1888 JMP COMTIM
1889
1890 PRMTTIM:
1891 MOV DX,OFFSET TRANGROUP:CURTIM
1892 MOV AH,PRINTBUF
1893 INT 33 ;Print "Current time is "
1894 MOV AH,GETTIME
1895 INT 33 ;Get time in CX:DX
1896 MOV BL,":"
1897 CALL SHOW
1898 GETTIM:
1899 XOR CX,CX ;Initialize hours and minutes to zero
1900 MOV DX,OFFSET TRANGROUP:NEWTIM
1901 MOV BX,3A00H+":"
1902 CALL GETBUF
1903 COMTIM: JZ RET100 ;If no time present, don't change it
1904 JC TIMERR
1905 MOV CX,DX
1906 XOR DX,DX
1907 LODSB
1908 CMP AL,13
1909 JZ SAVTIM
1910 CMP AL,BL
1911 JNZ TIMERR
1912 MOV BL,"."
1913 CALL GETNUM
1914 JC TIMERR
1915 MOV DH,AH ;Position seconds
1916 LODSB
1917 CMP AL,13
1918 JZ SAVTIM
1919 CMP AL,BL
1920 JNZ TIMERR
1921 CALL GETNUM
1922 JC TIMERR
1923 MOV DL,AH
1924 LODSB
1925 CMP AL,13
1926 JNZ TIMERR
1927 SAVTIM:
1928 MOV AH,SETTIME
1929 INT 33
1930 OR AL,AL
1931 JZ RET100 ;Error in time?
1932 TIMERR:
1933 MOV DX,OFFSET TRANGROUP:BADTIM
1934 MOV AH,PRINTBUF
1935 INT 33 ;Print error message
1936 JMP GETTIM ;Try again
1937
1938 GETBUF:
1939 MOV AH,PRINTBUF
1940 INT 33 ;Print "Enter new date: "
1941 MOV AH,INBUF
1942 MOV DX,OFFSET TRANGROUP:COMBUF
1943 INT 33 ;Get input line
1944 CALL CRLF2
1945 MOV SI,OFFSET TRANGROUP:COMBUF+2
1946 CMP BYTE PTR[SI],13 ;Check if new date entered
1947 JZ RET100
1948 INLINE:
1949 CALL GETNUM ;Get one or two digit number
1950 JC RET100
1951 MOV DH,AH ;Put in position
1952 LODSB
1953 CMP AL,BL
1954 JZ NEXT
1955 CMP BL,":" ;Is it a date seperator?
1956 JNZ DATESEP
1957 DEC SI
1958 MOV DL,0
1959 RET100: RET ;Time may have only an hour specified
1960 DATESEP:
1961 CMP AL,BH
1962 STC
1963 JNZ RET100
1964 NEXT: CALL GETNUM
1965 MOV DL,AH ;Put in position
1966 RET
1967
1968 GETNUM:
1969 CALL INDIG
1970 JC RET100
1971 MOV AH,AL ;Save first digit
1972 CALL INDIG ;Another digit?
1973 JC OKRET
1974 AAD ;Convert unpacked BCD to decimal
1975 MOV AH,AL
1976 OKRET:
1977 OR AL,1
1978 RET110: RET
1979
1980 INDIG:
1981 MOV AL,BYTE PTR[SI]
1982 SUB AL,"0"
1983 JC RET110
1984 CMP AL,10
1985 CMC
1986 JC RET110
1987 INC SI
1988 RET
1989
1990 SHOW:
1991 MOV AL,CH
1992 MOV BH,"0"-" " ;Enable leading zero suppression
1993 CALL OUT2
1994 MOV AL,BL
1995 CALL OUT
1996 MOV AL,CL
1997 CALL OUT2
1998 MOV AL,BL
1999 CALL OUT
2000 MOV AL,DH
2001 CALL OUT2
2002 CMP BL,":" ;Are we outputting time?
2003 JNZ SKIPIT
2004 MOV AL,"."
2005 CALL OUT
2006 SKIPIT: MOV AL,DL
2007 OUT2: ;Output binary number as two ASCII digits
2008 AAM ;Convert binary to unpacked BCD
2009 XCHG AL,AH
2010 OR AX,3030H ;Add "0" bias to both digits
2011 CMP AL,"0" ;Is MSD zero?
2012 JNZ NOSUP
2013 SUB AL,BH ;Suppress leading zero if enabled
2014 NOSUP:
2015 MOV BH,0 ;Disable zero suppression
2016 CALL OUT
2017 MOV AL,AH
2018 OUT:
2019 ;Print char in AL without affecting registers
2020 XCHG AX,DX
2021 PUSH AX
2022 MOV AH,OUTCH
2023 INT 33
2024 POP AX
2025 XCHG AX,DX
2026 RET
2027
2028 EXELOAD:
2029 MOV AX,CS
2030 ADD AX,LOADSEG
2031 MOV [EXEEND],AX ;Store in EXEEND
2032 MOV DX,OFFSET TRANGROUP:RUNVAR ;Read header in here
2033 MOV AH,SETDMA
2034 INT 33
2035 MOV CX,RUNVARSIZ ;Amount of header info we need
2036 MOV DX,OFFSET TRANGROUP:EXEFCB
2037 MOV AH,RDBLK
2038 INT 33 ;Read in header
2039 OR AL,AL
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
2044 MOV CL,5
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
2051 MOV [PSIZE],DX
2052 SHL DX,CL ;Convert pages back to paragraphs
2053 MOV AX,DX
2054 ADD DX,BX ;Size + start = minimum memory (paragr.)
2055 MOV CX,[EXEEND] ;Get memory size in paragraphs
2056 CMP DX,CX ;Enough memory?
2057 JA SHRTERR
2058 MOV DX,[INITSP]
2059 ADD DX,15
2060 SHR DX,1
2061 SHR DX,1
2062 SHR DX,1
2063 SHR DX,1
2064 ADD DX,[INITSS]
2065 ADD DX,BX ;Adjusted value of SP
2066 CMP DX,CX ;Is it valid?
2067 JA SHRTERR
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.
2071 MOV BX,CX
2072 LOAD:
2073 MOV BP,BX ;Save load segment
2074 LOAD1:
2075 LOADSEG EQU (LOAD1-ZERO)/16
2076 PUSH DS
2077 MOV DS,BX
2078 XOR DX,DX ;Address 0 in segment
2079 MOV AH,SETDMA
2080 INT 33 ;Set load address
2081 POP DS
2082 MOV CX,[PSIZE] ;Number of records to read
2083 MOV DX,OFFSET TRANGROUP:EXEFCB
2084 MOV AH,RDBLK
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
2092
2093 BADEXE:
2094 MOV DX,OFFSET TRANGROUP:EXEBAD
2095 JMP ERROR
2096
2097 SHRTERR:
2098 MOV DX,OFFSET TRANGROUP:TOOBIG
2099 JMP ERROR
2100
2101 HAVEXE:
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
2106 MOV AH,SETDMA
2107 INT 33
2108 CMP [RELCNT],0
2109 JZ NOREL
2110 RELOC:
2111 MOV AH,RDBLK
2112 MOV DX,OFFSET TRANGROUP:EXEFCB
2113 MOV CX,4
2114 INT 33 ;Read in one relocation pointer
2115 OR AL,AL ;Check return code
2116 JNZ BADEXE
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
2120 MOV ES,AX
2121 ADD WORD PTR ES:[DI],BP ;Relocate
2122 DEC [RELCNT] ;Count off
2123 JNZ RELOC
2124 ;Set up exit conditions
2125 NOREL:
2126 MOV AX,[INITSS]
2127 ADD AX,BP
2128 CLI
2129 MOV SS,AX ;Initialize SS
2130 MOV SP,[INITSP]
2131 STI
2132 ADD [INITCS],BP
2133 MOV AX,[TPA] ;Get pointer to parameter area
2134 MOV CX,[BYTCNT] ;Size of TPA segment
2135 MOV ES,AX
2136 MOV DS,AX ;Set segment registers to point to it
2137 CALL SETUP
2138 JMP DWORD PTR CS:[INITIP] ;Long jump to program
2139
2140 SETUP:
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
2145 MOV CL,4
2146 SAR AX,CL ;Convert to a segment address
2147 ADD WORD PTR DS:[8],AX ;Adjust long jump to go to same place
2148 MOV DX,80H
2149 MOV AH,SETDMA
2150 INT 33 ;Set default disk transfer address
2151 MOV AX,WORD PTR CS:[PARM1] ;Pass on info about FCBs
2152 XOR CX,CX
2153 MOV DX,CX ;Assume no batch file
2154 ASSUME CS:RESGROUP
2155 TEST CS:[BATCH],-1 ;Batch file in progress?
2156 ASSUME CS:TRANGROUP
2157 JZ RET120 ;If not, all set up
2158 MOV CX,CS:[RESSEG]
2159 MOV DX,OFFSET RESGROUP:BATFCB ;CX:DX points to batch FCB
2160 RET120: RET
2161 TRANCODESIZE EQU $-ZERO
2162 TRANCODE ENDS
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
2165 END PROGSTART
2166 \1a