OSDN Git Service

update year to 2020
[jnethack/source.git] / src / options.c
1 /* NetHack 3.6  options.c       $NHDT-Date: 1578996303 2020/01/14 10:05:03 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.396 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Michael Allison, 2008. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020            */
9 /* JNetHack may be freely redistributed.  See license for details. */
10
11 #ifdef OPTION_LISTS_ONLY /* (AMIGA) external program for opt lists */
12 #include "config.h"
13 #include "objclass.h"
14 #include "flag.h"
15 NEARDATA struct flag flags; /* provide linkage */
16 #ifdef SYSFLAGS
17 NEARDATA struct sysflag sysflags; /* provide linkage */
18 #endif
19 NEARDATA struct instance_flags iflags; /* provide linkage */
20 #define static
21 #else
22 #include "hack.h"
23 #include "tcap.h"
24 #include <ctype.h>
25 #endif
26
27 #define BACKWARD_COMPAT
28
29 #ifdef DEFAULT_WC_TILED_MAP
30 #define PREFER_TILED TRUE
31 #else
32 #define PREFER_TILED FALSE
33 #endif
34
35 #ifdef CURSES_GRAPHICS
36 extern int curses_read_attrs(const char *attrs);
37 extern char *curses_fmt_attrs(char *);
38 #endif
39
40 enum window_option_types {
41     MESSAGE_OPTION = 1,
42     STATUS_OPTION,
43     MAP_OPTION,
44     MENU_OPTION,
45     TEXT_OPTION
46 };
47
48 #define PILE_LIMIT_DFLT 5
49
50 static char empty_optstr[] = { '\0' };
51
52 /*
53  *  NOTE:  If you add (or delete) an option, please update the short
54  *  options help (option_help()), the long options help (dat/opthelp),
55  *  and the current options setting display function (doset()),
56  *  and also the Guidebooks.
57  *
58  *  The order matters.  If an option is a an initial substring of another
59  *  option (e.g. time and timed_delay) the shorter one must come first.
60  */
61
62 static struct Bool_Opt {
63     const char *name;
64     boolean *addr, initvalue;
65     int optflags;
66 } boolopt[] = {
67     { "acoustics", &flags.acoustics, TRUE, SET_IN_GAME },
68 #if defined(SYSFLAGS) && defined(AMIGA)
69     /* Amiga altmeta causes Alt+key to be converted into Meta+key by
70        low level nethack code; on by default, can be toggled off if
71        Alt+key is needed for some ASCII chars on non-ASCII keyboard */
72     { "altmeta", &sysflags.altmeta, TRUE, DISP_IN_GAME },
73 #else
74 #ifdef ALTMETA
75     /* non-Amiga altmeta causes nethack's top level command loop to treat
76        two character sequence "ESC c" as M-c, for terminals or emulators
77        which send "ESC c" when Alt+c is pressed; off by default, enabling
78        this can potentially make trouble if user types ESC when nethack
79        is honoring this conversion request (primarily after starting a
80        count prefix prior to a command and then deciding to cancel it) */
81     { "altmeta", &iflags.altmeta, FALSE, SET_IN_GAME },
82 #else
83     { "altmeta", (boolean *) 0, TRUE, DISP_IN_GAME },
84 #endif
85 #endif
86     { "ascii_map", &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME }, /*WC*/
87 #if defined(SYSFLAGS) && defined(MFLOPPY)
88     { "asksavedisk", &sysflags.asksavedisk, FALSE, SET_IN_GAME },
89 #else
90     { "asksavedisk", (boolean *) 0, FALSE, SET_IN_FILE },
91 #endif
92     { "autodescribe", &iflags.autodescribe, TRUE, SET_IN_GAME },
93     { "autodig", &flags.autodig, FALSE, SET_IN_GAME },
94     { "autoopen", &flags.autoopen, TRUE, SET_IN_GAME },
95     { "autopickup", &flags.pickup, TRUE, SET_IN_GAME },
96     { "autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME },
97 #if defined(MICRO) && !defined(AMIGA)
98     { "BIOS", &iflags.BIOS, FALSE, SET_IN_FILE },
99 #else
100     { "BIOS", (boolean *) 0, FALSE, SET_IN_FILE },
101 #endif
102     { "blind", &u.uroleplay.blind, FALSE, DISP_IN_GAME },
103     { "bones", &flags.bones, TRUE, SET_IN_FILE },
104 #ifdef INSURANCE
105     { "checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME },
106 #else
107     { "checkpoint", (boolean *) 0, FALSE, SET_IN_FILE },
108 #endif
109 #ifdef MFLOPPY
110     { "checkspace", &iflags.checkspace, TRUE, SET_IN_GAME },
111 #else
112     { "checkspace", (boolean *) 0, FALSE, SET_IN_FILE },
113 #endif
114     { "clicklook", &iflags.clicklook, FALSE, SET_IN_GAME },
115     { "cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME },
116 #if defined(MICRO) || defined(WIN32) || defined(CURSES_GRAPHICS)
117     { "color", &iflags.wc_color, TRUE, SET_IN_GAME }, /* on/off: use WC or not */
118 #else /* systems that support multiple terminals, many monochrome */
119     { "color", &iflags.wc_color, FALSE, SET_IN_GAME },
120 #endif
121     { "confirm", &flags.confirm, TRUE, SET_IN_GAME },
122     { "dark_room", &flags.dark_room, TRUE, SET_IN_GAME },
123     { "eight_bit_tty", &iflags.wc_eight_bit_input, FALSE, SET_IN_GAME }, /*WC*/
124 #if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS) || defined(X11_GRAPHICS)
125     { "extmenu", &iflags.extmenu, FALSE, SET_IN_GAME },
126 #else
127     { "extmenu", (boolean *) 0, FALSE, SET_IN_FILE },
128 #endif
129 #ifdef OPT_DISPMAP
130     { "fast_map", &flags.fast_map, TRUE, SET_IN_GAME },
131 #else
132     { "fast_map", (boolean *) 0, TRUE, SET_IN_FILE },
133 #endif
134     { "female", &flags.female, FALSE, DISP_IN_GAME },
135     { "fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME },
136 #if defined(SYSFLAGS) && defined(AMIFLUSH)
137     { "flush", &sysflags.amiflush, FALSE, SET_IN_GAME },
138 #else
139     { "flush", (boolean *) 0, FALSE, SET_IN_FILE },
140 #endif
141     { "force_invmenu", &iflags.force_invmenu, FALSE, SET_IN_GAME },
142     { "fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE }, /*WC2*/
143     { "goldX", &iflags.goldX, FALSE, SET_IN_GAME },
144     { "guicolor", &iflags.wc2_guicolor, TRUE, SET_IN_GAME}, /*WC2*/
145     { "help", &flags.help, TRUE, SET_IN_GAME },
146     { "herecmd_menu", &iflags.herecmd_menu, FALSE, SET_IN_GAME },
147     { "hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME }, /*WC*/
148     { "hilite_pile", &iflags.hilite_pile, FALSE, SET_IN_GAME },
149     { "hitpointbar", &iflags.wc2_hitpointbar, FALSE, SET_IN_GAME }, /*WC2*/
150 #ifndef MAC
151     { "ignintr", &flags.ignintr, FALSE, SET_IN_GAME },
152 #else
153     { "ignintr", (boolean *) 0, FALSE, SET_IN_FILE },
154 #endif
155     { "implicit_uncursed", &iflags.implicit_uncursed, TRUE, SET_IN_GAME },
156     { "large_font", &iflags.obsolete, FALSE, SET_IN_FILE }, /* OBSOLETE */
157     { "legacy", &flags.legacy, TRUE, DISP_IN_GAME },
158     { "lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME },
159     { "lootabc", &flags.lootabc, FALSE, SET_IN_GAME },
160 #ifdef MAIL
161     { "mail", &flags.biff, TRUE, SET_IN_GAME },
162 #else
163     { "mail", (boolean *) 0, TRUE, SET_IN_FILE },
164 #endif
165     { "mention_walls", &iflags.mention_walls, FALSE, SET_IN_GAME },
166     { "menucolors", &iflags.use_menu_color, FALSE, SET_IN_GAME },
167     /* for menu debugging only*/
168     { "menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_WIZGAME },
169     { "menu_objsyms", &iflags.menu_head_objsym, FALSE, SET_IN_GAME },
170 #ifdef TTY_GRAPHICS
171     { "menu_overlay", &iflags.menu_overlay, TRUE, SET_IN_GAME },
172 #else
173     { "menu_overlay", (boolean *) 0, FALSE, SET_IN_FILE },
174 #endif
175     { "monpolycontrol", &iflags.mon_polycontrol, FALSE, SET_IN_WIZGAME },
176 #ifdef NEWS
177     { "news", &iflags.news, TRUE, DISP_IN_GAME },
178 #else
179     { "news", (boolean *) 0, FALSE, SET_IN_FILE },
180 #endif
181     { "nudist", &u.uroleplay.nudist, FALSE, DISP_IN_GAME },
182     { "null", &flags.null, TRUE, SET_IN_GAME },
183 #if defined(SYSFLAGS) && defined(MAC)
184     { "page_wait", &sysflags.page_wait, TRUE, SET_IN_GAME },
185 #else
186     { "page_wait", (boolean *) 0, FALSE, SET_IN_FILE },
187 #endif
188     /* moved perm_invent from flags to iflags and out of save file in 3.6.2 */
189     { "perm_invent", &iflags.perm_invent, FALSE, SET_IN_GAME },
190     { "pickup_thrown", &flags.pickup_thrown, TRUE, SET_IN_GAME },
191     { "popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME },   /*WC*/
192     { "preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME }, /*WC*/
193     { "pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME },
194 #if defined(MICRO) && !defined(AMIGA)
195     { "rawio", &iflags.rawio, FALSE, DISP_IN_GAME },
196 #else
197     { "rawio", (boolean *) 0, FALSE, SET_IN_FILE },
198 #endif
199     { "rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME },
200 #ifdef RLECOMP
201     { "rlecomp", &iflags.rlecomp,
202 #if defined(COMPRESS) || defined(ZLIB_COMP)
203       FALSE,
204 #else
205       TRUE,
206 #endif
207       DISP_IN_GAME },
208 #endif
209     { "safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME },
210     { "sanity_check", &iflags.sanity_check, FALSE, SET_IN_WIZGAME },
211     { "selectsaved", &iflags.wc2_selectsaved, TRUE, DISP_IN_GAME }, /*WC*/
212     { "showexp", &flags.showexp, FALSE, SET_IN_GAME },
213     { "showrace", &flags.showrace, FALSE, SET_IN_GAME },
214 #ifdef SCORE_ON_BOTL
215     { "showscore", &flags.showscore, FALSE, SET_IN_GAME },
216 #else
217     { "showscore", (boolean *) 0, FALSE, SET_IN_FILE },
218 #endif
219     { "silent", &flags.silent, TRUE, SET_IN_GAME },
220     { "softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE }, /*WC2*/
221     { "sortpack", &flags.sortpack, TRUE, SET_IN_GAME },
222     { "sparkle", &flags.sparkle, TRUE, SET_IN_GAME },
223     { "splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME }, /*WC*/
224     { "standout", &flags.standout, FALSE, SET_IN_GAME },
225     { "status_updates", &iflags.status_updates, TRUE, DISP_IN_GAME },
226     { "tiled_map", &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME }, /*WC*/
227     { "time", &flags.time, FALSE, SET_IN_GAME },
228 #ifdef TIMED_DELAY
229     { "timed_delay", &flags.nap, TRUE, SET_IN_GAME },
230 #else
231     { "timed_delay", (boolean *) 0, FALSE, SET_IN_GAME },
232 #endif
233     { "tombstone", &flags.tombstone, TRUE, SET_IN_GAME },
234     { "toptenwin", &iflags.toptenwin, FALSE, SET_IN_GAME },
235     { "travel", &flags.travelcmd, TRUE, SET_IN_GAME },
236 #ifdef DEBUG
237     { "travel_debug", &iflags.trav_debug, FALSE, SET_IN_WIZGAME }, /*hack.c*/
238 #endif
239     { "use_darkgray", &iflags.wc2_darkgray, TRUE, SET_IN_FILE }, /*WC2*/
240 #ifdef WIN32
241     { "use_inverse", &iflags.wc_inverse, TRUE, SET_IN_GAME }, /*WC*/
242 #else
243     { "use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME }, /*WC*/
244 #endif
245     { "verbose", &flags.verbose, TRUE, SET_IN_GAME },
246 #ifdef TTY_TILES_ESCCODES
247     { "vt_tiledata", &iflags.vt_tiledata, FALSE, SET_IN_FILE },
248 #else
249     { "vt_tiledata", (boolean *) 0, FALSE, SET_IN_FILE },
250 #endif
251     { "whatis_menu", &iflags.getloc_usemenu, FALSE, SET_IN_GAME },
252     { "whatis_moveskip", &iflags.getloc_moveskip, FALSE, SET_IN_GAME },
253     { "wizweight", &iflags.wizweight, FALSE, SET_IN_WIZGAME },
254     { "wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME }, /*WC2*/
255 #ifdef ZEROCOMP
256     { "zerocomp", &iflags.zerocomp,
257 #if defined(COMPRESS) || defined(ZLIB_COMP)
258       FALSE,
259 #else
260       TRUE,
261 #endif
262       DISP_IN_GAME },
263 #endif
264     { (char *) 0, (boolean *) 0, FALSE, 0 }
265 };
266
267 /* compound options, for option_help() and external programs like Amiga
268  * frontend */
269 static struct Comp_Opt {
270     const char *name, *descr;
271     int size; /* for frontends and such allocating space --
272                * usually allowed size of data in game, but
273                * occasionally maximum reasonable size for
274                * typing when game maintains information in
275                * a different format */
276     int optflags;
277 } compopt[] = {
278 /*JP
279     { "align", "your starting alignment (lawful, neutral, or chaotic)", 8,
280 */
281     { "align",    "\83Q\81[\83\80\83X\83^\81[\83g\8e\9e\82Ì\91®\90« (lawful, neutral, or chaotic\82Ì\82¢\82¸\82ê\82©)", 8,
282       DISP_IN_GAME },
283 #if 0 /*JP:T*/
284     { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/
285 #else
286     { "align_message", "\83\81\83b\83Z\81[\83W\83E\83B\83\93\83h\83E\82Ì\91µ\82¦", 20, DISP_IN_GAME }, /*WC*/
287 #endif
288 #if 0 /*JP:T*/
289     { "align_status", "status window alignment", 20, DISP_IN_GAME },   /*WC*/
290 #else
291     { "align_status", "\8fó\8bµ\83E\83B\83\93\83h\83E\82Ì\91µ\82¦", 20, DISP_IN_GAME }, /*WC*/
292 #endif
293 /*JP
294     { "altkeyhandler", "alternate key handler", 20, SET_IN_GAME },
295 */
296     { "altkeyhandler", "ALT\83L\81[\83n\83\93\83h\83\89", 20, SET_IN_GAME },
297 #ifdef BACKWARD_COMPAT
298 /*JP
299     { "boulder", "deprecated (use S_boulder in sym file instead)", 1,
300 */
301     { "boulder",  "\8b\90\8aâ\82ð\95\\8e¦\82·\82é\83V\83\93\83{\83\8b\95\8e\9a", 1,
302       SET_IN_GAME },
303 #endif
304 /*JP
305     { "catname", "the name of your (first) cat (e.g., catname:Tabby)",
306 */
307     { "catname",  "\96`\8c¯\82ð\8b\9f\82É\82·\82é(\8dÅ\8f\89\82Ì)\94L\82Ì\96¼\91O (\97á catname:\82½\82Ü)",
308       PL_PSIZ, DISP_IN_GAME },
309 /*JP
310     { "disclose", "the kinds of information to disclose at end of game",
311 */
312     { "disclose", "\83Q\81[\83\80\8fI\97¹\8e\9e\82É\8c©\82é\8fî\95ñ\82Ì\8eí\97Þ",
313       sizeof flags.end_disclose * 2, SET_IN_GAME },
314 /*JP
315     { "dogname", "the name of your (first) dog (e.g., dogname:Fang)", PL_PSIZ,
316 */
317     { "dogname",  "\96`\8c¯\82ð\8b\9f\82É\82·\82é(\8dÅ\8f\89\82Ì)\8c¢\82Ì\96¼\91O (\97á dogname:\83|\83`)", PL_PSIZ,
318       DISP_IN_GAME },
319 /*JP
320     { "dungeon", "the symbols to use in drawing the dungeon map",
321 */
322     { "dungeon",  "\83_\83\93\83W\83\87\83\93\82ð\95`\89æ\82·\82é\83V\83\93\83{\83\8b\95\8e\9a",
323       MAXDCHARS + 1, SET_IN_FILE },
324 /*JP
325     { "effects", "the symbols to use in drawing special effects",
326 */
327     { "effects",  "\93Á\8eê\8cø\89Ê\82ð\95`\89æ\82·\82é\83V\83\93\83{\83\8b\95\8e\9a",
328       MAXECHARS + 1, SET_IN_FILE },
329 /*JP
330     { "font_map", "the font to use in the map window", 40,
331 */
332     { "font_map", "\83}\83b\83v\83E\83B\83\93\83h\83E\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40,
333       DISP_IN_GAME },                                              /*WC*/
334 #if 0 /*JP:T*/
335     { "font_menu", "the font to use in menus", 40, DISP_IN_GAME }, /*WC*/
336 #else
337     { "font_menu", "\83\81\83j\83\85\81[\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40, DISP_IN_GAME }, /*WC*/
338 #endif
339 /*JP
340     { "font_message", "the font to use in the message window", 40,
341 */
342     { "font_message", "\83\81\83b\83Z\81[\83W\83E\83B\83\93\83h\83E\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40,
343       DISP_IN_GAME },                                                  /*WC*/
344 #if 0 /*JP:T*/
345     { "font_size_map", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/
346 #else
347     { "font_size_map", "\83}\83b\83v\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20, DISP_IN_GAME }, /*WC*/
348 #endif
349 /*JP
350     { "font_size_menu", "the size of the menu font", 20,
351 */
352     { "font_size_menu", "\83\81\83j\83\85\81[\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20,
353       DISP_IN_GAME }, /*WC*/
354 /*JP
355     { "font_size_message", "the size of the message font", 20,
356 */
357     { "font_size_message", "\83\81\83b\83Z\81[\83W\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20,
358       DISP_IN_GAME }, /*WC*/
359 /*JP
360     { "font_size_status", "the size of the status font", 20,
361 */
362     { "font_size_status", "\8fó\8bµ\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20,
363       DISP_IN_GAME }, /*WC*/
364 /*JP
365     { "font_size_text", "the size of the text font", 20,
366 */
367     { "font_size_text", "\83e\83L\83X\83g\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20,
368       DISP_IN_GAME }, /*WC*/
369 /*JP
370     { "font_status", "the font to use in status window", 40,
371 */
372     { "font_status", "\8fó\8bµ\83E\83B\83\93\83h\83E\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40,
373       DISP_IN_GAME }, /*WC*/
374 /*JP
375     { "font_text", "the font to use in text windows", 40,
376 */
377     { "font_text", "\83e\83L\83X\83g\83E\83B\83\93\83h\83E\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40,
378       DISP_IN_GAME }, /*WC*/
379 /*JP
380     { "fruit", "the name of a fruit you enjoy eating", PL_FSIZ, SET_IN_GAME },
381 */
382     { "fruit", "\8dD\95¨\82Ì\89Ê\95¨\82Ì\96¼\91O", PL_FSIZ, SET_IN_GAME },
383 /*JP
384     { "gender", "your starting gender (male or female)", 8, DISP_IN_GAME },
385 */
386     { "gender", "\83Q\81[\83\80\8aJ\8en\8e\9e\82Ì\90«\95Ê(male \82Ü\82½\82Í female)", 8, DISP_IN_GAME },
387 /*JP
388     { "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
389 */
390     { "horsename", "\96`\8c¯\82ð\8b\9f\82É\82·\82é(\8dÅ\8f\89\82Ì)\94n\82Ì\96¼\91O (\97á ghoulname:\83V\83\8b\83o\81[)",
391       PL_PSIZ, DISP_IN_GAME },
392 #if 0 /*JP:T*/
393     { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/
394 #else
395     { "map_mode", "\83E\83B\83\93\83h\83E\95\\8e¦\8e\9e\82Ì\83}\83b\83v\82Ì\95\\8e¦\83\82\81[\83h", 20, DISP_IN_GAME }, /*WC*/
396 #endif
397 /*JP
398     { "menustyle", "user interface for object selection", MENUTYPELEN,
399 */
400     { "menustyle", "\83I\83u\83W\83F\83N\83g\82ð\91I\91ð\82·\82é\82Æ\82«\82Ì\83\86\81[\83U\81[\83C\83\93\83^\83t\83F\81[\83X", MENUTYPELEN,
401       SET_IN_GAME },
402 /*JP
403     { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE },
404 */
405     { "menu_deselect_all", "\91S\82Ä\82Ì\83A\83C\83e\83\80\82ð\94ñ\91I\91ð", 4, SET_IN_FILE },
406 /*JP
407     { "menu_deselect_page", "deselect all items on this page of a menu", 4,
408 */
409     { "menu_deselect_page", "\8c»\8dÝ\95\\8e¦\82³\82ê\82Ä\82¢\82é\83y\81[\83W\82Ì\83A\83C\83e\83\80\82ð\94ñ\91I\91ð", 4,
410       SET_IN_FILE },
411 /*JP
412     { "menu_first_page", "jump to the first page in a menu", 4, SET_IN_FILE },
413 */
414     { "menu_first_page", "\83\81\83j\83\85\81[\82Ì\8dÅ\8f\89\82Ì\83y\81[\83W\82Ö", 4, SET_IN_FILE },
415 /*JP
416     { "menu_headings", "text attribute for menu headings", 9, SET_IN_GAME },
417 */
418     { "menu_headings", "\8b­\92²\81C\94½\93]\82Ü\82½\82Í\89º\90ü\82Å\8eí\97Þ\82ð\95\\8e¦\82·\82é", 9, SET_IN_GAME },
419 /*JP
420     { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE },
421 */
422     { "menu_invert_all", "\91S\82Ä\82Ì\83A\83C\83e\83\80\82ð\94½\93]", 4, SET_IN_FILE },
423 /*JP
424     { "menu_invert_page", "invert all items on this page of a menu", 4,
425 */
426     { "menu_invert_page", "\8c»\8dÝ\95\\8e¦\82³\82ê\82Ä\82¢\82é\83y\81[\83W\82Ì\83A\83C\83e\83\80\82ð\94½\93]",
427       SET_IN_FILE },
428 /*JP
429     { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE },
430 */
431     { "menu_last_page", "\83\81\83j\83\85\81[\82Ì\8dÅ\8cã\82Ì\83y\81[\83W\82Ö", 4, SET_IN_FILE },
432 /*JP
433     { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE },
434 */
435     { "menu_next_page", "\8e\9f\82Ì\83\81\83j\83\85\81[\82Ì\83y\81[\83W\82Ö", 4, SET_IN_FILE },
436 /*JP
437     { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE },
438 */
439     { "menu_previous_page", "\91O\82Ì\83\81\83j\83\85\81[\82Ì\83y\81[\83W\82Ö", 4, SET_IN_FILE },
440 /*JP
441     { "menu_search", "search for a menu item", 4, SET_IN_FILE },
442 */
443     { "menu_search", "\83\81\83j\83\85\81[\82Ì\8c\9f\8dõ", 4, SET_IN_FILE },
444 /*JP
445     { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE },
446 */
447     { "menu_select_all", "\91S\82Ä\82Ì\83A\83C\83e\83\80\82ð\91I\91ð", 4, SET_IN_FILE },
448 /*JP
449     { "menu_select_page", "select all items on this page of a menu", 4,
450 */
451     { "menu_select_page", "\8c»\8dÝ\95\\8e¦\82³\82ê\82Ä\82¢\82é\91S\82Ä\82Ì\83A\83C\83e\83\80\82ð\91I\91ð", 4,
452       SET_IN_FILE },
453 /*JP
454     { "monsters", "the symbols to use for monsters", MAXMCLASSES,
455 */
456     { "monsters", "\83\82\83\93\83X\83^\81[\82É\8eg\97p\82³\82ê\82é\83V\83\93\83{\83\8b\95\8e\9a", MAXMCLASSES,
457       SET_IN_FILE },
458 /*JP
459     { "msghistory", "number of top line messages to save", 5, DISP_IN_GAME },
460 */
461     { "msghistory", "\90æ\93ª\8ds\82É\95\\8e¦\82³\82ê\82½\83\81\83b\83Z\81[\83W\97\9a\97ð\82Ì\95Û\91\90\94", 5, DISP_IN_GAME },
462 #if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS)
463 /*JP
464     { "msg_window", "the type of message window required", 1, SET_IN_GAME },
465 */
466     { "msg_window", "\83\81\83b\83Z\81[\83W\83E\83B\83\93\83h\83E\82Ì\83^\83C\83v\82ð\90Ý\92è",1, SET_IN_GAME },
467 #else
468 /*JP
469     { "msg_window", "the type of message window required", 1, SET_IN_FILE },
470 */
471     { "msg_window", "\83\81\83b\83Z\81[\83W\83E\83B\83\93\83h\83E\82Ì\83^\83C\83v\82ð\90Ý\92è", 1, SET_IN_FILE },
472 #endif
473 /*JP
474     { "name", "your character's name (e.g., name:Merlin-W)", PL_NSIZ,
475 */
476     { "name", "\82 \82È\82½\82Ì\96¼\91O (\97á name:\83}\81[\83\8a\83\93-W)", PL_NSIZ,
477       DISP_IN_GAME },
478     { "mouse_support", "game receives click info from mouse", 0, SET_IN_GAME },
479 /*JP
480     { "number_pad", "use the number pad for movement", 1, SET_IN_GAME },
481 */
482     { "number_pad", "\83i\83\93\83o\81[\83p\83b\83h\82ð\8eg\97p\82·\82é", 1, SET_IN_GAME },
483 /*JP
484     { "objects", "the symbols to use for objects", MAXOCLASSES, SET_IN_FILE },
485 */
486     { "objects",  "\83A\83C\83e\83\80\82É\8eg\97p\82³\82ê\82é\83V\83\93\83{\83\8b\95\8e\9a", MAXOCLASSES, SET_IN_FILE },
487 /*JP
488     { "packorder", "the inventory order of the items in your pack",
489 */
490     { "packorder", "\94w\95\89\82¢\91Ü\93à\82Ì\95¨\82Ì\8f\87\94Ô",
491       MAXOCLASSES, SET_IN_GAME },
492 #ifdef CHANGE_COLOR
493     { "palette",
494 #ifndef WIN32
495 /*JP
496       "palette (00c/880/-fff is blue/yellow/reverse white)", 15, SET_IN_GAME
497 */
498       "\83p\83\8c\83b\83g (00c/880/-fff\82Í\82»\82ê\82¼\82ê\90Â/\89©/\94½\93]\94\92\82ð\8e¦\82·)", 15, SET_IN_GAME
499 #else
500 /*JP
501       "palette (adjust an RGB color in palette (color-R-G-B)", 15, SET_IN_FILE
502 */
503       "\83p\83\8c\83b\83g (\83p\83\8c\83b\83g\82ÌRGB\90F\82ð\92²\90®\82·\82é (\90F-R-G-B)", 15, SET_IN_FILE
504 #endif
505     },
506 #if defined(MAC)
507 /*JP
508     { "hicolor", "same as palette, only order is reversed", 15, SET_IN_FILE },
509 */
510     { "hicolor",  "\83p\83\8c\83b\83g\82ª\93¯\82\82Æ\82«\81A\8ew\8e¦\82µ\82½\82à\82Ì\82¾\82¯\94½\93]\82³\82¹\82é", 15, SET_IN_FILE },
511 #endif
512 #endif
513 #if 0 /*JP:T*/
514     { "paranoid_confirmation", "extra prompting in certain situations", 28,
515       SET_IN_GAME },
516 #else
517     { "paranoid_confirmation", "\88ê\95\94\82Ì\8fó\8bµ\82Å\92Ç\89Á\82Ì\8am\94F\82ð\82·\82é", 28,
518       SET_IN_GAME },
519 #endif
520     { "petattr",  "attributes for highlighting pets", 88, SET_IN_GAME },
521 /*JP
522     { "pettype", "your preferred initial pet type", 4, DISP_IN_GAME },
523 */
524     { "pettype",  "\82 \82È\82½\82Ì\91I\91ð\82µ\82½\8f\89\8aú\83y\83b\83g\82Ì\8eí\97Þ", 4, DISP_IN_GAME },
525 /*JP
526     { "pickup_burden", "maximum burden picked up before prompt", 20,
527 */
528     { "pickup_burden",  "\8fE\82¤\82Æ\82«\82É\8dÅ\91å\89×\8fd\82É\82È\82é\8eè\91O\82Å\8am\94F\82·\82é", 20,
529       SET_IN_GAME },
530 /*JP
531     { "pickup_types", "types of objects to pick up automatically",
532 */
533     { "pickup_types", "\8e©\93®\82Å\8fE\82¢\82 \82°\82é\95¨\82Ì\83V\83\93\83{\83\8b",
534       MAXOCLASSES, SET_IN_GAME },
535 #if 0 /*JP:T*/
536     { "pile_limit", "threshold for \"there are many objects here\"", 24,
537       SET_IN_GAME },
538 #else
539     { "pile_limit", "\81u\82±\82±\82É\82Í\82½\82­\82³\82ñ\82Ì\82à\82Ì\82ª\82 \82é\81v\82Ì\82µ\82«\82¢\92l", 24,
540       SET_IN_GAME },
541 #endif
542 #if 0 /*JP:T*/
543     { "playmode", "normal play, non-scoring explore mode, or debug mode", 8,
544       DISP_IN_GAME },
545 #else
546     { "playmode", "\92Ê\8fí\83\82\81[\83h\81C\92T\8c\9f\83\82\81[\83h\81C\83f\83o\83b\83O\83\82\81[\83h\82Ì\82¢\82¸\82ê\82©", 8,
547       DISP_IN_GAME },
548 #endif
549 /*JP
550     { "player_selection", "choose character via dialog or prompts", 12,
551 */
552     { "player_selection", "\83L\83\83\83\89\83N\83^\81[\91I\91ð\82É\83_\83C\83A\83\8d\83O\82â\8am\94F\89æ\96Ê\82ð\8eg\82¤", 12,
553       DISP_IN_GAME },
554 /*JP
555     { "race", "your starting race (e.g., Human, Elf)", PL_CSIZ,
556 */
557     { "race",     "\83Q\81[\83\80\8aJ\8en\8e\9e\82Ì\8eí\91° (\97á Human, Elf)", PL_CSIZ,
558       DISP_IN_GAME },
559 /*JP
560     { "role", "your starting role (e.g., Barbarian, Valkyrie)", PL_CSIZ,
561 */
562     { "role",     "\83Q\81[\83\80\8aJ\8en\8e\9e\82Ì\90E\8bÆ (\97á Barbarian, Valkyrie)", PL_CSIZ,
563       DISP_IN_GAME },
564 /*JP
565     { "runmode", "display frequency when `running' or `travelling'",
566 */
567     { "runmode", "\83g\83\89\83x\83\8b\83R\83}\83\93\83h\93\99\82Å\82Ì\98A\91±\88Ú\93®\8e\9e\82Ì\95`\89æ\95p\93x",
568       sizeof "teleport", SET_IN_GAME },
569 /*JP
570     { "scores", "the parts of the score list you wish to see", 32,
571 */
572     { "scores",   "\83Q\81[\83\80\8fI\97¹\8e\9e\82É\8c©\82é\83X\83R\83A\82Ì\8eí\97Þ", 32,
573       SET_IN_GAME },
574 /*JP
575     { "scroll_amount", "amount to scroll map when scroll_margin is reached",
576 */
577     { "scroll_amount", "scroll_margin\82É\93Í\82¢\82½\82Æ\82«\82Ì\83}\83b\83v\83X\83N\83\8d\81[\83\8b\97Ê",
578       20, DISP_IN_GAME }, /*WC*/
579 /*JP
580     { "scroll_margin", "scroll map when this far from the edge", 20,
581 */
582     { "scroll_margin", "\83}\83b\83v\92[\82©\82ç\82Ì\83}\83b\83v\83X\83N\83\8d\81[\83\8b\8aJ\8en\8b\97\97£", 20,
583       DISP_IN_GAME }, /*WC*/
584 /*JP
585     { "sortloot", "sort object selection lists by description", 4,
586 */
587     { "sortloot", "\95¨\91Ì\91I\91ð\83\8a\83X\83g\82ð\90à\96¾\82Å\83\\81[\83g\82·\82é", 4,
588       SET_IN_GAME },
589 #ifdef MSDOS
590 /*JP
591     { "soundcard", "type of sound card to use", 20, SET_IN_FILE },
592 */
593     { "soundcard", "\8eg\97p\82µ\82Ä\82¢\82é\83T\83E\83\93\83h\83J\81[\83h\82Ì\8eí\97Þ", 20, SET_IN_FILE },
594 #endif
595     { "statushilites",
596 #ifdef STATUS_HILITES
597 #if 0 /*JP:T*/
598       "0=no status highlighting, N=show highlights for N turns",
599 #else
600       "0=\83X\83e\81[\83^\83X\83n\83C\83\89\83C\83g\82È\82µ\81CN\83^\81[\83\93\96\88\82É\83n\83C\83\89\83C\83g\95\\8e¦",
601 #endif
602       20, SET_IN_GAME
603 #else
604 /*JP
605     "highlight control", 20, SET_IN_FILE
606 */
607     "\83n\83C\83\89\83C\83g\82Ì\90§\8cä", 20, SET_IN_FILE
608 #endif
609     },
610     { "statuslines",
611 #ifdef CURSES_GRAPHICS
612       "2 or 3 lines for horizontal (bottom or top) status display",
613       20, SET_IN_GAME
614 #else
615       "2 or 3 lines for status display",
616       20, SET_IN_FILE
617 #endif
618     }, /*WC2*/
619 #if 0 /*JP:T*/
620     { "symset", "load a set of display symbols from the symbols file", 70,
621       SET_IN_GAME },
622 #else
623     { "symset", "symbols\83t\83@\83C\83\8b\82©\82ç\95\\8e¦\83V\83\93\83{\83\8b\82Ì\90Ý\92è\82ð\93Ç\82Ý\8d\9e\82Þ", 70,
624       SET_IN_GAME },
625 #endif
626 #if 0 /*JP:T*/
627     { "roguesymset",
628       "load a set of rogue display symbols from the symbols file", 70,
629       SET_IN_GAME },
630 #else
631     { "roguesymset",
632       "symbols\83t\83@\83C\83\8b\82©\82ç\83\8d\81[\83O\83\8c\83x\83\8b\82Ì\95\\8e¦\83V\83\93\83{\83\8b\82Ì\90Ý\92è\82ð\93Ç\82Ý\8d\9e\82Þ", 70,
633       SET_IN_GAME },
634 #endif
635 #ifdef WIN32
636 /*JP
637     { "subkeyvalue", "override keystroke value", 7, SET_IN_FILE },
638 */
639     { "subkeyvalue", "\83L\81[\83}\83b\83s\83\93\83O\82ð\95Ï\8dX\82·\82é", 7, SET_IN_FILE },
640 #endif
641 /*JP
642     { "suppress_alert", "suppress alerts about version-specific features", 8,
643 */
644     { "suppress_alert", "\83o\81[\83W\83\87\83\93\8aÔ\82Ì\88á\82¢\82É\8aÖ\82·\82é\8cx\8d\90\83\81\83b\83Z\81[\83W\82Ì\96³\8cø\89»", 8,
645       SET_IN_GAME },
646     /* term_cols,term_rows -> WC2_TERM_SIZE (6: room to format 1..32767) */
647     { "term_cols", "number of columns", 6, SET_IN_FILE }, /*WC2*/
648     { "term_rows", "number of rows", 6, SET_IN_FILE }, /*WC2*/
649 #if 0 /*JP:T*/
650     { "tile_width", "width of tiles", 20, DISP_IN_GAME },   /*WC*/
651 #else
652     { "tile_width", "\83^\83C\83\8b\82Ì\95\9d", 20, DISP_IN_GAME },   /*WC*/
653 #endif
654 #if 0 /*JP:T*/
655     { "tile_height", "height of tiles", 20, DISP_IN_GAME }, /*WC*/
656 #else
657     { "tile_height", "\83^\83C\83\8b\82Ì\8d\82\82³", 20, DISP_IN_GAME }, /*WC*/
658 #endif
659 #if 0 /*JP:T*/
660     { "tile_file", "name of tile file", 70, DISP_IN_GAME }, /*WC*/
661 #else
662     { "tile_file", "\83^\83C\83\8b\83t\83@\83C\83\8b\82Ì\96¼\91O", 70, DISP_IN_GAME }, /*WC*/
663 #endif
664 /*JP
665     { "traps", "the symbols to use in drawing traps", MAXTCHARS + 1,
666 */
667     { "traps", "ã©\82ð\95`\89æ\82·\82é\83V\83\93\83{\83\8b\95\8e\9a", MAXTCHARS + 1,
668       SET_IN_FILE },
669 /*JP
670     { "vary_msgcount", "show more old messages at a time", 20,
671 */
672     { "vary_msgcount", "\88ê\93x\82É\95\\8e¦\82·\82é\83\81\83b\83Z\81[\83W\82Ì\90\94", 20,
673       DISP_IN_GAME }, /*WC*/
674 #ifdef MSDOS
675 /*JP
676     { "video", "method of video updating", 20, SET_IN_FILE },
677 */
678     { "video", "\8eg\97p\82·\82é\83r\83f\83I\83\82\81[\83h\82ð\90Ý\92è\82·\82é", 20, SET_IN_FILE },
679 #endif
680 #ifdef VIDEOSHADES
681 /*JP
682     { "videocolors", "color mappings for internal screen routines", 40,
683 */
684     { "videocolors", "\93à\91 \83X\83N\83\8a\81[\83\93\83\8b\81[\83`\83\93\97p\82Ì\83J\83\89\81[\83}\83b\83v\82ð\97p\82¢\82é", 40,
685       DISP_IN_GAME },
686 /*JP
687     { "videoshades", "gray shades to map to black/gray/white", 32,
688 */
689     { "videoshades", "\95\\8e¦\82É\83O\83\8c\83C\83X\83P\81[\83\8b\82ð\97p\82¢\82é", 32,
690       DISP_IN_GAME },
691 #endif
692 #if 0 /*JP:T*/
693     { "whatis_coord", "show coordinates when auto-describing cursor position",
694       1, SET_IN_GAME },
695 #else
696     { "whatis_coord", "\83J\81[\83\\83\8b\88Ê\92u\82ð\8e©\93®\90à\96¾\82·\82é\82Æ\82«\82É\8dÀ\95W\82ð\95\\8e¦\82·\82é",
697       1, SET_IN_GAME },
698 #endif
699 #if 0 /*JP:T*/
700     { "whatis_filter",
701       "filter coordinate locations when targeting next or previous",
702       1, SET_IN_GAME },
703 #else
704     { "whatis_filter",
705       "\8e\9f\82â\8eè\91O\82ð\83^\81[\83Q\83b\83g\82·\82é\82Æ\82«\82É\8dÀ\95W\88Ê\92u\82ð\83t\83B\83\8b\83^\82·\82é",
706       1, SET_IN_GAME },
707 #endif
708     { "windowborders", "0 (off), 1 (on), 2 (auto)", 9, SET_IN_GAME }, /*WC2*/
709 #if 0 /*JP:T*/
710     { "windowcolors", "the foreground/background colors of windows", /*WC*/
711       80, DISP_IN_GAME },
712 #else
713     { "windowcolors", "\83E\83B\83\93\83h\83E\82ð\8ew\92è\82µ\82½\91O\8ci\90F/\94w\8ci\90F\82Å\95\\8e¦\82·\82é", /*WC*/
714       80, DISP_IN_GAME },
715 #endif
716 /*JP
717     { "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
718 */
719     { "windowtype", "\8eg\97p\82·\82é\83E\83C\83\93\83h\83E\83V\83X\83e\83\80", WINTYPELEN, DISP_IN_GAME },
720 #ifdef WINCHAIN
721 /*JP
722     { "windowchain", "window processor to use", WINTYPELEN, SET_IN_SYS },
723 */
724     { "windowchain", "\8eg\97p\82·\82é\83E\83B\83\93\83h\83E\83v\83\8d\83Z\83b\83T", WINTYPELEN, SET_IN_SYS },
725 #endif
726 #ifdef BACKWARD_COMPAT
727 /*JP
728     { "DECgraphics", "load DECGraphics display symbols", 70, SET_IN_FILE },
729 */
730     { "DECgraphics", "DECGraphics\95\\8e¦\83V\83\93\83{\83\8b\82ð\93Ç\82Ý\8d\9e\82Þ", 70, SET_IN_FILE },
731 /*JP
732     { "IBMgraphics", "load IBMGraphics display symbols", 70, SET_IN_FILE },
733 */
734     { "IBMgraphics", "IBMGraphics\95\\8e¦\83V\83\93\83{\83\8b\82ð\93Ç\82Ý\8d\9e\82Þ", 70, SET_IN_FILE },
735 #ifdef CURSES_GRAPHICS
736     { "cursesgraphics", "load curses display symbols", 70, SET_IN_FILE },
737 #endif
738 #ifdef MAC_GRAPHICS_ENV
739 /*JP
740     { "Macgraphics", "load MACGraphics display symbols", 70, SET_IN_FILE },
741 */
742     { "Macgraphics", "MACGraphics\95\\8e¦\83V\83\93\83{\83\8b\82ð\93Ç\82Ý\8d\9e\82Þ", 70, SET_IN_FILE },
743 #endif
744 #endif
745 #if 1 /*JP*/
746     { "kcode", "\92[\96\96\82Ì\8a¿\8e\9a\83R\81[\83h,", 4, SET_IN_FILE },
747 #endif
748     { (char *) 0, (char *) 0, 0, 0 }
749 };
750
751 #ifdef OPTION_LISTS_ONLY
752 #undef static
753
754 #else /* use rest of file */
755
756 extern char configfile[]; /* for messages */
757
758 extern struct symparse loadsyms[];
759 static boolean need_redraw; /* for doset() */
760
761 #if defined(TOS) && defined(TEXTCOLOR)
762 extern boolean colors_changed;  /* in tos.c */
763 #endif
764
765 #ifdef VIDEOSHADES
766 extern char *shade[3];          /* in sys/msdos/video.c */
767 extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */
768 #endif
769
770 static char def_inv_order[MAXOCLASSES] = {
771     COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
772     SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
773     TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
774 };
775
776 /*
777  * Default menu manipulation command accelerators.  These may _not_ be:
778  *
779  *      + a number - reserved for counts
780  *      + an upper or lower case US ASCII letter - used for accelerators
781  *      + ESC - reserved for escaping the menu
782  *      + NULL, CR or LF - reserved for commiting the selection(s).  NULL
783  *        is kind of odd, but the tty's xwaitforspace() will return it if
784  *        someone hits a <ret>.
785  *      + a default object class symbol - used for object class accelerators
786  *
787  * Standard letters (for now) are:
788  *
789  *              <  back 1 page
790  *              >  forward 1 page
791  *              ^  first page
792  *              |  last page
793  *              :  search
794  *
795  *              page            all
796  *               ,    select     .
797  *               \    deselect   -
798  *               ~    invert     @
799  *
800  * The command name list is duplicated in the compopt array.
801  */
802 typedef struct {
803     const char *name;
804     char cmd;
805     const char *desc;
806 } menu_cmd_t;
807
808 static const menu_cmd_t default_menu_cmd_info[] = {
809  { "menu_first_page", MENU_FIRST_PAGE, "Go to first page" },
810  { "menu_last_page", MENU_LAST_PAGE, "Go to last page" },
811  { "menu_next_page", MENU_NEXT_PAGE, "Go to next page" },
812  { "menu_previous_page", MENU_PREVIOUS_PAGE, "Go to previous page" },
813  { "menu_select_all", MENU_SELECT_ALL, "Select all items" },
814  { "menu_deselect_all", MENU_UNSELECT_ALL, "Unselect all items" },
815  { "menu_invert_all", MENU_INVERT_ALL, "Invert selection" },
816  { "menu_select_page", MENU_SELECT_PAGE, "Select items in current page" },
817  { "menu_deselect_page", MENU_UNSELECT_PAGE,
818    "Unselect items in current page" },
819  { "menu_invert_page", MENU_INVERT_PAGE, "Invert current page selection" },
820  { "menu_search", MENU_SEARCH, "Search and toggle matching items" },
821 };
822
823 /*
824  * Allow the user to map incoming characters to various menu commands.
825  * The accelerator list must be a valid C string.
826  */
827 #define MAX_MENU_MAPPED_CMDS 32 /* some number */
828 char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS + 1]; /* exported */
829 static char mapped_menu_op[MAX_MENU_MAPPED_CMDS + 1];
830 static short n_menu_mapped = 0;
831
832 static boolean initial, from_file;
833
834 STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
835 STATIC_DCL void FDECL(escapes, (const char *, char *));
836 STATIC_DCL void FDECL(rejectoption, (const char *));
837 STATIC_DCL char *FDECL(string_for_opt, (char *, BOOLEAN_P));
838 STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *, BOOLEAN_P));
839 STATIC_DCL void FDECL(bad_negation, (const char *, BOOLEAN_P));
840 STATIC_DCL int FDECL(change_inv_order, (char *));
841 STATIC_DCL boolean FDECL(warning_opts, (char *, const char *));
842 STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
843 STATIC_DCL boolean FDECL(duplicate_opt_detection, (const char *, int));
844 STATIC_DCL void FDECL(complain_about_duplicate, (const char *, int));
845
846 STATIC_DCL const char *FDECL(attr2attrname, (int));
847 STATIC_DCL const char * FDECL(msgtype2name, (int));
848 STATIC_DCL int NDECL(query_msgtype);
849 STATIC_DCL boolean FDECL(msgtype_add, (int, char *));
850 STATIC_DCL void FDECL(free_one_msgtype, (int));
851 STATIC_DCL int NDECL(msgtype_count);
852 STATIC_DCL boolean FDECL(test_regex_pattern, (const char *, const char *));
853 STATIC_DCL boolean FDECL(add_menu_coloring_parsed, (char *, int, int));
854 STATIC_DCL void FDECL(free_one_menu_coloring, (int));
855 STATIC_DCL int NDECL(count_menucolors);
856 STATIC_DCL boolean FDECL(parse_role_opts, (BOOLEAN_P, const char *,
857                                            char *, char **));
858
859 STATIC_DCL void FDECL(doset_add_menu, (winid, const char *, int));
860 STATIC_DCL void FDECL(opts_add_others, (winid, const char *, int,
861                                         char *, int));
862 STATIC_DCL int FDECL(handle_add_list_remove, (const char *, int));
863 STATIC_DCL boolean FDECL(special_handling, (const char *,
864                                             BOOLEAN_P, BOOLEAN_P));
865 STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
866 STATIC_DCL void FDECL(remove_autopickup_exception,
867                       (struct autopickup_exception *));
868
869 STATIC_DCL boolean FDECL(is_wc_option, (const char *));
870 STATIC_DCL boolean FDECL(wc_supported, (const char *));
871 STATIC_DCL boolean FDECL(is_wc2_option, (const char *));
872 STATIC_DCL boolean FDECL(wc2_supported, (const char *));
873 STATIC_DCL void FDECL(wc_set_font_name, (int, char *));
874 STATIC_DCL int FDECL(wc_set_window_colors, (char *));
875
876 void
877 reglyph_darkroom()
878 {
879     xchar x, y;
880
881     for (x = 0; x < COLNO; x++)
882         for (y = 0; y < ROWNO; y++) {
883             struct rm *lev = &levl[x][y];
884
885             if (!flags.dark_room || !iflags.use_color
886                 || Is_rogue_level(&u.uz)) {
887                 if (lev->glyph == cmap_to_glyph(S_darkroom))
888                     lev->glyph = lev->waslit ? cmap_to_glyph(S_room)
889                                              : cmap_to_glyph(S_stone);
890             } else {
891                 if (lev->glyph == cmap_to_glyph(S_room) && lev->seenv
892                     && lev->waslit && !cansee(x, y))
893                     lev->glyph = cmap_to_glyph(S_darkroom);
894                 else if (lev->glyph == cmap_to_glyph(S_stone)
895                          && lev->typ == ROOM && lev->seenv && !cansee(x, y))
896                     lev->glyph = cmap_to_glyph(S_darkroom);
897             }
898         }
899     if (flags.dark_room && iflags.use_color)
900         showsyms[S_darkroom] = showsyms[S_room];
901     else
902         showsyms[S_darkroom] = showsyms[S_stone];
903 }
904
905 /* check whether a user-supplied option string is a proper leading
906    substring of a particular option name; option string might have
907    a colon or equals sign and arbitrary value appended to it */
908 boolean
909 match_optname(user_string, opt_name, min_length, val_allowed)
910 const char *user_string, *opt_name;
911 int min_length;
912 boolean val_allowed;
913 {
914     int len = (int) strlen(user_string);
915
916     if (val_allowed) {
917         const char *p = index(user_string, ':'),
918                    *q = index(user_string, '=');
919
920         if (!p || (q && q < p))
921             p = q;
922         if (p) {
923             /* 'user_string' hasn't necessarily been through mungspaces()
924                so might have tabs or consecutive spaces */
925             while (p > user_string && isspace((uchar) *(p - 1)))
926                 p--;
927             len = (int) (p - user_string);
928         }
929     }
930
931     return (boolean) (len >= min_length
932                       && !strncmpi(opt_name, user_string, len));
933 }
934
935 /* most environment variables will eventually be printed in an error
936  * message if they don't work, and most error message paths go through
937  * BUFSZ buffers, which could be overflowed by a maliciously long
938  * environment variable.  If a variable can legitimately be long, or
939  * if it's put in a smaller buffer, the responsible code will have to
940  * bounds-check itself.
941  */
942 char *
943 nh_getenv(ev)
944 const char *ev;
945 {
946     char *getev = getenv(ev);
947
948     if (getev && strlen(getev) <= (BUFSZ / 2))
949         return getev;
950     else
951         return (char *) 0;
952 }
953
954 /* process options, possibly including SYSCF */
955 void
956 initoptions()
957 {
958     initoptions_init();
959 #ifdef SYSCF
960 /* someday there may be other SYSCF alternatives besides text file */
961 #ifdef SYSCF_FILE
962     /* If SYSCF_FILE is specified, it _must_ exist... */
963     assure_syscf_file();
964     config_error_init(TRUE, SYSCF_FILE, FALSE);
965
966     /* ... and _must_ parse correctly. */
967     if (!read_config_file(SYSCF_FILE, SET_IN_SYS)) {
968         if (config_error_done() && !iflags.initoptions_noterminate)
969             nh_terminate(EXIT_FAILURE);
970     }
971     config_error_done();
972     /*
973      * TODO [maybe]: parse the sysopt entries which are space-separated
974      * lists of usernames into arrays with one name per element.
975      */
976 #endif
977 #endif /* SYSCF */
978     initoptions_finish();
979 }
980
981 void
982 initoptions_init()
983 {
984 #if (defined(UNIX) || defined(VMS)) && defined(TTY_GRAPHICS)
985     char *opts;
986 #endif
987     int i;
988
989     /* set up the command parsing */
990     reset_commands(TRUE); /* init */
991
992     /* initialize the random number generator(s) */
993     init_random(rn2);
994     init_random(rn2_on_display_rng);
995
996     /* for detection of configfile options specified multiple times */
997     iflags.opt_booldup = iflags.opt_compdup = (int *) 0;
998
999     for (i = 0; boolopt[i].name; i++) {
1000         if (boolopt[i].addr)
1001             *(boolopt[i].addr) = boolopt[i].initvalue;
1002     }
1003 #if defined(COMPRESS) || defined(ZLIB_COMP)
1004     set_savepref("externalcomp");
1005     set_restpref("externalcomp");
1006 #ifdef RLECOMP
1007     set_savepref("!rlecomp");
1008     set_restpref("!rlecomp");
1009 #endif
1010 #else
1011 #ifdef ZEROCOMP
1012     set_savepref("zerocomp");
1013     set_restpref("zerocomp");
1014 #endif
1015 #ifdef RLECOMP
1016     set_savepref("rlecomp");
1017     set_restpref("rlecomp");
1018 #endif
1019 #endif
1020 #ifdef SYSFLAGS
1021     Strcpy(sysflags.sysflagsid, "sysflags");
1022     sysflags.sysflagsid[9] = (char) sizeof (struct sysflag);
1023 #endif
1024     flags.end_own = FALSE;
1025     flags.end_top = 3;
1026     flags.end_around = 2;
1027     flags.paranoia_bits = PARANOID_PRAY; /* old prayconfirm=TRUE */
1028     flags.pile_limit = PILE_LIMIT_DFLT;  /* 5 */
1029     flags.runmode = RUN_LEAP;
1030     iflags.msg_history = 20;
1031     /* msg_window has conflicting defaults for multi-interface binary */
1032 #ifdef TTY_GRAPHICS
1033     iflags.prevmsg_window = 's';
1034 #else
1035 #ifdef CURSES_GRAPHICS
1036     iflags.prevmsg_window = 'r';
1037 #endif
1038 #endif
1039     iflags.menu_headings = ATR_INVERSE;
1040     iflags.getpos_coords = GPCOORDS_NONE;
1041
1042     /* hero's role, race, &c haven't been chosen yet */
1043     flags.initrole = flags.initrace = flags.initgend = flags.initalign
1044         = ROLE_NONE;
1045
1046     init_ov_primary_symbols();
1047     init_ov_rogue_symbols();
1048     /* Set the default monster and object class symbols. */
1049     init_symbols();
1050     for (i = 0; i < WARNCOUNT; i++)
1051         warnsyms[i] = def_warnsyms[i].sym;
1052
1053     /* for "special achievement" tracking (see obj.h,
1054        create_object(sp_lev.c), addinv_core1(invent.c) */
1055     iflags.mines_prize_type = LUCKSTONE;
1056     iflags.soko_prize_type1 = BAG_OF_HOLDING;
1057     iflags.soko_prize_type2 = AMULET_OF_REFLECTION;
1058
1059     /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
1060     (void) memcpy((genericptr_t) flags.inv_order,
1061                   (genericptr_t) def_inv_order, sizeof flags.inv_order);
1062     flags.pickup_types[0] = '\0';
1063     flags.pickup_burden = MOD_ENCUMBER;
1064     flags.sortloot = 'l'; /* sort only loot by default */
1065
1066     for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
1067         flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
1068     switch_symbols(FALSE); /* set default characters */
1069     init_rogue_symbols();
1070 #if defined(UNIX) && defined(TTY_GRAPHICS)
1071     /*
1072      * Set defaults for some options depending on what we can
1073      * detect about the environment's capabilities.
1074      * This has to be done after the global initialization above
1075      * and before reading user-specific initialization via
1076      * config file/environment variable below.
1077      */
1078     /* this detects the IBM-compatible console on most 386 boxes */
1079     if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
1080         if (!symset[PRIMARY].explicitly)
1081             load_symset("IBMGraphics", PRIMARY);
1082         if (!symset[ROGUESET].explicitly)
1083             load_symset("RogueIBM", ROGUESET);
1084         switch_symbols(TRUE);
1085 #ifdef TEXTCOLOR
1086         iflags.use_color = TRUE;
1087 #endif
1088     }
1089 #endif /* UNIX && TTY_GRAPHICS */
1090 #if defined(UNIX) || defined(VMS)
1091 #ifdef TTY_GRAPHICS
1092     /* detect whether a "vt" terminal can handle alternate charsets */
1093     if ((opts = nh_getenv("TERM"))
1094         /* [could also check "xterm" which emulates vtXXX by default] */
1095         && !strncmpi(opts, "vt", 2)
1096         && AS && AE && index(AS, '\016') && index(AE, '\017')) {
1097         if (!symset[PRIMARY].explicitly)
1098             load_symset("DECGraphics", PRIMARY);
1099         switch_symbols(TRUE);
1100     }
1101 #endif
1102 #endif /* UNIX || VMS */
1103
1104 #if defined(MSDOS) || defined(WIN32)
1105     /* Use IBM defaults. Can be overridden via config file */
1106     if (!symset[PRIMARY].explicitly)
1107         load_symset("IBMGraphics_2", PRIMARY);
1108     if (!symset[ROGUESET].explicitly)
1109         load_symset("RogueEpyx", ROGUESET);
1110 #endif
1111 #ifdef MAC_GRAPHICS_ENV
1112     if (!symset[PRIMARY].explicitly)
1113         load_symset("MACGraphics", PRIMARY);
1114     switch_symbols(TRUE);
1115 #endif /* MAC_GRAPHICS_ENV */
1116     flags.menu_style = MENU_FULL;
1117
1118     iflags.wc_align_message = ALIGN_TOP;
1119     iflags.wc_align_status = ALIGN_BOTTOM;
1120     /* used by tty and curses */
1121     iflags.wc2_statuslines = 2;
1122     /* only used by curses */
1123     iflags.wc2_windowborders = 2; /* 'Auto' */
1124
1125     /* since this is done before init_objects(), do partial init here */
1126     objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
1127     nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
1128 }
1129
1130 void
1131 initoptions_finish()
1132 {
1133     nhsym sym = 0;
1134 #ifndef MAC
1135     char *opts = getenv("NETHACKOPTIONS");
1136
1137     if (!opts)
1138         opts = getenv("HACKOPTIONS");
1139     if (opts) {
1140         if (*opts == '/' || *opts == '\\' || *opts == '@') {
1141             if (*opts == '@')
1142                 opts++; /* @filename */
1143             /* looks like a filename */
1144             if (strlen(opts) < BUFSZ / 2) {
1145                 config_error_init(TRUE, opts, CONFIG_ERROR_SECURE);
1146                 read_config_file(opts, SET_IN_FILE);
1147                 config_error_done();
1148             }
1149         } else {
1150             config_error_init(TRUE, (char *) 0, FALSE);
1151             read_config_file((char *) 0, SET_IN_FILE);
1152             config_error_done();
1153             /* let the total length of options be long;
1154              * parseoptions() will check each individually
1155              */
1156             config_error_init(FALSE, "NETHACKOPTIONS", FALSE);
1157             (void) parseoptions(opts, TRUE, FALSE);
1158             config_error_done();
1159         }
1160     } else
1161 #endif /* !MAC */
1162     /*else*/ {
1163         config_error_init(TRUE, (char *) 0, FALSE);
1164         read_config_file((char *) 0, SET_IN_FILE);
1165         config_error_done();
1166     }
1167
1168     (void) fruitadd(pl_fruit, (struct fruit *) 0);
1169     /*
1170      * Remove "slime mold" from list of object names.  This will
1171      * prevent it from being wished unless it's actually present
1172      * as a named (or default) fruit.  Wishing for "fruit" will
1173      * result in the player's preferred fruit [better than "\033"].
1174      */
1175     obj_descr[SLIME_MOLD].oc_name = "fruit";
1176
1177     sym = get_othersym(SYM_BOULDER,
1178                 Is_rogue_level(&u.uz) ? ROGUESET : PRIMARY);
1179     if (sym)
1180         showsyms[SYM_BOULDER + SYM_OFF_X] = sym;
1181     reglyph_darkroom();
1182
1183 #ifdef STATUS_HILITES
1184     /*
1185      * A multi-interface binary might only support status highlighting
1186      * for some of the interfaces; check whether we asked for it but are
1187      * using one which doesn't.
1188      *
1189      * Option processing can take place before a user-decided WindowPort
1190      * is even initialized, so check for that too.
1191      */
1192     if (!WINDOWPORT("safe-startup")) {
1193         if (iflags.hilite_delta && !wc2_supported("statushilites")) {
1194             raw_printf("Status highlighting not supported for %s interface.",
1195                        windowprocs.name);
1196             iflags.hilite_delta = 0;
1197         }
1198     }
1199 #endif
1200     return;
1201 }
1202
1203 /* copy up to maxlen-1 characters; 'dest' must be able to hold maxlen;
1204    treat comma as alternate end of 'src' */
1205 STATIC_OVL void
1206 nmcpy(dest, src, maxlen)
1207 char *dest;
1208 const char *src;
1209 int maxlen;
1210 {
1211     int count;
1212
1213     for (count = 1; count < maxlen; count++) {
1214         if (*src == ',' || *src == '\0')
1215             break; /*exit on \0 terminator*/
1216         *dest++ = *src++;
1217     }
1218     *dest = '\0';
1219 }
1220
1221 /*
1222  * escapes(): escape expansion for showsyms.  C-style escapes understood
1223  * include \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal).
1224  * (Note: unlike in C, leading digit 0 is not used to indicate octal;
1225  * the letter o (either upper or lower case) is used for that.
1226  * The ^-prefix for control characters is also understood, and \[mM]
1227  * has the effect of 'meta'-ing the value which follows (so that the
1228  * alternate character set will be enabled).
1229  *
1230  * X     normal key X
1231  * ^X    control-X
1232  * \mX   meta-X
1233  *
1234  * For 3.4.3 and earlier, input ending with "\M", backslash, or caret
1235  * prior to terminating '\0' would pull that '\0' into the output and then
1236  * keep processing past it, potentially overflowing the output buffer.
1237  * Now, trailing \ or ^ will act like \\ or \^ and add '\\' or '^' to the
1238  * output and stop there; trailing \M will fall through to \<other> and
1239  * yield 'M', then stop.  Any \X or \O followed by something other than
1240  * an appropriate digit will also fall through to \<other> and yield 'X'
1241  * or 'O', plus stop if the non-digit is end-of-string.
1242  */
1243 STATIC_OVL void
1244 escapes(cp, tp)
1245 const char *cp; /* might be 'tp', updating in place */
1246 char *tp; /* result is never longer than 'cp' */
1247 {
1248     static NEARDATA const char oct[] = "01234567", dec[] = "0123456789",
1249                                hex[] = "00112233445566778899aAbBcCdDeEfF";
1250     const char *dp;
1251     int cval, meta, dcount;
1252
1253     while (*cp) {
1254         /* \M has to be followed by something to do meta conversion,
1255            otherwise it will just be \M which ultimately yields 'M' */
1256         meta = (*cp == '\\' && (cp[1] == 'm' || cp[1] == 'M') && cp[2]);
1257         if (meta)
1258             cp += 2;
1259
1260         cval = dcount = 0; /* for decimal, octal, hexadecimal cases */
1261         if ((*cp != '\\' && *cp != '^') || !cp[1]) {
1262             /* simple character, or nothing left for \ or ^ to escape */
1263             cval = *cp++;
1264         } else if (*cp == '^') { /* expand control-character syntax */
1265             cval = (*++cp & 0x1f);
1266             ++cp;
1267
1268         /* remaining cases are all for backslash; we know cp[1] is not \0 */
1269         } else if (index(dec, cp[1])) {
1270             ++cp; /* move past backslash to first digit */
1271             do {
1272                 cval = (cval * 10) + (*cp - '0');
1273             } while (*++cp && index(dec, *cp) && ++dcount < 3);
1274         } else if ((cp[1] == 'o' || cp[1] == 'O') && cp[2]
1275                    && index(oct, cp[2])) {
1276             cp += 2; /* move past backslash and 'O' */
1277             do {
1278                 cval = (cval * 8) + (*cp - '0');
1279             } while (*++cp && index(oct, *cp) && ++dcount < 3);
1280         } else if ((cp[1] == 'x' || cp[1] == 'X') && cp[2]
1281                    && (dp = index(hex, cp[2])) != 0) {
1282             cp += 2; /* move past backslash and 'X' */
1283             do {
1284                 cval = (cval * 16) + ((int) (dp - hex) / 2);
1285             } while (*++cp && (dp = index(hex, *cp)) != 0 && ++dcount < 2);
1286         } else { /* C-style character escapes */
1287             switch (*++cp) {
1288             case '\\':
1289                 cval = '\\';
1290                 break;
1291             case 'n':
1292                 cval = '\n';
1293                 break;
1294             case 't':
1295                 cval = '\t';
1296                 break;
1297             case 'b':
1298                 cval = '\b';
1299                 break;
1300             case 'r':
1301                 cval = '\r';
1302                 break;
1303             default:
1304                 cval = *cp;
1305             }
1306             ++cp;
1307         }
1308
1309         if (meta)
1310             cval |= 0x80;
1311         *tp++ = (char) cval;
1312     }
1313     *tp = '\0';
1314 }
1315
1316 STATIC_OVL void
1317 rejectoption(optname)
1318 const char *optname;
1319 {
1320 #ifdef MICRO
1321     pline("\"%s\" settable only from %s.", optname, configfile);
1322 #else
1323     pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
1324           configfile);
1325 #endif
1326 }
1327
1328 /*
1329
1330 # errors:
1331 OPTIONS=aaaaaaaaaa[ more than 247 (255 - 8 for 'OPTIONS=') total ]aaaaaaaaaa
1332 OPTIONS
1333 OPTIONS=
1334 MSGTYPE=stop"You swap places with "
1335 MSGTYPE=st.op "You swap places with "
1336 MSGTYPE=stop "You swap places with \"
1337 MENUCOLOR=" blessed "green&none
1338 MENUCOLOR=" holy " = green&reverse
1339 MENUCOLOR=" cursed " = red&uline
1340 MENUCOLOR=" unholy " = reed
1341 OPTIONS=!legacy:true,fooo
1342 OPTIONS=align:!pin
1343 OPTIONS=gender
1344
1345 */
1346
1347 STATIC_OVL char *
1348 string_for_opt(opts, val_optional)
1349 char *opts;
1350 boolean val_optional;
1351 {
1352     char *colon, *equals;
1353
1354     colon = index(opts, ':');
1355     equals = index(opts, '=');
1356     if (!colon || (equals && equals < colon))
1357         colon = equals;
1358
1359     if (!colon || !*++colon) {
1360         if (!val_optional)
1361 /*JP
1362             config_error_add("Missing parameter for '%s'", opts);
1363 */
1364             config_error_add("'%s'\82Ì\88ø\90\94\82ª\82 \82è\82Ü\82¹\82ñ", opts);
1365         return empty_optstr;
1366     }
1367     return colon;
1368 }
1369
1370 STATIC_OVL char *
1371 string_for_env_opt(optname, opts, val_optional)
1372 const char *optname;
1373 char *opts;
1374 boolean val_optional;
1375 {
1376     if (!initial) {
1377         rejectoption(optname);
1378         return empty_optstr;
1379     }
1380     return string_for_opt(opts, val_optional);
1381 }
1382
1383 STATIC_OVL void
1384 bad_negation(optname, with_parameter)
1385 const char *optname;
1386 boolean with_parameter;
1387 {
1388 #if 0 /*JP:T*/
1389     pline_The("%s option may not %sbe negated.", optname,
1390               with_parameter ? "both have a value and " : "");
1391 #else
1392     pline_The("%s\83I\83v\83V\83\87\83\93\82Í\94Û\92è%s\82Å\82«\82È\82¢\81D", optname,
1393               with_parameter ? "\82Æ\92l\8ew\92è\82Ì\97¼\95û\82Í" : "");
1394 #endif
1395 }
1396
1397 /*
1398  * Change the inventory order, using the given string as the new order.
1399  * Missing characters in the new order are filled in at the end from
1400  * the current inv_order, except for gold, which is forced to be first
1401  * if not explicitly present.
1402  *
1403  * This routine returns 1 unless there is a duplicate or bad char in
1404  * the string.
1405  */
1406 STATIC_OVL int
1407 change_inv_order(op)
1408 char *op;
1409 {
1410     int oc_sym, num;
1411     char *sp, buf[QBUFSZ];
1412     int retval = 1;
1413
1414     num = 0;
1415     if (!index(op, GOLD_SYM))
1416         buf[num++] = COIN_CLASS;
1417
1418     for (sp = op; *sp; sp++) {
1419         boolean fail = FALSE;
1420         oc_sym = def_char_to_objclass(*sp);
1421         /* reject bad or duplicate entries */
1422         if (oc_sym == MAXOCLASSES) { /* not an object class char */
1423             config_error_add("Not an object class '%c'", *sp);
1424             retval = 0;
1425             fail = TRUE;
1426         } else if (!index(flags.inv_order, oc_sym)) {
1427             /* VENOM_CLASS, RANDOM_CLASS, and ILLOBJ_CLASS are excluded
1428                because they aren't in def_inv_order[] so don't make it
1429                into flags.inv_order, hence always fail this index() test */
1430             config_error_add("Object class '%c' not allowed", *sp);
1431             retval = 0;
1432             fail = TRUE;
1433         } else if (index(sp + 1, *sp)) {
1434             config_error_add("Duplicate object class '%c'", *sp);
1435             retval = 0;
1436             fail = TRUE;
1437         }
1438         /* retain good ones */
1439         if (!fail)
1440             buf[num++] = (char) oc_sym;
1441     }
1442     buf[num] = '\0';
1443
1444     /* fill in any omitted classes, using previous ordering */
1445     for (sp = flags.inv_order; *sp; sp++)
1446         if (!index(buf, *sp))
1447             (void) strkitten(&buf[num++], *sp);
1448     buf[MAXOCLASSES - 1] = '\0';
1449
1450     Strcpy(flags.inv_order, buf);
1451     return retval;
1452 }
1453
1454 STATIC_OVL boolean
1455 warning_opts(opts, optype)
1456 register char *opts;
1457 const char *optype;
1458 {
1459     uchar translate[WARNCOUNT];
1460     int length, i;
1461
1462     if ((opts = string_for_env_opt(optype, opts, FALSE)) == empty_optstr)
1463         return FALSE;
1464     escapes(opts, opts);
1465
1466     length = (int) strlen(opts);
1467     /* match the form obtained from PC configuration files */
1468     for (i = 0; i < WARNCOUNT; i++)
1469         translate[i] = (i >= length) ? 0
1470                                      : opts[i] ? (uchar) opts[i]
1471                                                : def_warnsyms[i].sym;
1472     assign_warnings(translate);
1473     return TRUE;
1474 }
1475
1476 void
1477 assign_warnings(graph_chars)
1478 register uchar *graph_chars;
1479 {
1480     int i;
1481
1482     for (i = 0; i < WARNCOUNT; i++)
1483         if (graph_chars[i])
1484             warnsyms[i] = graph_chars[i];
1485 }
1486
1487 STATIC_OVL int
1488 feature_alert_opts(op, optn)
1489 char *op;
1490 const char *optn;
1491 {
1492     char buf[BUFSZ];
1493     unsigned long fnv = get_feature_notice_ver(op); /* version.c */
1494
1495     if (fnv == 0L)
1496         return 0;
1497     if (fnv > get_current_feature_ver()) {
1498         if (!initial) {
1499 /*JP
1500             You_cant("disable new feature alerts for future versions.");
1501 */
1502             You_cant("\8f«\97\88\82Ì\83o\81[\83W\83\87\83\93\82Ì\8b@\94\\8cx\8d\90\82ð\96³\8cø\82É\82·\82é\82±\82Æ\82Í\82Å\82«\82È\82¢\81D");
1503         } else {
1504             config_error_add(
1505                         "%s=%s Invalid reference to a future version ignored",
1506                              optn, op);
1507         }
1508         return 0;
1509     }
1510
1511     flags.suppress_alert = fnv;
1512     if (!initial) {
1513         Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
1514                 FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
1515 #if 0 /*JP:T*/
1516         pline(
1517           "Feature change alerts disabled for NetHack %s features and prior.",
1518               buf);
1519 #else
1520         pline(
1521           "NetHack %s \88È\91O\82Ì\8b@\94\\82É\91Î\82·\82é\8b@\94\\95Ï\8dX\8cx\8d\90\82ð\96³\8cø\82É\82µ\82½\81D",
1522               buf);
1523 #endif
1524     }
1525     return 1;
1526 }
1527
1528 void
1529 set_duplicate_opt_detection(on_or_off)
1530 int on_or_off;
1531 {
1532     int k, *optptr;
1533
1534     if (on_or_off != 0) {
1535         /*-- ON --*/
1536         if (iflags.opt_booldup)
1537             impossible("iflags.opt_booldup already on (memory leak)");
1538         iflags.opt_booldup = (int *) alloc(SIZE(boolopt) * sizeof (int));
1539         optptr = iflags.opt_booldup;
1540         for (k = 0; k < SIZE(boolopt); ++k)
1541             *optptr++ = 0;
1542
1543         if (iflags.opt_compdup)
1544             impossible("iflags.opt_compdup already on (memory leak)");
1545         iflags.opt_compdup = (int *) alloc(SIZE(compopt) * sizeof (int));
1546         optptr = iflags.opt_compdup;
1547         for (k = 0; k < SIZE(compopt); ++k)
1548             *optptr++ = 0;
1549     } else {
1550         /*-- OFF --*/
1551         if (iflags.opt_booldup)
1552             free((genericptr_t) iflags.opt_booldup);
1553         iflags.opt_booldup = (int *) 0;
1554         if (iflags.opt_compdup)
1555             free((genericptr_t) iflags.opt_compdup);
1556         iflags.opt_compdup = (int *) 0;
1557     }
1558 }
1559
1560 STATIC_OVL boolean
1561 duplicate_opt_detection(opts, iscompound)
1562 const char *opts;
1563 int iscompound; /* 0 == boolean option, 1 == compound */
1564 {
1565     int i, *optptr;
1566
1567     if (!iscompound && iflags.opt_booldup && initial && from_file) {
1568         for (i = 0; boolopt[i].name; i++) {
1569             if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
1570                 optptr = iflags.opt_booldup + i;
1571                 *optptr += 1;
1572                 if (*optptr > 1)
1573                     return TRUE;
1574                 else
1575                     return FALSE;
1576             }
1577         }
1578     } else if (iscompound && iflags.opt_compdup && initial && from_file) {
1579         for (i = 0; compopt[i].name; i++) {
1580             if (match_optname(opts, compopt[i].name, strlen(compopt[i].name),
1581                               TRUE)) {
1582                 optptr = iflags.opt_compdup + i;
1583                 *optptr += 1;
1584                 if (*optptr > 1)
1585                     return TRUE;
1586                 else
1587                     return FALSE;
1588             }
1589         }
1590     }
1591     return FALSE;
1592 }
1593
1594 STATIC_OVL void
1595 complain_about_duplicate(opts, iscompound)
1596 const char *opts;
1597 int iscompound; /* 0 == boolean option, 1 == compound */
1598 {
1599 #ifdef MAC
1600     /* the Mac has trouble dealing with the output of messages while
1601      * processing the config file.  That should get fixed one day.
1602      * For now just return.
1603      */
1604 #else /* !MAC */
1605 #if 0 /*JP:T*/
1606     config_error_add("%s option specified multiple times: %s",
1607                      iscompound ? "compound" : "boolean", opts);
1608 #else
1609     config_error_add("%s\83I\83v\83V\83\87\83\93\82ª\95¡\90\94\89ñ\8ew\92è\82³\82ê\82Ä\82¢\82Ü\82·\81F%s",
1610                      iscompound ? "\95¡\8d\87" : "\90^\8bU\92l", opts);
1611 #endif
1612 #endif /* ?MAC */
1613     return;
1614 }
1615
1616 /* paranoia[] - used by parseoptions() and special_handling() */
1617 STATIC_VAR const struct paranoia_opts {
1618     int flagmask;        /* which paranoid option */
1619     const char *argname; /* primary name */
1620     int argMinLen;       /* minimum number of letters to match */
1621     const char *synonym; /* alternate name (optional) */
1622     int synMinLen;
1623     const char *explain; /* for interactive menu */
1624 } paranoia[] = {
1625     /* there are some initial-letter conflicts: "a"ttack vs "a"ll, "attack"
1626        takes precedence and "all" isn't present in the interactive menu,
1627        and "d"ie vs "d"eath, synonyms for each other so doesn't matter;
1628        (also "p"ray vs "P"aranoia, "pray" takes precedence since "Paranoia"
1629        is just a synonym for "Confirm"); "b"ones vs "br"eak-wand, the
1630        latter requires at least two letters; "e"at vs "ex"plore,
1631        "cont"inue eating vs "C"onfirm; "wand"-break vs "Were"-change,
1632        both require at least two letters during config processing and use
1633        case-senstivity for 'O's interactive menu */
1634     { PARANOID_CONFIRM, "Confirm", 1, "Paranoia", 2,
1635 /*JP
1636       "for \"yes\" confirmations, require \"no\" to reject" },
1637 */
1638       "\"yes\"\82ð\8am\94F\82·\82é\82Æ\82«\82É\81C\8b\91\94Û\82·\82é\82Æ\82«\82É\82Í\"no\"\82ª\95K\97v" },
1639     { PARANOID_QUIT, "quit", 1, "explore", 2,
1640 /*JP
1641       "yes vs y to quit or to enter explore mode" },
1642 */
1643       "\8fI\97¹\82Ü\82½\82Í\92T\8c\9f\83\82\81[\83h\82É\93ü\82é\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1644     { PARANOID_DIE, "die", 1, "death", 2,
1645 /*JP
1646       "yes vs y to die (explore mode or debug mode)" },
1647 */
1648       "(\92T\8c\9f\83\82\81[\83h\82©\83f\83o\83b\83O\83\82\81[\83h\82Å)\8e\80\82Ê\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1649     { PARANOID_BONES, "bones", 1, 0, 0,
1650 /*JP
1651       "yes vs y to save bones data when dying in debug mode" },
1652 */
1653       "\83f\83o\83b\83O\83\82\81[\83h\82Å\8e\80\82ñ\82Å\8d\9c\83f\81[\83^\82ð\95Û\91\82·\82é\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1654     { PARANOID_HIT, "attack", 1, "hit", 1,
1655 /*JP
1656       "yes vs y to attack a peaceful monster" },
1657 */
1658       "\97F\8dD\93I\89ö\95¨\82ð\8dU\8c\82\82·\82é\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1659     { PARANOID_BREAKWAND, "wand-break", 2, "break-wand", 2,
1660 /*JP
1661       "yes vs y to break a wand via (a)pply" },
1662 */
1663       "(a)pply\82Å\8fñ\82ð\90Ü\82é\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1664     { PARANOID_EATING, "eat", 1, "continue", 4,
1665       "yes vs y to continue eating after first bite when satiated" },
1666     { PARANOID_WERECHANGE, "Were-change", 2, (const char *) 0, 0,
1667 /*JP
1668       "yes vs y to change form when lycanthropy is controllable" },
1669 */
1670       "\8fb\89»\95a\82ª\90§\8cä\89Â\94\\82È\8fê\8d\87\82É\95Ï\89»\82·\82é\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1671     { PARANOID_PRAY, "pray", 1, 0, 0,
1672 /*JP
1673       "y to pray (supersedes old \"prayconfirm\" option)" },
1674 */
1675       "\8bF\82é\82Æ\82«\82Éy\82ª\95K\97v(\8cÃ\82¢\"prayconfirm\"\83I\83v\83V\83\87\83\93\82ð\8fã\8f\91\82«\82·\82é)" },
1676     { PARANOID_REMOVE, "Remove", 1, "Takeoff", 1,
1677 /*JP
1678       "always pick from inventory for Remove and Takeoff" },
1679 */
1680       "Remove\82ÆTakeoff\82Å\8fí\82É\8e\9d\82¿\95¨\88ê\97\97\82©\82ç\91I\82Ô" },
1681     /* for config file parsing; interactive menu skips these */
1682     { 0, "none", 4, 0, 0, 0 }, /* require full word match */
1683     { ~0, "all", 3, 0, 0, 0 }, /* ditto */
1684 };
1685
1686 extern struct menucoloring *menu_colorings;
1687
1688 static const struct {
1689     const char *name;
1690     const int color;
1691 } colornames[] = {
1692     { "black", CLR_BLACK },
1693     { "red", CLR_RED },
1694     { "green", CLR_GREEN },
1695     { "brown", CLR_BROWN },
1696     { "blue", CLR_BLUE },
1697     { "magenta", CLR_MAGENTA },
1698     { "cyan", CLR_CYAN },
1699     { "gray", CLR_GRAY },
1700     { "orange", CLR_ORANGE },
1701     { "light green", CLR_BRIGHT_GREEN },
1702     { "yellow", CLR_YELLOW },
1703     { "light blue", CLR_BRIGHT_BLUE },
1704     { "light magenta", CLR_BRIGHT_MAGENTA },
1705     { "light cyan", CLR_BRIGHT_CYAN },
1706     { "white", CLR_WHITE },
1707     { "no color", NO_COLOR },
1708     { NULL, CLR_BLACK }, /* everything after this is an alias */
1709     { "transparent", NO_COLOR },
1710     { "purple", CLR_MAGENTA },
1711     { "light purple", CLR_BRIGHT_MAGENTA },
1712     { "bright purple", CLR_BRIGHT_MAGENTA },
1713     { "grey", CLR_GRAY },
1714     { "bright red", CLR_ORANGE },
1715     { "bright green", CLR_BRIGHT_GREEN },
1716     { "bright blue", CLR_BRIGHT_BLUE },
1717     { "bright magenta", CLR_BRIGHT_MAGENTA },
1718     { "bright cyan", CLR_BRIGHT_CYAN }
1719 };
1720
1721 static const struct {
1722     const char *name;
1723     const int attr;
1724 } attrnames[] = {
1725     { "none", ATR_NONE },
1726     { "bold", ATR_BOLD },
1727     { "dim", ATR_DIM },
1728     { "underline", ATR_ULINE },
1729     { "blink", ATR_BLINK },
1730     { "inverse", ATR_INVERSE },
1731     { NULL, ATR_NONE }, /* everything after this is an alias */
1732     { "normal", ATR_NONE },
1733     { "uline", ATR_ULINE },
1734     { "reverse", ATR_INVERSE },
1735 };
1736
1737 const char *
1738 clr2colorname(clr)
1739 int clr;
1740 {
1741     int i;
1742
1743     for (i = 0; i < SIZE(colornames); i++)
1744         if (colornames[i].name && colornames[i].color == clr)
1745             return colornames[i].name;
1746     return (char *) 0;
1747 }
1748
1749 int
1750 match_str2clr(str)
1751 char *str;
1752 {
1753     int i, c = CLR_MAX;
1754
1755     /* allow "lightblue", "light blue", and "light-blue" to match "light blue"
1756        (also junk like "_l i-gh_t---b l u e" but we won't worry about that);
1757        also copes with trailing space; caller has removed any leading space */
1758     for (i = 0; i < SIZE(colornames); i++)
1759         if (colornames[i].name
1760             && fuzzymatch(str, colornames[i].name, " -_", TRUE)) {
1761             c = colornames[i].color;
1762             break;
1763         }
1764     if (i == SIZE(colornames) && digit(*str))
1765         c = atoi(str);
1766
1767     if (c < 0 || c >= CLR_MAX) {
1768         config_error_add("Unknown color '%.60s'", str);
1769         c = CLR_MAX; /* "none of the above" */
1770     }
1771
1772     return c;
1773 }
1774
1775 STATIC_OVL const char *
1776 attr2attrname(attr)
1777 int attr;
1778 {
1779     int i;
1780
1781     for (i = 0; i < SIZE(attrnames); i++)
1782         if (attrnames[i].attr == attr)
1783             return attrnames[i].name;
1784     return (char *) 0;
1785 }
1786
1787 int
1788 match_str2attr(str, complain)
1789 const char *str;
1790 boolean complain;
1791 {
1792     int i, a = -1;
1793
1794     for (i = 0; i < SIZE(attrnames); i++)
1795         if (attrnames[i].name
1796             && fuzzymatch(str, attrnames[i].name, " -_", TRUE)) {
1797             a = attrnames[i].attr;
1798             break;
1799         }
1800
1801     if (a == -1 && complain)
1802         config_error_add("Unknown text attribute '%.50s'", str);
1803
1804     return a;
1805 }
1806
1807 int
1808 query_color(prompt)
1809 const char *prompt;
1810 {
1811     winid tmpwin;
1812     anything any;
1813     int i, pick_cnt;
1814     menu_item *picks = (menu_item *) 0;
1815
1816     tmpwin = create_nhwindow(NHW_MENU);
1817     start_menu(tmpwin);
1818     any = zeroany;
1819     for (i = 0; i < SIZE(colornames); i++) {
1820         if (!colornames[i].name)
1821             break;
1822         any.a_int = i + 1;
1823         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, colornames[i].name,
1824                  (colornames[i].color == NO_COLOR) ? MENU_SELECTED
1825                                                    : MENU_UNSELECTED);
1826     }
1827     end_menu(tmpwin, (prompt && *prompt) ? prompt : "Pick a color");
1828     pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
1829     destroy_nhwindow(tmpwin);
1830     if (pick_cnt > 0) {
1831         i = colornames[picks[0].item.a_int - 1].color;
1832         /* pick_cnt==2: explicitly picked something other than the
1833            preselected entry */
1834         if (pick_cnt == 2 && i == NO_COLOR)
1835             i = colornames[picks[1].item.a_int - 1].color;
1836         free((genericptr_t) picks);
1837         return i;
1838     } else if (pick_cnt == 0) {
1839         /* pick_cnt==0: explicitly picking preselected entry toggled it off */
1840         return NO_COLOR;
1841     }
1842     return -1;
1843 }
1844
1845 /* ask about highlighting attribute; for menu headers and menu
1846    coloring patterns, only one attribute at a time is allowed;
1847    for status highlighting, multiple attributes are allowed [overkill;
1848    life would be much simpler if that were restricted to one also...] */
1849 int
1850 query_attr(prompt)
1851 const char *prompt;
1852 {
1853     winid tmpwin;
1854     anything any;
1855     int i, pick_cnt;
1856     menu_item *picks = (menu_item *) 0;
1857     boolean allow_many = (prompt && !strncmpi(prompt, "Choose", 6));
1858     int default_attr = ATR_NONE;
1859
1860     if (prompt && strstri(prompt, "menu headings"))
1861         default_attr = iflags.menu_headings;
1862     tmpwin = create_nhwindow(NHW_MENU);
1863     start_menu(tmpwin);
1864     any = zeroany;
1865     for (i = 0; i < SIZE(attrnames); i++) {
1866         if (!attrnames[i].name)
1867             break;
1868         any.a_int = i + 1;
1869         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, attrnames[i].attr,
1870                  attrnames[i].name,
1871                  (attrnames[i].attr == default_attr) ? MENU_SELECTED
1872                                                      : MENU_UNSELECTED);
1873     }
1874     end_menu(tmpwin, (prompt && *prompt) ? prompt : "Pick an attribute");
1875     pick_cnt = select_menu(tmpwin, allow_many ? PICK_ANY : PICK_ONE, &picks);
1876     destroy_nhwindow(tmpwin);
1877     if (pick_cnt > 0) {
1878         int j, k = 0;
1879
1880         if (allow_many) {
1881             /* PICK_ANY, with one preselected entry (ATR_NONE) which
1882                should be excluded if any other choices were picked */
1883             for (i = 0; i < pick_cnt; ++i) {
1884                 j = picks[i].item.a_int - 1;
1885                 if (attrnames[j].attr != ATR_NONE || pick_cnt == 1) {
1886                     switch (attrnames[j].attr) {
1887                     case ATR_DIM:
1888                         k |= HL_DIM;
1889                         break;
1890                     case ATR_BLINK:
1891                         k |= HL_BLINK;
1892                         break;
1893                     case ATR_ULINE:
1894                         k |= HL_ULINE;
1895                         break;
1896                     case ATR_INVERSE:
1897                         k |= HL_INVERSE;
1898                         break;
1899                     case ATR_BOLD:
1900                         k |= HL_BOLD;
1901                         break;
1902                     case ATR_NONE:
1903                         k = HL_NONE;
1904                         break;
1905                     }
1906                 }
1907             }
1908         } else {
1909             /* PICK_ONE, but might get 0 or 2 due to preselected entry */
1910             j = picks[0].item.a_int - 1;
1911             /* pick_cnt==2: explicitly picked something other than the
1912                preselected entry */
1913             if (pick_cnt == 2 && attrnames[j].attr == default_attr)
1914                 j = picks[1].item.a_int - 1;
1915             k = attrnames[j].attr;
1916         }
1917         free((genericptr_t) picks);
1918         return k;
1919     } else if (pick_cnt == 0 && !allow_many) {
1920         /* PICK_ONE, preselected entry explicitly chosen */
1921         return default_attr;
1922     }
1923     /* either ESC to explicitly cancel (pick_cnt==-1) or
1924        PICK_ANY with preselected entry toggled off and nothing chosen */
1925     return -1;
1926 }
1927
1928 static const struct {
1929     const char *name;
1930     xchar msgtyp;
1931     const char *descr;
1932 } msgtype_names[] = {
1933 /*JP
1934     { "show", MSGTYP_NORMAL, "Show message normally" },
1935 */
1936     { "show", MSGTYP_NORMAL, "\92Ê\8fí\92Ê\82è\83\81\83b\83Z\81[\83W\82ð\95\\8e¦\82·\82é" },
1937 /*JP
1938     { "hide", MSGTYP_NOSHOW, "Hide message" },
1939 */
1940     { "hide", MSGTYP_NOSHOW, "\83\81\83b\83Z\81[\83W\82ð\95\\8e¦\82µ\82È\82¢" },
1941     { "noshow", MSGTYP_NOSHOW, NULL },
1942 /*JP
1943     { "stop", MSGTYP_STOP, "Prompt for more after the message" },
1944 */
1945     { "stop", MSGTYP_STOP, "more\83v\83\8d\83\93\83v\83g\82Å\91Ò\82Â" },
1946     { "more", MSGTYP_STOP, NULL },
1947 /*JP
1948     { "norep", MSGTYP_NOREP, "Do not repeat the message" }
1949 */
1950     { "norep", MSGTYP_NOREP, "\82±\82Ì\83\81\83b\83Z\81[\83W\82Í\8cJ\82è\95Ô\82³\82È\82¢" }
1951 };
1952
1953 STATIC_OVL const char *
1954 msgtype2name(typ)
1955 int typ;
1956 {
1957     int i;
1958
1959     for (i = 0; i < SIZE(msgtype_names); i++)
1960         if (msgtype_names[i].descr && msgtype_names[i].msgtyp == typ)
1961             return msgtype_names[i].name;
1962     return (char *) 0;
1963 }
1964
1965 STATIC_OVL int
1966 query_msgtype()
1967 {
1968     winid tmpwin;
1969     anything any;
1970     int i, pick_cnt;
1971     menu_item *picks = (menu_item *) 0;
1972
1973     tmpwin = create_nhwindow(NHW_MENU);
1974     start_menu(tmpwin);
1975     any = zeroany;
1976     for (i = 0; i < SIZE(msgtype_names); i++)
1977         if (msgtype_names[i].descr) {
1978             any.a_int = msgtype_names[i].msgtyp + 1;
1979             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1980                  msgtype_names[i].descr, MENU_UNSELECTED);
1981         }
1982 /*JP
1983     end_menu(tmpwin, "How to show the message");
1984 */
1985     end_menu(tmpwin, "\83\81\83b\83Z\81[\83W\82Ì\95\\8e¦\95û\96@");
1986     pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
1987     destroy_nhwindow(tmpwin);
1988     if (pick_cnt > 0) {
1989         i = picks->item.a_int - 1;
1990         free((genericptr_t) picks);
1991         return i;
1992     }
1993     return -1;
1994 }
1995
1996 STATIC_OVL boolean
1997 msgtype_add(typ, pattern)
1998 int typ;
1999 char *pattern;
2000 {
2001     struct plinemsg_type *tmp = (struct plinemsg_type *) alloc(sizeof *tmp);
2002
2003     tmp->msgtype = typ;
2004     tmp->regex = regex_init();
2005     if (!regex_compile(pattern, tmp->regex)) {
2006         static const char *re_error = "MSGTYPE regex error";
2007
2008         config_error_add("%s: %s", re_error, regex_error_desc(tmp->regex));
2009         regex_free(tmp->regex);
2010         free((genericptr_t) tmp);
2011         return FALSE;
2012     }
2013     tmp->pattern = dupstr(pattern);
2014     tmp->next = plinemsg_types;
2015     plinemsg_types = tmp;
2016     return TRUE;
2017 }
2018
2019 void
2020 msgtype_free()
2021 {
2022     struct plinemsg_type *tmp, *tmp2 = 0;
2023
2024     for (tmp = plinemsg_types; tmp; tmp = tmp2) {
2025         tmp2 = tmp->next;
2026         free((genericptr_t) tmp->pattern);
2027         regex_free(tmp->regex);
2028         free((genericptr_t) tmp);
2029     }
2030     plinemsg_types = (struct plinemsg_type *) 0;
2031 }
2032
2033 STATIC_OVL void
2034 free_one_msgtype(idx)
2035 int idx; /* 0 .. */
2036 {
2037     struct plinemsg_type *tmp = plinemsg_types;
2038     struct plinemsg_type *prev = NULL;
2039
2040     while (tmp) {
2041         if (idx == 0) {
2042             struct plinemsg_type *next = tmp->next;
2043
2044             regex_free(tmp->regex);
2045             free((genericptr_t) tmp->pattern);
2046             free((genericptr_t) tmp);
2047             if (prev)
2048                 prev->next = next;
2049             else
2050                 plinemsg_types = next;
2051             return;
2052         }
2053         idx--;
2054         prev = tmp;
2055         tmp = tmp->next;
2056     }
2057 }
2058
2059 int
2060 msgtype_type(msg, norepeat)
2061 const char *msg;
2062 boolean norepeat; /* called from Norep(via pline) */
2063 {
2064     struct plinemsg_type *tmp = plinemsg_types;
2065
2066     while (tmp) {
2067         /* we don't exclude entries with negative msgtype values
2068            because then the msg might end up matching a later pattern */
2069         if (regex_match(msg, tmp->regex))
2070             return tmp->msgtype;
2071         tmp = tmp->next;
2072     }
2073     return norepeat ? MSGTYP_NOREP : MSGTYP_NORMAL;
2074 }
2075
2076 /* negate one or more types of messages so that their type handling will
2077    be disabled or re-enabled; MSGTYPE_NORMAL (value 0) is not affected */
2078 void
2079 hide_unhide_msgtypes(hide, hide_mask)
2080 boolean hide;
2081 int hide_mask;
2082 {
2083     struct plinemsg_type *tmp;
2084     int mt;
2085
2086     /* negative msgtype value won't be recognized by pline, so does nothing */
2087     for (tmp = plinemsg_types; tmp; tmp = tmp->next) {
2088         mt = tmp->msgtype;
2089         if (!hide)
2090             mt = -mt; /* unhide: negate negative, yielding positive */
2091         if (mt > 0 && ((1 << mt) & hide_mask))
2092             tmp->msgtype = -tmp->msgtype;
2093     }
2094 }
2095
2096 STATIC_OVL int
2097 msgtype_count(VOID_ARGS)
2098 {
2099     int c = 0;
2100     struct plinemsg_type *tmp = plinemsg_types;
2101
2102     while (tmp) {
2103         c++;
2104         tmp = tmp->next;
2105     }
2106     return c;
2107 }
2108
2109 boolean
2110 msgtype_parse_add(str)
2111 char *str;
2112 {
2113     char pattern[256];
2114     char msgtype[11];
2115
2116     if (sscanf(str, "%10s \"%255[^\"]\"", msgtype, pattern) == 2) {
2117         int typ = -1;
2118         int i;
2119
2120         for (i = 0; i < SIZE(msgtype_names); i++)
2121             if (!strncmpi(msgtype_names[i].name, msgtype, strlen(msgtype))) {
2122                 typ = msgtype_names[i].msgtyp;
2123                 break;
2124             }
2125         if (typ != -1)
2126             return msgtype_add(typ, pattern);
2127         else
2128             config_error_add("Unknown message type '%s'", msgtype);
2129     } else {
2130         config_error_add("Malformed MSGTYPE");
2131     }
2132     return FALSE;
2133 }
2134
2135 STATIC_OVL boolean
2136 test_regex_pattern(str, errmsg)
2137 const char *str;
2138 const char *errmsg;
2139 {
2140     static const char re_error[] = "Regex error";
2141     struct nhregex *match;
2142     boolean retval = TRUE;
2143
2144     if (!str)
2145         return FALSE;
2146
2147     match = regex_init();
2148     if (!match) {
2149         config_error_add("NHregex error");
2150         return FALSE;
2151     }
2152
2153     if (!regex_compile(str, match)) {
2154         config_error_add("%s: %s", errmsg ? errmsg : re_error,
2155                          regex_error_desc(match));
2156         retval = FALSE;
2157     }
2158     regex_free(match);
2159     return retval;
2160 }
2161
2162 STATIC_OVL boolean
2163 add_menu_coloring_parsed(str, c, a)
2164 char *str;
2165 int c, a;
2166 {
2167     static const char re_error[] = "Menucolor regex error";
2168     struct menucoloring *tmp;
2169
2170     if (!str)
2171         return FALSE;
2172     tmp = (struct menucoloring *) alloc(sizeof *tmp);
2173     tmp->match = regex_init();
2174     if (!regex_compile(str, tmp->match)) {
2175         config_error_add("%s: %s", re_error, regex_error_desc(tmp->match));
2176         regex_free(tmp->match);
2177         free(tmp);
2178         return FALSE;
2179     } else {
2180         tmp->next = menu_colorings;
2181         tmp->origstr = dupstr(str);
2182         tmp->color = c;
2183         tmp->attr = a;
2184         menu_colorings = tmp;
2185         return TRUE;
2186     }
2187 }
2188
2189 /* parse '"regex_string"=color&attr' and add it to menucoloring */
2190 boolean
2191 add_menu_coloring(tmpstr)
2192 char *tmpstr; /* never Null but could be empty */
2193 {
2194     int c = NO_COLOR, a = ATR_NONE;
2195     char *tmps, *cs, *amp;
2196     char str[BUFSZ];
2197
2198     (void) strncpy(str, tmpstr, sizeof str - 1);
2199     str[sizeof str - 1] = '\0';
2200
2201     if ((cs = index(str, '=')) == 0) {
2202         config_error_add("Malformed MENUCOLOR");
2203         return FALSE;
2204     }
2205
2206     tmps = cs + 1; /* advance past '=' */
2207     mungspaces(tmps);
2208     if ((amp = index(tmps, '&')) != 0)
2209         *amp = '\0';
2210
2211     c = match_str2clr(tmps);
2212     if (c >= CLR_MAX)
2213         return FALSE;
2214
2215     if (amp) {
2216         tmps = amp + 1; /* advance past '&' */
2217         a = match_str2attr(tmps, TRUE);
2218         if (a == -1)
2219             return FALSE;
2220     }
2221
2222     /* the regexp portion here has not been condensed by mungspaces() */
2223     *cs = '\0';
2224     tmps = str;
2225     if (*tmps == '"' || *tmps == '\'') {
2226         cs--;
2227         while (isspace((uchar) *cs))
2228             cs--;
2229         if (*cs == *tmps) {
2230             *cs = '\0';
2231             tmps++;
2232         }
2233     }
2234     return add_menu_coloring_parsed(tmps, c, a);
2235 }
2236
2237 boolean
2238 get_menu_coloring(str, color, attr)
2239 const char *str;
2240 int *color, *attr;
2241 {
2242     struct menucoloring *tmpmc;
2243
2244     if (iflags.use_menu_color)
2245         for (tmpmc = menu_colorings; tmpmc; tmpmc = tmpmc->next)
2246             if (regex_match(str, tmpmc->match)) {
2247                 *color = tmpmc->color;
2248                 *attr = tmpmc->attr;
2249                 return TRUE;
2250             }
2251     return FALSE;
2252 }
2253
2254 void
2255 free_menu_coloring()
2256 {
2257     struct menucoloring *tmp, *tmp2;
2258
2259     for (tmp = menu_colorings; tmp; tmp = tmp2) {
2260         tmp2 = tmp->next;
2261         regex_free(tmp->match);
2262         free((genericptr_t) tmp->origstr);
2263         free((genericptr_t) tmp);
2264     }
2265 }
2266
2267 STATIC_OVL void
2268 free_one_menu_coloring(idx)
2269 int idx; /* 0 .. */
2270 {
2271     struct menucoloring *tmp = menu_colorings;
2272     struct menucoloring *prev = NULL;
2273
2274     while (tmp) {
2275         if (idx == 0) {
2276             struct menucoloring *next = tmp->next;
2277
2278             regex_free(tmp->match);
2279             free((genericptr_t) tmp->origstr);
2280             free((genericptr_t) tmp);
2281             if (prev)
2282                 prev->next = next;
2283             else
2284                 menu_colorings = next;
2285             return;
2286         }
2287         idx--;
2288         prev = tmp;
2289         tmp = tmp->next;
2290     }
2291 }
2292
2293 STATIC_OVL int
2294 count_menucolors(VOID_ARGS)
2295 {
2296     struct menucoloring *tmp;
2297     int count = 0;
2298
2299     for (tmp = menu_colorings; tmp; tmp = tmp->next)
2300         count++;
2301     return count;
2302 }
2303
2304 STATIC_OVL boolean
2305 parse_role_opts(negated, fullname, opts, opp)
2306 boolean negated;
2307 const char *fullname;
2308 char *opts;
2309 char **opp;
2310 {
2311     char *op = *opp;
2312
2313     if (negated) {
2314         bad_negation(fullname, FALSE);
2315     } else if ((op = string_for_env_opt(fullname, opts, FALSE))
2316                                         != empty_optstr) {
2317         boolean val_negated = FALSE;
2318
2319         while ((*op == '!') || !strncmpi(op, "no", 2)) {
2320             if (*op == '!')
2321                 op++;
2322             else
2323                 op += 2;
2324             val_negated = !val_negated;
2325         }
2326         if (val_negated) {
2327             if (!setrolefilter(op)) {
2328                 config_error_add("Unknown negated parameter '%s'", op);
2329                 return FALSE;
2330             }
2331         } else {
2332             if (duplicate_opt_detection(opts, 1))
2333                 complain_about_duplicate(opts, 1);
2334             *opp = op;
2335             return TRUE;
2336         }
2337     }
2338     return FALSE;
2339 }
2340
2341 /* Check if character c is illegal as a menu command key */
2342 boolean
2343 illegal_menu_cmd_key(c)
2344 char c;
2345 {
2346     if (c == 0 || c == '\r' || c == '\n' || c == '\033'
2347         || c == ' ' || digit(c) || (letter(c) && c != '@')) {
2348         config_error_add("Reserved menu command key '%s'", visctrl(c));
2349         return TRUE;
2350     } else { /* reject default object class symbols */
2351         int j;
2352         for (j = 1; j < MAXOCLASSES; j++)
2353             if (c == def_oc_syms[j].sym) {
2354                 config_error_add("Menu command key '%s' is an object class",
2355                                  visctrl(c));
2356                 return TRUE;
2357             }
2358     }
2359     return FALSE;
2360 }
2361
2362 boolean
2363 parseoptions(opts, tinitial, tfrom_file)
2364 register char *opts;
2365 boolean tinitial, tfrom_file;
2366 {
2367     char *op;
2368     unsigned num;
2369     boolean negated, duplicate;
2370     int i;
2371     const char *fullname;
2372     boolean retval = TRUE;
2373
2374     initial = tinitial;
2375     from_file = tfrom_file;
2376     if ((op = index(opts, ',')) != 0) {
2377         *op++ = 0;
2378         if (!parseoptions(op, initial, from_file))
2379             retval = FALSE;
2380     }
2381     if (strlen(opts) > BUFSZ / 2) {
2382         config_error_add("Option too long, max length is %i characters",
2383                          (BUFSZ / 2));
2384         return FALSE;
2385     }
2386
2387     /* strip leading and trailing white space */
2388     while (isspace((uchar) *opts))
2389         opts++;
2390     op = eos(opts);
2391     while (--op >= opts && isspace((uchar) *op))
2392         *op = '\0';
2393
2394     if (!*opts) {
2395         config_error_add("Empty statement");
2396         return FALSE;
2397     }
2398     negated = FALSE;
2399     while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
2400         if (*opts == '!')
2401             opts++;
2402         else
2403             opts += 2;
2404         negated = !negated;
2405     }
2406
2407     /* variant spelling */
2408
2409     if (match_optname(opts, "colour", 5, FALSE))
2410         Strcpy(opts, "color"); /* fortunately this isn't longer */
2411
2412     /* special boolean options */
2413
2414     if (match_optname(opts, "female", 3, FALSE)) {
2415         if (duplicate_opt_detection(opts, 0))
2416             complain_about_duplicate(opts, 0);
2417         if (!initial && flags.female == negated) {
2418             config_error_add("That is not anatomically possible.");
2419             return FALSE;
2420         } else
2421             flags.initgend = flags.female = !negated;
2422         return retval;
2423     }
2424
2425     if (match_optname(opts, "male", 4, FALSE)) {
2426         if (duplicate_opt_detection(opts, 0))
2427             complain_about_duplicate(opts, 0);
2428         if (!initial && flags.female != negated) {
2429             config_error_add("That is not anatomically possible.");
2430             return FALSE;
2431         } else
2432             flags.initgend = flags.female = negated;
2433         return retval;
2434     }
2435
2436 #if defined(MICRO) && !defined(AMIGA)
2437     /* included for compatibility with old NetHack.cnf files */
2438     if (match_optname(opts, "IBM_", 4, FALSE)) {
2439         iflags.BIOS = !negated;
2440         return retval;
2441     }
2442 #endif /* MICRO */
2443
2444     /* compound options */
2445
2446     /* This first batch can be duplicated if their values are negated */
2447
2448     /* align:string */
2449     fullname = "align";
2450     if (match_optname(opts, fullname, sizeof "align" - 1, TRUE)) {
2451         if (parse_role_opts(negated, fullname, opts, &op)) {
2452             if ((flags.initalign = str2align(op)) == ROLE_NONE) {
2453                 config_error_add("Unknown %s '%s'", fullname, op);
2454                 return FALSE;
2455             }
2456         } else
2457             return FALSE;
2458         return retval;
2459     }
2460
2461     /* role:string or character:string */
2462     fullname = "role";
2463     if (match_optname(opts, fullname, 4, TRUE)
2464         || match_optname(opts, (fullname = "character"), 4, TRUE)) {
2465         if (parse_role_opts(negated, fullname, opts, &op)) {
2466             if ((flags.initrole = str2role(op)) == ROLE_NONE) {
2467                 config_error_add("Unknown %s '%s'", fullname, op);
2468                 return FALSE;
2469             } else /* Backwards compatibility */
2470                 nmcpy(pl_character, op, PL_NSIZ);
2471         } else
2472             return FALSE;
2473         return retval;
2474     }
2475
2476     /* race:string */
2477     fullname = "race";
2478     if (match_optname(opts, fullname, 4, TRUE)) {
2479         if (parse_role_opts(negated, fullname, opts, &op)) {
2480             if ((flags.initrace = str2race(op)) == ROLE_NONE) {
2481                 config_error_add("Unknown %s '%s'", fullname, op);
2482                 return FALSE;
2483             } else /* Backwards compatibility */
2484                 pl_race = *op;
2485         } else
2486             return FALSE;
2487         return retval;
2488     }
2489
2490     /* gender:string */
2491     fullname = "gender";
2492     if (match_optname(opts, fullname, 4, TRUE)) {
2493         if (parse_role_opts(negated, fullname, opts, &op)) {
2494             if ((flags.initgend = str2gend(op)) == ROLE_NONE) {
2495                 config_error_add("Unknown %s '%s'", fullname, op);
2496                 return FALSE;
2497             } else
2498                 flags.female = flags.initgend;
2499         } else
2500             return FALSE;
2501         return retval;
2502     }
2503
2504     /* We always check for duplicates on the remaining compound options,
2505        although individual option processing can choose to complain or not */
2506
2507     duplicate = duplicate_opt_detection(opts, 1); /* 1: check compounds */
2508
2509     fullname = "pettype";
2510     if (match_optname(opts, fullname, 3, TRUE)) {
2511         if (duplicate)
2512             complain_about_duplicate(opts, 1);
2513         if ((op = string_for_env_opt(fullname, opts, negated))
2514                                      != empty_optstr) {
2515             if (negated) {
2516                 bad_negation(fullname, TRUE);
2517                 return FALSE;
2518             } else
2519                 switch (lowc(*op)) {
2520                 case 'd': /* dog */
2521                     preferred_pet = 'd';
2522                     break;
2523                 case 'c': /* cat */
2524                 case 'f': /* feline */
2525                     preferred_pet = 'c';
2526                     break;
2527                 case 'h': /* horse */
2528                 case 'q': /* quadruped */
2529                     /* avoids giving "unrecognized type of pet" but
2530                        pet_type(dog.c) won't actually honor this */
2531                     preferred_pet = 'h';
2532                     break;
2533                 case 'n': /* no pet */
2534                     preferred_pet = 'n';
2535                     break;
2536                 case '*': /* random */
2537                     preferred_pet = '\0';
2538                     break;
2539                 default:
2540 /*JP
2541                     config_error_add("Unrecognized pet type '%s'.", op);
2542 */
2543                     pline("'%s'\82Í\83y\83b\83g\82Ì\8eí\97Þ\82Æ\82µ\82Ä\8eó\82¯\95t\82¯\82ç\82ê\82Ü\82¹\82ñ\81D", op);
2544                     return FALSE;
2545                     break;
2546                 }
2547         } else if (negated)
2548             preferred_pet = 'n';
2549         return retval;
2550     }
2551
2552     fullname = "catname";
2553     if (match_optname(opts, fullname, 3, TRUE)) {
2554         if (duplicate)
2555             complain_about_duplicate(opts, 1);
2556         if (negated) {
2557             bad_negation(fullname, FALSE);
2558             return FALSE;
2559         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
2560                                             != empty_optstr) {
2561             nmcpy(catname, op, PL_PSIZ);
2562         } else
2563             return FALSE;
2564         sanitize_name(catname);
2565         return retval;
2566     }
2567
2568     fullname = "dogname";
2569     if (match_optname(opts, fullname, 3, TRUE)) {
2570         if (duplicate)
2571             complain_about_duplicate(opts, 1);
2572         if (negated) {
2573             bad_negation(fullname, FALSE);
2574             return FALSE;
2575         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
2576                                             != empty_optstr) {
2577             nmcpy(dogname, op, PL_PSIZ);
2578         } else
2579             return FALSE;
2580         sanitize_name(dogname);
2581         return retval;
2582     }
2583
2584     fullname = "horsename";
2585     if (match_optname(opts, fullname, 5, TRUE)) {
2586         if (duplicate)
2587             complain_about_duplicate(opts, 1);
2588         if (negated) {
2589             bad_negation(fullname, FALSE);
2590             return FALSE;
2591         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
2592                                             != empty_optstr) {
2593             nmcpy(horsename, op, PL_PSIZ);
2594         } else
2595             return FALSE;
2596         sanitize_name(horsename);
2597         return retval;
2598     }
2599
2600     fullname = "mouse_support";
2601     if (match_optname(opts, fullname, 13, TRUE)) {
2602         boolean compat = (strlen(opts) <= 13);
2603
2604         if (duplicate)
2605             complain_about_duplicate(opts, 1);
2606         op = string_for_opt(opts, (compat || !initial));
2607         if (op == empty_optstr) {
2608             if (compat || negated || initial) {
2609                 /* for backwards compatibility, "mouse_support" without a
2610                    value is a synonym for mouse_support:1 */
2611                 iflags.wc_mouse_support = !negated;
2612             }
2613         } else if (negated) {
2614             bad_negation(fullname, TRUE);
2615             return FALSE;
2616         } else {
2617             int mode = atoi(op);
2618
2619             if (mode < 0 || mode > 2 || (mode == 0 && *op != '0')) {
2620                 config_error_add("Illegal %s parameter '%s'", fullname, op);
2621                 return FALSE;
2622             } else { /* mode >= 0 */
2623                 iflags.wc_mouse_support = mode;
2624             }
2625         }
2626         return retval;
2627     }
2628
2629     fullname = "number_pad";
2630     if (match_optname(opts, fullname, 10, TRUE)) {
2631         boolean compat = (strlen(opts) <= 10);
2632
2633         if (duplicate)
2634             complain_about_duplicate(opts, 1);
2635         op = string_for_opt(opts, (compat || !initial));
2636         if (op == empty_optstr) {
2637             if (compat || negated || initial) {
2638                 /* for backwards compatibility, "number_pad" without a
2639                    value is a synonym for number_pad:1 */
2640                 iflags.num_pad = !negated;
2641                 iflags.num_pad_mode = 0;
2642             }
2643         } else if (negated) {
2644             bad_negation(fullname, TRUE);
2645             return FALSE;
2646         } else {
2647             int mode = atoi(op);
2648
2649             if (mode < -1 || mode > 4 || (mode == 0 && *op != '0')) {
2650                 config_error_add("Illegal %s parameter '%s'", fullname, op);
2651                 return FALSE;
2652             } else if (mode <= 0) {
2653                 iflags.num_pad = FALSE;
2654                 /* German keyboard; y and z keys swapped */
2655                 iflags.num_pad_mode = (mode < 0); /* 0 or 1 */
2656             } else {                              /* mode > 0 */
2657                 iflags.num_pad = TRUE;
2658                 iflags.num_pad_mode = 0;
2659                 /* PC Hack / MSDOS compatibility */
2660                 if (mode == 2 || mode == 4)
2661                     iflags.num_pad_mode |= 1;
2662                 /* phone keypad layout */
2663                 if (mode == 3 || mode == 4)
2664                     iflags.num_pad_mode |= 2;
2665             }
2666         }
2667         reset_commands(FALSE);
2668         number_pad(iflags.num_pad ? 1 : 0);
2669         return retval;
2670     }
2671
2672     fullname = "roguesymset";
2673     if (match_optname(opts, fullname, 7, TRUE)) {
2674         if (duplicate)
2675             complain_about_duplicate(opts, 1);
2676         if (negated) {
2677             bad_negation(fullname, FALSE);
2678             return FALSE;
2679         } else if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
2680             symset[ROGUESET].name = dupstr(op);
2681             if (!read_sym_file(ROGUESET)) {
2682                 clear_symsetentry(ROGUESET, TRUE);
2683                 config_error_add(
2684                                "Unable to load symbol set \"%s\" from \"%s\"",
2685                                  op, SYMBOLS);
2686                 return FALSE;
2687             } else {
2688                 if (!initial && Is_rogue_level(&u.uz))
2689                     assign_graphics(ROGUESET);
2690                 need_redraw = TRUE;
2691             }
2692         } else
2693             return FALSE;
2694         return retval;
2695     }
2696
2697     fullname = "symset";
2698     if (match_optname(opts, fullname, 6, TRUE)) {
2699         if (duplicate)
2700             complain_about_duplicate(opts, 1);
2701         if (negated) {
2702             bad_negation(fullname, FALSE);
2703             return FALSE;
2704         } else if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
2705             symset[PRIMARY].name = dupstr(op);
2706             if (!read_sym_file(PRIMARY)) {
2707                 clear_symsetentry(PRIMARY, TRUE);
2708                 config_error_add(
2709                                "Unable to load symbol set \"%s\" from \"%s\"",
2710                                  op, SYMBOLS);
2711                 return FALSE;
2712             } else {
2713                 switch_symbols(symset[PRIMARY].name != (char *) 0);
2714                 need_redraw = TRUE;
2715             }
2716         } else
2717             return FALSE;
2718         return retval;
2719     }
2720
2721     fullname = "runmode";
2722     if (match_optname(opts, fullname, 4, TRUE)) {
2723         if (duplicate)
2724             complain_about_duplicate(opts, 1);
2725         if (negated) {
2726             flags.runmode = RUN_TPORT;
2727         } else if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
2728             if (!strncmpi(op, "teleport", strlen(op)))
2729                 flags.runmode = RUN_TPORT;
2730             else if (!strncmpi(op, "run", strlen(op)))
2731                 flags.runmode = RUN_LEAP;
2732             else if (!strncmpi(op, "walk", strlen(op)))
2733                 flags.runmode = RUN_STEP;
2734             else if (!strncmpi(op, "crawl", strlen(op)))
2735                 flags.runmode = RUN_CRAWL;
2736             else {
2737                 config_error_add("Unknown %s parameter '%s'", fullname, op);
2738                 return FALSE;
2739             }
2740         } else
2741             return FALSE;
2742         return retval;
2743     }
2744
2745     /* menucolor:"regex_string"=color */
2746     fullname = "menucolor";
2747     if (match_optname(opts, fullname, 9, TRUE)) {
2748         if (negated) {
2749             bad_negation(fullname, FALSE);
2750             return FALSE;
2751         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
2752                                             != empty_optstr) {
2753             if (!add_menu_coloring(op))
2754                 return FALSE;
2755         } else
2756             return FALSE;
2757         return retval;
2758     }
2759
2760     fullname = "msghistory";
2761     if (match_optname(opts, fullname, 3, TRUE)) {
2762         if (duplicate)
2763             complain_about_duplicate(opts, 1);
2764         op = string_for_env_opt(fullname, opts, negated);
2765         if ((negated && op == empty_optstr)
2766             || (!negated && op != empty_optstr)) {
2767             iflags.msg_history = negated ? 0 : atoi(op);
2768         } else if (negated) {
2769             bad_negation(fullname, TRUE);
2770             return FALSE;
2771         }
2772         return retval;
2773     }
2774
2775     fullname = "msg_window";
2776     /* msg_window:single, combo, full or reversed */
2777     if (match_optname(opts, fullname, 4, TRUE)) {
2778 /* allow option to be silently ignored by non-tty ports */
2779 #ifdef TTY_GRAPHICS
2780         int tmp;
2781
2782         if (duplicate)
2783             complain_about_duplicate(opts, 1);
2784         if ((op = string_for_opt(opts, TRUE)) == empty_optstr) {
2785             tmp = negated ? 's' : 'f';
2786         } else {
2787             if (negated) {
2788                 bad_negation(fullname, TRUE);
2789                 return FALSE;
2790             }
2791             tmp = lowc(*op);
2792         }
2793         switch (tmp) {
2794         case 's': /* single message history cycle (default if negated) */
2795             iflags.prevmsg_window = 's';
2796             break;
2797         case 'c': /* combination: two singles, then full page */
2798             iflags.prevmsg_window = 'c';
2799             break;
2800         case 'f': /* full page (default if specified without argument) */
2801             iflags.prevmsg_window = 'f';
2802             break;
2803         case 'r': /* full page (reversed) */
2804             iflags.prevmsg_window = 'r';
2805             break;
2806         default:
2807             config_error_add("Unknown %s parameter '%s'", fullname, op);
2808             retval = FALSE;
2809         }
2810 #endif
2811         return retval;
2812     }
2813
2814     /* WINCAP
2815      * setting font options  */
2816     fullname = "font";
2817     if (!strncmpi(opts, fullname, 4)) {
2818         int opttype = -1;
2819         char *fontopts = opts + 4;
2820
2821         if (!strncmpi(fontopts, "map", 3) || !strncmpi(fontopts, "_map", 4))
2822             opttype = MAP_OPTION;
2823         else if (!strncmpi(fontopts, "message", 7)
2824                  || !strncmpi(fontopts, "_message", 8))
2825             opttype = MESSAGE_OPTION;
2826         else if (!strncmpi(fontopts, "text", 4)
2827                  || !strncmpi(fontopts, "_text", 5))
2828             opttype = TEXT_OPTION;
2829         else if (!strncmpi(fontopts, "menu", 4)
2830                  || !strncmpi(fontopts, "_menu", 5))
2831             opttype = MENU_OPTION;
2832         else if (!strncmpi(fontopts, "status", 6)
2833                  || !strncmpi(fontopts, "_status", 7))
2834             opttype = STATUS_OPTION;
2835         else if (!strncmpi(fontopts, "_size", 5)) {
2836             if (!strncmpi(fontopts, "_size_map", 8))
2837                 opttype = MAP_OPTION;
2838             else if (!strncmpi(fontopts, "_size_message", 12))
2839                 opttype = MESSAGE_OPTION;
2840             else if (!strncmpi(fontopts, "_size_text", 9))
2841                 opttype = TEXT_OPTION;
2842             else if (!strncmpi(fontopts, "_size_menu", 9))
2843                 opttype = MENU_OPTION;
2844             else if (!strncmpi(fontopts, "_size_status", 11))
2845                 opttype = STATUS_OPTION;
2846             else {
2847                 config_error_add("Unknown %s parameter '%s'", fullname, opts);
2848                 return FALSE;
2849             }
2850             if (duplicate)
2851                 complain_about_duplicate(opts, 1);
2852             if (opttype > 0 && !negated
2853                 && (op = string_for_opt(opts, FALSE)) != empty_optstr) {
2854                 switch (opttype) {
2855                 case MAP_OPTION:
2856                     iflags.wc_fontsiz_map = atoi(op);
2857                     break;
2858                 case MESSAGE_OPTION:
2859                     iflags.wc_fontsiz_message = atoi(op);
2860                     break;
2861                 case TEXT_OPTION:
2862                     iflags.wc_fontsiz_text = atoi(op);
2863                     break;
2864                 case MENU_OPTION:
2865                     iflags.wc_fontsiz_menu = atoi(op);
2866                     break;
2867                 case STATUS_OPTION:
2868                     iflags.wc_fontsiz_status = atoi(op);
2869                     break;
2870                 }
2871             }
2872             return retval;
2873         } else {
2874             config_error_add("Unknown %s parameter '%s'", fullname, opts);
2875             return FALSE;
2876         }
2877         if (opttype > 0
2878             && (op = string_for_opt(opts, FALSE)) != empty_optstr) {
2879             wc_set_font_name(opttype, op);
2880 #ifdef MAC
2881             set_font_name(opttype, op);
2882 #endif
2883             return retval;
2884         } else if (negated) {
2885             bad_negation(fullname, TRUE);
2886             return FALSE;
2887         }
2888         return retval;
2889     }
2890
2891 #ifdef CHANGE_COLOR
2892     if (match_optname(opts, "palette", 3, TRUE)
2893 #ifdef MAC
2894         || match_optname(opts, "hicolor", 3, TRUE)
2895 #endif
2896         ) {
2897         int color_number, color_incr;
2898
2899 #ifndef WIN32
2900         if (duplicate)
2901             complain_about_duplicate(opts, 1);
2902 #endif
2903 #ifdef MAC
2904         if (match_optname(opts, "hicolor", 3, TRUE)) {
2905             if (negated) {
2906                 bad_negation("hicolor", FALSE);
2907                 return FALSE;
2908             }
2909             color_number = CLR_MAX + 4; /* HARDCODED inverse number */
2910             color_incr = -1;
2911         } else
2912 #endif
2913         {
2914             if (negated) {
2915                 bad_negation("palette", FALSE);
2916                 return FALSE;
2917             }
2918             color_number = 0;
2919             color_incr = 1;
2920         }
2921 #ifdef WIN32
2922         op = string_for_opt(opts, TRUE);
2923         if (op == empty_optstr || !alternative_palette(op)) {
2924             config_error_add("Error in palette parameter '%s'", op);
2925             return FALSE;
2926         }
2927 #else
2928         if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
2929             char *pt = op;
2930             int cnt, tmp, reverse;
2931             long rgb;
2932
2933             while (*pt && color_number >= 0) {
2934                 cnt = 3;
2935                 rgb = 0L;
2936                 if (*pt == '-') {
2937                     reverse = 1;
2938                     pt++;
2939                 } else {
2940                     reverse = 0;
2941                 }
2942                 while (cnt-- > 0) {
2943                     if (*pt && *pt != '/') {
2944 #ifdef AMIGA
2945                         rgb <<= 4;
2946 #else
2947                         rgb <<= 8;
2948 #endif
2949                         tmp = *pt++;
2950                         if (isalpha((uchar) tmp)) {
2951                             tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */
2952                         } else {
2953                             tmp &= 0xf; /* Digits in ASCII too... */
2954                         }
2955 #ifndef AMIGA
2956                         /* Add an extra so we fill f -> ff and 0 -> 00 */
2957                         rgb += tmp << 4;
2958 #endif
2959                         rgb += tmp;
2960                     }
2961                 }
2962                 if (*pt == '/')
2963                     pt++;
2964                 change_color(color_number, rgb, reverse);
2965                 color_number += color_incr;
2966             }
2967         }
2968 #endif /* !WIN32 */
2969         if (!initial) {
2970             need_redraw = TRUE;
2971         }
2972         return retval;
2973     }
2974 #endif /* CHANGE_COLOR */
2975
2976     if (match_optname(opts, "fruit", 2, TRUE)) {
2977         struct fruit *forig = 0;
2978
2979         if (duplicate)
2980             complain_about_duplicate(opts, 1);
2981         op = string_for_opt(opts, negated || !initial);
2982         if (negated) {
2983             if (op != empty_optstr) {
2984                 bad_negation("fruit", TRUE);
2985                 return FALSE;
2986             }
2987             op = empty_optstr;
2988             goto goodfruit;
2989         }
2990         if (op == empty_optstr)
2991             return FALSE;
2992         /* strip leading/trailing spaces, condense internal ones (3.6.2) */
2993         mungspaces(op);
2994         if (!initial) {
2995             struct fruit *f;
2996             int fnum = 0;
2997
2998             /* count number of named fruits; if 'op' is found among them,
2999                then the count doesn't matter because we won't be adding it */
3000             f = fruit_from_name(op, FALSE, &fnum);
3001             if (!f) {
3002                 if (!flags.made_fruit)
3003                     forig = fruit_from_name(pl_fruit, FALSE, (int *) 0);
3004
3005                 if (!forig && fnum >= 100) {
3006 #if 0 /*JP:T*/
3007                     config_error_add(
3008                              "Doing that so many times isn't very fruitful.");
3009 #else
3010                     config_error_add(
3011                              "\82»\82ñ\82È\82É\89½\89ñ\82à\82â\82Á\82Ä\82à\82Ù\82Æ\82ñ\82Ç\88Ó\96¡\82Í\82È\82¢\81D");
3012 #endif
3013                     return retval;
3014                 }
3015             }
3016         }
3017  goodfruit:
3018         nmcpy(pl_fruit, op, PL_FSIZ);
3019         sanitize_name(pl_fruit);
3020         /* OBJ_NAME(objects[SLIME_MOLD]) won't work for this after
3021            initialization; it gets changed to generic "fruit" */
3022         if (!*pl_fruit)
3023             nmcpy(pl_fruit, "slime mold", PL_FSIZ);
3024         if (!initial) {
3025             /* if 'forig' is nonNull, we replace it rather than add
3026                a new fruit; it can only be nonNull if no fruits have
3027                been created since the previous name was put in place */
3028             (void) fruitadd(pl_fruit, forig);
3029             pline("Fruit is now \"%s\".", pl_fruit);
3030         }
3031         /* If initial, then initoptions is allowed to do it instead
3032          * of here (initoptions always has to do it even if there's
3033          * no fruit option at all.  Also, we don't want people
3034          * setting multiple fruits in their options.)
3035          */
3036         return retval;
3037     }
3038
3039     fullname = "whatis_coord";
3040     if (match_optname(opts, fullname, 8, TRUE)) {
3041         if (duplicate)
3042             complain_about_duplicate(opts, 1);
3043         if (negated) {
3044             iflags.getpos_coords = GPCOORDS_NONE;
3045             return retval;
3046         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
3047                                             != empty_optstr) {
3048             static char gpcoords[] = { GPCOORDS_NONE, GPCOORDS_COMPASS,
3049                                        GPCOORDS_COMFULL, GPCOORDS_MAP,
3050                                        GPCOORDS_SCREEN, '\0' };
3051             char c = lowc(*op);
3052
3053             if (c && index(gpcoords, c))
3054                 iflags.getpos_coords = c;
3055             else {
3056                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3057                 return FALSE;
3058             }
3059         } else
3060             return FALSE;
3061         return retval;
3062     }
3063
3064     fullname = "whatis_filter";
3065     if (match_optname(opts, fullname, 8, TRUE)) {
3066         if (duplicate)
3067             complain_about_duplicate(opts, 1);
3068         if (negated) {
3069             iflags.getloc_filter = GFILTER_NONE;
3070             return retval;
3071         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
3072                                             != empty_optstr) {
3073             char c = lowc(*op);
3074
3075             switch (c) {
3076             case 'n':
3077                 iflags.getloc_filter = GFILTER_NONE;
3078                 break;
3079             case 'v':
3080                 iflags.getloc_filter = GFILTER_VIEW;
3081                 break;
3082             case 'a':
3083                 iflags.getloc_filter = GFILTER_AREA;
3084                 break;
3085             default: {
3086                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3087                 return FALSE;
3088             }
3089             }
3090         } else
3091             return FALSE;
3092         return retval;
3093     }
3094
3095     fullname = "warnings";
3096     if (match_optname(opts, fullname, 5, TRUE)) {
3097         if (duplicate)
3098             complain_about_duplicate(opts, 1);
3099         if (negated) {
3100             bad_negation(fullname, FALSE);
3101             return FALSE;
3102         }
3103         return warning_opts(opts, fullname);
3104     }
3105
3106     /* boulder:symbol */
3107     fullname = "boulder";
3108     if (match_optname(opts, fullname, 7, TRUE)) {
3109 #ifdef BACKWARD_COMPAT
3110         int clash = 0;
3111
3112         if (duplicate)
3113             complain_about_duplicate(opts, 1);
3114         if (negated) {
3115             bad_negation(fullname, FALSE);
3116             return FALSE;
3117         }
3118         /* if ((opts = string_for_env_opt(fullname, opts, FALSE))
3119                                           == empty_optstr)
3120          */
3121         if ((opts = string_for_opt(opts, FALSE)) == empty_optstr)
3122             return FALSE;
3123         escapes(opts, opts);
3124         /* note: dummy monclass #0 has symbol value '\0'; we allow that--
3125            attempting to set bouldersym to '^@'/'\0' will reset to default */
3126         if (def_char_to_monclass(opts[0]) != MAXMCLASSES)
3127             clash = opts[0] ? 1 : 0;
3128         else if (opts[0] >= '1' && opts[0] < WARNCOUNT + '0')
3129             clash = 2;
3130         if (clash) {
3131             /* symbol chosen matches a used monster or warning
3132                symbol which is not good - reject it */
3133             config_error_add(
3134             "Badoption - boulder symbol '%s' would conflict with a %s symbol",
3135                              visctrl(opts[0]),
3136                              (clash == 1) ? "monster" : "warning");
3137         } else {
3138             /*
3139              * Override the default boulder symbol.
3140              */
3141             ov_primary_syms[SYM_BOULDER + SYM_OFF_X] = (nhsym) opts[0];
3142             ov_rogue_syms[SYM_BOULDER + SYM_OFF_X] = (nhsym) opts[0];
3143             /* for 'initial', update of BOULDER symbol is done in
3144                initoptions_finish(), after all symset options
3145                have been processed */
3146             if (!initial) {
3147                 nhsym sym = get_othersym(SYM_BOULDER,
3148                                 Is_rogue_level(&u.uz) ? ROGUESET : PRIMARY);
3149                 if (sym)
3150                     showsyms[SYM_BOULDER + SYM_OFF_X] = sym;
3151                 need_redraw = TRUE;
3152             }
3153         }
3154         return retval;
3155 #else
3156         config_error_add("'%s' no longer supported; use S_boulder:c instead",
3157                          fullname);
3158         return FALSE;
3159 #endif
3160     }
3161
3162     /* name:string */
3163     fullname = "name";
3164     if (match_optname(opts, fullname, 4, TRUE)) {
3165         if (duplicate)
3166             complain_about_duplicate(opts, 1);
3167         if (negated) {
3168             bad_negation(fullname, FALSE);
3169             return FALSE;
3170         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
3171                                             != empty_optstr) {
3172             nmcpy(plname, op, PL_NSIZ);
3173         } else
3174             return FALSE;
3175         return retval;
3176     }
3177
3178     /* altkeyhandler:string */
3179     fullname = "altkeyhandler";
3180     if (match_optname(opts, fullname, 4, TRUE)) {
3181         if (duplicate)
3182             complain_about_duplicate(opts, 1);
3183         if (negated) {
3184             bad_negation(fullname, FALSE);
3185             return FALSE;
3186         } else if ((op = string_for_opt(opts, negated)) != empty_optstr) {
3187 #if defined(WIN32) && defined(TTY_GRAPHICS)
3188             set_altkeyhandler(op);
3189 #endif
3190         } else
3191             return FALSE;
3192         return retval;
3193     }
3194
3195     /* WINCAP
3196      * align_status:[left|top|right|bottom] */
3197     fullname = "align_status";
3198     if (match_optname(opts, fullname, sizeof "align_status" - 1, TRUE)) {
3199         op = string_for_opt(opts, negated);
3200         if ((op != empty_optstr) && !negated) {
3201             if (!strncmpi(op, "left", sizeof "left" - 1))
3202                 iflags.wc_align_status = ALIGN_LEFT;
3203             else if (!strncmpi(op, "top", sizeof "top" - 1))
3204                 iflags.wc_align_status = ALIGN_TOP;
3205             else if (!strncmpi(op, "right", sizeof "right" - 1))
3206                 iflags.wc_align_status = ALIGN_RIGHT;
3207             else if (!strncmpi(op, "bottom", sizeof "bottom" - 1))
3208                 iflags.wc_align_status = ALIGN_BOTTOM;
3209             else {
3210                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3211                 return FALSE;
3212             }
3213         } else if (negated) {
3214             bad_negation(fullname, TRUE);
3215             return FALSE;
3216         }
3217         return retval;
3218     }
3219
3220     /* WINCAP
3221      * align_message:[left|top|right|bottom] */
3222     fullname = "align_message";
3223     if (match_optname(opts, fullname, sizeof "align_message" - 1, TRUE)) {
3224         if (duplicate)
3225             complain_about_duplicate(opts, 1);
3226         op = string_for_opt(opts, negated);
3227         if ((op != empty_optstr) && !negated) {
3228             if (!strncmpi(op, "left", sizeof "left" - 1))
3229                 iflags.wc_align_message = ALIGN_LEFT;
3230             else if (!strncmpi(op, "top", sizeof "top" - 1))
3231                 iflags.wc_align_message = ALIGN_TOP;
3232             else if (!strncmpi(op, "right", sizeof "right" - 1))
3233                 iflags.wc_align_message = ALIGN_RIGHT;
3234             else if (!strncmpi(op, "bottom", sizeof "bottom" - 1))
3235                 iflags.wc_align_message = ALIGN_BOTTOM;
3236             else {
3237                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3238                 return FALSE;
3239             }
3240         } else if (negated) {
3241             bad_negation(fullname, TRUE);
3242             return FALSE;
3243         }
3244         return retval;
3245     }
3246
3247     /* the order to list inventory */
3248     fullname = "packorder";
3249     if (match_optname(opts, fullname, 4, TRUE)) {
3250         if (duplicate)
3251             complain_about_duplicate(opts, 1);
3252         if (negated) {
3253             bad_negation(fullname, FALSE);
3254             return FALSE;
3255         } else if ((op = string_for_opt(opts, FALSE)) == empty_optstr)
3256             return FALSE;
3257
3258         if (!change_inv_order(op))
3259             return FALSE;
3260         return retval;
3261     }
3262
3263     /* user can change required response for some prompts (quit, die, hit),
3264        or add an extra prompt (pray, Remove) that isn't ordinarily there */
3265     fullname = "paranoid_confirmation";
3266     if (match_optname(opts, fullname, 8, TRUE)) {
3267         /* at present we don't complain about duplicates for this
3268            option, but we do throw away the old settings whenever
3269            we process a new one [clearing old flags is essential
3270            for handling default paranoid_confirm:pray sanely] */
3271         flags.paranoia_bits = 0; /* clear all */
3272         if (negated) {
3273             flags.paranoia_bits = 0; /* [now redundant...] */
3274         } else if ((op = string_for_opt(opts, TRUE)) != empty_optstr) {
3275             char *pp, buf[BUFSZ];
3276
3277             strncpy(buf, op, sizeof buf - 1);
3278             buf[sizeof buf - 1] = '\0';
3279             op = mungspaces(buf);
3280             for (;;) {
3281                 /* We're looking to parse
3282                    "paranoid_confirm:whichone wheretwo whothree"
3283                    and "paranoid_confirm:" prefix has already
3284                    been stripped off by the time we get here */
3285                 pp = index(op, ' ');
3286                 if (pp)
3287                     *pp = '\0';
3288                 /* we aren't matching option names but match_optname()
3289                    does what we want once we've broken the space
3290                    delimited aggregate into separate tokens */
3291                 for (i = 0; i < SIZE(paranoia); ++i) {
3292                     if (match_optname(op, paranoia[i].argname,
3293                                       paranoia[i].argMinLen, FALSE)
3294                         || (paranoia[i].synonym
3295                             && match_optname(op, paranoia[i].synonym,
3296                                              paranoia[i].synMinLen, FALSE))) {
3297                         if (paranoia[i].flagmask)
3298                             flags.paranoia_bits |= paranoia[i].flagmask;
3299                         else /* 0 == "none", so clear all */
3300                             flags.paranoia_bits = 0;
3301                         break;
3302                     }
3303                 }
3304                 if (i == SIZE(paranoia)) {
3305                     /* didn't match anything, so arg is bad;
3306                        any flags already set will stay set */
3307                     config_error_add("Unknown %s parameter '%s'",
3308                                      fullname, op);
3309                     return FALSE;
3310                 }
3311                 /* move on to next token */
3312                 if (pp)
3313                     op = pp + 1;
3314                 else
3315                     break; /* no next token */
3316             } /* for(;;) */
3317         } else
3318             return FALSE;
3319         return retval;
3320     }
3321
3322     /* accept deprecated boolean; superseded by paranoid_confirm:pray */
3323     fullname = "prayconfirm";
3324     if (match_optname(opts, fullname, 4, FALSE)) {
3325         if (negated)
3326             flags.paranoia_bits &= ~PARANOID_PRAY;
3327         else
3328             flags.paranoia_bits |= PARANOID_PRAY;
3329         return retval;
3330     }
3331
3332     /* maximum burden picked up before prompt (Warren Cheung) */
3333     fullname = "pickup_burden";
3334     if (match_optname(opts, fullname, 8, TRUE)) {
3335         if (duplicate)
3336             complain_about_duplicate(opts, 1);
3337         if (negated) {
3338             bad_negation(fullname, FALSE);
3339             return FALSE;
3340         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
3341                                             != empty_optstr) {
3342             switch (lowc(*op)) {
3343             case 'u': /* Unencumbered */
3344                 flags.pickup_burden = UNENCUMBERED;
3345                 break;
3346             case 'b': /* Burdened (slight encumbrance) */
3347                 flags.pickup_burden = SLT_ENCUMBER;
3348                 break;
3349             case 's': /* streSsed (moderate encumbrance) */
3350                 flags.pickup_burden = MOD_ENCUMBER;
3351                 break;
3352             case 'n': /* straiNed (heavy encumbrance) */
3353                 flags.pickup_burden = HVY_ENCUMBER;
3354                 break;
3355             case 'o': /* OverTaxed (extreme encumbrance) */
3356             case 't':
3357                 flags.pickup_burden = EXT_ENCUMBER;
3358                 break;
3359             case 'l': /* overLoaded */
3360                 flags.pickup_burden = OVERLOADED;
3361                 break;
3362             default:
3363                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3364                 return FALSE;
3365             }
3366         } else
3367             return FALSE;
3368         return retval;
3369     }
3370
3371     /* types of objects to pick up automatically */
3372     fullname = "pickup_types";
3373     if (match_optname(opts, fullname, 8, TRUE)) {
3374         char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1],
3375              qbuf[QBUFSZ], abuf[BUFSZ];
3376         int oc_sym;
3377         boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu;
3378
3379         if (duplicate)
3380             complain_about_duplicate(opts, 1);
3381         oc_to_str(flags.pickup_types, tbuf);
3382         flags.pickup_types[0] = '\0'; /* all */
3383         op = string_for_opt(opts, (compat || !initial));
3384         if (op == empty_optstr) {
3385             if (compat || negated || initial) {
3386                 /* for backwards compatibility, "pickup" without a
3387                    value is a synonym for autopickup of all types
3388                    (and during initialization, we can't prompt yet) */
3389                 flags.pickup = !negated;
3390                 return retval;
3391             }
3392             oc_to_str(flags.inv_order, ocl);
3393             use_menu = TRUE;
3394             if (flags.menu_style == MENU_TRADITIONAL
3395                 || flags.menu_style == MENU_COMBINATION) {
3396                 boolean wasspace;
3397
3398                 use_menu = FALSE;
3399 #if 0 /*JP:T*/
3400                 Sprintf(qbuf, "New %s: [%s am] (%s)", fullname, ocl,
3401                         *tbuf ? tbuf : "all");
3402 #else
3403                 Sprintf(qbuf, "\90V\82µ\82¢%s: [%s am] (%s)", fullname, ocl,
3404                         *tbuf ? tbuf : "all");
3405 #endif
3406                 abuf[0] = '\0';
3407                 getlin(qbuf, abuf);
3408                 wasspace = (abuf[0] == ' '); /* before mungspaces */
3409                 op = mungspaces(abuf);
3410                 if (wasspace && !abuf[0])
3411                     ; /* one or more spaces will remove old value */
3412                 else if (!abuf[0] || abuf[0] == '\033')
3413                     op = tbuf; /* restore */
3414                 else if (abuf[0] == 'm')
3415                     use_menu = TRUE;
3416                 /* note: abuf[0]=='a' is already handled via clearing the
3417                    the old value (above) as a default action */
3418             }
3419             if (use_menu) {
3420                 if (wizard && !index(ocl, VENOM_SYM))
3421                     strkitten(ocl, VENOM_SYM);
3422 #if 0 /*JP:T*/
3423                 (void) choose_classes_menu("Autopickup what?", 1, TRUE, ocl,
3424                                            tbuf);
3425 #else
3426                 (void) choose_classes_menu("\82Ç\82ê\82ð\8e©\93®\8fE\82¢\82É\90Ý\92è\82·\82é\81H", 1, TRUE, ocl,
3427                                            tbuf);
3428 #endif
3429                 op = tbuf;
3430             }
3431         }
3432         if (negated) {
3433             bad_negation(fullname, TRUE);
3434             return FALSE;
3435         }
3436         while (*op == ' ')
3437             op++;
3438         if (*op != 'a' && *op != 'A') {
3439             num = 0;
3440             while (*op) {
3441                 oc_sym = def_char_to_objclass(*op);
3442                 /* make sure all are valid obj symbols occurring once */
3443                 if (oc_sym != MAXOCLASSES
3444                     && !index(flags.pickup_types, oc_sym)) {
3445                     flags.pickup_types[num] = (char) oc_sym;
3446                     flags.pickup_types[++num] = '\0';
3447                 } else
3448                     badopt = TRUE;
3449                 op++;
3450             }
3451             if (badopt) {
3452                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3453                 return FALSE;
3454             }
3455         }
3456         return retval;
3457     }
3458
3459     /* pile limit: when walking over objects, number which triggers
3460        "there are several/many objects here" instead of listing them */
3461     fullname = "pile_limit";
3462     if (match_optname(opts, fullname, 4, TRUE)) {
3463         if (duplicate)
3464             complain_about_duplicate(opts, 1);
3465         op = string_for_opt(opts, negated);
3466         if ((negated && op == empty_optstr)
3467             || (!negated && op != empty_optstr))
3468             flags.pile_limit = negated ? 0 : atoi(op);
3469         else if (negated) {
3470             bad_negation(fullname, TRUE);
3471             return FALSE;
3472         } else /* op == empty_optstr */
3473             flags.pile_limit = PILE_LIMIT_DFLT;
3474         /* sanity check */
3475         if (flags.pile_limit < 0)
3476             flags.pile_limit = PILE_LIMIT_DFLT;
3477         return retval;
3478     }
3479
3480     /* play mode: normal, explore/discovery, or debug/wizard */
3481     fullname = "playmode";
3482     if (match_optname(opts, fullname, 4, TRUE)) {
3483         if (duplicate)
3484             complain_about_duplicate(opts, 1);
3485         if (negated)
3486             bad_negation(fullname, FALSE);
3487         if (duplicate || negated)
3488             return FALSE;
3489         op = string_for_opt(opts, FALSE);
3490         if (op == empty_optstr)
3491             return FALSE;
3492         if (!strncmpi(op, "normal", 6) || !strcmpi(op, "play")) {
3493             wizard = discover = FALSE;
3494         } else if (!strncmpi(op, "explore", 6)
3495                    || !strncmpi(op, "discovery", 6)) {
3496             wizard = FALSE, discover = TRUE;
3497         } else if (!strncmpi(op, "debug", 5) || !strncmpi(op, "wizard", 6)) {
3498             wizard = TRUE, discover = FALSE;
3499         } else {
3500             config_error_add("Invalid value for \"%s\":%s", fullname, op);
3501             return FALSE;
3502         }
3503         return retval;
3504     }
3505
3506     /* WINCAP
3507      * player_selection: dialog | prompt/prompts/prompting */
3508     fullname = "player_selection";
3509     if (match_optname(opts, fullname, sizeof "player_selection" - 1, TRUE)) {
3510         if (duplicate)
3511             complain_about_duplicate(opts, 1);
3512         op = string_for_opt(opts, negated);
3513         if (op != empty_optstr && !negated) {
3514             if (!strncmpi(op, "dialog", sizeof "dialog" - 1)) {
3515                 iflags.wc_player_selection = VIA_DIALOG;
3516             } else if (!strncmpi(op, "prompt", sizeof "prompt" - 1)) {
3517                 iflags.wc_player_selection = VIA_PROMPTS;
3518             } else {
3519                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3520                 return FALSE;
3521             }
3522         } else if (negated) {
3523             bad_negation(fullname, TRUE);
3524             return FALSE;
3525         }
3526         return retval;
3527     }
3528
3529     /* things to disclose at end of game */
3530     fullname = "disclose";
3531     if (match_optname(opts, fullname, 7, TRUE)) {
3532         /*
3533          * The order that the end_disclose options are stored:
3534          *      inventory, attribs, vanquished, genocided,
3535          *      conduct, overview.
3536          * There is an array in flags:
3537          *      end_disclose[NUM_DISCLOSURE_OPT];
3538          * with option settings for the each of the following:
3539          * iagvc [see disclosure_options in decl.c]:
3540          * Allowed setting values in that array are:
3541          *      DISCLOSE_PROMPT_DEFAULT_YES  ask with default answer yes
3542          *      DISCLOSE_PROMPT_DEFAULT_NO   ask with default answer no
3543          *      DISCLOSE_YES_WITHOUT_PROMPT  always disclose and don't ask
3544          *      DISCLOSE_NO_WITHOUT_PROMPT   never disclose and don't ask
3545          *      DISCLOSE_PROMPT_DEFAULT_SPECIAL  for 'vanquished' only...
3546          *      DISCLOSE_SPECIAL_WITHOUT_PROMPT  ...to set up sort order.
3547          *
3548          * Those setting values can be used in the option
3549          * string as a prefix to get the desired behaviour.
3550          *
3551          * For backward compatibility, no prefix is required,
3552          * and the presence of a i,a,g,v, or c without a prefix
3553          * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
3554          */
3555         int idx, prefix_val;
3556
3557         if (duplicate)
3558             complain_about_duplicate(opts, 1);
3559         op = string_for_opt(opts, TRUE);
3560         if (op != empty_optstr && negated) {
3561             bad_negation(fullname, TRUE);
3562             return FALSE;
3563         }
3564         /* "disclose" without a value means "all with prompting"
3565            and negated means "none without prompting" */
3566         if (op == empty_optstr
3567             || !strcmpi(op, "all") || !strcmpi(op, "none")) {
3568             if (op != empty_optstr && !strcmpi(op, "none"))
3569                 negated = TRUE;
3570             for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++)
3571                 flags.end_disclose[num] = negated
3572                                               ? DISCLOSE_NO_WITHOUT_PROMPT
3573                                               : DISCLOSE_PROMPT_DEFAULT_YES;
3574             return retval;
3575         }
3576
3577         num = 0;
3578         prefix_val = -1;
3579         while (*op && num < sizeof flags.end_disclose - 1) {
3580             static char valid_settings[] = {
3581                 DISCLOSE_PROMPT_DEFAULT_YES, DISCLOSE_PROMPT_DEFAULT_NO,
3582                 DISCLOSE_PROMPT_DEFAULT_SPECIAL,
3583                 DISCLOSE_YES_WITHOUT_PROMPT, DISCLOSE_NO_WITHOUT_PROMPT,
3584                 DISCLOSE_SPECIAL_WITHOUT_PROMPT, '\0'
3585             };
3586             register char c, *dop;
3587
3588             c = lowc(*op);
3589             if (c == 'k')
3590                 c = 'v'; /* killed -> vanquished */
3591             if (c == 'd')
3592                 c = 'o'; /* dungeon -> overview */
3593             dop = index(disclosure_options, c);
3594             if (dop) {
3595                 idx = (int) (dop - disclosure_options);
3596                 if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) {
3597                     impossible("bad disclosure index %d %c", idx, c);
3598                     continue;
3599                 }
3600                 if (prefix_val != -1) {
3601                     if (*dop != 'v') {
3602                         if (prefix_val == DISCLOSE_PROMPT_DEFAULT_SPECIAL)
3603                             prefix_val = DISCLOSE_PROMPT_DEFAULT_YES;
3604                         if (prefix_val == DISCLOSE_SPECIAL_WITHOUT_PROMPT)
3605                             prefix_val = DISCLOSE_YES_WITHOUT_PROMPT;
3606                     }
3607                     flags.end_disclose[idx] = prefix_val;
3608                     prefix_val = -1;
3609                 } else
3610                     flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT;
3611             } else if (index(valid_settings, c)) {
3612                 prefix_val = c;
3613             } else if (c == ' ') {
3614                 ; /* do nothing */
3615             } else {
3616                 config_error_add("Unknown %s parameter '%c'", fullname, *op);
3617                 return FALSE;
3618             }
3619             op++;
3620         }
3621         return retval;
3622     }
3623 #if 1 /*JP*/
3624     if (!strncmpi(opts, "kcode", 3)){
3625         if ((op = string_for_env_opt("kcode", opts, FALSE)) != 0){
3626             setkcode(*op);
3627         }
3628         return retval;
3629     }
3630 #endif
3631
3632     /* scores:5t[op] 5a[round] o[wn] */
3633     fullname = "scores";
3634     if (match_optname(opts, fullname, 4, TRUE)) {
3635         if (duplicate)
3636             complain_about_duplicate(opts, 1);
3637         if (negated) {
3638             bad_negation(fullname, FALSE);
3639             return FALSE;
3640         }
3641         if ((op = string_for_opt(opts, FALSE)) == empty_optstr)
3642             return FALSE;
3643
3644         while (*op) {
3645             int inum = 1;
3646
3647             if (digit(*op)) {
3648                 inum = atoi(op);
3649                 while (digit(*op))
3650                     op++;
3651             } else if (*op == '!') {
3652                 negated = !negated;
3653                 op++;
3654             }
3655             while (*op == ' ')
3656                 op++;
3657
3658             switch (*op) {
3659             case 't':
3660             case 'T':
3661                 flags.end_top = inum;
3662                 break;
3663             case 'a':
3664             case 'A':
3665                 flags.end_around = inum;
3666                 break;
3667             case 'o':
3668             case 'O':
3669                 flags.end_own = !negated;
3670                 break;
3671             default:
3672                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3673                 return FALSE;
3674             }
3675             /* "3a" is sufficient but accept "3around" (or "3abracadabra") */
3676             while (letter(*op))
3677                 op++;
3678             /* t, a, and o can be separated by space(s) or slash or both */
3679             while (*op == ' ')
3680                 op++;
3681             if (*op == '/')
3682                 op++;
3683         }
3684         return retval;
3685     }
3686
3687     fullname = "sortloot";
3688     if (match_optname(opts, fullname, 4, TRUE)) {
3689         op = string_for_env_opt(fullname, opts, FALSE);
3690         if (op != empty_optstr) {
3691             char c = lowc(*op);
3692
3693             switch (c) {
3694             case 'n': /* none */
3695             case 'l': /* loot (pickup) */
3696             case 'f': /* full (pickup + invent) */
3697                 flags.sortloot = c;
3698                 break;
3699             default:
3700                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3701                 return FALSE;
3702             }
3703         } else
3704             return FALSE;
3705         return retval;
3706     }
3707
3708     fullname = "suppress_alert";
3709     if (match_optname(opts, fullname, 4, TRUE)) {
3710         if (duplicate)
3711             complain_about_duplicate(opts, 1);
3712         op = string_for_opt(opts, negated);
3713         if (negated) {
3714             bad_negation(fullname, FALSE);
3715             return FALSE;
3716         } else if (op != empty_optstr)
3717             (void) feature_alert_opts(op, fullname);
3718         return retval;
3719     }
3720
3721 #ifdef VIDEOSHADES
3722     /* videocolors:string */
3723     fullname = "videocolors";
3724     if (match_optname(opts, fullname, 6, TRUE)
3725         || match_optname(opts, "videocolours", 10, TRUE)) {
3726         if (duplicate)
3727             complain_about_duplicate(opts, 1);
3728         if (negated) {
3729             bad_negation(fullname, FALSE);
3730             return FALSE;
3731         } else if ((opts = string_for_env_opt(fullname, opts, FALSE))
3732                                               == empty_optstr) {
3733             return FALSE;
3734         }
3735         if (!assign_videocolors(opts)) {
3736             config_error_add("Unknown error handling '%s'", fullname);
3737             return FALSE;
3738         }
3739         return retval;
3740     }
3741     /* videoshades:string */
3742     fullname = "videoshades";
3743     if (match_optname(opts, fullname, 6, TRUE)) {
3744         if (duplicate)
3745             complain_about_duplicate(opts, 1);
3746         if (negated) {
3747             bad_negation(fullname, FALSE);
3748             return FALSE;
3749         } else if ((opts = string_for_env_opt(fullname, opts, FALSE))
3750                                               == empty_optstr) {
3751             return FALSE;
3752         }
3753         if (!assign_videoshades(opts)) {
3754             config_error_add("Unknown error handling '%s'", fullname);
3755             return FALSE;
3756         }
3757         return retval;
3758     }
3759 #endif /* VIDEOSHADES */
3760
3761 #ifdef MSDOS
3762 #ifdef NO_TERMS
3763     /* video:string -- must be after longer tests */
3764     fullname = "video";
3765     if (match_optname(opts, fullname, 5, TRUE)) {
3766         if (duplicate)
3767             complain_about_duplicate(opts, 1);
3768         if (negated) {
3769             bad_negation(fullname, FALSE);
3770             return FALSE;
3771         } else if ((opts = string_for_env_opt(fullname, opts, FALSE))
3772                                               == empty_optstr) {
3773             return FALSE;
3774         }
3775         if (!assign_video(opts)) {
3776             config_error_add("Unknown error handling '%s'", fullname);
3777             return FALSE;
3778         }
3779         return retval;
3780     }
3781 #endif /* NO_TERMS */
3782     /* soundcard:string -- careful not to match boolean 'sound' */
3783     fullname = "soundcard";
3784     if (match_optname(opts, fullname, 6, TRUE)) {
3785         if (duplicate)
3786             complain_about_duplicate(opts, 1);
3787         if (negated) {
3788             bad_negation(fullname, FALSE);
3789             return FALSE;
3790         } else if ((opts = string_for_env_opt(fullname, opts, FALSE))
3791                                               == empty_optstr) {
3792             return FALSE;
3793         }
3794         if (!assign_soundcard(opts)) {
3795             config_error_add("Unknown error handling '%s'", fullname);
3796             return FALSE;
3797         }
3798         return retval;
3799     }
3800 #endif /* MSDOS */
3801
3802     /* WINCAP
3803      *
3804      *  map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12
3805      *            |ascii8x12|ascii16x12|ascii12x16|ascii10x18|fit_to_screen
3806      *            |ascii_fit_to_screen|tiles_fit_to_screen]
3807      */
3808     fullname = "map_mode";
3809     if (match_optname(opts, fullname, sizeof "map_mode" - 1, TRUE)) {
3810         if (duplicate)
3811             complain_about_duplicate(opts, 1);
3812         op = string_for_opt(opts, negated);
3813         if (op != empty_optstr && !negated) {
3814             if (!strcmpi(op, "tiles"))
3815                 iflags.wc_map_mode = MAP_MODE_TILES;
3816             else if (!strncmpi(op, "ascii4x6", sizeof "ascii4x6" - 1))
3817                 iflags.wc_map_mode = MAP_MODE_ASCII4x6;
3818             else if (!strncmpi(op, "ascii6x8", sizeof "ascii6x8" - 1))
3819                 iflags.wc_map_mode = MAP_MODE_ASCII6x8;
3820             else if (!strncmpi(op, "ascii8x8", sizeof "ascii8x8" - 1))
3821                 iflags.wc_map_mode = MAP_MODE_ASCII8x8;
3822             else if (!strncmpi(op, "ascii16x8", sizeof "ascii16x8" - 1))
3823                 iflags.wc_map_mode = MAP_MODE_ASCII16x8;
3824             else if (!strncmpi(op, "ascii7x12", sizeof "ascii7x12" - 1))
3825                 iflags.wc_map_mode = MAP_MODE_ASCII7x12;
3826             else if (!strncmpi(op, "ascii8x12", sizeof "ascii8x12" - 1))
3827                 iflags.wc_map_mode = MAP_MODE_ASCII8x12;
3828             else if (!strncmpi(op, "ascii16x12", sizeof "ascii16x12" - 1))
3829                 iflags.wc_map_mode = MAP_MODE_ASCII16x12;
3830             else if (!strncmpi(op, "ascii12x16", sizeof "ascii12x16" - 1))
3831                 iflags.wc_map_mode = MAP_MODE_ASCII12x16;
3832             else if (!strncmpi(op, "ascii10x18", sizeof "ascii10x18" - 1))
3833                 iflags.wc_map_mode = MAP_MODE_ASCII10x18;
3834             else if (!strncmpi(op, "fit_to_screen",
3835                                sizeof "fit_to_screen" - 1))
3836                 iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
3837             else if (!strncmpi(op, "ascii_fit_to_screen",
3838                                sizeof "ascii_fit_to_screen" - 1))
3839                 iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
3840             else if (!strncmpi(op, "tiles_fit_to_screen",
3841                                sizeof "tiles_fit_to_screen" - 1))
3842                 iflags.wc_map_mode = MAP_MODE_TILES_FIT_TO_SCREEN;
3843             else {
3844                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3845                 return FALSE;
3846             }
3847         } else if (negated) {
3848             bad_negation(fullname, TRUE);
3849             return FALSE;
3850         }
3851         return retval;
3852     }
3853
3854     /* WINCAP
3855      * scroll_amount:nn */
3856     fullname = "scroll_amount";
3857     if (match_optname(opts, fullname, sizeof "scroll_amount" - 1, TRUE)) {
3858         if (duplicate)
3859             complain_about_duplicate(opts, 1);
3860         op = string_for_opt(opts, negated);
3861         if ((negated && op == empty_optstr)
3862             || (!negated && op != empty_optstr)) {
3863             iflags.wc_scroll_amount = negated ? 1 : atoi(op);
3864         } else if (negated) {
3865             bad_negation(fullname, TRUE);
3866             return FALSE;
3867         }
3868         return retval;
3869     }
3870
3871     /* WINCAP
3872      * scroll_margin:nn */
3873     fullname = "scroll_margin";
3874     if (match_optname(opts, fullname, sizeof "scroll_margin" - 1, TRUE)) {
3875         if (duplicate)
3876             complain_about_duplicate(opts, 1);
3877         op = string_for_opt(opts, negated);
3878         if ((negated && op == empty_optstr)
3879             || (!negated && op != empty_optstr)) {
3880             iflags.wc_scroll_margin = negated ? 5 : atoi(op);
3881         } else if (negated) {
3882             bad_negation(fullname, TRUE);
3883             return FALSE;
3884         }
3885         return retval;
3886     }
3887
3888     fullname = "subkeyvalue";
3889     if (match_optname(opts, fullname, 5, TRUE)) {
3890         /* no duplicate complaint here */
3891         if (negated) {
3892             bad_negation(fullname, FALSE);
3893             return FALSE;
3894 #if defined(WIN32)
3895         } else {
3896             op = string_for_opt(opts, 0);
3897             if (op == empty_optstr)
3898                 return FALSE;
3899 #ifdef TTY_GRAPHICS
3900             map_subkeyvalue(op);
3901 #endif
3902 #endif
3903         }
3904         return retval;
3905     }
3906
3907     /* WINCAP
3908      * tile_width:nn */
3909     fullname = "tile_width";
3910     if (match_optname(opts, fullname, sizeof "tile_width" - 1, TRUE)) {
3911         if (duplicate)
3912             complain_about_duplicate(opts, 1);
3913         op = string_for_opt(opts, negated);
3914         if ((negated && op == empty_optstr)
3915             || (!negated && op != empty_optstr)) {
3916             iflags.wc_tile_width = negated ? 0 : atoi(op);
3917         } else if (negated) {
3918             bad_negation(fullname, TRUE);
3919             return FALSE;
3920         }
3921         return retval;
3922     }
3923     /* WINCAP
3924      * tile_file:name */
3925     fullname = "tile_file";
3926     if (match_optname(opts, fullname, sizeof "tile_file" - 1, TRUE)) {
3927         if (duplicate)
3928             complain_about_duplicate(opts, 1);
3929         if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
3930             if (iflags.wc_tile_file)
3931                 free(iflags.wc_tile_file);
3932             iflags.wc_tile_file = dupstr(op);
3933         } else
3934             return FALSE;
3935         return retval;
3936     }
3937     /* WINCAP
3938      * tile_height:nn */
3939     fullname = "tile_height";
3940     if (match_optname(opts, fullname, sizeof "tile_height" - 1, TRUE)) {
3941         if (duplicate)
3942             complain_about_duplicate(opts, 1);
3943         op = string_for_opt(opts, negated);
3944         if ((negated && op == empty_optstr)
3945             || (!negated && op != empty_optstr)) {
3946             iflags.wc_tile_height = negated ? 0 : atoi(op);
3947         } else if (negated) {
3948             bad_negation(fullname, TRUE);
3949             return FALSE;
3950         }
3951         return retval;
3952     }
3953
3954     /* WINCAP
3955      * vary_msgcount:nn */
3956     fullname = "vary_msgcount";
3957     if (match_optname(opts, fullname, sizeof "vary_msgcount" - 1, TRUE)) {
3958         if (duplicate)
3959             complain_about_duplicate(opts, 1);
3960         op = string_for_opt(opts, negated);
3961         if ((negated && op == empty_optstr)
3962             || (!negated && op != empty_optstr)) {
3963             iflags.wc_vary_msgcount = negated ? 0 : atoi(op);
3964         } else if (negated) {
3965             bad_negation(fullname, TRUE);
3966             return FALSE;
3967         }
3968         return retval;
3969     }
3970
3971     /*
3972      * windowtype:  option to choose the interface for binaries built
3973      * with support for more than one interface (tty + X11, for instance).
3974      *
3975      * Ideally, 'windowtype' should be processed first, because it
3976      * causes the wc_ and wc2_ flags to be set up.
3977      * For user, making it be first in a config file is trivial, use
3978      * OPTIONS=windowtype:Foo
3979      * as the first non-comment line of the file.
3980      * Making it first in NETHACKOPTIONS requires it to be at the _end_
3981      * because comma-separated option strings are processed from right
3982      * to left.
3983      */
3984     fullname = "windowtype";
3985     if (match_optname(opts, fullname, 3, TRUE)) {
3986         if (iflags.windowtype_locked)
3987             return retval;
3988         if (duplicate)
3989             complain_about_duplicate(opts, 1);
3990         if (negated) {
3991             bad_negation(fullname, FALSE);
3992             return FALSE;
3993         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
3994                                             != empty_optstr) {
3995             if (!iflags.windowtype_deferred) {
3996                 char buf[WINTYPELEN];
3997
3998                 nmcpy(buf, op, WINTYPELEN);
3999                 choose_windows(buf);
4000             } else {
4001                 nmcpy(chosen_windowtype, op, WINTYPELEN);
4002             }
4003         } else
4004             return FALSE;
4005         return retval;
4006     }
4007
4008 #ifdef WINCHAIN
4009     fullname = "windowchain";
4010     if (match_optname(opts, fullname, 3, TRUE)) {
4011         if (negated) {
4012             bad_negation(fullname, FALSE);
4013             return FALSE;
4014         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
4015                                             != empty_optstr) {
4016             char buf[WINTYPELEN];
4017
4018             nmcpy(buf, op, WINTYPELEN);
4019             addto_windowchain(buf);
4020         } else
4021             return FALSE;
4022         return retval;
4023     }
4024 #endif
4025
4026     /* WINCAP
4027      * setting window colors
4028      * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
4029      */
4030     fullname = "windowcolors";
4031     if (match_optname(opts, fullname, 7, TRUE)) {
4032         if (duplicate)
4033             complain_about_duplicate(opts, 1);
4034         if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
4035             if (!wc_set_window_colors(op)) {
4036                 config_error_add("Could not set %s '%s'", fullname, op);
4037                 return FALSE;
4038             }
4039         } else if (negated) {
4040             bad_negation(fullname, TRUE);
4041             return FALSE;
4042         }
4043         return retval;
4044     }
4045
4046 #ifdef CURSES_GRAPHICS
4047     /* WINCAP2
4048      * term_cols:amount or term_rows:amount */
4049     fullname = "term_cols";
4050     if (match_optname(opts, fullname, 8, TRUE)
4051         /* alternate spelling */
4052         || match_optname(opts, "term_columns", 9, TRUE)
4053         /* different option but identical handlng */
4054         || (fullname = "term_rows", match_optname(opts, fullname, 8, TRUE))) {
4055         long ltmp;
4056
4057         if ((op = string_for_opt(opts, negated)) != empty_optstr) {
4058             ltmp = atol(op);
4059             if (negated) {
4060                 bad_negation(fullname, FALSE);
4061                 retval = FALSE;
4062
4063             /* just checks atol() sanity, not logical window size sanity */
4064             } else if (ltmp <= 0L || ltmp >= (long) LARGEST_INT) {
4065                 config_error_add("Invalid %s: %ld", fullname, ltmp);
4066                 retval = FALSE;
4067
4068             } else {
4069                 if (!strcmp(fullname, "term_rows"))
4070                     iflags.wc2_term_rows = (int) ltmp;
4071                 else /* !strcmp(fullname, "term_cols") */
4072                     iflags.wc2_term_cols = (int) ltmp;
4073             }
4074         }
4075         return retval;
4076     }
4077
4078     /* WINCAP2
4079      * petattr:string */
4080     fullname = "petattr";
4081     if (match_optname(opts, fullname, sizeof "petattr" - 1, TRUE)) {
4082         op = string_for_opt(opts, negated);
4083         if (op != empty_optstr && negated) {
4084             bad_negation(fullname, TRUE);
4085             retval = FALSE;
4086         } else if (op != empty_optstr) {
4087 #ifdef CURSES_GRAPHICS
4088             int itmp = curses_read_attrs(op);
4089
4090             if (itmp == -1) {
4091                 config_error_add("Unknown %s parameter '%s'", fullname, opts);
4092                 retval = FALSE;
4093             } else
4094                 iflags.wc2_petattr = itmp;
4095 #else
4096             /* non-curses windowports will not use this flag anyway
4097              * but the above will not compile if we don't have curses.
4098              * Just set it to a sensible default: */
4099             iflags.wc2_petattr = ATR_INVERSE;
4100 #endif
4101         } else if (negated) {
4102             iflags.wc2_petattr = ATR_NONE;
4103         }
4104         if (retval) {
4105             iflags.hilite_pet = (iflags.wc2_petattr != ATR_NONE);
4106             if (!initial)
4107                 need_redraw = TRUE;
4108         }
4109         return retval;
4110     }
4111
4112     /* WINCAP2
4113      * windowborders:n */
4114     fullname = "windowborders";
4115     if (match_optname(opts, fullname, 10, TRUE)) {
4116         op = string_for_opt(opts, negated);
4117         if (negated && op != empty_optstr) {
4118             bad_negation(fullname, TRUE);
4119             retval = FALSE;
4120         } else {
4121             int itmp;
4122
4123             if (negated)
4124                 itmp = 0; /* Off */
4125             else if (op == empty_optstr)
4126                 itmp = 1; /* On */
4127             else    /* Value supplied; expect 0 (off), 1 (on), or 2 (auto) */
4128                 itmp = atoi(op);
4129
4130             if (itmp < 0 || itmp > 2) {
4131                 config_error_add("Invalid %s (should be 0, 1, or 2): %s",
4132                                  fullname, opts);
4133                 retval = FALSE;
4134             } else {
4135                 iflags.wc2_windowborders = itmp;
4136             }
4137         }
4138         return retval;
4139     }
4140 #endif /* CURSES_GRAPHICS */
4141
4142     /* WINCAP2
4143      * statuslines:n */
4144     fullname = "statuslines";
4145     if (match_optname(opts, fullname, 11, TRUE)) {
4146         int itmp = 0;
4147
4148         op = string_for_opt(opts, negated);
4149         if (negated) {
4150             bad_negation(fullname, TRUE);
4151             itmp = 2;
4152             retval = FALSE;
4153         } else if (op != empty_optstr) {
4154             itmp = atoi(op);
4155         }
4156         if (itmp < 2 || itmp > 3) {
4157             config_error_add("'%s' requires a value of 2 or 3", fullname);
4158             retval = FALSE;
4159         } else {
4160             iflags.wc2_statuslines = itmp;
4161             if (!initial)
4162                 need_redraw = TRUE;
4163         }
4164         return retval;
4165     }
4166
4167     /* menustyle:traditional or combination or full or partial */
4168     fullname = "menustyle";
4169     if (match_optname(opts, fullname, 4, TRUE)) {
4170         int tmp;
4171         boolean val_required = (strlen(opts) > 5 && !negated);
4172
4173         if (duplicate)
4174             complain_about_duplicate(opts, 1);
4175         if ((op = string_for_opt(opts, !val_required)) == empty_optstr) {
4176             if (val_required)
4177                 return FALSE; /* string_for_opt gave feedback */
4178             tmp = negated ? 'n' : 'f';
4179         } else {
4180             tmp = lowc(*op);
4181         }
4182         switch (tmp) {
4183         case 'n': /* none */
4184         case 't': /* traditional: prompt for class(es) by symbol,
4185                      prompt for each item within class(es) one at a time */
4186             flags.menu_style = MENU_TRADITIONAL;
4187             break;
4188         case 'c': /* combination: prompt for class(es) by symbol,
4189                      choose items within selected class(es) by menu */
4190             flags.menu_style = MENU_COMBINATION;
4191             break;
4192         case 'f': /* full: choose class(es) by first menu,
4193                      choose items within selected class(es) by second menu */
4194             flags.menu_style = MENU_FULL;
4195             break;
4196         case 'p': /* partial: skip class filtering,
4197                      choose items among all classes by menu */
4198             flags.menu_style = MENU_PARTIAL;
4199             break;
4200         default:
4201             config_error_add("Unknown %s parameter '%s'", fullname, op);
4202             return FALSE;
4203         }
4204         return retval;
4205     }
4206
4207     fullname = "menu_headings";
4208     if (match_optname(opts, fullname, 12, TRUE)) {
4209         int tmpattr;
4210
4211         if (duplicate)
4212             complain_about_duplicate(opts, 1);
4213         if (negated) {
4214             bad_negation(fullname, FALSE);
4215             return FALSE;
4216         } else if ((opts = string_for_env_opt(fullname, opts, FALSE))
4217                                               == empty_optstr) {
4218             return FALSE;
4219         }
4220         tmpattr = match_str2attr(opts, TRUE);
4221         if (tmpattr == -1)
4222             return FALSE;
4223         else
4224             iflags.menu_headings = tmpattr;
4225         return retval;
4226     }
4227
4228     /* check for menu command mapping */
4229     for (i = 0; i < SIZE(default_menu_cmd_info); i++) {
4230         fullname = default_menu_cmd_info[i].name;
4231         if (duplicate)
4232             complain_about_duplicate(opts, 1);
4233         if (match_optname(opts, fullname, (int) strlen(fullname), TRUE)) {
4234             if (negated) {
4235                 bad_negation(fullname, FALSE);
4236                 return FALSE;
4237             } else if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
4238                 char c, op_buf[BUFSZ];
4239
4240                 escapes(op, op_buf);
4241                 c = *op_buf;
4242
4243                 if (illegal_menu_cmd_key(c))
4244                     return FALSE;
4245
4246                 add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd);
4247             }
4248             return retval;
4249         }
4250     }
4251
4252     /* hilite fields in status prompt */
4253     fullname = "hilite_status";
4254     if (match_optname(opts, fullname, 13, TRUE)) {
4255 #ifdef STATUS_HILITES
4256         if (duplicate)
4257             complain_about_duplicate(opts, 1);
4258         op = string_for_opt(opts, TRUE);
4259         if (op != empty_optstr && negated) {
4260             clear_status_hilites();
4261             return retval;
4262         } else if (op == empty_optstr) {
4263             config_error_add("Value is mandatory for hilite_status");
4264             return FALSE;
4265         }
4266         if (!parse_status_hl1(op, tfrom_file))
4267             return FALSE;
4268         return retval;
4269 #else
4270         config_error_add("'%s' is not supported", fullname);
4271         return FALSE;
4272 #endif
4273     }
4274
4275     /* control over whether highlights should be displayed, and for how long */
4276     fullname = "statushilites";
4277     if (match_optname(opts, fullname, 9, TRUE)) {
4278 #ifdef STATUS_HILITES
4279         if (negated) {
4280             iflags.hilite_delta = 0L;
4281         } else {
4282             op = string_for_opt(opts, TRUE);
4283             iflags.hilite_delta = (op == empty_optstr || !*op) ? 3L : atol(op);
4284             if (iflags.hilite_delta < 0L)
4285                 iflags.hilite_delta = 1L;
4286         }
4287         if (!tfrom_file)
4288             reset_status_hilites();
4289         return retval;
4290 #else
4291         config_error_add("'%s' is not supported", fullname);
4292         return FALSE;
4293 #endif
4294     }
4295
4296     fullname = "DECgraphics";
4297     if (match_optname(opts, fullname, 3, TRUE)) {
4298 #ifdef BACKWARD_COMPAT
4299         boolean badflag = FALSE;
4300
4301         if (duplicate)
4302             complain_about_duplicate(opts, 1);
4303         if (!negated) {
4304             /* There is no rogue level DECgraphics-specific set */
4305             if (symset[PRIMARY].name) {
4306                 badflag = TRUE;
4307             } else {
4308                 symset[PRIMARY].name = dupstr(fullname);
4309                 if (!read_sym_file(PRIMARY)) {
4310                     badflag = TRUE;
4311                     clear_symsetentry(PRIMARY, TRUE);
4312                 } else
4313                     switch_symbols(TRUE);
4314             }
4315             if (badflag) {
4316                 config_error_add("Failure to load symbol set %s.", fullname);
4317                 return FALSE;
4318             }
4319         }
4320         return retval;
4321 #else
4322         config_error_add("'%s' no longer supported; use 'symset:%s' instead",
4323                          fullname, fullname);
4324         return FALSE;
4325 #endif
4326     } /* "DECgraphics" */
4327
4328     fullname = "IBMgraphics";
4329     if (match_optname(opts, fullname, 3, TRUE)) {
4330 #ifdef BACKWARD_COMPAT
4331         const char *sym_name = fullname;
4332         boolean badflag = FALSE;
4333
4334         if (duplicate)
4335             complain_about_duplicate(opts, 1);
4336         if (!negated) {
4337             for (i = 0; i < NUM_GRAPHICS; ++i) {
4338                 if (symset[i].name) {
4339                     badflag = TRUE;
4340                 } else {
4341                     if (i == ROGUESET)
4342                         sym_name = "RogueIBM";
4343                     symset[i].name = dupstr(sym_name);
4344                     if (!read_sym_file(i)) {
4345                         badflag = TRUE;
4346                         clear_symsetentry(i, TRUE);
4347                         break;
4348                     }
4349                 }
4350             }
4351             if (badflag) {
4352                 config_error_add("Failure to load symbol set %s.", sym_name);
4353                 return FALSE;
4354             } else {
4355                 switch_symbols(TRUE);
4356                 if (!initial && Is_rogue_level(&u.uz))
4357                     assign_graphics(ROGUESET);
4358             }
4359         }
4360         return retval;
4361 #else
4362         config_error_add("'%s' no longer supported; use 'symset:%s' instead",
4363                          fullname, fullname);
4364         return FALSE;
4365 #endif
4366     } /* "IBMgraphics" */
4367
4368     fullname = "MACgraphics";
4369     if (match_optname(opts, fullname, 3, TRUE)) {
4370 #if defined(MAC_GRAPHICS_ENV) && defined(BACKWARD_COMPAT)
4371         boolean badflag = FALSE;
4372
4373         if (duplicate)
4374             complain_about_duplicate(opts, 1);
4375         if (!negated) {
4376             if (symset[PRIMARY].name) {
4377                 badflag = TRUE;
4378             } else {
4379                 symset[PRIMARY].name = dupstr(fullname);
4380                 if (!read_sym_file(PRIMARY)) {
4381                     badflag = TRUE;
4382                     clear_symsetentry(PRIMARY, TRUE);
4383                 }
4384             }
4385             if (badflag) {
4386                 config_error_add("Failure to load symbol set %s.", fullname);
4387                 return FALSE;
4388             } else {
4389                 switch_symbols(TRUE);
4390                 if (!initial && Is_rogue_level(&u.uz))
4391                     assign_graphics(ROGUESET);
4392             }
4393         }
4394         return retval;
4395 #else   /* !(MAC_GRAPHICS_ENV && BACKWARD_COMPAT) */
4396         config_error_add("'%s' %s; use 'symset:%s' instead",
4397                          fullname,
4398 #ifdef MAC_GRAPHICS_ENV /* implies BACKWARD_COMPAT is not defined */
4399                          "no longer supported",
4400 #else
4401                          "is not supported",
4402 #endif
4403                          fullname);
4404         return FALSE;
4405 #endif  /* ?(MAC_GRAPHICS_ENV && BACKWARD_COMPAT) */
4406     } /* "MACgraphics" */
4407
4408     /*
4409      * OK, if we still haven't recognized the option, check the boolean
4410      * options list.
4411      */
4412     for (i = 0; boolopt[i].name; i++) {
4413         if (match_optname(opts, boolopt[i].name, 3, TRUE)) {
4414             /* options that don't exist */
4415             if (!boolopt[i].addr) {
4416                 if (!initial && !negated)
4417                     pline_The("\"%s\" option is not available.",
4418                               boolopt[i].name);
4419                 return retval;
4420             }
4421             /* options that must come from config file */
4422             if (!initial && (boolopt[i].optflags == SET_IN_FILE)) {
4423                 rejectoption(boolopt[i].name);
4424                 return retval;
4425             }
4426
4427             op = string_for_opt(opts, TRUE);
4428             if (op != empty_optstr) {
4429                 if (negated) {
4430                     config_error_add(
4431                            "Negated boolean '%s' should not have a parameter",
4432                                      boolopt[i].name);
4433                     return FALSE;
4434                 }
4435                 if (!strcmp(op, "true") || !strcmp(op, "yes")) {
4436                     negated = FALSE;
4437                 } else if (!strcmp(op, "false") || !strcmp(op, "no")) {
4438                     negated = TRUE;
4439                 } else {
4440                     config_error_add("Illegal parameter for a boolean");
4441                     return FALSE;
4442                 }
4443             }
4444             if (iflags.debug_fuzzer && !initial) {
4445                 /* don't randomly toggle this/these */
4446                 if (boolopt[i].addr == &flags.silent)
4447                     return TRUE;
4448             }
4449
4450             *(boolopt[i].addr) = !negated;
4451
4452             /* 0 means boolean opts */
4453             if (duplicate_opt_detection(boolopt[i].name, 0))
4454                 complain_about_duplicate(boolopt[i].name, 0);
4455 #ifdef RLECOMP
4456             if (boolopt[i].addr == &iflags.rlecomp)
4457                 set_savepref(iflags.rlecomp ? "rlecomp" : "!rlecomp");
4458 #endif
4459 #ifdef ZEROCOMP
4460             if (boolopt[i].addr == &iflags.zerocomp)
4461                 set_savepref(iflags.zerocomp ? "zerocomp" : "externalcomp");
4462 #endif
4463             if (boolopt[i].addr == &iflags.wc_ascii_map) {
4464                 /* toggling ascii_map; set tiled_map to its opposite;
4465                    what does it mean to turn off ascii map if tiled map
4466                    isn't supported? -- right now, we do nothing */
4467                 iflags.wc_tiled_map = negated;
4468             } else if (boolopt[i].addr == &iflags.wc_tiled_map) {
4469                 /* toggling tiled_map; set ascii_map to its opposite;
4470                    as with ascii_map, what does it mean to turn off tiled
4471                    map if ascii map isn't supported? */
4472                 iflags.wc_ascii_map = negated;
4473             }
4474             /* only do processing below if setting with doset() */
4475             if (initial)
4476                 return retval;
4477
4478             if (boolopt[i].addr == &flags.time
4479 #ifdef SCORE_ON_BOTL
4480                 || boolopt[i].addr == &flags.showscore
4481 #endif
4482                 || boolopt[i].addr == &flags.showexp) {
4483                 if (VIA_WINDOWPORT())
4484                     status_initialize(REASSESS_ONLY);
4485                 context.botl = TRUE;
4486             } else if (boolopt[i].addr == &flags.invlet_constant
4487                        || boolopt[i].addr == &flags.sortpack
4488                        || boolopt[i].addr == &iflags.implicit_uncursed) {
4489                 if (!flags.invlet_constant)
4490                     reassign();
4491                 update_inventory();
4492             } else if (boolopt[i].addr == &flags.lit_corridor
4493                        || boolopt[i].addr == &flags.dark_room) {
4494                 /*
4495                  * All corridor squares seen via night vision or
4496                  * candles & lamps change.  Update them by calling
4497                  * newsym() on them.  Don't do this if we are
4498                  * initializing the options --- the vision system
4499                  * isn't set up yet.
4500                  */
4501                 vision_recalc(2);       /* shut down vision */
4502                 vision_full_recalc = 1; /* delayed recalc */
4503                 if (iflags.use_color)
4504                     need_redraw = TRUE; /* darkroom refresh */
4505             } else if (boolopt[i].addr == &flags.showrace
4506                        || boolopt[i].addr == &iflags.use_inverse
4507                        || boolopt[i].addr == &iflags.hilite_pile
4508                        || boolopt[i].addr == &iflags.perm_invent
4509 #ifdef CURSES_GRAPHICS
4510                        || boolopt[i].addr == &iflags.cursesgraphics
4511 #endif
4512                        || boolopt[i].addr == &iflags.wc_ascii_map
4513                        || boolopt[i].addr == &iflags.wc_tiled_map) {
4514                 need_redraw = TRUE;
4515             } else if (boolopt[i].addr == &iflags.hilite_pet) {
4516 #ifdef CURSES_GRAPHICS
4517                 if (WINDOWPORT("curses")) {
4518                     /* if we're enabling hilite_pet and petattr isn't set,
4519                        set it to Inverse; if we're disabling, leave petattr
4520                        alone so that re-enabling will get current value back */
4521                     if (iflags.hilite_pet && !iflags.wc2_petattr)
4522                         iflags.wc2_petattr = curses_read_attrs("I");
4523                 }
4524 #endif
4525                 need_redraw = TRUE;
4526             } else if (boolopt[i].addr == &iflags.wc2_hitpointbar) {
4527                 if (VIA_WINDOWPORT()) {
4528                     /* [is reassessment really needed here?] */
4529                     status_initialize(REASSESS_ONLY);
4530                     need_redraw = TRUE;
4531                 }
4532 #ifdef TEXTCOLOR
4533             } else if (boolopt[i].addr == &iflags.use_color) {
4534                 need_redraw = TRUE;
4535 #ifdef TOS
4536                 if (iflags.BIOS) {
4537                     if (colors_changed)
4538                         restore_colors();
4539                     else
4540                         set_colors();
4541                 }
4542 #endif
4543             } else if (boolopt[i].addr == &iflags.use_menu_color
4544                        || boolopt[i].addr == &iflags.wc2_guicolor) {
4545                 update_inventory();
4546 #endif /* TEXTCOLOR */
4547             }
4548             return retval;
4549         }
4550     }
4551
4552     /* Is it a symbol? */
4553     if (strstr(opts, "S_") == opts && parsesymbols(opts, PRIMARY)) {
4554         switch_symbols(TRUE);
4555         check_gold_symbol();
4556         return retval;
4557     }
4558
4559     /* out of valid options */
4560     config_error_add("Unknown option '%s'", opts);
4561     return FALSE;
4562 }
4563
4564 /* parse key:command */
4565 boolean
4566 parsebindings(bindings)
4567 char* bindings;
4568 {
4569     char *bind;
4570     char key;
4571     int i;
4572     boolean ret = FALSE;
4573
4574     /* break off first binding from the rest; parse the rest */
4575     if ((bind = index(bindings, ',')) != 0) {
4576         *bind++ = 0;
4577         ret |= parsebindings(bind);
4578     }
4579
4580     /* parse a single binding: first split around : */
4581     if (! (bind = index(bindings, ':')))
4582         return FALSE; /* it's not a binding */
4583     *bind++ = 0;
4584
4585     /* read the key to be bound */
4586     key = txt2key(bindings);
4587     if (!key) {
4588         config_error_add("Unknown key binding key '%s'", bindings);
4589         return FALSE;
4590     }
4591
4592     bind = trimspaces(bind);
4593
4594     /* is it a special key? */
4595     if (bind_specialkey(key, bind))
4596         return TRUE;
4597
4598     /* is it a menu command? */
4599     for (i = 0; i < SIZE(default_menu_cmd_info); i++) {
4600         if (!strcmp(default_menu_cmd_info[i].name, bind)) {
4601             if (illegal_menu_cmd_key(key)) {
4602                 config_error_add("Bad menu key %s:%s", visctrl(key), bind);
4603                 return FALSE;
4604             } else
4605                 add_menu_cmd_alias(key, default_menu_cmd_info[i].cmd);
4606             return TRUE;
4607         }
4608     }
4609
4610     /* extended command? */
4611     if (!bind_key(key, bind)) {
4612         config_error_add("Unknown key binding command '%s'", bind);
4613         return FALSE;
4614     }
4615     return TRUE;
4616 }
4617
4618 static NEARDATA const char *menutype[] = { "traditional", "combination",
4619                                            "full", "partial" };
4620
4621 static NEARDATA const char *burdentype[] = { "unencumbered", "burdened",
4622                                              "stressed",     "strained",
4623                                              "overtaxed",    "overloaded" };
4624
4625 static NEARDATA const char *runmodes[] = { "teleport", "run", "walk",
4626                                            "crawl" };
4627
4628 static NEARDATA const char *sortltype[] = { "none", "loot", "full" };
4629
4630 /*
4631  * Convert the given string of object classes to a string of default object
4632  * symbols.
4633  */
4634 void
4635 oc_to_str(src, dest)
4636 char *src, *dest;
4637 {
4638     int i;
4639
4640     while ((i = (int) *src++) != 0) {
4641         if (i < 0 || i >= MAXOCLASSES)
4642             impossible("oc_to_str:  illegal object class %d", i);
4643         else
4644             *dest++ = def_oc_syms[i].sym;
4645     }
4646     *dest = '\0';
4647 }
4648
4649 /*
4650  * Add the given mapping to the menu command map list.  Always keep the
4651  * maps valid C strings.
4652  */
4653 void
4654 add_menu_cmd_alias(from_ch, to_ch)
4655 char from_ch, to_ch;
4656 {
4657     if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS) {
4658         pline("out of menu map space.");
4659     } else {
4660         mapped_menu_cmds[n_menu_mapped] = from_ch;
4661         mapped_menu_op[n_menu_mapped] = to_ch;
4662         n_menu_mapped++;
4663         mapped_menu_cmds[n_menu_mapped] = '\0';
4664         mapped_menu_op[n_menu_mapped] = '\0';
4665     }
4666 }
4667
4668 char
4669 get_menu_cmd_key(ch)
4670 char ch;
4671 {
4672     char *found = index(mapped_menu_op, ch);
4673
4674     if (found) {
4675         int idx = (int) (found - mapped_menu_op);
4676
4677         ch = mapped_menu_cmds[idx];
4678     }
4679     return ch;
4680 }
4681
4682 /*
4683  * Map the given character to its corresponding menu command.  If it
4684  * doesn't match anything, just return the original.
4685  */
4686 char
4687 map_menu_cmd(ch)
4688 char ch;
4689 {
4690     char *found = index(mapped_menu_cmds, ch);
4691
4692     if (found) {
4693         int idx = (int) (found - mapped_menu_cmds);
4694
4695         ch = mapped_menu_op[idx];
4696     }
4697     return ch;
4698 }
4699
4700 void
4701 show_menu_controls(win, dolist)
4702 winid win;
4703 boolean dolist;
4704 {
4705     char buf[BUFSZ];
4706
4707     putstr(win, 0, "Menu control keys:");
4708     if (dolist) {
4709         int i;
4710
4711         for (i = 0; i < SIZE(default_menu_cmd_info); i++) {
4712             Sprintf(buf, "%-8s %s",
4713                     visctrl(get_menu_cmd_key(default_menu_cmd_info[i].cmd)),
4714                     default_menu_cmd_info[i].desc);
4715             putstr(win, 0, buf);
4716         }
4717     } else {
4718         const char
4719             fmt3[] = " %-12s       %-2s        %-2s  %s",
4720             fmt2[] = " %-12s       %-2s        %-2s",
4721             fmt1[] = " %10s  %-2s  %s",
4722             fmt0[] = " %14s  %s";
4723
4724         putstr(win, 0, "");
4725         putstr(win, 0, "Selection:       On page   Full menu");
4726         Sprintf(buf, fmt2, "Select all",
4727                 visctrl(get_menu_cmd_key(MENU_SELECT_PAGE)),
4728                 visctrl(get_menu_cmd_key(MENU_SELECT_ALL)));
4729         putstr(win, 0, buf);
4730         Sprintf(buf, fmt2, "Deselect all",
4731                 visctrl(get_menu_cmd_key(MENU_UNSELECT_PAGE)),
4732                 visctrl(get_menu_cmd_key(MENU_UNSELECT_ALL)));
4733         putstr(win, 0, buf);
4734         Sprintf(buf, fmt2, "Invert all",
4735                 visctrl(get_menu_cmd_key(MENU_INVERT_PAGE)),
4736                 visctrl(get_menu_cmd_key(MENU_INVERT_ALL)));
4737         putstr(win, 0, buf);
4738         Sprintf(buf, fmt3, "Text match", "",
4739                 visctrl(get_menu_cmd_key(MENU_SEARCH)),
4740                 "Search and toggle matching entries");
4741         putstr(win, 0, buf);
4742         putstr(win, 0, "");
4743         putstr(win, 0, "Navigation:");
4744         Sprintf(buf, fmt1, "Go to     ",
4745                 visctrl(get_menu_cmd_key(MENU_NEXT_PAGE)),
4746                 "Next page");
4747         putstr(win, 0, buf);
4748         Sprintf(buf, fmt1, "",
4749                 visctrl(get_menu_cmd_key(MENU_PREVIOUS_PAGE)),
4750                 "Previous page");
4751         putstr(win, 0, buf);
4752         Sprintf(buf, fmt1, "",
4753                 visctrl(get_menu_cmd_key(MENU_FIRST_PAGE)),
4754                 "First page");
4755         putstr(win, 0, buf);
4756         Sprintf(buf, fmt1, "",
4757                 visctrl(get_menu_cmd_key(MENU_LAST_PAGE)),
4758                 "Last page");
4759         putstr(win, 0, buf);
4760         Sprintf(buf, fmt0, "SPACE", "Next page, if any, otherwise RETURN");
4761         putstr(win, 0, buf);
4762         Sprintf(buf, fmt0, "RETURN/ENTER",
4763                 "Finish menu with any selection(s) made");
4764         putstr(win, 0, buf);
4765         Sprintf(buf, fmt0, "ESCAPE",
4766                 "Cancel menu without selecting anything");
4767         putstr(win, 0, buf);
4768     }
4769 }
4770
4771 #if defined(MICRO) || defined(MAC) || defined(WIN32)
4772 #define OPTIONS_HEADING "OPTIONS"
4773 #else
4774 #define OPTIONS_HEADING "NETHACKOPTIONS"
4775 #endif
4776
4777 static char fmtstr_doset[] = "%s%-15s [%s]   ";
4778 static char fmtstr_doset_tab[] = "%s\t[%s]";
4779 /*JP
4780 static char n_currently_set[] = "(%d currently set)";
4781 */
4782 static char n_currently_set[] = "(%d\8cÂ\90Ý\92è\92\86)";
4783
4784 /* doset('O' command) menu entries for compound options */
4785 STATIC_OVL void
4786 doset_add_menu(win, option, indexoffset)
4787 winid win;          /* window to add to */
4788 const char *option; /* option name */
4789 int indexoffset;    /* value to add to index in compopt[], or zero
4790                        if option cannot be changed */
4791 {
4792     const char *value = "unknown"; /* current value */
4793     char buf[BUFSZ], buf2[BUFSZ];
4794     anything any;
4795     int i;
4796
4797     any = zeroany;
4798     if (indexoffset == 0) {
4799         any.a_int = 0;
4800         value = get_compopt_value(option, buf2);
4801     } else {
4802         for (i = 0; compopt[i].name; i++)
4803             if (strcmp(option, compopt[i].name) == 0)
4804                 break;
4805
4806         if (compopt[i].name) {
4807             any.a_int = i + 1 + indexoffset;
4808             value = get_compopt_value(option, buf2);
4809         } else {
4810             /* We are trying to add an option not found in compopt[].
4811                This is almost certainly bad, but we'll let it through anyway
4812                (with a zero value, so it can't be selected). */
4813             any.a_int = 0;
4814         }
4815     }
4816     /* "    " replaces "a - " -- assumes menus follow that style */
4817     if (!iflags.menu_tab_sep)
4818         Sprintf(buf, fmtstr_doset, any.a_int ? "" : "    ", option,
4819                 value);
4820     else
4821         Sprintf(buf, fmtstr_doset_tab, option, value);
4822     add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
4823 }
4824
4825 STATIC_OVL void
4826 opts_add_others(win, name, id, bufx, nset)
4827 winid win;
4828 const char *name;
4829 int id;
4830 char *bufx;
4831 int nset;
4832 {
4833     char buf[BUFSZ], buf2[BUFSZ];
4834     anything any = zeroany;
4835
4836     any.a_int = id;
4837     if (!bufx)
4838         Sprintf(buf2, n_currently_set, nset);
4839     else
4840         Sprintf(buf2, "%s", bufx);
4841     if (!iflags.menu_tab_sep)
4842         Sprintf(buf, fmtstr_doset, any.a_int ? "" : "    ",
4843                 name, buf2);
4844     else
4845         Sprintf(buf, fmtstr_doset_tab, name, buf2);
4846     add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
4847 }
4848
4849 int
4850 count_apes(VOID_ARGS)
4851 {
4852     int numapes = 0;
4853     struct autopickup_exception *ape = apelist;
4854
4855     while (ape) {
4856       numapes++;
4857       ape = ape->next;
4858     }
4859
4860     return numapes;
4861 }
4862
4863 enum opt_other_enums {
4864     OPT_OTHER_MSGTYPE = -4,
4865     OPT_OTHER_MENUCOLOR = -3,
4866     OPT_OTHER_STATHILITE = -2,
4867     OPT_OTHER_APEXC = -1
4868     /* these must be < 0 */
4869 };
4870
4871 static struct other_opts {
4872     const char *name;
4873     int optflags;
4874     enum opt_other_enums code;
4875     int NDECL((*othr_count_func));
4876 } othropt[] = {
4877     { "autopickup exceptions", SET_IN_GAME, OPT_OTHER_APEXC, count_apes },
4878     { "menu colors", SET_IN_GAME, OPT_OTHER_MENUCOLOR, count_menucolors },
4879     { "message types", SET_IN_GAME, OPT_OTHER_MSGTYPE, msgtype_count },
4880 #ifdef STATUS_HILITES
4881     { "status hilite rules", SET_IN_GAME, OPT_OTHER_STATHILITE,
4882       count_status_hilites },
4883 #endif
4884     { (char *) 0, 0, (enum opt_other_enums) 0 },
4885 };
4886
4887 /* the 'O' command */
4888 int
4889 doset() /* changing options via menu by Per Liboriussen */
4890 {
4891     static boolean made_fmtstr = FALSE;
4892     char buf[BUFSZ];
4893     const char *name;
4894     int i = 0, pass, boolcount, pick_cnt, pick_idx, opt_indx;
4895     boolean *bool_p;
4896     winid tmpwin;
4897     anything any;
4898     menu_item *pick_list;
4899     int indexoffset, startpass, endpass, optflags;
4900     boolean setinitial = FALSE, fromfile = FALSE;
4901     unsigned longest_name_len;
4902
4903     tmpwin = create_nhwindow(NHW_MENU);
4904     start_menu(tmpwin);
4905
4906 #ifdef notyet /* SYSCF */
4907     /* XXX I think this is still fragile.  Fixing initial/from_file and/or
4908        changing the SET_* etc to bitmaps will let me make this better. */
4909     if (wizard)
4910         startpass = SET_IN_SYS;
4911     else
4912 #endif
4913         startpass = DISP_IN_GAME;
4914     endpass = (wizard) ? SET_IN_WIZGAME : SET_IN_GAME;
4915
4916     if (!made_fmtstr && !iflags.menu_tab_sep) {
4917         /* spin through the options to find the longest name
4918            and adjust the format string accordingly */
4919         longest_name_len = 0;
4920         for (pass = 0; pass <= 2; pass++)
4921             for (i = 0; (name = ((pass == 0) ? boolopt[i].name
4922                                  : (pass == 1) ? compopt[i].name
4923                                    : othropt[i].name)) != 0; i++) {
4924                 if (pass == 0 && !boolopt[i].addr)
4925                     continue;
4926                 optflags = (pass == 0) ? boolopt[i].optflags
4927                            : (pass == 1) ? compopt[i].optflags
4928                              : othropt[i].optflags;
4929                 if (optflags < startpass || optflags > endpass)
4930                     continue;
4931                 if ((is_wc_option(name) && !wc_supported(name))
4932                     || (is_wc2_option(name) && !wc2_supported(name)))
4933                     continue;
4934
4935                 if (strlen(name) > longest_name_len)
4936                     longest_name_len = strlen(name);
4937             }
4938         Sprintf(fmtstr_doset, "%%s%%-%us [%%s]", longest_name_len);
4939         made_fmtstr = TRUE;
4940     }
4941
4942     any = zeroany;
4943     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
4944 /*JP
4945              "Booleans (selecting will toggle value):", MENU_UNSELECTED);
4946 */
4947              "\90^\8bU\83I\83v\83V\83\87\83\93 (\91I\91ð\82·\82é\82Æ\92l\82ª\90Ø\82è\91Ö\82í\82è\82Ü\82·)\81F", MENU_UNSELECTED);
4948     any.a_int = 0;
4949     /* first list any other non-modifiable booleans, then modifiable ones */
4950     for (pass = 0; pass <= 1; pass++)
4951         for (i = 0; (name = boolopt[i].name) != 0; i++)
4952             if ((bool_p = boolopt[i].addr) != 0
4953                 && ((boolopt[i].optflags <= DISP_IN_GAME && pass == 0)
4954                     || (boolopt[i].optflags >= SET_IN_GAME && pass == 1))) {
4955                 if (bool_p == &flags.female)
4956                     continue; /* obsolete */
4957                 if (boolopt[i].optflags == SET_IN_WIZGAME && !wizard)
4958                     continue;
4959                 if ((is_wc_option(name) && !wc_supported(name))
4960                     || (is_wc2_option(name) && !wc2_supported(name)))
4961                     continue;
4962
4963                 any.a_int = (pass == 0) ? 0 : i + 1;
4964                 if (!iflags.menu_tab_sep)
4965                     Sprintf(buf, fmtstr_doset, (pass == 0) ? "    " : "",
4966                             name, *bool_p ? "true" : "false");
4967                 else
4968                     Sprintf(buf, fmtstr_doset_tab,
4969                             name, *bool_p ? "true" : "false");
4970                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
4971                          MENU_UNSELECTED);
4972             }
4973
4974     boolcount = i;
4975     indexoffset = boolcount;
4976     any = zeroany;
4977     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
4978 #if 0 /*JP:T*/
4979     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
4980              "Compounds (selecting will prompt for new value):",
4981              MENU_UNSELECTED);
4982 #else
4983     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
4984              "\95\8e\9a\97ñ\83I\83v\83V\83\87\83\93 (\91I\91ð\82·\82é\82Æ\90V\82µ\82¢\92l\82Ì\93ü\97Í\82ð\8b\81\82ß\82Ü\82·)\81F",
4985              MENU_UNSELECTED);
4986 #endif
4987
4988     /* deliberately put playmode, name, role+race+gender+align first */
4989     doset_add_menu(tmpwin, "playmode", 0);
4990     doset_add_menu(tmpwin, "name", 0);
4991     doset_add_menu(tmpwin, "role", 0);
4992     doset_add_menu(tmpwin, "race", 0);
4993     doset_add_menu(tmpwin, "gender", 0);
4994     doset_add_menu(tmpwin, "align", 0);
4995
4996     for (pass = startpass; pass <= endpass; pass++)
4997         for (i = 0; (name = compopt[i].name) != 0; i++)
4998             if (compopt[i].optflags == pass) {
4999                 if (!strcmp(name, "playmode")  || !strcmp(name, "name")
5000                     || !strcmp(name, "role")   || !strcmp(name, "race")
5001                     || !strcmp(name, "gender") || !strcmp(name, "align"))
5002                     continue;
5003                 if ((is_wc_option(name) && !wc_supported(name))
5004                     || (is_wc2_option(name) && !wc2_supported(name)))
5005                     continue;
5006
5007                 doset_add_menu(tmpwin, name,
5008                                (pass == DISP_IN_GAME) ? 0 : indexoffset);
5009             }
5010
5011     any = zeroany;
5012     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
5013     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
5014              "Other settings:", MENU_UNSELECTED);
5015
5016     for (i = 0; (name = othropt[i].name) != 0; i++) {
5017         if ((is_wc_option(name) && !wc_supported(name))
5018             || (is_wc2_option(name) && !wc2_supported(name)))
5019             continue;
5020         opts_add_others(tmpwin, name, othropt[i].code,
5021                         (char *) 0, othropt[i].othr_count_func());
5022     }
5023
5024 #ifdef PREFIXES_IN_USE
5025     any = zeroany;
5026     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
5027     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
5028              "Variable playground locations:", MENU_UNSELECTED);
5029     for (i = 0; i < PREFIX_COUNT; i++)
5030         doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
5031 #endif
5032 /*JP
5033     end_menu(tmpwin, "Set what options?");
5034 */
5035     end_menu(tmpwin, "\82Ç\82Ì\83I\83v\83V\83\87\83\93\82ð\90Ý\92è\82µ\82Ü\82·\82©\81H");
5036     need_redraw = FALSE;
5037     if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
5038         /*
5039          * Walk down the selection list and either invert the booleans
5040          * or prompt for new values. In most cases, call parseoptions()
5041          * to take care of options that require special attention, like
5042          * redraws.
5043          */
5044         for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
5045             opt_indx = pick_list[pick_idx].item.a_int - 1;
5046             if (opt_indx < -1)
5047                 opt_indx++; /* -1 offset for select_menu() */
5048             if (opt_indx == OPT_OTHER_APEXC) {
5049                 (void) special_handling("autopickup_exception", setinitial,
5050                                         fromfile);
5051 #ifdef STATUS_HILITES
5052             } else if (opt_indx == OPT_OTHER_STATHILITE) {
5053                 if (!status_hilite_menu()) {
5054                     pline("Bad status hilite(s) specified.");
5055                 } else {
5056                     if (wc2_supported("hilite_status"))
5057                         preference_update("hilite_status");
5058                 }
5059 #endif
5060             } else if (opt_indx == OPT_OTHER_MENUCOLOR) {
5061                     (void) special_handling("menu_colors", setinitial,
5062                                             fromfile);
5063             } else if (opt_indx == OPT_OTHER_MSGTYPE) {
5064                     (void) special_handling("msgtype", setinitial, fromfile);
5065             } else if (opt_indx < boolcount) {
5066                 /* boolean option */
5067                 Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
5068                         boolopt[opt_indx].name);
5069                 (void) parseoptions(buf, setinitial, fromfile);
5070                 if (wc_supported(boolopt[opt_indx].name)
5071                     || wc2_supported(boolopt[opt_indx].name))
5072                     preference_update(boolopt[opt_indx].name);
5073             } else {
5074                 /* compound option */
5075                 opt_indx -= boolcount;
5076
5077                 if (!special_handling(compopt[opt_indx].name, setinitial,
5078                                       fromfile)) {
5079                     char abuf[BUFSZ];
5080
5081 /*JP
5082                     Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
5083 */
5084                     Sprintf(buf, "%s\82É\89½\82ð\90Ý\92è\82·\82é\81H", compopt[opt_indx].name);
5085                     abuf[0] = '\0';
5086                     getlin(buf, abuf);
5087                     if (abuf[0] == '\033')
5088                         continue;
5089                     Sprintf(buf, "%s:", compopt[opt_indx].name);
5090                     (void) strncat(eos(buf), abuf,
5091                                    (sizeof buf - 1 - strlen(buf)));
5092                     /* pass the buck */
5093                     (void) parseoptions(buf, setinitial, fromfile);
5094                 }
5095                 if (wc_supported(compopt[opt_indx].name)
5096                     || wc2_supported(compopt[opt_indx].name))
5097                     preference_update(compopt[opt_indx].name);
5098             }
5099         }
5100         free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
5101     }
5102
5103     destroy_nhwindow(tmpwin);
5104     if (need_redraw) {
5105         check_gold_symbol();
5106         reglyph_darkroom();
5107         (void) doredraw();
5108     }
5109     return 0;
5110 }
5111
5112 /* common to msg-types, menu-colors, autopickup-exceptions */
5113 STATIC_OVL int
5114 handle_add_list_remove(optname, numtotal)
5115 const char *optname;
5116 int numtotal;
5117 {
5118     winid tmpwin;
5119     anything any;
5120     int i, pick_cnt, opt_idx;
5121     menu_item *pick_list = (menu_item *) 0;
5122     static const struct action {
5123         char letr;
5124         const char *desc;
5125     } action_titles[] = {
5126 #if 0 /*JP:T*/
5127         { 'a', "add new %s" },         /* [0] */
5128 #else
5129         { 'a', "\90V\82µ\82¢%s\82ð\92Ç\89Á" },     /* [0] */
5130 #endif
5131 #if 0 /*JP:T*/
5132         { 'l', "list %s" },            /* [1] */
5133 #else
5134         { 'l', "%s\82ð\88ê\97\97\95\\8e¦" },       /* [1] */
5135 #endif
5136 #if 0 /*JP:T*/
5137         { 'r', "remove existing %s" }, /* [2] */
5138 #else
5139         { 'r', "\8aù\82É\82 \82é%s\82ð\8dí\8f\9c" },   /* [2] */
5140 #endif
5141 #if 0 /*JP:T*/
5142         { 'x', "exit this menu" },     /* [3] */
5143 #else
5144         { 'x', "\82±\82Ì\83\81\83j\83\85\81[\82ð\95Â\82\82é" }, /* [3] */
5145 #endif
5146     };
5147
5148     opt_idx = 0;
5149     tmpwin = create_nhwindow(NHW_MENU);
5150     start_menu(tmpwin);
5151     any = zeroany;
5152     for (i = 0; i < SIZE(action_titles); i++) {
5153         char tmpbuf[BUFSZ];
5154
5155         any.a_int++;
5156         /* omit list and remove if there aren't any yet */
5157         if (!numtotal && (i == 1 || i == 2))
5158             continue;
5159         Sprintf(tmpbuf, action_titles[i].desc,
5160                 (i == 1) ? makeplural(optname) : optname);
5161         add_menu(tmpwin, NO_GLYPH, &any, action_titles[i].letr, 0, ATR_NONE,
5162                  tmpbuf, (i == 3) ? MENU_SELECTED : MENU_UNSELECTED);
5163     }
5164 /*JP
5165     end_menu(tmpwin, "Do what?");
5166 */
5167     end_menu(tmpwin, "\82Ç\82¤\82·\82é\81H");
5168     if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
5169         opt_idx = pick_list[0].item.a_int - 1;
5170         if (pick_cnt > 1 && opt_idx == 3)
5171             opt_idx = pick_list[1].item.a_int - 1;
5172         free((genericptr_t) pick_list);
5173     } else
5174         opt_idx = 3; /* none selected, exit menu */
5175     destroy_nhwindow(tmpwin);
5176     return opt_idx;
5177 }
5178
5179 struct symsetentry *symset_list = 0; /* files.c will populate this with
5180                                       * list of available sets */
5181
5182 STATIC_OVL boolean
5183 special_handling(optname, setinitial, setfromfile)
5184 const char *optname;
5185 boolean setinitial, setfromfile;
5186 {
5187     winid tmpwin;
5188     anything any;
5189     int i, n;
5190     char buf[BUFSZ];
5191
5192     /* Special handling of menustyle, pickup_burden, pickup_types,
5193      * disclose, runmode, msg_window, menu_headings, sortloot,
5194      * and number_pad options.
5195      * Also takes care of interactive autopickup_exception_handling changes.
5196      */
5197     if (!strcmp("menustyle", optname)) {
5198         const char *style_name;
5199         menu_item *style_pick = (menu_item *) 0;
5200
5201         tmpwin = create_nhwindow(NHW_MENU);
5202         start_menu(tmpwin);
5203         any = zeroany;
5204         for (i = 0; i < SIZE(menutype); i++) {
5205             style_name = menutype[i];
5206             /* note: separate `style_name' variable used
5207                to avoid an optimizer bug in VAX C V2.3 */
5208             any.a_int = i + 1;
5209             add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0, ATR_NONE,
5210                      style_name, MENU_UNSELECTED);
5211         }
5212 /*JP
5213         end_menu(tmpwin, "Select menustyle:");
5214 */
5215         end_menu(tmpwin, "\83\81\83j\83\85\81[\83X\83^\83C\83\8b\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
5216         if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) {
5217             flags.menu_style = style_pick->item.a_int - 1;
5218             free((genericptr_t) style_pick);
5219         }
5220         destroy_nhwindow(tmpwin);
5221     } else if (!strcmp("paranoid_confirmation", optname)) {
5222         menu_item *paranoia_picks = (menu_item *) 0;
5223
5224         tmpwin = create_nhwindow(NHW_MENU);
5225         start_menu(tmpwin);
5226         any = zeroany;
5227         for (i = 0; paranoia[i].flagmask != 0; ++i) {
5228             if (paranoia[i].flagmask == PARANOID_BONES && !wizard)
5229                 continue;
5230             any.a_int = paranoia[i].flagmask;
5231             add_menu(tmpwin, NO_GLYPH, &any, *paranoia[i].argname, 0,
5232                      ATR_NONE, paranoia[i].explain,
5233                      (flags.paranoia_bits & paranoia[i].flagmask)
5234                          ? MENU_SELECTED
5235                          : MENU_UNSELECTED);
5236         }
5237         end_menu(tmpwin, "Actions requiring extra confirmation:");
5238         i = select_menu(tmpwin, PICK_ANY, &paranoia_picks);
5239         if (i >= 0) {
5240             /* player didn't cancel; we reset all the paranoia options
5241                here even if there were no items picked, since user
5242                could have toggled off preselected ones to end up with 0 */
5243             flags.paranoia_bits = 0;
5244             if (i > 0) {
5245                 /* at least 1 item set, either preselected or newly picked */
5246                 while (--i >= 0)
5247                     flags.paranoia_bits |= paranoia_picks[i].item.a_int;
5248                 free((genericptr_t) paranoia_picks);
5249             }
5250         }
5251         destroy_nhwindow(tmpwin);
5252     } else if (!strcmp("pickup_burden", optname)) {
5253         const char *burden_name, *burden_letters = "ubsntl";
5254         menu_item *burden_pick = (menu_item *) 0;
5255
5256         tmpwin = create_nhwindow(NHW_MENU);
5257         start_menu(tmpwin);
5258         any = zeroany;
5259         for (i = 0; i < SIZE(burdentype); i++) {
5260             burden_name = burdentype[i];
5261             any.a_int = i + 1;
5262             add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0, ATR_NONE,
5263                      burden_name, MENU_UNSELECTED);
5264         }
5265 /*JP
5266         end_menu(tmpwin, "Select encumbrance level:");
5267 */
5268         end_menu(tmpwin, "\8cx\8d\90\82ð\8fo\82·\89×\8fd\83\8c\83x\83\8b\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
5269         if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) {
5270             flags.pickup_burden = burden_pick->item.a_int - 1;
5271             free((genericptr_t) burden_pick);
5272         }
5273         destroy_nhwindow(tmpwin);
5274     } else if (!strcmp("pickup_types", optname)) {
5275         /* parseoptions will prompt for the list of types */
5276         (void) parseoptions(strcpy(buf, "pickup_types"),
5277                             setinitial, setfromfile);
5278     } else if (!strcmp("disclose", optname)) {
5279         /* order of disclose_names[] must correspond to
5280            disclosure_options in decl.c */
5281         static const char *disclosure_names[] = {
5282             "inventory", "attributes", "vanquished",
5283             "genocides", "conduct",    "overview",
5284         };
5285         int disc_cat[NUM_DISCLOSURE_OPTIONS];
5286         int pick_cnt, pick_idx, opt_idx;
5287         char c;
5288         menu_item *disclosure_pick = (menu_item *) 0;
5289
5290         tmpwin = create_nhwindow(NHW_MENU);
5291         start_menu(tmpwin);
5292         any = zeroany;
5293         for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
5294             Sprintf(buf, "%-12s[%c%c]", disclosure_names[i],
5295                     flags.end_disclose[i], disclosure_options[i]);
5296             any.a_int = i + 1;
5297             add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0,
5298                      ATR_NONE, buf, MENU_UNSELECTED);
5299             disc_cat[i] = 0;
5300         }
5301 /*JP
5302         end_menu(tmpwin, "Change which disclosure options categories:");
5303 */
5304         end_menu(tmpwin, "\82Ç\82Ì\83J\83e\83S\83\8a\82Ì\95\\8e¦\8fî\95ñ\83I\83v\83V\83\87\83\93\82ð\95Ï\8dX\82µ\82Ü\82·\82©\81F");
5305         pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_pick);
5306         if (pick_cnt > 0) {
5307             for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
5308                 opt_idx = disclosure_pick[pick_idx].item.a_int - 1;
5309                 disc_cat[opt_idx] = 1;
5310             }
5311             free((genericptr_t) disclosure_pick);
5312             disclosure_pick = (menu_item *) 0;
5313         }
5314         destroy_nhwindow(tmpwin);
5315
5316         for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
5317             if (disc_cat[i]) {
5318                 c = flags.end_disclose[i];
5319 /*JP
5320                 Sprintf(buf, "Disclosure options for %s:",
5321 */
5322                 Sprintf(buf, "%s\82Ì\8fo\97Í\8c`\8e®\81F",
5323                         disclosure_names[i]);
5324                 tmpwin = create_nhwindow(NHW_MENU);
5325                 start_menu(tmpwin);
5326                 any = zeroany;
5327                 /* 'y','n',and '+' work as alternate selectors; '-' doesn't */
5328                 any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
5329                 add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
5330 /*JP
5331                          "Never disclose, without prompting",
5332 */
5333                          "\8am\94F\82¹\82¸\82É\8fo\97Í\82à\82µ\82È\82¢",
5334                          (c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
5335                 any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
5336                 add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
5337 /*JP
5338                          "Always disclose, without prompting",
5339 */
5340                          "\8am\94F\82¹\82¸\82É\8fo\97Í\82·\82é",
5341                          (c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
5342                 if (*disclosure_names[i] == 'v') {
5343                     any.a_char = DISCLOSE_SPECIAL_WITHOUT_PROMPT; /* '#' */
5344                     add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
5345                              "Always disclose, pick sort order from menu",
5346                              (c == any.a_char) ? MENU_SELECTED
5347                                                : MENU_UNSELECTED);
5348                 }
5349                 any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
5350                 add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
5351 /*JP
5352                          "Prompt, with default answer of \"No\"",
5353 */
5354                          "\8am\94F\82·\82é\81C\83f\83t\83H\83\8b\83g\82Í\81u\8fo\97Í\82µ\82È\82¢\81v",
5355                          (c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
5356                 any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
5357                 add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
5358 /*JP
5359                          "Prompt, with default answer of \"Yes\"",
5360 */
5361                          "\8am\94F\82·\82é\81C\83f\83t\83H\83\8b\83g\82Í\81u\8fo\97Í\82·\82é\81v",
5362                          (c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
5363                 if (*disclosure_names[i] == 'v') {
5364                     any.a_char = DISCLOSE_PROMPT_DEFAULT_SPECIAL; /* '?' */
5365                     add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
5366                 "Prompt, with default answer of \"Ask\" to request sort menu",
5367                              (c == any.a_char) ? MENU_SELECTED
5368                                                : MENU_UNSELECTED);
5369                 }
5370                 end_menu(tmpwin, buf);
5371                 n = select_menu(tmpwin, PICK_ONE, &disclosure_pick);
5372                 if (n > 0) {
5373                     flags.end_disclose[i] = disclosure_pick[0].item.a_char;
5374                     if (n > 1 && flags.end_disclose[i] == c)
5375                         flags.end_disclose[i] = disclosure_pick[1].item.a_char;
5376                     free((genericptr_t) disclosure_pick);
5377                 }
5378                 destroy_nhwindow(tmpwin);
5379             }
5380         }
5381     } else if (!strcmp("runmode", optname)) {
5382         const char *mode_name;
5383         menu_item *mode_pick = (menu_item *) 0;
5384
5385         tmpwin = create_nhwindow(NHW_MENU);
5386         start_menu(tmpwin);
5387         any = zeroany;
5388         for (i = 0; i < SIZE(runmodes); i++) {
5389             mode_name = runmodes[i];
5390             any.a_int = i + 1;
5391             add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0, ATR_NONE,
5392                      mode_name, MENU_UNSELECTED);
5393         }
5394 /*JP
5395         end_menu(tmpwin, "Select run/travel display mode:");
5396 */
5397         end_menu(tmpwin, "\91\96\8ds/\83g\83\89\83x\83\8b\82Ì\95\\8e¦\83\82\81[\83h\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
5398         if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
5399             flags.runmode = mode_pick->item.a_int - 1;
5400             free((genericptr_t) mode_pick);
5401         }
5402         destroy_nhwindow(tmpwin);
5403     } else if (!strcmp("whatis_coord", optname)) {
5404         menu_item *window_pick = (menu_item *) 0;
5405         int pick_cnt;
5406         char gp = iflags.getpos_coords;
5407
5408         tmpwin = create_nhwindow(NHW_MENU);
5409         start_menu(tmpwin);
5410         any = zeroany;
5411         any.a_char = GPCOORDS_COMPASS;
5412         add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_COMPASS, 0, ATR_NONE,
5413                  "compass ('east' or '3s' or '2n,4w')",
5414                  (gp == GPCOORDS_COMPASS) ? MENU_SELECTED : MENU_UNSELECTED);
5415         any.a_char = GPCOORDS_COMFULL;
5416         add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_COMFULL, 0, ATR_NONE,
5417                  "full compass ('east' or '3south' or '2north,4west')",
5418                  (gp == GPCOORDS_COMFULL) ? MENU_SELECTED : MENU_UNSELECTED);
5419         any.a_char = GPCOORDS_MAP;
5420         add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_MAP, 0, ATR_NONE,
5421                  "map <x,y>",
5422                  (gp == GPCOORDS_MAP) ? MENU_SELECTED : MENU_UNSELECTED);
5423         any.a_char = GPCOORDS_SCREEN;
5424         add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_SCREEN, 0, ATR_NONE,
5425                  "screen [row,column]",
5426                  (gp == GPCOORDS_SCREEN) ? MENU_SELECTED : MENU_UNSELECTED);
5427         any.a_char = GPCOORDS_NONE;
5428         add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_NONE, 0, ATR_NONE,
5429                  "none (no coordinates displayed)",
5430                  (gp == GPCOORDS_NONE) ? MENU_SELECTED : MENU_UNSELECTED);
5431         any.a_long = 0L;
5432         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
5433         Sprintf(buf, "map: upper-left: <%d,%d>, lower-right: <%d,%d>%s",
5434                 1, 0, COLNO - 1, ROWNO - 1,
5435                 flags.verbose ? "; column 0 unused, off left edge" : "");
5436         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
5437         if (strcmp(windowprocs.name, "tty")) /* only show for non-tty */
5438             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
5439        "screen: row is offset to accommodate tty interface's use of top line",
5440                      MENU_UNSELECTED);
5441 #if COLNO == 80
5442 #define COL80ARG flags.verbose ? "; column 80 is not used" : ""
5443 #else
5444 #define COL80ARG ""
5445 #endif
5446         Sprintf(buf, "screen: upper-left: [%02d,%02d], lower-right: [%d,%d]%s",
5447                 0 + 2, 1, ROWNO - 1 + 2, COLNO - 1, COL80ARG);
5448 #undef COL80ARG
5449         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
5450         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
5451         end_menu(tmpwin,
5452             "Select coordinate display when auto-describing a map position:");
5453         if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &window_pick)) > 0) {
5454             iflags.getpos_coords = window_pick[0].item.a_char;
5455             /* PICK_ONE doesn't unselect preselected entry when
5456                selecting another one */
5457             if (pick_cnt > 1 && iflags.getpos_coords == gp)
5458                 iflags.getpos_coords = window_pick[1].item.a_char;
5459             free((genericptr_t) window_pick);
5460         }
5461         destroy_nhwindow(tmpwin);
5462     } else if (!strcmp("whatis_filter", optname)) {
5463         menu_item *window_pick = (menu_item *) 0;
5464         int pick_cnt;
5465         char gf = iflags.getloc_filter;
5466
5467         tmpwin = create_nhwindow(NHW_MENU);
5468         start_menu(tmpwin);
5469         any = zeroany;
5470         any.a_char = (GFILTER_NONE + 1);
5471         add_menu(tmpwin, NO_GLYPH, &any, 'n',
5472                  0, ATR_NONE, "no filtering",
5473                  (gf == GFILTER_NONE) ? MENU_SELECTED : MENU_UNSELECTED);
5474         any.a_char = (GFILTER_VIEW + 1);
5475         add_menu(tmpwin, NO_GLYPH, &any, 'v',
5476                  0, ATR_NONE, "in view only",
5477                  (gf == GFILTER_VIEW) ? MENU_SELECTED : MENU_UNSELECTED);
5478         any.a_char = (GFILTER_AREA + 1);
5479         add_menu(tmpwin, NO_GLYPH, &any, 'a',
5480                  0, ATR_NONE, "in same area",
5481                  (gf == GFILTER_AREA) ? MENU_SELECTED : MENU_UNSELECTED);
5482         end_menu(tmpwin,
5483       "Select location filtering when going for next/previous map position:");
5484         if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &window_pick)) > 0) {
5485             iflags.getloc_filter = (window_pick[0].item.a_char - 1);
5486             /* PICK_ONE doesn't unselect preselected entry when
5487                selecting another one */
5488             if (pick_cnt > 1 && iflags.getloc_filter == gf)
5489                 iflags.getloc_filter = (window_pick[1].item.a_char - 1);
5490             free((genericptr_t) window_pick);
5491         }
5492         destroy_nhwindow(tmpwin);
5493     } else if (!strcmp("msg_window", optname)) {
5494 #if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS)
5495         if (WINDOWPORT("tty") || WINDOWPORT("curses")) {
5496             /* by Christian W. Cooper */
5497             menu_item *window_pick = (menu_item *) 0;
5498
5499             tmpwin = create_nhwindow(NHW_MENU);
5500             start_menu(tmpwin);
5501             any = zeroany;
5502             if (!WINDOWPORT("curses")) {
5503                 any.a_char = 's';
5504                 add_menu(tmpwin, NO_GLYPH, &any, 's', 0, ATR_NONE,
5505                          "single", MENU_UNSELECTED);
5506                 any.a_char = 'c';
5507                 add_menu(tmpwin, NO_GLYPH, &any, 'c', 0, ATR_NONE,
5508                          "combination", MENU_UNSELECTED);
5509             }
5510             any.a_char = 'f';
5511             add_menu(tmpwin, NO_GLYPH, &any, 'f', 0, ATR_NONE, "full",
5512                      MENU_UNSELECTED);
5513             any.a_char = 'r';
5514             add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "reversed",
5515                      MENU_UNSELECTED);
5516 /*JP
5517             end_menu(tmpwin, "Select message history display type:");
5518 */
5519             end_menu(tmpwin, "\83\81\83b\83Z\81[\83W\97\9a\97ð\82Ì\95\\8e¦\95û\96@\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
5520             if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
5521                 iflags.prevmsg_window = window_pick->item.a_char;
5522                 free((genericptr_t) window_pick);
5523             }
5524             destroy_nhwindow(tmpwin);
5525         } else
5526 #endif /* msg_window for tty or curses */
5527             pline("'%s' option is not supported for '%s'.",
5528                   optname, windowprocs.name);
5529     } else if (!strcmp("sortloot", optname)) {
5530         const char *sortl_name;
5531         menu_item *sortl_pick = (menu_item *) 0;
5532
5533         tmpwin = create_nhwindow(NHW_MENU);
5534         start_menu(tmpwin);
5535         any = zeroany;
5536         for (i = 0; i < SIZE(sortltype); i++) {
5537             sortl_name = sortltype[i];
5538             any.a_char = *sortl_name;
5539             add_menu(tmpwin, NO_GLYPH, &any, *sortl_name, 0, ATR_NONE,
5540                      sortl_name, (flags.sortloot == *sortl_name)
5541                                     ? MENU_SELECTED : MENU_UNSELECTED);
5542         }
5543         end_menu(tmpwin, "Select loot sorting type:");
5544         n = select_menu(tmpwin, PICK_ONE, &sortl_pick);
5545         if (n > 0) {
5546             char c = sortl_pick[0].item.a_char;
5547
5548             if (n > 1 && c == flags.sortloot)
5549                 c = sortl_pick[1].item.a_char;
5550             flags.sortloot = c;
5551             free((genericptr_t) sortl_pick);
5552         }
5553         destroy_nhwindow(tmpwin);
5554     } else if (!strcmp("align_message", optname)
5555                || !strcmp("align_status", optname)) {
5556         menu_item *window_pick = (menu_item *) 0;
5557         char abuf[BUFSZ];
5558         boolean msg = (*(optname + 6) == 'm');
5559
5560         tmpwin = create_nhwindow(NHW_MENU);
5561         start_menu(tmpwin);
5562         any = zeroany;
5563         any.a_int = ALIGN_TOP;
5564         add_menu(tmpwin, NO_GLYPH, &any, 't', 0, ATR_NONE, "top",
5565                  MENU_UNSELECTED);
5566         any.a_int = ALIGN_BOTTOM;
5567         add_menu(tmpwin, NO_GLYPH, &any, 'b', 0, ATR_NONE, "bottom",
5568                  MENU_UNSELECTED);
5569         any.a_int = ALIGN_LEFT;
5570         add_menu(tmpwin, NO_GLYPH, &any, 'l', 0, ATR_NONE, "left",
5571                  MENU_UNSELECTED);
5572         any.a_int = ALIGN_RIGHT;
5573         add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "right",
5574                  MENU_UNSELECTED);
5575 #if 0 /*JP:T*/
5576         Sprintf(abuf, "Select %s window placement relative to the map:",
5577                 msg ? "message" : "status");
5578 #else
5579         Sprintf(abuf, "%s\83E\83B\83\93\83h\83E\82Ì\83}\83b\83v\82É\91Î\82·\82é\95\\8e¦\88Ê\92u\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F",
5580                 msg ? "\83\81\83b\83Z\81[\83W" : "\8fó\91Ô");
5581 #endif
5582         end_menu(tmpwin, abuf);
5583         if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
5584             if (msg)
5585                 iflags.wc_align_message = window_pick->item.a_int;
5586             else
5587                 iflags.wc_align_status = window_pick->item.a_int;
5588             free((genericptr_t) window_pick);
5589         }
5590         destroy_nhwindow(tmpwin);
5591     } else if (!strcmp("number_pad", optname)) {
5592         static const char *npchoices[] = {
5593 /*JP
5594             " 0 (off)", " 1 (on)", " 2 (on, MSDOS compatible)",
5595 */
5596             "0 (\96³\8cø)", "1 (\97L\8cø)", "2 (\97L\8cø\81CMSDOS\8cÝ\8a·)",
5597 /*JP
5598             " 3 (on, phone-style digit layout)",
5599 */
5600             " 3 (\97L\8cø\81C\93d\98b\8e®\82Ì\90\94\8e\9a\94z\92u)",
5601 /*JP
5602             " 4 (on, phone-style layout, MSDOS compatible)",
5603 */
5604             " 4 (\97L\8cø\81C\93d\98b\8e®\82Ì\94z\92u\81CMSDOS \8cÝ\8a·)",
5605 /*JP
5606             "-1 (off, 'z' to move upper-left, 'y' to zap wands)"
5607 */
5608             "-1 (\96³\8cø\81C'z' \82Å\8d\8fã\82É\88Ú\93®\81C'y' \82Å\8fñ\82ð\90U\82é)"
5609         };
5610         menu_item *mode_pick = (menu_item *) 0;
5611
5612         tmpwin = create_nhwindow(NHW_MENU);
5613         start_menu(tmpwin);
5614         any = zeroany;
5615         for (i = 0; i < SIZE(npchoices); i++) {
5616             any.a_int = i + 1;
5617             add_menu(tmpwin, NO_GLYPH, &any, 'a' + i, 0, ATR_NONE,
5618                      npchoices[i], MENU_UNSELECTED);
5619         }
5620 /*JP
5621         end_menu(tmpwin, "Select number_pad mode:");
5622 */
5623         end_menu(tmpwin, "number_pad\83\82\81[\83h\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
5624         if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
5625             switch (mode_pick->item.a_int - 1) {
5626             case 0:
5627                 iflags.num_pad = FALSE;
5628                 iflags.num_pad_mode = 0;
5629                 break;
5630             case 1:
5631                 iflags.num_pad = TRUE;
5632                 iflags.num_pad_mode = 0;
5633                 break;
5634             case 2:
5635                 iflags.num_pad = TRUE;
5636                 iflags.num_pad_mode = 1;
5637                 break;
5638             case 3:
5639                 iflags.num_pad = TRUE;
5640                 iflags.num_pad_mode = 2;
5641                 break;
5642             case 4:
5643                 iflags.num_pad = TRUE;
5644                 iflags.num_pad_mode = 3;
5645                 break;
5646             /* last menu choice: number_pad == -1 */
5647             case 5:
5648                 iflags.num_pad = FALSE;
5649                 iflags.num_pad_mode = 1;
5650                 break;
5651             }
5652             reset_commands(FALSE);
5653             number_pad(iflags.num_pad ? 1 : 0);
5654             free((genericptr_t) mode_pick);
5655         }
5656         destroy_nhwindow(tmpwin);
5657     } else if (!strcmp("menu_headings", optname)) {
5658 /*JP
5659         int mhattr = query_attr("How to highlight menu headings:");
5660 */
5661         int mhattr = query_attr("\83\81\83j\83\85\81[\83w\83b\83_\82Ì\8b­\92²\95û\96@\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
5662
5663         if (mhattr != -1)
5664             iflags.menu_headings = mhattr;
5665     } else if (!strcmp("msgtype", optname)) {
5666         int opt_idx, nmt, mttyp;
5667         char mtbuf[BUFSZ];
5668
5669  msgtypes_again:
5670         nmt = msgtype_count();
5671 /*JP
5672         opt_idx = handle_add_list_remove("message type", nmt);
5673 */
5674         opt_idx = handle_add_list_remove("\83\81\83b\83Z\81[\83W\8c^", nmt);
5675         if (opt_idx == 3) { /* done */
5676             return TRUE;
5677         } else if (opt_idx == 0) { /* add new */
5678             mtbuf[0] = '\0';
5679 /*JP
5680             getlin("What new message pattern?", mtbuf);
5681 */
5682             getlin("\90V\82µ\82¢\83\81\83b\83Z\81[\83W\83p\83^\81[\83\93\81F", mtbuf);
5683             if (*mtbuf == '\033')
5684                 return TRUE;
5685             if (*mtbuf
5686                 && test_regex_pattern(mtbuf, (const char *)0)
5687                 && (mttyp = query_msgtype()) != -1
5688                 && !msgtype_add(mttyp, mtbuf)) {
5689 /*JP
5690                 pline("Error adding the message type.");
5691 */
5692                 pline("\83\81\83b\83Z\81[\83W\8c^\92Ç\89Á\83G\83\89\81[\81D");
5693                 wait_synch();
5694             }
5695             goto msgtypes_again;
5696         } else { /* list (1) or remove (2) */
5697             int pick_idx, pick_cnt;
5698             int mt_idx;
5699             unsigned ln;
5700             const char *mtype;
5701             menu_item *pick_list = (menu_item *) 0;
5702             struct plinemsg_type *tmp = plinemsg_types;
5703
5704             tmpwin = create_nhwindow(NHW_MENU);
5705             start_menu(tmpwin);
5706             any = zeroany;
5707             mt_idx = 0;
5708             while (tmp) {
5709                 mtype = msgtype2name(tmp->msgtype);
5710                 any.a_int = ++mt_idx;
5711                 Sprintf(mtbuf, "%-5s \"", mtype);
5712                 ln = sizeof mtbuf - strlen(mtbuf) - sizeof "\"";
5713                 if (strlen(tmp->pattern) > ln)
5714                     Strcat(strncat(mtbuf, tmp->pattern, ln - 3), "...\"");
5715                 else
5716                     Strcat(strcat(mtbuf, tmp->pattern), "\"");
5717                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mtbuf,
5718                          MENU_UNSELECTED);
5719                 tmp = tmp->next;
5720             }
5721 #if 0 /*JP:T*/
5722             Sprintf(mtbuf, "%s message types",
5723                     (opt_idx == 1) ? "List of" : "Remove which");
5724 #else
5725             Strcpy(mtbuf, (opt_idx == 1) ?
5726                     "\83\81\83b\83Z\81[\83W\8c^\88ê\97\97" : "\8dí\8f\9c\82·\82é\83\81\83b\83Z\81[\83W\8c^");
5727 #endif
5728             end_menu(tmpwin, mtbuf);
5729             pick_cnt = select_menu(tmpwin,
5730                                    (opt_idx == 1) ? PICK_NONE : PICK_ANY,
5731                                    &pick_list);
5732             if (pick_cnt > 0) {
5733                 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
5734                     free_one_msgtype(pick_list[pick_idx].item.a_int - 1
5735                                            - pick_idx);
5736                 free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
5737             }
5738             destroy_nhwindow(tmpwin);
5739             if (pick_cnt >= 0)
5740                 goto msgtypes_again;
5741         }
5742     } else if (!strcmp("menu_colors", optname)) {
5743         int opt_idx, nmc, mcclr, mcattr;
5744         char mcbuf[BUFSZ];
5745
5746  menucolors_again:
5747         nmc = count_menucolors();
5748 /*JP
5749         opt_idx = handle_add_list_remove("menucolor", nmc);
5750 */
5751         opt_idx = handle_add_list_remove("\83\81\83j\83\85\81[\90F", nmc);
5752         if (opt_idx == 3) { /* done */
5753  menucolors_done:
5754             /* in case we've made a change which impacts current persistent
5755                inventory window; we don't track whether an actual changed
5756                occurred, so just assume there was one and that it matters;
5757                if we're wrong, a redundant update is cheap... */
5758             if (iflags.use_menu_color)
5759                 update_inventory();
5760
5761             /* menu colors aren't being used; if any are defined, remind
5762                player how to use them */
5763             else if (nmc > 0)
5764                 pline(
5765     "To have menu colors become active, toggle 'menucolors' option to True.");
5766             return TRUE;
5767
5768         } else if (opt_idx == 0) { /* add new */
5769             mcbuf[0] = '\0';
5770 /*JP
5771             getlin("What new menucolor pattern?", mcbuf);
5772 */
5773             getlin("\90V\82µ\82¢\83\81\83j\83\85\81[\90F\83p\83^\81[\83\93\81F", mcbuf);
5774             if (*mcbuf == '\033')
5775                 goto menucolors_done;
5776             if (*mcbuf
5777                 && test_regex_pattern(mcbuf, (const char *)0)
5778                 && (mcclr = query_color((char *) 0)) != -1
5779                 && (mcattr = query_attr((char *) 0)) != -1
5780                 && !add_menu_coloring_parsed(mcbuf, mcclr, mcattr)) {
5781 /*JP
5782                 pline("Error adding the menu color.");
5783 */
5784                 pline("\83\81\83j\83\85\81[\90F\92Ç\89Á\83G\83\89\81[\81D");
5785                 wait_synch();
5786             }
5787             goto menucolors_again;
5788
5789         } else { /* list (1) or remove (2) */
5790             int pick_idx, pick_cnt;
5791             int mc_idx;
5792             unsigned ln;
5793             const char *sattr, *sclr;
5794             menu_item *pick_list = (menu_item *) 0;
5795             struct menucoloring *tmp = menu_colorings;
5796             char clrbuf[QBUFSZ];
5797
5798             tmpwin = create_nhwindow(NHW_MENU);
5799             start_menu(tmpwin);
5800             any = zeroany;
5801             mc_idx = 0;
5802             while (tmp) {
5803                 sattr = attr2attrname(tmp->attr);
5804                 sclr = strcpy(clrbuf, clr2colorname(tmp->color));
5805                 (void) strNsubst(clrbuf, " ", "-", 0);
5806                 any.a_int = ++mc_idx;
5807                 /* construct suffix */
5808                 Sprintf(buf, "\"\"=%s%s%s", sclr,
5809                         (tmp->attr != ATR_NONE) ? "&" : "",
5810                         (tmp->attr != ATR_NONE) ? sattr : "");
5811                 /* now main string */
5812                 ln = sizeof buf - strlen(buf) - 1; /* length available */
5813                 Strcpy(mcbuf, "\"");
5814                 if (strlen(tmp->origstr) > ln)
5815                     Strcat(strncat(mcbuf, tmp->origstr, ln - 3), "...");
5816                 else
5817                     Strcat(mcbuf, tmp->origstr);
5818                 /* combine main string and suffix */
5819                 Strcat(mcbuf, &buf[1]); /* skip buf[]'s initial quote */
5820                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mcbuf,
5821                          MENU_UNSELECTED);
5822                 tmp = tmp->next;
5823             }
5824 #if 0 /*JP:T*/
5825             Sprintf(mcbuf, "%s menu colors",
5826                     (opt_idx == 1) ? "List of" : "Remove which");
5827 #else
5828             Strcpy(mcbuf, (opt_idx == 1) ?
5829                     "\83\81\83j\83\85\81[\90F\88ê\97\97" : "\8dí\8f\9c\82·\82é\83\81\83j\83\85\81[\90F");
5830 #endif
5831             end_menu(tmpwin, mcbuf);
5832             pick_cnt = select_menu(tmpwin,
5833                                    (opt_idx == 1) ? PICK_NONE : PICK_ANY,
5834                                    &pick_list);
5835             if (pick_cnt > 0) {
5836                 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
5837                     free_one_menu_coloring(pick_list[pick_idx].item.a_int - 1
5838                                            - pick_idx);
5839                 free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
5840             }
5841             destroy_nhwindow(tmpwin);
5842             if (pick_cnt >= 0)
5843                 goto menucolors_again;
5844         }
5845     } else if (!strcmp("autopickup_exception", optname)) {
5846         int opt_idx, numapes = 0;
5847         char apebuf[2 + BUFSZ]; /* so &apebuf[1] is BUFSZ long for getlin() */
5848         struct autopickup_exception *ape;
5849
5850  ape_again:
5851         numapes = count_apes();
5852 /*JP
5853         opt_idx = handle_add_list_remove("autopickup exception", numapes);
5854 */
5855         opt_idx = handle_add_list_remove("\8e©\93®\8fE\82¢\97á\8aO", numapes);
5856         if (opt_idx == 3) { /* done */
5857             return TRUE;
5858         } else if (opt_idx == 0) { /* add new */
5859             /* EDIT_GETLIN:  assume user doesn't user want previous
5860                exception used as default input string for this one... */
5861             apebuf[0] = apebuf[1] = '\0';
5862 /*JP
5863             getlin("What new autopickup exception pattern?", &apebuf[1]);
5864 */
5865             getlin("\90V\82µ\82¢\8e©\93®\8fE\82¢\97á\8aO\82Ì\83p\83^\81[\83\93\82ð\93ü\97Í\82µ\82Ä\82­\82¾\82³\82¢\81F", &apebuf[1]);
5866             mungspaces(&apebuf[1]); /* regularize whitespace */
5867             if (apebuf[1] == '\033')
5868                 return TRUE;
5869             if (apebuf[1]) {
5870                 apebuf[0] = '\"';
5871                 /* guarantee room for \" prefix and \"\0 suffix;
5872                    -2 is good enough for apebuf[] but -3 makes
5873                    sure the whole thing fits within normal BUFSZ */
5874                 apebuf[sizeof apebuf - 2] = '\0';
5875                 Strcat(apebuf, "\"");
5876                 add_autopickup_exception(apebuf);
5877             }
5878             goto ape_again;
5879         } else { /* list (1) or remove (2) */
5880             int pick_idx, pick_cnt;
5881             menu_item *pick_list = (menu_item *) 0;
5882
5883             tmpwin = create_nhwindow(NHW_MENU);
5884             start_menu(tmpwin);
5885             if (numapes) {
5886                 ape = apelist;
5887                 any = zeroany;
5888 #if 0 /*JP:T*/
5889                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
5890                          "Always pickup '<'; never pickup '>'",
5891                          MENU_UNSELECTED);
5892 #else
5893                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
5894                          "\8fí\82É\8fE\82¤ '<'; \8fí\82É\8fE\82í\82È\82¢ '>'",
5895                          MENU_UNSELECTED);
5896 #endif
5897                 for (i = 0; i < numapes && ape; i++) {
5898                     any.a_void = (opt_idx == 1) ? 0 : ape;
5899                     /* length of pattern plus quotes (plus '<'/'>') is
5900                        less than BUFSZ */
5901                     Sprintf(apebuf, "\"%c%s\"", ape->grab ? '<' : '>',
5902                             ape->pattern);
5903                     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, apebuf,
5904                              MENU_UNSELECTED);
5905                     ape = ape->next;
5906                 }
5907             }
5908 #if 0 /*JP*/
5909             Sprintf(apebuf, "%s autopickup exceptions",
5910                     (opt_idx == 1) ? "List of" : "Remove which");
5911 #else
5912             Sprintf(apebuf, "%s\8e©\93®\8fE\82¢\97á\8aO%s",
5913                     (opt_idx == 1) ? "" : "\82Ç\82Ì",
5914                     (opt_idx == 1) ? "\82Ì\88ê\97\97" : "\82ð\8dí\8f\9c\82µ\82Ü\82·\82©\81H");
5915 #endif
5916             end_menu(tmpwin, apebuf);
5917             pick_cnt = select_menu(tmpwin,
5918                                    (opt_idx == 1) ? PICK_NONE : PICK_ANY,
5919                                    &pick_list);
5920             if (pick_cnt > 0) {
5921                 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
5922                     remove_autopickup_exception(
5923                                          (struct autopickup_exception *)
5924                                              pick_list[pick_idx].item.a_void);
5925                 free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
5926             }
5927             destroy_nhwindow(tmpwin);
5928             if (pick_cnt >= 0)
5929                 goto ape_again;
5930         }
5931     } else if (!strcmp("symset", optname)
5932                || !strcmp("roguesymset", optname)) {
5933         menu_item *symset_pick = (menu_item *) 0;
5934         boolean rogueflag = (*optname == 'r'),
5935                 ready_to_switch = FALSE,
5936                 nothing_to_do = FALSE;
5937         char *symset_name, fmtstr[20];
5938         struct symsetentry *sl;
5939         int res, which_set, setcount = 0, chosen = -2, defindx = 0;
5940
5941         which_set = rogueflag ? ROGUESET : PRIMARY;
5942         symset_list = (struct symsetentry *) 0;
5943         /* clear symset[].name as a flag to read_sym_file() to build list */
5944         symset_name = symset[which_set].name;
5945         symset[which_set].name = (char *) 0;
5946
5947         res = read_sym_file(which_set);
5948         /* put symset name back */
5949         symset[which_set].name = symset_name;
5950
5951         if (res && symset_list) {
5952             int thissize,
5953                 biggest = (int) (sizeof "Default Symbols" - sizeof ""),
5954                 big_desc = 0;
5955
5956             for (sl = symset_list; sl; sl = sl->next) {
5957                 /* check restrictions */
5958                 if (rogueflag ? sl->primary : sl->rogue)
5959                     continue;
5960 #ifndef MAC_GRAPHICS_ENV
5961                 if (sl->handling == H_MAC)
5962                     continue;
5963 #endif
5964
5965                 setcount++;
5966                 /* find biggest name */
5967                 thissize = sl->name ? (int) strlen(sl->name) : 0;
5968                 if (thissize > biggest)
5969                     biggest = thissize;
5970                 thissize = sl->desc ? (int) strlen(sl->desc) : 0;
5971                 if (thissize > big_desc)
5972                     big_desc = thissize;
5973             }
5974             if (!setcount) {
5975 #if 0 /*JP:T*/
5976                 pline("There are no appropriate %s symbol sets available.",
5977                       rogueflag ? "rogue level" : "primary");
5978 #else
5979                 pline("\93K\90Ø\82È%s\83V\83\93\83{\83\8b\90Ý\92è\82ª\82 \82è\82Ü\82¹\82ñ\81D",
5980                       rogueflag ? "rogue\83\8c\83x\83\8b" : "\97D\90æ");
5981 #endif
5982                 return TRUE;
5983             }
5984
5985             Sprintf(fmtstr, "%%-%ds %%s", biggest + 2);
5986             tmpwin = create_nhwindow(NHW_MENU);
5987             start_menu(tmpwin);
5988             any = zeroany;
5989             any.a_int = 1; /* -1 + 2 [see 'if (sl->name) {' below]*/
5990             if (!symset_name)
5991                 defindx = any.a_int;
5992             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
5993                      "Default Symbols",
5994                      (any.a_int == defindx) ? MENU_SELECTED
5995                                             : MENU_UNSELECTED);
5996
5997             for (sl = symset_list; sl; sl = sl->next) {
5998                 /* check restrictions */
5999                 if (rogueflag ? sl->primary : sl->rogue)
6000                     continue;
6001 #ifndef MAC_GRAPHICS_ENV
6002                 if (sl->handling == H_MAC)
6003                     continue;
6004 #endif
6005                 if (sl->name) {
6006                     /* +2: sl->idx runs from 0 to N-1 for N symsets;
6007                        +1 because Defaults are implicitly in slot [0];
6008                        +1 again so that valid data is never 0 */
6009                     any.a_int = sl->idx + 2;
6010                     if (symset_name && !strcmpi(sl->name, symset_name))
6011                         defindx = any.a_int;
6012                     Sprintf(buf, fmtstr, sl->name, sl->desc ? sl->desc : "");
6013                     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
6014                              (any.a_int == defindx) ? MENU_SELECTED
6015                                                     : MENU_UNSELECTED);
6016                 }
6017             }
6018 #if 0 /*JP:T*/
6019             Sprintf(buf, "Select %ssymbol set:",
6020                     rogueflag ? "rogue level " : "");
6021 #else
6022             Sprintf(buf, "%s\83V\83\93\83{\83\8b\90Ý\92è\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F",
6023                     rogueflag ? "rogue\83\8c\83x\83\8b" : "");
6024 #endif
6025             end_menu(tmpwin, buf);
6026             n = select_menu(tmpwin, PICK_ONE, &symset_pick);
6027             if (n > 0) {
6028                 chosen = symset_pick[0].item.a_int;
6029                 /* if picking non-preselected entry yields 2, make sure
6030                    that we're going with the non-preselected one */
6031                 if (n == 2 && chosen == defindx)
6032                     chosen = symset_pick[1].item.a_int;
6033                 chosen -= 2; /* convert menu index to symset index;
6034                               * "Default symbols" have index -1 */
6035                 free((genericptr_t) symset_pick);
6036             } else if (n == 0 && defindx > 0) {
6037                 chosen = defindx - 2;
6038             }
6039             destroy_nhwindow(tmpwin);
6040
6041             if (chosen > -1) {
6042                 /* chose an actual symset name from file */
6043                 for (sl = symset_list; sl; sl = sl->next)
6044                     if (sl->idx == chosen)
6045                         break;
6046                 if (sl) {
6047                     /* free the now stale attributes */
6048                     clear_symsetentry(which_set, TRUE);
6049
6050                     /* transfer only the name of the symbol set */
6051                     symset[which_set].name = dupstr(sl->name);
6052                     ready_to_switch = TRUE;
6053                 }
6054             } else if (chosen == -1) {
6055                 /* explicit selection of defaults */
6056                 /* free the now stale symset attributes */
6057                 clear_symsetentry(which_set, TRUE);
6058             } else
6059                 nothing_to_do = TRUE;
6060         } else if (!res) {
6061             /* The symbols file could not be accessed */
6062 /*JP
6063             pline("Unable to access \"%s\" file.", SYMBOLS);
6064 */
6065             pline("\"%s\"\83t\83@\83C\83\8b\82É\83A\83N\83Z\83X\82Å\82«\82Ü\82¹\82ñ\81D", SYMBOLS);
6066             return TRUE;
6067         } else if (!symset_list) {
6068             /* The symbols file was empty */
6069 /*JP
6070             pline("There were no symbol sets found in \"%s\".", SYMBOLS);
6071 */
6072             pline("\"%s\"\82É\83V\83\93\83{\83\8b\90Ý\92è\82ª\82 \82è\82Ü\82¹\82ñ\81D", SYMBOLS);
6073             return TRUE;
6074         }
6075
6076         /* clean up */
6077         while ((sl = symset_list) != 0) {
6078             symset_list = sl->next;
6079             if (sl->name)
6080                 free((genericptr_t) sl->name), sl->name = (char *) 0;
6081             if (sl->desc)
6082                 free((genericptr_t) sl->desc), sl->desc = (char *) 0;
6083             free((genericptr_t) sl);
6084         }
6085
6086         if (nothing_to_do)
6087             return TRUE;
6088
6089         /* Set default symbols and clear the handling value */
6090         if (rogueflag)
6091             init_rogue_symbols();
6092         else
6093             init_primary_symbols();
6094
6095         if (symset[which_set].name) {
6096             /* non-default symbols */
6097             if (read_sym_file(which_set)) {
6098                 ready_to_switch = TRUE;
6099             } else {
6100                 clear_symsetentry(which_set, TRUE);
6101                 return TRUE;
6102             }
6103         }
6104
6105         if (ready_to_switch)
6106             switch_symbols(TRUE);
6107
6108         if (Is_rogue_level(&u.uz)) {
6109             if (rogueflag)
6110                 assign_graphics(ROGUESET);
6111         } else if (!rogueflag)
6112             assign_graphics(PRIMARY);
6113         preference_update("symset");
6114         need_redraw = TRUE;
6115
6116     } else {
6117         /* didn't match any of the special options */
6118         return FALSE;
6119     }
6120     return TRUE;
6121 }
6122
6123 #define rolestring(val, array, field) \
6124     ((val >= 0) ? array[val].field : (val == ROLE_RANDOM) ? randomrole : none)
6125
6126 /* This is ugly. We have all the option names in the compopt[] array,
6127    but we need to look at each option individually to get the value. */
6128 STATIC_OVL const char *
6129 get_compopt_value(optname, buf)
6130 const char *optname;
6131 char *buf;
6132 {
6133 #if 0 /*JP:T*/
6134     static const char none[] = "(none)", randomrole[] = "random",
6135                       to_be_done[] = "(to be done)",
6136                       defopt[] = "default", defbrief[] = "def";
6137 #else
6138     static const char none[] = "(\82È\82µ)", randomrole[] = "\83\89\83\93\83_\83\80",
6139                       to_be_done[] = "(\96¢\90Ý\92è)",
6140                       defopt[] = "\83f\83t\83H\83\8b\83g", defbrief[] = "def";
6141 #endif
6142     char ocl[MAXOCLASSES + 1];
6143     int i;
6144
6145     buf[0] = '\0';
6146     if (!strcmp(optname, "align_message")
6147         || !strcmp(optname, "align_status")) {
6148         int which = !strcmp(optname, "align_status") ? iflags.wc_align_status
6149                                                      : iflags.wc_align_message;
6150 #if 0 /*JP:T*/
6151         Sprintf(buf, "%s",
6152                 (which == ALIGN_TOP) ? "top"
6153                 : (which == ALIGN_LEFT) ? "left"
6154                   : (which == ALIGN_BOTTOM) ? "bottom"
6155                     : (which == ALIGN_RIGHT) ? "right"
6156                       : defopt);
6157 #else
6158         Sprintf(buf, "%s",
6159                 (which == ALIGN_TOP) ? "\8fã\91¤"
6160                 : (which == ALIGN_LEFT) ? "\8d\91¤"
6161                   : (which == ALIGN_BOTTOM) ? "\89º\91¤"
6162                     : (which == ALIGN_RIGHT) ? "\89E\91¤"
6163                       : defopt);
6164 #endif
6165     } else if (!strcmp(optname, "align"))
6166 #if 0 /*JP*/
6167         Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj));
6168 #else
6169         Sprintf(buf, "%s", rolestring(flags.initalign, aligns, noun));
6170 #endif
6171 #ifdef WIN32
6172     else if (!strcmp(optname, "altkeyhandler"))
6173         Sprintf(buf, "%s",
6174 /*JP
6175                 iflags.altkeyhandler[0] ? iflags.altkeyhandler : "default");
6176 */
6177                 iflags.altkeyhandler[0] ? iflags.altkeyhandler : defopt);
6178 #endif
6179 #ifdef BACKWARD_COMPAT
6180     else if (!strcmp(optname, "boulder"))
6181         Sprintf(buf, "%c",
6182                 ov_primary_syms[SYM_BOULDER + SYM_OFF_X]
6183                     ? ov_primary_syms[SYM_BOULDER + SYM_OFF_X]
6184                     : showsyms[(int) objects[BOULDER].oc_class + SYM_OFF_O]);
6185 #endif
6186     else if (!strcmp(optname, "catname"))
6187         Sprintf(buf, "%s", catname[0] ? catname : none);
6188     else if (!strcmp(optname, "disclose"))
6189         for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
6190             if (i)
6191                 (void) strkitten(buf, ' ');
6192             (void) strkitten(buf, flags.end_disclose[i]);
6193             (void) strkitten(buf, disclosure_options[i]);
6194         }
6195     else if (!strcmp(optname, "dogname"))
6196         Sprintf(buf, "%s", dogname[0] ? dogname : none);
6197     else if (!strcmp(optname, "dungeon"))
6198         Sprintf(buf, "%s", to_be_done);
6199     else if (!strcmp(optname, "effects"))
6200         Sprintf(buf, "%s", to_be_done);
6201     else if (!strcmp(optname, "font_map"))
6202         Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt);
6203     else if (!strcmp(optname, "font_message"))
6204         Sprintf(buf, "%s",
6205                 iflags.wc_font_message ? iflags.wc_font_message : defopt);
6206     else if (!strcmp(optname, "font_status"))
6207         Sprintf(buf, "%s",
6208                 iflags.wc_font_status ? iflags.wc_font_status : defopt);
6209     else if (!strcmp(optname, "font_menu"))
6210         Sprintf(buf, "%s",
6211                 iflags.wc_font_menu ? iflags.wc_font_menu : defopt);
6212     else if (!strcmp(optname, "font_text"))
6213         Sprintf(buf, "%s",
6214                 iflags.wc_font_text ? iflags.wc_font_text : defopt);
6215     else if (!strcmp(optname, "font_size_map")) {
6216         if (iflags.wc_fontsiz_map)
6217             Sprintf(buf, "%d", iflags.wc_fontsiz_map);
6218         else
6219             Strcpy(buf, defopt);
6220     } else if (!strcmp(optname, "font_size_message")) {
6221         if (iflags.wc_fontsiz_message)
6222             Sprintf(buf, "%d", iflags.wc_fontsiz_message);
6223         else
6224             Strcpy(buf, defopt);
6225     } else if (!strcmp(optname, "font_size_status")) {
6226         if (iflags.wc_fontsiz_status)
6227             Sprintf(buf, "%d", iflags.wc_fontsiz_status);
6228         else
6229             Strcpy(buf, defopt);
6230     } else if (!strcmp(optname, "font_size_menu")) {
6231         if (iflags.wc_fontsiz_menu)
6232             Sprintf(buf, "%d", iflags.wc_fontsiz_menu);
6233         else
6234             Strcpy(buf, defopt);
6235     } else if (!strcmp(optname, "font_size_text")) {
6236         if (iflags.wc_fontsiz_text)
6237             Sprintf(buf, "%d", iflags.wc_fontsiz_text);
6238         else
6239             Strcpy(buf, defopt);
6240     } else if (!strcmp(optname, "fruit"))
6241         Sprintf(buf, "%s", pl_fruit);
6242     else if (!strcmp(optname, "gender"))
6243         Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj));
6244     else if (!strcmp(optname, "horsename"))
6245         Sprintf(buf, "%s", horsename[0] ? horsename : none);
6246     else if (!strcmp(optname, "map_mode")) {
6247         i = iflags.wc_map_mode;
6248         Sprintf(buf, "%s",
6249                 (i == MAP_MODE_TILES) ? "tiles"
6250                 : (i == MAP_MODE_ASCII4x6) ? "ascii4x6"
6251                   : (i == MAP_MODE_ASCII6x8) ? "ascii6x8"
6252                     : (i == MAP_MODE_ASCII8x8) ? "ascii8x8"
6253                       : (i == MAP_MODE_ASCII16x8) ? "ascii16x8"
6254                         : (i == MAP_MODE_ASCII7x12) ? "ascii7x12"
6255                           : (i == MAP_MODE_ASCII8x12) ? "ascii8x12"
6256                             : (i == MAP_MODE_ASCII16x12) ? "ascii16x12"
6257                               : (i == MAP_MODE_ASCII12x16) ? "ascii12x16"
6258                                 : (i == MAP_MODE_ASCII10x18) ? "ascii10x18"
6259                                   : (i == MAP_MODE_ASCII_FIT_TO_SCREEN)
6260                                     ? "fit_to_screen"
6261                                     : defopt);
6262     } else if (!strcmp(optname, "menustyle"))
6263         Sprintf(buf, "%s", menutype[(int) flags.menu_style]);
6264     else if (!strcmp(optname, "menu_deselect_all"))
6265         Sprintf(buf, "%s", to_be_done);
6266     else if (!strcmp(optname, "menu_deselect_page"))
6267         Sprintf(buf, "%s", to_be_done);
6268     else if (!strcmp(optname, "menu_first_page"))
6269         Sprintf(buf, "%s", to_be_done);
6270     else if (!strcmp(optname, "menu_invert_all"))
6271         Sprintf(buf, "%s", to_be_done);
6272     else if (!strcmp(optname, "menu_headings"))
6273         Sprintf(buf, "%s", attr2attrname(iflags.menu_headings));
6274     else if (!strcmp(optname, "menu_invert_page"))
6275         Sprintf(buf, "%s", to_be_done);
6276     else if (!strcmp(optname, "menu_last_page"))
6277         Sprintf(buf, "%s", to_be_done);
6278     else if (!strcmp(optname, "menu_next_page"))
6279         Sprintf(buf, "%s", to_be_done);
6280     else if (!strcmp(optname, "menu_previous_page"))
6281         Sprintf(buf, "%s", to_be_done);
6282     else if (!strcmp(optname, "menu_search"))
6283         Sprintf(buf, "%s", to_be_done);
6284     else if (!strcmp(optname, "menu_select_all"))
6285         Sprintf(buf, "%s", to_be_done);
6286     else if (!strcmp(optname, "menu_select_page"))
6287         Sprintf(buf, "%s", to_be_done);
6288     else if (!strcmp(optname, "monsters")) {
6289         Sprintf(buf, "%s", to_be_done);
6290     } else if (!strcmp(optname, "msghistory")) {
6291         Sprintf(buf, "%u", iflags.msg_history);
6292 #ifdef TTY_GRAPHICS
6293     } else if (!strcmp(optname, "msg_window")) {
6294         Sprintf(buf, "%s", (iflags.prevmsg_window == 's') ? "single"
6295                            : (iflags.prevmsg_window == 'c') ? "combination"
6296                              : (iflags.prevmsg_window == 'f') ? "full"
6297                                : "reversed");
6298 #endif
6299     } else if (!strcmp(optname, "name")) {
6300         Sprintf(buf, "%s", plname);
6301     } else if (!strcmp(optname, "mouse_support")) {
6302 #ifdef WIN32
6303 #define MOUSEFIX1 ", QuickEdit off"
6304 #define MOUSEFIX2 ", QuickEdit unchanged"
6305 #else
6306 #define MOUSEFIX1 ", O/S adjusted"
6307 #define MOUSEFIX2 ", O/S unchanged"
6308 #endif
6309         static const char *mousemodes[][2] = {
6310             { "0=off", "" },
6311             { "1=on",  MOUSEFIX1 },
6312             { "2=on",  MOUSEFIX2 },
6313         };
6314 #undef MOUSEFIX1
6315 #undef MOUSEFIX2
6316         int ms = iflags.wc_mouse_support;
6317
6318         if (ms >= 0 && ms <= 2)
6319             Sprintf(buf, "%s%s", mousemodes[ms][0], mousemodes[ms][1]);
6320     } else if (!strcmp(optname, "number_pad")) {
6321         static const char *numpadmodes[] = {
6322 /*JP
6323             "0=off", "1=on", "2=on, MSDOS compatible",
6324 */
6325             "0=\96³\8cø", "1=\97L\8cø", "2=\97L\8cø\81CDOS\8cÝ\8a·",
6326 /*JP
6327             "3=on, phone-style layout",
6328 */
6329             "3=\97L\8cø\81C\93d\98b\8e®\82Ì\90\94\8e\9a\94z\92u",
6330 /*JP
6331             "4=on, phone layout, MSDOS compatible",
6332 */
6333             "4=\97L\8cø\81C\93d\98b\8e®\82Ì\94z\92u\81CMSDOS \8cÝ\8a·",
6334 #if 0 /*JP:T*/
6335             "-1=off, y & z swapped", /*[5]*/
6336 #else
6337             "-1=\96³\8cø\81Cy\82Æz\82ð\93ü\82ê\91Ö\82¦", /*[5]*/
6338 #endif
6339         };
6340         int indx = Cmd.num_pad
6341                        ? (Cmd.phone_layout ? (Cmd.pcHack_compat ? 4 : 3)
6342                                            : (Cmd.pcHack_compat ? 2 : 1))
6343                        : Cmd.swap_yz ? 5 : 0;
6344
6345         Strcpy(buf, numpadmodes[indx]);
6346     } else if (!strcmp(optname, "objects")) {
6347         Sprintf(buf, "%s", to_be_done);
6348     } else if (!strcmp(optname, "packorder")) {
6349         oc_to_str(flags.inv_order, ocl);
6350         Sprintf(buf, "%s", ocl);
6351 #ifdef CHANGE_COLOR
6352     } else if (!strcmp(optname, "palette")) {
6353         Sprintf(buf, "%s", get_color_string());
6354 #endif
6355     } else if (!strcmp(optname, "paranoid_confirmation")) {
6356         char tmpbuf[QBUFSZ];
6357
6358         tmpbuf[0] = '\0';
6359         for (i = 0; paranoia[i].flagmask != 0; ++i)
6360             if (flags.paranoia_bits & paranoia[i].flagmask)
6361                 Sprintf(eos(tmpbuf), " %s", paranoia[i].argname);
6362         Strcpy(buf, tmpbuf[0] ? &tmpbuf[1] : "none");
6363     } else if (!strcmp(optname, "petattr")) {
6364 #ifdef CURSES_GRAPHICS
6365         if (WINDOWPORT("curses")) {
6366             char tmpbuf[QBUFSZ];
6367
6368             Strcpy(buf, curses_fmt_attrs(tmpbuf));
6369         } else
6370 #endif
6371         if (iflags.wc2_petattr != 0)
6372             Sprintf(buf, "0x%08x", iflags.wc2_petattr);
6373         else
6374             Strcpy(buf, defopt);
6375     } else if (!strcmp(optname, "pettype")) {
6376 #if 0 /*JP:T*/
6377         Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat"
6378                            : (preferred_pet == 'd') ? "dog"
6379                              : (preferred_pet == 'h') ? "horse"
6380                                : (preferred_pet == 'n') ? "none"
6381                                  : "random");
6382 #else
6383         Sprintf(buf, "%s", (preferred_pet == 'c') ? "\94L"
6384                            : (preferred_pet == 'd') ? "\8c¢"
6385                              : (preferred_pet == 'h') ? "\94n"
6386                                : (preferred_pet == 'n') ? "\82È\82µ"
6387                                  : "\83\89\83\93\83_\83\80");
6388 #endif
6389     } else if (!strcmp(optname, "pickup_burden")) {
6390         Sprintf(buf, "%s", burdentype[flags.pickup_burden]);
6391     } else if (!strcmp(optname, "pickup_types")) {
6392         oc_to_str(flags.pickup_types, ocl);
6393         Sprintf(buf, "%s", ocl[0] ? ocl : "all");
6394     } else if (!strcmp(optname, "pile_limit")) {
6395         Sprintf(buf, "%d", flags.pile_limit);
6396     } else if (!strcmp(optname, "playmode")) {
6397         Strcpy(buf, wizard ? "debug" : discover ? "explore" : "normal");
6398     } else if (!strcmp(optname, "race")) {
6399         Sprintf(buf, "%s", rolestring(flags.initrace, races, noun));
6400     } else if (!strcmp(optname, "roguesymset")) {
6401         Sprintf(buf, "%s",
6402                 symset[ROGUESET].name ? symset[ROGUESET].name : "default");
6403         if (currentgraphics == ROGUESET && symset[ROGUESET].name)
6404             Strcat(buf, ", active");
6405     } else if (!strcmp(optname, "role")) {
6406         Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m));
6407     } else if (!strcmp(optname, "runmode")) {
6408         Sprintf(buf, "%s", runmodes[flags.runmode]);
6409     } else if (!strcmp(optname, "whatis_coord")) {
6410         Sprintf(buf, "%s",
6411                 (iflags.getpos_coords == GPCOORDS_MAP) ? "map"
6412                 : (iflags.getpos_coords == GPCOORDS_COMPASS) ? "compass"
6413                 : (iflags.getpos_coords == GPCOORDS_COMFULL) ? "full compass"
6414                 : (iflags.getpos_coords == GPCOORDS_SCREEN) ? "screen"
6415                 : "none");
6416     } else if (!strcmp(optname, "whatis_filter")) {
6417         Sprintf(buf, "%s",
6418                 (iflags.getloc_filter == GFILTER_VIEW) ? "view"
6419                 : (iflags.getloc_filter == GFILTER_AREA) ? "area"
6420                 : "none");
6421     } else if (!strcmp(optname, "scores")) {
6422         Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around,
6423                 flags.end_own ? "/own" : "");
6424     } else if (!strcmp(optname, "scroll_amount")) {
6425         if (iflags.wc_scroll_amount)
6426             Sprintf(buf, "%d", iflags.wc_scroll_amount);
6427         else
6428             Strcpy(buf, defopt);
6429     } else if (!strcmp(optname, "scroll_margin")) {
6430         if (iflags.wc_scroll_margin)
6431             Sprintf(buf, "%d", iflags.wc_scroll_margin);
6432         else
6433             Strcpy(buf, defopt);
6434     } else if (!strcmp(optname, "sortloot")) {
6435         for (i = 0; i < SIZE(sortltype); i++)
6436             if (flags.sortloot == sortltype[i][0]) {
6437                 Strcpy(buf, sortltype[i]);
6438                 break;
6439             }
6440     } else if (!strcmp(optname, "player_selection")) {
6441 #if 0 /*JP:T*/
6442         Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
6443 #else
6444         Sprintf(buf, "%s\93ü\97Í", iflags.wc_player_selection ? "\83v\83\8d\83\93\83v\83g" : "\83_\83C\83A\83\8d\83O");
6445 #endif
6446 #ifdef MSDOS
6447     } else if (!strcmp(optname, "soundcard")) {
6448         Sprintf(buf, "%s", to_be_done);
6449 #endif
6450 #ifdef STATUS_HILITES
6451     } else if (!strcmp("statushilites", optname)) {
6452         if (!iflags.hilite_delta)
6453             Strcpy(buf, "0 (off: don't highlight status fields)");
6454         else
6455             Sprintf(buf, "%ld (on: highlight status for %ld turns)",
6456                     iflags.hilite_delta, iflags.hilite_delta);
6457 #endif
6458     } else if (!strcmp(optname,"statuslines")) {
6459         if (wc2_supported(optname))
6460             Strcpy(buf, (iflags.wc2_statuslines < 3) ? "2" : "3");
6461         /* else default to "unknown" */
6462     } else if (!strcmp(optname, "suppress_alert")) {
6463         if (flags.suppress_alert == 0L)
6464             Strcpy(buf, none);
6465         else
6466             Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
6467                     FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
6468     } else if (!strcmp(optname, "symset")) {
6469         Sprintf(buf, "%s",
6470                 symset[PRIMARY].name ? symset[PRIMARY].name : "default");
6471         if (currentgraphics == PRIMARY && symset[PRIMARY].name)
6472             Strcat(buf, ", active");
6473     } else if (!strcmp(optname, "term_cols")) {
6474         if (iflags.wc2_term_cols)
6475             Sprintf(buf, "%d", iflags.wc2_term_cols);
6476         else
6477             Strcpy(buf, defopt);
6478     } else if (!strcmp(optname, "term_rows")) {
6479         if (iflags.wc2_term_rows)
6480             Sprintf(buf, "%d", iflags.wc2_term_rows);
6481         else
6482             Strcpy(buf, defopt);
6483     } else if (!strcmp(optname, "tile_file")) {
6484         Sprintf(buf, "%s",
6485                 iflags.wc_tile_file ? iflags.wc_tile_file : defopt);
6486     } else if (!strcmp(optname, "tile_height")) {
6487         if (iflags.wc_tile_height)
6488             Sprintf(buf, "%d", iflags.wc_tile_height);
6489         else
6490             Strcpy(buf, defopt);
6491     } else if (!strcmp(optname, "tile_width")) {
6492         if (iflags.wc_tile_width)
6493             Sprintf(buf, "%d", iflags.wc_tile_width);
6494         else
6495             Strcpy(buf, defopt);
6496     } else if (!strcmp(optname, "traps")) {
6497         Sprintf(buf, "%s", to_be_done);
6498     } else if (!strcmp(optname, "vary_msgcount")) {
6499         if (iflags.wc_vary_msgcount)
6500             Sprintf(buf, "%d", iflags.wc_vary_msgcount);
6501         else
6502             Strcpy(buf, defopt);
6503 #ifdef MSDOS
6504     } else if (!strcmp(optname, "video")) {
6505         Sprintf(buf, "%s", to_be_done);
6506 #endif
6507 #ifdef VIDEOSHADES
6508     } else if (!strcmp(optname, "videoshades")) {
6509         Sprintf(buf, "%s-%s-%s", shade[0], shade[1], shade[2]);
6510     } else if (!strcmp(optname, "videocolors")) {
6511         Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
6512                 ttycolors[CLR_RED], ttycolors[CLR_GREEN],
6513                 ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
6514                 ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],
6515                 ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
6516                 ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
6517                 ttycolors[CLR_BRIGHT_MAGENTA], ttycolors[CLR_BRIGHT_CYAN]);
6518 #endif /* VIDEOSHADES */
6519     } else if (!strcmp(optname,"windowborders")) {
6520         Sprintf(buf, "%s",
6521                 (iflags.wc2_windowborders == 0) ? "0=off"
6522                 : (iflags.wc2_windowborders == 1) ? "1=on"
6523                   : (iflags.wc2_windowborders == 2) ? "2=auto"
6524                     : defopt);
6525     } else if (!strcmp(optname, "windowtype")) {
6526         Sprintf(buf, "%s", windowprocs.name);
6527     } else if (!strcmp(optname, "windowcolors")) {
6528         Sprintf(
6529             buf, "%s/%s %s/%s %s/%s %s/%s",
6530             iflags.wc_foregrnd_menu ? iflags.wc_foregrnd_menu : defbrief,
6531             iflags.wc_backgrnd_menu ? iflags.wc_backgrnd_menu : defbrief,
6532             iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message
6533                                        : defbrief,
6534             iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message
6535                                        : defbrief,
6536             iflags.wc_foregrnd_status ? iflags.wc_foregrnd_status : defbrief,
6537             iflags.wc_backgrnd_status ? iflags.wc_backgrnd_status : defbrief,
6538             iflags.wc_foregrnd_text ? iflags.wc_foregrnd_text : defbrief,
6539             iflags.wc_backgrnd_text ? iflags.wc_backgrnd_text : defbrief);
6540 #ifdef PREFIXES_IN_USE
6541     } else {
6542         for (i = 0; i < PREFIX_COUNT; ++i)
6543             if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i])
6544                 Sprintf(buf, "%s", fqn_prefix[i]);
6545 #endif
6546     }
6547
6548     if (!buf[0])
6549 /*JP
6550         Strcpy(buf, "unknown");
6551 */
6552         Strcpy(buf, "\95s\96¾");
6553     return buf;
6554 }
6555
6556 int
6557 dotogglepickup()
6558 {
6559     char buf[BUFSZ], ocl[MAXOCLASSES + 1];
6560
6561     flags.pickup = !flags.pickup;
6562     if (flags.pickup) {
6563         oc_to_str(flags.pickup_types, ocl);
6564 #if 0 /*JP:T*/
6565         Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all",
6566                 (apelist)
6567                     ? ((count_apes() == 1)
6568                            ? ", with one exception"
6569                            : ", with some exceptions")
6570                     : "");
6571 #else
6572         Sprintf(buf, "%s\83A\83C\83e\83\80\82É\82Â\82¢\82Ä\83I\83\93%s", ocl[0] ? ocl : "\91S\82Ä\82Ì",
6573                 (apelist)
6574                     ? "\81C\97á\8aO\82 \82è"
6575                     : "");
6576 #endif
6577     } else {
6578 /*JP
6579         Strcpy(buf, "OFF");
6580 */
6581         Strcpy(buf, "\83I\83t");
6582     }
6583 /*JP
6584     pline("Autopickup: %s.", buf);
6585 */
6586     pline("\8e©\93®\8fE\82¢\81F%s\81D", buf);
6587     return 0;
6588 }
6589
6590 int
6591 add_autopickup_exception(mapping)
6592 const char *mapping;
6593 {
6594     static const char
6595         APE_regex_error[] = "regex error in AUTOPICKUP_EXCEPTION",
6596         APE_syntax_error[] = "syntax error in AUTOPICKUP_EXCEPTION";
6597
6598     struct autopickup_exception *ape;
6599     char text[256], end;
6600     int n;
6601     boolean grab = FALSE;
6602
6603     /* scan length limit used to be 255, but smaller size allows the
6604        quoted value to fit within BUFSZ, simplifying formatting elsewhere;
6605        this used to ignore the possibility of trailing junk but now checks
6606        for it, accepting whitespace but rejecting anything else unless it
6607        starts with '#" for a comment */
6608     end = '\0';
6609     if ((n = sscanf(mapping, "\"<%253[^\"]\" %c", text, &end)) == 1
6610         || (n == 2 && end == '#')) {
6611         grab = TRUE;
6612     } else if ((n = sscanf(mapping, "\">%253[^\"]\" %c", text, &end)) == 1
6613                || (n = sscanf(mapping, "\"%253[^\"]\" %c", text, &end)) == 1
6614                || (n == 2 && end == '#')) {
6615         grab = FALSE;
6616     } else {
6617         config_error_add("%s", APE_syntax_error);
6618         return 0;
6619     }
6620
6621     ape = (struct autopickup_exception *) alloc(sizeof *ape);
6622     ape->regex = regex_init();
6623     if (!regex_compile(text, ape->regex)) {
6624         config_error_add("%s: %s", APE_regex_error,
6625                          regex_error_desc(ape->regex));
6626         regex_free(ape->regex);
6627         free((genericptr_t) ape);
6628         return 0;
6629     }
6630
6631     ape->pattern = dupstr(text);
6632     ape->grab = grab;
6633     ape->next = apelist;
6634     apelist = ape;
6635     return 1;
6636 }
6637
6638 STATIC_OVL void
6639 remove_autopickup_exception(whichape)
6640 struct autopickup_exception *whichape;
6641 {
6642     struct autopickup_exception *ape, *freeape, *prev = 0;
6643
6644     for (ape = apelist; ape;) {
6645         if (ape == whichape) {
6646             freeape = ape;
6647             ape = ape->next;
6648             if (prev)
6649                 prev->next = ape;
6650             else
6651                 apelist = ape;
6652             regex_free(freeape->regex);
6653             free((genericptr_t) freeape->pattern);
6654             free((genericptr_t) freeape);
6655         } else {
6656             prev = ape;
6657             ape = ape->next;
6658         }
6659     }
6660 }
6661
6662 void
6663 free_autopickup_exceptions()
6664 {
6665     struct autopickup_exception *ape = apelist;
6666
6667     while ((ape = apelist) != 0) {
6668       regex_free(ape->regex);
6669       free((genericptr_t) ape->pattern);
6670       apelist = ape->next;
6671       free((genericptr_t) ape);
6672     }
6673 }
6674
6675 /* bundle some common usage into one easy-to-use routine */
6676 int
6677 load_symset(s, which_set)
6678 const char *s;
6679 int which_set;
6680 {
6681     clear_symsetentry(which_set, TRUE);
6682
6683     if (symset[which_set].name)
6684         free((genericptr_t) symset[which_set].name);
6685     symset[which_set].name = dupstr(s);
6686
6687     if (read_sym_file(which_set)) {
6688         switch_symbols(TRUE);
6689     } else {
6690         clear_symsetentry(which_set, TRUE);
6691         return 0;
6692     }
6693     return 1;
6694 }
6695
6696 void
6697 free_symsets()
6698 {
6699     clear_symsetentry(PRIMARY, TRUE);
6700     clear_symsetentry(ROGUESET, TRUE);
6701
6702     /* symset_list is cleaned up as soon as it's used, so we shouldn't
6703        have to anything about it here */
6704     /* assert( symset_list == NULL ); */
6705 }
6706
6707 /* Parse the value of a SYMBOLS line from a config file */
6708 boolean
6709 parsesymbols(opts, which_set)
6710 register char *opts;
6711 int which_set;
6712 {
6713     int val;
6714     char *op, *symname, *strval;
6715     struct symparse *symp;
6716
6717     if ((op = index(opts, ',')) != 0) {
6718         *op++ = 0;
6719         if (!parsesymbols(op, which_set))
6720             return FALSE;
6721     }
6722
6723     /* S_sample:string */
6724     symname = opts;
6725     strval = index(opts, ':');
6726     if (!strval)
6727         strval = index(opts, '=');
6728     if (!strval)
6729         return FALSE;
6730     *strval++ = '\0';
6731
6732     /* strip leading and trailing white space from symname and strval */
6733     mungspaces(symname);
6734     mungspaces(strval);
6735
6736     symp = match_sym(symname);
6737     if (!symp)
6738         return FALSE;
6739
6740     if (symp->range && symp->range != SYM_CONTROL) {
6741         val = sym_val(strval);
6742         if (which_set == ROGUESET)
6743             update_ov_rogue_symset(symp, val);
6744         else
6745             update_ov_primary_symset(symp, val);
6746     }
6747     return TRUE;
6748 }
6749
6750 struct symparse *
6751 match_sym(buf)
6752 char *buf;
6753 {
6754     size_t len = strlen(buf);
6755     const char *p = index(buf, ':'), *q = index(buf, '=');
6756     struct symparse *sp = loadsyms;
6757
6758     if (!p || (q && q < p))
6759         p = q;
6760     if (p) {
6761         /* note: there will be at most one space before the '='
6762            because caller has condensed buf[] with mungspaces() */
6763         if (p > buf && p[-1] == ' ')
6764             p--;
6765         len = (int) (p - buf);
6766     }
6767     while (sp->range) {
6768         if ((len >= strlen(sp->name)) && !strncmpi(buf, sp->name, len))
6769             return sp;
6770         sp++;
6771     }
6772     return (struct symparse *) 0;
6773 }
6774
6775 int
6776 sym_val(strval)
6777 const char *strval; /* up to 4*BUFSZ-1 long; only first few chars matter */
6778 {
6779     char buf[QBUFSZ], tmp[QBUFSZ]; /* to hold trucated copy of 'strval' */
6780
6781     buf[0] = '\0';
6782     if (!strval[0] || !strval[1]) { /* empty, or single character */
6783         /* if single char is space or tab, leave buf[0]=='\0' */
6784         if (!isspace((uchar) strval[0]))
6785             buf[0] = strval[0];
6786     } else if (strval[0] == '\'') { /* single quote */
6787         /* simple matching single quote; we know strval[1] isn't '\0' */
6788         if (strval[2] == '\'' && !strval[3]) {
6789             /* accepts '\' as backslash and ''' as single quote */
6790             buf[0] = strval[1];
6791
6792         /* if backslash, handle single or double quote or second backslash */
6793         } else if (strval[1] == '\\' && strval[2] && strval[3] == '\''
6794             && index("'\"\\", strval[2]) && !strval[4]) {
6795             buf[0] = strval[2];
6796
6797         /* not simple quote or basic backslash;
6798            strip closing quote and let escapes() deal with it */
6799         } else {
6800             char *p;
6801
6802             /* +1: skip opening single quote */
6803             (void) strncpy(tmp, strval + 1, sizeof tmp - 1);
6804             tmp[sizeof tmp - 1] = '\0';
6805             if ((p = rindex(tmp, '\'')) != 0) {
6806                 *p = '\0';
6807                 escapes(tmp, buf);
6808             } /* else buf[0] stays '\0' */
6809         }
6810     } else { /* not lone char nor single quote */
6811         (void) strncpy(tmp, strval, sizeof tmp - 1);
6812         tmp[sizeof tmp - 1] = '\0';
6813         escapes(tmp, buf);
6814     }
6815
6816     return (int) *buf;
6817 }
6818
6819 /* data for option_help() */
6820 static const char *opt_intro[] = {
6821     "",
6822 /*JP
6823     "                 NetHack Options Help:", "",
6824 */
6825     "               NetHack\83I\83v\83V\83\87\83\93\83w\83\8b\83v\81F", "",
6826 #define CONFIG_SLOT 3 /* fill in next value at run-time */
6827     (char *) 0,
6828 #if !defined(MICRO) && !defined(MAC)
6829 /*JP
6830     "or use `NETHACKOPTIONS=\"<options>\"' in your environment",
6831 */
6832     "\82Ü\82½\82Í\8aÂ\8b«\95Ï\90\94\82É`NETHACKOPTIONS=\"<options>\"'\82Æ\92è\8b`\82Å\82«\82Ü\82·",
6833 #endif
6834 /*JP
6835     "(<options> is a list of options separated by commas)",
6836 */
6837     "(<options>\82Í\83J\83\93\83}\82Å\8bæ\90Ø\82Á\82½\83I\83v\83V\83\87\83\93\82Å\82·)",
6838 #ifdef VMS
6839 /*JP
6840     "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
6841 */
6842     "-- \97á\82¦\82Î\8e\9f\82Ì\82æ\82¤\82É\82µ\82Ü\82·\81F$ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
6843 #endif
6844 /*JP
6845     "or press \"O\" while playing and use the menu.",
6846 */
6847     "\82à\82µ\82­\82Í\83Q\81[\83\80\83v\83\8c\83C\92\86\82É\"O\"\83{\83^\83\93\82ð\89\9f\82·\82±\82Æ\82Å\90Ý\92è\89Â\94\\82Å\82·\81D",
6848     "",
6849 /*JP
6850  "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
6851 */
6852  "\90^\8bU\92l\83I\83v\83V\83\87\83\93 (\94Û\92è\82Ì\92l\82ð\8ew\92è\82·\82é\8fê\8d\87\81C'!'\82à\82µ\82­\82Í\"no\"\82ð\90æ\93ª\82É\95t\89Á\82µ\82Ü\82·):",
6853     (char *) 0
6854 };
6855
6856 static const char *opt_epilog[] = {
6857     "",
6858 /*JP
6859     "Some of the options can be set only before the game is started; those",
6860 */
6861     "\83I\83v\83V\83\87\83\93\82É\82Í\83Q\81[\83\80\8aJ\8en\91O\82Ì\82Ý\82É\82µ\82©\90Ý\92è\82Å\82«\82È\82¢\82à\82Ì\82ª\82 \82è\82Ü\82·\81D",
6862 /*JP
6863     "items will not be selectable in the 'O' command's menu.",
6864 */
6865     "\82»\82ê\82ç\82Í'O'\83R\83}\83\93\83h\82Ì\83\81\83j\83\85\81[\82Å\82Í\91I\91ð\82·\82é\82±\82Æ\82ª\82Å\82«\82Ü\82¹\82ñ\81D",
6866     (char *) 0
6867 };
6868
6869 void
6870 option_help()
6871 {
6872     char buf[BUFSZ], buf2[BUFSZ];
6873     register int i;
6874     winid datawin;
6875
6876     datawin = create_nhwindow(NHW_TEXT);
6877 /*JP
6878     Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile);
6879 */
6880     Sprintf(buf, "\83I\83v\83V\83\87\83\93\82Í%s\82Ì\92\86\82ÅOPTIONS=<options>\82Æ\90Ý\92è\82µ\82Ü\82·", configfile);
6881     opt_intro[CONFIG_SLOT] = (const char *) buf;
6882     for (i = 0; opt_intro[i]; i++)
6883         putstr(datawin, 0, opt_intro[i]);
6884
6885     /* Boolean options */
6886     for (i = 0; boolopt[i].name; i++) {
6887         if (boolopt[i].addr) {
6888             if (boolopt[i].addr == &iflags.sanity_check && !wizard)
6889                 continue;
6890             if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard)
6891                 continue;
6892             next_opt(datawin, boolopt[i].name);
6893         }
6894     }
6895     next_opt(datawin, "");
6896
6897     /* Compound options */
6898 /*JP
6899     putstr(datawin, 0, "Compound options:");
6900 */
6901     putstr(datawin, 0, "\95\8e\9a\97ñ\83I\83v\83V\83\87\83\93:");
6902     for (i = 0; compopt[i].name; i++) {
6903         Sprintf(buf2, "`%s'", compopt[i].name);
6904         Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr,
6905                 compopt[i + 1].name ? ',' : '.');
6906         putstr(datawin, 0, buf);
6907     }
6908
6909     for (i = 0; opt_epilog[i]; i++)
6910         putstr(datawin, 0, opt_epilog[i]);
6911
6912     display_nhwindow(datawin, FALSE);
6913     destroy_nhwindow(datawin);
6914     return;
6915 }
6916
6917 /*
6918  * prints the next boolean option, on the same line if possible, on a new
6919  * line if not. End with next_opt("").
6920  */
6921 void
6922 next_opt(datawin, str)
6923 winid datawin;
6924 const char *str;
6925 {
6926     static char *buf = 0;
6927     int i;
6928     char *s;
6929
6930     if (!buf)
6931         *(buf = (char *) alloc(BUFSZ)) = '\0';
6932
6933     if (!*str) {
6934         s = eos(buf);
6935         if (s > &buf[1] && s[-2] == ',')
6936             Strcpy(s - 2, "."); /* replace last ", " */
6937         i = COLNO;              /* (greater than COLNO - 2) */
6938     } else {
6939         i = strlen(buf) + strlen(str) + 2;
6940     }
6941
6942     if (i > COLNO - 2) { /* rule of thumb */
6943         putstr(datawin, 0, buf);
6944         buf[0] = 0;
6945     }
6946     if (*str) {
6947         Strcat(buf, str);
6948         Strcat(buf, ", ");
6949     } else {
6950         putstr(datawin, 0, str);
6951         free((genericptr_t) buf), buf = 0;
6952     }
6953     return;
6954 }
6955
6956 /* Returns the fid of the fruit type; if that type already exists, it
6957  * returns the fid of that one; if it does not exist, it adds a new fruit
6958  * type to the chain and returns the new one.
6959  * If replace_fruit is sent in, replace the fruit in the chain rather than
6960  * adding a new entry--for user specified fruits only.
6961  */
6962 int
6963 fruitadd(str, replace_fruit)
6964 char *str;
6965 struct fruit *replace_fruit;
6966 {
6967     register int i;
6968     register struct fruit *f;
6969     int highest_fruit_id = 0, globpfx;
6970     char buf[PL_FSIZ], altname[PL_FSIZ];
6971     boolean user_specified = (str == pl_fruit);
6972     /* if not user-specified, then it's a fruit name for a fruit on
6973      * a bones level or from orctown raider's loot...
6974      */
6975
6976     /* Note: every fruit has an id (kept in obj->spe) of at least 1;
6977      * 0 is an error.
6978      */
6979     if (user_specified) {
6980         boolean found = FALSE, numeric = FALSE;
6981
6982         /* force fruit to be singular; this handling is not
6983            needed--or wanted--for fruits from bones because
6984            they already received it in their original game;
6985            str==pl_fruit but makesingular() creates a copy
6986            so we need to copy that back into pl_fruit */
6987         nmcpy(pl_fruit, makesingular(str), PL_FSIZ);
6988         /* (assertion doesn't matter; we use 'pl_fruit' from here on out) */
6989         /* assert( str == pl_fruit ); */
6990
6991         /* disallow naming after other foods (since it'd be impossible
6992          * to tell the difference); globs might have a size prefix which
6993          * needs to be skipped in order to match the object type name
6994          */
6995         globpfx = (!strncmp(pl_fruit, "small ", 6)
6996                    || !strncmp(pl_fruit, "large ", 6)) ? 6
6997                   : (!strncmp(pl_fruit, "very large ", 11)) ? 11
6998                     : 0;
6999         for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS; i++) {
7000             if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)
7001                 || (globpfx > 0
7002                     && !strcmp(OBJ_NAME(objects[i]), &pl_fruit[globpfx]))) {
7003                 found = TRUE;
7004                 break;
7005             }
7006         }
7007         if (!found) {
7008             char *c;
7009
7010             for (c = pl_fruit; *c >= '0' && *c <= '9'; c++)
7011                 continue;
7012             if (!*c || isspace((uchar) *c))
7013                 numeric = TRUE;
7014         }
7015         if (found || numeric
7016             /* these checks for applying food attributes to actual items
7017                are case sensitive; "glob of foo" is caught by 'found'
7018                if 'foo' is a valid glob; when not valid, allow it as-is */
7019             || !strncmp(pl_fruit, "cursed ", 7)
7020             || !strncmp(pl_fruit, "uncursed ", 9)
7021             || !strncmp(pl_fruit, "blessed ", 8)
7022             || !strncmp(pl_fruit, "partly eaten ", 13)
7023             || (!strncmp(pl_fruit, "tin of ", 7)
7024                 && (!strcmp(pl_fruit + 7, "spinach")
7025                     || name_to_mon(pl_fruit + 7) >= LOW_PM))
7026             || !strcmp(pl_fruit, "empty tin")
7027             || (!strcmp(pl_fruit, "glob")
7028                 || (globpfx > 0 && !strcmp("glob", &pl_fruit[globpfx])))
7029             || ((str_end_is(pl_fruit, " corpse")
7030                  || str_end_is(pl_fruit, " egg"))
7031                 && name_to_mon(pl_fruit) >= LOW_PM)) {
7032             Strcpy(buf, pl_fruit);
7033             Strcpy(pl_fruit, "candied ");
7034             nmcpy(pl_fruit + 8, buf, PL_FSIZ - 8);
7035         }
7036         *altname = '\0';
7037         /* This flag indicates that a fruit has been made since the
7038          * last time the user set the fruit.  If it hasn't, we can
7039          * safely overwrite the current fruit, preventing the user from
7040          * setting many fruits in a row and overflowing.
7041          * Possible expansion: check for specific fruit IDs, not for
7042          * any fruit.
7043          */
7044         flags.made_fruit = FALSE;
7045         if (replace_fruit) {
7046             /* replace_fruit is already part of the fruit chain;
7047                update it in place rather than looking it up again */
7048             f = replace_fruit;
7049             copynchars(f->fname, pl_fruit, PL_FSIZ - 1);
7050             goto nonew;
7051         }
7052     } else {
7053         /* not user_supplied, so assumed to be from bones (or orc gang) */
7054         copynchars(altname, str, PL_FSIZ - 1);
7055         sanitize_name(altname);
7056         flags.made_fruit = TRUE; /* for safety.  Any fruit name added from a
7057                                   * bones level should exist anyway. */
7058     }
7059     f = fruit_from_name(*altname ? altname : str, FALSE, &highest_fruit_id);
7060     if (f)
7061         goto nonew;
7062
7063     /* Maximum number of named fruits is 127, even if obj->spe can
7064        handle bigger values.  If adding another fruit would overflow,
7065        use a random fruit instead... we've got a lot to choose from.
7066        current_fruit remains as is. */
7067     if (highest_fruit_id >= 127)
7068         return rnd(127);
7069
7070     f = newfruit();
7071     (void) memset((genericptr_t) f, 0, sizeof (struct fruit));
7072     copynchars(f->fname, *altname ? altname : str, PL_FSIZ - 1);
7073     f->fid = ++highest_fruit_id;
7074     /* we used to go out of our way to add it at the end of the list,
7075        but the order is arbitrary so use simpler insertion at start */
7076     f->nextf = ffruit;
7077     ffruit = f;
7078  nonew:
7079     if (user_specified)
7080         context.current_fruit = f->fid;
7081     return f->fid;
7082 }
7083
7084 /*
7085  * This is a somewhat generic menu for taking a list of NetHack style
7086  * class choices and presenting them via a description
7087  * rather than the traditional NetHack characters.
7088  * (Benefits users whose first exposure to NetHack is via tiles).
7089  *
7090  * prompt
7091  *           The title at the top of the menu.
7092  *
7093  * category: 0 = monster class
7094  *           1 = object  class
7095  *
7096  * way
7097  *           FALSE = PICK_ONE, TRUE = PICK_ANY
7098  *
7099  * class_list
7100  *           a null terminated string containing the list of choices.
7101  *
7102  * class_selection
7103  *           a null terminated string containing the selected characters.
7104  *
7105  * Returns number selected.
7106  */
7107 int
7108 choose_classes_menu(prompt, category, way, class_list, class_select)
7109 const char *prompt;
7110 int category;
7111 boolean way;
7112 char *class_list;
7113 char *class_select;
7114 {
7115     menu_item *pick_list = (menu_item *) 0;
7116     winid win;
7117     anything any;
7118     char buf[BUFSZ];
7119     int i, n;
7120     int ret;
7121     int next_accelerator, accelerator;
7122
7123     if (class_list == (char *) 0 || class_select == (char *) 0)
7124         return 0;
7125     accelerator = 0;
7126     next_accelerator = 'a';
7127     any = zeroany;
7128     win = create_nhwindow(NHW_MENU);
7129     start_menu(win);
7130     while (*class_list) {
7131         const char *text;
7132         boolean selected;
7133
7134         text = (char *) 0;
7135         selected = FALSE;
7136         switch (category) {
7137         case 0:
7138             text = def_monsyms[def_char_to_monclass(*class_list)].explain;
7139             accelerator = *class_list;
7140             Sprintf(buf, "%s", text);
7141             break;
7142         case 1:
7143             text = def_oc_syms[def_char_to_objclass(*class_list)].explain;
7144             accelerator = next_accelerator;
7145             Sprintf(buf, "%c  %s", *class_list, text);
7146             break;
7147         default:
7148             impossible("choose_classes_menu: invalid category %d", category);
7149         }
7150         if (way && *class_select) { /* Selections there already */
7151             if (index(class_select, *class_list)) {
7152                 selected = TRUE;
7153             }
7154         }
7155         any.a_int = *class_list;
7156         add_menu(win, NO_GLYPH, &any, accelerator, category ? *class_list : 0,
7157                  ATR_NONE, buf, selected);
7158         ++class_list;
7159         if (category > 0) {
7160             ++next_accelerator;
7161             if (next_accelerator == ('z' + 1))
7162                 next_accelerator = 'A';
7163             if (next_accelerator == ('Z' + 1))
7164                 break;
7165         }
7166     }
7167     if (category == 1 && next_accelerator <= 'z') {
7168         /* for objects, add "A - ' '  all classes", after a separator */
7169         any = zeroany;
7170         add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
7171         any.a_int = (int) ' ';
7172         Sprintf(buf, "%c  %s", (char) any.a_int, "all classes of objects");
7173         /* we won't preselect this even if the incoming list is empty;
7174            having it selected means that it would have to be explicitly
7175            de-selected in order to select anything else */
7176         add_menu(win, NO_GLYPH, &any, 'A', 0, ATR_NONE, buf, MENU_UNSELECTED);
7177     }
7178     end_menu(win, prompt);
7179     n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list);
7180     destroy_nhwindow(win);
7181     if (n > 0) {
7182         if (category == 1) {
7183             /* for object classes, first check for 'all'; it means 'use
7184                a blank list' rather than 'collect every possible choice' */
7185             for (i = 0; i < n; ++i)
7186                 if (pick_list[i].item.a_int == ' ') {
7187                     pick_list[0].item.a_int = ' ';
7188                     n = 1; /* return 1; also an implicit 'break;' */
7189                 }
7190         }
7191         for (i = 0; i < n; ++i)
7192             *class_select++ = (char) pick_list[i].item.a_int;
7193         free((genericptr_t) pick_list);
7194         ret = n;
7195     } else if (n == -1) {
7196         class_select = eos(class_select);
7197         ret = -1;
7198     } else
7199         ret = 0;
7200     *class_select = '\0';
7201     return ret;
7202 }
7203
7204 static struct wc_Opt wc_options[] = {
7205     { "ascii_map", WC_ASCII_MAP },
7206     { "color", WC_COLOR },
7207     { "eight_bit_tty", WC_EIGHT_BIT_IN },
7208     { "hilite_pet", WC_HILITE_PET },
7209     { "popup_dialog", WC_POPUP_DIALOG },
7210     { "player_selection", WC_PLAYER_SELECTION },
7211     { "preload_tiles", WC_PRELOAD_TILES },
7212     { "tiled_map", WC_TILED_MAP },
7213     { "tile_file", WC_TILE_FILE },
7214     { "tile_width", WC_TILE_WIDTH },
7215     { "tile_height", WC_TILE_HEIGHT },
7216     { "use_inverse", WC_INVERSE },
7217     { "align_message", WC_ALIGN_MESSAGE },
7218     { "align_status", WC_ALIGN_STATUS },
7219     { "font_map", WC_FONT_MAP },
7220     { "font_menu", WC_FONT_MENU },
7221     { "font_message", WC_FONT_MESSAGE },
7222 #if 0
7223     {"perm_invent", WC_PERM_INVENT},
7224 #endif
7225     { "font_size_map", WC_FONTSIZ_MAP },
7226     { "font_size_menu", WC_FONTSIZ_MENU },
7227     { "font_size_message", WC_FONTSIZ_MESSAGE },
7228     { "font_size_status", WC_FONTSIZ_STATUS },
7229     { "font_size_text", WC_FONTSIZ_TEXT },
7230     { "font_status", WC_FONT_STATUS },
7231     { "font_text", WC_FONT_TEXT },
7232     { "map_mode", WC_MAP_MODE },
7233     { "scroll_amount", WC_SCROLL_AMOUNT },
7234     { "scroll_margin", WC_SCROLL_MARGIN },
7235     { "splash_screen", WC_SPLASH_SCREEN },
7236     { "vary_msgcount", WC_VARY_MSGCOUNT },
7237     { "windowcolors", WC_WINDOWCOLORS },
7238     { "mouse_support", WC_MOUSE_SUPPORT },
7239     { (char *) 0, 0L }
7240 };
7241 static struct wc_Opt wc2_options[] = {
7242     { "fullscreen", WC2_FULLSCREEN },
7243     { "softkeyboard", WC2_SOFTKEYBOARD },
7244     { "wraptext", WC2_WRAPTEXT },
7245     { "use_darkgray", WC2_DARKGRAY },
7246     { "hitpointbar", WC2_HITPOINTBAR },
7247     { "hilite_status", WC2_HILITE_STATUS },
7248     /* name shown in 'O' menu is different */
7249     { "status hilite rules", WC2_HILITE_STATUS },
7250     /* statushilites doesn't have its own bit */
7251     { "statushilites", WC2_HILITE_STATUS },
7252     { "term_cols", WC2_TERM_SIZE },
7253     { "term_rows", WC2_TERM_SIZE },
7254     { "petattr", WC2_PETATTR },
7255     { "guicolor", WC2_GUICOLOR },
7256     { "statuslines", WC2_STATUSLINES },
7257     { "windowborders", WC2_WINDOWBORDERS },
7258     { (char *) 0, 0L }
7259 };
7260
7261 /*
7262  * If a port wants to change or ensure that the SET_IN_SYS,
7263  * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
7264  * correct (for controlling its display in the option menu) call
7265  * set_option_mod_status()
7266  * with the appropriate second argument.
7267  */
7268 void
7269 set_option_mod_status(optnam, status)
7270 const char *optnam;
7271 int status;
7272 {
7273     int k;
7274
7275     if (SET__IS_VALUE_VALID(status)) {
7276         impossible("set_option_mod_status: status out of range %d.", status);
7277         return;
7278     }
7279     for (k = 0; boolopt[k].name; k++) {
7280         if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) {
7281             boolopt[k].optflags = status;
7282             return;
7283         }
7284     }
7285     for (k = 0; compopt[k].name; k++) {
7286         if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) {
7287             compopt[k].optflags = status;
7288             return;
7289         }
7290     }
7291 }
7292
7293 /*
7294  * You can set several wc_options in one call to
7295  * set_wc_option_mod_status() by setting
7296  * the appropriate bits for each option that you
7297  * are setting in the optmask argument
7298  * prior to calling.
7299  *    example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN,
7300  * SET_IN_GAME);
7301  */
7302 void
7303 set_wc_option_mod_status(optmask, status)
7304 unsigned long optmask;
7305 int status;
7306 {
7307     int k = 0;
7308
7309     if (SET__IS_VALUE_VALID(status)) {
7310         impossible("set_wc_option_mod_status: status out of range %d.",
7311                    status);
7312         return;
7313     }
7314     while (wc_options[k].wc_name) {
7315         if (optmask & wc_options[k].wc_bit) {
7316             set_option_mod_status(wc_options[k].wc_name, status);
7317         }
7318         k++;
7319     }
7320 }
7321
7322 STATIC_OVL boolean
7323 is_wc_option(optnam)
7324 const char *optnam;
7325 {
7326     int k = 0;
7327
7328     while (wc_options[k].wc_name) {
7329         if (strcmp(wc_options[k].wc_name, optnam) == 0)
7330             return TRUE;
7331         k++;
7332     }
7333     return FALSE;
7334 }
7335
7336 STATIC_OVL boolean
7337 wc_supported(optnam)
7338 const char *optnam;
7339 {
7340     int k;
7341
7342     for (k = 0; wc_options[k].wc_name; ++k) {
7343         if (!strcmp(wc_options[k].wc_name, optnam))
7344             return (windowprocs.wincap & wc_options[k].wc_bit) ? TRUE : FALSE;
7345     }
7346     return FALSE;
7347 }
7348
7349 /*
7350  * You can set several wc2_options in one call to
7351  * set_wc2_option_mod_status() by setting
7352  * the appropriate bits for each option that you
7353  * are setting in the optmask argument
7354  * prior to calling.
7355  *    example:
7356  * set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT,
7357  * SET_IN_FILE);
7358  */
7359
7360 void
7361 set_wc2_option_mod_status(optmask, status)
7362 unsigned long optmask;
7363 int status;
7364 {
7365     int k = 0;
7366
7367     if (SET__IS_VALUE_VALID(status)) {
7368         impossible("set_wc2_option_mod_status: status out of range %d.",
7369                    status);
7370         return;
7371     }
7372     while (wc2_options[k].wc_name) {
7373         if (optmask & wc2_options[k].wc_bit) {
7374             set_option_mod_status(wc2_options[k].wc_name, status);
7375         }
7376         k++;
7377     }
7378 }
7379
7380 STATIC_OVL boolean
7381 is_wc2_option(optnam)
7382 const char *optnam;
7383 {
7384     int k = 0;
7385
7386     while (wc2_options[k].wc_name) {
7387         if (strcmp(wc2_options[k].wc_name, optnam) == 0)
7388             return TRUE;
7389         k++;
7390     }
7391     return FALSE;
7392 }
7393
7394 STATIC_OVL boolean
7395 wc2_supported(optnam)
7396 const char *optnam;
7397 {
7398     int k;
7399
7400     for (k = 0; wc2_options[k].wc_name; ++k) {
7401         if (!strcmp(wc2_options[k].wc_name, optnam))
7402             return (windowprocs.wincap2 & wc2_options[k].wc_bit) ? TRUE
7403                                                                  : FALSE;
7404     }
7405     return FALSE;
7406 }
7407
7408 STATIC_OVL void
7409 wc_set_font_name(opttype, fontname)
7410 int opttype;
7411 char *fontname;
7412 {
7413     char **fn = (char **) 0;
7414
7415     if (!fontname)
7416         return;
7417     switch (opttype) {
7418     case MAP_OPTION:
7419         fn = &iflags.wc_font_map;
7420         break;
7421     case MESSAGE_OPTION:
7422         fn = &iflags.wc_font_message;
7423         break;
7424     case TEXT_OPTION:
7425         fn = &iflags.wc_font_text;
7426         break;
7427     case MENU_OPTION:
7428         fn = &iflags.wc_font_menu;
7429         break;
7430     case STATUS_OPTION:
7431         fn = &iflags.wc_font_status;
7432         break;
7433     default:
7434         return;
7435     }
7436     if (fn) {
7437         if (*fn)
7438             free((genericptr_t) *fn);
7439         *fn = dupstr(fontname);
7440     }
7441     return;
7442 }
7443
7444 STATIC_OVL int
7445 wc_set_window_colors(op)
7446 char *op;
7447 {
7448     /* syntax:
7449      *  menu white/black message green/yellow status white/blue text
7450      * white/black
7451      */
7452     int j;
7453     char buf[BUFSZ];
7454     char *wn, *tfg, *tbg, *newop;
7455     static const char *wnames[] = { "menu", "message", "status", "text" };
7456     static const char *shortnames[] = { "mnu", "msg", "sts", "txt" };
7457     static char **fgp[] = { &iflags.wc_foregrnd_menu,
7458                             &iflags.wc_foregrnd_message,
7459                             &iflags.wc_foregrnd_status,
7460                             &iflags.wc_foregrnd_text };
7461     static char **bgp[] = { &iflags.wc_backgrnd_menu,
7462                             &iflags.wc_backgrnd_message,
7463                             &iflags.wc_backgrnd_status,
7464                             &iflags.wc_backgrnd_text };
7465
7466     Strcpy(buf, op);
7467     newop = mungspaces(buf);
7468     while (newop && *newop) {
7469         wn = tfg = tbg = (char *) 0;
7470
7471         /* until first non-space in case there's leading spaces - before
7472          * colorname*/
7473         if (*newop == ' ')
7474             newop++;
7475         if (*newop)
7476             wn = newop;
7477         else
7478             return 0;
7479
7480         /* until first space - colorname*/
7481         while (*newop && *newop != ' ')
7482             newop++;
7483         if (*newop)
7484             *newop = '\0';
7485         else
7486             return 0;
7487         newop++;
7488
7489         /* until first non-space - before foreground*/
7490         if (*newop == ' ')
7491             newop++;
7492         if (*newop)
7493             tfg = newop;
7494         else
7495             return 0;
7496
7497         /* until slash - foreground */
7498         while (*newop && *newop != '/')
7499             newop++;
7500         if (*newop)
7501             *newop = '\0';
7502         else
7503             return 0;
7504         newop++;
7505
7506         /* until first non-space (in case there's leading space after slash) -
7507          * before background */
7508         if (*newop == ' ')
7509             newop++;
7510         if (*newop)
7511             tbg = newop;
7512         else
7513             return 0;
7514
7515         /* until first space - background */
7516         while (*newop && *newop != ' ')
7517             newop++;
7518         if (*newop)
7519             *newop++ = '\0';
7520
7521         for (j = 0; j < 4; ++j) {
7522             if (!strcmpi(wn, wnames[j]) || !strcmpi(wn, shortnames[j])) {
7523                 if (tfg && !strstri(tfg, " ")) {
7524                     if (*fgp[j])
7525                         free((genericptr_t) *fgp[j]);
7526                     *fgp[j] = dupstr(tfg);
7527                 }
7528                 if (tbg && !strstri(tbg, " ")) {
7529                     if (*bgp[j])
7530                         free((genericptr_t) *bgp[j]);
7531                     *bgp[j] = dupstr(tbg);
7532                 }
7533                 break;
7534             }
7535         }
7536     }
7537     return 1;
7538 }
7539
7540 /* set up for wizard mode if player or save file has requested to it;
7541    called from port-specific startup code to handle `nethack -D' or
7542    OPTIONS=playmode:debug, or from dorecover()'s restgamestate() if
7543    restoring a game which was saved in wizard mode */
7544 void
7545 set_playmode()
7546 {
7547     if (wizard) {
7548         if (authorize_wizard_mode())
7549             Strcpy(plname, "wizard");
7550         else
7551             wizard = FALSE; /* not allowed or not available */
7552         /* force explore mode if we didn't make it into wizard mode */
7553         discover = !wizard;
7554         iflags.deferred_X = FALSE;
7555     }
7556     /* don't need to do anything special for explore mode or normal play */
7557 }
7558
7559 #endif /* OPTION_LISTS_ONLY */
7560
7561 /*options.c*/