NetBSD/usr.bin/xstr/xstr.c

570 lines
11 KiB
C
Raw Normal View History

2005-06-02 08:34:57 +04:00
/* $NetBSD: xstr.c,v 1.21 2005/06/02 04:40:00 lukem Exp $ */
1993-03-21 12:45:37 +03:00
/*
* Copyright (c) 1980, 1993
* The Regents of the University of California. All rights reserved.
1993-03-21 12:45:37 +03:00
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
1993-03-21 12:45:37 +03:00
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
1993-03-21 12:45:37 +03:00
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
The Regents of the University of California. All rights reserved.\n");
1993-03-21 12:45:37 +03:00
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)xstr.c 8.1 (Berkeley) 6/9/93";
#else
2005-06-02 08:34:57 +04:00
__RCSID("$NetBSD: xstr.c,v 1.21 2005/06/02 04:40:00 lukem Exp $");
#endif
1993-03-21 12:45:37 +03:00
#endif /* not lint */
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
1994-12-24 19:57:59 +03:00
#include <stdlib.h>
#include <err.h>
1993-03-21 12:45:37 +03:00
#include "pathnames.h"
/*
* xstr - extract and hash strings in a C program
*
* Bill Joy UCB
* November, 1978
*/
2003-11-08 21:12:01 +03:00
static off_t hashit(const char *, int);
static void onintr(int);
static off_t yankstr(char **);
static int octdigit(char);
static void inithash(void);
static int fgetNUL(char *, int, FILE *);
static int xgetc(FILE *);
static void flushsh(void);
static void found(int, off_t, const char *);
static void prstr(const char *);
static void xsdotc(void);
static char lastchr(const char *);
static int istail(const char *, const char *);
static void process(const char *);
static void usage(void);
static off_t tellpt;
static off_t mesgpt;
static char *strings = "strings";
static char *array = 0;
static int cflg;
static int vflg;
static int readstd;
static char linebuf[8192];
#define BUCKETS 128
static struct hash {
off_t hpt;
char *hstr;
struct hash *hnext;
short hnew;
} bucket[BUCKETS];
2003-11-08 21:12:01 +03:00
int main(int, char *[]);
1993-03-21 12:45:37 +03:00
int
2003-11-08 21:12:01 +03:00
main(int argc, char *argv[])
1993-03-21 12:45:37 +03:00
{
int c;
1993-03-21 12:45:37 +03:00
while ((c = getopt(argc, argv, "-cvl:")) != -1)
switch (c) {
case '-':
1993-03-21 12:45:37 +03:00
readstd++;
break;
1993-03-21 12:45:37 +03:00
case 'c':
cflg++;
break;
1993-03-21 12:45:37 +03:00
case 'v':
vflg++;
break;
case 'l':
array = optarg;
break;
1993-03-21 12:45:37 +03:00
default:
usage();
}
argc -= optind;
argv += optind;
if (array == 0)
array = "xstr";
1993-03-21 12:45:37 +03:00
if (signal(SIGINT, SIG_IGN) == SIG_DFL)
(void)signal(SIGINT, onintr);
if (cflg || (argc == 0 && !readstd))
1993-03-21 12:45:37 +03:00
inithash();
1999-04-20 17:53:53 +04:00
else {
int fd;
strings = strdup(_PATH_TMP);
fd = mkstemp(strings);
if (fd == -1)
err(1, "mkstemp failed");
close(fd);
}
1993-03-21 12:45:37 +03:00
while (readstd || argc > 0) {
if (freopen("x.c", "w", stdout) == NULL)
err(1, "Cannot open `%s'", "x.c");
1993-03-21 12:45:37 +03:00
if (!readstd && freopen(argv[0], "r", stdin) == NULL)
err(1, "Cannot open `%s'", argv[0]);
1993-03-21 12:45:37 +03:00
process("x.c");
if (readstd == 0)
argc--, argv++;
else
readstd = 0;
};
flushsh();
if (cflg == 0)
xsdotc();
if (strings[0] == '/')
(void)unlink(strings);
1993-03-21 12:45:37 +03:00
exit(0);
}
static void
2003-11-08 21:12:01 +03:00
process(const char *name)
1993-03-21 12:45:37 +03:00
{
char *cp;
int c;
int incomm = 0;
int inasm = 0;
int asmparnest = 0;
1993-03-21 12:45:37 +03:00
int ret;
printf("extern char\t%s[];\n", array);
1993-03-21 12:45:37 +03:00
for (;;) {
if (fgets(linebuf, sizeof linebuf, stdin) == NULL) {
if (ferror(stdin))
err(1, "Error reading `%s'", name);
1993-03-21 12:45:37 +03:00
break;
}
if (linebuf[0] == '#') {
2003-11-08 21:44:52 +03:00
printf("%s", linebuf);
1993-03-21 12:45:37 +03:00
continue;
}
2003-11-08 21:12:01 +03:00
for (cp = linebuf; (c = *cp++);)
switch (c) {
2003-11-08 21:12:01 +03:00
case '"':
if (incomm || inasm)
goto def;
if ((ret = (int) yankstr(&cp)) == -1)
goto out;
printf("(&%s[%d])", array, ret);
break;
1993-03-21 12:45:37 +03:00
2003-11-08 21:12:01 +03:00
case '\'':
if (incomm || inasm)
goto def;
putchar(c);
if (*cp)
putchar(*cp++);
break;
1993-03-21 12:45:37 +03:00
2003-11-08 21:12:01 +03:00
case '/':
if (incomm || *cp != '*')
goto def;
incomm = 1;
1993-03-21 12:45:37 +03:00
cp++;
2003-11-08 21:12:01 +03:00
printf("/*");
1993-03-21 12:45:37 +03:00
continue;
2003-11-08 21:12:01 +03:00
case '*':
if (incomm && *cp == '/') {
incomm = 0;
cp++;
printf("*/");
continue;
}
goto def;
2003-11-08 21:12:01 +03:00
case '(':
if (!incomm && inasm)
asmparnest++;
goto def;
2003-11-08 21:12:01 +03:00
case ')':
if (!incomm && inasm && !--asmparnest)
inasm = 0;
goto def;
2003-11-08 21:12:01 +03:00
case '_':
if (incomm || inasm)
goto def;
2003-11-08 21:12:01 +03:00
if (!strncmp(cp, "_asm", 4)) {
cp += 4;
printf("__asm");
if (!strncmp(cp, "__", 2)) {
cp += 2;
printf("__");
}
if (isalnum((unsigned char)*cp) ||
*cp == '_')
goto def;
asmparnest = 0;
inasm = 1;
} else
goto def;
break;
1993-03-21 12:45:37 +03:00
def:
2003-11-08 21:12:01 +03:00
default:
putchar(c);
break;
}
1993-03-21 12:45:37 +03:00
}
out:
if (ferror(stdout)) {
warn("Error reading `%s'", "x.c");
onintr(1);
}
1993-03-21 12:45:37 +03:00
}
static off_t
2003-11-08 21:12:01 +03:00
yankstr(char **cpp)
1993-03-21 12:45:37 +03:00
{
char *cp = *cpp;
int c, ch;
char *dbuf, *dp, *edp;
char *tp;
off_t hash;
size_t bsiz = BUFSIZ;
if ((dp = dbuf = malloc(bsiz)) == NULL)
err(1, "malloc");
edp = dbuf + bsiz;
1993-03-21 12:45:37 +03:00
2003-11-08 21:12:01 +03:00
while ((c = *cp++) != '\0') {
1993-03-21 12:45:37 +03:00
switch (c) {
case '"':
/* Look for a concatenated string */
for (;;) {
while (isspace((unsigned char)*cp))
cp++;
if (*cp == '\0') {
if (fgets(linebuf,
sizeof linebuf, stdin) == NULL) {
if (ferror(stdin))
err(1,
"Error reading `x.c'");
goto out;
}
cp = linebuf;
} else {
if (*cp == '"') {
cp++;
if (*cp == '"') {
cp++;
continue;
} else {
c = *cp++;
goto gotc;
}
} else {
cp++;
goto out;
}
}
}
/*NOTREACHED*/
1993-03-21 12:45:37 +03:00
case '\\':
c = *cp++;
if (c == 0)
break;
if (c == '\n') {
if (fgets(linebuf, sizeof linebuf, stdin)
1993-03-21 12:45:37 +03:00
== NULL) {
if (ferror(stdin))
err(1, "Error reading `x.c'");
1993-03-21 12:45:37 +03:00
return(-1);
}
cp = linebuf;
continue;
}
for (tp = "b\bt\tr\rn\nf\f\\\\\"\""; (ch = *tp++); tp++)
1993-03-21 12:45:37 +03:00
if (c == ch) {
c = *tp;
goto gotc;
}
if (!octdigit(c)) {
*dp++ = '\\';
break;
}
c -= '0';
if (!octdigit(*cp))
break;
c <<= 3, c += *cp++ - '0';
if (!octdigit(*cp))
break;
c <<= 3, c += *cp++ - '0';
break;
}
gotc:
if (dp >= edp - 1) {
char *nbuf;
bsiz += BUFSIZ;
if ((nbuf = realloc(dbuf, bsiz)) == NULL) {
free(dbuf);
err(1, "realloc");
}
dp = nbuf + (dp - dbuf);
edp = nbuf + bsiz;
dbuf = nbuf;
}
1993-03-21 12:45:37 +03:00
*dp++ = c;
}
out:
*cpp = --cp;
*dp = '\0';
hash = hashit(dbuf, 1);
free(dbuf);
return hash;
1993-03-21 12:45:37 +03:00
}
static int
1993-03-21 12:45:37 +03:00
octdigit(c)
char c;
{
1998-12-20 22:05:19 +03:00
return (isdigit((unsigned char)c) && c != '8' && c != '9');
1993-03-21 12:45:37 +03:00
}
static void
2003-11-08 21:12:01 +03:00
inithash(void)
1993-03-21 12:45:37 +03:00
{
char buf[BUFSIZ];
FILE *mesgread = fopen(strings, "r");
1993-03-21 12:45:37 +03:00
if (mesgread == NULL)
return;
for (;;) {
mesgpt = tellpt;
if (fgetNUL(buf, sizeof buf, mesgread) == 0)
1993-03-21 12:45:37 +03:00
break;
(void)hashit(buf, 0);
1993-03-21 12:45:37 +03:00
}
(void)fclose(mesgread);
1993-03-21 12:45:37 +03:00
}
static int
2003-11-08 21:12:01 +03:00
fgetNUL(char *obuf, int rmdr, FILE *file)
1993-03-21 12:45:37 +03:00
{
int c;
char *buf = obuf;
1993-03-21 12:45:37 +03:00
2005-06-02 08:34:57 +04:00
c = 0; /* XXXGCC -Wuninitialized */
2003-11-08 21:12:01 +03:00
while (--rmdr > 0 && (c = xgetc(file) != 0 && c != EOF))
1993-03-21 12:45:37 +03:00
*buf++ = c;
*buf++ = 0;
2003-11-08 21:12:01 +03:00
return (feof(file) || ferror(file)) ? 0 : 1;
1993-03-21 12:45:37 +03:00
}
static int
2003-11-08 21:12:01 +03:00
xgetc(FILE *file)
1993-03-21 12:45:37 +03:00
{
tellpt++;
2003-11-08 21:12:01 +03:00
return getc(file);
1993-03-21 12:45:37 +03:00
}
static off_t
2003-11-08 21:12:01 +03:00
hashit(const char *str, int new)
1993-03-21 12:45:37 +03:00
{
int i;
struct hash *hp, *hp0;
1993-03-21 12:45:37 +03:00
hp = hp0 = &bucket[lastchr(str) & 0177];
while (hp->hnext) {
hp = hp->hnext;
i = istail(str, hp->hstr);
if (i >= 0)
return (hp->hpt + i);
}
2003-11-08 21:12:01 +03:00
if ((hp = calloc(1, sizeof (*hp))) == NULL)
err(1, NULL);
1993-03-21 12:45:37 +03:00
hp->hpt = mesgpt;
if ((hp->hstr = strdup(str)) == NULL)
err(1, NULL);
1993-03-21 12:45:37 +03:00
mesgpt += strlen(hp->hstr) + 1;
hp->hnext = hp0->hnext;
hp->hnew = new;
hp0->hnext = hp;
return (hp->hpt);
}
static void
2003-11-08 21:12:01 +03:00
flushsh(void)
1993-03-21 12:45:37 +03:00
{
int i;
struct hash *hp;
FILE *mesgwrit;
int old = 0, new = 0;
1993-03-21 12:45:37 +03:00
for (i = 0; i < BUCKETS; i++)
for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext)
if (hp->hnew)
new++;
else
old++;
if (new == 0 && old != 0)
return;
mesgwrit = fopen(strings, old ? "r+" : "w");
if (mesgwrit == NULL)
err(1, "Cannot open `%s'", strings);
1993-03-21 12:45:37 +03:00
for (i = 0; i < BUCKETS; i++)
for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext) {
found(hp->hnew, hp->hpt, hp->hstr);
if (hp->hnew) {
2003-11-08 21:12:01 +03:00
(void)fseek(mesgwrit, hp->hpt, 0);
(void)fwrite(hp->hstr, strlen(hp->hstr) + 1, 1,
mesgwrit);
1993-03-21 12:45:37 +03:00
if (ferror(mesgwrit))
err(1, "Error writing `%s'", strings);
1993-03-21 12:45:37 +03:00
}
}
if (fclose(mesgwrit) == EOF)
err(1, "Error closing `%s'", strings);
1993-03-21 12:45:37 +03:00
}
static void
2003-11-08 21:12:01 +03:00
found(int new, off_t off, const char *str)
1993-03-21 12:45:37 +03:00
{
if (vflg == 0)
return;
if (!new)
(void)fprintf(stderr, "found at %d:", (int) off);
1993-03-21 12:45:37 +03:00
else
(void)fprintf(stderr, "new at %d:", (int) off);
1993-03-21 12:45:37 +03:00
prstr(str);
(void)fprintf(stderr, "\n");
1993-03-21 12:45:37 +03:00
}
static void
2003-11-08 21:12:01 +03:00
prstr(const char *cp)
1993-03-21 12:45:37 +03:00
{
int c;
1993-03-21 12:45:37 +03:00
2003-11-08 21:12:01 +03:00
while ((c = (*cp++ & 0377)) != '\0')
1993-03-21 12:45:37 +03:00
if (c < ' ')
2003-11-08 21:12:01 +03:00
(void)fprintf(stderr, "^%c", c + '`');
1993-03-21 12:45:37 +03:00
else if (c == 0177)
2003-11-08 21:12:01 +03:00
(void)fprintf(stderr, "^?");
1993-03-21 12:45:37 +03:00
else if (c > 0200)
2003-11-08 21:12:01 +03:00
(void)fprintf(stderr, "\\%03o", c);
1993-03-21 12:45:37 +03:00
else
2003-11-08 21:12:01 +03:00
(void)fprintf(stderr, "%c", c);
1993-03-21 12:45:37 +03:00
}
static void
2003-11-08 21:12:01 +03:00
xsdotc(void)
1993-03-21 12:45:37 +03:00
{
FILE *strf = fopen(strings, "r");
FILE *xdotcf;
1993-03-21 12:45:37 +03:00
if (strf == NULL)
err(1, "Cannot open `%s'", strings);
1993-03-21 12:45:37 +03:00
xdotcf = fopen("xs.c", "w");
if (xdotcf == NULL)
err(1, "Cannot open `%s'", "xs.c");
2003-11-08 21:12:01 +03:00
(void)fprintf(xdotcf, "char\t%s[] = {\n", array);
1993-03-21 12:45:37 +03:00
for (;;) {
int i, c;
1993-03-21 12:45:37 +03:00
for (i = 0; i < 8; i++) {
c = getc(strf);
if (ferror(strf)) {
warn("Error reading `%s'", strings);
onintr(1);
1993-03-21 12:45:37 +03:00
}
if (feof(strf)) {
2003-11-08 21:12:01 +03:00
(void)fprintf(xdotcf, "\n");
1993-03-21 12:45:37 +03:00
goto out;
}
2003-11-08 21:12:01 +03:00
(void)fprintf(xdotcf, "0x%02x,", c);
1993-03-21 12:45:37 +03:00
}
2003-11-08 21:12:01 +03:00
(void)fprintf(xdotcf, "\n");
1993-03-21 12:45:37 +03:00
}
out:
2003-11-08 21:12:01 +03:00
(void)fprintf(xdotcf, "};\n");
(void)fclose(xdotcf);
(void)fclose(strf);
1993-03-21 12:45:37 +03:00
}
static char
2003-11-08 21:12:01 +03:00
lastchr(const char *cp)
1993-03-21 12:45:37 +03:00
{
while (cp[0] && cp[1])
cp++;
return (*cp);
}
static int
2003-11-08 21:12:01 +03:00
istail(const char *str, const char *of)
1993-03-21 12:45:37 +03:00
{
int d = strlen(of) - strlen(str);
1993-03-21 12:45:37 +03:00
if (d < 0 || strcmp(&of[d], str) != 0)
return (-1);
return (d);
}
static void
2003-11-08 21:12:01 +03:00
onintr(int dummy)
1993-03-21 12:45:37 +03:00
{
(void)signal(SIGINT, SIG_IGN);
1993-03-21 12:45:37 +03:00
if (strings[0] == '/')
(void)unlink(strings);
(void)unlink("x.c");
(void)unlink("xs.c");
exit(dummy);
}
static void
2003-11-08 21:12:01 +03:00
usage(void)
{
2001-02-20 02:03:42 +03:00
(void)fprintf(stderr, "usage: %s [-cv] [-l array] [-] [<name> ...]\n",
2001-02-20 02:03:42 +03:00
getprogname());
exit(1);
1993-03-21 12:45:37 +03:00
}