home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / ansi / isansi / isansi.a86 next >
Text File  |  1994-06-17  |  9KB  |  288 lines

  1. ;ISITANSI - check if the CON device is ANSI compatible.
  2. ;Just sends a DSR request and takes any terminated input as
  3. ;the answer. If it is of the form <CSI>n;nR then it returns
  4. ;with ERRORLEVEL 0 indicating ANSI.SYS is loaded. Otherwise
  5. ;it returns with ERRORLEVEL 1. If DOS error, ERRORLEVEL is 2.
  6. ;
  7. ;Here is a sample test program
  8. ;
  9. ;@echo off
  10. ;rem ;R-U-ANSI.BAT
  11. ;rem ;Test program for ISANSI.COM in the Assembly Language section
  12. ;rem ;of the IBMPRO forum on Compuserve. Rename it to ISITANSI.COM.
  13. ;rem ;Author John Lene Comeau, ICT, PO Box 100632, Ft. Laud. FL 33310
  14. ;rem ;Specialists in Device Drivers and Utilities on VAX/VMS, PDP/RSX,
  15. ;rem ;and PC/DOS platforms. 70641,57 on Compuserve.
  16. ;rem ;Internet address jcomeau@world.std.com
  17. ;isitansi
  18. ;cls
  19. ;if errorlevel 2 echo I don't know, there was a program error.
  20. ;if errorlevel 2 goto exit
  21. ;if errorlevel 1 echo No, I'm not.
  22. ;if errorlevel 1 goto exit
  23. ;if errorlevel 0 echo Yes, I am.
  24. ;:exit
  25. ;
  26. debug equ 1    ;set to 0 when finished debugging
  27. ;
  28. doscall    macro
  29.     clc    ;can't trust carry reg to always be cleared if success
  30.     int    21h    ;give DOS the reins
  31.     #em
  32. ;
  33. _byte    equ    -1    ;for use with stack variables
  34. esc    equ    27
  35. csi    equ    155    ;C1 (eight-bit) code for <ESC>[
  36. buffer    equ    254*_byte ;for buffer on stack
  37.     jmp    main
  38. dsr:    db    esc,'[6n$'
  39. ;tables for use with bounds_check routine:
  40. tbl1:    db    1,esc,1,csi,8,255,0
  41. ;even-numbered tables are routines to call if within bounds:
  42. tbl2:    dw    escroutine,csiroutine
  43. tbl3:    db    1,'R',4,';',8,'0'-1,9,'9',5,255,0
  44. ;
  45. main:
  46.     call    init_buffer ;set up buffer on stack
  47.     mov    dx,dsr ;point to DSR string
  48.     mov    ah,9    ;and load code for DOS console write
  49.     doscall        ;interrupt DOS for service
  50.     jc    error2    ;quit if DOS error
  51.     call    read_answer ;raw mode read no echo with timeout
  52.     jz    error1    ;quit if nothing returned
  53.     jc    error2
  54.     mov    si,di    ;point SI to buffer
  55.     mov    cx,ax    ;get byte count
  56.     lodsb        ;get the first byte
  57.     dec    cx    ;dec the count
  58.     jcxz    error1    ;quit if that's all there was
  59.     mov    bx,tbl1    ;load table into BX
  60.     call    bounds_check ;see if the char is acceptable
  61.     jc    error2    ;quit if program error
  62.     js    error1    ;ditto if bad character
  63.     call    tbl2[bx] ;call appropriate routine
  64.     jc    error2
  65.     js    error1
  66.     dec    cx    ;dec for next LODSB
  67. i1:    lodsb    ;next char
  68.     mov    bx,tbl3 ;if we got this far, look for 'R'
  69.     call    bounds_check
  70.     jc    error2    ;treat errors the same
  71.     js    error1
  72.     jz    success    ;finish up if R found
  73.     loop    i1    ;loop till done
  74.     jmp    error1    ;error at end of string
  75. success:
  76.     mov    ax,4c00h ;ERRORLEVEL 0, success
  77.     doscall        ;exit to DOS
  78. error1:
  79.     mov    ax,4c01h ;ERRORLEVEL 1
  80.     doscall        ;exit
  81. error2:
  82.     mov    ax,4c02h ;ERRORLEVEL 2
  83.     doscall
  84. escroutine:
  85. ;if found ESC, next char must be "[" or else forget it...
  86.     lodsb    ;get the following character
  87.     dec    cx    ;decrement the character count
  88.     js    ret    ;quit if underflow
  89.     cmp    al,'[' ;is it left square bracket?
  90.     jz    ret    ;jump if so
  91.     or    al,80h    ;else set sign flag to show syntax error
  92. csiroutine:
  93. ;if 8-bit character C1 was received, nothing more to do...
  94.     ret    ;return to main routine
  95. bounds_check:
  96. ;This routine is passed a character in AL and a table address in
  97. ;BX. The table consists of word entries, each with the low byte
  98. ;containing an action code and the high byte a character code. The
  99. ;action codes are:
  100. ; 0 - end of table
  101. ; 1 - char is legal
  102. ; 2 - chars less than or equal to this is legal
  103. ; 3 - chars greater than this are legal
  104. ; 4 - char is ignored
  105. ; 5 - chars <= are ignored
  106. ; 6 - chars > are ignored
  107. ; 7 - char is illegal
  108. ; 8 - chars <= are illegal
  109. ; 9 - chars > are illegal
  110. ;returns S set if char is illegal
  111. ;Z set if char is legal
  112. ;C set if passed bad parameters (program error) or reached end of table
  113. ;no flags if char is to be ignored
  114. ;doesn't change AX, but BX is returned as word offset to entry where
  115. ;match occurred. All other regs are saved.
  116.     push    dx    ;save aux register
  117.     push    ax    ;save character
  118.     push    bx    ;save start of table
  119.     mov    ah,10    ;highest legal action code is 9
  120.     jmp    b2    ;skip cleanup routine on first entry
  121. b1:    xchg    bx,dx    ;swap regs back where they belong
  122.     inc    bx    ;and point to next word entry
  123. b2:    cmp    [bx],ah    ;past highest legal action code?
  124.     jnc    b96    ;if so, quit
  125.     mov    dl,[bx]    ;else get the action code
  126.     xor    dh,dh    ;make word pointer
  127.     shl    dx,1
  128.     inc    bx    ;point to character code
  129.     cmp    al,[bx] ;compare current character to it
  130.     xchg    bx,dx    ;must be in BX to use indirectly
  131.     jmp    b4[bx]    ;jump to appropriate action routine
  132. b4:    dw    b96    ;end of table is error, shouldn't happen
  133.     dw    b10
  134.     dw    b20
  135.     dw    b30
  136.     dw    b40
  137.     dw    b50
  138.     dw    b60
  139.     dw    b70
  140.     dw    b80
  141.     dw    b90
  142. b10:    je    b97    ;char is legal, finish up
  143.     jmp    b1    ;else loop back and try again
  144. b20:    jbe    b97
  145.     jmp    b1
  146. b30:    ja    b97
  147.     jmp    b1
  148. b40:    je    b95
  149.     jmp    b1
  150. b50:    jbe    b95
  151.     jmp    b1
  152. b60:    ja    b95
  153.     jmp    b1
  154. b70:    je    b98
  155.     jmp    b1
  156. b80:    jbe    b98
  157.     jmp    b1
  158. b90:    ja    b98
  159.     jmp    b1
  160. b95:    xchg    bx,dx    ;get final address
  161.     dec    bx    ;make word
  162.     pop    dx    ;now get start of table
  163.     sub    bx,dx    ;and make offset
  164.     mov    al,1    ;reset all the flags
  165.     or    al,al    ;like this
  166.     pop    ax    ;now restore the registers
  167.     pop    dx
  168.     ret
  169. b96:    xchg    bx,dx    ;same except for carry flag set before RET
  170.     dec    bx
  171.     pop    dx
  172.     sub    bx,dx
  173.     stc        ;error indicator set here
  174.     pop    ax
  175.     pop    dx
  176.     ret
  177. b97:    xchg    bx,dx
  178.     dec    bx
  179.     pop    dx
  180.     sub    bx,dx
  181.     xor    al,al    ;set Z flag
  182.     pop    ax
  183.     pop    dx
  184.     ret
  185. b98:    xchg    bx,dx
  186.     dec    bx
  187.     pop    dx
  188.     sub    bx,dx
  189.     or    al,80h    ;set S flag
  190.     pop    ax
  191.     pop    dx
  192.     ret
  193. ;msec.asm - millisecond delay subroutine
  194. ;call with desired number of milliseconds (unsigned!) in CX
  195. ;Freeware, Uncopyrighted (U) 1993 John Lene Comeau
  196. ;Industrial Control Technology, experts in device drivers and
  197. ;utilities under VAX/VMS, MS-DOS, and PDP11/RSX11.
  198. ;Email jcomeau@world.std.com or 70641.57@compuserve.com
  199. ;
  200. ;this version written in A86, shareware by Eric Isaacson
  201. ;highly recommended for serious assembly language programmers
  202. ;
  203. msec:
  204.     jcxz    msec_quit ;if count zero, don't bother working
  205.     push    ax    ;save registers
  206.     push    di
  207.     push    cx
  208.     mov    di,-1    ;init DI for calculation
  209.     mov    al,0    ;to latch counter 0
  210.     cli    ;don't worry, it's just for a few usecs...
  211.     out    43h,al    ;send to timer command register
  212.     in    al,40h    ;get low byte of timer 0's count
  213.     mov    ah,al    ;store it...
  214.     in    al,40h    ;high byte waiting for us now...
  215.     sti    ;OK to interrupt now
  216.     xchg    al,ah    ;now put in proper order
  217.     sub    di,ax    ;this is the reference value, see why later
  218. ;now we loop until timeout is reached
  219. msec_loop:
  220.     cli    ;disable interrupts during timer 0 read
  221.     xor    al,al    ;clear it to latch timer
  222.     out    43h,al    ;send it
  223.     in    al,40h    ;get the count again, low byte first
  224.     mov    ah,al
  225.     in    al,40h
  226.     sti    ;reenable interrupts
  227.     xchg    al,ah
  228.     add    ax,di    ;add reference value
  229. ;you might be tempted to cut out this extra addition by adding
  230. ;the millisecond to the reference value in the initialization code
  231. ;above - but this will make the carry flag dependent upon the
  232. ;current value of the timer rather than just "timeout reached" -
  233. ;so we add the intermediate value first and let AX roll over if it
  234. ;has to without affecting the test which comes at the next addition.
  235. ;Otherwise this routine would work intermittently, hardly useful for
  236. ;reliable software.
  237. ;
  238. ;The timeout value was calculated from 1193180 Hz clock, which is
  239. ;standard on all PC's including the 8088 to the 80486. It counts
  240. ;down twice every cycle 0, fffe, fffc, ..., 4, 2, 0, fffe, etc.
  241. ;1193*2=2386=952h
  242.     add    ax,952h ;then add millisecond timeout value
  243.     jc    msec_loop ;if it rolled over, we're not there yet
  244.     add    di,952h    ;else add another msec to comparison value
  245.     loop    msec_loop ;loop around till CX counts out
  246.     pop    cx    ;restore registers
  247.     pop    di
  248.     pop    ax
  249. msec_quit:
  250.     ret
  251. ;
  252. init_buffer:
  253.     pop    ax    ;get return address before messing with stack
  254.     mov    bp,sp    ;init byte pointer
  255.     add    sp,buffer ;create the buffer...
  256.     jmp    ax    ;return to main routine
  257. ;
  258. read_answer:
  259. ;let's give the CON device enough time to respond. If it's the
  260. ;actual console running ANSI.SYS it will be almost immediate. But
  261. ;if it's some weirdo running a VT-220 off his COM port with a CTTY
  262. ;command, at 300 baud yet, it may take a little longer. So let's
  263. ;give 20 ms maximum.
  264.     lea    di,buffer[bp] ;point to buffer
  265.     mov    dx,20    ;countdown register
  266.     mov    cx,1    ;time for MSEC routine
  267. i1:    mov    ah,0bh    ;check if character is waiting
  268.     doscall
  269.     jc    ret    ;quit if error
  270.     inc    al    ;returned FF if so, this will set Z flag
  271.     jz    i2    ;skip ahead and fetch it
  272.     call    msec    ;else delay a millisecond
  273.     dec    dx    ;dec the count
  274.     jz    i8    ;quit if timeout
  275.     jmp    i1    ;else loop
  276. i2:    mov    ah,8    ;single character read, no echo, cooked
  277.     doscall        ;get one character from STDIN
  278.     jc    ret    ;quit if program error
  279.     stosb        ;store the character
  280.     cmp    di,bp    ;but check if we're at end of buffer
  281.     jz    ret    ;error if so
  282.     jmp    i1    ;loop until timeout
  283. i8:    lea    ax,buffer[bp] ;get buffer address again
  284.     sub    di,ax    ;see if we got anything
  285.     jz    ret    ;error if not
  286.     xchg    ax,di    ;count in AX, buffer address in DI
  287.     ret    ;else return with count in DI
  288.