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