This commit was generated by cvs2svn to compensate for changes in r81412,
which included commits to RCS files with non-trunk default branches.
This commit is contained in:
parent
e74335fc90
commit
a2b4cbc808
@ -1,764 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, Brian Berliner and Jeff Polk
|
||||
* Copyright (c) 1989-1992, Brian Berliner
|
||||
*
|
||||
* You may distribute under the terms of the GNU General Public License as
|
||||
* specified in the README file that comes with the CVS source distribution.
|
||||
*
|
||||
* Rtag
|
||||
*
|
||||
* Add or delete a symbolic name to an RCS file, or a collection of RCS files.
|
||||
* Uses the modules database, if necessary.
|
||||
*/
|
||||
|
||||
#include "cvs.h"
|
||||
|
||||
static int check_fileproc PROTO ((void *callerdat, struct file_info *finfo));
|
||||
static int check_filesdoneproc PROTO ((void *callerdat, int err,
|
||||
char *repos, char *update_dir,
|
||||
List *entries));
|
||||
static int pretag_proc PROTO((char *repository, char *filter));
|
||||
static void masterlist_delproc PROTO((Node *p));
|
||||
static void tag_delproc PROTO((Node *p));
|
||||
static int pretag_list_proc PROTO((Node *p, void *closure));
|
||||
|
||||
static Dtype rtag_dirproc PROTO ((void *callerdat, char *dir,
|
||||
char *repos, char *update_dir,
|
||||
List *entries));
|
||||
static int rtag_fileproc PROTO ((void *callerdat, struct file_info *finfo));
|
||||
static int rtag_filesdoneproc PROTO ((void *callerdat, int err,
|
||||
char *repos, char *update_dir,
|
||||
List *entries));
|
||||
static int rtag_proc PROTO((int argc, char **argv, char *xwhere,
|
||||
char *mwhere, char *mfile, int shorten,
|
||||
int local_specified, char *mname, char *msg));
|
||||
static int rtag_delete PROTO((RCSNode *rcsfile));
|
||||
|
||||
|
||||
struct tag_info
|
||||
{
|
||||
Ctype status;
|
||||
char *rev;
|
||||
char *tag;
|
||||
char *options;
|
||||
};
|
||||
|
||||
struct master_lists
|
||||
{
|
||||
List *tlist;
|
||||
};
|
||||
|
||||
static List *mtlist;
|
||||
static List *tlist;
|
||||
|
||||
static char *symtag;
|
||||
static char *numtag;
|
||||
static int numtag_validated = 0;
|
||||
static int delete_flag; /* adding a tag by default */
|
||||
static int attic_too; /* remove tag from Attic files */
|
||||
static int branch_mode; /* make an automagic "branch" tag */
|
||||
static char *date;
|
||||
static int local; /* recursive by default */
|
||||
static int force_tag_match = 1; /* force by default */
|
||||
static int force_tag_move; /* don't move existing tags by default */
|
||||
|
||||
static const char *const rtag_usage[] =
|
||||
{
|
||||
"Usage: %s %s [-aflRnF] [-b] [-d] [-r rev|-D date] tag modules...\n",
|
||||
"\t-a\tClear tag from removed files that would not otherwise be tagged.\n",
|
||||
"\t-f\tForce a head revision match if tag/date not found.\n",
|
||||
"\t-l\tLocal directory only, not recursive\n",
|
||||
"\t-R\tProcess directories recursively.\n",
|
||||
"\t-n\tNo execution of 'tag program'\n",
|
||||
"\t-d\tDelete the given Tag.\n",
|
||||
"\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
|
||||
"\t-r rev\tExisting revision/tag.\n",
|
||||
"\t-D\tExisting date.\n",
|
||||
"\t-F\tMove tag if it already exists\n",
|
||||
"(Specify the --help global option for a list of other help options)\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
int
|
||||
rtag (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
register int i;
|
||||
int c;
|
||||
DBM *db;
|
||||
int run_module_prog = 1;
|
||||
int err = 0;
|
||||
|
||||
if (argc == -1)
|
||||
usage (rtag_usage);
|
||||
|
||||
optind = 0;
|
||||
while ((c = getopt (argc, argv, "+FanfQqlRdbr:D:")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'a':
|
||||
attic_too = 1;
|
||||
break;
|
||||
case 'n':
|
||||
run_module_prog = 0;
|
||||
break;
|
||||
case 'Q':
|
||||
case 'q':
|
||||
#ifdef SERVER_SUPPORT
|
||||
/* The CVS 1.5 client sends these options (in addition to
|
||||
Global_option requests), so we must ignore them. */
|
||||
if (!server_active)
|
||||
#endif
|
||||
error (1, 0,
|
||||
"-q or -Q must be specified before \"%s\"",
|
||||
command_name);
|
||||
break;
|
||||
case 'l':
|
||||
local = 1;
|
||||
break;
|
||||
case 'R':
|
||||
local = 0;
|
||||
break;
|
||||
case 'd':
|
||||
delete_flag = 1;
|
||||
break;
|
||||
case 'f':
|
||||
force_tag_match = 0;
|
||||
break;
|
||||
case 'b':
|
||||
branch_mode = 1;
|
||||
break;
|
||||
case 'r':
|
||||
numtag = optarg;
|
||||
break;
|
||||
case 'D':
|
||||
if (date)
|
||||
free (date);
|
||||
date = Make_Date (optarg);
|
||||
break;
|
||||
case 'F':
|
||||
force_tag_move = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage (rtag_usage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (argc < 2)
|
||||
usage (rtag_usage);
|
||||
symtag = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if (date && numtag)
|
||||
error (1, 0, "-r and -D options are mutually exclusive");
|
||||
if (delete_flag && branch_mode)
|
||||
error (0, 0, "warning: -b ignored with -d options");
|
||||
RCS_check_tag (symtag);
|
||||
|
||||
#ifdef CLIENT_SUPPORT
|
||||
if (client_active)
|
||||
{
|
||||
/* We're the client side. Fire up the remote server. */
|
||||
start_server ();
|
||||
|
||||
ign_setup ();
|
||||
|
||||
if (!force_tag_match)
|
||||
send_arg ("-f");
|
||||
if (local)
|
||||
send_arg("-l");
|
||||
if (delete_flag)
|
||||
send_arg("-d");
|
||||
if (branch_mode)
|
||||
send_arg("-b");
|
||||
if (force_tag_move)
|
||||
send_arg("-F");
|
||||
if (!run_module_prog)
|
||||
send_arg("-n");
|
||||
if (attic_too)
|
||||
send_arg("-a");
|
||||
|
||||
if (numtag)
|
||||
option_with_arg ("-r", numtag);
|
||||
if (date)
|
||||
client_senddate (date);
|
||||
|
||||
send_arg (symtag);
|
||||
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < argc; ++i)
|
||||
send_arg (argv[i]);
|
||||
}
|
||||
|
||||
send_to_server ("rtag\012", 0);
|
||||
return get_responses_and_close ();
|
||||
}
|
||||
#endif
|
||||
|
||||
db = open_module ();
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
/* XXX last arg should be repository, but doesn't make sense here */
|
||||
history_write ('T', (delete_flag ? "D" : (numtag ? numtag :
|
||||
(date ? date : "A"))), symtag, argv[i], "");
|
||||
err += do_module (db, argv[i], TAG,
|
||||
delete_flag ? "Untagging" : "Tagging",
|
||||
rtag_proc, (char *) NULL, 0, 0, run_module_prog,
|
||||
symtag);
|
||||
}
|
||||
close_module (db);
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* callback proc for doing the real work of tagging
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
rtag_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified,
|
||||
mname, msg)
|
||||
int argc;
|
||||
char **argv;
|
||||
char *xwhere;
|
||||
char *mwhere;
|
||||
char *mfile;
|
||||
int shorten;
|
||||
int local_specified;
|
||||
char *mname;
|
||||
char *msg;
|
||||
{
|
||||
/* Begin section which is identical to patch_proc--should this
|
||||
be abstracted out somehow? */
|
||||
char *myargv[2];
|
||||
int err = 0;
|
||||
int which;
|
||||
char *repository;
|
||||
char *where;
|
||||
|
||||
repository = xmalloc (strlen (CVSroot_directory) + strlen (argv[0])
|
||||
+ (mfile == NULL ? 0 : strlen (mfile)) + 30);
|
||||
(void) sprintf (repository, "%s/%s", CVSroot_directory, argv[0]);
|
||||
where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile))
|
||||
+ 10);
|
||||
(void) strcpy (where, argv[0]);
|
||||
|
||||
/* if mfile isn't null, we need to set up to do only part of the module */
|
||||
if (mfile != NULL)
|
||||
{
|
||||
char *cp;
|
||||
char *path;
|
||||
|
||||
/* if the portion of the module is a path, put the dir part on repos */
|
||||
if ((cp = strrchr (mfile, '/')) != NULL)
|
||||
{
|
||||
*cp = '\0';
|
||||
(void) strcat (repository, "/");
|
||||
(void) strcat (repository, mfile);
|
||||
(void) strcat (where, "/");
|
||||
(void) strcat (where, mfile);
|
||||
mfile = cp + 1;
|
||||
}
|
||||
|
||||
/* take care of the rest */
|
||||
path = xmalloc (strlen (repository) + strlen (mfile) + 5);
|
||||
(void) sprintf (path, "%s/%s", repository, mfile);
|
||||
if (isdir (path))
|
||||
{
|
||||
/* directory means repository gets the dir tacked on */
|
||||
(void) strcpy (repository, path);
|
||||
(void) strcat (where, "/");
|
||||
(void) strcat (where, mfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
myargv[0] = argv[0];
|
||||
myargv[1] = mfile;
|
||||
argc = 2;
|
||||
argv = myargv;
|
||||
}
|
||||
free (path);
|
||||
}
|
||||
|
||||
/* cd to the starting repository */
|
||||
if ( CVS_CHDIR (repository) < 0)
|
||||
{
|
||||
error (0, errno, "cannot chdir to %s", repository);
|
||||
free (repository);
|
||||
return (1);
|
||||
}
|
||||
free (repository);
|
||||
/* End section which is identical to patch_proc. */
|
||||
|
||||
if (delete_flag || attic_too || (force_tag_match && numtag))
|
||||
which = W_REPOS | W_ATTIC;
|
||||
else
|
||||
which = W_REPOS;
|
||||
|
||||
if (numtag != NULL && !numtag_validated)
|
||||
{
|
||||
tag_check_valid (numtag, argc - 1, argv + 1, local, 0, NULL);
|
||||
numtag_validated = 1;
|
||||
}
|
||||
|
||||
/* check to make sure they are authorized to tag all the
|
||||
specified files in the repository */
|
||||
|
||||
mtlist = getlist();
|
||||
err = start_recursion (check_fileproc, check_filesdoneproc,
|
||||
(DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
|
||||
argc - 1, argv + 1, local, which, 0, 1,
|
||||
where, 1);
|
||||
|
||||
if (err)
|
||||
{
|
||||
error (1, 0, "correct the above errors first!");
|
||||
}
|
||||
|
||||
/* start the recursion processor */
|
||||
err = start_recursion (rtag_fileproc, rtag_filesdoneproc, rtag_dirproc,
|
||||
(DIRLEAVEPROC) NULL, NULL,
|
||||
argc - 1, argv + 1, local,
|
||||
which, 0, 0, where, 1);
|
||||
free (where);
|
||||
dellist(&mtlist);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
/* check file that is to be tagged */
|
||||
/* All we do here is add it to our list */
|
||||
|
||||
static int
|
||||
check_fileproc (callerdat, finfo)
|
||||
void *callerdat;
|
||||
struct file_info *finfo;
|
||||
{
|
||||
char *xdir;
|
||||
Node *p;
|
||||
Vers_TS *vers;
|
||||
|
||||
if (finfo->update_dir[0] == '\0')
|
||||
xdir = ".";
|
||||
else
|
||||
xdir = finfo->update_dir;
|
||||
if ((p = findnode (mtlist, xdir)) != NULL)
|
||||
{
|
||||
tlist = ((struct master_lists *) p->data)->tlist;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct master_lists *ml;
|
||||
|
||||
tlist = getlist ();
|
||||
p = getnode ();
|
||||
p->key = xstrdup (xdir);
|
||||
p->type = UPDATE;
|
||||
ml = (struct master_lists *)
|
||||
xmalloc (sizeof (struct master_lists));
|
||||
ml->tlist = tlist;
|
||||
p->data = (char *) ml;
|
||||
p->delproc = masterlist_delproc;
|
||||
(void) addnode (mtlist, p);
|
||||
}
|
||||
/* do tlist */
|
||||
p = getnode ();
|
||||
p->key = xstrdup (finfo->file);
|
||||
p->type = UPDATE;
|
||||
p->delproc = tag_delproc;
|
||||
vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
|
||||
p->data = RCS_getversion(vers->srcfile, numtag, date, force_tag_match,
|
||||
(int *) NULL);
|
||||
if (p->data != NULL)
|
||||
{
|
||||
int addit = 1;
|
||||
char *oversion;
|
||||
|
||||
oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1,
|
||||
(int *) NULL);
|
||||
if (oversion == NULL)
|
||||
{
|
||||
if (delete_flag)
|
||||
{
|
||||
/* Deleting a tag which did not exist is a noop and
|
||||
should not be logged. */
|
||||
addit = 0;
|
||||
}
|
||||
}
|
||||
else if (delete_flag)
|
||||
{
|
||||
free (p->data);
|
||||
p->data = xstrdup (oversion);
|
||||
}
|
||||
else if (strcmp(oversion, p->data) == 0)
|
||||
{
|
||||
addit = 0;
|
||||
}
|
||||
else if (!force_tag_move)
|
||||
{
|
||||
addit = 0;
|
||||
}
|
||||
if (oversion != NULL)
|
||||
{
|
||||
free(oversion);
|
||||
}
|
||||
if (!addit)
|
||||
{
|
||||
free(p->data);
|
||||
p->data = NULL;
|
||||
}
|
||||
}
|
||||
freevers_ts (&vers);
|
||||
(void) addnode (tlist, p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
check_filesdoneproc (callerdat, err, repos, update_dir, entries)
|
||||
void *callerdat;
|
||||
int err;
|
||||
char *repos;
|
||||
char *update_dir;
|
||||
List *entries;
|
||||
{
|
||||
int n;
|
||||
Node *p;
|
||||
|
||||
p = findnode(mtlist, update_dir);
|
||||
if (p != NULL)
|
||||
{
|
||||
tlist = ((struct master_lists *) p->data)->tlist;
|
||||
}
|
||||
else
|
||||
{
|
||||
tlist = (List *) NULL;
|
||||
}
|
||||
if ((tlist == NULL) || (tlist->list->next == tlist->list))
|
||||
{
|
||||
return (err);
|
||||
}
|
||||
if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, 1)) > 0)
|
||||
{
|
||||
error (0, 0, "Pre-tag check failed");
|
||||
err += n;
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
pretag_proc(repository, filter)
|
||||
char *repository;
|
||||
char *filter;
|
||||
{
|
||||
if (filter[0] == '/')
|
||||
{
|
||||
char *s, *cp;
|
||||
|
||||
s = xstrdup(filter);
|
||||
for (cp=s; *cp; cp++)
|
||||
{
|
||||
if (isspace ((unsigned char) *cp))
|
||||
{
|
||||
*cp = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isfile(s))
|
||||
{
|
||||
error (0, errno, "cannot find pre-tag filter '%s'", s);
|
||||
free(s);
|
||||
return (1);
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
run_setup (filter);
|
||||
run_arg (symtag);
|
||||
run_arg (delete_flag ? "del" : force_tag_move ? "mov" : "add");
|
||||
run_arg (repository);
|
||||
walklist(tlist, pretag_list_proc, NULL);
|
||||
return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL));
|
||||
}
|
||||
|
||||
static void
|
||||
masterlist_delproc(p)
|
||||
Node *p;
|
||||
{
|
||||
struct master_lists *ml;
|
||||
|
||||
ml = (struct master_lists *)p->data;
|
||||
dellist(&ml->tlist);
|
||||
free(ml);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
tag_delproc(p)
|
||||
Node *p;
|
||||
{
|
||||
if (p->data != NULL)
|
||||
{
|
||||
free(p->data);
|
||||
p->data = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
pretag_list_proc(p, closure)
|
||||
Node *p;
|
||||
void *closure;
|
||||
{
|
||||
if (p->data != NULL)
|
||||
{
|
||||
run_arg(p->key);
|
||||
run_arg(p->data);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to tag a particular file, as appropriate with the options that were
|
||||
* set above.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
rtag_fileproc (callerdat, finfo)
|
||||
void *callerdat;
|
||||
struct file_info *finfo;
|
||||
{
|
||||
RCSNode *rcsfile;
|
||||
char *version, *rev;
|
||||
int retcode = 0;
|
||||
|
||||
/* Lock the directory if it is not already locked. We might be
|
||||
able to rely on rtag_dirproc for this. */
|
||||
|
||||
/* It would be nice to provide consistency with respect to
|
||||
commits; however CVS lacks the infrastructure to do that (see
|
||||
Concurrency in cvs.texinfo and comment in do_recursion). We
|
||||
can and will prevent simultaneous tag operations from
|
||||
interfering with each other, by write locking each directory as
|
||||
we enter it, and unlocking it as we leave it. */
|
||||
|
||||
lock_dir_for_write (finfo->repository);
|
||||
|
||||
/* find the parsed RCS data */
|
||||
if ((rcsfile = finfo->rcs) == NULL)
|
||||
return (1);
|
||||
|
||||
/*
|
||||
* For tagging an RCS file which is a symbolic link, you'd best be
|
||||
* running with RCS 5.6, since it knows how to handle symbolic links
|
||||
* correctly without breaking your link!
|
||||
*/
|
||||
|
||||
if (delete_flag)
|
||||
return (rtag_delete (rcsfile));
|
||||
|
||||
/*
|
||||
* If we get here, we are adding a tag. But, if -a was specified, we
|
||||
* need to check to see if a -r or -D option was specified. If neither
|
||||
* was specified and the file is in the Attic, remove the tag.
|
||||
*/
|
||||
if (attic_too && (!numtag && !date))
|
||||
{
|
||||
if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
|
||||
return (rtag_delete (rcsfile));
|
||||
}
|
||||
|
||||
version = RCS_getversion (rcsfile, numtag, date, force_tag_match,
|
||||
(int *) NULL);
|
||||
if (version == NULL)
|
||||
{
|
||||
/* If -a specified, clean up any old tags */
|
||||
if (attic_too)
|
||||
(void) rtag_delete (rcsfile);
|
||||
|
||||
if (!quiet && !force_tag_match)
|
||||
{
|
||||
error (0, 0, "cannot find tag `%s' in `%s'",
|
||||
numtag ? numtag : "head", rcsfile->path);
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
if (numtag
|
||||
&& isdigit ((unsigned char) *numtag)
|
||||
&& strcmp (numtag, version) != 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* We didn't find a match for the numeric tag that was specified, but
|
||||
* that's OK. just pass the numeric tag on to rcs, to be tagged as
|
||||
* specified. Could get here if one tried to tag "1.1.1" and there
|
||||
* was a 1.1.1 branch with some head revision. In this case, we want
|
||||
* the tag to reference "1.1.1" and not the revision at the head of
|
||||
* the branch. Use a symbolic tag for that.
|
||||
*/
|
||||
rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag;
|
||||
retcode = RCS_settag(rcsfile, symtag, numtag);
|
||||
if (retcode == 0)
|
||||
RCS_rewrite (rcsfile, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *oversion;
|
||||
|
||||
/*
|
||||
* As an enhancement for the case where a tag is being re-applied to
|
||||
* a large body of a module, make one extra call to RCS_getversion to
|
||||
* see if the tag is already set in the RCS file. If so, check to
|
||||
* see if it needs to be moved. If not, do nothing. This will
|
||||
* likely save a lot of time when simply moving the tag to the
|
||||
* "current" head revisions of a module -- which I have found to be a
|
||||
* typical tagging operation.
|
||||
*/
|
||||
rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
|
||||
oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1,
|
||||
(int *) NULL);
|
||||
if (oversion != NULL)
|
||||
{
|
||||
int isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
|
||||
|
||||
/*
|
||||
* if versions the same and neither old or new are branches don't
|
||||
* have to do anything
|
||||
*/
|
||||
if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
|
||||
{
|
||||
free (oversion);
|
||||
free (version);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!force_tag_move)
|
||||
{
|
||||
/* we're NOT going to move the tag */
|
||||
(void) printf ("W %s", finfo->fullname);
|
||||
|
||||
(void) printf (" : %s already exists on %s %s",
|
||||
symtag, isbranch ? "branch" : "version",
|
||||
oversion);
|
||||
(void) printf (" : NOT MOVING tag to %s %s\n",
|
||||
branch_mode ? "branch" : "version", rev);
|
||||
free (oversion);
|
||||
free (version);
|
||||
return (0);
|
||||
}
|
||||
free (oversion);
|
||||
}
|
||||
retcode = RCS_settag(rcsfile, symtag, rev);
|
||||
if (retcode == 0)
|
||||
RCS_rewrite (rcsfile, NULL, NULL);
|
||||
}
|
||||
|
||||
if (retcode != 0)
|
||||
{
|
||||
error (1, retcode == -1 ? errno : 0,
|
||||
"failed to set tag `%s' to revision `%s' in `%s'",
|
||||
symtag, rev, rcsfile->path);
|
||||
if (branch_mode)
|
||||
free (rev);
|
||||
free (version);
|
||||
return (1);
|
||||
}
|
||||
if (branch_mode)
|
||||
free (rev);
|
||||
free (version);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If -d is specified, "force_tag_match" is set, so that this call to
|
||||
* RCS_getversion() will return a NULL version string if the symbolic
|
||||
* tag does not exist in the RCS file.
|
||||
*
|
||||
* If the -r flag was used, numtag is set, and we only delete the
|
||||
* symtag from files that have numtag.
|
||||
*
|
||||
* This is done here because it's MUCH faster than just blindly calling
|
||||
* "rcs" to remove the tag... trust me.
|
||||
*/
|
||||
static int
|
||||
rtag_delete (rcsfile)
|
||||
RCSNode *rcsfile;
|
||||
{
|
||||
char *version;
|
||||
int retcode;
|
||||
|
||||
if (numtag)
|
||||
{
|
||||
version = RCS_getversion (rcsfile, numtag, (char *) NULL, 1,
|
||||
(int *) NULL);
|
||||
if (version == NULL)
|
||||
return (0);
|
||||
free (version);
|
||||
}
|
||||
|
||||
version = RCS_getversion (rcsfile, symtag, (char *) NULL, 1,
|
||||
(int *) NULL);
|
||||
if (version == NULL)
|
||||
return (0);
|
||||
free (version);
|
||||
|
||||
if ((retcode = RCS_deltag(rcsfile, symtag)) != 0)
|
||||
{
|
||||
if (!quiet)
|
||||
error (0, retcode == -1 ? errno : 0,
|
||||
"failed to remove tag `%s' from `%s'", symtag,
|
||||
rcsfile->path);
|
||||
return (1);
|
||||
}
|
||||
RCS_rewrite (rcsfile, NULL, NULL);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Clear any lock we may hold on the current directory. */
|
||||
|
||||
static int
|
||||
rtag_filesdoneproc (callerdat, err, repos, update_dir, entries)
|
||||
void *callerdat;
|
||||
int err;
|
||||
char *repos;
|
||||
char *update_dir;
|
||||
List *entries;
|
||||
{
|
||||
Lock_Cleanup ();
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a warm fuzzy message
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static Dtype
|
||||
rtag_dirproc (callerdat, dir, repos, update_dir, entries)
|
||||
void *callerdat;
|
||||
char *dir;
|
||||
char *repos;
|
||||
char *update_dir;
|
||||
List *entries;
|
||||
{
|
||||
if (ignore_directory (update_dir))
|
||||
{
|
||||
/* print the warm fuzzy message */
|
||||
if (!quiet)
|
||||
error (0, 0, "Ignoring %s", update_dir);
|
||||
return R_SKIP_ALL;
|
||||
}
|
||||
|
||||
if (!quiet)
|
||||
error (0, 0, "%s %s", delete_flag ? "Untagging" : "Tagging",
|
||||
update_dir);
|
||||
return (R_PROCESS);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user