Annotation of early-roguelike/rogue5/options.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: * This file has all the code for the option command. I would rather
3: * this command were not necessary, but it is the only way to keep the
4: * wolves off of my back.
5: *
6: * @(#)options.c 4.24 (Berkeley) 05/10/83
7: *
8: * Rogue: Exploring the Dungeons of Doom
9: * Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
10: * All rights reserved.
11: *
12: * See the file LICENSE.TXT for full copyright and licensing information.
13: */
14:
15: #include <stdlib.h>
16: #include <curses.h>
17: #include <ctype.h>
18: #include <string.h>
19: #include "rogue.h"
20:
21: #define EQSTR(a, b, c) (strncmp(a, b, c) == 0)
22:
23: #define NUM_OPTS (sizeof optlist / sizeof (OPTION))
24:
25: /*
26: * description of an option and what to do with it
27: */
28: struct optstruct {
29: char *o_name; /* option name */
30: char *o_prompt; /* prompt for interactive entry */
31: void *o_opt; /* pointer to thing to set */
32: /* function to print value */
33: void (*o_putfunc)(void *opt);
34: /* function to get value interactively */
35: int (*o_getfunc)(void *opt, WINDOW *win);
36: };
37:
38: typedef struct optstruct OPTION;
39:
40: void pr_optname(const OPTION *op);
41: int allowchange(const OPTION *op);
42:
43: static const OPTION optlist[] = {
44: {"terse", "Terse output",
45: &terse, put_bool, get_bool },
46: {"flush", "Flush typeahead during battle",
47: &fight_flush, put_bool, get_bool },
48: {"jump", "Show position only at end of run",
49: &jump, put_bool, get_bool },
50: {"seefloor", "Show the lamp-illuminated floor",
51: &see_floor, put_bool, get_sf },
52: {"passgo", "Follow turnings in passageways",
53: &passgo, put_bool, get_bool },
54: {"tombstone", "Print out tombstone when killed",
55: &tombstone, put_bool, get_bool },
56: {"inven", "Inventory style",
57: &inv_type, put_inv_t, get_inv_t },
58: {"name", "Name",
59: whoami, put_str, get_str },
60: {"fruit", "Fruit",
61: fruit, put_str, get_str },
62: {"file", "Save file",
63: file_name, put_str, get_str }
64: };
65:
66: /*
67: * option:
68: * Print and then set options from the terminal
69: */
70:
71: void
72: option(void)
73: {
74: const OPTION *op;
75: int retval;
76:
77: wclear(hw);
78: /*
79: * Display current values of options
80: */
81: for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)
82: {
83: if (allowchange(op))
84: {
85: pr_optname(op);
86: (*op->o_putfunc)(op->o_opt);
87: waddch(hw, '\n');
88: }
89: }
90: /*
91: * Set values
92: */
93: wmove(hw, 0, 0);
94: for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)
95: {
96: if (!allowchange(op))
97: continue;
98: pr_optname(op);
99: retval = (*op->o_getfunc)(op->o_opt, hw);
100: if (retval)
101: {
102: if (retval == QUIT)
103: break;
104: #if 0
105: /* Support for MINUS removed until this section is rewritten. */
106: else if (op > optlist) { /* MINUS */
107: wmove(hw, (int)(op - optlist) - 1, 0);
108: op -= 2;
109: }
110: else /* trying to back up beyond the top */
111: {
112: putchar('\007');
113: wmove(hw, 0, 0);
114: op--;
115: }
116: #else
117: break;
118: #endif
119: }
120: }
121: /*
122: * Switch back to original screen
123: */
124: wmove(hw, LINES - 1, 0);
125: waddstr(hw, "--Press space to continue--");
126: wrefresh(hw);
127: wait_for(hw, ' ');
128: clearok(curscr, TRUE);
129: touchwin(stdscr);
130: after = FALSE;
131: }
132:
133: /*
134: * pr_optname:
135: * Print out the option name prompt
136: */
137:
138: void
139: pr_optname(const OPTION *op)
140: {
141: wprintw(hw, "%s (\"%s\"): ", op->o_prompt, op->o_name);
142: }
143:
144: /*
145: * put_bool
146: * Put out a boolean
147: */
148:
149: void
150: put_bool(void *b)
151: {
152: waddstr(hw, *(int *) b ? "True" : "False");
153: }
154:
155: /*
156: * put_str:
157: * Put out a string
158: */
159:
160: void
161: put_str(void *str)
162: {
163: waddstr(hw, (char *) str);
164: }
165:
166: /*
167: * put_inv_t:
168: * Put out an inventory type
169: */
170:
171: void
172: put_inv_t(void *ip)
173: {
174: waddstr(hw, inv_t_name[*(int *) ip]);
175: }
176:
177: /*
178: * get_bool:
179: * Allow changing a boolean option and print it out
180: */
181: int
182: get_bool(void *vp, WINDOW *win)
183: {
184: int *bp = (int *) vp;
185: int oy, ox;
186: int op_bad;
187:
188: op_bad = TRUE;
189: getyx(win, oy, ox);
190: waddstr(win, *bp ? "True" : "False");
191: while (op_bad)
192: {
193: wmove(win, oy, ox);
194: wrefresh(win);
195: switch (wreadchar(win))
196: {
197: case 't':
198: case 'T':
199: *bp = TRUE;
200: op_bad = FALSE;
201: break;
202: case 'f':
203: case 'F':
204: *bp = FALSE;
205: op_bad = FALSE;
206: break;
207: case '\n':
208: case '\r':
209: op_bad = FALSE;
210: break;
211: case ESCAPE:
212: return QUIT;
213: case '-':
214: return MINUS;
215: default:
216: wmove(win, oy, ox + 10);
217: waddstr(win, "(T or F)");
218: }
219: }
220: wmove(win, oy, ox);
221: waddstr(win, *bp ? "True" : "False");
222: waddch(win, '\n');
223: return NORM;
224: }
225:
226: /*
227: * get_sf:
228: * Change value and handle transition problems from see_floor to
229: * !see_floor.
230: */
231: int
232: get_sf(void *vp, WINDOW *win)
233: {
234: int *bp = (int *) vp;
235: int was_sf;
236: int retval;
237:
238: was_sf = see_floor;
239: retval = get_bool(bp, win);
240: if (retval == QUIT) return(QUIT);
241: if (was_sf != see_floor)
242: {
243: if (!see_floor) {
244: see_floor = TRUE;
245: erase_lamp(&hero, proom);
246: see_floor = FALSE;
247: }
248: else
249: look(FALSE);
250: }
251: return(NORM);
252: }
253:
254: /*
255: * get_str:
256: * Set a string option
257: */
258: #define MAXINP 50 /* max string to read from terminal or environment */
259:
260: int
261: get_str(void *vopt, WINDOW *win)
262: {
263: char *opt = (char *) vopt;
264: char *sp;
265: int oy, ox;
266: size_t i;
267: int c;
268: static char buf[MAXSTR];
269:
270: getyx(win, oy, ox);
271: wrefresh(win);
272: /*
273: * loop reading in the string, and put it in a temporary buffer
274: */
275: for (sp = buf; (c = wreadchar(win)) != '\n' && c != '\r' && c != ESCAPE;
276: wclrtoeol(win), wrefresh(win))
277: {
278: if (c == -1)
279: continue;
280: else if (c == erasechar()) /* process erase character */
281: {
282: if (sp > buf)
283: {
284: sp--;
285: for (i = strlen(unctrl(*sp)); i; i--)
286: waddch(win, '\b');
287: }
288: continue;
289: }
290: else if (c == killchar()) /* process kill character */
291: {
292: sp = buf;
293: wmove(win, oy, ox);
294: continue;
295: }
296: else if (sp == buf)
297: {
298: if (c == '-' && win != stdscr)
299: break;
300: else if (c == '~')
301: {
302: strcpy(buf, home);
303: waddstr(win, home);
304: sp += strlen(home);
305: continue;
306: }
307: }
308: if (sp >= &buf[MAXINP] || !(isprint(c) || c == ' '))
309: putchar(CTRL('G'));
310: else
311: {
312: *sp++ = (char) c;
313: waddstr(win, unctrl(c));
314: }
315: }
316: *sp = '\0';
317: if (sp > buf) /* only change option if something has been typed */
318: strucpy(opt, buf, strlen(buf));
319: mvwprintw(win, oy, ox, "%s\n", opt);
320: wrefresh(win);
321: if (win == stdscr)
322: mpos += (int)(sp - buf);
323: if (c == '-')
324: return MINUS;
325: else if (c == ESCAPE)
326: return QUIT;
327: else
328: return NORM;
329: }
330:
331: /*
332: * get_inv_t
333: * Get an inventory type name
334: */
335: int
336: get_inv_t(void *vp, WINDOW *win)
337: {
338: int *ip = (int *) vp;
339: int oy, ox;
340: int op_bad;
341:
342: op_bad = TRUE;
343: getyx(win, oy, ox);
344: waddstr(win, inv_t_name[*ip]);
345: while (op_bad)
346: {
347: wmove(win, oy, ox);
348: wrefresh(win);
349: switch (wreadchar(win))
350: {
351: case 'o':
352: case 'O':
353: *ip = INV_OVER;
354: op_bad = FALSE;
355: break;
356: case 's':
357: case 'S':
358: *ip = INV_SLOW;
359: op_bad = FALSE;
360: break;
361: case 'c':
362: case 'C':
363: *ip = INV_CLEAR;
364: op_bad = FALSE;
365: break;
366: case '\n':
367: case '\r':
368: op_bad = FALSE;
369: break;
370: case ESCAPE:
371: return QUIT;
372: case '-':
373: return MINUS;
374: default:
375: wmove(win, oy, ox + 15);
376: waddstr(win, "(O, S, or C)");
377: }
378: }
379: mvwprintw(win, oy, ox, "%s\n", inv_t_name[*ip]);
380: return NORM;
381: }
382:
383:
384: #ifdef MASTER
385: /*
386: * get_num:
387: * Get a numeric option
388: */
389: int
390: get_num(void *vp, WINDOW *win)
391: {
392: int *opt = (int *) vp;
393: int i;
394: static char buf[MAXSTR];
395:
396: if ((i = get_str(buf, win)) == NORM)
397: *opt = atoi(buf);
398: return i;
399: }
400: #endif
401:
402: /*
403: * parse_opts:
404: * Parse options from string, usually taken from the environment.
405: * The string is a series of comma seperated values, with booleans
406: * being stated as "name" (true) or "noname" (false), and strings
407: * being "name=....", with the string being defined up to a comma
408: * or the end of the entire option string.
409: */
410:
411: void
412: parse_opts(char *str)
413: {
414: char *sp;
415: const OPTION *op;
416: int len;
417: const char **i;
418: char *start;
419:
420: while (*str)
421: {
422: /*
423: * Get option name
424: */
425: for (sp = str; isalpha((int)*sp); sp++)
426: continue;
427: len = (int)(sp - str);
428: /*
429: * Look it up and deal with it
430: */
431: for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)
432: {
433: if (!allowchange(op))
434: continue;
435: if (EQSTR(str, op->o_name, len))
436: {
437: if (op->o_putfunc == put_bool) /* if option is a boolean */
438: *(int *)op->o_opt = TRUE; /* NOSTRICT */
439: else /* string option */
440: {
441: /*
442: * Skip to start of string value
443: */
444: for (str = sp + 1; *str == '='; str++)
445: continue;
446: if (*str == '~')
447: {
448: strcpy((char *) op->o_opt, home); /* NOSTRICT */
449: start = (char *) op->o_opt + strlen(home);/* NOSTRICT */
450: while (*++str == '/')
451: continue;
452: }
453: else
454: start = (char *) op->o_opt; /* NOSTRICT */
455: /*
456: * Skip to end of string value
457: */
458: for (sp = str + 1; *sp && *sp != ','; sp++)
459: continue;
460: /*
461: * check for type of inventory
462: */
463: if (op->o_putfunc == put_inv_t)
464: {
465: if (islower((int)*str))
466: *str = (char) toupper(*str);
467: for (i = inv_t_name; i <= &inv_t_name[INV_CLEAR]; i++)
468: if (strncmp(str, *i, sp - str) == 0)
469: {
470: inv_type = (int)(i - inv_t_name);
471: break;
472: }
473: }
474: else
475: strucpy(start, str, (size_t)(sp - str));
476: }
477: break;
478: }
479: /*
480: * check for "noname" for booleans
481: */
482: else if (op->o_putfunc == put_bool
483: && EQSTR(str, "no", 2) && EQSTR(str + 2, op->o_name, len - 2))
484: {
485: *(int *)op->o_opt = FALSE; /* NOSTRICT */
486: break;
487: }
488: }
489:
490: /*
491: * skip to start of next option name
492: */
493: while (*sp && !isalpha((int)*sp))
494: sp++;
495: str = sp;
496: }
497: }
498:
499: /*
500: * strucpy:
501: * Copy string using unctrl for things
502: */
503:
504: void
505: strucpy(char *s1, const char *s2, size_t len)
506: {
507: if (len > MAXINP)
508: len = MAXINP;
509: while (len--)
510: {
511: if (isprint((int)*s2) || *s2 == ' ')
512: *s1++ = *s2;
513: s2++;
514: }
515: *s1 = '\0';
516: }
517:
518: /* Tells whether the user is allowed to change the option. */
519: int
520: allowchange(const OPTION *opt)
521: {
522: if (!use_savedir)
523: return TRUE;
524: if (!strcmp(opt->o_name, "name"))
525: return FALSE;
526: if (!strcmp(opt->o_name, "file"))
527: return FALSE;
528: return TRUE;
529: }
CVSweb