if ((op = string_for_opt(opts, FALSE)) == empty_optstr)
return optn_err;
+ /* 3.7: earlier versions left old values for unspecified arguments
+ if player's scores:foo option only specified some of the three;
+ in particular, attempting to use 'scores:own' rather than
+ 'scores:0 top/0 around/own' didn't work as intended */
+ flags.end_top = flags.end_around = 0, flags.end_own = FALSE;
+
+ if (negated)
+ op = eos(op);
+
while (*op) {
int inum = 1;
+ negated = (*op == '!');
+ if (negated)
+ op++;
+
if (digit(*op)) {
inum = atoi(op);
while (digit(*op))
op++;
- } else if (*op == '!') {
- negated = !negated;
- op++;
}
while (*op == ' ')
op++;
- switch (*op) {
+ switch (lowc(*op)) {
case 't':
- case 'T':
- flags.end_top = inum;
+ flags.end_top = negated ? 0 : inum;
break;
case 'a':
- case 'A':
- flags.end_around = inum;
+ flags.end_around = negated ? 0 : inum;
break;
case 'o':
- case 'O':
- flags.end_own = !negated;
+ flags.end_own = (negated || !inum) ? FALSE : TRUE;
break;
+ case 'n': /* none */
+ flags.end_top = flags.end_around = 0, flags.end_own = FALSE;
+ break;
+ case '-':
+ if (digit(*(op + 1))) {
+ config_error_add(
+ "Values for %s:top and %s:around must not be negative",
+ allopt[optidx].name,
+ allopt[optidx].name);
+ return optn_silenterr;
+ }
+ /*FALLTHRU*/
default:
config_error_add("Unknown %s parameter '%s'",
allopt[optidx].name, op);
- return optn_err;
+ return optn_silenterr;
}
- /* "3a" is sufficient but accept "3around" (or "3abracadabra")
- */
+ /* "3a" is sufficient but accept "3around" (or "3abracadabra") */
while (letter(*op))
op++;
- /* t, a, and o can be separated by space(s) or slash or both
- */
+ /* t, a, and o can be separated by space(s) or slash or both */
while (*op == ' ')
op++;
if (*op == '/')
if (req == get_val) {
if (!opts)
return optn_err;
- Sprintf(opts, "%d top/%d around%s", flags.end_top, flags.end_around,
- flags.end_own ? "/own" : "");
+ *opts = '\0';
+ if (flags.end_top > 0)
+ Sprintf(opts, "%d top", flags.end_top);
+ if (flags.end_around > 0)
+ Sprintf(eos(opts), "%s%d around",
+ (flags.end_top > 0) ? "/" : "", flags.end_around);
+ if (flags.end_own)
+ Sprintf(eos(opts), "%sown",
+ (flags.end_top > 0 || flags.end_around > 0) ? "/" : "");
+ if (!*opts)
+ Strcpy(opts, "none");
return optn_ok;
}
return optn_ok;
char plalign[ROLESZ + 1];
char name[NAMSZ + 1];
char death[DTHSZ + 1];
-} * tt_head;
+} *tt_head;
/* size big enough to read in all the string fields at once; includes
room for separating space or trailing newline plus string terminator */
#define SCANBUFSZ (4 * (ROLESZ + 1) + (NAMSZ + 1) + (DTHSZ + 1) + 1)
+static struct toptenentry zerott;
+
static void topten_print(const char *);
static void topten_print_bold(const char *);
static void outheader(void);
}
static void
-topten_print_bold(const char* x)
+topten_print_bold(const char *x)
{
if (g.toptenwin == WIN_ERR)
raw_print_bold(x);
void
topten(int how, time_t when)
{
- int uid = getuid();
- int rank, rank0 = -1, rank1 = 0;
- int occ_cnt = sysopt.persmax;
register struct toptenentry *t0, *tprev;
struct toptenentry *t1;
FILE *rfile;
- register int flg = 0;
- boolean t0_used;
#ifdef LOGFILE
FILE *lfile;
-#endif /* LOGFILE */
+#endif
#ifdef XLOGFILE
FILE *xlfile;
-#endif /* XLOGFILE */
-
-#ifdef _DCC
- /* Under DICE 3.0, this crashes the system consistently, apparently due to
- * corruption of *rfile somewhere. Until I figure this out, just cut out
- * topten support entirely - at least then the game exits cleanly. --AC
- */
- return;
#endif
+ int uid = getuid();
+ int rank, rank0 = -1, rank1 = 0;
+ int occ_cnt = sysopt.persmax;
+ int flg = 0;
+ boolean t0_used, skip_scores;
/* If we are in the midst of a panic, cut out topten entirely.
* topten uses alloc() several times, which will lead to
/* create a new 'topten' entry */
t0_used = FALSE;
t0 = newttentry();
+ *t0 = zerott;
t0->ver_major = VERSION_MAJOR;
t0->ver_minor = VERSION_MINOR;
t0->patchlevel = PATCHLEVEL;
t1 = tt_head = newttentry();
tprev = 0;
/* rank0: -1 undefined, 0 not_on_list, n n_th on list */
- for (rank = 1;;) {
+ for (rank = 1; ; ) {
readentry(rfile, t1);
if (t1->points < sysopt.pointsmin)
t1->points = 0;
char pbuf[BUFSZ];
Sprintf(pbuf,
- "You didn't beat your previous score of %ld points.",
+ "You didn't beat your previous score of %ld points.",
t1->points);
topten_print(pbuf);
topten_print("");
topten_print("");
}
}
+ skip_scores = !flags.end_top && !flags.end_around && !flags.end_own;
if (rank0 == 0)
rank0 = rank1;
if (rank0 <= 0)
rank0 = rank;
- if (!done_stopprint)
+ if (!skip_scores && !done_stopprint)
outheader();
- t1 = tt_head;
- for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
+ for (t1 = tt_head, rank = 1; t1->points != 0; t1 = t1->tt_next, ++rank) {
if (flg
#ifdef UPDATE_RECORD_IN_PLACE
&& rank >= rank0
#endif
)
writeentry(rfile, t1);
- if (done_stopprint)
- continue;
- if (rank > flags.end_top && (rank < rank0 - flags.end_around
- || rank > rank0 + flags.end_around)
- && (!flags.end_own
- || (sysopt.pers_is_uid
- ? t1->uid == t0->uid
- : strncmp(t1->name, t0->name, NAMSZ) == 0)))
+ if (skip_scores || done_stopprint)
continue;
- if (rank == rank0 - flags.end_around
- && rank0 > flags.end_top + flags.end_around + 1 && !flags.end_own)
- topten_print("");
- if (rank != rank0)
- outentry(rank, t1, FALSE);
- else if (!rank1)
- outentry(rank, t1, TRUE);
- else {
- outentry(rank, t1, TRUE);
- outentry(0, t0, TRUE);
+ if (rank <= flags.end_top
+ || (rank >= rank0 - flags.end_around
+ && rank <= rank0 + flags.end_around)
+ || (flags.end_own && (sysopt.pers_is_uid
+ ? t1->uid == t0->uid
+ : !strncmp(t1->name, t0->name, NAMSZ)))) {
+ if (rank == rank0 - flags.end_around
+ && rank0 > flags.end_top + flags.end_around + 1
+ && !flags.end_own)
+ topten_print("");
+
+ if (rank != rank0) {
+ outentry(rank, t1, FALSE);
+ } else if (!rank1) {
+ outentry(rank, t1, TRUE);
+ } else {
+ outentry(rank, t1, TRUE);
+ outentry(0, t0, TRUE);
+ }
}
}
if (rank0 >= rank)
- if (!done_stopprint)
+ if (!skip_scores && !done_stopprint)
outentry(0, t0, TRUE);
#ifdef UPDATE_RECORD_IN_PLACE
if (flg) {
truncate_file(rfile);
#else
/* use sentinel record rather than relying on truncation */
- t1->points = 0L; /* terminates file when read back in */
- t1->ver_major = t1->ver_minor = t1->patchlevel = 0;
- t1->uid = t1->deathdnum = t1->deathlev = 0;
- t1->maxlvl = t1->hp = t1->maxhp = t1->deaths = 0;
+ *t1 = zerott;
+ t1->points = 0L; /* [redundant] terminates file when read back in */
t1->plrole[0] = t1->plrace[0] = t1->plgend[0] = t1->plalign[0] = '-';
- t1->plrole[1] = t1->plrace[1] = t1->plgend[1] = t1->plalign[1] = 0;
t1->birthdate = t1->deathdate = yyyymmdd((time_t) 0L);
Strcpy(t1->name, "@");
- Strcpy(t1->death, "<eod>\n");
+ Strcpy(t1->death, "<eod>\n"); /* end of data */
writeentry(rfile, t1);
+ /* note: there might be junk (if file has shrunk due to shorter
+ entries supplanting longer ones) after this dummy entry, but
+ reading and/or updating will ignore it */
(void) fflush(rfile);
#endif /* TRUNCATE_FILE */
}
unlock_file(RECORD);
free_ttlist(tt_head);
-showwin:
+ showwin:
if (iflags.toptenwin && !done_stopprint)
display_nhwindow(g.toptenwin, 1);
-destroywin:
+ destroywin:
if (!t0_used)
dealloc_ttentry(t0);
if (iflags.toptenwin) {
tt = &tt_buf;
rank = rnd(sysopt.tt_oname_maxrank);
-pickentry:
+ pickentry:
for (i = rank; i; i--) {
readentry(rfile, tt);
if (tt->points == 0)