home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / sampler0 / tk.asm < prev    next >
Assembly Source File  |  1987-05-05  |  21KB  |  614 lines

  1. page    55,132
  2. title    TK - Token Parsing filter
  3. ;
  4. ;    TK --- A Simple Token Parsing Filter for DOS 2.0
  5. ;
  6. ;    (c) Copyright 1984 by    Jim Mott
  7. ;                3710 Slopeview Drive
  8. ;                Sunnyvale, CA 95148
  9. ;                (408) 274-2620
  10. ;    All rights reserved. Permission granted to use this software for
  11. ;    personal, noncommercial purposes only.
  12. ;
  13. ;
  14. ;    This program is designed to be a filter for DOS 2.0.
  15. ;    It will tokenize its input and allow subsetting and/or
  16. ;    single token per line output.
  17. ;
  18. ;    The format of the command is:
  19. ;
  20. ;    TK {/RJx | /LJx} {/0} {{/v} | {/v/v}}
  21. ;      where /RJx means right justify all tokens to x positions
  22. ;        /LJx means left justify all tokens to x positions
  23. ;             In the two entries x must be in [1..15]
  24. ;        /0   means output one token per line
  25. ;        /v   means select token v for output. You may select any
  26. ;             number, up to 255, of tokens to output. Repeats are
  27. ;             allowed and you may change the order of the input tokens
  28. ;             on the output line.
  29. ;
  30. ;    For example, to extract the list of users from a VM directory file and
  31. ;    write a sorted list of them without passwords to the printer the
  32. ;    following command line would be used.
  33. ;
  34. ;    FIND "USER " < DIRECT.VM | TK/LJ8/2/4/5/6/7/8/9 | SORT > PRN
  35. ;
  36. ;
  37. ;    For example, to find a list of all sub-directories of the current
  38. ;    directory sorted by sub-directory name we would use the following
  39. ;    command line:
  40. ;
  41. ;    DIR | FIND "<DIR>" | TK/LJ8/1/3/4 | SORT | MORE
  42. ;
  43. ;
  44. ;    For example, to generate a sorted list of all words used in a document
  45. ;    with one word per line we could use the following command line:
  46. ;
  47. ;    TK/RJ8/0 < FOOBAR.DOC | SORT | MORE
  48. ;
  49. ;
  50. ;
  51. ;
  52. ;
  53. ;
  54. ;
  55. ;
  56. ;
  57. ;
  58. ;
  59. ;
  60. stack    segment para    stack    'STACK'
  61.     db    8 dup('Jim Mott  (408) 274-2620')
  62. stack    ends
  63. ;
  64. ;
  65. dsect    segment para    'DATA'
  66. buffer    db    255 dup('?')        ; where to put the data
  67.     db    ' '            ; be sure to end scan correctly
  68. ;
  69. glen    dw    0            ; length of gbuff
  70. gbptr    dw    gbuff            ; point to start of buffer
  71. gbuff    db    255 dup('G')        ; buffer used by bufget
  72. ;
  73. flag1    db    ?            ; options enabled
  74. f1rj    equ    01h            ; right justify tokens
  75. f1lj    equ    02h            ; left justify tokens
  76. f1one    equ    04h            ; output one token per line
  77. f1sub    equ    08h            ; substring function requested
  78. f1work    equ    10h            ; fill trailing spaces
  79. f1oerr    equ    20h            ; error in options string
  80. f1eof    equ    40h            ; end of file on standard input device
  81. f1qeof    equ    80h            ; queue the end of file
  82. ;
  83. spaces    db    ?            ; number of trailing spaces required
  84. ;
  85. toksiz    db    ?            ; token size if (f1rj or f1lj)
  86. ;
  87. three    db    3            ; length of each entry
  88. tokcnt    db    ?            ; count of tokens in table
  89. toktbl    db    3*255 dup('0')        ; table of token pointers and lengths
  90. ;
  91. outcnt    db    ?            ; number of subsetting entries in
  92.                     ; outers
  93. outers    db    255 dup('1')        ; list of token numbers to output
  94. ;
  95. tokptr    dw    ?            ; pointer to free token space
  96. tokens    db    900 dup('2')        ; string space of tokens
  97. ;
  98. msgver    db    'TK: Incorrect DOS version. Must be at least 2.00.'
  99.     db    0dh,0ah,'$'
  100. optmsg    db    'TK: Incorrect parameters given.'
  101.     db    0dh,0ah
  102. optmgl    equ    $ - optmsg
  103. noroom    db    'TK: No room for user on device.'
  104.     db    0dh,0ah
  105. lnoroom    equ    $ - noroom
  106. chrspa    db    ' '            ; a space to output
  107. chrclf    db    0dh,0ah            ; <cr><lf> sequence
  108. dsect    ends
  109. ;
  110. ;
  111. csect    segment para    'CODE'
  112.     assume cs:csect,ds:dsect,ss:stack
  113. ;
  114. main    proc    far
  115. ;
  116.     push    ds            ; set up a return address
  117.     sub    ax,ax            ; we want to return to DS:0000
  118.     push    ax
  119.     mov    ax,dsect        ; point to start of data area
  120.     mov    ds,ax            ; make assume and reality agree
  121.     mov    ah,30h            ; get DOS version number
  122.     int    21h            ; call OS to get it
  123.     cmp    al,2            ; is it at least 2.00?
  124.     jnl    main00            ; yesy - good enough
  125.     lea    dx,msgver        ; no - point to the "Bad DOS version"
  126.     mov    ah,9            ; message and use DOS 1.?? function
  127.     int    21h            ; call to print it.
  128.     ret                ; and do a long return
  129. ;
  130. main00:    call    options            ; parse the options (at ES:80) and set
  131.                     ; flags
  132.     mov    ax,ds            ; make ES and DS the same now
  133.     mov    es,ax            ; so the string moves work nicely.
  134.     test    flag1,f1oerr        ; was there and error in the options
  135.     jz    main01            ; no - then go with this baby
  136.     lea    dx,optmsg        ; yes - point to options error message
  137.     mov    cx,optmgl        ; get length of message
  138.     mov    bx,2            ; error output device handle
  139.     mov    ah,40h            ; set DOS function number for
  140.     int    21h            ; "write to file or device" & call DOS
  141.     jmp    short    main03        ; and return as done
  142. ;
  143. main01:    mov    tokcnt,0        ; no tokens in the table
  144.     lea    ax,tokens        ; point to start of token work area
  145.     mov    tokptr,ax        ; save pointer to next free byte
  146.     call    bufget            ; read in a buffer
  147.     test    flag1,f1eof        ; is there any data in the read buffer
  148.     jnz    main03            ; no - we are done with this pgm then
  149.     dec    cx            ; yes - ignore the trailing <cr>
  150.     jle    main01            ; if length is =<0 just get next line
  151.     lea    bx,buffer        ; point to the first byte of the data
  152. ;
  153. main02:    call    nextok            ; get the next token
  154.     or    cx,cx            ; are we done with this line yet
  155.     jnz    main02            ; no - get yet another token
  156.     call    write            ; write the lines
  157.     jmp    short    main01        ; and loop for the next line
  158. ;
  159. main03:    call    crlf            ; write a final <cr><lf> sequence
  160.     mov    al,0            ; put 0 in al - return code to post
  161.     mov    ah,4ch            ; terminate a process code
  162.     int    21h            ; end this program
  163. ;
  164. main    endp
  165. ;
  166. ;
  167. ;    OPTIONS - This subroutine will parse the options passed to the
  168. ;          program and set the required bits in flag1. No registers
  169. ;          are preserved since we are called only once, before the
  170. ;          program has really started.
  171. ;
  172. options    proc    near
  173. ;
  174.     mov    outcnt,0        ; initialize outers count
  175.     mov    si,81h            ; point to the first parms character
  176. ;
  177. opt01:    mov    al,byte ptr es:0[si]    ; get a byte from the parm string
  178.     inc    si            ; point to the next byte
  179.     cmp    al,0dh            ; is it the end of the string?
  180.     jne    opt02            ; no - goody, more data to process
  181.     ret                ; yes, return to the caller then
  182. ;
  183. opt02:    cmp    al,' '            ; allow spaces anywhere before slashes
  184.     je    opt01            ; ignore them though
  185.     cmp    al,'/'            ; we have to start with a slash now
  186.     je    opt04            ; if it is a slash then process it
  187. ;
  188. opterr:    or    flag1,f1oerr        ; otherwise set the options error flag
  189.     ret                ; and return
  190. ;
  191. opt04:    mov    al,byte ptr es:0[si]    ; get the next character after slash
  192.     inc    si            ; point to next character in parms
  193.     cmp    al,'a'            ; is it lower case or funny?
  194.     jl    opt4a            ; no - process it normally then
  195.     sub    al,'a'-'A'        ; yes - map lower case to upper
  196. ;
  197. opt4a:    cmp    al,'L'            ; might it be left justify or numeric
  198.     jl    optnum            ; perhaps numeric - check it out
  199.     jne    opt05            ; it is not LJ for sure
  200.     or    flag1,f1lj        ; assume it is LJ for the moment
  201.     test    flag1,f1rj        ; make sure this isn't a duplicate
  202.     jnz    opterr            ; if RJ already then big problems
  203.     jmp    short    opt06        ; and rejoin common justify code
  204. ;
  205. opt05:    cmp    al,'R'            ; might it be right justify (RJ)?
  206.     jne    opterr            ; no - then it is an error
  207.     or    flag1,f1rj        ; yes - assume for the moment it is
  208.     test    flag1,f1lj        ; make sure we aren't trying to left
  209.     jnz    opterr            ; justify too - if we are we are in
  210.                     ; deep s..t
  211. opt06:    mov    al,byte ptr es:0[si]    ; get the next character
  212.     inc    si            ; point to the next character in parms
  213.     cmp    al,'J'            ; is it the J we expect?
  214.     je    opt6a            ; yes - process it normally then
  215.     cmp    al,'j'            ; is it a lower case J
  216.     jne    opterr            ; no - that's too bad.
  217. ;
  218. opt6a:    mov    al,byte ptr es:0[si]    ; get the first byte of the number
  219.     inc    si            ; point to next character in parms
  220.     call    decbin            ; is it a number?
  221.     jc    opterr            ; no - then we have an error
  222.     or    al,al            ; is the field size 0?
  223.     je    opterr            ; yes - it is in error then
  224.     cmp    al,15            ; is field size more than 15?
  225.     jg    opterr            ; yes - it is in error then
  226.     mov    toksiz,al        ; save the justified field size
  227.     jmp    short opt01        ; and process further options
  228. ;
  229. optnum:    call    decbin            ; is it a number after slash?
  230.     jc    opterr            ; no - then it is an error
  231.     or    al,al            ; zero is special
  232.     jne    opt08            ; not zero - save it in array then
  233.      or    flag1,f1one        ; zero means one token per line
  234.     jmp    short    opt01        ; process some other token then
  235. ;
  236. opt08:    sub    cx,cx            ; get a zeroed double register
  237.     mov    cl,outcnt        ; get offset into outers for this guy
  238.     lea    bx,outers        ; point just before list of outers
  239.     add    bx,cx            ; bx points to origin 1 save spot
  240.     mov    byte ptr [bx],al    ; save the token position to write
  241.     inc    outcnt            ; add one to outcnt
  242.     or    flag1,f1sub        ; make sure substitute flag is on
  243.     jmp    opt01            ; and play it again Sam.
  244. ;
  245. options    endp
  246. ;
  247. ;
  248. ;    nextok - This subroutine will find the next token in the string
  249. ;         pointed to by bx, with length contained in cx, and move
  250. ;         it to the end of the token space. An entry in toktbl will
  251. ;         be created for this token. When the subroutine returns cx
  252. ;         will be zero if the source data string is empty. bx will
  253. ;         point to the first character past the last token.
  254. ;
  255. nextok    proc    near
  256. ;
  257.     mov    di,tokptr        ; get pointer to where to put token
  258. ;
  259. next01:    mov    al,byte ptr 0[bx]    ; loop past junk
  260.     cmp    al,' '            ; is it a leading space?
  261.     jne    next03            ; no - then we have a token
  262.     inc    bx            ; yes - point to the next character
  263.     loop    next01            ; and try that one
  264.     ret                ; return if we are done with output
  265. ;
  266. next03:    mov    si,bx            ; save pointer to start of token
  267.     mov    ah,1            ; initial guess for token length is 1
  268. ;
  269. next04:    inc    bx            ; point to the next character in input
  270.     mov    al,byte ptr [bx]    ; get the character
  271.     cmp    al,' '            ; is it the end of the token?
  272.     je    next05            ; yes - we have some good numbers
  273.     inc    ah            ; no - increment count of contiguous
  274.                     ; characters.
  275.     loop    next04            ; continue till out of chars or a
  276.                     ; field separator
  277.     dec    ah            ; shouldn't get here but correct for
  278.                     ; it anyway
  279. next05:    push    cx            ; save number of chars left in source
  280.                     ; string
  281.     test    flag1,f1rj + f1lj    ; do we have a maximum token length?
  282.     jz    next09            ; no - just a normal token write then
  283.     cmp    ah,toksiz        ; yes - is this token just right?
  284.     je    next09            ; it sure is. we will keep it as is
  285.     jl    next06            ; if token size < max token size - pad
  286.     mov    ah,toksiz        ; otherwise take max token size as own
  287.     jmp    short    next09        ; and continue normally
  288. ;
  289. next06:    mov    al,toksiz        ; get the toekn size we must pad to
  290.     sub    al,ah            ; al contains number of spaces needed
  291.     test    flag1,f1lj        ; left justify? (pad right with space)
  292.     jz    next07            ; no - must pad to the left with space
  293.     mov    spaces,al        ; yes - save how many spaces to fill
  294.     or    flag1,f1work        ; mark as work to do later on
  295.     jmp    short    next09        ; and join mainline code
  296. ;
  297. next07:    mov    cl,al            ; cx contains number of leading spaces
  298. ;
  299. next08:    mov    byte ptr [di],' '    ; put a leading space in this token
  300.     inc    di            ; point to the next slot
  301.     loop    next08            ; and fill in all needed spaces
  302. ;
  303. next09:    mov    cl,ah            ; cx now contains total number of
  304.                     ; chars in token
  305.     cld                ; make the direction ever upward
  306.     rep    movsb            ; move the token to its spot
  307.     test    flag1,f1work        ; is it left justified (need spaces)
  308.     jz    next11            ; no - we are done with hard part then
  309.     mov    cl,spaces        ; get count of spaces needed
  310. ;
  311. next10: mov    byte ptr [di],' '    ; move in a trailing space
  312.     inc    di            ; point to the next slot and
  313.     loop    next10            ; cont. till all trailing spaces done
  314.     and    flag1,255-f1work    ; reset the work to do bit
  315. ;
  316. next11:    mov    dx,tokptr        ; get pointer to start of this token
  317.     mov    tokptr,di        ; save pointer to next free token byte
  318.     test    flag1,f1lj + f1rj    ; do we have fixed length tokens?
  319.     jz    next12            ; no - take them as we get them
  320.     mov    ah,toksiz        ; yes - set this tokens length
  321. ;
  322. next12:    mov    cl,ah            ; save length of token
  323.     mov    al,3            ; number of bytes per entry
  324.     mul    tokcnt            ; ax is now an offset in toktbl
  325.     lea    si,toktbl        ; point to start of token table
  326.     add    si,ax            ; si points to an entry in toktbl
  327.     mov    byte ptr [si],cl    ; move in length of entry
  328.     mov    word ptr 1[si],dx    ; save pointer to start of token
  329.     inc    tokcnt            ; count one more token
  330.     pop    cx            ; cx contains number of source chars
  331.     or    cx,cx            ; left. Are we done yet?
  332.     jz    next13            ; yes - return
  333.     dec    cx            ; no - correct for undercounting by 1
  334. ;
  335. next13:    ret                ; and return
  336. ;
  337. nextok    endp
  338. ;
  339. ;
  340. ;    write - This routine will write the tokens to the standard output
  341. ;        device. It is controlled by the settings of flags in flag1.
  342. ;
  343. write    proc    near
  344. ;
  345.     sub    cx,cx            ; get an empty loop counter
  346.     mov    cl,tokcnt        ; cl contains total number tokens read
  347.     or    cx,cx            ; do we have anything to write out?
  348.     jnz    write1            ; yes - then go for it
  349.     ret                ; no - we are done before we begin
  350. ;
  351. write1:    test    flag1,f1sub        ; are we changing their order?
  352.     jnz    write3            ; yes - then use different write logic
  353.     sub    dl,dl            ; no - just output them all in order
  354. ;
  355. write2:    call    tout            ; write the sucker
  356.     inc    dl            ; point to the next token
  357.     loop    write2            ; and go through them all
  358.     jmp    short    write6        ; return. A job well done
  359. ;
  360. write3:    mov    cl,outcnt        ; get the number tokens to write
  361.     lea    bx,outers        ; point to the first one to output
  362. ;
  363. write4:    mov    dl,byte ptr [bx]    ; get a token to write
  364.     cmp    dl,tokcnt        ; is it <= max token?
  365.     jg    write5            ; no - don't write it then
  366.     dec    dl            ; yes - adjust for origin one and
  367.     call    tout            ; write this token then
  368. ;
  369. write5:    inc    bx            ; point to the next token count to
  370.     loop    write4            ; write and loop through whole list
  371. ;
  372. write6:    test    flag1,f1one        ; are we outputting one token/line?
  373.     jnz    write7            ; yes - the last <cr><lf> was written
  374.     call    crlf            ; no - write a trailing <cr><lf>
  375. ;
  376. write7:    ret                ; Done. Go home now.
  377. ;
  378. write    endp
  379. ;
  380. ;
  381. ;    tout -    This routine will find and write the token from the input
  382. ;        line that is in position dl on that line.
  383. ;
  384. tout    proc    near
  385. ;
  386.     push    bx            ; save the registers
  387.     push    cx
  388.     push    dx
  389.     mov    al,3            ; number of bytes per toktbl entry
  390.     mul    dl            ; get offset into toktbl for token
  391.     lea    bx,toktbl        ; point to the start of the table
  392.     add    bx,ax            ; point to the correct 3 byte entry
  393.     sub    cx,cx            ; zero the counter
  394.     mov    cl,byte ptr [bx]    ; get number of chars in this token
  395.     mov    dx,word ptr 1[bx]    ; and point to first byte of token
  396.     call    oswrite            ; write to standard output device
  397.     test    flag1,f1one        ; only one token per line?
  398.     jz    tout02            ; no - write a space then
  399.     call    crlf            ; yes - write a <cr><lf> sequence
  400.     jmp    short    tout03        ; and return
  401. ;
  402. tout02: mov    cx,1            ; length of space is one
  403.     lea    dx,chrspa        ; point to a space
  404.     call    oswrite            ; write to standard output device
  405. ;
  406. tout03:    pop    dx            ; restore the registers
  407.     pop    cx
  408.     pop    bx
  409.     ret                ; and return
  410. ;
  411. tout    endp
  412. ;
  413. ;
  414. ;    crlf -    Everybody knows what this routine does.
  415. ;
  416. crlf    proc    near
  417. ;
  418.     push    ax            ; save the registers
  419.     push    bx
  420.     push    cx
  421.     push    dx
  422.     mov    cx,2            ; length of <cr><lf> string
  423.     lea    dx,chrclf        ; point to the data to write
  424.     call    oswrite            ; write to the standard output device
  425.     pop    dx            ; restore the registers
  426.     pop    cx
  427.     pop    bx
  428.     pop    ax
  429.     ret                ; and return
  430. ;
  431. crlf    endp
  432. ;
  433. ;
  434. ;    oswrite - This routine will write characters pointed to by ds:dx
  435. ;          of length contained in cx, to the standard output device
  436. ;          I any errors are detected a message will be written to the
  437. ;          standard error device and flag f1eof will be set.
  438. ;
  439. oswrite    proc    near
  440. ;
  441.     mov    bx,1            ; file handle of standard output
  442.     mov    ah,40h            ; write to file or device DOS function
  443.     int    21h            ; call DOS
  444.     jc    oswr01            ; if error 5 or 6 then end
  445.     cmp    cx,ax            ; as many chars as we wanted written?
  446.     je    oswr99            ; return if all went well
  447. ;
  448. oswr01:    lea    dx,noroom        ; point to the "no space" message
  449.     mov    cx,lnoroom        ; get the length of the message
  450.     mov    bx,2            ; get handle for standard error device
  451.     mov    ah,40h            ; write to file or device DOS function
  452.     int    21h            ; let him know we erred
  453.     or    flag1,f1eof        ; pretend eof on input device so
  454. ;
  455. oswr99:    ret                ; program stops and return
  456. ;
  457. oswrite    endp
  458. ;
  459. ;
  460. ;    decbin -  On entry this routine has the first character to convert
  461. ;          to binary in al. si points to additional characters. On exit
  462. ;          si points to the first non-numeric character found.
  463. ;          al contains the binary value and carry isn't set. If carry
  464. ;          is set on return then an invalid number was found.
  465. ;
  466. decbin    proc    near
  467. ;
  468.     push    bx            ; save a register
  469.     call    decb04            ; check for numeric in al
  470.     jnc    decb02            ; if al was numeric it is now 0 .. 9
  471. ;
  472. decb01:    stc                ; make sure carry flag set
  473.     pop    bx            ; restore the register
  474.     ret                ; and return indicating an error
  475. ;
  476. decb02:    mov    bl,al            ; get total so far
  477.     mov    al,byte ptr es:0[si]    ; get a byte from the input stream
  478.     inc    si
  479.     call    decb04            ; check it for numeric
  480.     jnc    decb03            ; if numeric then juggle some
  481.     mov    al,bl            ; otherwise get the value to return
  482.     clc                ; clear carry flag to say it worked
  483.     dec    si            ; make sure next char is non-numeric
  484.     pop    bx            ; restore the register
  485.     ret                ; and return
  486. ;
  487. decb03:    mov    bh,al            ; save the number for a minute
  488.     mov    al,10            ; get the base
  489.     mul    bl            ; shift left one position (base al)
  490.     mov    bl,bh            ; make bx a good number
  491.     sub    bh,bh            ; bx now contains16 bit value of digit
  492.     add    ax,bx            ; add in the latest digit
  493.     or    ah,ah            ; make sure no overflow
  494.     jne    decb01            ; if there was this is an error
  495.     jmp    short    decb02        ; continue on our way
  496. ;
  497. decb04:    sub    al,'0'            ; is it less than a number?
  498.     jl    decb05            ; yes - return with carry set
  499.     cmp    al,9            ; is it more than a number?
  500.     jg    decb05            ; yes - return with carry set
  501.     clc                ; no - make sure carry is off
  502.     ret                ; then return the number
  503. ;
  504. decb05: stc                ; set carry on
  505.     ret                ; and return
  506. ;
  507. decbin    endp
  508. ;
  509. ;
  510. ;    bufget -  This routine will read one 'line' from the standard input
  511. ;          device to buffer. On exit cx contains the count of chars
  512. ;          read. f1eof is set if an end of file condition is
  513. ;          encountered.
  514. ;
  515. bufget    proc    near
  516. ;
  517.     push    ax            ; save the registers
  518.     push    bx
  519.     push    dx
  520.     push    di
  521.     push    si
  522.     test    flag1,f1qeof        ; should we reflect an immediate eof?
  523.     jz    bufg00            ; no - standard logic here then
  524.     or    flag1,f1eof        ; yes - set the end of file bit
  525.     and    flag1,255 - f1qeof    ; and say it is no longer pending
  526.     jmp    short    bufret        ; return now
  527. ;
  528. bufg00:    sub    cx,cx            ; count of characters gotten
  529.     lea    di,buffer        ; point destination to buffer
  530. ;
  531. bufg01:    call    cget            ; get one character
  532.     test    flag1,f1eof        ; did we get an eof on that try?
  533.     jz    bufg02            ; yes - let's hope it is an error
  534.     or    cl,cl            ; is there anything in the buffer?
  535.     jz    bufret            ; no - just return with cx=0 and f1eof
  536.     mov    ah,0dh            ; yes - slap a <cr> on the end
  537.     call    cput            ; put it at end of buffer
  538.     and    flag1,255 - f1eof    ; clear the end of file bit
  539.     or    flag1,f1qeof        ; say next time turn on eof for sure
  540.     jmp    short    bufret        ; and return this last buffer
  541. ;
  542. bufg02:    cmp    ah,0dh            ; is the record terminator character?
  543.     je    bufg03            ; yes - don't turn that into a space
  544.     cmp    ah,20h            ; no - if not <cr>
  545.     jge    bufg03            ; if >= 20h then use as is
  546.     mov    ah,' '            ; otherwise make it a space
  547. ;
  548. bufg03:    call    cput            ; write char to output buffer
  549.     cmp    ah,0dh            ; just write the record terminator?
  550.     je    bufret            ; yes - then return
  551.     cmp    cl,255            ; written 255 characters yet?
  552.     jne    bufg01            ; no - get the next character
  553.     mov    byte ptr [di],0dh    ; make it a terminator
  554. ;
  555. bufret:    pop    si            ; restore the registers
  556.     pop    di
  557.     pop    dx
  558.     pop    bx
  559.     pop    ax
  560.     ret                ; and return
  561. ;
  562. bufget    endp
  563. ;
  564. ;
  565. ;
  566. cget    proc    near
  567. ;
  568.     mov    dx,glen            ; is there any data in gbuff?
  569.     or    dx,dx            ; if count is zero there isn't
  570.     jnz    cget01            ; there is data so read it
  571.     push    cx            ; save the registers we might need
  572.     push    di
  573.     mov    ah,3fh            ; DOS function read from standard in
  574.     mov    bx,0            ; file handle for standard in
  575.     mov    cx,255            ; number of characters to read
  576.     lea    dx,gbuff        ; point to where to put the data
  577.     mov    gbptr,dx        ; save pointer to first character
  578.     int    21h            ; call DOS function
  579.     mov    glen,ax            ; save the number of characters read
  580.     mov    dx,ax            ; put data count in dx
  581.     pop    di            ; restore the registers
  582.     pop    cx
  583.     or    dx,dx            ; did we get data or eof?
  584.     jnz    cget01            ; data this time
  585.     or    flag1,f1eof        ; set the end of file encountered bit
  586.     ret                ; and return
  587. ;
  588. cget01:    mov    bx,gbptr        ; get pointer to character and return
  589.     mov    ah,byte ptr [bx]
  590.     inc    gbptr            ; get character and increment pointer
  591.     dec    glen            ; decrement length
  592.     inc    cl            ; count this character
  593.     ret                ; and return the character
  594. ;
  595. cget    endp
  596. ;
  597. ;
  598. ;
  599. ;
  600. cput    proc    near
  601. ;
  602.     mov    byte ptr [di],ah    ; save the character
  603.     inc    di            ; point to next spot
  604.     cmp    cl,255            ; will we overreach next time
  605.     jne    cput01            ; no - good thing
  606.     dec    di            ; yes - can't let that happen
  607. ;
  608. cput01:    ret                ; all done
  609. ;
  610. cput    endp
  611. ;
  612. csect    ends
  613.     end    main
  614.