Subject: Re: bin/34750: string handling cleanup for rogue(6)
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org,>
From: David Holland <dholland@eecs.harvard.edu>
List: netbsd-bugs
Date: 12/27/2007 23:20:04
The following reply was made to PR bin/34750; it has been noted by GNATS.

From: David Holland <dholland@eecs.harvard.edu>
To: gnats-bugs@NetBSD.org
Cc: gnats-admin@netbsd.org, netbsd-bugs@netbsd.org,
	dholland@eecs.harvard.edu
Subject: Re: bin/34750: string handling cleanup for rogue(6)
Date: Thu, 27 Dec 2007 18:16:40 -0500

  > [rogue patches from a long time ago]
 
 Here's an updated patch against HEAD. I'm now in a position to commit
 this if it's ok, so just give me the word...
 
 Index: hit.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/hit.c,v
 retrieving revision 1.7
 diff -u -p -r1.7 hit.c
 --- hit.c	7 Aug 2003 09:37:37 -0000	1.7
 +++ hit.c	27 Dec 2007 22:51:55 -0000
 @@ -56,7 +56,7 @@ __RCSID("$NetBSD: hit.c,v 1.7 2003/08/07
  #include "rogue.h"
  
  object *fight_monster = 0;
 -char hit_message[80] = "";
 +char hit_message[HIT_MESSAGE_SIZE] = "";
  
  void
  mon_hit(monster)
 @@ -86,16 +86,13 @@ mon_hit(monster)
  
  	if (!rand_percent(hit_chance)) {
  		if (!fight_monster) {
 -			sprintf(hit_message + strlen(hit_message),
 -			    "the %s misses", mn);
 -			message(hit_message, 1);
 +			messagef(1, "%sthe %s misses", hit_message, mn);
  			hit_message[0] = 0;
  		}
  		return;
  	}
  	if (!fight_monster) {
 -		sprintf(hit_message + strlen(hit_message), "the %s hit", mn);
 -		message(hit_message, 1);
 +		messagef(1, "%sthe %s hit", hit_message, mn);
  		hit_message[0] = 0;
  	}
  	if (!(monster->m_flags & STATIONARY)) {
 @@ -139,7 +136,8 @@ rogue_hit(monster, force_hit)
  		}
  		if (!rand_percent(hit_chance)) {
  			if (!fight_monster) {
 -				(void) strcpy(hit_message, "you miss  ");
 +				(void) strlcpy(hit_message, "you miss  ",
 +					       sizeof(hit_message));
  			}
  			goto RET;
  		}
 @@ -152,7 +150,8 @@ rogue_hit(monster, force_hit)
  		}
  		if (mon_damage(monster, damage)) {	/* still alive? */
  			if (!fight_monster) {
 -				(void) strcpy(hit_message, "you hit  ");
 +				(void) strlcpy(hit_message, "you hit  ",
 +					       sizeof(hit_message));
  			}
  		}
  RET:	check_gold_seeker(monster);
 @@ -186,9 +185,20 @@ get_damage(ds, r)
  
  	while (ds[i]) {
  		n = get_number(ds+i);
 -		while (ds[i++] != 'd') ;
 +		while ((ds[i] != 'd') && ds[i]) {
 +			i++;
 +		}
 +		if (ds[i] == 'd') {
 +			i++;
 +		}
 +
  		d = get_number(ds+i);
 -		while ((ds[i] != '/') && ds[i]) i++;
 +		while ((ds[i] != '/') && ds[i]) {
 +			i++;
 +		}
 +		if (ds[i] == '/') {
 +			i++;
 +		}
  
  		for (j = 0; j < n; j++) {
  			if (r) {
 @@ -197,9 +207,6 @@ get_damage(ds, r)
  				total += d;
  			}
  		}
 -		if (ds[i] == '/') {
 -			i++;
 -		}
  	}
  	return(total);
  }
 @@ -208,7 +215,7 @@ int
  get_w_damage(obj)
  	const object *obj;
  {
 -	char new_damage[12];
 +	char new_damage[32];
  	int tmp_to_hit, tmp_damage;
  	int i = 0;
  
 @@ -216,10 +223,16 @@ get_w_damage(obj)
  		return(-1);
  	}
  	tmp_to_hit = get_number(obj->damage) + obj->hit_enchant;
 -	while (obj->damage[i++] != 'd') ;
 +	while ((obj->damage[i] != 'd') && obj->damage[i]) {
 +		i++;
 +	}
 +	if (obj->damage[i] == 'd') {
 +		i++;
 +	}
  	tmp_damage = get_number(obj->damage + i) + obj->d_enchant;
  
 -	sprintf(new_damage, "%dd%d", tmp_to_hit, tmp_damage);
 +	snprintf(new_damage, sizeof(new_damage), "%dd%d", 
 +		tmp_to_hit, tmp_damage);
  
  	return(get_damage(new_damage, 1));
  }
 @@ -312,8 +325,7 @@ mon_damage(monster, damage)
  		fight_monster = 0;
  		cough_up(monster);
  		mn = mon_name(monster);
 -		sprintf(hit_message+strlen(hit_message), "defeated the %s", mn);
 -		message(hit_message, 1);
 +		messagef(1, "%sdefeated the %s", hit_message, mn);
  		hit_message[0] = 0;
  		add_exp(monster->kill_exp, 1);
  		take_from_pack(monster, &level_monsters);
 @@ -341,7 +353,7 @@ fight(to_the_death)
  	while (!is_direction(ch = rgetchar(), &d)) {
  		sound_bell();
  		if (first_miss) {
 -			message("direction?", 0);
 +			messagef(0, "direction?");
  			first_miss = 0;
  		}
  	}
 @@ -355,7 +367,7 @@ fight(to_the_death)
  	c = mvinch(row, col);
  	if (((c < 'A') || (c > 'Z')) ||
  		(!can_move(rogue.row, rogue.col, row, col))) {
 -		message("I see no monster there", 0);
 +		messagef(0, "I see no monster there");
  		return;
  	}
  	if (!(fight_monster = object_at(&level_monsters, row, col))) {
 @@ -465,7 +477,7 @@ s_con_mon(monster)
  	if (con_mon) {
  		monster->m_flags |= CONFUSED;
  		monster->moves_confused += get_rand(12, 22);
 -		message("the monster appears confused", 0);
 +		messagef(0, "the monster appears confused");
  		con_mon = 0;
  	}
  }
 Index: init.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/init.c,v
 retrieving revision 1.14
 diff -u -p -r1.14 init.c
 --- init.c	15 Dec 2007 19:44:43 -0000	1.14
 +++ init.c	27 Dec 2007 22:51:55 -0000
 @@ -96,7 +96,8 @@ init(argc, argv)
  	if ((!pn) || (strlen(pn) >= MAX_OPT_LEN)) {
  		clean_up("Hey!  Who are you?");
  	}
 -	(void) strcpy(login_name, pn);
 +	/* LOGIN_NAME_SIZE == MAX_OPT_LEN now, but just in case... */
 +	(void) strlcpy(login_name, pn, sizeof(login_name));
  
  	do_args(argc, argv);
  	do_opts();
 @@ -238,7 +239,7 @@ onintr(dummy)
  		did_int = 1;
  	} else {
  		check_message();
 -		message("interrupt", 1);
 +		messagef(1, "interrupt");
  	}
  	md_heed_signals();
  }
 @@ -341,6 +342,7 @@ env_get_value(s, e, add_blank)
  			break;
  		}
  	}
 +	/* note: edit_opts() in room.c depends on this being the right size */
  	*s = md_malloc(MAX_OPT_LEN + 2);
  	if (*s == NULL)
  		clean_up("out of memory");
 @@ -357,9 +359,10 @@ init_str(str, dflt)
  	const char *dflt;
  {
  	if (!(*str)) {
 +		/* note: edit_opts() in room.c depends on this size */
  		*str = md_malloc(MAX_OPT_LEN + 2);
  		if (*str == NULL)
  			clean_up("out of memory");
 -		(void) strcpy(*str, dflt);
 +		(void) strlcpy(*str, dflt, MAX_OPT_LEN + 2);
  	}
  }
 Index: inventory.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/inventory.c,v
 retrieving revision 1.10
 diff -u -p -r1.10 inventory.c
 --- inventory.c	14 May 2006 03:15:50 -0000	1.10
 +++ inventory.c	27 Dec 2007 22:51:56 -0000
 @@ -53,6 +53,7 @@ __RCSID("$NetBSD: inventory.c,v 1.10 200
   *
   */
  
 +#include <stdarg.h>
  #include "rogue.h"
  
  boolean is_wood[WANDS];
 @@ -216,43 +217,56 @@ inventory(pack, mask)
  	unsigned short mask;
  {
  	object *obj;
 -	short i = 0, j, maxlen = 0, n;
 -	char descs[MAX_PACK_COUNT+1][DCOLS];
 +	short i = 0, j;
 +	size_t maxlen = 0, n;
  	short row, col;
  
 +	struct {
 +		short letter;
 +		short sepchar;
 +		char desc[DCOLS];
 +		char savebuf[DCOLS+8];   
 +	} descs[MAX_PACK_COUNT+1];
 +
 +
  	obj = pack->next_object;
  
  	if (!obj) {
 -		message("your pack is empty", 0);
 +		messagef(0, "your pack is empty");
  		return;
  	}
  	while (obj) {
  		if (obj->what_is & mask) {
 -			descs[i][0] = ' ';
 -			descs[i][1] = obj->ichar;
 -			descs[i][2] = ((obj->what_is & ARMOR) && obj->is_protected)
 +			descs[i].letter = obj->ichar;
 +			descs[i].sepchar = ((obj->what_is & ARMOR) && obj->is_protected)
  				? '}' : ')';
 -			descs[i][3] = ' ';
 -			get_desc(obj, descs[i]+4);
 -			if ((n = strlen(descs[i])) > maxlen) {
 +			get_desc(obj, descs[i].desc, sizeof(descs[i].desc));
 +			n = strlen(descs[i].desc) + 4;
 +			if (n > maxlen) {
  				maxlen = n;
  			}
 -		i++;
 +			i++;
 +			/*assert(i<=MAX_PACK_COUNT);*/
  		}
  		obj = obj->next_object;
  	}
 -	(void) strcpy(descs[i++], press_space);
  	if (maxlen < 27) maxlen = 27;
 +	if (maxlen > DCOLS-2) maxlen = DCOLS-2;
  	col = DCOLS - (maxlen + 2);
  
 -	for (row = 0; ((row < i) && (row < DROWS)); row++) {
 -		if (row > 0) {
 -			for (j = col; j < DCOLS; j++) {
 -				descs[row-1][j-col] = mvinch(row, j);
 -			}
 -			descs[row-1][j-col] = 0;
 +	for (row = 0; ((row <= i) && (row < DROWS)); row++) {
 +		for (j = col; j < DCOLS; j++) {
 +			descs[row].savebuf[j-col] = mvinch(row, j);
 +		}
 +		descs[row].savebuf[j-col] = 0;
 +		if (row < i) {
 +			mvprintw(row, col, " %c%c %s", 
 +				descs[row].letter, descs[row].sepchar, 
 +				descs[row].desc);
 +		}
 +		else {
 +			mvaddstr(row, col, press_space);
  		}
 -		mvaddstr(row, col, descs[row]);
  		clrtoeol();
  	}
  	refresh();
 @@ -261,8 +275,8 @@ inventory(pack, mask)
  	move(0, 0);
  	clrtoeol();
  
 -	for (j = 1; ((j < i) && (j < DROWS)); j++) {
 -		mvaddstr(j, col, descs[j-1]);
 +	for (j = 1; ((j <= i) && (j < DROWS)); j++) {
 +		mvaddstr(j, col, descs[j].savebuf);
  	}
  }
  
 @@ -274,7 +288,7 @@ id_com()
  
  	while (ch != CANCEL) {
  		check_message();
 -		message("Character you want help for (* for all):", 0);
 +		messagef(0, "Character you want help for (* for all):");
  
  		refresh();
  		ch = getchar();
 @@ -334,7 +348,7 @@ MORE:
  			if (!pr_com_id(ch)) {
  				if (!pr_motion_char(ch)) {
  					check_message();
 -					message("unknown character", 0);
 +					messagef(0, "unknown character");
  				}
  			}
  			ch = CANCEL;
 @@ -353,7 +367,7 @@ pr_com_id(ch)
  		return(0);
  	}
  	check_message();
 -	message(com_id_tab[i].com_desc, 0);
 +	messagef(0, "%s", com_id_tab[i].com_desc);
  	return(1);
  }
  
 @@ -393,20 +407,18 @@ pr_motion_char(ch)
  			(ch == '\031') ||
  			(ch == '\016') ||
  			(ch == '\002')) {
 -		char until[18], buf[DCOLS];
 +		const char *until;
  		int n = 0;	/* XXX: GCC */
 -
  		if (ch <= '\031') {
  			ch += 96;
 -			(void) strcpy(until, "until adjascent");
 +			until = " until adjacent";
  		} else {
  			ch += 32;
 -			until[0] = '\0';
 +			until = "";
  		}
  		(void) get_com_id(&n, ch);
 -		sprintf(buf, "run %s %s", com_id_tab[n].com_desc + 8, until);
  		check_message();
 -		message(buf, 0);
 +		messagef(0, "run %s%s", com_id_tab[n].com_desc + 8, until);
  		return(1);
  	} else {
  		return(0);
 @@ -422,9 +434,10 @@ mix_colors()
  	for (i = 0; i <= 32; i++) {
  		j = get_rand(0, (POTIONS - 1));
  		k = get_rand(0, (POTIONS - 1));
 -		memcpy(t, id_potions[j].title, MAX_ID_TITLE_LEN);
 -		memcpy(id_potions[j].title, id_potions[k].title, MAX_ID_TITLE_LEN);
 -		memcpy(id_potions[k].title, t, MAX_ID_TITLE_LEN);
 +		strlcpy(t, id_potions[j].title, sizeof(t));
 +		strlcpy(id_potions[j].title, id_potions[k].title,
 +			sizeof(id_potions[j].title));
 +		strlcpy(id_potions[k].title, t, sizeof(id_potions[k].title));
  	}
  }
  
 @@ -433,181 +446,246 @@ make_scroll_titles()
  {
  	short i, j, n;
  	short sylls, s;
 +	size_t maxlen = sizeof(id_scrolls[0].title);
  
  	for (i = 0; i < SCROLS; i++) {
  		sylls = get_rand(2, 5);
 -		(void) strcpy(id_scrolls[i].title, "'");
 +		(void) strlcpy(id_scrolls[i].title, "'", maxlen);
  
  		for (j = 0; j < sylls; j++) {
  			s = get_rand(1, (MAXSYLLABLES-1));
 -			(void) strcat(id_scrolls[i].title, syllables[s]);
 +			(void) strlcat(id_scrolls[i].title, syllables[s],
 +					maxlen);
  		}
 +		/* trim trailing space */
  		n = strlen(id_scrolls[i].title);
 -		(void) strcpy(id_scrolls[i].title+(n-1), "' ");
 +		id_scrolls[i].title[n-1] = 0;
 +
 +		(void) strlcat(id_scrolls[i].title, "' ", maxlen);
 +	}
 +}
 +
 +struct sbuf {
 +	char *buf;
 +	size_t maxlen;
 +};
 +
 +static void sbuf_init __P((struct sbuf *s, char *buf, size_t maxlen));
 +static void sbuf_addstr __P((struct sbuf *s, const char *str));
 +static void sbuf_addf __P((struct sbuf *s, const char *fmt, ...));
 +static void desc_count __P((struct sbuf *s, int n));
 +static void desc_called __P((struct sbuf *s, const object *));
 +
 +static
 +void
 +sbuf_init(s, buf, maxlen)
 +	struct sbuf *s;
 +	char *buf;
 +	size_t maxlen;
 +{
 +	s->buf = buf;
 +	s->maxlen = maxlen;
 +	/*assert(maxlen>0);*/
 +	s->buf[0] = 0;
 +}
 +
 +static
 +void
 +sbuf_addstr(s, str)
 +	struct sbuf *s;
 +	const char *str;
 +{
 +	strlcat(s->buf, str, s->maxlen);
 +}
 +
 +static void sbuf_addf(struct sbuf *s, const char *fmt, ...)
 +	__attribute__((__format__(__printf__, 2, 3)));
 +
 +static
 +void
 +sbuf_addf(struct sbuf *s, const char *fmt, ...)
 +{
 +	va_list ap;
 +	size_t initlen;
 +
 +	initlen = strlen(s->buf);
 +	va_start(ap, fmt);
 +	vsnprintf(s->buf+initlen, s->maxlen-initlen, fmt, ap);
 +	va_end(ap);
 +}
 +
 +static
 +void
 +desc_count(s, n)
 +	struct sbuf *s;
 +	int n;
 +{
 +	if (n == 1) {
 +		sbuf_addstr(s, "an ");
 +	} else {
 +		sbuf_addf(s, "%d ", n);
  	}
  }
  
 +static
  void
 -get_desc(obj, desc)
 +desc_called(s, obj)
 +	struct sbuf *s;
 +	const object *obj;
 +{
 +	struct id *id_table;
 +
 +	id_table = get_id_table(obj);
 +	sbuf_addstr(s, name_of(obj));
 +	sbuf_addstr(s, "called ");
 +	sbuf_addstr(s, id_table[obj->which_kind].title);
 +}
 +
 +void
 +get_desc(obj, desc, desclen)
  	const object *obj;
  	char *desc;
 +	size_t desclen;
  {
  	const char *item_name;
  	struct id *id_table;
 -	char more_info[32];
 -	short i;
 +	struct sbuf db;
 +	unsigned short objtype_id_status;
  
  	if (obj->what_is == AMULET) {
 -		(void) strcpy(desc, "the amulet of Yendor ");
 +		(void) strlcpy(desc, "the amulet of Yendor ", desclen);
  		return;
  	}
 -	item_name = name_of(obj);
  
  	if (obj->what_is == GOLD) {
 -		sprintf(desc, "%d pieces of gold", obj->quantity);
 +		snprintf(desc, desclen, "%d pieces of gold", obj->quantity);
  		return;
  	}
  
 -	if (obj->what_is != ARMOR) {
 -		if (obj->quantity == 1) {
 -			(void) strcpy(desc, "a ");
 -		} else {
 -			sprintf(desc, "%d ", obj->quantity);
 +	item_name = name_of(obj);
 +	id_table = get_id_table(obj);
 +	if (wizard || id_table == NULL) {
 +		objtype_id_status = IDENTIFIED;
 +	}
 +	else {
 +		objtype_id_status = id_table[obj->which_kind].id_status;
 +	}
 +	if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
 +		if (obj->identified) {
 +			objtype_id_status = IDENTIFIED;
  		}
  	}
 -	if (obj->what_is == FOOD) {
 +
 +	sbuf_init(&db, desc, desclen);
 +
 +	switch (obj->what_is) {
 +	case FOOD:
  		if (obj->which_kind == RATION) {
  			if (obj->quantity > 1) {
 -				sprintf(desc, "%d rations of ", obj->quantity);
 +				sbuf_addf(&db,
 +					 "%d rations of %s", obj->quantity,
 +					 item_name);
  			} else {
 -				(void) strcpy(desc, "some ");
 +				sbuf_addf(&db, "some %s", item_name);
  			}
  		} else {
 -			(void) strcpy(desc, "a ");
 +			sbuf_addf(&db, "an %s", item_name);
  		}
 -		(void) strcat(desc, item_name);
 -		goto ANA;
 -	}
 -	id_table = get_id_table(obj);
 -
 -	if (wizard) {
 -		goto ID;
 -	}
 -	if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
 -		goto CHECK;
 -	}
 -
 -	switch(id_table[obj->which_kind].id_status) {
 -	case UNIDENTIFIED:
 -CHECK:
 -		switch(obj->what_is) {
 -		case SCROL:
 -			(void) strcat(desc, item_name);
 -			(void) strcat(desc, "entitled: ");
 -			(void) strcat(desc, id_table[obj->which_kind].title);
 -			break;
 -		case POTION:
 -			(void) strcat(desc, id_table[obj->which_kind].title);
 -			(void) strcat(desc, item_name);
 -			break;
 -		case WAND:
 -		case RING:
 -			if (obj->identified ||
 -			(id_table[obj->which_kind].id_status == IDENTIFIED)) {
 -				goto ID;
 -			}
 -			if (id_table[obj->which_kind].id_status == CALLED) {
 -				goto CALL;
 -			}
 -			(void) strcat(desc, id_table[obj->which_kind].title);
 -			(void) strcat(desc, item_name);
 -			break;
 -		case ARMOR:
 -			if (obj->identified) {
 -				goto ID;
 -			}
 -			(void) strcpy(desc, id_table[obj->which_kind].title);
 -			break;
 -		case WEAPON:
 -			if (obj->identified) {
 -				goto ID;
 -			}
 -			(void) strcat(desc, name_of(obj));
 -			break;
 +		break;
 +	case SCROL:
 +		desc_count(&db, obj->quantity);
 +		if (objtype_id_status==UNIDENTIFIED) {
 +			sbuf_addstr(&db, item_name);
 +			sbuf_addstr(&db, "entitled: ");
 +			sbuf_addstr(&db, id_table[obj->which_kind].title);
 +		} else if (objtype_id_status==CALLED) {
 +			desc_called(&db, obj);
 +		} else {
 +			sbuf_addstr(&db, item_name);
 +			sbuf_addstr(&db, id_table[obj->which_kind].real);
  		}
  		break;
 -	case CALLED:
 -CALL:	switch(obj->what_is) {
 -		case SCROL:
 -		case POTION:
 -		case WAND:
 -		case RING:
 -			(void) strcat(desc, item_name);
 -			(void) strcat(desc, "called ");
 -			(void) strcat(desc, id_table[obj->which_kind].title);
 -			break;
 +	case POTION:
 +		desc_count(&db, obj->quantity);
 +		if (objtype_id_status==UNIDENTIFIED) {
 +			sbuf_addstr(&db, id_table[obj->which_kind].title);
 +			sbuf_addstr(&db, item_name);
 +		} else if (objtype_id_status==CALLED) {
 +			desc_called(&db, obj);
 +		} else {
 +			sbuf_addstr(&db, item_name);
 +			sbuf_addstr(&db, id_table[obj->which_kind].real);
  		}
  		break;
 -	case IDENTIFIED:
 -ID:		switch(obj->what_is) {
 -		case SCROL:
 -		case POTION:
 -			(void) strcat(desc, item_name);
 -			(void) strcat(desc, id_table[obj->which_kind].real);
 -			break;
 -		case RING:
 -			if (wizard || obj->identified) {
 -				if ((obj->which_kind == DEXTERITY) ||
 -					(obj->which_kind == ADD_STRENGTH)) {
 -					sprintf(more_info, "%s%d ", ((obj->class > 0) ? "+" : ""),
 -						obj->class);
 -					(void) strcat(desc, more_info);
 -				}
 -			}
 -			(void) strcat(desc, item_name);
 -			(void) strcat(desc, id_table[obj->which_kind].real);
 -			break;
 -		case WAND:
 -			(void) strcat(desc, item_name);
 -			(void) strcat(desc, id_table[obj->which_kind].real);
 +	case WAND:
 +		desc_count(&db, obj->quantity);
 +		if (objtype_id_status==UNIDENTIFIED) {
 +			sbuf_addstr(&db, id_table[obj->which_kind].title);
 +			sbuf_addstr(&db, item_name);
 +		} else if (objtype_id_status==CALLED) {
 +			desc_called(&db, obj);
 +		} else {
 +			sbuf_addstr(&db, item_name);
 +			sbuf_addstr(&db, id_table[obj->which_kind].real);
  			if (wizard || obj->identified) {
 -				sprintf(more_info, "[%d]", obj->class);
 -				(void) strcat(desc, more_info);
 +				sbuf_addf(&db, "[%d]", obj->class);
  			}
 -			break;
 -		case ARMOR:
 -			sprintf(desc, "%s%d ", ((obj->d_enchant >= 0) ? "+" : ""),
 -			obj->d_enchant);
 -			(void) strcat(desc, id_table[obj->which_kind].title);
 -			sprintf(more_info, "[%d] ", get_armor_class(obj));
 -			(void) strcat(desc, more_info);
 -			break;
 -		case WEAPON:
 -			sprintf(desc+strlen(desc), "%s%d,%s%d ",
 -			((obj->hit_enchant >= 0) ? "+" : ""), obj->hit_enchant,
 -			((obj->d_enchant >= 0) ? "+" : ""), obj->d_enchant);
 -			(void) strcat(desc, name_of(obj));
 -			break;
  		}
  		break;
 -	}
 -ANA:
 -	if (!strncmp(desc, "a ", 2)) {
 -		if (is_vowel(desc[2])) {
 -			for (i = strlen(desc) + 1; i > 1; i--) {
 -				desc[i] = desc[i-1];
 +	case RING:
 +		desc_count(&db, obj->quantity);
 +		if (objtype_id_status==UNIDENTIFIED) {
 +			sbuf_addstr(&db, id_table[obj->which_kind].title);
 +			sbuf_addstr(&db, item_name);
 +		} else if (objtype_id_status==CALLED) {
 +			desc_called(&db, obj);
 +		} else {
 +			if ((wizard || obj->identified) &&
 +			    (obj->which_kind == DEXTERITY ||
 +			     obj->which_kind == ADD_STRENGTH)) {
 +				sbuf_addf(&db, "%+d ", obj->class);
  			}
 -			desc[1] = 'n';
 +			sbuf_addstr(&db, item_name);
 +			sbuf_addstr(&db, id_table[obj->which_kind].real);
 +		}
 +		break;
 +	case ARMOR:
 +		/* no desc_count() */
 +		if (objtype_id_status==UNIDENTIFIED) {
 +			sbuf_addstr(&db, id_table[obj->which_kind].title);
 +		} else {
 +			sbuf_addf(&db, "%+d %s[%d] ", obj->d_enchant,
 +				id_table[obj->which_kind].title,
 +				get_armor_class(obj));
 +    		}
 +		break;
 +	case WEAPON:
 +		desc_count(&db, obj->quantity);
 +		if (objtype_id_status==UNIDENTIFIED) {
 +			sbuf_addstr(&db, name_of(obj));
 +		} else {
 +			sbuf_addf(&db, "%+d,%+d %s",
 +				obj->hit_enchant, obj->d_enchant,
 +				name_of(obj));
  		}
 +		break;
  	}
 +
  	if (obj->in_use_flags & BEING_WIELDED) {
 -		(void) strcat(desc, "in hand");
 +		sbuf_addstr(&db, "in hand");
  	} else if (obj->in_use_flags & BEING_WORN) {
 -		(void) strcat(desc, "being worn");
 +		sbuf_addstr(&db, "being worn");
  	} else if (obj->in_use_flags & ON_LEFT_HAND) {
 -		(void) strcat(desc, "on left hand");
 +		sbuf_addstr(&db, "on left hand");
  	} else if (obj->in_use_flags & ON_RIGHT_HAND) {
 -		(void) strcat(desc, "on right hand");
 +		sbuf_addstr(&db, "on right hand");
 +	}
 +
 +	if (!strncmp(db.buf, "an ", 3)) {
 +		if (!is_vowel(db.buf[3])) {
 +			memmove(db.buf+2, db.buf+3, strlen(db.buf+3)+1);
 +			db.buf[1] = ' ';
 +		}
  	}
  }
  
 @@ -625,7 +703,8 @@ get_wand_and_ring_materials()
  			j = get_rand(0, WAND_MATERIALS-1);
  		} while (used[j]);
  		used[j] = 1;
 -		(void) strcpy(id_wands[i].title, wand_materials[j]);
 +		(void) strlcpy(id_wands[i].title, wand_materials[j],
 +			       sizeof(id_wands[i].title));
  		is_wood[i] = (j > MAX_METAL);
  	}
  	for (i = 0; i < GEMS; i++) {
 @@ -636,7 +715,8 @@ get_wand_and_ring_materials()
  			j = get_rand(0, GEMS-1);
  		} while (used[j]);
  		used[j] = 1;
 -		(void) strcpy(id_rings[i].title, gems[j]);
 +		(void) strlcpy(id_rings[i].title, gems[j],
 +			       sizeof(id_rings[i].title));
  	}
  }
  
 @@ -644,7 +724,7 @@ void
  single_inv(ichar)
  	short ichar;
  {
 -	short ch;
 +	short ch, ch2;
  	char desc[DCOLS];
  	object *obj;
  
 @@ -654,15 +734,12 @@ single_inv(ichar)
  		return;
  	}
  	if (!(obj = get_letter_object(ch))) {
 -		message("no such item.", 0);
 +		messagef(0, "no such item.");
  		return;
  	}
 -	desc[0] = ch;
 -	desc[1] = ((obj->what_is & ARMOR) && obj->is_protected) ? '}' : ')';
 -	desc[2] = ' ';
 -	desc[3] = 0;
 -	get_desc(obj, desc+3);
 -	message(desc, 0);
 +	ch2 = ((obj->what_is & ARMOR) && obj->is_protected) ? '}' : ')';
 +	get_desc(obj, desc, sizeof(desc));
 +	messagef(0, "%c%c %s", ch, ch2, desc);
  }
  
  struct id *
 @@ -694,13 +771,13 @@ inv_armor_weapon(is_weapon)
  		if (rogue.weapon) {
  			single_inv(rogue.weapon->ichar);
  		} else {
 -			message("not wielding anything", 0);
 +			messagef(0, "not wielding anything");
  		}
  	} else {
  		if (rogue.armor) {
  			single_inv(rogue.armor->ichar);
  		} else {
 -			message("not wearing anything", 0);
 +			messagef(0, "not wearing anything");
  		}
  	}
  }
 @@ -710,9 +787,8 @@ id_type()
  {
  	const char *id;
  	int ch;
 -	char buf[DCOLS];
  
 -	message("what do you want identified?", 0);
 +	messagef(0, "what do you want identified?");
  
  	ch = rgetchar();
  
 @@ -781,6 +857,5 @@ id_type()
  		}
  	}
  	check_message();
 -	sprintf(buf, "'%c': %s", ch, id);
 -	message(buf, 0);
 +	messagef(0, "'%c': %s", ch, id);
  }
 Index: level.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/level.c,v
 retrieving revision 1.7
 diff -u -p -r1.7 level.c
 --- level.c	7 Aug 2003 09:37:38 -0000	1.7
 +++ level.c	27 Dec 2007 22:51:56 -0000
 @@ -769,8 +769,8 @@ put_player(nr)
  	rn = get_room_number(rogue.row, rogue.col);
  	wake_room(rn, 1, rogue.row, rogue.col);
  	if (new_level_message) {
 -		message(new_level_message, 0);
 -		new_level_message = 0;
 +		messagef(0, "%s", new_level_message);
 +		new_level_message = NULL;
  	}
  	mvaddch(rogue.row, rogue.col, rogue.fchar);
  }
 @@ -783,12 +783,12 @@ drop_check()
  	}
  	if (dungeon[rogue.row][rogue.col] & STAIRS) {
  		if (levitate) {
 -			message("you're floating in the air!", 0);
 +			messagef(0, "you're floating in the air!");
  			return(0);
  		}
  		return(1);
  	}
 -	message("I see no way down", 0);
 +	messagef(0, "I see no way down");
  	return(0);
  }
  
 @@ -797,11 +797,11 @@ check_up()
  {
  	if (!wizard) {
  		if (!(dungeon[rogue.row][rogue.col] & STAIRS)) {
 -			message("I see no way up", 0);
 +			messagef(0, "I see no way up");
  			return(0);
  		}
  		if (!has_amulet()) {
 -			message("your way is magically blocked", 0);
 +			messagef(0, "your way is magically blocked");
  			return(0);
  		}
  	}
 @@ -820,7 +820,6 @@ add_exp(e, promotion)
  	int e;
  	boolean promotion;
  {
 -	char mbuf[40];
  	short new_exp;
  	short i, hp;
  
 @@ -832,8 +831,7 @@ add_exp(e, promotion)
  			rogue.exp_points = MAX_EXP + 1;
  		}
  		for (i = rogue.exp+1; i <= new_exp; i++) {
 -			sprintf(mbuf, "welcome to level %d", i);
 -			message(mbuf, 0);
 +			messagef(0, "welcome to level %d", i);
  			if (promotion) {
  				hp = hp_raise();
  				rogue.hp_current += hp;
 @@ -873,7 +871,6 @@ hp_raise()
  void
  show_average_hp()
  {
 -	char mbuf[80];
  	float real_average;
  	float effective_average;
  
 @@ -885,9 +882,8 @@ show_average_hp()
  		effective_average = (float) (rogue.hp_max - INIT_HP) / (rogue.exp - 1);
  
  	}
 -	sprintf(mbuf, "R-Hp: %.2f, E-Hp: %.2f (!: %d, V: %d)", real_average,
 +	messagef(0, "R-Hp: %.2f, E-Hp: %.2f (!: %d, V: %d)", real_average,
  		effective_average, extra_hp, less_hp);
 -	message(mbuf, 0);
  }
  
  void
 Index: machdep.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/machdep.c,v
 retrieving revision 1.14
 diff -u -p -r1.14 machdep.c
 --- machdep.c	24 Apr 2006 19:00:30 -0000	1.14
 +++ machdep.c	27 Dec 2007 22:51:56 -0000
 @@ -456,7 +456,7 @@ md_lock(l)
  		setegid(egid);
  		if ((fd = open(_PATH_SCOREFILE, O_RDONLY)) < 1) {
  			setegid(gid);
 -			message("cannot lock score file", 0);
 +			messagef(0, "cannot lock score file");
  			return;
  		}
  		setegid(gid);
 @@ -472,10 +472,13 @@ md_lock(l)
  /* md_shell():
   *
   * This function spawns a shell for the user to use.  When this shell is
 - * terminated, the game continues.  Since this program may often be run
 - * setuid to gain access to privileged files, care is taken that the shell
 - * is run with the user's REAL user id, and not the effective user id.
 - * The effective user id is restored after the shell completes.
 + * terminated, the game continues.
 + *
 + * It is important that the game not give the shell the privileges the
 + * game uses to access the scores file. This version of the game runs
 + * with privileges low by default; only the saved gid (if setgid) or uid
 + * (if setuid) will be privileged, but that privilege is discarded by
 + * exec().
   */
  
  void
 @@ -483,11 +486,19 @@ md_shell(shell)
  	const char *shell;
  {
  	int w;
 +	pid_t pid;
  
 -	if (!fork()) {
 +	pid = fork();
 +	switch (pid) {
 +	case -1:
 +		break;
 +	case 0:
  		execl(shell, shell, (char *) 0);
 +		_exit(255);
 +	default:
 +		waitpid(pid, &w, 0);
 +		break;
  	}
 -	wait(&w);
  }
  
  #endif
 Index: message.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/message.c,v
 retrieving revision 1.10
 diff -u -p -r1.10 message.c
 --- message.c	7 Aug 2003 09:37:38 -0000	1.10
 +++ message.c	27 Dec 2007 22:51:56 -0000
 @@ -55,6 +55,7 @@ __RCSID("$NetBSD: message.c,v 1.10 2003/
  
  #include <signal.h>
  #include <termios.h>
 +#include <stdarg.h>
  #include "rogue.h"
  
  char msgs[NMESSAGES][DCOLS] = {"", "", "", "", ""};
 @@ -63,6 +64,9 @@ boolean msg_cleared = 1, rmsg = 0;
  char hunger_str[HUNGER_STR_LEN] = "";
  const char *more = "-more-";
  
 +static void message __P((const char *, boolean));
 +
 +static
  void
  message(msg, intrpt)
  	const char *msg;
 @@ -86,7 +90,7 @@ message(msg, intrpt)
  	}
  	if (!rmsg) {
  		imsg = (imsg + 1) % NMESSAGES;
 -		(void) strcpy(msgs[imsg], msg);
 +		(void) strlcpy(msgs[imsg], msg, sizeof(msgs[imsg]));
  	}
  	mvaddstr(MIN_ROW-1, 0, msg);
  	addch(' ');
 @@ -103,6 +107,19 @@ message(msg, intrpt)
  }
  
  void
 +messagef(boolean intrpt, const char *fmt, ...)
 +{
 +	va_list ap;
 +	char buf[DCOLS];
 +
 +	va_start(ap, fmt);
 +	vsnprintf(buf, sizeof(buf), fmt, ap);
 +	va_end(ap);
 +
 +	message(buf, intrpt);
 +}
 +
 +void
  remessage(c)
  	short c;
  {
 @@ -132,9 +149,10 @@ check_message()
  }
  
  int
 -get_input_line(prompt, insert, buf, if_cancelled, add_blank, do_echo)
 +get_input_line(prompt, insert, buf, buflen, if_cancelled, add_blank, do_echo)
  	const char *prompt, *insert;
  	char *buf;
 +	size_t buflen;
  	const char *if_cancelled;
  	boolean add_blank;
  	boolean do_echo;
 @@ -147,14 +165,14 @@ get_input_line(prompt, insert, buf, if_c
  
  	if (insert[0]) {
  		mvaddstr(0, n + 1, insert);
 -		(void) strcpy(buf, insert);
 -		i = strlen(insert);
 +		(void) strlcpy(buf, insert, buflen);
 +		i = strlen(buf);
  		move(0, (n + i + 1));
  		refresh();
  	}
  
  	while (((ch = rgetchar()) != '\r') && (ch != '\n') && (ch != CANCEL)) {
 -		if ((ch >= ' ') && (ch <= '~') && (i < MAX_TITLE_LENGTH-2)) {
 +		if ((ch >= ' ') && (ch <= '~') && (i < buflen-2)) {
  			if ((ch != ' ') || (i > 0)) {
  				buf[i++] = ch;
  				if (do_echo) {
 @@ -239,9 +257,7 @@ print_stats(stat_mask)
  			mvaddstr(row, 0, "Level: ");
  		}
  		/* max level taken care of in make_level() */
 -		sprintf(buf, "%d", cur_level);
 -		mvaddstr(row, 7, buf);
 -		pad(buf, 2);
 +		mvprintw(row, 7, "%-2d", cur_level);
  	}
  	if (stat_mask & STAT_GOLD) {
  		if (label) {
 @@ -250,9 +266,7 @@ print_stats(stat_mask)
  		if (rogue.gold > MAX_GOLD) {
  			rogue.gold = MAX_GOLD;
  		}
 -		sprintf(buf, "%ld", rogue.gold);
 -		mvaddstr(row, 16, buf);
 -		pad(buf, 6);
 +		mvprintw(row, 16, "%-6ld", rogue.gold);
  	}
  	if (stat_mask & STAT_HP) {
  		if (label) {
 @@ -262,9 +276,9 @@ print_stats(stat_mask)
  			rogue.hp_current -= (rogue.hp_max - MAX_HP);
  			rogue.hp_max = MAX_HP;
  		}
 -		sprintf(buf, "%d(%d)", rogue.hp_current, rogue.hp_max);
 -		mvaddstr(row, 27, buf);
 -		pad(buf, 8);
 +		snprintf(buf, sizeof(buf), "%d(%d)",
 +			rogue.hp_current, rogue.hp_max);
 +		mvprintw(row, 27, "%-8s", buf);
  	}
  	if (stat_mask & STAT_STRENGTH) {
  		if (label) {
 @@ -274,10 +288,9 @@ print_stats(stat_mask)
  			rogue.str_current -= (rogue.str_max - MAX_STRENGTH);
  			rogue.str_max = MAX_STRENGTH;
  		}
 -		sprintf(buf, "%d(%d)", (rogue.str_current + add_strength),
 -			rogue.str_max);
 -		mvaddstr(row, 41, buf);
 -		pad(buf, 6);
 +		snprintf(buf, sizeof(buf), "%d(%d)",
 +			(rogue.str_current + add_strength), rogue.str_max);
 +		mvprintw(row, 41, "%-6s", buf);
  	}
  	if (stat_mask & STAT_ARMOR) {
  		if (label) {
 @@ -286,9 +299,7 @@ print_stats(stat_mask)
  		if (rogue.armor && (rogue.armor->d_enchant > MAX_ARMOR)) {
  			rogue.armor->d_enchant = MAX_ARMOR;
  		}
 -		sprintf(buf, "%d", get_armor_class(rogue.armor));
 -		mvaddstr(row, 53, buf);
 -		pad(buf, 2);
 +		mvprintw(row, 53, "%-2d", get_armor_class(rogue.armor));
  	}
  	if (stat_mask & STAT_EXP) {
  		if (label) {
 @@ -300,9 +311,9 @@ print_stats(stat_mask)
  		if (rogue.exp > MAX_EXP_LEVEL) {
  			rogue.exp = MAX_EXP_LEVEL;
  		}
 -		sprintf(buf, "%d/%ld", rogue.exp, rogue.exp_points);
 -		mvaddstr(row, 61, buf);
 -		pad(buf, 11);
 +		snprintf(buf, sizeof(buf), "%d/%ld",
 +			rogue.exp, rogue.exp_points);
 +		mvprintw(row, 61, "%-11s", buf);
  	}
  	if (stat_mask & STAT_HUNGER) {
  		mvaddstr(row, 73, hunger_str);
 @@ -312,37 +323,21 @@ print_stats(stat_mask)
  }
  
  void
 -pad(s, n)
 -	const char *s;
 -	short n;
 -{
 -	short i;
 -
 -	for (i = strlen(s); i < n; i++) {
 -		addch(' ');
 -	}
 -}
 -
 -void
  save_screen()
  {
  	FILE *fp;
  	short i, j;
  	char buf[DCOLS+2];
 -	boolean found_non_blank;
  
  	if ((fp = fopen("rogue.screen", "w")) != NULL) {
  		for (i = 0; i < DROWS; i++) {
 -			found_non_blank = 0;
 -			for (j = (DCOLS - 1); j >= 0; j--) {
 +			for (j=0; j<DCOLS; j++) {
  				buf[j] = mvinch(i, j);
 -				if (!found_non_blank) {
 -					if ((buf[j] != ' ') || (j == 0)) {
 -						buf[j + ((j == 0) ? 0 : 1)] = 0;
 -						found_non_blank = 1;
 -					}
 -				}
  			}
 +			/*buf[DCOLS] = 0; -- redundant */
 +			for (j=DCOLS; j>0 && buf[j-1]==' '; j--);
 +			buf[j] = 0;
 +
  			fputs(buf, fp);
  			putc('\n', fp);
  		}
 Index: monster.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/monster.c,v
 retrieving revision 1.11
 diff -u -p -r1.11 monster.c
 --- monster.c	30 Mar 2006 04:10:04 -0000	1.11
 +++ monster.c	27 Dec 2007 22:51:57 -0000
 @@ -709,7 +709,7 @@ create_monster()
  			wake_up(monster);
  		}
  	} else {
 -		message("you hear a faint cry of anguish in the distance", 0);
 +		messagef(0, "you hear a faint cry of anguish in the distance");
  	}
  }
  
 @@ -851,7 +851,7 @@ aggravate()
  {
  	object *monster;
  
 -	message("you hear a high pitched humming noise", 0);
 +	messagef(0, "you hear a high pitched humming noise");
  
  	monster = level_monsters.next_monster;
  
 Index: move.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/move.c,v
 retrieving revision 1.8
 diff -u -p -r1.8 move.c
 --- move.c	14 May 2006 03:15:50 -0000	1.8
 +++ move.c	27 Dec 2007 22:51:57 -0000
 @@ -66,7 +66,7 @@ one_move_rogue(dirch, pickup)
  	short row, col;
  	object *obj;
  	char desc[DCOLS];
 -	short n, status, d = 0;	/* XXX: GCC */
 +	short status, d = 0;	/* XXX: GCC */
  
  	row = rogue.row;
  	col = rogue.col;
 @@ -83,9 +83,9 @@ one_move_rogue(dirch, pickup)
  	if (being_held || bear_trap) {
  		if (!(dungeon[row][col] & MONSTER)) {
  			if (being_held) {
 -				message("you are being held", 1);
 +				messagef(1, "you are being held");
  			} else {
 -				message("you are still stuck in the bear trap", 0);
 +				messagef(0, "you are still stuck in the bear trap");
  				(void) reg_move();
  			}
  			return(MOVE_FAILED);
 @@ -135,9 +135,10 @@ one_move_rogue(dirch, pickup)
  		}
  		if (pickup && !levitate) {
  			if ((obj = pick_up(row, col, &status)) != NULL) {
 -				get_desc(obj, desc);
 +				get_desc(obj, desc, sizeof(desc));
  				if (obj->what_is == GOLD) {
  					free_object(obj);
 +					messagef(1, "%s", desc);
  					goto NOT_IN_PACK;
  				}
  			} else if (!status) {
 @@ -148,17 +149,12 @@ one_move_rogue(dirch, pickup)
  		} else {
  MOVE_ON:
  			obj = object_at(&level_objects, row, col);
 -			(void) strcpy(desc, "moved onto ");
 -			get_desc(obj, desc+11);
 +			get_desc(obj, desc, sizeof(desc));
 +			messagef(1, "moved onto %s", desc);
  			goto NOT_IN_PACK;
  		}
 -		n = strlen(desc);
 -		desc[n] = '(';
 -		desc[n+1] = obj->ichar;
 -		desc[n+2] = ')';
 -		desc[n+3] = 0;
 +		messagef(1, "%s(%c)", desc, obj->ichar);
  NOT_IN_PACK:
 -		message(desc, 1);
  		(void) reg_move();
  		return(STOPPED_ON_SOMETHING);
  	}
 @@ -326,7 +322,7 @@ move_onto()
  	while (!is_direction(ch = rgetchar(), &d)) {
  		sound_bell();
  		if (first_miss) {
 -			message("direction? ", 0);
 +			messagef(0, "direction? ");
  			first_miss = 0;
  		}
  	}
 @@ -382,19 +378,19 @@ check_hunger(msg_only)
  	boolean fainted = 0;
  
  	if (rogue.moves_left == HUNGRY) {
 -		(void) strcpy(hunger_str, "hungry");
 -		message(hunger_str, 0);
 +		(void) strlcpy(hunger_str, "hungry", sizeof(hunger_str));
 +		messagef(0, "%s", hunger_str);
  		print_stats(STAT_HUNGER);
  	}
  	if (rogue.moves_left == WEAK) {
 -		(void) strcpy(hunger_str, "weak");
 -		message(hunger_str, 1);
 +		(void) strlcpy(hunger_str, "weak", sizeof(hunger_str));
 +		messagef(1, "%s", hunger_str);
  		print_stats(STAT_HUNGER);
  	}
  	if (rogue.moves_left <= FAINT) {
  		if (rogue.moves_left == FAINT) {
 -			(void) strcpy(hunger_str, "faint");
 -			message(hunger_str, 1);
 +			(void) strlcpy(hunger_str, "faint", sizeof(hunger_str));
 +			messagef(1, "%s", hunger_str);
  			print_stats(STAT_HUNGER);
  		}
  		n = get_rand(0, (FAINT - rogue.moves_left));
 @@ -403,13 +399,13 @@ check_hunger(msg_only)
  			if (rand_percent(40)) {
  				rogue.moves_left++;
  			}
 -			message("you faint", 1);
 +			messagef(1, "you faint");
  			for (i = 0; i < n; i++) {
  				if (coin_toss()) {
  					mv_mons();
  				}
  			}
 -			message(you_can_move_again, 1);
 +			messagef(1, you_can_move_again);
  		}
  	}
  	if (msg_only) {
 @@ -482,7 +478,7 @@ reg_move()
  	}
  	if (levitate) {
  		if (!(--levitate)) {
 -			message("you float gently to the ground", 1);
 +			messagef(1, "you float gently to the ground");
  			if (dungeon[rogue.row][rogue.col] & TRAP) {
  				trap_player(rogue.row, rogue.col);
  			}
 @@ -490,7 +486,7 @@ reg_move()
  	}
  	if (haste_self) {
  		if (!(--haste_self)) {
 -			message("you feel yourself slowing down", 0);
 +			messagef(0, "you feel yourself slowing down");
  		}
  	}
  	heal();
 Index: object.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/object.c,v
 retrieving revision 1.10
 diff -u -p -r1.10 object.c
 --- object.c	30 Mar 2006 04:27:24 -0000	1.10
 +++ object.c	27 Dec 2007 22:51:58 -0000
 @@ -80,36 +80,36 @@ fighter rogue = {
  };
  
  struct id id_potions[POTIONS] = {
 -{100, "blue \0                           ", "of increase strength ", 0},
 -{250, "red \0                            ", "of restore strength ", 0},
 -{100, "green \0                          ", "of healing ", 0},
 -{200, "grey \0                           ", "of extra healing ", 0},
 - {10, "brown \0                          ", "of poison ", 0},
 -{300, "clear \0                          ", "of raise level ", 0},
 - {10, "pink \0                           ", "of blindness ", 0},
 - {25, "white \0                          ", "of hallucination ", 0},
 -{100, "purple \0                         ", "of detect monster ", 0},
 -{100, "black \0                          ", "of detect things ", 0},
 - {10, "yellow \0                         ", "of confusion ", 0},
 - {80, "plaid \0                          ", "of levitation ", 0},
 -{150, "burgundy \0                       ", "of haste self ", 0},
 -{145, "beige \0                          ", "of see invisible ", 0}
 +{100, "blue ",     "of increase strength ", 0},
 +{250, "red ",      "of restore strength ", 0},
 +{100, "green ",    "of healing ", 0},
 +{200, "grey ",     "of extra healing ", 0},
 + {10, "brown ",    "of poison ", 0},
 +{300, "clear ",    "of raise level ", 0},
 + {10, "pink ",     "of blindness ", 0},
 + {25, "white ",    "of hallucination ", 0},
 +{100, "purple ",   "of detect monster ", 0},
 +{100, "black ",    "of detect things ", 0},
 + {10, "yellow ",   "of confusion ", 0},
 + {80, "plaid ",    "of levitation ", 0},
 +{150, "burgundy ", "of haste self ", 0},
 +{145, "beige ",    "of see invisible ", 0}
  };
  
  struct id id_scrolls[SCROLS] = {
 -{505, "                                   ", "of protect armor ", 0},
 -{200, "                                   ", "of hold monster ", 0},
 -{235, "                                   ", "of enchant weapon ", 0},
 -{235, "                                   ", "of enchant armor ", 0},
 -{175, "                                   ", "of identify ", 0},
 -{190, "                                   ", "of teleportation ", 0},
 - {25, "                                   ", "of sleep ", 0},
 -{610, "                                   ", "of scare monster ", 0},
 -{210, "                                   ", "of remove curse ", 0},
 - {80, "                                   ", "of create monster ",0},
 - {25, "                                   ", "of aggravate monster ",0},
 -{180, "                                   ", "of magic mapping ", 0},
 - {90, "                                   ", "of confuse monster ", 0}
 +{505, "", "of protect armor ", 0},
 +{200, "", "of hold monster ", 0},
 +{235, "", "of enchant weapon ", 0},
 +{235, "", "of enchant armor ", 0},
 +{175, "", "of identify ", 0},
 +{190, "", "of teleportation ", 0},
 + {25, "", "of sleep ", 0},
 +{610, "", "of scare monster ", 0},
 +{210, "", "of remove curse ", 0},
 + {80, "", "of create monster ",0},
 + {25, "", "of aggravate monster ",0},
 +{180, "", "of magic mapping ", 0},
 + {90, "", "of confuse monster ", 0}
  };
  
  struct id id_weapons[WEAPONS] = {
 @@ -134,31 +134,31 @@ struct id id_armors[ARMORS] = {
  };
  
  struct id id_wands[WANDS] = {
 -	 {25, "                                 ", "of teleport away ",0},
 -	 {50, "                                 ", "of slow monster ", 0},
 -	  {8, "                                 ", "of invisibility ",0},
 -	 {55, "                                 ", "of polymorph ",0},
 -	  {2, "                                 ", "of haste monster ",0},
 -	 {20, "                                 ", "of magic missile ",0},
 -	 {20, "                                 ", "of cancellation ",0},
 -	  {0, "                                 ", "of do nothing ",0},
 -	 {35, "                                 ", "of drain life ",0},
 -	 {20, "                                 ", "of cold ",0},
 -	 {20, "                                 ", "of fire ",0}
 +	 {25, "", "of teleport away ",0},
 +	 {50, "", "of slow monster ", 0},
 +	  {8, "", "of invisibility ",0},
 +	 {55, "", "of polymorph ",0},
 +	  {2, "", "of haste monster ",0},
 +	 {20, "", "of magic missile ",0},
 +	 {20, "", "of cancellation ",0},
 +	  {0, "", "of do nothing ",0},
 +	 {35, "", "of drain life ",0},
 +	 {20, "", "of cold ",0},
 +	 {20, "", "of fire ",0}
  };
  
  struct id id_rings[RINGS] = {
 -	 {250, "                                 ", "of stealth ",0},
 -	 {100, "                                 ", "of teleportation ", 0},
 -	 {255, "                                 ", "of regeneration ",0},
 -	 {295, "                                 ", "of slow digestion ",0},
 -	 {200, "                                 ", "of add strength ",0},
 -	 {250, "                                 ", "of sustain strength ",0},
 -	 {250, "                                 ", "of dexterity ",0},
 -	  {25, "                                 ", "of adornment ",0},
 -	 {300, "                                 ", "of see invisible ",0},
 -	 {290, "                                 ", "of maintain armor ",0},
 -	 {270, "                                 ", "of searching ",0},
 +	 {250, "", "of stealth ",0},
 +	 {100, "", "of teleportation ", 0},
 +	 {255, "", "of regeneration ",0},
 +	 {295, "", "of slow digestion ",0},
 +	 {200, "", "of add strength ",0},
 +	 {250, "", "of sustain strength ",0},
 +	 {250, "", "of dexterity ",0},
 +	  {25, "", "of adornment ",0},
 +	 {300, "", "of see invisible ",0},
 +	 {290, "", "of maintain armor ",0},
 +	 {270, "", "of searching ",0},
  };
  
  void
 @@ -257,7 +257,7 @@ object_at(pack, row, col)
  			obj = obj->next_object;
  		}
  		if (!obj) {
 -			message("object_at(): inconsistent", 1);
 +			messagef(1, "object_at(): inconsistent");
  		}
  	}
  	return(obj);
 @@ -637,7 +637,7 @@ alloc_object()
  		obj = free_list;
  		free_list = free_list->next_object;
  	} else if (!(obj = (object *) md_malloc(sizeof(object)))) {
 -			message("cannot allocate object, saving game", 0);
 +			messagef(0, "cannot allocate object, saving game");
  			save_into_file(error_file);
  			clean_up("alloc_object:  save failed");
  	}
 @@ -739,10 +739,10 @@ c_object_for_wizard()
  
  	max = 0;
  	if (pack_count((object *) 0) >= MAX_PACK_COUNT) {
 -		message("pack full", 0);
 +		messagef(0, "pack full");
  		return;
  	}
 -	message("type of object?", 0);
 +	messagef(0, "type of object?");
  
  	while (r_index("!?:)]=/,\033", (ch = rgetchar()), 0) == -1) {
  		sound_bell();
 @@ -788,7 +788,7 @@ c_object_for_wizard()
  	}
  	if ((ch != ',') && (ch != ':')) {
  GIL:
 -		if (get_input_line("which kind?", "", buf, "", 0, 1)) {
 +		if (get_input_line("which kind?", "", buf, sizeof(buf), "", 0, 1)) {
  			wk = get_number(buf);
  			if ((wk >= 0) && (wk <= max)) {
  				obj->which_kind = (unsigned short) wk;
 @@ -804,7 +804,7 @@ GIL:
  			return;
  		}
  	}
 -	get_desc(obj, buf);
 -	message(buf, 0);
 +	get_desc(obj, buf, sizeof(buf));
 +	messagef(0, "%s", buf);
  	(void) add_to_pack(obj, &rogue.pack, 1);
  }
 Index: pack.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/pack.c,v
 retrieving revision 1.7
 diff -u -p -r1.7 pack.c
 --- pack.c	7 Aug 2003 09:37:39 -0000	1.7
 +++ pack.c	27 Dec 2007 22:51:58 -0000
 @@ -110,18 +110,18 @@ pick_up(row, col, status)
  	*status = 1;
  
  	if (levitate) {
 -		message("you're floating in the air!", 0);
 +		messagef(0, "you're floating in the air!");
  		return((object *) 0);
  	}
  	obj = object_at(&level_objects, row, col);
  	if (!obj) {
 -		message("pick_up(): inconsistent", 1);
 +		messagef(1, "pick_up(): inconsistent");
  		return(obj);
  	}
  	if (	(obj->what_is == SCROL) &&
  			(obj->which_kind == SCARE_MONSTER) &&
  			obj->picked_up) {
 -		message("the scroll turns to dust as you pick it up", 0);
 +		messagef(0, "the scroll turns to dust as you pick it up");
  		dungeon[row][col] &= (~OBJECT);
  		vanish(obj, 0, &level_objects);
  		*status = 0;
 @@ -138,7 +138,7 @@ pick_up(row, col, status)
  		return(obj);	/* obj will be free_object()ed in caller */
  	}
  	if (pack_count(obj) >= MAX_PACK_COUNT) {
 -		message("pack too full", 1);
 +		messagef(1, "pack too full");
  		return((object *) 0);
  	}
  	dungeon[row][col] &= ~(OBJECT);
 @@ -156,29 +156,29 @@ drop()
  	char desc[DCOLS];
  
  	if (dungeon[rogue.row][rogue.col] & (OBJECT | STAIRS | TRAP)) {
 -		message("there's already something there", 0);
 +		messagef(0, "there's already something there");
  		return;
  	}
  	if (!rogue.pack.next_object) {
 -		message("you have nothing to drop", 0);
 +		messagef(0, "you have nothing to drop");
  		return;
  	}
  	if ((ch = pack_letter("drop what?", ALL_OBJECTS)) == CANCEL) {
  		return;
  	}
  	if (!(obj = get_letter_object(ch))) {
 -		message("no such item.", 0);
 +		messagef(0, "no such item.");
  		return;
  	}
  	if (obj->in_use_flags & BEING_WIELDED) {
  		if (obj->is_cursed) {
 -			message(curse_message, 0);
 +			messagef(0, "%s", curse_message);
  			return;
  		}
  		unwield(rogue.weapon);
  	} else if (obj->in_use_flags & BEING_WORN) {
  		if (obj->is_cursed) {
 -			message(curse_message, 0);
 +			messagef(0, "%s", curse_message);
  			return;
  		}
  		mv_aquatars();
 @@ -186,7 +186,7 @@ drop()
  		print_stats(STAT_ARMOR);
  	} else if (obj->in_use_flags & ON_EITHER_HAND) {
  		if (obj->is_cursed) {
 -			message(curse_message, 0);
 +			messagef(0, "%s", curse_message);
  			return;
  		}
  		un_put_on(obj);
 @@ -205,9 +205,8 @@ drop()
  		take_from_pack(obj, &rogue.pack);
  	}
  	place_at(obj, rogue.row, rogue.col);
 -	(void) strcpy(desc, "dropped ");
 -	get_desc(obj, desc+8);
 -	message(desc, 0);
 +	get_desc(obj, desc, sizeof(desc));
 +	messagef(0, "dropped %s", desc);
  	(void) reg_move();
  }
  
 @@ -257,7 +256,9 @@ next_avail_ichar()
  	}
  	obj = rogue.pack.next_object;
  	while (obj) {
 -		ichars[(obj->ichar - 'a')] = 1;
 +		if (obj->ichar >= 'a' && obj->ichar <= 'z') {
 +			ichars[(obj->ichar - 'a')] = 1;
 +		}
  		obj = obj->next_object;
  	}
  	for (i = 0; i < 26; i++) {
 @@ -283,12 +284,12 @@ pack_letter(prompt, mask)
  	unsigned short tmask = mask;
  
  	if (!mask_pack(&rogue.pack, mask)) {
 -		message("nothing appropriate", 0);
 +		messagef(0, "nothing appropriate");
  		return(CANCEL);
  	}
  	for (;;) {
  
 -		message(prompt, 0);
 +		messagef(0, "%s", prompt);
  
  		for (;;) {
  			ch = rgetchar();
 @@ -320,19 +321,18 @@ take_off()
  
  	if (rogue.armor) {
  		if (rogue.armor->is_cursed) {
 -			message(curse_message, 0);
 +			messagef(0, "%s", curse_message);
  		} else {
  			mv_aquatars();
  			obj = rogue.armor;
  			unwear(rogue.armor);
 -			(void) strcpy(desc, "was wearing ");
 -			get_desc(obj, desc+12);
 -			message(desc, 0);
 +			get_desc(obj, desc, sizeof(desc));
 +			messagef(0, "was wearing %s", desc);
  			print_stats(STAT_ARMOR);
  			(void) reg_move();
  		}
  	} else {
 -		message("not wearing any", 0);
 +		messagef(0, "not wearing any");
  	}
  }
  
 @@ -344,7 +344,7 @@ wear()
  	char desc[DCOLS];
  
  	if (rogue.armor) {
 -		message("your already wearing some", 0);
 +		messagef(0, "you're already wearing some");
  		return;
  	}
  	ch = pack_letter("wear what?", ARMOR);
 @@ -353,17 +353,16 @@ wear()
  		return;
  	}
  	if (!(obj = get_letter_object(ch))) {
 -		message("no such item.", 0);
 +		messagef(0, "no such item.");
  		return;
  	}
  	if (obj->what_is != ARMOR) {
 -		message("you can't wear that", 0);
 +		messagef(0, "you can't wear that");
  		return;
  	}
  	obj->identified = 1;
 -	(void) strcpy(desc, "wearing ");
 -	get_desc(obj, desc + 8);
 -	message(desc, 0);
 +	get_desc(obj, desc, sizeof(desc));
 +	messagef(0, "wearing %s", desc);
  	do_wear(obj);
  	print_stats(STAT_ARMOR);
  	(void) reg_move();
 @@ -396,7 +395,7 @@ wield()
  	char desc[DCOLS];
  
  	if (rogue.weapon && rogue.weapon->is_cursed) {
 -		message(curse_message, 0);
 +		messagef(0, "%s", curse_message);
  		return;
  	}
  	ch = pack_letter("wield what?", WEAPON);
 @@ -405,22 +404,20 @@ wield()
  		return;
  	}
  	if (!(obj = get_letter_object(ch))) {
 -		message("No such item.", 0);
 +		messagef(0, "No such item.");
  		return;
  	}
  	if (obj->what_is & (ARMOR | RING)) {
 -		sprintf(desc, "you can't wield %s",
 +		messagef(0, "you can't wield %s",
  			((obj->what_is == ARMOR) ? "armor" : "rings"));
 -		message(desc, 0);
  		return;
  	}
  	if (obj->in_use_flags & BEING_WIELDED) {
 -		message("in use", 0);
 +		messagef(0, "in use");
  	} else {
  		unwield(rogue.weapon);
 -		(void) strcpy(desc, "wielding ");
 -		get_desc(obj, desc + 9);
 -		message(desc, 0);
 +		get_desc(obj, desc, sizeof(desc));
 +		messagef(0, "wielding %s", desc);
  		do_wield(obj);
  		(void) reg_move();
  	}
 @@ -458,18 +455,20 @@ call_it()
  		return;
  	}
  	if (!(obj = get_letter_object(ch))) {
 -		message("no such item.", 0);
 +		messagef(0, "no such item.");
  		return;
  	}
  	if (!(obj->what_is & (SCROL | POTION | WAND | RING))) {
 -		message("surely you already know what that's called", 0);
 +		messagef(0, "surely you already know what that's called");
  		return;
  	}
  	id_table = get_id_table(obj);
  
 -	if (get_input_line("call it:","",buf,id_table[obj->which_kind].title,1,1)) {
 +	if (get_input_line("call it:", "", buf, sizeof(buf),
 +			id_table[obj->which_kind].title, 1, 1)) {
  		id_table[obj->which_kind].id_status = CALLED;
 -		(void) strcpy(id_table[obj->which_kind].title, buf);
 +		(void) strlcpy(id_table[obj->which_kind].title, buf,
 +				sizeof(id_table[obj->which_kind].title));
  	}
  }
  
 @@ -565,23 +564,18 @@ kick_into_pack()
  {
  	object *obj;
  	char desc[DCOLS];
 -	short n, stat;
 +	short stat;
  
  	if (!(dungeon[rogue.row][rogue.col] & OBJECT)) {
 -		message("nothing here", 0);
 +		messagef(0, "nothing here");
  	} else {
  		if ((obj = pick_up(rogue.row, rogue.col, &stat)) != NULL) {
 -			get_desc(obj, desc);
 +			get_desc(obj, desc, sizeof(desc));
  			if (obj->what_is == GOLD) {
 -				message(desc, 0);
 +				messagef(0, "%s", desc);
  				free_object(obj);
  			} else {
 -				n = strlen(desc);
 -				desc[n] = '(';
 -				desc[n+1] = obj->ichar;
 -				desc[n+2] = ')';
 -				desc[n+3] = 0;
 -				message(desc, 0);
 +				messagef(0, "%s(%c)", desc, obj->ichar);
  			}
  		}
  		if (obj || (!stat)) {
 Index: play.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/play.c,v
 retrieving revision 1.6
 diff -u -p -r1.6 play.c
 --- play.c	7 Aug 2003 09:37:39 -0000	1.6
 +++ play.c	27 Dec 2007 22:51:58 -0000
 @@ -67,7 +67,7 @@ play_level()
  	for (;;) {
  		interrupted = 0;
  		if (hit_message[0]) {
 -			message(hit_message, 1);
 +			messagef(1, "%s", hit_message);
  			hit_message[0] = 0;
  		}
  		if (trap_door) {
 @@ -214,7 +214,7 @@ CH:
  			throw();
  			break;
  		case 'v':
 -			message("rogue-clone: Version III. (Tim Stoehr was here), tektronix!zeus!tims", 0);
 +			messagef(0, "rogue-clone: Version III. (Tim Stoehr was here), tektronix!zeus!tims");
  			break;
  		case 'Q':
  			quit(0);
 @@ -246,28 +246,28 @@ CH:
  			if (wizard) {
  				inventory(&level_objects, ALL_OBJECTS);
  			} else {
 -				message(unknown_command, 0);
 +				messagef(0, "%s", unknown_command);
  			}
  			break;
  		case '\023':
  			if (wizard) {
  				draw_magic_map();
  			} else {
 -				message(unknown_command, 0);
 +				messagef(0, "%s", unknown_command);
  			}
  			break;
  		case '\024':
  			if (wizard) {
  				show_traps();
  			} else {
 -				message(unknown_command, 0);
 +				messagef(0, "%s", unknown_command);
  			}
  			break;
  		case '\017':
  			if (wizard) {
  				show_objects();
  			} else {
 -				message(unknown_command, 0);
 +				messagef(0, "%s", unknown_command);
  			}
  			break;
  		case '\001':
 @@ -277,21 +277,21 @@ CH:
  			if (wizard) {
  				c_object_for_wizard();
  			} else {
 -				message(unknown_command, 0);
 +				messagef(0, "%s", unknown_command);
  			}
  			break;
  		case '\015':
  			if (wizard) {
  				show_monsters();
  			} else {
 -				message(unknown_command, 0);
 +				messagef(0, "%s", unknown_command);
  			}
  			break;
  		case 'S':
  			save_game();
  			break;
  		default:
 -			message(unknown_command, 0);
 +			messagef(0, "%s", unknown_command);
  			break;
  		}
  	}
 Index: ring.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/ring.c,v
 retrieving revision 1.6
 diff -u -p -r1.6 ring.c
 --- ring.c	7 Aug 2003 09:37:39 -0000	1.6
 +++ ring.c	27 Dec 2007 22:51:58 -0000
 @@ -77,28 +77,28 @@ put_on_ring()
  	object *ring;
  
  	if (r_rings == 2) {
 -		message("wearing two rings already", 0);
 +		messagef(0, "wearing two rings already");
  		return;
  	}
  	if ((ch = pack_letter("put on what?", RING)) == CANCEL) {
  		return;
  	}
  	if (!(ring = get_letter_object(ch))) {
 -		message("no such item.", 0);
 +		messagef(0, "no such item.");
  		return;
  	}
  	if (!(ring->what_is & RING)) {
 -		message("that's not a ring", 0);
 +		messagef(0, "that's not a ring");
  		return;
  	}
  	if (ring->in_use_flags & (ON_LEFT_HAND | ON_RIGHT_HAND)) {
 -		message("that ring is already being worn", 0);
 +		messagef(0, "that ring is already being worn");
  		return;
  	}
  	if (r_rings == 1) {
  		ch = (rogue.left_ring ? 'r' : 'l');
  	} else {
 -		message(left_or_right, 0);
 +		messagef(0, "%s", left_or_right);
  		do {
  			ch = rgetchar();
  		} while ((ch != CANCEL) && (ch != 'l') && (ch != 'r') && (ch != '\n') &&
 @@ -110,7 +110,7 @@ put_on_ring()
  	}
  	if (((ch == 'l') && rogue.left_ring)||((ch == 'r') && rogue.right_ring)) {
  		check_message();
 -		message("there's already a ring on that hand", 0);
 +		messagef(0, "there's already a ring on that hand");
  		return;
  	}
  	if (ch == 'l') {
 @@ -120,8 +120,8 @@ put_on_ring()
  	}
  	ring_stats(1);
  	check_message();
 -	get_desc(ring, desc);
 -	message(desc, 0);
 +	get_desc(ring, desc, sizeof(desc));
 +	messagef(0, "%s", desc);
  	(void) reg_move();
  }
  
 @@ -160,7 +160,7 @@ remove_ring()
  	} else if (!rogue.left_ring && rogue.right_ring) {
  		right = 1;
  	} else {
 -		message(left_or_right, 0);
 +		messagef(0, "%s", left_or_right);
  		do {
  			ch = rgetchar();
  		} while ((ch != CANCEL) && (ch != 'l') && (ch != 'r') &&
 @@ -174,22 +174,21 @@ remove_ring()
  			if (rogue.left_ring) {
  				ring = rogue.left_ring;
  			} else {
 -				message(no_ring, 0);
 +				messagef(0, "%s", no_ring);
  			}
  		} else {
  			if (rogue.right_ring) {
  				ring = rogue.right_ring;
  			} else {
 -				message(no_ring, 0);
 +				messagef(0, "%s", no_ring);
  			}
  		}
  		if (ring->is_cursed) {
 -			message(curse_message, 0);
 +			messagef(0, "%s", curse_message);
  		} else {
  			un_put_on(ring);
 -			(void) strcpy(buf, "removed ");
 -			get_desc(ring, buf + 8);
 -			message(buf, 0);
 +			get_desc(ring, buf, sizeof(buf));
 +			messagef(0, "removed %s", buf);
  			(void) reg_move();
  		}
  	}
 @@ -257,23 +256,22 @@ inv_rings()
  	char buf[DCOLS];
  
  	if (r_rings == 0) {
 -		message("not wearing any rings", 0);
 +		messagef(0, "not wearing any rings");
  	} else {
  		if (rogue.left_ring) {
 -			get_desc(rogue.left_ring, buf);
 -			message(buf, 0);
 +			get_desc(rogue.left_ring, buf, sizeof(buf));
 +			messagef(0, "%s", buf);
  		}
  		if (rogue.right_ring) {
 -			get_desc(rogue.right_ring, buf);
 -			message(buf, 0);
 +			get_desc(rogue.right_ring, buf, sizeof(buf));
 +			messagef(0, "%s", buf);
  		}
  	}
  	if (wizard) {
 -		sprintf(buf, "ste %d, r_r %d, e_r %d, r_t %d, s_s %d, a_s %d, reg %d, r_e %d, s_i %d, m_a %d, aus %d",
 +		messagef(0, "ste %d, r_r %d, e_r %d, r_t %d, s_s %d, a_s %d, reg %d, r_e %d, s_i %d, m_a %d, aus %d",
  			stealthy, r_rings, e_rings, r_teleport, sustain_strength,
  			add_strength, regeneration, ring_exp, r_see_invisible,
  			maintain_armor, auto_search);
 -		message(buf, 0);
  	}
  }
  
 Index: rogue.h
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/rogue.h,v
 retrieving revision 1.17
 diff -u -p -r1.17 rogue.h
 --- rogue.h	15 Feb 2005 12:54:50 -0000	1.17
 +++ rogue.h	27 Dec 2007 22:51:59 -0000
 @@ -515,14 +515,14 @@ void	freeze(object *);
  int	get_armor_class(const object *);
  int	get_com_id(int *, short);
  int	get_damage(const char *, boolean);
 -void	get_desc(const object *, char *);
 +void	get_desc(const object *, char *, size_t);
  int	get_dir(short, short, short, short);
  void	get_dir_rc(short, short *, short *, short);
  char	get_dungeon_char(short, short);
  int	get_exp_level(long);
  void	get_food(object *, boolean);
  int	get_hit_chance(const object *);
 -int	get_input_line(const char *, const char *, char *, const char *, boolean, boolean);
 +int	get_input_line(const char *, const char *, char *, size_t, const char *, boolean, boolean);
  char	get_mask_char(unsigned short);
  int	get_number(const char *);
  boolean	get_oth_room(short, short *, short *);
 @@ -597,7 +597,9 @@ void	md_lock(boolean);
  void	md_shell(const char *);
  void	md_sleep(int);
  void	md_slurp(void);
 -void	message(const char *, boolean);
 +/*void	message(const char *, boolean);*/
 +void	messagef(boolean, const char *, ...)
 +		__attribute__((__format__(__printf__, 2, 3)));
  void	mix_colors(void);
  void	mix_random_rooms(void);
  int	mon_can_go(const object *, int, int);
 @@ -759,7 +761,8 @@ extern	boolean	see_invisible;
  extern	boolean	sustain_strength;
  extern	boolean	trap_door;
  extern	boolean	wizard;
 -extern	char	hit_message[];
 +#define HIT_MESSAGE_SIZE 80
 +extern	char	hit_message[HIT_MESSAGE_SIZE];
  #define HUNGER_STR_LEN 8
  extern	char	hunger_str[HUNGER_STR_LEN];
  extern	char	login_name[MAX_OPT_LEN];
 Index: room.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/room.c,v
 retrieving revision 1.9
 diff -u -p -r1.9 room.c
 --- room.c	2 Apr 2006 00:13:29 -0000	1.9
 +++ room.c	27 Dec 2007 22:51:59 -0000
 @@ -60,7 +60,7 @@ boolean rooms_visited[MAXROOMS];
  
  #define NOPTS 7
  
 -struct option {
 +const struct option {
  	const char *prompt;
  	boolean is_bool;
  	char **strval;
 @@ -84,15 +84,15 @@ struct option {
  	},
  	{
  		"Name (\"name\"): ",
 -		0, &nick_name
 +		0, &nick_name, (boolean *) 0
  	},
  	{
  		"Fruit (\"fruit\"): ",
 -		0, &fruit
 +		0, &fruit, (boolean *) 0
  	},
  	{
  		"Save file (\"file\"): ",
 -		0, &save_file
 +		0, &save_file, (boolean *) 0
  	}
  };
  
 @@ -602,6 +602,11 @@ CH:
  					ch = rgetchar();
  				} while ((ch != '\012') && (ch != '\015') && (ch != '\033'));
  				if (j != 0) {
 +					/*
 +					 * We rely on the option string being
 +					 * allocated to hold MAX_OPT_LEN+2 
 +					 * bytes. This is arranged in init.c.
 +					 */
  					(void) strcpy(*(options[i].strval), buf);
  				}
  				opt_show(i);
 @@ -626,7 +631,7 @@ opt_show(i)
  	int i;
  {
  	const char *s;
 -	struct option *opt = &options[i];
 +	const struct option *opt = &options[i];
  
  	opt_erase(i);
  
 @@ -642,7 +647,7 @@ void
  opt_erase(i)
  	int i;
  {
 -	struct option *opt = &options[i];
 +	const struct option *opt = &options[i];
  
  	mvaddstr(i, 0, opt->prompt);
  	clrtoeol();
 Index: save.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/save.c,v
 retrieving revision 1.10
 diff -u -p -r1.10 save.c
 --- save.c	17 Mar 2006 23:04:01 -0000	1.10
 +++ save.c	27 Dec 2007 22:52:00 -0000
 @@ -64,12 +64,12 @@ save_game()
  {
  	char fname[64];
  
 -	if (!get_input_line("file name?", save_file, fname, "game not saved",
 -			0, 1)) {
 +	if (!get_input_line("file name?", save_file, fname, sizeof(fname),
 +			"game not saved", 0, 1)) {
  		return;
  	}
  	check_message();
 -	message(fname, 0);
 +	messagef(0, "%s", fname);
  	save_into_file(fname);
  }
  
 @@ -89,20 +89,25 @@ save_into_file(sfile)
  			len = strlen(hptr) + strlen(sfile);
  			name_buffer = md_malloc(len);
  			if (name_buffer == NULL) {
 -				message("out of memory for save file name", 0);
 +				messagef(0,
 +					"out of memory for save file name");
  				sfile = error_file;
  			} else {
  				(void) strcpy(name_buffer, hptr);
  				(void) strcat(name_buffer, sfile+1);
  				sfile = name_buffer;
  			}
 +			/* 
 +			 * Note: name_buffer gets leaked. But it's small,
 +			 * and in the common case we're about to exit.
 +			 */
  		}
  	}
  	if (((fp = fopen(sfile, "w")) == NULL) ||
  	    ((file_id = md_get_file_id(sfile)) == -1)) {
  		if (fp)
  			fclose(fp);
 -		message("problem accessing the save file", 0);
 +		messagef(0, "problem accessing the save file");
  		return;
  	}
  	md_ignore_signals();
 @@ -160,7 +165,7 @@ restore(fname)
  	FILE *fp;
  	struct rogue_time saved_time, mod_time;
  	char buf[4];
 -	char tbuf[40];
 +	char tbuf[MAX_OPT_LEN];
  	int new_file_id, saved_file_id;
  
  	fp = NULL;
 @@ -351,10 +356,13 @@ read_string(s, fp, len)
  	short n;
  
  	r_read(fp, (char *) &n, sizeof(short));
 -	if (n > len)
 +	if (n<=0 || (size_t)(unsigned short)n > len) {
  		clean_up("read_string: corrupt game file");
 +	}
  	r_read(fp, s, n);
  	xxxx(s, n);
 +	/* ensure null termination */
 +	s[n-1] = 0;
  }
  
  void
 @@ -389,7 +397,7 @@ r_write(fp, buf, n)
  {
  	if (!write_failed) {
  		if (fwrite(buf, sizeof(char), n, fp) != (size_t)n) {
 -			message("write() failed, don't know why", 0);
 +			messagef(0, "write() failed, don't know why");
  			sound_bell();
  			write_failed = 1;
  		}
 Index: score.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/score.c,v
 retrieving revision 1.11
 diff -u -p -r1.11 score.c
 --- score.c	7 Aug 2003 09:37:40 -0000	1.11
 +++ score.c	27 Dec 2007 22:52:00 -0000
 @@ -62,7 +62,10 @@ killed_by(monster, other)
  	const object *monster;
  	short other;
  {
 -	char buf[128];
 +	const char *mechanism = "killed by something unknown (?)";
 +	char mechanism_buf[128];
 +	const char *article;
 +	char message_buf[128];
  
  	md_ignore_signals();
  
 @@ -73,32 +76,35 @@ killed_by(monster, other)
  	if (other) {
  		switch(other) {
  		case HYPOTHERMIA:
 -			(void) strcpy(buf, "died of hypothermia");
 +			mechanism = "died of hypothermia";
  			break;
  		case STARVATION:
 -			(void) strcpy(buf, "died of starvation");
 +			mechanism = "died of starvation";
  			break;
  		case POISON_DART:
 -			(void) strcpy(buf, "killed by a dart");
 +			mechanism = "killed by a dart";
  			break;
  		case QUIT:
 -			(void) strcpy(buf, "quit");
 +			mechanism = "quit";
  			break;
  		case KFIRE:
 -			(void) strcpy(buf, "killed by fire");
 +			mechanism = "killed by fire";
  			break;
  		}
  	} else {
 -		(void) strcpy(buf, "Killed by ");
  		if (is_vowel(m_names[monster->m_char - 'A'][0])) {
 -			(void) strcat(buf, "an ");
 +			article = "an";
  		} else {
 -			(void) strcat(buf, "a ");
 +			article = "a";
  		}
 -		(void) strcat(buf, m_names[monster->m_char - 'A']);
 +		snprintf(mechanism_buf, sizeof(mechanism_buf),
 +			"Killed by %s %s",
 +			 article, m_names[monster->m_char - 'A']);
 +		mechanism = mechanism_buf;
  	}
 -	(void) strcat(buf, " with ");
 -	sprintf(buf+strlen(buf), "%ld gold", rogue.gold);
 +	snprintf(message_buf, sizeof(message_buf),
 +		 "%s with %ld gold", mechanism, rogue.gold);
 +
  	if ((!other) && (!no_skull)) {
  		clear();
  		mvaddstr(4, 32, "__---------__");
 @@ -118,11 +124,11 @@ killed_by(monster, other)
  		mvaddstr(18, 31, "\\_           _/");
  		mvaddstr(19, 33, "~---------~");
  		center(21, nick_name);
 -		center(22, buf);
 +		center(22, message_buf);
  	} else {
 -		message(buf, 0);
 +		messagef(0, "%s", message_buf);
  	}
 -	message("", 0);
 +	messagef(0, "%s", "");		/* gcc objects to just "" */
  	put_scores(monster, other);
  }
  
 @@ -143,8 +149,8 @@ win()
  	mvaddstr(17, 11, "Congratulations,  you have  been admitted  to  the");
  	mvaddstr(18, 11, "Fighters' Guild.   You return home,  sell all your");
  	mvaddstr(19, 11, "treasures at great profit and retire into comfort.");
 -	message("", 0);
 -	message("", 0);
 +	messagef(0, "%s", "");		/* gcc objects to just "" */
 +	messagef(0, "%s", "");		/* gcc objects to just "" */
  	id_all();
  	sell_pack();
  	put_scores((object *) 0, WIN);
 @@ -154,7 +160,7 @@ void
  quit(from_intrpt)
  	boolean from_intrpt;
  {
 -	char buf[128];
 +	char buf[DCOLS];
  	short i, orow, ocol;
  	boolean mc;
  
 @@ -173,7 +179,7 @@ quit(from_intrpt)
  		}
  	}
  	check_message();
 -	message("really quit?", 1);
 +	messagef(1, "really quit?");
  	if (rgetchar() != 'y') {
  		md_heed_signals();
  		check_message();
 @@ -194,17 +200,157 @@ quit(from_intrpt)
  	killed_by((object *) 0, QUIT);
  }
  
 +/*
 + * The score file on disk is up to ten entries of the form
 + *      score block [80 bytes]
 + *      nickname block [30 bytes]
 + *
 + * The score block is to be parsed as follows:
 + *      bytes 0-1	Rank (" 1" to "10")
 + *      bytes 2-4	space padding
 + *      bytes 5-15	Score/gold
 + *      byte 15 up to a ':'	Login name
 + *      past the ':'    Death mechanism
 + *
 + * The nickname block is an alternate name to be printed in place of the
 + * login name. Both blocks are supposed to contain a null-terminator.
 + */
 +
 +struct score_entry {
 +	long gold;
 +	char username[80];
 +	char death[80];
 +	char nickname[30];
 +};
 +
 +#define NUM_SCORE_ENTRIES 10
 +
 +static void pad_spaces __P((char *, size_t));
 +static void unpad_spaces(char *);
 +static int read_score_entry __P((struct score_entry *, FILE *));
 +static void write_score_entry __P((const struct score_entry *, int, FILE *));
 +static void make_score __P((struct score_entry *, const object *, int));
 +
 +
 +static
 +void
 +pad_spaces(str, len)
 +	char *str;
 +	size_t len;
 +{
 +	size_t x;
 +	for (x=strlen(str); x<len-1; x++) {
 +		str[x] = ' ';
 +	}
 +	str[len-1] = 0;
 +}
 +
 +static
 +void
 +unpad_spaces(str)
 +	char *str;
 +{
 +	size_t x;
 +	for (x=strlen(str); x>0 && str[x-1]==' '; x--);
 +	str[x] = 0;
 +}
 +
 +static
 +int
 +read_score_entry(se, fp)
 +	struct score_entry *se;
 +	FILE *fp;
 +{
 +	char score_block[80];
 +	char nickname_block[30];
 +	size_t n, x;
 +
 +	n = fread(score_block, 1, sizeof(score_block), fp);
 +	if (n==0) {
 +		/* EOF */
 +		return 0;
 +	}
 +	if (n != sizeof(score_block)) {
 +		sf_error();
 +	}
 +
 +	n = fread(nickname_block, 1, sizeof(nickname_block), fp);
 +	if (n != sizeof(nickname_block)) {
 +		sf_error();
 +	}
 +
 +	xxxx(score_block, sizeof(score_block));
 +	xxxx(nickname_block, sizeof(nickname_block));
 +
 +	/* Ensure null termination */
 +	score_block[sizeof(score_block)-1] = 0;
 +	nickname_block[sizeof(nickname_block)-1] = 0;
 +
 +	/* If there are other nulls in the score block, file is corrupt */
 +	if (strlen(score_block)!=sizeof(score_block)-1) {
 +		sf_error();
 +	}
 +	/* but this is NOT true of the nickname block */
 +
 +	/* quash trailing spaces */
 +	unpad_spaces(score_block);
 +	unpad_spaces(nickname_block);
 +
 +	for (x=5; score_block[x] == ' '; x++);
 +	se->gold = lget_number(score_block+x);
 +
 +	for (x=15; score_block[x] != 0 && score_block[x] != ':'; x++);
 +	if (score_block[x] == 0) {
 +		sf_error();
 +	}
 +	score_block[x++] = 0;
 +	strlcpy(se->username, score_block+15, sizeof(se->username));
 +
 +	strlcpy(se->death, score_block+x, sizeof(se->death));
 +	strlcpy(se->nickname, nickname_block, sizeof(se->nickname));
 +
 +	return 1;
 +}
 +
 +static
 +void
 +write_score_entry(se, rank, fp)
 +	const struct score_entry *se;
 +	int rank;
 +	FILE *fp;
 +{
 +	char score_block[80];
 +	char nickname_block[30];
 +
 +	/* avoid writing crap to score file */
 +	memset(score_block, 0, sizeof(score_block));
 +	memset(nickname_block, 0, sizeof(nickname_block));
 +
 +	snprintf(score_block, sizeof(score_block),
 +		 "%2d    %6ld   %s: %s",
 +		 rank+1, se->gold, se->username, se->death);
 +	strlcpy(nickname_block, se->nickname, sizeof(nickname_block));
 +
 +	/* pad blocks out with spaces */
 +	pad_spaces(score_block, sizeof(score_block));
 +	/*pad_spaces(nickname_block, sizeof(nickname_block)); -- wrong! */
 +
 +	xxxx(score_block, sizeof(score_block));
 +	xxxx(nickname_block, sizeof(nickname_block));
 +
 +	fwrite(score_block, 1, sizeof(score_block), fp);
 +	fwrite(nickname_block, 1, sizeof(nickname_block), fp);
 +}
 +
  void
  put_scores(monster, other)
  	const object *monster;
  	short other;
  {
 -	short i, n, rank = 10, x, ne = 0, found_player = -1;
 -	char scores[10][82];
 -	char n_names[10][30];
 -	char buf[128];
 +	short i, rank=-1, found_player = -1, numscores = 0;
 +	struct score_entry scores[NUM_SCORE_ENTRIES];
 +	const char *name;
  	FILE *fp;
 -	long s;
  	boolean dopause = score_only;
  
  	md_lock(1);
 @@ -213,180 +359,172 @@ put_scores(monster, other)
  	if ((fp = fopen(_PATH_SCOREFILE, "r+")) == NULL &&
  	    (fp = fopen(_PATH_SCOREFILE, "w+")) == NULL) {
  		setegid(gid);
 -		message("cannot read/write/create score file", 0);
 +		messagef(0, "cannot read/write/create score file");
  		sf_error();
  	}
  	setegid(gid);
  	rewind(fp);
  	(void) xxx(1);
  
 -	for (i = 0; i < 10; i++) {
 -		if (((n = fread(scores[i], sizeof(char), 80, fp)) < 80) && (n != 0)) {
 -			sf_error();
 -		} else if (n != 0) {
 -			xxxx(scores[i], 80);
 -			if ((n = fread(n_names[i], sizeof(char), 30, fp)) < 30) {
 -				sf_error();
 -			}
 -			xxxx(n_names[i], 30);
 -		} else {
 +	for (numscores = 0; numscores < NUM_SCORE_ENTRIES; numscores++) {
 +		if (read_score_entry(&scores[numscores], fp) == 0) {
  			break;
  		}
 -		ne++;
 -		if ((!score_only) && (found_player == -1)) {
 -			if (!name_cmp(scores[i]+15, login_name)) {
 -				x = 5;
 -				while (scores[i][x] == ' ') {
 -					x++;
 -				}
 -				s = lget_number(scores[i] + x);
 -				if (rogue.gold < s) {
 -					score_only = 1;
 -				} else {
 -					found_player = i;
 -				}
 +	}
 +
 +	/* Search the score list. */
 +	for (i=0; i<numscores; i++) {
 +		if (!strcmp(scores[i].username, login_name)) {
 +			/* found our score */
 +			if (rogue.gold < scores[i].gold) {
 +				/* we didn't do as well as last time */
 +				score_only = 1;
 +			} else {
 +				/* we did better; mark entry for removal */
 +				found_player = i;
  			}
 +			break;
  		}
  	}
 +
 +	/* Remove a superseded entry, if any. */
  	if (found_player != -1) {
 -		ne--;
 -		for (i = found_player; i < ne; i++) {
 -			(void) strcpy(scores[i], scores[i+1]);
 -			(void) strcpy(n_names[i], n_names[i+1]);
 +		numscores--;
 +		for (i = found_player; i < numscores; i++) {
 +			scores[i] = scores[i+1];
  		}
  	}
 +
 +	/* If we're going to insert ourselves, do it now */
  	if (!score_only) {
 -		for (i = 0; i < ne; i++) {
 -			x = 5;
 -			while (scores[i][x] == ' ') {
 -				x++;
 -			}
 -			s = lget_number(scores[i] + x);
  
 -			if (rogue.gold >= s) {
 +		/* if we aren't better than anyone, add at end. */
 +		rank = numscores;
 +
 +		/* Otherwise, find our slot. */
 +		for (i = 0; i < numscores; i++) {
 +			if (rogue.gold >= scores[i].gold) {
  				rank = i;
  				break;
  			}
  		}
 -		if (ne == 0) {
 -			rank = 0;
 -		} else if ((ne < 10) && (rank == 10)) {
 -			rank = ne;
 -		}
 -		if (rank < 10) {
 -			insert_score(scores, n_names, nick_name, rank, ne,
 -			    monster, other);
 -			if (ne < 10) {
 -				ne++;
 +
 +		if (rank < NUM_SCORE_ENTRIES) {
 +			/* Open up a slot */
 +			for (i = numscores; i > rank; i--) {
 +				scores[i] = scores[i-1];
  			}
 +			numscores++;
 +
 +			/* Put our info in the slot */
 +			make_score(&scores[rank], monster, other);
  		}
 +
 +		/* Now rewrite the score file */
 +
 +		md_ignore_signals();
  		rewind(fp);
 +		(void) xxx(1);
 +
 +		for (i = 0; i < numscores; i++) {
 +			write_score_entry(&scores[i], i, fp);
 +		}
  	}
 +	md_lock(0);
 +	fclose(fp);
 +
 +	/* Display the scores */
  
  	clear();
  	mvaddstr(3, 30, "Top  Ten  Rogueists");
  	mvaddstr(8, 0, "Rank   Score   Name");
  
 -	md_ignore_signals();
 -
 -	(void) xxx(1);
 -
 -	for (i = 0; i < ne; i++) {
 +	for (i = 0; i < numscores; i++) {
  		if (i == rank) {
  			standout();
  		}
 -		if (i == 9) {
 -			scores[i][0] = '1';
 -			scores[i][1] = '0';
 +
 +		if (scores[i].nickname[0]) {
 +			name = scores[i].nickname;
  		} else {
 -			scores[i][0] = ' ';
 -			scores[i][1] = i + '1';
 -		}
 -		nickize(buf, scores[i], n_names[i]);
 -		mvaddstr(i+10, 0, buf);
 -		if (rank < 10) {
 -			xxxx(scores[i], 80);
 -			fwrite(scores[i], sizeof(char), 80, fp);
 -			xxxx(n_names[i], 30);
 -			fwrite(n_names[i], sizeof(char), 30, fp);
 +			name = scores[i].username;
  		}
 +
 +		mvprintw(i+10, 0, "%2d    %6ld   %s: %s",
 +			 i+1, scores[i].gold, name, scores[i].death);
 +
  		if (i == rank) {
  			standend();
  		}
  	}
 -	md_lock(0);
  	refresh();
 -	fclose(fp);
 -	message("", 0);
 +	messagef(0, "%s", "");		/* gcc objects to just "" */
  	if (dopause) {
 -		message("", 0);
 +		messagef(0, "%s", "");
  	}
  	clean_up("");
  }
  
 +static
  void
 -insert_score(scores, n_names, n_name, rank, n, monster, other)
 -	char scores[][82];
 -	char n_names[][30];
 -	const char *n_name;
 -	short rank, n;
 +make_score(se, monster, other)
 +	struct score_entry *se;
  	const object *monster;
  	int other;
  {
 -	short i;
 -	char buf[128];
 +	const char *death = "bolts from the blue (?)";
 +	const char *hasamulet;
 +	char deathbuf[80];
  
 -	if (n > 0) {
 -		for (i = n; i > rank; i--) {
 -			if ((i < 10) && (i > 0)) {
 -				(void) strcpy(scores[i], scores[i-1]);
 -				(void) strcpy(n_names[i], n_names[i-1]);
 -			}
 -		}
 -	}
 -	sprintf(buf, "%2d    %6ld   %s: ", rank+1, (long)rogue.gold,
 -	    login_name);
 +	se->gold = rogue.gold;
 +	strlcpy(se->username, login_name, sizeof(se->username));
  
  	if (other) {
  		switch(other) {
  		case HYPOTHERMIA:
 -			(void) strcat(buf, "died of hypothermia");
 +			death = "died of hypothermia";
  			break;
  		case STARVATION:
 -			(void) strcat(buf, "died of starvation");
 +			death = "died of starvation";
  			break;
  		case POISON_DART:
 -			(void) strcat(buf, "killed by a dart");
 +			death = "killed by a dart";
  			break;
  		case QUIT:
 -			(void) strcat(buf, "quit");
 +			death = "quit";
  			break;
  		case WIN:
 -			(void) strcat(buf, "a total winner");
 +			death = "a total winner";
  			break;
  		case KFIRE:
 -			(void) strcat(buf, "killed by fire");
 +			death = "killed by fire";
  			break;
  		}
  	} else {
 -		(void) strcat(buf, "killed by ");
 -		if (is_vowel(m_names[monster->m_char - 'A'][0])) {
 -			(void) strcat(buf, "an ");
 +		const char *mn, *article;
 +
 +		mn = m_names[monster->m_char - 'A'];
 +		if (is_vowel(mn[0])) {
 +			article = "an";
  		} else {
 -			(void) strcat(buf, "a ");
 +			article = "a";
  		}
 -		(void) strcat(buf, m_names[monster->m_char - 'A']);
 -	}
 -	sprintf(buf+strlen(buf), " on level %d ",  max_level);
 -	if ((other != WIN) && has_amulet()) {
 -		(void) strcat(buf, "with amulet");
 +		
 +		snprintf(deathbuf, sizeof(deathbuf),
 +			 "killed by %s %s", article, mn);
 +		death = deathbuf;
  	}
 -	for (i = strlen(buf); i < 79; i++) {
 -		buf[i] = ' ';
 +
 +	if (other != WIN && has_amulet()) {
 +		hasamulet = " with amulet";
 +	} else {
 +		hasamulet = "";
  	}
 -	buf[79] = 0;
 -	(void) strcpy(scores[rank], buf);
 -	(void) strcpy(n_names[rank], n_name);
 +
 +	snprintf(se->death, sizeof(se->death), "%s on level %d%s",
 +		 death, max_level, hasamulet);
 +
 +	strlcpy(se->nickname, nick_name, sizeof(se->nickname));
  }
  
  boolean
 @@ -419,9 +557,8 @@ sell_pack()
  			rogue.gold += val;
  
  			if (row < DROWS) {
 -				sprintf(buf, "%5d      ", val);
 -				get_desc(obj, buf+11);
 -				mvaddstr(row++, 0, buf);
 +				get_desc(obj, buf, sizeof(buf));
 +				mvprintw(row++, 0, "%5d      %s", val, buf);
  			}
  		}
  		obj = obj->next_object;
 @@ -430,7 +567,7 @@ sell_pack()
  	if (rogue.gold > MAX_GOLD) {
  		rogue.gold = MAX_GOLD;
  	}
 -	message("", 0);
 +	messagef(0, "%s", "");		/* gcc objects to just "" */
  }
  
  int
 @@ -504,23 +641,6 @@ id_all()
  	}
  }
  
 -int
 -name_cmp(s1, s2)
 -	char *s1;
 -	const char *s2;
 -{
 -	short i = 0;
 -	int r;
 -
 -	while(s1[i] != ':') {
 -		i++;
 -	}
 -	s1[i] = 0;
 -	r = strcmp(s1, s2);
 -	s1[i] = ':';
 -	return(r);
 -}
 -
  void
  xxxx(buf, n)
  	char *buf;
 @@ -557,33 +677,6 @@ xxx(st)
  }
  
  void
 -nickize(buf, score, n_name)
 -	char *buf;
 -	const char *score, *n_name;
 -{
 -	short i = 15, j;
 -
 -	if (!n_name[0]) {
 -		(void) strcpy(buf, score);
 -	} else {
 -		(void) strncpy(buf, score, 16);
 -
 -		while (score[i] != ':') {
 -			i++;
 -		}
 -
 -		(void) strcpy(buf+15, n_name);
 -		j = strlen(buf);
 -
 -		while (score[i]) {
 -			buf[j++] = score[i++];
 -		}
 -		buf[j] = 0;
 -		buf[79] = 0;
 -	}
 -}
 -
 -void
  center(row, buf)
  	short row;
  	const char *buf;
 @@ -598,6 +691,6 @@ void
  sf_error()
  {
  	md_lock(0);
 -	message("", 1);
 +	messagef(1, "%s", "");		/* gcc objects to just "" */
  	clean_up("sorry, score file is out of order");
  }
 Index: spec_hit.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/spec_hit.c,v
 retrieving revision 1.5
 diff -u -p -r1.5 spec_hit.c
 --- spec_hit.c	7 Aug 2003 09:37:40 -0000	1.5
 +++ spec_hit.c	27 Dec 2007 22:52:00 -0000
 @@ -100,12 +100,12 @@ rust(monster)
  	}
  	if ((rogue.armor->is_protected) || maintain_armor) {
  		if (monster && (!(monster->m_flags & RUST_VANISHED))) {
 -			message("the rust vanishes instantly", 0);
 +			messagef(0, "the rust vanishes instantly");
  			monster->m_flags |= RUST_VANISHED;
  		}
  	} else {
  		rogue.armor->d_enchant--;
 -		message("your armor weakens", 0);
 +		messagef(0, "your armor weakens");
  		print_stats(STAT_ARMOR);
  	}
  }
 @@ -127,7 +127,7 @@ freeze(monster)
  
  	if (freeze_percent > 10) {
  		monster->m_flags |= FREEZING_ROGUE;
 -		message("you are frozen", 1);
 +		messagef(1, "you are frozen");
  
  		n = get_rand(4, 8);
  		for (i = 0; i < n; i++) {
 @@ -139,7 +139,7 @@ freeze(monster)
  			}
  			killed_by((object *)0, HYPOTHERMIA);
  		}
 -		message(you_can_move_again, 1);
 +		messagef(1, you_can_move_again);
  		monster->m_flags &= (~FREEZING_ROGUE);
  	}
  }
 @@ -160,7 +160,7 @@ steal_gold(monster)
  		amount = rogue.gold;
  	}
  	rogue.gold -= amount;
 -	message("your purse feels lighter", 0);
 +	messagef(0, "your purse feels lighter");
  	print_stats(STAT_GOLD);
  	disappear(monster);
  }
 @@ -205,13 +205,12 @@ steal_item(monster)
  			}
  		}
  	}
 -	(void) strcpy(desc, "she stole ");
  	if (obj->what_is != WEAPON) {
  		t = obj->quantity;
  		obj->quantity = 1;
  	}
 -	get_desc(obj, desc+10);
 -	message(desc, 0);
 +	get_desc(obj, desc, sizeof(desc));
 +	messagef(0, "she stole %s", desc);
  
  	obj->quantity = ((obj->what_is != WEAPON) ? t : 1);
  
 @@ -363,16 +362,13 @@ boolean
  check_imitator(monster)
  	object *monster;
  {
 -	char msg[80];
 -
  	if (monster->m_flags & IMITATES) {
  		wake_up(monster);
  		if (!blind) {
  			mvaddch(monster->row, monster->col,
  					get_dungeon_char(monster->row, monster->col));
  			check_message();
 -			sprintf(msg, "wait, that's a %s!", mon_name(monster));
 -			message(msg, 1);
 +			messagef(1, "wait, that's a %s!", mon_name(monster));
  		}
  		return(1);
  	}
 @@ -400,7 +396,6 @@ sting(monster)
  	object *monster;
  {
  	short sting_chance = 35;
 -	char msg[80];
  
  	if ((rogue.str_current <= 3) || sustain_strength) {
  		return;
 @@ -411,9 +406,8 @@ sting(monster)
  		sting_chance -= (6 * ((rogue.exp + ring_exp) - 8));
  	}
  	if (rand_percent(sting_chance)) {
 -		sprintf(msg, "the %s's bite has weakened you",
 -		mon_name(monster));
 -		message(msg, 0);
 +		messagef(0, "the %s's bite has weakened you",
 +			mon_name(monster));
  		rogue.str_current--;
  		print_stats(STAT_STRENGTH);
  	}
 @@ -450,7 +444,7 @@ drain_life()
  	n = get_rand(1, 3);		/* 1 Hp, 2 Str, 3 both */
  
  	if ((n != 2) || (!sustain_strength)) {
 -		message("you feel weaker", 0);
 +		messagef(0, "you feel weaker");
  	}
  	if (n != 2) {
  		rogue.hp_max--;
 @@ -472,8 +466,6 @@ boolean
  m_confuse(monster)
  	object *monster;
  {
 -	char msg[80];
 -
  	if (!rogue_can_see(monster->row, monster->col)) {
  		return(0);
  	}
 @@ -483,8 +475,8 @@ m_confuse(monster)
  	}
  	if (rand_percent(55)) {
  		monster->m_flags &= (~CONFUSES);
 -		sprintf(msg, "the gaze of the %s has confused you", mon_name(monster));
 -		message(msg, 1);
 +		messagef(1, "the gaze of the %s has confused you", 
 +			mon_name(monster));
  		cnfs();
  		return(1);
  	}
 Index: throw.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/throw.c,v
 retrieving revision 1.7
 diff -u -p -r1.7 throw.c
 --- throw.c	30 Mar 2006 05:04:22 -0000	1.7
 +++ throw.c	27 Dec 2007 22:52:00 -0000
 @@ -67,7 +67,7 @@ throw()
  	while (!is_direction(dir = rgetchar(), &d)) {
  		sound_bell();
  		if (first_miss) {
 -			message("direction? ", 0);
 +			messagef(0, "direction? ");
  			first_miss = 0;
  		}
  	}
 @@ -81,11 +81,11 @@ throw()
  	check_message();
  
  	if (!(weapon = get_letter_object(wch))) {
 -		message("no such item.", 0);
 +		messagef(0, "no such item.");
  		return;
  	}
  	if ((weapon->in_use_flags & BEING_USED) && weapon->is_cursed) {
 -		message(curse_message, 0);
 +		messagef(0, curse_message);
  		return;
  	}
  	row = rogue.row; col = rogue.col;
 @@ -142,15 +142,15 @@ throw_at_monster(monster, weapon)
  	}
  	t = weapon->quantity;
  	weapon->quantity = 1;
 -	sprintf(hit_message, "the %s", name_of(weapon));
 +	snprintf(hit_message, HIT_MESSAGE_SIZE, "the %s", name_of(weapon));
  	weapon->quantity = t;
  
  	if (!rand_percent(hit_chance)) {
 -		(void) strcat(hit_message, "misses  ");
 +		(void) strlcat(hit_message, "misses  ", HIT_MESSAGE_SIZE);
  		return(0);
  	}
  	s_con_mon(monster);
 -	(void) strcat(hit_message, "hit  ");
 +	(void) strlcat(hit_message, "hit  ", HIT_MESSAGE_SIZE);
  	(void) mon_damage(monster, damage);
  	return(1);
  }
 @@ -207,7 +207,6 @@ flop_weapon(weapon, row, col)
  {
  	object *new_weapon, *monster;
  	short i = 0;
 -	char msg[80];
  	boolean found = 0;
  	short mch, dch;
  	unsigned short mon;
 @@ -257,10 +256,9 @@ flop_weapon(weapon, row, col)
  
  		t = weapon->quantity;
  		weapon->quantity = 1;
 -		sprintf(msg, "the %svanishes as it hits the ground",
 -		name_of(weapon));
 +		messagef(0, "the %svanishes as it hits the ground",
 +			name_of(weapon));
  		weapon->quantity = t;
 -		message(msg, 0);
  	}
  }
  
 Index: trap.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/trap.c,v
 retrieving revision 1.6
 diff -u -p -r1.6 trap.c
 --- trap.c	7 Aug 2003 09:37:40 -0000	1.6
 +++ trap.c	27 Dec 2007 22:52:00 -0000
 @@ -99,7 +99,7 @@ trap_player(row, col)
  	}
  	dungeon[row][col] &= (~HIDDEN);
  	if (rand_percent(rogue.exp + ring_exp)) {
 -		message("the trap failed", 1);
 +		messagef(1, "the trap failed");
  		return;
  	}
  	switch(t) {
 @@ -108,7 +108,7 @@ trap_player(row, col)
  		new_level_message = trap_strings[(t*2)+1];
  		break;
  	case BEAR_TRAP:
 -		message(trap_strings[(t*2)+1], 1);
 +		messagef(1, "%s", trap_strings[(t*2)+1]);
  		bear_trap = get_rand(4, 7);
  		break;
  	case TELE_TRAP:
 @@ -116,7 +116,7 @@ trap_player(row, col)
  		tele();
  		break;
  	case DART_TRAP:
 -		message(trap_strings[(t*2)+1], 1);
 +		messagef(1, "%s", trap_strings[(t*2)+1]);
  		rogue.hp_current -= get_damage("1d6", 1);
  		if (rogue.hp_current <= 0) {
  			rogue.hp_current = 0;
 @@ -131,11 +131,11 @@ trap_player(row, col)
  		}
  		break;
  	case SLEEPING_GAS_TRAP:
 -		message(trap_strings[(t*2)+1], 1);
 +		messagef(1, "%s", trap_strings[(t*2)+1]);
  		take_a_nap();
  		break;
  	case RUST_TRAP:
 -		message(trap_strings[(t*2)+1], 1);
 +		messagef(1, "%s", trap_strings[(t*2)+1]);
  		rust((object *) 0);
  		break;
  	}
 @@ -191,7 +191,7 @@ id_trap()
  {
  	short dir, row, col, d, t;
  
 -	message("direction? ", 0);
 +	messagef(0, "direction? ");
  
  	while (!is_direction(dir = rgetchar(), &d)) {
  		sound_bell();
 @@ -208,9 +208,9 @@ id_trap()
  
  	if ((dungeon[row][col] & TRAP) && (!(dungeon[row][col] & HIDDEN))) {
  		t = trap_at(row, col);
 -		message(trap_strings[t*2], 0);
 +		messagef(0, "%s", trap_strings[t*2]);
  	} else {
 -		message("no trap there", 0);
 +		messagef(0, "no trap there");
  	}
  }
  
 @@ -269,7 +269,8 @@ search(n, is_auto)
  						shown++;
  						if (dungeon[row][col] & TRAP) {
  							t = trap_at(row, col);
 -							message(trap_strings[t*2], 1);
 +							messagef(1, "%s",
 +								 trap_strings[t*2]);
  						}
  					}
  				}
 Index: use.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/use.c,v
 retrieving revision 1.6
 diff -u -p -r1.6 use.c
 --- use.c	7 Aug 2003 09:37:40 -0000	1.6
 +++ use.c	27 Dec 2007 22:52:01 -0000
 @@ -70,7 +70,6 @@ void
  quaff()
  {
  	short ch;
 -	char buf[80];
  	object *obj;
  
  	ch = pack_letter("quaff what?", POTION);
 @@ -79,17 +78,16 @@ quaff()
  		return;
  	}
  	if (!(obj = get_letter_object(ch))) {
 -		message("no such item.", 0);
 +		messagef(0, "no such item.");
  		return;
  	}
  	if (obj->what_is != POTION) {
 -		message("you can't drink that", 0);
 +		messagef(0, "you can't drink that");
  		return;
  	}
  	switch(obj->which_kind) {
  		case INCREASE_STRENGTH:
 -			message("you feel stronger now, what bulging muscles!",
 -			0);
 +			messagef(0, "you feel stronger now, what bulging muscles!");
  			rogue.str_current++;
  			if (rogue.str_current > rogue.str_max) {
  				rogue.str_max = rogue.str_current;
 @@ -97,14 +95,14 @@ quaff()
  			break;
  		case RESTORE_STRENGTH:
  			rogue.str_current = rogue.str_max;
 -			message("this tastes great, you feel warm all over", 0);
 +			messagef(0, "this tastes great, you feel warm all over");
  			break;
  		case HEALING:
 -			message("you begin to feel better", 0);
 +			messagef(0, "you begin to feel better");
  			potion_heal(0);
  			break;
  		case EXTRA_HEALING:
 -			message("you begin to feel much better", 0);
 +			messagef(0, "you begin to feel much better");
  			potion_heal(1);
  			break;
  		case POISON:
 @@ -114,27 +112,27 @@ quaff()
  					rogue.str_current = 1;
  				}
  			}
 -			message("you feel very sick now", 0);
 +			messagef(0, "you feel very sick now");
  			if (halluc) {
  				unhallucinate();
  			}
  			break;
  		case RAISE_LEVEL:
  			rogue.exp_points = level_points[rogue.exp - 1];
 -			message("you suddenly feel much more skillful", 0);
 +			messagef(0, "you suddenly feel much more skillful");
  			add_exp(1, 1);
  			break;
  		case BLINDNESS:
  			go_blind();
  			break;
  		case HALLUCINATION:
 -			message("oh wow, everything seems so cosmic", 0);
 +			messagef(0, "oh wow, everything seems so cosmic");
  			halluc += get_rand(500, 800);
  			break;
  		case DETECT_MONSTER:
  			show_monsters();
  			if (!(level_monsters.next_monster)) {
 -				message(strange_feeling, 0);
 +				messagef(0, "%s", strange_feeling);
  			}
  			break;
  		case DETECT_OBJECTS:
 @@ -143,29 +141,29 @@ quaff()
  					show_objects();
  				}
  			} else {
 -				message(strange_feeling, 0);
 +				messagef(0, "%s", strange_feeling);
  			}
  			break;
  		case CONFUSION:
 -			message((halluc ? "what a trippy feeling" :
 -			"you feel confused"), 0);
 +			messagef(0, (halluc ? "what a trippy feeling" :
 +			"you feel confused"));
  			cnfs();
  			break;
  		case LEVITATION:
 -			message("you start to float in the air", 0);
 +			messagef(0, "you start to float in the air");
  			levitate += get_rand(15, 30);
  			being_held = bear_trap = 0;
  			break;
  		case HASTE_SELF:
 -			message("you feel yourself moving much faster", 0);
 +			messagef(0, "you feel yourself moving much faster");
  			haste_self += get_rand(11, 21);
  			if (!(haste_self % 2)) {
  				haste_self++;
  			}
  			break;
  		case SEE_INVISIBLE:
 -			sprintf(buf, "hmm, this potion tastes like %sjuice", fruit);
 -			message(buf, 0);
 +			messagef(0, "hmm, this potion tastes like %sjuice", 
 +				 fruit);
  			if (blind) {
  				unblind();
  			}
 @@ -185,7 +183,6 @@ read_scroll()
  {
  	short ch;
  	object *obj;
 -	char msg[DCOLS];
  
  	ch = pack_letter("read what?", SCROL);
  
 @@ -193,17 +190,16 @@ read_scroll()
  		return;
  	}
  	if (!(obj = get_letter_object(ch))) {
 -		message("no such item.", 0);
 +		messagef(0, "no such item.");
  		return;
  	}
  	if (obj->what_is != SCROL) {
 -		message("you can't read that", 0);
 +		messagef(0, "you can't read that");
  		return;
  	}
  	switch(obj->which_kind) {
  		case SCARE_MONSTER:
 -			message("you hear a maniacal laughter in the distance",
 -			0);
 +			messagef(0, "you hear a maniacal laughter in the distance");
  			break;
  		case HOLD_MONSTER:
  			hold_monster();
 @@ -211,11 +207,10 @@ read_scroll()
  		case ENCH_WEAPON:
  			if (rogue.weapon) {
  				if (rogue.weapon->what_is == WEAPON) {
 -					sprintf(msg, "your %sglow%s %sfor a moment",
 -					name_of(rogue.weapon),
 -					((rogue.weapon->quantity <= 1) ? "s" : ""),
 -					get_ench_color());
 -					message(msg, 0);
 +					messagef(0, "your %sglow%s %sfor a moment",
 +						name_of(rogue.weapon),
 +						((rogue.weapon->quantity <= 1) ? "s" : ""),
 +						get_ench_color());
  					if (coin_toss()) {
  						rogue.weapon->hit_enchant++;
  					} else {
 @@ -224,23 +219,22 @@ read_scroll()
  				}
  				rogue.weapon->is_cursed = 0;
  			} else {
 -				message("your hands tingle", 0);
 +				messagef(0, "your hands tingle");
  			}
  			break;
  		case ENCH_ARMOR:
  			if (rogue.armor) {
 -				sprintf(msg, "your armor glows %sfor a moment",
 -				get_ench_color());
 -				message(msg, 0);
 +				messagef(0, "your armor glows %sfor a moment",
 +					get_ench_color());
  				rogue.armor->d_enchant++;
  				rogue.armor->is_cursed = 0;
  				print_stats(STAT_ARMOR);
  			} else {
 -				message("your skin crawls", 0);
 +				messagef(0, "your skin crawls");
  			}
  			break;
  		case IDENTIFY:
 -			message("this is a scroll of identify", 0);
 +			messagef(0, "this is a scroll of identify");
  			obj->identified = 1;
  			id_scrolls[obj->which_kind].id_status = IDENTIFIED;
  			idntfy();
 @@ -249,22 +243,22 @@ read_scroll()
  			tele();
  			break;
  		case SLEEP:
 -			message("you fall asleep", 0);
 +			messagef(0, "you fall asleep");
  			take_a_nap();
  			break;
  		case PROTECT_ARMOR:
  			if (rogue.armor) {
 -				message( "your armor is covered by a shimmering gold shield",0);
 +				messagef(0, "your armor is covered by a shimmering gold shield");
  				rogue.armor->is_protected = 1;
  				rogue.armor->is_cursed = 0;
  			} else {
 -				message("your acne seems to have disappeared", 0);
 +				messagef(0, "your acne seems to have disappeared");
  			}
  			break;
  		case REMOVE_CURSE:
 -				message((!halluc) ?
 +				messagef(0, (!halluc) ?
  					"you feel as though someone is watching over you" :
 -					"you feel in touch with the universal oneness", 0);
 +					"you feel in touch with the universal oneness");
  			uncurse_all();
  			break;
  		case CREATE_MONSTER:
 @@ -274,13 +268,13 @@ read_scroll()
  			aggravate();
  			break;
  		case MAGIC_MAPPING:
 -			message("this scroll seems to have a map on it", 0);
 +			messagef(0, "this scroll seems to have a map on it");
  			draw_magic_map();
  			break;
  		case CON_MON:
  			con_mon = 1;
 -			sprintf(msg, "your hands glow %sfor a moment", get_ench_color());
 -			message(msg, 0);
 +			messagef(0, "your hands glow %sfor a moment", 
 +				 get_ench_color());
  			break;
  	}
  	if (id_scrolls[obj->which_kind].id_status != CALLED) {
 @@ -378,8 +372,8 @@ AGAIN:
  		return;
  	}
  	if (!(obj = get_letter_object(ch))) {
 -		message("no such item, try again", 0);
 -		message("", 0);
 +		messagef(0, "no such item, try again");
 +		messagef(0, "%s", "");	/* gcc objects to just "" */
  		check_message();
  		goto AGAIN;
  	}
 @@ -388,8 +382,8 @@ AGAIN:
  		id_table = get_id_table(obj);
  		id_table[obj->which_kind].id_status = IDENTIFIED;
  	}
 -	get_desc(obj, desc);
 -	message(desc, 0);
 +	get_desc(obj, desc, sizeof(desc));
 +	messagef(0, "%s", desc);
  }
  
  void
 @@ -398,7 +392,6 @@ eat()
  	short ch;
  	short moves;
  	object *obj;
 -	char buf[70];
  
  	ch = pack_letter("eat what?", FOOD);
  
 @@ -406,24 +399,23 @@ eat()
  		return;
  	}
  	if (!(obj = get_letter_object(ch))) {
 -		message("no such item.", 0);
 +		messagef(0, "no such item.");
  		return;
  	}
  	if (obj->what_is != FOOD) {
 -		message("you can't eat that", 0);
 +		messagef(0, "you can't eat that");
  		return;
  	}
  	if ((obj->which_kind == FRUIT) || rand_percent(60)) {
  		moves = get_rand(950, 1150);
  		if (obj->which_kind == RATION) {
 -			message("yum, that tasted good", 0);
 +			messagef(0, "yum, that tasted good");
  		} else {
 -			sprintf(buf, "my, that was a yummy %s", fruit);
 -			message(buf, 0);
 +			messagef(0, "my, that was a yummy %s", fruit);
  		}
  	} else {
  		moves = get_rand(750, 950);
 -		message("yuk, that food tasted awful", 0);
 +		messagef(0, "yuk, that food tasted awful");
  		add_exp(2, 1);
  	}
  	rogue.moves_left /= 3;
 @@ -459,11 +451,11 @@ hold_monster()
  		}
  	}
  	if (mcount == 0) {
 -		message("you feel a strange sense of loss", 0);
 +		messagef(0, "you feel a strange sense of loss");
  	} else if (mcount == 1) {
 -		message("the monster freezes", 0);
 +		messagef(0, "the monster freezes");
  	} else {
 -		message("the monsters around you freeze", 0);
 +		messagef(0, "the monsters around you freeze");
  	}
  }
  
 @@ -515,14 +507,14 @@ unhallucinate()
  {
  	halluc = 0;
  	relight();
 -	message("everything looks SO boring now", 1);
 +	messagef(1, "everything looks SO boring now");
  }
  
  void
  unblind()
  {
  	blind = 0;
 -	message("the veil of darkness lifts", 1);
 +	messagef(1, "the veil of darkness lifts");
  	relight();
  	if (halluc) {
  		hallucinate();
 @@ -555,7 +547,7 @@ take_a_nap()
  		mv_mons();
  	}
  	md_sleep(1);
 -	message(you_can_move_again, 0);
 +	messagef(0, "%s", you_can_move_again);
  }
  
  void
 @@ -564,7 +556,7 @@ go_blind()
  	short i, j;
  
  	if (!blind) {
 -		message("a cloak of darkness falls around you", 0);
 +		messagef(0, "a cloak of darkness falls around you");
  	}
  	blind += get_rand(500, 800);
  
 @@ -610,11 +602,8 @@ cnfs()
  void
  unconfuse()
  {
 -	char msg[80];
 -
  	confused = 0;
 -	sprintf(msg, "you feel less %s now", (halluc ? "trippy" : "confused"));
 -	message(msg, 1);
 +	messagef(1, "you feel less %s now", (halluc ? "trippy" : "confused"));
  }
  
  void
 Index: zap.c
 ===================================================================
 RCS file: /cvsroot/src/games/rogue/zap.c,v
 retrieving revision 1.6
 diff -u -p -r1.6 zap.c
 --- zap.c	7 Aug 2003 09:37:40 -0000	1.6
 +++ zap.c	27 Dec 2007 22:52:01 -0000
 @@ -69,7 +69,7 @@ zapp()
  	while (!is_direction(dir = rgetchar(), &d)) {
  		sound_bell();
  		if (first_miss) {
 -			message("direction? ", 0);
 +			messagef(0, "direction? ");
  			first_miss = 0;
  		}
  	}
 @@ -83,15 +83,15 @@ zapp()
  	check_message();
  
  	if (!(wand = get_letter_object(wch))) {
 -		message("no such item.", 0);
 +		messagef(0, "no such item.");
  		return;
  	}
  	if (wand->what_is != WAND) {
 -		message("you can't zap with that", 0);
 +		messagef(0, "you can't zap with that");
  		return;
  	}
  	if (wand->class <= 0) {
 -		message("nothing happens", 0);
 +		messagef(0, "nothing happens");
  	} else {
  		wand->class--;
  		row = rogue.row; col = rogue.col;
 @@ -198,7 +198,7 @@ zap_monster(monster, kind)
  			FLAMES | IMITATES | CONFUSES | SEEKS_GOLD | HOLDS));
  		break;
  	case DO_NOTHING:
 -		message("nothing happens", 0);
 +		messagef(0, "nothing happens");
  		break;
  	}
  }
 @@ -230,17 +230,18 @@ wizardize()
  
  	if (wizard) {
  		wizard = 0;
 -		message("not wizard anymore", 0);
 +		messagef(0, "not wizard anymore");
  	} else {
 -		if (get_input_line("wizard's password:", "", buf, "", 0, 0)) {
 +		if (get_input_line("wizard's password:", "", buf, sizeof(buf),
 +				"", 0, 0)) {
  			(void) xxx(1);
  			xxxx(buf, strlen(buf));
  			if (!strncmp(buf, "\247\104\126\272\115\243\027", 7)) {
  				wizard = 1;
  				score_only = 1;
 -				message("Welcome, mighty wizard!", 0);
 +				messagef(0, "Welcome, mighty wizard!");
  			} else {
 -				message("sorry", 0);
 +				messagef(0, "sorry");
  			}
  		}
  	}
 @@ -281,7 +282,6 @@ bounce(ball, dir, row, col, r)
  	short ball, dir, row, col, r;
  {
  	short orow, ocol;
 -	char buf[DCOLS];
  	const char *s;
  	short i, ch, new_dir = -1, damage;
  	static short btime;
 @@ -298,8 +298,7 @@ bounce(ball, dir, row, col, r)
  		s = "ice";
  	}
  	if (r > 1) {
 -		sprintf(buf, "the %s bounces", s);
 -		message(buf, 0);
 +		messagef(0, "the %s bounces", s);
  	}
  	orow = row;
  	ocol = col;
 @@ -336,8 +335,8 @@ bounce(ball, dir, row, col, r)
  
  		wake_up(monster);
  		if (rand_percent(33)) {
 -			sprintf(buf, "the %s misses the %s", s, mon_name(monster));
 -			message(buf, 0);
 +			messagef(0, "the %s misses the %s", s, 
 +				mon_name(monster));
  			goto ND;
  		}
  		if (ball == FIRE) {
 @@ -352,14 +351,14 @@ bounce(ball, dir, row, col, r)
  			} else {
  				damage = (monster->hp_to_kill / 2) + 1;
  			}
 -			sprintf(buf, "the %s hits the %s", s, mon_name(monster));
 -			message(buf, 0);
 +			messagef(0, "the %s hits the %s", s,
 +				mon_name(monster));
  			(void) mon_damage(monster, damage);
  		} else {
  			damage = -1;
  			if (!(monster->m_flags & FREEZES)) {
  				if (rand_percent(33)) {
 -					message("the monster is frozen", 0);
 +					messagef(0, "the monster is frozen");
  					monster->m_flags |= (ASLEEP | NAPPING);
  					monster->nap_length = get_rand(3, 6);
  				} else {
 @@ -369,15 +368,14 @@ bounce(ball, dir, row, col, r)
  				damage = -2;
  			}
  			if (damage != -1) {
 -				sprintf(buf, "the %s hits the %s", s, mon_name(monster));
 -				message(buf, 0);
 +				messagef(0, "the %s hits the %s", s, 
 +					mon_name(monster));
  				(void) mon_damage(monster, damage);
  			}
  		}
  	} else if ((row == rogue.row) && (col == rogue.col)) {
  		if (rand_percent(10 + (3 * get_armor_class(rogue.armor)))) {
 -			sprintf(buf, "the %s misses", s);
 -			message(buf, 0);
 +			messagef(0, "the %s misses", s);
  			goto ND;
  		} else {
  			damage = get_rand(3, (3 * rogue.exp));
 @@ -385,10 +383,9 @@ bounce(ball, dir, row, col, r)
  				damage = (damage * 3) / 2;
  				damage -= get_armor_class(rogue.armor);
  			}
 -			sprintf(buf, "the %s hits", s);
  			rogue_damage(damage, (object *) 0,
  					((ball == FIRE) ? KFIRE : HYPOTHERMIA));
 -			message(buf, 0);
 +			messagef(0, "the %s hits", s);
  		}
  	} else {
  		short nrow, ncol;
 
 
 -- 
    - David A. Holland / dholland@eecs.harvard.edu