From 124d0e882e417e0c89d348308f9a8f7d174c4760 Mon Sep 17 00:00:00 2001 From: Broken Pipe <85091235+TheBrokenPipe@users.noreply.github.com> Date: Fri, 3 Oct 2025 12:48:30 +1000 Subject: [PATCH] Added files --- .gitattributes | 4 +- ALLOC.ASM | 371 ++++++++++ BUF.ASM | 508 +++++++++++++ CHKDSK.ASM | 901 +++++++++++++++++++++++ CHKMES.ASM | 477 +++++++++++++ CHKPROC.ASM | 1408 ++++++++++++++++++++++++++++++++++++ COMEQU.ASM | 33 + COMLINK | Bin 0 -> 128 bytes COMMAND.ASM | 788 +++++++++++++++++++++ COMSEG.ASM | 38 + COMSW.ASM | 13 + COPY.ASM | 579 +++++++++++++++ COPYPROC.ASM | 526 ++++++++++++++ CPARSE.ASM | 291 ++++++++ CTRLC.ASM | 468 ++++++++++++ DEBASM.ASM | 1264 +++++++++++++++++++++++++++++++++ DEBCOM1.ASM | 694 ++++++++++++++++++ DEBCOM2.ASM | 1269 +++++++++++++++++++++++++++++++++ DEBCONST.ASM | 1103 +++++++++++++++++++++++++++++ DEBDATA.ASM | Bin 0 -> 2816 bytes DEBEQU.ASM | 32 + DEBMES.ASM | Bin 0 -> 5248 bytes DEBUASM.ASM | 868 +++++++++++++++++++++++ DEBUG.ASM | 838 ++++++++++++++++++++++ DEV.ASM | 439 ++++++++++++ DIR.ASM | 1084 ++++++++++++++++++++++++++++ DIRCALL.ASM | 507 +++++++++++++ DISK.ASM | 1302 ++++++++++++++++++++++++++++++++++ DISKCOPY.ASM | Bin 0 -> 6656 bytes DISKMES.ASM | Bin 0 -> 7808 bytes DOSLINK | 5 + DOSMAC.ASM | 274 +++++++ DOSMES.ASM | 355 ++++++++++ DOSSEG.ASM | 17 + DOSSYM.ASM | 963 +++++++++++++++++++++++++ EDLIN.ASM | 1846 ++++++++++++++++++++++++++++++++++++++++++++++++ EDLMES.ASM | Bin 0 -> 3200 bytes EDLPROC.ASM | 531 ++++++++++++++ EXE2BIN.ASM | 514 ++++++++++++++ EXEC.ASM | 1035 +++++++++++++++++++++++++++ EXEMES.ASM | Bin 0 -> 768 bytes FAT.ASM | 362 ++++++++++ FC.ASM | 1684 +++++++++++++++++++++++++++++++++++++++++++ FCB.ASM | 512 ++++++++++++++ FCMES.ASM | Bin 0 -> 2048 bytes FIND.ASM | 932 ++++++++++++++++++++++++ FINDMES.ASM | Bin 0 -> 1408 bytes FORMAT.ASM | 1627 ++++++++++++++++++++++++++++++++++++++++++ FORMES.ASM | Bin 0 -> 4529 bytes GETSET.ASM | 627 ++++++++++++++++ IFEQU.ASM | 18 + INIT.ASM | 939 ++++++++++++++++++++++++ LICENSE | 2 +- MISC.ASM | 648 +++++++++++++++++ MORE.ASM | Bin 0 -> 3712 bytes MOREMES.ASM | 17 + MSCODE.ASM | 615 ++++++++++++++++ MSDATA.ASM | 342 +++++++++ MSDOS.ASM | 12 + MSHEAD.ASM | 198 ++++++ MSINIT.ASM | 408 +++++++++++ PRINT.ASM | 1645 ++++++++++++++++++++++++++++++++++++++++++ PROC.ASM | 130 ++++ RDATA.ASM | Bin 0 -> 6784 bytes README.md | 98 ++- RECMES.ASM | Bin 0 -> 5760 bytes RECOVER.ASM | 876 +++++++++++++++++++++++ ROM.ASM | 530 ++++++++++++++ RUCODE.ASM | Bin 0 -> 6912 bytes SORT.ASM | 420 +++++++++++ SORTMES.ASM | Bin 0 -> 2688 bytes STDBUF.ASM | Bin 0 -> 256 bytes STDCALL.ASM | Bin 0 -> 256 bytes STDCTRLC.ASM | Bin 0 -> 256 bytes STDFCB.ASM | 16 + STDIO.ASM | 17 + STDPROC.ASM | 16 + STDSW.ASM | 34 + STRIN.ASM | 292 ++++++++ SYS.ASM | 587 +++++++++++++++ SYSCALL.ASM | 749 ++++++++++++++++++++ SYSIMES.ASM | Bin 0 -> 512 bytes SYSINIT.ASM | 1424 +++++++++++++++++++++++++++++++++++++ SYSMES.ASM | 51 ++ TCODE.ASM | 1088 ++++++++++++++++++++++++++++ TCODE2.ASM | 522 ++++++++++++++ TCODE3.ASM | 677 ++++++++++++++++++ TCODE4.ASM | 1002 ++++++++++++++++++++++++++ TCODE5.ASM | 953 +++++++++++++++++++++++++ TDATA.ASM | 243 +++++++ TIME.ASM | Bin 0 -> 7040 bytes TSPC.ASM | Bin 0 -> 4480 bytes TUCODE.ASM | Bin 0 -> 7808 bytes UINIT.ASM | Bin 0 -> 896 bytes XENIX.ASM | 907 ++++++++++++++++++++++++ XENIX2.ASM | 626 ++++++++++++++++ 96 files changed, 43187 insertions(+), 4 deletions(-) create mode 100644 ALLOC.ASM create mode 100644 BUF.ASM create mode 100644 CHKDSK.ASM create mode 100644 CHKMES.ASM create mode 100644 CHKPROC.ASM create mode 100644 COMEQU.ASM create mode 100644 COMLINK create mode 100644 COMMAND.ASM create mode 100644 COMSEG.ASM create mode 100644 COMSW.ASM create mode 100644 COPY.ASM create mode 100644 COPYPROC.ASM create mode 100644 CPARSE.ASM create mode 100644 CTRLC.ASM create mode 100644 DEBASM.ASM create mode 100644 DEBCOM1.ASM create mode 100644 DEBCOM2.ASM create mode 100644 DEBCONST.ASM create mode 100644 DEBDATA.ASM create mode 100644 DEBEQU.ASM create mode 100644 DEBMES.ASM create mode 100644 DEBUASM.ASM create mode 100644 DEBUG.ASM create mode 100644 DEV.ASM create mode 100644 DIR.ASM create mode 100644 DIRCALL.ASM create mode 100644 DISK.ASM create mode 100644 DISKCOPY.ASM create mode 100644 DISKMES.ASM create mode 100644 DOSLINK create mode 100644 DOSMAC.ASM create mode 100644 DOSMES.ASM create mode 100644 DOSSEG.ASM create mode 100644 DOSSYM.ASM create mode 100644 EDLIN.ASM create mode 100644 EDLMES.ASM create mode 100644 EDLPROC.ASM create mode 100644 EXE2BIN.ASM create mode 100644 EXEC.ASM create mode 100644 EXEMES.ASM create mode 100644 FAT.ASM create mode 100644 FC.ASM create mode 100644 FCB.ASM create mode 100644 FCMES.ASM create mode 100644 FIND.ASM create mode 100644 FINDMES.ASM create mode 100644 FORMAT.ASM create mode 100644 FORMES.ASM create mode 100644 GETSET.ASM create mode 100644 IFEQU.ASM create mode 100644 INIT.ASM create mode 100644 MISC.ASM create mode 100644 MORE.ASM create mode 100644 MOREMES.ASM create mode 100644 MSCODE.ASM create mode 100644 MSDATA.ASM create mode 100644 MSDOS.ASM create mode 100644 MSHEAD.ASM create mode 100644 MSINIT.ASM create mode 100644 PRINT.ASM create mode 100644 PROC.ASM create mode 100644 RDATA.ASM create mode 100644 RECMES.ASM create mode 100644 RECOVER.ASM create mode 100644 ROM.ASM create mode 100644 RUCODE.ASM create mode 100644 SORT.ASM create mode 100644 SORTMES.ASM create mode 100644 STDBUF.ASM create mode 100644 STDCALL.ASM create mode 100644 STDCTRLC.ASM create mode 100644 STDFCB.ASM create mode 100644 STDIO.ASM create mode 100644 STDPROC.ASM create mode 100644 STDSW.ASM create mode 100644 STRIN.ASM create mode 100644 SYS.ASM create mode 100644 SYSCALL.ASM create mode 100644 SYSIMES.ASM create mode 100644 SYSINIT.ASM create mode 100644 SYSMES.ASM create mode 100644 TCODE.ASM create mode 100644 TCODE2.ASM create mode 100644 TCODE3.ASM create mode 100644 TCODE4.ASM create mode 100644 TCODE5.ASM create mode 100644 TDATA.ASM create mode 100644 TIME.ASM create mode 100644 TSPC.ASM create mode 100644 TUCODE.ASM create mode 100644 UINIT.ASM create mode 100644 XENIX.ASM create mode 100644 XENIX2.ASM diff --git a/.gitattributes b/.gitattributes index dfe0770..d612cfe 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ -# Auto detect text files and perform LF normalization -* text=auto +# Treat all files as binary so we don't screw them up +* binary diff --git a/ALLOC.ASM b/ALLOC.ASM new file mode 100644 index 0000000..7b69826 --- /dev/null +++ b/ALLOC.ASM @@ -0,0 +1,371 @@ +; +; xenix memory calls for MSDOS +; +; CAUTION: The following routines rely on the fact that arena_signature and +; arena_owner_system are all equal to zero and are contained in DI. +; +INCLUDE DOSSEG.ASM + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xlist +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + +TITLE ALLOC.ASM - memory arena manager +NAME Alloc + +SUBTTL memory allocation utility routines +PAGE +; +; arena data +; + i_need arena_head,WORD ; seg address of start of arena + i_need CurrentPDB,WORD ; current process data block addr + i_need FirstArena,WORD ; first free block found + i_need BestArena,WORD ; best free block found + i_need LastArena,WORD ; last free block found + i_need AllocMethod,BYTE ; how to alloc first(best)last + +; +; arena_free_process +; input: BX - PID of process +; output: free all blocks allocated to that PID +; + procedure arena_free_process,NEAR + ASSUME DS:NOTHING,ES:NOTHING + MOV DI,arena_signature + MOV AX,[arena_head] + CALL Check_Signature ; ES <- AX, check for valid block + +arena_free_process_loop: + retc + PUSH ES + POP DS + CMP DS:[arena_owner],BX ; is block owned by pid? + JNZ arena_free_next ; no, skip to next + MOV DS:[arena_owner],DI ; yes... free him + +arena_free_next: + CMP BYTE PTR DS:[DI],arena_signature_end + ; end of road, Jack? + retz ; never come back no more + CALL arena_next ; next item in ES/AX carry set if trash + JMP arena_free_process_loop + +arena_free_process ENDP + +; +; arena_next +; input: DS - pointer to block head +; output: AX,ES - pointers to next head +; carry set if trashed arena +; + procedure arena_next,NEAR + ASSUME DS:NOTHING,ES:NOTHING + MOV AX,DS ; AX <- current block + ADD AX,DS:[arena_size] ; AX <- AX + current block length + INC AX ; remember that header! +; +; fall into check_signature and return +; +; CALL check_signature ; ES <- AX, carry set if error +; RET +arena_next ENDP + +; +; check_signature +; input: AX - address of block header +; output: ES=AX, carry set if signature is bad +; + procedure check_signature,NEAR + ASSUME DS:NOTHING,ES:NOTHING + MOV ES,AX ; ES <- AX + CMP BYTE PTR ES:[DI],arena_signature_normal + ; IF next signature = not_end THEN + JZ check_signature_ok ; GOTO ok + CMP BYTE PTR ES:[DI],arena_signature_end + ; IF next signature = end then + JZ check_signature_ok ; GOTO ok + STC ; set error + return + +check_signature_ok: + CLC + return +Check_signature ENDP + +; +; Coalesce - combine free blocks ahead with current block +; input: DS - pointer to head of free block +; output: updated head of block, AX is next block +; carry set -> trashed arena +; + procedure Coalesce,NEAR + ASSUME DS:NOTHING,ES:NOTHING + CMP BYTE PTR DS:[DI],arena_signature_end + ; IF current signature = END THEN + retz ; GOTO ok + CALL arena_next ; ES, AX <- next block, Carry set if error + retc ; IF no error THEN GOTO check + +coalesce_check: + CMP ES:[arena_owner],DI + retnz ; IF next block isnt free THEN return + MOV CX,ES:[arena_size] ; CX <- next block size + INC CX ; CX <- CX + 1 (for header size) + ADD DS:[arena_size],CX ; current size <- current size + CX + MOV CL,ES:[DI] ; move up signature + MOV DS:[DI],CL + JMP coalesce ; try again +Coalesce ENDP + +SUBTTL $Alloc - allocate space in memory +PAGE +; +; Assembler usage: +; MOV BX,size +; MOV AH,Alloc +; INT 21h +; AX:0 is pointer to allocated memory +; BX is max size if not enough memory +; +; Description: +; Alloc returns a pointer to a free block of +; memory that has the requested size in paragraphs. +; +; Error return: +; AX = error_not_enough_memory +; = error_arena_trashed +; + procedure $ALLOC,NEAR + ASSUME DS:NOTHING,ES:NOTHING + + XOR AX,AX + MOV DI,AX + + MOV [FirstArena],AX ; init the options + MOV [BestArena],AX + MOV [LastArena],AX + + PUSH AX ; alloc_max <- 0 + MOV AX,[arena_head] ; AX <- beginning of arena + CALL Check_signature ; ES <- AX, carry set if error + JC alloc_err ; IF error THEN GOTO err + +alloc_scan: + PUSH ES + POP DS ; DS <- ES + CMP DS:[arena_owner],DI + JZ alloc_free ; IF current block is free THEN examine + +alloc_next: + CMP BYTE PTR DS:[DI],arena_signature_end + ; IF current block is last THEN + JZ alloc_end ; GOTO end + CALL arena_next ; AX, ES <- next block, Carry set if error + JNC alloc_scan ; IF no error THEN GOTO scan + +alloc_err: + POP AX + +alloc_trashed: + error error_arena_trashed + +alloc_end: + CMP [FirstArena],0 + JNZ alloc_do_split + +alloc_fail: + invoke get_user_stack + POP BX + MOV [SI].user_BX,BX + error error_not_enough_memory + +alloc_free: + CALL coalesce ; add following free block to current + JC alloc_err ; IF error THEN GOTO err + MOV CX,DS:[arena_size] + + POP DX ; check for max found size + CMP CX,DX + JNA alloc_test + MOV DX,CX + +alloc_test: + PUSH DX + CMP BX,CX ; IF BX > size of current block THEN + JA alloc_next ; GOTO next + + CMP [FirstArena],0 + JNZ alloc_best + MOV [FirstArena],DS ; save first one found +alloc_best: + CMP [BestArena],0 + JZ alloc_make_best ; initial best + PUSH ES + MOV ES,[BestArena] + CMP ES:[arena_size],CX ; is size of best larger than found? + POP ES + JBE alloc_last +alloc_make_best: + MOV [BestArena],DS ; assign best +alloc_last: + MOV [LastArena],DS ; assign last + JMP alloc_next + +; +; split the block high +; +alloc_do_split_high: + MOV DS,[LastArena] + MOV CX,DS:[arena_size] + SUB CX,BX + MOV DX,DS + JE alloc_set_owner ; sizes are equal, no split + ADD DX,CX ; point to next block + MOV ES,DX ; no decrement! + DEC CX + XCHG BX,CX ; bx has size of lower block + JMP alloc_set_sizes ; cx has upper (requested) size + +; +; we have scanned memory and have found all appropriate blocks +; check for the type of allocation desired; first and best are identical +; last must be split high +; +alloc_do_split: + CMP BYTE PTR [AllocMethod], 1 + JA alloc_do_split_high + MOV DS,[FirstArena] + JB alloc_get_size + MOV DS,[BestArena] +alloc_get_size: + MOV CX,DS:[arena_size] + SUB CX,BX ; get room left over + MOV AX,DS + MOV DX,AX ; save for owner setting + JE alloc_set_owner ; IF BX = size THEN (don't split) + ADD AX,BX + INC AX ; remember the header + MOV ES,AX ; ES <- DS + BX (new header location) + DEC CX ; CX <- size of split block +alloc_set_sizes: + MOV DS:[arena_size],BX ; current size <- BX + MOV ES:[arena_size],CX ; split size <- CX + MOV BL,arena_signature_normal + XCHG BL,DS:[DI] ; current signature <- 4D + MOV ES:[DI],BL ; new block sig <- old block sig + MOV ES:[arena_owner],DI + +alloc_set_owner: + MOV DS,DX + MOV AX,[CurrentPDB] + MOV DS:[arena_owner],AX + MOV AX,DS + INC AX + POP BX + transfer SYS_RET_OK + +$alloc ENDP + +SUBTTL $SETBLOCK - change size of an allocated block (if possible) +PAGE +; +; Assembler usage: +; MOV ES,block +; MOV BX,newsize +; MOV AH,setblock +; INT 21h +; if setblock fails for growing, BX will have the maximum +; size possible +; Error return: +; AX = error_invalid_block +; = error_arena_trashed +; = error_not_enough_memory +; = error_invalid_function +; + procedure $SETBLOCK,NEAR + ASSUME DS:NOTHING,ES:NOTHING + MOV DI,arena_signature + MOV AX,ES + DEC AX + CALL check_signature + JNC setblock_grab + +setblock_bad: + JMP alloc_trashed + +setblock_grab: + MOV DS,AX + CALL coalesce + JC setblock_bad + MOV CX,DS:[arena_size] + PUSH CX + CMP BX,CX + JBE alloc_get_size + JMP alloc_fail +$setblock ENDP + +SUBTTL $DEALLOC - free previously allocated piece of memory +PAGE +; +; Assembler usage: +; MOV ES,block +; MOV AH,dealloc +; INT 21h +; +; Error return: +; AX = error_invalid_block +; = error_arena_trashed +; + procedure $DEALLOC,NEAR + ASSUME DS:NOTHING,ES:NOTHING + MOV DI,arena_signature + MOV AX,ES + DEC AX + CALL check_signature + JC dealloc_err + MOV ES:[arena_owner],DI + transfer SYS_RET_OK + +dealloc_err: + error error_invalid_block +$DEALLOC ENDP + +SUBTTL $AllocOper - get/set allocation mechanism +PAGE +; +; Assembler usage: +; MOV AH,AllocOper +; MOV BX,method +; MOV AL,func +; INT 21h +; +; Error return: +; AX = error_invalid_function +; + procedure $AllocOper,NEAR + ASSUME DS:NOTHING,ES:NOTHING + CMP AL,1 + JB AllocOperGet + JZ AllocOperSet + error error_invalid_function +AllocOperGet: + MOV AL,BYTE PTR [AllocMethod] + XOR AH,AH + transfer SYS_RET_OK +AllocOperSet: + MOV [AllocMethod],BL + transfer SYS_RET_OK +$AllocOper ENDP + +do_ext + +CODE ENDS + END + \ No newline at end of file diff --git a/BUF.ASM b/BUF.ASM new file mode 100644 index 0000000..70d795b --- /dev/null +++ b/BUF.ASM @@ -0,0 +1,508 @@ +; +; buffer management for MSDOS +; + +INCLUDE DOSSEG.ASM + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xlist +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + + i_need BuffHead,DWORD + i_need PreRead,WORD + i_need LastBuffer,DWORD + i_need CurBuf,DWORD + i_need WPErr,BYTE + +SUBTTL SETVISIT,SKIPVISIT -- MANAGE BUFFER SCANS +PAGE + procedure SETVISIT,near +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; None +; Function: +; Set up a scan of I/O buffers +; Outputs: +; All visit flags = 0 +; NOTE: This pre-scan is needed because a hard disk error +; may cause a scan to stop in the middle leaving some +; visit flags set, and some not set. +; DS:DI Points to [BUFFHEAD] +; No other registers altered + + LDS DI,[BUFFHEAD] + PUSH AX + XOR AX,AX +SETLOOP: + MOV [DI.VISIT],AL + LDS DI,[DI.NEXTBUF] + CMP DI,-1 + JNZ SETLOOP + LDS DI,[BUFFHEAD] + POP AX + return + + entry SKIPVISIT +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DI Points to a buffer +; Function: +; Skip visited buffers +; Outputs: +; DS:DI Points to next unvisited buffer +; Zero is set if skip to LAST buffer +; No other registers altered + + CMP DI,-1 + retz + CMP [DI.VISIT],1 + retnz + LDS DI,[DI.NEXTBUF] + JMP SHORT SKIPVISIT + return +SetVisit ENDP + + +SUBTTL SCANPLACE, PLACEBUF -- PUT A BUFFER BACK IN THE POOL +PAGE + procedure ScanPlace,near +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; Same as PLACEBUF +; Function: +; Save scan location and call PLACEBUF +; Outputs: +; DS:DI Points to saved scan location +; SI destroyed, other registers unchanged + + PUSH ES + LES SI,[DI.NEXTBUF] ; Save scan location + CALL PLACEBUF + PUSH ES + POP DS ; Restore scan location + MOV DI,SI + POP ES + return +ScanPlace ENDP + +NRETJ: JMP SHORT NRET + + procedure PLACEBUF,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Input: +; DS:DI points to buffer +; Function: +; Remove buffer from queue and re-insert it in proper place. +; If buffer doesn't go at end, and isn't free, decrement +; priorities. +; NO registers altered +; +; DS:SI -- Curbuf, current buffer in list +; ES:DI -- Buf, buffer passed as argument +; BP:CX -- Pointsave, saved Buf.nextbuf +; DX:BX -- Lastbuf, previous buffer in list +; AL -- Inserted, Buf has been inserted +; AH -- Removed, Buf has been removed + + IF IBM + IF NOT IBM + invoke save_world + XOR AX,AX ; Inserted = Removed = FALSE + LES CX,[DI.NEXTBUF] + MOV BP,ES ; Pointsave = Buf.nextbuf + MOV SI,DS + MOV ES,SI ; Buf is ES:DI + LDS SI,[BUFFHEAD] ; Curbuf = HEAD + CALL POINTCOMP ; Buf == HEAD? + JNZ TNEWHEAD + CMP CX,-1 ; Buf is LAST? + JZ NRETJ ; Only one buffer, nothing to do + MOV WORD PTR [BUFFHEAD],CX + MOV WORD PTR [BUFFHEAD+2],BP ; HEAD = Pointsave + INC AH ; Removed = TRUE + MOV DS,BP + MOV SI,CX ; Curbuf = HEAD +TNEWHEAD: + MOV BL,ES:[DI.BUFPRI] + CMP BL,[SI.BUFPRI] + JGE BUFLOOP +NEWHEAD: ; If Buf.pri < HEAD.pri + MOV WORD PTR ES:[DI.NEXTBUF],SI + MOV WORD PTR ES:[DI.NEXTBUF+2],DS ; Buf.nextbuf = HEAD + MOV WORD PTR [BUFFHEAD],DI + MOV WORD PTR [BUFFHEAD+2],ES ; HEAD = Buf + INC AL ; Inserted = TRUE + OR AH,AH + JNZ NRET ; If Removed == TRUE +BUFLOOP: + PUSH DS + PUSH SI + LDS SI,[SI.NEXTBUF] + CALL POINTCOMP + POP SI + POP DS + JNZ TESTINS + MOV WORD PTR [SI.NEXTBUF],CX ; If Curbuf.nextbuf == buf + MOV WORD PTR [SI.NEXTBUF+2],BP ; Curbuf.nextbuf = Pointsave + INC AH ; Removed = TRUE + OR AL,AL + JNZ SHUFFLE ; If Inserted == TRUE +TESTINS: + OR AL,AL + JNZ LOOKBUF + PUSH CX ; If NOT Inserted + MOV CL,ES:[DI.BUFPRI] + CMP CL,[SI.BUFPRI] + POP CX + JGE LOOKBUF + PUSH DS ; If Buf.pri < Curbuf.pri + MOV DS,DX + MOV WORD PTR [BX.NEXTBUF],DI + MOV WORD PTR [BX.NEXTBUF+2],ES ; Lastbuf.nextbuf = Buf + POP DS + MOV WORD PTR ES:[DI.NEXTBUF],SI + MOV WORD PTR ES:[DI.NEXTBUF+2],DS ; Buf.nextbuf = Curbuf + INC AL ; Inserted = TRUE + OR AH,AH + JNZ SHUFFLE ; If Removed == TRUE +LOOKBUF: + MOV BX,SI + MOV DX,DS ; Lastbuf = Curbuf + CMP WORD PTR [SI.NEXTBUF],-1 + JZ ISLAST + LDS SI,[SI.NEXTBUF] ; Curbuf = Curbuf.nextbuf + JMP SHORT BUFLOOP +ISLAST: ; If Curbuf is LAST + MOV WORD PTR [SI.NEXTBUF],DI + MOV WORD PTR [SI.NEXTBUF+2],ES ; Curbuf.nextbuf = Buf + MOV WORD PTR ES:[DI.NEXTBUF],-1 + MOV WORD PTR ES:[DI.NEXTBUF+2],-1 ; Buf is LAST +NRET: + invoke restore_world + return + +SHUFFLE: + LDS DI,[BUFFHEAD] +DECLOOP: + CMP [DI.BUFPRI],FREEPRI + JZ NODEC + DEC [DI.BUFPRI] +NODEC: + LDS DI,[DI.NEXTBUF] + CMP DI,-1 + JNZ DECLOOP + JMP SHORT NRET + ENDIF + ENDIF + + invoke save_world + LES CX,[DI.NEXTBUF] + CMP CX,-1 ; Buf is LAST? + JZ NRET ; Buffer already last + MOV BP,ES ; Pointsave = Buf.nextbuf + PUSH DS + POP ES ; Buf is ES:DI + LDS SI,[BUFFHEAD] ; Curbuf = HEAD + CALL POINTCOMP ; Buf == HEAD? + JNZ BUFLOOP + MOV WORD PTR [BUFFHEAD],CX + MOV WORD PTR [BUFFHEAD+2],BP ; HEAD = Pointsave + JMP SHORT LOOKEND + +BUFLOOP: + PUSH DS + PUSH SI + LDS SI,[SI.NEXTBUF] + CALL POINTCOMP + JZ GOTTHEBUF + POP AX + POP AX + JMP SHORT BUFLOOP + +GOTTHEBUF: + POP SI + POP DS + MOV WORD PTR [SI.NEXTBUF],CX ; If Curbuf.nextbuf == buf + MOV WORD PTR [SI.NEXTBUF+2],BP ; Curbuf.nextbuf = Pointsave +LOOKEND: + PUSH DS + PUSH SI + LDS SI,[SI.NEXTBUF] + CMP SI,-1 + JZ GOTHEEND + POP AX + POP AX + JMP SHORT LOOKEND + +GOTHEEND: + POP SI + POP DS + MOV WORD PTR [SI.NEXTBUF],DI + MOV WORD PTR [SI.NEXTBUF+2],ES ; Curbuf.nextbuf = Buf + MOV WORD PTR ES:[DI.NEXTBUF],-1 + MOV WORD PTR ES:[DI.NEXTBUF+2],-1 ; Buf is LAST +NRET: + invoke restore_world + return + +PLACEBUF ENDP + + procedure PLACEHEAD,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; SAME AS PLACEBUF except places buffer at head + + invoke save_world + PUSH DS + POP ES + LDS SI,[BUFFHEAD] + MOV WORD PTR [BUFFHEAD],DI + MOV WORD PTR [BUFFHEAD+2],ES + MOV WORD PTR ES:[DI.NEXTBUF],SI + MOV WORD PTR ES:[DI.NEXTBUF+2],DS +LOOKEND2: + PUSH DS + PUSH SI + LDS SI,[SI.NEXTBUF] + CALL POINTCOMP + JZ GOTHEEND2 + POP AX + POP AX + JMP SHORT LOOKEND2 + +GOTHEEND2: + POP SI + POP DS + MOV WORD PTR [SI.NEXTBUF],-1 + MOV WORD PTR [SI.NEXTBUF+2],-1 ; Buf is LAST + JMP SHORT NRET + +PLACEHEAD ENDP + +SUBTTL POINTCOMP -- 20 BIT POINTER COMPARE +PAGE + procedure PointComp,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Compare DS:SI to ES:DI (or DS:DI to ES:SI) for equality +; DO NOT USE FOR < or > +; No Registers altered + + CMP SI,DI + retnz + PUSH CX + PUSH DX + MOV CX,DS + MOV DX,ES + CMP CX,DX + POP DX + POP CX + return +PointComp ENDP + +SUBTTL GETBUFFR -- GET A SECTOR INTO A BUFFER +PAGE + procedure GETBUFFR,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Input: +; AH = Priority buffer is to have +; AL = 0 means sector must be pre-read +; ELSE no pre-read +; DX = Desired physical sector number +; ES:BP = Pointer to drive parameters +; Function: +; Get the specified sector into one of the I/O buffers +; And shuffle the queue +; Output: +; [CURBUF] Points to the Buffer for the sector +; DX,ES:BP unchanged, all other registers destroyed + + XOR SI,SI + entry GETBUFFRB + MOV [PREREAD],AX + MOV AL,ES:[BP.dpb_drive] + LDS DI,[LASTBUFFER] +ASSUME DS:NOTHING + CMP DI,-1 ; Recency pointer valid? + JZ SKBUF ; No + CMP DX,[DI.BUFSECNO] + JNZ SKBUF ; Wrong sector + CMP AL,[DI.BUFDRV] + JNZ SKBUF ; Wrong Drive + JMP SHORT JUSTBUF ; Just asked for same buffer +SKBUF: + LDS DI,[BUFFHEAD] +NXTBFF: + CMP DX,[DI.BUFSECNO] + JNZ BUMP + CMP AL,[DI.BUFDRV] + JNZ BUMP + JMP SHORT SETINF +BUMP: + LDS DI,[DI.NEXTBUF] + CMP DI,-1 + JNZ NXTBFF + LDS DI,[BUFFHEAD] + PUSH SI + PUSH DX + PUSH BP + PUSH ES + CALL BUFWRITE ; Write out the dirty buffer + POP ES + POP BP + POP DX + POP SI +RDSEC: ; Read in the new sector + TEST BYTE PTR [PREREAD],-1 + JNZ SETBUF + LEA BX,[DI.BufInSiz] ; Point at buffer + MOV CX,1 + PUSH SI + PUSH DI + PUSH DX + OR SI,SI + JZ NORMSEC + invoke FATSECRD + JMP SHORT GOTTHESEC ; Buffer is marked free if read barfs +NORMSEC: + invoke DREAD ; Buffer is marked free if read barfs +GOTTHESEC: + POP DX + POP DI + POP SI +SETBUF: + MOV [DI.BUFSECNO],DX + MOV WORD PTR [DI.BUFDRVDP],BP + MOV WORD PTR [DI.BUFDRVDP+2],ES + XOR AH,AH + MOV AL,ES:[BP.dpb_drive] + MOV WORD PTR [DI.BUFDRV],AX +SETINF: + MOV AX,1 ; Default to not a FAT sector + OR SI,SI + JZ SETSTUFFOK + MOV AL,ES:[BP.dpb_FAT_count] + MOV AH,ES:[BP.dpb_FAT_size] +SETSTUFFOK: + MOV WORD PTR [DI.BUFWRTCNT],AX + CALL PLACEBUF +JUSTBUF: + MOV WORD PTR [CURBUF+2],DS + MOV WORD PTR [LASTBUFFER+2],DS + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV WORD PTR [CURBUF],DI + MOV WORD PTR [LASTBUFFER],DI + return +GETBUFFR ENDP + + +SUBTTL FLUSHBUF -- WRITE OUT DIRTY BUFFERS +PAGE + procedure FlushBuf,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Input: +; DS = DOSGROUP +; AL = Physical unit number +; = -1 for all units +; Function: +; Write out all dirty buffers for unit, and flag them as clean +; DS Preserved, all others destroyed (ES too) + + LDS DI,[BUFFHEAD] +ASSUME DS:NOTHING + MOV AH,-1 +NXTBUFF: + CMP [DI.BUFDRV],AH + JZ SKIPBFF ; Skip free buffers + CMP AH,AL + JZ DOBUFFER ; Do all dirty buffers + CMP AL,[DI.BUFDRV] + JNZ SKIPBFF ; Buffer not for this unit +DOBUFFER: + CMP BYTE PTR [DI.BUFDIRTY],0 + JZ SKIPBFF ; Buffer not dirty + PUSH AX + PUSH WORD PTR [DI.BUFDRV] + CALL BUFWRITE + POP AX + XOR AH,AH ; Buffer is clean + CMP AL,BYTE PTR [WPERR] + JNZ NOZAP + MOV AL,0FFH ; Invalidate buffer, it is inconsistent +NOZAP: + MOV WORD PTR [DI.BUFDRV],AX + POP AX ; Search info +SKIPBFF: + LDS DI,[DI.NEXTBUF] + CMP DI,-1 + JNZ NXTBUFF + PUSH SS + POP DS + return +FlushBuf ENDP + + +SUBTTL BUFWRITE -- WRITE OUT A BUFFER IF DIRTY +PAGE + procedure BufWrite,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Input: +; DS:DI Points to the buffer +; Function: +; Write out all the buffer if dirty. +; Output: +; Buffer marked free +; DS:DI Preserved, ALL others destroyed (ES too) + + MOV AX,00FFH + XCHG AX,WORD PTR [DI.BUFDRV] ; Free, in case write barfs + CMP AL,0FFH + retz ; Buffer is free. + OR AH,AH + retz ; Buffer is clean. + CMP AL,BYTE PTR [WPERR] + retz ; If in WP error zap buffer + LES BP,[DI.BUFDRVDP] + LEA BX,[DI.BufInSiz] ; Point at buffer + MOV DX,[DI.BUFSECNO] + MOV CX,WORD PTR [DI.BUFWRTCNT] + MOV AL,CH ; [DI.BUFWRTINC] + XOR CH,CH + MOV AH,CH + PUSH DI +WRTAGAIN: + PUSH CX + PUSH AX + MOV CX,1 + PUSH BX + PUSH DX + invoke DWRITE ; Write out the dirty buffer + POP DX + POP BX + POP AX + POP CX + ADD DX,AX + LOOP WRTAGAIN + POP DI + return +BufWrite ENDP + +do_ext + +CODE ENDS + END diff --git a/CHKDSK.ASM b/CHKDSK.ASM new file mode 100644 index 0000000..c305a1d --- /dev/null +++ b/CHKDSK.ASM @@ -0,0 +1,901 @@ +TITLE CHKDSK - MS-DOS Disk consistancy checker + +; CHKDSK Version 2.30 +; Verifies and repairs MS-DOS disk directory. + + +; To build CHKDSK you need three modules: +; CHKDSK CHKPROC CHKMES +; They should be linked the that order as well. + + +; REVISION HISTORY + +;REV 1.1 +; 05/21/82 Added rev number + +;REV 1.5 +; Mod by NANCYP to report on extents +; Mod by AARONR to report volume ID + +;REV 2.0 +; Total rewrite for directories + +;REV 2.1 +; Added ^C and INT 24H handlers + +;REV 2.2 +; INTERNATIONAL support + +;REV 2.3 +; Split into two modules to allow assembly on a PC +; CHKDSK and CHKPROC + +FALSE EQU 0 +TRUE EQU NOT FALSE + +DRVCHAR EQU ":" + +;The following defines the ranges of DOS version numbers for which this CHKDSK +; is good + +DOSVER_LOW EQU 0136H ;1.54 in hex +DOSVER_HIGH EQU 020BH ;2.11 in hex + + + INCLUDE DOSSYM.ASM + +FCB EQU 5CH + +;Drive parameter block from DOS header + +SUBTTL Segments used in load order + +CODE SEGMENT PUBLIC +CODE ENDS + +CONST SEGMENT PUBLIC BYTE +CONST ENDS + +DATA SEGMENT PUBLIC WORD +DATA ENDS + +DG GROUP CODE,CONST,DATA + +SUBTTL Initialized Data +PAGE +CONST SEGMENT PUBLIC BYTE + + PUBLIC HECODE,SWITCHAR,NOISY,DOFIX,CONBUF,ORPHCNT,ORPHSIZ,DOFIX + PUBLIC HIDCNT,HIDSIZ,DIRCNT,DIRSIZ,FILCNT,FILSIZ,BADSIZ,LCLUS + PUBLIC DOTENT,HAVFIX,SECONDPASS,NUL,ALLFILE,PARSTR,ERRSUB,LCLUS + PUBLIC DIRTYFAT,BADSIZ,DDOTENT,CROSSCNT,ORPHFCB,ORPHEXT,ALLDRV + PUBLIC FRAGMENT,USERDIR,DIRBUF,USERDIR,FIXMFLG,DOTMES,DIRCHAR + + EXTRN IDMES1:BYTE,IDPOST:BYTE,VNAME:BYTE,MONTAB:BYTE + EXTRN TCHAR:BYTE,BADREAD_PRE:BYTE,BADREAD_POST:BYTE + EXTRN CRLF:BYTE,BADVER:BYTE,BADSUBDIR:BYTE,CENTRY:BYTE + EXTRN BADDRV:BYTE,BADCD:BYTE,BADRDMES:BYTE,OPNERR:BYTE + EXTRN CONTAINS:BYTE,EXTENTS:BYTE,NOEXTENTS:BYTE + EXTRN BADDRVM:BYTE,BADDRVM2:BYTE,BADIDBYT:BYTE + + +DIRBUF LABEL BYTE ;Entry buffer for searches +VOLID DB -1,0,0,0,0,0,8 ;Volume ID FCB +VOLNAM DB 0,"???????????" + DB 25 DUP(0) + +ALLFILE DB -1,0,0,0,0,0,1EH ;Extended FCB +ALLDRV DB 0,"???????????" + DB 25 DUP (?) + +ORPHFCB DB 0,"FILE0000" +ORPHEXT DB "CHK" + DB 25 DUP (?) + + +;Non-message data + +SWITCHAR DB "-" +ROOTSTR LABEL BYTE +DIRCHAR DB "/" +NUL DB 0 +PARSTR DB "..",0 +DOTMES DB ".",0 +DOTENT DB ". " +DDOTENT DB ".. " +HECODE DB ? +FIXMFLG DB 0 ;Flag for printing fixmes +ERRSUB DW 0 ;Flag for bad subdir error +FRAGMENT DB 0 ;Flag for extent processing +DIRTYFAT DB 0 ;Dirty flag for FAT +DIRCNT DW 0 ;# directories +DIRSIZ DW 0 ;# alloc units in directories +FILCNT DW 0 ;# reg files +FILSIZ DW 0 ;# alloc units in reg files +HIDCNT DW 0 ;# hidden files +HIDSIZ DW 0 ;# alloc units in hidden files +BADSIZ DW 0 ;# alloc units in bad sectors +ORPHCNT DW 0 ;# orphan files made +ORPHSIZ DW 0 ;# alloc units in orphan files +LCLUS DW 0 ;# alloc units in lost clusters +DISPFLG DB 0 ;used by number routines +CROSSCNT DW 0 ;# crosslinked files (first pass) +SECONDPASS DB 0 ;Pass flag +HAVFIX DB 0 ;non zero if any fixes +DOFIX DB 0 ;flag for F switch +NOISY DB 0 ;flag for V switch +USERDIR DB "/",0 ;Users current dir for drive + DB (DIRSTRLEN-1) DUP (?) +CONBUF DB 15,0 ;Input buffer + DB 15 DUP (?) + +CONST ENDS + +SUBTTL Un-initialized Data +PAGE +DATA SEGMENT PUBLIC WORD + + PUBLIC ZEROTRUNC,NAMBUF,MCLUS,THISDPB,STACKLIM,ERRCNT + PUBLIC SRFCBPT,ISCROSS,CSIZE,DSIZE,SSIZE,FAT,FATMAP + PUBLIC HARDCH,CONTCH,USERDEV,SECBUF,DOTSNOGOOD + +HARDCH DD ? ;Pointer to real INT 24 handler +CONTCH DD ? ;Pointer to real INT 23 handler +THISDPB DD ? ;Pointer to drive DPB +USERDEV DB ? ;Users current device +CSIZE DB ? ;Sectors per cluster +SSIZE DW ? ;bytes per sector +DSIZE DW ? ;# alloc units on disk +MCLUS DW ? ;DSIZE + 1 +NAMBUF DB 14 DUP (?) ;Buffer +DOTSNOGOOD DB ? ;. or .. error flag +ZEROTRUNC DB ? ;Trimming flag +ISCROSS DB ? ;Crosslink flag +OLDCLUS DW ? +SRFCBPT DW ? +FATMAP DW OFFSET DG:FAT ;Offset of FATMAP table +SECBUF DW ? ;Offset of sector buffer +ERRCNT DB ? ;Used by FATread and write +STACKLIM DW ? ;Stack growth limit + +INTERNATVARS internat_block <> + DB (internat_block_max - ($ - INTERNATVARS)) DUP (?) + +FAT LABEL WORD +DATA ENDS + + +SUBTTL Start of CHKDSK + +CODE SEGMENT PUBLIC +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + + PUBLIC SUBERRP,DOTCOMBMES,FIGREC,FCB_TO_ASCZ,PRTCHR,EPRINT + PUBLIC PRINT,DOCRLF,DISP16BITS,DISP32BITS,DISPCLUS,CHECKFILES + + EXTRN RDSKERR:NEAR,SETSWITCH:NEAR,PROMPTYN:NEAR,REPORT:NEAR + EXTRN PRINTCURRDIRERR:NEAR,PRINTTHISEL2:NEAR,CHECKERR:NEAR + EXTRN INT_23:NEAR,INT_24:NEAR,FINDCHAIN:NEAR,DONE:NEAR,AMDONE:NEAR + EXTRN FATAL:NEAR,DIRPROC:NEAR,CHKMAP:NEAR,CHKCROSS:NEAR,UNPACK:NEAR + + ORG 100H + +CHKDSK: + JMP SHORT CHSTRT + +HEADER DB "Ver 2.30" + +CHSTRT: + +;Code to print header. +; PUSH AX +; MOV DX,OFFSET DG:HEADER +; CALL PRINT +; POP AX + + PUSH AX ;Save DRIVE validity info + MOV AH,GET_VERSION + INT 21H + XCHG AH,AL ;Turn it around to AH.AL + CMP AX,DOSVER_LOW + JB GOTBADDOS + CMP AX,DOSVER_HIGH + JBE OKDOS +GOTBADDOS: + MOV DX,OFFSET DG:BADVER + JMP CERROR + +OKDOS: + POP AX ;Get back drive info + MOV BX,0FFF0H + MOV DX,SP + CMP DX,BX + JAE STACKOK ;Lots of stack + MOV DX,DS:[2] ;High break + MOV CX,CS + SUB DX,CX + CMP DX,0FFFH + JAE SETSTACK ;Lots to grab + MOV CX,4 ;Suck up more stack (blast command) + SHL DX,CL + MOV BX,DX +SETSTACK: + CLI + MOV SP,BX + STI +STACKOK: + PUSH AX + MOV AH,DISK_RESET ;Flush everything, and invalidate + INT 21H + POP AX + CMP AL,0FFH ;Illegal drive specifier? + JNZ FILECHK ;No -- check for filename + +DRVERR: + MOV DX,OFFSET DG:BADDRV +CERROR: + PUSH CS ;Make sure DS is OK + POP DS + CALL PRINT ;Print error message + INT 20H + +CERROR2: + PUSH DX + CALL DONE ;Reset users disk + POP DX + JMP SHORT CERROR + +FILECHK: + MOV AX,(CHAR_OPER SHL 8) + INT 21H + MOV [SWITCHAR],DL + CMP DL,"/" + JNZ SLASHOK + MOV [DIRCHAR],"\" + MOV [USERDIR],"\" +SLASHOK: + CMP DS:(BYTE PTR FCB+1)," " ;Filename specified? + JZ DRVCHK ;No -- get the correct drive + MOV AL,[SWITCHAR] + CMP DS:(BYTE PTR FCB+1),AL ;Filename specified? + JZ DRVCHK ;No -- get the correct drive + MOV BYTE PTR [FRAGMENT],1 ;Set flag to perform fragment + ;check on specified files +DRVCHK: + CALL SETSWITCH ;Look for switches + MOV AH,GET_DEFAULT_DRIVE ;Get current drive + INT 21H + MOV [USERDEV],AL ;Save for later + MOV AH,AL + INC AH ;A = 1 + MOV BH,DS:(BYTE PTR FCB) ;See if drive specified + OR BH,BH + JZ SETDSK + MOV AL,BH + MOV AH,AL + DEC AL ;A = 0 +SETDSK: + MOV [ALLDRV],AH ;Target drive + MOV [VOLNAM],AH ;A = 1 + MOV [ORPHFCB],AH ;A = 1 + ADD [BADDRVM],AL ;A = 0 + ADD [BADDRVM2],AL ;A = 0 + MOV DL,AH ;A = 1 + MOV AH,GET_DPB ;Get the DPB + INT 21H +ASSUME DS:NOTHING + CMP AL,-1 + JNZ DRVISOK ;Bad drive (should always be ok) + MOV DX,OFFSET DG:BADDRV +CERROR2J: JMP CERROR2 + +DRVISOK: + DEC DL ;A = 0 + MOV AH,SET_DEFAULT_DRIVE ;Set Target + INT 21H + CMP [BX.dpb_current_dir],0 + JZ CURRISROOT ;Save users current dir for target + MOV SI,BX + ADD SI,dpb_dir_text + MOV DI,OFFSET DG:USERDIR + 1 +SETDIRLP: + LODSB + STOSB + OR AL,AL + JZ CURRISROOT + JMP SHORT SETDIRLP +CURRISROOT: + MOV WORD PTR [THISDPB+2],DS + PUSH CS + POP DS +ASSUME DS:DG + MOV WORD PTR [THISDPB],BX + MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 23H + INT 21H + MOV WORD PTR [CONTCH],BX + MOV WORD PTR [CONTCH+2],ES + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H + MOV DX,OFFSET DG:INT_23 + INT 21H + MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 24H + INT 21H + MOV WORD PTR [HARDCH],BX + MOV WORD PTR [HARDCH+2],ES + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H + MOV DX,OFFSET DG:INT_24 + INT 21H + PUSH CS + POP ES + MOV DX,OFFSET DG:ROOTSTR + MOV AH,CHDIR ;Start at root + INT 21H + MOV DX,OFFSET DG:BADCD + JC CERROR2J ;Couldn't get there + MOV DX,OFFSET DG:FAT ;Scratch space + MOV AH,SET_DMA + INT 21H + MOV DX,OFFSET DG:VOLID ;Look for VOL ID + MOV AH,DIR_SEARCH_FIRST + INT 21H + CMP AL,-1 + JZ NOTVOLID + CALL PRINTID ;Have a VOL ID +NOTVOLID: + LDS BX,[THISDPB] +ASSUME DS:NOTHING + MOV AX,[BX.dpb_sector_size] + MOV [SSIZE],AX ;Sector size in bytes + MOV AL,[BX.dpb_cluster_mask] + INC AL + MOV [CSIZE],AL ;Sectros per cluster + MOV AX,[BX.dpb_max_cluster] + MOV [MCLUS],AX ;Bound for FAT searching + DEC AX + MOV [DSIZE],AX ;Total data clusters on disk + MOV AL,[BX.dpb_FAT_size] ;Sectors for one fat + XOR AH,AH + MOV CX,AX + MUL [SSIZE] ;Bytes for FAT + ADD [FATMAP],AX ;Allocate FAT space + MOV AX,[FATMAP] + ADD AX,[MCLUS] + ADD AX,2 ;Insurance + MOV [SECBUF],AX ;Allocate FATMAP space + ADD AX,[SSIZE] + ADD AX,20 ;Insurance + MOV [STACKLIM],AX ;Limit on recursion + MOV DI,CX + MOV CL,[BX.dpb_FAT_count] ;Number of FATs + MOV DX,[BX.dpb_first_FAT] ;First sector of FAT + PUSH CS + POP DS +ASSUME DS:DG + MOV BX,OFFSET DG:FAT + MOV AL,[ALLDRV] + DEC AL + MOV AH,'1' +RDLOOP: + XCHG CX,DI + PUSH DX + PUSH CX + PUSH DI + PUSH AX + INT 25H ;Read in the FAT + MOV [HECODE],AL + POP AX ;Flags + JNC RDOK + MOV DX,OFFSET DG:BADREAD_PRE ;Barfed + CALL PRINT + POP AX + PUSH AX + MOV DL,AH + CALL PRTCHR + MOV DX,OFFSET DG:BADREAD_POST + CALL PRINT + POP AX + POP CX + POP DI + POP DX + INC AH + ADD DX,DI + LOOP RDLOOP ;Try next FAT + CALL RDSKERR + JNZ NORETRY1 + JMP NOTVOLID +NORETRY1: + MOV BX,OFFSET DG:BADRDMES + JMP FATAL ;Couldn't read any FAT, BARF + +RDOK: + POP AX ;Clean up + POP AX + POP AX + POP AX + MOV SI,OFFSET DG:FAT + LODSB ;Check FAT ID byte + CMP AL,0F8H + JAE IDOK + MOV DX,OFFSET DG:BADIDBYT ;FAT ID bad + CALL PROMPTYN ;Ask user + JZ IDOK + JMP ALLDONE ;User said stop +IDOK: + MOV DI,[FATMAP] + MOV CX,[MCLUS] + INC CX + XOR AL,AL + REP STOSB ;Initialize FATMAP to all free + MOV DX,OFFSET DG:DIRBUF ;FOR ALL SEARCHING + MOV AH,SET_DMA + INT 21H + XOR AX,AX + PUSH AX ;I am root + PUSH AX ;Parent is root + CALL DIRPROC + CALL CHKMAP ;Look for badsectors, orphans + CALL CHKCROSS ;Check for second pass + CALL DOCRLF + CALL REPORT + +ALLDONE: + CALL AMDONE + INT 20H ;Fini + + +ASSUME DS:DG + +SUBTTL Check for extents in specified files +PAGE +CHECKFILES: +;Search the directory for the files specified on the command line +;and report the number of fragmented allocation units found in +;each one. + CALL DOCRLF + MOV AH,SET_DMA + MOV DX,[FATMAP] ;Use the first free space available + MOV BP,DX + ADD BP,27 ;cluster in the directory entry + INT 21H + MOV AH,DIR_SEARCH_FIRST ;Look for the first file +FRAGCHK: + MOV DX,FCB + INT 21H + OR AL,AL ;Did we find it? + JNZ MSGCHK ;No -- we're done + XOR AX,AX ;Initialize the fragment counter + MOV SI,[BP] ;Get the first cluster + CALL UNPACK + CMP DI,0FF8H ;End-of-file? + JAE NXTCHK ;Yes -- go report the results + INC SI + CMP SI,DI + JZ EACHCLUS + INC AX +EACHCLUS: + MOV [OLDCLUS],DI ;Save the last cluster found + MOV SI,DI ;Get the next cluster + CALL UNPACK + INC [OLDCLUS] ;Bump the old cluster + CMP DI,[OLDCLUS] ;Are they the same? + JNZ LASTCLUS ;No -- check for end-of-file + JMP SHORT EACHCLUS ;Continue processing +LASTCLUS: + CMP DI,0FF8H ;End-of-file? + JAE NXTCHK ;Yes -- go report the results + INC AX ;No -- found a fragement + JMP SHORT EACHCLUS ;Continue processing + +NXTCHK: + OR AX,AX + JZ GETNXT + MOV [FRAGMENT],2 ;Signal that we output at least one file + PUSH AX ;Save count of fragments + MOV SI,[FATMAP] + INC SI + CALL PRINTTHISEL2 + CALL DOCRLF + MOV DX,OFFSET DG:CONTAINS ;Print message + CALL PRINT + POP SI ;Number of fragments found + INC SI ;Number non-contig blocks + XOR DI,DI + MOV BX,OFFSET DG:EXTENTS + PUSH BP + CALL DISP16BITS + POP BP +GETNXT: + MOV AH,DIR_SEARCH_NEXT ;Look for the next file + JMP FRAGCHK + +MSGCHK: + CMP AH,DIR_SEARCH_FIRST + JNZ FILSPOK + MOV SI,FCB + 1 ;File not found error + CALL PRINTTHISEL2 + CALL DOCRLF + MOV DX,OFFSET DG:OPNERR + CALL PRINT ;Bad file spec + RET +FILSPOK: + CMP BYTE PTR [FRAGMENT],2 + JZ CDONE + MOV DX,OFFSET DG:NOEXTENTS + CALL PRINT +CDONE: + RET + + +FIGREC: +;Convert cluster number in BX to sector # AH of cluster in DX + LDS DI,[THISDPB] +ASSUME DS:NOTHING + MOV CL,[DI.dpb_cluster_shift] + MOV DX,BX + DEC DX + DEC DX + SHL DX,CL + OR DL,AH + ADD DX,[DI.dpb_first_sector] + PUSH CS + POP DS +ASSUME DS:DG + RET + + +SUBTTL PRINTID - Print Volume ID info +PAGE +PRINTID: +ASSUME DS:DG + MOV DX,OFFSET DG:INTERNATVARS + MOV AX,INTERNATIONAL SHL 8 + INT 21H + MOV [DISPFLG],1 ;Don't sub spaces for leading zeros + MOV SI,OFFSET DG:FAT + 8 + MOV DI,OFFSET DG:VNAME + MOV CX,11 + REP MOVSB + MOV DX,OFFSET DG:IDMES1 + CALL PRINT ;Print ID message + ADD SI,13 + LODSW ;Get date + PUSH SI + MOV DX,AX + MOV AX,[INTERNATVARS.Date_tim_format] + OR AX,AX + JZ USPDAT + DEC AX + JZ EUPDAT + CALL P_YR + CALL P_DSEP + CALL P_MON + CALL P_DSEP + MOV CX,1000H ;Do not supress leading zeroes + CALL P_DAY + JMP P_TIME + +USPDAT: + CALL P_MONTH_NAM + MOV CX,1110H ;Supress at most 1 leading 0 + CALL P_DAY + PUSH DX + MOV DL,',' + CALL PRTCHR + MOV DL,' ' + CALL PRTCHR + POP DX +PYA: + CALL P_YR + JMP P_TIME + +EUPDAT: + MOV CX,1110H ;Supress at most 1 leading 0 + CALL P_DAY + PUSH DX + MOV DL,' ' + CALL PRTCHR + POP DX + CALL P_MONTH_NAM + JMP PYA + +P_DSEP: + PUSH DX + MOV DL,[INTERNATVARS.Date_sep] + CALL PRTCHR + POP DX + RET + +P_MONTH_NAM: + MOV AX,DX + PUSH DX + MOV CL,5 + SHR AX,CL + AND AX,0FH ;Month in AX + DEC AX ;Make 0 indexed + MOV CX,AX + SHL AX,1 + ADD AX,CX ;Mult by 3 chars/mo + MOV SI,OFFSET DG:MONTAB + ADD SI,AX + LODSB + MOV DL,AL + CALL PRTCHR + LODSB + MOV DL,AL + CALL PRTCHR + LODSB + MOV DL,AL + CALL PRTCHR + MOV DL,' ' + CALL PRTCHR + POP DX + RET + +P_MON: + MOV SI,DX + PUSH DX + MOV CL,5 + SHR SI,CL + AND SI,0FH ;Month in SI + CALL CONVERT + MOV DL,AL + MOV CX,1000H ;Do not supress leading 0 + CALL OUTBYTE ;Print month + POP DX + RET + +P_DAY: + MOV SI,DX + PUSH DX + PUSH CX + AND SI,01FH ;SI has day + CALL CONVERT + POP CX + MOV DL,AL + CALL OUTBYTE ;Print day + POP DX + RET + +P_YR: + MOV SI,DX + PUSH DX + MOV CL,9 + SHR SI,CL + AND SI,07FH ;SI has raw year + ADD SI,1980 ;Real year + CALL CONVERT + MOV CX,1000H ;Do not supress leading zeros + CALL OUTWORD ;Print year + POP DX + RET + +P_TIME: + MOV DL,' ' + CALL PRTCHR + POP SI + ADD SI,-4 + LODSW ;Get time + MOV DI,AX + MOV SI,DI + MOV CL,11 + SHR SI,CL + AND SI,01FH ;SI has hour + CMP [INTERNATVARS.Time_24],0 + JNZ ISOK2 ;24 hour time? + CMP SI,12 + JB ISOK ;Is AM + MOV [TCHAR],'p' + JZ ISOK ;Is 12-1p + SUB SI,12 ;Is PM +ISOK: + OR SI,SI + JNZ ISOK2 + MOV SI,12 ;0 is 12a +ISOK2: + CALL CONVERT + MOV CX,1110H ;Supress at most 1 leading 0 + MOV DL,AL + CALL OUTBYTE ;Print hour + MOV DL,BYTE PTR [INTERNATVARS.Time_sep] + CALL PRTCHR + MOV SI,DI + MOV CL,5 + SHR SI,CL + AND SI,03FH ;SI has minute + CALL CONVERT + MOV CX,1000H ;Do not supress leading zeroes + MOV DL,AL + CALL OUTBYTE ;Print minute + MOV DL,[TCHAR] + CMP [INTERNATVARS.Time_24],0 + JNZ NOAP ;24 hour time, no a or p + CALL PRTCHR ;Print a or p +NOAP: + MOV DX,OFFSET DG:IDPOST + CALL PRINT + MOV [DISPFLG],0 + RET + +CONVERT: + MOV CX,16 + XOR AX,AX +CNVLOOP: + SHL SI,1 + CALL CONVWRD + CLC + LOOP CNVLOOP + RET + +SUBTTL Misc Routines - Mostly I/O +PAGE +CONVWRD: + ADC AL,AL + DAA + XCHG AL,AH + ADC AL,AL + DAA + XCHG AL,AH +RET1: RET + +UNSCALE: + SHR CX,1 + JC RET1 + SHL SI,1 + RCL DI,1 + JMP SHORT UNSCALE + +DISP16BITS: + MOV BYTE PTR DISPFLG,1 + JMP SHORT DISP32BITS + +DISPCLUS: + MUL [SSIZE] + MOV CL,[CSIZE] + XOR CH,CH + MOV SI,AX + MOV DI,DX + CALL UNSCALE + +DISP32BITS: + PUSH BP + PUSH BX + XOR AX,AX + MOV BX,AX + MOV BP,AX + MOV CX,32 +CONVLP: + SHL SI,1 + RCL DI,1 + XCHG AX,BP + CALL CONVWRD + XCHG AX,BP + XCHG AX,BX + CALL CONVWRD + XCHG AX,BX + ADC AL,0 + LOOP CONVLP + ; Conversion complete + MOV CX,1310H ;Print 3-digit number with 2 leading blanks + CMP BYTE PTR DISPFLG,0 + JNZ FOURDIG + MOV CX,1810H ;Print 8-digit number with 2 leading blanks + XCHG DX,AX + CALL DIGIT + XCHG AX,BX + CALL OUTWORD +FOURDIG: + MOV AX,BP + CALL OUTWORD + MOV BYTE PTR DISPFLG,0 + POP DX + CALL PRINT + POP BP + RET + +OUTWORD: + PUSH AX + MOV DL,AH + CALL OUTBYTE + POP DX +OUTBYTE: + MOV DH,DL + SHR DL,1 + SHR DL,1 + SHR DL,1 + SHR DL,1 + CALL DIGIT + MOV DL,DH +DIGIT: + AND DL,0FH + JZ BLANKZER + MOV CL,0 +BLANKZER: + DEC CH + AND CL,CH + OR DL,30H + SUB DL,CL + CMP BYTE PTR DISPFLG,0 + JZ PRTCHR + CMP DL,30H + JL RET2 +PRTCHR: + MOV AH,STD_CON_OUTPUT + INT 21H +RET2: RET + +PRINTCNT: + LODSB + MOV DL,AL + INT 21H + LOOP PRINTCNT + RET + +EPRINT: + CALL CHECKERR + JNZ RET$1 + JMP SHORT PRINT + +DOCRLF: + MOV DX,OFFSET DG:CRLF +PRINT: + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +RET$1: RET + +DOTCOMBMES: + CMP [NOISY],0 + JZ SUBERRP + PUSH DX + CALL PRINTCURRDIRERR + MOV DX,OFFSET DG:CENTRY + CALL EPRINT + POP DX + CALL EPRINT + CALL DOCRLF + RET + +SUBERRP: + MOV AL,1 + XCHG AL,[ERRSUB] + CMP AL,0 + JNZ RET32 + MOV SI,OFFSET DG:NUL + CALL PRINTCURRDIRERR + MOV DX,OFFSET DG:BADSUBDIR + CALL EPRINT +RET32: RET + + +FCB_TO_ASCZ: ;Convert DS:SI to ASCIIZ ES:DI + MOV CX,8 +MAINNAME: + LODSB + CMP AL,' ' + JZ SKIPSPC + STOSB +SKIPSPC: + LOOP MAINNAME + LODSB + CMP AL,' ' + JZ GOTNAME + MOV AH,AL + MOV AL,'.' + STOSB + XCHG AL,AH + STOSB + MOV CL,2 +EXTNAME: + LODSB + CMP AL,' ' + JZ GOTNAME + STOSB + LOOP EXTNAME + +GOTNAME: + XOR AL,AL + STOSB + RET + +CODE ENDS + END CHKDSK + \ No newline at end of file diff --git a/CHKMES.ASM b/CHKMES.ASM new file mode 100644 index 0000000..83af5ba --- /dev/null +++ b/CHKMES.ASM @@ -0,0 +1,477 @@ +TITLE CHKDSK Messages + +FALSE EQU 0 +TRUE EQU NOT FALSE + +.xlist +.xcref + INCLUDE DOSSYM.ASM +;The DOST: prefix is a DEC TOPS/20 directory prefix. Remove it for +; assembly in MS-DOS assembly environments using MASM. The DOSSYM.ASM +; file must exist though, it is included with OEM distribution. +.cref +.list +CODE SEGMENT PUBLIC BYTE +CODE ENDS + +CONST SEGMENT PUBLIC BYTE + EXTRN HIDSIZ:WORD,HIDCNT:WORD,DIRCNT:WORD,DIRSIZ:WORD,FILCNT:WORD + EXTRN FILSIZ:WORD,ORPHCNT:WORD,ORPHSIZ:WORD,BADSIZ:WORD,LCLUS:WORD + EXTRN DOFIX:BYTE +CONST ENDS + +DATA SEGMENT PUBLIC BYTE + EXTRN DSIZE:WORD +DATA ENDS + +DG GROUP CODE,CONST,DATA + + +CODE SEGMENT PUBLIC BYTE +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + + PUBLIC RDSKERR,WDSKERR,SETSWITCH,PROMPTYN,DOINT26,CHAINREPORT,REPORT + EXTRN RDONE:NEAR,PRTCHR:NEAR,PRINT:NEAR,DOCRLF:NEAR + EXTRN DISP16BITS:NEAR,FINDCHAIN:NEAR + EXTRN DISP32BITS:NEAR,DISPCLUS:NEAR + +DOINT26: + PUSH CX + PUSH AX + PUSH DX + PUSH BX + INT 26H + MOV [HECODE],AL + POP AX ;FLAGS + POP BX + POP DX + POP AX + POP CX + JNC RET23 + MOV SI,OFFSET DG:WRITING + CALL DSKERR + JZ DOINT26 +RET23: RET + +RDSKERR: + MOV SI,OFFSET DG:READING + JMP SHORT DSKERR + +WDSKERR: + MOV SI,OFFSET DG:WRITING +DSKERR: + PUSH AX + PUSH BX + PUSH CX + PUSH DX + PUSH DI + PUSH ES + MOV AL,[HECODE] + CMP AL,12 + JBE HAVCOD + MOV AL,12 +HAVCOD: + XOR AH,AH + MOV DI,AX + SHL DI,1 + MOV DX,WORD PTR [DI+MESBAS] ; Get pointer to error message + CALL PRINT ; Print error type + MOV DX,OFFSET DG:ERRMES + CALL PRINT + MOV DX,SI + CALL PRINT + MOV DX,OFFSET DG:DRVMES + CALL PRINT +ASK: + MOV DX,OFFSET DG:REQUEST + CALL PRINT + MOV AX,(STD_CON_INPUT_FLUSH SHL 8)+STD_CON_INPUT + INT 21H ; Get response + PUSH AX + CALL DOCRLF + POP AX + OR AL,20H ; Convert to lower case + CMP AL,"i" ; Ignore? + JZ EEXITNZ + CMP AL,"r" ; Retry? + JZ EEXIT + CMP AL,"a" ; Abort? + JNZ ASK + JMP RDONE + +EEXITNZ: + OR AL,AL ; Resets zero flag +EEXIT: + POP ES + POP DI + POP DX + POP CX + POP BX + POP AX + RET + +PROMPTYN: +;Prompt message in DX +;Prompt user for Y or N answer. Zero set if Y + PUSH SI + CALL PRINT +PAGAIN: + MOV DX,OFFSET DG:YES_NO + CALL PRINT + MOV DX,OFFSET DG:CONBUF + MOV AH,STD_CON_STRING_INPUT + INT 21H + CALL DOCRLF + MOV SI,OFFSET DG:CONBUF+2 + CMP BYTE PTR [SI-1],0 + JZ PAGAIN + LODSB + OR AL,20H ;Convert to lower case + CMP AL,'y' + JZ GOTANS + CMP AL,'n' + JZ GOTNANS + JMP PAGAIN +GOTNANS: + OR AL,AL ;Reset zero +GOTANS: + POP SI + RET + +SETSWITCH: +;Look for F or V switch in command line + MOV SI,80H + LODSB + MOV DI,SI + MOV CL,AL + XOR CH,CH + JCXZ RET10 ;No parameters + MOV AL,[SWITCHAR] +MORESCAN: + REPNZ SCASB + JNZ RET10 + JCXZ BADSWITCHA + MOV AH,[DI] + INC DI + OR AH,20H ;Convert to lower case + CMP AH,'f' + JNZ CHECKV + INC [DOFIX] + JMP SHORT CHEKMORE +CHECKV: + CMP AH,'v' + JZ SETNOISY + CALL BADSWITCH + JMP SHORT CHEKMORE +SETNOISY: + INC [NOISY] +CHEKMORE: + LOOP MORESCAN + RET + +BADSWITCHA: + MOV AH,' ' ;Print a non switch +BADSWITCH: + PUSH AX + MOV DL,[SWITCHAR] + CALL PRTCHR + POP AX + PUSH AX + MOV DL,AH + CALL PRTCHR + MOV DX,OFFSET DG:BADSWMES + CALL PRINT + POP AX +RET10: RET + + +;************************************** +; Prints XXX lost clusters found in YYY chains message +; On entry SI is the XXX value and the YYY value is +; in ORPHCNT. +; NOTE: +; The DISP16BITS routine prints the number in DI:SI followed +; by the message pointed to by BX. If it is desired to +; print a message before the first number, point at the +; message with DX and call PRINT. + +CHAINREPORT: + XOR DI,DI + MOV BX,OFFSET DG:ORPHMES2 + CALL DISP16BITS + CALL FINDCHAIN + MOV BX,OFFSET DG:CHNUMMES + MOV SI,[ORPHCNT] + XOR DI,DI + CALL DISP16BITS ;Tell user how many chains found + RET + +;***************************************** +;Prints all of the reporting data +;NOTE: +; The DISPCLUS, DISP16BITS and DISP32BITS routines +; print the number in DI:SI followed +; by the message pointed to by BX. If it is desired to +; print a message before the first number, point at the +; message with DX and call PRINT. + +REPORT: + MOV AX,[DSIZE] + MOV BX,OFFSET DG:DSKSPC + CALL DISPCLUS ;Total size + CMP [HIDCNT],0 + JZ USERLIN + MOV AX,[HIDSIZ] ;Hidden files + MOV BX,OFFSET DG:INMES + CALL DISPCLUS + MOV SI,[HIDCNT] + XOR DI,DI + MOV BX,OFFSET DG:HIDMES + CALL DISP16BITS +USERLIN: + CMP [DIRCNT],0 + JZ DIRLIN + MOV AX,[DIRSIZ] + MOV BX,OFFSET DG:INMES + CALL DISPCLUS + MOV SI,[DIRCNT] + XOR DI,DI + MOV BX,OFFSET DG:DIRMES + CALL DISP16BITS +DIRLIN: + CMP [FILCNT],0 + JZ ORPHLIN + MOV AX,[FILSIZ] ;Regular files + MOV BX,OFFSET DG:INMES + CALL DISPCLUS + MOV SI,[FILCNT] + XOR DI,DI + MOV BX,OFFSET DG:FILEMES + CALL DISP16BITS +ORPHLIN: + MOV AX,[ORPHSIZ] + OR AX,AX + JZ BADLIN + MOV BX,OFFSET DG:INMES ;Orphans + CMP [DOFIX],0 + JNZ ALLSET1 + MOV BX,OFFSET DG:INMES2 ;Orphans +ALLSET1: + CALL DISPCLUS + MOV SI,[ORPHCNT] + XOR DI,DI + MOV BX,OFFSET DG:ORPHMES + CALL DISP16BITS +BADLIN: + MOV AX,[BADSIZ] + OR AX,AX + JZ AVAILIN + MOV BX,OFFSET DG:BADSPC ;Bad sectors + CALL DISPCLUS +AVAILIN: + MOV AX,[DSIZE] + SUB AX,[DIRSIZ] + SUB AX,[FILSIZ] + SUB AX,[HIDSIZ] + SUB AX,[BADSIZ] + SUB AX,[ORPHSIZ] + SUB AX,[LCLUS] + MOV BX,OFFSET DG:FRESPC + CALL DISPCLUS ;Free space is whats left + MOV AX,DS:WORD PTR [2] ;Find out about memory + MOV DX,16 + MUL DX + MOV SI,AX + MOV DI,DX + MOV BX,OFFSET DG:TOTMEM + CALL DISP32BITS + MOV AX,DS:WORD PTR [2] + MOV DX,CS + SUB AX,DX + MOV DX,16 + MUL DX + MOV SI,AX + MOV DI,DX + MOV BX,OFFSET DG:FREMEM + CALL DISP32BITS + RET + +CODE ENDS + + +CONST SEGMENT PUBLIC BYTE + + EXTRN HECODE:BYTE,SWITCHAR:BYTE,NOISY:BYTE,DOFIX:BYTE,CONBUF:BYTE + + PUBLIC CRLF2,CRLF,BADVER,BADDRV + PUBLIC BADSUBDIR,CENTRY,CLUSBAD,BADATT,BADSIZM + PUBLIC FIXMES,DIRECMES,CDDDMES + PUBLIC FREEBYMESF_PRE,FREEBYMES_PRE,FREEBYMESF_POST,FREEBYMES_POST + PUBLIC CREATMES,NDOTMES + PUBLIC BADTARG1,BADTARG2,BADCD,FATALMES,BADRDMES + PUBLIC BADDRVM,STACKMES,BADDPBDIR + PUBLIC BADDRVM2 + PUBLIC NULNZ,NULDMES,BADCLUS,NORECDOT + PUBLIC NORECDDOT,IDMES1,IDPOST,VNAME,TCHAR + PUBLIC MONTAB,BADREAD_PRE,BADREAD_POST,BADWRITE_PRE + PUBLIC BADWRITE_POST,BADCHAIN,CROSSMES_PRE,CROSSMES_POST + PUBLIC FREEMES + PUBLIC OPNERR + PUBLIC CONTAINS,EXTENTS,NOEXTENTS,INDENT + PUBLIC BADIDBYT,PTRANDIR,PTRANDIR2 + + +MESBAS DW OFFSET DG:ERR0 + DW OFFSET DG:ERR1 + DW OFFSET DG:ERR2 + DW OFFSET DG:ERR3 + DW OFFSET DG:ERR4 + DW OFFSET DG:ERR5 + DW OFFSET DG:ERR6 + DW OFFSET DG:ERR7 + DW OFFSET DG:ERR8 + DW OFFSET DG:ERR9 + DW OFFSET DG:ERR10 + DW OFFSET DG:ERR11 + DW OFFSET DG:ERR12 + +CRLF2 DB 13,10 +CRLF DB 13,10,"$" + +;Messages + +BADVER DB "Incorrect DOS version",13,10,"$" +BADDRV DB "Invalid drive specification$" + +BADSWMES DB " Invalid parameter",13,10,"$" + +BADSUBDIR DB " Invalid sub-directory entry.",13,10,"$" +CENTRY DB " Entry has a bad $" +CLUSBAD DB " link$" +BADATT DB " attribute$" +BADSIZM DB " size$" + +;"BADTARG1BADTARG2" +BADTARG1 DB "Cannot CHDIR to $" +BADTARG2 DB " tree past this point not processed.",13,10,"$" + +BADCD DB "Cannot CHDIR to root",13,10,"$" + +FATALMES DB "Processing cannot continue.",13,10,"$" +BADRDMES DB "File allocation table bad drive " +BADDRVM DB "A.",13,10,"$" +STACKMES DB "Insufficient memory.",13,10,"$" +BADDPBDIR DB "Invalid current directory.",13,10,"$" + +;INT 24 MESSAGE SHOULD AGREE WITH COMMAND + +READING DB "read$" +WRITING DB "writ$" +ERRMES DB " error $" +DRVMES DB "ing drive " +BADDRVM2 DB "A",13,10,"$" +REQUEST DB "Abort, Retry, Ignore? $" +ERR0 DB "Write protect$" +ERR1 DB "Bad unit$" +ERR2 DB "Not ready$" +ERR3 DB "Bad command$" +ERR4 DB "Data$" +ERR5 DB "Bad call format$" +ERR6 DB "Seek$" +ERR7 DB "Non-DOS disk$" +ERR8 DB "Sector not found$" +ERR9 DB "No paper$" +ERR10 DB "Write fault$" +ERR11 DB "Read fault$" +ERR12 DB "Disk$" + + +NDOTMES DB " Does not exist.",13,10,"$" +NULNZ DB " First cluster number is invalid,",13,10 + DB " entry truncated.",13,10,"$" +NULDMES DB " Directory is totally empty, no . or ..",13,10,"$" +BADCLUS DB " Allocation error, size adjusted.",13,10,"$" +NORECDOT DB " Cannot recover . entry, processing continued.",13,10,"$" +NORECDDOT DB " Cannot recover .. entry," + +;VOLUME ID + +;"IDMES1/name at VNAMEIDPOST" +IDPOST DB 13,10,"$" ;WARNING this is currently the tail of + ; the previos message!!! +IDMES1 DB "Volume " +VNAME DB 12 DUP(' ') + DB "created $" +TCHAR DB 'a' +MONTAB DB "JanFebMarAprMayJunJulAugSepOctNovDec" + + + +;"BADREAD_PRE<# of FAT>BADREAD_POST" +BADREAD_PRE DB "Disk error reading FAT $" + +;"BADWRITE_PRE<# of FAT>BADWRITE_POST" +BADWRITE_PRE DB "Disk error writing FAT $" + +BADCHAIN DB " Has invalid cluster, file truncated." + +BADREAD_POST LABEL BYTE +BADWRITE_POST LABEL BYTE + +;"CROSSMES_PRE<# of cluster>CROSSMES_POST" +CROSSMES_POST DB 13,10,"$" ;WARNING Is tail of previos messages +CROSSMES_PRE DB " Is cross linked on cluster $" + +;CHAINREPORT messages +ORPHMES2 DB " lost clusters found in $" +CHNUMMES DB " chains.",13,10,"$" + +FREEMES DB "Convert lost chains to files $" + +;REPORT messages +ORPHMES DB " recovered files",13,10,"$" +DSKSPC DB " bytes total disk space",13,10,"$" +INMES DB " bytes in $" +INMES2 DB " bytes would be in",13,10 + DB " $" +FILEMES DB " user files",13,10,"$" +BADSPC DB " bytes in bad sectors",13,10,"$" +HIDMES DB " hidden files",13,10,"$" +DIRMES DB " directories",13,10,"$" +FRESPC DB " bytes available on disk",13,10,13,10,"$" +TOTMEM DB " bytes total memory",13,10,"$" +FREMEM DB " bytes free",13,10,13,10,"$" + +;"CONTAINS<# non-contig blocks>EXTENTS" +CONTAINS DB " Contains $" +EXTENTS DB " non-contiguous blocks.",13,10,"$" + +NOEXTENTS DB "All specified file(s) are contiguous.",13,10,"$" +INDENT DB " $" + +BADIDBYT DB "Probable non-DOS disk." + DB 13,10,"Continue $" +YES_NO DB "(Y/N)? $" +PTRANDIR DB " Unrecoverable error in directory.",13,10 +PTRANDIR2 DB " Convert directory to file $" +FIXMES DB 13,10,"Errors found, F parameter not specified." + DB 13,10,"Corrections will not be written to disk.",13,10,13,10,"$" +DIRECMES DB "Directory $" +CDDDMES DB " CHDIR .. failed, trying alternate method.",13,10,"$" + + +FREEBYMESF_POST DB " bytes disk space freed.",13,10 +FREEBYMESF_PRE DB "$" +FREEBYMES_POST DB " bytes disk space",13,10 + DB " would be freed.",13,10 +FREEBYMES_PRE DB "$" + + +CREATMES DB "Insufficient room in root directory." + DB 13,10,"Erase files in root and repeat CHKDSK.",13,10,"$" +OPNERR DB " File not found.",13,10,"$" + + +CONST ENDS + END + \ No newline at end of file diff --git a/CHKPROC.ASM b/CHKPROC.ASM new file mode 100644 index 0000000..b003f83 --- /dev/null +++ b/CHKPROC.ASM @@ -0,0 +1,1408 @@ +TITLE CHKPROC - Procedures called from chkdsk + +FALSE EQU 0 +TRUE EQU NOT FALSE + +DRVCHAR EQU ":" + + INCLUDE DOSSYM.ASM + +SUBTTL Segments used in load order + +CODE SEGMENT PUBLIC +CODE ENDS + +CONST SEGMENT PUBLIC BYTE + + EXTRN CLUSBAD:BYTE,BADATT:BYTE,BADSIZM:BYTE + EXTRN DIRECMES:BYTE,CDDDMES:BYTE,NDOTMES:BYTE + EXTRN BADTARG1:BYTE,BADTARG2:BYTE,FATALMES:BYTE + EXTRN STACKMES:BYTE,BADDPBDIR:BYTE,CREATMES:BYTE + EXTRN FREEBYMES_PRE:BYTE,FREEBYMESF_PRE:BYTE + EXTRN FREEBYMES_POST:BYTE,FREEBYMESF_POST:BYTE + EXTRN NULNZ:BYTE,NULDMES:BYTE,BADCLUS:BYTE + EXTRN NORECDDOT:BYTE,NORECDOT:BYTE,DOTMES:BYTE + EXTRN BADWRITE_PRE:BYTE,BADCHAIN:BYTE,CROSSMES_PRE:BYTE + EXTRN BADWRITE_POST:BYTE,CROSSMES_POST:BYTE,INDENT:BYTE + EXTRN PTRANDIR:BYTE,PTRANDIR2:BYTE,FREEMES:BYTE,FIXMES:BYTE + + EXTRN NOISY:BYTE,DOFIX:BYTE,DIRBUF:WORD,DOTENT:BYTE,FIXMFLG:BYTE + EXTRN HAVFIX:BYTE,SECONDPASS:BYTE,LCLUS:WORD,DIRTYFAT:BYTE + EXTRN NUL:BYTE,ALLFILE:BYTE,PARSTR:BYTE,ERRSUB:WORD,USERDIR:BYTE + EXTRN HIDCNT:WORD,HIDSIZ:WORD,FILCNT:WORD,FILSIZ:WORD,DIRCHAR:BYTE + EXTRN DIRCNT:WORD,DIRSIZ:WORD,FRAGMENT:BYTE,HECODE:BYTE + EXTRN BADSIZ:WORD,ORPHSIZ:WORD,DDOTENT:BYTE,CROSSCNT:WORD + EXTRN ORPHCNT:WORD,ORPHFCB:BYTE,ORPHEXT:BYTE,ALLDRV:BYTE,DIRCHAR:BYTE + +CONST ENDS + +DATA SEGMENT PUBLIC WORD + + EXTRN THISDPB:DWORD,HARDCH:DWORD,CONTCH:DWORD,USERDEV:BYTE + EXTRN CSIZE:BYTE,SSIZE:WORD,DSIZE:WORD,MCLUS:WORD,NAMBUF:BYTE + EXTRN DOTSNOGOOD:BYTE,ZEROTRUNC:BYTE,ISCROSS:BYTE,SRFCBPT:WORD + EXTRN FATMAP:WORD,SECBUF:WORD,ERRCNT:BYTE,STACKLIM:WORD,FAT:WORD + +DATA ENDS + +DG GROUP CODE,CONST,DATA + +SUBTTL Initialized Data +PAGE + + +CODE SEGMENT PUBLIC +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + + PUBLIC INT_23,INT_24,FINDCHAIN,DONE,AMDONE,RDONE + PUBLIC FATAL,DIRPROC,CHKMAP,CHKCROSS,UNPACK + PUBLIC PRINTTHISEL2,CHECKERR,PRINTCURRDIRERR + + EXTRN EPRINT:NEAR,DOCRLF:NEAR,PRINT:NEAR + EXTRN PROMPTYN:NEAR,DOINT26:NEAR,SUBERRP:NEAR + EXTRN DOTCOMBMES:NEAR,DISP16BITS:NEAR + EXTRN CHAINREPORT:NEAR,DISPCLUS:NEAR + EXTRN PRTCHR:NEAR,WDSKERR:NEAR,CHECKFILES:NEAR + EXTRN FCB_TO_ASCZ:NEAR,FIGREC:NEAR,RDSKERR:NEAR + +CHKPROC: + +SUBTTL DIRPROC -- Recursive directory processing + +; YOU ARE ADVISED NOT TO COPY THE FOLLOWING METHOD!!! + +DOTDOTHARDWAY: + LDS DI,[THISDPB] +ASSUME DS:NOTHING + MOV [DI.dpb_current_dir],-1 ;Invalidate path + MOV SI,DI + ADD SI,dpb_dir_text + MOV CX,SI +FINDEND: + LODSB ;Scan to end of current path + OR AL,AL + JNZ FINDEND + DEC SI ;Point at the NUL +DELLOOP: ;Delete last element + CMP SI,CX + JZ SETROOT + CMP BYTE PTR [SI],"/" + JZ SETTERM + CMP BYTE PTR [SI],"\" + JZ SETTERM + DEC SI + JMP SHORT DELLOOP + +SETTERM: + MOV BYTE PTR [SI],0 +SETCURR: + PUSH CS + POP DS +ASSUME DS:DG + MOV DX,OFFSET DG:DOTMES + MOV AH,CHDIR ;Chdir to altered path + INT 21H + RET + +SETROOT: +ASSUME DS:NOTHING + MOV [DI.dpb_current_dir],0 ;Set Path to Root + JMP SHORT SETCURR ;The CHDIR will fail, but who cares + + +;Structures used by DIRPROC + +SRCHFCB STRUC + DB 44 DUP (?) +SRCHFCB ENDS +SFCBSIZ EQU SIZE SRCHFCB +THISENT EQU 17H ;Relative entry number of current entry + +DIRENT STRUC + DB 7 DUP (?) ;Ext FCB junk + DB ? ;Drive +DIRNAM DB 11 DUP (?) +DIRATT DB ? + DB 10 DUP (?) +DIRTIM DW ? +DIRDAT DW ? +DIRCLUS DW ? +DIRESIZ DD ? +DIRENT ENDS +ENTSIZ EQU SIZE DIRENT + +;Attribute bits + +RDONLY EQU 1 +HIDDN EQU 2 +SYSTM EQU 4 +VOLIDA EQU 8 +ISDIR EQU 10H + +ASSUME DS:DG + +NODOT: ;No . + PUSH AX ;Return from SRCH + CMP [NOISY],0 + JNZ DOEXTMES1 + CALL SUBERRP + JMP SHORT MESD1 +DOEXTMES1: + MOV SI,OFFSET DG:DOTMES + CALL PRINTCURRDIRERR + MOV DX,OFFSET DG:NDOTMES + CALL EPRINT +MESD1: + XOR AX,AX + PUSH BX + PUSH BP + CALL GETENT + POP BP + PUSH BP + CMP BYTE PTR [DI],0E5H ;Have place to put .? + JNZ CANTREC ;Nope + MOV SI,OFFSET DG:DOTENT + MOV CX,11 + REP MOVSB ;Name + PUSH AX + MOV AL,ISDIR + STOSB ;Attribute + ADD DI,10 + XOR AX,AX + STOSW ;Date = 0 + STOSW ;Time = 0 + MOV AX,[BP+6] + STOSW ;Alloc # + XOR AX,AX + STOSW + STOSW ;Size + POP AX + MOV [HAVFIX],1 ;Have a fix + CMP [DOFIX],0 + JZ DOTGOON ;No fix if not F + MOV CX,1 + CALL DOINT26 + JMP SHORT DOTGOON + +CANTREC: + INC [DOTSNOGOOD] + CMP [NOISY],0 + JZ DOTGOON + MOV DX,OFFSET DG:NORECDOT + CALL EPRINT +DOTGOON: + POP BP + POP BX + POP AX + MOV SI,OFFSET DG:DIRBUF + JMP CHKDOTDOT ;Go look for .. + +NODDOT: ;No .. + PUSH AX ;Return from SRCH + CMP [NOISY],0 + JNZ DOEXTMES2 + CALL SUBERRP + JMP SHORT MESD2 +DOEXTMES2: + MOV SI,OFFSET DG:PARSTR + CALL PRINTCURRDIRERR + MOV DX,OFFSET DG:NDOTMES + CALL EPRINT +MESD2: + MOV AX,1 + PUSH BX + PUSH BP + CALL GETENT + POP BP + PUSH BP + CMP BYTE PTR [DI],0E5H ;Place to put it? + JNZ CANTREC2 ;Nope + MOV SI,OFFSET DG:DDOTENT + MOV CX,11 + REP MOVSB ;Name + PUSH AX + MOV AL,ISDIR + STOSB ;Attribute + ADD DI,10 + XOR AX,AX + STOSW ;Date + STOSW ;Time + MOV AX,[BP+4] + STOSW ;Alloc # + XOR AX,AX + STOSW + STOSW ;Size + POP AX + MOV [HAVFIX],1 ;Got a fix + CMP [DOFIX],0 + JZ NFIX ;No fix if no F, carry clear + MOV CX,1 + CALL DOINT26 +NFIX: + POP BP + POP BX + POP AX + MOV SI,OFFSET DG:DIRBUF + JMP ROOTDIR ;Process files + +CANTREC2: + POP BP + POP BX + POP AX + CMP [NOISY],0 + JZ DOTSBAD + MOV DX,OFFSET DG:NORECDDOT + CALL EPRINT + JMP DOTSBAD + +NULLDIRERR: + CMP [NOISY],0 + JNZ DOEXTMES3 + CALL SUBERRP + JMP SHORT DOTSBAD +DOEXTMES3: + MOV SI,OFFSET DG:NUL + CALL PRINTCURRDIRERR + MOV DX,OFFSET DG:NULDMES + CALL EPRINT +DOTSBAD: ;Can't recover + MOV DX,OFFSET DG:BADTARG2 + CALL EPRINT + CALL DOTDOTHARDWAY + INC [DOTSNOGOOD] + JMP DIRDONE ;Terminate tree walk at this level + +ROOTDIRJ: JMP ROOTDIR + +PAGE +DIRPROC: +;Recursive tree walker +;dirproc(self,parent) + MOV [DOTSNOGOOD],0 ;Init to dots OK + MOV [ERRSUB],0 ;No subdir errors yet + PUSH BP ;Save frame pointer + MOV BP,SP + SUB SP,SFCBSIZ ;Only local var + CMP SP,[STACKLIM] + JA STACKISOK + MOV BX,OFFSET DG:STACKMES ;Out of stack + JMP FATAL +STACKISOK: + CMP [NOISY],0 + JZ NOPRINT + CMP [SECONDPASS],0 + JNZ NOPRINT ;Don't do it again on second pass + MOV DX,OFFSET DG:DIRECMES ;Tell user where we are + CALL PRINT + MOV SI,OFFSET DG:NUL + CALL PRINTCURRDIR + CALL DOCRLF +NOPRINT: + MOV SI,OFFSET DG:ALLFILE + MOV DI,SP + PUSH DI + MOV CX,SFCBSIZ + REP MOVSB ;Initialize search FCB + POP DX + MOV BX,DX ;BX points to SRCH FCB + MOV AH,DIR_SEARCH_FIRST + INT 21H + CMP WORD PTR [BP+6],0 ;Am I the root + JZ ROOTDIRJ ;Yes, no . or .. + OR AL,AL + JZ NONULLDERR + JMP NULLDIRERR ;Dir is empty! +NONULLDERR: + MOV SI,OFFSET DG:DIRBUF + DIRNAM + MOV DI,OFFSET DG:DOTENT + MOV CX,11 + REP CMPSB + JZ DOTOK ;Got a . as first entry + JMP NODOT ;No . +DOTOK: + MOV SI,OFFSET DG:DIRBUF + MOV AL,[SI.DIRATT] + TEST AL,ISDIR + JNZ DATTOK + PUSH SI ;. not a dir? + MOV SI,OFFSET DG:DOTMES + MOV DX,OFFSET DG:BADATT + CALL DOTCOMBMES + POP SI + OR [SI.DIRATT],ISDIR + CALL FIXENT ;Fix it +DATTOK: + MOV AX,[SI.DIRCLUS] + CMP AX,[BP+6] ;. link = MYSELF? + JZ DLINKOK + PUSH SI ;Link messed up + MOV SI,OFFSET DG:DOTMES + MOV DX,OFFSET DG:CLUSBAD + CALL DOTCOMBMES + POP SI + MOV AX,[BP+6] + MOV [SI.DIRCLUS],AX + CALL FIXENT ;Fix it +DLINKOK: + MOV AX,WORD PTR [SI.DIRESIZ] + OR AX,AX + JNZ BADDSIZ + MOV AX,WORD PTR [SI.DIRESIZ+2] + OR AX,AX + JZ DSIZOK +BADDSIZ: ;Size should be zero + PUSH SI + MOV SI,OFFSET DG:DOTMES + MOV DX,OFFSET DG:BADSIZM + CALL DOTCOMBMES + POP SI + XOR AX,AX + MOV WORD PTR [SI.DIRESIZ],AX + MOV WORD PTR [SI.DIRESIZ+2],AX + CALL FIXENT ;Fix it +DSIZOK: ;Get next (should be ..) + MOV DX,BX + MOV AH,DIR_SEARCH_NEXT + INT 21H +CHKDOTDOT: ;Come here after . failure + OR AL,AL + JZ DOTDOTOK +NODDOTJ: JMP NODDOT ;No .. +DOTDOTOK: + MOV SI,OFFSET DG:DIRBUF + DIRNAM + MOV DI,OFFSET DG:DDOTENT + MOV CX,11 + REP CMPSB + JNZ NODDOTJ ;No .. + MOV SI,OFFSET DG:DIRBUF + MOV AL,[SI.DIRATT] + TEST AL,ISDIR + JNZ DDATTOK ;.. must be a dir + PUSH SI + MOV SI,OFFSET DG:PARSTR + MOV DX,OFFSET DG:BADATT + CALL DOTCOMBMES + POP SI + OR [SI.DIRATT],ISDIR + CALL FIXENT ;Fix it +DDATTOK: + PUSH SI + MOV AX,[SI.DIRCLUS] + CMP AX,[BP+4] ;.. link must be PARENT + JZ DDLINKOK + MOV SI,OFFSET DG:PARSTR + MOV DX,OFFSET DG:CLUSBAD + CALL DOTCOMBMES + POP SI + MOV AX,[BP+4] + MOV [SI.DIRCLUS],AX + CALL FIXENT ;Fix it +DDLINKOK: + MOV AX,WORD PTR [SI.DIRESIZ] + OR AX,AX + JNZ BADDDSIZ + MOV AX,WORD PTR [SI.DIRESIZ+2] + OR AX,AX + JZ DDSIZOK +BADDDSIZ: ;.. size should be 0 + PUSH SI + MOV SI,OFFSET DG:PARSTR + MOV DX,OFFSET DG:BADSIZM + CALL DOTCOMBMES + POP SI + XOR AX,AX + MOV WORD PTR [SI.DIRESIZ],AX + MOV WORD PTR [SI.DIRESIZ+2],AX + CALL FIXENT ;Fix it +DDSIZOK: + MOV DX,BX ;Next entry + MOV AH,DIR_SEARCH_NEXT + INT 21H + +ROOTDIR: ;Come here after .. failure also + OR AL,AL + JZ MOREDIR ;More to go + CMP WORD PTR [BP+6],0 ;Am I the root? + JZ DIRDONE ;Yes, no chdir + MOV DX,OFFSET DG:PARSTR + MOV AH,CHDIR ;Chdir to parent (..) + INT 21H + JNC DIRDONE ;Worked + CMP [NOISY],0 + JZ DODDH + MOV SI,OFFSET DG:NUL + CALL PRINTCURRDIRERR + MOV DX,OFFSET DG:CDDDMES + CALL EPRINT +DODDH: + CALL DOTDOTHARDWAY ;Try again +DIRDONE: + MOV SP,BP ;Pop local vars + POP BP ;Restore frame + RET 4 ;Pop args + +MOREDIR: + MOV SI,OFFSET DG:DIRBUF + TEST [SI.DIRATT],ISDIR + JNZ NEWDIR ;Is a new directory + CMP [SECONDPASS],0 + JZ FPROC1 ;First pass + CALL CROSSLOOK ;Check for cross links + JMP DDSIZOK ;Next +FPROC1: + CMP [NOISY],0 + JZ NOPRINT2 + MOV DX,OFFSET DG:INDENT ;Tell user where we are + CALL PRINT + PUSH BX + MOV BX,SI + CALL PRINTTHISEL + CALL DOCRLF + MOV SI,BX + POP BX +NOPRINT2: + MOV AL,81H ;Head of file + CALL MARKFAT + TEST [SI.DIRATT],VOLIDA + JNZ HIDENFILE ;VOL ID counts as hidden + TEST [SI.DIRATT],HIDDN + JZ NORMFILE +HIDENFILE: + INC [HIDCNT] + ADD [HIDSIZ],CX + JMP DDSIZOK ;Next +NORMFILE: + INC [FILCNT] + ADD [FILSIZ],CX + JMP DDSIZOK ;Next + +NEWDIR: + CMP [SECONDPASS],0 + JZ DPROC1 + CALL CROSSLOOK ;Check for cross links + JMP SHORT DPROC2 +DPROC1: + MOV AL,82H ;Head of dir + CALL MARKFAT + INC [DIRCNT] + ADD [DIRSIZ],CX + CMP [ZEROTRUNC],0 + JZ DPROC2 ;Dir not truncated +CONVDIR: + AND [SI.DIRATT],NOT ISDIR ;Turn into file + CALL FIXENT + JMP DDSIZOK ;Next +DPROC2: + PUSH [ERRSUB] + PUSH BX ;Save my srch FCB pointer + PUSH [SI.DIRCLUS] ;MYSELF for next directory + PUSH [BP+6] ;His PARENT is me + ADD SI,DIRNAM + MOV DI,OFFSET DG:NAMBUF + PUSH DI + CALL FCB_TO_ASCZ + POP DX + MOV AH,CHDIR ;CHDIR to new dir + INT 21H + JC CANTTARG ;Barfed + CALL DIRPROC + POP BX ;Get my SRCH FCB pointer back + POP [ERRSUB] + CMP [DOTSNOGOOD],0 + JNZ ASKCONV + JMP DDSIZOK ;Next + +CANTTARG: + POP AX ;Clean stack + POP AX + POP AX + POP AX + PUSH DX ;Save pointer to bad DIR + MOV DX,OFFSET DG:BADTARG1 + CALL EPRINT + POP SI ;Pointer to bad DIR + CALL PRINTCURRDIRERR + MOV DX,OFFSET DG:BADTARG2 + CALL EPRINT +DDSIZOKJ: JMP DDSIZOK ;Next + +ASKCONV: + CMP [SECONDPASS],0 + JNZ DDSIZOKJ ;Leave on second pass + MOV DX,OFFSET DG:PTRANDIR + CMP [NOISY],0 + JNZ PRINTTRMES + MOV DX,OFFSET DG:PTRANDIR2 +PRINTTRMES: + CALL PROMPTYN ;Ask user what to do + JNZ DDSIZOKJ ;User say leave alone + PUSH BP + PUSH BX + MOV AX,[BX+THISENT] ;Entry number + CALL GETENT ;Get the entry + MOV SI,DI + MOV DI,OFFSET DG:DIRBUF + PUSH DI + ADD DI,DIRNAM + MOV CX,32 + REP MOVSB ;Transfer entry to DIRBUF + POP SI + PUSH SI + MOV SI,[SI.DIRCLUS] ;First cluster + CALL GETFILSIZ + POP SI + POP BX + POP BP + MOV WORD PTR [SI.DIRESIZ],AX ;Fix entry + MOV WORD PTR [SI.DIRESIZ+2],DX + JMP CONVDIR + +SUBTTL FAT Look routines +PAGE +CROSSLOOK: +;Same as MRKFAT only simpler for pass 2 + MOV [SRFCBPT],BX + MOV BX,SI + MOV SI,[BX.DIRCLUS] + CALL CROSSCHK + JNZ CROSSLINKJ +CHLP: + PUSH BX + CALL UNPACK + POP BX + XCHG SI,DI + CMP SI,0FF8H + JAE CHAINDONEJ + CALL CROSSCHK + JZ CHLP +CROSSLINKJ: JMP SHORT CROSSLINK + +CROSSCHK: + MOV DI,[FATMAP] + ADD DI,SI + MOV AH,[DI] + TEST AH,10H + RET + +NOCLUSTERSJ: JMP NOCLUSTERS + +MARKFAT: +; Map the file and perform checks +; SI points to dir entry +; AL is head mark with app type +; On return CX is number of clusters +; BX,SI preserved +; ZEROTRUNC is non zero if the file was trimmed to zero length +; ISCROSS is non zero if the file is cross linked + + MOV [ZEROTRUNC],0 ;Initialize + MOV [ISCROSS],0 + MOV [SRFCBPT],BX + MOV BX,SI + XOR CX,CX + MOV SI,[BX.DIRCLUS] + CMP SI,2 + JB NOCLUSTERSJ ;Bad cluster # or nul file (SI = 0) + CMP SI,[MCLUS] + JA NOCLUSTERSJ ;Bad cluster # + PUSH BX + CALL UNPACK + POP BX + JZ NOCLUSTERSJ ;Bad cluster (it is marked free) + CALL MARKMAP + JNZ CROSSLINK + AND AL,7FH ;Turn off head bit +CHASELOOP: + PUSH BX + CALL UNPACK + POP BX + INC CX + XCHG SI,DI + CMP SI,0FF8H + JAE CHAINDONE + CMP SI,2 + JB MRKBAD + CMP SI,[MCLUS] + JBE MRKOK +MRKBAD: ;Bad cluster # in chain + PUSH CX + PUSH DI + CALL PRINTTHISELERR + MOV DX,OFFSET DG:BADCHAIN + CALL EPRINT + POP SI + MOV DX,0FFFH ;Insert EOF + PUSH BX + CALL PACK + POP BX + POP CX +CHAINDONEJ: JMP SHORT CHAINDONE + +MRKOK: + CALL MARKMAP + JZ CHASELOOP +CROSSLINK: ;File is cross linked + INC [ISCROSS] + CMP [SECONDPASS],0 + JZ CHAINDONE ;Crosslinks only on second pass + PUSH SI ;Cluster number + CALL PRINTTHISEL + CALL DOCRLF + MOV DX,OFFSET DG:CROSSMES_PRE + CALL PRINT + POP SI + PUSH BX + PUSH CX + MOV BX,OFFSET DG:CROSSMES_POST + XOR DI,DI + CALL DISP16BITS + POP CX + POP BX +CHAINDONE: + TEST [BX.DIRATT],ISDIR + JNZ NOSIZE ;Don't size dirs + CMP [ISCROSS],0 + JNZ NOSIZE ;Don't size cross linked files + CMP [SECONDPASS],0 + JNZ NOSIZE ;Don't size on pass 2 (CX garbage) + MOV AL,[CSIZE] + XOR AH,AH + MUL [SSIZE] + PUSH AX ;Size in bytes of one alloc unit + MUL CX + MOV DI,DX ;Save allocation size + MOV SI,AX + SUB AX,WORD PTR [BX.DIRESIZ] + SBB DX,WORD PTR [BX.DIRESIZ+2] + JC BADFSIZ ;Size to big + OR DX,DX + JNZ BADFSIZ ;Size to small + POP DX + CMP AX,DX + JB NOSIZE ;Size within one Alloc unit + PUSH DX ;Size to small +BADFSIZ: + POP DX + PUSH CX ;Save size of file + MOV WORD PTR [BX.DIRESIZ],SI + MOV WORD PTR [BX.DIRESIZ+2],DI + CALL FIXENT2 ;Fix it + CALL PRINTTHISELERR + MOV DX,OFFSET DG:BADCLUS + CALL EPRINT + POP CX ;Restore size of file +NOSIZE: + MOV SI,BX + MOV BX,[SRFCBPT] + RET + +NOCLUSTERS: +;File is zero length + OR SI,SI + JZ CHKSIZ ;Firclus is OK, Check size + MOV DX,OFFSET DG:NULNZ +ADJUST: + PUSH DX + CALL PRINTTHISELERR + POP DX + CALL EPRINT + XOR SI,SI + MOV [BX.DIRCLUS],SI ;Set it to 0 + MOV WORD PTR [BX.DIRESIZ],SI ;Set size too + MOV WORD PTR [BX.DIRESIZ+2],SI + CALL FIXENT2 ;Fix it + INC [ZEROTRUNC] ;Indicate truncation + JMP CHAINDONE + +CHKSIZ: + MOV DX,OFFSET DG:BADCLUS + CMP WORD PTR [BX.DIRESIZ],0 + JNZ ADJUST ;Size wrong + CMP WORD PTR [BX.DIRESIZ+2],0 + JNZ ADJUST ;Size wrong + JMP CHAINDONE ;Size OK + +UNPACK: +;Cluster number in SI, Return contents in DI, BX destroyed +;ZERO SET IF CLUSTER IS FREE + MOV BX,OFFSET DG:FAT + MOV DI,SI + SHR DI,1 + ADD DI,SI + MOV DI,WORD PTR [DI+BX] + TEST SI,1 + JZ HAVCLUS + SHR DI,1 + SHR DI,1 + SHR DI,1 + SHR DI,1 +HAVCLUS: + AND DI,0FFFH + RET + +PACK: +; SI CLUSTER NUMBER TO BE PACKED +; DX DATA TO BE PLACED IN CLUSTER (SI) +; BX,DX DESTROYED + MOV [DIRTYFAT],1 ;Set FAT dirty byte + MOV [HAVFIX],1 ;Indicate a fix + MOV BX,OFFSET DG:FAT + PUSH SI + MOV DI,SI + SHR SI,1 + ADD SI,BX + ADD SI,DI + SHR DI,1 + MOV DI,[SI] + JNC ALIGNED + SHL DX,1 + SHL DX,1 + SHL DX,1 + SHL DX,1 + AND DI,0FH + JMP SHORT PACKIN +ALIGNED: + AND DI,0F000H +PACKIN: + OR DI,DX + MOV [SI],DI + POP SI + RET + + + +MARKMAP: +; Mark in AL +; Cluster in SI +; AL,SI,CX preserved +; ZERO RESET IF CROSSLINK, AH IS THE MARK THAT WAS THERE + MOV DI,[FATMAP] + ADD DI,SI + MOV AH,[DI] + OR AH,AH + PUSH AX + JZ SETMARK + MOV AL,AH + INC [CROSSCNT] ;Count the crosslink + OR AL,10H ;Resets zero +SETMARK: + MOV [DI],AL + POP AX + RET + + +CHKMAP: +;Compare FAT and FATMAP looking for badsectors orphans + MOV SI,[FATMAP] + INC SI + INC SI + MOV DX,2 + MOV CX,[DSIZE] +CHKMAPLP: + LODSB + OR AL,AL + JNZ CONTLP ;Already seen this one + XCHG SI,DX + CALL UNPACK + XCHG SI,DX + JZ CONTLP ;Free cluster + CMP DI,0FF7H ;Bad sector? + JNZ ORPHAN ;No, found an orphan + INC [BADSIZ] + MOV BYTE PTR [SI-1],4 ;Flag it + JMP CONTLP +ORPHAN: + INC [ORPHSIZ] + MOV BYTE PTR [SI-1],8 ;Flag it +CONTLP: + INC DX ;Next cluster + LOOP CHKMAPLP + MOV SI,[ORPHSIZ] + OR SI,SI + JZ RET18 ;No orphans + CALL RECOVER +RET18: RET + +RECOVER: +;free orphans or do chain recovery + CALL CHECKNOFMES + CALL DOCRLF + CALL CHAINREPORT + MOV DX,OFFSET DG:FREEMES + CALL PROMPTYN ;Ask user + JNZ NOCHAINREC + JMP CHAINREC +NOCHAINREC: + MOV SI,[FATMAP] ;Free all orphans + INC SI + INC SI + MOV DX,2 + MOV CX,[DSIZE] +CHKMAPLP2: + LODSB + TEST AL,8 + JZ NEXTCLUS + XCHG SI,DX + PUSH DX + XOR DX,DX + CALL PACK ;Mark as free + POP DX + XCHG SI,DX +NEXTCLUS: + INC DX + LOOP CHKMAPLP2 + XOR AX,AX + XCHG AX,[ORPHSIZ] + PUSH AX + MOV DX,OFFSET DG:FREEBYMESF_PRE + CMP [DOFIX],0 + JNZ PRINTFMES + MOV DX,OFFSET DG:FREEBYMES_PRE +PRINTFMES: + CALL PRINT + POP AX + MOV BX,OFFSET DG:FREEBYMESF_POST + CMP [DOFIX],0 + JNZ DISPFRB + MOV BX,OFFSET DG:FREEBYMES_POST + MOV [LCLUS],AX +DISPFRB: + CALL DISPCLUS ;Tell how much freed + RET + +FINDCHAIN: +;Do chain recovery on orphans + MOV SI,[FATMAP] + INC SI + INC SI + MOV DX,2 + MOV CX,[DSIZE] +CHKMAPLP3: + LODSB + TEST AL,8 ;Orphan? + JZ NEXTCLUS2 ;Nope + TEST AL,1 ;Seen before ? + JNZ NEXTCLUS2 ;Yup + PUSH SI ;Save search environment + PUSH CX + PUSH DX + DEC SI + OR BYTE PTR [SI],81H ;Mark as seen and head + INC [ORPHCNT] ;Found a chain + MOV SI,DX +CHAINLP: + CALL UNPACK + XCHG SI,DI + CMP SI,0FF8H + JAE CHGOON ;EOF + PUSH DI + CMP SI,2 + JB INSERTEOF ;Bad cluster number + CMP SI,[MCLUS] + JA INSERTEOF ;Bad cluster number + CMP SI,DI + JZ INSERTEOF ;Tight loop + CALL CROSSCHK + TEST AH,8 ;Points to a non-orphan? + JNZ CHKCHHEAD ;Nope +INSERTEOF: + POP SI ;Need to stick EOF here + MOV DX,0FFFH + CALL PACK + JMP SHORT CHGOON +CHKCHHEAD: + TEST AH,80H ;Previosly marked head? + JZ ADDCHAIN ;Nope + AND BYTE PTR [DI],NOT 80H ;Turn off head bit + DEC [ORPHCNT] ;Wasn't really a head + POP DI ;Clean stack + JMP SHORT CHGOON +ADDCHAIN: + TEST AH,1 ;Previosly seen? + JNZ INSERTEOF ;Yup, don't make a cross link + OR BYTE PTR [DI],1 ;Mark as seen + POP DI ;Clean stack + JMP CHAINLP ;Follow chain + +CHGOON: + POP DX ;Restore search + POP CX + POP SI +NEXTCLUS2: + INC DX + LOOP CHKMAPLP3 + RET + +CHAINREC: + LDS DI,[THISDPB] +ASSUME DS:NOTHING + MOV CX,[DI.dpb_root_entries] + PUSH CS + POP DS +ASSUME DS:DG + MOV SI,[FATMAP] + INC SI + INC SI + MOV DI,1 + CALL NEXTORPH + PUSH SI + PUSH DI + MOV SI,DI + XOR AX,AX + MOV DX,[ORPHCNT] +MAKFILLP: + PUSH AX + PUSH CX + PUSH DX + PUSH SI + CALL GETENT + POP SI + CMP BYTE PTR [DI],0E5H + JZ GOTENT + CMP BYTE PTR [DI],0 + JNZ NEXTENT +GOTENT: + MOV [HAVFIX],1 ;Making a fix + CMP [DOFIX],0 + JZ ENTMADE ;Not supposed to, carry clear + MOV [DI+26],SI ;FIRCLUS Pointer + PUSH AX ;Save INT 26 data + PUSH DX + PUSH BX + MOV AH,DISK_RESET ;Force current state + INT 21H + MOV DX,OFFSET DG:ORPHFCB + MOV AH,FCB_OPEN +OPAGAIN: + INT 21H + OR AL,AL + JNZ GOTORPHNAM + CALL MAKORPHNAM ;Try next name + JMP SHORT OPAGAIN + +GOTORPHNAM: + MOV SI,OFFSET DG:ORPHFCB + 1 ;ORPHFCB Now has good name + MOV CX,11 + REP MOVSB + CALL MAKORPHNAM ;Make next name + XOR AX,AX + MOV CX,15 + REP STOSB + MOV SI,[DI] + INC DI ;Skip FIRCLUS + INC DI + PUSH DI + CALL GETFILSIZ + POP DI + STOSW + MOV AX,DX + STOSW + POP BX + POP DX + POP AX + MOV CX,1 + CALL DOINT26 +ENTMADE: + POP DX + POP CX + POP AX + POP DI + POP SI + DEC DX + OR DX,DX + JZ RET100 + CALL NEXTORPH + PUSH SI + PUSH DI + MOV SI,DI + JMP SHORT NXTORP + +NEXTENT: + POP DX + POP CX + POP AX +NXTORP: + INC AX + LOOP MAKFILLPJ + POP AX ;Clean Stack + POP AX + SUB [ORPHCNT],DX ;Couldn't make them all + MOV DX,OFFSET DG:CREATMES + CALL EPRINT +RET100: RET + +MAKFILLPJ: JMP MAKFILLP + +NEXTORPH: + PUSH AX + LODSB + INC DI + CMP AL,89H + POP AX + JZ RET100 + JMP SHORT NEXTORPH + +MAKORPHNAM: + PUSH SI + MOV SI,OFFSET DG:ORPHEXT - 1 +NAM0: + INC BYTE PTR [SI] + CMP BYTE PTR [SI],'9' + JLE NAMMADE + MOV BYTE PTR [SI],'0' + DEC SI + JMP NAM0 + +NAMMADE: + POP SI + RET + +GETFILSIZ: +;SI is start cluster, returns filesize as DX:AX + XOR AX,AX +NCLUS: + CALL UNPACK + XCHG SI,DI + INC AX + CMP SI,0FF8H + JAE GOTEOF + CMP SI,2 + JAE NCLUS +GOTEOF: + MOV BL,[CSIZE] + XOR BH,BH + MUL BX + MUL [SSIZE] + RET + + + +CHKCROSS: +;Check for Crosslinks, do second pass if any to find pairs + MOV SI,[CROSSCNT] + OR SI,SI + JZ RET8 ;None + CALL DOCRLF + INC [SECONDPASS] + XOR AX,AX + PUSH AX + PUSH AX + CALL DIRPROC ;Do it again +RET8: RET + +SUBTTL AMDONE - Finish up routine +PAGE +AMDONE: +ASSUME DS:NOTHING + CMP [DIRTYFAT],0 + JZ NOWRITE ;FAT not dirty + CMP [DOFIX],0 + JZ NOWRITE ;Not supposed to fix +REWRITE: + LDS BX,[THISDPB] +ASSUME DS:NOTHING + MOV CL,[BX.dpb_FAT_size] ;Sectors for one fat + XOR CH,CH + MOV DI,CX + MOV CL,[BX.dpb_FAT_count] ;Number of FATs + MOV DX,[BX.dpb_first_FAT] ;First sector of FAT + PUSH CS + POP DS +ASSUME DS:DG + MOV [ERRCNT],CH + MOV BX,OFFSET DG:FAT + MOV AL,[ALLDRV] + DEC AL + MOV AH,'1' + PUSH CX +WRTLOOP: + XCHG CX,DI + PUSH DX + PUSH CX + PUSH DI + PUSH AX + INT 26H ;Write out the FAT + MOV [HECODE],AL + POP AX ;Flags + JNC WRTOK + INC [ERRCNT] + MOV DX,OFFSET DG:BADWRITE_PRE + CALL PRINT + POP AX + PUSH AX + MOV DL,AH + CALL PRTCHR + MOV DX,OFFSET DG:BADWRITE_POST + CALL PRINT +WRTOK: + POP AX + POP CX + POP DI + POP DX + INC AH + ADD DX,DI + LOOP WRTLOOP ;Next FAT + POP CX ;Number of FATs + CMP CL,[ERRCNT] ;Error on all? + JNZ NOWRITE ;no + CALL WDSKERR + JZ REWRITE +NOWRITE: + MOV AH,DISK_RESET ;Invalidate any buffers in system + INT 21H + MOV DX,OFFSET DG:USERDIR ;Recover users directory + MOV AH,CHDIR + INT 21H + CMP BYTE PTR [FRAGMENT],1 ;Check for any fragmented files? + JNZ DONE ;No -- we're finished + CALL CHECKFILES ;Yes -- report any fragments +DONE: +ASSUME DS:NOTHING + MOV DL,[USERDEV] ;Recover users drive + MOV AH,SET_DEFAULT_DRIVE + INT 21H + RET + +SUBTTL Routines for manipulating dir entries +PAGE +FIXENT2: +;Same as FIXENT only [SRFCBPT] points to the search FCB, BX points to the entry + PUSH SI + PUSH BX + PUSH CX + MOV SI,BX + MOV BX,[SRFCBPT] + CALL FIXENT + POP CX + POP BX + POP SI +RET20: RET + +FIXENT: +;BX Points to search FCB +;SI Points to Entry to fix + MOV [HAVFIX],1 ;Indicate a fix + CMP [DOFIX],0 + JZ RET20 ;But don't do it! + PUSH BP + PUSH BX + PUSH SI + PUSH SI ;Entry pointer + MOV AX,[BX+THISENT] ;Entry number + CALL GETENT + POP SI ;Entry pointer + ADD SI,DIRNAM ;Point to start of entry + MOV CX,32 + REP MOVSB + INC CL + CALL DOINT26 + POP SI + POP BX + POP BP + RET + +GETENT: +;AX is desired entry number (in current directory) +; +;DI points to entry in SECBUF +;AX DX BX set to do an INT 26 to write it back out (CX must be reset to 1) +;ALL registers destroyed (via int 25) + LDS DI,[THISDPB] +ASSUME DS:NOTHING + MOV BX,[DI.dpb_current_dir] + PUSH CS + POP DS +ASSUME DS:DG + CMP BX,0FF8H + JB CLUSISOK + MOV BX,OFFSET DG:BADDPBDIR ;This should never happen + JMP FATAL +CLUSISOK: + MOV CL,4 + SHL AX,CL + XOR DX,DX + SHL AX,1 + RCL DX,1 ;Account for overflow + MOV CX,[SSIZE] + AND CL,255-31 ;Must be a multiple of 32 + DIV CX ;DX is position in sector, AX is dir sector # + OR BX,BX + JZ WANTROOT + DIV [CSIZE] ;AL # clusters to skip, AH position in cluster + MOV CL,AL + XOR CH,CH + JCXZ GOTCLUS + MOV SI,BX +SKIPLP: + CALL UNPACK + XCHG SI,DI + LOOP SKIPLP + MOV BX,SI +GOTCLUS: + PUSH DX ;Position in sector + CALL FIGREC ;Convert to sector # +DOROOTDIR: + MOV BX,[SECBUF] + MOV AL,[ALLDRV] + DEC AL +RDRETRY: + PUSH AX + PUSH DX + PUSH BX + MOV CX,1 + INT 25H ;Read it + MOV [HECODE],AL + POP AX ;FLAGS + POP BX + POP DX + POP AX + JNC RDOK2 + CALL RDSKERR + JZ RDRETRY +RDOK2: + POP DI ;Offset into sector + ADD DI,BX ;Add sector base offset + RET + +WANTROOT: + PUSH DX + LDS DI,[THISDPB] +ASSUME DS:NOTHING + MOV DX,AX + ADD DX,[DI.dpb_dir_sector] + PUSH CS + POP DS +ASSUME DS:DG + JMP DOROOTDIR + +CHECKNOFMES: + MOV AL,1 + XCHG AL,[FIXMFLG] + OR AL,AL + JNZ RET14 ;Don't print it more than once + CMP [DOFIX],0 + JNZ RET14 ;Don't print it if F switch specified + PUSH DX + MOV DX,OFFSET DG:FIXMES + CALL PRINT + POP DX + RET + +CHECKERR: + CALL CHECKNOFMES + CMP [SECONDPASS],0 +RET14: RET + +PRINTCURRDIRERR: + CALL CHECKERR + JNZ RET14 + CALL PRINTCURRDIR + JMP SHORT ERREX + +PRINTTHISELERR: + CALL CHECKERR + JNZ RET14 + CALL PRINTTHISEL +ERREX: + CALL DOCRLF + RET + +PRINTTHISEL: + MOV SI,BX + ADD SI,DIRNAM +PRINTTHISEL2: + MOV DI,OFFSET DG:NAMBUF + PUSH DI + CALL FCB_TO_ASCZ + POP SI +PRINTCURRDIR: + PUSH SI + MOV DL,[ALLDRV] + ADD DL,'@' + CALL PRTCHR + MOV DL,DRVCHAR + CALL PRTCHR + LDS SI,[THISDPB] +ASSUME DS:NOTHING + CMP [SI.dpb_current_dir],0 + JZ CURISROOT + MOV DL,[DIRCHAR] + CALL PRTCHR + ADD SI,dpb_dir_text +PCURRLP: + LODSB + OR AL,AL + JZ CURISROOT + MOV DL,AL + CALL PRTCHR + JMP PCURRLP + +CURISROOT: + PUSH CS + POP DS +ASSUME DS:DG + POP SI + CMP BYTE PTR [SI],0 + JZ LPDONE ;If tail string NUL, no '/' + MOV DL,[DIRCHAR] + CALL PRTCHR +ERRLOOP: + LODSB + OR AL,AL + JZ LPDONE + MOV DL,AL + CALL PRTCHR + JMP ERRLOOP +LPDONE: + RET + +FATAL: +;Unrecoverable error + MOV DX,OFFSET DG:FATALMES + CALL PRINT + MOV DX,BX + CALL PRINT + MOV DL,[USERDEV] ;At least leave on same drive + MOV AH,SET_DEFAULT_DRIVE + INT 21H + INT 20H + + +INT_24_RETADDR DW OFFSET DG:INT_24_BACK + +INT_24 PROC FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSHF + PUSH CS + PUSH [INT_24_RETADDR] + PUSH WORD PTR [HARDCH+2] + PUSH WORD PTR [HARDCH] + RET +INT_24 ENDP + +INT_24_BACK: + CMP AL,2 ;Abort? + JNZ IRETI + CALL DONE ;Forget about directory, restore users drive + INT 20H +IRETI: + IRET + +INT_23: + LDS DX,[HARDCH] + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H + INT 21H + LDS DX,[CONTCH] + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H + INT 21H + PUSH CS + POP DS +ASSUME DS:DG + MOV [FRAGMENT],0 +RDONE: + CALL NOWRITE ;Restore users drive and directory + INT 20H + +CODE ENDS + END CHKPROC + \ No newline at end of file diff --git a/COMEQU.ASM b/COMEQU.ASM new file mode 100644 index 0000000..56dbbe6 --- /dev/null +++ b/COMEQU.ASM @@ -0,0 +1,33 @@ +;************************************* +; COMMAND EQUs which are not switch dependant + +IFDEF IBM + INCLUDE IFEQU.ASM +ENDIF + + +SYM EQU ">" + +LINPERPAG EQU 23 +NORMPERLIN EQU 1 +WIDEPERLIN EQU 5 +COMBUFLEN EQU 128 ; Length of commmand buffer + +DRVCHAR EQU ":" + +FCB EQU 5CH + +VARSTRUC STRUC +ISDIR DB ? +SIZ DB ? +TTAIL DW ? +INFO DB ? +BUF DB DIRSTRLEN + 20 DUP (?) +VARSTRUC ENDS + +WSWITCH EQU 1 ; Wide display during DIR +PSWITCH EQU 2 ; Pause (or Page) mode during DIR +ASWITCH EQU 4 ; ASCII mode during COPY +BSWITCH EQU 8 ; Binary mode during COPY +VSWITCH EQU 10H ; Verify switch +GOTSWITCH EQU 8000H ; Meta switch set if switch character encountered diff --git a/COMLINK b/COMLINK new file mode 100644 index 0000000000000000000000000000000000000000..f7dd961cf614199e08e5b067323c00d68ec407f0 GIT binary patch literal 128 zcmYe!&&^HDOHn8)P0mkARVYeHEJ;+z%*!lMCc; literal 0 HcmV?d00001 diff --git a/COMMAND.ASM b/COMMAND.ASM new file mode 100644 index 0000000..db2783a --- /dev/null +++ b/COMMAND.ASM @@ -0,0 +1,788 @@ +; +; This version of COMMAND is divided into three distinct parts. First is the +; resident portion, which includes handlers for interrupts 22H (terminate), +; 23H (Cntrl-C), 24H (fatal error), and 27H (stay resident); it also has code +; to test and, if necessary, reload the transient portion. Following the +; resident is the init code, which is overwritten after use. Then comes the +; transient portion, which includes all command processing (whether internal +; or external). The transient portion loads at the end of physical memory, +; and it may be overlayed by programs that need as much memory as possible. +; When the resident portion of command regains control from a user program, a +; checksum is performed on the transient portion to see if it must be +; reloaded. Thus programs which do not need maximum memory will save the time +; required to reload COMMAND when they terminate. + +; +; REV 1.17 +; 05/19/82 Fixed bug in BADEXE error (relocation error must return to +; resident since the EXELOAD may have overwritten the transient. +; REV 1.18 +; 05/21/82 IBM version always looks on drive A +; MSVER always looks on default drive +; +; REV 1.19 +; 06/03/82 Drive spec now entered in command line +; 06/07/82 Added VER command (print DOS version number) and VOL command +; (print volume label) +; REV 1.20 +; 06/09/82 Prints "directory" after directories +; 06/13/82 MKDIR, CHDIR, PWD, RMDIR added +; REV 1.50 +; Some code for new 2.0 DOS, sort of HACKey. Not enough time to +; do it right. +; REV 1.70 +; EXEC used to fork off new processes +; REV 1.80 +; C switch for single command execution +; REV 1.90 +; Batch uses XENIX +; Rev 2.00 +; Lots of neato stuff +; IBM 2.00 level +; Rev 2.01 +; 'D' switch for date time suppression +; Rev 2.02 +; Default userpath is NUL rather than BIN +; same as IBM +; COMMAND split into pieces +; Rev 2.10 +; INTERNATIONAL SUPPORT +; Rev 2.11 COMMAND split into more pieces + + INCLUDE DOSSYM.ASM + INCLUDE DEVSYM.ASM + INCLUDE COMSW.ASM + INCLUDE COMEQU.ASM + +CODERES SEGMENT PUBLIC +CODERES ENDS + +DATARES SEGMENT PUBLIC BYTE + EXTRN COMBAD:BYTE,NEEDCOM:BYTE,DRVMSG:BYTE + EXTRN DEFMSG:BYTE,PROMPT:BYTE,EXECEMES:BYTE,EXEBAD:BYTE + EXTRN TOOBIG:BYTE,NOCOM:BYTE,RBADNAM:BYTE,INT_2E_RET:DWORD + EXTRN NOHANDMES:BYTE,BMEMMES:BYTE,HALTMES:BYTE,FRETMES:BYTE + EXTRN PARENT:WORD,HANDLE01:WORD,LOADING:BYTE,BATCH:WORD + EXTRN TRNSEG:WORD,COMDRV:BYTE,MEMSIZ:WORD,SUM:WORD,EXTCOM:BYTE + EXTRN IO_SAVE:WORD,PERMCOM:BYTE,SINGLECOM:WORD,VERVAL:WORD + EXTRN PIPEFLAG:BYTE,SAVE_PDB:WORD,COMSPEC:BYTE,TRANS:WORD + EXTRN TRANVARS:BYTE,LTPA:WORD,RSWITCHAR:BYTE,RDIRCHAR:BYTE + EXTRN RETCODE:WORD,FORFLAG:BYTE + + IF IBMVER + EXTRN SYS_CALL:DWORD,ZEXEC:WORD,EXESEG:WORD,EXESUM:WORD + EXTRN USER_SS:WORD,USER_SP:WORD + ENDIF + +DATARES ENDS + +ENVIRONMENT SEGMENT PUBLIC PARA ; Default COMMAND environment +ENVIRONMENT ENDS + +INIT SEGMENT PUBLIC PARA + EXTRN CONPROC:NEAR +INIT ENDS + +TAIL SEGMENT PUBLIC PARA +TAIL ENDS + +TRANCODE SEGMENT PUBLIC PARA +TRANCODE ENDS + +TRANDATA SEGMENT PUBLIC BYTE + EXTRN TRANDATAEND:BYTE +TRANDATA ENDS + +TRANSPACE SEGMENT PUBLIC BYTE + EXTRN TRANSPACEEND:BYTE,HEADCALL:DWORD +TRANSPACE ENDS + +TRANTAIL SEGMENT PUBLIC PARA +TRANTAIL ENDS + +ZEXEC_CODE SEGMENT PUBLIC PARA +ZEXEC_CODE ENDS + +ZEXEC_DATA SEGMENT PUBLIC BYTE +ZEXEC_DATA ENDS + +RESGROUP GROUP CODERES,DATARES,ENVIRONMENT,INIT,TAIL +TRANGROUP GROUP TRANCODE,TRANDATA,TRANSPACE,TRANTAIL +EGROUP GROUP ZEXEC_CODE,ZEXEC_DATA + +ENVIRONMENT SEGMENT PUBLIC PARA ; Default COMMAND environment + + PUBLIC ECOMSPEC,ENVIREND,PATHSTRING + + ORG 0 +ENVARENA DB 10H DUP (?) ; Pad for mem arena +PATHSTRING DB "PATH=" +USERPATH LABEL BYTE + + DB 0 ; Null path + DB "COMSPEC=" +ECOMSPEC DB "/COMMAND.COM" + DB 134 DUP (0) + +ENVIREND LABEL BYTE + +ENVIRONSIZ EQU $-PATHSTRING +ENVIRONSIZ2 EQU $-ECOMSPEC +ENVIRONMENT ENDS + + +; START OF RESIDENT PORTION + +CODERES SEGMENT PUBLIC + + PUBLIC GETCOMDSK2,LODCOM,THEADFIX,CONTCTERM,LOADCOM,INT_2E,LODCOM1 + PUBLIC CHKSUM,SETVECT,EXT_EXEC,TREMCHECK,RESTHAND,CONTC,RSTACK + PUBLIC SAVHAND + + IF IBMVER + PUBLIC EXECHK,SYSCALL,EXEC_WAIT + ENDIF + +ASSUME CS:RESGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + + EXTRN RPRINT:NEAR,ASKEND:NEAR,DSKERR:NEAR + + + ORG 0 +ZERO = $ + + ORG 100H + +PROGSTART: + JMP RESGROUP:CONPROC + + DB (80H - 3) DUP (?) +RSTACK LABEL WORD + +IF IBMVER +SYSCALL: + CMP AH,EXEC + JZ do_exec + JMP DWORD PTR [SYS_CALL] + +do_exec: + PUSH ES + PUSH DS + PUSH BP + PUSH DI + PUSH SI + PUSH DX + PUSH CX + PUSH BX + PUSH AX + MOV [user_ss],SS + MOV [user_sp],SP +; +; are we running on RSTACK already? +; + PUSH CS + POP BX ; BX <- CS + PUSH SS + POP AX ; AX <- SS + CMP AX,BX ; IF AX == BX then no stack switch! + JZ Get_mem + MOV SS,BX +ASSUME SS:RESGROUP + MOV SP,OFFSET RESGROUP:RSTACK + +Get_mem: + MOV BX,0FFFFH ; allocate all of memory + MOV AH,ALLOC + INT int_command + MOV AX,OFFSET EGROUP:ZEXECDATAEND + 15 + MOV CL,4 + SHR AX,CL + MOV CX,AX ; Save in CX + CMP BX,AX ; enough for EXEC? + JB EXECMER ; nope... cry + MOV AH,ALLOC + INT int_command + JC EXECMER ; Memory arenas probably trashed + ADD BX,AX + MOV [MEMSIZ],BX + SUB BX,CX + MOV [EXESEG],BX ; exec + MOV ES,AX + MOV AH,DEALLOC + INT int_command + PUSH CS + POP DS +ASSUME DS:RESGROUP + CALL EXECHK + CMP DX,[EXESUM] + JZ HAVEXEC ; EXEC OK + MOV DX,OFFSET RESGROUP:COMSPEC + MOV AX,OPEN SHL 8 + INT int_command ; Open COMMAND.COM + JC EXECMER + MOV BX,AX ; Handle + MOV DX,OFFSET RESGROUP:TRANSTART + ADD DX,OFFSET TRANGROUP:EXECSTART - 100H + XOR CX,CX ; Seek loc + MOV AX,LSEEK SHL 8 + INT int_command + MOV CX,OFFSET EGROUP:ZEXECCODEEND + MOV DS,[EXESEG] +ASSUME DS:NOTHING + MOV AH,READ + INT int_command + PUSH AX + MOV AH,CLOSE + INT int_command ; Close COMMAND.COM + POP CX + CMP CX,OFFSET EGROUP:ZEXECCODEEND + JNZ EXECMER ; Size matched + + CALL EXECHK + CMP DX,[EXESUM] + JNZ EXECMER +HAVEXEC: + MOV [LOADING],0 ; Flag to DSKERR + CALL DWORD PTR [ZEXEC] + JMP SHORT EXECRET +execmer: + LDS SI,DWORD PTR [user_Sp] + MOV [SI.user_AX],exec_not_enough_memory + PUSH [SI.user_F] + POPF + STC + PUSHF + POP [SI.user_F] +execret: + MOV SS,[user_SS] +ASSUME SS:NOTHING + MOV SP,[user_SP] + POP AX ; PUSH ES + POP BX ; PUSH DS + POP CX ; PUSH BP + POP DX ; PUSH DI + POP SI ; PUSH SI + POP DI ; PUSH DX + POP BP ; PUSH CX + POP DS ; PUSH BX + POP ES ; PUSH AX + IRET + +EXECHK: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH DS + MOV DS,[EXESEG] + MOV CX,OFFSET EGROUP:ZEXECCODEEND + XOR SI,SI + JMP CHECK_SUM +ENDIF + +EXEC_ERR: ; Select the correct error message + MOV DX,OFFSET RESGROUP:RBADNAM + CMP AX,exec_file_not_found + JZ GOTEXECEMES + CMP AX,error_access_denied + JZ GOTEXECEMES + MOV DX,OFFSET RESGROUP:TOOBIG + CMP AX,exec_not_enough_memory + JZ GOTEXECEMES + MOV DX,OFFSET RESGROUP:EXEBAD + CMP AX,exec_bad_format + JZ GOTEXECEMES + MOV DX,OFFSET RESGROUP:EXECEMES +GOTEXECEMES: + PUSH CS + POP DS + CALL RPRINT + JMP SHORT NOEXEC + +EXT_EXEC: +; +; we are now running in free space. anything we do from here +; on may get trashed. Move the stack (also in free space) to +; allocated space because since EXEC restores the stack, +; somebody may trash what is on the stack. +; + MOV CX,CS + MOV SS,CX + MOV SP,OFFSET RESGROUP:RSTACK +; +; Oops!! We have to make sure that the EXEC code doesn't blop a newstack! +; +; + INT int_command ; Do the EXEC + JC EXEC_ERR ; EXEC failed +EXEC_WAIT: + MOV AH,WAIT + INT int_command ; Get the return code + MOV [RETCODE],AX +NOEXEC: + JMP LODCOM + +CONTC: + STI + MOV AX,CS + MOV DS,AX +ASSUME DS:RESGROUP + MOV AH,DISK_RESET + INT int_command ; Reset disks in case files were open + TEST [BATCH],-1 + JZ CONTCTERM + JMP ASKEND ; See if user wants to terminate batch +CONTCTERM: + XOR BP,BP ; Indicate no read + MOV [FORFLAG],0 ; Turn off for processing + MOV [PIPEFLAG],0 ; Turn off any pipe + CMP [SINGLECOM],0 ; See if we need to set SINGLECOM + JZ NOSETSING + MOV [SINGLECOM],-1 ; Cause termination on pipe, batch, for +NOSETSING: + CMP [EXTCOM],0 + JNZ DODAB ; Internal ^C + JMP LODCOM1 +DODAB: + STC ; Tell DOS to abort +ZZY PROC FAR + RET ; Leave flags on stack +ZZY ENDP + +BADMEMERR: ; Allocation error loading transient + MOV DX,OFFSET RESGROUP:BMEMMES +FATALC: + PUSH CS + POP DS + CALL RPRINT + CMP [PERMCOM],0 + JZ FATALRET + CMP [SINGLECOM],0 ; If PERMCOM and SINGLECOM + JNZ FATALRET ; Must take INT_2E exit + MOV DX,OFFSET RESGROUP:HALTMES + CALL RPRINT +STALL: + JMP STALL ; Crash the system nicely + +FATALRET: + MOV DX,OFFSET RESGROUP:FRETMES + CALL RPRINT +FATALRET2: + CMP [PERMCOM],0 ; If we get here and PERMCOM, + JNZ RET_2E ; must be INT_2E +IF IBM + LDS DX,DWORD PTR [SYS_CALL] +ASSUME DS:NOTHING + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) + INT_COMMAND + INT int_command +ENDIF + MOV AX,[PARENT] + MOV WORD PTR CS:[PDB_Parent_PID],AX + MOV AX,(EXIT SHL 8) ; Return to lower level + INT int_command + +RET_2E: + PUSH CS + POP DS +ASSUME DS:RESGROUP,ES:NOTHING,SS:NOTHING + MOV [SINGLECOM],0 ; Turn off singlecom + MOV ES,[LTPA] + MOV AH,DEALLOC + INT int_command ; Free up space used by transient + MOV BX,[SAVE_PDB] + MOV AH,SET_CURRENT_PDB + INT int_command ; Current process is user + MOV AX,[RETCODE] + CMP [EXTCOM],0 + JNZ GOTECODE + XOR AX,AX ; Internals always return 0 +GOTECODE: + MOV [EXTCOM],1 ; Force external + JMP [INT_2E_RET] ;"IRET" + +INT_2E: ; Magic command executer +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + POP WORD PTR [INT_2E_RET] + POP WORD PTR [INT_2E_RET+2] ;Get return address + POP AX ;Chuck flags + PUSH CS + POP ES + MOV DI,80H + MOV CX,64 + REP MOVSW + MOV AH,GET_CURRENT_PDB + INT int_command ; Get user's header + MOV [SAVE_PDB],BX + MOV AH,SET_CURRENT_PDB + MOV BX,CS + INT int_command ; Current process is me + MOV [SINGLECOM],81H + MOV [EXTCOM],1 ; Make sure this case forced + +LODCOM: ; Termination handler + CMP [EXTCOM],0 + JZ LODCOM1 ; If internal, memory already allocated + MOV BX,0FFFFH + MOV AH,ALLOC + INT int_command + MOV AX,OFFSET TRANGROUP:TRANSPACEEND + 15 + MOV CL,4 + SHR AX,CL + + IF IBM + PUSH AX + MOV AX,OFFSET EGROUP:ZEXECDATAEND + 15 + MOV CL,4 + SHR AX,CL + POP CX + ADD AX,CX + ENDIF + + ADD AX,20H + CMP BX,AX ; Is less than 512 byte buffer worth it? + JNC MEMOK +BADMEMERRJ: + JMP BADMEMERR ; Not enough memory +MEMOK: + MOV AH,ALLOC + INT int_command + JC BADMEMERRJ ; Memory arenas probably trashed + MOV [EXTCOM],0 ; Flag not to ALLOC again + MOV [LTPA],AX ; New TPA is base just allocated + ADD BX,AX + MOV [MEMSIZ],BX + + MOV AX,OFFSET TRANGROUP:TRANSPACEEND + 15 + MOV CL,4 + SHR AX,CL + + IF IBM + PUSH AX + MOV AX,OFFSET EGROUP:ZEXECDATAEND + 15 + MOV CL,4 + SHR AX,CL + POP CX + ADD AX,CX + ENDIF + + SUB BX,AX + MOV [TRNSEG],BX ; Transient starts here +LODCOM1: + MOV AX,CS + MOV SS,AX +ASSUME SS:RESGROUP + MOV SP,OFFSET RESGROUP:RSTACK + MOV DS,AX +ASSUME DS:RESGROUP + CALL HEADFIX ; Make sure files closed stdin and stdout restored + XOR BP,BP ; Flag command ok + MOV AX,-1 + XCHG AX,[VERVAL] + CMP AX,-1 + JZ NOSETVER + MOV AH,SET_VERIFY_ON_WRITE ; AL has correct value + INT int_command +NOSETVER: + CMP [SINGLECOM],-1 + JNZ NOSNG + JMP FATALRET2 ; We have finished the single command +NOSNG: + CALL SETVECT + +IF IBMVER + CALL EXECHK ; Check exe loader + CMP DX,[EXESUM] + JNZ BOGUS_COM +ENDIF + + CALL CHKSUM ; Check the transient + CMP DX,[SUM] + JZ HAVCOM ; Transient OK +BOGUS_COM: + MOV [LOADING],1 ; Flag DSKERR routine + CALL LOADCOM +CHKSAME: + +IF IBMVER + CALL EXECHK + CMP DX,[EXESUM] + JNZ ALSO_BOGUS +ENDIF + + CALL CHKSUM + CMP DX,[SUM] + JZ HAVCOM ; Same COMMAND +ALSO_BOGUS: + CALL WRONGCOM + JMP SHORT CHKSAME +HAVCOM: + MOV AX,CHAR_OPER SHL 8 + INT int_command + MOV [RSWITCHAR],DL + CMP DL,'/' + JNZ USESLASH + MOV [RDIRCHAR],'\' ; Select alt path separator +USESLASH: + MOV [LOADING],0 ; Flag to DSKERR + MOV SI,OFFSET RESGROUP:TRANVARS + MOV DI,OFFSET TRANGROUP:HEADCALL + MOV ES,[TRNSEG] + CLD + MOV CX,8 + REP MOVSW ; Transfer INFO to transient + MOV AX,[MEMSIZ] + MOV WORD PTR DS:[PDB_block_len],AX ; Adjust my own header + JMP DWORD PTR [TRANS] + +; Far call to REMCHECK for TRANSIENT +TREMCHECK PROC FAR + CALL REMCHECK + RET +TREMCHECK ENDP + +REMCHECK: +;All registers preserved. Returns zero if media removable, NZ if fixed +; AL is drive (0=DEF, 1=A,...) + IF IBM + PUSH AX + OR AL,AL + JNZ GOTDRV2 + MOV AH,GET_DEFAULT_DRIVE + INT int_command + INC AL ;A=1 +GOTDRV2: + PUSH BX + MOV BL,AL + INT 11H ;IBM EQUIP CALL + ROL AL,1 + ROL AL,1 + AND AL,3 + JNZ NOT_SINGLE + INC AL +NOT_SINGLE: + INC AL ; AL is now MAX floppy # + CMP BL,AL + POP BX + JBE SETREM ; Is an IBM floppy and so is removable + OR AL,AL ; Know AL is non-zero + JMP SHORT SETNREM +SETREM: + ELSE + PUSH AX + ENDIF + + XOR AX,AX ;Zero + + IF IBM +SETNREM: + ENDIF + + POP AX + RET + +; Far call to HEADFIX for TRANSIENT +THEADFIX PROC FAR + CALL HEADFIX + RET +THEADFIX ENDP + +HEADFIX: + XOR BX,BX ; Clean up header + MOV CX,[IO_SAVE] + MOV DX,WORD PTR DS:[PDB_JFN_Table] + CMP CL,DL + JZ CHK1 ; Stdin matches + MOV AH,CLOSE + INT int_command + MOV DS:[PDB_JFN_Table],CL ; Restore stdin +CHK1: + INC BX + CMP CH,DH ; Stdout matches + JZ CHKOTHERHAND + MOV AH,CLOSE + INT int_command + MOV DS:[PDB_JFN_Table+1],CH ; Restore stdout +CHKOTHERHAND: + ADD BX,4 ; Skip 2,3,4 + MOV CX,FilPerProc - 5 ; Already done 0,1,2,3,4 +CLOSELOOP: + MOV AH,CLOSE + INT int_command + INC BX + LOOP CLOSELOOP + RET + +SAVHAND: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH DS + PUSH BX ; Set stdin to sterr, stdout to stderr + PUSH AX + MOV AH,GET_CURRENT_PDB + INT int_command ; Get user's header + MOV DS,BX + MOV AX,WORD PTR DS:[PDB_JFN_Table] + MOV [HANDLE01],AX ; Save user's stdin, stdout + MOV AL,DS:[PDB_JFN_Table+2] + MOV AH,AL + MOV WORD PTR DS:[PDB_JFN_Table],AX ; Dup stderr + POP AX + POP BX + POP DS + RET + +ASSUME DS:RESGROUP +GETCOMDSK2: + CALL GETCOMDSK + JMP LODCOM1 ; Memory already allocated + +RESTHAND: + PUSH DS + PUSH BX ; Restore stdin, stdout to user + PUSH AX + MOV AH,GET_CURRENT_PDB + INT int_command ; Point to user's header + MOV AX,[HANDLE01] + MOV DS,BX +ASSUME DS:NOTHING + MOV WORD PTR DS:[PDB_JFN_Table],AX ; Stuff his old 0 and 1 + POP AX + POP BX + POP DS + RET +ASSUME DS:RESGROUP,SS:RESGROUP + +HOPELESS: + MOV DX,OFFSET RESGROUP:NOCOM + JMP FATALC + +GETCOMDSK: + MOV DX,OFFSET RESGROUP:NEEDCOM +GETCOMDSK3: + MOV AL,[COMDRV] + CALL REMCHECK + JNZ HOPELESS ;Non-removable media + CALL RPRINT + MOV DX,OFFSET RESGROUP:DRVMSG + CMP [COMDRV],0 + JNZ GETCOM1 + MOV DX,OFFSET RESGROUP:DEFMSG +GETCOM1: + CALL RPRINT + MOV DX,OFFSET RESGROUP:PROMPT + CALL RPRINT + CALL GetRawFlushedByte + RET + +; flush world and get raw input +GetRawFlushedByte: + MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR RAW_CON_INPUT + INT int_command ; Get char without testing or echo + MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0 + INT int_command + return + +LOADCOM: ; Load in transient + INC BP ; Flag command read + MOV DX,OFFSET RESGROUP:COMSPEC + MOV AX,OPEN SHL 8 + INT int_command ; Open COMMAND.COM + JNC READCOM + CMP AX,open_too_many_open_files + JNZ TRYDOOPEN + MOV DX,OFFSET RESGROUP:NOHANDMES + JMP FATALC ; Fatal, will never find a handle + +TRYDOOPEN: + CALL GETCOMDSK + JMP SHORT LOADCOM + +READCOM: + MOV BX,AX ; Handle + MOV DX,OFFSET RESGROUP:TRANSTART + XOR CX,CX ; Seek loc + MOV AX,LSEEK SHL 8 + INT int_command + JC WRONGCOM1 + MOV CX,OFFSET TRANGROUP:TRANSPACEEND - 100H + + IF IBM + ADD CX,15 + AND CX,0FFF0H + ADD CX,OFFSET EGROUP:ZEXECCODEEND + ENDIF + + PUSH DS + MOV DS,[TRNSEG] +ASSUME DS:NOTHING + MOV DX,100H + MOV AH,READ + INT int_command + POP DS +ASSUME DS:RESGROUP +WRONGCOM1: + PUSHF + PUSH AX + MOV AH,CLOSE + INT int_command ; Close COMMAND.COM + POP AX + POPF + JC WRONGCOM ; If error on READ + CMP AX,CX + JZ RET10 ; Size matched +WRONGCOM: + MOV DX,OFFSET RESGROUP:COMBAD + CALL GETCOMDSK3 + JMP SHORT LOADCOM ; Try again + +CHKSUM: ; Compute transient checksum + PUSH DS + MOV DS,[TRNSEG] + MOV SI,100H + MOV CX,OFFSET TRANGROUP:TRANDATAEND - 100H + +CHECK_SUM: + CLD + SHR CX,1 + XOR DX,DX +CHK: + LODSW + ADD DX,AX + LOOP CHK + POP DS +RET10: RET + +SETVECT: ; Set useful vectors + MOV DX,OFFSET RESGROUP:LODCOM + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 22H ; Set Terminate address + INT int_command + MOV DX,OFFSET RESGROUP:CONTC + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H ; Set Ctrl-C address + INT int_command + MOV DX,OFFSET RESGROUP:DSKERR + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H ; Set Hard Disk Error address + INT int_command + RET + +CODERES ENDS + +; This TAIL segment is used to produce a PARA aligned label in the resident +; group which is the location where the transient segments will be loaded +; initial. + +TAIL SEGMENT PUBLIC PARA + ORG 0 +TRANSTART LABEL WORD +TAIL ENDS + +; This TAIL segment is used to produce a PARA aligned label in the transient +; group which is the location where the exec segments will be loaded +; initial. + +TRANTAIL SEGMENT PUBLIC PARA + ORG 0 +EXECSTART LABEL WORD +TRANTAIL ENDS + +IF IBMVER + INCLUDE EXEC.ASM +ENDIF + + END PROGSTART + \ No newline at end of file diff --git a/COMSEG.ASM b/COMSEG.ASM new file mode 100644 index 0000000..221266a --- /dev/null +++ b/COMSEG.ASM @@ -0,0 +1,38 @@ +; The following are all of the segments used in the load order + +CODERES SEGMENT PUBLIC +CODERES ENDS + +DATARES SEGMENT PUBLIC +DATARES ENDS + +ENVIRONMENT SEGMENT PUBLIC +ENVIRONMENT ENDS + +INIT SEGMENT PUBLIC +INIT ENDS + +TAIL SEGMENT PUBLIC +TAIL ENDS + +TRANCODE SEGMENT PUBLIC +TRANCODE ENDS + +TRANDATA SEGMENT PUBLIC +TRANDATA ENDS + +TRANSPACE SEGMENT PUBLIC +TRANSPACE ENDS + +TRANTAIL SEGMENT PUBLIC +TRANTAIL ENDS + +ZEXEC_CODE SEGMENT PUBLIC +ZEXEC_CODE ENDS + +ZEXEC_DATA SEGMENT PUBLIC +ZEXEC_DATA ENDS + +RESGROUP GROUP CODERES,DATARES,ENVIRONMENT,INIT,TAIL +TRANGROUP GROUP TRANCODE,TRANDATA,TRANSPACE,TRANTAIL +EGROUP GROUP ZEXEC_CODE,ZEXEC_DATA diff --git a/COMSW.ASM b/COMSW.ASM new file mode 100644 index 0000000..830585f --- /dev/null +++ b/COMSW.ASM @@ -0,0 +1,13 @@ +; Use the following booleans to set assembly flags +FALSE EQU 0 +TRUE EQU NOT FALSE + +IBMVER EQU true ; Switch to build IBM version of Command +IBM EQU IBMVER +MSVER EQU false ; Switch to build MS-DOS version of Command + +HIGHMEM EQU FALSE ; Run resident part above transient (high memory) +KANJI EQU false ; Support for dual byte Microsoft KANJI standard +IBMJAPAN EQU FALSE ;MUST BE TRUE (along with IBM and KANJI) + + \ No newline at end of file diff --git a/COPY.ASM b/COPY.ASM new file mode 100644 index 0000000..0456a4f --- /dev/null +++ b/COPY.ASM @@ -0,0 +1,579 @@ +TITLE COMMAND COPY routines. + + INCLUDE COMSW.ASM + +.xlist +.xcref + INCLUDE DOSSYM.ASM + INCLUDE DEVSYM.ASM + INCLUDE COMSEG.ASM +.list +.cref + + INCLUDE COMEQU.ASM + +DATARES SEGMENT PUBLIC + EXTRN VERVAL:WORD +DATARES ENDS + +TRANDATA SEGMENT PUBLIC + EXTRN BADARGS:BYTE,BADCD:BYTE,BADSWT:BYTE,COPIED_PRE:BYTE + EXTRN COPIED_POST:BYTE + EXTRN INBDEV:BYTE,OVERWR:BYTE,FULDIR:BYTE,LOSTERR:BYTE + EXTRN NOSPACE:BYTE,DEVWMES:BYTE,NOTFND:BYTE +TRANDATA ENDS + +TRANSPACE SEGMENT PUBLIC + EXTRN MELCOPY:BYTE,SRCPT:WORD,MELSTART:WORD,SCANBUF:BYTE + EXTRN DESTFCB2:BYTE,SDIRBUF:BYTE,SRCTAIL:WORD,CFLAG:BYTE + EXTRN NXTADD:WORD,DESTCLOSED:BYTE,ALLSWITCH:WORD,ARGC:BYTE + EXTRN PLUS:BYTE,BINARY:BYTE,ASCII:BYTE,FILECNT:WORD + EXTRN WRITTEN:BYTE,CONCAT:BYTE,DESTBUF:BYTE,SRCBUF:BYTE + EXTRN SDIRBUF:BYTE,DIRBUF:BYTE,DESTFCB:BYTE,FRSTSRCH:BYTE + EXTRN FIRSTDEST:BYTE,DESTISDIR:BYTE,DESTSWITCH:WORD,STARTEL:WORD + EXTRN DESTTAIL:WORD,DESTSIZ:BYTE,DESTINFO:BYTE,INEXACT:BYTE + EXTRN CURDRV:BYTE,DESTVARS:BYTE,RESSEG:WORD,SRCSIZ:BYTE + EXTRN SRCINFO:BYTE,SRCVARS:BYTE,USERDIR1:BYTE,NOWRITE:BYTE + EXTRN RDEOF:BYTE,SRCHAND:WORD,CPDATE:WORD,CPTIME:WORD + EXTRN SRCISDEV:BYTE,BYTCNT:WORD,TPA:WORD,TERMREAD:BYTE + EXTRN DESTHAND:WORD,DESTISDEV:BYTE,DIRCHAR:BYTE +TRANSPACE ENDS + + +; ************************************************** +; COPY CODE +; + +TRANCODE SEGMENT PUBLIC BYTE + + EXTRN RESTUDIR:NEAR,CERROR:NEAR,SWITCH:NEAR,DISP32BITS:NEAR + EXTRN PRINT:NEAR,TCOMMAND:NEAR,ZPRINT:NEAR,ONESPC:NEAR + EXTRN RESTUDIR1:NEAR,FCB_TO_ASCZ:NEAR,CRLF2:NEAR,SAVUDIR1:NEAR + EXTRN SETREST1:NEAR,BADCDERR:NEAR,STRCOMP:NEAR,DELIM:NEAR + EXTRN UPCONV:NEAR,PATHCHRCMP:NEAR,SCANOFF:NEAR + + EXTRN CPARSE:NEAR + + EXTRN SEARCH:NEAR,SEARCHNEXT:NEAR,DOCOPY:NEAR,CLOSEDEST:NEAR + EXTRN FLSHFIL:NEAR,SETASC:NEAR,BUILDNAME:NEAR,COPERR:NEAR + + PUBLIC COPY,BUILDPATH,COMPNAME,ENDCOPY + + +ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP,SS:NOTHING + +DOMELCOPY: + cmp [MELCOPY],0FFH + jz CONTMEL + mov SI,[SRCPT] + mov [MELSTART],si + mov [MELCOPY],0FFH +CONTMEL: + xor BP,BP + mov si,[SRCPT] + mov bl,'+' +SCANSRC2: + mov di,OFFSET TRANGROUP:SCANBUF + call CPARSE + test bh,80H + jz NEXTMEL ; Go back to start + test bh,1 ; Switch ? + jnz SCANSRC2 ; Yes + call SOURCEPROC + call RESTUDIR1 + mov di,OFFSET TRANGROUP:DESTFCB2 + mov ax,PARSE_FILE_DESCRIPTOR SHL 8 + INT int_command + mov bx,OFFSET TRANGROUP:SDIRBUF + 1 + mov si,OFFSET TRANGROUP:DESTFCB2 + 1 + mov di,[SRCTAIL] + call BUILDNAME + jmp MELDO + + +NEXTMEL: + call CLOSEDEST + xor ax,ax + mov [CFLAG],al + mov [NXTADD],ax + mov [DESTCLOSED],al + mov si,[MELSTART] + mov [SRCPT],si + call SEARCHNEXT + jz SETNMELJ + jmp ENDCOPY2 +SETNMELJ: + jmp SETNMEL + +COPY: +; First order of buisness is to find out about the destination +ASSUME DS:TRANGROUP,ES:TRANGROUP + xor ax,ax + mov [ALLSWITCH],AX ; no switches + mov [ARGC],al ; no arguments + mov [PLUS],al ; no concatination + mov [BINARY],al ; Binary not specifically specified + mov [ASCII],al ; ASCII not specifically specified + mov [FILECNT],ax ; No files yet + mov [WRITTEN],al ; Nothing written yet + mov [CONCAT],al ; No concatination + mov [MELCOPY],al ; Not a Mel Hallerman copy + mov word ptr [SCANBUF],ax ; Init buffer + mov word ptr [DESTBUF],ax ; Init buffer + mov word ptr [SRCBUF],ax ; Init buffer + mov word ptr [SDIRBUF],ax ; Init buffer + mov word ptr [DIRBUF],ax ; Init buffer + mov word ptr [DESTFCB],ax ; Init buffer + dec ax + mov [FRSTSRCH],al ; First search call + mov [FIRSTDEST],al ; First time + mov [DESTISDIR],al ; Don't know about dest + mov si,81H + mov bl,'+' ; include '+' as a delimiter +DESTSCAN: + xor bp,bp ; no switches + mov di,offset trangroup:SCANBUF + call CPARSE + PUSHF ; save flags + test bh,80H ; A '+' argument? + jz NOPLUS ; no + mov [PLUS],1 ; yes +NOPLUS: + POPF ; get flags back + jc CHECKDONE ; Hit CR? + test bh,1 ; Switch? + jz TESTP2 ; no + or [DESTSWITCH],BP ; Yes, assume destination + or [ALLSWITCH],BP ; keep tabs on all switches + jmp short DESTSCAN + +TESTP2: + test bh,80H ; Plus? + jnz GOTPLUS ; Yes, not a separate arg + inc [ARGC] ; found a real arg +GOTPLUS: + push SI + mov ax,[STARTEL] + mov SI,offset trangroup:SCANBUF ; Adjust to copy + sub ax,SI + mov DI,offset trangroup:DESTBUF + add ax,DI + mov [DESTTAIL],AX + mov [DESTSIZ],cl ; Save its size + inc cx ; Include the NUL + rep movsb ; Save potential destination + mov [DESTINFO],bh ; Save info about it + mov [DESTSWITCH],0 ; reset switches + pop SI + jmp short DESTSCAN ; keep going + +CHECKDONE: + mov al,[PLUS] + mov [CONCAT],al ; PLUS -> Concatination + shl al,1 + shl al,1 + mov [INEXACT],al ; CONCAT -> inexact copy + mov dx,offset trangroup:BADARGS + mov al,[ARGC] + or al,al ; Good number of args? + jz CERROR4J ; no, not enough + cmp al,2 + jbe ACOUNTOK +CERROR4J: + jmp CERROR ; no, too many +ACOUNTOK: + mov bp,offset trangroup:DESTVARS + cmp al,1 + jnz GOT2ARGS + mov al,[CURDRV] ; Dest is default drive:*.* + add al,'A' + mov ah,':' + mov [bp.SIZ],2 + mov di,offset trangroup:DESTBUF + stosw + mov [DESTSWITCH],0 ; no switches on dest + mov [bp.INFO],2 ; Flag dest is ambig + mov [bp.ISDIR],0 ; Know destination specs file + call SETSTARS +GOT2ARGS: + cmp [bp.SIZ],2 + jnz NOTSHORTDEST + cmp [DESTBUF+1],':' + jnz NOTSHORTDEST ; Two char file name + or [bp.INFO],2 ; Know dest is d: + mov di,offset trangroup:DESTBUF + 2 + mov [bp.ISDIR],0 ; Know destination specs file + call SETSTARS +NOTSHORTDEST: + mov di,[bp.TTAIL] + cmp byte ptr [DI],0 + jnz CHKSWTCHES + mov dx,offset trangroup:BADCD + cmp byte ptr [DI-2],':' + jnz CERROR4J ; Trailing '/' error + mov [bp.ISDIR],2 ; Know destination is d:/ + or [bp.INFO],6 + call SETSTARS +CHKSWTCHES: + mov dx,offset trangroup:BADSWT + mov ax,[ALLSWITCH] + cmp ax,GOTSWITCH + jz CERROR4J ; Switch specified which is not known + +; Now know most of the information needed about the destination + + TEST AX,VSWITCH ; Verify requested? + JZ NOVERIF ; No + MOV AH,GET_VERIFY_ON_WRITE + INT int_command ; Get current setting + PUSH DS + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + XOR AH,AH + MOV [VERVAL],AX ; Save current setting + POP DS +ASSUME DS:TRANGROUP + MOV AX,(SET_VERIFY_ON_WRITE SHL 8) OR 1 ; Set verify + INT int_command +NOVERIF: + xor bp,bp ; no switches + mov si,81H + mov bl,'+' ; include '+' as a delimiter +SCANFSRC: + mov di,offset trangroup:SCANBUF + call CPARSE ; Parse first source name + test bh,1 ; Switch? + jnz SCANFSRC ; Yes, try again + or [DESTSWITCH],bp ; Include copy wide switches on DEST + test bp,BSWITCH + jnz NOSETCASC ; Binary explicit + cmp [CONCAT],0 + JZ NOSETCASC ; Not Concat + mov [ASCII],ASWITCH ; Concat -> ASCII copy if no B switch +NOSETCASC: + push SI + mov ax,[STARTEL] + mov SI,offset trangroup:SCANBUF ; Adjust to copy + sub ax,SI + mov DI,offset trangroup:SRCBUF + add ax,DI + mov [SRCTAIL],AX + mov [SRCSIZ],cl ; Save its size + inc cx ; Include the NUL + rep movsb ; Save this source + mov [SRCINFO],bh ; Save info about it + pop SI + mov ax,bp ; Switches so far + call SETASC ; Set A,B switches accordingly + call SWITCH ; Get any more switches on this arg + call SETASC ; Set + call FRSTSRC + jmp FIRSTENT + +ENDCOPY: + CALL CLOSEDEST +ENDCOPY2: + MOV DX,OFFSET TRANGROUP:COPIED_PRE + CALL PRINT + MOV SI,[FILECNT] + XOR DI,DI + CALL DISP32BITS + MOV DX,OFFSET TRANGROUP:COPIED_POST + CALL PRINT + JMP TCOMMAND ; Stack could be messed up + +SRCNONEXIST: + cmp [CONCAT],0 + jnz NEXTSRC ; If in concat mode, ignore error + mov dx,offset trangroup:SRCBUF + call zprint + CALL ONESPC + mov dx,offset trangroup:NOTFND + jmp COPERR + +SOURCEPROC: + push SI + mov ax,[STARTEL] + mov SI,offset trangroup:SCANBUF ; Adjust to copy + sub ax,SI + mov DI,offset trangroup:SRCBUF + add ax,DI + mov [SRCTAIL],AX + mov [SRCSIZ],cl ; Save its size + inc cx ; Include the NUL + rep movsb ; Save this sorce + mov [SRCINFO],bh ; Save info about it + pop SI + mov ax,bp ; Switches so far + call SETASC ; Set A,B switches accordingly + call SWITCH ; Get any more switches on this arg + call SETASC ; Set + cmp [CONCAT],0 + jnz LEAVECFLAG ; Leave CFLAG if concatination +FRSTSRC: + xor ax,ax + mov [CFLAG],al ; Flag destination not created + mov [NXTADD],ax ; Zero out buffer + mov [DESTCLOSED],al ; Not created -> not closed +LEAVECFLAG: + mov [SRCPT],SI ; remember where we are + mov di,offset trangroup:USERDIR1 + mov bp,offset trangroup:SRCVARS + call BUILDPATH ; Figure out everything about the source + mov si,[SRCTAIL] ; Create the search FCB + return + +NEXTSRC: + cmp [PLUS],0 + jnz MORECP +ENDCOPYJ2: + jmp ENDCOPY ; Done +MORECP: + xor bp,bp ; no switches + mov si,[SRCPT] + mov bl,'+' ; include '+' as a delimiter +SCANSRC: + mov di,offset trangroup:SCANBUF + call CPARSE ; Parse first source name + JC EndCopyJ2 ; if error, then end (trailing + case) + test bh,80H + jz ENDCOPYJ2 ; If no '+' we're done + test bh,1 ; Switch? + jnz SCANSRC ; Yes, try again + call SOURCEPROC +FIRSTENT: + mov di,FCB + mov ax,PARSE_FILE_DESCRIPTOR SHL 8 + INT int_command + mov ax,word ptr [SRCBUF] ; Get drive + cmp ah,':' + jz DRVSPEC1 + mov al,'@' +DRVSPEC1: + sub al,'@' + mov ds:[FCB],al + mov ah,DIR_SEARCH_FIRST + call SEARCH + pushf ; Save result of search + call RESTUDIR1 ; Restore users dir + popf + jz NEXTAMBIG0 + jmp SRCNONEXIST ; Failed +NEXTAMBIG0: + xor al,al + xchg al,[FRSTSRCH] + or al,al + jz NEXTAMBIG +SETNMEL: + mov cx,12 + mov di,OFFSET TRANGROUP:SDIRBUF + mov si,OFFSET TRANGROUP:DIRBUF + rep movsb ; Save very first source name +NEXTAMBIG: + xor al,al + mov [NOWRITE],al ; Turn off NOWRITE + mov di,[SRCTAIL] + mov si,offset trangroup:DIRBUF + 1 + call FCB_TO_ASCZ ; SRCBUF has complete name +MELDO: + cmp [CONCAT],0 + jnz SHOWCPNAM ; Show name if concat + test [SRCINFO],2 ; Show name if multi + jz DOREAD +SHOWCPNAM: + mov dx,offset trangroup:SRCBUF + call ZPRINT + call CRLF2 +DOREAD: + call DOCOPY + cmp [CONCAT],0 + jnz NODCLOSE ; If concat, do not close + call CLOSEDEST ; else close current destination + jc NODCLOSE ; Concat flag got set, close didn't really happen + mov [CFLAG],0 ; Flag destination not created +NODCLOSE: + cmp [CONCAT],0 ; Check CONCAT again + jz NOFLUSH + CALL FLSHFIL ; Flush output between source files on CONCAT + ; so LOSTERR stuff works correctly + TEST [MELCOPY],0FFH + jz NOFLUSH + jmp DOMELCOPY + +NOFLUSH: + call SEARCHNEXT ; Try next match + jnz NEXTSRCJ ; Finished with this source spec + mov [DESTCLOSED],0 ; Not created or concat -> not closed + jmp NEXTAMBIG ; Do next ambig + +NEXTSRCJ: + jmp NEXTSRC + + + +BUILDPATH: + test [BP.INFO],2 + jnz NOTPFILE ; If ambig don't bother with open + mov dx,bp + add dx,BUF ; Set DX to spec + mov ax,OPEN SHL 8 + INT int_command + jc NOTPFILE + mov bx,ax ; Is pure file + mov ax,IOCTL SHL 8 + INT int_command + mov ah,CLOSE + INT int_command + test dl,devid_ISDEV + jnz ISADEV ; If device, done + test [BP.INFO],4 + jz ISSIMPFILE ; If no path seps, done +NOTPFILE: + mov dx,word ptr [BP.BUF] + cmp dh,':' + jz DRVSPEC5 + mov dl,'@' +DRVSPEC5: + sub dl,'@' ; A = 1 + call SAVUDIR1 + mov dx,bp + add dx,BUF ; Set DX for upcomming CHDIRs + mov bh,[BP.INFO] + and bh,6 + cmp bh,6 ; Ambig and path ? + jnz CHECKAMB ; jmp if no + mov si,[BP.TTAIL] + cmp byte ptr [si-2],':' + jnz KNOWNOTSPEC + mov [BP.ISDIR],2 ; Know is d:/file + jmp short DOPCDJ + +KNOWNOTSPEC: + mov [BP.ISDIR],1 ; Know is path/file + dec si ; Point to the / +DOPCDJ: + jmp short DOPCD + +CHECKAMB: + cmp bh,2 + jnz CHECKCD +ISSIMPFILE: +ISADEV: + mov [BP.ISDIR],0 ; Know is file since ambig but no path + return + +CHECKCD: + call SETREST1 + mov ah,CHDIR + INT int_command + jc NOTPDIR + mov di,dx + xor ax,ax + mov cx,ax + dec cx + repne scasb + dec di + mov al,[DIRCHAR] + mov [bp.ISDIR],2 ; assume d:/file + cmp al,[di-1] + jz GOTSRCSLSH + stosb + mov [bp.ISDIR],1 ; know path/file +GOTSRCSLSH: + or [bp.INFO],6 + call SETSTARS + return + + +NOTPDIR: + mov [bp.ISDIR],0 ; assume pure file + mov bh,[bp.INFO] + test bh,4 + retz ; Know pure file, no path seps + mov [bp.ISDIR],2 ; assume d:/file + mov si,[bp.TTAIL] + cmp byte ptr [si],0 + jz BADCDERRJ2 ; Trailing '/' + cmp byte ptr [si],'.' + jz BADCDERRJ2 ; If . or .. pure cd should have worked + cmp byte ptr [si-2],':' + jz DOPCD ; Know d:/file + mov [bp.ISDIR],1 ; Know path/file + dec si ; Point at last '/' +DOPCD: + xor bl,bl + xchg bl,[SI] ; Stick in a NUL + call SETREST1 + mov ah,CHDIR + INT int_command + xchg bl,[SI] + retnc +BADCDERRJ2: + JMP BADCDERR + +SETSTARS: + mov [bp.TTAIL],DI + add [bp.SIZ],12 + mov ax,('.' SHL 8) OR '?' + mov cx,8 + rep stosb + xchg al,ah + stosb + xchg al,ah + mov cl,3 + rep stosb + xor al,al + stosb + return + + +COMPNAME: + PUSH CX + PUSH AX + MOV si,offset trangroup:SRCBUF + MOV di,offset trangroup:DESTBUF + MOV CL,[CURDRV] + MOV CH,CL + CMP BYTE PTR [SI+1],':' + JNZ NOSRCDRV + LODSW + SUB AL,'A' + MOV CL,AL +NOSRCDRV: + CMP BYTE PTR [DI+1],':' + JNZ NODSTDRV + MOV AL,[DI] + INC DI + INC DI + SUB AL,'A' + MOV CH,AL +NODSTDRV: + CMP CH,CL + jnz RET81P + call STRCOMP + jz RET81P + mov ax,[si-1] + mov cx,[di-1] + push ax + and al,cl + pop ax + jnz RET81P ; Niether of the mismatch chars was a NUL +; Know one of the mismatch chars is a NUL +; Check for ".NUL" compared with NUL + cmp al,'.' + jnz CHECKCL + or ah,ah + jmp short RET81P ; If NUL return match, else no match +CHECKCL: + cmp cl,'.' + jnz RET81P ; Mismatch + or ch,ch ; If NUL return match, else no match +RET81P: + POP AX + POP CX + return + +TRANCODE ENDS + + END + \ No newline at end of file diff --git a/COPYPROC.ASM b/COPYPROC.ASM new file mode 100644 index 0000000..f6e3bb1 --- /dev/null +++ b/COPYPROC.ASM @@ -0,0 +1,526 @@ +TITLE COPYRPOC ;Procedures called by COPY + + INCLUDE COMSW.ASM + +.xlist +.xcref + INCLUDE DOSSYM.ASM + INCLUDE DEVSYM.ASM + INCLUDE COMSEG.ASM +.list +.cref + + INCLUDE COMEQU.ASM + +DATARES SEGMENT PUBLIC +DATARES ENDS + +TRANDATA SEGMENT PUBLIC + + EXTRN OVERWR:BYTE,FULDIR:BYTE,LOSTERR:BYTE + EXTRN DEVWMES:BYTE,INBDEV:BYTE,NOSPACE:BYTE + +TRANDATA ENDS + +TRANSPACE SEGMENT PUBLIC + + EXTRN CFLAG:BYTE,NXTADD:WORD,DESTCLOSED:BYTE + EXTRN PLUS:BYTE,BINARY:BYTE,ASCII:BYTE,FILECNT:WORD + EXTRN WRITTEN:BYTE,CONCAT:BYTE,DESTBUF:BYTE,SRCBUF:BYTE + EXTRN SDIRBUF:BYTE,DIRBUF:BYTE,DESTFCB:BYTE,MELCOPY:BYTE + EXTRN FIRSTDEST:BYTE,DESTISDIR:BYTE,DESTSWITCH:WORD + EXTRN DESTTAIL:WORD,DESTINFO:BYTE,INEXACT:BYTE + EXTRN DESTVARS:BYTE,SRCINFO:BYTE,RDEOF:BYTE + EXTRN USERDIR1:BYTE,NOWRITE:BYTE + EXTRN SRCHAND:WORD,CPDATE:WORD,CPTIME:WORD + EXTRN SRCISDEV:BYTE,BYTCNT:WORD,TPA:WORD,TERMREAD:BYTE + EXTRN DESTHAND:WORD,DESTISDEV:BYTE,DIRCHAR:BYTE + +TRANSPACE ENDS + +TRANCODE SEGMENT PUBLIC BYTE + + PUBLIC SEARCH,SEARCHNEXT,DOCOPY,CLOSEDEST,FLSHFIL,SETASC + PUBLIC BUILDNAME,COPERR + + EXTRN PRINT:NEAR,BUILDPATH:NEAR,RESTUDIR1:NEAR + EXTRN COMPNAME:NEAR,ENDCOPY:NEAR + +ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP,SS:NOTHING + + +SEARCHNEXT: + MOV AH,DIR_SEARCH_NEXT + TEST [SRCINFO],2 + JNZ SEARCH ; Do serach-next if ambig + OR AH,AH ; Reset zero flag + return +SEARCH: + PUSH AX + MOV AH,SET_DMA + MOV DX,OFFSET TRANGROUP:DIRBUF + INT int_command ; Put result of search in DIRBUF + POP AX ; Restore search first/next command + MOV DX,FCB + INT int_command ; Do the search + OR AL,AL + return + +DOCOPY: + mov [RDEOF],0 ; No EOF yet + mov dx,offset trangroup:SRCBUF + mov ax,OPEN SHL 8 + INT int_command + retc ; If open fails, ignore + mov bx,ax ; Save handle + mov [SRCHAND],bx ; Save handle + mov ax,(FILE_TIMES SHL 8) + INT int_command + mov [CPDATE],dx ; Save DATE + mov [CPTIME],cx ; Save TIME + mov ax,(IOCTL SHL 8) + INT int_command ; Get device stuff + and dl,devid_ISDEV + mov [SRCISDEV],dl ; Set source info + jz COPYLP ; Source not a device + cmp [BINARY],0 + jz COPYLP ; ASCII device OK + mov dx,offset trangroup:INBDEV ; Cannot do binary input + jmp COPERR + +COPYLP: + mov bx,[SRCHAND] + mov cx,[BYTCNT] + mov dx,[NXTADD] + sub cx,dx ; Compute available space + jnz GOTROOM + call FLSHFIL + CMP [TERMREAD],0 + JNZ CLOSESRC ; Give up + mov cx,[BYTCNT] +GOTROOM: + push ds + mov ds,[TPA] +ASSUME DS:NOTHING + mov ah,READ + INT int_command + pop ds +ASSUME DS:TRANGROUP + jc CLOSESRC ; Give up if error + mov cx,ax ; Get count + jcxz CLOSESRC ; No more to read + cmp [SRCISDEV],0 + jnz NOTESTA ; Is a device, ASCII mode + cmp [ASCII],0 + jz BINREAD +NOTESTA: + MOV DX,CX + MOV DI,[NXTADD] + MOV AL,1AH + PUSH ES + MOV ES,[TPA] + REPNE SCASB ; Scan for EOF + POP ES + JNZ USEALL + INC [RDEOF] + INC CX +USEALL: + SUB DX,CX + MOV CX,DX +BINREAD: + ADD CX,[NXTADD] + MOV [NXTADD],CX + CMP CX,[BYTCNT] ; Is buffer full? + JB TESTDEV ; If not, we may have found EOF + CALL FLSHFIL + CMP [TERMREAD],0 + JNZ CLOSESRC ; Give up + JMP SHORT COPYLP + +TESTDEV: + cmp [SRCISDEV],0 + JZ CLOSESRC ; If file then EOF + CMP [RDEOF],0 + JZ COPYLP ; On device, go till ^Z +CLOSESRC: + mov bx,[SRCHAND] + mov ah,CLOSE + INT int_command + return + +CLOSEDEST: + cmp [DESTCLOSED],0 + retnz ; Don't double close + MOV AL,BYTE PTR [DESTSWITCH] + CALL SETASC ; Check for B or A switch on destination + JZ BINCLOS + MOV BX,[NXTADD] + CMP BX,[BYTCNT] ; Is memory full? + JNZ PUTZ + call TRYFLUSH ; Make room for one lousy byte + jz NOCONC +CONCHNG: ; Concat flag changed on us + stc + return +NOCONC: + XOR BX,BX +PUTZ: + PUSH DS + MOV DS,[TPA] + MOV WORD PTR [BX],1AH ; Add End-of-file mark (Ctrl-Z) + POP DS + INC [NXTADD] + MOV [NOWRITE],0 ; Make sure our ^Z gets written + MOV AL,[WRITTEN] + XOR AH,AH + ADD AX,[NXTADD] + JC BINCLOS ; > 1 + CMP AX,1 + JZ FORGETIT ; WRITTEN = 0 NXTADD = 1 (the ^Z) +BINCLOS: + call TRYFLUSH + jnz CONCHNG + cmp [WRITTEN],0 + jz FORGETIT ; Never wrote nothin + MOV BX,[DESTHAND] + MOV CX,[CPTIME] + MOV DX,[CPDATE] + CMP [INEXACT],0 ; Copy not exact? + JZ DODCLOSE ; If no, copy date & time + MOV AH,GET_TIME + INT int_command + SHL CL,1 + SHL CL,1 ; Left justify min in CL + SHL CX,1 + SHL CX,1 + SHL CX,1 ; hours to high 5 bits, min to 5-10 + SHR DH,1 ; Divide seconds by 2 (now 5 bits) + OR CL,DH ; And stick into low 5 bits of CX + PUSH CX ; Save packed time + MOV AH,GET_DATE + INT int_command + SUB CX,1980 + XCHG CH,CL + SHL CX,1 ; Year to high 7 bits + SHL DH,1 ; Month to high 3 bits + SHL DH,1 + SHL DH,1 + SHL DH,1 + SHL DH,1 ; Most sig bit of month in carry + ADC CH,0 ; Put that bit next to year + OR DL,DH ; Or low three of month into day + MOV DH,CH ; Get year and high bit of month + POP CX ; Get time back +DODCLOSE: + MOV AX,(FILE_TIMES SHL 8) OR 1 + INT int_command ; Set date and time + MOV AH,CLOSE + INT int_command + INC [FILECNT] + INC [DESTCLOSED] +RET50: + CLC + return + +FORGETIT: + MOV BX,[DESTHAND] + CALL DODCLOSE ; Close the dest + MOV DX,OFFSET TRANGROUP:DESTBUF + MOV AH,UNLINK + INT int_command ; And delete it + MOV [FILECNT],0 ; No files transferred + JMP RET50 + +TRYFLUSH: + mov al,[CONCAT] + push ax + call FLSHFIL + pop ax + cmp al,[CONCAT] + return + +FLSHFIL: +; Write out any data remaining in memory. +; Inputs: +; [NXTADD] = No. of bytes to write +; [CFLAG] <>0 if file has been created +; Outputs: +; [NXTADD] = 0 + + MOV [TERMREAD],0 + cmp [CFLAG],0 + JZ NOTEXISTS + JMP EXISTS +NOTEXISTS: + call BUILDDEST ; Find out all about the destination + CALL COMPNAME ; Source and dest. the same? + JNZ PROCDEST ; If not, go ahead + CMP [SRCISDEV],0 + JNZ PROCDEST ; Same name on device OK + CMP [CONCAT],0 ; Concatenation? + MOV DX,OFFSET TRANGROUP:OVERWR + JZ COPERRJ ; If not, overwrite error + MOV [NOWRITE],1 ; Flag not writting (just seeking) +PROCDEST: + mov ax,(OPEN SHL 8) OR 1 + CMP [NOWRITE],0 + JNZ DODESTOPEN ; Don't actually create if NOWRITE set + mov ah,CREAT + xor cx,cx +DODESTOPEN: + mov dx,offset trangroup:DESTBUF + INT int_command + MOV DX,OFFSET TRANGROUP:FULDIR + JC COPERRJ + mov [DESTHAND],ax ; Save handle + mov [CFLAG],1 ; Destination now exists + mov bx,ax + mov ax,(IOCTL SHL 8) + INT int_command ; Get device stuff + mov [DESTISDEV],dl ; Set dest info + test dl,devid_ISDEV + jz EXISTS ; Dest not a device + mov al,BYTE PTR [DESTSWITCH] + AND AL,ASWITCH+BSWITCH + JNZ TESTBOTH + MOV AL,[ASCII] ; Neither set, use current setting + OR AL,[BINARY] + JZ EXSETA ; Neither set, default to ASCII +TESTBOTH: + JPE EXISTS ; Both are set, ignore + test AL,BSWITCH + jz EXISTS ; Leave in cooked mode + mov ax,(IOCTL SHL 8) OR 1 + xor dh,dh + or dl,devid_RAW + mov [DESTISDEV],dl ; New value + INT int_command ; Set device to RAW mode + jmp short EXISTS + +COPERRJ: + jmp SHORT COPERR + +EXSETA: +; What we read in may have been in binary mode, flag zapped write OK + mov [ASCII],ASWITCH ; Set ASCII mode + or [INEXACT],ASWITCH ; ASCII -> INEXACT +EXISTS: + cmp [NOWRITE],0 + jnz NOCHECKING ; If nowrite don't bother with name check + CALL COMPNAME ; Source and dest. the same? + JNZ NOCHECKING ; If not, go ahead + CMP [SRCISDEV],0 + JNZ NOCHECKING ; Same name on device OK +; At this point we know in append (would have gotten overwrite error on first +; destination create otherwise), and user trying to specify destination which +; has been scribbled already (if dest had been named first, NOWRITE would +; be set). + MOV DX,OFFSET TRANGROUP:LOSTERR ; Tell him he's not going to get it + CALL PRINT + MOV [NXTADD],0 ; Set return + INC [TERMREAD] ; Tell Read to give up +RET60: + return + +NOCHECKING: + mov bx,[DESTHAND] ; Get handle + XOR CX,CX + XCHG CX,[NXTADD] + JCXZ RET60 ; If Nothing to write, forget it + INC [WRITTEN] ; Flag that we wrote something + CMP [NOWRITE],0 ; If NOWRITE set, just seek CX bytes + JNZ SEEKEND + XOR DX,DX + PUSH DS + MOV DS,[TPA] +ASSUME DS:NOTHING + MOV AH,WRITE + INT int_command + POP DS +ASSUME DS:TRANGROUP + MOV DX,OFFSET TRANGROUP:NOSPACE + JC COPERR ; Failure + sub cx,ax + retz ; Wrote all supposed to + test [DESTISDEV],devid_ISDEV + jz COPERR ; Is a file, error + test [DESTISDEV],devid_RAW + jnz DEVWRTERR ; Is a raw device, error + cmp [INEXACT],0 + retnz ; INEXACT so OK + dec cx + retz ; Wrote one byte less (the ^Z) +DEVWRTERR: + MOV DX,OFFSET TRANGROUP:DEVWMES +COPERR: + CALL PRINT + inc [DESTCLOSED] + cmp [CFLAG],0 + jz ENDCOPYJ ; Never actually got it open + MOV bx,[DESTHAND] + MOV AH,CLOSE ; Close the file + INT int_command + MOV DX,OFFSET TRANGROUP:DESTBUF + MOV AH,UNLINK + INT int_command ; And delete it + MOV [CFLAG],0 +ENDCOPYJ: + JMP ENDCOPY + + +SEEKEND: + xor dx,dx ; Zero high half of offset + xchg dx,cx ; cx:dx is seek location + mov ax,(LSEEK SHL 8) OR 1 + INT int_command ; Seek ahead in the file + cmp [RDEOF],0 + retz +; If a ^Z has been read we must set the file size to the current +; file pointer location + MOV AH,WRITE + INT int_command ; CX is zero, truncates file + return + +SETASC: +; Given switch vector in AX, +; Set ASCII switch if A is set +; Clear ASCII switch if B is set +; BINARY set if B specified +; Leave ASCII unchanged if neither or both are set +; Also sets INEXACT if ASCII is ever set. AL = ASCII on exit, flags set + AND AL,ASWITCH+BSWITCH + JPE LOADSW ; PE means both or neither are set + PUSH AX + AND AL,BSWITCH + MOV [BINARY],AL + POP AX + AND AL,ASWITCH + MOV [ASCII],AL + OR [INEXACT],AL +LOADSW: + MOV AL,[ASCII] + OR AL,AL + return + +BUILDDEST: + cmp [DESTISDIR],-1 + jnz KNOWABOUTDEST ; Already done the figuring + MOV DI,OFFSET TRANGROUP:USERDIR1 + mov bp,offset trangroup:DESTVARS + call BUILDPATH + call RESTUDIR1 + +; Now know all about the destination + +KNOWABOUTDEST: + xor al,al + xchg al,[FIRSTDEST] + or al,al + jnz FIRSTDST + jmp NOTFIRSTDEST +FIRSTDST: + mov si,[DESTTAIL] ; Create an FCB of the original DEST + mov di,offset trangroup:DESTFCB + mov ax,PARSE_FILE_DESCRIPTOR SHL 8 + INT int_command + mov ax,word ptr [DESTBUF] ; Get drive + cmp ah,':' + jz DRVSPEC4 + mov al,'@' +DRVSPEC4: + MOV CL,[ASCII] ; Save current ASCII setting + sub al,'@' + mov [DESTFCB],al + mov al,[DESTINFO] + mov ah,[SRCINFO] + and ax,0202H + or al,al + jz NOTMELCOPY + cmp al,ah + jnz NOTMELCOPY + cmp [PLUS],0 + jz NOTMELCOPY + inc [MELCOPY] ; ambig source, ambig dest, and pluses + xor al,al + jmp short SETCONC + +NOTMELCOPY: + xor al,2 ; al=2 if unambig dest, =0 if ambig dest + and al,ah + shr al,1 ; al=1 if unambig dest AND ambig sorce + ; Implies concatination +SETCONC: + or al,[PLUS] ; al=1 if concat + mov [CONCAT],al + shl al,1 + shl al,1 + mov [INEXACT],al ; Concat -> inexact copy + cmp [BINARY],0 + jnz NOTFIRSTDEST ; Binary explicitly given, all OK + mov [ASCII],al ; Concat -> ASCII + or cl,cl + jnz NOTFIRSTDEST ; ASCII flag set before, DATA read correctly + or al,al + JZ NOTFIRSTDEST ; ASCII flag did not change states +; At this point there may already be binary read data in the read buffer. +; We need to find the first ^Z (if there is one) and trim the amount +; of data in the buffer correctly. + MOV CX,[NXTADD] + JCXZ NOTFIRSTDEST ; No data, everything OK + MOV AL,1AH + PUSH ES + XOR DI,DI + MOV ES,[TPA] + REPNE SCASB ; Scan for EOF + POP ES + JNZ NOTFIRSTDEST ; No ^Z in buffer, everything OK + DEC DI ; Point at ^Z + MOV [NXTADD],DI ; New buffer +NOTFIRSTDEST: + mov bx,offset trangroup:DIRBUF+1 ; Source of replacement chars + cmp [CONCAT],0 + jz GOTCHRSRC ; Not a concat + mov bx,offset trangroup:SDIRBUF+1 ; Source of replacement chars +GOTCHRSRC: + mov si,offset trangroup:DESTFCB+1 ; Original dest name + mov di,[DESTTAIL] ; Where to put result + +BUILDNAME: + mov cx,8 +BUILDMAIN: + lodsb + cmp al,"?" + jnz NOTAMBIG + mov al,byte ptr [BX] +NOTAMBIG: + cmp al,' ' + jz NOSTORE + stosb +NOSTORE: + inc bx + loop BUILDMAIN + mov cl,3 + cmp byte ptr [SI],' ' + jz ENDDEST ; No extension + mov al,'.' + stosb +BUILDEXT: + lodsb + cmp al,"?" + jnz NOTAMBIGE + mov al,byte ptr [BX] +NOTAMBIGE: + cmp al,' ' + jz NOSTOREE + stosb +NOSTOREE: + inc bx + loop BUILDEXT +ENDDEST: + xor al,al + stosb ; NUL terminate + return + +TRANCODE ENDS + END + \ No newline at end of file diff --git a/CPARSE.ASM b/CPARSE.ASM new file mode 100644 index 0000000..967efaa --- /dev/null +++ b/CPARSE.ASM @@ -0,0 +1,291 @@ +TITLE CPARSE + + INCLUDE COMSW.ASM + +.xlist +.xcref + INCLUDE DOSSYM.ASM + INCLUDE DEVSYM.ASM + INCLUDE COMSEG.ASM +.list +.cref + + INCLUDE COMEQU.ASM + +DATARES SEGMENT PUBLIC +DATARES ENDS + +TRANDATA SEGMENT PUBLIC + EXTRN BADCPMES:BYTE +TRANDATA ENDS + +TRANSPACE SEGMENT PUBLIC + EXTRN CURDRV:BYTE,ELPOS:BYTE,STARTEL:WORD + EXTRN SKPDEL:BYTE,SWITCHAR:BYTE,ELCNT:BYTE + +TRANSPACE ENDS + +TRANCODE SEGMENT PUBLIC BYTE + +ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP + + EXTRN DELIM:NEAR,UPCONV:NEAR,PATHCHRCMP:NEAR + EXTRN SWLIST:BYTE,BADCDERR:NEAR,SCANOFF:NEAR,CERROR:NEAR + + if KANJI + EXTRN TESTKANJ:NEAR + endif + +SWCOUNT EQU 5 + + PUBLIC CPARSE + +CPARSE: + +;-----------------------------------------------------------------------; +; ENTRY: ; +; DS:SI Points input buffer ; +; ES:DI Points to the token buffer ; +; BL Special delimiter for this call ; +; Always checked last ; +; set it to space if there is no special delimiter ; +; EXIT: ; +; DS:SI Points to next char in the input buffer ; +; ES:DI Points to the token buffer ; +; [STARTEL] Points to start of last element of path in token ; +; points to a NUL for no element strings 'd:' 'd:/' ; +; CX Character count ; +; BH Condition Code ; +; Bit 1H of BH set if switch character ; +; Token buffer contains char after ; +; switch character ; +; BP has switch bits set (ORing only) ; +; Bit 2H of BH set if ? or * in token ; +; if * found element ? filled ; +; Bit 4H of BH set if path sep in token ; +; Bit 80H of BH set if the special delimiter ; +; was skipped at the start of this token ; +; Token buffer always starts d: for non switch tokens ; +; CARRY SET ; +; if CR on input ; +; token buffer not altered ; +; ; +; DOES NOT RETURN ON BAD PATH ERROR ; +; MODIFIES: ; +; CX, SI, AX, BH, DX and the Carry Flag ; ; +; ; +; -----------------------------------------------------------------------; + + xor ax,ax + mov [STARTEL],DI ; No path element (Is DI correct?) + mov [ELPOS],al ; Start in 8 char prefix + mov [SKPDEL],al ; No skip delimiter yet + mov bh,al ; Init nothing + pushf ; save flags + push di ; save the token buffer addrss + xor cx,cx ; no chars in token buffer +moredelim: + LODSB + CALL DELIM + JNZ SCANCDONE + CMP AL,' ' + JZ moredelim + CMP AL,9 + JZ moredelim + xchg al,[SKPDEL] + or al,al + jz moredelim ; One non space/tab delimiter allowed + JMP x_done ; Nul argument + +SCANCDONE: + + IF NOT KANJI + call UPCONV + ENDIF + + cmp al,bl ; Special delimiter? + jnz nospec + or bh,80H + jmp short moredelim + +nospec: + cmp al,0DH ; a CR? + jne ncperror + jmp cperror +ncperror: + cmp al,[SWITCHAR] ; is the char the switch char? + jne na_switch ; yes, process... + jmp a_switch +na_switch: + cmp byte ptr [si],':' + jne anum_chard ; Drive not specified + + IF KANJI + call UPCONV + ENDIF + + call move_char + lodsb ; Get the ':' + call move_char + mov [STARTEL],di + mov [ELCNT],0 + jmp anum_test + +anum_chard: + mov [STARTEL],di + mov [ELCNT],0 ; Store of this char sets it to one + call PATHCHRCMP ; Starts with a pathchar? + jnz anum_char ; no + push ax + mov al,[CURDRV] ; Insert drive spec + add al,'A' + call move_char + mov al,':' + call move_char + pop ax + mov [STARTEL],di + mov [ELCNT],0 + +anum_char: + + IF KANJI + call TESTKANJ + jz TESTDOT + call move_char + lodsb + jmp short notspecial + +TESTDOT: + ENDIF + + cmp al,'.' + jnz testquest + inc [ELPOS] ; flag in extension + mov [ELCNT],0FFH ; Store of the '.' resets it to 0 +testquest: + cmp al,'?' + jnz testsplat + or bh,2 +testsplat: + cmp al,'*' + jnz testpath + or bh,2 + mov ah,7 + cmp [ELPOS],0 + jz gotelcnt + mov ah,2 +gotelcnt: + mov al,'?' + sub ah,[ELCNT] + jc badperr2 + xchg ah,cl + jcxz testpathx +qmove: + xchg ah,cl + call move_char + xchg ah,cl + loop qmove +testpathx: + xchg ah,cl +testpath: + call PATHCHRCMP + jnz notspecial + or bh,4 + test bh,2 ; If just hit a '/', cannot have ? or * yet + jnz badperr + mov [STARTEL],di ; New element + INC [STARTEL] ; Point to char after / + mov [ELCNT],0FFH ; Store of '/' sets it to 0 + mov [ELPOS],0 +notspecial: + call move_char ; just an alphanum string +anum_test: + lodsb + + IF NOT KANJI + call UPCONV + ENDIF + + call DELIM + je x_done + cmp al,0DH + je x_done + cmp al,[SWITCHAR] + je x_done + cmp al,bl + je x_done + cmp al,':' ; ':' allowed as trailer because + ; of devices + IF KANJI + je FOO15 + jmp anum_char +FOO15: + ELSE + jne anum_char + ENDIF + + mov byte ptr [si-1],' ' ; Change the trailing ':' to a space + jmp short x_done + +badperr2: + mov dx,offset trangroup:BADCPMES + jmp CERROR + +badperr: + jmp BADCDERR + +cperror: + dec si ; adjust the pointer + pop di ; retrive token buffer address + popf ; restore flags + stc ; set the carry bit + return + +x_done: + dec si ; adjust for next round + jmp short out_token + +a_switch: + OR BH,1 ; Indicate switch + OR BP,GOTSWITCH + CALL SCANOFF + INC SI + cmp al,0DH + je cperror + call move_char ; store the character + CALL UPCONV + PUSH ES + PUSH DI + PUSH CX + PUSH CS + POP ES +ASSUME ES:TRANGROUP + MOV DI,OFFSET TRANGROUP:SWLIST + MOV CX,SWCOUNT + REPNE SCASB + JNZ out_tokenp + MOV AX,1 + SHL AX,CL + OR BP,AX +out_tokenp: + POP CX + POP DI + POP ES +ASSUME ES:NOTHING +out_token: + mov al,0 + stosb ; null at the end + pop di ; restore token buffer pointer + popf + clc ; clear carry flag + return + +move_char: + stosb ; store char in token buffer + inc cx ; increment char count + inc [ELCNT] ; increment element count for * substi + return + +TRANCODE ENDS + END + \ No newline at end of file diff --git a/CTRLC.ASM b/CTRLC.ASM new file mode 100644 index 0000000..c9d6902 --- /dev/null +++ b/CTRLC.ASM @@ -0,0 +1,468 @@ +; +; ^C status routines for MSDOS +; + +INCLUDE DOSSEG.ASM + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xlist +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + + i_need DevIOBuf,BYTE + i_need DidCTRLC,BYTE + i_need INDOS,BYTE + i_need DSKSTCOM,BYTE + i_need DSKSTCALL,BYTE + i_need DSKSTST,WORD + i_need BCON,DWORD + i_need DSKCHRET,BYTE + i_need DSKSTCNT,WORD + i_need IDLEINT,BYTE + i_need CONSWAP,BYTE + i_need user_SS,WORD + i_need user_SP,WORD + i_need ERRORMODE,BYTE + i_need ConC_spSave,WORD + i_need Exit_type,BYTE + i_need PFLAG,BYTE + i_need ExitHold,DWORD + i_need WPErr,BYTE + i_need ReadOp,BYTE + i_need CONTSTK,WORD + i_need Exit_Code,WORD + i_need CurrentPDB,WORD + i_need DIVMES,BYTE + i_need DivMesLen,BYTE + +SUBTTL Checks for ^C in CON I/O +PAGE +ASSUME DS:NOTHING,ES:NOTHING + + procedure DSKSTATCHK,NEAR ; Check for ^C if only one level in + CMP BYTE PTR [INDOS],1 + retnz ; Do NOTHING + PUSH CX + PUSH ES + PUSH BX + PUSH DS + PUSH SI + PUSH CS + POP ES + PUSH CS + POP DS +ASSUME DS:DOSGROUP + XOR CX,CX + MOV BYTE PTR [DSKSTCOM],DEVRDND + MOV BYTE PTR [DSKSTCALL],DRDNDHL + MOV [DSKSTST],CX + MOV BX,OFFSET DOSGROUP:DSKSTCALL + LDS SI,[BCON] +ASSUME DS:NOTHING + invoke DEVIOCALL2 + TEST [DSKSTST],STBUI + JNZ ZRET ; No characters available + MOV AL,BYTE PTR [DSKCHRET] +DSK1: + CMP AL,"C"-"@" + JNZ RET36 + MOV BYTE PTR [DSKSTCOM],DEVRD + MOV BYTE PTR [DSKSTCALL],DRDWRHL + MOV BYTE PTR [DSKCHRET],CL + MOV [DSKSTST],CX + INC CX + MOV [DSKSTCNT],CX + invoke DEVIOCALL2 ; Eat the ^C + POP SI + POP DS + POP BX ; Clean stack + POP ES + POP CX + JMP SHORT CNTCHAND + +ZRET: + XOR AL,AL ; Set zero +RET36: + POP SI + POP DS + POP BX + POP ES + POP CX + return + +NOSTOP: + CMP AL,"P"-"@" + JZ INCHK + + IF NOT TOGLPRN + CMP AL,"N"-"@" + JZ INCHK + ENDIF + + CMP AL,"C"-"@" + JZ INCHK + return +DSKSTATCHK ENDP + + procedure SPOOLINT,NEAR + PUSHF + CMP BYTE PTR [IDLEINT],0 + JZ POPFRET + CMP BYTE PTR [ERRORMODE],0 + JNZ POPFRET ;No spool ints in error mode + INT int_spooler +POPFRET: + POPF +RET18: return +SPOOLINT ENDP + + procedure STATCHK,NEAR + + invoke DSKSTATCHK ; Allows ^C to be detected under + ; input redirection + PUSH BX + XOR BX,BX + invoke GET_IO_FCB + POP BX + JC RET18 + MOV AH,1 + invoke IOFUNC + JZ SPOOLINT + CMP AL,'S'-'@' + JNZ NOSTOP + XOR AH,AH + invoke IOFUNC ; Eat Cntrl-S + JMP SHORT PAUSOSTRT +PRINTOFF: +PRINTON: + NOT BYTE PTR [PFLAG] + return + +PAUSOLP: + CALL SPOOLINT +PAUSOSTRT: + MOV AH,1 + invoke IOFUNC + JZ PAUSOLP +INCHK: + PUSH BX + XOR BX,BX + invoke GET_IO_FCB + POP BX + JC RET18 + XOR AH,AH + invoke IOFUNC + CMP AL,'P'-'@' + JZ PRINTON + IF NOT TOGLPRN + CMP AL,'N'-'@' + JZ PRINTOFF + ENDIF + CMP AL,'C'-'@' + retnz +STATCHK ENDP + + procedure CNTCHAND,NEAR +; Ctrl-C handler. +; "^C" and CR/LF is printed. Then the user registers are restored and +; the user CTRL-C handler is executed. At this point the top of the stack +; has 1) the interrupt return address should the user CTRL-C handler wish +; to allow processing to continue; 2) the original interrupt return address +; to the code that performed the function call in the first place. If +; the user CTRL-C handler wishes to continue, it must leave all registers +; unchanged and RET (not IRET) with carry CLEAR. If carry is SET then +; an terminate system call is simulated. + MOV AL,3 ; Display "^C" + invoke BUFOUT + invoke CRLF + PUSH SS + POP DS +ASSUME DS:DOSGROUP + CMP BYTE PTR [CONSWAP],0 + JZ NOSWAP + invoke SWAPBACK +NOSWAP: + CLI ; Prepare to play with stack + MOV SP,[user_SP] + MOV SS,[user_SS] ; User stack now restored +ASSUME SS:NOTHING + invoke restore_world ; User registers now restored +ASSUME DS:NOTHING + MOV BYTE PTR [INDOS],0 ; Go to known state + MOV BYTE PTR [ERRORMODE],0 + MOV [ConC_spsave],SP ; save his SP + INT int_ctrl_c ; Execute user Ctrl-C handler + MOV [user_SS],AX ; save the AX + PUSHF ; and the flags (maybe new call) + POP AX + CMP SP,[ConC_spsave] + JNZ ctrlc_try_new ; new syscall maybe? +ctrlc_repeat: + MOV AX,[user_SS] ; no... + transfer COMMAND ; Repeat command otherwise + +ctrlc_try_new: + SUB [ConC_spsave],2 ; Are there flags on the stack? + CMP SP,[ConC_spsave] + JZ ctrlc_new ; yes, new system call + +ctrlc_abort: + MOV AX,(EXIT SHL 8) + 0 + MOV BYTE PTR [DidCTRLC],0FFh + + transfer COMMAND ; give up by faking $EXIT + +ctrlc_new: + PUSH AX + POPF + POP [user_SS] + JNC ctrlc_repeat ; repeat operation + JMP ctrlc_abort ; indicate ^ced + +CNTCHAND ENDP + +SUBTTL DIVISION OVERFLOW INTERRUPT +PAGE +; Default handler for division overflow trap + procedure DIVOV,NEAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + MOV SI,OFFSET DOSGROUP:DIVMES + CALL RealDivOv + JMP ctrlc_abort ; Use Ctrl-C abort on divide overflow +DIVOV ENDP + +; +; RealDivOv: perform actual divide overflow stuff. +; Inputs: none +; Outputs: message to BCON +; + procedure RealDivOv,NEAR ; Do divide overflow and clock process + + PUSH CS ; get ES addressability + POP ES + + PUSH CS ; get DS addressability + POP DS +ASSUME DS:DOSGROUP + + MOV BYTE PTR [DskStCom],DevWrt + MOV BYTE PTR [DskStCall],DRdWrHL + MOV [DskSTST],0 + MOV BL,[DivMesLen] + XOR BH,BH + MOV [DskStCnt],BX + MOV BX,OFFSET DOSGROUP:DskStCall + MOV WORD PTR [DskChRet+1],SI ; transfer address (need an EQU) + LDS SI,[BCON] +ASSUME DS:NOTHING + invoke DEVIOCALL2 + MOV WORD PTR [DskChRet+1],OFFSET DOSGROUP:DevIOBuf + MOV [DskStCnt],1 + return +RealDivOv ENDP + +SUBTTL CHARHRD,HARDERR,ERROR -- HANDLE DISK ERRORS AND RETURN TO USER +PAGE + procedure CHARHARD,NEAR +ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP + +; Character device error handler +; Same function as HARDERR + + MOV WORD PTR [EXITHOLD+2],ES + MOV WORD PTR [EXITHOLD],BP + PUSH SI + AND DI,STECODE + MOV BP,DS ;Device pointer is BP:SI + CALL FATALC + POP SI + return +CHARHARD ENDP + + procedure HardErr,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Hard disk error handler. Entry conditions: +; DS:BX = Original disk transfer address +; DX = Original logical sector number +; CX = Number of sectors to go (first one gave the error) +; AX = Hardware error code +; DI = Original sector transfer count +; ES:BP = Base of drive parameters +; [READOP] = 0 for read, 1 for write + ; + XCHG AX,DI ; Error code in DI, count in AX + AND DI,STECODE ; And off status bits + CMP DI,WRECODE ; Write Protect Error? + JNZ NOSETWRPERR + PUSH AX + MOV AL,ES:[BP.dpb_drive] + MOV BYTE PTR [WPERR],AL ; Flag drive with WP error + POP AX +NOSETWRPERR: + SUB AX,CX ; Number of sectors successfully transferred + ADD DX,AX ; First sector number to retry + PUSH DX + MUL ES:[BP.dpb_sector_size] ; Number of bytes transferred + POP DX + ADD BX,AX ; First address for retry + XOR AH,AH ; Flag disk section in error + CMP DX,ES:[BP.dpb_first_FAT] ; In reserved area? + JB ERRINT + INC AH ; Flag for FAT + CMP DX,ES:[BP.dpb_dir_sector] ; In FAT? + JB ERRINT + INC AH + CMP DX,ES:[BP.dpb_first_sector] ; In directory? + JB ERRINT + INC AH ; Must be in data area +ERRINT: + SHL AH,1 ; Make room for read/write bit + OR AH,BYTE PTR [READOP] + entry FATAL + MOV AL,ES:[BP.dpb_drive] ; Get drive number + entry FATAL1 + MOV WORD PTR [EXITHOLD+2],ES + MOV WORD PTR [EXITHOLD],BP ; The only things we preserve + LES SI,ES:[BP.dpb_driver_addr] + MOV BP,ES ; BP:SI points to the device involved +FATALC: + CMP BYTE PTR [ERRORMODE],0 + JNZ SETIGN ; No INT 24s if already INT 24 + MOV [CONTSTK],SP + PUSH SS + POP ES +ASSUME ES:DOSGROUP + CLI ; Prepare to play with stack + INC BYTE PTR [ERRORMODE] ; Flag INT 24 in progress + DEC BYTE PTR [INDOS] ; INT 24 handler might not return + MOV SS,[user_SS] +ASSUME SS:NOTHING + MOV SP,ES:[user_SP] ; User stack pointer restored + INT int_fatal_abort ; Fatal error interrupt vector, must preserve ES + MOV ES:[user_SP],SP ; restore our stack + MOV ES:[user_SS],SS + MOV SP,ES + MOV SS,SP +ASSUME SS:DOSGROUP + MOV SP,[CONTSTK] + INC BYTE PTR [INDOS] ; Back in the DOS + MOV BYTE PTR [ERRORMODE],0 ; Back from INT 24 + STI +IGNRET: + LES BP,[EXITHOLD] +ASSUME ES:NOTHING + CMP AL,2 + JZ error_abort + MOV BYTE PTR [WPERR],-1 ;Forget about WP error + return + +SETIGN: + XOR AL,AL ;Flag ignore + JMP SHORT IGNRET + +error_abort: + PUSH SS + POP DS +ASSUME DS:DOSGROUP + CMP BYTE PTR [CONSWAP],0 + JZ NOSWAP2 + invoke SWAPBACK +NOSWAP2: + MOV BYTE PTR [exit_Type],Exit_hard_error + MOV DS,[CurrentPDB] +ASSUME DS:NOTHING + +; +; reset_environment checks the DS value against the CurrentPDB. If they +; are different, then an old-style return is performed. If they are +; the same, then we release jfns and restore to parent. We still use +; the PDB at DS:0 as the source of the terminate addresses. +; +; output: none. +; + entry reset_environment + ASSUME DS:NOTHING,ES:NOTHING + PUSH DS ; save PDB of process + + MOV AL,int_Terminate + invoke $Get_interrupt_vector ; and who to go to + MOV WORD PTR [EXITHOLD+2],ES ; save return address + MOV WORD PTR [EXITHOLD],BX + + MOV BX,[CurrentPDB] ; get current process + MOV DS,BX ; + MOV AX,DS:[PDB_Parent_PID] ; get parent to return to + POP CX +; +; AX = parentPDB, BX = CurrentPDB, CX = ThisPDB +; Only free handles if AX <> BX and BX = CX and [exit_code].upper is not +; Exit_keep_process +; + CMP AX,BX + JZ reset_return ; parentPDB = CurrentPDB + CMP BX,CX + JNZ reset_return ; CurrentPDB <> ThisPDB + PUSH AX ; save parent + CMP BYTE PTR [exit_type],Exit_keep_process + JZ reset_to_parent ; keeping this process + + invoke arena_free_process + + ; reset environment at [CurrentPDB]; close those handles + MOV CX,FilPerProc + +reset_free_jfn: + MOV BX,CX + PUSH CX + DEC BX ; get jfn + invoke $CLOSE ; close it, ignore return + POP CX + LOOP reset_free_jfn ; and do 'em all + +reset_to_parent: + POP [CurrentPDB] ; set up process as parent + +reset_return: ; come here for normal return + PUSH CS + POP DS + ASSUME DS:DOSGROUP + MOV AL,-1 + invoke FLUSHBUF ; make sure that everything is clean + + CLI + MOV BYTE PTR [INDOS],0 ;Go to known state + MOV BYTE PTR [WPERR],-1 ;Forget about WP error +; +; Snake into multitasking... Get stack from CurrentPDB person +; + MOV DS,[CurrentPDB] + ASSUME DS:NOTHING + MOV SS,WORD PTR DS:[PDB_user_stack+2] + MOV SP,WORD PTR DS:[PDB_user_stack] + + ASSUME SS:NOTHING + invoke restore_world + ASSUME ES:NOTHING + POP AX ; suck off CS:IP of interrupt... + POP AX + POP AX + MOV AX,0F202h ; STI + PUSH AX + PUSH WORD PTR [EXITHOLD+2] + PUSH WORD PTR [EXITHOLD] + STI + IRET ; Long return back to user terminate address +HardErr ENDP + + ASSUME SS:DOSGROUP + +do_ext + +CODE ENDS + END diff --git a/DEBASM.ASM b/DEBASM.ASM new file mode 100644 index 0000000..a0fb0db --- /dev/null +++ b/DEBASM.ASM @@ -0,0 +1,1264 @@ +TITLE DEBASM + +; Code for the ASSEMble command in the debugger + +.xlist +.xcref + INCLUDE DEBEQU.ASM + INCLUDE DOSSYM.ASM +.cref +.list + + +CODE SEGMENT PUBLIC BYTE 'CODE' +CODE ENDS + +CONST SEGMENT PUBLIC BYTE + + EXTRN DBMN:BYTE,CSSAVE:WORD,REG8:BYTE,REG16:BYTE,SIZ8:BYTE + EXTRN SYNERR:BYTE,OPTAB:BYTE,MAXOP:ABS + +CONST ENDS + +DATA SEGMENT PUBLIC BYTE + + EXTRN HINUM:WORD,LOWNUM:WORD,ASSEM_CNT:BYTE + EXTRN ASSEM1:BYTE,ASSEM2:BYTE,ASSEM3:BYTE,ASSEM4:BYTE,ASSEM5:BYTE + EXTRN ASSEM6:BYTE,OPBUF:BYTE,OPCODE:WORD,REGMEM:BYTE,INDEX:WORD + EXTRN ASMADD:BYTE,ASMSP:WORD,MOVFLG:BYTE,SEGFLG:BYTE,TSTFLG:BYTE + EXTRN NUMFLG:BYTE,DIRFLG:BYTE,BYTEBUF:BYTE,F8087:BYTE,DIFLG:BYTE + EXTRN SIFLG:BYTE,BXFLG:BYTE,BPFLG:BYTE,NEGFLG:BYTE,MEMFLG:BYTE + EXTRN REGFLG:BYTE,AWORD:BYTE,MIDFLD:BYTE,MODE:BYTE + +DATA ENDS + +DG GROUP CODE,CONST,DATA + + +CODE SEGMENT PUBLIC BYTE 'CODE' +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + + PUBLIC ASSEM + PUBLIC DB_OPER,DW_OPER,ASSEMLOOP,GROUP2,AA_OPER,DCINC_OPER + PUBLIC GROUP1,ESC_OPER,FGROUPP,FGROUPX,FDE_OPER,FGROUPZ + PUBLIC FD9_OPER,FGROUP,FDB_OPER,FGROUPB,FGROUP3,FGROUP3W + PUBLIC FGROUPDS,INT_OPER,IN_OPER,DISP8_OPER,JMP_OPER,NO_OPER + PUBLIC OUT_OPER,L_OPER,MOV_OPER,POP_OPER,PUSH_OPER,ROTOP + PUBLIC TST_OPER,EX_OPER,GET_DATA16,CALL_OPER + + EXTRN INBUF:NEAR,SCANB:NEAR,SCANP:NEAR,GETHX:NEAR,GET_ADDRESS:NEAR + EXTRN DEFAULT:NEAR,OUTDI:NEAR,BLANK:NEAR,PRINTMES:NEAR,TAB:NEAR + +; +; Line by line assembler +; + +ASSEM: + MOV BP,[CSSAVE] ; Default code segment + MOV DI,OFFSET DG:ASMADD ; Default address + CALL DEFAULT + MOV WORD PTR [ASMADD],DX ; Displacement of disassembly + MOV WORD PTR [ASMADD+2],AX ; Segment + MOV [ASMSP],SP ; Save sp in case of error + +ASSEMLOOP: + MOV SP,[ASMSP] ; Restore sp in case of error + LES DI,DWORD PTR ASMADD ; GET PC + CALL OUTDI ; OUTPUT ADDRESS + CALL BLANK ; SKIP A SPACE + PUSH CS + POP ES + CALL INBUF ; GET A BUFFER + CALL SCANB + JNZ OPLOOK + RET ; IF EMPTY JUST RETURN +; +; At this point ds:si points to the opcode mnemonic... +; +OPLOOK: XOR CX,CX ; OP-CODE COUNT = 0 + MOV DI,OFFSET DG:DBMN +OPSCAN: XOR BX,BX +OPLOOP: MOV AL,[DI+BX] + AND AL,7FH + CMP AL,[SI+BX] + JZ OPMATCH + INC CX ; INCREMENT OP-CODE COUNT + CMP CX,MAXOP ; CHECK FOR END OF LIST + JB OP1 + JMP ASMERR +OP1: INC DI ; SCAN FOR NEXT OP-CODE... + TEST BYTE PTR [DI-1],80H + JZ OP1 + JMP OPSCAN + +OPMATCH:INC BX ; COMPARE NEXT CHAR + TEST BYTE PTR [DI+BX-1],80H ; ARE WE DONE? + JZ OPLOOP ; ..IF NOT KEEP COMPARING + XCHG BX,CX + MOV AX,BX + SHL AX,1 + ADD AX,BX + ADD AX,OFFSET DG:OPTAB + MOV BX,AX +; +; CX = COUNT OF CHARS IN OPCODE +; BX = POINTER INTO OPCODE TABLE +; + XOR AX,AX + MOV BYTE PTR [AWORD],AL + MOV WORD PTR [MOVFLG],AX ; MOVFLG + TSTFLG + MOV BYTE PTR [SEGFLG],AL ; ZERO SEGMENT REGISTER FLAG + MOV AH,00001010B ; SET UP FOR AA_OPER + MOV AL,BYTE PTR [BX] + MOV WORD PTR [ASSEM1],AX + MOV BYTE PTR [ASSEM_CNT],1 + + ADD SI,CX ; SI POINTS TO OPERAND + JMP WORD PTR [BX+1] +; +; 8087 INSTRUCTIONS WITH NO OPERANDS +; +FDE_OPER: + MOV AH,0DEH + JMP SHORT FDX_OPER +FDB_OPER: + MOV AH,0DBH + JMP SHORT FDX_OPER +FD9_OPER: + MOV AH,0D9H +FDX_OPER: + XCHG AL,AH + MOV WORD PTR [ASSEM1],AX +; +; aad and aam instrucions +; +AA_OPER:INC BYTE PTR [ASSEM_CNT] +; +; instructions with no operands +; +NO_OPER: + CALL STUFF_BYTES + CALL SCANP + PUSH CS + POP ES + JNZ OPLOOK + JMP ASSEMLOOP +; +; push instruction +; +PUSH_OPER: + MOV AH,11111111B + JMP SHORT POP1 +; +; pop instruction +; +POP_OPER: + MOV AH,10001111B +POP1: MOV [ASSEM1],AH + MOV [MIDFLD],AL + INC BYTE PTR [MOVFLG] ; ALLOW SEGMENT REGISTERS + MOV BYTE PTR [AWORD],2 ; MUST BE 16 BITS + CALL GETREGMEM + CALL BUILDIT + MOV AL,[DI+2] + CMP AL,11000000B + JB DATRET + MOV BYTE PTR [DI],1 + CMP BYTE PTR [MOVFLG],2 + JNZ POP2 + AND AL,00011000B + OR AL,00000110B + CMP BYTE PTR [MIDFLD],0 + JNZ POP3 + OR AL,00000001B + JMP SHORT POP3 + +POP2: AND AL,111B + OR AL,01010000B + CMP BYTE PTR [MIDFLD],0 + JNZ POP3 + OR AL,01011000B +POP3: MOV BYTE PTR [DI+1],AL + JMP ASSEM_EXIT +; +; ret and retf instructions +; +GET_DATA16: + CALL SCANB + MOV CX,4 + CALL GETHX + JC DATRET + DEC BYTE PTR [ASSEM1] ; CHANGE OP-CODE + ADD BYTE PTR [ASSEM_CNT],2 ; UPDATE LENGTH + MOV WORD PTR [ASSEM2],DX ; SAVE OFFSET +DATRET: JMP ASSEM_EXIT +; +; int instruction +; +INT_OPER: + CALL SCANB + MOV CX,2 + CALL GETHX + JC ERRV1 + MOV AL,DL + CMP AL,3 + JZ DATRET + INC BYTE PTR [ASSEM1] + JMP DISPX +; +; in instruction +; +IN_OPER: + CALL SCANB + LODSW + CMP AX,"A"+4C00H ; "AL" + JZ IN_1 + CMP AX,"A"+5800H ; "AX" + JZ IN_0 +ERRV1: JMP ASMERR +IN_0: INC BYTE PTR [ASSEM1] +IN_1: CALL SCANP + CMP WORD PTR [SI],"D"+5800H ; "DX" + JZ DATRET + MOV CX,2 + CALL GETHX + JC ERRV1 + AND BYTE PTR [ASSEM1],11110111B + MOV AL,DL + JMP DISPX +; +; out instruction +; +OUT_OPER: + CALL SCANB + CMP WORD PTR [SI],"D"+5800H ; "DX" + JNZ OUT_0 + INC SI + INC SI + JMP SHORT OUT_1 +OUT_0: AND BYTE PTR [ASSEM1],11110111B + MOV CX,2 + CALL GETHX + JC ERRV1 + INC BYTE PTR [ASSEM_CNT] + MOV BYTE PTR [ASSEM2],DL +OUT_1: CALL SCANP + LODSW + CMP AX,"A"+4C00H ; "AL" + JZ DATRET + CMP AX,"A"+5800H ; "AX" + JNZ ERRV1 + INC BYTE PTR [ASSEM1] + JMP DATRET + +; +; jump instruction +; +JMP_OPER: + INC BYTE PTR [TSTFLG] +; +; call instruction +; +CALL_OPER: + MOV BYTE PTR [ASSEM1],11111111B + MOV BYTE PTR [MIDFLD],AL + CALL GETREGMEM + CALL BUILD3 + CMP BYTE PTR [MEMFLG],0 + JNZ CALLJ1 + CMP BYTE PTR [REGMEM],-1 + JZ CALLJ2 +; +; INDIRECT JUMPS OR CALLS +; +CALLJ1: CMP BYTE PTR [AWORD],1 +ERRZ4: JZ ERRV1 + CMP BYTE PTR [AWORD],4 + JNZ ASMEX4 + OR BYTE PTR [DI+2],1000B + JMP SHORT ASMEX4 +; +; DIRECT JUMPS OR CALLS +; +CALLJ2: MOV AX,[LOWNUM] + MOV DX,[HINUM] + MOV BL,[AWORD] + CMP BYTE PTR [NUMFLG],0 + JZ ERRZ4 + +; BL = NUMBER OF BYTES IN JUMP +; DX = OFFSET +; AX = SEGMENT + +CALLJ3: + MOV BYTE PTR [DI],5 + MOV [DI+2],AX + MOV [DI+4],DX + + MOV AL,10011010B ; SET UP INTER SEGMENT CALL + CMP BYTE PTR [TSTFLG],0 + JZ CALLJ5 + MOV AL,11101010B ; FIX UP FOR JUMP +CALLJ5: MOV BYTE PTR [DI+1],AL + CMP BL,4 ; FAR SPECIFIED? + JZ ASMEX4 + OR BL,BL + JNZ CALLJ6 + CMP DX,WORD PTR [ASMADD+2] ; DIFFERENT SEGMENT? + JNZ ASMEX4 + +CALLJ6: MOV BYTE PTR [DI],3 + MOV AL,11101000B ; SET UP FOR INTRASEGMENT + OR AL,[TSTFLG] + MOV BYTE PTR [DI+1],AL + + MOV AX,[LOWNUM] + SUB AX,WORD PTR [ASMADD] + SUB AX,3 + MOV [DI+2],AX + CMP BYTE PTR [TSTFLG],0 + JZ ASMEX4 + CMP BL,2 + JZ ASMEX4 + + INC AX + MOV CX,AX + CBW + CMP AX,CX + JNZ ASMEX3 + MOV BYTE PTR [DI+1],11101011B + MOV [DI+2],AX + DEC BYTE PTR [DI] +ASMEX4: JMP ASSEM_EXIT +; +; conditional jumps and loop instructions +; +DISP8_OPER: + MOV BP,WORD PTR [ASMADD+2] ; GET DEFAULT DISPLACEMENT + CALL GET_ADDRESS + SUB DX,WORD PTR [ASMADD] + DEC DX + DEC DX + CALL CHKSIZ + CMP CL,1 + JNZ ERRV2 +DISPX: INC [ASSEM_CNT] + MOV BYTE PTR [ASSEM2],AL +ASMEX3: JMP ASSEM_EXIT +; +; lds, les, and lea instructions +; +L_OPER: + CALL SCANB + LODSW + MOV CX,8 + MOV DI,OFFSET DG:REG16 + CALL CHKREG + JZ ERRV2 ; CX = 0 MEANS NO REGISTER + SHL AL,1 + SHL AL,1 + SHL AL,1 + MOV BYTE PTR [MIDFLD],AL + CALL SCANP + CALL GETREGMEM + CMP BYTE PTR [AWORD],0 + JNZ ERRV2 + CALL BUILD2 + JMP SHORT ASEXV +; +; dec and inc instructions +; +DCINC_OPER: + MOV BYTE PTR [ASSEM1],11111110B + MOV BYTE PTR [MIDFLD],AL + CALL GETREGMEM + CALL BUILDIT + TEST BYTE PTR [DI+1],1 + JZ ASEXV + MOV AL,[DI+2] + CMP AL,11000000B + JB ASEXV + AND AL,1111B + OR AL,01000000B + MOV [DI+1],AL + DEC BYTE PTR [DI] +ASEXV: JMP ASSEM_EXIT + +ERRV2: JMP ASMERR +; +; esc instruction +; +ESC_OPER: + INC BYTE PTR [AWORD] + CALL SCANB + MOV CX,2 + CALL GETHX + CMP DX,64 + JAE ERRV2 + CALL SCANP + MOV AX,DX + MOV CL,3 + SHR DX,CL + OR [ASSEM1],DL + AND AL,111B + SHL AL,CL + JMP GROUPE +; +; 8087 arithmetic instuctions +; + +; +; OPERANDS THAT ALLOW THE REVERSE BIT +; +FGROUPDS: + CALL SETMID + CALL GETREGMEM2 + CALL BUILD3 + CMP BYTE PTR [MODE],11000000B + JNZ FGROUP1 + MOV AL,[DIRFLG] + OR AL,AL + JZ FEXIT + OR [DI+1],AL ; IF D=1... + XOR BYTE PTR [DI+2],00001000B ; ...REVERSE THE SENSE OF R + JMP SHORT FEXIT + +; +; Here when instruction could have memory or register operand +; +FGROUPX: + CALL SETMID ; THIS ENTRY POINT FOR 1 MEM OPER + MOV BYTE PTR [DIRFLG],0 + JMP SHORT FGRP2 +FGROUP: + CALL SETMID +FGRP2: + CALL GETREGMEM2 + CALL BUILD3 + CMP BYTE PTR [MODE],11000000B + JNZ FGROUP1 + MOV AL,[DIRFLG] + OR [DI+1],AL + JMP SHORT FEXIT +FGROUP1:CALL SETMF +FEXIT: JMP ASSEM_EXIT +; +; These 8087 instructions require a memory operand +; +FGROUPB: + MOV AH,5 ; MUST BE TBYTE + JMP SHORT FGROUP3E +FGROUP3W: + MOV AH,2 ; MUST BE WORD + JMP SHORT FGROUP3E +FGROUP3: + MOV AH,-1 ; SIZE CANNOT BE SPECIFIED +FGROUP3E: + MOV [AWORD],AH + CALL SETMID + CALL GETREGMEM + CMP BYTE PTR [MODE],11000000B + JZ FGRPERR +FGRP: + CALL BUILD3 + JMP FEXIT +; +; These 8087 instructions require a register operand +; +FGROUPP: ; 8087 POP OPERANDS + MOV BYTE PTR [AWORD],-1 + CALL SETMID + CALL GETREGMEM2 + CMP BYTE PTR [DIRFLG],0 + JNZ FGRP +FGRPERR:JMP ASMERR + +FGROUPZ: ; ENTRY POINT WHERE ARG MUST BE MEM + CALL SETMID + MOV BYTE PTR [DIRFLG],0 + CALL GETREGMEM + CMP BYTE PTR [MODE],11000000B + JZ FGRPERR + CALL BUILD3 + CALL SETMF + JMP FEXIT +; +; not, neg, mul, imul, div, and idiv instructions +; +GROUP1: + MOV [ASSEM1],11110110B +GROUPE: + MOV BYTE PTR [MIDFLD],AL + CALL GETREGMEM + CALL BUILDIT + JMP FEXIT +; +; shift and rotate instructions +; +ROTOP: + MOV [ASSEM1],11010000B + MOV BYTE PTR [MIDFLD],AL + CALL GETREGMEM + CALL BUILDIT + CALL SCANP + CMP BYTE PTR [SI],"1" + JZ ASMEXV1 + CMP WORD PTR [SI],"LC" ; CL + JZ ROTOP1 +ROTERR: JMP ASMERR +ROTOP1: OR BYTE PTR [ASSEM1],10B +ASMEXV1:JMP ASSEM_EXIT +; +; xchg instruction +; +EX_OPER: + INC BYTE PTR [TSTFLG] +; +; test instruction +; +TST_OPER: + INC BYTE PTR [TSTFLG] + JMP SHORT MOVOP +; +; mov instruction +; +MOV_OPER: + INC BYTE PTR [MOVFLG] +MOVOP: XOR AX,AX + JMP SHORT GROUPM +; +; add, adc, sub, sbb, cmp, and, or, xor instructions +; +GROUP2: + MOV BYTE PTR [ASSEM1],10000000B +GROUPM: + MOV BYTE PTR [MIDFLD],AL + + PUSH AX + CALL GETREGMEM + CALL BUILD2 + CALL SCANP ; POINT TO NEXT OPERAND + MOV AL,BYTE PTR [ASSEM_CNT] + PUSH AX + CALL GETREGMEM + POP AX + MOV BYTE PTR [DI],AL + POP AX + MOV BL,BYTE PTR [AWORD] + OR BL,BL + JZ ERRV5 + DEC BL + AND BL,1 + OR BYTE PTR [DI+1],BL + + CMP BYTE PTR [MEMFLG],0 + JNZ G21V + CMP BYTE PTR [NUMFLG],0 ; TEST FOR IMMEDIATE DATA + JZ G21V + CMP BYTE PTR [SEGFLG],0 + JNZ ERRV5 + CMP BYTE PTR [TSTFLG],2 ; XCHG? + JNZ IMMED1 +ERRV5: JMP ASMERR +G21V: JMP GRP21 +; +; SECOND OPERAND WAS IMMEDIATE +; +IMMED1: MOV AL,BYTE PTR [DI+2] + CMP BYTE PTR [MOVFLG],0 + JZ NOTMOV1 + AND AL,11000000B + CMP AL,11000000B + JNZ GRP23 ; not to a register + ; MOVE IMMEDIATE TO REGISTER + MOV AL,BYTE PTR [DI+1] + AND AL,1 ; SET SIZE + PUSHF + SHL AL,1 + SHL AL,1 + SHL AL,1 + OR AL,BYTE PTR [DI+2] ; SET REGISTER + AND AL,00001111B + OR AL,10110000B + MOV BYTE PTR [DI+1],AL + MOV AX,WORD PTR [LOWNUM] + MOV WORD PTR [DI+2],AX + POPF + JZ EXVEC + INC BYTE PTR [DI] +EXVEC: JMP GRPEX + +NOTMOV1:AND AL,11000111B + CMP AL,11000000B + JZ IMMACC ; IMMEDIATE TO ACC + + CMP BYTE PTR [TSTFLG],0 + JNZ GRP23 + CMP BYTE PTR [MIDFLD],1*8 ; OR? + JZ GRP23 + CMP BYTE PTR [MIDFLD],4*8 ; AND? + JZ GRP23 + CMP BYTE PTR [MIDFLD],6*8 ; XOR? + JZ GRP23 + TEST BYTE PTR [DI+1],1 ; TEST IF BYTE OPCODE + JZ GRP23 + + MOV AX,[LOWNUM] + MOV BX,AX + CBW + CMP AX,BX + JNZ GRP23 ; SMALL ENOUGH? + + MOV BL,[DI] + DEC BYTE PTR [DI] + OR BYTE PTR [DI+1],10B + JMP SHORT GRP23X + +IMMACC: MOV AL,BYTE PTR [DI+1] + AND AL,1 + CMP BYTE PTR [TSTFLG],0 + JZ NOTTST + OR AL,10101000B + JMP SHORT TEST1 +NOTTST: OR AL,BYTE PTR [MIDFLD] + OR AL,100B +TEST1: MOV BYTE PTR [DI+1],AL + DEC BYTE PTR [DI] + +GRP23: MOV BL,BYTE PTR [DI] +GRP23X: XOR BH,BH + ADD BX,DI + INC BX + MOV AX,WORD PTR [LOWNUM] + MOV WORD PTR [BX],AX + INC BYTE PTR [DI] + TEST BYTE PTR [DI+1],1 + JZ GRPEX1 + INC BYTE PTR [DI] +GRPEX1: JMP GRPEX +; +; SECOND OPERAND WAS MEMORY OR REGISTER +; +GRP21: + CMP BYTE PTR [SEGFLG],0 + JZ GRP28 ; FIRST OPERAND WAS A SEGMENT REG + MOV AL,BYTE PTR [REGMEM] + TEST AL,10000B + JZ NOTSEG1 +ERRV3: JMP ASMERR +NOTSEG1:AND AL,111B + OR BYTE PTR [DI+2],AL + AND BYTE PTR [DI+1],11111110B + CMP BYTE PTR [MEMFLG],0 + JNZ G22V + JMP GRPEX + +GRP28: AND BYTE PTR [DI+2],11000111B + MOV AL,BYTE PTR [DI+1] ; GET FIRST OPCODE + AND AL,1B + CMP BYTE PTR [MOVFLG],0 + JZ NOTMOV2 + OR AL,10001000B + JMP SHORT MOV1 +NOTMOV2:CMP BYTE PTR [TSTFLG],0 + JZ NOTTST2 + OR AL,10000100B + CMP BYTE PTR [TSTFLG],2 + JNZ NOTTST2 + OR AL,10B +NOTTST2:OR AL,BYTE PTR [MIDFLD] ; MIDFLD IS ZERO FOR TST +MOV1: MOV BYTE PTR [DI+1],AL + CMP BYTE PTR [MEMFLG],0 +G22V: JNZ GRP22 +; +; SECOND OPERAND WAS A REGISTER +; + MOV AL,BYTE PTR [REGMEM] + TEST AL,10000B ; SEGMENT REGISTER? + JZ NOTSEG + CMP BYTE PTR [MOVFLG],0 + JZ ERRV3 + MOV BYTE PTR [DI+1],10001100B + +NOTSEG: AND AL,111B + SHL AL,1 + SHL AL,1 + SHL AL,1 + OR BYTE PTR [DI+2],AL +; +; SPECIAL FORM OF THE EXCHANGE COMMAND +; + CMP BYTE PTR [TSTFLG],2 + JNZ GRPEX + TEST BYTE PTR [DI+1],1 + JZ GRPEX + PUSH AX + MOV AL,BYTE PTR [DI+2] + AND AL,11000000B + CMP AL,11000000B ; MUST BE REGISTER TO REGISTER + POP AX + JB GRPEX + OR AL,AL + JZ SPECX + MOV AL,[DI+2] + AND AL,00000111B + JNZ GRPEX + MOV CL,3 + SHR BYTE PTR [DI+2],CL +SPECX: MOV AL,[DI+2] + AND AL,00000111B + OR AL,10010000B + MOV BYTE PTR [DI+1],AL + DEC BYTE PTR [DI] + JMP SHORT GRPEX +; +; SECOND OPERAND WAS A MEMORY REFERENCE +; +GRP22: CMP BYTE PTR [TSTFLG],0 + JNZ TST2 + OR BYTE PTR [DI+1],10B +TST2: MOV AL,BYTE PTR [DI+2] + CMP AL,11000000B ; MUST BE A REGISTER + JB ASMERR + CMP BYTE PTR [SEGFLG],0 + JZ GRP223 + AND AL,00011000B + JMP SHORT GRP222 +GRP223: AND AL,111B + SHL AL,1 + SHL AL,1 + SHL AL,1 +GRP222: OR AL,BYTE PTR [MODE] + OR AL,BYTE PTR [REGMEM] + MOV BYTE PTR [DI+2],AL + MOV AX,WORD PTR [LOWNUM] + MOV WORD PTR [DI+3],AX +GRPSIZ: MOV BYTE PTR [DI],2 + MOV AL,BYTE PTR [DI+2] + AND AL,11000111B + CMP AL,00000110B + JZ GRP24 + AND AL,11000000B + CMP AL,01000000B + JZ GRP25 + CMP AL,10000000B + JNZ GRPEX +GRP24: INC BYTE PTR [DI] +GRP25: INC BYTE PTR [DI] + +GRPEX: CMP BYTE PTR [MOVFLG],0 + JZ ASSEM_EXIT +; +; TEST FOR SPECIAL FORM OF MOV AX,[MEM] OR MOV [MEM],AX +; + MOV AL,[DI+1] ; GET OP-CODE + AND AL,11111100B + CMP AL,10001000B + JNZ ASSEM_EXIT + CMP BYTE PTR [DI+2],00000110B ; MEM TO AX OR AX TO MEM + JNZ ASSEM_EXIT + MOV AL,BYTE PTR [DI+1] + AND AL,11B + XOR AL,10B + OR AL,10100000B + MOV BYTE PTR [DI+1],AL + DEC BYTE PTR [DI] + MOV AX,[DI+3] + MOV WORD PTR [DI+2],AX + +ASSEM_EXIT: + CALL STUFF_BYTES + JMP ASSEMLOOP + +; Assem error. SI points to character in the input buffer +; which caused error. By subtracting from start of buffer, +; we will know how far to tab over to appear directly below +; it on the terminal. Then print "^ Error". + +ASMERR: + SUB SI,OFFSET DG:(BYTEBUF-10) ; How many char processed so far? + MOV CX,SI ; Parameter for TAB in CX + CALL TAB ; Directly below bad char + MOV SI,OFFSET DG:SYNERR ; Error message + CALL PRINTMES + JMP ASSEMLOOP +; +; assemble the different parts into an instruction +; +BUILDIT: + MOV AL,BYTE PTR [AWORD] + OR AL,AL + JNZ BUILD1 +BLDERR: JMP ASMERR + +BUILD1: DEC AL + OR BYTE PTR [DI+1],AL ; SET THE SIZE + +BUILD2: CMP BYTE PTR [NUMFLG],0 ; TEST FOR IMMEDIATE DATA + JZ BUILD3 + CMP BYTE PTR [MEMFLG],0 + JZ BLDERR + +BUILD3: MOV AL,BYTE PTR [REGMEM] + CMP AL,-1 + JZ BLD1 + TEST AL,10000B ; TEST IF SEGMENT REGISTER + JZ BLD1 + CMP BYTE PTR [MOVFLG],0 + JZ BLDERR + MOV WORD PTR [DI+1],10001110B + INC BYTE PTR [MOVFLG] + INC BYTE PTR [SEGFLG] + AND AL,00000011B + SHL AL,1 + SHL AL,1 + SHL AL,1 + OR AL,BYTE PTR 11000000B + MOV BYTE PTR [DI+2],AL + RET + +BLD1: AND AL,00000111B +BLD4: OR AL,BYTE PTR [MODE] + OR AL,BYTE PTR [MIDFLD] + MOV BYTE PTR [DI+2],AL + MOV AX,WORD PTR [LOWNUM] + MOV WORD PTR [DI+3],AX + RET + +GETREGMEM: + MOV BYTE PTR [F8087],0 +GETREGMEM2: + CALL SCANP + XOR AX,AX + MOV WORD PTR [LOWNUM],AX ; OFFSET + MOV WORD PTR [DIFLG],AX ; DIFLG+SIFLG + MOV WORD PTR [BXFLG],AX ; BXFLG+BPFLG + MOV WORD PTR [NEGFLG],AX ; NEGFLG+NUMFLG + MOV WORD PTR [MEMFLG],AX ; MEMFLG+REGFLG + DEC AL + CMP BYTE PTR [F8087],0 + JZ PUTREG + MOV AL,1 ; DEFAULT 8087 REG IS 1 +PUTREG: MOV BYTE PTR [REGMEM],AL + +GETLOOP:MOV BYTE PTR [NEGFLG],0 +GETLOOP1: + MOV AX,WORD PTR [SI] + CMP AL,',' + JZ GOMODE + CMP AL,13 + JZ GOMODE + CMP AL,';' + JZ GOMODE + CMP AL,9 + JZ GETTB + CMP AL,' ' + JNZ GOGET +GETTB: INC SI + JMP GETLOOP1 +GOGET: JMP GETINFO +; +; DETERMINE THE MODE BITS +; +GOMODE: MOV DI,OFFSET DG:ASSEM_CNT + MOV BYTE PTR [MODE],11000000B + MOV BYTE PTR [ASSEM_CNT],2 + CMP BYTE PTR [MEMFLG],0 + JNZ GOMODE1 + MOV AL,[NUMFLG] + OR AL,[REGFLG] + JNZ MORET + OR AL,[F8087] + JZ ERRET + MOV AL,[DI+1] + OR AL,[DIRFLG] + CMP AL,0DCH ; ARITHMETIC? + JNZ MORET + MOV BYTE PTR [DI+1],0DEH ; ADD POP TO NULL ARG 8087 +MORET: RET +ERRET: JMP ASMERR + +GOMODE1:MOV BYTE PTR [MODE],0 + CMP BYTE PTR [NUMFLG],0 + JZ GOREGMEM + + MOV BYTE PTR [DI],4 + MOV AX,WORD PTR [DIFLG] + OR AX,WORD PTR [BXFLG] + JNZ GOMODE2 + MOV BYTE PTR [REGMEM],00000110B + RET + +GOMODE2:MOV BYTE PTR [MODE],10000000B + CALL CHKSIZ1 + CMP CL,2 + JZ GOREGMEM + DEC BYTE PTR [DI] + MOV BYTE PTR [MODE],01000000B +; +; DETERMINE THE REG-MEM BITS +; +GOREGMEM: + MOV BX,WORD PTR [BXFLG] + MOV CX,WORD PTR [DIFLG] + XOR DX,DX +GOREG0: + MOV AL,BL ; BX + ADD AL,CH ; SI + CMP AL,2 + JZ GOGO + INC DL + MOV AL,BL + ADD AL,CL + CMP AL,2 + JZ GOGO + INC DL + MOV AL,BH + ADD AL,CH + CMP AL,2 + JZ GOGO + INC DL + MOV AL,BH + ADD AL,CL + CMP AL,2 + JZ GOGO + INC DL + OR CH,CH + JNZ GOGO + INC DL + OR CL,CL + JNZ GOGO + INC DL ; BP+DISP + OR BH,BH + JZ GOREG1 + CMP BYTE PTR [MODE],0 + JNZ GOGO + MOV BYTE PTR [MODE],01000000B + INC BYTE PTR [DI] + DEC DL +GOREG1: INC DL ; BX+DISP +GOGO: MOV BYTE PTR [REGMEM],DL + RET + +GETINFO:CMP AX,'EN' ; NEAR + JNZ GETREG3 +GETREG0:MOV DL,2 +GETRG01:CALL SETSIZ1 +GETREG1:CALL SCANS + MOV AX,WORD PTR [SI] + CMP AX,"TP" ; PTR + JZ GETREG1 + JMP GETLOOP + +GETREG3:MOV CX,5 + MOV DI,OFFSET DG:SIZ8 + CALL CHKREG ; LOOK FOR BYTE, WORD, DWORD, ETC. + JZ GETREG41 + INC AL + MOV DL,AL + JMP GETRG01 + +GETREG41: + MOV AX,[SI] + CMP BYTE PTR [F8087],0 + JZ GETREG5 + CMP AX,"TS" ; 8087 STACK OPERAND + JNZ GETREG5 + CMP BYTE PTR [SI+2],"," + JNZ GETREG5 + MOV BYTE PTR [DIRFLG],0 + ADD SI,3 + JMP GETLOOP + +GETREG5:CMP AX,"HS" ; SHORT + JZ GETREG1 + + CMP AX,"AF" ; FAR + JNZ GETRG51 + CMP BYTE PTR [SI+2],"R" + JNZ GETRG51 + ADD SI,3 + MOV DL,4 + JMP GETRG01 + +GETRG51:CMP AL,'[' + JNZ GETREG7 +GETREG6:INC BYTE PTR [MEMFLG] + INC SI + JMP GETLOOP + +GETREG7:CMP AL,']' + JZ GETREG6 + CMP AL,'.' + JZ GETREG6 + CMP AL,'+' + JZ GETREG6 + CMP AL,'-' + JNZ GETREG8 + INC BYTE PTR [NEGFLG] + INC SI + JMP GETLOOP1 + +GETREG8: ; LOOK FOR A REGISTER + CMP BYTE PTR [F8087],0 + JZ GETREGREG + CMP AX,"TS" + JNZ GETREGREG + CMP BYTE PTR [SI+2],"(" + JNZ GETREGREG + CMP BYTE PTR [SI+4],")" + JNZ ASMPOP + MOV AL,[SI+3] + SUB AL,"0" + JB ASMPOP + CMP AL,7 + JA ASMPOP + MOV [REGMEM],AL + INC BYTE PTR [REGFLG] + ADD SI,5 + CMP WORD PTR [SI],"S," + JNZ ZLOOP + CMP BYTE PTR [SI+2],"T" + JNZ ZLOOP + ADD SI,3 +ZLOOP: JMP GETLOOP + +GETREGREG: + MOV CX,20 + MOV DI,OFFSET DG:REG8 + CALL CHKREG + JZ GETREG12 ; CX = 0 MEANS NO REGISTER + MOV BYTE PTR [REGMEM],AL + INC BYTE PTR [REGFLG] ; TELL EVERYONE WE FOUND A REG + CMP BYTE PTR [MEMFLG],0 + JNZ NOSIZE + CALL SETSIZ +INCSI2: ADD SI,2 + JMP GETLOOP + +NOSIZE: CMP AL,11 ; BX REGISTER? + JNZ GETREG9 + CMP WORD PTR [BXFLG],0 + JZ GETOK +ASMPOP: JMP ASMERR + +GETOK: INC BYTE PTR [BXFLG] + JMP INCSI2 +GETREG9: + CMP AL,13 ; BP REGISTER? + JNZ GETREG10 + CMP WORD PTR [BXFLG],0 + JNZ ASMPOP + INC BYTE PTR [BPFLG] + JMP INCSI2 +GETREG10: + CMP AL,14 ; SI REGISTER? + JNZ GETREG11 + CMP WORD PTR [DIFLG],0 + JNZ ASMPOP + INC BYTE PTR [SIFLG] + JMP INCSI2 +GETREG11: + CMP AL,15 ; DI REGISTER? + JNZ ASMPOP ; *** error + CMP WORD PTR [DIFLG],0 + JNZ ASMPOP + INC BYTE PTR [DIFLG] + JMP INCSI2 + +GETREG12: ; BETTER BE A NUMBER! + MOV BP,WORD PTR [ASMADD+2] + CMP BYTE PTR [MEMFLG],0 + JZ GTRG121 +GTRG119:MOV CX,4 +GTRG120:CALL GETHX + JMP SHORT GTRG122 +GTRG121:MOV CX,2 + CMP BYTE PTR [AWORD],1 + JZ GTRG120 + CMP BYTE PTR [AWORD],CL + JZ GTRG119 + CALL GET_ADDRESS +GTRG122:JC ASMPOP + MOV [HINUM],AX + CMP BYTE PTR [NEGFLG],0 + JZ GETREG13 + NEG DX +GETREG13: + ADD WORD PTR [LOWNUM],DX + INC BYTE PTR [NUMFLG] +GETLOOPV: + JMP GETLOOP + +CHKREG: PUSH CX + INC CX + REPNZ SCASW + POP AX + SUB AX,CX + OR CX,CX + RET + +STUFF_BYTES: + PUSH SI + LES DI,DWORD PTR ASMADD + MOV SI,OFFSET DG:ASSEM_CNT + XOR AX,AX + LODSB + MOV CX,AX + JCXZ STUFFRET + REP MOVSB + MOV WORD PTR [ASMADD],DI +STUFFRET: + POP SI + RET + +SETSIZ: + MOV DL,1 + TEST AL,11000B ; 16 BIT OR SEGMENT REGISTER? + JZ SETSIZ1 + INC DL +SETSIZ1: + CMP BYTE PTR [AWORD],0 + JZ SETSIZ2 + CMP BYTE PTR [AWORD],DL + JZ SETSIZ2 +SETERR: POP DX + JMP ASMPOP +SETSIZ2:MOV BYTE PTR [AWORD],DL + RET +; +; DETERMINE IF NUMBER IN AX:DX IS 8 BITS, 16 BITS, OR 32 BITS +; +CHKSIZ: MOV CL,4 + CMP AX,BP + JNZ RETCHK +CHKSIZ1:MOV CL,2 + MOV AX,DX + CBW + CMP AX,DX + JNZ RETCHK + DEC CL +RETCHK: RET +; +; get first character after first space +; +SCANS: CMP BYTE PTR [SI],13 + JZ RETCHK + CMP BYTE PTR [SI],"[" + JZ RETCHK + LODSB + CMP AL," " + JZ SCANBV + CMP AL,9 + JNZ SCANS +SCANBV: JMP SCANB +; +; Set up for 8087 op-codes +; +SETMID: + MOV BYTE PTR [ASSEM1],0D8H + MOV AH,AL + AND AL,111B ; SET MIDDLE BITS OF SECOND BYTE + SHL AL,1 + SHL AL,1 + SHL AL,1 + MOV [MIDFLD],AL + MOV AL,AH ; SET LOWER BITS OF FIRST BYTE + SHR AL,1 + SHR AL,1 + SHR AL,1 + OR [ASSEM1],AL + MOV BYTE PTR [F8087],1 ; INDICATE 8087 OPERAND + MOV BYTE PTR [DIRFLG],100B + RET +; +; Set MF bits for 8087 op-codes +; +SETMF: MOV AL,[AWORD] + TEST BYTE PTR [DI+1],10B + JNZ SETMFI + AND BYTE PTR [DI+1],11111001B ; CLEAR MF BITS + CMP AL,3 ; DWORD? + JZ SETMFRET + CMP AL,4 ; QWORD? + JZ SETMFRET2 + TEST BYTE PTR [DI+1],1 + JZ SETMFERR + CMP AL,5 ; TBYTE? + JZ SETMFRET3 + JMP SHORT SETMFERR + +SETMFI: CMP AL,3 ; DWORD? + JZ SETMFRET + CMP AL,2 ; WORD? + JZ SETMFRET2 + TEST BYTE PTR [DI+1],1 + JZ SETMFERR + CMP AL,4 ; QWORD? + JNZ SETMFERR + OR BYTE PTR [DI+1],111B +SETMFRET3: + OR BYTE PTR [DI+1],011B + OR BYTE PTR [DI+2],101000B + JMP SHORT SETMFRET +SETMFRET2: + OR BYTE PTR [DI+1],100B +SETMFRET: + RET + +SETMFERR: + JMP ASMPOP + + +DW_OPER: + MOV BP,1 + JMP SHORT DBEN + +DB_OPER: + XOR BP,BP +DBEN: MOV DI,OFFSET DG:ASSEM_CNT + DEC BYTE PTR [DI] + INC DI +DB0: XOR BL,BL + CALL SCANP + JNZ DB1 +DBEX: JMP ASSEM_EXIT +DB1: OR BL,BL + JNZ DB3 + MOV BH,BYTE PTR [SI] + CMP BH,"'" + JZ DB2 + CMP BH,'"' + JNZ DB4 +DB2: INC SI + INC BL +DB3: LODSB + CMP AL,13 + JZ DBEX + CMP AL,BH + JZ DB0 + STOSB + INC BYTE PTR [ASSEM_CNT] + JMP DB3 +DB4: MOV CX,2 + CMP BP,0 + JZ DB41 + MOV CL,4 +DB41: PUSH BX + CALL GETHX + POP BX + JNC DB5 + JMP ASMERR +DB5: MOV AX,DX + CMP BP,0 + JZ DB6 + STOSW + INC BYTE PTR [ASSEM_CNT] + JMP SHORT DB7 +DB6: STOSB +DB7: INC BYTE PTR [ASSEM_CNT] + JMP DB0 + +CODE ENDS + END ASSEM + \ No newline at end of file diff --git a/DEBCOM1.ASM b/DEBCOM1.ASM new file mode 100644 index 0000000..8e992d9 --- /dev/null +++ b/DEBCOM1.ASM @@ -0,0 +1,694 @@ +TITLE PART1 DEBUGGER COMMANDS + +; Routines to perform debugger commands except ASSEMble and UASSEMble + +.xlist +.xcref + INCLUDE DEBEQU.ASM + INCLUDE DOSSYM.ASM +.cref +.list + +CODE SEGMENT PUBLIC BYTE 'CODE' +CODE ENDS + +CONST SEGMENT PUBLIC BYTE + + EXTRN SYNERR:BYTE + + EXTRN DISPB:WORD,DSIZ:BYTE,DSSAVE:WORD + if sysver + EXTRN CIN:DWORD,PFLAG:BYTE + endif + +CONST ENDS + +DATA SEGMENT PUBLIC BYTE + + EXTRN DEFLEN:WORD,BYTEBUF:BYTE,DEFDUMP:BYTE + +DATA ENDS + +DG GROUP CODE,CONST,DATA + + +CODE SEGMENT PUBLIC BYTE 'CODE' +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + + + PUBLIC HEXCHK,GETHEX1,PRINT,DSRANGE,ADDRESS,HEXIN,PERROR + PUBLIC GETHEX,GET_ADDRESS,GETEOL,GETHX,PERR + PUBLIC PERR,MOVE,DUMP,ENTER,FILL,SEARCH,DEFAULT + if sysver + PUBLIC IN + EXTRN DISPREG:NEAR,DEVIOCALL:NEAR + endif + + EXTRN OUT:NEAR,CRLF:NEAR,OUTDI:NEAR,OUTSI:NEAR,SCANP:NEAR + EXTRN SCANB:NEAR,BLANK:NEAR,TAB:NEAR,PRINTMES:NEAR,COMMAND:NEAR + EXTRN HEX:NEAR,BACKUP:NEAR + + +DEBCOM1: + +; RANGE - Looks for parameters defining an address range. +; The first parameter is the starting address. The second parameter +; may specify the ending address, or it may be preceded by +; "L" and specify a length (4 digits max), or it may be +; omitted and a length of 128 bytes is assumed. Returns with +; segment in AX, displacement in DX, and length in CX. + +DSRANGE: + MOV BP,[DSSAVE] ; Set default segment to DS + MOV [DEFLEN],128 ; And default length to 128 bytes +RANGE: + CALL ADDRESS + PUSH AX ; Save segment + PUSH DX ; Save offset + CALL SCANP ; Get to next parameter + MOV AL,[SI] + CMP AL,"L" ; Length indicator? + JE GETLEN + MOV DX,[DEFLEN] ; Default length + CALL HEXIN ; Second parameter present? + JC GetDef ; If not, use default + MOV CX,4 + CALL GETHEX ; Get ending address (same segment) + MOV CX,DX ; Low 16 bits of ending addr. + POP DX ; Low 16 bits of starting addr. + SUB CX,DX ; Compute range + JAE DSRNG2 +DSRNG1: JMP PERROR ; Negative range +DSRNG2: INC CX ; Include last location + JCXZ DSRNG1 ; Wrap around error + POP AX ; Restore segment + RET +GetDef: + POP CX ; get original offset + PUSH CX ; save it + NEG CX ; rest of segment + JZ RngRet ; use default + CMP CX,DX ; more room in segment? + JAE RngRet ; yes, use default + JMP RngRet1 ; no, length is in CX + +GETLEN: + INC SI ; Skip over "L" to length + MOV CX,4 ; Length may have 4 digits + CALL GETHEX ; Get the range +RNGRET: + MOV CX,DX ; Length +RngRet1: + POP DX ; Offset + MOV AX,CX + ADD AX,DX + JNC OKRET + CMP AX,1 + JAE DSRNG1 ; Look for wrap error +OKRET: + POP AX ; Segment + RET + +DEFAULT: +; DI points to default address and CX has default length + CALL SCANP + JZ USEDEF ; Use default if no parameters + MOV [DEFLEN],CX + CALL RANGE + JMP GETEOL +USEDEF: + MOV SI,DI + LODSW ; Get default displacement + MOV DX,AX + LODSW ; Get default segment + RET + +; Dump an area of memory in both hex and ASCII + +DUMP: + MOV BP,[DSSAVE] + MOV CX,DISPB + MOV DI,OFFSET DG:DEFDUMP + CALL DEFAULT ; Get range if specified + MOV DS,AX ; Set segment + MOV SI,DX ; SI has displacement in segment + + IF ZIBO + PUSH SI ; save SI away + AND SI,0FFF0h ; convert to para number + CALL OutSI ; display location + POP SI ; get SI back + MOV AX,SI ; move offset + MOV AH,3 ; spaces per byte + AND AL,0Fh ; convert to real offset + MUL AH ; compute (AL+1)*3-1 + OR AL,AL ; set flag + JZ InRow ; if xero go on + PUSH CX ; save count + MOV CX,AX ; move to convenient spot + CALL Tab ; move over + POP CX ; get back count + JMP InRow ; display line + ENDIF + +ROW: + CALL OUTSI ; Print address at start of line +InRow: + PUSH SI ; Save address for ASCII dump + CALL BLANK +BYTE0: + CALL BLANK ; Space between bytes +BYTE1: + LODSB ; Get byte to dump + CALL HEX ; and display it + POP DX ; DX has start addr. for ASCII dump + DEC CX ; Drop loop count + JZ ToAscii ; If through do ASCII dump + MOV AX,SI + TEST AL,CS:(BYTE PTR DSIZ) ; On 16-byte boundary? + JZ ENDROW + PUSH DX ; Didn't need ASCII addr. yet + TEST AL,7 ; On 8-byte boundary? + JNZ BYTE0 + MOV AL,"-" ; Mark every 8 bytes + CALL OUT + JMP SHORT BYTE1 +ENDROW: + CALL ASCII ; Show it in ASCII + JMP SHORT ROW ; Loop until count is zero +ToAscii: + MOV AX,SI ; get offset + AND AL,0Fh ; real offset + JZ ASCII ; no loop if already there + SUB AL,10h ; remainder + NEG AL + MOV CL,3 + MUL CL + MOV CX,AX ; number of chars to move + CALL Tab +ASCII: + PUSH CX ; Save byte count + MOV AX,SI ; Current dump address + MOV SI,DX ; ASCII dump address + SUB AX,DX ; AX=length of ASCII dump + IF NOT ZIBO +; Compute tab length. ASCII dump always appears on right side +; screen regardless of how many bytes were dumped. Figure 3 +; characters for each byte dumped and subtract from 51, which +; allows a minimum of 3 blanks after the last byte dumped. + MOV BX,AX + SHL AX,1 ; Length times 2 + ADD AX,BX ; Length times 3 + MOV CX,51 + SUB CX,AX ; Amount to tab in CX + CALL TAB + MOV CX,BX ; ASCII dump length back in CX + ELSE + MOV CX,SI ; get starting point + DEC CX + AND CX,0Fh + INC CX + AND CX,0Fh + ADD CX,3 ; we have the correct number to tab + PUSH AX ; save count + CALL TAB + POP CX ; get count back + ENDIF +ASCDMP: + LODSB ; Get ASCII byte to dump + AND AL,7FH ; ASCII uses 7 bits + CMP AL,7FH ; Don't try to print RUBOUT + JZ NOPRT + CMP AL," " ; Check for control characters + JNC PRIN +NOPRT: + MOV AL,"." ; If unprintable character +PRIN: + CALL OUT ; Print ASCII character + LOOP ASCDMP ; CX times + POP CX ; Restore overall dump length + MOV ES:WORD PTR [DEFDUMP],SI + MOV ES:WORD PTR [DEFDUMP+2],DS ; Save last address as default + CALL CRLF ; Print CR/LF and return + RET + + +; Block move one area of memory to another. Overlapping moves +; are performed correctly, i.e., so that a source byte is not +; overwritten until after it has been moved. + +MOVE: + CALL DSRANGE ; Get range of source area + PUSH CX ; Save length + PUSH AX ; Save segment + PUSH DX ; Save source displacement + CALL ADDRESS ; Get destination address (same segment) + CALL GETEOL ; Check for errors + POP SI + MOV DI,DX ; Set dest. displacement + POP BX ; Source segment + MOV DS,BX + MOV ES,AX ; Destination segment + POP CX ; Length + CMP DI,SI ; Check direction of move + SBB AX,BX ; Extend the CMP to 32 bits + JB COPYLIST ; Move forward into lower mem. +; Otherwise, move backward. Figure end of source and destination +; areas and flip direction flag. + DEC CX + ADD SI,CX ; End of source area + ADD DI,CX ; End of destination area + STD ; Reverse direction + INC CX +COPYLIST: + MOVSB ; Do at least 1 - Range is 1-10000H not 0-FFFFH + DEC CX + REP MOVSB ; Block move +RET1: RET + +; Fill an area of memory with a list values. If the list +; is bigger than the area, don't use the whole list. If the +; list is smaller, repeat it as many times as necessary. + +FILL: + CALL DSRANGE ; Get range to fill + PUSH CX ; Save length + PUSH AX ; Save segment number + PUSH DX ; Save displacement + CALL LIST ; Get list of values to fill with + POP DI ; Displacement in segment + POP ES ; Segment + POP CX ; Length + CMP BX,CX ; BX is length of fill list + MOV SI,OFFSET DG:BYTEBUF ; List is in byte buffer + JCXZ BIGRNG + JAE COPYLIST ; If list is big, copy part of it +BIGRNG: + SUB CX,BX ; How much bigger is area than list? + XCHG CX,BX ; CX=length of list + PUSH DI ; Save starting addr. of area + REP MOVSB ; Move list into area + POP SI +; The list has been copied into the beginning of the +; specified area of memory. SI is the first address +; of that area, DI is the end of the copy of the list +; plus one, which is where the list will begin to repeat. +; All we need to do now is copy [SI] to [DI] until the +; end of the memory area is reached. This will cause the +; list to repeat as many times as necessary. + MOV CX,BX ; Length of area minus list + PUSH ES ; Different index register + POP DS ; requires different segment reg. + JMP SHORT COPYLIST ; Do the block move + +; Search a specified area of memory for given list of bytes. +; Print address of first byte of each match. + +SEARCH: + CALL DSRANGE ; Get area to be searched + PUSH CX ; Save count + PUSH AX ; Save segment number + PUSH DX ; Save displacement + CALL LIST ; Get search list + DEC BX ; No. of bytes in list-1 + POP DI ; Displacement within segment + POP ES ; Segment + POP CX ; Length to be searched + SUB CX,BX ; minus length of list +SCAN: + MOV SI,OFFSET DG:BYTEBUF ; List kept in byte buffer + LODSB ; Bring first byte into AL +DOSCAN: + SCASB ; Search for first byte + LOOPNE DOSCAN ; Do at least once by using LOOP + JNZ RET1 ; Exit if not found + PUSH BX ; Length of list minus 1 + XCHG BX,CX + PUSH DI ; Will resume search here + REPE CMPSB ; Compare rest of string + MOV CX,BX ; Area length back in CX + POP DI ; Next search location + POP BX ; Restore list length + JNZ TEST ; Continue search if no match + DEC DI ; Match address + CALL OUTDI ; Print it + INC DI ; Restore search address + CALL CRLF +TEST: + JCXZ RET1 + JMP SHORT SCAN ; Look for next occurrence + +; Get the next parameter, which must be a hex number. +; CX is maximum number of digits the number may have. + +GETHX: + CALL SCANP +GETHX1: + XOR DX,DX ; Initialize the number + CALL HEXIN ; Get a hex digit + JC HXERR ; Must be one valid digit + MOV DL,AL ; First 4 bits in position +GETLP: + INC SI ; Next char in buffer + DEC CX ; Digit count + CALL HEXIN ; Get another hex digit? + JC RETHX ; All done if no more digits + STC + JCXZ HXERR ; Too many digits? + SHL DX,1 ; Multiply by 16 + SHL DX,1 + SHL DX,1 + SHL DX,1 + OR DL,AL ; and combine new digit + JMP SHORT GETLP ; Get more digits + +GETHEX: + CALL GETHX ; Scan to next parameter + JMP SHORT GETHX2 +GETHEX1: + CALL GETHX1 +GETHX2: JC PERROR +RETHX: CLC +HXERR: RET + + +; Check if next character in the input buffer is a hex digit +; and convert it to binary if it is. Carry set if not. + +HEXIN: + MOV AL,[SI] + +; Check if AL has a hex digit and convert it to binary if it +; is. Carry set if not. + +HEXCHK: + SUB AL,"0" ; Kill ASCII numeric bias + JC RET2 + CMP AL,10 + CMC + JNC RET2 ; OK if 0-9 + AND AL,5FH + SUB AL,7 ; Kill A-F bias + CMP AL,10 + JC RET2 + CMP AL,16 + CMC +RET2: RET + +; Process one parameter when a list of bytes is +; required. Carry set if parameter bad. Called by LIST. + +LISTITEM: + CALL SCANP ; Scan to parameter + CALL HEXIN ; Is it in hex? + JC STRINGCHK ; If not, could be a string + MOV CX,2 ; Only 2 hex digits for bytes + CALL GETHEX ; Get the byte value + MOV [BX],DL ; Add to list + INC BX +GRET: CLC ; Parameter was OK + RET +STRINGCHK: + MOV AL,[SI] ; Get first character of param + CMP AL,"'" ; String? + JZ STRING + CMP AL,'"' ; Either quote is all right + JZ STRING + STC ; Not string, not hex - bad + RET +STRING: + MOV AH,AL ; Save for closing quote + INC SI +STRNGLP: + LODSB ; Next char of string + CMP AL,13 ; Check for end of line + JZ PERR ; Must find a close quote + CMP AL,AH ; Check for close quote + JNZ STOSTRG ; Add new character to list + CMP AH,[SI] ; Two quotes in a row? + JNZ GRET ; If not, we're done + INC SI ; Yes - skip second one +STOSTRG: + MOV [BX],AL ; Put new char in list + INC BX + JMP SHORT STRNGLP ; Get more characters + +; Get a byte list for ENTER, FILL or SEARCH. Accepts any number +; of 2-digit hex values or character strings in either single +; (') or double (") quotes. + +LIST: + MOV BX,OFFSET DG:BYTEBUF ; Put byte list in the byte buffer +LISTLP: + CALL LISTITEM ; Process a parameter + JNC LISTLP ; If OK, try for more + SUB BX,OFFSET DG:BYTEBUF ; BX now has no. of bytes in list + JZ PERROR ; List must not be empty + +; Make sure there is nothing more on the line except for +; blanks and carriage return. If there is, it is an +; unrecognized parameter and an error. + +GETEOL: + CALL SCANB ; Skip blanks + JNZ PERROR ; Better be a RETURN +RET3: RET + +; Command error. SI has been incremented beyond the +; command letter so it must decremented for the +; error pointer to work. + +PERR: + DEC SI + +; Syntax error. SI points to character in the input buffer +; which caused error. By subtracting from start of buffer, +; we will know how far to tab over to appear directly below +; it on the terminal. Then print "^ Error". + +PERROR: + SUB SI,OFFSET DG:(BYTEBUF-1); How many char processed so far? + MOV CX,SI ; Parameter for TAB in CX + CALL TAB ; Directly below bad char + MOV SI,OFFSET DG:SYNERR ; Error message + +; Print error message and abort to command level + +PRINT: + CALL PRINTMES + JMP COMMAND + +; Gets an address in Segment:Displacement format. Segment may be omitted +; and a default (kept in BP) will be used, or it may be a segment +; register (DS, ES, SS, CS). Returns with segment in AX, OFFSET in DX. + +ADDRESS: + CALL GET_ADDRESS + JC PERROR +ADRERR: STC + RET + +GET_ADDRESS: + CALL SCANP + MOV AL,[SI+1] + CMP AL,"S" + JZ SEGREG + MOV CX,4 + CALL GETHX + JC ADRERR + MOV AX,BP ; Get default segment + CMP BYTE PTR [SI],":" + JNZ GETRET + PUSH DX +GETDISP: + INC SI ; Skip over ":" + MOV CX,4 + CALL GETHX + POP AX + JC ADRERR +GETRET: CLC + RET +SEGREG: + MOV AL,[SI] + MOV DI,OFFSET DG:SEGLET + MOV CX,4 + REPNE SCASB + JNZ ADRERR + INC SI + INC SI + SHL CX,1 + MOV BX,CX + CMP BYTE PTR [SI],":" + JNZ ADRERR + PUSH [BX+DSSAVE] + JMP SHORT GETDISP + +SEGLET DB "CSED" + +; Short form of ENTER command. A list of values from the +; command line are put into memory without using normal +; ENTER mode. + +GETLIST: + CALL LIST ; Get the bytes to enter + POP DI ; Displacement within segment + POP ES ; Segment to enter into + MOV SI,OFFSET DG:BYTEBUF ; List of bytes is in byte 2uffer + MOV CX,BX ; Count of bytes + REP MOVSB ; Enter that byte list + RET + +; Enter values into memory at a specified address. If the +; line contains nothing but the address we go into "enter +; mode", where the address and its current value are printed +; and the user may change it if desired. To change, type in +; new value in hex. Backspace works to correct errors. If +; an illegal hex digit or too many digits are typed, the +; bell is sounded but it is otherwise ignored. To go to the +; next byte (with or without change), hit space bar. To +; back CLDto a previous address, type "-". On +; every 8-byte boundary a new line is started and the address +; is printed. To terminate command, type carriage return. +; Alternatively, the list of bytes to be entered may be +; included on the original command line immediately following +; the address. This is in regular LIST format so any number +; of hex values or strings in quotes may be entered. + +ENTER: + MOV BP,[DSSAVE] ; Set default segment to DS + CALL ADDRESS + PUSH AX ; Save for later + PUSH DX + CALL SCANB ; Any more parameters? + JNZ GETLIST ; If not end-of-line get list + POP DI ; Displacement of ENTER + POP ES ; Segment +GETROW: + CALL OUTDI ; Print address of entry + CALL BLANK ; Leave a space + CALL BLANK +GETBYTE: + MOV AL,ES:[DI] ; Get current value + CALL HEX ; And display it +PUTDOT: + MOV AL,"." + CALL OUT ; Prompt for new value + MOV CX,2 ; Max of 2 digits in new value + MOV DX,0 ; Intial new value +GETDIG: + CALL IN ; Get digit from user + MOV AH,AL ; Save + CALL HEXCHK ; Hex digit? + XCHG AH,AL ; Need original for echo + JC NOHEX ; If not, try special command + MOV DH,DL ; Rotate new value + MOV DL,AH ; And include new digit + LOOP GETDIG ; At most 2 digits +; We have two digits, so all we will accept now is a command. +DWAIT: + CALL IN ; Get command character +NOHEX: + CMP AL,8 ; Backspace + JZ BS + CMP AL,7FH ; RUBOUT + JZ RUB + CMP AL,"-" ; Back CLDto previous address + JZ PREV + CMP AL,13 ; All done with command? + JZ EOL + CMP AL," " ; Go to next address + JZ NEXT + MOV AL,8 + CALL OUT ; Back CLDover illegal character + CALL BACKUP + JCXZ DWAIT + JMP SHORT GETDIG + +RUB: + MOV AL,8 + CALL OUT +BS: + CMP CL,2 ; CX=2 means nothing typed yet + JZ PUTDOT ; Put back the dot we backed CLDover + INC CL ; Accept one more character + MOV DL,DH ; Rotate out last digit + MOV DH,CH ; Zero this digit + CALL BACKUP ; Physical backspace + JMP SHORT GETDIG ; Get more digits + +; If new value has been entered, convert it to binary and +; put into memory. Always bump pointer to next location + +STORE: + CMP CL,2 ; CX=2 means nothing typed yet + JZ NOSTO ; So no new value to store +; Rotate DH left 4 bits to combine with DL and make a byte value + PUSH CX + MOV CL,4 + SHL DH,CL + POP CX + OR DL,DH ; Hex is now converted to binary + MOV ES:[DI],DL ; Store new value +NOSTO: + INC DI ; Prepare for next location + RET +NEXT: + CALL STORE ; Enter new value + INC CX ; Leave a space plus two for + INC CX ; each digit not entered + CALL TAB + MOV AX,DI ; Next memory address + AND AL,7 ; Check for 8-byte boundary + JNZ GETBYTE ; Take 8 per line +NEWROW: + CALL CRLF ; Terminate line + JMP GETROW ; Print address on new line +PREV: + CALL STORE ; Enter the new value +; DI has been bumped to next byte. Drop it 2 to go to previous addr + DEC DI + DEC DI + JMP SHORT NEWROW ; Terminate line after backing CLD + +EOL: + CALL STORE ; Enter the new value + JMP CRLF ; CR/LF and terminate + +; Console input of single character + + IF SYSVER +IN: + PUSH DS + PUSH SI + LDS SI,CS:[CIN] + MOV AH,4 + CALL DEVIOCALL + POP SI + POP DS + CMP AL,3 + JNZ NOTCNTC + INT 23H +NOTCNTC: + CMP AL,'P'-'@' + JZ PRINTON + CMP AL,'N'-'@' + JZ PRINTOFF + CALL OUT + RET + +PRINTOFF: +PRINTON: + NOT [PFLAG] + JMP SHORT IN + + ELSE + +IN: + MOV AH,1 + INT 21H + RET + ENDIF + +CODE ENDS + END DEBCOM1 + \ No newline at end of file diff --git a/DEBCOM2.ASM b/DEBCOM2.ASM new file mode 100644 index 0000000..852bed5 --- /dev/null +++ b/DEBCOM2.ASM @@ -0,0 +1,1269 @@ +TITLE PART2 DEBUGGER COMMANDS + +; Routines to perform debugger commands except ASSEMble and UASSEMble + +.xlist +.xcref + INCLUDE DEBEQU.ASM + INCLUDE DOSSYM.ASM +.cref +.list + +CODE SEGMENT PUBLIC BYTE 'CODE' +CODE ENDS + +CONST SEGMENT PUBLIC BYTE + + EXTRN NOTFND:BYTE,NOROOM:BYTE,DRVLET:BYTE,NOSPACE:BYTE,NAMBAD:BYTE + EXTRN TOOBIG:BYTE,ERRMES:BYTE + EXTRN EXEBAD:BYTE,HEXERR:BYTE,EXEWRT:BYTE,HEXWRT:BYTE + EXTRN EXECEMES:BYTE,WRTMES1:BYTE,WRTMES2:BYTE,ACCMES:BYTE + + EXTRN FLAGTAB:WORD,EXEC_BLOCK:BYTE,COM_LINE:DWORD,COM_FCB1:DWORD + EXTRN COM_FCB2:DWORD,COM_SSSP:DWORD,COM_CSIP:DWORD,RETSAVE:WORD + EXTRN NEWEXEC:BYTE,HEADSAVE:WORD + EXTRN REGTAB:BYTE,TOTREG:BYTE,NOREGL:BYTE + EXTRN USER_PROC_PDB:WORD,STACK:BYTE,RSTACK:WORD,AXSAVE:WORD + EXTRN BXSAVE:WORD,DSSAVE:WORD,ESSAVE:WORD,CSSAVE:WORD,IPSAVE:WORD + EXTRN SSSAVE:WORD,CXSAVE:WORD,SPSAVE:WORD,FSAVE:WORD + EXTRN SREG:BYTE,SEGTAB:WORD,REGDIF:WORD,RDFLG:BYTE + +CONST ENDS + +DATA SEGMENT PUBLIC BYTE + + EXTRN DEFDUMP:BYTE,TRANSADD:DWORD,INDEX:WORD,BUFFER:BYTE + EXTRN ASMADD:BYTE,DISADD:BYTE,NSEG:WORD,BPTAB:BYTE + EXTRN BRKCNT:WORD,TCOUNT:WORD,SWITCHAR:BYTE,XNXCMD:BYTE,XNXOPT:BYTE + EXTRN AWORD:BYTE,EXTPTR:WORD,HANDLE:WORD,PARSERR:BYTE + +DATA ENDS + +DG GROUP CODE,CONST,DATA + + +CODE SEGMENT PUBLIC BYTE 'CODE' +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + + PUBLIC DEFIO,SKIP_FILE,PREPNAME,DEBUG_FOUND + PUBLIC REG,COMPARE,GO,INPUT,LOAD + PUBLIC NAME,OUTPUT,TRACE,ZTRACE,DWRITE + if sysver + PUBLIC DISPREG + endif + + EXTRN GETHEX:NEAR,GETEOL:NEAR + EXTRN CRLF:NEAR,BLANK:NEAR,OUT:NEAR + EXTRN OUTSI:NEAR,OUTDI:NEAR,INBUF:NEAR,SCANB:NEAR,SCANP:NEAR + EXTRN RPRBUF:NEAR,HEX:NEAR,OUT16:NEAR,DIGIT:NEAR + EXTRN COMMAND:NEAR,DISASLN:NEAR,SET_TERMINATE_VECTOR:NEAR + EXTRN RESTART:NEAR,DABORT:NEAR,TERMINATE:NEAR,DRVERR:NEAR + EXTRN FIND_DEBUG:NEAR,NMIInt:NEAR,NMIIntEnd:NEAR + EXTRN HEXCHK:NEAR,GETHEX1:NEAR,PRINT:NEAR,DSRANGE:NEAR + EXTRN ADDRESS:NEAR,HEXIN:NEAR,PERROR:NEAR + + +DEBCOM2: +DISPREG: + MOV SI,OFFSET DG:REGTAB + MOV BX,OFFSET DG:AXSAVE + MOV BYTE PTR TOTREG,13 + MOV CH,0 + MOV CL,NOREGL +REPDISP: + SUB TOTREG,CL + CALL DISPREGLINE + CALL CRLF + MOV CH,0 + MOV CL,NOREGL + CMP CL,TOTREG + JL REPDISP + MOV CL,TOTREG + CALL DISPREGLINE + CALL BLANK + CALL DISPFLAGS + CALL CRLF + MOV AX,[IPSAVE] + MOV WORD PTR [DISADD],AX + PUSH AX + MOV AX,[CSSAVE] + MOV WORD PTR [DISADD+2],AX + PUSH AX + MOV [NSEG],-1 + CALL DISASLN + POP WORD PTR DISADD+2 + POP WORD PTR DISADD + MOV AX,[NSEG] + CMP AL,-1 + JZ CRLFJ + CMP AH,-1 + JZ NOOVER + XCHG AL,AH +NOOVER: + CBW + MOV BX,AX + SHL BX,1 + MOV AX,WORD PTR [BX+SREG] + CALL OUT + XCHG AL,AH + CALL OUT + MOV AL,":" + CALL OUT + MOV DX,[INDEX] + CALL OUT16 + MOV AL,"=" + CALL OUT + MOV BX,[BX+SEGTAB] + PUSH DS + MOV DS,[BX] + MOV BX,DX + MOV DX,[BX] + POP DS + TEST BYTE PTR [AWORD],-1 + JZ OUT8 + CALL OUT16 +CRLFJ: + JMP CRLF +OUT8: + MOV AL,DL + CALL HEX + JMP CRLF + +DISPREGJ:JMP DISPREG + +; Perform register dump if no parameters or set register if a +; register designation is a parameter. + +REG: + CALL SCANP + JZ DISPREGJ + MOV DL,[SI] + INC SI + MOV DH,[SI] + CMP DH,13 + JZ FLAG + INC SI + CALL GETEOL + CMP DH," " + JZ FLAG + MOV DI,OFFSET DG:REGTAB + XCHG AX,DX + PUSH CS + POP ES + MOV CX,REGTABLEN + REPNZ SCASW + JNZ BADREG + OR CX,CX + JNZ NOTPC + DEC DI + DEC DI + MOV AX,CS:[DI-2] +NOTPC: + CALL OUT + MOV AL,AH + CALL OUT + CALL BLANK + PUSH DS + POP ES + LEA BX,[DI+REGDIF-2] + MOV DX,[BX] + CALL OUT16 + CALL CRLF + MOV AL,":" + CALL OUT + CALL INBUF + CALL SCANB + JZ RET4 + MOV CX,4 + CALL GETHEX1 + CALL GETEOL + MOV [BX],DX +RET4: RET +BADREG: + MOV AX,5200H+"B" ; BR ERROR + JMP ERR +FLAG: + CMP DL,"F" + JNZ BADREG + CALL DISPFLAGS + MOV AL,"-" + CALL OUT + CALL INBUF + CALL SCANB + XOR BX,BX + MOV DX,[FSAVE] +GETFLG: + LODSW + CMP AL,13 + JZ SAVCHG + CMP AH,13 + JZ FLGERR + MOV DI,OFFSET DG:FLAGTAB + MOV CX,32 + PUSH CS + POP ES + REPNE SCASW + JNZ FLGERR + MOV CH,CL + AND CL,0FH + MOV AX,1 + ROL AX,CL + TEST AX,BX + JNZ REPFLG + OR BX,AX + OR DX,AX + TEST CH,16 + JNZ NEXFLG + XOR DX,AX +NEXFLG: + CALL SCANP + JMP SHORT GETFLG +DISPREGLINE: + LODS CS:WORD PTR [SI] + CALL OUT + MOV AL,AH + CALL OUT + MOV AL,"=" + CALL OUT + MOV DX,[BX] + INC BX + INC BX + CALL OUT16 + CALL BLANK + CALL BLANK + LOOP DISPREGLINE + RET +REPFLG: + MOV AX,4600H+"D" ; DF ERROR +FERR: + CALL SAVCHG +ERR: + CALL OUT + MOV AL,AH + CALL OUT + MOV SI,OFFSET DG:ERRMES + JMP PRINT +SAVCHG: + MOV [FSAVE],DX + RET +FLGERR: + MOV AX,4600H+"B" ; BF ERROR + JMP SHORT FERR +DISPFLAGS: + MOV SI,OFFSET DG:FLAGTAB + MOV CX,16 + MOV DX,[FSAVE] +DFLAGS: + LODS CS:WORD PTR [SI] + SHL DX,1 + JC FLAGSET + MOV AX,CS:[SI+30] +FLAGSET: + OR AX,AX + JZ NEXTFLG + CALL OUT + MOV AL,AH + CALL OUT + CALL BLANK +NEXTFLG: + LOOP DFLAGS + RET + +; Input from the specified port and display result + +INPUT: + MOV CX,4 ; Port may have 4 digits + CALL GETHEX ; Get port number in DX + CALL GETEOL + IN AL,DX ; Variable port input + CALL HEX ; And display + JMP CRLF + +; Output a value to specified port. + +OUTPUT: + MOV CX,4 ; Port may have 4 digits + CALL GETHEX ; Get port number + PUSH DX ; Save while we get data + MOV CX,2 ; Byte output only + CALL GETHEX ; Get data to output + CALL GETEOL + XCHG AX,DX ; Output data in AL + POP DX ; Port in DX + OUT DX,AL ; Variable port output +RET5: RET +COMPARE: + CALL DSRANGE + PUSH CX + PUSH AX + PUSH DX + CALL ADDRESS ; Same segment + CALL GETEOL + POP SI + MOV DI,DX + MOV ES,AX + POP DS + POP CX ; Length + DEC CX + CALL COMP ; Do one less than total + INC CX ; CX=1 (do last one) +COMP: + REPE CMPSB + JZ RET5 +; Compare error. Print address, value; value, address. + DEC SI + CALL OUTSI + CALL BLANK + CALL BLANK + LODSB + CALL HEX + CALL BLANK + CALL BLANK + DEC DI + MOV AL,ES:[DI] + CALL HEX + CALL BLANK + CALL BLANK + CALL OUTDI + INC DI + CALL CRLF + XOR AL,AL + JMP SHORT COMP + +ZTRACE: +IF ZIBO +; just like trace except skips OVER next INT or CALL. + CALL SETADD ; get potential starting point + CALL GETEOL ; check for end of line + MOV [TCOUNT],1 ; only a single go at it + MOV ES,[CSSAVE] ; point to instruction to execute + MOV DI,[IPSAVE] ; include offset in segment + XOR DX,DX ; where to place breakpoint + MOV AL,ES:[DI] ; get the opcode + CMP AL,11101000B ; direct intra call + JZ ZTrace3 ; yes, 3 bytes + CMP AL,10011010B ; direct inter call + JZ ZTrace5 ; yes, 5 bytes + CMP AL,11111111B ; indirect? + JZ ZTraceModRM ; yes, go figure length + CMP AL,11001100B ; short interrupt? + JZ ZTrace1 ; yes, 1 byte + CMP AL,11001101B ; long interrupt? + JZ ZTrace2 ; yes, 2 bytes + CMP AL,11100010B ; loop + JZ ZTrace2 ; 2 byter + CMP AL,11100001B ; loopz/loope + JZ ZTrace2 ; 2 byter + CMP AL,11100000B ; loopnz/loopne + JZ ZTrace2 ; 2 byter + AND AL,11111110B ; check for rep + CMP AL,11110010B ; perhaps? + JNZ Step ; can't do anything special, step + MOV AL,ES:[DI+1] ; next instruction + AND AL,11111110B ; ignore w bit + CMP AL,10100100B ; MOVS + JZ ZTrace2 ; two byte + CMP AL,10100110B ; CMPS + JZ ZTrace2 ; two byte + CMP AL,10101110B ; SCAS + JZ ZTrace2 ; two byte + CMP AL,10101100B ; LODS + JZ ZTrace2 ; two byte + CMP AL,10101010B ; STOS + JZ ZTrace2 ; two byte + JMP Step ; bogus, do single step + +ZTraceModRM: + MOV AL,ES:[DI+1] ; get next byte + AND AL,11111000B ; get mod and type + CMP AL,01010000B ; indirect intra 8 bit offset? + JZ ZTrace3 ; yes, three byte whammy + CMP AL,01011000B ; indirect inter 8 bit offset + JZ ZTrace3 ; yes, three byte guy + CMP AL,10010000B ; indirect intra 16 bit offset? + JZ ZTrace4 ; four byte offset + CMP AL,10011000B ; indirect inter 16 bit offset? + JZ ZTrace4 ; four bytes + JMP Step ; can't figger out what this is! +ZTrace5:INC DX +ZTrace4:INC DX +ZTrace3:INC DX +ZTrace2:INC DX +ZTrace1:INC DX + ADD DI,DX ; offset to breakpoint instruction + MOV WORD PTR [BPTab],DI ; save offset + MOV WORD PTR [BPTab+2],ES ; save segment + MOV AL,ES:[DI] ; get next opcode byte + MOV BYTE PTR [BPTab+4],AL ; save it + MOV BYTE PTR ES:[DI],0CCh ; break point it + MOV [BrkCnt],1 ; only this breakpoint + JMP DExit ; start the operation! + ENDIF + +; Trace 1 instruction or the number of instruction specified +; by the parameter using 8086 trace mode. Registers are all +; set according to values in save area + +TRACE: + CALL SETADD + CALL SCANP + CALL HEXIN + MOV DX,1 + JC STOCNT + MOV CX,4 + CALL GETHEX +STOCNT: + MOV [TCOUNT],DX + CALL GETEOL +STEP: + MOV [BRKCNT],0 + OR BYTE PTR [FSAVE+1],1 +DEXIT: +IF NOT SYSVER + MOV BX,[USER_PROC_PDB] + MOV AH,SET_CURRENT_PDB + INT 21H +ENDIF + PUSH DS + XOR AX,AX + MOV DS,AX + MOV WORD PTR DS:[12],OFFSET DG:BREAKFIX ; Set vector 3--breakpoint instruction + MOV WORD PTR DS:[14],CS + MOV WORD PTR DS:[4],OFFSET DG:REENTER ; Set vector 1--Single step + MOV WORD PTR DS:[6],CS + CLI + + IF SETCNTC + MOV WORD PTR DS:[8CH],OFFSET DG:CONTC ; Set vector 23H (CTRL-C) + MOV WORD PTR DS:[8EH],CS + ENDIF + + POP DS + MOV SP,OFFSET DG:STACK + POP AX + POP BX + POP CX + POP DX + POP BP + POP BP + POP SI + POP DI + POP ES + POP ES + POP SS + MOV SP,[SPSAVE] + PUSH [FSAVE] + PUSH [CSSAVE] + PUSH [IPSAVE] + MOV DS,[DSSAVE] + IRET +STEP1: + CALL CRLF + CALL DISPREG + JMP SHORT STEP + +; Re-entry point from CTRL-C. Top of stack has address in 86-DOS for +; continuing, so we must pop that off. + +CONTC: + ADD SP,6 + JMP SHORT ReEnterReal + +; Re-entry point from breakpoint. Need to decrement instruction +; pointer so it points to location where breakpoint actually +; occured. + +BREAKFIX: + PUSH BP + MOV BP,SP + DEC WORD PTR [BP].OldIP + POP BP + JMP ReenterReal + +; Re-entry point from trace mode or interrupt during +; execution. All registers are saved so they can be +; displayed or modified. + +Interrupt_Frame STRUC +OldBP DW ? +OldIP DW ? +OldCS DW ? +OldF DW ? +OlderIP DW ? +OlderCS DW ? +OlderF DW ? +Interrupt_Frame ENDS + +REENTER: + PUSH BP + MOV BP,SP ; get a frame to address from + PUSH AX + MOV AX,CS + CMP AX,[BP].OldCS ; Did we interrupt ourselves? + JNZ GoReEnter ; no, go reenter + MOV AX,[BP].OldIP + CMP AX,OFFSET DG:NMIInt ; interrupt below NMI interrupt? + JB GoReEnter ; yes, go reenter + CMP [BP].OLDIP,OFFSET DG:NMIIntEnd + JAE GoReEnter ; interrupt above NMI interrupt? + POP AX ; restore state + POP BP + SUB SP,6 ; switch TRACE and NMI stack frames + PUSH BP + MOV BP,SP ; set up frame + PUSH AX ; get temp variable + MOV AX,[BP].OlderIP ; get NMI Vector + MOV [BP].OldIP,AX ; stuff in new NMI vector + MOV AX,[BP].OlderCS ; get NMI Vector + MOV [BP].OldCS,AX ; stuff in new NMI vector + MOV AX,[BP].OlderF ; get NMI Vector + AND AH,0FEh ; turn off Trace if present + MOV [BP].OldF,AX ; stuff in new NMI vector + MOV [BP].OlderF,AX + MOV [BP].OlderIP,OFFSET DG:ReEnter ; offset of routine + MOV [BP].OlderCS,CS ; and CS + POP AX + POP BP + IRET ; go try again +GoReEnter: + POP AX + POP BP +ReEnterReal: + MOV CS:[SPSAVE+SEGDIF],SP + MOV CS:[SSSAVE+SEGDIF],SS + MOV CS:[FSAVE],CS + MOV SS,CS:[FSAVE] + MOV SP,OFFSET DG:RSTACK + PUSH ES + PUSH DS + PUSH DI + PUSH SI + PUSH BP + DEC SP + DEC SP + PUSH DX + PUSH CX + PUSH BX + PUSH AX + PUSH SS + POP DS + MOV SS,[SSSAVE] + MOV SP,[SPSAVE] + POP [IPSAVE] + POP [CSSAVE] + POP AX + AND AH,0FEH ; turn off trace mode bit + MOV [FSAVE],AX + MOV [SPSAVE],SP + PUSH DS + POP ES + PUSH DS + POP SS + MOV SP,OFFSET DG:STACK + PUSH DS + XOR AX,AX + MOV DS,AX + + IF SETCNTC + MOV WORD PTR DS:[8CH],OFFSET DG:DABORT ; Set Ctrl-C vector + MOV WORD PTR DS:[8EH],CS + ENDIF + + POP DS + STI + CLD +IF NOT SYSVER + MOV AH,GET_CURRENT_PDB + INT 21H + MOV [USER_PROC_PDB],BX + MOV BX,DS + MOV AH,SET_CURRENT_PDB + INT 21H +ENDIF + DEC [TCOUNT] + JZ CheckDisp + JMP Step1 +CheckDisp: + MOV SI,OFFSET DG:BPTAB + MOV CX,[BRKCNT] + JCXZ SHOREG + PUSH ES +CLEARBP: + LES DI,DWORD PTR [SI] + ADD SI,4 + MOVSB + LOOP CLEARBP + POP ES +SHOREG: + CALL CRLF + CALL DISPREG + JMP COMMAND + +SETADD: + MOV BP,[CSSAVE] + CALL SCANP + CMP BYTE PTR [SI],"=" + JNZ RET$5 + INC SI + CALL ADDRESS + MOV [CSSAVE],AX + MOV [IPSAVE],DX +RET$5: RET + +; Jump to program, setting up registers according to the +; save area. up to 10 breakpoint addresses may be specified. + +GO: + CALL SETADD + XOR BX,BX + MOV DI,OFFSET DG:BPTAB +GO1: + CALL SCANP + JZ DEXEC + MOV BP,[CSSAVE] + CALL ADDRESS + MOV [DI],DX ; Save offset + MOV [DI+2],AX ; Save segment + ADD DI,5 ; Leave a little room + INC BX + CMP BX,1+BPMAX + JNZ GO1 + MOV AX,5000H+"B" ; BP ERROR + JMP ERR +DEXEC: + MOV [BRKCNT],BX + MOV CX,BX + JCXZ NOBP + MOV DI,OFFSET DG:BPTAB + PUSH DS +SETBP: + LDS SI,ES:DWORD PTR [DI] + ADD DI,4 + MOVSB + MOV BYTE PTR [SI-1],0CCH + LOOP SETBP + POP DS +NOBP: + MOV [TCOUNT],1 + JMP DEXIT + +SKIP_FILE: + MOV AH,CHAR_OPER + INT 21H + MOV [SWITCHAR],DL ; GET THE CURRENT SWITCH CHARACTER +FIND_DELIM: + LODSB + CALL DELIM1 + JZ GOTDELIM + CALL DELIM2 + JNZ FIND_DELIM +GOTDELIM: + DEC SI + RET + +PREPNAME: + MOV ES,DSSAVE + PUSH SI + MOV DI,81H +COMTAIL: + LODSB + STOSB + CMP AL,13 + JNZ COMTAIL + SUB DI,82H + XCHG AX,DI + MOV ES:(BYTE PTR [80H]),AL + POP SI + MOV DI,FCB + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H + INT 21H + MOV BYTE PTR [AXSAVE],AL ; Indicate analysis of first parm + CALL SKIP_FILE + MOV DI,6CH + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H + INT 21H + MOV BYTE PTR [AXSAVE+1],AL ; Indicate analysis of second parm +RET23: RET + + +; OPENS A XENIX PATHNAME SPECIFIED IN THE UNFORMATTED PARAMETERS +; VARIABLE [XNXCMD] SPECIFIES WHICH COMMAND TO OPEN IT WITH +; +; VARIABLE [HANDLE] CONTAINS THE HANDLE +; VARIABLE [EXTPTR] POINTS TO THE FILES EXTENSION + +DELETE_A_FILE: + MOV BYTE PTR [XNXCMD],UNLINK + JMP SHORT OC_FILE + +PARSE_A_FILE: + MOV BYTE PTR [XNXCMD],0 + JMP SHORT OC_FILE + +EXEC_A_FILE: + MOV BYTE PTR [XNXCMD],EXEC + MOV BYTE PTR [XNXOPT],1 + JMP SHORT OC_FILE + +OPEN_A_FILE: + MOV BYTE PTR [XNXCMD],OPEN + MOV BYTE PTR [XNXOPT],2 ; Try read write + CALL OC_FILE + JNC RET23 + MOV BYTE PTR [XNXCMD],OPEN + MOV BYTE PTR [XNXOPT],0 ; Try read only + JMP SHORT OC_FILE + +CREATE_A_FILE: + MOV BYTE PTR [XNXCMD],CREAT + +OC_FILE: + PUSH DS + PUSH ES + PUSH AX + PUSH BX + PUSH CX + PUSH DX + PUSH SI + XOR AX,AX + MOV [EXTPTR],AX ; INITIALIZE POINTER TO EXTENSIONS + MOV AH,CHAR_OPER + INT 21H + MOV [SWITCHAR],DL ; GET THE CURRENT SWITCH CHARACTER + + MOV SI,81H + +OPEN1: CALL GETCHRUP + CALL DELIM2 ; END OF LINE? + JZ OPEN4 + CALL DELIM1 ; SKIP LEADING DELIMITERS + JZ OPEN1 + + MOV DX,SI ; SAVE POINTER TO BEGINNING + DEC DX +OPEN2: CMP AL,"." ; LAST CHAR A "."? + JNZ OPEN3 + MOV [EXTPTR],SI ; SAVE POINTER TO THE EXTENSION +OPEN3: CALL GETCHRUP + CALL DELIM1 ; LOOK FOR END OF PATHNAME + JZ OPEN4 + CALL DELIM2 + JNZ OPEN2 + +OPEN4: DEC SI ; POINT BACK TO LAST CHAR + PUSH [SI] ; SAVE TERMINATION CHAR + MOV BYTE PTR [SI],0 ; NULL TERMINATE THE STRING + + MOV AL,[XNXOPT] + MOV AH,[XNXCMD] ; OPEN OR CREATE FILE + OR AH,AH + JZ OPNRET + MOV BX,OFFSET DG:EXEC_BLOCK + XOR CX,CX + INT 21H + MOV CS:[HANDLE],AX ; SAVE ERROR CODE OR HANDLE + +OPNRET: POP [SI] + + POP SI + POP DX + POP CX + POP BX + POP AX + POP ES + POP DS + RET + +GETCHRUP: + LODSB + CMP AL,"a" + JB GCUR + CMP AL,"z" + JA GCUR + SUB AL,32 + MOV [SI-1],AL +GCUR: RET + +DELIM0: CMP AL,"[" + JZ LIMRET +DELIM1: CMP AL," " ; SKIP THESE GUYS + JZ LIMRET + CMP AL,";" + JZ LIMRET + CMP AL,"=" + JZ LIMRET + CMP AL,9 + JZ LIMRET + CMP AL,"," + JMP SHORT LIMRET + +DELIM2: CMP AL,[SWITCHAR] ; STOP ON THESE GUYS + JZ LIMRET + CMP AL,13 +LIMRET: RET + +NAME: + CALL PREPNAME + MOV AL,BYTE PTR AXSAVE + MOV PARSERR,AL + PUSH ES + POP DS + PUSH CS + POP ES + MOV SI,FCB ; DS:SI points to user FCB + MOV DI,SI ; ES:DI points to DEBUG FCB + MOV CX,82 + REP MOVSW +RET6: RET + +BADNAM: + MOV DX,OFFSET DG:NAMBAD + JMP RESTART + +IFHEX: + CMP BYTE PTR [PARSERR],-1 ; Invalid drive specification? + JZ BADNAM + CALL PARSE_A_FILE + MOV BX,[EXTPTR] + CMP WORD PTR DS:[BX],"EH" ; "HE" + JNZ RET6 + CMP BYTE PTR DS:[BX+2],"X" + RET + +IFEXE: + PUSH BX + MOV BX,[EXTPTR] + CMP WORD PTR DS:[BX],"XE" ; "EX" + JNZ RETIF + CMP BYTE PTR DS:[BX+2],"E" +RETIF: POP BX + RET + +LOAD: + MOV BYTE PTR [RDFLG],READ + JMP SHORT DSKIO + +DWRITE: + MOV BYTE PTR [RDFLG],WRITE +DSKIO: + MOV BP,[CSSAVE] + CALL SCANB + JNZ PRIMIO + JMP DEFIO +PRIMIO: CALL ADDRESS + CALL SCANB + JNZ PRMIO + JMP FILEIO +PRMIO: PUSH AX ; Save segment + MOV BX,DX ; Put displacement in proper register + MOV CX,1 + CALL GETHEX ; Drive number must be 1 digit + PUSH DX + MOV CX,4 + CALL GETHEX ; Logical record number + PUSH DX + MOV CX,3 + CALL GETHEX ; Number of records + CALL GETEOL + MOV CX,DX + POP DX ; Logical record number + POP AX ; Drive number + CBW ; Turn off verify after write + MOV BYTE PTR DRVLET,AL ; Save drive in case of error + PUSH AX + PUSH BX + PUSH DX + MOV DL,AL + INC DL + MOV AH,GET_DPB + INT 21H + POP DX + POP BX + OR AL,AL + POP AX + POP DS ; Segment of transfer + JNZ DRVERRJ + CMP CS:BYTE PTR [RDFLG],WRITE + JZ ABSWRT + INT 25H ; Primitive disk read + JMP SHORT ENDABS + +ABSWRT: + INT 26H ; Primitive disk write +ENDABS: + JNC RET0 +DRVERRJ: JMP DRVERR + +RET0: + POPF + RET + +DEFIO: + MOV AX,[CSSAVE] ; Default segment + MOV DX,100H ; Default file I/O offset + CALL IFHEX + JNZ EXECHK + XOR DX,DX ; If HEX file, default OFFSET is zero +HEX2BINJ:JMP HEX2BIN + +FILEIO: +; AX and DX have segment and offset of transfer, respectively + CALL IFHEX + JZ HEX2BINJ +EXECHK: + CALL IFEXE + JNZ BINFIL + CMP BYTE PTR [RDFLG],READ + JZ EXELJ + MOV DX,OFFSET DG:EXEWRT + JMP RESTART ; Can't write .EXE files + +BINFIL: + CMP BYTE PTR [RDFLG],WRITE + JZ BINLOAD + CMP WORD PTR DS:[BX],4F00H + "C" ; "CO" + JNZ BINLOAD + CMP BYTE PTR DS:[BX+2],"M" + JNZ BINLOAD +EXELJ: + DEC SI + CMP DX,100H + JNZ PRER + CMP AX,[CSSAVE] + JZ OAF +PRER: JMP PERROR +OAF: CALL OPEN_A_FILE + JNC GDOPEN + MOV AX,exec_file_not_found + JMP EXECERR + +GDOPEN: XOR DX,DX + XOR CX,CX + MOV BX,[HANDLE] + MOV AL,2 + MOV AH,LSEEK + INT 21H + CALL IFEXE ; SUBTRACT 512 BYTES FOR EXE + JNZ BIN2 ; FILE LENGTH BECAUSE OF + SUB AX,512 ; THE HEADER +BIN2: MOV [BXSAVE],DX ; SET UP FILE SIZE IN DX:AX + MOV [CXSAVE],AX + MOV AH,CLOSE + INT 21H + JMP EXELOAD + +NO_MEM_ERR: + MOV DX,OFFSET DG:TOOBIG + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + JMP COMMAND + +WRTFILEJ: JMP WRTFILE +NOFILEJ: JMP NOFILE + +BINLOAD: + PUSH AX + PUSH DX + CMP BYTE PTR [RDFLG],WRITE + JZ WRTFILEJ + CALL OPEN_A_FILE + JC NOFILEJ + MOV BX,[HANDLE] + MOV AX,(LSEEK SHL 8) OR 2 + XOR DX,DX + MOV CX,DX + INT 21H ; GET SIZE OF FILE + MOV SI,DX + MOV DI,AX ; SIZE TO SI:DI + MOV AX,(LSEEK SHL 8) OR 0 + XOR DX,DX + MOV CX,DX + INT 21H ; RESET POINTER BACK TO BEGINNING + POP AX + POP BX + PUSH BX + PUSH AX ; TRANS ADDR TO BX:AX + ADD AX,15 + MOV CL,4 + SHR AX,CL + ADD BX,AX ; Start of transfer rounded up to seg + MOV DX,SI + MOV AX,DI ; DX:AX is size + MOV CX,16 + DIV CX + OR DX,DX + JZ NOREM + INC AX +NOREM: ; AX is number of paras in transfer + ADD AX,BX ; AX is first seg that need not exist + CMP AX,CS:[PDB_block_len] + JA NO_MEM_ERR + MOV CXSAVE,DI + MOV BXSAVE,SI + POP DX + POP AX + +RDWR: +; AX:DX is disk transfer address (segment:offset) +; SI:DI is length (32-bit number) + +RDWRLOOP: + MOV BX,DX ; Make a copy of the offset + AND DX,000FH ; Establish the offset in 0H-FH range + MOV CL,4 + SHR BX,CL ; Shift offset and + ADD AX,BX ; Add to segment register to get new Seg:offset + PUSH AX + PUSH DX ; Save AX,DX register pair + MOV WORD PTR [TRANSADD],DX + MOV WORD PTR [TRANSADD+2],AX + MOV CX,0FFF0H ; Keep request in segment + OR SI,SI ; Need > 64K? + JNZ BIGRDWR + MOV CX,DI ; Limit to amount requested +BIGRDWR: + PUSH DS + PUSH BX + MOV BX,[HANDLE] + MOV AH,[RDFLG] + LDS DX,[TRANSADD] + INT 21H ; Perform read or write + POP BX + POP DS + JC BADWR + CMP BYTE PTR [RDFLG],WRITE + JNZ GOODR + CMP CX,AX + JZ GOODR +BADWR: MOV CX,AX + STC + POP DX ; READ OR WRITE BOMBED OUT + POP AX + RET + +GOODR: + MOV CX,AX + SUB DI,CX ; Request minus amount transferred + SBB SI,0 ; Ripple carry + OR CX,CX ; End-of-file? + POP DX ; Restore DMA address + POP AX + JZ RET8 + ADD DX,CX ; Bump DMA address by transfer length + MOV BX,SI + OR BX,DI ; Finished with request + JNZ RDWRLOOP +RET8: CLC ; End-of-file not reached + RET + +NOFILE: + MOV DX,OFFSET DG:NOTFND +RESTARTJMP: + JMP RESTART + +WRTFILE: + CALL CREATE_A_FILE ; Create file we want to write to + MOV DX,OFFSET DG:NOROOM ; Creation error - report error + JC RESTARTJMP + MOV SI,BXSAVE ; Get high order number of bytes to transfer + CMP SI,000FH + JLE WRTSIZE ; Is bx less than or equal to FH + XOR SI,SI ; Ignore BX if greater than FH - set to zero +WRTSIZE: + MOV DX,OFFSET DG:WRTMES1 ; Print number bytes we are writing + CALL RPRBUF + OR SI,SI + JZ NXTBYT + MOV AX,SI + CALL DIGIT +NXTBYT: + MOV DX,CXSAVE + MOV DI,DX + CALL OUT16 ; Amount to write is SI:DI + MOV DX,OFFSET DG:WRTMES2 + CALL RPRBUF + POP DX + POP AX + CALL RDWR + JNC CLSFLE + CALL CLSFLE + CALL DELETE_A_FILE + MOV DX,OFFSET DG:NOSPACE + JMP RESTARTJMP + CALL CLSFLE + JMP COMMAND + +CLSFLE: + MOV AH,CLOSE + MOV BX,[HANDLE] + INT 21H + RET + +EXELOAD: + POP [RETSAVE] ; Suck up return addr + INC BYTE PTR [NEWEXEC] + MOV BX,[USER_PROC_PDB] + MOV AX,DS + CMP AX,BX + JZ DEBUG_CURRENT + JMP FIND_DEBUG + +DEBUG_CURRENT: + MOV AX,[DSSAVE] +DEBUG_FOUND: + MOV BYTE PTR [NEWEXEC],0 + MOV [HEADSAVE],AX + PUSH [RETSAVE] ; Get the return address back + PUSH AX + MOV BX,CS + SUB AX,BX + PUSH CS + POP ES + MOV BX,AX + ADD BX,10H ; RESERVE HEADER + MOV AH,SETBLOCK + INT 21H + POP AX + MOV WORD PTR [COM_LINE+2],AX + MOV WORD PTR [COM_FCB1+2],AX + MOV WORD PTR [COM_FCB2+2],AX + + CALL EXEC_A_FILE + JC EXECERR + CALL SET_TERMINATE_VECTOR ; Reset int 22 + MOV AH,GET_CURRENT_PDB + INT 21H + MOV [USER_PROC_PDB],BX + MOV [DSSAVE],BX + MOV [ESSAVE],BX + MOV ES,BX + MOV WORD PTR ES:[PDB_exit],OFFSET DG:TERMINATE + MOV WORD PTR ES:[PDB_exit+2],DS + LES DI,[COM_CSIP] + MOV [CSSAVE],ES + MOV [IPSAVE],DI + MOV WORD PTR [DISADD+2],ES + MOV WORD PTR [DISADD],DI + MOV WORD PTR [ASMADD+2],ES + MOV WORD PTR [ASMADD],DI + MOV WORD PTR [DEFDUMP+2],ES + MOV WORD PTR [DEFDUMP],DI + MOV BX,DS + MOV AH,SET_CURRENT_PDB + INT 21H + LES DI,[COM_SSSP] + MOV AX,ES:[DI] + INC DI + INC DI + MOV [AXSAVE],AX + MOV [SSSAVE],ES + MOV [SPSAVE],DI + RET + +EXECERR: + MOV DX,OFFSET DG:NOTFND + CMP AX,exec_file_not_found + JZ GOTEXECEMES + MOV DX,OFFSET DG:ACCMES + CMP AX,error_access_denied + JZ GOTEXECEMES + MOV DX,OFFSET DG:TOOBIG + CMP AX,exec_not_enough_memory + JZ GOTEXECEMES + MOV DX,OFFSET DG:EXEBAD + CMP AX,exec_bad_format + JZ GOTEXECEMES + MOV DX,OFFSET DG:EXECEMES +GOTEXECEMES: + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + JMP COMMAND + +HEX2BIN: + MOV [INDEX],DX + MOV DX,OFFSET DG:HEXWRT + CMP BYTE PTR [RDFLG],WRITE + JNZ RDHEX + JMP RESTARTJ2 +RDHEX: + MOV ES,AX + CALL OPEN_A_FILE + MOV DX,OFFSET DG:NOTFND + JNC HEXFND + JMP RESTART +HEXFND: + XOR BP,BP + MOV SI,OFFSET DG:(BUFFER+BUFSIZ) ; Flag input buffer as empty +READHEX: + CALL GETCH + CMP AL,":" ; Search for : to start line + JNZ READHEX + CALL GETBYT ; Get byte count + MOV CL,AL + MOV CH,0 + JCXZ HEXDONE + CALL GETBYT ; Get high byte of load address + MOV BH,AL + CALL GETBYT ; Get low byte of load address + MOV BL,AL + ADD BX,[INDEX] ; Add in offset + MOV DI,BX + CALL GETBYT ; Throw away type byte +READLN: + CALL GETBYT ; Get data byte + STOSB + CMP DI,BP ; Check if this is the largest address so far + JBE HAVBIG + MOV BP,DI ; Save new largest +HAVBIG: + LOOP READLN + JMP SHORT READHEX + +GETCH: + CMP SI,OFFSET DG:(BUFFER+BUFSIZ) + JNZ NOREAD + MOV DX,OFFSET DG:BUFFER + MOV SI,DX + MOV AH,READ + PUSH BX + PUSH CX + MOV CX,BUFSIZ + MOV BX,[HANDLE] + INT 21H + POP CX + POP BX + OR AX,AX + JZ HEXDONE +NOREAD: + LODSB + CMP AL,1AH + JZ HEXDONE + OR AL,AL + JNZ RET7 +HEXDONE: + MOV [CXSAVE],BP + MOV BXSAVE,0 + RET + +HEXDIG: + CALL GETCH + CALL HEXCHK + JNC RET7 + MOV DX,OFFSET DG:HEXERR +RESTARTJ2: + JMP RESTART + +GETBYT: + CALL HEXDIG + MOV BL,AL + CALL HEXDIG + SHL BL,1 + SHL BL,1 + SHL BL,1 + SHL BL,1 + OR AL,BL +RET7: RET + + +CODE ENDS + END DEBCOM2 diff --git a/DEBCONST.ASM b/DEBCONST.ASM new file mode 100644 index 0000000..e8f8c35 --- /dev/null +++ b/DEBCONST.ASM @@ -0,0 +1,1103 @@ +.xlist +.xcref +INCLUDE debequ.asm +INCLUDE dossym.asm +.list +.cref + +CODE SEGMENT PUBLIC BYTE 'CODE' +CODE ENDS + +CONST SEGMENT PUBLIC BYTE +CONST ENDS + +DATA SEGMENT PUBLIC BYTE +DATA ENDS + +DG GROUP CODE,CONST,DATA + +CODE SEGMENT PUBLIC BYTE 'CODE' + + EXTRN ALUFROMREG:NEAR,ALUTOREG:NEAR,ACCIMM:NEAR + EXTRN SEGOP:NEAR,ESPRE:NEAR,SSPRE:NEAR,CSPRE:NEAR + EXTRN DSPRE:NEAR,REGOP:NEAR,NOOPERANDS:NEAR + EXTRN SAVHEX:NEAR,SHORTJMP:NEAR,MOVSEGTO:NEAR + EXTRN WORDTOALU:NEAR,MOVSEGFROM:NEAR,GETADDR:NEAR + EXTRN XCHGAX:NEAR,LONGJMP:NEAR,LOADACC:NEAR,STOREACC:NEAR + EXTRN REGIMMB:NEAR,SAV16:NEAR,MEMIMM:NEAR,INT3:NEAR,SAV8:NEAR + EXTRN CHK10:NEAR,M8087:NEAR,M8087_D9:NEAR,M8087_DB:NEAR + EXTRN M8087_DD:NEAR,M8087_DF:NEAR,INFIXB:NEAR,INFIXW:NEAR + EXTRN OUTFIXB:NEAR,OUTFIXW:NEAR,JMPCALL:NEAR,INVARB:NEAR + EXTRN INVARW:NEAR,OUTVARB:NEAR,OUTVARW:NEAR,PREFIX:NEAR + EXTRN IMMED:NEAR,SIGNIMM:NEAR,SHIFT:NEAR,SHIFTV:NEAR + EXTRN GRP1:NEAR,GRP2:NEAR,REGIMMW:NEAR + + + EXTRN DB_OPER:NEAR,DW_OPER:NEAR,ASSEMLOOP:NEAR,GROUP2:NEAR + EXTRN NO_OPER:NEAR,GROUP1:NEAR,FGROUPP:NEAR,FGROUPX:NEAR + EXTRN FGROUPZ:NEAR,FD9_OPER:NEAR,FGROUPB:NEAR,FGROUP:NEAR + EXTRN FGROUPDS:NEAR,DCINC_OPER:NEAR,INT_OPER:NEAR,IN_OPER:NEAR + EXTRN DISP8_OPER:NEAR,JMP_OPER:NEAR,L_OPER:NEAR,MOV_OPER:NEAR + EXTRN OUT_OPER:NEAR,PUSH_OPER:NEAR,GET_DATA16:NEAR + EXTRN FGROUP3:NEAR,FGROUP3W:NEAR,FDE_OPER:NEAR,ESC_OPER:NEAR + EXTRN AA_OPER:NEAR,CALL_OPER:NEAR,FDB_OPER:NEAR,POP_OPER:NEAR + EXTRN ROTOP:NEAR,TST_OPER:NEAR,EX_OPER:NEAR + +CODE ENDS + +CONST SEGMENT PUBLIC BYTE + + PUBLIC REG8,REG16,SREG,SIZ8,DISTAB,DBMN,ADDMN,ADCMN,SUBMN + PUBLIC SBBMN,XORMN,ORMN,ANDMN,AAAMN,AADMN,AASMN,CALLMN,CBWMN + PUBLIC UPMN,DIMN,CMCMN,CMPMN,CWDMN,DAAMN,DASMN,DECMN,DIVMN + PUBLIC ESCMN,HLTMN,IDIVMN,IMULMN,INCMN,INTOMN,INTMN,INMN,IRETMN + PUBLIC JAMN,JCXZMN,JNCMN,JBEMN,JZMN,JGEMN,JGMN,JLEMN,JLMN,JMPMN + PUBLIC JNZMN,JPEMN,JNZMN,JPEMN,JPOMN,JNSMN,JNOMN,JOMN,JSMN,LAHFMN + PUBLIC LDSMN,LEAMN,LESMN,LOCKMN,LODBMN,LODWMN,LOOPNZMN,LOOPZMN + PUBLIC LOOPMN,MOVBMN,MOVWMN,MOVMN,MULMN,NEGMN,NOPMN,NOTMN,OUTMN + PUBLIC POPFMN,POPMN,PUSHFMN,PUSHMN,RCLMN,RCRMN,REPZMN,REPNZMN + PUBLIC RETFMN,RETMN,ROLMN,RORMN,SAHFMN,SARMN,SCABMN,SCAWMN,SHLMN + PUBLIC SHRMN,STCMN,DOWNMN,EIMN,STOBMN,STOWMN,TESTMN,WAITMN,XCHGMN + PUBLIC XLATMN,ESSEGMN,CSSEGMN,SSSEGMN,DSSEGMN,BADMN + + PUBLIC M8087_TAB,FI_TAB,SIZE_TAB,MD9_TAB,MD9_TAB2,MDB_TAB + PUBLIC MDB_TAB2,MDD_TAB,MDD_TAB2,MDF_TAB,OPTAB,MAXOP,SHFTAB,IMMTAB + PUBLIC GRP1TAB,GRP2TAB,SEGTAB,REGTAB,FLAGTAB,STACK + + PUBLIC AXSAVE,BXSAVE,CXSAVE,DXSAVE,BPSAVE,SPSAVE,SISAVE + PUBLIC DISAVE,DSSAVE,ESSAVE,SSSAVE,CSSAVE,IPSAVE,FSAVE,RSTACK + PUBLIC REGDIF,RDFLG,TOTREG,DSIZ,NOREGL,DISPB,LBUFSIZ,LBUFFCNT + PUBLIC LINEBUF,PFLAG,COLPOS + + IF SYSVER + PUBLIC CONFCB,POUT,COUT,CIN,IOBUFF,IOADDR,IOCALL,IOCOM,IOSTAT + PUBLIC IOCHRET,IOSEG,IOCNT + ENDIF + + PUBLIC QFLAG,NEWEXEC,RETSAVE,USER_PROC_PDB,HEADSAVE,EXEC_BLOCK + PUBLIC COM_LINE,COM_FCB1,COM_FCB2,COM_SSSP,COM_CSIP + +REG8 DB "ALCLDLBLAHCHDHBH" +REG16 DB "AXCXDXBXSPBPSIDI" +SREG DB "ESCSSSDS",0,0 +SIZ8 DB "BYWODWQWTB",0,0 +; 0 +DISTAB DW OFFSET DG:ADDMN,ALUFROMREG + DW OFFSET DG:ADDMN,ALUFROMREG + DW OFFSET DG:ADDMN,ALUTOREG + DW OFFSET DG:ADDMN,ALUTOREG + DW OFFSET DG:ADDMN,ACCIMM + DW OFFSET DG:ADDMN,ACCIMM + DW OFFSET DG:PUSHMN,SEGOP + DW OFFSET DG:POPMN,SEGOP + DW OFFSET DG:ORMN,ALUFROMREG + DW OFFSET DG:ORMN,ALUFROMREG + DW OFFSET DG:ORMN,ALUTOREG + DW OFFSET DG:ORMN,ALUTOREG + DW OFFSET DG:ORMN,ACCIMM + DW OFFSET DG:ORMN,ACCIMM + DW OFFSET DG:PUSHMN,SEGOP + DW OFFSET DG:POPMN,SEGOP +; 10H + DW OFFSET DG:ADCMN,ALUFROMREG + DW OFFSET DG:ADCMN,ALUFROMREG + DW OFFSET DG:ADCMN,ALUTOREG + DW OFFSET DG:ADCMN,ALUTOREG + DW OFFSET DG:ADCMN,ACCIMM + DW OFFSET DG:ADCMN,ACCIMM + DW OFFSET DG:PUSHMN,SEGOP + DW OFFSET DG:POPMN,SEGOP + DW OFFSET DG:SBBMN,ALUFROMREG + DW OFFSET DG:SBBMN,ALUFROMREG + DW OFFSET DG:SBBMN,ALUTOREG + DW OFFSET DG:SBBMN,ALUTOREG + DW OFFSET DG:SBBMN,ACCIMM + DW OFFSET DG:SBBMN,ACCIMM + DW OFFSET DG:PUSHMN,SEGOP + DW OFFSET DG:POPMN,SEGOP +; 20H + DW OFFSET DG:ANDMN,ALUFROMREG + DW OFFSET DG:ANDMN,ALUFROMREG + DW OFFSET DG:ANDMN,ALUTOREG + DW OFFSET DG:ANDMN,ALUTOREG + DW OFFSET DG:ANDMN,ACCIMM + DW OFFSET DG:ANDMN,ACCIMM + DW OFFSET DG:ESSEGMN,ESPRE + DW OFFSET DG:DAAMN,NOOPERANDS + DW OFFSET DG:SUBMN,ALUFROMREG + DW OFFSET DG:SUBMN,ALUFROMREG + DW OFFSET DG:SUBMN,ALUTOREG + DW OFFSET DG:SUBMN,ALUTOREG + DW OFFSET DG:SUBMN,ACCIMM + DW OFFSET DG:SUBMN,ACCIMM + DW OFFSET DG:CSSEGMN,CSPRE + DW OFFSET DG:DASMN,NOOPERANDS +; 30H + DW OFFSET DG:XORMN,ALUFROMREG + DW OFFSET DG:XORMN,ALUFROMREG + DW OFFSET DG:XORMN,ALUTOREG + DW OFFSET DG:XORMN,ALUTOREG + DW OFFSET DG:XORMN,ACCIMM + DW OFFSET DG:XORMN,ACCIMM + DW OFFSET DG:SSSEGMN,SSPRE + DW OFFSET DG:AAAMN,NOOPERANDS + DW OFFSET DG:CMPMN,ALUFROMREG + DW OFFSET DG:CMPMN,ALUFROMREG + DW OFFSET DG:CMPMN,ALUTOREG + DW OFFSET DG:CMPMN,ALUTOREG + DW OFFSET DG:CMPMN,ACCIMM + DW OFFSET DG:CMPMN,ACCIMM + DW OFFSET DG:DSSEGMN,DSPRE + DW OFFSET DG:AASMN,NOOPERANDS +; 40H + DW OFFSET DG:INCMN,REGOP + DW OFFSET DG:INCMN,REGOP + DW OFFSET DG:INCMN,REGOP + DW OFFSET DG:INCMN,REGOP + DW OFFSET DG:INCMN,REGOP + DW OFFSET DG:INCMN,REGOP + DW OFFSET DG:INCMN,REGOP + DW OFFSET DG:INCMN,REGOP + DW OFFSET DG:DECMN,REGOP + DW OFFSET DG:DECMN,REGOP + DW OFFSET DG:DECMN,REGOP + DW OFFSET DG:DECMN,REGOP + DW OFFSET DG:DECMN,REGOP + DW OFFSET DG:DECMN,REGOP + DW OFFSET DG:DECMN,REGOP + DW OFFSET DG:DECMN,REGOP +; 50H + DW OFFSET DG:PUSHMN,REGOP + DW OFFSET DG:PUSHMN,REGOP + DW OFFSET DG:PUSHMN,REGOP + DW OFFSET DG:PUSHMN,REGOP + DW OFFSET DG:PUSHMN,REGOP + DW OFFSET DG:PUSHMN,REGOP + DW OFFSET DG:PUSHMN,REGOP + DW OFFSET DG:PUSHMN,REGOP + DW OFFSET DG:POPMN,REGOP + DW OFFSET DG:POPMN,REGOP + DW OFFSET DG:POPMN,REGOP + DW OFFSET DG:POPMN,REGOP + DW OFFSET DG:POPMN,REGOP + DW OFFSET DG:POPMN,REGOP + DW OFFSET DG:POPMN,REGOP + DW OFFSET DG:POPMN,REGOP +; 60H + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX +; 70H + DW OFFSET DG:JOMN,SHORTJMP + DW OFFSET DG:JNOMN,SHORTJMP + DW OFFSET DG:JCMN,SHORTJMP + DW OFFSET DG:JNCMN,SHORTJMP + DW OFFSET DG:JZMN,SHORTJMP + DW OFFSET DG:JNZMN,SHORTJMP + DW OFFSET DG:JBEMN,SHORTJMP + DW OFFSET DG:JAMN,SHORTJMP + DW OFFSET DG:JSMN,SHORTJMP + DW OFFSET DG:JNSMN,SHORTJMP + DW OFFSET DG:JPEMN,SHORTJMP + DW OFFSET DG:JPOMN,SHORTJMP + DW OFFSET DG:JLMN,SHORTJMP + DW OFFSET DG:JGEMN,SHORTJMP + DW OFFSET DG:JLEMN,SHORTJMP + DW OFFSET DG:JGMN,SHORTJMP +; 80H + DW 0,IMMED + DW 0,IMMED + DW 0,IMMED + DW 0,SIGNIMM + DW OFFSET DG:TESTMN,ALUFROMREG + DW OFFSET DG:TESTMN,ALUFROMREG + DW OFFSET DG:XCHGMN,ALUFROMREG + DW OFFSET DG:XCHGMN,ALUFROMREG + DW OFFSET DG:MOVMN,ALUFROMREG + DW OFFSET DG:MOVMN,ALUFROMREG + DW OFFSET DG:MOVMN,ALUTOREG + DW OFFSET DG:MOVMN,ALUTOREG + DW OFFSET DG:MOVMN,MOVSEGTO + DW OFFSET DG:LEAMN,WORDTOALU + DW OFFSET DG:MOVMN,MOVSEGFROM + DW OFFSET DG:POPMN,GETADDR +; 90H + DW OFFSET DG:NOPMN,NOOPERANDS + DW OFFSET DG:XCHGMN,XCHGAX + DW OFFSET DG:XCHGMN,XCHGAX + DW OFFSET DG:XCHGMN,XCHGAX + DW OFFSET DG:XCHGMN,XCHGAX + DW OFFSET DG:XCHGMN,XCHGAX + DW OFFSET DG:XCHGMN,XCHGAX + DW OFFSET DG:XCHGMN,XCHGAX + DW OFFSET DG:CBWMN,NOOPERANDS + DW OFFSET DG:CWDMN,NOOPERANDS + DW OFFSET DG:CALLMN,LONGJMP + DW OFFSET DG:WAITMN,NOOPERANDS + DW OFFSET DG:PUSHFMN,NOOPERANDS + DW OFFSET DG:POPFMN,NOOPERANDS + DW OFFSET DG:SAHFMN,NOOPERANDS + DW OFFSET DG:LAHFMN,NOOPERANDS +; A0H + DW OFFSET DG:MOVMN,LOADACC + DW OFFSET DG:MOVMN,LOADACC + DW OFFSET DG:MOVMN,STOREACC + DW OFFSET DG:MOVMN,STOREACC + DW OFFSET DG:MOVBMN,NOOPERANDS + DW OFFSET DG:MOVWMN,NOOPERANDS + DW OFFSET DG:CMPBMN,NOOPERANDS + DW OFFSET DG:CMPWMN,NOOPERANDS + DW OFFSET DG:TESTMN,ACCIMM + DW OFFSET DG:TESTMN,ACCIMM + DW OFFSET DG:STOBMN,NOOPERANDS + DW OFFSET DG:STOWMN,NOOPERANDS + DW OFFSET DG:LODBMN,NOOPERANDS + DW OFFSET DG:LODWMN,NOOPERANDS + DW OFFSET DG:SCABMN,NOOPERANDS + DW OFFSET DG:SCAWMN,NOOPERANDS +; B0H + DW OFFSET DG:MOVMN,REGIMMB + DW OFFSET DG:MOVMN,REGIMMB + DW OFFSET DG:MOVMN,REGIMMB + DW OFFSET DG:MOVMN,REGIMMB + DW OFFSET DG:MOVMN,REGIMMB + DW OFFSET DG:MOVMN,REGIMMB + DW OFFSET DG:MOVMN,REGIMMB + DW OFFSET DG:MOVMN,REGIMMB + DW OFFSET DG:MOVMN,REGIMMW + DW OFFSET DG:MOVMN,REGIMMW + DW OFFSET DG:MOVMN,REGIMMW + DW OFFSET DG:MOVMN,REGIMMW + DW OFFSET DG:MOVMN,REGIMMW + DW OFFSET DG:MOVMN,REGIMMW + DW OFFSET DG:MOVMN,REGIMMW + DW OFFSET DG:MOVMN,REGIMMW +; C0H + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:RETMN,SAV16 + DW OFFSET DG:RETMN,NOOPERANDS + DW OFFSET DG:LESMN,WORDTOALU + DW OFFSET DG:LDSMN,WORDTOALU + DW OFFSET DG:MOVMN,MEMIMM + DW OFFSET DG:MOVMN,MEMIMM + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:RETFMN,SAV16 + DW OFFSET DG:RETFMN,NOOPERANDS + DW OFFSET DG:INTMN,INT3 + DW OFFSET DG:INTMN,SAV8 + DW OFFSET DG:INTOMN,NOOPERANDS + DW OFFSET DG:IRETMN,NOOPERANDS +; D0H + DW 0,SHIFT + DW 0,SHIFT + DW 0,SHIFTV + DW 0,SHIFTV + DW OFFSET DG:AAMMN,CHK10 + DW OFFSET DG:AADMN,CHK10 + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:XLATMN,NOOPERANDS + DW 0,M8087 ; d8 + DW 0,M8087_D9 ; d9 + DW 0,M8087 ; da + DW 0,M8087_DB ; db + DW 0,M8087 ; dc + DW 0,M8087_DD ; dd + DW 0,M8087 ; de + DW 0,M8087_DF ; df +; E0H + DW OFFSET DG:LOOPNZMN,SHORTJMP + DW OFFSET DG:LOOPZMN,SHORTJMP + DW OFFSET DG:LOOPMN,SHORTJMP + DW OFFSET DG:JCXZMN,SHORTJMP + DW OFFSET DG:INMN,INFIXB + DW OFFSET DG:INMN,INFIXW + DW OFFSET DG:OUTMN,OUTFIXB + DW OFFSET DG:OUTMN,OUTFIXW + DW OFFSET DG:CALLMN,JMPCALL + DW OFFSET DG:JMPMN,JMPCALL + DW OFFSET DG:JMPMN,LONGJMP + DW OFFSET DG:JMPMN,SHORTJMP + DW OFFSET DG:INMN,INVARB + DW OFFSET DG:INMN,INVARW + DW OFFSET DG:OUTMN,OUTVARB + DW OFFSET DG:OUTMN,OUTVARW +; F0H + DW OFFSET DG:LOCKMN,PREFIX + DW OFFSET DG:DBMN,SAVHEX + DW OFFSET DG:REPNZMN,PREFIX + DW OFFSET DG:REPZMN,PREFIX + DW OFFSET DG:HLTMN,NOOPERANDS + DW OFFSET DG:CMCMN,NOOPERANDS + DW 0,GRP1 + DW 0,GRP1 + DW OFFSET DG:CLCMN,NOOPERANDS + DW OFFSET DG:STCMN,NOOPERANDS + DW OFFSET DG:DIMN,NOOPERANDS + DW OFFSET DG:EIMN,NOOPERANDS + DW OFFSET DG:UPMN,NOOPERANDS + DW OFFSET DG:DOWNMN,NOOPERANDS + DW 0,GRP2 + DW 0,GRP2 + +DBMN DB "D","B"+80H + DB "D","W"+80H + DB ";"+80H +ADDMN DB "AD","D"+80H +ADCMN DB "AD","C"+80H +SUBMN DB "SU","B"+80H +SBBMN DB "SB","B"+80H +XORMN DB "XO","R"+80H +ORMN DB "O","R"+80H +ANDMN DB "AN","D"+80H +AAAMN DB "AA","A"+80H +AADMN DB "AA","D"+80H +AAMMN DB "AA","M"+80H +AASMN DB "AA","S"+80H +CALLMN DB "CAL","L"+80H +CBWMN DB "CB","W"+80H +CLCMN DB "CL","C"+80H +UPMN DB "CL","D"+80H ; CLD+80H +DIMN DB "CL","I"+80H +CMCMN DB "CM","C"+80H +CMPBMN DB "CMPS","B"+80H ; CMPSB +CMPWMN DB "CMPS","W"+80H ; CMPSW+80H +CMPMN DB "CM","P"+80H +CWDMN DB "CW","D"+80H +DAAMN DB "DA","A"+80H +DASMN DB "DA","S"+80H +DECMN DB "DE","C"+80H +DIVMN DB "DI","V"+80H +ESCMN DB "ES","C"+80H + DB "FXC","H"+80H + DB "FFRE","E"+80H + DB "FCOMP","P"+80H + DB "FCOM","P"+80H + DB "FCO","M"+80H + DB "FICOM","P"+80H + DB "FICO","M"+80H + DB "FNO","P"+80H + DB "FCH","S"+80H + DB "FAB","S"+80H + DB "FTS","T"+80H + DB "FXA","M"+80H + DB "FLDL2","T"+80H + DB "FLDL2","E"+80H + DB "FLDLG","2"+80H + DB "FLDLN","2"+80H + DB "FLDP","I"+80H + DB "FLD","1"+80H + DB "FLD","Z"+80H + DB "F2XM","1"+80H + DB "FYL2XP","1"+80H + DB "FYL2","X"+80H + DB "FPTA","N"+80H + DB "FPATA","N"+80H + DB "FXTRAC","T"+80H + DB "FDECST","P"+80H + DB "FINCST","P"+80H + DB "FPRE","M"+80H + DB "FSQR","T"+80H + DB "FRNDIN","T"+80H + DB "FSCAL","E"+80H + DB "FINI","T"+80H + DB "FDIS","I"+80H + DB "FEN","I"+80H + DB "FCLE","X"+80H + DB "FBL","D"+80H + DB "FBST","P"+80H + DB "FLDC","W"+80H + DB "FSTC","W"+80H + DB "FSTS","W"+80H + DB "FSTEN","V"+80H + DB "FLDEN","V"+80H + DB "FSAV","E"+80H + DB "FRSTO","R"+80H + DB "FADD","P"+80H + DB "FAD","D"+80H + DB "FIAD","D"+80H + DB "FSUBR","P"+80H + DB "FSUB","R"+80H + DB "FSUB","P"+80H + DB "FSU","B"+80H + DB "FISUB","R"+80H + DB "FISU","B"+80H + DB "FMUL","P"+80H + DB "FMU","L"+80H + DB "FIMU","L"+80H + DB "FDIVR","P"+80H + DB "FDIV","R"+80H + DB "FDIV","P"+80H + DB "FDI","V"+80H + DB "FIDIV","R"+80H + DB "FIDI","V"+80H + DB "FWAI","T"+80H + DB "FIL","D"+80H + DB "FL","D"+80H + DB "FST","P"+80H + DB "FS","T"+80H + DB "FIST","P"+80H + DB "FIS","T"+80H +HLTMN DB "HL","T"+80H +IDIVMN DB "IDI","V"+80H +IMULMN DB "IMU","L"+80H +INCMN DB "IN","C"+80H +INTOMN DB "INT","O"+80H +INTMN DB "IN","T"+80H +INMN DB "I","N"+80H ; IN +IRETMN DB "IRE","T"+80H + DB "JNB","E"+80H + DB "JA","E"+80H +JAMN DB "J","A"+80H +JCXZMN DB "JCX","Z"+80H +JNCMN DB "JN","B"+80H +JBEMN DB "JB","E"+80H +JCMN DB "J","B"+80H + DB "JN","C"+80H + DB "J","C"+80H + DB "JNA","E"+80H + DB "JN","A"+80H +JZMN DB "J","Z"+80H + DB "J","E"+80H +JGEMN DB "JG","E"+80H +JGMN DB "J","G"+80H + DB "JNL","E"+80H + DB "JN","L"+80H +JLEMN DB "JL","E"+80H +JLMN DB "J","L"+80H + DB "JNG","E"+80H + DB "JN","G"+80H +JMPMN DB "JM","P"+80H +JNZMN DB "JN","Z"+80H + DB "JN","E"+80H +JPEMN DB "JP","E"+80H +JPOMN DB "JP","O"+80H + DB "JN","P"+80H +JNSMN DB "JN","S"+80H +JNOMN DB "JN","O"+80H +JOMN DB "J","O"+80H +JSMN DB "J","S"+80H + DB "J","P"+80H +LAHFMN DB "LAH","F"+80H +LDSMN DB "LD","S"+80H +LEAMN DB "LE","A"+80H +LESMN DB "LE","S"+80H +LOCKMN DB "LOC","K"+80H +LODBMN DB "LODS","B"+80H ; LODSB +LODWMN DB "LODS","W"+80H ; LODSW+80H +LOOPNZMN DB "LOOPN","Z"+80H +LOOPZMN DB "LOOP","Z"+80H + DB "LOOPN","E"+80H + DB "LOOP","E"+80H +LOOPMN DB "LOO","P"+80H +MOVBMN DB "MOVS","B"+80H ; MOVSB +MOVWMN DB "MOVS","W"+80H ; MOVSW+80H +MOVMN DB "MO","V"+80H +MULMN DB "MU","L"+80H +NEGMN DB "NE","G"+80H +NOPMN DB "NO","P"+80H +NOTMN DB "NO","T"+80H +OUTMN DB "OU","T"+80H ; OUT +POPFMN DB "POP","F"+80H +POPMN DB "PO","P"+80H +PUSHFMN DB "PUSH","F"+80H +PUSHMN DB "PUS","H"+80H +RCLMN DB "RC","L"+80H +RCRMN DB "RC","R"+80H +REPZMN DB "REP","Z"+80H +REPNZMN DB "REPN","Z"+80H + DB "REP","E"+80H + DB "REPN","E"+80H + DB "RE","P"+80H +RETFMN DB "RET","F"+80H +RETMN DB "RE","T"+80H +ROLMN DB "RO","L"+80H +RORMN DB "RO","R"+80H +SAHFMN DB "SAH","F"+80H +SARMN DB "SA","R"+80H +SCABMN DB "SCAS","B"+80H ; SCASB +SCAWMN DB "SCAS","W"+80H ; SCASW+80H +SHLMN DB "SH","L"+80H +SHRMN DB "SH","R"+80H +STCMN DB "ST","C"+80H +DOWNMN DB "ST","D"+80H ; STD +EIMN DB "ST","I"+80H ; STI +STOBMN DB "STOS","B"+80H ; STOSB +STOWMN DB "STOS","W"+80H ; STOSW+80H +TESTMN DB "TES","T"+80H +WAITMN DB "WAI","T"+80H +XCHGMN DB "XCH","G"+80H +XLATMN DB "XLA","T"+80H +ESSEGMN DB "ES",":"+80H +CSSEGMN DB "CS",":"+80H +SSSEGMN DB "SS",":"+80H +DSSEGMN DB "DS",":"+80H +BADMN DB "??","?"+80H + +M8087_TAB DB "ADD$MUL$COM$COMP$SUB$SUBR$DIV$DIVR$" +FI_TAB DB "F$FI$F$FI$" +SIZE_TAB DB "DWORD PTR $DWORD PTR $QWORD PTR $WORD PTR $" + DB "BYTE PTR $TBYTE PTR $" + +MD9_TAB DB "LD$@$ST$STP$LDENV$LDCW$STENV$STCW$" +MD9_TAB2 DB "CHS$ABS$@$@$TST$XAM$@$@$LD1$LDL2T$LDL2E$" + DB "LDPI$LDLG2$LDLN2$LDZ$@$2XM1$YL2X$PTAN$PATAN$XTRACT$" + DB "@$DECSTP$INCSTP$PREM$YL2XP1$SQRT$@$RNDINT$SCALE$@$@$" + +MDB_TAB DB "ILD$@$IST$ISTP$@$LD$@$STP$" +MDB_TAB2 DB "ENI$DISI$CLEX$INIT$" + +MDD_TAB DB "LD$@$ST$STP$RSTOR$@$SAVE$STSW$" +MDD_TAB2 DB "FREE$XCH$ST$STP$" + +MDF_TAB DB "ILD$@$IST$ISTP$BLD$ILD$BSTP$ISTP$" + + +OPTAB DB 11111111B ; DB + DW DB_OPER + DB 11111111B ; DW + DW DW_OPER + DB 11111111B ; COMMENT + DW ASSEMLOOP + DB 0 * 8 ; ADD + DW GROUP2 + DB 2 * 8 ; ADC + DW GROUP2 + DB 5 * 8 ; SUB + DW GROUP2 + DB 3 * 8 ; SBB + DW GROUP2 + DB 6 * 8 ; XOR + DW GROUP2 + DB 1 * 8 ; OR + DW GROUP2 + DB 4 * 8 ; AND + DW GROUP2 + DB 00110111B ; AAA + DW NO_OPER + DB 11010101B ; AAD + DW AA_OPER + DB 11010100B ; AAM + DW AA_OPER + DB 00111111B ; AAS + DW NO_OPER + DB 2 * 8 ; CALL + DW CALL_OPER + DB 10011000B ; CBW + DW NO_OPER + DB 11111000B ; CLC + DW NO_OPER + DB 11111100B ; CLD + DW NO_OPER + DB 11111010B ; DIM + DW NO_OPER + DB 11110101B ; CMC + DW NO_OPER + DB 10100110B ; CMPB + DW NO_OPER + DB 10100111B ; CMPW + DW NO_OPER + DB 7 * 8 ; CMP + DW GROUP2 + DB 10011001B ; CWD + DW NO_OPER + DB 00100111B ; DAA + DW NO_OPER + DB 00101111B ; DAS + DW NO_OPER + DB 1 * 8 ; DEC + DW DCINC_OPER + DB 6 * 8 ; DIV + DW GROUP1 + DB 11011000B ; ESC + DW ESC_OPER + DB 00001001B ; FXCH + DW FGROUPP + DB 00101000B ; FFREE + DW FGROUPP + DB 11011001B ; FCOMPP + DW FDE_OPER + DB 00000011B ; FCOMP + DW FGROUPX ; Exception to normal P instructions + DB 00000010B ; FCOM + DW FGROUPX + DB 00010011B ; FICOMP + DW FGROUPZ + DB 00010010B ; FICOM + DW FGROUPZ + DB 11010000B ; FNOP + DW FD9_OPER + DB 11100000B ; FCHS + DW FD9_OPER + DB 11100001B ; FABS + DW FD9_OPER + DB 11100100B ; FTST + DW FD9_OPER + DB 11100101B ; FXAM + DW FD9_OPER + DB 11101001B ; FLDL2T + DW FD9_OPER + DB 11101010B ; FLDL2E + DW FD9_OPER + DB 11101100B ; FLDLG2 + DW FD9_OPER + DB 11101101B ; FLDLN2 + DW FD9_OPER + DB 11101011B ; FLDPI + DW FD9_OPER + DB 11101000B ; FLD1 + DW FD9_OPER + DB 11101110B ; FLDZ + DW FD9_OPER + DB 11110000B ; F2XM1 + DW FD9_OPER + DB 11111001B ; FYL2XP1 + DW FD9_OPER + DB 11110001B ; FYL2X + DW FD9_OPER + DB 11110010B ; FPTAN + DW FD9_OPER + DB 11110011B ; FPATAN + DW FD9_OPER + DB 11110100B ; FXTRACT + DW FD9_OPER + DB 11110110B ; FDECSTP + DW FD9_OPER + DB 11110111B ; FINCSTP + DW FD9_OPER + DB 11111000B ; FPREM + DW FD9_OPER + DB 11111010B ; FSQRT + DW FD9_OPER + DB 11111100B ; FRNDINT + DW FD9_OPER + DB 11111101B ; FSCALE + DW FD9_OPER + DB 11100011B ; FINIT + DW FDB_OPER + DB 11100001B ; FDISI + DW FDB_OPER + DB 11100000B ; FENI + DW FDB_OPER + DB 11100010B ; FCLEX + DW FDB_OPER + DB 00111100B ; FBLD + DW FGROUPB + DB 00111110B ; FBSTP + DW FGROUPB + DB 00001101B ; FLDCW + DW FGROUP3W + DB 00001111B ; FSTCW + DW FGROUP3W + DB 00101111B ; FSTSW + DW FGROUP3W + DB 00001110B ; FSTENV + DW FGROUP3 + DB 00001100B ; FLDENV + DW FGROUP3 + DB 00101110B ; FSAVE + DW FGROUP3 + DB 00101100B ; FRSTOR + DW FGROUP3 + DB 00110000B ; FADDP + DW FGROUPP + DB 00000000B ; FADD + DW FGROUP + DB 00010000B ; FIADD + DW FGROUPZ + DB 00110100B ; FSUBRP + DW FGROUPP + DB 00000101B ; FSUBR + DW FGROUPDS + DB 00110101B ; FSUBP + DW FGROUPP + DB 00000100B ; FSUB + DW FGROUPDS + DB 00010101B ; FISUBR + DW FGROUPZ + DB 00010100B ; FISUB + DW FGROUPZ + DB 00110001B ; FMULP + DW FGROUPP + DB 00000001B ; FMUL + DW FGROUP + DB 00010001B ; FIMUL + DW FGROUPZ + DB 00110110B ; FDIVRP + DW FGROUPP + DB 00000111B ; FDIVR + DW FGROUPDS + DB 00110111B ; FDIVP + DW FGROUPP + DB 00000110B ; FDIV + DW FGROUPDS + DB 00010111B ; FIDIVR + DW FGROUPZ + DB 00010110B ; FIDIV + DW FGROUPZ + DB 10011011B ; FWAIT + DW NO_OPER + DB 00011000B ; FILD + DW FGROUPZ + DB 00001000B ; FLD + DW FGROUPX + DB 00001011B ; FSTP + DW FGROUPX + DB 00101010B ; FST + DW FGROUPX + DB 00011011B ; FISTP + DW FGROUPZ + DB 00011010B ; FIST + DW FGROUPZ + DB 11110100B ; HLT + DW NO_OPER + DB 7 * 8 ; IDIV + DW GROUP1 + DB 5 * 8 ; IMUL + DW GROUP1 + DB 0 * 8 ; INC + DW DCINC_OPER + DB 11001110B ; INTO + DW NO_OPER + DB 11001100B ; INTM + DW INT_OPER + DB 11101100B ; IN + DW IN_OPER + DB 11001111B ; IRET + DW NO_OPER + DB 01110111B ; JNBE + DW DISP8_OPER + DB 01110011B ; JAE + DW DISP8_OPER + DB 01110111B ; JA + DW DISP8_OPER + DB 11100011B ; JCXZ + DW DISP8_OPER + DB 01110011B ; JNB + DW DISP8_OPER + DB 01110110B ; JBE + DW DISP8_OPER + DB 01110010B ; JB + DW DISP8_OPER + DB 01110011B ; JNC + DW DISP8_OPER + DB 01110010B ; JC + DW DISP8_OPER + DB 01110010B ; JNAE + DW DISP8_OPER + DB 01110110B ; JNA + DW DISP8_OPER + DB 01110100B ; JZ + DW DISP8_OPER + DB 01110100B ; JE + DW DISP8_OPER + DB 01111101B ; JGE + DW DISP8_OPER + DB 01111111B ; JG + DW DISP8_OPER + DB 01111111B ; JNLE + DW DISP8_OPER + DB 01111101B ; JNL + DW DISP8_OPER + DB 01111110B ; JLE + DW DISP8_OPER + DB 01111100B ; JL + DW DISP8_OPER + DB 01111100B ; JNGE + DW DISP8_OPER + DB 01111110B ; JNG + DW DISP8_OPER + DB 4 * 8 ; JMP + DW JMP_OPER + DB 01110101B ; JNZ + DW DISP8_OPER + DB 01110101B ; JNE + DW DISP8_OPER + DB 01111010B ; JPE + DW DISP8_OPER + DB 01111011B ; JPO + DW DISP8_OPER + DB 01111011B ; JNP + DW DISP8_OPER + DB 01111001B ; JNS + DW DISP8_OPER + DB 01110001B ; JNO + DW DISP8_OPER + DB 01110000B ; JO + DW DISP8_OPER + DB 01111000B ; JS + DW DISP8_OPER + DB 01111010B ; JP + DW DISP8_OPER + DB 10011111B ; LAHF + DW NO_OPER + DB 11000101B ; LDS + DW L_OPER + DB 10001101B ; LEA + DW L_OPER + DB 11000100B ; LES + DW L_OPER + DB 11110000B ; LOCK + DW NO_OPER + DB 10101100B ; LODB + DW NO_OPER + DB 10101101B ; LODW + DW NO_OPER + DB 11100000B ; LOOPNZ + DW DISP8_OPER + DB 11100001B ; LOOPZ + DW DISP8_OPER + DB 11100000B ; LOOPNE + DW DISP8_OPER + DB 11100001B ; LOOPE + DW DISP8_OPER + DB 11100010B ; LOOP + DW DISP8_OPER + DB 10100100B ; MOVB + DW NO_OPER + DB 10100101B ; MOVW + DW NO_OPER + DB 11000110B ; MOV + DW MOV_OPER + DB 4 * 8 ; MUL + DW GROUP1 + DB 3 * 8 ; NEG + DW GROUP1 + DB 10010000B ; NOP + DW NO_OPER + DB 2 * 8 ; NOT + DW GROUP1 + DB 11101110B ; OUT + DW OUT_OPER + DB 10011101B ; POPF + DW NO_OPER + DB 0 * 8 ; POP + DW POP_OPER + DB 10011100B ; PUSHF + DW NO_OPER + DB 6 * 8 ; PUSH + DW PUSH_OPER + DB 2 * 8 ; RCL + DW ROTOP + DB 3 * 8 ; RCR + DW ROTOP + DB 11110011B ; REPZ + DW NO_OPER + DB 11110010B ; REPNZ + DW NO_OPER + DB 11110011B ; REPE + DW NO_OPER + DB 11110010B ; REPNE + DW NO_OPER + DB 11110011B ; REP + DW NO_OPER + DB 11001011B ; RETF + DW GET_DATA16 + DB 11000011B ; RET + DW GET_DATA16 + DB 0 * 8 ; ROL + DW ROTOP + DB 1 * 8 ; ROR + DW ROTOP + DB 10011110B ; SAHF + DW NO_OPER + DB 7 * 8 ; SAR + DW ROTOP + DB 10101110B ; SCAB + DW NO_OPER + DB 10101111B ; SCAW + DW NO_OPER + DB 4 * 8 ; SHL + DW ROTOP + DB 5 * 8 ; SHR + DW ROTOP + DB 11111001B ; STC + DW NO_OPER + DB 11111101B ; STD + DW NO_OPER + DB 11111011B ; EI + DW NO_OPER + DB 10101010B ; STOB + DW NO_OPER + DB 10101011B ; STOW + DW NO_OPER + DB 11110110B ; TEST + DW TST_OPER + DB 10011011B ; WAIT + DW NO_OPER + DB 10000110B ; XCHG + DW EX_OPER + DB 11010111B ; XLAT + DW NO_OPER + DB 00100110B ; ESSEG + DW NO_OPER + DB 00101110B ; CSSEG + DW NO_OPER + DB 00110110B ; SSSEG + DW NO_OPER + DB 00111110B ; DSSEG + DW NO_OPER + +zzopcode label byte +MAXOP = (zzopcode-optab)/3 + +SHFTAB DW OFFSET DG:ROLMN,OFFSET DG:RORMN,OFFSET DG:RCLMN + DW OFFSET DG:RCRMN,OFFSET DG:SHLMN,OFFSET DG:SHRMN + DW OFFSET DG:BADMN,OFFSET DG:SARMN + +IMMTAB DW OFFSET DG:ADDMN,OFFSET DG:ORMN,OFFSET DG:ADCMN + DW OFFSET DG:SBBMN,OFFSET DG:ANDMN,OFFSET DG:SUBMN + DW OFFSET DG:XORMN,OFFSET DG:CMPMN + +GRP1TAB DW OFFSET DG:TESTMN,OFFSET DG:BADMN,OFFSET DG:NOTMN + DW OFFSET DG:NEGMN,OFFSET DG:MULMN,OFFSET DG:IMULMN + DW OFFSET DG:DIVMN,OFFSET DG:IDIVMN + +GRP2TAB DW OFFSET DG:INCMN,OFFSET DG:DECMN,OFFSET DG:CALLMN + DW OFFSET DG:CALLMN,OFFSET DG:JMPMN,OFFSET DG:JMPMN + DW OFFSET DG:PUSHMN,OFFSET DG:BADMN + +SEGTAB DW OFFSET DG:ESSAVE,OFFSET DG:CSSAVE,OFFSET DG:SSSAVE + DW OFFSET DG:DSSAVE + +REGTAB DB "AXBXCXDXSPBPSIDIDSESSSCSIPPC" + +; Flags are ordered to correspond with the bits of the flag +; register, most significant bit first, zero if bit is not +; a flag. First 16 entries are for bit set, second 16 for +; bit reset. + +FLAGTAB DW 0 + DW 0 + DW 0 + DW 0 + DB "OV" + DB "DN" + DB "EI" ; "STI" + DW 0 + DB "NG" + DB "ZR" + DW 0 + DB "AC" + DW 0 + DB "PE" + DW 0 + DB "CY" + DW 0 + DW 0 + DW 0 + DW 0 + DB "NV" + DB "UP" ; "CLD" + DB "DI" + DW 0 + DB "PL" + DB "NZ" + DW 0 + DB "NA" + DW 0 + DB "PO" + DW 0 + DB "NC" + + DB 80H DUP(?) +STACK LABEL BYTE + + +; Register save area + +AXSAVE DW 0 +BXSAVE DW 0 +CXSAVE DW 0 +DXSAVE DW 0 +SPSAVE DW 5AH +BPSAVE DW 0 +SISAVE DW 0 +DISAVE DW 0 +DSSAVE DW 0 +ESSAVE DW 0 +RSTACK LABEL WORD ; Stack set here so registers can be saved by pushing +SSSAVE DW 0 +CSSAVE DW 0 +IPSAVE DW 100H +FSAVE DW 0 + +REGDIF EQU AXSAVE-REGTAB + +; RAM area. + +RDFLG DB READ +TOTREG DB 13 +DSIZ DB 0FH +NOREGL DB 8 +DISPB DW 128 + +LBUFSIZ DB BUFLEN +LBUFFCNT DB 0 +LINEBUF DB 0DH + DB BUFLEN DUP (?) +PFLAG DB 0 +COLPOS DB 0 + + IF SYSVER +CONFCB DB 0 + DB "PRN " + DB 25 DUP(0) + +POUT DD ? +COUT DD ? +CIN DD ? +IOBUFF DB 3 DUP (?) +IOADDR DD ? + +IOCALL DB 22 + DB 0 +IOCOM DB 0 +IOSTAT DW 0 + DB 8 DUP (0) +IOCHRET DB 0 + DW OFFSET DG:IOBUFF +IOSEG DW ? +IOCNT DW 1 + DW 0 + ENDIF + +QFLAG DB 0 +NEWEXEC DB 0 +RETSAVE DW ? + +USER_PROC_PDB DW ? + +HEADSAVE DW ? + +EXEC_BLOCK LABEL BYTE + DW 0 +COM_LINE LABEL DWORD + DW 80H + DW ? +COM_FCB1 LABEL DWORD + DW FCB + DW ? +COM_FCB2 LABEL DWORD + DW FCB + 10H + DW ? +COM_SSSP DD ? +COM_CSIP DD ? + +CONST ENDS + END + \ No newline at end of file diff --git a/DEBDATA.ASM b/DEBDATA.ASM new file mode 100644 index 0000000000000000000000000000000000000000..fbe4a3fdd5b8dd5258989c269f8068451869b06c GIT binary patch literal 2816 zcmdO^$jK}&;pNh+NG?iEffE=LX?C%#Gq61P2vK&N%6k%~NNSc=mBniS$ zpC|+*7G;)Hy5%IM>qPiP_y>f5C}&?6o#1fK5N8j^ARX6;kbsaN9S=u87av!hkRV6D zU`H1hEG9Vy1-k|X={N@aI=Z;%xOjq;fhcFc5RhPSfR3l1i))0Ai>sSUsBZv>_Hp&Y zG$_c`J=ihKRVNrq`@6Y;`5~^p0Xj~hZf>qYI!=)xAY=Ulz+vDR?jMB3MM0og^VRY7 zbaC@>(ed?nan>mntV6dxiyt7{jrh6QNgI#?Mb-ygbPX+_8q3kn zNZP>0_y@T9#XH8kdHT32g!n52xCXiT2l?`H!BQXCnF5=OI#yDT>XMQ{rz~kAjzH>LtqYp=-}mo zUFBc?ZAwt=>rN7Cy<#6ps0eBJSZ9=r4XtRw040x$DWr9R6c=B zfkzFeOI64(N`W{gvA8%j zH$FM9L?JORMFGq+gqmmw(}xmrkg^!Jlre586Wmg!xTVanNFjv4ESw&z0Q)MbvLrRB zG!2}nK$QeMvp9u9a|k3egUtdF)(RnsNja$srNyZ!3Q3g;KAyoLyj)J8ss$-EI0b-` zfðBHncYXv8G3@em?3<8xBZa$zU1UzbZxxkeXl5zIDT;Q4sO$by?p$b9jER;y` z1J_?jLSTnr64nY)u0j3^zOIgb!3uu<3Vxx!POd=;!LFdj0HpRqGK7~4QWK&GK`KEM zAxMRYA_S=%QG_5BB~nV~DyR fQMxLyC;?Ty&{`N?yg=G3=q)^$f#CX@ff4`!o@!nH literal 0 HcmV?d00001 diff --git a/DEBEQU.ASM b/DEBEQU.ASM new file mode 100644 index 0000000..5a20f01 --- /dev/null +++ b/DEBEQU.ASM @@ -0,0 +1,32 @@ +FALSE EQU 0 +TRUE EQU NOT FALSE + +IBMVER EQU true ; Set conditional switches +MSVER EQU false + +SYSVER EQU FALSE ; if true, i/o direct to bios + ; so DOS can be debugged +IBMJAPAN EQU FALSE + +SETCNTC EQU TRUE ; If this is FALSE, DEBUG will not set + ; the Control C int vector + +ZIBO EQU TRUE ; true if P traces over interrupts + ; and calls and dump looks pretty +PROMPT EQU "-" +FCB EQU 5CH +EXEFCB EQU FCB +BUFLEN EQU 80 ; Maximum length of line input buffer +BPMAX EQU 10 ; Maximum number of breakpoints +BPLEN EQU 5*BPMAX ; Length of breakpoint table +REGTABLEN EQU 14 ; Number of registers +SEGDIF EQU 0 +BUFSIZ EQU 512 + +BXREG EQU "B"+5800H ; "BX" +BPREG EQU "B"+5000H ; "BP" +SIREG EQU "S"+4900H ; "SI" +DIREG EQU "D"+4900H ; "DI" +COMMA EQU 2C00H +OPBUFLEN EQU 35 + \ No newline at end of file diff --git a/DEBMES.ASM b/DEBMES.ASM new file mode 100644 index 0000000000000000000000000000000000000000..791b2e5d40e316c3d8f33531871b888b18f88939 GIT binary patch literal 5248 zcmWIX4DoSQP*8AjbqaM)Pc2gLO)V}?OiwN5<#KcM2?j~I28JqtfB`R8NKhz9L;)t` z=O3Z~R>sT4%M~0M9OfFN0G9+yfHb0E>&!HTlA_X79feH&e1(+EqSWLPg_3-Qq|E$c zUM@7nIJwpe#rX;@{=o{#iFpc1sR}8nNu}xOsVTf%o=(1Ajsak&fZc-A9bi`|q~#YW zlw_o47AX`Lq$X!3<|q^-7G;)HDioKLrlo;ArdN@ZSzN-)rB{($l$wTcqNks;PpFG4 z$Q8knzIu+qzPwy|5G8sL9lTs_ouk*u^o#5u_QbVvqy~ zyGDcr`6(zU1b{v4mXnxn1#$r|7fd(YGHeO(n4oP(`g+;v>Qq$`*V29Y3xAT}u|z#JD85ablNK0^eVu5E~35bb;trb!-Q&MtL72rl7?b3(UOSOpK(3Y-Mn2NxUa45ypps6Cs&a=A@P=_y;Q#rB{7TtqH=U7nM2GySVMVaZDd5JlQ0Dy%NvV&k^C=Q2ZCgc(fCWaIc zu$YcUO~qgjf(Z2FT##Q}oSBr9ijn*lEJd@ypFKk zKNOO)4IGU!bR5Ao075%B`4y#ta+sg5C$#WEt~6lr?Hp`{66LUG>?DY9N-|QRMNKg{fdrHkDJZzOK%8$6p)g2m zh4PG4Xt@pYQ+jGiu|jc4VsQqjT?kVSO@xqC=bD#d1!{Fb+74CcM z!RsKGpfDfT5FJ>%6w{r-o=B~YAXi5hUraSF$ZA}JfaaT_-%q zGsG343Km?x{$akz4u%C6iZeiZeR;VcYLPU4 zK|!t|I)0A6PL3`*e*PhDejqBy-ybRLVOstCg999$U3DN4iD|T>volJ7!t{ms`#X8M z>jX#off~uKK|vs!ogA?%c8zcaImN>@0<1W~H9ROp$HO%OM1=>1___ug>Og3uh6Kze z*9cc6yZ9 zS5Q#$%uCKM0(XN!9on+gqTp?(S|%14pmyoGp{T$Co@GMr6{v371AqC%Y<}QP#gtGsA!tq zGILTD^72a*((+65Qqa_cQZzR8$wjGw<^6XI^n>T3TjuW@=uE zLUBQ2a;idpoP$*i0EJ#jDr!E1lxdI_ z4%}g&1ObXmP+EW}FakROu0SEFvLv+_C1_z~AV?upof1e)AuTa8r?d#wQ;;GXq!f|6 zl^m0kQ;UlgQd09WQ&IB~r2XxiT8x~eA%f6UnO~%km!Fqfky%`lm{+0ziF&9Ute1)6 cTxbP`sNW#98Ki!LI7~so)z5{Oi-EcT0Qu^kGXMYp literal 0 HcmV?d00001 diff --git a/DEBUASM.ASM b/DEBUASM.ASM new file mode 100644 index 0000000..6a53124 --- /dev/null +++ b/DEBUASM.ASM @@ -0,0 +1,868 @@ +TITLE DEBUASM + +; Code for the UASSEMble command in the debugger + +.xlist +.xcref + INCLUDE DEBEQU.ASM + INCLUDE DOSSYM.ASM +.cref +.list + + +CODE SEGMENT PUBLIC BYTE 'CODE' +CODE ENDS + +CONST SEGMENT PUBLIC BYTE + + EXTRN SYNERR:BYTE + EXTRN NSEG:WORD,SISAVE:WORD,BPSAVE:WORD,DISAVE:WORD + EXTRN BXSAVE:WORD,DSSAVE:WORD,ESSAVE:WORD,CSSAVE:WORD,IPSAVE:WORD + EXTRN SSSAVE:WORD,CXSAVE:WORD,SPSAVE:WORD,FSAVE:WORD + EXTRN DISTAB:WORD,SHFTAB:WORD,IMMTAB:WORD,GRP1TAB:WORD,GRP2TAB:WORD + EXTRN DBMN:BYTE,ESCMN:BYTE,DISPB:WORD,STACK:BYTE,REG8:BYTE + EXTRN REG16:BYTE,SREG:BYTE,SIZ8:BYTE,SEGTAB:WORD,M8087_TAB:BYTE + EXTRN FI_TAB:BYTE,SIZE_TAB:BYTE,MD9_TAB:BYTE,MD9_TAB2:BYTE + EXTRN MDB_TAB:BYTE,MDB_TAB2:BYTE,MDD_TAB:BYTE,MDD_TAB2:BYTE + EXTRN MDF_TAB:BYTE + +CONST ENDS + +DATA SEGMENT PUBLIC BYTE + + EXTRN DISADD:BYTE,DISCNT:WORD,BYTCNT:BYTE,TEMP:BYTE,AWORD:BYTE + EXTRN MIDFLD:BYTE,MODE:BYTE,REGMEM:BYTE,OPCODE:WORD,OPBUF:BYTE + EXTRN INDEX:WORD + +DATA ENDS + +DG GROUP CODE,CONST,DATA + + +CODE SEGMENT PUBLIC BYTE 'CODE' +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + + + PUBLIC UNASSEM + PUBLIC DISASLN,MEMIMM,JMPCALL,SIGNIMM,ALUFROMREG,WORDTOALU + PUBLIC GRP2,PREFIX,OUTVARW,GRP1,SSPRE,MOVSEGTO,DSPRE,SHIFT + PUBLIC ESPRE,IMMED,CSPRE,OUTVARB,CHK10,ACCIMM,INT3,INVARB + PUBLIC MOVSEGFROM,LOADACC,OUTFIXB,XCHGAX,REGIMMW,SHORTJMP + PUBLIC SAV8,M8087,M8087_DB,M8087_DF,M8087_D9,M8087_DD + PUBLIC SAV16,SAVHEX,INFIXW,REGIMMB,OUTFIXW,SHIFTV,LONGJMP + PUBLIC INVARW,STOREACC,INFIXB,NOOPERANDS,ALUTOREG + PUBLIC SEGOP,REGOP,GETADDR + + EXTRN CRLF:NEAR,PRINTMES:NEAR,BLANK:NEAR,TAB:NEAR,OUT:NEAR + EXTRN HEX:NEAR,DEFAULT:NEAR,OUTSI:NEAR,OUTDI:NEAR + +UNASSEM: + MOV BP,[CSSAVE] ; Default code segment + MOV DI,OFFSET DG:DISADD ; Default address + MOV CX,DISPB ; Default length + SHR CX,1 + SHR CX,1 + CALL DEFAULT + MOV WORD PTR [DISADD],DX ; Displacement of disassembly + MOV WORD PTR [DISADD+2],AX ; Segment + MOV WORD PTR [DISCNT],CX ; No. of bytes (but whole instructions) +DISLP: + CALL DISASLN ; Disassemble one line + CALL CRLF + TEST [DISCNT],-1 ; See if we've used up the range + JNZ DISLP + RET + +GOTDIS: PUSH DS ; RE-GET LAST BYTE + PUSH SI + LDS SI,DWORD PTR [DISADD] + MOV AL,[SI-1] + POP SI + POP DS + RET + +GETDIS: + PUSH DS + LDS SI,DWORD PTR [DISADD] + LODSB ; Get the next byte of code + POP DS + MOV WORD PTR [DISADD],SI ; Update pointer + PUSH AX + CALL HEX ; Display each code byte + MOV SI,[DISCNT] + OR SI,SI ; Check if range exhausted + JZ ENDRNG ; If so, don't wrap around + DEC SI ; Count off the bytes + MOV [DISCNT],SI +ENDRNG: + INC BYTE PTR[BYTCNT] ; Keep track of no. of bytes per line + POP AX + RET + +DSPRE: INC BYTE PTR [NSEG+1] +SSPRE: INC BYTE PTR [NSEG+1] +CSPRE: INC BYTE PTR [NSEG+1] +ESPRE: INC BYTE PTR [NSEG+1] + +PREFIX: + POP BX ; Dump off return address + CALL FINLN + CALL CRLF +DISASLN: + PUSH DS + LDS SI,DWORD PTR [DISADD] + CALL OUTSI ; Show disassembly address + POP DS + CALL BLANK +DISASLN1: + MOV BYTE PTR [BYTCNT],0 ; Count of code bytes per line + MOV DI,OFFSET DG:OPBUF ; Point to operand buffer + MOV AL," " + MOV CX,OPBUFLEN-1 ; Don't do last byte which has end marker + REP STOSB ; Initialize operand buffer to blanks + MOV BYTE PTR [DI]," "+80H + CALL GETDIS ; Get opcode + MOV AH,0 + MOV BX,AX + AND AL,1 ; Mask to "W" bit + MOV [AWORD],AL + MOV AL,BL ; Restore opcode + SHL BX,1 + SHL BX,1 ; Multiply opcode by 4 + ADD BX,OFFSET DG:DISTAB + MOV DX,[BX] ; Get pointer to mnemonic from table + MOV [OPCODE],DX ; Save it until line is complete + MOV DI,OFFSET DG:OPBUF ; Initialize for opcode routines + CALL WORD PTR [BX+2] ; Dispatch to opcode routine +FINLN: + MOV SI,OFFSET DG:DISADD + MOV AH,[BYTCNT] ; See how many bytes in this instruction + ADD AH,AH ; Each uses two characters + MOV AL,14 ; Amount of space we want to use + SUB AL,AH ; See how many fill characters needed + CBW + XCHG CX,AX ; Parameter for TAB needed in CX + CALL TAB + MOV SI,[OPCODE] + OR SI,SI ; MAKE SURE THERE IS SOMETHING TO PRINT + JZ NOOPC + CALL PRINTMES ; Print opcode mnemonic + MOV AL,9 + CALL OUT ; and a tab +NOOPC: MOV SI,OFFSET DG:OPBUF + JMP PRINTMES ; and the operand buffer + +GETMODE: + CALL GETDIS ; Get the address mode byte + MOV AH,AL + AND AL,7 ; Mask to "r/m" field + MOV [REGMEM],AL + SHR AH,1 + SHR AH,1 + SHR AH,1 + MOV AL,AH + AND AL,7 ; Mask to center 3-bit field + MOV [MIDFLD],AL + SHR AH,1 + SHR AH,1 + SHR AH,1 + MOV [MODE],AH ; Leaving 2-bit "MOD" field + RET + +IMMED: + MOV BX,OFFSET DG:IMMTAB + CALL GETMNE +FINIMM: + CALL TESTREG + JMP SHORT IMM + +MEMIMM: + CALL GETMODE + JMP SHORT FINIMM + +ACCIMM: + XOR AL,AL +IMM1: + CALL SAVREG +IMM: + MOV AL,"," + STOSB + TEST BYTE PTR [AWORD],-1 + JNZ SAV16 +SAV8: + CALL GETDIS + JMP SHORT SAVHEX + +LONGJMP: + PUSH DI + MOV DI,OFFSET DG:TEMP + CALL SAV16 + POP DI + CALL SAV16 + MOV AL,":" + STOSB + MOV SI,OFFSET DG:TEMP + MOV CX,4 +MOVDIG: + LODSB + STOSB + LOOP MOVDIG + RET +SAV16: + CALL GETDIS ; Get low byte + MOV DL,AL + CALL GETDIS ; Get high byte + MOV DH,AL + CALL SAVHEX ; Convert and store high byte + MOV AL,DL +SAVHEX: + MOV AH,AL + SHR AL,1 + SHR AL,1 + SHR AL,1 + SHR AL,1 + CALL SAVDIG + MOV AL,AH +SAVDIG: + AND AL,0FH + ADD AL,90H + DAA + ADC AL,40H + DAA + STOSB + RET + +CHK10: + CALL GETDIS + CMP AL,10 + JNZ SAVHEX + RET + +SIGNIMM: + MOV BX,OFFSET DG:IMMTAB + CALL GETMNE + CALL TESTREG + MOV AL,"," + STOSB +SAVD8: + CALL GETDIS ; Get signed 8-bit number + CBW + MOV DX,AX ; Save true 16-bit value in DX + MOV AH,AL + MOV AL,"+" + OR AH,AH +; JZ nosign + JNS POSITIV ; OK if positive + MOV AL,"-" + NEG AH ; Get magnitude if negative +POSITIV: + STOSB +; nosign: + MOV AL,AH + JMP SHORT SAVHEX + +ALUFROMREG: + CALL GETADDR + MOV AL,"," + STOSB +REGFLD: + MOV AL,[MIDFLD] +SAVREG: + MOV SI,OFFSET DG:REG8 + CMP BYTE PTR [AWORD],1 + JNE FNDREG +SAVREG16: + MOV SI,OFFSET DG:REG16 +FNDREG: + CBW + ADD SI,AX + ADD SI,AX + MOVSW + RET + +SEGOP: + SHR AL,1 + SHR AL,1 + SHR AL,1 +SAVSEG: + AND AL,3 + MOV SI,OFFSET DG:SREG + JMP SHORT FNDREG + +REGOP: + AND AL,7 + JMP SHORT SAVREG16 + +MOVSEGTO: + MOV BYTE PTR [AWORD],1 + CALL GETADDR + MOV AL,"," + STOSB + MOV AL,[MIDFLD] + JMP SHORT SAVSEG + +MOVSEGFROM: + CALL GETMODE + CALL SAVSEG + MOV BYTE PTR [AWORD],1 + JMP SHORT MEMOP2 + +GETADDR: + CALL GETMODE + JMP SHORT ADDRMOD + +WORDTOALU: + MOV BYTE PTR [AWORD],1 +ALUTOREG: + CALL GETMODE + CALL REGFLD +MEMOP2: + MOV AL,"," + STOSB +ADDRMOD: + CMP BYTE PTR [MODE],3 + MOV AL,[REGMEM] + JE SAVREG + XOR BX,BX + MOV BYTE PTR [NSEG],3 + MOV BYTE PTR [DI],"[" + INC DI + CMP AL,6 + JNE NODRCT + CMP BYTE PTR [MODE],0 + JE DIRECT ; Mode=0 and R/M=6 means direct addr. +NODRCT: + MOV DL,AL + CMP AL,1 + JBE USEBX + CMP AL,7 + JE USEBX + CMP AL,3 + JBE USEBP + CMP AL,6 + JNE CHKPLS +USEBP: + MOV BX,[BPSAVE] + MOV BYTE PTR [NSEG],2 ; Change default to Stack Segment + MOV AX,BPREG +SAVBASE: + STOSW +CHKPLS: + CMP DL,4 + JAE NOPLUS + MOV AL,"+" + STOSB +NOPLUS: + CMP DL,6 + JAE DOMODE ; No index register + AND DL,1 ; Even for SI, odd for DI + JZ USESI + ADD BX,[DISAVE] + MOV AX,DIREG +SAVINDX: + STOSW +DOMODE: + MOV AL,[MODE] + OR AL,AL + JZ CLOSADD ; If no displacement, then done + CMP AL,2 + JZ ADDDIR + CALL SAVD8 ; Signed 8-bit displacement +ADDCLOS: + ADD BX,DX +CLOSADD: + MOV AL,"]" + STOSB + MOV [INDEX],BX +NOOPERANDS: + RET + +ADDDIR: + MOV AL,"+" + STOSB +DIRECT: + CALL SAV16 + JMP SHORT ADDCLOS + +USEBX: + MOV BX,[BXSAVE] + MOV AX,BXREG + JMP SHORT SAVBASE + +USESI: + ADD BX,[SISAVE] + MOV AX,SIREG + JMP SHORT SAVINDX + +SHORTJMP: + CALL GETDIS + CBW + ADD AX,WORD PTR [DISADD] + XCHG DX,AX +SAVJMP: + MOV AL,DH + CALL SAVHEX + MOV AL,DL + JMP SAVHEX + +JMPCALL: + CALL GETDIS + MOV DL,AL + CALL GETDIS + MOV DH,AL + ADD DX,WORD PTR [DISADD] + JMP SHORT SAVJMP + +XCHGAX: + AND AL,7 + CALL SAVREG16 + MOV AL,"," + STOSB + XOR AL,AL + JMP SAVREG16 + +LOADACC: + XOR AL,AL + CALL SAVREG + MOV AL,"," + STOSB +MEMDIR: + MOV AL,"[" + STOSB + XOR BX,BX + MOV BYTE PTR [NSEG],3 + JMP DIRECT + +STOREACC: + CALL MEMDIR + MOV AL,"," + STOSB + XOR AL,AL + JMP SAVREG + +REGIMMB: + MOV BYTE PTR [AWORD],0 + JMP SHORT REGIMM +REGIMMW: + MOV BYTE PTR [AWORD],1 +REGIMM: + AND AL,7 + JMP IMM1 + +INT3: + MOV BYTE PTR [DI],"3" + RET +; +; 8087 instructions whose first byte is 0dfh +; +M8087_DF: + CALL GET64F + JZ ISDD3 + MOV SI,OFFSET DG:MDF_TAB + JMP NODB3 +; +; 8087 instructions whose first byte is 0ddh +; +M8087_DD: + CALL GET64F + JZ ISDD3 + MOV SI,OFFSET DG:MDD_TAB + JMP NOD93 + +ISDD3: + MOV AL,DL + TEST AL,100B + JZ ISSTI + JMP ESC0 +ISSTI: AND AL,11B + MOV SI,OFFSET DG:MDD_TAB2 + MOV CL,AL + CALL MOVBYT + JMP PUTRST +; +; 8087 instructions whose first byte is 0dbh +; +M8087_DB: + CALL GET64F + JZ ISDB3 + MOV SI,OFFSET DG:MDB_TAB +NODB3: CALL PUTOP + CALL PUTSIZE + JMP ADDRMOD + +ISDB3: + MOV AL,DL + TEST AL,100B + JNZ ISDBIG +ESC0V: JMP ESC0 +ISDBIG: CALL GOTDIS + AND AL,11111B + CMP AL,4 + JAE ESC0V + MOV SI,OFFSET DG:MDB_TAB2 + JMP DOBIG +; +; 8087 instructions whose first byte is 0d9h +; +M8087_D9: + CALL GET64F + JZ ISD93 + + MOV SI,OFFSET DG:MD9_TAB +NOD93: CALL PUTOP + AND AL,111B + CMP AL,3 + JA NOSHO + MOV AL,DL + CALL PUTSIZE +NOSHO: JMP ADDRMOD + +ISD93: MOV AL,DL + TEST AL,100B + JNZ ISD9BIG + AND AL,111B + OR AL,AL + JNZ NOTFLD + MOV AX,"DL" + STOSW + JMP SHORT PUTRST +NOTFLD: CMP AL,1 + JNZ NOTFXCH + MOV AX,"CX" + STOSW + MOV AL,"H" + JMP SHORT PUTRST1 +NOTFXCH:CMP AL,3 + JNZ NOTFSTP + MOV AX,"TS" + STOSW + MOV AL,"P" +PUTRST1:STOSB +PUTRST: MOV AL,9 + STOSB + JMP PUTST0 + +NOTFSTP:CALL GOTDIS + CMP AL,11010000B ; CHECK FOR FNOP + JZ GOTFNOP + JMP ESC0 +GOTFNOP:MOV AX,"ON" + STOSW + MOV AL,"P" + STOSB + RET + +ISD9BIG: + CALL GOTDIS ; GET THE MODE BYTE + MOV SI,OFFSET DG:MD9_TAB2 +DOBIG: AND AL,11111B + MOV CL,AL + JMP MOVBYT +; +; entry point for the remaining 8087 instructions +; +M8087: + CALL GET64 + CALL PUTFI ; PUT FIRST PART OF OPCODE + MOV AL,DL + CMP BYTE PTR [MODE],11B ; CHECK FOR REGISTER MODE + JZ MODEIS3 + CALL PUTMN ; PUT MIDDLE PART OF OPCODE +NO3: MOV AL,9 ; OUTPUT A TAB + STOSB + MOV AL,DL + CALL PUTSIZE ; OUTPUT THE OPERAND SIZE + JMP ADDRMOD + +MODEIS3: + TEST AL,100000B ; D BIT SET? + JZ MPUT ; NOPE... + TEST AL,000100B ; FDIV OR FSUB? + JZ MPUT ; NOPE... + XOR AL,1 ; REVERSE SENSE OF R + MOV DL,AL ; SAVE CHANGE +MPUT: CALL PUTMN ; PUT MIDDLE PART OF OPCODE + MOV AL,DL + TEST AL,010000B + JZ NOPSH + MOV AL,"P" + STOSB +NOPSH: MOV AL,9 + STOSB + MOV AL,DL + AND AL,00000111B + CMP AL,2 ; FCOM + JZ PUTST0 + CMP AL,3 ; FCOMP + JZ PUTST0 + MOV AL,DL + TEST AL,100000B + JZ PUTSTST0 +; +; output 8087 registers in the form st(n),st +; +PUTST0ST: + CALL PUTST0 + MOV AL,',' +ISCOMP: STOSB + +PUTST: MOV AX,"TS" + STOSW + RET +; +; output 8087 registers in the form st,st(n) +; +PUTSTST0: + CALL PUTST + MOV AL,',' + STOSB + +PUTST0: CALL PUTST + MOV AL,"(" + STOSB + MOV AL,[REGMEM] + ADD AL,"0" + STOSB + MOV AL,")" + STOSB + RET +; +; output an 8087 mnemonic +; +PUTMN: MOV SI,OFFSET DG:M8087_TAB + MOV CL,AL + AND CL,00000111B + JMP SHORT MOVBYT +; +; output either 'FI' or 'F' for first byte of opcode +; +PUTFI: MOV SI,OFFSET DG:FI_TAB + JMP SHORT PUTFI2 +; +; output size (dword, tbyte, etc.) +; +PUTSIZE:MOV SI,OFFSET DG:SIZE_TAB +PUTFI2: CMP BYTE PTR [MODE],11B ; check if 8087 register + JNZ PUTFI3 + AND AL,111000B ; LOOK FOR INVALID FORM OF 0DAH OPERANDS + CMP AL,010000B + JZ ESC0PJ + MOV AL,DL + CMP AL,110011B ; FCOMPP + JNZ GOFI + CMP BYTE PTR [REGMEM],1 + JZ GOFI +ESC0PJ: JMP ESC0P +GOFI: XOR CL,CL + JMP SHORT MOVBYT +; +; Look for qword +; +PUTFI3: CMP AL,111101B + JZ GOTQU + CMP AL,111111B + JNZ NOTQU +GOTQU: MOV CL,2 + JMP SHORT MOVBYT +; +; look for tbyte +; +NOTQU: CMP AL,011101B + JZ GOTTB + CMP AL,111100B + JZ GOTTB + CMP AL,111110B + JZ GOTTB + CMP AL,011111B + JNZ NOTTB +GOTTB: MOV CL,5 + JMP SHORT MOVBYT + +NOTTB: MOV CL,4 + SHR AL,CL + MOV CL,AL +; +; SI POINTS TO A TABLE OF TEXT SEPARATED BY "$" +; CL = WHICH ELEMENT IN THE TABLE YOU WISH TO COPY TO [DI] +; +MOVBYT: PUSH AX + INC CL +MOVBYT1:DEC CL + JZ MOVBYT3 +MOVBYT2:LODSB + CMP AL,'$' + JZ MOVBYT1 + JMP MOVBYT2 +MOVBYT3:LODSB + CMP AL,'$' + JZ MOVBYT5 + CMP AL,'@' ; THIS MEANS RESVERED OP-CODE + JNZ MOVBYT4 + POP AX + JMP SHORT ESC0P ; GO DO AN ESCAPE COMMAND +MOVBYT4:STOSB + JMP MOVBYT3 +MOVBYT5:POP AX + RET + +PUTOP: AND AL,111B + MOV CL,AL + CALL MOVBYT + MOV AL,9 + STOSB + MOV AL,DL + RET + +GET64F: CALL GET64 + MOV AL,"F" + STOSB + CMP BYTE PTR [MODE],3 + MOV AL,DL + RET + +GET64: + AND AL,7 + MOV DL,AL + CALL GETMODE + SHL DL,1 + SHL DL,1 + SHL DL,1 + OR AL,DL + MOV DL,AL ; SAVE RESULT + RET + +ESC0P: POP DI ; CLEAN UP STACK +ESC0: MOV WORD PTR [OPCODE],OFFSET DG:ESCMN + MOV AL,DL + MOV DI,OFFSET DG:OPBUF + JMP SHORT ESC1 + +ESC: CALL GET64 +ESC1: CALL SAVHEX + CMP BYTE PTR [MODE],3 + JZ SHRTESC + MOV BYTE PTR [AWORD],1 + JMP MEMOP2 + +SHRTESC: + MOV AL,"," + STOSB + MOV AL,[REGMEM] + AND AL,7 + JMP SAVREG + +INVARW: + CALL PUTAX + JMP SHORT INVAR +INVARB: + CALL PUTAL +INVAR: MOV AL,',' + STOSB + JMP PUTDX + +INFIXW: + CALL PUTAX + JMP SHORT INFIX +INFIXB: + CALL PUTAL +INFIX: MOV AL,',' + STOSB + JMP SAV8 + STOSW + RET + +OUTVARB: + MOV BX,"LA" + JMP SHORT OUTVAR +OUTVARW: + MOV BX,"XA" +OUTVAR: CALL PUTDX +OUTFV: MOV AL,',' + STOSB + MOV AX,BX + STOSW + RET + +OUTFIXB: + MOV BX,"LA" + JMP SHORT OUTFIX +OUTFIXW: + MOV BX,"XA" +OUTFIX: CALL SAV8 + JMP OUTFV + +PUTAL: MOV AX,"A"+4C00H ; "AL" + JMP SHORT PUTX +PUTAX: MOV AX,"A"+5800H ; "AX" + JMP SHORT PUTX +PUTDX: MOV AX,"D"+5800H ; "DX" +PUTX: STOSW + RET + +SHFT: + MOV BX,OFFSET DG:SHFTAB + CALL GETMNE +TESTREG: + CMP BYTE PTR [MODE],3 + JZ NOFLG + MOV SI,OFFSET DG:SIZE_TAB + MOV CL,3 + TEST BYTE PTR [AWORD],-1 + JNZ TEST_1 + INC CL +TEST_1: CALL MOVBYT +NOFLG: + JMP ADDRMOD + +SHIFTV: + CALL SHFT + MOV AL,"," + STOSB + MOV WORD PTR [DI],"C"+4C00H ; "CL" + RET + +SHIFT: + CALL SHFT + MOV AX,"1," + STOSW + RET + +GETMNE: + CALL GETMODE + MOV DL,AL + CBW + SHL AX,1 + ADD BX,AX + MOV AX,[BX] + MOV [OPCODE],AX + MOV AL,DL + RET + +GRP1: + MOV BX,OFFSET DG:GRP1TAB + CALL GETMNE + OR AL,AL + JZ FINIMMJ + JMP TESTREG +FINIMMJ: + JMP FINIMM + +GRP2: + MOV BX,OFFSET DG:GRP2TAB + CALL GETMNE + CMP AL,2 + JB TESTREG + CMP AL,6 + JAE INDIRECT + TEST AL,1 + JZ INDIRECT + MOV AX,"AF" ; "FAR" + STOSW + MOV AX," R" + STOSW +INDIRECT: + JMP ADDRMOD + +CODE ENDS + END UNASSEM + \ No newline at end of file diff --git a/DEBUG.ASM b/DEBUG.ASM new file mode 100644 index 0000000..91db1ca --- /dev/null +++ b/DEBUG.ASM @@ -0,0 +1,838 @@ +TITLE DEBUGger for MS-DOS +; DEBUG-86 8086 debugger runs under 86-DOS version 2.30 +; +; Modified 5/4/82 by AaronR to do all I/O direct to devices +; Runs on MS-DOS 1.28 and above +; REV 1.20 +; Tab expansion +; New device interface (1.29 and above) +; REV 2.0 +; line by line assembler added by C. Peters +; REV 2.1 +; Uses EXEC system call +; REV 2.2 +; Ztrace mode by zibo. +; Fix dump display to indent properly +; Parity nonsense by zibo +; +; REV 2.3 +; Split into seperate modules to allow for +; assembly on an IBM PC +; + + + +.xlist +.xcref + INCLUDE DEBEQU.ASM + INCLUDE DOSSYM.ASM +.cref +.list + + IF SYSVER + +; Structure for system call 72 + +SYSINITVAR STRUC +DPBHEAD DD ? ; Pointer to head of DPB-FAT list +sft_addr DD ? ; Pointer to first FCB table +; The following address points to the CLOCK device +BCLOCK DD ? +; The following address is used by DISKSTATCHK it is always +; points to the console input device header +BCON DD ? ; Console device entry points +NUMIO DB 0 ; Number of disk tables +MAXSEC DW 0 ; Maximum allowed sector size +BUFFHEAD DD ? +DEVHEAD DD ? +SYSINITVAR ENDS + + ENDIF + + +CODE SEGMENT PUBLIC 'CODE' +CODE ENDS + +CONST SEGMENT PUBLIC BYTE + + EXTRN USER_PROC_PDB:WORD,STACK:BYTE,CSSAVE:WORD,DSSAVE:WORD + EXTRN SPSAVE:WORD,IPSAVE:WORD,LINEBUF:BYTE,QFLAG:BYTE + EXTRN NEWEXEC:BYTE,HEADSAVE:WORD,LBUFSIZ:BYTE,BACMES:BYTE + EXTRN BADVER:BYTE,ENDMES:BYTE,CARRET:BYTE,ParityMes:BYTE + + IF IBMVER + EXTRN DSIZ:BYTE,NOREGL:BYTE,DISPB:WORD + ENDIF + + IF SYSVER + EXTRN CONFCB:BYTE,POUT:DWORD,COUT:DWORD,CIN:DWORD,IOBUFF:BYTE + EXTRN IOADDR:DWORD,IOCALL:BYTE,IOCOM:BYTE,IOSTAT:WORD,IOCNT:WORD + EXTRN IOSEG:WORD,COLPOS:BYTE,BADDEV:BYTE,BADLSTMES:BYTE + EXTRN LBUFFCNT:BYTE,PFLAG:BYTE + ENDIF + +CONST ENDS + +DATA SEGMENT PUBLIC BYTE + + EXTRN PARSERR:BYTE,DATAEND:WORD,ParityFlag:BYTE,DISADD:BYTE + EXTRN ASMADD:BYTE,DEFDUMP:BYTE,BYTEBUF:BYTE + +DATA ENDS + +DG GROUP CODE,CONST,DATA + + +CODE SEGMENT PUBLIC 'CODE' +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + + PUBLIC RESTART,SET_TERMINATE_VECTOR,DABORT,TERMINATE,COMMAND + PUBLIC FIND_DEBUG,CRLF,BLANK,TAB,OUT,INBUF,SCANB,SCANP + PUBLIC PRINTMES,RPRBUF,HEX,OUTSI,OUTDI,OUT16,DIGIT,BACKUP,RBUFIN + + IF SYSVER + PUBLIC SETUDEV,DEVIOCALL + EXTRN DISPREG:NEAR,IN:NEAR + ENDIF + + EXTRN PERR:NEAR,COMPARE:NEAR,DUMP:NEAR,ENTER:NEAR,FILL:NEAR + EXTRN GO:NEAR,INPUT:NEAR,LOAD:NEAR,MOVE:NEAR,NAME:NEAR + EXTRN REG:NEAR,SEARCH:NEAR,DWRITE:NEAR,UNASSEM:NEAR,ASSEM:NEAR + EXTRN OUTPUT:NEAR,ZTRACE:NEAR,TRACE:NEAR,GETHEX:NEAR,GETEOL:NEAR + + EXTRN PREPNAME:NEAR,DEFIO:NEAR,SKIP_FILE:NEAR,DEBUG_FOUND:NEAR + EXTRN TrapParity:NEAR,ReleaseParity:NEAR + + ORG 100H + +START: +DEBUG: + JMP SHORT DSTRT + +HEADER DB "Vers 2.30" + +DSTRT: +DOSVER_HIGH EQU 0200H ; 2.00 in hex + MOV AH,GET_VERSION + INT 21H + XCHG AH,AL ; Turn it around to AH.AL + CMP AX,DOSVER_HIGH + JAE OKDOS +GOTBADDOS: + MOV DX,OFFSET DG:BADVER + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + INT 20H + +OKDOS: + CALL TrapParity ; scarf up those parity guys + MOV AH,GET_CURRENT_PDB + INT 21H + MOV [USER_PROC_PDB],BX ; Initially set to DEBUG + + IF SYSVER + MOV [IOSEG],CS + ENDIF + + MOV SP,OFFSET DG:STACK + MOV [PARSERR],AL + MOV AH,GET_IN_VARS + INT 21H + + + IF SYSVER + LDS SI,ES:[BX.BCON] + MOV WORD PTR CS:[CIN+2],DS + MOV WORD PTR CS:[CIN],SI + MOV WORD PTR CS:[COUT+2],DS + MOV WORD PTR CS:[COUT],SI + PUSH CS + POP DS + MOV DX,OFFSET DG:CONFCB + MOV AH,FCB_OPEN + INT 21H + OR AL,AL + JZ GOTLIST + MOV DX,OFFSET DG:BADLSTMES + CALL RPRBUF + CALL RBUFIN + CALL CRLF + MOV CL,[LBUFFCNT] + OR CL,CL + JZ NOLIST1 ; User didn't specify one + XOR CH,CH + MOV DI,OFFSET DG:(CONFCB + 1) + MOV SI,OFFSET DG:LINEBUF + REP MOVSB + MOV DX,OFFSET DG:CONFCB + MOV AH,FCB_OPEN + INT 21H + OR AL,AL + JZ GOTLIST ; GOOD + MOV DX,OFFSET DG:BADDEV + CALL RPRBUF +NOLIST1: + MOV WORD PTR [POUT+2],CS + MOV WORD PTR [POUT],OFFSET DG:LONGRET + JMP NOLIST + +XXX PROC FAR +LONGRET:RET +XXX ENDP + ENDIF + +GOTLIST: + IF SYSVER + MOV SI,DX + LDS SI,DWORD PTR DS:[SI.fcb_FIRCLUS] + MOV WORD PTR CS:[POUT+2],DS + MOV WORD PTR CS:[POUT],SI + ENDIF +NOLIST: + MOV AX,CS + MOV DS,AX + MOV ES,AX + +; Code to print header +; MOV DX,OFFSET DG:HEADER +; CALL RPRBUF + + CALL SET_TERMINATE_VECTOR + + IF SETCNTC + MOV AL,23H ; Set vector 23H + MOV DX,OFFSET DG:DABORT + INT 21H + ENDIF + + MOV DX,CS ; Get DEBUG's segment + MOV AX,OFFSET DG:DATAEND + 15 ; End of debug + SHR AX,1 ; Convert to segments + SHR AX,1 + SHR AX,1 + SHR AX,1 + ADD DX,AX ; Add siz of debug in paragraphs + MOV AH,CREATE_PROCESS_DATA_BLOCK ; create program segment just after DEBUG + INT 21H + MOV AX,DX + MOV DI,OFFSET DG:DSSAVE + CLD + STOSW + STOSW + STOSW + STOSW + MOV WORD PTR [DISADD+2],AX + MOV WORD PTR [ASMADD+2],AX + MOV WORD PTR [DEFDUMP+2],AX + MOV AX,100H + MOV WORD PTR[DISADD],AX + MOV WORD PTR[ASMADD],AX + MOV WORD PTR [DEFDUMP],AX + MOV DS,DX + MOV ES,DX + MOV DX,80H + MOV AH,SET_DMA + INT 21H ; Set default DMA address to 80H + MOV AX,WORD PTR DS:[6] + MOV BX,AX + CMP AX,0FFF0H + PUSH CS + POP DS + JAE SAVSTK + MOV AX,WORD PTR DS:[6] + PUSH BX + MOV BX,OFFSET DG:DATAEND + 15 + AND BX,0FFF0H ; Size of DEBUG in bytes (rounded up to PARA) + SUB AX,BX + POP BX +SAVSTK: + PUSH BX + DEC AX + DEC AX + MOV BX,AX + MOV WORD PTR [BX],0 + POP BX + MOV SPSAVE,AX + DEC AH + MOV ES:WORD PTR [6],AX + SUB BX,AX + MOV CL,4 + SHR BX,CL + ADD ES:WORD PTR [8],BX + + IF IBMVER + ; Get screen size and initialize display related variables + MOV AH,15 + INT 10H + CMP AH,40 + JNZ PARSCHK + MOV BYTE PTR DSIZ,7 + MOV BYTE PTR NOREGL,4 + MOV DISPB,64 + ENDIF + +PARSCHK: +; Copy rest of command line to test program's parameter area + MOV DI,FCB + MOV SI,81H + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H + INT 21H + CALL SKIP_FILE ; Make sure si points to delimiter + CALL PREPNAME + PUSH CS + POP ES +FILECHK: + MOV DI,80H + CMP BYTE PTR ES:[DI],0 ; ANY STUFF FOUND? + JZ COMMAND ; NOPE +FILOOP: INC DI + CMP BYTE PTR ES:[DI],13 ; COMMAND LINE JUST SPACES? + JZ COMMAND + CMP BYTE PTR ES:[DI]," " + JZ FILOOP + CMP BYTE PTR ES:[DI],9 + JZ FILOOP + + CALL DEFIO ; WELL READ IT IN + MOV AX,CSSAVE + MOV WORD PTR DISADD+2,AX + MOV WORD PTR ASMADD+2,AX + MOV AX,IPSAVE + MOV WORD PTR DISADD,AX + MOV WORD PTR ASMADD,AX +COMMAND: + CLD + MOV AX,CS + MOV DS,AX + MOV ES,AX + MOV SS,AX + MOV SP,OFFSET DG:STACK + STI + CMP [ParityFlag],0 ; did we detect a parity error? + JZ GoPrompt ; nope, go prompt + MOV [ParityFlag],0 ; reset flag + MOV DX,OFFSET DG:ParityMes ; message to print + MOV AH,STD_CON_STRING_OUTPUT; easy way out + INT 21h ; blam +GoPrompt: + MOV AL,PROMPT + CALL OUT + CALL INBUF ; Get command line +; From now and throughout command line processing, DI points +; to next character in command line to be processed. + CALL SCANB ; Scan off leading blanks + JZ COMMAND ; Null command? + LODSB ; AL=first non-blank character +; Prepare command letter for table lookup + SUB AL,"A" ; Low end range check + JB ERR1 + CMP AL,"Z"-"A" ; Upper end range check + JA ERR1 + SHL AL,1 ; Times two + CBW ; Now a 16-bit quantity + XCHG BX,AX ; In BX we can address with it + CALL CS:[BX+COMTAB] ; Execute command + JMP SHORT COMMAND ; Get next command +ERR1: JMP PERR + +SET_TERMINATE_VECTOR: + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 22H ; Set vector 22H + MOV DX,OFFSET DG:TERMINATE + INT 21H + RET + +TERMINATE: + CMP BYTE PTR CS:[QFLAG],0 + JNZ QUITING + MOV CS:[USER_PROC_PDB],CS + CMP BYTE PTR CS:[NEWEXEC],0 + JZ NORMTERM + MOV AX,CS + MOV DS,AX + MOV SS,AX + MOV SP,OFFSET DG:STACK + MOV AX,[HEADSAVE] + JMP DEBUG_FOUND + +NORMTERM: + MOV DX,OFFSET DG:ENDMES + JMP SHORT RESTART + +QUITING: + MOV AX,(EXIT SHL 8) + INT 21H + +DABORT: + MOV DX,OFFSET DG:CARRET +RESTART: + MOV AX,CS + MOV DS,AX + MOV SS,AX + MOV SP,OFFSET DG:STACK + CALL RPRBUF + JMP COMMAND + + IF SYSVER +SETUDEV: + MOV DI,OFFSET DG:CONFCB + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H + INT 21H + CALL USERDEV + JMP DISPREG + +USERDEV: + MOV DX,OFFSET DG:CONFCB + MOV AH,FCB_OPEN + INT 21H + OR AL,AL + JNZ OPENERR + MOV SI,DX + TEST BYTE PTR [SI.fcb_DEVID],080H ; Device? + JZ OPENERR ; NO + LDS SI,DWORD PTR [CONFCB.fcb_FIRCLUS] + MOV WORD PTR CS:[CIN],SI + MOV WORD PTR CS:[CIN+2],DS + MOV WORD PTR CS:[COUT],SI + MOV WORD PTR CS:[COUT+2],DS + PUSH CS + POP DS + RET + + +OPENERR: + MOV DX,OFFSET DG:BADDEV + CALL RPRBUF + RET + ENDIF + +; Get input line. Convert all characters NOT in quotes to upper case. + +INBUF: + CALL RBUFIN + MOV SI,OFFSET DG:LINEBUF + MOV DI,OFFSET DG:BYTEBUF +CASECHK: + LODSB + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + ADD AL,"A"-"a" ; Convert to upper case +NOCONV: + STOSB + CMP AL,13 + JZ INDONE + CMP AL,'"' + JZ QUOTSCAN + CMP AL,"'" + JNZ CASECHK +QUOTSCAN: + MOV AH,AL +KILLSTR: + LODSB + STOSB + CMP AL,13 + JZ INDONE + CMP AL,AH + JNZ KILLSTR + JMP SHORT CASECHK + +INDONE: + MOV SI,OFFSET DG:BYTEBUF + +; Output CR/LF sequence + +CRLF: + MOV AL,13 + CALL OUT + MOV AL,10 + JMP OUT + +; Physical backspace - blank, backspace, blank + +BACKUP: + MOV SI,OFFSET DG:BACMES + +; Print ASCII message. Last char has bit 7 set + +PRINTMES: + LODS CS:BYTE PTR [SI] ; Get char to print + CALL OUT + SHL AL,1 ; High bit set? + JNC PRINTMES + RET + +; Scan for parameters of a command + +SCANP: + CALL SCANB ; Get first non-blank + CMP BYTE PTR [SI],"," ; One comma between params OK + JNE EOLCHK ; If not comma, we found param + INC SI ; Skip over comma + +; Scan command line for next non-blank character + +SCANB: + PUSH AX +SCANNEXT: + LODSB + CMP AL," " + JZ SCANNEXT + CMP AL,9 + JZ SCANNEXT + DEC SI ; Back to first non-blank + POP AX +EOLCHK: + CMP BYTE PTR [SI],13 + RET + +; Hex addition and subtraction + +HEXADD: + MOV CX,4 + CALL GETHEX + MOV DI,DX + MOV CX,4 + CALL GETHEX + CALL GETEOL + PUSH DX + ADD DX,DI + CALL OUT16 + CALL BLANK + CALL BLANK + POP DX + SUB DI,DX + MOV DX,DI + CALL OUT16 + JMP SHORT CRLF + +; Print the hex address of DS:SI + +OUTSI: + MOV DX,DS ; Put DS where we can work with it + CALL OUT16 ; Display segment + MOV AL,":" + CALL OUT + MOV DX,SI + JMP SHORT OUT16 ; Output displacement + +; Print hex address of ES:DI +; Same as OUTSI above + +OUTDI: + MOV DX,ES + CALL OUT16 + MOV AL,":" + CALL OUT + MOV DX,DI + +; Print out 16-bit value in DX in hex + +OUT16: + MOV AL,DH ; High-order byte first + CALL HEX + MOV AL,DL ; Then low-order byte + +; Output byte in AL as two hex digits + +HEX: + MOV AH,AL ; Save for second digit +; Shift high digit into low 4 bits + PUSH CX + MOV CL,4 + SHR AL,CL + POP CX + + CALL DIGIT ; Output first digit + MOV AL,AH ; Now do digit saved in AH +DIGIT: + AND AL,0FH ; Mask to 4 bits +; Trick 6-byte hex conversion works on 8086 too. + ADD AL,90H + DAA + ADC AL,40H + DAA + +; Console output of character in AL. No registers affected but bit 7 +; is reset before output. + + IF SYSVER +OUT: + PUSH AX + AND AL,7FH + CMP AL,7FH + JNZ NOTDEL + MOV AL,8 ; DELETE same as backspace +NOTDEL: + CMP AL,9 + JZ TABDO + CALL DOCONOUT + CMP AL,0DH + JZ ZEROPOS + CMP AL,0AH + JZ ZEROPOS + CMP AL,8 + JNZ OOKRET + MOV AL," " + CALL DOCONOUT + MOV AL,8 + CALL DOCONOUT + CMP BYTE PTR CS:[COLPOS],0 + JZ NOTINC + DEC BYTE PTR CS:[COLPOS] + JMP NOTINC +ZEROPOS: + MOV BYTE PTR CS:[COLPOS],0FFH +OOKRET: + INC BYTE PTR CS:[COLPOS] +NOTINC: + TEST BYTE PTR CS:[PFLAG],1 + JZ POPRET + CALL LISTOUT +POPRET: + POP AX + RET + +TABDO: + MOV AL,CS:[COLPOS] + OR AL,0F8H + NEG AL + PUSH CX + MOV CL,AL + XOR CH,CH + JCXZ POPTAB +TABLP: + MOV AL," " + CALL OUT + LOOP TABLP +POPTAB: + POP CX + POP AX + RET + + +DOCONOUT: + PUSH DS + PUSH SI + PUSH AX +CONOWAIT: + LDS SI,CS:[COUT] + MOV AH,10 + CALL DEVIOCALL + MOV AX,CS:[IOSTAT] + AND AX,200H + JNZ CONOWAIT + POP AX + PUSH AX + MOV AH,8 + CALL DEVIOCALL + POP AX + POP SI + POP DS + RET + + +LISTOUT: + PUSH DS + PUSH SI + PUSH AX +LISTWAIT: + LDS SI,CS:[POUT] + MOV AH,10 + CALL DEVIOCALL + MOV AX,CS:[IOSTAT] + AND AX,200H + JNZ LISTWAIT + POP AX + PUSH AX + MOV AH,8 + CALL DEVIOCALL + POP AX + POP SI + POP DS + RET + +DEVIOCALL: + PUSH ES + PUSH BX + PUSH CS + POP ES + MOV BX,OFFSET DG:IOCALL + MOV CS:[IOCOM],AH + MOV WORD PTR CS:[IOSTAT],0 + MOV WORD PTR CS:[IOCNT],1 + MOV CS:[IOBUFF],AL + MOV WORD PTR CS:[IOADDR+2],DS + MOV AX,[SI+6] + MOV WORD PTR CS:[IOADDR],AX + CALL DWORD PTR CS:[IOADDR] + MOV AX,[SI+8] + MOV WORD PTR CS:[IOADDR],AX + CALL DWORD PTR CS:[IOADDR] + MOV AL,CS:[IOBUFF] + POP BX + POP ES + RET + ELSE + +OUT: + PUSH DX + PUSH AX + AND AL,7FH + MOV DL,AL + MOV AH,2 + INT 21H + POP AX + POP DX + RET + ENDIF + + + IF SYSVER +RBUFIN: + PUSH AX + PUSH ES + PUSH DI + PUSH CS + POP ES + MOV BYTE PTR [LBUFFCNT],0 + MOV DI,OFFSET DG:LINEBUF +FILLBUF: + CALL IN + CMP AL,0DH + JZ BDONE + CMP AL,8 + JZ ECHR + CMP AL,7FH + JZ ECHR + CMP BYTE PTR [LBUFFCNT],BUFLEN + JAE BFULL + STOSB + INC BYTE PTR [LBUFFCNT] + JMP SHORT FILLBUF + +BDONE: + STOSB + POP DI + POP ES + POP AX + RET + +BFULL: + MOV AL,8 + CALL OUT + MOV AL,7 + CALL OUT + JMP SHORT FILLBUF + +ECHR: + CMP DI,OFFSET DG:LINEBUF + JZ FILLBUF + DEC DI + DEC BYTE PTR [LBUFFCNT] + JMP SHORT FILLBUF + ELSE + +RBUFIN: + PUSH AX + PUSH DX + MOV AH,10 + MOV DX,OFFSET DG:LBUFSIZ + INT 21H + POP DX + POP AX + RET + ENDIF + + + IF SYSVER +RPRBUF: + PUSHF + PUSH AX + PUSH SI + MOV SI,DX +PLOOP: + LODSB + CMP AL,"$" + JZ PRTDONE + CALL OUT + JMP SHORT PLOOP +PRTDONE: + POP SI + POP AX + POPF + RET + ELSE + +RPRBUF: + MOV AH,9 + INT 21H + RET + ENDIF + +; Output one space + +BLANK: + MOV AL," " + JMP OUT + +; Output the number of blanks in CX + +TAB: + CALL BLANK + LOOP TAB + RET + +; Command Table. Command letter indexes into table to get +; address of command. PERR prints error for no such command. + +COMTAB DW ASSEM ; A + DW PERR ; B + DW COMPARE ; C + DW DUMP ; D + DW ENTER ; E + DW FILL ; F + DW GO ; G + DW HEXADD ; H + DW INPUT ; I + DW PERR ; J + DW PERR ; K + DW LOAD ; L + DW MOVE ; M + DW NAME ; N + DW OUTPUT ; O + IF ZIBO + DW ZTRACE + ELSE + DW PERR ; P + ENDIF + DW QUIT ; Q (QUIT) + DW REG ; R + DW SEARCH ; S + DW TRACE ; T + DW UNASSEM ; U + DW PERR ; V + DW DWRITE ; W + IF SYSVER + DW SETUDEV ; X + ELSE + DW PERR + ENDIF + DW PERR ; Y + DW PERR ; Z + +QUIT: + INC BYTE PTR [QFLAG] + MOV BX,[USER_PROC_PDB] +FIND_DEBUG: +IF NOT SYSVER + MOV AH,SET_CURRENT_PDB + INT 21H +ENDIF + CALL ReleaseParity ; let system do normal parity stuff + MOV AX,(EXIT SHL 8) + INT 21H + +CODE ENDS + END START + \ No newline at end of file diff --git a/DEV.ASM b/DEV.ASM new file mode 100644 index 0000000..b640d55 --- /dev/null +++ b/DEV.ASM @@ -0,0 +1,439 @@ +; +; Device call routines for MSDOS +; + +INCLUDE DOSSEG.ASM + +IFNDEF KANJI +KANJI EQU 0 ;FALSE +ENDIF + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xlist +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + +TITLE DEV - Device call routines +NAME Dev + + i_need IOXAD,DWORD + i_need IOSCNT,WORD + i_need DEVIOBUF,4 + i_need IOCALL,BYTE + i_need IOMED,BYTE + i_need IORCHR,BYTE + i_need CALLSCNT,WORD + i_need DMAAdd,DWORD + i_need NullDevPt,DWORD + i_need CallDevAd,DWORD + i_need Attrib,BYTE + i_need NULDEV,DWORD + i_need Name1,BYTE + i_need DevPt,DWORD + i_need DPBHead,DWORD + i_need NumIO,BYTE + i_need ThisDPB,DWORD + i_need DevCall,DWORD + i_need VerFlg,BYTE + +SUBTTL IOFUNC -- DO FUNCTION 1-12 I/O +PAGE +IOFUNC_RETRY: +ASSUME DS:NOTHING,ES:NOTHING + invoke restore_world + + procedure IOFUNC,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:SI Points to FCB +; AH is function code +; = 0 Input +; = 1 Input Status +; = 2 Output +; = 3 Output Status +; = 4 Flush +; AL = character if output +; Function: +; Perform indicated I/O to device or file +; Outputs: +; AL is character if input +; If a status call +; zero set if not ready +; zero reset if ready (character in AL for input status) +; For regular files: +; Input Status +; Gets character but restores fcb_RR field +; Zero set on EOF +; Input +; Gets character advances fcb_RR field +; Returns ^Z on EOF +; Output Status +; Always ready +; AX altered, all other registers preserved + + MOV WORD PTR [IOXAD+2],SS + MOV WORD PTR [IOXAD],OFFSET DOSGROUP:DEVIOBUF + MOV WORD PTR [IOSCNT],1 + MOV WORD PTR [DEVIOBUF],AX + +IOFUNC2: + TEST [SI.fcb_DEVID],080H + JNZ IOTODEV + JMP IOTOFILE + +IOTODEV: + invoke save_world + PUSH DS + PUSH SS + POP ES + PUSH SS + POP DS +ASSUME DS:DOSGROUP + XOR BX,BX + MOV [IOCALL.REQSTAT],BX + MOV BYTE PTR [IOMED],BL + + MOV BX,OFFSET DOSGROUP:IOCALL + + MOV CX,(DEVRD SHL 8) OR DRDWRHL + OR AH,AH + JZ DCALLR + MOV CX,(DEVRDND SHL 8) OR DRDNDHL + DEC AH + JZ DCALLR + MOV CX,(DEVWRT SHL 8) OR DRDWRHL + DEC AH + JZ DCALLO + MOV CX,(DEVOST SHL 8) OR DSTATHL + DEC AH + JZ DCALLO +DFLUSH: + MOV CX,(DEVIFL SHL 8) OR DFLSHL +DCALLR: + MOV AH,86H +DCALL: + MOV [IOCALL.REQLEN],CL + MOV [IOCALL.REQFUNC],CH + MOV CL,AH + POP DS +ASSUME DS:NOTHING + CALL DEVIOCALL + MOV DI,[IOCALL.REQSTAT] + TEST DI,STERR + JZ OKDEVIO + MOV AH,CL + invoke CHARHARD + CMP AL,1 + JZ IOFUNC_RETRY +;Know user must have wanted ignore. Make sure device shows ready so +;that DOS doesn't get caught in a status loop when user simply wants +;to ignore the error. + AND BYTE PTR [IOCALL.REQSTAT+1], NOT (STBUI SHR 8) +OKDEVIO: + PUSH SS + POP DS +ASSUME DS:DOSGROUP + CMP CH,DEVRDND + JNZ DNODRD + MOV AL,BYTE PTR [IORCHR] + MOV [DEVIOBUF],AL + +DNODRD: MOV AH,BYTE PTR [IOCALL.REQSTAT+1] + NOT AH ; Zero = busy, not zero = ready + AND AH,STBUI SHR 8 + + invoke restore_world +ASSUME DS:NOTHING + MOV AX,WORD PTR [DEVIOBUF] + return + +DCALLO: + MOV AH,87H + JMP SHORT DCALL + +IOTOFILE: +ASSUME DS:NOTHING + OR AH,AH + JZ IOIN + DEC AH + JZ IOIST + DEC AH + JZ IOUT + return ; NON ZERO FLAG FOR OUTPUT STATUS + +IOIST: + PUSH WORD PTR [SI.fcb_RR] ; Save position + PUSH WORD PTR [SI.fcb_RR+2] + CALL IOIN + POP WORD PTR [SI.fcb_RR+2] ; Restore position + POP WORD PTR [SI.fcb_RR] + return + +IOUT: + CALL SETXADDR + invoke STORE + invoke FINNOSAV + CALL RESTXADDR ; If you change this into a jmp don't come + return ; crying to me when things don't work ARR + +IOIN: + CALL SETXADDR + invoke LOAD + PUSH CX + invoke FINNOSAV + POP CX + OR CX,CX ; Check EOF + CALL RESTXADDR + MOV AL,[DEVIOBUF] ; Get byte from trans addr + retnz + MOV AL,1AH ; ^Z if EOF + return + +SETXADDR: + POP WORD PTR [CALLSCNT] ; Return address + invoke save_world + PUSH WORD PTR [DMAADD] ; Save Disk trans addr + PUSH WORD PTR [DMAADD+2] + PUSH DS + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV CX,WORD PTR [IOXAD+2] + MOV WORD PTR [DMAADD+2],CX + MOV CX,WORD PTR [IOXAD] + MOV WORD PTR [DMAADD],CX ; Set byte trans addr + MOV CX,[IOSCNT] ; ioscnt specifies length of buffer + POP DS +ASSUME DS:NOTHING + MOV [SI.fcb_RECSIZ],1 ; One byte per record + MOV DX,SI ; FCB to DS:DX + invoke GETRRPOS + JMP SHORT RESTRET ; RETURN ADDRESS + +RESTXADDR: + POP WORD PTR [CALLSCNT] ; Return address + POP WORD PTR [DMAADD+2] ; Restore Disk trans addr + POP WORD PTR [DMAADD] + invoke restore_world +RESTRET:JMP WORD PTR [CALLSCNT] ; Return address +IOFUNC ENDP + +SUBTTL DEVIOCALL, DEVIOCALL2 - CALL A DEVICE +PAGE + procedure DEVIOCALL,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:SI Points to device FCB +; ES:BX Points to request data +; Function: +; Call the device +; Outputs: +; None +; DS:SI,AX destroyed, others preserved + + LDS SI,DWORD PTR [SI.fcb_FIRCLUS] + + entry DEVIOCALL2 +; As above only DS:SI points to device header on entry, and DS:SI is preserved + MOV AX,[SI.SDEVSTRAT] + MOV WORD PTR [CALLDEVAD],AX + MOV WORD PTR [CALLDEVAD+2],DS + CALL DWORD PTR [CALLDEVAD] + MOV AX,[SI.SDEVINT] + MOV WORD PTR [CALLDEVAD],AX + CALL DWORD PTR [CALLDEVAD] + return +DEVIOCALL ENDP + +SUBTTL DEVNAME - LOOK FOR NAME OF DEVICE +PAGE + procedure DEVNAME,NEAR +ASSUME DS:DOSGROUP,ES:DOSGROUP + +; Inputs: +; DS,ES:DOSGROUP +; Filename in NAME1 +; Function: +; Determine if file is in list of I/O drivers +; Outputs: +; Carry set if name not found +; ELSE +; Zero flag set +; BH = Bit 7,6 = 1, bit 5 = 0 (cooked mode) +; bits 0-4 set from low byte of attribute word +; DEVPT = DWORD pointer to Device header of device +; Registers BX destroyed + + PUSH SI + PUSH DI + PUSH CX + + IF KANJI + PUSH WORD PTR [NAME1] + CMP [NAME1],5 + JNZ NOKTR + MOV [NAME1],0E5H +NOKTR: + ENDIF + + TEST BYTE PTR [ATTRIB],attr_volume_id ; If looking for VOL id don't find devs + JNZ RET31 + MOV SI,OFFSET DOSGROUP:NULDEV +LOOKIO: +ASSUME DS:NOTHING + TEST [SI.SDEVATT],DEVTYP + JZ SKIPDEV ; Skip block devices + PUSH SI + ADD SI,SDEVNAME + MOV DI,OFFSET DOSGROUP:NAME1 + MOV CX,4 ; All devices are 8 letters + REPE CMPSW ; Check for name in list + POP SI + JZ IOCHK ; Found it? +SKIPDEV: + LDS SI,DWORD PTR [SI] ; Get address of next device + CMP SI,-1 ; At end of list? + JNZ LOOKIO +RET31: STC ; Not found +RETNV: PUSH SS + POP DS +ASSUME DS:DOSGROUP + + IF KANJI + POP WORD PTR [NAME1] + ENDIF + + POP CX + POP DI + POP SI + RET + +IOCHK: +ASSUME DS:NOTHING + MOV WORD PTR [DEVPT+2],DS ; Save pointer to device + MOV BH,BYTE PTR [SI.SDEVATT] + OR BH,0C0H + AND BH,NOT 020H ;Clears Carry + MOV WORD PTR [DEVPT],SI + JMP RETNV +DevName ENDP + + procedure GetBP,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; AL = Logical unit number (A = 0) +; Function: +; Find Drive Parameter Block +; Outputs: +; ES:BP points to DPB +; [THISDPB] = ES:BP +; Carry set if unit number bad +; No other registers altered + + LES BP,[DPBHEAD] ; Just in case drive isn't valid + AND AL,3FH ; Mask out dirty and device bits + CMP AL,BYTE PTR [NUMIO] + CMC + JC GOTDPB ; Get drive A +FNDDPB: + CMP AL,ES:[BP.dpb_drive] + JZ GOTDPB ; Carry is clear if jump executed + LES BP,ES:[BP.dpb_next_dpb] + JMP SHORT FNDDPB +GOTDPB: + MOV WORD PTR [THISDPB],BP + MOV WORD PTR [THISDPB+2],ES + RET +GetBP ENDP + +SUBTTL SETREAD, SETWRITE -- SET UP HEADER BLOCK +PAGE + procedure SETREAD,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:BX = Transfer Address +; CX = Record Count +; DX = Starting Record +; AH = Media Byte +; AL = Unit Code +; Function: +; Set up the device call header at DEVCALL +; Output: +; ES:BX Points to DEVCALL +; No other registers effected + + PUSH DI + PUSH CX + PUSH AX + MOV CL,DEVRD +SETCALLHEAD: + MOV AL,DRDWRHL + PUSH SS + POP ES + MOV DI,OFFSET DOSGROUP:DEVCALL + STOSB ; length + POP AX + STOSB ; Unit + PUSH AX + MOV AL,CL + STOSB ; Command code + XOR AX,AX + STOSW ; Status + ADD DI,8 ; Skip link fields + POP AX + XCHG AH,AL + STOSB ; Media byte + XCHG AL,AH + PUSH AX + MOV AX,BX + STOSW + MOV AX,DS + STOSW ; Transfer addr + POP CX ; Real AX + POP AX ; Real CX + STOSW ; Count + XCHG AX,DX ; AX=Real DX, DX=real CX, CX=real AX + STOSW ; Start + XCHG AX,CX + XCHG DX,CX + POP DI + MOV BX,OFFSET DOSGROUP:DEVCALL + RET + + entry SETWRITE +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:BX = Transfer Address +; CX = Record Count +; DX = Starting Record +; AH = Media Byte +; AL = Unit Code +; Function: +; Set up the device call header at DEVCALL +; Output: +; ES:BX Points to DEVCALL +; No other registers effected + + PUSH DI + PUSH CX + PUSH AX + MOV CL,DEVWRT + ADD CL,[VERFLG] + JMP SHORT SETCALLHEAD +SETREAD ENDP + +do_ext + +CODE ENDS + END + \ No newline at end of file diff --git a/DIR.ASM b/DIR.ASM new file mode 100644 index 0000000..d0bb84f --- /dev/null +++ b/DIR.ASM @@ -0,0 +1,1084 @@ +; +; Directory routines for MSDOS +; + +INCLUDE DOSSEG.ASM + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xlist +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + +TITLE DIR - Directory and path cracking +NAME Dir + + i_need NoSetDir,BYTE + i_need EntFree,WORD + i_need DirStart,WORD + i_need LastEnt,WORD + i_need ClusNum,WORD + i_need CurBuf,DWORD + i_need ThisFCB,DWORD + i_need Attrib,BYTE + i_need DelAll,BYTE + i_need VolID,BYTE + i_need Name1,BYTE + i_need ThisDPB,DWORD + i_need EntLast,WORD + i_need Creating,BYTE + i_need SecClusPos,BYTE + i_need ClusFac,BYTE + i_need NxtClusNum,WORD + i_need DirSec,WORD + i_need DriveSpec,BYTE + i_need Device_availability,BYTE + i_need RootStart,BYTE + i_need DevString,BYTE + i_need DevStrLen,BYTE + +SUBTTL BUILDDIR,NEWDIR -- ALLOCATE DIRECTORIES +PAGE + procedure BUILDDIR,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; ES:BP Points to DPB +; [THISFCB] Set if using NEWDIR entry point +; [LASTENT] current last valid entry number in directory if no free +; entries +; Function: +; Grow directory if no free entries and not root +; Outputs: +; CARRY SET IF FAILURE +; ELSE +; AX entry number of new entry +; If a new dir [DIRSTART],[CLUSFAC],[CLUSNUM],[DIRSEC] set +; AX = first entry of new dir +; GETENT should be called to set [LASTENT] + + MOV AX,[ENTFREE] + CMP AX,-1 + JNZ GOTRET + CMP [DIRSTART],0 + JNZ NEWDIR + STC + return ; Can't grow root + + entry NEWDIR + MOV BX,[DIRSTART] + OR BX,BX + JZ NULLDIR + invoke GETEOF +NULLDIR: + MOV CX,1 + invoke ALLOCATE + retc + MOV DX,[DIRSTART] + OR DX,DX + JNZ ADDINGDIR + call SETDIRSRCH + MOV [LASTENT],-1 + JMP SHORT GOTDIRREC +ADDINGDIR: + CMP [CLUSNUM],0FF8H + JB NOTFIRSTGROW + MOV [CLUSNUM],BX +NOTFIRSTGROW: + MOV DX,BX + XOR BL,BL + invoke FIGREC +GOTDIRREC: + MOV CL,ES:[BP.dpb_cluster_mask] + INC CL + XOR CH,CH +ZERODIR: + PUSH CX + MOV AL,0FFH + invoke GETBUFFR + MOV CX,ES:[BP.dpb_sector_size] + PUSH ES + LES DI,[CURBUF] + PUSH DI + ADD DI,BUFINSIZ + XOR AX,AX + SHR CX,1 + REP STOSW + JNC EVENZ + STOSB +EVENZ: + POP DI + INC AL + MOV ES:[DI.BUFDIRTY],AL + POP ES + POP CX + INC DX + LOOP ZERODIR + MOV AX,[LASTENT] + INC AX +GOTRET: + CLC + return + +BUILDDIR ENDP + +; +; set up a . and .. directory entry for a directory +; + procedure SETDOTENT,NEAR +ASSUME DS:DOSGROUP + MOV CX,4 + MOV AX,2020H + REP STOSW + STOSB + MOV SI,WORD PTR [THISFCB] + MOV AL,attr_directory + STOSB + ADD DI,10 + MOV AX,[SI.fcb_FTIME] + STOSW + MOV AX,[SI.fcb_FDATE] + STOSW + MOV AX,DX + STOSW + XOR AX,AX + STOSW + STOSW + return +SETDOTENT ENDP + +SUBTTL GETFILE, GETNAME, FINDNAME -- LOOK FOR A FILE +PAGE + procedure SEARCH,near + + entry GETFILE +ASSUME DS:NOTHING,ES:NOTHING +; Same as GETNAME except ES:DI points to FCB on successful return + invoke MOVNAME + retc + PUSH DX + PUSH DS + CALL FINDNAME + POP ES + POP DI + return + + entry GETNAME +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS,DX point to FCB +; Function: +; Find file name in disk directory. First byte is +; drive number (0=current disk). "?" matches any +; character. +; Outputs: +; Carry set if file not found +; ELSE +; Zero set if attributes match (always except when creating) +; AH = Device ID (bit 7 set if not disk) +; [THISDPB] = Base of drive parameters +; DS = DOSGROUP +; ES = DOSGROUP +; [CURBUF+2]:BX = Pointer into directory buffer +; [CURBUF+2]:SI = Pointer to First Cluster field in directory entry +; [CURBUF] has directory record with match +; [NAME1] has file name +; All other registers destroyed. + + invoke MOVNAME +ASSUME ES:DOSGROUP + retc ; Bad file name? + + entry FINDNAME + PUSH SS + POP DS +ASSUME DS:DOSGROUP + invoke DEVNAME + JC FindEntry + invoke BUILDFCB + return +ASSUME ES:NOTHING + +; NOTE THE FALL THROUGH + +SUBTTL FINDENTRY -- LOOK FOR AN ENTRY +PAGE + entry FindEntry +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; [THISDPB] set +; [SECCLUSPOS] = 0 +; [DIRSEC] = Starting directory sector number +; [CLUSNUM] = Next cluster of directory +; [CLUSFAC] = Sectors/Cluster +; [NAME1] = Name to look for +; Function: +; Find file name in disk directory. +; "?" matches any character. +; Outputs: +; Carry set if name not found +; ELSE +; Zero set if attributes match (always except when creating) +; AH = Device ID (bit 7 set if not disk) +; [THISDPB] = Base of drive parameters +; DS = DOSGROUP +; ES = DOSGROUP +; [CURBUF+2]:BX = Pointer into directory buffer +; [CURBUF+2]:SI = Pointer to First Cluster field in directory entry +; [CURBUF] has directory record with match +; [NAME1] has file name +; [LASTENT] is entry number of the entry +; All other registers destroyed. + + CALL STARTSRCH + CMP BYTE PTR [ATTRIB],attr_volume_id + ; Looking for vol ID only ? + JNZ NOTVOLSRCH ; No + CALL SETROOTSRCH ; Yes force search of root +NOTVOLSRCH: + CALL GETENTRY + entry Srch + PUSH DS + MOV DS,WORD PTR [CURBUF+2] +ASSUME DS:NOTHING + MOV AH,BYTE PTR [BX] + OR AH,AH ; End of directory? + JZ FREE + CMP AH,BYTE PTR [DELALL] ; Free entry? + JZ FREE + TEST BYTE PTR [BX+11],attr_volume_id + ; Volume ID file? + JZ CHKFNAM ; NO + INC BYTE PTR [VOLID] +CHKFNAM: + MOV SI,BX + PUSH SS + POP ES +ASSUME ES:DOSGROUP + MOV DI,OFFSET DOSGROUP:NAME1 + MOV CX,11 +WILDCRD: + REPE CMPSB + JZ FOUND + CMP BYTE PTR ES:[DI-1],"?" + JZ WILDCRD + POP DS +ASSUME DS:DOSGROUP + entry NEXTENT + LES BP,[THISDPB] +ASSUME ES:NOTHING + CALL NEXTENTRY + JNC SRCH + JMP SHORT SETESRET + +FREE: + POP DS +ASSUME DS:DOSGROUP + MOV CX,[LASTENT] + CMP CX,[ENTFREE] + JAE TSTALL + MOV [ENTFREE],CX +TSTALL: + CMP AH,BYTE PTR [DELALL] ; At end of directory? + JZ NEXTENT ; No - continue search + MOV [ENTLAST],CX + STC + JMP SHORT SETESRET + +FOUND: +; +; We have a file with a matching name. We must now consider +; the attributes: +; ATTRIB Action +; ------ ------ +; Volume_ID Is Volume_ID in test? +; Otherwise If no create then Is ATTRIB+extra superset of test? +; If create then Is ATTRIB equal to test? +; + MOV CH,[SI] ; Attributes of file + POP DS +ASSUME DS:DOSGROUP + MOV AH,BYTE PTR [ATTRIB] ; Attributes of search + TEST CH,attr_volume_id ; Volume ID file? + JZ check_one_volume_id ; Nope check other attributes + TEST AH,attr_volume_id ; Can we find Volume ID? + JZ NEXTENT ; Nope, (not even $FCB_CREATE) + XOR AH,AH ; Set zero flag for $FCB_CREATE + JMP SHORT RETF ; Found Volume ID +check_one_volume_id: + CMP AH,attr_volume_id ; Looking only for Volume ID? + JZ NEXTENT ; Yes, continue search + ADD SI,15 + CALL MatchAttributes + JZ RETF + TEST BYTE PTR [CREATING],-1 ; Pass back mismatch if creating + JZ NEXTENT ; Otherwise continue searching +RETF: + LES BP,[THISDPB] + MOV AH,ES:[BP.dpb_drive] +SETESRET: + PUSH SS + POP ES + return + +SUBTTL GETENTRY, NEXTENTRY, GETENT -- STEP THROUGH DIRECTORY +PAGE + entry GETENTRY +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; [LASTENT] has directory entry +; ES:BP points to drive parameters +; Function: +; Locates directory entry in preparation for search +; GETENT provides entry for passing desired entry in AX +; A valid search environment MUST exist +; ENDENT,ENTLAST,ENTFREE +; Outputs: +; [CURBUF+2]:BX = Pointer to next directory entry in CURBUF +; [CURBUF+2]:DX = Pointer to first byte after end of CURBUF +; [LASTENT] = New directory entry number + + MOV AX,[LASTENT] + entry GETENT + MOV [LASTENT],AX + MOV CL,4 + SHL AX,CL + XOR DX,DX + SHL AX,1 + RCL DX,1 ; Account for overflow in last shift + MOV BX,ES:[BP.dpb_sector_size] + AND BL,255-31 ; Must be multiple of 32 + DIV BX + MOV BX,DX ; Position within sector + PUSH BX + invoke DIRREAD + POP BX +SETENTRY: + MOV DX,WORD PTR [CURBUF] + ADD DX,BUFINSIZ + ADD BX,DX + ADD DX,ES:[BP.dpb_sector_size] ; Always clears carry + return + + entry NEXTENTRY +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; Same as outputs of GETENTRY, above +; Function: +; Update BX, and [LASTENT] for next directory entry. +; Carry set if no more. + + MOV AX,[LASTENT] + CMP AX,[ENTLAST] + JZ NONE + INC AX + ADD BX,32 + CMP BX,DX + JB HAVIT + MOV BL,BYTE PTR [SECCLUSPOS] + INC BL + CMP BL,BYTE PTR [CLUSFAC] + JB SAMECLUS + MOV BX,[NXTCLUSNUM] + CMP BX,0FF8H + JAE NONE + CMP BX,2 + JB NONE + JMP GETENT + +NONE: + STC + return + +HAVIT: + MOV [LASTENT],AX + CLC + return + +SAMECLUS: + MOV BYTE PTR [SECCLUSPOS],BL + MOV [LASTENT],AX + PUSH DS + LDS DI,[CURBUF] +ASSUME DS:NOTHING + MOV DX,[DI.BUFSECNO] + INC DX + POP DS +ASSUME DS:DOSGROUP + invoke FIRSTCLUSTER + XOR BX,BX + JMP SETENTRY +Search ENDP + +SUBTTL GETCURRDIR -- GET CURRENT DIRECTORY +PAGE + procedure Dir_search,NEAR + entry GETCURRDIR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; ES:BP Points to DPB +; FATREAD should be called before this routine +; Function: +; Find current directory for drive +; If path is bad set current directory to the root +; Outputs: +; DS = DOSGROUP +; [SECCLUSPOS] = 0 +; [DIRSTART] = Cluster # of first cluster of directory ( 0 if root) +; [DIRSEC] Set to phys sec # of first sector first cluster of directory +; [CLUSNUM] Set to next cluster +; [CLUSFAC] Sectors/cluster +; Destroys all registers + + MOV BX,ES:[BP.dpb_current_dir] + OR BX,BX + JZ SETROOTSRCH + CMP BX,0FF8H + JB SETDIRSRCH + PUSH ES + POP DS + LEA SI,[BP.dpb_dir_text] + CALL ROOTPATH +ASSUME DS:DOSGROUP + JNC SETCURR + MOV ES:[BP.dpb_current_dir],0 + +SETROOTSRCH: +ASSUME DS:NOTHING,ES:NOTHING + PUSH SS + POP DS +ASSUME DS:DOSGROUP + XOR AX,AX + MOV [DIRSTART],AX + MOV BYTE PTR [SECCLUSPOS],AL + DEC AX + MOV [CLUSNUM],AX + MOV AX,ES:[BP.dpb_first_sector] + MOV DX,ES:[BP.dpb_dir_sector] + SUB AX,DX + MOV BYTE PTR [CLUSFAC],AL + MOV [DIRSEC],DX + return + +SETCURR: +ASSUME DS:DOSGROUP + MOV AX,[DIRSTART] + MOV ES:[BP.dpb_current_dir],AX + return + + entry SETDIRSRCH +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; BX cluster number of start of directory +; ES:BP Points to DPB +; Function: +; Set up a directory search +; Outputs: +; DS = DOSGROUP +; [DIRSTART] = BX +; [CLUSFAC],[CLUSNUM],[SECCLUSPOS],[DIRSEC] set +; destroys AX,DX + + OR BX,BX + JZ SETROOTSRCH + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV [DIRSTART],BX + MOV AL,ES:[BP.dpb_cluster_mask] + INC AL + MOV BYTE PTR [CLUSFAC],AL + invoke UNPACK + MOV [CLUSNUM],DI + MOV DX,BX + XOR BL,BL + MOV BYTE PTR [SECCLUSPOS],BL + invoke FIGREC + MOV [DIRSEC],DX + return +Dir_search ENDP + +SUBTTL MAKENODE -- CREATE A NEW NODE +PAGE + procedure MakeNode,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; AL - attribute to create +; DS:SI Points to asciz path +; [THISFCB] Points to an empty FCB +; Function: +; Make a new node +; Outputs: +; DS=DOSGROUP +; ES:BP Points to DPB +; AX = 0 Success +; AX = 1 A node by this name exists and is a directory +; AX = 2 A new node could not be created error +; AX = 3 A node by this name exists and is a file error +; AX = 4 Bad Path error +; AX = 5 Attribute mismatch error +; CARRY SET IF ERROR +; ELSE +; [DIRSTART],[DIRSEC],[CLUSFAC],[CLUSNUM] set to directory +; containing new node. +; [CURBUF+2]:BX Points to entry +; [CURBUF+2]:SI Points to entry.fcb_firclus +; [ThisFCB] is filled in +; If this is a new entry zero is set and +; Attribute byte in entry is directory +; else a file existed by this name and: +; [NAME1] has name +; entry is not changed in any way +; Destroys all registers + + PUSH AX + CALL GetPath + MOV DL,CL ; Save CL info + POP CX + MOV BYTE PTR [ATTRIB],CL + MOV CX,AX + JNC make_exists ; File existed + JNZ make_err_4 ; Path bad + OR DL,DL ; Check "CL" return from GETPATH + JNZ make_type ; Name simply not found +make_err_4: + MOV AL,4 ; case 1 bad path +make_err_ret: + STC + return + +make_type: + XOR AL,AL ; nothing exists... assume 0 + STC + JMP SHORT make_save +make_exists: + JZ make_exists_dir + MOV AL,3 ; file exists type 3 + TEST BYTE PTR [ATTRIB],(attr_volume_id+attr_directory) + JNZ make_err_ret_5 ; but we wanted a volid or dir + OR CH,CH + JS make_dev ; No furthur checks if device + PUSH CX + MOV DS,WORD PTR [CURBUF+2] + MOV CH,[BX+dir_attr] ; Get file attributes + TEST CH,attr_read_only + JNZ make_err_ret_5P ; Cannot create on read only files + CALL MatchAttributes +make_err_ret_5P: + POP CX + JZ make_dev ; Attributes ok +make_err_ret_5: + MOV AL,5 ; Attribute mismatch + JMP SHORT make_err_ret + +make_dev: + XOR AL,AL ; Make sure zero set(atts match), carry clear(exists) + MOV AL,3 ; Restore correct value + JMP SHORT make_save +make_exists_dir: + MOV AL,1 ; directory exists + TEST BYTE PTR [ATTRIB],attr_directory + JZ make_err_ret ; we didn't want a directory + CLC + return ; just return +make_save: + PUSH AX +; +; set up for call to NewEntry - it is in the middle of FCB_CREATE +; so we must also pre-push two registers. They will be popped off +; by FCB_CREATE +; + PUSH SS + POP DS + ASSUME DS:DOSGROUP + PUSHF ;Save state of flags + CMP BYTE PTR [NAME1],'.' ;Detect attempt to make '.' or '..' + JNZ NOTLDOT ; Needed because no '.' or '..' in root + POPF + MOV AL,1 ;Force type 2 error + JMP SHORT SET2ERR + +NOTLDOT: + POPF + PUSH ES + LES DI,[ThisFCB] + PUSH DS + PUSH DI + PUSH ES + MOV AX,CX + invoke NewEntry + POP DS + POP ES +SET2ERR: + OR AL,AL + POP AX + JZ make_set_fcb + MOV AL,2 ; create failed case 2 + STC + return +make_set_fcb: +ASSUME DS:DOSGROUP + PUSH ES + LES DI,[THISFCB] + INC DI + PUSH DS + PUSH SI + MOV DS,WORD PTR [CURBUF+2] +ASSUME DS:NOTHING + MOV SI,BX + MOV CX,11 + REP MOVSB + POP SI + POP DS +ASSUME DS:DOSGROUP + POP ES + CMP AL,1 + JA make_errors + OR AL,AL + CLC + return +make_errors: + STC + return + +MakeNode ENDP + +SUBTTL GETPATH -- PARSE AN asciz PATH +PAGE + + procedure GETPATH,near +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:SI Points to asciz path +; Function: +; Crack the path +; Outputs: +; [DRIVESPEC] is non zero if a drive was specified +; [ROOTSTART] is non zero if a / started the path +; [ATTRIB] set to attr_directory+attr_hidden+attr_system +; Same as FINDPATH except if path specifies a device in which case +; bit 7 of AH will be set and SI and BX will point DOSGROUP relative +; Destroys all registers + + XOR AX,AX + MOV WORD PTR [DRIVESPEC],AX + MOV BYTE PTR [ATTRIB],attr_directory+attr_system+attr_hidden + LODSB + invoke PATHCHRCMP + JZ DEFAULTROOT + MOV AH,AL + LODSB + CMP AL,':' + JZ DRVSPEC + DEC SI + DEC SI + PUSH DS + PUSH SI + PUSH SS + POP ES + CMP BYTE PTR [device_availability],0 + JZ NOWDEV + CALL GOTPRESTRING2 + JNC BUILDFCBJ ; If no carry then we have a device +NOWDEV: + CALL DEFPATH +GOFIND: + MOV AL,[NoSetDir] + PUSH AX + MOV [NoSetDir],0 + CALL GETCURRDIR + POP AX + MOV [NoSetDir],AL + POP SI + POP DS + JMP FINDPATH + +DEFPATH: + XOR AL,AL +DRVPATH: + invoke GETTHISDRV + retc ; Bad drive + PUSH SS + POP DS + invoke FATREAD + CLC + return + +DEFAULTROOT: + PUSH DS + PUSH SI + CALL DEFPATH + POP SI + POP DS +ROOTSRCH: + INC BYTE PTR [ROOTSTART] + CMP BYTE PTR [SI],0 + JZ PATHISNULL + PUSH DS + PUSH SI + PUSH ES ; Save pointer to DPB + CALL CHKDEV + POP ES + JNC BUILDFCBJ + POP SI + POP DS + JMP ROOTPATH + +BUILDFCBJ: + POP AX + POP AX + context es + invoke BUILDFCB ; Clears carry sets zero + INC AL ; reset zero + return + +DRVSPEC: + INC [DRIVESPEC] + MOV AL,AH + OR AL,20H ; Convert to lower case + SUB AL,60H ; Make A=1 + PUSH DS + PUSH SI + PUSH AX + context es + CALL GotPreString2 + ASSUME ES:NOTHING + POP AX + JNC BuildFCBJ + CALL DRVPATH + POP SI + POP DS + retc ; Bad drive + LODSB + invoke PATHCHRCMP + JZ ROOTSRCH + DEC SI + PUSH DS + PUSH SI + JMP GOFIND + +PATHISNULL: + CALL SETROOTSRCH +ASSUME DS:DOSGROUP + XOR AL,AL ; Set zero (directory) clear carry + return + +CHKDEV: +ASSUME DS:NOTHING + PUSH SS + POP ES + MOV DI,OFFSET DOSGROUP:DEVSTRING + XOR CX,CX + MOV CL,DEVSTRLEN +CHKPRESTRING: + REPE CMPSB + JZ GOTPRESTRING + DEC SI + invoke GETLET ; Try convert to upper case + CMP AL,ES:[DI-1] + JZ CHKPRESTRING +NOPRESTRING: + STC + return + +GOTPRESTRING: + LODSB + invoke PATHCHRCMP + JNZ NOPRESTRING +GOTPRESTRING2: + MOV DI,OFFSET DOSGROUP:NAME1 + MOV CX,9 +TESTLOOP: + invoke GETLET + CMP AL,'.' + JZ TESTDEVICE + invoke PATHCHRCMP + JZ NOTDEV + OR AL,AL + JZ TESTDEVICE + STOSB + LOOP TESTLOOP +NOTDEV: + STC + return + +TESTDEVICE: + ADD CX,2 + MOV AL,' ' + REP STOSB + PUSH SS + POP DS + invoke DEVNAME + return +GETPATH ENDP + +SUBTTL ROOTPATH, FINDPATH -- PARSE A PATH +PAGE + procedure ROOTPATH,near + +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; ES:BP Points to DPB +; FATREAD should be called before this routine +; DS:SI Points to asciz string of path which is assumed to start at +; the root (no leading '/'). +; Function: +; Search from root for path +; Outputs: +; Same as FINDPATH +; Destroys all registers + + PUSH DS + CALL SETROOTSRCH + POP DS + +; NOTE FALL THROUGH + + entry FINDPATH +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; ES:BP Points to DPB +; DS:SI Points to asciz string of path (no leading '/'). +; [SECCLUSPOS] = 0 +; [DIRSEC] = Phys sec # of first sector of directory +; [CLUSNUM] = Cluster # of next cluster +; [CLUSFAC] = Sectors per cluster +; Validate_path should be called before this routine is used, +; unless it is KNOWN the path is good. +; Function: +; Parse path name +; Outputs: +; ES:BP Points to DPB +; Carry set if bad path +; DS:SI Points to path element causing failure +; Zero set +; [DIRSTART],[DIRSEC],[CLUSNUM], and [CLUSFAC] are set up to +; start a search on the last directory +; CL is zero if there is a bad name in the path +; CL is non-zero if the name was simply not found +; [ENTFREE] may have free spot in directory +; [NAME1] is the name. +; CL = 81H if '*'s or '?' in name 1, 80H otherwise +; Zero reset +; File in middle of path or bad name in path +; or path too long or malformed path +; ELSE +; DS = DOSGROUP +; AH = device ID +; [CURBUF] contains directory record with match +; [CURBUF+2]:BX Points into [CURBUF] to start of entry +; [CURBUF+2]:SI Points to fcb_FIRCLUS field for entry +; [NAME1] Has entry name +; If last element is a directory zero is set and: +; [DIRSTART],[SECCLUSPOS],[DIRSEC],[CLUSNUM], and [CLUSFAC] +; are set up to start a search on it. +; If last element is a file zero is reset +; Destroys all registers + + PUSH ES + PUSH SI + invoke NAMETRANS + MOV CL,AL + OR CL,80H + POP DI + POP ES + CMP SI,DI + JNZ check_device + JMP BADPATH +check_device: + PUSH DS + PUSH SI + MOV AL,BYTE PTR [SI] + +; +; can we see all devices +; + context DS + CMP BYTE PTR [device_availability],0 + JZ FindFile + +; +; check name1 to see if we have a device... +; + PUSH ES + context ES + invoke DevName ; blast BX + POP ES + ASSUME ES:NOTHING + JC FindFile + OR AL,AL + JNZ FileInPath + POP SI + POP SI + context ES + invoke BuildFCB + INC AL + return + +FindFile: + ASSUME ES:NOTHING + PUSH DI ; Start of this element + PUSH ES + PUSH CX + CALL FINDENTRY + POP CX + POP ES + POP DI + JC BADPATHPOP + LDS DI,[CURBUF] +ASSUME DS:NOTHING + TEST BYTE PTR [BX+dir_attr],attr_directory + JZ FileInPath + +; +; if we are not setting the directory, then +; check for end of string +; + CMP BYTE PTR [NoSetDir],0 + JZ SetDir + MOV DX,DI + MOV AX,DS + POP DI + POP DS + CMP BYTE PTR [DI],0 + JZ SetRet + PUSH DS + PUSH DI + MOV DI,DX + MOV DS,AX + +SetDir: + MOV DX,[SI] + SUB BX,DI + SUB SI,DI + PUSH BX + PUSH AX + PUSH SI + PUSH CX + PUSH [DI.BUFSECNO] + MOV BX,DX + CALL SETDIRSRCH +ASSUME DS:DOSGROUP + POP DX + XOR AL,AL + invoke GETBUFFR + POP CX + POP SI + POP AX + POP BX + MOV DI,WORD PTR [CURBUF] + ADD SI,DI + ADD BX,DI + POP DI + POP DS +ASSUME DS:NOTHING + MOV AL,[DI] + OR AL,AL + JZ SETRET + INC DI + MOV SI,DI + invoke PATHCHRCMP + JNZ find_bad_name + JMP FINDPATH + +find_bad_name: + DEC SI +BADPATH: + XOR CL,CL ; Set zero + STC + return + +FILEINPATH: + POP DI + POP DS + MOV AL,[DI] + OR AL,AL + JZ INCRET + MOV SI,DI ; Path too long + STC + return + +INCRET: + INC AL ; Reset zero +SETRET: + PUSH SS + POP DS + return + +BADPATHPOP: + POP SI + POP DS + MOV AL,[SI] + MOV SI,DI ; Start of bad element + OR AL,AL ; zero if bad element is last, non-zero if path too long + STC + return +ROOTPATH ENDP + +SUBTTL STARTSRCH -- INITIATE DIRECTORY SEARCH +PAGE + procedure StartSrch,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; [THISDPB] Set +; Function: +; Set up a search for GETENTRY and NEXTENTRY +; Outputs: +; ES:BP = Drive parameters +; Sets up LASTENT, ENDENT, ENTFREE=ENTLAST=-1, VOLID=0 +; Destroys all registers (via FATREAD) + + LES BP,[THISDPB] + XOR AX,AX + MOV [LASTENT],AX + MOV BYTE PTR [VOLID],AL ; No volume ID found + DEC AX + MOV [ENTFREE],AX + MOV [ENTLAST],AX + return +StartSrch ENDP + +BREAK + +; +; Input: [Attrib] = attribute to search for +; CH = found attribute +; Output: JZ +; JNZ +; + procedure MatchAttributes,near + ASSUME DS:NOTHING,ES:NOTHING + PUSH AX + MOV AL,[Attrib] ; AL <- SearchSet + NOT AL ; AL <- SearchSet' + AND AL,CH ; AL <- SearchSet' and FoundSet + AND AL,attr_all ; AL <- SearchSet' and FoundSet and Important +; +; the result is non-zero if an attribute is not in the search set +; and in the found set and in the important set. This means that we do not +; have a match. Do a JNZ or JZ +; + POP AX + return +MatchAttributes ENDP + +do_ext + +CODE ENDS + END + \ No newline at end of file diff --git a/DIRCALL.ASM b/DIRCALL.ASM new file mode 100644 index 0000000..db55ab8 --- /dev/null +++ b/DIRCALL.ASM @@ -0,0 +1,507 @@ +TITLE DIRCALL - Directory manipulation internal calls +NAME DIRCALL + +; $MKDIR +; $CHDIR +; $RMDIR + +.xlist +INCLUDE DOSSEG.ASM + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + +ifndef Kanji +Kanji equ 0 +endif + + i_need AUXSTACK,BYTE + i_need NoSetDir,BYTE + i_need CURBUF, DWORD + i_need DIRSTART,WORD + i_need THISDPB,DWORD + i_need NAME1,BYTE + i_need LASTENT,WORD + i_need ATTRIB,BYTE + i_need THISFCB,DWORD + i_need AUXSTACK,BYTE + i_need CREATING,BYTE + i_need DRIVESPEC,BYTE + i_need ROOTSTART,BYTE + i_need SWITCH_CHARACTER,BYTE + + extrn sys_ret_ok:near,sys_ret_err:near + + +; XENIX CALLS +BREAK <$MkDir - Make a directory entry> +MKNERRJ: JMP MKNERR +NODEEXISTSJ: JMP NODEEXISTS + procedure $MKDIR,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX Points to asciz name +; Function: +; Make a new directory +; Returns: +; STD XENIX Return +; AX = mkdir_path_not_found if path bad +; AX = mkdir_access_denied If +; Directory cannot be created +; Node already exists +; Device name given +; Disk or directory(root) full + invoke validate_path + JC MKNERRJ + MOV SI,DX + MOV WORD PTR [THISFCB+2],SS + MOV WORD PTR [THISFCB],OFFSET DOSGROUP:AUXSTACK-40 ; Scratch space + MOV AL,attr_directory + MOV WORD PTR [CREATING],0E500h + invoke MAKENODE +ASSUME DS:DOSGROUP + MOV AL,mkdir_path_not_found + JC MKNERRJ + JNZ NODEEXISTSJ + LDS DI,[CURBUF] +ASSUME DS:NOTHING + SUB SI,DI + PUSH SI ; Pointer to fcb_FIRCLUS + PUSH [DI.BUFSECNO] ; Sector of new node + PUSH SS + POP DS +ASSUME DS:DOSGROUP + PUSH [DIRSTART] ; Parent for .. entry + XOR AX,AX + MOV [DIRSTART],AX ; Null directory + invoke NEWDIR + JC NODEEXISTSPOPDEL ; No room + invoke GETENT ; First entry + LES DI,[CURBUF] + MOV ES:[DI.BUFDIRTY],1 + ADD DI,BUFINSIZ ; Point at buffer + MOV AX,202EH ; ". " + STOSW + MOV DX,[DIRSTART] ; Point at itself + invoke SETDOTENT + MOV AX,2E2EH ; ".." + STOSW + POP DX ; Parent + invoke SETDOTENT + LES BP,[THISDPB] + POP DX ; Entry sector + XOR AL,AL ; Pre read + invoke GETBUFFR + MOV DX,[DIRSTART] + LDS DI,[CURBUF] +ASSUME DS:NOTHING +ZAPENT: + POP SI ; fcb_Firclus pointer + ADD SI,DI + MOV [SI],DX + XOR DX,DX + MOV [SI+2],DX + MOV [SI+4],DX +DIRUP: + MOV [DI.BUFDIRTY],1 + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV AL,ES:[BP.dpb_drive] + invoke FLUSHBUF +SYS_RET_OKJ: + JMP SYS_RET_OK + +NODEEXISTSPOPDEL: + POP DX ; Parent + POP DX ; Entry sector + LES BP,[THISDPB] + XOR AL,AL ; Pre read + invoke GETBUFFR + LDS DI,[CURBUF] +ASSUME DS:NOTHING + POP SI ; dir_first pointer + ADD SI,DI + SUB SI,dir_first ; Point back to start of dir entry + MOV BYTE PTR [SI],0E5H ; Free the entry + CALL DIRUP +NODEEXISTS: + MOV AL,mkdir_access_denied +MKNERR: + JMP SYS_RET_ERR +$MKDIR ENDP + +BREAK <$ChDir -- Change current directory on a drive> + procedure $CHDIR,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX Points to asciz name +; Function: +; Change current directory +; Returns: +; STD XENIX Return +; AX = chdir_path_not_found if error + + invoke validate_path + JC PathTooLong + + PUSH DS + PUSH DX + MOV SI,DX + invoke GETPATH + JC PATHNOGOOD + JNZ PATHNOGOOD +ASSUME DS:DOSGROUP + MOV AX,[DIRSTART] + MOV BX,AX + XCHG BX,ES:[BP.dpb_current_dir] + OR AX,AX + POP SI + POP DS +ASSUME DS:NOTHING + JZ SYS_RET_OKJ + MOV DI,BP + ADD DI,dpb_dir_text + MOV DX,DI + CMP [DRIVESPEC],0 + JZ NODRIVESPEC + INC SI + INC SI +NODRIVESPEC: + MOV CX,SI + CMP [ROOTSTART],0 + JZ NOTROOTPATH + INC SI + INC CX + JMP SHORT COPYTHESTRINGBXZ +NOTROOTPATH: + OR BX,BX ; Previous path root? + JZ COPYTHESTRING ; Yes + XOR BX,BX +ENDLOOP: + CMP BYTE PTR ES:[DI],0 + JZ PATHEND + INC DI + INC BX + JMP SHORT ENDLOOP +PATHEND: + MOV AL,'/' + CMP AL,[switch_character] + JNZ SLASHOK + MOV AL,'\' ; Use the alternate character +SLASHOK: + STOSB + INC BX + JMP SHORT CHECK_LEN + +PATHNOGOOD: + POP AX + POP AX +PATHTOOLONG: + error error_path_not_found + +ASSUME DS:NOTHING + +INCBXCHK: + INC BX +BXCHK: + CMP BX,DIRSTRLEN + return + +COPYTHESTRINGBXZ: + XOR BX,BX +COPYTHESTRING: + LODSB + OR AL,AL + + JNZ FOOB + JMP CPSTDONE +FOOB: + CMP AL,'.' + JZ SEEDOT + CALL COPYELEM +CHECK_LEN: + CMP BX,DIRSTRLEN + JB COPYTHESTRING + MOV AL,ES:[DI-1] + invoke PATHCHRCMP + JNZ OK_DI + DEC DI +OK_DI: + XOR AL,AL + STOSB ; Correctly terminate the path + MOV ES:[BP.dpb_current_dir],-1 ; Force re-validation + JMP SHORT PATHTOOLONG + +SEEDOT: + LODSB + OR AL,AL ; Check for null + JZ CPSTDONEDEC + CMP AL,'.' + JNZ COPYTHESTRING ; eat ./ + CALL DELELMES ; have .. + LODSB ; eat the / + OR AL,AL ; Check for null + JZ CPSTDONEDEC + JMP SHORT COPYTHESTRING + +; Copy one element from DS:SI to ES:DI include trailing / not trailing null +; LODSB has already been done +COPYELEM: + PUSH DI ; Save in case too long + PUSH CX + MOV CX,800h ; length of filename + MOV AH,'.' ; char to stop on + CALL CopyPiece ; go for it! + CALL BXCHK ; did we go over? + JAE POPCXDI ; yep, go home + CMP AH,AL ; did we stop on .? + JZ CopyExt ; yes, go copy ext + OR AL,AL ; did we end on nul? + JZ DECSIRet ; yes, bye +CopyPathEnd: + STOSB ; save the path char + CALL INCBXCHK ; was there room for it? + JAE POPCXDI ; Nope + INC SI ; guard against following dec +DECSIRET: + DEC SI ; point back at null + POP CX + POP AX ; toss away saved DI + return +POPCXDI: + POP CX ; restore + POP DI ; point back... + return +CopyExt: + STOSB ; save the dot + CALL INCBXCHK ; room? + JAE POPCXDI ; nope. + LODSB ; get next char + XOR AH,AH ; NUL here + MOV CX,300h ; at most 3 chars + CALL CopyPiece ; go copy it + CALL BXCHK ; did we go over + JAE POPCXDI ; yep + OR AL,AL ; sucessful end? + JZ DECSIRET ; yes + JMP CopyPathEnd ; go stash path char + +DELELMES: +; Delete one path element from ES:DI + DEC DI ; the '/' + DEC BX + + IF KANJI + PUSH AX + PUSH CX + PUSH DI + PUSH DX + MOV CX,DI + MOV DI,DX +DELLOOP: + CMP DI,CX + JZ GOTDELE + MOV AL,ES:[DI] + INC DI + invoke TESTKANJ + JZ NOTKANJ11 + INC DI + JMP DELLOOP + +NOTKANJ11: + invoke PATHCHRCMP + JNZ DELLOOP + MOV DX,DI ; Point to char after '/' + JMP DELLOOP + +GOTDELE: + MOV DI,DX + POP DX + POP AX ; Initial DI + SUB AX,DI ; Distance moved + SUB BX,AX ; Set correct BX + POP CX + POP AX + return + ELSE +DELLOOP: + CMP DI,DX + retz + PUSH AX + MOV AL,ES:[DI-1] + invoke PATHCHRCMP + POP AX + retz + DEC DI + DEC BX + JMP SHORT DELLOOP + ENDIF + +CPSTDONEDEC: + DEC DI ; Back up over trailing / +CPSTDONE: + STOSB ; The NUL + JMP SYS_RET_OK + +; copy a piece CH chars max until the char in AH (or path or NUL) +CopyPiece: + STOSB ; store the character + INC CL ; moved a byte + CALL INCBXCHK ; room enough? + JAE CopyPieceRet ; no, pop CX and DI + OR AL,AL ; end of string? + JZ CopyPieceRet ; yes, dec si and return + + IF KANJI + CALL TestKanj ; was it kanji? + JZ NotKanj ; nope + MOVSB ; move the next byte + CALL INCBXCHK ; room for it? + JAE CopyPieceRet ; nope + INC CL ; moved a byte +NotKanj: + ENDIF + + CMP CL,CH ; move too many? + JBE CopyPieceNext ; nope + + IF KANJI + CALL TestKanj ; was the last byte kanji + JZ NotKanj2 ; no only single byte backup + DEC DI ; back up a char + DEC BX +NotKanj2: + ENDIF + + DEC DI ; back up a char + DEC BX +CopyPieceNext: + LODSB ; get next character + invoke PathChrCmp ; end of road? + JZ CopyPieceRet ; yep, return and don't dec SI + CMP AL,AH ; end of filename? + JNZ CopyPiece ; go do name +CopyPieceRet: + return ; bye! + +$CHDIR ENDP + +BREAK <$RmDir -- Remove a directory> +NOPATHJ: JMP NOPATH + + procedure $RMDIR,NEAR ; System call 47 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX Points to asciz name +; Function: +; Delete directory if empty +; Returns: +; STD XENIX Return +; AX = rmdir_path_not_found If path bad +; AX = rmdir_access_denied If +; Directory not empty +; Path not directory +; Root directory specified +; Directory malformed (. and .. not first two entries) +; AX = rmdir_current_directory + + invoke Validate_path + JC NoPathJ + MOV SI,DX + invoke GETPATH + JC NOPATHJ +ASSUME DS:DOSGROUP + JNZ NOTDIRPATH + MOV DI,[DIRSTART] + OR DI,DI + JZ NOTDIRPATH + MOV CX,ES:[BP.dpb_current_dir] + CMP CX,-1 + JNZ rmdir_current_dir_check + invoke GetCurrDir + invoke Get_user_stack + MOV DX,[SI.user_DX] + MOV DS,[SI.user_DS] + JMP $RMDIR + +NOTDIRPATHPOP: + POP AX + POP AX +NOTDIRPATH: + error error_access_denied + +rmdir_current_dir_check: + CMP DI,CX + JNZ rmdir_get_buf + error error_current_directory + +rmdir_get_buf: + LDS DI,[CURBUF] +ASSUME DS:NOTHING + SUB BX,DI + PUSH BX ; Save entry pointer + PUSH [DI.BUFSECNO] ; Save sector number + PUSH SS + POP DS +ASSUME DS:DOSGROUP + PUSH SS + POP ES + MOV DI,OFFSET DOSGROUP:NAME1 + MOV AL,'?' + MOV CX,11 + REP STOSB + XOR AL,AL + STOSB + invoke STARTSRCH + invoke GETENTRY + MOV DS,WORD PTR [CURBUF+2] +ASSUME DS:NOTHING + MOV SI,BX + LODSW + CMP AX,(' ' SHL 8) OR '.' + JNZ NOTDIRPATHPOP + ADD SI,32-2 + LODSW + CMP AX,('.' SHL 8) OR '.' + JNZ NOTDIRPATHPOP + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV [LASTENT],2 ; Skip . and .. + invoke GETENTRY + MOV [ATTRIB],attr_directory+attr_hidden+attr_system + invoke SRCH + JNC NOTDIRPATHPOP + LES BP,[THISDPB] + MOV BX,[DIRSTART] + invoke RELEASE + POP DX + XOR AL,AL + invoke GETBUFFR + LDS DI,[CURBUF] +ASSUME DS:NOTHING + POP BX + ADD BX,DI + MOV BYTE PTR [BX],0E5H ; Free the entry + JMP DIRUP + +NOPATH: + error error_path_not_found + +$RMDIR ENDP + + do_ext + +CODE ENDS + END + \ No newline at end of file diff --git a/DISK.ASM b/DISK.ASM new file mode 100644 index 0000000..b1acd82 --- /dev/null +++ b/DISK.ASM @@ -0,0 +1,1302 @@ +; +; Disk routines for MSDOS +; + +INCLUDE DOSSEG.ASM + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xlist +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + +TITLE DISK - Disk utility routines +NAME Disk + + i_need COUTDSAV,BYTE + i_need COUTSAV,DWORD + i_need CINDSAV,BYTE + i_need CINSAV,DWORD + i_need CONSWAP,BYTE + i_need IDLEINT,BYTE + i_need THISFCB,DWORD + i_need DMAADD,DWORD + i_need DEVCALL,BYTE + i_need CALLSCNT,WORD + i_need CALLXAD,DWORD + i_need CONTPOS,WORD + i_need NEXTADD,WORD + i_need CONBUF,BYTE + i_need User_SS,WORD + i_need User_SP,WORD + i_need DSKStack,BYTE + i_need InDOS,BYTE + i_need NumIO,BYTE + i_need CurDrv,BYTE + i_need ThisDrv,BYTE + i_need ClusFac,BYTE + i_need SecClusPos,BYTE + i_need DirSec,WORD + i_need ClusNum,WORD + i_need NxtClusNum,WORD + i_need ReadOp,BYTE + i_need DskErr,BYTE + i_need RecCnt,WORD + i_need RecPos,4 + i_need Trans,BYTE + i_need BytPos,4 + i_need SecPos,WORD + i_need BytSecPos,WORD + i_need BytCnt1,WORD + i_need BytCnt2,WORD + i_need SecCnt,WORD + i_need ThisDPB,DWORD + i_need LastPos,WORD + i_need ValSec,WORD + i_need GrowCnt,DWORD + +SUBTTL LOAD -- MAIN READ ROUTINE AND DEVICE IN ROUTINES +PAGE +; * * * * Drivers for file input from devices * * * * + + procedure SWAPBACK,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + PUSH ES + PUSH DI + PUSH SI + PUSH BX + MOV BX,1 + invoke get_sf_from_jfn + ADD DI,sf_fcb + MOV BL,BYTE PTR [COUTDSAV] + LDS SI,[COUTSAV] +ASSUME DS:NOTHING + MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI + MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS + MOV ES:[DI.fcb_DEVID],BL + PUSH SS + POP DS +ASSUME DS:DOSGROUP + XOR BX,BX + invoke get_sf_from_jfn + ADD DI,sf_fcb + MOV BL,BYTE PTR [CINDSAV] + LDS SI,[CINSAV] +ASSUME DS:NOTHING + MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI + MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS + MOV ES:[DI.fcb_DEVID],BL + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV BYTE PTR [CONSWAP],0 + MOV BYTE PTR [IDLEINT],1 +SWAPRET: + POP BX + POP SI + POP DI + POP ES + return +SWAPBACK ENDP + + procedure SWAPCON,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + PUSH ES + PUSH DI + PUSH SI + PUSH BX + MOV BYTE PTR [CONSWAP],1 + MOV BYTE PTR [IDLEINT],0 + XOR BX,BX + invoke get_sf_from_jfn + ADD DI,sf_fcb + MOV BL,ES:[DI.fcb_DEVID] + MOV BYTE PTR [CINDSAV],BL + LDS SI,DWORD PTR ES:[DI.fcb_FIRCLUS] +ASSUME DS:NOTHING + MOV WORD PTR [CINSAV],SI + MOV WORD PTR [CINSAV+2],DS + LDS SI,[THISFCB] + MOV BL,[SI.fcb_DEVID] + LDS SI,DWORD PTR [SI.fcb_FIRCLUS] + MOV ES:[DI.fcb_DEVID],BL + MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI + MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV BX,1 + invoke get_sf_from_jfn + ADD DI,sf_fcb + MOV BL,ES:[DI.fcb_DEVID] + MOV BYTE PTR [COUTDSAV],BL + LDS SI,DWORD PTR ES:[DI.fcb_FIRCLUS] +ASSUME DS:NOTHING + MOV WORD PTR [COUTSAV],SI + MOV WORD PTR [COUTSAV+2],DS + LDS SI,[THISFCB] + MOV BL,[SI.fcb_DEVID] + LDS SI,DWORD PTR [SI.fcb_FIRCLUS] + MOV ES:[DI.fcb_DEVID],BL + MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI + MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS + PUSH SS + POP DS + JMP SWAPRET +SWAPCON ENDP + + procedure LOAD,NEAR +ASSUME DS:NOTHING,ES:NOTHING +; +; Inputs: +; DS:DI point to FCB +; DX:AX = Position in file to read +; CX = No. of records to read +; Outputs: +; DX:AX = Position of last record read +; CX = No. of bytes read +; ES:DI point to FCB +; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set + + call SETUP +ASSUME DS:DOSGROUP + OR BL,BL ; Check for named device I/O + JS READDEV + call DISKREAD + return + +READDEV: +ASSUME DS:DOSGROUP,ES:NOTHING + LES DI,[DMAADD] + TEST BL,40H ; End of file? + JZ ENDRDDEVJ3 + TEST BL,ISNULL ; NUL device? + JZ TESTRAW ; NO + XOR AL,AL ; Indicate EOF +ENDRDDEVJ3: JMP ENDRDDEVJ2 + +DVRDRAW: +ASSUME DS:DOSGROUP + PUSH ES + POP DS +ASSUME DS:NOTHING +DVRDRAWR: + MOV BX,DI ; DS:BX transfer addr + XOR DX,DX ; Start at 0 + XOR AX,AX ; Media Byte, unit = 0 + invoke SETREAD + LDS SI,[THISFCB] + invoke DEVIOCALL + MOV DX,DI ; DX is preserved by INT 24 + MOV AH,86H ; Read error + MOV DI,[DEVCALL.REQSTAT] + TEST DI,STERR + JZ CRDROK ; No errors + invoke CHARHARD + MOV DI,DX + CMP AL,1 + JZ DVRDRAWR ; Retry +CRDROK: + MOV DI,DX + ADD DI,[CALLSCNT] ; Amount transferred + JMP SHORT ENDRDDEVJ2 + +TESTRAW: + TEST BL,020H ; Raw mode? + JNZ DVRDRAW + TEST BL,ISCIN ; Is it console device? + JZ NOTRDCON + JMP READCON +NOTRDCON: + MOV AX,ES + MOV DS,AX +ASSUME DS:NOTHING + MOV BX,DI + XOR DX,DX + MOV AX,DX + PUSH CX + MOV CX,1 + invoke SETREAD + POP CX + LDS SI,[THISFCB] + LDS SI,DWORD PTR [SI.fcb_FIRCLUS] +DVRDLP: + invoke DSKSTATCHK + invoke DEVIOCALL2 + PUSH DI + MOV AH,86H + MOV DI,[DEVCALL.REQSTAT] + TEST DI,STERR + JZ CRDOK + invoke CHARHARD + POP DI + MOV [CALLSCNT],1 + CMP AL,1 + JZ DVRDLP ;Retry + XOR AL,AL ;Pick some random character + JMP SHORT DVRDIGN +CRDOK: + POP DI + CMP [CALLSCNT],1 + JNZ ENDRDDEVJ2 + PUSH DS + MOV DS,WORD PTR [CALLXAD+2] + MOV AL,BYTE PTR [DI] + POP DS +DVRDIGN: + INC WORD PTR [CALLXAD] + MOV [DEVCALL.REQSTAT],0 + INC DI + CMP AL,1AH ; ^Z? + JZ ENDRDDEVJ + CMP AL,c_CR ; CR? + LOOPNZ DVRDLP +ENDRDDEVJ: + DEC DI +ENDRDDEVJ2: + JMP SHORT ENDRDDEV + +ASSUME DS:NOTHING,ES:NOTHING + +TRANBUF: + LODSB + STOSB + CMP AL,c_CR ; Check for carriage return + JNZ NORMCH + MOV BYTE PTR [SI],c_LF +NORMCH: + CMP AL,c_LF + LOOPNZ TRANBUF + JNZ ENDRDCON + XOR SI,SI ; Cause a new buffer to be read + invoke OUT ; Transmit linefeed + OR AL,1 ; Clear zero flag--not end of file +ENDRDCON: + PUSH SS + POP DS +ASSUME DS:DOSGROUP + CALL SWAPBACK + MOV [CONTPOS],SI +ENDRDDEV: + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV [NEXTADD],DI + JNZ SETFCBC ; Zero set if Ctrl-Z found in input + LES DI,[THISFCB] + AND ES:BYTE PTR [DI.fcb_DEVID],0FFH-40H ; Mark as no more data available +SETFCBC: + call SETFCB + return + +ASSUME DS:NOTHING,ES:NOTHING + +READCON: +ASSUME DS:DOSGROUP + CALL SWAPCON + MOV SI,[CONTPOS] + OR SI,SI + JNZ TRANBUF + CMP BYTE PTR [CONBUF],128 + JZ GETBUF + MOV WORD PTR [CONBUF],0FF80H ; Set up 128-byte buffer with no template +GETBUF: + PUSH CX + PUSH ES + PUSH DI + MOV DX,OFFSET DOSGROUP:CONBUF + invoke $STD_CON_STRING_INPUT ; Get input buffer + POP DI + POP ES + POP CX + MOV SI,2 + OFFSET DOSGROUP:CONBUF + CMP BYTE PTR [SI],1AH ; Check for Ctrl-Z in first character + JNZ TRANBUF + MOV AL,1AH + STOSB + DEC DI + MOV AL,10 + invoke OUT ; Send linefeed + XOR SI,SI + JMP SHORT ENDRDCON + +LOAD ENDP + +SUBTTL STORE -- MAIN WRITE ROUTINE AND DEVICE OUT ROUTINES +PAGE +ASSUME DS:NOTHING,ES:NOTHING + procedure STORE,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DI point to FCB +; DX:AX = Position in file of disk transfer +; CX = Record count +; Outputs: +; DX:AX = Position of last record written +; CX = No. of records written +; ES:DI point to FCB +; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set + + call SETUP +ASSUME DS:DOSGROUP + OR BL,BL + JS WRTDEV + invoke DATE16 + MOV ES:[DI.fcb_FDATE],AX + MOV ES:[DI.fcb_FTIME],DX + call DISKWRITE + return + +WRITECON: + PUSH DS + PUSH SS + POP DS +ASSUME DS:DOSGROUP + CALL SWAPCON + POP DS +ASSUME DS:NOTHING + MOV SI,BX + PUSH CX +WRCONLP: + LODSB + CMP AL,1AH ; ^Z? + JZ CONEOF + invoke OUT + LOOP WRCONLP +CONEOF: + POP AX ; Count + SUB AX,CX ; Amount actually written + POP DS +ASSUME DS:DOSGROUP + CALL SWAPBACK + JMP SHORT ENDWRDEV + +DVWRTRAW: +ASSUME DS:NOTHING + XOR AX,AX ; Media Byte, unit = 0 + invoke SETWRITE + LDS SI,[THISFCB] + invoke DEVIOCALL + MOV DX,DI + MOV AH,87H + MOV DI,[DEVCALL.REQSTAT] + TEST DI,STERR + JZ CWRTROK + invoke CHARHARD + MOV BX,DX ; Recall transfer addr + CMP AL,1 + JZ DVWRTRAW ; Try again +CWRTROK: + POP DS +ASSUME DS:DOSGROUP + MOV AX,[CALLSCNT] ; Get actual number of bytes transferred +ENDWRDEV: + LES DI,[THISFCB] + XOR DX,DX + DIV ES:[DI.fcb_RECSIZ] + MOV CX,AX ; Partial record is ignored + call ADDREC + return + +ASSUME DS:DOSGROUP +WRTDEV: + OR BL,40H ; Reset EOF for input + XOR AX,AX + JCXZ ENDWRDEV ; problem of creating on a device. + PUSH DS + MOV AL,BL + LDS BX,[DMAADD] +ASSUME DS:NOTHING + MOV DI,BX + XOR DX,DX ; Set starting point + TEST AL,020H ; Raw? + JNZ DVWRTRAW + TEST AL,ISCOUT ; Console output device? + JNZ WRITECON + TEST AL,ISNULL + JNZ WRTNUL + MOV AX,DX + CMP BYTE PTR [BX],1AH ; ^Z? + JZ WRTCOOKDONE ; Yes, transfer nothing + PUSH CX + MOV CX,1 + invoke SETWRITE + POP CX + LDS SI,[THISFCB] + LDS SI,DWORD PTR [SI.fcb_FIRCLUS] +DVWRTLP: + invoke DSKSTATCHK + invoke DEVIOCALL2 + PUSH DI + MOV AH,87H + MOV DI,[DEVCALL.REQSTAT] + TEST DI,STERR + JZ CWROK + invoke CHARHARD + POP DI + MOV [CALLSCNT],1 + CMP AL,1 + JZ DVWRTLP + JMP SHORT DVWRTIGN +CWROK: + POP DI + CMP [CALLSCNT],0 + JZ WRTCOOKDONE +DVWRTIGN: + INC DX + INC WORD PTR [CALLXAD] + INC DI + PUSH DS + MOV DS,WORD PTR [CALLXAD+2] + CMP BYTE PTR [DI],1AH ; ^Z? + POP DS + JZ WRTCOOKDONE + MOV [DEVCALL.REQSTAT],0 + LOOP DVWRTLP +WRTCOOKDONE: + MOV AX,DX + POP DS + JMP ENDWRDEV + +WRTNUL: + MOV DX,CX ;Entire transfer done + JMP WRTCOOKDONE + +STORE ENDP + + procedure get_io_fcb,near +ASSUME DS:NOTHING,ES:NOTHING +; Convert JFN number in BX to FCB in DS:SI + PUSH SS + POP DS +ASSUME DS:DOSGROUP + PUSH ES + PUSH DI + invoke get_sf_from_jfn + JC RET44P + MOV SI,DI + ADD SI,sf_fcb + PUSH ES + POP DS +ASSUME DS:NOTHING +RET44P: + POP DI + POP ES + return +get_io_fcb ENDP + +SUBTTL GETTHISDRV -- FIND CURRENT DRIVE +PAGE +; Input: AL has drive identifier (1=A, 0=default) +; Output: AL has physical drive (0=A) +; Carry set if invalid drive (and AL is garbage anyway) + procedure GetThisDrv,NEAR +ASSUME DS:NOTHING,ES:NOTHING + CMP BYTE PTR [NUMIO],AL + retc + DEC AL + JNS PHYDRV + MOV AL,[CURDRV] +PHYDRV: + MOV BYTE PTR [THISDRV],AL + return +GetThisDrv ENDP + +SUBTTL DIRREAD -- READ A DIRECTORY SECTOR +PAGE + procedure DirRead,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; AX = Directory block number (relative to first block of directory) +; ES:BP = Base of drive parameters +; [DIRSEC] = First sector of first cluster of directory +; [CLUSNUM] = Next cluster +; [CLUSFAC] = Sectors/Cluster +; Function: +; Read the directory block into [CURBUF]. +; Outputs: +; [NXTCLUSNUM] = Next cluster (after the one skipped to) +; [SECCLUSPOS] Set +; ES:BP unchanged [CURBUF] Points to Buffer with dir sector +; All other registers destroyed. + + MOV CL,[CLUSFAC] + DIV CL ; AL # clusters to skip, AH position in cluster + MOV [SECCLUSPOS],AH + MOV CL,AL + XOR CH,CH + MOV DX,[DIRSEC] + ADD DL,AH + ADC DH,0 + MOV BX,[CLUSNUM] + MOV [NXTCLUSNUM],BX + JCXZ FIRSTCLUSTER +SKPCLLP: + invoke UNPACK + XCHG BX,DI + CMP BX,0FF8H + JAE HAVESKIPPED + LOOP SKPCLLP +HAVESKIPPED: + MOV [NXTCLUSNUM],BX + MOV DX,DI + MOV BL,AH + invoke FIGREC + entry FIRSTCLUSTER + XOR AL,AL ; Indicate pre-read + MOV AH,DIRPRI + invoke GETBUFFR + ret +DirRead ENDP + +SUBTTL FATSECRD -- READ A FAT SECTOR +PAGE + procedure FATSecRd,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; Same as DREAD +; DS:BX = Transfer address +; CX = Number of sectors +; DX = Absolute record number +; ES:BP = Base of drive parameters +; Function: +; Calls BIOS to perform FAT read. +; Outputs: +; Same as DREAD + + MOV DI,CX + MOV CL,ES:[BP.dpb_FAT_count] + MOV AL,ES:[BP.dpb_FAT_size] + XOR AH,AH + MOV CH,AH + PUSH DX +NXTFAT: + PUSH CX + PUSH AX + MOV CX,DI + CALL DSKREAD + POP AX + POP CX + JZ RET41P + ADD DX,AX + LOOP NXTFAT + POP DX + MOV CX,DI + +; NOTE FALL THROUGH + +SUBTTL DREAD -- DO A DISK READ +PAGE + entry DREAD +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:BX = Transfer address +; CX = Number of sectors +; DX = Absolute record number +; ES:BP = Base of drive parameters +; Function: +; Calls BIOS to perform disk read. If BIOS reports +; errors, will call HARDERR for further action. +; DS,ES:BP preserved. All other registers destroyed. + + CALL DSKREAD + retz + MOV BYTE PTR [READOP],0 + invoke HARDERR + CMP AL,1 ; Check for retry + JZ DREAD + return ; Ignore otherwise +RET41P: POP DX + return +FATSecRd ENDP + +SUBTTL DSKREAD -- PHYSICAL DISK READ +PAGE + procedure DskRead,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:BX = Transfer addr +; CX = Number of sectors +; DX = Absolute record number +; ES:BP = Base of drive parameters +; Function: +; Call BIOS to perform disk read +; Outputs: +; DI = CX on entry +; CX = Number of sectors unsuccessfully transfered +; AX = Status word as returned by BIOS (error code in AL if error) +; Zero set if OK (from BIOS) +; Zero clear if error +; SI Destroyed, others preserved + + PUSH CX + MOV AH,ES:[BP.dpb_media] + MOV AL,ES:[BP.dpb_UNIT] + PUSH BX + PUSH ES + invoke SETREAD + JMP DODSKOP + +SUBTTL DWRITE -- SEE ABOUT WRITING +PAGE + entry DWRITE +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:BX = Transfer address +; CX = Number of sectors +; DX = Absolute record number +; ES:BP = Base of drive parameters +; Function: +; Calls BIOS to perform disk write. If BIOS reports +; errors, will call HARDERR for further action. +; BP preserved. All other registers destroyed. + + CALL DSKWRITE + retz + MOV BYTE PTR [READOP],1 + invoke HARDERR + CMP AL,1 ; Check for retry + JZ DWRITE + return + +SUBTTL DSKWRITE -- PHYSICAL DISK WRITE +PAGE + entry DSKWRITE +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:BX = Transfer addr +; CX = Number of sectors +; DX = Absolute record number +; ES:BP = Base of drive parameters +; Function: +; Call BIOS to perform disk read +; Outputs: +; DI = CX on entry +; CX = Number of sectors unsuccessfully transfered +; AX = Status word as returned by BIOS (error code in AL if error) +; Zero set if OK (from BIOS) +; Zero clear if error +; SI Destroyed, others preserved + + PUSH CX + MOV AH,ES:[BP.dpb_media] + MOV AL,ES:[BP.dpb_UNIT] + PUSH BX + PUSH ES + invoke SETWRITE +DODSKOP: + MOV CX,DS ; Save DS + POP DS ; DS:BP points to DPB + PUSH DS + LDS SI,DS:[BP.dpb_driver_addr] + invoke DEVIOCALL2 + MOV DS,CX ; Restore DS + POP ES ; Restore ES + POP BX + MOV CX,[CALLSCNT] ; Number of sectors transferred + POP DI + SUB CX,DI + NEG CX ; Number of sectors not transferred + MOV AX,[DEVCALL.REQSTAT] + TEST AX,STERR + return +DskRead ENDP + +SUBTTL SETUP -- SETUP A DISK READ OR WRITE FROM USER +PAGE +ASSUME DS:DOSGROUP,ES:NOTHING + + procedure SETUP,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DI point to FCB +; DX:AX = Record position in file of disk transfer +; CX = Record count +; Outputs: +; DS = DOSGROUP +; BL = fcb_DEVID from FCB +; CX = No. of bytes to transfer (0 = 64K) +; [THISDPB] = Base of drive parameters +; [RECCNT] = Record count +; [RECPOS] = Record position in file +; ES:DI Points to FCB +; [THISFCB] = ES:DI +; [NEXTADD] = Displacement of disk transfer within segment +; [SECPOS] = Position of first sector +; [BYTPOS] = Byte position in file +; [BYTSECPOS] = Byte position in first sector +; [CLUSNUM] = First cluster +; [SECCLUSPOS] = Sector within first cluster +; [DSKERR] = 0 (no errors yet) +; [TRANS] = 0 (No transfers yet) +; [THISDRV] = Physical drive unit number + + PUSH AX + MOV AL,[DI] + DEC AL + MOV BYTE PTR [THISDRV],AL + MOV AL,[DI.fcb_DEVID] + MOV SI,[DI.fcb_RECSIZ] + OR SI,SI + JNZ HAVRECSIZ + MOV SI,128 + MOV [DI.fcb_RECSIZ],SI +HAVRECSIZ: + MOV WORD PTR [THISFCB+2],DS + PUSH SS + POP DS ; Set DS to DOSGROUP +ASSUME DS:DOSGROUP + MOV WORD PTR [THISFCB],DI + OR AL,AL ; Is it a device? + JNS NOTDEVICE + XOR AL,AL ; Fake in drive 0 so we can get BP +NOTDEVICE: + invoke GETBP + POP AX + JNC CheckRecLen + XOR CX,CX + MOV BYTE PTR [DSKERR],4 + POP BX + return + +CheckRecLen: + CMP SI,64 ; Check if highest byte of RECPOS is significant + JB SMALREC + XOR DH,DH ; Ignore MSB if record >= 64 bytes +SMALREC: + MOV [RECCNT],CX + MOV WORD PTR [RECPOS],AX + MOV WORD PTR [RECPOS+2],DX + MOV BX,WORD PTR [DMAADD] + MOV [NEXTADD],BX + MOV BYTE PTR [DSKERR],0 + MOV BYTE PTR [TRANS],0 + MOV BX,DX + MUL SI + MOV WORD PTR [BYTPOS],AX + PUSH DX + MOV AX,BX + MUL SI + POP BX + ADD AX,BX + ADC DX,0 ; Ripple carry + JNZ EOFERR + MOV WORD PTR [BYTPOS+2],AX + MOV DX,AX + MOV AX,WORD PTR [BYTPOS] + MOV BX,ES:[BP.dpb_sector_size] + CMP DX,BX ; See if divide will overflow + JNC EOFERR + DIV BX + MOV [SECPOS],AX + MOV [BYTSECPOS],DX + MOV DX,AX + AND AL,ES:[BP.dpb_cluster_mask] + MOV [SECCLUSPOS],AL + MOV AX,CX ; Record count + MOV CL,ES:[BP.dpb_cluster_shift] + SHR DX,CL + MOV [CLUSNUM],DX + MUL SI ; Multiply by bytes per record + MOV CX,AX + ADD AX,WORD PTR [DMAADD] ; See if it will fit in one segment + ADC DX,0 + JZ OK ; Must be less than 64K + MOV AX,WORD PTR [DMAADD] + NEG AX ; Amount of room left in segment + JNZ PARTSEG + DEC AX +PARTSEG: + XOR DX,DX + DIV SI ; How many records will fit? + MOV [RECCNT],AX + MUL SI ; Translate that back into bytes + MOV BYTE PTR [DSKERR],2 ; Flag that trimming took place + MOV CX,AX + JCXZ NOROOM +OK: + LES DI,[THISFCB] + MOV BL,ES:[DI.fcb_DEVID] + return + +EOFERR: + MOV BYTE PTR [DSKERR],1 + XOR CX,CX +NOROOM: + LES DI,[THISFCB] + POP BX ; Kill return address + return +SETUP ENDP + +SUBTTL BREAKDOWN -- CUT A USER READ OR WRITE INTO PIECES +PAGE + procedure BREAKDOWN,near +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; CX = Length of disk transfer in bytes +; ES:BP = Base of drive parameters +; [BYTSECPOS] = Byte position witin first sector +; Outputs: +; [BYTCNT1] = Bytes to transfer in first sector +; [SECCNT] = No. of whole sectors to transfer +; [BYTCNT2] = Bytes to transfer in last sector +; AX, BX, DX destroyed. No other registers affected. + + MOV AX,[BYTSECPOS] + MOV BX,CX + OR AX,AX + JZ SAVFIR ; Partial first sector? + SUB AX,ES:[BP.dpb_sector_size] + NEG AX ; Max number of bytes left in first sector + SUB BX,AX ; Subtract from total length + JAE SAVFIR + ADD AX,BX ; Don't use all of the rest of the sector + XOR BX,BX ; And no bytes are left +SAVFIR: + MOV [BYTCNT1],AX + MOV AX,BX + XOR DX,DX + DIV ES:[BP.dpb_sector_size] ; How many whole sectors? + MOV [SECCNT],AX + MOV [BYTCNT2],DX ; Bytes remaining for last sector + OR DX,[BYTCNT1] + retnz ; NOT (BYTCNT1 = BYTCNT2 = 0) + CMP AX,1 + retnz + MOV AX,ES:[BP.dpb_sector_size] ; Buffer EXACT one sector I/O + MOV [BYTCNT2],AX + MOV [SECCNT],DX ; DX = 0 + return +BreakDown ENDP + +SUBTTL DISKREAD -- PERFORM USER DISK READ +PAGE + procedure DISKREAD,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; Outputs of SETUP +; Function: +; Perform disk read +; Outputs: +; DX:AX = Position of last record read +; CX = No. of records read +; ES:DI point to FCB +; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set + + MOV AX,ES:WORD PTR [DI.fcb_FILSIZ] + MOV BX,ES:WORD PTR [DI.fcb_FILSIZ+2] + SUB AX,WORD PTR [BYTPOS] + SBB BX,WORD PTR [BYTPOS+2] + JB RDERR + JNZ ENUF + OR AX,AX + JZ RDERR + CMP AX,CX + JAE ENUF + MOV CX,AX +ENUF: + LES BP,[THISDPB] + CALL BREAKDOWN + MOV CX,[CLUSNUM] + invoke FNDCLUS + OR CX,CX + JZ SHORT SKIPERR +RDERR: + JMP WRTERR +RDLASTJ:JMP RDLAST +SETFCBJ2: JMP SETFCB + +SKIPERR: + + MOV [LASTPOS],DX + MOV [CLUSNUM],BX + CMP [BYTCNT1],0 + JZ RDMID + invoke BUFRD +RDMID: + CMP [SECCNT],0 + JZ RDLASTJ + invoke NEXTSEC + JC SETFCBJ2 + MOV BYTE PTR [TRANS],1 ; A transfer is taking place +ONSEC: + MOV DL,[SECCLUSPOS] + MOV CX,[SECCNT] + MOV BX,[CLUSNUM] +RDLP: + invoke OPTIMIZE + PUSH DI + PUSH AX + PUSH BX + MOV DS,WORD PTR [DMAADD+2] +ASSUME DS:NOTHING + PUSH DX + PUSH CX + CALL DREAD + POP BX + POP DX + ADD BX,DX ; Upper bound of read + MOV AL,ES:[BP.dpb_drive] + invoke SETVISIT +NXTBUF: ; Must see if one of these sectors is buffered + MOV [DI.VISIT],1 ; Mark as visited + CMP AL,[DI.BUFDRV] + JNZ DONXTBUF ; Not for this drive + CMP [DI.BUFSECNO],DX + JC DONXTBUF ; Below first sector + CMP [DI.BUFSECNO],BX + JNC DONXTBUF ; Above last sector + CMP BYTE PTR [DI.BUFDIRTY],0 + JZ CLBUFF ; Buffer is clean, so OK +; A sector has been read in when a dirty copy of it is in a buffer +; The buffered sector must now be read into the right place + POP AX ; Recall transfer address + PUSH AX + PUSH DI ; Save search environment + PUSH DX + SUB DX,[DI.BUFSECNO] ; How far into transfer? + NEG DX + MOV SI,DI + MOV DI,AX + MOV AX,DX + MOV CX,ES:[BP.dpb_sector_size] + MUL CX + ADD DI,AX ; Put the buffer here + ADD SI,BUFINSIZ + SHR CX,1 + PUSH ES + MOV ES,WORD PTR [DMAADD+2] + REP MOVSW + JNC EVENMOV + MOVSB +EVENMOV: + POP ES + POP DX + POP DI + MOV AL,ES:[BP.dpb_drive] +CLBUFF: + invoke SCANPLACE +DONXTBUF: + invoke SKIPVISIT + JNZ NXTBUF + PUSH SS + POP DS +ASSUME DS:DOSGROUP + POP CX + POP CX + POP BX + JCXZ RDLAST + CMP BX,0FF8H + JAE SETFCB + MOV DL,0 + INC [LASTPOS] ; We'll be using next cluster + JMP RDLP + +RDLAST: + MOV AX,[BYTCNT2] + OR AX,AX + JZ SETFCB + MOV [BYTCNT1],AX + invoke NEXTSEC + JC SETFCB + MOV [BYTSECPOS],0 + invoke BUFRD + + entry SETFCB + LES SI,[THISFCB] + MOV AX,[NEXTADD] + MOV DI,AX + SUB AX,WORD PTR [DMAADD] ; Number of bytes transfered + XOR DX,DX + MOV CX,ES:[SI.fcb_RECSIZ] + DIV CX ; Number of records + CMP AX,[RECCNT] ; Check if all records transferred + JZ FULLREC + MOV BYTE PTR [DSKERR],1 + OR DX,DX + JZ FULLREC ; If remainder 0, then full record transfered + MOV BYTE PTR [DSKERR],3 ; Flag partial last record + SUB CX,DX ; Bytes left in last record + PUSH ES + MOV ES,WORD PTR [DMAADD+2] + XCHG AX,BX ; Save the record count temporarily + XOR AX,AX ; Fill with zeros + SHR CX,1 + JNC EVENFIL + STOSB +EVENFIL: + REP STOSW + XCHG AX,BX ; Restore record count to AX + POP ES + INC AX ; Add last (partial) record to total +FULLREC: + MOV CX,AX + MOV DI,SI ; ES:DI point to FCB +SETCLUS: + TEST ES:[DI].fcb_DEVID,-1 + JS ADDREC ; don't set clisters if device + MOV AX,[CLUSNUM] + AND ES:[DI.fcb_LSTCLUS],0F000h ; fcb_lstclus is packed with dir clus + OR ES:[DI.fcb_LSTCLUS],AX ; drop in the correct part of fcb_lstclus + MOV AX,[LASTPOS] + MOV ES:[DI.fcb_CLUSPOS],AX + entry AddRec + MOV AX,WORD PTR [RECPOS] + MOV DX,WORD PTR [RECPOS+2] + JCXZ RET28 ; If no records read, don't change position + DEC CX + ADD AX,CX ; Update current record position + ADC DX,0 + INC CX +RET28: return +DISKREAD ENDP + +SUBTTL DISKWRITE -- PERFORM USER DISK WRITE +PAGE + procedure DISKWRITE,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; Outputs of SETUP +; Function: +; Perform disk write +; Outputs: +; DX:AX = Position of last record written +; CX = No. of records written +; ES:DI point to FCB +; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set + + AND BL,3FH ; Mark file as dirty + MOV ES:[DI.fcb_DEVID],BL + LES BP,[THISDPB] + CALL BREAKDOWN + MOV AX,WORD PTR [BYTPOS] + MOV DX,WORD PTR [BYTPOS+2] + JCXZ WRTEOFJ + ADD AX,CX + ADC DX,0 ; AX:DX=last byte accessed + DIV ES:[BP.dpb_sector_size] ; AX=last sector accessed + MOV BX,AX ; Save last full sector + OR DX,DX + JNZ CALCLUS + DEC AX ; AX must be zero base indexed +CALCLUS: + MOV CL,ES:[BP.dpb_cluster_shift] + SHR AX,CL ; Last cluster to be accessed + PUSH AX + PUSH DX ; Save the size of the "tail" + PUSH ES + LES DI,[THISFCB] + MOV AX,ES:WORD PTR [DI.fcb_FILSIZ] + MOV DX,ES:WORD PTR [DI.fcb_FILSIZ+2] + POP ES + DIV ES:[BP.dpb_sector_size] + MOV CX,AX ; Save last full sector of current file + OR DX,DX + JZ NORNDUP + INC AX ; Round up if any remainder +NORNDUP: + MOV [VALSEC],AX ; Number of sectors that have been written + XOR AX,AX + MOV WORD PTR [GROWCNT],AX + MOV WORD PTR [GROWCNT+2],AX + POP AX + SUB BX,CX ; Number of full sectors + JB NOGROW + JZ TESTTAIL + MOV CX,DX + XCHG AX,BX + MUL ES:[BP.dpb_sector_size] ; Bytes of full sector growth + SUB AX,CX ; Take off current "tail" + SBB DX,0 ; 32-bit extension + ADD AX,BX ; Add on new "tail" + ADC DX,0 ; ripple tim's head off + JMP SHORT SETGRW + +HAVSTART: + MOV CX,AX + invoke SKPCLP + JCXZ DOWRTJ + invoke ALLOCATE + JNC DOWRTJ +WRTERR: + XOR CX,CX + MOV BYTE PTR [DSKERR],1 + MOV AX,WORD PTR [RECPOS] + MOV DX,WORD PTR [RECPOS+2] + LES DI,[THISFCB] + return + +DOWRTJ: JMP DOWRT + +WRTEOFJ: + JMP WRTEOF + +TESTTAIL: + SUB AX,DX + JBE NOGROW + XOR DX,DX +SETGRW: + MOV WORD PTR [GROWCNT],AX + MOV WORD PTR [GROWCNT+2],DX +NOGROW: + POP AX + MOV CX,[CLUSNUM] ; First cluster accessed + invoke FNDCLUS + MOV [CLUSNUM],BX + MOV [LASTPOS],DX + SUB AX,DX ; Last cluster minus current cluster + JZ DOWRT ; If we have last clus, we must have first + JCXZ HAVSTART ; See if no more data + PUSH CX ; No. of clusters short of first + MOV CX,AX + invoke ALLOCATE + POP AX + JC WRTERR + MOV CX,AX + MOV DX,[LASTPOS] + INC DX + DEC CX + JZ NOSKIP + invoke SKPCLP +NOSKIP: + MOV [CLUSNUM],BX + MOV [LASTPOS],DX +DOWRT: + CMP [BYTCNT1],0 + JZ WRTMID + MOV BX,[CLUSNUM] + invoke BUFWRT +WRTMID: + MOV AX,[SECCNT] + OR AX,AX + JZ WRTLAST + ADD [SECPOS],AX + invoke NEXTSEC + MOV BYTE PTR [TRANS],1 ; A transfer is taking place + MOV DL,[SECCLUSPOS] + MOV BX,[CLUSNUM] + MOV CX,[SECCNT] +WRTLP: + invoke OPTIMIZE + PUSH DI + PUSH AX + PUSH DX + PUSH BX + MOV AL,ES:[BP.dpb_drive] + MOV BX,CX + ADD BX,DX ; Upper bound of write + invoke SETVISIT +ASSUME DS:NOTHING +NEXTBUFF: ; Search for buffers + MOV [DI.VISIT],1 ; Mark as visited + CMP AL,[DI.BUFDRV] + JNZ DONEXTBUFF ; Not for this drive + CMP [DI.BUFSECNO],DX + JC DONEXTBUFF ; Buffer is not in range of write + CMP [DI.BUFSECNO],BX + JNC DONEXTBUFF ; Buffer is not in range of write + MOV WORD PTR [DI.BUFDRV],00FFH ; Free the buffer, it is being over written + invoke SCANPLACE +DONEXTBUFF: + invoke SKIPVISIT + JNZ NEXTBUFF + POP BX + POP DX + MOV DS,WORD PTR [DMAADD+2] + CALL DWRITE + POP CX + POP BX + PUSH SS + POP DS +ASSUME DS:DOSGROUP + JCXZ WRTLAST + MOV DL,0 + INC [LASTPOS] ; We'll be using next cluster + JMP SHORT WRTLP + +WRTERRJ: JMP WRTERR + +WRTLAST: + MOV AX,[BYTCNT2] + OR AX,AX + JZ FINWRT + MOV [BYTCNT1],AX + invoke NEXTSEC + MOV [BYTSECPOS],0 + invoke BUFWRT +FINWRT: + LES DI,[THISFCB] + MOV AX,WORD PTR [GROWCNT] + MOV CX,WORD PTR [GROWCNT+2] + OR AX,AX + JNZ UPDATE_size + OR CX,CX + JZ SAMSIZ +Update_size: + ADD WORD PTR ES:[DI.fcb_FILSIZ],AX + ADC WORD PTR ES:[DI.fcb_FILSIZ+2],CX +SAMSIZ: + MOV CX,[RECCNT] + JMP SETCLUS + +WRTEOF: + MOV CX,AX + OR CX,DX + JZ KILLFIL + SUB AX,1 + SBB DX,0 + DIV ES:[BP.dpb_sector_size] + MOV CL,ES:[BP.dpb_cluster_shift] + SHR AX,CL + MOV CX,AX + invoke FNDCLUS + JCXZ RELFILE + invoke ALLOCATE + JC WRTERRJ +UPDATE: + LES DI,[THISFCB] + MOV AX,WORD PTR [BYTPOS] + MOV ES:WORD PTR [DI.fcb_FILSIZ],AX + MOV AX,WORD PTR [BYTPOS+2] + MOV ES:WORD PTR [DI.fcb_FILSIZ+2],AX + XOR CX,CX + JMP ADDREC + +RELFILE: + MOV DX,0FFFH + invoke RELBLKS + JMP SHORT UPDATE + +KILLFIL: + XOR BX,BX + PUSH ES + LES DI,[THISFCB] + MOV ES:[DI.fcb_CLUSPOS],BX + XCHG BX,ES:[DI.fcb_FIRCLUS] + AND ES:[DI.fcb_LSTCLUS],0F000H + POP ES + OR BX,BX + JZ UPDATE + invoke RELEASE + JMP SHORT UPDATE +DISKWRITE ENDP +do_ext + +CODE ENDS + END + \ No newline at end of file diff --git a/DISKCOPY.ASM b/DISKCOPY.ASM new file mode 100644 index 0000000000000000000000000000000000000000..56e39cbcece208d4726f17f121c082ed7cdf4b5b GIT binary patch literal 6656 zcmY#@f)LLTA6Eqh1sBg?Z)g92NCn?u7yn=dm(1d91?T*N%+w-YE^A$~0WX&|FPAmc zE|8(g`302l|`B986^sa zmKH_|NtFt|naM@@#rbI^3eNdO1^GpZC7Jno2#dmtGD}KQ^FS({Gm0{c6#`OAQj3ap z6dX&_ON$}KKx`n}W4gK!0~CT%%M=Xt3=ANC^vugF$xO^q$jmD)Nz6-51-S{L!pH!` zhNyy(L8*x;3YmEdb_!-D-U=C|dD+FhT)bRvjy}PlIB^XO1*Up`6Qu2#IN>d9ND^+6X);)ov%d@2rNOT5zOH^D z3IU-`KAz6JTrhE0KbK&Tc4vRT;1C4`1ypqkPLUz5AjJ?#m|_>l5J!+@SQW!0;fmcs zN);5`gZx7S6ciLdHtT?`(*Y@kSPpVzacX*QYF-K4i4biH3W>$VrMamJ3dzM*F77%h zU@{d<7K2ET0WhVm5g|c-3JMA-#o0wER(`IIK{_eL+2utg5OzUPer`cYWgeKv%LUT~ z2@?f{fFMu55S;+$ARjj!$6#+qKmQO9*C3tZ)MPW0Y!FqPS%qv{eo;Eu2txxgd>tl)6!ClP*f$ArlA|p%T+;0R5{0zFyd5?-JmIkb}7v62xGw3W#V-%+ZNXs?bg;NQzI+DJ?EZ zEsD=gEY6Na=ub{6M{r=4gWQR3RB{E}sNBQ~m~luZrKCb!o?L-2Ft-#OX$r_y zvl9^prezitm&8ND5y?cDzmcqlsEG#!C>DiD2=9XP0+Nz~d}yvl3Ttqr@^XQqqo@p# z5Fvqvq!;G1M5H)LhL#eEIXb#Xi6<+s3hcS`)Dk37m`6aV)G`ARJg~?ECpC~3D+L8e z_5dff;?xp_s??%*l1&KweRB{pmt=x$;^ne-&QD1NHI2Z|Rmez9OaV8; zpb7&*gFQe@#|T7=!q-0xB&6UHfn4%IihYDCXGb3&kTS5j2;l&KP&KKb05TBMov4Lr zN>N#AQ4vz=faf}-^OE9d0OQvCyg*hZK zLkH9-j}LMUcEwREf#MP!Tc?6r9175?v#>O^G!>MpV9H>oCm~mn1x5MkpjuU1!O#@p z?c$6gu&$&EkO}Mb%(7I4q{QTGh180Y zqC|z<)ZBbXBL}7oW`0tIj)9w-n;W`8)``X0;7ZjgGd&&D%mFpL5#EMrPt4Fs%*n}5 zM#vz!4I!8Xt@6_IOL9|l5#mG|1JQ<5roi+?Lt-#i2e}wSmMqS!iq%P~07WjS4Vajo zhs_jl3oTX$+C6~Y5fZTMnxB`NQdEXi62KgXT3{3x zCF5%fK~1s3t{Id;@acy62j*Bvs|*w*Fd4YHIXcncY>My*lBSdbq_PF3B^un|#SsC; z;AU>D4szQ7t`Smw>m=nMy98z(W`II#-IDTrDg-FZ<1p(GK>{@&5!5+4uws(C?aR>(~(0remu>J$`UZIRTX zqB1PzV~HDB!UQ$1^0RrlKsrH95?GfAQ5*4cLDXQ$Fi90U(a^X>*a|DKK_wwl0SSxm zi} z4N99}DR6@WvrV6w2Od~RssxXyfK@6eC=hlDsO$k1FGM;9+P{Oj28Uw`Qi~KoD)HnA zm3v0X6$U-c8OcL28@A8m=H&ND@ZamX(wWHUumVO2A+qQhx|p z6I2l*GlSACs5g#e8O$ju#X6uEO-n68l7y8H;E@Z2BVdhZ)PO(^9+<0OVxSTbp&w=} zfl|&0p#$zpV;Tk-qJt=eG-IH~K{&<` z8PM1vn1yKoJdU992o2V1Ks|(3FR3h-*-=f;uQ9@sDnUf(Vq1VBInw oM<-WMza1tH8pQ@hQfeNklm@XtI5iJ4G6fo`0L3^j7Xuyu06}|2HUIzs literal 0 HcmV?d00001 diff --git a/DISKMES.ASM b/DISKMES.ASM new file mode 100644 index 0000000000000000000000000000000000000000..d5f0226903efc73f3ca7aaa8e2b88cc27ea9b6cf GIT binary patch literal 7808 zcmY#@f)LLTA6Eqh1sBg?Z)g92NCn^2;^M^g)M8#PUM@FBpJ0%rYhWl?xdAU%NKhz9 zL;)t`=O3Z~Rt8ef%cWP5lUZB>qLYhK(|EbS+7uKNJpG(~LS0-HT>OKBBYpK8gME3q z^dL&~AUb%tta-VTQu2#IT2c#3L6m}#VFoW(Qht63hzA!m$l&ElEJ{sGQBY8T3z~ui z%ZoBgQjrABGCUIOD?-xM&m|aSwzI!qaEO9}0uIFxNtj|6#}G%5tymSqB;ktPK}r=A+=Ki>0~8b# zK+e(uTc-n33b7pIQmm#y^eQMM78jT1rYa~T7hAcw>!g6mR4`c#B0;9Wl)6TQ1omv8{NytOLN}3b~NPr;wSa;1YolE-g+i zQb@}$QixQ@FH-PRNX#oPPc70@h)ONWS13*`QOHbFh(y@z?C9eI@)X!3yj%f}?v9>* zRtR}t|1glWf=h&sznfdIYlwo2yH%uXaJ-*CLJ^uFU=0ci3NXEn5jq;dAujRG{(kYE zegUB&@oqk$!5#|19zF^dn%XE*2tz&nKxsum!N|}9As7JCr=XzV7=aLj+YX8Vgm8dA zC?%jO^$&u$&Cy54$iM@_29egz`FUljMI{O)`3gDt<*7vq$%)0O2(z4hp=SB$s8^~Z z#J!?Gx)l`M{X-o6f)V1#>hrLx_e0U(1+@SY{=8i7{vjX*ND+bLbVqQEL2OpA4oU^Z zYE^1cK3JQhUoeucAlDF3^2ta|&QD2IP)JFF=rZ8tDoM^S%_~t*NGXR1*@M)9(;t%d z-25`IY*J-OszO0Y5h!a!rxcatq?W|$C^;%2e4Ln)0#=z^Yz0@4n1hgqnFNxDSRJdA zT!D};C@sza8IV$pDTY;D1us`#MM+T#l51gRBw{f)35!??k{H~56*?d%LUL>@!Y#?U z1t8}sBtzt(UO>oaC8dJp)ALJ;lJiOs5@-g)H9{3)aXzwlGeJ?Lpr8OQ!m$`yY!wZO z+gKgs(9Xb9%u^^WP$(`*OwL9qEXap>6;lj3$YAPFf)=V5 zISR6%jwwpXN3sPLF2$Kh1&acxrpnAqM_8Pkn3Dr?Z%T1?YEcnFJgW*Ms-OT)0}2YD zY*3JzSfWspky)%@X5tMtiI)pxCsGg>mqIcCD2kymfszVgu?WfssYsCsOWi3ID9T|8 z4kc8e2^l#AV17-6Bpyf=fRwm$OTm6rNUnf*3Pf5bRw#h89VDOTrzw;aCFT{Ur4}h@ zWas6VBe*uUAP;LI!X_VDho|J|q#$L%tUO4VrB);+mzbF#)Wf`i&B@6*I!G#uGayET zJc490%zw!hI>`AK7HY{AI@pX(DMk%UXwpGW{)u_eQl&!2zzwMyfSH_x8XvHfR*+wi zp3ln#^(a#O6LzSffq?;%MKBFew}K5uG7pvoki7>JLrxS~(9#2(T44okY6%vTkafXK zLJkp_7;-o#=OiN{vj~)Kp;nX^AzK0S3piB`#=;!cx!6)AObn&Sfo3@5kb`*@T3S<5 znwKXNS(<|sB1b6HS;&zGFU`SiZ$zBIoja6@^YWq+!sR*0qokJS>wq2IU+^DG756R1W#o{wn#6Bm+9q5NdWFIoV5=Tg*viA5$3>y12hHzvIc^! z6#|Mt1wBMpNo4_2KN9XvWBgkVOY*ZF#+12cl6Ow%2a~79n?)x@J!FkFG{sX1Rrb+!PPawGsG_nA%T>2 zl!{Qy2udv}s>Edkb^{Vo3~)@!FDgMczz;Hz;TY_V&<=}!#|Rzdf(j<=5{#19V8X7b z!p=TONflO77Z+pg5EK{a7#bLWhXKGLW~~4j+d%7|28SRS39}Yue9F-YC6U7hR}jN; zpt2eo-bm>kDGi|xu|V8WtN4Oy}hS>qgQGO9aUI7$$~N+(JjCP>N-!7)tRC z6+7h4Q>Zg@eLjHfepaI21&u=p}2-$5z!7Ci%c%4%q>pWNzczuF$9w!UU5+} zl*&mh(Mc&T0r66bOL9QH4sfJ_21P@`gTM;esbCXQipo-piVSriw6RWdQBImp8dNWc z1{sx@mk$}^1Vs&`Bvw#x35OVoRQk9E1sNdRid_LxS&v--QbmMafiWQ~kov^fO)w>7 zf*BzN=7bbj5K>@CNP!{Ypd=WUplX_zE6CN+#naDS!Nmy@V@jZb92F&AuJ9nw5EKbe zJ02tfsq_>OIusxkCP)raOCiZ+=A|p76lIpBDk$-CxdeszxP~CfI)d~-t0lO3hQ>OE z20BXMl1@hfTw?0L3SR|~23{^uS^_y2?&xsvlt@8Qeo1O_2}q4=P>>;t3a7*rh0?rC zn4}Skq+fmsc-W~Ds?``p7Nj*fKQ}iqF9j-Zf+FvdSds{pFh!97YXl90rR5jpCc>;X zLs1i)nwkyOY>pz~m!GHW;vcM#l35H>V1c3_I5oK>zepi3zeFJ|zZC8^OB6+Z`3ePz z1*t_)D+~=lvtY2OhJ;#LVrdS{ZHAyggNJGmX!Z$38We1BX&0!=c)1|c3P=&F5vlK| zX%CJqc=-Sw!%i;J$w|{ucg`=UR7lLrFUd$PQczLn<${!2h>>oHItU3?otc-er>6%} z3NG0cuqx%{0!ii;r$cR1Pyp*yNY2kK$Vn|pRo8)<2r>s;+aQ?(Q3?uBnDP`9^^h_Y ztGznvo_WQfd5Gft(xT*4aIB@4l%#?tc_8UuotLY)C^;t;G;$9a%T!Qzv;sK;RFWdQ z80tc(fsnLQlA5AWl30|UT7unZkQpGeVeZpPAtjH z&qE1zh<0N%?NCF4A>j=gZ$$D=F=*T!oHa@^Qjw-{V8H{`te{Ywn41ckbjwXF(Nl0v z%mYP!O1?r#Myf(`enF)kC}9>sW>L}ff?^I-QTu^sMj=%-DC>c+tDg%m7Xt$W03r_a A`Tzg` literal 0 HcmV?d00001 diff --git a/DOSLINK b/DOSLINK new file mode 100644 index 0000000..3786395 --- /dev/null +++ b/DOSLINK @@ -0,0 +1,5 @@ +msdos mscode dosmes misc getset dircall alloc dev dir + +disk fat rom stdbuf stdcall stdctrlc stdfcb stdproc + +stdio time xenix xenix2; + + \ No newline at end of file diff --git a/DOSMAC.ASM b/DOSMAC.ASM new file mode 100644 index 0000000..d1501f5 --- /dev/null +++ b/DOSMAC.ASM @@ -0,0 +1,274 @@ +; +; Macro file for MSDOS. +; + +SUBTTL BREAK a listing into pages and give new subtitles +PAGE +BREAK MACRO subtitle + SUBTTL subtitle + PAGE +ENDM + +BREAK + +; +; declare a variable external and allocate a size +; +I_NEED MACRO sym,len + DATA SEGMENT BYTE PUBLIC 'DATA' + IFIDN , + EXTRN &sym:WORD + ELSE + IFIDN , + EXTRN &sym:DWORD + ELSE + EXTRN &sym:BYTE + ENDIF + ENDIF + DATA ENDS +ENDM + +; +; call a procedure that may be external. The call will be short. +; +invoke MACRO name +.xcref + IF2 + IFNDEF name + EXTRN name:NEAR + ENDIF + ENDIF +.cref + CALL name +ENDM + +PAGE +; +; jump to a label that may be external. The jump will be near. +; +transfer MACRO name +.xcref + IF2 + IFNDEF name + EXTRN name:NEAR + ENDIF + ENDIF +.cref + JUMP name +ENDM + +; +; get a short address in a word +; +short_addr MACRO name + IFDIF , +.xcref + IF2 + IFNDEF name + EXTRN name:NEAR + ENDIF + ENDIF +.cref + DW OFFSET DOSGROUP:name + ELSE + DW ? + ENDIF +ENDM + +; +; get a long address in a dword +; +long_addr MACRO name +.xcref + IF2 + IFNDEF name + EXTRN name:NEAR + ENDIF +.cref + DD name +ENDM + +; +; declare a PROC near or far but PUBLIC nonetheless +; +procedure MACRO name,distance + PUBLIC name +name PROC distance +ENDM + +PAGE +; +; define a data item to be public and of an appropriate size/type +; +I_AM MACRO name,size + PUBLIC name + + IFIDN , +name DW ? + ELSE + IFIDN , +name DD ? + ELSE + IFIDN , +name DB ? + ELSE +name DB size DUP (?) + ENDIF + ENDIF + ENDIF +ENDM + +PAGE +; +; call the macro chain +; +do_ext macro +endm + +PAGE + +; +; define an entry in a procedure +; +entry macro name + PUBLIC name +name: +endm + +BREAK + +error macro code + local a +.xcref + MOV AL,code + transfer SYS_RET_ERR +.cref +ENDM + +BREAK +; +; given a label either 2 byte jump to another label _J +; if it is near enough or 3 byte jump to +; + +jump macro lbl + local a +.xcref + a: + ifndef lbl&_J ;; is this the first invocation + JMP lbl + ELSE + IF lbl&_J GE $ + JMP lbl + ELSE + IF ($-lbl&_J) GT 126 ;; is the jump too far away? + JMP lbl + ELSE ;; do the short one... + JMP lbl&_J + ENDIF + ENDIF + ENDIF + lbl&_j = a +.cref +endm + +BREAK + +return macro + local a +.xcref +a: + RET +ret_l = a +.cref +endm + +BREAK + +makelab macro l,cc,ncc + local a + j&ncc a ;; j a: + return ;; return + a: ;; a: + ret_&cc = ret_l ;; define ret_ to be ret_l +endm + +condret macro cc,ncc + local a,b + ifdef ret_l ;; if ret_l is defined + if (($ - ret_l) le 126) and ($ gt ret_l) + ;; if ret_l is near enough then + a: j&cc ret_l ;; a: j to ret_l + ret_&cc = a ;; define ret_ to be a: + else + makelab a,cc,ncc + endif + else + ifdef ret_&cc ;; if ret_ defined + if (($ - ret_&cc) le 126) and ($ gt ret_&cc) + ;; if ret_ is near enough + a: j&cc ret_&cc ;; a: j to ret_ + ret_&cc = a ;; define ret_ to be a: + else + makelab a,cc,ncc + endif + else + makelab a,cc,ncc + endif + endif +endm +;condret macro cc,ncc +; local a,b +; ifdef ret_l ; if ret_l is defined +; if (($ - ret_l) le 126) and ($ gt ret_l) +; ; if ret_l is near enough then +; a: j&cc ret_l ; a: j to ret_l +; ret_&cc = a ; define ret_ to be a: +; exitm +; endif +; endif +; ifdef ret_&cc ; if ret_ defined +; if (($ - ret_&cc) le 126) and ($ gt ret_&cc) +; ; if ret_ is near enough +; a: j&cc ret_&cc ; a: j to ret_ +; ret_&cc = a ; define ret_ to be a: +; exitm +; endif +; endif +; j&ncc a ; j a: +; return ; return +; a: ; a: +; ret_&cc = ret_l ; define ret_ to be ret_l +;endm +; +BREAK + +retz macro + condret z,nz +endm + +BREAK + +retnz macro + condret nz,z +endm + +BREAK + +retc macro + condret c,nc +endm + +BREAK + +retnc macro + condret nc,c +endm + +BREAK + +context macro r + PUSH SS + POP r + ASSUME r:DOSGROUP +endm diff --git a/DOSMES.ASM b/DOSMES.ASM new file mode 100644 index 0000000..fb3f17a --- /dev/null +++ b/DOSMES.ASM @@ -0,0 +1,355 @@ + INCLUDE STDSW.ASM + +KANJI EQU FALSE + +Rainbow EQU FALSE + + INCLUDE DOSSYM.ASM +; +; segment ordering for MSDOS +; + +CONSTANTS SEGMENT BYTE PUBLIC 'CONST' +CONSTANTS ENDS + +DATA SEGMENT BYTE PUBLIC 'DATA' +DATA ENDS + +CODE SEGMENT BYTE PUBLIC 'CODE' +CODE ENDS + +LAST SEGMENT BYTE PUBLIC 'LAST' +LAST ENDS + +DOSGROUP GROUP CODE,CONSTANTS,DATA,LAST + +CONSTANTS SEGMENT BYTE PUBLIC 'CONST' + + PUBLIC DIVMES +DIVMES DB 13,10,"Divide overflow",13,10 + + PUBLIC DivMesLen +DivMesLen DB $-DivMes ; Length of the above message in bytes + + +; +; The next variable points to the country table for the current country +; ( the table returned by the AL=0 INTERNATIONAL call). +; + PUBLIC Current_Country + + IF KANJI +Current_Country DW OFFSET DOSGROUP:JAPTABLE + ELSE +Current_Country DW OFFSET DOSGROUP:USTABLE + ENDIF + +; +; The international tabel(s). +; This is simply a sequence of tables of the following form: +; +; BYTE Size of this table excluding this byte and the next +; BYTE Country code represented by this table +; A sequence of n bytes, where n is the number specified +; by the first byte above and is not > internat_block_max, +; in the correct order for being returned by the +; INTERNATIONAL call as follows: +; WORD Date format 0=mdy, 1=dmy, 2=ymd +; 5 BYTE Currency symbol null terminated +; 2 BYTE thousands separator null terminated +; 2 BYTE Decimal point null terminated +; 2 BYTE Date separator null terminated +; 2 BYTE Time separator null terminated +; 1 BYTE Bit field. Currency format. +; Bit 0. =0 $ before # =1 $ after # +; Bit 1. no. of spaces between # and $ (0 or 1) +; 1 BYTE No. of significant decimal digits in currency +; 1 BYTE Bit field. Time format. +; Bit 0. =0 12 hour clock =1 24 hour +; WORD Segment offset for address of case conversion routine +; WORD RESERVED. Filled in by DOS. Segment value for above routine +; 2 BYTE Data list separator null terminated. +; NOTE: The segment part of the DWORD Map_call is set +; by the INTERNATIONAL call. Do not try to initialize +; it to anything meaningful. +; +; The list of tables is terminated by putting a byte of -1 after the last +; table (a table with length -1). + + PUBLIC international_table + +international_table LABEL BYTE + + IF KANJI + DB SIZE internat_block ; Size in bytes of this table + DB 81 ; Country code +JAPTABLE internat_block <2,'\',0,0,0,0,',',0,'.',0,'-',0,':',0,0,0,1,OFFSET DOSGROUP:MAP_DCASE , 0,',',0> + ENDIF + + DB SIZE internat_block ; Size in bytes of this table + DB 1 ; Country code +USTABLE internat_block <0,'$',0,0,0,0,',',0,'.',0,'-',0,':',0,0,2,0,OFFSET DOSGROUP:MAP_DCASE,0,',',0> +; Tables for the IBM PC character set follow. The values +; associated with some of the currency symbols may change with +; other character sets. You may wish to add or delete country +; entries. NOTE: It is not a mistake that the JAPANESE entry +; has different currency symbols for the KANJI and +; non-KANJI versions. + +IF NOT KANJI +IF IBM + DB SIZE internat_block ; Size in bytes of this table + DB 44 ; Country code +UKTABLE internat_block <1,9Ch,0,0,0,0,',',0,'.',0,'-',0,':',0,0,2,0,OFFSET DOSGROUP:MAP_DCASE,0,',',0> + DB SIZE internat_block ; Size in bytes of this table + DB 49 ; Country code +GRMTABLE internat_block <1,'D','M',0,0,0,'.',0,',',0,'.',0,'.',0,3,2,1,OFFSET DOSGROUP:MAP_DCASE,0,';',0> + DB SIZE internat_block ; Size in bytes of this table + DB 33 ; Country code +FRNTABLE internat_block <1,'F',0,0,0,0,' ',0,',',0,'/',0,':',0,3,2,1,OFFSET DOSGROUP:MAP_DCASE,0,';',0> + DB SIZE internat_block ; Size in bytes of this table + DB 81 ; Country code +JAPTABLE internat_block <2,9DH,0,0,0,0,',',0,'.',0,'-',0,':',0,0,0,1,OFFSET DOSGROUP:MAP_DCASE , 0,',',0> +ENDIF +ENDIF + DB -1 ; End of tables + +CONSTANTS ENDS + + +CODE SEGMENT BYTE PUBLIC 'CODE' +ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + +;CASE MAPPER ROUTINE FOR 80H-FFH character range +; ENTRY: AL = Character to map +; EXIT: AL = The converted character +; Alters no registers except AL and flags. +; The routine should do nothing to chars below 80H. +; +; Example: + MAP_DCASE PROC FAR +IF NOT KANJI +IF IBM + CMP AL,80H + JB L_RET ;Map no chars below 80H ever + CMP AL,0A7H + JA L_RET ;This routine maps chars between 80H and A7H + SUB AL,80H ;Turn into index value + PUSH DS + PUSH BX + PUSH CS ;Move to DS + POP DS + MOV BX,OFFSET DOSGROUP:TABLE + XLAT ;Get upper case character + POP BX + POP DS +ENDIF +ENDIF + L_RET: RET + MAP_DCASE ENDP +IF NOT KANJI +IF IBM +TABLE: DB 80H,9AH,"E","A",8EH,"A",8FH,80H + DB "E","E","E","I","I","I",8EH,8FH + DB 90H,92H,92H,"O",99H,"O","U","U" + DB "Y",99H,9AH,9BH,9CH,9DH,9EH,9FH + DB "A","I","O","U",0A5H,0A5H,0A6H,0A7H +ENDIF +ENDIF + +SUBTTL EDIT FUNCTION ASSIGNMENTS AND HEADERS +PAGE +; The following two tables implement the current buffered input editing +; routines. The tables are pairwise associated in reverse order for ease +; in indexing. That is; The first entry in ESCTAB corresponds to the last +; entry in ESCFUNC, and the last entry in ESCTAB to the first entry in ESCFUNC. + + + PUBLIC ESCCHAR +ESCCHAR DB ESCCH ;Lead-in character for escape sequences + IF NOT Rainbow +ESCTAB: + IF NOT IBM + IF WANG + DB 0C0h ; ^Z inserter + DB 0C1H ; Copy one char + DB 0C7H ; Skip one char + DB 08AH ; Copy to char + DB 088H ; Skip to char + DB 09AH ; Copy line + DB 0CBH ; Kill line (no change in template) + DB 08BH ; Reedit line (new template) + DB 0C3H ; Backspace + DB 0C6H ; Enter insert mode + IF NOT TOGLINS + DB 0D6H ; Exit insert mode + ENDIF + DB 0C6H ; Escape character + DB 0C6H ; End of table + ELSE + ; VT52 equivalences + DB "Z" ; ^Z inserter + DB "S" ; F1 Copy one char + DB "V" ; F4 Skip one char + DB "T" ; F2 Copy to char + DB "W" ; F5 Skip to char + DB "U" ; F3 Copy line + DB "E" ; SHIFT ERASE Kill line (no change in template) + DB "J" ; ERASE Reedit line (new template) + DB "D" ; LEFT Backspace + DB "P" ; BLUE Enter insert mode + DB "Q" ; RED Exit insert mode + DB "R" ; GRAY Escape character + DB "R" ; End of table + ENDIF + ENDIF + IF IBM + DB 64 ; Ctrl-Z - F6 + DB 77 ; Copy one char - --> + DB 59 ; Copy one char - F1 + DB 83 ; Skip one char - DEL + DB 60 ; Copy to char - F2 + DB 62 ; Skip to char - F4 + DB 61 ; Copy line - F3 + DB 61 ; Kill line (no change to template ) - Not used + DB 63 ; Reedit line (new template) - F5 + DB 75 ; Backspace - <-- + DB 82 ; Enter insert mode - INS (toggle) + DB 65 ; Escape character - F7 + DB 65 ; End of table + ENDIF +ESCEND: +ESCTABLEN EQU ESCEND-ESCTAB + +ESCFUNC LABEL WORD + short_addr GETCH ; Ignore the escape sequence + short_addr TWOESC + IF NOT TOGLINS + short_addr EXITINS + ENDIF + short_addr ENTERINS + short_addr BACKSP + short_addr REEDIT + short_addr KILNEW + short_addr COPYLIN + short_addr SKIPSTR + short_addr COPYSTR + short_addr SKIPONE + short_addr COPYONE + + IF IBM + short_addr COPYONE + ENDIF + short_addr CTRLZ + ENDIF + +; +; OEMFunction key is expected to process a single function +; key input from a device and dispatch to the proper +; routines leaving all registers UNTOUCHED. +; +; Inputs: CS, SS are DOSGROUP +; Outputs: None. This function is expected to JMP to onw of +; the following labels: +; +; GetCh - ignore the sequence +; TwoEsc - insert an ESCChar in the buffer +; ExitIns - toggle insert mode +; EnterIns - toggle insert mode +; BackSp - move backwards one space +; ReEdit - reedit the line with a new template +; KilNew - discard the current line and start from scratch +; CopyLin - copy the rest of the template into the line +; SkipStr - read the next character and skip to it in the template +; CopyStr - read next char and copy from template to line until char +; SkipOne - advance position in template one character +; CopyOne - copy next character in template into line +; CtrlZ - place a ^Z into the template +; Registers that are allowed to be modified by this function are: +; AX, CX, BP + + PUBLIC OEMFunctionKey +OEMFunctionKey PROC NEAR + ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP + invoke $STD_CON_INPUT_NO_ECHO ; Get the second byte of the sequence + + IF NOT Rainbow + MOV CL,ESCTABLEN ; length of table for scan + PUSH DI ; save DI (cannot change it!) + MOV DI,OFFSET DOSGROUP:ESCTAB ; offset of second byte table + REPNE SCASB ; Look it up in the table + POP DI ; restore DI + SHL CX,1 ; convert byte offset to word + MOV BP,CX ; move to indexable register + JMP [BP+OFFSET DOSGROUP:ESCFUNC] ; Go to the right routine + ENDIF + IF Rainbow + +TransferIf MACRO value,address + local a + CMP AL,value + JNZ a + transfer address +a: +ENDM + + CMP AL,'[' ; is it second lead char + JZ EatParm ; yes, go walk tree +GoGetCh: + transfer GetCh ; no, ignore sequence +EatParm: + invoke $STD_CON_INPUT_NO_ECHO ; get argument + CMP AL,'A' ; is it alphabetic arg? + JAE EatAlpha ; yes, go snarf one up + XOR BP,BP ; init digit counter + JMP InDigit ; jump into internal eat digit routine +EatNum: + invoke $STD_CON_INPUT_NO_ECHO ; get next digit +InDigit: + CMP AL,'9' ; still a digit? + JA CheckNumEnd ; no, go check for end char + SUB AL,'0' ; turn into potential digit + JB GoGetCh ; oops, not a digit, ignore + MOV CX,BP ; save BP for 10 multiply + CBW ; make AL into AX + SHL BP,1 ; 2*BP + SHL BP,1 ; 4*BP + ADD BP,CX ; 5*BP + SHL BP,1 ; 10*BP + ADD BP,AX ; 10*BP + digit + JMP EatNum ; continue with number +CheckNumEnd: + CMP AL,7Eh ; is it end char ~ + JNZ GoGetCh ; nope, ignore key sequence + MOV AX,BP + transferIf 1,SkipStr ; FIND key + transferIf 2,EnterIns ; INSERT HERE key + transferIf 3,SkipOne ; REMOVE + transferIf 4,CopyStr ; SELECT + transferIf 17,TwoEsc ; INTERRUPT + transferIf 18,ReEdit ; RESUME + transferIf 19,KilNew ; CANCEL + transferIf 21,CtrlZ ; EXIT + transferIf 29,CopyLin ; DO + JMP GoGetCh +EatAlpha: + CMP AL,'O' ; is it O? + JA GoGetCh ; no, after assume bogus + JZ EatPQRS ; eat the rest of the bogus key + transferIf 'C',CopyOne ; RIGHT + transferIf 'D',BackSp ; LEFT + JMP GoGetCh +EatPQRS: + invoke $STD_CON_INPUT_NO_ECHO ; eat char after O + JMP GoGetCh + ENDIF + +OEMFunctionKey ENDP + +CODE ENDS + + do_ext + END + + + \ No newline at end of file diff --git a/DOSSEG.ASM b/DOSSEG.ASM new file mode 100644 index 0000000..98dbdf3 --- /dev/null +++ b/DOSSEG.ASM @@ -0,0 +1,17 @@ +; +; segment ordering for MSDOS +; + +CONSTANTS SEGMENT BYTE PUBLIC 'CONST' +CONSTANTS ENDS + +DATA SEGMENT BYTE PUBLIC 'DATA' +DATA ENDS + +CODE SEGMENT BYTE PUBLIC 'CODE' +CODE ENDS + +LAST SEGMENT BYTE PUBLIC 'LAST' +LAST ENDS + +DOSGROUP GROUP CODE,CONSTANTS,DATA,LAST diff --git a/DOSSYM.ASM b/DOSSYM.ASM new file mode 100644 index 0000000..417b13b --- /dev/null +++ b/DOSSYM.ASM @@ -0,0 +1,963 @@ +include DOSMAC.ASM +IF2 + %OUT DOSSYM in Pass 2 +ENDIF + +IFNDEF ALTVECT +ALTVECT EQU 0 ;FALSE +ENDIF + +DOS_MAJOR_VERSION EQU 2 +DOS_MINOR_VERSION EQU 11 + +BREAK + +c_DEL EQU 7Fh ; ASCII rubout or delete previous char +c_BS EQU 08h ; ^H ASCII backspace +c_CR EQU 0Dh ; ^M ASCII carriage return +c_LF EQU 0Ah ; ^J ASCII linefeed +c_ETB EQU 17h ; ^W ASCII end of transmission +c_NAK EQU 15h ; ^U ASCII negative acknowledge +c_ETX EQU 03h ; ^C ASCII end of text +c_HT EQU 09h ; ^I ASCII tab + +BREAK + + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; ; +; C A V E A T P R O G R A M M E R ; +; ; +; Certain structures, constants and system calls below are private to ; +; the DOS and are extremely version-dependent. They may change at any ; +; time at the implementors' whim. As a result, they must not be ; +; documented to the general public. If an extreme case arises, they ; +; must be documented with this warning. ; +; ; +; Those structures and constants that are subject to the above will be ; +; marked and bracketed with the flag: ; +; ; +; C A V E A T P R O G R A M M E R ; +; ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + +; Bios Parameter Block definition +; This structure is used to build a full DPB + +BPBLOCK STRUC +BPSECSZ DW ? ; Size in bytes of physical sector +BPCLUS DB ? ; Sectors/Alloc unit +BPRES DW ? ; Number of reserved sectors +BPFTCNT DB ? ; Number of FATs +BPDRCNT DW ? ; Number of directory entries +BPSCCNT DW ? ; Total number of sectors +BPMEDIA DB ? ; Media descriptor byte +BPFTSEC DW ? ; Number of sectors taken up by one FAT +BPBLOCK ENDS +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + +; Field definition for I/O buffer information + +BUFFINFO STRUC +NEXTBUF DD ? ; Pointer to next buffer in list +; The next two items are often refed as a word +BUFDRV DB ? ; Logical drive # assoc with buffer FF = free +BUFDIRTY DB ? ; Dirty flag +BUFPRI DB ? ; Buffer selection priority (see EQUs below) +VISIT DB ? ; Visit flag for buffer pool scans +BUFSECNO DW ? ; Sector number of buffer +; The next two items are often refed as a word +BUFWRTCNT DB ? ; For FAT sectors, # times sector written out +BUFWRTINC DB ? ; " " " , # sectors between each write +BUFDRVDP DD ? ; Pointer to drive parameters +BUFFINFO ENDS + +BUFINSIZ EQU SIZE BUFFINFO + ; Size of structure in bytes + +FREEPRI EQU 0 +LBRPRI EQU 2 ; Last byte of buffer read +LBWPRI EQU 4 ; Last byte written +RPRI EQU 6 ; Read but not last byte +WPRI EQU 8 ; Written but not last byte +DIRPRI EQU 15 ; Directory Sector +FATPRI EQU 30 ; FAT sector +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +BREAK +; Location of user registers relative user stack pointer + +user_environ STRUC +user_AX DW ? +user_BX DW ? +user_CX DW ? +user_DX DW ? +user_SI DW ? +user_DI DW ? +user_BP DW ? +user_DS DW ? +user_ES DW ? +user_IP DW ? +user_CS DW ? +user_F DW ? +user_environ ENDS + +BREAK + +INTTAB EQU 20H +INTBASE EQU 4 * inttab +ENTRYPOINT EQU INTBASE+40H + + IF ALTVECT +ALTTAB EQU 0F0H +ALTBASE EQU 4 * ALTTAB + ENDIF + +; +; interrupt assignments +; + IF NOT ALTVECT +int_abort EQU INTTAB ; abort process +int_command EQU int_abort+1 ; call MSDOS +int_terminate EQU int_abort+2 ; int to terminate address +int_ctrl_c EQU int_abort+3 ; ^c trapper +int_fatal_abort EQU int_abort+4 ; hard disk error +int_disk_read EQU int_abort+5 ; logical sector disk read +int_disk_write EQU int_abort+6 ; logical sector disk write +int_keep_process EQU int_abort+7 ; terminate program and stay + ; resident +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +int_spooler EQU int_abort+8 ; spooler call +int_fastcon EQU int_abort+9 ; fast CON interrupt +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + ELSE +int_abort EQU INTTAB ; abort process +int_command EQU int_abort+1 ; call MSDOS +int_terminate EQU ALTTAB ; int to terminate address +int_ctrl_c EQU int_terminate+1 ; ^c trapper +int_fatal_abort EQU int_terminate+2 ; hard disk error +int_disk_read EQU int_abort+5 ; logical sector disk read +int_disk_write EQU int_abort+6 ; logical sector disk write +int_keep_process EQU int_abort+7 ; terminate program and stay + ; resident +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +int_spooler EQU int_terminate+3 ; spooler call +int_fastcon EQU int_abort+9 ; fast CON interrupt +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + ENDIF + +addr_int_abort EQU 4 * int_abort +addr_int_command EQU 4 * int_command +addr_int_terminate EQU 4 * int_terminate +addr_int_ctrl_c EQU 4 * int_ctrl_c +addr_int_fatal_abort EQU 4 * int_fatal_abort +addr_int_disk_read EQU 4 * int_disk_read +addr_int_disk_write EQU 4 * int_disk_write +addr_int_keep_process EQU 4 * int_keep_process +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +addr_int_spooler EQU 4 * int_spooler +addr_int_fastcon EQU 4 * int_fastcon +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +BREAK +; MSDOS partitions the disk into 4 sections: +; +; phys sector 0: +-------------------+ +; | | boot/reserved | +; | +-------------------+ +; | | File allocation | +; v | table(s) | +; | (multiple copies | +; | are kept) | +; +-------------------+ +; | Directory | +; +-------------------+ +; | File space | +; +-------------------+ +; | Unaddressable | +; | (to end of disk) | +; +-------------------+ +; +; All partition boundaries are sector boundaries. The size of the FAT is +; adjusted to maximize the file space addressable. + +BREAK + +; +; +---------------------------+ +; | (12 BYTE) filename/ext | 0 0 +; +---------------------------+ +; | (BYTE) attributes | 11 B +; +---------------------------+ +; | (10 BYTE) reserved | 12 C +; +---------------------------+ +; | (WORD) time of last write | 22 16 +; +---------------------------+ +; | (WORD) date of last write | 24 18 +; +---------------------------+ +; | (WORD) First cluster | 26 1A +; +---------------------------+ +; | (DWORD) file size | 28 1C +; +---------------------------+ +; +; First byte of filename = E5 -> free directory entry +; = 00 -> end of allocated directory +; Time: Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour +; Date: Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980 +; +dir_entry STRUC +dir_name DB 11 DUP (?) ; file name +dir_attr DB ? ; attribute bits +dir_pad DB 10 DUP (?) ; reserved for expansion +dir_time DW ? ; time of last write +dir_date DW ? ; date of last write +dir_first DW ? ; first allocation unit of file +dir_size_l DW ? ; low 16 bits of file size +dir_size_h DW ? ; high 16 bits of file size +dir_entry ENDS + +attr_read_only EQU 1h +attr_hidden EQU 2h +attr_system EQU 4h +attr_volume_id EQU 8h +attr_directory EQU 10h +attr_archive EQU 20h + +attr_all EQU attr_hidden+attr_system+attr_directory + ; OR of hard attributes for FINDENTRY + +attr_ignore EQU attr_read_only+attr_archive + ; ignore this(ese) attribute(s) during + ; search first/next + +attr_changeable EQU attr_read_only+attr_hidden+attr_system+attr_archive + ; changeable via CHMOD + +BREAK +; +; The File Allocation Table uses a 12-bit entry for each allocation unit on +; the disk. These entries are packed, two for every three bytes. The contents +; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result +; to the base address of the Allocation Table; 3) fetching the 16-bit word +; at this address; 4) If N was odd (so that N*1.5 was not an integer), shift +; the word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry +; number zero is used as an end-of-file trap in the OS and is passed to the +; BIOS to help determine disk format. Entry 1 is reserved for future use. +; The first available allocation unit is assigned entry number two, and even +; though it is the first, is called cluster 2. Entries greater than 0FF8H +; are end of file marks; entries of zero are unallocated. Otherwise, the +; contents of a FAT entry is the number of the next cluster in the file. +; +; Clusters with bad sectors are tagged with FF7H. Any non-zero number would +; do because these clusters show as allocated, but are not part of any +; allocation chain and thus will never be allocated to a file. A particular +; number is selected so that disk checking programs know what to do (ie. a +; cluster with entry FF7H which is not in a chain is not an error). + +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + +DIRSTRLEN EQU 64 ; Max length in bytes of directory strings + +dpb STRUC +dpb_drive DB ? ; Logical drive # assoc with DPB (A=0,B=1,...) +dpb_UNIT DB ? ; Driver unit number of DPB +dpb_sector_size DW ? ; Size of physical sector in bytes +dpb_cluster_mask DB ? ; Sectors/cluster - 1 +dpb_cluster_shift DB ? ; Log2 of sectors/cluster +dpb_first_FAT DW ? ; Starting record of FATs +dpb_FAT_count DB ? ; Number of FATs for this drive +dpb_root_entries DW ? ; Number of directory entries +dpb_first_sector DW ? ; First sector of first cluster +dpb_max_cluster DW ? ; Number of clusters on drive + 1 +dpb_FAT_size DB ? ; Number of records occupied by FAT +dpb_dir_sector DW ? ; Starting record of directory +dpb_driver_addr DD ? ; Pointer to driver +dpb_media DB ? ; Media byte +dpb_first_access DB ? ; This is initialized to -1 to force a media + ; check the first time this DPB is used +dpb_next_dpb DD ? ; Pointer to next Drive parameter block +dpb_current_dir DW ? ; Cluster number of start of current directory + ; 0 indicates root, -1 indicates invalid (disk + ; ? changed) +dpb_dir_text DB DIRSTRLEN DUP(?) + ; ASCIZ string of current directory +dpb ENDS + +DPBSIZ EQU SIZE dpb ; Size of the structure in bytes + +DSKSIZ = dpb_max_cluster ; Size of disk (temp used during init only) +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +BREAK +; +; Field definition for FCBs +; The FCB has the following structure: +; +; +---------------------------+ +; | Drive indicator(byte) | +; +---------------------------+ +; | Filename (8 chars) | +; +---------------------------+ +; | Extension (3 chars) | +; +---------------------------+ +; | Current Extent(word) | +; +---------------------------+ +; | Record size (word) | +; +---------------------------+ +; | File Size (2 words) | +; +---------------------------+ +; | Date of write | +; +---------------------------+ +; | Time of write | +; +---------------------------+ +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; | Flags: | +; | bit 7=0 file/1 device | +; | bit 6=0 if dirty | +; | bits 0-5 deviceid | +; +---------------------------+ +; | first cluster in file | +; +---------------------------+ +; | position of last cluster | +; +---------------------------+ +; | last cluster accessed | 12 bit-+--- packed in 3 bytes +; +---------------------------+ | +; | parent directory | <------+ +; +---------------------------+ +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; | next record number | +; +---------------------------+ +; | random record number | +; +---------------------------+ +; + +sys_fcb STRUC +fcb_drive DB ? +fcb_name DB 8 DUP (?) +fcb_ext DB 3 DUP (?) +fcb_EXTENT DW ? +fcb_RECSIZ DW ? ; Size of record (user settable) +fcb_FILSIZ DW ? ; Size of file in bytes; used with the following + ; word +fcb_DRVBP DW ? ; BP for SEARCH FIRST and SEARCH NEXT +fcb_FDATE DW ? ; Date of last writing +fcb_FTIME DW ? ; Time of last writing +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +fcb_DEVID DB ? ; Device ID number, bits 0-5 if file. + ; bit 7=0 for file, bit 7=1 for I/O device + ; If file, bit 6=0 if dirty + ; If I/O device, bit 6=0 if EOF (input) + ; Bit 5=1 if Raw mode + ; Bit 0=1 if console input device + ; Bit 1=1 if console output device + ; Bit 2=1 if null device + ; Bit 3=1 if clock device +fcb_FIRCLUS DW ? ; First cluster of file +fcb_CLUSPOS DW ? ; Position of last cluster accessed +fcb_LSTCLUS DW ? ; Last cluster accessed and directory pack 2 12 + DB ? ; bit numbers into 24 bits... +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +fcb_NR DB ? ; Next record +fcb_RR DB 4 DUP (?) ; Random record +sys_fcb ENDS + +FILDIRENT = fcb_FILSIZ ; Used only by SEARCH FIRST and SEARCH + ; NEXT + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +devid_file_clean EQU 40h ; true if file and not written +devid_file_mask_drive EQU 3Fh ; mask for drive number + +devid_device EQU 80h ; true if a device +devid_device_EOF EQU 40h ; true if end of file reached +devid_device_raw EQU 20h ; true if in raw mode +devid_device_special EQU 10h ; true if special device +devid_device_clock EQU 08h ; true if clock device +devid_device_null EQU 04h ; true if null device +devid_device_con_out EQU 02h ; true if console output +devid_device_con_in EQU 01h ; true if consle input + +; +; structure of devid field as returned by IOCTL is: +; +; BIT 7 6 5 4 3 2 1 0 +; |---|---|---|---|---|---|---|---| +; | I | E | R | S | I | I | I | I | +; | S | O | A | P | S | S | S | S | +; | D | F | W | E | C | N | C | C | +; | E | | | C | L | U | O | I | +; | V | | | L | K | L | T | N | +; |---|---|---|---|---|---|---|---| +; ISDEV = 1 if this channel is a device +; = 0 if this channel is a disk file +; +; If ISDEV = 1 +; +; EOF = 0 if End Of File on input +; RAW = 1 if this device is in Raw mode +; = 0 if this device is cooked +; ISCLK = 1 if this device is the clock device +; ISNUL = 1 if this device is the null device +; ISCOT = 1 if this device is the console output +; ISCIN = 1 if this device is the console input +; +; If ISDEV = 0 +; EOF = 0 if channel has been written +; Bits 0-5 are the block device number for +; the channel (0 = A, 1 = B, ...) +; +devid_ISDEV EQU 80h +devid_EOF EQU 40h +devid_RAW EQU 20h +devid_SPECIAL EQU 10H +devid_ISCLK EQU 08h +devid_ISNUL EQU 04h +devid_ISCOT EQU 02h +devid_ISCIN EQU 01h + +devid_block_dev EQU 1Fh ; mask for block device number + +; +; find first/next buffer +; +find_buf STRUC +find_buf_sattr DB ? ; attribute of search +find_buf_drive DB ? ; drive of search +find_buf_name DB 11 DUP (?) ; formatted name +find_buf_LastEnt DW ? ; LastEnt +find_buf_ThisDPB DD ? ; This DPB +find_buf_DirStart DW ? ; DirStart +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +find_buf_attr DB ? ; attribute found +find_buf_time DW ? ; time +find_buf_date DW ? ; date +find_buf_size_l DW ? ; low(size) +find_buf_size_h DW ? ; high(size) +find_buf_pname DB 13 DUP (?) ; packed name +find_buf ENDS + +BREAK +; +; Process data block (otherwise known as program header) +; + +FilPerProc EQU 20 + +Process_data_block STRUC +PDB_Exit_Call DW ? ; INT int_abort system terminate +PDB_block_len DW ? ; size of execution block + DB ? +PDB_CPM_Call DB 5 DUP (?) ; ancient call to system +PDB_Exit DD ? ; pointer to exit routine +PDB_Ctrl_C DD ? ; pointer to ^C routine +PDB_Fatal_abort DD ? ; pointer to fatal error +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +PDB_Parent_PID DW ? ; PID of parent (terminate PID) +PDB_JFN_Table DB FilPerProc DUP (?) + ; indices into system table +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +PDB_environ DW ? ; seg addr of environment +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +PDB_User_stack DD ? ; stack of self during system calls +PDB_PAD1 DB 1Eh DUP (?) +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +PDB_Call_system DB 5 DUP (?) ; portable method of system call +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +PDB_PAD2 DB 6h DUP (?) ; +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Process_data_block ENDS + +BREAK +; +; EXEC arg block - load/go program +; + +; +; The following get used as arguments to the EXEC system call. They indicate +; whether or not the program is executed or whether or not a program header +; gets created. +; +exec_func_no_execute EQU 1 ; no execute bit +exec_func_overlay EQU 2 ; overlay bit + +Exec0 STRUC +Exec0_environ DW ? ; seg addr of environment +Exec0_com_line DD ? ; pointer to asciz command line +Exec0_5C_FCB DD ? ; default fcb at 5C +Exec0_6C_FCB DD ? ; default fcb at 6C +Exec0 ENDS + +Exec1 STRUC +Exec1_environ DW ? ; seg addr of environment +Exec1_com_line DD ? ; pointer to asciz command line +Exec1_5C_FCB DD ? ; default fcb at 5C +Exec1_6C_FCB DD ? ; default fcb at 6C +Exec1_SP DW ? ; stack pointer of program +Exec1_SS DW ? ; stack seg register of program +Exec1_IP DW ? ; entry point IP +Exec1_CS DW ? ; entry point CS +Exec1 ENDS + +Exec3 STRUC +Exec3_load_addr DW ? ; seg address of load point +Exec3_reloc_fac DW ? ; relocation factor +Exec3 ENDS + +; +; Exit codes in upper byte +; +Exit_terminate EQU 0 +Exit_abort EQU 0 +Exit_Ctrl_C EQU 1 +Exit_Hard_Error EQU 2 +Exit_Keep_process EQU 3 + +; +; EXE file header +; + +EXE_file STRUC +exe_signature DW ? ; must contain 4D5A (yay zibo!) +exe_len_mod_512 DW ? ; low 9 bits of length +exe_pages DW ? ; number of 512b pages in file +exe_rle_count DW ? ; count of reloc entries +exe_par_dir DW ? ; number of paragraphs before image +exe_min_BSS DW ? ; minimum number of para of BSS +exe_max_BSS DW ? ; max number of para of BSS +exe_SS DW ? ; stack of image +exe_SP DW ? ; SP of image +exe_chksum DW ? ; checksum of file (ignored) +exe_IP DW ? ; IP of entry +exe_CS DW ? ; CS of entry +exe_rle_table DW ? ; byte offset of reloc table +exe_iov DW ? ; overlay number (0 for root) +exe_sym_tab DD ? ; offset of symbol table in file +EXE_file ENDS + +exe_valid_signature EQU 5A4Dh +exe_valid_old_signature EQU 4D5Ah + +symbol_entry STRUC +sym_value DD ? +sym_type DW ? +sym_len DB ? +sym_name DB 255 dup (?) +symbol_entry ENDS + +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; +; system file table +; + +sft STRUC +sft_link DD ? +sft_count DW ? ; number of entries +sft_table DW ? ; beginning of array of the following +sft ENDS + +; +; system file table entry +; + +sf_entry STRUC +sf_ref_count DB ? ; number of processes sharing fcb +sf_mode DB ? ; mode of access +sf_attr DB ? ; attribute of file +sf_fcb DB (SIZE sys_fcb) DUP (?) + ; actual FCB +sf_entry ENDS + +sf_default_number EQU 5h +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; +; arena item +; +arena STRUC +arena_signature DB ? ; 4D for valid item, 5A for last item +arena_owner DW ? ; owner of arena item +arena_size DW ? ; size in paragraphs of item +arena ENDS + +; +; Current structure of the data returned by the international call +; + +internat_block STRUC +Date_tim_format DW ? ; 0-USA, 1-EUR, 2-JAP +Currency_sym DB ? ; Currency Symbol 5 bytes + DB ? + DB ? + DB ? + DB ? +Thous_sep DB ? ; Thousands separator 2 bytes + DB ? +Decimal_sep DB ? ; Decimal separator 2 bytes + DB ? +Date_sep DB ? ; Date separator 2 bytes + DB ? +Time_sep DB ? ; Decimal separator 2 bytes + DB ? +Bit_feild DB ? ; Bit values + ; Bit 0 = 0 if currency symbol first + ; = 1 if currency symbol last + ; Bit 1 = 0 if No space after currency symbol + ; = 1 if space after currency symbol +Currency_cents DB ? ; Number of places after currency dec point +Time_24 DB ? ; 1 if 24 hour time, 0 if 12 hour time +Map_call DW ? ; Address of case mapping call (DWORD) + DW ? ; THIS IS TWO WORDS SO IT CAN BE INITIALIZED + ; in pieces. +Data_sep DB ? ; Data list separator character + DB ? +internat_block ENDS + +; +; Max size of the block returned by the INTERNATIONAL call +; +internat_block_max EQU 32 + +; +; CAUTION: The routines in ALLOC.ASM rely on the fact that arena_signature +; and arena_owner_system are all equal to zero and are contained in DI. Change +; them and change ALLOC.ASM. + +arena_owner_system EQU 0 ; free block indication + +arena_signature_normal EQU 4Dh ; valid signature, not end of arena +arena_signature_end EQU 5Ah ; valid signature, last block in arena +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +BREAK + +mi_INT EQU 0CDh +mi_Long_JMP EQU 0EAh +mi_Long_CALL EQU 09Ah +mi_Long_RET EQU 0CBh + +BREAK + +stdin EQU 0 +stdout EQU 1 +stderr EQU 2 +stdaux EQU 3 +stdprn EQU 4 + +BREAK + +open_for_read EQU 0 +open_for_write EQU 1 +open_for_both EQU 2 + +BREAK + +; +; XENIX calls all return error codes through AX. If an error occurred then +; the carry bit will be set and the error code is in AX. If no error occurred +; then the carry bit is reset and AX contains returned info. +; + +no_error_occurred EQU 0 ? + +error_invalid_function EQU 1 +error_file_not_found EQU 2 +error_path_not_found EQU 3 +error_too_many_open_files EQU 4 +error_access_denied EQU 5 +error_invalid_handle EQU 6 +error_arena_trashed EQU 7 +error_not_enough_memory EQU 8 +error_invalid_block EQU 9 +error_bad_environment EQU 10 +error_bad_format EQU 11 +error_invalid_access EQU 12 +error_invalid_data EQU 13 +;**** unused EQU 14 +error_invalid_drive EQU 15 +error_current_directory EQU 16 +error_not_same_device EQU 17 +error_no_more_files EQU 18 + +country_not_found EQU error_file_not_found +alloc_not_enough_memory EQU error_not_enough_memory +alloc_arena_trashed EQU error_arena_trashed + +close_invalid_handle EQU error_invalid_handle +close_invalid_function EQU error_invalid_function + +chdir_path_not_found EQU error_path_not_found + +chmod_path_not_found EQU error_path_not_found +chmod_access_denied EQU error_access_denied +chmod_invalid_function EQU error_invalid_function + +creat_access_denied EQU error_access_denied +creat_path_not_found EQU error_path_not_found +creat_too_many_open_files EQU error_too_many_open_files + +curdir_invalid_drive EQU error_invalid_drive + +dealloc_invalid_block EQU error_invalid_block +dealloc_arena_trashed EQU error_arena_trashed + +dup_invalid_handle EQU error_invalid_handle +dup_too_many_open_files EQU error_too_many_open_files + +dup2_invalid_handle EQU error_invalid_handle + +exec_invalid_function EQU error_invalid_function +exec_bad_environment EQU error_bad_environment +exec_bad_format EQU error_bad_format +exec_not_enough_memory EQU error_not_enough_memory +exec_file_not_found EQU error_file_not_found + +filetimes_invalid_function EQU error_invalid_function +filetimes_invalid_handle EQU error_invalid_handle + +findfirst_file_not_found EQU error_file_not_found +findfirst_no_more_files EQU error_no_more_files +findnext_no_more_files EQU error_no_more_files + +international_invalid_function EQU error_invalid_function + +ioctl_invalid_handle EQU error_invalid_handle +ioctl_invalid_function EQU error_invalid_function +ioctl_invalid_data EQU error_invalid_data + +lseek_invalid_handle EQU error_invalid_handle +lseek_invalid_function EQU error_invalid_function + +mkdir_path_not_found EQU error_path_not_found +mkdir_access_denied EQU error_access_denied + +open_invalid_access EQU error_invalid_access +open_file_not_found EQU error_file_not_found +open_access_denied EQU error_access_denied +open_too_many_open_files EQU error_too_many_open_files + +read_invalid_handle EQU error_invalid_handle +read_access_denied EQU error_access_denied + +rename_file_not_found EQU error_file_not_found +rename_not_same_device EQU error_not_same_device +rename_access_denied EQU error_access_denied + +rmdir_path_not_found EQU error_path_not_found +rmdir_access_denied EQU error_access_denied +rmdir_current_directory EQU error_current_directory + +setblock_invalid_block EQU error_invalid_block +setblock_arena_trashed EQU error_arena_trashed +setblock_not_enough_memory EQU error_not_enough_memory +setblock_invalid_function EQU error_invalid_function + +unlink_file_not_found EQU error_file_not_found +unlink_access_denied EQU error_access_denied + +write_invalid_handle EQU error_invalid_handle +write_access_denied EQU error_access_denied + +BREAK + +Abort EQU 0 ; 0 0 +Std_Con_Input EQU 1 ; 1 1 +Std_Con_Output EQU 2 ; 2 2 +Std_Aux_Input EQU 3 ; 3 3 +Std_Aux_Output EQU 4 ; 4 4 +Std_Printer_Output EQU 5 ; 5 5 +Raw_Con_IO EQU 6 ; 6 6 +Raw_Con_Input EQU 7 ; 7 7 +Std_Con_Input_No_Echo EQU 8 ; 8 8 +Std_Con_String_Output EQU 9 ; 9 9 +Std_Con_String_Input EQU 10 ; 10 A +Std_Con_Input_Status EQU 11 ; 11 B +Std_Con_Input_Flush EQU 12 ; 12 C +Disk_Reset EQU 13 ; 13 D +Set_Default_Drive EQU 14 ; 14 E +FCB_Open EQU 15 ; 15 F +FCB_Close EQU 16 ; 16 10 +Dir_Search_First EQU 17 ; 17 11 +Dir_Search_Next EQU 18 ; 18 12 +FCB_Delete EQU 19 ; 19 13 +FCB_Seq_Read EQU 20 ; 20 14 +FCB_Seq_Write EQU 21 ; 21 15 +FCB_Create EQU 22 ; 22 16 +FCB_Rename EQU 23 ; 23 17 +Get_Default_Drive EQU 25 ; 25 19 +Set_DMA EQU 26 ; 26 1A +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Get_Default_DPB EQU 31 ; 31 1F +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +FCB_Random_Read EQU 33 ; 33 21 +FCB_Random_Write EQU 34 ; 34 22 +Get_FCB_File_Length EQU 35 ; 35 23 +Get_FCB_Position EQU 36 ; 36 24 +Set_Interrupt_Vector EQU 37 ; 37 25 +Create_Process_Data_Block EQU 38 ; 38 26 +FCB_Random_Read_Block EQU 39 ; 39 27 +FCB_Random_Write_Block EQU 40 ; 40 28 +Parse_File_Descriptor EQU 41 ; 41 29 +Get_Date EQU 42 ; 42 2A +Set_Date EQU 43 ; 43 2B +Get_Time EQU 44 ; 44 2C +Set_Time EQU 45 ; 45 2D +Set_Verify_On_Write EQU 46 ; 46 2E +; Extended functionality group +Get_DMA EQU 47 ; 47 2F +Get_Version EQU 48 ; 48 30 +Keep_Process EQU 49 ; 49 31 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Get_DPB EQU 50 ; 50 32 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Set_CTRL_C_Trapping EQU 51 ; 51 33 +Get_InDOS_Flag EQU 52 ; 52 34 +Get_Interrupt_Vector EQU 53 ; 53 35 +Get_Drive_Freespace EQU 54 ; 54 36 +Char_Oper EQU 55 ; 55 37 +International EQU 56 ; 56 38 +; Directory Group +MKDir EQU 57 ; 57 39 +RMDir EQU 58 ; 58 3A +CHDir EQU 59 ; 59 3B +; File Group +Creat EQU 60 ; 60 3C +Open EQU 61 ; 61 3D +Close EQU 62 ; 62 3E +Read EQU 63 ; 63 3F +Write EQU 64 ; 64 40 +Unlink EQU 65 ; 65 41 +LSeek EQU 66 ; 66 42 +CHMod EQU 67 ; 67 43 +IOCtl EQU 68 ; 68 44 +XDup EQU 69 ; 69 45 +XDup2 EQU 70 ; 70 46 +Current_Dir EQU 71 ; 71 47 +; Memory Group +Alloc EQU 72 ; 72 48 +Dealloc EQU 73 ; 73 49 +Setblock EQU 74 ; 74 4A +; Process Group +Exec EQU 75 ; 75 4B +Exit EQU 76 ; 76 4C +Wait EQU 77 ; 77 4D +Find_First EQU 78 ; 78 4E +; Special Group +Find_Next EQU 79 ; 79 4F +; SPECIAL SYSTEM GROUP +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Set_Current_PDB EQU 80 ; 80 50 +Get_Current_PDB EQU 81 ; 81 51 +Get_In_Vars EQU 82 ; 82 52 +SetDPB EQU 83 ; 83 53 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Get_Verify_On_Write EQU 84 ; 84 54 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Dup_PDB EQU 85 ; 85 55 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Rename EQU 86 ; 86 56 +File_Times EQU 87 ; 87 57 +AllocOper EQU 88 ; 88 58 +; Network extention system calls +GetExtendedError EQU 89 ; 89 59 +CreateTempFile EQU 90 ; 90 5A +CreateNewFile EQU 91 ; 91 5B +LockOper EQU 92 ; 92 5C Lock and Unlock +ServerCall EQU 93 ; 93 5D CommitAll, ServerDOSCall, + ; CloseByName, CloseUser, + ; CloseUserProcess, + ; GetOpenFileList +UserIDOper EQU 94 ; 94 5E Get and Set +AssignOper EQU 95 ; 95 5F On, Off, Get, Set, Cancel + +Set_Oem_Handler EQU 248 ; 248 F8 +OEM_C1 EQU 249 ; 249 F9 +OEM_C2 EQU 250 ; 250 FA +OEM_C3 EQU 251 ; 251 FB +OEM_C4 EQU 252 ; 252 FC +OEM_C5 EQU 253 ; 253 FD +OEM_C6 EQU 254 ; 254 FE +OEM_C7 EQU 255 ; 255 FF +SUBTTL diff --git a/EDLIN.ASM b/EDLIN.ASM new file mode 100644 index 0000000..534b483 --- /dev/null +++ b/EDLIN.ASM @@ -0,0 +1,1846 @@ + title EDLIN for MSDOS 2.0 + +;-----------------------------------------------------------------------; +; REVISION HISTORY: ; +; ; +; V1.02 ; +; ; +; V2.00 9/13/82 M.A. Ulloa ; +; Modified to use Pathnames in command line file ; +; specification, modified REPLACE to use an empty ; +; string intead of the old replace string when this ; +; is missing, and search and replace now start from ; +; first line of buffer (like old version of EDLIN) ; +; instead than current+1 line. Also added the U and ; +; V commands that search (replace) starting from the ; +; current+1 line. ; +; ; +; 9/15/82 M.A. Ulloa ; +; Added the quote character (^V). ; +; ; +; 9/16/82 M.A. Ulloa ; +; Corrected bug about use of quote char when going ; +; into default insert mode. Also corrected the problem ; +; with ^Z being the end of file marker. End of file is ; +; reached when an attempt to read returns less chars ; +; than requested. ; +; ; +; 9/17/82 M.A. Ulloa ; +; Corrected bug about boundaries for Copy ; +; ; +; 10/4/82 Rev. 1 M.A. Ulloa ; +; The IBM version now does NOT have the U and V ; +; commands. The MSDOS version HAS the U and V commands. ; +; Added the B switch, and modified the effect of ; +; the quote char. ; +; ; +; 10/7/82 Rev. 2 M.A. Ulloa ; +; Changed the S and R commands to start from the ; +; current line+1 (as U and V did). Took away U and V in ; +; all versions. ; +; ; +; 10/13/82 Rev. 3 M.A. Ulloa ; +; Now if parameter1 < 1 then parameter1 = 1 ; +; ; +; 10/15/82 Rev. 4 M.A. Ulloa ; +; Param4 if specified must be an absolute number that ; +; reprecents the count. ; +; ; +; 10/18/82 Rev. 5 M.A. Ulloa ; +; Fixed problem with trying to edit files with the ; +; same name as directories. Also, if the end of file is ; +; reached it checks that a LF is the last character, ; +; otherwise it inserts a CRLF pair at the end. ; +; ; +; 10/20/82 Rev. 6 M.A.Ulloa ; +; Changed the text of some error messages for IBM and ; +; rewrite PAGE. ; +; ; +; 10/25/82 Rev. 7 M.A.Ulloa ; +; Made all messages as in the IBM vers. ; +; ; +; 10/28/82 Rev. 8 M.A.Ulloa ; +; Corrected problem with parsing for options. ; +; ; +; Rev. 9 Aaron Reynolds ; +; Made error messages external. ; +; ; +; 12/08/82 Rev. 10 M.A. Ulloa ; +; Corrected problem arising with having to restore ; +; the old directory in case of a file name error. ; +; ; +; 12/17/82 Rev. 11 M.A. Ulloa ; +; Added the ROPROT equate for R/O file protection. ; +; It causes only certain operations (L,P,S,W,A, and Q) ; +; to be allowed on read only files. ; +; ; +; 12/29/82 Rev. 12 M.A. Ulloa : +; Added the creation error message. ; +; ; +; 4/14/83 Rev. 13 N.Panners ; +; Fixed bug in Merge which lost char if not ^Z. ; +; Fixed bug in Copy to correctly check ; +; for full buffers. ; +; ; +; ; +; 7/23/83 Rev. 14 N.Panners ; +; Split EDLIN into two seperate modules to ; +; allow assembly of sources on an IBM PC ; +; EDLIN and EDLPROC ; +; ; +;-----------------------------------------------------------------------; + + +FALSE EQU 0 +TRUE EQU NOT FALSE + +KANJI EQU FALSE + +roprot equ true ;set to TRUE if protection to r/o files + ; desired. +FCB EQU 5CH + +Comand_Line_Length equ 128 +quote_char equ 16h ;quote character = ^V + + +PAGE + + .xlist + INCLUDE DOSSYM.ASM + .list + + +SUBTTL Contants and Data areas +PAGE + +PROMPT EQU "*" +STKSIZ EQU 80H + +CODE SEGMENT PUBLIC +CODE ENDS + +CONST SEGMENT PUBLIC WORD +CONST ENDS + +DATA SEGMENT PUBLIC WORD +DATA ENDS + +DG GROUP CODE,CONST,DATA + +CONST SEGMENT PUBLIC WORD + + EXTRN BADDRV:BYTE,NDNAME:BYTE,bad_vers_err:BYTE,opt_err:BYTE + EXTRN NOBAK:BYTE,BADCOM:BYTE,NEWFIL:BYTE,DEST:BYTE,MRGERR:BYTE + EXTRN NODIR:BYTE,DSKFUL:BYTE,MEMFUL:BYTE,FILENM:BYTE + EXTRN NOSUCH:BYTE,TOOLNG:BYTE,EOF:BYTE,ro_err:byte,bcreat:byte + + PUBLIC TXT1,TXT2,FUDGE,USERDIR,HARDCH + +BAK DB "BAK" + +make db "***MAUlloa/Microsoft/V20***" +rev db "14" + + if roprot ;***** R/O ***** +roflag db 0 ; =1 if file is r/o + endif + +fourth db 0 ;fourth parameter flag + +loadmod db 0 ;Load mode flag, 0 = ^Z marks the + ; end of a file, 1 = viceversa. +hardch dd ? + +the_root db 0 ;root directory flag + +fudge db 0 ;directory changed flag +user_drive db 0 + + +optchar db "-" + +dirchar db "/",0 + +userdir db "/",0 + db (dirstrlen) dup(0) + +fname_buffer db Comand_Line_Length dup(0) +;-----------------------------------------------------------------------; + +TXT1 DB 0,80H DUP (?) +TXT2 DB 0,80H DUP (?) +DELFLG DB 0 + +CONST ENDS + +DATA SEGMENT PUBLIC WORD + + PUBLIC QFLG,FCB2,OLDLEN,PARAM1,PARAM2,OLDDAT,SRCHFLG + PUBLIC COMLINE,NEWLEN,SRCHMOD,CURRENT,LSTFND,NUMPOS + PUBLIC LSTNUM,SRCHCNT,POINTER,START,ENDTXT,USER_DRIVE + +;-----------------------------------------------------------------------; +; Be carefull when adding parameters, they have to follow the +; order in which they apperar here. (this is a table, ergo it +; is indexed thru a pointer, and random additions will cause the +; wrong item to be accessed). Also param4 is known to be the +; count parameter, and known to be the fourth entry in the table +; so it receives special treatment. (See GETNUM) + +PARAM1 DW 1 DUP (?) +PARAM2 DW 1 DUP (?) +PARAM3 DW 1 DUP (?) +PARAM4 DW 1 DUP (?) + +;-----------------------------------------------------------------------; + +PTR_1 DW 1 DUP (?) +PTR_2 DW 1 DUP (?) +PTR_3 DW 1 DUP (?) +COPYSIZ DW 1 DUP (?) +OLDLEN DW 1 DUP (?) +NEWLEN DW 1 DUP (?) +LSTFND DW 1 DUP (?) +LSTNUM DW 1 DUP (?) +NUMPOS DW 1 DUP (?) +SRCHCNT DW 1 DUP (?) +CURRENT DW 1 DUP (?) +POINTER DW 1 DUP (?) +ONE4TH DW 1 DUP (?) +THREE4TH DW 1 DUP (?) +LAST DW 1 DUP (?) +ENDTXT DW 1 DUP (?) +COMLINE DW 1 DUP (?) +LASTLIN DW 1 DUP (?) +COMBUF DB 82H DUP (?) +EDITBUF DB 258 DUP (?) +EOL DB 1 DUP (?) +FCB2 DB 37 DUP (?) +FCB3 DB 37 DUP (?) +fake_fcb db 37 dup (?) ;fake for size figuring +QFLG DB 1 DUP (?) +HAVEOF DB 1 DUP (?) +ENDING DB 1 DUP (?) +SRCHFLG DB 1 DUP (?) +amnt_req dw 1 dup (?) ;ammount of bytes requested to read +olddat db 1 dup (?) ;Used in replace and search, + ; replace by old data flag (1=yes) +srchmod db 1 dup (?) ;Search mode: 1=from current+1 to + ; end of buffer, 0=from beg. of + ; buffer to the end (old way). +MOVFLG DB 1 DUP (?) + DB STKSIZ DUP (?) + +STACK LABEL BYTE +START LABEL WORD + +DATA ENDS + +SUBTTL Main Body +PAGE + +CODE SEGMENT PUBLIC + +ASSUME CS:DG,DS:DG,SS:DG,ES:DG + + EXTRN QUIT:NEAR,QUERY:NEAR,FNDFIRST:NEAR,FNDNEXT:NEAR + EXTRN UNQUOTE:NEAR,LF:NEAR,CRLF:NEAR,OUT:NEAR + EXTRN REST_DIR:NEAR,KILL_BL:NEAR,INT_24:NEAR + EXTRN FINDLIN:NEAR,SHOWNUM:NEAR,SCANLN:NEAR + + if Kanji + EXTRN TESTKANJ:NEAR + endif + + PUBLIC CHKRANGE + + ORG 100H + +EDLIN: + JMP SIMPED + +edl_pad db 0e00h dup (?) + +HEADER DB "Vers 2.14" + +NONAME: + MOV DX,OFFSET DG:NDNAME +ERRJ: JMP xERROR + +SIMPED: + MOV BYTE PTR [ENDING],0 + MOV SP,OFFSET DG:STACK + +;Code to print header +; PUSH AX +; MOV DX,OFFSET DG:HEADER +; MOV AH,STD_CON_STRING_OUTPUT +; INT 21H +; POP AX + +;----- Check Version Number --------------------------------------------; + push ax + mov ah,Get_Version + int 21h + cmp al,2 + jae vers_ok ; version >= 2, enter editor + mov dx,offset dg:bad_vers_err + jmp short errj +;-----------------------------------------------------------------------; + +vers_ok: + +;----- Process Pathnames -----------------------------------------------; + + mov ax,(char_oper shl 8) ;get switch character + int 21h + cmp dl,"/" + jnz slashok ;if not / , then not PC + mov [dirchar],"\" ;in PC, dir separator = \ + mov [userdir],"\" + mov [optchar],"/" ;in PC, option char = / + +slashok: + mov si,81h ;point to cammand line + + call kill_bl + cmp al,13 ;A carriage return? + je noname ;yes, file name missing + + mov di,offset dg:fname_buffer + xor cx,cx ;zero pathname length + +next_char: + stosb ;put patname in buffer + inc cx + lodsb + cmp al,' ' + je xx1 + cmp al,13 ; a CR ? + je name_copied + cmp al,[optchar] ; an option character? + je an_option + jmp short next_char + +xx1: + dec si + call kill_bl + cmp al,[optchar] + jne name_copied + +an_option: + lodsb ;get the option + cmp al,'B' + je b_opt + cmp al,'b' + je b_opt + mov dx,offset dg:opt_err ;bad option specified + jmp xerror + +b_opt: + mov [loadmod],1 + +name_copied: + mov byte ptr dg:[di],0 ;nul terminate the pathname + + if roprot ;***** R/O ***** +;----- Check that file is not R/O --------------------------------------; + push cx ;save character count + mov dx,offset dg:fname_buffer + mov al,0 ;get attributes + mov ah,chmod + int 21h + jc attr_are_ok + and cl,00000001b ;mask all but: r/o + jz attr_are_ok ;if all = 0 then file ok to edit, + mov dg:[roflag],01h ;otherwise: Error (GONG!!!) +attr_are_ok: + pop cx ;restore character count + endif + +;----- Scan for directory ----------------------------------------------; + dec di ;adjust to the end of the pathname + + IF KANJI + mov dx,offset dg: fname_buffer + PUSH DX + PUSH DI + MOV BX,DI + MOV DI,DX +DELLOOP: + CMP DI,BX + Jae GOTDELE + MOV AL,[DI] + INC DI + CALL TESTKANJ + JZ NOTKANJ11 + INC DI + JMP DELLOOP + +NOTKANJ11: + cmp al,dg:[dirchar] + JNZ DELLOOP + MOV DX,DI ;Point to char after '/' + DEC DX + DEC DX ;Point to char before '/' + JMP DELLOOP + +GOTDELE: + MOV DI,DX + POP AX ;Initial DI + POP DX + SUB AX,DI ;Distance moved + SUB CX,AX ;Set correct CX + CMP DX,DI + JB sj1 ;Found a pathsep + JA sj2 ;Started with a pathsep, root + MOV AX,[DI] + CALL TESTKANJ + JNZ same_dirj + XCHG AH,AL + cmp al,dg:[dirchar] + jz sj1 ;One character directory +same_dirj: + ELSE + mov al,dg:[dirchar] ;get directory separator character + std ;scan backwards + repnz scasb ;(cx has the pathname length) + cld ;reset direction, just in case + jz sj1 + ENDIF + + jmp same_dir ;no dir separator char. found, the + ; file is in the current directory + ; of the corresponding drive. Ergo, + ; the FCB contains the data already. + +sj1: + jcxz sj2 ;no more chars left, it refers to root + cmp byte ptr [di],':' ;is the prvious character a disk def? + jne not_root +sj2: + mov dg:[the_root],01h ;file is in the root +not_root: + inc di ;point to dir separator char. + mov al,0 + stosb ;nul terminate directory name + pop ax + push di ;save pointer to file name + mov dg:[fudge],01h ;remember that the current directory + ; has been changed. + +;----- Save current directory for exit ---------------------------------; + mov ah,get_default_drive ;save current drive + int 21h + mov dg:[user_drive],al + + mov dl,byte ptr ds:[fcb] ;get specified drive if any + or dl,dl ;default disk? + jz same_drive + dec dl ;adjust to real drive (a=0,b=1,...) + mov ah,set_default_drive ;change disks + int 21h + cmp al,-1 ;error? + jne same_drive + mov dx,offset dg:baddrv + jmp xerror + +same_drive: + mov ah,get_default_dpb + int 21h + +assume ds:nothing + + cmp al,-1 ;bad drive? (should always be ok) + jne drvisok + mov dx,offset dg:baddrv + jmp xerror + +drvisok: + cmp [bx.dpb_current_dir],0 + je curr_is_root + mov si,bx + add si,dpb_dir_text + mov di,offset dg:userdir + 1 + +dir_save_loop: + lodsb + stosb + or al,al + jnz dir_save_loop + +curr_is_root: + push cs + pop ds + +assume ds:dg + + +;----- Change directories ----------------------------------------------; + cmp [the_root],01h + mov dx,offset dg:[dirchar] ;assume the root + je sj3 + mov dx,offset dg:[fname_buffer] +sj3: + mov ah,chdir ;change directory + int 21h + mov dx,offset dg:baddrv + jnc no_errors + jmp xerror +no_errors: + +;----- Set Up int 24 intercept -----------------------------------------; + + mov ax,(get_interrupt_vector shl 8) or 24h + int 21h + mov word ptr [hardch],bx + mov word ptr [hardch+2],es + mov ax,(set_interrupt_vector shl 8) or 24h + mov dx,offset dg:int_24 + int 21h + push cs + pop es + +;----- Parse filename to FCB -------------------------------------------; + pop si + mov di,fcb + mov ax,(parse_file_descriptor shl 8) or 1 + int 21h + push ax + +;-----------------------------------------------------------------------; + +same_dir: + pop ax + OR AL,AL + MOV DX,OFFSET DG:BADDRV + jz sj4 + jmp xerror +sj4: + CMP BYTE PTR DS:[FCB+1]," " + jnz sj5 + jmp noname +sj5: + MOV SI,OFFSET DG:BAK + MOV DI,FCB+9 + MOV CX,3 + ;File must not have .BAK extension + REPE CMPSB + JZ NOTBAK + ;Open input file + MOV AH,FCB_OPEN + MOV DX,FCB + INT 21H + MOV [HAVEOF],AL + OR AL,AL + JZ HAVFIL + +;----- Check that file is not a directory ------------ + mov ah,fcb_create + mov dx,fcb + int 21h + or al,al + jz sj50 ;no error found + mov dx,offset dg:bcreat ;creation error + jmp xerror +sj50: + mov ah,fcb_close ;no error, close the file + mov dx,fcb + int 21h + mov ah,fcb_delete ;delete the file + mov dx,fcb + int 21h + +;----------------------------------------------------- + + MOV DX,OFFSET DG:NEWFIL + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +HAVFIL: + MOV SI,FCB + MOV DI,OFFSET DG:FCB2 + MOV CX,9 + REP MOVSB + MOV AL,"$" + STOSB + STOSB + STOSB +MAKFIL: + ;Create .$$$ file to make sure directory has room + MOV DX,OFFSET DG:FCB2 + MOV AH,FCB_CREATE + INT 21H + OR AL,AL + JZ SETUP + CMP BYTE PTR [DELFLG],0 + JNZ NOROOM + CALL DELBAK + JMP MAKFIL +NOROOM: + MOV DX,OFFSET DG:NODIR + JMP xERROR +NOTBAK: + MOV DX,OFFSET DG:NOBAK + JMP xERROR +SETUP: + XOR AX,AX + MOV WORD PTR DS:[FCB+fcb_RR],AX ;Set RR field to zero + MOV WORD PTR DS:[FCB+fcb_RR+2],AX + MOV WORD PTR [FCB2+fcb_RR],AX + MOV WORD PTR [FCB2+fcb_RR+2],AX + INC AX + MOV WORD PTR DS:[FCB+fcb_RECSIZ],AX ;Set record length to 1 + MOV WORD PTR [FCB2+fcb_RECSIZ],AX + MOV DX,OFFSET DG:START + MOV DI,DX + MOV AH,SET_DMA + INT 21H + MOV CX,DS:[6] + DEC CX + MOV [LAST],CX + TEST BYTE PTR [HAVEOF],-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 + ;Read in input file + MOV DX,FCB + MOV AH,FCB_RANDOM_READ_BLOCK + mov [amnt_req],cx ;save ammount of chars requested + INT 21H + CALL SCANEOF + ADD DI,CX ;Point to last byte +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 [PARAM1],1 + TEST BYTE PTR [HAVEOF],-1 + JNZ COMMAND + CALL APPEND + +COMMAND: + MOV SP, OFFSET DG:STACK + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H + MOV DX,OFFSET DG:ABORTCOM + INT 21H + MOV AL,PROMPT + CALL OUT + MOV DX,OFFSET DG:COMBUF + MOV AH,STD_CON_STRING_INPUT + INT 21H + MOV [COMLINE],OFFSET DG:COMBUF + 2 + MOV AL,10 + CALL OUT +PARSE: + MOV [PARAM2],0 + MOV [PARAM3],0 + MOV [PARAM4],0 + mov [fourth],0 ;reset the fourth parameter flag + MOV BYTE PTR [QFLG],0 + MOV SI,[COMLINE] + MOV BP,OFFSET DG:PARAM1 + XOR DI,DI +CHKLP: + CALL GETNUM + MOV [BP+DI],DX + INC DI + INC DI + CALL SKIP1 + CMP AL,"," + JNZ CHKNXT + INC SI +CHKNXT: + DEC SI + CMP DI,8 + JB CHKLP + CALL SKIP + CMP AL,"?" + JNZ DISPATCH + MOV [QFLG],AL + CALL SKIP +DISPATCH: + CMP AL,5FH + JBE UPCASE + AND AL,5FH +UPCASE: + MOV DI,OFFSET DG:COMTAB + MOV CX,NUMCOM + REPNE SCASB + JNZ COMERR + MOV BX,CX + MOV AX,[PARAM2] + OR AX,AX + JZ PARMOK + CMP AX,[PARAM1] + JB COMERR ;Param. 2 must be >= param 1 +PARMOK: + MOV [COMLINE],SI + + if roprot ;***** R/O ***** + cmp [roflag],01 ;file r/o? + jne paramok2 + cmp byte ptr [bx+rotable],01 ;operation allowed? + je paramok2 + mov dx,offset dg:ro_err ;error + jmp short comerr1 +paramok2: + endif + + SHL BX,1 + CALL [BX+TABLE] +COMOVER: + MOV SI,[COMLINE] + CALL SKIP + 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 + +SKIP: + LODSB +SKIP1: + CMP AL," " + JZ SKIP +RET1: RET + +CHKRANGE: + CMP [PARAM2],0 + JZ RET1 + CMP BX,[PARAM2] + JBE RET1 +COMERR: + MOV DX,OFFSET DG:BADCOM +COMERR1: + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + JMP COMMAND + + +GETNUM: + CALL SKIP + 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 + JZ RET1 + OR DX,DX + JZ COMERR ;Don't allow zero as a parameter + RET + +CURLIN: + cmp [fourth],1 ;the fourth parameter? + je comerra ;yes, an error + MOV DX,[CURRENT] + LODSB + RET +MAXLIN: + cmp [fourth],1 ;the fourth parameter? + je comerra ;yes, an error + MOV DX,-2 + LODSB + RET +FORLIN: + cmp [fourth],1 ;the fourth parameter? + je comerra ;yes, an error + CALL GETNUM + ADD DX,[CURRENT] + RET +BACKLIN: + cmp [fourth],1 ;the fourth parameter? + je comerra ;yes, an error + CALL GETNUM + MOV BX,[CURRENT] + SUB BX,DX + jns sk2 ;if below beg of buffer then default to the + mov bx,1 ; beg of buffer (line1) +sk2: + MOV DX,BX + RET + +comerra: + jmp comerr + + +COMTAB DB "QTCMWASRDLPIE;",13 + +NUMCOM EQU $-COMTAB + +;-----------------------------------------------------------------------; +; Carefull changing the order of the next two tables. They are +; linked and chnges should be be to both. + +TABLE DW NOCOM ;No command--edit line + DW NOCOM + DW ENDED + DW INSERT + DW PAGE + DW LIST + DW DELETE + dw replac_from_curr ;replace from current+1 line + dw search_from_curr ;search from current+1 line + DW APPEND + DW EWRITE + DW MOVE + DW COPY + DW MERGE + + if roprot ;***** R/O ***** + DW QUIT1 + else + DW QUIT + endif + + if roprot ;***** R/O ***** +;-----------------------------------------------------------------------; +; If = 1 then the command can be executed with a file that +; is r/o. If = 0 the command can not be executed, and error. + +ROTABLE db 0 ;NOCOM + db 0 ;NOCOM + db 0 ;ENDED + db 0 ;INSERT + db 1 ;PAGE + db 1 ;LIST + db 0 ;DELETE + db 0 ;replac_from_curr + db 1 ;search_from_curr + db 1 ;APPEND + db 1 ;EWRITE + db 0 ;MOVE + db 0 ;COPY + db 0 ;MERGE + db 1 ;QUIT + +;-----------------------------------------------------------------------; + endif + + if roprot ;***** R/O ***** +quit1: + cmp [roflag],01 ;are we in r/o mode? + jne q3 ;no query.... + MOV DX,OFFSET DG:FCB2 ;yes, quit without query. + MOV AH,FCB_CLOSE + INT 21H + MOV AH,FCB_DELETE + INT 21H + call rest_dir ;restore directory if needed + INT 20H +q3: + call quit + endif + +SCANEOF: + cmp [loadmod],0 + je sj52 + +;----- Load till physical end of file + cmp cx,word ptr[amnt_req] + jb sj51 + xor al,al + inc al ;reset zero flag + ret +sj51: + jcxz sj51b + push di ;get rid of any ^Z at the end of the file + add di,cx + dec di ;points to last char + cmp byte ptr [di],1ah + pop di + jne sj51b + dec cx +sj51b: + xor al,al ;set zero flag + call check_end ;check that we have a CRLF pair at the end + ret + +;----- Load till first ^Z is found +sj52: + PUSH DI + PUSH CX + MOV AL,1AH + or cx,cx + jz not_found ;skip with zero flag set + REPNE SCASB ;Scan for end of file mark + jnz not_found + LAHF ;Save flags momentarily + inc cx ;include the ^Z + SAHF ;Restore flags +not_found: + mov di,cx ;not found at the end + POP CX + LAHF ;Save flags momentarily + SUB CX,DI ;Reduce byte count if EOF found + SAHF ;Restore flags + POP DI + call check_end ;check that we have a CRLF pair at the end + +RET2: RET + + +;----------------------------------------------------------------------- +; If the end of file was found, then check that the last character +; in the file is a LF. If not put a CRLF pair in. + +check_end: + jnz not_end ;end was not reached + pushf ;save return flag + push di ;save pointer to buffer + add di,cx ;points to one past end on text + dec di ;points to last character + cmp di,offset dg:start + je check_no + cmp byte ptr[di],0ah ;is a LF the last character? + je check_done ;yes, exit +check_no: + mov byte ptr[di+1],0dh ;no, put a CR + inc cx ;one more char in text + mov byte ptr[di+2],0ah ;put a LF + inc cx ;another character at the end +check_done: + pop di + popf +not_end: + ret + + + +NOMOREJ:JMP NOMORE + +APPEND: + TEST BYTE PTR [HAVEOF],-1 + JNZ NOMOREJ + MOV DX,[ENDTXT] + CMP [PARAM1],0 ;See if parameter is missing + JNZ PARMAPP + CMP DX,[THREE4TH] ;See if already 3/4ths full + JAE RET2 ;If so, then done already +PARMAPP: + MOV DI,DX + MOV AH,SET_DMA + INT 21H + MOV CX,[LAST] + SUB CX,DX ;Amount of memory available + jnz sj53 + jmp memerr +sj53: + MOV DX,FCB + mov [amnt_req],cx ;save ammount of chars requested + MOV AH,FCB_RANDOM_READ_BLOCK + INT 21H ;Fill memory with file data + MOV [HAVEOF],AL + PUSH CX ;Save actual byte count + CALL SCANEOF + JNZ NOTEND + MOV BYTE PTR [HAVEOF],1 ;Set flag if 1AH found in file +NOTEND: + XOR DX,DX + MOV BX,[PARAM1] + OR BX,BX + JNZ COUNTLN + MOV AX,DI + ADD AX,CX ;First byte after loaded text + CMP AX,[THREE4TH] ;See if we made 3/4 full + JBE COUNTLN + MOV DI,[THREE4TH] + MOV CX,AX + SUB CX,DI ;Length remaining over 3/4 + MOV BX,1 ;Look for one more line +COUNTLN: + CALL SCANLN ;Look for BX lines + CMP [DI-1],AL ;Check for full line + JZ FULLN + STD + DEC DI + MOV CX,[LAST] + REPNE SCASB ;Scan backwards for last line + INC DI + INC DI + DEC DX + CLD +FULLN: + POP CX ;Actual amount read + MOV WORD PTR [DI],1AH ;Place EOF after last line + SUB CX,DI + XCHG DI,[ENDTXT] + ADD DI,CX ;Amount of file read but not used + SUB WORD PTR DS:[FCB+fcb_RR],DI ;Adjust RR field in case end of file + SBB WORD PTR DS:[FCB+fcb_RR+2],0 ; was not reached + CMP BX,DX + JNZ EOFCHK + MOV BYTE PTR [HAVEOF],0 + RET +NOMORE: + MOV DX,OFFSET DG:EOF + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +RET3: RET +EOFCHK: + TEST BYTE PTR [HAVEOF],-1 + JNZ NOMORE + TEST BYTE PTR [ENDING],-1 + JNZ RET3 ;Suppress memory error during End + JMP MEMERR + +EWRITE: + MOV BX,[PARAM1] + OR BX,BX + JNZ WRT + MOV CX,[ONE4TH] + MOV DI,[ENDTXT] + SUB DI,CX ;Write everything in front of here + JBE RET3 + CMP DI,OFFSET DG:START ;See if there's anything to write + JBE RET3 + XOR DX,DX + MOV BX,1 ;Look for one more line + CALL SCANLN + JMP SHORT WRTADD +WRT: + INC BX + CALL FINDLIN +WRTADD: + CMP BYTE PTR [DELFLG],0 + JNZ WRTADD1 + PUSH DI + CALL DELBAK ;Want to delete the .BAK file + ;as soon as the first write occurs + POP DI +WRTADD1: + MOV CX,DI + MOV DX,OFFSET DG:START + SUB CX,DX ;Amount to write + JZ RET3 + MOV AH,SET_DMA + INT 21H + MOV DX,OFFSET DG:FCB2 + MOV AH,FCB_RANDOM_WRITE_BLOCK + INT 21H + OR AL,AL + JNZ WRTERR + MOV SI,DI + MOV DI,OFFSET DG:START + MOV [POINTER],DI + MOV CX,[ENDTXT] + SUB CX,SI + INC CX ;Amount of text remaining + REP MOVSB + DEC DI ;Point to EOF + MOV [ENDTXT],DI + MOV [CURRENT],1 + RET + +WRTERR: + MOV AH,FCB_CLOSE + INT 21H + MOV DX,OFFSET DG:DSKFUL +xERROR: + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +;----------------------------------------------------------------------- + call rest_dir ;restore to the proper directory +;----------------------------------------------------------------------- + INT 32 + +RET$5: RET + +PAGE: + xor bx,bx ;get last line in the buffer + call findlin + mov [lastlin],dx + + mov bx,[param1] + or bx,bx ;was it specified? + jnz frstok ;yes, use it + mov bx,[current] + cmp bx,1 ;if current line =1 start from there + je frstok + inc bx ;start from current+1 line +frstok: + cmp bx,[lastlin] ;check that we are in the buffer + ja ret$5 ;if not just quit +infile: + mov dx,[param2] + or dx,dx ;was param2 specified? + jnz scndok ;yes,.... + mov dx,bx ;no, take the end line to be the + add dx,22 ; start line + 23 +scndok: + inc dx + cmp dx,[lastlin] ;check that we are in the buffer + jbe infile2 + mov dx,[lastlin] ;we are not, take the last line as end +infile2: + cmp dx,bx ;is param1 < param2 ? + jbe ret$5 ;yes, no backwards listing, quit + push dx ;save the end line + push bx ;save start line + mov bx,dx ;set the current line + dec bx + call findlin + mov [pointer],di + mov [current],dx + pop bx ;restore start line + call findlin ;get pointer to start line + mov si,di ;save pointer + pop di ;get end line + sub di,bx ;number of lines + jmp short display + + +LIST: + MOV BX,[PARAM1] + OR BX,BX + JNZ CHKP2 + MOV BX,[CURRENT] + SUB BX,11 + JA CHKP2 + MOV BX,1 +CHKP2: + CALL FINDLIN + JNZ RET7 + MOV SI,DI + MOV DI,[PARAM2] + INC DI + SUB DI,BX + JA DISPLAY + MOV DI,23 + JMP SHORT DISPLAY + + +DISPONE: + MOV DI,1 + +DISPLAY: + +; Inputs: +; BX = Line number +; SI = Pointer to text buffer +; DI = No. of lines +; Function: +; Ouputs specified no. of line to terminal, each +; with leading line number. +; Outputs: +; BX = Last line output. +; All registers destroyed. + + MOV CX,[ENDTXT] + SUB CX,SI + JZ RET7 + MOV BP,[CURRENT] +DISPLN: + PUSH CX + CALL SHOWNUM + POP CX +OUTLN: + LODSB + CMP AL," " + JAE SEND + CMP AL,10 + JZ SEND + CMP AL,13 + JZ SEND + CMP AL,9 + JZ SEND + PUSH AX + MOV AL,"^" + CALL OUT + POP AX + OR AL,40H +SEND: + CALL OUT + CMP AL,10 + LOOPNZ OUTLN + JCXZ RET7 + INC BX + DEC DI + JNZ DISPLN + DEC BX +RET7: RET + +LOADBUF: + MOV DI,2 + OFFSET DG:EDITBUF + MOV CX,255 + MOV DX,-1 +LOADLP: + LODSB + STOSB + INC DX + CMP AL,13 + LOOPNZ LOADLP + MOV [EDITBUF+1],DL + JZ RET7 +TRUNCLP: + LODSB + INC DX + CMP AL,13 + JNZ TRUNCLP + DEC DI + STOSB + RET + +NOTFNDJ:JMP NOTFND + +replac_from_curr: + mov byte ptr [srchmod],1 ;search from curr+1 line + jmp short sj6 + +REPLAC: + mov byte ptr [srchmod],0 ;search from beg of buffer +sj6: + MOV BYTE PTR [SRCHFLG],0 + CALL FNDFIRST + JNZ NOTFNDJ +REPLP: + MOV SI,[NUMPOS] + CALL LOADBUF ;Count length of line + SUB DX,[OLDLEN] + MOV CX,[NEWLEN] + ADD DX,CX ;Length of new line + CMP DX,254 + JA TOOLONG + MOV BX,[LSTNUM] + PUSH DX + CALL SHOWNUM + POP DX + MOV CX,[LSTFND] + MOV SI,[NUMPOS] + SUB CX,SI ;Get no. of char on line before change + DEC CX + CALL OUTCNT ;Output first part of line + PUSH SI + MOV SI,1+ OFFSET DG:TXT2 + MOV CX,[NEWLEN] + CALL OUTCNT ;Output change + POP SI + ADD SI,[OLDLEN] ;Skip over old stuff in line + MOV CX,DX ;DX=no. of char left in line + ADD CX,2 ;Include CR/LF + CALL OUTCNT ;Output last part of line + CALL QUERY ;Check if change OK + JNZ REPNXT + CALL PUTCURS + MOV DI,[LSTFND] + DEC DI + MOV SI,1+ OFFSET DG:TXT2 + MOV DX,[OLDLEN] + MOV CX,[NEWLEN] + DEC CX + ADD [LSTFND],CX ;Bump pointer beyond new text + INC CX + DEC DX + SUB [SRCHCNT],DX ;Old text will not be searched + JAE SOMELEFT + MOV [SRCHCNT],0 +SOMELEFT: + INC DX + CALL REPLACE +REPNXT: + CALL FNDNEXT + JNZ RET8 + JMP REPLP + +OUTCNT: + JCXZ RET8 +OUTLP: + LODSB + CALL OUT + DEC DX + LOOP OUTLP +RET8: RET + +TOOLONG: + MOV DX,OFFSET DG:TOOLNG + JMP SHORT PERR + +search_from_curr: + mov byte ptr [srchmod],1 ;search from curr+1 line + jmp short sj7 + +SEARCH: + mov byte ptr [srchmod],0 ;search from beg of buffer +sj7: + MOV BYTE PTR [SRCHFLG],1 + CALL FNDFIRST + JNZ NOTFND +SRCH: + MOV BX,[LSTNUM] + MOV SI,[NUMPOS] + CALL DISPONE + MOV DI,[LSTFND] + MOV CX,[SRCHCNT] + MOV AL,10 + REPNE SCASB + JNZ NOTFND + MOV [LSTFND],DI + MOV [NUMPOS],DI + MOV [SRCHCNT],CX + INC [LSTNUM] + CALL QUERY + JZ PUTCURS + CALL FNDNEXT + JZ SRCH +NOTFND: + MOV DX,OFFSET DG:NOSUCH +PERR: + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + RET + +PUTCURS: + MOV BX,[LSTNUM] + DEC BX ;Current <= Last matched line + CALL FINDLIN + MOV [CURRENT],DX + MOV [POINTER],DI +RET9: RET + +DELETE: + MOV BX,[PARAM1] + OR BX,BX + JNZ DELFIN1 + MOV BX,[CURRENT] + CALL CHKRANGE +DELFIN1: + CALL FINDLIN + JNZ RET9 + PUSH BX + PUSH DI + MOV BX,[PARAM2] + OR BX,BX + JNZ DELFIN2 + MOV BX,DX +DELFIN2: + INC BX + CALL FINDLIN + MOV DX,DI + POP DI + SUB DX,DI + JBE COMERRJ + POP [CURRENT] + MOV [POINTER],DI + XOR CX,CX + JMP SHORT REPLACE + +COMERRJ:JMP COMERR + + +NOCOM: + DEC [COMLINE] + MOV BX,[PARAM1] + OR BX,BX + JNZ HAVLIN + MOV BX,[CURRENT] + INC BX ;Default is current line plus one + CALL CHKRANGE +HAVLIN: + CALL FINDLIN + MOV SI,DI + MOV [CURRENT],DX + MOV [POINTER],SI + jz sj12 + ret +sj12: + CMP SI,[ENDTXT] + JZ RET12 + CALL LOADBUF + MOV [OLDLEN],DX + MOV SI,[POINTER] + CALL DISPONE + CALL SHOWNUM + MOV AH,STD_CON_STRING_INPUT ;Get input buffer + MOV DX,OFFSET DG:EDITBUF + INT 21H + MOV AL,10 + CALL OUT + MOV CL,[EDITBUF+1] + MOV CH,0 + JCXZ RET12 + MOV DX,[OLDLEN] + MOV SI,2 + OFFSET DG:EDITBUF +;----------------------------------------------------------------------- + call unquote ;scan for quote chars if any +;----------------------------------------------------------------------- + MOV DI,[POINTER] + +REPLACE: + +; Inputs: +; CX = Length of new text +; DX = Length of original text +; SI = Pointer to new text +; DI = Pointer to old text in buffer +; Function: +; New text replaces old text in buffer and buffer +; size is adjusted. CX or DX may be zero. +; CX, SI, DI all destroyed. No other registers affected. + + CMP CX,DX + JZ COPYIN + PUSH SI + PUSH DI + PUSH CX + MOV SI,DI + ADD SI,DX + ADD DI,CX + MOV AX,[ENDTXT] + SUB AX,DX + ADD AX,CX + CMP AX,[LAST] + JAE MEMERR + XCHG AX,[ENDTXT] + MOV CX,AX + SUB CX,SI + CMP SI,DI + JA DOMOV + ADD SI,CX + ADD DI,CX + STD +DOMOV: + INC CX + + REP MOVSB + CLD + POP CX + POP DI + POP SI +COPYIN: + REP MOVSB +RET12: RET + +MEMERR: + MOV DX,OFFSET DG:MEMFUL + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + JMP COMMAND + +MOVERR: + MOV DX,OFFSET DG:BADCOM +ERRORJ: + JMP COMERR + +MOVE: + MOV BYTE PTR [MOVFLG],1 + JMP SHORT BLKMOVE +COPY: + MOV BYTE PTR [MOVFLG],0 + +BLKMOVE: + MOV BX,[PARAM3] ;Third parameter must be specified + OR BX,BX + MOV DX,OFFSET DG:DEST + JZ ERRORJ + MOV BX,[PARAM1] ;Get the first parameter + OR BX,BX ;Not specified? + JNZ NXTARG + MOV BX,[CURRENT] ;Defaults to the current line + CALL CHKRANGE + MOV [PARAM1],BX ;Save it since current line may change + NXTARG: + CALL FINDLIN ;Get a pointer to the line + MOV [PTR_1],DI ;Save it + MOV BX,[PARAM2] ;Get the second parameter + OR BX,BX ;Not specified? + JNZ HAVARGS + MOV BX,[CURRENT] ;Defaults to the current line + MOV [PARAM2],BX ;Save it since current line may change +HAVARGS: + ;Parameters must not overlap + MOV DX,[PARAM3] + CMP DX,[PARAM1] + JBE NOERROR + CMP DX,[PARAM2] + JBE MOVERR +NOERROR: + INC BX ;Get pointer to line Param2+1 + CALL FINDLIN + MOV SI,DI + MOV [PTR_2],SI ;Save it + MOV CX,DI + MOV DI,[PTR_1] ;Restore pointer to line Param1 + SUB CX,DI ;Calculate number of bytes to copy + MOV [COPYSIZ],CX ;Save in COPYSIZ + PUSH CX ;And on the stack + MOV AX,[PARAM4] ;Is count specified? + OR AX,AX + JZ MEM_CHECK + MUL [COPYSIZ] + OR DX,DX + JZ COPYSIZ_OK + JMP MEMERR +COPYSIZ_OK: + MOV CX,AX + MOV [COPYSIZ],CX +MEM_CHECK: + MOV AX,[ENDTXT] + MOV DI,[LAST] + SUB DI,AX + CMP DI,CX + JAE HAV_ROOM + JMP MEMERR +HAV_ROOM: + MOV BX,[PARAM3] + PUSH BX + CALL FINDLIN + MOV [PTR_3],DI + MOV CX,[ENDTXT] + SUB CX,DI + INC CX + MOV SI,[ENDTXT] + MOV DI,SI + ADD DI,[COPYSIZ] + MOV [ENDTXT],DI + STD + REP MOVSB + CLD + POP BX + CMP BX,[PARAM1] + JB GET_PTR_2 + MOV SI,[PTR_1] + JMP SHORT COPY_TEXT +GET_PTR_2: + MOV SI,[PTR_2] +COPY_TEXT: + MOV BX,[PARAM4] + MOV DI,[PTR_3] + POP CX + MOV [COPYSIZ],CX +COPY_TEXT_1: + REP MOVSB + DEC BX + CMP BX,0 + JLE MOV_CHK + MOV [PARAM4],BX + SUB SI,[COPYSIZ] + MOV CX,[COPYSIZ] + JMP SHORT COPY_TEXT_1 +MOV_CHK: + CMP BYTE PTR[MOVFLG],0 + JZ COPY_DONE + MOV DI,[PTR_1] + MOV SI,[PTR_2] + MOV BX,[PARAM3] + CMP BX,[PARAM1] + JAE DEL_TEXT + ADD DI,[COPYSIZ] + ADD SI,[COPYSIZ] +DEL_TEXT: + MOV CX,[ENDTXT] + SUB CX,SI + REP MOVSB + MOV [ENDTXT],DI + MOV CX,[PARAM2] + SUB CX,[PARAM1] + MOV BX,[PARAM3] + SUB BX,CX + JNC MOVE_DONE +COPY_DONE: + MOV BX,[PARAM3] +MOVE_DONE: + CALL FINDLIN + MOV [POINTER],DI + MOV [CURRENT],BX + RET + + +MOVEFILE: + MOV CX,[ENDTXT] ;Get End-of-text marker + MOV SI,CX + SUB CX,DI ;Calculate number of bytes to copy + INC CX + 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 + RET + +NAMERR: + JMP COMERR1 + + +MERGE: + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 1 + MOV DI,OFFSET DG:FCB3 + INT 21H + OR AL,AL + MOV DX,OFFSET DG:BADDRV + JNZ NAMERR + MOV [COMLINE],SI + MOV DX,OFFSET DG:FCB3 + MOV AH,FCB_OPEN + INT 21H + OR AL,AL + MOV DX,OFFSET DG:FILENM + JNZ NAMERR + 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] + CALL MOVEFILE + ;Set DMA address for reading in new file + MOV DX,[POINTER] + MOV AH,SET_DMA + INT 21H + XOR AX,AX + MOV WORD PTR DS:[FCB3+fcb_RR],AX + MOV WORD PTR DS:[FCB3+fcb_RR+2],AX + INC AX + MOV WORD PTR DS:[FCB3+fcb_RECSIZ],AX + MOV DX,OFFSET DG:FCB3 + MOV CX,[ENDTXT] + SUB CX,[POINTER] + MOV AH,FCB_RANDOM_READ_BLOCK + INT 21H + CMP AL,1 + JZ FILEMRG + MOV DX,OFFSET DG:MRGERR + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + MOV CX,[POINTER] + JMP SHORT RESTORE +FILEMRG: + ADD CX,[POINTER] + MOV SI,CX + DEC SI + LODSB + CMP AL,1AH + JNZ RESTORE + DEC CX +RESTORE: + MOV DI,CX + MOV SI,[ENDTXT] + INC SI + MOV CX,[LAST] + SUB CX,SI + REP MOVSB + MOV [ENDTXT],DI + MOV BYTE PTR [DI],1AH + MOV DX,OFFSET DG:FCB3 + MOV AH,FCB_CLOSE + INT 21H + MOV DX,OFFSET DG:START + MOV AH,SET_DMA + INT 21H + RET + + +INSERT: + 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] + 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 SS,AX + MOV SP,OFFSET DG:STACK + STI + CALL CRLF + CALL ENDINS + JMP COMOVER + +ENDINS: + CALL END_INS + RET + +END_INS: + MOV BP,[ENDTXT] + MOV DI,[POINTER] + MOV SI,BP + INC SI + MOV CX,[LAST] + 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 + RET + +FILLBUF: + MOV [PARAM1],-1 ;Read in max. no of lines + CALL APPEND +ENDED: +;Write text out to .$$$ file + 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 AH,SET_DMA + INT 21H + MOV CX,1 + MOV DX,OFFSET DG:FCB2 + MOV AH,FCB_RANDOM_WRITE_BLOCK + INT 21H ;Write end-of-file byte +;Close .$$$ file + MOV AH,FCB_CLOSE + INT 21H + MOV SI,FCB + LEA DI,[SI+fcb_FILSIZ] + MOV DX,SI + MOV CX,9 + REP MOVSB + MOV SI,OFFSET DG:BAK + MOVSW + MOVSB +;Rename original file .BAK + MOV AH,FCB_RENAME + INT 21H + MOV SI,FCB + MOV DI,OFFSET DG:FCB2 + fcb_FILSIZ + MOV CX,6 + REP MOVSW +;Rename .$$$ file to original name + MOV DX,OFFSET DG:FCB2 + INT 21H + call rest_dir ;restore directory if needed + INT 20H + +ABORTCOM: + MOV AX,CS + MOV DS,AX + MOV ES,AX + MOV SS,AX + MOV SP,OFFSET DG:STACK + STI + CALL CRLF + JMP COMMAND + +DELBAK: + MOV BYTE PTR [DELFLG],1 + MOV DI,9+OFFSET DG:FCB2 + MOV SI,OFFSET DG:BAK + MOVSW + MOVSB + ;Delete old backup file (.BAK) + MOV AH,FCB_DELETE + MOV DX,OFFSET DG:FCB2 + INT 21H + MOV DI,9+OFFSET DG:FCB2 + MOV AL,"$" + STOSB + STOSB + STOSB + RET + +CODE ENDS + END EDLIN + \ No newline at end of file diff --git a/EDLMES.ASM b/EDLMES.ASM new file mode 100644 index 0000000000000000000000000000000000000000..f49ed960326154ace552463d6c34087205d067c2 GIT binary patch literal 3200 zcmY#@f|AUVoKyt`1y>gzPd^3U)Z*gA^weTrE?zEcUFra9UM_2>Wt37#M!DqYr7EQ5 z7b%3L78NTP=@}R(XcVQEDOhSMBvmRnCKl!ADFmff=H=(46l1d%$*9nRl*AHf39DC&f|t~DqQ-5h;_T|u!M7z%cd0WVib zP$)=5!4)dx=O3Z~Rt8ef%LP`ZprD{vk&{_mg5Z1lIs1gVxGK2#2M0&`>Ny7cBINWS zN_roQBZIX@(&GAP*4Cl zPsiEcFE~U8q!i*p7gy}gFEcG0R;skLl1-?%m&8@ z9SxX%PrrcBka#zr&|nXRU=JS!3rz+8AO#dzgaJsVf}IK{tb=Ei6 z{anCG9DQ_5-H;sO>PmgnF+iuyO@Ie^5Xni9^*xL?N<-LJpKd5GKIA z?g2_V@yBKcC63M$EuHfti&V332Awde!pnMUlqicvT z0v3`%t|68PQJ9xdl9*$#H>Qd~kirm-3IHWe1qB7i2!xokqmK_LWFbic!~)>}e`vx& zRtZf!jy^hu#vnydZ0(#_RFs*Ro~lrkT2fk+r;wYPm{+V&392TcN))gMBcbGr8tBNX zE0uV;K(bZ}3JO84A)wd=6;B}RV8s`>q{3BtBK!|6ffbw_U0i~~bo^ZW9DQANk`hzm z%TkMq<5P=@bn**Iz_g#glOs|T!*u%jyLblaxCDEYT>ag2TwH@gbbN!{U4w#jit@p>CM6f8CYFGF z2yvo=w9F z0uqZ7b5l!Fi$JO%K2X3^m0yrrlvt9PpJ$~Ir0)-Qwvvvav5ujEjuJ>C#Lq|?!A^Gu z1w>|ko`P#pQGOAM23{_3Ie83!#P2k8w z*5;S5P?VpatB{$8RJMQ`QlPK}>3~Eul0`0=#n}pJr8zmex(ek*nI)+TAbXSZa|?1( zOCUiDNfih^P_KIC6_=)^WhQ5)=9MVqrsn1sRigOH4V;P)+LXY-05Ux-zceoeMJ*($ zA*prED=Df}NW};$NMb}%=$Bd!4h|IKAW0KhRep&Armc>_-r)F$CrN)jZ#{bjP&h$S zHIfNFnR%%SCHeUZIr(|%D3-bUyP=xmnwO%GpQezRS5R7l={8VZ4pI-d)G;Z)2pZEG zk@|j`5C?$r5{fckP^yO{`AUV9)Z&uNJa8gZ$N{-5uQWF)6*W~sG9r=}{6GmRFTXTB x1CmHe@)dGZi_%jSN-|OvQu9hOi&8P23u@T;fomE_(FAf62)p{Z@NzNW0001%$cg{} literal 0 HcmV?d00001 diff --git a/EDLPROC.ASM b/EDLPROC.ASM new file mode 100644 index 0000000..0128b1d --- /dev/null +++ b/EDLPROC.ASM @@ -0,0 +1,531 @@ + + +FALSE EQU 0 +TRUE EQU NOT FALSE + +KANJI EQU FALSE + +roprot equ FALSE ;set to TRUE if protection to r/o files + ; desired. +FCB EQU 5CH + +Comand_Line_Length equ 128 +quote_char equ 16h ;quote character = ^V + + +PAGE + + .xlist + INCLUDE DOSSYM.ASM + .list + + +SUBTTL Contants and Data areas +PAGE + +PROMPT EQU "*" +STKSIZ EQU 80H + +CODE SEGMENT PUBLIC +CODE ENDS + +CONST SEGMENT PUBLIC WORD + + EXTRN TXT1:BYTE,TXT2:BYTE,FUDGE:BYTE,HARDCH:DWORD,USERDIR:BYTE + +CONST ENDS + +DATA SEGMENT PUBLIC WORD + + EXTRN OLDLEN:WORD,OLDDAT:BYTE,SRCHFLG:BYTE,COMLINE:WORD + EXTRN PARAM1:WORD,PARAM2:WORD,NEWLEN:WORD,SRCHMOD:BYTE + EXTRN CURRENT:WORD,POINTER:WORD,START:BYTE,ENDTXT:WORD + EXTRN USER_DRIVE:BYTE,LSTNUM:WORD,NUMPOS:WORD,LSTFND:WORD + EXTRN SRCHCNT:WORD + +DATA ENDS + +DG GROUP CODE,CONST,DATA + +CODE SEGMENT PUBLIC + +ASSUME CS:DG,DS:DG,SS:DG,ES:DG + + PUBLIC REST_DIR,KILL_BL,INT_24,SCANLN,FINDLIN,SHOWNUM + PUBLIC FNDFIRST,FNDNEXT,CRLF,LF,OUT,UNQUOTE + + if kanji + PUBLIC TESTKANJ + endif + + EXTRN CHKRANGE:NEAR + +EDLPROC: + +RET1: RET + +FNDFIRST: + MOV DI,1+OFFSET DG:TXT1 + mov byte ptr[olddat],1 ;replace with old value if none new + CALL GETTEXT + OR AL,AL ;Reset zero flag in case CX is zero + JCXZ RET1 + cmp al,1ah ;terminated with a ^Z ? + jne sj8 + mov byte ptr[olddat],0 ;do not replace with old value +sj8: + MOV [OLDLEN],CX + XOR CX,CX + CMP AL,0DH + JZ SETBUF + CMP BYTE PTR [SRCHFLG],0 + JZ NXTBUF +SETBUF: + DEC SI +NXTBUF: + MOV [COMLINE],SI + MOV DI,1+OFFSET DG:TXT2 + CALL GETTEXT + CMP BYTE PTR [SRCHFLG],0 + JNZ NOTREPL + CMP AL,0DH + JNZ HAVCHR + DEC SI +HAVCHR: + MOV [COMLINE],SI +NOTREPL: + MOV [NEWLEN],CX + MOV BX,[PARAM1] + OR BX,BX + JNZ CALLER + cmp byte ptr[srchmod],0 + jne sj9 + mov bx,1 ;start from line number 1 + jmp short sj9a +sj9: + MOV BX,[CURRENT] + INC BX ;Default search and replace to current+1 +sj9a: + CALL CHKRANGE +CALLER: + CALL FINDLIN + MOV [LSTFND],DI + MOV [NUMPOS],DI + MOV [LSTNUM],DX + MOV BX,[PARAM2] + CMP BX,1 + SBB BX,-1 ;Decrement everything except zero + CALL FINDLIN + MOV CX,DI + SUB CX,[LSTFND] + OR AL,-1 + JCXZ aret + CMP CX,[OLDLEN] + jae sj10 +aret: ret +sj10: + MOV [SRCHCNT],CX + +FNDNEXT: + +; Inputs: +; [TXT1+1] has string to search for +; [OLDLEN] has length of the string +; [LSTFND] has starting position of search in text buffer +; [LSTNUM] has line number which has [LSTFND] +; [SRCHCNT] has length to be searched +; [NUMPOS] has beginning of line which has [LSTFND] +; Outputs: +; Zero flag set if match found +; [LSTFND],[LSTNUM],[SRCHCNT] updated for continuing the search +; [NUMPOS] has beginning of line in which match was made + + MOV AL,[TXT1+1] + MOV CX,[SRCHCNT] + MOV DI,[LSTFND] +SCAN: + OR DI,DI ;Clear zero flag in case CX=0 + REPNE SCASB + JNZ RET11 + MOV DX,CX + MOV BX,DI ;Save search position + MOV CX,[OLDLEN] + DEC CX + MOV SI,2 + OFFSET DG:TXT1 + CMP AL,AL ;Set zero flag in case CX=0 +if kanji + dec si ;Want to look at the first character again + dec di +kanjchar: + lodsb + call testkanj + jz nxt_kj_char + xchg ah,al + lodsb + mov bx,[di] + add di,2 + cmp ax,bx + jnz not_kj_match + dec cx + loop kanjchar +nxt_kj_char: + cmp al,byte ptr[di] + jnz not_kj_match + inc di + loop kanjchar + +not_kj_match: +else + REPE CMPSB +endif + MOV CX,DX + MOV DI,BX + JNZ SCAN + MOV [SRCHCNT],CX + MOV CX,DI + MOV [LSTFND],DI + MOV DI,[NUMPOS] + SUB CX,DI + MOV AL,10 + MOV DX,[LSTNUM] +;Determine line number of match +GETLIN: + INC DX + MOV BX,DI + REPNE SCASB + JZ GETLIN + DEC DX + MOV [LSTNUM],DX + MOV [NUMPOS],BX + XOR AL,AL +RET11: RET + + +GETTEXT: + +; Inputs: +; SI points into command line buffer +; DI points to result buffer +; Function: +; Moves [SI] to [DI] until ctrl-Z (1AH) or +; RETURN (0DH) is found. Termination char not moved. +; Outputs: +; AL = Termination character +; CX = No of characters moved. +; SI points one past termination character +; DI points to next free location + + XOR CX,CX + +GETIT: + LODSB +;----------------------------------------------------------------------- + cmp al,quote_char ;a quote character? + jne sj101 ;no, skip.... + lodsb ;yes, get quoted character + call make_cntrl + jmp short sj102 +;----------------------------------------------------------------------- +sj101: + CMP AL,1AH + JZ DEFCHK +sj102: + CMP AL,0DH + JZ DEFCHK + STOSB + INC CX + JMP SHORT GETIT + +DEFCHK: + OR CX,CX + JZ OLDTXT + PUSH DI + SUB DI,CX + MOV BYTE PTR [DI-1],cl + POP DI + RET + +OLDTXT: + cmp byte ptr[olddat],1 ;replace with old text? + je sj11 ;yes... + mov byte ptr[di-1],cl ;zero text buffer char count + ret + +sj11: + MOV CL,BYTE PTR [DI-1] + ADD DI,CX + RET + + +FINDLIN: + +; Inputs +; BX = Line number to be located in buffer (0 means last line) +; Outputs: +; DX = Actual line found +; DI = Pointer to start of line DX +; Zero set if BX = DX +; AL,CX destroyed. No other registers affected. + + MOV DX,[CURRENT] + MOV DI,[POINTER] + CMP BX,DX + JZ RET4 + JA FINDIT + OR BX,BX + JZ FINDIT + MOV DX,1 + MOV DI,OFFSET DG:START + CMP BX,DX + JZ RET4 +FINDIT: + MOV CX,[ENDTXT] + SUB CX,DI +SCANLN: + MOV AL,10 + OR AL,AL ;Clear zero flag +FINLIN: + JCXZ RET4 + REPNE SCASB + INC DX + CMP BX,DX + JNZ FINLIN +RET4: RET + + +SHOWNUM: + +; Inputs: +; BX = Line number to be displayed +; Function: +; Displays line number on terminal in 8-character +; format, suppressing leading zeros. +; AX, CX, DX destroyed. No other registers affected. + + PUSH BX + MOV AL," " + CALL OUT + CALL CONV10 + MOV AL,":" + CALL OUT + MOV AL,"*" + POP BX + CMP BX,[CURRENT] + JZ STARLIN + MOV AL," " +STARLIN: + JMP OUT + + +CONV10: + +;Inputs: +; BX = Binary number to be displayed +; Function: +; Ouputs binary number. Five digits with leading +; zero suppression. Zero prints 5 blanks. + + XOR AX,AX + MOV DL,AL + MOV CX,16 +CONV: + SHL BX,1 + ADC AL,AL + DAA + XCHG AL,AH + ADC AL,AL + DAA + XCHG AL,AH + ADC DL,DL + LOOP CONV + MOV BL,"0"-" " + XCHG AX,DX + CALL LDIG + MOV AL,DH + CALL DIGITS + MOV AL,DL +DIGITS: + MOV DH,AL + SHR AL,1 + SHR AL,1 + SHR AL,1 + SHR AL,1 + CALL LDIG + MOV AL,DH +LDIG: + AND AL,0FH + JZ ZERDIG + MOV BL,0 +ZERDIG: + ADD AL,"0" + SUB AL,BL + JMP OUT + +RET5: RET + + +CRLF: + MOV AL,13 + CALL OUT +LF: + MOV AL,10 +OUT: + PUSH DX + XCHG AX,DX + MOV AH,STD_CON_OUTPUT + INT 21H + XCHG AX,DX + POP DX + RET + + +;-----------------------------------------------------------------------; +; Will scan buffer given pointed to by SI and get rid of quote +;characters, compressing the line and adjusting the length at the +;begining of the line. +; Preserves al registers except flags and AX . + +unquote: + push cx + push di + push si + mov di,si + mov cl,[si-1] ;length of buffer + xor ch,ch + mov al,quote_char + cld +unq_loop: + jcxz unq_done ;no more chars in the buffer, exit + repnz scasb ;search for quote character + jnz unq_done ;none found, exit + push cx ;save chars left in buffer + push di ;save pointer to quoted character + push ax ;save quote character + mov al,byte ptr[di] ;get quoted character + call make_cntrl + mov byte ptr[di],al + pop ax ;restore quote character + mov si,di + dec di ;points to the quote character + inc cx ;include the carriage return also + rep movsb ;compact line + pop di ;now points to after quoted character + pop cx + jcxz sj13 ;if quote char was last of line do not adjust + dec cx ;one less char left in the buffer +sj13: pop si + dec byte ptr[si-1] ;one less character in total buffer count also + push si + jmp short unq_loop + +unq_done: + pop si + pop di + pop cx + ret + + +;-----------------------------------------------------------------------; +; Convert the character in AL to the corresponding control +; character. AL has to be between @ and _ to be converted. That is, +; it has to be a capital letter. All other letters are left unchanged. + +make_cntrl: + push ax + and ax,11100000b + cmp ax,01000000b + pop ax + jne sj14 + and ax,00011111b +sj14: + ret + + +;---- Kill spaces in buffer --------------------------------------------; +kill_bl: + lodsb ;get rid of blanks + cmp al,' ' + je kill_bl + ret + + +;----- Restore INT 24 vector and old current directory -----------------; +rest_dir: + cmp [fudge],0 + je no_fudge + + mov ax,(set_interrupt_vector shl 8) or 24h + lds dx,[hardch] + int 21h + push cs + pop ds + + mov dx,offset dg:userdir ;restore directory + mov ah,chdir + int 21h + mov dl,[user_drive] ;restore old current drive + mov ah,set_default_drive + int 21h + +no_fudge: + ret + +;----- INT 24 Processing -----------------------------------------------; + +int_24_retaddr dw offset dg:int_24_back + +int_24 proc far +assume ds:nothing,es:nothing,ss:nothing + + pushf + push cs + push [int_24_retaddr] + push word ptr [hardch+2] + push word ptr [hardch] + ret +int_24 endp + +int_24_back: + cmp al,2 ;abort? + jnz ireti + push cs + pop ds + +assume ds:dg + + call rest_dir + int 20h +ireti: + iret + + IF KANJI +TESTKANJ: + CMP AL,81H + JB NOTLEAD + CMP AL,9FH + JBE ISLEAD + CMP AL,0E0H + JB NOTLEAD + CMP AL,0FCH + JBE ISLEAD +NOTLEAD: + PUSH AX + XOR AX,AX ;Set zero + POP AX + RET + +ISLEAD: + PUSH AX + XOR AX,AX ;Set zero + INC AX ;Reset zero + POP AX + RET + ENDIF + +;-----------------------------------------------------------------------; + +CODE ENDS + END EDLPROC + + + \ No newline at end of file diff --git a/EXE2BIN.ASM b/EXE2BIN.ASM new file mode 100644 index 0000000..80deb43 --- /dev/null +++ b/EXE2BIN.ASM @@ -0,0 +1,514 @@ + title LOCATE (EXE2BIN) + +;Loader for EXE files under 86-DOS + +;The following switch allows use with the "old linker", which put a version +;number where the new linker puts the number of bytes used in the last page. +;If enabled, this will cause a test for 0004 at this location (the old linker +;version number), and if equal, change it to 200H so all of the last page +;will be used. + +;VER. 1.5 +; 05/21/82 Added rev number +; +;VER. 1.6 +; 07/01/82 A little less choosy about size matches +; +;VER. 2.0 Rev. 1 M.A.Ulloa +; 10/08/82 Modified to use new 2.0 system calls for file i/o +; +; Rev. 2 M.A.Ulloa +; 10/27/82 Added the DOS version check + +FALSE EQU 0 +TRUE EQU NOT FALSE + +OLDLINK EQU 0 ;1 to enable, 0 to disable + + .xlist + INCLUDE DOSSYM.ASM + .list + + + subttl Main Code Area + page + + +code segment byte +code ends + +DATA SEGMENT PUBLIC BYTE + + + EXTRN bad_vers_err:BYTE,NOTFND:BYTE,NOROOM:BYTE,DIRFULL:BYTE + EXTRN CANTFIX:BYTE,RDBAD:BYTE,FULL:BYTE,PROMPT:BYTE,CRLF:BYTE + +make db "MAUlloa/Microsoft/V20" +rev db "2" + +file1_ext db ".EXE",00h +file2_ext db ".BIN",00h + +per1 db 0 +per2 db 0 + +file1 db 64 dup(?) +handle1 dw 1 dup(?) + +file2 db 64 dup(?) +handle2 dw 1 dup(?) + + +INBUF DB 5,0 + DB 5 DUP(?) + +;The following locations must be defined for storing the header: + +RUNVAR LABEL BYTE ;Start of RUN variables +RELPT DW ? +LASTP LABEL WORD +RELSEG DW ? +SIZ LABEL WORD ;Share these locations +PAGES DW ? +RELCNT DW ? +HEADSIZ DW ? + DW ? +LOADLOW DW ? +INITSS DW ? +INITSP DW ? + DW ? +INITIP DW ? +INITCS DW ? +RELTAB DW ? +RUNVARSIZ EQU $-RUNVAR + +DATA ENDS + +STACK SEGMENT WORD STACK + DB 80H DUP (?) +STACK ENDS + +ZLOAD SEGMENT +ZLOAD ENDS +LOAD EQU ZLOAD + +CODE SEGMENT BYTE + + ASSUME CS:CODE + +LOCATE PROC FAR + JMP SHORT LOCSTRT + +HEADER DB "Vers 2.00" + +LOCSTRT: + MOV SI,81H + PUSH DS + XOR AX,AX + PUSH AX ;Push return address to DS:0 + +;Code to print header +; PUSH DS +; MOV DX,DATA +; MOV DS,DX +; MOV DX,OFFSET HEADER +; MOV AH,STD_CON_STRING_OUTPUT +; INT 21H +; POP DS + +;----- Check Version Number --------------------------------------------; + mov ah,Get_Version + int 21h + cmp al,2 + jge vers_ok ; version >= 2, enter locate + push ds + mov dx,data + mov ds,dx + mov dx,offset bad_vers_err + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + pop ds + ret ;long return to DOS + +;-----------------------------------------------------------------------; +vers_ok: + + + MOV BX,WORD PTR DS:2 ;Get size of memory + MOV DX,DATA + MOV ES,DX + + assume es:data + +;-----------------------------------------------------------------------; + +;----- Get the first file name + call kill_bl + jnc sj01 + mov ds,dx + jmp bad_file +sj01: + mov di,offset file1 +sj0: + lodsb ;get character of file name + cmp al,' ' + je sj2 + cmp al,0dh + je sj2 + cmp al,'.' ;an extension separator found? + jne sj1 + mov es:[per1],-1 +sj1: + stosb + jmp short sj0 +sj2: + dec si + mov byte ptr es:[di],00h ;nul terminate the filename + call kill_bl + jc no_second + +;----- Get the second file name + mov di,offset file2 +sj3: + lodsb ;get character of file name + cmp al,' ' + je sj5 + cmp al,0dh + je sj5 + cmp al,'.' ;an extension separator found? + jne sj4 + mov es:[per2],-1 +sj4: + stosb + jmp short sj3 +sj5: + mov byte ptr es:[di],00h ;nul terminate + jmp short check_ext + +;----- Copy file1 to file2 +no_second: + mov ds,dx + + assume ds:data + + mov si,offset file1 + mov di,offset file2 +sj6: + lodsb + cmp al,'.' + je sj7 + cmp al,00h + je sj7 + stosb + jmp short sj6 +sj7: + mov byte ptr [di],00h + +;----- Check that files have an extension, otherwise set default +check_ext: + mov ds,dx + + assume ds:data + + cmp [per1],-1 + je file1_ok + mov si,offset file1 +sj8: + lodsb + cmp al,00h + jne sj8 + mov di,si + mov si,offset file1_ext + call put_ext + +file1_ok: + cmp [per2],-1 + je file2_ok + mov si,offset file2 +sj9: + lodsb + cmp al,00h + jne sj9 + mov di,si + mov si,offset file2_ext + call put_ext + jmp short file2_ok + +;----- Fill in the default extent +put_ext proc near + dec di + mov cx,5 ;move extent: period,extent,null + rep movsb + ret +put_ext endp + +;----- Find the first non-blank +kill_bl proc near + cld +sj10: + lodsb + cmp al,' ' + je sj10 + dec si + cmp al,0dh + clc + jne sj11 + stc +sj11: + ret +kill_bl endp + +file2_ok: + +;-----------------------------------------------------------------------; + + mov dx,offset file1 + mov ah,open + mov al,0 ;ror reading only + INT 21H ;Open input file + jc bad_file + mov [handle1],ax + jmp exeload + +bad_file: + MOV DX,OFFSET NOTFND +xERROR: + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + RET ;FAR return to MS-DOS +TOOBIG: + MOV DX,OFFSET NOROOM + JMP xERROR +BADEXE: + MOV DX,OFFSET CANTFIX +ERRORJ: JMP xERROR + +EXELOAD: + MOV DX,OFFSET RUNVAR ;Read header in here + MOV CX,RUNVARSIZ ;Amount of header info we need + push bx + mov bx,[handle1] + MOV AH,read + INT 21H ;Read in header + pop bx + CMP [RELPT],5A4DH ;Check signature word + JNZ BADEXE + MOV AX,[HEADSIZ] ;size of header in paragraphs + ADD AX,31 ;Round up first + CMP AX,1000H ;Must not be >=64K + JAE TOOBIG + AND AX,NOT 31 + MOV CL,4 + SHL AX,CL ;Header size in bytes + + push dx + push cx + push ax + push bx + mov dx,ax + xor cx,cx + mov al,0 + mov bx,[handle1] + mov ah,lseek + int 21h + pop bx + pop ax + pop cx + pop dx + + XCHG AL,AH + SHR AX,1 ;Convert to pages + MOV DX,[PAGES] ;Total size of file in 512-byte pages + SUB DX,AX ;Size of program in pages + CMP DX,80H ;Fit in 64K? + JAE TOOBIG + XCHG DH,DL + SHL DX,1 ;Convert pages to bytes + MOV AX,[LASTP] ;Get count of bytes in last page + OR AX,AX ;If zero, use all of last page + JZ WHOLEP + + IF OLDLINK + CMP AX,4 ;Produced by old linker? + JZ WHOLEP ;If so, use all of last page too + ENDIF + + SUB DX,200H ;Subtract last page + ADD DX,AX ;Add in byte count for last page +WHOLEP: + MOV [SIZ],DX + ADD DX,15 + SHR DX,CL ;Convert bytes to paragraphs + MOV BP,LOAD + ADD DX,BP ;Size + start = minimum memory (paragr.) + CMP DX,BX ;Enough memory? + JA TOOBIG + MOV DX,OFFSET CANTFIX + MOV AX,[INITSS] + OR AX,[INITSP] + OR AX,[INITCS] +ERRORNZ: + jz xj + JMP ERRORJ ;Must not have SS, SP, or CS to init. +xj: MOV AX,[INITIP] + OR AX,AX ;If IP=0, do binary fix + JZ BINFIX + CMP AX,100H ;COM file must be set up for CS:100 + JNZ ERRORNZ + + push dx + push cx + push ax + push bx + mov dx,100h ;chop off first 100h + xor cx,cx + mov al,1 ;seek from current position + mov bx,[handle1] + mov ah,lseek + int 21h + pop bx + pop ax + pop cx + pop dx + + SUB [SIZ],AX ;And count decreased size + CMP [RELCNT],0 ;Must have no fixups + JNZ ERRORNZ +BINFIX: + XOR BX,BX ;Initialize fixup segment +;See if segment fixups needed + CMP [RELCNT],0 + JZ LOADEXE +GETSEG: + MOV DX,OFFSET PROMPT + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + MOV AH,STD_CON_STRING_INPUT + MOV DX,OFFSET INBUF + INT 21H ;Get user response + MOV DX,OFFSET CRLF + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + MOV SI,OFFSET INBUF+2 + MOV BYTE PTR [SI-1],0 ;Any digits? + JZ GETSEG +DIGLP: + LODSB + SUB AL,"0" + JC DIGERR + CMP AL,10 + JB HAVDIG + AND AL,5FH ;Convert to upper case + SUB AL,7 + CMP AL,10 + JB DIGERR + CMP AL,10H + JAE DIGERR +HAVDIG: + SHL BX,1 + SHL BX,1 + SHL BX,1 + SHL BX,1 + OR BL,AL + JMP DIGLP + +DIGERR: + CMP BYTE PTR [SI-1],0DH ;Is last char. a CR? + JNZ GETSEG +LOADEXE: + XCHG BX,BP ;BX has LOAD, BP has fixup + + MOV CX,[SIZ] + MOV AH,read + push di + mov di,[handle1] + PUSH DS + MOV DS,BX + XOR DX,DX + push bx + mov bx,di + INT 21H ;Read in up to 64K + pop bx + POP DS + pop di + Jnc HAVEXE ;Did we get it all? + MOV DX,OFFSET RDBAD + jmp xERROR ;Non fatal, print warning +HAVEXE: + CMP [RELCNT],0 ;Any fixups to do? + JZ STORE + MOV AX,[RELTAB] ;Get position of table + + push dx + push cx + push ax + push bx + mov dx,ax + xor cx,cx + mov al,0 + mov bx,[handle1] + mov ah,lseek + int 21h + pop bx + pop ax + pop cx + pop dx + + MOV DX,OFFSET RELPT ;4-byte buffer for relocation address +RELOC: + MOV DX,OFFSET RELPT ;4-byte buffer for relocation address + MOV CX,4 + MOV AH,read + push bx + mov bx,[handle1] + INT 21H ;Read in one relocation pointer + pop bx + Jnc RDCMP + JMP BADEXE +RDCMP: + MOV DI,[RELPT] ;Get offset of relocation pointer + MOV AX,[RELSEG] ;Get segment + ADD AX,BX ;Bias segment with actual load segment + MOV ES,AX + ADD ES:[DI],BP ;Relocate + DEC [RELCNT] ;Count off + JNZ RELOC +STORE: + MOV AH,CREAT + MOV DX,OFFSET file2 + xor cx,cx + INT 21H + Jc MKERR + mov [handle2],ax + MOV CX,[SIZ] + MOV AH,write + push di + mov di,[handle2] + PUSH DS + MOV DS,BX + XOR DX,DX ;Address 0 in segment + push bx + mov bx,di + INT 21H + pop bx + POP DS + pop di + Jc WRTERR ;Must be zero if more to come + MOV AH,CLOSE + push bx + mov bx,[handle2] + INT 21H + pop bx + RET + +WRTERR: + MOV DX,OFFSET FULL + JMP xERROR +MKERR: + MOV DX,OFFSET DIRFULL + JMP xERROR + +LOCATE ENDP +CODE ENDS + END LOCATE + \ No newline at end of file diff --git a/EXEC.ASM b/EXEC.ASM new file mode 100644 index 0000000..3419249 --- /dev/null +++ b/EXEC.ASM @@ -0,0 +1,1035 @@ +SUBTTL $exec - load/go a program +PAGE +; +; Assembler usage: +; LDS DX, name +; LES BX, blk +; MOV AH, Exec +; MOV AL, func +; INT int_command +; +; AL Function +; -- -------- +; 0 Load and execute the program. +; 1 Load, create the program header but do not +; begin execution. +; 3 Load overlay. No header created. +; +; AL = 0 -> load/execute program +; +; +---------------------------+ +; | WORD segment address of | +; | environment. | +; +---------------------------+ +; | DWORD pointer to ASCIZ | +; | command line at 80h | +; +---------------------------+ +; | DWORD pointer to default | +; | FCB to be passed at 5Ch | +; +---------------------------+ +; | DWORD pointer to default | +; | FCB to be passed at 6Ch | +; +---------------------------+ +; +; AL = 1 -> load program +; +; +---------------------------+ +; | WORD segment address of | +; | environment. | +; +---------------------------+ +; | DWORD pointer to ASCIZ | +; | command line at 80h | +; +---------------------------+ +; | DWORD pointer to default | +; | FCB to be passed at 5Ch | +; +---------------------------+ +; | DWORD pointer to default | +; | FCB to be passed at 6Ch | +; +---------------------------+ +; | DWORD returned value of | +; | CS:IP | +; +---------------------------+ +; | DWORD returned value of | +; | SS:IP | +; +---------------------------+ +; +; AL = 3 -> load overlay +; +; +---------------------------+ +; | WORD segment address where| +; | file will be loaded. | +; +---------------------------+ +; | WORD relocation factor to | +; | be applied to the image. | +; +---------------------------+ +; +; Returns: +; AX = exec_invalid_function +; = exec_bad_format +; = exec_bad_environment +; = exec_not_enough_memory +; = exec_file_not_found +; + +IF IBM +ZEXEC_DATA SEGMENT PUBLIC BYTE +ZERO = $ +ENDIF + +exec_blk DD ? +exec_func DB ? +exec_fh DW ? +exec_rel_fac DW ? +exec_res_len_para DW ? +exec_init_IP DW ? +exec_init_CS DW ? +exec_init_SP DW ? +exec_init_SS DW ? +exec_environ DW ? +exec_size DW ? +exec_load_block DW ? + +exec_load_high DB ? + +exec_internal_buffer EQU $ +exec_signature DW ? ; must contain 4D5A (yay zibo!) +exec_len_mod_512 DW ? ; low 9 bits of length +exec_pages DW ? ; number of 512b pages in file +exec_rle_count DW ? ; count of reloc entries +exec_par_dir DW ? ; number of paragraphs before image +exec_min_BSS DW ? ; minimum number of para of BSS +exec_max_BSS DW ? ; max number of para of BSS +exec_SS DW ? ; stack of image +exec_SP DW ? ; SP of image +exec_chksum DW ? ; checksum of file (ignored) +exec_IP DW ? ; IP of entry +exec_CS DW ? ; CS of entry +exec_rle_table DW ? ; byte offset of reloc table +exec_iov DW ? ; overlay number (0 for root) +exec_dma DW ? +exec_internal_buffer_size EQU $-exec_internal_buffer + +IF IBM +exec_ctrlc DB ? ; state of users ctrlc flag +Exec_low_seg DW ? +CurrentPDB DW ? +NUMIO DB ? +ZEXECDATASIZ = $-ZERO +ZEXECDATAEND LABEL BYTE + PUBLIC ZEXECDATAEND +ZEXEC_DATA ENDS +ZEXEC_CODE SEGMENT PUBLIC PARA + PUBLIC $EXEC +ZERO = $ + procedure $EXEC,FAR + ASSUME CS:EGROUP,SS:RESGROUP,ES:NOTHING,DS:NOTHING +ENDIF +IF NOT IBM + procedure $Exec,NEAR + ASSUME DS:NOTHING, ES:NOTHING +ENDIF +; +; validate function +; + +IF IBM + PUSH CS + POP DS + ASSUME DS:EGROUP + + MOV AX,(Set_Ctrl_C_Trapping SHL 8) + 0 ; Save current ctrl-c + INT int_command + MOV exec_ctrlc,DL + XOR DX,DX + MOV AX,(Set_Ctrl_C_Trapping SHL 8) + 1 ; Turn it off! + INT int_command + + MOV AH,Get_current_PDB + INT int_command + MOV [CurrentPDB],BX +; +; set up user return stack info +; + MOV ES,BX + LES BX,DWORD PTR [user_sp] + MOV WORD PTR ES:[PDB_user_stack+2],ES + MOV WORD PTR ES:[PDB_user_stack],BX + + MOV AH,Get_Default_Drive + INT int_command + MOV DL,AL + MOV AH,Set_default_drive + INT int_command + MOV [NUMIO],AL +; +; determine lowest seg address for overwrite problem (round DOWN) +; + MOV CL,4 + MOV AX,OFFSET ZEXEC_CODE:exec_check + SHR AX,CL + PUSH CS + POP BX + ADD AX,BX + MOV [exec_low_seg],AX + + CALL get_user_stack + ASSUME DS:NOTHING + MOV AX,[SI.user_AX] + MOV BX,[SI.user_BX] + MOV DX,[SI.user_DX] + MOV ES,[SI.user_ES] + MOV DS,[SI.user_DS] +ENDIF + + CMP AL,3 ; only 0, 1 or 3 are allowed + JNA exec_check_2 + +exec_bad_fun: + error error_invalid_function + +exec_ret_err: + transfer SYS_RET_ERR + +exec_check_2: + CMP AL,2 + JZ exec_bad_fun + + MOV WORD PTR [exec_blk],BX ; stash args + MOV WORD PTR [exec_blk+2],ES + MOV BYTE PTR [exec_func],AL + MOV BYTE PTR [exec_load_high],0 +IF IBM + MOV AX,(OPEN SHL 8) + 0 + INT int_command +ENDIF +IF NOT IBM + XOR AL,AL ; open for reading + invoke $OPEN ; is the file there? +ENDIF + JC exec_ret_err + MOV [exec_fh],AX + MOV BX,AX +IF IBM + MOV AX,(ioctl SHL 8) ; get device information + INT int_command +ENDIF +IF NOT IBM + XOR AL,AL + invoke $IOCTL +ENDIF + TEST DL,devid_ISDEV + JZ exec_check_environ + MOV AL,exec_file_not_found + transfer SYS_RET_ERR + +exec_check_environ: + MOV [exec_load_block],0 + + TEST BYTE PTR [exec_func],exec_func_overlay ; overlays... no environment + JNZ exec_read_header + LDS SI,DWORD PTR [exec_blk] ; get block + MOV AX,[SI].Exec1_environ ; address of environ + OR AX,AX + JNZ exec_scan_env + MOV DS,[CurrentPDB] + MOV AX,DS:[PDB_environ] + MOV [exec_environ],AX + OR AX,AX + JZ exec_read_header + +exec_scan_env: + CLD + MOV ES,AX + XOR DI,DI + MOV CX,07FFFh ; at most 32k of environment + XOR AL,AL + +exec_get_environ_len: + REPNZ SCASB ; find that nul byte + JZ exec_check ; CX is out... bad environment + MOV AL,exec_bad_environment + JMP exec_bomb + +exec_check: + SCASB ; is there another nul byte? + JNZ exec_get_environ_len ; no, scan some more + PUSH DI + MOV BX,DI ; AX <- length of environment + ADD BX,0Fh + MOV CL,4 + SHR BX,CL ; number of paragraphs needed + PUSH ES +IF IBM + MOV AH,ALLOC + INT int_command +ENDIF +IF NOT IBM + invoke $ALLOC ; can we get the space? +ENDIF + POP DS + POP CX + JNC exec_save_environ + JMP exec_no_mem ; nope... cry and sob + +exec_save_environ: + MOV ES,AX + MOV [exec_environ],AX ; save him for a rainy day +IF IBM + PUSH CX + MOV CX,ES + ADD CX,BX + CMP BX,[exec_low_seg] + POP CX + JA exec_no_mem +ENDIF + XOR SI,SI + XOR DI,DI + REP MOVSB ; copy the environment + +exec_read_header: +; +; We read in the program header into the above data area and determine +; where in this memory the image will be located. +; +IF IBM + PUSH CS + POP DS ; and put it in DS:DX + ASSUME DS:EGROUP +ENDIF +IF NOT IBM + PUSH SS + POP DS ; and put it in DS:DX + ASSUME DS:DOSGROUP +ENDIF + MOV CX,exec_internal_buffer_size; header size + MOV BX,[exec_fh] ; from the handle +IF IBM + MOV DX,OFFSET EGROUP:exec_signature +ENDIF +IF NOT IBM + MOV DX,OFFSET DOSGROUP:exec_signature +ENDIF + PUSH ES + PUSH DS + CALL exec_dealloc +IF IBM + MOV AH,READ + INT int_command +ENDIF +IF NOT IBM + invoke $READ +ENDIF + CALL exec_alloc + POP DS + POP ES + JC exec_bad_file + CMP AX,exec_internal_buffer_size; did we read the right number? + JNZ exec_com_filej ; yep... continue + CMP [exec_max_BSS],0 + JNZ exec_check_sig + MOV [exec_load_high],-1 +exec_check_sig: + MOV AX,[exec_signature] + CMP AX,exe_valid_signature ; zibo arises! + JZ exec_save_start ; assume com file if no signature + CMP AX,exe_valid_old_signature ; zibo arises! + JZ exec_save_start ; assume com file if no signature + +exec_com_filej: + JMP exec_com_file + +; +; We have the program header... determine memory requirements +; +exec_save_start: + MOV AX,[exec_pages] ; get 512-byte pages + MOV CL,5 ; convert to paragraphs + SHL AX,CL + SUB AX,[exec_par_dir] ; AX = size in paragraphs + MOV [exec_res_len_para],AX + +; +; Do we need to allocate memory? Yes if function is not load-overlay +; + TEST BYTE PTR [exec_func],exec_func_overlay + JZ exec_allocate ; allocation of space +; +; get load address from block +; + LES DI,DWORD PTR [exec_blk] + MOV AX,ES:[DI].exec3_load_addr + MOV [exec_dma],AX + MOV AX,ES:[DI].exec3_reloc_fac + MOV [exec_rel_fac],AX +IF IBM + JMP exec_find_res +ENDIF +IF NOT IBM + JMP SHORT exec_find_res +ENDIF + +exec_no_mem: + MOV AL,exec_not_enough_memory + JMP SHORT exec_bomb ; AX should be set by $ALLOC + +exec_bad_file: + MOV AL,exec_bad_format + +exec_bomb: + ASSUME DS:NOTHING,ES:NOTHING + PUSH AX + MOV BX,[exec_fh] + CALL exec_dealloc +IF IBM + MOV AH,CLOSE + INT int_command +ENDIF +IF NOT IBM + invoke $CLOSE +ENDIF + POP AX + transfer SYS_RET_ERR + +exec_allocate: +IF IBM + ASSUME DS:EGROUP +ENDIF +IF NOT IBM + ASSUME DS:DOSGROUP +ENDIF + PUSH AX + MOV BX,0FFFFh ; see how much room in arena + PUSH DS +IF IBM + MOV AH,ALLOC + INT int_command +ENDIF +IF NOT IBM + invoke $ALLOC ; should have carry set and BX has max +ENDIF + POP DS + POP AX + ADD AX,10h ; room for header + CMP BX,11h ; enough room for a header + JB exec_no_mem + CMP AX,BX ; is there enough for bare image? + JA exec_no_mem + CMP [exec_load_high],0 ; if load high, use max + JNZ exec_BX_max ; use max + ADD AX,[exec_min_BSS] ; go for min allocation + JC exec_no_mem ; oops! carry + CMP AX,BX ; enough space? + JA exec_no_mem ; nope... + SUB AX,[exec_min_BSS] + ADD AX,[exec_max_BSS] ; go for the MAX + JC exec_BX_max + CMP AX,BX + JBE exec_got_block + +exec_BX_max: + MOV AX,BX + +exec_got_block: + PUSH DS + MOV BX,AX + MOV [exec_size],BX +IF IBM + MOV AH,ALLOC + INT int_command +ENDIF +IF NOT IBM + invoke $ALLOC ; get the space +ENDIF + POP DS + JC exec_no_mem + MOV [exec_load_block],AX + ADD AX,10h + CMP [exec_load_high],0 + JZ exec_use_ax ; use ax for load info + ADD AX,[exec_size] ; go to end + SUB AX,[exec_res_len_para] ; drop off header + SUB AX,10h ; drop off pdb +exec_use_ax: + MOV [exec_rel_fac],AX ; new segment + MOV [exec_dma],AX ; beginning of dma +IF IBM + CMP AX,[exec_low_seg] ; below loader + JA exec_no_mem_try + ADD AX,[exec_res_len_para] ; go to end + CMP Ax,[exec_low_seg] ; above loader + JBE exec_find_res +exec_try_high: + CMP [exec_load_high],0 + JZ exec_no_memj1 +exec_try_just_below: + MOV DX,AX + SUB DX,[exec_size] ; get beginning + ADD DX,[exec_res_len_para] ; no space + CMP DX,[exec_low_seg] ; room there? + JA exec_no_memj1 + MOV AX,[exec_low_seg] + SUB AX,[exec_res_len_para] + JMP exec_use_ax +exec_no_mem_try: + MOV DX,CS + ADD DX,(zexecdatasiz+zexeccodesize+15)/16 + CMP AX,DX + JAE exec_try_high + JMP exec_try_just_below +exec_no_memj1: + JMP exec_no_mem +ENDIF + +; +; Determine the location in the file of the beginning of the resident +; +exec_find_res: + MOV DX,[exec_par_dir] + PUSH DX + MOV CL,4 + SHL DX,CL ; low word of location + POP AX + MOV CL,12 + SHR AX,CL ; high word of location + MOV CX,AX ; CX <- high + +; +; Read in the resident image (first, seek to it) +; + MOV BX,[exec_fh] + PUSH DS +IF IBM + MOV AX,(LSEEK SHL 8) + 0 + INT int_command +ENDIF +IF NOT IBM + XOR AL,AL + invoke $LSEEK ; seek to resident +ENDIF + POP DS + +exec_big_read: ; Read resident into memory + MOV BX,[exec_res_len_para] + CMP BX,1000h ; too many bytes to read? + JB exec_read_ok + MOV BX,0FE0h ; max in one chunk FE00 bytes + +exec_read_ok: + SUB [exec_res_len_para],BX ; we read (soon) this many + PUSH BX + MOV CL,4 + SHL BX,CL ; get count in bytes from paras + MOV CX,BX ; count in correct register + MOV BX,[exec_fh] ; handle in correct register + PUSH DS + MOV DS,[exec_dma] ; Set up read buffer + ASSUME DS:NOTHING + XOR DX,DX + PUSH CX ; save our count + CALL exec_dealloc +IF IBM + MOV AH,READ + INT int_command +ENDIF +IF NOT IBM + invoke $READ ; WOMP! +ENDIF + CALL exec_alloc + POP CX ; get old count to verify + POP DS +IF IBM + ASSUME DS:EGROUP +ENDIF +IF NOT IBM + ASSUME DS:DOSGROUP +ENDIF + CMP CX,AX ; did we read enough? + POP BX ; get paragraph count back + JNZ exec_do_reloc ; and do reloc if no more to read +; +; We've read in CX bytes... bump DTA location +; + + ADD [exec_dma],BX ; bump dma address + CMP [exec_res_len_para],0 + JNZ exec_big_read + +; +; The image has now been read in. We must perform relocation to +; the current location. +; + +exec_do_reloc: + MOV CX,[exec_rel_fac] + MOV AX,[exec_SS] ; get initial SS + ADD AX,CX ; and relocate him + MOV [exec_init_SS],AX + + MOV AX,[exec_SP] ; initial SP + MOV [exec_init_SP],AX + + LES AX,DWORD PTR [exec_IP] + MOV [exec_init_IP],AX + MOV AX,ES + ADD AX,CX ; relocated... + MOV [exec_init_CS],AX + + XOR CX,CX + MOV DX,[exec_rle_table] + MOV BX,[exec_fh] + PUSH DS +IF IBM + MOV AX,(LSEEK SHL 8) + 0 + INT int_command +ENDIF +IF NOT IBM + XOR AX,AX + invoke $LSEEK +ENDIF + POP DS + + JNC exec_get_entries +exec_bad_filej: + JMP exec_bad_file + +exec_get_entries: + MOV DX,[exec_rle_count] ; Number of entries left + +exec_read_reloc: + ASSUME DS:NOTHING + PUSH DX +IF IBM + MOV DX,OFFSET EGROUP:exec_signature +ENDIF +IF NOT IBM + MOV DX,OFFSET DOSGROUP:exec_signature +ENDIF + MOV CX,((exec_internal_buffer_size)/4)*4 + MOV BX,[exec_fh] + PUSH DS + CALL exec_dealloc +IF IBM + MOV AH,READ + INT int_command +ENDIF +IF NOT IBM + invoke $READ +ENDIF + CALL exec_alloc + POP ES + POP DX + JC exec_bad_filej + MOV CX,(exec_internal_buffer_size)/4 +IF IBM + MOV DI,OFFSET EGROUP:exec_signature ; Pointer to byte location in header +ENDIF +IF NOT IBM + MOV DI,OFFSET DOSGROUP:exec_signature ; Pointer to byte location in header +ENDIF +; +; Relocate a single address +; + MOV SI,[exec_rel_fac] + +exec_reloc_one: + CMP DX,0 ; Any more entries? + JNE exec_get_addr + JMP Exec_set_PDB + +exec_get_addr: + LDS BX,DWORD PTR ES:[DI] ; Get ra/sa of entry + MOV AX,DS ; Relocate address of item + ADD AX,SI + MOV DS,AX + MOV AX,WORD PTR DS:[BX] ; Relocate item + ADD AX,SI + MOV WORD PTR DS:[BX],AX + ADD DI,4 + DEC DX + LOOP exec_reloc_one ; End of internal buffer? + +; +; We've exhausted a single buffer's worth. Read in the next piece +; of the relocation table. +; + + PUSH ES + POP DS + JMP exec_read_reloc + +exec_no_memj: + JMP exec_no_mem + +; +; we have a .COM file. First, determine if we are merely loading an overlay. +; +exec_com_file: + TEST BYTE PTR [exec_func],exec_func_overlay + JZ exec_alloc_com_file + LDS SI,DWORD PTR [exec_blk] ; get arg block + LODSW ; get load address + MOV [exec_dma],AX + JMP SHORT exec_64k ; read it all! + +; We must allocate the max possible size block (ick!) and set up +; CS=DS=ES=SS=PDB pointer, IP=100, SP=max size of block. +; +exec_alloc_com_file: + MOV BX,0FFFFh +IF IBM + MOV AH,ALLOC + INT int_command +ENDIF +IF NOT IBM + invoke $ALLOC ; largest piece available as error +ENDIF + OR BX,BX + JZ exec_no_memj + MOV [exec_size],BX ; save size of allocation block +IF IBM + MOV AH,ALLOC + INT int_command +ENDIF +IF NOT IBM + PUSH BX + invoke $ALLOC ; largest piece available as error + POP BX ; get size of block... +ENDIF + MOV [exec_load_block],AX + ADD AX,10h ; increment for header + MOV [exec_dma],AX + SUB BX,10h ; remember header +IF IBM +; +; need to read up to exec_low_seg (at most) +; + MOV CX,[exec_low_seg] + CMP AX,CX ; is base of allocation above spot + JA exec_check_64k + SUB CX,AX + CMP CX,BX + JA exec_check_64k + MOV BX,CX + +exec_check_64k: +ENDIF + CMP BX,1000h ; 64k or more? + JAE exec_64k ; yes, read only 64k + MOV AX,BX ; convert size to bytes + MOV CL,4 + SHL AX,CL + JMP SHORT exec_read_com + +exec_64k: + MOV AX,0FFFFh ; 64k-1 bytes + +exec_read_com: + PUSH AX ; save number to read + MOV BX,[exec_fh] ; of com file + XOR CX,CX ; but seek to 0:0 + MOV DX,CX +IF IBM + MOV AX,(LSEEK SHL 8) + 0 + INT int_command +ENDIF +IF NOT IBM + XOR AX,AX ; seek relative to beginning + invoke $LSEEK ; back to beginning of file +ENDIF + MOV BX,[exec_fh] + POP CX ; number to read + MOV DS,[exec_dma] + XOR DX,DX + PUSH CX + CALL exec_dealloc +IF IBM + MOV AH,READ + INT int_command +ENDIF +IF NOT IBM + invoke $READ ; read in com file +ENDIF + CALL exec_alloc + POP SI ; get number of bytes to read + CMP AX,SI ; did we read them all? +IF IBM + JNZ exec_skip ; exactly the wrong number... no memory + JMP exec_no_mem +exec_skip: +ENDIF +IF NOT IBM + JZ exec_no_memj ; exactly the wrong number... no memory +ENDIF + TEST BYTE PTR [exec_func],exec_func_overlay + JNZ exec_set_PDB ; no starto, chumo! + MOV AX,[exec_DMA] + SUB AX,10h + MOV [exec_init_CS],AX + MOV [exec_init_IP],100h ; initial IP is 100 + ; SI is at most FFFFh + DEC SI ; make room for stack + ; SI is at most FFFEh, room for a 0! + MOV [exec_init_SP],SI ; max value for read is also SP! + MOV [exec_init_SS],AX + MOV DS,AX + MOV WORD PTR DS:[SI],0 ; 0 for return + +exec_set_PDB: + MOV BX,[exec_fh] ; we are finished with the file. + CALL exec_dealloc +IF IBM + MOV AH,CLOSE + INT int_command +ENDIF +IF NOT IBM + invoke $CLOSE ; release the jfn +ENDIF + CALL exec_alloc + TEST BYTE PTR [exec_func],exec_func_overlay + JZ exec_build_header + transfer SYS_RET_OK ; overlay load -> done + +exec_build_header: + MOV DX,[exec_load_block] +; +; assign the space to the process +; + + MOV SI,arena_owner ; pointer to owner field + + MOV AX,[exec_environ] ; get environ pointer + OR AX,AX + JZ NO_OWNER ; no environment + DEC AX ; point to header + MOV DS,AX + MOV DS:[SI],DX ; assign ownership +NO_OWNER: + MOV AX,[exec_load_block] ; get load block pointer + DEC AX + MOV DS,AX ; point to header + MOV DS:[SI],DX ; assign ownership + + PUSH DX +IF IBM + MOV AH,DUP_PDB + INT int_command + MOV ES,DX + MOV [CurrentPDB],DX +ENDIF +IF NOT IBM + MOV BYTE PTR [CreatePDB], 0FFH ; indicate a new process + invoke $Dup_PDB ; ES is now PDB +ENDIF + POP DX + PUSH [exec_environ] + POP ES:[PDB_environ] + MOV SI,[exec_size] + ADD SI,DX + MOV ES:[PDB_block_len],SI +; +; set up proper command line stuff +; + LDS SI,DWORD PTR [exec_blk] ; get the block + PUSH DS ; save its location + PUSH SI + LDS SI,DS:[SI.exec0_5C_FCB] ; get the 5c fcb + MOV CX,12 ; copy drive, name and ext + PUSH CX + MOV DI,5Ch + MOV BL,DS:[SI] + REP MOVSB + XOR AX,AX ; zero extent, etc for CPM + STOSW + STOSW + POP CX + POP SI ; get block + POP DS + PUSH DS ; save (again) + PUSH SI + LDS SI,DS:[SI.exec0_6C_FCB] ; get 6C FCB + MOV DI,6Ch ; do same as above + MOV BH,DS:[SI] + REP MOVSB + STOSW + STOSW + POP SI ; get block (last time) + POP DS + LDS SI,DS:[SI.exec0_com_line] ; command line + MOV CX,80h + MOV DI,CX + REP MOVSB ; Wham! + +; +; Process BX into default AX (validity of drive specs on args) +; + DEC CL ; get 0FFh in CX + CMP BH,[NUMIO] + JBE exec_BH_good + MOV BH,CL + JMP SHORT exec_BL +exec_BH_good: + XOR BH,BH +exec_BL: + CMP BL,[NUMIO] + JBE exec_BL_good + MOV BL,CL + JMP SHORT exec_set_return +exec_BL_good: + XOR BL,BL +exec_set_return: + invoke get_user_stack ; get his return address + PUSH [SI.user_CS] ; suck out the CS and IP + PUSH [SI.user_IP] + PUSH [SI.user_CS] ; suck out the CS and IP + PUSH [SI.user_IP] + POP WORD PTR ES:[PDB_Exit] + POP WORD PTR ES:[PDB_Exit+2] + XOR AX,AX + MOV DS,AX + POP DS:[addr_int_terminate] ; save them where we can get them later + POP DS:[addr_int_terminate+2] ; when the child exits. +IF NOT IBM + MOV WORD PTR [DMAADD],80h + MOV DS,[CurrentPDB] + MOV WORD PTR [DMAADD+2],DS +ENDIF +IF IBM + PUSH DX + PUSH DS + MOV DS,[CurrentPDB] + MOV DX,80h + MOV AH,SET_DMA + INT int_command + POP DS + POP DX +ENDIF + TEST BYTE PTR [exec_func],exec_func_no_execute + JZ exec_go + + LDS SI,DWORD PTR [exec_init_SP] ; get stack + LES DI,DWORD PTR [exec_blk] ; and block for return + MOV ES:[DI].exec1_SS,DS ; return SS + + DEC SI ; 'push' default AX + DEC SI + MOV DS:[SI],BX ; save default AX reg + MOV ES:[DI].exec1_SP,SI ; return 'SP' + + LDS AX,DWORD PTR [exec_init_IP] + MOV ES:[DI].exec1_CS,DS ; initial entry stuff + + MOV ES:[DI].exec1_IP,AX + transfer SYS_RET_OK + +exec_go: +IF IBM + CALL restore_ctrlc ; restore value of ctrl-c checker +ENDIF + LDS SI,DWORD PTR [exec_init_IP] ; get entry point + CLI +IF NOT IBM + MOV BYTE PTR INDOS,0 +ENDIF + MOV SS,[exec_init_SS] ; set up user's stack + ASSUME SS:NOTHING + MOV SP,[exec_init_SP] ; and SP + STI + PUSH DS ; fake long call to entry + PUSH SI + MOV ES,DX ; set up proper seg registers + MOV DS,DX + MOV AX,BX ; set up proper AX + procedure exec_long_ret,FAR + RET +exec_long_ret ENDP + +$Exec ENDP + + procedure exec_dealloc,near + ASSUME DS:NOTHING,ES:NOTHING + PUSH BX + MOV BX,arena_owner_system + CALL exec_do_change_owner + POP BX + return +exec_dealloc ENDP + + procedure exec_alloc,near + PUSH BX + MOV BX,[CurrentPDB] + CALL exec_do_change_owner + POP BX + return +exec_alloc ENDP + + procedure exec_do_change_owner,NEAR + PUSH DS + PUSH AX + MOV AX,[exec_environ] + OR AX,AX + JZ exec_alloc_try_load + DEC AX + MOV DS,AX + MOV DS:[arena_owner],BX +exec_alloc_try_load: + MOV AX,[exec_load_block] + OR AX,AX + JZ exec_alloc_done + DEC AX + MOV DS,AX + MOV DS:[arena_owner],BX +exec_alloc_done: + POP AX + POP DS + RET +exec_do_change_owner ENDP + +IF IBM +SYS_RET_ERR: + CALL get_user_stack + PUSH [SI.user_f] + XOR AH,AH + MOV [SI.user_AX],AX + POPF + STC + JMP SYS_RET +SYS_RET_OK: + CALL get_user_stack + PUSH [SI.user_f] + POPF + CLC +SYS_RET: + PUSHF + CALL restore_ctrlc + POP [SI.user_f] + JMP exec_long_ret + +; +; get_user_stack returns the user's stack (and hence registers) in DS:SI +; + procedure get_user_stack,NEAR + PUSH SS + POP DS + ASSUME DS:RESGROUP + LDS SI,DWORD PTR [user_SP] + RET +get_user_stack ENDP +; +; restore value of the ctrl-c checker +; + procedure restore_ctrlc + PUSH AX + PUSH DX + MOV DL,CS:[exec_ctrlc] + MOV AX,(Set_Ctrl_C_Trapping SHL 8) + 1 ; Put it back + INT int_command + POP DX + POP AX + RET +restore_ctrlc ENDP + +ZEXECCODESIZE EQU $-ZERO +ZEXECCODEEND LABEL BYTE + PUBLIC ZEXECCODEEND +ZEXEC_CODE ENDS +ENDIF diff --git a/EXEMES.ASM b/EXEMES.ASM new file mode 100644 index 0000000000000000000000000000000000000000..542ec127572f5b51a37a1b9e3b441da55d23a458 GIT binary patch literal 768 zcmY#@f|AUVoKyt`1s{KB#}HQq4c7=)BPUNkO$Fc7;^M^g)M8#PUM@FBpI}!71qIi@ zP_Q-wUapX!P>={*$j?7S0jvz9-o-J*5u`BK)!oh!T)aa#3nxNoIbYLTXV_ei29=$Uh*<;8voTmy%hWtx#N$n4Ahy3-LCR-ENr`x}^oh z3VEriDXA$6x(Z2&#ip5?4PLUM>a_001>1xD)^Y literal 0 HcmV?d00001 diff --git a/FAT.ASM b/FAT.ASM new file mode 100644 index 0000000..b1a4863 --- /dev/null +++ b/FAT.ASM @@ -0,0 +1,362 @@ +; +; FAT operations for MSDOS +; + +INCLUDE DOSSEG.ASM + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xlist +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + +TITLE FAT - FAT maintenance routines +NAME FAT + + i_need CURBUF,DWORD + i_need CLUSSPLIT,BYTE + i_need CLUSSAVE,WORD + i_need CLUSSEC,WORD + i_need THISDRV,BYTE + i_need DEVCALL,BYTE + i_need CALLMED,BYTE + i_need CALLRBYT,BYTE + i_need BUFFHEAD,DWORD + i_need CALLXAD,DWORD + i_need CALLBPB,DWORD + +SUBTTL UNPACK -- UNPACK FAT ENTRIES +PAGE + +ASSUME SS:DOSGROUP + procedure UNPACK,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; BX = Cluster number +; ES:BP = Base of drive parameters +; Outputs: +; DI = Contents of FAT for given cluster +; Zero set means DI=0 (free cluster) +; SI Destroyed, No other registers affected. Fatal error if cluster too big. + + CMP BX,ES:[BP.dpb_max_cluster] + JA HURTFAT + CALL MAPCLUSTER +ASSUME DS:NOTHING + MOV DI,[DI] + JNC HAVCLUS + PUSH CX + MOV CL,4 + SHR DI,CL + POP CX + STC +HAVCLUS: + AND DI,0FFFH + PUSH SS + POP DS + return + +HURTFAT: + PUSH AX + MOV AH,80H ; Signal Bad FAT to INT int_fatal_abort handler + MOV DI,0FFFH ; In case INT int_fatal_abort returns (it shouldn't) + invoke FATAL + POP AX ; Try to ignore bad FAT + return +UNPACK ENDP + +SUBTTL PACK -- PACK FAT ENTRIES +PAGE + procedure PACK,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; BX = Cluster number +; DX = Data +; ES:BP = Pointer to drive DPB +; Outputs: +; The data is stored in the FAT at the given cluster. +; SI,DX,DI all destroyed +; No other registers affected + + CALL MAPCLUSTER +ASSUME DS:NOTHING + MOV SI,[DI] + JNC ALIGNED + PUSH CX + MOV CL,4 + SHL DX,CL + POP CX + AND SI,0FH + JMP SHORT PACKIN +ALIGNED: + AND SI,0F000H +PACKIN: + OR SI,DX + MOV [DI],SI + LDS SI,[CURBUF] + MOV [SI.BUFDIRTY],1 + CMP BYTE PTR [CLUSSPLIT],0 + PUSH SS + POP DS +ASSUME DS:DOSGROUP + retz + PUSH AX + PUSH BX + PUSH CX + MOV AX,[CLUSSAVE] + MOV DS,WORD PTR [CURBUF+2] +ASSUME DS:NOTHING + ADD SI,BUFINSIZ + MOV [SI],AH + PUSH SS + POP DS +ASSUME DS:DOSGROUP + PUSH AX + MOV DX,[CLUSSEC] + MOV SI,1 + XOR AL,AL + invoke GETBUFFRB + LDS DI,[CURBUF] +ASSUME DS:NOTHING + MOV [DI.BUFDIRTY],1 + ADD DI,BUFINSIZ + DEC DI + ADD DI,ES:[BP.dpb_sector_size] + POP AX + MOV [DI],AL + PUSH SS + POP DS + POP CX + POP BX + POP AX + return +PACK ENDP + +SUBTTL MAPCLUSTER - BUFFER A FAT SECTOR +PAGE + procedure MAPCLUSTER,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; ES:BP Points to DPB +; BX Is cluster number +; Function: +; Get a pointer to the cluster +; Outputs: +; DS:DI Points to contents of FAT for given cluster +; DS:SI Points to start of buffer +; Carry set if cluster data is in high 12 bits of word +; No other registers effected + + MOV BYTE PTR [CLUSSPLIT],0 + PUSH AX + PUSH BX + PUSH CX + PUSH DX + MOV AX,BX + SHR AX,1 + ADD AX,BX + XOR DX,DX + MOV CX,ES:[BP.dpb_sector_size] + DIV CX ; AX is FAT sector # DX is sector index + ADD AX,ES:[BP.dpb_first_FAT] + DEC CX + PUSH AX + PUSH DX + PUSH CX + MOV DX,AX + XOR AL,AL + MOV SI,1 + invoke GETBUFFRB + LDS SI,[CURBUF] +ASSUME DS:NOTHING + LEA DI,[SI.BufInSiz] + POP CX + POP AX + POP DX + ADD DI,AX + CMP AX,CX + JNZ MAPRET + MOV AL,[DI] + PUSH SS + POP DS +ASSUME DS:DOSGROUP + INC BYTE PTR [CLUSSPLIT] + MOV BYTE PTR [CLUSSAVE],AL + MOV [CLUSSEC],DX + INC DX + XOR AL,AL + MOV SI,1 + invoke GETBUFFRB + LDS SI,[CURBUF] +ASSUME DS:NOTHING + LEA DI,[SI.BufInSiz] + MOV AL,[DI] + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV BYTE PTR [CLUSSAVE+1],AL + MOV DI,OFFSET DOSGROUP:CLUSSAVE +MAPRET: + POP DX + POP CX + POP BX + MOV AX,BX + SHR AX,1 + POP AX + return +MAPCLUSTER ENDP + +SUBTTL FATREAD -- CHECK DRIVE GET FAT +PAGE +ASSUME DS:DOSGROUP,ES:NOTHING + + procedure FAT_operation,NEAR +FATERR: + AND DI,STECODE ; Put error code in DI + MOV AH,2 ; While trying to read FAT + MOV AL,BYTE PTR [THISDRV] ; Tell which drive + invoke FATAL1 + + entry FATREAD +ASSUME DS:DOSGROUP,ES:NOTHING + +; Function: +; If disk may have been changed, FAT is read in and buffers are +; flagged invalid. If not, no action is taken. +; Outputs: +; ES:BP = Base of drive parameters +; All other registers destroyed + + MOV AL,BYTE PTR [THISDRV] + invoke GETBP + MOV AL,DMEDHL + MOV AH,ES:[BP.dpb_UNIT] + MOV WORD PTR [DEVCALL],AX + MOV BYTE PTR [DEVCALL.REQFUNC],DEVMDCH + MOV [DEVCALL.REQSTAT],0 + MOV AL,ES:[BP.dpb_media] + MOV BYTE PTR [CALLMED],AL + PUSH ES + PUSH DS + MOV BX,OFFSET DOSGROUP:DEVCALL + LDS SI,ES:[BP.dpb_driver_addr] ; DS:SI Points to device header +ASSUME DS:NOTHING + POP ES ; ES:BX Points to call header + invoke DEVIOCALL2 + PUSH SS + POP DS +ASSUME DS:DOSGROUP + POP ES ; Restore ES:BP + MOV DI,[DEVCALL.REQSTAT] + TEST DI,STERR + JNZ FATERR + XOR AH,AH + XCHG AH,ES:[BP.dpb_first_access] ; Reset dpb_first_access + MOV AL,BYTE PTR [THISDRV] ; Use physical unit number + OR AH,BYTE PTR [CALLRBYT] + JS NEWDSK ; new disk or first access? + JZ CHKBUFFDIRT + return ; If Media not changed +CHKBUFFDIRT: + INC AH ; Here if ?Media..Check buffers + LDS DI,[BUFFHEAD] +ASSUME DS:NOTHING +NBUFFER: ; Look for dirty buffers + CMP AX,WORD PTR [DI.BUFDRV] + retz ; There is a dirty buffer, assume Media OK + LDS DI,[DI.NEXTBUF] + CMP DI,-1 + JNZ NBUFFER +; If no dirty buffers, assume Media changed +NEWDSK: + invoke SETVISIT +NXBUFFER: + MOV [DI.VISIT],1 + CMP AL,[DI.BUFDRV] ; For this drive? + JNZ SKPBUFF + MOV WORD PTR [DI.BUFDRV],00FFH ; Free up buffer + invoke SCANPLACE +SKPBUFF: + invoke SKIPVISIT + JNZ NXBUFFER + LDS DI,ES:[BP.dpb_driver_addr] + TEST [DI.SDEVATT],ISFATBYDEV + JNZ GETFREEBUF + context DS + MOV BX,2 + CALL UNPACK ; Read the first FAT sector into CURBUF + LDS DI,[CURBUF] + JMP SHORT GOTGETBUF +GETFREEBUF: +ASSUME DS:NOTHING + PUSH ES ; Get a free buffer for BIOS to use + PUSH BP + LDS DI,[BUFFHEAD] + invoke BUFWRITE + POP BP + POP ES +GOTGETBUF: + ADD DI,BUFINSIZ + MOV WORD PTR [CALLXAD+2],DS + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV WORD PTR [CALLXAD],DI + MOV AL,DBPBHL + MOV AH,BYTE PTR ES:[BP.dpb_UNIT] + MOV WORD PTR [DEVCALL],AX + MOV BYTE PTR [DEVCALL.REQFUNC],DEVBPB + MOV [DEVCALL.REQSTAT],0 + MOV AL,BYTE PTR ES:[BP.dpb_media] + MOV [CALLMED],AL + PUSH ES + PUSH DS + PUSH WORD PTR ES:[BP.dpb_driver_addr+2] + PUSH WORD PTR ES:[BP.dpb_driver_addr] + MOV BX,OFFSET DOSGROUP:DEVCALL + POP SI + POP DS ; DS:SI Points to device header +ASSUME DS:NOTHING + POP ES ; ES:BX Points to call header + invoke DEVIOCALL2 + POP ES ; Restore ES:BP + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV DI,[DEVCALL.REQSTAT] + TEST DI,STERR + JNZ FATERRJ + MOV AL,BYTE PTR ES:[BP.dpb_media] + LDS SI,[CALLBPB] +ASSUME DS:NOTHING + CMP AL,BYTE PTR [SI.BPMEDIA] + JZ DPBOK + invoke $SETDPB + LDS DI,[CALLXAD] ; Get back buffer pointer + MOV AL,BYTE PTR ES:[BP.dpb_FAT_count] + MOV AH,BYTE PTR ES:[BP.dpb_FAT_size] + MOV WORD PTR [DI.BUFWRTCNT-BUFINSIZ],AX ;Correct buffer info +DPBOK: + context ds + MOV AX,-1 + TEST ES:[BP.dpb_current_dir],AX + retz ; If root, leave as root + MOV ES:[BP.dpb_current_dir],AX ; Path may be bad, mark invalid + return + +FATERRJ: JMP FATERR + +FAT_operation ENDP + +do_ext + +CODE ENDS + END + \ No newline at end of file diff --git a/FC.ASM b/FC.ASM new file mode 100644 index 0000000..21ed991 --- /dev/null +++ b/FC.ASM @@ -0,0 +1,1684 @@ + title File Compare Routine for MSDOS 2.0 + +;-----------------------------------------------------------------------; +; Revision History: ; +; ; +; V1.0 Rev. 0 10/27/82 M.A.Ulloa ; +; ; +; Rev. 1 10/28/82 M.A.Ulloa ; +; Changed switch names and added binary compare using the ; +; -b switch. ; +; ; +; Rev. 1 11/4/82 A.R. Reynolds ; +; Messages in separate module ; +; Also added header for MSVER ; +; ; +; Rev. 2 11/29/82 M.A. Ulloa ; +; Corrected sysntex problem with references to [base...] ; +; ; +; Rev. 3 01/03/83 M.A. Ulloa ; +; Stack is right size now. ; +; ; +;-----------------------------------------------------------------------; + +FALSE equ 0 +TRUE equ 0ffh + + +buf_size equ 4096 ;buffer size + + +;-----------------------------------------------------------------------; +; Description ; +; ; +; FC [-# -b -w -c] ; +; ; +; Options: ; +; ; +; -# were # is a number from 1 to 9, how many lines have to ; +; before the end of an area of difference ends. ; +; ; +; -b will force a binary comparation of both files. ; +; ; +; -w will cause all spaces and tabs to be compressed to a single ; +; space before comparing. All leading and trailing spaces and/or tabs ; +; in a line are ignored. ; +; ; +; -c will cause FC to ignore the case of the letters. ; +; ; +; Algorithm for text compare: (The one for binary comp. is trivial) ; +; ; +; The files are read into two separate buffers and the ; +; comparation starts. If two lines are found to be different in the ; +; two buffers, say line i of buffer A and line j of buffer B differ. ; +; The program will try to match line i with line j+1, then with line ; +; j+2 and so on, if the end of buffer is reached the program will ; +; recompact the buffer and try to read more lines into the buffer, if ; +; no more lines can be read because either the buffer is full, or the ; +; end of file was reached, then it will revert and try to match line ; +; j of buffer B to line i+1, i+2 and so on of buffer A. If an end of ; +; buffer is found, it tries to refill it as before. If no matches are ; +; found, then it will try to match line i+1 of buffer A to line j+1, ; +; j+2, j+3, .... of buffer B, if still no matches are found, it reverts ; +; again and tries to match line j+1 of buffer B with lines i+2, i+3,... ; +; of buffer A. And so on till a match is found. ; +; ; +; Once a match is found it continues chcking pairs of lines till ; +; the specified number are matched (option #, 3 by default), and then ; +; it prints the differing area in both files, each followed by the ; +; first line matched. ; +; ; +; If no match is found (the difference is bigger than the buffer) ; +; a "files different" message is printed. ; +; ; +; If one of the files finishes before another the remaining ; +; portion of the file (plus any ongoing difference) is printed out. ; +; ; +;-----------------------------------------------------------------------; + + + subttl Debug Macros + page + +m_debug macro str + local a,b + jmp short b +a db str,0dh,0ah,"$" +b: pushf + push dx + mov dx,offset code:a + push ds + push cs + pop ds + push ax + mov ah,9h + int 21h + pop ax + pop ds + pop dx + popf + endm + + +m_bname macro + local a0,a1,a2,b1,b2 + jmp short a0 +b1 db "------ buffer 1",0dh,0ah,"$" +b2 db "------ buffer 2",0dh,0ah,"$" +a0: pushf + push dx + cmp bx,offset dg:buf1 + je a1 + mov dx,offset code:b2 + jmp short a2 +a1: mov dx,offset code:b1 +a2: push ds + push cs + pop ds + push ax + mov ah,9h + int 21h + pop ax + pop ds + pop dx + popf + endm + + + page + + .SALL + .XLIST + include dossym.asm + .LIST + + subttl General Definitions + page + +CR equ 0dh +LF equ 0ah + + +;-----------------------------------------------------------------------; +; Offsets to buffer structure +; For text comparations: + +fname equ 0 ;file name ptr +fname_len equ 2 ;file name length +handle equ 4 ;handle +curr equ 6 ;current line ptr +lst_curr equ 8 ;last current line ptr +fst_sinc equ 10 ;first line towards a sinc ptr +fst_nosinc equ 12 ;first line out of sinc ptr +dat_end equ 14 ;ptr to last char of the buffer +buf_end equ 16 ;pointer to the end of the buffer +buf equ 18 ;pointer to the buffer + +; For binary comparations: + +by_read equ 6 ;bytes read into buffer + +;-----------------------------------------------------------------------; + + +code segment word +code ends + +const segment public word +const ends + +data segment word +data ends + +dg group code,const,data + + + subttl Constants Area + page + +const segment public word + +make db "MAUlloa/Microsoft/V10" +rev db "2" + +;----- CAREFULL WITH PRESERVING THE ORDER OF THE TABLE ----- +opt_tbl equ $ ;option table + +flg_b db FALSE +flg_c db FALSE +flg_s db FALSE +flg_w db FALSE +;----------------------------------------------------------- + +ib_first1 db FALSE ;flags used when comparing lines +ib_first2 db FALSE ; while in ignore white mode. + +m_num dw 3 ;lines that have to match before + ; reporting a match + +mtch_cntr dw 0 ;matches towards a sinc + +mode db FALSE ;If false then trying to match a line + ; from buf1 to lines in buf2. If true + ; then viceversa. + +sinc db TRUE ;Sinc flag, start IN SINC + +bend db 0 ;binary end of file flag, 0= none yet, + ; 1= file 1 ended, 2= file 2 ended + +base dd 0 ;base address of files for binary + ; comparations + +bhead_flg db false ;true if heading for binary comp. + ; has been printed already. + +;----------------------------------------------------------- +bp_buf equ $ ;binary compare difference template + +bp_buf1 db 8 dup(' ') ;file address + db 3 dup(' ') +bp_buf2 db 2 dup(' ') ;byte of file 1 + db 3 dup(' ') +bp_buf3 db 2 dup(' ') ;byte of file 1 + db CR,LF + +bp_buf_len equ $ - bp_buf ;length of template +;----------------------------------------------------------- + + EXTRN vers_err:byte,opt_err:byte,opt_e:byte,crlf:byte,opt_err_len:byte + EXTRN bhead_len:byte + EXTRN found_err_pre:byte,found_err_pre_len:byte + EXTRN found_err_post:byte,found_err_post_len:byte + EXTRN read_err_pre:byte,read_err_pre_len:byte + EXTRN read_err_post:byte,read_err_post_len:byte + EXTRN file_err:byte,file_err_len:byte + EXTRN bf1ne:byte,bf1ne_len:byte,bf2ne:byte,bf2ne_len:byte,bhead:byte + EXTRN int_err:byte,int_err_len:byte,dif_err:byte,dif_err_len:byte + EXTRN args_err:byte,args_err_len:byte,fname_sep:byte,fname_sep_len:byte + EXTRN diff_sep:byte,diff_sep_len:byte + +const ends + + + + subttl Data Area + page + +data segment word + +com_buf db 128 dup(?) ;command line buffer + +;----- Buffer structures +buf1 dw 11 dup(?) +buf2 dw 11 dup(?) + +; two extra for guard in case of need to insert a CR,LF pair +b1 db buf_size dup(?) +end_b1 db 2 dup(?) +b2 db buf_size dup(?) +end_b2 db 2 dup(?) + +data ends + + + + subttl MAIN Routine + page + +code segment +assume cs:dg,ds:nothing,es:nothing,ss:stack + +start: + jmp short FCSTRT +;-----------------------------------------------------------------------; +; Check version number + +HEADER DB "Vers 1.00" + +FCSTRT: +;Code to print header +; PUSH DS +; push cs +; pop ds +; MOV DX,OFFSET DG:HEADER +; mov ah,std_con_string_output +; int 21h +; POP DS + + mov ah,get_version + int 21h + cmp al,2 + jge vers_ok + mov dx,offset dg:vers_err + mov ah,std_con_string_output + int 21h + push es ;bad vers, exit a la 1.x + xor ax,ax + push ax + +badvex proc far + ret +badvex endp + + +vers_ok: + push cs + pop es + +assume es:dg + +;-----------------------------------------------------------------------; +; Copy command line + + mov si,80h ;command line address + cld + lodsb ;get char count + mov cl,al + xor ch,ch + inc cx ;include the CR + mov di,offset dg:com_buf + cld + rep movsb + + push cs + pop ds + +assume ds:dg + + + +;-----------------------------------------------------------------------; +; Initialize buffer structures + + mov bx,offset dg:buf1 + mov word ptr [bx].buf,offset dg:b1 + mov word ptr [bx].buf_end,offset dg:end_b1 + mov bx,offset dg:buf2 + mov word ptr [bx].buf,offset dg:b2 + mov word ptr [bx].buf_end,offset dg:end_b2 + + +;-----------------------------------------------------------------------; +; Process options + + mov ah,char_oper + mov al,0 + int 21h ;get switch character + mov si,offset dg:com_buf + +cont_opt: + call kill_bl + jc bad_args ;arguments missing + cmp al,dl ;switch character? + jne get_file ;no, process file names + cld + lodsb ;get option + call make_caps ;capitalize option + mov bx,offset dg:opt_tbl + + cmp al,'B' + je b_opt + cmp al,'C' + je c_opt + cmp al,'S' + je s_opt + cmp al,'W' + je w_opt + cmp al,'1' ;a number option? + jb bad_opt + cmp al,'9' + ja bad_opt + and al,0fh ;a number option, convert to binary + xor ah,ah ;zero high nibble + mov [m_num],ax + jmp short cont_opt + +bad_opt: ;a bad option: + push dx ; save switch character + mov [opt_e],al ; option in error + mov dx,offset dg:opt_err + mov cl,opt_err_len + call prt_err ; print error message + pop dx + jmp short cont_opt ; process rest of options + +b_opt: + mov di,0 + jmp short opt_dispatch + +c_opt: + mov di,1 + jmp short opt_dispatch + +s_opt: + mov di,2 + jmp short opt_dispatch + +w_opt: + mov di,3 + +opt_dispatch: + mov byte ptr dg:[bx+di],TRUE ;set the corresponding flag + jmp short cont_opt + + +bad_args: + mov dx,offset dg:args_err + mov cl,args_err_len + jmp an_err + + + +;-----------------------------------------------------------------------; +; Get the file names + +get_file: + dec si ;adjust pointer + call find_nonb ;find first non blank in com. buffer + jc bad_args ;file (or files) missing + mov byte ptr [di],0 ;nul terminate + mov dx,si ;pointer to file name + mov bx,offset dg:buf1 + mov word ptr [bx].fname,dx ;save pointer to file name + mov word ptr [bx].fname_len,cx ;file name length + mov ah,open + mov al,0 ;open for reading + int 21h + jc bad_file + mov word ptr [bx].handle,ax ;save the handle + + mov si,di + inc si ;point past the nul + call kill_bl ;find other file name + jc bad_args ;a CR found: file name missing + dec si ;adjust pointer + call find_nonb + mov byte ptr [di],0 ;nul terminate the file name + mov dx,si + mov bx,offset dg:buf2 + mov word ptr [bx].fname,dx ;save pointer to file name + mov word ptr [bx].fname_len,cx ;file name length + mov ah,open + mov al,0 ;open for reading + int 21h + jc bad_file + mov word ptr [bx].handle,ax ;save the handle + jmp short go_compare + +bad_file: + cmp ax,error_file_not_found + je sj01 + mov dx,offset dg:int_err + mov cl,int_err_len + jmp short an_err +sj01: + push cx ;save file name length + mov dx,offset dg:found_err_pre + mov cl,found_err_pre_len + call prt_err + pop cx + mov dx,si ;pointer to file name length + call prt_err + mov dx,offset dg:found_err_post + mov cl,found_err_post_len +an_err: + call prt_err + mov al,-1 ;return an error code + mov ah,exit + int 21h + + + +;-----------------------------------------------------------------------; +; CHECK COMPARE MODE + +go_compare: + cmp [flg_b],true ;do we do a binary comparation? + je bin_compare + jmp txt_compare + + + subttl Binary Compare Routine + page + +;-----------------------------------------------------------------------; +; COMPARE BUFFERS IN BINARY MODE + +bin_compare: + +;----- Fill in the buffers + + mov bx,offset dg:buf1 ;pointer to buffer structure + mov dx,word ptr[bx].buf ;pointer to buffer + mov si,dx ;save for latter comparation + call read_dat ;read into buffer + jc bad_datj ;an error + mov word ptr[bx].by_read,AX ;save ammount read + push ax ;save for now + + mov bx,offset dg:buf2 ;pointer to buffer structure + mov dx,word ptr[bx].buf ;pointer to buffer + mov di,dx ;save for comparation + call read_dat ;read into buffer +bad_datj: jc bad_dat ;an error + mov word ptr[bx].by_read,AX ;save ammount read + + pop cx ;restore byte count of buffer1 + cmp ax,cx ;compare byte counts + ja morein_b2 + jb morein_b1 + or ax,ax ;the same ammount, is it 0? + jne go_bcomp ;no,compare + jmp go_quit ;yes, all done.... + +morein_b2: + mov [bend],1 ;file 1 ended + jmp short go_bcomp + +morein_b1: + mov [bend],2 ;file 2 ended + mov cx,ax + +;----- Compare data in buffers + +go_bcomp: + mov ax,word ptr [base] ;load base addrs. to AX,BX pair + mov bx,word ptr [base+2] + add bx,cx ;add to base num. of bytes to + adc ax,0 ; compare. + mov word ptr [base],ax ;save total + mov word ptr [base+2],bx + +next_bcomp: + cld + jcxz end_check + repz cmpsb ;compare both buffers + jz end_check ;all bytes match + push cx ;save count so far + push ax + push bx + inc cx + sub bx,cx ;get file address of bytes that + sbb ax,0 ; are different. + call prt_bdif ;print difference + pop bx + pop ax + pop cx ;restore on-going comparation count + jmp short next_bcomp + +bnot_yet: + jmp bin_compare + +end_check: + cmp [bend],0 ;have any file ended yet? + je bnot_yet ;no, read in more data + cmp [bend],1 ;yes, was it file 1? + je bf1_ended ;yes, data left in file 2 + mov dx,offset dg:bf1ne + mov cl,bf1ne_len + jmp short bend_mes + +bf1_ended: + mov dx,offset dg:bf2ne + mov cl,bf2ne_len + +bend_mes: + xor ch,ch + call prout + jmp go_quit + + + + subttl Text Compare Routine + page + +;-----------------------------------------------------------------------; +; Fill in the buffers + +bad_dat: + mov dx,offset dg:file_err + mov cl,file_err_len + jmp an_err + + +txt_compare: + + mov bx,offset dg:buf1 + mov dx,word ptr [bx].buf + mov word ptr [bx].fst_nosinc,dx + mov word ptr [bx].curr,dx + + call fill_buffer + jc bad_dat + + mov bx,offset dg:buf2 + mov dx,word ptr [bx].buf + mov word ptr [bx].fst_nosinc,dx + mov word ptr [bx].curr,dx + + call fill_buffer + jc bad_dat + + +;-----------------------------------------------------------------------; +; COMPARE BUFFERS IN TEXT MODE + +another_line: + call go_match ;try to match both current lines + jc sj02 ;a match + jmp no_match ;no match, continue.... +sj02: + cmp byte ptr[sinc],true ;are we in SINC? + je sj04 + mov ax,[mtch_cntr] + or ax,ax ;first line of a possible SINC? + jnz sj03 + mov bx,offset dg:buf1 + mov word ptr [bx].fst_sinc,si ;yes, save curr line buffer 1 + mov bx,offset dg:buf2 + mov word ptr [bx].fst_sinc,di ;save curr line buffer 2 +sj03: + inc ax ;increment match counter + mov [mtch_cntr],ax ;save number of matches + cmp m_num,ax ;enough lines matched for a SINC? + jne sj04 ;not yet, match some more + mov [sinc],true ;yes, flag we are now in sinc + call print_diff ;print mismatched lines + + + +;-----------------------------------------------------------------------; +; Advance current line pointer in both buffers + +sj04: + mov bx,offset dg:buf1 + call adv_b + jnc sj05 + jmp no_more1 +sj05: + mov word ptr[bx].curr,si + mov bx,offset dg:buf2 + call adv_b + jnc sj051 + jmp no_more2 +sj051: + mov word ptr[bx].curr,si + jmp another_line ;continue matching + + + +;-----------------------------------------------------------------------; +; Process a mismatch + +no_match: + cmp [sinc],true ;are we in SINC? + jne sj06 + mov [sinc],false ;not any more.... + mov bx,offset dg:buf1 + mov word ptr [bx].fst_nosinc,si ;save current lines + mov word ptr [bx].lst_curr,si + mov bx,offset dg:buf2 + mov word ptr [bx].fst_nosinc,di + mov word ptr [bx].lst_curr,di +sj06: + mov [mtch_cntr],0 ;reset match counter + cmp [mode],true + je sj09 + +;----- MODE A ----- + mov bx,offset dg:buf2 + call adv_b ;get next line in buffer (or file) + jc sj08 ;no more lines in buffer +sj07: + mov word ptr [bx].curr,si + jmp another_line +sj08: + mov [mode],true ;change mode + mov si,word ptr [bx].lst_curr + mov word ptr [bx].curr,si + mov bx,offset dg:buf1 + mov si,word ptr [bx].lst_curr + mov word ptr [bx].curr,si + call adv_b ;get next line + jc no_more1 ;no more lines fit in buffer 1 + mov word ptr [bx].lst_curr,si + jmp short sj10 + +;----- MODE B ----- +sj09: + mov bx,offset dg:buf1 + call adv_b ;get next line in buffer (or file) + jc sj11 ;no more lines in buffer +sj10: + mov word ptr [bx].curr,si + jmp another_line + +sj11: + mov [mode],false + mov si,word ptr [bx].lst_curr + mov word ptr [bx].curr,si + mov bx,offset dg:buf2 + mov si,word ptr [bx].lst_curr + mov word ptr [bx].curr,si + call adv_b ;get next line + jc no_more2 ;no more lines fit in buffer 2 + mov word ptr [bx].lst_curr,si + jmp sj07 + + + +;-----------------------------------------------------------------------; +; Process end of files + +no_more1: + cmp ax,0 ;end of file reached? + jz xj1 + jmp dif_files ;no, difference was too big +xj1: + cmp [sinc],true ;file1 ended, are we in SINC? + je xj3 + jmp no_sinc +xj3: + mov bx,offset dg:buf2 + call adv_b ;advance current line in buf2 + jnc xj5 + jmp go_quit ;file2 ended too, terminate prog. +xj5: + +;----- File 1 ended but NOT file 2 + mov bx,offset dg:buf1 + call print_head + mov bx,offset dg:buf2 + call print_head + call print_all ;print the rest of file2 + jmp go_quit + + +no_more2: + cmp ax,0 ;end of file reached? + jz xj2 + jmp dif_files ;no, difference was too big +xj2: + cmp [sinc],true ;file1 ended, are we in SINC? + je xj4 + jmp no_sinc +xj4: + mov bx,offset dg:buf1 + call adv_b ;advance current line in buf2 + jnc xj6 + jmp go_quit ;file2 ended too, terminate prog. +xj6: + +;----- File 2 ended but NOT file 1 + mov bx,offset dg:buf1 + call print_head + call print_all ;print the rest of file1 + mov bx,offset dg:buf2 + call print_head + jmp go_quit + + + +no_sinc: + mov bx,offset dg:buf1 + call print_head + call print_all + mov bx,offset dg:buf2 + call print_head + call print_all + jmp go_quit + + + +dif_files: + mov dx,offset dg:dif_err + mov cl,dif_err_len + jmp an_err + +go_quit: + mov al,0 + mov ah,exit + int 21h + + + subttl Subroutines: make caps + page + +;-----------------------------------------------------------------------; +; CAPIALIZES THE CHARACTER IN AL ; +; ; +; entry: ; +; AL has the character to Capitalize ; +; ; +; exit: ; +; AL has the capitalized character ; +; ; +; Called from MAIN and go_match ; +;-----------------------------------------------------------------------; +make_caps: + cmp al,'a' + jb sa1 + cmp al,'z' + jg sa1 + and al,0dfh +sa1: ret + + + subttl Subroutines: kill_bl + page + +;-----------------------------------------------------------------------; +; Get rid of blanks in command line. ; +; ; +; entry: ; +; SI points to the first character on the line to scan. ; +; ; +; exit: ; +; SI points to the next char after the first non-blank ; +; char found. ; +; Carry Set if a CR found ; +; ; +; modifies: ; +; SI and AX ; +; ; +; Called from MAIN ; +;-----------------------------------------------------------------------; +kill_bl: + cld ;increment +sb1: lodsb ;get rid of blanks + cmp al,' ' + je sb1 + cmp al,9 + je sb1 + cmp al,CR + clc ;assume not a CR + jne sb2 + stc ;a CR found, set carry +sb2: ret + + + subttl Subroutines: find_nonb + page + +;-----------------------------------------------------------------------; +; Find the first non-blank in a line ; +; ; +; entry: ; +; SI points to the line buffer ; +; ; +; exit: ; +; DI pointer to the first blank found (incl. CR) ; +; CX character count of non-blanks ; +; Carry Set if a CR was found ; +; ; +; modifies: ; +; AX ; +; ; +; Called from MAIN ; +;-----------------------------------------------------------------------; +find_nonb: + push si ;save pointer + xor cx,cx ;zero character count + cld +sc1: + lodsb + cmp al,' ' + je sc2 + cmp al,9 + je sc2 + cmp al,CR + je sc2 + inc cx ;inc character count + jmp short sc1 +sc2: + dec si + mov di,si + pop si + cmp al,CR + jne sc3 + stc + ret +sc3: + clc + ret + + + subttl Subroutines: prt_bdif + page + +;-----------------------------------------------------------------------; +; Print a binary difference ; +; ; +; entry: ; +; AX,BX file address of diference ; +; SI pointer to one past byte in buffer1 ; +; DI pointer to one past byte in buffer2 ; +; ; +; modifies: ; +; AX, DX and CX ; +; ; +; called from bin_compare ; +;-----------------------------------------------------------------------; +prt_bdif: + cmp [bhead_flg],true ;have we peinted head yet? + je bhead_ok + mov [bhead_flg],true ;no, set flag + push ax ;print heading + mov dx,offset dg:bhead + mov cl,bhead_len + xor ch,ch + call prout + pop ax + +bhead_ok: + mov dx,di ;conver file address + mov di,offset dg:bp_buf1 + push ax + mov al,ah + call bin2hex + pop ax + call bin2hex + mov al,bh + call bin2hex + mov al,bl + call bin2hex + + mov di,offset dg:bp_buf2 ;convert byte from file 1 + mov al, byte ptr[si-1] + call bin2hex + + mov di,offset dg:bp_buf3 ;convert byte from file 2 + push si + mov si,dx + mov al, byte ptr[si-1] + pop si + call bin2hex + + mov di,dx ;print result + mov dx,offset dg:bp_buf + mov cx,bp_buf_len + call prout + ret + + + subttl Subroutines: bin2hex + page + +;-----------------------------------------------------------------------; +; Binary to ASCII hex conversion ; +; ; +; entry: ; +; AL byte to convert ; +; DI pointer to were the two result ASCII bytes should go ; +; ; +; exit: ; +; DI points to one past were the last result byte whent ; +; ; +; modifies: ; +; AH and CL ; +; ; +; Called from prt_bdif ; +;-----------------------------------------------------------------------; +bin2hex: + mov cl,4 + ror ax,cl ;get the high nibble + and al,0fh ;mask of high nible + call pt_hex + rol ax,cl ;get the low nibble + and al,0fh ;mask.... + +pt_hex: + cmp al,0ah ;is it past an A ? + jae pasta + add al,30h + jmp short put_hex +pasta: + add al,37h +put_hex: + stosb ;place in buffer + ret + + + subttl Subroutines: go_match + page + +;-----------------------------------------------------------------------; +; Match current lines ; +; ; +; exit: ; +; Carry set if the match reset otherwise ; +; SI Current line of buff1 ; +; DI Current line of buff2 ; +; ; +; ; +; modifies: ; +; AX,BX,CX,DX and BP ; +; ; +; Called from txt_compare ; +;-----------------------------------------------------------------------; +go_match: + mov bx,offset dg:buf1 + mov si,word ptr[bx].curr + push si + mov bp,si ;save line pointer + call find_eol + mov dx,cx ;save length of line + mov bx,offset dg:buf2 + mov si,word ptr[bx].curr + push si + mov di,si + call find_eol + cmp cx,dx ;compare lengths + jne sd1 ;they do not match + mov si,bp ;restore line pointer + jcxz sd4 ;both length = 0, they match + push cx ;save the length + cld + repz cmpsb ;compare strings + pop cx ;restore the length + jz sd4 ;they match +sd1: + cmp [flg_w],true ;do we ignore multiple whites? + je ib_compare ;yes, go compare + cmp [flg_c],true ;do we ignore case differences? + je ic_compare ;yes, go compare +sd3: + clc ;they don't match + jmp short sd5 +sd4: + stc +sd5: + pop di ;curr2 + pop si ;curr1 + ret + + + page + +;-----------------------------------------------------------------------; +; Compare ignoring case differences. + +ic_compare: + pop di ;get pointer to lines + pop si + push si ;re-save pointers + push di +sd8: + mov al,byte ptr [si] ;get next char. of first line + call make_caps + mov bl,al ;save capitalized char + mov al,byte ptr [di] ;get next chra. of second line + call make_caps + cmp al,bl + jne sd3 ;they do not match.... + inc si ;advance pointers + inc di + loop sd8 ;loop for the line lengths + jmp short sd4 ;they match + + + page + +;-----------------------------------------------------------------------; +; Compare compressing whites and ignoring case differences if +; desired too. + +ib_compare: + mov [ib_first1],true ;we start by the first char in the + mov [ib_first2],true ; in the lines. + pop di ;get pointer to lines + pop si + push si ;re-save pointers + push di +sd9: + mov al,byte ptr [si] ;get next char. of first line + call isa_white ;is it a white? + jnc sd12 ;no, compare.... +sd10: + mov al,byte ptr [si+1] ;peek to next, + call isa_white ; it is a white too? + jnc sd11 + inc si ; yes, + jmp short sd10 ; compress all whites to a blank +sd11: + cmp [ib_first1],true ;is this the first char. of the line? + jne sd111 ;no, it stays a white + inc si ;ignore the white + jmp short sd12 +sd111: + cmp al,CR ;is this the last char. of the line + jne sd112 ;no, it stays a white + inc si ;yes, ignore the whites + jmp short sd12 +sd112: + mov al,' ' ;no more whites found + +sd12: + cmp [ib_first1],true ;is this the first char. of the line? + jne sd121 ;no, continue + mov [ib_first1],false ;yes, reset the flag +sd121: + cmp [flg_c],true ;do we ignore case? + jne sd122 ;no,.... + call make_caps +sd122: + mov bl,al ;save char + mov al,byte ptr [di] ;get next chra. of second line + call isa_white + jnc sd15 +sd13: + mov al,byte ptr [di+1] ;peek to next as before + call isa_white + jnc sd14 + inc di + jmp short sd13 +sd14: + cmp [ib_first2],true ;is this the first char. of the line? + jne sd141 ;no, it stays a white + inc di ;ignore the white + jmp short sd15 +sd141: + cmp al,CR ;is this the last char. of the line + jne sd142 ;no, it stays a white + inc si ;yes, ignore the whites + jmp short sd15 +sd142: + mov al,' ' + +sd15: + cmp [ib_first2],true ;is this the first char. of the line? + jne sd151 ;no, continue + mov [ib_first2],false ;yes, reset the flag +sd151: + cmp [flg_c],true ;do we ignore case? + jne sd152 ;no,.... + call make_caps +sd152: + cmp al,bl + je sd153 + jmp sd3 ;they do not match.... +sd153: + cmp al,CR ;have we reached the end? + jne sd154 ;no, continue.... + jmp sd4 ;yes, they match +sd154: + inc si ;no, advance pointers + inc di + jmp sd9 ;loop for the line lengths + + +isa_white: + cmp al,' ' ;is it a space? + je sdx1 + cmp al,09h ;is it a tab? + je sdx1 + clc ;if not a white return with carry clear + ret +sdx1: + stc ;is a white return with carry set + ret + + + page + +;-----------------------------------------------------------------------; +find_eol: + xor cx,cx ;zero count + cld +sd6: + lodsb + cmp al,CR + je sd7 + inc cx + jmp short sd6 +sd7: + ret + + + subttl Subroutines: adv_b + page + +;-----------------------------------------------------------------------; +; Get the next line in the buffer ; +; ; +; It will attempt to get the next current line from the buffer ; +; if it fails, it will force a refill, and if some data is read in ; +; then it will return the next current line. ; +; ; +; entry: ; +; BX pointer to buffer structure ; +; ; +; exit: ; +; SI pointer to next line (if any) ; +; Carry set if no more lines available. If carry set then: ; +; AX End Code: 0 = end of file reached ; +; 1 = no room in buffer for a line ; +; ; +; modifies: ; +; CX,DX and DI ; +; ; +; Called from txt_compare ; +;-----------------------------------------------------------------------; +adv_b: + call get_nextl + jc se1 + ret +se1: + call refill + jnc se0 + ret +se0: + call get_nextl + ret + + + subttl Subroutines: get_nextl + page + +;-----------------------------------------------------------------------; +; Returns the next line in a buffer ; +; (next from current or next from pointer) ; +; ; +; entry: ; +; BX pointer to buffer structure ; +; (SI pointer to line, if calling get_next) ; +; ; +; exit: ; +; SI pointer to next line ; +; Carry set if no more lines available ; +; ; +; modifies: ; +; DI and CX ; +; ; +; Called from adv_b and print_diff (in the case of get_next) ; +;-----------------------------------------------------------------------; +get_nextl: + mov si,word ptr [bx].curr +get_next: + mov cx,word ptr [bx].dat_end + sub cx,si + mov di,si + mov al,LF + cld + repnz scasb + mov si,di ;pointer to next line + jnz se2 ;not found + clc + ret +se2: + inc si ;point past the LF + stc + ret + + + subttl Subroutines: refill + page + +;-----------------------------------------------------------------------; +; Refill a buffer ; +; ; +; It will refill a buffer with data from the corresponding ; +; file. It will first recompact the buffer to make room for the new ; +; data. If in SINC then it will move the current line to the top of ; +; the buffer, and read the data from the end of this line till the ; +; end of the buffer. ; +; If NOT in SINC then it will recompact the buffer by moving ; +; all lines between the first to go out of SINC till the current line ; +; to the top of the buffer, and then reading data after the current ; +; line. ; +; When recompacting the buffer it relocates all pointers to ; +; point to the new locations of the respective lines. ; +; Some of the pointers may be pointing to meaningless locations ; +; before the relocation, and consecuently they will be pointing to ; +; even less meaningfull locations after relocation. ; +; After reading the data it normalizes the buffer to make sure ; +; that no partially full lines are present at the end of the buffer. If ; +; after recompacting and reading some character it is found that the ; +; characters read do not constitute a full line, then it will return ; +; with an error code. It will also return with an error code if it ; +; attempts to read past the end of file. ; +; ; +; entry: ; +; BX pointer to buffer structure ; +; ; +; exit: ; +; Carry set if no chars read into the buffer. If carry set then: ; +; AX End Code: 0 = end of file reached ; +; 1 = no room in the buffer for a line ; +; ; +; modifies: ; +; CX,DX,SI and DI ; +; ; +; Called from adv_b ; +;-----------------------------------------------------------------------; +refill: + +;----- Calculate ammount to move & pointer relocation factor. + + cmp [sinc],true + jne sf1 + mov si,word ptr [bx].curr + jmp short sf2 +sf1: + mov si,word ptr [bx].fst_nosinc +sf2: + mov di,word ptr [bx].buf + mov cx,word ptr [bx].dat_end + + mov dx,si ;calculate pointer relocation factor + sub dx,di ;DX = factor + jz sf3 ;no room in buffer + sub cx,si ;calculate ammount of data to move + inc cx ;CX = ammount + +;----- Move data + + cld ;auto decrement + rep movsb + +;----- Relocate pointers + + sub word ptr [bx].curr,dx + sub word ptr [bx].lst_curr,dx + sub word ptr [bx].fst_sinc,dx + sub word ptr [bx].fst_nosinc,dx + sub word ptr [bx].dat_end,dx + +sf3: + mov dx,word ptr [bx].dat_end + inc dx ;empty part starts here + +;----- fill the buffer + + call fill_buffer + ret + + + subttl Subroutines: fill_buffer + page + +;-----------------------------------------------------------------------; +; Fill the data buffers ; +; ; +; It will fill the buffer from the pointer to the end of buffer ; +; and normalize the buffer. ; +; ; +; entry: ; +; BX pointer to buffer structure ; +; DX pointer to buffer (or part of buffer) ; +; ; +; exit: ; +; Carry set if no chars read into the buffer. If carry set then: ; +; AX End Code: 0 = end of file reached ; +; 1 = no room in the buffer for a line ; +; ; +; modifies: ; +; AX,CX,DX and DI ; +; ; +; Called from txt_compare and refill ; +;-----------------------------------------------------------------------; +fill_buffer: + push bx + call read_dat ;get data + jc bad_read + or ax,ax ;zero chars read? + jz rd_past_eof + call nor_buf + mov di,cx ;save normalized char. count + mov bp,dx ;save data end for now + +;----- seek for old partial line + + or ax,ax ;is the seek value = 0 ? + jz sg1 ;yes, do not seek + mov dx,ax + neg dx + mov cx,-1 + mov al,1 ;seek from current position + mov ah,lseek + int 21h + jc bad_read ;error mesage (BX already in stack) + +sg1: + mov cx,di ;restore normalized char count. + or cx,cx ;char count = 0 due to normalization? + jz no_room + + pop bx + mov word ptr [bx].dat_end,bp + clc + ret + +bad_read: + mov dx,offset dg:read_err_pre + mov cl,read_err_pre_len + call prt_err ;print error message + pop bx + mov dx,word ptr[bx].fname + mov cx,word ptr[bx].fname_len + call prt_err ;print file name + mov dx,offset dg:read_err_post + mov cl,read_err_post_len + jmp an_err + +no_room: + mov ax,1 + jmp short sg2 + +rd_past_eof: + xor ax,ax +sg2: + pop bx + stc + ret + + + subttl Subroutines: read_dat + page + +;-----------------------------------------------------------------------; +; ; +; entry: ; +; DX pointer to data area (buffer or part of buffer) ; +; ; +; exit: ; +; AX character count or error code (from DOS read) ; +; Carry set if error condition ; +; ; +; modifies: ; +; BX and CX ; +; ; +; Called from fill_buffer, print_all and bin_compare ; +;-----------------------------------------------------------------------; +read_dat: + mov cx,word ptr [bx].buf_end + mov bx,word ptr [bx].handle + sub cx,dx ;ammount to read to buff1 + mov ah,read + int 21h + ret + + + subttl Subroutines: nor_buf + page + +;-----------------------------------------------------------------------; +; Normalize buffers so they do not have partially full ; +; lines at the end. If character count is less than the buffer size ; +; then it checks that the last line is terminated by a CR,LF pair. ; +; If it is not it inserts a CR,LF at the end. It returns a seek value ; +; for the buffer corresponding to the number of characters in the ; +; incomplete line at the end of the buffer (if any). This can be used ; +; to start reading from the beggining of the incomplete line on next ; +; time the buffer is loaded. ; +; ; +; ENTRY: ; +; DX buffer pointer ; +; AX character count read ; +; CX character count requested ; +; ; +; EXIT: ; +; DX pointer to last char in buffer (normalized) ; +; CX character count (normalized) ; +; AX seek value ; +; ; +; MODIFIES: ; +; DI ; +; ; +; Called from fill_buffer ; +;-----------------------------------------------------------------------; +nor_buf: + mov di,dx + add di,ax + dec di ;points to last char in buffer + cmp ax,cx ;were all chars. requested read? + je sm7 ;yes, buffer full + cmp byte ptr[di],1ah ;terminated with a ^Z ? + jne sm1 + dec di ;point to previous character + dec ax ;decrement character count +sm1: cmp byte ptr[di],lf ;is last char a LF? + je sm6 + cmp byte ptr[di],cr ;is it a CR then? + je sm5 + add ax,2 ;two more chars in buffer + inc di +sm2: mov byte ptr[di],cr +sm3: inc di + mov byte ptr[di],lf +sm4: mov cx,ax ;new character count + mov dx,di ;pointer to last char + xor ax,ax ;seek = 0 + ret + +sm5: + inc ax ;one more char in buffer + jmp short sm3 + +sm6: + cmp byte ptr[di-1],cr ;is previous char a CR? + je sm4 + inc ax ;no, one more char in buffer + jmp short sm2 + +sm7: + push ax ;save char count + mov cx,ax + mov al,LF + std + repnz scasb ;search for last LF + pop ax ;restore char count + jnz bad_line ;none found, line too big + inc di ;point to last LF + mov dx,di + inc cx ;ammount of chars in buffer + sub ax,cx ;seek value + ret + +bad_line: ;full line not possible, return + mov dx,di ; with AX=count, CX=0 and DX= + ret ; old last char in buffer pointer. + + + + subttl Subroutines: print_diff + page + +;-----------------------------------------------------------------------; +; print the difference between buffers ; +; ; +; It will print the mismatched lines. First it prints a heading ; +; with the first file name, then the lines that differ from file 1, ; +; then a heading with the second file name, and then the lines that ; +; differ in file 2 . ; +; The lines that differ are considered to start from fst_nosinc ; +; till fst_sinc. ; +; ; +; Called from txt_compare ; +;-----------------------------------------------------------------------; +print_diff: + mov bx,offset dg:buf1 + call print_head ;print heading for file 1 + mov dx,word ptr [bx].fst_nosinc + mov si,word ptr [bx].fst_sinc + call get_next ;get pointer to next line + mov cx,si + sub cx,dx ;get character count + call prout + mov bx,offset dg:buf2 + call print_head ;print heading for file 1 + mov dx,word ptr [bx].fst_nosinc + mov si,word ptr [bx].fst_sinc + call get_next ;get pointer to next line + mov cx,si + sub cx,dx ;get character count + call prout + mov dx,offset dg:diff_sep + mov cl,diff_sep_len + xor ch,ch + call prout ;print difference separator + ret + + + subttl Subroutines: print_head + page + +;-----------------------------------------------------------------------; +; Print heading for difference ; +; ; +; entry: ; +; BX pointer to buffer structure ; +; ; +; modifies: ; +; AX,CX and DX ; +; ; +; Called from txt_compare and print_diff ; +;-----------------------------------------------------------------------; +print_head: + mov dx,offset dg:fname_sep + mov cl,fname_sep_len + xor ch,ch + call prout + mov dx,word ptr [bx].fname + mov cx,word ptr [bx].fname_len + call prout + mov dx,offset dg:CRLF + mov cx,2 + call prout + ret + + + subttl Subroutines: print_all + page + +;-----------------------------------------------------------------------; +; Print the rest of a file ; +; ; +; If in SINC it will print the file from the fst_nosinc line ; +; till the end of the file. If NOT in SINC then it will print from ; +; the current line of the buffer to the end of the file. ; +; ; +; entry: ; +; BX pointer to buffer structure ; +; ; +; modifies: ; +; AX,CX and DX ; +; ; +; Called from txt_compare ; +;-----------------------------------------------------------------------; +print_all: + cmp [sinc],true ;are we in SINC? + jne so1 + mov dx,word ptr [bx].curr + jmp short so2 +so1: + mov dx,word ptr [bx].fst_nosinc +so2: + mov cx,word ptr [bx].dat_end + inc cx + +prt_again: + sub cx,dx ;ammount of data to write + call prout ;write it out + +;----- Read more data to the buffer + push bx ;save pointer to buffer struct + mov dx,word ptr [bx].buf + call read_dat + jnc so3 + jmp bad_read ;print error (BX in stack) +so3: + or ax,ax ;zero chars read? + jne so4 + pop bx ;all done writting + ret +so4: + pop bx + mov cx,word ptr [bx].buf_end + jmp short prt_again ;print next buffer full + + + subttl Subroutines: prout and prt_err + page + +;-----------------------------------------------------------------------; +; ; +;-----------------------------------------------------------------------; +prout: + push bx + mov bx,stdout + mov ah,write + int 21h + pop bx + ret + + +;-----------------------------------------------------------------------; +; ; +;-----------------------------------------------------------------------; +prt_err: + push bx + xor ch,ch + jcxz retpbx + mov bx,stderr + mov ah,write + int 21h +retpbx: + pop bx + ret + +code ends + + page + + +stack segment stack + + dw 128 dup(?) + +stack ends + + + end start + \ No newline at end of file diff --git a/FCB.ASM b/FCB.ASM new file mode 100644 index 0000000..bf8cf64 --- /dev/null +++ b/FCB.ASM @@ -0,0 +1,512 @@ +; +; FCB management routines for MSDOS +; + +INCLUDE DOSSEG.ASM + +IFNDEF KANJI +KANJI EQU 0 ;FALSE +ENDIF + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xlist +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + + i_need Name1,BYTE + i_need NumIO,BYTE + i_need DevFCB,BYTE + i_need Creating,BYTE + i_need ExtFCB,BYTE + i_need Attrib,BYTE + i_need SpaceFlag,BYTE + i_need Current_Country,WORD + + procedure MakeFcb,NEAR +DRVBIT EQU 2 +NAMBIT EQU 4 +EXTBIT EQU 8 + MOV BYTE PTR [SpaceFlag],0 + XOR DL,DL ; Flag--not ambiguous file name + TEST AL,DRVBIT ; Use current drive field if default? + JNZ DEFDRV + MOV BYTE PTR ES:[DI],0 ; No - use default drive +DEFDRV: + INC DI + MOV CX,8 + TEST AL,NAMBIT ; Use current name fields as defualt? + XCHG AX,BX ; Save bits in BX + MOV AL," " + JZ FILLB ; If not, go fill with blanks + ADD DI,CX + XOR CX,CX ; Don't fill any +FILLB: + REP STOSB + MOV CL,3 + TEST BL,EXTBIT ; Use current extension as default + JZ FILLB2 + ADD DI,CX + XOR CX,CX +FILLB2: + REP STOSB + XCHG AX,CX ; Put zero in AX + STOSW + STOSW ; Initialize two words after to zero + SUB DI,16 ; Point back at start + TEST BL,1 ; Scan off separators if not zero + JZ SKPSPC + CALL SCANB ; Peel off blanks and tabs + CALL DELIM ; Is it a one-time-only delimiter? + JNZ NOSCAN + INC SI ; Skip over the delimiter +SKPSPC: + CALL SCANB ; Always kill preceding blanks and tabs +NOSCAN: + CALL GETLET + JBE NODRV ; Quit if termination character + CMP BYTE PTR[SI],":" ; Check for potential drive specifier + JNZ NODRV + INC SI ; Skip over colon + SUB AL,"@" ; Convert drive letter to binary drive number + JBE BADDRV ; Valid drive numbers are <= NUMIO + CMP AL,BYTE PTR [NUMIO] + JBE HAVDRV +BADDRV: + MOV DL,-1 +HAVDRV: + STOSB ; Put drive specifier in first byte + INC SI + DEC DI ; Counteract next two instructions +NODRV: + DEC SI ; Back up + INC DI ; Skip drive byte +NORMSCAN: + MOV CX,8 + CALL GETWORD ; Get 8-letter file name + CMP BYTE PTR [SI],"." + JNZ NODOT + INC SI ; Skip over dot if present + MOV CX,3 ; Get 3-letter extension + CALL MUSTGETWORD +NODOT: + MOV AL,DL + return + +NONAM: + ADD DI,CX + DEC SI + return + +GETWORD: + CALL GETLET + JBE NONAM ; Exit if invalid character + DEC SI +; +; UGH!!! Horrible bug here that should be fixed at some point: +; If the name we are scanning is longer than CX, we keep on reading! +; +MUSTGETWORD: + CALL GETLET +; +; If spaceFlag is set then we allow spaces in a pathname +; + JB FILLNAM + JNZ MustCheckCX + TEST BYTE PTR [SpaceFlag],0FFh + JZ FILLNAM + CMP AL," " + JNZ FILLNAM + +MustCheckCX: + JCXZ MUSTGETWORD + DEC CX + CMP AL,"*" ; Check for ambiguous file specifier + JNZ NOSTAR + MOV AL,"?" + REP STOSB +NOSTAR: + STOSB + + IF KANJI + CALL TESTKANJ + JZ NOTDUAL3 + JCXZ BNDERR ; Attempt to straddle boundry + MOVSB ; Transfer second byte + DEC CX + JMP SHORT NOTDUAL3 +BNDERR: + MOV BYTE PTR ES:[DI-1]," " ; patch up that space + JMP MustGetWord ; go back and scan until delim + +NOTDUAL3: + ENDIF + + CMP AL,"?" + JNZ MUSTGETWORD + OR DL,1 ; Flag ambiguous file name + JMP MUSTGETWORD +FILLNAM: + MOV AL," " + REP STOSB + DEC SI + return + +SCANB: + LODSB + CALL SPCHK + JZ SCANB + DEC SI + return +MakeFCB ENDP + +; +; NameTrans is used by FindPath to scan off an element +; of a path. We must allow spaces in pathnames +; Inputs: SS - DOSGROUP +; DS:SI name +; Outputs: DS:SI advanced over spot +; ES:DI point to after Name1 +; registers modified: AX, BX, CX, DX +procedure NameTrans,near + MOV BYTE PTR [SpaceFlag],1 + PUSH SS + POP ES + MOV DI,OFFSET DOSGROUP:NAME1 + PUSH DI + MOV AL,' ' + MOV CX,11 + REP STOSB + XOR AL,AL + MOV DL,AL + STOSB + POP DI + CMP BYTE PTR [SI],'.' + + IF KANJI + JZ FOOBAR + CALL NORMSCAN + CMP [NAME1],0E5H + retnz + MOV [NAME1],5 + return +FOOBAR: + ELSE + JNZ NORMSCAN + ENDIF + + MOVSB + LODSB + CALL PATHCHRCMP + JZ GOTDOTNAME + OR AL,AL + JZ GOTDOTNAME + CMP AL,'.' + JNZ BADDOTS + STOSB + LODSB + CALL PATHCHRCMP + JZ GOTDOTNAME + OR AL,AL + JZ GOTDOTNAME + DEC SI +BADDOTS: + DEC SI +GOTDOTNAME: + DEC SI + XOR AL,AL + return +nametrans ENDP + +SUBTTL BUILDFCB -- MAKE A BLANK FCB FOR A DEVICE +PAGE + procedure BuildFCB,near +ASSUME DS:DOSGROUP,ES:DOSGROUP + +; Function: +; Build a blank FCB for I/O to a device +; Outputs: +; Same as GETNAME + + MOV AX," " + MOV DI,OFFSET DOSGROUP:DEVFCB+8 ; Point to extent field + STOSW + STOSB ; Blank out extent field + XOR AX,AX + MOV CX,10 + REP STOSW ; Fill FCB with zeros + STOSB + invoke DATE16 + MOV DI,OFFSET DOSGROUP:DEVFCB+22 + XCHG AX,DX + STOSW + XCHG AX,DX + STOSW + XCHG AX,BX ; But device number in AH + MOV BX,OFFSET DOSGROUP:DEVFCB + MOV SI,DI + XOR AL,AL ; Set zero, clear carry + return +BuildFCB ENDP + +SUBTTL MOVENAME, LODNAME -- EXAMINE FCB AND SETUP +PAGE + procedure FCB_move,NEAR + + entry MOVNAMENOSET + MOV DI,1 + JMP SHORT MOVSTART + + entry MOVNAME +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS, DX point to FCB or extended FCB +; Outputs: +; DS:DX point to normal FCB +; DS:SI point after end of NAME/EXT in FCB +; ES = DOSGROUP +; If file name OK: +; [NAME1] has name in upper case +; All registers destroyed +; Carry set if bad file name or drive + + XOR DI,DI +MOVSTART: + MOV WORD PTR [CREATING],0E500H ; Not creating, not DEL *.* + MOV SI,DX + LODSB + MOV [EXTFCB],AL ; Set flag if extended FCB in use + XOR AH,AH ; Set default attributes + CMP AL,-1 ; Is it an extended FCB? + JNZ HAVATTRB + ADD DX,7 ; Adjust to point to normal FCB + ADD SI,6 + MOV AH,[SI-1] ; Attribute byte + LODSB ; Get drive select byte +HAVATTRB: + invoke GETTHISDRV + retc + PUSH DS + PUSH DX + PUSH SI + PUSH AX +; +; DS:DX is pointer to good FCB +; DS:SI is same +; +; Move the file into Name1 and UCASE it +; + PUSH DI + context ES + MOV DI,OFFSET DOSGROUP:NAME1 + CALL LodName + POP DI + JC DrvNoSet + +; +; are we setting current dir info? +; + OR DI,DI + JNZ DrvNoSet ; do not set dir info + +; +; check for device name first, eliminating drive hits on devices +; + context DS + invoke DEVNAME + JNC DrvNoSet ; we have a device + +; +; make sure that everything is current +; + invoke FATREAD + ASSUME DS:NOTHING,ES:NOTHING + MOV BYTE PTR [ATTRIB],attr_directory+attr_hidden+attr_system + invoke GETCURRDIR +DrvNoSet: + POP AX + MOV BYTE PTR [ATTRIB],AH + + POP SI + POP DX + POP DS + context ES + MOV DI,OFFSET DOSGROUP:NAME1 + + entry LODNAME +; Inputs: DS:SI point to an FCB +; ES:DI point to an FCB +; Outputs: DS:SI point to after FCB +; ES:DI point to after FCB +; FCB from DS:SI copied and ucased to ES:DI +; Carry set if there was an error. +; Destroys AX,CX + CMP BYTE PTR [SI]," " ; Don't allow blank as first letter + STC ; In case of error + retz + + IF KANJI + MOV CX,8 + CMP BYTE PTR [SI],0E5H + JNZ MOVCHK + INC SI + MOV AL,5 + STOSB + MOVSB + MOV CX,6 +MOVCHK: + CALL GETLET + JB RET6 + JNZ STOLET ; Is it a delimiter? + CMP AL," " ; This is the only delimiter allowed + STC ; In case of error + JNZ RET6 +STOLET: + STOSB + CALL TESTKANJ + JZ MOVLP ;No + LODSB ;Get second byte + DEC CX + JZ BOUNDERR ;Attempt to cross boundry + STOSB +MOVLP: + LOOP MOVCHK + MOV CX,3 +MOVCHK2: + CALL GETLET + JB RET6 + JNZ STOLET2 ; Is it a delimiter? + CMP AL," " ; This is the only delimiter allowed + STC ; In case of error + retnz +STOLET2: + STOSB + CALL TESTKANJ + JZ MOVLP2 ;No + LODSB ;Get second byte + DEC CX + JNZ DOSTORE +BOUNDERR: ;Attempt to cross boundry + STC + return + +DOSTORE: + STOSB +MOVLP2: + LOOP MOVCHK2 + ELSE + MOV CX,11 +MOVCHK: + CALL GETLET + JB RET6 + JNZ STOLET ; Is it a delimiter? + CMP AL," " ; This is the only delimiter allowed + STC ; In case of error + retnz +STOLET: + STOSB + LOOP MOVCHK + ENDIF + + CLC ; Got through whole name - no error +RET6: return +FCB_Move ENDP + +SUBTTL GETLET, DELIM -- CHECK CHARACTERS AND CONVERT +PAGE + procedure GetLet,NEAR +; Get a byte from [SI], convert it to upper case, and compare for delimiter. +; ZF set if a delimiter, CY set if a control character (other than TAB). + LODSB + + CMP AL,"a" + JB CHK1 + CMP AL,"z" + JA CHK1 + SUB AL,20H ; Convert to upper case +CHK1: + PUSH SI + MOV SI,[Current_Country] + ADD SI,Map_call + PUSH CS ; CS for long return + CALL WORD PTR CS:[SI] + POP SI + entry CHK + CMP AL,"." + retz + CMP AL,'"' + retz + CALL PATHCHRCMP + retz + CMP AL,"[" + retz + CMP AL,"]" + retz + +DELIM: + CMP AL,":" ; Allow ":" as separator in IBM version + retz + + CMP AL,"<" + retz + CMP AL,"|" + retz + CMP AL,">" + retz + + CMP AL,"+" + retz + CMP AL,"=" + retz + CMP AL,";" + retz + CMP AL,"," + retz +SPCHK: + CMP AL,9 ; Filter out tabs too + retz +; WARNING! " " MUST be the last compare + CMP AL," " + return +GetLet ENDP + + procedure PATHCHRCMP,NEAR + CMP AL,'/' + retz + CMP AL,'\' + return +PathChrCMP ENDP + + IF KANJI + procedure TESTKANJ,NEAR + CMP AL,81H + JB NOTLEAD + CMP AL,9FH + JBE ISLEAD + CMP AL,0E0H + JB NOTLEAD + CMP AL,0FCH + JBE ISLEAD +NOTLEAD: + PUSH AX + XOR AX,AX ;Set zero + POP AX + return + +ISLEAD: + PUSH AX + XOR AX,AX ;Set zero + INC AX ;Reset zero + POP AX + return +TESTKANJ ENDP + ENDIF +do_ext + +CODE ENDS + END diff --git a/FCMES.ASM b/FCMES.ASM new file mode 100644 index 0000000000000000000000000000000000000000..1fc52cb49f3bd68e1f5fa7e0b845bbbf51f2985a GIT binary patch literal 2048 zcmY#@f|AUVoKyt`1-HzcR0Ze!+=9fSRE41Y(vr-)RE4zsA_d=I7yn=dBRvCNE?zF@ zAc(fq!cs89ASHvB%f}7OR)7m8W`NYXIr;>s3LqQ=YF)1}i0h%w6ltU9E4#U7nnU~9236b22Qc=Bykb(FL!H0PY zX0}pLYGR5)YEe;skwRu3$WzE_A%23X1$hctmX`~`gLw(nPbl&b!=RCeY8KQ>peO+a zC(J@6r^FO+Jb@wxnv=k$fD8ed0Mh`9XK2!g=>;XLlGLKS#2f`zknfauxu7cGCV*oJ zDhM(Gno$rYXlZGIi_&5RP&t~CnU!Wi zlv)HzgYXnzti;O&Qx7)~Q1S-lQ4~|)Izh&O`~gw{ zH3gE5kd1+xhmWD81GXL<4DgZ!Y$V9pFgrl@fr~XnK7!c?3S5`Ol0=1^)U*t>{@4tFE0L`F6bBnEOLtQJhoODRSav8j0}yj%=a1^|M9 BLmdDB literal 0 HcmV?d00001 diff --git a/FIND.ASM b/FIND.ASM new file mode 100644 index 0000000..7c82768 --- /dev/null +++ b/FIND.ASM @@ -0,0 +1,932 @@ + title MSDOS V2.0 FIND + +;--------------------------------------------------------------------; +; Revision History: ; +; ; +; V1.1 8/23/82 M.A.Ulloa ; +; ; +; V1.2 9/22/82 M.A.Ulloa ; +; Added the -c and -n options ; +; ; +; 9/23/82 M.A.Ulloa ; +; Added DOS version number control ; +; ; +; 10/07/82 Rev.2 M.A.Ulloa ; +; Changed quote for double quotes, and added ; +; file name printing ; +; ; +; 10/20/82 Rev.3 M.A.Ulloa ; +; Modified IBM name to FIND, and changed the text ; +; of some messages. ; +; ; +; 10/25/82 Rev.4 M.A.Ulloa ; +; Changed name to FIND and all messages to the ; +; IBM form. ; +; ; +; 10/27/82 Rev.5 M.A.Ulloa ; +; Made the correct exit on version check in case ; +; of a 1.x DOS. ; +; ; +; 11/4/82 Rev. 5 A.R. Reynolds ; +; Messages moved to external module ; +; ; +; 11/10/82 Rev. 6 M.A. Ulloa ; +; Corrected problem with line numbers, and a problem ; +; with seeking for 0 chars. ; +; ; +; 03/30/83 Rev. 7 M.A. Ulloa ; +; Added patch area for bug fixing. ; +; ; +; 04/14/83 Rev. 8 M.A. Ulloa ; +; Made changes for Kanji characters. (uhg!) ; +; ; +;--------------------------------------------------------------------; + +FALSE equ 0 +TRUE equ NOT FALSE + +KANJI equ FALSE ;set to true is kanji vers. + +;--------------------------------------------------------------------; +; FIND program following the standart UNIX operation. ; +; ; +; FORMAT: ; +; find {option} string {filename {filename} {...}} ; +; ; +; NOTES: ; +; 1) String arguments HAVE to be enclosed ; +; in double quotes. (Two double quotes if a ; +; doble quote is to be included). Only ONE ; +; string argument is presently allowed. ; +; ; +; 2) Options are available: ; +; v All lines but those matching are considered ; +; c Only print a count of matching lines ; +; n Each line is preceded by its relative ; +; line number in the file. ; +; ; +; - Options can be Upper or lower case. ; +; - Format: The switch character followed by an options ; +; character. I.e.: In the IBM PC: /v ; +; ; +; 3) The program returns: ; +; 0 - OK, and some matches ; +; 2 - Some Error ; +; ; +; 4) The maximum line size is determined by ; +; buffer size. Bigger lines will bomb the program. ; +; ; +; 5) If no file name is given then it will asssume ; +; the input is comming from the Standart Input. NO ; +; errors are reported when reading from Standart Input. ; +;--------------------------------------------------------------------; + +code segment public +assume cs:code,ss:code,ds:nothing,es:nothing + + +CR equ 0dh ;A Carriage Return +LF equ 0ah ;A Line Feed +quote_char equ 22h ;A double quote character + + +buffer_size equ 4096 ;file buffer size +st_buf_size equ 128 ;string arg. buffer size +fname_buf_size equ 64 ;file name buffer size + + +;----- DOS EQUATES --------------------------------------------------; +std_in equ 0 ;STD input handle +std_out equ 1 ;STD output handle +std_err equ 2 ;STD error handle +dos_ent equ 21h ;DOS entry point + +std_con_string_output equ 9 +get_version equ 48 +char_oper equ 55 ;get configuration parameters +open equ 61 ;DOS std open code +close equ 62 ;DOS std close code +read equ 63 ;DOS std read code +write equ 64 ;DOS std write code +lseek equ 66 ;DOS file seek +exit equ 76 ;DOS process exit code + + +;----- Misc Data -----------------------------------------------; +make db "***MAUlloa/Microsoft/V12***" +rev db "8" + + +colon db ": " +n1_buf db "[" +n2_buf db 8 dup(0) ;buffer for number conversion + + + +;----- OPTION FLAGS -------------------------------------------------; +; If a flag is set (0ffh) then the option has been selected, if +;reset (0) then it has been not. All options are reset initially. +; NOTE: the order of this table has to remain consistent with the +;options dispatch code. If any changes are made they have to +;correspond with the code. + +opt_tbl: + +v_flg db 0 +c_flg db 0 +n_flg db 0 +x_flg db 0 ;not used +l_flg db 0 ;not used + + +;----- LINE COUNTERS ------------------------------------------------; +mtch_cntr dw 0 ;matched lines counter +line_cntr dw 0 ;line counter + + +;----- MAIN ROUTINE -------------------------------------------------; +start: + +;----- CHECK VERSION NUMBER -----------------------------------------; + + mov ah,get_version + int 21h + cmp al,2 + jge vers_ok + push cs + pop ds + mov dx,offset bad_vers + mov ah,std_con_string_output + int 21h + push es ;bad vers, exit a la 1.x + xor ax,ax + push ax + +badfart proc far ;(what a hack!!) + ret +badfart endp + +vers_ok: + + push cs ;load ES to the right area, + pop es ; for use with DI register + +assume es:code + +;--------------------------------------------------------------------; + + mov si,81h ;Start addrss. of commad line buf. + + call kill_bl ;Get rid of blanks + or bx,bx ;A CR found? + jz find_opt ;no, first find the options +args_missing: + mov dx,offset errmsg1 ;empty command line, no args: error. + mov cl,cs:errlen1 + call prt_err + mov al,2 ;error code for exit + jmp done + + +;----- FIND THE OPTION IF ANY ---------------------------------------; +find_opt: + mov ah,char_oper ;get the dos switch char. + mov al,0 + int dos_ent ;switch char in DL + push dx +another_opt: + lodsb ;get the first char of command line + cmp al,' ' ;a blank? + je cont_scan + cmp al,CR ;a Carriage Return + je args_missing + pop dx ;get switch character + cmp al,dl ;is it the switch char? + jne find_str ;no, no options: get the string + push dx ;save for another round + + lodsb ;get the option character + cmp al,' ' ;a blank? + je cont_scan ;yes, ignore and continue + cmp al,CR ;a CR? + je args_missing ;yes, error... + call make_caps ;Capitalize the character + mov bx,offset opt_tbl ;pointer to option flag table + + cmp al,'V' ;the v option? + je opt_v + cmp al,'C' ;the c option? + je opt_c + cmp al,'N' ;the n option? + je opt_n + + mov cs:errmsg5_opt,al ;save the option + mov dx,offset errmsg5 ;unknown option: error + mov cl,cs:errlen5 + call prt_err + mov dx,offset crlf ;print a CRLF + mov cx,2 + call prt_err + jmp another_opt ;process next option + +opt_v: + mov di,0 + jmp short opt_dispatch + +opt_c: + mov di,1 + jmp short opt_dispatch + +opt_n: + mov di,2 + +opt_dispatch: + mov es:byte ptr[bx+di],0ffh ;set the corresponding flag + jmp another_opt ;process the rest of the options + +cont_scan: + dec si ;adjust SI + call kill_bl ;get rid of blanks + or bx,bx ;A CR found? + jz another_opt ;no, test for other options + jmp args_missing ;yes, error... + + +;----- FIND STRING ARGUMENT -----------------------------------------; +find_str: + cmp al,quote_char ;string should start with a + jnz bad_str_err ; quote character, if not: error. + mov di,offset st_buffer ;String argument buffer addrss. + xor cx,cx ;Clear to keep string length. + +move_str: + lodsb + cmp al,CR ;if a CR is found in the string + jnz str_ok ; then it's a bad string +bad_str_err: + mov dx,offset errmsg2 ;bad string error message + mov cl,cs:errlen2 + call prt_err ;print the error. + mov al,2 + jmp done + +str_ok: + cmp al,quote_char ;look for a quote character + jnz move_char ;not an apost., move to buffer + lodsb ;an apost., check next char. + cmp al,quote_char ;another quote character? + je move_char ;yes, move it to the buffer + dec si ;no, adjust the pointer + mov es:st_length,cx ;store the string length + or cx,cx ;Is the string empty? + jnz other_args ;no: get the rest of the args. + mov al,1 ;empty: no matches(!?) + jmp done +move_char: + stosb ;put in buffer + inc cx ;increment string length + jmp move_str + + +;----- FIND THE FILE ARGUMENTS --------------------------------------; +other_args: ;Process the rest of the command + ; line arguments. + call kill_bl ;get rid of leading blanks + or bx,bx ;At least one argument necessary, + jz further_args ; if a CR not found: ok. + +;----- USE STD IN FOR INPUT -----------------------------------------; + push cs + pop ds + mov ax,std_in ;handle + jmp fill + +further_args: + call clr_cntrs ;set all counters to zero + mov di,offset file_name_buf ;Set pointer to the name buffer + xor cx,cx ;zero file name length +move_fname: + lodsb + cmp al,' ' ;A blank: end of file name, + je done_move + cmp al,CR ;A CR: idem. + je done_move + stosb ;store in name buffer + inc cx ;increment file name length + jmp move_fname +done_move: + dec si ;Adjust pointer for next round. + mov es:byte ptr[di],00h ;File names are null terminated + push si ;Save SI to continue com. line scan. + push ds ;Save DS register contents for + ; later because it points to the + ; rest of the arguments. + mov es:file_name_len,cx ;save the name length + +;----- OPEN FILE FOR READING ----------------------------------------; + push cs ;Load new DS with CS + pop ds + mov dx,offset file_name_buf ;addrss. of the file name + mov ah,open + mov al,0 ;file open for reading + int dos_ent ;call the DOS + jnc say_name ;if no carry then no errors + jmp open_error + +;----- PRINT FILE NAME ----------------------------------------------; +say_name: + push ax ;save file handle + mov dx,offset heading + mov cl,cs:heading_len + xor ch,ch + call prout + + mov dx,offset file_name_buf + mov cx,ds:file_name_len + call prout + + cmp ds:c_flg,0ffh ;count only flag set? + je xx1 + + mov dx,offset crlf + mov cx,2 + call prout + +xx1: + pop ax + +;----- Fill Buffer for Matching -------------------------------------; +fill: + mov bx,ax ;retrieve handle +refill: + mov dx,offset buffer ;data buffer addrss. + mov cx,buffer_size + mov ah,read + int dos_ent + jnc no_read_error ;if carry then read error + jmp read_error +no_read_error: + or ax,ax ;if ax=0 then all done + jnz go_match + cmp ds:c_flg,0ffh ;count only flag set? + jne sj2 + call print_count +sj2: + cmp bx,std_in ;Using STD IN? + jnz regular + jmp foo ;if so: all done, exit +regular: + mov ah,close ;otherwise close the file + int dos_ent + jmp scan_rest ;get another file + +;----- MATCH ROUTINE ------------------------------------------------; +;Note: If input is being taken from a file the stack contains +; (from top to bottom): +; - Pointer to the next command in the command line +; - Pointer to the program segment prefix (to be loaded into +; DS to access the command line. +; if the imput is from the standart input then NONE of it will be +; in the stack. + +go_match: + push bx ;save the file handle + mov bp,offset buffer ;ptr to first line of file + mov di,ax ;dispalcement from beg of buffer + + cmp ax,buffer_size-1 ;last line of the file? + jg no_last_line ;if yes, add a CRLF just in case + mov bx,bp + cmp byte ptr[bx+di-1],LF ;finished with a LF? + je no_last_line ;yes, it's an OK line. + mov byte ptr[bx+di],CR ;put a CR at the end of the data + inc di + mov byte ptr[bx+di],LF ;put a LF ... + inc di + +no_last_line: + push di ;save the # of chars. in the buffer + push bp + mov dx,ds:st_length ;length of the string arg. + dec dx ;adjust for later use + jmp short try_again + + +more_stuff_o: + jmp more_stuff + + + +;----- SCAN LINES IN THE BUFFER FOR A MATCH -------------------------; +;Note: at this point the stack contains (from top to bottom): +; - Stuff mentioned before +; - File Handle +; - Number of chars. left in the buffer from the next line. +; - Addrs. of the next line in the buffer. +; +; plus, DX has the adjusted length of the string argument. + +try_again: + inc ds:line_cntr ;increment line counter + pop bp ;addrs. of next line in the buffer + mov di,bp ;points to beg. of a line + pop cx ;get # of chars left in the buffer + mov bx,cx ;save in case a non-complete line + mov al,LF ;search for a Line Feed + jcxz more_stuff_o ;no chars left in buffer + repnz scasb + jnz more_stuff_o ;no full line left in buffer + + push cx ;save chars left in buffer + push di ;points to beg. of next line + mov cx,di + sub cx,bp ;length of the current line + mov bx,cx ;save in case it has a match + dec cx + dec cx ;CRLF characters discounted + jcxz try_again_opt ;if line empty go to next line + mov di,bp ;pointer to the beg. of current line +another_char: +; +; On entry: +; BX line length +; CX adjusted line length +; DX adjusted string argument length +; DI points to beg. of line +; + +IF KANJI + + push dx ;save for next line +lop: + pop dx + push dx + inc dx ;different algorithm! + mov si,offset st_buffer ;pointer to beg. of string argument + +comp_next_char: + push di + mov di,si + call is_prefix ;check for a prefix char + pop di + jnc nopre + lodsw + cmp cx,1 ; Can not compare a two byte char + jz try_again_opt1 ; if there is only one available + cmp ax,word ptr [di] + jz kmatch1 + call next_kchar ;no match, advance di to next kanji + jc try_again_opt1 ;not enough chars left in line + jmp short lop ;try another char in line + +nopre: + lodsb + cmp al,byte ptr [di] + jz kmatch + call next_kchar ;no match, advance di to next kanji + jc try_again_opt1 ;not enough chars left in line + jmp short lop ;try another char in line + +try_again_opt1: + pop dx + jmp try_again_opt + + +kmatch1: + dec dx ;last char had prefix so it was + ; long. +kmatch: + dec dx + jz a_matchk ; no chars left: a match! + call next_kchar + jc try_again_opt1 + jmp comp_next_char ; loop if chars left in arg. + +a_matchk: + pop dx + +ELSE + + mov si,offset st_buffer ;pointer to beg. of string argument + lodsb ;get first character of the str. arg. + repnz scasb ;search for a match in current line + jnz try_again_opt ;no match, try the next line + cmp cx,dx ;compare lengths, a full match is not + jb try_again_opt ; possible if CX < DX. + push di ;save addrs. of next char. in the line + push cx ;save the # of chars. left in the line + mov cx,dx ;get the adjusted string arg. length + jcxz a_match ;if a single char string, then match! + repz cmpsb ;compare string with line + jz a_match ;a match found, hurrah! + pop cx ;no match, get # of chars remaining + ; in the line. + pop di ;position of the next char. in the line + jmp another_char + + +;----- A MATCH: CHECK FOR THE v OPTION ------------------------------; +a_match: + pop ax ;adjust stack + pop ax +ENDIF + + cmp ds:v_flg,0ffh ;is flag set? + jne prt_line ;no, print the line + jmp try_again + +;----- NO MATCH: CHECK FOR THE v OPTION -----------------------------; +try_again_opt: + cmp ds:v_flg,0ffh ;is flag set? + jne try_again ;no goto next line + +;----- PRINT THE LINE WITH THE MATCH --------------------------------; +;Note: at this point the stack contains (top to bottom) +; - Stuff mentioned before +; +; plus, BP points to begginig of the current line, BX has the length +;of the current line including the CRLF, and DX the adjusted length of +;the string argument. + +prt_line: + cmp ds:c_flg,0ffh ;is count only flag set? + jne no_c_flg + inc ds:mtch_cntr ;yes, increment counter + jmp try_again + +no_c_flg: + push dx ;save the adjusted string arg. length + cmp ds:n_flg,0ffh ;is line number flag set? + jne no_n_flg + call prt_lcntr +no_n_flg: + mov dx,bp + mov cx,bx + call prout + pop dx ;restore + jmp try_again + +;----- READ MORE TEXT LINES INTO THE BUFFER -------------------------; +; The scanning routines have detected that the buffer does not +;contain a full line any more. More lines have to be read into the +;buffer. But first perform a seek on the file in order to re-read +;the non-complete line into the begining of the buffer. +; Uppon entry BP contains points to the begining of the non-complete +;line, and BX has the number of characters left in the buffer. +; The Stack contains (top to bottom): +; - Pointer to the next command in the command line +; - Pointer to the program segment prefix (to be loaded into +; DS to access the command line). +; - File handle. + +more_stuff: + mov dx,bx ;get chars left in buffer + pop bx ;get the handle + or dx,dx ;are there 0 left? + jz no_seek ;yes, do not seek + neg dx ;form two's complement + mov cx,-1 + mov al,1 ;seek from the current position + mov ah,lseek ;seek on file + int dos_ent + jc read_error +no_seek: + jmp refill ;no errors: refill the buffer +read_error: + cmp bx,std_in ;Using STD IN? + je foo ;if so: all done, exit + mov ah,close ;close the file + int dos_ent + mov dx,offset errmsg4_pre ;read error + mov cl,cs:errlen4_pre + call prt_file_name ;print the file name in error + mov dx,offset errmsg4_post ;read error + mov cl,cs:errlen4_post + jmp r_error + +;----- PRINT ERRORS -------------------------------------------------; +open_error: + mov dx,offset errmsg3_pre ;error in open operation + mov cl,cs:errlen3_pre + call prt_err_2 ;print error message + call prt_file_name ;print the file name in error + mov dx,offset errmsg3_post ;error in open operation + mov cl,cs:errlen3_post +r_error: + call prt_err_2 ;print error message + +;----- SCAN THE REST OF THE COMMAND LINE ----------------------------; +scan_rest: + pop ds ;restore pointer to comm. line + pop si ;restore pointer to next comm. + call kill_bl ;look for further args. + or bx,bx ;test for a CR + jnz foo + jmp further_args +foo: + mov al,0 ;Proper code +done: + mov ah,exit ;All done, exit with proper code. + int dos_ent + + +;--------------------------------------------------------------------; +; Get rid of blanks in command line. ; +; Advances the SI reg till the next non-blank character, if the ; +; character is a CR (0dh) then returns with BX non-zero, otherwise ; +; BX is zero. ; +; ; +; entry: ; +; SI points to the first character on the line to scan. ; +; ; +; exit: ; +; SI points to the first non-blank character found. ; +; BX contains 0D hex if the first non-blank found is ; +; a Carriage Return, otherwise it is 0. ; +; ; +; modifies: ; +; BX, SI, and AX ; +; ; +;--------------------------------------------------------------------; +kill_bl: + cld ;increment + xor bx,bx ;zero bx to start: no CR found +no_bl: + lodsb ;get rid of blanks + cmp al,' ' + je no_bl + cmp al,CR + jnz no_cr + mov bx,ax ;make bx non-zero (actually 0dh) +no_cr: + dec si ;adjust pointer + ret + + +;--------------------------------------------------------------------; +; Clear Counters ; +;--------------------------------------------------------------------; +clr_cntrs: + mov byte ptr es:mtch_cntr,0 + mov byte ptr es:line_cntr,0 + ret + +;--------------------------------------------------------------------; +; Print Count of Matched lines ; +; ; +; Modifies: AX,CX,DX and DI ; +;--------------------------------------------------------------------; +print_count: + push bx ;save handle + cmp bx,std_in ;using std_in? + jz sj3 ;if so do not print file name + + mov dx,offset colon + mov cx,2 + call prout ;print colon +sj3: + mov ax,ds:mtch_cntr + mov di,offset n2_buf ;buffer for characters + call bin2asc ;convert to ascii + mov dx,offset n2_buf + call prout ;print the number + mov dx,offset crlf + mov cx,2 + call prout ;print an end of line + pop bx + ret + + +;--------------------------------------------------------------------; +; Print relative line number ; +; ; +; Modifies: AX,CX and DI ; +;--------------------------------------------------------------------; +prt_lcntr: + push bx + push dx + mov ax,ds:line_cntr + mov di,offset n2_buf + call bin2asc + mov byte ptr[di],"]" + inc cx + inc cx + mov dx,offset n1_buf + call prout + pop dx + pop bx + ret + +;--------------------------------------------------------------------; +; Print string to STD_OUT ; +;--------------------------------------------------------------------; +prout: + mov bx,std_out + mov ah,write + int dos_ent + ret + + +;--------------------------------------------------------------------; +; Binary to Ascii conversion routine ; +; ; +; Entry: ; +; AX Binary number ; +; DI Points to one past the last char in the ; +; result buffer. ; +; ; +; Exit: ; +; Result in the buffer MSD first ; +; CX Digit count ; +; ; +; Modifies: ; +; AX,BX,CX,DX and DI ; +; ; +;--------------------------------------------------------------------; +bin2asc: + mov bx,0ah + xor cx,cx +go_div: + inc cx + cmp ax,bx + jb div_done + xor dx,dx + div bx + add dl,'0' ;convert to ASCII + push dx + jmp short go_div + +div_done: + add al,'0' + push ax + mov bx,cx +deposit: + pop ax + stosb + loop deposit + mov cx,bx + ret + + +;--------------------------------------------------------------------; +; Print the current file name ; +; ; +; modifies: ; +; DX, CX, BX and AX ; +;--------------------------------------------------------------------; +prt_file_name: + mov dx,offset file_name_buf ;print the file name + mov cx,ds:file_name_len ;retrive file name length + jmp short prt_err_2 + + +;--------------------------------------------------------------------; +; Print an error message to the Standart error ; +; ; +; entry: ; +; DX has the pointer to the message ; +; CX has the length of the message ; +; ; +; modifies: ; +; BX and AX ; +;--------------------------------------------------------------------; +prt_err: + push ds ;Save the current DS + push cs ;Make DS point to the right + pop ds ; place, for DOS use. + call prt_err_2 + pop ds + ret + +prt_err_2: + xor ch,ch + mov bx,std_err + mov ah,write + int dos_ent ;write error message + ret + + +;--------------------------------------------------------------------; +; CAPIALIZES THE CHARACTER IN AL ; +; ; +; entry: ; +; AL has the character to Capitalize ; +; ; +; exit: ; +; AL has the capitalized character ; +; ; +; modifies: ; +; AL ; +;--------------------------------------------------------------------; +make_caps: + cmp al,'a' + jb no_cap + cmp al,'z' + jg no_cap + and al,0dfh +no_cap: + ret + + + +IF KANJI + +;--------------------------------------------------------------------; +; ADVANCE POINTER TO NEXT KANJI CHARACTER ; +; ; +; entry: DI points to a Kanji string ; +; CX length in bytes of the string ; +; ; +; exit: DI points to next Kanji char ; +; CX has number of bytes left ; +; ; +; modifies: AX ; +; ; +;--------------------------------------------------------------------; +next_kchar: + jcxz no_kleft + call is_prefix + jnc no_p + inc di + dec cx + jcxz no_kleft ; for insurance +no_p: + inc di + dec cx + clc + ret + +no_kleft: + stc + ret + + +;--------------------------------------------------------------------; +; FIND OUT IS THE BYTE IS A KANJI PREFIX ; +; ; +; entry: DI points to a kanji string ; +; ; +; exit: Carry set if it is a kanji prefix ; +; ; +; modifies: AX ; +; ; +;--------------------------------------------------------------------; +is_prefix: + mov al,byte ptr [di] + cmp al,81h + jb nok + cmp al,0a0h + jb isk + cmp al,0e0h + jb nok + cmp al,0fdh + jb isk +nok: + clc + ret +isk: + stc + ret + +ENDIF + + +;----- PATCH AREA ---------------------------------------------------; + +patch_area dw 100h dup(?) + + + +;----- BUFFER AREA --------------------------------------------------; +st_length dw 0 ;String argumnet length +st_buffer db st_buf_size dup(?) ;String argument buffer + +file_name_len dw 0 ;File name length +file_name_buf db fname_buf_size+1 dup(?) ;File name buffer,(allow for + ; null at the end). + +buffer db buffer_size+1 dup(?) ;file buffer, the last byte is + ;a guard in case of forced insertion + ;of a CRLF pair. + +;----- ERROR MESSAGES -----------------------------------------------; + EXTRN bad_vers:byte,crlf:byte,errmsg1:byte,errlen1:byte,errmsg2:byte + EXTRN errmsg3_pre:byte,errlen3_pre:byte + EXTRN errmsg3_post:byte,errlen3_post:byte + EXTRN errmsg4_pre:byte,errlen4_pre:byte + EXTRN errmsg4_post:byte,errlen4_post:byte + EXTRN heading:byte,heading_len:byte,errlen2:byte + EXTRN errmsg5:byte,errmsg5_opt:byte,errlen5:byte +code ends + + +;----- STACK AREA ---------------------------------------------------; +stack segment stack + + dw 64 dup(?,?) +stack_top equ $ + +stack ends + + end start + \ No newline at end of file diff --git a/FINDMES.ASM b/FINDMES.ASM new file mode 100644 index 0000000000000000000000000000000000000000..cb120dbc0adcbb7925bf91370bba5b9f68ad252e GIT binary patch literal 1408 zcmY!YgObdWoKyt`1vgJW7X{zc;^M^g)M8#P5OfX#t58TSECn+RQZm3aI$`ao;G9@g zl$n^Gst}Y~Qd*S9%jM$+Q3cnVh*PgmW?rg-TWV?w$j;>a6p(8aic`~bQ}ap`3QCi5 zGLu0v5c3oi0z#d9Je?I3k`hzm%TkMqb&`v6(sWXbigJt74MB8HY95%*ElxLr@{M@8 z(6vJ}7{?bBr9u_K*}28(CP?C7HXZ}=i%SqDKsgX2pq!l4Jd^l>{NfT^hL}S2gX!Gj zbkq3!0xXI%QWH}$^U`&obbL-~9w=a70ilqR1ootoXI^rCQBi7giGquNumUKIGV}9P zlz6#7Aq7?fRjJ?{q~qfTG6NDChA<-(lt9VBO2IR)EHNiDMIo;=Hz~D9AwNx_Ah9Sh zH?<_Ss8~q{synr)2o&USy($X23Q+S9MjOGUp+*N+=9MH?fE4Bzp&5lxi!jOvWR$fM z#9VMp+2keWrh=T5mYI`k2bah%E>Ys;f^&<&sR`Y3x6GVWg}nR{g|z(Ayc7k9hMd$q zu)!!Hgm3{^4$0*F;u4Tbw4j6phA}w0k)=`00Vf4sE|_<~2@IQeAgKo8I!KDb?wz32 z#1u$KDrDv%d;>NY87hp^fdlq8^e0q#R^n$%I!g#(Z^P(`2&16Bw!11bhG16Jmw S=A{%PvS?~v3NIG}4FLdIRd4zL literal 0 HcmV?d00001 diff --git a/FORMAT.ASM b/FORMAT.ASM new file mode 100644 index 0000000..4140075 --- /dev/null +++ b/FORMAT.ASM @@ -0,0 +1,1627 @@ +;*************************************************************** +; +; 86-DOS FORMAT DISK UTILITY +; +; This routine formats a new disk,clears the FAT and DIRECTORY +; then optionally copies the SYSTEM and COMMAND.COM to this +; new disk +; +; SYNTAX: FORMAT [drive][/switch1][/switch2]...[/switch16] +; +; Regardless of the drive designator , the user will be +; prompted to insert the diskette to be formatted. +; +;*************************************************************** + +;Mod to ask for volume ID ARR 5/12/82 +; 05/19/82 Fixed rounding bug in CLUSCAL: ARR +;REV 1.5 +; Added rev number message +; Added dir attribute to DELALL FCB +;REV 2.00 +; Redone for 2.0 +;REV 2.10 +; 5/1/83 ARR Re-do to transfer system on small memory systems + +FALSE EQU 0 +TRUE EQU NOT FALSE + +IBMJAPVER EQU FALSE ; SET ONLY ONE SWITCH TO TRUE! +IBMVER EQU FALSE +MSVER EQU TRUE + +KANJI EQU FALSE + + .xlist + INCLUDE DOSSYM.ASM + .list + + +;FORMAT Pre-defined switches +SYSSW EQU 1 ; System transfer +VOLSW EQU 2 ; Volume ID prompt +OLDSW EQU 4 ; E5 dir terminator + + +DRNUM EQU 5CH + +RECLEN EQU fcb_RECSIZ+7 +RR EQU fcb_RR+7 + +;Per system file data structure + +FILESTRUC STRUC +FILE_HANDLE DW ? ; Source handle +FILE_SIZEP DW ? ; File size in para +FILE_SIZEB DD ? ; File size in bytes +FILE_OFFSET DD ? ; Offset in file (partial) +FILE_START DW ? ; Para number of start in buffer +FILE_DATE DW ? ; Date of file +FILE_TIME DW ? ; Time of file +FILE_NAME DB ? ; Start of name +FILESTRUC ENDS + +CODE SEGMENT PUBLIC 'CODE' + + ASSUME CS:CODE,DS:CODE,ES:CODE + + ORG 100H + +;For OEM module + PUBLIC SWITCHMAP,DRIVE + EXTRN HARDFLAG:BYTE ;0 = REMOVABLE MEDIA + EXTRN SWITCHLIST:BYTE,FATID:BYTE,FATSPACE:WORD + EXTRN STARTSECTOR:WORD,FREESPACE:WORD,INIT:NEAR + EXTRN DISKFORMAT:NEAR,BADSECTOR:NEAR,DONE:NEAR + EXTRN WRTFAT:NEAR + +;For FORMES module + EXTRN WAITYN:NEAR,REPORT:NEAR + PUBLIC PRINT,CRLF,DISP32BITS,UNSCALE,FDSKSIZ,SECSIZ,CLUSSIZ + PUBLIC SYSSIZ,BADSIZ + +START: + JMP SHORT FSTRT + +HEADER DB "Vers 2.10" + +FSTRT: + MOV SP,OFFSET STACK ;Use internal stack + +;Code to print header +; PUSH AX +; MOV DX,OFFSET HEADER +; CALL PRINT +; POP AX + +DOSVER_HIGH EQU 020BH ;2.11 in hex + PUSH AX ;Save DRIVE validity info + MOV AH,GET_VERSION + INT 21H + XCHG AH,AL ;Turn it around to AH.AL + CMP AX,DOSVER_HIGH + JAE OKDOS +GOTBADDOS: + MOV DX,OFFSET BADVER + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + INT 20H + +OKDOS: + + IF IBMVER ; IBM WANTS TO CHECK FOR ASSIGN.COM + XOR AX,AX + MOV ES,AX + MOV BX,ES:[4*21H] + MOV ES,ES:[4*21H+2] + CMP BX,122H + JNZ NO_ASSIGN + CMP ES:[109H],0807H + JNZ NO_ASSIGN + CMP ES:[103H],0201H + JNZ RE_ASSIGN + CMP ES:[105H],0403H + JNZ RE_ASSIGN + CMP ES:[107H],0605H + JZ NO_ASSIGN +RE_ASSIGN: + MOV DX,OFFSET ASGERR + CALL PRINT + JMP FEXIT2 +NO_ASSIGN: + PUSH CS + POP ES + ENDIF + + POP AX + + CMP AL,0FFH ;See if invalid drive specified + JNZ DRVGD ;If not proceed + MOV DX,OFFSET INVDRV ;Invalid drive message + CALL PRINT ;Print the message + JMP FEXIT2 ;Exit +DRVGD: + MOV AH,GET_DEFAULT_DRIVE ;Must get the default drive + INT 21H ;Default now in AL + MOV DEFALT,AL ;Save for later + ADD AL,"A" + MOV [BIODRV],AL + MOV [DOSDRV],AL + MOV [SYSDRV],AL + MOV [COMDRV],AL + MOV SI,DRNUM ;So we can get our parameters + LODSB ;Fetch drive designation + OR AL,AL ;See if specified + JNZ DRVSPEC ;If specfied proceed + MOV AL,DEFALT + INC AL +DRVSPEC: + DEC AL ;Drive designator now correct + MOV BYTE PTR DS:[DRNUM],AL ;And updated + MOV DRIVE,AL ;Save copy + MOV DX,OFFSET INT_23 + MOV AH,SET_INTERRUPT_VECTOR + MOV AL,23H + INT 21H ;Set ^C vector + ;Get all the swith information from the command line + XOR AX,AX + MOV AH,CHAR_OPER ;GET SWITCH CHARACTER + INT 21H ;CALL THE DOS + MOV [SWTCH],DL + + XOR BX,BX ;Store switch information in BX + MOV SI,81H ;Point to the command line buffer +NXTSWT: + CALL SCANOFF + LODSB + CMP AL,[SWTCH] + JZ GETPARM + CMP AL,13 + JZ SAVSWT + LODSB ;Get next character + CMP AL,":" ;Is it a drive specifier? + JNZ INVALID ;No -- invalid parameter + CMP BYTE PTR DBLFLG,0 ;Is is the only drive specifier we've seen + JNZ INVALID ;No -- invalid parameter + INC BYTE PTR DBLFLG ;Yes -- set the flag + JMP SHORT NXTSWT +GETPARM: + LODSB + ;Convert any lower case input into upper case + CMP AL,41H + JL GETCHR ;Switch is a digit don't try to convert it + AND AL,0DFH +GETCHR: + MOV CL,SWITCHLIST ;Number of legal switches + OR CL,CL ;If it's none we shouldn't be here + JZ INVALID ;Report the error + MOV CH,0 + MOV DI,1+OFFSET SWITCHLIST ;Point to the legal switch characters + REPNE SCASB + JNZ INVALID + MOV AX,1 + SHL AX,CL + OR BX,AX ;Set the appropriate bit in SWITCHMAP + JMP SHORT NXTSWT ;See if there are anymore + +INVALID: + MOV DX,OFFSET INVPAR + CALL PRINT + JMP FEXIT + +SCANOFF: + LODSB + CMP AL,20H + JZ SCANOFF + CMP AL,9 + JZ SCANOFF + DEC SI + RET + +MEMERR: + MOV DX,OFFSET MEMEX + CALL PRINT + JMP FEXIT + + +SAVSWT: + + IF IBMVER ;/B SWITCH TURNS /8 ON AND /S OFF + TEST BX,00100000B + JZ NOT_SW_B + AND BX,NOT SYSSW ;TURN OFF /S + OR BX,00010000B ;TURN ON /8 +NOT_SW_B: + ENDIF + + MOV SWITCHMAP,BX + TEST SWITCHMAP,SYSSW + JZ INITCALL + CALL SAVUDIRS + MOV BX,[FREESPACE] + ADD BX,15 + MOV CL,4 + SHR BX,CL + PUSH CS + POP ES + MOV AH,SETBLOCK + INT 21H + MOV BX,0FFFFH + MOV AH,ALLOC + INT 21H + OR BX,BX + JZ MEMERR ;No memory + MOV [MSIZE],BX + MOV AH,ALLOC + INT 21H + JC MEMERR ;No memory + MOV [MSTART],AX + MOV DX,OFFSET SWTCH + MOV AH,CHDIR + INT 21H ;Go to root on default drive (source) + +RDFRST: + CALL READDOS ;Read BIOS and DOS + JNC INITCALL ;OK -- read next file +NEEDSYS: + CALL SYSPRM ;Prompt for system disk + JMP RDFRST ;Try again + +INITCALL: + CALL INIT ;Let OEM read any files before disk is changed + JNC SWITCHCHK + MOV DX,OFFSET FRMTERR + CALL PRINT + JMP FEXIT + +SWITCHCHK: + MOV DX,SWITCHMAP + MOV SWITCHCOPY,DX + +SYSLOOP: + MOV WORD PTR BADSIZ,0 ;Must intialize for each iteration + MOV WORD PTR BADSIZ+2,0 + MOV WORD PTR SYSSIZ,0 + MOV WORD PTR SYSSIZ+2,0 + MOV BYTE PTR DBLFLG,0 + MOV BYTE PTR CLEARFLG,0 + MOV DX,SWITCHCOPY + MOV SWITCHMAP,DX ;Restore original Switches + MOV AL,DRIVE ;Fetch drive + ADD AL,"A" ;(AL)= ASCII designation + MOV BYTE PTR SNGDRV,AL ;Fill out the message + MOV BYTE PTR TARGDRV,AL + MOV BYTE PTR HRDDRV,AL + CALL DSKPRM ;Prompt for new disk + CALL DISKFORMAT ;Format the disk + JNC GETTRK +FRMTPROB: + MOV DX,OFFSET FRMTERR + CALL PRINT + JMP SHORT SYSLOOP + + ;Mark any bad sectors in the FATs + ;And keep track of how many bytes there are in bad sectors + +GETTRK: + CALL BADSECTOR ;Do bad track fix-up + JC FRMTPROB ;Had an error in Formatting - can't recover + CMP AX,0 ;Are we finished? + JNZ TRKFND ;No - check error conditions + JMP DRTFAT ;Yes +TRKFND: + CMP BX,STARTSECTOR ;Are any sectors in the system area bad? + JGE CLRTEST + MOV DX,OFFSET NOUSE ;Can't build FATs of Directory + CALL PRINT + JMP FRMTPROB ;Bad disk -- try again +CLRTEST: + MOV SECTORS,AX ;Save the number of sectors on the track + CMP BYTE PTR CLEARFLG,0 ;Have we already cleared the FAT and DIR? + JNZ SYSTEST ;Yes - all set + INC CLEARFLG ;Set the flag + PUSH BX + CALL CLEAR ;Fix-up fat and directory + POP BX +SYSTEST: + TEST SWITCHMAP,SYSSW ;If system requested calculate size + JZ BAD100 + CMP BYTE PTR DBLFLG,0 ;Have we already calculated System space? + JNZ CMPTRKS ;Yes -- all ready for the compare + INC BYTE PTR DBLFLG ;No -- set the flag + CALL GETSIZE ;Calculate the system size + MOV DX,WORD PTR SYSSIZ+2 + MOV AX,WORD PTR SYSSIZ + DIV SECSIZ + ADD AX,STARTSECTOR + MOV SYSTRKS,AX ;Space FAT,Dir,and system files require +CMPTRKS: + CMP BX,SYSTRKS + JG BAD100 + MOV DX,OFFSET NOTSYS ;Can't transfer a system + CALL PRINT + AND SWITCHMAP,NOT SYSSW ;Turn off system transfer switch + MOV WORD PTR SYSSIZ+2,0 ;No system to transfer + MOV WORD PTR SYSSIZ,0 ;No system to transfer +BAD100: +; BX is the first bad sector #, SECTORS is the number of bad sectors starting +; at BX. This needs to be converted to clusters. The start sector number may +; need to be rounded down to a cluster boundry, the end sector may need to be +; rounded up to a cluster boundry. Know BX >= STARTSECTOR + SUB BX,STARTSECTOR ; BX is now DATA area relative + MOV CX,BX + ADD CX,SECTORS + DEC CX ; CX is now the last bad sector # + MOV AX,BX + XOR DX,DX + DIV CLUSSIZ + MOV BX,AX ; BX is rounded down and converted + ; to a cluster #. Where cluster 0 = + ; first cluster of data. First bad + ; Sector is in cluster BX. + MOV AX,CX + XOR DX,DX + DIV CLUSSIZ + MOV CX,AX ; CX is rounded up and converted to a + ; to a cluster #. Where cluster 0 = + ; first cluster of data. Last bad + ; Sector is in cluster CX. + SUB CX,BX + INC CX ; CX is number of clusters to mark bad + ADD BX,2 ; Bias start by correct amount since + ; first cluster of data is really + ; cluster 2. + MOV AX,CLUSSIZ ; Sectors/Cluster + MUL SECSIZ ; Times Bytes/Sector + MOV BP,AX ; = Bytes/Cluster + +; Mark CX clusters bad starting at cluster BX +PACKIT: + MOV DX,0FF7H ;0FF7H indicates a bad sector + CALL PACK ;Put it in the allocation map + CMP DX,DI ;Have we already marked it bad? + JZ BAD150 ;if so, don't add it in + ADD WORD PTR BADSIZ,BP ;Add in number of bad bytes + JNB BAD150 + INC WORD PTR BADSIZ+2 +BAD150: + INC BX ;Next cluster + LOOP PACKIT ;Continue for # of clusters + JMP GETTRK + +; Inputs: + ;BX = Cluster number + ;DX = Data +; Outputs: + ;The data is stored in the FAT at the given cluster. + ;SI is destroyed + ;DI contains the former contents + ;No other registers affected +PACK: + PUSH BX + PUSH CX + PUSH DX + MOV SI,BX + SHR BX,1 + ADD BX,FATSPACE + ADD BX,SI + SHR SI,1 + MOV SI,WORD PTR [BX] + MOV DI,SI + JNB ALIGNED + MOV CL,4 + SHL DX,CL + SHR DI,CL + AND SI,15 + JMP SHORT PACKIN + +ALIGNED: + AND SI,0F000H +PACKIN: + AND DI,00FFFH ;DI CONTAINS FORMER CONTENTS + OR SI,DX + MOV WORD PTR[BX],SI + POP DX + POP CX + POP BX + RET + +DRTFAT: + CMP BYTE PTR CLEARFLG,0 + JNZ CLEARED + CALL CLEAR ;Clear the FAT and Dir + TEST SWITCHMAP,SYSSW ;If system requested, calculate size + JZ CLEARED + CMP BYTE PTR DBLFLG,0 ;Have we already calculated System space? + JNZ CLEARED ;Yes + INC BYTE PTR DBLFLG ;No -- set the flag + CALL GETSIZE ;Calculate the system size +CLEARED: + CALL WRTFAT + JNC FATWRT + MOV DX,OFFSET NOUSE + CALL PRINT + JMP FRMTPROB + +FATWRT: + + TEST SWITCHMAP,SYSSW ;System desired + JZ STATUS + CALL WRITEDOS ;Write the BIOS & DOS + JNC SYSOK + MOV DX,OFFSET NOTSYS ;Can't transfer a system + CALL PRINT + MOV WORD PTR SYSSIZ+2,0 ;No system transfered + MOV WORD PTR SYSSIZ,0 ;No system transfered + JMP SHORT STATUS + +SYSOK: + MOV DX,OFFSET SYSTRAN + CALL PRINT +STATUS: + CALL CRLF + CALL VOLID + MOV AH,DISK_RESET + INT 21H + CALL DONE ;Final call to OEM module + JNC REPORTC + JMP FRMTPROB ;Report an error + +REPORTC: + CALL REPORT + + CALL MORE ;See if more disks to format + JMP SYSLOOP ;If we returned from MORE then continue + +DISP32BITS: + PUSH BX + XOR AX,AX + MOV BX,AX + MOV BP,AX + MOV CX,32 +CONVLP: + SHL SI,1 + RCL DI,1 + XCHG AX,BP + CALL CONVWRD + XCHG AX,BP + XCHG AX,BX + CALL CONVWRD + XCHG AX,BX + ADC AL,0 + LOOP CONVLP + ; Conversion complete. Print 8-digit number with 2 leading blanks. + MOV CX,1810H + XCHG DX,AX + CALL DIGIT + XCHG AX,BX + CALL OUTWORD + XCHG AX,BP + CALL OUTWORD + POP DX + CMP DX,0 + JZ RET3 + CALL PRINT +RET3: RET + +OUTWORD: + PUSH AX + MOV DL,AH + CALL OUTBYTE + POP DX +OUTBYTE: + MOV DH,DL + SHR DL,1 + SHR DL,1 + SHR DL,1 + SHR DL,1 + CALL DIGIT + MOV DL,DH +DIGIT: + AND DL,0FH + JZ BLANKZER + MOV CL,0 +BLANKZER: + DEC CH + AND CL,CH + OR DL,30H + SUB DL,CL + MOV AH,STD_CON_OUTPUT + INT 21H + RET + +CONVWRD: + ADC AL,AL + DAA + XCHG AL,AH + ADC AL,AL + DAA + XCHG AL,AH +RET2: RET + +UNSCALE: + SHR CX,1 + JC RET2 + SHL AX,1 + RCL DX,1 + JMP SHORT UNSCALE + + +;****************************************** +; Calculate the size in bytes of the system rounded up to sector and +; cluster boundries, Answer in SYSSIZ + +GETSIZE: + MOV AX,WORD PTR BIOSSIZB ;And calculate the system size + MOV DX,WORD PTR BIOSSIZB+2 + CALL FNDSIZ + MOV AX,WORD PTR DOSSIZB + MOV DX,WORD PTR DOSSIZB+2 + CALL FNDSIZ + MOV AX,WORD PTR COMSIZB + MOV DX,WORD PTR COMSIZB+2 + +;Calculate the number of sectors used for the system +FNDSIZ: + DIV SECSIZ + OR DX,DX + JZ FNDSIZ0 + INC AX ; Round up to next sector +FNDSIZ0: + PUSH AX + XOR DX,DX + DIV CLUSSIZ + POP AX + OR DX,DX + JZ ONCLUS + SUB DX,CLUSSIZ + NEG DX + ADD AX,DX ; Round up sector count to cluster + ; boundry +ONCLUS: + MUL SECSIZ ; Turn it back into bytes + ADD WORD PTR SYSSIZ,AX + ADC WORD PTR SYSSIZ+2,DX + RET + +PRINT: MOV AH,STD_CON_STRING_OUTPUT ;Print msg pointed to by DX + INT 21H + RET + +MORE: CMP BYTE PTR [HARDFLAG],0 ;Check if removable media + JNZ FEXIT + CALL WAITYN ;Get yes or no response + JB FEXIT ;Exit if CF=1 + CALL CRLF +CRLF: + MOV DX,OFFSET CRLFMSG + CALL PRINT + RET + +PERROR: CALL PRINT ;Print message and exit +FEXIT: + CALL RESTUDIR ;Restore users dirs +FEXIT2: + INT 20H + + ;Prompt the user for a system diskette in the default drive +SYSPRM: + MOV AH,GET_DEFAULT_DRIVE ;Will find out the default drive + INT 21H ;Default now in AL + IF IBMVER OR IBMJAPVER + MOV BX,AX + ENDIF + ADD AL,41H ;Now in Ascii + MOV SYSDRV,AL ;Text now ok + + IF IBMVER OR IBMJAPVER + INT 11H ;Make sure drive has insertable media + AND AL,11000000B + ROL AL,1 + ROL AL,1 + OR AL,AL + JNZ NOTONEDRV + INC AL +NOTONEDRV: + CMP BL,AL + JBE ISFLOPPY + MOV AL,"A" + MOV BYTE PTR [SYSDRV],AL + MOV [BIODRV],AL + MOV [DOSDRV],AL + MOV [COMDRV],AL +ISFLOPPY: + ENDIF + + MOV DX,OFFSET SYSMSG + CALL PRINT ;Print first line + CALL WAITKY ;Wait for a key + CALL CRLF + RET + +TARGPRM: + MOV DX,OFFSET TARGMSG + CALL PRINT ;Print first line + CALL WAITKY ;Wait for a key + CALL CRLF + RET + +DSKPRM: + MOV DX,OFFSET SNGMSG ;Point to the message + CMP BYTE PTR [HARDFLAG],0 ;Check if removable media + JZ GOPRNIT + MOV DX,OFFSET HRDMSG +GOPRNIT: + CALL PRINT ;Print the message + CALL WAITKY ;Wait for space bar + CALL CRLF + CALL CRLF + RET + + ;Will wait for any key to be depressed. +WAITKY: + MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR STD_CON_INPUT_NO_ECHO + INT 21H + MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0 + INT 21H + + return + +FDPB: MOV DL,DRIVE + INC DL + MOV AH,GET_DPB + PUSH DS + INT 21H + INC AL + JZ DRVERR + MOV DX,WORD PTR [BX+13] + DEC DX + MOV AL,BYTE PTR [BX+4] + INC AL + MOV CX,WORD PTR [BX+2] + POP DS + RET +DRVERR: + POP DS + MOV DX,OFFSET INVDRV + JMP PERROR + + ;Clear the FAT and directory and set Dirty byte in the FAT +CLEAR: + MOV AL,FATID + OR AL,0F8H ;Make sure it's a legal value + MOV AH,0FFH + MOV DI,FATSPACE + MOV WORD PTR[DI],AX + MOV BYTE PTR[DI+2],AH + MOV AH,DISK_RESET + INT 21H + CALL WRTFAT + + IF IBMJAPVER + PUSH DS + MOV DL,[DRIVE] ;GET THE DRIVE PARAMETER + INC DL + MOV AH,32H + INT 21H + + MOV DPB_FIRST_ACCESS[BX],-1 ;FORCE MEDIA CHANGE + POP DS + ENDIF + + CALL FDPB + MOV WORD PTR FDSKSIZ,DX + MOV SECSIZ,CX + MOV AH,0 + MOV CLUSSIZ,AX + SHR DX,1 + JNC ROUNDED + INC DX +ROUNDED: + ADD DX,WORD PTR FDSKSIZ + XOR AX,AX + MOV CX,DX + MOV DI,FATSPACE + ADD DI,3 + REP STOSB + MOV AH,DISK_RESET + INT 21H + CALL WRTFAT + MOV DL,[DRIVE] + ADD DL,'A' + MOV [ROOTSTR],DL + MOV DX,OFFSET ROOTSTR + MOV AH,CHDIR + INT 21H ;Go to root on target drive + MOV AL,DRIVE + INC AL + MOV ALLDRV,AL + MOV AH,FCB_DELETE + MOV DX,OFFSET ALLFILE + INT 21H + + TEST SWITCHMAP,OLDSW ;See if E5 terminated DIR requested + JZ RET25 + MOV AL,DRIVE + INC AL + MOV BYTE PTR CLEANFILE,AL ;Get the drive + MOV DX,OFFSET CLEANFILE + MOV AH,FCB_CREATE +MAKE_NEXT: + INT 21H + OR AL,AL + JNZ DELETE_THEM + INC BYTE PTR CLNNAM + CMP BYTE PTR CLNNAM,"Z" + 1 + JNZ MAKE_NEXT + MOV BYTE PTR CLNNAM,"A" + INC BYTE PTR CLNNAM + 1 + CMP BYTE PTR CLNNAM + 1,"Z" + 1 + JNZ MAKE_NEXT + MOV BYTE PTR CLNNAM + 1,"A" + INC BYTE PTR CLNNAM + 2 + JMP MAKE_NEXT + +DELETE_THEM: + MOV WORD PTR CLNNAM,"??" + MOV BYTE PTR CLNNAM + 2,"?" + MOV AH,FCB_DELETE + INT 21H +RET25: + RET ;And return + + +;***************************************** +; Process V switch if set + +VOLID: + TEST [SWITCHMAP],VOLSW + JNZ DOVOL +VRET: CLC + RET + +DOVOL: + PUSH CX + PUSH SI + PUSH DI + PUSH ES + PUSH DS + POP ES +VOL_LOOP: + MOV AL,DRIVE + INC AL + MOV DS:BYTE PTR[VOLFCB+7],AL + MOV DX,OFFSET LABPRMT + CALL PRINT + MOV DX,OFFSET INBUFF + MOV AH,STD_CON_STRING_INPUT + INT 21H + MOV DX,OFFSET CRLFMSG + CALL PRINT + MOV DX,OFFSET CRLFMSG + CALL PRINT + MOV CL,[INBUFF+1] + OR CL,CL + JZ VOLRET + XOR CH,CH + MOV SI,OFFSET INBUFF+2 + MOV DI,SI + ADD DI,CX + MOV CX,11 + MOV AL,' ' + REP STOSB + MOV CX,5 + MOV DI,OFFSET VOLNAM + REP MOVSW + MOVSB + MOV DX,OFFSET VOLFCB + MOV AH,FCB_CREATE + INT 21H + OR AL,AL + JZ GOOD_CREATE + MOV DX,OFFSET INVCHR ;PRINT INVALID CHARS MESSAGE + CALL PRINT + JMP VOL_LOOP +GOOD_CREATE: + MOV DX,OFFSET VOLFCB + MOV AH,FCB_CLOSE + INT 21H + CALL CRLF +VOLRET: + POP ES + POP DI + POP SI + POP CX + RET + +;**************************************** +;Copy IO.SYS, MSDOS.SYS and COMMAND.COM into data area. +; Carry set if problems + +READDOS: + CALL TESTSYSDISK + JNC RDFILS + RET + +RDFILS: + MOV BYTE PTR [FILSTAT],0 + MOV BX,[BIOSHandle] + MOV AX,[MSTART] + MOV DX,AX + ADD DX,[MSIZE] ; CX first bad para + MOV [BIOSSTRT],AX + MOV CX,[BIOSSIZP] + ADD AX,CX + CMP AX,DX + JBE GOTBIOS + MOV BYTE PTR [FILSTAT],00000001B ; Got part of BIOS + MOV SI,[MSIZE] + XOR DI,DI + CALL DISIX4 + MOV DS,[BIOSSTRT] +ASSUME DS:NOTHING + CALL READFILE +ASSUME DS:CODE + JC CLSALL + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [BIOSOFFS],AX + MOV WORD PTR [BIOSOFFS+2],DX +FILESDONE: + CLC +CLSALL: + PUSHF + CALL COMCLS + POPF + RET + +GOTBIOS: + MOV BYTE PTR [FILSTAT],00000010B ; Got all of BIOS + LES SI,[BIOSSIZB] + MOV DI,ES + MOV DS,[BIOSSTRT] +ASSUME DS:NOTHING + CALL READFILE +ASSUME DS:CODE + JC CLSALL + MOV BX,[DOSHandle] + MOV [DOSSTRT],AX + CMP AX,DX ; No room left? + JZ CLSALL ; Yes + MOV CX,[DOSSIZP] + ADD AX,CX + CMP AX,DX + JBE GOTDOS + OR BYTE PTR [FILSTAT],00000100B ; Got part of DOS + SUB DX,[DOSSTRT] + MOV SI,DX + XOR DI,DI + CALL DISIX4 + MOV DS,[DOSSTRT] +ASSUME DS:NOTHING + CALL READFILE +ASSUME DS:CODE + JC CLSALL + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [DOSOFFS],AX + MOV WORD PTR [DOSOFFS+2],DX + JMP FILESDONE + +GOTDOS: + OR BYTE PTR [FILSTAT],00001000B ; Got all of DOS + LES SI,[DOSSIZB] + MOV DI,ES + MOV DS,[DOSSTRT] +ASSUME DS:NOTHING + CALL READFILE +ASSUME DS:CODE +CLSALLJ: JC CLSALL + MOV BX,[COMHandle] + MOV [COMSTRT],AX + CMP AX,DX ; No room left? + JZ CLSALL ; Yes + MOV CX,[COMSIZP] + ADD AX,CX + CMP AX,DX + JBE GOTCOM + OR BYTE PTR [FILSTAT],00010000B ; Got part of COMMAND + SUB DX,[COMSTRT] + MOV SI,DX + XOR DI,DI + CALL DISIX4 + MOV DS,[COMSTRT] +ASSUME DS:NOTHING + CALL READFILE +ASSUME DS:CODE + JC CLSALLJ + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [COMOFFS],AX + MOV WORD PTR [COMOFFS+2],DX + JMP FILESDONE + +GOTCOM: + OR BYTE PTR [FILSTAT],00100000B ; Got all of COMMAND + LES SI,[COMSIZB] + MOV DI,ES + MOV DS,[COMSTRT] +ASSUME DS:NOTHING + CALL READFILE +ASSUME DS:CODE + JMP CLSALL + +;************************************************** +;Write BIOS DOS COMMAND to the newly formatted disk. + +WRITEDOS: + MOV CX,BIOSATT + MOV DX,OFFSET BIOSFIL + LES SI,[BIOSSIZB] + MOV DI,ES + CALL MAKEFIL + JNC GOTNBIO +RET34: RET + +GOTNBIO: + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00000010B + JNZ GOTALLBIO + LES SI,[BIOSOFFS] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + MOV BP,OFFSET BIOSData + CALL GOTTARG + JC RET34 + JMP SHORT BIOSDONE + +GOTALLBIO: + LES SI,[BIOSSIZB] + MOV DI,ES + MOV DS,[BIOSSTRT] +ASSUME DS:NOTHING + CALL WRITEFILE +ASSUME DS:CODE +BIOSDONE: + MOV BX,[TempHandle] + MOV CX,BTIME + MOV DX,BDATE + CALL CLOSETARG + MOV CX,DOSATT + MOV DX,OFFSET DOSFIL + LES SI,[DOSSIZB] + MOV DI,ES + CALL MAKEFIL + JC RET34 + +GOTNDOS: + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00001000B + JNZ GOTALLDOS + MOV BP,OFFSET DOSData + TEST BYTE PTR FILSTAT,00000100B + JNZ PARTDOS + MOV WORD PTR [DOSOFFS],0 + MOV WORD PTR [DOSOFFS+2],0 + CALL GETSYS3 +RET34J: JC RET34 + JMP SHORT DOSDONE + +PARTDOS: + LES SI,[DOSOFFS] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + CALL GOTTARG + JC RET34J + JMP SHORT DOSDONE + +GOTALLDOS: + LES SI,[DOSSIZB] + MOV DI,ES + MOV DS,[DOSSTRT] +ASSUME DS:NOTHING + CALL WRITEFILE +ASSUME DS:CODE +DOSDONE: + MOV BX,[TempHandle] + MOV CX,DTIME + MOV DX,DDATE + CALL CLOSETARG + MOV CX,COMATT + MOV DX,OFFSET COMFIL + LES SI,[COMSIZB] + MOV DI,ES + CALL MAKEFIL + JNC GOTNCOM +RET35: RET + +GOTNCOM: + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00100000B + JNZ GOTALLCOM + MOV BP,OFFSET COMData + TEST BYTE PTR FILSTAT,00010000B + JNZ PARTCOM + MOV WORD PTR [COMOFFS],0 + MOV WORD PTR [COMOFFS+2],0 + CALL GETSYS3 + JC RET35 + JMP SHORT COMDONE + +PARTCOM: + LES SI,[COMOFFS] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + CALL GOTTARG + JC RET35 + JMP SHORT COMDONE + +GOTALLCOM: + LES SI,[COMSIZB] + MOV DI,ES + MOV DS,[COMSTRT] +ASSUME DS:NOTHING + CALL WRITEFILE +ASSUME DS:CODE +COMDONE: + MOV BX,[TempHandle] + MOV CX,CTIME + MOV DX,CDATE + CALL CLOSETARG + CMP BYTE PTR [FILSTAT],00101010B + JZ NOREDOS +RDFRST2: + CALL READDOS ; Start back with BIOS + JNC NOREDOS + CALL SYSPRM ;Prompt for system disk + JMP RDFRST2 ;Try again +NOREDOS: + CLC + RET + +;********************************************* +; Create a file on target disk +; CX = attributes, DX points to name +; DI:SI is size file is to have +; +; There is a bug in DOS 2.00 and 2.01 having to do with writes +; from the end of memory. In order to circumvent it this routine +; must create files with the length in DI:SI +; +; On return BX is handle, carry set if problem + +MAKEFIL: + MOV BX,DX + PUSH WORD PTR [BX] + MOV AL,TARGDRV + MOV [BX],AL + MOV AH,CREAT + INT 21H + POP WORD PTR [BX] + MOV BX,AX + JC RET50 + MOV CX,DI + MOV DX,SI + MOV AX,LSEEK SHL 8 + INT 21H ; Seek to eventual EOF + XOR CX,CX + MOV AH,WRITE + INT 21H ; Set size of file to position + XOR CX,CX + MOV DX,CX + MOV AX,LSEEK SHL 8 + INT 21H ; Seek back to start +RET50: + RET + +;********************************************* +; Close a file on the target disk +; CX/DX is time/date, BX is handle + +CLOSETARG: + MOV AX,(FILE_TIMES SHL 8) OR 1 + INT 21H + MOV AH,CLOSE + INT 21H + RET + +SAVUDIRS: + XOR DL,DL + MOV SI,OFFSET USERDIRS + MOV BYTE PTR [SI],'\' + INC SI + MOV AH,CURRENT_DIR + INT 21H +RET43: RET + + +RESTUDIR: + TEST SWITCHMAP,SYSSW + JZ RET43 + MOV DX,OFFSET USERDIRS + MOV AH,CHDIR + INT 21H ; Restore users DIR + RET + +INT_23: + PUSH CS + POP DS + JMP FEXIT + +;**************************************** +; Transfer system files +; BP points to data structure for file involved +; offset is set to current amount read in +; Start set to start of file in buffer +; TempHandle is handle to write to on target + +IOLOOP: + MOV AL,[SYSDRV] + CMP AL,[TARGDRV] + JNZ GOTTARG + MOV AH,DISK_RESET + INT 21H + CALL TARGPRM ;Get target disk + +GOTTARG: +;Enter here if some of file is already in buffer, IOCNT must be set +; to size already in buffer. + MOV BX,[TempHandle] + MOV SI,WORD PTR [IOCNT] + MOV DI,WORD PTR [IOCNT+2] + MOV DS,[BP.FILE_START] +ASSUME DS:NOTHING + CALL WRITEFILE ; Write next part +ASSUME DS:CODE + JNC TESTDONE + RET + +TESTDONE: + LES AX,[BP.FILE_OFFSET] + CMP AX,WORD PTR [BP.FILE_SIZEB] + JNZ GETSYS3 + MOV AX,ES + CMP AX,WORD PTR [BP.FILE_SIZEB+2] + JNZ GETSYS3 + RET ; Carry clear from CMP + +GETSYS3: +;Enter here if none of file is in buffer + MOV AX,[MSTART] ; Furthur IO done starting here + MOV [BP.FILE_START],AX + MOV AL,[SYSDRV] + CMP AL,[TARGDRV] + JNZ TESTSYS + MOV AH,DISK_RESET + INT 21H +GSYS: + CALL SYSPRM ;Prompt for system disk +TESTSYS: + CALL TESTSYSDISK + JC GSYS + MOV BX,[BP.FILE_HANDLE] + LES DX,[BP.FILE_OFFSET] + PUSH DX + MOV CX,ES + MOV AX,LSEEK SHL 8 + INT 21H + POP DX + LES SI,[BP.FILE_SIZEB] + MOV DI,ES + SUB SI,DX + SBB DI,CX ; DI:SI is #bytes to go + PUSH DI + PUSH SI + ADD SI,15 + ADC DI,0 + CALL DISID4 + MOV AX,SI + POP SI + POP DI + CMP AX,[MSIZE] + JBE GOTSIZ2 + MOV SI,[MSIZE] + XOR DI,DI + CALL DISIX4 +GOTSIZ2: + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + MOV DS,[MSTART] +ASSUME DS:NOTHING + CALL READFILE +ASSUME DS:CODE + JNC GETOFFS + CALL CLSALL + JMP GSYS +GETOFFS: + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [BP.FILE_OFFSET],AX + MOV WORD PTR [BP.FILE_OFFSET+2],DX + CALL CLSALL + JMP IOLOOP + +;************************************************* +; Test to see if correct system disk. Open handles + +TESTSYSDISK: + MOV AX,OPEN SHL 8 + MOV DX,OFFSET BIOSFIL + INT 21H + JNC SETBIOS +CRET12: STC +RET12: RET + +SETBIOS: + MOV [BIOSHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [BIOSSIZP],0 + JZ SETBIOSSIZ + CMP [BIOSSIZP],AX + JZ SETBIOSSIZ +BIOSCLS: + MOV AH,CLOSE + MOV BX,[BIOSHandle] + INT 21H + JMP CRET12 + +SETBIOSSIZ: + MOV [BIOSSIZP],AX + MOV WORD PTR [BIOSSIZB],SI + MOV WORD PTR [BIOSSIZB+2],DI + MOV [BDATE],DX + MOV [BTIME],CX + MOV AX,OPEN SHL 8 + MOV DX,OFFSET DOSFIL + INT 21H + JNC DOSOPNOK + JMP BIOSCLS + +DOSOPNOK: + MOV [DOSHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [DOSSIZP],0 + JZ SETDOSSIZ + CMP [DOSSIZP],AX + JZ SETDOSSIZ +DOSCLS: + MOV AH,CLOSE + MOV BX,[DOSHandle] + INT 21H + JMP BIOSCLS + +SETDOSSIZ: + MOV [DOSSIZP],AX + MOV WORD PTR [DOSSIZB],SI + MOV WORD PTR [DOSSIZB+2],DI + MOV [DDATE],DX + MOV [DTIME],CX + MOV AX,OPEN SHL 8 + MOV DX,OFFSET COMFIL + INT 21H + JC DOSCLS + MOV [COMHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [COMSIZP],0 + JZ SETCOMSIZ + CMP [COMSIZP],AX + JZ SETCOMSIZ +COMCLS: + MOV AH,CLOSE + MOV BX,[COMHandle] + INT 21H + JMP DOSCLS + +SETCOMSIZ: + MOV [COMSIZP],AX + MOV WORD PTR [COMSIZB],SI + MOV WORD PTR [COMSIZB+2],DI + MOV [CDATE],DX + MOV [CTIME],CX + CLC + RET + +;******************************************* +; Handle in BX, return file size in para in AX +; File size in bytes DI:SI, file date in DX, file +; time in CX. + +GETFSIZ: + MOV AX,(LSEEK SHL 8) OR 2 + XOR CX,CX + MOV DX,CX + INT 21H + MOV SI,AX + MOV DI,DX + ADD AX,15 ; Para round up + ADC DX,0 + AND DX,0FH ; If the file is larger than this + ; it is bigger than the 8086 address space! + MOV CL,12 + SHL DX,CL + MOV CL,4 + SHR AX,CL + OR AX,DX + PUSH AX + MOV AX,LSEEK SHL 8 + XOR CX,CX + MOV DX,CX + INT 21H + MOV AX,FILE_TIMES SHL 8 + INT 21H + POP AX + RET + +;******************************************** +; Read/Write file +; DS:0 is Xaddr +; DI:SI is byte count to I/O +; BX is handle +; Carry set if screw up +; +; I/O SI bytes +; I/O 64K - 1 bytes DI times +; I/O DI bytes +; DS=CS on output + + +READFILE: +; Must preserve AX,DX + PUSH AX + PUSH DX + PUSH BP + MOV BP,READ SHL 8 + CALL FILIO + POP BP + POP DX + POP AX + PUSH CS + POP DS + RET + +WRITEFILE: + PUSH BP + MOV BP,WRITE SHL 8 + CALL FILIO + POP BP + PUSH CS + POP DS + RET + +FILIO: + XOR DX,DX + MOV CX,SI + JCXZ K64IO + MOV AX,BP + INT 21H + JC IORET + ADD DX,AX + CMP AX,CX ; If not =, AXKXXbMy&zRZviH4GdKP0RvvHkf2bI2wcd| zKSTkn45Z%E$v4b32%#P>p;wWUSzN-)rB{($l$yrN1u_hTJ^h@0LS0-HT>OKBBYpK8 zgME3q^dL&~AUb%toc&$EHU_)8`?~stCfuu~wcP`_YjM;})R$Hg-^z}U#iGb9+y$27vtCD=RIGs?;(+&{=g zC)m{)!~wINeL{oboZv_>8>|Y`5GO|$kV>d5Lf$$&F|$M=Ex$-XDN;!RMENQ4azT7! zg;3_}9|np+1(ygNe>b;a*AN9?{~+IBcd(#>f`WBGer8^YLP@?tNk*zdE+j1@v^zWc z_<)pxLj%M>!`6;@DGCKeAR{tM5ZYk2I!5Sd1c$i9JNx^^d-?^0hQz!1ga&&k1bg@> zSZFHv2PvS)A`C#Y27_zumQz}sp^#LXmX=zikeHXEP!0=@?9|HQlA`?VRD@}sej#8J zj0`=%G&*7JnO9I+qL7@CSd^Gtl3JvYmtU@ss1OMXR-~li=;s2~>FA?l;Npg9lyz{v zLQZ~pYLP;6VsWZMd45rLu|i3HKEff+z5y^3lp>W7;$Bf;VFgh185tnNk=28u7oti* z0a?8vvU+HAfie%m6fdZ)!5;oWAz(W|2_9sZp@Ee`aELP`-542IDFnHOfHFQWm$eot zfS1c!!8b8GRUuKKxFoTpv{<1iwIIK!L?JUTIj1xwGcO&SywdV>a`MYTyv)3`{G!~% zlFa-(E0E@p{F1~Rg_O+VY=z{+g2d#^l1hYdabX>n=_LMACOMWMJL zF*#KsF()TKIk5y;G9|Gj5hh!fn3Lds<<1%qRR4yZ^{2nY#MfEHMYl;ax;&ix9IvI|KZ zTBdA30R?kZk>)JQn8Fnk+zWz$dj;uf+-93#H!oH6RT<`cp(TX znFE{=Zi6`*DJ8(H0@Kz(kn~)FNT=X*hcE%jMQ{&7N_I>&E}n=mhp5puLa2ge`e08T zq^#}b2Pq?hJ^aIiBZD!OyPztEs8(?H@OE-^;pKvA!;%0HfdX<0Ie`KW32@E?WdlfV z<>i9djK#uWB;P}7H-u+kp@nGG&2DKQo*gYl%mYCR0W6*m!L2t9Tiq^6G07{;*z3FP>q^bsgRvosZgGg znx{~dnwU}vvJTSdM$#Nmlv-S@kO);=lCO}Inx2`b0I6k5Kvk|1FBhbZj-;!?N&#dV zw9Sq1Z!o0BEh$ROD^5!-DoRa(I}M~B)`WzIj~lo$S4hmuFUd$PQqYLh_tUfosRT7d zK&?%fN~92jH0+TafEyYoYLG>g`C8s)EpE?KzamN^g}|pxF9t- zGc7Y2+{OSo1=4lEqP`%pC^0v+B((^n3e+z_cCb=Vs%~Z;I4VJ{6U=A?X#m9|%!f*( zL}PGdFvv1Qz*aVHTw8YGu(xOyY$RfoL zr1OMioeQXSR+?8_nppyBN`car0;I49yA@^xI6Hv5Tnb2!Kqa3pSiM4N zUTHDNAQX+@UK+AS&%EN&w6x6R%+$ORh1}HK{Gv)^n_)>5#SmUDSbYs`B^C2>L27&? z7bzrFmZXB(=kS&%xE@0>2vl+fIAdx8wL%ef9f}rEv58GfW**q@#gI}TMGLevL&Oc# zX^F5_t3rMrILKhSkYWi@dU?8mi+Kgem;yo^)&qA8c6SX5;^l(SNPcoo%*)FMmxsBD zB?^go3XZ|Sp6-6BDGK1Erw1+~AZ9Blxca$xx`7&$&<;Jq(P2m#RYAkh5Gfz)D7gBC pxCVjaEiXSWRns19Cde4j&;!V9S3eh|HjS&F3ojP~RRG8mDFDu>IGF$d literal 0 HcmV?d00001 diff --git a/GETSET.ASM b/GETSET.ASM new file mode 100644 index 0000000..289f4c8 --- /dev/null +++ b/GETSET.ASM @@ -0,0 +1,627 @@ +TITLE GETSET - GETting and SETting MS-DOS system calls +NAME GETSET +; +; System Calls which get and set various things +; +; $GET_VERSION +; $GET_VERIFY_ON_WRITE +; $SET_VERIFY_ON_WRITE +; $SET_CTRL_C_TRAPPING +; $INTERNATIONAL +; $GET_DRIVE_FREESPACE +; $GET_DMA +; $SET_DMA +; $GET_DEFAULT_DRIVE +; $SET_DEFAULT_DRIVE +; $GET_INTERRUPT_VECTOR +; $SET_INTERRUPT_VECTOR +; RECSET +; $CHAR_OPER +; +.xlist +; +; get the appropriate segment definitions +; +INCLUDE DOSSEG.ASM + +IFNDEF ALTVECT +ALTVECT EQU 0 ; FALSE +ENDIF + +IFNDEF IBM +IBM EQU 0 +ENDIF + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + + + i_need VERFLG,BYTE + i_need CNTCFLAG,BYTE + i_need DMAADD,DWORD + i_need CURDRV,BYTE + i_need Current_Country,WORD + i_need international_table,BYTE + i_need INDOS,BYTE + i_need SYSINITVAR,WORD + i_need NUMIO,BYTE + i_need SWITCH_CHARACTER,BYTE + i_need DEVICE_AVAILABILITY,BYTE + +USERNUM DW ? ; 24 bit user number + DB ? + IF IBM +OEMNUM DB 0 ; 8 bit OEM number + ELSE +OEMNUM DB 0FFH ; 8 bit OEM number + ENDIF + +MSVERS EQU THIS WORD ; MS-DOS version in hex for $GET_VERSION +MSMAJOR DB DOS_MAJOR_VERSION +MSMINOR DB DOS_MINOR_VERSION + + +BREAK <$Get_Version -- Return MSDOS version number> + procedure $GET_VERSION,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; None +; Function: +; Return MS-DOS version number +; Outputs: +; OEM number in BH +; User number in BL:CX (24 bits) +; Version number as AL.AH in binary +; NOTE: On pre 1.28 DOSs AL will be zero + + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV BX,[USERNUM + 2] + MOV CX,[USERNUM] + MOV AX,[MSVERS] + invoke get_user_stack +ASSUME DS:NOTHING + MOV [SI.user_BX],BX + MOV [SI.user_CX],CX + MOV [SI.user_AX],AX ; Really only sets AH + return +$GET_VERSION ENDP + +BREAK <$International - return country-dependent information> +; +; Inputs: +; DS:DX point to a block +; Function: +; give users an idea of what country the application is running +; Outputs: +; AX = number of bytes transferred +; DS:DX ->+---------------------------------+ +; | WORD Date/time format | +; +---------------------------------+ +; | BYTE ASCIZ currency symbol | +; +---------------------------------+ +; | BYTE ASCIZ thousands separator | +; +---------------------------------+ +; | BYTE ASCIZ decimal separator | +; +---------------------------------+ + + procedure $INTERNATIONAL,NEAR +ASSUME DS:NOTHING,ES:NOTHING + MOV BL,AL + PUSH DS + POP ES + PUSH DX + POP DI + PUSH SS + POP DS +ASSUME DS:DOSGROUP + CMP DI,-1 + JZ international_set + OR BL,BL + JNZ international_find + MOV SI,[Current_Country] + MOV AX,WORD PTR [SI-2] ; Get size in AL, country code in AH + MOV BL,AH ; Set country code + JMP SHORT international_copy + +international_find: + CALL international_get + JNC international_copy + error country_not_found + +international_get: + MOV SI,OFFSET DOSGROUP:international_table +international_next: + LODSW ; Get size in AL, country code in AH + CMP AL,-1 + JNZ check_code + STC +RET35: + RET + +check_code: + CMP BL,AH + JZ RET35 ; Carry clear + XOR AH,AH + ADD SI,AX + JMP international_next + +international_copy: + MOV CL,AL + XOR CH,CH + PUSH DI + REP MOVSB + POP DI + MOV WORD PTR ES:[DI.MAP_CALL + 2],CS ; Set segment for case map call +international_ok: + XOR AX,AX + MOV AL,BL ; Return country code in AX + transfer SYS_RET_OK + +international_set: + CALL international_get + JNC international_store + error country_not_found + +international_store: + MOV [Current_Country],SI + JMP international_ok + +$INTERNATIONAL ENDP + +BREAK <$Get_Verify_on_Write - return verify-after-write flag> + procedure $GET_VERIFY_ON_WRITE,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; none. +; Function: +; returns flag +; Returns: +; AL = value of VERIFY flag + + MOV AL,[VERFLG] + return +$GET_VERIFY_ON_WRITE ENDP + +BREAK <$Set_Verify_on_Write - Toggle verify-after-write flag> + procedure $SET_VERIFY_ON_WRITE,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; AL = desired value of VERIFY flag +; Function: +; Sets flag +; Returns: +; None + + AND AL,1 + MOV [VERFLG],AL + return +$SET_VERIFY_ON_WRITE ENDP + +BREAK <$Set_CTRL_C_Trapping -- En/Disable ^C check in dispatcher> + procedure $SET_CTRL_C_TRAPPING,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; AL = 0 read ^C status +; AL = 1 Set ^C status, DL = 0/1 for ^C off/on +; Function: +; Enable disable ^C checking in dispatcher +; Outputs: +; If AL = 0 then DL = 0/1 for ^C off/on + + OR AL,AL + JNZ CTRL_C_set + invoke get_user_stack + MOV AL,[CNTCFLAG] + MOV BYTE PTR [SI.user_DX],AL + return +CTRL_C_set: + DEC AL + JNZ bad_val + AND DL,01h + MOV [CNTCFLAG],DL + return +bad_val: + MOV AL,0FFH + return +$SET_CTRL_C_TRAPPING ENDP + +BREAK <$Get_INDOS_Flag -- Return location of DOS critical-section flag> + procedure $GET_INDOS_FLAG,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; None +; Function: +; Returns location of DOS status for interrupt routines +; Returns: +; Flag location in ES:BX + + invoke get_user_stack + MOV [SI.user_BX],OFFSET DOSGROUP:INDOS + MOV [SI.user_ES],SS + return +$GET_INDOS_FLAG ENDP + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + procedure $GET_IN_VARS,NEAR +; Return a pointer to interesting DOS variables This call is version +; dependent and is subject to change without notice in future versions. +; Use at risk. + invoke get_user_stack + MOV [SI.user_BX],OFFSET DOSGROUP:SYSINITVAR + MOV [SI.user_ES],SS + return +$GET_IN_VARS ENDP +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +BREAK <$Get_Drive_Freespace -- Return bytes of free disk space on a drive> + procedure $GET_DRIVE_FREESPACE,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DL = Drive number +; Function: +; Return number of free allocation units on drive +; Outputs: +; BX = Number of free allocation units +; DX = Total Number of allocation units on disk +; CX = Sector size +; AX = Sectors per allocation unit +; = -1 if bad drive specified +; This call returns the same info in the same registers (except for FAT pointer) +; as the old FAT pointer calls + + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV AL,DL + invoke GETTHISDRV + MOV AX,-1 + JC BADFRDRIVE + invoke FATREAD + XOR DX,DX + MOV BX,2 + MOV CX,ES:[BP.dpb_max_cluster] + DEC CX + PUSH CX ; Save Total +SCANFREE: + invoke UNPACK + JNZ NOTFREECLUS + INC DX +NOTFREECLUS: + INC BX + LOOP SCANFREE + POP BX ; Remember Total + MOV AL,ES:[BP.dpb_cluster_mask] + INC AL + XOR AH,AH + MOV CX,ES:[BP.dpb_sector_size] +BADFRDRIVE: + invoke get_user_stack +ASSUME DS:NOTHING + MOV [SI. user_CX],CX + MOV [SI.user_DX],BX + MOV [SI.user_BX],DX + MOV [SI.user_AX],AX + return + +$GET_DRIVE_FREESPACE ENDP + +BREAK <$Get_DMA, $Set_DMA -- Get/Set current DMA address> + procedure $GET_DMA,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; None +; Function: +; Get DISK TRANSFER ADDRESS +; Returns: +; ES:BX is current transfer address + + MOV BX,WORD PTR [DMAADD] + MOV CX,WORD PTR [DMAADD+2] + invoke get_user_stack + MOV [SI.user_BX],BX + MOV [SI.user_ES],CX + return +$GET_DMA ENDP + + procedure $SET_DMA,NEAR ; System call 26 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX is desired new disk transfer address +; Function: +; Set DISK TRANSFER ADDRESS +; Returns: +; None + + MOV WORD PTR [DMAADD],DX + MOV WORD PTR [DMAADD+2],DS + return +$SET_DMA ENDP + +BREAK <$Get_Default_DPB,$Get_DPB -- Return pointer to DPB> +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + procedure $GET_DEFAULT_DPB,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DL = Drive number (always default drive for call 31) +; Function: +; Return pointer to drive parameter table for default drive +; Returns: +; DS:BX points to the DPB +; AL = 0 If OK, = -1 if bad drive (call 50 only) + + MOV DL,0 + entry $GET_DPB + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV AL,DL + invoke GETTHISDRV + JC ISNODRV + invoke FATREAD + invoke get_user_stack +ASSUME DS:NOTHING + MOV [SI.user_BX],BP + MOV [SI.user_DS],ES + XOR AL,AL + return + +ISNODRV: + MOV AL,-1 + return +$GET_Default_dpb ENDP +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + + +BREAK <$Get_Default_Drive, $Set_Default_Drive -- Set/Get default drive> + procedure $GET_DEFAULT_DRIVE,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; None +; Function: +; Return current drive number +; Returns: +; AL = drive number + + MOV AL,[CURDRV] + return +$GET_DEFAULT_DRIVE ENDP + + procedure $SET_DEFAULT_DRIVE,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DL = Drive number for new default drive +; Function: +; Set the default drive +; Returns: +; AL = Number of drives, NO ERROR RETURN IF DRIVE NUMBER BAD + + MOV AL,[NUMIO] + CMP DL,AL + JNB RET17 + MOV [CURDRV],DL +RET17: return +$SET_DEFAULT_DRIVE ENDP + + +BREAK <$Get_Interrupt_Vector - Get/Set interrupt vectors> + procedure $GET_INTERRUPT_VECTOR,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; AL = interrupt number +; Function: +; Get the interrupt vector +; Returns: +; ES:BX is current interrupt vector + + CALL RECSET + LES BX,DWORD PTR ES:[BX] + invoke get_user_stack + MOV [SI.user_BX],BX + MOV [SI.user_ES],ES + return +$GET_INTERRUPT_VECTOR ENDP + + procedure $SET_INTERRUPT_VECTOR,NEAR ; System call 37 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; AL = interrupt number +; DS:DX is desired new interrupt vector +; Function: +; Set the interrupt vector +; Returns: +; None + + CALL RECSET + MOV ES:[BX],DX + MOV ES:[BX+2],DS + return +$SET_INTERRUPT_VECTOR ENDP + + IF ALTVECT +VECIN: ; INPUT VECTORS + DB 22H ; Terminate + DB 23H ; ^C + DB 24H ; Hard error + DB 28H ; Spooler +LSTVEC DB ? ; ALL OTHER + +VECOUT: ; GET MAPPED VECTOR + DB int_terminate + DB int_ctrl_c + DB int_fatal_abort + DB int_spooler +LSTVEC2 DB ? ; Map to itself + +NUMVEC = VECOUT-VECIN + ENDIF + +procedure RECSET,NEAR + + IF ALTVECT + PUSH SS + POP ES + MOV [LSTVEC],AL ; Terminate list with real vector + MOV [LSTVEC2],AL ; Terminate list with real vector + MOV CX,NUMVEC ; Number of possible translations + MOV DI,OFFSET DOSGROUP:VECIN ; Point to vectors + REPNE SCASB + MOV AL,ES:[DI+NUMVEC-1] ; Get translation + ENDIF + + XOR BX,BX + MOV ES,BX + MOV BL,AL + SHL BX,1 + SHL BX,1 + return +recset ENDP + +BREAK <$Char_Oper - hack on paths, switches so that xenix can look like PCDOS> +; +; input: AL = function: +; 0 - read switch char +; 1 - set switch char (char in DL) +; 2 - read device availability +; 3 - set device availability (0/FF in DL) +; DL = 0 means /DEV/ must preceed device names +; DL = Non0 means /DEV/ need not preeceed +; output: (get) DL - character/flag +; + procedure $CHAR_OPER,NEAR + ASSUME DS:NOTHING,ES:NOTHING + PUSH SS + POP DS +ASSUME DS:DOSGROUP + OR AL,AL + JNZ char_oper_set_switch + MOV DL,[switch_character] + JMP SHORT char_oper_ret +char_oper_set_switch: + DEC AL + JNZ char_oper_read_avail + MOV [switch_character],DL + return +char_oper_read_avail: + DEC AL + JNZ char_oper_set_avail + MOV DL,[device_availability] + JMP SHORT char_oper_ret +char_oper_set_avail: + DEC AL + JNZ char_oper_bad_ret + MOV [device_availability],DL + return +char_oper_bad_ret: + MOV AL,0FFh + return +char_oper_ret: + invoke get_user_stack + MOV [SI.user_DX],DX + return +$CHAR_OPER ENDP + +BREAK <$SetDPB - Create a valid DPB from a user-specified BPB> + procedure $SETDPB,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; ES:BP Points to DPB +; DS:SI Points to BPB +; Function: +; Build a correct DPB from the BPB +; Outputs: +; ES:BP and DS preserved all others destroyed + + MOV DI,BP + ADD DI,2 ; Skip over dpb_drive and dpb_UNIT + LODSW + STOSW ; dpb_sector_size + MOV DX,AX + LODSB + DEC AL + STOSB ; dpb_cluster_mask + INC AL + XOR AH,AH +LOG2LOOP: + TEST AL,1 + JNZ SAVLOG + INC AH + SHR AL,1 + JMP SHORT LOG2LOOP +SAVLOG: + MOV AL,AH + STOSB ; dpb_cluster_shift + MOV BL,AL + MOVSW ; dpb_first_FAT Start of FAT (# of reserved sectors) + LODSB + STOSB ; dpb_FAT_count Number of FATs + MOV BH,AL + LODSW + STOSW ; dpb_root_entries Number of directory entries + MOV CL,5 + SHR DX,CL ; Directory entries per sector + DEC AX + ADD AX,DX ; Cause Round Up + MOV CX,DX + XOR DX,DX + DIV CX + MOV CX,AX ; Number of directory sectors + INC DI + INC DI ; Skip dpb_first_sector + MOVSW ; Total number of sectors in DSKSIZ (temp as dpb_max_cluster) + LODSB + MOV ES:[BP.dpb_media],AL ; Media byte + LODSW ; Number of sectors in a FAT + STOSB ; dpb_FAT_size + MUL BH ; Space occupied by all FATs + ADD AX,ES:[BP.dpb_first_FAT] + STOSW ; dpb_dir_sector + ADD AX,CX ; Add number of directory sectors + MOV ES:[BP.dpb_first_sector],AX + SUB AX,ES:[BP.DSKSIZ] + NEG AX ; Sectors in data area + MOV CL,BL ; dpb_cluster_shift + SHR AX,CL ; Div by sectors/cluster + INC AX + MOV ES:[BP.dpb_max_cluster],AX + MOV ES:[BP.dpb_current_dir],0 ; Current directory is root + return +$SETDPB ENDP +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + + do_ext + +CODE ENDS + END + \ No newline at end of file diff --git a/IFEQU.ASM b/IFEQU.ASM new file mode 100644 index 0000000..e831e03 --- /dev/null +++ b/IFEQU.ASM @@ -0,0 +1,18 @@ +;************************************* +; COMMAND EQUs which are switch dependant + +IF1 + IF IBM + %OUT IBM version + ELSE + %OUT Normal version + ENDIF + + IF HIGHMEM + %OUT Highmem version + ENDIF + + IF KANJI + %OUT Kanji version + ENDIF +ENDIF diff --git a/INIT.ASM b/INIT.ASM new file mode 100644 index 0000000..0ea86f5 --- /dev/null +++ b/INIT.ASM @@ -0,0 +1,939 @@ +TITLE COMMAND Initialization + + INCLUDE COMSW.ASM + +.xlist +.xcref + INCLUDE DOSSYM.ASM + INCLUDE DEVSYM.ASM + INCLUDE COMSEG.ASM +.list +.cref + + INCLUDE COMEQU.ASM + +ENVIRONSIZ EQU 0A0H ;Must agree with values in EVIRONMENT segment +ENVIRONSIZ2 EQU 092H + +CODERES SEGMENT PUBLIC + EXTRN RSTACK:WORD,SETVECT:NEAR,LODCOM:NEAR,CONTC:NEAR,INT_2E:NEAR + EXTRN LOADCOM:NEAR,CHKSUM:NEAR + + IF IBMVER + EXTRN EXECHK:NEAR,SYSCALL:NEAR + ENDIF + +CODERES ENDS + +DATARES SEGMENT PUBLIC + EXTRN DATARESEND:BYTE,LTPA:WORD,MYSEG:WORD,MYSEG1:WORD,MYSEG2:WORD + EXTRN MEMSIZ:WORD,TRNSEG:WORD,ENVIRSEG:WORD,RSWITCHAR:BYTE + EXTRN COMDRV:BYTE,COMLET:BYTE,PERMCOM:BYTE,SINGLECOM:WORD + EXTRN PARENT:WORD,IO_SAVE:WORD,COM_PTR:DWORD,COM_FCB1:DWORD + EXTRN COM_FCB2:DWORD,SUM:WORD,BATCH:WORD,COMSPEC:BYTE + + IF IBMVER + EXTRN SYS_CALL:DWORD,EXESEG:WORD,EXESUM:WORD + ENDIF + +DATARES ENDS + +ENVIRONMENT SEGMENT PUBLIC + EXTRN ENVIREND:BYTE,PATHSTRING:BYTE,ECOMSPEC:BYTE +ENVIRONMENT ENDS + +TRANCODE SEGMENT PUBLIC + EXTRN DATINIT:FAR +TRANCODE ENDS + +TRANSPACE SEGMENT PUBLIC + EXTRN TRANSPACEEND:BYTE +TRANSPACE ENDS + +ZEXEC_DATA SEGMENT PUBLIC + IF IBM + EXTRN ZEXECDATAEND:BYTE + ENDIF +ZEXEC_DATA ENDS + +; ******************************************************************* +; START OF INIT PORTION +; This code is overlayed the first time the TPA is used. + +INIT SEGMENT PUBLIC PARA + + EXTRN HEADER:BYTE + EXTRN BADCOMLKMES:BYTE + + PUBLIC CONPROC + +ASSUME CS:RESGROUP,DS:RESGROUP,ES:RESGROUP,SS:RESGROUP + + ORG 0 +ZERO = $ + +CONPROC: + MOV SP,OFFSET RESGROUP:RSTACK + + IF HIGHMEM + MOV BX,WORD PTR DS:[PDB_block_len] + MOV AX,OFFSET RESGROUP:ENVIREND + 15 + MOV CL,4 + SHR AX,CL + PUSH AX ; Save size to alloc + INC AX ; Plus one for arena + SUB BX,AX ; Subtract size of resident + MOV WORD PTR DS:[PDB_block_len],BX + MOV AX,CS + SUB BX,AX + MOV AH,SETBLOCK + INT 21H + POP BX ; Get back size to alloc + MOV AH,ALLOC + INT 21H + MOV [REALRES],AX + MOV ES,AX + XOR SI,SI + MOV DI,SI + MOV CX,OFFSET RESGROUP:ENVIREND + SHR CX,1 ; Length of resident and environment in words + ; Last byte doesn't matter + REP MOVSW ; Move to end of memory + MOV DS,AX + MOV BX,AX + MOV AH,SET_CURRENT_PDB + INT 21H + MOV AX,BX + MOV BX,OFFSET RESGROUP:DATARESEND + 15 + MOV CL,4 + SHR BX,CL ; BX is size for SETBLOCK + MOV WORD PTR DS:[PDB_block_len],BX + ADD WORD PTR DS:[PDB_block_len],AX + MOV [LTPA],CS + MOV AH,SETBLOCK + INT 21H ;Shrink to not include environment + MOV BX,(ENVIRONSIZ + 15) / 16 + MOV AH,ALLOC + INT 21H ;Allocate the environment + MOV [ENVIRSEG],AX + MOV CS:[ENVIRSEGSAV],AX + MOV ES,AX +ASSUME ES:ENVIRONMENT + XOR DI,DI + MOV SI,OFFSET RESGROUP:PATHSTRING + MOV CX,ENVIRONSIZ + REP MOVSB + MOV AX,WORD PTR CS:[PDB_block_len] + ENDIF + + IF NOT HIGHMEM + MOV AX,OFFSET RESGROUP:ENVIREND + 15 + MOV CL,4 + SHR AX,CL + MOV CX,CS + ADD AX,CX ; Compute segment of TPA + MOV [LTPA],AX ; Good enough for the moment + MOV AX,WORD PTR DS:[PDB_block_len] + ENDIF + + MOV [MYSEG1],DS + MOV [MYSEG2],DS + MOV [MYSEG],DS + MOV [MEMSIZ],AX + + MOV DX,OFFSET TRANGROUP:TRANSPACEEND + 15 + MOV CL,4 + SHR DX,CL + + IF IBM + PUSH DX + MOV DX,OFFSET EGROUP:ZEXECDATAEND + 15 + MOV CL,4 + SHR DX,CL + POP CX + ADD DX,CX + ENDIF + + SUB AX,DX + MOV [TRNSEG],AX ; Read it in here + MOV AX,DS:[PDB_environ] + OR AX,AX + JZ BUILDENV ; Need to make an environment + + IF HIGHMEM + INC BYTE PTR CS:[CHUCKENV] ; Flag no ENVIRONSEG + ELSE + INC BYTE PTR [CHUCKENV] ; Flag no ENVIRONSEG + ENDIF + + JMP SHORT ENVIRONPASSED + +BUILDENV: + + IF NOT HIGHMEM + MOV AX,OFFSET RESGROUP:PATHSTRING ; Figure environment pointer + MOV CL,4 + SHR AX,CL + MOV DX,DS + ADD AX,DX + ELSE + JMP SHORT GOTTHEENVIR + ENDIF + +ENVIRONPASSED: + MOV [ENVIRSEG],AX + + IF HIGHMEM + DEC AX + MOV ES,AX + INC AX + MOV ES:[arena_owner],DS ; Adjust owner of passed envir + ENDIF + + MOV ES,AX +ASSUME ES:ENVIRONMENT + +GOTTHEENVIR: + MOV AX,CHAR_OPER SHL 8 + INT int_command + MOV [RSWITCHAR],DL + + CMP DL,'/' + JNZ IUSESLASH + + IF HIGHMEM + MOV CS:[COMSPECT],'\' + ELSE + MOV [COMSPECT],'\' + ENDIF + + IF HIGHMEM + CMP BYTE PTR CS:[CHUCKENV],0 + ELSE + CMP BYTE PTR [CHUCKENV],0 + ENDIF + + JNZ IUSESLASH + + MOV ES:[ECOMSPEC-10H],'\' +IUSESLASH: + +IF IBMVER + PUSH ES + MOV AX,(Get_interrupt_vector SHL 8) + int_command + INT int_command + MOV WORD PTR [SYS_CALL],BX + MOV WORD PTR [SYS_CALL+2],ES + MOV DX,OFFSET RESGROUP:SYSCALL + MOV AX,(Set_interrupt_vector SHL 8) + int_command + INT int_command + POP ES +ENDIF + + MOV AL,BYTE PTR DS:[FCB] ; get drive spec for default + MOV AH,DRVCHAR + MOV [COMDRV],AL + ADD AL,40H ; Convert to letter + CMP AL,40H + JZ NOCOMDRV + STD + IF HIGHMEM + CMP BYTE PTR CS:[CHUCKENV],0 + ELSE + CMP BYTE PTR [CHUCKENV],0 + ENDIF + + JNZ NOTWIDENV + + PUSH DS + PUSH ES + POP DS + MOV DI,OFFSET ENVIRONMENT:ECOMSPEC + ENVIRONSIZ2 - 1 - 10H + MOV SI,OFFSET ENVIRONMENT:ECOMSPEC + ENVIRONSIZ2 - 3 - 10H + MOV CX,ENVIRONSIZ2 - 2 + REP MOVSB + + POP DS + MOV WORD PTR ES:[ECOMSPEC-10H],AX + +NOTWIDENV: + CLD + IF HIGHMEM + MOV WORD PTR CS:[AUTOBAT],AX + ELSE + MOV WORD PTR [AUTOBAT],AX + ENDIF + + MOV [COMLET],AL +NOCOMDRV: + CALL SETVECT ; Set the vectors + + MOV SI,80H + LODSB + MOV CL,AL + XOR CH,CH + JCXZ COMRETURNSJ ; No parameters + MOV SI,81H ; Start of parms +CHKARG: + LODSB + CMP AL,' ' + JZ NEXTCH + CMP AL,9 ; Tab only other delimiter + JZ NEXTCH + CMP AL,[RSWITCHAR] ; Switch? + JNZ CHKOTHERARGS ; No + DEC CX + JCXZ ARGSDONEJ ; oops + LODSB + OR AL,20H ; Lower case + CMP AL,'p' ; PERMCOM switch + JNZ NEXTCH + JMP SETPERM + +NEXTCH: + CMP AL,'d' + JNZ NEXTCH3 + + IF HIGHMEM + MOV BYTE PTR CS:[PRDATTM],1 ; User explicitly says no date time + ELSE + MOV BYTE PTR [PRDATTM],1 ; User explicitly says no date time + ENDIF + + LOOP CHKARG + JMP SHORT ARGSDONEJ +NEXTCH3: + CMP AL,'c' + JNZ NEXTCH2 ; SINGLECOM switch 2 + MOV [SINGLECOM],SI ; Point to the rest of the command line + MOV [PERMCOM],0 ; A SINGLECOM must not be a PERMCOM + + IF HIGHMEM + MOV BYTE PTR CS:[PRDATTM],1 ; No date or time either, explicit + ELSE + MOV BYTE PTR [PRDATTM],1 ; No date or time either, explicit + ENDIF + +ARGSDONEJ: + JMP ARGSDONE + +NEXTCH2: + LOOP CHKARG + +COMRETURNSJ: + JMP COMRETURNS + +CHKOTHERARGS: + DEC SI + MOV DX,SI + PUSH CX + PUSH SI +CONTRLOOP: + LODSB + DEC CX + CMP AL,' ' + JZ SETCDEV + CMP AL,9 + JZ SETCDEV + JCXZ SETCDEVA + JMP SHORT CONTRLOOP + +SETCDEVA: + INC SI +SETCDEV: + MOV BYTE PTR [SI-1],0 + MOV AX,(OPEN SHL 8) OR 2 ; Read and write + INT int_command + JC CHKSRCHSPEC ; Wasn't a file + MOV BX,AX + MOV AX,IOCTL SHL 8 + INT int_command + TEST DL,80H + JNZ ISADEVICE + MOV AH,CLOSE ; Close initial handle, wasn't a device + INT int_command + JMP CHKSRCHSPEC + +ISADEVICE: + XOR DH,DH + OR DL,3 ; Make sure has CON attributes + MOV AX,(IOCTL SHL 8) OR 1 + INT int_command + MOV DX,BX ; Save new handle + POP BX ; Throw away saved SI + POP BX ; Throw away saved CX + PUSH CX + MOV CX,3 + XOR BX,BX +RCCLLOOP: ; Close 0,1 and 2 + MOV AH,CLOSE + INT int_command + INC BX + LOOP RCCLLOOP + MOV BX,DX ; New device handle + MOV AH,XDUP + INT int_command ; Dup to 0 + MOV AH,XDUP + INT int_command ; Dup to 1 + MOV AH,XDUP + INT int_command ; Dup to 2 + MOV AH,CLOSE + INT int_command ; Close initial handle + POP CX + JCXZ ARGSDONEJ2 + JMP CHKARG + +CHKSRCHSPEC: ; Not a device, so must be directory spec + + IF HIGHMEM + MOV BYTE PTR CS:[CHUCKENV],0 ; If search specified -- no inheritance + MOV AX,CS:[ENVIRSEGSAV] + MOV [ENVIRSEG],AX + ELSE + MOV BYTE PTR [CHUCKENV],0 ; If search specified -- no inheritance + MOV AX,OFFSET RESGROUP:PATHSTRING ; Figure environment pointer + MOV CL,4 + SHR AX,CL + MOV DX,DS + ADD AX,DX + MOV [ENVIRSEG],AX + ENDIF + + MOV ES,AX + MOV BYTE PTR [SI-1],' ' + POP SI ; Remember location + POP CX ; and count + + IF HIGHMEM + MOV DI,CS:[ECOMLOC] + ELSE + MOV DI,[ECOMLOC] + ENDIF + +COMTRLOOP: + LODSB + DEC CX + CMP AL,' ' + JZ SETCOMSR + CMP AL,9 + JZ SETCOMSR + STOSB + + IF KANJI + XOR AH,AH + ENDIF + + JCXZ SETCOMSR + + IF KANJI + CALL ITESTKANJ + JZ COMTRLOOP + DEC CX + MOVSB + INC AH + JCXZ SETCOMSR + ENDIF + + JMP SHORT COMTRLOOP + +SETCOMSR: + PUSH SI + PUSH CX + + PUSH DS + + IF HIGHMEM + PUSH CS + POP DS + ENDIF + + MOV SI,OFFSET RESGROUP:COMSPECT + MOV CX,14 + + MOV AL,ES:[DI-1] + + IF KANJI + OR AH,AH + JNZ INOTROOT ; Last char was KANJI second byte, might be '\' + ENDIF + + CALL PATHCHRCMPR + JNZ INOTROOT + INC SI ; Don't make a double / + DEC CX +INOTROOT: + REP MOVSB + + MOV DX,[ECOMLOC] ; Now lets make sure its good! + PUSH ES + POP DS + + MOV AX,OPEN SHL 8 + INT int_command ; Open COMMAND.COM + POP DS + JC SETCOMSRBAD ; No COMMAND.COM here + MOV BX,AX ; Handle + MOV AH,CLOSE + INT int_command ; Close COMMAND.COM +SETCOMSRRET: + POP CX + POP SI +ARGSDONEJ2: + JCXZ ARGSDONE + JMP CHKARG + +SETCOMSRBAD: + + IF HIGHMEM + PUSH DS + PUSH CS + POP DS + ENDIF + + MOV DX,OFFSET RESGROUP:BADCOMLKMES + MOV AH,STD_CON_STRING_OUTPUT + INT int_command + MOV SI,OFFSET RESGROUP:COMSPECT + MOV DI,[ECOMLOC] + MOV CX,14 + REP MOVSB ; Get my default back + + IF HIGHMEM + POP DS + ENDIF + + JMP SHORT SETCOMSRRET + +CHKARGJ: + JMP CHKARG + +SETPERM: + INC [PERMCOM] + + IF HIGHMEM + CMP BYTE PTR CS:[PRDATTM],-1 + ELSE + CMP BYTE PTR [PRDATTM],-1 + ENDIF + + JNZ LOOPIT + + IF HIGHMEM + MOV BYTE PTR CS:[PRDATTM],0 ; If not set explicit, set to prompt + ELSE + MOV BYTE PTR [PRDATTM],0 ; If not set explicit, set to prompt + ENDIF + +LOOPIT: + LOOP CHKARGJ +ARGSDONE: + CMP [PERMCOM],0 + JZ COMRETURNS + PUSH ES ; Save environment pointer + MOV AH,SET_CURRENT_PDB + MOV BX,DS + MOV ES,BX + INT int_command ; Current process is me + MOV DI,PDB_Exit ; Diddle the addresses in my header + MOV AX,OFFSET RESGROUP:LODCOM + STOSW + MOV AX,DS + STOSW + MOV AX,OFFSET RESGROUP:CONTC + STOSW + MOV AX,DS + STOSW + MOV WORD PTR DS:[PDB_Parent_PID],DS ; Parent is me forever + MOV DX,OFFSET RESGROUP:INT_2E + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 02EH + INT int_command ;Set magic interrupt + POP ES ;Remember environment +COMRETURNS: + MOV AX,WORD PTR DS:[PDB_Parent_PID] + MOV [PARENT],AX ; Save parent + MOV WORD PTR DS:[PDB_Parent_PID],DS ; Parent is me + MOV AX,WORD PTR DS:[PDB_JFN_Table] + MOV [IO_SAVE],AX ; Get the default stdin and out + MOV WORD PTR [COM_PTR+2],DS ; Set all these to resident + MOV WORD PTR [COM_FCB1+2],DS + MOV WORD PTR [COM_FCB2+2],DS + MOV DI,OFFSET RESGROUP:COMSPEC + + IF HIGHMEM + MOV SI,CS:[ECOMLOC] + CMP BYTE PTR CS:[CHUCKENV],0 + ELSE + MOV SI,[ECOMLOC] + CMP BYTE PTR [CHUCKENV],0 + ENDIF + + MOV AX,DS ; XCHG ES,DS + PUSH ES + POP DS + MOV ES,AX + + JZ COPYCOMSP ; All set up for copy + + PUSH CS + POP DS + + MOV SI,OFFSET RESGROUP:COMSPSTRING + PUSH ES + PUSH DI + CALL IFINDE + MOV SI,DI + PUSH ES + POP DS + POP DI + POP ES + JNC COPYCOMSP +COMSPECNOFND: + + IF HIGHMEM + MOV DS,CS:[ENVIRSEG] + MOV SI,CS:[ECOMLOC] + ELSE + MOV SI,[ECOMLOC] + ADD SI,OFFSET RESGROUP:PATHSTRING + PUSH CS + POP DS + ENDIF + +COPYCOMSP: + LODSB + STOSB + OR AL,AL + JNZ COPYCOMSP + + IF HIGHMEM + MOV DS,CS:[REALRES] + PUSH CS + POP ES + MOV AH,DEALLOC + INT 21H + CMP BYTE PTR CS:[CHUCKENV],0 + JZ GOTENVIR ; Environment is ok + MOV ES,CS:[ENVIRSEGSAV] + MOV AH,DEALLOC + INT 21H + ELSE + PUSH CS + POP DS + MOV BX,OFFSET RESGROUP:DATARESEND + 15 + MOV CL,4 + SHR BX,CL + MOV AH,SETBLOCK + INT int_command ; Shrink me to the resident only + CMP BYTE PTR [CHUCKENV],0 + JNZ GOTENVIR ; Environment was passed + MOV BX,(ENVIRONSIZ + 15) /16 + MOV AH,ALLOC + INT int_command ; "ALLOCATE" the environment + MOV DS,[ENVIRSEG] + MOV [ENVIRSEG],AX + MOV ES,AX + XOR SI,SI + MOV DI,SI + MOV CX,ENVIRONSIZ + REP MOVSB + PUSH CS + POP DS + ENDIF + +GOTENVIR: + CALL LOADCOM ; Load the transient in the right place + CALL CHKSUM ; Compute the checksum + MOV [SUM],DX ; Save it +IF IBM + MOV AX,[MEMSIZ] + MOV DX,OFFSET EGROUP:ZEXECDATAEND + 15 + MOV CL,4 + SHR DX,CL + SUB AX,DX + MOV [EXESEG],AX + CALL EXECHK + MOV [EXESUM],DX +ENDIF + IF MSVER + CMP [SINGLECOM],0 + JNZ NOPHEAD ; Don't print header if SINGLECOM + IF HIGHMEM + PUSH DS + PUSH CS + POP DS + ENDIF + MOV DX,OFFSET RESGROUP:HEADER + MOV AH,STD_CON_STRING_OUTPUT + INT int_command + IF HIGHMEM + POP DS + ENDIF +NOPHEAD: + ENDIF + + IF HIGHMEM + CMP BYTE PTR CS:[PRDATTM],0 + ELSE + CMP BYTE PTR [PRDATTM],0 + ENDIF + + JNZ NODTTM ; Don't do AUTOEXEC or date time + MOV BX,3 ; 48 BYTES ENOUGH + MOV AH,ALLOC + INT int_command + JC DODTTM ; PRETEND NO BATCH + MOV [BATCH],AX + MOV ES,AX + XOR DI,DI + + IF HIGHMEM + CMP BYTE PTR CS:[AUTOBAT],0 + ELSE + CMP BYTE PTR [AUTOBAT],0 + ENDIF + + JNZ NOAUTSET + MOV AH,GET_DEFAULT_DRIVE + INT int_command + ADD AL,'A' + + IF HIGHMEM + MOV CS:[AUTOBAT],AL + ELSE + MOV [AUTOBAT],AL + ENDIF + +NOAUTSET: + + IF HIGHMEM + PUSH DS + PUSH CS + POP DS + ENDIF + + MOV SI,OFFSET RESGROUP:AUTOBAT + MOV CX,8 + REP MOVSW ; NAME + MOV AX,-1 + MOV CL,10 + REP STOSW ; PARMS + MOV DX,OFFSET RESGROUP:AUTOBAT + MOV AX,OPEN SHL 8 + INT int_command ; See if AUTOEXEC.BAT exists + JC NOABAT + MOV BX,AX + MOV AH,CLOSE + INT int_command + + IF HIGHMEM + POP DS + ENDIF + + JMP SHORT DRV0 + +NOABAT: + + IF HIGHMEM + POP DS + ENDIF + + MOV ES,[BATCH] ; Not found--turn off batch job + MOV AH,DEALLOC + INT int_command + MOV [BATCH],0 ; AFTER DEALLOC in case of ^C +DODTTM: + + IF HIGHMEM + MOV AX,OFFSET TRANGROUP:DATINIT + MOV WORD PTR CS:[INITADD],AX + MOV AX,[TRNSEG] + MOV WORD PTR CS:[INITADD+2],AX + CALL DWORD PTR CS:[INITADD] + ELSE + MOV AX,OFFSET TRANGROUP:DATINIT + MOV WORD PTR[INITADD],AX + MOV AX,[TRNSEG] + MOV WORD PTR[INITADD+2],AX + CALL DWORD PTR [INITADD] + ENDIF + +NODTTM: + + IF IBMVER + CMP [SINGLECOM],0 + JNZ DRV0 ; Don't print header if SINGLECOM + MOV DX,OFFSET RESGROUP:HEADER + MOV AH,STD_CON_STRING_OUTPUT + INT int_command + ENDIF + +DRV0: + IF HIGHMEM + PUSH DS + MOV AX,OFFSET RESGROUP:LODCOM + PUSH AX +MQQ PROC FAR + RET +MQQ ENDP + ELSE + JMP LODCOM ; Allocate the transient + ENDIF + +PATHCHRCMPR: + CMP [RSWITCHAR],'/' + JZ RNOSLASHT + CMP AL,'/' + JZ RET41 +RNOSLASHT: + CMP AL,'\' +RET41: + RET + + +IFINDE: + CALL IFIND ; FIND THE NAME + JC IFIND2 ; CARRY MEANS NOT FOUND + JMP ISCASB1 ; SCAN FOR = SIGN +; +; On return of FIND1, ES:DI points to beginning of name +; +IFIND: + CLD + + CALL ICOUNT0 ; CX = LENGTH OF NAME + + IF HIGHMEM + MOV ES,CS:[REALRES] +ASSUME ES:RESGROUP + MOV ES,ES:[ENVIRSEG] +ASSUME ES:NOTHING + ELSE + MOV ES,[ENVIRSEG] + ENDIF + + XOR DI,DI +IFIND1: + PUSH CX + PUSH SI + PUSH DI +IFIND11: + LODSB + + IF KANJI + CALL ITESTKANJ + JZ NOTKANJ4 + DEC SI + LODSW + INC DI + INC DI + CMP AX,ES:[DI-2] + JNZ IFIND12 + DEC CX + LOOP IFIND11 + JMP SHORT IFIND12 + +NOTKANJ4: + ENDIF + + CALL IUPCONV + INC DI + CMP AL,ES:[DI-1] + JNZ IFIND12 + LOOP IFIND11 +IFIND12: + POP DI + POP SI + POP CX + JZ IFIND2 + PUSH CX + CALL ISCASB2 ; SCAN FOR A NUL + POP CX + CMP BYTE PTR ES:[DI],0 + JNZ IFIND1 + STC ; INDICATE NOT FOUND +IFIND2: + RET + +ICOUNT0: + PUSH DS + POP ES + MOV DI,SI + + PUSH DI ; COUNT NUMBER OF CHARS UNTIL "=" + CALL ISCASB1 + JMP SHORT ICOUNTX + PUSH DI ; COUNT NUMBER OF CHARS UNTIL NUL + CALL ISCASB2 +ICOUNTX: + POP CX + SUB DI,CX + XCHG DI,CX + RET + +ISCASB1: + MOV AL,"=" ; SCAN FOR AN = + JMP SHORT ISCASBX +ISCASB2: + XOR AL,AL ; SCAN FOR A NUL +ISCASBX: + MOV CX,100H + REPNZ SCASB + RET + + IF KANJI +ITESTKANJ: + CMP AL,81H + JB NOTLEAD + CMP AL,9FH + JBE ISLEAD + CMP AL,0E0H + JB NOTLEAD + CMP AL,0FCH + JBE ISLEAD +NOTLEAD: + PUSH AX + XOR AX,AX ;Set zero + POP AX + RET + +ISLEAD: + PUSH AX + XOR AX,AX ;Set zero + INC AX ;Reset zero + POP AX + RET + ENDIF + +IUPCONV: + CMP AL,"a" + JB IRET22 + CMP AL,"z" + JA IRET22 + SUB AL,20H ; Lower-case changed to upper-case +IRET22: + RET + +ICONDEV LABEL BYTE + DB "/DEV/" + DB "CON",0,0,0,0,0,0 ; Room for 8 char device +BADCSPFL DB 0 +COMSPECT DB "/COMMAND.COM",0,0 +AUTOBAT DB 0,":\AUTOEXEC.BAT",0 + +PRDATTM DB -1 ;Init not to prompt for date time +INITADD DD ? +CHUCKENV DB 0 +ECOMLOC DW OFFSET ENVIRONMENT:ECOMSPEC-10H + + IF HIGHMEM +REALRES DW ? +ENVIRSEGSAV DW ? + ENDIF + +COMSPSTRING DB "COMSPEC=" + + +INIT ENDS + + END + \ No newline at end of file diff --git a/LICENSE b/LICENSE index 483c460..6d85807 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Broken Pipe +Copyright (c) 1983 Microsoft Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MISC.ASM b/MISC.ASM new file mode 100644 index 0000000..e0a5cee --- /dev/null +++ b/MISC.ASM @@ -0,0 +1,648 @@ +TITLE MISC - Miscellanious routines for MS-DOS +NAME MISC +; +; Miscellaneous system calls most of which are CAVEAT +; +; $SLEAZEFUNC +; $SLEAZEFUNCDL +; $GET_INDOS_FLAG +; $GET_IN_VARS +; $GET_DEFAULT_DPB +; $GET_DPB +; $DISK_RESET +; $SETDPB +; $Dup_PDB +; $CREATE_PROCESS_DATA_BLOCK +; SETMEM +; +.xlist +; +; get the appropriate segment definitions +; +INCLUDE DOSSEG.ASM + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + + +ifndef Kanji +Kanji equ 0 +endif + +ENTRYPOINTSEG EQU 0CH +MAXDIF EQU 0FFFH +SAVEXIT EQU 10 + + i_need LASTBUFFER,DWORD + i_need INDOS,BYTE + i_need SYSINITVAR,BYTE + i_need CurrentPDB,WORD + i_need CreatePDB,BYTE + i_need EXIT_TYPE,BYTE + i_need EXIT_CODE,WORD + i_need LASTENT,WORD + i_need THISDPB,DWORD + i_need ATTRIB,BYTE + i_need EXTFCB,BYTE + i_need DMAADD,DWORD + i_need DIRSTART,WORD + i_need CURBUF,DWORD + i_need USER_SP,WORD + i_need ENTLAST,WORD + i_need THISDRV,BYTE + +ASSUME SS:DOSGROUP + +BREAK + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + procedure $SLEAZEFUNC,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; None +; Function: +; Return Stuff sort of like old get fat call +; Outputs: +; DS:BX = Points to FAT ID byte (IBM only) +; GOD help anyone who tries to do ANYTHING except +; READ this ONE byte. +; DX = Total Number of allocation units on disk +; CX = Sector size +; AL = Sectors per allocation unit +; = -1 if bad drive specified + + MOV DL,0 + entry $SLEAZEFUNCDL + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV AL,DL + invoke GETTHISDRV + MOV AL,-1 + JC BADSLDRIVE + invoke FATREAD + MOV DX,ES:[BP.dpb_max_cluster] + DEC DX + MOV AL,ES:[BP.dpb_cluster_mask] + INC AL + MOV CX,ES:[BP.dpb_sector_size] + ADD BP,dpb_media +BADSLDRIVE: + invoke get_user_stack +ASSUME DS:NOTHING + MOV [SI.user_CX],CX + MOV [SI.user_DX],DX + MOV [SI.user_BX],BP + MOV [SI.user_DS],ES + return +$SLEAZEFUNC ENDP +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + + + +BREAK <$ABORT -- Terminate a process> + procedure $ABORT,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; CS:00 must point to valid program header block +; Function: +; Restore terminate and Cntrl-C addresses, flush buffers +; and transfer to the terminate address +; Returns: +; TO THE TERMINATE ADDRESS + + XOR AL,AL + MOV [exit_type],exit_abort + +; +; abort_inner must have AL set as the exit code! +; + entry abort_inner + MOV AH,[exit_type] + MOV [exit_code],AX + invoke Get_user_stack + MOV DS,[SI.user_CS] ; set up old interrupts + XOR AX,AX + MOV ES,AX + MOV SI,SAVEXIT + MOV DI,addr_int_terminate + MOVSW + MOVSW + MOVSW + MOVSW + MOVSW + MOVSW + transfer reset_environment +$ABORT ENDP + +BREAK <$Dir_Search_First -- Start a directory search> + procedure $DIR_SEARCH_FIRST,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX Points to unopenned FCB +; Function: +; Directory is searched for first matching entry and the directory +; entry is loaded at the disk transfer address +; Returns: +; AL = -1 if no entries matched, otherwise 0 + + invoke GETFILE +ASSUME DS:DOSGROUP +SAVPLCE: +; Search-for-next enters here to save place and report +; findings. + MOV DL,0 ; Do not XOR!!! + JC KILLSRCH + OR AH,AH ; Is it I/O device? + JS KILLIT ; If so, sign bit will end search + MOV AX,[LASTENT] + INC DL +KILLIT: + MOV ES:[DI.FILDIRENT],AX + MOV AX,WORD PTR [THISDPB] + MOV ES:[DI.fcb_DRVBP],AX + MOV AX,WORD PTR [THISDPB+2] + MOV ES:[DI.fcb_DRVBP+2],AX + MOV AX,[DIRSTART] + MOV ES:[DI.fcb_DRVBP+4],AX +; Information in directory entry must be copied into the first +; 33 bytes starting at the disk transfer address. + MOV SI,BX + LES DI,[DMAADD] + MOV AX,00FFH + CMP AL,[EXTFCB] + JNZ NORMFCB + STOSW + INC AL + STOSW + STOSW + MOV AL,[ATTRIB] + STOSB +NORMFCB: + MOV AL,[THISDRV] + INC AL + STOSB ; Set drive number + OR DL,DL + JZ DOSRELATIVE + MOV DS,WORD PTR [CURBUF+2] +ASSUME DS:NOTHING +DOSRELATIVE: + + IF KANJI + MOVSW + CMP BYTE PTR ES:[DI-2],5 + JNZ NOTKTRAN + MOV BYTE PTR ES:[DI-2],0E5H +NOTKTRAN: + MOV CX,15 + ELSE + MOV CX,16 + ENDIF + + REP MOVSW ; Copy 32 bytes of directory entry + XOR AL,AL + return + +ASSUME DS:NOTHING +KILLSRCH1: + PUSH DS + POP ES ; Make ES:DI point to the FCB +KILLSRCH: + MOV AX,-1 + MOV WORD PTR ES:[DI.FILDIRENT],AX + return +$DIR_SEARCH_FIRST ENDP + +BREAK <$Dir_Search_Next -- Find next matching directory entry> + procedure $DIR_SEARCH_NEXT,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX points to unopenned FCB returned by $DIR_SEARCH_FIRST +; Function: +; Directory is searched for the next matching entry and the directory +; entry is loaded at the disk transfer address +; Returns: +; AL = -1 if no entries matched, otherwise 0 + + invoke MOVNAMENOSET +ASSUME ES:DOSGROUP + MOV DI,DX + JC NEAR PTR KILLSRCH1 + MOV AX,[DI.FILDIRENT] + LES BP,DWORD PTR [DI.fcb_DRVBP] + OR AX,AX + JS NEAR PTR KILLSRCH1 + MOV BX,[DI.fcb_DRVBP+4] + PUSH DX + PUSH DS + PUSH AX + MOV WORD PTR [THISDPB],BP + MOV WORD PTR [THISDPB+2],ES + invoke SetDirSrch + ASSUME DS:DOSGROUP + POP AX + MOV [ENTLAST],-1 + invoke GetEnt + invoke NextEnt + POP ES + ASSUME ES:NOTHING + POP DI + JMP SAVPLCE +$DIR_SEARCH_NEXT ENDP + +BREAK <$Get_FCB_File_Length -- Return size of file in current records> + procedure $GET_FCB_FILE_LENGTH,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX points to unopenned FCB +; Function: +; Set random record field to size of file +; Returns: +; AL = -1 if no entries matched, otherwise 0 + + invoke GETFILE +ASSUME DS:DOSGROUP + MOV AL,-1 + retc + ADD DI,fcb_RR ; Write size in RR field + MOV CX,WORD PTR ES:[DI.fcb_RECSIZ-fcb_RR] + OR CX,CX + JNZ RECOK + MOV CX,128 +RECOK: + XOR DX,DX ; Intialize size to zero + INC SI + INC SI ; Point to length field + MOV DS,WORD PTR [CURBUF+2] +ASSUME DS:NOTHING + MOV AX,[SI+2] ; Get high word of size + DIV CX + PUSH AX ; Save high part of result + LODSW ; Get low word of size + DIV CX + OR DX,DX ; Check for zero remainder + POP DX + JZ DEVSIZ + INC AX ; Round up for partial record + JNZ DEVSIZ ; Propagate carry? + INC DX +DEVSIZ: + STOSW + MOV AX,DX + STOSB + MOV AL,0 + CMP CX,64 + JAE RET14 ; Only 3-byte field if fcb_RECSIZ >= 64 + MOV ES:[DI],AH +RET14: return +$GET_FCB_FILE_LENGTH ENDP + +BREAK <$Get_Fcb_Position -- Set random record field to current position> + procedure $GET_FCB_POSITION,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX points to openned FCB +; Function: +; Sets random record field to be same as current record fields +; Returns: +; None + + invoke GETREC + MOV WORD PTR [DI+fcb_RR],AX + MOV [DI+fcb_RR+2],DL + CMP [DI.fcb_RECSIZ],64 + JAE RET16 + MOV [DI+fcb_RR+2+1],DH ; Set 4th byte only if record size < 64 +RET16: return +$GET_FCB_POSITION ENDP + +BREAK <$Disk_Reset -- Flush out all dirty buffers> + procedure $DISK_RESET,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; None +; Function: +; Flush and invalidate all buffers +; Returns: +; Nothing + + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV AL,-1 + invoke FLUSHBUF + MOV WORD PTR [LASTBUFFER+2],-1 + MOV WORD PTR [LASTBUFFER],-1 + invoke SETVISIT +ASSUME DS:NOTHING +NBFFR: ; Free ALL buffers + MOV [DI.VISIT],1 ; Mark as visited + CMP BYTE PTR [DI.BUFDRV],-1 + JZ SKPBF ; Save a call to PLACEBUF + MOV WORD PTR [DI.BUFDRV],00FFH + invoke SCANPLACE +SKPBF: + invoke SKIPVISIT + JNZ NBFFR + return +$DISK_RESET ENDP + + procedure $RAW_CON_IO,NEAR ; System call 6 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DL = -1 if input +; else DL is output character +; Function: +; Input or output raw character from console, no echo +; Returns: +; AL = character + + MOV AL,DL + CMP AL,-1 + JNZ RAWOUT + LES DI,DWORD PTR [user_SP] ; Get pointer to register save area + XOR BX,BX + invoke GET_IO_FCB + retc + MOV AH,1 + invoke IOFUNC + JNZ RESFLG + invoke SPOOLINT + OR BYTE PTR ES:[DI.user_F],40H ; Set user's zero flag + XOR AL,AL + return + +RESFLG: + AND BYTE PTR ES:[DI.user_F],0FFH-40H ; Reset user's zero flag + +RILP: + invoke SPOOLINT + entry $RAW_CON_INPUT ; System call 7 + +; Inputs: +; None +; Function: +; Input raw character from console, no echo +; Returns: +; AL = character + + XOR BX,BX + invoke GET_IO_FCB + retc + MOV AH,1 + invoke IOFUNC + JZ RILP + XOR AH,AH + invoke IOFUNC + return +; +; Output the character in AL to stdout +; +entry RAWOUT + + PUSH BX + MOV BX,1 + + invoke GET_IO_FCB + JC RAWRET1 + + TEST [SI.fcb_DEVID],080H ; output to file? + JZ RAWNORM ; if so, do normally + PUSH DS + PUSH SI + LDS SI,DWORD PTR [SI.fcb_FIRCLUS] ; output to special? + TEST BYTE PTR [SI+SDEVATT],ISSPEC + POP SI + POP DS + JZ RAWNORM ; if not, do normally + INT int_fastcon ; quickly output the char + JMP SHORT RAWRET +RAWNORM: + + CALL RAWOUT3 +RAWRET: CLC +RAWRET1: + POP BX + return + +; +; Output the character in AL to handle in BX +; +entry RAWOUT2 + + invoke GET_IO_FCB + retc +RAWOUT3: + PUSH AX + JMP SHORT RAWOSTRT +ROLP: + invoke SPOOLINT +RAWOSTRT: + MOV AH,3 + CALL IOFUNC + JZ ROLP + POP AX + MOV AH,2 + CALL IOFUNC + CLC ; Clear carry indicating successful + return +$RAW_CON_IO ENDP + +ASSUME DS:NOTHING,ES:NOTHING +; This routine is called at DOS init + + procedure OUTMES,NEAR ; String output for internal messages + LODS CS:BYTE PTR [SI] + CMP AL,"$" + retz + invoke OUT + JMP SHORT OUTMES + return +OutMes ENDP + ASSUME SS:DOSGROUP + +BREAK <$Parse_File_Descriptor -- Parse an arbitrary string into an FCB> + procedure $PARSE_FILE_DESCRIPTOR,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:SI Points to a command line +; ES:DI Points to an empty FCB +; Bit 0 of AL = 1 At most one leading separator scanned off +; = 0 Parse stops if separator encountered +; Bit 1 of AL = 1 If drive field blank in command line - leave FCB +; = 0 " " " " " " - put 0 in FCB +; Bit 2 of AL = 1 If filename field blank - leave FCB +; = 0 " " " - put blanks in FCB +; Bit 3 of AL = 1 If extension field blank - leave FCB +; = 0 " " " - put blanks in FCB +; Function: +; Parse command line into FCB +; Returns: +; AL = 1 if '*' or '?' in filename or extension, 0 otherwise +; DS:SI points to first character after filename + + invoke MAKEFCB + PUSH SI + invoke get_user_stack + POP [SI.user_SI] + return +$PARSE_FILE_DESCRIPTOR ENDP + +BREAK <$Create_Process_Data_Block,SetMem -- Set up process data block> +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + procedure $Dup_PDB,NEAR +ASSUME DS:NOTHING,ES:NOTHING + MOV BYTE PTR [CreatePDB], 0FFH ; indicate a new process +$Dup_PDB ENDP + + + procedure $CREATE_PROCESS_DATA_BLOCK,NEAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + +; Inputs: +; DX = Segment number of new base +; Function: +; Set up program base and copy term and ^C from int area +; Returns: +; None +; Called at DOS init + + MOV ES,DX + TEST BYTE PTR [CreatePDB],0FFh + JZ create_PDB_old + MOV DS,[CurrentPDB] + JMP SHORT Create_copy + +Create_PDB_old: + invoke get_user_stack + MOV DS,[SI.user_CS] + +Create_copy: + XOR SI,SI ; copy all 80h bytes + MOV DI,SI + MOV CX,80H + REP MOVSW + + TEST BYTE PTR [CreatePDB],0FFh ; Shall we create a process? + JZ Create_PDB_cont ; nope, old style call +; +; Here we set up for a new process... +; + + PUSH CS + POP DS + ASSUME DS:DOSGROUP + XOR BX,BX ; dup all jfns + MOV CX,FilPerProc + +Create_dup_jfn: + PUSH ES ; save new PDB + invoke get_jfn_pointer ; ES:DI is jfn + JC create_skip ; not a valid jfn + PUSH ES ; save him + PUSH DI + invoke get_sf_from_jfn ; get sf pointer + JC create_no_inc + INC ES:[DI].sf_ref_count ; new fh + +create_no_inc: + POP DI + POP ES ; get old jfn + MOV AL,ES:[DI] ; get sfn + POP ES + PUSH ES + MOV AL,ES:[BX] ; copy into new place! + +create_skip: + POP ES + INC BX ; next jfn... + LOOP create_dup_jfn + + PUSH [CurrentPDB] ; get current process + POP BX + PUSH BX + POP ES:[PDB_Parent_PID] ; stash in child + MOV [CurrentPDB],ES + ASSUME DS:NOTHING + MOV DS,BX +; +; end of new process create +; +Create_PDB_cont: + MOV BYTE PTR [CreatePDB],0h ; reset flag + MOV AX,DS:[2] ; set up size for fall through + +entry SETMEM +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + +; Inputs: +; AX = Size of memory in paragraphs +; DX = Segment +; Function: +; Completely prepares a program base at the +; specified segment. +; Called at DOS init +; Outputs: +; DS = DX +; ES = DX +; [0] has INT int_abort +; [2] = First unavailable segment ([ENDMEM]) +; [5] to [9] form a long call to the entry point +; [10] to [13] have exit address (from int_terminate) +; [14] to [17] have ctrl-C exit address (from int_ctrl_c) +; [18] to [21] have fatal error address (from int_fatal_abort) +; DX,BP unchanged. All other registers destroyed. + + XOR CX,CX + MOV DS,CX + MOV ES,DX + MOV SI,addr_int_terminate + MOV DI,SAVEXIT + MOV CX,6 + REP MOVSW + MOV ES:[2],AX + SUB AX,DX + CMP AX,MAXDIF + JBE HAVDIF + MOV AX,MAXDIF +HAVDIF: + MOV BX,ENTRYPOINTSEG + SUB BX,AX + MOV CL,4 + SHL AX,CL + MOV DS,DX + MOV WORD PTR DS:[PDB_CPM_Call+1],AX + MOV WORD PTR DS:[PDB_CPM_Call+3],BX + MOV DS:[PDB_Exit_Call],(int_abort SHL 8) + mi_INT + MOV BYTE PTR DS:[PDB_CPM_Call],mi_Long_CALL + MOV WORD PTR DS:[PDB_Call_System],(int_command SHL 8) + mi_INT + MOV BYTE PTR DS:[PDB_Call_System+2],mi_Long_RET + return + +$CREATE_PROCESS_DATA_BLOCK ENDP + do_ext + + CODE ENDS + END + \ No newline at end of file diff --git a/MORE.ASM b/MORE.ASM new file mode 100644 index 0000000000000000000000000000000000000000..6c9bf9510681df4c1fd8ce54f0d6a0300b6a4ac9 GIT binary patch literal 3712 zcmY#@f)LLTA6Eqh1z-OlR|Vf-T^Ijgg@DBL%)G>sR0X%poRZWcUM@FBpJ0$8*T7J) zHUnO+kf2bIhyqN=&p$)~tc;h7m&?=1H_SCi0WJwr%**BN=;!6B02bwhD)kKptAi_q z3iEP-tx-@=@bq)`33YK*aPbcgj`Y=Y4E6%e4D8ve60a!OURKmbaM-Lr$ z*O2%y*Pviee?Nppo_--<2JUK|#UG5$tgVe{UE6V1#;Ke~3F>B6R%S+=5+0 z6r3Dg!d!zeRXBR+1c$i9JNx^^2ZscC`nkvZhlT`%h9Fd8^%GnW6rfLKx;;r^pajg@BMC1z*RAApdY3BNK!gSD#>41P`YUQ-m5Eo*4;ppe$W}>5qPLQi3l2us49U8+5juGH+hX#OxmtPc^8SEP39Kp-w;_v5b z1uh^V3C{?WF~M?Hpu!wd95|yI0dq&Nr;ZCaMnllT!N=bv*a;C5@KVS}#}GMBctKpE z0CEF%)y4>6n7jS_L!7bX1b7kP92x}5dxl6lp@m?uhksCrf@iR^Ur3M-C?SH4vQkh$ zb{|qQN3ziesXXxXa|Q<>vW-Fh;l$bJ_J#-+kfY9OS;sSP*qlb<;lBgeC z)DQ#=3=EKrg9S8ll7U$PF(0Lb#pjn0C!|~ot7Kq}2C&1B2x|pTCtn3;f4`6*e;);B z562)!=MdK*g@7PWKcxB%7BP-KI_e7Q2v2!ALCnI44U8%P<`DGS4#{M5h*_wlwSuD$ zlEZ=_E>my{4N-7%^+AqaTnPiyDOeIUN=ktRJeIhHJJ&-8Qt=^&1*DmQ5f+|U>_f>! zF#E71dtNT6aY%6rQ|{uUgWUds2_v;uh-#)F>2nSZLU9Ipb`;O#yAFh zgPO$HoCxpkA}<$M z)=EJECJb&hfNX)ZRuvRnpd|*V*$T-)2r&x-UM@%yM2H!Jg`E9;P=sKPa*YTH@&ord zf?Pu)Laaa@)PXePA#7-HLpYE&378FX5~yPXGRW1>1*u!$3N5F>9UERQ24n!zB{gsW E03 + +CODSTRT EQU $ + + IF NOT IBM + IF NOT KANJI + PUBLIC HEADER +HEADER DB 13,10,"Microsoft MS-DOS version " + DB DOS_MAJOR_VERSION + "0" + DB "." + DB (DOS_MINOR_VERSION / 10) + "0" + DB (DOS_MINOR_VERSION MOD 10) + "0" + IF HIGHMEM + DB "H" + ENDIF + ENDIF + IF KANJI + PUBLIC HEADER +HEADER DB 13,10,82h,"M"+1fh,82h,"i"+20h,82h,"c"+20h,82h,"r"+20h,82h,"o"+20h + DB 82h,"s"+20h,82h,"o"+20h,82h,"f"+20h,82h,"t"+20h + DB 81h,40h,82h,"M"+1fh,82h,"S"+1fh,81h,5dh+1fh + DB 82h,"D"+1fh,82h,"O"+1fh,82h,"S"+1fh,81h,40h + DB 82h,DOS_MAJOR_VERSION+"0"+1fh + DB 81h,25h+1fh + DB 82h,(DOS_MINOR_VERSION / 10)+"0"+1fh + DB 82h,(DOS_MINOR_VERSION MOD 10)+"0"+1fh + DB 94h,0c5h + ENDIF + DB 13,10 + DB "Copyright 1981,82,83 Microsoft Corp.",13,10,"$" + ENDIF +BREAK +ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + + procedure SYSTEM_CALL,NEAR +entry QUIT ; INT 20H entry point + MOV AH,0 + JMP SHORT SAVREGS + +entry COMMAND ; Interrupt call entry point (INT 21H) + + IF NOT IBM + CMP AH,SET_OEM_HANDLER + JB NOTOEM + JMP $SET_OEM_HANDLER +NOTOEM: + ENDIF + + CMP AH,MAXCOM + JBE SAVREGS +BADCALL: + MOV AL,0 +entry IRET + IRET + +entry CALL_ENTRY ; System call entry point and dispatcher + POP AX ; IP from the long call at 5 + POP AX ; Segment from the long call at 5 + POP [User_SP] ; IP from the CALL 5 + PUSHF ; Start re-ordering the stack + CLI + PUSH AX ; Save segment + PUSH [User_SP] ; Stack now ordered as if INT had been used + CMP CL,MAXCALL ; This entry point doesn't get as many calls + JA BADCALL + MOV AH,CL +SAVREGS: + CALL save_world + MOV [SaveDS],DS + MOV [SaveBX],BX + MOV BX,CS + MOV DS,BX +ASSUME DS:DOSGROUP + INC [INDOS] ; Flag that we're in the DOS + MOV AX,[user_SP] + MOV [NSP],AX + MOV AX,[user_SS] + MOV [NSS],AX + POP AX + PUSH AX + MOV [user_SP],SP + MOV [user_SS],SS +; +; save user stack in his area for later returns (possibly from EXEC) +; Here comes multitasking!!! +; + MOV DS,[CurrentPDB] + MOV WORD PTR DS:[PDB_User_stack],SP + MOV WORD PTR DS:[PDB_User_stack+2],SS + + MOV BX,CS ; no holes here. + MOV SS,BX +ASSUME SS:DOSGROUP + + entry REDISP + MOV SP,OFFSET DOSGROUP:AUXSTACK ; Enough stack for interrupts + STI ; Stack OK now + PUSH CS + POP DS + XOR BH,BH + MOV [CONSWAP],BH + MOV [IDLEINT],1 + MOV BYTE PTR [NoSetDir],0 ; set directories on search + MOV BL,AH + SHL BX,1 + CLD + OR AH,AH + JZ DSKROUT ; ABORT + CMP AH,12 + JBE IOROUT ; Character I/O + CMP AH,GET_CURRENT_PDB ; INT 24 needs GET,SET PDB + JZ IOROUT + CMP AH,SET_CURRENT_PDB + JNZ DSKROUT +IOROUT: + CMP [ERRORMODE],0 + JNZ DISPCALL ; Stay on AUXSTACK if INT 24 + MOV SP,OFFSET DOSGROUP:IOSTACK + JMP SHORT DISPCALL + +DSKROUT: + MOV [ERRORMODE],0 ; Cannot make non 1-12 calls in + MOV [WPERR],-1 ; error mode, so good place to + ; make sure flags are reset + MOV SP,OFFSET DOSGROUP:DSKSTACK + TEST [CNTCFLAG],-1 + JZ DISPCALL + PUSH AX + invoke DSKSTATCHK + POP AX +DISPCALL: + PUSH [LEAVEADDR] + PUSH CS:[BX+DISPATCH] + MOV BX,[SaveBX] + MOV DS,[SaveDS] +ASSUME DS:NOTHING + return + + entry LEAVE +ASSUME SS:NOTHING ; User routines may misbehave + CLI + DEC [INDOS] + MOV SP,[user_SP] + MOV SS,[user_SS] + MOV BP,SP + MOV BYTE PTR [BP.user_AX],AL + MOV AX,[NSP] + MOV [user_SP],AX + MOV AX,[NSS] + MOV [user_SS],AX + CALL restore_world + + IRET +SYSTEM_CALL ENDP + +; +; restore_world restores all registers ('cept SS:SP, CS:IP, flags) from +; the stack prior to giving the user control +; + ASSUME DS:NOTHING,ES:NOTHING +restore_tmp DW ? + procedure restore_world,NEAR + POP restore_tmp ; POP restore_tmp + POP AX ; PUSH ES + POP BX ; PUSH DS + POP CX ; PUSH BP + POP DX ; PUSH DI + POP SI ; PUSH SI + POP DI ; PUSH DX + POP BP ; PUSH CX + POP DS ; PUSH BX + POP ES ; PUSH AX +world_ret: + PUSH restore_tmp ; PUSH restore_tmp + return +restore_world ENDP + +; +; save_world saves complete registers on the stack +; + procedure save_world,NEAR + POP restore_tmp + PUSH ES + PUSH DS + PUSH BP + PUSH DI + PUSH SI + PUSH DX + PUSH CX + PUSH BX + PUSH AX + JMP SHORT world_ret +save_world ENDP + +; +; get_user_stack returns the user's stack (and hence registers) in DS:SI +; + procedure get_user_stack,NEAR + LDS SI,DWORD PTR [user_SP] + return +get_user_stack ENDP + +; Standard Functions +DISPATCH LABEL WORD +.lall + short_addr $ABORT ; 0 0 +.xall + short_addr $STD_CON_INPUT ; 1 1 + short_addr $STD_CON_OUTPUT ; 2 2 + short_addr $STD_AUX_INPUT ; 3 3 + short_addr $STD_AUX_OUTPUT ; 4 4 + short_addr $STD_PRINTER_OUTPUT ; 5 5 + short_addr $RAW_CON_IO ; 6 6 + short_addr $RAW_CON_INPUT ; 7 7 + short_addr $STD_CON_INPUT_NO_ECHO ; 8 8 + short_addr $STD_CON_STRING_OUTPUT ; 9 9 + short_addr $STD_CON_STRING_INPUT ; 10 A + short_addr $STD_CON_INPUT_STATUS ; 11 B + short_addr $STD_CON_INPUT_FLUSH ; 12 C + short_addr $DISK_RESET ; 13 D + short_addr $SET_DEFAULT_DRIVE ; 14 E + short_addr $FCB_OPEN ; 15 F + short_addr $FCB_CLOSE ; 16 10 + short_addr $DIR_SEARCH_FIRST ; 17 11 + short_addr $DIR_SEARCH_NEXT ; 18 12 + short_addr $FCB_DELETE ; 19 13 + short_addr $FCB_SEQ_READ ; 20 14 + short_addr $FCB_SEQ_WRITE ; 21 15 + short_addr $FCB_CREATE ; 22 16 + short_addr $FCB_RENAME ; 23 17 + short_addr CPMFUNC ; 24 18 + short_addr $GET_DEFAULT_DRIVE ; 25 19 + short_addr $SET_DMA ; 26 1A + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + short_addr $SLEAZEFUNC ; 27 1B + short_addr $SLEAZEFUNCDL ; 28 1C +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + + short_addr CPMFUNC ; 29 1D + short_addr CPMFUNC ; 30 1E +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + short_addr $GET_DEFAULT_DPB ; 31 1F +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + short_addr CPMFUNC ; 32 20 + short_addr $FCB_RANDOM_READ ; 33 21 + short_addr $FCB_RANDOM_WRITE ; 34 22 + short_addr $GET_FCB_FILE_LENGTH ; 35 23 + short_addr $GET_FCB_POSITION ; 36 24 +MAXCALL = ($-DISPATCH)/2 - 1 + +; Extended Functions + short_addr $SET_INTERRUPT_VECTOR ; 37 25 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + short_addr $CREATE_PROCESS_DATA_BLOCK ; 38 26 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + short_addr $FCB_RANDOM_READ_BLOCK ; 39 27 + short_addr $FCB_RANDOM_WRITE_BLOCK ; 40 28 + short_addr $PARSE_FILE_DESCRIPTOR ; 41 29 + short_addr $GET_DATE ; 42 2A + short_addr $SET_DATE ; 43 2B + short_addr $GET_TIME ; 44 2C + short_addr $SET_TIME ; 45 2D + short_addr $SET_VERIFY_ON_WRITE ; 46 2E + +; Extended functionality group + short_addr $GET_DMA ; 47 2F + short_addr $GET_VERSION ; 48 30 + short_addr $Keep_Process ; 49 31 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + short_addr $GET_DPB ; 50 32 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + short_addr $SET_CTRL_C_TRAPPING ; 51 33 + short_addr $GET_INDOS_FLAG ; 52 34 + short_addr $GET_INTERRUPT_VECTOR ; 53 35 + short_addr $GET_DRIVE_FREESPACE ; 54 36 + short_addr $CHAR_OPER ; 55 37 + short_addr $INTERNATIONAL ; 56 38 +; XENIX CALLS +; Directory Group + short_addr $MKDIR ; 57 39 + short_addr $RMDIR ; 58 3A + short_addr $CHDIR ; 59 3B +; File Group + short_addr $CREAT ; 60 3C + short_addr $OPEN ; 61 3D + short_addr $CLOSE ; 62 3E + short_addr $READ ; 63 3F + short_addr $WRITE ; 64 40 + short_addr $UNLINK ; 65 41 + short_addr $LSEEK ; 66 42 + short_addr $CHMOD ; 67 43 + short_addr $IOCTL ; 68 44 + short_addr $DUP ; 69 45 + short_addr $DUP2 ; 70 46 + short_addr $CURRENT_DIR ; 71 47 +; Memory Group + short_addr $ALLOC ; 72 48 + short_addr $DEALLOC ; 73 49 + short_addr $SETBLOCK ; 74 4A +; Process Group + short_addr $EXEC ; 75 4B + short_addr $EXIT ; 76 4C + short_addr $WAIT ; 77 4D + short_addr $FIND_FIRST ; 78 4E +; Special Group + short_addr $FIND_NEXT ; 79 4F +; SPECIAL SYSTEM GROUP +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + short_addr $SET_CURRENT_PDB ; 80 50 + short_addr $GET_CURRENT_PDB ; 81 51 + short_addr $GET_IN_VARS ; 82 52 + short_addr $SETDPB ; 83 53 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + short_addr $GET_VERIFY_ON_WRITE ; 84 54 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + short_addr $DUP_PDB ; 85 55 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + short_addr $RENAME ; 86 56 + short_addr $FILE_TIMES ; 87 57 + short_addr $AllocOper ; 88 58 + +MAXCOM = ($-DISPATCH)/2 - 1 + +CPMFUNC: + XOR AL,AL + return + + IF NOT IBM +BREAK + +$SET_OEM_HANDLER: +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; User registers, User Stack, INTS disabled +; If CALL F8, DS:DX is new handler address +; Function: +; Process OEM INT 21 extensions +; Outputs: +; Jumps to OEM_HANDLER if appropriate + + JNE DO_OEM_FUNC ; If above F8 try to jump to handler + MOV WORD PTR [OEM_HANDLER],DX ; Set Handler + MOV WORD PTR [OEM_HANDLER+2],DS + IRET ; Quick return, Have altered no registers + +DO_OEM_FUNC: + CMP WORD PTR [OEM_HANDLER],-1 + JNZ OEM_JMP + JMP BADCALL ; Handler not initialized + +OEM_JMP: + JMP [OEM_HANDLER] + + ENDIF + + +ASSUME SS:DOSGROUP + +; +; $Set_current_PDB takes BX and sets it to be the current process +; *** THIS FUNCTION CALL IS SUBJECT TO CHANGE!!! *** +; + procedure $SET_CURRENT_PDB,NEAR + ASSUME DS:NOTHING,SS:NOTHING + MOV [CurrentPDB],BX + return +$SET_CURRENT_PDB ENDP + +; +; $get_current_PDB returns in BX the current process +; *** THIS FUNCTION CALL IS SUBJECT TO CHANGE!!! *** +; + procedure $GET_CURRENT_PDB,NEAR + ASSUME DS:NOTHING,SS:NOTHING + invoke get_user_stack + PUSH [CurrentPDB] + POP [SI.user_BX] + return +$GET_CURRENT_PDB ENDP +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +BREAK + procedure SNULDEV,FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + MOV WORD PTR [NULLDEVPT],BX + MOV WORD PTR [NULLDEVPT+2],ES + return +SNULDEV ENDP + + procedure INULDEV,FAR + PUSH ES + PUSH BX + LES BX,[NULLDEVPT] + OR ES:[BX.REQSTAT],STDON ; Set done bit + POP BX + POP ES + return + +INULDEV ENDP + + +BREAK > + + + IF IBM +ERRIN: ; Codes returned by BIOS + DB 2 ; NO RESPONSE + DB 6 ; SEEK FAILURE + DB 12 ; GENERAL ERROR + DB 4 ; BAD CRC + DB 8 ; SECTOR NOT FOUND + DB 0 ; WRITE ATTEMPT ON WRITE-PROTECT DISK +ERROUT: ; DISK ERRORS RETURNED FROM INT 25 and 26 + DB 80H ; NO RESPONSE + DB 40H ; Seek failure + DB 2 ; Address Mark not found + DB 8 ; DMA OVERRUN + DB 4 ; SECTOR NOT FOUND + DB 3 ; WRITE ATTEMPT TO WRITE-PROTECT DISK + +NUMERR EQU $-ERROUT + ENDIF + + procedure ABSDRD,FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + + CLI + MOV [user_SS],SS + MOV [user_SP],SP + PUSH CS + POP SS +ASSUME SS:DOSGROUP + MOV SP,OFFSET DOSGROUP:DSKSTACK + INC BYTE PTR [INDOS] + STI + CLD + PUSH ES + PUSH DS + PUSH SS + POP DS +ASSUME DS:DOSGROUP + invoke GETBP + POP DS +ASSUME DS:NOTHING + JC ILEAVE + invoke DSKREAD +TLEAVE: + JZ ILEAVE + + IF IBM +; Translate the error code to ancient 1.1 codes + PUSH ES + PUSH CS + POP ES + XOR AH,AH ; Nul error code + MOV CX,NUMERR ; Number of possible error conditions + MOV DI,OFFSET DOSGROUP:ERRIN ; Point to error conditions + REPNE SCASB + JNZ LEAVECODE ; Not found + MOV AH,ES:[DI+NUMERR-1] ; Get translation +LEAVECODE: + POP ES + ENDIF + + STC +ILEAVE: + POP ES + CLI + DEC BYTE PTR [INDOS] + MOV SP,[user_SP] + MOV SS,[user_SS] +ASSUME SS:NOTHING + STI + return +ABSDRD ENDP + + procedure ABSDWRT,FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + + CLI + MOV [user_SS],SS + MOV [user_SP],SP + PUSH CS + POP SS +ASSUME SS:DOSGROUP + MOV SP,OFFSET DOSGROUP:DSKSTACK + INC BYTE PTR [INDOS] + STI + CLD + PUSH ES + PUSH DS + PUSH SS + POP DS +ASSUME DS:DOSGROUP + invoke GETBP + POP DS +ASSUME DS:NOTHING + JC ILEAVE + invoke DSKWRITE + JMP TLEAVE +ABSDWRT ENDP + + + + procedure SYS_RETURN,NEAR + ASSUME DS:NOTHING,ES:NOTHING + entry SYS_RET_OK + call get_user_stack + PUSH [SI.user_F] + POPF + CLC + JMP SHORT DO_RET + + entry SYS_RET_ERR + XOR AH,AH ; hack to allow for smaller error rets + call get_user_stack + PUSH [SI.user_F] + POPF + STC +DO_RET: + MOV [SI.user_AX],AX ; Really only sets AH + PUSHF + POP [SI.user_F] ; dump on his flags + return +SYS_RETURN ENDP + +do_ext + +CODE ENDS + END + \ No newline at end of file diff --git a/MSDATA.ASM b/MSDATA.ASM new file mode 100644 index 0000000..ed524e8 --- /dev/null +++ b/MSDATA.ASM @@ -0,0 +1,342 @@ +SUBTTL Initialized data and data used at DOS initialization +PAGE +; DATA AREA for MS-DOS + +IFNDEF KANJI +KANJI EQU 0 ;FALSE +ENDIF + +CONSTANTS SEGMENT BYTE PUBLIC 'CONST' + EXTRN international_table:BYTE + EXTRN Current_Country:WORD + + + ORG 0 +CONSTRT EQU $ ; Start of constants segment + + PUBLIC DevStrLen +DEVSTRLEN DB 3 ; Size of below + PUBLIC DevString +DEVSTRING DB "DEV" ; Dummy device directory + +; +; Table of routines for assignable devices +; +; MSDOS allows assignment if the following standard devices: +; stdin (usually CON input) +; stdout (usually CON output) +; auxin (usually AUX input) +; auxout (usually AUX output) +; stdlpt (usually PRN output) +; +; SPECIAL NOTE: +; Status of a file is a strange idea. We choose to handle it in this manner: +; If we're not at end-of-file, then we always say that we have a character. +; Otherwise, we return ^Z as the character and set the ZERO flag. In this +; manner we can support program written under the old DOS (they use ^Z as EOF +; on devices) and programs written under the new DOS (they use the ZERO flag +; as EOF). + +; Default FCBs for boot up + +sftabl LABEL DWORD ; file table + DW -1 + DW -1 + DW sf_default_number ; Number of entries in table + DB sf_default_number DUP ( (SIZE sf_entry) DUP (0)) + + I_AM NoSetDir,BYTE ; true -> do not set directory + I_am DidCTRLC,BYTE ; true -> we did a ^C exit + I_am SpaceFlag,BYTE ; true -> embedded spaces are allowed + ; in FCB +; the next two variables relate to the position of the logical stdout/stdin +; cursor. They are only meaningful when stdin/stdout are assigned to the +; console. + + i_am CARPOS,BYTE ; cursor position in stdin + i_am STARTPOS,BYTE ; position of cursor at beginning + ; of buffered input call + I_AM PFLAG,BYTE + I_AM VERFLG,BYTE ; Initialize with verify off + I_AM CONTPOS,WORD + PUBLIC CHARCO +CHARCO DB 00000011B ; Allows statchks every 4 chars... + + I_AM DMAADD,DWORD ; User's disk transfer address + ; (disp/seg) + ORG $-CONSTRT-4 + DW 80H + DW ? + +ENDMEM DW ? + + PUBLIC switch_character +switch_character DB '/' + + PUBLIC device_availability +device_availability DB 0FFH + + I_AM FirstArena,WORD ; first free block found + I_AM BestArena,WORD ; best free block found + I_AM LastArena,WORD ; last free block found + I_AM AllocMethod,BYTE ; how to alloc first(best)last + I_AM arena_head,WORD + +; The following block of data is used by SYSINIT. Do not change the order or +; size of this block + + PUBLIC SYSINITVAR +SYSINITVAR LABEL WORD + I_AM DPBHEAD,DWORD ; Pointer to head of DPB-FAT list + I_AM sft_addr,DWORD ; Pointer to first FCB table + ORG $-CONSTRT-4 + short_addr sftabl + DW ? ; DOS segment set at INIT + +; The following address points to the CLOCK device + i_am BCLOCK,DWORD +; The following address is used by DISKSTATCHK it is always points to the +; console input device header + I_AM BCON,DWORD ; Console device entry points + i_am NUMIO,BYTE ; Number of disk tables +MAXSEC DW 0 ; Maximum allowed sector size + I_AM BUFFHEAD,DWORD ; Pointer to head of buffer queue +DEVHEAD LABEL DWORD + I_AM NULDEV,DWORD ; Set to list start passed by + ; BIOS at DOS Init + + DW DEVTYP OR ISNULL + short_addr SNULDEV + short_addr INULDEV + DB "NUL " + + + i_am DAY,BYTE + i_am MONTH,BYTE + i_am YEAR,WORD + i_am DAYCNT,WORD + i_am WEEKDAY,BYTE + ORG $-CONSTRT-7 + DB 0,0 + DW 0,-1 + DB 0 + + I_AM CURDRV,BYTE ; Default to drive A + I_AM LASTENT,WORD + i_am INDOS,BYTE ; DOS status for interrupt processing + ORG $-CONSTRT-1 + DB 0 + I_AM ErrorMode,BYTE ; Flag for INT 24 processing + PUBLIC WPErr +WPERR DB -1 ; Write protect error flag + I_AM CONSWAP,BYTE + PUBLIC IDLEINT +IDLEINT DB 1 + PUBLIC CNTCFLAG +CNTCFLAG DB 0 ; ^C check in dispatch disabled + + PUBLIC LastBuffer +LASTBUFFER LABEL DWORD ; Buffer queue recency pointer + DW -1 + DW -1 + +; Combination of all device call parameters + + PUBLIC DEVCALL +DEVCALL SRHEAD <> +CALLUNIT LABEL BYTE +CALLFLSH LABEL WORD + I_AM CALLMED,BYTE +CALLBR LABEL DWORD + PUBLIC CALLXAD +CALLXAD LABEL DWORD + I_AM CALLRBYT,BYTE + DB 3 DUP(?) + PUBLIC CallBPB +CALLBPB LABEL DWORD + I_AM CALLSCNT,WORD +CALLSSEC DW ? + + I_AM CALLDEVAD,DWORD ; stash for device entry point + +; Same as above for I/O calls + + PUBLIC IOCall +IOCALL SRHEAD <> +IOFLSH LABEL WORD + PUBLIC IORCHR +IORCHR LABEL BYTE + I_AM IOMED,BYTE + I_AM IOXAD,DWORD + I_AM IOSCNT,WORD + I_AM IOSSEC,WORD + +; Call struct for DSKSTATCHK + PUBLIC DSKSTCALL +DSKSTCALL DB DRDNDHL + DB 0 + PUBLIC DSKSTCOM +DSKSTCOM DB DEVRDND + I_AM DSKSTST,WORD + DB 8 DUP (0) + I_AM DSKCHRET,BYTE + short_addr DEVIOBUF + DW ? ; DOS segment set at Init + PUBLIC DSKSTCNT +DSKSTCNT DW 1 + DW 0 + +; Days in year + i_am YRTAB,8 + ORG $-CONSTRT-8 + DB 200,166 ; Leap year + DB 200,165 + DB 200,165 + DB 200,165 + +; Days of each month + i_am MONTAB,12 + ORG $-CONSTRT-12 + DB 31 ; January + DB 28 ; February--reset each + ; time year changes + DB 31 ; March + DB 30 ; April + DB 31 ; May + DB 30 ; June + DB 31 ; July + DB 31 ; August + DB 30 ; September + DB 31 ; October + DB 30 ; November + DB 31 ; December + + IF NOT IBM + PUBLIC OEM_HANDLER +OEM_HANDLER DD -1 + ENDIF + +;WARNING For HIGHMEM version, these two vars must be at the end of the +; Constants segment to prevent them getting overwritten. + I_AM CurrentPDB,WORD + i_am CreatePDB,BYTE ; flag for creating a process + + PUBLIC LEAVEADDR +LEAVEADDR LABEL WORD + short_addr LEAVE + +CONSTANTS ENDS + +SUBTTL Uninitialized data overlayed by initialization code +PAGE +DATA SEGMENT WORD PUBLIC 'DATA' +; Init code overlaps with data area below + + ORG 0 + i_am INBUF,128 + I_AM CONBUF,131 ; The rest of INBUF and console buffer + i_am TIMEBUF,6 + I_AM DEVIOBUF,2 ; Buffer for I/O under file assignment + I_AM EXITHOLD,DWORD + + PUBLIC DevFCB +DEVFCB LABEL BYTE ; Uses NAME1, NAME2, NAME3 combined +; WARNING.. do not alter size or relative location of the following 4 items +; without first examining FCB_RENAME + I_AM NAME1,12 ; File name buffer + I_AM ATTRIB,BYTE + I_AM NAME2,13 + I_AM NAME3,14 + + I_AM EXTFCB,BYTE + +; WARNING - the following two items are accessed as a word + I_AM CREATING,BYTE + I_AM DELALL,BYTE + + I_AM FoundDel,BYTE + + I_AM user_SP,WORD + I_AM user_SS,WORD + I_AM CONTSTK,WORD + I_AM SECCLUSPOS,BYTE ; Position of first sector + ; within cluster + I_AM DSKERR,BYTE + I_AM TRANS,BYTE + I_AM READOP,BYTE + I_AM THISDRV,BYTE + I_AM THISDPB,DWORD + I_AM CLUSFAC,BYTE + +; WARNING - the following two items are accessed as a word + I_AM DRIVESPEC,BYTE + I_AM ROOTSTART,BYTE + + I_AM CLUSSPLIT,BYTE + i_am INSMODE,BYTE + I_AM CLUSSAVE,WORD + I_AM CLUSSEC,WORD + I_AM PREREAD,WORD ; 0 means preread; 1 means optional + I_AM FATBYT,WORD + I_AM DEVPT,DWORD + I_AM THISFCB,DWORD ; Address of user FCB + + I_AM NEXTADD,WORD + I_AM RECPOS,4 + I_AM RECCNT,WORD + I_AM LASTPOS,WORD + I_AM CLUSNUM,WORD + I_AM DIRSEC,WORD + I_AM DIRSTART,WORD + I_AM SECPOS,WORD ; Position of first sector accessed + I_AM VALSEC,WORD ; Number of valid (previously written) + ; sectors + I_AM BYTSECPOS,WORD ; Position of first byte within sector + I_AM BYTPOS,4 ; Byte position in file of access + I_AM BYTCNT1,WORD ; No. of bytes in first sector + I_AM BYTCNT2,WORD ; No. of bytes in last sector + I_AM SECCNT,WORD ; No. of whole sectors + I_AM ENTFREE,WORD + I_AM ENTLAST,WORD + I_AM NXTCLUSNUM,WORD + I_AM GROWCNT,DWORD + I_AM CURBUF,DWORD + I_AM VOLID,BYTE + I_AM NULLDEVPT,DWORD + I_AM CINSAV,DWORD + I_AM CINDSAV,BYTE + I_AM COUTDSAV,BYTE + I_AM COUTSAV,DWORD + PUBLIC SaveBX +SaveBX DW ? + PUBLIC SaveDS +SaveDS DW ? + I_AM ConC_spsave,WORD + + I_AM exit_code,WORD ; exit code of last proc. + I_am exit_type,BYTE ; type of exit... + + IF IBM +;For 2.00 this pads the DOS so that on a 2 disk IBM PC with no +;CONFIG.SYS file the space taken up by BIOS, DOS, res COMMAND is +;about 24K +IBMPAD DB 540h DUP(?) + ENDIF + +; make those pushes fast!!! +EVEN + DB 0A0H DUP (?) + I_am AuxStack,0A0h + I_AM DSKSTACK,0A0h ; Stack space + PUBLIC IOSTACK +IOSTACK LABEL BYTE + + PUBLIC NSS +NSS DW ? + PUBLIC NSP +NSP DW ? + +PAGE + INCLUDE MSINIT.ASM + + \ No newline at end of file diff --git a/MSDOS.ASM b/MSDOS.ASM new file mode 100644 index 0000000..904cb34 --- /dev/null +++ b/MSDOS.ASM @@ -0,0 +1,12 @@ +TITLE Standard MSDOS +NAME MSDOS_2 + +; Number of disk I/O buffers + + INCLUDE STDSW.ASM + INCLUDE MSHEAD.ASM + INCLUDE MSDATA.ASM + + END + + \ No newline at end of file diff --git a/MSHEAD.ASM b/MSHEAD.ASM new file mode 100644 index 0000000..e2f184b --- /dev/null +++ b/MSHEAD.ASM @@ -0,0 +1,198 @@ +; TITLE MSHEAD.ASM -- MS-DOS DEFINITIONS +PAGE +; MS-DOS High-performance operating system for the 8086 version 1.28 +; by Microsoft MSDOS development group: +; Tim Paterson (Ret.) +; Aaron Reynolds +; Nancy Panners (Parenting) +; Mark Zbikowski +; Chris Peters (BIOS) (ret.) + +; ****************** Revision History ************************* +; >> EVERY change must noted below!! << +; +; 0.34 12/29/80 General release, updating all past customers +; 0.42 02/25/81 32-byte directory entries added +; 0.56 03/23/81 Variable record and sector sizes +; 0.60 03/27/81 Ctrl-C exit changes, including register save on user stack +; 0.74 04/15/81 Recognize I/O devices with file names +; 0.75 04/17/81 Improve and correct buffer handling +; 0.76 04/23/81 Correct directory size when not 2^N entries +; 0.80 04/27/81 Add console input without echo, Functions 7 & 8 +; 1.00 04/28/81 Renumber for general release +; 1.01 05/12/81 Fix bug in `STORE' +; 1.10 07/21/81 Fatal error trapping, NUL device, hidden files, date & time, +; RENAME fix, general cleanup +; 1.11 09/03/81 Don't set CURRENT BLOCK to 0 on open; fix SET FILE SIZE +; 1.12 10/09/81 Zero high half of CURRENT BLOCK after all (CP/M programs don't) +; 1.13 10/29/81 Fix classic "no write-through" error in buffer handling +; 1.20 12/31/81 Add time to FCB; separate FAT from DPT; Kill SMALLDIR; Add +; FLUSH and MAPDEV calls; allow disk mapping in DSKCHG; Lots +; of smaller improvements +; 1.21 01/06/82 HIGHMEM switch to run DOS in high memory +; 1.22 01/12/82 Add VERIFY system call to enable/disable verify after write +; 1.23 02/11/82 Add defaulting to parser; use variable escape character Don't +; zero extent field in IBM version (back to 1.01!) +; 1.24 03/01/82 Restore fcn. 27 to 1.0 level; add fcn. 28 +; 1.25 03/03/82 Put marker (00) at end of directory to speed searches +; 1.26 03/03/82 Directory buffers searched as a circular queue, current buffer +; is searched first when possible to minimize I/O +; 03/03/82 STORE routine optimized to tack on partial sector tail as +; full sector write when file is growing +; 03/09/82 Multiple I/O buffers +; 03/29/82 Two bugs: Delete all case resets search to start at beginning +; of directory (infinite loop possible otherwise), DSKRESET +; must invalidate all buffers (disk and directory). +; 1.27 03/31/82 Installable device drivers +; Function call 47 - Get pointer to device table list +; Function call 48 - Assign CON AUX LIST +; 04/01/82 Spooler interrupt (INT 28) added. +; 1.28 04/15/82 DOS retructured to use ASSUMEs and PROC labels around system +; call entries. Most CS relative references changed to SS +; relative with an eye toward putting a portion of the DOS in +; ROM. DOS source also broken into header, data and code pieces +; 04/15/82 GETDMA and GETVECT calls added as 24 and 32. These calls +; return the current values. +; 04/15/82 INDOS flag implemented for interrupt processing along with +; call to return flag location (call 29) +; 04/15/82 Volume ID attribute added +; 04/17/82 Changed ABORT return to user to a long ret from a long jump to +; avoid a CS relative reference. +; 04/17/82 Put call to STATCHK in dispatcher to catch ^C more often +; 04/20/82 Added INT int_upooler into loop ^S wait +; 04/22/82 Dynamic disk I/O buffer allocation and call to manage them +; call 49. +; 04/23/82 Added GETDSKPTDL as call 50, similar to GETFATPT(DL), returns +; address of DPB +; 04/29/82 Mod to WRTDEV to look for ^C or ^S at console input when +; writting to console device via file I/O. Added a console +; output attribute to devices. +; 04/30/82 Call to en/dis able ^C check in dispatcher Call 51 +; 04/30/82 Code to allow assignment of func 1-12 to disk files as well +; as devices.... pipes, redirection now possible +; 04/30/82 Expanded GETLIST call to 2.0 standard +; 05/04/82 Change to INT int_fatal_abort callout int HARDERR. DOS SS +; (data segment) stashed in ES, INT int_fatal_abort routines must +; preserve ES. This mod so HARDERR can be ROMed. +; 1.29 06/01/82 Installable block and character devices as per 2.0 spec +; 06/04/82 Fixed Bug in CLOSE regarding call to CHKFATWRT. It got left +; out back about 1.27 or so (oops). ARR +; 1.30 06/07/82 Directory sector buffering added to main DOS buffer queue +; 1.40 06/15/82 Tree structured directories. XENIX Path Parser MKDIR CHDIR +; RMDIR Xenix calls +; 1.41 06/13/82 Made GETBUFFR call PLACEBUF +; 1.50 06/17/82 FATs cached in buffer pool, get FAT pointer calls disappear +; Frees up lots of memory. +; 1.51 06/24/82 BREAKDOWN modified to do EXACT one sector read/write through +; system buffers +; 1.52 06/30/82 OPEN, CLOSE, READ, WRITE, DUP, DUP2, LSEEK implemented +; 1.53 07/01/82 OPEN CLOSE mod for Xenix calls, saves and gets remote dir +; 1.54 07/11/82 Function calls 1-12 make use of new 2.0 PDB. Init code +; changed to set file handle environment. +; 2.00 08/01/82 Number for IBM release +; 01/19/83 No environ bug in EXEC +; 01/19/83 MS-DOS OEM INT 21 extensions (SET_OEM_HANDLER) +; 01/19/83 Performance bug fix in cooked write to NUL +; 01/27/83 Growcnt fixed for 32-bits +; 01/27/83 Find-first problem after create +; 2.01 02/17/83 International DOS +; 2.11 08/12/83 Dos split into several more modules for assembly on +; an IBM PC +; +; ************************************************************* + + +SUBTTL EQUATES +PAGE +; Interrupt Entry Points: + +; INTBASE: ABORT +; INTBASE+4: COMMAND +; INTBASE+8: BASE EXIT ADDRESS +; INTBASE+C: CONTROL-C ABORT +; INTBASE+10H: FATAL ERROR ABORT +; INTBASE+14H: BIOS DISK READ +; INTBASE+18H: BIOS DISK WRITE +; INTBASE+1CH: END BUT STAY RESIDENT (NOT SET BY DOS) +; INTBASE+20H: SPOOLER INTERRUPT +; INTBASE+40H: Long jump to CALL entry point + +ENTRYPOINTSEG EQU 0CH +MAXDIF EQU 0FFFH +SAVEXIT EQU 10 + + INCLUDE DOSSYM.ASM + INCLUDE DEVSYM.ASM + +SUBTTL ^C, terminate/abort/exit and Hard error actions +PAGE +; +; There are three kinds of context resets that can occur during normal DOS +; functioning: ^C trap, terminate/abort/exit, and Hard-disk error. These must +; be handles in a clean fashion that allows nested executions along with the +; ability to trap one's own errors. +; +; ^C trap - A process may elect to catch his own ^Cs. This is achieved by +; using the $GET_INTERRUPT_VECTOR and $SET_INTERRUPT_VECTOR as +; follows: +; +; $GET_INTERRUPT_VECTOR for INT int_ctrl_c +; Save it in static memory. +; $SET_INTERRUPT_VECTOR for INT int_ctrl_c +; +; The interrupt service routine must preserve all registers and +; return carry set iff the operation is to be aborted (via abort +; system call), otherwise, carry is reset and the operation is +; restarted. ANY DEVIATION FROM THIS WILL LEAD TO UNRELIABLE +; RESULTS. +; +; To restore original ^C processing (done on terminate/abort/exit), +; restore INT int_ctrl_c from the saved vector. +; +; Hard-disk error -- The interrupt service routine for INT int_fatal_abort must +; also preserve registers and return one of three values in AL: 0 and +; 1 imply retry and ignore (???) and 2 indicates an abort. The user +; himself is not to issue the abort, rather, the dos will do it for +; him by simulating a normal abort/exit system call. ANY DEVIATION +; FROM THIS WILL LEAD TO UNRELIABLE RESULTS. +; +; terminate/abort/exit -- The user may not, under any circumstances trap an +; abort call. This is reserved for knowledgeable system programs. +; ANY DEVIATION FROM THIS WILL LEAD TO UNRELIABLE RESULTS. + +SUBTTL SEGMENT DECLARATIONS +PAGE + +; The following are all of the segments used. They are declared in the order +; that they should be placed in the executable + +; +; segment ordering for MSDOS +; + +START SEGMENT BYTE PUBLIC 'START' +START ENDS + +CONSTANTS SEGMENT BYTE PUBLIC 'CONST' +CONSTANTS ENDS + +DATA SEGMENT WORD PUBLIC 'DATA' +DATA ENDS + +CODE SEGMENT BYTE PUBLIC 'CODE' +CODE ENDS + +LAST SEGMENT BYTE PUBLIC 'LAST' +LAST ENDS + +DOSGROUP GROUP CODE,CONSTANTS,DATA,LAST + +; The following segment is defined such that the data/const classes appear +; before the code class for ROMification + +START SEGMENT BYTE PUBLIC 'START' + ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + JMP DOSINIT +START ENDS + + \ No newline at end of file diff --git a/MSINIT.ASM b/MSINIT.ASM new file mode 100644 index 0000000..36edf9f --- /dev/null +++ b/MSINIT.ASM @@ -0,0 +1,408 @@ +; TITLE MSINIT.ASM -- MS-DOS INITIALIZATION CODE + + ORG 0 ; reset to beginning of data segment +; Init code below overlaps with data area + +INITBLOCK DB 110H DUP(0) ; Allow for segment round up + +INITSP DW ? +INITSS DW ? +BUFFSTRT DW ? + +ASSUME CS:DOSGROUP,DS:DOSGROUP,ES:DOSGROUP,SS:NOTHING + + EXTRN QUIT:NEAR,IRET:NEAR,ABSDRD:FAR,ABSDWRT:FAR + EXTRN COMMAND:NEAR,CALL_ENTRY:NEAR + IF NOT IBM + EXTRN HEADER:BYTE + ENDIF + +MOVDPB: +; This section of code is safe from being overwritten by block move + MOV SP,CS:[INITSP] + MOV SS,CS:[INITSS] + REP MOVS BYTE PTR [DI],[SI] + CLD + MOV WORD PTR ES:[DMAADD+2],DX + MOV SI,WORD PTR [DPBHEAD] ; Address of first DPB + MOV WORD PTR ES:[DPBHEAD+2],ES + MOV WORD PTR ES:[sft_addr+2],ES + MOV CL,[NUMIO] ; Number of DPBs + XOR CH,CH +SETFINDPB: + MOV WORD PTR ES:[SI.dpb_next_dpb+2],ES + MOV ES:[SI.dpb_first_access],-1 ; Never accessed before + ADD SI,DPBSIZ ; Point to next DPB + LOOP SETFINDPB + SUB SI,DPBSIZ + MOV WORD PTR ES:[SI.dpb_next_dpb+2],-1 + MOV DI,[BUFFSTRT] ; Set up one default buffer + MOV WORD PTR ES:[BUFFHEAD+2],ES + MOV WORD PTR ES:[BUFFHEAD],DI + MOV WORD PTR ES:[DI.BUFDRV],00FFH + MOV ES:[DI.BUFPRI],FREEPRI + MOV WORD PTR ES:[DI.NEXTBUF],-1 + MOV WORD PTR ES:[DI.NEXTBUF+2],-1 + PUSH ES + INC DX ; Leave enough room for the ARENA + MOV BYTE PTR [CreatePDB],0FFh ; create jfns and set CurrentPDB + invoke $CREATE_PROCESS_DATA_BLOCK ; Set up segment +ASSUME DS:NOTHING,ES:NOTHING + POP ES +ASSUME ES:DOSGROUP + +; +; set up memory arena +;SPECIAL NOTE FOR HIGHMEM VERSION +; At this point a process header has been built where the start of the +; CONSTANTS segment as refed by CS is. From this point until the return +; below be careful about references off of CS. +; + PUSH AX + MOV AX,[CurrentPDB] + MOV ES:[CurrentPDB],AX ; Put it in the REAL location + MOV BYTE PTR ES:[CreatePDB],0h ; reset flag in REAL location + DEC AX + MOV ES:[arena_head],AX + PUSH DS + MOV DS,AX + MOV DS:[arena_signature],arena_signature_end + MOV DS:[arena_owner],arena_owner_system + SUB AX,ES:[ENDMEM] + NEG AX + DEC AX + MOV DS:[arena_size],AX + POP DS + POP AX + + MOV DI,OFFSET DOSGROUP:sftabl + sft_table ; Point to sft 0 + MOV AL,3 + STOSB ; Adjust Refcount + MOV DI,OFFSET DOSGROUP:SYSINITVAR + +XXX PROC FAR + RET +XXX ENDP +DATA ENDS + +; the next segment defines a new class that MUST appear last in the link map. +; This defines several important locations for the initialization process that +; must be the first available locations of free memory. + +LAST SEGMENT BYTE PUBLIC 'LAST' + PUBLIC SYSBUF + PUBLIC MEMSTRT + +SYSBUF LABEL WORD +ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + +DOSINIT: + CLI + CLD + MOV [ENDMEM],DX + MOV [INITSP],SP + MOV [INITSS],SS + MOV SP,OFFSET DOSGROUP:INITSTACK + MOV AX,CS + MOV SS,AX +ASSUME SS:DOSGROUP + MOV WORD PTR [DEVHEAD+2],DS + MOV WORD PTR [DEVHEAD],SI ; DS:SI Points to CONSOLE Device + CALL CHARINIT + PUSH SI + ADD SI,SDEVNAME ; Point to name + PUSH CS + POP ES +ASSUME ES:DOSGROUP + MOV DI,OFFSET DOSGROUP:sftabl + sft_table ; Point to sft 0 + MOV AL,3 + STOSB ; Refcount + DEC AL + STOSB ; Access rd/wr + XOR AL,AL + STOSB ; Drive byte + STOSB ; attribute + MOV CX,4 + REP MOVSW ; Name + MOV CL,3 + MOV AL," " + REP STOSB ; Extension + ADD DI,12 ; Skip + MOV AL,0C0H OR ISCIN OR ISCOUT + STOSB + POP SI + MOV AX,SI + STOSW ; Device pointer in FIRCLUS + MOV AX,DS + STOSW + OR BYTE PTR [SI.SDEVATT],ISCIN OR ISCOUT + MOV WORD PTR [BCON],SI + MOV WORD PTR [BCON+2],DS +CHAR_INIT_LOOP: + LDS SI,DWORD PTR [SI] ; AUX device + CALL CHARINIT + TEST BYTE PTR [SI.SDEVATT],ISCLOCK + JZ CHAR_INIT_LOOP + MOV WORD PTR [BCLOCK],SI + MOV WORD PTR [BCLOCK+2],DS + MOV BP,OFFSET DOSGROUP:MEMSTRT ; ES:BP points to DPB +PERDRV: + LDS SI,DWORD PTR [SI] ; Next device + CMP SI,-1 + JZ CONTINIT + CALL CHARINIT + TEST [SI.SDEVATT],DEVTYP + JNZ PERDRV ; Skip any other character devs + MOV CL,[CALLUNIT] + XOR CH,CH + MOV [SI.SDEVNAME],CL ; Number of units in name field + MOV DL,[NUMIO] + XOR DH,DH + ADD [NUMIO],CL + PUSH DS + PUSH SI + LDS BX,[CALLBPB] +PERUNIT: + MOV SI,[BX] ; DS:SI Points to BPB + INC BX + INC BX ; On to next BPB + MOV ES:[BP.dpb_drive],DL + MOV ES:[BP.dpb_UNIT],DH + PUSH BX + PUSH CX + PUSH DX + invoke $SETDPB + MOV AX,ES:[BP.dpb_sector_size] + CMP AX,[MAXSEC] + JBE NOTMAX + MOV [MAXSEC],AX +NOTMAX: + POP DX + POP CX + POP BX + MOV AX,DS ; Save DS + POP SI + POP DS + MOV WORD PTR ES:[BP.dpb_driver_addr],SI + MOV WORD PTR ES:[BP.dpb_driver_addr+2],DS + PUSH DS + PUSH SI + INC DH + INC DL + MOV DS,AX + ADD BP,DPBSIZ + LOOP PERUNIT + POP SI + POP DS + JMP PERDRV + +CONTINIT: + PUSH CS + POP DS +ASSUME DS:DOSGROUP +; Calculate true address of buffers, FATs, free space + MOV DI,BP ; First byte after current DPBs + MOV BP,[MAXSEC] + MOV AX,OFFSET DOSGROUP:SYSBUF + MOV [BUFFSTRT],AX + ADD AX,BP ; One I/O buffer + ADD AX,BUFINSIZ + MOV WORD PTR [DPBHEAD],AX ; True start of DPBs + MOV DX,AX + SUB DX,OFFSET DOSGROUP:SYSBUF + MOV BP,DX + ADD BP,DI ; Allocate buffer space + SUB BP,ADJFAC ; True address of free memory + PUSH BP + MOV DI,OFFSET DOSGROUP:MEMSTRT ; Current start of DPBs + ADD DI,dpb_next_dpb ; Point at dpb_next_dpb field + MOV CL,[NUMIO] + XOR CH,CH +TRUEDPBAD: + ADD AX,DPBSIZ ; Compute address of next DPB + STOSW ; Set the link to next DPB + ADD DI,DPBSIZ-2 ; Point at next address + LOOP TRUEDPBAD + SUB DI,DPBSIZ ; Point at last dpb_next_dpb field + MOV AX,-1 + STOSW ; End of list + ADD BP,15 ;True start of free space (round up to segment) + MOV CL,4 + SHR BP,CL ; Number of segments for DOS resources + MOV DX,CS + ADD DX,BP ; First free segment + MOV BX,0FH + MOV CX,[ENDMEM] + + IF HIGHMEM + SUB CX,BP + MOV BP,CX ; Segment of DOS + MOV DX,CS ; Program segment + ENDIF + + IF NOT HIGHMEM + MOV BP,CS + ENDIF + +; BP has segment of DOS (whether to load high or run in place) +; DX has program segment (whether after DOS or overlaying DOS) +; CX has size of memory in paragraphs (reduced by DOS size if HIGHMEM) + MOV [ENDMEM],CX + MOV ES,BP +ASSUME ES:DOSGROUP + + IF HIGHMEM + XOR SI,SI + MOV DI,SI + MOV CX,OFFSET DOSGROUP:SYSBUF ;# bytes to move + SHR CX,1 ;# words to move (carry set if odd) + REP MOVSW ; Move DOS to high memory + JNC NOTODD + MOVSB +NOTODD: + ENDIF + + MOV WORD PTR ES:[DSKCHRET+3],ES + XOR AX,AX + MOV DS,AX + MOV ES,AX +ASSUME DS:NOTHING,ES:NOTHING + MOV DI,INTBASE+2 + MOV AX,BP + MOV BYTE PTR DS:[ENTRYPOINT],mi_Long_JMP + MOV WORD PTR DS:[ENTRYPOINT+1],OFFSET DOSGROUP:CALL_ENTRY + MOV WORD PTR DS:[ENTRYPOINT+3],AX + EXTRN DIVOV:near + MOV WORD PTR DS:[0],OFFSET DOSGROUP:DIVOV ; Set default divide + ; trap address + MOV DS:[2],AX + MOV CX,17 + REP STOSW ; Set 9 segments (skip 2 between each) + + IF ALTVECT + MOV DI,ALTBASE+2 + MOV CX,15 + REP STOSW ; Set 8 segments (skip 2 between each) + ENDIF + + MOV WORD PTR DS:[addr_int_abort],OFFSET DOSGROUP:QUIT + MOV WORD PTR DS:[addr_int_command],OFFSET DOSGROUP:COMMAND + MOV WORD PTR DS:[addr_int_terminate],100H + MOV WORD PTR DS:[addr_int_terminate+2],DX + MOV WORD PTR DS:[addr_int_ctrl_c],OFFSET DOSGROUP:IRET + ; Ctrl-C exit + MOV WORD PTR DS:[addr_int_fatal_abort],OFFSET DOSGROUP:IRET + ; Fatal error exit + MOV WORD PTR DS:[addr_int_disk_read],OFFSET DOSGROUP:ABSDRD + ; INT 25 + MOV WORD PTR DS:[addr_int_disk_write],OFFSET DOSGROUP:ABSDWRT + ; INT 26 + EXTRN Stay_resident:NEAR + MOV WORD PTR DS:[addr_int_keep_process],OFFSET DOSGROUP:Stay_resident + MOV WORD PTR DS:[addr_int_spooler],OFFSET DOSGROUP:IRET ; Spooler + + IF NOT ALTVECT + MOV CX,12 + XOR AX,AX + MOV DI,2AH*4 + REP STOSW ;Zero interrupt locs for ints 2AH-2FH + ENDIF + + PUSH CS + POP DS + PUSH CS + POP ES +ASSUME DS:DOSGROUP,ES:DOSGROUP + MOV AX,OFFSET DOSGROUP:INITBLOCK + ADD AX,0Fh ; round to a paragraph + MOV CL,4 + SHR AX,CL + MOV DI,DS + ADD DI,AX + INC DI + MOV [CurrentPDB],DI + PUSH BP + PUSH DX ; Save COMMAND address + MOV AX,[ENDMEM] + MOV DX,DI + + invoke SETMEM ; Basic Header +ASSUME DS:NOTHING,ES:NOTHING + PUSH CS + POP DS +ASSUME DS:DOSGROUP + MOV DI,PDB_JFN_Table + XOR AX,AX + STOSW + STOSB ; 0,1 and 2 are CON device + MOV AL,0FFH + MOV CX,FilPerProc - 3 + REP STOSB ; Rest are unused + PUSH CS + POP ES +ASSUME ES:DOSGROUP + MOV WORD PTR [sft_addr+2],DS ; Must be set to print messages + +; After this points the char device functions for CON will work for +; printing messages + + IF NOT IBM + IF NOT ALTVECT + MOV SI,OFFSET DOSGROUP:HEADER + invoke OUTMES + PUSH CS ; Outmes stomps on segments + POP DS + PUSH CS + POP ES + ENDIF + ENDIF + +; Move the FATs into position + POP DX ; Restore COMMAND address + POP BP + POP CX ; True address of free memory + MOV SI,OFFSET DOSGROUP:MEMSTRT ; Place to move DPBs from + MOV DI,WORD PTR [DPBHEAD] ; Place to move DPBs to + SUB CX,DI ; Total length of DPBs + CMP DI,SI + JBE MOVJMP ; Are we moving to higher or + ; lower memory? + DEC CX ; Move backwards to higher memory + ADD DI,CX + ADD SI,CX + INC CX + STD +MOVJMP: + MOV ES,BP +ASSUME ES:DOSGROUP + JMP MOVDPB + +CHARINIT: +ASSUME DS:NOTHING,ES:NOTHING +; DS:SI Points to device header + MOV [DEVCALL.REQLEN],DINITHL + MOV [DEVCALL.REQUNIT],0 + MOV [DEVCALL.REQFUNC],DEVINIT + MOV [DEVCALL.REQSTAT],0 + PUSH ES + PUSH BX + PUSH AX + MOV BX,OFFSET DOSGROUP:DEVCALL + PUSH CS + POP ES + invoke DEVIOCALL2 + POP AX + POP BX + POP ES + RET + + DB 80H DUP(?) +INITSTACK LABEL BYTE + DW ? + +MEMSTRT LABEL WORD +ADJFAC EQU MEMSTRT-SYSBUF + + do_ext +LAST ENDS + \ No newline at end of file diff --git a/PRINT.ASM b/PRINT.ASM new file mode 100644 index 0000000..746c6c8 --- /dev/null +++ b/PRINT.ASM @@ -0,0 +1,1645 @@ +;MS-DOS PRINT program for background printing of text files to the list +; device. INT 28H is a software interrupt generated by the DOS +; in its I/O wait loops. This spooler can be assembled for +; operation using only this interrupt which is portable from +; system to system. It may also be assembled to use a hardware +; timer interrupt in addition to the software INT 28H. The +; purpose of using hardware interrupts is to allow printing to +; continue during programs which do not enter the system and +; therefore causes the INT 28H to go away. A timer interrupt is +; chosen in preference to a "printer buffer empty" interrupt +; because PRINT in the timer form is generic. It can be given +; the name of any currently installed character device as the +; "printer", this makes it portable to devices which are +; installed by the user even in the hardware case. It could be +; modified to use a buffer empty interrupt (no code is given for +; this case), if this is done the PROMPT and BADMES messages and +; their associated code should be removed as PRINT will then be +; device specific. +; +; VERSION 1.00 07/03/82 + + +FALSE EQU 0 +TRUE EQU NOT FALSE + +IBM EQU TRUE +IBMVER EQU IBM +MSVER EQU FALSE + + IF MSVER +HARDINT EQU FALSE ;No hardware ints +AINT EQU FALSE ;No need to do interrupt acknowledge + ENDIF + + IF IBM +HARDINT EQU TRUE +INTLOC EQU 1CH ;Hardware interrupt location (Timer) +AINT EQU TRUE ;Acknowledge interrupts +EOI EQU 20H ;End Of Interrupt "instruction" +AKPORT EQU 20H ;Interrupt Acknowledge port + ENDIF + +;The following values have to do with the ERRCNT variable and the +; CNTMES message. The values define levels at wich it is assumed +; an off-line error exists. ERRCNT1 defines the value of ERRCNT above +; which the CNTMES message is printed by the transient. ERRCNT2 +; defines the value of ERRCNT above which the resident will give up +; trying to print messages on the printer, it is much greater than +; ERRCNT1 because a much tighter loop is involved. The bounding event +; which determines the correct value is the time required to do a +; form feed. + + IF IBM +ERRCNT1 EQU 1000 +ERRCNT2 EQU 20000 + ELSE +ERRCNT1 EQU 1000 +ERRCNT2 EQU 20000 + ENDIF + + IF HARDINT +TIMESLICE EQU 8 ;The PRINT scheduling time slice. PRINT + ; lets this many "ticks" go by before + ; using a time slice to pump out characters. + ; Setting this to 3 for instance means PRINT + ; Will skip 3 slices, then take the fourth. + ; Thus using up 1/4 of the CPU. Setting it + ; to one gives PRINT 1/2 of the CPU. + ; The above examples assume MAXTICK is + ; 1. The actual PRINT CPU percentage is + ; (MAXTICK/(1+TIMESLICE))*100 + +MAXTICK EQU 2 ;The PRINT in timeslice. PRINT will pump + ; out characters for this many clock ticks + ; and then exit. The selection of a value + ; for this is dependent on the timer rate. + +BUSYTICK EQU 1 ;If PRINT sits in a wait loop waiting for + ; output device to come ready for this + ; many ticks, it gives up its time slice. + ; Setting it greater than or equal to + ; MAXTICK causes it to be ignored. + +;User gets TIMESLICE ticks and then PRINT takes MAXTICK ticks unless BUSYTICK +; ticks go by without getting a character out. + ENDIF + + +;WARNING DANGER WARNING: +; PRINT is a systems utility. It is clearly understood that it may have +; to be entirely re-written for future versions of MS-DOS. The following +; TWO vectors are version specific, they may not exist at all in future +; versions. If they do exist, they may function differently. +; ANY PROGRAM WHICH IMITATES PRINTS USE OF THESE VECTORS IS ALSO A SYSTEMS +; UTILITY AND IS THEREFORE NOT VERSION PORTABLE IN ANY WAY SHAPE OR FORM. +; YOU HAVE BEEN WARNED, "I DID IT THE SAME WAY PRINT DID" IS NOT AN REASON +; TO EXPECT A PROGRAM TO WORK ON FUTURE VERSIONS OF MS-DOS. +SOFTINT EQU 28H ;Software interrupt generated by DOS +COMINT EQU 2FH ;Communications interrupt used by PRINT + ; This vector number is DOS reserved. It + ; is not generally available to programs + ; other than PRINT. + +BLKSIZ EQU 512 ;Size of the PRINT I/O block in bytes +FCBSIZ EQU 40 ;Size of an FCB + + INCLUDE DOSSYM.ASM + +FCB EQU 5CH +PARMS EQU 80H + +DG GROUP CODE,DATA + +CODE SEGMENT +ASSUME CS:DG + + ORG 100H +START: + JMP TRANSIENT + +HEADER DB "Vers 1.00" + + DB 128 DUP (?) +ISTACK LABEL WORD ;Stack starts here and grows down + +;Resident data + + IF HARDINT +INDOS DD ? ;DOS buisy flag +NEXTINT DD ? ;Chain for int +BUSY DB 0 ;Internal ME flag +SOFINT DB 0 ;Internal ME flag +TICKCNT DB 0 ;Tick counter +TICKSUB DB 0 ;Tick miss counter +SLICECNT DB TIMESLICE ;Time slice counter + ENDIF + +CBUSY DB 0 ;ME on com interrupt +SPNEXT DD ? ;Chain location for INT 28 +PCANMES DB 0 ;Cancel message flag +SSsave DW ? ;Stack save area for INT 24 +SPsave DW ? +DMAADDR DD ? ;Place to save DMA address +HERRINT DD ? ;Place to save Hard error interrupt +LISTDEV DD ? ;Pointer to Device +COLPOS DB 0 ;Column position for TAB processing +NXTCHR DW OFFSET DG:BUFFER + BLKSIZ ;Buffer pointer +CURRFIL DW OFFSET DG:SPLFCB ;Current file being printed + +LASTFCB DW ? ;Back pointer +LASTFCB2 DW ? ;Another back pointer +PABORT DB 0 ;Abort flag + +;Resident messages + +ERRMES DB 13,10,13,10,"**********",13,10,"$" +ERRMEST DB " error reading file",13,10 +EMFILNAM DB " : . " +BELMES DB 13,0CH,7,"$" + +CANMES DB 13,10,13,10 +CANFILNAM DB " : . " + DB " Canceled by operator$" + +ALLCAN DB 13,10,13,10,"All files canceled by operator$" + +MESBAS DW OFFSET DG:ERR0 + DW OFFSET DG:ERR1 + DW OFFSET DG:ERR2 + DW OFFSET DG:ERR3 + DW OFFSET DG:ERR4 + DW OFFSET DG:ERR5 + DW OFFSET DG:ERR6 + DW OFFSET DG:ERR7 + DW OFFSET DG:ERR8 + DW OFFSET DG:ERR9 + DW OFFSET DG:ERR10 + DW OFFSET DG:ERR11 + DW OFFSET DG:ERR12 + +;INT 24 messages A La COMMAND + +ERR0 DB "Write protect$" +ERR1 DB "Bad unit$" +ERR2 DB "Not ready$" +ERR3 DB "Bad command$" +ERR4 DB "Data$" +ERR5 DB "Bad call format$" +ERR6 DB "Seek$" +ERR7 DB "Non-DOS disk$" +ERR8 DB "Sector not found$" +ERR9 DB "No paper$" +ERR10 DB "Write fault$" +ERR11 DB "Read fault$" +ERR12 DB "Disk$" + +FATMES DB "File allocation table bad drive " +BADDRVM DB "A.",13,10,"$" + +;The DATA buffer +BUFFER DB BLKSIZ DUP(0) + DB ? +CODE ENDS + +;Transient data + +DATA SEGMENT BYTE + ORG 0 +SWITCHAR DB ? ;User switch character +FULLFLAG DB 0 ;Flag for printing queue full message +MAKERES DB 0 ;Flag to indicate presence of resident +ARGSETUP DB 0 ;Flag to indicate a formatted FCB exists at 5C +DEFDRV DB 0 ;Default drive +CANFLG DB 0 ;Flag to indicate cancel +FILCNT DB 0 ;Number of files +SPLIST DD ? ;Pointer to FCBs in resident +CURFILE DD ? ;Pointer to current FCB +SRCHFCB DB 38 DUP (0) ;SEARCH-FIRST/NEXT FCB +ENDRES DW OFFSET DG:DEF_ENDRES ;Term-Res location + +;Messages + +NOFILS DB "PRINT queue is empty",13,10,"$" +CURMES DB 13,10," " +CURFNAM DB " : . is currently being printed",13,10,"$" +FILMES DB " " +FILFNAM DB " : . is in queue" +CRLF DB 13,10,"$" +OPMES DB "Cannot open " +OPFILNAM DB " : . ",13,10,"$" +FULLMES DB "PRINT queue is full",13,10,"$" +SRCHMES LABEL BYTE +SRCHFNAM DB " : . "," File not found",13,10,"$" +BADMES DB "List output is not assigned to a device",13,10,"$" +GOODMES DB "Resident part of PRINT installed",13,10,"$" +PROMPT DB "Name of list device [PRN]: $" +CNTMES DB "Errors on list device indicate that it",13,10 + DB "may be off-line. Please check it.",13,10,13,10,"$" +BADSWT DB "Invalid parameter",13,10,"$" + + +BADVER DB "Incorrect DOS version",13,10,"$" + + IF IBM +;Reserved names for parallel card +INT_17_HITLIST LABEL BYTE + DB 8,"PRN ",0 + DB 8,"LPT1 ",0 + DB 8,"LPT2 ",1 + DB 8,"LPT3 ",2 + DB 0 +;Reserved names for Async adaptor +INT_14_HITLIST LABEL BYTE + DB 8,"AUX ",0 + DB 8,"COM1 ",0 + DB 8,"COM2 ",1 + DB 0 + ENDIF + +COMBUF DB 14,0 ;Device name buffer + DB 14 DUP (?) +LISTFCB DB 0,"PRN " ;Device name FCB + DB 25 DUP (0) +PARSEBUF DB 80 DUP (?) ;Parsing space + +DATA ENDS + +CODE SEGMENT +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + + +;Interrupt routines +ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:NOTHING + IF HARDINT +HDSPINT: ;Hardware interrupt entry point + INC [TICKCNT] ;Tick + INC [TICKSUB] ;Tick + CMP [SLICECNT],0 + JZ TIMENOW + DEC [SLICECNT] ;Count down + JMP SHORT CHAININT ;Not time yet +TIMENOW: + CMP [BUSY],0 ;See if interrupting ourself + JNZ CHAININT + PUSH DS + PUSH SI + LDS SI,[INDOS] ;Check for making DOS calls + CMP BYTE PTR [SI],0 + POP SI + POP DS + JNZ CHAININT ;DOS is Buisy + INC [BUSY] ;Exclude furthur interrupts + MOV [TICKCNT],0 ;Reset tick counter + MOV [TICKSUB],0 ;Reset tick counter + STI ;Keep things rolling + + IF AINT + MOV AL,EOI ;Acknowledge interrupt + OUT AKPORT,AL + ENDIF + + CALL DOINT + CLI + MOV [SLICECNT],TIMESLICE ;Either soft or hard int resets time slice + MOV [BUSY],0 ;Done, let others in +CHAININT: + JMP [NEXTINT] ;Chain to next clock routine + ENDIF + + +SPINT: ;INT 28H entry point + IF HARDINT + CMP [BUSY],0 + JNZ NXTSP + INC [BUSY] ;Exclude hardware interrupt + INC [SOFINT] ;Indicate a software int in progress + ENDIF + + STI ;Hardware interrupts ok on INT 28H entry + CALL DOINT + + IF HARDINT + CLI + MOV [SOFINT],0 ;Indicate INT done + MOV [SLICECNT],TIMESLICE ;Either soft or hard int resets time slice + MOV [BUSY],0 + ENDIF + +NXTSP: JMP [SPNEXT] ;Chain to next INT 28 + +DOINT: + PUSH SI + MOV SI,[CURRFIL] + INC SI + INC SI + CMP BYTE PTR CS:[SI],-1 + POP SI + JNZ GOAHEAD + JMP SPRET ;Nothing to do +GOAHEAD: + PUSH AX ;Need a working register + MOV [SSsave],SS + MOV [SPsave],SP + MOV AX,CS + CLI +;Go to internal stack to prevent INT 24 overflowing system stack + MOV SS,AX + MOV SP,OFFSET DG:ISTACK + STI + PUSH ES + PUSH DS + PUSH BX + PUSH CX + PUSH DX + PUSH SI + PUSH DI + PUSH CS + POP DS +ASSUME DS:DG + + MOV BX,[NXTCHR] + CMP BX,OFFSET DG:BUFFER + BLKSIZ + JNZ PLOOP + JMP READBUFF ;Buffer empty + +PLOOP: + IF HARDINT + MOV BX,[NXTCHR] + CMP BX,OFFSET DG:BUFFER + BLKSIZ + JZ DONEJMP ;Buffer has become empty + CMP [SOFINT],0 + JNZ STATCHK + CMP [TICKCNT],MAXTICK ;Check our time slice + JAE DONEJMP +STATCHK: + ENDIF + + CALL PSTAT + + IF HARDINT + JZ DOCHAR ;Printer ready + CMP [SOFINT],0 + ENDIF + + JNZ DONEJMP ;If soft int give up + + IF HARDINT + CMP [TICKSUB],BUSYTICK ;Check our busy timeout + JAE DONEJMP + JMP PLOOP + ENDIF + +DOCHAR: + MOV AL,BYTE PTR [BX] + CMP AL,1AH ;^Z? + JZ FILEOFJ ;CPM EOF + CMP AL,0DH ;CR? + JNZ NOTCR + MOV [COLPOS],0 +NOTCR: + CMP AL,9 ;TAB? + JNZ NOTABDO + MOV CL,[COLPOS] + OR CL,0F8H + NEG CL + XOR CH,CH + JCXZ TABDONE +TABLP: + MOV AL," " + INC [COLPOS] + PUSH CX + CALL POUT + POP CX + LOOP TABLP + JMP TABDONE + +NOTABDO: + CMP AL,8 ;Back space? + JNZ NOTBACK + DEC [COLPOS] +NOTBACK: + CMP AL,20H ;Non Printing char? + JB NOCHAR + INC [COLPOS] ;Printing char +NOCHAR: + CALL POUT ;Print it +TABDONE: + INC [NXTCHR] ;Next char + + IF HARDINT + MOV [TICKSUB],0 ;Got a character out, Reset counter + CMP [SOFINT],0 ;Soft int does one char at a time + JZ PLOOP + ENDIF + +DONEJMP: + POP DI + POP SI + POP DX + POP CX + POP BX + POP DS + POP ES +ASSUME DS:NOTHING,ES:NOTHING + CLI + MOV SS,[SSsave] ;Restore Entry Stack + MOV SP,[SPsave] + STI + POP AX +SPRET: + RET + +FILEOFJ: JMP FILEOF + +READBUFF: +ASSUME DS:DG,ES:NOTHING + + MOV AL,24H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [HERRINT+2],ES ;Save current vector + MOV WORD PTR [HERRINT],BX + MOV DX,OFFSET DG:DSKERR + MOV AL,24H + MOV AH,SET_INTERRUPT_VECTOR ;Install our own + INT 21H ;Spooler must catch its errors + MOV AH,GET_DMA + INT 21H + MOV WORD PTR [DMAADDR+2],ES ;Save DMA address + MOV WORD PTR [DMAADDR],BX + MOV DX,OFFSET DG:BUFFER + MOV AH,SET_DMA + INT 21H ;New DMA address + MOV [PABORT],0 ;No abort + MOV DX,[CURRFIL] ;Read + INC DX + INC DX ;Skip over pointer + MOV AH,FCB_SEQ_READ + INT 21H + PUSH AX + LDS DX,[DMAADDR] +ASSUME DS:NOTHING + MOV AH,SET_DMA + INT 21H ;Restore DMA + LDS DX,[HERRINT] + MOV AL,24H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Restore Error INT + POP AX + PUSH CS + POP DS +ASSUME DS:DG + CMP [PABORT],0 + JNZ TONEXTFIL ;Barf on this file, got INT 24 + CMP AL,01 + JZ FILEOF ;Read EOF? + MOV BX,OFFSET DG:BUFFER ;Buffer full + MOV [NXTCHR],BX + JMP DONEJMP + +FILEOF: + MOV AL,0CH ;Form feed + CALL LOUT +TONEXTFIL: + CALL NEXTFIL + JMP DONEJMP + +;INT 24 handler + +DSKERR: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + STI + CMP [PABORT],0 + JNZ IGNRET + PUSH BX + PUSH CX + PUSH DX + PUSH DI + PUSH SI + PUSH BP + PUSH ES + PUSH DS + PUSH CS + POP DS + PUSH CS + POP ES +ASSUME DS:DG,ES:DG + ADD [BADDRVM],AL ;Set correct drive letter + MOV SI,OFFSET DG:ERRMES + CALL LISTMES + TEST AH,080H + JNZ FATERR + AND DI,0FFH + CMP DI,12 + JBE HAVCOD + MOV DI,12 +HAVCOD: + SHL DI,1 + MOV DI,WORD PTR [DI+MESBAS] ; Get pointer to error message + MOV SI,DI + CALL LISTMES ; Print error type + MOV DI,OFFSET DG:EMFILNAM + MOV SI,[CURRFIL] + ADD SI,2 ;Get to file name + LODSB + ADD AL,'@' + STOSB + INC DI + MOV CX,4 + REP MOVSW + INC DI + MOVSW + MOVSB + MOV SI,OFFSET DG:ERRMEST + CALL LISTMES +SETABORT: + INC [PABORT] ;Indicate abort + POP DS + POP ES + POP BP + POP SI + POP DI + POP DX + POP CX + POP BX +IGNRET: + XOR AL,AL ;Ignore + IRET + +FATERR: + MOV SI,OFFSET DG:FATMES + CALL LISTMES + JMP SHORT SETABORT + +ADDFILJ: JMP ADDFIL + +COMBUSY: + MOV AX,-1 + IRET + +;Communications interrupt +SPCOMINT: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CBUSY],0 + JNZ COMBUSY + INC [CBUSY] ;Exclude + STI ;Turn ints back on + PUSH SI + PUSH DI + PUSH CX + PUSH DS + PUSH CS + POP DS +ASSUME DS:DG + MOV [PCANMES],0 ;Havn't printed cancel message + OR AH,AH + JZ ADDFILJ ;Add file + CMP AH,1 + JZ CANFIL ;Cancel File(s) + XOR AL,AL +SETCOUNT: + PUSH AX ;Save AL return code + XOR AH,AH + MOV SI,OFFSET DG:SPLFCB + MOV CX,[NUMFCBS] +CNTFILS: + CMP BYTE PTR [SI+2],-1 ;Valid? + JZ LNEXT + INC AH +LNEXT: + ADD SI,FCBSIZ + LOOP CNTFILS +COMRET: + MOV BX,OFFSET DG:SPLFCB + MOV DX,[CURRFIL] + PUSH DS + POP ES +ASSUME ES:NOTHING + MOV CH,AH + POP AX ;Get AL return + MOV AH,CH + + IF HARDINT +BWAIT3: + CMP [BUSY],0 + JNZ BWAIT3 + INC [BUSY] + ENDIF + + CALL PSTAT ; Tweek error counter + + IF HARDINT + MOV [BUSY],0 + ENDIF + + POP DS +ASSUME DS:NOTHING + POP CX + POP DI + POP SI + MOV [CBUSY],0 + IRET + +DELALLJ: JMP DELALL + +CANFIL: +ASSUME DS:DG,ES:NOTHING + MOV CX,[NUMFCBS] + + IF HARDINT +BWAIT: + CMP [BUSY],0 + JNZ BWAIT + INC [BUSY] + ENDIF + + MOV SI,[CURRFIL] + CMP DX,-1 + JZ DELALLJ + MOV BX,[SI] + PUSH BX +LOOKEND: ;Set initial pointer values + CMP BX,SI + JZ GOTLAST + POP AX + PUSH BX + MOV BX,[BX] + JMP SHORT LOOKEND + +GOTLAST: + POP BX + MOV [LASTFCB],BX + MOV [LASTFCB2],BX + POP ES + PUSH ES + MOV BX,SI +LOOKMATCH: + MOV DI,DX + ADD SI,2 ;Skip pointer + CMP BYTE PTR [SI],-1 + JZ CANTERMJ ;No more + CMPSB + JNZ SKIPFIL ;DRIVE + PUSH CX + MOV CX,11 +NXTCHAR: + MOV AL,ES:[DI] + INC DI + CALL UPCONV + MOV AH,AL + LODSB + CALL UPCONV + CMP AH,"?" ;Wild card? + JZ NXTCHRLP ;Yes + CMP AH,AL + JNZ SKIPFILC +NXTCHRLP: + LOOP NXTCHAR +MATCH: + POP CX + MOV AH,-1 + XCHG AH,[BX+2] ;Zap it + CMP BX,[CURRFIL] ;Is current file? + JNZ REQUEUE ;No + MOV AL,1 + XCHG AL,[PCANMES] + OR AL,AL + JNZ DIDCMES ;Only print cancel message once + PUSH ES + PUSH CS + POP ES + MOV DI,OFFSET DG:CANFILNAM + MOV SI,BX + ADD SI,3 ;Get to file name + MOV AL,AH + ADD AL,'@' + STOSB + INC DI + MOV CX,4 + REP MOVSW + INC DI + MOVSW + MOVSB + POP ES + MOV SI,OFFSET DG:CANMES + CALL LISTMES + MOV SI,OFFSET DG:BELMES + CALL LISTMES +DIDCMES: + PUSH CX + CALL NEXTFIL +SKIPFILC: + POP CX +SKIPFIL: + MOV [LASTFCB2],BX + MOV BX,[BX] +NEXTFC: + MOV SI,BX + LOOP LOOKMATCH +CANTERMJ: JMP SHORT CANTERM + +REQUEUE: + MOV AX,[BX] + CMP AX,[CURRFIL] ;Is last FCB? + JZ SKIPFIL ;Yes, is in right place + MOV SI,[LASTFCB2] + MOV [SI],AX ;Unlink FCB + MOV SI,[CURRFIL] + MOV [BX],SI + MOV SI,[LASTFCB] + MOV [SI],BX ;Link FCB at end + MOV [LASTFCB],BX ;New end + MOV BX,AX ;Process what it pointed to + JMP SHORT NEXTFC + +DELALL: + CMP BYTE PTR CS:[SI+2],-1 ;Examine current file +DELALL2: + MOV BYTE PTR [SI+2],-1 ;Zap it + MOV SI,[SI] + LOOP DELALL2 + JZ CANTERM1 ;No message if nothing was in progress + MOV SI,OFFSET DG:ALLCAN + CALL LISTMES + MOV SI,OFFSET DG:BELMES + CALL LISTMES +CANTERM1: + MOV [NXTCHR],OFFSET DG:BUFFER + BLKSIZ ;Buffer empty +CANTERM: + + IF HARDINT + MOV [BUSY],0 + ENDIF + + XOR AX,AX + JMP SETCOUNT + +UPCONV: + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + SUB AL,20H +NOCONV: + RET + +ADDFIL: +ASSUME DS:DG,ES:NOTHING + MOV SI,[CURRFIL] + MOV CX,[NUMFCBS] + + IF HARDINT +BWAIT2: + CMP [BUSY],0 + JNZ BWAIT2 + INC [BUSY] + ENDIF + +LOOKSPOT: + CMP BYTE PTR [SI+2],-1 + JZ GOTSPOT + MOV SI,[SI] + LOOP LOOKSPOT + + IF HARDINT + MOV [BUSY],0 + ENDIF + + MOV AL,1 + JMP SETCOUNT + +GOTSPOT: + PUSH DS + POP ES + POP DS + PUSH DS +ASSUME DS:NOTHING + PUSH SI + MOV DI,SI + ADD DI,2 + MOV SI,DX + MOV CX,19 + REP MOVSW ;Copy in and set FCB + POP SI + PUSH ES + POP DS +ASSUME DS:DG + MOV WORD PTR [SI+2+fcb_EXTENT],0 + MOV BYTE PTR [SI+2+fcb_NR],0 + MOV WORD PTR [SI+2+fcb_RECSIZ],BLKSIZ + + IF HARDINT + MOV [BUSY],0 + ENDIF + + XOR AL,AL + JMP SETCOUNT + +NEXTFIL: +ASSUME DS:DG,ES:NOTHING + MOV SI,[CURRFIL] + MOV BYTE PTR [SI+2],-1 ;Done with current file + MOV SI,[SI] + MOV [CURRFIL],SI + MOV [NXTCHR],OFFSET DG:BUFFER + BLKSIZ ;Buffer empty + MOV [COLPOS],0 ;Start of line + RET + +LISTMES: +ASSUME DS:DG,ES:NOTHING + LODSB + CMP AL,"$" + JZ LMESDONE + CALL LOUT + JMP LISTMES + +LMESDONE: + RET + +LOUT: + PUSH BX +LWAIT: + CALL PSTAT + JZ PREADY + CMP [ERRCNT],ERRCNT2 + JA POPRET ;Don't get stuck + JMP SHORT LWAIT +PREADY: + CALL POUT +POPRET: + POP BX + RET + +;Stuff for BIOS interface +IOBUSY EQU 0200H +IOERROR EQU 8000H + +BYTEBUF DB ? + +CALLAD DD ? + +IOCALL DB 22 + DB 0 +IOREQ DB ? +IOSTAT DW 0 + DB 8 DUP(?) + DB 0 + DW OFFSET DG:BYTEBUF +INTSEG DW ? +IOCNT DW 1 + DW 0 + +PSTAT: +ASSUME DS:DG + PUSH BX + INC [ERRCNT] + MOV BL,10 + CALL DOCALL + TEST [IOSTAT],IOERROR + JZ NOSTATERR + OR [IOSTAT],IOBUSY ;If error, show buisy +NOSTATERR: + TEST [IOSTAT],IOBUSY + JNZ RET13P ;Shows buisy + MOV [ERRCNT],0 +RET13P: + POP BX + RET + +POUT: +ASSUME DS:DG + MOV [BYTEBUF],AL + MOV BL,8 +DOCALL: + PUSH ES + MOV [IOREQ],BL + MOV BX,CS + MOV ES,BX + MOV BX,OFFSET DG:IOCALL + MOV [IOSTAT],0 + MOV [IOCNT],1 + PUSH DS + PUSH SI + PUSH AX + LDS SI,[LISTDEV] +ASSUME DS:NOTHING + MOV AX,[SI+6] + MOV WORD PTR [CALLAD],AX + CALL [CALLAD] + MOV AX,[SI+8] + MOV WORD PTR [CALLAD],AX + CALL [CALLAD] + POP AX + POP SI + POP DS +ASSUME DS:DG + POP ES + RET + + IF IBM +REAL_INT_13 DD ? +INT_13_RETADDR DW OFFSET DG:INT_13_BACK + +INT_13 PROC FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSHF + INC [BUSY] ;Exclude if dumb program call ROM + PUSH CS + PUSH [INT_13_RETADDR] + PUSH WORD PTR [REAL_INT_13+2] + PUSH WORD PTR [REAL_INT_13] + RET +INT_13 ENDP + +INT_13_BACK PROC FAR + PUSHF + DEC [BUSY] + POPF + RET 2 ;Chuck saved flags +INT_13_BACK ENDP + ENDIF + + + IF IBM + +REAL_INT_5 DD ? +REAL_INT_17 DD ? +INT_17_NUM DW 0 + +INT_17: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH SI + MOV SI,[CURRFIL] + INC SI + INC SI + CMP BYTE PTR CS:[SI],-1 + POP SI + JZ DO_INT_17 ;Nothing pending, so OK + CMP DX,[INT_17_NUM] + JNZ DO_INT_17 ;Not my unit + CMP [BUSY],0 + JNZ DO_INT_17 ;You are me + STI + MOV AH,0A1H ;You are bad, get out of paper + IRET + +DO_INT_17: + JMP [REAL_INT_17] ;Do a 17 + +REAL_INT_14 DD ? +INT_14_NUM DW 0 + +INT_14: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH SI + MOV SI,[CURRFIL] + INC SI + INC SI + CMP BYTE PTR CS:[SI],-1 + POP SI + JZ DO_INT_14 ;Nothing pending, so OK + CMP DX,[INT_14_NUM] + JNZ DO_INT_14 ;Not my unit + CMP [BUSY],0 + JNZ DO_INT_14 ;You are me + STI + OR AH,AH + JZ SET14_AX + CMP AH,2 + JBE SET14_AH +SET14_AX: + MOV AL,0 +SET14_AH: + MOV AH,80H ;Time out + IRET + +DO_INT_14: + JMP [REAL_INT_14] ;Do a 14 + +INT_5: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH SI + MOV SI,[CURRFIL] + INC SI + INC SI + CMP BYTE PTR CS:[SI],-1 + POP SI + JZ DO_INT_5 ;Nothing pending, so OK + CMP [INT_17_NUM],0 + JNZ DO_INT_5 ;Only care about unit 0 + IRET ;Pretend it worked + +DO_INT_5: + JMP [REAL_INT_5] ;Do a 5 + ENDIF + + +;The following data is order and position dependant +NUMFCBS DW 10 +ERRCNT DW 0 + +SPLFCB DW OFFSET DG:FC1 + DB (FCBSIZ - 2) DUP (-1) +FC1 DW OFFSET DG:FC2 + DB (FCBSIZ - 2) DUP (-1) +FC2 DW OFFSET DG:FC3 + DB (FCBSIZ - 2) DUP (-1) +FC3 DW OFFSET DG:FC4 + DB (FCBSIZ - 2) DUP (-1) +FC4 DW OFFSET DG:FC5 + DB (FCBSIZ - 2) DUP (-1) +FC5 DW OFFSET DG:FC6 + DB (FCBSIZ - 2) DUP (-1) +FC6 DW OFFSET DG:FC7 + DB (FCBSIZ - 2) DUP (-1) +FC7 DW OFFSET DG:FC8 + DB (FCBSIZ - 2) DUP (-1) +FC8 DW OFFSET DG:FC9 + DB (FCBSIZ - 2) DUP (-1) +FC9 DW OFFSET DG:SPLFCB + DB (FCBSIZ - 2) DUP (-1) + +DEF_ENDRES LABEL BYTE + +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + +BADSPOOL: + MOV DX,OFFSET DG:BADMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + INT 20H + +SETUP: +;Called once to install resident + CLD + MOV [INTSEG],CS + MOV DX,OFFSET DG:PROMPT + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + MOV DX,OFFSET DG:COMBUF + MOV AH,STD_CON_STRING_INPUT + INT 21H ;Get device name + MOV DX,OFFSET DG:CRLF + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + MOV CL,[COMBUF+1] + OR CL,CL + JZ DEFSPOOL ;User didn't specify one + XOR CH,CH + MOV DI,OFFSET DG:LISTFCB + 1 + MOV SI,OFFSET DG:COMBUF + 2 + REP MOVSB +DEFSPOOL: + MOV DX,OFFSET DG:LISTFCB + MOV AH,FCB_OPEN + INT 21H + OR AL,AL + JNZ BADSPOOL ;Bad + TEST BYTE PTR [LISTFCB.fcb_DEVID],080H + JZ BADSPOOL ;Must be a device + LDS SI,DWORD PTR [LISTFCB.fcb_FIRCLUS] +ASSUME DS:NOTHING + MOV WORD PTR [CALLAD+2],DS ;Get I/O routines + MOV WORD PTR [LISTDEV+2],DS ;Get I/O routines + MOV WORD PTR [LISTDEV],SI + PUSH CS + POP DS +ASSUME DS:DG + MOV DX,OFFSET DG:SPINT + MOV AL,SOFTINT + MOV AH,GET_INTERRUPT_VECTOR + INT 21H ;Get soft vector + MOV WORD PTR [SPNEXT+2],ES + MOV WORD PTR [SPNEXT],BX + MOV AL,SOFTINT + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set soft vector + MOV DX,OFFSET DG:SPCOMINT + MOV AL,COMINT + MOV AH,SET_INTERRUPT_VECTOR ;Set communication vector + INT 21H + + IF IBM + MOV AL,13H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_13+2],ES + MOV WORD PTR [REAL_INT_13],BX + MOV DX,OFFSET DG:INT_13 + MOV AL,13H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set diskI/O interrupt + MOV AL,17H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_17+2],ES + MOV WORD PTR [REAL_INT_17],BX + MOV AL,14H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_14+2],ES + MOV WORD PTR [REAL_INT_14],BX + MOV AL,5H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_5+2],ES + MOV WORD PTR [REAL_INT_5],BX + PUSH CS + POP ES + MOV BP,OFFSET DG:LISTFCB + 1 + MOV SI,BP + MOV CX,8 +CONLP: ;Make sure device name in upper case + LODSB + CMP AL,'a' + JB DOCONLP + CMP AL,'z' + JA DOCONLP + SUB BYTE PTR [SI-1],20H +DOCONLP: + LOOP CONLP + MOV DI,OFFSET DG:INT_17_HITLIST +CHKHIT: + MOV SI,BP + MOV CL,[DI] + INC DI + JCXZ NOTONHITLIST + REPE CMPSB + LAHF + ADD DI,CX ;Bump to next position without affecting flags + MOV BL,[DI] ;Get device number + INC DI + SAHF + JNZ CHKHIT + XOR BH,BH + MOV [INT_17_NUM],BX + MOV DX,OFFSET DG:INT_17 + MOV AL,17H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set printer interrupt + MOV DX,OFFSET DG:INT_5 + MOV AL,5H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set print screen interrupt + JMP SHORT ALLSET +NOTONHITLIST: + MOV DI,OFFSET DG:INT_14_HITLIST +CHKHIT2: + MOV SI,BP + MOV CL,[DI] + INC DI + JCXZ ALLSET + REPE CMPSB + LAHF + ADD DI,CX ;Bump to next position without affecting flags + MOV BL,[DI] ;Get device number + INC DI + SAHF + JNZ CHKHIT2 + XOR BH,BH + MOV [INT_14_NUM],BX + MOV DX,OFFSET DG:INT_14 + MOV AL,14H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set RS232 port interrupt +ALLSET: + ENDIF + + IF HARDINT + MOV AH,GET_INDOS_FLAG + INT 21H + MOV WORD PTR [INDOS+2],ES ;Get indos flag location + MOV WORD PTR [INDOS],BX + MOV AL,INTLOC + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [NEXTINT+2],ES + MOV WORD PTR [NEXTINT],BX + MOV DX,OFFSET DG:HDSPINT + MOV AL,INTLOC + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set hardware interrupt + ENDIF + + MOV [MAKERES],1 ;Indicate to do a terminate stay resident + MOV DX,OFFSET DG:GOODMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + RET + +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + +TRANSIENT: +;User interface + CLD + +;Code to print header +; MOV DX,OFFSET DG:HEADER +; MOV AH,STD_CON_STRING_OUTPUT +; INT 21H + +DOSVER_LOW EQU 0136H ;1.54 in hex +DOSVER_HIGH EQU 020BH ;2.11 in hex + MOV AH,GET_VERSION + INT 21H + XCHG AH,AL ;Turn it around to AH.AL + CMP AX,DOSVER_LOW + JB GOTBADDOS + CMP AX,DOSVER_HIGH + JBE OKDOS +GOTBADDOS: + PUSH CS + POP DS + MOV DX,OFFSET DG:BADVER + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + INT 20H +OKDOS: + MOV AX,CHAR_OPER SHL 8 + INT 21H + MOV [SWITCHAR],DL ;Get user switch character + MOV AH,GET_INTERRUPT_VECTOR + MOV AL,COMINT + INT 21H +ASSUME ES:NOTHING + MOV DI,BX + MOV SI,OFFSET DG:SPCOMINT + MOV CX,13 + REPE CMPSB + JZ GOTRES ;Signature matched + PUSH CS + POP ES + CALL SETUP +GOTRES: + PUSH CS + POP ES + MOV AH,GET_DEFAULT_DRIVE + INT 21H + MOV [DEFDRV],AL + MOV SI,PARMS + LODSB + OR AL,AL + JNZ GOTPARMS +TRANEXIT: + CALL GETSPLIST + CMP [MAKERES],0 + JNZ SETRES + INT 20H + +SETRES: + MOV DX,[ENDRES] + INT 27H + +ARGSDONE: + CMP [ARGSETUP],0 + JZ TRANEXIT + CALL PROCESS + JMP SHORT TRANEXIT + +GOTPARMS: +PARSE: + MOV DI,OFFSET DG:PARSEBUF + CALL CPARSE + JC ARGSDONE + CMP AX,4 ;Switch? + JNZ GOTNORMARG + MOV AL,[DI] ;Get the switch character + CMP AL,'C' + JZ SETCAN + CMP AL,'c' + JNZ CHKSPL +SETCAN: + MOV [CANFLG],1 + JMP SHORT PARSE +CHKSPL: + CMP AL,'P' + JZ RESETCAN + CMP AL,'p' + JNZ CHKTERM +RESETCAN: + MOV [CANFLG],0 + JMP SHORT PARSE +CHKTERM: + CMP AL,'T' + JZ SETTERM + CMP AL,'t' + JZ SETTERM + MOV DX,OFFSET DG:BADSWT + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + JMP SHORT PARSE + +SETTERM: + CALL TERMPROCESS + JMP TRANEXIT ; Ignore everything after T switch + +GOTNORMARG: + XOR AL,AL + XCHG AL,[ARGSETUP] + OR AL,AL + JZ PARSEARG + CALL NORMPROC ;Don't test ARGSETUP, it just got zeroed +PARSEARG: + PUSH SI + MOV SI,DI + MOV DI,FCB + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 1 + INT 21H ;Parse the arg + CMP BYTE PTR [DI],0 + JNZ DRVOK + MOV DL,[DEFDRV] + INC DL + MOV BYTE PTR [DI],DL ;Set the default drive +DRVOK: + POP SI + INC [ARGSETUP] + JMP SHORT PARSE + +TERMPROCESS: + MOV DX,-1 +PROCRET: + MOV AH,1 + CALL DOSET +PROCRETNFUNC: + MOV [ARGSETUP],0 + PUSH CS + POP ES +RET14: RET + +PROCESS: + CMP [ARGSETUP],0 + JZ RET14 ;Nothing to process +NORMPROC: + MOV AL,BYTE PTR DS:[FCB+1] + CMP AL," " + JZ SRCHBADJ + MOV DX,FCB + MOV AH,[CANFLG] + CMP AH,0 + JNZ PROCRET + MOV DX,OFFSET DG:SRCHFCB + MOV AH,SET_DMA + INT 21H + MOV DX,FCB + MOV AH,DIR_SEARCH_FIRST + INT 21H + OR AL,AL + JNZ SRCHBADJ +SRCHLOOP: + MOV DX,OFFSET DG:SRCHFCB + MOV AH,FCB_OPEN + INT 21H + OR AL,AL + JZ OPENOK + CALL OPENERR + JMP SHORT NEXTSEARCH +SRCHBADJ: JMP SRCHBAD +OPENOK: + MOV DX,OFFSET DG:SRCHFCB + MOV AH,0 + CALL DOSET + OR AL,AL + JZ NEXTSEARCH + XCHG AL,[FULLFLAG] ;Know AL non-zero + OR AL,AL + JNZ NEXTSEARCH ;Only print message once + MOV DX,OFFSET DG:FULLMES ;Queue full + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +NEXTSEARCH: + MOV DX,OFFSET DG:SRCHFCB + MOV AH,SET_DMA + INT 21H + MOV DX,FCB + MOV AH,DIR_SEARCH_NEXT + INT 21H + OR AL,AL + JNZ PROCRETNFUNC + JMP SRCHLOOP + +DOSET: + INT COMINT + MOV [FILCNT],AH ;Suck up return info + MOV WORD PTR [SPLIST+2],ES + MOV WORD PTR [CURFILE+2],ES + MOV WORD PTR [SPLIST],BX + MOV WORD PTR [CURFILE],DX + RET + +OPENERR: + PUSH SI + PUSH DI + MOV SI,OFFSET DG:OPFILNAM + PUSH DS + POP ES + MOV DI,OFFSET DG:SRCHFCB + CALL MVFNAM + MOV DX,OFFSET DG:OPMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + POP DI + POP SI + RET + +SRCHBAD: + PUSH SI + PUSH DI + MOV SI,OFFSET DG:SRCHFNAM + PUSH DS + POP ES + MOV DI,FCB + CALL MVFNAM + MOV DX,OFFSET DG:SRCHMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + POP DI + POP SI + JMP PROCRETNFUNC + +GETSPLIST: + MOV AH,0FFH + CALL DOSET + PUSH DS + LDS DI,[SPLIST] + MOV DI,[DI-2] ;Get the error count + POP DS + CMP DI,ERRCNT1 + JB CNTOK + MOV DX,OFFSET DG:CNTMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +CNTOK: + MOV CL,[FILCNT] + OR CL,CL + JZ NOFILES + XOR CH,CH + LES DI,[CURFILE] + PUSH DI + INC DI + INC DI + MOV SI,OFFSET DG:CURFNAM + CALL MVFNAM + POP DI + MOV DX,OFFSET DG:CURMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + DEC CX + JCXZ RET12 +FILOOP: + MOV DI,ES:[DI] + PUSH DI + INC DI + INC DI + MOV SI,OFFSET DG:FILFNAM + CALL MVFNAM + POP DI + MOV DX,OFFSET DG:FILMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + LOOP FILOOP +RET12: RET + +NOFILES: + MOV DX,OFFSET DG:NOFILS + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + RET + +;Make a message with the file name +MVFNAM: +ASSUME DS:NOTHING,ES:NOTHING + PUSH SI + PUSH DI + PUSH CX + MOV AX,ES + PUSH DS + POP ES + MOV DS,AX + XCHG SI,DI + LODSB + ADD AL,"@" + CMP AL,"@" + JNZ STCHR + MOV AL,[DEFDRV] + ADD AL,"A" +STCHR: + STOSB + INC DI + MOV CX,4 + REP MOVSW + INC DI + MOVSW + MOVSB + MOV AX,ES + PUSH DS + POP ES + MOV DS,AX + POP CX + POP DI + POP SI + RET + +;-----------------------------------------------------------------------; +; ENTRY: ; +; DS:SI Points input buffer ; +; ES:DI Points to the token buffer ; +; ; +; EXIT: ; +; DS:SI Points to next char in the input buffer ; +; ES:DI Points to the token buffer ; +; CX Character count ; +; AX Condition Code ; +; =1 same as carry set ; +; =2 normal token ; +; =4 switch character, char in token buffer ; +; Carry Flag Set if a CR was found, Reset otherwise ; +; ; +; MODIFIES: ; +; CX, SI, AX and the Carry Flag ; +; ; +;-----------------------------------------------------------------------; + +TAB equ 09h +CR equ 0dh + +CPARSE: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + pushf ;save flags + push di ;save the token buffer addrss + xor cx,cx ;no chars in token buffer + call kill_bl + + cmp al,CR ;a CR? + jne sj2 ;no, skip +sj1: + mov ax,1 ;condition code + dec si ;adjust the pointer + pop di ;retrive token buffer address + popf ;restore flags + stc ;set the carry bit + ret + +sj2: + mov dl,[SWITCHAR] + cmp al,dl ;is the char the switch char? + jne anum_char ;no, process... + call kill_bl + cmp al,CR ;a CR? + je sj1 ;yes, error exit + call move_char ;Put the switch char in the token buffer + mov ax,4 ;Flag switch + jmp short x_done2 + +anum_char: + call move_char ;just an alphanum string + lodsb + cmp al,' ' + je x_done + cmp al,tab + je x_done + cmp al,CR + je x_done + cmp al,',' + je x_done + cmp al,'=' + je x_done + cmp al,dl ;Switch character + jne anum_char +x_done: + dec si ;adjust for next round + mov ax,2 ;normal token +x_done2: + push ax ;save condition code + mov al,0 + stosb ;null at the end + pop ax + pop di ;restore token buffer pointer + popf + clc ;clear carry flag + ret + + +kill_bl proc near + lodsb + cmp al,' ' + je kill_bl + cmp al,tab + je kill_bl + cmp al,',' ;a comma? + je kill_bl + cmp al,'=' + je kill_bl + ret +kill_bl endp + + +move_char proc near + stosb ;store char in token buffer + inc cx ;increment char count + ret +move_char endp + +CODE ENDS + END START + \ No newline at end of file diff --git a/PROC.ASM b/PROC.ASM new file mode 100644 index 0000000..694b7d0 --- /dev/null +++ b/PROC.ASM @@ -0,0 +1,130 @@ +; +; process control system calls for MSDOS +; + +INCLUDE DOSSEG.ASM + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xlist +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + + i_need CurrentPDB,WORD + i_need CreatePDB,BYTE + i_need NUMIO,BYTE + i_need Exit_type,BYTE + i_need INDOS,BYTE + i_need DMAADD,DWORD + i_need DidCTRLC,BYTE + +SUBTTL $WAIT - return previous process error code +PAGE +; +; process control data +; + i_need exit_code,WORD ; code of exit + +; +; Assembler usage: +; MOV AH, Wait +; INT int_command +; AX has the exit code + procedure $WAIT,NEAR + ASSUME DS:NOTHING,ES:NOTHING + MOV AX,[exit_code] + XOR DX,DX + MOV [exit_code],DX + transfer SYS_RET_OK +$WAIT ENDP + +IF IBM + procedure $EXEC,NEAR + error error_invalid_function +$EXEC ENDP +ENDIF +IF NOT IBM +INCLUDE EXEC.ASM +ENDIF + +SUBTTL Terminate and stay resident handler +PAGE +; +; Input: DX is an offset from CurrentPDB at which to +; truncate the current block. +; +; output: The current block is truncated (expanded) to be [DX+15]/16 +; paragraphs long. An exit is simulated via resetting CurrentPDB +; and restoring the vectors. +; + procedure $Keep_process,NEAR + ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP + + PUSH AX ; keep exit code around + MOV BYTE PTR [Exit_type],Exit_keep_process + MOV ES,[CurrentPDB] + CMP DX,6h ; keep enough space around for system + JAE Keep_shrink ; info + MOV DX,6h +keep_shrink: + MOV BX,DX + PUSH BX + PUSH ES + invoke $SETBLOCK ; ignore return codes. + POP DS + POP BX + JC keep_done ; failed on modification + MOV AX,DS + ADD AX,BX + MOV DS:[PDB_block_len],AX + +keep_done: + POP AX + JMP SHORT exit_inner ; and let abort take care of the rest + +$Keep_process ENDP + + procedure Stay_resident,NEAR + ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + MOV AX,(Keep_process SHL 8) + 0 ; Lower part is return code + ADD DX,15 + MOV CL,4 + SHR DX,CL + + transfer COMMAND +Stay_resident ENDP + +SUBTTL $EXIT - return to parent process +PAGE +; +; Assembler usage: +; MOV AL, code +; MOV AH, Exit +; INT int_command +; Error return: +; None. +; + procedure $EXIT,NEAR + ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP + XOR AH,AH + XCHG AH,BYTE PTR [DidCTRLC] + OR AH,AH + MOV BYTE PTR [Exit_type],exit_terminate + JZ exit_inner + MOV BYTE PTR [Exit_type],exit_ctrl_c + +Exit_inner: + invoke get_user_stack + PUSH [CurrentPDB] + POP [SI.user_CS] + transfer abort_inner +$EXIT ENDP + +do_ext + +CODE ENDS + END diff --git a/RDATA.ASM b/RDATA.ASM new file mode 100644 index 0000000000000000000000000000000000000000..7a9b3682f66c7d84a5090564944b358b0ef6a287 GIT binary patch literal 6784 zcmWIX4DoSQP*8C8_w{x3b5RINEzV3y%_~uGaSUKX1fC5iHXP;0PSCGQsa6QLh zUtTV~ik!^i5)hqSl$wTJsjE9wEmSE)C8kB*@j**~8V@8_Y$R z>FVba4Dwee8Yo0LtJ%SgMxfrgLORpLm~roT!O;< zLVZD$k86mIpKG{}rys&YFwo+1YnWq*j+3K{n`4NM zv%jyCql=E8tE-E%KiEv)V0TQzoc(=4cDcB^`3Ae|1O)l}288Ii`nfnchJfqMe*Vt>zL3G6 zcq7;NAlDF`V8<}m_y89tOydF^gIxVWKtbf}5^rRp12Wvl)xc24$KTP#)6ZSU$uY#) z14R1xJA*tN9N_A#14>W9n1+P}`31YWgH*W$g@N=qMTY43y7~rtM(G5H`ht=?D4c>^ zLqJJR$JN=x-_6GnONe>;$Ag@#6XY5k;^G;k6W|);3(^_v>F4g_3Sx!128B8L=(za@ zflSZ|b@LB$2@1n>lAC`}uxkiN9Y~j(e^8iX5QrBL0;WRUoSi^i5EbMa@97sD5~LI4 z8t)$(67LugfN35?4x}o;Gr$#WH<;n+;~K03Vu1_>(J&>3U{NDXlRW)E%0SBfLqlLp zP+Ew0^6_`})^YU<^9+IpXFN!mv%hb=o3oQ4rcqECBb@-pAYZ3YH*oxfIR*vm_(p_Y86Na17E3a`6lTF)$4RD>sDb!s29TmUQ)VLC%4=3I|wT3XTkpcXssg z(E%3)I<66}AUA~uy9UJv2k1cPV6bo~QhJ9L9|$-42f2guyaA|83GxTAZ9#;Bf`SS! z7bN>DD7b_}#Qfddf?Y!tf?R{$gZx7StXzYF3=n4FQH2z|cvK+;4jxs;MA>LUlqyrA zRGAT_%A6=w7DTDCBubSbk%3QK=o=b=(jTO##~tO6vK^8fK%}*jff8ZII{W*o7=n~T zv9*#R5xQK1f{dXWz?8L;5fQo^eSG|#RS+7jm5hnd<>u+*s$v4R225BhnGm5XD9ArZ z#T2XoOjs+K5~0i4(NDz;tR6yGE140Y%hlIEC{o27qD4VL!CJ|j2whH&Au1MdJs@2c zMCkJL3s$j2(PgOwN*$mK4-$590+9*|O5sJBC8-JpMfoME$x1p(B}&>B1{u6uu0cWI z=!UCvN=#8G&C5hpVgxb-uEa0DM4>1(F-1v7sS;rfI3D3@K*l8J=jJBnfs`pAl!0Ro zuFNH|L`g>}5g`qZBDgfzl*F7IP%9}n5!FrLc!8@7PEA$PQOZUb1P*?Tt<;UQTG1x>M zB^4!5io}AgeM^f=6p~UER1`{5i*hsb5=&B3K>Z0wv4*f6(nCJ{lqBZl zSB8sthkO0XmhD}E5l(lT>E$pEGRR?@%~6cyzcAsGNGQ{eK>iFtYXplkp$0akv% zRix&EO@L)KCum6lmsdziECFTe45(LNg#uiGXI^nC$PKVu4{guG16;{5DZi*hM!ys&PqTQckKu61a5Gfw~9MQ9xGe znOByWlbK?u=j`tbPB-8#1j0QAmS8DRe$7?@CrMb~xCDjy2D>Af1y7NXeg=|^Ba#Oo zy$>YGlvGfjD^UPxSJF{Rg*p||JwZ}ukeHXEP+U@!nVqVTm{+Ngom#0-o{^ddE&(f* zbd(IBI^jJUs4tWZLSPBdLLnN>Ol= z!5t$cH@TW-<|(*FxSAkY59u}`DGDgcPcKT$RVc~NS4hfCS18F>NXsly$jnp7HAm71 z?q?wv0tTQ$H@`?BH?z1nGcR4i8B&TXc;=O)78MkwmVlfFF7rHix!~O~s2`LJ{PGpj zic(WeG7|Gr!1X%HM-EAWSx$apilL4|ab? zVh-4HSeXp%@gZv{E=epZG1O5=t;j6N%u7e|C$w9LP;8W6WRjPd3vvN0pn16vokj&0 z7X<|cd$c0PTERClJu_JWTD2*pR-`7EmZXBZ@Fk^1c?yXsDMhKp#k^dg{u`*v32Twt z^KwD@nxLSDG}7&PLA5Wq--)CO)&oTng7!t>PB#E$z7S^*gi#8hdI#C5)(Vcr#ihBa z3VHe9!XZN;H$Np+Au}(tBr`E5rxI*}kH515#G48VSWF1WFU|xNexM`+Dqu1cKqVcx zECuy~;m$EJ02S972AaHF;Epkpv!LA&kT9el0x5M}Kq^6fWkl=M9&D~lP#7WwV}`v; zkY|{y0@(5pe+5vmC^&|O_=B?zXgCaRx|3swQzTO5WDn{g`38GNp;#Ck>I)7tSQiEq zArT?Y{=Nt|fNE;68Yp3{;Fezm4n`dXa9+quQOE+-I4PMa3W<3NsTC!uMR|!iyj;*; zJ}ep)K!!s*{IHNSAs?~s(3o<5v@S(0Ds38a) zB7p0)=jDQq7QlrJc)1|s1PFga;uKN^yZHy9go!0MzTt9VjzI{0_F$s|LO?>0R1WgE zn|}~!qycUr$YmgRIXfYABKMG>b-l3(IANhQ1E7W?tA+_dqXD|kXuduCOtLQs%G zT4ria3aAvUN-fFxfZ`K0DiRzL1QAg{Qq9X{9g>k+ zoT^Y#p0AKpS&~|;P?VaMnxc?ctdOWso?n#0%LN+Y01cPGJPe9e&-~?)-0mxAx zb)euwN|PWVguMz1hDMg~Z~@7I(kQ&9kGIlS1qV)4 zgPQlC`pj7&IWZ@vn3u~HI`{*zM*)fPokYO6C4RE=cV|XezKU02PY}yQ~!g z@-y>F6cS4mO7qh4i*gf7N>Wo43KEMFb5l!Fi;6LgfD}dGu_mbV6; z0qtfuw1cY(&_EV6VZfstlIM82JlzyvL(#C&C6JFnHI_YScqqcv8N`Pc#L#F04?lqi zyRE?E)x2D;;GrmpN>F+O6%CMKDX&>KhW44%DlZpkOc108Mv;=P5-%5QU=b>&prlVk2Oc&L0`-m|C}o2j1Wxo220{oUEMU_n mP~AodrQp&8F=7cZ36^<4kpe1hpz@%}3Z(ID@Bk+RHUI#VD)p)W literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 09c0c83..8cc8973 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,98 @@ # MS-DOS 2.11 -MS-DOS 2.11 Source Code +MS-DOS 2.11 source code released by CHM, with files from the MS-DOS 2.00 OAK removed (as they are not MS-DOS 2.11 source files). CHM did not preserve the directory structure of the original source code. Timestamps provided below for reference: + +``` +1983/08/18 14:26:36 11,648 ALLOC.ASM +1983/08/19 11:53:04 14,716 BUF.ASM +1983/08/18 16:10:38 26,880 CHKDSK.ASM +1983/08/18 16:14:44 14,080 CHKMES.ASM +1983/08/18 16:12:18 40,704 CHKPROC.ASM +1983/08/25 15:06:18 900 COMEQU.ASM +1983/08/18 15:18:16 128 COMLINK +1983/08/18 14:59:06 23,936 COMMAND.ASM +1983/08/25 15:04:08 782 COMSEG.ASM +1980/01/01 00:13:10 512 COMSW.ASM +1983/08/18 15:14:20 20,480 COPY.ASM +1983/08/18 15:15:16 18,304 COPYPROC.ASM +1983/08/18 15:15:56 9,472 CPARSE.ASM +1983/08/19 11:55:50 14,764 CTRLC.ASM +1983/08/18 16:03:54 34,304 DEBASM.ASM +1983/08/18 15:58:12 27,008 DEBCOM1.ASM +1983/10/20 10:28:10 37,356 DEBCOM2.ASM +1983/08/18 16:07:06 38,912 DEBCONST.ASM +1983/08/18 16:07:40 2,816 DEBDATA.ASM +1980/01/01 01:12:36 1,280 DEBEQU.ASM +1980/01/01 00:49:10 5,248 DEBMES.ASM +1983/08/18 16:05:14 21,888 DEBUASM.ASM +1983/08/18 15:56:58 22,016 DEBUG.ASM +1983/08/18 14:27:22 12,032 DEV.ASM +1983/08/18 14:28:48 29,568 DIR.ASM +1983/08/18 14:25:40 14,592 DIRCALL.ASM +1983/08/18 14:30:38 38,016 DISK.ASM +1980/01/01 00:51:48 6,656 DISKCOPY.ASM +1980/01/01 00:52:38 7,808 DISKMES.ASM +1983/08/25 16:46:20 141 DOSLINK +1983/09/12 10:41:22 4,395 DOSMAC.ASM +1983/09/28 14:41:50 14,098 DOSMES.ASM +1983/08/25 15:04:22 357 DOSSEG.ASM +1983/08/25 15:05:44 44,887 DOSSYM.ASM +1980/01/01 02:08:10 56,960 EDLIN.ASM +1983/08/18 16:21:46 3,200 EDLMES.ASM +1983/09/22 23:03:32 13,190 EDLPROC.ASM +1980/01/01 00:45:06 13,824 EXE2BIN.ASM +1983/08/19 11:59:32 31,011 EXEC.ASM +1980/01/01 00:45:24 768 EXEMES.ASM +1983/08/18 14:31:30 10,112 FAT.ASM +1980/01/01 00:26:22 65,024 FC.ASM +1983/08/19 11:52:32 13,392 FCB.ASM +1980/01/01 00:26:42 2,048 FCMES.ASM +1980/01/01 00:28:36 39,168 FIND.ASM +1980/01/01 00:29:22 1,408 FINDMES.ASM +1980/01/01 14:48:16 46,720 FORMAT.ASM +1983/09/22 22:00:04 4,529 FORMES.ASM +1983/08/18 14:14:38 18,048 GETSET.ASM +1983/08/25 15:06:00 303 IFEQU.ASM +1983/08/18 15:01:24 24,832 INIT.ASM +1983/08/18 14:13:16 18,304 MISC.ASM +1980/01/01 02:39:20 3,712 MORE.ASM +1983/09/22 21:23:54 313 MOREMES.ASM +1980/01/03 05:25:56 22,208 MSCODE.ASM +1980/01/01 00:15:46 11,520 MSDATA.ASM +1980/01/03 05:18:14 176 MSDOS.ASM +1980/01/01 00:10:14 9,216 MSHEAD.ASM +1980/01/01 00:24:52 13,568 MSINIT.ASM +1980/01/01 02:42:56 48,000 PRINT.ASM +1983/08/19 11:55:22 3,222 PROC.ASM +1983/08/18 15:00:18 6,784 RDATA.ASM +1980/01/01 00:39:06 5,760 RECMES.ASM +1980/01/01 03:01:58 23,808 RECOVER.ASM +1983/08/18 14:32:20 14,336 ROM.ASM +1983/08/18 14:59:40 6,912 RUCODE.ASM +1983/09/22 22:27:04 17,099 SORT.ASM +1980/01/01 03:07:50 2,688 SORTMES.ASM +1983/08/18 14:32:46 256 STDBUF.ASM +1983/08/18 14:33:56 256 STDCALL.ASM +1983/08/18 14:39:02 256 STDCTRLC.ASM +1980/01/03 07:40:50 193 STDFCB.ASM +1980/01/03 07:41:02 210 STDIO.ASM +1980/01/03 06:27:54 185 STDPROC.ASM +1980/01/01 00:12:18 1,280 STDSW.ASM +1983/08/19 11:54:24 9,726 STRIN.ASM +1983/09/22 21:29:40 22,784 SYS.ASM +1980/01/03 06:26:22 21,220 SYSCALL.ASM +1980/01/01 00:44:22 512 SYSIMES.ASM +1983/10/12 21:24:26 37,644 SYSINIT.ASM +1983/09/22 21:52:50 1,206 SYSMES.ASM +1983/09/08 01:48:06 33,664 TCODE.ASM +1983/08/18 15:05:08 13,568 TCODE2.ASM +1983/08/18 15:10:32 16,896 TCODE3.ASM +1983/08/18 15:11:40 27,392 TCODE4.ASM +1983/09/08 01:49:00 24,576 TCODE5.ASM +1980/01/01 00:38:32 9,088 TDATA.ASM +1983/08/18 14:45:52 7,040 TIME.ASM +1983/08/18 15:17:42 4,480 TSPC.ASM +1983/08/18 15:13:22 7,808 TUCODE.ASM +1980/01/01 00:03:04 896 UINIT.ASM +1980/01/03 06:57:14 25,984 XENIX.ASM +1983/08/18 14:51:18 17,792 XENIX2.ASM +``` diff --git a/RECMES.ASM b/RECMES.ASM new file mode 100644 index 0000000000000000000000000000000000000000..0723208bf80f584f0605e24b4396e2833a2cbeb2 GIT binary patch literal 5760 zcmWIX4DoSQP*4bRb@mT)4N~w;EiO(>Pc7!)kQNh$foAeE_wr65Yd$S{MKD=9y}1jK_28f5TtB^IS7rYI;Vzy(b~g5^b- zC8l+y;q+}MQCYR(FRYFzhDFmhF=9i@^WR@tT zBmq=OVID5MwVmlh}}D1aQS19puLNHN%LMGz&h*f&VY;N{9mLlaB{$393qNCK-r zKoTIFSX^A1o2sCYTx^w+u9E^LQ^900hy>XQQU<~>Uj#S@`M6p6xjF{v1O$2dg+Q2| zej)Kj#t^o%zh9VZ5JUoz<^n>Ud_0{M6jF+_%Zo~MQi`*SQgmE`yM3+?|pHvQt6903-;}Vx>?}TATqAPOLx}3lmGiB9@FrECop{GY=He3JQtf{DUwv zH@^&IjY2fUHL*I0IS9$jykxLsaRD|lu#|#za!zVuo$N z0TV-UEmR$fub^VczR!X>rl2Ub1Yrxz{l%F&`DtmzsU-?2=~fCLPiE$&Ba|g4=H!6f zn^K&eT2zD(&#D56!eR;`o}81+%LTH@N&K;gqX9Vj}ORR zaJhjH_Vo_~i7Ghy=tO(CI{Ul0#v&x0eFI>UhDHcsFDGy%s^H-m=Irl+5Jxf#q#PoR znoFk!6_Py{NDAi7E_3sMnU zVBT|y(D8S33w8}raB;VC4GQwb8q6SbvFZ&*iYOFUU{#H<$t5TZpG}Uz-bg`>)vZCU zfuXL!Aqaa2Snn92qY)h967THq7w_p85E>Hi<^xK-pqR1H)JBm)80zU40uD+eLvT6= zvq1zTW{Oga3-a@dk%ARlhJZT^RLLQX4)BMjN2K%*O;ex*Y-E6BqqTx_eqLE>Q3)s! zo(P#q0*B2rR73Lr;Fj)Hi`S|KR4 zIJKl$p(?c~Um-0gF`btStQ$!$EWnXdI84k1DILSbkRk>qhEjk*BM_yagNh;N{UFy6 zkY}v5hz6iWFF5NKE0koUDnvv?DCDOpL`Ft}8-c|NMXAa8WvNA}DX^kI52ORs-UTTw zOUx-vg*3EN%JYj-6cS4mQZls-%@p$U6jJj_iYnpCK}KRI*GNfC&PfEBo(O8JgN)Dw znUR*6Q=C}^*6WvFl4=FA6B7EKY0w6AN@{T?NMlL9LIJqwNrbsjAt^O2zbF;#pR~-P z;u3|t(%hufA{~S&3JQ>-4rCX|+t6YT(inG%P)N*6Q2;kDz)eIwP?$p6ct~*!tILZs zb)vz3j)l0;8dQ*i421^}BHh9Cq(JppAXOSLxugo@R!@FfZZVcNPck%*LabC!um;DW zf)dEi{4@n61qBTkPpe>0g|z$}P$o`MNUDT|55hSx-RLx^AA}|bsTop0g+fxLf>VSh z!W5Xpi!*f~@dnij4+wbFW9mtP>Cr~2Ct(JnhD2&!3Q0i$vK7?pK~BTYK?*)@N(g5_ zTY-=^yMh9&GXw6mC@3gk?Ry|}!@2}cjxJ%YK{|=W*}28(Iw?hEIjJQ&E9MYvoF3L#*X-h3C(n(58NhvDR$uGzQ@nE|0LA_vJE=Xmq zpx_b?31UPg=Nc4bfN&UAd8EbwR(Yfdz$$M{zmj%?QYw6OgwcAa6-P-jHAb z5(+_3YC~*x=GGP?zy?S?f{W;4^2O4oJ^xw6VzgWq-%9vE=U=Quu9$0N18E|F91C&}Qk`K3QkxX1zyo*)=R(~9uHqGtgh8$V1vsR}LzY0R&(x7KJ2=!*i;9rcd*+oT=47To z+dm*<3lfVGb5l!Fi;6)OKq?z78XysoUj+7)LSABSDo8n`QbJPh1{&f-VALSEC + XOR AL,AL +NOREAD: + PUSH ES + CALL BUFSEC + MOV DS,[DMAADD+2] +ASSUME DS:NOTHING + SHR CX,1 + JNC EVENWRT + MOVSB +EVENWRT: + REP MOVSW + POP ES + LDS BX,[CURBUF] + MOV BYTE PTR [BX.BUFDIRTY],1 + LEA SI,[BX.BufInSiz] + SUB DI,SI ; Position in buffer + MOV SI,DI + MOV DI,BX + invoke PLACEBUF + CMP SI,ES:[BP.dpb_sector_size] + JB WBUFPLACED + invoke PLACEHEAD +WBUFPLACED: + PUSH SS + POP DS + return +BUFWRT ENDP + +SUBTTL NEXTSEC -- Compute next sector to read or write +PAGE + procedure NEXTSEC,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Compute the next sector to read or write +; ES:BP Points to DPB + + TEST BYTE PTR [TRANS],-1 + JZ CLRET + MOV AL,[SECCLUSPOS] + INC AL + CMP AL,ES:[BP.dpb_cluster_mask] + JBE SAVPOS + MOV BX,[CLUSNUM] + CMP BX,0FF8H + JAE NONEXT + invoke UNPACK + MOV [CLUSNUM],DI + INC [LASTPOS] + MOV AL,0 +SAVPOS: + MOV [SECCLUSPOS],AL +CLRET: + CLC + return +NONEXT: + STC + return +NEXTSEC ENDP + +SUBTTL OPTIMIZE -- DO A USER DISK REQUEST WELL +PAGE + procedure OPTIMIZE,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; BX = Physical cluster +; CX = No. of records +; DL = sector within cluster +; ES:BP = Base of drives parameters +; [NEXTADD] = transfer address +; Outputs: +; AX = No. of records remaining +; BX = Transfer address +; CX = No. or records to be transferred +; DX = Physical sector address +; DI = Next cluster +; [CLUSNUM] = Last cluster accessed +; [NEXTADD] updated +; ES:BP unchanged. Note that segment of transfer not set. + + PUSH DX + PUSH BX + MOV AL,ES:[BP.dpb_cluster_mask] + INC AL ; Number of sectors per cluster + MOV AH,AL + SUB AL,DL ; AL = Number of sectors left in first cluster + MOV DX,CX + MOV CX,0 +OPTCLUS: +; AL has number of sectors available in current cluster +; AH has number of sectors available in next cluster +; BX has current physical cluster +; CX has number of sequential sectors found so far +; DX has number of sectors left to transfer +; ES:BP Points to DPB +; ES:SI has FAT pointer + invoke UNPACK + ADD CL,AL + ADC CH,0 + CMP CX,DX + JAE BLKDON + MOV AL,AH + INC BX + CMP DI,BX + JZ OPTCLUS + DEC BX +FINCLUS: + MOV [CLUSNUM],BX ; Last cluster accessed + SUB DX,CX ; Number of sectors still needed + PUSH DX + MOV AX,CX + MUL ES:[BP.dpb_sector_size] ; Number of sectors times sector size + MOV SI,[NEXTADD] + ADD AX,SI ; Adjust by size of transfer + MOV [NEXTADD],AX + POP AX ; Number of sectors still needed + POP DX ; Starting cluster + SUB BX,DX ; Number of new clusters accessed + ADD [LASTPOS],BX + POP BX ; BL = sector postion within cluster + invoke FIGREC + MOV BX,SI + return +BLKDON: + SUB CX,DX ; Number of sectors in cluster we don't want + SUB AH,CL ; Number of sectors in cluster we accepted + DEC AH ; Adjust to mean position within cluster + MOV [SECCLUSPOS],AH + MOV CX,DX ; Anyway, make the total equal to the request + JMP SHORT FINCLUS +OPTIMIZE ENDP + +SUBTTL FIGREC -- Figure sector in allocation unit +PAGE + procedure FIGREC,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DX = Physical cluster number +; BL = Sector postion within cluster +; ES:BP = Base of drive parameters +; Outputs: +; DX = physical sector number +; No other registers affected. + + PUSH CX + MOV CL,ES:[BP.dpb_cluster_shift] + DEC DX + DEC DX + SHL DX,CL + OR DL,BL + ADD DX,ES:[BP.dpb_first_sector] + POP CX + return +FIGREC ENDP + +SUBTTL GETREC -- Figure record in file from fcb +PAGE + procedure GETREC,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX point to FCB +; Outputs: +; CX = 1 +; DX:AX = Record number determined by fcb_EXTENT and fcb_NR fields +; DS:DI point to FCB +; No other registers affected. + + MOV DI,DX + CMP BYTE PTR [DI],-1 ; Check for extended FCB + JNZ NORMFCB2 + ADD DI,7 +NORMFCB2: + MOV CX,1 + MOV AL,[DI.fcb_NR] + MOV DX,[DI.fcb_EXTENT] + SHL AL,1 + SHR DX,1 + RCR AL,1 + MOV AH,DL + MOV DL,DH + MOV DH,0 + return +GETREC ENDP + +SUBTTL ALLOCATE -- Assign disk space +PAGE + procedure ALLOCATE,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; BX = Last cluster of file (0 if null file) +; CX = No. of clusters to allocate +; DX = Position of cluster BX +; ES:BP = Base of drive parameters +; [THISFCB] = Points to FCB +; Outputs: +; IF insufficient space +; THEN +; Carry set +; CX = max. no. of records that could be added to file +; ELSE +; Carry clear +; BX = First cluster allocated +; FAT is fully updated including dirty bit +; fcb_FIRCLUS field of FCB set if file was null +; SI,BP unchanged. All other registers destroyed. + + PUSH BX ; save the fat byte + XOR BX,BX + invoke UNPACK + MOV [FATBYT],DI + POP BX + + PUSH DX + PUSH CX + PUSH BX + MOV AX,BX +CLUSALLOC: + MOV DX,BX +FINDFRE: + INC BX + CMP BX,ES:[BP.dpb_max_cluster] + JLE TRYOUT + CMP AX,1 + JG TRYIN + POP BX + MOV DX,0FFFH + invoke RELBLKS + POP AX ; No. of clusters requested + SUB AX,CX ; AX=No. of clusters allocated + POP DX + invoke RESTFATBYT + INC DX ; Position of first cluster allocated + ADD AX,DX ; AX=max no. of cluster in file + MOV DL,ES:[BP.dpb_cluster_mask] + MOV DH,0 + INC DX ; DX=records/cluster + MUL DX ; AX=max no. of records in file + MOV CX,AX + SUB CX,WORD PTR [RECPOS] ; CX=max no. of records that could be written + JA MAXREC + XOR CX,CX ; If CX was negative, zero it +MAXREC: + STC + return + +TRYOUT: + invoke UNPACK + JZ HAVFRE +TRYIN: + DEC AX + JLE FINDFRE + XCHG AX,BX + invoke UNPACK + JZ HAVFRE + XCHG AX,BX + JMP SHORT FINDFRE +HAVFRE: + XCHG BX,DX + MOV AX,DX + invoke PACK + MOV BX,AX + LOOP CLUSALLOC + MOV DX,0FFFH + invoke PACK + POP BX + POP CX ; Don't need this stuff since we're successful + POP DX + invoke UNPACK + invoke RESTFATBYT + XCHG BX,DI + OR DI,DI + retnz + PUSH ES + LES DI,[THISFCB] + AND BX,0FFFh + MOV ES:[DI.fcb_FIRCLUS],BX + AND ES:[DI.fcb_LSTCLUS],0F000h ; clear out old lstclus + OR ES:[DI.fcb_LSTCLUS],BX ; or the new guy in... + POP ES + return +ALLOCATE ENDP + + procedure RESTFATBYT,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + + PUSH BX + PUSH DX + PUSH DI + XOR BX,BX + MOV DX,[FATBYT] + invoke PACK + POP DI + POP DX + POP BX + return +RESTFATBYT ENDP + +SUBTTL RELEASE -- DEASSIGN DISK SPACE +PAGE + procedure RELEASE,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; BX = Cluster in file +; ES:BP = Base of drive parameters +; Function: +; Frees cluster chain starting with [BX] +; AX,BX,DX,DI all destroyed. Other registers unchanged. + + XOR DX,DX +entry RELBLKS +; Enter here with DX=0FFFH to put an end-of-file mark +; in the first cluster and free the rest in the chain. + invoke UNPACK + retz + MOV AX,DI + invoke PACK + CMP AX,0FF8H + MOV BX,AX + JB RELEASE +RET12: return +RELEASE ENDP + +SUBTTL GETEOF -- Find the end of a file +PAGE + procedure GETEOF,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; ES:BP Points to DPB +; BX = Cluster in a file +; DS = CS +; Outputs: +; BX = Last cluster in the file +; DI destroyed. No other registers affected. + + invoke UNPACK + CMP DI,0FF8H + JAE RET12 + MOV BX,DI + JMP SHORT GETEOF +GETEOF ENDP + +do_ext + +CODE ENDS + END + \ No newline at end of file diff --git a/RUCODE.ASM b/RUCODE.ASM new file mode 100644 index 0000000000000000000000000000000000000000..927a559ee312175972e261974bc8373fd5242589 GIT binary patch literal 6912 zcmWIX4DoSQP*8C8_w{x3b5Za~%u6p#OixwF%}>cp%S=qlNmX#pPf1k>N-fSzNzE(a z0Q_k7nH`vu3 zyFQRyI7CVhYCFVoOe>uIeO&`XA!>QKTpU9jgIt3Zf?eHxUHw870z#d9Je?7`Tq8n) z{1g-vT>V^}97B9vgRPt*LtJ&797CKvtit_+Ty$KWJ^bB#9Ni%j&MvNDjv-(+rXen_ zVXl6TzF=7$m!L2oSBOd--yl~<7l^QLc#vm^D}?Ro9}*b=W@4J<8WiO05^rPzafGjH zu#+RyZLUE z-N)70-xuN%H~%2GVjU+(7dL2V==iyY`*`}{@Qtr)u%ink1Q2oJ>gN&+N>IF9&i*d0 zn6ab)iVBbdXaZA!MOLt5n1`dEi^o_e~h_k=1 zOR%>QQ~^Q>BxxupI0k#W`nl-11be#%1?dC@1bO;}fL!4i931NFs-WN;Y!&1h>>lJF z8ldA6Y~|-4;^FD%uH%Ye2E&;keb!ne0A4O@1(5SS{TxGF6~M_*!OP!CAt1=#Hz33{ z2xK74Aub4q@Nz+1ZH4fTv!jm>DByx2fdx}xgrvmRKMbTo!6ib+-_0%9HADgCF)Mg} zz%&pRB4Diw3JNe&93ylzf|iz%xQ70MhRC|D z6?_x3Qx%F!i&7OpN)$>;i}F%a6p|8?vla65c)7rt%?l|B!BQDm!qLwK;XE&B9KmxW zDCvSQBx6~D5+o!;5za&~H(D!@kd=^>B3uOu6p(2l9-hGpp1}$s9(@wVd{1abM*9abn4?Sd+NRB6gi7+8J#1p{@0A)i3 z1qD!X3-UY&!^B*Jv8cnM*Es@Hogo^4`PqYQn*^!E!FVet=2f3v?GW%dHiHQ%gXhl9QjDn4^%ASdyqvoSL2s zZY*N0r;q{zmMW1_5zJA}K|XFsDxqF?i2#)!Fn7YD%+W_j$x#U=s-R%4;GCaZP+F3z zkW!Rcma34GT2hi)govx;jKreEL9%C;;9X3-p49fE4ZhYKr(7-kwQs6BsD4IrWO|`rXyAT5zZd&P}5x^Kny4b)!&s0 zd8w%>3N8@}If*5yNJ$Zvw;=5|s15~CehDbb%qxM~RZ>}iWD(4l*jk9-ZV19}sKz72 ziB0H`mY9N*52)FV(2mCiprRdX%5?P5fweY+LxMd0+~fU2LjpoW5T@d7r@^vTu!nz8 z2&g*%4J&H}m;5~S5{06~oPrEcsSoWqg9;^xv$3QPEFlN!mLVL2E979U)@W$oEmp?> zp$V2d9fQ3Qf^d_deIkSm%uk5^55!Z}3Z7}un9s>iOv%hkhYbhlC={jY78K>@7LyermIl2Bn89Egl97s1iwpAeklV~K*Pzxf{y|_(3XVQHMrZ|m zeqLE>Q3)t3=H!>B7NIr4VTsex1GO=4tq_z7YC0<a5eqJjz@{oBDimZEq=I@q1x5MkMXANbh!BCA zsNmwGVw4dm zV67Egz)haK{1Szt)WnoZgcevs0-TCKYM~fbs3n5pQlTUxRRL@h%uXct!$Sf(1QZKR z^VSNm7<2Ov!X9C8_re1TYw&~JhHx_6LL^;;gC1-M7H2#9pmZ%@hJ%u&C$wYhf}{;r zQebv$VGVZV-jrvMD|n0u(i%fD2FV)qAr{Es8N$188*!ABSZWf;P#{G{5L+3+JOU~s zp-Bf!L1Q1`23So44mcN3-N?&D(h!&yXbcR}Bq_=-Ey>JFEmi;(p&|L%sd<@IsVNFY z(D7(k!>AZ!3$(Z4f*2Ij2}ZC%DnNxkaZ%$39?Jyjfi#wobisN@j>zpUaJhwWAGE!u zPylLIAveKbnw^lkJTNij!VxAGjMV>wML@78xEzHz%n-?Cp!PCyUlZEBLT*yS8pn=4 zI_B8g#-Q5B0C{}O2^_}?5X+ES&9Dp&(qM_K!4Zds;82KBAPvYiI6EPA3t)|A#|Y$p z2+ZS7n4^@CVP!_+PU!K_A3gfKCb#0u@5qalM4K&sd8U2Sj P))h2#$UsBDi)l6hwK1_S literal 0 HcmV?d00001 diff --git a/SORT.ASM b/SORT.ASM new file mode 100644 index 0000000..a4f39e8 --- /dev/null +++ b/SORT.ASM @@ -0,0 +1,420 @@ +TITLE SORT FILTER FOR MS-DOS +; +; Sort /R /+n +; /R -> reverse sort +; /+n -> sort on column n +; +; Written by: Chris Peters +; +; Modification History: +; 3-18-83 MZ Fix CR-LF at end of buffer +; Fix small file sorting +; Fix CR-LF line termination bug +; Comment the Damn source +; +FALSE EQU 0 +TRUE EQU NOT FALSE + +;NOTE: "internat" must be false if KANJI version +internat equ true +;NOTE: see above + +.xlist +.xcref + INCLUDE DOSSYM.ASM +.cref +.list + +sys MACRO name ; system call macro + MOV AH,name + INT 21h + ENDM +save MACRO reglist ; push those registers +IRP reg, + PUSH reg +ENDM +ENDM +restore MACRO reglist ; pop those registers +IRP reg, + POP reg +ENDM +ENDM + +MAXREC EQU 256 ; MAXIMUM NUL RECORD SIZE + +SPACE EQU 0 ; Offset zero in the allocated block +BUFFER EQU MAXREC ; Offset MAXREC in the allocated block + +SUBTTL Segments used in load order + + +CODE SEGMENT +CODE ENDS + +CONST SEGMENT PUBLIC BYTE +CONST ENDS + +CSTACK SEGMENT STACK + DB 128 DUP (0) ; initial stack to be clear +CSTACK ENDS + +DG GROUP CODE,CONST,CSTACK + +CODE SEGMENT +ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:CSTACK + +COLUMN DW 0 ; COLUMN TO USE FOR KEY + 1 +SWITCH DB '/' + +SORT: +; +; check for proper version number of system +; + sys GET_VERSION + XCHG AH,AL ; Turn it around to AH.AL + CMP AX,200H ; Version 2.00 only + JAE OKDOS ; Success + MOV DX,OFFSET DG:BADVER ; Get error message + PUSH CS ; Get DS addressability + POP DS + sys STD_CON_STRING_OUTPUT ; Send to STDOUT + PUSH ES ; long segment + PUSH COLUMN ; offset zero +LONG_RET PROC FAR + RET ; long return to OS +LONG_RET ENDP +; +; get proper switch character +; +OKDOS: + MOV AL,0 ; Get current switch character + sys CHAR_OPER + MOV SWITCH,DL +; +; parse command line +; + MOV SI,80H ; pointer to command line + CLD ; go left to right + XOR CX,CX + LODSB + MOV CL,AL ; CX = length of command line +SWITCH_LOOP: + CALL GET_CHAR ; get a character + CMP AL,SWITCH ; beginning of switch? + JNZ SWITCH_LOOP ; No, get next character + CALL GET_CHAR ; get 1st char of switch + CMP AL,'+' ; Column to sort? + JZ SWITCH_NUMBER ; Yes, parse a number + OR AL,20h ; convert to lower case + CMP AL,'r' ; Reverse sort? + JNZ SWITCH_LOOP ; No, get next switch + MOV CS:CODE_PATCH,72h ; sleaze JAE into JB + JMP SWITCH_LOOP ; get next switch +SWITCH_NUMBER: + MOV COLUMN,0 ; start off at 0 +SWITCH_NEXT_NUMBER: + CALL GET_CHAR ; get supposed digit + SUB AL,'0' ; convert to number + JB SWITCH_LOOP ; less than '0' + CMP AL,9 ; is it a valid digit? + JA SWITCH_LOOP ; nope, get next switch + CBW ; make it a full word + MOV BX,AX ; save byte away + MOV AX,10 ; decimal number system + MUL COLUMN ; take previous result + ADD AX,BX ; add in low order digit + MOV COLUMN,AX ; save away value + JMP SWITCH_NEXT_NUMBER ; get next character +GET_CHAR: + JCXZ END_GET ; End of line + DEC CX ; dec char count + LODSB ; get the character + RET ; return +END_GET: + POP AX ; nuke return on stack +; +; set up column for proper sort offset +; +END_SWITCH: + ADD COLUMN,2 + CMP COLUMN,2 + JZ GOT_COL + DEC COLUMN + +; +; Get sorting area, no more than 64K +; +GOT_COL: + MOV BX,1000H ; 64K worth of paragraphs +GET_MEM: + sys ALLOC ; allocate them from somewhere + JNC GOT_MEM ; if error, BX has amount free, try to get it + OR BX,BX ; but, is BX = 0? + JNZ GET_MEM ; nope, try to allocate it + JMP SIZERR ; complain + +GOT_MEM: + MOV DS,AX ; Point DS to buffer + MOV ES,AX ; and point ES to buffer + MOV CL,4 ; 2^4 bytes per paragraph + SHL BX,CL ; Find out how many bytes we have + +; +; clear out temporary record area +; + MOV CX,MAXREC/2 ; Size of temporary buffer (words) + MOV AX,' ' ; Character to fill with + MOV DI,SPACE ; Beginning of temp buffer + REP STOSW ; Blam. +; +; read in file from standard input +; + MOV DX,BUFFER + 2 ; DX = place to begin reading + MOV CX,BX ; CX is the max number to read + SUB CX,MAXREC + 2 ; remember offset of temp buffer +SORTL: + XOR BX,BX ; Standard input + sys READ ; Read it in + ADD DX,AX ; Bump pointer by count read + SUB CX,AX ; subtract from remaining the count read + JZ SIZERR ; if buffer is full then error + OR AX,AX ; no chars read -> end of file + JNZ SORTL ; there were chars read. go read again + JMP SHORT SIZOK ; trim last ^Z terminated record +SIZERR: + MOV SI,OFFSET DG:ERRMSG ; not enough memory error +ERROR_EXIT: + PUSH CS ; DS addressability + POP DS + LODSW ; get length + MOV CX,AX ; put into appropriate register + MOV DX,SI ; get output destination + MOV BX,2 ; output to standard error + sys WRITE ; and write it out + MOV AL,1 ; return an error code + sys EXIT + +; +; Look for a ^Z. Terminate buffer at 1st ^Z. +; +SIZOK: + MOV BX,DX ; save end pointer + MOV CX,DX ; get pointer to end of text + SUB CX,BUFFER+2 ; dif in pointers is count + MOV AL,1AH ; char is ^Z + MOV DI,BUFFER+2 ; point to beginning of text + REPNZ SCASB ; find one + JNZ NoBack ; nope, try to find CRLF + DEC BX ; pretend that we didn't see ^Z +NoBack: + SUB BX,CX ; sub from endpointer the number left + SUB BX,2 ; Hope for a CR LF at end + CMP WORD PTR [BX],0A0Dh ; Was there one there? + JZ GOTEND ; yep, here is the end + ADD BX,2 ; nope, bump back to SCASB spot + CMP BYTE PTR [BX],AL ; Was there ^Z there? + JZ GOTEND ; yep, chop it + INC BX ; Nope, skip last char +GOTEND: + MOV BP,BX ; BP = filesize-2(CRLF)+temp buffer+2 + MOV WORD PTR DS:[BP],0 ; 0 at end of the file +; +; We now turn the entire buffer into a linked list of chains by +; replacing CRLFs with the length of the following line (with 2 for CRLF) +; + MOV BX,BUFFER ; pointer to line head (length) + MOV DI,BUFFER+2 ; pointer to line text +REPLACE_LOOP: + MOV AL,13 ; char to look for is CR + MOV CX,BP ; count = end pointer + SUB CX,DI ; chop off start point to get length + INC CX ; add 1??? +REPLACE_SCAN: + REPNZ SCASB ; look for CR + JNZ REPLACE_SKIP ; count exhausted + CMP BYTE PTR [DI],10 ; LF there? + JNZ REPLACE_SCAN ; nope, continue scanning +REPLACE_SKIP: + MOV AX,DI ; AX to point after CR + DEC AX ; AX to point to CR + save ; save pointer + SUB AX,BX ; AX is length of line found + MOV [BX],AX ; stuff it in previous link + restore ; get pointer to next + INC DI ; skip LF??? + JCXZ END_REPLACE_LOOP ; no more to scan -> go sort + JMP REPLACE_LOOP ; look for next + +END_REPLACE_LOOP: + MOV WORD PTR [BX],0 ; terminate file with nul + LEA BP,[BX+2] ; remember the null line at end + MOV DI,BUFFER ; DI is start of unsorted section + +; +; begin sort. Outer loop steps over all unsorted lines +; +OUTER_SORT_LOOP: + MOV BX,DI ; BX is start of unsorted section + MOV SI,BX ; SI is scanning place link + CMP WORD PTR [BX],0 ; are we at the end of the buffer? + JNZ INNER_SORT_LOOP ; No, do inner process + JMP END_OUTER_SORT_LOOP ; yes, go dump out + +; +; BX points to best guy found so far. We scan through the sorted section +; to find an appropriate insertion point +; +INNER_SORT_LOOP: + ADD SI,[SI] ; link to next fellow + MOV AX,[SI] ; get length of comparison guy + OR AX,AX ; test for end of buffer + JZ END_INNER_SORT_LOOP ; if zero then figure out insertion + save ; save SI,DI + MOV DI,BX ; DI = pointer to tester link + SUB AX,COLUMN ; adjust length for column + JA AXOK ; more chars in tester than column? + MOV SI,SPACE ; point SI to blank area + MOV AX,MAXREC ; make AX be max length +AXOK: + MOV DX,[DI] ; get length of best guy + SUB DX,COLUMN ; adjust length for column + JA DXOK ; there are more chars after column + MOV DI,SPACE ; point air to a space + MOV DX,MAXREC ; really big record +DXOK: + MOV CX,AX ; AX is shortest record + CMP AX,DX ; perhaps DX is shorter + JB SMALL ; nope, leace CX alone + MOV CX,DX ; DX is shorter, put length in CX +SMALL: + ADD DI,COLUMN ; offset into record + ADD SI,COLUMN ; offset into other record +if not internat + REPZ CMPSB ; compare every one + endif +if internat + push bx + push ax + mov bx,offset dg:table +tloop: lodsb + xlat byte ptr cs:[bx] + mov ah,al + mov al,es:[di] + inc di + xlat byte ptr cs:[bx] + cmp ah,al + loopz tloop + pop ax + pop bx + endif + restore ; get head pointers back + JNZ TESTED_NOT_EQUAL ; didn't exhaust counter, conditions set + CMP AX,DX ; check string lengths +TESTED_NOT_EQUAL: +; +; note! jae is patched to a jbe if file is to be sorted in reverse! +; +CODE_PATCH LABEL BYTE + JAE INNER_SORT_LOOP ; if this one wasn't better then go again + MOV BX,SI ; it was better, save header + JMP INNER_SORT_LOOP ; and scan again + +END_INNER_SORT_LOOP: + MOV SI,BX ; SI is now the best person + CMP SI,DI ; check best for current + JZ END_INSERT ; best equals current, all done + +; +; SI points to best line found so far +; DI points to a place to insert this line +; DI is guaranteed to be < SI +; make room for line at destination +; + MOV DX,[SI] ; get length of line + save ; save positions of people + STD ; go right to left + MOV CX,BP ; get end of file pointer + SUB CX,DI ; get length from destination to end + MOV SI,BP ; start from end + DEC SI ; SI points to end of file + MOV DI,SI ; destination is end of file + ADD DI,DX ; DI points to new end of file + REP MOVSB ; blam. Move every one up + CLD ; back left to right + restore ; get old source and destination +; +; MOVE NEW LINE INTO PLACE +; + save ; save destination + ADD SI,DX ; adjust for previous movement + save ; save this value + MOV CX,DX ; get number to move + REP MOVSB ; blam. move the new line in + restore ; get back destination and new source +; +; DELETE LINE FROM OLD PLACE +; + save ; save destination + MOV CX,BP ; pointer to end + ADD CX,DX ; remember bump + SUB CX,SI ; get count of bytes to move + INC CX ; turn it into a word + SHR CX,1 ; or a count of words + MOV DI,SI ; new destination of move + ADD SI,DX ; offset of block + REP MOVSW ; blam, squeeze out the space + restore ; get back original destination + MOV WORD PTR DS:[BP-2],0 ; remake the end of file mark + +END_INSERT: + ADD DI,[DI] ; link to next guy + JMP OUTER_SORT_LOOP ; and continue +; +; PUT BACK IN THE CR-LF +; +END_OUTER_SORT_LOOP: + MOV DI,BUFFER ; start at beginning (where else) + MOV CX,[DI] ; count of butes + +INSERT_LOOP: + ADD DI,CX ; point to next length + MOV CX,[DI] ; get length + MOV WORD PTR [DI],0A0DH ; replace length with CRLF + CMP CX,0 ; check for end of file + JNZ INSERT_LOOP ; nope, try again + +WRITE_FILE: + MOV DX,BUFFER+2 ; get starting point + MOV CX,BP ; pointer to end of buffer + SUB CX,DX ; dif in pointers is number of bytes + MOV BX,1 ; to standard output + sys WRITE ; write 'em out + JC BADWRT ; some bizarre error -> flag it + CMP AX,CX ; did we write what was expected? + JZ WRTOK ; yes, say bye bye +BADWRT: + MOV SI,OFFSET dg:ERRMSG2 ; strange write error + JMP ERROR_EXIT ; bye bye +WRTOK: + XOR AL,AL ; perfect return (by convention) + sys EXIT ; bye! + +CODE ENDS + +CONST SEGMENT PUBLIC BYTE + EXTRN BADVER:BYTE,ERRMSG:BYTE,ERRMSG2:BYTE +if internat + extrn table:byte + endif +CONST ENDS + +SUBTTL Initialized Data +PAGE +CSTACK SEGMENT STACK + DB 96 dup (0) +CSTACK ENDS + + END SORT + + + \ No newline at end of file diff --git a/SORTMES.ASM b/SORTMES.ASM new file mode 100644 index 0000000000000000000000000000000000000000..4fb6556e3e5caa390770439291a434fddfa1a205 GIT binary patch literal 2688 zcmWIX4DoSQP*4c=4+>H6O)V}?OiwN5<>KW^OUx-wWSgtIud82(LO`gKkEgSO zQ)GxM$W8?)fC?)(Il6?o2I;s41^EWMLn$MWLWqQdf{PPGhZ4y7RtlbZ$@xV^smUb@ zF8;v^WvNBQnfZB2I)=tNh6XxHDoP-&5W^G{T*4t*A$%hRT?OA@cf*i~5MC}Q1Jm^4 z(zLY9@^Wz&lqTh5CUce~Cgr5^a#@FDWELxcISMJMX_-l>#R?@EsS3&Yi8+ZSnR)37 z#i@m*sd>q%3MKgpNvR5@#i=O@Y57IGT-Go{GxPHja}<&@5{nX(OHzx9^%NA4Oij!w z&R0k+EKMu{r3~ww{PNTyh2+HIRD=$Y(WM0iF!9p7oXqT0g+ztolA^@S^o$Y($6#kq zPle+Aq7pq`E^E&;h06TWA|(CAsU-@T#R_0;AlG|3`6>iBD->tu7UWbal#~|b@p4(` z=Yf3&l1t9dOUWz&yIW5|!81)E6RbZaGc7H(2oyh1ow@lbnQ4_EZM7|M3NdDyIvQA1ZDNjw! zQz$9Vhx!T;ZXj2bXXfO9f;lfW8I+rfDiuoddAY2WiZe3PN|Y25b8B1Iy*-q$ogT$}=*PGZZos%Rn}y<|%+8CnFVN zPe}$S%^}4#BxWHx^*|W`9Lk(2Nt^~chB`(%#yTcCraERi=Db`WK?@yAP-ZkV)G;&y zXG{|vLsN*9p_z`MxsIWQj-jQFk%5kpp^lM}j*&4$(#S-|$W+J3OvlJv$H+p*$Wq7H zK*!h+BB`XHq@$#$q@%8+uA`)^1j_0>~ zV5qC4qok*#qofa0WT2#@WT>R0WTd2{WUQp4WTK>_WU8d2WTvE}WDZkgp`@c^sidQ1 zrKF=|t)!!5qoku`tE8i3r=+7~4^!lzq@(1hq@(1dq@(1lq@(1bq@(1jq@(1fq@&~x zQ{V9YbRi9YbSS zA~818F*G*UF*LT&F*LT+F*GsIF*GsMF*GsKF*JcD7DE#g9YYgS9YYf{9YYgy9YYff z9YYgK9Ya$C9Ya%SqA@fz(lInO)-f~%B|%diLsK&yLsN4dLsJVKLsLtro6HP!49yI6 z49$#m49$#n49!e*49!e+49(1R49%cv+R)5G$I#4D$I#qB$I#qR$I#qJ$I#qZ$I#qF z$Iu+)@YKAN%rvlnGm~;5CWF%iC>B9!0+ddWu`?{fK$0*FN+&Q3Q4BQ+qyQoSN;C)z zGCdS#5-4r>Llce)G>af;s7WAGKvuvMf|8-15~^>N>_GykzJ+BzbtQFPE>5U#LD}8V z9F(cebqvidbPUZcbqp;GbPO#Fbqp?0xWb4Ei82m zEe&)GEn(4RX{2LlX{=*tX`*9jX{uvrX{KXnX|7{v2`Vt4(Pd;{pkriUsAFVcq+?`Y ztYc(gqGM!Ws$*nerekCPjV>bt3mqc^OC2LaP$6TeV`ONgV`ONoV`ONeV+1RVj10|m zj10|nj0`Pwj6ekvs6+x6Nk%$Gph5{$C&S{>$jAhgGkLk7K1WU0AXy_LQ@AWBT#P^^ z8K@`&m1RbjI!49@I!3VK%*Ys2?iuSC8Jp-B8Jp@D8Jp=C8Jp`E8C&QW8Np^lNMk&cn6v5t`` ss5nJRnXb^*ifdpfxLKqED#>B3HCI2EU|ue;xPpR$tDg%m7X!5b0GM8O82|tP literal 0 HcmV?d00001 diff --git a/STDBUF.ASM b/STDBUF.ASM new file mode 100644 index 0000000000000000000000000000000000000000..400280a140f93bea9c1c41c654c68c24d77fef0d GIT binary patch literal 256 zcmcEK<+4@?E=kNwNi0fHNGeTBOD$5!P0UM7Pt8ruD^W>IN~Kfyw{?jGZt( literal 0 HcmV?d00001 diff --git a/STDCALL.ASM b/STDCALL.ASM new file mode 100644 index 0000000000000000000000000000000000000000..5d9d9266084f85be49a4bb45cf48a694e9d54308 GIT binary patch literal 256 zcmcEK<+4@?E=kNwNi0fHD6T9nNzGMAPRz+ER!GY)Qt%CS@ek(ZvgYOD<CngPR{24AKm-fq}{Z00+@8n*aa+ literal 0 HcmV?d00001 diff --git a/STDCTRLC.ASM b/STDCTRLC.ASM new file mode 100644 index 0000000000000000000000000000000000000000..a02d90dc2eee2af7aef763ff203f20036696e5f1 GIT binary patch literal 256 zcmcEK<+4_Yb5=;qOHoKID#|ZX$Vkjf$w@6zNXsu$@C|nH59Z~v=H=q$(yPeHEG_}j z$wjGYyj-4s&OV_ot_r~+F2Uh?j={dXTzU{0J%~bHt`N@!qtMTgjoUB46%ZN$^Za=(=QtU literal 0 HcmV?d00001 diff --git a/STDFCB.ASM b/STDFCB.ASM new file mode 100644 index 0000000..c046da1 --- /dev/null +++ b/STDFCB.ASM @@ -0,0 +1,16 @@ +; +; Standard FCB calls for MSDOS (first 12 function calls) +; + +.xlist +.xcref +INCLUDE STDSW.ASM +.cref +.list + +TITLE STDFCB - FCB calls for MSDOS +NAME STDFCB + +INCLUDE FCB.ASM + + \ No newline at end of file diff --git a/STDIO.ASM b/STDIO.ASM new file mode 100644 index 0000000..6a68b3e --- /dev/null +++ b/STDIO.ASM @@ -0,0 +1,17 @@ +; +; Standard device IO for MSDOS (first 12 function calls) +; + +.xlist +.xcref +INCLUDE STDSW.ASM +INCLUDE DOSSEG.ASM +.cref +.list + +TITLE STDIO - device IO for MSDOS +NAME STDIO + +INCLUDE IO.ASM + + \ No newline at end of file diff --git a/STDPROC.ASM b/STDPROC.ASM new file mode 100644 index 0000000..b9f8e36 --- /dev/null +++ b/STDPROC.ASM @@ -0,0 +1,16 @@ +; +; Pseudo EXEC system call for MSDOS +; + +.xlist +.xcref +INCLUDE STDSW.ASM +.cref +.list + +TITLE STDPROC - process maintenance for MSDOS +NAME STDPROC + +INCLUDE PROC.ASM + + \ No newline at end of file diff --git a/STDSW.ASM b/STDSW.ASM new file mode 100644 index 0000000..30a8a16 --- /dev/null +++ b/STDSW.ASM @@ -0,0 +1,34 @@ +TRUE EQU 0FFFFH +FALSE EQU NOT TRUE + +; Use the switches below to produce the standard Microsoft version or the IBM +; version of the operating system +MSVER EQU false +IBM EQU true +WANG EQU FALSE +ALTVECT EQU FALSE + +; Set this switch to cause DOS to move itself to the end of memory +HIGHMEM EQU FALSE + + IF IBM +ESCCH EQU 0 ; character to begin escape seq. +CANCEL EQU 27 +TOGLINS EQU TRUE ;One key toggles insert mode +TOGLPRN EQU TRUE ;One key toggles printer echo +ZEROEXT EQU TRUE + ELSE + IF WANG ;Are we assembling for WANG? +ESCCH EQU 1FH ;Yes. Use 1FH for escape character + ELSE +ESCCH EQU 1BH + ENDIF +CANCEL EQU "X"-"@" ;Cancel with Ctrl-X +TOGLINS EQU WANG ;Separate keys for insert mode on + ;and off if not WANG +TOGLPRN EQU FALSE ;Separate keys for printer echo on + ;and off +ZEROEXT EQU TRUE + ENDIF + + \ No newline at end of file diff --git a/STRIN.ASM b/STRIN.ASM new file mode 100644 index 0000000..7d87dbe --- /dev/null +++ b/STRIN.ASM @@ -0,0 +1,292 @@ + procedure $STD_CON_STRING_INPUT,NEAR ;System call 10 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX Point to an input buffer +; Function: +; Fill buffer from console input until CR +; Returns: +; None + + MOV AX,SS + MOV ES,AX + MOV SI,DX + XOR CH,CH + LODSW + OR AL,AL + retz ;Buffer is 0 length!!? + MOV BL,AH ;Init template counter + MOV BH,CH ;Init template counter + CMP AL,BL + JBE NOEDIT ;If length of buffer inconsistent with contents + CMP BYTE PTR [BX+SI],c_CR + JZ EDITON ;If CR correctly placed EDIT is OK +NOEDIT: + MOV BL,CH ;Reset buffer +EDITON: + MOV DL,AL + DEC DX ;DL is # of bytes we can put in the buffer +NEWLIN: + MOV AL,[CARPOS] + MOV [STARTPOS],AL ;Remember position in raw buffer + PUSH SI + MOV DI,OFFSET DOSGROUP:INBUF ;Build the new line here + MOV [INSMODE],CH ;Insert mode off + MOV BH,CH ;No chars from template yet + MOV DH,CH ;No chars to new line yet + invoke $STD_CON_INPUT_NO_ECHO ;Get first char + CMP AL,c_LF ;Linefeed + JNZ GOTCH ;Filter out LF so < works + entry GETCH + invoke $STD_CON_INPUT_NO_ECHO +GOTCH: + CMP AL,"F"-"@" ;Ignore ^F + JZ GETCH + CMP AL,[ESCCHAR] + JZ ESC + CMP AL,c_DEL + JZ BACKSPJ + CMP AL,c_BS + JZ BACKSPJ + CMP AL,c_CR + JZ ENDLIN + CMP AL,c_LF + JZ PHYCRLF + CMP AL,CANCEL + JZ KILNEW +SAVCH: + CMP DH,DL + JAE BUFFUL ;No room + STOSB + INC DH ;Got a char + invoke BUFOUT ;Print control chars nicely + CMP BYTE PTR [INSMODE],0 + JNZ GETCH ;In insert mode, get more chars + CMP BH,BL + JAE GETCH ;We are out of chars in template + INC SI ;Skip to next char in template + INC BH + JMP SHORT GETCH + +BACKSPJ: JMP SHORT BACKSP + +BUFFUL: + MOV AL,7 ;Bell + invoke OUT + JMP SHORT GETCH + +ESC: + transfer OEMFunctionKey + +ENDLIN: + STOSB ;Put the CR in the buffer + invoke OUT ;Echo it + POP DI ;Get start of buffer + MOV [DI-1],DH ;Tell user how many bytes + INC DH ;DH is length including CR +COPYNEW: + MOV BP,ES ;XCHG ES,DS + MOV BX,DS + MOV ES,BX + MOV DS,BP + MOV SI,OFFSET DOSGROUP:INBUF + MOV CL,DH + REP MOVSB ;Copy final line to user buffer + return ;All done + +;Output a CRLF + entry CRLF + MOV AL,c_CR + invoke OUT + MOV AL,c_LF + JMP OUT + +;Output a CRLF which is not terminate buffer +PHYCRLF: + invoke CRLF + JMP GETCH + +;Zap the line without zapping the template + entry KILNEW + MOV AL,"\" + invoke OUT ;Print the CANCEL indicator + POP SI ;Remember start of edit buffer +PUTNEW: + invoke CRLF ;Go to next line on screen + MOV AL,[STARTPOS] + invoke TAB ;Tab over + JMP NEWLIN ;Start over again + +;Back up one char + entry BACKSP + OR DH,DH + JZ OLDBAK ;No chars in line, do nothing to line + CALL BACKUP ;Do the backup + MOV AL,ES:[DI] ;Get the deleted char + CMP AL," " + JAE OLDBAK ;Was a normal char + CMP AL,c_HT + JZ BAKTAB ;Was a tab, fix up users display + CALL BACKMES ;Was a control char, zap the '^' +OLDBAK: + CMP BYTE PTR [INSMODE],0 + JNZ GETCH1 ;In insert mode, get more chars + OR BH,BH + JZ GETCH1 ;Not advanced in template, stay where we are + DEC BH ;Go back in template + DEC SI +GETCH1: + JMP GETCH + +BAKTAB: + PUSH DI + DEC DI ;Back up one char + STD ;Go backward + MOV CL,DH ;Number of chars currently in line + MOV AL," " + PUSH BX + MOV BL,7 ;Max + JCXZ FIGTAB ;At start, do nothing +FNDPOS: + SCASB ;Look back + JNA CHKCNT + CMP BYTE PTR ES:[DI+1],9 + JZ HAVTAB ;Found a tab + DEC BL ;Back one char if non tab control char +CHKCNT: + LOOP FNDPOS +FIGTAB: + SUB BL,[STARTPOS] +HAVTAB: + SUB BL,DH + ADD CL,BL + AND CL,7 ;CX has correct number to erase + CLD ;Back to normal + POP BX + POP DI + JZ OLDBAK ;Nothing to erase +TABBAK: + invoke BACKMES + LOOP TABBAK ;Erase correct number of chars + JMP SHORT OLDBAK + +BACKUP: + DEC DH ;Back up in line + DEC DI +BACKMES: + MOV AL,c_BS ;Backspace + invoke OUT + MOV AL," " ;Erase + invoke OUT + MOV AL,c_BS ;Backspace + JMP OUT ;Done + +;User really wants an ESC character in his line + entry TwoEsc + MOV AL,[ESCCHAR] + JMP SAVCH + +;Copy the rest of the template + entry COPYLIN + MOV CL,BL ;Total size of template + SUB CL,BH ;Minus position in template, is number to move + JMP SHORT COPYEACH + + entry CopyStr + invoke FINDOLD ;Find the char + JMP SHORT COPYEACH ;Copy up to it + +;Copy one char from template to line + entry COPYONE + MOV CL,1 +;Copy CX chars from template to line +COPYEACH: + MOV BYTE PTR [INSMODE],0 ;All copies turn off insert mode + CMP DH,DL + JZ GETCH2 ;At end of line, can't do anything + CMP BH,BL + JZ GETCH2 ;At end of template, can't do anything + LODSB + STOSB + invoke BUFOUT + INC BH ;Ahead in template + INC DH ;Ahead in line + LOOP COPYEACH +GETCH2: + JMP GETCH + +;Skip one char in template + entry SKIPONE + CMP BH,BL + JZ GETCH2 ;At end of template + INC BH ;Ahead in template + INC SI + JMP GETCH + + entry SKIPSTR + invoke FINDOLD ;Find out how far to go + ADD SI,CX ;Go there + ADD BH,CL + JMP GETCH + +;Get the next user char, and look ahead in template for a match +;CX indicates how many chars to skip to get there on output +;NOTE: WARNING: If the operation cannot be done, the return +; address is popped off and a jump to GETCH is taken. +; Make sure nothing extra on stack when this routine +; is called!!! (no PUSHes before calling it). +FINDOLD: + invoke $STD_CON_INPUT_NO_ECHO + CMP AL,[ESCCHAR] ; did he type a function key? + JNZ FindSetup ; no, set up for scan + invoke $STD_CON_INPUT_NO_ECHO ; eat next char + JMP NotFnd ; go try again +FindSetup: + MOV CL,BL + SUB CL,BH ;CX is number of chars to end of template + JZ NOTFND ;At end of template + DEC CX ;Cannot point past end, limit search + JZ NOTFND ;If only one char in template, forget it + PUSH ES + PUSH DS + POP ES + PUSH DI + MOV DI,SI ;Template to ES:DI + INC DI + REPNE SCASB ;Look + POP DI + POP ES + JNZ NOTFND ;Didn't find the char + NOT CL ;Turn how far to go into how far we went + ADD CL,BL ;Add size of template + SUB CL,BH ;Subtract current pos, result distance to skip + return + +NOTFND: + POP BP ;Chuck return address + JMP GETCH + + entry REEDIT + MOV AL,"@" ;Output re-edit character + invoke OUT + POP DI + PUSH DI + PUSH ES + PUSH DS + invoke COPYNEW ;Copy current line into template + POP DS + POP ES + POP SI + MOV BL,DH ;Size of line is new size template + JMP PUTNEW ;Start over again + + entry EXITINS + entry ENTERINS + NOT BYTE PTR [INSMODE] + JMP GETCH + +;Put a real live ^Z in the buffer (embedded) + entry CTRLZ + MOV AL,"Z"-"@" + JMP SAVCH +$STD_CON_STRING_INPUT ENDP diff --git a/SYS.ASM b/SYS.ASM new file mode 100644 index 0000000..e15758e --- /dev/null +++ b/SYS.ASM @@ -0,0 +1,587 @@ +TITLE MS-DOS SYS Program +; SYS - Copies system programs IBMBIO.COM/IO.SYS and IBMDOS.COM/MSDOS.SYS +; 1.6 05/21/82 Added rev number message +; 1.61 06/04/82 Allow SYS to blank disk TimP at SCP +; 1.70 06/30/82 NON contiguous DOS allowed on 2.00 IBM. Allows SYS to +; 1.0 1.1 disks. +; 1.71 07/02/82 Put in CHDIRs to make sure everything done in root dir. +; 1.80 04/26/83 MZ make sys work in small machines; use full 2.0 system +; calls +; 1.81 07/22/83 ARR Added check in IBM version for valid FAT ID on +; destination because of IBM problem with SYSing to +; unformatted disks which are really formatted. +; Prints NoDest message for ridic IBM reasons, should +; have a better message. + +FALSE EQU 0 +TRUE EQU NOT FALSE + +IBMJAPVER EQU FALSE +IBMVER EQU FALSE +MSVER EQU TRUE + +.xlist +.xcref + INCLUDE DOSSYM.ASM +.cref +.list + + +DOSVER_LOW EQU 0136H ; Lowest acceptable DOS version number +DOSVER_HIGH EQU 020BH ; Highest acceptable DOS version + +CODE SEGMENT WORD PUBLIC +CODE ENDS + +CONST SEGMENT BYTE PUBLIC +CONST ENDS + +DATA SEGMENT BYTE PUBLIC +DATA ENDS + +DG GROUP CODE,DATA,CONST + +DATA SEGMENT PUBLIC BYTE + + EXTRN BADDRV:BYTE, BADDRVLen:WORD + EXTRN BADPARM:BYTE, BADPARMLen:WORD + EXTRN GETSYS:BYTE, GETSYSLen:WORD + EXTRN SYSDRV:BYTE + EXTRN NODEST:BYTE, NODESTLen:WORD + EXTRN BADSIZ:BYTE, BADSIZLen:WORD + EXTRN DONE:BYTE, DONELen:WORD + EXTRN BADVER:BYTE + + IF IBMJAPVER + EXTRN BADDISK:BYTE, BADDISKLen:WORD + ENDIF + +DEFALT DB 0 + IF MSVER +BIOSName DB "A:\IO.SYS",0 +DOSName DB "A:\MSDOS.SYS",0 + ENDIF + IF IBMVER OR IBMJAPVER +BIOSName DB "A:\IBMBIO.COM",0 +DOSName DB "A:\IBMDOS.COM",0 + ENDIF + +BIOSInFH DW ? ; file handle of source BIOS +BIOSLenLow DW 2 DUP (?) ; 32-bit length of BIOS +BIOSLenHigh DW 2 DUP (?) ; 32-bit length of BIOS +BIOSTime DW 2 DUP (?) ; place to store time of BIOS write +BIOSOutFH DW ? ; fh of BIOS destination + +DOSInFH DW ? ; file handle of source DOS +DOSLenLow DW 2 DUP (?) ; 32-bit length of DOS +DOSLenHigh DW 2 DUP (?) ; 32-bit length of DOS +DOSTime DW 2 DUP (?) ; place to store time of DOS write +DOSOutFH DW ? ; fh of DOS destination + +AllName DB "A:\*.*",0 + +cbBuf DW ? ; number of bytes in buffer +pDOS DW ? ; offset of beginning of DOS in buffer +pDOSEnd DW ? ; offset of end of DOS in buffer + + IF IBMVER OR IBMJAPVER +BOOT DW 256 DUP (0) + IF IBMJAPVER +LLISTBUF DW 256 DUP (0) + ENDIF + ENDIF + + IF IBMJAPVER +RELOC DW 1 DUP(?) +STARTSECTOR DW 1 DUP(?) + ENDIF + +BUF LABEL BYTE ; beginning of area for file reads + +DATA ENDS + +CODE SEGMENT PUBLIC + + ASSUME CS:DG,DS:DG,ES:DG,SS:DG + + ORG 100H + +Start: + JMP SHORT CheckVersion + + IF IBMVER + DW OFFSET DG:BOOT + ENDIF +HEADER DB "Vers 1.81" +CheckVersion: + PUSH AX ; save drive letter validity + MOV AH,GET_VERSION + INT 21H ; get dos version + XCHG AH,AL ; Turn it around to AH.AL + CMP AX,DOSVER_LOW ; is it too low? + JB GOTBADDOS ; yes, error + CMP AX,DOSVER_HIGH ; too high? + JBE OKDOS ; yes, go check drive letter +GOTBADDOS: + MOV DX,OFFSET DG:BADVER ; message to dump + MOV AH,STD_CON_STRING_OUTPUT ; standard output device + INT 21H + INT 20H ; old style exit for compatability + +OKDOS: POP AX ; get drive validity + JMP SHORT SYS ; go process + +ERR0: MOV DX,OFFSET DG:BADPARM ; no drive letter + MOV CX,BadParmLen + JMP DisplayError + +ERR1: MOV DX,OFFSET DG:BADDRV ; drive letter invalid + MOV CX,BadDrvLen + JMP DisplayError + +ERR2: MOV AL,DEFALT ; get default drive number + ADD AL,'A'-1 ; turn into letter + MOV SYSDRV,AL ; place into middle of message + MOV DX,OFFSET DG:GETSYS + MOV CX,GETSYSLen ; length for output + MOV BX,stderr ; use stderr + MOV AH,Write ; Ask for system disk + INT 21H + CALL GetKeystroke ; wait for him to type simething + XOR AL,AL ; valid drive spec now... +SYS: + CMP DS:(BYTE PTR 5DH)," " ; Was file specified? + JNZ ERR0 ; yes, no files are allowed -> error + CMP AL,-1 ; Invalid drive spec? + JZ ERR1 ; yes, must have valid drive -> error + CMP DS:(BYTE PTR 5CH),0 ; No drive specified? + JZ ERR1 ; yes, cannot sys to default drive error + MOV AH,GET_DEFAULT_DRIVE ; Get default drive + INT 21H + INC AL ; turn from phys drive to logical drive + MOV DEFALT,AL ; save it for possible printing + CMP DS:(BYTE PTR 5CH),AL ; did he specify the default drive? + JZ ERR1 ; yes, default drive not allowed + + IF IBMVER ; Check for "valid" destination + PUSH AX + MOV AL,BYTE PTR DS:[5Ch] + DEC AL + MOV BX,OFFSET DG:BUF ; Temp space + MOV DX,1 ; Sector 1 (first sec of FAT) + MOV CX,DX ; One sector + INT 25H ; Read Fat sector + POP AX ; Flags + POP AX ; Real AX + JC OKFAT ; Don't error here, let a CREATE or + ; some other call to the dest + ; generate a more useful INT 24H + ; error + CMP BYTE PTR [BUF],0F8H + JAE OKFAT + JMP ERR3 +OKFAT: + ENDIF + + ADD AL,'A'-1 ; turn into letter + MOV BIOSName,AL ; twiddle source name + MOV DOSName,AL ; twiddle source name + CLD + MOV DX,OFFSET DG:BIOSName ; source name + MOV DI,OFFSET DG:BIOSInFH ; pointer to block of data + CALL OpenFile + JC Err2 ; not found, go and try again + MOV DX,OFFSET DG:DOSName ; source of DOS + MOV DI,OFFSET DG:DOSInFH ; pointer to block of data + CALL OpenFile ; Look for DOS + JC ERR2 ; not there, go ask for a system disk + MOV CX,SP ; get lowest available spot + SUB CX,0200h+(OFFSET DG:BUF); leave room for all sorts of things + MOV cbBuf,CX ; store length away + CALL FillMem ; load up memory with files + + IF IBMJAPVER + CALL READ_BOOT ; need to copy boot sector too + ENDIF + + MOV AL,DS:(BYTE PTR 5CH) ; get drive of destination + + IF IBMJAPVER + CALL CHECK_TRAN ; check for bootable device + JZ DOSWRT ; ok to boot + MOV DX,OFFSET DG:BADDISK ; incorrect format to boot + MOV CX,BadDiskLen + JMP DisplayError ; go error and quit +DOSWRT: + ENDIF + + ADD AL,'A'-1 ; convert to letter + MOV BIOSName,AL ; point names at destination drive + MOV DOSName,AL + MOV AllName,AL ; look for any files + + MOV AH,Find_First ; look for files + MOV DX,OFFSET DG:AllName ; path of where to look + MOV CX,Attr_Hidden+Attr_System ; attributes to find + INT 21H + JC PutSys ; no files - go and copy + + IF MSVER + MOV DL,DS:(BYTE PTR 5CH) ; get drive number + MOV AH,GET_DRIVE_FREESPACE ; get free space available + INT 21H + MUL CX ; Compute size of cluster (secsiz*secperclus) + XCHG CX,AX ; move it to correct spot + MOV DX,OFFSET DG:BIOSName ; who to open + MOV AX,BIOSLenLow+2 ; get low part of size + MOV BX,BIOSLenHigh+2 ; get high size + CALL CHKLEN ; open and snoop size + JNZ ERR4 ; Must fit exact so MSDOS is in right place + MOV DX,OFFSET DG:DOSName ; other guy to open + MOV AX,DOSLenLow+2 ; get low part of size + MOV BX,DOSLenHigh+2 ; get high size + CALL CHKLEN ; open and snoop second size + JA ERR4 ; Must be enough (or too much) space + ENDIF + + IF IBMVER OR IBMJAPVER + MOV DX,OFFSET DG:BIOSName ; open BIOS + MOV CX,7 ; attributes + MOV AH,Find_First + INT 21H + JNC FindDos +Err3J: JMP Err3 ; not found, go and complain +FindDos: + MOV DX,OFFSET DG:DOSName ; open DOS + MOV AH,Find_First + INT 21H + JC Err3J ; Not found, go complain + ENDIF + +PUTSYS: + MOV DX,OFFSET DG:BIOSName ; who to change mode + MOV CX,0 ; undo attributes + MOV AX,(ChMod SHL 8) + 1 ; set the attributes + INT 21h + MOV DX,OFFSET DG:DOSName ; who to change mode + MOV CX,0 ; undo attributes + MOV AX,(ChMod SHL 8) + 1 ; set the attributes + INT 21h + MOV DX,OFFSET DG:BIOSName ; destination of BIOS + MOV CX,7 ; fancy attributes + MOV AH,Creat ; make a new one + INT 21h + MOV BIOSOutFH,AX ; save handle + MOV DX,OFFSET DG:DOSName ; destination of DOS + MOV AH,Creat ; make a new one + INT 21h + MOV DOSOutFH,AX ; save handle +Copy: + CALL DumpMem ; flush out memory + MOV AX,DOSLenHigh ; more DOS? + OR AX,DOSLenLow ; more low dos + OR AX,BIOSLenHigh ; more high BIOS + OR AX,BIOSLenLow ; more low BIOS + JZ AllDone ; nope, all done + CALL FillMem ; reload world + JMP Copy +ERR4: + MOV DX,OFFSET DG:BADSIZ + MOV CX,BadSizLen + JMP DisplayError +AllDone: + MOV CX,BIOSTime ; get time and date + MOV DX,BIOSTime+2 + MOV BX,BIOSOutFH ; where to stuff the time + MOV AX,(File_Times SHL 8) + 1 + INT 21h + MOV AH,Close + INT 21h + + MOV CX,DOSTime ; get time and date + MOV DX,DOSTime+2 + MOV BX,DOSOutFH ; where to stuff the time + MOV AX,(File_Times SHL 8) + 1 + INT 21h + MOV AH,Close + INT 21h + + IF IBMVER OR IBMJAPVER + CALL PUTBOOT ; copy the boot sector also + ENDIF + + MOV DX,OFFSET DG:DONE ; all finished message + MOV CX,DoneLen + XOR AL,AL ; ok error code +SERROR: + PUSH AX + MOV BX,stderr + MOV AH,Write ; convenient place to display message + INT 21H + POP AX +ErrorExit: + MOV AH,EXIT ; bye and return error code + INT 21h + +DisplayError: + MOV AL,1 + JMP SERROR +FillMem: + MOV CX,cbBuf ; get length of buffer + MOV BX,BIOSInFH ; get bios source handle + MOV DX,OFFSET DG:BUF ; point to beginning of buffer + PUSH CX ; save away total length + CMP BIOSLenHigh,0 ; > 64K to read? + JA UseCX ; use CX + CMP BIOSLenLow,CX ; more left to read? + JA UseCX ; use CX + MOV CX,BIOSLenLow ; move new +UseCX: + MOV AH,Read + INT 21h ; read in what we can + ADD DX,AX ; update pointer for DOS Read + MOV pDOS,DX ; point to beginning of DOS + SUB BIOSLenLow,AX ; decrement remaining + SBB BIOSLenHigh,0 ; do 32 bit + POP CX ; get original length + SUB CX,AX ; this much is left + + MOV BX,DOSInFH ; get bios source handle + CMP DOSLenHigh,0 ; > 64K to read? + JA UseCXDOS ; use CX + CMP DOSLenLow,CX ; more left to read? + JA UseCXDOS ; use CX + MOV CX,DOSLenLow ; move new +UseCXDOS: + MOV AH,Read + INT 21h ; read in what we can + ADD DX,AX ; update pointer for DOS Read + MOV pDOSEnd,DX ; point to End of dos DOS + SUB DOSLenLow,AX ; decrement remaining + SBB DOSLenHigh,0 ; do 32 bit arithmetic + return + +OpenFile: + MOV AX,(OPEN SHL 8) + 0 ; open for reading only + INT 21H ; Look for BIOS + retc ; not found, go and try again + STOSW ; stash away handle + MOV BX,AX ; get ready for seeks + MOV AX,(LSeek SHL 8) + 2 ; seek relative to eof + XOR CX,CX ; zero offset + XOR DX,DX ; zero offset + INT 21h ; get offsets + STOSW ; save low part of size + STOSW ; save low part of size + MOV AX,DX + STOSW ; save high part of size + STOSW ; save high part of size + XOR DX,DX ; zero offset + MOV AX,(LSeek SHL 8) + 0 ; seek relative to beginning + INT 21h + MOV AX,(File_Times SHL 8) + 0 + INT 21h ; get last write times + MOV AX,CX + STOSW ; save time + MOV AX,DX + STOSW ; save date + return + +ERR3: + MOV DX,OFFSET DG:NODEST + MOV CX,NoDestLen + JMP DisplayError + +DumpMem: + MOV DX,OFFSET DG:BUF ; get offset of bios start + MOV CX,pDOS ; beginning of next guy + SUB CX,DX ; difference is length + JZ DumpDos ; no bios to move + MOV BX,BIOSOutFH ; where to output + MOV AH,Write + INT 21h ; wham +DumpDos: + MOV DX,pDOS ; beginning of dos + MOV CX,pDOSEnd ; end of dos + SUB CX,DX ; difference is length + retz ; if zero no write + MOV BX,DOSOutFH ; where to output + MOV AH,Write + INT 21h ; wham + ret + + IF MSVER +CHKLEN: +; CX has size of cluster, DX has pointer to file name +; Returns with flags set on (size of file) - (size of hole) + PUSH AX ; old size low + PUSH BX ; old size high + PUSH CX ; old cluster size + MOV AH,Find_First + MOV CX,7 ; attributes to search for + INT 21H + JC ERR3 ; cannot find file, error + POP CX ; get cluster size back + MOV DX,DS:[80h+find_buf_size_h] ; get destination size high + MOV AX,DS:[80h+find_buf_size_l] ; get size low + ADD AX,CX ; add cluster size + ADC DX,0 ; 32 bit add + SUB AX,1 ; adding CLUSSIZE-1 + SBB DX,0 ; 32 bit dec + DIV CX ; compute new cluster size + POP DX ; get old high + POP BX ; get old low + PUSH AX ; save away dividend + MOV AX,BX ; put into correct register + ADD AX,CX ; do the same as above (+CLUSSIZE-1)/CLUSSIZE + ADC DX,0 ; 32 bit add + SUB AX,1 ; adding CLUSSIZE-1 + SBB DX,0 ; 32 bit dec + DIV CX ; compute old cluster size + POP DX ; get new size + CMP AX,DX ; is old >= new? + return + ENDIF + + IF IBMJAPVER +PUTBOOT: + CALL READ_LLIST ; Get the list sector and set new boot sector + MOV AL,DS:(BYTE PTR 5CH) + DEC AL ; A=0 + MOV CX,1 + XOR DX,DX + MOV BX,OFFSET DG:BOOT + INT 26H ; Write out new boot sector + POPF + CALL WRITE_LLIST ; Make and write out new list sector + RET + ENDIF + + IF IBMVER +PUTBOOT: + MOV AH,GET_DPB + MOV DL,BYTE PTR DS:[5Ch] ; Target drive + INT 21H +ASSUME DS:NOTHING + MOV AL,[BX+16H] ; Media byte + PUSH CS + POP DS +ASSUME DS:DG + CMP AL,0FEH + JB RET1 + TEST AL,1 + JZ GOTBOOT + MOV BX,OFFSET DG:BOOT + MOV WORD PTR [BX+17],112 ; Set number of dir entries + MOV WORD PTR [BX+19],2*8*40 ; Set number of sectors + INC BYTE PTR [BX+21] ; Media = ff + INC WORD PTR [BX+26] ; Number of heads = 2 + +GOTBOOT: + MOV AL,BYTE PTR DS:[5Ch] + DEC AL + MOV BX,OFFSET DG:BOOT ; Boot sector + XOR DX,DX ; Sector 0 + MOV CX,DX + INC CX ; One sector + INT 26H ; Write out 8 sector boot sector + POP AX ; Flags +RET1: RET + ENDIF + + IF IBMJAPVER +READ_BOOT: + MOV AL,[DEFALT] + DEC AL ; A=0 + MOV CX,1 + XOR DX,DX + MOV BX,OFFSET DG:BOOT + INT 25H + POPF + MOV AX,[BOOT+108H] ; Get old first sector of data + MOV [RELOC],AX + RET + +READ_LLIST: + MOV AL,DS:(BYTE PTR 5CH) + DEC AL ; A=0 + MOV CX,1 + MOV DX,[STARTSECTOR] + MOV BX,OFFSET DG:LLISTBUF + INT 25H + POPF + RET + +WRITE_LLIST: + MOV AX,[STARTSECTOR] + MOV DX,AX + SUB AX,[RELOC] ; True reloc factor + MOV CL,BYTE PTR [LLISTBUF+0CH] ; Number of entries needing reloc + XOR CH,CH + JCXZ NO_RELOCS + MOV BX,OFFSET DG:LLISTBUF + 10H +RELLOOP: + ADD WORD PTR [BX+2],AX + ADD BX,10H + LOOP RELLOOP +NO_RELOCS: + MOV AL,DS:(BYTE PTR 5CH) + DEC AL ; A=0 + MOV CX,1 + MOV BX,OFFSET DG:LLISTBUF + INT 26H + POPF + RET + +CHECK_TRAN: +; All registers preserved. Returns zero if SYS OK, NZ if SYS FAIL +; AL is drive (1=A,...) AL=0 is not valid + + PUSH BX + PUSH AX + PUSH DS + MOV DL,AL + MOV AH,GET_DPB + INT 21H + MOV AX,[BX.dpb_first_sector] ; Get new first sector of data + MOV BH,[BX.dpb_media] + POP DS + MOV [STARTSECTOR],AX + MOV [BOOT+108H],AX ; Set new start of data in boot + POP AX + PUSH AX + MOV BL,AL + INT 11H ; IBM EQUIP CALL + ROL AL,1 + ROL AL,1 + AND AL,3 + JNZ NOT_SINGLE + INC AL +NOT_SINGLE: + INC AL ; AL is now MAX floppy # + CMP BL,AL + POP AX + JBE CHECK_FLOP ; Is a floppy + XOR BL,BL ; Is Hard file + POP BX + RET + +CHECK_FLOP: + CMP BH,0FBH ; Only floppy that boots + POP BX + RET + ENDIF + +GetKeystroke: + MOV AX,(Std_CON_Input_Flush SHL 8) + Std_CON_Input_No_Echo + INT 21H + MOV AX,(Std_CON_Input_Flush SHL 8) + 0 + INT 21H + + return + +CODE ENDS + END START + + + \ No newline at end of file diff --git a/SYSCALL.ASM b/SYSCALL.ASM new file mode 100644 index 0000000..e113df3 --- /dev/null +++ b/SYSCALL.ASM @@ -0,0 +1,749 @@ +; +; system call entry points MSDOS +; + +INCLUDE DOSSEG.ASM + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xlist +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + + + i_need YEAR,WORD + i_need DAY,BYTE + i_need WeekDay,BYTE + i_need TimeBuf,6 + i_need BCLOCK,DWORD + i_need DskErr,BYTE + i_need Attrib,BYTE + i_need Name1,BYTE + i_need Name2,BYTE + i_need Name3,BYTE + i_need DelAll,BYTE + i_need ThisDPB,DWORD + i_need CurBuf,DWORD + i_need LastEnt,WORD + i_need ThisDrv,BYTE + i_need DirStart,WORD + i_need DevPt,DWORD + i_need Creating,BYTE + i_need VolID,BYTE + i_need FoundDel,BYTE + +SUBTTL DATE AND TIME - SYSTEM CALLS 42,43,44,45; S/G DATE,TIME +PAGE + procedure $GET_DATE,NEAR ;System call 42 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; None +; Function: +; Return current date +; Returns: +; Date in CX:DX + + PUSH SS + POP DS +ASSUME DS:DOSGROUP + invoke READTIME ;Check for rollover to next day + MOV AX,[YEAR] + MOV BX,WORD PTR [DAY] + invoke get_user_stack ;Get pointer to user registers +ASSUME DS:NOTHING + MOV [SI.user_DX],BX ;DH=month, DL=day + ADD AX,1980 ;Put bias back + MOV [SI.user_CX],AX ;CX=year + MOV AL,BYTE PTR [WEEKDAY] + RET +$GET_DATE ENDP + + procedure $SET_DATE,NEAR ;System call 43 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; CX:DX valid date +; Function: +; Set current date +; Returns: +; AL = -1 date bad, = 0 OK + + MOV AL,-1 ;Be ready to flag error + SUB CX,1980 ;Fix bias in year + JC RET24 ;Error if not big enough + CMP CX,119 ;Year must be less than 2100 + JA RET24 + OR DH,DH + JZ RET24 + OR DL,DL + JZ RET24 ;Error if either month or day is 0 + CMP DH,12 ;Check against max. month + JA RET24 + PUSH SS + POP DS +ASSUME DS:DOSGROUP + invoke DODATE +RET24: RET +$SET_DATE ENDP + + procedure $GET_TIME,NEAR ;System call 44 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; None +; Function: +; Get current time +; Returns: +; Time in CX:DX + + PUSH SS + POP DS +ASSUME DS:DOSGROUP + invoke READTIME + invoke get_user_stack ;Get pointer to user registers + MOV [SI.user_DX],DX + MOV [SI.user_CX],CX + XOR AL,AL +RET26: RET +$GET_TIME ENDP + + procedure $SET_TIME,NEAR ;System call 45 +;Time is in CX:DX in hours, minutes, seconds, 1/100 sec. +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; CX:DX = Time +; Function: +; Set time +; Returns: +; AL = -1 time bad, = 0 OK + + MOV AL,-1 ;Flag in case of error + CMP CH,24 ;Check hours + JAE RET26 + CMP CL,60 ;Check minutes + JAE RET26 + CMP DH,60 ;Check seconds + JAE RET26 + CMP DL,100 ;Check 1/100's + JAE RET26 + PUSH CX + PUSH DX + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV BX,OFFSET DOSGROUP:TIMEBUF + MOV CX,6 + XOR DX,DX + MOV AX,DX + PUSH BX + invoke SETREAD +ASSUME ES:DOSGROUP + PUSH DS + LDS SI,[BCLOCK] +ASSUME DS:NOTHING + invoke DEVIOCALL2 ;Get correct day count + POP DS +ASSUME DS:DOSGROUP + POP BX + invoke SETWRITE + POP WORD PTR [TIMEBUF+4] + POP WORD PTR [TIMEBUF+2] + LDS SI,[BCLOCK] +ASSUME DS:NOTHING + invoke DEVIOCALL2 ;Set the time + XOR AL,AL + RET +$SET_TIME ENDP + +SUBTTL DISK R/W ROUTINES +PAGE + procedure $FCB_SEQ_READ,NEAR ; System call 20 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX Points to openned FCB +; Function: +; Read next record from file to disk transfer address +; Returns: +; AL = 1 EOF record is empty +; AL = 3 EOF record is partial zero filled +; AL = 2 No room at disk transfer address +; AL = 0 All OK + + invoke GETREC + invoke LOAD + JMP SHORT FINSEQ + + entry $FCB_SEQ_WRITE ; System call 21 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX Points to openned FCB +; Function: +; Write next record to file from disk transfer address +; Returns: +; AL = 1 Disk full +; AL = 2 No room in disk transfer segment +; AL = 0 All OK + + invoke GETREC + invoke STORE +FINSEQ: + JCXZ SETNREX + ADD AX,1 + ADC DX,0 + JMP SHORT SETNREX + + entry $FCB_RANDOM_READ ; System call 33 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX Points to openned FCB +; Function: +; Read record addressed by random record field from file to +; disk transfer address +; Returns: +; AL = 1 EOF record is empty +; AL = 3 EOF record is partial zero filled +; AL = 2 No room at disk transfer address +; AL = 0 All OK + + invoke GETRRPOS1 + invoke LOAD + JMP SHORT FINRND + + entry $FCB_RANDOM_WRITE ; System call 34 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX Points to openned FCB +; Function: +; Write record addressed by random record field to file from +; disk transfer address +; Returns: +; AL = 1 Disk full +; AL = 2 No room in disk transfer segment +; AL = 0 All OK + + invoke GETRRPOS1 + invoke STORE + JMP SHORT FINRND + + entry $FCB_RANDOM_READ_BLOCK ; System call 39 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX Points to openned FCB +; CX = Record count +; Function: +; Read CX records starting at random record field from file +; to disk transfer address +; Returns: +; AL = 1 EOF record is empty +; AL = 3 EOF record is partial zero filled +; AL = 2 No room at disk transfer address +; AL = 0 All OK +; CX = Actual number of records read + + invoke GETRRPOS + invoke LOAD + JMP SHORT FINBLK + + entry $FCB_RANDOM_WRITE_BLOCK ; System call 40 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX Points to openned FCB +; CX = Record count +; Function: +; Write CX records starting at random record field to file +; from disk transfer address +; If CX = 0 File is set to length determined from random record field +; Returns: +; AL = 1 Disk full +; AL = 2 No room in disk transfer segment +; AL = 0 All OK +; CX = Actual number of records written + + invoke GETRRPOS + invoke STORE +FINBLK: + invoke get_user_stack + MOV [SI.user_CX],CX + entry FINNOSAV + JCXZ FINRND + ADD AX,1 + ADC DX,0 +FINRND: + MOV WORD PTR ES:[DI.fcb_RR],AX + MOV ES:[DI.fcb_RR+2],DL + OR DH,DH + JZ SETNREX + MOV ES:[DI.fcb_RR+3],DH ; Save 4 byte of RECPOS only if significant +SETNREX: + MOV CX,AX + AND AL,7FH + MOV ES:[DI.fcb_NR],AL + AND CL,80H + SHL CX,1 + RCL DX,1 + MOV AL,CH + MOV AH,DL + MOV ES:[DI.fcb_EXTENT],AX + MOV AL,BYTE PTR [DSKERR] +RET4: + RET +$FCB_SEQ_READ ENDP + +SUBTTL $FCB_DELETE -- SYSTEM CALL 19 +PAGE + procedure $FCB_DELETE,NEAR ; System call 19 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX point to unopened FCB +; Function: +; Delete all matching entries +; Returns: +; AL = -1 if no entries matched, otherwise 0 + + invoke MOVNAME +ASSUME ES:DOSGROUP + MOV AL,-1 + MOV BYTE PTR [FoundDel],AL + JC RET4 + MOV AL,BYTE PTR [ATTRIB] + AND AL,attr_hidden+attr_system+attr_directory+attr_volume_id+attr_read_only + ; Look only at hidden bits + CMP AL,attr_hidden+attr_system+attr_directory+attr_volume_id+attr_read_only + ; All must be set + JNZ NOTALL + MOV CX,11 + MOV AL,"?" + MOV DI,OFFSET DOSGROUP:NAME1 + REPE SCASB ; See if name is *.* + JNZ NOTALL + MOV BYTE PTR [DELALL],0 ; DEL *.* - flag deleting all +NOTALL: + invoke FINDNAME +ASSUME DS:DOSGROUP + MOV AL,-1 + JC RET4 + OR AH,AH ; Check if device name + JS RET4 ; Can't delete I/O devices +DELFILE: + LES BP,[THISDPB] + MOV AH,BYTE PTR [DELALL] + PUSH DS + LDS DI,[CURBUF] +ASSUME DS:NOTHING + TEST [Attrib],attr_read_only ; are we deleting RO files too? + JNZ DoDelete ; yes + TEST DS:[BX.dir_attr],attr_read_only + JZ DoDelete ; not read only + POP DS + JMP SHORT DelNxt +DoDelete: + MOV BYTE PTR [FoundDel],0 + MOV [DI.BUFDIRTY],1 + MOV BYTE PTR [BX],AH + MOV BX,[SI] + POP DS +ASSUME DS:DOSGROUP + OR BX,BX + JZ DELNXT + CMP BX,ES:[BP.dpb_max_cluster] + JA DELNXT + invoke RELEASE +DELNXT: + invoke GETENTRY ; Registers need to be reset + invoke NEXTENT + JNC DELFILE + CALL FLUSHRET1 + MOV AL,BYTE PTR [FoundDel] + RET + +$FCB_DELETE ENDP + +SUBTTL $FCB_RENAME -- SYSTEM CALL 23; RENAME FILES +PAGE +ERRETJ: JMP ERRET + + procedure $FCB_RENAME,NEAR ; System call 23 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX point to a modified FCB (DS:DX+11H points to destination +; name) +; Function: +; Rename all matching entries to indicated name +; Returns: +; AL = -1 if no entries matched, otherwise 0 + + invoke MOVNAME +ASSUME ES:DOSGROUP + JC ERRETJ + ADD SI,5 + MOV DI,OFFSET DOSGROUP:NAME2 + invoke LODNAME + JC ERRETJ ; Report error if second name invalid + invoke FINDNAME +ASSUME DS:DOSGROUP + JC ERRETJ + OR AH,AH ; Check if I/O device name + JS ERRETJ ; If so, can't rename it + MOV SI,OFFSET DOSGROUP:NAME1 + MOV DI,OFFSET DOSGROUP:NAME3 + MOV CX,13 + REP MOVSB ; Copy name to search for --include attribute byte +RENFIL: + MOV DI,OFFSET DOSGROUP:NAME1 + MOV SI,OFFSET DOSGROUP:NAME2 + MOV CX,11 +NEWNAM: + LODSB + CMP AL,"?" + JNZ NOCHG + PUSH DS + MOV DS,WORD PTR [CURBUF+2] + MOV AL,[BX] + POP DS +NOCHG: + STOSB + INC BX + LOOP NEWNAM + INC DI + MOV BYTE PTR [DI],attr_all ;Sets ATTRIB + ; Stop duplicates with any attributes + invoke DEVNAME ; Check if giving it a device name + JNC RENERR + XOR AX,AX + PUSH [LASTENT] + invoke FINDENTRY ; See if new name already exists + POP AX + JNC RENERR ; Error if found + LES BP,[THISDPB] + invoke GETENT ; Re-read matching entry + MOV DI,BX ; Leave BX,DX until call to NEXTENT + MOV ES,WORD PTR [CURBUF+2] + MOV SI,OFFSET DOSGROUP:NAME1 + MOV CX,11 + REP MOVSB ; Replace old name with new one + MOV DI,WORD PTR [CURBUF] + MOV ES:[DI.BUFDIRTY],1 ; Directory changed + PUSH SS + POP ES + MOV SI,OFFSET DOSGROUP:NAME3 + MOV DI,OFFSET DOSGROUP:NAME1 + MOV CX,13 ; Include attribute byte + REP MOVSB ; Copy name back into search buffer + invoke NEXTENT + JNC RENFIL + JMP FLUSHRET1 + +RENERR: + CALL FLUSHRET1 +ERRET: + MOV AL,-1 + RET +$FCB_RENAME ENDP + +SUBTTL $FCB_OPEN -- SYSTEM CALL 15; OPEN A FILE +PAGE + procedure $FCB_OPEN,NEAR ; System call 15 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX point to an unopened FCB +; Function: +; Open indicated file and fill in FCB +; Returns: +; AL = -1 if no entries matched, otherwise 0 +; FOR INTERNAL USE +; [CURBUF+2]:SI and [CURBUF+2]:BX Preserved + + invoke GETFILE +ASSUME DS:DOSGROUP,ES:NOTHING + + entry DOOPEN + +; Enter here to perform $FCB_OPEN on file already found +; in directory. AH=device ID number, DS=CS, BX points to directory +; entry in [CURBUF], SI points to First Cluster field, and +; ES:DI point to the FCB to be opened. This entry point +; is used by $FCB_CREATE. + JC ERRET + PUSH SI + PUSH AX ; Save I/O driver number + XOR AL,AL + OR AH,AH + JS OPENDEV + MOV AL,[THISDRV] + MOV DS,WORD PTR [CURBUF+2] +ASSUME DS:NOTHING + INC AX +OPENDEV: + STOSB + XOR AX,AX +IF ZEROEXT + ADD DI,11 + STOSW ; Zero low byte of extent field if ZERPEXT only +ELSE + ADD DI,12 ; Point to high half of CURRENT BLOCK field + STOSB ; Set it to zero (CP/M programs set low byte) +ENDIF + MOV AL,128 ; Default record size + STOSW ; Set record size + LODSW ; Get starting cluster + MOV DX,AX ; Save it for the moment + MOVSW ; Transfer size to FCB + MOVSW + MOV AX,[SI-8] ; Get date + STOSW ; Save date in FCB + MOV AX,[SI-10] ; Get time + STOSW ; Save it in FCB + POP AX ; Restore I/O driver number + POP SI + MOV AL,AH + OR AL,40H ; Not dirty + STOSB + JS SAVDEVPT ; If device, go save pointer to it + MOV AX,DX ; Restore starting cluster + STOSW ; first cluster + PUSH AX ; save cluster + XOR AX,AX + STOSW ; clus pos + POP AX ; last cluster + STOSB + MOV AL,AH + MOV AH,BYTE PTR [DIRSTART] + PUSH CX + MOV CL,4 + SHL AH,CL + OR AL,AH + STOSB + MOV AX,[DIRSTART] + MOV CL,4 + SHL AX,CL + POP CX + MOV AL,AH + STOSB +OPEN_RET: + XOR AX,AX + RET + +SAVDEVPT: +ASSUME DS:DOSGROUP + LDS AX,[DEVPT] +ASSUME DS:NOTHING + STOSW + MOV ES:[DI],DS + JMP SHORT OPEN_RET +$FCB_OPEN ENDP + +SUBTTL $FCB_CLOSE -- SYSTEM CALL 16; CLOSE FILE +PAGE + procedure $FCB_CLOSE,NEAR ; System call 16 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX point to an opened FCB +; Function: +; Close the indicated file +; Returns: +; AL = -1 if disk has been changed, otherwise 0 + + MOV DI,DX + CMP BYTE PTR [DI],-1 ; Check for extended FCB + JNZ NORMFCB3 + ADD DI,7 +NORMFCB3: + TEST [DI.fcb_DEVID],devid_file_clean+devid_device + ; Allow only dirty files + JNZ OKRET1 ; can't close I/O device or not written + invoke MOVNAMENOSET + JC BADCLOSE ; Bad file name + entry FCB_CLOSE_INNER + PUSH DX + PUSH DS + MOV SI,DX + MOV BX,[SI.fcb_LSTCLUS+1] + MOV CL,4 + SHR BX,CL + PUSH BX + PUSH SS + POP DS +ASSUME DS:DOSGROUP + invoke FATREAD + POP BX + invoke SETDIRSRCH + invoke FINDENTRY + POP ES + POP DI + JC BADCLOSE + LDS BX,[CURBUF] +ASSUME DS:NOTHING + + ; note that SI points to dir_first... + + OR BYTE PTR [SI-dir_first+dir_attr],attr_archive + MOV CX,ES:[DI.fcb_FIRCLUS] + MOV [SI-dir_first+dir_first],CX + MOV DX,ES:WORD PTR [DI.fcb_FILSIZ] + MOV [SI-dir_first+dir_size_l],DX + MOV DX,ES:WORD PTR [DI.fcb_FILSIZ+2] + MOV [SI-dir_first+dir_size_h],DX + MOV DX,ES:[DI.fcb_FDATE] + MOV [SI-dir_first+dir_date],DX + MOV DX,ES:[DI.fcb_FTIME] + MOV [SI-dir_first+dir_time],DX + MOV [BX.BUFDIRTY],1 + PUSH SS + POP DS +ASSUME DS:DOSGROUP +FLUSHRET1: + LES BP,[THISDPB] + MOV AL,ES:[BP.dpb_drive] + invoke FLUSHBUF +OKRET1: + XOR AL,AL + RET + +BADCLOSE: + MOV AL,-1 + RET +$FCB_CLOSE ENDP + +SUBTTL $FCB_CREATE -- SYSTEM CALL 22; MAKE AND OPEN A NEW FILE +PAGE + procedure $FCB_CREATE,NEAR ; System call 22 +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DX point to an unopened FCB +; Function: +; If file does not exist, create it and open it +; If file exists, free up its contents and open the file +; Returns: +; AL = -1 if file cannot be created, otherwise 0 + + invoke MOVNAME +ASSUME ES:DOSGROUP + JC ERRET3 + MOV DI,OFFSET DOSGROUP:NAME1 + MOV CX,11 + MOV AL,"?" + REPNE SCASB + JZ ERRET3 + MOV BYTE PTR [CREATING],-1 + PUSH DX + PUSH DS + invoke FINDNAME +ASSUME DS:DOSGROUP +NWENTY: + LES BP,[THISDPB] +ASSUME ES:NOTHING + JNC EXISTENT + invoke BUILDDIR + JC ERRPOP + invoke GETENT ; Point at that free entry + JMP SHORT FREESPOT +ERRPOP: + POP DS + POP DX +ASSUME DS:NOTHING +ERRET3: + JMP SHORT BADCLOSE + + entry NEWENTRY + POP DX ; Return address + POP ES ; ES + POP CX ; DI + PUSH DX + PUSH CX + PUSH ES + JMP NWENTY + +EXISTENT: +ASSUME DS:DOSGROUP + JNZ ERRPOP ; Error if attributes don't match + OR AH,AH ; Check if file is I/O device + JS OPENJMP ; If so, no action + PUSH DS + LDS DI,[CURBUF] +ASSUME DS:NOTHING + MOV CX,[SI] ; Get pointer to clusters + MOV SI,[DI.BUFSECNO] + POP DS +ASSUME DS:DOSGROUP + JCXZ FREESPOT + CMP CX,ES:[BP.dpb_max_cluster] + JA FREESPOT + SUB BX,DI + PUSH BX + PUSH SI ; Save sector number + MOV BX,CX + invoke RELEASE ; Free any data already allocated + POP DX + XOR AL,AL + invoke GETBUFFR + POP BX + ADD BX,WORD PTR [CURBUF] +FREESPOT: + TEST BYTE PTR [ATTRIB],attr_volume_id + JZ NOTVOLID + CMP BYTE PTR [VOLID],0 + JNZ ERRPOP ; Can't create a second volume ID +NOTVOLID: + MOV ES,WORD PTR [CURBUF+2] + MOV DI,BX + MOV SI,OFFSET DOSGROUP:NAME1 + MOV CX,5 + MOVSB + REP MOVSW + MOV AL,[ATTRIB] + STOSB + MOV CL,5 + XOR AX,AX + REP STOSW + invoke DATE16 + XCHG AX,DX + STOSW + XCHG AX,DX + STOSW + XOR AX,AX + PUSH DI + STOSW + STOSW + STOSW + MOV SI,WORD PTR [CURBUF] + MOV ES:[SI.BUFDIRTY],1 + LES BP,[THISDPB] + MOV AL,ES:[BP.dpb_drive] + PUSH AX + PUSH BX + invoke FLUSHBUF + POP BX + POP AX + POP SI + MOV AH,AL ; Get I/O driver number back +OPENJMP: + CLC ; Clear carry so OPEN won't fail + POP ES + POP DI +ASSUME ES:NOTHING + JMP DOOPEN +$FCB_CREATE ENDP + +do_ext + +CODE ENDS + END + + \ No newline at end of file diff --git a/SYSIMES.ASM b/SYSIMES.ASM new file mode 100644 index 0000000000000000000000000000000000000000..1ff4f0d9cb2ecaa09e4ffe64b739b62ba2772883 GIT binary patch literal 512 zcmWHJ4EFT%3<-91R{(=xS9f1mzYv9hP$wTxX9cIo5LX5D;K<+*SKoM$LUmp)UM{do z1qGNQ1t&)r{{UYd=O7<9UmYh$mtfB*5ar_nBAxwxb%G;lhm7D23(~r6%X6=Vex@a4g_8Vyg`C8q^i+_^X_+~x3MxuaH~F|=n5*QJn4*whq>!6g zT%4Jgj!^6D?~AZT$r + ENDIF + +COUNT DW 0000 +CHRPTR DW 0000 + +BUFPTR LABEL DWORD ; LEAVE THIS STUFF IN ORDER! +MEMLO DW 0 +PRMBLK LABEL WORD +MEMHI DW 0 +LDOFF DW 0 +AREA DW 0 + +PACKET DB 22 + DB 0 + DB 0 ; INITIALIZE CODE + DW 0 + DB 8 DUP (?) +UNITCOUNT DB 0 +BREAK_ADDR DD 0 +BPB_ADDR DD 0 + +GOINIT: + CLD + XOR SI,SI + MOV DI,SI + + IF MSVER + MOV CX,[MEMORY_SIZE] + CMP CX,1 + JNZ NOSCAN + MOV CX,2048 ; START SCANNING AT 32K BOUNDARY + XOR BX,BX + +MEMSCAN:INC CX + JZ SETEND + MOV DS,CX + MOV AL,[BX] + NOT AL + MOV [BX],AL + CMP AL,[BX] + NOT AL + MOV [BX],AL + JZ MEMSCAN +SETEND: + MOV [MEMORY_SIZE],CX + ENDIF + + IF IBMVER OR IBMJAPVER + MOV CX,[MEMORY_SIZE] + ENDIF + +NOSCAN: + MOV AX,CS + MOV DS,AX +ASSUME DS:SYSINITSEG + + IF HIGHMEM + SUB CX,(DOSSIZE / 16) ; Leave room for DOS + SUB CX,CS:[DPBBUF_SIZ] ; Allow OEM to tune + ENDIF + + MOV AX,OFFSET SYSSIZE + 15 + SHR AX,1 ; Divide by 16 for paras + SHR AX,1 + SHR AX,1 + SHR AX,1 + SUB CX,AX + MOV ES,CX + MOV CX,OFFSET SYSSIZE + 1 + SHR CX,1 ; Divide by 2 to get words + REP MOVSW ; RELOCATE SYSINIT + + ASSUME ES:SYSINITSEG + + PUSH ES + MOV AX,OFFSET SYSIN + PUSH AX + +AAA PROC FAR + RET +AAA ENDP +; +; MOVE THE DOS TO ITS PROPER LOCATION +; +SYSIN: + + ASSUME DS:NOTHING,ES:SYSINITSEG,SS:NOTHING + + MOV AX,[CURRENT_DOS_LOCATION] + MOV DS,AX + MOV AX,[FINAL_DOS_LOCATION] + MOV ES,AX + + ASSUME ES:NOTHING + + XOR SI,SI + MOV DI,SI + MOV CX,DOSSIZE/2 + REP MOVSW + + LDS SI,[DEVICE_LIST] + MOV DX,[MEMORY_SIZE] + + CLI + MOV AX,CS + MOV SS,AX + MOV SP,OFFSET LOCSTACK + + ASSUME SS:SYSINITSEG + + IF NOT ALTVECT + STI ; Leave INTs disabled for ALTVECT + ENDIF +LOCSTACK LABEL BYTE + + CALL MSDOS + MOV WORD PTR [DOSINFO+2],ES ; SAVE POINTER TO DOS INFO + MOV WORD PTR [DOSINFO],DI + + IF NOT IBM + IF NOT IBMJAPVER + CALL RE_INIT ; Re-call the BIOS + ENDIF + ENDIF + + STI + CLD + + IF HIGHMEM + PUSH DS + MOV BX,DS + ADD BX,10H + MOV ES,BX + PUSH CS + POP DS + XOR SI,SI + MOV DI,SI + MOV CX,OFFSET SYSSIZE + 1 + SHR CX,1 ; Divide by 2 to get words + REP MOVSW + POP DS + PUSH ES + MOV AX,OFFSET SECONDRELOC + PUSH AX +BBB PROC FAR + RET +BBB ENDP + +SECONDRELOC: + MOV AX,CS + CLI + MOV SS,AX + MOV SP,OFFSET LOCSTACK + STI + ELSE + MOV BX,CS + SUB BX,10H + MOV ES,BX + XOR SI,SI + MOV DI,SI + MOV CX,80H + REP MOVSW + MOV AH,SET_CURRENT_PDB + INT 21H + ENDIF + + PUSH DS + PUSH CS + POP DS + MOV DX,OFFSET INT24 ; SET UP INT 24 HANDLER + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H + INT 21H + + IF ALTVECT + MOV DX,OFFSET BOOTMES + CALL PRINT ; Print message DOSINIT couldn't + ENDIF + + POP DS + + MOV DL,[DEFAULT_DRIVE] + OR DL,DL + JZ NODRVSET + DEC DL ; A = 0 + MOV AH,SET_DEFAULT_DRIVE + INT 21H ; SELECT THE DISK +NODRVSET: + + CALL DOCONF ; DO THE CONFIG STUFF + + IF HIGHMEM + PUSH DS + MOV AX,OFFSET SYSSIZE + 15 + MOV CL,4 + SHR AX,CL ; Divide by 16 to get para + MOV CX,ES + SUB CX,AX + MOV ES,CX + PUSH CS + POP DS + XOR SI,SI + MOV DI,SI + MOV CX,OFFSET SYSSIZE + 1 + SHR CX,1 ; Divide by 2 to get words + REP MOVSW + POP DS + PUSH ES + MOV AX,OFFSET THIRDRELOC + PUSH AX +CCC PROC FAR + RET +CCC ENDP + +THIRDRELOC: + MOV AX,CS + CLI + MOV SS,AX + MOV SP,OFFSET LOCSTACK + STI + ENDIF + + IF NOEXEC + MOV BP,DS ; SAVE COMMAND.COM SEGMENT + + PUSH DS + POP ES + + MOV BX,CS + SUB BX,10H + MOV DS,BX + XOR SI,SI + MOV DI,SI + MOV CX,80H + REP MOVSW + MOV BX,ES + MOV AH,SET_CURRENT_PDB + INT 21H + + MOV ES:[PDB_PARENT_PID],ES ; WE ARE THE ROOT + ENDIF + + PUSH CS + POP DS +ASSUME DS:SYSINITSEG + MOV AL,[FILES] + CBW + MOV CX,AX + XOR BX,BX ; Close standard input + MOV AH,CLOSE + INT 21H + MOV BX,2 +RCCLLOOP: ; Close everybody but standard output + MOV AH,CLOSE + INT 21H + INC BX + LOOP RCCLLOOP + + MOV DX,OFFSET CONDEV + MOV AL,2 + MOV AH,OPEN ; OPEN CON FOR READ/WRITE + STC + INT 21H + JNC GOAUX + CALL BADFIL + JMP SHORT GOAUX2 + +GOAUX: PUSH AX + MOV BX,1 ; close standard output + MOV AH,CLOSE + INT 21H + POP AX + + MOV BX,AX ; New device handle + MOV AH,XDUP + INT 21H ; Dup to 1, STDOUT + MOV AH,XDUP + INT 21H ; Dup to 2, STDERR + +GOAUX2: MOV DX,OFFSET AUXDEV + MOV AL,2 ; READ/WRITE ACCESS + CALL OPEN_DEV + + MOV DX,OFFSET PRNDEV + MOV AL,1 ; WRITE ONLY + CALL OPEN_DEV +; +; SET UP THE PARAMETERS FOR COMMAND +; +GOSET: + MOV SI,OFFSET COMMAND_LINE+1 + + IF NOEXEC + MOV DI,81H + ELSE + PUSH DS + POP ES + MOV DI,SI + ENDIF + + MOV CL,-1 +COMTRANLP: ; FIND LENGTH OF COMMAND LINE + INC CL + LODSB + STOSB ; COPY COMMAND LINE IN + OR AL,AL + JNZ COMTRANLP + DEC DI + MOV AL,0DH + STOSB + + IF NOEXEC + MOV ES:[80H],CL + MOV AL,[DEFAULT_DRIVE] + MOV ES:[5CH],AL + ELSE + MOV [COMMAND_LINE],CL ; Count + ENDIF + + PUSH CS + POP ES + + ASSUME ES:SYSINITSEG + + MOV DX,OFFSET COMMND ; NOW POINTING TO FILE DESCRIPTION + + IF NOEXEC + MOV ES,BP ; SET LOAD ADDRESS + MOV BX,100H + CALL LDFIL ; READ IN COMMAND + JC COMERR + MOV DS,BP + CLI + MOV DX,80H + MOV SS,BP + MOV SP,DX + STI + + XOR AX,AX ; PUSH A WORD OF ZEROS + PUSH AX + MOV AH,SET_DMA ; SET DISK TRANFER ADDRESS + INT 21H + PUSH BP ; SET HIGH PART OF JUMP ADDRESS + MOV AX,100H + PUSH AX ; SET LOW PART OF JUMP ADDRESS +CCC PROC FAR + RET ; CRANK UP COMMAND! +CCC ENDP + + ELSE + MOV BX,OFFSET COMEXE + MOV WORD PTR [BX.EXEC0_COM_LINE+2],CS + MOV WORD PTR [BX.EXEC0_5C_FCB+2],CS + MOV WORD PTR [BX.EXEC0_6C_FCB+2],CS + + XOR AX,AX + MOV AH,EXEC + STC ; IN CASE OF INT 24 + INT 21H ; GO START UP COMMAND + ENDIF + +COMERR: + MOV DX,OFFSET BADCOM ; WANT TO PRINT COMMAND ERROR + CALL BADFIL +STALL: JMP STALL + +DOCONF: + PUSH CS + POP DS + + ASSUME DS:SYSINITSEG + + MOV BX,0FFFFH + MOV AH,ALLOC + INT 21H ; FIRST TIME FAILS + MOV AH,ALLOC + INT 21H ; SECOND TIME GETS IT + MOV [AREA],AX + + IF HIGHMEM + ADD AX,BX + ENDIF + + MOV [MEMHI],AX + + MOV AX,(CHAR_OPER SHL 8) ; GET SWITCH CHARACTER + INT 21H + MOV [COMMAND_LINE+1],DL + + MOV DX,OFFSET CONFIG ; NOW POINTING TO FILE DESCRIPTION + MOV AX,OPEN SHL 8 ; OPEN FILE "CONFIG.SYS" + STC ; IN CASE OF INT 24 + INT 21H ; FUNCTION REQUEST + JC ENDFILE + JMP NOPROB ; PROBLEM WITH OPEN + +ENDFILE: + PUSH CS + POP DS + CALL ROUND + MOV AL,[FILES] + SUB AL,5 + JBE DOBUFF + CBW + + IF HIGHMEM + PUSH AX + MOV BL,SIZE SF_ENTRY + MUL BL + ADD AX,15+6 + MOV CL,4 + SHR AX,CL + SUB [MEMHI],AX + POP AX + ENDIF + + MOV BX,[MEMLO] + MOV DX,[MEMHI] + LDS DI,[DOSINFO] ; GET POINTER TO DOS DATA + LDS DI,[DI+SFT_ADDR] ; DS:BP POINTS TO SFT + MOV WORD PTR [DI+SFT_LINK],BX + MOV WORD PTR [DI+SFT_LINK+2],DX ; SET POINTER TO NEW SFT + PUSH CS + POP DS + LES DI,DWORD PTR [MEMLO] ; POINT TO NEW SFT + MOV WORD PTR ES:[DI+SFT_LINK],-1 + MOV ES:[DI+SFT_COUNT],AX + MOV BL,SIZE SF_ENTRY + MUL BL ; AX = NUMBER OF BYTES TO CLEAR + MOV CX,AX + + IF HIGHMEM + MOV AX,6 + ELSE + ADD [MEMLO],AX ; ALLOCATE MEMORY + MOV AX,6 + ADD [MEMLO],AX ; REMEMBER THE HEADER TOO + ENDIF + + ADD DI,AX + XOR AX,AX + REP STOSB ; CLEAN OUT THE STUFF + +DOBUFF: CALL ROUND + + DEC [BUFFERS] + JZ BUF1 + + PUSH DS + LES DI,BUFPTR + LDS BX,DOSINFO + + IF HIGHMEM + MOV AX,[BX.MAXSEC] + ADD AX,BUFINSIZ + 15 + MOV CL,4 + SHR AX,CL + SUB CS:[MEMHI],AX + MOV ES,CS:[MEMHI] + ENDIF + + MOV AX,WORD PTR [BX.BUFFHEAD] + MOV WORD PTR ES:[DI.NEXTBUF],AX + MOV AX,WORD PTR [BX.BUFFHEAD+2] + MOV WORD PTR ES:[DI.NEXTBUF+2],AX + + MOV WORD PTR [BX.BUFFHEAD],DI + MOV WORD PTR [BX.BUFFHEAD+2],ES + + MOV WORD PTR ES:[DI.BUFDRV],00FFH ; NEW BUFFER FREE + MOV BX,[BX.MAXSEC] + POP DS + + IF NOT HIGHMEM + ADD BX,BUFINSIZ + ADD [MEMLO],BX + ENDIF + + JMP DOBUFF + +BUF1: CALL ROUND + MOV BX,[MEMHI] + MOV AX,[AREA] + MOV ES,AX ; CALC WHAT WE NEEDED + SUB BX,AX + + IF HIGHMEM + DEC BX ; Arena + PUSH BX + ENDIF + + MOV AH,SETBLOCK + INT 21H ; GIVE THE REST BACK + + IF NOT HIGHMEM + PUSH ES + MOV AX,ES + DEC AX + MOV ES,AX + MOV ES:[arena_owner],8 ; Set impossible owner + POP ES + ENDIF + + IF HIGHMEM + MOV BX,0FFFFH + MOV AH,ALLOC + INT 21H + MOV AH,ALLOC + INT 21H + + PUSH ES + DEC AX + MOV ES,AX + MOV ES:[arena_owner],8 ; Set impossible owner + POP ES + + IF NOT NOEXEC + MOV ES,[AREA] + MOV AH,DEALLOC + INT 21H + ENDIF + + POP BX + MOV AX,[AREA] + MOV DS,AX + ADD AX,BX + MOV ES,AX + ELSE + IF NOEXEC + MOV BX,0FFFFH ; ALLOCATE THE REST OF MEM FOR COMMAND + MOV AH,ALLOC + INT 21H + MOV AH,ALLOC + INT 21H + MOV DS,AX + ENDIF + ENDIF + + RET + +BADOP: MOV DX,OFFSET BADOPM ; WANT TO PRINT COMMAND ERROR + CALL PRINT + JMP COFF + +NOPROB: ; GET FILE SIZE (NOTE < 64K!!) + MOV BX,AX + XOR CX,CX + XOR DX,DX + MOV AX,(LSEEK SHL 8) OR 2 + INT 21H + MOV [COUNT],AX + XOR DX,DX + MOV AX,LSEEK SHL 8 ; Reset pointer to beginning of file + INT 21H + MOV DX,CS + + IF HIGHMEM + MOV AX,OFFSET SYSSIZE + 15 + MOV CL,4 + SHR AX,CL + ADD DX,AX + ELSE + MOV AX,[COUNT] + ADD AX,15 + MOV CL,4 + SHR AX,CL ; NUMBER OF SEGMENTS + SUB DX,AX + SUB DX,11H ; ROOM FOR HEADER + ENDIF + + MOV DS,DX + MOV ES,DX +ASSUME DS:NOTHING,ES:NOTHING + XOR DX,DX + MOV CX,[COUNT] + MOV AH,READ + STC ; IN CASE OF INT 24 + INT 21H ; Function request + PUSHF + PUSH CS + POP DS +ASSUME DS:SYSINITSEG + PUSH AX + MOV AH,CLOSE + INT 21H + POP AX + POPF + JC CONFERR ; IF NOT WE'VE GOT A PROBLEM + CMP CX,AX + JZ GETCOM ; COULDN'T READ THE FILE +CONFERR: + MOV DX,OFFSET CONFIG ; WANT TO PRINT CONFIG ERROR + CALL BADFIL +ENDFILV:JMP ENDFILE + +GETCOM: + CALL ORGANIZE ; ORGANIZE THE FILE + CALL GETCHR + +CONFLP: JC ENDFILV + MOV AH,AL + CALL GETCHR + + CMP AH,'B' ; BUFFER COMMAND? + JNZ TRYC + CALL GETNUM + JZ COFF + CMP AX,100 + JAE badop + MOV [BUFFERS],AL + JMP SHORT COFF + +TRYC: CMP AH,'C' + JZ GOTC + JMP TRYD +GOTC: + CMP AL,'O' ; FIRST LETTER OF "ON" + JNZ COFF + CALL GETCHR + JC ENDFILV + CMP AL,'N' ; SECOND LETTER OF "ON" + JNZ COFF + MOV AH,SET_CTRL_C_TRAPPING ; TURN ON CONTROL-C CHECK + MOV AL,1 + MOV DL,AL + INT 21H + +COFF: PUSH CS + POP DS + CALL NEWLINE + JMP CONFLP + +TRYD: CMP AH,'D' + JZ GOTD + JMP TRYF +GOTD: MOV BX,CS + MOV DS,BX + + MOV WORD PTR [BPB_ADDR],SI + MOV WORD PTR [BPB_ADDR+2],ES + + CALL ROUND + + IF HIGHMEM + PUSH DS + PUSH ES + POP DS + MOV DX,SI + MOV AX,OPEN SHL 8 + STC ; In case INT 24H + INT 21H + POP DS + JC BADBRK + MOV BX,AX + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 2 + INT 21H + PUSH AX + MOV AH,CLOSE + INT 21H + POP AX ; DX:AX is size of file + ADD AX,15 + ADC DX,0 + MOV CL,4 + SHR AX,CL + MOV CL,12 + SHL DX,CL + OR AX,DX ; AX is size in PARA + MOV CX,[MEMHI] + SUB [MEMHI],AX + JNC SIZEOK + MOV [MEMHI],CX ; Not enough memory + JMP SHORT BADBRK +SIZEOK: + MOV BX,CS + ENDIF + + XOR AX,AX + MOV WORD PTR [ENTRY_POINT],AX + MOV AX,[MEMHI] + MOV WORD PTR [ENTRY_POINT+2],AX ; SET ENTRY POINT + + + IF NOT NOEXEC + MOV [LDOFF],AX ; SET LOAD OFFSET + ENDIF + + PUSH ES + POP DS + MOV DX,SI ; DS:DX POINTS TO FILE NAME + + IF NOEXEC + LES BX,DWORD PTR CS:[MEMLO] + CALL LDFIL ; LOAD IN THE DEVICE DRIVER + ELSE + MOV ES,BX + MOV BX,OFFSET PRMBLK ; ES:BX POINTS TO PARAMETERS + MOV AL,3 + MOV AH,EXEC + STC ; IN CASE OF INT 24 + INT 21H ; LOAD IN THE DEVICE DRIVER + ENDIF + + PUSH DS + POP ES ; ES:SI BACK TO CONFIG.SYS + PUSH CS + POP DS ; DS BACK TO SYSINIT + JNC GOODLD +BADBRK: CALL BADLOAD + JMP COFF + +GOODLD: PUSH ES ; INITIALIZE THE DEVICE + PUSH SI + + PUSH CS + POP ES + MOV BX,SDEVSTRAT + CALL CALLDEV + MOV BX,SDEVINT + CALL CALLDEV + + PUSH CS + POP DS + + IF NOT HIGHMEM + MOV AX,WORD PTR [BREAK_ADDR+2] ; REMOVE THE INIT CODE + CMP AX,[MEMORY_SIZE] + JB BREAKOK + POP SI + POP ES + JMP BADBRK +BREAKOK: + + MOV [MEMHI],AX + MOV AX,WORD PTR [BREAK_ADDR]; REMOVE THE INIT CODE + MOV [MEMLO],AX + ENDIF + + LDS DX,[ENTRY_POINT] ; SET DS:DX TO HEADER + MOV SI,DX + ADD SI,SDEVATT ; DS:SI POINTS TO ATTRIBUTES + LES DI,CS:[DOSINFO] ; ES:DI POINT TO DOS INFO + MOV AX,DS:[SI] ; GET ATTRIBUTES + TEST AX,DEVTYP ; TEST IF BLOCK DEV + JZ ISBLOCK + + TEST AX,ISCIN ; IS IT A CONSOLE IN? + JZ TRYCLK + MOV WORD PTR ES:[DI.BCON],DX + MOV WORD PTR ES:[DI.BCON+2],DS + +TRYCLK: TEST AX,ISCLOCK ; IS IT A CLOCK DEVICE? + JZ GOLINK + MOV WORD PTR ES:[DI+BCLOCK],DX + MOV WORD PTR ES:[DI+BCLOCK+2],DS +GOLINK: JMP LINKIT + +ISBLOCK: + MOV AL,CS:[UNITCOUNT] ; IF NO UNITS FOUND.... + OR AL,AL + JNZ PERDRV + + IF NOT HIGHMEM + MOV CS:[MEMLO],0 ; ...ERASE THE DEVICE + ENDIF + + MOV AX,-1 + JMP ENDDEV + +PERDRV: + CBW + MOV CX,AX + MOV DH,AH + MOV DL,ES:[DI.NUMIO] ; GET NUMBER OF DEVICES + ADD ES:[DI.NUMIO],AL ; UPDATE THE AMOUNT + + LDS BX,CS:[BPB_ADDR] ; POINT TO BPB ARRAY +PERUNIT: + LES BP,CS:[DOSINFO] + LES BP,DWORD PTR ES:[BP.DPBHEAD]; GET FIRST DPB + +SCANDPB:CMP WORD PTR ES:[BP.DPB_NEXT_DPB],-1 + JZ FOUNDPB + LES BP,ES:[BP.DPB_NEXT_DPB] + JMP SCANDPB +FOUNDPB: + MOV AX,CS:[MEMLO] + MOV WORD PTR ES:[BP.DPB_NEXT_DPB],AX + + IF HIGHMEM + MOV AX,(DPBSIZ + 15) / 16 + SUB CS:[MEMHI],AX + ENDIF + + MOV AX,CS:[MEMHI] + MOV WORD PTR ES:[BP.DPB_NEXT_DPB+2],AX + LES BP,DWORD PTR CS:[MEMLO] + + IF NOT HIGHMEM + ADD WORD PTR CS:[MEMLO],DPBSIZ + ENDIF + + MOV WORD PTR ES:[BP.DPB_NEXT_DPB],-1 + MOV ES:[BP.DPB_FIRST_ACCESS],-1 + + MOV SI,[BX] ; DS:SI POINTS TO BPB + INC BX + INC BX ; POINT TO NEXT GUY + MOV WORD PTR ES:[BP.DPB_DRIVE],DX + MOV AH,SETDPB ; HIDDEN SYSTEM CALL + INT 21H + MOV AX,ES:[BP.DPB_SECTOR_SIZE] + PUSH ES + LES DI,CS:[DOSINFO] ; ES:DI POINT TO DOS INFO + CMP AX,ES:[DI.MAXSEC] + POP ES + JBE NOTMAX + POP SI + POP ES + MOV DX,OFFSET BADSIZ_PRE + MOV BX,OFFSET BADSIZ_POST + CALL PRNERR + JMP COFF + +NOTMAX: PUSH DS + PUSH DX + LDS DX,CS:[ENTRY_POINT] + MOV WORD PTR ES:[BP.DPB_DRIVER_ADDR],DX + MOV WORD PTR ES:[BP.DPB_DRIVER_ADDR+2],DS + POP DX + POP DS + INC DX + INC DH + LOOP PERUNIT + +LINKIT: + LES DI,CS:[DOSINFO] ; ES:DI = DOS TABLE + MOV CX,WORD PTR ES:[DI.DEVHEAD] ; DX:CX = HEAD OF LIST + MOV DX,WORD PTR ES:[DI.DEVHEAD+2] + + LDS SI,CS:[ENTRY_POINT] ; DS:SI = DEVICE LOCATION + MOV WORD PTR ES:[DI.DEVHEAD],SI ; SET HEAD OF LIST IN DOS + MOV WORD PTR ES:[DI.DEVHEAD+2],DS + MOV AX,DS:[SI] ; GET POINTER TO NEXT DEVICE + MOV WORD PTR CS:[ENTRY_POINT],AX; AND SAVE IT + + MOV WORD PTR DS:[SI],CX ; LINK IN THE DRIVER + MOV WORD PTR DS:[SI+2],DX +ENDDEV: + POP SI + POP ES + INC AX ; AX = FFFF? + JZ COFFV + JMP GOODLD ; OTHERWISE PRETEND WE LOADED IT IN +COFFV: JMP COFF + +TRYQ: + CMP AH,'Q' + JNZ TRYW + CALL GETNUM + JZ COFFV + OR AH,AH + JNZ COFFV + MOV AH,INTERNATIONAL ; AL is country code + MOV DX,-1 ; Set country + INT 21H + JNC COFFV + MOV DX,OFFSET BADCOUNTRY + CALL PRINT + JMP COFFV + +TRYF: + CMP AH,'F' + JNZ TRYQ + CALL GETNUM + JZ COFFV + CMP AX,100 + JAE TryX + MOV [FILES],AL + JMP COFFV +TRYW: + CMP AH,'W' + JNZ TRYA + MOV DL,AL + MOV AX,(CHAR_OPER SHL 8) OR 1 ; SET SWITCH CHARACTER + MOV [COMMAND_LINE+1],DL + INT 21H + JMP COFF + +TRYA: + CMP AH,'A' + JNZ TRYS + CMP AL,'F' ; FIRST LETTER OF "FALSE" + JNZ COFFJ + MOV AX,(CHAR_OPER SHL 8) OR 3 ; TURN ON "/DEV" PREFIX + XOR DL,DL + INT 21H +COFFJ: JMP COFF + +TRYS: + CMP AH,'S' + JNZ TRYX + MOV [COMMAND_LINE+1],0 + MOV DI,OFFSET COMMND + 1 + MOV [DI-1],AL +STORESHELL: + CALL GETCHR + OR AL,AL + JZ GETSHPARMS + CMP AL," " + JB ENDSH + MOV [DI],AL + INC DI + JMP STORESHELL + +ENDSH: + MOV BYTE PTR [DI],0 + CALL GETCHR + CMP AL,10 + JNZ CONV + CALL GETCHR +CONV: JMP CONFLP + +TRYX: + JMP BADOP + +GETSHPARMS: + MOV BYTE PTR [DI],0 + MOV DI,OFFSET COMMAND_LINE+1 +PARMLOOP: + CALL GETCHR + CMP AL," " + JB ENDSH + MOV [DI],AL + INC DI + JMP PARMLOOP + +GETCHR: MOV CX,COUNT + JCXZ NOCHAR + MOV SI,CHRPTR + MOV AL,ES:[SI] + DEC COUNT + INC CHRPTR + CLC + RET +NOCHAR: STC + RET + +ORGANIZE: + MOV CX,[COUNT] + JCXZ NOCHAR + CALL MAPCASE + XOR SI,SI + MOV DI,SI + +ORG1: CALL GET ; SKIP LEADING CONTROL CHARACTERS + CMP AL,' ' + JB ORG1 + + PUSH CX + PUSH SI + PUSH DI + MOV BP,SI + DEC BP + MOV SI,OFFSET COMTAB ; Prepare to search command table + MOV CH,0 +FINDCOM: + MOV DI,BP + MOV CL,[SI] + INC SI + JCXZ NOCOM + REPE CMPSB + LAHF + ADD SI,CX ; Bump to next position without affecting flags + SAHF + LODSB ; Get indicator letter + JNZ FINDCOM + POP DI + POP SI + POP CX + JMP SHORT GOTCOM + +NOCOM: + POP DI + POP SI + POP CX + MOV AL,'Z' +GOTCOM: STOSB ; SAVE INDICATOR CHAR IN BUFFER + +ORG2: CALL GET2 ; SKIP NAME UNTIL DELIMETER + CALL DELIM ; + JNZ ORG2 + + CALL GET ; GET CHARS TO RIGHT OF EQUALS SIGN + STOSB + +ORG4: CALL GET2 + STOSB + CMP AL,' ' + JA ORG4 + CMP AL,10 + JZ ORG1 + + MOV BYTE PTR ES:[DI-1],0 +ORG5: CALL GET2 + STOSB + CMP AL,10 + JNZ ORG5 + JMP ORG1 + +GET2: + JCXZ NOGET + MOV AL,ES:[SI] + INC SI + DEC CX + RET + +GET: JCXZ NOGET + MOV AL,ES:[SI] + INC SI + DEC CX + CALL DELIM + JZ GET +GRET: RET + + +DELIM: CMP AL,' ' + JZ GRET + CMP AL,9 + JZ GRET + CMP AL,'=' + JZ GRET + CMP AL,',' + JZ GRET + CMP AL,';' + RET + + +NOGET: POP CX + MOV COUNT,DI + XOR SI,SI + MOV CHRPTR,SI + RET +; +; NEWLINE RETURNS WITH FIRST CHARACTER OF NEXT LINE +; +NEWLINE:CALL GETCHR ; SKIP NON-CONTROL CHARACTERS + JC NONEW + CMP AL,10 ; LOOK FOR LINE FEED + JNZ NEWLINE + CALL GETCHR +NONEW: RET + +MAPCASE: + PUSH CX + PUSH SI + PUSH DS + PUSH ES + POP DS + XOR SI,SI +CONVLOOP: + LODSB + + IF KANJI + CALL TESTKANJ + JZ NORMCONV + INC SI ; Skip next char + DEC CX + JCXZ CONVDONE ; Just ignore 1/2 kanji error +; Fall through, know AL is not in 'a'-'z' range +NORMCONV: + ENDIF + + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + SUB AL,20H + MOV [SI-1],AL +NOCONV: + LOOP CONVLOOP +CONVDONE: + POP DS + POP SI + POP CX + RET + + IF KANJI +TESTKANJ: + CMP AL,81H + JB NOTLEAD + CMP AL,9FH + JBE ISLEAD + CMP AL,0E0H + JB NOTLEAD + CMP AL,0FCH + JBE ISLEAD +NOTLEAD: + PUSH AX + XOR AX,AX ; Set zero + POP AX + RET + +ISLEAD: + PUSH AX + XOR AX,AX ; Set zero + INC AX ; Reset zero + POP AX + RET + ENDIF + +ASSUME DS:NOTHING + +ROUND: MOV AX,[MEMLO] + + IF NOT HIGHMEM + ADD AX,15 + ENDIF + + SHR AX,1 + SHR AX,1 + SHR AX,1 + SHR AX,1 + ADD [MEMHI],AX + XOR AX,AX + MOV [MEMLO],AX + RET + +CALLDEV:MOV DS,WORD PTR CS:[ENTRY_POINT+2] + ADD BX,WORD PTR CS:[ENTRY_POINT]; Do a little relocation + MOV AX,DS:[BX] + PUSH WORD PTR CS:[ENTRY_POINT] + MOV WORD PTR CS:[ENTRY_POINT],AX + MOV BX,OFFSET PACKET + CALL [ENTRY_POINT] + POP WORD PTR CS:[ENTRY_POINT] + RET + +BADNUM: POP AX ; POP RETURN ADDRESS + JMP BADOP + +ToDigit: + SUB AL,'0' + JB NotDig + CMP AL,9 + JA NotDig + CLC + RET +NotDig: STC + RET + +GETNUM: XOR BX,BX ; running count is zero +B2: CALL ToDigit ; do we have a digit + JC BadNum ; no, bomb + XCHG AX,BX ; put total in AX + PUSH BX ; save digit + MOV BX,10 ; base of arithmetic + MUL BX ; shift by one decimal digit + POP BX ; get back digit + ADD AL,BL ; get total + ADC AH,0 ; make that 16 bits + JC BADNUM ; too big a number + XCHG AX,BX ; stash total + CALL GETCHR ; GET NEXT DIGIT + JC B1 ; no more characters + OR AL,AL ; end of line separator? + JNZ B2 ; no, try as a valid character + INC COUNT ; one more character to scan + DEC CHRPTR ; back up over separator +B1: MOV AX,BX ; get proper count + OR AX,AX + RET +; +; ES:SI POINTS TO FILE NAME (NUL TERMINATED) +; DS:DX POINTS TO STRING TO OUTPUT IN FRONT OF NAME ($ TERM) +; +BADFIL: + PUSH CS + POP ES + MOV SI,DX +BADLOAD: + MOV DX,OFFSET BADLD_PRE ; WANT TO PRINT CONFIG ERROR + MOV BX,OFFSET BADLD_POST +PRNERR: + PUSH CS + POP DS + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +PRN1: MOV DL,ES:[SI] + OR DL,DL + JZ PRN2 + MOV AH,STD_CON_OUTPUT + INT 21H + INC SI + JMP PRN1 +PRN2: MOV DX,BX +PRINT: MOV AH,STD_CON_STRING_OUTPUT + INT 21H + RET +; +; LOAD FILE CALLED [DS:DX] AT MEMORY LOCATION ES:BX +; +LDFIL: + PUSH AX + PUSH BX + PUSH CX + PUSH DX + PUSH SI + PUSH DS + PUSH BX + + XOR AX,AX ; OPEN THE FILE + MOV AH,OPEN + STC ; IN CASE OF INT 24 + INT 21H + POP DX ; Trans addr is DS:DX + JC LDRET + + PUSH ES ; READ THE FILE IN + POP DS + MOV BX,AX ; Handle in BX + MOV CX,0FF00H + MOV AH,READ + STC ; IN CASE OF INT 24 + INT 21H + JC LDRET + MOV SI,DX ; CHECK FOR EXE FILE + CMP WORD PTR [SI],"ZM" + JNZ LDCLS +LDERR: STC + JMP SHORT LDRET + +LDCLS: MOV AH,CLOSE ; CLOSE THE FILE + STC + INT 21H + +LDRET: POP DS + POP SI + POP DX + POP CX + POP BX + POP AX + RET +; +; OPEN DEVICE POINTED TO BY DX, AL HAS ACCESS CODE +; IF UNABLE TO OPEN DO A DEVICE OPEN NULL DEVICE INSTEAD +; +OPEN_DEV: + CALL OPEN_FILE + JNC OPEN_DEV3 +OPEN_DEV1: + MOV DX,OFFSET NULDEV + CALL OPEN_FILE +OPEN_DEV2: + RET +OPEN_DEV3: + XOR AX,AX ; GET DEVICE INFO + MOV AH,IOCTL + INT 21H + TEST DL,10000000B + JNZ OPEN_DEV2 + MOV AH,CLOSE + INT 21H + JMP OPEN_DEV1 + +OPEN_FILE: + MOV AH,OPEN + STC + INT 21H + RET + +INT24: ADD SP,6 ; RESTORE MACHINE STATE + POP AX + POP BX + POP CX + POP DX + POP SI + POP DI + POP BP + POP DS + POP ES + PUSH AX + MOV AH,GET_DEFAULT_DRIVE ; INITIALIZE DOS + INT 21H + POP AX + IRET ; BACK TO USER + + IF ALTVECT +BOOTMES DB 13 +TEN: DB 10 + DB "MS-DOS version " + DB MAJOR_VERSION + "0" + DB "." + DB (MINOR_VERSION / 10) + "0" + DB (MINOR_VERSION MOD 10) + "0" + DB 13,10 + DB "Copyright 1981,82 Microsoft Corp.",13,10,"$" + ENDIF + +NULDEV DB "\DEV\NUL",0 +CONDEV DB "\DEV\CON",0 +AUXDEV DB "\DEV\AUX",0 +PRNDEV DB "\DEV\PRN",0 + +CONFIG DB "\CONFIG.SYS",0 + +COMMND DB "\COMMAND.COM",0 + +COMTAB LABEL BYTE + DB 7,"BUFFERS",'B' + DB 5,"BREAK",'C' + DB 5,"SHELL",'S' + DB 6,"DEVICE",'D' + DB 5,"FILES",'F' + DB 8,"SWITCHAR",'W' + DB 8,"AVAILDEV",'A' + DB 7,"COUNTRY",'Q' + DB 0 + + +SYSINITSEG ENDS + END + + + \ No newline at end of file diff --git a/SYSMES.ASM b/SYSMES.ASM new file mode 100644 index 0000000..3b72a53 --- /dev/null +++ b/SYSMES.ASM @@ -0,0 +1,51 @@ + TITLE Message file for MS-DOS SYS Program + +FALSE EQU 0 +TRUE EQU NOT FALSE + + INCLUDE DOSSYM.ASM + +Message MACRO label,text + PUBLIC label,label&Len +label DB text +label&Len DW $-label +ENDM + + +IBMJAPVER EQU FALSE + +CONST SEGMENT PUBLIC BYTE + +; only this message must be terminated with a $ + PUBLIC BadVer +BADVER DB "Incorrect DOS version",13,10,"$" + + IF IBMJAPVER + Message BadDisk,<"Destination disk cannot be booted"> + ENDIF + + Message BadDrv,<"Invalid drive specification"> + Message BadParm,<"Invalid parameter"> + Message NoDest,<"No room for system on destination disk"> + Message BadSiz,<"Incompatible system size"> + Message Done,<"System transferred"> + + PUBLIC GetSys,SysDrv,GetSysLen +GETSYS DB "Insert system disk in drive " +SYSDRV DB "A",13,10 + DB "and strike any key when ready",13,10 +GetSysLen DW GetSysLen-GetSys + +CONST ENDS + +DATA SEGMENT BYTE PUBLIC +DATA ENDS + +CODE SEGMENT +DG GROUP CODE,CONST,DATA + ASSUME CS:DG,DS:DG,ES:DG,SS:DG + +CODE ENDS + END + + \ No newline at end of file diff --git a/TCODE.ASM b/TCODE.ASM new file mode 100644 index 0000000..dfe6ca5 --- /dev/null +++ b/TCODE.ASM @@ -0,0 +1,1088 @@ +TITLE PART1 - COMMAND Transient routines. + + INCLUDE COMSW.ASM + +.xlist +.xcref + INCLUDE DOSSYM.ASM + INCLUDE DEVSYM.ASM + INCLUDE COMSEG.ASM +.list +.cref + + INCLUDE COMEQU.ASM + + +DATARES SEGMENT PUBLIC + EXTRN BATCH:WORD,BATLOC:DWORD,PARMBUF:BYTE + EXTRN RESTDIR:BYTE,EXTCOM:BYTE,ECHOFLAG:BYTE + EXTRN SINGLECOM:WORD,VERVAL:WORD,FORFLAG:BYTE + EXTRN RE_INSTR:BYTE,RE_OUT_APP:BYTE,PIPE1:BYTE,PIPE2:BYTE + EXTRN RE_OUTSTR:BYTE,PIPEFLAG:BYTE,PIPEFILES:BYTE,PIPEPTR:WORD + EXTRN INPIPEPTR:WORD,OUTPIPEPTR:WORD,EXEC_BLOCK:BYTE,ENVIRSEG:WORD +DATARES ENDS + +TRANDATA SEGMENT PUBLIC + EXTRN BADBAT:BYTE,NEEDBAT:BYTE,BADNAM:BYTE + EXTRN SYNTMES:BYTE,BADDRV:BYTE,BYTMES_POST:BYTE + EXTRN DIRMES_PRE:BYTE,DIRMES_POST:BYTE,BYTMES_PRE:BYTE + EXTRN NOTFND:BYTE,PIPEEMES:BYTE,BADPMES:BYTE,COMTAB:BYTE +TRANDATA ENDS + +TRANSPACE SEGMENT PUBLIC + EXTRN UCOMBUF:BYTE,COMBUF:BYTE,USERDIR1:BYTE,EXECPATH:BYTE + EXTRN DIRCHAR:BYTE,EXEC_ADDR:DWORD,RCH_ADDR:DWORD,CHKDRV:BYTE + EXTRN CURDRV:BYTE,PARM1:BYTE,PARM2:BYTE,COMSW:WORD,ARG1S:WORD + EXTRN ARG2S:WORD,ARGTS:WORD,SPECDRV:BYTE,BYTCNT:WORD,IDLEN:BYTE + EXTRN DIRBUF:BYTE,ID:BYTE,COM:BYTE,LINCNT:BYTE,INTERNATVARS:BYTE + EXTRN HEADCALL:DWORD,RESSEG:WORD,TPA:WORD,SWITCHAR:BYTE + EXTRN STACK:WORD,FILTYP:BYTE,FILECNT:WORD,LINLEN:BYTE + + + IF KANJI + EXTRN KPARSE:BYTE + ENDIF +TRANSPACE ENDS + +; ******************************************************************** +; START OF TRANSIENT PORTION +; This code is loaded at the end of memory and may be overwritten by +; memory-intensive user programs. + +TRANCODE SEGMENT PUBLIC PARA +ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + + + EXTRN SCANOFF:NEAR,DELIM:NEAR,SAVUDIR:NEAR,SAVUDIR1:NEAR + EXTRN PATHCHRCMP:NEAR,PRINT:NEAR,RESTUDIR:NEAR + EXTRN CRLF2:NEAR,PRINT_PROMPT:NEAR,GETBATBYT:NEAR,PRESCAN:NEAR + EXTRN CRPRINT:NEAR,DISP32BITS:NEAR,FCB_TO_ASCZ:NEAR + EXTRN ERROR_PRINT:NEAR,FREE_TPA:NEAR,ALLOC_TPA:NEAR + EXTRN $EXIT:NEAR,FORPROC:NEAR,FIND_NAME_IN_ENVIRONMENT:NEAR + EXTRN UPCONV:NEAR,BATOPEN:NEAR,BATCLOSE:NEAR,IOSET:NEAR,FIND_PATH:NEAR + EXTRN TESTDOREIN:NEAR,TESTDOREOUT:NEAR + + PUBLIC SWLIST,CERROR,SETREST1,DOCOM,DOCOM1,DRVBAD,NOTFNDERR + PUBLIC COMMAND,TCOMMAND,SWITCH,PIPEERRSYN,GETKEYSTROKE,SETREST + PUBLIC CHKCNT + + + IF KANJI + EXTRN TESTKANJ:NEAR + ENDIF + + ORG 0 +ZERO = $ + + ORG 100H ; Allow for 100H parameter area + +SETDRV: + MOV AH,SET_DEFAULT_DRIVE + INT int_command +TCOMMAND: + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + MOV AX,-1 + XCHG AX,[VERVAL] + CMP AX,-1 + JZ NOSETVER2 + MOV AH,SET_VERIFY_ON_WRITE ; AL has correct value + INT int_command +NOSETVER2: + CALL [HEADCALL] ; Make sure header fixed + XOR BP,BP ; Flag transient not read + CMP [SINGLECOM],-1 + JNZ COMMAND +$EXITPREP: + PUSH CS + POP DS + JMP $EXIT ; Have finished the single command +ASSUME DS:NOTHING +COMMAND: + CLD + MOV AX,CS + MOV SS,AX +ASSUME SS:TRANGROUP + MOV SP,OFFSET TRANGROUP:STACK + MOV ES,AX +ASSUME ES:TRANGROUP + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + STI + + MOV [UCOMBUF],COMBUFLEN ; Init UCOMBUF + MOV [COMBUF],COMBUFLEN ; Init COMBUF (Autoexec doing DATE) + OR BP,BP ; See if just read + JZ TESTRDIR ; Not read, check user directory + MOV WORD PTR [UCOMBUF+1],0D01H ; Reset buffer + JMP SHORT NOSETBUF +TESTRDIR: + CMP [RESTDIR],0 + JZ NOSETBUF ; User directory OK + PUSH DS + PUSH CS + POP DS +ASSUME DS:TRANGROUP + MOV DX,OFFSET TRANGROUP:USERDIR1 + MOV AH,CHDIR + INT int_command ; Restore users directory + POP DS +ASSUME DS:RESGROUP +NOSETBUF: + CMP [PIPEFILES],0 + JZ NOPCLOSE ; Don't bother if they don't exist + CMP [PIPEFLAG],0 + JNZ NOPCLOSE ; Don't del if still piping + CALL PIPEDEL +NOPCLOSE: + MOV [EXTCOM],0 ; Flag internal command + MOV [RESTDIR],0 ; Flag users dirs OK + MOV AX,CS ; Get segment we're in + MOV DS,AX +ASSUME DS:TRANGROUP + PUSH AX + MOV DX,OFFSET TRANGROUP:INTERNATVARS + MOV AX,INTERNATIONAL SHL 8 + INT 21H + POP AX + SUB AX,[TPA] ; AX=size of TPA in paragraphs + MOV DX,16 + MUL DX ; DX:AX=size of TPA in bytes + OR DX,DX ; See if over 64K + JZ SAVSIZ ; OK if not + MOV AX,-1 ; If so, limit to 65535 bytes +SAVSIZ: + MOV [BYTCNT],AX ; Max no. of bytes that can be buffered + MOV DS,[RESSEG] ; All batch work must use resident seg. +ASSUME DS:RESGROUP + TEST [ECHOFLAG],-1 + JZ GETCOM ; Don't do the CRLF + CALL SINGLETEST + JB GETCOM + CALL CRLF2 +GETCOM: + MOV AH,GET_DEFAULT_DRIVE + INT int_command + MOV [CURDRV],AL + TEST [ECHOFLAG],-1 + JZ NOPDRV ; No prompt if echo off + CALL SINGLETEST + JB NOPDRV + CALL PRINT_PROMPT ; Prompt the user +NOPDRV: + TEST [PIPEFLAG],-1 ; Pipe has highest presedence + JZ NOPIPE + JMP PIPEPROC ; Continue the pipeline +NOPIPE: + TEST [FORFLAG],-1 ; FOR has next highest precedence + JZ TESTFORBAT + JMP FORPROC ; Continue the FOR +TESTFORBAT: + MOV [RE_INSTR],0 ; Turn redirection back off + MOV [RE_OUTSTR],0 + MOV [RE_OUT_APP],0 + TEST [BATCH],-1 ; Batch has lowest precedence + JZ ISNOBAT + JMP READBAT ; Continue BATCH + +ISNOBAT: + CMP [SINGLECOM],0 + JZ REGCOM + MOV SI,-1 + XCHG SI,[SINGLECOM] + MOV DI,OFFSET TRANGROUP:COMBUF + 2 + XOR CX,CX +SINGLELOOP: + LODSB + STOSB + INC CX + CMP AL,0DH + JNZ SINGLELOOP + DEC CX + PUSH CS + POP DS +ASSUME DS:TRANGROUP + MOV [COMBUF + 1],CL + JMP DOCOM + +REGCOM: + PUSH CS + POP DS ; Need local segment to point to buffer + MOV DX,OFFSET TRANGROUP:UCOMBUF + MOV AH,STD_CON_STRING_INPUT + INT int_command ; Get a command + MOV CL,[UCOMBUF] + XOR CH,CH + ADD CX,3 + MOV SI,OFFSET TRANGROUP:UCOMBUF + MOV DI,OFFSET TRANGROUP:COMBUF + REP MOVSB ; Transfer it to the cooked buffer + JMP DOCOM + +; All batch proccessing has DS set to segment of resident portion +ASSUME DS:RESGROUP,ES:TRANGROUP + +NEEDENV: + PUSH DS + PUSH SI + PUSH DI + + MOV DI,OFFSET TRANGROUP:ID + ADD AL,"0" + STOSB +GETENV1: + CALL GETBATBYT + STOSB + CMP AL,13 + JZ GETENV2 + CMP AL,"%" + JNZ GETENV1 + MOV BYTE PTR ES:[DI-1],"=" +GETENV2: + MOV SI,OFFSET TRANGROUP:ID + PUSH CS + POP DS ; DS:SI POINTS TO NAME +ASSUME DS:TRANGROUP,ES:RESGROUP + CALL FIND_NAME_IN_environment + PUSH ES + POP DS + PUSH CS + POP ES +ASSUME DS:RESGROUP,ES:TRANGROUP + MOV SI,DI + POP DI ; get back pointer to command line + JNC GETENV4 + +GETENV3: ; Parameter not found + PUSH CS + POP DS + MOV SI,OFFSET TRANGROUP:ID + +GETENV4: + LODSB ; From resident segment + OR AL,AL ; Check for end of parameter + JZ GETENV6 + CMP AL,13 + JZ GETENV6 + CMP AL,"=" + JZ GETENVX + STOSB + JMP GETENV4 + +GETENVX: + MOV AL,"%" + STOSB +GETENV6: + POP SI + POP DS + CMP AL,13 + JZ SAVBATBYTJ + JMP RDBAT + +NEEDPARM: + CALL GETBATBYT + CMP AL,"%" ; Check for two consecutive % + JZ SAVBATBYTJ + CMP AL,13 ; Check for end-of-line + JNZ PAROK +SAVBATBYTJ: + JMP SAVBATBYT +PAROK: + SUB AL,"0" + JB NEEDENV ; look for parameter in the environment + CMP AL,9 + JA NEEDENV + + CBW + MOV SI,AX + SHL SI,1 ; Two bytes per entry + PUSH ES + PUSH DI + MOV ES,[BATCH] + XOR CX,CX + MOV AX,CX + MOV DI,CX + DEC CX + REPNZ SCASB + ADD DI,SI + MOV SI,ES:[DI] + POP DI + POP ES + CMP SI,-1 ; Check if parameter exists + JZ RDBAT ; Ignore if it doesn't +RDPARM: + LODSB ; From resident segment + CMP AL,0DH ; Check for end of parameter + JZ RDBAT + STOSB + JMP RDPARM + +PROMPTBAT: + MOV DX,OFFSET TRANGROUP:NEEDBAT + CALL [RCH_ADDR] + JZ AskForBat ; Media is removable +NoAskForBat: + MOV ES,[BATCH] ; Turn off batch + MOV AH,DEALLOC + INT int_command ; free up the batch piece + MOV [BATCH],0 ; AFTER DEALLOC in case of ^C + MOV [FORFLAG],0 ; Turn off for processing + MOV [PIPEFLAG],0 ; Turn off any pipe + PUSH CS + POP DS + MOV DX,OFFSET TRANGROUP:BADBAT + CALL ERROR_PRINT ; Tell user no batch file + JMP TCOMMAND + +ASKFORBAT: + PUSH CS + POP DS + CALL ERROR_PRINT ; Prompt for batch file + CALL GetKeystroke + JMP TCOMMAND +;************************************************************************** +; read the next keystroke + +GetKeystroke: + MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR STD_CON_INPUT_no_echo + INT int_command ; Get character with KB buffer flush + MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0 + INT int_command + return + +READBAT: + CALL BATOPEN + JC PROMPTBAT + MOV DI,OFFSET TRANGROUP:COMBUF+2 +TESTNOP: + CALL GETBATBYT + CMP AL,':' ; Label/Comment? + JNZ NOTLABEL +NOPLINE: ; Consume the line + CALL GETBATBYT + CMP AL,0DH + JNZ NOPLINE + CALL GETBATBYT ; Eat Linefeed + TEST [BATCH],-1 + JNZ TESTNOP + JMP TCOMMAND ; Hit EOF + +RDBAT: + CALL GETBATBYT +NOTLABEL: + CMP AL,"%" ; Check for parameter + JNZ SAVBATBYT + JMP NEEDPARM +SAVBATBYT: + STOSB + CMP AL,0DH + JNZ RDBAT + SUB DI,OFFSET TRANGROUP:COMBUF+3 + MOV AX,DI + MOV ES:[COMBUF+1],AL ; Set length of line + CALL GETBATBYT ; Eat linefeed + CALL BATCLOSE + TEST [ECHOFLAG],-1 + PUSH CS + POP DS ; Go back to local segment + JZ NOECHO2 +ASSUME DS:TRANGROUP + MOV DX,OFFSET TRANGROUP:COMBUF+2 + CALL CRPRINT +DOCOM: +; All segments are local for command line processing + CALL CRLF2 +DOCOM1: + +NOECHO2: + CALL PRESCAN ; Cook the input buffer + JZ NOPIPEPROC + JMP PIPEPROCSTRT ; Fire up the pipe +NOPIPEPROC: + MOV SI,OFFSET TRANGROUP:COMBUF+2 + MOV DI,OFFSET TRANGROUP:IDLEN + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H ; Make FCB with blank scan-off + INT int_command + CMP AL,1 ; Check for ambiguous command name + JZ BADCOMJ1 ; Ambiguous commands not allowed + CMP AL,-1 + JNZ DRVGD + JMP DRVBAD + +BADCOMJ1: + JMP BADCOM + +DRVGD: + MOV AL,[DI] + MOV [SPECDRV],AL + MOV AL," " + MOV CX,9 + INC DI + REPNE SCASB ; Count no. of letters in command name + MOV AL,9 + SUB AL,CL + MOV [IDLEN],AL + MOV DI,81H + XOR CX,CX + PUSH SI +COMTAIL: + LODSB + STOSB ; Move command tail to 80H + CMP AL,13 + LOOPNZ COMTAIL + NOT CL + MOV BYTE PTR DS:[80H],CL + POP SI +; If the command has 0 parameters must check here for +; any switches that might be present. +; SI -> first character after the command. + CALL SWITCH ; Is the next character a SWITCHAR + MOV [COMSW],AX + MOV DI,FCB + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H + INT int_command + MOV [PARM1],AL ; Save result of parse + +PRBEG: + LODSB + CMP AL,[SWITCHAR] + JZ PRFIN + CMP AL,13 + JZ PRFIN + CALL DELIM + JNZ PRBEG +PRFIN: + DEC SI + CALL SWITCH + MOV [ARG1S],AX + MOV DI,FCB+10H + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H + INT int_command ; Parse file name + MOV [PARM2],AL ; Save result + CALL SWITCH + MOV [ARG2S],AX + OR AX,[ARG1S] + MOV [ARGTS],AX +SWTLP: ; Find any remaining switches + CMP BYTE PTR [SI],0DH + JZ GOTALLSW + INC SI + CALL SWITCH + OR [ARGTS],AX + JMP SHORT SWTLP + +GOTALLSW: + MOV AL,[IDLEN] + MOV DL,[SPECDRV] + OR DL,DL ; Check if drive was specified + JZ OK + JMP DRVCHK +OK: + DEC AL ; Check for null command + JNZ FNDCOM + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + CMP [SINGLECOM],-1 + JZ EXITJ + JMP GETCOM + +EXITJ: + JMP $EXITPREP +ASSUME DS:TRANGROUP + +RETSW: + XCHG AX,BX ; Put switches in AX + return + +SWITCH: + XOR BX,BX ; Initialize - no switches set +SWLOOP: + CALL SCANOFF ; Skip any delimiters + CMP AL,[SWITCHAR] ; Is it a switch specifier? + JNZ RETSW ; No -- we're finished + OR BX,GOTSWITCH ; Indicate there is a switch specified + INC SI ; Skip over the switch character + CALL SCANOFF + CMP AL,0DH + JZ RETSW ; Oops + INC SI +; Convert lower case input to upper case + CALL UPCONV + MOV DI,OFFSET TRANGROUP:SWLIST + MOV CX,SWCOUNT + REPNE SCASB ; Look for matching switch + JNZ BADSW + MOV AX,1 + SHL AX,CL ; Set a bit for the switch + OR BX,AX + JMP SHORT SWLOOP + +BADSW: + JMP SHORT SWLOOP + +SWLIST DB "VBAPW" +SWCOUNT EQU $-SWLIST + +DRVBAD: + MOV DX,OFFSET TRANGROUP:BADDRV + JMP CERROR + +FNDCOM: + MOV SI,OFFSET TRANGROUP:COMTAB ; Prepare to search command table + MOV CH,0 +FINDCOM: + MOV DI,OFFSET TRANGROUP:IDLEN + MOV CL,[SI] + JCXZ EXTERNAL + REPE CMPSB + LAHF + ADD SI,CX ; Bump to next position without affecting flags + SAHF + LODSB ; Get flag for drive check + MOV [CHKDRV],AL + LODSW ; Get address of command + JNZ FINDCOM + MOV DX,AX + CMP [CHKDRV],0 + JZ NOCHECK + MOV AL,[PARM1] + OR AL,[PARM2] ; Check if either parm. had invalid drive + CMP AL,-1 + JZ DRVBAD +NOCHECK: + CALL IOSET + CALL DX ; Call the internal +COMJMP: + JMP TCOMMAND + +SETDRV1: + JMP SETDRV + +DRVCHK: + DEC DL ; Adjust for correct drive number + DEC AL ; Check if anything else is on line + JZ SETDRV1 +EXTERNAL: + MOV [FILTYP],0 + MOV DL,[SPECDRV] + MOV [IDLEN],DL + CALL SAVUDIR ; Drive letter already checked + MOV AL,'?' + MOV DI,OFFSET TRANGROUP:COM + STOSB ; Look for any extension + STOSB + STOSB + MOV DX,OFFSET TRANGROUP:DIRBUF ; Command will end up here + MOV AH,SET_DMA + INT int_command + PUSH ES + CALL FIND_PATH + MOV SI,DI + POP ES + + MOV DI,OFFSET TRANGROUP:EXECPATH + MOV BYTE PTR [DI],0 ; Initialize to current directory +RESEARCH: + MOV AH,DIR_SEARCH_FIRST +COMSRCH: + PUSH CS + POP DS + MOV DX,OFFSET TRANGROUP:IDLEN + INT int_command + OR AL,AL + MOV AH,DIR_SEARCH_NEXT ; Do search-next next + JNZ PATHCHK + CMP WORD PTR [DIRBUF+9],4F00H + "C" + JNZ CHKEXE + CMP [DIRBUF+11],"M" + JNZ CHKEXE + OR [FILTYP],4 + JMP EXECUTE ; If we find a COM were done + +CHKEXE: + CMP WORD PTR [DIRBUF+9],5800H + "E" + JNZ CHKBAT + CMP [DIRBUF+11],"E" + JNZ CHKBAT + OR [FILTYP],1 ; Flag an EXE found + JMP COMSRCH ; Continue search + +CHKBAT: + CMP WORD PTR [DIRBUF+9],4100H + "B" + JNZ COMSRCH + CMP [DIRBUF+11],"T" + JNZ COMSRCH + OR [FILTYP],2 ; Flag BAT found + JMP COMSRCH ; Continue search + +PATHCHK: + TEST [FILTYP],1 + JZ TESTBAT + MOV WORD PTR [DIRBUF+9],5800H+"E" + MOV [DIRBUF+11],"E" + JMP EXECUTE ; Found EXE + +TESTBAT: + TEST [FILTYP],2 + JZ NEXTPATH ; Found nothing, try next path + MOV WORD PTR [DIRBUF+9],4100H+"B" + MOV [DIRBUF+11],"T" + MOV DX,OFFSET TRANGROUP:DIRBUF ; Found BAT + MOV AH,FCB_OPEN + INT int_command + OR AL,AL + JZ BATCOMJ ; Bat exists + CALL RESTUDIR + JMP BADCOM + +BATCOMJ: + JMP BATCOM + +NEXTPATH: + MOV DX,OFFSET TRANGROUP:USERDIR1 ; Restore users dir + MOV AH,CHDIR + INT int_command + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + MOV [RESTDIR],0 +BADPATHEL: + MOV DI,OFFSET TRANGROUP:EXECPATH ; Build a full path here + MOV DX,SI + MOV DS,[ENVIRSEG] ; Point into environment +ASSUME DS:NOTHING + LODSB + + IF KANJI + MOV [KPARSE],0 + ENDIF + + OR AL,AL + JZ BADCOMJ ; NUL, command not found + XOR BL,BL ; Make BL a NUL +PSKIPLP: ; Get the path + STOSB + OR AL,AL + JZ LASTPATH + CMP AL,';' + JZ GOTNEXTPATH + CMP DI,15+DirStrLen+(OFFSET TRANGROUP:EXECPATH) + JB OKPath +SKIPPathElem: + LODSB ; scan to end of path element + OR AL,AL + JZ BadPathEl + CMP AL,';' + JZ BadPathEl + JMP SkipPathElem + +OKPath: + IF KANJI + MOV [KPARSE],0 + CALL TESTKANJ + JZ NXTPTCHR + INC [KPARSE] + MOVSB +NXTPTCHR: + ENDIF + + LODSB + JMP SHORT PSKIPLP + +BADCOMJ: + JMP BADCOM + +LASTPATH: + MOV BYTE PTR ES:[DI-1],';' ; Fix up the NUL in EXECPATH + DEC SI ; Point to the NUL in PATHSTRING + MOV BL,[SI-1] ; Change substi char to char before NUL + +GOTNEXTPATH: + DEC DI ; Point to the end of the dir + PUSH BX + PUSH SI + PUSH DX + MOV SI,DX + XOR DL,DL + CMP BYTE PTR [SI+1],DRVCHAR + JNZ DEFDRVPATH ; No drive spec + MOV DL,[SI] + SUB DL,'@' +DEFDRVPATH: + PUSH DS + PUSH CS + POP DS +ASSUME DS:TRANGROUP + MOV [IDLEN],DL ; New drive + PUSH DI + CALL SAVUDIR ; Save the users dir + POP DI + JNC PATHTRY + MOV DX,OFFSET TRANGROUP:BADPMES ; Tell the user bad stuff in path + CALL PRINT +PATHTRY: + POP DS +ASSUME DS:NOTHING + POP DX + POP SI + POP BX + XCHG BL,[SI-1] ; Stick in NUL, or same thing if LASTPATH +CDPATH: + MOV AH,CHDIR + INT int_command + MOV [SI-1],BL ; Fix the path string back up + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + INC [RESTDIR] ; Say users dir needs restoring + JNC ResearchJ + JMP BADPATHEL ; Ignore a directory which doesn't exist +ResearchJ: + JMP RESEARCH ; Try looking in this one + +BATCOM: +ASSUME DS:TRANGROUP +; Batch parameters are read with ES set to segment of resident part + CALL IOSET ; Set up any redirection + MOV ES,[RESSEG] +ASSUME ES:RESGROUP +;Since BATCH has lower precedence than PIPE or FOR. If a new BATCH file +;is being started it MUST be true that no FOR or PIPE is currently in +;progress. + MOV [FORFLAG],0 ; Turn off for processing + MOV [PIPEFLAG],0 ; Turn off any pipe + TEST [BATCH],-1 + JNZ CHAINBAT ; Don't need allocation if chaining + CALL FREE_TPA +ASSUME ES:RESGROUP + MOV BX,6 ; 64 + 32 bytes + MOV AH,ALLOC + INT int_command ; Suck up a little piece for batch processing + MOV [BATCH],AX + CALL ALLOC_TPA +CHAINBAT: + PUSH ES + MOV ES,[BATCH] +ASSUME ES:NOTHING + MOV DL,[DIRBUF] + XOR DI,DI + CALL SAVUDIR1 ; ES:DI set up, get dir containing Batch file + XOR AX,AX + MOV CX,AX + DEC CX + REPNZ SCASB ; Find the NUL + DEC DI ; Point at the NUL + MOV AL,[DIRCHAR] + CMP AL,ES:[DI-1] + JZ NOPUTSLASH + STOSB +NOPUTSLASH: + MOV SI,OFFSET TRANGROUP:DIRBUF+1 + CALL FCB_TO_ASCZ ; Tack on batch file name + MOV AX,-1 + MOV BX,DI + MOV CX,10 + REP STOSW ; Init Parmtab to no parms + POP ES +ASSUME ES:RESGROUP + CALL RESTUDIR + MOV SI,OFFSET TRANGROUP:COMBUF+2 + MOV DI,OFFSET RESGROUP:PARMBUF + MOV CX,10 +EACHPARM: + CALL SCANOFF + CMP AL,0DH + JZ HAVPARM + JCXZ MOVPARM ; Only first 10 parms get pointers + PUSH ES + MOV ES,[BATCH] + MOV ES:[BX],DI ; Set pointer table to point to actual parameter + POP ES + INC BX + INC BX +MOVPARM: + LODSB + CALL DELIM + JZ ENDPARM ; Check for end of parameter + STOSB + CMP AL,0DH + JZ HAVPARM + JMP SHORT MOVPARM +ENDPARM: + MOV AL,0DH + STOSB ; End-of-parameter marker + JCXZ EACHPARM + DEC CX + JMP SHORT EACHPARM +HAVPARM: + XOR AL,AL + STOSB ; Nul terminate the parms + XOR AX,AX + PUSH ES + POP DS ; Simply batch FCB setup +ASSUME DS:RESGROUP + MOV WORD PTR [BATLOC],AX ; Start at beginning of file + MOV WORD PTR [BATLOC+2],AX + CMP [SINGLECOM],-1 + JNZ NOBATSING + MOV [SINGLECOM],0FFF0H ; Flag single command BATCH job +NOBATSING: + JMP TCOMMAND +ASSUME DS:TRANGROUP,ES:TRANGROUP + +EXECUTE: + CALL RESTUDIR +NeoExecute: + CMP BYTE PTR [DI],0 ; Command in current directory + JZ NNSLSH + MOV AL,[DI-1] + + IF KANJI + CMP [KPARSE],0 + JNZ StuffPath ; Last char is second KANJI byte, might be '\' + ENDIF + + CALL PATHCHRCMP + JZ HAVEXP ; Don't double slash +StuffPath: + MOV AL,[DIRCHAR] + STOSB + JMP SHORT HAVEXP + +NNSLSH: + MOV AL,[DIRBUF] ; Specify a drive + ADD AL,'@' + STOSB + MOV AL,DRVCHAR + STOSB +HAVEXP: + MOV SI,OFFSET TRANGROUP:DIRBUF+1 + CALL FCB_TO_ASCZ ; Tack on the filename + CALL IOSET + MOV ES,[TPA] + MOV AH,DEALLOC + INT int_command ; Now running in "free" space + MOV ES,[RESSEG] +ASSUME ES:RESGROUP + INC [EXTCOM] ; Indicate external command + MOV [RESTDIR],0 ; Since USERDIR1 is in transient, insure + ; this flag value for re-entry to COMMAND + MOV DI,FCB + MOV SI,DI + MOV CX,052H + REP MOVSW ; Transfer parameters to resident header + MOV DX,OFFSET TRANGROUP:EXECPATH + MOV BX,OFFSET RESGROUP:EXEC_BLOCK + MOV AX,EXEC SHL 8 + JMP [EXEC_ADDR] ; Jmp to the EXEC in the resident + +BADCOM: + PUSH CS + POP DS + MOV DX,OFFSET TRANGROUP:BADNAM +CERROR: + CALL ERROR_PRINT + JMP TCOMMAND + +SINGLETEST: +ASSUME DS:RESGROUP + CMP [SINGLECOM],0 + JZ RET5 + CMP [SINGLECOM],0EFFFH + return + + +ASSUME DS:TRANGROUP +SETREST1: + MOV AL,1 +SETREST: + PUSH DS + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + MOV [RESTDIR],AL + POP DS +ASSUME DS:TRANGROUP +RET5: + return + +CHKCNT: + TEST [FILECNT],-1 + JNZ ENDDIR +NOTFNDERR: + MOV DX,OFFSET TRANGROUP:NOTFND + JMP CERROR + +ENDDIR: +; Make sure last line ends with CR/LF + MOV AL,[LINLEN] + CMP AL,[LINCNT] ; Will be equal if just had CR/LF + JZ MESSAGE + CALL CRLF2 +MESSAGE: + MOV DX,OFFSET TRANGROUP:DIRMES_PRE + CALL PRINT + MOV SI,[FILECNT] + XOR DI,DI + CALL DISP32BITS + MOV DX,OFFSET TRANGROUP:DIRMES_POST + CALL PRINT + MOV AH,GET_DRIVE_FREESPACE + MOV DL,BYTE PTR DS:[FCB] + INT int_command + CMP AX,-1 + retz + MOV DX,OFFSET TRANGROUP:BYTMES_PRE + CALL PRINT + MUL CX ; AX is bytes per cluster + MUL BX + MOV DI,DX + MOV SI,AX + CALL DISP32BITS + MOV DX,OFFSET TRANGROUP:BYTMES_POST + JMP PRINT + +ASSUME DS:RESGROUP + +PIPEDEL: + PUSH DX + MOV DX,OFFSET RESGROUP:PIPE1 ; Clean up in case ^C + MOV AH,UNLINK + INT int_command + MOV DX,OFFSET RESGROUP:PIPE2 + MOV AH,UNLINK + INT int_command + XOR AX,AX + MOV WORD PTR [PIPEFLAG],AX ; Pipe files and pipe gone + MOV [ECHOFLAG],1 ; Make sure ^C to pipe doesn't leave ECHO OFF + POP DX + return + +PIPEERRSYN: + MOV DX,OFFSET TRANGROUP:SYNTMES + JMP SHORT PIPPERR +PIPEERR: + MOV DX,OFFSET TRANGROUP:PIPEEMES +PIPPERR: + CALL PIPEDEL + PUSH CS + POP DS + JMP CERROR + +PIPEPROCSTRT: +ASSUME DS:TRANGROUP,ES:TRANGROUP + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + INC [PIPEFILES] ; Flag that the pipe files exist + MOV AH,19H ; Get current drive + INT int_command + ADD AL,'A' + MOV [PIPE2],AL ; Make pipe files in root of def drv + MOV BX,OFFSET RESGROUP:PIPE1 + MOV [BX],AL + MOV DX,BX + XOR CX,CX + MOV AH,CREAT + INT int_command + JC PIPEERR ; Couldn't create + MOV BX,AX + MOV AH,CLOSE ; Don't proliferate handles + INT int_command + MOV DX,OFFSET RESGROUP:PIPE2 + MOV AH,CREAT + INT int_command + JC PIPEERR + MOV BX,AX + MOV AH,CLOSE + INT int_command + CALL TESTDOREIN ; Set up a redirection if specified + MOV [ECHOFLAG],0 ; No echo on pipes + MOV SI,[PIPEPTR] + CMP [SINGLECOM],-1 + JNZ NOSINGP + MOV [SINGLECOM],0F000H ; Flag single command pipe +NOSINGP: + JMP SHORT FIRSTPIPE + +PIPEPROC: +ASSUME DS:RESGROUP + MOV [ECHOFLAG],0 ; No echo on pipes + MOV SI,[PIPEPTR] + LODSB + CMP AL,'|' + JNZ PIPEEND ; Pipe done + MOV DX,[INPIPEPTR] ; Get the input file name + MOV AX,(OPEN SHL 8) + INT int_command +PIPEERRJ: + JC PIPEERR ; Lost the pipe file + MOV BX,AX + MOV AL,0FFH + XCHG AL,[BX.PDB_JFN_Table] + MOV DS:[PDB_JFN_Table],AL ; Redirect +FIRSTPIPE: + MOV DI,OFFSET TRANGROUP:COMBUF + 2 + XOR CX,CX + CMP BYTE PTR [SI],0DH ; '|' + JNZ PIPEOK1 +PIPEERRSYNJ: + JMP PIPEERRSYN +PIPEOK1: + CMP BYTE PTR [SI],'|' ; '||' + JZ PIPEERRSYNJ +PIPECOMLP: + LODSB + STOSB + + IF KANJI + CALL TESTKANJ + JZ NOTKANJ5 + MOVSB + JMP PIPECOMLP + +NOTKANJ5: + ENDIF + + CMP AL,0DH + JZ LASTPIPE + INC CX + CMP AL,'|' + JNZ PIPECOMLP + MOV BYTE PTR ES:[DI-1],0DH + DEC CX + MOV [COMBUF+1],CL + DEC SI + MOV [PIPEPTR],SI ; On to next pipe element + MOV DX,[OUTPIPEPTR] + PUSH CX + XOR CX,CX + MOV AX,(CREAT SHL 8) + INT int_command + POP CX + JC PIPEERRJ ; Lost the file + MOV BX,AX + MOV AL,0FFH + XCHG AL,[BX.PDB_JFN_Table] + MOV DS:[PDB_JFN_Table+1],AL + XCHG DX,[INPIPEPTR] ; Swap for next element of pipe + MOV [OUTPIPEPTR],DX + JMP SHORT PIPECOM + +LASTPIPE: + MOV [COMBUF+1],CL + DEC SI + MOV [PIPEPTR],SI ; Point at the CR (anything not '|' will do) + CALL TESTDOREOUT ; Set up the redirection if specified +PIPECOM: + PUSH CS + POP DS + JMP NOPIPEPROC ; Process the pipe element + +PIPEEND: + CALL PIPEDEL + CMP [SINGLECOM],0F000H + JNZ NOSINGP2 + MOV [SINGLECOM],-1 ; Make it return +NOSINGP2: + JMP TCOMMAND + +TRANCODE ENDS + END + \ No newline at end of file diff --git a/TCODE2.ASM b/TCODE2.ASM new file mode 100644 index 0000000..bc2742d --- /dev/null +++ b/TCODE2.ASM @@ -0,0 +1,522 @@ +TITLE PART2 - COMMAND Transient routines. + + INCLUDE COMSW.ASM + +.xlist +.xcref + INCLUDE DOSSYM.ASM + INCLUDE DEVSYM.ASM + INCLUDE COMSEG.ASM +.list +.cref + + INCLUDE COMEQU.ASM + +CODERES SEGMENT PUBLIC + EXTRN LODCOM1:NEAR +CODERES ENDS + +DATARES SEGMENT PUBLIC + EXTRN PARENT:WORD,IO_SAVE:WORD,PERMCOM:BYTE + EXTRN PIPEFLAG:BYTE,ENVIRSEG:WORD + if ibmver + EXTRN SYS_CALL:DWORD + endif +DATARES ENDS + +TRANDATA SEGMENT PUBLIC + + EXTRN PATH_TEXT:BYTE,PROMPT_TEXT:BYTE + EXTRN BADDEV:BYTE,SYNTMES:BYTE,ENVERR:BYTE +TRANDATA ENDS + +TRANSPACE SEGMENT PUBLIC + + EXTRN CURDRV:BYTE,DIRCHAR:BYTE,PWDBUF:BYTE + EXTRN INTERNATVARS:BYTE,RESSEG:WORD,TPA:WORD + +TRANSPACE ENDS + + +TRANCODE SEGMENT PUBLIC BYTE +ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + + EXTRN CERROR:NEAR,ZPRINT:NEAR + EXTRN CRLF2:NEAR,SCANOFF:NEAR,FREE_TPA:NEAR,ALLOC_TPA:NEAR + EXTRN OUT:NEAR,DRVBAD:NEAR,SETPATH:NEAR,PRINT:NEAR + EXTRN FCB_TO_ASCZ:NEAR + + PUBLIC PRINT_DRIVE,$EXIT,MOVE_NAME + PUBLIC UPCONV,ADD_PROMPT,CTTY,PRINT_DEFAULT_DIRECTORY + PUBLIC ADD_NAME_TO_ENVIRONMENT,PWD,SCAN_DOUBLE_NULL + PUBLIC FIND_NAME_IN_ENVIRONMENT,STORE_CHAR + PUBLIC FIND_PATH,DELETE_PATH,FIND_PROMPT + PUBLIC SCASB2 + + IF KANJI + PUBLIC TESTKANJ + ENDIF + +BREAK +ASSUME DS:TRANGROUP + +ADD_PROMPT: + CALL DELETE_PROMPT ; DELETE ANY EXISTING PROMPT + CALL SCAN_DOUBLE_NULL +ADD_PROMPT2: + PUSH SI + CALL GETARG + POP SI + retz ; PRE SCAN FOR ARGUMENTS + CALL MOVE_NAME ; MOVE IN NAME + CALL GETARG + JMP SHORT ADD_NAME +; +; Input: DS:SI points to a CR terminated string +; Output: carry flag is set if no room +; otherwise name is added to environment +; +ADD_NAME_TO_ENVIRONMENT: + CALL GETARG + JZ DISP_ENV +; +; check if line contains exactly one equals sign +; + XOR BX,BX ;= COUNT IS 0 + PUSH SI ;SAVE POINTER TO BEGINNING OF LINE +EQLP: + LODSB ;GET A CHAR + CMP AL,13 ;IF CR WE'RE ALL DONE + JZ QUEQ + CMP AL,"=" ;LOOK FOR = SIGN + JNZ EQLP ;NOT THERE, GET NEXT CHAR + INC BL ;OTHERWISE INCREMENT EQ COUNT + CMP BYTE PTR [SI],13 ;LOOK FOR CR FOLLOWING = SIGN + JNZ EQLP + INC BH ;SET BH=1 MEANS NO PARAMETERS + JMP EQLP ;AND LOOK FOR MORE +QUEQ: + POP SI ;RESTORE BEGINNING OF LINE + DEC BL ;ZERO FLAG MEANS ONLY ONE EQ + JZ ONEQ ;GOOD LINE + MOV DX,OFFSET TRANGROUP:SYNTMES + JMP CERROR + +ONEQ: + PUSH BX + CALL DELETE_NAME_IN_ENVIRONMENT + POP BX + DEC BH + retz + + CALL SCAN_DOUBLE_NULL + CALL MOVE_NAME +ADD_NAME: + LODSB + CMP AL,13 + retz + CALL STORE_CHAR + JMP ADD_NAME + +DISP_ENV: + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + MOV DS,[ENVIRSEG] +ASSUME DS:NOTHING + XOR SI,SI +PENVLP: + CMP BYTE PTR [SI],0 + retz + + MOV DX,SI + CALL ZPRINT + CALL CRLF2 +PENVLP2: + LODSB + OR AL,AL + JNZ PENVLP2 + JMP PENVLP + +ASSUME DS:TRANGROUP +DELETE_PATH: + MOV SI,OFFSET TRANGROUP:PATH_TEXT + JMP SHORT DELETE_NAME_IN_environment + +DELETE_PROMPT: + MOV SI,OFFSET TRANGROUP:PROMPT_TEXT + +DELETE_NAME_IN_environment: +; +; Input: DS:SI points to a "=" terminated string +; Output: carry flag is set if name not found +; otherwise name is deleted +; + PUSH SI + PUSH DS + CALL FIND ; ES:DI POINTS TO NAME + JC DEL1 + MOV SI,DI ; SAVE IT + CALL SCASB2 ; SCAN FOR THE NUL + XCHG SI,DI + CALL GETENVSIZ + SUB CX,SI + PUSH ES + POP DS ; ES:DI POINTS TO NAME, DS:SI POINTS TO NEXT NAME + REP MOVSB ; DELETE THE NAME +DEL1: + POP DS + POP SI + return + +FIND_PATH: + MOV SI,OFFSET TRANGROUP:PATH_TEXT + JMP SHORT FIND_NAME_IN_environment + +FIND_PROMPT: + MOV SI,OFFSET TRANGROUP:PROMPT_TEXT + +FIND_NAME_IN_environment: +; +; Input: DS:SI points to a "=" terminated string +; Output: ES:DI points to the arguments in the environment +; zero is set if name not found +; carry flag is set if name not valid format +; + CALL FIND ; FIND THE NAME + retc ; CARRY MEANS NOT FOUND + JMP SCASB1 ; SCAN FOR = SIGN +; +; On return of FIND1, ES:DI points to beginning of name +; +FIND: + CLD + CALL COUNT0 ; CX = LENGTH OF NAME + MOV ES,[RESSEG] +ASSUME ES:RESGROUP + MOV ES,[ENVIRSEG] +ASSUME ES:NOTHING + XOR DI,DI +FIND1: + PUSH CX + PUSH SI + PUSH DI +FIND11: + LODSB + + IF KANJI + CALL TESTKANJ + JZ NOTKANJ3 + DEC SI + LODSW + INC DI + INC DI + CMP AX,ES:[DI-2] + JNZ FIND12 + DEC CX + LOOP FIND11 + JMP SHORT FIND12 + +NOTKANJ3: + ENDIF + + CALL UPCONV + INC DI + CMP AL,ES:[DI-1] + JNZ FIND12 + LOOP FIND11 +FIND12: + POP DI + POP SI + POP CX + retz + PUSH CX + CALL SCASB2 ; SCAN FOR A NUL + POP CX + CMP BYTE PTR ES:[DI],0 + JNZ FIND1 + STC ; INDICATE NOT FOUND + return + +COUNT0: + PUSH DS + POP ES + MOV DI,SI + +COUNT1: + PUSH DI ; COUNT NUMBER OF CHARS UNTIL "=" + CALL SCASB1 + JMP SHORT COUNTX +COUNT2: + PUSH DI ; COUNT NUMBER OF CHARS UNTIL NUL + CALL SCASB2 +COUNTX: + POP CX + SUB DI,CX + XCHG DI,CX + return + +MOVE_NAME: + CMP BYTE PTR DS:[SI],13 + retz + LODSB + + IF KANJI + CALL TESTKANJ + JZ NOTKANJ1 + CALL STORE_CHAR + LODSB + CALL STORE_CHAR + JMP SHORT MOVE_NAME + +NOTKANJ1: + ENDIF + + CALL UPCONV + CALL STORE_CHAR + CMP AL,"=" + JNZ MOVE_NAME + return + +GETARG: + MOV SI,80H + LODSB + OR AL,AL + retz + CALL SCANOFF + CMP AL,13 + return + +SCAN_DOUBLE_NULL: + MOV ES,[RESSEG] +ASSUME ES:RESGROUP + MOV ES,[ENVIRSEG] +ASSUME ES:NOTHING + XOR DI,DI +SDN1: + CALL SCASB2 + CMP BYTE PTR ES:[DI],0 + JNZ SDN1 + return + +SCASB1: + MOV AL,"=" ; SCAN FOR AN = + JMP SHORT SCASBX +SCASB2: + XOR AL,AL ; SCAN FOR A NUL +SCASBX: + MOV CX,100H + REPNZ SCASB + return + + IF KANJI +TESTKANJ: + CMP AL,81H + JB NOTLEAD + CMP AL,9FH + JBE ISLEAD + CMP AL,0E0H + JB NOTLEAD + CMP AL,0FCH + JBE ISLEAD +NOTLEAD: + PUSH AX + XOR AX,AX ;Set zero + POP AX + return + +ISLEAD: + PUSH AX + XOR AX,AX ;Set zero + INC AX ;Reset zero + POP AX + return + ENDIF + +UPCONV: + CMP AL,"a" + JB RET22C + CMP AL,"z" + JA RET22C + SUB AL,20H ; Lower-case changed to upper-case +RET22C: + CALL DWORD PTR CS:[INTERNATVARS.Map_call] + return +; +; STORE A CHAR IN environment, GROWING IT IF NECESSARY +; +STORE_CHAR: + PUSH CX + PUSH BX + CALL GETENVSIZ + MOV BX,CX + SUB BX,2 ; SAVE ROOM FOR DOUBLE NULL + CMP DI,BX + JB STORE1 + + PUSH AX + PUSH CX + PUSH BX ; Save Size of environment + CALL FREE_TPA + POP BX + ADD BX,2 ; Recover true environment size + MOV CL,4 + SHR BX,CL ; Convert back to paragraphs + INC BX ; Try to grow environment by one para + MOV AH,SETBLOCK + INT int_command + PUSHF + PUSH ES + MOV ES,[RESSEG] + CALL ALLOC_TPA + POP ES + POPF + POP CX + POP AX + JNC STORE1 + MOV DX,OFFSET TRANGROUP:ENVERR + JMP CERROR +STORE1: + STOSB + MOV WORD PTR ES:[DI],0 ; NULL IS AT END + POP BX + POP CX + return + +GETENVSIZ: +;Get size of environment in bytes, rounded up to paragraph boundry +;ES has environment segment +;Size returned in CX, all other registers preserved + + PUSH ES + PUSH AX + MOV AX,ES + DEC AX ;Point at arena + MOV ES,AX + MOV AX,ES:[arena_size] + MOV CL,4 + SHL AX,CL ;Convert to bytes + MOV CX,AX + POP AX + POP ES + return + +PRINT_DRIVE: + MOV AH,GET_DEFAULT_DRIVE + INT int_command + ADD AL,"A" + JMP OUT + +ASSUME DS:TRANGROUP,ES:TRANGROUP +PWD: + CALL PRINT_DIRECTORY + CALL CRLF2 + return + +PRINT_DEFAULT_DIRECTORY: + MOV BYTE PTR DS:[FCB],0 +PRINT_DIRECTORY: + MOV DL,DS:[FCB] + MOV AL,DL + ADD AL,'@' + CMP AL,'@' + JNZ GOTDRIVE + ADD AL,[CURDRV] + INC AL +GOTDRIVE: + PUSH AX + MOV SI,OFFSET TRANGROUP:PWDBUF+3 + MOV AH,CURRENT_DIR + INT int_command + JNC DPBISOK + PUSH CS + POP DS + JMP DRVBAD +DPBISOK: + MOV DI,OFFSET TRANGROUP:PWDBUF + MOV DX,DI + POP AX + MOV AH,DRVCHAR + STOSW + MOV AL,[DIRCHAR] + STOSB + JMP ZPRINT + +$EXIT: + PUSH ES + MOV ES,[RESSEG] +ASSUME ES:RESGROUP + MOV AX,[PARENT] + MOV WORD PTR ES:[PDB_Parent_PID],AX + +IF IBM + CMP [PERMCOM],0 + JNZ NORESETVEC ;Don't reset the vector if a PERMCOM + LDS DX,DWORD PTR ES:[SYS_CALL] +ASSUME DS:NOTHING + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) + INT_COMMAND + INT int_command +NORESETVEC: +ENDIF + + POP ES +ASSUME ES:TRANGROUP + MOV ES,[TPA] + MOV AH,DEALLOC + INT int_command ; Now running in "free" space + MOV AX,(EXIT SHL 8) + INT int_command + +CTTY: + CALL SETPATH ; Get spec + MOV AX,(OPEN SHL 8) OR 2 ; Read and write + INT int_command ; Open new device + JC ISBADDEV + MOV BX,AX + MOV AX,IOCTL SHL 8 + INT int_command + TEST DL,80H + JNZ DEVISOK + MOV AH,CLOSE ; Close initial handle + INT int_command +ISBADDEV: + MOV DX,OFFSET TRANGROUP:BADDEV + CALL PRINT + JMP RESRET + +DEVISOK: + XOR DH,DH + OR DL,3 ; Make sure has CON attributes + MOV AX,(IOCTL SHL 8) OR 1 + INT int_command + PUSH BX ; Save handle + MOV CX,3 + XOR BX,BX +ICLLOOP: ; Close basic handles + MOV AH,CLOSE + INT int_command + INC BX + LOOP ICLLOOP + POP BX ; Get handle + MOV AH,XDUP + INT int_command ; Dup it to 0 + MOV AH,XDUP + INT int_command ; Dup to 1 + MOV AH,XDUP + INT int_command ; Dup to 2 + MOV AH,CLOSE ; Close initial handle + INT int_command +RESRET: + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + PUSH DS + MOV AX,WORD PTR DS:[PDB_JFN_Table] ; Get new 0 and 1 + MOV [IO_SAVE],AX + MOV AX,OFFSET RESGROUP:LODCOM1 + PUSH AX +ZMMMM PROC FAR + RET ; Force header to be checked +ZMMMM ENDP + +TRANCODE ENDS + END + \ No newline at end of file diff --git a/TCODE3.ASM b/TCODE3.ASM new file mode 100644 index 0000000..547c937 --- /dev/null +++ b/TCODE3.ASM @@ -0,0 +1,677 @@ +TITLE PART3 - COMMAND Transient routines. + + INCLUDE COMSW.ASM + +.xlist +.xcref + INCLUDE DOSSYM.ASM + INCLUDE DEVSYM.ASM + INCLUDE COMSEG.ASM +.list +.cref + + INCLUDE COMEQU.ASM + + +DATARES SEGMENT PUBLIC + EXTRN BATCH:WORD,BATLOC:DWORD + EXTRN RETCODE:WORD,ECHOFLAG:BYTE + EXTRN SINGLECOM:WORD,FORFLAG:BYTE,UFORDRV:BYTE + EXTRN FORSET:BYTE,FORCOM:BYTE,FORVAR:BYTE,FORPTR:WORD + EXTRN FORUFCB:BYTE,FORFCB:BYTE,RE_INSTR:BYTE,RE_OUT_APP:BYTE + EXTRN RE_OUTSTR:BYTE,PIPEFLAG:BYTE + +DATARES ENDS + +TRANDATA SEGMENT PUBLIC + + EXTRN BADLAB:BYTE,SYNTMES:BYTE,FORNESTMES:BYTE + EXTRN NOTFND:BYTE,FULDIR:BYTE,IFTAB:BYTE +TRANDATA ENDS + +TRANSPACE SEGMENT PUBLIC + + EXTRN BATHAND:WORD,RESSEG:WORD,DIRBUF:BYTE,COMBUF:BYTE + EXTRN GOTOLEN:WORD,IFNOTFLAG:BYTE + +TRANSPACE ENDS + + +TRANCODE SEGMENT PUBLIC BYTE +ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + + EXTRN SCANOFF:NEAR,DOCOM:NEAR,DOCOM1:NEAR,CERROR:NEAR + EXTRN PRINT:NEAR,TCOMMAND:NEAR,DELIM:NEAR,GETBATBYT:NEAR + EXTRN FCB_TO_ASCZ:NEAR + + PUBLIC GOTO,$IF,IFERLEV,SHIFT,IFEXISTS + PUBLIC STRCOMP,MesTran,$FOR,IFNOT + PUBLIC FORPROC,BATOPEN,BATCLOSE + PUBLIC IOSET,TESTDOREIN,TESTDOREOUT + + ASSUME DS:RESGROUP +FORTERM: + MOV [FORFLAG],0 + CMP [SINGLECOM],0FF00H + JNZ NOFORP2 + MOV [SINGLECOM],-1 ; Cause a terminate +NOFORP2: + JMP TCOMMAND + +FORPROC: +ASSUME DS:RESGROUP + CMP [FORUFCB],-1 + JZ NORMFOR + MOV DX,OFFSET TRANGROUP:DIRBUF + PUSH DS + PUSH CS + POP DS +ASSUME DS:TRANGROUP + MOV AH,SET_DMA + INT int_command + POP DS +ASSUME DS:RESGROUP + MOV DX,OFFSET RESGROUP:FORFCB + MOV AH,DIR_SEARCH_NEXT + CMP [FORUFCB],0 + JZ DOFORSRCH + MOV AH,DIR_SEARCH_FIRST + MOV [FORUFCB],0 +DOFORSRCH: + INT int_command + OR AL,AL + JNZ FORTERM + PUSH DS + POP ES +ASSUME ES:RESGROUP + PUSH CS + POP DS +ASSUME DS:TRANGROUP + MOV SI,OFFSET TRANGROUP:DIRBUF + MOV DI,OFFSET RESGROUP:FORSET + MOV [FORPTR],DI + LODSB ;Get drive spec + ADD AL,'@' + CMP AL,'@' + JZ NDRV8 + CMP [UFORDRV],0 + JZ NDRV8 + MOV AH,':' + STOSW +NDRV8: + CALL FCB_TO_ASCZ + MOV BYTE PTR ES:[DI-1],0DH + PUSH ES + POP DS +ASSUME DS:RESGROUP +NORMFOR: + PUSH CS + POP ES +ASSUME ES:TRANGROUP + MOV BX,[FORPTR] + CMP BYTE PTR [BX],0 + JZ FORTERM + MOV SI,BX +PARMSUB0: + LODSB + CMP AL,0DH + JNZ PARMSUB0 + MOV DX,SI ; DX points to next parm + MOV SI,OFFSET RESGROUP:FORCOM + MOV DI,OFFSET TRANGROUP:COMBUF+2 + XOR CX,CX +TFORCOM: + LODSB + CMP AL,'%' + JNZ NOFORPARM + MOV AH,[FORVAR] + CMP AH,[SI] + JNZ NOFORPARM + INC SI + PUSH SI + MOV SI,BX +PARMSUB: + LODSB + CMP AL,0DH + JZ PARMSUBDONE + INC CX + STOSB + JMP SHORT PARMSUB +PARMSUBDONE: + POP SI ; Get back command line pointer + JMP TFORCOM +NOFORPARM: + STOSB + INC CX + CMP AL,0DH + JNZ TFORCOM + DEC CX + MOV [COMBUF+1],CL + MOV [FORPTR],DX ; Point to next set element + TEST [ECHOFLAG],-1 + PUSH CS + POP DS +ASSUME DS:TRANGROUP + JZ NOECHO3 + MOV BYTE PTR ES:[DI-1],'$' + MOV DX,OFFSET TRANGROUP:COMBUF+2 + CALL PRINT + MOV BYTE PTR ES:[DI-1],0DH + JMP DOCOM +NOECHO3: + JMP DOCOM1 + +ASSUME DS:TRANGROUP,ES:TRANGROUP + +FORNESTERR: + PUSH DS + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + MOV DX,OFFSET TRANGROUP:FORNESTMES + CMP [SINGLECOM],0FF00H + JNZ NOFORP3 + MOV [SINGLECOM],-1 ; Cause termination +NOFORP3: + POP DS +ASSUME DS:TRANGROUP + JMP CERROR + +$FOR: + MOV SI,81H + XOR CX,CX + MOV ES,[RESSEG] +ASSUME ES:RESGROUP + MOV DI,OFFSET RESGROUP:FORSET + XOR AL,AL + MOV [UFORDRV],AL + XCHG AL,[FORFLAG] + OR AL,AL + JNZ FORNESTERR + MOV [FORPTR],DI + MOV [FORUFCB],-1 + CALL SCANOFF + LODSW + CMP AL,'%' + JNZ FORERRORJ + MOV [FORVAR],AH + CALL SCANOFF + CMP AL,0DH + JZ FORERRORJ2 + LODSW + CMP AX,('N' SHL 8) OR 'I' + JZ FOROK1 + CMP AX,('n' SHL 8) OR 'i' + JNZ FORERRORJ +FOROK1: + CALL SCANOFF + LODSB + CMP AL,'(' + JNZ FORERRORJ + CALL SCANOFF + CMP AL,')' ; Special check for null set + JNZ FORSETLP + MOV DS,[RESSEG] + JMP FORTERM +FORSETLP: + LODSB + CMP AL,0DH +FORERRORJ2: + JZ FORERRORJ3 + CMP AL,')' + JZ FORSETEND + STOSB + CMP AL,'*' + JZ SETFORSCAN + CMP AL,'?' + JNZ NOFORSCAN +SETFORSCAN: + MOV [FORUFCB],1 +NOFORSCAN: + CALL DELIM + JNZ FORSETLP + MOV BYTE PTR ES:[DI-1],0DH + CALL SCANOFF + JMP FORSETLP + +FORSETEND: + MOV AX,000DH + CMP BYTE PTR ES:[DI-1],0DH + JNZ FORSETTERM + XOR AX,AX +FORSETTERM: + STOSW + CALL SCANOFF + LODSW + CMP AX,('O' SHL 8) OR 'D' + JZ FOROK2 + CMP AX,('o' SHL 8) OR 'd' +FORERRORJ: + JNZ FORERROR +FOROK2: + CALL SCANOFF + CMP AL,0DH +FORERRORJ3: + JZ FORERROR + MOV DI,OFFSET RESGROUP:FORCOM +FORCOMLP: + LODSB + STOSB + CMP AL,0DH + JNZ FORCOMLP + INC [FORFLAG] + CMP [SINGLECOM],-1 + JNZ NOFORP + MOV [SINGLECOM],0FF00H ; Flag single command for +NOFORP: + CMP [FORUFCB],1 + retnz + PUSH ES + POP DS +ASSUME DS:RESGROUP + MOV DI,OFFSET RESGROUP:FORFCB + MOV SI,OFFSET RESGROUP:FORSET + CMP BYTE PTR [SI+1],':' + JNZ NOSETUDRV + INC [UFORDRV] +NOSETUDRV: + MOV AX,PARSE_FILE_DESCRIPTOR SHL 8 + INT int_command + return + + +ASSUME DS:TRANGROUP,ES:TRANGROUP + +IFERRORP: + POP AX +IFERROR: +FORERROR: + MOV DX,OFFSET TRANGROUP:SYNTMES + JMP CERROR + +$IF: + MOV [IFNOTFLAG],0 + MOV SI,81H +IFREENT: + CALL SCANOFF + CMP AL,0DH + JZ IFERROR + MOV BP,SI + MOV DI,OFFSET TRANGROUP:IFTAB ; Prepare to search if table + MOV CH,0 +IFINDCOM: + MOV SI,BP + MOV CL,[DI] + INC DI + JCXZ IFSTRING + JMP SHORT FIRSTCOMP +IFCOMP: + JNZ IFDIF +FIRSTCOMP: + LODSB + MOV AH,ES:[DI] + INC DI + CMP AL,AH + JZ IFLP + OR AH,20H ; Try lower case + CMP AL,AH +IFLP: + LOOP IFCOMP +IFDIF: + LAHF + ADD DI,CX ; Bump to next position without affecting flags + MOV BX,[DI] ; Get handler address + INC DI + INC DI + SAHF + JNZ IFINDCOM + LODSB + CMP AL,0DH +IFERRORJ: + JZ IFERROR + CALL DELIM + JNZ IFINDCOM + CALL SCANOFF + JMP BX + +IFNOT: + NOT [IFNOTFLAG] + JMP IFREENT + + +IFSTRING: + PUSH SI + XOR CX,CX +FIRST_STRING: + LODSB + CMP AL,0DH + JZ IFERRORP + CALL DELIM + JZ EQUAL_CHECK + INC CX + JMP SHORT FIRST_STRING +EQUAL_CHECK: + CMP AL,'=' + JZ EQUAL_CHECK2 + CMP AL,0DH + JZ IFERRORP + LODSB + JMP SHORT EQUAL_CHECK +EQUAL_CHECK2: + LODSB + CMP AL,'=' + JNZ IFERRORP + CALL SCANOFF + CMP AL,0DH + JZ IFERRORP + POP DI + REPE CMPSB + JZ MATCH + CMP BYTE PTR [SI-1],0DH + JZ IFERRORJ +SKIPSTRINGEND: + LODSB +NOTMATCH: + CMP AL,0DH +IFERRORJ2: + JZ IFERRORJ + CALL DELIM + JNZ SKIPSTRINGEND + MOV AL,-1 + JMP SHORT IFRET +MATCH: + LODSB + CALL DELIM + JNZ NOTMATCH + XOR AL,AL + JMP SHORT IFRET + +IFEXISTS: + MOV DI,OFFSET TRANGROUP:DIRBUF + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H + INT int_command + MOV AH,FCB_OPEN + MOV DX,DI + INT int_command +IFRET: + TEST [IFNOTFLAG],-1 + JZ REALTEST + NOT AL +REALTEST: + OR AL,AL + JZ IFTRUE + JMP TCOMMAND +IFTRUE: + CALL SCANOFF + MOV CX,SI + SUB CX,81H + SUB DS:[80H],CL + MOV CL,DS:[80H] + MOV [COMBUF+1],CL + MOV DI,OFFSET TRANGROUP:COMBUF+2 + REP MOVSB + MOV AL,0DH + STOSB + JMP DOCOM1 + +IFERLEV: + MOV BH,10 + XOR BL,BL +GETNUMLP: + LODSB + CMP AL,0DH + JZ IFERRORJ2 + CALL DELIM + JZ GOTNUM + SUB AL,'0' + XCHG AL,BL + MUL BH + ADD AL,BL + XCHG AL,BL + JMP SHORT GETNUMLP +GOTNUM: + PUSH DS + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + MOV AH,BYTE PTR [RETCODE] + POP DS +ASSUME DS:TRANGROUP + XOR AL,AL + CMP AH,BL + JAE IFRET + DEC AL + JMP SHORT IFRET + +ASSUME DS:TRANGROUP + +SHIFT: + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + MOV AX,[BATCH] + TEST AX,-1 + retz + MOV ES,AX + MOV DS,AX +ASSUME DS:NOTHING,ES:NOTHING + XOR CX,CX + MOV AX,CX + MOV DI,CX + DEC CX + REPNZ SCASB + MOV SI,DI + INC SI + INC SI + MOV CX,9 + REP MOVSW ; Perform shift of existing parms + CMP WORD PTR [DI],-1 + retz ; No new parm + MOV SI,[DI] + MOV WORD PTR [DI],-1 ; Assume no parm + MOV DS,[RESSEG] +ASSUME DS:RESGROUP +SKIPCRLP: + LODSB + CMP AL,0DH + JNZ SKIPCRLP + CMP BYTE PTR [SI],0 + retz ; End of parms + MOV ES:[DI],SI ; Pointer to next parm as %9 + return + + +ASSUME DS:TRANGROUP,ES:TRANGROUP +GOTO: + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + TEST [BATCH],-1 + retz ; If not in batch mode, a nop + XOR DX,DX + MOV WORD PTR [BATLOC],DX ; Back to start + MOV WORD PTR [BATLOC+2],DX + CALL BATOPEN ; Find the batch file + MOV DI,FCB+1 ; Get the label + MOV CX,11 + MOV AL,' ' + REPNE SCASB + JNZ NOINC + INC CX +NOINC: + SUB CX,11 + NEG CX + MOV [GOTOLEN],CX + CALL GETBATBYT + CMP AL,':' + JZ CHKLABEL +LABLKLP: ; Look for the label + CALL GETBATBYT + CMP AL,0AH + JNZ LABLKTST + CALL GETBATBYT + CMP AL,':' + JZ CHKLABEL +LABLKTST: + TEST [BATCH],-1 + JNZ LABLKLP + CALL BATCLOSE + PUSH CS + POP DS + MOV DX,OFFSET TRANGROUP:BADLAB + JMP CERROR + +CHKLABEL: + MOV DI,FCB+1 + MOV CX,[GOTOLEN] +NEXTCHRLP: + PUSH CX + CALL GETBATBYT + POP CX + OR AL,20H + CMP AL,ES:[DI] + JNZ TRYUPPER + JMP SHORT NEXTLABCHR +TRYUPPER: + SUB AL,20H + CMP AL,ES:[DI] + JNZ LABLKTST +NEXTLABCHR: + INC DI + LOOP NEXTCHRLP + CALL GETBATBYT + CMP AL,' ' + JA LABLKTST + CMP AL,0DH + JZ SKIPLFEED +TONEXTBATLIN: + CALL GETBATBYT + CMP AL,0DH + JNZ TONEXTBATLIN +SKIPLFEED: + CALL GETBATBYT +BATCLOSE: + MOV BX,CS:[BATHAND] + MOV AH,CLOSE + INT int_command + return + +BATOPEN: +;Open the BATCH file, If open fails, AL is drive of batch file (A=1) +ASSUME DS:RESGROUP,ES:TRANGROUP + PUSH DS + MOV DS,[BATCH] +ASSUME DS:NOTHING + XOR DX,DX + MOV AX,OPEN SHL 8 + INT int_command ; Open the batch file + JC SETERRDL + POP DS +ASSUME DS:RESGROUP + MOV [BATHAND],AX + MOV BX,AX + MOV DX,WORD PTR [BATLOC] + MOV CX,WORD PTR [BATLOC+2] + MOV AX,LSEEK SHL 8 ; Go to the right spot + INT int_command + return + +SETERRDL: + MOV BX,DX + MOV AL,[BX] ; Get drive spec + SUB AL,'@' ; A = 1 + POP DS + STC ; SUB mucked over carry + return + +MESTRAN: +ASSUME DS:NOTHING,ES:NOTHING + LODSB + CMP AL,"$" + retz + STOSB + JMP MESTRAN +IOSET: +; ALL REGISTERS PRESERVED +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH DS + PUSH DX + PUSH AX + PUSH BX + PUSH CX + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + CMP [PIPEFLAG],0 + JNZ NOREDIR ; Don't muck up the pipe + CALL TESTDOREIN + CALL TESTDOREOUT +NOREDIR: + POP CX + POP BX + POP AX + POP DX + POP DS +ASSUME DS:NOTHING + return + +TESTDOREIN: +ASSUME DS:RESGROUP + CMP [RE_INSTR],0 + retz + MOV DX,OFFSET RESGROUP:RE_INSTR + MOV AX,(OPEN SHL 8) + INT int_command + MOV DX,OFFSET TRANGROUP:NOTFND + JC REDIRERR + MOV BX,AX + MOV AL,0FFH + XCHG AL,[BX.PDB_JFN_Table] + MOV DS:[PDB_JFN_Table],AL + return + +REDIRERR: + PUSH CS + POP DS + JMP CERROR + +TESTDOREOUT: +ASSUME DS:RESGROUP + CMP [RE_OUTSTR],0 + JZ NOREOUT + CMP [RE_OUT_APP],0 + JZ REOUTCRT + MOV DX,OFFSET RESGROUP:RE_OUTSTR + MOV AX,(OPEN SHL 8) OR 1 + INT int_command + JC REOUTCRT + XOR DX,DX + XOR CX,CX + MOV BX,AX + MOV AX,(LSEEK SHL 8) OR 2 + INT int_command + JMP SHORT SET_REOUT +REOUTCRT: + MOV DX,OFFSET RESGROUP:RE_OUTSTR + XOR CX,CX + MOV AH,CREAT + INT int_command + MOV DX,OFFSET TRANGROUP:FULDIR + JC REDIRERR + MOV BX,AX +SET_REOUT: + MOV AL,0FFH + XCHG AL,[BX.PDB_JFN_Table] + MOV DS:[PDB_JFN_Table+1],AL +NOREOUT: + return + +STRCOMP: +; Compare ASCIZ DS:SI with ES:DI. +; SI,DI destroyed. + CMPSB + retnz ; Strings not equal + cmp byte ptr [SI-1],0 ; Hit NUL terminator? + retz ; Yes, strings equal + jmp short STRCOMP ; Equal so far, keep going + + + +TRANCODE ENDS + END + \ No newline at end of file diff --git a/TCODE4.ASM b/TCODE4.ASM new file mode 100644 index 0000000..a8c44a6 --- /dev/null +++ b/TCODE4.ASM @@ -0,0 +1,1002 @@ +TITLE PART4 - COMMAND Transient routines. + + INCLUDE COMSW.ASM + +.xlist +.xcref + INCLUDE DOSSYM.ASM + INCLUDE DEVSYM.ASM + INCLUDE COMSEG.ASM +.list +.cref + + INCLUDE COMEQU.ASM + + +DATARES SEGMENT PUBLIC + EXTRN RESTDIR:BYTE +DATARES ENDS + +TRANDATA SEGMENT PUBLIC + EXTRN BADDRV:BYTE,BADSWT:BYTE + EXTRN BADDAT:BYTE,NEWDAT:BYTE,BADTIM:BYTE + EXTRN DMES:BYTE,CURDAT_PRE:BYTE,CURDAT_MID:BYTE,CURDAT_POST:BYTE + EXTRN RENERR:BYTE,VERMES_PRE:BYTE,VERMES_POST:BYTE + EXTRN DIRHEAD_PRE:BYTE,DIRHEAD_POST:BYTE + EXTRN ACRLF:BYTE,BADARGS:BYTE,NOTFND:BYTE + EXTRN NEWTIM:BYTE,BADCD:BYTE,BADMKD:BYTE,CLSSTRING:BYTE + EXTRN CURTIM_PRE:BYTE,CURTIM_POST:BYTE,PauseMes:BYTE + EXTRN BADRMD:BYTE +TRANDATA ENDS + +TRANSPACE SEGMENT PUBLIC + EXTRN COMBUF:BYTE,DIRCHAR:BYTE,USERDIR1:BYTE + EXTRN BYTCNT:WORD,CURDRV:BYTE,COMSW:WORD,ARGTS:WORD + EXTRN LINCNT:BYTE,LINLEN:BYTE,FILECNT:WORD,CHARBUF:BYTE + EXTRN DIRBUF:BYTE,BITS:WORD,PATHPOS:WORD + EXTRN DESTISDIR:BYTE,DESTTAIL:WORD,DESTINFO:BYTE,FULLSCR:WORD + EXTRN INTERNATVARS:BYTE,RESSEG:WORD,TPA:WORD +TRANSPACE ENDS + + +TRANCODE SEGMENT PUBLIC BYTE +ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + + EXTRN NOTEST2:NEAR,PRINTVOL:NEAR,Print_Date:NEAR + EXTRN CERROR:NEAR,SWITCH:NEAR,PWD:NEAR,SETREST:NEAR,MESTRAN:NEAR + EXTRN NOTFNDERR:NEAR,CHKCNT:NEAR,GETKEYSTROKE:NEAR + EXTRN SETPATH:NEAR,PATHCRUNCH:NEAR,PRINT:NEAR,ZPRINT:NEAR + EXTRN DISPSIZE:NEAR,OUT:NEAR,OUT2:NEAR,ERROR_PRINT:NEAR + EXTRN SCANOFF:NEAR,OUTBYTE:NEAR,GETNUM:NEAR,ERROR_OUTPUT:NEAR + + + PUBLIC PRINT_TIME,CATALOG + PUBLIC BADCDERR,PRINT_VERSION,CLS,SAVUDIR,SAVUDIR1 + PUBLIC TYPEFIL,CRENAME,$RMDIR + PUBLIC CTIME,$CHDIR,ONESPC,DATINIT + PUBLIC $MKDIR,VERSION,RESTUDIR1 + PUBLIC RESTUDIR,CRLF2,ERASE + PUBLIC volume,date,P_date,PAUSE + + +CATALOG: + CALL OKVOLARG + MOV AL,"?" ; *.* is default file spec. + MOV DI,5DH + MOV CX,11 + REP STOSB + MOV SI,81H + CALL SWITCH + MOV DI,FCB + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 0DH ; Parse with default name and extension + INT int_command + +; Begin by processing any switches that may have been specified. +; BITS will contain any information about switches that was +; found when the command line was parsed. + +SETSWT: + MOV AX,[COMSW] ; Get switches from command + OR AX,[ARGTS] ; OR in switches from all of tail + MOV [BITS],AX + MOV BYTE PTR[FULLSCR],LINPERPAG + TEST AL,1 ; Look for W switch + MOV AL,NORMPERLIN + JZ DIR + MOV AL,WIDEPERLIN +DIR: + MOV [LINLEN],AL ; Set number of entries per line + MOV [LINCNT],AL + MOV [FILECNT],0 ; Keep track of how many files found + MOV DX,OFFSET TRANGROUP:DIRBUF ; Set Disk transfer address + MOV AH,SET_DMA + INT int_command + CALL PATHCRUNCH ; Get where we're going + PUSHF + JNC NOTEST + CMP [DESTISDIR],0 ; No CHDIRs worked + JZ NOTEST ; see if they should have + JMP BADCDERR + +NOTEST: + MOV SI,FCB + MOV DI,OFFSET TRANGROUP:DIRBUF + MOV DX,DI + MOV CX,12 + REP MOVSB + MOV AH,FCB_OPEN + INT int_command + MOV DX,OFFSET TRANGROUP:DIRHEAD_PRE ; Print "Directory of" + PUSH AX ; save return code + CALL PRINT + CALL PWD ; print the path + MOV DX,OFFSET TRANGROUP:DIRHEAD_POST + CALL PRINT + POP AX + OR AL,AL + JNZ OKDODIR ; Go ahead and dir if open fail + TEST [DIRBUF+fcb_DEVID],devid_device + JZ OKDODIR + JMP NOTFNDERR ; Can't DIR a device +OKDODIR: + MOV AH,DIR_SEARCH_FIRST + MOV BYTE PTR DS:[FCB-7],0FFH + MOV BYTE PTR DS:[FCB-1],010H + POPF + JC SHOWDIR ; Current dir + JZ DOFIRST ; FCB is *.* + MOV AL,"?" + MOV DI,5DH + MOV CX,11 + REP STOSB ; Remake default FCB + MOV SI,[DESTTAIL] + MOV DI,FCB + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 0EH ; Parse with default drive, name and extension + INT int_command + MOV AH,DIR_SEARCH_FIRST +DOFIRST: + MOV DX,FCB-7 + INT int_command + PUSH AX + CALL RESTUDIR + POP AX + JMP SHORT DIRSTART + +SHOWDIR: + MOV DX,FCB-7 ; DX -> Unopened FCB + INT int_command ; Search for a file to match FCB +DIRSTART: + INC AL ; FF = file not found + JNZ AGAIN ; Either an error or we are finished + JMP CHKCNT +NEXENTJ: + JMP NEXENT +AGAIN: + INC [FILECNT] ; Keep track of how many we find + MOV SI,OFFSET TRANGROUP:DIRBUF+8 ; SI -> information returned by sys call + CALL SHONAME + TEST BYTE PTR[BITS],WSWITCH ; W switch set? + JNZ NEXENTJ ; If so, no size, date, or time + MOV SI,OFFSET TRANGROUP:DIRBUF+8+dir_attr + TEST BYTE PTR [SI],attr_directory + JZ FILEENT + MOV DX,OFFSET TRANGROUP:DMES + CALL PRINT + JMP SHORT NOFSIZ +FILEENT: + CALL DISPSIZE ; Print size of file +NOFSIZ: + MOV AX,WORD PTR [DIRBUF+8+dir_date] ; Get date + OR AX,AX + JZ NEXENT ; Skip if no date + MOV DI,OFFSET TRANGROUP:CHARBUF + PUSH AX + MOV AX," " + STOSW + POP AX + MOV BX,AX + AND AX,1FH ; get day + MOV DL,AL + MOV AX,BX + MOV CL,5 + SHR AX,CL ; Align month + AND AL,0FH ; Get month + MOV DH,AL + MOV CL,BH + SHR CL,1 ; Align year + XOR CH,CH + ADD CX,80 ; Relative 1980 + CMP CL,100 + JB MILLENIUM + SUB CL,100 +MILLENIUM: + CALL DATE_CXDX + MOV CX,WORD PTR[DIRBUF+8+dir_time] ; Get time + JCXZ PRBUF ; Time field present? + MOV AX," " + STOSW + SHR CX,1 + SHR CX,1 + SHR CX,1 + SHR CL,1 + SHR CL,1 ; Hours in CH, minutes in CL + MOV BL,[INTERNATVARS.Time_24] + OR BL,80H ; Tell P_TIME called from DIR + CALL P_TIME ; Don't care about DX, never used with DIR +PRBUF: + XOR AX,AX + STOSB + MOV DX,OFFSET TRANGROUP:CHARBUF + CALL ZPRINT +NEXENT: + DEC [LINCNT] + JNZ SAMLIN +NEXLIN: + MOV AL,[LINLEN] + MOV [LINCNT],AL + CALL CRLF2 + TEST BYTE PTR[BITS],PSWITCH ; P switch present? + JZ SCROLL ; If not, just continue + DEC BYTE PTR[FULLSCR] + JNZ SCROLL + MOV BYTE PTR[FULLSCR],LINPERPAG + MOV DX,OFFSET TRANGROUP:PAUSEMES + CALL PRINT + CALL GetKeystroke + CALL CRLF2 +SCROLL: + MOV AH,DIR_SEARCH_NEXT + JMP SHOWDIR + +SAMLIN: + MOV AL,9 ; Output a tab + CALL OUT + JMP SHORT SCROLL + +SHONAME: + MOV DI,OFFSET TRANGROUP:CHARBUF + MOV CX,8 + REP MOVSB + MOV AL," " + STOSB + MOV CX,3 + REP MOVSB + XOR AX,AX + STOSB + PUSH DX + MOV DX,OFFSET TRANGROUP:CHARBUF + CALL ZPRINT + POP DX + return + +ONESPC: + MOV AL," " + JMP OUT + +CRLF2: + PUSH DX + MOV DX,OFFSET TRANGROUP:ACRLF +PR: + PUSH DS + PUSH CS + POP DS + CALL PRINT + POP DS + POP DX + return + +PAUSE: + MOV DX,OFFSET TRANGROUP:PAUSEMES + CALL ERROR_PRINT + CALL GetKeystroke + CALL CRLF2 + return + +ERASE: + MOV DX,OFFSET TRANGROUP:BADARGS + MOV SI,80H + LODSB + OR AL,AL + JZ ERRJ2 + CALL SCANOFF + CMP AL,13 ; RETURN KEY? + JZ ERRJ2 ; IF SO NO PARAMETERS SPECIFIED + +ERA1: + CALL PATHCRUNCH + JNC NOTEST2J + CMP [DESTISDIR],0 ; No CHDIRs worked + JZ NOTEST2J ; see if they should have +BADCDERR: + MOV DX,OFFSET TRANGROUP:BADCD +ERRJ2: + JMP CERROR + +NOTEST2J: + JMP NOTEST2 + +CRENAME: + CALL PATHCRUNCH + JNC NOTEST3 + CMP [DESTISDIR],0 ; No CHDIRs worked + JZ NOTEST3 ; see if they should have + JMP BADCDERR + +NOTEST3: + MOV SI,[PATHPOS] + MOV DI,FCB+10H + CALL SCANOFF + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H + INT int_command + CMP BYTE PTR DS:[FCB+10H+1]," " ; Check if parameter exists + MOV DX,OFFSET TRANGROUP:BADARGS + JZ ERRJ ; Error if missing parameter + MOV AH,FCB_RENAME + MOV DX,FCB + INT int_command + PUSH AX + CALL RESTUDIR + POP AX + MOV DX,OFFSET TRANGROUP:RENERR + INC AL + retnz +ERRJ: + JMP CERROR + +ASSUME DS:TRANGROUP,ES:TRANGROUP +TYPEFIL: + mov si,81H + call SCANOFF ; Skip to first non-delim + cmp al,0DH + jnz GOTTARG + jmp NOARGERR ; No args +GOTTARG: + CALL SETPATH + MOV AX,OPEN SHL 8 + INT int_command + MOV DX,OFFSET TRANGROUP:NOTFND + JC ERRJ + MOV BX,AX ; Handle + MOV DS,[TPA] + XOR DX,DX +ASSUME DS:NOTHING +TYPELP: + MOV CX,[BYTCNT] + MOV AH,READ + INT int_command + MOV CX,AX + JCXZ RET56 + PUSH BX + MOV BX,1 + MOV AH,WRITE + INT int_command + POP BX + JC ERROR_OUTPUTJ + CMP AX,CX + JZ TYPELP + DEC CX + CMP AX,CX + retz ; One less byte OK (^Z) +ERROR_OUTPUTJ: + MOV BX,1 + MOV AX,IOCTL SHL 8 + INT int_command + TEST DL,devid_ISDEV + retnz ; If device, no error message + JMP ERROR_OUTPUT + +RESTUDIR1: + PUSH DS + MOV DS,[RESSEG] +ASSUME DS:RESGROUP + CMP [RESTDIR],0 + POP DS +ASSUME DS:TRANGROUP + retz +RESTUDIR: + MOV DX,OFFSET TRANGROUP:USERDIR1 + MOV AH,CHDIR + INT int_command ; Restore users DIR + XOR AL,AL + CALL SETREST +RET56: + return + + +VOLUME: + mov si,81H + call SCANOFF ; Skip to first non-delim + CMP BYTE PTR DS:[FCB],0 ;Default drive? + JZ CHECKNOARG ;Yes + INC SI + INC SI ;Skip over d: + MOV BX,SI + CALL SCANOFF + CMP BX,SI + JNZ OKVOLARG ; If we skipped some delims at this point, OK +CHECKNOARG: + cmp al,0DH + JZ OKVOLARG +BADVOLARG: + MOV DX,OFFSET TRANGROUP:BADDRV + JMP CERROR + +OKVOLARG: + CALL CRLF2 + PUSH DS + POP ES + MOV DI,FCB-7 ; Set up extended FCB + MOV AX,-1 + STOSB + XOR AX,AX + STOSW + STOSW + STOSB + MOV AL,8 ; Look for volume label + STOSB + INC DI ; Skip drive byte + MOV CX,11 + MOV AL,'?' + REP STOSB + MOV DX,OFFSET TRANGROUP:DIRBUF + MOV AH,SET_DMA + INT int_command + MOV DX,FCB-7 + MOV AH,DIR_SEARCH_FIRST + INT int_command + JMP PRINTVOL + +VERSION: + CALL CRLF2 + CALL PRINT_VERSION + JMP CRLF2 + +PRINT_VERSION: + MOV DI,OFFSET TRANGROUP:CHARBUF + MOV SI,OFFSET TRANGROUP:VERMES_PRE + CALL MESTRAN + MOV AH,GET_VERSION + INT int_command + PUSH AX + XOR AH,AH + MOV CL,10 + DIV CL + MOV CL,4 + SHL AL,CL + OR AL,AH + MOV CX,1110H + MOV DL,AL + CALL OUTBYTE + MOV AL,'.' + STOSB + POP AX + MOV AL,AH + XOR AH,AH + MOV CL,10 + DIV CL + MOV CL,4 + SHL AL,CL + OR AL,AH + MOV CX,1010H + MOV DL,AL + CALL OUTBYTE + MOV SI,OFFSET TRANGROUP:VERMES_POST + CALL MESTRAN + XOR AX,AX + STOSB + MOV DX,OFFSET TRANGROUP:CHARBUF + JMP ZPRINT + +ASSUME DS:TRANGROUP + +CLS: + IF IBMVER + MOV BX,1 + MOV AX,IOCTL SHL 8 + INT int_command + TEST DL,devid_ISDEV + JZ ANSICLS ; If a file put out ANSI + TEST DL,devid_SPECIAL + JZ ANSICLS ; If not special CON, do ANSI + MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 29H + INT int_command + MOV DX,ES + MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 20H + INT int_command + MOV AX,ES + CMP DX,AX + JA ANSICLS ; If not default driver, do ANSI + MOV AH,11 ; Set overscan to black + XOR BX,BX + INT 16 + MOV AH,15 + INT 16 + MOV DL,AH + DEC DL + + IF KANJI + MOV DH,23 + ELSE + MOV DH,25 + ENDIF + + XOR AX,AX + MOV CX,AX + + IF KANJI + MOV BH,0 + ELSE + MOV BH,7 + ENDIF + + MOV AH,6 + INT 16 + XOR DX,DX + MOV BH,0 + MOV AH,2 + INT 16 + return + +ANSICLS: + ENDIF + + MOV SI,OFFSET TRANGROUP:CLSSTRING + LODSB + MOV CL,AL + XOR CH,CH + MOV AH,RAW_CON_IO +CLRLOOP: + LODSB + MOV DL,AL + INT int_command + LOOP CLRLOOP + return + +$CHDIR: + MOV AX,[COMSW] + OR AX,[ARGTS] + MOV DX,OFFSET TRANGROUP:BADSWT + JNZ CERRORJ3 + mov si,81H + call SCANOFF ; Skip to first non-delim + cmp al,0DH + jz PWDJ ; No args + inc si ; Skip first char + lodsw + cmp ax,(0DH SHL 8) OR ':' ; d: ? + jnz REALCD ; no +PWDJ: + jmp PWD ; Drive only specified +REALCD: + CALL SETPATH + TEST [DESTINFO],2 + JNZ BADCDERRJ + MOV AH,CHDIR + INT int_command + retnc +BADCDERRJ: + JMP BADCDERR + +$MKDIR: + CALL SETRMMK + JNZ BADMDERR + MOV AH,MKDIR + INT int_command + retnc +BADMDERR: + MOV DX,OFFSET TRANGROUP:BADMKD +CERRORJ3: + JMP CERROR + +NOARGERR: + MOV DX,OFFSET TRANGROUP:BADARGS + JMP SHORT CERRORJ3 + +SETRMMK: + mov si,81H + call SCANOFF ; Skip to first non-delim + cmp al,0DH + jz NOARGERR ; No args + MOV AX,[COMSW] + OR AX,[ARGTS] + MOV DX,OFFSET TRANGROUP:BADSWT + JNZ CERRORJ3 + CALL SETPATH + TEST [DESTINFO],2 + return + +$RMDIR: + CALL SETRMMK + JNZ BADRDERR + MOV AH,RMDIR + INT int_command + retnc +BADRDERR: + MOV DX,OFFSET TRANGROUP:BADRMD + JMP CERROR + +SAVUDIR: +; DL is drive number A=1 + MOV DI,OFFSET TRANGROUP:USERDIR1 +SAVUDIR1: + MOV AL,DL + ADD AL,'@' + CMP AL,'@' + JNZ GOTUDRV + ADD AL,[CURDRV] + INC AL ; A = 1 +GOTUDRV: + STOSB + MOV AH,[DIRCHAR] + MOV AL,DRVCHAR + STOSW + PUSH ES + POP DS +ASSUME DS:NOTHING + MOV SI,DI + MOV AH,CURRENT_DIR ; Get the Directory Text + INT int_command + retc + PUSH CS + POP DS +ASSUME DS:TRANGROUP + return + +ASSUME DS:TRANGROUP,ES:TRANGROUP + +; Date and time are set during initialization and use +; this routines since they need to do a long return + +DATINIT PROC FAR + PUSH ES + PUSH DS ; Going to use the previous stack + MOV AX,CS ; Set up the appropriate segment registers + MOV ES,AX + MOV DS,AX + MOV DX,OFFSET TRANGROUP:INTERNATVARS ;Set up internat vars + MOV AX,INTERNATIONAL SHL 8 + INT 21H + MOV WORD PTR DS:[81H],13 ; Want to prompt for date during initialization + MOV [COMBUF],COMBUFLEN ; Init COMBUF + MOV WORD PTR [COMBUF+1],0D01H + CALL DATE + CALL CTIME + POP DS + POP ES + RET +DATINIT ENDP + +; DATE - Gets and sets the time + +DATE_CXDX: + MOV BX,CX +P_DATE: + MOV AX,BX + MOV CX,DX + MOV DL,100 + DIV DL + XCHG AL,AH + XCHG AX,DX + MOV BH,"0"-" " ; Enable leading zero suppression + MOV AX,WORD PTR [INTERNATVARS.Date_tim_format] + OR AX,AX + JZ USPDAT + DEC AX + JZ EUPDAT + MOV BH,0 ; Disable leading zero suppression + CALL P_YR + CALL P_DSEP + CALL P_MON + CALL P_DSEP + CALL P_DAY + return + +USPDAT: + CALL P_MON + CALL P_DSEP + CALL P_DAY +PLST: + CALL P_DSEP + CALL P_YR + return + +EUPDAT: + CALL P_DAY + CALL P_DSEP + CALL P_MON + JMP PLST + +P_MON: + MOV AL,CH + CALL OUT2 + return + +P_DSEP: + MOV AL,BYTE PTR [INTERNATVARS.Date_sep] + STOSB + return + +P_DAY: + MOV AL,CL + CALL OUT2 + return + +P_YR: + MOV AL,DH + OR AL,AL + JZ TWODIGYR ; Two instead of 4 digit year + CALL OUT2 +TWODIGYR: + MOV AL,DL + CALL OUT2 + return + +DATE: + MOV SI,81H ; Accepting argument for date inline + CALL SCANOFF + CMP AL,13 + JZ PRMTDAT + JMP COMDAT + +PRMTDAT: + MOV DX,OFFSET TRANGROUP:CURDAT_PRE + CALL PRINT ; Print "Current date is " + CALL PRINT_DATE + MOV DX,OFFSET TRANGROUP:CURDAT_POST + CALL PRINT +GETDAT: + MOV DX,OFFSET TRANGROUP:NEWDAT + CALL ERROR_PRINT ; Print "Enter new date: " + MOV AH,STD_CON_STRING_INPUT + MOV DX,OFFSET TRANGROUP:COMBUF + INT int_command ; Get input line + CALL CRLF2 + MOV SI,OFFSET TRANGROUP:COMBUF+2 + CMP BYTE PTR[SI],13 ; Check if new date entered + retz +COMDAT: + MOV AX,WORD PTR [INTERNATVARS.Date_tim_format] + OR AX,AX + JZ USSDAT + DEC AX + JZ EUSDAT + CALL GET_YR + JC DATERRJ + CALL GET_DSEP + JC DATERRJ + CALL GET_MON + JC DATERRJ + CALL GET_DSEP + JC DATERRJ + CALL GET_DAY +DAT_SET: + JC DATERR + LODSB + CMP AL,13 + JNZ DATERR + MOV AH,SET_DATE + INT int_command + OR AL,AL + JNZ DATERR + return + +USSDAT: + CALL GET_MON + JC DATERR + CALL GET_DSEP +DATERRJ: + JC DATERR + CALL GET_DAY +TGET: + JC DATERR + CALL GET_DSEP + JC DATERR + CALL GET_YR + JMP DAT_SET + +EUSDAT: + CALL GET_DAY + JC DATERR + CALL GET_DSEP + JC DATERR + CALL GET_MON + JMP TGET + +GET_MON: + CALL GETNUM ; Get one or two digit number + retc + MOV DH,AH ; Put in position + return + +GET_DAY: + CALL GETNUM + MOV DL,AH ; Put in position + return + +GET_YR: + CALL GETNUM + retc + MOV CX,1900 + CALL GET_DSEP + PUSHF + DEC SI + POPF + JZ BIAS + CMP BYTE PTR[SI],13 + JZ BIAS + MOV AL,100 + MUL AH + MOV CX,AX + CALL GETNUM + retc +BIAS: + MOV AL,AH + MOV AH,0 + ADD CX,AX + + IF IBM AND KANJI +; +; Gross hack for PC-J machine: CMOS clock cannot handle years after 2079 +; + CMP CX,2080 + JB YearOk + STC + return +YearOk: CLC + ENDIF + return + +DATERR: + MOV DX,OFFSET TRANGROUP:BADDAT + CALL PRINT + JMP GETDAT + +GET_DSEP: + LODSB + CMP AL,'/' + retz + CMP AL,'.' + retz + CMP AL,'-' + retz + STC + return + +; TIME gets and sets the time + +CTIME: + MOV SI,81H ; Accepting argument for time inline + CALL SCANOFF + CMP AL,13 + JZ PRMTTIM + MOV BX,".:" + CALL INLINE + JMP COMTIM + +PRINT_TIME: + MOV AH,GET_TIME + INT int_command ; Get time in CX:DX + PUSH DI + PUSH ES + PUSH CS + POP ES + MOV DI,OFFSET TRANGROUP:CHARBUF + MOV BL,1 ; Always 24 hour time + CALL P_TIME + XOR AX,AX + STOSB + MOV DX,OFFSET TRANGROUP:CHARBUF + CALL ZPRINT + POP ES + POP DI + return + +P_TIME: + MOV AL,CH + TEST BL,07FH ; Ignore high bit + JNZ T24 ; 24 hr time? + MOV BH,"a" ; Assume A.M. + CMP AL,12 ; In the afternoon? + JB MORN + MOV BH,"p" + JE MORN + SUB AL,12 ; Keep it to 12 hours or less +MORN: + OR AL,AL ; Before 1 am? + JNZ T24 + MOV AL,12 +T24: + PUSH BX + MOV BH,"0"-" " ; Enable leading zero suppression + CALL OUT2 + CALL P_TSEP + MOV AL,CL + CALL OUT2 + POP BX + PUSH BX + TEST BL,80H + JNZ PAP ; If from DIR, go directly to am pm + MOV BH,0 ; Disable leading zero suppression + CALL P_TSEP + MOV AL,DH + CALL OUT2 + IF NOT IBMJAPAN + MOV AL,"." + STOSB + MOV AL,DL + CALL OUT2 + ENDIF +PAP: + POP BX + TEST BL,07FH ; Ignore high bit + retnz ; 24 hour time, no am pm + MOV AL,BH + STOSB ; Store 'a' or 'p' + return + +P_TSEP: + MOV AL,[INTERNATVARS.Time_sep] + STOSB + return + + +PRMTTIM: + MOV DX,OFFSET TRANGROUP:CURTIM_PRE + CALL PRINT ; Print "Current time is " + CALL PRINT_TIME + MOV DX,OFFSET TRANGROUP:CURTIM_POST + CALL PRINT +GETTIM: + XOR CX,CX ; Initialize hours and minutes to zero + MOV DX,OFFSET TRANGROUP:NEWTIM + MOV BX,".:" + CALL GETBUF +COMTIM: + retz ; If no time present, don't change it + JC TIMERR + MOV CX,DX + XOR DX,DX + LODSB + CMP AL,13 + JZ SAVTIM + CMP AL,BL + JZ GOTSEC + CMP AL,BH + JNZ TIMERR +GOTSEC: + CALL GETNUM + JC TIMERR + MOV DH,AH ; Position seconds + LODSB + CMP AL,13 + JZ SAVTIM + CMP AL,"." + JNZ TIMERR + CALL GETNUM + JC TIMERR + MOV DL,AH + LODSB + CMP AL,13 + JNZ TIMERR +SAVTIM: + MOV AH,SET_TIME + INT int_command + OR AL,AL + retz ; Error in time? +TIMERR: + MOV DX,OFFSET TRANGROUP:BADTIM + CALL PRINT ; Print error message + JMP GETTIM ; Try again + +GETBUF: + CALL ERROR_PRINT ; Print "Enter new time: " + MOV AH,STD_CON_STRING_INPUT + MOV DX,OFFSET TRANGROUP:COMBUF + INT int_command ; Get input line + CALL CRLF2 + MOV SI,OFFSET TRANGROUP:COMBUF+2 + CMP BYTE PTR[SI],13 ; Check if new time entered + retz +INLINE: + CALL GETNUM ; Get one or two digit number + retc + MOV DH,AH ; Put in position + LODSB + CMP AL,BL + JZ NEXT + CMP AL,BH + JZ NEXT + DEC SI ; Clears zero flag + CLC + MOV DL,0 + return ; Time may have only an hour specified + +NEXT: + CALL GETNUM + MOV DL,AH ; Put in position + return + + +TRANCODE ENDS + END + \ No newline at end of file diff --git a/TCODE5.ASM b/TCODE5.ASM new file mode 100644 index 0000000..63fb3cf --- /dev/null +++ b/TCODE5.ASM @@ -0,0 +1,953 @@ +TITLE PART5 - COMMAND Transient routines. + + INCLUDE COMSW.ASM + +.xlist +.xcref + INCLUDE DOSSYM.ASM + INCLUDE DEVSYM.ASM + INCLUDE COMSEG.ASM +.list +.cref + + INCLUDE COMEQU.ASM + +CODERES SEGMENT PUBLIC + + IF IBMVER + EXTRN EXEC_WAIT:NEAR + ENDIF + +CODERES ENDS + + +DATARES SEGMENT PUBLIC + EXTRN BATCH:WORD,BATLOC:DWORD,BATBYT:BYTE,ECHOFLAG:BYTE + EXTRN SINGLECOM:WORD,RE_OUTSTR:BYTE,PIPEFLAG:BYTE,PIPEPTR:WORD + EXTRN RE_INSTR:BYTE,RE_OUT_APP:BYTE,PARMBUF:BYTE,PIPESTR:BYTE + EXTRN LTPA:WORD,ENVIRSEG:WORD +DATARES ENDS + +TRANDATA SEGMENT PUBLIC + EXTRN PIPEEMES:BYTE,NULPATH:BYTE,NOSPACE:BYTE + EXTRN DBACK:BYTE,PROMPT_TABLE:BYTE +TRANDATA ENDS + +TRANSPACE SEGMENT PUBLIC + EXTRN PATHCNT:WORD,PATHPOS:WORD,PATHSW:WORD + EXTRN DESTISDIR:BYTE,DESTTAIL:WORD,DESTINFO:BYTE + EXTRN BATHAND:WORD,RESSEG:WORD,TPA:WORD,SWITCHAR:BYTE + EXTRN BYTCNT:WORD,COMBUF:BYTE,DIRBUF:BYTE,CHARBUF:BYTE + + + IF KANJI + EXTRN KPARSE:BYTE + ENDIF + +TRANSPACE ENDS + + +TRANCODE SEGMENT PUBLIC BYTE +ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + + IF KANJI + EXTRN TESTKANJ:NEAR + ENDIF + + EXTRN CERROR:NEAR,UPCONV:NEAR,PIPEERRSYN:NEAR,SETREST1:NEAR + EXTRN SWITCH:NEAR,SETREST1:NEAR,BATCLOSE:NEAR,MOVE_NAME:NEAR + EXTRN FIND_PROMPT:NEAR,FIND_PATH:NEAR,DELETE_PATH:NEAR + EXTRN STORE_CHAR:NEAR,SCAN_DOUBLE_NULL:NEAR,SCASB2:NEAR + EXTRN PRINT_DRIVE:NEAR,SAVUDIR:NEAR,CRLF2:NEAR,PAUSE:NEAR + + PUBLIC PRINT_B,PRINT_G,DISPSIZE,GETNUM,OUTBYTE + PUBLIC DELIM,OUT,OUT2,SETPATH,PATHCRUNCH + PUBLIC CRPRINT,SCANOFF,FCB_TO_ASCZ + PUBLIC PRINT_L,PATH,PATHCHRCMP,PRINT_ESC,PRINT_BACK + PUBLIC PRINT_EQ,PRINT,ZPRINT,PRINT_PROMPT + PUBLIC DISP32BITS,ERROR_PRINT,ERROR_OUTPUT + PUBLIC FREE_TPA,ALLOC_TPA,PRESCAN,GETBATBYT + + +FREE_TPA: +ASSUME DS:TRANGROUP,ES:NOTHING + PUSH ES + MOV ES,[TPA] + MOV AH,DEALLOC + INT int_command ; Make lots of free memory + POP ES + return + +ALLOC_TPA: +ASSUME DS:TRANGROUP,ES:RESGROUP + MOV BX,0FFFFH ; Re-allocate the transient + MOV AH,ALLOC + INT int_command + MOV AH,ALLOC + INT int_command + MOV [LTPA],AX ; Re-compute evrything + MOV [TPA],AX + MOV BX,AX + MOV AX,CS + SUB AX,BX + MOV DX,16 + MUL DX + OR DX,DX + JZ SAVSIZ2 + MOV AX,-1 +SAVSIZ2: + MOV [BYTCNT],AX + return + + +PRESCAN: ; Cook the input buffer +ASSUME DS:TRANGROUP,ES:TRANGROUP + XOR CX,CX + MOV ES,[RESSEG] +ASSUME ES:RESGROUP + MOV SI,OFFSET TRANGROUP:COMBUF+2 + MOV DI,SI + +CountQuotes: + LODSB ; get a byte + CMP AL,22h ; is it a quote? + JNZ CountEnd ; no, try for end of road + INC CH ; bump count + JMP CountQuotes ; go get next char +CountEnd: + CMP AL,13 ; end of road? + JNZ CountQuotes ; no, go back for next char + + IF KANJI + PUSH CX ; save count + MOV SI,DI ; get back beginning of buffer +KanjiScan: + LODSB ; get a byte + CALL TestKanj ; is it a leadin byte + JZ KanjiQuote ; no, check for quotes + MOV AH,AL ; save leadin + LODSB ; get trailing byte + CMP AX,8140h ; is it Kanji space + JNZ KanjiScan ; no, go get next + MOV [SI-2],2020h ; replace with spaces + JMP KanjiScan ; go get next char +KanjiQuote: + CMP AL,22h ; beginning of quoted string + JNZ KanjiEnd ; no, check for end + DEC CH ; drop count + JZ KanjiScan ; if count is zero, no quoting +KanjiQuoteLoop: + LODSB ; get next byte + CMP AL,22h ; is it another quote + JNZ KanjiQuoteLoop ; no, get another + DEC CH ; yes, drop count + JMP KanjiScan ; go get next char +KanjiEnd: + CMP AL,13 ; end of line character? + JNZ KanjiScan ; go back to beginning + POP CX ; get back original count + ENDIF + + MOV SI,DI ; restore pointer to begining +PRESCANLP: + LODSB + + IF KANJI + CALL TESTKANJ + JZ NOTKANJ6 + MOV [DI],AL + INC DI ; fake STOSB into DS + LODSB ; grab second byte + MOV [DI],AL ; fake stosb into DS + INC DI + INC CL + INC CL + JMP PRESCANLP +NOTKANJ6: + ENDIF + + CMP AL,22H ; " character + JNZ TRYGREATER + DEC CH + JZ TRYGREATER +QLOOP: + MOV [DI],AL + INC DI + INC CL + LODSB + CMP AL,22H ; " character + JNZ QLOOP + DEC CH + +TRYGREATER: + CMP AL,'>' + JNZ NOOUT + CMP BYTE PTR [SI],'>' + JNZ NOAPPND + LODSB + INC [RE_OUT_APP] ; Flag >> +NOAPPND: + CALL SCANOFF + CMP AL,0DH + JNZ GOTREOFIL + MOV WORD PTR [RE_OUTSTR],09H ; Cause an error later + JMP SHORT PRESCANEND +GOTREOFIL: + PUSH DI + MOV DI,OFFSET RESGROUP:RE_OUTSTR +SETREOUTSTR: ; Get the output redirection name + LODSB + CMP AL,0DH + JZ GOTRESTR + CALL DELIM + JZ GOTRESTR + CMP AL,[SWITCHAR] + JZ GOTRESTR + STOSB ; store it into resgroup + JMP SHORT SETREOUTSTR + +NOOUT: + CMP AL,'<' + JNZ CHKPIPE + CALL SCANOFF + CMP AL,0DH + JNZ GOTREIFIL + MOV WORD PTR [RE_INSTR],09H ; Cause an error later + JMP SHORT PRESCANEND +GOTREIFIL: + PUSH DI + MOV DI,OFFSET RESGROUP:RE_INSTR + JMP SHORT SETREOUTSTR ; Get the input redirection name + +CHKPIPE: + MOV AH,AL + CMP AH,'|' + JNZ CONTPRESCAN + INC [PIPEFLAG] + CALL SCANOFF + CMP AL,0DH + JZ PIPEERRSYNJ5 + CMP AL,'|' ; Double '|'? + JNZ CONTPRESCAN +PIPEERRSYNJ5: + PUSH ES + POP DS ; DS->RESGROUP + JMP PIPEERRSYN + +GOTRESTR: + XCHG AH,AL + CMP BYTE PTR ES:[DI-1],':' ; Trailing ':' OK on devices + JNZ NOTTRAILCOL + DEC DI ; Back up over trailing ':' +NOTTRAILCOL: + XOR AL,AL + STOSB ; NUL terminate the string + POP DI ; Remember the start +CONTPRESCAN: + MOV [DI],AH ; "delete" the redirection string + INC DI + CMP AH,0DH + JZ PRESCANEND + INC CL + JMP PRESCANLP +PRESCANEND: + CMP [PIPEFLAG],0 + JZ ISNOPIPE + MOV DI,OFFSET RESGROUP:PIPESTR + MOV [PIPEPTR],DI + MOV SI,OFFSET TRANGROUP:COMBUF+2 + CALL SCANOFF +PIPESETLP: ; Transfer the pipe into the resident pipe buffer + LODSB + STOSB + CMP AL,0DH + JNZ PIPESETLP +ISNOPIPE: + MOV [COMBUF+1],CL + CMP [PIPEFLAG],0 + PUSH CS + POP ES + return + +ASSUME DS:TRANGROUP,ES:TRANGROUP + +PATHCHRCMP: + CMP [SWITCHAR],'/' + JZ NOSLASHT + CMP AL,'/' + retz +NOSLASHT: + CMP AL,'\' + return + +PATHCRUNCH: +; Drive taken from FCB +; DI = Dirsave pointer +; +; Zero set if path dir, CHDIR to this dir, FCB filled with ? +; NZ set if path/file, CHDIR to file, FCB has file (parsed fill ' ') +; [DESTTAIL] points to parse point +; Carry set if no CHDIRs worked, FCB not altered. +; DESTISDIR set non zero if PATHCHRs in path (via SETPATH) + + MOV DL,DS:[FCB] + CALL SAVUDIR + CALL SETPATH + TEST [DESTINFO],2 + JNZ TRYPEEL ; If ? or * cannot be pure dir + MOV AH,CHDIR + INT int_command + JC TRYPEEL + CALL SETREST1 + MOV AL,"?" ; *.* is default file spec if pure dir + MOV DI,5DH + MOV CX,11 + REP STOSB + XOR AL,AL ; Set zero + return + +TRYPEEL: + MOV SI,[PATHPOS] + DEC SI ; Point at NUL + MOV AL,[SI-1] + + IF KANJI + CMP [KPARSE],0 + JNZ DELSTRT ; Last char is second KANJI byte, might be '\' + ENDIF + + CALL PATHCHRCMP + JZ PEELFAIL ; Trailing '/' + + IF KANJI +DELSTRT: + MOV CX,SI + MOV SI,DX + PUSH DX +DELLOOP: + CMP SI,CX + JZ GOTDELE + LODSB + CALL TESTKANJ + JZ NOTKANJ8 + INC SI + JMP DELLOOP + +NOTKANJ8: + CALL PATHCHRCMP + JNZ DELLOOP + MOV DX,SI + DEC DX + JMP DELLOOP + +GOTDELE: + MOV SI,DX + POP DX + CMP SI,DX + JZ BADRET + MOV CX,SI + MOV SI,DX +DELLOOP2: ; Set value of KPARSE + CMP SI,CX + JZ KSET + MOV [KPARSE],0 + LODSB + CALL TESTKANJ + JZ DELLOOP2 + INC SI + INC [KPARSE] + JMP DELLOOP2 + +KSET: + ELSE +DELLOOP: + CMP SI,DX + JZ BADRET + MOV AL,[SI] + CALL PATHCHRCMP + JZ TRYCD + DEC SI + JMP SHORT DELLOOP + ENDIF + +TRYCD: + CMP BYTE PTR [SI+1],'.' + JZ PEELFAIL ; If . or .., pure cd should have worked + mov al,[si-1] + CMP al,DRVCHAR ; Special case dDRVCHAR,DIRCHARfile + JZ BADRET + + IF KANJI + CMP [KPARSE],0 + JNZ NOTDOUBLESL ; Last char is second KANJI byte, might be '\' + ENDIF + + CALL PATHCHRCMP + JNZ NOTDOUBLESL +PEELFAIL: + STC ; // + return +NOTDOUBLESL: + MOV BYTE PTR [SI],0 + MOV AH,CHDIR + INT int_command + JNC CDSUCC + return + +BADRET: + MOV AL,[SI] + CALL PATHCHRCMP ; Special case 'DIRCHAR'file + STC + retnz + XOR BL,BL + XCHG BL,[SI+1] + MOV AH,CHDIR + INT int_command + retc + MOV [SI+1],BL +CDSUCC: + CALL SETREST1 + INC SI ; Reset zero + MOV [DESTTAIL],SI + MOV DI,FCB + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 02H ; Parse with default drive + INT int_command + return + + +DISPSIZE: + MOV SI,WORD PTR[DIRBUF+29+7] + MOV DI,WORD PTR[DIRBUF+31+7] + +DISP32BITS: +; Prints the 32-bit number DI:SI on the console in decimal. Uses a total +; of 9 digit positions with leading blanks. + XOR AX,AX + MOV BX,AX + MOV BP,AX + MOV CX,32 +CONVLP: + SHL SI,1 + RCL DI,1 + XCHG AX,BP + CALL CONVWRD + XCHG AX,BP + XCHG AX,BX + CALL CONVWRD + XCHG AX,BX + ADC AL,0 + LOOP CONVLP + +; Conversion complete. Print 9-digit number. + + MOV DI,OFFSET TRANGROUP:CHARBUF + MOV CX,1810H ; Allow leading zero blanking for 8 digits + XCHG DX,AX + CALL DIGIT + XCHG AX,BX + CALL OUTWORD + XCHG AX,BP + CALL OUTWORD + XOR AX,AX + STOSB + MOV DX,OFFSET TRANGROUP:CHARBUF + JMP ZPRINT + +OUTWORD: + PUSH AX + MOV DL,AH + CALL OUTBYTE + POP DX +OUTBYTE: + MOV DH,DL + SHR DL,1 + SHR DL,1 + SHR DL,1 + SHR DL,1 + CALL DIGIT + MOV DL,DH +DIGIT: + AND DL,0FH + JZ BLANKZER + MOV CL,0 +BLANKZER: + DEC CH + AND CL,CH + OR DL,30H + SUB DL,CL + MOV AL,DL + STOSB + return + +CONVWRD: + ADC AL,AL + DAA + XCHG AL,AH + ADC AL,AL + DAA + XCHG AL,AH + return + + +GETBATBYT: +; Get one byte from the batch file and return it in AL. End-of-file +; returns and ends batch mode. DS must be set to resident segment. +; AH, CX, DX destroyed. +ASSUME DS:RESGROUP + ADD WORD PTR [BATLOC],1 ; Add one to file location + ADC WORD PTR [BATLOC+2],0 + PUSH BX + MOV DX,OFFSET RESGROUP:BATBYT + MOV BX,[BATHAND] + MOV AH,READ + MOV CX,1 + INT int_command ; Get one more byte from batch file + POP BX + MOV CX,AX + JC BATEOF + JCXZ BATEOF + MOV AL,[BATBYT] + CMP AL,1AH + retnz +BATEOF: + PUSH ES + MOV ES,[BATCH] ; Turn off batch + MOV AH,DEALLOC + INT int_command ; free up the batch piece + POP ES + MOV [BATCH],0 ; AFTER DEALLOC in case of ^C + CALL BATCLOSE + MOV AL,0DH ; If end-of-file, then end of line + CMP [SINGLECOM],0FFF0H ; See if we need to set SINGLECOM + JNZ NOSETSING2 + MOV [SINGLECOM],-1 ; Cause termination +NOSETSING2: + MOV [ECHOFLAG],1 + return +ASSUME DS:TRANGROUP + +SCANOFF: + LODSB + CALL DELIM + JZ SCANOFF + DEC SI ; Point to first non-delimiter + return + +DELIM: + CMP AL," " + retz + CMP AL,"=" + retz + CMP AL,"," + retz + CMP AL,";" + retz + CMP AL,9 ; Check for TAB character + return + + +PRINT_PROMPT: + PUSH DS + PUSH CS + POP DS ; MAKE SURE DS IS IN TRANGROUP + + PUSH ES + CALL FIND_PROMPT ; LOOK FOR PROMPT STRING + JC PP0 ; CAN'T FIND ONE + CMP BYTE PTR ES:[DI],0 + JNZ PP1 +PP0: + CALL PRINT_DRIVE ; USE DEFAULT PROMPT + MOV AL,SYM + CALL OUT + JMP SHORT PP5 + +PP1: + MOV AL,ES:[DI] ; GET A CHAR + INC DI + OR AL,AL + JZ PP5 ; NUL TERMINATED + CMP AL,"$" ; META CHARACTER? + JZ PP2 ; NOPE +PPP1: + CALL OUT + JMP PP1 + +PP2: + MOV AL,ES:[DI] + INC DI + MOV BX,OFFSET TRANGROUP:PROMPT_TABLE-3 + OR AL,AL + JZ PP5 + +PP3: + ADD BX,3 + CALL UPCONV + CMP AL,[BX] + JZ PP4 + CMP BYTE PTR [BX],0 + JNZ PP3 + JMP PP1 + +PP4: + PUSH ES + PUSH DI + PUSH CS + POP ES + CALL [BX+1] + POP DI + POP ES + JMP PP1 + +PP5: + POP ES ; RESTORE SEGMENTS + POP DS + return + +PRINT_BACK: + MOV DX,OFFSET TRANGROUP:DBACK + JMP ZPRINT + +PRINT_EQ: + MOV AL,"=" + JMP SHORT OUTV +PRINT_ESC: + MOV AL,1BH + JMP SHORT OUTV +PRINT_G: + MOV AL,">" + JMP SHORT OUTV +PRINT_L: + MOV AL,"<" + JMP SHORT OUTV +PRINT_B: + MOV AL,"|" +OUTV: + JMP OUT + +SETPATH: +; Get an ASCIZ argument from the unformatted parms +; DESTISDIR set if pathchars in string +; DESTINFO set if ? or * in string + MOV SI,80H + LODSB + XOR AH,AH + MOV [PATHCNT],AX + MOV [PATHPOS],SI +GETPATH: + MOV [DESTINFO],0 + MOV [DESTISDIR],0 + MOV SI,[PATHPOS] + MOV CX,[PATHCNT] + MOV DX,SI + JCXZ PATHDONE + PUSH CX + PUSH SI + CALL SWITCH + MOV [PATHSW],AX + POP BX + SUB BX,SI + POP CX + ADD CX,BX + MOV DX,SI +SKIPPATH: + + IF KANJI + MOV [KPARSE],0 +SKIPPATH2: + ENDIF + + JCXZ PATHDONE + DEC CX + LODSB + + IF KANJI + CALL TESTKANJ + JZ TESTPPSEP + DEC CX + INC SI + INC [KPARSE] + JMP SKIPPATH2 + +TESTPPSEP: + ENDIF + + CALL PATHCHRCMP + JNZ TESTPMETA + INC [DESTISDIR] +TESTPMETA: + CMP AL,'?' + JNZ TESTPSTAR + OR [DESTINFO],2 +TESTPSTAR: + CMP AL,'*' + JNZ TESTPDELIM + OR [DESTINFO],2 +TESTPDELIM: + CALL DELIM + JZ PATHDONEDEC + CMP AL,[SWITCHAR] + JNZ SKIPPATH +PATHDONEDEC: + DEC SI +PATHDONE: + XOR AL,AL + XCHG AL,[SI] + INC SI + CMP AL,0DH + JNZ NOPSTORE + MOV [SI],AL ;Don't loose the CR +NOPSTORE: + MOV [PATHPOS],SI + MOV [PATHCNT],CX + return + +PGETARG: + MOV SI,80H + LODSB + OR AL,AL + retz + CALL PSCANOFF + CMP AL,13 + return + +PSCANOFF: + LODSB + CALL DELIM + JNZ PSCANOFFD + CMP AL,';' + JNZ PSCANOFF ; ';' is not a delimiter +PSCANOFFD: + DEC SI ; Point to first non-delimiter + return + +PATH: + CALL FIND_PATH + CALL PGETARG ; Pre scan for arguments + JZ DISPPATH ; Print the current path + CALL DELETE_PATH ; DELETE ANY OFFENDING NAME + CALL SCAN_DOUBLE_NULL + CALL MOVE_NAME ; MOVE IN PATH= + CALL PGETARG + CMP AL,';' ; NUL path argument? + JZ GOTPATHS +PATHSLP: ; Get the user specified path + LODSB + CMP AL,0DH + JZ GOTPATHS + + IF KANJI + CALL TESTKANJ + JZ NOTKANJ2 + CALL STORE_CHAR + LODSB + CALL STORE_CHAR + JMP SHORT PATHSLP + +NOTKANJ2: + ENDIF + + CALL UPCONV + CMP AL,';' ; ';' not a delimiter on PATH + JZ NOTDELIM + CALL DELIM + JZ GOTPATHS +NOTDELIM: + CALL STORE_CHAR + JMP SHORT PATHSLP + +GOTPATHS: + XOR AX,AX + STOSW + return + +DISPPATH: + CALL PRINT_PATH + CALL CRLF2 + return + +PRINT_PATH: + CMP BYTE PTR ES:[DI],0 + JNZ PATH1 +PATH0: + MOV DX,OFFSET TRANGROUP:NULPATH + PUSH CS + POP DS + JMP PRINT +PATH1: + PUSH ES + POP DS + SUB DI,5 + MOV DX,DI +ASSUME DS:RESGROUP + CALL SCASB2 ; LOOK FOR NUL + CMP CX,0FFH + JZ PATH0 + JMP ZPRINT + +FCB_TO_ASCZ: ; Convert DS:SI to ASCIZ ES:DI + MOV CX,8 +MAINNAME: + LODSB + CMP AL,' ' + JZ SKIPSPC + STOSB +SKIPSPC: + LOOP MAINNAME + LODSB + CMP AL,' ' + JZ GOTNAME + MOV AH,AL + MOV AL,'.' + STOSB + XCHG AL,AH + STOSB + MOV CL,2 +EXTNAME: + LODSB + CMP AL,' ' + JZ GOTNAME + STOSB + LOOP EXTNAME + +GOTNAME: + XOR AL,AL + STOSB + return + +GETNUM: + CALL INDIG + retc + MOV AH,AL ; Save first digit + CALL INDIG ; Another digit? + JC OKRET + AAD ; Convert unpacked BCD to decimal + MOV AH,AL +OKRET: + OR AL,1 + return + +INDIG: + MOV AL,BYTE PTR[SI] + SUB AL,"0" + retc + CMP AL,10 + CMC + retc + INC SI + return + + +OUT2: ; Output binary number as two ASCII digits + AAM ; Convert binary to unpacked BCD + XCHG AL,AH + OR AX,3030H ; Add "0" bias to both digits + CMP AL,"0" ; Is MSD zero? + JNZ NOSUP + SUB AL,BH ; Suppress leading zero if enabled +NOSUP: + MOV BH,0 ; Disable zero suppression + STOSW + return + +OUT: +; Print char in AL without affecting registers + XCHG AX,DX + PUSH AX + CALL OUT_CHAR + POP AX + XCHG AX,DX + return + +OUT_CHAR: + PUSH DS + PUSH DX + PUSH CX + PUSH BX + PUSH AX + PUSH CS + POP DS + MOV BX,OFFSET TRANGROUP:CHARBUF + MOV [BX],DL + MOV DX,BX + MOV BX,1 + MOV CX,BX + MOV AH,WRITE + INT int_command + POP AX + POP BX + POP CX + POP DX + POP DS + return + + +ERROR_PRINT: + PUSH AX + PUSH BX + MOV AL,"$" + MOV BX,2 ;STD ERROR + JMP SHORT STRING_OUT + +CRPRINT: + PUSH AX + MOV AL,13 + JMP SHORT Z$PRINT +PRINT: ;$ TERMINATED STRING + PUSH AX + MOV AL,"$" + JMP SHORT Z$PRINT +ZPRINT: + PUSH AX + XOR AX,AX ;NUL TERMINATED STRING +Z$PRINT: + PUSH BX + MOV BX,1 ;STD CON OUT +; +; output string terminated by AL to handle BX, DS:DX points to string +; +STRING_OUT: + PUSH CX + PUSH DI + MOV DI,DX + MOV CX,-1 + PUSH ES + PUSH DS + POP ES + REPNZ SCASB ; LOOK FOR TERMINATOR + POP ES + NEG CX + DEC CX + DEC CX +; +; WRITE CHARS AT DS:DX TO HANDLE IN BX, COUNT IN CX +; + MOV AH,WRITE + INT int_command + JC ERROR_OUTPUT + CMP AX,CX + JNZ ERROR_OUTPUT + POP DI + POP CX + POP BX + POP AX + return + +ERROR_OUTPUT: + PUSH CS + POP DS +ASSUME DS:TRANGROUP + MOV ES,[RESSEG] +ASSUME ES:RESGROUP + MOV DX,OFFSET TRANGROUP:NOSPACE + CMP [PIPEFLAG],0 + JZ GO_TO_ERROR + MOV [PIPEFLAG],0 + MOV DX,OFFSET TRANGROUP:PIPEEMES +GO_TO_ERROR: + JMP CERROR + + +TRANCODE ENDS + END + \ No newline at end of file diff --git a/TDATA.ASM b/TDATA.ASM new file mode 100644 index 0000000..9a4af2e --- /dev/null +++ b/TDATA.ASM @@ -0,0 +1,243 @@ +TITLE COMMAND Transient Initialized DATA + + INCLUDE COMSW.ASM +.xlist +.xcref + INCLUDE COMSEG.ASM +.list +.cref + + INCLUDE IFEQU.ASM + +TRANCODE SEGMENT PUBLIC + EXTRN PRINT_DATE:NEAR,PRINT_TIME:NEAR,PRINT_DEFAULT_DIRECTORY:NEAR + EXTRN PRINT_DRIVE:NEAR,PRINT_VERSION:NEAR,PRINT_G:NEAR + EXTRN PRINT_L:NEAR,PRINT_B:NEAR,CRLF2:NEAR,OUT:NEAR,PRINT_ESC:NEAR + EXTRN PRINT_BACK:NEAR,PRINT_EQ:NEAR + + EXTRN IFNOT:NEAR,IFERLEV:NEAR,IFEXISTS:NEAR + + EXTRN CATALOG:NEAR,CRENAME:NEAR,ERASE:NEAR,TYPEFIL:NEAR + EXTRN TCOMMAND:NEAR,COPY:NEAR,PAUSE:NEAR,DATE:NEAR,CTIME:NEAR + EXTRN VERSION:NEAR,VOLUME:NEAR,$CHDIR:NEAR,$MKDIR:NEAR,$RMDIR:NEAR + EXTRN CNTRLC:NEAR,VERIFY:NEAR,ADD_NAME_TO_ENVIRONMENT:NEAR + EXTRN ADD_PROMPT:NEAR,PATH:NEAR,$EXIT:NEAR,CTTY:NEAR,ECHO:NEAR + EXTRN GOTO:NEAR,SHIFT:NEAR,$IF:NEAR,$FOR:NEAR,CLS:NEAR +TRANCODE ENDS + +; Data for transient portion + +TRANDATA SEGMENT PUBLIC BYTE + + PUBLIC BADBAT,NEEDBAT,BADNAM,RENERR,NOTFND,NOSPACE,ENVERR,FULDIR + PUBLIC OVERWR,LOSTERR,DIRMES_PRE,DIRMES_POST,BADDRV,PAUSEMES,BADSWT + PUBLIC COPIED_PRE,COPIED_POST,BYTMES_PRE,BYTMES_POST + PUBLIC WEEKTAB,BADDAT,NEWDAT,BADTIM,NEWTIM,SUREMES,CURDAT_MID + PUBLIC CURDAT_PRE,CURDAT_POST,CURTIM_PRE,CURTIM_POST,VERMES_POST + PUBLIC DMES,VERMES_PRE,VOLMES,GOTVOL,NOVOL,BADCD,BADMKD,BADRMD + PUBLIC BAD_ON_OFF,NULPATH,PATH_TEXT,PROMPT_TEXT,BADPMES + PUBLIC BADDEV,BADLAB,SYNTMES,FORNESTMES,PIPEEMES,INBDEV,OFFMES + PUBLIC ONMES,CTRLCMES,VERIMES,ECHOMES,BADCPMES,BADARGS,DEVWMES + PUBLIC ACRLF,DBACK,CLSSTRING,PROMPT_TABLE,IFTAB,COMTAB + PUBLIC TRANDATAEND,DIRHEAD_PRE,DIRHEAD_POST + + ORG 0 +ZERO = $ +BADBAT DB 13,10,"Batch file missing",13,10,"$" +NEEDBAT DB 13,10,"Insert disk with batch file" + DB 13,10,"and press any key when ready",13,10,"$" +BADNAM DB "Bad command or file name",13,10,"$" +RENERR DB "Duplicate file name or " +NOTFND DB "File not found",13,10,"$" +NOSPACE DB "Insufficient disk space",13,10,"$" +ENVERR DB "Out of environment space",13,10,"$" +FULDIR DB "File creation error",13,10,"$" +OVERWR DB "File cannot be copied onto itself",13,10,"$" +LOSTERR DB "Content of destination lost before copy",13,10,"$" + +;"COPIED_PRE<# files copied>COPIED_POST" +COPIED_POST DB " File(s) copied",13,10 ŠCOPIED_PRE DB "$" + +;"DIRMES_PRE<# files in dir>DIRMES_POST" +DIRMES_POST DB " File(s) " +DIRMES_PRE DB "$" + +;"BYTMES_PRE<# free bytes>BYTMES_POST" +BYTMES_POST DB " bytes free",13,10 +BYTMES_PRE DB "$" + +BADDRV DB "Invalid drive specification",13,10,"$" +PAUSEMES DB "Strike a key when ready . . . $" +BADSWT DB "Invalid parameter",13,10,"$" +WEEKTAB DB "SunMonTueWedThuFriSat" +BADDAT DB 13,10,"Invalid date$" + +;"CURDAT_PRECURDAT_MIDCURDAT_POST" +;Note: CURDAT_MID also appears in the date printed via PROMPT command +CURDAT_PRE DB "Current date is " +CURDAT_MID LABEL BYTE +CURDAT_POST DB "$" + +NEWDAT DB 13,10,"Enter new date: $" +BADTIM DB 13,10,"Invalid time$" + +;"CURTIM_PRECURTIM_POST" +CURTIM_PRE DB "Current time is " +CURTIM_POST DB "$" + +NEWTIM DB 13,10,"Enter new time: $" +SUREMES DB "Are you sure (Y/N)? $" +DMES DB " $" + +;"VERMES_PREVERMES_POST" + IF IBMVER +VERMES_PRE DB "TeleVideo Personal Computer DOS Version " + ENDIF + IF MSVER +VERMES_PRE DB "MS-DOS Version " + ENDIF +VERMES_POST DB "$" + +VOLMES DB " Volume in drive $" +GOTVOL DB " is $" +NOVOL DB " has no label$" + +BADCD DB "Invalid directory",13,10,"$" +BADMKD DB "Unable to create directory",13,10,"$" +BADRMD DB "Invalid path, not directory,",13,10 + DB "or directory not empty",13,10,"$" +BAD_ON_OFF DB "Must specify ON or OFF" ;Note Run over to next message + +;"DIRHEAD_PREDIRHEAD_POST" +DIRHEAD_POST DB 13,10,"$" +DIRHEAD_PRE DB " Directory of $" Š +NULPATH DB "No Path $" +PATH_TEXT DB "PATH=" +PROMPT_TEXT DB "PROMPT=" +BADPMES DB "Invalid drive in search path",13,10,"$" +BADDEV DB "Invalid device",13,10,"$" +BADLAB DB "Label not found",13,10,"$" +SYNTMES DB "Syntax error",13,10,"$" +FORNESTMES DB 13,"FOR cannot be nested",13,10,"$" +PIPEEMES DB "Intermediate file error during pipe",13,10,"$" +INBDEV DB "Cannot do binary reads from a device",13,10,"$" +OFFMES DB "off",13,10,"$" +ONMES DB "on",13,10,"$" +CTRLCMES DB "BREAK is $" +VERIMES DB "VERIFY is $" +ECHOMES DB "ECHO is $" +BADCPMES DB "Invalid path or file name",13,10,"$" +BADARGS DB "Invalid number of parameters",13,10,"$" +DEVWMES DB "Error writing to device" +ACRLF DB 13,10,"$" +DBACK DB 8," ",8,0 ; DESTRUCTIVE BACK SPACE + +CLSSTRING DB 4,01BH,"[2J" ; ANSI Clear screen + +PROMPT_TABLE LABEL BYTE + DB "D" + DW OFFSET TRANGROUP:PRINT_DATE + DB "T" + DW OFFSET TRANGROUP:PRINT_TIME + DB "P" + DW OFFSET TRANGROUP:PRINT_DEFAULT_DIRECTORY + DB "N" + DW OFFSET TRANGROUP:PRINT_DRIVE + DB "V" + DW OFFSET TRANGROUP:PRINT_VERSION + DB "G" + DW OFFSET TRANGROUP:PRINT_G + DB "L" + DW OFFSET TRANGROUP:PRINT_L + DB "B" + DW OFFSET TRANGROUP:PRINT_B + DB "_" + DW OFFSET TRANGROUP:CRLF2 + DB "$" + DW OFFSET TRANGROUP:OUT + DB "E" + DW OFFSET TRANGROUP:PRINT_ESC + DB "H" + DW OFFSET TRANGROUP:PRINT_BACK + DB "Q" + DW OFFSET TRANGROUP:PRINT_EQ + DB 0 ; NUL TERMINATED + +IFTAB LABEL BYTE ; Table of IF conditionals + DB 3,"NOT" ; First byte is count Š DW OFFSET TRANGROUP:IFNOT + DB 10,"ERRORLEVEL" + DW OFFSET TRANGROUP:IFERLEV + DB 5,"EXIST" + DW OFFSET TRANGROUP:IFEXISTS + DB 0 + +COMTAB DB 4,"DIR",1 ; Table for internal command names + DW OFFSET TRANGROUP:CATALOG + DB 7,"RENAME",1 + DW OFFSET TRANGROUP:CRENAME + DB 4,"REN",1 + DW OFFSET TRANGROUP:CRENAME + DB 6,"ERASE",1 + DW OFFSET TRANGROUP:ERASE + DB 4,"DEL",1 + DW OFFSET TRANGROUP:ERASE + DB 5,"TYPE",1 + DW OFFSET TRANGROUP:TYPEFIL + DB 4,"REM",0 + DW OFFSET TRANGROUP:TCOMMAND + DB 5,"COPY",1 + DW OFFSET TRANGROUP:COPY + DB 6,"PAUSE",0 + DW OFFSET TRANGROUP:PAUSE + DB 5,"DATE",0 + DW OFFSET TRANGROUP:DATE + DB 5,"TIME",0 + DW OFFSET TRANGROUP:CTIME + DB 4,"VER",0 + DW OFFSET TRANGROUP:VERSION + DB 4,"VOL",1 + DW OFFSET TRANGROUP:VOLUME + DB 3,"CD",1 + DW OFFSET TRANGROUP:$CHDIR + DB 6,"CHDIR",1 + DW OFFSET TRANGROUP:$CHDIR + DB 3,"MD",1 + DW OFFSET TRANGROUP:$MKDIR + DB 6,"MKDIR",1 + DW OFFSET TRANGROUP:$MKDIR + DB 3,"RD",1 + DW OFFSET TRANGROUP:$RMDIR + DB 6,"RMDIR",1 + DW OFFSET TRANGROUP:$RMDIR + DB 6,"BREAK",0 + DW OFFSET TRANGROUP:CNTRLC + DB 7,"VERIFY",0 + DW OFFSET TRANGROUP:VERIFY + DB 4,"SET",0 + DW OFFSET TRANGROUP:ADD_NAME_TO_ENVIRONMENT + DB 7,"PROMPT",0 + DW OFFSET TRANGROUP:ADD_PROMPT + DB 5,"PATH",0 + DW OFFSET TRANGROUP:PATH Š DB 5,"EXIT",0 + DW OFFSET TRANGROUP:$EXIT + DB 5,"CTTY",1 + DW OFFSET TRANGROUP:CTTY + DB 5,"ECHO",0 + DW OFFSET TRANGROUP:ECHO + DB 5,"GOTO",0 + DW OFFSET TRANGROUP:GOTO + DB 6,"SHIFT",0 + DW OFFSET TRANGROUP:SHIFT + DB 3,"IF",0 + DW OFFSET TRANGROUP:$IF + DB 4,"FOR",0 + DW OFFSET TRANGROUP:$FOR + DB 4,"CLS",0 + DW OFFSET TRANGROUP:CLS + DB 0 ; Terminate command table + +TRANDATAEND LABEL BYTE + +TRANDATA ENDS + END + \ No newline at end of file diff --git a/TIME.ASM b/TIME.ASM new file mode 100644 index 0000000000000000000000000000000000000000..f1e4a1cadb97a693f0f24566f580fefaefef7998 GIT binary patch literal 7040 zcmcEK<+4@?$;?evNX$!7NJ%V7RY)t%OD@UG&ns3)%P&&!4R-Ml=H;^H<>KY?^mFzJ zb#Ya2@edAmb=PwY_63PL`@6U*KtZspyRWNXh=NmOh^sZW6cs=>+G$KTmo#|6_U7sp6v zzYr{TLmuHa;1 zt>BVal4@wCP?TCyT9j9;P?C|VkX%|+l$uupNnn|I3XTyva4~SCWacTjM1azwf`Vg& zg04a&1o-;;`nrICf(xOxaP!xlG?C0tj#LERspe~3+spA@K z<>w#b;pyiN30;r@0inSjAlf+sQ_M9OA?EDp;{#F$3r>VgfPVl;LIGKIum@PNg0qi~ zAy^VhSo=bKQ@(uqL81akW^WciZBvcI~LIhG(!VQi!-311u6k@(dr{El6ke6Bx&FN_hnI#GtiNy-Z8Hsu6sVREA zT-Kq*sm0&|z&S!k!6iZu*-fw<73_)d1We2cDVM?G&?!R4-_0%9H3U>Afol>gPW0t{Q|lZ7D`7z)5CIJ}mk1qD!2=QkVVGh^RN>6Lvi$5+1%+VO5KvGd42L<+1u47x zxCDcYQV90ciG~#7u_ytGQI5b&cX18#^am9dMqvF4pg>kg&MzuTO@72x6H=)ZC*~rRdtOnHKnrpWF)~7U8_867y{Bbt zpkVD+nwykb1S&s4m5D-To`Ru~0i>2e==O31wH_1{z=lH12b0#G>3R7@U}u%&=PTqS z7NsLO1r|1-+z9f9jw4dig{2teFo%gD=W3XkO9a?PIAI-}Se6RTc?f3`NX*U=I&i;( z%)#P!6Lg=uctQ$KXLReG^K%PIOHvi`;NfSY3o0QMO7k*HiV<#tmxw6k7hzG517X9{dR6V5pI4Sz1S(Hq-Un4B zWiAmqMg|7FT*2N}2uYaV zf?Y#EEk}d|Jk-$}D~=@!IjM=oB?^fp3Tc@|#U;=RH8T(FR!kGH!~v*Mc60)}N7Rs*#H^TDM$QlSAWtzFPFF|-cIEKw-W%*jzm%Pc{7-wSFw$V8m8bl2AK_M+?FNgl%|5JCg%t}1;>=E(qd4q%1bW+mm+SdNkyfJ zMU~*TV@XD4F*s-GA)Ez^8BpI9Qjdc&Z!9=b^KvmoPBhVLs7xn zIU_YW8*E8VYGMJ{5==WBeRPbV9Z!%UUVf13IM^}F%@q>fAYlb-BMVSPUJRNq_EUQ>MKO}ID#V-Vkv^O_Q}uB23ZZO%)m(+VF@e~I{KiLORxZT^wH5p?wDE! zr51yOIJKxKzepi1Cox?|0i0Ab^AwU3i;=P(a!xfxI7q?T6|6NgO##%J%1z9x1Vu7( zxd81!L!%1eR+ys@O;u12NC#d-gM&ILza#@>AhFqdu_og{83s z^9LvdP&)a(paC9G6^A`PVDUF3;Uiq;;tFZ|U=-wz$zVT#a~wDo6f1zM=ghoxNO6l& zO%U=Ris!(_A)J8hJ4oz9g2&n=5nO$vDJROsVEgd67peV*;&X6>WafdIiYbYe3MKg^ zi8%>LEb}9%fF3TO1~9mJjivp7 zH2i?Dm2d~!9HAKAf44h7fO*Ez2hu`(B_L0>Gyr3mDS7|^ literal 0 HcmV?d00001 diff --git a/TSPC.ASM b/TSPC.ASM new file mode 100644 index 0000000000000000000000000000000000000000..85f02e79afba750dbbe27dfe0b6dda7e16eb67e9 GIT binary patch literal 4480 zcmWIX4DoSQP*8C8_w{x3b5RH>O3W+HOwB7%2+hmP%Ph%E%*m`uO;K=h3~}V;;^k6+ z0#83@pHLT9kiOt>J;z{QUM{_goXp}95S?6g@096zZk}r9y*UgIqj=40T*1T%7|PLp*dmTpeAU9esRsf?R`xUEOs; z0vvUM!#zWsJsg7&K8G3S;u!>z0BetTba4sN33B#;Fq}QSU4p`Nf?Qnv-E=(N{QN`Q zd>q|%+&q0kA_Fi@at;jwDR=hwb9M~T32+SZHPmqoa(4zZjX>@V4hIPs2J5)E28TeL zglUXpkh@W^j-!tcL;*-gNU)AG*lLhIXCMDyR~Mb&09R*_bxx5X&VC`7#`r~qIJ&s# zxCI4=1P3{L==ga0Is1ixC?8ipkRMz@T#(m6feA9$&DqIF$J52f)eqA&PZyB;!R`hV zevZDbV1}Es6PR}K4AOD;5Ag>X9uV#VGSfA})y>%n(<~RyAdqx0ly>qA3DyBc9LPN& zI=~;o4-VIH3-$2{cE%QKuE8N;jzN%+^aL3Nc15sf6qpWi^z;EUJpJ7K!3?KRH!Lo3 z4G!^e^m75L@C}ephz7MC&blHC&V?#H^|k|1=BRgU}sNHodBQEU>)ZG7sn7+9p``$ zPhVFZCr5~{!QOK9(Q)+w1-+{eDBy#=16*8vFbxa#4-Im5)d>!9boR!Sg=b|~KP(RM z^b2tf@^b`77;=vGbW>39bn?YCF38_E9+HFoed9d?bin*zggRG07f&~IlR!m?x1*nz zCqf-8k9!9=1_iq!#4+^y2f2f^D;V%{MY#s~gV?qpLP0@6g_jFj;wZQ{LBt>>kB_UL zwy}asXn=;jCPds?AtM9hHHfy#OX1(43Rrl!fpj5ZYlYzQ%#!4c)MACC)ROYl)I3R!(C?po8 z^Kv-`xf=$9j0PE|prBxnWCnBSyc7kaycCETppq04Y0#j7Bmi(7N1V}#X(g#e z2m|5uBD#4Y_?_zLdIBA0ei4 z*jm8_Rz`w-3u=id6sIN@fiem&7qo2yHyo0VAuS#B%nNDwAVeW*AE(9tMkTgP@RmiG9g&4Fp z2G_Qr`~r8vTfqpP z`a!iB$UIO>5Zydbn-FTCJuer$aflFtwi2NNV7K|Y`hZ(jNM`YJK^u?oL;>+EsD%iM zbC`B}utH?Nf;wOLzC}?5ZR;Yd3V}9zVPYWT zLG4|TBM@acsPPL*s<48@o|g;K6o#ZmkQ7)5)GS63f;N#6K@L)igsl~v5=)XZ6fzR? zQgTvxxxf+b>Vr_v%LQ&#qdEuN#6}f@w6{@w8w_r0BZQEOI7AZ`)OH5B2ioF=v~Ur6 z>=7#A`3<=l4$_*L2X57s#3$wCCub|z*dg?Qq(K-KZW^d+<8u=$6m%6dR1|a-kWJOp z1Ql1H8U>Vm5XQlbu`uueDbO&0H<&&1GD{Rn@)Zm~L~desszPyTQK~{oMyf(iW?pt` zkwRv%LS8DN4*M&P>fK z;pGBBy^5U7;u2miy^7?b)HGf$1t{?JbM^^!aaC~f4-Ss>)pHE?#Uke#hEvYj-#6IR z9lJh|TsTBZ4{AHaa!f0n{e4{nLm_H;xm+AW9D`hg6@p#eeO>)R6aqq>d_0{Ix?Ced zg8UQ|6kMG>{M~#U-L0G=LtGKsT>V^vL4FPia`Xck1@$UH`G>gq zxj@(;d*BkzAwfRQFdn9x{QY2ZI{t2MaCVq$kSCnug@G;5aq$dt3Waz_$JxUX&f(<(*^F!hvdzx^E-;JHVn+cI zrI;ze}(aLW{F+0N5l)9~~uoC4{(_Uldf_ z$Ia6RA@1Yv57q!Rn3v1Z2c!VW0+@-;5jqA4eK7O<`~!k~142N-?Ct38holeYCzl9N zp%CmEq5uzmD^L*mx&|v)D=0Y@r7BeBmnsyO7Nsg^MC$u#B0JmJ(Z>hmZg3nUY=@a0 z?5Sg6;DIUb5}^}}l;mK_K{;3&#*8SyTzKCYnL4)Y-_!d)Uj z(gQ9xFWWUarO8)}k=)U62po_@|C%M=`uG9xT( zA;q^BFBc?`k^CLx8UiXoc)5rznBc`1sDuI+o(fJuu8!V13W<3s3Xl?10h%a_^%R^l zQj@b4((;QGl>Ggaz-pBI-Q1KwmV$I!figOzJjGdrBK!yoJxINe5ch(3UBSg4)b>D# z!^1CFCmK@e#-i94z(J z6?tGyDDHt5XuMnyuV69D(MJbVt%Hjlmtd=C3j>c>gfo$HjS)iB%L$w`6aqkwhcHn{ zYX$fGl0=1!#IjU{#1e&^)WqTv1tW#zjKreE*I~hwbxDXwsFc&-d=pZ5wVIwS; zItL?(LGvQ02@I?5k&`DvCCqSal@iF$zOG2d!aNu3;U5&D5D@7H$_2b!(A|tQCqu5nP;FkXV#hl8>A=fY8xOG zJFs#u0AdZo(Xe6+B96TzbMZkg!LZb1D898;2u>|gh(qc?f{QPN1xS93fHoFfd~{rp zY9qo{gn&XiKP^om&RHQDRC6GF1h$Qr3+huO%U}Tt%?Bus263#hXB&_d2*X1P+$He> z387$Xg}i(nh5Y=2Vnu{wU>4(M3 zI2y6oi~{$l5sraIkb;wsjuTQ0!2$zpa2T@J@HrFGMd#&$=|XZTtRMqRf$|8XfqB14JXJ#~&W#8RAMHKR{F?{0s9~m}?MfX223nQ4^>M+kDXln(Kuzyf$3Z$|Fxhb<)p|~V7CkG^jFbS6rgIpn< zPlTDMENcbl#G;}~h2)&n#3F^XqWoM1XWsx`E{IE!;szeH5jtjOW@Z>|Noxi5v@{}v z94RK@#`=IlfUtiM{U%g@zOSDa}n)@N`kg%uCA$mATkjusX74;0Bs(D<2l&XG052?-pw;8I0W413-k9;@N_|#h%YE0!?g&tu!0TjFoZD7 z2uDa`&du2gsrTdP;sSOeXpF%DDd`}m31o3t8g~f_^GC`=NOnX+#%FQZ;i%5b1=foc z-7t6ihlU_rjjeN!ROBF67_dIOyT89nm_JhG409E>bOavLMpy@P16tU@YGY{U3TgwA z+woZe8A2y$2h50IPs~v|$oRH`wt@x17?^q-Bb6>#jDZe~W18U-q2q!yN*Ck`9*I=& z^$$ZH(S+IP7@=d}XyAf0C>9*zAB>`EAXP}^4J=S0M2|goz;s2TTlGM;BQyEPO}`dT2`kGDZ&0g9-`? zSgL=R6qvSFa8E5!0C^46i*t^!azP#`b3%#=Sb~O*$b)qw6V?jpFq1&TP@vvnW?o6Y z0$TU4ucxH;7aTlL!Du7($%5WCe2u zw%m@90bo|a(jY8oV8sq{^uolDg9cKFgVHWEfRU0H%pt*^sJXxcJdUmq?1|iqgcZPG z#V}WZ2gHLtZ5<=Dj1j?rq!eRpGu+kHJH!zwlffL}6rtmclty5}&Jj9DCgaHW2v36I V33=8GGMff-uB)F5FBbzX0RYUaWJv%3 literal 0 HcmV?d00001 diff --git a/UINIT.ASM b/UINIT.ASM new file mode 100644 index 0000000000000000000000000000000000000000..2e6bc77a94b01f9f38e4baf1892140e5deddf5ff GIT binary patch literal 896 zcmWIX4DoSQP*8C8_w{x3b5Zcj%Ph%E%*m`uEXmBzQ^-v%E>28OE#~FoDi=8mKKQxK(<(;d38Ue@JRh zYFK7UYQ921YEf~1USf`dbAE0?X-R64f{TB!LRe~1G1LP(U@e#~QPObMRB+BOs4U7% z&nQtqm>67HT#}kwtfSzWm#n8?XlY@r1T%xv#fcM5pKoSzQGRiLT8V;leo+Bfy`c_B zml2qR>D5uf;$>bgq(}rugi>%pYI0^;W@-v3;egXxacW{wa)v@mW>IQ#Nq$kKLQ-N1 e)IktKdAVRI$JNgTB`vu6x$tr^Py + +CODE ENDS +DATA SEGMENT BYTE PUBLIC 'DATA' + +open_name DW ? + DW ? +open_access DB ? +open_jfn DW ? ; accessed as DD +open_jfn_b DW ? ; accessed as DD with above +open_sfn DW ? +open_sfoff DW ? ; accessed as DD +open_sfn_b DW ? ; accessed as DD with above +open_devid DB ? +Cr_read_only DB ? +rename_source DD ? +rename_dest DD ? + +DATA ENDS +CODE SEGMENT BYTE PUBLIC 'CODE' + +BREAK + +; +; Input: DS:DX is an ASCIZ path +; Output: Carry set if meta-characters present or path malformed and +; Zero is set if the only problem is that meta-characters +; are present in the last element of the path +procedure Validate_path,near + ASSUME DS:NOTHING,ES:NOTHING + PUSH AX + PUSH CX + PUSH SI + MOV SI,DX + MOV CX,0FFH ;No path seps yet + MOV AX,[SI] ; Get first two bytes + OR AL,AL + JZ validate_malformed ; NUL path + CMP AH,':' + JNZ validate_loop ; OK so far + CMP BYTE PTR [SI+2],0 + JZ validate_malformed ; NUL path (just d:) +validate_loop: + LODSB +validate_loop1: + + IF KANJI + invoke TESTKANJ + JZ NOTKANJ6 + INC SI + JMP validate_loop + +NOTKANJ6: + ENDIF + + OR AL,AL + JZ validate_end + CMP AL,"?" + JZ validate_error + CMP AL,"*" + JZ validate_error + invoke PathChrCmp + JNZ validate_loop + JCXZ validate_malformed ;If path sep, cannot have meta yet + LODSB ;Look ahead one char + OR AL,AL + JZ validate_checktslsh ;Trailing path sep + invoke PathChrCmp + JNZ validate_loop1 ;Double path sep? +validate_malformed: + INC CX + OR CX,CX ;Reset zero + JMP SHORT validate_set_carry + +validate_error: + XOR CX,CX ;Flag metas found + JMP validate_loop + +validate_checktslsh: +;A bizarre case, "/" is OK, "d:/" is OK, anything else is an error + SUB SI,DX + CMP SI,2 + JZ validate_end ;Two chars, the '/' and the NUL + CMP SI,4 + JNZ validate_malformed ;Four chars, "D:/" + MOV SI,DX + CMP BYTE PTR [SI+1],':' + JNZ validate_malformed ;Second char must be a ':' + +validate_end: + OR CX,CX ;Clears carry + JNZ validate_ok ;No metas found, leave carry clear +validate_set_carry: + STC +validate_ok: + POP SI + POP CX + POP AX + return +validate_path ENDP + +BREAK + +; +; Input: DS:DX point to a path +; Output: Carry reset - outputs of GetPath +; carry set - AL has error code +; + procedure Access_path,NEAR + ASSUME DS:NOTHING,ES:NOTHING + CALL Validate_path + JC access_no_path + MOV SI,DX + invoke GetPath + retnc + MOV AL,error_file_not_found + OR CL,CL + JNZ access_ret +access_no_path: + MOV AL,error_path_not_found +access_ret: + STC + return +access_path ENDP + +BREAK +; +; system file table data +; + +; +; The system file table is two linear tables. The first table is the +; DOS initialization table containing a default number of FCBs. The +; first word in the table is a link to the second table, which +; SYSINIT sets up, the second word is the number of FCBs in the table. +; + +; +; find_free_jfn +; input: none +; output: JNC +; ES:DI is pointer to free JFN +; JC +; ES,DI indeterminate +; + procedure Find_free_jfn,NEAR + ASSUME DS:NOTHING,ES:NOTHING + PUSH AX + PUSH CX + MOV AL,0FFh + MOV ES,[CurrentPDB] + MOV DI,PDB_JFN_Table + MOV CX,FilPerProc + REPNE SCASB + STC + JNZ Find_jfn_ret + DEC DI + CLC +Find_jfn_ret: + POP CX + POP AX + return +Find_free_jfn ENDP + +BREAK +; +; find_free_sfn +; input: none +; output: JNC +; ES:DI is free sf entry +; SI is sfn +; JC +; ES,DI,SI indeterminate +; +; sft_addr --> (link) count (fcbs) +; links = -1 means end of list +; + procedure Find_free_sfn,NEAR + ASSUME DS:NOTHING,ES:NOTHING + PUSH BX + PUSH CX + LES BX,sft_addr ; head of chain of tables + XOR SI,SI ; count of sfn + + ; ES:BX points to table... search through table +Find_sfn_in_table: + CMP BX,-1 ; end of chain + JZ Find_no_free_sfns + MOV DI,sft_table ; offset to sf entry + MOV CX,ES:[BX].sft_count ; count of fcbs in table + +Find_sfn: + CMP ES:BYTE PTR [BX+DI].sf_ref_count,0h + JZ Find_got_sfn ; ref count is 0 -> free entry + ADD DI,SIZE sf_entry ; look to next entry + INC SI ; bump sfn + LOOP Find_sfn + LES BX,ES:[BX].sft_link ; link to next + JMP SHORT Find_sfn_in_table ; look for more + +Find_no_free_sfns: + STC + JMP SHORT find_ret +Find_got_sfn: + ADD DI,BX + CLC +Find_ret: + POP CX + POP BX + RET +Find_free_sfn ENDP + +BREAK <$Open - open a file handle> +; +; Assembler usage: +; LDS DX, Name +; MOV AH, Open +; MOV AL, access +; INT int_command +; +; ACCESS Function +; ------ -------- +; open_for_read file is opened for reading +; open_for_write file is opened for writing +; open_for_both file is opened for both reading and writing. +; +; Error returns: +; AX = error_invalid_access +; = error_file_not_found +; = error_access_denied +; = error_too_many_open_files +; + + procedure $Open,NEAR + ASSUME DS:NOTHING,ES:NOTHING + MOV [Cr_read_only],0 +Open_create: + CMP AL,open_for_both ; validate access + JBE OPEN_get_jfn + error error_invalid_access + +OPEN_get_jfn: + MOV [open_name+2],DS + context DS + MOV open_name,DX + MOV open_access,AL + + invoke Find_free_jfn ; scan through user's area + ; ES:DI is the jfn entry + JNC OPEN_get_sfn +OPEN_too_many: + error error_too_many_open_files + +OPEN_get_sfn: + MOV OPEN_jfn_b,ES + MOV OPEN_jfn,DI + invoke Find_free_sfn ; get a free sft entry + ; ES:DI is the SFT entry that's free, SI is the sfn + JC OPEN_too_many + +OPEN_file: + MOV OPEN_sfn,SI + MOV OPEN_sfoff,DI + MOV OPEN_sfn_b,ES +; +; open the file +; + PUSH DS + LDS DX,DWORD PTR [open_name] + ASSUME DS:NOTHING + CALL access_path + POP DS + ASSUME DS:DOSGROUP + JNC open_check_access ; carry set -> error + transfer SYS_RET_ERR + +open_check_access: + MOV ES,WORD PTR [CURBUF+2] ; get buffer location + MOV open_devid,AH + TEST AH,080h + JNZ open_set_FCB_dev ;is a device + MOV AL,ES:[BX].dir_attr + TEST AL,attr_directory ; can't open directories + JZ open_try_volid + +open_bad_access: + error error_access_denied + +open_try_volid: + TEST AL,attr_volume_id ; can't open volume ids + JNZ open_bad_access + TEST AL,attr_read_only ; check write on read only + JZ open_set_FCB + CMP [Cr_read_only],0 + JNZ open_set_FCB ; ok if creating read only file + CMP open_access, open_for_read + JNZ open_bad_access ; writing on a read only file + JMP SHORT open_set_FCB + +open_set_FCB_dev: + PUSH SS + POP ES ;Device opens are DOSGROUP relative + +open_set_FCB: + MOV CX,11 ; copy name into FCB... + PUSH SI ; ES:BX is source, must change + MOV SI,BX ; ES:SI is source + MOV DI,open_sfoff ; ??:DI is dest + PUSH DS + PUSH ES + MOV ES,open_sfn_b ; ES:DI is dest + POP DS ; DS:SI is source + ASSUME DS:NOTHING +; +; need to save attribute for the close operation +; + MOV AH,DS:[BX.dir_attr] ; save attribute for close + MOV ES:[DI.sf_attr],AH + + ADD DI,sf_fcb+1 ; point to name + + IF KANJI + MOVSB + CMP BYTE PTR ES:[DI-1],5 + JNZ NOTKTRAN + MOV BYTE PTR ES:[DI-1],0E5H +NOTKTRAN: + DEC CX + ENDIF + + REP MOVSB ; move in parsed name + POP DS + ASSUME DS:DOSGROUP + POP SI + LES DI,DWORD PTR [open_sfoff] + ADD DI,sf_fcb ; offset on fcb in sf entry + MOV AH,open_devid + invoke DOOPEN ; let open code fill in blanks + context DS + LES DI,DWORD PTR [open_sfoff] + INC ES:[DI].sf_ref_count ; reference this FCB + MOV AL,open_access ; stash the access + MOV ES:BYTE PTR [DI].sf_mode,AL + XOR AX,AX + MOV ES:WORD PTR [DI.sf_FCB.fcb_RR],AX ; beginning of file + MOV ES:WORD PTR [DI.sf_FCB.fcb_RR+2],AX + INC AX + MOV ES:WORD PTR [DI.sf_FCB.fcb_RECSIZ],AX ; byte io only + LES DI,DWORD PTR [open_jfn] + MOV AX,open_sfn + MOV ES:BYTE PTR [DI],AL ; stash sfn in PDB + SUB DI,PDB_jfn_table ; get jfn for user + MOV AX,DI + transfer SYS_RET_OK +$Open ENDP + + +BREAK <$UNLINK - delete a file entry> +; +; Assembler usage: +; LDS DX, name +; MOV AH, Unlink +; INT 21h +; +; Error returns: +; AX = error_file_not_found +; = error_access_denied +; + procedure $UNLINK,NEAR + ASSUME DS:NOTHING,ES:NOTHING + CALL access_path + JNC unlink_check_attr + transfer SYS_RET_ERR + +unlink_check_attr: + JZ unlink_dir + LDS DI,DWORD PTR [CURBUF] ; get directory entry + TEST DS:[BX.dir_attr],attr_read_only + JZ unlink_doit + +unlink_dir: + error error_access_denied + +unlink_doit: + MOV BYTE PTR DS:[BX.dir_name],0E5h ; delete dir entry + MOV BYTE PTR DS:[DI.BUFDIRTY],1 ; dirty the buffer + LODSW + MOV BX,AX + AND BX,0FFFh + context DS + JZ unlink_flush + invoke RELEASE +unlink_flush: + MOV AL,BYTE PTR ES:[BP.DPB_drive] + invoke FLUSHBUF + transfer SYS_RET_OK +$UNLINK ENDP + +BREAK <$CREAT - creat a new file and open him for input> +; +; Assembler usage: +; LDS DX, name +; MOV AH, Creat +; MOV CX, access +; INT 21h +; ; AX now has the handle +; +; Error returns: +; AX = error_access_denied +; = error_path_not_found +; = error_too_many_open_files +; + + + procedure $CREAT,NEAR + ASSUME DS:NOTHING,ES:NOTHING + CALL Validate_path + JNC unlink_do_make + error error_path_not_found +unlink_do_make: + PUSH DX + PUSH DS + context DS + MOV WORD PTR [CREATING],0E5FFh + MOV WORD PTR [ThisFCB+2],SS + MOV WORD PTR [ThisFCB],OFFSET DOSGROUP:AUXSTACK-40 + MOV SI,DX + MOV AL,CL + AND CL,attr_read_only + MOV [Cr_read_only],CL + POP DS + PUSH DS +ASSUME DS:NOTHING + invoke MakeNode + POP DS + POP DX + OR AL,AL + JZ creat_open + CMP AL,3 + JZ creat_open +creat_no_access: + error error_access_denied +creat_open: + MOV AL,open_for_both + JMP Open_create + +$CREAT ENDP + + +BREAK <$DUP - duplicate a jfn> +; +; Assembler usage: +; MOV BX, fh +; MOV AH, Dup +; INT int_command +; AX has the returned handle +; Errors: +; AX = dup_invalid_handle +; = dup_too_many_open_files + procedure $DUP,NEAR + ASSUME DS:NOTHING,ES:NOTHING + context DS + invoke Find_free_jfn + JC dup_no_free_handles + +dup_force: + PUSH ES + PUSH DI + invoke Get_sf_from_jfn + POP SI + POP DS + JC dup_bad_handle + ; ES:DI is pointer to sf entry + ; DS:DI is pointer to jfn + INC ES:[DI].sf_ref_count ; another jfn reference... + MOV AL,[BX].PDB_JFN_table ; get old sfn + MOV [SI],AL ; store in new place + SUB SI,PDB_JFN_table ; get jfn + MOV AX,SI + transfer SYS_RET_OK + +dup_no_free_handles: + error error_too_many_open_files + +dup_bad_handle: + error error_invalid_handle +$DUP ENDP + +BREAK <$DUP2 - force a dup on a particular jfn> +; +; Assembler usage: +; MOV BX, fh +; MOV CX, newfh +; MOV AH, Dup2 +; INT int_command +; Error returns: +; AX = error_invalid_handle +; + procedure $DUP2,NEAR + ASSUME DS:NOTHING,ES:NOTHING + XCHG BX,CX ; BX < destination jfn + PUSH BX + PUSH CX + invoke $CLOSE ; close BX + context DS + POP CX + POP BX + invoke Get_jfn_pointer + XCHG BX,CX + JNC dup_force +lseek_bad_handle: + error error_invalid_handle +$DUP2 ENDP + + +BREAK <$CHMOD - change file attributes> +; +; Assembler usage: +; LDS DX, name +; MOV CX, attributes +; INT 21h +; Error returns: +; AX = error_path_not_found +; AX = error_access_denied +; + procedure $CHMOD,NEAR + ASSUME DS:NOTHING,ES:NOTHING + CMP AL,1 + JBE chmod_save + error error_invalid_function +chmod_save: + JB chmod_try_file + MOV BX,CX + AND BX,NOT attr_changeable + JZ chmod_try_file + +chmod_bad: + error error_access_denied + +chmod_bye: + transfer SYS_RET_ERR +chmod_try_file: + PUSH CX + PUSH AX + CALL access_path + POP DX + POP CX + JC chmod_bye + LES DI,[CURBUF] + context DS + OR DL,DL + JZ chmod_fetch + AND BYTE PTR ES:[BX].dir_attr,NOT attr_changeable + OR BYTE PTR ES:[BX].dir_attr,CL + MOV ES:[DI.BUFDIRTY],1 + MOV AL,-1 + invoke FlushBuf + transfer SYS_RET_OK +chmod_fetch: + XOR CX,CX + MOV CL,BYTE PTR ES:[BX].dir_attr + invoke Get_user_stack + MOV [SI.user_CX],CX + transfer SYS_RET_OK +$chmod ENDP + +BREAK <$CURRENT_DIR - dump the current directory into user space> +; +; Assembler usage: +; LDS SI,area +; MOV DL,drive +; INT 21h +; ; DS:SI is a pointer to 64 byte area that contains drive +; ; current directory. +; Error returns: +; AX = error_invalid_drive +; +procedure $CURRENT_DIR,NEAR + ASSUME DS:NOTHING,ES:NOTHING + PUSH DS + PUSH BX + PUSH SI + invoke $get_DPB +; +; ES:BP points to DPB. DS:SI points to user stack, unless error +; + CMP AL,0FFh + JNZ current_copy + POP AX ; Clean Stack + POP AX + POP AX + error error_invalid_drive + +current_copy: + POP DI ; where to move to + POP [SI.user_BX] ; restore old BX + POP BX + MOV [SI.user_DS],BX ; and restore old DS +; +; ES:BP is pointer to DPB. BX:DI is pointer to destination +; + CMP ES:[BP.dpb_current_dir],-1 + JNZ current_ok + PUSH BX + PUSH DI + MOV [ATTRIB],attr_all + invoke GETCURRDIR + POP DI + POP BX +current_ok: + MOV SI,BP ; ES:SI is source + PUSH ES + POP DS ; DS:SI is source + MOV ES,BX ; ES:DI is destination + CMP [SI.dpb_current_dir],0 + JNZ current_move + MOV BYTE PTR [SI.dpb_dir_text],0 + +current_move: + ADD SI,dpb_dir_text + MOV CX,DIRSTRLEN +current_loop: + LODSB + STOSB + OR AL,AL + LOOPNZ current_loop + transfer SYS_RET_OK +$CURRENT_DIR ENDP + + +BREAK <$RENAME - move directory entries around> +; +; Assembler usage: +; LDS DX, source +; LES DI, dest +; MOV AH, Rename +; INT 21h +; +; Error returns: +; AX = error_file_not_found +; = error_not_same_device +; = error_access_denied +procedure $RENAME,near + + MOV WORD PTR [rename_source],DX + MOV WORD PTR [rename_source+2],DS + MOV WORD PTR [rename_dest],DI + MOV WORD PTR [rename_dest+2],ES + CALL Access_path + JNC rename_check_dir + transfer SYS_RET_ERR + +rename_check_dir: + JZ rename_no_access + MOV DS,WORD PTR [CurBuf+2] + PUSH [BX.dir_date] + PUSH [BX.dir_first] + PUSH [BX.dir_size_h] + PUSH [BX.dir_size_l] + PUSH [BX.dir_time] + PUSH WORD PTR [BX.dir_attr] + PUSH WORD PTR [ThisDrv] + LDS SI,[rename_dest] + invoke GetPath + POP AX + JC rename_check_drives +rename_bad_access: + ADD SP,12 +rename_no_access: + error error_access_denied +rename_check_drives: + CMP AL,[ThisDrv] + JZ rename_create + ADD SP,12 + error error_not_same_device +rename_create: + LDS SI,[rename_dest] + POP AX + PUSH AX + MOV WORD PTR [Creating],0E5FFh + MOV WORD PTR [ThisFCB+2],SS + MOV WORD PTR [ThisFCB],OFFSET DOSGROUP:AUXStack-40 + invoke MakeNode + JC rename_bad_access + LDS SI,[CurBuf] + POP AX + MOV [BX.dir_attr],AL + POP [BX.dir_time] + POP [BX.dir_size_l] + POP [BX.dir_size_h] + POP [BX.dir_first] + POP [BX.dir_date] + MOV [SI.BUFDIRTY],1 + LDS SI,[rename_source] + invoke GetPath + LDS SI,[CurBuf] + MOV BYTE PTR [BX],0E5h + MOV [SI.BUFDIRTY],1 + context DS + MOV AL,0FFh + invoke FlushBuf + transfer SYS_RET_OK + +$RENAME ENDP + +BREAK <$FIND_FIRST - find first matching xenix filename> +; +; Assembler usage: +; MOV AH, FindFirst +; LDS DX, name +; MOV CX, attr +; INT 21h +; ; DMA address has datablock +; +; Error Returns: +; AX = error_file_not_found +; = error_no_more_files +; +procedure $FIND_FIRST,near + ASSUME DS:NOTHING,ES:NOTHING + CALL Validate_path + JNC find_get + JZ find_get + error error_file_not_found +find_get: + MOV SI,DX + PUSH CX + INC BYTE PTR [NoSetDir] ; if we find a dir, don't change to it + MOV WORD PTR [Creating],0E500h + CALL GetPath + POP CX + MOV [Attrib],CL +find_check: + JNC find_check_attr +find_no_more: + error error_no_more_files +find_check_attr: + MOV DS,WORD PTR [CURBUF+2] + MOV CH,[BX.dir_attr] + invoke MatchAttributes + JZ found_it + PUSH [LastEnt] + MOV BX,[DirStart] + JMP find_it_next +found_it: + LES DI,[DMAADD] + MOV AL,[Attrib] + STOSB ; find_buf 0 = attribute in search + MOV AL,[ThisDrv] + STOSB ; find_buf 1 = drive + MOV CX,11 + PUSH BX + MOV SI,OFFSET DOSGROUP:NAME1; find_buf 2 = formatted name + PUSH DS + PUSH SS + POP DS + + IF KANJI + MOVSB + CMP BYTE PTR ES:[DI-1],5 + JNZ NOTKANJB + MOV BYTE PTR ES:[DI-1],0E5H +NOTKANJB: + DEC CX + ENDIF + + REP MOVSB + POP DS + MOV AX,[LastEnt] + STOSW ; find_buf 13 = LastEnt + MOV AX,WORD PTR [ThisDPB] + STOSW ; find_buf 15 = ThisDPB + MOV AX,WORD PTR [ThisDPB+2] + STOSW + MOV AX,[DirStart] + STOSW ; find_buf 19 = DirStart + MOV AL,[BX].dir_attr + STOSB ; find_buf 21 = attribute found + MOV AX,[BX].dir_time + STOSW ; find_buf 22 = time + MOV AX,[BX].dir_date + STOSW ; find_buf 24 = date + MOV AX,[BX].dir_size_l + STOSW ; find_buf 26 = low(size) + MOV AX,[BX].dir_size_h + STOSW ; find_buf 28 = high(size) + POP SI + MOV CX,8 ; find_buf 30 = packed name +find_loop_name: + LODSB + STOSB + CMP AL," " + LOOPNZ find_loop_name + JNZ find_check_dot + DEC DI +find_check_dot: + ADD SI,CX + CMP BYTE PTR [SI]," " + JZ find_done + MOV AL,"." + STOSB + MOV CX,3 +find_loop_ext: + LODSB + STOSB + CMP AL," " + LOOPNZ find_loop_ext + JNZ find_done + DEC DI +find_done: + XOR AL,AL + STOSB + transfer SYS_RET_OK +$FIND_FIRST ENDP + +BREAK <$FIND_NEXT - scan for match in directory> +; +; Assembler usage: +; ; dma points at area returned by find_first +; MOV AH, findnext +; INT 21h +; ; next entry is at dma +; +; Error Returns: +; AX = error_no_more_files +; +procedure $FIND_NEXT,near + ASSUME DS:NOTHING,ES:NOTHING + LDS SI,[DMAADD] + MOV DX,SI + INC DX + PUSH SI + invoke MOVNAMENOSET + POP SI + JNC find_load +findnext_no_more: + error error_no_more_files +find_load: + MOV AX,[SI.find_buf_LastEnt] + LES BP,[SI.find_buf_ThisDPB] + OR AX,AX + JS findnext_no_more + MOV BX,[SI.find_buf_DirStart] + MOV DL,[SI.find_buf_sattr] + MOV [Attrib],DL + PUSH AX + MOV WORD PTR [ThisDPB],BP + MOV WORD PTR [ThisDPB+2],ES +find_it_next: + invoke SetDirSrch + ASSUME DS:DOSGROUP + POP AX + MOV [ENTLAST],-1 + invoke GetEnt + invoke NextEnt + JMP find_check +$find_next ENDP + +do_ext + +CODE ENDS + END + \ No newline at end of file diff --git a/XENIX2.ASM b/XENIX2.ASM new file mode 100644 index 0000000..1535dbb --- /dev/null +++ b/XENIX2.ASM @@ -0,0 +1,626 @@ +; +; xenix file calls for MSDOS +; + +INCLUDE DOSSEG.ASM + +IFNDEF KANJI +KANJI EQU 0 ;FALSE +ENDIF + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xlist +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + +TITLE XENIX - IO system to mimic UNIX +NAME XENIX + + i_need NoSetDir,BYTE + i_need CURDRV,BYTE + i_need IOCALL,BYTE + i_need IOMED,BYTE + i_need IOSCNT,WORD + i_need IOXAD,DWORD + i_need DIRSTART,WORD + i_need ATTRIB,BYTE + i_need THISFCB,DWORD + i_need AuxStack,BYTE + i_need Creating,BYTE + i_need ThisDRV,BYTE + i_need NAME1,BYTE + i_need LastEnt,WORD + i_need ThisDPB,DWORD + i_need EntLast,WORD + i_need CurrentPDB,WORD + i_need sft_addr,DWORD ; pointer to head of table + i_need CURBUF,DWORD ; pointer to current buffer + i_need DMAADD,DWORD ; pointer to current dma address + +BREAK + +CODE ENDS +DATA SEGMENT BYTE PUBLIC 'DATA' + + +PushSave DW ? +PushES DW ? +PushBX DW ? + +xenix_count DW ? + +DATA ENDS +CODE SEGMENT BYTE PUBLIC 'CODE' + + +BREAK +; +; get_sf_from_sfn +; input: AX has sfn (0 based) +; DS is DOSGROUP +; output: JNC +; ES:DI is sf entry +; JC +; ES,DI indeterminate +; + procedure get_sf_from_sfn,NEAR + ASSUME DS:DOSGROUP,ES:NOTHING + PUSH AX ; we trash AX in process + LES DI,[sft_addr] + +get_sfn_loop: + CMP DI,-1 ; end of chain of tables? + JZ get_sf_invalid ; I guess so... + SUB AX,ES:[DI].sft_count ; chop number of entries in this table + JL get_sf_gotten ; sfn is in this table + LES DI,ES:[DI].sft_link ; step to next table + JMP get_sfn_loop + +get_sf_gotten: + ADD AX,ES:[DI].sft_count ; reset to index in this table + PUSH BX + MOV BX,SIZE sf_entry + MUL BL ; number of bytes offset into table + POP BX + ADD AX,sft_table ; offset into sf table structure + ADD DI,AX ; offset into memory + CLC + JMP SHORT get_sf_ret + +get_sf_jfn_invalid: +get_sf_invalid: + STC + +get_sf_jfn_ret: +get_sf_ret: + POP AX ; remember him? + RET +get_sf_from_sfn ENDP + +BREAK +; +; get_sf_from_jfn +; input: BX is jfn 0 based +; DS is DOSGROUP +; output: JNC +; ES:DI is sf entry +; JC +; ES,DI is indeterminate +; + procedure get_sf_from_jfn,NEAR + ASSUME DS:DOSGROUP,ES:NOTHING + PUSH AX ; save him + invoke get_jfn_pointer + JC get_sf_jfn_invalid + MOV AL,ES:[DI] ; get sfn + CMP AL,0FFh ; is it free? + JZ get_sf_jfn_invalid ; yep... error + XOR AH,AH + invoke get_sf_from_sfn ; check this sfn out... + JMP SHORT get_sf_jfn_ret ; condition codes are properly set + +get_sf_from_jfn ENDP + +BREAK +; +; get_jfn_pointer +; input: BX is jfn +; DS is DOSGROUP +; output: JNC +; ES:DI is pointer to jfn +; JC +; + procedure Get_jfn_pointer,NEAR + ASSUME DS:DOSGROUP,ES:NOTHING + CMP BX,FilPerProc + JAE get_jfn_bad + MOV ES,[CurrentPDB] + MOV DI,BX + ADD DI,PDB_JFN_Table + CLC + RET + +get_jfn_bad: + STC + RET +get_jfn_pointer ENDP + + +BREAK <$Close - release a handle> +; +; Assembler usage: +; MOV BX, handle +; MOV AH, Close +; INT int_command +; +; Error return: +; AX = error_invalid_handle +; + procedure $Close,NEAR + ASSUME DS:NOTHING,ES:NOTHING + + context DS + + invoke get_jfn_pointer ; get jfn loc + JNC close_jfn +close_bad_handle: + error error_invalid_handle + +close_jfn: + MOV AL,BYTE PTR ES:[DI] + CMP AL,0FFh + JE close_bad_handle + MOV BYTE PTR ES:[DI],0FFh; + XOR AH,AH + invoke get_sf_from_sfn + JC close_bad_handle + PUSH ES + POP DS + ASSUME DS:NOTHING + DEC [DI].sf_ref_count ; no more reference + LEA DX,[DI].sf_fcb +; +; need to restuff Attrib if we are closing a protected file +; + TEST [DI.sf_fcb.fcb_DevID],devid_file_clean+devid_device + JNZ close_ok + PUSH WORD PTR [DI].sf_attr + invoke MOVNAMENOSET + POP BX + MOV [Attrib],BL + invoke FCB_CLOSE_INNER + CMP AL,0FFh ; file not found error? + JNZ close_ok + error error_file_not_found +close_ok: + transfer SYS_RET_OK + +$Close ENDP + + +BREAK +; PushDMA +; input: DS:DX is DMA +; output: DS:DX is normalized , ES:BX destroyed +; [DMAADD] is now set up to DS:DX +; old DMA is pushed + + procedure PushDMA,NEAR + ASSUME DS:NOTHING,ES:NOTHING + + MOV PushES,ES + MOV PushBX,BX + POP PushSave + LES BX,DWORD PTR [DMAADD] ; get old dma + PUSH ES + PUSH BX + PUSH PushSave + invoke ptr_normalize ; get new dma + MOV WORD PTR [DMAADD],DX ; save IT! + MOV WORD PTR [DMAADD+2],DS + MOV ES,PushES + MOV BX,PushBX + RET +PushDMA ENDP + +; PopDMA +; input: old DMA under ret address on stack +; output: [DMAADD] set to old version and stack popped + procedure PopDMA,NEAR + ASSUME DS:NOTHING,ES:NOTHING + + POP PushSave + POP WORD PTR [DMAADD] + POP WORD PTR [DMAADD+2] + PUSH PushSave + RET +PopDMA ENDP + +; ptr_normalize +; input: DS:DX is a pointer +; output: DS:DX is normalized (DX < 10h) + procedure ptr_normalize,NEAR + PUSH CX ; T1 = CX + PUSH DX ; T2 = DX + MOV CL,4 + SHR DX,CL ; DX = (DX >> 4) (using CX) + MOV CX,DS + ADD CX,DX + MOV DS,CX ; DS = DS + DX (using CX) + POP DX + AND DX,0Fh ; DX = T2 & 0Fh + POP CX ; CX = T1 + +; PUSH AX +; PUSH DX +; MOV AX,DS +; PUSH CX +; MOV CL,4 +; SHR DX,CL ; get upper part of dx +; POP CX +; ADD AX,DX ; add into seg address +; MOV DS,AX +; POP DX +; AND DX,0Fh ; save low part +; POP AX + + RET +ptr_normalize ENDP + +BREAK <$Read - Do file/device I/O> +; +; Assembler usage: +; LDS DX, buf +; MOV CX, count +; MOV BX, handle +; MOV AH, Read +; INT int_command +; AX has number of bytes read +; Errors: +; AX = read_invalid_handle +; = read_access_denied +; + + procedure $Read,NEAR + ASSUME DS:NOTHING,ES:NOTHING + + invoke PushDMA + CALL IO_setup + JC IO_err + CMP ES:[DI].sf_mode,open_for_write + JNE read_setup +IO_bad_mode: + MOV AL,read_access_denied +IO_err: + invoke PopDMA + transfer SYS_RET_ERR + +read_setup: + invoke $FCB_RANDOM_READ_BLOCK ; do read +IO_done: + invoke get_user_stack ; get old frame + MOV AX,[SI].user_CX ; get returned CX + MOV CX,xenix_count + MOV [SI].user_CX,CX ; stash our CX + invoke PopDMA ; get old DMA + transfer SYS_RET_OK +$Read ENDP + +BREAK <$Write - Do file/device I/O> +; +; Assembler usage: +; LDS DX, buf +; MOV CX, count +; MOV BX, handle +; MOV AH, Write +; INT int_command +; AX has number of bytes written +; Errors: +; AX = write_invalid_handle +; = write_access_denied +; + + procedure $Write,NEAR + ASSUME DS:NOTHING,ES:NOTHING + + invoke PushDMA + CALL IO_setup + JC IO_err + CMP ES:[DI].sf_mode,open_for_read + JE IO_bad_mode + invoke $FCB_RANDOM_WRITE_BLOCK ; do write + JMP IO_done + +$write ENDP + +IO_setup: + ASSUME DS:NOTHING,ES:NOTHING + context DS + MOV xenix_count,CX + invoke Get_sf_from_jfn + ; ES:DI is sf pointer + MOV AL,read_invalid_handle ;Assume an error + MOV CX,xenix_count + LEA DX,[DI].sf_fcb + PUSH ES + POP DS + ASSUME DS:NOTHING + RET + +BREAK <$LSEEK - set random record field> +; +; Assembler usage: +; MOV DX, offsetlow +; MOV CX, offsethigh +; MOV BX, handle +; MOV AL, method +; MOV AH, LSeek +; INT int_command +; DX:AX has the new location of the pointer +; Error returns: +; AX = error_invalid_handle +; = error_invalid_function + procedure $LSEEK,NEAR + ASSUME DS:NOTHING,ES:NOTHING + CMP AL,3 + JB lseek_get_sf + error error_invalid_function + +lseek_get_sf: + context DS + invoke get_sf_from_jfn + PUSH ES + POP DS + ASSUME DS:NOTHING + JC lseek_bad +; +; don't seek device +; + TEST [DI.sf_fcb+fcb_devid],devid_device + JZ lseek_dispatch + XOR AX,AX + XOR DX,DX + JMP SHORT lseek_ret +lseek_dispatch: + DEC AL + JL lseek_beginning + DEC AL + JL lseek_current +; move from end of file +; first, get end of file + XCHG AX,DX ; AX <- low + XCHG DX,CX ; DX <- high + ASSUME DS:NOTHING + ADD AX,[DI+sf_fcb+fcb_FILSIZ] + ADC DX,[DI+sf_fcb+fcb_FILSIZ+2] + JMP SHORT lseek_ret + +lseek_beginning: + XCHG AX,DX ; AX <- low + XCHG DX,CX ; DX <- high + +lseek_ret: + MOV WORD PTR [DI+sf_fcb+fcb_RR],AX + MOV WORD PTR [DI+sf_fcb+fcb_RR+2],DX + invoke get_user_stack + MOV [SI.user_DX],DX + MOV [SI.user_AX],AX + transfer SYS_RET_OK + +lseek_current: +; ES:DI is pointer to sf... need to invoke set random record for place + XCHG AX,DX ; AX <- low + XCHG DX,CX ; DX <- high + ADD AX,WORD PTR [DI+sf_fcb+fcb_RR] + ADC DX,WORD PTR [DI+sf_fcb+fcb_RR+2] + JMP lseek_ret + +lseek_bad: + error error_invalid_handle +$lseek ENDP + + +BREAK <$IOCTL - return/set device dependent stuff> +; +; Assembler usage: +; MOV BX, Handle +; MOV DX, Data +; +; (or LDS DX,BUF +; MOV CX,COUNT) +; +; MOV AH, Ioctl +; MOV AL, Request +; INT 21h +; +; Error returns: +; AX = error_invalid_handle +; = error_invalid_function +; = error_invalid_data + + procedure $IOCTL,NEAR + ASSUME DS:NOTHING,ES:NOTHING + MOV SI,DS ;Stash DS for calls 2,3,4 and 5 + context DS + CMP AL,3 + JA ioctl_check_block ;Block device + PUSH DX + invoke get_sf_from_jfn + POP DX ;Restore DATA + JNC ioctl_check_permissions ; have valid handle + error error_invalid_handle + +ioctl_check_permissions: + CMP AL,2 + JAE ioctl_control_string + CMP AL,0 + MOV AL,BYTE PTR ES:[DI+sf_fcb+fcb_devid] + JZ ioctl_read ; read the byte + OR DH,DH + JZ ioctl_check_device ; can I set with this data? + error error_invalid_data ; no DH <> 0 + +ioctl_check_device: + TEST AL,devid_ISDEV ; can I set this handle? + JZ ioctl_bad_fun ; no, it is a file. + MOV BYTE PTR ES:[DI+sf_fcb+fcb_devid],DL + transfer SYS_RET_OK + +ioctl_read: + XOR AH,AH + TEST AL,devid_ISDEV ; Should I set high byte + JZ ioctl_no_high ; no + LES DI,DWORD PTR ES:[DI+sf_fcb+fcb_FIRCLUS] ;Get device pointer + MOV AH,BYTE PTR ES:[DI.SDEVATT+1] ;Get high byte +ioctl_no_high: + invoke get_user_stack + MOV DX,AX + MOV [SI.user_DX],DX + transfer SYS_RET_OK + +ioctl_control_string: + TEST BYTE PTR ES:[DI+sf_fcb+fcb_devid],devid_ISDEV ; can I? + JZ ioctl_bad_fun ; no, it is a file. + LES DI,DWORD PTR ES:[DI+sf_fcb+fcb_FIRCLUS] ;Get device pointer + XOR BL,BL ; Unit number of char dev = 0 + JMP SHORT ioctl_do_string + +ioctl_check_block: + DEC AL + DEC AL ;4=2,5=3,6=4,7=5 + CMP AL,3 + JBE ioctl_get_dev + + MOV AH,1 + SUB AL,4 ;6=0,7=1 + JZ ioctl_get_status + MOV AH,3 + DEC AL + JNZ ioctl_bad_fun + +ioctl_get_status: + PUSH AX + invoke GET_IO_FCB + POP AX + JC ioctl_acc_err + invoke IOFUNC + MOV AH,AL + MOV AL,0FFH + JNZ ioctl_status_ret + INC AL +ioctl_status_ret: + transfer SYS_RET_OK + +ioctl_bad_fun: + error error_invalid_function + +ioctl_acc_err: + error error_access_denied + +ioctl_get_dev: + PUSH CX + PUSH DX + PUSH AX + PUSH SI ;DS in disguise + MOV AL,BL ;Drive + invoke GETTHISDRV + JC ioctl_bad_drv + invoke FATREAD ;"get" the drive + MOV BL,ES:[BP.dpb_UNIT] ; Unit number + LES DI,ES:[BP.dpb_driver_addr] + CLC ;Make sure error jump not taken +ioctl_bad_drv: + POP SI + POP AX + POP DX + POP CX + JC ioctl_acc_err +ioctl_do_string: + TEST ES:[DI.SDEVATT],DEVIOCTL ;See if device accepts control + JZ ioctl_bad_fun ;NO + DEC AL + DEC AL + JZ ioctl_control_read + MOV [IOCALL.REQFUNC],DEVWRIOCTL + JMP SHORT ioctl_control_call +ioctl_control_read: + MOV [IOCALL.REQFUNC],DEVRDIOCTL +ioctl_control_call: + MOV AL,DRDWRHL + MOV AH,BL ;Unit number + MOV WORD PTR [IOCALL.REQLEN],AX + XOR AX,AX + MOV [IOCALL.REQSTAT],AX + MOV [IOMED],AL + MOV [IOSCNT],CX + MOV WORD PTR [IOXAD],DX + MOV WORD PTR [IOXAD+2],SI + PUSH ES + POP DS +ASSUME DS:NOTHING + MOV SI,DI ;DS:SI -> driver + PUSH SS + POP ES + MOV BX,OFFSET DOSGROUP:IOCALL ;ES:BX -> Call header + invoke DEVIOCALL2 + MOV AX,[IOSCNT] ;Get actual bytes transferred + transfer SYS_RET_OK + +$IOCTL ENDP + +BREAK +; +; Assembler usage: +; MOV AH, FileTimes +; MOV AL, func +; MOV BX, handle +; ; if AL = 1 then then next two are mandatory +; MOV CX, time +; MOV DX, date +; INT 21h +; ; if AL = 0 then CX/DX has the last write time/date +; ; for the handle. +; +; Error returns: +; AX = error_invalid_function +; = error_invalid_handle +; +procedure $File_times,near + CMP AL,2 + JB filetimes_ok + error error_invalid_function + +filetimes_ok: + PUSH SS + POP DS + CALL Get_sf_from_jfn + JNC filetimes_disp + error error_invalid_handle + +filetimes_disp: + OR AL,AL + JNZ filetimes_set + MOV CX,ES:[DI.sf_fcb.fcb_FTIME] + MOV DX,ES:[DI.sf_fcb.fcb_FDATE] + invoke Get_user_stack + MOV [SI.user_CX],CX + MOV [SI.user_DX],DX + transfer SYS_RET_OK + +filetimes_set: + MOV ES:[DI.sf_fcb.fcb_FTIME],CX + MOV ES:[DI.sf_fcb.fcb_FDATE],DX + AND ES:[DI.sf_fcb.fcb_DEVID],NOT devid_file_clean + transfer SYS_RET_OK +$file_times ENDP + +do_ext + +CODE ENDS + END + \ No newline at end of file