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