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