xref: /illumos-gate/usr/src/cmd/exstr/exstr.c (revision 24da5b34f49324ed742a340010ed5bd3d4e06625)
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 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <sys/types.h>
36 #include <signal.h>
37 #include <setjmp.h>
38 #include <string.h>
39 
40 /* external functions */
41 
42 extern	int	getopt();
43 extern	void	exit();
44 extern	int	atoi();
45 extern	int	_filbuf();
46 extern	char	*optarg;
47 extern	int	optind, opterr;
48 
49 /* static functions */
50 
51 static	void	extract();
52 static	void	replace();
53 static	void	yankstr();
54 static	void	badformat();
55 static	void	prstr();
56 static	int	getachar();
57 static  void	usage();
58 
59 /* static variables */
60 
61 static	int	eflg;		/* find strings in source file(s) */
62 static	int	dflg;		/* use replaced string a second argument */
63 static  int	rflg;		/* replace strings by function calls */
64 static  int	errflg;		/* syntax error on command line */
65 static  char	*Fname;		/* name of source file */
66 static  int	Lineno;		/* line number in source file */
67 static	int	Posno;		/* character position within line */
68 static  int	flag;		/* sets when newline is encountered */
69 static  jmp_buf	to_eof;
70 
71 
72 int
73 main(int argc, char *argv[])
74 {
75 	int	ch;
76 
77 	while ((ch = getopt(argc, argv, "erd")) != -1)
78 		switch (ch) {
79 		    case 'e':
80 			if (rflg)
81 				errflg++;
82 			else
83 				eflg++;
84 			continue;
85 		    case 'r':
86 			if (eflg)
87 				errflg++;
88 			else
89 				rflg++;
90 			continue;
91 		    case 'd':
92 			if (eflg)
93 				errflg++;
94 			else
95 				dflg++;
96 			continue;
97 		    default:
98 			errflg++;
99 		}
100 	if (optind ==  argc || errflg)
101 		usage();
102 	if (!rflg)
103 		for (; optind < argc; optind++)
104 			extract(argv[optind]);
105 	else  {
106 		if (optind+1 != argc)
107 			usage();
108 		replace(argv[optind]);
109 	}
110 	return (0);
111 }
112 
113 static	void
114 extract(name)
115 char	*name;
116 {
117 	if (freopen(name, "r", stdin) == NULL) {
118 		(void) fprintf(
119 		    stderr, "exstr: ERROR: couldn't open file '%s'\n", name);
120 		exit(1);
121 	}
122 	Fname = name;
123 	flag = 1;
124 	Lineno = 0;
125 
126 	if (setjmp(to_eof) != 0)
127 		return;
128 
129 	for (;;) {
130 		char ch;
131 
132 		ch = getachar();
133 
134 		switch (ch) {
135 		case '#':
136 			if (Posno != 0)
137 				continue;
138 			do {
139 				ch = getachar();
140 			} while (isspace(ch));
141 			if (ch == 'd')
142 				continue;
143 			while (getachar() != '\n');
144 			break;
145 		case '"':
146 			yankstr();
147 			break;
148 		case '\'':
149 			while ((ch = getachar()) != '\'')
150 				if (ch == '\\')
151 					ch = getachar();
152 			break;
153 
154 		case '/':
155 			ch = getachar();
156 			if (ch == '*') {
157 				int level = 0;
158 				while (level != 2) {
159 					ch = getachar();
160 					if (level == 0 && ch == '*')
161 						level++;
162 					else if (level == 1 && ch == '/')
163 						level++;
164 					else
165 						level = 0;
166 				}
167 			}
168 			break;
169 		}
170 	}
171 }
172 
173 static	void
174 yankstr()
175 {
176 	char cc;
177 	char dbuf[BUFSIZ];
178 	register char *dp = dbuf;
179 	int saved_posno;
180 	int saved_lineno;
181 
182 	saved_posno = Posno;
183 	saved_lineno = Lineno;
184 	while ((cc = getachar()) != '"') {
185 		if (cc == '\\') {
186 			*dp++ = cc;
187 			cc = getachar();
188 		}
189 		if (cc == '\n') {
190 			dp--;
191 			continue;
192 		}
193 		*dp++ = cc;
194 	}
195 	*dp = 0;
196 	prstr(dbuf, saved_lineno, saved_posno);
197 }
198 
199 static	void
200 prstr(cp, lineno, posno)
201 register char *cp;
202 {
203 	if (eflg)
204 		(void) fprintf(stdout, "%s:%d:%d:::%s\n", Fname, lineno, posno,
205 		    cp);
206 	else
207 		(void) fprintf(stdout, "%s:%s\n", Fname, cp);
208 
209 }
210 
211 static	void
212 usage()
213 {
214 	(void) fprintf(stderr, "usage: exstr [-e] files\n");
215 	(void) fprintf(stderr, "or   : exstr -r [-d] file\n");
216 	exit(1);
217 }
218 
219 static	int
220 getachar()
221 {
222 	int cc;
223 
224 	cc = getchar();
225 	if (flag) {
226 		Lineno++;
227 		Posno = 0;
228 		flag = 0;
229 	} else
230 		Posno++;
231 	if (cc == EOF)
232 		longjmp(to_eof, 1);
233 	if (cc == '\n')
234 		flag = 1;
235 	return (cc);
236 }
237 
238 
239 static void
240 replace(name)
241 char	*name;
242 {
243 	char	linebuf[BUFSIZ];
244 	char	*cp;
245 	int	curlineno;		/* line number in strings file */
246 	int	curposno;		/* character position in string file */
247 	int	savelineno = 0;
248 	int	curmsgno;		/* message number in strings file */
249 	int	wrong_msg;		/* invalid message number */
250 	int	cont_str = 0;		/* string continues in the next line */
251 	char	*repstr;
252 	char	repbuf[BUFSIZ], *repbufp;
253 	char	curline[BUFSIZ];
254 	char	outbuf[BUFSIZ];
255 	/* keeps track of character position within input file */
256 	char	*inp;
257 	/* keeps track of character position within output buffer */
258 	char	*outp;
259 	char	*msgfile;
260 	FILE	*fi;			/* input source file pointer */
261 
262 	inp = linebuf;
263 	outp = outbuf;
264 	linebuf[0] = '\0';
265 	/* open input C source file */
266 	if ((fi = fopen(name, "r")) == (FILE *)NULL) {
267 		(void) fprintf(stderr,
268 		    "exstr: ERROR: couldn't open file '%s'\n", name);
269 		exit(1);
270 	}
271 	Fname = name;
272 
273 	(void) fprintf(stdout, "extern char *gettxt();\n");
274 
275 	/* process file containing the list of strings */
276 	while (fgets(repbuf, sizeof (repbuf), stdin) != (char *)NULL) {
277 
278 		wrong_msg = 0;
279 
280 		/* save a copy of the current line */
281 		(void) strcpy(curline, repbuf);
282 
283 		/* take apart the input string */
284 		repbufp = strchr(repbuf, ':');
285 		if (repbufp == (char *)NULL)
286 			badformat(curline);
287 		*repbufp++ = '\0';
288 		/* verify that string belongs to the input C source file */
289 		if (strcmp(repbuf, name) != NULL)
290 			continue;
291 		repstr = strchr(repbufp, ':');
292 		if (repstr == (char *)NULL)
293 			badformat(curline);
294 		*repstr++ = '\0';
295 		curlineno = atoi(repbufp);
296 		if (curlineno < savelineno) {
297 			(void) fprintf(stderr,
298 			    "exstr: ERROR: stdin: line out of order\n");
299 			(void) fprintf(stderr, "%s", curline);
300 			exit(1);
301 		}
302 		savelineno = curlineno;
303 		repbufp = repstr;
304 		repstr = strchr(repbufp, ':');
305 		if (repstr == (char *)NULL)
306 			badformat(curline);
307 		repstr[strlen(repstr) - 1 ] = '\0';
308 		*repstr++ = '\0';
309 		curposno = atoi(repbufp);
310 		repbufp = repstr;
311 		repstr = strchr(repbufp, ':');
312 		if (repstr == (char *)NULL)
313 			badformat(curline);
314 		*repstr++ = '\0';
315 		msgfile = repbufp;
316 		if (strlen(msgfile) > (size_t)14 || *msgfile == '\0') {
317 			(void) fprintf(stderr,
318 			    "exstr: ERROR: stdin: invalid message file name "
319 			    "'%s'\n", msgfile);
320 			(void) fprintf(stderr, "%s", curline);
321 			exit(1);
322 		}
323 		repbufp = repstr;
324 		repstr = strchr(repbufp, ':');
325 		if (repstr == (char *)NULL)
326 			badformat(curline);
327 		*repstr++ = '\0';
328 		cp = repbufp;
329 		while (*cp)
330 			if (!isdigit(*cp++)) {
331 				wrong_msg++;
332 				break;
333 			}
334 		if (*repbufp == '\0' || wrong_msg) {
335 			(void) fprintf(stderr, "exstr: ERROR: stdin: invalid "
336 			    "message number '%s'\n", repbufp);
337 			(void) fprintf(stderr, "%s", curline);
338 			exit(1);
339 		}
340 		curmsgno = atoi(repbufp);
341 
342 		/* move up to this line */
343 		while (Lineno != curlineno) {
344 			if (outp != outbuf) {
345 				while (*inp != '\0')
346 					*outp++ = *inp++;
347 				*outp = '\0';
348 				(void) fputs(outbuf, stdout);
349 			} else if (*linebuf != '\0')
350 				(void) fputs(linebuf, stdout);
351 			outp = outbuf;
352 			inp = linebuf;
353 			if (fgets(linebuf,
354 			    sizeof (linebuf), fi) == (char *)NULL) {
355 				(void) fprintf(stderr, "read error\n");
356 				exit(1);
357 			}
358 			Lineno++;
359 			Posno = 0;
360 		}
361 		if (Posno > curposno) {
362 			(void) fprintf(stderr,
363 			    "Bad input record line number %d\n", Lineno);
364 			exit(1);
365 		}
366 		while (Posno != curposno) {
367 			*outp++ = *inp++;
368 			Posno++;
369 		}
370 		if (*inp != '"') {
371 			(void) fprintf(stderr, "exstr: ERROR: cannot replace "
372 			    "string '%s' in line (%d) of file (%s)\n", repstr,
373 			    Lineno, Fname);
374 			exit(1);
375 		}
376 		/* check if string continues in next line */
377 		while (inp[strlen(inp)-2] == '\\' &&
378 		    inp[strlen(inp)-1] == '\n') {
379 			if (fgets(linebuf,
380 			    sizeof (linebuf), fi) == (char *)NULL) {
381 				(void) fprintf(stderr, "exstr: ERROR: read "
382 				    "error in file (%s)\n", Fname);
383 				exit(1);
384 			}
385 			cont_str++;
386 			Lineno++;
387 		}
388 		if (cont_str) {
389 			cp = linebuf;
390 			while (*cp != '\0' && *cp++ != '"')
391 				;
392 			if (*cp == '\0') {
393 				(void) fprintf(stderr, "exstr: ERROR: cannot "
394 				    "replace string '%s' in line (%d) of file "
395 				    "(%s)\n", repstr, Lineno, Fname);
396 				exit(1);
397 			}
398 			inp = cp;
399 			Posno = cp - linebuf;
400 		}
401 		if (dflg)
402 			outp += snprintf(outp, BUFSIZ - (outp - outbuf),
403 			    "gettxt(\"%s:%d\", \"%s\")", msgfile, curmsgno,
404 			    repstr);
405 		else
406 			outp += snprintf(outp, BUFSIZ - (outp - outbuf),
407 			    "gettxt(\"%s:%d\", \"\")", msgfile, curmsgno);
408 		if (!cont_str) {
409 			inp += strlen(repstr)+2;
410 			Posno += strlen(repstr)+2;
411 		}
412 		else
413 			cont_str = 0;
414 	}
415 	if (outp != outbuf) {
416 		while (*inp != '\0')
417 			*outp++ = *inp++;
418 		*outp = '\0';
419 		(void) fputs(outbuf, stdout);
420 	}
421 	while (fgets(linebuf, sizeof (linebuf), fi) != (char *)NULL)
422 		(void) fputs(linebuf, stdout);
423 
424 	(void) fclose(fi);
425 }
426 
427 static	void
428 badformat(line)
429 char  	*line;
430 {
431 	(void) fprintf(stderr, "exstr: ERROR: stdin: Badly formatted "
432 	    "replacement string\n%s", line);
433 	exit(1);
434 }
435