1 /* 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static const char copyright[] = 36 "@(#) Copyright (c) 1980, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)mkstr.c 8.1 (Berkeley) 6/6/93"; 43 #endif 44 static const char rcsid[] = 45 "$Id$"; 46 #endif /* not lint */ 47 48 #include <err.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 52 #define ungetchar(c) ungetc(c, stdin) 53 54 /* 55 * mkstr - create a string error message file by massaging C source 56 * 57 * Bill Joy UCB August 1977 58 * 59 * Modified March 1978 to hash old messages to be able to recompile 60 * without addding messages to the message file (usually) 61 * 62 * Based on an earlier program conceived by Bill Joy and Chuck Haley 63 * 64 * Program to create a string error message file 65 * from a group of C programs. Arguments are the name 66 * of the file where the strings are to be placed, the 67 * prefix of the new files where the processed source text 68 * is to be placed, and the files to be processed. 69 * 70 * The program looks for 'error("' in the source stream. 71 * Whenever it finds this, the following characters from the '"' 72 * to a '"' are replaced by 'seekpt' where seekpt is a 73 * pointer into the error message file. 74 * If the '(' is not immediately followed by a '"' no change occurs. 75 * 76 * The optional '-' causes strings to be added at the end of the 77 * existing error message file for recompilation of single routines. 78 */ 79 80 FILE *mesgread, *mesgwrite; 81 char name[100], *np; 82 83 void copystr __P((void)); 84 int fgetNUL __P((char *, int, FILE *)); 85 unsigned hashit __P((char *, char, unsigned)); 86 void inithash __P((void)); 87 int match __P((char *)); 88 int octdigit __P((char)); 89 void process __P((void)); 90 static void usage __P((void)); 91 92 int 93 main(argc, argv) 94 int argc; 95 char *argv[]; 96 { 97 char addon = 0; 98 99 argc--, argv++; 100 if (argc > 1 && argv[0][0] == '-') 101 addon++, argc--, argv++; 102 if (argc < 3) 103 usage(); 104 mesgwrite = fopen(argv[0], addon ? "a" : "w"); 105 if (mesgwrite == NULL) 106 err(1, "%s", argv[0]); 107 mesgread = fopen(argv[0], "r"); 108 if (mesgread == NULL) 109 err(1, "%s", argv[0]); 110 inithash(); 111 argc--, argv++; 112 strcpy(name, argv[0]); 113 np = name + strlen(name); 114 argc--, argv++; 115 do { 116 strcpy(np, argv[0]); 117 if (freopen(name, "w", stdout) == NULL) 118 err(1, "%s", name); 119 if (freopen(argv[0], "r", stdin) == NULL) 120 err(1, "%s", argv[0]); 121 process(); 122 argc--, argv++; 123 } while (argc > 0); 124 exit(0); 125 } 126 127 static void 128 usage() 129 { 130 fprintf(stderr, "usage: mkstr [ - ] mesgfile prefix file ...\n"); 131 exit(1); 132 } 133 134 void 135 process() 136 { 137 register c; 138 139 for (;;) { 140 c = getchar(); 141 if (c == EOF) 142 return; 143 if (c != 'e') { 144 putchar(c); 145 continue; 146 } 147 if (match("error(")) { 148 printf("error("); 149 c = getchar(); 150 if (c != '"') 151 putchar(c); 152 else 153 copystr(); 154 } 155 } 156 } 157 158 int 159 match(ocp) 160 char *ocp; 161 { 162 register char *cp; 163 register c; 164 165 for (cp = ocp + 1; *cp; cp++) { 166 c = getchar(); 167 if (c != *cp) { 168 while (ocp < cp) 169 putchar(*ocp++); 170 ungetchar(c); 171 return (0); 172 } 173 } 174 return (1); 175 } 176 177 void 178 copystr() 179 { 180 register c, ch; 181 char buf[512]; 182 register 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 printf("%d", hashit(buf, 1, NULL)); 239 } 240 241 int 242 octdigit(c) 243 char c; 244 { 245 246 return (c >= '0' && c <= '7'); 247 } 248 249 void 250 inithash() 251 { 252 char buf[512]; 253 int mesgpt = 0; 254 255 rewind(mesgread); 256 while (fgetNUL(buf, sizeof buf, mesgread) != 0) { 257 hashit(buf, 0, mesgpt); 258 mesgpt += strlen(buf) + 2; 259 } 260 } 261 262 #define NBUCKETS 511 263 264 struct hash { 265 long hval; 266 unsigned hpt; 267 struct hash *hnext; 268 } *bucket[NBUCKETS]; 269 270 unsigned 271 hashit(str, really, fakept) 272 char *str; 273 char really; 274 unsigned fakept; 275 { 276 int i; 277 register struct hash *hp; 278 char buf[512]; 279 long hashval = 0; 280 register char *cp; 281 282 if (really) 283 fflush(mesgwrite); 284 for (cp = str; *cp;) 285 hashval = (hashval << 1) + *cp++; 286 i = hashval % NBUCKETS; 287 if (i < 0) 288 i += NBUCKETS; 289 if (really != 0) 290 for (hp = bucket[i]; hp != 0; hp = hp->hnext) 291 if (hp->hval == hashval) { 292 fseek(mesgread, (long) hp->hpt, 0); 293 fgetNUL(buf, sizeof buf, mesgread); 294 /* 295 fprintf(stderr, "Got (from %d) %s\n", hp->hpt, buf); 296 */ 297 if (strcmp(buf, str) == 0) 298 break; 299 } 300 if (!really || hp == 0) { 301 hp = (struct hash *) calloc(1, sizeof *hp); 302 hp->hnext = bucket[i]; 303 hp->hval = hashval; 304 hp->hpt = really ? ftell(mesgwrite) : fakept; 305 if (really) { 306 fwrite(str, sizeof (char), strlen(str) + 1, mesgwrite); 307 fwrite("\n", sizeof (char), 1, mesgwrite); 308 } 309 bucket[i] = hp; 310 } 311 /* 312 fprintf(stderr, "%s hashed to %ld at %d\n", str, hp->hval, hp->hpt); 313 */ 314 return (hp->hpt); 315 } 316 317 #include <sys/types.h> 318 #include <sys/stat.h> 319 320 int 321 fgetNUL(obuf, rmdr, file) 322 char *obuf; 323 register int rmdr; 324 FILE *file; 325 { 326 register c; 327 register char *buf = obuf; 328 329 while (--rmdr > 0 && (c = getc(file)) != 0 && c != EOF) 330 *buf++ = c; 331 *buf++ = 0; 332 getc(file); 333 return ((feof(file) || ferror(file)) ? 0 : 1); 334 } 335