OSDN Git Service

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