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 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* 29 * mkstr - create a string error message file by massaging C source 30 * 31 * Bill Joy UCB August 1977 32 * 33 * Modified March 1978 to hash old messages to be able to recompile 34 * without addding messages to the message file (usually) 35 * 36 * Based on an earlier program conceived by Bill Joy and Chuck Haley 37 * 38 * Program to create a string error message file 39 * from a group of C programs. Arguments are the name 40 * of the file where the strings are to be placed, the 41 * prefix of the new files where the processed source text 42 * is to be placed, and the files to be processed. 43 * 44 * The program looks for 'error("' in the source stream. 45 * Whenever it finds this, the following characters from the '"' 46 * to a '"' are replaced by 'seekpt' where seekpt is a 47 * pointer into the error message file. 48 * If the '(' is not immediately followed by a '"' no change occurs. 49 * 50 * The optional '-' causes strings to be added at the end of the 51 * existing error message file for recompilation of single routines. 52 */ 53 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <locale.h> 58 #include <sys/param.h> 59 60 #define ungetchar(c) ungetc(c, stdin) 61 62 #define NBUCKETS 511 63 64 static char usagestr[] = "usage: %s [ - ] mesgfile prefix file ...\n"; 65 66 static FILE *mesgread, *mesgwrite; 67 68 static void process(void); 69 static int match(char *ocp); 70 static void copystr(void); 71 static int octdigit(char c); 72 static void inithash(void); 73 static int hashit(char *str, char really, unsigned int fakept); 74 static int fgetNUL(char *obuf, int rmdr, FILE *file); 75 76 int 77 main(int argc, char *argv[]) 78 { 79 char addon = 0; 80 char *progname, *np, name[MAXPATHLEN]; 81 size_t size = 0; 82 size_t len; 83 84 (void) setlocale(LC_ALL, ""); 85 86 #if !defined(TEXT_DOMAIN) 87 #define TEXT_DOMAIN "SYS_TEST" 88 #endif 89 (void) textdomain(TEXT_DOMAIN); 90 91 argc--, progname = *argv++; 92 if (argc > 1 && argv[0][0] == '-') 93 addon++, argc--, argv++; 94 if (argc < 3) 95 (void) fprintf(stderr, gettext(usagestr), progname), exit(1); 96 mesgwrite = fopen(argv[0], addon ? "a" : "w"); 97 if (mesgwrite == NULL) 98 perror(argv[0]), exit(1); 99 mesgread = fopen(argv[0], "r"); 100 if (mesgread == NULL) 101 perror(argv[0]), exit(1); 102 inithash(); 103 argc--, argv++; 104 105 if (strlcpy(name, argv[0], sizeof (name)) >= sizeof (name)) { 106 (void) fprintf(stderr, gettext("%s: %s: string too long"), 107 progname, argv[0]); 108 exit(1); 109 } 110 111 np = name + strlen(name); 112 113 len = strlen(name); 114 np = name + len; 115 size = sizeof (name) - len; 116 argc--, argv++; 117 do { 118 if (strlcpy(np, argv[0], size) >= size) { 119 (void) fprintf(stderr, 120 gettext("%s: %s: string too long"), 121 progname, argv[0]); 122 exit(1); 123 } 124 if (freopen(name, "w", stdout) == NULL) 125 perror(name), exit(1); 126 if (freopen(argv[0], "r", stdin) == NULL) 127 perror(argv[0]), exit(1); 128 process(); 129 argc--, argv++; 130 } while (argc > 0); 131 132 return (0); 133 } 134 135 static void 136 process(void) 137 { 138 int c; 139 140 for (;;) { 141 c = getchar(); 142 if (c == EOF) 143 return; 144 if (c != 'e') { 145 (void) putchar(c); 146 continue; 147 } 148 if (match("error(")) { 149 (void) printf(gettext("error(")); 150 c = getchar(); 151 if (c != '"') 152 (void) putchar(c); 153 else 154 copystr(); 155 } 156 } 157 } 158 159 static int 160 match(char *ocp) 161 { 162 char *cp; 163 int c; 164 165 for (cp = ocp + 1; *cp; cp++) { 166 c = getchar(); 167 if (c != *cp) { 168 while (ocp < cp) 169 (void) putchar(*ocp++); 170 (void) ungetchar(c); 171 return (0); 172 } 173 } 174 return (1); 175 } 176 177 static void 178 copystr(void) 179 { 180 int c, ch; 181 char buf[512]; 182 char *cp = buf; 183 184 for (;;) { 185 c = getchar(); 186 if (c == EOF) 187 break; 188 switch (c) { 189 190 case '"': 191 *cp++ = 0; 192 goto out; 193 case '\\': 194 c = getchar(); 195 switch (c) { 196 197 case 'b': 198 c = '\b'; 199 break; 200 case 't': 201 c = '\t'; 202 break; 203 case 'r': 204 c = '\r'; 205 break; 206 case 'n': 207 c = '\n'; 208 break; 209 case '\n': 210 continue; 211 case 'f': 212 c = '\f'; 213 break; 214 case '0': 215 c = 0; 216 break; 217 case '\\': 218 break; 219 default: 220 if (!octdigit(c)) 221 break; 222 c -= '0'; 223 ch = getchar(); 224 if (!octdigit(ch)) 225 break; 226 c <<= 7, c += ch - '0'; 227 ch = getchar(); 228 if (!octdigit(ch)) 229 break; 230 c <<= 3, c += ch - '0', ch = -1; 231 break; 232 } 233 } 234 *cp++ = c; 235 } 236 out: 237 *cp = 0; 238 (void) printf("%d", hashit(buf, 1, 0)); 239 } 240 241 static int 242 octdigit(char c) 243 { 244 245 return (c >= '0' && c <= '7'); 246 } 247 248 static void 249 inithash(void) 250 { 251 char buf[512]; 252 int mesgpt = 0; 253 254 rewind(mesgread); 255 while (fgetNUL(buf, sizeof (buf), mesgread) != 0) { 256 (void) hashit(buf, 0, mesgpt); 257 mesgpt += strlen(buf) + 2; 258 } 259 } 260 261 static struct hash { 262 long hval; 263 unsigned int hpt; 264 struct hash *hnext; 265 } *bucket[NBUCKETS]; 266 267 static int 268 hashit(char *str, char really, unsigned int fakept) 269 { 270 int i; 271 struct hash *hp; 272 char buf[512]; 273 long hashval = 0; 274 char *cp; 275 276 if (really) 277 (void) fflush(mesgwrite); 278 for (cp = str; *cp; ) 279 hashval = (hashval << 1) + *cp++; 280 i = hashval % NBUCKETS; 281 if (i < 0) 282 i += NBUCKETS; 283 if (really != 0) 284 for (hp = bucket[i]; hp != 0; hp = hp->hnext) 285 if (hp->hval == hashval) { 286 (void) fseek(mesgread, (long)hp->hpt, 0); 287 (void) fgetNUL(buf, sizeof (buf), mesgread); 288 if (strcmp(buf, str) == 0) 289 break; 290 } 291 if (!really || hp == 0) { 292 hp = (struct hash *)calloc(1, sizeof (*hp)); 293 hp->hnext = bucket[i]; 294 hp->hval = hashval; 295 hp->hpt = really ? ftell(mesgwrite) : fakept; 296 if (really) { 297 (void) fwrite(str, sizeof (char), strlen(str) + 1, 298 mesgwrite); 299 (void) fwrite("\n", sizeof (char), 1, mesgwrite); 300 } 301 bucket[i] = hp; 302 } 303 return (hp->hpt); 304 } 305 306 static int 307 fgetNUL(char *obuf, int rmdr, FILE *file) 308 { 309 int c; 310 char *buf = obuf; 311 312 while (--rmdr > 0 && (c = getc(file)) != 0 && c != EOF) 313 *buf++ = c; 314 *buf++ = 0; 315 (void) getc(file); 316 return ((feof(file) || ferror(file)) ? 0 : 1); 317 } 318