2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
5 * You may distribute under the terms of the GNU General Public License as
6 * specified in the README file that comes with the CVS source distribution.
10 * Add or delete a symbolic name to an RCS file, or a collection of RCS files.
11 * Tag uses the checked out revision in the current directory, rtag uses
12 * the modules database, if necessary.
20 static int rtag_proc PROTO((int argc, char **argv, char *xwhere,
21 char *mwhere, char *mfile, int shorten,
22 int local_specified, char *mname, char *msg));
23 static int check_fileproc PROTO ((void *callerdat, struct file_info *finfo));
24 static int check_filesdoneproc PROTO ((void *callerdat, int err,
26 const char *update_dir,
28 static int pretag_proc PROTO((const char *repository, const char *filter));
29 static void masterlist_delproc PROTO((Node *p));
30 static void tag_delproc PROTO((Node *p));
31 static int pretag_list_proc PROTO((Node *p, void *closure));
33 static Dtype tag_dirproc PROTO ((void *callerdat, const char *dir,
34 const char *repos, const char *update_dir,
36 static int rtag_fileproc PROTO ((void *callerdat, struct file_info *finfo));
37 static int rtag_delete PROTO((RCSNode *rcsfile));
38 static int tag_fileproc PROTO ((void *callerdat, struct file_info *finfo));
40 static char *numtag; /* specific revision to tag */
41 static int numtag_validated = 0;
42 static char *date = NULL;
43 static char *symtag; /* tag to add or delete */
44 static int delete_flag; /* adding a tag by default */
45 static int branch_mode; /* make an automagic "branch" tag */
46 static int disturb_branch_tags = 0; /* allow -F,-d to disturb branch tags */
47 static int force_tag_match = 1; /* force tag to match by default */
48 static int force_tag_move; /* don't force tag to move by default */
49 static int check_uptodate; /* no uptodate-check by default */
50 static int attic_too; /* remove tag from Attic files */
69 static const char rtag_opts[] = "+aBbdFflnQqRr:D:";
70 static const char *const rtag_usage[] =
72 "Usage: %s %s [-abdFflnR] [-r rev|-D date] tag modules...\n",
73 "\t-a\tClear tag from removed files that would not otherwise be tagged.\n",
74 "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
75 "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n",
76 "\t-d\tDelete the given tag.\n",
77 "\t-F\tMove tag if it already exists.\n",
78 "\t-f\tForce a head revision match if tag/date not found.\n",
79 "\t-l\tLocal directory only, not recursive.\n",
80 "\t-n\tNo execution of 'tag program'.\n",
81 "\t-R\tProcess directories recursively.\n",
82 "\t-r rev\tExisting revision/tag.\n",
83 "\t-D\tExisting date.\n",
84 "(Specify the --help global option for a list of other help options)\n",
88 static const char tag_opts[] = "+BbcdFflQqRr:D:";
89 static const char *const tag_usage[] =
91 "Usage: %s %s [-bcdFflR] [-r rev|-D date] tag [files...]\n",
92 "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
93 "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n",
94 "\t-c\tCheck that working files are unmodified.\n",
95 "\t-d\tDelete the given tag.\n",
96 "\t-F\tMove tag if it already exists.\n",
97 "\t-f\tForce a head revision match if tag/date not found.\n",
98 "\t-l\tLocal directory only, not recursive.\n",
99 "\t-R\tProcess directories recursively.\n",
100 "\t-r rev\tExisting revision/tag.\n",
101 "\t-D\tExisting date.\n",
102 "(Specify the --help global option for a list of other help options)\n",
111 int local = 0; /* recursive by default */
114 int run_module_prog = 1;
116 is_rtag = (strcmp (cvs_cmd_name, "rtag") == 0);
119 usage (is_rtag ? rtag_usage : tag_usage);
122 while ((c = getopt (argc, argv, is_rtag ? rtag_opts : tag_opts)) != -1)
133 disturb_branch_tags = 1;
155 #ifdef SERVER_SUPPORT
156 /* The CVS 1.5 client sends these options (in addition to
157 Global_option requests), so we must ignore them. */
161 "-q or -Q must be specified before \"%s\"",
173 date = Make_Date (optarg);
177 usage (is_rtag ? rtag_usage : tag_usage);
184 if (argc < (is_rtag ? 2 : 1))
185 usage (is_rtag ? rtag_usage : tag_usage);
191 error (1, 0, "-r and -D options are mutually exclusive");
192 if (delete_flag && branch_mode)
193 error (0, 0, "warning: -b ignored with -d options");
194 RCS_check_tag (symtag);
196 #ifdef CLIENT_SUPPORT
197 if (current_parsed_root->isremote)
199 /* We're the client side. Fire up the remote server. */
208 if (disturb_branch_tags)
216 if (!force_tag_match)
220 if (!run_module_prog)
224 option_with_arg ("-r", numtag);
226 client_senddate (date);
235 for (i = 0; i < argc; ++i)
237 send_to_server ("rtag\012", 0);
241 send_files (argc, argv, local, 0,
243 /* I think the -c case is like "cvs status", in
244 which we really better be correct rather than
245 being fast; it is just too confusing otherwise. */
246 check_uptodate ? 0 : SEND_NO_CONTENTS);
247 send_file_names (argc, argv, SEND_EXPAND_WILD);
248 send_to_server ("tag\012", 0);
251 return get_responses_and_close ();
260 for (i = 0; i < argc; i++)
262 /* XXX last arg should be repository, but doesn't make sense here */
263 history_write ('T', (delete_flag ? "D" : (numtag ? numtag :
264 (date ? date : "A"))), symtag, argv[i], "");
265 err += do_module (db, argv[i], TAG,
266 delete_flag ? "Untagging" : "Tagging",
267 rtag_proc, (char *) NULL, 0, local, run_module_prog,
274 err = rtag_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, local, NULL,
282 * callback proc for doing the real work of tagging
286 rtag_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified,
298 /* Begin section which is identical to patch_proc--should this
299 be abstracted out somehow? */
308 repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0])
309 + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2);
310 (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
311 where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1)
313 (void) strcpy (where, argv[0]);
315 /* if mfile isn't null, we need to set up to do only part of the module */
321 /* if the portion of the module is a path, put the dir part on repos */
322 if ((cp = strrchr (mfile, '/')) != NULL)
325 (void) strcat (repository, "/");
326 (void) strcat (repository, mfile);
327 (void) strcat (where, "/");
328 (void) strcat (where, mfile);
332 /* take care of the rest */
333 path = xmalloc (strlen (repository) + strlen (mfile) + 5);
334 (void) sprintf (path, "%s/%s", repository, mfile);
337 /* directory means repository gets the dir tacked on */
338 (void) strcpy (repository, path);
339 (void) strcat (where, "/");
340 (void) strcat (where, mfile);
352 /* cd to the starting repository */
353 if ( CVS_CHDIR (repository) < 0)
355 error (0, errno, "cannot chdir to %s", repository);
359 /* End section which is identical to patch_proc. */
361 if (delete_flag || attic_too || (force_tag_match && numtag))
362 which = W_REPOS | W_ATTIC;
373 if (numtag != NULL && !numtag_validated)
375 tag_check_valid (numtag, argc - 1, argv + 1, local_specified, 0, repository);
376 numtag_validated = 1;
379 /* check to make sure they are authorized to tag all the
380 specified files in the repository */
383 err = start_recursion (check_fileproc, check_filesdoneproc,
384 (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
385 argc - 1, argv + 1, local_specified, which, 0,
386 CVS_LOCK_READ, where, 1, repository);
390 error (1, 0, "correct the above errors first!");
393 /* It would be nice to provide consistency with respect to
394 commits; however CVS lacks the infrastructure to do that (see
395 Concurrency in cvs.texinfo and comment in do_recursion). */
397 /* start the recursion processor */
398 err = start_recursion (is_rtag ? rtag_fileproc : tag_fileproc,
399 (FILESDONEPROC) NULL, tag_dirproc,
400 (DIRLEAVEPROC) NULL, NULL, argc - 1, argv + 1,
401 local_specified, which, 0, CVS_LOCK_WRITE, where, 1,
403 if ( which & W_REPOS ) free ( repository );
410 /* check file that is to be tagged */
411 /* All we do here is add it to our list */
414 check_fileproc (callerdat, finfo)
416 struct file_info *finfo;
424 switch (Classify_File (finfo, (char *) NULL, (char *) NULL,
425 (char *) NULL, 1, 0, &vers, 0))
439 error (0, 0, "%s is locally modified", finfo->fullname);
445 vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
447 if (finfo->update_dir[0] == '\0')
450 xdir = finfo->update_dir;
451 if ((p = findnode (mtlist, xdir)) != NULL)
453 tlist = ((struct master_lists *) p->data)->tlist;
457 struct master_lists *ml;
461 p->key = xstrdup (xdir);
463 ml = (struct master_lists *)
464 xmalloc (sizeof (struct master_lists));
467 p->delproc = masterlist_delproc;
468 (void) addnode (mtlist, p);
472 p->key = xstrdup (finfo->file);
474 p->delproc = tag_delproc;
475 if (vers->srcfile == NULL)
478 error (0, 0, "nothing known about %s", finfo->file);
484 /* Here we duplicate the calculation in tag_fileproc about which
485 version we are going to tag. There probably are some subtle races
486 (e.g. numtag is "foo" which gets moved between here and
488 if (!is_rtag && numtag == NULL && date == NULL)
489 p->data = xstrdup (vers->vn_user);
491 p->data = RCS_getversion (vers->srcfile, numtag, date,
492 force_tag_match, NULL);
499 oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1,
501 if (oversion == NULL)
505 /* Deleting a tag which did not exist is a noop and
506 should not be logged. */
510 else if (delete_flag)
513 p->data = xstrdup (oversion);
515 else if (strcmp(oversion, p->data) == 0)
519 else if (!force_tag_move)
523 if (oversion != NULL)
534 (void) addnode (tlist, p);
539 check_filesdoneproc (callerdat, err, repos, update_dir, entries)
543 const char *update_dir;
549 p = findnode(mtlist, update_dir);
552 tlist = ((struct master_lists *) p->data)->tlist;
556 tlist = (List *) NULL;
558 if ((tlist == NULL) || (tlist->list->next == tlist->list))
562 if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, 1)) > 0)
564 error (0, 0, "Pre-tag check failed");
571 pretag_proc (repository, filter)
572 const char *repository;
575 if (filter[0] == '/')
580 for (cp=s; *cp; cp++)
582 if (isspace ((unsigned char) *cp))
590 error (0, errno, "cannot find pre-tag filter '%s'", s);
598 run_arg (delete_flag ? "del" : force_tag_move ? "mov" : "add");
599 run_arg (repository);
600 walklist(tlist, pretag_list_proc, NULL);
601 return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL));
605 masterlist_delproc(p)
608 struct master_lists *ml = p->data;
628 pretag_list_proc(p, closure)
642 * Called to rtag a particular file, as appropriate with the options that were
647 rtag_fileproc (callerdat, finfo)
649 struct file_info *finfo;
655 /* find the parsed RCS data */
656 if ((rcsfile = finfo->rcs) == NULL)
660 * For tagging an RCS file which is a symbolic link, you'd best be
661 * running with RCS 5.6, since it knows how to handle symbolic links
662 * correctly without breaking your link!
666 return (rtag_delete (rcsfile));
669 * If we get here, we are adding a tag. But, if -a was specified, we
670 * need to check to see if a -r or -D option was specified. If neither
671 * was specified and the file is in the Attic, remove the tag.
673 if (attic_too && (!numtag && !date))
675 if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
676 return (rtag_delete (rcsfile));
679 version = RCS_getversion (rcsfile, numtag, date, force_tag_match,
683 /* If -a specified, clean up any old tags */
685 (void) rtag_delete (rcsfile);
687 if (!quiet && !force_tag_match)
689 error (0, 0, "cannot find tag `%s' in `%s'",
690 numtag ? numtag : "head", rcsfile->path);
696 && isdigit ((unsigned char) *numtag)
697 && strcmp (numtag, version) != 0)
701 * We didn't find a match for the numeric tag that was specified, but
702 * that's OK. just pass the numeric tag on to rcs, to be tagged as
703 * specified. Could get here if one tried to tag "1.1.1" and there
704 * was a 1.1.1 branch with some head revision. In this case, we want
705 * the tag to reference "1.1.1" and not the revision at the head of
706 * the branch. Use a symbolic tag for that.
708 rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag;
709 retcode = RCS_settag(rcsfile, symtag, numtag);
711 RCS_rewrite (rcsfile, NULL, NULL);
718 * As an enhancement for the case where a tag is being re-applied to
719 * a large body of a module, make one extra call to RCS_getversion to
720 * see if the tag is already set in the RCS file. If so, check to
721 * see if it needs to be moved. If not, do nothing. This will
722 * likely save a lot of time when simply moving the tag to the
723 * "current" head revisions of a module -- which I have found to be a
724 * typical tagging operation.
726 rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
727 oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1,
729 if (oversion != NULL)
731 int isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
734 * if versions the same and neither old or new are branches don't
735 * have to do anything
737 if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
746 /* we're NOT going to move the tag */
747 (void) printf ("W %s", finfo->fullname);
749 (void) printf (" : %s already exists on %s %s",
750 symtag, isbranch ? "branch" : "version",
752 (void) printf (" : NOT MOVING tag to %s %s\n",
753 branch_mode ? "branch" : "version", rev);
756 if (branch_mode) free(rev);
759 else /* force_tag_move is set and... */
760 if ((isbranch && !disturb_branch_tags) ||
761 (!isbranch && disturb_branch_tags))
763 error(0,0, "%s: Not moving %s tag `%s' from %s to %s%s.",
765 isbranch ? "branch" : "non-branch",
766 symtag, oversion, rev,
767 isbranch ? "" : " due to `-B' option");
768 if (branch_mode) free(rev);
775 retcode = RCS_settag(rcsfile, symtag, rev);
777 RCS_rewrite (rcsfile, NULL, NULL);
782 error (1, retcode == -1 ? errno : 0,
783 "failed to set tag `%s' to revision `%s' in `%s'",
784 symtag, rev, rcsfile->path);
797 * If -d is specified, "force_tag_match" is set, so that this call to
798 * RCS_getversion() will return a NULL version string if the symbolic
799 * tag does not exist in the RCS file.
801 * If the -r flag was used, numtag is set, and we only delete the
802 * symtag from files that have numtag.
804 * This is done here because it's MUCH faster than just blindly calling
805 * "rcs" to remove the tag... trust me.
808 rtag_delete (rcsfile)
812 int retcode, isbranch;
816 version = RCS_getversion (rcsfile, numtag, (char *) NULL, 1,
823 version = RCS_getversion (rcsfile, symtag, (char *) NULL, 1,
830 isbranch = RCS_nodeisbranch (rcsfile, symtag);
831 if ((isbranch && !disturb_branch_tags) ||
832 (!isbranch && disturb_branch_tags))
836 "Not removing %s tag `%s' from `%s'%s.",
837 isbranch ? "branch" : "non-branch",
838 symtag, rcsfile->path,
839 isbranch ? "" : " due to `-B' option");
843 if ((retcode = RCS_deltag(rcsfile, symtag)) != 0)
846 error (0, retcode == -1 ? errno : 0,
847 "failed to remove tag `%s' from `%s'", symtag,
851 RCS_rewrite (rcsfile, NULL, NULL);
857 * Called to tag a particular file (the currently checked out version is
858 * tagged with the specified tag - or the specified tag is deleted).
862 tag_fileproc (callerdat, finfo)
864 struct file_info *finfo;
866 char *version, *oversion;
867 char *nversion = NULL;
873 vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
875 if ((numtag != NULL) || (date != NULL))
877 nversion = RCS_getversion(vers->srcfile,
882 if (nversion == NULL)
883 goto free_vars_and_return;
890 * If -d is specified, "force_tag_match" is set, so that this call to
891 * RCS_getversion() will return a NULL version string if the symbolic
892 * tag does not exist in the RCS file.
894 * This is done here because it's MUCH faster than just blindly calling
895 * "rcs" to remove the tag... trust me.
898 version = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1,
900 if (version == NULL || vers->srcfile == NULL)
901 goto free_vars_and_return;
905 isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
906 if ((isbranch && !disturb_branch_tags) ||
907 (!isbranch && disturb_branch_tags))
911 "Not removing %s tag `%s' from `%s'%s.",
912 isbranch ? "branch" : "non-branch",
913 symtag, vers->srcfile->path,
914 isbranch ? "" : " due to `-B' option");
916 goto free_vars_and_return;
919 if ((retcode = RCS_deltag(vers->srcfile, symtag)) != 0)
922 error (0, retcode == -1 ? errno : 0,
923 "failed to remove tag %s from %s", symtag,
924 vers->srcfile->path);
926 goto free_vars_and_return;
928 RCS_rewrite (vers->srcfile, NULL, NULL);
933 cvs_output ("D ", 2);
934 cvs_output (finfo->fullname, 0);
935 cvs_output ("\n", 1);
938 goto free_vars_and_return;
942 * If we are adding a tag, we need to know which version we have checked
943 * out and we'll tag that version.
945 if (nversion == NULL)
947 version = vers->vn_user;
955 goto free_vars_and_return;
957 else if (strcmp (version, "0") == 0)
960 error (0, 0, "couldn't tag added but un-commited file `%s'", finfo->file);
961 goto free_vars_and_return;
963 else if (version[0] == '-')
966 error (0, 0, "skipping removed but un-commited file `%s'", finfo->file);
967 goto free_vars_and_return;
969 else if (vers->srcfile == NULL)
972 error (0, 0, "cannot find revision control file for `%s'", finfo->file);
973 goto free_vars_and_return;
977 * As an enhancement for the case where a tag is being re-applied to a
978 * large number of files, make one extra call to RCS_getversion to see
979 * if the tag is already set in the RCS file. If so, check to see if it
980 * needs to be moved. If not, do nothing. This will likely save a lot of
981 * time when simply moving the tag to the "current" head revisions of a
982 * module -- which I have found to be a typical tagging operation.
984 rev = branch_mode ? RCS_magicrev (vers->srcfile, version) : version;
985 oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1,
987 if (oversion != NULL)
989 int isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
992 * if versions the same and neither old or new are branches don't have
995 if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
1000 goto free_vars_and_return;
1003 if (!force_tag_move)
1005 /* we're NOT going to move the tag */
1006 cvs_output ("W ", 2);
1007 cvs_output (finfo->fullname, 0);
1008 cvs_output (" : ", 0);
1009 cvs_output (symtag, 0);
1010 cvs_output (" already exists on ", 0);
1011 cvs_output (isbranch ? "branch" : "version", 0);
1012 cvs_output (" ", 0);
1013 cvs_output (oversion, 0);
1014 cvs_output (" : NOT MOVING tag to ", 0);
1015 cvs_output (branch_mode ? "branch" : "version", 0);
1016 cvs_output (" ", 0);
1017 cvs_output (rev, 0);
1018 cvs_output ("\n", 1);
1022 goto free_vars_and_return;
1024 else /* force_tag_move == 1 and... */
1025 if ((isbranch && !disturb_branch_tags) ||
1026 (!isbranch && disturb_branch_tags))
1028 error(0,0, "%s: Not moving %s tag `%s' from %s to %s%s.",
1030 isbranch ? "branch" : "non-branch",
1031 symtag, oversion, rev,
1032 isbranch ? "" : " due to `-B' option");
1036 goto free_vars_and_return;
1041 if ((retcode = RCS_settag(vers->srcfile, symtag, rev)) != 0)
1043 error (1, retcode == -1 ? errno : 0,
1044 "failed to set tag %s to revision %s in %s",
1045 symtag, rev, vers->srcfile->path);
1049 goto free_vars_and_return;
1053 RCS_rewrite (vers->srcfile, NULL, NULL);
1055 /* more warm fuzzies */
1058 cvs_output ("T ", 2);
1059 cvs_output (finfo->fullname, 0);
1060 cvs_output ("\n", 1);
1063 free_vars_and_return:
1064 if (nversion != NULL)
1066 freevers_ts (&vers);
1071 * Print a warm fuzzy message
1075 tag_dirproc (callerdat, dir, repos, update_dir, entries)
1079 const char *update_dir;
1083 if (ignore_directory (update_dir))
1085 /* print the warm fuzzy message */
1087 error (0, 0, "Ignoring %s", update_dir);
1092 error (0, 0, "%s %s", delete_flag ? "Untagging" : "Tagging", update_dir);
1096 /* Code relating to the val-tags file. Note that this file has no way
1097 of knowing when a tag has been deleted. The problem is that there
1098 is no way of knowing whether a tag still exists somewhere, when we
1099 delete it some places. Using per-directory val-tags files (in
1100 CVSREP) might be better, but that might slow down the process of
1101 verifying that a tag is correct (maybe not, for the likely cases,
1102 if carefully done), and/or be harder to implement correctly. */
1109 static int val_fileproc PROTO ((void *callerdat, struct file_info *finfo));
1112 val_fileproc (callerdat, finfo)
1114 struct file_info *finfo;
1117 struct val_args *args = (struct val_args *)callerdat;
1120 if ((rcsdata = finfo->rcs) == NULL)
1121 /* Not sure this can happen, after all we passed only
1122 W_REPOS | W_ATTIC. */
1125 tag = RCS_gettag (rcsdata, args->name, 1, (int *) NULL);
1128 /* FIXME: should find out a way to stop the search at this point. */
1137 static Dtype val_direntproc PROTO ((void *, const char *, const char *,
1138 const char *, List *));
1141 val_direntproc (callerdat, dir, repository, update_dir, entries)
1144 const char *repository;
1145 const char *update_dir;
1148 /* This is not quite right--it doesn't get right the case of "cvs
1149 update -d -r foobar" where foobar is a tag which exists only in
1150 files in a directory which does not exist yet, but which is
1151 about to be created. */
1157 /* Check to see whether NAME is a valid tag. If so, return. If not
1158 print an error message and exit. ARGC, ARGV, LOCAL, and AFLAG specify
1159 which files we will be operating on.
1161 REPOSITORY is the repository if we need to cd into it, or NULL if
1162 we are already there, or "" if we should do a W_LOCAL recursion.
1163 Sorry for three cases, but the "" case is needed in case the
1164 working directories come from diverse parts of the repository, the
1165 NULL case avoids an unneccesary chdir, and the non-NULL, non-""
1166 case is needed for checkout, where we don't want to chdir if the
1167 tag is found in CVSROOTADM_VALTAGS, but there is not (yet) any
1170 tag_check_valid (name, argc, argv, local, aflag, repository)
1179 char *valtags_filename;
1182 struct val_args the_val_args;
1183 struct saved_cwd cwd;
1186 /* Numeric tags require only a syntactic check. */
1187 if (isdigit ((unsigned char) name[0]))
1190 for (p = name; *p != '\0'; ++p)
1192 if (!(isdigit ((unsigned char) *p) || *p == '.'))
1194 Numeric tag %s contains characters other than digits and '.'", name);
1199 /* Special tags are always valid. */
1200 if (strcmp (name, TAG_BASE) == 0
1201 || strcmp (name, TAG_HEAD) == 0)
1207 /* FIXME: This routine doesn't seem to do any locking whatsoever
1208 (and it is called from places which don't have locks in place).
1209 If two processes try to write val-tags at the same time, it would
1210 seem like we are in trouble. */
1213 mytag.dsize = strlen (name);
1215 valtags_filename = xmalloc (strlen (current_parsed_root->directory)
1217 + sizeof CVSROOTADM_VALTAGS + 3);
1218 sprintf (valtags_filename, "%s/%s/%s", current_parsed_root->directory,
1219 CVSROOTADM, CVSROOTADM_VALTAGS);
1220 db = dbm_open (valtags_filename, O_RDWR, 0666);
1223 if (!existence_error (errno))
1225 error (0, errno, "warning: cannot open %s read/write",
1227 db = dbm_open (valtags_filename, O_RDONLY, 0666);
1230 else if (!existence_error (errno))
1231 error (1, errno, "cannot read %s", valtags_filename);
1233 /* If the file merely fails to exist, we just keep going and create
1234 it later if need be. */
1240 val = dbm_fetch (db, mytag);
1241 if (val.dptr != NULL)
1243 /* Found. The tag is valid. */
1245 free (valtags_filename);
1248 /* FIXME: should check errors somehow (add dbm_error to myndbm.c?). */
1251 /* We didn't find the tag in val-tags, so look through all the RCS files
1252 to see whether it exists there. Yes, this is expensive, but there
1253 is no other way to cope with a tag which might have been created
1254 by an old version of CVS, from before val-tags was invented.
1256 Since we need this code anyway, we also use it to create
1257 entries in val-tags in general (that is, the val-tags entry
1258 will get created the first time the tag is used, not when the
1261 the_val_args.name = name;
1262 the_val_args.found = 0;
1264 which = W_REPOS | W_ATTIC;
1266 if (repository != NULL)
1268 if (repository[0] == '\0')
1272 if (save_cwd (&cwd))
1274 if (CVS_CHDIR (repository) < 0)
1275 error (1, errno, "cannot change to %s directory", repository);
1279 start_recursion (val_fileproc, (FILESDONEPROC) NULL,
1280 val_direntproc, (DIRLEAVEPROC) NULL,
1281 (void *)&the_val_args,
1282 argc, argv, local, which, aflag,
1283 CVS_LOCK_READ, NULL, 1, repository);
1284 if (repository != NULL && repository[0] != '\0')
1286 if (restore_cwd (&cwd, NULL))
1291 if (!the_val_args.found)
1292 error (1, 0, "no such tag %s", name);
1295 /* The tags is valid but not mentioned in val-tags. Add it. */
1298 if (noexec || nowrite)
1302 free (valtags_filename);
1309 omask = umask (cvsumask);
1310 db = dbm_open (valtags_filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
1311 (void)umask (omask);
1315 error (0, errno, "warning: cannot create %s", valtags_filename);
1316 free (valtags_filename);
1322 if (dbm_store (db, mytag, value, DBM_REPLACE) < 0)
1323 error (0, errno, "cannot store %s into %s", name,
1327 free (valtags_filename);
1331 * Check whether a join tag is valid. This is just like
1332 * tag_check_valid, but we must stop before the colon if there is one.
1336 tag_check_valid_join (join_tag, argc, argv, local, aflag, repository)
1346 c = xstrdup (join_tag);
1347 s = strchr (c, ':');
1350 if (isdigit ((unsigned char) join_tag[0]))
1352 "Numeric join tag %s may not contain a date specifier",
1356 /* hmmm... I think it makes sense to allow -j:<date>, but
1357 * for now this fixes a bug where CVS just spins and spins (I
1358 * think in the RCS code) looking for a zero length tag.
1362 "argument to join may not contain a date specifier without a tag");
1365 tag_check_valid (c, argc, argv, local, aflag, repository);