summaryrefslogtreecommitdiff
path: root/contrib/cvs/src/history.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/history.c')
-rw-r--r--contrib/cvs/src/history.c186
1 files changed, 134 insertions, 52 deletions
diff --git a/contrib/cvs/src/history.c b/contrib/cvs/src/history.c
index 81c71ffbea5a0..7d28e8102388d 100644
--- a/contrib/cvs/src/history.c
+++ b/contrib/cvs/src/history.c
@@ -17,6 +17,7 @@
* X is a single character showing the type of event:
* T "Tag" cmd.
* O "Checkout" cmd.
+ * E "Export" cmd.
* F "Release" cmd.
* W "Update" cmd - No User file, Remove from Entries file.
* U "Update" cmd - File was checked out over User file.
@@ -40,18 +41,18 @@
* command was typed.
* T "A" --> New Tag, "D" --> Delete Tag
* Otherwise it is the Tag or Date to modify.
- * O,F A "" (null field)
+ * O,F,E A "" (null field)
*
* rev(s) Revision number or tag.
* T The Tag to apply.
- * O The Tag or Date, if specified, else "" (null field).
+ * O,E The Tag or Date, if specified, else "" (null field).
* F "" (null field)
* W The Tag or Date, if specified, else "" (null field).
* U The Revision checked out over the User file.
* G,C The Revision(s) involved in merge.
* M,A,R RCS Revision affected.
*
- * argument The module (for [TOUF]) or file (for [WUGCMAR]) affected.
+ * argument The module (for [TOEUF]) or file (for [WUGCMAR]) affected.
*
*
*** Report categories: "User" and "Since" modifiers apply to all reports.
@@ -59,7 +60,7 @@
*
* Extract list of record types
*
- * -e, -x [TOFWUGCMAR]
+ * -e, -x [TOEFWUGCMAR]
*
* Extracted records are simply printed, No analysis is performed.
* All "field" modifiers apply. -e chooses all types.
@@ -177,6 +178,7 @@
*/
#include "cvs.h"
+#include "savecwd.h"
static struct hrec
{
@@ -206,7 +208,7 @@ static void save_file PROTO((char *dir, char *name, char *module));
static void save_module PROTO((char *module));
static void save_user PROTO((char *name));
-#define ALL_REC_TYPES "TOFWUCGMAR"
+#define ALL_REC_TYPES "TOEFWUCGMAR"
#define USER_INCREMENT 2
#define FILE_INCREMENT 128
#define MODULE_INCREMENT 5
@@ -236,13 +238,24 @@ static char *tz_name = "+0000";
static char tz_name[] = "LT";
#endif
+/* -r, -t, or -b options, malloc'd. These are "" if the option in
+ question is not specified or is overridden by another option. The
+ main reason for using "" rather than NULL is historical. Together
+ with since_date, these are a mutually exclusive set; one overrides the
+ others. */
+static char *since_rev;
+static char *since_tag;
+static char *backto;
+/* -D option, or 0 if not specified. */
static time_t since_date;
-static char since_rev[20]; /* Maxrev ~= 99.99.99.999 */
-static char since_tag[64];
+
static struct hrec *last_since_tag;
-static char backto[128];
static struct hrec *last_backto;
-static char rec_types[20];
+
+/* Record types to look for, malloc'd. Probably could be statically
+ allocated, but only if we wanted to check for duplicates more than
+ we do. */
+static char *rec_types;
static int hrec_count;
static int hrec_max;
@@ -265,6 +278,12 @@ static int mod_count; /* Number of elements used */
static char *histfile; /* Ptr to the history file name */
+/* This is pretty unclear. First of all, separating "flags" vs.
+ "options" (I think the distinction is that "options" take arguments)
+ is nonstandard, and not something we do elsewhere in CVS. Second of
+ all, what does "reports" mean? I think it means that you can only
+ supply one of those options, but "reports" hardly has that meaning in
+ a self-explanatory way. */
static const char *const history_usg[] =
{
"Usage: %s %s [-report] [-flags] [-options args] [files...]\n\n",
@@ -273,7 +292,7 @@ static const char *const history_usg[] =
" -c Committed (Modified) files\n",
" -o Checked out modules\n",
" -m <module> Look for specified module (repeatable)\n",
- " -x [TOFWUCGMAR] Extract by record type\n",
+ " -x [TOEFWUCGMAR] Extract by record type\n",
" Flags:\n",
" -a All users (Default is self)\n",
" -e Everything (same as -x, but all record types)\n",
@@ -367,13 +386,17 @@ history (argc, argv)
char **argv;
{
int i, c;
- char fname[PATH_MAX];
+ char *fname;
if (argc == -1)
usage (history_usg);
+ since_rev = xstrdup ("");
+ since_tag = xstrdup ("");
+ backto = xstrdup ("");
+ rec_types = xstrdup ("");
optind = 1;
- while ((c = getopt (argc, argv, "Tacelow?D:b:f:m:n:p:r:t:u:x:X:z:")) != -1)
+ while ((c = getopt (argc, argv, "+Tacelow?D:b:f:m:n:p:r:t:u:x:X:z:")) != -1)
{
switch (c)
{
@@ -391,7 +414,8 @@ history (argc, argv)
case 'e':
report_count++;
extract++;
- (void) strcpy (rec_types, ALL_REC_TYPES);
+ free (rec_types);
+ rec_types = xstrdup (ALL_REC_TYPES);
break;
case 'l': /* Find Last file record */
last_entry = 1;
@@ -421,13 +445,8 @@ history (argc, argv)
*since_rev = *since_tag = '\0';
since_date = 0;
}
- if (strlen (optarg) >= sizeof (backto))
- {
- error (0, 0, "backto truncated to %d bytes",
- sizeof (backto) - 1);
- optarg[sizeof (backto) - 1] = '\0';
- }
- (void) strcpy (backto, optarg);
+ free (backto);
+ backto = xstrdup (optarg);
break;
case 'f': /* For specified file */
save_file ("", optarg, (char *) NULL);
@@ -448,7 +467,8 @@ history (argc, argv)
*since_tag = *backto = '\0';
since_date = 0;
}
- (void) strcpy (since_rev, optarg);
+ free (since_rev);
+ since_rev = xstrdup (optarg);
break;
case 't': /* Since specified Tag/Rev */
if (since_date || *since_rev || *backto)
@@ -457,7 +477,8 @@ history (argc, argv)
*since_rev = *backto = '\0';
since_date = 0;
}
- (void) strcpy (since_tag, optarg); /* tag */
+ free (since_tag);
+ since_tag = xstrdup (optarg);
break;
case 'u': /* For specified username */
save_user (optarg);
@@ -472,7 +493,8 @@ history (argc, argv)
if (!strchr (ALL_REC_TYPES, *cp))
error (1, 0, "%c is not a valid report type", *cp);
}
- (void) strcpy (rec_types, optarg);
+ free (rec_types);
+ rec_types = xstrdup (optarg);
break;
case 'z':
#ifndef HAVE_RCS5
@@ -564,9 +586,9 @@ history (argc, argv)
send_arg("-m");
for (mod = mod_list; mod < &mod_list[mod_count]; ++mod)
option_with_arg ("-n", *mod);
- if (since_rev != NULL)
+ if (*since_rev)
option_with_arg ("-r", since_rev);
- if (since_tag != NULL)
+ if (*since_tag)
option_with_arg ("-t", since_tag);
for (mod = user_list; mod < &user_list[user_count]; ++mod)
option_with_arg ("-u", *mod);
@@ -588,7 +610,10 @@ history (argc, argv)
if (tag_report)
{
if (!strchr (rec_types, 'T'))
+ {
+ rec_types = xrealloc (rec_types, strlen (rec_types) + 5);
(void) strcat (rec_types, "T");
+ }
}
else if (extract)
{
@@ -597,7 +622,8 @@ history (argc, argv)
}
else if (modified)
{
- (void) strcpy (rec_types, "MAR");
+ free (rec_types);
+ rec_types = xstrdup ("MAR");
/*
* If the user has not specified a date oriented flag ("Since"), sort
* by Repository/file before date. Default is "just" date.
@@ -616,7 +642,8 @@ history (argc, argv)
}
else if (module_report)
{
- (void) strcpy (rec_types, last_entry ? "OMAR" : ALL_REC_TYPES);
+ free (rec_types);
+ rec_types = xstrdup (last_entry ? "OMAR" : ALL_REC_TYPES);
module_sort++;
repos_sort++;
file_sort++;
@@ -625,7 +652,8 @@ history (argc, argv)
else
/* Must be "checkout" or default */
{
- (void) strcpy (rec_types, "OF");
+ free (rec_types);
+ rec_types = xstrdup ("OF");
/* See comments in "modified" above */
if (!last_entry && user_list)
user_sort++;
@@ -639,7 +667,10 @@ history (argc, argv)
/* If we're looking back to a Tag value, must consider "Tag" records */
if (*since_tag && !strchr (rec_types, 'T'))
+ {
+ rec_types = xrealloc (rec_types, strlen (rec_types) + 5);
(void) strcat (rec_types, "T");
+ }
argc -= c;
argv += c;
@@ -647,14 +678,23 @@ history (argc, argv)
save_file ("", argv[i], (char *) NULL);
if (histfile)
- (void) strcpy (fname, histfile);
+ fname = xstrdup (histfile);
else
- (void) sprintf (fname, "%s/%s/%s", CVSroot,
+ {
+ fname = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM)
+ + sizeof (CVSROOTADM_HISTORY) + 10);
+ (void) sprintf (fname, "%s/%s/%s", CVSroot_directory,
CVSROOTADM, CVSROOTADM_HISTORY);
+ }
read_hrecs (fname);
qsort ((PTR) hrec_head, hrec_count, sizeof (struct hrec), sort_order);
report_hrecs ();
+ free (fname);
+ free (since_rev);
+ free (since_tag);
+ free (backto);
+ free (rec_types);
return (0);
}
@@ -667,7 +707,8 @@ history_write (type, update_dir, revs, name, repository)
char *name;
char *repository;
{
- char fname[PATH_MAX], workdir[PATH_MAX], homedir[PATH_MAX];
+ char *fname;
+ char *workdir;
char *username = getcaller ();
int fd;
char *line;
@@ -678,13 +719,16 @@ history_write (type, update_dir, revs, name, repository)
if (logoff) /* History is turned off by cmd line switch */
return;
- (void) sprintf (fname, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_HISTORY);
+ fname = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM)
+ + sizeof (CVSROOTADM_HISTORY) + 10);
+ (void) sprintf (fname, "%s/%s/%s", CVSroot_directory,
+ CVSROOTADM, CVSROOTADM_HISTORY);
/* turn off history logging if the history file does not exist */
if (!isfile (fname))
{
logoff = 1;
- return;
+ goto out;
}
if (trace)
@@ -695,8 +739,8 @@ history_write (type, update_dir, revs, name, repository)
fprintf (stderr, "-> fopen(%s,a)\n", fname);
#endif
if (noexec)
- return;
- fd = open (fname, O_WRONLY | O_APPEND | O_CREAT | OPEN_BINARY, 0666);
+ goto out;
+ fd = CVS_OPEN (fname, O_WRONLY | O_APPEND | O_CREAT | OPEN_BINARY, 0666);
if (fd < 0)
error (1, errno, "cannot open history file: %s", fname);
@@ -720,13 +764,21 @@ history_write (type, update_dir, revs, name, repository)
else
{
/* Try harder to find a "homedir" */
- if (!getwd (workdir))
- error (1, errno, "can't getwd in history");
- if (chdir (pwdir) < 0)
+ struct saved_cwd cwd;
+ char *homedir;
+
+ if (save_cwd (&cwd))
+ error_exit ();
+
+ if ( CVS_CHDIR (pwdir) < 0)
error (1, errno, "can't chdir(%s)", pwdir);
- if (!getwd (homedir))
+ homedir = xgetwd ();
+ if (homedir == NULL)
error (1, errno, "can't getwd in %s", pwdir);
- (void) chdir (workdir);
+
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+ free_cwd (&cwd);
i = strlen (homedir);
if (!strncmp (CurDir, homedir, i))
@@ -734,6 +786,7 @@ history_write (type, update_dir, revs, name, repository)
PrCurDir += i; /* Point to '/' separator */
tilde = "~";
}
+ free (homedir);
}
}
}
@@ -748,6 +801,8 @@ history_write (type, update_dir, revs, name, repository)
else
update_dir = "";
+ workdir = xmalloc (strlen (tilde) + strlen (PrCurDir) + strlen (slash)
+ + strlen (update_dir) + 10);
(void) sprintf (workdir, "%s%s%s%s", tilde, PrCurDir, slash, update_dir);
/*
@@ -821,6 +876,9 @@ history_write (type, update_dir, revs, name, repository)
free (line);
if (close (fd) != 0)
error (1, errno, "cannot close history file: %s", fname);
+ free (workdir);
+ out:
+ free (fname);
}
/*
@@ -968,7 +1026,7 @@ fill_hrec (line, hr)
NEXT_BAR (repos);
NEXT_BAR (rev);
hr->idx = idx++;
- if (strchr ("FOT", *(hr->type)))
+ if (strchr ("FOET", *(hr->type)))
hr->mod = line;
NEXT_BAR (file); /* This returns ptr to next line or final '\0' */
@@ -994,7 +1052,7 @@ read_hrecs (fname)
struct hrec *hr;
struct stat st_buf;
- if ((fd = open (fname, O_RDONLY | OPEN_BINARY)) < 0)
+ if ((fd = CVS_OPEN (fname, O_RDONLY | OPEN_BINARY)) < 0)
error (1, errno, "cannot open history file: %s", fname);
if (fstat (fd, &st_buf) < 0)
@@ -1134,9 +1192,19 @@ select_hrec (hr)
{
Vers_TS *vers;
time_t t;
-
- vers = Version_TS (hr->repos, (char *) NULL, since_rev, (char *) NULL,
- hr->file, 1, 0, (List *) NULL, (RCSNode *) NULL);
+ struct file_info finfo;
+
+ memset (&finfo, 0, sizeof finfo);
+ finfo.file = hr->file;
+ /* Not used, so don't worry about it. */
+ finfo.update_dir = NULL;
+ finfo.fullname = finfo.file;
+ finfo.repository = hr->repos;
+ finfo.entries = NULL;
+ finfo.rcs = NULL;
+
+ vers = Version_TS (&finfo, (char *) NULL, since_rev, (char *) NULL,
+ 1, 0);
if (vers->vn_rcs)
{
if ((t = RCS_getrevtime (vers->srcfile, vers->vn_rcs, (char *) 0, 0))
@@ -1208,7 +1276,7 @@ select_hrec (hr)
*/
if (!strchr (rec_types, *(hr->type)))
return (0);
- if (!strchr ("TFO", *(hr->type))) /* Don't bother with "file" if "TFO" */
+ if (!strchr ("TFOE", *(hr->type))) /* Don't bother with "file" if "TFOE" */
{
if (file_list) /* If file_list is null, accept all */
{
@@ -1220,7 +1288,7 @@ select_hrec (hr)
* the concatenation of the repository and file from hrec.
* 3. Else compare the file_list entry against the hrec file.
*/
- char cmpfile[PATH_MAX];
+ char *cmpfile = NULL;
if (*(cp = fl->l_file) == '*')
{
@@ -1236,8 +1304,12 @@ select_hrec (hr)
{
if (strchr (cp, '/'))
{
- (void) sprintf (cp2 = cmpfile, "%s/%s",
+ cmpfile = xmalloc (strlen (hr->repos)
+ + strlen (hr->file)
+ + 10);
+ (void) sprintf (cmpfile, "%s/%s",
hr->repos, hr->file);
+ cp2 = cmpfile;
}
else
{
@@ -1250,6 +1322,8 @@ select_hrec (hr)
hr->mod = fl->l_module;
break;
}
+ if (cmpfile != NULL)
+ free (cmpfile);
}
}
if (!count)
@@ -1308,7 +1382,7 @@ report_hrecs ()
hr++;
for (count = hrec_count; count--; lr = hr, hr++)
{
- char repos[PATH_MAX];
+ char *repos;
if (!count)
hr = NULL;
@@ -1316,7 +1390,7 @@ report_hrecs ()
continue;
ty = *(lr->type);
- (void) strcpy (repos, lr->repos);
+ repos = xstrdup (lr->repos);
if ((cp = strrchr (repos, '/')) != NULL)
{
if (lr->mod && !strcmp (++cp, lr->mod))
@@ -1334,6 +1408,7 @@ report_hrecs ()
rev_len = i;
if (lr->mod && (i = strlen (lr->mod)) > mod_len)
mod_len = i;
+ free (repos);
}
/* Walk through hrec array setting "lr" (Last Record) to each element.
@@ -1347,7 +1422,8 @@ report_hrecs ()
*/
for (lr = hrec_head, hr = (lr + 1); hrec_count--; lr = hr, hr++)
{
- char workdir[PATH_MAX], repos[PATH_MAX];
+ char *workdir;
+ char *repos;
if (!hrec_count)
hr = NULL;
@@ -1368,6 +1444,7 @@ report_hrecs ()
tm->tm_mday, tm->tm_hour, tm->tm_min, tz_name,
user_len, lr->user);
+ workdir = xmalloc (strlen (lr->dir) + strlen (lr->end) + 10);
(void) sprintf (workdir, "%s%s", lr->dir, lr->end);
if ((cp = strrchr (workdir, '/')) != NULL)
{
@@ -1376,6 +1453,7 @@ report_hrecs ()
(void) strcpy (cp, "*");
}
}
+ repos = xmalloc (strlen (lr->repos) + 10);
(void) strcpy (repos, lr->repos);
if ((cp = strrchr (repos, '/')) != NULL)
{
@@ -1395,11 +1473,13 @@ report_hrecs ()
(void) printf (" {%s}", workdir);
break;
case 'F':
+ case 'E':
case 'O':
if (lr->rev && *(lr->rev))
(void) printf (" [%s]", lr->rev);
(void) printf (" %-*s =%s%-*s %s", repos_len, repos, lr->mod,
- mod_len + 1 - strlen (lr->mod), "=", workdir);
+ mod_len + 1 - (int) strlen (lr->mod),
+ "=", workdir);
break;
case 'W':
case 'U':
@@ -1417,6 +1497,8 @@ report_hrecs ()
break;
}
(void) putchar ('\n');
+ free (workdir);
+ free (repos);
}
}