home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / prgramer / rcs / sources / tag.c < prev    next >
C/C++ Source or Header  |  1992-02-23  |  7KB  |  263 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Id: tag.c,v 1.19.1.2 91/01/29 19:45:54 berliner Exp $";
  3. #endif 
  4.  
  5. /*
  6.  *    Copyright (c) 1989, Brian Berliner
  7.  *
  8.  *    You may distribute under the terms of the GNU General Public License
  9.  *    as specified in the README file that comes with the CVS 1.0 kit.
  10.  *
  11.  * Tag
  12.  *
  13.  *    Add or delete a symbolic name to an RCS file, or a collection
  14.  *    of RCS files.  Uses the modules database, if necessary.
  15.  */
  16.  
  17. #include <sys/types.h>
  18. #include <ctype.h>
  19. #include "dir.h"
  20. #include "cvs.h"
  21.  
  22. extern char update_dir[];
  23. extern int run_module_prog;
  24. extern DBM *open_module();
  25.  
  26. static char *symtag;
  27. static char *numtag = "";        /* must be null string, not pointer */
  28. static int _delete = 0;            /* adding a tag by default */
  29. static int tag_recursive = 1;        /* recursive by default */
  30.  
  31. tag(argc, argv)
  32.     int argc;
  33.     char *argv[];
  34. {
  35.     register int i;
  36.     int c;
  37.     DBM *db;
  38.     int err = 0;
  39.  
  40.     if (argc == -1)
  41.     tag_usage();
  42.     optind = 1;
  43.     while ((c = getopt(argc, argv, "nfQqldr:D:")) != -1) {
  44.     switch (c) {
  45.     case 'n':
  46.         run_module_prog = 0;
  47.         break;
  48.     case 'Q':
  49.         really_quiet = 1;
  50.         /* FALL THROUGH */
  51.     case 'q':
  52.         quiet = 1;
  53.         break;
  54.     case 'l':
  55.         tag_recursive = 0;
  56.         break;
  57.     case 'd':
  58.         _delete = 1;
  59.         /* FALL THROUGH */
  60.     case 'f':
  61.         /*
  62.          * Only makes sense when the -r option is specified, or deleting
  63.          */
  64.         force_tag_match = 1;
  65.         break;
  66.     case 'r':
  67.         numtag = optarg;
  68.         break;
  69.     case 'D':
  70.         Make_Date(optarg, Date);
  71.         break;
  72.     case '?':
  73.     default:
  74.         tag_usage();
  75.         break;
  76.     }
  77.     }
  78.     argc -= optind;
  79.     argv += optind;
  80.     if (argc < 2)
  81.     tag_usage();
  82.     symtag = argv[0];
  83.     argc--;
  84.     argv++;
  85.     /*
  86.      * Do some consistency checks on the symbolic tag... I'm not sure
  87.      * how these relate to the checks that RCS does.
  88.      */
  89.     if (isdigit(symtag[0]) || index(symtag, '.') ||
  90.     index(symtag, ':') || index(symtag, ';'))
  91.     error(0, "symbolic tag %s must not contain any of '.:;' or start with 0-9",
  92.           symtag);
  93.     db = open_module();
  94.     for (i = 0; i < argc; i++)
  95.     err += do_module(db, argv[i], TAG, "Tagging");
  96.     close_module(db);
  97.     exit(err);
  98. }
  99.  
  100. /*
  101.  * This is the recursive function that adds/deletes tags from
  102.  * RCS files.  If the "rcs" argument is NULL, descend the current
  103.  * directory, tagging all the files as appropriate; otherwise, just
  104.  * tag the argument rcs file
  105.  */
  106. tagit(rcs)
  107.     char *rcs;
  108. {
  109.     DIR *dirp;
  110.     struct dirent *dp;
  111.     char line[10];
  112.     char *cp;
  113.     int err = 0;
  114.  
  115.     if (rcs == NULL) {
  116.     if ((dirp = opendir(".")) == NULL) {
  117.         err++;
  118.     } else {
  119.         (void) sprintf(line, ".*%s$", RCSEXT);
  120.         if ((cp = re_comp(line)) != NULL) {
  121.         warn(0, "%s", cp);
  122.         err++;
  123.         } while ((dp = readdir(dirp)) != NULL) {
  124.         if (strcmp(dp->d_name, ".") == 0 ||
  125.             strcmp(dp->d_name, "..") == 0 ||
  126.             stricmp(dp->d_name, CVSLCK) == 0)
  127.             continue;
  128.         if (stricmp(dp->d_name, CVSATTIC) == 0 &&
  129.             !_delete && numtag[0] == '\0')
  130.             continue;
  131.         if (isdir(dp->d_name) && tag_recursive) {
  132.             char cwd[MAXPATHLEN];
  133.  
  134.             if (getwd(cwd) == NULL) {
  135.             warn(0, "cannot get working directory: %s", cwd);
  136.             continue;
  137.             }
  138.             if (update_dir[0] == '\0') {
  139.             (void) strcpy(update_dir, dp->d_name);
  140.             } else {
  141.             (void) strcat(update_dir, DIRSEPSTR);
  142.             (void) strcat(update_dir, dp->d_name);
  143.             }
  144.             if (!quiet) {
  145.             printf("%s %s: Tagging %s\n",
  146.                    progname, command, update_dir);
  147.             }
  148.             if (chdir(dp->d_name) < 0) {
  149.             warn(0, "chdir failed, %s ignored", update_dir);
  150.             continue;
  151.             }
  152.             err += tagit((char *)0);
  153.             if ((cp = rindex_sep(update_dir)) != NULL)
  154.             *cp = '\0';
  155.             else
  156.             update_dir[0] = '\0';
  157.             if (chdir(cwd) < 0)
  158.             error(1, "cannot chdir back to %s", cwd);
  159.             continue;
  160.         }
  161.         if (re_exec(dp->d_name))
  162.             err += tag_file(dp->d_name);
  163.         }
  164.     }
  165.     if (dirp)
  166.         (void) closedir(dirp);
  167.     } else {
  168.     return (tag_file(rcs));
  169.     }
  170.     return (err);
  171. }
  172.  
  173. /*
  174.  * Called to tag a particular file, as appropriate with the options
  175.  * that were set above.
  176.  */
  177. tag_file(rcs)
  178.     char *rcs;
  179. {
  180.     char version[50];
  181.  
  182. #ifdef S_IFLNK
  183.     /*
  184.      * Ooops..  if there is a symbolic link in the source repository
  185.      * which points to a normal file, rcs will do its file renaming
  186.      * mumbo-jumbo and blow away the symbolic link; this is essentially
  187.      * like a copy-on-commit RCS revision control file, but I consider
  188.      * it a bug.  Instead, read the contents of the link and recursively
  189.      * tag the link contents (which may be a symlink itself...).
  190.      */
  191.     if (islink(rcs) && isfile(rcs)) {
  192.     char link_name[MAXPATHLEN];
  193.     int count;
  194.  
  195.     if ((count = readlink(rcs, link_name, sizeof(link_name))) != -1) {
  196.         link_name[count] = '\0';
  197.         return (tag_file(link_name));
  198.     }
  199.     }
  200. #endif
  201.  
  202.     if (_delete) {
  203.     /*
  204.      * If -d is specified, "force_tag_match" is set, so that this call
  205.      * to Version_Number() will return a NULL version string if
  206.      * the symbolic tag does not exist in the RCS file.
  207.      *
  208.      * If the -r flag was used, numtag is set, and we only delete
  209.      * the symtag from files that have contain numtag.
  210.      *
  211.      * This is done here because it's MUCH faster than just blindly
  212.      * calling "rcs" to remove the tag... trust me.
  213.      */
  214.     if (numtag[0] != '\0') {
  215.         Version_Number(rcs, numtag, "", version);
  216.         if (version[0] == '\0')
  217.         return (0);
  218.     }
  219.     Version_Number(rcs, symtag, "", version);
  220.     if (version[0] == '\0')
  221.         return (0);
  222.     (void) sprintf(prog, "%s -q -N%s %s 2>%s", RCS, symtag, rcs, DEVNULL);
  223.     if (system(prog) != 0) {
  224.         warn(0, "failed to remove tag %s for %s", symtag, rcs);
  225.         return (1);
  226.     }
  227.     return (0);
  228.     }
  229.     Version_Number(rcs, numtag, Date, version);
  230.     if (version[0] == '\0') {
  231.     if (!quiet) {
  232.         warn(0, "cannot find tag '%s' for %s", numtag[0] ? numtag : "head",
  233.          rcs);
  234.         return (1);
  235.     }
  236.     return (0);
  237.     }
  238.     if (isdigit(numtag[0]) && strcmp(numtag, version) != 0) {
  239.     /*
  240.      * We didn't find a match for the numeric tag that was specified,
  241.      * but that's OK.  just pass the numeric tag on to rcs, to be
  242.      * tagged as specified
  243.      */
  244.     (void) strcpy(version, numtag);
  245.     }
  246.     (void) sprintf(prog, "%s -q -N%s:%s %s", RCS, symtag, version, rcs);
  247.     if (system(prog) != 0) {
  248.     warn(0, "failed to set tag %s to revision %s for %s",
  249.          symtag, version, rcs);
  250.     return (1);
  251.     }
  252.     return (0);
  253. }
  254.  
  255. static
  256. tag_usage()
  257. {
  258.     (void) fprintf(stderr,
  259.     "Usage: %s %s [-Qqlfn] [-d] [-r tag|-D date] tag modules...\n",
  260.            progname, command);
  261.     exit(1);
  262. }
  263.