this is not used anymore.
This commit is contained in:
parent
71a5c52102
commit
a65d983bd0
|
@ -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…
Reference in New Issue