home *** CD-ROM | disk | FTP | other *** search
/ ftp.update.uu.se / ftp.update.uu.se.2014.03.zip / ftp.update.uu.se / pub / rainbow / msdos / misc / tabs.lzh / TABS.ASM next >
Assembly Source File  |  1985-06-19  |  15KB  |  656 lines

  1.     Page    82,132
  2.     Title    TABS - Align ASCII File
  3.  
  4.     Comment    | Version 1.6, June 27,    1984
  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.  
  30. CSeg    Segment    Public Para 'CODE'
  31.     Assume    CS:Cseg,DS:Cseg,ES:CSeg
  32.     Org    100h
  33.  
  34. Tabs    Proc    Far
  35.     Push    DS            ;DOS convention
  36.     Sub    AX,AX
  37.     Push    AX
  38.  
  39.     Mov    CS:Stk_Top,SP        ;Save stack ptr    to insure return
  40.  
  41.     Call    ChkVer            ;Check for DOS 2
  42.  
  43.     Call    Alloc            ;Get maximum I/O buffers
  44.  
  45.     Call    GetFile            ;Get file names
  46.  
  47.     Call    OpenIn            ;Open input
  48.  
  49.     Call    OpenOut            ; and output
  50.  
  51.     Call    Inform            ;Display "cooking" message
  52.  
  53.     Call    GenTab            ;Generate tabs
  54.  
  55.     Call    Flush            ;Empty the output buffer
  56.  
  57.     Mov    DX,Offset EofMsg    ;Say END-OF-FILE
  58. Error:    Mov    SP,Stk_Top        ;Insure    proper return
  59.     Call    PrintS            ;Print any message
  60.  
  61.     Call    Close            ;Close files
  62.  
  63.     Ret                ;Return    to DOS
  64.     Page
  65.  
  66. Buflen    Dw    0            ;I/O buffer size
  67. MinCore    Dw    512            ;Minimum of one sector
  68. Maxrec    Equ    255            ;Longest logical record
  69.  
  70. S_Quote    Equ    34            ;Single    quote
  71. D_Quote    Equ    39            ;Double    quote
  72. Tab    Equ    9
  73. Lf    Equ    10
  74. Cr    Equ    13
  75. EOF    Equ    1Ah
  76.  
  77. Rec    Db    Maxrec Dup (0)        ;Current record
  78. Sw    Db    0            ;Number    of blanks skipped
  79. Qsw    Db    0            ;Quote switch
  80. Detab    Db    0            ;Non-zero for detab function
  81. Stk_Top    Dw    0            ;SP at entry
  82.  
  83. MsgIn    Db    Cr,Lf,'Enter INPUT file name-  ',255
  84. Msg1    Db    Cr,Lf,'Input failed to open, '
  85. InKey    Db    32,32            ;Keyboard buffer
  86. Input    Db    76 Dup (0),0,255    ;Drive:path\name.ext
  87. IHandle    Dw    0            ;Input file handle
  88. Ilen    Dw    0            ;Input block length
  89. Iptr    Dw    0            ;Offset    to next    char
  90. In_Ptr    Dw    0            ;Seg offset
  91.  
  92. MsgOut    Db    Cr,Lf,'Enter OUTPUT file name- ',255
  93. Msg2    Db    Cr,Lf,'Output failed to open, '
  94. OutKey    Db    32,32
  95. Output    Db    76 Dup (0),0,255
  96. OHandle    Dw    0            ;Output    file handle
  97. Olen    Dw    0            ;Bytes in output buffer
  98. Optr    Dw    0            ;Offset    to next    char
  99. Out_Ptr    Dw    0            ;Seg offset
  100.  
  101. DTA    Db    48 Dup (0)
  102.     Page
  103. Sorry    Db    Cr,Lf,'Sorry, PC DOS Version 2 required',Cr,Lf,255
  104. Msg3f    Db    Cr,Lf,'I/O error reading',Cr,Lf,255
  105. Msg40    Db    Cr,Lf,'I/O error writing',Cr,Lf,255
  106. Msg4a    Db    Cr,Lf,'Insufficient memory',Cr,Lf,255
  107. Msg4e    Db    Cr,Lf,'No matching file(s) found',Cr,Lf,255
  108. InformD    Db    'DE-'
  109. Cooking    Db    'TABS:     ',255
  110.     Db    'Version 1.6 by Vernon Buerg, '
  111.     Db    'June 27, 1984, public domain.'
  112. Mark    Db    ' => ',255
  113. EofMsg    Db    Cr,Lf,'End of File',Cr,Lf,255
  114. NewLine    Db    CR,LF,255
  115.  
  116. Code2    Db    'File not found ',255
  117. Code3    Db    'Path not found ',255
  118. Code4    Db    'Too many files ',255
  119. Code5    Db    'Access denied  ',255
  120.     Page
  121. ;
  122. ;    Replace    blanks with tabs
  123.  
  124. GenTab    Proc    Near
  125. Loop:    Call    GetRec            ;Get a record, length in CX
  126.     Sub    BX,BX            ;Output    column
  127.     Mov    Sw,BL            ;No blanks yet
  128.     Mov    Qsw,BL            ;No quotes yet
  129.     Or    CX,CX            ;Any data in record?
  130.     Jz    Null            ; no, just CR-LF
  131.  
  132. Set1:    Mov    SI,Offset Rec        ;Look for blanks and
  133. Wloop:    Lodsb                ; replace strings of blanks
  134.     Inc    BX            ; with tab characters
  135.     Cmp    AL,D_Quote        ;Don't count blanks
  136.     Jne    Chk1            ; within single    or double
  137.     Xor    Qsw,2            ; quoted strings
  138.     Jmp    Chk2
  139.  
  140. Chk1:    Cmp    AL,S_Quote        ;Insert    TABs for any
  141.     Jne    Chk3            ; blanks skipped before
  142.     Xor    Qsw,1            ; a quote
  143. Chk2:    Cmp    Sw,0            ;Must re-insert
  144.     Je    Check            ; any blanks skipped
  145.     Jmp    Insert            ; if not enough    for a TAB
  146.  
  147. Chk3:    Cmp    Detab,0            ;Leave expanded    record as-is
  148.     Jne    Check            ; if de-tabbing
  149.     Cmp    AL,' '            ;Tis a blank?
  150.     Jne    Check            ; no, see if eof
  151.     Test    Qsw,3            ;Within    quotes?
  152.     Jnz    Check
  153.     Inc    Sw
  154.     Test    BL,07h            ;Ready for a tab?
  155.     Jnz    Tloop            ; no, keep going
  156.     Mov    AL,Tab            ; yes, send one
  157.     Jmp    Copy
  158.  
  159. Check:    Cmp    AL,EOF            ;End of    file?
  160.     Je    Done            ; yes, all done
  161.     Cmp    Detab,0
  162.     Jne    Copy
  163.     Test    Qsw,3            ;When a    non-blank is
  164.     Jnz    Copy            ; encountered, insert a    TAB
  165.     Cmp    Sw,0            ; if there were    blanks
  166.     Je    Copy            ; before it
  167.     Mov    DX,BX
  168.     Dec    DL
  169.     Test    DL,07h            ;If the    non-blank is not
  170.     Jnz    Insert            ; in a TAB column, then
  171.     Push    AX            ; keeps    all the    blanks
  172.     Mov    AL,Tab
  173.     Call    PutChar
  174.     Pop    AX
  175. Copy:    Call    PutChar            ; and write it
  176.     Mov    Sw,0            ;Ind not blank
  177. Tloop:    Loop    Wloop
  178. Null:    Mov    AL,Cr            ;Append    CR
  179.     Call    PutChar
  180.     Mov    AL,Lf            ; and LF
  181.     Call    PutChar
  182.     Jmp    Loop
  183.  
  184. Insert:    Push    AX            ;Insert    any blanks that
  185.     Mov    DL,Sw            ; didn't line up on
  186. Blanks:    Cmp    DL,1            ; a TAB    column
  187.     Jb    None
  188.     Mov    AL,' '
  189.     Call    PutChar
  190.     Dec    DL            ;Decr insert count
  191.     Jmp    Blanks            ; and continue
  192. None:    Pop    AX            ;Get char back
  193.     Jmp    Copy
  194.  
  195. Done:    Ret
  196. GenTab    Endp
  197.     Page
  198. ;
  199. ;    Build a    logical    record with TABs expanded
  200.  
  201. GetRec    Proc    Near
  202. ;    Push    DI
  203.     Sub    DI,DI            ;Target    record offset
  204.     Mov    Qsw,0            ;Quote indicator
  205.  
  206. Get1:    Call    GetChar            ;Build up a logical record
  207.     Cmp    AL,Cr            ; by looking for a CR or LF
  208.     Je    Get1            ; as end-of-record
  209.     Cmp    AL,Lf
  210.     Je    Get7
  211.     Cmp    AL,S_Quote        ;Don't expand tabs
  212.     Jne    Get2            ; found    within a
  213.     Xor    Qsw,1            ; quoted string
  214. Get2:    Cmp    AL,D_Quote
  215.     Jne    Get3
  216.     Xor    Qsw,2
  217. Get3:    Cmp    AL,Tab            ;Is it TAB?
  218.     Jne    Get5            ; no, pass it
  219.     Test    Qsw,3            ;Within    quotes?
  220.     Jnz    Get5            ; yes, pass it as-is
  221. Get4:    Mov    Rec[DI],' '        ;Expand    embedded tabs
  222.     Inc    DI            ; with blanks
  223.     Test    DI,0007h
  224.     Jz    Get1
  225.     Jmp    Get4
  226.  
  227. Get5:    Mov    Rec[DI],AL        ;Build the record by
  228.     Inc    DI            ; copying each character
  229.     Cmp    DI,Maxrec        ; or TABs expanded to blanks
  230.     Jae    Get6
  231.     Cmp    AL,EOF            ;Is it EOF?
  232.     Je    Get6            ; yes, all done
  233.     Jmp    Get1            ; no, continue
  234. Get6:    Mov    CX,DI            ;Final record length
  235. ;    Pop    DI
  236.     Ret
  237.  
  238. Get7:    Cmp    Rec-1[DI],' '        ;Omit trailing blanks
  239.     Jne    Get6
  240.     Dec    DI
  241.     Jz    Get6
  242.     Jmp    Get7
  243.  
  244. GetRec    Endp
  245.     Page
  246. ;
  247. ;    Extract    one char from record
  248.  
  249. GetChar    Proc    Near            ;Read char into    AL
  250. Read1:    Dec    Ilen            ;Any in    buffer?
  251.     Js    Read            ; no, read next    block
  252.     Mov    SI,Iptr            ; yes, get offset in buf
  253.     Lodsb
  254.     Mov    Iptr,SI            ;Offset    for next one
  255.     Cmp    AL,EOF
  256.     Je    Read2            ;Ignore    EOF marks
  257.     Ret
  258. Read2:    Mov    AL,' '
  259.     Ret
  260.  
  261. Read:    Push    CX
  262.     Mov    BX,IHandle        ;Read a    block of data
  263.     Mov    CX,BufLen        ; into Input (segment) buffer
  264.     Mov    DX,In_Ptr
  265.     Mov    Iptr,DX
  266.     Mov    AH,3Fh
  267.     Int    21h
  268.     Pop    CX
  269.     Mov    Ilen,AX            ; and length
  270.     Jc    Read3
  271.     Or    AX,AX            ;Anything read?
  272.     Jnz    Read1            ; yes, pick it up
  273.     Mov    AL,EOF            ; no, return EOF
  274.     Ret
  275.  
  276. Read3:    Mov    DX,Offset Msg3f        ;Say I/O ERROR
  277.     Jmp    Error
  278. GetChar    Endp
  279.     Page
  280. ;
  281. ;    Block output records
  282.  
  283. PutChar    Proc    Near            ;Write from AL
  284.     Push    CX
  285. ;    Push    DI
  286.     Mov    DI,Optr            ;Offset    in buffer
  287.     Stosb
  288.     Mov    Optr,DI            ;New buffer ptr
  289.     Inc    Olen
  290.     Mov    CX,Buflen
  291.     Cmp    Olen,CX            ;Full block?
  292.     Jae    Write3            ; yes, write it
  293. ;rite1:    Pop    DI
  294. Write1:    Pop    CX
  295.     Ret
  296.  
  297. Flush:    Push    CX            ;Write data left over
  298. ;    Push    DI            ; in output buffer
  299.     Mov    CX,Olen            ;Any left in output?
  300.     Or    CX,CX
  301.     Jnz    Write3
  302.     Jmp    Write1
  303.  
  304. Write3:    Push    AX
  305.     Push    BP
  306.     Push    BX
  307.     Push    DX
  308.     Mov    BX,OHandle        ;Get file handle
  309.     Mov    BP,CX            ;Save size requested
  310.     Mov    DX,Out_Ptr
  311.     Mov    Optr,DX
  312.     Mov    AH,40h            ;Write the block
  313.     Int    21h
  314.     Jc    Writer            ;Write OK?
  315.     Sub    BP,AX            ;Wrote all data?
  316.     Mov    Olen,BP
  317.     Jz    Write2            ; yes, good
  318. Writer:    Mov    DX,Offset Msg40        ; no, say I/O error
  319.     Jmp    Error
  320.  
  321. Write2:    Pop    DX
  322.     Pop    BX
  323.     Pop    BP
  324.     Pop    AX
  325. ;    Pop    DI
  326.     Pop    CX
  327.     Ret
  328. PutChar    Endp
  329.     Page
  330.  
  331. ;    Open input file
  332.  
  333. OpenIn    Proc    Near
  334.     Mov    DX,Offset Input
  335.     Mov    AL,0            ;For input
  336.     Mov    AH,3Dh            ;Open a    file
  337.     Int    21h
  338.     Jnc    Openi
  339.     Mov    DX,Offset Msg1
  340.     Jmp    OpenErr
  341.  
  342. Openi:    Mov    IHandle,AX
  343.     Ret
  344. OpenIn    Endp
  345.  
  346. ;    Open output file
  347.  
  348. OpenOut    Proc    Near
  349.     Mov    DX,Offset Output
  350.     Sub    CX,CX            ;Normal    file attribute
  351.     Mov    AH,3Ch            ;Create    a file
  352.     Int    21h
  353.     Jnc    Openo
  354.     Mov    DX,Offset Msg2
  355.     Jmp    OpenErr
  356.  
  357. Openo:    Mov    OHandle,AX
  358.     Ret
  359. OpenOut    Endp
  360.  
  361. ;    Determine why OPEN failed
  362.  
  363. OpenErr:Cmp    AL,2            ;AL has    reason code
  364.     Jb    Opene
  365.     Cmp    AL,5
  366.     Ja    Opene
  367.     Sub    BX,BX            ;Get offset to reason
  368.     Mov    BL,AL            ; text for open    failure
  369.     Mov    CL,4
  370.     Shl    BX,CL
  371.     Call    PrintS            ;Say OPEN FAILED
  372.     Mov    DX,Offset NewLine
  373.     Call    PrintS
  374.     Lea    DX,Code2-32[BX]
  375. Opene:    Jmp    Error
  376.  
  377. ;    Close input/output
  378.  
  379. Close    Proc    Near            ;Close files
  380.     Mov    BX,OHandle        ; output
  381.     Mov    AH,3Eh
  382.     Int    21h
  383.     Mov    BX,IHandle        ; input
  384.     Mov    AH,3Eh
  385.     Int    21h
  386.     Ret
  387. Close    Endp
  388.     Page
  389. ;
  390. ;    Find first matching file, just cuz I'm lazy
  391.  
  392. Find    Proc    Near            ;Find first matching file
  393.     Mov    DX,Offset DTA        ;Set data xfer area
  394.     Mov    AH,1Ah
  395.     Int    21h
  396.     Mov    DX,Offset Input        ;Input path\filename.ext
  397.     Sub    CX,CX            ;Search    for first normal file
  398.     Mov    AH,4Eh
  399.     Int    21h
  400.     Jnc    Find1
  401. Find0:    Mov    DX,Offset Msg4e        ;Say NO    MATCHING FILE
  402.     Jmp    Error
  403.  
  404. Find1:    Or    AL,AL            ;Set ZF    for return
  405.     Jnz    Find0            ; if none found
  406.     Mov    DI,Offset Input
  407.     Cmp    Byte Ptr [DI+1],':'    ;If drive was supplied
  408.     Jne    Find2            ; leave    it in file name
  409.     Add    DI,2
  410. Find2:    Cmp    Byte Ptr [DI],'\'    ;If path was supplied
  411.     Jne    Find5            ; try to leave it in Input name
  412.     Mov    SI,Offset Input+75
  413.     Std
  414.     Mov    CX,76
  415. Find3:    Lodsb
  416.     Cmp    AL,'\'            ;Find the last separator
  417.     Je    Find4            ; which    is the filename    spec
  418.     Loop    Find3
  419.     Mov    SI,DI
  420.  
  421. Find4:    Mov    DI,SI
  422.     Add    DI,2
  423. Find5:    Mov    CX,13            ;Copy found name to Input name
  424.     Cld
  425.     Mov    SI,Offset DTA+30    ; after    drive and first    path name
  426. Find7:    Lodsb
  427.     Stosb
  428.     Cmp    AL,0            ;Don't want crud in message
  429.     Je    Find9
  430.     Loop    Find7
  431. Find9:    Ret
  432. Find    Endp
  433.     Page
  434. ;
  435. ;    Get file names from command line
  436.  
  437. GetFile    Proc    Near            ;Get file name(s)
  438.     Mov    SI,80h            ;Point to command line
  439.     Sub    CX,CX            ;The PSP may contain one or two
  440.     Or    CL,Byte    Ptr DS:[SI]    ; filenames separated by blanks
  441.     Jz    GetF6
  442.     Lea    DI,ES:Input        ;Target    is infile for
  443.     Inc    SI            ; first    command    operand
  444.  
  445. GetF1:    Lodsb                ;Copy command line to file names
  446.     Cmp    AL,' '            ; by skipping leading blanks
  447.     Jne    GetF1a            ; until    a CR is    found
  448.     Loope    GetF1
  449.     JCXz    GetF6            ;If all    blank
  450.  
  451. GetF1a:    Cmp    AL,Cr            ;Is it CR, end of line?
  452.     Je    GetF5            ; yes, terminate fname
  453.     Cmp    AL,'/'            ;Or option string?
  454.     Je    GetF1c
  455.     Cmp    AL,' '            ;Ending    blank?
  456.     Je    GetF2
  457.     Stosb
  458.     Lodsb
  459.     Loop    GetF1a
  460.     Jmp    GetF5
  461.  
  462. GetF1c:    Mov    AX,0FF00h        ;Terminate fname operand
  463.     Stosw
  464.     Lodsb                ;Get option letter
  465.     Cmp    AL,'D'            ;Set /D    option for detabbing
  466.     Je    GetF1d
  467.     Cmp    AL,'d'
  468.     Jne    GetF3
  469. GetF1d:    Mov    Detab,255
  470. GetF3:
  471.     Jmp    GetF6
  472.  
  473. GetF2:    Mov    AX,0FF00h        ;Terminate fname operand
  474.     Stosw
  475.     Lea    DI,ES:Output        ;Process second    fname
  476. GetF2a:    Lodsb
  477.     Cmp    AL,' '            ;Skip intervening blanks
  478.     Jne    GetF2b
  479.     Loope    GetF2a
  480.     JCXz    GetF6            ;If no operand
  481.  
  482. GetF2b:    Cmp    AL,Cr            ;Is it CR, end of line?
  483.     Je    GetF5            ; yes, end of command
  484.     Cmp    AL,'/'            ;Or option string?
  485.     Je    GetF1c            ; yes, copy it
  486.     Cmp    AL,' '            ;Or ending blank?
  487.     Je    GetF2c
  488.     Stosb                ;Copy second operand
  489. GetF2c:    Lodsb
  490.     Loop    GetF2b
  491.  
  492. GetF5:    Mov    AX,0FF00h        ;Append    zero and dollar    sign
  493.     Stosw
  494.  
  495. GetF6:    Mov    AX,CS            ;When done, set    up
  496.     Mov    DS,AX            ; segment registers
  497.     Mov    ES,AX
  498.  
  499. GetF7:    Cmp    Input,0            ;Any input name?
  500.     Jne    GetF8            ; yes, try output name
  501.     Mov    DI,Offset MsgIn        ; no, ask for one
  502.     Mov    SI,Offset InKey
  503.     Call    AskName            ;Get the input file name
  504.  
  505. GetF8:
  506.     Call    Find            ;Find first matching file
  507. GetF8a:    Cmp    Output,0        ;Any output name?
  508.     Jne    GetF9            ; yes, that was    easy
  509.     Mov    DI,Offset MsgOut    ; no, ask for it
  510.     Mov    SI,Offset OutKey
  511.     Call    AskName            ;Get the output    name
  512.  
  513. GetF9:    Cmp    Word Ptr Output+1,003Ah    ;If just a drive is given
  514.     Jne    GetFend            ; for the output,
  515.     Mov    CX,74            ; use the input    filename
  516.     Mov    DI,Offset Output+2
  517.     Mov    SI,Offset Input
  518.     Cmp    Input+1,':'        ;If drive was given for
  519.     Jne    GetF10            ; input, must skip over    it
  520.     Sub    CL,2            ;Adjust    pointers passed    drive
  521.     Add    SI,2
  522. GetF10:    Rep    Movsb
  523.  
  524. GetFend:Ret
  525. GetFile    Endp
  526.     Page
  527. ;
  528. ;    Ask for    file name(s)
  529.  
  530. AskName    Proc    Near            ;Ask for input file name
  531.     Push    DI            ;Ptr to    prompt msg
  532.     Push    SI            ;Ptr to    reply buffer
  533.     Mov    Byte Ptr [SI],76    ;Reply length
  534. Ask1:    Mov    DX,DI
  535.     Call    PrintS            ;Print the prompt msg
  536.     Mov    DX,SI            ;Read console reply
  537.     Mov    AH,10
  538.     Int    21h
  539.     Sub    BX,BX            ;If a reply is given,
  540.     Add    BL,1[SI]        ; append a zero    as the
  541.     Jz    Ask1            ; ASCIIZ name stopper
  542.     Mov    Word Ptr 2[SI][BX],0FF00h
  543.     Mov    Word Ptr 0[SI],'  '    ;Clear error message part
  544.     Pop    SI
  545.     Pop    DI
  546.     Ret
  547. AskName    Endp
  548.  
  549. ;    Display    "cooking" message
  550.  
  551. Inform    Proc    Near
  552.     Mov    DX,Offset NewLine
  553.     Call    PrintS
  554.     Mov    DX,Offset Cooking
  555.     Cmp    Detab,0
  556.     Je    Inform1
  557.     Mov    DX,Offset InformD
  558. Inform1:Call    PrintS
  559.     Mov    DX,Offset Input
  560.     Call    PrintS
  561.     Mov    DX,Offset Mark
  562.     Call    PrintS
  563.     Mov    DX,Offset Output
  564.     Call    PrintS
  565.     Ret
  566. Inform    Endp
  567.  
  568. ChkVer    Proc    Near
  569.     Mov    AH,30h
  570.     Int    21h            ;Verify    DOS 2.0    or later
  571.     Cmp    AL,2
  572.     Jae    Chk9
  573.     Mov    DX,Offset Sorry
  574.     Jmp    Error
  575. Chk9:    Ret
  576. ChkVer    Endp
  577.  
  578. PrintS    Proc    Near            ;Print string like Int 21h (9)
  579.     Push    BX            ;DX points to string
  580.     Push    SI
  581.     Mov    SI,DX
  582. PS1:    Lodsb
  583.     Cmp    AL,255            ;String    ends in    a hex FF
  584.     Je    PS9            ; so can display dollar    sign
  585.     Cmp    AL,0            ;Ignore    zeros
  586.     Je    PS1
  587.     Mov    BX,7
  588.     Mov    AH,14            ;TTY write
  589.     Int    10h
  590.     Jmp    PS1
  591.  
  592. PS9:    Pop    SI
  593.     Pop    BX
  594.     Ret
  595. PrintS    Endp
  596.  
  597.     Page
  598. ;
  599. ;    Allocate up to 32K per buffer by modifying memory
  600. ;    to use all of the 64K allowed for a COM program.
  601. ;    This is more complicated than using data segments
  602. ;    for the buffers, but has the advantages of allowing
  603. ;    for variable buffer sizes depending upon the amount
  604. ;    of memory available. It also allows DS and ES to remain
  605. ;    static. Besides, the COM version is under 2K bytes.
  606.  
  607. Alloc    Proc    Near            ;Get I/O buffers
  608.     Mov    BX,PgmSize        ;Paras in program
  609.     Mov    AH,4Ah            ; and modify allocated memory
  610.     Int    21h            ; using ES from entry
  611.     Jnc    Alloc1
  612. Alloc0:    Mov    DX,Offset Msg4a
  613.     Jmp    Error
  614.  
  615. Alloc1:    Mov    BX,MaxCore        ;Get rest of 64k
  616. Alloc2:    Mov    AH,48h
  617.     Int    21h
  618.     Jc    Alloc2            ; but settle for what there is
  619.     Mov    In_Ptr,AX        ;Seg addr for input buffer
  620.     Sub    BX,32            ;Size less stack and PSP
  621.     Js    Alloc0
  622.     Sar    BX,1            ;Paras for each buffer
  623.     Add    AX,BX
  624.     Mov    Out_Ptr,AX        ;Seg addr for output buffer
  625.  
  626.     Mov    AX,BX
  627.     Mov    CL,4
  628.     Shl    AX,CL            ;Convert to bytes
  629.     Mov    BufLen,AX
  630.     Cmp    AX,MinCore        ;Have enough?
  631.     Jb    Alloc0
  632.  
  633.     Mov    DX,DS            ;Convert ptrs to offsets
  634.     Mov    AX,In_Ptr
  635.     Sub    AX,DX
  636.     Shl    AX,CL
  637.     Mov    In_Ptr,AX
  638.     Mov    Iptr,AX
  639.  
  640.     Mov    AX,Out_Ptr
  641.     Sub    AX,DX
  642.     Shl    AX,CL
  643.     Mov    Out_Ptr,AX
  644.     Mov    Optr,AX
  645.     Ret
  646. Alloc    Endp
  647.  
  648. Tabs    Endp
  649.  
  650. PgmSize    Equ    ($-Cseg+16)/16        ;Cseg and stack length
  651. MaxCore    Equ    4096-PgmSize        ;Max 64k COM
  652.  
  653. Cseg    Ends
  654.  
  655.     End    Tabs
  656.