home *** CD-ROM | disk | FTP | other *** search
/ Phoenix CD 2.0 / Phoenix_CD.cdr / 15a / lue19.zip / LUE19.ASM
Assembly Source File  |  1989-03-21  |  23KB  |  1,088 lines

  1.     Page    80,132
  2.  
  3.     Title    LUE - Extract LBR Member
  4.  
  5.     Comment | Version 1.93, February 22, 1985
  6.  
  7. LUE Command
  8. -----------
  9.  
  10. Purpose:   Extract a file (member) from an LU or LAR type library.
  11.  
  12. Format:    LUE    [d:][path]filename[.ext] filename[.ext]
  13.  
  14. Remarks:   The library name must be supplied. If the member file
  15.        name is omitted, all files are extracted.
  16.  
  17. Notes:       Written for the IBM PC using DOS 2.0 or later.
  18.        Copyright 1984 Vernon Buerg, for public domain use.
  19.  
  20.        LUE duplicates the A and E function of LU. The advantages
  21.        of LUE are:
  22.         - smaller, so a copy can be kept on the "system" disk
  23.         - faster, mucho
  24.         - handles paths and wildcards.
  25.         - retains input file or member date/time
  26.  
  27.        1.7 updates:
  28.         - checks for CRC in bytes 16-17
  29.         - allocate more memory for buffers, up to 60K
  30.        1.8 updates:
  31.         - extracts members in LU86 format
  32.        1.9 updates:
  33.         - default library extension to LBR
  34.         - allow multiple filenames on command line
  35.  
  36. ----------|
  37.  
  38. DirNtry Struc                ;LU/LAR directory entries
  39. D_Stat    Db    0            ;File status
  40. D_File    Db    8 Dup (' ')             ;File name (FCB format)
  41. D_Ext    Db    3 Dup (' ')             ;Extension part
  42. D_Ptr    Dw    0            ;Offset to data (mod 128)
  43. D_Len    Dw    0            ;Length, 128-byte sectors
  44.  
  45. D_CRC    Dw    0            ;CRC check bytes
  46. D_Cdate Dw    0            ;Create date
  47. D_Udate Dw    0            ;Update date
  48. D_Ctime Dw    0            ;Create time
  49. D_Utime Dw    0            ;Update time
  50. D_Pad    Dw    0,0,0            ;Pad bytes in last block
  51. DirNtry Ends
  52.     Page
  53. ;
  54. ;    Extract an LU member file
  55.  
  56. Cseg    Segment Public Para 'CODE'
  57.     Assume    CS:Cseg,DS:Cseg,ES:Cseg,SS:Cseg
  58.     Org    100h
  59.  
  60. Lue    Proc    Far
  61.     Lea    SP,Stackx        ; Use local stack
  62.     Push    DS            ; Standard entry
  63.     Sub    AX,AX            ;  for DOS return
  64.     Push    AX
  65.     Mov    StkTop,SP        ; Save stack ptr for return
  66.  
  67.     Call    ChkVer            ; Check DOS version
  68.  
  69.     Call    Alloc            ; Get buffers
  70.  
  71.     Call    GetParm         ; Get LBR and file name
  72.  
  73.     Call    OpenLbr         ; Access library
  74.  
  75.     Call    LoadDir         ; Load directory
  76.  
  77.     Call    Search            ; Find and extract file(s)
  78.  
  79.     Call    CloseLbr        ; Final close
  80.  
  81.     Mov    DX,Offset EofMsg
  82. Error:    Mov    AX,CS            ;Insure DS
  83.     Mov    DS,AX
  84.     Mov    SP,StkTop        ;Insure stack is proper
  85.     Call    PrintS            ;Display a message
  86.  
  87.     Ret                ;Return to DOS
  88.     Page
  89. ;
  90. ;    Messages, Constants, and Work Areas
  91.  
  92. Active    Equ    0
  93. Deleted Equ    254
  94. Unused    Equ    255
  95.  
  96. Dir_Len Equ    Size DirNtry
  97. Sector    Equ    128            ; Logical sector size
  98.  
  99. MaxPara Equ    (60*1024)/16        ; Maximum buffer size
  100. MinPara Equ    (12*1024)/16        ; Minumum buffer size
  101.  
  102. CR    Equ    13
  103. LF    Equ    10
  104. Stopper Equ    255            ; Ends message text
  105.  
  106. Mode    Db    0            ;Library format
  107. ;       01 = ***DIR format    02 = CRC included
  108. ;       04 = LU86 format    08 = CRC invalid
  109.  
  110. IHandle Dw    0            ;Input file handle
  111. OHandle Dw    0            ;Output file handle
  112. SecSize Dw    Sector
  113. BufSize Dw    0            ;Block size to use
  114.  
  115. BufSec    Dw    0            ;Sectors in a block
  116. S_Dir    Dw    0            ;Addr of DIR segment
  117. S_Buf    Dw    0            ;Addr of buffer segment
  118.  
  119. StkTop    Dw    0
  120. ParmNxt Dw    0            ; Pointer to next filename operand
  121. FilePtr Dw    0            ; Pointer to current filename
  122. FileNm    Db    13 Dup (0)        ; File name from command line
  123. LbrPtr    Dw    Offset LbrName        ; Offset to file name part
  124.  
  125. Entries Dw    0            ; Number of directory entries
  126. Counter Dw    0            ;  for search loop
  127. NumSecs Dw    0            ; Number of data sectors
  128. DirPtr    Dw    0            ; Points to next dir entry
  129. LenDir    Dw    0            ; Total directory size
  130.  
  131. Blanks    Db    13 Dup (' ')            ; Name in old format files
  132. DirKey    Db    '********DIR'           ;  in new format libs
  133. Year    Dw    0
  134.  
  135. Msg10    Db    CR,LF,'Requested member file not found  '
  136. Member    Db    8 Dup (' ')             ;Requested member file
  137. Ext    Db    3 Dup (' '),0,255
  138.  
  139. MsgE    Db    CR,LF,'Extracting  '
  140. NewName Db    13 Dup (0),255,' - from ',Stopper
  141.  
  142. ;
  143. ;    Error messages
  144.  
  145. Msg2    Db    CR,LF,'I/O error reading',CR,LF,255
  146. Msg7    Db    CR,LF,'LSEEK failed',CR,LF,255
  147. Msg8    Db    CR,LF,'CREATE failed for ',255
  148. EofMsg    Db    CR,LF,'End of file',CR,LF,255
  149.     Page
  150. ;
  151. ;    Insure Usable DOS version
  152.  
  153. ChkVer    Proc    Near
  154.     Mov    DX,Offset Version    ; Show current program version
  155.     Call    PrintS
  156.  
  157.     Mov    AH,30h            ; Get DOS version
  158.     Int    21h
  159.     Cmp    AL,2            ; Insure 2.0 or later
  160.     Jb    VerBad
  161.     Ret
  162.  
  163. VerBad: Mov    DX,Offset Sorry
  164.     Jmp    Error
  165.  
  166. Sorry    Db    CR,LF,'Sorry, PC DOS Version 2 required',CR,LF,255
  167. Version Db    'LUE - Version 1.92 - V.Buerg',CR,LF,Stopper
  168. ChkVer    Endp
  169.     Page
  170. ;
  171. ;    Allocate directory and I/O buffer
  172.  
  173. Alloc    Proc    Near
  174.     Mov    BX,Paras_C        ;Add up program size
  175.     Mov    AH,4Ah            ;Shrink memory
  176.     Int    21h
  177.  
  178. Alloc1: Mov    BX,MaxPara        ;Maximum memory requested
  179.     Mov    AH,48h
  180.     Int    21h
  181.     Jc    Alloc1            ;Get what there is
  182.  
  183.     Cmp    BX,MinPara        ;Have enough?
  184.     Jb    Alloc6
  185.     Mov    S_Dir,AX        ;Set directory segment
  186.  
  187.     Mov    CX,512            ;Paras in DIR
  188.     Add    AX,CX            ;Bump over 8k
  189.     Mov    S_Buf,AX        ; as I/O buffer
  190.     Sub    BX,CX            ;Paras in buffer
  191.     Mov    CL,3            ; into sectors
  192.     Shr    BX,CL
  193.     Mov    BufSec,BX
  194.  
  195.     Mov    AX,CS            ; Get offset to directory
  196.     Mov    DX,S_Dir        ;  rather than use segment addresses
  197.     Sub    DX,AX
  198.     Mov    CL,4
  199.     Shl    DX,CL
  200.     Mov    S_Dir,DX
  201.     Mov    DirPtr,DX
  202.     Ret
  203.  
  204. Alloc6: Mov    DX,Offset AlocMsg    ;Insufficient memory
  205.     Jmp    Error
  206.  
  207. AlocMsg Db    CR,LF,'Insufficient memory',255
  208. Alloc    Endp
  209.     Page
  210. ;
  211. ;    Get Command Tail Operands
  212. ;
  213. ;    Input:    DS must point to program PSP
  214. ;    Output:
  215. ;        Carry flag if any errors encountered, message sent
  216. ;        LbrName - receives the first operand, library file name
  217. ;        FileNm    - receives the second operand, a member name
  218. ;        FilePtr - points to the first member name
  219.  
  220. GetParm Proc    Near            ; First operand is LBR name
  221.     Mov    SI,82h            ; Second is requested member
  222.     Sub    CX,CX
  223.     Or    CL,DS:[80h]        ; Length of command operands
  224.     Jnz    Parm0
  225.     Jmp    Parm_Error        ; Library name missing
  226.  
  227. Parm0:    Mov    DI,Offset ParmFld    ; Save command operands
  228.     Rep    Movsb
  229.     Mov    CX,129            ;  and pad with CRs
  230.     Sub    CL,DS:[80h]
  231.     Mov    AL,CR
  232.     Rep    Stosb
  233.  
  234.     Mov    SI,Offset ParmFld    ; Point to operands
  235.     Mov    CL,DS:[80h]        ; and get length
  236.  
  237. Parm1:    Lodsb                ; Skip leading blanks
  238.     Cmp    AL,' '                  ; while Parming LBR name
  239.     Loope    Parm1
  240.  
  241.     Mov    DI,Offset LbrName    ; Copy library name operand
  242. Parm2:    Stosb
  243.     Lodsb
  244.     Cmp    AL,0Dh            ; The library name operand may end
  245.     Je    Parm20            ; in a blank but not a CR, because
  246.     Cmp    AL,'.'                  ; a CR means there are no filenames
  247.     Je    Parm2a
  248.     Cmp    AL,' '                  ; Copy the first operand and check for
  249.     Loopne    Parm2            ; an extension delimiter.
  250.     Jcxz    Parm_Error
  251. Parm20:
  252.         Mov    AX,'L.'                 ; If no extension is supplied,
  253.     Stosw                ; supply a default of .LBR
  254.     Mov    AX,'RB'
  255.     Stosw
  256.     Jmp    Short Parm2d
  257.  
  258. Parm2a: Stosb                ; Copy the extension
  259.     Lodsb
  260.     Cmp    AL,0Dh            ; End of lbr name?
  261.     Je    Parm2d
  262.     Cmp    AL,' '
  263.     Loopne    Parm2a
  264.  
  265. Parm2d: Mov    AX,0FF00h        ; Append ASCIIZ and print stopper
  266.     Stosw
  267. Parm2e: Mov    ParmNxt,SI        ; Set pointer to next operand
  268.  
  269.     Mov    SI,DI            ; Look for path or drive
  270.     Sub    SI,2
  271.     Mov    CX,SI
  272.     Sub    CX,Offset LbrName
  273.     Std
  274. Parm23: Lodsb
  275.     Cmp    AL,':'                  ; drive specifier?
  276.     Je    Parm24            ;  yes, may be start of file name part
  277.     Cmp    AL,'\'                  ; path specifier?
  278.     Je    Parm24
  279.     Loop    Parm23
  280.     Mov    SI,Offset LbrName    ; Simple filename
  281.     Jmp    Short Parm25
  282.  
  283. Parm24:    Add    SI,2
  284. Parm25: Mov    LbrPtr,SI        ;  followed by a filename
  285.     Cld
  286.     Clc
  287.     Ret
  288.  
  289. Parm_Error:                ; Library name missing
  290.     Mov    DX,Offset Usage     ; or member name(s) missing
  291.     Jmp    Error            ; Send usage message
  292.  
  293. Usage    Db    CR,LF,'Usage:  LUE  library[.LBR]  filename(s)',CR,LF,Stopper
  294. GetParm Endp
  295.     Page
  296. ;
  297. ;    Open the Library
  298.  
  299. OpenLbr Proc    Near            ;Open the library
  300.     Mov    DX,Offset MyDta     ; Set local data transfer area
  301.     Mov    AH,1Ah
  302.     Int    21h
  303.  
  304.     Mov    AH,4Eh            ; Find first matching file
  305.     Mov    DX,Offset LbrName
  306.     Sub    CX,CX
  307.     Int    21h
  308.     Jc    Error9            ; Library file not found
  309.  
  310.     Mov    CX,13            ; Copy first file name
  311.     Mov    SI,Offset MyDta+30
  312.     Mov    DI,LbrPtr
  313. Openl1: Lodsb                ; Copy until null found
  314.     Stosb
  315.     Cmp    AL,0
  316.     Loopne    Openl1
  317.     Mov    AL,Stopper
  318.     Stosb
  319.  
  320.     Mov    AX,3D00h        ; Open library file for reading
  321.     Mov    DX,Offset LbrName
  322.     Int    21h
  323.     Jc    Error1            ; Library failed to open
  324.     Mov    IHandle,AX        ; yes, save handle
  325.     Mov    DX,Offset MsgU        ; Show name of library in use
  326.     Call    PrintS
  327.     Mov    DX,Offset LbrName
  328.     Call    PrintS
  329.     Ret                ; and return
  330.  
  331. Error9: Mov    DX,Offset Msg9        ; Say LIBRARY not found
  332.     Jmp    Short Errorl
  333.  
  334. Error1: Mov    DX,Offset Msg1        ; Say OPEN FAILED
  335. Errorl: Call    PrintS
  336.     Mov    DX,Offset LbrName    ;  and add file name
  337.     Jmp    Error
  338.  
  339. Msg9    Db    CR,LF,'Library not found: ',Stopper
  340. Msg1    Db    CR,LF,'Unable to open:',Stopper
  341. MsgU    Db    CR,LF,'Using: ',Stopper
  342. OpenLbr Endp
  343.     Page
  344. ;
  345. ;    Get pointer to next command operand
  346.  
  347. GetNext Proc    Near            ; Returns ZF if there's an operand
  348.     Mov    Filenm,0
  349.     Mov    CX,14
  350.     Mov    DI,Offset FileNm    ; Copy the next operand as a
  351.     Mov    SI,ParmNxt        ; member file name
  352.     Cmp    Byte Ptr [SI],CR    ; No more operands?
  353.     Je    Parm7
  354. Parm3a: Lodsb
  355.     Cmp    AL,' '                  ; Skip leading blanks
  356.     Loope    Parm3a
  357.     Dec    SI
  358. Parm3:    Mov    ParmNxt,SI
  359.     Lodsb
  360.     Cmp    AL,' '                  ; Multiple member names are separated
  361.     Je    Parm4            ; by blanks. The last one ends in a CR.
  362.     Cmp    AL,CR
  363.     Je    Parm4
  364.     Stosb
  365.     Loop    Parm3
  366.  
  367. Parm4:    Mov    AX,0FF00h        ; Append ASCIIZ and print stopper
  368.     Stosw
  369.     Mov    SI,DI            ; Each member filename may include
  370.     Std                ; a drive and/or path names, need to
  371.     Dec    SI            ; the address of the filename part
  372. Parm5:    Lodsb
  373.     Cmp    AL,':'                  ; Check for drive
  374.     Je    Parm6
  375.     Cmp    AL,'\'                  ; Check for paths
  376.     Je    Parm6
  377.     Cmp    AL,'/'
  378.     Je    Parm6
  379.     Cmp    SI,Offset Filenm-1
  380.     Ja    Parm5
  381.     Dec    SI
  382. Parm6:    Inc    SI            ; Save a pointer to the filename
  383.     Inc    SI
  384. Parm7:    Mov    FilePtr,SI        ; part of the member name
  385.     Cld
  386.     Clc
  387.     Cmp    Byte Ptr FileNm,0    ; Set ZF to indicate whether
  388.     Ret                ; there is a file name
  389.  
  390. GetNext Endp
  391.     Page
  392. ;
  393. ;    Load entire directory into memory
  394.  
  395. LoadDir Proc    Near
  396.  
  397.     Call    ReadMst         ;Get master DIR entry
  398.     Jnc    Load2
  399.     Mov    DX,Offset Msg3        ;Say I/O ERROR
  400.     Jmp    Errmsg
  401.  
  402. Load2:    Call    Verify            ;Validate master entry
  403.     Jnc    Load3
  404.     Mov    DX,Offset Msg6        ;Say INVALID LBR FORMAT
  405.     Jmp    Errmsg
  406.  
  407. Load3:    Call    ReadLib         ;Read remainder of directory
  408.     Jnc    Load4
  409.     Mov    DX,Offset Msg3
  410.     Jmp    ErrMsg
  411.  
  412. Load4:    Call    ChkCRC            ;Validate directory CRC
  413.     Test    Mode,8            ; is it okay?
  414.     Jz    Load5            ; yup
  415.     Mov    DX,Offset CRC_Bad
  416.     Call    PrintS
  417.  
  418. Load5:    Ret
  419.  
  420. ErrMsg: Call    PrintS            ;Display error message
  421.     Mov    DX,Offset LbrName
  422.     Jmp    Error
  423.  
  424. Msg3    Db    CR,LF,'I/O error writing',CR,LF,Stopper
  425. Msg6    Db    CR,LF,'Invalid LBR format: ',Stopper
  426. CRC_Bad Db    CR,LF,'Directory CRC invalid',CR,LF,Stopper
  427. LoadDir Endp
  428.     Page
  429. ;
  430. ;    Search for requested file
  431.  
  432. Search    Proc    Near            ; First member from FilePtr
  433.  
  434.     Call    GetNext         ; Any members specified?
  435.     Jz    Search0         ;  no, extract all members
  436.     Call    Fcbname         ;  yes, change name to FCB format
  437.  
  438. Search0:
  439.     Mov    AX,S_Dir        ; Offset to DIR in memory
  440.     Add    AX,Dir_Len        ;  bump over master entry
  441.     Mov    DirPtr,AX
  442.     Mov    AX,Entries        ; Reset directory entries counter
  443.     Mov    Counter,AX
  444.  
  445. Search1:
  446.     Mov    BX,DirPtr        ;Point to current entry
  447.  
  448.     Cmp    [BX].D_Stat,Deleted    ;Entry deleted?
  449.     Je    Search2         ; yes, skip it
  450.  
  451.     Cmp    [BX].D_Stat,Active    ;Is entry in use?
  452.     Jne    Search2         ; no, skip it
  453.  
  454.     Cmp    Member,' '              ; Want all files?
  455.     Je    Search3         ;  yes, extract it
  456.  
  457.     Lea    DI,[BX].D_File-1    ; Directory file name
  458.     Mov    SI,Offset Member    ; Selected member name
  459.     Mov    CX,11
  460. Search7:Lodsb
  461.     Inc    DI
  462.     Cmp    AL,'?'                  ; Wildcard?
  463.     Je    Search5         ;  yup, consider a match
  464.     Cmp    AL,Byte Ptr [DI]
  465.     Jne    Search2
  466. Search5:Loop    Search7         ; No match
  467.  
  468. Search3:Call    Extract         ; Matched, extract it
  469.  
  470. Search2:Add    DirPtr,Size DirNtry    ; Next directory entry
  471.     Dec    Counter         ; Number of dir entries
  472.     Jnz    Search1         ; not found, try next entry
  473.     Cmp    NewName,0        ; Extracted any files?
  474.     Jne    Search4         ;  yes, normal exit
  475.     Mov    DX,Offset Msg10     ;  no, say file not found
  476.     Jmp    Error
  477.  
  478. Search4:
  479.     Call    GetNext         ; Any more to select?
  480.     Jz    Search9         ;  no, done
  481.     Call    FcbName
  482.     Jmp    Search0         ;  yes, all again
  483.  
  484. Search9:
  485.     Ret
  486. Search    Endp
  487.  
  488.     Page
  489. ;
  490. ;    Extract the requested file
  491.  
  492. Extract Proc    Near            ;BX points to directory entry
  493.  
  494.     Mov    AX,[BX].D_Len        ;Number of sectors
  495.     Mov    NumSecs,AX
  496.     Mov    AX,[BX].D_Ptr        ;Get offset to data
  497.     Mul    SecSize
  498.     Mov    CX,DX            ; in CX:DX for LSEEK
  499.     Mov    DX,AX
  500.  
  501.     Call    Lseek            ;Reposition input
  502.  
  503.     Call    FixName         ;Format FCB file name
  504.  
  505.     Call    Create            ;Create output file
  506.  
  507.     Mov    DX,Offset MsgE        ;Say extracting
  508.     Call    PrintS
  509.  
  510. Ext3:    Mov    AX,NumSecs        ;Total data sectors
  511.     Cmp    AX,BufSec        ;Will fit in one buffer?
  512.     Jbe    Ext4            ; yes, just one r/w
  513.     Mov    AX,BufSec        ; no, set max size to read
  514.  
  515. Ext4:    Mul    SecSize         ;Sectors*size = bytes to read
  516.     Mov    BufSize,AX
  517.  
  518.     Call    Read            ;Read a block
  519.  
  520.     Mov    AX,BufSec
  521.     Cmp    NumSecs,AX        ;Last block?
  522.     Ja    Ext6            ; no, full block
  523.     Test    Mode,4            ;LU86 format?
  524.     Jz    Ext6            ; no, use entire size
  525.     Mov    DL,Byte Ptr [BX].D_Pad    ; yes, less pad
  526.     Sub    DH,DH
  527.     Sub    BufSize,DX
  528.  
  529. Ext6:    Call    Write            ;Write a block
  530.  
  531.     Mov    AX,BufSec
  532.     Sub    NumSecs,AX        ;Get number of sectors left
  533.     Js    Ext7            ; no more, return
  534.     Jnz    Ext3            ; more, read next block
  535.  
  536. Ext7:    Call    GetDate         ;Original member date
  537.  
  538.     Call    SetDate         ; as new file date
  539.  
  540.     Call    CloseO            ;Close output
  541.  
  542.     Ret
  543. Extract Endp
  544.  
  545.     Subttl    ---  Subroutines
  546.     Page
  547. ;
  548. ;    Read a Sector Subroutine
  549.  
  550. Read    Proc    Near            ;Read a sector
  551.     Push    BX
  552.     Mov    BX,IHandle        ;File handle
  553.     Mov    CX,BufSize        ;Number of bytes
  554.     Mov    DX,S_Buf
  555.     Push    DS
  556.     Mov    DS,DX
  557.     Sub    DX,DX
  558.     Mov    AH,3Fh            ;Read from file
  559.     Int    21h
  560.     Pop    DS
  561.     Jc    Err2
  562.     Or    AX,AX            ;Any data read?
  563.     Jz    Err2            ; no, send message
  564.     Pop    BX
  565.     Ret
  566. Err2:    Mov    DX,Offset Msg2        ;Say I/O error reading
  567.     Jmp    Error
  568. Read    Endp
  569.  
  570. ;
  571. ;     Write a Sector Subroutine
  572.  
  573. Write    Proc    Near            ;Write a sector
  574.     Push    BX
  575.     Mov    BX,OHandle        ;File handle
  576.     Mov    CX,BufSize        ;Bytes to write
  577.     Push    DS
  578.     Mov    DX,S_Buf
  579.     Mov    DS,DX
  580.     Sub    DX,DX
  581.     Mov    AH,40h            ;Write to a file
  582.     Int    21h
  583.     Pop    DS
  584.     Jc    Err3
  585.     Pop    BX
  586.     Ret
  587. Err3:    Mov    DX,Offset Msg3        ;Say I/O error writing
  588.     Jmp    Error
  589. Write    Endp
  590.  
  591. ;
  592. ;    Create File Subroutine
  593.  
  594. Create    Proc    Near            ;Create output file
  595.     Sub    CX,CX            ;Normal attribute
  596.     Mov    DX,Offset NewName    ;New file name
  597.     Mov    AH,3Ch            ;Create a file
  598.     Int    21h
  599.     Jc    Err8
  600.     Mov    OHandle,AX        ;Save file handle
  601.     Ret                ; and return
  602. Err8:    Mov    DX,Offset Msg8        ;Say CREATE failed
  603.     Call    PrintS
  604.     Mov    DX,Offset NewName
  605.     Jmp    Error
  606. Create    Endp
  607.  
  608. ;
  609. ;    Position File Subroutine
  610.  
  611. Lseek    Proc    Near
  612.     Push    BX
  613.     Mov    AX,4200h        ;Reposition to member data
  614.     Mov    BX,IHandle
  615.     Int    21h            ; pointed to by CX:DX
  616.     Jc    Err7
  617.     Pop    BX
  618.     Ret
  619. Err7:    Mov    DX,Offset Msg7        ;Say LSEEK FAILED
  620.     Jmp    Error
  621. Lseek    Endp
  622.  
  623. ;
  624. ;    Close file handle
  625.  
  626. CloseLbr Proc    Near            ;Close input (library)
  627.     Push    BX
  628.     Mov    BX,Ihandle
  629.     Mov    AH,3Eh
  630.     Int    21h
  631.     Pop    BX
  632.     Ret
  633. CloseLbr Endp
  634.  
  635. CloseO    Proc    Near            ;Close output
  636.     Push    BX
  637.     Mov    BX,OHandle
  638.     Mov    AH,3Eh
  639.     Int    21h
  640.     Pop    BX
  641.     Ret
  642. CloseO    Endp
  643.  
  644.     Page
  645. ;
  646. ;    Get original member/file date/time
  647.  
  648. GetDate Proc    Near            ;Determine original date
  649.     Push    BX
  650.     Test    Mode,5            ;Date in directory?
  651.     Jz    GetDat1         ; no, use LBR file date
  652.     Test    Mode,1            ;ASCII stamps?
  653.     Jnz    GetDat2         ; no, maybe LU86 format
  654.  
  655.     Mov    CX,Word Ptr [BX].D_Utime
  656.     Mov    DX,Word Ptr [BX].D_Udate
  657.     Or    CX,CX            ;Any update time?
  658.     Jnz    GetDat3
  659.     Mov    CX,Word Ptr [BX].D_Ctime
  660.     Mov    DX,Word Ptr [BX].D_Cdate
  661. GetDat3:Call    CPM_Date
  662.     Pop    BX
  663.     Ret
  664.  
  665. ;    Convert ASCII date/time to DOS date format
  666.  
  667. GetDat2:Sub    Byte Ptr [BX].D_Ctime,'8' ;Adjust year
  668.     Mov    AX,Word Ptr [BX].D_Ctime
  669.     Call    Cnvrt
  670.     Mov    DH,AL
  671.     Shl    DH,1
  672.  
  673.     Mov    AX,Word Ptr [BX].D_CRC    ; Month
  674.     Call    Cnvrt
  675.     Mov    DL,AL
  676.     Mov    CL,5
  677.     Shl    DL,CL
  678.     Mov    CL,3
  679.     Shr    AL,CL
  680.     Or    DH,AL
  681.  
  682.     Mov    AX,Word Ptr [BX].D_CRC+3    ; Day
  683.     Call    Cnvrt
  684.     Or    DL,AL
  685.     Push    DX
  686.  
  687.     Mov    AX,Word Ptr [BX].D_Utime    ; Hour
  688.     Call    Cnvrt
  689.     Mov    CL,3
  690.     Shl    AL,CL
  691.     Mov    DH,AL
  692.  
  693.     Mov    AX,Word Ptr [BX].D_Utime+3    ; Minute
  694.     Call    Cnvrt
  695.     Mov    DL,AL
  696.     Mov    CL,5
  697.     Shl    DL,CL
  698.     Mov    CL,3
  699.     Shr    AL,CL
  700.     Or    DH,AL
  701.  
  702.     Mov    AX,Word Ptr [BX].D_Utime+6    ; Second
  703.     Call    Cnvrt
  704.     Or    DL,AL
  705.     Mov    CX,DX
  706.     Pop    DX
  707.     Pop    BX
  708.     Ret
  709.  
  710. GetDat1:
  711.     Mov    BX,IHandle
  712.     Mov    AX,5700h        ;Get input file date/time
  713.     Int    21h            ; in DX:CX
  714.     Pop    BX
  715.     Ret
  716. GetDate Endp
  717.     Page
  718. ;
  719. ;    Set output file date/time
  720.  
  721. SetDate Proc    Near            ;Set output date/time
  722.     Push    BX            ; from DX:CX
  723.     Mov    BX,OHandle
  724.     Mov    AX,5701h        ;Change output file date
  725.     Int    21h
  726.     Pop    BX
  727.     Ret
  728. SetDate Endp
  729.  
  730.  
  731. Cnvrt    Proc    Near            ;Convert ASCII to binary
  732.     Xchg    AH,AL
  733.     And    AH,0Fh
  734.     And    AL,0Fh
  735.     Aad
  736.     Ret
  737. Cnvrt    Endp
  738.     Page
  739. ;
  740. ;    Convert CPM date
  741.  
  742. CPM_Date Proc    Near            ;Convert CP/M date
  743.     Push    AX            ; to DOS format in DX
  744.     Push    BX
  745.     Push    CX
  746.     Push    SI
  747.  
  748.     Mov    AX,DX            ;Days since 12/31/77
  749.     Sub    CX,CX            ;Years since
  750.     Mov    DX,OneYear
  751. CD1:    Sub    AX,DX            ; for 1978
  752.     Jle    CD2
  753.     Inc    CL
  754.     Sub    AX,DX            ; for 1979
  755.     Jle    CD2
  756.     Inc    CL
  757.     Inc    DX
  758.     Sub    AX,DX            ; for next leap year
  759.     Jle    CD2
  760.     Dec    DX
  761.     Inc    CL
  762.     Sub    AX,DX            ; and year after
  763.     Jle    CD2
  764.     Inc    CL
  765.     Jmp    Short CD1
  766.  
  767. CD2:    Add    AX,DX
  768.     Mov    DX,AX            ;Save days left over
  769.  
  770. CD3:    Mov    AX,CX            ;Adjust year
  771.     Add    AL,78            ; plus base year
  772.  
  773.     Mov    Days+1,28        ;Days in Feb
  774.     Test    AL,3            ;Is it leap year?
  775.     Jnz    CD4            ; no, has 28
  776.     Mov    Days+1,29        ; yes, has one more
  777.  
  778. CD4:    Mov    Year,AX         ;Save year
  779.  
  780.     Mov    SI,Offset Days        ; point to days/month
  781.     Sub    AX,AX
  782.     Sub    BX,BX
  783.     Mov    BL,1            ; month number
  784. CD5:    Lodsb
  785.     Sub    DX,AX            ; days into month
  786.     Jle    CD6            ; within month
  787.     Inc    BL
  788.     Jmp    Short CD5
  789.  
  790. CD6:    Add    DX,AX
  791.     Mov    AX,Year         ;Combine into DOS format
  792.     Sub    AX,80
  793.     Mov    CL,9
  794.     Shl    AX,CL
  795.     Mov    CL,5
  796.     Shl    BX,CL
  797.     Add    AX,BX            ; year and month
  798.     Add    DX,AX            ; and day
  799.  
  800.     Pop    SI
  801.     Pop    CX
  802.     Pop    BX
  803.     Pop    AX
  804.     Ret
  805.  
  806. Days    Db    31,28,31,30,31,30,31,31,30,31,30,31
  807. OneYear Equ    365            ;Days in normal year
  808. CPM_Date Endp
  809.     Page
  810. ;
  811. ;    Format new file name
  812.  
  813. FixName Proc    Near
  814.     Mov    DI,Offset NewName    ;Clear target name
  815.     Mov    SI,Offset Blanks
  816.     Mov    CX,12
  817.     Rep    Movsb
  818.     Lea    SI,[BX].D_File        ;Must convert FCB name format
  819.     Mov    DI,Offset NewName    ; to ASCIIZ format for Int 21
  820.     Mov    CX,8
  821. Fix5:    Lodsb                ;Copy name part
  822.     Cmp    AL,' '
  823.     Je    Fix7
  824.     Stosb
  825.     Loop    Fix5
  826.  
  827. Fix7:    Cmp    Byte Ptr [BX].D_Ext,' '
  828.     Je    Fix9            ;If not extension
  829.     Mov    AL,'.'                  ;Otherwise, dlimit the parts
  830.     Stosb
  831.     Mov    CX,3
  832.     Lea    SI,[BX].D_Ext        ;Extension part in dir name
  833. Fix8:    Lodsb
  834.     Cmp    AL,' '                  ;Copy non-blank chars
  835.     Je    Fix9
  836.     Stosb
  837.     Loop    Fix8
  838. Fix9:    Mov    AL,0            ;Final ASCIIZ stopper
  839.     Stosb
  840.     Ret
  841. FixName Endp
  842.  
  843. ;
  844. ;    Change filename to FCB format
  845.  
  846. FcbName Proc    Near
  847.     Mov    SI,Offset Blanks    ; Clear target MEMBER field
  848.     Mov    DI,Offset Member
  849.     Mov    CX,11
  850.     Rep    Movsb
  851.  
  852.     Mov    SI,Offset FileNm    ; Reformat to FCB style
  853.     Mov    DI,Offset Member
  854.     Mov    CX,9
  855. Fcbnm1: Lodsb                ; Next filename char
  856.     Cmp    AL,'a'                  ; Insure in upper case
  857.     Jb    FcbNm2
  858.     Cmp    AL,'z'
  859.     Ja    FcbNm2
  860.     Sub    AL,32            ; Make it upper case
  861. FcbNm2: Cmp    AL,'.'
  862.     Je    Fcbnm3
  863.     Cmp    AL,'*'            ; Wildcard?
  864.     Je    FcbNm8            ;  yes, expand it
  865.     Cmp    AL,0            ; End of ASCIIZ name?
  866.     Je    FcbNm7
  867.     Stosb                ; Copy name part
  868.     Loop    Fcbnm1
  869. FcbNm7:    Jmp    Short Fcbnm9        ; If no extension
  870.  
  871. FcbNm8:    Mov    AL,'?'            ; Expand * wildcard
  872.     Rep    Stosb
  873.     Lodsb
  874.     Cmp    AL,'.'            ; Is there one?
  875.     Jne    FcbNm9            ;  no, have it all
  876.  
  877. Fcbnm3: Mov    DI,Offset Ext        ; Copy extension
  878.     Mov    CX,3
  879. Fcbnm4: Lodsb                ; Copy extension
  880.     Cmp    AL,'a'                  ; Insure in upper case
  881.     Jb    FcbNm5
  882.     Cmp    AL,'z'
  883.     Ja    FcbNm5
  884.     Sub    AL,32            ; Make it upper case
  885. FcbNm5: Cmp    AL,'*'            ; Have wildcard?
  886.     Je    FcbNm6            ;  yes, expand it
  887.     Cmp    AL,0            ; End of ASCIIZ name?
  888.     Je    FcbNm9
  889.     Stosb
  890.     Loop    Fcbnm4
  891.     Jmp    Short FcbNm9
  892.  
  893. FcbNm6:    Mov    AL,'?'            ; Expand ext wildcards
  894.     Rep    Stosb
  895. Fcbnm9: Ret
  896. FcbName Endp
  897.     Page
  898. ;
  899. ;    Print String
  900.  
  901. PrintS    Proc    Near            ;Print string like Int 21h (9)
  902.     Push    BX            ;DX points to string
  903.     Push    BP
  904.     Push    SI
  905.     Mov    SI,DX
  906. PS1:    Lodsb
  907.     Cmp    AL,0            ;Skip zeros
  908.     Je    PS1
  909.     Cmp    AL,255            ;String ends in a hex FF
  910.     Je    PS9            ; so can print $
  911.     Mov    AH,2            ;Use std output device
  912.     Mov    DL,AL
  913.     Int    21h
  914.     Jmp    Short PS1
  915.  
  916. PS9:    Pop    SI
  917.     Pop    BP
  918.     Pop    BX
  919.     Ret
  920. PrintS    Endp
  921.     Page
  922. ;
  923. ;    Build directory in memory
  924.  
  925. ReadMst Proc    Near
  926.     Mov    BX,Ihandle        ;Read master directory entry
  927.     Mov    CX,32            ; first 32-byte record
  928.     Mov    DX,S_Dir
  929.     Mov    AH,3Fh
  930.     Int    21h
  931.     Jc    Error3
  932.     Cmp    AX,CX            ;Got all of it?
  933.     Jne    Error3
  934.     Ret
  935.  
  936. ReadLib:                ;Read remaining entries
  937.     Mov    BX,S_Dir
  938.     Mov    AX,Word Ptr [BX].D_Len    ;Sectors for direc.
  939.     Sub    DX,DX
  940.  
  941.     Shl    AX,1            ;Calc number of entries
  942.     Shl    AX,1            ; four per sector
  943.     Dec    AX            ; less master entry
  944.     Mov    Entries,AX
  945.  
  946.     Mov    CL,5            ;Calc size remaining
  947.     Shl    AX,CL
  948.     Mov    CX,AX
  949.     Mov    LenDir,CX        ;Save length
  950.     Add    LenDir,Dir_Len        ; of entire directory
  951.  
  952.     Mov    BX,IHandle        ;Read rest of directory
  953.     Mov    DX,S_Dir
  954.     Add    DX,Dir_Len
  955.     Mov    AH,3Fh
  956.     Int    21h
  957.     Jc    Error3
  958.     Cmp    AX,CX            ;Got all of it?
  959.     Jne    Error3
  960.     Ret
  961.  
  962. Error3: Clc
  963.     Ret
  964. ReadMst Endp
  965.     Page
  966. ;
  967. ;    Validate master directory entry
  968.  
  969. Verify    Proc    Near
  970.     Mov    BX,S_Dir
  971.     Sub    AX,AX
  972.     Cmp    Byte Ptr [BX].D_Stat,AL ;Active first entry?
  973.     Jne    NotLBR
  974.     Cmp    Word Ptr [BX].D_Ptr,AX    ;Valid index pointer?
  975.     Jne    NotLBR
  976.  
  977.     Mov    Mode,AL         ;Init LBR type and
  978.  
  979.     Mov    CX,11            ;Check name of blanks
  980.     Lea    SI,Word Ptr [BX].D_File
  981.     Mov    DI,Offset Blanks
  982.     Repe    Cmpsb
  983.     Jne    Ver4
  984.  
  985.     Cmp    Word Ptr [BX].D_CRC,CX    ;Any CRC?
  986.     Je    Ver2
  987.     Or    Mode,2            ; yes...
  988. Ver2:    Cmp    Word Ptr [BX].D_Ctime,CX
  989.     Je    Ver9            ;Any LU86 stamps?
  990.     Or    Mode,4            ; yes...
  991.     Jmp    Short Ver9
  992.  
  993. Ver4:    Mov    CX,11            ;May be new format
  994.     Lea    SI,Byte Ptr [BX].D_File
  995.     Mov    DI,Offset DirKey
  996.     Repe    Cmpsb
  997.     Jne    NotLBR
  998.     Mov    Mode,1            ;Indicate ***DIR format
  999.  
  1000. Ver9:    Clc                ;Return CD=0
  1001.     Ret
  1002.  
  1003. NotLBR: Stc                ;or CF=1 if not LBR
  1004.     Ret
  1005. Verify    Endp
  1006.     Page
  1007. ;
  1008. ;    Check CRC for directory
  1009.  
  1010. ChkCRC    Proc    Near
  1011.     And    Mode,0FFh-8        ;Clear error indication
  1012.     Test    Mode,2            ;LU86 CRC included?
  1013.     Jz    ChkCRC9         ; no, skip it
  1014.     Mov    SI,S_Dir        ;Calculate directory CRC
  1015.     Mov    BX,SI
  1016.     Mov    CX,LenDir
  1017.     Mov    DX,Word Ptr [BX].D_CRC    ;Save original CRC
  1018.     Or    DX,DX            ; any used?
  1019.     Jz    ChkCRC9         ; nope, skip check
  1020.     Mov    Word Ptr [BX].D_CRC,0
  1021.  
  1022.     Call    GetCRC            ;CRC for directory block
  1023.     Call    UpdCRC            ; and for end-of-block
  1024.  
  1025.     Mov    Word Ptr [BX].D_CRC,DX
  1026.     Cmp    AX,DX            ;CRC correct?
  1027.     Je    ChkCRC9
  1028.     Or    Mode,8            ; no, indicate error
  1029. ChkCRC9:Ret
  1030. ChkCRC    Endp
  1031.  
  1032.  
  1033. ;
  1034. ;    Calculate CRC for a block from CCIT polynomial
  1035. ;
  1036. ;    CRC = x^16 + x^12 + x^5 + 1
  1037.  
  1038. GetCRC    Proc    Near            ;SI points to data
  1039.     Push    BX            ;CX contains length
  1040.     Push    DX
  1041.  
  1042.     Sub    BX,BX            ;Zero resultant CRC
  1043. GetCRCs:Mov    DX,CX
  1044.  
  1045. GetCRC0:Mov    CX,8            ; bits in a byte
  1046.     Lodsb                ; get next byte
  1047. GetCRC1:Rol    AL,1            ;MSB -> carry
  1048.     Rcl    BX,1            ;    -> CRC LSB
  1049.     Jnc    GetCRC2
  1050.     Xor    BX,1021h
  1051. GetCRC2:Loop    GetCRC1
  1052.     Dec    DX
  1053.     Jnz    GetCRC0
  1054.  
  1055.     Mov    AX,BX            ;Return CRC in AX
  1056.     Pop    DX
  1057.     Pop    BX
  1058.     Ret
  1059. GetCRC    Endp
  1060.  
  1061. ;    Update CRC at end of block
  1062.  
  1063. UpdCRC    Proc    Near            ;CRC in AX
  1064.     Push    BX
  1065.     Push    DX
  1066.     Mov    BX,AX            ;Current CRC
  1067.     Mov    CX,2            ;Last two bytes
  1068.     Mov    SI,Offset Zero        ; of zero
  1069.     Jmp    Short GetCRCs
  1070. Zero    Dw    0
  1071. UpdCRC    Endp
  1072.     Page
  1073.  
  1074. Lue    Endp
  1075.  
  1076. Storage Equ    This Byte
  1077. Stackx    Equ    Storage+256        ; Local stack end
  1078. ParmFld Equ    Stackx+4        ; Command line operands
  1079. MyDta    Equ    ParmFld+128        ; Disk data transfer area
  1080. LbrName Equ    MyDta+48
  1081. WorkEnd Equ    LbrName+77
  1082.  
  1083. Paras_C Equ    (WorkEnd-Cseg+2048)/16          ; Paragraphs in program and stack
  1084.  
  1085. Cseg    Ends
  1086.  
  1087.     End    Lue
  1088.