home *** CD-ROM | disk | FTP | other *** search
- ;EMIT.A - Unix-style utility to output control characters
- ;Author: John Lene-Comeau, Industrial Control Technology, jcomeau@world.std.com
- ;Specialists in utilities and device drivers under RSX, VMS, and MS-DOS.
- ;PO Box 100632, Ft. Lauderdale, FL 33310-0632 * (305)966-0162
- ;
- ;Uncopyrighted (U) 1994 John Lene Comeau. Public Domain software.
- ;
- ;To use: emit 0x1b "[7mThis is a test",27,"[m" ;comment
- ; note that whitespace or commas can be separators
- ; text may be in single or double quotes
- ; numbers beginning with 0x are hexadecimal, with 0 are octal, otherwise decimal
- ; comment may follow, preceded by semicolon
- ; default output to screen may be overridden by using redirection
- ;
- dos equ 21h
- ;set up for stack variables
- _byte equ -1
- _word equ -2
- _dword equ -4
- ;
- stackv macro ;set up variables on stack, index to using BP
- ##if !stktop
- stktop = 0
- ##endif
- #1 equ stktop + #2
- stktop = #1
- #em
- ;
- newstate macro ;set new processing state
- mov cx,offset #1 ;move memory to memory using CX
- mov state[bp],cx
- #em
- ;
- error macro ;output message to STDERR and exit with specified errorlevel
- ##if #s2 ;if there's a string supplied
- mov cx,#s2-2 ;number of bytes in message
- ##else
- xor cx,cx ;else don't print anything
- ##endif
- mov bx,2 ;STDERR
- mov dx,offset >m1
- mov ah,40h ;dos WRITE function
- int dos ;do it
- mov ax,4c00h+#1 ;set errorlevel
- int dos ;and exit
- m1: db #2
- #em
- ;
- ;the variables themselves...
- ;
- stackv state,_word
- stackv delimiter,_word
- ;
- mov bp,sp ;get current stack pointer
- add sp,stktop ;initialize variable space on stack
- newstate start ;initialize state
- mov bx,80h ;point to input character count
- mov dl,[bx] ;get count byte
- add bl,dl ;point to end...
- inc bx ;now it does
- mov byte ptr [bx],0 ;zero-terminate it
- mov si,81h ;point DS:SI to arg string
-
- emitloop:
- lodsb ;get next byte
- jmp state[bp] ;jump to routine corresponding to state
- ;
- start:
- mov bx,offset >s1 ;load table
- call bounds ;get appropriate subroutine
- jmp >s2[bx] ;and jump to it
- s1: db 1,0,1,';',2,' ',0
- s2: dw >s3,>s4,>s5,>s6
- s3: error 1,'Usage: emit nn [nn...] ;nn is value of ASCII character'
- s4: error 0 ;exit normally
- s5: newstate waiting ;else now waiting for an arg
- jmp emitloop ;so go back and find one
- s6: error 2,'EMIT -- Error - Invalid character found'
- ;
-
- waiting:
- mov bx,offset >s1 ;load table
- call bounds ;get appropriate subroutine
- jmp >s2[bx] ;and jump to it
- s1: db 1,0,1,';',1,"'",1,'"',2,' ',1,',',8,'0'-1,1,'0',2,'9',0
- s2: dw >s3,>s3,>s4,>s4,emitloop,emitloop,>s5,>s6,>s7,>s5
- s3: error 0 ;normal exit on null or comment
- s4: newstate string ;switch to string storage state
- mov delimiter[bp],al ;store delimiter
- jmp emitloop ;loop around
- s5: error 3,'EMIT -- Error - expecting string or number'
- s6: newstate number ;start of hex or octal number
- xor dx,dx ;clear result register
- jmp emitloop ;loop back for more
- s7: newstate decimal ;start of decimal number
- xor dx,dx ;clear result register
- jmp decimal ;go straight to it with this digit
- ;
-
- string:
- or al,al ;end of command line?
- je >s1 ;error if so
- cmp al,delimiter[bp] ;otherwise, same as starting delimiter?
- je >s2 ;end of string mode if so
- mov dl,al ;else send char
- mov ah,2 ;DOS function
- int dos ;do it
- jmp emitloop
- s1: error 4,'EMIT -- Error - Unexpected termination within string'
- s2: newstate waiting ;done with string processing
- jmp emitloop ;back for more input
- ;
- number:
- mov bx,offset >s1 ;load table
- call bounds ;get subroutine offset
- jmp >s2[bx] ;jump to it
- s1: db 1,0,2,' ',1,',',1,';',1,'X',1,'x',8,'0'-1,2,'7',0
- s2: dw >s3,>s4,>s4,>s3,>s5,>s5,>s6,>s7,>s6
- s3: call numout ;output number as is (must be zero)
- error 0 ;and exit
- s4: call numout ;output the null
- jmp emitloop ;loop back for more
- s5: newstate hexadecimal ;switch to HEX processing state
- jmp emitloop ;go get the rest
- s6: error 5,'EMIT -- Error - Invalid octal digit found'
- s7: newstate octal ;switch to OCTAL processing state
- jmp octal ;and go straight to it from here
- ;
- decimal:
- mov bx,offset >s1 ;load table
- call bounds ;get subroutine offset
- jmp >s2[bx] ;jump to it
- s1: db 1,0,2,' ',1,',',1,';',8,'0'-1,2,'9',0
- s2: dw >s3,>s4,>s4,>s3,>s5,>s6,>s5
- s3: call numout ;output what we have so far
- error 0 ;exit
- s4: call numout ;output what we have
- newstate waiting ;back to fishing mode
- jmp emitloop ;go get rest of command line
- s5: error 6,'EMIT -- Error - Invalid decimal digit found'
- s6: aam 10h ;split so AL contains decimal digit
- xchg ax,dx ;switch with result register
- mov cl,10
- mul cl ;shift current result one decimal place over
- add al,dl ;and merge in current digit
- xchg ax,dx ;switch back
- jmp emitloop ;go back for more
- ;
-
- hexadecimal:
- mov bx,offset >s1 ;load table
- call bounds ;get subroutine offset
- jmp >s2[bx] ;jump to it
- s1: db 1,0,2,' ',1,',',1,';',8,'0'-1,2,'9',8,'A'-1,2,'F'
- db 8,'a'-1,2,'f',0
- s2: dw >s3,>s4,>s4,>s3,>s5,>s6,>s5,>s7,>s5,>s7,>s5
- s3: call numout ;output what we have so far
- error 0 ;exit
- s4: call numout ;output what we have
- newstate waiting ;no longer in HEX mode
- jmp emitloop ;go get rest of command line
- s5: error 7,'EMIT -- Error - Invalid hexadecimal digit found'
- s6: aam 10h ;split so AL contains decimal digit
- mov cl,4 ;8088 won't accept SHL DX,4
- shl dx,cl ;shift current result one nybble over
- add dl,al ;and merge in current digit
- jmp emitloop ;go back for more
- s7: aam 10h ;split so AL contains 1 thru 6
- add al,9 ;now make it 0xa-0xf
- mov cl,4 ;in case running on 8086/88
- shl dx,cl ;shift current result one nybble over
- add dl,al ;and merge in current digit
- jmp emitloop ;go back for more
- octal:
- mov bx,offset >s1 ;load table
- call bounds ;get subroutine offset
- jmp >s2[bx] ;jump to it
- s1: db 1,0,2,' ',1,',',1,';',8,'0'-1,2,'7',0
- s2: dw >s3,>s4,>s4,>s3,>s5,>s6,>s5
- s3: call numout ;output what we have so far
- error 0 ;exit
- s4: call numout ;output what we have
- newstate waiting
- jmp emitloop ;go get rest of command line
- s5: error 8,'EMIT -- Error - Invalid octal digit found'
- s6: aam 10h ;split so AL contains octal digit
- mov cl,3 ;in case running on 8088
- shl dx,cl ;shift current result one octal place over
- add dl,al ;and merge in current digit
- jmp emitloop ;go back for more
- ;
- numout:
- mov ah,2 ;DOS function for character output
- int dos ;do it (send DL)
- ret ;and return
- ;
-
- bounds:
- ;This routine is passed a character in AL and a table address in
- ;BX. The table consists of word entries, each with the low byte
- ;containing an action code and the high byte a character code. The
- ;action codes are:
- ; 0 - end of table
- ; 1 - char is legal
- ; 2 - chars less than or equal to this is legal
- ; 3 - chars greater than this are legal
- ; 4 - char is ignored
- ; 5 - chars <= are ignored
- ; 6 - chars > are ignored
- ; 7 - char is illegal
- ; 8 - chars <= are illegal
- ; 9 - chars > are illegal
- ;returns S set if char is illegal
- ;Z set if char is legal
- ;C set if passed bad parameters (program error) or reached end of table
- ;no flags if char is to be ignored
- ;doesn't change AX, but BX is returned as word offset to entry where
- ;match occurred. All other regs are saved.
- push dx ;save aux register
- push ax ;save character
- push bx ;save start of table
- mov ah,10 ;highest legal action code is 9
- jmp b2 ;skip cleanup routine on first entry
- b1: xchg bx,dx ;swap regs back where they belong
- inc bx ;and point to next word entry
- b2: cmp [bx],ah ;past highest legal action code?
- jnc b96 ;if so, quit
- mov dl,[bx] ;else get the action code
- xor dh,dh ;make word pointer
- shl dx,1
- inc bx ;point to character code
- cmp al,[bx] ;compare current character to it
- xchg bx,dx ;must be in BX to use indirectly
- jmp b4[bx] ;jump to appropriate action routine
- b4: dw b96 ;end of table is error, shouldn't happen
- dw b10
- dw b20
- dw b30
- dw b40
- dw b50
- dw b60
- dw b70
- dw b80
- dw b90
- b10: je b97 ;char is legal, finish up
- jmp b1 ;else loop back and try again
- b20: jbe b97
- jmp b1
- b30: ja b97
- jmp b1
- b40: je b95
- jmp b1
- b50: jbe b95
- jmp b1
- b60: ja b95
- jmp b1
- b70: je b98
- jmp b1
- b80: jbe b98
- jmp b1
- b90: ja b98
- jmp b1
- b95: xchg bx,dx ;get final address
- dec bx ;make word
- pop dx ;now get start of table
- sub bx,dx ;and make offset
- mov al,1 ;reset all the flags
- or al,al ;like this
- pop ax ;now restore the registers
- pop dx
- ret
- b96: xchg bx,dx ;same except for carry flag set before RET
- dec bx
- pop dx
- sub bx,dx
- stc ;error indicator set here
- pop ax
- pop dx
- ret
- b97: xchg bx,dx
- dec bx
- pop dx
- sub bx,dx
- xor al,al ;set Z flag
- pop ax
- pop dx
- ret
- b98: xchg bx,dx
- dec bx
- pop dx
- sub bx,dx
- or al,80h ;set S flag
- pop ax
- pop dx
- ret
-