MCPcopy Create free account
hub / github.com/NetHack/NetHack / get_rnd_line

Function get_rnd_line

src/rumors.c:419–494  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

417 more likely than average to be picked, and lines after short lines
418 are less likely */
419staticfn char *
420get_rnd_line(
421 dlb *fh, /* already opened file */
422 char *buf, /* output buffer */
423 unsigned bufsiz, /* (unsigned) sizeof buf */
424 int (*rng)(int), /* random number routine; rn2(N) or similar, 0..N-1 */
425 long startpos, /* location in file of first line of interest */
426 long endpos, /* location one byte past last line of interest;
427 * if 0, end-of-file will be used */
428 unsigned padlength) /* expected line length; 0 if no expectations */
429{
430 char *newl, *xbufp, xbuf[BUFSZ];
431 long filechunksize, chunkoffset;
432 int trylimit;
433
434 *buf = '\0';
435 if (!endpos) {
436 (void) dlb_fseek(fh, 0L, SEEK_END);
437 endpos = dlb_ftell(fh);
438 }
439 filechunksize = endpos - startpos;
440
441 /* might be zero (only if file is empty); should complain in that
442 case but it could happen over and over, also the suggestion
443 that save and restore might fix the problem wouldn't be useful */
444 if (filechunksize < 1L)
445 return buf;
446 /* 'rumors' is about 3/4 of the way to the limit on a 16-bit config
447 for the whole, roughly 3/8 of the way for either half; all active
448 configurations these days are at least 32-bits anyway */
449 nhassert(filechunksize <= INT_MAX); /* essential for rn2() */
450
451 /*
452 * Position randomly which will probably be in the middle of a line.
453 * (Occasionally by chance it will happen to be at the very start of
454 * a line, but we'll have no way of knowing that so have to behave
455 * as if it were positioned in the middle.)
456 * Read the rest of that line, then use the next one. If there's no
457 * next line (ie, end of file), go back to beginning and use first.
458 *
459 * When short lines have been padded to length N, only accept long
460 * lines if we land within last N+1 characters (+1 is for newline
461 * which hasn't been stripped away yet), effectively shortening
462 * them to normal length. That yields even selection distribution.
463 */
464 for (trylimit = 10; trylimit > 0; --trylimit) {
465 chunkoffset = (long) (*rng)((int) filechunksize);
466 (void) dlb_fseek(fh, startpos + chunkoffset, SEEK_SET);
467 (void) dlb_fgets(buf, bufsiz, fh);
468 /* if padlength is 0, accept any position; when non-zero,
469 padlength does not count the newline but strlen(buf) does */
470 if (!padlength || (unsigned) strlen(buf) <= padlength + 1)
471 break;
472 }
473 /* use next line; for rumors, caller takes care of whether startpos
474 and endpos cover just true rumors or just false rumors; reaching
475 endpos is equivalent to end-of-file in order to avoid using the
476 first false rumor if fseek for a true one lands within the last one */

Callers 2

getrumorFunction · 0.85
get_rnd_textFunction · 0.85

Calls 6

dlb_fseekFunction · 0.85
dlb_ftellFunction · 0.85
dlb_fgetsFunction · 0.85
xcryptFunction · 0.85
unpadlineFunction · 0.85
allocFunction · 0.70

Tested by

no test coverage detected