oksh-noxz

[fork] Portable OpenBSD ksh, based on the Public Domain Korn Shell (pdksh).
git clone https://noxz.tech/git/oksh-noxz.git
oksh-noxz

commit: 768bf7d9500cb8824c38da3a13c8202aaae53bd7
parent: bb1108a6464f947d991340bf2ae0598438bb13cd
author: Brian Callahan <dodonpachi-github@mailinator.com>
date:   Sat, 21 Apr 2018 16:53:40 -0400
Update to latest ksh(1) code. This changes all use of long to
uint64_t, making oksh now 64-bit on 32-bit platforms.
While here, fix up some Cygwin compile warnings.
MCVS/Entries84++++++++++----------
MREADME.md2+-
Mc_ksh.c4+-
Mc_sh.c4+-
Mc_test.c4+-
Mc_ulimit.c7+-
Mconfigure17++--
Medit.c6+-
Meval.c4+-
Mexpr.c6+-
Mmail.c4+-
Mmain.c4+-
Mmisc.c6+-
Mportable.h2+-
Msh.h14++--
Mtable.h4+-
Mtree.c8+-
Mvar.c55+++++++------
18 files changed, 123 insertions(+), 112 deletions(-)
diff --git a/CVS/Entries b/CVS/Entries
@@ -1,46 +1,46 @@
 /config.h/1.19/Tue Jan 16 02:21:56 2018//
 /history.c/1.80/Tue Jan 16 02:21:56 2018//
 /emacs.c/1.84/Result of merge//
-/CONTRIBUTORS/1.10/Mon Apr  2 01:50:45 2018//
-/LEGAL/1.2/Mon Apr  2 01:50:45 2018//
-/Makefile/1.38/Mon Apr  2 01:50:52 2018//
-/NOTES/1.16/Mon Apr  2 01:50:45 2018//
-/PROJECTS/1.9/Mon Apr  2 01:50:45 2018//
-/README/1.16/Mon Apr  2 01:50:52 2018//
-/alloc.c/1.19/Mon Apr  2 01:50:45 2018//
-/c_ksh.c/1.59/Mon Apr  2 01:50:52 2018//
-/c_sh.c/1.62/Mon Apr  2 01:50:45 2018//
-/c_test.c/1.24/Mon Apr  2 01:50:45 2018//
-/c_test.h/1.4/Mon Apr  2 01:50:45 2018//
-/c_ulimit.c/1.27/Mon Apr  2 01:50:52 2018//
-/edit.c/1.64/Mon Apr  2 01:50:52 2018//
-/edit.h/1.11/Mon Apr  2 01:50:45 2018//
-/eval.c/1.59/Mon Apr  2 01:50:45 2018//
-/exec.c/1.73/Mon Apr  2 01:50:52 2018//
-/expand.h/1.15/Mon Apr  2 01:50:45 2018//
-/expr.c/1.32/Mon Apr  2 01:50:45 2018//
-/io.c/1.36/Mon Apr  2 01:50:45 2018//
-/jobs.c/1.60/Mon Apr  2 01:50:52 2018//
-/ksh.1/1.198/Mon Apr  2 01:50:52 2018//
-/lex.c/1.78/Mon Apr  2 01:50:45 2018//
-/lex.h/1.21/Mon Apr  2 01:50:45 2018//
-/mail.c/1.22/Mon Apr  2 01:50:45 2018//
-/main.c/1.90/Result of merge//
-/misc.c/1.69/Mon Apr  2 01:50:52 2018//
-/path.c/1.22/Mon Apr  2 01:50:45 2018//
-/sh.1/1.148/Mon Apr  2 01:50:52 2018//
-/sh.h/1.71/Mon Apr  2 01:50:45 2018//
-/shf.c/1.33/Mon Apr  2 01:50:53 2018//
-/shf.h/1.8/Mon Apr  2 01:50:45 2018//
-/syn.c/1.38/Mon Apr  2 01:50:45 2018//
-/table.c/1.25/Mon Apr  2 01:50:45 2018//
-/table.h/1.13/Mon Apr  2 01:50:45 2018//
-/trap.c/1.32/Mon Apr  2 01:50:53 2018//
-/tree.c/1.33/Mon Apr  2 01:50:53 2018//
-/tree.h/1.12/Mon Apr  2 01:50:45 2018//
-/tty.c/1.17/Mon Apr  2 01:50:53 2018//
-/tty.h/1.6/Mon Apr  2 01:50:45 2018//
-/var.c/1.66/Mon Apr  2 01:50:53 2018//
-/version.c/1.12/Mon Apr  2 01:50:45 2018//
-/vi.c/1.56/Mon Apr  2 01:50:53 2018//
+/CONTRIBUTORS/1.10/Sat Apr 21 20:30:10 2018//
+/LEGAL/1.2/Sat Apr 21 20:30:11 2018//
+/Makefile/1.38/Sat Apr 21 20:30:20 2018//
+/NOTES/1.16/Sat Apr 21 20:30:11 2018//
+/PROJECTS/1.9/Sat Apr 21 20:30:11 2018//
+/README/1.16/Sat Apr 21 20:30:20 2018//
+/alloc.c/1.19/Sat Apr 21 20:30:11 2018//
+/c_ksh.c/1.60/Sat Apr 21 20:30:20 2018//
+/c_sh.c/1.63/Sat Apr 21 20:30:20 2018//
+/c_test.c/1.25/Sat Apr 21 20:30:20 2018//
+/c_test.h/1.4/Sat Apr 21 20:30:11 2018//
+/c_ulimit.c/1.28/Sat Apr 21 20:30:21 2018//
+/edit.c/1.65/Sat Apr 21 20:30:21 2018//
+/edit.h/1.11/Sat Apr 21 20:30:11 2018//
+/eval.c/1.60/Sat Apr 21 20:30:21 2018//
+/exec.c/1.73/Sat Apr 21 20:30:11 2018//
+/expand.h/1.15/Sat Apr 21 20:30:11 2018//
+/expr.c/1.33/Sat Apr 21 20:30:21 2018//
+/io.c/1.36/Sat Apr 21 20:30:11 2018//
+/jobs.c/1.60/Sat Apr 21 20:30:11 2018//
+/ksh.1/1.198/Sat Apr 21 20:30:11 2018//
+/lex.c/1.78/Sat Apr 21 20:30:11 2018//
+/lex.h/1.21/Sat Apr 21 20:30:11 2018//
+/mail.c/1.23/Sat Apr 21 20:30:21 2018//
+/main.c/1.91/Result of merge//
+/misc.c/1.70/Sat Apr 21 20:30:21 2018//
+/path.c/1.22/Sat Apr 21 20:30:11 2018//
+/sh.1/1.148/Sat Apr 21 20:30:11 2018//
+/sh.h/1.72/Sat Apr 21 20:30:21 2018//
+/shf.c/1.33/Sat Apr 21 20:30:11 2018//
+/shf.h/1.8/Sat Apr 21 20:30:11 2018//
+/syn.c/1.38/Sat Apr 21 20:30:11 2018//
+/table.c/1.25/Sat Apr 21 20:30:11 2018//
+/table.h/1.14/Sat Apr 21 20:30:21 2018//
+/trap.c/1.32/Sat Apr 21 20:30:11 2018//
+/tree.c/1.34/Sat Apr 21 20:30:21 2018//
+/tree.h/1.12/Sat Apr 21 20:30:11 2018//
+/tty.c/1.17/Sat Apr 21 20:30:11 2018//
+/tty.h/1.6/Sat Apr 21 20:30:11 2018//
+/var.c/1.68/Sat Apr 21 20:30:21 2018//
+/version.c/1.12/Sat Apr 21 20:30:11 2018//
+/vi.c/1.56/Sat Apr 21 20:30:11 2018//
 D
diff --git a/README.md b/README.md
@@ -72,4 +72,4 @@ for details.
 
 Get a tarball
 -------------
-http://devio.us/~bcallah/oksh/oksh-20180401.tar.gz
+http://devio.us/~bcallah/oksh/oksh-20180421.tar.gz
diff --git a/c_ksh.c b/c_ksh.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: c_ksh.c,v 1.59 2018/03/15 16:51:29 anton Exp $	*/
+/*	$OpenBSD: c_ksh.c,v 1.60 2018/04/09 17:53:36 tobias Exp $	*/
 
 /*
  * built-in Korn commands: c_*
@@ -1017,7 +1017,7 @@ int
 c_let(char **wp)
 {
 	int rv = 1;
-	long val;
+	int64_t val;
 
 	if (wp[1] == NULL) /* at&t ksh does this */
 		bi_errorf("no arguments");
diff --git a/c_sh.c b/c_sh.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: c_sh.c,v 1.62 2017/12/27 13:02:57 millert Exp $	*/
+/*	$OpenBSD: c_sh.c,v 1.63 2018/04/09 17:53:36 tobias Exp $	*/
 
 /*
  * built-in Bourne commands
@@ -33,7 +33,7 @@ c_shift(char **wp)
 {
 	struct block *l = genv->loc;
 	int n;
-	long val;
+	int64_t val;
 	char *arg;
 
 	if (ksh_getopt(wp, &builtin_opt, null) == '?')
diff --git a/c_test.c b/c_test.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: c_test.c,v 1.24 2017/12/26 19:10:31 millert Exp $	*/
+/*	$OpenBSD: c_test.c,v 1.25 2018/04/09 17:53:36 tobias Exp $	*/
 
 /*
  * test(1); version 7-like  --  author Erik Baalbergen
@@ -308,7 +308,7 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
 	case TO_INTLE: /* -le */
 	case TO_INTLT: /* -lt */
 		{
-			long v1, v2;
+			int64_t v1, v2;
 
 			if (!evaluate(opnd1, &v1, KSH_RETURN_ERROR, false) ||
 			    !evaluate(opnd2, &v2, KSH_RETURN_ERROR, false)) {
diff --git a/c_ulimit.c b/c_ulimit.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: c_ulimit.c,v 1.27 2018/03/15 16:51:29 anton Exp $	*/
+/*	$OpenBSD: c_ulimit.c,v 1.28 2018/04/09 17:53:36 tobias Exp $	*/
 
 /*
 	ulimit -- handle "ulimit" builtin
@@ -22,6 +22,7 @@
 
 #include <ctype.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <string.h>
 
 #include "sh.h"
@@ -139,7 +140,7 @@ set_ulimit(const struct limits *l, const char *v, int how)
 	if (strcmp(v, "unlimited") == 0)
 		val = RLIM_INFINITY;
 	else {
-		long rval;
+		int64_t rval;
 
 		if (!evaluate(v, &rval, KSH_RETURN_ERROR, false))
 			return 1;
@@ -187,6 +188,6 @@ print_ulimit(const struct limits *l, int how)
 		shprintf("unlimited\n");
 	else {
 		val /= l->factor;
-		shprintf("%ld\n", (long) val);
+		shprintf("%" PRIi64 "\n", (int64_t) val);
 	}
 }
diff --git a/configure b/configure
@@ -404,14 +404,15 @@ printf "checking for OS... "
 os=`uname -s`
 echo "$os"
 
-if [ "x$os" = "xLinux" ] ; then
-  cflags="$cflags -D_GNU_SOURCE"
-elif [ "x$os" = "xNetBSD" ] ; then
-  tflags="-D_OPENBSD_SOURCE"
-  cflags="$cflags $tflags"
-else
-  tflags=""
-fi
+case "x$os" in
+  "xLinux"|"xCYGWIN"*)
+    cflags="$cflags -D_GNU_SOURCE"
+    ;;
+  "xNetBSD")
+    tflags="-D_OPENBSD_SOURCE"
+    cflags="$cflags $tflags"
+    ;;
+esac
 
 cat << EOF > pconfig.h
 /* This file automatically generated by configure.  */
diff --git a/edit.c b/edit.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: edit.c,v 1.64 2018/03/15 16:51:29 anton Exp $	*/
+/*	$OpenBSD: edit.c,v 1.65 2018/04/09 17:53:36 tobias Exp $	*/
 
 /*
  * Command line editing - common code
@@ -80,10 +80,10 @@ check_sigwinch(void)
 				    ws.ws_col;
 
 				if ((vp = typeset("COLUMNS", 0, 0, 0, 0)))
-					setint(vp, (long) ws.ws_col);
+					setint(vp, (int64_t) ws.ws_col);
 			}
 			if (ws.ws_row && (vp = typeset("LINES", 0, 0, 0, 0)))
-				setint(vp, (long) ws.ws_row);
+				setint(vp, (int64_t) ws.ws_row);
 		}
 	}
 }
diff --git a/eval.c b/eval.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: eval.c,v 1.59 2018/01/16 22:52:32 jca Exp $	*/
+/*	$OpenBSD: eval.c,v 1.60 2018/04/09 17:53:36 tobias Exp $	*/
 
 /*
  * Expansion - quoting, separation, substitution, globbing
@@ -732,7 +732,7 @@ varsub(Expand *xp, char *sp, char *word,
 		if (Flag(FNOUNSET) && c == 0 && !zero_ok)
 			errorf("%s: parameter not set", sp);
 		*stypep = 0; /* unqualified variable/string substitution */
-		xp->str = str_save(ulton((unsigned long)c, 10), ATEMP);
+		xp->str = str_save(u64ton((uint64_t)c, 10), ATEMP);
 		return XSUB;
 	}
 
diff --git a/expr.c b/expr.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: expr.c,v 1.32 2015/12/30 09:07:00 tedu Exp $	*/
+/*	$OpenBSD: expr.c,v 1.33 2018/04/09 17:53:36 tobias Exp $	*/
 
 /*
  * Korn expression evaluation
@@ -148,7 +148,7 @@ static struct tbl *intvar(Expr_state *, struct tbl *);
  * parse and evaluate expression
  */
 int
-evaluate(const char *expr, long int *rval, int error_ok, bool arith)
+evaluate(const char *expr, int64_t *rval, int error_ok, bool arith)
 {
 	struct tbl v;
 	int ret;
@@ -280,7 +280,7 @@ evalexpr(Expr_state *es, enum prec prec)
 {
 	struct tbl *vl, *vr = NULL, *vasn;
 	enum token op;
-	long res = 0;
+	int64_t res = 0;
 
 	if (prec == P_PRIMARY) {
 		op = es->tok;
diff --git a/mail.c b/mail.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: mail.c,v 1.22 2015/10/19 14:42:16 mmcc Exp $	*/
+/*	$OpenBSD: mail.c,v 1.23 2018/04/09 17:53:36 tobias Exp $	*/
 
 /*
  * Mailbox checking code by Robert J. Gibson, adapted for PD ksh by
@@ -81,7 +81,7 @@ mcheck(void)
 }
 
 void
-mcset(long int interval)
+mcset(int64_t interval)
 {
 	mailcheck_interval = interval;
 }
diff --git a/main.c b/main.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: main.c,v 1.90 2018/03/15 16:51:29 anton Exp $	*/
+/*	$OpenBSD: main.c,v 1.91 2018/04/09 17:53:36 tobias Exp $	*/
 
 /*
  * startup, main loop, environments and error handling
@@ -289,7 +289,7 @@ main(int argc, char *argv[])
 			setstr(pwd_v, current_wd, KSH_RETURN_ERROR);
 	}
 	ppid = getppid();
-	setint(global("PPID"), (long) ppid);
+	setint(global("PPID"), (int64_t) ppid);
 	/* setstr can't fail here */
 	setstr(global(version_param), ksh_version, KSH_RETURN_ERROR);
 
diff --git a/misc.c b/misc.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: misc.c,v 1.69 2018/03/15 16:51:29 anton Exp $	*/
+/*	$OpenBSD: misc.c,v 1.70 2018/04/09 17:53:36 tobias Exp $	*/
 
 /*
  * Miscellaneous functions
@@ -56,10 +56,10 @@ initctypes(void)
 	setctypes(" \n\t\"#$&'()*;<>?[\\`|", C_QUOTE);
 }
 
-/* convert unsigned long to base N string */
+/* convert uint64_t to base N string */
 
 char *
-ulton(long unsigned int n, int base)
+u64ton(uint64_t n, int base)
 {
 	char *p;
 	static char buf [20];
diff --git a/portable.h b/portable.h
@@ -9,7 +9,7 @@
  * Includes
  */
 
-#ifdef __linux__
+#if defined(__linux__) || defined(__CYGWIN__)
 #include <sys/file.h>
 #include <sys/types.h>
 
diff --git a/sh.h b/sh.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: sh.h,v 1.71 2018/01/16 22:52:32 jca Exp $	*/
+/*	$OpenBSD: sh.h,v 1.72 2018/04/09 17:53:36 tobias Exp $	*/
 
 /*
  * Public Domain Bourne/Korn shell
@@ -440,7 +440,7 @@ int	search_access(const char *, int, int *);
 int	pr_menu(char *const *);
 int	pr_list(char *const *);
 /* expr.c */
-int	evaluate(const char *, long *, int, bool);
+int	evaluate(const char *, int64_t *, int, bool);
 int	v_evaluate(struct tbl *, const char *, volatile int, bool);
 /* history.c */
 void	init_histvec(void);
@@ -512,7 +512,7 @@ pid_t	j_async(void);
 int	j_stopped_running(void);
 /* mail.c */
 void	mcheck(void);
-void	mcset(long);
+void	mcset(int64_t);
 void	mbset(char *);
 void	mpset(char *);
 /* main.c */
@@ -527,7 +527,7 @@ void	cleanup_proc_env(void);
 /* misc.c */
 void	setctypes(const char *, int);
 void	initctypes(void);
-char *	ulton(unsigned long, int);
+char *	u64ton(uint64_t, int);
 char *	str_save(const char *, Area *);
 char *	str_nsave(const char *, int, Area *);
 int	option(const char *);
@@ -583,11 +583,11 @@ void	initvar(void);
 struct tbl *	global(const char *);
 struct tbl *	local(const char *, bool);
 char *	str_val(struct tbl *);
-long	intval(struct tbl *);
+int64_t	intval(struct tbl *);
 int	setstr(struct tbl *, const char *, int);
 struct tbl *setint_v(struct tbl *, struct tbl *, bool);
-void	setint(struct tbl *, long);
-int	getint(struct tbl *, long *, bool);
+void	setint(struct tbl *, int64_t);
+int	getint(struct tbl *, int64_t *, bool);
 struct tbl *typeset(const char *, int, int, int, int);
 void	unset(struct tbl *, int);
 char  * skip_varname(const char *, int);
diff --git a/table.h b/table.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: table.h,v 1.13 2017/12/27 13:02:57 millert Exp $	*/
+/*	$OpenBSD: table.h,v 1.14 2018/04/09 17:53:36 tobias Exp $	*/
 
 /* $From: table.h,v 1.3 1994/05/31 13:34:34 michael Exp $ */
 
@@ -19,7 +19,7 @@ struct tbl {			/* table item */
 	Area	*areap;		/* area to allocate from */
 	union {
 		char *s;	/* string */
-		long i;		/* integer */
+		int64_t i;	/* integer */
 		int (*f)(char **);	/* int function */
 		struct op *t;	/* "function" tree */
 	} val;			/* value */
diff --git a/tree.c b/tree.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: tree.c,v 1.33 2018/03/15 16:51:29 anton Exp $	*/
+/*	$OpenBSD: tree.c,v 1.34 2018/04/09 17:53:36 tobias Exp $	*/
 
 /*
  * command tree climbing
@@ -365,7 +365,7 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
 
 	while ((c = *fmt++)) {
 		if (c == '%') {
-			long n;
+			int64_t n;
 			char *p;
 			int neg;
 
@@ -376,7 +376,7 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
 			case 'd': /* decimal */
 				n = va_arg(va, int);
 				neg = n < 0;
-				p = ulton(neg ? -n : n, 10);
+				p = u64ton(neg ? -n : n, 10);
 				if (neg)
 					*--p = '-';
 				while (*p)
@@ -392,7 +392,7 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
 				tputS(p, shf);
 				break;
 			case 'u': /* unsigned decimal */
-				p = ulton(va_arg(va, unsigned int), 10);
+				p = u64ton(va_arg(va, unsigned int), 10);
 				while (*p)
 					tputc(*p++, shf);
 				break;
diff --git a/var.c b/var.c
@@ -1,9 +1,11 @@
-/*	$OpenBSD: var.c,v 1.66 2018/03/15 16:51:29 anton Exp $	*/
+/*	$OpenBSD: var.c,v 1.68 2018/04/13 18:18:36 cheloha Exp $	*/
 
 #include <sys/stat.h>
+#include <sys/time.h>
 
 #include <ctype.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
@@ -136,7 +138,7 @@ array_index_calc(const char *n, bool *arrayp, int *valp)
 	p = skip_varname(n, false);
 	if (p != n && *p == '[' && (len = array_ref_len(p))) {
 		char *sub, *tmp;
-		long rval;
+		int64_t rval;
 
 		/* Calculate the value of the subscript */
 		*arrayp = true;
@@ -146,7 +148,8 @@ array_index_calc(const char *n, bool *arrayp, int *valp)
 		n = str_nsave(n, p - n, ATEMP);
 		evaluate(sub, &rval, KSH_UNWIND_ERROR, true);
 		if (rval < 0 || rval > INT_MAX)
-			errorf("%s: subscript %ld out of range", n, rval);
+			errorf("%s: subscript %" PRIi64 " out of range",
+			    n, rval);
 		*valp = rval;
 		afree(sub, ATEMP);
 	}
@@ -295,18 +298,18 @@ str_val(struct tbl *vp)
 	else if (!(vp->flag&INTEGER))	/* string source */
 		s = vp->val.s + vp->type;
 	else {				/* integer source */
-		/* worst case number length is when base=2, so use BITS(long) */
-		/* minus base #     number    null */
-		char strbuf[1 + 2 + 1 + BITS(long) + 1];
+		/* worst case number length is when base=2, so use
+		 * minus base # number BITS(int64_t) NUL */
+		char strbuf[1 + 2 + 1 + BITS(int64_t) + 1];
 		const char *digits = (vp->flag & UCASEV_AL) ?
 		    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" :
 		    "0123456789abcdefghijklmnopqrstuvwxyz";
-		unsigned long n;
+		uint64_t n;
 		unsigned int base;
 
 		s = strbuf + sizeof(strbuf);
 		if (vp->flag & INT_U)
-			n = (unsigned long) vp->val.i;
+			n = (uint64_t) vp->val.i;
 		else
 			n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
 		base = (vp->type == 0) ? 10 : vp->type;
@@ -335,10 +338,10 @@ str_val(struct tbl *vp)
 }
 
 /* get variable integer value, with error checking */
-long
+int64_t
 intval(struct tbl *vp)
 {
-	long num;
+	int64_t num;
 	int base;
 
 	base = getint(vp, &num, false);
@@ -393,7 +396,7 @@ setstr(struct tbl *vq, const char *s, int error_ok)
 
 /* set variable to integer */
 void
-setint(struct tbl *vq, long int n)
+setint(struct tbl *vq, int64_t n)
 {
 	if (!(vq->flag&INTEGER)) {
 		struct tbl *vp = &vtemp;
@@ -411,13 +414,13 @@ setint(struct tbl *vq, long int n)
 }
 
 int
-getint(struct tbl *vp, long int *nump, bool arith)
+getint(struct tbl *vp, int64_t *nump, bool arith)
 {
 	char *s;
 	int c;
 	int base, neg;
 	int have_base = 0;
-	long num;
+	int64_t num;
 
 	if (vp->flag&SPECIAL)
 		getspec(vp);
@@ -483,7 +486,7 @@ struct tbl *
 setint_v(struct tbl *vq, struct tbl *vp, bool arith)
 {
 	int base;
-	long num;
+	int64_t num;
 
 	if ((base = getint(vp, &num, arith)) == -1)
 		return NULL;
@@ -906,7 +909,7 @@ unspecial(const char *name)
 		ktdelete(tp);
 }
 
-static	time_t	seconds;		/* time SECONDS last set */
+static	struct	timespec seconds;	/* time SECONDS last set */
 static	int	user_lineno;		/* what user set $LINENO to */
 
 static void
@@ -919,28 +922,33 @@ getspec(struct tbl *vp)
 		 * has been set - don't do anything in this case
 		 * (see initcoms[] in main.c).
 		 */
-		if (vp->flag & ISSET)
-			setint(vp, (long)(time(NULL) - seconds)); /* XXX 2038 */
+		if (vp->flag & ISSET) {
+			struct timespec difference, now;
+
+			clock_gettime(CLOCK_MONOTONIC, &now);
+			timespecsub(&now, &seconds, &difference);
+			setint(vp, (int64_t)difference.tv_sec);
+		}
 		vp->flag |= SPECIAL;
 		break;
 	case V_RANDOM:
 		vp->flag &= ~SPECIAL;
-		setint(vp, (long) (rand() & 0x7fff));
+		setint(vp, (int64_t) (rand() & 0x7fff));
 		vp->flag |= SPECIAL;
 		break;
 	case V_HISTSIZE:
 		vp->flag &= ~SPECIAL;
-		setint(vp, (long) histsize);
+		setint(vp, (int64_t) histsize);
 		vp->flag |= SPECIAL;
 		break;
 	case V_OPTIND:
 		vp->flag &= ~SPECIAL;
-		setint(vp, (long) user_opt.uoptind);
+		setint(vp, (int64_t) user_opt.uoptind);
 		vp->flag |= SPECIAL;
 		break;
 	case V_LINENO:
 		vp->flag &= ~SPECIAL;
-		setint(vp, (long) current_lineno + user_lineno);
+		setint(vp, (int64_t) current_lineno + user_lineno);
 		vp->flag |= SPECIAL;
 		break;
 	}
@@ -1004,7 +1012,7 @@ setspec(struct tbl *vp)
 		break;
 	case V_COLUMNS:
 		{
-			long l;
+			int64_t l;
 
 			if (getint(vp, &l, false) == -1) {
 				x_cols = MIN_COLS;
@@ -1034,7 +1042,8 @@ setspec(struct tbl *vp)
 		break;
 	case V_SECONDS:
 		vp->flag &= ~SPECIAL;
-		seconds = time(NULL) - intval(vp); /* XXX 2038 */
+		clock_gettime(CLOCK_MONOTONIC, &seconds);
+		seconds.tv_sec -= intval(vp);
 		vp->flag |= SPECIAL;
 		break;
 	case V_TMOUT: