diff --git a/src/rumors.c b/src/rumors.c index 6e78a90c8..0bca828da 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)rumors.c 3.5 1996/04/20 */ +/* SCCS Id: @(#)rumors.c 3.5 2006/05/05 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -15,7 +15,19 @@ * this also happens with real fortune cookies. -dgk */ -/* 3.1 +/* 3.5 + * The rumors file consists of a "do not edit" line, then a line containing + * three sets of three counts (first two in decimal, third in hexadecimal). + * The first set has the number of true rumors, the count in bytes for all + * true rumors, and the file offset to the first one. The second set has + * the same group of numbers for the false rumors. The third set has 0 for + * count, 0 for size, and the file offset for end-of-file. The offset of + * the first true rumor plus the size of the true rumors matches the offset + * of the first false rumor. Likewise, the offset of the first false rumor + * plus the size of the false rumors matches the offset for end-of-file. + */ + +/* 3.1 [now obsolete for rumors but still accurate for oracles] * The rumors file consists of a "do not edit" line, a hexadecimal number * giving the number of bytes of useful/true rumors, followed by those * true rumors (one per line), followed by the useless/false/misleading/cute @@ -41,21 +53,26 @@ STATIC_OVL void init_rumors(fp) dlb *fp; { + static const char rumors_header[] = "%d,%ld,%lx;%d,%ld,%lx;0,0,%lx\n"; + int true_count, false_count; /* in file but not used here */ + long eof_offset; char line[BUFSZ]; (void) dlb_fgets(line, sizeof line, fp); /* skip "don't edit" comment */ (void) dlb_fgets(line, sizeof line, fp); - if (sscanf(line, "%6lx\n", &true_rumor_size) == 1 && - true_rumor_size > 0L) { - (void) dlb_fseek(fp, 0L, SEEK_CUR); - true_rumor_start = dlb_ftell(fp); - true_rumor_end = true_rumor_start + true_rumor_size; - (void) dlb_fseek(fp, 0L, SEEK_END); - false_rumor_end = dlb_ftell(fp); - false_rumor_start = true_rumor_end; /* ok, so it's redundant... */ - false_rumor_size = false_rumor_end - false_rumor_start; - } else + if (sscanf(line, rumors_header, + &true_count, &true_rumor_size, &true_rumor_start, + &false_count, &false_rumor_size, &false_rumor_start, + &eof_offset) == 7 && + true_rumor_size > 0L && false_rumor_size > 0L) { + true_rumor_end = true_rumor_start + true_rumor_size; + /* assert( true_rumor_end == false_rumor_start ); */ + false_rumor_end = false_rumor_start + false_rumor_size; + /* assert( false_rumor_end == eof_offset ); */ + } else { true_rumor_size = -1L; /* init failed */ + (void) dlb_fclose(fp); + } } /* exclude_cookie is a hack used because we sometimes want to get rumors in a @@ -145,8 +162,11 @@ rumor_check() winid tmpwin; char *endp, line[BUFSZ], xbuf[BUFSZ], rumor_buf[BUFSZ]; - if (true_rumor_size < 0L) /* we couldn't open RUMORFILE */ + if (true_rumor_size < 0L) { /* we couldn't open RUMORFILE */ + no_rumors: + pline("rumors not accessible."); return; + } rumors = dlb_fopen(RUMORFILE, "r"); @@ -155,8 +175,7 @@ rumor_check() rumor_buf[0] = '\0'; if (true_rumor_size == 0L) { /* if this is 1st outrumor() */ init_rumors(rumors); - if (true_rumor_size < 0L) /* init failed */ - return; + if (true_rumor_size < 0L) goto no_rumors; /* init failed */ } tmpwin = create_nhwindow(NHW_TEXT); @@ -193,6 +212,13 @@ rumor_check() Sprintf(rumor_buf, "T %06ld %s", ftell_rumor_start, xcrypt(line, xbuf)); putstr(tmpwin, 0, rumor_buf); + /* find last true rumor */ + while (dlb_fgets(line, sizeof line, rumors) && + dlb_ftell(rumors) < true_rumor_end) + continue; + if ((endp = index(line, '\n')) != 0) *endp = 0; + Sprintf(rumor_buf, " %6s %s", "", xcrypt(line, xbuf)); + putstr(tmpwin, 0, rumor_buf); rumor_buf[0] = '\0'; (void) dlb_fseek(rumors, false_rumor_start, SEEK_SET); @@ -202,6 +228,13 @@ rumor_check() Sprintf(rumor_buf, "F %06ld %s", ftell_rumor_start, xcrypt(line, xbuf)); putstr(tmpwin, 0, rumor_buf); + /* find last false rumor */ + while (dlb_fgets(line, sizeof line, rumors) && + dlb_ftell(rumors) < false_rumor_end) + continue; + if ((endp = index(line, '\n')) != 0) *endp = 0; + Sprintf(rumor_buf, " %6s %s", "", xcrypt(line, xbuf)); + putstr(tmpwin, 0, rumor_buf); (void) dlb_fclose(rumors); display_nhwindow(tmpwin, TRUE); diff --git a/util/makedefs.c b/util/makedefs.c index c3b0ea451..c1d131e8a 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)makedefs.c 3.5 2005/01/04 */ +/* SCCS Id: @(#)makedefs.c 3.5 2006/05/05 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) M. Stephenson, 1990, 1991. */ /* Copyright (c) Dean Luick, 1990. */ @@ -347,84 +347,110 @@ const char *str; void do_rumors() { - char infile[60]; - long true_rumor_size; + static const char rumors_header[] = + "%s%04d,%06ld,%06lx;%04d,%06ld,%06lx;0,0,%06lx\n"; + char infile[60], tempfile[60]; + int true_rumor_count, false_rumor_count; + long true_rumor_size, false_rumor_size, + true_rumor_offset, false_rumor_offset, eof_offset; + Sprintf(tempfile, DATA_TEMPLATE, "rumors.tmp"); filename[0]='\0'; #ifdef FILE_PREFIX - Strcat(filename,file_prefix); + Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, RUMOR_FILE); - if (!(ofp = fopen(filename, -#ifdef WIN32 - WRBMODE -#else - WRTMODE -#endif - ))) { + if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } - Fprintf(ofp,Dont_Edit_Data); + if (!(tfp = fopen(tempfile, WRTMODE))) { + perror(tempfile); + Fclose(ofp); + exit(EXIT_FAILURE); + } + + true_rumor_count = false_rumor_count = 0; + true_rumor_size = false_rumor_size = 0L; + true_rumor_offset = false_rumor_offset = eof_offset = 0L; + + /* output a dummy header record; we'll replace it in final output */ + Fprintf(tfp, rumors_header, Dont_Edit_Data, + true_rumor_count, true_rumor_size, true_rumor_offset, + false_rumor_count, false_rumor_size, false_rumor_offset, + eof_offset); + /* record the current position; true rumors will start here */ + true_rumor_offset = ftell(tfp); Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE); Strcat(infile, ".tru"); - if (!(ifp = fopen(infile, -#ifdef WIN32 - RDBMODE -#else - RDTMODE -#endif - ))) { + if (!(ifp = fopen(infile, RDTMODE))) { perror(infile); - Fclose(ofp); - Unlink(filename); /* kill empty output file */ - exit(EXIT_FAILURE); + goto rumors_failure; } - /* get size of true rumors file */ -#ifndef VMS - (void) fseek(ifp, 0L, SEEK_END); - true_rumor_size = ftell(ifp); -#else - /* seek+tell is only valid for stream format files; since rumors.%%% - might be in record format, count the actual data bytes instead. - */ - true_rumor_size = 0; - while (fgets(in_line, sizeof in_line, ifp) != 0) + /* copy the true rumors */ + while (fgets(in_line, sizeof in_line, ifp) != 0) { + true_rumor_count++; true_rumor_size += strlen(in_line); /* includes newline */ -#endif /* VMS */ - Fprintf(ofp,"%06lx\n", true_rumor_size); - (void) fseek(ifp, 0L, SEEK_SET); - - /* copy true rumors */ - while (fgets(in_line, sizeof in_line, ifp) != 0) - (void) fputs(xcrypt(in_line), ofp); - - Fclose(ifp); + (void) fputs(xcrypt(in_line), tfp); + } + /* record the current position; false rumors will start here */ + false_rumor_offset = ftell(tfp); + Fclose(ifp); /* all done with rumors.tru */ + /* process rumors.fal */ Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE); Strcat(infile, ".fal"); - if (!(ifp = fopen(infile, -#ifdef WIN32 - RDBMODE -#else - RDTMODE -#endif - ))) { + if (!(ifp = fopen(infile, RDTMODE))) { perror(infile); - Fclose(ofp); - Unlink(filename); /* kill incomplete output file */ - exit(EXIT_FAILURE); + goto rumors_failure; } /* copy false rumors */ - while (fgets(in_line, sizeof in_line, ifp) != 0) - (void) fputs(xcrypt(in_line), ofp); + while (fgets(in_line, sizeof in_line, ifp) != 0) { + false_rumor_count++; + false_rumor_size += strlen(in_line); /* includes newline */ + (void) fputs(xcrypt(in_line), tfp); + } + /* record the current position; EOF available for sanity check */ + eof_offset = ftell(tfp); + Fclose(ifp); /* all done with rumors.fal */ - Fclose(ifp); + /* get ready to transfer the contents of temp file to output file */ + Sprintf(in_line, "rewind of \"%s\"", tempfile); + if (rewind(tfp) != 0) { + perror(in_line); + goto rumors_failure; + } + + /* output the header record */ + Fprintf(ofp, rumors_header, Dont_Edit_Data, + true_rumor_count, true_rumor_size, true_rumor_offset, + false_rumor_count, false_rumor_size, false_rumor_offset, + eof_offset); + /* skip the temp file's dummy header */ + if (!fgets(in_line, sizeof in_line, tfp) || /* "Don't Edit" */ + !fgets(in_line, sizeof in_line, tfp)) { /* count,size,offset */ + perror(tempfile); + goto rumors_failure; + } + /* copy the rest of the temp file into the final output file */ + while (fgets(in_line, sizeof in_line, tfp) != 0) { + (void) fputs(in_line, ofp); + } + /* all done; delete temp file */ + Fclose(tfp); + Unlink(tempfile); Fclose(ofp); return; + + rumors_failure: + Fclose(ofp); + Unlink(filename); /* kill empty or incomplete output file */ + Fclose(tfp); + Unlink(tempfile); /* and temporary file */ + exit(EXIT_FAILURE); } /*