home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 536.lha / QDCopy_v1.0 / QDCopy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-09  |  19.5 KB  |  553 lines

  1. /*
  2. QDCopy Version 1.0
  3.  
  4. Quick & Dirty File Copier (or Qwazy Darren File Copier!)
  5.  
  6. Created on   July 10, 1991
  7. Last revised July 15, 1991
  8.  
  9. Copyright (C) 1991 by Darren Ewaniuk
  10. Freely distributable with conditions
  11. (See "distribution" section of the documentation file for more information)
  12.  
  13. Compiled using the Freely distributable DICE C compiler version 2.06.16
  14. (Thanks to Matt Dillon for DICE - as soon as it includes the 2.0
  15.  specific files, I'm sending in the registration for it)
  16.  
  17. Compile using "DCC QDCopy.c /arplib/aztecglue.o -o QDCopy"
  18.  
  19. Library functions used:
  20.  
  21.     Exec
  22.         OpenLibrary     To open ARP library
  23.         CloseLibrary    To close ARP library
  24.         SetSignal       Break handling
  25.  
  26.     DOS.library
  27.         Close           Close files
  28.         DeleteFile      Delete incomplete file when disk full
  29.         IoErr           Check what error occurred
  30.         Open            Open files
  31.         Read            Read files
  32.         SetComment      Set file comment
  33.         SetProtection   Set protection bits
  34.         Write           Write files
  35.  
  36.     Arp.library V39
  37.         BaseName        Finds base name of read files
  38.         DosAllocMem     Allocates memory
  39.         DosFreeMem      Frees memory
  40.         FindFile        Finds first wildcard file
  41.         FindNext        Finds subsequent wildcard files
  42.         FreeAnchorChain Frees ARP's wildcard file structures
  43.         ReadLine        Gets user input during diskchanges
  44.         TackOn          Puts together filename from basename and pathname
  45.  
  46.         NOTE:   The C functions malloc() and free() can be used instead of
  47.                 DosAllocMem() and DosFreeMem() but I've heard problems with
  48.                 one of the 'big-name' compilers that use these functions,
  49.                 so I just used the ARP ones since I'm using ARP anyways.
  50. /*
  51.  
  52. /* Pretend DICE is Aztec C so that arpbase.h does not try to use #pragmas */
  53.  
  54. #define AZTEC_C 1
  55.  
  56. /* Include the necessary files */
  57.  
  58. #include <exec/types.h>
  59. #include <exec/memory.h>
  60. #include <libraries/dos.h>
  61. #include <libraries/arpbase.h>
  62. #include <stdio.h>
  63. #include <stdlib.h>
  64.  
  65. /* Set up Arp library base */
  66.  
  67. struct ArpBase *ArpBase;
  68.  
  69. /* Stuff for file name buffers */
  70.  
  71. #define MaxPathSize 130
  72. #define MaxFileNameSize 30
  73. #define MaxPathNameSize MaxPathSize+MaxFileNameSize+1
  74.  
  75. /* This is where I store the filenames which match the wildcard */
  76.  
  77. struct QDFileChain  /* Structure for each file buffer entry */
  78. {
  79.     struct QDFileChain  *Next;          /* Pointer to next file name */
  80.     void                *FileBuffer;    /* Pointer to storage buffer */
  81.     char                FileName[MaxPathNameSize];  /* full path file name */
  82.     LONG                Protection;     /* DOS protection bits */
  83.     LONG                Size;           /* DOS file size */
  84.     char                Comment[80];    /* DOS file comment */
  85. };
  86.  
  87. /* This function cleans up all memory used by QDFileChain structures */
  88. /* Shouldn't be needed for normal exit, but if premature, this frees */
  89. /* the memory used by the programs */
  90.  
  91. void cleanupchain (struct QDFileChain *chainhead)
  92. {
  93.     struct QDFileChain *nextptr;
  94.  
  95.     while (chainhead)   /* While the head is not NULL free up the next */
  96.     {
  97.         nextptr = chainhead->Next;
  98.  
  99.         if (chainhead->FileBuffer)  /* Is the file buffered in memory? */
  100.         {
  101.             DosFreeMem (chainhead->FileBuffer);  /* Free it back to the system */
  102.         }
  103.         DosFreeMem (chainhead);   /* Free this file chain structure */
  104.         chainhead = nextptr;
  105.     }
  106. }
  107.  
  108. /* This function tests a file or path name for an explicitly specified */
  109. /* device name.  If the name contains ':' then I assume one is specified */
  110.  
  111. int isfullname (char *name)
  112. {
  113.     int pos = 0;
  114.     while ((name[pos] != 0) && (name[pos] != ':'))
  115.     {
  116.         pos++;
  117.     }
  118.     if (name[pos])  /* If not end of string, current char is ':' */
  119.     {
  120.         return(TRUE);
  121.     }
  122.     else            /* Reached end of string first.  No ':' in name */
  123.     {
  124.         return(FALSE);
  125.     }
  126. }
  127.  
  128. /* Kill DICE's break handling */
  129.  
  130. void chkabort()
  131. {
  132. }
  133.  
  134. /* Checks for break and returns TRUE if pressed */
  135.  
  136. int taskbreak()
  137. {
  138.     /* Check and clear break signal */
  139.  
  140.     if ((SetSignal(0L, SIGBREAKF_CTRL_C)) & SIGBREAKF_CTRL_C)
  141.     {
  142.         printf ("***QDCOPY BREAK\n");
  143.         return (TRUE);
  144.     }
  145.     else
  146.     {
  147.         return (FALSE);
  148.     }
  149. }
  150.  
  151. /* Start of the main program */
  152.  
  153. void main (int argc, char *argv[])
  154. {
  155.     BPTR filehandle;            /* BPTR file handle for src, dest files */
  156.     LONG len;                   /* # of bytes read from/written to file */
  157.  
  158.     int warncode = 0;           /* Exit code for return to shell */
  159.     int breaksignal;            /* Break flag */
  160.     int memfull = FALSE;        /* Memory full flag */
  161.     int newdest;                /* Prompt for new Destination disk flag */
  162.  
  163.     char destpath[MaxPathSize+1];   /* Current destination path */
  164.     char pathname[MaxPathNameSize]; /* Full path name for write */
  165.     char *basename;                 /* Base name for write */
  166.  
  167.     /* Used for diskchange prompt */
  168.  
  169.     char inputline [MaxInputBuf];   /* Input line buffer */
  170.     LONG inputlength;               /* Length of input line buffer */
  171.  
  172.     struct QDFileChain  *filehead = NULL;   /* First file in chain */
  173.     struct QDFileChain  *fileptr1 = NULL;   /* Last file read */
  174.     struct QDFileChain  *fileptr2 = NULL;   /* Last file written */
  175.     struct AnchorPath *anchorpath;  /* ARP wildcard anchorpath structure */
  176.  
  177.     LONG errorcode;                 /* DOS & ARP error code */
  178.  
  179.     /* DICE leaves before 0 args are passed because there's no WBMain() */
  180.     /* but I thought I'd leave it in for people with other compilers */
  181.  
  182.     if (argc == 0)          /* Too bad, cannot run from Workbench. */
  183.     {
  184.         exit (0);
  185.     }
  186.     else if (argc !=3)      /* User doesn't know what he's doing! */
  187.     {
  188.         printf ("\n\033[33mQDCopy 1.0\033[31m (July 15, 1991) Quick and Dirty file copier\n");
  189.         printf ("Copyright \251 1991 by Darren Ewaniuk, freely distributable with conditions\n");
  190.         printf ("Usage:  QDCopy <source file pattern> <destination path>\n\n");
  191.         exit (1);
  192.     }
  193.     else                        /* Right number of arguments.  Lets go! */
  194.     {
  195.         /* Open ARP library V39+ */
  196.  
  197.         if (!(ArpBase = (struct ArpBase *) OpenLibrary ("arp.library",39L)))
  198.         {
  199.             printf ("\n\033[33mQDCopy Error:  ARP library V39+ required\033[31m\n\n");
  200.             exit (10);
  201.         }
  202.         /* Make a 'to read' file list */
  203.  
  204.         /* Get memory for anchor path structure including */
  205.         /* a MaxPathNameSize full path name buffer */
  206.  
  207.         if  (!(anchorpath = DosAllocMem (sizeof (struct AnchorPath) + MaxPathNameSize)))
  208.         {
  209.             printf ("\n\033[33mQDCopy Error:  Cannot allocate memory for AnchorPath\033[31m\n\n");
  210.             CloseLibrary (ArpBase);
  211.             exit (10);
  212.         }
  213.  
  214.         /* Initialize anchorpath structure */
  215.  
  216.         anchorpath->ap_BreakBits = 0;       /* Not equipped to handle break */
  217.         anchorpath->ap_StrLen = MaxPathNameSize;    /* Handle full path names */
  218.         anchorpath->ap_Flags = 0;           /* Don't use special features */
  219.  
  220.         /* Initial destination is specified by user */
  221.         /* This might change later when disk error or disk full */
  222.  
  223.         strcpy (destpath, argv[2]);
  224.  
  225.         /* Prompt for source disk */
  226.  
  227.         /* If source pattern is relative to current directory, don't */
  228.         /* bother to prompt for the source disk since its already in use */
  229.         /* or if it isn't, the system knows where it is and can prompt */
  230.         /* for it itself.  */
  231.  
  232.         if (isfullname (argv[1]))
  233.         {
  234.             printf ("\nInsert SOURCE and press RETURN\n");
  235.             inputlength = ReadLine (inputline);
  236.         }
  237.         /* Start FindFirst */
  238.  
  239.         if (!(breaksignal = taskbreak()))
  240.         {
  241.             errorcode = FindFirst (argv[1], anchorpath);
  242.  
  243.             /* Continue searching until an error, break, or no files left */
  244.  
  245.             while ((!errorcode) && (!breaksignal))
  246.             {
  247.                 /* Fill in a QDFileChain block */
  248.  
  249.                 if (fileptr1 = DosAllocMem (sizeof (struct QDFileChain)))
  250.                 {
  251.                     if (anchorpath->ap_Info.fib_DirEntryType < 0)
  252.                     {
  253.                         /* Its a file so add it to the list */
  254.  
  255.                         fileptr1->Next = NULL;
  256.                         fileptr1->FileBuffer = NULL;
  257.                         strcpy (fileptr1->FileName, anchorpath->ap_Buf);
  258.                         fileptr1->Protection = anchorpath->ap_Info.fib_Protection;
  259.                         fileptr1->Size = anchorpath->ap_Info.fib_Size;
  260.                         strcpy (fileptr1->Comment, anchorpath->ap_Info.fib_Comment);
  261.  
  262.                         /* If this is the first, set the head of the list here */
  263.  
  264.                         if (!filehead)
  265.                         {
  266.                             filehead = fileptr1;
  267.                         }
  268.                         else
  269.  
  270.                         /* Link previous item in chain to new header */
  271.                         {
  272.                             fileptr2->Next = fileptr1;
  273.                         }
  274.                         /* Now make this pointer the previous pointer */
  275.  
  276.                         fileptr2 = fileptr1;
  277.                     }
  278.                     else
  279.                     {
  280.                         /* Hey!  This isn't a file!  Don't put it in list */
  281.  
  282.                         DosFreeMem (fileptr1);
  283.                     }
  284.                 }
  285.                 else
  286.                 {
  287.                     /* System is in sorry state if there is no memory for the */
  288.                     /* file structure.  Free memory and leave */
  289.  
  290.                     printf ("\n\033[33mQDCopy Error:  Cannot allocate memory for filename storage\033[31m\n\n");
  291.                     FreeAnchorChain (anchorpath);
  292.                     DosFreeMem (anchorpath);
  293.                     cleanupchain (filehead);
  294.                     CloseLibrary (ArpBase);
  295.                     exit (10);
  296.                 }
  297.                 /* Get ready for next file name */
  298.  
  299.                 breaksignal = taskbreak();
  300.                 errorcode = FindNext (anchorpath);
  301.             }
  302.             /* Now all wildcard files are accounted for */
  303.  
  304.             /* Nuke the structures required by ARP */
  305.  
  306.             FreeAnchorChain (anchorpath);
  307.         }
  308.  
  309.         DosFreeMem (anchorpath);
  310.  
  311.         /* Now read in the files */
  312.  
  313.         while ((filehead) && (!breaksignal))  /* While there are more files to read */
  314.         {
  315.             /* Set up for a new batch read cycle */
  316.  
  317.             /* Prompt for source disk if it was not a relative directory */
  318.             /* Otherwise, the system knows where it is and will prompt itself */
  319.  
  320.             if (memfull && isfullname(argv[1]))
  321.             {
  322.                 printf ("\nInsert SOURCE and press RETURN\n");
  323.                 inputlength = ReadLine (inputline);
  324.             }
  325.             memfull = FALSE;
  326.             fileptr1 = filehead;
  327.  
  328.             /* Batch read files until no files left or memory full */
  329.  
  330.             while ((fileptr1) && (!memfull) && (!(breaksignal = taskbreak())))
  331.             {
  332.                 /* If the file is not empty then copy it */
  333.  
  334.                 if (fileptr1->Size > 0)
  335.                 {
  336.                     /* Get memory for buffer */
  337.  
  338.                     if (fileptr1->FileBuffer = DosAllocMem (fileptr1->Size))
  339.                     {
  340.                         /* Read file */
  341.  
  342.                         if (filehandle = Open (fileptr1->FileName, MODE_OLDFILE))
  343.                         {
  344.                             printf ("Reading %s\n", fileptr1->FileName);
  345.  
  346.                             /* Read the file into the buffer */
  347.  
  348.                             len = Read (filehandle, fileptr1->FileBuffer, fileptr1->Size);
  349.                             Close (filehandle);
  350.                             if (len != fileptr1->Size)
  351.                             {
  352.                                 /* File changed before reading */
  353.                                 /* Clear it from the buffer and ignore it */
  354.  
  355.                                 warncode = 5;
  356.                                 printf ("\033[33m%s not read:  File changed since tested\033[31m\n", fileptr1->FileName);
  357.                                 DosFreeMem (fileptr1->FileBuffer);
  358.                                 fileptr1->FileBuffer = NULL;
  359.                             }
  360.                         }
  361.                         else
  362.                         {
  363.                             /* File was deleted before reading */
  364.                             /* or cannot be opened.  Ignore it */
  365.  
  366.                             warncode = 5;
  367.                             errorcode = IoErr();
  368.                             printf ("\033[33m%s not read:  Error %d opening file\033[31m\n",fileptr1->FileName, errorcode);
  369.                             DosFreeMem (fileptr1->FileBuffer);
  370.                             fileptr1->FileBuffer = NULL;
  371.                         }
  372.                         /* No matter what happened during opening or */
  373.                         /* reading, go on to next file */
  374.                         fileptr1 = fileptr1->Next;
  375.                     }
  376.                     else
  377.                     {
  378.                         /* Out of memory */
  379.  
  380.                         if (fileptr1 == filehead)
  381.                         {
  382.                             /* First file this pass and still too big */
  383.                             /* So skip it */
  384.  
  385.                             warncode = 5;
  386.                             printf ("\033[33m%s not read:  File too big for memory\033[31m\n", fileptr1->FileName);
  387.                             fileptr1 = fileptr1->Next;
  388.                         }
  389.                         else
  390.                         {
  391.                             /* This is not the first file this pass, so */
  392.                             /* start writing and come back to this */
  393.                             /* file on the next pass */
  394.  
  395.                             memfull = TRUE;
  396.                         }
  397.                     }
  398.                 }
  399.                 else    /* File size is zero.  Skip it. */
  400.                 {
  401.                     printf ("\033[33m%s not read:  Blank file\033[31m\n",fileptr1->FileName);
  402.                     fileptr1 = fileptr1->Next;
  403.                 }
  404.             }
  405.  
  406.             /* Now batch write the buffered files to destination */
  407.  
  408.             /* Reset file pointer to first in memory */
  409.  
  410.             fileptr2 = filehead;
  411.  
  412.             /* If destination path is relative to current directory, don't */
  413.             /* bother to prompt for the destination disk since its already */
  414.             /* in use, or if not, the system knows where it is */
  415.  
  416.             if (isfullname (destpath))
  417.             {
  418.                 newdest = TRUE;     /* Drive specified, ask for disk */
  419.             }
  420.             else
  421.             {
  422.                 newdest = FALSE;    /* Don't need to ask for disk */
  423.             }
  424.             while ((fileptr2 != fileptr1) && (!breaksignal))
  425.             {
  426.                 if (fileptr2->FileBuffer != NULL)
  427.                 {
  428.                     if (newdest)
  429.                     {
  430.                         printf ("\nInsert DESTINATION and press RETURN or type new destination path\n");
  431.                         inputlength = ReadLine (inputline);
  432.  
  433.                         /* If user typed something, use it for new path */
  434.  
  435.                         if (inputlength > 1)    /* Anything input? */
  436.                         {
  437.                             strcpy (destpath, inputline);
  438.                         }
  439.                     }
  440.                     if (!(breaksignal = taskbreak()))
  441.                     {
  442.                         newdest = FALSE;
  443.  
  444.                         /* Create destination file name */
  445.  
  446.                         strcpy (pathname, destpath);
  447.                         basename = BaseName (fileptr2->FileName);
  448.                         TackOn (pathname, basename);
  449.  
  450.                         if (filehandle = Open (pathname, MODE_NEWFILE))
  451.                         {
  452.                             /* Write out the destination file */
  453.  
  454.                             printf ("Writing %s\n", pathname);
  455.                             len = Write (filehandle, fileptr2->FileBuffer, fileptr2->Size);
  456.                             errorcode = IoErr();
  457.                             Close (filehandle);
  458.                             if (len != fileptr2->Size)
  459.                             {
  460.                                 /* Error writing file */
  461.  
  462.                                 /* Try to delete file */
  463.  
  464.                                 if (errorcode != ERROR_DISK_FULL)
  465.                                 {
  466.                                     printf ("\033[33mError %d writing %s:", errorcode, pathname);
  467.                                 }
  468.                                 else
  469.                                 {
  470.                                     printf ("\033[33mDisk full writing %s:", pathname);
  471.                                 }
  472.                                 if (DeleteFile (pathname))
  473.                                 {
  474.                                     printf ("  Incomplete file deleted\033[31m\n");
  475.                                 }
  476.                                 else
  477.                                 {
  478.                                     printf ("  Incomplete file not deleted\033[31m\n");
  479.                                 }
  480.  
  481.                                 newdest = TRUE;
  482.                             }
  483.                             else
  484.                             {
  485.                                 /* Successful write */
  486.  
  487.                                 /* Set protection bits */
  488.  
  489.                                 if (!(SetProtection (pathname, fileptr2->Protection)))
  490.                                 {
  491.                                     warncode = 5;
  492.                                     printf ("\033[33m%s protection bits not set\033[31m\n", pathname);
  493.                                 }
  494.                                 /* Set file comment */
  495.  
  496.                                 if (!(SetComment (pathname, fileptr2->Comment)))
  497.                                 {
  498.                                     warncode = 5;
  499.                                     printf ("\033[33m%s comment not set\033[31m\n", pathname);
  500.                                 }
  501.                                 /* Free current file, go to next file */
  502.  
  503.                                 DosFreeMem (fileptr2->FileBuffer);
  504.                                 fileptr2 = fileptr2->Next;
  505.                                 DosFreeMem (filehead);
  506.                                 filehead = fileptr2;
  507.                             }
  508.                         }
  509.                         else
  510.                         {
  511.                             /* Could not open file */
  512.  
  513.                             /* Could be write protected disk, etc. */
  514.  
  515.                             errorcode = IoErr();
  516.                             newdest = TRUE;
  517.  
  518.                             printf ("\033[33mError %d writing %s:  Cannot open file\033[31m\n", errorcode, pathname);
  519.                         }
  520.                     }
  521.                     /* above if not break */
  522.                 }
  523.                 else
  524.                 {
  525.                     /* File is empty or could not be read earlier */
  526.                     /* Just skip it */
  527.  
  528.                     fileptr2 = fileptr2->Next;
  529.                     DosFreeMem (filehead);
  530.                     filehead = fileptr2;
  531.                 }
  532.             }
  533.         }
  534.         cleanupchain (filehead);
  535.  
  536.         if (breaksignal)
  537.         {
  538.             warncode = 6;
  539.         }
  540.  
  541.         if (warncode)
  542.         {
  543.             printf ("\nQDCopy:  Copy not completely successful\n\n");
  544.         }
  545.         else
  546.         {
  547.             printf ("\nQDCopy:  Copy successful\n\n");
  548.         }
  549.         CloseLibrary (ArpBase);
  550.         exit (warncode);
  551.     }
  552. }
  553.