Mercurial > hg > early-roguelike
view arogue7/rip.c @ 270:7a96fede6cc8
UltraRogue: check the return value from getpwuid().
It is possible for getpwuid() to return NULL. Such a failure will no
longer cause a segfault. However, the call to getpwuid() may normally
not be reachable.
author | John "Elwin" Edwards |
---|---|
date | Wed, 01 Mar 2017 20:40:18 -0500 |
parents | f9ef86cf22b2 |
children | d3968e9cb98d |
line wrap: on
line source
/* * rip.c - File for the fun ends Death or a total win * * Advanced Rogue * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T * All rights reserved. * * Based on "Rogue: Exploring the Dungeons of Doom" * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman * All rights reserved. * * See the file LICENSE.TXT for full copyright and licensing information. */ /* Print flags for scoring */ #define REALLIFE 1 /* Print out machine and logname */ #define EDITSCORE 2 /* Edit the current score file */ #define ADDSCORE 3 /* Add a new score */ #define NAMELEN 80 /* * File for the fun ends * Death or a total win * */ #include "curses.h" #ifdef BSD #include <sys/time.h> #else #include <time.h> #endif #include <signal.h> #include <ctype.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <fcntl.h> #include "mach_dep.h" #include "network.h" #include "rogue.h" #ifdef PC7300 #include "sys/window.h" extern struct uwdata wdata, oldwin; extern char oldtext[WTXTNUM][WTXTLEN]; #endif extern int scorefd; extern FILE *logfile; #ifdef NUMNET /* Network machines (for mutual score keeping) */ static struct network Network[NUMNET] = { { "ihwpt", "/t1/michael/bin/rg" }, }; #endif /* * If you change this structure, change the compatibility routines * scoreout() and scorein() to reflect the change. Also update SCORELEN. */ struct sc_ent { unsigned long sc_score; char sc_name[NAMELEN]; char sc_system[SYSLEN]; char sc_login[LOGLEN]; short sc_flags; short sc_level; short sc_ctype; short sc_monster; short sc_quest; }; #define SCORELEN \ (sizeof(unsigned long) + NAMELEN + SYSLEN + LOGLEN + 5*sizeof(short)) static char *rip[] = { " __________", " / \\", " / REST \\", " / IN \\", " / PEACE \\", " / \\", " | |", " | |", " | killed by |", " | |", " | 1984 |", " *| * * * | *", " ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______", 0 }; char *killname(short monst); void showpack(char *howso); int update(struct sc_ent top_ten[], unsigned long amount, short quest, char *whoami, short flags, short level, short monst, short ctype, char *system, char *login); void byebye(int sig) { if (!isendwin()) { clear(); endwin(); } #ifdef PC7300 endhardwin(); #endif printf("\n"); exit(0); } /* * death: * Do something really fun when he dies */ void death(short monst) { register char **dp = rip, *killer; register struct tm *lt; time_t date; char buf[LINELEN]; struct tm *localtime(); time(&date); lt = localtime(&date); clear(); move(8, 0); while (*dp) printw("%s\n", *dp++); mvaddstr(14, 28-((strlen(whoami)+1)/2), whoami); sprintf(buf, "%lu Points", pstats.s_exp ); mvaddstr(15, 28-((strlen(buf)+1)/2), buf); killer = killname(monst); mvaddstr(17, 28-((strlen(killer)+1)/2), killer); mvaddstr(18, 26, (sprintf(prbuf, "%4d", 1900+lt->tm_year), prbuf)); move(lines-1, 0); refresh(); writelog(pstats.s_exp, KILLED, monst); score(pstats.s_exp, KILLED, monst); endwin(); #ifdef PC7300 endhardwin(); #endif exit(0); } #ifdef PC7300 /* * Restore window characteristics on a hard window terminal (PC7300). */ void endhardwin(void) { register int i; struct utdata labelbuf; /* Restore the old window size */ if (oldwin.uw_width) ioctl(1, WIOCSETD, &oldwin); /* Restore the old window text */ for (i=0; i<WTXTNUM; i++) { labelbuf.ut_num = i; strcpy(labelbuf.ut_text, oldtext[i]); ioctl(1, WIOCSETTEXT, &labelbuf); } } #endif char * killname(short monst) { static char mons_name[LINELEN]; int i; if (monst > NUMMONST) return("a strange monster"); if (monst >= 0) { switch (monsters[monst].m_name[0]) { case 'a': case 'e': case 'i': case 'o': case 'u': sprintf(mons_name, "an %s", monsters[monst].m_name); break; default: sprintf(mons_name, "a %s", monsters[monst].m_name); } return(mons_name); } for (i = 0; i< DEATHNUM; i++) { if (deaths[i].reason == monst) break; } if (i >= DEATHNUM) return ("strange death"); return (deaths[i].name); } /* Writes an entry in the log file */ void writelog(unsigned long amount, int flags, short monst) { char had_quest = '0'; char fate[LINELEN]; struct linked_list *item; struct object *obj; #ifdef LOGFILE if (waswizard) return; if (logfile == NULL) return; /* Check for quest item */ for (item = pack; item != NULL; item = next(item)) { obj = OBJPTR(item); if (obj->o_type == RELIC && obj->o_which == quest_item) had_quest = '1'; } /* Describe what happened */ if (flags == KILLED) { snprintf(fate, LINELEN, "killed by %s", killname(monst)); } else if (flags == CHICKEN) { strcpy(fate, "quit"); } else if (flags == WINNER) { strcpy(fate, "escaped"); } else return; /* Write */ fprintf(logfile, "%d %d %s %d %s %d %d %d %c %s\n", time(NULL), amount, whoami, pstats.s_lvl, char_class[char_type].name, level, max_level, quest_item, had_quest, fate); fclose(logfile); #endif return; } /* * score -- figure score and post it. */ /* VARARGS2 */ void score(unsigned long amount, int flags, short monst) { static struct sc_ent top_ten[NUMSCORE]; register struct sc_ent *scp; register int i; register struct sc_ent *sc2; register int outfd; register char *killer; register int prflags = 0; register int fd; short upquest, wintype, uplevel, uptype; /* For network updating */ char upsystem[SYSLEN], uplogin[LOGLEN]; char *thissys; /* Holds the name of this system */ char *compatstr=NULL; /* Holds scores for writing compatible score files */ char scoreline[100]; #define REASONLEN 3 static char *reason[] = { "killed", "quit", "A total winner", "somehow left", }; char *packend; signal(SIGINT, byebye); if (flags != WINNER && flags != SCOREIT && flags != UPDATE) { if (flags == CHICKEN) packend = "when you quit"; else { packend = "at your untimely demise"; mvaddstr(lines - 1, 0, retstr); refresh(); getstr(prbuf); } showpack(packend); } purse = 0; /* Steal all the gold */ /* * Open file and read list */ if ((fd = scorefd) < 0) return; outfd = fd; #ifndef SYSTEM thissys = md_gethostname(); #else thissys = SYSTEM; #endif for (scp = top_ten; scp <= &top_ten[NUMSCORE-1]; scp++) { scp->sc_score = 0L; for (i = 0; i < NAMELEN; i++) scp->sc_name[i] = rnd(255); scp->sc_quest= RN; scp->sc_flags = RN; scp->sc_level = RN; scp->sc_monster = RN; scp->sc_ctype = 0; strncpy(scp->sc_system, thissys, SYSLEN); scp->sc_login[0] = '\0'; } /* * If this is a SCOREIT optin (rogue -s), don't call byebye. The * endwin() call in byebye() will result in a core dump. */ if (flags == SCOREIT) signal(SIGINT, SIG_DFL); else signal(SIGINT, byebye); if (flags != SCOREIT && flags != UPDATE) { mvaddstr(lines - 1, 0, retstr); refresh(); fflush(stdout); getstr(prbuf); } /* Check for special options */ if (strcmp(prbuf, "names") == 0) prflags = REALLIFE; #ifdef WIZARD else if (wizard) { if (strcmp(prbuf, "edit") == 0) prflags = EDITSCORE; else if (strcmp(prbuf, "add") == 0) { prflags = ADDSCORE; waswizard = FALSE; /* We want the new score recorded */ } } #endif /* Read the score and convert it to a compatible format */ for(i = 0; i < NUMSCORE; i++) { encread(top_ten[i].sc_name, NAMELEN, fd); encread(top_ten[i].sc_system, SYSLEN, fd); encread(top_ten[i].sc_login, LOGLEN, fd); encread(scoreline, 100, fd); sscanf(scoreline, " %lu %hd %hd %hd %hd %hd \n", &top_ten[i].sc_score, &top_ten[i].sc_flags, &top_ten[i].sc_level, &top_ten[i].sc_ctype, &top_ten[i].sc_monster, &top_ten[i].sc_quest ); } /* Get some values if this is an update */ if (flags == UPDATE) { unsigned long netread(); int errcheck, errors = 0; upquest = (short) netread(&errcheck, sizeof(short), stdin); if (errcheck) errors++; if (fread(whoami, 1, NAMELEN, stdin) != NAMELEN) errors++; wintype = (short) netread(&errcheck, sizeof(short), stdin); if (errcheck) errors++; uplevel = (short) netread(&errcheck, sizeof(short), stdin); if (errcheck) errors++; uptype = (short) netread(&errcheck, sizeof(short), stdin); if (errcheck) errors++; if (fread(upsystem, 1, SYSLEN, stdin) != SYSLEN) errors++; if (fread(uplogin, 1, LOGLEN, stdin) != LOGLEN) errors++; if (errors) { close(outfd); free(compatstr); return; } } /* * Insert player in list if need be */ if (!waswizard) { char *login = ""; if (flags != UPDATE) { login = md_getusername(); } if (flags == UPDATE) (void) update(top_ten, amount, upquest, whoami, wintype, uplevel, monst, uptype, upsystem, uplogin); else { #ifdef WIZARD if (prflags == ADDSCORE) { /* Overlay characteristic by new ones */ char buffer[LINELEN]; clear(); mvaddstr(1, 0, "Score: "); mvaddstr(2, 0, "Quest (number): "); mvaddstr(3, 0, "Name: "); mvaddstr(4, 0, "System: "); mvaddstr(5, 0, "Login: "); mvaddstr(6, 0, "Level: "); mvaddstr(7, 0, "Char type: "); mvaddstr(8, 0, "Result: "); /* Get the score */ move(1, 7); get_str(buffer, stdscr); amount = atol(buffer); /* Get the character's quest -- must be a number */ move(2, 16); get_str(buffer, stdscr); quest_item = atoi(buffer); /* Get the character's name */ move(3, 6); get_str(buffer, stdscr); strncpy(whoami, buffer, NAMELEN); /* Get the system */ move(4, 8); get_str(buffer, stdscr); strncpy(thissys, buffer, SYSLEN); /* Get the login */ move(5, 7); get_str(buffer, stdscr); strncpy(login, buffer, LOGLEN); /* Get the level */ move(6, 7); get_str(buffer, stdscr); level = max_level = (short) atoi(buffer); /* Get the character type */ move(7, 11); get_str(buffer, stdscr); for (i=0; i<NUM_CHARTYPES; i++) { if (EQSTR(buffer, char_class[i].name, strlen(buffer))) break; } player.t_ctype = i; /* Get the win type */ move(8, 8); get_str(buffer, stdscr); switch (buffer[0]) { case 'W': case 'w': case 'T': case 't': flags = WINNER; break; case 'Q': case 'q': flags = CHICKEN; break; case 'k': case 'K': default: flags = KILLED; break; } /* Get the monster if player was killed */ if (flags == KILLED) { mvaddstr(9, 0, "Death type: "); get_str(buffer, stdscr); if (buffer[0] == 'M' || buffer[0] == 'm') do { monst = makemonster(TRUE, "Editing", "choose"); } while (monst < 0); /* Force a choice */ else monst = getdeath(); } } #endif if (update(top_ten, amount, (short) quest_item, whoami, flags, (flags == WINNER) ? (short) max_level : (short) level, monst, player.t_ctype, thissys, login) #ifdef NUMNET && fork() == 0 /* Spin off network process */ #endif ) { #ifdef NUMNET /* Send this update to the other systems in the network */ int i, j; char cmd[256]; /* Command for remote execution */ FILE *rmf, *popen(); /* For input to remote command */ for (i=0; i<NUMNET; i++) if (Network[i].system[0] != '!' && strcmp(Network[i].system, thissys)) { sprintf(cmd, NETCOMMAND, Network[i].system, Network[i].rogue); /* Execute the command */ if ((rmf=popen(cmd, "w")) != NULL) { unsigned long temp; /* Temporary value */ /* Write out the parameters */ (void) netwrite((unsigned long) amount, sizeof(unsigned long), rmf); (void) netwrite((unsigned long) monst, sizeof(short), rmf); (void) netwrite((unsigned long) quest_item, sizeof(short), rmf); (void) fwrite(whoami, 1, strlen(whoami), rmf); for (j=strlen(whoami); j<NAMELEN; j++) putc('\0', rmf); (void) netwrite((unsigned long) flags, sizeof(short), rmf); temp = (unsigned long) (flags==WINNER ? max_level : level); (void) netwrite(temp, sizeof(short), rmf); (void) netwrite((unsigned long) player.t_ctype, sizeof(short), rmf); (void) fwrite(thissys, 1, strlen(thissys), rmf); for (j=strlen(thissys); j<SYSLEN; j++) putc('\0', rmf); (void) fwrite(login, 1, strlen(login), rmf); for (j=strlen(login); j<LOGLEN; j++) putc('\0', rmf); /* Close off the command */ (void) pclose(rmf); } } _exit(0); /* Exit network process */ #endif } } } /* * SCOREIT -- rogue -s option. Never started curses if this option. * UPDATE -- network scoring update. Never started curses if this option. * EDITSCORE -- want to delete or change a score. */ /* if (flags != SCOREIT && flags != UPDATE && prflags != EDITSCORE) endwin(); */ if (flags != UPDATE) { if (flags != SCOREIT) { clear(); refresh(); endwin(); } /* * Print the list */ printf("\nTop %d Adventurers:\nRank Score\tName\n", NUMSCORE); for (scp = top_ten; scp <= &top_ten[NUMSCORE-1]; scp++) { const char *class; if (scp->sc_score != 0) { class = char_class[scp->sc_ctype].name; /* Make sure we have an in-bound reason */ if (scp->sc_flags > REASONLEN) scp->sc_flags = REASONLEN; printf("%3d %10lu\t%s (%s)", scp - top_ten + 1, scp->sc_score, scp->sc_name, class); if (prflags == REALLIFE) printf(" [in real life %.*s!%.*s]", SYSLEN, scp->sc_system, LOGLEN, scp->sc_login); printf(":\n\t\t%s on level %d", reason[scp->sc_flags], scp->sc_level); switch (scp->sc_flags) { case KILLED: printf(" by"); killer = killname(scp->sc_monster); printf(" %s", killer); break; case WINNER: printf(" with the %s", rel_magic[scp->sc_quest].mi_name); break; } if (prflags == EDITSCORE) { fflush(stdout); getstr(prbuf); printf("\n"); if (prbuf[0] == 'd') { for (sc2 = scp; sc2 < &top_ten[NUMSCORE-1]; sc2++) *sc2 = *(sc2 + 1); top_ten[NUMSCORE-1].sc_score = 0; for (i = 0; i < NAMELEN; i++) top_ten[NUMSCORE-1].sc_name[i] = rnd(255); top_ten[NUMSCORE-1].sc_flags = RN; top_ten[NUMSCORE-1].sc_level = RN; top_ten[NUMSCORE-1].sc_monster = RN; scp--; } else if (prbuf[0] == 'e') { printf("Death type: "); getstr(prbuf); if (prbuf[0] == 'M' || prbuf[0] == 'm') do { scp->sc_monster = makemonster(TRUE, "Editing", "choose"); } while (scp->sc_monster < 0); /* Force a choice */ else scp->sc_monster = getdeath(); clear(); refresh(); } } else printf("\n"); } } if ((flags != SCOREIT) && (flags != UPDATE)) { printf("\n[Press return to exit]"); fflush(stdout); fgets(prbuf,80,stdin); } /* if (prflags == EDITSCORE) endwin();*/ /* End editing windowing */ } lseek(outfd, 0L, 0); /* * Update the list file */ for(i = 0; i < NUMSCORE; i++) { memset(scoreline,0,100); encwrite(top_ten[i].sc_name, NAMELEN, outfd); encwrite(top_ten[i].sc_system, SYSLEN, outfd); encwrite(top_ten[i].sc_login, LOGLEN, outfd); sprintf(scoreline, " %lu %hd %hd %hd %hd %hd \n", top_ten[i].sc_score, top_ten[i].sc_flags, top_ten[i].sc_level, top_ten[i].sc_ctype, top_ten[i].sc_monster, top_ten[i].sc_quest); encwrite(scoreline,100,outfd); } close(outfd); } /* * scorein: * Convert a character string that has been translated from a * score file by scoreout() back to a score file structure. * num_bytes: Number of bytes of input that we want to convert */ void scorein(unsigned char *input, struct sc_ent scores[], int num_bytes) { register int i, j; unsigned long *lptr; unsigned short *sptr; unsigned char *cptr; /* Convert a maximum of NUMSCORE entries */ for (i=0; num_bytes > 0 && i < NUMSCORE; num_bytes -= SCORELEN, i++) { /* The long fields are first -- ordered low to high byte in input */ lptr = &scores[i].sc_score; *lptr = ((unsigned long) *input++) & 0x000000ffL; *lptr |= (((unsigned long) *input++) << 8) & 0x0000ff00L; *lptr |= (((unsigned long) *input++) << 16) & 0x00ff0000L; *lptr |= (((unsigned long) *input++) << 24) & 0xff000000L; /* The short fields are next -- ordered low to high byte in input */ sptr = (unsigned short *) &scores[i].sc_flags; *sptr = ((unsigned short) *input++) & 0xff; *sptr |= (((unsigned short) *input++) << 8) & 0xff00; sptr = (unsigned short *) &scores[i].sc_level; *sptr = ((unsigned short) *input++) & 0xff; *sptr |= (((unsigned short) *input++) << 8) & 0xff00; sptr = (unsigned short *) &scores[i].sc_ctype; *sptr = ((unsigned short) *input++) & 0xff; *sptr |= (((unsigned short) *input++) << 8) & 0xff00; sptr = (unsigned short *) &scores[i].sc_monster; *sptr = ((unsigned short) *input++) & 0xff; *sptr |= (((unsigned short) *input++) << 8) & 0xff00; sptr = (unsigned short *) &scores[i].sc_quest; *sptr = ((unsigned short) *input++) & 0xff; *sptr |= (((unsigned short) *input++) << 8) & 0xff00; /* Finally comes the char fields -- they're easy */ cptr = (unsigned char *) scores[i].sc_name; for (j = 0; j < NAMELEN; j++) *cptr++ = *input++; cptr = (unsigned char *) scores[i].sc_system; for (j = 0; j < SYSLEN; j++) *cptr++ = *input++; cptr = (unsigned char *) scores[i].sc_login; for (j = 0; j < LOGLEN; j++) *cptr++ = *input++; } } /* * scoreout: * Convert a score file structure to a character string. We do * this for compatibility sake since some machines write out fields in * different orders. */ void scoreout(struct sc_ent scores[], unsigned char *output) { register int i, j; unsigned long *lptr; unsigned short *sptr; unsigned char *cptr; for (i=0; i<NUMSCORE; i++) { /* The long fields are first -- ordered low to high byte in input */ lptr = &scores[i].sc_score; for (j = 0; j < sizeof(unsigned long); j++) *output++ = (unsigned char) ((*lptr >> 8*j) & 0xff); /* The short fields are next -- ordered low to high byte in input */ sptr = (unsigned short *) &scores[i].sc_flags; *output++ = (unsigned char) (*sptr & 0xff); *output++ = (unsigned char) ((*sptr >> 8) & 0xff); sptr = (unsigned short *) &scores[i].sc_level; *output++ = (unsigned char) (*sptr & 0xff); *output++ = (unsigned char) ((*sptr >> 8) & 0xff); sptr = (unsigned short *) &scores[i].sc_ctype; *output++ = (unsigned char) (*sptr & 0xff); *output++ = (unsigned char) ((*sptr >> 8) & 0xff); sptr = (unsigned short *) &scores[i].sc_monster; *output++ = (unsigned char) (*sptr & 0xff); *output++ = (unsigned char) ((*sptr >> 8) & 0xff); sptr = (unsigned short *) &scores[i].sc_quest; *output++ = (unsigned char) (*sptr & 0xff); *output++ = (unsigned char) ((*sptr >> 8) & 0xff); /* Finally comes the char fields -- they're easy */ cptr = (unsigned char *) scores[i].sc_name; for (j = 0; j < NAMELEN; j++) *output++ = *cptr++; cptr = (unsigned char *) scores[i].sc_system; for (j = 0; j < SYSLEN; j++) *output++ = *cptr++; cptr = (unsigned char *) scores[i].sc_login; for (j = 0; j < LOGLEN; j++) *output++ = *cptr++; } } /* * showpack: * Display the contents of the hero's pack */ void showpack(char *howso) { reg char *iname; reg int cnt, packnum; reg struct linked_list *item; reg struct object *obj; idenpack(); cnt = 1; clear(); mvprintw(0, 0, "Contents of your pack %s:\n",howso); packnum = 'a'; for (item = pack; item != NULL; item = next(item)) { obj = OBJPTR(item); iname = inv_name(obj, FALSE); mvprintw(cnt, 0, "%c) %s\n",packnum++,iname); if (++cnt >= lines - 2 && next(item) != NULL) { cnt = 1; mvaddstr(lines - 1, 0, morestr); refresh(); wait_for(' '); clear(); } } mvprintw(cnt + 1,0,"--- %d Gold Pieces ---",purse); refresh(); } void total_winner(void) { register struct linked_list *item; register struct object *obj; register int worth; register char c; register int oldpurse; clear(); standout(); addstr(" \n"); addstr(" @ @ @ @ @ @@@ @ @ \n"); addstr(" @ @ @@ @@ @ @ @ @ \n"); addstr(" @ @ @@@ @ @ @ @ @ @@@ @@@@ @@@ @ @@@ @ \n"); addstr(" @@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ \n"); addstr(" @ @ @ @ @ @ @ @@@@ @ @ @@@@@ @ @ @ \n"); addstr(" @ @ @ @ @ @@ @ @ @ @ @ @ @ @ @ @ \n"); addstr(" @@@ @@@ @@ @ @ @ @@@@ @@@@ @@@ @@@ @@ @ \n"); addstr(" \n"); addstr(" Congratulations, you have made it to the light of day! \n"); standend(); addstr("\nYou have joined the elite ranks of those who have escaped the\n"); addstr("Dungeons of Doom alive. You journey home and sell all your loot at\n"); addstr("a great profit and are appointed leader of a "); switch (player.t_ctype) { case C_MAGICIAN:addstr("magician's guild.\n"); when C_FIGHTER: addstr("fighter's guild.\n"); when C_RANGER: addstr("ranger's guild.\n"); when C_CLERIC: addstr("monastery.\n"); when C_PALADIN: addstr("monastery.\n"); when C_MONK: addstr("monastery.\n"); when C_DRUID: addstr("monastery.\n"); when C_THIEF: addstr("thief's guild.\n"); when C_ASSASIN: addstr("assassin's guild.\n"); otherwise: addstr("tavern.\n"); } mvaddstr(lines - 1, 0, spacemsg); refresh(); wait_for(' '); clear(); mvaddstr(0, 0, " Worth Item"); oldpurse = purse; for (c = 'a', item = pack; item != NULL; c++, item = next(item)) { obj = OBJPTR(item); worth = get_worth(obj); if (obj->o_group == 0)