]> granicus.if.org Git - nethack/commitdiff
readobjnam()'s "overlapping strcat"
authorPatR <rankin@nethack.org>
Sat, 14 Nov 2015 08:46:19 +0000 (00:46 -0800)
committerPatR <rankin@nethack.org>
Sat, 14 Nov 2015 08:46:19 +0000 (00:46 -0800)
Replace the code that uses strcat with two pointers into the same buffer.
Treated separately, they point at distinct strings (no overlap possible),
but the C standard does disallow that in order to enable optimizations
using block transfer or such, so the tool that complained about it isn't
wrong.  The characters getting appended to the output pointer can end
up overlapping the beginning of the other input pointer, conceivably
breaking an implementation that didn't use simple left-to-right byte-at-
a-time copying.

Also, I noticed that wishing for "luck stone" gave me a random gem.
There's code to strip off " stone" and compare against gem types, but it
prevents other code that accepts "foo bar" as a match for "foobar" and
vice versa from finding a match, since "luck" doesn't match anything
once "stone" is gone.  So add the four gray stones into the array of
alternate spellings.

Another bit:  it now accepts " gem" in addition to " stone" as optional
gem suffix, so "ruby", "ruby stone", and "ruby gem" all yield ruby.
("luck gem" won't work; you'll end up with a random gem-class object.)

And a last other bit:  wishing for "lamp (lit) named foo" would yield
an unlit, unnamed lamp because "(lit)" followed by anything didn't match
"(lit)" and threw away everything past the opening paren.  Now it will
produce "lamp named foo (lit)"--a lit lamp named "foo".  (Wishing for
"lamp named foo (lit)" produces an unlit lamp named "foo (lit)".  That's
acceptable to me... I'm not crawling any farther down this hole.  Maybe
object formatting should be changed to keep the lit attribute in front
of the name?)

src/objnam.c

index 3a1a66acb8446562083435a3c44251355ae37cd0..18d78fee141b5de49dfc366543c25c88e6c0585a 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 objnam.c        $NHDT-Date: 1446892450 2015/11/07 10:34:10 $  $NHDT-Branch: master $:$NHDT-Revision: 1.153 $ */
+/* NetHack 3.6 objnam.c        $NHDT-Date: 1447490776 2015/11/14 08:46:16 $  $NHDT-Branch: master $:$NHDT-Revision: 1.154 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -2364,6 +2364,13 @@ struct alt_spellings {
     { "grappling iron", GRAPPLING_HOOK },
     { "grapnel", GRAPPLING_HOOK },
     { "grapple", GRAPPLING_HOOK },
+    /* normally we wouldn't have to worry about unnecessary <space>, but
+       " stone" will get stripped off, preventing a wishymatch; that actually
+       lets "flint stone" be a match, so we also accept bogus "flintstone" */
+    { "luck stone", LUCKSTONE },
+    { "load stone", LOADSTONE },
+    { "touch stone", TOUCHSTONE },
+    { "flintstone", FLINT },
     { (const char *) 0, 0 },
 };
 
@@ -2429,7 +2436,6 @@ struct obj *no_wish;
      * "2 3 alarm chilis".  Currently this isn't allowed; options.c
      * automatically sticks 'candied' in front of such names.
      */
-
     char oclass;
     char *un, *dn, *actualn;
     const char *name = 0;
@@ -2556,36 +2562,45 @@ struct obj *no_wish;
     }
     if (!cnt)
         cnt = 1; /* %% what with "gems" etc. ? */
-    if (strlen(bp) > 1) {
-        if ((p = rindex(bp, '(')) != 0) {
-            if (p > bp && p[-1] == ' ')
-                p[-1] = 0;
-            else
-                *p = 0;
-            p++;
-            if (!strcmpi(p, "lit)")) {
-                islit = 1;
-            } else {
+    if (strlen(bp) > 1 && (p = rindex(bp, '(')) != 0) {
+        boolean keeptrailingchars = TRUE;
+
+        p[(p > bp && p[-1] == ' ') ? -1 : 0] = '\0'; /*terminate bp */
+        ++p; /* advance past '(' */
+        if (!strncmpi(p, "lit)", 4)) {
+            islit = 1;
+            p += 4 - 1; /* point at ')' */
+        } else {
+            spe = atoi(p);
+            while (digit(*p))
+                p++;
+            if (*p == ':') {
+                p++;
+                rechrg = spe;
                 spe = atoi(p);
                 while (digit(*p))
                     p++;
-                if (*p == ':') {
-                    p++;
-                    rechrg = spe;
-                    spe = atoi(p);
-                    while (digit(*p))
-                        p++;
-                }
-                if (*p != ')') {
-                    spe = rechrg = 0;
-                } else {
-                    spesgn = 1;
-                    p++;
-                    if (*p)
-                        Strcat(bp, p);
-                }
+            }
+            if (*p != ')') {
+                spe = rechrg = 0;
+                /* mis-matched parentheses; rest of string will be ignored
+                 * [probably we should restore everything back to '('
+                 * instead since it might be part of "named ..."]
+                 */
+                keeptrailingchars = FALSE;
+            } else {
+                spesgn = 1;
             }
         }
+        if (keeptrailingchars) {
+            char *pp = eos(bp);
+
+            /* 'pp' points at 'pb's terminating '\0',
+               'p' points at ')' and will be incremented past it */
+            do {
+                *pp++ = *++p;
+            } while (*p);
+        }
     }
     /*
      * otmp->spe is type schar, so we don't want spe to be any bigger or
@@ -2892,8 +2907,8 @@ retry:
             goto typfnd;
         }
 
-    if (!BSTRCMPI(bp, p - 6, " stone")) {
-        p[-6] = 0;
+    if (!BSTRCMPI(bp, p - 6, " stone") || !BSTRCMPI(bp, p - 4, " gem")) {
+        p[!strcmpi(p - 4, " gem") ? -4 : -6] = '\0';
         oclass = GEM_CLASS;
         dn = actualn = bp;
         goto srch;
@@ -2918,8 +2933,9 @@ retry:
                 goto typfnd;
             else
                 typ = 0; /* somebody changed objects[]? punt */
-        } else {         /* try to construct canonical form */
+        } else { /* try to construct canonical form */
             char tbuf[BUFSZ];
+
             Strcpy(tbuf, "worthless piece of ");
             Strcat(tbuf, g); /* assume it starts with the color */
             Strcpy(bp, tbuf);
@@ -2967,6 +2983,7 @@ srch:
     }
     if (actualn) {
         struct Jitem *j = Japanese_items;
+
         while (j->item) {
             if (actualn && !strcmpi(actualn, j->name)) {
                 typ = j->item;