;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