;************************************************ ;* * ;* FILE PRINT UTILITY * ;* * ;************************************************ ; ; By Bill Bolton ; Software Tools ; P.O. Box 80 ; Newport Beach ; NSW, 2016 ; AUSTRALIA ; ; CP/M-86 History (most recent version at top) ; ; Version 1.0 Adapted from PAGE utility ; 4/Mar/82 ; TITLE 'PRINT utility for CP/M-86' PAGEWIDTH 132 EJECT ;************************************************ ;* * ;* MISCELLANEOUS EQUATES * ;* * ;************************************************ TFCB EQU 005CH ;TRANSIENT PROGRAM FCB TBUF EQU 0080H ;TRANSIENT PROGRAM BUFFER OPEN EQU 15 ;OPEN FUNCTION CODE READ EQU 20 ;READ FUNCTION CODE BS EQU 08H ;ASCII Back Space TAB EQU 09H ;ASCII TAB LF EQU 0AH ;ASCII Line Feed FORMF EQU 0CH ;ASCII Form Feed CR EQU 0DH ;ASCII Carriage Return SPACE EQU 20H ;ASCII Blank FILLER EQU 00H ;USED AS FF NULL PAGSZ EQU 66 ;LINES/PAGE MAXLN EQU 58 ;USABLE LINES/PAGE NULLS EQU 1 ;NULLS AFTER A FORM FEED ODEV EQU 5 ;CON:=2 LST:=5 M EQU Byte Ptr 0[BX] ;Handy for ASM86 EJECT CSEG ;************************************************ ;* * ;* GET PARAMETERS FROM COMMAND LINE * ;* * ;************************************************ PRINT: MOV BX,TBUF ;POINT TO BUFFER MOV CH,M ;GET COUNT OF CHARACTERS IN CMD MOV AL,M ;GET COUNT AGAIN OR AL,AL ;TEST FOR ZERO JNZ L_1 JMP PERR ;YES, NO ARGUMENTS L_1: INC BX ;SKIP COUNT SKP1: MOV AL,M ;GET BYTE CMP AL,' ' ;SPACE? JNZ SKP2 ;NO INC BX ;BUMP POINTER DEC CH ;DECRMENT COUNT JNZ SKP1 ;SKIP TO FIRST NON-SPACE JMPS PERR ;NO, NON SPACE AFTER FILE ID SKP2: MOV AL,M ;GET CHAR CMP AL,' ' ;SPACE? JZ SKP3 ;YES INC BX ;BUMP POINTER DEC CH ;DECREMENT COUNT JNZ SKP2 ;SKIP TO SPACE JMP PEND ;NO SPACE AFTER FILE ID SKP3: MOV AL,M ;GET CHAR CMP AL,' ' ;TEST FOR NON,SPACE JNZ SKP4 ;FOUND ARGUMENTS INC BX ;BUMP POINTER DEC CH ;DECREMENT COUNT JNZ SKP3 JMP PEND SKP4: MOV DX,(Offset PARMS) SKP4A: MOV AL,M MOV SI,DX MOV [SI],AL INC BX INC DX DEC CH JNZ SKP4A MOV AL,' ' MOV SI,DX ;INDICATE END OF PARMS MOV [SI],AL ;************************************************ ;* * ;* PROCESS PARAMETERS * ;* * ;************************************************ PPARM: MOV DX,(Offset PARMS) ;POINT TO PARMS AREA PLP0: MOV BX,(Offset PTAB) ;POINT TO PARM TABLE MOV CH,(Offset PTABS) ;SIZE OF PARM TABLE PLP1: MOV SI,DX ;GET PARM BYTE MOV AL,[SI] CMP AL,' ' ;END OF PARMS? JZ PEND ;YES, DONE CMP AL,00 ;END OF PARMS? JZ PEND ;YES, DONE CMP AL,M ;COMPARE TO TABLE ENTRY JZ PFND ;FOUND IT INC BX ;BUMP PARM TABLE PTR INC BX INC BX DEC CH ;DECREMENT COUNT JNZ PLP1 ;KEEP LOOKING PERR: MOV DX,(Offset PERMSG) ;POINT TO PARM ERROR MSG MOV CL,09 ;WRITE MSG INT 224 MOV CL,0 ;EXIT MOV DL,0 INT 224 PFND: INC BX ;POINT TO ROUTINE ADDR PUSH DX ;SAVE PARM POINTER MOV DL,M INC BX MOV DH,M ;GET ROUTINE ADDR MOV BX,(Offset PRET) ;RETURN ADDRESS PUSH BX ;SIMULATE CALL XCHG BX,DX ;GET ROUTINE ADDR JMP BX ;EXIT TO PARM PROC. ROUTINE PRET: POP DX ;GET PARM POINTER AGAIN INC DX ;POINT TO NEXT ONE JMPS PLP0 ;CONTINUE ; ;************************************************ ;* * ;* PARAMETER PROCESSING ROUTINES * ;* * ;************************************************ NPARM: MOV AL,0FFH ;SET 'NO HEADING' SWITCH MOV Byte Ptr NSWT,AL RET ; CPARM: MOV AL,0FFH ;SET 'NO PAGINATION' SWITCH MOV Byte Ptr CSWT,AL RET ;************************************************ ;* * ;* OPEN FILE FOR INPUT * ;* * ;************************************************ PEND: MOV DX,TFCB ;POINT TO FCB CALL FOPEN ;OPEN FILE JNB L_2 JMP ERR ;IF ERROR, EXIT L_2: CALL HEAD ;PRINT HEADING ;**************************************** ;* * ;* MAIN PROCESSING LOOP * ;* * ;**************************************** LOOP: CALL GETBT ;GET A BYTE JNB L_3 JMP ERR ;ERROR L_3: CMP AL,1AH ;EOF? JZ DONE ;YES CMP AL,CR ;CR? JZ CRET ;YES CMP AL,LF ;LF? JZ LFEED ;YES CMP AL,TAB ;TAB? JZ TABMOV ;YES CMP AL,FORMF ;FORM FEED? JZ FFEED ;YES CMP AL,BS ;BACKSPACE JZ BSPACE ;YES CMP AL,SPACE ;ODD CONTROL CHR? JB LOOP ;YES, IGNORE IT CALL PBYT ;OTHERWISE PRINT IT JMPS LOOP ;CONTINUE ;************************************************ ;* * ;* FINAL PROCESSING * ;* * ;************************************************ DONE: CALL TPAGE ;MOVE TO TOP OF PAGE MOV CL,0 ;EXIT TO BDOS MOV DL,0 INT 224 ;************************************************ ;* * ;* PROCESS TABS * ;* * ;************************************************ TABMOV: MOV BX,(Offset COL) ;POINT TO COLUMN TBLP: MOV AL,SPACE ;PRINT ONE SPACE CALL PBYT MOV AL,M ;GET COLUMN AND AL,07H ;MODULO 8 JNZ TBLP ;IF NOT AT TAB STOP, KEEP TYPING JMPS LOOP CALL PBYT ;PRINT BYTE JMPS LOOP ;************************************************ ;* * ;* PROCESS * ;* * ;************************************************ CRET: XOR AL,AL MOV Byte Ptr COL,AL MOV AL,CR CALL PBYT ;PRINT JMPS LOOP ;CONTINUE IN MAIN LOOP ;************************************************ ;* * ;* PROCESS * ;* * ;************************************************ LFEED: MOV AL,Byte Ptr CSWT ;GET PAGINATION SWITCH OR AL,AL ;SEE IF 'NO PAGINATION' JNZ LFEED2 ;TRUE, SKIP PAGINATION TEST MOV AL,Byte Ptr LINE ;GET LINE COUNT CMP AL,MAXLN ;PAGE OVERFLOW? JZ FFEED ;YES LFEED2: MOV AL,Byte Ptr LINE ;GET LINE COUNT INC AL ;BUMP LINE COUNT MOV Byte Ptr LINE,AL MOV AL,LF CALL PBYT JMP LOOP ;**************************************** ;* * ;* PROCESS * ;* * ;**************************************** BSPACE: MOV AL,BS CALL PBYT MOV AL,Byte Ptr COL ;GET COLUMN COUNTER OR AL,AL ;IF ZERO, DONT DECREMENT IT JNZ L_4 JMP LOOP L_4: DEC AL MOV Byte Ptr COL,AL ;DECREMENT COLUMN COUNT JMP LOOP ;************************************************ ;* * ;* PROCESS FORM FEED * ;* * ;************************************************ FFEED: MOV AL,CR CALL PBYT ;PRINT CR CALL TPAGE ;POSITION AT TOP OF PAGE CALL HEAD ;PRINT HEADING JMP LOOP ;CONTINUE IN MAIN LOOP ;************************************************ ;* * ;* HEADING PRINT ROUTINE * ;* * ;************************************************ HEAD: MOV AL,Byte Ptr NSWT ;NO HEADING SWITCH OR AL,AL ;IF SET, NO HEADING JNZ HEADA MOV BX,(Offset FMSG) ;POINT TO MESSAGE CALL PSTRNG ;PRINT STRING MOV BX,TFCB+1 ;POINT TO NAME MOV CH,8 ;SIZE OF NAME CALL PCNT ;PRINT COUNT MOV AL,SPACE ;PRINT A SPACE CALL PBYT MOV BX,TFCB+9 ;POINT TO TYPE MOV CH,03 ;SIZE OF TYPE CALL PCNT ;PRINT COUNT MOV BX,(Offset PMSG) ;POINT TO MESSAGE CALL PSTRNG ;PRINT STRING MOV AL,Byte Ptr PAGEN ;GET PAGE NUMBER INC AL ;BUMP IT MOV Byte Ptr PAGEN,AL ;SAVE IT CALL DEC ;CONVERT TO DECIMAL MOV BX,(Offset DECWRK) ;POINT TO DEC STRING MOV CH,3 CALL PCNT ;PRINT PAGE NUMBER MOV AL,CR ;PRINT CR CALL PBYT MOV AL,LF CALL PBYT ;PRINT LF MOV AL,LF CALL PBYT ;AND SECOND MOV AL,LF CALL PBYT ;AND A THIRD MOV AL,3 ;SET NUMBER OF LINES PRINTED JMPS HEADB HEADA: XOR AL,AL HEADB: MOV Byte Ptr LINE,AL ;RESET LINE COUNT XOR AL,AL ;RESET COLUMN MOV Byte Ptr COL,AL ;RESET COLUMN RET ;************************************************ ;* * ;* CHARACTER PRINT ROUTINE * ;* * ;************************************************ PBYT: PUSH BX PUSH CX PUSH AX MOV DL,AL MOV CL,ODEV INT 224 ;PRINT POP AX CMP AL,SPACE ;NON-PRINTING? JB PBY2 ;YES, DONT BUMP COL MOV BX,(Offset COL) ;INCREMENT COLUMN INC M PBY2: MOV CL,11 ;GET CONSOLE STATUS INT 224 CMP AL,00 ;BREAK? JZ L_5 MOV CL,0 ;YES, DONE MOV DL,0 INT 224 L_5: POP CX POP BX RET ;************************************************ ;* * ;* STRING PRINT ROUTINE * ;* * ;************************************************ PSTRNG: MOV AL,M ;GET BYTE CMP AL,'$' ;STRING END? JNZ L_6 RET ;YES, DONE L_6: CALL PBYT ;PRINT BYTE INC BX ;BUMP POINTER JMPS PSTRNG ;LOOP ;************************************************ ;* * ;* STRING PRINT ROUTINE (COUNT IN B) * ;* * ;************************************************ PCNT: MOV AL,M ;GET BYTE CALL PBYT ;PRINT IT INC BX ;BUMP POINTER DEC CH ;DECREMENT COUNT JNZ PCNT RET ;************************************************ ;* * ;* DECIMAL OUTPUT ROUTINE * ;* * ;************************************************ DEC: MOV BX,(Offset DECWRK) MOV CL,100 CALL DIGIT MOV CL,10 CALL DIGIT MOV CL,1 CALL DIGIT RET DIGIT: MOV M,'0' DI0: SUB AL,CL JS DI1 INC M JMPS DI0 DI1: ADD AL,CL LAHF INC BX SAHF RET ;************************************************ ;* * ;* TOP OF PAGE ROUTINE * ;* * ;************************************************ TPAGE: MOV AL,FORMF ;ISSUE FORM FEED CALL PBYT MOV CH,NULLS ;NUMBER OF NULLS TPAGE2: MOV AL,FILLER CALL PBYT DEC CH ;PRINT N FILLERS JNZ TPAGE2 RET ;************************************************ ;* * ;* I/O ERROR MESSAGE ROUTINE * ;* * ;************************************************ ERR: MOV DX,(Offset ERMSG) MOV CL,09H ;WRITE MSG INT 224 MOV CL,0 MOV DL,0 INT 224 ;************************************************ ;* * ;* F O P E N * ;* ROUTINE TO OPEN A DISK FILE * ;* * ;* INPUT: DX= pointer to FCB * ;* OUTPUT: CARRY=ERROR * ;* * ;************************************************ FOPEN: MOV CL,OPEN ;OPEN CODE INT 224 ;ISSUE OPEN CMP AL,0FFH ;ERROR? JZ FOERR ;YES XOR AL,AL ;CLEAR CARRY RET FOERR: STC RET ;******************************************************** ;* * ;* G E T B T * ;* ROUTINE TO READ A BYTE * ;* * ;* OUTPUTS: AL = BYTE * ;* CARRY = ERROR * ;* * ;******************************************************** GETBT: MOV BX,TBUF+128 XCHG BX,DX ;BUFFER END ADDR. IN DE MOV BX,Word Ptr INPTR ;CURRENT POINTER IN HL CMP BX,DX ;TEST FOR END OF BUFFER JZ GETB2 ;YES, READ GETB1: MOV AL,M ;GET BYTE INC BX ;BUMP POINTER INC Word Ptr INPTR ;BUMP POINTER OR AL,AL ;RESET CARRY RET GETB2: MOV CL,READ ;READ CODE MOV DX,TFCB ;FCB ADDRESS INT 224 ;ISSUE READ CMP AL,00 ;ERROR? JNZ IERR ;YES MOV BX,TBUF ;RESET BUFFER POINTER MOV Word Ptr INPTR,BX JMPS GETB1 ;CONTINUE IERR: STC RET EJECT ;************************************************ ;* * ;* D A T A * ;* * ;************************************************ L_8 EQU $ DSEG ORG Offset L_8 DB 'PRINT.CMD - File PRINT Utility, CP/M-86 Version 1.0, ' DB '(C) Copyright March 1982, ' DB 'By Bill Bolton, Software Tools, Sydney, Australia' NSWT DB 0 ;NO HEADING SWITCH CSWT DB 0 ;NO PAGINATION SWITCH INPTR DW TBUF+128 ;INPUT POINTER DECWRK DB '000' ;DECIMAL WORK AREA COL DB 0 ;COLUMN COUNTER LINE DB 0 ;LINE COUNTER PAGEN DB 0 ;PAGE COUNTER FMSG DB CR,'FILE: $' PMSG DB ' PAGE $' PERMSG DB 'PARAMETER ERROR',CR,LF,'$' ERMSG DB 'ERROR',CR,LF,'$' PARMS RS 16 ;PARAMETER STORAGE AREA ;************************************************ ;* * ;* PARAMETER PROCESSING TABLE * ;* * ;* ENTRIES ARE 3 BYTES WIDE * ;* * ;* BYTE 1 = PARAMETER BYTE * ;* * ;* BYTES 2,3 = ROUTINE ADDRESS * ;* * ;************************************************ PTAB DB 'N' DW (Offset NPARM) DB 'C' DW (Offset CPARM) PTABS EQU ((Offset $)-(Offset PTAB))/3 END