From 07c54674341ea5b9af9df03fa0678d14ebf4f6f9 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 25 Apr 2015 10:51:07 -0400 Subject: [PATCH 1/7] checkfile protection from caller Changes to be committed: modified: src/pager.c --- src/pager.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/pager.c b/src/pager.c index 4033a1746..2e3d56e8e 100644 --- a/src/pager.c +++ b/src/pager.c @@ -310,6 +310,14 @@ checkfile(inp, pm, user_typed_name, without_asking) return; } + /* + * If someone passed us garbage, prevent fault + * + if (!inp || (inp && strlen(inp) > (BUFSZ - 1))) { + pline("bad do_look buffer passed!"); + return; + } + /* To prevent the need for entries in data.base like *ngel to account * for Angel and angel, make the lookup string the same for both * user_typed_name and picked name. From 8624709c0d2be08681fbcad8d2d6d0c94073cc80 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 25 Apr 2015 15:49:14 -0400 Subject: [PATCH 2/7] comment termination bit --- src/pager.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pager.c b/src/pager.c index 2e3d56e8e..f3c6c66b0 100644 --- a/src/pager.c +++ b/src/pager.c @@ -311,8 +311,8 @@ checkfile(inp, pm, user_typed_name, without_asking) } /* - * If someone passed us garbage, prevent fault - * + * If someone passed us garbage, prevent fault. + */ if (!inp || (inp && strlen(inp) > (BUFSZ - 1))) { pline("bad do_look buffer passed!"); return; From 4e067f5f2b4d83ebecb4bd189a7efe3634a8a55b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 26 Apr 2015 10:46:38 +0300 Subject: [PATCH 3/7] Show level annotation on level entry Idea by Chris Smith, via Unnethack --- include/extern.h | 1 + src/do.c | 4 ++++ src/dungeon.c | 10 ++++++++++ 3 files changed, 15 insertions(+) diff --git a/include/extern.h b/include/extern.h index 821f2a41c..4bf8dbbf3 100644 --- a/include/extern.h +++ b/include/extern.h @@ -570,6 +570,7 @@ E boolean FDECL(Invocation_lev, (d_level *)); E xchar NDECL(level_difficulty); E schar FDECL(lev_by_name, (const char *)); E schar FDECL(print_dungeon, (BOOLEAN_P,schar *,xchar *)); +E char *FDECL(get_annotation, (d_level *)); E int NDECL(donamelevel); E int NDECL(dooverview); E void FDECL(show_overview, (int,int)); diff --git a/src/do.c b/src/do.c index 97c11a8ef..3962e6d01 100644 --- a/src/do.c +++ b/src/do.c @@ -1069,6 +1069,7 @@ boolean at_stairs, falling, portal; boolean new = FALSE; /* made a new level? */ struct monst *mtmp; char whynot[BUFSZ]; + char *annotation; if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel)) newlevel->dlevel = dunlevs_in_dungeon(newlevel); @@ -1458,6 +1459,9 @@ boolean at_stairs, falling, portal; save_currentstate(); #endif + if ((annotation = get_annotation(&u.uz))) + You("remember this level as %s.", annotation); + /* assume this will always return TRUE when changing level */ (void) in_out_region(u.ux, u.uy); (void) pickup(1); diff --git a/src/dungeon.c b/src/dungeon.c index d02f3aec6..9a34aff0c 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -1848,6 +1848,16 @@ d_level *dest; } } +char * +get_annotation(lev) +d_level *lev; +{ + mapseen *mptr; + if ((mptr = find_mapseen(lev))) + return mptr->custom; + return NULL; +} + /* #annotate command - add a custom name to the current level */ int donamelevel() From cc5274d0b6531bb6527154de4b5884b3f61db14d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 26 Apr 2015 10:57:21 +0300 Subject: [PATCH 4/7] Mung annotation spaces --- src/dungeon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dungeon.c b/src/dungeon.c index 9a34aff0c..cde5b8917 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -1869,6 +1869,7 @@ donamelevel() getlin("What do you want to call this dungeon level?", nbuf); if (index(nbuf, '\033')) return 0; + (void)mungspaces(nbuf); /* discard old annotation, if any */ if (mptr->custom) { From f28ba6f131d1773ccb0124fb17c6885b42fc9dcb Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 26 Apr 2015 11:10:34 +0300 Subject: [PATCH 5/7] Show level annotation when overwriting existing one Idea by Chris Smith, via UnNetHack --- src/dungeon.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dungeon.c b/src/dungeon.c index cde5b8917..8c436e1c8 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -1867,7 +1867,12 @@ donamelevel() if (!(mptr = find_mapseen(&u.uz))) return 0; - getlin("What do you want to call this dungeon level?", nbuf); + if (mptr->custom) { + char qbuf[BUFSZ]; + Sprintf(qbuf, "Replace annotation \"%s\" with?", mptr->custom); + getlin(qbuf, nbuf); + } else + getlin("What do you want to call this dungeon level?", nbuf); if (index(nbuf, '\033')) return 0; (void)mungspaces(nbuf); From 54a22d39eaeef9d96b4b95684a1adbacda15b493 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 26 Apr 2015 11:29:54 +0300 Subject: [PATCH 6/7] Add level annotating to the Call menu Via UnNetHack --- src/do_name.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/do_name.c b/src/do_name.c index bd1dc6f49..06d305401 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -596,6 +596,9 @@ docallcmd() any.a_char = 'd'; /* entry 'd' (or 'b'), group accelator 'd' */ add_menu(win, NO_GLYPH, &any, 0, any.a_char, ATR_NONE, "the type of an object on discoveries list", MENU_UNSELECTED); + any.a_char = 'e'; + add_menu(win, NO_GLYPH, &any, 0, any.a_char, ATR_NONE, + "the current level", MENU_UNSELECTED); #if 0 any.a_char = 'f'; /* entry 'e' (or 'c'), group accelator 'f' */ add_menu(win, NO_GLYPH, &any, 0, any.a_char, ATR_NONE, @@ -643,6 +646,9 @@ docallcmd() case 'd': /* name a type of object on the discoveries list */ rename_disco(); break; + case 'e': /* annotate level */ + donamelevel(); + break; #if 0 case 'f': /* name a type of object visible on the floor */ /* [not implemented] */ From 6386331148c12538db70f69010e344f86d2813ec Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 26 Apr 2015 03:20:58 -0700 Subject: [PATCH 7/7] 'I' command support for BUCX Allow the 'I' command to show inventory of known blessed items via pseudo object classes B, C, U, and X. That's instead of an showing inventory of specific object class. The two can't be combined because 'I' operates on single character input. I had to modify tty_yn_function to prevent it from forcing a BUCX character into lower case (simply using lower case would cause a conflict with 'u' and 'x' for inventory of shopping bill), and did that by checking whether any of the acceptable response characters are upper case. Pretty straightforward and shouldn't impact any other uses that don't specify upper case choices. I did the same thing for X11. Other interfaces most likely need to do something similar. If they don't, a response of 'B' or 'C' (for menustyle:traditional or menustyle:combination) will simply not work, without causing any problems, same as typing an invalid choice, and 'U' or 'X' will give shop feedback instead of the requested subset of inventory. The Guidebook revisions are untested. --- doc/Guidebook.mn | 16 ++++- doc/Guidebook.tex | 16 ++++- doc/fixes35.0 | 2 + src/invent.c | 159 +++++++++++++++++++++++++++++++++------------- win/X11/winX.c | 15 ++++- win/tty/topl.c | 20 ++++-- 6 files changed, 174 insertions(+), 54 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 8b32a50aa..9466f72e5 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1,4 +1,4 @@ -.\" $NHDT-Branch$:$NHDT-Revision$ $NHDT-Date$ +.\" $NHDT-Branch: master $:$NHDT-Revision: 1.160 $ $NHDT-Date: 1430043650 2015/04/26 10:20:50 $ .\" $Revision: 1.130 $ $Date: 2015/03/27 00:38:30 $ .ds h0 "NetHack Guidebook .ds h1 @@ -607,12 +607,17 @@ is true. .lp i List your inventory (everything you're carrying). .lp I -List selected parts of your inventory. +List selected parts of your inventory, usually be specifying the character +for a particular set of objects, like `[' for armor or `!' for potions. .sd .si I* - list all gems in inventory; Iu - list all unpaid items; Ix - list all used up items that are on your shopping bill; +IB - list all items known to be blessed; +IU - list all items known to be uncursed; +IC - list all items known to be cursed; +IX - list all items whose bless/curse status is known; I$ - count your money. .ei .ed @@ -1256,6 +1261,11 @@ Objects can also be blessed. Blessed items usually work better or more beneficially than normal uncursed items. For example, a blessed weapon will do more damage against demons. .pg +Objects which are neither cursed nor blessed are referred to as uncursed. +They could just as easily have been described as unblessed, but the +uncursed designation is what you will see within the game. A ``glass +half full versus glass half empty'' situation; make of that what you will. +.pg There are magical means of bestowing or removing curses upon objects, so even if you are stuck with one, you can still have the curse lifted and the item removed. Priests and Priestesses have an innate @@ -1266,6 +1276,8 @@ An item with unknown status will be reported in your inventory with no prefix. An item which you know the state of will be distinguished in your inventory by the presence of the word ``cursed'', ``uncursed'' or ``blessed'' in the description of the item. +In some cases ``uncursed'' will be omitted as being redundant when +enough other information is displayed. .hn 2 Weapons (`)') .pg diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 057fbc8e9..7855d595b 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -742,12 +742,18 @@ something appropriate if {\it autoquiver\/} is true. List your inventory (everything you're carrying). %.lp \item[\tb{I}] -List selected parts of your inventory.\\ +List selected parts of your inventory, usually be specifying the character +for a particular set of objects, like `{\tt [}' for armor or `{\tt !}' +for potions.\\ %.sd %.si {\tt I*} --- list all gems in inventory;\\ {\tt Iu} --- list all unpaid items;\\ {\tt Ix} --- list all used up items that are on your shopping bill;\\ +{\tt IB} --- list all items known to be blessed;\\ +{\tt IU} --- list all items known to be uncursed;\\ +{\tt IC} --- list all items known to be cursed;\\ +{\tt IX} --- list all items whose bless/curse status is unknown;\\ {\tt I\$} --- count your money. %.ei %.ed @@ -1543,6 +1549,12 @@ Objects can also be blessed. Blessed items usually work better or more beneficially than normal uncursed items. For example, a blessed weapon will do more damage against demons. +%.pg +Objects which are neither cursed nor blessed are referred to as uncursed. +They could just as easily have been described as unblessed, but the +uncursed designation is what you will see within the game. A ``glass +half full versus glass half empty'' situation; make of that what you will. + %.pg There are magical means of bestowing or removing curses upon objects, so even if you are stuck with one, you can still have the curse @@ -1555,6 +1567,8 @@ An item with unknown status will be reported in your inventory with no prefix. An item which you know the state of will be distinguished in your inventory by the presence of the word ``cursed'', ``uncursed'' or ``blessed'' in the description of the item. +In some cases ``uncursed'' will be omitted as being redundant when +enough other information is displayed. %.hn 2 \subsection*{Weapons (`{\tt )}')} diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 072dbc6f3..991c41011 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -1128,6 +1128,8 @@ Some levels in Gehennom now use the old corridor-style maze instead of "beetle legs" are restored. gnomes will occasionally have a candle stop travel or run when you get hungry +'I' command can accept 'B','U','C',or 'X' as an alternative to normal object + class character to show inventory of items known to be blessed,&c Platform- and/or Interface-Specific New Features diff --git a/src/invent.c b/src/invent.c index 2cc65798d..b1aee908b 100644 --- a/src/invent.c +++ b/src/invent.c @@ -24,6 +24,7 @@ STATIC_PTR char *FDECL(safeq_xprname, (struct obj *)); STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *)); STATIC_DCL char FDECL(display_pickinv, (const char *,BOOLEAN_P, long *)); STATIC_DCL char FDECL(display_used_invlets, (CHAR_P)); +STATIC_DCL void FDECL(tally_BUCX, (struct obj *,int *,int *,int *,int *,int *)); STATIC_DCL boolean FDECL(this_type_only, (struct obj *)); STATIC_DCL void NDECL(dounpaid); STATIC_DCL struct obj *FDECL(find_unpaid,(struct obj *,struct obj **)); @@ -2067,6 +2068,33 @@ count_buc(list, type) return count; } +/* similar to count_buc(), but tallies all states at once + rather than looking for a specific type */ +STATIC_OVL void +tally_BUCX(list, bcp, ucp, ccp, xcp, ocp) +struct obj *list; +int *bcp, *ucp, *ccp, *xcp, *ocp; +{ + *bcp = *ucp = *ccp = *xcp = *ocp = 0; + for ( ; list; list = list->nobj) { + if (list->oclass == COIN_CLASS) { + ++(*ocp); /* "other" */ + continue; + } + /* priests always know bless/curse state */ + if (Role_if(PM_PRIEST)) list->bknown = 1; + + if (!list->bknown) + ++(*xcp); + else if (list->blessed) + ++(*bcp); + else if (list->cursed) + ++(*ccp); + else /* neither blessed nor cursed => uncursed */ + ++(*ucp); + } +} + long count_contents(container, nested, quantity, everything) struct obj *container; @@ -2189,7 +2217,18 @@ STATIC_OVL boolean this_type_only(obj) struct obj *obj; { - return (obj->oclass == this_type); + boolean res = (obj->oclass == this_type); + + if (obj->oclass != COIN_CLASS) { + switch (this_type) { + case 'B': res = (obj->bknown && obj->blessed); break; + case 'U': res = (obj->bknown && !(obj->blessed || obj->cursed)); break; + case 'C': res = (obj->bknown && obj->cursed); break; + case 'X': res = !obj->bknown; break; + default: break; /* use 'res' as-is */ + } + } + return res; } /* the 'I' command */ @@ -2200,6 +2239,7 @@ dotypeinv() int n, i = 0; char *extra_types, types[BUFSZ]; int class_count, oclass, unpaid_count, itemcount; + int bcnt, ccnt, ucnt, xcnt, ocnt; boolean billx = *u.ushops && doinvbill(0); menu_item *pick_list; boolean traditional = TRUE; @@ -2210,12 +2250,18 @@ dotypeinv() return 0; } unpaid_count = count_unpaid(invent); + tally_BUCX(invent, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt); + if (flags.menu_style != MENU_TRADITIONAL) { if (flags.menu_style == MENU_FULL || flags.menu_style == MENU_PARTIAL) { traditional = FALSE; i = UNPAID_TYPES; if (billx) i |= BILLED_TYPES; + if (bcnt) i |= BUC_BLESSED; + if (ucnt) i |= BUC_UNCURSED; + if (ccnt) i |= BUC_CURSED; + if (xcnt) i |= BUC_UNKNOWN; n = query_category(prompt, invent, i, &pick_list, PICK_ONE); if (!n) return 0; this_type = c = pick_list[0].item.a_int; @@ -2225,73 +2271,96 @@ dotypeinv() if (traditional) { /* collect a list of classes of objects carried, for use as a prompt */ types[0] = 0; - class_count = collect_obj_classes(types, invent, - FALSE, - (boolean FDECL((*),(OBJ_P))) 0, &itemcount); - if (unpaid_count) { - Strcat(types, "u"); - class_count++; - } - if (billx) { - Strcat(types, "x"); - class_count++; - } + class_count = collect_obj_classes(types, invent, FALSE, + (boolean FDECL((*),(OBJ_P))) 0, + &itemcount); + if (unpaid_count || billx || (bcnt + ccnt + ucnt + xcnt) != 0) + types[class_count++] = ' '; + if (unpaid_count) types[class_count++] = 'u'; + if (billx) types[class_count++] = 'x'; + if (bcnt) types[class_count++] = 'B'; + if (ucnt) types[class_count++] = 'U'; + if (ccnt) types[class_count++] = 'C'; + if (xcnt) types[class_count++] = 'X'; + types[class_count] = '\0'; /* add everything not already included; user won't see these */ extra_types = eos(types); *extra_types++ = '\033'; if (!unpaid_count) *extra_types++ = 'u'; if (!billx) *extra_types++ = 'x'; + if (!bcnt) *extra_types++ = 'B'; + if (!ucnt) *extra_types++ = 'U'; + if (!ccnt) *extra_types++ = 'C'; + if (!xcnt) *extra_types++ = 'X'; *extra_types = '\0'; /* for index() */ for (i = 0; i < MAXOCLASSES; i++) - if (!index(types, def_oc_syms[i].sym)) { - *extra_types++ = def_oc_syms[i].sym; - *extra_types = '\0'; - } + if (!index(types, def_oc_syms[i].sym)) { + *extra_types++ = def_oc_syms[i].sym; + *extra_types = '\0'; + } - if(class_count > 1) { - c = yn_function(prompt, types, '\0'); - savech(c); - if(c == '\0') { - clear_nhwindow(WIN_MESSAGE); - return 0; - } + if (class_count > 1) { + c = yn_function(prompt, types, '\0'); + savech(c); + if (c == '\0') { + clear_nhwindow(WIN_MESSAGE); + return 0; + } } else { - /* only one thing to itemize */ - if (unpaid_count) - c = 'u'; - else if (billx) - c = 'x'; - else - c = types[0]; + /* only one thing to itemize */ + if (unpaid_count) + c = 'u'; + else if (billx) + c = 'x'; + else + c = types[0]; } } - if (c == 'x') { + if (c == 'x' || (c == 'X' && billx && !xcnt)) { if (billx) - (void) doinvbill(1); - else - pline("No used-up objects on your shopping bill."); + (void) doinvbill(1); + else + pline("No used-up objects%s.", + unpaid_count ? " on your shopping bill" : ""); return 0; } - if (c == 'u') { + if (c == 'u' || (c == 'U' && unpaid_count && !ucnt)) { if (unpaid_count) - dounpaid(); + dounpaid(); else - You("are not carrying any unpaid objects."); + You("are not carrying any unpaid objects."); return 0; } if (traditional) { - oclass = def_char_to_objclass(c); /* change to object class */ - if (oclass == COIN_CLASS) { - return doprgold(); - } else if (index(types, c) > index(types, '\033')) { - You("have no such objects."); - return 0; + if (index("BUCX", c)) + oclass = c; /* not a class but understood by this_type_only() */ + else + oclass = def_char_to_objclass(c); /* change to object class */ + + if (oclass == COIN_CLASS) + return doprgold(); + if (index(types, c) > index(types, '\033')) { + /* '> ESC' => "hidden choice", something known not to be carried */ + const char *which = 0; + + switch (c) { + case 'B': which = "known to be blessed"; break; + case 'U': which = "known to be uncursed"; break; + case 'C': which = "known to be cursed"; break; + case 'X': You( + "have no objects whose blessed/uncursed/cursed status is unknown."); + break; /* better phrasing is desirable */ + default: which = "such"; break; + } + if (which) + You("have no %s objects.", which); + return 0; } this_type = oclass; } if (query_objlist((char *) 0, invent, - (flags.invlet_constant ? USE_INVLET : 0)|INVORDER_SORT, - &pick_list, PICK_NONE, this_type_only) > 0) + (flags.invlet_constant ? USE_INVLET : 0)|INVORDER_SORT, + &pick_list, PICK_NONE, this_type_only) > 0) free((genericptr_t)pick_list); return 0; } diff --git a/win/X11/winX.c b/win/X11/winX.c index 85852598d..203822595 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -1,4 +1,4 @@ -/* NetHack 3.5 winX.c $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */ +/* NetHack 3.5 winX.c $NHDT-Date: 1430040327 2015/04/26 09:25:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.28 $ */ /* NetHack 3.5 winX.c $Date: 2012/01/24 04:26:26 $ $Revision: 1.27 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -1532,6 +1532,7 @@ static char yn_esc_map; /* ESC maps to this char. */ static Widget yn_popup; /* popup for the yn fuction (created once) */ static Widget yn_label; /* label for yn function (created once) */ static boolean yn_getting_num; /* TRUE if accepting digits */ +static boolean yn_preserve_case; /* default is to force yn to lower case */ static int yn_ndigits; /* digit count */ static long yn_val; /* accumulated value */ @@ -1604,7 +1605,8 @@ yn_key(w, event, params, num_params) if (!yn_choices) { /* accept any input */ yn_return = ch; } else { - ch = lowc(ch); /* move to lower case */ + if (!yn_preserve_case) + ch = lowc(ch); /* move to lower case */ if (ch == '\033') { yn_getting_num = FALSE; @@ -1664,6 +1666,7 @@ X11_yn_function(ques, choices, def) yn_choices = choices; /* set up globals for callback to use */ yn_def = def; + yn_preserve_case = !choices; /* preserve when arbitrary response allowed */ /* * This is sort of a kludge. There are quite a few places in the main @@ -1679,6 +1682,14 @@ X11_yn_function(ques, choices, def) char *cb, choicebuf[QBUFSZ]; Strcpy(choicebuf, choices); /* anything beyond is hidden */ + /* default when choices are present is to force yn answer to + lowercase unless one or more choices are explicitly uppercase; + check this before stripping the hidden choices */ + for (cb = choicebuf; *cb; ++cb) + if ('A' <= *cb && *cb <= 'Z') { + yn_preserve_case = TRUE; + break; + } if ((cb = index(choicebuf, '\033')) != 0) *cb = '\0'; /* ques [choices] (def) */ if ((int)(1 + strlen(ques) + 2 + strlen(choicebuf) + 4) >= BUFSZ) diff --git a/win/tty/topl.c b/win/tty/topl.c index cc4df15d5..dbeea75dd 100644 --- a/win/tty/topl.c +++ b/win/tty/topl.c @@ -1,4 +1,4 @@ -/* NetHack 3.5 topl.c $NHDT-Date: 1425081315 2015/02/27 23:55:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.24 $ */ +/* NetHack 3.5 topl.c $NHDT-Date: 1430040322 2015/04/26 09:25:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.29 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -333,7 +333,7 @@ char def; { register char q; char rtmp[40]; - boolean digit_ok, allow_num; + boolean digit_ok, allow_num, preserve_case = FALSE; struct WinDesc *cw = wins[WIN_MESSAGE]; boolean doprev = 0; char prompt[BUFSZ]; @@ -347,6 +347,14 @@ char def; allow_num = (index(resp, '#') != 0); Strcpy(respbuf, resp); + /* normally we force lowercase, but if any uppercase letters + are present in the allowed response, preserve case; + check this before stripping the hidden choices */ + for (rb = respbuf; *rb; ++rb) + if ('A' <= *rb && *rb <= 'Z') { + preserve_case = TRUE; + break; + } /* any acceptable responses that follow aren't displayed */ if ((rb = index(respbuf, '\033')) != 0) *rb = '\0'; (void)strncpy(prompt, query, QBUFSZ-1); @@ -358,13 +366,16 @@ char def; Strcat(prompt, " "); pline("%s", prompt); } else { + /* no restriction on allowed response, so always preserve case */ + /* preserve_case = TRUE; -- moot since we're jumping to the end */ pline("%s ", query); q = readchar(); goto clean_up; } do { /* loop until we get valid input */ - q = lowc(readchar()); + q = readchar(); + if (!preserve_case) q = lowc(q); if (q == '\020') { /* ctrl-P */ if (iflags.prevmsg_window != 's') { int sav = ttyDisplay->inread; @@ -422,7 +433,8 @@ char def; q = '#'; } do { /* loop until we get a non-digit */ - z = lowc(readchar()); + z = readchar(); + if (!preserve_case) z = lowc(z); if (digit(z)) { value = (10 * value) + (z - '0'); if (value < 0) break; /* overflow: try again */