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