436 lines
6.8 KiB
C
436 lines
6.8 KiB
C
/*
|
|
*
|
|
* Rogue: Exploring the Dungeons of Doom
|
|
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
|
|
* All rights reserved.
|
|
*
|
|
* See the file LICENSE.TXT for full copyright and licensing information.
|
|
*/
|
|
|
|
static char *sccsid = "@(#)xstr.c 4.1 (Berkeley) 10/1/80";
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <signal.h>
|
|
|
|
/*
|
|
* xstr - extract and hash strings in a C program
|
|
*
|
|
* Bill Joy UCB
|
|
* November, 1978
|
|
*/
|
|
|
|
#define ignore(a) (a)
|
|
|
|
char *calloc();
|
|
off_t tellpt;
|
|
off_t hashit();
|
|
char *mktemp();
|
|
void onintr(int);
|
|
char *savestr();
|
|
char *strcat();
|
|
char *strcpy();
|
|
off_t yankstr();
|
|
|
|
off_t mesgpt;
|
|
char *strings = "strings";
|
|
|
|
int cflg;
|
|
int vflg;
|
|
int readstd;
|
|
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
|
|
argc--, argv++;
|
|
while (argc > 0 && argv[0][0] == '-') {
|
|
register char *cp = &(*argv++)[1];
|
|
|
|
argc--;
|
|
if (*cp == 0) {
|
|
readstd++;
|
|
continue;
|
|
}
|
|
do switch (*cp++) {
|
|
|
|
case 'c':
|
|
cflg++;
|
|
continue;
|
|
|
|
case 'v':
|
|
vflg++;
|
|
continue;
|
|
|
|
default:
|
|
fprintf(stderr, "usage: xstr [ -v ] [ -c ] [ - ] [ name ... ]\n");
|
|
} while (*cp);
|
|
}
|
|
if (signal(SIGINT, SIG_IGN) == SIG_DFL)
|
|
signal(SIGINT, onintr);
|
|
if (cflg || argc == 0 && !readstd)
|
|
inithash();
|
|
else
|
|
strings = mktemp(savestr("/tmp/xstrXXXXXX"));
|
|
while (readstd || argc > 0) {
|
|
if (freopen("x.c", "w", stdout) == NULL)
|
|
perror("x.c"), exit(1);
|
|
if (!readstd && freopen(argv[0], "r", stdin) == NULL)
|
|
perror(argv[0]), exit(2);
|
|
process("x.c");
|
|
if (readstd == 0)
|
|
argc--, argv++;
|
|
else
|
|
readstd = 0;
|
|
};
|
|
flushsh();
|
|
if (cflg == 0)
|
|
xsdotc();
|
|
if (strings[0] == '/')
|
|
ignore(md_unlink(strings));
|
|
exit(0);
|
|
}
|
|
|
|
process(name)
|
|
char *name;
|
|
{
|
|
char *cp;
|
|
char linebuf[BUFSIZ];
|
|
register int c;
|
|
register int incomm = 0;
|
|
|
|
printf("extern char\txstr[];\n");
|
|
for (;;) {
|
|
if (fgets(linebuf, sizeof linebuf, stdin) == NULL) {
|
|
if (ferror(stdin)) {
|
|
perror(name);
|
|
exit(3);
|
|
}
|
|
break;
|
|
}
|
|
if (linebuf[0] == '#') {
|
|
if (linebuf[1] == ' ' && isdigit(linebuf[2]))
|
|
printf("#line%s", &linebuf[1]);
|
|
else
|
|
printf("%s", linebuf);
|
|
continue;
|
|
}
|
|
for (cp = linebuf; c = *cp++;) switch (c) {
|
|
|
|
case '"':
|
|
if (incomm)
|
|
goto def;
|
|
printf("(&xstr[%d])", (int) yankstr(&cp));
|
|
break;
|
|
|
|
case '\'':
|
|
if (incomm)
|
|
goto def;
|
|
putchar(c);
|
|
if (*cp)
|
|
putchar(*cp++);
|
|
break;
|
|
|
|
case '/':
|
|
if (incomm || *cp != '*')
|
|
goto def;
|
|
incomm = 1;
|
|
cp++;
|
|
printf("/*");
|
|
continue;
|
|
|
|
case '*':
|
|
if (incomm && *cp == '/') {
|
|
incomm = 0;
|
|
cp++;
|
|
printf("*/");
|
|
continue;
|
|
}
|
|
goto def;
|
|
|
|
def:
|
|
default:
|
|
putchar(c);
|
|
break;
|
|
}
|
|
}
|
|
if (ferror(stdout))
|
|
perror("x.c"), onintr(-1);
|
|
}
|
|
|
|
off_t
|
|
yankstr(cpp)
|
|
register char **cpp;
|
|
{
|
|
register char *cp = *cpp;
|
|
register int c, ch;
|
|
char dbuf[BUFSIZ];
|
|
register char *dp = dbuf;
|
|
register char *tp;
|
|
|
|
while (c = *cp++) {
|
|
switch (c) {
|
|
|
|
case '"':
|
|
cp++;
|
|
goto out;
|
|
|
|
case '\\':
|
|
c = *cp++;
|
|
if (c == 0)
|
|
break;
|
|
if (c == '\n')
|
|
continue;
|
|
for (tp = "b\bt\tr\rn\nf\f\\\\\"\""; ch = *tp++; tp++)
|
|
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:
|
|
*dp++ = c;
|
|
}
|
|
out:
|
|
*cpp = --cp;
|
|
*dp = 0;
|
|
return (hashit(dbuf, 1));
|
|
}
|
|
|
|
octdigit(c)
|
|
char c;
|
|
{
|
|
|
|
return (isdigit(c) && c != '8' && c != '9');
|
|
}
|
|
|
|
inithash()
|
|
{
|
|
char buf[BUFSIZ];
|
|
register FILE *mesgread = fopen(strings, "r");
|
|
|
|
if (mesgread == NULL)
|
|
return;
|
|
for (;;) {
|
|
mesgpt = tellpt;
|
|
if (fgetNUL(buf, sizeof buf, mesgread) == 0)
|
|
break;
|
|
hashit(buf, 0);
|
|
}
|
|
ignore(fclose(mesgread));
|
|
}
|
|
|
|
fgetNUL(obuf, rmdr, file)
|
|
char *obuf;
|
|
register int rmdr;
|
|
FILE *file;
|
|
{
|
|
register c;
|
|
register char *buf = obuf;
|
|
|
|
while (--rmdr > 0 && (c = xgetc(file)) != 0 && c != EOF)
|
|
*buf++ = c;
|
|
*buf++ = 0;
|
|
return ((feof(file) || ferror(file)) ? 0 : 1);
|
|
}
|
|
|
|
xgetc(file)
|
|
FILE *file;
|
|
{
|
|
|
|
tellpt++;
|
|
return (getc(file));
|
|
}
|
|
|
|
#define BUCKETS 128
|
|
|
|
struct hash {
|
|
off_t hpt;
|
|
char *hstr;
|
|
struct hash *hnext;
|
|
short hnew;
|
|
} bucket[BUCKETS];
|
|
|
|
off_t
|
|
hashit(str, new)
|
|
char *str;
|
|
int new;
|
|
{
|
|
int i;
|
|
register struct hash *hp, *hp0;
|
|
|
|
hp = hp0 = &bucket[lastchr(str) & 0177];
|
|
while (hp->hnext) {
|
|
hp = hp->hnext;
|
|
i = istail(str, hp->hstr);
|
|
if (i >= 0)
|
|
return (hp->hpt + i);
|
|
}
|
|
hp = (struct hash *) calloc(1, sizeof (*hp));
|
|
hp->hpt = mesgpt;
|
|
hp->hstr = savestr(str);
|
|
mesgpt += strlen(hp->hstr) + 1;
|
|
hp->hnext = hp0->hnext;
|
|
hp->hnew = new;
|
|
hp0->hnext = hp;
|
|
return (hp->hpt);
|
|
}
|
|
|
|
flushsh()
|
|
{
|
|
register int i;
|
|
register struct hash *hp;
|
|
register FILE *mesgwrit;
|
|
register int old = 0, new = 0;
|
|
|
|
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 ? "a" : "w");
|
|
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) {
|
|
fseek(mesgwrit, hp->hpt, 0);
|
|
ignore(fwrite(hp->hstr, strlen(hp->hstr) + 1, 1, mesgwrit));
|
|
if (ferror(mesgwrit))
|
|
perror(strings), exit(4);
|
|
}
|
|
}
|
|
ignore(fclose(mesgwrit));
|
|
}
|
|
|
|
found(new, off, str)
|
|
int new;
|
|
off_t off;
|
|
char *str;
|
|
{
|
|
if (vflg == 0)
|
|
return;
|
|
if (!new)
|
|
fprintf(stderr, "found at %d:", (int) off);
|
|
else
|
|
fprintf(stderr, "new at %d:", (int) off);
|
|
prstr(str);
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
prstr(cp)
|
|
register char *cp;
|
|
{
|
|
register int c;
|
|
|
|
while (c = (*cp++ & 0377))
|
|
if (c < ' ')
|
|
fprintf(stderr, "^%c", c + '`');
|
|
else if (c == 0177)
|
|
fprintf(stderr, "^?");
|
|
else if (c > 0200)
|
|
fprintf(stderr, "\\%03o", c);
|
|
else
|
|
fprintf(stderr, "%c", c);
|
|
}
|
|
|
|
xsdotc()
|
|
{
|
|
register FILE *strf = fopen(strings, "r");
|
|
register FILE *xdotcf;
|
|
|
|
if (strf == NULL)
|
|
perror(strings), exit(5);
|
|
xdotcf = fopen("xs.c", "w");
|
|
if (xdotcf == NULL)
|
|
perror("xs.c"), exit(6);
|
|
fprintf(xdotcf, "char\txstr[] = {\n");
|
|
for (;;) {
|
|
register int i, c;
|
|
|
|
for (i = 0; i < 20; i++) {
|
|
c = getc(strf);
|
|
if (ferror(strf)) {
|
|
perror(strings);
|
|
onintr(-1);
|
|
}
|
|
if (feof(strf)) {
|
|
fprintf(xdotcf, "\n");
|
|
goto out;
|
|
}
|
|
fprintf(xdotcf, "%d,", c);
|
|
}
|
|
fprintf(xdotcf, "\n");
|
|
}
|
|
out:
|
|
fprintf(xdotcf, "};\n");
|
|
ignore(fclose(xdotcf));
|
|
ignore(fclose(strf));
|
|
}
|
|
|
|
char *
|
|
savestr(cp)
|
|
register char *cp;
|
|
{
|
|
register char *dp = (char *) calloc(1, strlen(cp) + 1);
|
|
|
|
return (strcpy(dp, cp));
|
|
}
|
|
|
|
Ignore(void *a)
|
|
{
|
|
|
|
a = a;
|
|
}
|
|
|
|
ignorf(a)
|
|
void (*a)();
|
|
{
|
|
|
|
a = a;
|
|
}
|
|
|
|
lastchr(cp)
|
|
register char *cp;
|
|
{
|
|
|
|
while (cp[0] && cp[1])
|
|
cp++;
|
|
return (*cp);
|
|
}
|
|
|
|
istail(str, of)
|
|
register char *str, *of;
|
|
{
|
|
register int d = strlen(of) - strlen(str);
|
|
|
|
if (d < 0 || strcmp(&of[d], str) != 0)
|
|
return (-1);
|
|
return (d);
|
|
}
|
|
|
|
void
|
|
onintr(int sig)
|
|
{
|
|
|
|
ignorf(signal(SIGINT, SIG_IGN));
|
|
if (strings[0] == '/')
|
|
ignore(md_unlink(strings));
|
|
ignore(md_unlink("x.c"));
|
|
ignore(md_unlink("xs.c"));
|
|
exit(7);
|
|
}
|