Mercurial > hg > early-roguelike
view rogue4/xstr.c @ 111:7f8f43943b1f
Fix some terribly depressing corruption during restore.
In rogue5/state.c, rs_read_daemons() zeroes out the argument and delay
if the daemon slot is empty. Unfortunately that code ended up on the
wrong side of the brace that closes the for loop, so instead of running
after each daemon, it got run once after the loop exited, when the
index was of course out of bounds.
This tended to manifest, when compiled with -O2, by overwriting hw and
setting it to NULL. When inventory() next ran, hw would be passed to
wgetch(), which returns ERR when it gets a NULL argument. This made
md_readchar() think something was wrong and autosave the game.
Upon investigation, rogue3 was found to commit the same mistake.
rogue4 and srogue don't zero the data. arogue5 already does it
properly.
Someday I am going to run all this through Valgrind. Someday when I
am a kinder person who will not be driven to invoke hordes of trolls
and centaurs upon the original authors.
author | John "Elwin" Edwards |
---|---|
date | Wed, 08 Jan 2014 16:44:16 -0500 |
parents | 9535a08ddc39 |
children |
line wrap: on
line source
/* * * 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); }