Hi,

after getting negative responses, I decided to start a wheezy
maintenance branch and only cherry-pick the important fixes.
The attached diff has been cleaned off "RCS ID" and other
version numbering only noise from comments, and diffs the
patched source + debian/ not the quilt patches, for easier
review.

The package's otherwise in a good shape, built everywhere,
I've been using the new version for a while, etc. (and even
the klibc version is safe, as longjmp is never passed 0).

Changes:

* Fix CONSERVATIVE_FDS: the definition was missing in one
  case and silently ignored in another due to use of the
  macro before its implicit definition; also add this fact
  to the lksh(1) manpage

* Correct a regression wrt. tab completion, at least two
  other bugs in the same code, and the same bug class in
  similar code (e.g. inline-expansion with Esc+*) that
  could lead to unrelated input on the current command
  line being overwritten (and sanitise int into size_t,
  for 64-bit cleanliness), upstream bug LP#1025843

Thanks in advance,
//mirabilos
-- 
13:37⎜«Natureshadow» Deep inside, I hate mirabilos. I mean, he's a good
guy. But he's always right! In every fsckin' situation, he's right. Even
with his deeply perverted taste in software and borked ambition towards
broken OSes - in the end, he's damn right about it :(! […] works in mksh
--- mksh-40.9.20120630-1/Build.sh       2012-06-28 20:18:21.000000000 +0000
+++ mksh-40.9.20120630-2/Build.sh       2012-07-24 09:54:20.000000000 +0000
@@ -414,6 +414,7 @@ else
        check_categories="$check_categories shell:legacy-yes"
        add_cppflags -DMKSH_LEGACY_MODE
        HAVE_PERSISTENT_HISTORY=0
+       HAVE_ISSET_MKSH_CONSERVATIVE_FDS=1      # from sh.h
 fi
 
 if test x"$srcdir" = x"."; then
--- mksh-40.9.20120630-1/debian/changelog       2012-06-30 17:34:53.000000000 
+0000
+++ mksh-40.9.20120630-2/debian/changelog       2012-07-20 23:33:59.000000000 
+0000
@@ -1,3 +1,14 @@
+mksh (40.9.20120630-2) unstable; urgency=low
+
+  * The “kutweer” upload
+  * Apply cherry-picked fixes from mksh CVS (branch mksh-wheezy):
+    - [tg] Fix CONSERVATIVE_FDS use-before-definition bug
+    - [tg] Correct a regression when tab-completing (LP#1025843) and fix
+      bugs in the same code wrt. completion display and other expansions
+  * Document use of CONSERVATIVE_FDS in lksh manpage
+
+ -- Thorsten Glaser <[email protected]>  Fri, 20 Jul 2012 23:32:37 +0000
+
 mksh (40.9.20120630-1) unstable; urgency=low
 
   * The “GC2TDN7” upload
--- mksh-40.9.20120630-1/debian/lksh.1  2012-06-30 17:25:00.000000000 +0000
+++ mksh-40.9.20120630-2/debian/lksh.1  2012-07-20 23:34:00.000000000 +0000
@@ -223,6 +223,9 @@ but might work on 32-bit and 64-bit
 .Vt long
 types
 .Pc .
+.It
+.Nm
+only offers the traditional ten file descriptors to scripts.
 .El
 .Sh SEE ALSO
 .Xr mksh 1
@@ -262,4 +265,8 @@ or the
 IRC channel at
 .Pa irc.freenode.net
 .Pq Port 6697 SSL, 6667 unencrypted
-if you need any further quirks.
+if you need any further quirks or assistance,
+and consider migrating your legacy scripts to work with
+.Nm mksh
+instead of requiring
+.Nm .
--- mksh-40.9.20120630-1/edit.c 2012-05-05 17:33:19.000000000 +0000
+++ mksh-40.9.20120630-2/edit.c 2012-07-24 09:54:20.000000000 +0000
@@ -76,6 +76,8 @@ static int x_do_comment(char *, ssize_t,
 static void x_print_expansions(int, char *const *, bool);
 static int x_cf_glob(int *, const char *, int, int, int *, int *, char ***);
 static size_t x_longest_prefix(int, char *const *);
+static void x_glob_hlp_add_qchar(char *);
+static void x_glob_hlp_rem_qchar(char *);
 static int x_basename(const char *, const char *);
 static void x_free_words(int, char **);
 static int x_escape(const char *, size_t, int (*)(const char *, size_t));
@@ -281,50 +283,78 @@ x_print_expansions(int nwords, char * co
                XPfree(l);
 }
 
-/**
- * Do file globbing:
- *     - appends * to (copy of) str if no globbing chars found
- *     - does expansion, checks for no match, etc.
- *     - sets *wordsp to array of matching strings
- *     - returns number of matching strings
+/*
+ * Convert backslash-escaped string to QCHAR-escaped
+ * string useful for globbing; loses QCHAR unless it
+ * can squeeze in, eg. by previous loss of backslash
  */
-static int
-x_file_glob(int flags MKSH_A_UNUSED, char *toglob, char ***wordsp)
+static void
+x_glob_hlp_add_qchar(char *cp)
 {
-       char ch, **words;
-       int nwords, i = 0, idx = 0;
-       bool escaping;
-       XPtrV w;
-       struct source *s, *sold;
+       char ch, *dp = cp;
+       bool escaping = false;
 
-       /* remove all escaping backward slashes */
-       escaping = false;
-       while ((ch = toglob[i++])) {
+       while ((ch = *cp++)) {
                if (ch == '\\' && !escaping) {
                        escaping = true;
                        continue;
                }
-               if (escaping) {
+               if (escaping || (ch == QCHAR && (cp - dp) > 1)) {
                        /*
                         * empirically made list of chars to escape
-                        * for globbing; ASCII 0x02 probably too as
-                        * that's what QCHAR is, but...
+                        * for globbing as well as QCHAR itself
                         */
                        switch (ch) {
+                       case QCHAR:
                        case '$':
                        case '*':
                        case '?':
                        case '[':
                        case '\\':
                        case '`':
-                               toglob[idx++] = QCHAR;
+                               *dp++ = QCHAR;
                                break;
                        }
                        escaping = false;
                }
-               toglob[idx++] = ch;
+               *dp++ = ch;
        }
-       toglob[idx] = '\0';
+       *dp = '\0';
+}
+
+/*
+ * Unescape a QCHAR-escaped string
+ */
+static void
+x_glob_hlp_rem_qchar(char *cp)
+{
+       char ch, *dp = cp;
+
+       while ((ch = *cp++)) {
+               if (ch == QCHAR && !(ch = *cp++))
+                       break;
+               *dp++ = ch;
+       }
+       *dp = '\0';
+}
+
+/**
+ * Do file globbing:
+ *     - appends * to (copy of) str if no globbing chars found
+ *     - does expansion, checks for no match, etc.
+ *     - sets *wordsp to array of matching strings
+ *     - returns number of matching strings
+ */
+static int
+x_file_glob(int flags MKSH_A_UNUSED, char *toglob, char ***wordsp)
+{
+       char **words;
+       int nwords;
+       XPtrV w;
+       struct source *s, *sold;
+
+       /* remove all escaping backward slashes */
+       x_glob_hlp_add_qchar(toglob);
 
        /*
         * Convert "foo*" (toglob) to an array of strings (words)
@@ -350,13 +380,7 @@ x_file_glob(int flags MKSH_A_UNUSED, cha
                struct stat statb;
 
                /* Drop all QCHAR from toglob for strcmp below */
-               i = 0;
-               idx = 0;
-               while ((ch = toglob[i++])) {
-                       if (ch != QCHAR)
-                               toglob[idx++] = ch;
-               }
-               toglob[idx] = '\0';
+               x_glob_hlp_rem_qchar(toglob);
 
                /*
                 * Check if globbing failed (returned glob pattern),
@@ -915,9 +939,9 @@ static int holdlen;         /* length of holdbu
 static bool prompt_redraw;     /* false if newline forced after prompt */
 
 static int x_ins(const char *);
-static void x_delete(int, int);
-static int x_bword(void);
-static int x_fword(int);
+static void x_delete(size_t, bool);
+static size_t x_bword(void);
+static size_t x_fword(bool);
 static void x_goto(char *);
 static void x_bs3(char **);
 static int x_size_str(char *);
@@ -949,6 +973,7 @@ static int x_fold_case(int);
 #endif
 static char *x_lastcp(void);
 static void do_complete(int, Comp_type);
+static size_t x_nb2nc(size_t);
 
 static int unget_char = -1;
 
@@ -1067,6 +1092,17 @@ static struct x_defbindings const x_defb
 #endif
 };
 
+static size_t
+x_nb2nc(size_t nb)
+{
+       char *cp;
+       size_t nc = 0;
+
+       for (cp = xcp; cp < (xcp + nb); ++nc)
+               cp += utf_ptradj(cp);
+       return (nc);
+}
+
 #ifdef MKSH_SMALL
 static void x_modified(void);
 static void
@@ -1329,7 +1365,7 @@ x_ins(const char *s)
 static int
 x_del_back(int c MKSH_A_UNUSED)
 {
-       int i = 0;
+       ssize_t i = 0;
 
        if (xcp == xbuf) {
                x_e_putc2(7);
@@ -1346,7 +1382,7 @@ static int
 x_del_char(int c MKSH_A_UNUSED)
 {
        char *cp, *cp2;
-       int i = 0;
+       ssize_t i = 0;
 
        cp = xcp;
        while (i < x_arg) {
@@ -1367,9 +1403,9 @@ x_del_char(int c MKSH_A_UNUSED)
 
 /* Delete nc chars to the right of the cursor (including cursor position) */
 static void
-x_delete(int nc, int push)
+x_delete(size_t nc, bool push)
 {
-       int i, nb, nw;
+       size_t i, nb, nw;
        char *cp;
 
        if (nc == 0)
@@ -1453,21 +1489,21 @@ x_mv_bword(int c MKSH_A_UNUSED)
 static int
 x_mv_fword(int c MKSH_A_UNUSED)
 {
-       x_fword(1);
+       x_fword(true);
        return (KSTD);
 }
 
 static int
 x_del_fword(int c MKSH_A_UNUSED)
 {
-       x_delete(x_fword(0), true);
+       x_delete(x_fword(false), true);
        return (KSTD);
 }
 
-static int
+static size_t
 x_bword(void)
 {
-       int nc = 0, nb = 0;
+       size_t nb = 0;
        char *cp = xcp;
 
        if (cp == xbuf) {
@@ -1485,16 +1521,14 @@ x_bword(void)
                }
        }
        x_goto(cp);
-       for (cp = xcp; cp < (xcp + nb); ++nc)
-               cp += utf_ptradj(cp);
-       return (nc);
+       return (x_nb2nc(nb));
 }
 
-static int
-x_fword(int move)
+static size_t
+x_fword(bool move)
 {
-       int nc = 0;
-       char *cp = xcp, *cp2;
+       size_t nc;
+       char *cp = xcp;
 
        if (cp == xep) {
                x_e_putc2(7);
@@ -1506,8 +1540,7 @@ x_fword(int move)
                while (cp != xep && !is_mfs(*cp))
                        cp++;
        }
-       for (cp2 = xcp; cp2 < cp; ++nc)
-               cp2 += utf_ptradj(cp2);
+       nc = x_nb2nc(cp - xcp);
        if (move)
                x_goto(cp);
        return (nc);
@@ -2195,20 +2228,18 @@ x_meta2(int c MKSH_A_UNUSED)
 static int
 x_kill(int c MKSH_A_UNUSED)
 {
-       int col = xcp - xbuf;
-       int lastcol = xep - xbuf;
-       int ndel;
-
-       if (x_arg_defaulted)
-               x_arg = lastcol;
-       else if (x_arg > lastcol)
-               x_arg = lastcol;
-       ndel = x_arg - col;
-       if (ndel < 0) {
-               x_goto(xbuf + x_arg);
-               ndel = -ndel;
-       }
-       x_delete(ndel, true);
+       size_t col = xcp - xbuf;
+       size_t lastcol = xep - xbuf;
+       size_t ndel, narg;
+
+       if (x_arg_defaulted || (narg = x_arg) > lastcol)
+               narg = lastcol;
+       if (narg < col) {
+               x_goto(xbuf + narg);
+               ndel = col - narg;
+       } else
+               ndel = narg - col;
+       x_delete(x_nb2nc(ndel), true);
        return (KSTD);
 }
 
@@ -2256,7 +2287,7 @@ x_meta_yank(int c MKSH_A_UNUSED)
        }
        len = strlen(killstack[killtp]);
        x_goto(xcp - len);
-       x_delete(len, false);
+       x_delete(x_nb2nc(len), false);
        do {
                if (killtp == 0)
                        killtp = KILLSIZE - 1;
@@ -2576,7 +2607,7 @@ x_set_mark(int c MKSH_A_UNUSED)
 static int
 x_kill_region(int c MKSH_A_UNUSED)
 {
-       int rsize;
+       size_t rsize;
        char *xr;
 
        if (xmp == NULL) {
@@ -2591,7 +2622,7 @@ x_kill_region(int c MKSH_A_UNUSED)
                xr = xmp;
        }
        x_goto(xr);
-       x_delete(rsize, true);
+       x_delete(x_nb2nc(rsize), true);
        xmp = xr;
        return (KSTD);
 }
@@ -2684,7 +2715,7 @@ x_expand(int c MKSH_A_UNUSED)
                return (KSTD);
        }
        x_goto(xbuf + start);
-       x_delete(end - start, false);
+       x_delete(x_nb2nc(end - start), false);
 
        i = 0;
        while (i < nwords) {
@@ -2708,7 +2739,7 @@ do_complete(
 {
        char **words;
        int start, end, nlen, olen, nwords;
-       bool completed = false;
+       bool completed;
 
        nwords = x_cf_glob(&flags, xbuf, xep - xbuf, xcp - xbuf,
            &start, &end, &words);
@@ -2726,14 +2757,47 @@ do_complete(
        }
        olen = end - start;
        nlen = x_longest_prefix(nwords, words);
-       /* always complete */
-       x_goto(xbuf + start);
-       x_delete(olen, false);
-       x_escape(words[0], nlen, x_do_ins);
-       x_adjust();
-       /* check if we did add something */
-       if (xcp - (xbuf + start) > olen)
+       if (nwords == 1 || (flags & XCF_IS_SUBGLOB)) {
+               /*
+                * always complete the expansion of parameter and
+                * homedir substitution as well as single matches
+                */
                completed = true;
+       } else {
+               char *unescaped;
+
+               /* make a copy of the original string part and... */
+               strndupx(unescaped, xbuf + start, olen, ATEMP);
+               /* ... convert it from backslash-escaped via QCHAR-escaped... */
+               x_glob_hlp_add_qchar(unescaped);
+               /* ... to unescaped, for comparison with the matches */
+               x_glob_hlp_rem_qchar(unescaped);
+               /*
+                * match iff entire original string is part of the
+                * longest prefix, implying the latter is at least
+                * the same size (after unescaping)
+                */
+               completed = !strncmp(words[0], unescaped, strlen(unescaped));
+
+               afree(unescaped, ATEMP);
+       }
+       if (type == CT_COMPLIST && nwords > 1) {
+               /*
+                * print expansions, since we didn't get back
+                * just a single match
+                */
+               x_print_expansions(nwords, words,
+                   tobool(flags & XCF_IS_COMMAND));
+       }
+       if (completed) {
+               /* expand on the command line */
+               xmp = NULL;
+               xcp = xbuf + start;
+               xep -= olen;
+               memmove(xcp, xcp + olen, xep - xcp + 1);
+               x_escape(words[0], nlen, x_do_ins);
+       }
+       x_adjust();
        /*
         * append a space if this is a single non-directory match
         * and not a parameter or homedir substitution
@@ -2741,15 +2805,7 @@ do_complete(
        if (nwords == 1 && words[0][nlen - 1] != '/' &&
            !(flags & XCF_IS_SUBGLOB)) {
                x_ins(" ");
-               completed = true;
        }
-       if (type == CT_COMPLIST && !completed) {
-               x_print_expansions(nwords, words,
-                   tobool(flags & XCF_IS_COMMAND));
-               completed = true;
-       }
-       if (completed)
-               x_redraw(0);
 
        x_free_words(nwords, words);
 }
--- mksh-40.9.20120630-1/sh.h   2012-06-28 20:18:25.000000000 +0000
+++ mksh-40.9.20120630-2/sh.h   2012-07-24 09:54:20.000000000 +0000
@@ -412,15 +412,6 @@ extern int wcwidth(__WCHAR_TYPE__);
 #define BIT(i)         (1 << (i))
 #define NELEM(a)       (sizeof(a) / sizeof((a)[0]))
 
-/* these shall be smaller than 100 */
-#ifdef MKSH_CONSERVATIVE_FDS
-#define NUFILE         32      /* Number of user-accessible files */
-#define FDBASE         10      /* First file usable by Shell */
-#else
-#define NUFILE         56      /* Number of user-accessible files */
-#define FDBASE         24      /* First file usable by Shell */
-#endif
-
 /*
  * Make MAGIC a char that might be printed to make bugs more obvious, but
  * not a char that is used often. Also, can't use the high bit as it causes
@@ -545,6 +536,9 @@ im_sorry_dave(void)
 #ifndef MKSH_NO_CMDLINE_EDITING
 #define MKSH_NO_CMDLINE_EDITING        /* defined */
 #endif
+#ifndef MKSH_CONSERVATIVE_FDS
+#define MKSH_CONSERVATIVE_FDS  /* defined */
+#endif
 #undef MKSH_S_NOVI
 #define MKSH_S_NOVI            1
 #endif
@@ -569,6 +563,15 @@ im_sorry_dave(void)
 #define MKSH_UNEMPLOYED                1
 #endif
 
+/* these shall be smaller than 100 */
+#ifdef MKSH_CONSERVATIVE_FDS
+#define NUFILE         32      /* Number of user-accessible files */
+#define FDBASE         10      /* First file usable by Shell */
+#else
+#define NUFILE         56      /* Number of user-accessible files */
+#define FDBASE         24      /* First file usable by Shell */
+#endif
+
 /*
  * simple grouping allocator
  */

Reply via email to