; ; 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