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