Annotation of src/usr.bin/rcs/rlog.c, Revision 1.28
1.28 ! xsa 1: /* $OpenBSD: rlog.c,v 1.27 2006/03/07 09:19:11 xsa Exp $ */
1.1 joris 2: /*
3: * Copyright (c) 2005 Joris Vink <joris@openbsd.org>
1.20 xsa 4: * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org>
1.1 joris 5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: *
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. The name of the author may not be used to endorse or promote products
14: * derived from this software without specific prior written permission.
15: *
16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26: */
27:
1.18 xsa 28: #include "includes.h"
1.1 joris 29:
1.19 xsa 30: #include "rcsprog.h"
1.3 niallo 31: #include "diff.h"
1.1 joris 32:
1.23 xsa 33: static int rlog_file(const char *, const char *);
1.20 xsa 34: static void rlog_rev_print(struct rcs_delta *);
35: static char **rlog_strsplit(char *, const char *);
1.1 joris 36:
37: #define REVSEP "----------------------------"
38: #define REVEND \
1.6 xsa 39: "============================================================================="
1.1 joris 40:
1.23 xsa 41: static int hflag, Lflag, lflag, tflag, Nflag, wflag;
42: static char *llist = NULL;
1.20 xsa 43: static char *slist = NULL;
44: static char *wlist = NULL;
1.23 xsa 45: static RCSFILE *file;
1.1 joris 46:
1.21 xsa 47: void
48: rlog_usage(void)
49: {
50: fprintf(stderr,
1.25 jmc 51: "usage: rlog [-bhLNqRtV] [-ddates] [-l[lockers]] [-r[revs]]\n"
1.28 ! xsa 52: " [-sstates] [-w[logins]] [-xsuffixes]\n"
! 53: " [-ztz] file ...\n");
1.21 xsa 54: }
55:
1.1 joris 56: int
57: rlog_main(int argc, char **argv)
58: {
59: int Rflag;
60: int i, ch;
61: char fpath[MAXPATHLEN];
62:
63: hflag = Rflag = 0;
1.26 joris 64: while ((ch = rcs_getopt(argc, argv, "hLl::NqRs:TtVw::x:z:")) != -1) {
1.1 joris 65: switch (ch) {
66: case 'h':
67: hflag = 1;
68: break;
1.11 xsa 69: case 'L':
70: Lflag = 1;
71: break;
1.23 xsa 72: case 'l':
73: lflag = 1;
74: llist = rcs_optarg;
75: break;
1.1 joris 76: case 'N':
77: Nflag = 1;
78: break;
79: case 'q':
80: verbose = 0;
81: break;
82: case 'R':
83: Rflag = 1;
84: break;
1.20 xsa 85: case 's':
86: slist = rcs_optarg;
87: break;
1.8 xsa 88: case 'T':
89: /*
90: * kept for compatibility
91: */
92: break;
1.1 joris 93: case 't':
94: tflag = 1;
95: break;
96: case 'V':
97: printf("%s\n", rcs_version);
98: exit(0);
1.20 xsa 99: case 'w':
100: wflag = 1;
101: wlist = rcs_optarg;
102: break;
1.14 xsa 103: case 'x':
104: rcs_suffixes = rcs_optarg;
105: break;
1.26 joris 106: case 'z':
107: timezone_flag = rcs_optarg;
1.27 xsa 108: break;
1.1 joris 109: default:
1.21 xsa 110: (usage());
111: exit(1);
1.1 joris 112: }
113: }
114:
1.5 joris 115: argc -= rcs_optind;
116: argv += rcs_optind;
1.1 joris 117:
118: if (argc == 0) {
119: cvs_log(LP_ERR, "no input file");
120: (usage)();
121: exit(1);
122: }
123:
1.7 xsa 124: if ((hflag == 1) && (tflag == 1)) {
1.6 xsa 125: cvs_log(LP_WARN, "warning: -t overrides -h.");
1.7 xsa 126: hflag = 0;
127: }
1.6 xsa 128:
1.1 joris 129: for (i = 0; i < argc; i++) {
130: if (rcs_statfile(argv[i], fpath, sizeof(fpath)) < 0)
131: continue;
132:
1.17 niallo 133: if ((file = rcs_open(fpath, RCS_READ|RCS_PARSE_FULLY)) == NULL)
1.11 xsa 134: continue;
135:
136: if ((Lflag == 1) && (TAILQ_EMPTY(&(file->rf_locks)))) {
137: rcs_close(file);
138: continue;
139: }
140:
1.9 xsa 141: if (Rflag == 1) {
142: printf("%s\n", fpath);
1.11 xsa 143: rcs_close(file);
1.9 xsa 144: continue;
145: }
146:
1.23 xsa 147: rlog_file(argv[i], fpath);
1.9 xsa 148:
1.1 joris 149: rcs_close(file);
150: }
151:
152: return (0);
153: }
154:
155: static int
1.23 xsa 156: rlog_file(const char *fname, const char *fpath)
1.1 joris 157: {
158: char numb[64];
159: struct rcs_sym *sym;
160: struct rcs_access *acp;
1.20 xsa 161: struct rcs_delta *rdp;
1.10 xsa 162: struct rcs_lock *lkp;
1.1 joris 163:
1.12 xsa 164: printf("\nRCS file: %s", fpath);
1.6 xsa 165: printf("\nWorking file: %s", fname);
1.1 joris 166: printf("\nhead:");
167: if (file->rf_head != NULL)
168: printf(" %s", rcsnum_tostr(file->rf_head, numb, sizeof(numb)));
169:
170: printf("\nbranch:");
171: if (rcs_branch_get(file) != NULL) {
172: printf(" %s", rcsnum_tostr(rcs_branch_get(file),
173: numb, sizeof(numb)));
174: }
175:
176: printf("\nlocks: %s", (file->rf_flags & RCS_SLOCK) ? "strict" : "");
1.10 xsa 177: TAILQ_FOREACH(lkp, &(file->rf_locks), rl_list)
178: printf("\n\t%s: %s", lkp->rl_name,
179: rcsnum_tostr(lkp->rl_num, numb, sizeof(numb)));
1.1 joris 180: printf("\naccess list:\n");
181: TAILQ_FOREACH(acp, &(file->rf_access), ra_list)
182: printf("\t%s\n", acp->ra_name);
183:
184: if (Nflag == 0) {
185: printf("symbolic names:\n");
186: TAILQ_FOREACH(sym, &(file->rf_symbols), rs_list) {
187: printf("\t%s: %s\n", sym->rs_name,
188: rcsnum_tostr(sym->rs_num, numb, sizeof(numb)));
189: }
190: }
191:
192: printf("keyword substitution: %s\n",
193: file->rf_expand == NULL ? "kv" : file->rf_expand);
194:
1.20 xsa 195: printf("total revisions: %u", file->rf_ndelta);
196:
197: if ((hflag == 0) && (tflag == 0))
198: printf(";\tselected revisions:"); /* XXX */
199:
200: printf("\n");
201:
1.1 joris 202:
203: if ((hflag == 0) || (tflag == 1))
1.13 xsa 204: printf("description:\n%s", file->rf_desc);
1.1 joris 205:
1.20 xsa 206: if ((hflag == 0) && (tflag == 0)) {
207: TAILQ_FOREACH(rdp, &(file->rf_delta), rd_list)
208: rlog_rev_print(rdp);
209: }
1.1 joris 210:
211: printf("%s\n", REVEND);
212: return (0);
1.16 xsa 213: }
214:
215: static void
1.20 xsa 216: rlog_rev_print(struct rcs_delta *rdp)
1.16 xsa 217: {
1.20 xsa 218: int i, found;
219: char *author, numb[64];
1.23 xsa 220: char **largv, **sargv, **wargv;
1.20 xsa 221:
222: i = found = 0;
223: author = NULL;
224:
1.23 xsa 225: /* -l[lockers] */
226: if (lflag == 1) {
227: /* if no locks at all, abort. */
228: if (TAILQ_EMPTY(&(file->rf_locks)))
229: return;
230: else
231: if (rdp->rd_locker != NULL)
232: found++;
233:
234: if (llist != NULL) {
235: /* if locker is empty, no need to go further. */
236: if (rdp->rd_locker == NULL)
237: return;
238: largv = rlog_strsplit(llist, ",");
239: for (i = 0; largv[i] != NULL; i++) {
240: if (strcmp(rdp->rd_locker, largv[i]) == 0) {
241: found++;
242: break;
243: }
244: found = 0;
245: }
246: }
247: }
1.20 xsa 248: /* -sstates */
249: if (slist != NULL) {
250: sargv = rlog_strsplit(slist, ",");
251: for (i = 0; sargv[i] != NULL; i++) {
252: if (strcmp(rdp->rd_state, sargv[i]) == 0) {
253: found++;
254: break;
255: }
256: found = 0;
257: }
258: }
259: /* -w[logins] */
260: if (wflag == 1) {
261: if (wlist != NULL) {
262: wargv = rlog_strsplit(wlist, ",");
263: for (i = 0; wargv[i] != NULL; i++) {
264: if (strcmp(rdp->rd_author, wargv[i]) == 0) {
265: found++;
266: break;
267: }
268: found = 0;
269: }
270: } else {
271: if ((author = getlogin()) == NULL)
272: fatal("getlogin failed");
1.16 xsa 273:
1.20 xsa 274: if (strcmp(rdp->rd_author, author) == 0)
275: found++;
276: }
277: }
1.16 xsa 278:
1.20 xsa 279: /* XXX dirty... */
1.23 xsa 280: if (((((slist != NULL) && (wflag == 1)) ||
281: ((slist != NULL) && (lflag == 1)) ||
282: ((lflag == 1) && (wflag == 1))) && (found < 2)) ||
283: ((((slist != NULL) && (lflag == 1) && (wflag == 1)) ||
284: ((slist != NULL) || (lflag == 1) || (wflag == 1))) && (found == 0)))
1.20 xsa 285: return;
286:
287: printf("%s\n", REVSEP);
288:
289: rcsnum_tostr(rdp->rd_num, numb, sizeof(numb));
290:
1.22 xsa 291: printf("revision %s", numb);
292: if (rdp->rd_locker != NULL)
293: printf("\tlocked by: %s;", rdp->rd_locker);
294: printf("\ndate: %d/%02d/%02d %02d:%02d:%02d;"
1.20 xsa 295: " author: %s; state: %s;\n",
296: rdp->rd_date.tm_year + 1900,
297: rdp->rd_date.tm_mon + 1,
298: rdp->rd_date.tm_mday, rdp->rd_date.tm_hour,
299: rdp->rd_date.tm_min, rdp->rd_date.tm_sec,
300: rdp->rd_author, rdp->rd_state);
301: printf("%s", rdp->rd_log);
302: }
1.16 xsa 303:
1.20 xsa 304: /*
305: * rlog_strsplit()
306: *
307: * Split a string <str> of <sep>-separated values and allocate
308: * an argument vector for the values found.
309: */
310: static char **
311: rlog_strsplit(char *str, const char *sep)
312: {
313: char **argv, **nargv;
314: char *cp, *p;
315: int i = 0;
316:
317: cp = xstrdup(str);
318: argv = (char **)xmalloc((i+1) * sizeof(char *));
319:
320: while ((p = strsep(&cp, sep)) != NULL) {
321: argv[i++] = p;
322: nargv = (char **)xrealloc((void *)argv, (i+1) * sizeof(char *));
323: argv = nargv;
1.16 xsa 324: }
1.20 xsa 325: argv[i] = NULL;
326:
327: return (argv);
1.1 joris 328: }