xref: /illumos-gate/usr/src/cmd/genmsg/main.c (revision 381a2a9a387f449fab7d0c7e97c4184c26963abf)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  *	Copyright (c) 1995 by Sun Microsystems, Inc.
24  *	All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <limits.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <libgen.h>
34 #include <libintl.h>
35 #include <locale.h>
36 #include <unistd.h>
37 #include <sys/param.h>
38 
39 #include "genmsg.h"
40 
41 #define	MSG_SUFFIX	".msg"
42 #define	NEW_SUFFIX	".new"
43 
44 #if !defined(TEXT_DOMAIN)
45 #define	TEXT_DOMAIN	"genmsg"
46 #endif
47 
48 /*
49  * External functions.
50  */
51 extern void write_msgfile(char *);	/* from util.c */
52 extern int read_projfile(char *);	/* from util.c */
53 extern void write_projfile(char *);	/* from util.c */
54 extern void read_msgfile(char *);	/* from util.c */
55 extern int is_writable(char *);		/* from util.c */
56 extern int file_copy(char *, char *);	/* from util.c */
57 extern void init_lex(void);		/* from genmsg.l */
58 extern void init_linemsgid(void);	/* from genmsg.l */
59 
60 /* Program name. */
61 char *program;
62 
63 /* File pointer for auto-message-numbering. */
64 FILE *newfp = NULL;
65 
66 /* Input source file. */
67 char *srcfile;
68 
69 /* Tag for message comments. */
70 char *mctag = NULL;
71 
72 /* Tag for set number comments. */
73 char *sctag = NULL;
74 
75 /* Mode mask to define the genmsg tasks. */
76 Mode active_mode = NoMode;
77 
78 /*
79  * This flag will be TRUE if a catgets() call is found
80  * in the input file.
81  */
82 int is_cat_found = FALSE;
83 
84 /* Suppress an error message if this flag is TRUE. */
85 int suppress_error = FALSE;
86 
87 /* Prefix and suffix of messages for testing. */
88 char *premsg = NULL;
89 char *sufmsg = NULL;
90 
91 static void usage(void);
92 static void validate_options(void);
93 
94 int
95 main(int argc, char **argv)
96 {
97 	int c;
98 	extern char *optarg;	/* from getopt */
99 	extern int optind;	/* from getopt */
100 	extern FILE *yyin;	/* from lex */
101 	extern int yyparse(void);
102 	char *msgfile = NULL;
103 	char *projfile = NULL;
104 	char *newprojfile = NULL;
105 	char *cpppath = NULL;
106 	int do_msgfile = FALSE;
107 	int tmpfd = -1;
108 
109 	program = basename(argv[0]);
110 
111 	(void) setlocale(LC_ALL, "");
112 	(void) textdomain(TEXT_DOMAIN);
113 
114 	while ((c = getopt(argc, argv, "arndfg:o:l:p:c:s:m:M:txvb")) != EOF) {
115 		switch (c) {
116 		case 'o':
117 			SetActiveMode(MessageMode);
118 			msgfile = optarg;
119 			break;
120 		case 'a':
121 			SetActiveMode(AppendMode);
122 			break;
123 		case 'l':
124 			projfile = optarg;
125 			SetActiveMode(AutoNumMode);
126 			break;
127 		case 'r':
128 			SetActiveMode(ReverseMode);
129 			break;
130 		case 'p':
131 			cpppath = optarg;
132 			SetActiveMode(PreProcessMode);
133 			break;
134 		case 'g':
135 			newprojfile = optarg;
136 			suppress_error = TRUE;
137 			SetActiveMode(ProjectMode);
138 			break;
139 		case 'c':
140 			mctag = optarg;
141 			SetActiveMode(MsgCommentMode);
142 			break;
143 		case 's':
144 			sctag = optarg;
145 			SetActiveMode(SetCommentMode);
146 			break;
147 		case 'b':
148 			SetActiveMode(BackCommentMode);
149 			break;
150 		case 'n':
151 			SetActiveMode(LineInfoMode);
152 			break;
153 		case 'm':
154 			premsg = optarg;
155 			SetActiveMode(PrefixMode);
156 			break;
157 		case 'M':
158 			sufmsg = optarg;
159 			SetActiveMode(SuffixMode);
160 			break;
161 		case 't':
162 			SetActiveMode(TripleMode);
163 			break;
164 		case 'd':
165 			SetActiveMode(DoubleLineMode);
166 			break;
167 		case 'f':
168 			SetActiveMode(OverwriteMode);
169 			break;
170 		case 'x':
171 			suppress_error = TRUE;
172 			SetActiveMode(NoErrorMode);
173 			break;
174 		case 'v':
175 			(void) printf("genmsg version %s\n", "%I%");
176 			exit(EXIT_SUCCESS);
177 			break;
178 		default:
179 			usage();
180 			break;
181 		}
182 	}
183 
184 	if (optind >= argc) {
185 		usage();
186 	}
187 
188 	validate_options();
189 
190 	if (IsActiveMode(AutoNumMode)) {
191 		int len;
192 		char *tmp;
193 		if (read_projfile(projfile)) {
194 			tmp = basename(projfile);
195 			len = strlen(tmp);
196 			if ((newprojfile = malloc(len + sizeof (NEW_SUFFIX)))
197 				== NULL) {
198 				prg_err(gettext("fatal: out of memory"));
199 				exit(EXIT_FAILURE);
200 			}
201 			(void) sprintf(newprojfile, "%s%s", tmp, NEW_SUFFIX);
202 		} else {
203 			newprojfile = basename(projfile);
204 		}
205 	}
206 
207 	if ((IsActiveMode(AutoNumMode) || IsActiveMode(ProjectMode)) &&
208 		(is_writable(IsActiveMode(OverwriteMode) ?
209 				projfile : newprojfile) == FALSE)) {
210 		prg_err(gettext("cannot write \"%s\": permission denied"),
211 			IsActiveMode(OverwriteMode) ? projfile : newprojfile);
212 		exit(EXIT_FAILURE);
213 	}
214 
215 	if (IsActiveMode(AppendMode) && msgfile) {
216 		read_msgfile(msgfile);
217 	}
218 
219 	if (!msgfile) {
220 		char *tmp = basename(argv[optind]);
221 		int len = strlen(tmp);
222 		if ((msgfile = malloc(len + sizeof (MSG_SUFFIX)))
223 			== NULL) {
224 			prg_err(gettext("fatal: out of memory"));
225 			exit(EXIT_FAILURE);
226 		}
227 		(void) sprintf(msgfile, "%s%s", tmp, MSG_SUFFIX);
228 	}
229 
230 	while (optind < argc) {
231 		is_cat_found = FALSE;
232 		srcfile = argv[optind];
233 
234 		if (IsActiveMode(AutoNumMode) || IsActiveMode(ReverseMode)) {
235 			init_linemsgid();
236 		}
237 
238 		if (IsActiveMode(PreProcessMode)) {
239 			char cmd[MAXPATHLEN];
240 			(void) sprintf(cmd, "%s %s", cpppath, srcfile);
241 			if ((yyin = (FILE *) popen(cmd, "r")) == NULL) {
242 				prg_err(
243 				gettext("fatal: cannot execute \"%s\""),
244 				cpppath);
245 				exit(EXIT_FAILURE);
246 			}
247 		} else {
248 			if ((yyin = fopen(srcfile, "r")) == NULL) {
249 				prg_err(/* stupid cstyle */
250 				gettext("cannot open \"%s\""), srcfile);
251 				goto end;
252 			}
253 		}
254 
255 		init_lex();
256 		yyparse();
257 
258 		if (IsActiveMode(PreProcessMode)) {
259 			if (pclose(yyin) != 0) {
260 				prg_err(gettext("\"%s\" failed for \"%s\""),
261 					cpppath, srcfile);
262 				goto end;
263 			}
264 		}
265 
266 		if (is_cat_found == FALSE) {
267 			if (!IsActiveMode(PreProcessMode)) {
268 				(void) fclose(yyin);
269 			}
270 			goto end;
271 		}
272 
273 		if (!do_msgfile) {
274 			do_msgfile = TRUE;
275 		}
276 
277 		if (IsActiveMode(AutoNumMode) || IsActiveMode(ReverseMode)) {
278 			char *tmp = basename(srcfile);
279 			char newfile[MAXPATHLEN];
280 			char tmpfile[32];
281 
282 			if (IsActiveMode(OverwriteMode)) {
283 				(void) sprintf(newfile, "%s", srcfile);
284 			} else {
285 				(void) sprintf(newfile, "%s%s",
286 						tmp, NEW_SUFFIX);
287 			}
288 
289 			if (is_writable(newfile) == FALSE) {
290 				prg_err(
291 			gettext("cannot create \"%s\": permission denied"),
292 					newfile);
293 				goto end;
294 			}
295 
296 			(void) sprintf(tmpfile, "%s", "/tmp/gensmg.XXXXXX");
297 			if ((tmpfd = mkstemp(tmpfile)) == -1) {
298 				prg_err(/* stupid cstyle */
299 				gettext("cannot create \"%s\""), tmpfile);
300 				if (!IsActiveMode(PreProcessMode)) {
301 					(void) fclose(yyin);
302 				}
303 					goto end;
304 			}
305 			(void) close(tmpfd);
306 			if ((newfp = fopen(tmpfile, "w")) == NULL) {
307 				prg_err(/* stupid cstyle */
308 				gettext("cannot create \"%s\""), tmpfile);
309 				if (!IsActiveMode(PreProcessMode)) {
310 					(void) fclose(yyin);
311 				}
312 				(void) unlink(tmpfile);
313 				goto end;
314 			}
315 
316 			if (IsActiveMode(PreProcessMode)) {
317 				if ((yyin = fopen(srcfile, "r")) == NULL) {
318 					prg_err(/* stupid cstyle */
319 				gettext("cannot open \"%s\""), srcfile);
320 					(void) unlink(tmpfile);
321 					goto end;
322 				}
323 			} else {
324 				rewind(yyin);
325 			}
326 
327 			SetActiveMode(ReplaceMode);
328 			init_lex();
329 			yyparse();
330 			ResetActiveMode(ReplaceMode);
331 
332 			(void) fclose(newfp);
333 			newfp = NULL;
334 
335 			(void) fclose(yyin);
336 
337 			(void) file_copy(tmpfile, newfile);
338 
339 			(void) unlink(tmpfile);
340 
341 			goto end;
342 		}
343 
344 		if (!IsActiveMode(PreProcessMode)) {
345 			(void) fclose(yyin);
346 		}
347 
348 end:
349 		optind++;
350 	}
351 
352 	if (!do_msgfile) { /* no more business. */
353 		return (EXIT_SUCCESS);
354 	}
355 
356 	if (!IsActiveMode(ReverseMode) && !IsActiveMode(ProjectMode)) {
357 		write_msgfile(msgfile);
358 	}
359 
360 	if (IsActiveMode(AutoNumMode) || IsActiveMode(ProjectMode)) {
361 		write_projfile(IsActiveMode(OverwriteMode) ?
362 				projfile : newprojfile);
363 	}
364 	return (EXIT_SUCCESS);
365 }
366 
367 static void
368 validate_options(void)
369 {
370 	/* -r doesn't work with either -a or -l. */
371 	if (IsActiveMode(ReverseMode) &&
372 		(IsActiveMode(AutoNumMode) || IsActiveMode(AppendMode))) {
373 		usage();
374 	}
375 	/* -b should be accompanied with -c, -s, -d, and -n. */
376 	if (IsActiveMode(BackCommentMode) &&
377 		(!IsActiveMode(MsgCommentMode) &&
378 		!IsActiveMode(SetCommentMode) &&
379 		!IsActiveMode(DoubleLineMode) &&
380 		!IsActiveMode(LineInfoMode))) {
381 		usage();
382 	}
383 	if (IsActiveMode(ProjectMode) &&
384 		(IsActiveMode(AutoNumMode) || IsActiveMode(ReverseMode) ||
385 		IsActiveMode(AppendMode) || IsActiveMode(MsgCommentMode) ||
386 		IsActiveMode(LineInfoMode) || IsActiveMode(OverwriteMode) ||
387 		IsActiveMode(PrefixMode) || IsActiveMode(SuffixMode) ||
388 		IsActiveMode(TripleMode) || IsActiveMode(DoubleLineMode) ||
389 		IsActiveMode(MessageMode) || IsActiveMode(NoErrorMode))) {
390 		usage();
391 	}
392 }
393 
394 static void
395 usage(void)
396 {
397 	(void) fprintf(stderr,
398 	gettext("Usage: %s [-o message-file] [-a] [-d] [-p preprocessor]\n"
399 		"          [-s set-tag] [-c message-tag] [-b] [-n]\n"
400 		"          [-l project-file] [-r] [-f] [-g project-file]\n"
401 		"          [-m prefix] [-M suffix] [-t] [-x] files ...\n"),
402 		program);
403 	exit(EXIT_FAILURE);
404 }
405