;---------------------------------------------------------------------- ; Fontedit - Loads the current screen font and lets you modify it. ; Saves font in a COM file with integral loader. Requires EGA or VGA. ; Syntax: FONTEDIT [filespec] ; PC Magazine September 13, 1988 ;---------------------------------------------------------------------- _TEXT SEGMENT PUBLIC 'CODE' ASSUME CS:_TEXT,DS:_TEXT ASSUME ES:_TEXT,SS:_TEXT ORG 100H START: JMP MAIN ; DATA AREA ; --------- DB CR,SPACE,SPACE,SPACE,CR,LF COPYRIGHT DB "FONTEDIT 1.0 (C) 1988 Ziff Communications Co. ",BOX PROGRAMMER1 DB " PC Magazine ",BOX," Michael J. Mefford",0,CTRL_Z CR EQU 13 LF EQU 10 CTRL_Z EQU 26 SPACE EQU 32 BOX EQU 254 ESC_SCAN EQU 1 ENTER_SCAN EQU 1CH UP_ARROW EQU 48H DN_ARROW EQU 50H LEFT_ARROW EQU 4BH RIGHT_ARROW EQU 4DH Y_SCAN EQU 15H BS_SCAN EQU 0EH TAB_CHAR EQU 9 MAX_POINTS EQU 16 PIXEL_OFF EQU 177 PIXEL_ON EQU 219 EDIT_COL EQU 32 EDIT_ROW EQU 8 EDIT_TOP EQU EDIT_ROW SHL 8 + EDIT_COL TEMPLATE_TOP EQU EDIT_TOP - 28 CHAR_TOP EQU EDIT_TOP + 28 BOX_TOP EQU EDIT_TOP + 1 - 400H INTENSITY EQU 1000B MICKEY EQU 20 BUTTONS LABEL WORD LEFT_BUTTON DB 0 RIGHT_BUTTON DB 0 SHIFT_KEYS EQU 3 SHIFT_STATE DB ? HORIZONTAL DW 0 VERTICAL DW 0 NORMAL EQU 07H ATTRIBUTE DB 07H INVERSE DB 70H ROWS DB ? MAX_LINES DW 16 MOUSE_FLAG DB 0 MODIFY_FLAG DB 0 BLANKS DB 0,32,255 FILE_FLAG DB 0 FILE_HANDLE DW ? FILENAME DW ? LAST_PIXEL DB ? ;format: reg,value SEQUENCER REGISTERS GRAPHICS CONTROLLER REGISTERS ; MAP MASK MEMORY MODE MODE REG MISC READ MAP SELECT ACCESS_A000H DB 2,4, 4,7, 5,0, 6,4, 4,2 PROTECT_A000H DB 2,3, 4,3, 5,10H, 6,0AH, 4,0 MENU LABEL BYTE DB "F1 Del row F2 Ins row F3 Dup row F4 Save $" MENU1 LABEL BYTE DB "F5 Copy template char. Tab = select edit/char box" DB " Use: arrow keys or mouse",CR,LF DB "Hold Shift key or mouse button to drag. Esc to exit" DB " Rows displayed = ",CR,LF DB "Left button = pixel on",CR,LF DB "Right button = pixel off",CR,LF DB "Space bar = toggle pixel$" MENU2 LABEL BYTE DB "Enter = select char.",0 DB "Button = select char.",0 DB "PgUp/PgDn prev./next char.",0 CAPTIONS DW TEMPLATE_TOP - 2 DB "Template Char",0 DW EDIT_TOP - 2 DB " Edit Char",0 DW CHAR_TOP - 2 DB "Character Set",0 CURRENT_BOX DB 218, 5 DUP (196), 194, 5 DUP (196), 191 DB 179, 5 DUP (SPACE), 179, 5 DUP (SPACE), 179 DB 192, 5 DUP (196), 193, 5 DUP (196), 217 NOT_ENOUGH DB "Not enough memory$" NOT_SUPPORTED DB "Font too tall$" NOT_EGA_VGA DB "Ega/Vga not found$" SAVE_MSG DB CR,LF,"Save ",0 FILE_MSG DB "file",0 CREATE_MSG DB CR,LF,"Create ",0 EXIST_MSG DB CR,LF,"Write over existing ",0 YES_NO DB "? Y/N",0 FAILED_MSG DB CR,LF,"Failed$" FILENAME_MSG DB CR,LF,"Enter filename",CR,LF,"$" NOT_FONT_MSG DB " not font$" COM DB ".COM",0 WARNING_MSG DB LF,"Warning! The cursor row will be deleted in" DB " EVERY character in this font.",CR,LF,"Continue$" DISPATCH_KEY DB 1, 4BH, 4DH, 48H, 50H, 49H DB 51H, 0FH, 39H, 1CH, 3BH, 53H DB 3CH, 52H, 3DH, 3EH, 3FH DISPATCH_CNT EQU $ - DISPATCH_KEY DISPATCH_TABLE DW EXIT, LEFT, RIGHT, UP, DOWN, PGUP DW PGDN, TAB, SPACE_BAR, ENTER, DEL_ROW, DEL_ROW DW INS_ROW, INS_ROW, DUP_ROW, SAVE, COPY_TEMP DISPATCH_END EQU $ - 2 ; CODE AREA ; --------- MAIN PROC NEAR CLD ;All string operations forward. MOV BX,1024 ;Allocate 1024 paragraphs; 16K. MOV AH,4AH INT 21H MOV DX,OFFSET NOT_ENOUGH ;Exit with message if not enough. JC ERROR_MSG MOV AX,500H ;Make sure zero video page. INT 10H MOV AX,40H ;Point to BIOS data area. MOV ES,AX MOV AX,1A00H ;Get display info. INT 10H CMP AL,1AH ;Function supported? JNZ CK_EGA ;If no, not VGA; check EGA. CMP BL,7 ;Else, monochrome VGA? JZ GET_CRT_MODE ;If yes, OK. CMP BL,8 ;Else, color VGA? JZ GET_CRT_MODE ;If yes, OK. CK_EGA: MOV MAX_LINES,14 ;Else, use 14 max lines for EGA. MOV BL,10H ;Get EGA information. MOV AH,12H INT 10H MOV DX,OFFSET NOT_EGA_VGA CMP BL,10H ;Is there an EGA? JZ ERROR_MSG ;If no, exit with message. TEST ES:BYTE PTR [87H],8 ;Is EGA active? JNZ ERROR_MSG ;If no, exit with message. GET_CRT_MODE: MOV BL,ES:[49H] ;Retrieve CRT_MODE. CALL INFORMATION ;Get font information. MOV DX,OFFSET NOT_SUPPORTED CMP CX,MAX_POINTS ;Font greater than 16 points? JBE CK_MODE ;If no, OK. ERROR_MSG: CALL PRINT_STRING ;Print error message. ERROR_EXIT: MOV AL,1 ;ERRORLEVEL = 1 JMP TERMINATE ;Exit. CK_MODE: CMP BL,7 ;CRT_MODE mono? JZ SAVE_MODE ;If yes, skip. MOV BYTE PTR PROTECT_A000H + 7,0EH ;Else, change parameter. CMP BL,2 ;Is mode BW80? JZ SAVE_MODE ;If yes, defaults. MOV ATTRIBUTE,17H ;Else, use color attributes. MOV INVERSE,71H CMP BL,3 ;Are we in CO80? JZ SAVE_MODE ;If yes, done here. MOV AX,3 ;Else, change to CO80. INT 10H MOV BL,3 SAVE_MODE: MOV CRT_MODE,BL ;Save CRT_MODE in loader. CALL SETUP ;Setup the display. ;************************** MAIN LOOP **************************; ; User input dispatcher. AH = ASCII character; AL = Scan Code. ; ;***************************************************************; INPUT: CALL HIDE_CURSOR ;Park cursor off screen. CALL GET_INPUT ;Get some input from user. CMP BUTTONS,0 ;Was a mouse button pressed? JZ CK_ASCII ;If no, check keyboard input. CALL BUTTON_PRESS ;Else, process button press. JMP SHORT INPUT ;Next input. CK_ASCII: OR AL,AL ;Scan code zero? JZ ALT_INPUT ;If yes, ALT keypad entry. MOV DI,OFFSET DISPATCH_KEY ;Else, check dispatch table. MOV CX,DISPATCH_CNT REPNZ SCASB JNZ ALT_INPUT ;If no match, keyboard char. SHL CX,1 ;Else, look up subroutine MOV DI,OFFSET DISPATCH_END SUB DI,CX CALL [DI] ; and process command. JMP SHORT INPUT ;Next input. ALT_INPUT: OR AH,AH ;ASCII zero? JZ INPUT ;If yes, skip. MOV EDIT_CHAR,AH ;Else, store as new character. CALL SETUP_END ;Display new edit character. JMP SHORT INPUT ;Next input. ;---------------------------------------------------; ; Exit. If font was modified, prompt user to save. ; ;---------------------------------------------------; EXIT: CALL CLS ;Clear the screen. CMP MODIFY_FLAG,1 ;Font modified? JNZ GOOD_EXIT ;If no, return to DOS. MOV SI,OFFSET FILE_MSG CMP FILE_FLAG,1 ;If there a filename? JZ DO_FILE ;If yes, display it. MOV FILENAME,SI ;Else, display "file". DO_FILE: MOV SI,OFFSET SAVE_MSG CALL PROMPT ;Prompt user to save. JNZ GOOD_EXIT ;If "Y"es not pressed, exit. CMP FILE_FLAG,1 ;Else, is there a filename? JZ DO_SAVE ;If yes, save it. CALL GET_NAME ;Else, get a filename. JC GOOD_EXIT ;If aborted, exit. DO_SAVE: CALL SAVE_FILE ;Save the font COM file. GOOD_EXIT: CALL CLS ;Clear the screen. XOR AL,AL ;ERRORLEVEL zero. TERMINATE: MOV AH,4CH ;Return to DOS. INT 21H MAIN ENDP ; *************** ; * SUBROUTINES * ; *************** ;-------------------------------------------------------------; ; What follows is the user input command processing routines. ; ;-------------------------------------------------------------; BUTTON_PRESS: CALL GET_CURSOR ;Is cursor in character box? JNZ DO_ENTER ;If yes, process as if Enter. CMP LEFT_BUTTON,0 ;Else, left button press JZ TURN_OFF ; will turn on pixel. CALL GET_PIXEL ;Get the pixel. OR [DI],AH ;Turn it on. JMP SHORT BUTTON_END TURN_OFF: CALL GET_PIXEL ;Right button will turn off pixel XOR AH,0FFH ;Invert bit mask. AND [DI],AH ;Turn it off. BUTTON_END: CALL UPDATE_CURSOR ;Update the cursor. CALL LOAD_CHAR ;Load the character. RET ;--------------------------------; ENTER: CALL GET_CURSOR ;Is cursor in character box? JZ ENTER_END ;If no, ignore. DO_ENTER: CALL GET_CHAR ;Else, get the highlighted char. MOV EDIT_CHAR,AL ;Store it as new edit char. CALL NEW_CHAR ;Display the edit character. ENTER_END: RET ;--------------------------------; LEFT: MOV BP,0FFH ;Movement = 0 rows; -1 cols. JMP SHORT ARROWS RIGHT: MOV BP,1 ;Movement = 0 rows; +1 cols. JMP SHORT ARROWS UP: MOV BP,0FF00H ;Movement = -1 rows; 0 cols. JMP SHORT ARROWS DOWN: MOV BP,100H ;Movement = +1 rows; 0 cols. ARROWS: CALL RESTORE ;Restore current cursor position. CALL GET_CURSOR ;Cursor in edit box? MOV CX,BP JNZ CHAR_ARROW ;If no, do character movement. ADD CL,CL ;Else, double up col. movement. CALL CK_BOUNDS ;Move cursor; check the boundary. SUB AX,EDIT_TOP ;AX has position; make relative. MOV EDIT_CURSOR,AX ;Store as new edit cursor. MOV BH,LAST_PIXEL ;Retrieve the last pixel. CALL GET_PIXEL ;Get pixel in new position. CMP SHIFT_STATE,0 ;Button or Shift key depressed? JZ UPDATE_PIXEL2 ;If no, update new cursor pos. OR BH,BH ;Else, was last pixel on? JNZ BIT_ON ;If yes, drag to new position. XOR AH,0FFH ;Else, invert mask AND BYTE PTR [DI],AH; ; and drag pixel off. JMP SHORT UPDATE_PIXEL1 BIT_ON: OR BYTE PTR [DI],AH ;Turn the pixel on. UPDATE_PIXEL1: CALL LOAD_CHAR ;Load the character. UPDATE_PIXEL2: CALL UPDATE_CURSOR ;Update the cursor display. RET ;--------------------------------; CHAR_ARROW: CALL CK_BOUNDS ;Move cursor; check the boundary. SUB AX,CHAR_TOP ;Convert to relative position. MOV CHAR_CURSOR,AX ;Store new character box pos. CMP SHIFT_STATE,0 ;Button or Shift key depressed? JZ CHAR_END ;If no, done here. NEW_CHAR: CALL GET_CHAR ;Else, get the character MOV EDIT_CHAR,AL ; and use as new edit character. CALL DISPLAY_FONT ;Display it. CHAR_END: CALL UPDATE_CURSOR ;Update the cursor display. RET ;--------------------------------; PGUP: DEC EDIT_CHAR ;Next lower edit character. JMP SHORT PAGE_END PGDN: INC EDIT_CHAR ;Next higher edit character. PAGE_END: CALL SETUP_END ;Display it. RET ;--------------------------------; TAB: CALL RESTORE ;Restore current cursor position. XOR EDIT_FLAG,1 ;Toggle Edit/char active box. CALL UPDATE_CURSOR ;Display cursor in new box. RET ;--------------------------------; SPACE_BAR: CALL GET_CURSOR ;Is cursor in character box? JNZ SPACE_END ;If yes, ignore. CALL GET_PIXEL ;Else, get the pixel. XOR [DI],AH ;Toggle the pixel. CALL UPDATE_PIXEL1 ;Update character and cursor. SPACE_END: RET ;--------------------------------; DEL_ROW: CALL GET_CURSOR ;Is cursor in character box? JNZ DELETE_RETURN ;If yes, ignore. MOV BP,POINTS ;Else, retrieve scan line points. CMP BP,1 ;Is there only one scan line? JZ DELETE_RETURN ;If yes, ignore. MOV AL,AH ;Else, delete position equals XOR AH,AH ; POINTS - relative ROW. SUB BP,AX CALL CLEAR_MENU ;Clear part of the menu and MOV DX,OFFSET WARNING_MSG ; display warning message. CALL PRINT_STRING CALL QUERY ;Should we delete? JNZ DELETE_END ;If no, done here. MOV BX,POINTS ;Else, retrieve bytes/char. MOV SI,OFFSET EDIT_FONT ;Delete edit font. CALL DELETE MOV SI,OFFSET TEMPLATE_FONT ;Do same to template font. CALL DELETE DEC BX ;One less byte/char. MOV BH,BL CMP BYTE PTR EDIT_CURSOR + 1,BL ;Was last row deleted? JNZ LOAD_IT ;If no, OK. DEC BL ;Else, move cursor up one MOV BYTE PTR EDIT_CURSOR + 1,BL ; row so it's on new char. LOAD_IT: MOV BP,OFFSET EDIT_FONT CALL USER_LOAD ;Load the new font. CALL INFORMATION ;Get font information. MOV MODIFY_FLAG,1 ;Note that font's been modified. CALL CLS ;Clear the old display. DELETE_END: XOR DX,DX CALL SET_CURSOR CALL DISPLAY_COPY ;Display new font. DELETE_RETURN: RET ;-----------------; DELETE: MOV DI,SI ;Destination starts at source. MOV CX,256 ;256 characters to do. NEXT_DELETE: PUSH CX ;Save character count. MOV CX,BX ;BX has bytes/character. CK_SKIP: CMP CX,BP ;Is this the row to delete? JZ SKIP_ROW ;If yes, skip it. MOVSB ;Else, move it down. JMP SHORT LOOP_DELETE SKIP_ROW: INC SI ;Skip deletion row. LOOP_DELETE: LOOP CK_SKIP ;Do all character rows. POP CX LOOP NEXT_DELETE ;Do all 256 characters. RET ;--------------------------------; INS_ROW: XOR BL,BL ;Insert a zero byte. JMP SHORT INS_EDIT ;--------------------------------; DUP_ROW: MOV BL,-1 ;Insert a duplicate byte. INS_EDIT: CALL GET_CURSOR ;Is cursor in character box? JNZ INSERT_END ;If yes, ignore. MOV BH,AH ;Row to be inserted. INC BH ;Adjust. MOV BP,POINTS ;Retrieve bytes/char. CMP BP,MAX_LINES ;Character maxed out? JZ INSERT_END ;If yes, done here. STD ;Else, backward moves. MOV SI,OFFSET EDIT_FONT ;Insert a row. CALL INSERT MOV SI,OFFSET TEMPLATE_FONT ;Do same to template font. CALL INSERT CLD ;String operation back forward. MOV BX,BP ;Increment bytes/character. MOV BH,BL INC BH MOV BP,OFFSET EDIT_FONT ;Load the new font. CALL USER_LOAD CALL INFORMATION ;Get font information. MOV MODIFY_FLAG,1 ;Note that font's been modified. CALL SETUP_END ;Display new font. INSERT_END: RET ;-----------------; INSERT: MOV AX,BP ;Go to end of font MOV CX,256 ; (256 * points) - 1 MUL CX DEC AX ADD SI,AX MOV DI,SI ADD DI,CX ;New font = old font + 256. NEXT_INSERT: PUSH CX ;Save character count. MOV CX,BP ;Retrieve bytes/char. MOVE_BYTE: MOVSB ;Move a byte. CMP CL,BH ;Is there an insert row? JNZ LOOP_INSERT MOV AL,BL ;If yes, assume zero insert. OR BL,BL ;Is zero to be inserted? JZ INSERT_IT ;If yes, guessed right. MOV AL,[SI+1] ;Else, duplicate with byte below. INSERT_IT: STOSB ;Insert it. LOOP_INSERT: LOOP MOVE_BYTE ;Do all bytes/char. POP CX LOOP NEXT_INSERT ;Do all 256 characters. RET ;--------------------------------; COPY_TEMP: CALL GET_PIXEL ;Get index to current char. MOV DI,SI ;Destination = Source+(16 * 256). ADD SI,MAX_POINTS * 256 MOV CX,POINTS ;Bytes/character to copy. REP MOVSB ;Copy them. CALL SETUP_END ;Update the display. CALL LOAD_CHAR ;Load the new character. RET ;--------------------------------; SAVE: CMP FILE_FLAG,1 ;Is there a filename? JZ SAVE_IT ;If yes, save it. CALL CLS ;Else, clear screen. CALL GET_NAME ;Get a filename. PUSHF ;Save results. CALL DISPLAY_HEAD ;Redisplay menu. POPF ;Retrieve results. JC SAVE_END ;If user aborted, skip save. SAVE_IT: CALL SAVE_FILE ;Save the file. SAVE_END: RET ;*********** END OF COMMAND PROCESSING ROUTINES ***********; ;---------------------------; ; OUTPUT ; ; If Edit cursor, ZF = 1 ; ; If Char cursor, ZF = 0 ; ; DX = cursor position. ; ; AX = relative position. ; ;---------------------------; GET_CURSOR: MOV AX,EDIT_CURSOR ;Assume edit cursor; retrieve it. MOV DX,AX ;Cursor position = relative ADD DX,EDIT_TOP ; position + top left of edit box CMP EDIT_FLAG,1 ;Are we in edit box? JZ CURSOR_END ;If yes, guessed right. MOV AX,CHAR_CURSOR ;Else, retrieve char. cursor. MOV DX,AX ;Calculate cursor position. ADD DX,CHAR_TOP CURSOR_END: RET ;---------------------------------------------------; ; Return highlighted cursor position to background. ; ;---------------------------------------------------; RESTORE: MOV BL,ATTRIBUTE ;Background attribute. CALL GET_CURSOR ;Is cursor in character box? JNZ CHAR_RESTORE ;If yes, restore char box. CALL GET_PIXEL ;Else, get pixel and write. CALL WRITE_PIXEL RET CHAR_RESTORE: CALL GET_CHAR ;Get character and write. CALL WRITE_CHAR RET ;--------------------------------; ; Highlight new cursor position. ; ;--------------------------------; UPDATE_CURSOR: MOV BL,ATTRIBUTE ;Retrieve background attribute. OR BL,INTENSITY ;Turn on intensity bit. CALL GET_CURSOR ;Is cursor in character box? JNZ DO_CHAR ;If yes, do character cursor. FONT_CURSOR: CALL GET_PIXEL ;Else, get pixel and write it. CALL WRITE_PIXEL RET DO_CHAR: CALL GET_CHAR ;Retrieve character. MOV DI,OFFSET BLANKS ;Use inverse video for invisible MOV CX,3 ; characters 0, 32 and 255. REPNZ SCASB JNZ DO_CURSOR MOV BL,INVERSE DO_CURSOR: CALL WRITE_CHAR ;Update the character cursor. RET ;-----------------------------------; ; INPUT ; ; AX = Relative cursor position. ; ; DX = Actual cursor position. ; ; CX = Direction. ; ; ; ; OUTPUT ; ; DX = New cursor position. ; ; AX = New cursor position. ; ; BX preserved. ; ;-----------------------------------; CK_BOUNDS: ADD DH,CH ;Add row direction ADD DL,CL ; and column direction. PUSH BX ;Save BX. MOV BL,16 ;Use 16 as bounds for char. CMP EDIT_FLAG,1 ; box bottom. JNZ CK_LEFT ;Use bytes/char bounds for edit MOV BX,POINTS ; box bottom. CK_LEFT: ADD AL,CL ;Add column to relative pos. JGE CK_RIGHT ADD DL,16 ;If too far left, JMP SHORT BOUNDS_END ; wrap to right. CK_RIGHT: CMP AL,16 ;If too far right, JB CK_UP SUB DL,16 ; wrap to left. CK_UP: ADD AH,CH ;Add row to relative position. JGE CK_DOWN ADD DH,BL ;If too far up, JMP SHORT BOUNDS_END ; wrap to bottom CK_DOWN: CMP AH,BL ;If too far down, JB BOUNDS_END ; wrap to top. MOV DH,EDIT_ROW BOUNDS_END: MOV AX,DX ;Return copy of cursor position. POP BX ;Restore BX. RET ;----------------------------------; ; INPUT ; ; AX = Relative cursor position. ; ; ; ; OUTPUT ; ; AL = character. ; ;----------------------------------; GET_CHAR: MOV CL,4 ;Character = row * 16 + column. SHL AH,CL ADD AL,AH RET ;-------------------; ; Font information. ; ;-------------------; INFORMATION: MOV BH,2 ;Get information. MOV AX,1130H INT 10H PUSH CS ;Restore extra segment. POP ES MOV POINTS,CX ;Store bytes/character. MOV ROWS,DL ;Store rows on screen. RET ;----------------------------------------------------------------; ; Filename is parsed of white space and COM extension tacked on. ; ;----------------------------------------------------------------; PARSE_FILE: MOV SI,81H ;Point to parameter. NEXT_PARSE: LODSB ;Get a byte. CMP AL,SPACE ;Is it leading space? JZ NEXT_PARSE ;If yes, ignore. CMP AL,TAB_CHAR ;Is it leading tab? JZ NEXT_PARSE ;If yes, ignore. DEC SI ;Adjust pointer. MOV FILENAME,SI ;Store start of filename. FIND_END: LODSB ;Get a byte. CMP AL,SPACE ;Is it space or below? JBE PARSE_END ;If yes, end of filename. CMP AL,"a" ;Capitalize. JB CK_DOT CMP AL,"z" JA CK_DOT AND BYTE PTR [SI-1],5FH CK_DOT: CMP AL,"." ;Is it a dot? JNZ FIND_END ;If no, continue. PARSE_END: MOV DI,SI ;Else, if dot or end of filename DEC DI ; tack on ".COM". MOV SI,OFFSET COM MOV CX,5 REP MOVSB RET ;-----------------------------; ; OUTPUT ; ; If file exists, CY = 0 ; ; If file not found, CY = 1 ; ;-----------------------------; OPEN_FILE: MOV DX,FILENAME MOV AX,3D02H ;Open file for reading, writing. INT 21H SAVE_HANDLE: MOV FILE_HANDLE,AX ;Save filehandle. MOV BX,AX RET ;------------------------; ; OUTPUT ; ; If successful CY = 0 ; ; If failed CY = 1 ; ;------------------------; CREATE_FILE: MOV DX,FILENAME XOR CX,CX ;Create normal file. MOV AH,3CH INT 21H JC CREATE_END CALL SAVE_HANDLE ;If successful, save filehandle CALL SAVE_FILE ; and save font file. CREATE_END: RET ;-----------------------------------------------------------------------; ; Read the parsed file. Check if legitimate font file. Load the font. ; ;-----------------------------------------------------------------------; READ_FILE: MOV BX,FILE_HANDLE ;Retrieve filehandle. MOV DX,OFFSET LOADER ;Point to loader. MOV CX,LOADER_LENGTH ;Bytes to read. MOV AH,3FH ;Read from disk. INT 21H MOV SI,OFFSET PROGRAMMER1 ;Use name as legitimate font MOV DI,OFFSET PROGRAMMER2 ; file signature. MOV CX,SIGNATURE_LEN / 2 REPZ CMPSW JZ READ_END CALL DISP_FILENAME MOV DX,OFFSET NOT_FONT_MSG ;If not font file, exit JMP ERROR_MSG ; with message. READ_END: MOV FILE_FLAG,1 ;Else, note that filename found. PUSH BX ;Save filehandle. MOV BP,OFFSET EDIT_FONT ;Point to font. MOV BH,BYTE PTR POINTS ;Bytes/character. CALL USER_LOAD ;Load the font. CALL INFORMATION ;Get font information. POP BX ;Retrieve filehandle. ;--------------------------------; CLOSE_FILE: MOV AH,3EH INT 21H RET ;--------------------------------; SAVE_FILE: CALL OPEN_FILE ;Open the file and write MOV DX,OFFSET LOADER ; font image and loader to disk. MOV CX,LOADER_LENGTH MOV AH,40H INT 21H MOV MODIFY_FLAG,0 ;Reset modify flag. MOV FILE_FLAG,1 ;Note that have a filename. JMP SHORT CLOSE_FILE ;-------------------------------; ; INPUT ; ; SI = first string to write. ; ; ; ; OUTPUT ; ; If "Y"es pressed, ZF = 1 ; ; Else, ZF = 0 ; ;-------------------------------; PROMPT: CALL TTY_STRING ;Write preface string. CALL DISP_FILENAME ;Write filename. QUERY: MOV SI,OFFSET YES_NO ;Write query string. CALL TTY_STRING CALL GET_KEY ;Get a response. CMP AH,Y_SCAN ;Check if "Y" pressed. RET ;-------------------------------; ; OUTPUT ; ; If name valid, CY = 0 ; ; If invalid or abort, CY = 1 ; ;-------------------------------; GET_NAME: MOV DX,OFFSET FILENAME_MSG ;Ask for filename. CALL PRINT_STRING MOV DI,81H ;Use PSP's DTA for input. NEXT_NAME: CALL GET_KEY ;Get a keystroke. CMP AH,ESC_SCAN ;Esc? STC JZ NAME_END ;If yes, abort with CY = 1. CMP AH,LEFT_ARROW ;Backspace with left arrow JZ DO_BS ; or backspace key. CMP AH,BS_SCAN JZ DO_BS CMP AH,ENTER_SCAN ;If Enter key, done here. JZ STORE_BYTE CMP AL,SPACE ;Ignore space and below. JBE NEXT_NAME JMP SHORT STORE_BYTE DO_BS: DEC DI ;TTY Backspace = the characters MOV AL,8 ; 8, space and 8. PUSH AX CALL WRITE_TTY MOV AL,SPACE CALL WRITE_TTY POP AX JMP SHORT DISPLAY_BYTE STORE_BYTE: STOSB CMP AH,ENTER_SCAN ;Done if Enter. JZ PARSE_IT DISPLAY_BYTE: CALL WRITE_TTY ;Echo input to screen. JMP SHORT NEXT_NAME PARSE_IT: CALL PARSE_FILE ;Parse the filename. CALL OPEN_FILE ;See if it exists. JC CREATE_IT ;If no, create it. MOV SI,OFFSET EXIST_MSG ;Else, ask if should write CALL PROMPT ; over existing file. JNZ GET_NAME CREATE_IT: CALL CREATE_FILE ;Create the file. JNC NAME_END MOV DX,OFFSET FAILED_MSG ;If failed, inform user CALL PRINT_STRING ; and ask for new filename. JMP SHORT GET_NAME NAME_END: RET ;--------------------------------------; ; OUTPUT ; ; AH = Bit mask ; ; AL = PIXEL_ON or PIXEL_OFF ; ; SI = Pointer to start of Character ; ; DI = Pointer to start of Scan Line ; ; PIXEL = 0 or -1 ; ;--------------------------------------; GET_PIXEL: MOV SI,OFFSET EDIT_FONT ;Point to start of edit font. CALL CHAR_START ;Index to current character. MOV DI,SI ;Also into DI. MOV CX,EDIT_CURSOR ;Retrieve edit cursor. SHR CL,1 ;Two col/bit so divide by two. MOV AH,10000000B ;Bit starts in most significant. SHR AH,CL ;Shift bit to column position. MOV CL,CH ;Row in CL. XOR CH,CH ;Zero in high half. ADD DI,CX ;Add to character start. MOV CL,[DI] ;Retrieve the current byte. MOV AL,PIXEL_OFF ;Assume it is off. MOV LAST_PIXEL,0 AND CL,AH ;AND with bit mask. JZ END_PIXEL ;If off, guessed right. MOV AL,PIXEL_ON ;Else, pixel is on. MOV LAST_PIXEL,-1 END_PIXEL: RET ;--------------------------------; WRITE_PIXEL: CALL WRITE_CHAR ;Two characters/pixel. INC DL CALL WRITE_CHAR INC DL RET ;----------------------------; ; INPUT ; ; SI = Font start. ; ; ; ; OUTPUT ; ; AX = Edit character. ; ; SI = Start of character. ; ;----------------------------; CHAR_START: MOV CX,POINTS ;Retrieve bytes/character. MOV AL,EDIT_CHAR ;Retrieve edit character. XOR AH,AH ;Zero in high half. PUSH AX ;Preserve character. MUL CL ;Char start = bytes/char * char. ADD SI,AX ;Add to index. POP AX ;Retrieve character. RET ;--------------------------------------------; ; OUTPUT ; ; AH = ASCII character. ; ; AL = Scan code. ; ; BUTTONS = button pressed. ; ; SHIFT_STATE = Shift or button depressed. ; ;--------------------------------------------; GET_INPUT: XOR BP,BP ;Store input in BP; start with 0. MOV SHIFT_STATE,0 ;Zero in Shift state. MOV BUTTONS,0 ;Zero in Buttons also. CMP MOUSE_FLAG,1 ;Is the mouse active? JNZ CK_KEYBOARD ;If no, skip mouse poll. XOR BX,BX ;Left button. MOV AX,5 ;Button press information. INT 33H OR SHIFT_STATE,AL ;Store button depressed info. OR LEFT_BUTTON,BL ;Store button press info. MOV BX,1 ;Do same for right button. MOV AX,5 INT 33H OR RIGHT_BUTTON,BL ;Store button pressed info. CMP BUTTONS,0 ;Any button pressed? JNZ INPUT_END ;If yes, done here. MOUSE_MOTION: MOV AX,0BH ;Read mouse motion. INT 33H ADD CX,HORIZONTAL ;Add in last horizontal motion. ADD DX,VERTICAL ; and last vertical motion. MOV AX,MICKEY ;Retrieve mouse unit of motion. MOV SI,RIGHT_ARROW ;Assume right movement. CMP CX,AX ;Is horizontal > mickey? JG HORIZ ;If yes, guessed right. MOV SI,DN_ARROW ;Assume down movement. CMP DX,AX ;Is vertical > mickey? JG VERT ;if yes, guessed right. NEG AX ;Else, negate mickey. MOV SI,LEFT_ARROW ;Assume left movement. CMP CX,AX ;Is horizontal < mickey? JL HORIZ ;If yes, guessed right. MOV SI,UP_ARROW ;Assume up movement. CMP DX,AX ;Is vertical < mickey? JGE STORE_MOTION ;If yes, guessed right. VERT: SUB DX,AX ;Subtract vertical mickey. JMP SHORT STORE_SCAN ;Update vertical. HORIZ: SUB CX,AX ;Subtract horizontal mickey. STORE_SCAN: MOV BP,SI ;Store scan code in BP. STORE_MOTION: MOV HORIZONTAL,CX ;Update movements. MOV VERTICAL,DX CK_KEYBOARD: MOV AH,2 ;Keyboard Shift state. INT 16H AND AL,SHIFT_KEYS ;Mask off all but Shift keys. OR SHIFT_STATE,AL ;Store Shift state. MOV AH,1 ;Keystroke status. INT 16H JZ STORE_INPUT ;If none available, done here. CALL GET_KEY ;Else, get keystroke XCHG AL,AH ;Exchange scan/ASCII code. JMP SHORT INPUT_END STORE_INPUT: MOV AX,BP ;Return input in AX OR AX,AX ;Is there input? JNZ INPUT_END ;If yes, done here. CMP BUTTONS,0 ;Is there button pressed? JNZ INPUT_END ;If yes, done here. JMP GET_INPUT ;Else, wait until input. INPUT_END: RET ;--------------------------------; DISPLAY_FONT: MOV AL,ROWS ;Retrieve rows on screen. INC AL ;Zero based; adjust. MOV DX,34EH ;Display at Row 2; Col. 77. MOV CX,3 ;Three bytes to write. MOV BL,ATTRIBUTE ;Use background attribute. CALL DIVIDE ;Display the number. MOV DX,BOX_TOP + 103H ;Point to inside of info box. MOV AL,EDIT_CHAR ;Retrieve character. CALL WRITE_CHAR ;Display it. ADD DL,7 ;Move to end of number col. MOV CX,3 ;Three bytes to write. CALL DIVIDE ;Display the number. MOV BP,TEMPLATE_TOP ;Display template character. MOV SI,OFFSET TEMPLATE_FONT CALL UPDATE_FONT MOV BP,EDIT_TOP ;Display edit character. MOV SI,OFFSET EDIT_FONT UPDATE_FONT: CALL CHAR_START ;Retrieve index to character. NEXT_LINE: LODSB ;Get a byte. MOV AH,AL ;Store in AH. MOV DI,AX ;Store in DI. PUSH CX ;Preserve bytes/char. MOV CX,8 ;Eight bits/byte. MOV DX,BP ;Top left of font display. NEXT_PIXEL: RCL DI,1 ;Get a bit. MOV AL,PIXEL_ON ;Assume it's on. JC DISPLAY_IT ;Did bit end up in carry flag? MOV AL,PIXEL_OFF ;If no, guessed wrong; pixel off. DISPLAY_IT: CALL WRITE_PIXEL ;Display the pixel. LOOP NEXT_PIXEL ;Do all 8 pixels. ADD BP,100H ;Next display row. POP CX ;Retrieve bytes/char. LOOP NEXT_LINE ;Do all rows. RET ;---------------------------; ; INPUT ; ; Entry point = DIVIDE. ; ; AL = Number to display. ; ; BL = Attribute. ; ; CX = Places to display. ; ; DX = Cursor position. ; ;---------------------------; NEXT_COUNT: MOV AH,SPACE ;Assume zero. OR AL,AL ;Is it a zero? JZ ASCII ;If yes, display space instead. DIVIDE: MOV BH,10 ;Divisor of ten. XOR AH,AH ;Zero in high half. DIV BH ;Divide by ten. ADD AH,"0" ;Convert to ASCII. ASCII: XCHG AL,AH ;Remainder in AL. CALL WRITE_CHAR ;Display it. XCHG AL,AH ;Back to AH. DEC DL ;Move back one column. LOOP NEXT_COUNT ;Display all three bytes. RET ;---------------------; ; INPUT ; ; AL = Character ; ; BL = Attribute ; ; AX, CX preserved. ; ;---------------------; WRITE_CHAR: PUSH AX PUSH CX CALL SET_CURSOR MOV CX,1 MOV AH,9 ;Write attribute/character. INT 10H POP CX POP AX RET ;------------------------------------------------------------------------------; ; The Ega/Vga registers are programmed to access segment A000h where the ; ; fonts are stored. The font is retrieved and registers reset back to normal. ; ;------------------------------------------------------------------------------; RETRIEVE_FONT: MOV SI,OFFSET ACCESS_A000H ;Point to access parameters. CALL SET_REGISTERS ;Set the registers. MOV BX,POINTS ;Retrieve bytes/character. MOV AX,0A000H ;Point to font segment. MOV DS,AX MOV DI,OFFSET EDIT_FONT ;Point to destination. MOV BP,256 ;256 characters. XOR DX,DX ;Source starting offset of zero. NEXT_CHAR: MOV SI,DX ;Point to source. MOV CX,BX ;Bytes/character. REP MOVSB ;Retrieve the bytes. ADD DX,20H ;Next character two paragraphs. DEC BP ;Do all 256 characters. JNZ NEXT_CHAR PUSH CS ;Restore data segment. POP DS MOV SI,OFFSET EDIT_FONT ;Copy the edit font to template. MOV DI,OFFSET TEMPLATE_FONT MOV CX,MAX_POINTS * 256 / 2 REP MOVSW MOV SI,OFFSET PROTECT_A000H ;Point to normal parameters. SET_REGISTERS: MOV CX,2 ;Two sequencer registers. MOV DX,3C4H ;Indexing register. CALL NEXT_REGISTER MOV CX,3 ;Three graphics controller regs. MOV DL,0CEH ;Indexing registers. NEXT_REGISTER: LODSB ;Get index. OUT DX,AL INC DX LODSB ;Get value. OUT DX,AL DEC DX LOOP NEXT_REGISTER RET ;-----------------------------------------------------; ; Similar to RETRIEVE_FONT procedure except character ; ; is uploaded instead of entire font down loaded. ; ;-----------------------------------------------------; LOAD_CHAR: MOV SI,OFFSET ACCESS_A000H CLI CALL SET_REGISTERS MOV SI,OFFSET EDIT_FONT ;Point to character CALL CHAR_START ; to upload. PUSH CX ;Preserve bytes/char. MOV CL,5 ;32 bytes record for A000h font. SHL AX,CL ;Index to appropriate character. MOV DI,AX POP CX MOV AX,0A000H ;Point to font segment. MOV ES,AX REP MOVSB ;Upload the bytes. PUSH CS ;Restore extra segment. POP ES MOV SI,OFFSET PROTECT_A000H CALL SET_REGISTERS STI MOV MODIFY_FLAG,1 ;Note that font modified. RET ;--------------------------------; SET_CURSOR: PUSH AX XOR BH,BH MOV AH,2 ;Set cursor position. INT 10H POP AX RET ;--------------------------------; HIDE_CURSOR: MOV DH,ROWS INC DH XOR DL,DL ;Hide cursor one row below CALL SET_CURSOR ; displayable rows. RET ;--------------------------------; CLEAR_MENU: MOV CX,100H ;Row 1; column zero. MOV DX,34FH ;Row 3; column 79. JMP SHORT SCROLL CLS: XOR CX,CX ;Row zero; column zero. MOV DH,ROWS ;Rows. MOV DL,79 ;Column 79. SCROLL: MOV BH,7 ;Attribute. MOV AX,600H ;Scroll window of active page. INT 10H XOR DX,DX CALL SET_CURSOR RET ;--------------------------------; GET_KEY: XOR AH,AH INT 16H RET ;--------------------------------; PRINT_STRING: MOV AH,9 INT 21H RET ;--------------------------------; DISP_FILENAME: MOV SI,FILENAME JMP SHORT TTY_STRING ;-----------------; DO_WRITE: CALL WRITE_TTY TTY_STRING: LODSB OR AL,AL JNZ DO_WRITE RET ;-----------------; WRITE_TTY: MOV AH,0EH INT 10H RET ;--------------------------------; DO_CHAR_ATTR: CALL WRITE_CHAR INC DL CHAR_ATTRIB: LODSB OR AL,AL JNZ DO_CHAR_ATTR RET ;--------------------------------; SETUP: CLI ;No interrupts. CALL RETRIEVE_FONT ;Retrieve font. STI ;Interrupts back on. CMP BYTE PTR DS:[80H],0 ;Command line parameter? JZ CK_MOUSE ;If no, skip to mouse. CALL PARSE_FILE ;Else, parse the parameter. CALL OPEN_FILE ;Try to open the file. JC CREATE_PROMPT ;If not found, ask to create. CALL READ_FILE ;Else, read the file. JMP SHORT CK_MOUSE ;Done here. CREATE_PROMPT: MOV SI,OFFSET CREATE_MSG ;Display create query. CALL PROMPT JZ CREATE ;If got thumbs up, create it. JMP ERROR_EXIT ;Else, exit. CREATE: CALL CREATE_FILE ;Create the file. MOV DX,OFFSET FAILED_MSG ;If failed, exit with message. JNC CK_MOUSE JMP ERROR_MSG CK_MOUSE: XOR AX,AX ;Mouse reset and status. INT 33H OR AX,AX ;Is mouse active? JZ DISPLAY_HEAD ;If no, skip. MOV MOUSE_FLAG,1 ;Else, flag. DISPLAY_HEAD: CALL CLS ;Clear the screen. DISPLAY_COPY: MOV SI,OFFSET COPYRIGHT ;Display copyright in MOV BL,INVERSE ; inverse video. CALL CHAR_ATTRIB MOV DX,100H ;Row 1; column 0. CALL SET_CURSOR MOV DX,OFFSET MENU ;Display menu. CALL PRINT_STRING CMP FILE_FLAG,1 ;If filename, display it. JNZ DISPLAY_MENU CALL DISP_FILENAME DISPLAY_MENU: MOV DX,200H ;Row 2; column 0. CALL SET_CURSOR MOV DX,OFFSET MENU1 ;Display more menu. CALL PRINT_STRING MOV SI,OFFSET MENU2 MOV BL,NORMAL MOV DX,436H CALL CHAR_ATTRIB MOV DX,536H CALL CHAR_ATTRIB MOV DX,636H CALL CHAR_ATTRIB MOV SI,OFFSET CAPTIONS ;Display three captions. MOV CX,3 NEXT_CAPTION: LODSW MOV DX,AX ;Caption starting cursor pos. NEXT_CAP: LODSB CMP AL,0 ;End of string? JZ END_CAPTION CALL WRITE_CHAR ;Write the caption. INC DH ;Next row. JMP SHORT NEXT_CAP END_CAPTION: LOOP NEXT_CAPTION ;Do all three captions. MOV BL,ATTRIBUTE ;Background attribute. MOV SI,OFFSET CURRENT_BOX ;Display char/ASCII box. MOV DX,BOX_TOP ;Starting position. MOV BP,3 ;Three rows. NEXT_BOX: MOV CX,13 ;13 characters/row. NEXT_BOX_CHAR: LODSB CALL WRITE_CHAR INC DL ;Next column. LOOP NEXT_BOX_CHAR MOV DL,LOW BOX_TOP ;Starting column. INC DH ;Next row. DEC BP JNZ NEXT_BOX MOV DX,CHAR_TOP ;Display character set. XOR AL,AL ;Start with ASCII zero. NEXT_SET: MOV CX,16 ;16 bytes/row. NEXT_BYTE: CALL WRITE_CHAR INC AL ;Next character. JZ SETUP_END INC DL ;Next row. LOOP NEXT_BYTE MOV DL,LOW CHAR_TOP ;Starting column. INC DH JMP NEXT_SET SETUP_END: CALL DISPLAY_FONT ;Display the edit and template. CALL UPDATE_CURSOR ;Display the cursor. RET ;**************** FONTLOADER ****************; ; This is the code to load the font and ; ; is followed by the edit and template font ; ;********************************************; LOADER LABEL BYTE LOADER_OFFSET EQU 100H - LOADER JMP BEGINNING ; DATA AREA ; --------- DB CR,SPACE,SPACE,SPACE,CR,LF PROGRAMMER2 DB " PC Magazine ",BOX," Michael J. Mefford",0,CTRL_Z SIGNATURE_LEN EQU $ - PROGRAMMER2 CRT_MODE DB ? EDIT_CURSOR DW 102H CHAR_CURSOR DW 401H EDIT_CHAR DB 65 POINTS DW ? EDIT_FLAG DB 1 ; CODE AREA ; --------- BEGINNING: MOV AX,500H ;Active page zero INT 10H MOV AH,0FH ;Current video state. INT 10H MOV DI,OFFSET CRT_MODE + LOADER_OFFSET ;Font CRT_MODE. MOV AH,[DI] CMP AL,AH ;Same mode? JZ LOAD_FONT ;If yes, skip. MOV AL,AH ;Else, change video mode. XOR AH,AH INT 10H LOAD_FONT: MOV BP,OFFSET EDIT_FONT + LOADER_OFFSET MOV DI,OFFSET POINTS + LOADER_OFFSET MOV BH,[DI] USER_LOAD: MOV CX,256 XOR DX,DX XOR BL,BL MOV AX,1110H ;User alpha load. INT 10H RET ;Terminate. ;--------------------------------; EVEN EDIT_FONT LABEL BYTE TEMPLATE_FONT EQU EDIT_FONT + MAX_POINTS * 256 LOADER_END EQU TEMPLATE_FONT + MAX_POINTS * 256 LOADER_LENGTH EQU LOADER_END - LOADER _TEXT ENDS END START