Annotation of src/usr.bin/rcs/rlog.c, Revision 1.29
1.29 ! ray 1: /* $OpenBSD: rlog.c,v 1.28 2006/03/08 12:34:53 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.29 ! ray 99: /* NOTREACHED */
1.20 xsa 100: case 'w':
101: wflag = 1;
102: wlist = rcs_optarg;
103: break;
1.14 xsa 104: case 'x':
105: rcs_suffixes = rcs_optarg;
106: break;
1.26 joris 107: case 'z':
108: timezone_flag = rcs_optarg;
1.27 xsa 109: break;
1.1 joris 110: default:
1.21 xsa 111: (usage());
112: exit(1);
1.1 joris 113: }
114: }
115:
1.5 joris 116: argc -= rcs_optind;
117: argv += rcs_optind;
1.1 joris 118:
119: if (argc == 0) {
120: cvs_log(LP_ERR, "no input file");
121: (usage)();
122: exit(1);
123: }
124:
1.7 xsa 125: if ((hflag == 1) && (tflag == 1)) {
1.6 xsa 126: cvs_log(LP_WARN, "warning: -t overrides -h.");
1.7 xsa 127: hflag = 0;
128: }
1.6 xsa 129:
1.1 joris 130: for (i = 0; i < argc; i++) {
131: if (rcs_statfile(argv[i], fpath, sizeof(fpath)) < 0)
132: continue;
133:
1.17 niallo 134: if ((file = rcs_open(fpath, RCS_READ|RCS_PARSE_FULLY)) == NULL)
1.11 xsa 135: continue;
136:
137: if ((Lflag == 1) && (TAILQ_EMPTY(&(file->rf_locks)))) {
138: rcs_close(file);
139: continue;
140: }
141:
1.9 xsa 142: if (Rflag == 1) {
143: printf("%s\n", fpath);
1.11 xsa 144: rcs_close(file);
1.9 xsa 145: continue;
146: }
147:
1.23 xsa 148: rlog_file(argv[i], fpath);
1.9 xsa 149:
1.1 joris 150: rcs_close(file);
151: }
152:
153: return (0);
154: }
155:
156: static int
1.23 xsa 157: rlog_file(const char *fname, const char *fpath)
1.1 joris 158: {
159: char numb[64];
160: struct rcs_sym *sym;
161: struct rcs_access *acp;
1.20 xsa 162: struct rcs_delta *rdp;
1.10 xsa 163: struct rcs_lock *lkp;
1.1 joris 164:
1.12 xsa 165: printf("\nRCS file: %s", fpath);
1.6 xsa 166: printf("\nWorking file: %s", fname);
1.1 joris 167: printf("\nhead:");
168: if (file->rf_head != NULL)
169: printf(" %s", rcsnum_tostr(file->rf_head, numb, sizeof(numb)));
170:
171: printf("\nbranch:");
172: if (rcs_branch_get(file) != NULL) {
173: printf(" %s", rcsnum_tostr(rcs_branch_get(file),
174: numb, sizeof(numb)));
175: }
176:
177: printf("\nlocks: %s", (file->rf_flags & RCS_SLOCK) ? "strict" : "");
1.10 xsa 178: TAILQ_FOREACH(lkp, &(file->rf_locks), rl_list)
179: printf("\n\t%s: %s", lkp->rl_name,
180: rcsnum_tostr(lkp->rl_num, numb, sizeof(numb)));
1.1 joris 181: printf("\naccess list:\n");
182: TAILQ_FOREACH(acp, &(file->rf_access), ra_list)
183: printf("\t%s\n", acp->ra_name);
184:
185: if (Nflag == 0) {
186: printf("symbolic names:\n");
187: TAILQ_FOREACH(sym, &(file->rf_symbols), rs_list) {
188: printf("\t%s: %s\n", sym->rs_name,
189: rcsnum_tostr(sym->rs_num, numb, sizeof(numb)));
190: }
191: }
192:
193: printf("keyword substitution: %s\n",
194: file->rf_expand == NULL ? "kv" : file->rf_expand);
195:
1.20 xsa 196: printf("total revisions: %u", file->rf_ndelta);
197:
198: if ((hflag == 0) && (tflag == 0))
199: printf(";\tselected revisions:"); /* XXX */
200:
201: printf("\n");
202:
1.1 joris 203:
204: if ((hflag == 0) || (tflag == 1))
1.13 xsa 205: printf("description:\n%s", file->rf_desc);
1.1 joris 206:
1.20 xsa 207: if ((hflag == 0) && (tflag == 0)) {
208: TAILQ_FOREACH(rdp, &(file->rf_delta), rd_list)
209: rlog_rev_print(rdp);
210: }
1.1 joris 211:
212: printf("%s\n", REVEND);
213: return (0);
1.16 xsa 214: }
215:
216: static void
1.20 xsa 217: rlog_rev_print(struct rcs_delta *rdp)
1.16 xsa 218: {
1.20 xsa 219: int i, found;
220: char *author, numb[64];
1.23 xsa 221: char **largv, **sargv, **wargv;
1.20 xsa 222:
223: i = found = 0;
224: author = NULL;
225:
1.23 xsa 226: /* -l[lockers] */
227: if (lflag == 1) {
228: /* if no locks at all, abort. */
229: if (TAILQ_EMPTY(&(file->rf_locks)))
230: return;
231: else
232: if (rdp->rd_locker != NULL)
233: found++;
234:
235: if (llist != NULL) {
236: /* if locker is empty, no need to go further. */
237: if (rdp->rd_locker == NULL)
238: return;
239: largv = rlog_strsplit(llist, ",");
240: for (i = 0; largv[i] != NULL; i++) {
241: if (strcmp(rdp->rd_locker, largv[i]) == 0) {
242: found++;
243: break;
244: }
245: found = 0;
246: }
247: }
248: }
1.20 xsa 249: /* -sstates */
250: if (slist != NULL) {
251: sargv = rlog_strsplit(slist, ",");
252: for (i = 0; sargv[i] != NULL; i++) {
253: if (strcmp(rdp->rd_state, sargv[i]) == 0) {
254: found++;
255: break;
256: }
257: found = 0;
258: }
259: }
260: /* -w[logins] */
261: if (wflag == 1) {
262: if (wlist != NULL) {
263: wargv = rlog_strsplit(wlist, ",");
264: for (i = 0; wargv[i] != NULL; i++) {
265: if (strcmp(rdp->rd_author, wargv[i]) == 0) {
266: found++;
267: break;
268: }
269: found = 0;
270: }
271: } else {
272: if ((author = getlogin()) == NULL)
273: fatal("getlogin failed");
1.16 xsa 274:
1.20 xsa 275: if (strcmp(rdp->rd_author, author) == 0)
276: found++;
277: }
278: }
1.16 xsa 279:
1.20 xsa 280: /* XXX dirty... */
1.23 xsa 281: if (((((slist != NULL) && (wflag == 1)) ||
282: ((slist != NULL) && (lflag == 1)) ||
283: ((lflag == 1) && (wflag == 1))) && (found < 2)) ||
284: ((((slist != NULL) && (lflag == 1) && (wflag == 1)) ||
285: ((slist != NULL) || (lflag == 1) || (wflag == 1))) && (found == 0)))
1.20 xsa 286: return;
287:
288: printf("%s\n", REVSEP);
289:
290: rcsnum_tostr(rdp->rd_num, numb, sizeof(numb));
291:
1.22 xsa 292: printf("revision %s", numb);
293: if (rdp->rd_locker != NULL)
294: printf("\tlocked by: %s;", rdp->rd_locker);
295: printf("\ndate: %d/%02d/%02d %02d:%02d:%02d;"
1.20 xsa 296: " author: %s; state: %s;\n",
297: rdp->rd_date.tm_year + 1900,
298: rdp->rd_date.tm_mon + 1,
299: rdp->rd_date.tm_mday, rdp->rd_date.tm_hour,
300: rdp->rd_date.tm_min, rdp->rd_date.tm_sec,
301: rdp->rd_author, rdp->rd_state);
302: printf("%s", rdp->rd_log);
303: }
1.16 xsa 304:
1.20 xsa 305: /*
306: * rlog_strsplit()
307: *
308: * Split a string <str> of <sep>-separated values and allocate
309: * an argument vector for the values found.
310: */
311: static char **
312: rlog_strsplit(char *str, const char *sep)
313: {
314: char **argv, **nargv;
315: char *cp, *p;
316: int i = 0;
317:
318: cp = xstrdup(str);
319: argv = (char **)xmalloc((i+1) * sizeof(char *));
320:
321: while ((p = strsep(&cp, sep)) != NULL) {
322: argv[i++] = p;
323: nargv = (char **)xrealloc((void *)argv, (i+1) * sizeof(char *));
324: argv = nargv;
1.16 xsa 325: }
1.20 xsa 326: argv[i] = NULL;
327:
328: return (argv);
1.1 joris 329: }