Home | History | Annotate | Download | only in mkstr
      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