2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution.
15 * Add or delete a symbolic name to an RCS file, or a collection of RCS files.
16 * Tag uses the checked out revision in the current directory, rtag uses
17 * the modules database, if necessary.
23 static int rtag_proc (int argc
, char **argv
, char *xwhere
,
24 char *mwhere
, char *mfile
, int shorten
,
25 int local_specified
, char *mname
, char *msg
);
26 static int check_fileproc (void *callerdat
, struct file_info
*finfo
);
27 static int check_filesdoneproc (void *callerdat
, int err
,
28 const char *repos
, const char *update_dir
,
30 static int pretag_proc (const char *_repository
, const char *_filter
,
32 static void masterlist_delproc (Node
*_p
);
33 static void tag_delproc (Node
*_p
);
34 static int pretag_list_to_args_proc (Node
*_p
, void *_closure
);
36 static Dtype
tag_dirproc (void *callerdat
, const char *dir
,
37 const char *repos
, const char *update_dir
,
39 static int rtag_fileproc (void *callerdat
, struct file_info
*finfo
);
40 static int rtag_delete (RCSNode
*rcsfile
);
41 static int tag_fileproc (void *callerdat
, struct file_info
*finfo
);
43 static char *numtag
; /* specific revision to tag */
44 static bool numtag_validated
= false;
45 static char *date
= NULL
;
46 static char *symtag
; /* tag to add or delete */
47 static bool delete_flag
; /* adding a tag by default */
48 static bool branch_mode
; /* make an automagic "branch" tag */
49 static bool disturb_branch_tags
= false;/* allow -F,-d to disturb branch tags */
50 static bool force_tag_match
= true; /* force tag to match by default */
51 static bool force_tag_move
; /* don't force tag to move by default */
52 static bool check_uptodate
; /* no uptodate-check by default */
53 static bool attic_too
; /* remove tag from Attic files */
72 static const char rtag_opts
[] = "+aBbdFflnQqRr:D:";
73 static const char *const rtag_usage
[] =
75 "Usage: %s %s [-abdFflnR] [-r rev|-D date] tag modules...\n",
76 "\t-a\tClear tag from removed files that would not otherwise be tagged.\n",
77 "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
78 "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n",
79 "\t-d\tDelete the given tag.\n",
80 "\t-F\tMove tag if it already exists.\n",
81 "\t-f\tForce a head revision match if tag/date not found.\n",
82 "\t-l\tLocal directory only, not recursive.\n",
83 "\t-n\tNo execution of 'tag program'.\n",
84 "\t-R\tProcess directories recursively.\n",
85 "\t-r rev\tExisting revision/tag.\n",
86 "\t-D\tExisting date.\n",
87 "(Specify the --help global option for a list of other help options)\n",
91 static const char tag_opts
[] = "+BbcdFflQqRr:D:";
92 static const char *const tag_usage
[] =
94 "Usage: %s %s [-bcdFflR] [-r rev|-D date] tag [files...]\n",
95 "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
96 "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n",
97 "\t-c\tCheck that working files are unmodified.\n",
98 "\t-d\tDelete the given tag.\n",
99 "\t-F\tMove tag if it already exists.\n",
100 "\t-f\tForce a head revision match if tag/date not found.\n",
101 "\t-l\tLocal directory only, not recursive.\n",
102 "\t-R\tProcess directories recursively.\n",
103 "\t-r rev\tExisting revision/tag.\n",
104 "\t-D\tExisting date.\n",
105 "(Specify the --help global option for a list of other help options)\n",
112 cvstag (int argc
, char **argv
)
114 bool local
= false; /* recursive by default */
117 bool run_module_prog
= true;
119 is_rtag
= (strcmp (cvs_cmd_name
, "rtag") == 0);
122 usage (is_rtag
? rtag_usage
: tag_usage
);
125 while ((c
= getopt (argc
, argv
, is_rtag
? rtag_opts
: tag_opts
)) != -1)
136 disturb_branch_tags
= true;
139 check_uptodate
= true;
145 force_tag_move
= true;
148 force_tag_match
= false;
154 run_module_prog
= false;
158 /* The CVS 1.5 client sends these options (in addition to
159 Global_option requests), so we must ignore them. */
162 "-q or -Q must be specified before \"%s\"",
169 parse_tagdate (&numtag
, &date
, optarg
);
172 if (date
) free (date
);
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
);
190 if (date
&& delete_flag
)
191 error (1, 0, "-d makes no sense with a date specification.");
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
, NULL
, 0, local
, run_module_prog
,
274 err
= rtag_proc (argc
+ 1, argv
- 1, NULL
, NULL
, NULL
, 0, local
, NULL
,
283 struct pretag_proc_data
{
291 * called from Parse_Info, this routine processes a line that came out
292 * of the posttag file and turns it into a command and executes it.
295 * the absolute value of the return value of run_exec, which may or
296 * may not be the return value of the child process. this is
297 * contrained to return positive values because Parse_Info is summing
298 * return values and testing for non-zeroness to signify one or more
299 * of its callbacks having returned an error.
302 posttag_proc (const char *repository
, const char *filter
, void *closure
)
305 const char *srepos
= Short_Repository (repository
);
306 struct pretag_proc_data
*ppd
= closure
;
308 /* %t = tag being added/moved/removed
309 * %o = operation = "add" | "mov" | "del"
310 * %b = branch mode = "?" (delete ops - unknown) | "T" (branch)
313 * %p = path from $CVSROOT
314 * %r = path from root
315 * %{sVv} = attribute list = file name, old version tag will be deleted
316 * from, new version tag will be added to (or
318 * SUPPORT_OLD_INFO_FMT_STRINGS is undefined).
321 * Cast any NULL arguments as appropriate pointers as this is an
322 * stdarg function and we need to be certain the caller gets what
325 cmdline
= format_cmdline (
326 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
328 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
330 "t", "s", ppd
->symtag
,
331 "o", "s", ppd
->delete_flag
332 ? "del" : ppd
->force_tag_move
? "mov" : "add",
333 "b", "c", delete_flag
334 ? '?' : branch_mode
? 'T' : 'N',
335 "c", "s", cvs_cmd_name
,
336 #ifdef SERVER_SUPPORT
337 "R", "s", referrer
? referrer
->original
: "NONE",
338 #endif /* SERVER_SUPPORT */
340 "r", "s", current_parsed_root
->directory
,
341 "sVv", ",", ppd
->tlist
,
342 pretag_list_to_args_proc
, (void *) NULL
,
345 if (!cmdline
|| !strlen (cmdline
))
347 if (cmdline
) free (cmdline
);
348 error (0, 0, "pretag proc resolved to the empty string!");
355 return abs (run_exec (RUN_TTY
, RUN_TTY
, RUN_TTY
, RUN_NORMAL
));
361 * Call any postadmin procs.
364 tag_filesdoneproc (void *callerdat
, int err
, const char *repository
,
365 const char *update_dir
, List
*entries
)
368 List
*mtlist
, *tlist
;
369 struct pretag_proc_data ppd
;
371 TRACE (TRACE_FUNCTION
, "tag_filesdoneproc (%d, %s, %s)", err
, repository
,
375 p
= findnode (mtlist
, update_dir
);
377 tlist
= ((struct master_lists
*) p
->data
)->tlist
;
380 if (tlist
== NULL
|| tlist
->list
->next
== tlist
->list
)
384 ppd
.delete_flag
= delete_flag
;
385 ppd
.force_tag_move
= force_tag_move
;
387 Parse_Info (CVSROOTADM_POSTTAG
, repository
, posttag_proc
,
396 * callback proc for doing the real work of tagging
400 rtag_proc (int argc
, char **argv
, char *xwhere
, char *mwhere
, char *mfile
,
401 int shorten
, int local_specified
, char *mname
, char *msg
)
403 /* Begin section which is identical to patch_proc--should this
404 be abstracted out somehow? */
411 #ifdef HAVE_PRINTF_PTR
412 TRACE (TRACE_FUNCTION
,
413 "rtag_proc (argc=%d, argv=%p, xwhere=%s,\n"
414 " mwhere=%s, mfile=%s, shorten=%d,\n"
415 " local_specified=%d, mname=%s, msg=%s)",
416 argc
, (void *)argv
, xwhere
? xwhere
: "(null)",
417 mwhere
? mwhere
: "(null)", mfile
? mfile
: "(null)",
418 shorten
, local_specified
,
419 mname
? mname
: "(null)", msg
? msg
: "(null)" );
421 TRACE (TRACE_FUNCTION
,
422 "rtag_proc (argc=%d, argv=%lx, xwhere=%s,\n"
423 " mwhere=%s, mfile=%s, shorten=%d,\n"
424 " local_specified=%d, mname=%s, msg=%s )",
425 argc
, (unsigned long)argv
, xwhere
? xwhere
: "(null)",
426 mwhere
? mwhere
: "(null)", mfile
? mfile
: "(null)",
427 shorten
, local_specified
,
428 mname
? mname
: "(null)", msg
? msg
: "(null)" );
433 repository
= xmalloc (strlen (current_parsed_root
->directory
)
435 + (mfile
== NULL
? 0 : strlen (mfile
) + 1)
437 (void) sprintf (repository
, "%s/%s", current_parsed_root
->directory
,
439 where
= xmalloc (strlen (argv
[0])
440 + (mfile
== NULL
? 0 : strlen (mfile
) + 1)
442 (void) strcpy (where
, argv
[0]);
444 /* If MFILE isn't null, we need to set up to do only part of the
452 /* If the portion of the module is a path, put the dir part on
455 if ((cp
= strrchr (mfile
, '/')) != NULL
)
458 (void) strcat (repository
, "/");
459 (void) strcat (repository
, mfile
);
460 (void) strcat (where
, "/");
461 (void) strcat (where
, mfile
);
465 /* take care of the rest */
466 path
= xmalloc (strlen (repository
) + strlen (mfile
) + 5);
467 (void) sprintf (path
, "%s/%s", repository
, mfile
);
470 /* directory means repository gets the dir tacked on */
471 (void) strcpy (repository
, path
);
472 (void) strcat (where
, "/");
473 (void) strcat (where
, mfile
);
485 /* cd to the starting repository */
486 if (CVS_CHDIR (repository
) < 0)
488 error (0, errno
, "cannot chdir to %s", repository
);
493 /* End section which is identical to patch_proc. */
495 if (delete_flag
|| attic_too
|| (force_tag_match
&& numtag
))
496 which
= W_REPOS
| W_ATTIC
;
507 if (numtag
!= NULL
&& !numtag_validated
)
509 tag_check_valid (numtag
, argc
- 1, argv
+ 1, local_specified
, 0,
511 numtag_validated
= true;
514 /* check to make sure they are authorized to tag all the
515 specified files in the repository */
518 err
= start_recursion (check_fileproc
, check_filesdoneproc
,
520 argc
- 1, argv
+ 1, local_specified
, which
, 0,
521 CVS_LOCK_READ
, where
, 1, repository
);
525 error (1, 0, "correct the above errors first!");
528 /* It would be nice to provide consistency with respect to
529 commits; however CVS lacks the infrastructure to do that (see
530 Concurrency in cvs.texinfo and comment in do_recursion). */
532 /* start the recursion processor */
533 err
= start_recursion
534 (is_rtag
? rtag_fileproc
: tag_fileproc
,
535 tag_filesdoneproc
, tag_dirproc
, NULL
, mtlist
, argc
- 1, argv
+ 1,
536 local_specified
, which
, 0, CVS_LOCK_WRITE
, where
, 1,
539 if (which
& W_REPOS
) free (repository
);
547 /* check file that is to be tagged */
548 /* All we do here is add it to our list */
550 check_fileproc (void *callerdat
, struct file_info
*finfo
)
559 TRACE (TRACE_FUNCTION
, "check_fileproc (%s, %s, %s)",
560 finfo
->repository
? finfo
->repository
: "(null)",
561 finfo
->fullname
? finfo
->fullname
: "(null)",
562 finfo
->rcs
? (finfo
->rcs
->path
? finfo
->rcs
->path
: "(null)")
567 switch (Classify_File (finfo
, NULL
, NULL
, NULL
, 1, 0, &vers
, 0))
581 error (0, 0, "%s is locally modified", finfo
->fullname
);
587 vers
= Version_TS (finfo
, NULL
, NULL
, NULL
, 0, 0);
589 if (finfo
->update_dir
[0] == '\0')
592 xdir
= finfo
->update_dir
;
593 if ((p
= findnode (mtlist
, xdir
)) != NULL
)
595 tlist
= ((struct master_lists
*) p
->data
)->tlist
;
599 struct master_lists
*ml
;
603 p
->key
= xstrdup (xdir
);
605 ml
= xmalloc (sizeof (struct master_lists
));
608 p
->delproc
= masterlist_delproc
;
609 (void) addnode (mtlist
, p
);
613 p
->key
= xstrdup (finfo
->file
);
615 p
->delproc
= tag_delproc
;
616 if (vers
->srcfile
== NULL
)
619 error (0, 0, "nothing known about %s", finfo
->file
);
625 /* Here we duplicate the calculation in tag_fileproc about which
626 version we are going to tag. There probably are some subtle races
627 (e.g. numtag is "foo" which gets moved between here and
629 p
->data
= ti
= xmalloc (sizeof (struct tag_info
));
630 ti
->tag
= xstrdup (numtag
? numtag
: vers
->tag
);
631 if (!is_rtag
&& numtag
== NULL
&& date
== NULL
)
632 ti
->rev
= xstrdup (vers
->vn_user
);
634 ti
->rev
= RCS_getversion (vers
->srcfile
, numtag
, date
,
635 force_tag_match
, NULL
);
639 ti
->oldrev
= RCS_getversion (vers
->srcfile
, symtag
, NULL
, 1, NULL
);
641 if (ti
->oldrev
== NULL
)
645 /* Deleting a tag which did not exist is a noop and
646 should not be logged. */
650 else if (delete_flag
)
653 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
654 /* a hack since %v used to mean old or new rev */
655 ti
->rev
= xstrdup (ti
->oldrev
);
656 #else /* SUPPORT_OLD_INFO_FMT_STRINGS */
658 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
660 else if (strcmp(ti
->oldrev
, p
->data
) == 0)
662 else if (!force_tag_move
)
673 (void)addnode (tlist
, p
);
680 check_filesdoneproc (void *callerdat
, int err
, const char *repos
,
681 const char *update_dir
, List
*entries
)
686 struct pretag_proc_data ppd
;
688 p
= findnode (mtlist
, update_dir
);
690 tlist
= ((struct master_lists
*) p
->data
)->tlist
;
693 if (tlist
== NULL
|| tlist
->list
->next
== tlist
->list
)
697 ppd
.delete_flag
= delete_flag
;
698 ppd
.force_tag_move
= force_tag_move
;
700 if ((n
= Parse_Info (CVSROOTADM_TAGINFO
, repos
, pretag_proc
, PIOPT_ALL
,
703 error (0, 0, "Pre-tag check failed");
712 * called from Parse_Info, this routine processes a line that came out
713 * of a taginfo file and turns it into a command and executes it.
716 * the absolute value of the return value of run_exec, which may or
717 * may not be the return value of the child process. this is
718 * contrained to return positive values because Parse_Info is adding up
719 * return values and testing for non-zeroness to signify one or more
720 * of its callbacks having returned an error.
723 pretag_proc (const char *repository
, const char *filter
, void *closure
)
725 char *newfilter
= NULL
;
727 const char *srepos
= Short_Repository (repository
);
728 struct pretag_proc_data
*ppd
= closure
;
730 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
731 if (!strchr (filter
, '%'))
734 "warning: taginfo line contains no format strings:\n"
736 "Filling in old defaults ('%%t %%o %%p %%{sv}'), but please be aware that this\n"
737 "usage is deprecated.", filter
);
738 newfilter
= xmalloc (strlen (filter
) + 16);
739 strcpy (newfilter
, filter
);
740 strcat (newfilter
, " %t %o %p %{sv}");
743 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
745 /* %t = tag being added/moved/removed
746 * %o = operation = "add" | "mov" | "del"
747 * %b = branch mode = "?" (delete ops - unknown) | "T" (branch)
750 * %p = path from $CVSROOT
751 * %r = path from root
752 * %{sVv} = attribute list = file name, old version tag will be deleted
753 * from, new version tag will be added to (or
755 * SUPPORT_OLD_INFO_FMT_STRINGS is undefined)
758 * Cast any NULL arguments as appropriate pointers as this is an
759 * stdarg function and we need to be certain the caller gets what
762 cmdline
= format_cmdline (
763 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
765 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
767 "t", "s", ppd
->symtag
,
768 "o", "s", ppd
->delete_flag
? "del" :
769 ppd
->force_tag_move
? "mov" : "add",
770 "b", "c", delete_flag
771 ? '?' : branch_mode
? 'T' : 'N',
772 "c", "s", cvs_cmd_name
,
773 #ifdef SERVER_SUPPORT
774 "R", "s", referrer
? referrer
->original
: "NONE",
775 #endif /* SERVER_SUPPORT */
777 "r", "s", current_parsed_root
->directory
,
778 "sVv", ",", ppd
->tlist
,
779 pretag_list_to_args_proc
, (void *) NULL
,
782 if (newfilter
) free (newfilter
);
784 if (!cmdline
|| !strlen (cmdline
))
786 if (cmdline
) free (cmdline
);
787 error (0, 0, "pretag proc resolved to the empty string!");
793 /* FIXME - the old code used to run the following here:
797 * error (0, errno, "cannot find pre-tag filter '%s'", s);
802 * not sure this is really necessary. it might give a little finer grained
803 * error than letting the execution attempt fail but i'm not sure. in any
804 * case it should be easy enough to add a function in run.c to test its
805 * first arg for fileness & executability.
809 return abs (run_exec (RUN_TTY
, RUN_TTY
, RUN_TTY
, RUN_NORMAL
));
815 masterlist_delproc (Node
*p
)
817 struct master_lists
*ml
= p
->data
;
819 dellist (&ml
->tlist
);
827 tag_delproc (Node
*p
)
832 ti
= (struct tag_info
*) p
->data
;
833 if (ti
->oldrev
) free (ti
->oldrev
);
834 if (ti
->rev
) free (ti
->rev
);
844 /* to be passed into walklist with a list of tags
846 * p->data = struct tag_info *
847 * p->data->oldrev = rev tag will be deleted from
848 * p->data->rev = rev tag will be added to
849 * p->data->tag = tag oldrev is attached to, if any
851 * closure will be a struct format_cmdline_walklist_closure
852 * where closure is undefined
855 pretag_list_to_args_proc (Node
*p
, void *closure
)
857 struct tag_info
*taginfo
= (struct tag_info
*)p
->data
;
858 struct format_cmdline_walklist_closure
*c
=
859 (struct format_cmdline_walklist_closure
*)closure
;
865 if (!p
->data
) return 1;
869 /* foreach requested attribute */
878 arg
= taginfo
->tag
? taginfo
->tag
: "";
881 arg
= taginfo
->rev
? taginfo
->rev
: "NONE";
884 arg
= taginfo
->oldrev
? taginfo
->oldrev
: "NONE";
888 "Unknown format character or not a list attribute: %c",
892 /* copy the attribute into an argument */
895 arg
= cmdlineescape (c
->quotes
, arg
);
899 arg
= cmdlinequote ('"', arg
);
903 expand_string (c
->buf
, c
->length
, doff
+ strlen (arg
));
905 strncpy (d
, arg
, strlen (arg
));
910 /* and always put the extra space on. we'll have to back up a char when we're
911 * done, but that seems most efficient
914 expand_string (c
->buf
, c
->length
, doff
+ 1);
918 /* correct our original pointer into the buff */
925 * Called to rtag a particular file, as appropriate with the options that were
930 rtag_fileproc (void *callerdat
, struct file_info
*finfo
)
933 char *version
= NULL
, *rev
= NULL
;
936 static bool valtagged
= false;
938 /* find the parsed RCS data */
939 if ((rcsfile
= finfo
->rcs
) == NULL
)
942 goto free_vars_and_return
;
946 * For tagging an RCS file which is a symbolic link, you'd best be
947 * running with RCS 5.6, since it knows how to handle symbolic links
948 * correctly without breaking your link!
953 retval
= rtag_delete (rcsfile
);
954 goto free_vars_and_return
;
958 * If we get here, we are adding a tag. But, if -a was specified, we
959 * need to check to see if a -r or -D option was specified. If neither
960 * was specified and the file is in the Attic, remove the tag.
962 if (attic_too
&& (!numtag
&& !date
))
964 if ((rcsfile
->flags
& VALID
) && (rcsfile
->flags
& INATTIC
))
966 retval
= rtag_delete (rcsfile
);
967 goto free_vars_and_return
;
971 version
= RCS_getversion (rcsfile
, numtag
, date
, force_tag_match
, NULL
);
974 /* If -a specified, clean up any old tags */
976 (void)rtag_delete (rcsfile
);
978 if (!quiet
&& !force_tag_match
)
980 error (0, 0, "cannot find tag `%s' in `%s'",
981 numtag
? numtag
: "head", rcsfile
->path
);
984 goto free_vars_and_return
;
987 && isdigit ((unsigned char)*numtag
)
988 && strcmp (numtag
, version
) != 0)
992 * We didn't find a match for the numeric tag that was specified, but
993 * that's OK. just pass the numeric tag on to rcs, to be tagged as
994 * specified. Could get here if one tried to tag "1.1.1" and there
995 * was a 1.1.1 branch with some head revision. In this case, we want
996 * the tag to reference "1.1.1" and not the revision at the head of
997 * the branch. Use a symbolic tag for that.
999 rev
= branch_mode
? RCS_magicrev (rcsfile
, version
) : numtag
;
1000 retcode
= RCS_settag(rcsfile
, symtag
, numtag
);
1002 RCS_rewrite (rcsfile
, NULL
, NULL
);
1009 * As an enhancement for the case where a tag is being re-applied to
1010 * a large body of a module, make one extra call to RCS_getversion to
1011 * see if the tag is already set in the RCS file. If so, check to
1012 * see if it needs to be moved. If not, do nothing. This will
1013 * likely save a lot of time when simply moving the tag to the
1014 * "current" head revisions of a module -- which I have found to be a
1015 * typical tagging operation.
1017 rev
= branch_mode
? RCS_magicrev (rcsfile
, version
) : version
;
1018 oversion
= RCS_getversion (rcsfile
, symtag
, NULL
, 1, NULL
);
1019 if (oversion
!= NULL
)
1021 int isbranch
= RCS_nodeisbranch (finfo
->rcs
, symtag
);
1024 * if versions the same and neither old or new are branches don't
1025 * have to do anything
1027 if (strcmp (version
, oversion
) == 0 && !branch_mode
&& !isbranch
)
1030 goto free_vars_and_return
;
1033 if (!force_tag_move
)
1035 /* we're NOT going to move the tag */
1036 (void)printf ("W %s", finfo
->fullname
);
1038 (void)printf (" : %s already exists on %s %s",
1039 symtag
, isbranch
? "branch" : "version",
1041 (void)printf (" : NOT MOVING tag to %s %s\n",
1042 branch_mode
? "branch" : "version", rev
);
1044 goto free_vars_and_return
;
1046 else /* force_tag_move is set and... */
1047 if ((isbranch
&& !disturb_branch_tags
) ||
1048 (!isbranch
&& disturb_branch_tags
))
1050 error(0,0, "%s: Not moving %s tag `%s' from %s to %s%s.",
1052 isbranch
? "branch" : "non-branch",
1053 symtag
, oversion
, rev
,
1054 isbranch
? "" : " due to `-B' option");
1056 goto free_vars_and_return
;
1060 retcode
= RCS_settag (rcsfile
, symtag
, rev
);
1062 RCS_rewrite (rcsfile
, NULL
, NULL
);
1067 error (1, retcode
== -1 ? errno
: 0,
1068 "failed to set tag `%s' to revision `%s' in `%s'",
1069 symtag
, rev
, rcsfile
->path
);
1071 goto free_vars_and_return
;
1074 free_vars_and_return
:
1075 if (branch_mode
&& rev
) free (rev
);
1076 if (version
) free (version
);
1077 if (!delete_flag
&& !retval
&& !valtagged
)
1079 tag_check_valid (symtag
, 0, NULL
, 0, 0, NULL
, true);
1088 * If -d is specified, "force_tag_match" is set, so that this call to
1089 * RCS_getversion() will return a NULL version string if the symbolic
1090 * tag does not exist in the RCS file.
1092 * If the -r flag was used, numtag is set, and we only delete the
1093 * symtag from files that have numtag.
1095 * This is done here because it's MUCH faster than just blindly calling
1096 * "rcs" to remove the tag... trust me.
1099 rtag_delete (RCSNode
*rcsfile
)
1102 int retcode
, isbranch
;
1106 version
= RCS_getversion (rcsfile
, numtag
, NULL
, 1, NULL
);
1107 if (version
== NULL
)
1112 version
= RCS_getversion (rcsfile
, symtag
, NULL
, 1, NULL
);
1113 if (version
== NULL
)
1118 isbranch
= RCS_nodeisbranch (rcsfile
, symtag
);
1119 if ((isbranch
&& !disturb_branch_tags
) ||
1120 (!isbranch
&& disturb_branch_tags
))
1124 "Not removing %s tag `%s' from `%s'%s.",
1125 isbranch
? "branch" : "non-branch",
1126 symtag
, rcsfile
->path
,
1127 isbranch
? "" : " due to `-B' option");
1131 if ((retcode
= RCS_deltag(rcsfile
, symtag
)) != 0)
1134 error (0, retcode
== -1 ? errno
: 0,
1135 "failed to remove tag `%s' from `%s'", symtag
,
1139 RCS_rewrite (rcsfile
, NULL
, NULL
);
1146 * Called to tag a particular file (the currently checked out version is
1147 * tagged with the specified tag - or the specified tag is deleted).
1151 tag_fileproc (void *callerdat
, struct file_info
*finfo
)
1153 char *version
, *oversion
;
1154 char *nversion
= NULL
;
1159 static bool valtagged
= false;
1161 vers
= Version_TS (finfo
, NULL
, NULL
, NULL
, 0, 0);
1165 nversion
= RCS_getversion (vers
->srcfile
, numtag
, date
,
1166 force_tag_match
, NULL
);
1168 goto free_vars_and_return
;
1175 * If -d is specified, "force_tag_match" is set, so that this call to
1176 * RCS_getversion() will return a NULL version string if the symbolic
1177 * tag does not exist in the RCS file.
1179 * This is done here because it's MUCH faster than just blindly calling
1180 * "rcs" to remove the tag... trust me.
1183 version
= RCS_getversion (vers
->srcfile
, symtag
, NULL
, 1, NULL
);
1184 if (version
== NULL
|| vers
->srcfile
== NULL
)
1185 goto free_vars_and_return
;
1189 isbranch
= RCS_nodeisbranch (finfo
->rcs
, symtag
);
1190 if ((isbranch
&& !disturb_branch_tags
) ||
1191 (!isbranch
&& disturb_branch_tags
))
1195 "Not removing %s tag `%s' from `%s'%s.",
1196 isbranch
? "branch" : "non-branch",
1197 symtag
, vers
->srcfile
->path
,
1198 isbranch
? "" : " due to `-B' option");
1200 goto free_vars_and_return
;
1203 if ((retcode
= RCS_deltag (vers
->srcfile
, symtag
)) != 0)
1206 error (0, retcode
== -1 ? errno
: 0,
1207 "failed to remove tag %s from %s", symtag
,
1208 vers
->srcfile
->path
);
1210 goto free_vars_and_return
;
1212 RCS_rewrite (vers
->srcfile
, NULL
, NULL
);
1217 cvs_output ("D ", 2);
1218 cvs_output (finfo
->fullname
, 0);
1219 cvs_output ("\n", 1);
1222 goto free_vars_and_return
;
1226 * If we are adding a tag, we need to know which version we have checked
1227 * out and we'll tag that version.
1230 version
= vers
->vn_user
;
1234 goto free_vars_and_return
;
1235 else if (strcmp (version
, "0") == 0)
1238 error (0, 0, "couldn't tag added but un-commited file `%s'",
1240 goto free_vars_and_return
;
1242 else if (version
[0] == '-')
1245 error (0, 0, "skipping removed but un-commited file `%s'",
1247 goto free_vars_and_return
;
1249 else if (vers
->srcfile
== NULL
)
1252 error (0, 0, "cannot find revision control file for `%s'",
1254 goto free_vars_and_return
;
1258 * As an enhancement for the case where a tag is being re-applied to a
1259 * large number of files, make one extra call to RCS_getversion to see
1260 * if the tag is already set in the RCS file. If so, check to see if it
1261 * needs to be moved. If not, do nothing. This will likely save a lot of
1262 * time when simply moving the tag to the "current" head revisions of a
1263 * module -- which I have found to be a typical tagging operation.
1265 rev
= branch_mode
? RCS_magicrev (vers
->srcfile
, version
) : version
;
1266 oversion
= RCS_getversion (vers
->srcfile
, symtag
, NULL
, 1, NULL
);
1267 if (oversion
!= NULL
)
1269 int isbranch
= RCS_nodeisbranch (finfo
->rcs
, symtag
);
1272 * if versions the same and neither old or new are branches don't have
1275 if (strcmp (version
, oversion
) == 0 && !branch_mode
&& !isbranch
)
1280 goto free_vars_and_return
;
1283 if (!force_tag_move
)
1285 /* we're NOT going to move the tag */
1286 cvs_output ("W ", 2);
1287 cvs_output (finfo
->fullname
, 0);
1288 cvs_output (" : ", 0);
1289 cvs_output (symtag
, 0);
1290 cvs_output (" already exists on ", 0);
1291 cvs_output (isbranch
? "branch" : "version", 0);
1292 cvs_output (" ", 0);
1293 cvs_output (oversion
, 0);
1294 cvs_output (" : NOT MOVING tag to ", 0);
1295 cvs_output (branch_mode
? "branch" : "version", 0);
1296 cvs_output (" ", 0);
1297 cvs_output (rev
, 0);
1298 cvs_output ("\n", 1);
1302 goto free_vars_and_return
;
1304 else /* force_tag_move == 1 and... */
1305 if ((isbranch
&& !disturb_branch_tags
) ||
1306 (!isbranch
&& disturb_branch_tags
))
1308 error (0,0, "%s: Not moving %s tag `%s' from %s to %s%s.",
1310 isbranch
? "branch" : "non-branch",
1311 symtag
, oversion
, rev
,
1312 isbranch
? "" : " due to `-B' option");
1316 goto free_vars_and_return
;
1321 if ((retcode
= RCS_settag(vers
->srcfile
, symtag
, rev
)) != 0)
1323 error (1, retcode
== -1 ? errno
: 0,
1324 "failed to set tag %s to revision %s in %s",
1325 symtag
, rev
, vers
->srcfile
->path
);
1329 goto free_vars_and_return
;
1333 RCS_rewrite (vers
->srcfile
, NULL
, NULL
);
1335 /* more warm fuzzies */
1338 cvs_output ("T ", 2);
1339 cvs_output (finfo
->fullname
, 0);
1340 cvs_output ("\n", 1);
1343 free_vars_and_return
:
1344 if (nversion
!= NULL
)
1346 freevers_ts (&vers
);
1347 if (!delete_flag
&& !retval
&& !valtagged
)
1349 tag_check_valid (symtag
, 0, NULL
, 0, 0, NULL
, true);
1358 * Print a warm fuzzy message
1362 tag_dirproc (void *callerdat
, const char *dir
, const char *repos
,
1363 const char *update_dir
, List
*entries
)
1366 if (ignore_directory (update_dir
))
1368 /* print the warm fuzzy message */
1370 error (0, 0, "Ignoring %s", update_dir
);
1375 error (0, 0, "%s %s", delete_flag
? "Untagging" : "Tagging",
1382 /* Code relating to the val-tags file. Note that this file has no way
1383 of knowing when a tag has been deleted. The problem is that there
1384 is no way of knowing whether a tag still exists somewhere, when we
1385 delete it some places. Using per-directory val-tags files (in
1386 CVSREP) might be better, but that might slow down the process of
1387 verifying that a tag is correct (maybe not, for the likely cases,
1388 if carefully done), and/or be harder to implement correctly. */
1396 val_fileproc (void *callerdat
, struct file_info
*finfo
)
1399 struct val_args
*args
= callerdat
;
1402 if ((rcsdata
= finfo
->rcs
) == NULL
)
1403 /* Not sure this can happen, after all we passed only
1404 W_REPOS | W_ATTIC. */
1407 tag
= RCS_gettag (rcsdata
, args
->name
, 1, NULL
);
1410 /* FIXME: should find out a way to stop the search at this point. */
1419 /* This routine determines whether a tag appears in CVSROOT/val-tags.
1421 * The val-tags file will be open read-only when IDB is NULL. Since writes to
1422 * val-tags always append to it, the lack of locking is okay. The worst case
1423 * race condition might misinterpret a partially written "foobar" matched, for
1424 * instance, a request for "f", "foo", of "foob". Such a mismatch would be
1425 * caught harmlessly later.
1427 * Before CVS adds a tag to val-tags, it will lock val-tags for write and
1428 * verify that the tag is still not present to avoid adding it twice.
1431 * This function expects its parent to handle any necessary locking of the
1435 * idb When this value is NULL, the val-tags file is opened in
1436 * in read-only mode. When present, the val-tags file is opened
1437 * in read-write mode and the DBM handle is stored in *IDB.
1438 * name The tag to search for.
1441 * *idb The val-tags file opened for read/write, or NULL if it couldn't
1445 * Exits with an error message if the val-tags file cannot be opened for
1446 * read (failure to open val-tags read/write is harmless - see below).
1449 * true 1. If NAME exists in val-tags.
1450 * 2. If IDB is non-NULL and val-tags cannot be opened for write.
1451 * This allows callers to ignore the harmless inability to
1452 * update the val-tags cache.
1453 * false If the file could be opened and the tag is not present.
1455 static int is_in_val_tags (DBM
**idb
, const char *name
)
1458 char *valtags_filename
;
1462 /* Casting out const should be safe here - input datums are not
1463 * written to by the myndbm functions.
1465 mytag
.dptr
= (char *)name
;
1466 mytag
.dsize
= strlen (name
);
1468 valtags_filename
= Xasprintf ("%s/%s/%s", current_parsed_root
->directory
,
1469 CVSROOTADM
, CVSROOTADM_VALTAGS
);
1475 omask
= umask (cvsumask
);
1476 db
= dbm_open (valtags_filename
, O_RDWR
| O_CREAT
, 0666);
1482 error (0, errno
, "warning: cannot open `%s' read/write",
1492 db
= dbm_open (valtags_filename
, O_RDONLY
, 0444);
1493 if (!db
&& !existence_error (errno
))
1494 error (1, errno
, "cannot read %s", valtags_filename
);
1497 /* If the file merely fails to exist, we just keep going and create
1498 it later if need be. */
1505 val
= dbm_fetch (db
, mytag
);
1506 if (val
.dptr
!= NULL
)
1507 /* Found. The tag is valid. */
1510 /* FIXME: should check errors somehow (add dbm_error to myndbm.c?). */
1512 if (!idb
) dbm_close (db
);
1515 free (valtags_filename
);
1521 /* Add a tag to the CVSROOT/val-tags cache. Establishes a write lock and
1522 * reverifies that the tag does not exist before adding it.
1524 static void add_to_val_tags (const char *name
)
1530 if (noexec
|| readonlyfs
) return;
1532 val_tags_lock (current_parsed_root
->directory
);
1534 /* Check for presence again since we have a lock now. */
1535 if (is_in_val_tags (&db
, name
)) return;
1537 /* Casting out const should be safe here - input datums are not
1538 * written to by the myndbm functions.
1540 mytag
.dptr
= (char *)name
;
1541 mytag
.dsize
= strlen (name
);
1545 if (dbm_store (db
, mytag
, value
, DBM_REPLACE
) < 0)
1546 error (0, errno
, "failed to store %s into val-tags", name
);
1549 clear_val_tags_lock ();
1555 val_direntproc (void *callerdat
, const char *dir
, const char *repository
,
1556 const char *update_dir
, List
*entries
)
1558 /* This is not quite right--it doesn't get right the case of "cvs
1559 update -d -r foobar" where foobar is a tag which exists only in
1560 files in a directory which does not exist yet, but which is
1561 about to be created. */
1569 /* With VALID set, insert NAME into val-tags if it is not already present
1572 * Without VALID set, check to see whether NAME is a valid tag. If so, return.
1573 * If not print an error message and exit.
1577 * ARGC, ARGV, LOCAL, and AFLAG specify which files we will be operating on.
1579 * REPOSITORY is the repository if we need to cd into it, or NULL if
1580 * we are already there, or "" if we should do a W_LOCAL recursion.
1581 * Sorry for three cases, but the "" case is needed in case the
1582 * working directories come from diverse parts of the repository, the
1583 * NULL case avoids an unneccesary chdir, and the non-NULL, non-""
1584 * case is needed for checkout, where we don't want to chdir if the
1585 * tag is found in CVSROOTADM_VALTAGS, but there is not (yet) any
1589 * Errors may be encountered opening and accessing the DBM file. Write
1590 * errors generate warnings and read errors are fatal. When !VALID and NAME
1591 * is not in val-tags, errors may also be generated as per start_recursion.
1592 * When !VALID, non-existance of tags both in val-tags and in the archive
1593 * files also causes a fatal error.
1599 tag_check_valid (const char *name
, int argc
, char **argv
, int local
, int aflag
,
1600 char *repository
, bool valid
)
1602 struct val_args the_val_args
;
1603 struct saved_cwd cwd
;
1606 #ifdef HAVE_PRINTF_PTR
1607 TRACE (TRACE_FUNCTION
,
1608 "tag_check_valid (name=%s, argc=%d, argv=%p, local=%d,\n"
1609 " aflag=%d, repository=%s, valid=%s)",
1610 name
? name
: "(name)", argc
, (void *)argv
, local
, aflag
,
1611 repository
? repository
: "(null)",
1612 valid
? "true" : "false");
1614 TRACE (TRACE_FUNCTION
,
1615 "tag_check_valid (name=%s, argc=%d, argv=%lx, local=%d,\n"
1616 " aflag=%d, repository=%s, valid=%s)",
1617 name
? name
: "(name)", argc
, (unsigned long)argv
, local
, aflag
,
1618 repository
? repository
: "(null)",
1619 valid
? "true" : "false");
1622 /* Numeric tags require only a syntactic check. */
1623 if (isdigit ((unsigned char) name
[0]))
1625 /* insert is not possible for numeric revisions */
1627 if (RCS_valid_rev (name
)) return;
1630 Numeric tag %s invalid. Numeric tags should be of the form X[.X]...", name
);
1633 /* Special tags are always valid. */
1634 if (strcmp (name
, TAG_BASE
) == 0
1635 || strcmp (name
, TAG_HEAD
) == 0)
1637 /* insert is not possible for numeric revisions */
1642 /* Verify that the tag is valid syntactically. Some later code once made
1643 * assumptions about this.
1645 RCS_check_tag (name
);
1647 if (is_in_val_tags (NULL
, name
)) return;
1651 /* We didn't find the tag in val-tags, so look through all the RCS files
1652 * to see whether it exists there. Yes, this is expensive, but there
1653 * is no other way to cope with a tag which might have been created
1654 * by an old version of CVS, from before val-tags was invented
1657 the_val_args
.name
= name
;
1658 the_val_args
.found
= 0;
1659 which
= W_REPOS
| W_ATTIC
;
1661 if (repository
== NULL
|| repository
[0] == '\0')
1665 if (save_cwd (&cwd
))
1666 error (1, errno
, "Failed to save current directory.");
1667 if (CVS_CHDIR (repository
) < 0)
1668 error (1, errno
, "cannot change to %s directory", repository
);
1672 (val_fileproc
, NULL
, val_direntproc
, NULL
,
1673 &the_val_args
, argc
, argv
, local
, which
, aflag
,
1674 CVS_LOCK_READ
, NULL
, 1, repository
);
1675 if (repository
!= NULL
&& repository
[0] != '\0')
1677 if (restore_cwd (&cwd
))
1678 error (1, errno
, "Failed to restore current directory, `%s'.",
1683 if (!the_val_args
.found
)
1684 error (1, 0, "no such tag `%s'", name
);
1687 /* The tags is valid but not mentioned in val-tags. Add it. */
1688 add_to_val_tags (name
);