home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 December / simtel1292_SIMTEL_1292_Walnut_Creek.iso / msdos / txtutl / tabs21.arc / TABS21TH.ASM < prev   
Assembly Source File  |  1988-01-07  |  17KB  |  749 lines

  1.     Page    74,132
  2.     Title    TABS - Align ASCII File
  3.  
  4.     Comment    | Version 2.1, Oct 14, 1986
  5.  
  6. TABS Command
  7. -----------------
  8.  
  9. Purpose:   Replace blanks with TAB character(s); or expand TABs.
  10.  
  11. Format:       TABS     [d:[input.ext]] [d:[output.ext]] [/D]
  12.  
  13. Remarks:   Any TAB characters found are    first expanded.    If TABS
  14.     appear within quoted strings - out of context -    they will
  15.     not be expanded.
  16.  
  17.     The /D option may be used to remove TABs from a    file,
  18.  
  19.     The maximum logical record size    is 255,    see MAXREC equate.
  20.     Defacto    tab columns are    9,17,25,...
  21.  
  22.     Written    by Vernon Buerg    for the    IBM PC using DOS 2.
  23.     For public domain use.
  24.  
  25. Notes:    Version    1.6 includes a correction for the use of wildcards
  26.     to name    the output file    the same as the    input file if only
  27.     a drive    was supplied for the output file name.
  28.  
  29.     Version    1.7 fixes a problem regarding the EOF character. It
  30.     now considers the EOF as the end of a file and will no longer
  31.     copy data after    that point. Also, if wildcards are used, all
  32.     matching files are processed.
  33.  
  34.     Version    1.8 cleans up the messages displayed.
  35.  
  36.     Version 1.9 requires the ouput file on a different drive,
  37.     or in a different path.
  38.  
  39.     Version 2.0 improves performance, adds EOF to end of file.
  40.     Version 2.1 ignore EOF (1Ah ) in input files.
  41.     Version 2.1TH Toad Hall Tweak
  42.             mask chars to eliminate "high bit" setting by
  43.             some word processors (like WordStar).
  44.             Slightly tweaked (like with near jmps) to reduce
  45.             code size yet more.  (only saved a few bytes)
  46.             David Kirschbaum, Toad Hall
  47.             kirsch@braggvax.ARPA
  48.  
  49. -----------------                    |
  50.  
  51. CSeg    Segment    Public Para 'CODE'
  52.     Assume    CS:Cseg,DS:Cseg,ES:CSeg
  53.     Org    100h
  54.  
  55. Tabs    Proc    Far
  56.     Mov    CS:Stk_Top,SP        ;Save stack ptr    to insure return
  57.  
  58.     Call    ChkVer            ;Check for DOS 2
  59.  
  60.     Call    Alloc            ;Get maximum I/O buffers
  61.  
  62.     Call    GetFile            ;Get file names
  63.  
  64. Again:
  65.     Call    OpenIn            ;Open input
  66.  
  67.     Call    OpenOut            ; and output
  68.  
  69.     Call    Inform            ;Display "cooking" message
  70.  
  71.     Call    GenTab            ;Generate tabs
  72.  
  73.     Call    Flush            ;Empty the output buffer
  74.  
  75.     Call    Close            ;Close files
  76.  
  77.     Call    Next            ;Get next matching file
  78.     Or    AL,AL
  79.     Jz    Again
  80.     Sub    AL,AL            ;All done
  81.     Jmp    Short Exit
  82.  
  83.  
  84. Error:    Mov    SP,Stk_Top        ;Insure    proper return
  85.     Call    PrintS            ;Print any message
  86.  
  87.     Mov    AL,1            ;Set ERRORLEVEL    to 1
  88. Exit:    Mov    AH,4Ch
  89.     Int    21h            ;Return    to DOS
  90.     Page
  91. ;
  92. ;    Constants, equates, and    work areas
  93.  
  94. BufLen    Dw    0            ;I/O buffer size
  95. MinCore    Equ    512            ;Minimum of one    sector
  96. Maxrec    Equ    255            ;Longest logical record
  97.  
  98. S_Quote    Equ    34            ;Single    quote
  99. D_Quote    Equ    39            ;Double    quote
  100. Tab    Equ    9
  101. LF    Equ    10
  102. CR    Equ    13
  103. EOF    Equ    1Ah
  104. Stopper    Equ    255
  105. CRLF    Equ    1013H        ;TH
  106.  
  107. Sw    Db    0            ;Number    of blanks skipped
  108. Qsw    Db    0            ;Quote switch
  109. Detab    Db    0            ;Non-zero for detab function
  110. Stk_Top    Dw    0            ;SP at entry
  111.  
  112. Msg1    Db    CR,LF,'Input failed to open, '
  113. Input    Db    76 Dup (0),0,Stopper    ;Drive:path\name.ext
  114. IHandle    Dw    0            ;Input file handle
  115. Ilen    Dw    0            ;Input block length
  116. Iptr    Dw    0            ;Offset    to next    char
  117. In_Ptr    Dw    0            ;Seg offset
  118.  
  119. Msg2    Db    CR,LF,'Output failed to open, '
  120. Output    Db    76 Dup (0),0,CR,LF,Stopper
  121. OHandle    Dw    0            ;Output    file handle
  122. Olen    Dw    0            ;Bytes in output buffer
  123. Optr    Dw    0            ;Offset    to next    char
  124. Out_Ptr    Dw    0            ;Seg offset
  125.  
  126. Spaces    Db    8 Dup (' ')
  127. FilePtr    Dw    Offset Input        ;Addr of file name part
  128. NewPtr    Dw    Offset Output        ;Spot for output file name
  129. DTA    Db    48 Dup (0)        ;DOS data transfer area
  130.     Page
  131. ;
  132. ;    Messages
  133.  
  134. Version    Db    'TABS - Version 2.1TH - V.Buerg',CR,LF,CR,LF
  135.     Db    'Usage:  TABS  infile  outfile  [/D]',CR,LF
  136.     Db    ' o  infile and outfile may include drive and path names',CR,LF
  137.     Db    ' o  use ending /D to expand tabs to spaces.',CR,LF
  138.     Db    ' o  Oct 14, 1986; public domain.',Stopper
  139.  
  140. Sorry    Db    CR,LF,'Wrong PC DOS Version',Stopper
  141. Msg3f    Db    CR,LF,'Read error',Stopper
  142. Msg40    Db    CR,LF,'Write error or Disk full.',Stopper
  143. Msg4a    Db    CR,LF,'Not enough memory',Stopper
  144. Msg4e    Db    CR,LF,'No matching file(s) found',Stopper
  145. InformD    Db    'de-'
  146. Cooking    Db    'TABS:',9,Stopper
  147. Mark    Db    9,'-> ',Stopper
  148. NewLine    Db    CR,LF,Stopper
  149.  
  150. Code2    Db    'File not found ',Stopper
  151. Code3    Db    'Path not found ',Stopper
  152. Code4    Db    'Too many files ',Stopper
  153. Code5    Db    'Access denied  ',Stopper
  154.     Page
  155. ;
  156. ;    Replace    blanks with tabs
  157.  
  158. GenTab    Proc    Near
  159. RecLoop:Call    GetRec        ;TH    ; Get a record, length in CX
  160.     Jnc    Init_Rec        ; Was it end of file?
  161.     Jmp    Done
  162. Init_Rec:
  163.     Sub    BX,BX            ;Output    column
  164.     Mov    Sw,BL            ;No blanks yet
  165.     Mov    Qsw,BL            ;No quotes yet
  166.     Or    CX,CX            ;Any data in record?
  167.     Jz    Null            ; no, just CR-LF
  168.  
  169. Set1:    Mov    SI,Offset Rec        ;Look for blanks and
  170. Wloop:    Lodsb                ; replace strings of blanks
  171.     Inc    BX            ; with tab characters
  172.     and    al,7FH            ;TH mask hi bits
  173.     Cmp    AL,D_Quote        ;Don't count blanks
  174.     Je    Chk2d            ; within single    or double
  175.  
  176. Chk1:    Cmp    AL,S_Quote        ;Insert    TABs for any
  177.     Je    Chk3d            ; blanks skipped before
  178.  
  179. Chk3:    Cmp    Detab,0            ;Leave expanded    record as-is
  180.     Jne    Check            ; if de-tabbing
  181.     Cmp    AL,' '            ;Tis a blank?
  182.     Jne    Check            ; no, see if eof
  183.     Test    Qsw,3            ;Within    quotes?
  184.     Jnz    Check
  185.     Inc    Sw
  186.     Test    BL,07h            ;Ready for a tab?
  187.     Jnz    Tloop            ; no, keep going
  188.     Mov    AL,Tab            ; yes, send one
  189.     Jmp    short Copy    ;TH
  190. Chk3d:
  191.     Xor    Qsw,1            ; a quote
  192. Chk2:    Cmp    Sw,0            ;Must re-insert
  193.     Je    Check            ; any blanks skipped
  194.     Jmp    short Insert    ;TH    ; if not enough    for a TAB
  195. Chk2d:
  196.     Xor    Qsw,2            ; quoted strings
  197.     Jmp    short Chk2    ;TH
  198.  
  199. Check:     Cmp    Detab,0
  200.     Jne    Copy
  201.     Test    Qsw,3            ;When a    non-blank is
  202.     Jnz    Copy            ; encountered, insert a    TAB
  203.     Cmp    Sw,0            ; if there were    blanks
  204.     Je    Copy            ; before it
  205.     Mov    DX,BX
  206.     Dec    DL
  207.     Test    DL,07h            ;If the    non-blank is not
  208.     Jnz    Insert            ; in a TAB column, then
  209.     Push    AX            ; keeps    all the    blanks
  210.     Mov    AL,Tab
  211.     Call    PutChar
  212.     Pop    AX
  213. Copy:    Call    PutChar            ; and write it
  214.     Mov    Sw,0            ;Ind not blank
  215.  
  216. Tloop:    Loop    Wloop
  217.  
  218. Null:    Mov    AL,CR            ;Append    CR
  219.     Call    PutChar
  220.     Mov    AL,LF            ; and LF
  221.     Call    PutChar
  222.     Jmp    RecLoop        ;TH
  223.  
  224. Insert:    Push    AX            ;Insert    any blanks that
  225.     Mov    DL,Sw            ; didn't line up on
  226. Blanks:    Cmp    DL,1            ; a TAB    column
  227.     Jb    None
  228.     Mov    AL,' '
  229.     Call    PutChar
  230.     Dec    DL            ;Decr insert count
  231.     Jmp    short Blanks    ;TH    ; and continue
  232. None:    Pop    AX            ;Get char back
  233.     Jmp    short Copy    ;TH
  234.  
  235. Done:    Ret
  236. GenTab    Endp
  237.     Page
  238. ;
  239. ;    Build a    logical    record with TABs expanded
  240.  
  241. GetRec    Proc    Near
  242.     Sub    DI,DI            ;Target    record offset
  243.     Mov    Qsw,0            ;Quote indicator
  244.  
  245. Get1:    Call    GetChar            ; Build up a logical record
  246.     Jc    GetEof             ; End of file?
  247.     Cmp    AL,CR            ; Looking for a CR or LF
  248.     Je    Get1            ;  as end-of-record
  249.     Cmp    AL,LF
  250.     Je    Get7
  251.     Cmp    AL,EOF            ; Ignore EOF control char
  252.     Jne    Get1e
  253.     Mov    AL,' '
  254. Get1e:    Cmp    AL,S_Quote        ; Don't expand tabs
  255.     Jne    Get2            ;  found within a
  256.     Xor    Qsw,1            ;  quoted string
  257. Get2:    Cmp    AL,D_Quote
  258.     Jne    Get3
  259.     Xor    Qsw,2
  260. Get3:    Cmp    AL,Tab            ;Is it TAB?
  261.     Jne    Get5            ; no, pass it
  262.     Test    Qsw,3            ;Within    quotes?
  263.     Jnz    Get5            ; yes, pass it as-is
  264. Get4:    Mov    Rec[DI],' '        ;Expand    embedded tabs
  265.     Inc    DI            ; with blanks
  266.     Test    DI,0007h
  267.     Jz    Get1
  268.     Jmp    short Get4    ;TH
  269.  
  270. Get5:    Mov    Rec[DI],AL        ;Build the record by
  271.     Inc    DI            ; copying each character
  272.     Cmp    DI,Maxrec        ; or TABs expanded to blanks
  273.     Jae    Get6
  274.     Jmp    short Get1    ;TH    ; no, continue
  275. Get6:    Clc
  276. GetEof:    Mov    CX,DI            ;Final record length
  277.     Ret
  278.  
  279. Get7:
  280. ;    Cmp    Rec-1[DI],' '        ;Omit trailing blanks
  281.     mov    al,Rec-1[DI]    ;TH omit trailing blanks
  282.     and    al,7FH        ;TH mask hi bits
  283.     cmp    al,' '        ;a space?
  284.     Jne    Get6        ;nope
  285.     
  286.     Dec    DI        ;back up from record's end
  287.     Jz    Get6        ;done
  288.     Jmp    short Get7    ;TH keep testing
  289.  
  290. GetRec    Endp
  291.     Page
  292. ;
  293. ;    Extract    one char from record
  294.  
  295. GetChar    Proc    Near            ;Read char into    AL
  296. Read1:    Cmp    Ilen,0            ;Any in    buffer?
  297.     Je    Read            ; no, read next    block
  298.     Mov    SI,Iptr            ; yes, get offset in buf
  299.     Lodsb
  300.     Mov    Iptr,SI            ;Offset    for next one
  301.     Dec    Ilen
  302.     Clc
  303.     Ret
  304.  
  305. Read:    Push    CX
  306.     Mov    BX,IHandle        ;Read a    block of data
  307.     Mov    CX,BufLen        ; into Input (segment) buffer
  308.     Mov    DX,In_Ptr
  309.     Mov    Iptr,DX
  310.     Mov    AH,3Fh
  311.     Int    21h
  312.     Pop    CX
  313.     Mov    Ilen,AX            ; and length
  314.     Jc    Read3
  315.     Or    AX,AX            ; Anything read?
  316.     Jnz    Read1            ;  yes, pick it up
  317.     Stc                ;  no, return EOF
  318.     Ret
  319.  
  320. Read3:    Mov    DX,Offset Msg3f        ;Say I/O ERROR
  321.     Jmp    Error
  322. GetChar    Endp
  323.     Page
  324. ;
  325. ;    Block output records
  326.  
  327. PutChar    Proc    Near               ;Write from AL
  328.     Mov    DI,Optr            ;Offset    in buffer
  329.     Stosb
  330.     Mov    Optr,DI            ;New buffer ptr
  331.     Dec    Olen            ;Full buffer?
  332.     Jz    PutChars
  333.     Ret
  334. PutChars:
  335.     Call    Write            ;  yes, write it
  336.        Ret
  337. PutChar    Endp
  338.  
  339.  
  340. Write    Proc    Near
  341.     Push    CX            ;Write full buffer
  342.     Mov    CX,BufLen        ;Buffer size
  343.  
  344. Write3:    Push    AX
  345.     Push    BP
  346.     Push    BX
  347.     Push    DX
  348.     Mov    BX,OHandle        ;Get file handle
  349.     Mov    BP,CX            ;Save size requested
  350.     Mov    DX,Out_Ptr
  351.     Mov    Optr,DX
  352.     Mov    AX,BufLen        ;Reset buffer size free
  353.     Mov    Olen,AX
  354.     Mov    AH,40h            ;Write the block
  355.     Int    21h
  356.     Jc    Writer            ;Write OK?
  357.     Sub    BP,AX            ;Wrote all data?
  358.     Jz    Write2            ; yes, good
  359. Writer:    Mov    DX,Offset Msg40        ; no, say I/O error
  360.     Jmp    Error
  361.  
  362. Flush:    Mov    AL,EOF            ;Append EOF for funny programs
  363.     Call    PutChar
  364.     Push    CX            ;Write data left over
  365.     Mov    CX,BufLen
  366.     Sub    CX,Olen            ;Any left in output?
  367.     Jnz    Write3
  368.     Pop    CX
  369.     Ret
  370.  
  371. Write2:    Pop    DX
  372.     Pop    BX
  373.     Pop    BP
  374.     Pop    AX
  375.     Pop    CX
  376.     Ret
  377. Write    Endp
  378.     Page
  379.  
  380. ;    Open input file
  381.  
  382. OpenIn    Proc    Near
  383.     Mov    DX,Offset Input
  384.     Mov    AX,3D00h        ;For input
  385.     Int    21h
  386.     Jnc    Openi
  387.     Mov    DX,Offset Msg1
  388.     Jmp    short OpenErr    ;TH
  389.  
  390. Openi:    Mov    IHandle,AX
  391.     Ret
  392. OpenIn    Endp
  393.  
  394. ;    Open output file
  395.  
  396. OpenOut    Proc    Near
  397.     Mov    DX,Offset Output
  398.     Sub    CX,CX            ;Normal    file attribute
  399.     Mov    AH,3Ch            ;Create    a file
  400.     Int    21h
  401.     Jnc    Openo
  402.     Mov    DX,Offset Msg2        ;Oops, can't open output
  403.     Jmp    short OpenErr    ;TH
  404.  
  405. Openo:    Mov    OHandle,AX
  406.     Ret
  407. OpenOut    Endp
  408.  
  409. ;    Determine why OPEN failed
  410.  
  411. OpenErr:Cmp    AL,2            ;AL has    reason code
  412.     Jb    Opene
  413.     Cmp    AL,5
  414.     Ja    Opene
  415.     Sub    BX,BX            ;Get offset to reason
  416.     Mov    BL,AL            ; text for open    failure
  417.     Mov    CL,4
  418.     Shl    BX,CL
  419.     Call    PrintS            ;Say OPEN FAILED
  420.     Mov    DX,Offset NewLine
  421.     Call    PrintS
  422.     Lea    DX,Code2-32[BX]
  423. Opene:    Jmp    Error
  424.  
  425. ;    Close input/output
  426.  
  427. Close    Proc    Near            ;Close files
  428.     Mov    BX,OHandle        ; output
  429.     Mov    AH,3Eh
  430.     Int    21h
  431.  
  432.     Mov    BX,IHandle        ; input
  433.     Mov    AH,3Eh
  434.     Int    21h
  435.     Ret
  436. Close    Endp
  437.     Page
  438. ;
  439. ;    Get file names from command line
  440.  
  441. GetFile    Proc    Near            ;Get file name(s)
  442.     Mov    SI,80h            ;Point to command line
  443.     Sub    CX,CX            ;The PSP may contain one or two
  444.     Or    CL,Byte    Ptr DS:[SI]    ; filenames separated by blanks
  445.     Jnz    GetF0
  446. GetUse:    Mov    DX,Offset Version    ;None, display usage message
  447.     Jmp    Error
  448.  
  449. GetF0:    Mov    DI,Offset Input        ;Target    is infile for
  450.     Inc    SI            ; first    command    operand
  451.  
  452. GetF1:    Lodsb                ;Copy command line to file names
  453.     Cmp    AL,' '            ; by skipping leading blanks
  454.     Jne    GetF1a            ; until    a CR is    found
  455.     Loope    GetF1
  456.     JCXz    GetUse            ;If all    blank
  457.  
  458. GetF1a:    Cmp    AL,CR            ;Is it CR, end of line?
  459.     Je    GetF5            ; yes, terminate infile    name
  460.     Cmp    AL,'/'            ;Or option string?
  461.     Je    GetF1c
  462.     Cmp    AL,' '            ;Ending    blank?
  463.     Je    GetF2
  464.     Stosb
  465.     Lodsb
  466.     Loop    GetF1a
  467.     Jmp    short GetF5    ;TH
  468.  
  469. GetF1c:    Mov    AX,0FF00h        ;Terminate fname operand
  470.     Stosw
  471.     Lodsb                ;Get option letter
  472.     Cmp    AL,'D'            ;Set /D    option for detabbing
  473.     Je    GetF1d
  474.     Cmp    AL,'d'
  475.     Jne    GetF3
  476. GetF1d:    Mov    Detab,Stopper
  477. GetF3:
  478.     Jmp    short GetF6
  479.  
  480. GetF2:    Mov    AX,0FF00h        ;Terminate fname operand
  481.     Stosw
  482.     Lea    DI,ES:Output        ;Process second    fname
  483. GetF2a:    Lodsb
  484.     Cmp    AL,' '            ;Skip intervening blanks
  485.     Jne    GetF2b
  486.     Loope    GetF2a
  487.     JCXz    GetF6            ;If no operand
  488.  
  489. GetF2b:    Cmp    AL,CR            ;Is it CR, end of line?
  490.     Je    GetF5            ; yes, end of name
  491.     Cmp    AL,'/'            ;Or option string?
  492.     Je    GetF1c            ; yes, copy it
  493.     Cmp    AL,' '            ;Or ending blank?
  494.     Je    GetF2c
  495.     Stosb                ;Copy second operand
  496.     Mov    NewPtr,DI
  497. GetF2c:    Lodsb
  498.     Loop    GetF2b
  499.  
  500. GetF5:    Mov    AX,0FF00h        ;Append    zero and dollar    sign
  501.     Stosw
  502.  
  503. GetF6:
  504. GetF7:    Cmp    Input,0            ;Any input name?
  505.     Jne    GetF8            ; yes, try output name
  506.     Jmp    GetUse            ; no, display usage
  507.  
  508. GetF8:
  509.     Call    Find            ;Find first matching file
  510. GetF8a:    Cmp    Output,0        ;Any output name?
  511.     Jne    GetF9            ; yes, further check name
  512.     Cmp    Input+1,':'        ;Make sure don't over-write
  513.     Je    GetFo            ; the input file
  514.     Jmp    GetUse
  515.  
  516. GetF9:    Cmp    Word Ptr OutPut+1,003Ah    ;If just a drive is given
  517.     Jne    GetFp            ; for the output
  518.     Mov    DI,Offset OutPut+2    ;Skip over drive
  519.     Mov    Newptr,DI
  520.     Jmp    Short GetFo        ; and copy as outfile name
  521.  
  522. GetFp:    Cmp    Word Ptr Output+1,'\:'    ;Drive and path?
  523.     Je    GetFs            ; yes, append infile name
  524.     Cmp    Byte Ptr Output,'\'    ;Just a    path?
  525.     Jne    GetFend            ; no, outfile is a filename
  526.  
  527. GetFs:    Mov    DI,NewPtr        ;Append    path delimiter
  528.     Mov    AL,'\'
  529.     Stosb
  530.     Mov    NewPtr,DI
  531. GetFo:    Mov    CX,74            ;Copy the input    filename
  532.     Mov    DI,NewPtr        ; after    the outfile spec
  533.     Mov    SI,FilePtr
  534.     Rep    Movsb
  535. GetFend:Ret
  536. GetFile    Endp
  537.     Page
  538. ;
  539. ;    Find first matching file, just cuz I'm lazy
  540.  
  541. Find    Proc    Near            ;Find first matching file
  542.     Mov    DX,Offset DTA        ;Set data xfer area
  543.     Mov    AH,1Ah
  544.     Int    21h
  545.     Mov    DX,Offset Input        ;Input path\filename.ext
  546.     Sub    CX,CX            ;Search    for first normal file
  547.     Mov    AH,4Eh
  548.     Int    21h
  549.     Jnc    Find1
  550. Find0:    Mov    DX,Offset Msg4e        ;Say NO    MATCHING FILE
  551.     Jmp    Error
  552.  
  553. Find1:    Or    AL,AL            ;Set ZF    for return
  554.     Jnz    Find0            ; if none found
  555.     Mov    DI,Offset Input
  556.     Cmp    Byte Ptr [DI+1],':'    ;If drive was supplied
  557.     Jne    Find2            ; leave    it in file name
  558.     Add    DI,2
  559. Find2:    Cmp    Byte Ptr [DI],'\'    ;If path was supplied
  560.     Jne    Find4a            ; try to leave it in Input name
  561.     Mov    SI,Offset Input+75
  562.     Std
  563.     Mov    CX,76
  564. Find3:    Lodsb
  565.     Cmp    AL,'\'            ;Find the last separator
  566.     Je    Find4            ; which    is the filename    spec
  567.     Loop    Find3
  568.     Mov    SI,DI
  569.  
  570. Find4:    Mov    DI,SI
  571.     Add    DI,2
  572. Find4a:    Mov    FilePtr,DI        ;Save addr of filename part
  573. Find5:    Mov    CX,13            ;Copy found name to Input name
  574.     Mov    DI,FilePtr
  575.     Cld
  576.     Mov    SI,Offset DTA+30    ; after    drive and first    path name
  577. Find7:    Lodsb
  578.     Stosb
  579. ;    Cmp    AL,0            ;Don't want crud in message
  580.     or    al,al        ;TH    ;Don't want crud in message
  581.     Loopne    Find7
  582. Find9:    Mov    AL,Stopper
  583.     Stosb
  584.     Sub    AL,AL            ;Set good return code
  585.     Ret
  586.  
  587. Next:    Mov    AH,4Fh            ;Get next matching file
  588.     Int    21h
  589.     Or    AL,AL            ; any more?
  590.     Jnz    Nexted            ; no, just return
  591.  
  592. ;TH    Mov    Qsw,0            ;Re-initialize
  593. ;TH    Mov    Sw,0
  594.     Mov    AX,BufLen
  595.     Mov    Olen,AX            ;Reset buffer counts
  596. ;TH    Mov    Ilen,0
  597.     xor    ax,ax        ;TH get a zero
  598.     mov    Qsw,al        ;TH
  599.     mov    Sw,al        ;TH
  600.     mov    Ilen,ax        ;TH
  601.     Mov    AX,Out_Ptr        ;Reset buffer ptrs
  602.     Mov    Optr,AX
  603.     Mov    AX,In_Ptr
  604.     Mov    Iptr,AX
  605.     Mov    AX,Offset Output    ;Was output name supplied?
  606.     Cmp    AX,Newptr
  607.     Jne     Next1
  608.     Mov    Output,0        ;Reset output file name
  609. Next1:
  610.     Mov    CX,8            ;Clear message prefix
  611.     Mov    SI,Offset Spaces
  612.     Mov    DI,Offset InformD
  613.     Rep    Movsb
  614. ;TH    Mov    Cooking,CR
  615. ;TH    Mov    Cooking+1,LF
  616.     mov    word ptr Cooking,CRLF    ;TH
  617.  
  618.     Mov    DI,NewPtr        ;Copy input name as output name
  619.     Mov    CX,13
  620.     Mov    SI,Offset DTA+30
  621. Next7:    Lodsb
  622.     Stosb
  623. ;    Cmp    AL,0            ;Don't want crud in message
  624.     or    al,al        ;TH    ;Don't want crud in message
  625.     Loopne    Next7
  626.     Mov    AL,Stopper
  627.     Stosb
  628.     Jmp    short Find5    ;TH    ; yes, copy the    name
  629. Nexted:    Ret
  630. Find    Endp
  631.  
  632.     Page
  633. ;
  634. ;    Display    "cooking" message
  635.  
  636. Inform    Proc    Near
  637.     Mov    DX,Offset Cooking
  638.     Cmp    Detab,0
  639.     Je    Inform1
  640.     Mov    DX,Offset InformD
  641. Inform1:Call    PrintS
  642.     Mov    DX,Offset Input
  643.     Call    PrintS
  644.     Mov    DX,Offset Mark
  645.     Call    PrintS
  646.     Mov    DX,Offset Output
  647.     Call    PrintS
  648.     Ret
  649. Inform    Endp
  650.  
  651. ChkVer    Proc    Near
  652.     Mov    AH,30h
  653.     Int    21h            ;Verify    DOS 2.0    or later
  654.     Cmp    AL,2
  655.     Jae    Chk9
  656.     Mov    DX,Offset Sorry
  657.     Jmp    Error
  658. Chk9:    Ret
  659. ChkVer    Endp
  660.  
  661. PrintS    Proc    Near            ;Print string like Int 21h (9)
  662.     Push    BX            ;DX points to string
  663.     Push    SI
  664.     Mov    SI,DX
  665. PS1:    Lodsb
  666.     Cmp    AL,Stopper        ;String    ends in    a hex FF
  667.     Je    PS9            ; so can display dollar    sign
  668. ;    Cmp    AL,0            ;Ignore    zeros
  669.     or    al,al        ;TH    ;Ignore zeros
  670.     Je    PS1
  671.     Mov    DL,AL
  672.     Mov    AH,2            ;Display to standard device
  673.     Int    21h
  674.     Jmp    short PS1    ;TH
  675.  
  676. PS9:    Pop    SI
  677.     Pop    BX
  678.     Ret
  679. PrintS    Endp
  680.  
  681.     Page
  682. ;
  683. ;    Allocate up to 32K per buffer by modifying memory
  684. ;    to use all of the 64K allowed for a COM    program.
  685. ;    This is    more complicated than using data segments
  686. ;    for the    buffers, but has the advantages    of allowing
  687. ;    for variable buffer sizes depending upon the amount
  688. ;    of memory available. It    also allows DS and ES to remain
  689. ;    static.    Besides, the COM version is under 2K bytes.
  690.  
  691. Alloc    Proc    Near            ;Get I/O buffers
  692.     Mov    CX,PgmSize        ;Program size in paragraphs
  693.     Mov    BX,Word    Ptr DS:[2]    ;DOS ending seg    address
  694.     Mov    AX,CS            ;My starting seg address
  695.     Sub    BX,AX            ;Paragraphs for    this COM program
  696.     Sub    BX,CX            ; less code size
  697.     Add    AX,CX            ;Next available    segment    addr
  698.  
  699.     Cmp    BX,Maxcore        ;Can only use 64k
  700.     Jbe    Alloc0
  701.     Mov    BX,Maxcore
  702. Alloc0:    Mov    In_Ptr,AX        ;Seg addr for input buffer
  703.     Cmp    BX,MinCore        ;Enough    just to    run?
  704.     Jb    Alloc1
  705.     Sub    BX,32            ;Size less stack and PSP
  706. Alloc2:    Sar    BX,1            ;Paras for each    buffer
  707.     Add    AX,BX
  708.     Mov    Out_Ptr,AX        ;Seg addr for output buffer
  709.  
  710.     Mov    AX,BX
  711.     Mov    CL,4
  712.     Shl    AX,CL            ;Convert to bytes
  713.     Mov    BufLen,AX
  714.     Mov    Olen,AX
  715.     Cmp    AX,Minpara        ;Have enough?
  716.     Jb    Alloc0            ; nope,    bye
  717.  
  718.     Mov    DX,DS            ;Convert ptrs to offsets
  719.     Mov    AX,In_Ptr
  720.     Sub    AX,DX
  721.     Shl    AX,CL
  722.     Mov    In_Ptr,AX
  723.     Mov    Iptr,AX
  724.  
  725.     Mov    AX,Out_Ptr
  726.     Sub    AX,DX
  727.     Shl    AX,CL
  728.     Mov    Out_Ptr,AX
  729.     Mov    Optr,AX
  730.     Ret
  731.  
  732. Alloc1:    Mov    DX,Offset Msg4a        ;Not enough memory
  733.     Jmp    Error
  734.  
  735. Alloc    Endp
  736.  
  737. Tabs    Endp
  738.  
  739. Rec    Db    0            ;Current record
  740.  
  741. PgmEnd    Equ    $+MaxRec
  742.  
  743. PgmSize    Equ    (PgmEnd-Cseg+256)/16    ;Cseg and stack    length
  744. Maxcore    Equ    4096-PgmSize        ;Max I/O buffer    size, paras
  745. Minpara    Equ    32
  746.  
  747. Cseg    Ends
  748.     End    Tabs
  749.