diff options
Diffstat (limited to 'contrib/cvs/src/history.c')
-rw-r--r-- | contrib/cvs/src/history.c | 186 |
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); } } |