2025-04-27 07:49:33 -04:00

1362 lines
65 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;/*
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1988 - 1991
; * All Rights Reserved.
; */
;************************************************************
;**
;** NAME: Support for HP PCL printers added to GRAPHICS.
;**
;** DESCRIPTION: I modified the procedures STORE_BOX, PRINT_BUFFER,
;** GET_SCREEN_INFO, DET_CUR_SCAN_LNE_LENGTH, and NEW_PRT_LINE
;** as follows.
;**
;** For STORE_BOX:
;** if data_type = data_row, then store printbox in print buffer
;** in row format - not column format.
;**
;** For PRINT_BUFFER:
;** if data_type = data_row, then print one byte at a time.
;**
;** For GET_SCREEN_INFO:
;** if data_type = data_row
;** nb_boxes_per_prt_buf = 8/box_height
;** if print_options = rotate
;** nb_scan_lines = screen_width
;** else
;** nb_scan_lines = screen_height
;** endif
;** endif
;**
;** For DET_CUR_SCAN_LNE_LENGTH:
;** if data_type = data_row
;** don't go down the columns to determine the scan_line_length
;** endif
;**
;** For NEW_PRT_LINE:
;** Altered it so send escape number sequence, COUNT or LOWCOUNT and
;** HIGHCOUNT, if they are specified before the new keyword DATA.
;**
;**
;** I added the the procedures END_PRT_LINE and GET_COUNT, which
;** are described below.
;**
;** END_PRT_LINE sends escape number sequence, COUNT or LOWCOUNT and
;** HIGHCOUNT, if they are specified after the new keyword DATA
;** in the GRAPHICS statement of the profile. It also sends a
;** CR & LF for IBM type printers if needed.
;**
;** GET_COUNT gets the number of bytes that are going to be sent to the
;** printer and converts the number to ASCII if DATA_TYPE = DATA_ROW.
;**
;** BUG NOTES: The following bug was fixed for the pre-release
;** version Q.01.02.
;**
;** BUG (mda003)
;** ------------
;**
;** NAME: GRAPHICS prints a CR & LF after each scan line unless it is
;** loaded twice.
;**
;** FILES & PROCEDURES AFFECTED: GRLOAD3.ASM - PARSE_GRAPHICS
;** GRCOMMON.ASM - END_PRT_LINE
;** GRSHAR.STR - N/A
;**
;** CAUSES: The local variables LOWCOUNT_FOUND, HIGHCOUNT_FOUND CR_FOUND and
;** LF_FOUND used for loading, were incorrectly being used as global
;** variables during printing.
;**
;** FIX: Created a new variable Printer_Needs_CR_LF in GRSHAR.STR, which
;** is used to determine in GRCOMMON.ASM if it's necessary to
;** manually send a CR & LF to the printer at print time. The
;** variable is set at load time in GRLOAD3.ASM, if the variables
;** Data_Found and Build_State are set.
;**
;** DOCUMENTATION NOTES: This version of GRCOMMON.ASM differs from the previous
;** version only in terms of documentation.
;**
;************************************************************
PAGE ,132 ;AN000;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;AN000;
;; DOS - GRAPHICS Command
;;
;; ;AN000;
;; File Name: GRCOMMON.ASM ;AN000;
;; ---------- ;AN000;
;; ;AN000;
;; Description: ;AN000;
;; ------------ ;AN000;
;; ;AN000;
;; This file contains the modules common to the Print Screen ;AN000;
;; process of GRAPHICS.COM. ;AN000;
;; This file is included by both set of Print modules. ;AN000;
;; ;AN000;
;; This file MUST BE COMPILED WITH EACH SET OF MODULES since, ;AN000;
;; one set is relocated in memory at installation time; all ;AN000;
;; references to the common procedures must be resolved from ;AN000;
;; within each set of print modules. ;AN000;
;; ;AN000;
;; The set of common modules is relocated in memory along with ;AN000;
;; the selected set of print modules. ;AN000;
;; ;AN000;
;; Documentation Reference: ;AN000;
;; ------------------------ ;AN000;
;; OASIS High Level Design ;AN000;
;; OASIS GRAPHICS I1 Overview ;AN000;
;; ;AN000;
;; Procedures Contained in This File: ;AN000;
;; ---------------------------------- ;AN000;
;; READ_DOT ;AN000;
;; LOC_MODE_PRT_INFO ;AN000;
;; STORE_BOX ;AN000;
;; PRINT_BUFFER ;AN000;
;; GET_SCREEN_INFO ;AN000;
;; SETUP_PRT ;AN000;
;; RESTORE_PRT ;AN000;
;; NEW_PRT_LINE ;AN000;
;; PRINT_BYTE ;AN000;
;; DET_CUR_SCAN_LNE_LENGTH ;AN000;
; \/ ~~mda(001) -----------------------------------------------------------------------
;; Added the following procedures to support printers with horizontal
;; printer heads, such as an HP PCL printers.
;; GET_COUNT
;; END_PRT_LINE
; /\ ~~mda(001) -----------------------------------------------------------------------
;; ;AN000;
;; Include Files Required: ;AN000;
;; ----------------------- ;AN000;
;; ;AN000;
;; External Procedure References: ;AN000;
;; ------------------------------ ;AN000;
;; FROM FILE GRCTRL.ASM: ;AN000;
;; PRT_SCR - Main module for printing the screen. ;AN000;
;; FROM FILE GRBWPRT.ASM: ;AN000;
;; PRT_BW_APA - Main module for printing on BW printer. ;AN000;
;; FROM FILE GRCOLPRT.ASM: ;AN000;
;; PRINT_COLOR - Main module for printing on COLOR printer. ;AN000;
;; ;AN000;
;; Linkage Instructions: ;AN000;
;; -------------------- ;AN000;
;; ;AN000;
;; This file is included by both GRBWPRT.ASM and GRCOLPRT.ASM and is ;AN000;
;; compiled with each of them. However, only one copy is made resident. ;AN000;
;; ;AN000;
;; Change History: ;AN000;
;; --------------- ;AN000;
;; ;AN000;
;; ;AN000;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;AN000;
;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; LOC_MODE_PRT_INFO: LOCATE DISPLAYMODE PRINTER INFO. FOR THE CURRENT ;AN000;
; MODE ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: BP = Offset of the shared data area ;AN000;
; CUR_MODE = Current video mode ;AN000;
; ;AN000;
; OUTPUT: CUR_MODE_PTR = Absolute Offset of the ;AN000;
; current DISPLAYMODE INFO record. ;AN000;
; ;AN000;
; ERROR_CODE = DISPLAYMODE_INFO_NOT_FOUND if not found. ;AN000;
; ;AN000;
; CALLED BY: PRINT_COLOR ;AN000;
; PRINT_BW_APA ;AN000;
; ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: DISPLAYMODE_PTR is pointing to the first DISPLAYMODE ;AN000;
; INFO record within the Shared Data Area. ;AN000;
; ;AN000;
; This (chained) list of DISPLAYMODE records is scanned until the record ;AN000;
; for the current mode is found. ;AN000;
; ;AN000;
; Note: All pointers in the DISPLAYMODE records are relative to the beginning ;AN000;
; of the shared data area. Therefore, we must add the offset of the ;AN000;
; shared data area (in BP) in order to access the data these pointers ;AN000;
; are referencing. ;AN000;
; ;AN000;
; The CUR_MODE_PTR is relative to the segment and references the ;AN000;
; DISPLAYMODE record for the video mode currently set at print screen ;AN000;
; time. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; FOUND := FALSE ;AN000;
; DO UNTIL FOUND OR END_OF_LIST ;AN000;
; Get a display mode information record ;AN000;
; IF record.DISP_MODE = CUR_MODE ;AN000;
; THEN FOUND := TRUE ;AN000;
; ELSE ;AN000;
; CUR_MODE_PTR := record.NEXT_DISP_MODE ;AN000;
; ;AN000;
; ;AN000;
;AN000;
LOC_MODE_PRT_INFO PROC NEAR ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
PUSH DX ;AN000;
PUSH SI ;AN000;
;AN000;
MOV BX,DS:[BP].DISPLAYMODE_PTR ; [BX] := Current DISPLAYMODE ;AN000;
ADD BX,BP ; record ;AN000;
MOV DL,CUR_MODE ; DL := Current mode ;AN000;
;AN000;
SCAN_1_DISPLAYMODE_RECORD: ;AN000;
MOV SI,[BX].DISP_MODE_LIST_PTR ; [SI] : First mode covered ;AN000;
ADD SI,BP ; by this DISPLAYMODE record ;AN000;
MOV CL,[BX].NUM_DISP_MODE ; Scan each mode in the list ;AN000;
XOR CH,CH ;AN000;
SCAN_LIST_OF_MODES: ;AN000;
CMP CS:[SI],DL ; FOUND ? ;AN000;
JE FOUND ;AN000;
INC SI ; NO, get next mode in ;AN000;
LOOP SCAN_LIST_OF_MODES ; DISPLAYMODE record ;AN000;
;AN000;
CMP [BX].NEXT_DISP_MODE,-1 ; END OF DISPLAYMODE LIST ? ;AN000;
JE NOT_FOUND ; Yes, this mode not supported ;AN000;
NEXT_RECORD: ; No, ;AN000;
MOV BX,[BX].NEXT_DISP_MODE ; [BX] := Next record ;AN000;
ADD BX,BP ; ;AN000;
JMP SHORT SCAN_1_DISPLAYMODE_RECORD ;AN000;
;AN000;
FOUND: ; Found: ;AN000;
MOV CUR_MODE_PTR,BX ; Update pointer to current ;AN000;
JMP SHORT LOC_MODE_PRT_INFO_END ; DISPLAYMODE record. ;AN000;
;AN000;
NOT_FOUND: ; Not found: ;AN000;
MOV ERROR_CODE,DISPLAYMODE_INFO_NOT_FOUND ; Return error condition ;AN000;
;AN000;
LOC_MODE_PRT_INFO_END: ;AN000;
POP SI ;AN000;
POP DX ;AN000;
POP CX ;AN000;
POP BX ;AN000;
RET ;AN000;
LOC_MODE_PRT_INFO ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; STORE_BOX : STORE ONE BOX IN THE PRINT BUFFER. ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: SI = OFFSET OF THE BOX TO BE PRINTED ;AN000;
; BOX_W = BOX WIDTH IN BITS ;AN000;
; BOX_H = BOX HEIGHT IN BITS ;AN000;
; ;AN000;
; OUTPUT: PRT_BUF = THE PRINT BUFFER ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: The print buffer is first shifted left in order to make ;AN000;
; room for the new box (Note: the MSB's are lost; they are assumed to ;AN000;
; have been printed), then the box is inserted in the low-order bits of ;AN000;
; the printer buffer. ;AN000;
; ;AN000;
PAGE ;AN000;
; EXAMPLE ;AN000;
; ------- ;AN000;
; BEFORE: AFTER: ;AN000;
; ;AN000;
; BOX: 0 0 0 ;AN000;
; 0 0 0 ;AN000;
; 0 0 0 ;AN000;
; 0 0 0 ;AN000;
; 0 0 0 ;AN000;
; 0 0 0 ;AN000;
; b1 b2 b3 ;AN000;
; b4 b5 b6 ;AN000;
; ;AN000;
; PRT_BUF: byte1 byte2 byte3 PRT_BUF: byte1 byte2 byte3 ;AN000;
; 0 1 0 1 1 1 ;AN000;
; 1 0 1 1 1 1 ;AN000;
; 1 1 1 1 1 1 ;AN000;
; 1 1 1 1 1 1 ;AN000;
; 1 1 1 1 1 1 ;AN000;
; 1 1 1 1 1 1 ;AN000;
; 1 1 1 b1 b2 b3 ;AN000;
; LSB --> 1 1 1 b4 b5 b6 ;AN000;
; ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; FOR each byte of the buffer (BOX_W) ;AN000;
; BEGIN ;AN000;
; Make room for the box to be inserted ;AN000;
; Insert the box ;AN000;
; END ;AN000;
; ;AN000;
STORE_BOX PROC NEAR ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
PUSH DI ;AN000;
;AN000;
MOV DI,OFFSET PRT_BUF ; DI := Offset of the Print buffer ;AN000;
XOR BX,BX ; BX := Byte index number ;AN000;
; \/ ~~mda(001) -----------------------------------------------------------------------
; Added the following modification to support printers with
; vertical print heads, such as HP PCL printers. The code
; as is does not work for these printers because the data
; is being stored in the print buffer with the assumption
; that the print head is vertical.
;
.IF <DS:[BP].DATA_TYPE EQ DATA_ROW>
PUSH AX ;
PUSH DX ;
PUSH BP ;
MOV CL,BOX_W ; Make room for the bits to be inserted.
SHL BYTE PTR [BX][DI],CL ;
MOV CL,DS:[BP].ROW_TO_EXTRACT ; CL determines which row we're extracting
XOR BP,BP ; Point to first column.
XOR DX,DX ; Clear counter
XOR AX,AX ; Clear register
;
EXTRACT_NEXT_BIT: ;
;
SHL AH,1 ; Make room for next bit
MOV AL,DS:[SI][BP] ; Read column
SHR AL,CL ; Get bit from row we're extracting
AND AL,1 ; Isolate bit we got from row we're extracting
OR AH,AL ; Place it in AH
INC BP ; Advance to next column
INC DL ; Inc. counter
CMP DL,BOX_W ; Check if have more bits to extract from the row
JL EXTRACT_NEXT_BIT; We do
OR DS:[DI][BX],AH ; We don't so place the row we extracted in the
; print buffer.
POP BP ;
POP DX ;
POP AX ;
.ELSE ;
; /\ ~~mda(001) -----------------------------------------------------------------------
;AN000;
MOV CL,BOX_H ; CL := Number of BITS to be shifted ;AN000;
; FOR each column (byte) of the box to be stored in the buffer: ;AN000;
STORE_1_BYTE: ;AN000;
SHL BYTE PTR [BX][DI],CL ; Make room for the bits to be inserted ;AN000;
MOV CH,[BX][SI] ; CH := column of the box to be inserted;AN000;
OR [BX][DI],CH ; Insert the box column in the buffer ;AN000;
INC BL ; Get next column (byte) of the box ;AN000;
CMP BL,BOX_W ; All columns (bytes) of box stored ? ;AN000;
JL STORE_1_BYTE ; No, store next one. ;AN000;
.ENDIF ; ~~mda(001) Close the IF stmt ;AN000;
STORE_BOX_END: ;AN000;
POP DI ;AN000;
POP CX ;AN000;
POP BX ;AN000;
RET ;AN000;
STORE_BOX ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; PRINT_BUFFER : PRINT THE BUFFER ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: PRT_BUF = BYTES TO BE PRINTED ;AN000;
; BOW_W = BOX WIDTH ;AN000;
; ;AN000;
; OUTPUT: PRINTER ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: Prints BOX_W bytes. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; DO for each column in one pattern ;AN000;
; BEGIN ;AN000;
; Print one byte from the buffer ;AN000;
; END ;AN000;
; ;AN000;
PRINT_BUFFER PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
;AN000;
MOV BX,OFFSET PRT_BUF ;AN000;
; \/ ~~mda(001) -----------------------------------------------------------------------
; If DATA_TYPE = DATA_ROW then the most we store in the print
; buffer at one time is one byte.
.IF <DS:[BP].DATA_TYPE EQ DATA_ROW> ;
MOV AL,[BX] ; Print one byte
CALL PRINT_BYTE ;
JC PRINT_BUFFER_END ; If printer error, quit the loop
.ELSE
; /\ ~~mda(001) -----------------------------------------------------------------------
XOR CX,CX ;AN000;
MOV CL,BOX_W ;AN000;
PRINT_1_BUF_COLUMN: ;AN000;
MOV AL,[BX] ; Print one byte ;AN000;
CALL PRINT_BYTE ;AN000;
JC PRINT_BUFFER_END; If printer error, quit the loop ;AN000;
INC BX ; Get next byte ;AN000;
LOOP PRINT_1_BUF_COLUMN ;AN000;
.ENDIF ;~~mda(001) close IF stmt
PRINT_BUFFER_END: ;AN000;
POP CX ;AN000;
POP BX ;AN000;
POP AX ;AN000;
RET ;AN000;
PRINT_BUFFER ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; GET_SCREEN_INFO : GET INFORMATION ABOUT HOW TO READ THE SCREEN. ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: SCREEN_HEIGHT = Number of pixel rows on the screen ;AN000;
; SCREEN_WIDTH = Number of pixel columns on screen ;AN000;
; CUR_MODE_PTR = Offset of the current DISPLAYMODE info rec. ;AN000;
; ;AN000;
; OUTPUT: PRINTER ;AN000;
; SCAN_LINE_MAX_LENGTH = Maximum length of Screen scan line. ;AN000;
; NB_SCAN_LINES = Number of SCAN LINES on the screen ;AN000;
; CUR_ROW,CUR_COLUMN = Coordinates of the first pixel to be ;AN000;
; read on the screen ;AN000;
; NB_BOXES_PER_PRT_BUF = Number of boxes fitting in the Print ;AN000;
; buffer ;AN000;
; ;AN000;
; CALLED BY: PRINT_COLOR ;AN000;
; PRT_BW_APA ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: ;AN000;
; ;AN000;
; 1) Determine where to start reading the screen. ;AN000;
; For non-rotated printing, it should start with the top-left ;AN000;
; corner pixel. ;AN000;
; For rotated printing, it should start with the low-left corner ;AN000;
; pixel. ;AN000;
; ;AN000;
; 2) Determine the length of a scan line. ;AN000;
; For non-rotated printing, it is the WIDTH of the screen. ;AN000;
; For rotated printing, it is the HEIGHT of the screen. ;AN000;
; ;AN000;
; 3) Determine the number of scan lines on the screen. ;AN000;
; For non-rotated printing, it is the HEIGHT of the screen divided ;AN000;
; by the number of boxes fitting in the print buffer. ;AN000;
; For rotated printing, it is the WIDTH of the screen divided by ;AN000;
; the number of boxes fitting in the print buffer. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; CUR_COLUMN := 0 ;AN000;
; IF printing is sideways ;AN000;
; THEN ;AN000;
; CUR_ROW := SCREEN_HEIGHT - 1 ; Low-left pixel ;AN000;
; SCAN_LINE_MAX_LENGTH := SCREEN_HEIGHT ;AN000;
; NB_SCAN_LINES := SCREEN_WIDTH / NB_BOXES_PER_PRT_BUF ;AN000;
; ELSE ;AN000;
; CUR_ROW := 0 ; Top-left pixel ;AN000;
; SCAN_LINE_MAX_LENGTH := SCREEN_WIDTH ;AN000;
; NB_SCAN_LINES := SCREEN_HEIGHT / NB_BOXES_PER_PRT_BUF ;AN000;
; ;AN000;
; ;AN000;
GET_SCREEN_INFO PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH BX ; Used for DIV ;AN000;
PUSH DX ; Used for DIV ;AN000;
;AN000;
MOV BX,CUR_MODE_PTR ; BX := Offset DISPLAYMODE info record ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; Calculate how many printer boxes fit in the print buffer: ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; \/ ~~mda(001) -----------------------------------------------------------------------
; The NB_BOXES_PER_PRT_BUF depends on if the printer head is
; vertical, as in IBM's case, or if it's horizontal, as in
; HP's case. If DATA_TYPE is DATA_COL, then we have a vertical
; print head. If DATA_TYPE is DATA_ROW, then we have a
; horizontal print head.
.IF <DS:[BP].DATA_TYPE EQ DATA_ROW> ; Print head is horizontal
MOV AX,8 ; Num := 8 bits / Box width
MOV DL,[BX].BOX_WIDTH ;
DIV DL ;
MOV NB_BOXES_PER_PRT_BUF,AL ;
.ELSE ;
; /\ ~~mda(001) -----------------------------------------------------------------------
MOV AX,8 ; Num := 8 bits / Box heigth ;AN000;
MOV DL,[BX].BOX_HEIGHT ;AN000;
DIV DL ;AN000;
MOV NB_BOXES_PER_PRT_BUF,AL ;AN000;
.ENDIF ; ~~mda(001) Close IF stmt.
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; Determine where to start reading the screen: ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
MOV CUR_COLUMN,0 ; Reading always start from left of scr ;AN000;
.IF <[BX].PRINT_OPTIONS EQ ROTATE> ;AN000;
.THEN ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; Printing is sideways; screen must be read starting in low-left corner. ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
MOV AX,SCREEN_HEIGHT ;AN000;
MOV SCAN_LINE_MAX_LENGTH,AX ; Scan line length := screen height ;AN000;
DEC AX ;AN000;
MOV CUR_ROW,AX ; First row := screen height - 1 ;AN000;
;AN000;
;-------Calculate the number of scan lines: ;AN000;
; \/ ~~mda(001) -----------------------------------------------------------------------
; The NB_SCAN_LINES depends on if the printer head is
; vertical, as in IBM's case, or if it's horizontal, as in
; HP's case. If the printer head is horizontal, then we can't
; make use of the concept of scan lines. However, we can still
; use the symbol NB_SCAN_LINES by just stuffing into it the
; screen width.
;
.IF <DS:[BP].DATA_TYPE EQ DATA_ROW> ; Print head is horizontal
MOV AX,SCREEN_WIDTH ; DX AX = Screen width
CWD ;
MOV NB_SCAN_LINES,AX;
.ELSE
; /\ ~~mda(001) -----------------------------------------------------------------------
MOV AX,SCREEN_WIDTH ; DX AX = Screen width ;AN000;
CWD ; ;AN000;
XOR BX,BX ; BX = Number of boxes per print buf ;AN000;
MOV BL,NB_BOXES_PER_PRT_BUF ; ;AN000;
DIV BX ; Screen width / number boxes per buff ;AN000;
MOV NB_SCAN_LINES,AX ; Number of scan lines := result ;AN000;
.ENDIF ; ~~mda(001) Close IF stmt.
.ELSE ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; Printing is not sideways; screen must be read starting in top-left corner ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
MOV AX,SCREEN_WIDTH ;AN000;
MOV SCAN_LINE_MAX_LENGTH,AX ; Scan line length := screen width ;AN000;
MOV CUR_ROW,0 ; First row := 0 ;AN000;
;AN000;
;-------Calculate the number of scan lines: ;AN000;
; \/ ~~mda(001) -----------------------------------------------------------------------
; The NB_SCAN_LINES depends on if the printer head is
; vertical, as in IBM's case, or if it's horizontal, as in
; HP's case. If the printer head is horizontal, then we can't
; make use of the concept of scan lines. However, we can still
; use the symbol NB_SCAN_LINES by just stuffing into it the
; screen height.
;
.IF <DS:[BP].DATA_TYPE EQ DATA_ROW> ; Print head is vertical
MOV AX,SCREEN_HEIGHT; DX AX = Screen height
CWD ;
MOV NB_SCAN_LINES,AX;
.ELSE
; /\ ~~mda(001) -----------------------------------------------------------------------
MOV AX,SCREEN_HEIGHT ; DX AX = Screen height ;AN000;
CWD ; ;AN000;
XOR BX,BX ; BX = Number of boxes per print buff ;AN000;
MOV BL,NB_BOXES_PER_PRT_BUF ; ;AN000;
DIV BX ; Screen height/number boxes per buff. ;AN000;
MOV NB_SCAN_LINES,AX ; Number of scan lines := result ;AN000;
.ENDIF ; ~~mda(001) Close IF stmt.
.ENDIF ;AN000;
POP DX ;AN000;
POP BX ;AN000;
POP AX ;AN000;
RET ;AN000;
GET_SCREEN_INFO ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; DET_CUR_SCAN_LNE_LENGTH : Determine where is the last non-blank "scan line ;AN000;
; column" on the current scan line. ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: CUR_ROW, ;AN000;
; CUR_COLUMN = Coordinates of the top pixel of the current ;AN000;
; scan line. ;AN000;
; XLT_TAB = Color translation table ;AN000;
; ;AN000;
; OUTPUT: CUR_SCAN_LNE_LENGTH = Number of "columns" of pixels from the ;AN000;
; beginning of the scan line up to ;AN000;
; the last non-blank pixel. ;AN000;
; ;AN000;
; DATA SCREEN_WIDTH, ;AN000;
; REFERENCED: SCREEN_HEIGHT = Dimensions of the screen in pels ;AN000;
; SCAN_LINE_MAX_LENGTH= Maximum length of the scan line ;AN000;
; ROTATE_SW = ON if printing is sideways ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: Determine where is the last non-blank "column" by reading ;AN000;
; the scan line backwards, one column at a time. ;AN000;
; ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; ; Obtain coordinates for the top pixel of the last column on the current ;AN000;
; ; scan line: ;AN000;
; IF printing is sideways ;AN000;
; THEN ;AN000;
; CUR_ROW := 0 ;AN000;
; ELSE ;AN000;
; CUR_COLUMN := SCREEN_WIDTH - 1 ;AN000;
; ;AN000;
; CUR_SCAN_LNE_LENGTH := SCAN_LINE_MAX_LENGTH ;AN000;
; ; Read a column of pixels on the scan line until a non-blank is found: ;AN000;
; For each column on the screen ;AN000;
; CALL FILL_BUFF ;AN000;
; ; Check if PRT_BUF is empty ;AN000;
; IF buffer is empty ;AN000;
; THEN DEC CUR_SCAN_LNE_LENGTH ;AN000;
; ; Get next column ;AN000;
; IF printing sideways THEN DEC CUR_ROW ;AN000;
; ELSE DEC CUR_COLUMN ;AN000;
; ELSE quit the loop ;AN000;
; ;AN000;
DET_CUR_SCAN_LNE_LENGTH PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
PUSH DX ;AN000;
PUSH SI ;AN000;
PUSH DI ;AN000;
PUSH CUR_COLUMN ;AN000;
PUSH CUR_ROW ;AN000;
;AN000;
MOV BX,OFFSET XLT_TAB ; BX := Offset of XLT_TAB ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; Obtain coordinates of the top pixel for the last column of the current ;AN000;
; scan line: ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
.IF <ROTATE_SW EQ ON> ; If printing sideways ;AN000;
.THEN ; then, ;AN000;
MOV CUR_ROW,0 ; CUR_ROW := 0 ;AN000;
.ELSE ; else, ;AN000;
MOV CX,SCREEN_WIDTH ; CUR_COLUMN := SCREEN_WIDTH - 1 ;AN000;
DEC CX ; ;AN000;
MOV CUR_COLUMN,CX ; ;AN000;
.ENDIF ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; Read the scan line backwards "column" by "column" until a non-blank is found: ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
MOV CX,SCAN_LINE_MAX_LENGTH ; CX := current length ;AN000;
; ;AN000;
;-------For each "column" ;AN000;
CHECK_1_COLUMN: ;AN000;
MOV SI,CUR_ROW ; Save coordinates of the column ;AN000;
MOV DI,CUR_COLUMN ; in SI, DI ;AN000;
XOR DL,DL ; DL := Number of pixels verified in ;AN000;
; one "column" ;AN000;
; ;AN000;
;-------For each pixel within that "column" ;AN000;
CHECK_1_PIXEL: ;AN000;
CALL READ_DOT ; AL := Index into translation table ;AN000;
XLAT XLT_TAB ; AL := Band mask or Intensity ;AN000;
;AN000;
;-------Check if pixel will map to an empty box: ;AN000;
.IF <DS:[BP].PRINTER_TYPE EQ BLACK_WHITE> ; If BLACK AND WHITE printer ;AN000;
.THEN ; then, check for intensity of white ;AN000;
CMP AL,WHITE_INT ; If curent pixel not blank ;AN000;
JNE DET_LENGTH_END ; THEN, LEAVE THE LOOP ;AN000;
.ELSE ; else, COLOR printer ;AN000;
OR AL,AL ; IF Band mask not blank ;AN000;
JNZ DET_LENGTH_END ; THEN, LEAVE THE LOOP ;AN000;
.ENDIF ;AN000;
;AN000;
; \/ ~~mda(001) -----------------------------------------------------------------------
; Only if DATA_TYPE is DATA_COL do we have "columns",
; so skip this section otherwise.
.IF <DS:[BP].DATA_TYPE EQ DATA_COL> ; Print head is vertical
; /\ ~~mda(001) -----------------------------------------------------------------------
;-------All pixels so far on this "column" are blank, get next pixel: ;AN000;
.IF <ROTATE_SW EQ ON> ; If printing sideways ;AN000;
.THEN ; ;AN000;
INC CUR_COLUMN ; then, increment column number ;AN000;
.ELSE ; ;AN000;
INC CUR_ROW ; else, increment row number ;AN000;
.ENDIF ; ;AN000;
INC DL ; One more pixel checked ;AN000;
CMP DL,NB_BOXES_PER_PRT_BUF ; All pixels for that column done ? ;AN000;
JL CHECK_1_PIXEL ; No, check next one. ;AN000;
.ENDIF ;~~mda(001) Close IF stmt.
;AN000;
;-------Nothing to print for this column, get next column ;AN000;
.IF <ROTATE_SW EQ ON> ; If printing sideways ;AN000;
.THEN ; then, ;AN000;
MOV CUR_COLUMN,DI ; Restore column number ;AN000;
INC CUR_ROW ; Get next row ;AN000;
.ELSE ; else, ;AN000;
MOV CUR_ROW,SI ; Restore row number ;AN000;
DEC CUR_COLUMN ; Get next column ;AN000;
.ENDIF ; ;AN000;
LOOP CHECK_1_COLUMN ; CX (length) := CX - 1 ;AN000;
;AN000;
DET_LENGTH_END: ;AN000;
MOV CUR_SCAN_LNE_LENGTH,CX ; Get current length ;AN000;
;AN000;
POP CUR_ROW ;AN000;
POP CUR_COLUMN ;AN000;
POP DI ;AN000;
POP SI ;AN000;
POP DX ;AN000;
POP CX ;AN000;
POP BX ;AN000;
POP AX ;AN000;
RET ;AN000;
DET_CUR_SCAN_LNE_LENGTH ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; SETUP_PRT : SET UP THE PRINTER FOR PRINTING IN GRAPHIC MODE ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: CUR_MODE_PTR = Offset of the DISPLAYMODE information ;AN000;
; record for the current mode ;AN000;
; ;AN000;
; OUTPUT: PRINTER ;AN000;
; ;AN000;
; CALLED BY: PRINT_COLOR ;AN000;
; PRT_BW_APA ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: Extract the SETUP escape sequence from the DISPLAYMODE ;AN000;
; information record; Send this escape sequence to the printer. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; Number of bytes to print := CUR_MODE_PTR.NUM_SETUP_ESC ;AN000;
; ;AN000;
; Get the escape sequence: ;AN000;
; SI := CUR_MODE_PTR.SETUP_ESC_PTR ;AN000;
; ;AN000;
; FOR each byte to be printed ;AN000;
; PRINT_BYTE [SI] ; Send the byte to the printer ;AN000;
; INC SI ; Get the next byte ;AN000;
; ;AN000;
SETUP_PRT PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
;AN000;
MOV BX,CUR_MODE_PTR ; BX := Displaymode info record. ;AN000;
;AN000;
XOR CX,CX ; CX := Number of bytes to print ;AN000;
MOV CL,[BX].NUM_SETUP_ESC ; ;AN000;
.IF <CL G 0> ; If there is at least one ;AN000;
.THEN ; byte to be printed: ;AN000;
MOV BX,[BX].SETUP_ESC_PTR ; BX := Offset sequence to send ;AN000;
ADD BX,BP ;AN000;
;AN000;
SEND_1_SETUP_BYTE: ;AN000;
MOV AL,[BX] ; AL := byte to print ;AN000;
CALL PRINT_BYTE ; Send it to the printer ;AN000;
JC SETUP_PRT_END ; If printer error, quit the loop ;AN000;
INC BX ; Get next byte ;AN000;
LOOP SEND_1_SETUP_BYTE ;AN000;
.ENDIF ;AN000;
SETUP_PRT_END: ;AN000;
POP CX ;AN000;
POP BX ;AN000;
POP AX ;AN000;
RET ;AN000;
SETUP_PRT ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; RESTORE_PRT : RESTORE THE PRINTER TO ITS INITIAL STATUS ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: CUR_MODE_PTR = Offset of the DISPLAYMODE information ;AN000;
; record for the current mode ;AN000;
; ;AN000;
; OUTPUT: PRINTER ;AN000;
; ;AN000;
; CALLED BY: PRINT_COLOR ;AN000;
; PRT_BW_APA ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: Extract the RESTORE escape sequence from the DISPLAYMODE ;AN000;
; information record; Send this escape sequence to the printer. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; Number of bytes to print := CUR_MODE_PTR.NUM_RESTORE_ESC ;AN000;
; ;AN000;
; Get the escape sequence: ;AN000;
; SI := CUR_MODE_PTR.RESTORE_ESC_PTR ;AN000;
; FOR each byte to be printed ;AN000;
; PRINT_BYTE [SI] ; Send the byte to the printer ;AN000;
; INC SI ; Get the next byte ;AN000;
; ;AN000;
RESTORE_PRT PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
;AN000;
MOV BX,CUR_MODE_PTR ; BX := Displaymode info record. ;AN000;
;AN000;
XOR CX,CX ; CX := Number of bytes to print ;AN000;
MOV CL,[BX].NUM_RESTORE_ESC ;AN000;
.IF <CL G 0> ; If there is at least one ;AN000;
.THEN ; byte to be printed: ;AN000;
MOV BX,[BX].RESTORE_ESC_PTR ; BX := Offset sequence to send ;AN000;
ADD BX,BP ;AN000;
;AN000;
SEND_1_RESTORE_BYTE: ;AN000;
MOV AL,[BX] ; AL := byte to print ;AN000;
CALL PRINT_BYTE ; Send it to the printer ;AN000;
JC RESTORE_PRT_END ; If printer error, quit the loop ;AN000;
INC BX ; Get next byte ;AN000;
LOOP SEND_1_RESTORE_BYTE ;AN000;
.ENDIF ;AN000;
RESTORE_PRT_END: ;AN000;
POP CX ;AN000;
POP BX ;AN000;
POP AX ;AN000;
RET ;AN000;
RESTORE_PRT ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; NEW_PRT_LINE : INITIALIZE THE PRINTER FOR A GRAPHIC LINE ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: CUR_MODE_PTR = Offset of the DISPLAYMODE information ;AN000;
; record for the current mode ;AN000;
; CUR_SCAN_LNE_LENGTH = Number of bytes to send to the printer. ;AN000;
; ;AN000;
; OUTPUT: PRINTER ;AN000;
; ;AN000;
; CALLED BY: PRINT_BAND ;AN000;
; PRT_BW_APA ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: Extract the GRAPHICS escape sequence from the DISPLAYMODE ;AN000;
; information record; Send this escape sequence to the printer. ;AN000;
; Then, send the number of bytes that will follow. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; Number of bytes to print := CUR_MODE_PTR.NUM_GRAPHICS_ESC ;AN000;
; ;AN000;
; Get the escape sequence: ;AN000;
; Set up the 2 bytes containing the number of bytes to send in this sequence. ;AN000;
; SI := CUR_MODE_PTR.GRAPHICS_ESC_PTR ;AN000;
; ;AN000;
; FOR each byte to be printed ;AN000;
; PRINT_BYTE [SI] ; Send the byte to the printer ;AN000;
; INC SI ; Get the next byte ;AN000;
; ;AN000;
; Send the byte count ;AN000;
; ;AN000;
;AN000;
NEW_PRT_LINE PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
PUSH DX ;AN000;
PUSH DI ;AN000;
;AN000;
MOV BX,CUR_MODE_PTR ; BX := Displaymode info record. ;AN000;
;AN000;
;-------------------------------------------------------------------------------;AN000;
; Set up the 2 bytes containing the number of bytes to send in the GRAPHICS seq.;AN000;
; NOTE: number of bytes to send is "CUR_SCAN_LNE_LENGTH * BOX_W" ;AN000;
;-------------------------------------------------------------------------------;AN000;
MOV AL,BOX_W ; cur_scan_lne_length * ;AN000;
CBW ; printer box width = nb bytes to send;AN000;
MUL CUR_SCAN_LNE_LENGTH ; (result in DX AX) ;AN000;
;-------AX := Number of bytes to print ;AN000;
; \/ ~~mda(001) -----------------------------------------------------------------------
; Since we have added the key words DATA and COUNT to the
; list of allowable words for the GRAPHICS statement
; we have to take into consideration if the esc. sequence
; numbers come before of after the word DATA. Also we have
; to take into consideration if the printer is expecting
; to receive the COUNT in binary form or in ASCII form.
; Note this section of code replaces the section of code
; which follows it.
MOV DI,[BX].GRAPHICS_ESC_PTR ; DI := offset seq. to send
XOR CX,CX ; CX := Length of the escape seq
MOV CL,[BX].NUM_GRAPHICS_ESC ; before the word DATA
.WHILE <CX NE 0> ; Doing while loop just in case DATA is the
; first word after GRAPHICS. In that case
; skip this and send the actual data.
MOV BL,BYTE PTR DS:[BP+DI] ; Get code.
;
.SELECT ; Case statement
.WHEN <BL EQ ESC_NUM_CODE> ; We have an esc. number
PUSH AX ; Save count
INC DI ; Point to esc. number
MOV AL,DS:[BP+DI] ;
CALL PRINT_BYTE ; Send esc. number
JC NEW_PRT_LINE_ENDP_1 ; If printer error then quit
; the loop and restore registers
INC DI ; Point to next tag
POP AX ; Restore the count
DEC CX ;
.WHEN <BL EQ COUNT_CODE> ; Need to send count in ascii form
PUSH AX ; Save count
PUSH SI ;
CALL GET_COUNT ; Get # bytes to send to printer
PUSH CX ; Save counter for outside loop
XOR CH,CH ;
MOV CL,DS:[BP].NUM_BYTES_FOR_COUNT ;
LEA SI,DS:[BP].COUNT ; Get ptr. to count
SUB SI,CX ; Need to send MSB first
INC SI ;
CLD ;
SEND_ASCII_COUNT: ;
LODSB ;
CALL PRINT_BYTE ; Print it
JC NEW_PRT_LINE_ENDP_2 ; If printer error then quit
; the loop and restore registers
LOOP SEND_ASCII_COUNT ;
POP CX ; Restore outside loop counter
ADD DI,2 ; Point to next tag
POP SI ;
POP AX ; Restore COUNT
DEC CX ;
.WHEN <BL EQ LOWCOUNT_CODE> ; Sending lowbyte of COUNT
CALL PRINT_BYTE ; Print it
JC NEW_PRT_LINE_ENDP ; If printer error then quit
ADD DI,2 ; Point to next tag
DEC CX ;
.WHEN <BL EQ HIGHCOUNT_CODE> ; Sending highbyte of COUNT
PUSH AX ; Save count
CWD ;
MOV BX,100h ;
DIV BX ; Put highbyte in AL
CALL PRINT_BYTE ; Print it
JC NEW_PRT_LINE_ENDP_1 ; If printer error then quit
; the loop and restore registers
ADD DI,2 ; Point to next tag
; the loop.
POP AX ; Restore count
DEC CX ;
.ENDSELECT ;
.ENDWHILE ;
ADD DI,2 ; Skip over DATA tag and byte
; so pointing to correct place when
; get to END_PRT_LINE proc.
; /\ ~~mda(001) -----------------------------------------------------------------------
; \/ ~~mda(001) -----------------------------------------------------------------------
; The following piece of code is replaced by the above piece
; of code.
;
;;;; MOV DI,[BX].LOW_BYT_COUNT_PTR; DI := Offset of LOW byte of ;AN000;
;;;; ADD DI,BP ; byte count ;AN000;
;;;; MOV [DI],AL ; Store low byte ;AN000;
;;;; MOV DI,[BX].HGH_BYT_COUNT_PTR; DI := Offset of HIGH byte of ;AN000;
;;;; ADD DI,BP ; byte count ;AN000;
;;;; MOV [DI],AH ; Store high byte ;AN000;
;;;; ;AN000;
;;;;;-------------------------------------------------------------------------------;AN000;
;;;;; Send the GRAPHICS escape sequence to the printer: ;AN000;
;;;;;-------------------------------------------------------------------------------;AN000;
;;;; XOR CX,CX ; CX := Length of the escape seq;AN000;
;;;; MOV CL,[BX].NUM_GRAPHICS_ESC ;AN000;
;;;; MOV BX,[BX].GRAPHICS_ESC_PTR ; BX := Offset sequence to send ;AN000;
;;;; ADD BX,BP ;AN000;
;;;; ;AN000;
;;;;SEND_1_GRAPHICS_BYTE: ;AN000;
;;;; MOV AL,[BX] ; AL := byte to print ;AN000;
;;;; CALL PRINT_BYTE ; Send it to the printer ;AN000;
;;;; JC NEW_PRT_LINE_ENDP ; If printer error, quit the loop ;AN000;
;;;; INC BX ; Get next byte ;AN000;
;;;; LOOP SEND_1_GRAPHICS_BYTE ;AN000;
; /\ ~~mda(001) -----------------------------------------------------------------------
JMP SHORT NEW_PRT_LINE_ENDP ; ~~mda(001) Restore registers
JMP SHORT NEW_PRT_LINE_ENDP ;
NEW_PRT_LINE_ENDP_2: ; ~~mda(001)
POP SI
NEW_PRT_LINE_ENDP_1: ; ~~mda(001)
POP AX
NEW_PRT_LINE_ENDP: ;AN000;
POP DI ;AN000;
POP DX ;AN000;
POP CX ;AN000;
POP BX ;AN000;
POP AX ;AN000;
RET ;AN000;
NEW_PRT_LINE ENDP ;AN000;
PAGE ;AN000;
; \/ ~~mda(001) -----------------------------------------------------------------------
; Since we have the keyword DATA, and we allow it to be anywhere
; on the GRAPHICS line, then it is possible to have an
; esc. sequence to send to the printer after the data has been
; sent. Therefore we need this new procedure.
;===============================================================================
;
; END_PRT_LINE : SEND THE REST OF THE GRAPHICS LINE
;
;-------------------------------------------------------------------------------
;
; INPUT: CUR_MODE_PTR = Offset of the DISPLAYMODE information
; record for the current mode
; DI = Points to the section of the esc. seq that
; comes after the keyword DATA.
;
; OUTPUT: PRINTER
;
; CALLED BY: PRT_BW_APA
;
;-------------------------------------------------------------------------------
;
; DESCRIPTION: Extract the GRAPHICS escape sequence that comes after the keyword
; DATA from the DISPLAYMODE information record; Send this escape sequence to the
; printer.
;
;
CR_FOUND DB ? ; So we know if a carriage return has been sent
LF_FOUND DB ? ; So we know if a line feed has been sent
END_PRT_LINE PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
MOV CR_FOUND,NO ; Initialize
MOV LF_FOUND,NO ;
MOV BX,CUR_MODE_PTR ; BX := Displaymode info record.
;-------------------------------------------------------------------------------
; Set up the 2 bytes containing the number of bytes to send in the GRAPHICS seq.
; NOTE: number of bytes to send is "CUR_SCAN_LNE_LENGTH * BOX_W"
;-------------------------------------------------------------------------------
MOV AL,BOX_W ; cur_scan_lne_length *
CBW ; printer box width = nb bytes to send
MUL CUR_SCAN_LNE_LENGTH ; (result in DX AX)
;-------AX := Number of bytes to print
XOR CX,CX ; CX := Length of the escape seq
MOV CL,[BX].NUM_GRAPHICS_ESC_AFTER_DATA ;after the word DATA
.WHILE <CX NE 0> ; Doing a while loop just in case DATA is the
; last word on the GRAPHICS line. In that case
; skip this and send a CR or LF if needed.
MOV BL,BYTE PTR DS:[BP+DI] ; Get code.
.SELECT ; Case statement
.WHEN <BL EQ ESC_NUM_CODE> ; We have an esc. number
PUSH AX ; Save count
INC DI ; Point to esc. number
MOV AL,DS:[BP+DI] ;
.IF <AL EQ CR> ; Check if a CR is
MOV CR_FOUND,YES ; explicitly stated
.ENDIF
.IF <AL EQ LF> ; Check if a LF is
MOV LF_FOUND,YES ; explicitly stated
.ENDIF
CALL PRINT_BYTE ; Send esc. number
JC GOTO_END_PRT_LINE_ENDP_1; If printer error then quit
; the loop and restore registers
INC DI ; Point to next tag
POP AX ; Restore the count
DEC CX ;
.WHEN <BL EQ COUNT_CODE> ; Need to send count in ascii form
PUSH AX ; Save count
PUSH SI ;
CALL GET_COUNT ; Get # of bytes to send to printer
PUSH CX ; Save counter for outside loop
XOR CH,CH ;
MOV CL,DS:[BP].NUM_BYTES_FOR_COUNT ;
LEA SI,DS:[BP].COUNT ; Get ptr. to count
SUB SI,CX ; Need to send MSB first
INC SI ;
CLD ;
SEND_THE_ASCII_COUNT: ;
LODSB ;
CALL PRINT_BYTE ; Print it
JC GOTO_END_PRT_LINE_ENDP_2 ; If printer error then quit
; the loop and restore registers.
LOOP SEND_THE_ASCII_COUNT ;
POP CX ; Restore outside loop counter
ADD DI,2 ; Point to next tag
POP SI ;
POP AX ; Restore COUNT
DEC CX ;
.WHEN <BL EQ LOWCOUNT_CODE> ; Sending lowbyte of COUNT
CALL PRINT_BYTE ; Print it
JC END_PRT_LINE_ENDP ; If printer error then quit
ADD DI,2 ; Point to next tag
DEC CX ;
.WHEN <BL EQ HIGHCOUNT_CODE> ; Sending highbyte of COUNT
PUSH AX ; Save count
CWD ;
MOV BX,100h ;
DIV BX ; Put highbyte in AL
CALL PRINT_BYTE ; Print it
JC END_PRT_LINE_ENDP_1 ; If printer error then quit
; the loop and restore registers
ADD DI,2 ; Point to next tag
; the loop.
POP AX ; Restore count
DEC CX ;
.ENDSELECT ;
.ENDWHILE ;
JMP SHORT CR_LF ;
GOTO_END_PRT_LINE_ENDP_2: ; Conditional jump was out of range
JMP SHORT END_PRT_LINE_ENDP_2 ;
GOTO_END_PRT_LINE_ENDP_1: ; Conditional jump was out of range
JMP SHORT END_PRT_LINE_ENDP_1 ;
CR_LF: ;
.IF <DS:[BP].PRINTER_NEEDS_CR_LF EQ YES> ; ~~mda(003) We have an IBM type printer
; so we need to do a CR and LF if it
; already hasn't been done.
.IF <CR_FOUND EQ NO> ; It hasn't been done.
MOV AL,CR ;
CALL PRINT_BYTE ;
JC END_PRT_LINE_ENDP ; If printer error then quit
.ENDIF ;
.IF <LF_FOUND EQ NO> ; It hasn't been done.
MOV AL,LF ;
CALL PRINT_BYTE ;
JC END_PRT_LINE_ENDP ; If printer error then quit
.ENDIF ;
;
.ENDIF ;
JMP NEW_PRT_LINE_ENDP ; Restore registers
JMP SHORT END_PRT_LINE_ENDP ;
END_PRT_LINE_ENDP_2: ; Restore registers
POP SI ;
END_PRT_LINE_ENDP_1: ; Restore registers
POP AX ;
END_PRT_LINE_ENDP: ;
POP DI ;
POP DX ;
POP CX ;
POP BX ;
POP AX ;
RET ;
END_PRT_LINE ENDP ;
; /\ ~~mda(001) -----------------------------------------------------------------------
PAGE ;AN000;
; \/ ~~mda(001) -----------------------------------------------------------------------
; Since we now can do HP PCL, we have to get the number of
; bytes that are going to be sent to the printer and convert
; the number to ASCII if DATA_TYPE = DATA_ROW.
;===============================================================================;AN000;
; ;AN000;
; GET_COUNT : GET THE NUMBER OF BYTES TO SEND TO THE PRINTER
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: CUR_SCAN_LNE_LENGTH
; NB_BOXES_PER_PRT_BUF ;AN000;
; ;AN000;
; output : si pointer to ascii string
;
; si --> len=4 (hex = 4d2h)
; 1
; 2
; 3
; 4
;
; count (from shared_data_area)
;
; ;AN000;
; CALLED BY: NEW_PRT_LINE
; END_PRT_LINE
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
GET_COUNT proc near
push ax ;
push bx ;
push cx ;
push dx ;
push si ;
mov ax,cur_scan_lne_length ; Get # bytes to send to
cwd ; the printer
xor bh,bh ;
mov bl,nb_boxes_per_prt_buf ;
div bx ;
.IF <DX NE 0> ; So don't lose data when
INC AX ; have a remainder.
.ENDIF ;
;
;--------- AX is the # bytes to send to the printer. Now convert it to ascii.
;
xor dx,dx ;clear upper 16 bits
lea si,ds:[bp].count ;get pointer
PUSH SI ; Save ptr.
MOV CX,5 ; Init. COUNT
INIT_COUNT: ;
MOV BYTE PTR [SI],0 ;
DEC SI ;
LOOP INIT_COUNT ;
POP SI ;
;
mov bx,10 ; mod 10, div 10
xor cx,cx ;length counter = 0
hx_asc: ;
div bx ;div, mod
add dl,'0' ;add 48 for ASCII
mov [si],dl ;store it
dec si ;point to next string element
inc cx ;inc length counter
xor dx,dx ;consider only div part for next loop
cmp ax,0 ;end of loops ? (div=0)
jnz hx_asc ;no
mov ds:[bp].num_bytes_for_count,cl ;save the length
;
pop si ;
pop dx ;
pop cx ;
pop bx ;
pop ax ;
ret ;
GET_COUNT endp ;
; /\ ~~mda(001) -----------------------------------------------------------------------
PAGE
;
;===============================================================================;AN000;
; ;AN000;
; PRINT_BYTE : SEND A BYTE TO THE PRINTER AT LPT1 ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: AL = Byte to be printed ;AN000;
; ;AN000;
; OUTPUT: PRINTER ;AN000;
; ERROR_CODE = PRINTER_ERROR if an error is detected. ;AN000;
; Carry flag is set in case of error. ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
PRINT_BYTE PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH DX ;AN000;
;AN000;
MOV DX,0000 ; PRINTER NUMBER ;AN000;
MOV AH,00 ; REQUEST PRINT ;AN000;
INT 17H ; CALL BIOS : SEND THE CHARACTER ;AN000;
;AN000;
AND AH,00101001B ; Test error code returned in AH for ;AN000;
; "Out of paper", "I/O error" and "Time-out". ;AN000;
JNZ PRINT_BYTE_ERROR; Set the error code if error ;AN000;
JMP SHORT PRINT_BYTE_END ; else, return normally ;AN000;
PRINT_BYTE_ERROR: ;AN000;
MOV ERROR_CODE,PRINTER_ERROR ;AN000;
STC ; Set the carry flag to indicate ERROR ;AN000;
PRINT_BYTE_END: ;AN000;
POP DX ;AN000;
POP AX ;AN000;
RET ;AN000;
PRINT_BYTE ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; READ_DOT: READ A PIXEL - RETURN A COLOR TRANSLATION TABLE INDEX ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: CUR_MODE = Current video mode. ;AN000;
; CUR_ROW, ;AN000;
; CUR_COLUMN = Coordinates of the pixel to be read. ;AN000;
; CUR_PAGE = Active page number ;AN000;
; ;AN000;
; OUTPUT: AL = Index into COLOR TRANSLATION TABLE. ;AN000;
; ;AN000;
; DEPENDENCIES : COLOR TRANSLATION TABLE entries must be bytes ;AN000;
; ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: Use VIDEO BIOS INTERRUPT 10H "READ DOT CALL". ;AN000;
; ;AN000;
; Depending on the video hardware, the dot returned by BIOS has ;AN000;
; different meanings. ;AN000;
; With an EGA it is an index into the Palette registers, ;AN000;
; With a CGA it is a number from 0 to 3, mapping to a specific color ;AN000;
; depending on the background color and the color palette currently ;AN000;
; selected. ;AN000;
; ;AN000;
; The Color Translation table has been set up to hold the correct color ;AN000;
; mapping for any "dot" in any mode. Therefore, the dot number returned ;AN000;
; by INT 10H can be used with any mode as a direct index within that ;AN000;
; table. ;AN000;
; ;AN000;
; With APA Monochrome mode 0FH there are 4 different dots: white, ;AN000;
; blinking white, high-intensity white, and black. ;AN000;
; ;AN000;
; For mode 0FH, the dot returned by interrupt 10 "read dot" call is a byte ;AN000;
; where only bits 0 and 2 are significant. These 2 bits must be appended ;AN000;
; together in order to obtain a binary number (from 0 to 3) that will be used ;AN000;
; as an index in the Color Translation table. ;AN000;
; ;AN000;
; For mode 11H, the dot is either 0 (for background color) or 7 (for the ;AN000;
; foreground color) only the LSB is returned. That is, we return either ;AN000;
; 0 or 1. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; Call VIDEO BIOS "READ DOT" ;AN000;
; IF CUR_MODE = 0FH ;AN000;
; THEN ;AN000;
; Append bits 1 and 3. ;AN000;
; IF CUR_MODE = 11H ;AN000;
; THEN ;AN000;
; Wipe out bits 1 and 2. ;AN000;
; ;AN000;
READ_DOT PROC NEAR ;AN000;
PUSH BX ; Save registers ;AN000;
PUSH CX ;AN000;
PUSH DX ;AN000;
;AN000;
MOV BH,CUR_PAGE ;AN000;
MOV DX,CUR_ROW ;AN000;
MOV CX,CUR_COLUMN ;AN000;
MOV AH,READ_DOT_CALL ;AN000;
INT 10H ; Call BIOS: AL <-- Dot read ;AN000;
;AN000;
CMP CUR_MODE,0FH ; Is it Mode 0fH ? ;AN000;
JNE MODE_11H? ; No, look for mode 11h. ;AN000;
;-------Mode 0Fh is the current mode: ;AN000;
;-------Convert bits 2 and 0 into a 2 bit number: ;AN000;
MOV BL,AL ; BL := AL = "Pixel read" ;AN000;
AND BL,00000100B ; Wipe off all bits but bit 2 in BL ;AN000;
AND AL,00000001B ; Wipe off all bits but bit 0 in AL ;AN000;
SHR BL,1 ; Move bit 2 to bit 1 in BL ;AN000;
OR AL,BL ; Append bit 1 and bit 0 ;AN000;
JMP SHORT READ_DOT_END ; Quit. ;AN000;
;AN000;
MODE_11H?: ;AN000;
CMP CUR_MODE,11H ; Is it Mode 0fH ? ;AN000;
JNE READ_DOT_END ; No, quit ;AN000;
;AN000;
;-------Mode 11H is the current mode: ;AN000;
AND AL,00000001B ; Keep only the Least significant bit ;AN000;
;AN000;
READ_DOT_END: ;AN000;
POP DX ; Restore registers ;AN000;
POP CX ;AN000;
POP BX ;AN000;
RET ;AN000;
READ_DOT ENDP ;AN000;