xref: /openbsd-src/usr.bin/cvs/status.c (revision daf88648c0e349d5c02e1504293082072c981640)
1 /*	$OpenBSD: status.c,v 1.70 2007/01/12 19:28:12 joris Exp $	*/
2 /*
3  * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
4  * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include "includes.h"
20 
21 #include "cvs.h"
22 #include "log.h"
23 #include "remote.h"
24 
25 void	cvs_status_local(struct cvs_file *);
26 
27 static int show_sym = 0;
28 
29 struct cvs_cmd cvs_cmd_status = {
30 	CVS_OP_STATUS, 0, "status",
31 	{ "st", "stat" },
32 	"Display status information on checked out files",
33 	"[-lRv]",
34 	"lRv",
35 	NULL,
36 	cvs_status
37 };
38 
39 #define CVS_STATUS_SEP	\
40 	"==================================================================="
41 
42 const char *status_tab[] = {
43 	"Unknown",
44 	"Locally Added",
45 	"Locally Removed",
46 	"Locally Modified",
47 	"Up-to-date",
48 	"Needs Checkout",
49 	"Needs Checkout",
50 	"Needs Merge",
51 	"Needs Patch",
52 	"Entry Invalid",
53 	"Unresolved Conflict",
54 	"Classifying error",
55 };
56 
57 int
58 cvs_status(int argc, char **argv)
59 {
60 	int ch, flags;
61 	char *arg = ".";
62 	struct cvs_recursion cr;
63 
64 	flags = CR_RECURSE_DIRS;
65 
66 	while ((ch = getopt(argc, argv, cvs_cmd_status.cmd_opts)) != -1) {
67 		switch (ch) {
68 		case 'l':
69 			flags &= ~CR_RECURSE_DIRS;
70 			break;
71 		case 'R':
72 			break;
73 		case 'v':
74 			show_sym = 1;
75 			break;
76 		default:
77 			fatal("%s", cvs_cmd_status.cmd_synopsis);
78 		}
79 	}
80 
81 	argc -= optind;
82 	argv += optind;
83 
84 	cr.enterdir = NULL;
85 	cr.leavedir = NULL;
86 
87 	if (current_cvsroot->cr_method == CVS_METHOD_LOCAL) {
88 		flags |= CR_REPO;
89 		cr.fileproc = cvs_status_local;
90 	} else {
91 		cvs_client_connect_to_server();
92 		if (!(flags & CR_RECURSE_DIRS))
93 			cvs_client_send_request("Argument -l");
94 		if (show_sym)
95 			cvs_client_send_request("Argument -v");
96 		cr.fileproc = cvs_client_sendfile;
97 	}
98 
99 	cr.flags = flags;
100 
101 	if (argc > 0)
102 		cvs_file_run(argc, argv, &cr);
103 	else
104 		cvs_file_run(1, &arg, &cr);
105 
106 	if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
107 		cvs_client_send_files(argv, argc);
108 		cvs_client_senddir(".");
109 		cvs_client_send_request("status");
110 		cvs_client_get_responses();
111 	}
112 
113 	return (0);
114 }
115 
116 void
117 cvs_status_local(struct cvs_file *cf)
118 {
119 	int l;
120 	size_t len;
121 	RCSNUM *head;
122 	const char *status;
123 	char buf[128], timebuf[32], revbuf[32];
124 	struct rcs_sym *sym;
125 
126 	cvs_log(LP_TRACE, "cvs_status_local(%s)", cf->file_path);
127 
128 	cvs_file_classify(cf, NULL, 1);
129 
130 	if (cf->file_type == CVS_DIR) {
131 		if (verbosity > 1)
132 			cvs_log(LP_NOTICE, "Examining %s", cf->file_path);
133 		return;
134 	}
135 
136 	cvs_printf("%s\n", CVS_STATUS_SEP);
137 
138 	status = status_tab[cf->file_status];
139 	if (cf->file_status == FILE_MODIFIED &&
140 	    cf->file_ent->ce_conflict != NULL)
141 		status = "File had conflicts on merge";
142 
143 	if (cf->file_status == FILE_LOST ||
144 	    cf->file_status == FILE_UNKNOWN ||
145 	    (cf->file_rcs != NULL && cf->file_rcs->rf_inattic == 1)) {
146 		l = snprintf(buf, sizeof(buf), "no file %s\t", cf->file_name);
147 		if (l == -1 || l >= (int)sizeof(buf))
148 			fatal("cvs_status_local: overflow");
149 	} else
150 		if (strlcpy(buf, cf->file_name, sizeof(buf)) >= sizeof(buf))
151 			fatal("cvs_status_local: overflow");
152 
153 	cvs_printf("File: %-17s\tStatus: %s\n\n", buf, status);
154 
155 	if (cf->file_ent == NULL) {
156 		l = snprintf(buf, sizeof(buf),
157 		    "No entry for %s", cf->file_name);
158 		if (l == -1 || l >= (int)sizeof(buf))
159 			fatal("cvs_status_local: overflow");
160 	} else if (cf->file_status == FILE_ADDED) {
161 		len = strlcpy(buf, "New file!", sizeof(buf));
162 		if (len >= sizeof(buf))
163 			fatal("cvs_status_local: truncation");
164 	} else {
165 		rcsnum_tostr(cf->file_ent->ce_rev, revbuf, sizeof(revbuf));
166 
167 		if (cf->file_ent->ce_conflict == NULL) {
168 			ctime_r(&(cf->file_ent->ce_mtime), timebuf);
169 			if (timebuf[strlen(timebuf) - 1] == '\n')
170 				timebuf[strlen(timebuf) - 1] = '\0';
171 		} else {
172 			len = strlcpy(timebuf, cf->file_ent->ce_conflict,
173 			    sizeof(timebuf));
174 			if (len >= sizeof(timebuf))
175 				fatal("cvs_status_local: truncation");
176 		}
177 
178 		l = snprintf(buf, sizeof(buf), "%s\t%s", revbuf, timebuf);
179 		if (l == -1 || l >= (int)sizeof(buf))
180 			fatal("cvs_status_local: overflow");
181 	}
182 
183 	cvs_printf("   Working revision:\t%s\n", buf);
184 
185 	buf[0] = '\0';
186 	if (cf->file_rcs == NULL) {
187 		len = strlcat(buf, "No revision control file", sizeof(buf));
188 		if (len >= sizeof(buf))
189 			fatal("cvs_status_local: truncation");
190 	} else {
191 		head = rcs_head_get(cf->file_rcs);
192 		rcsnum_tostr(head, revbuf, sizeof(revbuf));
193 		rcsnum_free(head);
194 		l = snprintf(buf, sizeof(buf), "%s\t%s", revbuf,
195 		    cf->file_rpath);
196 		if (l == -1 || l >= (int)sizeof(buf))
197 			fatal("cvs_status_local: overflow");
198 	}
199 
200 	cvs_printf("   Repository revision:\t%s\n", buf);
201 
202 	if (cf->file_ent != NULL) {
203 		if (cf->file_ent->ce_tag != NULL)
204 			cvs_printf("   Sticky Tag:\t\t%s\n",
205 			    cf->file_ent->ce_tag);
206 		else if (verbosity > 0)
207 			cvs_printf("   Sticky Tag:\t\t(none)\n");
208 
209 		if (cf->file_ent->ce_opts != NULL)
210 			cvs_printf("   Sticky Options:\t%s\n",
211 			    cf->file_ent->ce_opts);
212 		else if (verbosity > 0)
213 			cvs_printf("   Sticky Options:\t(none)\n");
214 	}
215 
216 	if (show_sym == 1) {
217 		cvs_printf("\n");
218 		cvs_printf("   Existing Tags:\n");
219 
220 		if (!TAILQ_EMPTY(&(cf->file_rcs->rf_symbols))) {
221 			TAILQ_FOREACH(sym,
222 			    &(cf->file_rcs->rf_symbols), rs_list) {
223 				(void)rcsnum_tostr(sym->rs_num, revbuf,
224 				    sizeof(revbuf));
225 
226 				cvs_printf("\t%-25s\t(%s: %s)\n", sym->rs_name,
227 				    RCSNUM_ISBRANCH(sym->rs_num) ? "branch" :
228 				    "revision", revbuf);
229 			 }
230 		} else
231 			cvs_printf("\tNo Tags Exist\n");
232 	}
233 
234 	cvs_printf("\n");
235 }
236