about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
authorBart Schaefer <barts@users.sourceforge.net>2005-01-30 00:05:52 +0000
committerBart Schaefer <barts@users.sourceforge.net>2005-01-30 00:05:52 +0000
commit912826aeb6986cfb9d82291f749a7b226fccfee8 (patch)
tree7d6e3b465b8e48d9f46ccc8fdcf8781b54bd4742 /Src
parentafe0e139c8fb5acdbd1d744b9be3d7830302c144 (diff)
downloadzsh-912826aeb6986cfb9d82291f749a7b226fccfee8.tar.gz
zsh-912826aeb6986cfb9d82291f749a7b226fccfee8.tar.xz
zsh-912826aeb6986cfb9d82291f749a7b226fccfee8.zip
Patches from zsh-4.2.3-dev-1 that affect compilation or C code, excluding
any of those that introduce UTF-8 support.
Diffstat (limited to 'Src')
-rw-r--r--Src/Builtins/rlimits.awk18
-rw-r--r--Src/Builtins/rlimits.c698
-rw-r--r--Src/cond.c216
3 files changed, 628 insertions, 304 deletions
diff --git a/Src/Builtins/rlimits.awk b/Src/Builtins/rlimits.awk
index 5e48725e2..e1a06fe2b 100644
--- a/Src/Builtins/rlimits.awk
+++ b/Src/Builtins/rlimits.awk
@@ -6,7 +6,7 @@
 #
 BEGIN {limidx = 0}
 
-/^[\t ]*(#[\t ]*define[\t _]*RLIMIT_[A-Z_]*[\t ]*[0-9][0-9]*|RLIMIT_[A-Z_]*,[\t ]*)/ {
+/^[\t ]*(#[\t ]*define[\t _]*RLIMIT_[A-Z_]*[\t ]*[0-9][0-9]*|RLIMIT_[A-Z_]*,[\t ]*|RLIMIT_[A-Z_]*[\t ]*=[\t ]*[0-9][0-9]*,[\t ]*)/ {
     limindex = index($0, "RLIMIT_")
     limtail = substr($0, limindex, 80)
     split(limtail, tmp)
@@ -18,6 +18,11 @@ BEGIN {limidx = 0}
 	limindex = index($0, ",")
 	limnam = substr(limnam, 1, limindex-1)
     }
+    if (limnum == "=") {
+	limnum = limidx++
+	limindex = index($0, ",")
+	limnam = substr(limnam, 1, limindex-1)
+    }
     limrev[limnam] = limnum
     if (lim[limnum] == "") {
 	lim[limnum] = limnam
@@ -29,6 +34,7 @@ BEGIN {limidx = 0}
 	    if (limnam == "CPU")     { msg[limnum] = "Tcputime" }
 	    if (limnam == "DATA")    { msg[limnum] = "Mdatasize" }
 	    if (limnam == "FSIZE")   { msg[limnum] = "Mfilesize" }
+	    if (limnam == "LOCKS")   { msg[limnum] = "Nmaxfilelocks" }
 	    if (limnam == "MEMLOCK") { msg[limnum] = "Mmemorylocked" }
 	    if (limnam == "NOFILE")  { msg[limnum] = "Ndescriptors" }
 	    if (limnam == "NPROC")   { msg[limnum] = "Nmaxproc" }
@@ -39,6 +45,8 @@ BEGIN {limidx = 0}
 	    if (limnam == "STACK")   { msg[limnum] = "Mstacksize" }
 	    if (limnam == "TCACHE")  { msg[limnum] = "Ncachedthreads" }
 	    if (limnam == "VMEM")    { msg[limnum] = "Mvmemorysize" }
+	    if (limnam == "SIGPENDING") { msg[limnum] = "Nsigpending" }
+	    if (limnam == "MSGQUEUE") { msg[limnum] = "Nmsgqueue" }
         }
     }
 }
@@ -50,7 +58,13 @@ BEGIN {limidx = 0}
 }
 # in case of GNU libc
 /^[\t ]*RLIM_NLIMITS[\t ]*=[\t ]*RLIMIT_NLIMITS/ {
-    nlimits = limidx
+    if(!nlimits) { nlimits = limidx }
+}
+/^[\t ]*RLIM(IT)?_NLIMITS[\t ]*=[\t ]*[0-9][0-9]*/ {
+    limindex = index($0, "=")
+    limtail = substr($0, limindex, 80)
+    split(limtail, tmp)
+    nlimits = tmp[2]
 }
 
 END {
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index f81ce2412..9256f25b2 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -44,12 +44,17 @@ enum {
 
 # include "rlimits.h"
 
-# if defined(RLIM_T_IS_QUAD_T) || defined(RLIM_T_IS_LONG_LONG) || defined(RLIM_T_IS_UNSIGNED)
 static rlim_t
 zstrtorlimt(const char *s, char **t, int base)
 {
     rlim_t ret = 0;
- 
+
+    if (strcmp(s, "unlimited") == 0) {
+	if (t)
+	    *t = (char *) s + 9;
+	return RLIM_INFINITY;
+    }
+# if defined(RLIM_T_IS_QUAD_T) || defined(RLIM_T_IS_LONG_LONG) || defined(RLIM_T_IS_UNSIGNED)
     if (!base) {
 	if (*s != '0')
 	    base = 10;
@@ -67,63 +72,114 @@ zstrtorlimt(const char *s, char **t, int base)
 	    ret = ret * base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9);
     if (t)
 	*t = (char *)s;
-    return ret;
-}
 # else /* !RLIM_T_IS_QUAD_T && !RLIM_T_IS_LONG_LONG && !RLIM_T_IS_UNSIGNED */
-#  define zstrtorlimt(a, b, c)	zstrtol((a), (b), (c))
+    ret = zstrtol(s, t, base);
 # endif /* !RLIM_T_IS_QUAD_T && !RLIM_T_IS_LONG_LONG && !RLIM_T_IS_UNSIGNED */
-
-/* Display resource limits.  hard indicates whether `hard' or `soft'  *
- * limits should be displayed.  lim specifies the limit, or may be -1 *
- * to show all.                                                       */
+    return ret;
+}
 
 /**/
 static void
-showlimits(int hard, int lim)
+showlimitvalue(int lim, rlim_t val)
 {
-    int rt;
-    rlim_t val;
-
-    /* main loop over resource types */
-    for (rt = 0; rt != ZSH_NLIMITS; rt++)
-	if (rt == lim || lim == -1) {
-	    /* display limit for resource number rt */
-	    printf("%-16s", recs[rt]);
-	    val = (hard) ? limits[rt].rlim_max : limits[rt].rlim_cur;
-	    if (val == RLIM_INFINITY)
-		printf("unlimited\n");
-	    else if (limtype[rt] == ZLIMTYPE_TIME) {
-		/* time-type resource -- display as hours, minutes and
-		seconds. */
-		printf("%d:%02d:%02d\n", (int)(val / 3600),
-		       (int)(val / 60) % 60, (int)(val % 60));
-	    } else if (limtype[rt] == ZLIMTYPE_NUMBER || limtype[rt] == ZLIMTYPE_UNKNOWN) {
-		/* pure numeric resource */
-		printf("%d\n", (int)val);
-	    } else if (val >= 1024L * 1024L)
-		/* memory resource -- display with `K' or `M' modifier */
+    /* display limit for resource number lim */
+    if (lim < ZSH_NLIMITS)
+	printf("%-16s", recs[lim]);
+    else
+    {
+	/* Unknown limit, hence unknown units. */
+	printf("%-16d", lim);
+    }
+    if (val == RLIM_INFINITY)
+	printf("unlimited\n");
+    else if (lim >= ZSH_NLIMITS)
+    {
 # ifdef RLIM_T_IS_QUAD_T
-		printf("%qdMB\n", val / (1024L * 1024L));
-	    else
-		printf("%qdkB\n", val / 1024L);
+	printf("%qd\n", val);
 # else
 #  ifdef RLIM_T_IS_LONG_LONG
-		printf("%lldMB\n", val / (1024L * 1024L));
-            else
-		printf("%lldkB\n", val / 1024L);
+	printf("%lld\n", val);
 #  else
 #   ifdef RLIM_T_IS_UNSIGNED
-		printf("%luMB\n", val / (1024L * 1024L));
-            else
-		printf("%lukB\n", val / 1024L);
+	printf("%lu\n", val);
 #   else
-		printf("%ldMB\n", val / (1024L * 1024L));
-            else
-		printf("%ldkB\n", val / 1024L);
+	printf("%ld\n", val);
 #   endif /* RLIM_T_IS_UNSIGNED */
 #  endif /* RLIM_T_IS_LONG_LONG */
 # endif /* RLIM_T_IS_QUAD_T */
+    }
+    else if (limtype[lim] == ZLIMTYPE_TIME) {
+	/* time-type resource -- display as hours, minutes and
+	   seconds. */
+	printf("%d:%02d:%02d\n", (int)(val / 3600),
+	       (int)(val / 60) % 60, (int)(val % 60));
+    } else if (limtype[lim] == ZLIMTYPE_NUMBER ||
+	       limtype[lim] == ZLIMTYPE_UNKNOWN) {
+	/* pure numeric resource */
+	printf("%d\n", (int)val);
+    } else if (val >= 1024L * 1024L)
+	/* memory resource -- display with `K' or `M' modifier */
+# ifdef RLIM_T_IS_QUAD_T
+	printf("%qdMB\n", val / (1024L * 1024L));
+    else
+	printf("%qdkB\n", val / 1024L);
+# else
+#  ifdef RLIM_T_IS_LONG_LONG
+    printf("%lldMB\n", val / (1024L * 1024L));
+    else
+	printf("%lldkB\n", val / 1024L);
+#  else
+#   ifdef RLIM_T_IS_UNSIGNED
+    printf("%luMB\n", val / (1024L * 1024L));
+    else
+	printf("%lukB\n", val / 1024L);
+#   else
+    printf("%ldMB\n", val / (1024L * 1024L));
+    else
+	printf("%ldkB\n", val / 1024L);
+#   endif /* RLIM_T_IS_UNSIGNED */
+#  endif /* RLIM_T_IS_LONG_LONG */
+# endif /* RLIM_T_IS_QUAD_T */
+}
+
+/* Display resource limits.  hard indicates whether `hard' or `soft'  *
+ * limits should be displayed.  lim specifies the limit, or may be -1 *
+ * to show all.                                                       */
+
+/**/
+static int
+showlimits(char *nam, int hard, int lim)
+{
+    int rt;
+
+    if (lim >= ZSH_NLIMITS)
+    {
+	/*
+	 * Not configured into the shell.  Ask the OS
+	 * explicitly for this limit.
+	 */
+	struct rlimit vals;
+	if (getrlimit(lim, &vals) < 0)
+	{
+	    zwarnnam(nam, "can't read limit: %e", NULL, errno);
+	    return 1;
 	}
+	showlimitvalue(lim, hard ? vals.rlim_max : vals.rlim_cur);
+    }
+    else if (lim != -1)
+    {
+	showlimitvalue(lim, hard ? limits[lim].rlim_max :
+		       limits[lim].rlim_cur);
+    }
+    else
+    {
+	/* main loop over resource types */
+	for (rt = 0; rt != ZSH_NLIMITS; rt++)
+	    showlimitvalue(rt, (hard) ? limits[rt].rlim_max :
+			   limits[rt].rlim_cur);
+    }
+
+    return 0;
 }
 
 /* Display a resource limit, in ulimit style.  lim specifies which   *
@@ -131,121 +187,165 @@ showlimits(int hard, int lim)
  * soft limit should be displayed.                                   */
 
 /**/
-static void
-printulimit(int lim, int hard, int head)
+static int
+printulimit(char *nam, int lim, int hard, int head)
 {
     rlim_t limit;
 
     /* get the limit in question */
-    limit = (hard) ? limits[lim].rlim_max : limits[lim].rlim_cur;
+    if (lim >= ZSH_NLIMITS)
+    {
+	struct rlimit vals;
+
+	if (getrlimit(lim, &vals) < 0)
+	{
+	    zwarnnam(nam, "can't read limit: %e", NULL, errno);
+	    return 1;
+	}
+	limit = (hard) ? vals.rlim_max : vals.rlim_cur;
+    }
+    else
+	limit = (hard) ? limits[lim].rlim_max : limits[lim].rlim_cur;
     /* display the appropriate heading */
     switch (lim) {
-    case RLIMIT_CPU:
-	if (head)
-	    printf("cpu time (seconds)         ");
-	break;
-    case RLIMIT_FSIZE:
+    case RLIMIT_CORE:
 	if (head)
-	    printf("file size (blocks)         ");
+	    printf("-c: core file size (blocks)    ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 512;
 	break;
     case RLIMIT_DATA:
 	if (head)
-	    printf("data seg size (kbytes)     ");
+	    printf("-d: data seg size (kbytes)     ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
-    case RLIMIT_STACK:
+    case RLIMIT_FSIZE:
 	if (head)
-	    printf("stack size (kbytes)        ");
+	    printf("-f: file size (blocks)         ");
 	if (limit != RLIM_INFINITY)
-	    limit /= 1024;
+	    limit /= 512;
 	break;
-    case RLIMIT_CORE:
+# ifdef HAVE_RLIMIT_SIGPENDING
+    case RLIMIT_SIGPENDING:
+	if (head)
+	    printf("-i: pending signals            ");
+	break;
+# endif
+# ifdef HAVE_RLIMIT_MEMLOCK
+    case RLIMIT_MEMLOCK:
 	if (head)
-	    printf("core file size (blocks)    ");
+	    printf("-l: locked-in-memory size (kb) ");
 	if (limit != RLIM_INFINITY)
-	    limit /= 512;
+	    limit /= 1024;
 	break;
-# ifdef RLIMIT_RSS
+# endif /* HAVE_RLIMIT_MEMLOCK */
+/* If RLIMIT_VMEM and RLIMIT_RSS are defined and equal, avoid *
+ * duplicate case statement.  Observed on QNX Neutrino 6.1.0. */
+# if defined(HAVE_RLIMIT_RSS) && !defined(RLIMIT_VMEM_IS_RSS)
     case RLIMIT_RSS:
 	if (head)
-	    printf("resident set size (kbytes) ");
+	    printf("-m: resident set size (kbytes) ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
-# endif /* RLIMIT_RSS */
-# ifdef RLIMIT_MEMLOCK
-    case RLIMIT_MEMLOCK:
+# endif /* HAVE_RLIMIT_RSS */
+# if defined(HAVE_RLIMIT_VMEM) && defined(HAVE_RLIMIT_RSS) && defined(RLIMIT_VMEM_IS_RSS)
+    case RLIMIT_VMEM:
 	if (head)
-	    printf("locked-in-memory size (kb) ");
+	    printf("-m: memory size (kb)           ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
-# endif /* RLIMIT_MEMLOCK */
-# ifdef RLIMIT_NPROC
-    case RLIMIT_NPROC:
+# endif /* HAVE_RLIMIT_VMEM */
+# ifdef HAVE_RLIMIT_NOFILE
+    case RLIMIT_NOFILE:
 	if (head)
-	    printf("processes                  ");
+	    printf("-n: file descriptors           ");
 	break;
-# endif /* RLIMIT_NPROC */
-# ifdef RLIMIT_NOFILE
-    case RLIMIT_NOFILE:
+# endif /* HAVE_RLIMIT_NOFILE */
+# ifdef HAVE_RLIMIT_MSGQUEUE
+    case RLIMIT_MSGQUEUE:
 	if (head)
-	    printf("file descriptors           ");
+	    printf("-q: bytes in POSIX msg queues  ");
 	break;
-# endif /* RLIMIT_NOFILE */
-# ifdef RLIMIT_VMEM
-    case RLIMIT_VMEM:
+# endif
+    case RLIMIT_STACK:
 	if (head)
-	    printf("virtual memory size (kb)   ");
+	    printf("-s: stack size (kbytes)        ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
-# endif /* RLIMIT_VMEM */
-# if defined RLIMIT_AS && RLIMIT_AS != RLIMIT_VMEM
-    case RLIMIT_AS:
+    case RLIMIT_CPU:
+	if (head)
+	    printf("-t: cpu time (seconds)         ");
+	break;
+# ifdef HAVE_RLIMIT_NPROC
+    case RLIMIT_NPROC:
+	if (head)
+	    printf("-u: processes                  ");
+	break;
+# endif /* HAVE_RLIMIT_NPROC */
+# if defined(HAVE_RLIMIT_VMEM) && (!defined(HAVE_RLIMIT_RSS) || !defined(RLIMIT_VMEM_IS_RSS))
+    case RLIMIT_VMEM:
 	if (head)
-	    printf("address space (kb)         ");
+	    printf("-v: virtual memory size (kb)   ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
-# endif /* RLIMIT_AS */
-# ifdef RLIMIT_TCACHE
-    case RLIMIT_TCACHE:
+# endif /* HAVE_RLIMIT_VMEM */
+# if defined HAVE_RLIMIT_AS && !defined(RLIMIT_VMEM_IS_AS)
+    case RLIMIT_AS:
 	if (head)
-	    printf("cached threads             ");
+	    printf("-v: address space (kb)         ");
+	if (limit != RLIM_INFINITY)
+	    limit /= 1024;
 	break;
-# endif /* RLIMIT_TCACHE */
-# ifdef RLIMIT_AIO_OPS
-    case RLIMIT_AIO_OPS:
+# endif /* HAVE_RLIMIT_AS */
+# ifdef HAVE_RLIMIT_LOCKS
+    case RLIMIT_LOCKS:
 	if (head)
-	    printf("AIO operations             ");
+	    printf("-x: file locks                 ");
 	break;
-# endif /* RLIMIT_AIO_OPS */
-# ifdef RLIMIT_AIO_MEM
+# endif /* HAVE_RLIMIT_LOCKS */
+# ifdef HAVE_RLIMIT_AIO_MEM
     case RLIMIT_AIO_MEM:
 	if (head)
-	    printf("AIO locked-in-memory (kb)  ");
+	    printf("-N %2d: AIO locked-in-memory (kb) ", RLIMIT_AIO_MEM);
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
-# endif /* RLIMIT_AIO_MEM */
-# ifdef RLIMIT_SBSIZE
+# endif /* HAVE_RLIMIT_AIO_MEM */
+# ifdef HAVE_RLIMIT_AIO_OPS
+    case RLIMIT_AIO_OPS:
+	if (head)
+	    printf("-N %2d: AIO operations          ", RLIMIT_AIO_OPS);
+	break;
+# endif /* HAVE_RLIMIT_AIO_OPS */
+# ifdef HAVE_RLIMIT_TCACHE
+    case RLIMIT_TCACHE:
+	if (head)
+	    printf("-N %2d: cached threads          ", RLIMIT_TCACHE);
+	break;
+# endif /* HAVE_RLIMIT_TCACHE */
+# ifdef HAVE_RLIMIT_SBSIZE
     case RLIMIT_SBSIZE:
 	if (head)
-	    printf("socket buffer size (kb)    ");
+	    printf("-N %2d: socket buffer size (kb) ", RLIMIT_SBSIZE);
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
-# endif /* RLIMIT_SBSIZE */
-# ifdef RLIMIT_PTHREAD
+# endif /* HAVE_RLIMIT_SBSIZE */
+# ifdef HAVE_RLIMIT_PTHREAD
     case RLIMIT_PTHREAD:
 	if (head)
-	    printf("threads per process        ");
+	    printf("-N %2d: threads per process     ", RLIMIT_PTHREAD);
+	break;
+# endif /* HAVE_RLIMIT_PTHREAD */
+    default:
+	if (head)
+	    printf("-N %2d:                         ", lim);
 	break;
-# endif /* RLIMIT_PTHREAD */
     }
     /* display the limit */
     if (limit == RLIM_INFINITY)
@@ -265,6 +365,93 @@ printulimit(int lim, int hard, int head)
 #  endif /* RLIM_T_IS_LONG_LONG */
 # endif /* RLIM_T_IS_QUAD_T */
     }
+
+    return 0;
+}
+
+/**/
+static int
+do_limit(char *nam, int lim, rlim_t val, int hard, int soft, int set)
+{
+    if (lim >= ZSH_NLIMITS) {
+	struct rlimit vals;
+	if (getrlimit(lim, &vals) < 0)
+	{
+	    /* best guess about error */
+	    zwarnnam(nam, "can't read limit: %e", NULL, errno);
+	    return 1;
+	}
+	if (hard)
+	{
+	    if (val > vals.rlim_max && geteuid()) {
+		zwarnnam(nam, "can't raise hard limits", NULL, 0);
+		return 1;
+	    }
+	    vals.rlim_max = val;
+	    /*
+	     * not show if all systems will do this silently, but
+	     * best be safe...
+	     */
+	    if (val < vals.rlim_cur)
+		vals.rlim_cur = val;
+	}
+	if (soft || !hard) {
+	    if (val > vals.rlim_max) {
+		zwarnnam(nam, "limit exceeds hard limit", NULL, 0);
+		return 1;
+	    }
+	    else
+		vals.rlim_cur = val;
+	}
+	if (!set)
+	{
+	    zwarnnam(nam,
+		     "warning: unrecognised limit %d, use -s to set",
+		     NULL, lim);
+	    return 1;
+	}
+	else if (setrlimit(lim, &vals) < 0)
+	{
+	    zwarnnam(nam, "setrlimit failed: %e", NULL, errno);
+	    return 1;
+	}
+    } else {
+	/* new limit is valid and has been interpreted; apply it to the
+	specified resource */
+	if (hard) {
+	    /* can only raise hard limits if running as root */
+	    if (val > current_limits[lim].rlim_max && geteuid()) {
+		zwarnnam(nam, "can't raise hard limits", NULL, 0);
+		return 1;
+	    } else {
+		limits[lim].rlim_max = val;
+		if (val < limits[lim].rlim_cur)
+		    limits[lim].rlim_cur = val;
+	    }
+	}
+	if (soft || !hard) {
+	    if (val > limits[lim].rlim_max) {
+		/* no idea about this difference, don't intend to worry */
+		if (*nam == 'u')
+		{
+		    /* ulimit does this */
+		    if (val > current_limits[lim].rlim_max && geteuid()) {
+			zwarnnam(nam, "value exceeds hard limit", NULL, 0);
+			return 1;
+		    }
+		    limits[lim].rlim_max = limits[lim].rlim_cur = val;
+		} else {
+		    /* but limit does this */
+		    zwarnnam(nam, "limit exceeds hard limit", NULL, 0);
+		    return 1;
+		}
+	    } else
+		limits[lim].rlim_cur = val;
+	    if (set && zsetlimit(lim, "limit"))
+		return 1;
+	}
+    }
+    return 0;
 }
 
 /* limit: set or show resource limits.  The variable hard indicates *
@@ -272,46 +459,57 @@ printulimit(int lim, int hard, int head)
 
 /**/
 static int
-bin_limit(char *nam, char **argv, char *ops, int func)
+bin_limit(char *nam, char **argv, Options ops, UNUSED(int func))
 {
     char *s;
     int hard, limnum, lim;
     rlim_t val;
     int ret = 0;
 
-    hard = ops['h'];
-    if (ops['s'] && !*argv)
+    hard = OPT_ISSET(ops,'h');
+    if (OPT_ISSET(ops,'s') && !*argv)
 	return setlimits(NULL);
     /* without arguments, display limits */
-    if (!*argv) {
-	showlimits(hard, -1);
-	return 0;
-    }
+    if (!*argv)
+	return showlimits(nam, hard, -1);
     while ((s = *argv++)) {
 	/* Search for the appropriate resource name.  When a name matches (i.e. *
 	 * starts with) the argument, the lim variable changes from -1 to the   *
 	 * number of the resource.  If another match is found, lim goes to -2.  */
-	for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++)
-	    if (!strncmp(recs[limnum], s, strlen(s))) {
-		if (lim != -1)
-		    lim = -2;
-		else
-		    lim = limnum;
-	    }
+	if (idigit(*s))
+	{
+	    lim = (int)zstrtol(s, NULL, 10);
+	}
+	else
+	    for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++)
+		if (!strncmp(recs[limnum], s, strlen(s))) {
+		    if (lim != -1)
+			lim = -2;
+		    else
+			lim = limnum;
+		}
 	/* lim==-1 indicates that no matches were found.       *
 	 * lim==-2 indicates that multiple matches were found. */
 	if (lim < 0) {
-	    zwarnnam("limit",
+	    zwarnnam(nam,
 		     (lim == -2) ? "ambiguous resource specification: %s"
 		     : "no such resource: %s", s, 0);
 	    return 1;
 	}
 	/* without value for limit, display the current limit */
-	if (!(s = *argv++)) {
-	    showlimits(hard, lim);
-	    return 0;
+	if (!(s = *argv++))
+	    return showlimits(nam, hard, lim);
+	if (lim >= ZSH_NLIMITS)
+	{
+	    val = zstrtorlimt(s, &s, 10);
+	    if (*s)
+	    {
+		/* unknown limit, no idea how to scale */
+		zwarnnam(nam, "unknown scaling factor: %s", s, 0);
+		return 1;
+	    }
 	}
-	if (limtype[lim] == ZLIMTYPE_TIME) {
+	else if (limtype[lim] == ZLIMTYPE_TIME) {
 	    /* time-type resource -- may be specified as seconds, or minutes or *
 	     * hours with the `m' and `h' modifiers, and `:' may be used to add *
 	     * together more than one of these.  It's easier to understand from *
@@ -325,48 +523,83 @@ bin_limit(char *nam, char **argv, char *ops, int func)
 		else if (*s == ':')
 		    val = val * 60 + zstrtorlimt(s + 1, &s, 10);
 		else {
-		    zwarnnam("limit", "unknown scaling factor: %s", s, 0);
+		    zwarnnam(nam, "unknown scaling factor: %s", s, 0);
 		    return 1;
 		}
 	    }
 	} else if (limtype[lim] == ZLIMTYPE_NUMBER || limtype[lim] == ZLIMTYPE_UNKNOWN) {
 	    /* pure numeric resource -- only a straight decimal number is
 	    permitted. */
-	    val = zstrtorlimt(s, &s, 10);
+	    char *t = s;
+	    val = zstrtorlimt(t, &s, 10);
+	    if (s == t) {
+		zwarnnam(nam, "limit must be a number", NULL, 0);
+		return 1;
+	    }
 	} else {
 	    /* memory-type resource -- `k' and `M' modifiers are permitted,
 	    meaning (respectively) 2^10 and 2^20. */
 	    val = zstrtorlimt(s, &s, 10);
-	    if (!*s || ((*s == 'k' || *s == 'K') && !s[1]))
-		val *= 1024L;
-	    else if ((*s == 'M' || *s == 'm') && !s[1])
+	    if (!*s || ((*s == 'k' || *s == 'K') && !s[1])) {
+		if (val != RLIM_INFINITY)
+		    val *= 1024L;
+	    } else if ((*s == 'M' || *s == 'm') && !s[1])
 		val *= 1024L * 1024;
 	    else {
-		zwarnnam("limit", "unknown scaling factor: %s", s, 0);
+		zwarnnam(nam, "unknown scaling factor: %s", s, 0);
 		return 1;
 	    }
 	}
-	/* new limit is valid and has been interpreted; apply it to the
-	specified resource */
+	if (do_limit(nam, lim, val, hard, !hard, OPT_ISSET(ops, 's')))
+	    ret++;
+    }
+    return ret;
+}
+
+/**/
+static int
+do_unlimit(char *nam, int lim, int hard, int soft, int set, int euid)
+{
+    /* remove specified limit */
+    if (lim >= ZSH_NLIMITS) {
+	struct rlimit vals;
+	if (getrlimit(lim, &vals) < 0)
+	{
+	    zwarnnam(nam, "can't read limit: %e", NULL, errno);
+	    return 1;
+	}
 	if (hard) {
-	    /* can only raise hard limits if running as root */
-	    if (val > current_limits[lim].rlim_max && geteuid()) {
-		zwarnnam("limit", "can't raise hard limits", NULL, 0);
+	    if (euid && vals.rlim_max != RLIM_INFINITY) {
+		zwarnnam(nam, "can't remove hard limits", NULL, 0);
 		return 1;
-	    } else {
-		limits[lim].rlim_max = val;
-		if (val < limits[lim].rlim_cur)
-		    limits[lim].rlim_cur = val;
-	    }
-	} else if (val > limits[lim].rlim_max) {
-	    zwarnnam("limit", "limit exceeds hard limit", NULL, 0);
+	    } else
+		vals.rlim_max = RLIM_INFINITY;
+	}
+	if (!hard || soft)
+	    vals.rlim_cur = vals.rlim_max;
+	if (!set) {
+	    zwarnnam(nam,
+		     "warning: unrecognised limit %d, use -s to set",
+		     NULL, lim);
+	    return 1;
+	} else if (setrlimit(lim, &vals) < 0) {
+	    zwarnnam(nam, "setrlimit failed: %e", NULL, errno);
+	    return 1;
+	}
+    } else {
+	if (hard) {
+	    if (euid && current_limits[lim].rlim_max != RLIM_INFINITY) {
+		zwarnnam(nam, "can't remove hard limits", NULL, 0);
+		return 1;
+	    } else
+		limits[lim].rlim_max = RLIM_INFINITY;
+	}
+	if (!hard || soft)
+	    limits[lim].rlim_cur = limits[lim].rlim_max;
+	if (set && zsetlimit(lim, nam))
 	    return 1;
-	} else
-	    limits[lim].rlim_cur = val;
-	if (ops['s'] && zsetlimit(lim, "limit"))
-	    ret++;
     }
-    return ret;
+    return 0;
 }
 
 /* unlimit: remove resource limits.  Much of this code is the same as *
@@ -374,13 +607,13 @@ bin_limit(char *nam, char **argv, char *ops, int func)
 
 /**/
 static int
-bin_unlimit(char *nam, char **argv, char *ops, int func)
+bin_unlimit(char *nam, char **argv, Options ops, UNUSED(int func))
 {
     int hard, limnum, lim;
     int ret = 0;
     uid_t euid = geteuid();
 
-    hard = ops['h'];
+    hard = OPT_ISSET(ops,'h');
     /* Without arguments, remove all limits. */
     if (!*argv) {
 	for (limnum = 0; limnum != RLIM_NLIMITS; limnum++) {
@@ -392,7 +625,7 @@ bin_unlimit(char *nam, char **argv, char *ops, int func)
 	    } else
 		limits[limnum].rlim_cur = limits[limnum].rlim_max;
 	}
-	if (ops['s'])
+	if (OPT_ISSET(ops,'s'))
 	    ret += setlimits(nam);
 	if (ret)
 	    zwarnnam(nam, "can't remove hard limits", NULL, 0);
@@ -402,13 +635,17 @@ bin_unlimit(char *nam, char **argv, char *ops, int func)
 	     * matches (i.e. starts with) the argument, the lim variable  *
 	     * changes from -1 to the number of the resource.  If another *
 	     * match is found, lim goes to -2.                            */
-	    for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++)
-		if (!strncmp(recs[limnum], *argv, strlen(*argv))) {
-		    if (lim != -1)
-			lim = -2;
-		    else
-			lim = limnum;
-		}
+	    if (idigit(**argv)) {
+		lim = (int)zstrtol(*argv, NULL, 10);
+	    } else {
+		for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++)
+		    if (!strncmp(recs[limnum], *argv, strlen(*argv))) {
+			if (lim != -1)
+			    lim = -2;
+			else
+			    lim = limnum;
+		    }
+	    }
 	    /* lim==-1 indicates that no matches were found.       *
 	     * lim==-2 indicates that multiple matches were found. */
 	    if (lim < 0) {
@@ -417,16 +654,8 @@ bin_unlimit(char *nam, char **argv, char *ops, int func)
 			 : "no such resource: %s", *argv, 0);
 		return 1;
 	    }
-	    /* remove specified limit */
-	    if (hard) {
-		if (euid && current_limits[lim].rlim_max != RLIM_INFINITY) {
-		    zwarnnam(nam, "can't remove hard limits", NULL, 0);
-		    ret++;
-		} else
-		    limits[lim].rlim_max = RLIM_INFINITY;
-	    } else
-		limits[lim].rlim_cur = limits[lim].rlim_max;
-	    if (ops['s'] && zsetlimit(lim, nam))
+	    else if (do_unlimit(nam, lim, hard, !hard, OPT_ISSET(ops, 's'),
+				euid))
 		ret++;
 	}
     }
@@ -437,9 +666,9 @@ bin_unlimit(char *nam, char **argv, char *ops, int func)
 
 /**/
 static int
-bin_ulimit(char *name, char **argv, char *ops, int func)
+bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
 {
-    int res, resmask = 0, hard = 0, soft = 0, nres = 0;
+    int res, resmask = 0, hard = 0, soft = 0, nres = 0, all = 0, ret = 0;
     char *options;
 
     do {
@@ -462,12 +691,29 @@ bin_ulimit(char *name, char **argv, char *ops, int func)
 		case 'S':
 		    soft = 1;
 		    continue;
+		case 'N':
+		    if (options[1]) {
+			res = (int)zstrtol(options+1, NULL, 10);
+		    } else if (*argv) {
+			res = (int)zstrtol(*argv++, NULL, 10);
+		    } else {
+			zwarnnam(name, "number required after -N",
+				 NULL, 0);
+			return 1;
+		    }
+		    /*
+		     * fake it so it looks like we just finished an option...
+		     */
+		    while (options[1])
+			options++;
+		    break;
 		case 'a':
-		    if (*argv || options[1] || resmask) {
-			zwarnnam(name, "no arguments required after -a",
+		    if (resmask) {
+			zwarnnam(name, "no limits allowed with -a",
 				 NULL, 0);
 			return 1;
 		    }
+		    all = 1;
 		    resmask = (1 << RLIM_NLIMITS) - 1;
 		    nres = RLIM_NLIMITS;
 		    continue;
@@ -486,31 +732,50 @@ bin_ulimit(char *name, char **argv, char *ops, int func)
 		case 'c':
 		    res = RLIMIT_CORE;
 		    break;
-# ifdef RLIMIT_RSS
+# ifdef HAVE_RLIMIT_RSS
 		case 'm':
 		    res = RLIMIT_RSS;
 		    break;
-# endif /* RLIMIT_RSS */
-# ifdef RLIMIT_MEMLOCK
+# endif /* HAVE_RLIMIT_RSS */
+# ifdef HAVE_RLIMIT_MEMLOCK
 		case 'l':
 		    res = RLIMIT_MEMLOCK;
 		    break;
-# endif /* RLIMIT_MEMLOCK */
-# ifdef RLIMIT_NOFILE
+# endif /* HAVE_RLIMIT_MEMLOCK */
+# ifdef HAVE_RLIMIT_NOFILE
 		case 'n':
 		    res = RLIMIT_NOFILE;
 		    break;
-# endif /* RLIMIT_NOFILE */
-# ifdef RLIMIT_NPROC
+# endif /* HAVE_RLIMIT_NOFILE */
+# ifdef HAVE_RLIMIT_NPROC
 		case 'u':
 		    res = RLIMIT_NPROC;
 		    break;
-# endif /* RLIMIT_NPROC */
-# ifdef RLIMIT_VMEM
+# endif /* HAVE_RLIMIT_NPROC */
+# if defined(HAVE_RLIMIT_VMEM) || defined(HAVE_RLIMIT_AS)
 		case 'v':
+#  ifdef HAVE_RLIMIT_VMEM
 		    res = RLIMIT_VMEM;
+#  else
+		    res = RLIMIT_AS;
+#  endif
+		    break;
+# endif /* HAVE_RLIMIT_VMEM */
+# ifdef HAVE_RLIMIT_LOCKS
+		case 'x':
+		    res = RLIMIT_LOCKS;
+		    break;
+# endif
+# ifdef HAVE_RLIMIT_SIGPENDING
+		case 'i':
+		    res = RLIMIT_SIGPENDING;
+		    break;
+# endif
+# ifdef HAVE_RLIMIT_MSGQUEUE
+		case 'q':
+		    res = RLIMIT_MSGQUEUE;
 		    break;
-# endif /* RLIMIT_VMEM */
+# endif
 		default:
 		    /* unrecognised limit */
 		    zwarnnam(name, "bad option: -%c", NULL, *options);
@@ -520,6 +785,11 @@ bin_ulimit(char *name, char **argv, char *ops, int func)
 		    resmask |= 1 << res;
 		    nres++;
 		}
+		if (all && res != -1) {
+		    zwarnnam(name, "no limits allowed with -a",
+			     NULL, 0);
+		    return 1;
+		}
 	    }
 	}
 	if (!*argv || **argv == '-') {
@@ -533,6 +803,10 @@ bin_ulimit(char *name, char **argv, char *ops, int func)
 	    nres++;
 	    continue;
 	}
+	if (all) {
+	    zwarnnam(name, "no arguments allowed after -a", NULL, 0);
+	    return 1;
+	}
 	if (res < 0)
 	    res = RLIMIT_FSIZE;
 	if (strcmp(*argv, "unlimited")) {
@@ -548,65 +822,39 @@ bin_ulimit(char *name, char **argv, char *ops, int func)
 		break;
 	    case RLIMIT_DATA:
 	    case RLIMIT_STACK:
-# ifdef RLIMIT_RSS
+# ifdef HAVE_RLIMIT_RSS
 	    case RLIMIT_RSS:
-# endif /* RLIMIT_RSS */
-# ifdef RLIMIT_MEMLOCK
+# endif /* HAVE_RLIMIT_RSS */
+# ifdef HAVE_RLIMIT_MEMLOCK
 	    case RLIMIT_MEMLOCK:
-# endif /* RLIMIT_MEMLOCK */
-# ifdef RLIMIT_VMEM
+# endif /* HAVE_RLIMIT_MEMLOCK */
+/* If RLIMIT_VMEM and RLIMIT_RSS are defined and equal, avoid *
+ * duplicate case statement.  Observed on QNX Neutrino 6.1.0. */
+# if defined(HAVE_RLIMIT_VMEM) && !defined(RLIMIT_VMEM_IS_RSS)
 	    case RLIMIT_VMEM:
-# endif /* RLIMIT_VMEM */
-# ifdef RLIMIT_AIO_MEM
+# endif /* HAVE_RLIMIT_VMEM */
+/* ditto RLIMIT_VMEM and RLIMIT_AS */
+# if defined(HAVE_RLIMIT_AS) && !defined(RLIMIT_VMEM_IS_AS)
+	    case RLIMIT_AS:
+# endif /* HAVE_RLIMIT_AS */
+# ifdef HAVE_RLIMIT_AIO_MEM
 	    case RLIMIT_AIO_MEM:
-# endif /* RLIMIT_AIO_MEM */
+# endif /* HAVE_RLIMIT_AIO_MEM */
 		limit *= 1024;
 		break;
 	    }
-	    if (hard) {
-		/* can't raise hard limit unless running as root */
-		if (limit > current_limits[res].rlim_max && geteuid()) {
-		    zwarnnam(name, "can't raise hard limits", NULL, 0);
-		    return 1;
-		}
-		limits[res].rlim_max = limit;
-		if (limit < limits[res].rlim_cur)
-		    limits[res].rlim_cur = limit;
-	    }
-	    if (!hard || soft) {
-		/* can't raise soft limit above hard limit */
-		if (limit > limits[res].rlim_max) {
-		    if (limit > current_limits[res].rlim_max && geteuid()) {
-			zwarnnam(name, "value exceeds hard limit", NULL, 0);
-			return 1;
-		    }
-		    limits[res].rlim_max = limits[res].rlim_cur = limit;
-		} else
-		    limits[res].rlim_cur = limit;
-	    }
+	    if (do_limit(name, res, limit, hard, soft, 1))
+		ret++;
 	} else {
-	    /* remove specified limit */
-	    if (hard) {
-		/* can't remove hard limit unless running as root */
-		if (current_limits[res].rlim_max != RLIM_INFINITY && geteuid()) {
-		    zwarnnam(name, "can't remove hard limits", NULL, 0);
-		    return 1;
-		}
-		limits[res].rlim_max = RLIM_INFINITY;
-	    }
-	    if (!hard || soft)
-		/* `removal' of soft limit means setting it equal to the
-		   corresponding hard limit */
-		limits[res].rlim_cur = limits[res].rlim_max;
+	    if (do_unlimit(name, res, hard, soft, 1, geteuid()))
+		ret++;
 	}
-	if (zsetlimit(res, name))
-	    return 1;
 	argv++;
     } while (*argv);
-    for (res = 0; res < RLIM_NLIMITS; res++, resmask >>= 1)
-	if (resmask & 1)
-	    printulimit(res, hard, nres > 1);
-    return 0;
+    for (res = 0; resmask; res++, resmask >>= 1)
+	if ((resmask & 1) && printulimit(name, res, hard, nres > 1))
+	    ret++;
+    return ret;
 }
 
 #else /* !HAVE_GETRLIMIT || !RLIM_INFINITY */
@@ -625,7 +873,7 @@ static struct builtin bintab[] = {
 
 /**/
 int
-setup_(Module m)
+setup_(UNUSED(Module m))
 {
     return 0;
 }
@@ -647,7 +895,7 @@ cleanup_(Module m)
 
 /**/
 int
-finish_(Module m)
+finish_(UNUSED(Module m))
 {
     return 0;
 }
diff --git a/Src/cond.c b/Src/cond.c
index 5593097a0..aa808715f 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -37,15 +37,26 @@ static char *condstr[COND_MOD] = {
     "-ne", "-lt", "-gt", "-le", "-ge"
 };
 
+/*
+ * Evaluate a conditional expression given the arguments.
+ * If fromtest is set, the caller is the test or [ builtin;
+ * with the pointer giving the name of the command.
+ * for POSIX conformance this supports a more limited range
+ * of functionality.
+ *
+ * Return status is the final shell status, i.e. 0 for true,
+ * 1 for false and 2 for error.
+ */
+
 /**/
 int
-evalcond(Estate state)
+evalcond(Estate state, char *fromtest)
 {
     struct stat *st;
     char *left, *right;
     Wordcode pcode;
     wordcode code;
-    int ctype, htok = 0;
+    int ctype, htok = 0, ret;
 
  rec:
 
@@ -58,24 +69,28 @@ evalcond(Estate state)
     case COND_NOT:
 	if (tracingcond)
 	    fprintf(xtrerr, " %s", condstr[ctype]);
-	return !evalcond(state);
+	ret = evalcond(state, fromtest);
+	if (ret == 2)
+	    return ret;
+	else
+	    return !ret;
     case COND_AND:
-	if (evalcond(state)) {
+	if (!(ret = evalcond(state, fromtest))) {
 	    if (tracingcond)
 		fprintf(xtrerr, " %s", condstr[ctype]);
 	    goto rec;
 	} else {
 	    state->pc = pcode + (WC_COND_SKIP(code) + 1);
-	    return 0;
+	    return ret;
 	}
     case COND_OR:
-	if (!evalcond(state)) {
+	if ((ret = evalcond(state, fromtest)) == 1) {
 	    if (tracingcond)
 		fprintf(xtrerr, " %s", condstr[ctype]);
 	    goto rec;
 	} else {
 	    state->pc = pcode + (WC_COND_SKIP(code) + 1);
-	    return 1;
+	    return ret;
 	}
     case COND_MOD:
     case COND_MODI:
@@ -99,12 +114,13 @@ evalcond(Estate state)
 	    if ((cd = getconddef((ctype == COND_MODI), name + 1, 1))) {
 		if (ctype == COND_MOD &&
 		    (l < cd->min || (cd->max >= 0 && l > cd->max))) {
-		    zerr("unrecognized condition: `%s'", name, 0);
-		    return 0;
+		    zwarnnam(fromtest, "unrecognized condition: `%s'",
+			     name, 0);
+		    return 2;
 		}
 		if (tracingcond)
 		    tracemodcond(name, strs, ctype == COND_MODI);
-		return cd->handler(strs, cd->condid);
+		return !cd->handler(strs, cd->condid);
 	    }
 	    else {
 		char *s = strs[0];
@@ -115,16 +131,20 @@ evalcond(Estate state)
 		if (name && name[0] == '-' &&
 		    (cd = getconddef(0, name + 1, 1))) {
 		    if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
-			zerr("unrecognized condition: `%s'", name, 0);
-			return 0;
+			zwarnnam(fromtest, "unrecognized condition: `%s'",
+				 name, 0);
+			return 2;
 		    }
 		    if (tracingcond)
 			tracemodcond(name, strs, ctype == COND_MODI);
-		    return cd->handler(strs, cd->condid);
-		} else
-		    zerr("unrecognized condition: `%s'", name, 0);
+		    return !cd->handler(strs, cd->condid);
+		} else {
+		    zwarnnam(fromtest,
+			     "unrecognized condition: `%s'", name, 0);
+		}
 	    }
-	    return 0;
+	    /* module not found, error */
+	    return 2;
 	}
     }
     left = ecgetstr(state, EC_DUPTOK, &htok);
@@ -147,15 +167,46 @@ evalcond(Estate state)
 		singsub(&rt);
 		untokenize(rt);
 	    }
-	    fprintf(xtrerr, " %s %s %s", left, condstr[ctype], rt);
-	} else
-	    fprintf(xtrerr, " -%c %s", ctype, left);
+	    fputc(' ',xtrerr);
+	    quotedzputs(left, xtrerr);
+	    fprintf(xtrerr, " %s ", condstr[ctype]);
+	    quotedzputs(rt, xtrerr);
+	} else {
+	    fprintf(xtrerr, " -%c ", ctype);
+	    quotedzputs(left, xtrerr);
+	}
     }
 
     if (ctype >= COND_EQ && ctype <= COND_GE) {
 	mnumber mn1, mn2;
-	mn1 = matheval(left);
-	mn2 = matheval(right);
+	if (fromtest) {
+	    /*
+	     * For test and [, the expressions must be base 10 integers,
+	     * not integer expressions.
+	     */
+	    char *eptr, *err;
+
+	    mn1.u.l = zstrtol(left, &eptr, 10);
+	    if (!*eptr)
+	    {
+		mn2.u.l = zstrtol(right, &eptr, 10);
+		err = right;
+	    }
+	    else
+		err = left;
+
+	    if (*eptr)
+	    {
+		zwarnnam(fromtest, "integer expression expected: %s",
+			 err, 0);
+		return 2;
+	    }
+
+	    mn1.type = mn2.type = MN_INTEGER;
+	} else {
+	    mn1 = matheval(left);
+	    mn2 = matheval(right);
+	}
 
 	if (((mn1.type|mn2.type) & (MN_INTEGER|MN_FLOAT)) ==
 	    (MN_INTEGER|MN_FLOAT)) {
@@ -171,23 +222,23 @@ evalcond(Estate state)
 	}
 	switch(ctype) {
 	case COND_EQ:
-	    return (mn1.type & MN_FLOAT) ? (mn1.u.d == mn2.u.d) :
-		(mn1.u.l == mn2.u.l);
+	    return !((mn1.type & MN_FLOAT) ? (mn1.u.d == mn2.u.d) :
+		     (mn1.u.l == mn2.u.l));
 	case COND_NE:
-	    return (mn1.type & MN_FLOAT) ? (mn1.u.d != mn2.u.d) :
-		(mn1.u.l != mn2.u.l);
+	    return !((mn1.type & MN_FLOAT) ? (mn1.u.d != mn2.u.d) :
+		     (mn1.u.l != mn2.u.l));
 	case COND_LT:
-	    return (mn1.type & MN_FLOAT) ? (mn1.u.d < mn2.u.d) :
-		(mn1.u.l < mn2.u.l);
+	    return !((mn1.type & MN_FLOAT) ? (mn1.u.d < mn2.u.d) :
+		     (mn1.u.l < mn2.u.l));
 	case COND_GT:
-	    return (mn1.type & MN_FLOAT) ? (mn1.u.d > mn2.u.d) :
-		(mn1.u.l > mn2.u.l);
+	    return !((mn1.type & MN_FLOAT) ? (mn1.u.d > mn2.u.d) :
+		     (mn1.u.l > mn2.u.l));
 	case COND_LE:
-	    return (mn1.type & MN_FLOAT) ? (mn1.u.d <= mn2.u.d) :
-		(mn1.u.l <= mn2.u.l);
+	    return !((mn1.type & MN_FLOAT) ? (mn1.u.d <= mn2.u.d) :
+		     (mn1.u.l <= mn2.u.l));
 	case COND_GE:
-	    return (mn1.type & MN_FLOAT) ? (mn1.u.d >= mn2.u.d) :
-		(mn1.u.l >= mn2.u.l);
+	    return !((mn1.type & MN_FLOAT) ? (mn1.u.d >= mn2.u.d) :
+		     (mn1.u.l >= mn2.u.l));
 	}
     }
 
@@ -202,89 +253,91 @@ evalcond(Estate state)
 		char *opat;
 		int save;
 
-		right = opat = dupstring(ecrawstr(state->prog, state->pc,
+		right = dupstring(opat = ecrawstr(state->prog, state->pc,
 						  &htok));
 		if (htok)
 		    singsub(&right);
-		save = (state->prog->alloc != EA_HEAP &&
+		save = (!(state->prog->flags & EF_HEAP) &&
 			!strcmp(opat, right) && pprog != dummy_patprog2);
 
 		if (!(pprog = patcompile(right, (save ? PAT_ZDUP : PAT_STATIC),
-					 NULL)))
-		    zerr("bad pattern: %s", right, 0);
+					 NULL))) {
+		    zwarnnam(fromtest, "bad pattern: %s", right, 0);
+		    return 2;
+		}
 		else if (save)
 		    state->prog->pats[npat] = pprog;
 	    }
 	    state->pc += 2;
 	    test = (pprog && pattry(pprog, left));
 
-	    return (ctype == COND_STREQ ? test : !test);
+	    return !(ctype == COND_STREQ ? test : !test);
 	}
     case COND_STRLT:
-	return strcmp(left, right) < 0;
+	return !(strcmp(left, right) < 0);
     case COND_STRGTR:
-	return strcmp(left, right) > 0;
+	return !(strcmp(left, right) > 0);
     case 'e':
     case 'a':
-	return (doaccess(left, F_OK));
+	return (!doaccess(left, F_OK));
     case 'b':
-	return (S_ISBLK(dostat(left)));
+	return (!S_ISBLK(dostat(left)));
     case 'c':
-	return (S_ISCHR(dostat(left)));
+	return (!S_ISCHR(dostat(left)));
     case 'd':
-	return (S_ISDIR(dostat(left)));
+	return (!S_ISDIR(dostat(left)));
     case 'f':
-	return (S_ISREG(dostat(left)));
+	return (!S_ISREG(dostat(left)));
     case 'g':
-	return (!!(dostat(left) & S_ISGID));
+	return (!(dostat(left) & S_ISGID));
     case 'k':
-	return (!!(dostat(left) & S_ISVTX));
+	return (!(dostat(left) & S_ISVTX));
     case 'n':
-	return (!!strlen(left));
+	return (!strlen(left));
     case 'o':
-	return (optison(left));
+	return (optison(fromtest, left));
     case 'p':
-	return (S_ISFIFO(dostat(left)));
+	return (!S_ISFIFO(dostat(left)));
     case 'r':
-	return (doaccess(left, R_OK));
+	return (!doaccess(left, R_OK));
     case 's':
-	return ((st = getstat(left)) && !!(st->st_size));
+	return !((st = getstat(left)) && !!(st->st_size));
     case 'S':
-	return (S_ISSOCK(dostat(left)));
+	return (!S_ISSOCK(dostat(left)));
     case 'u':
-	return (!!(dostat(left) & S_ISUID));
+	return (!(dostat(left) & S_ISUID));
     case 'w':
-	return (doaccess(left, W_OK));
+	return (!doaccess(left, W_OK));
     case 'x':
 	if (privasserted()) {
 	    mode_t mode = dostat(left);
-	    return (mode & S_IXUGO) || S_ISDIR(mode);
+	    return !((mode & S_IXUGO) || S_ISDIR(mode));
 	}
-	return doaccess(left, X_OK);
+	return !doaccess(left, X_OK);
     case 'z':
-	return (!strlen(left));
+	return !!(strlen(left));
     case 'h':
     case 'L':
-	return (S_ISLNK(dolstat(left)));
+	return (!S_ISLNK(dolstat(left)));
     case 'O':
-	return ((st = getstat(left)) && st->st_uid == geteuid());
+	return !((st = getstat(left)) && st->st_uid == geteuid());
     case 'G':
-	return ((st = getstat(left)) && st->st_gid == getegid());
+	return !((st = getstat(left)) && st->st_gid == getegid());
     case 'N':
-	return ((st = getstat(left)) && st->st_atime <= st->st_mtime);
+	return !((st = getstat(left)) && st->st_atime <= st->st_mtime);
     case 't':
-	return isatty(mathevali(left));
+	return !isatty(mathevali(left));
     case COND_NT:
     case COND_OT:
 	{
 	    time_t a;
 
 	    if (!(st = getstat(left)))
-		return 0;
+		return 1;
 	    a = st->st_mtime;
 	    if (!(st = getstat(right)))
-		return 0;
-	    return (ctype == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
+		return 1;
+	    return !((ctype == COND_NT) ? a > st->st_mtime : a < st->st_mtime);
 	}
     case COND_EF:
 	{
@@ -292,17 +345,18 @@ evalcond(Estate state)
 	    ino_t i;
 
 	    if (!(st = getstat(left)))
-		return 0;
+		return 1;
 	    d = st->st_dev;
 	    i = st->st_ino;
 	    if (!(st = getstat(right)))
-		return 0;
-	    return d == st->st_dev && i == st->st_ino;
+		return 1;
+	    return !(d == st->st_dev && i == st->st_ino);
 	}
     default:
-	zerr("bad cond code", NULL, 0);
+	zwarnnam(fromtest, "bad cond code", NULL, 0);
+	return 2;
     }
-    return 0;
+    return 1;
 }
 
 
@@ -324,6 +378,8 @@ static struct stat st;
 static struct stat *
 getstat(char *s)
 {
+    char *us;
+
 /* /dev/fd/n refers to the open file descriptor n.  We always use fstat *
  * in this case since on Solaris /dev/fd/n is a device special file     */
     if (!strncmp(s, "/dev/fd/", 8)) {
@@ -332,7 +388,9 @@ getstat(char *s)
         return &st;
     }
 
-    if (stat(unmeta(s), &st))
+    if (!(us = unmeta(s)))
+        return NULL;
+    if (stat(us, &st))
 	return NULL;
     return &st;
 }
@@ -362,9 +420,13 @@ dolstat(char *s)
 }
 
 
+/*
+ * optison returns evalcond-friendly statuses (true, false, error).
+ */
+
 /**/
 static int
-optison(char *s)
+optison(char *name, char *s)
 {
     int i;
 
@@ -373,12 +435,12 @@ optison(char *s)
     else
 	i = optlookup(s);
     if (!i) {
-	zerr("no such option: %s", s, 0);
-	return 0;
+	zwarnnam(name, "no such option: %s", s, 0);
+	return 2;
     } else if(i < 0)
-	return unset(-i);
+	return !unset(-i);
     else
-	return isset(i);
+	return !isset(i);
 }
 
 /**/