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
main(int argc,char * argv[])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
extract(name)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
yankstr()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
prstr(cp,lineno,posno)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
usage()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
getachar()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
replace(name)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
badformat(line)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