home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format 91 / af091a.adf / af91a3.lzx / prgs / ShellUtils / chcp.b < prev    next >
Encoding:
Text File  |  1996-09-15  |  6.1 KB  |  243 lines

  1. /* 
  2. ** This program copies source files to a destination 
  3. ** directory/volume. Wildcards are supported. Recurses 
  4. ** into directories if "all" is part of the pattern and
  5. ** directories are created as necessary.
  6. **
  7. ** Files are copied piece-wise according to a CHUNK 
  8. ** size. This permits slow/dodgy devices (eg. my 100M 
  9. ** SCSI Zip drive on an A1200 Ferret SCSI interface can't 
  10. ** handle big (~0.5M) files correctly).
  11. **
  12. ** Known Bugs: Assumes that all path components higher
  13. ** than the ones to be visited exist, eg. if we're
  14. ** trying to create the directory 1.3 in ACE:bin/1.3
  15. ** when supplying the pattern "ACE:bin/#? all", then
  16. ** ACE:bin must already exist. So, it's best to choose
  17. ** a source which is high-level and can be recursed into.
  18. ** An obvious solution to this bug is to call a SUB which
  19. ** examines all path components and creates any that don't
  20. ** exist. Use Examine and ExAll for this? Or just take
  21. ** substrings delimited by ":" and "/"? 
  22. **
  23. ** Author: David J Benn
  24. **   Date: 29th December 1994,
  25. **       15th July 1996,
  26. **         25th,26th,27th August 1996
  27. */
  28.  
  29. #include <exec/memory.h>
  30. #include <dos/dos.h>
  31. #include <dos/dosasl.h>
  32. #include <funcs/exec_funcs.h>
  33. #include <funcs/dos_funcs.h>
  34.  
  35. DefLng a-z
  36.  
  37. Library "exec.library"
  38.  
  39. Const FILEPATHSZ = 1024    /* size of file pathname */
  40. Const CHUNK = 10240    /* copy files in 10K chunks */
  41.  
  42. Declare Sub Abort
  43. Declare Sub CopyFile(src$,dest$)
  44.  
  45. On Break Call Abort : Break On
  46.  
  47. SUB Usage
  48.     PRINT "usage: ";ARG$(0);" file-pattern [...] destination"
  49.     STOP
  50. END SUB
  51.  
  52. Sub Abort
  53. /*
  54. ** Quits but does no cleanup!
  55. */
  56.   Print Arg$(0);": ***break!"
  57.   Library Close
  58.   Stop
  59. End Sub
  60.  
  61. Sub VisitFiles(pat$, dest$, allFiles)
  62. /*
  63. ** Visit each file specified by the pattern.
  64. ** If the pattern contains "all", this function
  65. ** is called recursively. Each recursive call
  66. ** requires a new AnchorPath structure variable
  67. ** so that previous pattern match states aren't
  68. ** affected. 
  69. */
  70. Declare Struct AnchorPath *anchor
  71. Declare Struct FileInfoBlock *fileInfo
  72.  
  73.   /*
  74.   ** Allocate a structure for the search.
  75.   */
  76.   anchor = AllocMem(Sizeof(AnchorPath)+FILEPATHSZ, MEMF_ANY Or MEMF_CLEAR)
  77.   If anchor = NULL Then 
  78.     Print Arg$(0);": Memory allocation error!"
  79.   Else
  80.     /*
  81.     ** Set file path buffer length.
  82.     */
  83.     anchor->ap_StrLen = FILEPATHSZ
  84.  
  85.     /*
  86.     ** Pattern-based search.
  87.     */
  88.     result = MatchFirst(pat$, anchor)
  89.     While result <> ERROR_NO_MORE_ENTRIES
  90.       /*
  91.       ** Get the path.
  92.       */
  93.       path$ = anchor->ap_Buf
  94.  
  95.       /*
  96.       ** Get the path minus the first directory
  97.       ** or volume name.
  98.       */
  99.       destFilePart$ = path$
  100.       posn = Instr(destFilePart$,":")
  101.       If posn > 0 Then 
  102.         destFilePart$ = Mid$(destFilePart$,posn+1)
  103.       Else
  104.         posn = Instr(destFilePart$,"/")
  105.     If posn > 0 Then
  106.       destFilePart$ = Mid$(destFilePart$,posn+1)
  107.     End If
  108.       End If
  109.  
  110.       /*
  111.       ** Is this a directory or file? If the former,
  112.       ** does it need to be created? Otherwise, just
  113.       ** copy the file. 
  114.       */
  115.       fileInfo = @anchor->ap_Info
  116.       If fileInfo->fib_DirEntryType > 0 Then
  117.           /*
  118.     ** Try to create the directory. If it
  119.      ** fails, either it already exists or
  120.     ** we don't have any space left.
  121.     */
  122.     dirLock = CreateDir(dest$+destFilePart$)
  123.         If dirLock Then 
  124.       Print path$;" [directory created]"
  125.       UnLock(dirLock)
  126.     Else 
  127.       Print path$;" [directory]"
  128.     End If
  129.  
  130.         /*
  131.         ** Visit this directory recursively?
  132.         */
  133.         If allFiles Then Call VisitFiles(path$+"/#?", dest$, allFiles)
  134.       Else
  135.     /*
  136.     ** Copy the file then sleep for awhile to let 
  137.     ** the destination device (eg. Zip) to catch 
  138.     ** up if need be.
  139.     */
  140.     CopyFile(path$, dest$+destFilePart$)
  141.     Sleep For .25
  142.       End If
  143.       result = MatchNext(anchor)
  144.     Wend
  145.  
  146.     /*
  147.     ** Clean up resources associated with this search.
  148.     */
  149.     If anchor Then 
  150.       MatchEnd(anchor)
  151.       FreeMem(anchor, Sizeof(AnchorPath)+FILEPATHSZ)
  152.     End If
  153.   End If
  154. End Sub
  155.  
  156. Sub ReportFileError(n) 
  157.     CASE
  158.     n = 1 : PRINT "Unable to open source file."
  159.     n = 2 : PRINT "Source file empty."
  160.     n = 3 : PRINT "Unable to allocate memory for file buffer."
  161.     n = 4 : PRINT "Error while reading from source file."
  162.     n = 5 : PRINT "Unable to open destination file."
  163.     n = 6 : PRINT "Error while writing to destination file."
  164.     END CASE
  165.     CLOSE #1
  166.     CLOSE #2
  167. End Sub
  168.  
  169. Sub CopyFile(src$, dest$)
  170. /*
  171. ** Copy a file from the specified full source path
  172. ** to the specified full destination path.
  173. */ 
  174. ADDRESS src,dest,buf 
  175. LONGINT length,bytes,bytes_read,bytes_written,total
  176.  
  177.   Print src$;" -> ";dest$
  178.  
  179.   OPEN "I",#1,src$ 
  180.   src = HANDLE(1) : IF src = NULL THEN CALL ReportFileError(1) 
  181.   bytes = LOF(1)
  182.   OPEN "O",#2,dest$ 
  183.   dest = HANDLE(2) : IF dest = NULL THEN CALL ReportFileError(5)
  184.   IF bytes = 0 THEN CALL ReportFileError(2) 
  185.   If bytes > CHUNK Then length = CHUNK Else length = bytes
  186.   buf = AllocMem(length, MEMF_ANY Or MEMF_CLEAR)
  187.   IF buf = NULL THEN CALL ReportFileError(3) 
  188.   While Not Eof(1)
  189.     bytes_read = _Read(src,buf,length)
  190.     If bytes_read = -1 THEN 
  191.       ReportFileError(4) 
  192.     Else
  193.       If bytes_read <> 0 Then
  194.         bytes_written = _Write(dest,buf,bytes_read)
  195.         If bytes_written <> bytes_read THEN CALL ReportFileError(6)
  196.         total = total + bytes_written
  197.       End If
  198.     End If
  199.     Print "Written";total;"bytes (";Str$((total*100)\bytes);"% )";Chr$(13);
  200.   Wend
  201.   If buf Then Call FreeMem(buf,length)
  202.   Print
  203.   CLOSE #2 
  204.   CLOSE #1 
  205. End Sub
  206.  
  207. /*
  208. ** Main.
  209. */
  210. If Argcount >= 2 Then
  211.   /*
  212.   ** Construct the pattern from potentially multiple arguments.
  213.   ** There must be at least two arguments the last of which is
  214.   ** asumed to be a destination directory/volume (see usage).
  215.   */
  216.   pat$ = ""
  217.   For i=1 To Argcount-1
  218.     pat$ = pat$ + Arg$(i)
  219.     If i <> Argcount-1 Then pat$ = pat$ + " "
  220.   Next
  221.   If Ucase$(Right$(pat$,4)) = " ALL" Then
  222.     allFiles = TRUE
  223.     pat$ = Left$(pat$,Len(pat$)-4)
  224.   Else
  225.     allFiles = FALSE
  226.   End If
  227.  
  228.   /*
  229.   ** Make sure we have a semi-sane destination.
  230.   */
  231.   dest$ = Arg$(Argcount)
  232.   If Right$(dest$,1) <> ":" And Right$(dest$,1) <> "/" Then 
  233.     dest$ = dest$ + "/"
  234.   End If
  235.  
  236.   /*
  237.   ** Go to it.
  238.   */
  239.   VisitFiles(pat$, dest$, allFiles)
  240. Else
  241.   Usage
  242. End If
  243.