text: /*
   * This file has all the code for the option command.  I would rather
   * this command were not necessary, but it is the only way to keep the
   * wolves off of my back.
   *
   * @(#)options.c	4.24 (Berkeley) 05/10/83
   *
   * Rogue: Exploring the Dungeons of Doom
   * Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
   * All rights reserved.
   *
   * See the file LICENSE.TXT for full copyright and licensing information.
   */
  
  #include <stdlib.h>
  #include <ctype.h>
  #include <string.h>
  #include "rogue.h"
  
  #define	EQSTR(a, b, c)	(strncmp(a, b, c) == 0)
  
  #define	NUM_OPTS	(sizeof optlist / sizeof (OPTION))
  
  /*
   * description of an option and what to do with it
   */
  struct optstruct {
      char	*o_name;	/* option name */
      char	*o_prompt;	/* prompt for interactive entry */
      void 	*o_opt;		/* pointer to thing to set */
  				/* function to print value */
      void 	(*o_putfunc)(void *opt);
  				/* function to get value interactively */
      int		(*o_getfunc)(void *opt, WINDOW *win);
  };
  
  typedef struct optstruct	OPTION;
  
  void	pr_optname(OPTION *op);
  
  OPTION	optlist[] = {
      {"terse",	 "Terse output",
  		 &terse,	put_bool,	get_bool	},
      {"flush",	 "Flush typeahead during battle",
  		 &fight_flush,	put_bool,	get_bool	},
      {"jump",	 "Show position only at end of run",
  		 &jump,		put_bool,	get_bool	},
      {"seefloor", "Show the lamp-illuminated floor",
  		 &see_floor,	put_bool,	get_sf		},
      {"passgo",	"Follow turnings in passageways",
  		 &passgo,	put_bool,	get_bool	},
      {"inven",	"Inventory style",
  		 &inv_type,	put_inv_t,	get_inv_t	},
      {"name",	 "Name",
  		 whoami,	put_str,	get_str		},
      {"fruit",	 "Fruit",
  		 fruit,		put_str,	get_str		},
      {"file",	 "Save file",
  		 file_name,	put_str,	get_str		}
  };
  
  /*
   * option:
   *	Print and then set options from the terminal
   */
  
  void
  option()
  {
      OPTION	*op;
      int		retval;
  
      wclear(hw);
      /*
       * Display current values of options
       */
      for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)
      {
  		pr_optname(op);
  		(*op->o_putfunc)(op->o_opt);
  		waddch(hw, '\n');
      }
      /*
       * Set values
       */
      wmove(hw, 0, 0);
      for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)
      {
  		pr_optname(op);
  		retval = (*op->o_getfunc)(op->o_opt, hw);
  		if (retval)
  		{
  			if (retval == QUIT)
  				break;
  			else if (op > optlist) /* MINUS */
  			{	
  				wmove(hw, (int)(op - optlist) - 1, 0);
  				op -= 2;
  			}
  			else	/* trying to back up beyond the top */
  			{
  				putchar('\007');
  				wmove(hw, 0, 0);
  				op--;
  			}
  		}
      }
      /*
       * Switch back to original screen
       */
      wmove(hw, LINES - 1, 0);
      waddstr(hw, RS_PRESS_KEY_TO_CONTINUE2);
      wrefresh(hw);
      wait_for(RC_KEY_CONTINUE);
      clearok(curscr, TRUE);
      touchwin(stdscr);
      after = FALSE;
  }
  
  /*
   * pr_optname:
   *	Print out the option name prompt
   */
  
  void
  pr_optname(OPTION *op)
  {
      wprintw(hw, "%s (\"%s\"): ", op->o_prompt, op->o_name);
  }
  
  /*
   * put_bool
   *	Put out a boolean
   */
  
  void
  put_bool(void *b)
  {
      waddstr(hw, *(bool *) b ? "True" : "False");
  }
  
  /*
   * put_str:
   *	Put out a string
   */
  
  void
  put_str(void *str)
  {
      waddstr(hw, (char *) str);
  }
  
  /*
   * put_inv_t:
   *	Put out an inventory type
   */
  
  void
  put_inv_t(void *ip)
  {
      waddstr(hw, inv_t_name[*(int *) ip]);
  }
  
  /*
   * get_bool:
   *	Allow changing a boolean option and print it out
   */
  int
  get_bool(void *vp, WINDOW *win)
  {
      bool *bp = (bool *) vp;
      int oy, ox;
      bool op_bad;
  
      op_bad = TRUE;
      getyx(win, oy, ox);
      waddstr(win, *bp ? "True" : "False");
      while (op_bad)	
      {
  		wmove(win, oy, ox);
  		wrefresh(win);
  		switch (readchar(0))
  		{
  		case 't':
  		case 'T':
  			*bp = TRUE;
  			op_bad = FALSE;
  			break;
  		case 'f':
  		case 'F':
  			*bp = FALSE;
  			op_bad = FALSE;
  			break;
  		case '\n':
  		case '\r':
  			op_bad = FALSE;
  			break;
  		case ESCAPE:
  			return QUIT;
  			break;
  		case '-':
  			return MINUS;
  			break;
  		default:
  			wmove(win, oy, ox + 10);
  			waddstr(win, "(T or F)");
  			break;
  		}
      }
      wmove(win, oy, ox);
      waddstr(win, *bp ? "True" : "False");
      waddch(win, '\n');
      return NORM;
  }
  
  /*
   * get_sf:
   *	Change value and handle transition problems from see_floor to
   *	!see_floor.
   */
  int
  get_sf(void *vp, WINDOW *win)
  {
      bool	*bp = (bool *) vp;
      bool	was_sf;
      int		retval;
  
      was_sf = see_floor;
      retval = get_bool(bp, win);
      if (retval == QUIT) 
  		return(QUIT);
      if (was_sf != see_floor)
      {
  		if (!see_floor) 
  		{
  			see_floor = TRUE;
  			erase_lamp(&hero, proom);
  			see_floor = FALSE;
  		}
  		else
  			look(FALSE);
      }
      return(NORM);
  }
  
  /*
   * get_str:
   *	Set a string option
   */
  #define MAXINP	50	/* max string to read from terminal or environment */
  
  int
  get_str(void *vopt, WINDOW *win)
  {
      char *opt = (char *) vopt;
      int oy, ox;
      static char buf[MAXSTR];
  
      getyx(win, oy, ox);
      wrefresh(win);
      
  	if( wgetnstre(win, buf, MAXINP, NAME_CHARS) != ERR) {
  		int l;
  
  		l = strlen(buf);
  		if(l == 0)
  			return QUIT;
  		if(l > 0) {
  			strucpy(opt, buf, l);
  			mvwprintw(win, oy, ox, "%s\n", opt);
  			wrefresh(win);
  			if (win == stdscr)
  				mpos += l;
  		}
  		return NORM;
  	}
  	return ERR;
  }
  
  /*
   * get_inv_t
   *	Get an inventory type name
   */
  int
  get_inv_t(void *vp, WINDOW *win)
  {
      int *ip = (int *) vp;
      int oy, ox;
      bool op_bad;
  
      op_bad = TRUE;
      getyx(win, oy, ox);
      waddstr(win, inv_t_name[*ip]);
      while (op_bad)	
      {
  		wmove(win, oy, ox);
  		wrefresh(win);
  		switch (readchar(0))
  		{
  		case 'o':
  		case 'O':
  			*ip = INV_OVER;
  			op_bad = FALSE;
  			break;
  		case 's':
  		case 'S':
  			*ip = INV_SLOW;
  			op_bad = FALSE;
  			break;
  		case 'c':
  		case 'C':
  			*ip = INV_CLEAR;
  			op_bad = FALSE;
  			break;
  		case '\n':
  		case '\r':
  			op_bad = FALSE;
  			break;
  		case ESCAPE:
  			return QUIT;
  			break;
  		case '-':
  			return MINUS;
  			break;
  		default:
  			wmove(win, oy, ox + 15);
  			waddstr(win, "(O, S, or C)");
  			break;
  		}
      }
      mvwprintw(win, oy, ox, "%s\n", inv_t_name[*ip]);
      return NORM;
  }
  	
  
  #ifdef MASTER
  /*
   * get_num:
   *	Get a numeric option
   */
  int
  get_num(void *vp, WINDOW *win)
  {
      short *opt = (short *) vp;
      int i;
      static char buf[MAXSTR];
  
      if ((i = get_str(buf, win)) == NORM)
  		*opt = (short) atoi(buf);
      return i;
  }
  #endif
  
  /*
   * parse_opts:
   *	Parse options from string, usually taken from the environment.
   *	The string is a series of comma seperated values, with booleans
   *	being stated as "name" (true) or "noname" (false), and strings
   *	being "name=....", with the string being defined up to a comma
   *	or the end of the entire option string.
   */
  
  void
  parse_opts(char *str)
  {
      char *sp;
      OPTION *op;
      int len;
      char **i;
      char *start;
  
      while (*str)
      {
  		/*
  		 * Get option name
  		 */
  		for (sp = str; isalpha(*sp); sp++)
  			continue;
  		len = (int)(sp - str);
  		/*
  		 * Look it up and deal with it
  		 */
  		for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)
  		{
  			if (EQSTR(str, op->o_name, len))
  			{
  				if (op->o_putfunc == put_bool)	/* if option is a boolean */
  					*(bool *)op->o_opt = TRUE;	/* NOSTRICT */
  				else				/* string option */
  				{
  					/*
  					 * Skip to start of string value
  					 */
  					for (str = sp + 1; *str == '='; str++)
  						continue;
  					if (*str == '~')
  					{
  						strcpy((char *) op->o_opt, home);	  /* NOSTRICT */
  						start = (char *) op->o_opt + strlen(home);/* NOSTRICT */
  						while (*++str == '/')
  							continue;
  					}
  					else
  						start = (char *) op->o_opt;	/* NOSTRICT */
  					/*
  					 * Skip to end of string value
  					 */
  					for (sp = str + 1; *sp && *sp != ','; sp++)
  						continue;
  					/*
  					 * check for type of inventory
  					 */
  					if (op->o_putfunc == put_inv_t)
  					{
  						if (islower(*str))
  							*str = (char) toupper(*str);
  						for (i = inv_t_name; i < &inv_t_name[INV_TYPES]; i++)
  						{
  							if (strncmp(str, *i, sp - str) == 0)
  							{
  								inv_type = (int)(i - inv_t_name);
  								break;
  							}
  						}
  					}
  					else
  						strucpy(start, str, (int)(sp - str));
  				}
  				break;
  			}
  			/*
  			 * check for "noname" for booleans
  			 */
  			else if (op->o_putfunc == put_bool
  			  && EQSTR(str, "no", 2) && EQSTR(str + 2, op->o_name, len - 2))
  			{
  				*(bool *)op->o_opt = FALSE;	/* NOSTRICT */
  				break;
  			}
  		}
  		/*
  		 * skip to start of next option name
  		 */
  		while (*sp && !isalpha(*sp))
  			sp++;
  		str = sp;
      }
  }
  
  /*
   * strucpy:
   *	Copy string using unctrl for things
   */
  
  void
  strucpy(char *s1, char *s2, int len)
  {
      if (len > MAXINP)
  		len = MAXINP;
      while (len--)
      {
  		if (isprint(*s2) || *s2 == ' ')
  			*s1++ = *s2;
  		s2++;
      }
      *s1 = '\0';
  }
  