home *** CD-ROM | disk | FTP | other *** search
/ The Developer Connection…ice Driver Kit for OS/2 3 / DEV3-D1.ISO / source / util2src / ccp.c32 < prev    next >
Encoding:
Text File  |  1992-09-22  |  37.0 KB  |  855 lines

  1. /*============================================================================*
  2.  * main() module: ccp.c - Conditional copy command - OS/2 2.0 version.
  3.  *
  4.  * (C)Copyright IBM Corporation, 1991, 1992.              Brian E. Yoder
  5.  *
  6.  * This program conditionally copies (based on size, modification time
  7.  * and date, and an optional set of flags) source files to a target
  8.  * directory.  See ccp.doc for more information.
  9.  *
  10.  * This DOS version of the program allocates a buffer to use during a file
  11.  * copy.  The OS/2 version uses the DosCopy() subroutine, which (I suppose)
  12.  * supplies its own copy buffer.
  13.  *
  14.  * 05/11/91 - Created, using crc.c as a template.
  15.  * 05/19/91 - Version 1.0 - Initial DOS version completed.
  16.  * 05/20/91 - Version 1.0 - Ported to initial OS/2 version.  The fcopy()
  17.  *            subroutine in this module uses DosCopy() to copy a file.
  18.  *            Also, the OS/2 file information structure defines the time
  19.  *            and date as a bit record and not as a ushort, so the Fdate and
  20.  *            Ftime fields must be handled differently than on DOS.
  21.  * 01/11/92 - Version 1.1 - Add support for -f flag: force the target to
  22.  *            be overwritten if it is readonly.
  23.  * 03/26/92 - Version 1.2 - If there's only one source file specification,
  24.  *            the target directory defaults to . (the current directory).
  25.  * 07/24/92 - Version 1.2 - For OS/2 2.0 and C Set/2.
  26.  * 09/21/92 - Version 1.3 - Supports the -s flag to copy subdirectories.
  27.  *            Also supports the -t flag to list the target as well as source.
  28.  *============================================================================*/
  29.  
  30. static char ver[]  = "ccp: version 1.3";
  31. static char copr[] = "(c)Copyright IBM Corporation, 1992.  All rights reserved.";
  32.  
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <memory.h>
  36. #include <string.h>
  37. #include <malloc.h>
  38. #include <sys/types.h>
  39.  
  40. #include <sys/stat.h>               /* Used by open(), etc. */
  41. #include <fcntl.h>
  42. #include <io.h>
  43.  
  44. #include "util.h"
  45.  
  46. #define CCP_DIFFERENT 0             /* Copy if source is different than target */
  47. #define CCP_LATER     1             /* Copy if source is later than target */
  48.  
  49. #define CPE_FULL      1             /* Error codes from fcopy() */
  50. #define CPE_OTHER     2
  51. #define CPE_MKDIR     3             /* Error if we can't make a directory */
  52.  
  53. static USHORT attrib =              /* Set up attribute for findfirst */
  54.            _A_NORMAL  |
  55.            _A_RDONLY  |                   /* These labels are from <dos.h> */
  56.            _A_HIDDEN  |
  57.            _A_SYSTEM  |
  58.         /* _A_VOLID   |  */               /* OS/2 doesn't support _A_VOLID */
  59.            _A_SUBDIR  |
  60.            _A_ARCH;
  61.  
  62. /* Not needed if we're using DosCopy() */
  63. #define CPLEN_1  32000              /* Copy buffer length: 1st choice */
  64. #define CPLEN_2  2048               /*                     2nd choice */
  65.  
  66. #define XLEN     2048               /* Total length of compiled reg expressions */
  67. static  char     xsrcbuff[XLEN];    /* Buffer to hold compiled regular expressions */
  68.  
  69. #define ELEN     4096               /* Length of expression/filename buffer */
  70. static  char     buff[ELEN+1];      /* Buffer for output filenames and expansions */
  71.  
  72. /*============================================================================*
  73.  * Full prototypes for private (static) functions
  74.  *============================================================================*/
  75.  
  76. static void       syntax       ( void );
  77. static int        excludef     ( char *, int, char ** );
  78. static int        copyit       ( char *, ulong, ushort, ushort, ushort,
  79.                                  char *, int, int );
  80. static int        fcopy        ( char *, ushort, ushort, ushort, char *, int );
  81.  
  82. /*============================================================================*
  83.  * Main Program Entry Point
  84.  *============================================================================*/
  85.  
  86. main(argc, argv)
  87.  
  88. int argc;                           /* arg count */
  89. char *argv[];                       /* arg pointers */
  90.  
  91. {
  92.   int     rc;                       /* Return code storage */
  93.   char   *str;                      /* Pointer to string */
  94.   long    lrc;                      /* Long return code */
  95.   char   *flagstr;                  /* Pointer to string of flags */
  96.  
  97.   char   *tdir;                     /* Pointer to target directory name */
  98.   uint    tlen;                     /* Length of target directory name */
  99.  
  100.   int     srcc;                     /* Count and pointer to array of */
  101.   char  **srcv;                     /* source file specifications */
  102.  
  103.   int     xsrc;                     /* Count and pointer to array of */
  104.   char  **xsrv;                     /* xsource (exclusion) file specifications */
  105.   PATH_NAME *pn;                    /* Pointer returned by decompose() */
  106.  
  107.   int     cnt;                      /* General count */
  108.   char  **charv;                    /* General character pointer vector */
  109.   char   *next_eexpr;               /* Pointer returned by rexpand() */
  110.   char   *xsrccurr;                 /* Current pointer within xsrcbuff[] */
  111.   char   *xsrcnext;                 /* Pointer returned by rcompile() */
  112.  
  113.   int     uniq;                     /* 'uniq' flag for slmake() */
  114.   SLPATH *speclist;                 /* Pointer to linked list of path specs */
  115.   ushort  mflags;                   /* Match flags for slrewind() */
  116.   ushort  recurse;                  /* Recursive directory descent? */
  117.  
  118.   FINFO  *fdata;                    /* Pointers returned by slmatch() */
  119.   SLPATH *pdata;
  120.   SLNAME *ndata;
  121.  
  122.   char   *sourcename;               /* Pointers to name strings */
  123.   char   *targetname;
  124.   char   *basename;
  125.   uint    sourcelen;                /* And the lengths of these strings */
  126.   uint    targetlen;
  127.   uint    baselen;
  128.  
  129.   ushort  sdate;                    /* Source file's time/date */
  130.   ushort  stime;
  131.  
  132.   int     ccopy;                    /* Conditional copy: different/later/etc. */
  133.   int     mustexist;                /* Must target file exist before copying? */
  134.   int     copyfiles;                /* Actually perform the copy? TRUE/FALSE */
  135.   int     showx;                    /* Show names of files excluded (not copied)? */
  136.   int     force;                    /* Force readonly files to be overwritten? */
  137.   int     showtarget;               /* Show target as well as source? */
  138.  
  139.   ulong   copycnt = 0L;             /* No. of files copied */
  140.  
  141. /*----------------------------------------------------------------------------*
  142.  * Set initial values of flags:
  143.  *----------------------------------------------------------------------------*/
  144.  
  145.   uniq      = TRUE;                 /* Build SLPATHs only for unique paths */
  146.   recurse   = FALSE;                /* Don't descend subdirectories */
  147.   ccopy     = CCP_DIFFERENT;        /* Copy if source is different than target */
  148.   mustexist = FALSE;                /* Target file doesn't have to exist */
  149.   copyfiles = TRUE;                 /* Yes, we want to copy files */
  150.   showx     = FALSE;                /* Don't show names of excluded files */
  151.   force     = FALSE;                /* No, don't overwrite readonly target files */
  152.   showtarget= FALSE;                /* No, just show source filenames */
  153.  
  154. /*----------------------------------------------------------------------------*
  155.  * Be sure we have at least one argument:
  156.  *----------------------------------------------------------------------------*/
  157.  
  158.   argc--;                           /* Ignore 1st argument (program name) */
  159.   argv++;
  160.  
  161.   if (argc <= 0) syntax();          /* If no arguments: Display syntax */
  162.  
  163.  /*---------------------------------------------------------------------------*
  164.   * Process flags, if any
  165.   *---------------------------------------------------------------------------*/
  166.  
  167.   flagstr = *argv;                  /* Point 'flagstr' to argument */
  168.   if (*flagstr == '-')              /* If it begins with '-': It's a list of flags */
  169.   {
  170.      flagstr++;                          /* Point past the dash */
  171.  
  172.      while (*flagstr != '\0')            /* For each character in flag string: */
  173.      {
  174.         switch (*flagstr)
  175.         {
  176.            case 'l':
  177.            case 'L':
  178.               ccopy = CCP_LATER;              /* Copy if source is later than target */
  179.               break;
  180.  
  181.            case 'e':
  182.            case 'E':
  183.               mustexist = TRUE;               /* Target file must exist before copying */
  184.               break;
  185.  
  186.            case 'n':
  187.            case 'N':
  188.               copyfiles = FALSE;              /* Don't copy any files */
  189.               break;
  190.  
  191.            case 'x':
  192.            case 'X':
  193.               showx = TRUE;                   /* Show files excluded (not copied) */
  194.               break;
  195.  
  196.            case 'f':
  197.            case 'F':
  198.               force = TRUE;                   /* Force overwriting readonly files */
  199.               break;
  200.  
  201.            case 'g':                          /* 'g' means group in order that */
  202.            case 'G':                          /* filespecs were listed on cmd line */
  203.               uniq = FALSE;
  204.               break;
  205.  
  206.            case 's':                          /* 's' means recurse subdirectories */
  207.            case 'S':
  208.               recurse = TRUE;
  209.               break;
  210.  
  211.            case 't':                          /* 't' means show target filenames */
  212.            case 'T':
  213.               showtarget = TRUE;
  214.               break;
  215.  
  216.            default:
  217.               fprintf(stderr, "Invalid flag '%c'.  For help, enter command with no arguments.\n",
  218.                  *flagstr);
  219.               exit(2);
  220.               break;
  221.         }
  222.         flagstr++;                            /* Check next character */
  223.      }
  224.  
  225.      argc--;                             /* Done with flags: Discard them */
  226.      argv++;
  227.   }
  228.  
  229.  /*---------------------------------------------------------------------------*
  230.   * Store pointer to the name of the target directory, and its length
  231.   *---------------------------------------------------------------------------*/
  232.  
  233.   if (argc <= 0) syntax();          /* If no arguments: Display syntax */
  234.  
  235.   if (argc == 1)                    /* If only one argument: */
  236.   {                                      /* Assume it's a source filespec */
  237.      tdir = ".";                         /* Assume target is current directory */
  238.   }
  239.   else                              /* Else: last argument is target directory */
  240.   {
  241.      tdir = argv[argc-1];                /* Point to last argument: target dir */
  242.      argc--;                             /* Decrement arg count to exclude last arg */
  243.   }
  244.  
  245.   tlen = strlen(tdir);              /* Store length of target directory */
  246.  
  247.  /*---------------------------------------------------------------------------*
  248.   * Find out how many source file specifications we have (at least one needed)
  249.   *---------------------------------------------------------------------------*/
  250.  
  251.   srcc = 0;                         /* Initialize to no source specs */
  252.   srcv = argv;                      /* Point source spec vector to 1st arg */
  253.  
  254.   while (argc > 0)                  /* For each argument: */
  255.   {
  256.      if ((*argv)[0] == '!')             /* If we found a !: */
  257.         break;                               /* The break out of loop */
  258.      srcc++;                            /* We have a source spec: Update count */
  259.      argc--;                            /* Decrement no. of arguments left */
  260.      argv++;                            /* And point to next argument */
  261.   }
  262.  
  263.   if (srcc <= 0)                    /* If no source file specs: Error */
  264.   {
  265.      fprintf(stderr, "ccp: Source file specification(s) are missing.\n");
  266.      return(2);
  267.   }
  268.  
  269.  /*---------------------------------------------------------------------------*
  270.   * Find out how many xsource (exclusion) file specifications we have.
  271.   * If we broke out of the previous loop because of a !, then we may have
  272.   * xsource specs.  We allow the ! and the first xsource spec to either
  273.   * be part of the same argument or be in separate arguements (i.e. we
  274.   * allow: '!*.exe' and '! *.exe').
  275.   *---------------------------------------------------------------------------*/
  276.  
  277.   xsrc = 0;                         /* Assume no xsource specs, then: */
  278.  
  279.   if ( (argc >= 1) &&               /* If there's at least one arg left, */
  280.      ( (*argv)[0] == '!') )         /* and it is a !, then: */
  281.   {                                 /* We have xsource specifications: */
  282.      if ((*argv)[1] != '\0')             /* If ! is not by itself: */
  283.      {                                        /* Then rest of arg is an xsource */
  284.         xsrc = 1;                             /* So we have at least one xsource */
  285.         xsrv = argv;                          /* Point xsrv to current argv */
  286.         (*xsrv)++;                            /* And bump its pointer past the ! */
  287.      }
  288.      else                                /* Else: the ! is by itself: */
  289.         xsrv = argv + 1;                      /* xsrv vector starts at next arg */
  290.  
  291.      argc--;                             /* Decrement arg count */
  292.      argv++;                             /* And point to next argument */
  293.  
  294.      while (argc > 0)                    /* For each argument left: */
  295.      {
  296.         xsrc++;                               /* It's an xsource spec */
  297.         argc--;                               /* Decrement arg count */
  298.         argv++;                               /* And point to next argument */
  299.      }
  300.  
  301.      if (xsrc == 0)                      /* If we have no xsource (but found a !): */
  302.      {                                        /* Error! */
  303.         fprintf(stderr, "ccp: Found ! but there are no xsource specifications.\n");
  304.         return(2);
  305.      }
  306.   }
  307.  
  308.  /*---------------------------------------------------------------------------*
  309.   * TEST: Display source, xsource, and target specifications
  310.   *---------------------------------------------------------------------------*/
  311.  
  312. //printf("\n");
  313. //printf("Target directory: '%s'\n", tdir);
  314. //
  315. //printf("Source specs:\n");
  316. //cnt = srcc;
  317. //charv = srcv;
  318. //while (cnt > 0)
  319. //{
  320. //   printf("   '%s'\n", *charv);
  321. //   cnt--;
  322. //   charv++;
  323. //}
  324. //
  325. //printf("Xsource specs:\n");
  326. //cnt = xsrc;
  327. //charv = xsrv;
  328. //while (cnt > 0)
  329. //{
  330. //   printf("   '%s'\n", *charv);
  331. //   cnt--;
  332. //   charv++;
  333. //}
  334. //
  335. //printf("\n");
  336. //exit(0);
  337.  
  338.  /*---------------------------------------------------------------------------*
  339.   * Be sure that the target directory exists
  340.   *---------------------------------------------------------------------------*/
  341.  
  342.   if (!isdir(tdir))
  343.   {
  344.      fprintf(stderr, "ccp: '%s' is not a valid target directory.\n", tdir);
  345.      return(2);
  346.   }
  347.  
  348.  /*---------------------------------------------------------------------------*
  349.   * Expand all xsource file specifications into regular expressions and compile
  350.   * While we're at it, be sure that none has any drive or path information.
  351.   *
  352.   * Each xsource spec is expanded into a regular expression and stored in
  353.   * the 'xsrcbuff' buffer for compiling.  The compiled regular expressions
  354.   * are stored back-to-back in the 'xsrcbuff' buffer.
  355.   *
  356.   * As each xsource spec is processed, the xsource pointer in the 'xsrv' array
  357.   * is overwritten with a pointer to its compiled regular expression in the
  358.   * buffer.
  359.   *---------------------------------------------------------------------------*/
  360.  
  361.   cnt = xsrc;                       /* Set count to no. of xsource specs */
  362.   charv = xsrv;                     /* And set up vector pointer to 1st one */
  363.   xsrccurr = xsrcbuff;              /* Point xsrccurr to start of buffer */
  364.  
  365.   while (cnt > 0)                   /* For each xsource spec: */
  366.   {
  367.      pn = decompose(*charv);             /* Check for d:path within it */
  368.      if (pn->pathlen != 0)               /* If xsource spec contains d:path: */
  369.      {                                        /* Error! */
  370.         fprintf(stderr, "ccp: !xsource '%s' contains a drive and/or path.\n", *charv);
  371.         return(2);
  372.      }
  373.  
  374.      rc = rexpand(*charv, buff,          /* Expand it into a regular expression */
  375.                   &buff[ELEN+1], &next_eexpr);
  376.      if (rc != 0)
  377.      {
  378.         fprintf(stderr, "ccp: !xsource specification is too long: '%s'\n", *charv);
  379.         return(2);
  380.      }
  381.  
  382.      strupr(buff);                       /* Convert spec to upper case */
  383.      rc = rcompile(buff, xsrccurr,       /* Compile the regular expression */
  384.                    &xsrcbuff[XLEN+1], '\0',  /* rcompile() updates xsrcnext to */
  385.                    &xsrcnext);               /* point to where next one will be stored */
  386.      if (rc != 0)
  387.      {
  388.         fprintf(stderr, "ccp: !xsource specification is not valid: '%s'\n", *charv);
  389.         return(2);
  390.      }
  391.  
  392.      *charv = xsrccurr;                  /* Overwrite with pointer to compiled expr */
  393.      xsrccurr = xsrcnext;                /* And update past compiled expression */
  394.  
  395.      cnt--;                              /* And process next xsource spec */
  396.      charv++;
  397.   }
  398.  
  399.  /*---------------------------------------------------------------------------*
  400.   * Process source file specifications and build specification list
  401.   *---------------------------------------------------------------------------*/
  402.  
  403.   rc = slmake(&speclist, uniq, TRUE, srcc, srcv);
  404.  
  405.   if (rc != 0)                      /* If there was an error: */
  406.   {                                 /* Analyze rc, show msg, and return */
  407.      if (rc == REGX_MEMORY)
  408.         fprintf(stderr, "ccp: Out of memory while processing '%s'.\n",
  409.            slerrspec());
  410.      else
  411.         fprintf(stderr, "ccp: source specification is not valid: '%s'.\n",
  412.            slerrspec());
  413.  
  414.      return(2);
  415.   }
  416.  
  417.  /*---------------------------------------------------------------------------*
  418.   * If we aren't going to actually copy any files, say so now!
  419.   *---------------------------------------------------------------------------*/
  420.  
  421.   if (!copyfiles)
  422.   {
  423.      fprintf(stderr, "ccp: *** No files will actually be copied ***\n");
  424.      fflush(stderr);
  425.   }
  426.  
  427.  /*---------------------------------------------------------------------------*
  428.   * Conditionally copy each matching source file in the specification list
  429.   *---------------------------------------------------------------------------*/
  430.  
  431.   mflags = 0;                       /* Set list of files to match to include: */
  432.   mflags = mflags | SL_NORMAL;           /* Ordinary files only */
  433.  
  434.   slrewind(speclist, mflags, recurse);/* Initialize slmatch() */
  435.   for (;;)                          /* Loop to find all matching files: */
  436.   {
  437.     /*-----------------------------------------------------*
  438.      * Get next matching file, if any
  439.      *-----------------------------------------------------*/
  440.  
  441.      fdata = slmatch(&pdata,             /* Get next matching file */
  442.                      &ndata);
  443.      if (fdata == NULL)                  /* If none: */
  444.         break;                                /* Done */
  445.  
  446.     /*-----------------------------------------------------*
  447.      * Before we store names in buff[], be sure they will
  448.      * fit by calculating the approx. max lengths of names.
  449.      * Lengths are approx. at first, since we don't know
  450.      * if we need a path separator.  Later, we'll find the
  451.      * exact lengths, after calling pathcat().
  452.      *-----------------------------------------------------*/
  453.  
  454.      baselen = strlen(fdata->Fname);     /* Calculate true length of base name */
  455.  
  456.      sourcelen = strlen(pdata->path) + baselen + 1;  /* approx. */
  457.      targetlen = strlen(tdir) + baselen + 1;         /* approx. */
  458.  
  459.      if (recurse)
  460.         targetlen += sourcelen - baselen + 1;        /* very approx. */
  461.  
  462.      if ((baselen + sourcelen + targetlen + 3) > ELEN)
  463.      {                                   /* Add 3 for the null terminators! */
  464.         fprintf(stderr, "ccp: Internal error: Names are too long.\n");
  465.         return(2);
  466.      }
  467.  
  468.     /*-----------------------------------------------------*
  469.      * Store names in the buff[] buffer, as 3 strings:
  470.      *    sourcename,0    Full pathname of source file
  471.      *    targetname,0    Full pathname of target file
  472.      *    basename,0      Uppercase filename portion
  473.      *-----------------------------------------------------*/
  474.  
  475.      sourcename = buff;                  /* Store full path+name of source */
  476.      strcpy(sourcename, pdata->path);
  477.      pathcat(sourcename, fdata->Fname);
  478.      sourcelen = strlen(sourcename);          /* And store its true length */
  479.  
  480.      targetname = sourcename +           /* Store full path+name of target */
  481.                   sourcelen + 1;
  482.      strcpy(targetname, tdir);
  483.  
  484.      if (recurse)                        /* If recursing subdirectories: */
  485.      {
  486.         str = pdata->path +                   /* Point str past base portion */
  487.              pdata->bpathlen;                 /* of the path */
  488.         if (*str == '\\') str++;              /* Bump past path separator, if any */
  489.  
  490.         pathcat(targetname, str);             /* And add the recursed subdir's name */
  491.      }                                        /* to the target path */
  492.  
  493.      pathcat(targetname, fdata->Fname);
  494.      targetlen = strlen(targetname);          /* And store its true length */
  495.  
  496.      basename = targetname +             /* Store upper-case base name */
  497.                 targetlen + 1;
  498.      strcpy(basename, fdata->Fname);
  499.      strupr(basename);
  500.  
  501.     /*-----------------------------------------------------*
  502.      * TEST: Display name strings
  503.      *-----------------------------------------------------*/
  504. /*
  505.      printf("Copy from: '%s'\n", sourcename);
  506.      printf("Copy to:   '%s'\n", targetname);
  507.      printf("Base name: '%s'\n", basename);
  508.      printf("\n");
  509. */
  510.     /*-----------------------------------------------------*
  511.      * Compare basename against compiled xsource expressions
  512.      * to see if we should exclude this source file
  513.      *-----------------------------------------------------*/
  514.  
  515.      if (excludef(basename, xsrc, xsrv)) /* If we are to exclude this file: */
  516.      {
  517.         if (showx)                            /* If we are to display its name: */
  518.         {
  519.            printf("! %s\n", sourcename);           /* Display its name */
  520.            fflush(stdout);
  521.         }
  522.      }
  523.      else                                /* Else: user didn't exclude file: */
  524.      {
  525.          /*--------------------------------------------*
  526.           * Check to see if we should copy this file
  527.           *--------------------------------------------*/
  528.           memcpy(&sdate,                      /* Store source file's date/time */
  529.                  &fdata->fdateLastWrite,
  530.                  sizeof(ushort));
  531.           memcpy(&stime,
  532.                  &fdata->ftimeLastWrite,
  533.                  sizeof(ushort));
  534.           if (copyit(sourcename,              /* If the file should be copied: */
  535.                      fdata->Fsize,
  536.                      sdate, /*fdata->Fdate,*/
  537.                      stime, /*fdata->Ftime,*/
  538.                      fdata->Fmode,
  539.                      targetname,
  540.                      mustexist,
  541.                      ccopy))
  542.           {
  543.              if (!showtarget)                      /* Display either: */
  544.                 printf("%s\n", sourcename);             /* Just the source */
  545.              else                                  /* or: */
  546.                 printf("%s -> %s\n", sourcename,        /* Both source and target */
  547.                                      targetname);
  548.              fflush(stdout);
  549.              rc = 0;                               /* Init rc to zero */
  550.              if (copyfiles)                        /* If we are to perform the copy: */
  551.              {
  552.                 if (recurse)                            /* If recursing subdirs: */
  553.                 {
  554.                    rc = makepath(targetname);                /* We might need to make */
  555.                    if (rc != 0)                              /* them in the target dir */
  556.                       rc = CPE_MKDIR;
  557.                 }
  558.  
  559.                 if (rc == 0)                            /* If no errors so far: */
  560.                 {
  561.                   rc = fcopy(sourcename,                  /* Perform the copy */
  562.                              sdate,
  563.                              stime,
  564.                              fdata->Fmode,
  565.                              targetname,
  566.                              force);
  567.                 }
  568.  
  569.                 switch (rc)                             /* Check return code from copy: */
  570.                 {
  571.                    case 0:                                   /* If ok: */
  572.                       break;                                      /* Keep going */
  573.                    case CPE_FULL:                            /* If target is full: */
  574.                       fflush(stdout);                             /* Display error msg */
  575.                       fprintf(stderr, "ccp: Target is full when copying to %s\n",
  576.                          targetname);
  577.                       fflush(stderr);
  578.                       return(2);                                  /* Return: can't copy if full */
  579.                       break;
  580.                    case CPE_MKDIR:                           /* If we can't make a dir: */
  581.                       fflush(stdout);                             /* Display error msg */
  582.                       fprintf(stderr, "ccp: Can't make a directory within %s\n",
  583.                          targetname);
  584.                       fflush(stderr);
  585.                       break;
  586.                    default:                                  /* If other error: */
  587.                       fflush(stdout);
  588.                       fprintf(stderr, "ccp: Error while copying to %s\n",
  589.                          targetname);
  590.                       fflush(stderr);
  591.                       break;
  592.                 } /* end of switch stmt to process fcopy() return code */
  593.              } /* end of 'if (copyfiles)' */
  594.  
  595.              if (rc == 0) copycnt++;               /* Update count of files copied */
  596.  
  597.           } /* end of 'if the file should be copied */
  598.           else                                /* Else: ccp says "don't copy file": */
  599.           {
  600.              if (showx)                            /* If we are to display its name: */
  601.              {
  602.                 printf("x %s\n", sourcename);           /* Display its name */
  603.                 fflush(stdout);
  604.              }
  605.           } /* end of check to see if file should be copied */
  606.      } /* end of check to see if user wants to exclude this file */
  607.   } /* end of loop to find all matching files */
  608.  
  609.  /*---------------------------------------------------------------------------*
  610.   * Display (on stderr) all source filespecs that had no matching files
  611.   *---------------------------------------------------------------------------*/
  612.  
  613.   lrc = slnotfound(speclist);       /* Display path\names w/no matching files */
  614.   if (lrc == 0L)                    /* If all fspecs were matched: */
  615.      rc = 0;                             /* Setup for return successfully */
  616.   else                              /* Otherwise:  One or more not found: */
  617.      rc = 2;                             /* Setup for return with error */
  618.  
  619.  /*---------------------------------------------------------------------------*
  620.   * Display (on stdout) how many files we copied
  621.   *---------------------------------------------------------------------------*/
  622.  
  623.   fflush(stdout);                   /* First flush any stdout filenames */
  624.   fprintf(stderr, "%lu file(s) copied.\n", copycnt);
  625.  
  626.   return(rc);                       /* Return with proper exit code */
  627.  
  628. } /* end of main() */
  629.  
  630. /*============================================================================*
  631.  * syntax() - Display command syntax and exit to operating system!
  632.  *============================================================================*/
  633. static void syntax()
  634. {
  635.   fprintf(stderr, "%s\n", ver);
  636.   fprintf(stderr, "Usage: ccp [-flags] source ... [! Xsource ...] targetdir\n");
  637.   fprintf(stderr, "\n");
  638.   fprintf(stderr, "The ccp program conditionally copies files that match the source file\n");
  639.   fprintf(stderr, "specification(s), excluding those whose names match the optional Xsource\n");
  640.   fprintf(stderr, "file specification(s), to the target directory. Source files are copied if\n");
  641.   fprintf(stderr, "they don't exist in the target directory or if they have a different time,\n");
  642.   fprintf(stderr, "date, or size in the target directory. The following flags are supported:\n");
  643.   fprintf(stderr, "\n");
  644.   fprintf(stderr, "  l  If a copy of the source file exists in the target directory, copy the\n");
  645.   fprintf(stderr, "     source file only if it is later than the one in the target directory.\n");
  646.   fprintf(stderr, "\n");
  647.   fprintf(stderr, "  e  Don't copy a source file that doesn't already exist in the\n");
  648.   fprintf(stderr, "     target directory.\n");
  649.   fprintf(stderr, "\n");
  650.   fprintf(stderr, "  f  Force copy even if target file is read-only.\n");
  651.   fprintf(stderr, "\n");
  652.   fprintf(stderr, "  n  Don't copy any files; just list the names of the files that\n");
  653.   fprintf(stderr, "     would have been copied.\n");
  654.   fprintf(stderr, "\n");
  655.   fprintf(stderr, "  s  Descend subdirectories and preserve them in the target directory.\n");
  656. //fprintf(stderr, "\n");
  657. //fprintf(stderr, "  t  Show the names of each target filename as well as each source filename.\n");
  658.   fprintf(stderr, "\n");
  659.   fprintf(stderr, "  x  Also list the names of files that are being excluded (not copied).\n");
  660.   exit(1);
  661. }
  662.  
  663. /*============================================================================*
  664.  * excludef() - Should we exclude the file?
  665.  *
  666.  * REMARKS:
  667.  *   This subroutine compares the base name of a file to a list of compiled
  668.  *   regular expressions.
  669.  *
  670.  * RETURNS:
  671.  *   TRUE: If the file matches one of the regular expressions: Exclude it!
  672.  *   FALSE: If the file matches none of the regular expressions.
  673.  *============================================================================*/
  674.  
  675. static int excludef(
  676.  
  677. char    *name ,                     /* Uppercase version of base filename */
  678. int      regc ,                     /* No. of regular expressions */
  679. char   **regv )                     /* Pointer to array of regular expressions */
  680.  
  681. {
  682.   while (regc > 0)                  /* For each expression in array: */
  683.   {
  684.      if (rmatch(*regv, name) == 0)       /* If we found a match: */
  685.         return(TRUE);                         /* Return TRUE */
  686.      regc--;                             /* Else try next expression */
  687.      regv++;
  688.   }
  689.  
  690.   return(FALSE);                    /* We matched none of the expressions */
  691. }
  692.  
  693. /*============================================================================*
  694.  * copyit() - Should we copy the file?
  695.  *
  696.  * REMARKS:
  697.  *   This subroutine compares source file with the target file (if it exists),
  698.  *   checks the flags passed to it, and determines whether or not we should
  699.  *   copy the file.
  700.  *
  701.  * RETURNS:
  702.  *   TRUE: If the file should be copied.
  703.  *   FALSE: If the file should NOT be copied.
  704.  *
  705.  * SIDE EFFECTS:
  706.  *   If the target file exists but is a directory, this routine returns
  707.  *   FALSE (don't copy) but prints an error message.
  708.  *============================================================================*/
  709.  
  710. static int copyit(
  711.  
  712. char    *source      ,              /* Full pathname of source file */
  713. ulong    ssize       ,              /* Size of source file */
  714. ushort   sdate       ,              /* Date of source file */
  715. ushort   stime       ,              /* Time of source file */
  716. ushort   smode       ,              /* File mode of source file */
  717. char    *target      ,              /* Full pathname of target file */
  718. int      MustExist   ,              /* Must target exist (TRUE, FALSE) */
  719. int      condition   )              /* CCP_DIFFERENT, CCP_LATER ... */
  720.  
  721. {
  722.   int    rc;                        /* Return code storage */
  723.   ushort tdate;                     /* Target file's date/time */
  724.   ushort ttime;
  725.  
  726.   ulong   scnt;                     /* Count used by findfirst */
  727.   HDIR    findh;                    /* Handle returned by DosFindFirst() */
  728.  
  729.   FINFO  finfo;                     /* File information structure */
  730.  
  731.   findh = HDIR_CREATE;              /* Set initial value of handle */
  732.   scnt = 1;                         /* Find target file */
  733.   rc = DosFindFirst(target,
  734.           &findh, attrib,
  735.           &finfo, sizeof(FINFO),
  736.           &scnt,
  737.           (ULONG)FIL_STANDARD);          /* Was 0L for 1.3. Is 1 for 2.0  */
  738.  
  739.   if ((rc != 0) || (scnt == 0))     /* If target doesn't exist: */
  740.   {
  741.      if (MustExist)                      /* If target must exist: */
  742.         return(FALSE);                        /* Then don't perform a copy */
  743.      else                                /* Else target doesn't have to exist: */
  744.         return(TRUE);                         /* Then we need to copy, period */
  745.   }
  746.   else                              /* Else target exists: */
  747.   {
  748.      DosFindClose(findh);                /* (Close the handle first) */
  749.      if ((finfo.Fmode & _A_SUBDIR) != 0) /* Be sure it's not a directory */
  750.      {
  751.         fprintf(stderr, "ccp: Target file is a directory: %s\n", target);
  752.         fflush(stderr);
  753.         return(FALSE);
  754.      }
  755.  
  756.       memcpy(&tdate,                      /* Store target file's date/time */
  757.              &finfo.fdateLastWrite,
  758.              sizeof(ushort));
  759.       memcpy(&ttime,
  760.              &finfo.ftimeLastWrite,
  761.              sizeof(ushort));
  762.  
  763.      switch (condition)                  /* Check condition for copy: */
  764.      {
  765.         case CCP_DIFFERENT:                   /*---- Time/date/size must be different: */
  766.            if (ssize != finfo.Fsize) return(TRUE);
  767.            if (sdate != tdate) return(TRUE);
  768.            if (stime != ttime) return(TRUE);
  769.            return(FALSE);                          /* Source/target are the same */
  770.            break;
  771.  
  772.         case CCP_LATER:                       /*---- Source must be later: */
  773.           /*---------------------------------------------*
  774.            *   The source is later than the target if:
  775.            *      (date(source) > date(target)), or:
  776.            *      (date(source) == date(target)) &&
  777.            *      (time(source) > time(target))
  778.            *---------------------------------------------*/
  779.            if (sdate > tdate) return(TRUE);
  780.            if ((sdate == tdate) &&
  781.                (stime > ttime)) return(TRUE);
  782.            return(FALSE);                          /* Source is same or earlier */
  783.            break;
  784.      }
  785.   }
  786.  
  787.   return(FALSE);                    /* Will only get here if 'condition' is bad */
  788. }
  789.  
  790. /*============================================================================*
  791.  * fcopy() - Copy file (OS/2 version).
  792.  *
  793.  * REMARKS:
  794.  *   This subroutine copies the source file to the target file, overwriting
  795.  *   the target file if it already exists.
  796.  *
  797.  *   The OS/2 version requires no copy buffer, since it uses OS/2's
  798.  *   OS/2's DosCopy() subroutine.
  799.  *
  800.  *   If an error occurs, the target file (or what there is of it) is erased.
  801.  *
  802.  * RETURNS:
  803.  *   0         : Successful.
  804.  *   CPE_FULL  : The target is full.
  805.  *   CPE_OTHER : Other error.
  806.  *============================================================================*/
  807.  
  808. #define _COPY_OP   0x0001           /* Replace target, Copy even if target exists */
  809.  
  810. static int fcopy(
  811.  
  812. char    *source ,                   /* Full pathname of source file */
  813. ushort   sdate  ,                   /* Date of source file */
  814. ushort   stime  ,                   /* Time of source file */
  815. ushort   smode  ,                   /* File mode of source file */
  816. char    *target ,                   /* Full pathname of target file */
  817. int      force  )                   /* Force copy if target is readonly? */
  818.  
  819. {
  820.   int    rc;                        /* Return code storage */
  821.   int    cperr;                     /* File copy error code */
  822.  
  823.  /*---------------------------------------------------------------------------*
  824.   * Copy the source file to the target file:
  825.   *---------------------------------------------------------------------------*/
  826.  
  827.   cperr = DosCopy(source, target,   /* Copy the file */
  828.                  _COPY_OP);
  829.  
  830.  /*---------------------------------------------------------------------------*
  831.   * If access to target file was denied and force is TRUE, make file
  832.   * writable and try again
  833.   *---------------------------------------------------------------------------*/
  834.  
  835.   if ((cperr == ERROR_ACCESS_DENIED) &&
  836.      (force == TRUE))               /* If target is readonly and force is TRUE: */
  837.   {
  838.      cperr = chmod(target, S_IWRITE);    /* Make target writable */
  839.      if (cperr == 0)
  840.      {
  841.         cperr = DosCopy(source, target,  /* Again, copy the file */
  842.                        _COPY_OP);
  843.      }
  844.   }
  845.  
  846.  /*---------------------------------------------------------------------------*
  847.   * Done: Check for errors and return
  848.   *---------------------------------------------------------------------------*/
  849.  
  850.   if (cperr != 0)                   /* If error: */
  851.      return(CPE_OTHER);                  /* Return error code */
  852.  
  853.   return(0);                        /* Done with copy */
  854. }
  855.