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