Annotation of src/usr.bin/rcs/rlog.c, Revision 1.56
1.56 ! niallo 1: /* $OpenBSD: rlog.c,v 1.55 2006/05/27 05:49:14 ray 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.44 ray 33: static void rlog_file(const char *, RCSFILE *);
1.32 xsa 34: static void rlog_rev_print(struct rcs_delta *);
1.1 joris 35:
1.38 xsa 36: #define RLOG_OPTSTRING "hLl::NqRr::s:TtVw::x::z::"
1.1 joris 37: #define REVSEP "----------------------------"
38: #define REVEND \
1.6 xsa 39: "============================================================================="
1.1 joris 40:
1.36 ray 41: static int hflag, Lflag, lflag, rflag, tflag, Nflag, wflag;
1.23 xsa 42: static char *llist = NULL;
1.20 xsa 43: static char *slist = NULL;
44: static char *wlist = NULL;
1.36 ray 45: static char *revisions = NULL;
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: {
1.44 ray 59: RCSFILE *file;
1.1 joris 60: int Rflag;
1.52 joris 61: int i, ch, fd;
1.1 joris 62: char fpath[MAXPATHLEN];
63:
1.45 joris 64: rcsnum_flags |= RCSNUM_NO_MAGIC;
1.36 ray 65: hflag = Rflag = rflag = 0;
66: while ((ch = rcs_getopt(argc, argv, RLOG_OPTSTRING)) != -1) {
1.1 joris 67: switch (ch) {
68: case 'h':
69: hflag = 1;
70: break;
1.11 xsa 71: case 'L':
72: Lflag = 1;
73: break;
1.23 xsa 74: case 'l':
75: lflag = 1;
76: llist = rcs_optarg;
77: break;
1.1 joris 78: case 'N':
79: Nflag = 1;
80: break;
81: case 'q':
1.47 xsa 82: /*
83: * kept for compatibility
84: */
1.1 joris 85: break;
1.37 xsa 86: case 'R':
87: Rflag = 1;
88: break;
1.36 ray 89: case 'r':
90: rflag = 1;
91: revisions = rcs_optarg;
92: break;
1.20 xsa 93: case 's':
94: slist = rcs_optarg;
95: break;
1.8 xsa 96: case 'T':
97: /*
98: * kept for compatibility
99: */
100: break;
1.1 joris 101: case 't':
102: tflag = 1;
103: break;
104: case 'V':
105: printf("%s\n", rcs_version);
106: exit(0);
1.20 xsa 107: case 'w':
108: wflag = 1;
109: wlist = rcs_optarg;
110: break;
1.14 xsa 111: case 'x':
1.33 ray 112: /* Use blank extension if none given. */
113: rcs_suffixes = rcs_optarg ? rcs_optarg : "";
1.14 xsa 114: break;
1.26 joris 115: case 'z':
116: timezone_flag = rcs_optarg;
1.27 xsa 117: break;
1.1 joris 118: default:
1.21 xsa 119: (usage());
120: exit(1);
1.1 joris 121: }
122: }
123:
1.5 joris 124: argc -= rcs_optind;
125: argv += rcs_optind;
1.1 joris 126:
127: if (argc == 0) {
1.48 xsa 128: warnx("no input file");
1.1 joris 129: (usage)();
130: exit(1);
131: }
132:
1.41 deraadt 133: if (hflag == 1 && tflag == 1) {
1.48 xsa 134: warnx("warning: -t overrides -h.");
1.7 xsa 135: hflag = 0;
136: }
1.6 xsa 137:
1.1 joris 138: for (i = 0; i < argc; i++) {
1.55 ray 139: fd = rcs_choosefile(argv[i], fpath, sizeof(fpath));
140: if (fd < 0) {
1.56 ! niallo 141: warn("%s", fpath);
1.1 joris 142: continue;
1.55 ray 143: }
1.1 joris 144:
1.52 joris 145: if ((file = rcs_open(fpath, fd,
146: RCS_READ|RCS_PARSE_FULLY)) == NULL)
1.11 xsa 147: continue;
148:
1.41 deraadt 149: if (Lflag == 1 && TAILQ_EMPTY(&(file->rf_locks))) {
1.11 xsa 150: rcs_close(file);
151: continue;
152: }
153:
1.9 xsa 154: if (Rflag == 1) {
155: printf("%s\n", fpath);
1.11 xsa 156: rcs_close(file);
1.9 xsa 157: continue;
158: }
159:
1.44 ray 160: rlog_file(argv[i], file);
1.9 xsa 161:
1.1 joris 162: rcs_close(file);
163: }
164:
165: return (0);
166: }
167:
1.32 xsa 168: static void
1.44 ray 169: rlog_file(const char *fname, RCSFILE *file)
1.1 joris 170: {
171: char numb[64];
1.36 ray 172: u_int nrev;
1.1 joris 173: struct rcs_sym *sym;
174: struct rcs_access *acp;
1.20 xsa 175: struct rcs_delta *rdp;
1.10 xsa 176: struct rcs_lock *lkp;
1.45 joris 177: char *workfile, *p;
1.1 joris 178:
1.36 ray 179: if (rflag == 1)
1.46 xsa 180: nrev = rcs_rev_select(file, revisions);
1.36 ray 181: else
182: nrev = file->rf_ndelta;
183:
1.45 joris 184: if ((workfile = basename(fname)) == NULL)
1.50 xsa 185: err(1, "basename");
1.45 joris 186:
187: /*
188: * In case they specified 'foo,v' as argument.
189: */
190: if ((p = strrchr(workfile, ',')) != NULL)
191: *p = '\0';
192:
1.43 ray 193: printf("\nRCS file: %s", file->rf_path);
1.45 joris 194: printf("\nWorking file: %s", workfile);
1.1 joris 195: printf("\nhead:");
196: if (file->rf_head != NULL)
197: printf(" %s", rcsnum_tostr(file->rf_head, numb, sizeof(numb)));
198:
199: printf("\nbranch:");
200: if (rcs_branch_get(file) != NULL) {
201: printf(" %s", rcsnum_tostr(rcs_branch_get(file),
202: numb, sizeof(numb)));
203: }
204:
205: printf("\nlocks: %s", (file->rf_flags & RCS_SLOCK) ? "strict" : "");
1.10 xsa 206: TAILQ_FOREACH(lkp, &(file->rf_locks), rl_list)
207: printf("\n\t%s: %s", lkp->rl_name,
208: rcsnum_tostr(lkp->rl_num, numb, sizeof(numb)));
1.1 joris 209: printf("\naccess list:\n");
210: TAILQ_FOREACH(acp, &(file->rf_access), ra_list)
211: printf("\t%s\n", acp->ra_name);
212:
213: if (Nflag == 0) {
214: printf("symbolic names:\n");
215: TAILQ_FOREACH(sym, &(file->rf_symbols), rs_list) {
216: printf("\t%s: %s\n", sym->rs_name,
217: rcsnum_tostr(sym->rs_num, numb, sizeof(numb)));
218: }
219: }
220:
221: printf("keyword substitution: %s\n",
222: file->rf_expand == NULL ? "kv" : file->rf_expand);
223:
1.20 xsa 224: printf("total revisions: %u", file->rf_ndelta);
225:
1.41 deraadt 226: if (file->rf_head != NULL && hflag == 0 && tflag == 0)
1.36 ray 227: printf(";\tselected revisions: %u", nrev);
1.20 xsa 228:
229: printf("\n");
230:
1.1 joris 231:
1.41 deraadt 232: if (hflag == 0 || tflag == 1)
1.13 xsa 233: printf("description:\n%s", file->rf_desc);
1.1 joris 234:
1.42 ray 235: if (hflag == 0 && tflag == 0 &&
236: !(lflag == 1 && TAILQ_EMPTY(&file->rf_locks))) {
1.36 ray 237: TAILQ_FOREACH(rdp, &(file->rf_delta), rd_list) {
238: /*
239: * if selections are enabled verify that entry is
1.39 niallo 240: * selected.
1.36 ray 241: */
1.41 deraadt 242: if (rflag == 0 || (rdp->rd_flags & RCS_RD_SELECT))
1.36 ray 243: rlog_rev_print(rdp);
244: }
1.20 xsa 245: }
1.1 joris 246:
247: printf("%s\n", REVEND);
1.16 xsa 248: }
249:
250: static void
1.20 xsa 251: rlog_rev_print(struct rcs_delta *rdp)
1.16 xsa 252: {
1.20 xsa 253: int i, found;
1.40 joris 254: struct tm t;
255: char *author, numb[64], *fmt, timeb[64];
1.51 joris 256: struct rcs_argvector *largv, *sargv, *wargv;
1.20 xsa 257:
258: i = found = 0;
259: author = NULL;
260:
1.23 xsa 261: /* -l[lockers] */
262: if (lflag == 1) {
1.42 ray 263: if (rdp->rd_locker != NULL)
264: found++;
1.23 xsa 265:
266: if (llist != NULL) {
267: /* if locker is empty, no need to go further. */
268: if (rdp->rd_locker == NULL)
269: return;
1.51 joris 270: largv = rcs_strsplit(llist, ",");
1.34 pat 271: for (i = 0; largv->argv[i] != NULL; i++) {
272: if (strcmp(rdp->rd_locker, largv->argv[i])
273: == 0) {
1.23 xsa 274: found++;
275: break;
276: }
277: found = 0;
278: }
1.51 joris 279: rcs_argv_destroy(largv);
1.23 xsa 280: }
281: }
1.40 joris 282:
1.20 xsa 283: /* -sstates */
284: if (slist != NULL) {
1.51 joris 285: sargv = rcs_strsplit(slist, ",");
1.34 pat 286: for (i = 0; sargv->argv[i] != NULL; i++) {
287: if (strcmp(rdp->rd_state, sargv->argv[i]) == 0) {
1.20 xsa 288: found++;
289: break;
290: }
291: found = 0;
292: }
1.51 joris 293: rcs_argv_destroy(sargv);
1.20 xsa 294: }
1.40 joris 295:
1.20 xsa 296: /* -w[logins] */
297: if (wflag == 1) {
298: if (wlist != NULL) {
1.51 joris 299: wargv = rcs_strsplit(wlist, ",");
1.34 pat 300: for (i = 0; wargv->argv[i] != NULL; i++) {
301: if (strcmp(rdp->rd_author, wargv->argv[i])
302: == 0) {
1.20 xsa 303: found++;
304: break;
305: }
306: found = 0;
307: }
1.51 joris 308: rcs_argv_destroy(wargv);
1.20 xsa 309: } else {
310: if ((author = getlogin()) == NULL)
1.50 xsa 311: err(1, "getlogin");
1.16 xsa 312:
1.20 xsa 313: if (strcmp(rdp->rd_author, author) == 0)
314: found++;
315: }
316: }
1.16 xsa 317:
1.20 xsa 318: /* XXX dirty... */
1.41 deraadt 319: if ((((slist != NULL && wflag == 1) ||
320: (slist != NULL && lflag == 1) ||
321: (lflag == 1 && wflag == 1)) && found < 2) ||
322: (((slist != NULL && lflag == 1 && wflag == 1) ||
323: (slist != NULL || lflag == 1 || wflag == 1)) && found == 0))
1.20 xsa 324: return;
325:
326: printf("%s\n", REVSEP);
327:
328: rcsnum_tostr(rdp->rd_num, numb, sizeof(numb));
329:
1.22 xsa 330: printf("revision %s", numb);
331: if (rdp->rd_locker != NULL)
332: printf("\tlocked by: %s;", rdp->rd_locker);
1.40 joris 333:
334: if (timezone_flag != NULL) {
335: rcs_set_tz(timezone_flag, rdp, &t);
1.53 xsa 336: fmt = "%Y-%m-%d %H:%M:%S%z";
1.40 joris 337: } else {
338: t = rdp->rd_date;
339: fmt = "%Y/%m/%d %H:%M:%S";
340: }
341:
342: strftime(timeb, sizeof(timeb), fmt, &t);
343:
344: printf("\ndate: %s; author: %s; state: %s;\n", timeb, rdp->rd_author,
1.41 deraadt 345: rdp->rd_state);
1.40 joris 346:
1.20 xsa 347: printf("%s", rdp->rd_log);
1.1 joris 348: }