155714Skris/* 2160814Ssimon * Copyright (c) 1980, 1993 3160814Ssimon * The Regents of the University of California. All rights reserved. 4160814Ssimon * 5160814Ssimon * Redistribution and use in source and binary forms, with or without 6160814Ssimon * modification, are permitted provided that the following conditions 7160814Ssimon * are met: 8160814Ssimon * 1. Redistributions of source code must retain the above copyright 9160814Ssimon * notice, this list of conditions and the following disclaimer. 10160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright 11160814Ssimon * notice, this list of conditions and the following disclaimer in the 12160814Ssimon * documentation and/or other materials provided with the distribution. 13160814Ssimon * 4. Neither the name of the University nor the names of its contributors 14160814Ssimon * may be used to endorse or promote products derived from this software 15160814Ssimon * without specific prior written permission. 16160814Ssimon * 17160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18160814Ssimon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20160814Ssimon * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21160814Ssimon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22160814Ssimon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23160814Ssimon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25160814Ssimon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26160814Ssimon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27160814Ssimon * SUCH DAMAGE. 28160814Ssimon */ 29160814Ssimon 30160814Ssimon#ifndef lint 31160814Ssimonstatic const char copyright[] = 32160814Ssimon"@(#) Copyright (c) 1980, 1993\n\ 33160814Ssimon The Regents of the University of California. All rights reserved.\n"; 34160814Ssimon#endif /* not lint */ 35160814Ssimon 36160814Ssimon#ifndef lint 37160814Ssimon#if 0 38160814Ssimonstatic char sccsid[] = "@(#)mkstr.c 8.1 (Berkeley) 6/6/93"; 39160814Ssimon#endif 40160814Ssimon#endif /* not lint */ 41160814Ssimon 42160814Ssimon#include <sys/cdefs.h> 43160814Ssimon__FBSDID("$FreeBSD: releng/10.3/usr.bin/mkstr/mkstr.c 216370 2010-12-11 08:32:16Z joel $"); 44160814Ssimon 45160814Ssimon#include <err.h> 46160814Ssimon#include <errno.h> 47160814Ssimon#include <stdio.h> 48160814Ssimon#include <stdlib.h> 49160814Ssimon#include <string.h> 50160814Ssimon 51160814Ssimon#define ungetchar(c) ungetc(c, stdin) 52160814Ssimon 53160814Ssimon/* 54160814Ssimon * mkstr - create a string error message file by massaging C source 5555714Skris * 5655714Skris * Bill Joy UCB August 1977 5755714Skris * 5855714Skris * Modified March 1978 to hash old messages to be able to recompile 5955714Skris * without addding messages to the message file (usually) 6055714Skris * 6155714Skris * Based on an earlier program conceived by Bill Joy and Chuck Haley 6255714Skris * 6355714Skris * Program to create a string error message file 6455714Skris * from a group of C programs. Arguments are the name 6555714Skris * of the file where the strings are to be placed, the 6655714Skris * prefix of the new files where the processed source text 6755714Skris * is to be placed, and the files to be processed. 6855714Skris * 6955714Skris * The program looks for 'error("' in the source stream. 7055714Skris * Whenever it finds this, the following characters from the '"' 7155714Skris * to a '"' are replaced by 'seekpt' where seekpt is a 7255714Skris * pointer into the error message file. 7355714Skris * If the '(' is not immediately followed by a '"' no change occurs. 7455714Skris * 7555714Skris * The optional '-' causes strings to be added at the end of the 7655714Skris * existing error message file for recompilation of single routines. 7755714Skris */ 7855714Skris 7955714SkrisFILE *mesgread, *mesgwrite; 8055714Skrischar name[100], *np; 8155714Skris 8255714Skrisvoid copystr(void); 8355714Skrisint fgetNUL(char *, int, FILE *); 8455714Skrisunsigned hashit(char *, int, unsigned); 8555714Skrisvoid inithash(void); 8655714Skrisint match(const char *); 8755714Skrisint octdigit(char); 8855714Skrisvoid process(void); 8955714Skrisvoid usage(void); 9055714Skris 9155714Skrisint 9255714Skrismain(int argc, char *argv[]) 9355714Skris{ 9455714Skris char addon = 0; 9555714Skris size_t namelen; 9655714Skris 9755714Skris argc--, argv++; 9855714Skris if (argc > 1 && argv[0][0] == '-') 9955714Skris addon++, argc--, argv++; 10055714Skris if (argc < 3) 10155714Skris usage(); 10255714Skris mesgwrite = fopen(argv[0], addon ? "a" : "w"); 10355714Skris if (mesgwrite == NULL) 10455714Skris err(1, "%s", argv[0]); 10555714Skris mesgread = fopen(argv[0], "r"); 10655714Skris if (mesgread == NULL) 10755714Skris err(1, "%s", argv[0]); 10855714Skris inithash(); 10955714Skris argc--, argv++; 11055714Skris namelen = strlcpy(name, argv[0], sizeof(name)); 111160814Ssimon if (namelen >= sizeof(name)) { 112160814Ssimon errno = ENAMETOOLONG; 113160814Ssimon err(1, "%s", argv[0]); 114160814Ssimon } 115160814Ssimon np = name + namelen; 11655714Skris argc--, argv++; 11755714Skris do { 11868651Skris if (strlcpy(np, argv[0], sizeof(name) - namelen) >= 11955714Skris sizeof(name) - namelen) { 120109998Smarkm errno = ENAMETOOLONG; 12155714Skris err(1, "%s%s", name, argv[0]); 12255714Skris } 12355714Skris if (freopen(name, "w", stdout) == NULL) 12455714Skris err(1, "%s", name); 12555714Skris if (freopen(argv[0], "r", stdin) == NULL) 12655714Skris err(1, "%s", argv[0]); 12755714Skris process(); 12855714Skris argc--, argv++; 12968651Skris } while (argc > 0); 13055714Skris exit(0); 13155714Skris} 13255714Skris 13355714Skrisvoid 13455714Skrisusage(void) 13555714Skris{ 13655714Skris fprintf(stderr, "usage: mkstr [-] mesgfile prefix file ...\n"); 13755714Skris exit(1); 13855714Skris} 13955714Skris 14055714Skrisvoid 14155714Skrisprocess(void) 14255714Skris{ 14355714Skris int c; 14455714Skris 14555714Skris for (;;) { 14655714Skris c = getchar(); 14755714Skris if (c == EOF) 14855714Skris return; 14955714Skris if (c != 'e') { 15055714Skris putchar(c); 15155714Skris continue; 15255714Skris } 15355714Skris if (match("error(")) { 15455714Skris printf("error("); 15555714Skris c = getchar(); 15655714Skris if (c != '"') 15755714Skris putchar(c); 15855714Skris else 15955714Skris copystr(); 16055714Skris } 16155714Skris } 16255714Skris} 16355714Skris 16455714Skrisint 16555714Skrismatch(const char *ocp) 16655714Skris{ 16755714Skris const char *cp; 16855714Skris int c; 16955714Skris 17055714Skris for (cp = ocp + 1; *cp; cp++) { 17155714Skris c = getchar(); 17255714Skris if (c != *cp) { 17355714Skris while (ocp < cp) 17455714Skris putchar(*ocp++); 175109998Smarkm ungetchar(c); 17655714Skris return (0); 177109998Smarkm } 17855714Skris } 17959191Skris return (1); 18055714Skris} 18155714Skris 18255714Skrisvoid 18355714Skriscopystr(void) 18455714Skris{ 18555714Skris int c, ch; 18655714Skris char buf[512]; 18755714Skris char *cp = buf; 18855714Skris 18955714Skris for (;;) { 190194206Ssimon if (cp == buf + sizeof(buf) - 2) 191194206Ssimon errx(1, "message too long"); 192194206Ssimon c = getchar(); 193194206Ssimon if (c == EOF) 194194206Ssimon break; 195194206Ssimon switch (c) { 196194206Ssimon 197194206Ssimon case '"': 19855714Skris *cp++ = 0; 19955714Skris goto out; 20055714Skris case '\\': 20155714Skris c = getchar(); 20255714Skris switch (c) { 20355714Skris 20455714Skris case 'b': 20555714Skris c = '\b'; 20655714Skris break; 20755714Skris case 't': 20855714Skris c = '\t'; 20955714Skris break; 21055714Skris case 'r': 21155714Skris c = '\r'; 21255714Skris break; 21355714Skris case 'n': 21455714Skris c = '\n'; 21555714Skris break; 21655714Skris case '\n': 21755714Skris continue; 21855714Skris case 'f': 21955714Skris c = '\f'; 22055714Skris break; 22155714Skris case '0': 22255714Skris c = 0; 22368651Skris break; 22468651Skris case '\\': 225194206Ssimon break; 226194206Ssimon default: 22768651Skris if (!octdigit(c)) 22868651Skris break; 22968651Skris c -= '0'; 23068651Skris ch = getchar(); 23155714Skris if (!octdigit(ch)) 23255714Skris break; 23355714Skris c <<= 7, c += ch - '0'; 23455714Skris ch = getchar(); 23555714Skris if (!octdigit(ch)) 23668651Skris break; 23755714Skris c <<= 3, c+= ch - '0', ch = -1; 23855714Skris break; 23955714Skris } 24055714Skris } 24155714Skris *cp++ = c; 24255714Skris } 24355714Skrisout: 24455714Skris *cp = 0; 24555714Skris printf("%d", hashit(buf, 1, 0)); 24655714Skris} 24755714Skris 24855714Skrisint 24955714Skrisoctdigit(char c) 25055714Skris{ 25155714Skris 25255714Skris return (c >= '0' && c <= '7'); 25355714Skris} 25455714Skris 25555714Skrisvoid 25655714Skrisinithash(void) 25755714Skris{ 25855714Skris char buf[512]; 25955714Skris int mesgpt = 0; 26055714Skris 26155714Skris rewind(mesgread); 26255714Skris while (fgetNUL(buf, sizeof buf, mesgread) != 0) { 26355714Skris hashit(buf, 0, mesgpt); 26455714Skris mesgpt += strlen(buf) + 2; 26555714Skris } 26655714Skris} 26755714Skris 26855714Skris#define NBUCKETS 511 26955714Skris 27055714Skrisstruct hash { 271160814Ssimon long hval; 272160814Ssimon unsigned hpt; 273194206Ssimon struct hash *hnext; 27455714Skris} *bucket[NBUCKETS]; 275160814Ssimon 276160814Ssimonunsigned 277160814Ssimonhashit(char *str, int really, unsigned fakept) 278160814Ssimon{ 279160814Ssimon int i; 280160814Ssimon struct hash *hp; 281160814Ssimon char buf[512]; 282160814Ssimon long hashval = 0; 283160814Ssimon char *cp; 284160814Ssimon 285160814Ssimon if (really) 286160814Ssimon fflush(mesgwrite); 287160814Ssimon for (cp = str; *cp;) 288160814Ssimon hashval = (hashval << 1) + *cp++; 289160814Ssimon i = hashval % NBUCKETS; 290160814Ssimon if (i < 0) 291160814Ssimon i += NBUCKETS; 292160814Ssimon if (really != 0) 293160814Ssimon for (hp = bucket[i]; hp != 0; hp = hp->hnext) 294160814Ssimon if (hp->hval == hashval) { 295160814Ssimon fseek(mesgread, (long) hp->hpt, 0); 296160814Ssimon fgetNUL(buf, sizeof buf, mesgread); 297160814Ssimon/* 298160814Ssimon fprintf(stderr, "Got (from %d) %s\n", hp->hpt, buf); 299160814Ssimon*/ 300160814Ssimon if (strcmp(buf, str) == 0) 301160814Ssimon break; 302160814Ssimon } 303160814Ssimon if (!really || hp == 0) { 304160814Ssimon hp = (struct hash *) calloc(1, sizeof *hp); 305160814Ssimon if (hp == NULL) 306160814Ssimon err(1, NULL); 307160814Ssimon hp->hnext = bucket[i]; 308160814Ssimon hp->hval = hashval; 309194206Ssimon hp->hpt = really ? ftell(mesgwrite) : fakept; 310194206Ssimon if (really) { 311194206Ssimon fwrite(str, sizeof (char), strlen(str) + 1, mesgwrite); 312194206Ssimon fwrite("\n", sizeof (char), 1, mesgwrite); 313194206Ssimon } 314194206Ssimon bucket[i] = hp; 315194206Ssimon } 316194206Ssimon/* 317194206Ssimon fprintf(stderr, "%s hashed to %ld at %d\n", str, hp->hval, hp->hpt); 318194206Ssimon*/ 319194206Ssimon return (hp->hpt); 320194206Ssimon} 321194206Ssimon 322194206Ssimonint 323194206SsimonfgetNUL(char *obuf, int rmdr, FILE *file) 324194206Ssimon{ 325194206Ssimon int c; 326194206Ssimon char *buf = obuf; 327194206Ssimon 328194206Ssimon while (--rmdr > 0 && (c = getc(file)) != 0 && c != EOF) 329194206Ssimon *buf++ = c; 330194206Ssimon *buf++ = 0; 331194206Ssimon getc(file); 332194206Ssimon return ((feof(file) || ferror(file)) ? 0 : 1); 333194206Ssimon} 334194206Ssimon