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 (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 (void *callerdat, struct file_info *finfo);
22 static int check_filesdoneproc (void *callerdat, int err,
23 const char *repos, const char *update_dir,
25 static int pretag_proc (const char *_repository, const char *_filter,
27 static void masterlist_delproc (Node *_p);
28 static void tag_delproc (Node *_p);
29 static int pretag_list_to_args_proc (Node *_p, void *_closure);
31 static Dtype tag_dirproc (void *callerdat, const char *dir,
32 const char *repos, const char *update_dir,
34 static int rtag_fileproc (void *callerdat, struct file_info *finfo);
35 static int rtag_delete (RCSNode *rcsfile);
36 static int tag_fileproc (void *callerdat, struct file_info *finfo);
38 static char *numtag; /* specific revision to tag */
39 static bool numtag_validated = false;
40 static char *date = NULL;
41 static char *symtag; /* tag to add or delete */
42 static bool delete_flag; /* adding a tag by default */
43 static bool branch_mode; /* make an automagic "branch" tag */
44 static bool disturb_branch_tags = false;/* allow -F,-d to disturb branch tags */
45 static bool force_tag_match = true; /* force tag to match by default */
46 static bool force_tag_move; /* don't force tag to move by default */
47 static bool check_uptodate; /* no uptodate-check by default */
48 static bool 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",
107 cvstag (int argc, char **argv)
109 bool local = false; /* recursive by default */
112 bool run_module_prog = true;
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 = true;
134 check_uptodate = true;
140 force_tag_move = true;
143 force_tag_match = false;
149 run_module_prog = false;
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, NULL, 0, local, run_module_prog,
272 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 (int argc, char **argv, char *xwhere, char *mwhere, char *mfile,
287 int shorten, int local_specified, char *mname, char *msg)
289 /* Begin section which is identical to patch_proc--should this
290 be abstracted out somehow? */
297 #ifdef HAVE_PRINTF_PTR
298 TRACE (TRACE_FUNCTION,
299 "rtag_proc (argc=%d, argv=%p, xwhere=%s,\n"
300 " mwhere=%s, mfile=%s, shorten=%d,\n"
301 " local_specified=%d, mname=%s, msg=%s)",
302 argc, (void *)argv, xwhere ? xwhere : "(null)",
303 mwhere ? mwhere : "(null)", mfile ? mfile : "(null)",
304 shorten, local_specified,
305 mname ? mname : "(null)", msg ? msg : "(null)" );
307 TRACE (TRACE_FUNCTION,
308 "rtag_proc (argc=%d, argv=%lx, xwhere=%s,\n"
309 " mwhere=%s, mfile=%s, shorten=%d,\n"
310 " local_specified=%d, mname=%s, msg=%s )",
311 argc, (unsigned long)argv, xwhere ? xwhere : "(null)",
312 mwhere ? mwhere : "(null)", mfile ? mfile : "(null)",
313 shorten, local_specified,
314 mname ? mname : "(null)", msg ? msg : "(null)" );
319 repository = xmalloc (strlen (current_parsed_root->directory)
321 + (mfile == NULL ? 0 : strlen (mfile) + 1)
323 (void) sprintf (repository, "%s/%s", current_parsed_root->directory,
325 where = xmalloc (strlen (argv[0])
326 + (mfile == NULL ? 0 : strlen (mfile) + 1)
328 (void) strcpy (where, argv[0]);
330 /* If MFILE isn't null, we need to set up to do only part of the
338 /* If the portion of the module is a path, put the dir part on
341 if ((cp = strrchr (mfile, '/')) != NULL)
344 (void) strcat (repository, "/");
345 (void) strcat (repository, mfile);
346 (void) strcat (where, "/");
347 (void) strcat (where, mfile);
351 /* take care of the rest */
352 path = xmalloc (strlen (repository) + strlen (mfile) + 5);
353 (void) sprintf (path, "%s/%s", repository, mfile);
356 /* directory means repository gets the dir tacked on */
357 (void) strcpy (repository, path);
358 (void) strcat (where, "/");
359 (void) strcat (where, mfile);
371 /* cd to the starting repository */
372 if (CVS_CHDIR (repository) < 0)
374 error (0, errno, "cannot chdir to %s", repository);
378 /* End section which is identical to patch_proc. */
380 if (delete_flag || attic_too || (force_tag_match && numtag))
381 which = W_REPOS | W_ATTIC;
392 if (numtag != NULL && !numtag_validated)
394 tag_check_valid (numtag, argc - 1, argv + 1, local_specified, 0,
396 numtag_validated = true;
399 /* check to make sure they are authorized to tag all the
400 specified files in the repository */
403 err = start_recursion (check_fileproc, check_filesdoneproc,
405 argc - 1, argv + 1, local_specified, which, 0,
406 CVS_LOCK_READ, where, 1, repository);
410 error (1, 0, "correct the above errors first!");
413 /* It would be nice to provide consistency with respect to
414 commits; however CVS lacks the infrastructure to do that (see
415 Concurrency in cvs.texinfo and comment in do_recursion). */
417 /* start the recursion processor */
418 err = start_recursion
419 (is_rtag ? rtag_fileproc : tag_fileproc,
420 NULL, tag_dirproc, NULL, NULL, argc - 1, argv + 1,
421 local_specified, which, 0, CVS_LOCK_WRITE, where, 1,
424 if (which & W_REPOS) free (repository);
432 /* check file that is to be tagged */
433 /* All we do here is add it to our list */
435 check_fileproc (void *callerdat, struct file_info *finfo)
444 TRACE (TRACE_FUNCTION, "check_fileproc (%s, %s, %s)",
445 finfo->repository ? finfo->repository : "(null)",
446 finfo->fullname ? finfo->fullname : "(null)",
447 finfo->rcs ? (finfo->rcs->path ? finfo->rcs->path : "(null)")
452 switch (Classify_File (finfo, NULL, NULL, NULL, 1, 0, &vers, 0))
466 error (0, 0, "%s is locally modified", finfo->fullname);
472 vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
474 if (finfo->update_dir[0] == '\0')
477 xdir = finfo->update_dir;
478 if ((p = findnode (mtlist, xdir)) != NULL)
480 tlist = ((struct master_lists *) p->data)->tlist;
484 struct master_lists *ml;
488 p->key = xstrdup (xdir);
490 ml = xmalloc (sizeof (struct master_lists));
493 p->delproc = masterlist_delproc;
494 (void) addnode (mtlist, p);
498 p->key = xstrdup (finfo->file);
500 p->delproc = tag_delproc;
501 if (vers->srcfile == NULL)
504 error (0, 0, "nothing known about %s", finfo->file);
510 /* Here we duplicate the calculation in tag_fileproc about which
511 version we are going to tag. There probably are some subtle races
512 (e.g. numtag is "foo" which gets moved between here and
514 p->data = ti = xmalloc (sizeof (struct tag_info));
515 if (!is_rtag && numtag == NULL && date == NULL)
516 ti->rev = xstrdup (vers->vn_user);
518 ti->rev = RCS_getversion (vers->srcfile, numtag, date,
519 force_tag_match, NULL);
523 ti->oldrev = RCS_getversion (vers->srcfile, symtag, NULL, 1, NULL);
525 if (ti->oldrev == NULL)
529 /* Deleting a tag which did not exist is a noop and
530 should not be logged. */
534 else if (delete_flag)
537 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
538 /* a hack since %v used to mean old or new rev */
539 ti->rev = xstrdup (ti->oldrev);
540 #else /* SUPPORT_OLD_INFO_FMT_STRINGS */
542 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
544 else if (strcmp(ti->oldrev, p->data) == 0)
546 else if (!force_tag_move)
557 (void)addnode (tlist, p);
563 struct pretag_proc_data {
571 check_filesdoneproc (void *callerdat, int err, const char *repos,
572 const char *update_dir, List *entries)
577 struct pretag_proc_data ppd;
579 p = findnode(mtlist, update_dir);
582 tlist = ((struct master_lists *) p->data)->tlist;
586 tlist = (List *) NULL;
588 if ((tlist == NULL) || (tlist->list->next == tlist->list))
594 ppd.delete_flag = delete_flag;
595 ppd.force_tag_move = force_tag_move;
597 if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, PIOPT_ALL, &ppd)) > 0)
599 error (0, 0, "Pre-tag check failed");
608 * called from Parse_Info, this routine processes a line that came out
609 * of a taginfo file and turns it into a command and executes it.
612 * the absolute value of the return value of run_exec, which may or
613 * may not be the return value of the child process. this is
614 * contrained to return positive values because Parse_Info is adding up
615 * return values and testing for non-zeroness to signify one or more
616 * of its callbacks having returned an error.
619 pretag_proc (const char *repository, const char *filter, void *closure)
621 char *newfilter = NULL;
623 const char *srepos = Short_Repository (repository);
624 struct pretag_proc_data *ppd = (struct pretag_proc_data *)closure;
626 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
627 if (!strchr(filter, '%'))
630 "warning: taginfo line contains no format strings:\n"
632 "Filling in old defaults ('%%t %%o %%p %%{sv}'), but please be aware that this\n"
633 "usage is deprecated.", filter);
634 newfilter = xmalloc (strlen(filter) + 16);
635 strcpy (newfilter, filter);
636 strcat (newfilter, " %t %o %p %{sv}");
639 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
641 /* %t = tag being added/moved/removed
642 * %o = operation = "add" | "mov" | "del"
643 * %b = branch mode = "?" (delete ops - unknown) | "T" (branch) | "N" (not branch)
644 * %p = path from $CVSROOT
645 * %r = path from root
646 * %{sVv} = attribute list = file name, old version tag will be deleted from,
647 * new version tag will be added to (or deleted from until
648 * SUPPORT_OLD_INFO_FMT_STRINGS is undefined)
650 cmdline = format_cmdline(
651 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
653 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
655 "t", "s", ppd->symtag,
656 "o", "s", ppd->delete_flag ? "del" :
657 ppd->force_tag_move ? "mov" : "add",
658 "b", "c", delete_flag ? '?' : branch_mode ? 'T' : 'N',
660 "r", "s", current_parsed_root->directory,
661 "sVv", ",", ppd->tlist, pretag_list_to_args_proc, (void *) NULL,
665 if (newfilter) free (newfilter);
667 if (!cmdline || !strlen (cmdline))
669 if (cmdline) free (cmdline);
670 error(0, 0, "pretag proc resolved to the empty string!");
676 /* FIXME - the old code used to run the following here:
680 * error (0, errno, "cannot find pre-tag filter '%s'", s);
685 * not sure this is really necessary. it might give a little finer grained
686 * error than letting the execution attempt fail but i'm not sure. in any
687 * case it should be easy enough to add a function in run.c to test its
688 * first arg for fileness & executability.
692 return abs (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL));
696 masterlist_delproc(Node *p)
698 struct master_lists *ml = p->data;
711 ti = (struct tag_info *) p->data;
712 if (ti->oldrev) free (ti->oldrev);
713 if (ti->rev) free (ti->rev);
720 /* to be passed into walklist with a list of tags
722 * p->data = struct tag_info *
723 * p->data->oldrev = rev tag will be deleted from
724 * p->data->rev = rev tag will be added to
726 * closure will be a struct format_cmdline_walklist_closure
727 * where closure is undefined
730 pretag_list_to_args_proc(Node *p, void *closure)
732 struct tag_info *taginfo = (struct tag_info *)p->data;
733 struct format_cmdline_walklist_closure *c =
734 (struct format_cmdline_walklist_closure *)closure;
740 if (p->data == NULL) return 1;
744 /* foreach requested attribute */
753 arg = taginfo->rev ? taginfo->rev : "NONE";
756 arg = taginfo->oldrev ? taginfo->oldrev : "NONE";
760 "Unknown format character or not a list attribute: %c",
764 /* copy the attribute into an argument */
767 arg = cmdlineescape (c->quotes, arg);
771 arg = cmdlinequote ('"', arg);
775 expand_string (c->buf, c->length, doff + strlen (arg));
777 strncpy (d, arg, strlen (arg));
782 /* and always put the extra space on. we'll have to back up a char when we're
783 * done, but that seems most efficient
786 expand_string (c->buf, c->length, doff + 1);
790 /* correct our original pointer into the buff */
797 * Called to rtag a particular file, as appropriate with the options that were
802 rtag_fileproc (void *callerdat, struct file_info *finfo)
808 /* find the parsed RCS data */
809 if ((rcsfile = finfo->rcs) == NULL)
813 * For tagging an RCS file which is a symbolic link, you'd best be
814 * running with RCS 5.6, since it knows how to handle symbolic links
815 * correctly without breaking your link!
819 return rtag_delete (rcsfile);
822 * If we get here, we are adding a tag. But, if -a was specified, we
823 * need to check to see if a -r or -D option was specified. If neither
824 * was specified and the file is in the Attic, remove the tag.
826 if (attic_too && (!numtag && !date))
828 if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
829 return rtag_delete (rcsfile);
832 version = RCS_getversion (rcsfile, numtag, date, force_tag_match, NULL);
835 /* If -a specified, clean up any old tags */
837 (void)rtag_delete (rcsfile);
839 if (!quiet && !force_tag_match)
841 error (0, 0, "cannot find tag `%s' in `%s'",
842 numtag ? numtag : "head", rcsfile->path);
848 && isdigit ((unsigned char)*numtag)
849 && strcmp (numtag, version) != 0)
853 * We didn't find a match for the numeric tag that was specified, but
854 * that's OK. just pass the numeric tag on to rcs, to be tagged as
855 * specified. Could get here if one tried to tag "1.1.1" and there
856 * was a 1.1.1 branch with some head revision. In this case, we want
857 * the tag to reference "1.1.1" and not the revision at the head of
858 * the branch. Use a symbolic tag for that.
860 rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag;
861 retcode = RCS_settag(rcsfile, symtag, numtag);
863 RCS_rewrite (rcsfile, NULL, NULL);
870 * As an enhancement for the case where a tag is being re-applied to
871 * a large body of a module, make one extra call to RCS_getversion to
872 * see if the tag is already set in the RCS file. If so, check to
873 * see if it needs to be moved. If not, do nothing. This will
874 * likely save a lot of time when simply moving the tag to the
875 * "current" head revisions of a module -- which I have found to be a
876 * typical tagging operation.
878 rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
879 oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1,
881 if (oversion != NULL)
883 int isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
886 * if versions the same and neither old or new are branches don't
887 * have to do anything
889 if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
898 /* we're NOT going to move the tag */
899 (void)printf ("W %s", finfo->fullname);
901 (void)printf (" : %s already exists on %s %s",
902 symtag, isbranch ? "branch" : "version",
904 (void)printf (" : NOT MOVING tag to %s %s\n",
905 branch_mode ? "branch" : "version", rev);
908 if (branch_mode) free (rev);
911 else /* force_tag_move is set and... */
912 if ((isbranch && !disturb_branch_tags) ||
913 (!isbranch && disturb_branch_tags))
915 error(0,0, "%s: Not moving %s tag `%s' from %s to %s%s.",
917 isbranch ? "branch" : "non-branch",
918 symtag, oversion, rev,
919 isbranch ? "" : " due to `-B' option");
920 if (branch_mode) free(rev);
927 retcode = RCS_settag(rcsfile, symtag, rev);
929 RCS_rewrite (rcsfile, NULL, NULL);
934 error (1, retcode == -1 ? errno : 0,
935 "failed to set tag `%s' to revision `%s' in `%s'",
936 symtag, rev, rcsfile->path);
951 * If -d is specified, "force_tag_match" is set, so that this call to
952 * RCS_getversion() will return a NULL version string if the symbolic
953 * tag does not exist in the RCS file.
955 * If the -r flag was used, numtag is set, and we only delete the
956 * symtag from files that have numtag.
958 * This is done here because it's MUCH faster than just blindly calling
959 * "rcs" to remove the tag... trust me.
962 rtag_delete (RCSNode *rcsfile)
965 int retcode, isbranch;
969 version = RCS_getversion (rcsfile, numtag, (char *) NULL, 1,
976 version = RCS_getversion (rcsfile, symtag, NULL, 1, NULL);
982 isbranch = RCS_nodeisbranch (rcsfile, symtag);
983 if ((isbranch && !disturb_branch_tags) ||
984 (!isbranch && disturb_branch_tags))
988 "Not removing %s tag `%s' from `%s'%s.",
989 isbranch ? "branch" : "non-branch",
990 symtag, rcsfile->path,
991 isbranch ? "" : " due to `-B' option");
995 if ((retcode = RCS_deltag(rcsfile, symtag)) != 0)
998 error (0, retcode == -1 ? errno : 0,
999 "failed to remove tag `%s' from `%s'", symtag,
1003 RCS_rewrite (rcsfile, NULL, NULL);
1010 * Called to tag a particular file (the currently checked out version is
1011 * tagged with the specified tag - or the specified tag is deleted).
1015 tag_fileproc (void *callerdat, struct file_info *finfo)
1017 char *version, *oversion;
1018 char *nversion = NULL;
1024 vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
1026 if ((numtag != NULL) || (date != NULL))
1028 nversion = RCS_getversion(vers->srcfile,
1033 if (nversion == NULL)
1034 goto free_vars_and_return;
1041 * If -d is specified, "force_tag_match" is set, so that this call to
1042 * RCS_getversion() will return a NULL version string if the symbolic
1043 * tag does not exist in the RCS file.
1045 * This is done here because it's MUCH faster than just blindly calling
1046 * "rcs" to remove the tag... trust me.
1049 version = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1,
1051 if (version == NULL || vers->srcfile == NULL)
1052 goto free_vars_and_return;
1056 isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
1057 if ((isbranch && !disturb_branch_tags) ||
1058 (!isbranch && disturb_branch_tags))
1062 "Not removing %s tag `%s' from `%s'%s.",
1063 isbranch ? "branch" : "non-branch",
1064 symtag, vers->srcfile->path,
1065 isbranch ? "" : " due to `-B' option");
1067 goto free_vars_and_return;
1070 if ((retcode = RCS_deltag(vers->srcfile, symtag)) != 0)
1073 error (0, retcode == -1 ? errno : 0,
1074 "failed to remove tag %s from %s", symtag,
1075 vers->srcfile->path);
1077 goto free_vars_and_return;
1079 RCS_rewrite (vers->srcfile, NULL, NULL);
1084 cvs_output ("D ", 2);
1085 cvs_output (finfo->fullname, 0);
1086 cvs_output ("\n", 1);
1089 goto free_vars_and_return;
1093 * If we are adding a tag, we need to know which version we have checked
1094 * out and we'll tag that version.
1096 if (nversion == NULL)
1098 version = vers->vn_user;
1104 if (version == NULL)
1106 goto free_vars_and_return;
1108 else if (strcmp (version, "0") == 0)
1111 error (0, 0, "couldn't tag added but un-commited file `%s'", finfo->file);
1112 goto free_vars_and_return;
1114 else if (version[0] == '-')
1117 error (0, 0, "skipping removed but un-commited file `%s'", finfo->file);
1118 goto free_vars_and_return;
1120 else if (vers->srcfile == NULL)
1123 error (0, 0, "cannot find revision control file for `%s'", finfo->file);
1124 goto free_vars_and_return;
1128 * As an enhancement for the case where a tag is being re-applied to a
1129 * large number of files, make one extra call to RCS_getversion to see
1130 * if the tag is already set in the RCS file. If so, check to see if it
1131 * needs to be moved. If not, do nothing. This will likely save a lot of
1132 * time when simply moving the tag to the "current" head revisions of a
1133 * module -- which I have found to be a typical tagging operation.
1135 rev = branch_mode ? RCS_magicrev (vers->srcfile, version) : version;
1136 oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1,
1138 if (oversion != NULL)
1140 int isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
1143 * if versions the same and neither old or new are branches don't have
1146 if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
1151 goto free_vars_and_return;
1154 if (!force_tag_move)
1156 /* we're NOT going to move the tag */
1157 cvs_output ("W ", 2);
1158 cvs_output (finfo->fullname, 0);
1159 cvs_output (" : ", 0);
1160 cvs_output (symtag, 0);
1161 cvs_output (" already exists on ", 0);
1162 cvs_output (isbranch ? "branch" : "version", 0);
1163 cvs_output (" ", 0);
1164 cvs_output (oversion, 0);
1165 cvs_output (" : NOT MOVING tag to ", 0);
1166 cvs_output (branch_mode ? "branch" : "version", 0);
1167 cvs_output (" ", 0);
1168 cvs_output (rev, 0);
1169 cvs_output ("\n", 1);
1173 goto free_vars_and_return;
1175 else /* force_tag_move == 1 and... */
1176 if ((isbranch && !disturb_branch_tags) ||
1177 (!isbranch && disturb_branch_tags))
1179 error(0,0, "%s: Not moving %s tag `%s' from %s to %s%s.",
1181 isbranch ? "branch" : "non-branch",
1182 symtag, oversion, rev,
1183 isbranch ? "" : " due to `-B' option");
1187 goto free_vars_and_return;
1192 if ((retcode = RCS_settag(vers->srcfile, symtag, rev)) != 0)
1194 error (1, retcode == -1 ? errno : 0,
1195 "failed to set tag %s to revision %s in %s",
1196 symtag, rev, vers->srcfile->path);
1200 goto free_vars_and_return;
1204 RCS_rewrite (vers->srcfile, NULL, NULL);
1206 /* more warm fuzzies */
1209 cvs_output ("T ", 2);
1210 cvs_output (finfo->fullname, 0);
1211 cvs_output ("\n", 1);
1214 free_vars_and_return:
1215 if (nversion != NULL)
1217 freevers_ts (&vers);
1224 * Print a warm fuzzy message
1228 tag_dirproc (void *callerdat, const char *dir, const char *repos,
1229 const char *update_dir, List *entries)
1232 if (ignore_directory (update_dir))
1234 /* print the warm fuzzy message */
1236 error (0, 0, "Ignoring %s", update_dir);
1241 error (0, 0, "%s %s", delete_flag ? "Untagging" : "Tagging",
1248 /* Code relating to the val-tags file. Note that this file has no way
1249 of knowing when a tag has been deleted. The problem is that there
1250 is no way of knowing whether a tag still exists somewhere, when we
1251 delete it some places. Using per-directory val-tags files (in
1252 CVSREP) might be better, but that might slow down the process of
1253 verifying that a tag is correct (maybe not, for the likely cases,
1254 if carefully done), and/or be harder to implement correctly. */
1261 static int val_fileproc (void *callerdat, struct file_info *finfo);
1264 val_fileproc (void *callerdat, struct file_info *finfo)
1267 struct val_args *args = (struct val_args *)callerdat;
1270 if ((rcsdata = finfo->rcs) == NULL)
1271 /* Not sure this can happen, after all we passed only
1272 W_REPOS | W_ATTIC. */
1275 tag = RCS_gettag (rcsdata, args->name, 1, (int *) NULL);
1278 /* FIXME: should find out a way to stop the search at this point. */
1288 val_direntproc (void *callerdat, const char *dir, const char *repository,
1289 const char *update_dir, List *entries)
1291 /* This is not quite right--it doesn't get right the case of "cvs
1292 update -d -r foobar" where foobar is a tag which exists only in
1293 files in a directory which does not exist yet, but which is
1294 about to be created. */
1300 /* Check to see whether NAME is a valid tag. If so, return. If not
1301 print an error message and exit. ARGC, ARGV, LOCAL, and AFLAG specify
1302 which files we will be operating on.
1304 REPOSITORY is the repository if we need to cd into it, or NULL if
1305 we are already there, or "" if we should do a W_LOCAL recursion.
1306 Sorry for three cases, but the "" case is needed in case the
1307 working directories come from diverse parts of the repository, the
1308 NULL case avoids an unneccesary chdir, and the non-NULL, non-""
1309 case is needed for checkout, where we don't want to chdir if the
1310 tag is found in CVSROOTADM_VALTAGS, but there is not (yet) any
1313 tag_check_valid (char *name, int argc, char **argv, int local, int aflag,
1317 char *valtags_filename;
1320 struct val_args the_val_args;
1321 struct saved_cwd cwd;
1324 #ifdef HAVE_PRINTF_PTR
1325 TRACE ( TRACE_FUNCTION,
1326 "tag_check_valid ( name=%s, argc=%d, argv=%p, local=%d,\n"
1327 " aflag=%d, repository=%s )",
1328 name ? name : "(name)", argc, (void *)argv, local, aflag,
1329 repository ? repository : "(null)" );
1331 TRACE ( TRACE_FUNCTION,
1332 "tag_check_valid ( name=%s, argc=%d, argv=%lx, local=%d,\n"
1333 " aflag=%d, repository=%s )",
1334 name ? name : "(name)", argc, (unsigned long)argv, local, aflag,
1335 repository ? repository : "(null)" );
1338 /* Numeric tags require only a syntactic check. */
1339 if (isdigit ((unsigned char) name[0]))
1342 for (p = name; *p != '\0'; ++p)
1344 if (!(isdigit ((unsigned char) *p) || *p == '.'))
1346 Numeric tag %s contains characters other than digits and '.'", name);
1351 /* Special tags are always valid. */
1352 if (strcmp (name, TAG_BASE) == 0
1353 || strcmp (name, TAG_HEAD) == 0)
1356 /* FIXME: This routine doesn't seem to do any locking whatsoever
1357 (and it is called from places which don't have locks in place).
1358 If two processes try to write val-tags at the same time, it would
1359 seem like we are in trouble. */
1362 mytag.dsize = strlen (name);
1364 valtags_filename = xmalloc (strlen (current_parsed_root->directory)
1366 + sizeof CVSROOTADM_VALTAGS + 3);
1367 sprintf (valtags_filename, "%s/%s/%s", current_parsed_root->directory,
1368 CVSROOTADM, CVSROOTADM_VALTAGS);
1369 db = dbm_open (valtags_filename, O_RDWR, 0666);
1372 if (!existence_error (errno))
1374 error (0, errno, "warning: cannot open %s read/write",
1376 db = dbm_open (valtags_filename, O_RDONLY, 0666);
1379 else if (!existence_error (errno))
1380 error (1, errno, "cannot read %s", valtags_filename);
1382 /* If the file merely fails to exist, we just keep going and create
1383 it later if need be. */
1389 val = dbm_fetch (db, mytag);
1390 if (val.dptr != NULL)
1392 /* Found. The tag is valid. */
1394 free (valtags_filename);
1397 /* FIXME: should check errors somehow (add dbm_error to myndbm.c?). */
1400 /* We didn't find the tag in val-tags, so look through all the RCS files
1401 to see whether it exists there. Yes, this is expensive, but there
1402 is no other way to cope with a tag which might have been created
1403 by an old version of CVS, from before val-tags was invented.
1405 Since we need this code anyway, we also use it to create
1406 entries in val-tags in general (that is, the val-tags entry
1407 will get created the first time the tag is used, not when the
1410 the_val_args.name = name;
1411 the_val_args.found = 0;
1413 which = W_REPOS | W_ATTIC;
1415 if (repository == NULL || repository[0] == '\0')
1419 if (save_cwd (&cwd))
1420 exit (EXIT_FAILURE);
1421 if (CVS_CHDIR (repository) < 0)
1422 error (1, errno, "cannot change to %s directory", repository);
1426 (val_fileproc, NULL, val_direntproc, NULL,
1427 &the_val_args, argc, argv, local, which, aflag,
1428 CVS_LOCK_READ, NULL, 1, repository);
1429 if (repository != NULL && repository[0] != '\0')
1431 if (restore_cwd (&cwd, NULL))
1432 exit (EXIT_FAILURE);
1436 if (!the_val_args.found)
1437 error (1, 0, "no such tag %s", name);
1440 /* The tags is valid but not mentioned in val-tags. Add it. */
1443 if (noexec || nowrite)
1447 free (valtags_filename);
1454 omask = umask (cvsumask);
1455 db = dbm_open (valtags_filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
1456 (void)umask (omask);
1460 error (0, errno, "warning: cannot create %s", valtags_filename);
1461 free (valtags_filename);
1467 if (dbm_store (db, mytag, value, DBM_REPLACE) < 0)
1468 error (0, errno, "cannot store %s into %s", name,
1472 free (valtags_filename);
1476 * Check whether a join tag is valid. This is just like
1477 * tag_check_valid, but we must stop before the colon if there is one.
1481 tag_check_valid_join (char *join_tag, int argc, char **argv, int local, int aflag, char *repository)
1485 c = xstrdup (join_tag);
1486 s = strchr (c, ':');
1489 if (isdigit ((unsigned char) join_tag[0]))
1491 "Numeric join tag %s may not contain a date specifier",
1495 /* hmmm... I think it makes sense to allow -j:<date>, but
1496 * for now this fixes a bug where CVS just spins and spins (I
1497 * think in the RCS code) looking for a zero length tag.
1501 "argument to join may not contain a date specifier without a tag");
1504 tag_check_valid (c, argc, argv, local, aflag, repository);