home *** CD-ROM | disk | FTP | other *** search
/ RBBS in a Box Volume 1 #2 / RBBS_vol1_no2.iso / 014r / kopy.zip / KOPY.C next >
Text File  |  1988-02-04  |  13KB  |  376 lines

  1. /*Kopy - Copy or Find and optionally Delete files Everywhere
  2.    by Stephen R. Davis, 1987
  3.       214-454-2426
  4.  
  5.   Search all subdirectories for a particular file pattern.  All files
  6.   found matching that pattern are copied to the target path.  The
  7.   arguments to KOPY are explained in ERRMSG below.
  8.  
  9.   (Note: compiling with the label SWITCH defined in the
  10.          Options/Compiler/Defines menu reverses the sense of
  11.          the "/S" flag for those that prefer it the other way)
  12. */
  13. char *banner = {
  14.   "This program was developed for Borland's Turbo C (Ver 1.0) by \n"
  15.   "Stephen R. Davis for the book:\n\n"
  16.   "                            Turbo C:\n"
  17.   "    The Art of Advanced Program Design, Optimization and Debugging\n"
  18.   "                           M&T Books\n"
  19.   "                       501 Galveston Drive\n"
  20.   "                     Redwood City, CA 94063\n\n"
  21.   "This program is released into the public domain without charge for\n"
  22.   "the use and enjoyment of the public with the single provision that this\n"
  23.   "banner remain intact.  Anyone wishing to learn more about getting the\n"
  24.   "most out of the IBM PC and its clones using Turbo C, can order a copy of\n"
  25.   "this book by calling:\n\n"
  26.   "                        1-800-533-4372\n"
  27.   "                    (in CA, 1-800-356-2002)\n"
  28.   "                       8 am to 5 pm PST\n\n"};
  29.  
  30. #include <stdio.h>
  31. #include <dir.h>
  32. #include <io.h>
  33. #include <dos.h>
  34. #include <process.h>
  35. #include <fcntl.h>
  36. #include <conio.h>
  37. #include <ctype.h>
  38. #include <string.h>
  39. #include <stat.h>
  40.  
  41. #define TRUE 1
  42. #define FALSE 0
  43.  
  44. /*define error message*/
  45. char *errmsg = {
  46.   "This program copies all files from the source path and all\n"
  47.   "of its subdirectories which match the source pattern to the\n"
  48.   "target path.  If no target path is given, the current directory\n"
  49.   "is assumed.  The following switches are defined:\n"
  50.   " /D  - delete after copying/finding (prompts operator for okay)\n"
  51.   " /F  - simply find (do not copy)\n"
  52.   " /S  - search single directory only (no subdirectories)\n"
  53.   " /V  - requests operator verification before continuing\n"
  54.   " /R  - copy to the console (may be redirected with >)\n\n"
  55.   "For example:\n\n"
  56.   "KOPY /D C:\\*.DAT             copy and delete all .DAT files from\n"
  57.   "                             all of the directories on disk C to\n"
  58.   "                             the current directory.\n\n"
  59.   "KOPY /S \\USER\\*.DAT B:\\COPY  copy all the .DAT files from \\USER\n"
  60.   "                             to directory COPY on drive B.\n\n"
  61.   "KOPY /F/D \\*.BAK             find and delete all *.BAK files on\n"
  62.   "                             current disk\n\n"
  63.   "If the target disk fills you will be prompted to insert a new one.\n"
  64.   };
  65.  
  66. /*prototyping definitions*/
  67. void main (unsigned, char **);
  68. void copyall (char *, char *, char *);
  69. void copy (char *, char *);
  70. void find (char *);
  71. void append (char *, char *, char *);
  72. void addslash (char *);
  73. void closefiles (int, int);
  74. void arg_error (void);
  75. int getyval (char *);
  76. int opennew (char *);
  77.  
  78. /*define global flags*/
  79.  
  80. char found_one = FALSE, delete = FALSE, find_only = FALSE;
  81. char verify = FALSE, standardoutput = FALSE;
  82. int thandle, fhandle;
  83.  
  84. char include_subdirs =
  85. #ifdef SWITCH
  86.      FALSE;  /*default subdirectory search to off*/
  87. #else
  88.      TRUE;   /*   "          "        "     " on*/
  89. #endif
  90.  
  91. /*Main - parse user input and start the ball rolling*/
  92. void main (argc, argv)
  93.      unsigned argc;
  94.      char *argv [];
  95. {
  96.      char sourcedisk [MAXDRIVE], sourcedir [MAXDIR];
  97.      char sourcefile [MAXFILE], sourceext [MAXEXT];
  98.      char fromdir [MAXPATH], pattern [MAXFILE+MAXEXT];
  99.      char *secondarg, *switchptr, *srcfile;
  100.  
  101.      /*first check for switches -- ignore case and extra '/'s*/
  102.  
  103.      while (*(switchptr = argv [1]) == '/') {
  104.           while (*++switchptr) {
  105.                switch (tolower (*switchptr)) {
  106.                     case 'd': delete = TRUE;
  107.                               break;
  108.                     case 'f': find_only = TRUE;
  109.                               break;
  110.                     case 's': include_subdirs = !include_subdirs;
  111.                               break;
  112.                     case 'v': verify = TRUE;
  113.                               break;
  114.                     case 'r': standardoutput = TRUE;
  115.                }
  116.           }
  117.  
  118.           /*now skip over this argument*/
  119.           argc--;
  120.           argv [1] = argv [0];
  121.           argv++;
  122.      }
  123.  
  124.      /*check the argument count*/
  125.      if (argc == 1 || argc > 3)
  126.           arg_error ();
  127.  
  128.      /*parse argument 1 into its two halves
  129.       (if no source path given, assume "*.*") */
  130.      fnsplit (argv [1], sourcedisk, sourcedir, sourcefile, sourceext);
  131.      if (!*(srcfile = sourcefile))
  132.           srcfile = "*.*";
  133.  
  134.      /*now reconstruct the two halves*/
  135.      fnmerge (fromdir, sourcedisk, sourcedir,          0,         0);
  136.      fnmerge (pattern,          0,         0,    srcfile, sourceext);
  137.  
  138.      /*if no second argument and not redirected, assume the
  139.        current directory*/
  140.      if (standardoutput) {
  141.           secondarg = " ";
  142.           thandle = fileno (stdout);
  143.      } else {
  144.           if (!(secondarg = argv [2]))
  145.                secondarg = ".\\";
  146.           addslash (secondarg);
  147.      }
  148.  
  149.      /*now just copy/find them everywhere*/
  150.      copyall (fromdir, pattern, secondarg);
  151.      if (!found_one) {
  152.           fprintf (stderr, "No files found");
  153.           if (include_subdirs && (sourcedir [0] != '\\'))
  154.                fprintf (stderr, " (use %s\\%s%s to search entire disk)\n",
  155.                         sourcedisk, sourcefile, sourceext);
  156.           fprintf (stderr, "\n");
  157.      }
  158.  
  159.      /*exit normally*/
  160.      exit (0);
  161. }
  162.  
  163. /*Copyall - copy/find all files matching a given pattern from the
  164.             current directory and all subdirectories*/
  165. void copyall (fromdir, pattern, todir)
  166.      char *fromdir, *pattern, *todir;
  167. {
  168.      char spath [MAXPATH], tpath [MAXPATH];
  169.      struct ffblk block;
  170.  
  171.      /*first copy/find all files patching the pattern*/
  172.      append (spath, fromdir, pattern);
  173.      if (!findfirst (spath, &block, 0))
  174.           do {
  175.                append (spath, fromdir, block.ff_name);
  176.                append (tpath,   todir, block.ff_name);
  177.                if (!find_only)
  178.                     copy (spath, tpath);
  179.                else
  180.                     find (spath);
  181.           } while (!findnext (&block));
  182.  
  183.      /*now check all subdirectories, if desired*/
  184.      if (include_subdirs) {
  185.           append (spath, fromdir, "*.*");
  186.           if (!findfirst (spath, &block, FA_DIREC))
  187.                do {
  188.  
  189.                     /*only pay attention to directories*/
  190.                     if (block.ff_attrib & FA_DIREC)
  191.  
  192.                          /*ignore directories '.' and '..'*/
  193.                          if (block.ff_name [0] != '.') {
  194.  
  195.                               /*now tack on name of directory + '\'*/
  196.                               append (spath, fromdir, block.ff_name);
  197.                               addslash (spath);
  198.  
  199.                               /*and copy its contents too*/
  200.                               copyall (spath, pattern, todir);
  201.                          }
  202.                } while (!findnext (&block));
  203.      }
  204. }
  205.  
  206. /*Copy - given two patterns, copy the source to the destination file*/
  207. #define NSECT 64
  208. void copy (from, to)
  209.      char *from, *to;
  210. {
  211.      int number;
  212.      char buffer [NSECT*512], failure; /* I find this gives an error.  replacing */
  213.          /* it with the (supposedly) equivalent [32768] compiles properly, */
  214.          /* though I haven't tested the functionality yet.  If you know why */
  215.          /* please send me email letting me know. */
  216.          /* BTW, I am Grant Prellwitz.    76474,2121 on CIS, ID1694 on Plantz */
  217.          /*   and ...!ihnp4!gargoyle!sphinx!pre1 on Usenet */
  218.  
  219.      /*don't copy a file to itself*/
  220.      if (!stricmp (to, from))
  221.           return;
  222.      found_one = TRUE;
  223.  
  224.      do {
  225.           /*check for verification before copying*/
  226.           fprintf (stderr, "\nCopying %s -> %s", from, to);
  227.           if (verify)
  228.                if (!getyval (" - copy?"))
  229.                     return;
  230.  
  231.           /*open the source for reading binary*/
  232.           _fmode = O_BINARY;
  233.           if ((fhandle = open (from, O_RDONLY)) == -1) {
  234.                perror ("\nError opening source file");
  235.                return;
  236.           }
  237.  
  238.           /*now open the destination, if not standard output*/
  239.           if (!standardoutput)
  240.                if ((thandle = opennew (to)) == -1) {
  241.                     if (!getyval (" - overwrite target?")) {
  242.                          close (fhandle);
  243.                          return;
  244.                     }
  245.                     if ((thandle = open (to, O_RDWR + O_TRUNC,
  246.                                          S_IWRITE)) == -1) {
  247.                          perror ("\nError opening target file");
  248.                          return;
  249.                     }
  250.                }
  251.  
  252.           /*now perform the copy*/
  253.           failure = FALSE;
  254.           while (number = read (fhandle, buffer, NSECT*512))
  255.                if (number != _write (thandle, buffer, number))
  256.                     if (!standardoutput) {
  257.  
  258.                          /*disk full, close source and delete target*/
  259.                          closefiles (fhandle, thandle);
  260.                          unlink (to);
  261.                          getyval ("\nDisk full - "
  262.                                   "insert new disk and hit any key");
  263.                          failure = TRUE;
  264.                          break;
  265.                     }
  266.      } while (failure);
  267.      fprintf (stderr, " - copied");
  268.      closefiles (fhandle, thandle);
  269.  
  270.      /*delete source, if requested*/
  271.      if (delete)
  272.           if (getyval (" - delete source?"))
  273.                unlink (from);
  274. }
  275.  
  276. /*Find - in case of find, ask user permission to delete file if
  277.          "/d" switch and whether we should continue if verify enabled*/
  278. void find (fname)
  279.      char *fname;
  280. {
  281.      found_one = TRUE;
  282.      printf ("\nFound %s", fname);
  283.      if (delete)
  284.           if (getyval (" - delete?"))
  285.                if (unlink (fname))
  286.                     perror ("\nError on delete");
  287.  
  288.      if (verify)
  289.           if (!getyval (" - continue?"))
  290.                exit (0);
  291. }
  292.  
  293. /*Append - concatenate two strings together*/
  294. void append (to, from1, from2)
  295.      char *to, *from1, *from2;
  296. {
  297.      /*copy the first string*/
  298.      while (*from1)
  299.           *to++ = *from1++;
  300.  
  301.      /*now the second*/
  302.      while (*from2)
  303.           *to++ = *from2++;
  304.  
  305.      /*and then tack on a terminator*/
  306.      *to = '\0';
  307. }
  308.  
  309. /*Addslash - add a slash onto a directory name which doesn't
  310.              already end in '\' or ':'*/
  311. void addslash (dirptr)
  312.      char *dirptr;
  313. {
  314.      /*skip to next to last character in path*/
  315.      while (*dirptr)
  316.           dirptr++;
  317.      dirptr--;
  318.  
  319.      /*now check last character*/
  320.      if (*dirptr != '\\' && *dirptr != ':') {
  321.           *++dirptr = '\\';
  322.           *++dirptr = '\0';
  323.      }
  324. }
  325.  
  326. /*closefiles - close the source and, if not stdout, the target*/
  327. void closefiles (fhandle, thandle)
  328.      int fhandle, thandle;
  329. {
  330.      close (fhandle);
  331.      if (!standardoutput)
  332.           close (thandle);
  333. }
  334.  
  335. /*Opennew - use creatnew() to create a new file.  Since this system
  336.             call is not present under DOS 2.x, its function must
  337.             be emulated by normal open() calls.*/
  338. int opennew (name)
  339.      char *name;
  340. {
  341.      int handle;
  342.  
  343.      if (_osmajor >= 3)
  344.           return creatnew (name, 0);
  345.  
  346.      if ((handle = open (name, O_RDONLY)) != -1) {
  347.           close (handle);
  348.           return -1;
  349.      }
  350.      return open (name, O_RDWR + O_CREAT, S_IWRITE);
  351. }
  352.  
  353. /*Arg_error - print error message and then abort*/
  354. void arg_error (void)
  355. {
  356.      printf (errmsg);
  357.      if (!include_subdirs)
  358.           printf ("(Note: This version has the meaning of the "
  359.                   "/S switch inverted.)");
  360.      getyval ("\nEnter any key to continue");
  361.      printf ("\n\n\n\n\n\n\n%s", banner);
  362.      exit (1);
  363. }
  364.  
  365. /*Getyval - out a string and then await a response.
  366.             Exit program if Break (Control-C).  Return a 1
  367.             if entered 'y', else 0*/
  368. int getyval (msg)
  369.      char *msg;
  370. {
  371.      char entered;
  372.  
  373.      fprintf (stderr, msg);
  374.      if ((entered = getch ()) == 0x03) exit (1);
  375.      return (tolower (entered) == 'y');
  376. }