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.
18 static int rtag_proc PROTO((int argc, char **argv, char *xwhere,
19 char *mwhere, char *mfile, int shorten,
20 int local_specified, char *mname, char *msg));
21 static int check_fileproc PROTO ((void *callerdat, struct file_info *finfo));
22 static int check_filesdoneproc PROTO ((void *callerdat, int err,
24 const char *update_dir,
26 static int pretag_proc PROTO((const char *repository, const char *filter));
27 static void masterlist_delproc PROTO((Node *p));
28 static void tag_delproc PROTO((Node *p));
29 static int pretag_list_proc PROTO((Node *p, void *closure));
31 static Dtype tag_dirproc PROTO ((void *callerdat, const char *dir,
32 const char *repos, const char *update_dir,
34 static int rtag_fileproc PROTO ((void *callerdat, struct file_info *finfo));
35 static int rtag_delete PROTO((RCSNode *rcsfile));
36 static int tag_fileproc PROTO ((void *callerdat, struct file_info *finfo));
38 static char *numtag; /* specific revision to tag */
39 static int numtag_validated = 0;
40 static char *date = NULL;
41 static char *symtag; /* tag to add or delete */
42 static int delete_flag; /* adding a tag by default */
43 static int branch_mode; /* make an automagic "branch" tag */
44 static int disturb_branch_tags = 0; /* allow -F,-d to disturb branch tags */
45 static int force_tag_match = 1; /* force tag to match by default */
46 static int force_tag_move; /* don't force tag to move by default */
47 static int check_uptodate; /* no uptodate-check by default */
48 static int attic_too; /* remove tag from Attic files */
67 static const char rtag_opts[] = "+aBbdFflnQqRr:D:";
68 static const char *const rtag_usage[] =
70 "Usage: %s %s [-abdFflnR] [-r rev|-D date] tag modules...\n",
71 "\t-a\tClear tag from removed files that would not otherwise be tagged.\n",
72 "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
73 "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n",
74 "\t-d\tDelete the given tag.\n",
75 "\t-F\tMove tag if it already exists.\n",
76 "\t-f\tForce a head revision match if tag/date not found.\n",
77 "\t-l\tLocal directory only, not recursive.\n",
78 "\t-n\tNo execution of 'tag program'.\n",
79 "\t-R\tProcess directories recursively.\n",
80 "\t-r rev\tExisting revision/tag.\n",
81 "\t-D\tExisting date.\n",
82 "(Specify the --help global option for a list of other help options)\n",
86 static const char tag_opts[] = "+BbcdFflQqRr:D:";
87 static const char *const tag_usage[] =
89 "Usage: %s %s [-bcdFflR] [-r rev|-D date] tag [files...]\n",
90 "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
91 "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n",
92 "\t-c\tCheck that working files are unmodified.\n",
93 "\t-d\tDelete the given tag.\n",
94 "\t-F\tMove tag if it already exists.\n",
95 "\t-f\tForce a head revision match if tag/date not found.\n",
96 "\t-l\tLocal directory only, not recursive.\n",
97 "\t-R\tProcess directories recursively.\n",
98 "\t-r rev\tExisting revision/tag.\n",
99 "\t-D\tExisting date.\n",
100 "(Specify the --help global option for a list of other help options)\n",
109 int local = 0; /* recursive by default */
112 int run_module_prog = 1;
114 is_rtag = (strcmp (cvs_cmd_name, "rtag") == 0);
117 usage (is_rtag ? rtag_usage : tag_usage);
120 while ((c = getopt (argc, argv, is_rtag ? rtag_opts : tag_opts)) != -1)
131 disturb_branch_tags = 1;
153 #ifdef SERVER_SUPPORT
154 /* The CVS 1.5 client sends these options (in addition to
155 Global_option requests), so we must ignore them. */
159 "-q or -Q must be specified before \"%s\"",
171 date = Make_Date (optarg);
175 usage (is_rtag ? rtag_usage : tag_usage);
182 if (argc < (is_rtag ? 2 : 1))
183 usage (is_rtag ? rtag_usage : tag_usage);
189 error (1, 0, "-r and -D options are mutually exclusive");
190 if (delete_flag && branch_mode)
191 error (0, 0, "warning: -b ignored with -d options");
192 RCS_check_tag (symtag);
194 #ifdef CLIENT_SUPPORT
195 if (current_parsed_root->isremote)
197 /* We're the client side. Fire up the remote server. */
206 if (disturb_branch_tags)
214 if (!force_tag_match)
218 if (!run_module_prog)
222 option_with_arg ("-r", numtag);
224 client_senddate (date);
233 for (i = 0; i < argc; ++i)
235 send_to_server ("rtag\012", 0);
239 send_files (argc, argv, local, 0,
241 /* I think the -c case is like "cvs status", in
242 which we really better be correct rather than
243 being fast; it is just too confusing otherwise. */
244 check_uptodate ? 0 : SEND_NO_CONTENTS);
245 send_file_names (argc, argv, SEND_EXPAND_WILD);
246 send_to_server ("tag\012", 0);
249 return get_responses_and_close ();
258 for (i = 0; i < argc; i++)
260 /* XXX last arg should be repository, but doesn't make sense here */
261 history_write ('T', (delete_flag ? "D" : (numtag ? numtag :
262 (date ? date : "A"))), symtag, argv[i], "");
263 err += do_module (db, argv[i], TAG,
264 delete_flag ? "Untagging" : "Tagging",
265 rtag_proc, (char *) NULL, 0, local, run_module_prog,
272 err = rtag_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, local, NULL,
280 * callback proc for doing the real work of tagging
284 rtag_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified,
296 /* Begin section which is identical to patch_proc--should this
297 be abstracted out somehow? */
306 repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0])
307 + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2);
308 (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
309 where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1)
311 (void) strcpy (where, argv[0]);
313 /* if mfile isn't null, we need to set up to do only part of the module */
319 /* if the portion of the module is a path, put the dir part on repos */
320 if ((cp = strrchr (mfile, '/')) != NULL)
323 (void) strcat (repository, "/");
324 (void) strcat (repository, mfile);
325 (void) strcat (where, "/");
326 (void) strcat (where, mfile);
330 /* take care of the rest */
331 path = xmalloc (strlen (repository) + strlen (mfile) + 5);
332 (void) sprintf (path, "%s/%s", repository, mfile);
335 /* directory means repository gets the dir tacked on */
336 (void) strcpy (repository, path);
337 (void) strcat (where, "/");
338 (void) strcat (where, mfile);
350 /* cd to the starting repository */
351 if ( CVS_CHDIR (repository) < 0)
353 error (0, errno, "cannot chdir to %s", repository);
357 /* End section which is identical to patch_proc. */
359 if (delete_flag || attic_too || (force_tag_match && numtag))
360 which = W_REPOS | W_ATTIC;
371 if (numtag != NULL && !numtag_validated)
373 tag_check_valid (numtag, argc - 1, argv + 1, local_specified, 0, repository);
374 numtag_validated = 1;
377 /* check to make sure they are authorized to tag all the
378 specified files in the repository */
381 err = start_recursion (check_fileproc, check_filesdoneproc,
382 (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
383 argc - 1, argv + 1, local_specified, which, 0,
384 CVS_LOCK_READ, where, 1, repository);
388 error (1, 0, "correct the above errors first!");
391 /* It would be nice to provide consistency with respect to
392 commits; however CVS lacks the infrastructure to do that (see
393 Concurrency in cvs.texinfo and comment in do_recursion). */
395 /* start the recursion processor */
396 err = start_recursion (is_rtag ? rtag_fileproc : tag_fileproc,
397 (FILESDONEPROC) NULL, tag_dirproc,
398 (DIRLEAVEPROC) NULL, NULL, argc - 1, argv + 1,
399 local_specified, which, 0, CVS_LOCK_WRITE, where, 1,
401 if ( which & W_REPOS ) free ( repository );
408 /* check file that is to be tagged */
409 /* All we do here is add it to our list */
412 check_fileproc (callerdat, finfo)
414 struct file_info *finfo;
422 switch (Classify_File (finfo, (char *) NULL, (char *) NULL,
423 (char *) NULL, 1, 0, &vers, 0))
437 error (0, 0, "%s is locally modified", finfo->fullname);
443 vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
445 if (finfo->update_dir[0] == '\0')
448 xdir = finfo->update_dir;
449 if ((p = findnode (mtlist, xdir)) != NULL)
451 tlist = ((struct master_lists *) p->data)->tlist;
455 struct master_lists *ml;
459 p->key = xstrdup (xdir);
461 ml = (struct master_lists *)
462 xmalloc (sizeof (struct master_lists));
465 p->delproc = masterlist_delproc;
466 (void) addnode (mtlist, p);
470 p->key = xstrdup (finfo->file);
472 p->delproc = tag_delproc;
473 if (vers->srcfile == NULL)
476 error (0, 0, "nothing known about %s", finfo->file);
482 /* Here we duplicate the calculation in tag_fileproc about which
483 version we are going to tag. There probably are some subtle races
484 (e.g. numtag is "foo" which gets moved between here and
486 if (!is_rtag && numtag == NULL && date == NULL)
487 p->data = xstrdup (vers->vn_user);
489 p->data = RCS_getversion (vers->srcfile, numtag, date,
490 force_tag_match, NULL);
497 oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1,
499 if (oversion == NULL)
503 /* Deleting a tag which did not exist is a noop and
504 should not be logged. */
508 else if (delete_flag)
511 p->data = xstrdup (oversion);
513 else if (strcmp(oversion, p->data) == 0)
517 else if (!force_tag_move)
521 if (oversion != NULL)
532 (void) addnode (tlist, p);
537 check_filesdoneproc (callerdat, err, repos, update_dir, entries)
541 const char *update_dir;
547 p = findnode(mtlist, update_dir);
550 tlist = ((struct master_lists *) p->data)->tlist;
554 tlist = (List *) NULL;
556 if ((tlist == NULL) || (tlist->list->next == tlist->list))
560 if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, 1)) > 0)
562 error (0, 0, "Pre-tag check failed");
569 pretag_proc (repository, filter)
570 const char *repository;
573 if (filter[0] == '/')
578 for (cp=s; *cp; cp++)
580 if (isspace ((unsigned char) *cp))
588 error (0, errno, "cannot find pre-tag filter '%s'", s);
596 run_arg (delete_flag ? "del" : force_tag_move ? "mov" : "add");
597 run_arg (repository);
598 walklist(tlist, pretag_list_proc, NULL);
599 return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL));
603 masterlist_delproc(p)
606 struct master_lists *ml = p->data;
626 pretag_list_proc(p, closure)
640 * Called to rtag a particular file, as appropriate with the options that were
645 rtag_fileproc (callerdat, finfo)
647 struct file_info *finfo;
653 /* find the parsed RCS data */
654 if ((rcsfile = finfo->rcs) == NULL)
658 * For tagging an RCS file which is a symbolic link, you'd best be
659 * running with RCS 5.6, since it knows how to handle symbolic links
660 * correctly without breaking your link!
664 return (rtag_delete (rcsfile));
667 * If we get here, we are adding a tag. But, if -a was specified, we
668 * need to check to see if a -r or -D option was specified. If neither
669 * was specified and the file is in the Attic, remove the tag.
671 if (attic_too && (!numtag && !date))
673 if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
674 return (rtag_delete (rcsfile));
677 version = RCS_getversion (rcsfile, numtag, date, force_tag_match,
681 /* If -a specified, clean up any old tags */
683 (void) rtag_delete (rcsfile);
685 if (!quiet && !force_tag_match)
687 error (0, 0, "cannot find tag `%s' in `%s'",
688 numtag ? numtag : "head", rcsfile->path);
694 && isdigit ((unsigned char) *numtag)
695 && strcmp (numtag, version) != 0)
699 * We didn't find a match for the numeric tag that was specified, but
700 * that's OK. just pass the numeric tag on to rcs, to be tagged as
701 * specified. Could get here if one tried to tag "1.1.1" and there
702 * was a 1.1.1 branch with some head revision. In this case, we want
703 * the tag to reference "1.1.1" and not the revision at the head of
704 * the branch. Use a symbolic tag for that.
706 rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag;
707 retcode = RCS_settag(rcsfile, symtag, numtag);
709 RCS_rewrite (rcsfile, NULL, NULL);
716 * As an enhancement for the case where a tag is being re-applied to
717 * a large body of a module, make one extra call to RCS_getversion to
718 * see if the tag is already set in the RCS file. If so, check to
719 * see if it needs to be moved. If not, do nothing. This will
720 * likely save a lot of time when simply moving the tag to the
721 * "current" head revisions of a module -- which I have found to be a
722 * typical tagging operation.
724 rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
725 oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1,
727 if (oversion != NULL)
729 int isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
732 * if versions the same and neither old or new are branches don't
733 * have to do anything
735 if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
744 /* we're NOT going to move the tag */
745 (void) printf ("W %s", finfo->fullname);
747 (void) printf (" : %s already exists on %s %s",
748 symtag, isbranch ? "branch" : "version",
750 (void) printf (" : NOT MOVING tag to %s %s\n",
751 branch_mode ? "branch" : "version", rev);
754 if (branch_mode) free(rev);
757 else /* force_tag_move is set and... */
758 if ((isbranch && !disturb_branch_tags) ||
759 (!isbranch && disturb_branch_tags))
761 error(0,0, "%s: Not moving %s tag `%s' from %s to %s%s.",
763 isbranch ? "branch" : "non-branch",
764 symtag, oversion, rev,
765 isbranch ? "" : " due to `-B' option");
766 if (branch_mode) free(rev);
773 retcode = RCS_settag(rcsfile, symtag, rev);
775 RCS_rewrite (rcsfile, NULL, NULL);
780 error (1, retcode == -1 ? errno : 0,
781 "failed to set tag `%s' to revision `%s' in `%s'",
782 symtag, rev, rcsfile->path);
795 * If -d is specified, "force_tag_match" is set, so that this call to
796 * RCS_getversion() will return a NULL version string if the symbolic
797 * tag does not exist in the RCS file.
799 * If the -r flag was used, numtag is set, and we only delete the
800 * symtag from files that have numtag.
802 * This is done here because it's MUCH faster than just blindly calling
803 * "rcs" to remove the tag... trust me.
806 rtag_delete (rcsfile)
810 int retcode, isbranch;
814 version = RCS_getversion (rcsfile, numtag, (char *) NULL, 1,
821 version = RCS_getversion (rcsfile, symtag, (char *) NULL, 1,
828 isbranch = RCS_nodeisbranch (rcsfile, symtag);
829 if ((isbranch && !disturb_branch_tags) ||
830 (!isbranch && disturb_branch_tags))
834 "Not removing %s tag `%s' from `%s'%s.",
835 isbranch ? "branch" : "non-branch",
836 symtag, rcsfile->path,
837 isbranch ? "" : " due to `-B' option");
841 if ((retcode = RCS_deltag(rcsfile, symtag)) != 0)
844 error (0, retcode == -1 ? errno : 0,
845 "failed to remove tag `%s' from `%s'", symtag,
849 RCS_rewrite (rcsfile, NULL, NULL);
855 * Called to tag a particular file (the currently checked out version is
856 * tagged with the specified tag - or the specified tag is deleted).
860 tag_fileproc (callerdat, finfo)
862 struct file_info *finfo;
864 char *version, *oversion;
865 char *nversion = NULL;
871 vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
873 if ((numtag != NULL) || (date != NULL))
875 nversion = RCS_getversion(vers->srcfile,
880 if (nversion == NULL)
881 goto free_vars_and_return;
888 * If -d is specified, "force_tag_match" is set, so that this call to
889 * RCS_getversion() will return a NULL version string if the symbolic
890 * tag does not exist in the RCS file.
892 * This is done here because it's MUCH faster than just blindly calling
893 * "rcs" to remove the tag... trust me.
896 version = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1,
898 if (version == NULL || vers->srcfile == NULL)
899 goto free_vars_and_return;
903 isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
904 if ((isbranch && !disturb_branch_tags) ||
905 (!isbranch && disturb_branch_tags))
909 "Not removing %s tag `%s' from `%s'%s.",
910 isbranch ? "branch" : "non-branch",
911 symtag, vers->srcfile->path,
912 isbranch ? "" : " due to `-B' option");
914 goto free_vars_and_return;
917 if ((retcode = RCS_deltag(vers->srcfile, symtag)) != 0)
920 error (0, retcode == -1 ? errno : 0,
921 "failed to remove tag %s from %s", symtag,
922 vers->srcfile->path);
924 goto free_vars_and_return;
926 RCS_rewrite (vers->srcfile, NULL, NULL);
931 cvs_output ("D ", 2);
932 cvs_output (finfo->fullname, 0);
933 cvs_output ("\n", 1);
936 goto free_vars_and_return;
940 * If we are adding a tag, we need to know which version we have checked
941 * out and we'll tag that version.
943 if (nversion == NULL)
945 version = vers->vn_user;
953 goto free_vars_and_return;
955 else if (strcmp (version, "0") == 0)
958 error (0, 0, "couldn't tag added but un-commited file `%s'", finfo->file);
959 goto free_vars_and_return;
961 else if (version[0] == '-')
964 error (0, 0, "skipping removed but un-commited file `%s'", finfo->file);
965 goto free_vars_and_return;
967 else if (vers->srcfile == NULL)
970 error (0, 0, "cannot find revision control file for `%s'", finfo->file);
971 goto free_vars_and_return;
975 * As an enhancement for the case where a tag is being re-applied to a
976 * large number of files, make one extra call to RCS_getversion to see
977 * if the tag is already set in the RCS file. If so, check to see if it
978 * needs to be moved. If not, do nothing. This will likely save a lot of
979 * time when simply moving the tag to the "current" head revisions of a
980 * module -- which I have found to be a typical tagging operation.
982 rev = branch_mode ? RCS_magicrev (vers->srcfile, version) : version;
983 oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1,
985 if (oversion != NULL)
987 int isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
990 * if versions the same and neither old or new are branches don't have
993 if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
998 goto free_vars_and_return;
1001 if (!force_tag_move)
1003 /* we're NOT going to move the tag */
1004 cvs_output ("W ", 2);
1005 cvs_output (finfo->fullname, 0);
1006 cvs_output (" : ", 0);
1007 cvs_output (symtag, 0);
1008 cvs_output (" already exists on ", 0);
1009 cvs_output (isbranch ? "branch" : "version", 0);
1010 cvs_output (" ", 0);
1011 cvs_output (oversion, 0);
1012 cvs_output (" : NOT MOVING tag to ", 0);
1013 cvs_output (branch_mode ? "branch" : "version", 0);
1014 cvs_output (" ", 0);
1015 cvs_output (rev, 0);
1016 cvs_output ("\n", 1);
1020 goto free_vars_and_return;
1022 else /* force_tag_move == 1 and... */
1023 if ((isbranch && !disturb_branch_tags) ||
1024 (!isbranch && disturb_branch_tags))
1026 error(0,0, "%s: Not moving %s tag `%s' from %s to %s%s.",
1028 isbranch ? "branch" : "non-branch",
1029 symtag, oversion, rev,
1030 isbranch ? "" : " due to `-B' option");
1034 goto free_vars_and_return;
1039 if ((retcode = RCS_settag(vers->srcfile, symtag, rev)) != 0)
1041 error (1, retcode == -1 ? errno : 0,
1042 "failed to set tag %s to revision %s in %s",
1043 symtag, rev, vers->srcfile->path);
1047 goto free_vars_and_return;
1051 RCS_rewrite (vers->srcfile, NULL, NULL);
1053 /* more warm fuzzies */
1056 cvs_output ("T ", 2);
1057 cvs_output (finfo->fullname, 0);
1058 cvs_output ("\n", 1);
1061 free_vars_and_return:
1062 if (nversion != NULL)
1064 freevers_ts (&vers);
1069 * Print a warm fuzzy message
1073 tag_dirproc (callerdat, dir, repos, update_dir, entries)
1077 const char *update_dir;
1081 if (ignore_directory (update_dir))
1083 /* print the warm fuzzy message */
1085 error (0, 0, "Ignoring %s", update_dir);
1090 error (0, 0, "%s %s", delete_flag ? "Untagging" : "Tagging", update_dir);
1094 /* Code relating to the val-tags file. Note that this file has no way
1095 of knowing when a tag has been deleted. The problem is that there
1096 is no way of knowing whether a tag still exists somewhere, when we
1097 delete it some places. Using per-directory val-tags files (in
1098 CVSREP) might be better, but that might slow down the process of
1099 verifying that a tag is correct (maybe not, for the likely cases,
1100 if carefully done), and/or be harder to implement correctly. */
1107 static int val_fileproc PROTO ((void *callerdat, struct file_info *finfo));
1110 val_fileproc (callerdat, finfo)
1112 struct file_info *finfo;
1115 struct val_args *args = (struct val_args *)callerdat;
1118 if ((rcsdata = finfo->rcs) == NULL)
1119 /* Not sure this can happen, after all we passed only
1120 W_REPOS | W_ATTIC. */
1123 tag = RCS_gettag (rcsdata, args->name, 1, (int *) NULL);
1126 /* FIXME: should find out a way to stop the search at this point. */
1135 static Dtype val_direntproc PROTO ((void *, const char *, const char *,
1136 const char *, List *));
1139 val_direntproc (callerdat, dir, repository, update_dir, entries)
1142 const char *repository;
1143 const char *update_dir;
1146 /* This is not quite right--it doesn't get right the case of "cvs
1147 update -d -r foobar" where foobar is a tag which exists only in
1148 files in a directory which does not exist yet, but which is
1149 about to be created. */
1155 /* Check to see whether NAME is a valid tag. If so, return. If not
1156 print an error message and exit. ARGC, ARGV, LOCAL, and AFLAG specify
1157 which files we will be operating on.
1159 REPOSITORY is the repository if we need to cd into it, or NULL if
1160 we are already there, or "" if we should do a W_LOCAL recursion.
1161 Sorry for three cases, but the "" case is needed in case the
1162 working directories come from diverse parts of the repository, the
1163 NULL case avoids an unneccesary chdir, and the non-NULL, non-""
1164 case is needed for checkout, where we don't want to chdir if the
1165 tag is found in CVSROOTADM_VALTAGS, but there is not (yet) any
1168 tag_check_valid (name, argc, argv, local, aflag, repository)
1177 char *valtags_filename;
1180 struct val_args the_val_args;
1181 struct saved_cwd cwd;
1184 /* Numeric tags require only a syntactic check. */
1185 if (isdigit ((unsigned char) name[0]))
1188 for (p = name; *p != '\0'; ++p)
1190 if (!(isdigit ((unsigned char) *p) || *p == '.'))
1192 Numeric tag %s contains characters other than digits and '.'", name);
1197 /* Special tags are always valid. */
1198 if (strcmp (name, TAG_BASE) == 0
1199 || strcmp (name, TAG_HEAD) == 0)
1202 /* FIXME: This routine doesn't seem to do any locking whatsoever
1203 (and it is called from places which don't have locks in place).
1204 If two processes try to write val-tags at the same time, it would
1205 seem like we are in trouble. */
1208 mytag.dsize = strlen (name);
1210 valtags_filename = xmalloc (strlen (current_parsed_root->directory)
1212 + sizeof CVSROOTADM_VALTAGS + 3);
1213 sprintf (valtags_filename, "%s/%s/%s", current_parsed_root->directory,
1214 CVSROOTADM, CVSROOTADM_VALTAGS);
1215 db = dbm_open (valtags_filename, O_RDWR, 0666);
1218 if (!existence_error (errno))
1220 error (0, errno, "warning: cannot open %s read/write",
1222 db = dbm_open (valtags_filename, O_RDONLY, 0666);
1225 else if (!existence_error (errno))
1226 error (1, errno, "cannot read %s", valtags_filename);
1228 /* If the file merely fails to exist, we just keep going and create
1229 it later if need be. */
1235 val = dbm_fetch (db, mytag);
1236 if (val.dptr != NULL)
1238 /* Found. The tag is valid. */
1240 free (valtags_filename);
1243 /* FIXME: should check errors somehow (add dbm_error to myndbm.c?). */
1246 /* We didn't find the tag in val-tags, so look through all the RCS files
1247 to see whether it exists there. Yes, this is expensive, but there
1248 is no other way to cope with a tag which might have been created
1249 by an old version of CVS, from before val-tags was invented.
1251 Since we need this code anyway, we also use it to create
1252 entries in val-tags in general (that is, the val-tags entry
1253 will get created the first time the tag is used, not when the
1256 the_val_args.name = name;
1257 the_val_args.found = 0;
1259 which = W_REPOS | W_ATTIC;
1261 if (repository != NULL)
1263 if (repository[0] == '\0')
1267 if (save_cwd (&cwd))
1269 if (CVS_CHDIR (repository) < 0)
1270 error (1, errno, "cannot change to %s directory", repository);
1274 start_recursion (val_fileproc, (FILESDONEPROC) NULL,
1275 val_direntproc, (DIRLEAVEPROC) NULL,
1276 (void *)&the_val_args,
1277 argc, argv, local, which, aflag,
1278 CVS_LOCK_READ, NULL, 1, repository);
1279 if (repository != NULL && repository[0] != '\0')
1281 if (restore_cwd (&cwd, NULL))
1286 if (!the_val_args.found)
1287 error (1, 0, "no such tag %s", name);
1290 /* The tags is valid but not mentioned in val-tags. Add it. */
1293 if (noexec || nowrite)
1297 free (valtags_filename);
1304 omask = umask (cvsumask);
1305 db = dbm_open (valtags_filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
1306 (void)umask (omask);
1310 error (0, errno, "warning: cannot create %s", valtags_filename);
1311 free (valtags_filename);
1317 if (dbm_store (db, mytag, value, DBM_REPLACE) < 0)
1318 error (0, errno, "cannot store %s into %s", name,
1322 free (valtags_filename);
1326 * Check whether a join tag is valid. This is just like
1327 * tag_check_valid, but we must stop before the colon if there is one.
1331 tag_check_valid_join (join_tag, argc, argv, local, aflag, repository)
1341 c = xstrdup (join_tag);
1342 s = strchr (c, ':');
1345 if (isdigit ((unsigned char) join_tag[0]))
1347 "Numeric join tag %s may not contain a date specifier",
1351 /* hmmm... I think it makes sense to allow -j:<date>, but
1352 * for now this fixes a bug where CVS just spins and spins (I
1353 * think in the RCS code) looking for a zero length tag.
1357 "argument to join may not contain a date specifier without a tag");
1360 tag_check_valid (c, argc, argv, local, aflag, repository);