From 80ab2fddfdf30f09f0a0a637654cbb3cd5c7baa6 Mon Sep 17 00:00:00 2001 From: Rich Turner Date: Fri, 12 Aug 1983 17:53:34 -0700 Subject: MS-DOS v2.0 Release --- v2.0/source/ALLOC.ASM | 371 +++++++++ v2.0/source/ANSI.txt | Bin 0 -> 6784 bytes v2.0/source/BUF.ASM | 508 ++++++++++++ v2.0/source/CHKDSK.ASM | 901 +++++++++++++++++++++ v2.0/source/CHKMES.ASM | 477 +++++++++++ v2.0/source/CHKPROC.ASM | 1408 +++++++++++++++++++++++++++++++++ v2.0/source/COMEQU.ASM | 33 + v2.0/source/COMLINK | Bin 0 -> 128 bytes v2.0/source/COMMAND.ASM | 788 ++++++++++++++++++ v2.0/source/COMSEG.ASM | 38 + v2.0/source/COMSW.ASM | 13 + v2.0/source/CONFIG.txt | Bin 0 -> 3456 bytes v2.0/source/COPY.ASM | 579 ++++++++++++++ v2.0/source/COPYPROC.ASM | 526 ++++++++++++ v2.0/source/CPARSE.ASM | 291 +++++++ v2.0/source/CTRLC.ASM | 468 +++++++++++ v2.0/source/DEBASM.ASM | 1264 +++++++++++++++++++++++++++++ v2.0/source/DEBCOM1.ASM | 694 ++++++++++++++++ v2.0/source/DEBCOM2.ASM | 1269 +++++++++++++++++++++++++++++ v2.0/source/DEBCONST.ASM | 1103 ++++++++++++++++++++++++++ v2.0/source/DEBDATA.ASM | Bin 0 -> 2816 bytes v2.0/source/DEBEQU.ASM | 32 + v2.0/source/DEBMES.ASM | Bin 0 -> 5248 bytes v2.0/source/DEBUASM.ASM | 868 ++++++++++++++++++++ v2.0/source/DEBUG.ASM | 838 ++++++++++++++++++++ v2.0/source/DEV.ASM | 439 ++++++++++ v2.0/source/DEVDRIV.txt | 802 +++++++++++++++++++ v2.0/source/DEVSYM.ASM | Bin 0 -> 2688 bytes v2.0/source/DIR.ASM | 1084 +++++++++++++++++++++++++ v2.0/source/DIRCALL.ASM | 507 ++++++++++++ v2.0/source/DISK.ASM | 1302 ++++++++++++++++++++++++++++++ v2.0/source/DISKCOPY.ASM | Bin 0 -> 6656 bytes v2.0/source/DISKMES.ASM | Bin 0 -> 7808 bytes v2.0/source/DOSLINK | 5 + v2.0/source/DOSMAC.ASM | Bin 0 -> 6656 bytes v2.0/source/DOSMAC_v211.ASM | 274 +++++++ v2.0/source/DOSMES.ASM | 355 +++++++++ v2.0/source/DOSSEG.ASM | 17 + v2.0/source/DOSSYM.ASM | 904 +++++++++++++++++++++ v2.0/source/DOSSYM_v211.ASM | 963 ++++++++++++++++++++++ v2.0/source/EDLIN.ASM | 1846 +++++++++++++++++++++++++++++++++++++++++++ v2.0/source/EDLMES.ASM | Bin 0 -> 3200 bytes v2.0/source/EDLPROC.ASM | 531 +++++++++++++ v2.0/source/EXE2BIN.ASM | 514 ++++++++++++ v2.0/source/EXEC.ASM | 1035 ++++++++++++++++++++++++ v2.0/source/EXEMES.ASM | Bin 0 -> 768 bytes v2.0/source/FAT.ASM | 362 +++++++++ v2.0/source/FC.ASM | 1684 +++++++++++++++++++++++++++++++++++++++ v2.0/source/FCB.ASM | 512 ++++++++++++ v2.0/source/FCMES.ASM | Bin 0 -> 2048 bytes v2.0/source/FIND.ASM | 932 ++++++++++++++++++++++ v2.0/source/FINDMES.ASM | Bin 0 -> 1408 bytes v2.0/source/FORMAT.ASM | 1627 ++++++++++++++++++++++++++++++++++++++ v2.0/source/FORMAT.txt | 393 +++++++++ v2.0/source/FORMES.ASM | Bin 0 -> 4529 bytes v2.0/source/GENFOR.ASM | Bin 0 -> 4096 bytes v2.0/source/GETSET.ASM | 627 +++++++++++++++ v2.0/source/HRDDRV.ASM | 501 ++++++++++++ v2.0/source/IFEQU.ASM | 18 + v2.0/source/INCOMP.txt | Bin 0 -> 2688 bytes v2.0/source/INIT.ASM | 939 ++++++++++++++++++++++ v2.0/source/INT24.txt | Bin 0 -> 4224 bytes v2.0/source/MISC.ASM | 648 +++++++++++++++ v2.0/source/MORE.ASM | Bin 0 -> 3712 bytes v2.0/source/MOREMES.ASM | 17 + v2.0/source/MSCODE.ASM | 615 ++++++++++++++ v2.0/source/MSDATA.ASM | 342 ++++++++ v2.0/source/MSDOS.ASM | 12 + v2.0/source/MSHEAD.ASM | 198 +++++ v2.0/source/MSINIT.ASM | 408 ++++++++++ v2.0/source/PCLOCK.ASM | Bin 0 -> 3200 bytes v2.0/source/PRINT.ASM | 1645 ++++++++++++++++++++++++++++++++++++++ v2.0/source/PRINT_v211.ASM | 1645 ++++++++++++++++++++++++++++++++++++++ v2.0/source/PROC.ASM | 130 +++ v2.0/source/PROFIL.ASM | 705 +++++++++++++++++ v2.0/source/PROFILE.txt | Bin 0 -> 3968 bytes v2.0/source/PROHST.HLP | 35 + v2.0/source/QUICK.txt | Bin 0 -> 3456 bytes v2.0/source/RDATA.ASM | Bin 0 -> 6784 bytes v2.0/source/README.txt | 177 +++++ v2.0/source/RECMES.ASM | Bin 0 -> 5760 bytes v2.0/source/RECOVER.ASM | 876 ++++++++++++++++++++ v2.0/source/ROM.ASM | 530 +++++++++++++ v2.0/source/RUCODE.ASM | Bin 0 -> 6912 bytes v2.0/source/SKELIO.ASM | 1377 ++++++++++++++++++++++++++++++++ v2.0/source/SORT.ASM | 420 ++++++++++ v2.0/source/SORTMES.ASM | Bin 0 -> 2688 bytes v2.0/source/STDBUF.ASM | Bin 0 -> 256 bytes v2.0/source/STDCALL.ASM | Bin 0 -> 256 bytes v2.0/source/STDCTRLC.ASM | Bin 0 -> 256 bytes v2.0/source/STDFCB.ASM | 16 + v2.0/source/STDIO.ASM | 17 + v2.0/source/STDPROC.ASM | 16 + v2.0/source/STDSW.ASM | 34 + v2.0/source/STRIN.ASM | 292 +++++++ v2.0/source/SYS.ASM | 587 ++++++++++++++ v2.0/source/SYSCALL.ASM | 749 ++++++++++++++++++ v2.0/source/SYSCALL.txt | 1657 ++++++++++++++++++++++++++++++++++++++ v2.0/source/SYSIMES.ASM | Bin 0 -> 512 bytes v2.0/source/SYSINIT.ASM | 1424 +++++++++++++++++++++++++++++++++ v2.0/source/SYSINIT.txt | Bin 0 -> 3072 bytes v2.0/source/SYSMES.ASM | 51 ++ v2.0/source/TCODE.ASM | 1088 +++++++++++++++++++++++++ v2.0/source/TCODE2.ASM | 522 ++++++++++++ v2.0/source/TCODE3.ASM | 677 ++++++++++++++++ v2.0/source/TCODE4.ASM | 1002 +++++++++++++++++++++++ v2.0/source/TCODE5.ASM | 953 ++++++++++++++++++++++ v2.0/source/TDATA.ASM | 243 ++++++ v2.0/source/TIME.ASM | Bin 0 -> 7040 bytes v2.0/source/TSPC.ASM | Bin 0 -> 4480 bytes v2.0/source/TUCODE.ASM | Bin 0 -> 7808 bytes v2.0/source/UINIT.ASM | Bin 0 -> 896 bytes v2.0/source/UTILITY.txt | 813 +++++++++++++++++++ v2.0/source/WSBAUD.BAS | Bin 0 -> 1152 bytes v2.0/source/WSMSGS.OVR | Bin 0 -> 27264 bytes v2.0/source/WSOVLY1.OVR | Bin 0 -> 40960 bytes v2.0/source/XENIX.ASM | 907 +++++++++++++++++++++ v2.0/source/XENIX2.ASM | 626 +++++++++++++++ 118 files changed, 52096 insertions(+) create mode 100644 v2.0/source/ALLOC.ASM create mode 100644 v2.0/source/ANSI.txt create mode 100644 v2.0/source/BUF.ASM create mode 100644 v2.0/source/CHKDSK.ASM create mode 100644 v2.0/source/CHKMES.ASM create mode 100644 v2.0/source/CHKPROC.ASM create mode 100644 v2.0/source/COMEQU.ASM create mode 100644 v2.0/source/COMLINK create mode 100644 v2.0/source/COMMAND.ASM create mode 100644 v2.0/source/COMSEG.ASM create mode 100644 v2.0/source/COMSW.ASM create mode 100644 v2.0/source/CONFIG.txt create mode 100644 v2.0/source/COPY.ASM create mode 100644 v2.0/source/COPYPROC.ASM create mode 100644 v2.0/source/CPARSE.ASM create mode 100644 v2.0/source/CTRLC.ASM create mode 100644 v2.0/source/DEBASM.ASM create mode 100644 v2.0/source/DEBCOM1.ASM create mode 100644 v2.0/source/DEBCOM2.ASM create mode 100644 v2.0/source/DEBCONST.ASM create mode 100644 v2.0/source/DEBDATA.ASM create mode 100644 v2.0/source/DEBEQU.ASM create mode 100644 v2.0/source/DEBMES.ASM create mode 100644 v2.0/source/DEBUASM.ASM create mode 100644 v2.0/source/DEBUG.ASM create mode 100644 v2.0/source/DEV.ASM create mode 100644 v2.0/source/DEVDRIV.txt create mode 100644 v2.0/source/DEVSYM.ASM create mode 100644 v2.0/source/DIR.ASM create mode 100644 v2.0/source/DIRCALL.ASM create mode 100644 v2.0/source/DISK.ASM create mode 100644 v2.0/source/DISKCOPY.ASM create mode 100644 v2.0/source/DISKMES.ASM create mode 100644 v2.0/source/DOSLINK create mode 100644 v2.0/source/DOSMAC.ASM create mode 100644 v2.0/source/DOSMAC_v211.ASM create mode 100644 v2.0/source/DOSMES.ASM create mode 100644 v2.0/source/DOSSEG.ASM create mode 100644 v2.0/source/DOSSYM.ASM create mode 100644 v2.0/source/DOSSYM_v211.ASM create mode 100644 v2.0/source/EDLIN.ASM create mode 100644 v2.0/source/EDLMES.ASM create mode 100644 v2.0/source/EDLPROC.ASM create mode 100644 v2.0/source/EXE2BIN.ASM create mode 100644 v2.0/source/EXEC.ASM create mode 100644 v2.0/source/EXEMES.ASM create mode 100644 v2.0/source/FAT.ASM create mode 100644 v2.0/source/FC.ASM create mode 100644 v2.0/source/FCB.ASM create mode 100644 v2.0/source/FCMES.ASM create mode 100644 v2.0/source/FIND.ASM create mode 100644 v2.0/source/FINDMES.ASM create mode 100644 v2.0/source/FORMAT.ASM create mode 100644 v2.0/source/FORMAT.txt create mode 100644 v2.0/source/FORMES.ASM create mode 100644 v2.0/source/GENFOR.ASM create mode 100644 v2.0/source/GETSET.ASM create mode 100644 v2.0/source/HRDDRV.ASM create mode 100644 v2.0/source/IFEQU.ASM create mode 100644 v2.0/source/INCOMP.txt create mode 100644 v2.0/source/INIT.ASM create mode 100644 v2.0/source/INT24.txt create mode 100644 v2.0/source/MISC.ASM create mode 100644 v2.0/source/MORE.ASM create mode 100644 v2.0/source/MOREMES.ASM create mode 100644 v2.0/source/MSCODE.ASM create mode 100644 v2.0/source/MSDATA.ASM create mode 100644 v2.0/source/MSDOS.ASM create mode 100644 v2.0/source/MSHEAD.ASM create mode 100644 v2.0/source/MSINIT.ASM create mode 100644 v2.0/source/PCLOCK.ASM create mode 100644 v2.0/source/PRINT.ASM create mode 100644 v2.0/source/PRINT_v211.ASM create mode 100644 v2.0/source/PROC.ASM create mode 100644 v2.0/source/PROFIL.ASM create mode 100644 v2.0/source/PROFILE.txt create mode 100644 v2.0/source/PROHST.HLP create mode 100644 v2.0/source/QUICK.txt create mode 100644 v2.0/source/RDATA.ASM create mode 100644 v2.0/source/README.txt create mode 100644 v2.0/source/RECMES.ASM create mode 100644 v2.0/source/RECOVER.ASM create mode 100644 v2.0/source/ROM.ASM create mode 100644 v2.0/source/RUCODE.ASM create mode 100644 v2.0/source/SKELIO.ASM create mode 100644 v2.0/source/SORT.ASM create mode 100644 v2.0/source/SORTMES.ASM create mode 100644 v2.0/source/STDBUF.ASM create mode 100644 v2.0/source/STDCALL.ASM create mode 100644 v2.0/source/STDCTRLC.ASM create mode 100644 v2.0/source/STDFCB.ASM create mode 100644 v2.0/source/STDIO.ASM create mode 100644 v2.0/source/STDPROC.ASM create mode 100644 v2.0/source/STDSW.ASM create mode 100644 v2.0/source/STRIN.ASM create mode 100644 v2.0/source/SYS.ASM create mode 100644 v2.0/source/SYSCALL.ASM create mode 100644 v2.0/source/SYSCALL.txt create mode 100644 v2.0/source/SYSIMES.ASM create mode 100644 v2.0/source/SYSINIT.ASM create mode 100644 v2.0/source/SYSINIT.txt create mode 100644 v2.0/source/SYSMES.ASM create mode 100644 v2.0/source/TCODE.ASM create mode 100644 v2.0/source/TCODE2.ASM create mode 100644 v2.0/source/TCODE3.ASM create mode 100644 v2.0/source/TCODE4.ASM create mode 100644 v2.0/source/TCODE5.ASM create mode 100644 v2.0/source/TDATA.ASM create mode 100644 v2.0/source/TIME.ASM create mode 100644 v2.0/source/TSPC.ASM create mode 100644 v2.0/source/TUCODE.ASM create mode 100644 v2.0/source/UINIT.ASM create mode 100644 v2.0/source/UTILITY.txt create mode 100644 v2.0/source/WSBAUD.BAS create mode 100644 v2.0/source/WSMSGS.OVR create mode 100644 v2.0/source/WSOVLY1.OVR create mode 100644 v2.0/source/XENIX.ASM create mode 100644 v2.0/source/XENIX2.ASM (limited to 'v2.0/source') diff --git a/v2.0/source/ALLOC.ASM b/v2.0/source/ALLOC.ASM new file mode 100644 index 0000000..7b69826 --- /dev/null +++ b/v2.0/source/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/v2.0/source/ANSI.txt b/v2.0/source/ANSI.txt new file mode 100644 index 0000000..040d9d2 Binary files /dev/null and b/v2.0/source/ANSI.txt differ diff --git a/v2.0/source/BUF.ASM b/v2.0/source/BUF.ASM new file mode 100644 index 0000000..f1ad800 --- /dev/null +++ b/v2.0/source/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/v2.0/source/CHKDSK.ASM b/v2.0/source/CHKDSK.ASM new file mode 100644 index 0000000..c305a1d --- /dev/null +++ b/v2.0/source/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/v2.0/source/CHKMES.ASM b/v2.0/source/CHKMES.ASM new file mode 100644 index 0000000..83af5ba --- /dev/null +++ b/v2.0/source/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/v2.0/source/CHKPROC.ASM b/v2.0/source/CHKPROC.ASM new file mode 100644 index 0000000..b003f83 --- /dev/null +++ b/v2.0/source/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/v2.0/source/COMEQU.ASM b/v2.0/source/COMEQU.ASM new file mode 100644 index 0000000..81763fb --- /dev/null +++ b/v2.0/source/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/v2.0/source/COMLINK b/v2.0/source/COMLINK new file mode 100644 index 0000000..f7dd961 Binary files /dev/null and b/v2.0/source/COMLINK differ diff --git a/v2.0/source/COMMAND.ASM b/v2.0/source/COMMAND.ASM new file mode 100644 index 0000000..db2783a --- /dev/null +++ b/v2.0/source/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/v2.0/source/COMSEG.ASM b/v2.0/source/COMSEG.ASM new file mode 100644 index 0000000..81ab3c8 --- /dev/null +++ b/v2.0/source/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/v2.0/source/COMSW.ASM b/v2.0/source/COMSW.ASM new file mode 100644 index 0000000..830585f --- /dev/null +++ b/v2.0/source/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/v2.0/source/CONFIG.txt b/v2.0/source/CONFIG.txt new file mode 100644 index 0000000..bfb1985 Binary files /dev/null and b/v2.0/source/CONFIG.txt differ diff --git a/v2.0/source/COPY.ASM b/v2.0/source/COPY.ASM new file mode 100644 index 0000000..0456a4f --- /dev/null +++ b/v2.0/source/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/v2.0/source/COPYPROC.ASM b/v2.0/source/COPYPROC.ASM new file mode 100644 index 0000000..f6e3bb1 --- /dev/null +++ b/v2.0/source/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/v2.0/source/CPARSE.ASM b/v2.0/source/CPARSE.ASM new file mode 100644 index 0000000..967efaa --- /dev/null +++ b/v2.0/source/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/v2.0/source/CTRLC.ASM b/v2.0/source/CTRLC.ASM new file mode 100644 index 0000000..054903d --- /dev/null +++ b/v2.0/source/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/v2.0/source/DEBASM.ASM b/v2.0/source/DEBASM.ASM new file mode 100644 index 0000000..a0fb0db --- /dev/null +++ b/v2.0/source/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/v2.0/source/DEBCOM1.ASM b/v2.0/source/DEBCOM1.ASM new file mode 100644 index 0000000..8e992d9 --- /dev/null +++ b/v2.0/source/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/v2.0/source/DEBCOM2.ASM b/v2.0/source/DEBCOM2.ASM new file mode 100644 index 0000000..a800d4b --- /dev/null +++ b/v2.0/source/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/v2.0/source/DEBCONST.ASM b/v2.0/source/DEBCONST.ASM new file mode 100644 index 0000000..e8f8c35 --- /dev/null +++ b/v2.0/source/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/v2.0/source/DEBDATA.ASM b/v2.0/source/DEBDATA.ASM new file mode 100644 index 0000000..fbe4a3f Binary files /dev/null and b/v2.0/source/DEBDATA.ASM differ diff --git a/v2.0/source/DEBEQU.ASM b/v2.0/source/DEBEQU.ASM new file mode 100644 index 0000000..5a20f01 --- /dev/null +++ b/v2.0/source/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/v2.0/source/DEBMES.ASM b/v2.0/source/DEBMES.ASM new file mode 100644 index 0000000..791b2e5 Binary files /dev/null and b/v2.0/source/DEBMES.ASM differ diff --git a/v2.0/source/DEBUASM.ASM b/v2.0/source/DEBUASM.ASM new file mode 100644 index 0000000..6a53124 --- /dev/null +++ b/v2.0/source/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/v2.0/source/DEBUG.ASM b/v2.0/source/DEBUG.ASM new file mode 100644 index 0000000..91db1ca --- /dev/null +++ b/v2.0/source/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/v2.0/source/DEV.ASM b/v2.0/source/DEV.ASM new file mode 100644 index 0000000..b640d55 --- /dev/null +++ b/v2.0/source/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/v2.0/source/DEVDRIV.txt b/v2.0/source/DEVDRIV.txt new file mode 100644 index 0000000..3c82793 --- /dev/null +++ b/v2.0/source/DEVDRIV.txt @@ -0,0 +1,802 @@ + MS-DOS 2.0 Device Drivers + +INTRODUCTION + + In the past, DOS-device driver (BIOS for those who are +familiar with CP/M) communication has been mediated with +registers and a fixed-address jump-table. This approach +has suffered heavily from the following two observations: + + o The old jump-table ideas of the past are fixed in + scope and allow no extensibility. + + o The past device driver interfaces have been written + without regard for the true power of the hardware. + When a multitasking system or interrupt driven + hardware is installed a new BIOS must be written + largely from scratch. + + In MSDOS 2.0, the DOS-device driver interface has changed +from the old jump-table style to one in which the device +drivers are linked together in a list. This allows new +drivers for optional hardware to be installed (and even +written) in the field by other vendors or the user himself. +This flexibility is one of the major new features of MS-DOS +2.0. + + Each driver in the chain defines two entry points; the +strategy routine and the interrupt routine. The 2.0 DOS +does not really make use of two entry points (it simply calls +strategy, then immediately calls interrupt). This dual entry +point scheme is designed to facilitate future multi-tasking +versions of MS-DOS. In multi-tasking environments I/O must +be asynchronous, to accomplish this the strategy routine +will be called to queue (internally) a request and return +quickly. It is then the responsibility of the interrupt +routine to perform the actual I/O at interrupt time by picking +requests off the internal queue (set up by the strategy +routine), and process them. When a request is complete, +it is flagged as "done" by the interrupt routine. The DOS +periodically scans the list of requests looking for ones +flagged as done, and "wakes up" the process waiting for the +completion of the request. + + In order for requests to be queued as above it is no +longer sufficient to pass I/O information in registers, since +many requests may be pending at any one time. Therefore +the new device interface uses data "packets" to pass request +information. A device is called with a pointer to a packet, +this packet is linked into a global chain of all pending +I/O requests maintained by the DOS. The device then links +the packet into its own local chain of requests for this +particular device. The device interrupt routine picks +requests of the local chain for processing. The DOS scans +the global chain looking for completed requests. These +packets are composed of two pieces, a static piece which +has the same format for all requests (called the static +request header), which is followed by information specific +to the request. Thus packets have a variable size and format. + + At this points it should be emphasized that MS-DOS 2.0 +does not implement most of these features, as future versions +will. There is no global or local queue. Only one request +is pending at any one time, and the DOS waits for this current +request to be completed. For 2.0 it is sufficient for the +strategy routine to simply store the address of the packet +at a fixed location, and for the interrupt routine to then +process this packet by doing the request and returning. +Remember: the DOS just calls the strategy routine and then +immediately calls the interrupt routine, it is assumed that +the request is completed when the interrupt routine returns. +This additional functionality is defined at this time so +that people will be aware and thinking about the future. + + +FORMAT OF A DEVICE DRIVER + + A device driver is simply a relocatable memory image +with all of the code in it to implement the device (like +a .COM file, but not ORGed at 100 Hex). In addition it has +a special header at the front of it which identifies it as +a device, defines the strategy and interrupt entry points, +and defines various attributes. It should also be noted +that there are two basic types of devices. + + The first is character devices. These are devices which +are designed to do character I/O in a serial manner like +CON, AUX, and PRN. These devices are named (ie. CON, AUX, +CLOCK, etc.), and users may open channels (FCBs) to do I/O +to them. + + The second class of devices is block devices. These +devices are the "disk drives" on the system, they can do +random I/O in pieces called blocks (usually the physical +sector size) and hence the name. These devices are not +"named" as the character devices are, and therefore cannot +be "opened" directly. Instead they are "mapped" via the +drive letters (A,B,C, etc.). + + Block devices also have units. In other words a single +driver may be responsible for one or more disk drives. For +instance block device driver ALPHA (please note that we cannot +actually refer to block devices by a name!) may be +responsible for drives A,B,C and D, this simply means that +it has four units (0-3) defined and therefore takes up four +drive letters. Which units correspond to which drive letters +is determined by the position of the driver in the chain +of all drivers: if driver ALPHA is the first block driver +in the device chain, and it defines 4 units (0-3), then they +will be A,B,C and D. If BETA is the second block driver +and defines three units (0-2), then they will be E,F and +G and so on. MS-DOS 2.0 is not limited to 16 block device +units, as previous versions were. The theoretical limit +is 63 (2^6 - 1), but it should be noted that after 26 the +drive letters get a little strange (like ] \ and ^). NOTE: +Character devices cannot define multiple units (this because +they have only one name). + + +Here is what that special device header looks like: + + +--------------------------------------+ + | DWORD Pointer to next device | + | (Must be set to -1) | + +--------------------------------------+ + | WORD Attributes | + | Bit 15 = 1 if char device 0 if blk | + | if bit 15 is 1 | + | Bit 0 = 1 if Current sti device | + | Bit 1 = 1 if Current sto output | + | Bit 2 = 1 if Current NUL device | + | Bit 3 = 1 if Current CLOCK dev | + | Bit 4 = 1 if SPECIAL | + | Bit 14 is the IOCTL bit (see below) | + | Bit 13 is the NON IBM FORMAT bit | + +--------------------------------------+ + | WORD Pointer to Device strategy | + | entry point | + +--------------------------------------+ + | WORD Pointer to Device interrupt | + | entry point | + +--------------------------------------+ + | 8-BYTE character device name field | + | Character devices set a device name | + | For block devices the first byte is | + | The number of units | + +--------------------------------------+ + + Note that the device entry points are words. They must +be offsets from the same segment number used to point to +this table. Ie. if XXX.YYY points to the start of this +table, then XXX.strategy and XXX.interrupt are the entry +points. + + A word about the Attribute field. This field is used +most importantly to tell the system whether this device is +a block or character device (bit 15). Most of other bits +are used to give selected character devices certain special +treatment (NOTE: these bits mean nothing on a block device). +Let's say a user has a new device driver which he wants to +be the standard input and output. Besides just installing +the driver he needs to tell SYSINIT (and the DOS) that he +wishes his new driver to override the current sti and sto +(the "CON" device). This is accomplished by setting the +attributes to the desired characteristics, so he would set +Bits 0 and 1 to 1 (note that they are separate!!). Similarly +a new CLOCK device could be installed by setting that +attribute, see the section at the end on the CLOCK device. +NOTE: that although there is a NUL device attribute, the +NUL device cannot be re-assigned. This attribute exists +for the DOS so that it can tell if the NUL device is being +used. + + The NON IBM FORMAT bit applies only to block devices +and effects the operation of the get BPB device call (see +below). + + The other bit of interest is the IOCTL bit which has +meaning on character or block devices. This bit tells the +DOS whether this device can handle control strings (via the +IOCTL system call). + + If a driver cannot process control strings, it should +initially set this bit to 0. This tells the DOS to return +an error if an attempt is made (via IOCTL system call) to +send or receive control strings to this device. A device +which can process control strings should initialize it to +1. For drivers of this type, the DOS will make calls to +the IOCTL INPUT and OUTPUT device functions to send and +receive IOCTL strings (see IOCTL in the SYSTEM-CALLS +document). + + The IOCTL functions allow data to be sent and received +by the device itself for its own use (to set baud rate, stop +bits, form length etc., etc.), instead of passing data over +the device channel as a normal read or write does. The +interpretation of the passed information is up to the device, +but it MUST NOT simply be treated as a normal I/O. + + The SPECIAL bit applies only to character drivers and +more particularly to CON drivers. The new 2.0 interface +is a much more general and consistent interface than the +old 1.25 DOS interface. It allows for a number of additional +features of 2.0. It is also slower than 1.25 if old style +"single byte" system calls are made. To make most efficient +use of the interface all applications should block their +I/O as much as possible. This means make one XENIX style +system call to output X bytes rather than X system calls +to output one byte each. Also putting a device channel in +RAW mode (see IOCTL) provides a means of putting out +characters even FASTER than 1.25. To help alleviate the +CON output speed problem for older programs which use the +1 - 12 system calls to output large amounts of data the +SPECIAL bit has been implemented. If this bit is 1 it means +the device is the CON output device, and has implemented +an interrupt 29 Hex handler, where the 29 Hex handler is +defined as follows: + + Interrupt 29h handlers + + Input: + Character in AL + + Function: + output the character in al to the user + screen. + Output: + None + Registers: + all registers except bx must be preserved. + No registers except for al have a known or + consistent value. + + If a character device implements the SPECIAL bit, it +is the responsibility of the driver to install an address +at the correct location in the interrupt table for interrupt +29 Hex as part of its INIT code. IMPLICATION: There can +be only one device driver with the SPECIAL bit set in the +system. There is no check to insure this state. + +WARNING: THIS FEATURE WILL NOT BE SUPPORTED IN FUTURE VERSIONS + OF THE OPERATING SYSTEM. IMPLICATION: Any application + (not device driver) which uses INT 29H directly will + not work on future versions, YOU HAVE BEEN WARNED. + + In order to "make" a device driver that SYSINIT can +install, a memory image or .EXE (non-IBM only) format file +must be created with the above header at the start. The +link field should be initialized to -1 (SYSINIT fills it +in). The attribute field and entry points must be set +correctly, and if the device is a character device, the name +field must be filled in with the name (if a block device +SYSINIT will fill in the correct unit count). This name +can be any 8 character "legal" file name. In fact SYSINIT +always installs character devices at the start of the device +list, so if you want to install a new CON device all you +have to do is name it "CON". The new one is ahead of the +old one in the list and thus preempts the old one as the +search for devices stops on the first match. Be sure to +set the sti and sto bits on a new CON device! + +NOTE: Since SYSINIT may install the driver anywhere, you + must be very careful about FAR memory references. You + should NOT expect that your driver will go in the same + place every time (The default BIOS drivers are exempted + from this of course). + + +INSTALLATION OF DEVICE DRIVERS + + Unlike past versions MS-DOS 2.0 allows new device drivers +to be installed dynamically at boot time. This is +accomplished by the new SYSINIT module supplied by Microsoft, +which reads and processes the CONFIG.SYS file. This module +is linked together with the OEM default BIOS in a similar +manner to the way FORMAT is built. + + One of the functions defined for each device is INIT. +This routine is called once when the device is installed, +and never again. The only thing returned by the init routine +is a location (DS:DX) which is a pointer to the first free +byte of memory after the device driver, (like a terminate +and stay resident). This pointer method can be used to "throw +away" initialization code that is only needed once, saving +on space. + + Block devices are installed the same way and also return +a first free byte pointer as above, additional information +is also returned: + + o The number of units is returned, this determines + logical device names. If the current maximum logical + device letter is F at the time of the install call, + and the init routine returns 4 as the number of units, + then they will have logical names G, H, I and J. + This mapping is determined by by the position of + the driver in the device list and the number of units + on the device (stored in the first byte of the device + name field). + + o A pointer to a BPB (Bios Parameter Block) pointer + array is also returned. This will be similar to + the INIT table used in previous versions, but will + have more information in it. There is one table + for each unit defined. These blocks will be used + to build a DPB (Drive Parameter Block) for each of + the units. The pointer passed to the DOS from the + driver points to an array of n word pointers to BPBs + where n is the number of units defined. In this + way if all units are the same, all of the pointers + can point to the same BPB, saving space. NOTE: this + array must be protected (below the free pointer set + by the return) since the DPB will be built starting + at the byte pointed to by the free pointer. The + sector size defined must be less than or equal to + the maximum sector size defined at default BIOS init + time. If it isn't the install will fail. One new + piece of DPB info set from this table will be a "media + descriptor byte". This byte means nothing to the + DOS, but is passed to devices so that they know what + form of a DPB the DOS is currently using for a + particular Drive-Unit. + + Block devices may take several approaches; they may be +dumb or smart. A dumb device would define a unit (and +therefore a DPB) for each possible media drive combination. +Unit 0 = drive 0 single side, unit 1 = drive 0 double side, +etc. For this approach media descriptor bytes would mean +nothing. A smart device would allow multiple media per unit, +in this case the BPB table returned at init must define space +large enough to accommodate the largest possible media +supported. Smart drivers will use the "media byte" to pass +around info about what media is currently in a unit. NOTE: +If the DPB is a "hybrid" made to get the right sizes, it +should give an invalid "media byte" back to the DOS. + + The BOOT (default BIOS) drivers are installed pretty +much as above. The preset device list is scanned. If block +drivers are encountered they are installed as above (with +the exception that the break is not moved since the drivers +are already resident in the BIOS). Note that the logical +drive letters are assigned in list order, thus the driver +which is to have logical A must be the first unit of the +first block device in the list. The order of character +devices is also important. There must be at least 4 character +devices defined at boot which must be the first four devices +(of either type), the first will become standard input, +standard output, and standard error output. The second will +become standard auxiliary input and output, the third will +become standard list output, and the forth will become the +date/time (CLOCK) device. Thus the BIOS device list must +look like this: + +->CON->AUX->PRN->CLOCK->any other block or character devices + +THE DRIVER + + A device driver will define the following functions: + + Command Function + Code + + 0 INIT + 1 MEDIA CHECK (Block only, NOP for character) + 2 BUILD BPB " " " " " + 3 IOCTL INPUT (Only called if device has IOCTL) + 4 INPUT (read) + 5 NON-DESTRUCTIVE INPUT NO WAIT (Char devs only) + 6 INPUT STATUS " " " + 7 INPUT FLUSH " " " + 8 OUTPUT (write) + 9 OUTPUT (Write) with verify + 10 OUTPUT STATUS " " " + 11 OUTPUT FLUSH " " " + 12 IOCTL OUTPUT (Only called if device has IOCTL) + + As mentioned before, the first entry point is the strategy +routine which is called with a pointer to a data block. This +call does not perform the request, all it does is queue it +(save the data block pointer). The second interrupt entry +point is called immediately after the strategy call. The +"interrupt" routine is called with no parameters, its primary +function is to perform the operation based on the queued +data block and set up any returns. + + The "BUILD BPB" and "MEDIA CHECK" are the interesting +new ones, these are explained by examining the sequence of +events in the DOS which occurs when a drive access call (other +than read or write) is made: + + I. Turn drive letter into DPB pointer by looking + for DPB with correct driver-unit number. + + II. Call device driver and request media check for + Drive-Unit. DOS passes its current Media + descriptor byte (from DPB). Call returns: + + Media Not Changed + Media Changed + Not Sure + Error + + Error - If an error occurs the error code should + be set accordingly. + + Media Not changed - Current DPB and media byte + are OK, done. + + Media Changed - Current DPB and media are wrong, + invalidate any buffers for this unit, and + goto III. + + Not Sure - If there are dirty buffers for this + unit, assume DPB and media byte are OK and + done. If nothing dirty, assume media changed, + invalidate any buffers for unit, and goto + III. + + NOTE: If a hybrid DPB was built at init and + an invalid Media byte was set, the driver + should return media changed when this invalid + media byte is encountered. + + III. Call device driver to build BPB with media byte + and buffer. + + What the driver must do at step III is determine the +correct media that is currently in the unit, and return a +pointer to a BPB table (same as for the install call). This +table will be used as at init to build a correct DPB for +the unit If the determined media descriptor byte in the table +turns out to be the same as the one passed in, then the DOS +will not build a new table, but rather just use the old one. +Therefore in this case the driver doesn't have to correctly +fill in the other entries if desired. + + The build BPB call also gets a pointer to a one sector +buffer. What this buffer contains is determined by the NON +IBM FORMAT bit in the attribute field. If the bit is zero +(device is IBM format compatible) then the buffer contains +the first sector of the first FAT, in particular the FAT +ID byte is the first byte of this buffer. NOTE: It must +be true that the BPB is the same, as far as location of the +FAT is concerned, for all possible media. This is because +this first FAT sector must be read BEFORE the actual BPB +is returned. If the NON IBM FORMAT bit is set then the +pointer points to one sector of scratch space which may be +used for anything. + +CALL FORMAT + + When the DOS calls a device driver to perform a finction, +it passes a structure (Drive Request Structure) in ES:BX +to perform operations and does a long call to the driver's +strategy entry point. This structure is a fixed length header +(Static Request Header) followed by data pertinent to the +operation being performed. NOTE: It is the drivers +responsibility to preserve machine state. + +STATIC REQUEST HEADER -> + +-----------------------------+ + | BYTE length of record | + | Length in bytes of this | + | Drive Request Structure | + +-----------------------------+ + | BYTE unit code | + | The subunit the operation | + | is for (minor device) | + | (no meaning on character | + | devices) | + +-----------------------------+ + | BYTE command code | + +-----------------------------+ + | WORD Status | + +-----------------------------+ + | 8 bytes reserved here for | + | two DWORD links. One will | + | be a link for the DOS queue | + | The other for the device | + | queue | + +-----------------------------+ + +STATUS WORD + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ + | E | | B | D | | + | R | RESERVED | U | O | ERROR CODE (bit 15 on)| + | R | | I | N | | + +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ + + The status word is zero on entry and is set by the driver +interrupt routine on return. + + Bit 8 is the done bit, it means the operation is complete. +For the moment the Driver just sets it to one when it exits, +in the future this will be set by the interrupt routine to +tell the DOS the operation is complete. + + Bit 15 is the error bit, if it is set then the low 8 +bits indicate the error: + + 0 Write Protect violation + (NEW) 1 Unknown Unit + 2 Drive not ready + (NEW) 3 Unknown command + 4 CRC error + (NEW) 5 Bad Drive Request Structure length + 6 Seek error + (NEW) 7 Unknown media + 8 Sector not found + (NEW) 9 Printer out of paper + A Write Fault + (NEW) B Read Fault + C General Failure + +Bit 9 is the busy bit which is set only by status calls (see +STATUS CALL below). + + + Here is the data block format for each function: + +READ or WRITE - ES:BX (Including IOCTL) -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + | BYTE Media descriptor from DPB | + +------------------------------------+ + | DWORD transfer address | + +------------------------------------+ + | WORD byte/sector Count | + ---+------------------------------------+--- + | WORD starting sector number | + | (ignored on Char Devs) | + +------------------------------------+ + + In addition to setting the status word, the driver must +set the Sector count to the actual number of sectors (or +bytes) transferred. NOTE: No error check is performed on +an IOCTL I/O call, driver MUST correctly set the return sector +(byte) count to the actual number of bytes transferred, +however. + +NOTE: THE FOLLOWING APPLIES TO BLOCK DEVICE DRIVERS. + + Under certain circumstances the BIOS may be asked to +do a write operation of 64K bytes which seems to be a "wrap +around" of the transfer address in the BIOS I/O packet. This +arises due to an optimization added to the write code in +MS-DOS. It will only manifest on user WRITEs which are within +a sector size of 64K bytes on files which are "growing" past +the current EOF. IT IS ALLOWABLE FOR THE BIOS TO IGNORE +THE BALANCE OF THE WRITE WHICH "WRAPS AROUND" IF IT SO +CHOOSES. For instance a WRITE of 10000H bytes worth of +sectors with a transfer address of XXX:1 could ignore the +last two bytes (remember that a user program can never request +an I/O of more than FFFFH bytes and cannot wrap around (even +to 0) in his transfer segment, so in this case the last two +bytes can be ignored). + + +NON DESRUCTIVE READ NO WAIT - ES:BX -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + | BYTE read from device | + +------------------------------------+ + + This call is analogous to the console input status call +on MS-DOS 1.25. If the character device returns Busy bit += 0 (characters in buffer), then the next character that +would be read is returned. This character is NOT removed +from the input buffer (hence the term Non Destructive Read). +In essence this call allows the DOS to look ahead one input +character. + + +MEDIA CHECK - ES:BX -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + | BYTE Media Descriptor from DPB | + +------------------------------------+ + | BYTE returned | + +------------------------------------+ + + In addition to setting status word, driver must set the +return byte. + + Return Byte : + -1 Media has been changed + 0 Don't know if media has been changed + 1 Media has not been changed + + If the driver can return -1 or 1 (by having a door-lock +or other interlock mechanism) the performance of MSDOS 2.0 +is enhanced as the DOS need not reread the FAT for each +directory access. + + +BUILD BPB - ES:BX -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + | BYTE Media Descriptor from DPB | + +------------------------------------+ + | DWORD Transfer Address | + | (points to one sectors worth of | + | scratch space or first sector | + | of FAT depending on the value | + | of the NON IBM FORMAT bit) | + +------------------------------------+ + | DWORD Pointer to BPB | + +------------------------------------+ + + If the NON IBM FORMAT bit of the device is set, then +the DWORD Transfer Address points to a one sector buffer +which can be used for any purpose. If the NON IBM FORMAT +bit is 0, then this buffer contains the first sector of the +FAT; in this case the driver must not alter this buffer (this +mode is useful if all that is desired is to read the FAT +ID byte). + + If IBM compatible format is used (NON IBM FORMAT BIT += 0), then it must be true that the first sector of the first +FAT is located at the same sector on all possible media. +This is because the FAT sector will be read BEFORE the media +is actually determined. + + In addition to setting status word, driver must set the +Pointer to the BPB on return. + + + In order to allow for many different OEMs to read each +other's disks, the following standard is suggested: The +information relating to the BPB for a particular piece of +media is kept in the boot sector for the media. In +particular, the format of the boot sector is: + + +------------------------------------+ + | 3 BYTE near JUMP to boot code | + +------------------------------------+ + | 8 BYTES OEM name and version | + ---+------------------------------------+--- + B | WORD bytes per sector | + P +------------------------------------+ + B | BYTE sectors per allocation unit | + +------------------------------------+ + | | WORD reserved sectors | + V +------------------------------------+ + | BYTE number of FATs | + +------------------------------------+ + | WORD number of root dir entries | + +------------------------------------+ + | WORD number of sectors in logical | + ^ | image | + | +------------------------------------+ + B | BYTE media descriptor | + P +------------------------------------+ + B | WORD number of FAT sectors | + ---+------------------------------------+--- + | WORD sectors per track | + +------------------------------------+ + | WORD number of heads | + +------------------------------------+ + | WORD number of hidden sectors | + +------------------------------------+ + + The three words at the end are optional, the DOS doesn't +care about them (since they are not part of the BPB). They +are intended to help the BIOS understand the media. Sectors +per track may be redundant (could be figured out from total +size of the disk). Number of heads is useful for supporting +different multi-head drives which have the same storage +capacity, but a different number of surfaces. Number of +hidden sectors is useful for supporting drive partitioning +schemes. + + + Currently, the media descriptor byte has been defined +for a small range of media: + + 5 1/4" diskettes: + + Flag bits: + 01h - on -> 2 double sided + + All other bits must be on. + + 8" disks: + FEh - IBM 3740 format, singled-sided, single-density, + 128 bytes per sector, soft sectored, 4 sectors + per allocation unit, 1 reserved sector, 2 FATs, + 68 directory entries, 77*26 sectors + + FDh - 8" IBM 3740 format, singled-sided, + single-density, 128 bytes per sector, soft + sectored, 4 sectors per allocation unit, 4 + reserved sectors, 2 FATs, 68 directory entries, + 77*26 sectors + + FEh - 8" Double-sided, double-density, 1024 bytes + per sector, soft sectored, 1 sector per allocation + unit, 1 reserved sector, 2 FATs, 192 directory + entries, 77*8*2 sectors + + +STATUS Calls - ES:BX -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + + All driver must do is set status word accordingly and +set the busy bit as follows: + + o For output on character devices: If it is 1 on + return, a write request (if made) would wait for + completion of a current request. If it is 0, there + is no current request and a write request (if made) + would start immediately. + + o For input on character devices with a buffer a return + of 1 means, a read request (if made) would go to + the physical device. If it is 0 on return, then + there are characters in the devices buffer and a + read would return quickly, it also indicates that + the user has typed something. The DOS assumes all + character devices have an input type ahead buffer. + Devices which don't have them should always return + busy = 0 so that the DOS won't hang waiting for + something to get into a buffer which doesn't exist. + + +FLUSH Calls - ES:BX -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + + This call tells the driver to flush (terminate) all +pending requests that it has knowledge of. Its primary use +is to flush the input queue on character devices. + + +INIT - ES:BX -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + | BYTE # of units | + +------------------------------------+ + | DWORD Break Address | + ---+------------------------------------+--- + | DWORD Pointer to BPB array | + | (not set by Character devices) | + +------------------------------------+ + + The number of units, break address, and BPB pointer are +set by the driver. + + +FORMAT OF BPB (Bios Parameter Block) - + + +------------------------------------+ + | WORD Sector size in Bytes | + | Must be at least 32 | + +------------------------------------+ + | BYTE Sectors/Allocation unit | + | Must be a power of 2 | + +------------------------------------+ + | WORD Number of reserved sectors | + | May be zero | + +------------------------------------+ + | BYTE Number of FATS | + +------------------------------------+ + | WORD Number of directory entries | + +------------------------------------+ + | WORD Total number of sectors | + +------------------------------------+ + | BYTE Media descriptor | + +------------------------------------+ + | WORD Number of sectors occupied by | + | FAT | + +------------------------------------+ + + +THE CLOCK DEVICE + + One of the most popular add on boards seems to be "Real +Time CLOCK Boards". To allow these boards to be integrated +into the system for TIME and DATE, there is a special device +(determined by the attribute word) which is the CLOCK device. +In all respects this device defines and performs functions +like any other character device (most functions will be "set +done bit, reset error bit, return). When a read or write +to this device occurs, exactly 6 bytes are transferred. This +I/O can be thought of as transferring 3 words which correspond +exactly to the values of AX, CX and DX which were used in +the old 1.25 DOS date and time routines. Thus the first +two bytes are a word which is the count of days since 1-1-80. +The third byte is minutes, the fourth hours, the fifth +hundredths of seconds, and the sixth seconds. Reading the +CLOCK device gets the date and time, writing to it sets the +date and time. + \ No newline at end of file diff --git a/v2.0/source/DEVSYM.ASM b/v2.0/source/DEVSYM.ASM new file mode 100644 index 0000000..b648f04 Binary files /dev/null and b/v2.0/source/DEVSYM.ASM differ diff --git a/v2.0/source/DIR.ASM b/v2.0/source/DIR.ASM new file mode 100644 index 0000000..d0bb84f --- /dev/null +++ b/v2.0/source/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/v2.0/source/DIRCALL.ASM b/v2.0/source/DIRCALL.ASM new file mode 100644 index 0000000..db55ab8 --- /dev/null +++ b/v2.0/source/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/v2.0/source/DISK.ASM b/v2.0/source/DISK.ASM new file mode 100644 index 0000000..b1acd82 --- /dev/null +++ b/v2.0/source/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/v2.0/source/DISKCOPY.ASM b/v2.0/source/DISKCOPY.ASM new file mode 100644 index 0000000..56e39cb Binary files /dev/null and b/v2.0/source/DISKCOPY.ASM differ diff --git a/v2.0/source/DISKMES.ASM b/v2.0/source/DISKMES.ASM new file mode 100644 index 0000000..d5f0226 Binary files /dev/null and b/v2.0/source/DISKMES.ASM differ diff --git a/v2.0/source/DOSLINK b/v2.0/source/DOSLINK new file mode 100644 index 0000000..9d56841 --- /dev/null +++ b/v2.0/source/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/v2.0/source/DOSMAC.ASM b/v2.0/source/DOSMAC.ASM new file mode 100644 index 0000000..35c16f1 Binary files /dev/null and b/v2.0/source/DOSMAC.ASM differ diff --git a/v2.0/source/DOSMAC_v211.ASM b/v2.0/source/DOSMAC_v211.ASM new file mode 100644 index 0000000..3340505 --- /dev/null +++ b/v2.0/source/DOSMAC_v211.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/v2.0/source/DOSMES.ASM b/v2.0/source/DOSMES.ASM new file mode 100644 index 0000000..fb3f17a --- /dev/null +++ b/v2.0/source/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/v2.0/source/DOSSEG.ASM b/v2.0/source/DOSSEG.ASM new file mode 100644 index 0000000..5d7e8c2 --- /dev/null +++ b/v2.0/source/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/v2.0/source/DOSSYM.ASM b/v2.0/source/DOSSYM.ASM new file mode 100644 index 0000000..918ed5d --- /dev/null +++ b/v2.0/source/DOSSYM.ASM @@ -0,0 +1,904 @@ +include DOSMAC.ASM +IF2 + %OUT DOSSYM in Pass 2 +ENDIF + +IFNDEF ALTVECT +ALTVECT EQU 0 ;FALSE +ENDIF + +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 + DB ? ; pack 2 12 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 + +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 + +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 +; XENIX CALLS +; 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 + +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 + \ No newline at end of file diff --git a/v2.0/source/DOSSYM_v211.ASM b/v2.0/source/DOSSYM_v211.ASM new file mode 100644 index 0000000..106e115 --- /dev/null +++ b/v2.0/source/DOSSYM_v211.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/v2.0/source/EDLIN.ASM b/v2.0/source/EDLIN.ASM new file mode 100644 index 0000000..f795ac4 --- /dev/null +++ b/v2.0/source/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/v2.0/source/EDLMES.ASM b/v2.0/source/EDLMES.ASM new file mode 100644 index 0000000..f49ed96 Binary files /dev/null and b/v2.0/source/EDLMES.ASM differ diff --git a/v2.0/source/EDLPROC.ASM b/v2.0/source/EDLPROC.ASM new file mode 100644 index 0000000..0128b1d --- /dev/null +++ b/v2.0/source/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/v2.0/source/EXE2BIN.ASM b/v2.0/source/EXE2BIN.ASM new file mode 100644 index 0000000..80deb43 --- /dev/null +++ b/v2.0/source/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/v2.0/source/EXEC.ASM b/v2.0/source/EXEC.ASM new file mode 100644 index 0000000..d41aceb --- /dev/null +++ b/v2.0/source/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/v2.0/source/EXEMES.ASM b/v2.0/source/EXEMES.ASM new file mode 100644 index 0000000..542ec12 Binary files /dev/null and b/v2.0/source/EXEMES.ASM differ diff --git a/v2.0/source/FAT.ASM b/v2.0/source/FAT.ASM new file mode 100644 index 0000000..b1a4863 --- /dev/null +++ b/v2.0/source/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/v2.0/source/FC.ASM b/v2.0/source/FC.ASM new file mode 100644 index 0000000..21ed991 --- /dev/null +++ b/v2.0/source/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/v2.0/source/FCB.ASM b/v2.0/source/FCB.ASM new file mode 100644 index 0000000..11528f7 --- /dev/null +++ b/v2.0/source/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/v2.0/source/FCMES.ASM b/v2.0/source/FCMES.ASM new file mode 100644 index 0000000..1fc52cb Binary files /dev/null and b/v2.0/source/FCMES.ASM differ diff --git a/v2.0/source/FIND.ASM b/v2.0/source/FIND.ASM new file mode 100644 index 0000000..7c82768 --- /dev/null +++ b/v2.0/source/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/v2.0/source/FINDMES.ASM b/v2.0/source/FINDMES.ASM new file mode 100644 index 0000000..cb120db Binary files /dev/null and b/v2.0/source/FINDMES.ASM differ diff --git a/v2.0/source/FORMAT.ASM b/v2.0/source/FORMAT.ASM new file mode 100644 index 0000000..694857b --- /dev/null +++ b/v2.0/source/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 =, AX--+ | If variable HARDFLAG + | | is set then the loop ++----------+ | is only performed +| | | once. +| WRTFAT | | ++----------+ | + | | + +------+ | + | DONE | | + +------+ | + +---->--------------------------+ + + The INIT, DISKFORMAT, and BADSECTOR routines are free +to use any MS-DOS system calls, except for calls that cause +disk accesses on the disk being formatted. DONE may use +ANY calls, since by the time it is called the new disk has +been formatted. + +The following data must be declared PUBLIC in a module +provided by the OEM: + + SWITCHLIST - A string of bytes. The first byte is count + N, followed by N characters which are the switches to + be accepted by the command line scanner. Alphabetic + characters must be in upper case (the numeric + characters 0-9 are allowed). The last three switches, + normally "O", "V" and "S", have pre-defined meanings. + + The "S" switch is the switch which causes the + system files IO.SYS, MSDOS.SYS, and COMMAND.COM to be + transfered to the disk after it is formatted thus + making a "S"ystem disk. The switch can be some letter + other than "S", but the last switch in the list is + assumed to have the meaning "transfer system", + regardles of what the particular letter is. + + The second to the last switch, "V", causes FORMAT + to prompt the user for a volume label after the disk + is formatted. Again, as with "S", the particular + letter is not important but rather the position in the + list. + + The third to the last switch, "O", causes FORMAT to + produce an IBM Personal Computer DOS version 1.X + compatible disk. Normally FORMAT causes a 0 byte to + be placed in the first byte of each directory entry + instead of the 0E5 Hex free entry designator. This + results in a very marked directory search performance + increase due to an optimization in the DOS. Disks + made this way cause trouble on IBM PC DOS 1.X + versions, however, which did not have this + optimization. The 0 byte fools IBM 1.X versions into + thinking these entries are allocated instead of free, + NOTE that IBM Personnal Computer DOS version 2.00 and + MS-DOS version 1.25 will have no trouble with these + disks, since they have the same optimization. The "O" + switch causes FORMAT to re-do the directory with a 0E5 + Hex byte at the start of each entry so that the disk + may be used with 1.X versions of IBM PC DOS, as well + as MS-DOS 1.25/2.00 and IBM PC DOS 2.00. This switch + should only be given when needed because it takes a + fair amount of time for FORMAT to perform the + conversion, and it noticably decreases 1.25 and 2.00 + performance on disks with few directory entries. + + Up to 16 switches are permitted. Normally a "C" + switch is specified for "Clear". This switch should + cause the formatting operation to be bypassed (within + DISKFORMAT or BADSECTOR). This is provided as a + time-saving convenience to the user, who may wish + to "start fresh" on a previosly formatted and used + disk. + + HARDFLAG - BYTE location which specifies whether the + OEM routine is formatting a fixed disk or a a drive + with removable media. A zero indicates removable + media, any other value indicates a fixed disk. The + status of this byte only effect the messages printed + by the main format module. This value should be + set or reset by the OEM supplied INIT routine. + + FATID - BYTE location containing the value to be used + in the first byte of the FAT. Must be in the range + F8 hex to FF hex. + + STARTSECTOR - WORD location containing the sector number + of the first sector of the data area. + + FATSPACE - WORD location containing the address of the + start of the FAT area. A FAT built in this area + will be written to disk using the OEM supplied WRTFAT + subroutine. 6k is sufficient to store any FAT. This + area must not overlap the FREESPACE area. + + FREESPACE - WORD location which contains the address + of the start of free memory space. This is where + the system will be loaded, by the Microsoft module, + for transferring to the newly formatted disk. Memory + should be available from this address to the end + of memory, so it is typically the address of the + end of the OEM module. + +The following routines must be declared PUBLIC in the +OEM-supplied module: + + INIT - An initialization routine. This routine is called + once at the start of the FORMAT run after the switches + have been processed. This routine should perform + any functions that only need to be done once per + FORMAT run. An example of what this routine might + do is read the boot sector into a buffer so that + it can be transferred to the new disks by DISKFORMAT. + If this routine returns with the CARRY flag set it + indicates an error, and FORMAT will print "Format + failure" and quit. This feature can be used to detect + conflicting switches (like specifying both single + and double density) and cause FORMAT to quit without + doing anything. + + DISKFORMAT - Formats the disk according to the options + indicated by the switches and the value of FATID + must be defined when it returns (although INIT may + have already done it). This routine is called once + for EACH disk to be formatted. If neccessary it + must transfer the Bootstrap loader. If any error + conditions are detected, set the CARRY flag and return + to FORMAT. FORMAT will report a 'Format failure' + and prompt for another disk. (If you only require + a clear directory and FAT then simply setting the + appropriate FATID, if not done by INIT, will be all + that DISKFORMAT must do.) + + BADSECTOR - Reports the sector number of any bad sectors + that may have been found during the formatting of + the disk. This routine is called at least once for + EACH disk to be formatted, and is called repeatedly + until AX is zero or the carry flag is set. The carry + flag is used just as in DISKFORMAT to indicate an + error, and FORMAT handles it in the same way. The + first sector in the data area must be in STARTSECTOR + for the returns from this routine to be interpreted + correctly. If there are bad sectors, BADSECTOR must + return a sector number in in register BX, the number + of consecutive bad sectors in register AX, and carry + clear. FORMAT will then process the bad sectors + and call BADSECTOR again. When BADSECTOR returns + with AX = 0 this means there are no more bad sectors; + FORMAT clears the directory and goes on to DONE, + so for this last return BX need not contain anything + meaningful. + + FORMAT processes bad sectors by determining their + corresponding allocation unit and marking that unit + with an FF7 hex in the File Allocation Table. CHKDSK + understands the FF7 mark as a flag for bad sectors + and accordingly reports the number of bytes marked + in this way. + + NOTE: Actual formatting of the disk can be done in + BADSECTOR instead of DISKFORMAT on a "report as you + go" basis. Formatting goes until a group of bad + sectors is encountered, BADSECTOR then reports them + by returning with AX and BX set. FORMAT will then + call BADSECTOR again and formatting can continue. + + WRTFAT - This routine is called after the disk is + formatted and bad sectors have been reported. Its + purpose is to write all copies of the FAT from the + area of memory referenced by FATSPACE to the drive + just formatted. It may be possible to use INT 26H + to perform the write, or a direct BIOS call. Whether + this is possible depends on whether the FAT ID byte + is used by the BIOS to determine the media in the + drive. If it is, these methods will probably fail + because there is no FAT ID byte on the disk yet (in + this case WRTFATs primary job is to get the FAT ID + byte out on the disk and thus solve the chicken and + egg problem). + + DONE - This routine is called after the formatting is + complete, the disk directory has been initialized, + and the system has been transferred. It is called + once for EACH disk to be formatted. This gives the + chance for any finishing-up operations, if needed. + If the OEM desires certain extra files to be put + on the diskette by default, or according to a switch, + this could be done in DONE. Again, as in BADSECTOR + and DISKFORMAT, carry flag set on return means an + error has occurred: 'Format failure' will be printed + and FORMAT will prompt for another disk. + + +The following data is declared PUBLIC in Microsoft's FORMAT +module: + + SWITCHMAP - A word with a bit vector indicating what + switches have been included in the command line. The + correspondence of the bits to the switches is + determined by SWITCHLIST. The right-most + (highest-addressed) switch in SWITCHLIST (which must + be the system transfer switch, normally "S") + corresponds to bit 0, the second from the right, + normally "V" to bit 1, etc. For example, if + SWITCHLIST is the string "7,'AGI2OVS'", and the user + specifies "/G/S" on the command line, then bit 6 will + be 0 (A not specified), bit 5 will be 1 (G specified), + bits 4,3,2 and 1 will be 0 (neither I,2,O or V + specified), and bit 0 will be 1 (S specified). + + Bits 0,1 and 2 are the only switches used in + Microsoft's FORMAT module. These switches are used 1) + after INIT has been called, to determine if it is + necessary to load the system; 2) after the last + BADSECTOR call, to determine if the system is to be + written, E5 directory conversion is to be done, and/or + a volume label is to be asked for. INIT may force + these bits set or reset if desired (for example, some + drives may never be used as system disk, such as hard + disks). After INIT, the "S" bit may be turned off + (but not on, since the system was never read) if + something happens that means the system should not be + transferred. + + After INIT, a second copy of SWITCHMAP is made + internally which is used to restore SWITCHMAP for + each disk to be formatted. FORMAT itself will turn + off the system bit if bad sectors are reported in + the system area; DISKFORMAT and BADSECTOR are also + allowed to change the map. However, these changes + affect only the current disk being formatted, since + SWITCHMAP is restored after each disk. (Changes + made to SWITCHMAP by INIT do affect ALL disks.) + + DRIVE - A byte containing the drive specified in the + command line. 0=A, 1=B, etc. + +Once the OEM-supplied module has been prepared, it must linked +with Microsoft's FORMAT.OBJ module and the FORMES.OBJ module. +If the OEM-supplied module is called OEMFOR.OBJ, then the +following linker command will do: + + LINK FORMAT FORMES OEMFOR; + +This command will produce a file called FORMAT.EXE. FORMAT +has been designed to run under MS-DOS as a simple binary +.COM file. This conversion is performed by LOCATE (EXE2BIN) +with the command + + LOCATE FORMAT.EXE FORMAT.COM + +which will produce the file FORMAT.COM. + +;***************************************** +; +; A Sample OEM module +; +;***************************************** + +CODE SEGMENT BYTE PUBLIC 'CODE' +; This segment must be +; named CODE, it must be +; PUBLIC, and it's +; classname must be 'CODE' + + + ASSUME CS:CODE,DS:CODE,ES:CODE + +; Must declare data and routines PUBLIC + +PUBLIC FATID,STARTSECTOR,SWITCHLIST,FREESPACE +PUBLIC INIT,DISKFORMAT,BADSECTOR,DONE,WRTFAT +PUBLIC FATSPACE,HARDFLAG + +; This data defined in Microsoft-supplied module + + EXTRN SWITCHMAP:WORD,DRIVE:BYTE + +INIT: + +; Read the boot sector into memory + CALL READBOOT + ... +; Set FATID to double sided if "D" switch specified + TEST SWITCHMAP,10H + JNZ SETDBLSIDE + ... + RET + +DISKFORMAT: + ... + +; Use the bit map in SWITCHMAP to determine +; what switches are set + + TEST SWITCHMAP,8 ;Is there a "/C"? + JNZ CLEAR ; Yes -- clear operation + ; requested jump around the + ; format code + < format the disk > +CLEAR: + ... +; Transfer the boot from memory to the new disk + CALL TRANSBOOT + ... + RET + +; Error return - set carry + +ERRET: + STC + RET + +BADSECTOR: + ... + RET + + +WRTFAT: + ... + +WRTFATLOOP: + < Set up call to write out a fat to disk> + ... + MOV BX,[FATSPACE] + + < Write out one fat to disk> + JC ERRET + ... + < Decrement fat counter > + JNZ WRTFATLOOP + CLC ;Good return + RET + + +DONE: + ... + RET + +; Default Single sided +FATID DB 0FEH + +HARDFLAG DB 0 + +STARTSECTOR DW 9 + +SWITCHLIST DB 5,"DCOVS" ; "OVS" must be the last + ; switches in the list + +FATSPACE DW FATBUF + +FREESPACE DW ENDBOOT + +BOOT DB BOOTSIZE DUP(?) ; Buffer for the + ; boot sector + +FATBUF DB 6 * 1024 DUP(?) ; Fat buffer +ENDBOOT LABEL BYTE + +CODE ENDS + END + \ No newline at end of file diff --git a/v2.0/source/FORMES.ASM b/v2.0/source/FORMES.ASM new file mode 100644 index 0000000..eedae27 Binary files /dev/null and b/v2.0/source/FORMES.ASM differ diff --git a/v2.0/source/GENFOR.ASM b/v2.0/source/GENFOR.ASM new file mode 100644 index 0000000..a108593 Binary files /dev/null and b/v2.0/source/GENFOR.ASM differ diff --git a/v2.0/source/GETSET.ASM b/v2.0/source/GETSET.ASM new file mode 100644 index 0000000..289f4c8 --- /dev/null +++ b/v2.0/source/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/v2.0/source/HRDDRV.ASM b/v2.0/source/HRDDRV.ASM new file mode 100644 index 0000000..672b99d --- /dev/null +++ b/v2.0/source/HRDDRV.ASM @@ -0,0 +1,501 @@ + TITLE HRDDRV.SYS for the ALTOS ACS-86C. + +; Hard Disk Drive for Version 2.x of MSDOS. + +; Constants for commands in Altos ROM. + +ROM_CONSTA EQU 01 ;Return status AL of console selected in CX. +ROM_CONIN EQU 02 ;Get char. from console in CX to AL +ROM_CONOUT EQU 03 ;Write char. in DL to console in CX. +ROM_PMSG EQU 07 ;Write string ES:DX to console in CX. +ROM_DISKIO EQU 08 ;Perform disk I/O from IOPB in ES:CX. +ROM_INIT EQU 10 ;Returns boot console and top memory ES:DX. + + +CODE SEGMENT +ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE + + ORG 0 ;Starts at an offset of zero. + + PAGE + SUBTTL Device driver tables. + +;-----------------------------------------------+ +; DWORD pointer to next device | 1 word offset. +; (-1,-1 if last device) | 1 word segement. +;-----------------------------------------------+ +; Device attribute WORD ; 1 word. +; Bit 15 = 1 for chacter devices. ; +; 0 for Block devices. ; +; ; +; Charcter devices. (Bit 15=1) ; +; Bit 0 = 1 current sti device. ; +; Bit 1 = 1 current sto device. ; +; Bit 2 = 1 current NUL device. ; +; Bit 3 = 1 current Clock device. ; +; ; +; Bit 13 = 1 for non IBM machines. ; +; 0 for IBM machines only. ; +; Bit 14 = 1 IOCTL control bit. ; +;-----------------------------------------------+ +; Device strategy pointer. ; 1 word offset. +;-----------------------------------------------+ +; Device interrupt pointer. ; 1 word offset. +;-----------------------------------------------+ +; Device name field. ; 8 bytes. +; Character devices are any valid name ; +; left justified, in a space filled ; +; field. ; +; Block devices contain # of units in ; +; the first byte. ; +;-----------------------------------------------+ + +DSKDEV: ;Header for hard disk driver. + DW -1,-1 ;Last device + DW 2000H ;Is a block device + DW STRATEGY + DW DSK_INT +MEMMAX DB 1 ;Number of Units + + PAGE + SUBTTL Dispatch tables for each device. + +DSK_TBL:DW DSK_INI ;0 - Initialize Driver. + DW MEDIAC ;1 - Return current media code. + DW GET_BPB ;2 - Get Bios Parameter Block. + DW CMDERR ;3 - Reserved. (currently returns error) + DW DSK_RED ;4 - Block read. + DW BUS_EXIT ;5 - (Not used, return busy flag) + DW EXIT ;6 - Return status. (Not used) + DW EXIT ;7 - Flush input buffer. (Not used.) + DW DSK_WRT ;8 - Block write. + DW DSK_WRV ;9 - Block write with verify. + DW EXIT ;10 - Return output status. + DW EXIT ;11 - Flush output buffer. (Not used.) + DW EXIT ;12 - IO Control. + + PAGE + SUBTTL Strategy and Software Interrupt routines. + +;Define offsets for io data packet + +IODAT STRUC +CMDLEN DB ? ;LENGTH OF THIS COMMAND +UNIT DB ? ;SUB UNIT SPECIFIER +CMD DB ? ;COMMAND CODE +STATUS DW ? ;STATUS + DB 8 DUP (?) +MEDIA DB ? ;MEDIA DESCRIPTOR +TRANS DD ? ;TRANSFER ADDRESS +COUNT DW ? ;COUNT OF BLOCKS OR CHARACTERS +START DW ? ;FIRST BLOCK TO TRANSFER +IODAT ENDS + +PTRSAV DD 0 ;Strategy pointer save. + +; +; Simplistic Strategy routine for non-multi-Tasking system. +; +; Currently just saves I/O packet pointers in PTRSAV for +; later processing by the individual interrupt routines. +; + +STRATP PROC FAR + +STRATEGY: + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + RET + +STRATP ENDP + + +; +; Ram memory driver interrupt routine for processing I/O packets. +; + +DSK_INT: + PUSH SI ;Save SI from caller. + MOV SI,OFFSET DSK_TBL + +; +; Common program for handling the simplistic I/O packet +; processing scheme in MSDOS 2.0 +; + +ENTRY: PUSH AX ;Save all nessacary registers. + PUSH CX + PUSH DX + PUSH DI + PUSH BP + PUSH DS + PUSH ES + PUSH BX + + LDS BX,CS:[PTRSAV] ;Retrieve pointer to I/O Packet. + + MOV AL,[BX.UNIT] ;AL = Unit code. + MOV AH,[BX.MEDIA] ;AH = Media descriptor. + MOV CX,[BX.COUNT] ;CX = Contains byte/sector count. + MOV DX,[BX.START] ;DX = Starting Logical sector. + XCHG DI,AX ;Save Unit and Media Temporarily. + MOV AL,[BX.CMD] ;Retrieve Command type. (1 => 11) + XOR AH,AH ;Clear upper half of AX for calculation. + ADD SI,AX ;Compute entry pointer in dispatch table. + ADD SI,AX + CMP AL,11 ;Verify that not more than 11 commands. + JA CMDERR ;Ah, well, error out. + XCHG AX,DI + LES DI,[BX.TRANS] ;DI contains addess of Transfer address. + ;ES contains segment. + PUSH CS + POP DS ;Data segment same as Code segment. + JMP [SI] ;Perform I/O packet command. + + PAGE + SUBTTL Common error and exit points. + +BUS_EXIT: ;Device busy exit. + MOV AH,00000011B ;Set busy and done bits. + JMP SHORT EXIT1 + +CMDERR: MOV AL,3 ;Set unknown command error #. + +; +; Common error processing routine. +; AL contains actual error code. +; +; Error # 0 = Write Protect violation. +; 1 = Unkown unit. +; 2 = Drive not ready. +; 3 = Unknown command in I/O packet. +; 4 = CRC error. +; 5 = Bad drive request structure length. +; 6 = Seek error. +; 7 = Unknown media discovered. +; 8 = Sector not found. +; 9 = Printer out of paper. +; 10 = Write fault. +; 11 = Read fault. +; 12 = General failure. +; + +ERR_EXIT: + MOV AH,10000001B ;Set error and done bits. + STC ;Set carry bit also. + JMP SHORT EXIT1 ;Quick way out. + +EXITP PROC FAR ;Normal exit for device drivers. + +EXIT: MOV AH,00000001B ;Set done bit for MSDOS. +EXIT1: LDS BX,CS:[PTRSAV] + MOV [BX.STATUS],AX ;Save operation compete and status. + + POP BX ;Restore registers. + POP ES + POP DS + POP BP + POP DI + POP DX + POP CX + POP AX + POP SI + RET ;RESTORE REGS AND RETURN +EXITP ENDP + + PAGE + + subttl Hard Disk drive control. + +; +; Read command = 09 hex. +; Write command = 02 hex. +; Seek command = 10 hex. +; Recal command = 20 hex. +; Rezero command = 40 hex. +; Reset command = 80 hex. +; +; Busy = 01 hex. +; Operation Complete = 02 hex. +; Bad Sector = 04 hex. +; Record Not found = 08 hex. +; CRC error = 10 hex. +; (not used) = 20 hex. +; Write fault = 40 hex. +; Drive Ready = 80 hex. +; + +hd_read equ 09h +hd_writ equ 02h +hd_wmsk equ 5dh +hd_rmsk equ 9ch + page + + SUBTTL Altos monitor ram and 8089 IOPB structures. + +; +; Structure to reference 8089 and ROM command table. +; + +SIOPB STRUC + DB 4 DUP (?) ;Monitor Use Only +OPCODE DB ? ;I/O operation code. +DRIVE DB ? ;Logical drive spec. +TRACK DW ? ;Logical track number. +HEAD DB ? ;Logical head number. +SECTOR DB ? ;Logical sector to start with. +SCOUNT DB ? ;Number of logical sectors in buffer. +RETCODE DB ? ;Error code after masking. +RETMASK DB ? ;Error mask. +RETRIES DB ? ;Number of retries before error exit. +DMAOFF DW ? ;Buffer offset address. +DMASEG DW ? ;Buffer segment. +SECLENG DW ? ;Sector Length. + DB 6 DUP (?) ;8089 use only. +SIOPB ENDS + +IOPB SIOPB <,0,0,0,0,0,0,0,0,0,0,0,0,> + + PAGE + SUBTTL Common Drive parameter block definitions on Altos. + +DBP STRUC + +JMPNEAR DB 3 DUP (?) ;Jmp Near xxxx for boot. +NAMEVER DB 8 DUP (?) ;Name / Version of OS. + +;------- Start of Drive Parameter Block. + +SECSIZE DW ? ;Sector size in bytes. (dpb) +ALLOC DB ? ;Number of sectors per alloc. block. (dpb) +RESSEC DW ? ;Reserved sectors. (dpb) +FATS DB ? ;Number of FAT's. (dpb) +MAXDIR DW ? ;Number of root directory entries. (dpb) +SECTORS DW ? ;Number of sectors per diskette. (dpb) +MEDIAID DB ? ;Media byte ID. (dpb) +FATSEC DW ? ;Number of FAT Sectors. (dpb) + +;------- End of Drive Parameter Block. + +SECTRK DW ? ;Number of Sectors per track. +HEADS DW ? ;Number of heads per cylinder. +HIDDEN DW ? ;Number of hidden sectors. + +DBP ENDS + +HDDRIVE DBP <,,512,4,0,2,256,4000,0F5H,3,12,4,0> + + +INI_TAB DW OFFSET HDDRIVE.SECSIZE + + PAGE + SUBTTL Media check routine + +; +; Media check routine. +; On entry: +; AL = memory driver unit number. +; AH = media byte +; On exit: +; +; [MEDIA FLAG] = -1 (FF hex) if disk is changed. +; [MEDIA FLAG] = 0 if don't know. +; [MEDIA FLAG] = 1 if not changed. +; + +MEDIAC: LDS BX,CS:[PTRSAV] + MOV BYTE PTR [BX.TRANS],1 + JMP EXIT + + PAGE + SUBTTL Build and return Bios Parameter Block for a diskette. + +; +; Build Bios Parameter Blocks. +; +; On entry: ES:BX contains the address of a scratch sector buffer. +; AL = Unit number. +; AH = Current media byte. +; +; On exit: Return a DWORD pointer to the associated BPB +; in the Request packet. +; + +GET_BPB: + MOV SI,OFFSET HDDRIVE+11 + LDS BX,CS:[PTRSAV] + MOV WORD PTR [BX.COUNT],SI + MOV WORD PTR [BX.COUNT+2],CS + JMP EXIT + + PAGE + SUBTTL MSDOS 2.x Disk I/O drivers. + +; +; Disk READ/WRITE functions. +; +; On entry: +; AL = Disk I/O driver number +; AH = Media byte. +; ES = Disk transfer segment. +; DI = Disk transfer offset in ES. +; CX = Number of sectors to transfer +; DX = Logical starting sector. +; +; On exit: +; Normal exit through common exit routine. +; +; Abnormal exit through common error routine. +; + +DSK_RED: + MOV AH,HD_READ + JMP SHORT DSK_COM +DSK_WRV: +DSK_WRT: + MOV AH,HD_WRIT +DSK_COM: + MOV SI,OFFSET HDDRIVE ;Keeps code size down. + MOV [IOPB.DMASEG],ES + MOV [IOPB.DMAOFF],DI + MOV DI,[SI.SECSIZE] + MOV [IOPB.SECLENG],DI + MOV [IOPB.RETRIES],1 + MOV [IOPB.RETMASK],05DH ;Error return mask. + MOV [IOPB.OPCODE],AH + MOV [IOPB.DRIVE],4 ;Drive 4 is only available. + ADD DX,[SI.HIDDEN] ;Account for invisible sectors. + MOV BP,CX ;Save number of sectors to R/W +DSK_IO1: + PUSH DX ;Save starting sector. + MOV AX,DX + MOV DX,0 ;32 bit divide coming up. + MOV CX,[SI.SECTRK] + DIV CX ;Get track+head and start sector. + MOV [IOPB.SECTOR],DL ;Starting sector. + MOV BL,DL ;Save starting sector for later. + MOV DX,0 + MOV CX,[SI.HEADS] + DIV CX ;Compute head we are on. + MOV [IOPB.HEAD],DL + MOV [IOPB.TRACK],AX ;Track to read/write. + MOV AX,[SI.SECTRK] ;Now see how many sectors + INC AL ; we can burst read. + SUB AL,BL ;BL is the starting sector. + MOV AH,0 + POP DX ;Retrieve logical sector start. + CMP AX,BP ;See if on last partial track+head. + JG DSK_IO2 ;Yes, on last track+head. + SUB BP,AX ;No, update number of sectors left. + ADD DX,AX ;Update next starting sector. + JMP SHORT DSK_IO3 +DSK_IO2:MOV AX,BP ;Only read enough of sector + MOV BP,0 ;to finish buffer and clear # left. +DSK_IO3:MOV [IOPB.SCOUNT],AL + MOV DI,AX ;Save number sectors for later. + MOV BX,ROM_DISKIO + MOV CX,OFFSET IOPB + PUSH CS + POP ES + CALL ROM_CALL ;Do disk operation. + MOV AL,[IOPB.RETCODE] ;Get error code. + OR AL,AL + JNZ DERROR + MOV AX,DI ;Retrieve number of sectors read. + MOV CX,[SI.SECSIZE] ;Number of bytes per sector. + PUSH DX + MUL CX + POP DX + TEST AL,0FH ;Make sure no strange sizes. + JNZ SERR1 + MOV CL,4 + SHR AX,CL ;Convert number of bytes to para. + ADD AX,[IOPB.DMASEG] + MOV [IOPB.DMASEG],AX + OR BP,BP + JNZ DSK_IO1 ;Still more to do. + MOV AL,0 + JMP EXIT ;All done. +SERR1: MOV AL,12 + JMP ERR_EXIT + + PAGE + SUBTTL Disk Error processing. + +; +; Disk error routine. +; + +DERROR: + LDS BX,CS:[PTRSAV] + MOV [BX.COUNT],0 + PUSH CS + POP DS + + MOV BL,-1 + MOV AH,AL + MOV BH,14 ;Lenght of table. + MOV SI,OFFSET DERRTAB +DERROR2:INC BL ;Increment to next error code. + LODS BYTE PTR CS:[SI] + CMP AH,AL ;See if error code matches disk status. + JZ DERROR3 ;Got the right error, exit. + DEC BH + JNZ DERROR2 ;Keep checking table. + MOV BL,12 ;Set general type of error. +DERROR3:MOV AL,BL ;Now we've got the code. + JMP ERR_EXIT + +DERRTAB DB 00H ; 0. Write protect error + DB 00H ; 1. Unknown unit. + DB 00H ; 2. Not ready error. + DB 00H ; 3. Unknown command. + DB 10H ; 4. CRC error + DB 00H ; 5. Bad drive request. + DB 00H ; 6. Seek error + DB 00H ; 7. Unknown media. + DB 08H ; 8. Sector not found + DB 00H ; 9. (Not used.) + DB 40H ;10. Write fault. + DB 04H ;11. Read fault. + DB 01H ;12. General type of failure. + + PAGE + SUBTTL Common ROM call routine. + +; +; Save all registers except CX, BX and AX. + +ROMRTN DD 0FE000000H ;Main ROM entry point. + +ROM_CALL: + PUSH DI + PUSH SI + PUSH BP + PUSH DX + PUSH ES + CALL CS:DWORD PTR [ROMRTN] + POP ES + POP DX + POP BP + POP SI + POP DI + RET + + + PAGE + SUBTTL Hard Disk Drive initalization routine. + +DSK_INI: + LDS BX,CS:[PTRSAV] + MOV BYTE PTR [BX.MEDIA],1 + MOV WORD PTR [BX.TRANS],OFFSET DSK_INI + MOV WORD PTR [BX.TRANS+2],CS + MOV WORD PTR [BX.COUNT],OFFSET INI_TAB + MOV WORD PTR [BX.COUNT+2],CS + JMP EXIT + +CODE ENDS + + END +  \ No newline at end of file diff --git a/v2.0/source/IFEQU.ASM b/v2.0/source/IFEQU.ASM new file mode 100644 index 0000000..ff5f581 --- /dev/null +++ b/v2.0/source/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/v2.0/source/INCOMP.txt b/v2.0/source/INCOMP.txt new file mode 100644 index 0000000..6c187b6 Binary files /dev/null and b/v2.0/source/INCOMP.txt differ diff --git a/v2.0/source/INIT.ASM b/v2.0/source/INIT.ASM new file mode 100644 index 0000000..0ea86f5 --- /dev/null +++ b/v2.0/source/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/v2.0/source/INT24.txt b/v2.0/source/INT24.txt new file mode 100644 index 0000000..d38d6fa Binary files /dev/null and b/v2.0/source/INT24.txt differ diff --git a/v2.0/source/MISC.ASM b/v2.0/source/MISC.ASM new file mode 100644 index 0000000..e0a5cee --- /dev/null +++ b/v2.0/source/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/v2.0/source/MORE.ASM b/v2.0/source/MORE.ASM new file mode 100644 index 0000000..6c9bf95 Binary files /dev/null and b/v2.0/source/MORE.ASM differ diff --git a/v2.0/source/MOREMES.ASM b/v2.0/source/MOREMES.ASM new file mode 100644 index 0000000..57c28d1 --- /dev/null +++ b/v2.0/source/MOREMES.ASM @@ -0,0 +1,17 @@ +TITLE MORE Messages + +CODE SEGMENT PUBLIC + PUBLIC MORETXT,BADVER,CRLFTXT,BUFFER + +MORETXT DB 13,"-- More --$" +BADVER DB "MORE: Incorrect DOS version" +CRLFTXT DB 13,10,"$" +; +; THIS VARIABLE MUST BE DEFINED LAST! +; +BUFFER DB 4098 DUP (?) + +CODE ENDS + END + + \ No newline at end of file diff --git a/v2.0/source/MSCODE.ASM b/v2.0/source/MSCODE.ASM new file mode 100644 index 0000000..c4b58bc --- /dev/null +++ b/v2.0/source/MSCODE.ASM @@ -0,0 +1,615 @@ +; +; MSCODE.ASM -- MSDOS code +; + +INCLUDE DOSSEG.ASM +INCLUDE STDSW.ASM + +CODE SEGMENT BYTE PUBLIC 'CODE' +ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + +IFNDEF KANJI +KANJI EQU 0 ; FALSE +ENDIF + +IFNDEF IBM +IBM EQU 0 +ENDIF + +IFNDEF HIGHMEM +HIGHMEM EQU 0 +ENDIF + + + i_need USER_SP,WORD + i_need USER_SS,WORD + i_need SAVEDS,WORD + i_need SAVEBX,WORD + i_need INDOS,BYTE + i_need NSP,WORD + i_need NSS,WORD + i_need CURRENTPDB,WORD + i_need AUXSTACK,BYTE + i_need CONSWAP,BYTE + i_need IDLEINT,BYTE + i_need NOSETDIR,BYTE + i_need ERRORMODE,BYTE + i_need IOSTACK,BYTE + i_need WPERR,BYTE + i_need DSKSTACK,BYTE + i_need CNTCFLAG,BYTE + i_need LEAVEADDR,WORD + i_need NULLDEVPT,DWORD + + IF NOT IBM + i_need OEM_HANDLER,DWORD + ENDIF + + EXTRN DSKSTATCHK:NEAR,GETBP:NEAR,DSKREAD:NEAR,DSKWRITE:NEAR + + +BREAK + +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/v2.0/source/MSDATA.ASM b/v2.0/source/MSDATA.ASM new file mode 100644 index 0000000..ed524e8 --- /dev/null +++ b/v2.0/source/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/v2.0/source/MSDOS.ASM b/v2.0/source/MSDOS.ASM new file mode 100644 index 0000000..1d43531 --- /dev/null +++ b/v2.0/source/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/v2.0/source/MSHEAD.ASM b/v2.0/source/MSHEAD.ASM new file mode 100644 index 0000000..108197d --- /dev/null +++ b/v2.0/source/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/v2.0/source/MSINIT.ASM b/v2.0/source/MSINIT.ASM new file mode 100644 index 0000000..36edf9f --- /dev/null +++ b/v2.0/source/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/v2.0/source/PCLOCK.ASM b/v2.0/source/PCLOCK.ASM new file mode 100644 index 0000000..6018bfd Binary files /dev/null and b/v2.0/source/PCLOCK.ASM differ diff --git a/v2.0/source/PRINT.ASM b/v2.0/source/PRINT.ASM new file mode 100644 index 0000000..dd58735 --- /dev/null +++ b/v2.0/source/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 FALSE +IBMVER EQU IBM +MSVER EQU TRUE + + 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 DOST: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 0200H ;2.00 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/v2.0/source/PRINT_v211.ASM b/v2.0/source/PRINT_v211.ASM new file mode 100644 index 0000000..4585af7 --- /dev/null +++ b/v2.0/source/PRINT_v211.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/v2.0/source/PROC.ASM b/v2.0/source/PROC.ASM new file mode 100644 index 0000000..abc6f9c --- /dev/null +++ b/v2.0/source/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/v2.0/source/PROFIL.ASM b/v2.0/source/PROFIL.ASM new file mode 100644 index 0000000..08a5ada --- /dev/null +++ b/v2.0/source/PROFIL.ASM @@ -0,0 +1,705 @@ + TITLE PROFIL - MS-DOS Profile program + +;Profiler for MS-DOS 1.25 2.00 +; +; Lots of stuff stolen from debug. +; User provides # of paragraphs per bucket, program is cut up accordingly. +; User also specifies clock interval + + +;System calls +PRINTBUF EQU 9 +SETDMA EQU 26 +CREATE EQU 22 +OPEN EQU 15 +CLOSE EQU 16 +GETBUF EQU 10 +BLKWRT EQU 40 +BLKRD EQU 39 +OUTCH EQU 2 +SETBASE EQU 38 + +FCB EQU 5CH +BUFLEN EQU 80 + +; FCB offsets +RR EQU 33 +RECLEN EQU 14 +FILELEN EQU 16 + + +;Segments in load order + +CODE SEGMENT PUBLIC +CODE ENDS + +DATA SEGMENT BYTE +DATA ENDS + +INIT SEGMENT BYTE +INIT ENDS + +DG GROUP CODE,DATA,INIT + +;The data segment + +DATA SEGMENT BYTE + ORG 0 +ENDMES DB 13,10,"Program terminated normally",13,10,"$" +ABORTMES DB 13,10,"Program aborted",13,10,"$" +TOOBIG DB "Program too big",13,10,"$" +EXEBAD DB "EXE file bad",13,10,"$" + +OUT_FCB LABEL WORD + DB 0 +OUTNAME DB " PRF" + DB 30 DUP(0) + + DB 80H DUP(?) +STACK LABEL WORD + +BYTEBUF DB BUFLEN DUP(?) ;Processed input queue +AXSAVE DW ? ;See interrupt routine +BXSAVE DW ? ; " " " +PROG_AREA DW ? ;Segment of program start + +;EXE file header +RUNVAR LABEL WORD +RELPT DW ? +LASTP LABEL WORD +RELSEG DW ? +PSIZE LABEL WORD +PAGES DW ? +RELCNT DW ? +HEADSIZ DW ? + DW ? +LOADLOW DW ? +PROG_SS LABEL WORD ;Program stack seg +INITSS DW ? +PROG_SP LABEL WORD ;Program SP +INITSP DW ? + DW ? +PROG_ENTRY EQU THIS DWORD +PROG_RA LABEL WORD ;Program start offset +INITIP DW ? +PROG_SA LABEL WORD ;Program start segment (may be different from PROG_AREA) +INITCS DW ? +RELTAB DW ? +RUNVARSIZ EQU $-RUNVAR + +EXEFILE DB 0 ;Flag to indicate EXE file +DRV_VALID DW ? ;Init for AX register +OUTPUT_DATA LABEL WORD ;Start of the profile data +CLOCK_GRAIN DW ? ;Clock interval micro-seconds +BUCKET_NUM DW ? ;Number of buckets +BUCKET_SIZE DW ? ;Paragraphs per bucket +PROG_LOW_PA DW ? ;Start of program (PARA #) +PROG_HIGH_PA DW ? ;End of program (PARA #) +DOS_PA DW ? ;IO-DOS PARA boundry +HIT_IO DW 0 ;IO bucket +HIT_DOS DW 0 ;DOS bucket +HIT_HIGH DW 0 ;Above Program bucket +NUM_DATA_WORDS EQU ($-OUTPUT_DATA)/2 ;Number of word items +BUCKET LABEL WORD ;Bucket count area + +;The following data will be overwritten when the buckets are initialized +LINEBUF DB BUFLEN,1,0DH ;Raw input buffer + DB BUFLEN DUP(?) + +NOFILE DB "File not found",13,10,"$" +OUTERR DB "Cannot open output file",13,10,"$" +GRAIN_PROMPT DB "Sample time (micro-sec) >= 60 ? ","$" +SIZE_PROMPT DB "Number of paragraphs (16 bytes) per bucket? ","$" +PARAM_PROMPT DB "Parameters to program? ","$" +DATA ENDS + +;The resident code portion +CODE SEGMENT PUBLIC +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + +;The clock interrupt routine + PUBLIC CLK_INTER + +;Stuff provided by external clock handler routine + EXTRN CLOCKON:NEAR,CLOCKOFF:NEAR,LEAVE_INT:NEAR + + ORG 100H +START: + CLD + MOV SP,OFFSET DG:STACK ;Use internal stack + CALL SETUP +;The following setup stuff cannot be done in SETUP because we're probably +; overwritting the INIT area + MOV DX,[PROG_AREA] + MOV AH,SETBASE + INT 21H ;Set base for program + MOV ES,[PROG_AREA] + PUSH SI ;Points to BYTEBUF + MOV DI,81H ;Set unformatted params +COMTAIL: + LODSB + STOSB + CMP AL,13 + JNZ COMTAIL + SUB DI,82H ;Figure length + XCHG AX,DI + MOV BYTE PTR ES:[80H],AL + POP SI + MOV DI,FCB ;First param + MOV AX,2901H + INT 21H + MOV BYTE PTR [DRV_VALID],AL + MOV AX,2901H + MOV DI,6CH ;Second param + INT 21H + MOV BYTE PTR [DRV_VALID+1],AL + + MOV AX,ES ;Prog segment to AX + MOV DX,[PROG_RA] ;Offset + CMP [EXEFILE],1 + JZ EXELOAD ;EXE file + JMP BINFIL ;Regular file (.COM) + +EXELOAD: + MOV AX,[HEADSIZ] ;Size of header in paragraphs + ADD AX,31 + MOV CL,4 + ROL AX,CL ;Size in bytes + MOV BX,AX + AND AX,0FE00H + AND BX,0FH + MOV WORD PTR DS:[FCB+RR],AX ;Position in file of program + MOV WORD PTR DS:[FCB+RR+2],BX ;Record size + MOV DX,[PAGES] ;Size in 512 byte blocks + DEC DX + XCHG DH,DL + ROL DX,1 + MOV DI,DX + MOV SI,DX + AND DI,0FE00H + AND SI,1FFH + SUB DI,AX + SBB SI,BX + MOV AX,[LASTP] + OR AX,AX + JNZ PARTP + MOV AX,200H +PARTP: + ADD DI,AX + ADC SI,0 + MOV AX,DI + ADD AX,15 + AND AL,0F0H + OR AX,SI + MOV CL,4 + ROR AX,CL + XCHG AX,CX + MOV BX,[PROG_AREA] + ADD BX,10H + MOV AX,WORD PTR DS:[2] + SUB AX,CX + MOV DX,OFFSET DG:TOOBIG + JB ERROR + CMP BX,AX + JA ERROR + CMP [LOADLOW],-1 + JNZ LOADEXE + XCHG AX,BX +LOADEXE: + MOV BP,AX + XOR DX,DX + CALL READ + JC HAVEXE +BADEXE: + MOV DX,OFFSET DG:EXEBAD + +ERROR: + MOV AH,PRINTBUF ;Print the message in DX + INT 21H + INT 20H ;Exit + +HAVEXE: + MOV AX,[RELTAB] ;Get position of relocation table + MOV WORD PTR DS:[FCB+RR],AX + MOV WORD PTR DS:[FCB+RR+2],0 + MOV DX,OFFSET DG:RELPT ;Four byte buffer + MOV AH,SETDMA + INT 21H + CMP [RELCNT],0 + JZ NOREL +RELOC: + MOV AH,BLKRD + MOV DX,FCB + MOV CX,4 + INT 21H ;Read in one relocation pointer + OR AL,AL + JNZ BADEXE + MOV DI,[RELPT] ;Pointer offset + MOV AX,[RELSEG] ;pointer segment + ADD AX,BP ;Bias with actual load segment + MOV ES,AX + ADD ES:[DI],BP ;Relocate + DEC [RELCNT] + JNZ RELOC + +NOREL: + ADD [INITSS],BP + ADD [INITCS],BP + JMP SHORT PROGGO + +BINFIL: + MOV WORD PTR DS:[FCB+RECLEN],1 + MOV SI,-1 + MOV DI,SI + CALL READ + MOV ES,[PROG_SA] ;Prog segment to ES + MOV AX,WORD PTR ES:[6] + MOV [PROG_SP],AX ;Default SP for non EXE files + DEC AH + MOV WORD PTR ES:[6],AX ;Fix size + +PROGGO: + PUSH DS + MOV AX,[PROG_AREA] + MOV DS,AX + MOV DX,80H + MOV AH,SETDMA + INT 21H ;Set default disk transfer address + POP DS + MOV BX,[BUCKET_NUM] + SHL BX,1 ;Mult by 2 to get #bytes in bucket area +CLEAR: + MOV BUCKET[BX],0 ;Zero counts + SUB BX,2 + JGE CLEAR + MOV DX,[CLOCK_GRAIN] + PUSH DS + POP ES + CLI ;Don't collect data yet + CALL CLOCKON ;Set the interrupt + MOV SI,[PROG_RA] + MOV DI,[PROG_AREA] + MOV BX,[PROG_SS] + MOV CX,[PROG_SP] + MOV AX,[DRV_VALID] + MOV DX,[PROG_SA] + MOV SS,BX + MOV SP,CX + XOR CX,CX + PUSH CX ;0 on prog stack + PUSH DX + PUSH SI + MOV DS,DI ;Set up segments + MOV ES,DI + STI ;Start collecting data +XXX PROC FAR + RET ;Hop to program +XXX ENDP + +READ: +; AX:DX is disk transfer address (segment:offset) +; SI:DI is 32 bit length + +RDLOOP: + MOV BX,DX + AND DX,000FH + MOV CL,4 + SHR BX,CL + ADD AX,BX + PUSH AX + PUSH DX + PUSH DS + MOV DS,AX + MOV AH,SETDMA + INT 21H + POP DS + MOV DX,FCB + MOV CX,0FFF0H ;Keep request in segment + OR SI,SI ;Need > 64K? + JNZ BIGRD + MOV CX,DI ;Limit to amount requested +BIGRD: + MOV AH,BLKRD + INT 21H + SUB DI,CX ;Subtract off amount done + SBB SI,0 ;Ripple carry + CMP AL,1 ;EOF? + POP DX + POP AX ;Restore transfer address + JZ RET10 + ADD DX,CX ;Bump transfer address by last read + MOV BX,SI + OR BX,DI ;Finished with request + JNZ RDLOOP +RET10: STC + RET + + +;Return here on termination or abort + +TERMINATE: + CLI ;Stop collecting data + MOV DX,OFFSET DG:ENDMES + JMP SHORT WRITEOUT +ABORT: + CLI ;Stop collecting data + MOV DX,OFFSET DG:ABORTMES +WRITEOUT: + MOV AX,CS + MOV DS,AX + MOV SS,AX + MOV SP,OFFSET DG:STACK ;Use internal stack + PUSH DX + CALL CLOCKOFF ;Restore original clock routine + STI ;Back to normal clock + POP DX + MOV AH,PRINTBUF + INT 21H ;Apropriate termination message + MOV [OUT_FCB+14],2 ;Word size records + MOV DX,OFFSET DG:OUTPUT_DATA + MOV AH,SETDMA + INT 21H ;Set the transfer address + MOV CX,NUM_DATA_WORDS + ADD CX,[BUCKET_NUM] + MOV DX,OFFSET DG:OUT_FCB + MOV AH,BLKWRT + INT 21H ;Write out data + MOV DX,OFFSET DG:OUT_FCB + MOV AH,CLOSE + INT 21H + INT 20H ;Exit + + +;The clock interrupt routine +CLK_INTER PROC NEAR + CLI + PUSH DS + PUSH CS + POP DS ;Get profile segment + MOV [AXSAVE],AX + MOV [BXSAVE],BX + POP AX ;old DS + MOV BX,OFFSET DG:LEAVE_INT + PUSH BX + PUSH AX + PUSH ES + PUSH [AXSAVE] + PUSH [BXSAVE] + PUSH CX + PUSH DX + + +;Stack looks like this +; +; +18 OLDFLAGS +; +16 OLDCS +; +14 OLDIP +; +12 RETURN TO LEAVE_INT +; +10 OLDDS +; +8 OLDES +; +6 OLDAX +; +4 OLDBX +; +2 OLDCX +;SP-> OLDDX + + MOV BX,SP + LES BX,DWORD PTR SS:[BX+14] ;Get CS:IP + MOV AX,BX + MOV CL,4 + SHR AX,CL + MOV CX,ES + ADD AX,CX ;Paragraph of CS:IP + CMP AX,[DOS_PA] ;Below DOS? + JB IOHIT + CMP AX,[PROG_LOW_PA] ;Below program? + JB DOSHIT + CMP AX,[PROG_HIGH_PA] ;Above program? + JAE MISSH + + SUB AX,[PROG_LOW_PA] ;Paragraph offset + XOR DX,DX + + DIV [BUCKET_SIZE] + MOV BX,AX + SHL BX,1 ;Mult by 2 to get byte offset + INC BUCKET[BX] + JMP SHORT DONE + +IOHIT: + INC [HIT_IO] + JMP SHORT DONE + +DOSHIT: + INC [HIT_DOS] + JMP SHORT DONE + +MISSH: + INC [HIT_HIGH] + +DONE: + POP DX + POP CX + POP BX + POP AX + POP ES + POP DS + STI + RET ;To LEAVE_INT + +CLK_INTER ENDP + +CODE ENDS + +;The init segment contains code to process input parameters +; It will be blasted as soon as the program to be run is read in +; And/or the bucket area is initialized + +INIT SEGMENT BYTE + ORG 0 + +SETUP: + MOV DX,FCB + MOV AH,OPEN + INT 21H ;Open program file + AND AL,AL + JZ OPENOK + MOV DX,OFFSET DG:NOFILE + JMP ERROR + +OPENOK: + XOR BX,BX + MOV WORD PTR DS:[FCB+RR],BX + MOV WORD PTR DS:[FCB+RR+2],BX ;RR to 0 + MOV SI,FCB + MOV DI,OFFSET DG:OUT_FCB + MOV CX,4 + REP MOVSW + MOVSB ;Transfer drive spec and file to output + MOV DX,OFFSET DG:OUT_FCB + MOV AH,CREATE + INT 21H ;Try to create the output file + AND AL,AL + JZ GETSIZE + MOV DX,OFFSET DG:OUTERR + JMP ERROR + +GETSIZE: ;Get bucket size + MOV DX,OFFSET DG:SIZE_PROMPT + MOV AH,PRINTBUF + INT 21H + CALL INBUF + CALL SCANB + JZ GETSIZE ;SCANB went to CR + XOR BX,BX + INC BX ;Size >=1 + CALL GETNUM + JC GETSIZE ;Bad number + MOV [BUCKET_SIZE],DX + + CMP WORD PTR DS:[FCB+9],5800H+"E" ;"EX" + JNZ NOTEXE + CMP BYTE PTR DS:[FCB+11],"E" + JNZ NOTEXE + +LOADEXEHEAD: ;Load the EXE header + MOV [EXEFILE],1 + MOV DX,OFFSET DG:RUNVAR ;Read header in here + MOV AH,SETDMA + INT 21H + MOV CX,RUNVARSIZ + MOV DX,FCB + MOV WORD PTR DS:[FCB+RECLEN],1 + OR AL,AL + MOV AH,BLKRD + INT 21H + CMP [RELPT],5A4DH ;Magic number + JZ EXEOK + JMP BADEXE +EXEOK: + MOV AX,[PAGES] ;Size of file in 512 byte blocks + MOV CL,5 + SHL AX,CL ;Size in paragraphs + JMP SHORT SETBUCKET + +NOTEXE: + MOV AX,WORD PTR DS:[FCB+FILELEN] + MOV DX,WORD PTR DS:[FCB+FILELEN+2] ;Size of file in bytes DX:AX + ADD AX,15 + ADC DX,0 ;Round to PARA + MOV CL,4 + SHR AX,CL + AND AX,0FFFH + MOV CL,12 + SHL DX,CL + AND DX,0F000H + OR AX,DX ;Size in paragraphs to AX + MOV [PROG_RA],100H ;Default offset + +SETBUCKET: + PUSH AX ;Save size + XOR DX,DX + DIV [BUCKET_SIZE] + INC AX ;Round up + MOV [BUCKET_NUM],AX + MOV BX,OFFSET DG:BUCKET + SHL AX,1 ;Number of bytes in bucket area + ADD AX,BX ;Size of profil in bytes + ADD AX,15 ;Round up to PARA boundry + MOV CL,4 + SHR AX,CL ;Number of paragraphs in profil + INC AX ;Insurance + MOV BX,CS + ADD AX,BX + MOV [PROG_AREA],AX + + CMP [EXEFILE],1 + JZ SETBOUNDS + MOV AX,[PROG_AREA] ;Set up .COM segments + MOV [PROG_SS],AX + MOV [PROG_SA],AX + +SETBOUNDS: ;Set the sample window + MOV BX,10H ;Get start offset + ADD BX,[PROG_AREA] ;PARA # of start + MOV [PROG_LOW_PA],BX + POP AX ;Recall size of PROG in paragraphs + ADD BX,AX + MOV [PROG_HIGH_PA],BX + +SETDOS: + XOR DX,DX + MOV ES,DX ;look in interrupt area + MOV DX,WORD PTR ES:[82H] ;From int #20 + MOV [DOS_PA],DX + PUSH DS + POP ES + +GETGRAIN: ;Get sample interval + MOV DX,OFFSET DG:GRAIN_PROMPT + MOV AH,PRINTBUF + INT 21H + CALL INBUF + CALL SCANB + JZ GETGRAIN ;SCANB went to CR + MOV BX,60 ;Grain >=60 + CALL GETNUM + JC GETGRAIN ;Bad number + MOV [CLOCK_GRAIN],DX + + MOV DX,OFFSET DG:PARAM_PROMPT + MOV AH,PRINTBUF + INT 21H + CALL INBUF ;Get program parameters + + MOV AX,2522H ;Set vector 22H + MOV DX,OFFSET DG:TERMINATE + INT 21H + MOV AL,23H ;Set vector 23H + MOV DX,OFFSET DG:ABORT + INT 21H + RET ;Back to resident code + +GETNUM: ;Get a number, DS:SI points to buffer, carry set if bad + XOR DX,DX + MOV CL,0 + LODSB +NUMLP: + SUB AL,"0" + JB NUMCHK + CMP AL,9 + JA NUMCHK + CMP DX,6553 + JAE BADNUM + MOV CL,1 + PUSH BX + MOV BX,DX + SHL DX,1 + SHL DX,1 + ADD DX,BX + SHL DX,1 + CBW + POP BX + ADD DX,AX + LODSB + JMP NUMLP +NUMCHK: + CMP CL,0 + JZ BADNUM + CMP BX,DX + JA BADNUM + CLC + RET +BADNUM: + STC + RET + +INBUF: ;Read in from console, SI points to start on exit + MOV AH,GETBUF + MOV DX,OFFSET DG:LINEBUF + INT 21H + MOV SI,2 + 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,'"' + JNZ 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 + +CRLF: + MOV AL,13 + CALL OUT + MOV AL,10 + +OUT: + PUSH AX + PUSH DX + AND AL,7FH + XCHG AX,DX + MOV AH,OUTCH + INT 21H + POP DX + POP AX + RET + +SCANB: ;Scan to first non-blank + PUSH AX +SCANNEXT: + LODSB + CMP AL," " + JZ SCANNEXT + CMP AL,9 + JZ SCANNEXT + DEC SI + POP AX +EOLCHK: + CMP BYTE PTR[SI],13 + RET + +INIT ENDS + END START + \ No newline at end of file diff --git a/v2.0/source/PROFILE.txt b/v2.0/source/PROFILE.txt new file mode 100644 index 0000000..2d50631 Binary files /dev/null and b/v2.0/source/PROFILE.txt differ diff --git a/v2.0/source/PROHST.HLP b/v2.0/source/PROHST.HLP new file mode 100644 index 0000000..13880e5 --- /dev/null +++ b/v2.0/source/PROHST.HLP @@ -0,0 +1,35 @@ +PROHST is a preliminary version of a utility to process the profile +file produced by the PROFIL utility of MSDOS. +Those of you familiar with MS-Pascal or MS-Fortran will have little +difficulty in understanding how the parameters work. There are three, +the .PRF filename, an optional histogram file (default extension .HST, +default name same as the .PRF file) and an optional link map. If the +link map was produced with the line number options PROHST will try +and relate buckets to line numbers. Otherwise, it will relate it to +module offsets. If you specify no map file (the default), addresses +relative to the start of the program will be used. The default extension +for the map file is .MAP. + +a:prohst f; + +this will produce a histogram for the file f.prf in f.hst and no map file +will be assumed. + +a:prohst f,,; + +this will produce a histogram for f.prf in f.hst and expects a f.map file. + +a:prohst f,g,k + +this produces a histogram for f.prf in g.hst and expects a map file k.map. + +Note that if you select the map option with line numbers, the program will +appear to be looping. Never fear, go and have lunch or some other time +consuming pastime, and you will be suprised how long it took to produce +such a small file. Also, some of the line number/bucket correspondances are +not what they might be. Future version shoudl fix this. If you make a better +version, be sure to let me have a copy. + +David Jones. + + \ No newline at end of file diff --git a/v2.0/source/QUICK.txt b/v2.0/source/QUICK.txt new file mode 100644 index 0000000..d443b8e Binary files /dev/null and b/v2.0/source/QUICK.txt differ diff --git a/v2.0/source/RDATA.ASM b/v2.0/source/RDATA.ASM new file mode 100644 index 0000000..7a9b368 Binary files /dev/null and b/v2.0/source/RDATA.ASM differ diff --git a/v2.0/source/README.txt b/v2.0/source/README.txt new file mode 100644 index 0000000..c5bbf25 --- /dev/null +++ b/v2.0/source/README.txt @@ -0,0 +1,177 @@ + MSDOS 2.0 RELEASE + + +The 2.0 Release of MSDOS includes five 5 1/4 double density single sided +diskettes or three 8 iinch CP/M 80 format diskettes. + +The software/documentation on the five inch diskettes is arranged +as follows: + +1. DOS distribution diskette. This diskette contains files which + should be distriibuted to all users. This allows the DOS distri- + bution diskette to meet the requirements of users of high level + language compilers as well as users running only applications. + Many compilers marketed independently through the retail channel + (including those of Microsoft) assume LINK comes with the DOS, as + in the case of IBM. How you choose to distrubute BASIC (contracted + for separately) is up to you. + +2. Assembly Language Development System diskette. This diskette + contains files of interest to assembly language programmers. + High level language programmers do not need these programs unless + they are writing assembly language subroutines. IBM chose to + unbundle this package from the DOS distribution diskette (except + for DEBUG), but you do not have to do so. + +3. PRINT and FORMAT diskette. This diskette contains .ASM source + files which are necessary to assemble the print spooler, which you + may wish to customize for greater performance. .OBJ files are also + included for the FORMAT utility. + +4. Skeltal BIOS and documentation diskette. This diskette contains + the skeltal BIOS source code and the SYSINIT and SYSIMES object + modules which must be linked with your BIOS module. The proper + sequence for linking is BIOS - SYSINIT - SYSIMES. + A profiler utiliity is also included on the diskette, but this + is not intended for end-users. This is distributed for use by + your development staff only and is not supported by Microsoft + If you do decide to distribute it, it is at your own risk! + + +5. Documentation. Features of 2.0 are documented on this disk. + +The user manual contains some significant errors. Most of these are +due to last minute changes to achieve a greater degree of compatibility +with IBM's implementation of MS-DOS (PC DOS). This includes the use +of "\" instead of "/" as the path separator, and "/" instead of "-" +as the switch character. For transporting of batch files across +machines, Microsoft encourages the use of "\" and "/" respectively +in the U.S. market. (See DOSPATCH.TXT for how you can overide this. +The user guide explains how the end-user can override this in CONFIG.SYS). +Both the printer echo keys and insert mode keys have now been made to +toggle. The default prompt (this may also be changed by the user +with the PROMPT command) has been changed from "A:" to "A>". +We apologize for any inconveniences these changes may have caused +your technical publications staff. + + +Here is what you need to do to MSDOS 2.0 to create a shipable product: +(see "Making a Bootable Diskette" below) + +1. BIOS. If you have developed a BIOS for the Beta Test 2.0 version + You should link your BIOS module to SYSINIT.OBJ and SYSIMES.OBJ. + You must modify your BIOS to accomodate the call back to the BIOS + at the end of SYSINIT. If you have no need for this call, simply + find a far RET and label it RE_INIT and declare it public. + An example of this can be found in the skeletal BIOS. In addition + please add support for the new fast console output routine as + described in the device drivers document. We strongly recommend + that you adapt the standard boot sector format also described in + device drivers. Once again, please refer to the skeletal BIOS. + If you have not yet implemented version 2.0 please read the device + drivers document. Microsoft strongly recommends that machines + incorporating integrated display devices with memory mapped video + RAM implement some sort of terminal emulations through the use of + escape sequences. The skeletal BIOS includes a sample ANSI + terminal driver. + +2. Please refer to DOSPATCH.TXT for possible changes you might wish + to make. We strongly recommend that you not patch the switch + characters for the U.S. market. Your one byte serial number + will be issued upon signing the license agreement. Please patch + the DOS accordingly. If you wish to serialize the DOS, this is + described in DOSPATCH.TXT. Please patch the editing template + definitions. Please note the addition of the Control-Z entry + at the beginning of the table. Also note that the insert switches + have now both been made to toggle. + +3. Utilities. FORMAT must be configured for each specific system. + GENFOR is a generic example of a system independent format module, + but it is not recommended that this be distributed to your customers. + Link in the following order: FORMAT, FORMES, (your format module). + The print spooler is distributed as an executable file, which only + prints during wait for keyboard input. If you wish with your + implementation to steal some compute time when printing as well, + you will need to customize it and reassemble. Please note that + you can use a printer-ready or timer interrupt. The former is more + efficient, but ties the user to a specific device. Sample code + is conditionaled out for the IBM PC timer interrupt. + +The following problems are known to exist: + +1. Macro assembler does not support the initialization of 10-byte + floating point constants in 8087 emulation mode - the last two bytes + are zero filled. + +2. LIB has not been provided. The version which incorporates support + for 2.0 path names will be completed in a couple of weeks. The + 1.x version should work fine if you cannot wait. Because the library + manager acts as a counterpart to the linker, we recommend that it + be distributed with the DOS distribution diskette as opposed to the + assembly language development system. + +3. International (French, German, Japanese, and U.K.) versions will be + available in several months. + +4. COMMAND.ASM is currently too large to assemble on a micro. It is + being broken down into separate modules so it can be asembled on + a machine. Source licensees should realize that the resultant + binaries from the new version will not correspond exactly to the + old version. + +5. If you have any further questions regarding the MSDOS 2.0 distribution + please contact Don Immerwahr (OEM technical support (206) 828-8086). + + + Sincerely yours, + + + Chris Larson + MS-DOS Product Marketing Manager + (206) 828-8080 + + + + BUILDING A BOOTABLE (MSDOS FORMAT) DISKETTE + + +1. In implementing MSDOS on a new machine, it is highly recommended + that an MSDOS machine be available for the development. + Please note that utilities shipped with MSDOS 2.0 use MSDOS 2.0 + system calls and WILL NOT not run under MSDOS 1.25. + +2. Use your MSDOS development machine and EDLIN or a word processor + package to write BOOT.ASM, your bootstrap loader BIOS.ASM and + your Format module. + +3. Use MASM, the Microsoft Macro-86 Assembler, to assemble these + modules. LINK is then used to link together the .OBJ modules in + the order specified. + +4. Link creates .EXE format files which are not memory image files + and contain relocation information in their headers. Since your + BIOS and BOOT routines will not be loaded by the EXE loader in + MSDOS, they must first be turned into memory image files by + using the EXE2BIN utility. + +5. The easiest thing to do is to (using your development machine) + FORMAT a single sided diskette without the system. Use DEBUG + to load and write your BOOT.COM bootstrap loader to the BOOT + sector of that diskette. You may decide to have your bootstrap + load BIOS and let the BIOS load MSDOS or it may load both. Note that + the Bootstrap loader will have to know physically where to go on + the disk to get the BIOS and the DOS. COMMAND.COM is loaded + by the SYSINIT module. + +6. Use the COPY command to copy your IO.SYS file (what the + BIOS-SYSINIT-SYSIMES module is usually called) onto the disk + followed by MSDOS.SYS and COMMAND.COM. You may use DEBUG + to change the directory attribute bytes to make these files hidden. + +CAUTION: + +At all times, the BIOS writer should be careful to preserve the state +of the DOS - including the flags. You should be also be cautioned that +the MSDOS stack is not deep. You should not count on more than one or +two pushes of the registers. + \ No newline at end of file diff --git a/v2.0/source/RECMES.ASM b/v2.0/source/RECMES.ASM new file mode 100644 index 0000000..0723208 Binary files /dev/null and b/v2.0/source/RECMES.ASM differ diff --git a/v2.0/source/RECOVER.ASM b/v2.0/source/RECOVER.ASM new file mode 100644 index 0000000..05d27f9 --- /dev/null +++ b/v2.0/source/RECOVER.ASM @@ -0,0 +1,876 @@ +TITLE RECOVER MS-DOS File/Disk Recovery Utility +;---------------------------------------------------------- +; +; Recover - Program to rebuild an ms.dos directory +; +; Copyright 1982 by Microsoft Corporation +; Written by Chris Peters, April 1982 +; +;----------------------------------------------------------- +; +;REV 1.5 added header message ARR +; + +FALSE EQU 0 +TRUE EQU NOT FALSE + + +IBMVER EQU true +KANJI EQU FALSE + +bdos equ 21h +boot equ 20h +aread equ 25h +awrite equ 26h + + INCLUDE DOSSYM.ASM + +; +cr equ 0dh +lf equ 0ah +; +fcb equ 5ch + +code segment public +code ends + +const segment public byte +const ends + +data segment public byte +data ends + + +dg group code,const,data + +code segment public + assume cs:dg,ds:dg,es:dg,ss:dg + + PUBLIC PCRLF,PRINT,INT_23,convert + EXTRN dskwrt:NEAR,dskrd:NEAR,DSKERR:NEAR,report:NEAR + + org 100h + +recover:jmp rec_start + +HEADER DB "Vers 1.50" + +;-----------------------------------------------------------------------; +hardch dd ? + +the_root db 0 ;root directory flag + +fudge db 0 ;directory changed flag +user_drive db 0 +drive db 0 + + +dirchar db "/",0 + + +userdir db "/",0 + db (dirstrlen) dup(0) + +fname_buffer db 128 dup(0) +;-----------------------------------------------------------------------; + +pcrlf: mov dx,offset dg: crlf +print: mov ah,STD_CON_STRING_OUTPUT + int bdos +pret: ret +; +convert: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 + + mov cx,1810h + xchg dx,ax + call digit + xchg ax,bx + call outword + mov ax,bp + call outword + pop dx + call print +ret2: 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 + xor cl,cl +blankzer: + dec ch + and cl,ch + or dl,30h + sub dl,cl + cmp dl,30h + jl ret2 + mov ah,STD_CON_OUTPUT + int bdos + ret +; +convwrd:adc al,al + daa + xchg al,ah + adc al,al + daa + xchg al,ah + ret +; +; bx = fat[ax] +; +getfat: mov bx,offset dg: fattbl + push ax + mov si,ax + sar ax,1 + pushf + add si,ax + mov bx,word ptr [bx][si] + popf + jnc getfat1 + mov cl,4 + shr bx,cl +getfat1:and bh,00001111b + pop ax + mov cx,secsiz + ret +; +; fat[ax] = dx +; +setfat: mov bx,offset dg: fattbl + push ax + push dx + mov si,ax + sar ax,1 + pushf + add si,ax + mov ax,word ptr [bx][si] + popf + jnc setfat2 + and ax,000fh + mov cl,4 + shl dx,cl +setfat1:or ax,dx + mov word ptr [bx][si],ax + pop dx + pop ax + ret + +setfat2:and ax,0f000h + jmp setfat1 + +load: mov dx,firfat + mov al,byte ptr fatnum + mov byte ptr fatcnt,al + mov al,byte ptr drive + mov cx,fatsiz + mov bx,offset dg: fattbl +ret66: ret + +readft: call load +readit: call dskrd + cmp [fndfat],0 ;save location of readable fat sector + jnz fdfat + mov [fndfat],dx +fdfat: cmp word ptr [bx+1],-1 + jz ret66 + + add dx,cx ;try to read the other fats + dec byte ptr fatcnt + jnz readit + + mov dx,[fndfat] ;see if any readable at all + or dx,dx + jz readft ;if not disk is blown, keep trying + call dskrd + ret + +wrtfat: call load +wrtit: push ax + push bx + push cx + push dx + call dskwrt + pop dx + pop cx + pop bx + pop ax + +wrtok: add dx,cx + dec byte ptr fatcnt + jnz wrtit + ret + +printerr: + call print + jmp rabort + + +rec_start: + +;Code to print header +; PUSH AX +; MOV DX,OFFSET DG:HEADER +; CALL print +; POP AX + +DOSVER_HIGH EQU 0200H ;2.00 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 DG:BADVER + CALL PRINT + INT 20H + +OKDOS: POP AX + + cmp al,0ffH + JZ BADDRVSPECJ + mov si,80h + lodsb + or al,al + jz noparm +look: lodsb + cmp al," " + jz look + cmp al,9 + jz look + cmp al,13 + jnz gotparm +noparm: + jmp noname + +BADDRVSPECJ: JMP BADDRVSPEC + +gotparm: + mov ah,DISK_RESET + int bdos ;empty buffer queue + + mov ah,get_default_drive ;save current drive + int 21h + mov [user_drive],al + + mov bx,fcb ;determine input command + mov al,[bx] + dec al + cmp al,-1 + jnz drvok1 + mov al,[user_drive] +drvok1: + mov [drive],al + add [drvlet],al + add [drvlet1],al + mov dx,offset dg: askmsg + call print + mov ah,STD_CON_INPUT_FLUSH + mov al,1 ;wait for a key + int bdos + + cmp al,17h + jnz drvok2 + mov dx,offset dg: egomes + jmp printerr +egomes: db "Chris Peters helped with the new dos!",cr,lf + db "Microsoft rules ok$" + +drvok2: + IF IBMVER + MOV AL,DRIVE ;This is for ibm's single drive sys + PUSH DS + MOV BX,50H + MOV DS,BX + MOV DS:(BYTE PTR 4),AL ;Indicate drive changed + POP DS + ENDIF + +;----- 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],"\" + +slashok: + mov si,81h ;point to cammand line + mov di,offset dg: fname_buffer + xor cx,cx ;zero pathname length + +kill_bl: + lodsb ;get rid of blanks + cmp al,9 + je kill_bl + cmp al,' ' + je kill_bl + cmp al,13 ;A carriage return? + jne next_char + jmp noname ;yes, file name missing + +next_char: + stosb ;put patname in buffer + inc cx + lodsb + cmp al,' ' + je name_copied + cmp al,9 + je name_copied + cmp al,13 ; a CR ? + jne next_char + +name_copied: + mov byte ptr [di],0 ;nul terminate the pathname + dec di ;adjust to the end of the pathname + +;----- Scan for directory ----------------------------------------------; + + IF KANJI + mov dx,offset dg: [fname_buffer] + PUSH DX + PUSH DI + MOV BX,DI + MOV DI,DX +DELLOOP: + CMP DI,BX + JZ GOTDELE + MOV AL,[DI] + INC DI + CALL TESTKANJ + JZ NOTKANJ11 + INC DI + JMP DELLOOP + +NOTKANJ11: + cmp al,[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 sja ;Found a pathsep + JA sjb ;Started with a pathsep, root + MOV AX,[DI] + CALL TESTKANJ + JNZ same_dirj + XCHG AH,AL + cmp al,[dirchar] + jz sja ;One character directory +same_dirj: + ELSE + mov al,[dirchar] ;get directory separator character + std ;scan backwards + repnz scasb ;(cx has the pathname length) + cld ;reset direction, just in case + jz sja + 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. + +sja: + jcxz sjb ;no more chars left, it refers to root + cmp byte ptr [di],':' ;is the prvious character a disk def? + jne not_root +sjb: + mov [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 [fudge],01h ;remember that the current directory + ; has been changed. + +;----- Save current directory for exit ---------------------------------; + 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 +BADDRVSPEC: + mov dx,offset dg: baddrv + jmp printerr + +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 printerr + +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 sj1 + mov dx,offset dg: [fname_buffer] +sj1: + mov ah,chdir ;change directory + int 21h + mov dx,offset dg: baddrv + jnc no_errors + jmp printerr +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 23h + mov dx,offset dg: int_23 + int 21h + 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 + + mov bx,fcb + cmp byte ptr [bx+1],' ' ;must specify file name + jnz drvok + cmp byte ptr [bx],0 ;or drive specifier + jnz drvok +noname: mov dx,offset dg: drverr + call print + jmp int_23 + +drvok: push ds + mov dl,drive + inc dl + mov ah,GET_DPB + int bdos + mov ax,word ptr [bx+2] ;get physical sector size + mov cl,byte ptr [bx+4] ;get sectors/cluster - 1 + xor ch,ch + inc cx + mov cs:secall,cx ;save sectors per cluster + mul cx ;ax = bytes per cluster + mov bp,word ptr [bx+11] ;get record of first sector + mov dx,word ptr [bx+16] ;get record of first directory entry + mov si,word ptr [bx+6] ;get record of first fat + mov cl,byte ptr [bx+15] ;get size of fat + mov di,word ptr [bx+13] ;get number of clusters + mov ch,byte ptr [bx+8] ;get number of fats on drive + mov bx,word ptr [bx+9] ;get max number of dir entries + pop ds + + mov maxent,bx + mov firfat,si + mov firrec,bp + mov firdir,dx + mov byte ptr fatsiz,cl + mov lastfat,di ;number of fat entries + mov byte ptr fatnum,ch ;save number of fats on disk + + mov secsiz,ax + + mov di,table ;di points into constructed directory + mov ax,0e5e5h ;deleted file magic number + shl bx,1 ;16 words in a dir entry + shl bx,1 + shl bx,1 + shl bx,1 + mov cx,bx + rep stosw + + call readft + mov bx,fcb + cmp byte ptr [bx+1],' ' + jz recdsk + jmp recfil + +recdsk: mov di,table + mov fatptr,2 + mov ax,fatptr +step1: call getfat + cmp bx,0fffh + jz step1a + jmp step6 +step1a: mov filsiz,0 + mov word ptr filsiz+2,0 + mov dx,lastfat + mov target,ax +step2: mov ax,2 + add filsiz,cx + adc word ptr filsiz+2,0 +step3: call getfat + cmp bx,target + jne step4 + mov target,ax + jmp step2 +step4: inc ax + cmp ax,dx + jle step3 +; +; at this point target = head of list, filsiz = file size +; + inc filcnt ;increment file count + mov ax,maxent + cmp filcnt,ax ;compare with max number of entries + ja direrr + + mov si,(offset dg: dirent)+7 +nam0: inc byte ptr [si] ;increment file name + cmp byte ptr [si],'9' + jle nam1 + mov byte ptr [si],'0' + dec si + jmp nam0 + +nam1: mov ah,GET_DATE + int bdos ;set the date + sub cx,1980 + add dh,dh + add dh,dh + add dh,dh + add dh,dh + add dh,dh + rcl cl,1 + or dh,dl + mov byte ptr dirent+24,dh + mov byte ptr dirent+25,cl + mov ah,GET_TIME + int bdos ;set the time + shr dh,1 + add cl,cl + add cl,cl + add cl,cl + rcl ch,1 + add cl,cl + rcl ch,1 + add cl,cl + rcl ch,1 + or dh,cl + mov byte ptr dirent+22,dh + mov byte ptr dirent+23,ch + + mov ax,filsiz ;set file size + mov word ptr dirent+28,ax + mov ax,word ptr filsiz+2 + mov word ptr dirent+30,ax + mov ax,target ;set first cluster location + mov word ptr dirent+26,ax + + mov si,offset dg: dirent ;copy in new dir entry + mov cx,32 + rep movsb + +step6: inc fatptr ;keep looking for eof's + mov ax,fatptr + cmp ax,lastfat + jg step7 + jmp step1 + +direrr: dec filcnt + mov dx,offset dg: dirmsg + call print + +step7: + mov al,drive + mov dx,firdir ;write out constructed directory + mov cx,firrec + sub cx,dx + mov bx,table + call dskwrt + call pcrlf + mov dx,offset dg: recmsg_pre + call print + mov bx,offset dg: recmsg_post + mov si,filcnt + xor di,di ;output number of files created + call convert + jmp rexit +recfil: mov dx,fcb + mov ah,FCB_OPEN + int bdos + inc al + jnz recfil0 + mov dx,offset dg: opnerr + call print + jmp rexit + +recfil0:mov lastfat,1 ;indicate location of list head + mov di,fcb + mov ax,[di+16] ;get file size + mov filsiz,ax + mov siztmp,ax + mov ax,[di+18] + mov filsiz+2,ax + mov siztmp+2,ax + mov ax,[di+25] ;get list head + or ax,ax + mov fatptr,ax + jnz recfil1 +recvec: jmp recfil6 + +recfil1:cmp fatptr,0fffh + jz recvec ;terminate loop at e-o-f + + mov cx,secall + mov ax,fatptr + dec ax + dec ax + mul cx + add ax,firrec + mov dx,ax + mov bx,table + mov al,drive + int aread + pop di ;restore stack pointer + mov di,fcb ;restore pointer to fcb + jnc recfil4 ;if no error continue reading + + mov ax,fatptr + call getfat + cmp lastfat,1 + jnz recfil2 + + cmp bx,0fffh + jnz noteof + xor bx,bx +noteof: mov word ptr [di+25],bx + jmp recfil3 + +recfil2:mov dx,bx ;jump around bad sector + mov ax,lastfat + call setfat + +recfil3:mov ax,fatptr ;mark sector bad + mov dx,0ff7h + call setfat + mov ax,secsiz ;prepare to dec filsiz by secsiz + cmp siztmp+2,0 + jnz recfilx + cmp siztmp,ax + ja recfilx + mov ax,siztmp + +recfilx:sub word ptr [di+16],ax + sbb word ptr [di+18],0 + sub siztmp,ax + sbb siztmp,0 + + and byte ptr [di+24],10111111b ;mark file dirty + + mov ax,lastfat ;point to next sector to check + jmp recfil5 + +recfil4: + mov ax,secsiz ;set bytes remaining to be read + sub siztmp,ax + sbb siztmp+2,0 + jnc recok + xor ax,ax ;if < 0, then set to zero + mov siztmp,ax + mov siztmp+2,ax + +recok: mov ax,fatptr ;get next sector to test + mov lastfat,ax +recfil5:call getfat + mov fatptr,bx + jmp recfil1 + +recfil6: ;all done + mov dx,fcb + mov ah,FCB_CLOSE + int bdos ;close the file + call pcrlf + call report + +; +rexit: mov ah,DISK_RESET + int bdos + call wrtfat ;save the fat +int_23: call rest_dir +rabort: int boot ;home, james... + +;----- 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 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 + +const segment public byte + + EXTRN BADVER:BYTE,askmsg:BYTE,drvlet:BYTE,dirmsg:BYTE + EXTRN recmsg_pre:BYTE,DRVLET1:BYTE,recmsg_post:BYTE + EXTRN crlf:BYTE,drverr:BYTE,baddrv:BYTE,opnerr:BYTE + +const ends + +data segment byte + + PUBLIC filsiz + +dirent db 'FILE0000REC' + db 21 dup (00) + +fndfat dw 0000 ;sector of first good fat +filcnt dw 0000 +fatcnt db 00 +fatnum db 00 +fatsiz dw 0000 +firfat dw 0000 +fatptr dw 0000 +secall dw 0000 ;sectors per cluster +target dw 0000 +maxent dw 0000 +firrec dw 0000 +firdir dw 0000 +secsiz dw 0000 +siztmp dw 0000 + dw 0000 +filsiz dw 0000 + dw 0000 +lastfat dw 0000 +; +table dw offset dg:fattbl + 6 * 1024 +fattbl db 0 + +data ends + + end recover + \ No newline at end of file diff --git a/v2.0/source/ROM.ASM b/v2.0/source/ROM.ASM new file mode 100644 index 0000000..f668986 --- /dev/null +++ b/v2.0/source/ROM.ASM @@ -0,0 +1,530 @@ +; +; Disk utilities of 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 ROM - miscellaneous routines +NAME ROM + + i_need CLUSNUM,WORD + i_need NEXTADD,WORD + i_need LASTPOS,WORD + i_need SECCLUSPOS,BYTE + i_need FATBYT,WORD + i_need RECPOS,4 + i_need THISFCB,DWORD + i_need TRANS,BYTE + i_need BYTCNT1,WORD + i_need CURBUF,DWORD + i_need BYTSECPOS,WORD + i_need DMAADD,WORD + i_need SECPOS,WORD + i_need VALSEC,WORD + + procedure GET_random_record,NEAR + entry GETRRPOS1 + MOV CX,1 + entry GetRRPos + MOV DI,DX + CMP BYTE PTR [DI],-1 + JNZ NORMFCB1 + ADD DI,7 +NORMFCB1: + MOV AX,WORD PTR [DI.fcb_RR] + MOV DX,WORD PTR [DI.fcb_RR+2] + return +GET_random_record ENDP + +SUBTTL FNDCLUS -- Skip over allocation units +PAGE + procedure FNDCLUS,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; CX = No. of clusters to skip +; ES:BP = Base of drive parameters +; [THISFCB] point to FCB +; Outputs: +; BX = Last cluster skipped to +; CX = No. of clusters remaining (0 unless EOF) +; DX = Position of last cluster +; DI destroyed. No other registers affected. + + PUSH ES + LES DI,[THISFCB] + MOV BX,ES:[DI.fcb_LSTCLUS] ; fcb_lstclus is packed with dir clus + AND BX,0FFFh ; get rid of dir nibble + MOV DX,ES:[DI.fcb_CLUSPOS] + OR BX,BX + JZ NOCLUS + SUB CX,DX + JNB FINDIT + ADD CX,DX + XOR DX,DX + MOV BX,ES:[DI.fcb_FIRCLUS] +FINDIT: + POP ES + JCXZ RET10 +entry SKPCLP + invoke UNPACK + CMP DI,0FF8H + JAE RET10 + XCHG BX,DI + INC DX + LOOP SKPCLP +RET10: return + +NOCLUS: + POP ES + INC CX + DEC DX + return +FNDCLUS ENDP + +SUBTTL BUFSEC -- BUFFER A SECTOR AND SET UP A TRANSFER +PAGE + procedure BUFSEC,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; AH = priority of buffer +; AL = 0 if buffer must be read, 1 if no pre-read needed +; ES:BP = Base of drive parameters +; [CLUSNUM] = Physical cluster number +; [SECCLUSPOS] = Sector position of transfer within cluster +; [BYTCNT1] = Size of transfer +; Function: +; Insure specified sector is in buffer, flushing buffer before +; read if necessary. +; Outputs: +; ES:DI = Pointer to buffer +; SI = Pointer to transfer address +; CX = Number of bytes +; [NEXTADD] updated +; [TRANS] set to indicate a transfer will occur + + MOV DX,[CLUSNUM] + MOV BL,[SECCLUSPOS] + CALL FIGREC + invoke GETBUFFR + MOV BYTE PTR [TRANS],1 ; A transfer is taking place + MOV SI,[NEXTADD] + MOV DI,SI + MOV CX,[BYTCNT1] + ADD DI,CX + MOV [NEXTADD],DI + LES DI,[CURBUF] + ADD DI,BUFINSIZ ; Point to buffer + ADD DI,[BYTSECPOS] + return +BUFSEC ENDP + +SUBTTL BUFRD, BUFWRT -- PERFORM BUFFERED READ AND WRITE +PAGE + procedure BUFRD,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Do a partial sector read via one of the system buffers +; ES:BP Points to DPB + + PUSH ES + MOV AX,LBRPRI SHL 8 ; Assume last byte read + CALL BUFSEC + MOV BX,ES + MOV ES,[DMAADD+2] + MOV DS,BX +ASSUME DS:NOTHING + XCHG DI,SI + SHR CX,1 + JNC EVENRD + MOVSB +EVENRD: + REP MOVSW + POP ES + LDS DI,[CURBUF] + LEA BX,[DI.BufInSiz] + SUB SI,BX ; Position in buffer + invoke PLACEBUF + CMP SI,ES:[BP.dpb_sector_size] + JB RBUFPLACED + invoke PLACEHEAD +RBUFPLACED: + PUSH SS + POP DS + return +BUFRD ENDP + + procedure BUFWRT,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Do a partial sector write via one of the system buffers +; ES:BP Points to DPB + + MOV AX,[SECPOS] + INC AX ; Set for next sector + MOV [SECPOS],AX + CMP AX,[VALSEC] ; Has sector been written before? + MOV AL,1 + JA NOREAD ; Skip preread if SECPOS>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/v2.0/source/RUCODE.ASM b/v2.0/source/RUCODE.ASM new file mode 100644 index 0000000..927a559 Binary files /dev/null and b/v2.0/source/RUCODE.ASM differ diff --git a/v2.0/source/SKELIO.ASM b/v2.0/source/SKELIO.ASM new file mode 100644 index 0000000..b2ff8e3 --- /dev/null +++ b/v2.0/source/SKELIO.ASM @@ -0,0 +1,1377 @@ + TITLE IO.SYS for the ALTOS ACS-86C. + +; I/O system for Version 2.x of MSDOS. + +;This BIOS designed to be linked with the SYSINIT module provided by +;Microsoft + +BIOSIZ EQU 4096 ;Size of BIOS in bytes. +BIOSIZS EQU 100H ;Size of BIOS in Paragraphs. +ANSI EQU 0 ;Ansi switch. + +;Additional Information for the ALTOS machine. + +QSIZE EQU 100 ;Input queue size. +BIOSSEG EQU 0C0H ;I/O system segment. +MAX_MEM EQU 4000H ;Memory size in paragraphs. + +; Constants for commands in Altos ROM. + +ROM_CONSTA EQU 01 ;Return status AL of console selected in CX. +ROM_CONIN EQU 02 ;Get char. from console in CX to AL +ROM_CONOUT EQU 03 ;Write char. in DL to console in CX. +ROM_PMSG EQU 07 ;Write string ES:DX to console in CX. +ROM_DISKIO EQU 08 ;Perform disk I/O from IOPB in ES:CX. +ROM_INIT EQU 10 ;Returns boot console and top memory ES:DX. + +;Things needed to communicate with SYSINIT + +EXTRN SYSINIT:FAR ;The entry point of SYSINIT +EXTRN CURRENT_DOS_LOCATION:WORD ;Where the DOS is when SYSINIT called +EXTRN FINAL_DOS_LOCATION:WORD ;Where I want SYSINIT to put the DOS +EXTRN DEVICE_LIST:DWORD ;Pointer to the DEVICE list. +EXTRN MEMORY_SIZE:WORD ;Size in paragraphs of Physical memory. +EXTRN DEFAULT_DRIVE:BYTE ;Default Drive to use when system booted +EXTRN BUFFERS:BYTE ;Number of default buffers. + ; Leave as is and SYSINIT uses only 2. + +CODE SEGMENT +ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE + + ORG 0 ;Starts at an offset of zero. + +INIT: JMP HWINIT + + PAGE + + SUBTTL Device driver tables. + +;-----------------------------------------------+ +; DWORD pointer to next device | 1 word offset. +; (-1,-1 if last device) | 1 word segement. +;-----------------------------------------------+ +; Device attribute WORD ; 1 word. +; Bit 15 = 1 for chacter devices. ; +; 0 for Block devices. ; +; ; +; Charcter devices. (Bit 15=1) ; +; Bit 0 = 1 current sti device. ; +; Bit 1 = 1 current sto device. ; +; Bit 2 = 1 current NUL device. ; +; Bit 3 = 1 current Clock device. ; +; ; +; Bit 13 = 1 for non IBM machines. ; +; 0 for IBM machines only. ; +; Bit 14 = 1 IOCTL control bit. ; +;-----------------------------------------------+ +; Device strategy pointer. ; 1 word offset. +;-----------------------------------------------+ +; Device interrupt pointer. ; 1 word offset. +;-----------------------------------------------+ +; Device name field. ; 8 bytes. +; Character devices are any valid name ; +; left justified, in a space filled ; +; field. ; +; Block devices contain # of units in ; +; the first byte. ; +;-----------------------------------------------+ + +DEVSTART LABEL WORD +CONDEV: ;Header for device CON + DW AUXDEV,BIOSSEG ;Link to next device + DW 8003H ;Attributes - console input, output device + DW STRATEGY ;Srategy entry point + DW CON_INT ;Interrupt entry point + DB "CON " ;Device name + +AUXDEV: ;Header for device AUX + DW PRNDEV,BIOSSEG + DW 8000H + DW STRATEGY + DW AUX_INT + DB "AUX " + +PRNDEV: ;Header for device PRN + DW TIMDEV,BIOSSEG + DW 8000H + DW STRATEGY + DW PRN_INT + DB "PRN " + +TIMDEV: ;Header for device CLOCK + DW DSKDEV,BIOSSEG + DW 8008H + DW STRATEGY + DW TIM_INT + DB "CLOCK " + +DSKDEV: ;Header for disk devices + DW -1,-1 ;Last device + DW 2000H ;Is a block device + DW STRATEGY + DW DSK_INT +DRVMAX DB 1 ;Number of Units + DB 7 DUP (?) + + PAGE + SUBTTL Dispatch tables for each device. + +DSKTBL: DW DSK_INIT ;0 - Initialize Driver. + DW MEDIAC ;1 - Return current media code. + DW GET_BPB ;2 - Get Bios Parameter Block. + DW CMDERR ;3 - Reserved. (currently returns error) + DW DSK_RED ;4 - Block read. + DW BUS_EXIT ;5 - (Not used, return busy flag) + DW EXIT ;6 - Return status. (Not used) + DW EXIT ;7 - Flush input buffer. (Not used.) + DW DSK_WRT ;8 - Block write. + DW DSK_WRV ;9 - Block write with verify. + DW EXIT ;10 - Return output status. + DW EXIT ;11 - Flush output buffer. (Not used.) + DW EXIT ;12 - IO Control. + +CONTBL: DW EXIT ;0 - Init. (Not used) + DW EXIT ;1 - Media check (Not used) + DW EXIT ;2 - Get Bios Parameter Block (Not used) + DW CMDERR ;3 - Reserved. (Currently returns error) + DW CON_READ ;4 - Character read. (Destructive) + DW CON_RDND ;5 - Character read. (Non-destructive) + DW EXIT ;6 - Return status. (Not used) + DW CON_FLSH ;7 - Flush Input buffer. + DW CON_WRIT ;8 - Character write. + DW CON_WRIT ;9 - Character write with Verify. + DW CON_WRST ;10 - Character write status. + DW EXIT ;11 - Flush output buffer. (Not used.) + DW EXIT ;12 - IO Control. + +AUXTBL: DW EXIT ;0 - Init. (Not used) + DW EXIT ;1 - Media check (Not used) + DW EXIT ;2 - Get Bios Parameter Block (Not used) + DW CMDERR ;3 - Reserved. (Returns an error) + DW AUX_READ ;4 - Character read. (Destructive) + DW AUX_RDND ;5 - Character read. (Non-destructive) + DW EXIT ;6 - Return status. (Not used) + DW AUX_CLR ;7 - Flush Input buffer. + DW AUX_WRIT ;8 - Character write. + DW AUX_WRIT ;9 - Character write with verify. + DW AUX_WRST ;10 - Character write status. + DW EXIT ;11 - Flush output buffer. (Not used.) + DW EXIT ;12 - IO Control. + +TIMTBL: DW EXIT ;0 - Init. (Not used) + DW EXIT ;1 - Media check (Not used) + DW EXIT ;2 - Get Bios Parameter Block (Not used) + DW CMDERR ;3 - Reserved. (Currently returns an error) + DW TIM_RED ;4 - Character read. (Destructive) + DW BUS_EXIT ;5 - (Not used, returns busy flag.) + DW EXIT ;6 - Return status. (Not used) + DW EXIT ;7 - Flush Input buffer. (Not used) + DW TIM_WRT ;8 - Character write. + DW TIM_WRT ;9 - Character write with verify. + DW EXIT ;10 - Character write status. (Not used) + DW EXIT ;11 - Flush output buffer. (Not used) + DW EXIT ;12 - IO Control. + +PRNTBL: DW EXIT ;0 - (Not used) + DW EXIT ;1 - (Not used) + DW EXIT ;2 - Block (Not used) + DW CMDERR ;3 - Reserved. (currently returns error) + DW EXIT ;4 - (Not used) + DW BUS_EXIT ;5 - (Not used, returns busy flag.) + DW EXIT ;6 - (Not used) + DW EXIT ;7 - (Not used) + DW PRN_WRT ;8 - Character write. + DW PRN_WRT ;9 - Character write with verify. + DW PRN_STA ;10 - Character write status. + DW EXIT ;11 - (Not used.) + DW EXIT ;12 - IO Control. + + PAGE + SUBTTL Strategy and Software Interrupt routines. + +;Define offsets for io data packet + +IODAT STRUC +CMDLEN DB ? ;LENGTH OF THIS COMMAND +UNIT DB ? ;SUB UNIT SPECIFIER +CMD DB ? ;COMMAND CODE +STATUS DW ? ;STATUS + DB 8 DUP (?) +MEDIA DB ? ;MEDIA DESCRIPTOR +TRANS DD ? ;TRANSFER ADDRESS +COUNT DW ? ;COUNT OF BLOCKS OR CHARACTERS +START DW ? ;FIRST BLOCK TO TRANSFER +IODAT ENDS + +PTRSAV DD 0 ;Strategy pointer save. + +; +; Simplistic Strategy routine for non-multi-Tasking system. +; +; Currently just saves I/O packet pointers in PTRSAV for +; later processing by the individual interrupt routines. +; + +STRATP PROC FAR + +STRATEGY: + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + RET + +STRATP ENDP + +; +; Console interrupt routine for processing I/O packets. +; + +CON_INT: + PUSH SI + MOV SI,OFFSET CONTBL + JMP SHORT ENTRY + +; +; Auxilary interrupt routine for processing I/O packets. +; + +AUX_INT: + PUSH SI + MOV SI,OFFSET AUXTBL + JMP SHORT ENTRY + +; +; Printer interrupt routine for processing I/O packets. +; + +PRN_INT: + PUSH SI + MOV SI,OFFSET PRNTBL + JMP SHORT ENTRY + +; +; Clock interrupt routine for processing I/O packets. +; + +TIM_INT: + PUSH SI + MOV SI,OFFSET TIMTBL + JMP SHORT ENTRY + +; +; Disk interrupt routine for processing I/O packets. +; + +DSK_INT: + PUSH SI + MOV SI,OFFSET DSKTBL + +; +; Common program for handling the simplistic I/O packet +; processing scheme in MSDOS 2.0 +; + +ENTRY: PUSH AX ;Save all nessacary registers. + PUSH CX + PUSH DX + PUSH DI + PUSH BP + PUSH DS + PUSH ES + PUSH BX + + LDS BX,CS:[PTRSAV] ;Retrieve pointer to I/O Packet. + + MOV AL,[BX.UNIT] ;AL = Unit code. + MOV AH,[BX.MEDIA] ;AH = Media descriptor. + MOV CX,[BX.COUNT] ;CX = Contains byte/sector count. + MOV DX,[BX.START] ;DX = Starting Logical sector. + + XCHG DI,AX ;Move Unit & Media into DI temporarily. + MOV AL,[BX.CMD] ;Retrieve Command type. (1 => 11) + XOR AH,AH ;Clear upper half of AX for calculation. + ADD SI,AX ;Compute entry pointer in dispatch table. + ADD SI,AX + CMP AL,11 ;Verify that not more than 11 commands. + JA CMDERR ;Ah, well, error out. + XCHG AX,DI ;Move Unit & Media back where they belong. + LES DI,[BX.TRANS] ;DI contains addess of Transfer address. + ;ES contains segment. + PUSH CS + POP DS ;Data segment same as Code segment. + JMP [SI] ;Perform I/O packet command. + + PAGE + SUBTTL Common error and exit points. + +BUS_EXIT: ;Device busy exit. + MOV AH,00000011B ;Set busy and done bits. + JMP SHORT EXIT1 + +CMDERR: MOV AL,3 ;Set unknown command error #. + +; +; Common error processing routine. +; AL contains actual error code. +; +; Error # 0 = Write Protect violation. +; 1 = Unkown unit. +; 2 = Drive not ready. +; 3 = Unknown command in I/O packet. +; 4 = CRC error. +; 5 = Bad drive request structure length. +; 6 = Seek error. +; 7 = Unknown media discovered. +; 8 = Sector not found. +; 9 = Printer out of paper. +; 10 = Write fault. +; 11 = Read fault. +; 12 = General failure. +; + +ERR_EXIT: + MOV AH,10000001B ;Set error and done bits. + STC ;Set carry bit also. + JMP SHORT EXIT1 ;Quick way out. + +EXITP PROC FAR ;Normal exit for device drivers. + +EXIT: MOV AH,00000001B ;Set done bit for MSDOS. +EXIT1: LDS BX,CS:[PTRSAV] + MOV [BX.STATUS],AX ;Save operation compete and status. + + POP BX ;Restore registers. + POP ES + POP DS + POP BP + POP DI + POP DX + POP CX + POP AX + POP SI + RET ;RESTORE REGS AND RETURN +EXITP ENDP + + PAGE + SUBTTL Main console I/O section. + +MCON DW 0001H +PCON DW 0002H +ACON DW 0003H + +CHAR DB ? ;Small typeahead buffer for now. + +; +; Console keyboard handler. +; + +CISTAT: PUSH CX ;Save CX pair. + MOV AL,[CHAR] + OR AL,AL + JNZ CISTA9 ;Character still in buffer. +CISTA1: MOV BX,ROM_CONSTA + MOV CX,[MCON] + CALL ROM_CALL ;See if character waiting. + TEST AL,AL + JZ CISTA9 + MOV BX,ROM_CONIN + MOV CX,[MCON] + CALL ROM_CALL ;Get character from Rom. + OR AL,AL + JZ CISTA1 ;Got a null character. + MOV [CHAR],AL +CISTA9: POP CX ;Can't lose CX pair. + RET + +; +; Get a character from the buffer queue. +; + +CINP: CALL CISTAT ;Check for character ready in queue. + JZ CINP ;Cycle until one ready. + MOV [CHAR],0 ;We have character in AL, clear type a head. + RET + +; +; Console read non-destructive. +; + +CON_RDND: + CALL CISTAT ;See if character ready. + JZ CON_RDN2 ;No, return busy signal. +CON_RDN1: + LDS BX,CS:[PTRSAV] + MOV [BX.MEDIA],AL + JMP EXIT +CON_RDN2: + JMP BUS_EXIT + +; +; Console destructive read. +; + +CON_READ: + CALL CINP ;Get character. + STOSB ;Save it in users buffer. + LOOP CON_READ ;Loop until CX is exhausted. + JMP EXIT + +; +; Console flush routine. (ctrl-c, ctrl-f, or ctrl-s inspired) +; + +CON_FLSH: + MOV [CHAR],0 ;Clear small type a head buffer. + JMP EXIT + +; +; Console output status routine. +; + +CON_WRST: + JMP EXIT ;Yes, normal exit. + +; +; Console output routine. +; + +CON_WRIT: + MOV SI,DI ;Get destination to source. +CON_WRI1: + LODS BYTE PTR ES:[SI] + PUSH CX +IF ANSI + CALL CONOUT ;Call ansi driver. + ENDIF +IFE ANSI + CALL OUTCHR + ENDIF + POP CX + LOOP CON_WRI1 ;Keep going until user buffer through. + JMP EXIT + +; +; Console character output routine. +; + +OUTCHR: MOV BX,ROM_CONOUT + MOV CX,[MCON] ;Get current console port. + MOV DL,AL + CALL ROM_CALL + RET + + PAGE + +IF ANSI + + SUBTTL ANSI interface section. + +; +;ANSI Info and routines. ANSI driver implemented as a finite state automata +;This ANSI driver translates the ANSI standard escape sequences into the +; Zenith Escape sequences used on the Zenith(Heath) Z(H)-19 terminal. +;This is not a full implementation of ANSI, but rather a minimal implementation +; which implements all of the necessary ANSI functions. +; + +ESC EQU 1BH ;Escape character used in this implementation. +STATE DW ST1 ;Current ANSI character state. +PRMPNT DW PARMS ;Current parameter pointer. +PARMS DB 0,0,0,0,0,0,0 ;Allow for up to eight parameters. +LASTPRM DB 0 ;With this being the eight one. + +CMDTABL DB 'A' ;Cursor up. "esc","[",#,"A" + DW CUU + DB 'B' ;Cursor down. "esc","[",#,"B" + DW CUD + DB 'C' ;Cursor forward. "esc","[",#,"C" + DW CUF + DB 'D' ;Cursor back. "esc","[",#,"D" + DW CUB + DB 'H' ;Direct cursor posit. "esc","[",x,y,"H" + DW CUP + DB 'J' ;Erase. "esc","[",code,"J" + DW ED + DB 'K' ;Erase in line. "esc","[",code,"K" + DW EL + DB 'f' ;Direct cursor posit. "esc","[",x,y,"f" + DW CUP + DB 'm' ;Special video mode. "esc","[",code,"m" + DW SGR + DB 's' ;Save cursor posit. "esc","[","s" + DW PSCP + DB 'u' ;Move cursor to saved. "esc","[","u" + DW PRCP + DB 00 ;End of table. + +; +; ANSI console output driver. +; + +CONOUT: MOV DI,OFFSET STATE ;Retrieve current ansi state. + JMP [DI] ;Jump to it. + +; +; State one (1). +; Looks for an Escape character. +; + +ST1: CMP AL,ESC ;See if this the first character is ESC. + JNZ OUTCHR ;No, treat as regular character output. + MOV WORD PTR [DI],OFFSET ST2 ;Yes, setup state two. + RET + +; +; State two (2). +; Looks for the "[" character. +; + +ST2: CMP AL,'[' ;See if a valide state two. + JNZ OUTCHR ;No, treat as regular charcter + MOV BX,OFFSET PARMS ;Yes, get parameter pointer. + MOV WORD PTR [PRMPNT],BX ;Setup in pointer index. + MOV WORD PTR [BX],0 ;Clear first entry. + MOV WORD PTR [DI],OFFSET ST3;Setup for state three. + RET + +; +; State three (3). +; Entered one or more times for parameter passing. +; + +ST3: CMP AL,';' ;Look for decimal # seperator. + JNZ ST3A ;No check phase A. + INC WORD PTR [PRMPNT] ;Yes, incr. pointer to next param. + MOV AX,OFFSET LASTPRM ;Check for outside parameter list. + CMP [PRMPNT],AX + JBE RETST3 ;Yes, proceed with next parameter. + MOV [PRMPNT],AX ;No, treat as extentsion to old. +RETST3: MOV DI,[PRMPNT] ;Setup for next parameter. + MOV BYTE PTR [DI],0 ;Pre-Initialize it to zero. + RET + +; +; State three A (3A). +; Check for a ascii digit. +; + +ST3A: CMP AL,'0' ;Check for ASCII digit. + JB ST3B ;No, check for seconday command character. + CMP AL,'9' ;Still checking for ASCII digit. + JA ST3B ;No, it must be a secondary. + SUB AL,'0' ;Convert to binary. + MOV DI,[PRMPNT] ;Get the current parameter pointer. + XCHG [DI],AL ;Get existing #. + MOV AH,10 ;Scale by 10. + MUL AH + ADD [DI],AL ;Add to new digit. + RET + +; +; State three B (3B). +; Wasn't a ascii digit, so check for secondary command. +; + +ST3B: MOV [DI],OFFSET ST1 ;Preset STATE to state 1 just in case. + MOV DI,OFFSET PARMS-1 ;Get pointer to start of parameters. + MOV [PRMPNT],DI ;Save it in Parameter pointer. + MOV DI,OFFSET CMDTABL-3 ;Get start of Secondary command table. + +ST3B1: ADD DI,3 ;Update Command table pointer. + CMP BYTE PTR [DI],0 ;Check for end of table. + JNZ ST3B2 ;No, continue processing. + JMP OUTCHR ;Yes, treat as regular character. +ST3B2: CMP AL,[DI] ;Check for valid. command. + JNZ ST3B1 ;No, keep checking. + JMP [DI+1] ;Yes, transfer to that secondary command. + +; +; Get binary parameter from storage and return a one if = 0 +; + +GETONE: CALL GETPARM ;Get parameter form list. + OR AL,AL ;Verify for non-zero. + JNZ GETRET ;Good, then return to caller. + INC AL ;Bad, make it at least a one. +GETRET: CBW ;Sign extend AL. + MOV CX,AX ;Copy of it to CX. + RET + +GETPARM:INC WORD PTR [PRMPNT] ;Increment parameter pointer. +GOTPARM:MOV DI,[PRMPNT] ;Get parameter pointer. + MOV AL,[DI] ;Get parameter value. + RET + +; +; Send escape, character sequence. +; + +OUTESC: MOV AL,ESC ;Send escape character. + CALL OUTCHR + MOV AL,BL ;Send follow character. + JMP OUTCHR + +; +; Cursor Positioning routines. +; + +CUU: MOV BL,'A' ;Cursor up. + JMP SHORT CURPOS +CUD: MOV BL,'B' ;Cursor down. + JMP SHORT CURPOS +CUF: MOV BL,'C' ;Cursor forward. + JMP SHORT CURPOS +CUB: MOV BL,'D' ;Cursor back. + +CURPOS: CALL GETONE ;Get number of positions to move into CX. +MOVCUR: CALL OUTESC ;Send escape, command characters. + LOOP MOVCUR ;Keep moving until done. + RET + +; +; Direct cursor positioning routine. +; + +CUP: CALL GETONE ;Get X position. + MOV DX,AX ;Save in DX. + CALL GETONE ;Get Y position. + MOV BL,'Y' + CALL OUTESC ;Send escape, "Y" sequence. + MOV AL,DL + ADD AL,' '-1 ;Convert binary to Character. + CALL OUTCHR ;Send X posit. + MOV AL,CL + ADD AL,' '-1 ;Convert binary to Character. + JMP OUTCHR ;Send Y posit. + +; +; Erase all/part of screen. +; + +ED: CALL GETPARM ;Get trinary command type. + MOV BL,'b' + DEC AL ;See if erase from begining of screen. + JZ ED1 ;Yes, perform ZDS function. + MOV BL,'E' + DEC AL ;See if erase from end of screen. + JZ ED1 ;Yes, perform ZDS function. + MOV BL,'J' ;Now we assume erase whole screen. +ED1: JMP OUTESC + +; +; Erase all/part of a line. +; + +EL: CALL GETPARM ;Get trinary command type. + MOV BL,'o' + DEC AL ;See if erase from begining of line. + JZ EL1 ;Yes, perform ZDS function. + MOV BL,'l' + DEC AL ;See if erase whole line. + JZ EL1 ;Yes, perform ZDS function. + MOV BL,'K' ;Now we assume erase to end of line. +EL1: JMP OUTESC + +; +; Special video modes. +; + +SGR: CALL GETPARM ;Get trinary command type. + MOV BL,'p' + CMP AL,7 ;See if enter reverse video mode. + JZ SGR2 ;Yes, perform ZDS function. + MOV BL,'q' + OR AL,AL ;See if exit reverse video mode. + JNZ SGR3 ;No, ignore. +SGR2: CALL OUTESC +SGR3: RET + +; +; Save / restore cursor position. +; + +PSCP: MOV BL,'j' ;Set save cursor posit. mode. + JMP OUTESC + +PRCP: MOV BL,'k' ;Restore last cursor save. + JMP OUTESC + + ENDIF + + + PAGE + SUBTTL Printer buffer handler. + +; +; Printer status routine. +; + +PRN_STA: + JMP EXIT + +; +; Printer write routine. +; + +PRN_WRT:MOV SI,DI ;Set source = destination index. + +PRN_WR1:LODS BYTE PTR ES:[SI];Get a data byte. + PUSH CX + MOV CX,[PCON] + MOV BX,ROM_CONOUT + MOV DL,AL + CALL ROM_CALL + POP CX + LOOP PRN_WR1 + RET + + PAGE + SUBTTL Auxilary I/O routines. + +AUXCHAR DB 0 ;Temporary AUX ahead storage. + +; +; Status routine for Auxilary port. +; + +AISTAT: MOV AL,[AUXCHAR] + TEST AL,AL + JNZ AISTA9 ;Character already waiting. + MOV CX,[ACON] + MOV BX,ROM_CONSTA + CALL ROM_CALL + TEST AL,AL + JZ AISTA9 ;Still none waiting. + MOV CX,[ACON] + MOV BX,ROM_CONIN + CALL ROM_CALL +AISTA9: MOV [AUXCHAR],AL + RET + +; +; Auxilary port read. +; + +AIN: CALL AISTAT ;Get status and/or char. + JZ AIN ;Cycle until one is ready. + MOV [AUXCHAR],0 + RET + +; +; Write routine for Auxilary port. +; + +AOUT: MOV CX,[ACON] + MOV BX,ROM_CONOUT + MOV DL,AL + CALL ROM_CALL + RET + +; +; Non-Destructive Auxilary read routine. +; + +AUX_RDND: + CALL AISTAT ;Get status and copy of char. waiting if any. + JZ AUX_RDN2 ;No character waiting, exit. + JMP CON_RDN1 +AUX_RDN2: + JMP BUS_EXIT + +; +; Destructive Auxilary read routine. +; + +AUX_READ: + CALL AIN ;Get data character. + STOSB ;Save it through DI. + LOOP AUX_READ ;Cycle until user buffer full. + JMP EXIT + +; +; Auxilary clear type a head. +; + +AUX_CLR: + MOV [AUXCHAR],0 + JMP EXIT + +; +; Auxilary write port status. +; + +AUX_WRST: + JMP EXIT + +; +; Auxilary write. +; + +AUX_WRIT: + MOV SI,DI +AUX_WRI1: + LODS BYTE PTR ES:[SI] ;Get char. from users buffer. + CALL AOUT ;Send it to device. + LOOP AUX_WRI1 ;Cycle until all done. + JMP EXIT + + PAGE + SUBTTL Date/Time Routines. + +TIM_DAYS: DB 2 DUP (?) ;Number of days since 1-1-80. +TIM_MINS: DB ? ;Minutes. +TIM_HRS: DB ? ;Hours. +TIM_HSEC: DB ? ;Hundreths of a second. +TIM_SECS: DB ? ;Seconds. + +; +; Time write routine. +; + +TIM_WRT: + MOV SI,OFFSET TIM_DAYS + XCHG SI,DI + PUSH ES + MOV AX,DS + POP DS + MOV ES,AX + MOV CX,6 + REP MOVSB + MOV AL,0 + JMP EXIT + +; +; Time read routine. +; + +TIM_RED: + MOV SI,OFFSET TIM_DAYS + MOV CX,6 + REP MOVSB + MOV AL,0 + JMP EXIT + + PAGE + SUBTTL 8089 Monitor structure. + +; +; Structure to reference 8089 and ROM command table. +; + +SIOPB STRUC + DB 4 DUP (?) ;Monitor Use Only +OPCODE DB ? ;I/O operation code. +DRIVE DB ? ;Logical drive spec. +TRACK DW ? ;Logical track number. +HEAD DB ? ;Logical head number. +SECTOR DB ? ;Logical sector to start with. +SCOUNT DB ? ;Number of logical sectors in buffer. +RETCODE DB ? ;Error code after masking. +RETMASK DB ? ;Error mask. +RETRIES DB ? ;Number of retries before error exit. +DMAOFF DW ? ;Buffer offset address. +DMASEG DW ? ;Buffer segment. +SECLENG DW ? ;Sector Length. + DB 6 DUP (?) ;8089 use only. +SIOPB ENDS + +IOPB SIOPB <,00H,0,0,0,0,0,0,000H,0,0,0,0,> + + PAGE + SUBTTL Drive Tables. + + +; +; MSDOS drive initialization tables and other what not. +; +; Drive 0 is: +; Single sided, Single density, 77 track with 26 +; 128 byte sectors per track. One sector for +; boot and header. (256,128 bytes free, old style). +; or +; Single sided, Single density, 77 track with 26 +; 128 byte sectors per track. Four sectors for +; boot and header. (255,744 bytes free). +; or +; Single sided, Double Density, 75 track with 12 +; 512 byte sectors per track. +; (460,800 bytes) +; Two hidden single density tracks. +; + +DBP STRUC + +JMPNEAR DB 3 DUP (?) ;Jmp Near xxxx for boot. +NAMEVER DB 8 DUP (?) ;Name / Version of OS. + +;------- Start of Drive Parameter Block. + +SECSIZE DW ? ;Sector size in bytes. (dpb) +ALLOC DB ? ;Number of sectors per alloc. block. (dpb) +RESSEC DW ? ;Reserved sectors. (dpb) +FATS DB ? ;Number of FAT's. (dpb) +MAXDIR DW ? ;Number of root directory entries. (dpb) +SECTORS DW ? ;Number of sectors per diskette. (dpb) +MEDIAID DB ? ;Media byte ID. (dpb) +FATSEC DW ? ;Number of FAT Sectors. (dpb) + +;------- End of Drive Parameter Block. + +SECTRK DW ? ;Number of Sectors per track. + +DBP ENDS + +LSDRIV1 DBP <,,128,4,1,2,68,2002,0FEH,6,26> + +LSDRIV2 DBP <,,128,4,4,2,68,2002,0FDH,6,26> + +LDDRIV1 DBP <,,512,1,24,2,128,924,0F8H,3,12> + +LDDRIV2 DBP <,,1024,1,16,2,128,616,0F9H,1,8> + +DSK_INIT: + MOV AX,1 + MOV SI,OFFSET INITTAB + JMP GET_BP5 + +INITTAB: + DW LDDRIV2.SECSIZE + +DSTAT EQU 41H ;1793 status port. +DTRACK EQU 43H ;1793 track port. +DSECTOR EQU 45H ;1793 sector port. +DDATA EQU 47H ;1793 data I/O port. + +DDENS EQU 55H ;Density select port. +DDBIT EQU 04H ;Density select bit. +DSELECT EQU 53H ;Drive select port. + +CURDRV DB 0 +DRVTAB DB 0EH,0DH,0BH,07H +TRKPT DB 0,1,2,3 +TRKTAB DB -1,-1,-1,-1 +PREDENS DB 0,0,0,0 + + PAGE + SUBTTL Media check routine + +; +; Media check routine. +; On entry: +; AL = disk unit number. +; AH = media byte +; On exit: +; +; [MEDIA FLAG] = -1 (FF hex) if disk is changed. +; [MEDIA FLAG] = 0 if don't know. +; [MEDIA FLAG] = 1 if not changed. +; +; [MEDIA] = 0FEH for Standard single density. +; [MEDIA] = 0FDH for Altos single density. +; [MEDIA] = 0F4H for Altos double density. +; + +MEDIAS STRUC + DB 13 DUP(?) ;Static request header. +MEDIAS1 DB ? ;Media byte. +MEDIAS2 DB ? ;Media status byte flag. +MEDIAS ENDS + +MEDIAC: + AND AL,03H ;Clear any extraneous bits. + PUSH AX ;Save drive number requested. + MOV AL,0D0H ;Terminate with no interrupt. + CALL DCOM + AND AL,20H ;See if head load bit set. + POP AX + JZ MEDIA2 ;Head not loaded, so see if media changed. + MOV AH,1 ; AH = 1, disk not changed. + JMP SHORT MEDIA1 + +MEDIA1A:MOV [PREDENS],DL ;Save last density used for read. + +MEDIA1: LDS BX,[PTRSAV] ;Udate media section of data block. + MOV [BX.MEDIAS2],AH + MOV AL,0 + JMP EXIT + +MEDIA2: CALL MEDIA4 ;Unload head if selecting new drive. + MOV CX,2 ;Try each density once. + MOV BX,OFFSET DRVTAB + XLAT ;Convert from drive # to select code. + OUT DSELECT,AL ;Select disk + MOV AH,0 ;Assume that we don't know. + MOV DL,[PREDENS] ;Get last density. + AND DL,DDBIT ;Be sure only Density bit set/clr. +MEDIA3: IN AL,DDENS + AND AL,0FBH ;Clear density bit. + OR AL,DL ;Set/clear density bit. + OUT DDENS,AL ;Select density. + MOV AL,0C4H ;READ ADDRESS command + CALL DCOM + AND AL,98H + IN AL,DDATA ;Eat last byte to reset DRQ + JZ MEDIA1A ;Jump if no error in reading address. + MOV AH,0FFH ; AH = -1 (disk changed) if new density works. + XOR DL,DDBIT ;Flip density bit. + LOOP MEDIA3 + MOV AX,2 ;Couldn't read disk at all, AH = 0 for don't + JMP ERR_EXIT ; know if disk changed, AL = error code 2 - + +MEDIA4: MOV AH,AL ;Save disk drive number in AH. + XCHG AL,[CURDRV] ;make new drive current, AL = previous + CMP AL,AH ;Changing drives? + JZ MEDIA5 ;No, return to caller. +; +; If changing drives, unload head so the head load delay one-shot +; will fire again. Do it by seeking to same track with the H bit reset. +; + IN AL,DTRACK ;Get current track number + OUT DDATA,AL ;Make it the track to seek to + MOV AL,10H ;Seek and unload head + CALL DCOM + MOV AL,AH ;Restore current drive number +MEDIA5: RET + +; +; Short routine to send a command to 1793 diskette controller chip and +; wait for 1793 to complete the command. +; + +DCOM: OUT 41H,AL ;Send command to 1793. + MOV CX,10H +DCOM1: LOOP DCOM1 ;Wait a short time for 1793 to digest it. + +DCOM2: IN AL,41H ;Get 1793's status. + AND AL,1 ;See if busy. + JNZ DCOM2 ;Yes, keep checking. + IN AL,41H ;Get 1793's status for return + RET + + PAGE + SUBTTL Build and return Bios Parameter Block for a diskette. + +; +; Build Bios Parameter Blocks. +; +; On entry: ES:DI contains the address of a scratch sector buffer. +; AL = Unit number. +; AH = Current media byte. +; +; On exit: Return a DWORD pointer to the associated BPB +; in the Request packet. +; + +BPBS STRUC + DB 13 DUP(?) ;Static request header. +BPB1 DB ? ;Media byte. +BPB2 DW ? ;DWORD transfer address. + DW ? +BPB3 DW ? ;DWORD pointer to BPB + DW ? +BPBS ENDS + +GET_BPB: + PUSH ES + PUSH DI + MOV [IOPB.DMASEG],ES + MOV [IOPB.DMAOFF],DI + MOV BYTE PTR[IOPB.SECTOR],1 + MOV BYTE PTR[IOPB.SCOUNT],1 + MOV BYTE PTR[IOPB.OPCODE],088H + MOV BYTE PTR[IOPB.RETRIES],1 + MOV BYTE PTR[IOPB.DRIVE],0 + MOV [IOPB.TRACK],0 + MOV BYTE PTR[IOPB.HEAD],1 + MOV BYTE PTR[IOPB.RETMASK],0DCH + MOV [IOPB.SECLENG],128 + MOV BX,ROM_DISKIO + MOV CX,OFFSET IOPB + PUSH CS + POP ES + CALL ROM_CALL ;Read sector zero for information. + PUSH CS + POP DS + POP DI + POP ES + MOV AH,[IOPB.RETCODE] + OR AH,AH + JNZ GET_BP3 ;Disk error, assume old single density. + +GET_BP1:MOV AL,ES:[DI.MEDIAID] ;Get diskettes media ID. + MOV SI,OFFSET LSDRIV2 + CMP AL,[SI.MEDIAID] + JZ GET_BP4 + MOV SI,OFFSET LDDRIV1 + CMP AL,[SI.MEDIAID] + JZ GET_BP4 + MOV SI,OFFSET LDDRIV2 + CMP AL,[SI.MEDIAID] + JZ GET_BP4 + +GET_BP3:MOV SI,OFFSET LSDRIV1 ;No compares, assume old style for now. + +GET_BP4:MOV AL,[SI.MEDIAID] + ADD SI,11 ;Convert to DPB pointer + +GET_BP5:LDS BX,[PTRSAV] ;Update I/O data packet. + MOV [BX.BPB1],AL ;Media byte. + MOV [BX.BPB3],SI ;DPB pointer. + MOV [BX.BPB3+2],CS ;Code segment. + OR AH,AH + JNZ GET_BP6 + MOV AL,0 + JMP EXIT +GET_BP6:MOV AX,7 + JMP ERR_EXIT + + PAGE + + SUBTTL Disk I/O equates. + +; Floppy drives + +; -------------------------- +; Hardware command def. +; -------------------------- +; +; Read command = 88 hex. +; Write command = A8 hex. +; Format command = F0 hex. +; Seek command = 1E hex. +; Recal command = 0A hex. +; Set DD mode = 80 hex. +; +; -------------------------- +; Status bits: +; -------------------------- +; +; Busy = 01 hex. +; (not used) = 02 hex. +; TK0(seek) = 04 hex. +; Lost Data = 04 hex. +; CRC error = 08 hex. +; Seek error = 10 hex. +; Not found = 10 hex. +; Write fault = 20 hex. +; Write protect = 40 hex. +; Not ready = 80 hex. +; +; -------------------------- + +F_READ EQU 088H ;Floppy read command. +F_WRIT EQU 0A8H ;Floppy write command. +F_FMT EQU 0F0H ;Floppy format command. +F_SEEK EQU 01EH ;Floppy seek command. +F_RECAL EQU 00AH ;Floppy recal. command. +F_DD EQU 080H ;Set Drive double density bit. + + PAGE + SUBTTL MSDOS 2.x Disk I/O drivers. + +; +; Disk READ/WRITE functions. +; +; On entry: +; AL = Disk I/O driver number +; AH = Media byte. +; ES = Disk transfer segment. +; DI = Disk transfer offset in ES. +; CX = Number of sectors to transfer +; DX = Logical starting sector. +; +; On exit: +; Normal exit through common exit routine. +; +; Abnormal exit through common error routine. +; + +DSK_RED: + MOV BX,0DC88H ;Set read mode and Error mask. + JMP SHORT DSK_COM +DSK_WRV: +DSK_WRT:MOV BX,0FCA8H ;Set write mode and Error mask. + +DSK_COM:MOV SI,OFFSET LSDRIV1 + CMP AH,[SI.MEDIAID] + JE DSK_CO3 + MOV SI,OFFSET LSDRIV2 + CMP AH,[SI.MEDIAID] + JE DSK_CO3 + MOV SI,OFFSET LDDRIV1 + CMP AH,[SI.MEDIAID] + JE DSK_CO2 + MOV SI,OFFSET LDDRIV2 + CMP AH,[SI.MEDIAID] + JE DSK_CO2 + MOV AL,7 + JMP ERR_EXIT + +DSK_CO2:OR AL,F_DD ;Set double density mode. + +DSK_CO3:MOV [IOPB.DMASEG],ES ;Setup Buffer segment. + MOV [IOPB.DMAOFF],DI ;Setup buffer offset. + MOV DI,[SI.SECSIZE] ;Get sector size. + MOV [IOPB.SECLENG],DI + MOV [IOPB.RETRIES],1 ;Setup number of retries. + MOV [IOPB.RETMASK],BH ;Operation error mask. + MOV [IOPB.OPCODE],BL ;R/W opcode. + MOV [IOPB.DRIVE],AL ;Drive with density select. + MOV [IOPB.HEAD],1 ;Only one head on floppy drive. + MOV BP,CX ;Save number of sectors to R/W +DSK_CO4:PUSH DX ;Save starting sector. + MOV AX,DX + MOV DX,0 ;32 bit divide coming up. + MOV CX,[SI.SECTRK] + DIV CX ;Get track+head and start sector. + INC DL + MOV [IOPB.SECTOR],DL ;Starting sector. + MOV BL,DL ;Save starting sector for later. + MOV [IOPB.TRACK],AX ;Track to read/write. + MOV AX,[SI.SECTRK] ;Now see how many sectors + INC AL ; we can burst read. + SUB AL,BL ;BL is the starting sector. + MOV AH,0 + POP DX ;Retrieve logical sector start. + CMP AX,BP ;See if on last partial track+head. + JG DSK_CO5 ;Yes, on last track+head. + SUB BP,AX ;No, update number of sectors left. + ADD DX,AX ;Update next starting sector. + JMP SHORT DSK_CO6 +DSK_CO5:MOV AX,BP ;Only read enough of sector + MOV BP,0 ;to finish buffer and clear # left. +DSK_CO6:MOV [IOPB.SCOUNT],AL + MOV DI,AX ;Save number sectors for later. + MOV BX,ROM_DISKIO + MOV CX,OFFSET IOPB + PUSH CS + POP ES + CALL ROM_CALL ;Do disk operation. + MOV AL,[IOPB.RETCODE] ;Get error code. + OR AL,AL + JNZ DERROR + MOV AX,DI ;Retrieve number of sectors read. + MOV CX,[SI.SECSIZE] ;Number of bytes per sector. + PUSH DX + MUL CX + POP DX + TEST AL,0FH ;Make sure no strange sizes. + JNZ DSK_CO7 ;Illegal sector size found. + MOV CL,4 + SHR AX,CL ;Convert number of bytes to para. + ADD AX,[IOPB.DMASEG] + MOV [IOPB.DMASEG],AX + OR BP,BP + JNZ DSK_CO4 ;Still more to do. + MOV AL,0 + JMP EXIT ;All done. +DSK_CO7:MOV AL,12 + JMP ERR_EXIT + + PAGE + SUBTTL Disk Error processing. + +; +; Disk error routine. +; + +DERROR: LDS BX,CS:[PTRSAV] + MOV [BX.COUNT],0 + PUSH CS + POP DS + + MOV BL,-1 + MOV AH,AL + MOV BH,14 ;Lenght of table. + MOV SI,OFFSET DERRTAB +DERROR2:INC BL ;Increment to next error code. + LODS BYTE PTR CS:[SI] + CMP AH,AL ;See if error code matches disk status. + JZ DERROR3 ;Got the right error, exit. + DEC BH + JNZ DERROR2 ;Keep checking table. + MOV BL,12 ;Set general type of error. +DERROR3:MOV AL,BL ;Now we've got the code. + RET + +DERRTAB DB 40H ; 0. Write protect error + DB 00H ; 1. Unknown unit. + DB 80H ; 2. Not ready error. + DB 0FFH ; 3. Unknown command. + DB 08H ; 4. CRC error + DB 00H ; 5. Bad drive request. + DB 02H ; 6. Seek error + DB 00H ; 7. Unknown media. + DB 10H ; 8. Sector not found + DB 00H ; 9. (Not used.) + DB 20H ;10. Write fault. + DB 04H ;11. Read fault. + DB 07H ;12. General type of failure. + + PAGE + SUBTTL Common ROM call routine. + +; +; Save all registers except CX, BX and AX. + +ROMRTN DD 0FE000000H ;Main ROM entry point. + +ROM_CALL: + PUSH DI + PUSH SI + PUSH BP + PUSH DX + PUSH ES + CALL CS:DWORD PTR [ROMRTN] + POP ES + POP DX + POP BP + POP SI + POP DI + RET + + PAGE + SUBTTL Initalization code and temporary work areas. + +; +; Overlayed by MSDOS by SYSINIT. +; + +WRKSTK LABEL WORD + DB 100 DUP (?) + + +HWINIT: XOR BP,BP + MOV SS,BP + MOV SP,OFFSET WRKSTK+98 ;Some nice area for stack. + + PUSH CS + POP ES + + MOV BX,ROM_INIT + CALL ROM_CALL + MOV AH,0 + MOV MCON,AX + + MOV AX,SEG SYSINIT + MOV DS,AX + +ASSUME DS:SEG SYSINIT + + MOV AX,CS + ADD AX,BIOSIZS + MOV DS:[CURRENT_DOS_LOCATION],AX + MOV DS:[MEMORY_SIZE],MAX_MEM + MOV AX,CS + MOV WORD PTR DS:[DEVICE_LIST+2],AX + MOV WORD PTR DS:[DEVICE_LIST],OFFSET DEVSTART + MOV AX,CS + ADD AX,((OFFSET WRKSTK - OFFSET INIT)+50) /16 + MOV DS:[FINAL_DOS_LOCATION],AX + JMP SYSINIT + +DOSSPOT LABEL WORD + +CODE ENDS + + END + \ No newline at end of file diff --git a/v2.0/source/SORT.ASM b/v2.0/source/SORT.ASM new file mode 100644 index 0000000..a4f39e8 --- /dev/null +++ b/v2.0/source/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/v2.0/source/SORTMES.ASM b/v2.0/source/SORTMES.ASM new file mode 100644 index 0000000..4fb6556 Binary files /dev/null and b/v2.0/source/SORTMES.ASM differ diff --git a/v2.0/source/STDBUF.ASM b/v2.0/source/STDBUF.ASM new file mode 100644 index 0000000..400280a Binary files /dev/null and b/v2.0/source/STDBUF.ASM differ diff --git a/v2.0/source/STDCALL.ASM b/v2.0/source/STDCALL.ASM new file mode 100644 index 0000000..5d9d926 Binary files /dev/null and b/v2.0/source/STDCALL.ASM differ diff --git a/v2.0/source/STDCTRLC.ASM b/v2.0/source/STDCTRLC.ASM new file mode 100644 index 0000000..a02d90d Binary files /dev/null and b/v2.0/source/STDCTRLC.ASM differ diff --git a/v2.0/source/STDFCB.ASM b/v2.0/source/STDFCB.ASM new file mode 100644 index 0000000..17cf4e9 --- /dev/null +++ b/v2.0/source/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/v2.0/source/STDIO.ASM b/v2.0/source/STDIO.ASM new file mode 100644 index 0000000..c14c98a --- /dev/null +++ b/v2.0/source/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/v2.0/source/STDPROC.ASM b/v2.0/source/STDPROC.ASM new file mode 100644 index 0000000..3d44849 --- /dev/null +++ b/v2.0/source/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/v2.0/source/STDSW.ASM b/v2.0/source/STDSW.ASM new file mode 100644 index 0000000..30a8a16 --- /dev/null +++ b/v2.0/source/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/v2.0/source/STRIN.ASM b/v2.0/source/STRIN.ASM new file mode 100644 index 0000000..2bc58fb --- /dev/null +++ b/v2.0/source/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/v2.0/source/SYS.ASM b/v2.0/source/SYS.ASM new file mode 100644 index 0000000..e15758e --- /dev/null +++ b/v2.0/source/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/v2.0/source/SYSCALL.ASM b/v2.0/source/SYSCALL.ASM new file mode 100644 index 0000000..02d38d8 --- /dev/null +++ b/v2.0/source/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/v2.0/source/SYSCALL.txt b/v2.0/source/SYSCALL.txt new file mode 100644 index 0000000..26d4729 --- /dev/null +++ b/v2.0/source/SYSCALL.txt @@ -0,0 +1,1657 @@ + + + + + + + + + + + + + + + + + + + MS-DOS 2.0 + + System Calls Reference + + + + + + + + + + + + ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| | +| 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 | +| | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + + + + + + + + + + + + + + + + + + Section 1 + + Extensions to existing call structure + + + Name: * Alloc - allocate memory + + Assembler usage: + MOV BX,size + MOV AH,Alloc + INT 21h + ; AX:0 is pointer to allocated memory + ; if alloc fails, BX is the largest block available + + 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 + The largest available free block is smaller + than that requested or there is no free block. + = error_arena_trashed + The internal consistency of the memory arena + has been destroyed. This is due to a user + program changing memory that does not belong + to it. + + + Name: * CharOper - change incompatible configuration + parameters + + Assembler usage: + MOV AH, CharOper + MOV AL, func + MOV DL, data + INT 21h + ; on read functions, data is returned in DL + + Description: + CharOper allows a program to change system + parameters to allow for switch indicators and whether + devices are available at every level of the directory + tree. + + A function code is passed in AL: + + AL Function + -- -------- + 0 DL, on return, will contain the DOS switch + character. On most systems this will default to + '-'. + 1 Set the switch character to the character in DL. + 2 Read the device availability byte into DL. If + this byte is 0, then devices must be accessed in + file I/O calls by /dev/device. If this byte is + non-zero, then the devices are available at every + node of the directory tree (i.e. CON is the + console device not the file CON). This byte is + generally 0. + 3 Set the device availability byte to the value in + DL. + + Error returns: + AL = FF + The function code specified in AL is not in + the range 0:3 + + + Name: * CurrentDir - return text of current directory + + Assembler usage: + MOV AH,CurrentDir + LDS SI,area + MOV DL,drive + INT 21h + ; DS:SI is a pointer to 64 byte area that contains + ; drive current directory. + + Description: + CurrentDir returns the current directory for a + particular drive. The directory is root-relative and + does not contain the drive specifier. The drive code + passed in DL is 0=default, 1=A, 2=B, etc. + + Error returns: + AX = error_invalid_drive + The drive specified in DL was invalid. + + + Name: * Dealloc - free allocated memory + + Assembler usage: + MOV ES,block + MOV AH,dealloc + INT 21h + + Description: + Dealloc returns a piece of memory to the system + pool that was allocated by alloc. + + Error return: + AX = error_invalid_block + The block passed in ES is not one allocated + via Alloc. + = error_arena_trashed + The internal consistency of the memory arena + has been destroyed. This is due to a user + program changing memory that does not belong + to it. + + + Name: * FileTimes - get/set the write times of a + handle + + 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. + + Description: + FileTimes returns or sets the last-write time for + a handle. These times are not recorded until the file + is closed. + + A function code is passed in AL: + + AL Function + -- -------- + 0 Return the time/date of the handle in CX/DX + 1 Set the time/date of the handle to CX/DX + + Error returns: + AX = error_invalid_function + The function passed in AL was not in the range + 0:1. + = error_invalid_handle + The handle passed in BX was not currently + open. + + + Name: * FindFirst - find matching file + + Assembler usage: + MOV AH, FindFirst + LDS DX, pathname + MOV CX, attr + INT 21h + ; DMA address has datablock + + Description: + FindFirst takes a pathname with wildcards in the + last component (passed in DS:DX), a set of attributes + (passed in CX) and attempts to find all files that + match the pathname and have a subset of the required + attributes. A datablock at the current DMA is written + that contains information in the following form: + + find_buf STRUC ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| C A V E A T P R O G R A M M E R | +| | + find_buf_sattr DB ? ; attribute of search + find_buf_drive DB ? ; drive of search + find_buf_name DB 11 DUP (?); search 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 + + To obtain the subsequent matches of the pathname, + see the description of FindNext + + Error Returns: + AX = error_file_not_found + The path specified in DS:DX was an invalid + path. + = error_no_more_files + There were no files matching this + specification. + + + Name: * FindNext - step through a directory matching + files + + Assembler usage: + ; DMA points at area returned by find_first + MOV AH, findnext + INT 21h + ; next entry is at dma + + Description: + FindNext finds the next matching entry in a + directory. The current DMA address must point at a + block returned by FindFirst (see FindFirst). + + Error Returns: + AX = error_no_more_files + There are no more files matching this pattern. + + + Name: * GetDMA - get current DMA transfer address + + Assembler usage: + MOV AH,GetDMA + INT 21h + ; ES:BX has current DMA transfer address + + Description: + Return DMA transfer address. + + Error returns: + None. + ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| C A V E A T P R O G R A M M E R | +| | + + Name: * GetDSKPT(DL) - get pointer to drive parameter + block + + Assembler usage: + MOV AH,GetDSKPT + INT 21h + ; DS:BX has address of drive parameter block + + Description: + Return pointer to default drive parameter block. + + Error returns: + None. + + Assembler usage: + MOV DL,DrvNUM + MOV AH,GetDSKPTDL + INT 21h + ; DS:BX has address of drive parameter block + + Description: + Return pointer to drive parameter block for drive + designated in DL (0=Default, A=1, B=2 ...) + + Error returns: + AL = FF + The drive given in DL is invalid. +| | +| C A V E A T P R O G R A M M E R | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + + Name: * GetFreespace - get Disk free space + + Assembler usage: + MOV AH,GetFreespace + MOV DL,Drive ;0 = default, A = 1 + INT 21h + ; BX = Number of free allocation units on drive + ; DX = Total number of allocation units on drive + ; CX = Bytes per sector + ; AX = Sectors per allocation unit + + Description: + Return Free space on disk along with additional + information about the disk. + + Error returns: + AX = FFFF + The drive number given in DL was invalid. + + NOTE: This call returns the same information in the same + registers (except for the FAT pointer) as the get FAT + pointer calls did in previous versions of the DOS. + + + Name: * GetInDOSF - get DOS critical-section flag + + Assembler usage: + MOV AH,GetInDOSF + INT 21h + ; ES:BX has location of the flag + MOV CritSEG, ES + MOV CritOFF, BX + ... + IntVec: + MOV AX, DWORD PTR Crit + CMP AX,0 + JZ DoFunc + IRET + DoFunc: ... + + Description: + Return location of indos flag. On return ES:BX is + the address of a byte memory cell inside the DOS. If + used in an interrupt service routine, it indicates + whether or not the DOS was interrupted in a critical + section. If the cell was zero, then the DOS was not + in a critical section and thus can be called by the + interrupt routine. If the cell was non-zero, the DOS + should be considered to be in an uninterruptable state + and for reliability, no DOS calls should be given. + + Error returns: + None. + + + Name: * GetVector - get interrupt vector + + Assembler usage: + MOV AH,GetVector + MOV AL,interrupt + INT 21h + ; ES:BX now has long pointer to interrupt routine + + Description: + Return interrupt vector associated with an + interrupt. + + Error returns: + None. + + + Name: * GetVerifyFlag - return current setting of the + verify after write flag. + + Assembler usage: + MOV AH,GetVerifyFlag + INT 21h + ; AL is the current verify flag value + + Description: + The current value of the verify flag is returned + in AL. + + Error returns: + None. + + + Name: * GetVersion - get DOS version number + + Assembler usage: + MOV AH,GetVersion + INT 21h + ; AL is the major version number + ; AH is the minor version number + ; BH is the OEM number + ; BL:CX is the (24 bit) user number + + Description: + Return MS-DOS version number. On return AL.AH + will be the two part version designation, ie. for + MS-DOS 1.28 AL would be 1 and AH would be 28. For pre + 1.28 DOS AL = 0. Note that version 1.1 is the same as + 1.10, not the same as 1.01. + + Error returns: + None. + + + Name: * International - return country dependent + information + + Assembler usage: + LDS DX, blk + MOV AH, International + MOV AL, func + INT 21h + + Description: + This call returns in the block of memory pointed + to by DS:DX, the following information pertinent to + international applications: + + +---------------------------+ + | WORD Date/time format | + +---------------------------+ + | BYTE ASCIZ string | + | currency symbol | + +---------------------------+ + | BYTE ASCIZ string | + | thousands separator | + +---------------------------+ + | BYTE ASCIZ string decimal | + | separator | + +---------------------------+ + + The date/time format has the following values and + meanings: + + 0 - USA standard h:m:s m/d/y + 1 - Europe standard h:m:s d/m/y + 2 - Japan standard y/m/d h:m:s + + The value passed in AL is either 0 (for current + country) or a country code (to be defined later. + Currently the country code must be zero). + + Error returns: + AX = error_invalid_function + The function passed in AL was not 0 + (currently). + + + Name: * KeepProcess - terminate process and remain + resident + + Assembler usage: + MOV AL, exitcode + MOV DX, parasize + MOV AH, KeepProcess + INT 21h + + Description: + This call terminates the current process and + attempts to set the initial allocation block to a + specific size in paragraphs. It will not free up any + other allocation blocks belonging to that process. + The exit code passed in AX is retrievable by the + parent via Wait. + + Error Returns: + None. + + + Name: * Rename - move a directory entry + + Assembler usage: + LDS DX, source + LES DI, dest + MOV AH, Rename + INT 21h + + Description: + Rename will attempt to rename a file into another + path. The paths must be on the same device. + + Error returns: + AX = error_file_not_found + The file name specifed by DS:DX was not found. + = error_not_same_device + The source and destination are on different + drives. + = error_access_denied + The path specified in DS:DX was a directory or + the file specified by ES:DI exists or the + destination directory entry could not be + created. + + + Name: * SetBlock - modify allocated blocks + + 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 + + Description: + Setblock will attempt to grow/shrink an allocated + block of memory. + + Error return: + AX = error_invalid_block + The block passed in ES is not one allocated + via Alloc. + = error_arena_trashed + The internal consistency of the memory arena + has been destroyed. This is due to a user + program changing memory that does not belong + to it. + = error_not_enough_memory + There was not enough free memory after the + specified block to satisfy the grow request. + + + Name: * SetCtrlCTrapping - turn on/off broad ^C + checking + + Assembler usage: + MOV DL,val + MOV AH,SetCtrlCTrapping + MOV AL,func + INT 21h + ; If AL was 0, then DL has the current value of the + ; ^C check + + Description: + MSDOS ordinarily checks for a ^C on the + controlling device only when doing a function 1-12 + operation to that device. SetCtrlCTrapping allows the + user to expand this checking to include any system + call. For example, with the ^C trapping off, all disk + I/O will proceed without interruption while with ^C + trapping on, the ^C interrupt is given at the system + call that initiates the disk operation. + + Error return: + AL = FF + The function passed in AL was not in the range + 0:1. + ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| C A V E A T P R O G R A M M E R | +| | + + Name: * Set_OEM_Handler - set handler for OEM + specific INT 21H calls. + + Assembler usage: + LDS DX,handler_address + MOV AH,Set_OEM_Handler + INT 21H + + Description: + Set handler address for 0F9H-0FFH INT 21H system + calls to DS:DX. To return the 0F9H-0FFH calls to + the uninitialized state, give DS=DX=-1. + + Error returns: + None. + + Handler entry: + All registers as user set them when INT 21H + issued (including SS:SP). INT 21 return is on + stack, so the correct method for the OEM handler + to return to the user is to give an IRET. The + OEM handler is free to make any INT 21H system + call (including the 0F9H- 0FFH group if the OEM + handler is re-entrant). + + + The AH INT 21H function codes 0F8H through 0FFH are + reserved for OEM extensions to the INT 21H calling + convention. These calls have two states, initialized + and uninitialized. There will be one handler for all 7 + (0F9-0FFH) functions. When the DOS is first + initialized, these calls are uninitialized. The AH=0F8H + call is the call which will set the handler address for + the 0F9-0FFH calls. If the 0F9-0FFH calls are + uninitialized, an attempt to call them results in the + normal invalid system call number return. + OEMs should NOT document the 0F8 call. +| | +| C A V E A T P R O G R A M M E R | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + + + + + + + + + + + + + + + + + + Section 2 + + XENIX-compatible system calls + + + + Previous to version 2.0, MSDOS had a simple single + directory structure that sufficed for small (160k to 320K) + diskettes. As the need for hard disk support grows, and + as MSDOS 2.0 will support a wide variety of hard disks, + the need for better disk organization also grows. Merely + expanding the directory is not an effective solution; + doing a 'DIR' on a directory with 1000 files is not a + user-friendly characteristic. + + People, by nature, think in hierarchical terms: + organization charts and family trees, for example. It + would be nice to allow users to organize their files on + disk in a similar manner. Consider the following: + + In a particular business, both sales and accounting + share a computer with a large disk and the individual + employees use it for preparation of reports and + maintaining accounting information. One would naturally + view the organization of files on the disk in this + fashion: + + +-disk-+ + / \ + / \ + / \ + sales accounting + / | | \ + / | | \ + / | | \ + John Mary Steve Sue + / | (A) | | | \ + / | | | | \ + / | | | | \ + report accts. report accts. report report + receiv. receiv + + In MSDOS 2.0 the user can arrange his files in such a + manner that files that are not part of his current task do + not interfere with that task. Pre-2.0 versions of MSDOS + has a single directory that contains files. MSDOS extends + this concept to allow a directory to contain both files + and directories and to introduce the notion of the + 'current' directory. + + To specify a filename, the user could use one of two + methods, either specify a path from the root node to the + file, or specify a path from the current node to the file. + A path is a series of directory names separated by '/' and + ending with a filename. A path that starts at the root + begins with a '/'. + + There is a special directory entry in each directory, + denoted by '..' that is the parent of the directory. The + root directory's parent is itself (who created God?). + + Using a directory structure like the hierarchy above, + and assuming that the current directory is at point (D), + to reference the report under John, the following are all + equivalent: + + report + /sales/John/report + ../John/report + + To refer to the report under Mary, the following are + all equivalent: + + ../Mary/report + /sales/Mary/report + + To refer to the report under Sue, the following are + all equivalent. + + ../../accounting/Sue/report + /accounting/Sue/report + + There is no restriction in MSDOS 2.0 on the depth of a + tree (the length of the longest path from root to leaf) + except in the number of allocation units available. The + root directory will have a fixed number of entries, 64 for + the single sided diskettes to XXX for a large hard disk. + For non-root directories, there is no limit to the number + of files per directory excepting in the number of + allocation units available. + + Old (pre-2.0) disks will appear to MSDOS 2.0 as having + only a root directory with files in it and no + subdirectories whatever. + + Implementation of the tree-structure is simple. The + root directory is the pre-2.0 directory. Subdirectories + of the root have a special attribute set indicating that + they are directories. The subdirectories themselves are + files, linked through the FAT as usual. Their contents + are identical in character to the contents of the root + directory. + + Pre-2.0 programs that use system calls not described + below will not be able to make use of files in other + directories. They will only be able to access files in + the current directory. This is no great loss of + functionality as users will aggregate their files into + sub-directories on basis of functionality; the files that + are being used will be found in the current directory. + Those that are not necessary for the current task will be + placed in other directories. Out of sight, out of mind. + + There are also new attributes in 2.0. These and the + old attributes apply to the tree structured directories in + the following manner: + + Attribute Meaning/Function Meaning/Function + for files for directories + + volume_id Present at the root. Meaningless. + Only one file may have + this set. + + directory Meaningless. Indicates that the + directory entry is a + directory. Cannot be + changed with ChMod. + + read_only Old fcb-create, new Meaningless. + Creat, new open (for + write or read/write) + will fail. + + archive Set when file is Meaningless. + written. Set/reset via + ChMod. + + hidden/ Prevents file from Prevents directory + system being found in search entry from being + first/search next. found. ChDir to + New open will fail. directory will still + work. + + + Name: * ChDir - Change the current directory + + Assembler usage: + LDS DX, name + MOV AH, ChDir + INT 21h + + Description: + ChDir is given the ASCIZ name of the directory + which is to become the current directory. If any + member of the specified pathname does not exist, then + the current directory is unchanged. Otherwise, the + current directory is set to the string. + + Error returns: + AX = error_path_not_found + The path specified in DS:DX either indicated a + file or the path was invalid. + + + Name: * ChMod - change write protection + + Assembler usage: + LDS DX, name + MOV CX, attribute + MOV AL, func + MOV AH, ChMod + INT 21h + + Description: + Given an ASCIZ name, ChMod will set/get the + attributes of the file to those given in CX. + + A function code is passed in AL: + + AL Function + -- -------- + 0 Return the attributes of the file in CX + 1 Set the attributes of the file to those in CX + + Error returns: + AX = error_path_not_found + The path specified was invalid. + = error_access_denied + The attributes specified in CX contained one + that could not be changed (directory, volume + ID). + = error_invalid_function + The function passed in AL was not in the range + 0:1. + + + Name: * Close - close a file handle + + Assembler usage: + MOV BX, handle + MOV AH, Close + INT 21h + + Description: + In BX is passed a file handle (like that returned + by Open, Creat or Dup); the Close call will close the + associated file. Internal buffers are flushed. + + Error return: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + + + Name: * Creat - create a file + + Assembler usage: + LDS DX, name + MOV AH, Creat + MOV CX, attribute + INT 21h + ; AX now has the handle + + Description: + Creat creates a new file or truncates an old file + to zero length in preparation for writing. If the + file did not exist, then the file is created in the + appropriate directory and the file is given the + read/write protection code of access. + + CX contains the default attributes to be set for + the file. Currently, the read-only bit must be off. + + Error returns: + AX = error_access_denied + The attributes specified in CX contained one + that could not be created (directory, volume + ID), a file already existed with a more + inclusive set of attributes, or a directory + existed with the same name. + = error_path_not_found + The path specified was invalid. + = error_too_many_open_files + The file was created with the specified + attributes, but there were no free handles + available for the process or that the internal + system tables were full. + + + Name: * Dup - duplicate a file handle + + Assembler usage: + MOV BX, fh + MOV AH, Dup + INT 21h + ; AX has the returned handle + + Description: + Dup takes an already opened file handle and + returns a new handle that refers to the same file at + the same position. + + Error returns: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + = error_too_many_open_files + There were no free handles available in the + current process or the internal system tables + were full. + + + Name: * Dup2 - force a duplicate of a handle + + Assembler usage: + MOV BX, fh + MOV CX, newfh + MOV AH, Dup2 + INT 21h + + Description: + Dup2 will cause newfh to refer to the same stream + as fh. If there was an open file on newfh, then it is + closed first. + + Error returns: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + + + Name: * Exec - load / execute a program + + Assembler usage: + LDS DX, name + LES BX, blk + MOV AH, Exec + MOV AL, func + INT 21h + + Description: + This call allows a program to load another program + into memory and (default) begin execution of it. + DS:DX points to the ASCIZ name of the file to be + loaded. ES:BX points to a parameter block for the + load. + + A function code is passed in AL: + + AL Function + -- -------- + 0 Load and execute the program. A program header is + established for the program and the terminate and + ^C addresses are set to the instruction after the + EXEC system call. + + NOTE: When control is returned, via a ^C or + terminate, from the program being EXECed ALL + registers are altered including the stack. + This is because control is returned from the + EXECed program, not the system. To regain + your stack, store an SS:SP value in a data + location reachable from your CS. + ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| C A V E A T P R O G R A M M E R | +| | + 1 Load, create the program header but do not begin + execution. The CS:IP/SS:SP of the program are + returned in the area provided by the user. +| | +| C A V E A T P R O G R A M M E R | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + 3 Load, do not create the program header, and do not + begin execution. This is useful in loading + program overlays. + + For each value of AL, the block has the following + format: + + AL = 0 -> load/execute program + + +---------------------------+ + | WORD segment address of | + | environment. | + +---------------------------+ + | DWORD pointer to command | + | line at 80h | + +---------------------------+ + | DWORD pointer to default | + | FCB to be passed at 5Ch | + +---------------------------+ + | DWORD pointer to default | + | FCB to be passed at 6Ch | + +---------------------------+ + ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| C A V E A T P R O G R A M M E R | +| | + AL = 1 -> load program + + +---------------------------+ + | WORD segment address of | + | environment. | + +---------------------------+ + | DWORD pointer to 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 | + | SS:SP | + +---------------------------+ + | DWORD returned value of | + | CS:IP | + +---------------------------+ +| | +| C A V E A T P R O G R A M M E R | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + AL = 3 -> load overlay + + +---------------------------+ + | WORD segment address where| + | file will be loaded. | + +---------------------------+ + | WORD relocation factor to | + | be applied to the image. | + +---------------------------+ + + Note that all open files of a process are + duplicated in the child process after an Exec. This + is extremely powerful; the parent process has control + over the meanings of stdin, stdout, stderr, stdaux and + stdprn. The parent could, for example, write a series + of records to a file, open the file as standard input, + open a listing file as standard output and then Exec a + sort program that takes its input from stdin and + writes to stdout. + + Also inherited (or passed from the parent) is an + 'environment'. This is a block of text strings (less + than 32K bytes total) that convey various + configurations parameters. The format of the + environment is as follows: + + (paragraph boundary) + +---------------------------+ + | BYTE asciz string 1 | + +---------------------------+ + | BYTE asciz string 2 | + +---------------------------+ + | ... | + +---------------------------+ + | BYTE asciz string n | + +---------------------------+ + | BYTE of zero | + +---------------------------+ + + Typically the environment strings have the form: + + parameter=value + + for example, COMMAND.COM always passes its execution + search path as: + + PATH=A:/BIN;B:/BASIC/LIB + + A zero value of the environment address will cause the + child process to inherit the parent's environment + unchanged. + + Note that on a successful return from EXEC, all + registers, except for CS:IP, are changed. + + Error return: + AX = error_invalid_function + The function passed in AL was not 0, 1 or 3. + = error_bad_environment + The environment was larger than 32Kb. + = error_bad_format + The file pointed to by DS:DX was an EXE format + file and contained information that was + internally inconsistent. + = error_not_enough_memory + There was not enough memory for the process to + be created. + = error_file_not_found + The path specified was invalid or not found. + + + Name: * Exit - terminate a process + + Assembler usage: + MOV AL, code + MOV AH, Exit + INT 21h + + Description: + Exit will terminate the current process, + transferring control to the invoking process. In + addition, a return code may be sent. All files open + at the time are closed. + + Error returns: + None. + + + Name: * Ioctl - I/O control for devices + + Assembler usage: + MOV BX, Handle + + (or MOV BL, drive for calls AL=4,5 + 0=default,A=1...) + + MOV DX, Data + + (or LDS DX, buf and + MOV CX, count for calls AL=2,3,4,5) + + MOV AH, Ioctl + MOV AL, func + INT 21h + ; For calls AL=2,3,4,5 AX is the number of bytes + ; transferred (same as READ and WRITE). + ; For calls AL=6,7 AL is status returned, AL=0 if + ; status is not ready, AL=0FFH otherwise. + + Description: + Set or Get device information associated with open + Handle, or send/receive control string to device + Handle or device. + + The following values are allowed for func: + + Request Function + ------ -------- + 0 Get device information (returned in DX) + 1 Set device information (as determined by DX) + 2 Read CX number of bytes into DS:DX from device + control channel. + 3 Write CX number of bytes from DS:DX to device + control channel. + 4 Same as 2 only drive number in BL + 0=default,A=1,B=2,... + 5 Same as 3 only drive number in BL + 0=default,A=1,B=2,... + 6 Get input status + 7 Get output status + + Ioctl can be used to get information about device + channels. It is ok to make Ioctl calls on regular + files but only calls 0,6 and 7 are defined in that + case (AL=0,6,7), all other calls return an + error_invalid_function error. + + CALLS AL=0 and AL=1 + + The bits of DX are defined as follows for calls + AL=0 and AL=1. Note that the upper byte MUST be zero + on a set call. + + | + 15 14 13 12 11 10 9 8|7 6 5 4 3 2 1 0 + +--+--+--+--+--+--+-+-+-+-+-+-+-+-+-+-+ + | R| C| |I|E|R|S|I|I|I|I| + | e| T| |S|O|A|P|S|S|S|S| + | s| R| Reserved |D|F|W|E|C|N|C|C| + | | L| |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 (Bits 8-15 = + 0 in this case) + + 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 + SPECL = 1 if this device is special + + CTRL = 0 if this device can NOT do control strings + via calls AL=2 and AL=3. + CTRL = 1 if this device can process control + strings via calls AL=2 and AL=3. + NOTE that this bit cannot be set. + + 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, ...) + + Bits 15,8-13,4 are reserved and should not be altered. + + Calls 2..5: + These four calls allow arbitrary control strings to be + sent or received from a device. The Call syntax is + the same as the READ and WRITE calls, except for 4 and + 5 which take a drive number in BL instead of a handle + in BX. + + An error_invalid_function error is returned if the + CTRL bit (see above) is 0. + + An error_access_denied is returned by calls AL=4,5 if + the drive number is invalid. + + Calls 6,7: + These two calls allow the user to check if a file + handle is ready for input or output. Status of + handles open to a device is the intended use of these + calls, but status of a handle open to a disk file is + OK and is defined as follows: + + Input: + Always ready (AL=FF) until EOF reached, then + always not ready (AL=0) unless current + position changed via LSEEK. + Output: + Always ready (even if disk full). + + IMPORTANT NOTE: + The status is defined at the time the system is + CALLED. On future versions, by the time control is + returned to the user from the system, the status + returned may NOT correctly reflect the true current + state of the device or file. + + Error returns: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + = error_invalid_function + The function passed in AL was not in the range + 0:7. + = error_invalid_data + = error_access_denied (calls AL=4..7) + + + Name: * LSeek - move file read/write pointer + + Assembler usage: + MOV DX, offsetlow + MOV CX, offsethigh + MOV AL, method + MOV BX, handle + MOV AH, LSeek + INT 21h + ; DX:AX has the new location of the pointer + + Description: + LSeek moves the read/write pointer according to + method: + + Method Function + ------ -------- + 0 The pointer is moved to offset bytes from the + beginning of the file. + 1 The pointer is moved to the current location + plus offset. + 2 The pointer is moved to the end of file plus + offset. + + Offset should be regarded as a 32-bit integer with + CX occupying the most significant 16 bits. + + Error returns: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + = error_invalid_function + The function passed in AL was not in the range + 0:2. + + + Name: * MkDir - Create a directory entry + + Assembler usage: + LDS DX, name + MOV AH, MkDir + INT 21h + + Description: + Given a pointer to an ASCIZ name, create a new + directory entry at the end. + + Error returns: + AX = error_path_not_found + The path specified was invalid or not found. + = error_access_denied + The directory could not be created (no room in + parent directory), the directory/file already + existed or a device name was specified. + + + Name: * Open - access a file + + Assembler usage: + LDS DX, name + MOV AH, Open + MOV AL, access + INT 21h + ; AX has error or file handle + ; If successful open + + Description: + Open associates a 16-bit file handle with a file. + + The following values are allowed for access: + + ACCESS Function + ------ -------- + 0 file is opened for reading + 1 file is opened for writing + 2 file is opened for both reading and writing. + + DS:DX point to an ASCIZ name of the file to be + opened. + + The read/write pointer is set at the first byte of + the file and the record size of the file is 1 byte. + The returned file handle must be used for subsequent + I/O to the file. + + The DOS, on initialization, will have a maximum + number of files. See the configuration file document + for information on changing this default. + + Error returns: + AX = error_invalid_access + The access specified in AL was not in the + range 0:2. + = error_file_not_found + The path specified was invalid or not found. + = error_access_denied + The user attempted to open a directory or + volume-id, or open a read-only file for + writing. + = error_too_many_open_files + There were no free handles available in the + current process or the internal system tables + were full. + + + Name: * Read - Do file/device I/O + + Assembler usage: + LDS DX, buf + MOV CX, count + MOV BX, handle + MOV AH, Read + INT 21h + ; AX has number of bytes read + + Description: + Read transfers count bytes from a file into a + buffer location. It is not guaranteed that all count + bytes will be read; for example, reading from the + keyboard will read at most one line of text. If the + returned value is zero, then the program has tried to + read from the end of file. + + All I/O is done using normalized pointers; no + segment wraparound will occur. + + Error returns: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + = error_access_denied + The handle passed in BX was opened in a mode + that did not allow reading. + + + Name: * RmDir - Remove a directory entry + + Assembler usage: + LDS DX, name + MOV AH, RmDir + INT 21h + + Description: + RmDir is given an asciz name of a directory. That + directory is removed from its parent + + Error returns: + AX = error_path_not_found + The path specified was invalid or not found. + = error_access_denied + The path specified was not empty, not a + directory, the root directory or contained + invalid information. + = error_current_directory + The path specified was the current directory + on a drive. + + + Name: * Unlink - delete a directory entry + + Assembler usage: + LDS DX, name + MOV AH, Unlink + INT 21h + + Description: + Unlink removes a directory entry associated with a + filename. If the file is currently open on another + handle, then no removal will take place. + + Error returns: + AX = error_file_not_found + The path specified was invalid or not found. + = error_access_denied + The path specified was a directory or + read-only. + + + Name: * Wait - retrieve the return code of a child + + Assembler usage: + MOV AH, Wait + INT 21h + ; AX has the exit code + + Description: + Wait will return the Exit code specified by a + child process. It will return this Exit code only + once. The low byte of this code is that sent by the + Exit routine. The high byte is one of the following: + + 0 - terminate/abort + 1 - ^C + 2 - Hard error + 3 - Terminate and stay resident + + Error returns: + None. + + + Name: * Write - write to a file + + Assembler usage: + LDS DX, buf + MOV CX, count + MOV BX, handle + MOV AH, Write + INT 21h + ; AX has number of bytes written + + Description: + Write transfers count bytes from a buffer into + a file. It should be regarded as an error if the + number of bytes written is not the same as the number + requested. + + It is important to note that the write system + call with a count of zero (CX = 0) will truncate + the file at the current position. + + All I/O is done using normalized pointers; no + segment wraparound will occur. + + Error Returns: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + = error_access_denied + The handle was not opened in a mode that + allowed writing. + + +The following XENIX convention is followed for the new 2.0 +system calls: + + o If no error occurred, then the carry flag will be + reset and register AX will contain the appropriate + information. + + o If an error occurred, then the carry flag will be + set and register AX will contain the error code. + +The following code sample illustrates the recommended method +of detecting these errors: + + ... + MOV errno,0 + INT 21h + JNC continue + MOV errno,AX +continue: + ... + +The word variable errno will now have the correct error code +for that system call. + +The current equates for the error codes are: + +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 +error_invalid_drive EQU 15 +error_current_directory EQU 16 +error_not_same_device EQU 17 +error_no_more_files EQU 18 + + +System call assignments: + +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 +; XENIX CALLS +; 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 + \ No newline at end of file diff --git a/v2.0/source/SYSIMES.ASM b/v2.0/source/SYSIMES.ASM new file mode 100644 index 0000000..1ff4f0d Binary files /dev/null and b/v2.0/source/SYSIMES.ASM differ diff --git a/v2.0/source/SYSINIT.ASM b/v2.0/source/SYSINIT.ASM new file mode 100644 index 0000000..0c198b1 --- /dev/null +++ b/v2.0/source/SYSINIT.ASM @@ -0,0 +1,1424 @@ +TITLE BIOS SYSTEM INITIALIZATION + +FALSE EQU 0 +TRUE EQU NOT FALSE + +IBMVER EQU FALSE +IBM EQU IBMVER +IBMJAPVER EQU FALSE ; If TRUE set KANJI true also +MSVER EQU TRUE +ALTVECT EQU FALSE ; Switch to build ALTVECT version +HIGHMEM EQU FALSE +KANJI EQU FALSE + + IF IBMVER OR IBMJAPVER +NOEXEC EQU TRUE + ELSE +NOEXEC EQU FALSE + ENDIF + +; Set to agree with those in DOST:MSHEAD.ASM, ALTVECT version only +MAJOR_VERSION EQU 2 +MINOR_VERSION EQU 0B ;2.11 + +DOSSIZE EQU 5000H + +; Internal DOS data returned by DOSINIT + +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 ? ; Head of buffer queue +DEVHEAD DD ? +SYSINITVAR ENDS + + INCLUDE DOSSYM.ASM + INCLUDE DEVSYM.ASM + + IF NOT IBM + IF NOT IBMJAPVER + EXTRN RE_INIT:FAR + ENDIF + ENDIF + +SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' + +ASSUME CS:SYSINITSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING + + EXTRN BADOPM:BYTE,CRLFM:BYTE,BADCOM:BYTE + EXTRN BADSIZ_PRE:BYTE,BADLD_PRE:BYTE + EXTRN BADSIZ_POST:BYTE,BADLD_POST:BYTE + EXTRN SYSSIZE:BYTE,BADCOUNTRY:BYTE + + PUBLIC CURRENT_DOS_LOCATION + PUBLIC FINAL_DOS_LOCATION + PUBLIC DEVICE_LIST + PUBLIC MEMORY_SIZE + PUBLIC DEFAULT_DRIVE + PUBLIC BUFFERS + PUBLIC FILES + PUBLIC SYSINIT + + IF HIGHMEM + PUBLIC DPBBUF_SIZ + ENDIF + +SYSINIT: + JMP GOINIT + +DOSINFO LABEL DWORD + DW 0000 +CURRENT_DOS_LOCATION DW 0000 + +MSDOS LABEL DWORD +ENTRY_POINT LABEL DWORD + DW 0000 +FINAL_DOS_LOCATION DW 0000 +DEVICE_LIST DD 00000000 + + IF HIGHMEM +DPBBUF_SIZ DW (4472 + 15) / 16 + ENDIF + +MEMORY_SIZE DW 0001 +DEFAULT_DRIVE DB 00 +BUFFERS DB 2 +FILES DB 8 +COMMAND_LINE DB 2,0,"P" ; Default Command.com Args + DB 29 DUP (0) +ZERO DB 0 + + IF NOT NOEXEC +COMEXE EXEC0 <0,COMMAND_LINE,DEFAULT_DRIVE,ZERO> + 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/v2.0/source/SYSINIT.txt b/v2.0/source/SYSINIT.txt new file mode 100644 index 0000000..fa20d08 Binary files /dev/null and b/v2.0/source/SYSINIT.txt differ diff --git a/v2.0/source/SYSMES.ASM b/v2.0/source/SYSMES.ASM new file mode 100644 index 0000000..c7dea6d --- /dev/null +++ b/v2.0/source/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/v2.0/source/TCODE.ASM b/v2.0/source/TCODE.ASM new file mode 100644 index 0000000..dfe6ca5 --- /dev/null +++ b/v2.0/source/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/v2.0/source/TCODE2.ASM b/v2.0/source/TCODE2.ASM new file mode 100644 index 0000000..bc2742d --- /dev/null +++ b/v2.0/source/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/v2.0/source/TCODE3.ASM b/v2.0/source/TCODE3.ASM new file mode 100644 index 0000000..547c937 --- /dev/null +++ b/v2.0/source/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/v2.0/source/TCODE4.ASM b/v2.0/source/TCODE4.ASM new file mode 100644 index 0000000..a8c44a6 --- /dev/null +++ b/v2.0/source/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/v2.0/source/TCODE5.ASM b/v2.0/source/TCODE5.ASM new file mode 100644 index 0000000..63fb3cf --- /dev/null +++ b/v2.0/source/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/v2.0/source/TDATA.ASM b/v2.0/source/TDATA.ASM new file mode 100644 index 0000000..9a4af2e --- /dev/null +++ b/v2.0/source/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/v2.0/source/TIME.ASM b/v2.0/source/TIME.ASM new file mode 100644 index 0000000..f1e4a1c Binary files /dev/null and b/v2.0/source/TIME.ASM differ diff --git a/v2.0/source/TSPC.ASM b/v2.0/source/TSPC.ASM new file mode 100644 index 0000000..85f02e7 Binary files /dev/null and b/v2.0/source/TSPC.ASM differ diff --git a/v2.0/source/TUCODE.ASM b/v2.0/source/TUCODE.ASM new file mode 100644 index 0000000..1a69b77 Binary files /dev/null and b/v2.0/source/TUCODE.ASM differ diff --git a/v2.0/source/UINIT.ASM b/v2.0/source/UINIT.ASM new file mode 100644 index 0000000..2e6bc77 Binary files /dev/null and b/v2.0/source/UINIT.ASM differ diff --git a/v2.0/source/UTILITY.txt b/v2.0/source/UTILITY.txt new file mode 100644 index 0000000..a63793c --- /dev/null +++ b/v2.0/source/UTILITY.txt @@ -0,0 +1,813 @@ + + + + + + + + + + + + + + + + + + + MS-DOS 2.0 + + Utility Extensions + + + + + + + + + The following notation is used below: + + [item] item is optional. + item* item is repeated 0 or more times. + item+ item is repeated 1 or more times. + {item1 | item2} + item1 is present or item 2 is present but + not both. + indicates a syntactic variable. + + +COMMAND invokation + +COMMAND [[:]] [] [-D] [-P] [-C ] + + -P If present COMMAND will be permanent, otherwise + this is a transient command. + + -D If present COMMAND will not prompt for DATE and + TIME when it comes up. + + d: Specifies device where command will look for + COMMAND.COM current default drive if absent. + + Specifies a directory on device d: root + directory if absent. + + Name of the CTTY device. /DEV/CON if absent + and command is permanent. The /DEV/ may be left + off if AVAILDEV is TRUE (see sysinit doc). + + -C If present -C must be the last switch. + This causes COMMAND to try to execute the string + as if the user had typed it at the standard input. + COMMAND executes this single command string and + then exits. If the -P switch is present it is + ignored (can't have a single command, permanent + COMMAND). NOTE: ALL of the text on the command + line after the -C is just passed on. It is not + processed for more arguments, this is why -C must + be last. + +COMMAND extensions + +IF + + where is one of the following: + + ERRORLEVEL + true if and only if the previous program EXECed by + COMMAND had an exit code of or higher. + + == + true if and only if and are + identical after parameter substitution. Strings + may not have embedded delimiters. + + EXIST + true if and only if exists. + + NOT + true if and only if is false. + + The IF statement allows conditional execution of commands. + When the is true, then the is + executed otherwise, the is skipped. + + Examples: + + IF not exist /tmp/foo ECHO Can't find file /tmp/foo + + IF $1x == x ECHO Need at least one parameter + + IF NOT ERRORLEVEL 3 LINK $1,,; + + +FOR %% IN DO + + can be any character but 0,1,2,3,..,9 (so there is no + confusion with the %0 - %9 batch parameters). + + is ( * ) + + The %% variable is sequentially set to each member of + and then is evaluated. If a member of + is an expression involving * and/or ?, then the + variable is set to each matching pattern from disk. In + this case only one such may be in the set, any + s after the first are ignored. + + Example: + + FOR %%f IN ( *.ASM ) DO MASM %%f; + + for %%f in (FOO BAR BLECH) do REM %%f to you + + NOTE: The '%%' is needed so that after Batch parameter + (%0 - %9) processing is done, there is one '%' left. + If only '%f' were there, the batch parameter processor + would see the '%' then look at 'f', decide that '%f' + was an error (bad parameter reference) and throw out + the '%f' so that FOR would never see it. If the FOR + is NOT in a batch file, then only ONE '%' should be + used. + + +SHIFT + + Currently, command files are limited to handling 10 + parameters: %0 through %9. To allow access to more than + these, the command SHIFT will perform a 'pop' of the + command line parameters: + + if %0 = "foo" + %1 = "bar" + %2 = "blech" + %3...%9 are empty + + then a SHIFT will result in the following: + + %0 = "bar" + %1 = "blech" + %2...%9 are empty + + If there are more than 10 parameters given on a command + line, then the those that appear after the 10th (%9) will + be shifted one at a time into %9 by successive shifts. + +: