xref: /openbsd/usr.bin/cvs/getlog.c (revision 528e2d0c)
1*528e2d0cStobias /*	$OpenBSD: getlog.c,v 1.80 2008/01/12 22:39:32 tobias Exp $	*/
26c121f58Sjfb /*
37573783fSxsa  * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org>
4e8c16debSjoris  * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
56c121f58Sjfb  *
6e8c16debSjoris  * Permission to use, copy, modify, and distribute this software for any
7e8c16debSjoris  * purpose with or without fee is hereby granted, provided that the above
8e8c16debSjoris  * copyright notice and this permission notice appear in all copies.
96c121f58Sjfb  *
10e8c16debSjoris  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11e8c16debSjoris  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12e8c16debSjoris  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13e8c16debSjoris  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14e8c16debSjoris  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15e8c16debSjoris  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16e8c16debSjoris  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176c121f58Sjfb  */
186c121f58Sjfb 
191f8531bdSotto #include <unistd.h>
201f8531bdSotto #include <string.h>
21449bca81Sniallo #include <errno.h>
226c121f58Sjfb 
236c121f58Sjfb #include "cvs.h"
249fac60a5Sjoris #include "remote.h"
256c121f58Sjfb 
267573783fSxsa #define L_HEAD		0x01
277573783fSxsa #define L_HEAD_DESCR	0x02
287573783fSxsa #define L_NAME		0x04
297573783fSxsa #define L_NOTAGS	0x08
308371e6b6Sxsa #define L_LOGINS	0x10
318371e6b6Sxsa #define L_STATES	0x20
327573783fSxsa 
33e8c16debSjoris void	cvs_log_local(struct cvs_file *);
3469d26cb1Sxsa 
358371e6b6Sxsa static void	log_rev_print(struct rcs_delta *);
368371e6b6Sxsa 
377573783fSxsa int	 runflags = 0;
38e8c16debSjoris char 	*logrev = NULL;
398371e6b6Sxsa char	*slist = NULL;
408371e6b6Sxsa char	*wlist = NULL;
416c121f58Sjfb 
42e4276007Sjfb struct cvs_cmd cvs_cmd_log = {
4362dc927bSjoris 	CVS_OP_LOG, 0, "log",
44e4276007Sjfb 	{ "lo" },
45e4276007Sjfb 	"Print out history information for files",
46e4276007Sjfb 	"[-bhlNRt] [-d dates] [-r revisions] [-s states] [-w logins]",
47a347ceb8Sxsa 	"bd:hlNRr:s:tw:",
48e4276007Sjfb 	NULL,
49e8c16debSjoris 	cvs_getlog
50e4276007Sjfb };
51e4276007Sjfb 
52449bca81Sniallo struct cvs_cmd cvs_cmd_rlog = {
53449bca81Sniallo 	CVS_OP_RLOG, 0, "rlog",
54449bca81Sniallo 	{ "rlo" },
55449bca81Sniallo 	"Print out history information for files",
56449bca81Sniallo 	"[-bhlNRt] [-d dates] [-r revisions] [-s states] [-w logins]",
57449bca81Sniallo 	"bd:hlNRr:s:tw:",
58449bca81Sniallo 	NULL,
59449bca81Sniallo 	cvs_getlog
60449bca81Sniallo };
61449bca81Sniallo 
62e8c16debSjoris int
63e8c16debSjoris cvs_getlog(int argc, char **argv)
646c121f58Sjfb {
65f2271752Stobias 	int ch, flags, i;
66e8c16debSjoris 	char *arg = ".";
67e8c16debSjoris 	struct cvs_recursion cr;
686c121f58Sjfb 
69e8c16debSjoris 	rcsnum_flags |= RCSNUM_NO_MAGIC;
70e8c16debSjoris 	flags = CR_RECURSE_DIRS;
71e8c16debSjoris 
72e8c16debSjoris 	while ((ch = getopt(argc, argv, cvs_cmd_log.cmd_opts)) != -1) {
7316cfc147Sjoris 		switch (ch) {
747573783fSxsa 		case 'h':
757573783fSxsa 			runflags |= L_HEAD;
767573783fSxsa 			break;
776c121f58Sjfb 		case 'l':
78e8c16debSjoris 			flags &= ~CR_RECURSE_DIRS;
796c121f58Sjfb 			break;
807573783fSxsa 		case 'N':
817573783fSxsa 			runflags |= L_NOTAGS;
827573783fSxsa 			break;
837573783fSxsa 		case 'R':
847573783fSxsa 			runflags |= L_NAME;
85*528e2d0cStobias 			break;
866c121f58Sjfb 		case 'r':
87e8c16debSjoris 			logrev = optarg;
8884c3cb67Sxsa 			break;
898371e6b6Sxsa 		case 's':
908371e6b6Sxsa 			runflags |= L_STATES;
918371e6b6Sxsa 			slist = optarg;
928371e6b6Sxsa 			break;
937573783fSxsa 		case 't':
947573783fSxsa 			runflags |= L_HEAD_DESCR;
957573783fSxsa 			break;
968371e6b6Sxsa 		case 'w':
978371e6b6Sxsa 			runflags |= L_LOGINS;
988371e6b6Sxsa 			wlist = optarg;
998371e6b6Sxsa 			break;
1006c121f58Sjfb 		default:
101e8c16debSjoris 			fatal("%s", cvs_cmd_log.cmd_synopsis);
1026c121f58Sjfb 		}
1036c121f58Sjfb 	}
1046c121f58Sjfb 
105e8c16debSjoris 	argc -= optind;
106e8c16debSjoris 	argv += optind;
1076c121f58Sjfb 
108f2271752Stobias 	if (cvs_cmdop == CVS_OP_RLOG) {
109f2271752Stobias 		if (argc == 0)
110f2271752Stobias 			return 0;
111f2271752Stobias 
112f2271752Stobias 		for (i = 0; i < argc; i++)
113f2271752Stobias 			if (argv[i][0] == '/')
114f2271752Stobias 				fatal("Absolute path name is invalid: %s",
115f2271752Stobias 				    argv[i]);
116f2271752Stobias 	}
117f2271752Stobias 
118e8c16debSjoris 	cr.enterdir = NULL;
119e8c16debSjoris 	cr.leavedir = NULL;
1209fac60a5Sjoris 
1219fac60a5Sjoris 	if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
12280f6ca9bSjoris 		cvs_client_connect_to_server();
1239fac60a5Sjoris 		cr.fileproc = cvs_client_sendfile;
1249fac60a5Sjoris 
1257573783fSxsa 		if (runflags & L_HEAD)
1267573783fSxsa 			cvs_client_send_request("Argument -h");
1277573783fSxsa 
1289fac60a5Sjoris 		if (!(flags & CR_RECURSE_DIRS))
1299fac60a5Sjoris 			cvs_client_send_request("Argument -l");
1309fac60a5Sjoris 
1317573783fSxsa 		if (runflags & L_NOTAGS)
1327573783fSxsa 			cvs_client_send_request("Argument -N");
1337573783fSxsa 
1347573783fSxsa 		if (runflags & L_NAME)
1357573783fSxsa 			cvs_client_send_request("Argument -R");
1367573783fSxsa 
1379fac60a5Sjoris 		if (logrev != NULL)
1389fac60a5Sjoris 			cvs_client_send_request("Argument -r%s", logrev);
1397573783fSxsa 
1408371e6b6Sxsa 		if (runflags & L_STATES)
1418371e6b6Sxsa 			cvs_client_send_request("Argument -s%s", slist);
1428371e6b6Sxsa 
1437573783fSxsa 		if (runflags & L_HEAD_DESCR)
1447573783fSxsa 			cvs_client_send_request("Argument -t");
1458371e6b6Sxsa 
1468371e6b6Sxsa 		if (runflags & L_LOGINS)
1478371e6b6Sxsa 			cvs_client_send_request("Argument -w%s", wlist);
1489fac60a5Sjoris 	} else {
149e0b2359bSxsa 		if (cvs_cmdop == CVS_OP_RLOG &&
150449bca81Sniallo 		    chdir(current_cvsroot->cr_dir) == -1)
15186fbe768Sxsa 			fatal("cvs_getlog: %s", strerror(errno));
152449bca81Sniallo 
153bc5d89feSjoris 		cr.fileproc = cvs_log_local;
1549fac60a5Sjoris 	}
1559fac60a5Sjoris 
156e8c16debSjoris 	cr.flags = flags;
15769d26cb1Sxsa 
158f2271752Stobias 	if (cvs_cmdop == CVS_OP_LOG ||
159f2271752Stobias 	    current_cvsroot->cr_method == CVS_METHOD_LOCAL) {
160e8c16debSjoris 		if (argc > 0)
161e8c16debSjoris 			cvs_file_run(argc, argv, &cr);
16225c4314aSjfb 		else
163e8c16debSjoris 			cvs_file_run(1, &arg, &cr);
164f2271752Stobias 	}
16525c4314aSjfb 
1669fac60a5Sjoris 	if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
1679fac60a5Sjoris 		cvs_client_send_files(argv, argc);
1689fac60a5Sjoris 		cvs_client_senddir(".");
169e0b2359bSxsa 
170e0b2359bSxsa 		cvs_client_send_request((cvs_cmdop == CVS_OP_RLOG) ?
171e0b2359bSxsa 		    "rlog" : "log");
172e0b2359bSxsa 
1739fac60a5Sjoris 		cvs_client_get_responses();
1749fac60a5Sjoris 	}
1759fac60a5Sjoris 
1767e393898Sjoris 	return (0);
177a96bf98bSjfb }
178df745765Sjfb 
179e8c16debSjoris void
180e8c16debSjoris cvs_log_local(struct cvs_file *cf)
1819931af54Sjfb {
182e8c16debSjoris 	u_int nrev;
1839931af54Sjfb 	struct rcs_sym *sym;
184e8c16debSjoris 	struct rcs_lock *lkp;
1859931af54Sjfb 	struct rcs_delta *rdp;
186874e0b9fSjfb 	struct rcs_access *acp;
1870a7da307Sxsa 	char numb[CVS_REV_BUFSZ];
1889931af54Sjfb 
189c76dba03Sjoris 	cvs_log(LP_TRACE, "cvs_log_local(%s)", cf->file_path);
190c76dba03Sjoris 
1915a1806edSjoris 	cvs_file_classify(cf, cvs_directory_tag);
1925bf4e3f1Sxsa 
193e8c16debSjoris 	if (cf->file_status == FILE_UNKNOWN) {
194f2271752Stobias 		if (verbosity > 0 && cvs_cmdop != CVS_OP_RLOG)
195e8c16debSjoris 			cvs_log(LP_ERR, "nothing known about %s",
196e8c16debSjoris 			    cf->file_path);
197e8c16debSjoris 		return;
198e8c16debSjoris 	} else if (cf->file_status == FILE_ADDED) {
199ef407d49Sxsa 		if (verbosity > 0)
2009a192d08Sdavid 			cvs_log(LP_ERR, "%s has been added, but not committed",
201e8c16debSjoris 			    cf->file_path);
202e8c16debSjoris 		return;
2039931af54Sjfb 	}
2049931af54Sjfb 
2053daa20b3Sjoris 	if (cf->file_type == CVS_DIR) {
2063daa20b3Sjoris 		if (verbosity > 1)
2073daa20b3Sjoris 			cvs_log(LP_NOTICE, "Logging %s", cf->file_path);
2083daa20b3Sjoris 		return;
2093daa20b3Sjoris 	}
2103daa20b3Sjoris 
2117573783fSxsa 	if (runflags & L_NAME) {
2127573783fSxsa 		cvs_printf("%s\n", cf->file_rpath);
2137573783fSxsa 		return;
2147573783fSxsa 	}
2157573783fSxsa 
2169fac60a5Sjoris 	cvs_printf("\nRCS file: %s", cf->file_rpath);
2175f291a7eSxsa 
2185f291a7eSxsa 	if (cvs_cmdop != CVS_OP_RLOG)
2199fac60a5Sjoris 		cvs_printf("\nWorking file: %s", cf->file_path);
2205f291a7eSxsa 
2219fac60a5Sjoris 	cvs_printf("\nhead:");
222e8c16debSjoris 	if (cf->file_rcs->rf_head != NULL)
2239fac60a5Sjoris 		cvs_printf(" %s", rcsnum_tostr(cf->file_rcs->rf_head,
224e8c16debSjoris 		    numb, sizeof(numb)));
225e8c16debSjoris 
2269fac60a5Sjoris 	cvs_printf("\nbranch:");
227e8c16debSjoris 	if (rcs_branch_get(cf->file_rcs) != NULL) {
2289fac60a5Sjoris 		cvs_printf(" %s", rcsnum_tostr(rcs_branch_get(cf->file_rcs),
229e8c16debSjoris 		    numb, sizeof(numb)));
230874e0b9fSjfb 	}
2319931af54Sjfb 
2329fac60a5Sjoris 	cvs_printf("\nlocks: %s", (cf->file_rcs->rf_flags & RCS_SLOCK)
233e8c16debSjoris 	    ? "strict" : "");
234e8c16debSjoris 	TAILQ_FOREACH(lkp, &(cf->file_rcs->rf_locks), rl_list)
2359fac60a5Sjoris 		cvs_printf("\n\t%s: %s", lkp->rl_name,
236e8c16debSjoris 		    rcsnum_tostr(lkp->rl_num, numb, sizeof(numb)));
2379931af54Sjfb 
2389fac60a5Sjoris 	cvs_printf("\naccess list:\n");
239e8c16debSjoris 	TAILQ_FOREACH(acp, &(cf->file_rcs->rf_access), ra_list)
2409fac60a5Sjoris 		cvs_printf("\t%s\n", acp->ra_name);
241e8c16debSjoris 
2427573783fSxsa 	if (!(runflags & L_NOTAGS)) {
2439fac60a5Sjoris 		cvs_printf("symbolic names:\n");
244e8c16debSjoris 		TAILQ_FOREACH(sym, &(cf->file_rcs->rf_symbols), rs_list) {
2459fac60a5Sjoris 			cvs_printf("\t%s: %s\n", sym->rs_name,
246e8c16debSjoris 			    rcsnum_tostr(sym->rs_num, numb, sizeof(numb)));
247874e0b9fSjfb 		}
2487573783fSxsa 	}
249874e0b9fSjfb 
2509fac60a5Sjoris 	cvs_printf("keyword substitution: %s\n",
251e8c16debSjoris 	    cf->file_rcs->rf_expand == NULL ? "kv" : cf->file_rcs->rf_expand);
2529931af54Sjfb 
2539fac60a5Sjoris 	cvs_printf("total revisions: %u", cf->file_rcs->rf_ndelta);
2549931af54Sjfb 
255e8c16debSjoris 	if (logrev != NULL)
25640440ce1Sjoris 		nrev = cvs_revision_select(cf->file_rcs, logrev);
257e8c16debSjoris 	else
258e8c16debSjoris 		nrev = cf->file_rcs->rf_ndelta;
259874e0b9fSjfb 
2607573783fSxsa 	if (cf->file_rcs->rf_head != NULL &&
2617573783fSxsa 	    !(runflags & L_HEAD) && !(runflags & L_HEAD_DESCR))
2629fac60a5Sjoris 		cvs_printf(";\tselected revisions: %u", nrev);
2637573783fSxsa 
2649fac60a5Sjoris 	cvs_printf("\n");
2657573783fSxsa 
2667573783fSxsa 	if (!(runflags & L_HEAD) || (runflags & L_HEAD_DESCR))
2679fac60a5Sjoris 		cvs_printf("description:\n%s", cf->file_rcs->rf_desc);
268874e0b9fSjfb 
2697573783fSxsa 	if (!(runflags & L_HEAD) && !(runflags & L_HEAD_DESCR)) {
270e8c16debSjoris 		TAILQ_FOREACH(rdp, &(cf->file_rcs->rf_delta), rd_list) {
2718371e6b6Sxsa 			/*
2728371e6b6Sxsa 			 * if selections are enabled verify that entry is
2738371e6b6Sxsa 			 * selected.
2748371e6b6Sxsa 			 */
2758371e6b6Sxsa 			if (logrev == NULL || (rdp->rd_flags & RCS_RD_SELECT))
2768371e6b6Sxsa 				log_rev_print(rdp);
2778371e6b6Sxsa 		}
2788371e6b6Sxsa 	}
2798371e6b6Sxsa 
2808371e6b6Sxsa 	cvs_printf("%s\n", LOG_REVEND);
2818371e6b6Sxsa }
2828371e6b6Sxsa 
2838371e6b6Sxsa static void
2848371e6b6Sxsa log_rev_print(struct rcs_delta *rdp)
2858371e6b6Sxsa {
2868371e6b6Sxsa 	int i, found;
2870a7da307Sxsa 	char numb[CVS_REV_BUFSZ], timeb[CVS_TIME_BUFSZ];
2888371e6b6Sxsa 	struct cvs_argvector *sargv, *wargv;
2898371e6b6Sxsa 
2908371e6b6Sxsa 	i = found = 0;
2918371e6b6Sxsa 
2928371e6b6Sxsa 	/* -s states */
2938371e6b6Sxsa 	if (runflags & L_STATES) {
2948371e6b6Sxsa 		sargv = cvs_strsplit(slist, ",");
2958371e6b6Sxsa 		for (i = 0; sargv->argv[i] != NULL; i++) {
2968371e6b6Sxsa 			if (strcmp(rdp->rd_state, sargv->argv[i]) == 0) {
2978371e6b6Sxsa 				found++;
2988371e6b6Sxsa 				break;
2998371e6b6Sxsa 			}
3008371e6b6Sxsa 			found = 0;
3018371e6b6Sxsa 		}
3028371e6b6Sxsa 		cvs_argv_destroy(sargv);
3038371e6b6Sxsa 	}
3048371e6b6Sxsa 
3058371e6b6Sxsa 	/* -w[logins] */
3068371e6b6Sxsa 	if (runflags & L_LOGINS) {
3078371e6b6Sxsa 		wargv = cvs_strsplit(wlist, ",");
3088371e6b6Sxsa 		for (i = 0; wargv->argv[i] != NULL; i++) {
3098371e6b6Sxsa 			if (strcmp(rdp->rd_author, wargv->argv[i]) == 0) {
3108371e6b6Sxsa 				found++;
3118371e6b6Sxsa 				break;
3128371e6b6Sxsa 			}
3138371e6b6Sxsa 			found = 0;
3148371e6b6Sxsa 		}
3158371e6b6Sxsa 		cvs_argv_destroy(wargv);
3168371e6b6Sxsa 	}
3178371e6b6Sxsa 
318a347ceb8Sxsa 	if ((runflags & (L_STATES|L_LOGINS)) && found == 0)
3198371e6b6Sxsa 		return;
3203fe70097Sxsa 
3219fac60a5Sjoris 	cvs_printf("%s\n", LOG_REVSEP);
322daf00afbSxsa 
32340440ce1Sjoris 	rcsnum_tostr(rdp->rd_num, numb, sizeof(numb));
3249fac60a5Sjoris 	cvs_printf("revision %s", numb);
325daf00afbSxsa 
3268371e6b6Sxsa 	strftime(timeb, sizeof(timeb), "%Y/%m/%d %H:%M:%S", &rdp->rd_date);
3277573783fSxsa 	cvs_printf("\ndate: %s;  author: %s;  state: %s;\n",
3287573783fSxsa 	    timeb, rdp->rd_author, rdp->rd_state);
3299fac60a5Sjoris 	cvs_printf("%s", rdp->rd_log);
330874e0b9fSjfb }
331