home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / pcmagazi / 1989 / 09 / split.asm < prev    next >
Assembly Source File  |  1989-01-29  |  32KB  |  814 lines

  1.         PAGE    78,132
  2.         TITLE   "SPLIT - Break file for multiple diskettes"
  3.  
  4. CSEG        SEGMENT PARA PUBLIC 'CODE'
  5.         ASSUME  CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  6.  
  7. ; ---------------------------------------------------------------------------
  8. ;   DTA structure for DOS "find matching" call
  9. ; ---------------------------------------------------------------------------
  10.         ORG     80H             ; dta offset
  11. DTA        DB        21 dup (0)            ; start of find file area
  12. DTA_ATTR    DB        0                ; file attribute
  13. DTA_TIME    DW        0                ; file time
  14. DTA_DATE    DW        0                ; file date
  15. DTA_LSIZ    DW        0                ; file lsw of size
  16. DTA_HSIZ    DW        0                ; file msw of size
  17. DTA_NAME    DB        12 DUP (0)            ; file name of file
  18. DTA_LEN     EQU     $-DTA            ; length of dta find entry
  19.  
  20.         ORG     100H            ; start of program area
  21. START:        JMP     MAIN            ; go to the code
  22.  
  23. ; ---------------------------------------------------------------------------
  24. ;   Common initialized work areas
  25. ; ---------------------------------------------------------------------------
  26. ARG        DW        0                ; addr of first argument
  27. FLOPDRV     DB        0,":\"                  ; output drive letter
  28. DESTFILE    DB        "            ",0        ; output file name
  29. DESTEXT     DW        0                ; pointer to extension
  30. DESTEXTC    DB        "0"                     ; 1st character of extension
  31. DESTNBR     DW        1                ; file extension counter
  32. RSTFLAG     DB        0                ; split/restore flag
  33. CURRDIR     DB        ".",0                   ; argument for current directory
  34. IHANDLE     DW        0                ; input file handle
  35. OHANDLE     DW        0                ; output file handle
  36.  
  37. ; ---------------------------------------------------------------------------
  38. ;   Messages to user
  39. ; ---------------------------------------------------------------------------
  40. HEADER_MSG  DB        "SPLIT   1.0 - (c) 1989 Ziff Communications Co.",0DH,0AH
  41.         DB        "PC Magazine ",254," Bob Flanders & Michael Holmes",0AH
  42.         DB        0DH,0AH
  43. DOLLAR        DB        "$"
  44. FILENF        DB        "File not found$"
  45. NOCREATE    DB        "Error opening output$"
  46. NOROOM        DB        "Not enough room, try another$"
  47. WRONGDISK   DB        "Wrong restore disk, insert number "
  48. DISKNO        DB        "XX$"
  49. DRVNR        DB        "Must be removable media$"
  50. RDERROR     DB        "Error reading input$"
  51. WRTERROR    DB        "Error writing output$"
  52. FILEFND     DB        "File exists$"
  53. NEXTDISK    DB        "Insert #"
  54. DISKNO2     DB        "XX$"
  55. HITANYKEY   DB        ", Press any key ..",07H,0DH,0AH,"$"
  56. FORMAT        DB        0DH,0AH,"format:",09H,"$"
  57. RSFORM        DB        "UNSPLIT  d:  d:[\path]",0DH,0AH,"$"
  58. RESTORING   DB        "Restoring: "
  59. RESTFILE    DB        12 DUP (" "),0DH,0AH,"$"
  60.  
  61. ; ---------------------------------------------------------------------------
  62. ;   File ID Header
  63. ; ---------------------------------------------------------------------------
  64. RSTLAST     DB        0                ; last file flag
  65. RSTATTR     DB        0                ; file attributes
  66. RSTTIME     DW        0                ; file time
  67. RSTDATE     DW        0                ; file date
  68. RSTLSIZ     DW        0                ; file lsw of size
  69. RSTHSIZ     DW        0                ; file msw of size
  70. RSTNAME     DB        12 DUP (0)            ; file name of file
  71. RST_FFLEN   EQU     $-RSTATTR            ; length to move from ff area
  72. RSTSDTE     DD        0                ; date ..
  73. RSTSTME     DD        0                ; ..and time of save
  74. RST_LEN     EQU     $-RSTLAST            ; length of our file header
  75.  
  76. ; ---------------------------------------------------------------------------
  77. ;   MAIN - Mainline of program
  78. ; ---------------------------------------------------------------------------
  79. MAIN        PROC                ; start of program
  80.         CMP     RSTFLAG, 0            ; q. restoring?
  81.         JNZ     RESTORE            ; a. goto restore section
  82.  
  83.         CALL    INIT            ; initialize program
  84.         CALL    PARMS            ; check parameters
  85.         CALL    OPEN            ; open the input file
  86.         CALL    SAVE            ; copy/split the file to output
  87.         JMP     SHORT MAIN10        ; return to dos
  88.  
  89. RESTORE:    CALL    INIT            ; perform restore setup
  90.         CALL    PARMS            ; check parameters
  91.         CALL    ROPEN            ; open the output file
  92.         CALL    RFILE            ; restore the file
  93.  
  94. MAIN10:     MOV     DX, OFFSET DOLLAR        ; dx -> null message
  95.         CALL    DIE             ; .. say goodnight
  96. MAIN        ENDP
  97.  
  98. ; ---------------------------------------------------------------------------
  99. ;   INIT - Handle initialization
  100. ; ---------------------------------------------------------------------------
  101. INIT        PROC
  102.         CLD                 ; assure ascending
  103.         MOV     DX, OFFSET HEADER_MSG   ; dx -> header message
  104.         MOV     AH, 9            ; ah = print ascii$ message
  105.         INT     21H             ; .. ask DOS to do it
  106.         RET                 ; return to caller
  107. INIT        ENDP
  108.  
  109. ; ---------------------------------------------------------------------------
  110. ;   ROPEN - open the file to restore
  111. ; ---------------------------------------------------------------------------
  112. ROPEN        PROC
  113.         MOV     DI, OFFSET ROPENFILE    ; di -> work area
  114.         MOV     SI, ARG            ; si -> where to restore
  115.  
  116. ROPEN10:    MOVSB                ; move a character
  117.  
  118.         CMP     BYTE PTR [SI], 0        ; q. end of parm?
  119.         JNE     ROPEN10            ; a. yes .. continue
  120.  
  121.         CMP     BYTE PTR [DI-1], "\"    ; q. last byte a back-slash?
  122.         JE        ROPEN20            ; a. yes .. continue
  123.  
  124.         CMP     BYTE PTR [DI-1],":"     ; q. last byte a colon (drive)?
  125.         JE        ROPEN20            ; a. yes .. continue
  126.  
  127.         MOV     AL, "\"                 ; end as directory
  128.         STOSB
  129.  
  130. ROPEN20:    MOV     SI, OFFSET RSTNAME        ; si -> name of original file
  131.         MOV     BX, OFFSET RESTFILE     ; bx -> restore filename
  132.  
  133. ROPEN30:    LODSB                ; al = char of filename
  134.         STOSB                ; .. save it
  135.  
  136.         OR        AL, AL            ; q. end of file name?
  137.         JZ        ROPEN40            ; a. yes .. continue
  138.  
  139.         MOV     [BX], AL            ; save in message
  140.         INC     BX                ; bx -> next char
  141.         JMP     ROPEN30            ; .. continue
  142.  
  143. ROPEN40:    MOV     AH, 4EH            ; ah = find first
  144.         MOV     DX, OFFSET ROPENFILE    ; dx -> file to find
  145.         MOV     CX, 0FFH            ; .. any attribute
  146.         INT     21H             ; q. file found?
  147.         JC        ROPEN45            ; a. no .. continue
  148.  
  149.         MOV     DX, OFFSET FILEFND        ; dx -> file already exists
  150.         CALL    DIE             ; .. push up some daisies
  151.  
  152. ROPEN45:    MOV     AH, 3CH            ; ah = create function code
  153.         MOV     CL, RSTATTR         ; cx = original attributes
  154.         XOR     CH,CH            ; .. upper byte off
  155.         INT     21H             ; issue DOS call
  156.         JNC     ROPEN50            ; if no problems, continue
  157.  
  158.         MOV     DX, OFFSET NOCREATE     ; dx -> create error message
  159.         CALL    DIE             ; .. go deep six
  160.  
  161. ROPEN50:    MOV     OHANDLE, AX         ; save the file handle
  162.  
  163.         MOV     DX, OFFSET RESTORING    ; dx -> restore message
  164.         MOV     AH, 09H            ; ah = print ascii$
  165.         INT     21H             ; .. tell the user
  166.  
  167.         RET                 ; return to caller
  168. ROPEN        ENDP
  169.  
  170. ; ---------------------------------------------------------------------------
  171. ;   RFILE - restore file
  172. ; ---------------------------------------------------------------------------
  173. RFILE        PROC
  174.         CALL    NEXTFILE            ; create a file name
  175.  
  176. RFILE10:    MOV     DX, OFFSET FLOPDRV        ; dx -> file name
  177.         MOV     AX, 3D00H            ; al = open for read
  178.         INT     21H             ; .. ask DOS to do it.
  179.         JNC     RFILE20            ; ok .. continue
  180.  
  181. RFILE15:    MOV     DX, OFFSET WRONGDISK    ; dx -> wrong disk message
  182.         CALL    HITKEY            ; .. display and wait
  183.         JMP     RFILE10            ; .. and try again
  184.  
  185. RFILE20:    MOV     IHANDLE, AX         ; save file handle
  186.  
  187.         MOV     BX, AX            ; bx = handle
  188.         MOV     AH, 03FH            ; ah = read file
  189.         MOV     CX, RST_LEN         ; cx = len to read
  190.         MOV     DX, OFFSET BUFFER        ; dx -> buffer to read
  191.         INT     21H             ; read a buffer
  192.         JC        RFILE35            ; tell 'em we cant read it
  193.  
  194.         MOV     SI, DX            ; si -> buffer
  195.         MOV     DI, OFFSET RSTLAST        ; di -> our header
  196.         MOVSB                ; move last flag, setup for compare
  197.         MOV     CX, RST_LEN-1        ; cx = bytes to check
  198.        REPE CMPSB                ; q. headers the same?
  199.         JE        RFILE30            ; a. yes .. continue
  200.  
  201.         MOV     AH, 3EH            ; ah = close file
  202.         INT     21H             ; close output file
  203.         MOV     IHANDLE, 0            ; .. show file not open
  204.         JMP     RFILE15            ; tell 'em
  205.  
  206. RFILE30:    MOV     AH, 03FH            ; ah = read file
  207.         MOV     BX, IHANDLE         ; bx = handle of file to read
  208.         MOV     CX, BUFLEN            ; cx = amount to read
  209.         MOV     DX, OFFSET BUFFER        ; dx -> buffer
  210.         INT     21H             ; read, please
  211.         JNC     RFILE40            ; if no error .. continue
  212.  
  213. RFILE35:    MOV     DX, OFFSET RDERROR        ; dx -> read error message
  214.         CALL    DIE             ; ..and die gracefully
  215.  
  216. RFILE40:    MOV     CX, AX            ; cx = bytes to write
  217.         JCXZ    RFILE80            ; if finished .. exit loop
  218.  
  219.         MOV     AH, 40H            ; ax = write
  220.         MOV     BX, OHANDLE         ; bx = output file handle
  221.         INT     21H             ; write a buffer
  222.         JC        RFILE50            ; error .. die
  223.  
  224.         CMP     AX, CX            ; q. able to write it?
  225.         JE        RFILE30            ; a. no .. tell 'em
  226.  
  227.         MOV     DI, OFFSET NOROOM        ; di -> wontfit msg
  228.         JMP     SHORT RFILE60        ; ..and exit gracefully
  229.  
  230. RFILE50:    MOV     DI, OFFSET WRTERROR     ; di -> write error message
  231.  
  232. RFILE60:    MOV     AH, 41H            ; ah = delete function
  233.         MOV     DX, OFFSET ROPENFILE    ; dx -> filename
  234.         INT     21H             ; issue DOS call
  235.  
  236.         MOV     DX, DI            ; dx -> error message to give
  237.         CALL    DIE             ; ..make my day, punk!
  238.  
  239. RFILE80:    MOV     AH, 3EH            ; ah = close file
  240.         INT     21H             ; close input file
  241.         MOV     IHANDLE, 0            ; .. clear the input handle
  242.  
  243.         CMP     RSTLAST, 0            ; q. end of file
  244.         JNE     RFILE90            ; a. no .. continue
  245.  
  246.         MOV     DX, OFFSET NEXTDISK     ; dx -> next disk message
  247.         CALL    HITKEY            ; display message and wait
  248.         JMP     RFILE            ; .. get next file
  249.  
  250. RFILE90:    MOV     DX, RSTDATE         ; dx = original file date
  251.         MOV     CX, RSTTIME         ; cx = original file time
  252.         MOV     BX, OHANDLE         ; bx = output file handle
  253.         MOV     AX, 5701H            ; ax = set file date & time
  254.         INT     21H             ; .. Please, Mr. DOS?
  255.  
  256.         RET                 ; .. return to caller
  257. RFILE        ENDP
  258.  
  259. ; ---------------------------------------------------------------------------
  260. ;   NEXTFILE - Build next filename
  261. ; ---------------------------------------------------------------------------
  262. NEXTFILE    PROC
  263.         MOV     AX, DESTNBR         ; ax = current count
  264.         PUSH    AX                ; .. save the value
  265.  
  266.         MOV     BL, 10            ; bl = divisor
  267.         DIV     BL                ; ax = almost ascii nbr
  268.         OR        AX, 3030H            ; ax = ascii values
  269.  
  270.         MOV     BX, DESTEXT         ; bx -> 2nd char of extension
  271.         MOV     [BX], AX            ; store rest of extension
  272.         MOV     WORD PTR DISKNO, AX     ; .. and in message
  273.  
  274.         POP     AX                ; ax = current count
  275.         INC     AX                ; ax = next count
  276.         MOV     DESTNBR, AX         ; .. save new count
  277.  
  278.         MOV     BL, 10            ; bl = divisor
  279.         DIV     BL                ; ax = almost ascii nbr
  280.         OR        AX, 3030H            ; ax = ascii values
  281.  
  282.         MOV     WORD PTR DISKNO2, AX    ; ..
  283.  
  284.         RET                 ; ..and return to caller
  285. NEXTFILE    ENDP
  286.  
  287. ; ---------------------------------------------------------------------------
  288. ;   HITKEY - Allow user to change diskettes; dx -> first message
  289. ; ---------------------------------------------------------------------------
  290. HITKEY        PROC
  291.         MOV     AH, 9H            ; ah = print string
  292.         INT     21H             ; .. call dos to print message
  293.  
  294.         MOV     DX, OFFSET HITANYKEY    ; dx -> prompt
  295.         INT     21H             ; issue prompt message
  296.  
  297.         MOV     AX, 0C08H            ; ax = clear buffer, wait for key
  298.         INT     21H             ; issue DOS call
  299.  
  300.         OR        AL, AL            ; q. function key hit?
  301.         JNZ     HITKEY90            ; a. no .. exit
  302.  
  303.         MOV     AH, 08H            ; ah = wait for key
  304.         INT     21H             ; issue DOS call
  305.  
  306. HITKEY90:   RET
  307. HITKEY        ENDP
  308.  
  309. ; ---------------------------------------------------------------------------
  310. ;   PARMS - Parses the command line
  311. ; ---------------------------------------------------------------------------
  312. PARMS        PROC
  313.         CALL    UPCASE            ; upper case the parm area
  314.         MOV     SI, 81H            ; si -> parms area
  315.  
  316. PARMS10:    LODSB                ; get parameter character
  317.  
  318.         CMP     AL, 0DH            ; q. end of line?
  319.         JE        PARMS50            ; a. yes .. exit
  320.         CMP     AL, " "                 ; q. blank?
  321.         JNA     PARMS10            ; a. yes .. skip
  322.         CALL    ARGCHK            ; set the argument
  323.         JC        PARMSERR            ; .. die on an error
  324.  
  325. PARMS30:    LODSB                ; get next character
  326.         CMP     AL, 0DH            ; q. end of line?
  327.         JE        PARMS50            ; a. yes .. process
  328.         CMP     AL, " "                 ; q. end of PARMS?
  329.         JA        PARMS30            ; a. no .. next char
  330.  
  331.         MOV     BYTE PTR [SI-1], 0        ; end the parameter
  332.         JMP     PARMS10            ; .. look for next
  333.  
  334. PARMS50:    MOV     BYTE PTR [SI-1], 0        ; end the parameter
  335.  
  336.         CMP     ARG, 0            ; q. PARMS 1 available?
  337.         JNE     PARMS60            ; a. no .. error
  338.  
  339.         CMP     RSTFLAG, 0            ; q. restoring?
  340.         JE        PARMSERR            ; a. no .. error
  341.  
  342.         MOV     ARG, OFFSET CURRDIR     ; arg -> current directory
  343.  
  344. PARMS60:    CMP     FLOPDRV, 0            ; q. Drive given?
  345.         JE        PARMSERR            ; a. no .. error also
  346.  
  347.         RET                 ; .. else .. return to caller
  348.  
  349. PARMSERR:   MOV     DX, OFFSET FORMAT        ; dx -> format message
  350.         MOV     AH, 09H            ; ah = print ascii$
  351.         INT     21H             ; hey DOS .. print it!
  352.  
  353.         MOV     DX, OFFSET RSFORM        ; dx -> restore format
  354.  
  355.         CMP     RSTFLAG, 0            ; q. restore?
  356.         JNZ     PARMSERR1            ; a. yes .. die now
  357.  
  358.         MOV     DX, OFFSET SPFORM        ; dx -> split format
  359.  
  360. PARMSERR1:  CALL    DIE             ; .. play taps
  361. PARMS        ENDP
  362.  
  363. ; ---------------------------------------------------------------------------
  364. ;   ARGCHK - Setup pointers to command line args; si -> 2nd char in arg
  365. ;         Exit: ARG or FLOPDRV filled in; Carry set if > 2 args
  366. ; ---------------------------------------------------------------------------
  367. ARGCHK        PROC
  368.         LEA     BX, [SI-1]            ; bx -> argument
  369.  
  370.         CMP     RSTFLAG, 0            ; q. restoring?
  371.         JE        ARG05            ; a. no .. continue
  372.  
  373.         CMP     FLOPDRV, 0            ; q. drive filled in?
  374.         JE        ARG20            ; a. no .. fill it in
  375.  
  376. ARG05:        CMP     ARG, 0            ; q. ARG filled in?
  377.         JNE     ARG10            ; a. yes .. check 2
  378.         MOV     ARG, BX            ; save ARG pointer
  379.         JMP     SHORT ARG90         ; .. exit ok!
  380.  
  381. ARG10:        CMP     FLOPDRV, 0            ; q. drive filled in?
  382.         JE        ARG20            ; a. no .. fill it in
  383.         STC                 ; else .. error
  384.         RET                 ; .. and return to caller
  385.  
  386. ARG20:        MOV     FLOPDRV, AL         ; save drive
  387.         MOV     UNSPLITDRV, AL        ; .. in file and program names
  388.  
  389.         MOV     BL, AL            ; bl = drive letter
  390.         SUB     BL, "@"                 ; bl = drive number
  391.         MOV     AX, 4408H            ; ax = ioctl, removable?
  392.         INT     21H             ; issue DOS call
  393.  
  394.         OR        AL, AL            ; q. removable media drive?
  395.         JZ        ARG90            ; a. yes .. return
  396.  
  397.         MOV     DX, OFFSET DRVNR        ; dx -> error message
  398.         CALL    DIE             ; issue non-removable message
  399.  
  400. ARG90:        CLC                 ; show no error
  401.         RET                 ; return to caller
  402. ARGCHK        ENDP
  403.  
  404. ; ---------------------------------------------------------------------------
  405. ;   UPCASE - Convert command line arguments to uppercase
  406. ; ---------------------------------------------------------------------------
  407. UPCASE        PROC
  408.         PUSH    SI                ; save caller regs
  409.         PUSH    DI
  410.         MOV     SI, 81H            ; si -> start of parm area
  411.         MOV     DI, SI            ; .. same for di
  412.         CLD                 ; .. assure ascending
  413.  
  414. UPCASE10:   LODSB                ; al = char
  415.         CMP     AL, 0DH            ; q. end of line?
  416.         JE        UPCASE90            ; a. yes .. end of line!
  417.         CMP     AL, "a"                 ; q. is it below 'a'?
  418.         JB        UPCASE20            ; a. yes .. continue
  419.         CMP     AL, "z"                 ; q. is it above 'z'?
  420.         JA        UPCASE20            ; a. yes .. continue
  421.         SUB     AL, 20H            ; set to upper case
  422.  
  423. UPCASE20:   STOSB                ; save the byte
  424.         JMP     UPCASE10            ; .. and continue
  425.  
  426. UPCASE90:   POP     DI                ; restore caller regs
  427.         POP     SI
  428.         RET                 ; .. and return to caller
  429. UPCASE        ENDP
  430.  
  431. ; ---------------------------------------------------------------------------
  432. ;   DIE - Display an error message and return to DOS; dx -> ascii$ error msg
  433. ; ---------------------------------------------------------------------------
  434. DIE        PROC
  435.         MOV     AH, 9H            ; ah = print string
  436.         INT     21H             ; .. call dos to print error
  437.  
  438.         MOV     BX, IHANDLE         ; bx = input file handle
  439.         OR        BX, BX            ; q. file opened?
  440.         JZ        DIE90            ; a. no .. try output file
  441.  
  442.         MOV     AH, 3EH            ; ah = close file
  443.         INT     21H             ; .. ask DOS to do it
  444.  
  445. DIE90:        MOV     BX, OHANDLE         ; bx = output file handle
  446.         OR        BX, BX            ; q. file opened?
  447.         JZ        DIE95            ; a. no .. just exit
  448.  
  449.         MOV     AH, 3EH            ; ah = close file
  450.         INT     21H             ; .. ask DOS to do it
  451.  
  452. DIE95:        MOV     AX, 4C00H            ; ax = exit
  453.         INT     21H             ; .. terminate routine
  454. DIE        ENDP
  455.  
  456.  
  457. RESTLIMIT   EQU     $                ; only need up to here
  458.  
  459.  
  460. ; ---------------------------------------------------------------------------
  461. ;   Split only areas and messages
  462. ; ---------------------------------------------------------------------------
  463. SPFORM        DB        "SPLIT     [d:\path\]filename[.ext] "
  464.         DB        " d:",0DH,0AH,0AH,"$"
  465. ZEROLEN     DB        "Input file empty",0DH,0AH,"$"
  466. NOCOM        DB        "Program won't fit",0DH,0AH,"$"
  467. UNSPLITDRV  DB        "x:\"
  468. UNSPLIT     DB        "UNSPLIT.COM",0
  469.  
  470. ; ---------------------------------------------------------------------------
  471. ;   OPEN - Opens next file to process; Carry indicates file would not open.
  472. ; ---------------------------------------------------------------------------
  473. OPEN        PROC
  474.         MOV     DX, ARG            ; dx -> file name
  475.         MOV     AX, 3D00H            ; al = open for read
  476.         INT     21H             ; .. ask DOS to do it.
  477.         JC        OPEN05            ; ok .. continue
  478.  
  479.         MOV     IHANDLE, AX         ; save file handle
  480.  
  481.         MOV     AH, 4EH            ; ah = find first
  482.         MOV     DX, ARG            ; dx -> file to find
  483.         XOR     CX, CX            ; cx = search attribute
  484.         INT     21H             ; q. find first file ok?
  485.         JNC     OPEN10            ; a. yes .. continue
  486.  
  487. OPEN05:     MOV     DX, OFFSET FILENF        ; dx -> file not found
  488.         CALL    DIE             ; .. gasp your final breath
  489.  
  490. OPEN10:     MOV     AX, DS:DTA_LSIZ        ; ax = lsw of size
  491.         OR        AX, DS:DTA_HSIZ        ; q. any data?
  492.         JNZ     OPEN90            ; a. yes ..continue
  493.  
  494.         MOV     DX, OFFSET ZEROLEN        ; dx -> file contains no data
  495.         CALL    DIE             ; .. dearly beloved ...
  496.  
  497. OPEN90:     RET
  498. OPEN        ENDP
  499.  
  500. ; ---------------------------------------------------------------------------
  501. ;   SAVE - Handle building split files on destination
  502. ; ---------------------------------------------------------------------------
  503. SAVE        PROC
  504.         CALL    BLD_RESTORE         ; build restore program
  505.  
  506. SAVE10:     MOV     AH, 03FH            ; ah = read file
  507.         MOV     BX, IHANDLE         ; bx = handle of file to read
  508.         MOV     CX, BUFLEN            ; cx = amount to read
  509.         MOV     DX, OFFSET BUFFER        ; dx -> buffer
  510.         INT     21H             ; read, please
  511.         JNC     SAVE20            ; if no error .. continue
  512.  
  513.         MOV     DX, OFFSET RDERROR        ; dx -> read error message
  514.         CALL    DIE             ; ..and die gracefully
  515.  
  516. SAVE20:     CALL    WRITE            ; ..and write out a buffer full
  517.         JC        SAVE90            ; if finished .. exit loop
  518.         JMP     SAVE10            ; else .. get next buffer
  519.  
  520. SAVE90:     RET                 ; return to caller
  521. SAVE        ENDP
  522.  
  523. ; ---------------------------------------------------------------------------
  524. ;   BLD_RESTORE - Build the restore program
  525. ; ---------------------------------------------------------------------------
  526. BLD_RESTORE PROC
  527.         MOV     AH, 2AH            ; ah = get date function call
  528.         INT     21H             ; issue DOS call
  529.  
  530.         MOV     WORD PTR RSTSDTE, CX    ; save year
  531.         MOV     WORD PTR RSTSDTE+2, DX  ; ..and month and day
  532.  
  533.         MOV     AH, 2CH            ; ah = get time function call
  534.         INT     21H             ; issue DOS call
  535.  
  536.         MOV     WORD PTR RSTSTME, CX    ; save hours and minutes
  537.         MOV     WORD PTR RSTSTME+2, DX  ; ..and seconds and hundredths
  538.  
  539.         MOV     SI, OFFSET DTA_ATTR     ; si -> source string
  540.         MOV     DI, OFFSET RSTATTR        ; di -> save area
  541.         MOV     CX, RST_FFLEN        ; cx = length to move
  542.     REP MOVSB                ; copy string
  543.  
  544.         MOV     DI, OFFSET HEADER_MSG   ; di -> program name
  545.         MOV     SI, OFFSET UNSPLIT        ; si -> restore program name
  546.         MOV     CX, 7            ; cx = length
  547.     REP MOVSB                ; .. setup program name
  548.  
  549.         MOV     SI, OFFSET DTA_NAME     ; si -> source file name
  550.         MOV     DI, OFFSET DESTFILE     ; di -> work file name
  551.         MOV     CX, 8            ; cx = length to move
  552.  
  553. BLD_REST10: LODSB                ; al = char from filename
  554.  
  555.         CMP     AL, "."                 ; q. end of filename?
  556.         JE        BLD_REST30            ; a. yes .. exit loop
  557.         OR        AL, AL            ; q. end of string?
  558.         JZ        BLD_REST20            ; a. yes .. exit loop
  559.  
  560.         STOSB                ; save character
  561.         LOOP    BLD_REST10            ; ..and loop till end of string
  562.  
  563. BLD_REST20: MOV     AL, "."                 ; assure file separator char
  564. BLD_REST30: STOSB                ; save the separator
  565.  
  566.         MOV     DESTEXT, DI         ; save pointer to file extension
  567.  
  568.         CMP     BYTE PTR [SI-1], "."    ; q. was extension found?
  569.         JNE     BLD_REST32            ; a. no .. allow default
  570.  
  571.         LODSB                ; get 1st char after extenstion
  572.         MOV     DESTEXTC, AL        ; ..and save for later
  573.  
  574. BLD_REST32: MOV     RSTFLAG, 1            ; set restore flag
  575.  
  576.         MOV     AL, DESTEXTC        ; al = 1st char of extension
  577.         MOV     DI, DESTEXT         ; di -> position in filename
  578.         STOSB                ; save 1st character
  579.         MOV     DESTEXT, DI         ; save pointer to 2nd char
  580.  
  581. BLD_REST35: MOV     DX, OFFSET UNSPLITDRV   ; dx -> UNSPLIT program name
  582.         CALL    CREATE            ; create the new file
  583.  
  584.         PUSH    WORD PTR FLOPDRV        ; save drive parameter
  585.         PUSH    ARG             ; .. and ARG
  586.         MOV     FLOPDRV, 0            ; zero ..
  587.         MOV     ARG, 0            ; .. them out
  588.  
  589.         MOV     AH, 40H            ; ah = write function code
  590.         MOV     CX, OFFSET RESTLIMIT    ; cx = length to move
  591.         MOV     DX, OFFSET START        ; dx -> start of program
  592.         SUB     CX, DX            ; .. forget the PSP
  593.         INT     21H             ; issue DOS call
  594.  
  595.         POP     ARG             ; restore ..
  596.         POP     WORD PTR FLOPDRV        ; .. parameters
  597.         JC        BLD_REST40            ; if error .. try again
  598.  
  599.         CMP     AX, CX            ; q. all of pgm get out?
  600.         JE        BLD_REST50            ; a. yes .. continue
  601.  
  602. BLD_REST40: MOV     AH, 3EH            ; ah = close function
  603.         INT     21H             ; close file
  604.  
  605.         CALL    DELETE            ; delete output file
  606.         MOV     DX, OFFSET NOCOM        ; dx -> no room at the inn
  607.         CALL    HITKEY            ; ..issue message
  608.         JMP     BLD_REST35            ; ..and try with a new diskette
  609.  
  610. BLD_REST50: MOV     AH, 3EH            ; ah = close file
  611.         INT     21H             ; .. ask DOS to do it
  612.  
  613.         RET                 ; return to caller
  614. BLD_RESTORE ENDP
  615.  
  616. ; ---------------------------------------------------------------------------
  617. ;   WRITE - Write a file segment; ax = nbr of bytes to write (0 if EOF)
  618. ;                Exit: Carry set if EOF processing complete
  619. ; ---------------------------------------------------------------------------
  620. WRITE        PROC
  621.         MOV     BX, OHANDLE         ; bx = handle number
  622.         MOV     CX, AX            ; q. anything to write?
  623.         JCXZ    WRITE50            ; a. no .. EOF request
  624.  
  625.         MOV     DX, OFFSET BUFFER        ; dx -> start of buffer
  626.         OR        BX, BX            ; q. handle open?
  627.         JNZ     WRITE40            ; a. yes .. continue
  628.  
  629. WRITE05:    PUSH    CX                ; save length
  630.         PUSH    DX                ; ..and buffer address
  631.         CALL    NEXTFILE            ; build extension for next file
  632.  
  633. WRITE10:    MOV     DX, OFFSET FLOPDRV        ; dx -> file to create
  634.         CALL    CREATE            ; open new file
  635.  
  636.         MOV     OHANDLE, BX         ; save file handle
  637.         MOV     CX, RST_LEN         ; cx = length of header
  638.         CALL    HOWMUCH            ; update remaining disk space
  639.         MOV     AH, 40H            ; ah = write file function
  640.         MOV     DX, OFFSET RSTLAST        ; dx -> our file header
  641.         INT     21H             ; issue DOS call
  642.         JNC     WRITE20            ; if no error .. continue
  643.  
  644.         MOV     DX, OFFSET WRTERROR     ; dx -> error message
  645.         CALL    DIE             ; ..then display and die
  646.  
  647. WRITE20:    CMP     AX, CX            ; q. write out all of header?
  648.         JE        WRITE30            ; a. yes .. continue
  649.  
  650.         MOV     AH, 3EH            ; ah = close function
  651.         INT     21H             ; issue DOS call
  652.         MOV     OHANDLE, 0            ; .. show file closed
  653.  
  654.         CALL    DELETE            ; delete new file
  655.  
  656.         MOV     DX, OFFSET NOROOM        ; dx -> next disk message
  657.         CALL    HITKEY            ; issue message and wait
  658.         JMP     WRITE10            ; ..try to get next file
  659.  
  660. WRITE30:    POP     DX                ; restore registers
  661.         POP     CX                ;
  662.  
  663. WRITE40:    CALL    HOWMUCH            ; get how much to write
  664.  
  665.         MOV     AH, 40H            ; ah = write file
  666.         INT     21H             ; issue DOS call
  667.         JNC     WRITE45            ; die on any error
  668.  
  669.         MOV     DX, OFFSET WRTERROR     ; dx -> general error msg
  670.         CALL    DIE             ; issue msg and terminate
  671.  
  672. WRITE45:    ADD     DX, AX            ; dx -> next buffer address
  673.         MOV     CX, DI            ; cx = remainder of bytes to write
  674.         JCXZ    WRITE48            ; if no more, exit
  675.  
  676.         PUSH    DX                ; save buffer address
  677.         MOV     AH, 3EH            ; ah = close function
  678.         INT     21H             ; issue DOS call
  679.         MOV     OHANDLE, 0            ; .. show file closed
  680.  
  681.         MOV     DX, OFFSET NEXTDISK     ; dx -> next disk message
  682.         CALL    HITKEY            ; display message and wait
  683.         POP     DX                ; .. restore buffer address
  684.         JMP     WRITE05            ; ..then get next file
  685.  
  686. WRITE48:    CLC                 ; clear carry for caller
  687.         RET                 ; ..and return
  688.  
  689.  
  690. WRITE50:    OR        BX, BX            ; q. handle open?
  691.         JZ        WRITE60            ; a. no .. continue
  692.  
  693.         MOV     AX, 4200H            ; ah = position file
  694.         XOR     CX, CX            ; cx = file position
  695.         XOR     DX, DX            ; dx = msb of file position
  696.         INT     21H             ; position to top of file
  697.  
  698.         MOV     RSTLAST, 1            ; set flag
  699.         MOV     AH, 40H            ; ah = write function
  700.         MOV     CX, 1            ; cx = length
  701.         MOV     DX, OFFSET RSTLAST        ; dx -> buffer
  702.         INT     21H             ; write eof marker in header
  703.  
  704.         MOV     AH, 3EH            ; ah = close function
  705.         INT     21H             ; issue DOS call
  706.         MOV     OHANDLE, 0            ; .. show file closed
  707.  
  708. WRITE60:    STC                 ; set carry flag
  709.         RET                 ; ..and return to caller
  710. WRITE        ENDP
  711.  
  712. ; ---------------------------------------------------------------------------
  713. ;   HOWMUCH - Calculate how much to write; cx = requested amount to write
  714. ;                     Exit: cx = nbr of bytes which will fit
  715. ;                       di = remainder
  716. ; ---------------------------------------------------------------------------
  717. HOWMUCH     PROC
  718.         PUSH    DX                ; save registers
  719.  
  720.         MOV     AX, WORD PTR AVAIL        ; get howmuch is available
  721.         MOV     DX, WORD PTR AVAIL+2    ; . . . .
  722.         MOV     DI, 0            ; assume everything will fit
  723.  
  724.         OR        DX, DX            ; q. more than 64k?
  725.         JNZ     HOWMUCH80            ; a. no .. must be less than 64k
  726.  
  727.         CMP     CX, AX            ; q. enough room left?
  728.         JNA     HOWMUCH80            ; a. yes .. use it all
  729.  
  730.         MOV     DI, CX            ; di = nbr requested
  731.         SUB     DI, AX            ; di = remainder
  732.         MOV     CX, AX            ; cx = nbr to write
  733.  
  734. HOWMUCH80:  SUB     AX, CX            ; ax = new available
  735.         SBB     DX, 0            ; dx:ax = new available
  736.         MOV     WORD PTR AVAIL, AX        ; store for later
  737.         MOV     WORD PTR AVAIL+2, DX    ; . . . .
  738.  
  739. HOWMUCH90:  POP     DX                ; restore registers
  740.         RET                 ; ..and return
  741. HOWMUCH     ENDP
  742.  
  743. ; ---------------------------------------------------------------------------
  744. ;   CREATE - Create new file; dx -> file to open
  745. ;            Exit: bx = handle of opened file
  746. ; ---------------------------------------------------------------------------
  747. CREATE        PROC
  748.         MOV     BP, DX            ; save file name pointer
  749.  
  750. CREATE10:   MOV     AH, 36H            ; ah = get drive info
  751.         MOV     DL, FLOPDRV         ; dl = drive letter
  752.         SUB     DL, "@"                 ; dl = drive number
  753.         INT     21H             ; get free space
  754.  
  755.         CMP     AX, -1            ; q. drive ok?
  756.         JE        CREATE15            ; a. no .. next disk
  757.  
  758.         OR        BX, BX            ; q. any clusters available?
  759.         JNZ     CREATE18            ; a. yes .. build new file
  760.  
  761. CREATE15:   MOV     DX, OFFSET NOROOM        ; dx -> no room at inn message
  762.         CALL    HITKEY            ; get new diskette
  763.         JMP     CREATE10            ; ..try again
  764.  
  765. CREATE18:   MUL     BX                ; dx:ax = nbr of sectors available
  766.         MUL     CX                ; dx:ax = nbr of bytes available
  767.         MOV     WORD PTR AVAIL, AX        ; store howmuch is available
  768.         MOV     WORD PTR AVAIL+2, DX    ; . . . .
  769.  
  770.         MOV     AH, 4EH            ; ah = find first function code
  771.         MOV     CX, 0FFH            ; cx = any attributes
  772.         MOV     DX, BP            ; dx -> filename
  773.         INT     21H             ; issue DOS call
  774.         JC        CREATE20            ; if not available, create it
  775.  
  776.         MOV     DX, OFFSET FILEFND        ; dx -> file found message
  777.         CALL    HITKEY            ; let user change diskette
  778.         JMP     CREATE10            ; ..then try again
  779.  
  780. CREATE20:   MOV     AH, 3CH            ; ah = create function code
  781.         XOR     CX, CX            ; cx = no (special) attributes
  782.         INT     21H             ; issue DOS call
  783.         JNC     CREATE90            ; if problems, exit
  784.  
  785.         MOV     DX, OFFSET NOCREATE     ; dx -> create error message
  786.         CALL    DIE             ; ..and die
  787.  
  788. CREATE90:   MOV     BX, AX            ; bx = handle
  789.         RET                 ; ..and return to caller
  790. CREATE        ENDP
  791.  
  792. ; ---------------------------------------------------------------------------
  793. ;   DELETE - Delete a file
  794. ; ---------------------------------------------------------------------------
  795. DELETE        PROC
  796.         MOV     AH, 41H            ; ah = delete function
  797.         MOV     DX, OFFSET FLOPDRV        ; dx -> filename
  798.         INT     21H             ; issue DOS call
  799.  
  800.         RET                 ; ..and return
  801. DELETE        ENDP
  802.  
  803. ; ---------------------------------------------------------------------------
  804. ;   Uninitialized data areas
  805. ; ---------------------------------------------------------------------------
  806. UDATA        EQU     $                ; start of unitialized data
  807. ROPENFILE   EQU     BYTE PTR UDATA        ; word area for ropen
  808. AVAIL        EQU     DWORD PTR ROPENFILE+65  ; available output space
  809. BUFFER        EQU     BYTE PTR AVAIL+4        ; file buffer
  810. BUFLEN        EQU     32*1024            ; length of buffer
  811.  
  812. CSEG        ENDS                ; end of code segment
  813.         END     START
  814.