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