Category : Assembly Language Source Code
Archive   : MISC_ASM.ZIP
Filename : MAKEBAR.ASM

 
Output of file : MAKEBAR.ASM contained in archive : MISC_ASM.ZIP
;======================================================================
; MAKEBAR: read a bar-definition-file (.BDF) and produce a tokenized
; .BAR file to be read by the TSR interpreter.
;----------------------------------------------------------------------
CSEG SEGMENT PUBLIC PARA 'CODE'
ASSUME CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
ORG 100H
ENTPT: JMP MAIN

COPYRIGHT DB "MAKEBAR 1.0 (c) 1987, Ziff-Davis Publishing Corp",CR,LF,'$'
AUTHOR DB 1AH,"Robert L. Hummel"

;======================================================================
; EQUATES
;----------------------------------------------------------------------
SPACE EQU 20H ;Some keys
CR EQU 0DH
LF EQU 0AH
QUOTE EQU 22H
TAB EQU 09H

INPUT_BUF_LEN EQU 4000 ;Size constants
OUTPUT_BUF_LEN EQU 46000
MENU_BUF_LEN EQU 4000
MENU_TBL_LEN EQU 4000
BUF_TOTAL = INPUT_BUF_LEN + OUTPUT_BUF_LEN + MENU_BUF_LEN + MENU_TBL_LEN

_SHIFT EQU 1 ;Internal shift flags
_CTRL EQU 2
_ALT EQU 4


;----------------------------------------------------------------------
; BUFFERS AND POINTERS
;----------------------------------------------------------------------
INPUT_HNDL DW 0 ;Handle of source file
INPUT_HNDL_PTR DW 0 ;Pointer to source file
INPUT_BUF_END DW 0FFFFH ;Used by GET_CHAR
OUTPUT_HNDL DW 0 ;Handle of output file
MENU_HEAD DW 0 ;Pointer to current menu
SHIFT_FLAGS DB 0 ;Hold current shift state

;----------------------------------------------------------------------
; COUNTERS
;----------------------------------------------------------------------
SOURCE_LINE DW 0 ;For error messages
NEW_REF DB -1 ;Two counters track menu
OLD_REF DB 0 ; references

;----------------------------------------------------------------------
; TABLES
;----------------------------------------------------------------------
CMD_TABLE LABEL BYTE ;All commands names
_ASK EQU 0 ; and their token values
A_CMD DB 'ASK',0
_CR EQU 1
C_CMD DB 'CR',0
_EXECUTE EQU 2
E_CMD DB 'EXECUTE',0
_INPUT EQU 3
I_CMD DB 'INPUT',0
_MENU EQU 4
M_CMD DB 'MENU',0
_OPTION EQU 5
O_CMD DB 'OPTION',0
_PROGRAM EQU 6
P_CMD DB 'PROGRAM',0
_TYPE EQU 7
_CMD DB 'TYPE',0
_MEND EQU 8
DB 'MEND',0
_END EQU 9
DB 'END',0
_SEND EQU 10
DB 0 ;End-of-table byte
;----------------------------------------------------------------------
KEY_NAME_TBL LABEL BYTE ;Special key names
DB "S",0,"C",0,"A",0

DB "F1",0,"F2",0,"F3",0,"F4",0,"F5",0
DB "F6",0,"F7",0,"F8",0,"F9",0,"F10",0

DB "ESC",0,"TAB",0,"ENTER",0,"BS",0

DB "HOME",0,"PGUP",0,"END",0,"PGDN",0,"INS",0
DB "DEL",0,"U",0,"D",0,"L",0,"R",0,0
;----------------------------------------------------------------------
; These keys may be combined with the CRTL and ALT keys
;----------------------------------------------------------------------
KEY_TBL_1 DB "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-=\[]",0

;----------------------------------------------------------------------
; CTRL combinations for 1234567890-= (use {c}1 for ; {c}3 for ")
;----------------------------------------------------------------------
KEY_TBL_2 DW 003BH,0FE03H,0022H,0,0,001EH,0,0,0,0,001FH,0
DW 001CH, 001BH, 001DH
;----------------------------------------------------------------------
; Scan codes for alpha keys a-z (used for ALT-alpha)
;----------------------------------------------------------------------
KEY_TBL_3 DB 01EH,30H,2EH,20H,12H,21H,22H,23H,17H,24H,25H,26H
DB 32H,31H,18H,19H,10H,13H,1FH,14H,16H,2FH,11H,2DH
DB 15H,2CH

;----------------------------------------------------------------------
; SHIFT,CTRL for enter,bs,home,pgup,end,pgdn,ins,del,up,down,left,right
;----------------------------------------------------------------------
KEY_TBL_4 DB 0DH,0FEH, 8,7FH, 47H,77H, 49H,84H, 4FH,75H
DB 51H,76H, 52H,0, 53H,0, 48H,0, 50H,0, 4BH,73H,4DH,74H

;----------------------------------------------------------------------
; FLAGS
;----------------------------------------------------------------------
MENU_FLAG DB 0 ;Non-zero when open menu blk
OPTION_FLAG DB 0 ;Non-zero when open option blk
PROGRAM_NAME_FLAG DB 0 ;Non-zero when PROGRAM cmd read

;----------------------------------------------------------------------
; MESSAGES
;----------------------------------------------------------------------
USAGE_MSG DB "Usage: MAKEBAR [path]input_file [path]output_file$"
BAD_FILE_MSG DB "Can't Open File$"
READ_MSG DB "Error Reading File$"

DUP_CMD_MSG DB "Duplicate Cmd$"
CMD_ORDER_MSG DB "Cmd Out Of Order$"
UNK_CMD_MSG DB "Unknown Cmd$"

NEST_MSG DB "MENU Without MEND$"
SYNTAX_MSG DB "Syntax Error$"
NO_NAME_MSG DB "Missing Name$"
REF_MSG DB "Bad MENU Reference$"
EOF_MSG DB "Missing END$"
DEAD_KEY_MSG DB "Dead-Key or Bad Key$"
LINE_MSG DB CR,LF,"Error At Line # $"
LINE_NUM_BUF EQU $-2

;======================================================================
; MENU FILE TOKENIZER - MAIN PROCEDURE
;----------------------------------------------------------------------
MAIN PROC NEAR

MOV AH,9 ;Display string fn
MOV DX,OFFSET COPYRIGHT ;Say who we are
INT 21H ; Thru DOS

CLD ;Strings moves forward
;----------------------------------------------------------------------
; Check the file specs given on the command line. Open the files and
; save the file handles.
;----------------------------------------------------------------------
CALL OPEN_FILES

;----------------------------------------------------------------------
; Read in the Menu-Definition-File and tokenize. Write the output to
; the new .BAR file for use with the resident interpreter.
;----------------------------------------------------------------------
CALL TOKENIZE

;----------------------------------------------------------------------
; Close and update any open files. Terminate gracefully.
;----------------------------------------------------------------------
CALL CLOSE_FILES
MOV AX,4C00H ;Terminate process
INT 21H ; Thru DOS

MAIN ENDP

;======================================================================
; OPEN_FILES - Open the file given on the command line and the working
; files needed during operation of the tokenizer.
;----------------------------------------------------------------------
OPEN_FILES PROC NEAR

MOV SI,81H ;Command line parameters
CALL OPEN_A_FILE ;Open source
MOV INPUT_HNDL,AX ;Save handle

CALL OPEN_A_FILE ;Open destination file
MOV OUTPUT_HNDL,AX ;Save handle

MOV INPUT_BUF_END,0 ;Make refresh occur
RET

OPEN_FILES ENDP

;======================================================================
; OPEN_A_FILE - Read a string from the command line and attempt to open
; it as a file.
;----------------------------------------------------------------------
OPEN_CNT DB 0 ;Switch for open function

OPEN_A_FILE PROC NEAR

CALL NON_WHITE ;Point SI to 1st nonwhite
CMP AL,CR ;If not carriage return
JNE HAVE_ARGS ; go parse arguments
NO_SPECS:
MOV DX,OFFSET USAGE_MSG ;Say how we are used
OPEN_ERR:
JMP ERROR_EXIT ;Exit thru error procedure
HAVE_ARGS:
PUSH SI ;Save start of string
CALL WHITE ;Point past end
MOV CX,SI ;End of string
POP SI ;Restore start
SUB CX,SI ;Get length of string
OR CX,CX ;If zero
JZ NO_SPECS ; no file names
MOV DI,OFFSET PATH_BUF ;Copy string here
REP MOVSB ; do it
XOR AL,AL ;Make ASCIIZ
STOSB ; put in buffer

;----------------------------------------------------------------------
; Attempt to open the file.
;----------------------------------------------------------------------
MOV AX,3D00H ;Open file for reading
CMP OPEN_CNT,0 ; if first file
JE FILE_OPEN
DEC AH ;Create file if second
FILE_OPEN:
MOV DX,OFFSET PATH_BUF ;Pathname of file
INT 21H ;Handle in AX
JNC SOURCE_OPEN ;No carry if open OK
MOV DX,OFFSET BAD_FILE_MSG
JMP OPEN_ERR
SOURCE_OPEN:
INC OPEN_CNT ;Change switch
RET

OPEN_A_FILE ENDP

;======================================================================
; Close the files to update the length.
;----------------------------------------------------------------------
CLOSE_FILES PROC NEAR

MOV AH,3EH ;Close file function
MOV BX,INPUT_HNDL ; first file
INT 21H ; Thru DOS

MOV AH,3EH ;Close file function
MOV BX,OUTPUT_HNDL ; second file
INT 21H ; Thru DOS
RET

CLOSE_FILES ENDP

;======================================================================
; TOKENIZE - Read and process the Bar Definition File (BDF).
;----------------------------------------------------------------------
TOKENIZE PROC NEAR

;----------------------------------------------------------------------
; Clear flags and reset source line counter.
;----------------------------------------------------------------------
XOR AX,AX ;Zero
MOV PROGRAM_NAME_FLAG,AL ;No program name
MOV MENU_FLAG,AL ;Not inside MENU block
MOV SOURCE_LINE,AX ;Source line counter

MOV DI,OFFSET MENU_NAME_TBL ;Fill the table with zeros
MOV CX,MENU_TBL_LEN ;Entire length
REP STOSB ; do it

CALL REFRESH_BUFFER ;Load some chars into buf
MOV DI,OFFSET OUTPUT_BUF ;Init output buffer pointer

;----------------------------------------------------------------------
; Parse the input file to find commands and arguments.
;----------------------------------------------------------------------
FIND_WORD:
CALL NON_WHITE ;Find non-white char
CMP AL,CR ;Ignore blank lines
JNE TKN_1
CALL NEXT_LINE ;Skip to next line
JMP FIND_WORD ;Continue search
TKN_1:
;----------------------------------------------------------------------
; SI points to word. Compare with known commands. Return token in AL
; or 0FFh if not recognized.
;----------------------------------------------------------------------
CALL MAKEZ ;Copy word at SI to buffer
; and make ASCIIZ
PUSH SI ;Preserve SI
MOV SI,OFFSET CMD_TABLE ;Look up word in this table
CALL TABLE_LOOKUP ;Compare cmd in buffer
POP SI ;AL = CMD # or FFh
CMP AL,0FFH ;Is error?
JNE TKN_1A ;No, valid CMD found
MOV DX,OFFSET UNK_CMD_MSG
JMP SHORT TKN_ERR
TKN_1A:
;----------------------------------------------------------------------
; If this is a PROGRAM statement, load the name of the program into the
; buffer. Must be the first command in the file.
;----------------------------------------------------------------------
CMP PROGRAM_NAME_FLAG,0 ;Test if already had PROGRAM
PUSHF ;Save result

CMP AL,_PROGRAM ;Is this PROGRAM?
JE TKN_2 ; yes, jump

POPF ;Did we have one?
JNZ TKN_4 ; yes, try next cmd
JMP TKN_7A ; no, error
TKN_2:
POPF ; yes, Did we have one?
JZ TKN_3 ; No, this is first
MOV DX,OFFSET DUP_CMD_MSG ; Yes, indicate error
JMP SHORT TKN_ERR
TKN_3:
;----------------------------------------------------------------------
; Copy the name of the program to the output buffer.
;----------------------------------------------------------------------
MOV BX,DI ;Point BX to start of buf
MOV AL,SPACE ;Fill name with spaces
MOV CX,10 ;10 chars
REP STOSB ;do it

CALL NEXT_WORD
CALL TKN_STRING ;Copy quoted string

INC PROGRAM_NAME_FLAG ;Make flag non-zero
JMP FIND_WORD ;Get next command
TKN_4:
;----------------------------------------------------------------------
; END command terminates processing.
;----------------------------------------------------------------------
CMP AL,_END ;If not END, jump
JNE TKN_4A

MOV AL,MENU_FLAG ;If no open menus
OR AL,OPTION_FLAG ; or options
JZ NO_OPENS ; then clean up
TKN_4AA:
MOV DX,OFFSET NEST_MSG ;Else, nesting error
JMP SHORT TKN_ERR
NO_OPENS:
MOV AL,NEW_REF ;If no unbalanced menu
OR AL,OLD_REF ; references
JZ REFS_OK ; write the results
MOV DX,OFFSET REF_MSG ;Else, error
TKN_ERR:
JMP ERROR_EXIT
REFS_OK:
;----------------------------------------------------------------------
; Flush the output buffer.
;----------------------------------------------------------------------
MOV DX,OFFSET OUTPUT_BUF ;Source buffer
MOV CX,DI ;End of buf
SUB CX,DX ; minus start = length
MOV AH,40H ;Write to file
MOV BX,OUTPUT_HNDL ; this handle
INT 21H ;Thru DOS
RET ;Return to top level

;----------------------------------------------------------------------
; Is this a command to start a MENU block?
;----------------------------------------------------------------------
TKN_4A:
CMP AL,_MENU
JNE TKN_6 ;Jump if not MENU

;----------------------------------------------------------------------
; If we are already inside an active menu block, either an MEND is
; missing or the menus are nested (both are errors).
;----------------------------------------------------------------------
CMP MENU_FLAG,0
JNE TKN_4AA ;Jump if in block

;----------------------------------------------------------------------
; Execute MENU block startup code. Point BX to a buffer where the
; tokenized output will be temporarily stored. When then menu block is
; closed, the addresses in the menu header will be adjusted by the length
; of the header.
;----------------------------------------------------------------------
TKN_5:
MOV BX,OFFSET MENU_BUF ;Buffer for menu tokens
MOV MENU_HEAD,DI ;Location of menu header
XOR AX,AX ;Number of OPTIONS = 0
STOSW ; placed in header (at DI)
INC MENU_FLAG ;Say we're inside menu

;----------------------------------------------------------------------
; Make sure the MENU command is followed by a name
;----------------------------------------------------------------------
CALL NEXT_WORD ;Point SI to next word
CMP AL,CR ;If CR, no name = error
JE TKN_8A
;----------------------------------------------------------------------
; If Menu name is in table, it was referenced by an earlier menu and
; the address must be put back into that command line. If it's not in
; the table, add it and point to it's address.
;----------------------------------------------------------------------
CALL MAKEZ ;Change menu name to ASCIIZ
MOV AX,MENU_HEAD ;Signal says posting
SUB AX,OFFSET OUTPUT_BUF ;Make into offset
CALL SEARCH_MENU_TABLE ;Enter in table or resolve
; reference or error
CALL NEXT_LINE ;Skip to next line
JMP FIND_WORD ;Continue parsing

;----------------------------------------------------------------------
; If not a MENU command, must be inside a block to be valid.
;----------------------------------------------------------------------
TKN_6:
CMP MENU_FLAG,0
JE TKN_7A ;Jump if outside block
TKN_7:
;----------------------------------------------------------------------
; Inside a MENU block must reside a series of OPTION blocks.
;----------------------------------------------------------------------
CMP OPTION_FLAG,0 ;Test if in option block
PUSHF ; save result

CMP AL,_OPTION
JE TKN_8 ;Jump if OPTION
POPF ;Inside option block?
JNE TKN_12 ;Jump if yes
TKN_7A:
MOV DX,OFFSET CMD_ORDER_MSG
JMP TKN_ERR
TKN_8:
POPF ;Inside option block?
JE NEW_OPTION_BLOCK ;Jump if not

;----------------------------------------------------------------------
; Close this option block by adding the SEND command.
;----------------------------------------------------------------------
MOV AL,_SEND ;Send token
CALL PUT_MENUBUF ; to buffer

;----------------------------------------------------------------------
; To start new option block, increase the option counter.
; Parse name and help line and point the pointers at them.
;----------------------------------------------------------------------
NEW_OPTION_BLOCK:
INC OPTION_FLAG ;Inside option block
MOV BP,MENU_HEAD ;Number options this MENU
INC WORD PTR [BP] ; increase by 1

;----------------------------------------------------------------------
; Save the option name
;----------------------------------------------------------------------
CALL NEXT_WORD ;Point to OPTION NAME
CMP AL,CR ;Option must have name
JNE TKN_9 ;Jump if name
TKN_8A:
MOV DX,OFFSET NO_NAME_MSG
JMP TKN_ERR
TKN_9:
CALL MAKEZ ;Make name at SI into ASCIIZ
MOV AX,BX ;Address where name is stored
SUB AX,OFFSET MENU_BUF ; from start of buffer
STOSW ; is saved in menu header

;----------------------------------------------------------------------
; Copy the option name from the asciiz buffer to the menu buffer
;----------------------------------------------------------------------
PUSH SI ;Save register
MOV SI,OFFSET PATH_BUF ;Source for copy
COPY_NAME:
LODSB ;Get char
CALL PUT_MENUBUF
OR AL,AL ;If not last byte
JNZ COPY_NAME ;continue copy
POP SI ;Restore register
CALL NEXT_WORD ;Look for help line

;----------------------------------------------------------------------
; HELP line is quoted string
;----------------------------------------------------------------------
TKN_11:
MOV AX,BX ;Offset from start of buf
SUB AX,OFFSET MENU_BUF ; is location to put
STOSW ; in header
CALL TKN_STRING

;----------------------------------------------------------------------
; Put the offset where the tokenized commands will start into the header.
;----------------------------------------------------------------------
MOV AX,BX ;Current location
SUB AX,OFFSET MENU_BUF ; minus start is offset
STOSW ;Put word
JMP FIND_WORD

;----------------------------------------------------------------------
; The MEND command requires some cleanup to be performed.
; The length of the header is calculated and added to the offsets in
; the header. Then the menu_buf is appended to the output_buf.
;----------------------------------------------------------------------
TKN_12:
CMP AL,_MEND
JNE TKN_12AA ;If not MEND, move on
;----------------------------------------------------------------------
; Close out the option block (if there was one).
;----------------------------------------------------------------------
MOV AL,_SEND ;Write send token
CALL PUT_MENUBUF
;----------------------------------------------------------------------
; Flush the buffers.
;----------------------------------------------------------------------
PUSH SI ;Save register
MOV SI,MENU_HEAD ;Address of start of menu
; in the output file
LODSW ;Number of entries in menu

MOV CX,AX ;#Words = # entries * 3
SHL CX,1 ; *2
ADD CX,AX ; +1 is same as *3

JCXZ APPEND_TOKENS ;NULL menu bailout
PUSH CX ;Save number words to update
MOV AX,CX ;Length of offset
INC AX ; plus one
SHL AX,1 ; times two

MOV CX,MENU_HEAD ;Offset of start of menu
SUB CX,OFFSET OUTPUT_BUF ; from start of buf
ADD AX,CX ; plus length of header
POP CX
UPDATE_POINTERS:
ADD WORD PTR [SI],AX ; makes pointers correct
INC SI ;Skip to next pointer
INC SI
LOOP UPDATE_POINTERS

;----------------------------------------------------------------------
; Append the tokenized menu.
;----------------------------------------------------------------------
APPEND_TOKENS:
MOV CX,BX ;End of menu buf
MOV SI,OFFSET MENU_BUF ;start of menu buf
SUB CX,SI ;# bytes to transfer
REP MOVSB ;do it
POP SI ;restore register

;----------------------------------------------------------------------
; Reset the flags.
;----------------------------------------------------------------------
MOV MENU_FLAG,0
MOV OPTION_FLAG,0
JMP FIND_WORD ;get next command

;----------------------------------------------------------------------
; Deal with commands other than PROGRAM, MENU, and OPTION
;----------------------------------------------------------------------
TKN_12AA:
CALL PUT_MENUBUF ;Put the token in the file
CMP AL,_EXECUTE ;If not execute
JNE TKN_13 ; move on

;----------------------------------------------------------------------
; EXECUTE command references another menu. Let the SEARCH_MENU_TABLE
; routine satisfy the reference, or leave a "wanted" message.
;----------------------------------------------------------------------
CALL NEXT_WORD ;Point to named menu
CMP AL,CR ;End of line?
JNE TKN_12A
JMP TKN_8A ;(out of range jump)
TKN_12A:
CALL MAKEZ ;Put name in buffer
MOV AX,0FFFFH ;= want address
CALL SEARCH_MENU_TABLE ;Try and resolve
JMP FIND_WORD

;----------------------------------------------------------------------
; Separate out commands that take arguments.
;----------------------------------------------------------------------
TKN_13:
CMP AL,_ASK ;Ask takes string
JE TKN_17
CMP AL,_TYPE ;So does type
JE TKN_17
JMP FIND_WORD ;Token already in, so go

;----------------------------------------------------------------------
; These commads require the quoted string following them to be included
; as an ASCIIZ string following the command byte.
;----------------------------------------------------------------------
TKN_17:
CALL NEXT_WORD ;Point to string
CALL TKN_STRING ;Copy it
JMP FIND_WORD

TOKENIZE ENDP

;======================================================================
; AX points to an ASCIIZ string. Look up that string in table pointed
; to by SI to see if we can find a match.
;----------------------------------------------------------------------
TABLE_LOOKUP PROC NEAR

PUSH DI ;Save registers
PUSH CX
PUSH DX

XOR CL,CL ;Command counter
CL_0:
CMP BYTE PTR [SI],0 ;End of table?
JNZ CL_2 ; jump if not
MOV CL,0FFH ;Signal error
CL_1:
MOV AL,CL ;Return cmd number
POP DX ;Restore registers
POP CX
POP DI
RET
CL_2:
MOV DI,AX ;Pointer to unknown command
CALL STR_CMP ;NC if matched
JNC CL_1
INC CL ;Point to next
JMP CL_0 ;Test for table end

TABLE_LOOKUP ENDP

;======================================================================
; Compare strings at DI,SI where SI is a table.
;----------------------------------------------------------------------
STR_CMP PROC NEAR
STR_1:
MOV DL,[DI] ;Get char from string
INC DI ;Point to next
MOV DH,[SI] ;Get char from table
INC SI ;Point to next
CMP DH,DL ;If equal
JE STR_3 ; jump
DEC SI ;Backup in table
STR_2:
MOV DH,[SI] ;Examine char in table
INC SI ;Goto next char
OR DH,DH ;Is it end of entry?
JNZ STR_2 ; no, continue scanning
STC ; return with failure
RET
STR_3:
OR DX,DX ;If both not 0
JNZ STR_1 ; continue compare
CLC ; else, they match
RET

STR_CMP ENDP

;======================================================================
; This procedure prints an error message and indicates the source line
; number on which it occured.
;----------------------------------------------------------------------
ERROR_EXIT PROC NEAR

MOV AH,9 ;Print the error message
INT 21H ; Thru DOS

MOV DI,OFFSET LINE_NUM_BUF ;Put line number here
MOV AX,SOURCE_LINE ;Contains line number
MOV BX,10 ;Base 10 numbers
LINE_LOOP:
XOR DX,DX ;Divide DX:AX by BX
DIV BX
ADD DL,30H ;Make number into ASCII

MOV [DI],DL ;Save it
DEC DI ;Move toward more significant
OR AX,AX ;If remainder not 0
JNZ LINE_LOOP ; continue

MOV DX,OFFSET LINE_MSG ;Write message
MOV AH,9 ;Display string fn
INT 21H ; Thru DOS

CALL CLOSE_FILES ;Close files and terminate
MOV AX,4CFFH ; with error=255
INT 21H ; Thru DOS

ERROR_EXIT ENDP

;======================================================================
; Position SI to the begining of the next word.
;----------------------------------------------------------------------
NEXT_WORD PROC NEAR

CALL IS_WHITE ;Is current char white?
JNC NW_1 ; yes, jump
CALL WHITE ; no, find first white
NW_1:
CALL NON_WHITE ;Scan for first non-white
RET

NEXT_WORD ENDP

;======================================================================
; Enter with SI pointing to string. Position so SI points at first
; delimiter character AFTER the present char. Return char in AL.
; AL changed, SI moved by file routines.
;----------------------------------------------------------------------
WHITE PROC NEAR

MOV AL,[SI] ;Check current char
CMP AL,CR ; for EOL
JE W_RET ; and leave
W_LOOP:
CALL GET_CHAR ;Get the next char
CMP AL,CR ;If EOL
JE W_RET ; return
CALL IS_WHITE ;Returns NC if white
JC W_LOOP
W_RET:
RET
WHITE ENDP

;======================================================================
; Enter with SI pointing to string. Position so SI points at first
; non-delimiter character AFTER the present char. Return char in AL.
; AL changed, SI moved by file routines.
;----------------------------------------------------------------------
NON_WHITE PROC NEAR

MOV AL,[SI] ;Check current char
CMP AL,CR ; for EOL
JE NW_RET ; and leave
NW_LOOP:
CALL GET_CHAR ;Get the next char
CMP AL,CR ;If EOL
JE NW_RET ; return
CALL IS_WHITE ;Returns NC if white
JNC NW_LOOP
NW_RET:
RET
NON_WHITE ENDP

;======================================================================
; Examine Char at SI and return CY if non-white, NC if delimiter
; Only flags changed.
;----------------------------------------------------------------------
DELIMS DB " ,:",LF,TAB ;White chars

IS_WHITE PROC NEAR

PUSH AX ;Save registers
PUSH CX
PUSH DI

MOV AL,[SI] ;Examine current char
MOV CX,5 ;Number delims to compare
MOV DI,OFFSET DELIMS ;Here they are
REPNE SCASB ;Compare them
CLC ;NC if delimiter
JZ IW_1 ;ZR indicates match found
STC ; else CY
IW_1:
POP DI ;Restore registers
POP CX
POP AX
RET

IS_WHITE ENDP

;======================================================================
; Make the character in AL UPPER case.
;----------------------------------------------------------------------
MAKE_UC PROC NEAR

CMP AL,'a' ;If between a and z
JB UC_1
CMP AL,'z'
JA UC_1
SUB AL,20H ;Make upper case
UC_1:
RET
MAKE_UC ENDP

;======================================================================
; Position SI to the next char after a CR. Start search with current
; char.
;----------------------------------------------------------------------
NEXT_LINE PROC NEAR

MOV AL,[SI] ;Examine current char
NL_1:
CMP AL,CR ;Is it CR?
JE NL_2 ; yes, jump
CALL GET_CHAR ; no, get next char
JMP NL_1 ; and try again
NL_2:
CALL GET_CHAR ;Go to first char after CR
RET

NEXT_LINE ENDP

;======================================================================
; This proc helps resolve references to other menus made with
; EXECUTE commands. If entered with AX=FFFF, the calling procedure has
; a reference it needs to satisfy. If an address has been entered in
; the table for that name, the address is returned and the reference is
; satisfied. If not, a "IOU" is inserted in the table.
; If entered with AX != FFFFh, the calling procedure is supplying the
; starting address of the MENU named at PATH_BUF, and asking that these
; be entered into the table to satisfy a reference. If the name is found
; in the table, left in a previous bookmark, the reference is satisfied
; and the entry is marked "USED". Any further use of that name generates
; an error.
; For a forward reference, the structure is:
; ASCIIZ string
; WORD - Address of the start of the menu that
; contains the reference (menu_head)
; WORD - Offset from the end of menu header that
; is the destination for the fix-up
; For a POST:
; ASCIIZ string
; WORD - Address in output file of menu
; WORD - 0FFFFh
; Possibilities:
; 1) Post a MENU not previously requested
; 2) Post a MENU previously requested
; 3) Request a MENU previously posted
; 4) Ask for a MENU not previously posted
;----------------------------------------------------------------------
SEARCH_MENU_TABLE PROC NEAR

PUSH SI ;Save used registers
PUSH DI
PUSH DX
PUSH CX

;----------------------------------------------------------------------
; AX=FFFF if request. AX != FFFF, then post the MENU address.
;----------------------------------------------------------------------
CMP AX,0FFFFH ;Switch = FFFF if request
JE WANT_ADR ; to satisfy reference

;----------------------------------------------------------------------
; AX contains the output file offset of a menu to post in this table.
; If the name is in the table, it was referenced earlier and we can go
; back and fix it up. If the name is NOT in the table, post it.
;----------------------------------------------------------------------
CALL MENU_LOOK ;Changes SI
JNC SMT_7 ;Match was found if NC

;----------------------------------------------------------------------
; 1) Post a menu not previously requested. No match found. Create a
; new entry for this menu. SI points to end of table.
; Copy the name from the buffer to the menu table.
;----------------------------------------------------------------------
INC NEW_REF ;Add a new reference
MOV CX,0FFFFH ;POST code
SMT_1:
MOV DI,OFFSET PATH_BUF ;Name of MENU is here
;----------------------------------------------------------------------
; Copy menu name to menu_name_table
;----------------------------------------------------------------------
SMT_5:
MOV DL,[DI] ;Get char in DL
INC DI ;Point to next
MOV [SI],DL ;Save this char in table
INC SI ;next destination
OR DL,DL ;Was that last byte?
JNZ SMT_5 ; no, get more

;----------------------------------------------------------------------
; Make AX into offset from buffer start. Save in menu table.
; CX contains either offset from menu_buf of reference or FFFF (POST).
;----------------------------------------------------------------------
MOV WORD PTR [SI],AX ;Menu at this address
MOV WORD PTR [SI][2],CX
JMP SHORT SMT_EXIT ;clean up

;----------------------------------------------------------------------
; 2) Post a MENU previously requested. SI points past the ASCIIZ name
; in the table to the location of the forward reference.
;----------------------------------------------------------------------
SMT_7:
INC OLD_REF ;Add an old reference
MOV DX,WORD PTR [SI][2] ;2nd word
CMP DX,0FFFFH ; if POST, two menus have
JE SMT_7B ; the same name (error)
CMP DX,0FFFEH ;Already referenced
JNE SMT_8 ; is also an error
SMT_7B:
MOV DX,OFFSET REF_MSG ;error
JMP ERROR_EXIT
SMT_8:
;----------------------------------------------------------------------
; SI points to address of menu as offset from start of buffer.
; SI+2 points to additional offset from end of header.
; Address of reference is [si] + 2 + 3 * 2 * [[si]] + [si+2] !
;----------------------------------------------------------------------
MOV DI,WORD PTR [SI] ;Offset into output_buf
ADD DI,OFFSET OUTPUT_BUF ;Absolute memory location
MOV CX,WORD PTR [DI] ;Number of entries in header
SHL CX,1 ; 2 bytes per word
ADD DI,CX
INC CX ; 2 for first word
SHL CX,1
ADD DI,CX

ADD DI,WORD PTR [SI][2]
MOV [DI],AX ; reference satisfied
MOV WORD PTR [SI][2],0FFFEH ;Mark this entry USED
JMP SHORT SMT_EXIT ;Clean up

;----------------------------------------------------------------------
; Try and satisfy a reference.
;----------------------------------------------------------------------
WANT_ADR:
CALL MENU_LOOK ;CY if no match
JC SMT_9

;----------------------------------------------------------------------
; 3) Request a MENU previously posted. Entry name was in table.
;----------------------------------------------------------------------
DEC NEW_REF
MOV DX,WORD PTR [SI][2] ;Second word
CMP DX,0FFFFH ; should contain POST code
JNE SMT_7B ;if not, ERROR!

MOV AX,[SI] ;Get address of menu
CALL PUT_MENUBUF ;Put lower byte
MOV AL,AH
CALL PUT_MENUBUF ;Put upper byte

MOV WORD PTR [SI][2],0FFFEH ;Mark entry used
JMP SHORT SMT_EXIT

;----------------------------------------------------------------------
; 4) Ask for a MENU not previously posted. Put an IOU in the table.
;----------------------------------------------------------------------
SMT_9:
DEC OLD_REF
MOV AX,MENU_HEAD ;First entry is offset of
SUB AX,OFFSET OUTPUT_BUF ; requesting menu

MOV CX,BX ;Second entry is offset past
SUB CX,OFFSET MENU_BUF ; the menu header

ADD BX,2 ;Leave room for address
JMP SMT_1 ;Go create table entry
SMT_EXIT:
POP CX ;Restore registers
POP DX
POP DI
POP SI
RET

SEARCH_MENU_TABLE ENDP

;======================================================================
; Look for a name in the menu. If carry is set, no match was found
; and SI points to the end of the table. If carry is clear, match was
; found and SI points to address word after entry.
; SI is changed.
;----------------------------------------------------------------------
MENU_LOOK PROC NEAR

PUSH DI ;Save registers
PUSH DX

MOV SI,OFFSET MENU_NAME_TBL ;Known names
ML_1:
CMP BYTE PTR [SI],0 ;If 0, end of table
JNE ML_3 ; else compare entry
STC ;signal error
ML_2:
POP DX ;Restore registers
POP DI
RET
ML_3:
MOV DI,OFFSET PATH_BUF ;Name to find
CALL STR_CMP ;CY if no match
JNC ML_2 ;Return result
ADD SI,4 ;Skip past addresses
JMP ML_1 ;Check next table entry

MENU_LOOK ENDP

;======================================================================
; Interpret the contents of the quoted string and write to output buffer.
; Entered with SI pointing to the beginning quote. An illegal character
; or combination produces an error and terminates processing.
;----------------------------------------------------------------------
TKN_STRING PROC NEAR

CMP BYTE PTR [SI],QUOTE ;Must point to quoted string
JNE TS_ERR ; or syntax error.

PUSH DI ;Save used register
TS_1:
MOV SHIFT_FLAGS,0 ;Clear shift flags
TS_1AA:
CALL GET_CHAR ;Get next char
CMP AL,CR ;If not CR
JNE TS_QUOTE ; go to next test
TS_ERR:
JMP SC_ERR ;Report a syntax error
TS_QUOTE:
CMP AL,QUOTE ;If quote
JNE TS_1A
TS_EXIT:
XOR AL,AL ; make string asciiz
CALL PUT_MENUBUF ; and write to buffer

CALL NEXT_LINE ;Position to next line
POP DI ;Restore register
RET ; and leave
TS_1A:
CMP AL,"{" ;Key name follows
JE SPEC_CHAR ;Go snif it out

CMP SHIFT_FLAGS,0 ;If any shift keys on
JNE DO_XLAT ; do translation
XOR AH,AH ;Else, ASCII output of AL

;----------------------------------------------------------------------
; If AH=0, output the code in AL; If AH != 0, output AH, then AL.
;----------------------------------------------------------------------
OUTPUT_CODE:
OR AH,AH ;If AH=0
JZ OC_1 ; output AL only
XCHG AH,AL ;Switch
CALL PUT_MENUBUF ;Write the high byte
XCHG AH,AL ;restore AL
OC_1:
CALL PUT_MENUBUF ;Put AL in buffer
JMP TS_1 ;Get another character

;----------------------------------------------------------------------
; These keys may be valid with CTRL and ALT, but not SHIFT
;----------------------------------------------------------------------
DO_XLAT:
CMP SHIFT_FLAGS,_SHIFT ;Is SHIFT on?
JNE TS_1B
DEAD_KEY_ERROR:
MOV DX,OFFSET DEAD_KEY_MSG ;Invalid key combo
JMP ERROR_EXIT
TS_1B:
;----------------------------------------------------------------------
; See if the key is in the table.
;----------------------------------------------------------------------
CALL MAKE_UC ;Make upper case

MOV AH,AL ;Save original char
MOV DI,OFFSET KEY_TBL_1 ;Source for compare
MOV CX,DI ;Save start of table
TS_2:
MOV AL,[DI] ;Get char from table
INC DI ;Point to next
OR AL,AL ;If 0, AL was illegal char
JE DEAD_KEY_ERROR
CMP AL,AH ;Do we have a match?
JNE TS_2 ;No, try again
DEC DI ;Backup pointer
MOV AX,DI ;Have a match if here
SUB AX,CX ;Offset into table

;----------------------------------------------------------------------
; Found a match. Tediously calculate output byte.
;----------------------------------------------------------------------
CMP AL,25 ;If A-Z
JBE IS_ALPHA ; process as alpha keys
SUB AL,26 ;Remove alpha bias

CMP SHIFT_FLAGS,_CTRL ;Go perform CTRL combos
JE TS_4
;These are ALT combos
CMP AL,11
JA DEAD_KEY_ERROR ;Too high
ADD AX,0FE78H ;Output 2 bytes
JMP OUTPUT_CODE
TS_4: ;CTRL combos
SHL AL,1 ;multiply by 2
MOV DI,OFFSET KEY_TBL_2
ADD DI,AX ;Find word in table
MOV AX,[DI] ;Load into AX
OR AX,AX ;If zero
JZ DEAD_KEY_ERROR ; this combo not allowed
JMP OUTPUT_CODE ; else write it

;----------------------------------------------------------------------
; CTRL/ALT alphabet combinations.
;----------------------------------------------------------------------
IS_ALPHA:
CMP SHIFT_FLAGS,_ALT
JE TS_5
INC AL ;ALT is simple, add 1
JMP OUTPUT_CODE
TS_5:
MOV DI,OFFSET KEY_TBL_3 ;CTRL keys combos
ADD DI,AX ;Add offset to
MOV AL,[DI] ; get char code
MOV AH,0FEH ;Signal extended ASCII
JMP OUTPUT_CODE ;Send it to buffer

;----------------------------------------------------------------------
; Here the {strings} are translated to their equivalent keystrokes.
; Move the key name into the ASCIIZ buffer.
;----------------------------------------------------------------------
SPEC_CHAR:
MOV DI,OFFSET PATH_BUF
SC_1:
CALL GET_CHAR ;Get char inside brace

CMP AL,'{' ;If doubled, use {
JNE SC_2 ;Jump for other chars
CMP DI,OFFSET PATH_BUF ;If = no chars have been
JE OC_1 ; processed yet. {{
SC_ERR:
MOV DX,OFFSET SYNTAX_MSG
JMP ERROR_EXIT
SC_2:
CMP AL,QUOTE ;If char is quote
JE SC_ERR

CMP AL,'}' ;Close brace?
JE SC_3 ; go search table
CALL MAKE_UC ;Make Upper case
STOSB ;Put char in buffer
JMP SC_1 ;Continue to copy key name
SC_3:
XOR AL,AL ;Make asciiz
STOSB
PUSH SI ;Save register
MOV SI,OFFSET KEY_NAME_TBL ;Search this table
MOV AX,OFFSET PATH_BUF ; for this entry
CALL TABLE_LOOKUP
POP SI ;Restore register

;----------------------------------------------------------------------
; Return # of entry in table or FFh if not found.
;----------------------------------------------------------------------
CMP AL,0FFH
JE SC_ERR

OR AL,AL ;0 = Turn SHIFT on
JNZ SC_4
MOV SHIFT_FLAGS,_SHIFT
JMP TS_1AA
SC_4:
DEC AL ;0 = Turn CTRL on
JNZ SC_5
MOV SHIFT_FLAGS,_CTRL
JMP TS_1AA
SC_5:
DEC AL ;0 = Turn ALT on
JNZ SC_6
MOV SHIFT_FLAGS,_ALT
JMP TS_1AA

;----------------------------------------------------------------------
; Test for the Function keys (40 combinations).
;----------------------------------------------------------------------
SC_6:
DEC AL ;Adjust key number
CMP AL,9 ;Keys 0-9
JA SC_10 ;Can't be function key
ADD AL,3BH ;Key code
MOV AH,SHIFT_FLAGS ;Test for shift states
CMP AH,_SHIFT ;For shift
JNE SC_7
ADD AL,19H ;Add 19h
SC_7:
CMP AH,_CTRL ;For CTRL
JNE SC_8
ADD AL,23H ;Add 23h
SC_8:
CMP AH,_ALT ;For ALT
JNE SC_9
ADD AL,2DH ;Add 2dh
SC_9:
MOV AH,0FEH ;Say this is extended ascii
JMP OUTPUT_CODE ;Dump the bytes

;----------------------------------------------------------------------
; ALT is not allowed for these keys.
;----------------------------------------------------------------------
SC_10:
CMP SHIFT_FLAGS,_ALT ;If Alt's not on
JNE SC_10B ; jump
SC_10A:
JMP DEAD_KEY_ERROR ; else, error
SC_10B:
SUB AL,10 ;Eliminate BIAS
JNZ SC_11
MOV AL,01BH ;ESC key
JMP OC_1
SC_11:
DEC AL ;TAB key
JNZ SC_13
CMP SHIFT_FLAGS,0 ;Any shift keys on?
JE SC_12 ; no, jump
CMP SHIFT_FLAGS,_SHIFT ;SHIFT only is allowed
JNE SC_10A ; else error
MOV AX,0FE0FH ;SHIFT-TAB
JMP OUTPUT_CODE ;to output
SC_12:
MOV AL,9 ;Normal TAB
SC_12A:
JMP OC_1

;----------------------------------------------------------------------
; These keys are the same alone or with SHIFT, but CTRL is different.
;----------------------------------------------------------------------
SC_13:
DEC AL ;Remove bias
XOR AH,AH ;Zero AH
MOV DI,OFFSET KEY_TBL_4 ;Table of SHIFT/CTRL values
SHL AX,1 ;Make into offset
ADD DI,AX ; from start of table
MOV DH,SHIFT_FLAGS ;If CTRL
CMP DH,_CTRL
JNE SC_14
INC DI ; move one byte further
SC_14:
MOV DL,[DI] ;Get char from table
OR DL,DL ; =0 if illegal
JZ SC_10A
XCHG AL,DL ;Put offset in DL
CMP DL,2 ;What key?
JE SC_12A ;If BS, all ascii
JA SC_15 ;above, all extended
CMP DH,_CTRL ;CTRL-ENTER is special
JNE SC_12A
SC_15:
MOV AH,0FEH ;Add extended code
JMP OUTPUT_CODE

TKN_STRING ENDP

;======================================================================
; Read from the BDF file into a buffer. If an EOF is found, perform
; the final cleanup and return to the main procedure.
; (must also keep track of file pointer and signal when EOF)
;----------------------------------------------------------------------
REFRESH_BUFFER PROC NEAR

PUSH BX
PUSH CX
PUSH DX

MOV AH,42H ;Move file pointer
XOR AL,AL ; offset from begining
MOV BX,INPUT_HNDL ;File handle
XOR CX,CX ;Offset CX:DX
MOV DX,INPUT_HNDL_PTR
INT 21H ;Thru DOS
JC READ_ERR

;----------------------------------------------------------------------
; Fill buffer.
;----------------------------------------------------------------------
MOV AH,3FH ;Read from handle fn
MOV BX,INPUT_HNDL
MOV CX,INPUT_BUF_LEN ;Number bytes to read
MOV SI,OFFSET INPUT_BUF
MOV DX,SI ;DS:DX destination

CMP [INPUT_HNDL_PTR],0 ;If start of file
JNE NOT_FIRST_READ
MOV BYTE PTR [SI],20H ;Make a current char
DEC CX ;Read one less byte
INC DX ;New destination
NOT_FIRST_READ:
INT 21H ;Thru DOS
JNC READ_OK
READ_ERR:
MOV DX,OFFSET READ_MSG
JMP ERROR_EXIT
READ_OK:
ADD INPUT_HNDL_PTR,AX ;Add bytes read
SUB DX,SI ;Calculate ending address
ADD AX,DX ; of our buffer
MOV INPUT_BUF_END,AX ; and save it

POP DX ;Restore registers
POP CX
POP BX
RET

REFRESH_BUFFER ENDP

;======================================================================
; Copy the word at SI into a buffer and make it asciiz
;----------------------------------------------------------------------
MAKEZ PROC NEAR

PUSH DI
MOV DI,OFFSET PATH_BUF ;Destination
PUSH DI
MZ_1:
CALL IS_WHITE ;Examine char at SI
JNC MZ_2

MOV AL,[SI] ;Get the char
CMP AL,CR ;Is it CR?
JE MZ_2 ; yes, terminate string
CALL MAKE_UC ; else, change to lower case
STOSB ; save at DI
CALL GET_CHAR ;Get next char
JMP MZ_1
MZ_2:
XOR AL,AL ;Make ASCIIZ
STOSB

POP AX ;Return buffer address
POP DI ;Restore pointer
RET

MAKEZ ENDP

;======================================================================
; Get a char from the input buffer. If past the end of the buffer,
; refresh the buffer. Check for EOF (SI = INPUT_BUF_END != BUF_LEN)
; If comments are detected, they are weeded out.
;----------------------------------------------------------------------
COMMENT_FLAG DB 0 ;=1 if inside comment

GET_CHAR PROC NEAR
;----------------------------------------------------------------------
; Check buffer for pointer past end.
;----------------------------------------------------------------------
PUSH AX ;Save register
INC SI ;Advance pointer
MOV AX,SI ;Current location
SUB AX,OFFSET INPUT_BUF ; minus start
CMP AX,INPUT_BUF_END ; longer than allowed
POP AX ;(restore pointer)
JB GC_1 ; no need to refresh
CALL REFRESH_BUFFER ;Attempt to load buffer

;----------------------------------------------------------------------
; AX contains the number of chars read. If AX=0, unexpected EOF.
;----------------------------------------------------------------------
OR AX,AX ;# chars read
JNZ GC_1 ;jump if not 0
MOV DX,OFFSET EOF_MSG
JMP ERROR_EXIT

;----------------------------------------------------------------------
; check for, and eliminate comments
;----------------------------------------------------------------------
GC_1:
MOV AL,[SI] ;Get new char
CMP AL,CR ;If new line
JNE GC_3
MOV COMMENT_FLAG,0 ; reset comment
INC SOURCE_LINE ; next line
GC_2:
CMP COMMENT_FLAG,0 ;If inside comment
JNE GET_CHAR ; read until CR
RET
GC_3:
CMP AL,';' ;If this isn't a comment
JNE GC_2 ; then continue
INC COMMENT_FLAG ;else read until CR
JMP GET_CHAR

GET_CHAR ENDP

;======================================================================
PUT_MENUBUF PROC NEAR

MOV [BX],AL ;Write byte to [bx]
INC BX ;Move pointer
RET

PUT_MENUBUF ENDP

;======================================================================
; Buffer Allocation area
;----------------------------------------------------------------------
PC = $
LAST_BYTE = PC

PATH_BUF = PC ;DB 64 DUP (?)
PC = PC + 64

INPUT_BUF = PC ;DB INPUT_BUF_LEN DUP(?)
PC = PC + INPUT_BUF_LEN

OUTPUT_BUF = PC ;DB OUTPUT_BUF_LEN DUP(?)
PC = PC + OUTPUT_BUF_LEN

MENU_BUF = PC ;DB MENU_BUF_LEN DUP(?)
PC = PC + MENU_BUF_LEN

MENU_NAME_TBL = PC ;DB MENU_TBL_ELN DUP(?)
PC = PC + MENU_TBL_LEN

;----------------------------------------------------------------------
CSEG ENDS
END ENTPT


  3 Responses to “Category : Assembly Language Source Code
Archive   : MISC_ASM.ZIP
Filename : MAKEBAR.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/