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