xref: /third_party/mksh/sh.h (revision c84f3f3c)
1/*	$OpenBSD: sh.h,v 1.35 2015/09/10 22:48:58 nicm Exp $	*/
2/*	$OpenBSD: shf.h,v 1.6 2005/12/11 18:53:51 deraadt Exp $	*/
3/*	$OpenBSD: table.h,v 1.8 2012/02/19 07:52:30 otto Exp $	*/
4/*	$OpenBSD: tree.h,v 1.10 2005/03/28 21:28:22 deraadt Exp $	*/
5/*	$OpenBSD: expand.h,v 1.7 2015/09/01 13:12:31 tedu Exp $	*/
6/*	$OpenBSD: lex.h,v 1.13 2013/03/03 19:11:34 guenther Exp $	*/
7/*	$OpenBSD: proto.h,v 1.35 2013/09/04 15:49:19 millert Exp $	*/
8/*	$OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $	*/
9/*	$OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $	*/
10
11/*-
12 * Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
13 *	       2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
14 *	       2019, 2020
15 *	mirabilos <m@mirbsd.org>
16 *
17 * Provided that these terms and disclaimer and all copyright notices
18 * are retained or reproduced in an accompanying document, permission
19 * is granted to deal in this work without restriction, including un‐
20 * limited rights to use, publicly perform, distribute, sell, modify,
21 * merge, give away, or sublicence.
22 *
23 * This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
24 * the utmost extent permitted by applicable law, neither express nor
25 * implied; without malicious intent or gross negligence. In no event
26 * may a licensor, author or contributor be held liable for indirect,
27 * direct, other damage, loss, or other issues arising in any way out
28 * of dealing in the work, even if advised of the possibility of such
29 * damage or existence of a defect, except proven that it results out
30 * of said person’s immediate fault when using the work as intended.
31 */
32
33#ifdef __dietlibc__
34/* XXX imake style */
35#define _BSD_SOURCE	/* live, BSD, live❣ */
36#endif
37
38#if HAVE_SYS_PARAM_H
39#include <sys/param.h>
40#endif
41#include <sys/types.h>
42#if HAVE_BOTH_TIME_H
43#include <sys/time.h>
44#include <time.h>
45#elif HAVE_SYS_TIME_H
46#include <sys/time.h>
47#elif HAVE_TIME_H
48#include <time.h>
49#endif
50#include <sys/ioctl.h>
51#if HAVE_SYS_SYSMACROS_H
52#include <sys/sysmacros.h>
53#endif
54#if HAVE_SYS_MKDEV_H
55#include <sys/mkdev.h>
56#endif
57#if HAVE_SYS_MMAN_H
58#include <sys/mman.h>
59#endif
60#if HAVE_SYS_RESOURCE_H
61#include <sys/resource.h>
62#endif
63#include <sys/stat.h>
64#include <sys/wait.h>
65#include <dirent.h>
66#include <errno.h>
67#include <fcntl.h>
68#if HAVE_IO_H
69#include <io.h>
70#endif
71#if HAVE_LIBGEN_H
72#include <libgen.h>
73#endif
74#if HAVE_LIBUTIL_H
75#include <libutil.h>
76#endif
77#include <limits.h>
78#if HAVE_PATHS_H
79#include <paths.h>
80#endif
81#ifndef MKSH_NOPWNAM
82#include <pwd.h>
83#endif
84#include <setjmp.h>
85#include <signal.h>
86#include <stdarg.h>
87#include <stddef.h>
88#if HAVE_STDINT_H
89#include <stdint.h>
90#endif
91#include <stdio.h>
92#include <stdlib.h>
93#include <string.h>
94#if HAVE_STRINGS_H
95#include <strings.h>
96#endif
97#if HAVE_TERMIOS_H
98#include <termios.h>
99#else
100/* shudder… */
101#include <termio.h>
102#endif
103#ifdef _ISC_UNIX
104/* XXX imake style */
105#include <sys/sioctl.h>
106#endif
107#if HAVE_ULIMIT_H
108#include <ulimit.h>
109#endif
110#include <unistd.h>
111#if HAVE_VALUES_H
112#include <values.h>
113#endif
114#ifdef MIRBSD_BOOTFLOPPY
115#include <wchar.h>
116#endif
117
118/* monkey-patch known-bad offsetof versions to quell a warning */
119#if (defined(__KLIBC__) || defined(__dietlibc__)) && \
120    ((defined(__GNUC__) && (__GNUC__ > 3)) || defined(__NWCC__))
121#undef offsetof
122#define offsetof(s,e)		__builtin_offsetof(s, e)
123#endif
124
125#undef __attribute__
126#if HAVE_ATTRIBUTE_BOUNDED
127#define MKSH_A_BOUNDED(x,y,z)	__attribute__((__bounded__(x, y, z)))
128#else
129#define MKSH_A_BOUNDED(x,y,z)	/* nothing */
130#endif
131#if HAVE_ATTRIBUTE_FORMAT
132#define MKSH_A_FORMAT(x,y,z)	__attribute__((__format__(x, y, z)))
133#else
134#define MKSH_A_FORMAT(x,y,z)	/* nothing */
135#endif
136#if HAVE_ATTRIBUTE_NORETURN
137#define MKSH_A_NORETURN		__attribute__((__noreturn__))
138#else
139#define MKSH_A_NORETURN		/* nothing */
140#endif
141#if HAVE_ATTRIBUTE_PURE
142#define MKSH_A_PURE		__attribute__((__pure__))
143#else
144#define MKSH_A_PURE		/* nothing */
145#endif
146#if HAVE_ATTRIBUTE_UNUSED
147#define MKSH_A_UNUSED		__attribute__((__unused__))
148#else
149#define MKSH_A_UNUSED		/* nothing */
150#endif
151#if HAVE_ATTRIBUTE_USED
152#define MKSH_A_USED		__attribute__((__used__))
153#else
154#define MKSH_A_USED		/* nothing */
155#endif
156
157#if defined(MirBSD) && (MirBSD >= 0x09A1) && \
158    defined(__ELF__) && defined(__GNUC__) && \
159    !defined(__llvm__) && !defined(__NWCC__)
160/*
161 * We got usable __IDSTRING __COPYRIGHT __RCSID __SCCSID macros
162 * which work for all cases; no need to redefine them using the
163 * "portable" macros from below when we might have the "better"
164 * gcc+ELF specific macros or other system dependent ones.
165 */
166#else
167#undef __IDSTRING
168#undef __IDSTRING_CONCAT
169#undef __IDSTRING_EXPAND
170#undef __COPYRIGHT
171#undef __RCSID
172#undef __SCCSID
173#define __IDSTRING_CONCAT(l,p)		__LINTED__ ## l ## _ ## p
174#define __IDSTRING_EXPAND(l,p)		__IDSTRING_CONCAT(l,p)
175#ifdef MKSH_DONT_EMIT_IDSTRING
176#define __IDSTRING(prefix,string)	/* nothing */
177#elif defined(__ELF__) && defined(__GNUC__) && \
178    !(defined(__GNUC__) && defined(__mips16) && (__GNUC__ >= 8)) && \
179    !defined(__llvm__) && !defined(__NWCC__) && !defined(NO_ASM)
180#define __IDSTRING(prefix,string)				\
181	__asm__(".section .comment"				\
182	"\n	.ascii	\"@(\"\"#)" #prefix ": \""		\
183	"\n	.asciz	\"" string "\""				\
184	"\n	.previous")
185#else
186#define __IDSTRING(prefix,string)				\
187	static const char __IDSTRING_EXPAND(__LINE__,prefix) []	\
188	    MKSH_A_USED = "@(""#)" #prefix ": " string
189#endif
190#define __COPYRIGHT(x)		__IDSTRING(copyright,x)
191#define __RCSID(x)		__IDSTRING(rcsid,x)
192#define __SCCSID(x)		__IDSTRING(sccsid,x)
193#endif
194
195#ifdef EXTERN
196__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.904 2020/10/31 03:53:06 tg Exp $");
197#endif
198#define MKSH_VERSION "R59 2020/10/31"
199
200/* arithmetic types: C implementation */
201#if !HAVE_CAN_INTTYPES
202#if !HAVE_CAN_UCBINTS
203typedef signed int int32_t;
204typedef unsigned int uint32_t;
205#else
206typedef u_int32_t uint32_t;
207#endif
208#endif
209
210/* arithmetic types: shell arithmetics */
211#ifdef MKSH_LEGACY_MODE
212/*
213 * POSIX demands these to be the C environment's long type
214 */
215typedef long mksh_ari_t;
216typedef unsigned long mksh_uari_t;
217#else
218/*
219 * These types are exactly 32 bit wide; signed and unsigned
220 * integer wraparound, even across division and modulo, for
221 * any shell code using them, is guaranteed.
222 */
223typedef int32_t mksh_ari_t;
224typedef uint32_t mksh_uari_t;
225#endif
226
227/* boolean type (no <stdbool.h> deliberately) */
228typedef unsigned char mksh_bool;
229#undef bool
230/* false MUST equal the same 0 as written by static storage initialisation */
231#undef false
232#undef true
233/* access macros for boolean type */
234#define bool		mksh_bool
235/* values must have identity mapping between mksh_bool and short */
236#define false		0
237#define true		1
238/* make any-type into bool or short */
239#define tobool(cond)	((cond) ? true : false)
240
241/* char (octet) type: C implementation */
242#if !HAVE_CAN_INT8TYPE
243#if !HAVE_CAN_UCBINT8
244typedef unsigned char uint8_t;
245#else
246typedef u_int8_t uint8_t;
247#endif
248#endif
249
250/* other standard types */
251
252#if !HAVE_SIG_T
253#undef sig_t
254typedef void (*sig_t)(int);
255#endif
256
257#ifdef MKSH_TYPEDEF_SIG_ATOMIC_T
258typedef MKSH_TYPEDEF_SIG_ATOMIC_T sig_atomic_t;
259#endif
260
261#ifdef MKSH_TYPEDEF_SSIZE_T
262typedef MKSH_TYPEDEF_SSIZE_T ssize_t;
263#endif
264
265#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
266#define MKSH_SHF_NO_INLINE
267#endif
268
269/* do not merge these conditionals as neatcc’s preprocessor is simple */
270#ifdef __neatcc__
271/* parsing of comma operator <,> in expressions broken */
272#define MKSH_SHF_NO_INLINE
273#endif
274
275/* un-do vendor damage */
276
277#undef BAD		/* AIX defines that somewhere */
278#undef PRINT		/* LynxOS defines that somewhere */
279#undef flock		/* SCO UnixWare defines that to flock64 but ENOENT */
280
281
282#ifndef MKSH_INCLUDES_ONLY
283
284/* compile-time assertions */
285#define cta(name,expr)	struct cta_ ## name { char t[(expr) ? 1 : -1]; }
286
287/* EBCDIC fun */
288
289/* see the large comment in shf.c for an EBCDIC primer */
290
291#if defined(MKSH_FOR_Z_OS) && defined(__MVS__) && defined(__IBMC__) && defined(__CHARSET_LIB)
292# if !__CHARSET_LIB && !defined(MKSH_EBCDIC)
293#  error "Please compile with Build.sh -E for EBCDIC!"
294# endif
295# if __CHARSET_LIB && defined(MKSH_EBCDIC)
296#  error "Please compile without -E argument to Build.sh for ASCII!"
297# endif
298# if __CHARSET_LIB && !defined(_ENHANCED_ASCII_EXT)
299   /* go all-out on ASCII */
300#  define _ENHANCED_ASCII_EXT 0xFFFFFFFF
301# endif
302#endif
303
304/* extra types */
305
306/* getrusage does not exist on OS/2 kLIBC */
307#if !HAVE_GETRUSAGE && !defined(__OS2__)
308#undef rusage
309#undef RUSAGE_SELF
310#undef RUSAGE_CHILDREN
311#define rusage mksh_rusage
312#define RUSAGE_SELF		0
313#define RUSAGE_CHILDREN		-1
314
315struct rusage {
316	struct timeval ru_utime;
317	struct timeval ru_stime;
318};
319#endif
320
321/* extra macros */
322
323#ifndef timerclear
324#define timerclear(tvp)							\
325	do {								\
326		(tvp)->tv_sec = (tvp)->tv_usec = 0;			\
327	} while (/* CONSTCOND */ 0)
328#endif
329#ifndef timeradd
330#define timeradd(tvp,uvp,vvp)						\
331	do {								\
332		(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;		\
333		(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;	\
334		if ((vvp)->tv_usec >= 1000000) {			\
335			(vvp)->tv_sec++;				\
336			(vvp)->tv_usec -= 1000000;			\
337		}							\
338	} while (/* CONSTCOND */ 0)
339#endif
340#ifndef timersub
341#define timersub(tvp,uvp,vvp)						\
342	do {								\
343		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
344		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;	\
345		if ((vvp)->tv_usec < 0) {				\
346			(vvp)->tv_sec--;				\
347			(vvp)->tv_usec += 1000000;			\
348		}							\
349	} while (/* CONSTCOND */ 0)
350#endif
351
352#ifdef MKSH__NO_PATH_MAX
353#undef PATH_MAX
354#else
355#ifndef PATH_MAX
356#ifdef MAXPATHLEN
357#define PATH_MAX	MAXPATHLEN
358#else
359#define PATH_MAX	1024
360#endif
361#endif
362#endif
363#ifndef SIZE_MAX
364#ifdef SIZE_T_MAX
365#define SIZE_MAX	SIZE_T_MAX
366#else
367#define SIZE_MAX	((size_t)-1)
368#endif
369#endif
370#ifndef S_ISLNK
371#define S_ISLNK(m)	((m & 0170000) == 0120000)
372#endif
373#ifndef S_ISSOCK
374#define S_ISSOCK(m)	((m & 0170000) == 0140000)
375#endif
376#if !defined(S_ISCDF) && defined(S_CDF)
377#define S_ISCDF(m)	(S_ISDIR(m) && ((m) & S_CDF))
378#endif
379#ifndef DEFFILEMODE
380#define DEFFILEMODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
381#endif
382
383
384/* determine ksh_NSIG: first, use the traditional definitions */
385#undef ksh_NSIG
386#if defined(NSIG)
387#define ksh_NSIG (NSIG)
388#elif defined(_NSIG)
389#define ksh_NSIG (_NSIG)
390#elif defined(SIGMAX)
391#define ksh_NSIG (SIGMAX + 1)
392#elif defined(_SIGMAX)
393#define ksh_NSIG (_SIGMAX + 1)
394#elif defined(NSIG_MAX)
395#define ksh_NSIG (NSIG_MAX)
396#elif defined(MKSH_FOR_Z_OS)
397#define ksh_NSIG 40
398#else
399# error Please have your platform define NSIG.
400#endif
401/* range-check them */
402#if (ksh_NSIG < 1)
403# error Your NSIG value is not positive.
404#undef ksh_NSIG
405#endif
406/* second, see if the new POSIX definition is available */
407#ifdef NSIG_MAX
408#if (NSIG_MAX < 2)
409/* and usable */
410# error Your NSIG_MAX value is too small.
411#undef NSIG_MAX
412#elif (ksh_NSIG > NSIG_MAX)
413/* and realistic */
414# error Your NSIG value is larger than your NSIG_MAX value.
415#undef NSIG_MAX
416#else
417/* since it’s usable, prefer it */
418#undef ksh_NSIG
419#define ksh_NSIG (NSIG_MAX)
420#endif
421/* if NSIG_MAX is now still defined, use sysconf(_SC_NSIG) at runtime */
422#endif
423/* third, for cpp without the error directive, default */
424#ifndef ksh_NSIG
425#define ksh_NSIG 64
426#endif
427
428#define ksh_sigmask(sig) (((sig) < 1 || (sig) > 127) ? 255 : 128 + (sig))
429
430
431/* OS-dependent additions (functions, variables, by OS) */
432
433#ifdef MKSH_EXE_EXT
434#undef MKSH_EXE_EXT
435#define MKSH_EXE_EXT	".exe"
436#else
437#define MKSH_EXE_EXT	""
438#endif
439
440#ifdef __OS2__
441#define MKSH_UNIXROOT	"/@unixroot"
442#else
443#define MKSH_UNIXROOT	""
444#endif
445
446#ifdef MKSH_DOSPATH
447#ifndef __GNUC__
448# error GCC extensions needed later on
449#endif
450#define MKSH_PATHSEPS	";"
451#define MKSH_PATHSEPC	';'
452#else
453#define MKSH_PATHSEPS	":"
454#define MKSH_PATHSEPC	':'
455#endif
456
457#if !HAVE_FLOCK_DECL
458extern int flock(int, int);
459#endif
460
461#if !HAVE_GETTIMEOFDAY
462#define mksh_TIME(tv) do {		\
463	(tv).tv_usec = 0;		\
464	(tv).tv_sec = time(NULL);	\
465} while (/* CONSTCOND */ 0)
466#else
467#define mksh_TIME(tv) gettimeofday(&(tv), NULL)
468#endif
469
470#if !HAVE_GETRUSAGE
471extern int getrusage(int, struct rusage *);
472#endif
473
474#if !HAVE_MEMMOVE
475/* we assume either memmove or bcopy exist, at the moment */
476#define memmove(dst,src,len)	bcopy((src), (dst), (len))
477#endif
478
479#if !HAVE_REVOKE_DECL
480extern int revoke(const char *);
481#endif
482
483#if defined(DEBUG) || !HAVE_STRERROR
484#undef strerror
485#define strerror		/* poisoned */ dontuse_strerror
486#define cstrerror		/* replaced */ cstrerror
487extern const char *cstrerror(int);
488#else
489#define cstrerror(errnum)	((const char *)strerror(errnum))
490#endif
491
492#if !HAVE_STRLCPY
493size_t strlcpy(char *, const char *, size_t);
494#endif
495
496#ifdef __INTERIX
497/* XXX imake style */
498#define makedev mkdev
499extern int __cdecl seteuid(uid_t);
500extern int __cdecl setegid(gid_t);
501#endif
502
503#if defined(__COHERENT__)
504#ifndef O_ACCMODE
505/* this need not work everywhere, take care */
506#define O_ACCMODE	(O_RDONLY | O_WRONLY | O_RDWR)
507#endif
508#endif
509
510#ifndef O_BINARY
511#define O_BINARY	0
512#endif
513
514#undef O_MAYEXEC	/* https://lwn.net/Articles/820658/ */
515#define O_MAYEXEC	0
516
517#ifdef MKSH__NO_SYMLINK
518#undef S_ISLNK
519#define S_ISLNK(m)	(/* CONSTCOND */ 0)
520#define mksh_lstat	stat
521#else
522#define mksh_lstat	lstat
523#endif
524
525#if HAVE_TERMIOS_H
526#define mksh_ttyst	struct termios
527#define mksh_tcget(fd,st) tcgetattr((fd), (st))
528#define mksh_tcset(fd,st) tcsetattr((fd), TCSADRAIN, (st))
529#else
530#define mksh_ttyst	struct termio
531#define mksh_tcget(fd,st) ioctl((fd), TCGETA, (st))
532#define mksh_tcset(fd,st) ioctl((fd), TCSETAW, (st))
533#endif
534
535#ifndef ISTRIP
536#define ISTRIP		0
537#endif
538
539#ifdef MKSH_EBCDIC
540#define KSH_BEL		'\a'
541#define KSH_ESC		047
542#define KSH_ESC_STRING	"\047"
543#define KSH_VTAB	'\v'
544#else
545/*
546 * According to the comments in pdksh, \007 seems to be more portable
547 * than \a (HP-UX cc, Ultrix cc, old pcc, etc.) so we avoid the escape
548 * sequence if ASCII can be assumed.
549 */
550#define KSH_BEL		7
551#define KSH_ESC		033
552#define KSH_ESC_STRING	"\033"
553#define KSH_VTAB	11
554#endif
555
556
557/* some useful #defines */
558#ifdef EXTERN
559# define E_INIT(i) = i
560#else
561# define E_INIT(i)
562# define EXTERN extern
563# define EXTERN_DEFINED
564#endif
565
566/* define bit in flag */
567#define BIT(i)		(1U << (i))
568#define NELEM(a)	(sizeof(a) / sizeof((a)[0]))
569
570/*
571 * Make MAGIC a char that might be printed to make bugs more obvious, but
572 * not a char that is used often. Also, can't use the high bit as it causes
573 * portability problems (calling strchr(x, 0x80 | 'x') is error prone).
574 *
575 * MAGIC can be followed by MAGIC (to escape the octet itself) or one of:
576 * ' !)*,-?[]{|}' 0x80|' !*+?@' (probably… hysteric raisins abound)
577 *
578 * The |0x80 is likely unsafe on EBCDIC :( though the listed chars are
579 * low-bit7 at least on cp1047 so YMMV
580 */
581#define MAGIC		KSH_BEL	/* prefix for *?[!{,} during expand */
582#define ISMAGIC(c)	(ord(c) == ORD(MAGIC))
583
584EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */
585
586#ifdef MKSH_LEGACY_MODE
587#define KSH_VERSIONNAME_ISLEGACY	"LEGACY"
588#else
589#define KSH_VERSIONNAME_ISLEGACY	"MIRBSD"
590#endif
591#ifdef MKSH_WITH_TEXTMODE
592#define KSH_VERSIONNAME_TEXTMODE	" +TEXTMODE"
593#else
594#define KSH_VERSIONNAME_TEXTMODE	""
595#endif
596#ifdef MKSH_EBCDIC
597#define KSH_VERSIONNAME_EBCDIC		" +EBCDIC"
598#else
599#define KSH_VERSIONNAME_EBCDIC		""
600#endif
601#ifndef KSH_VERSIONNAME_VENDOR_EXT
602#define KSH_VERSIONNAME_VENDOR_EXT	""
603#endif
604EXTERN const char initvsn[] E_INIT("KSH_VERSION=@(#)" KSH_VERSIONNAME_ISLEGACY \
605    " KSH " MKSH_VERSION KSH_VERSIONNAME_EBCDIC KSH_VERSIONNAME_TEXTMODE \
606    KSH_VERSIONNAME_VENDOR_EXT);
607#define KSH_VERSION	(initvsn + /* "KSH_VERSION=@(#)" */ 16)
608
609EXTERN const char digits_uc[] E_INIT("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
610EXTERN const char digits_lc[] E_INIT("0123456789abcdefghijklmnopqrstuvwxyz");
611
612/*
613 * Evil hack for const correctness due to API brokenness
614 */
615union mksh_cchack {
616	char *rw;
617	const char *ro;
618};
619union mksh_ccphack {
620	char **rw;
621	const char **ro;
622};
623
624/*
625 * Evil hack since casting uint to sint is implementation-defined
626 */
627typedef union {
628	mksh_ari_t i;
629	mksh_uari_t u;
630} mksh_ari_u;
631
632/* for const debugging */
633#if defined(DEBUG) && defined(__GNUC__) && !defined(__ICC) && \
634    !defined(__INTEL_COMPILER) && !defined(__SUNPRO_C)
635char *ucstrchr(char *, int);
636char *ucstrstr(char *, const char *);
637#undef strchr
638#define strchr ucstrchr
639#define strstr ucstrstr
640#define cstrchr(s,c) ({			\
641	union mksh_cchack in, out;	\
642					\
643	in.ro = (s);			\
644	out.rw = ucstrchr(in.rw, (c));	\
645	(out.ro);			\
646})
647#define cstrstr(b,l) ({			\
648	union mksh_cchack in, out;	\
649					\
650	in.ro = (b);			\
651	out.rw = ucstrstr(in.rw, (l));	\
652	(out.ro);			\
653})
654#define vstrchr(s,c)	(cstrchr((s), (c)) != NULL)
655#define vstrstr(b,l)	(cstrstr((b), (l)) != NULL)
656#else /* !DEBUG, !gcc */
657#define cstrchr(s,c)	((const char *)strchr((s), (c)))
658#define cstrstr(s,c)	((const char *)strstr((s), (c)))
659#define vstrchr(s,c)	(strchr((s), (c)) != NULL)
660#define vstrstr(b,l)	(strstr((b), (l)) != NULL)
661#endif
662
663#if defined(DEBUG) || defined(__COVERITY__)
664#ifndef DEBUG_LEAKS
665#define DEBUG_LEAKS
666#endif
667#endif
668
669#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 593)
670#error Must run Build.sh to compile this.
671extern void thiswillneverbedefinedIhope(void);
672int
673im_sorry_dave(void)
674{
675	/* I’m sorry, Dave. I’m afraid I can’t do that. */
676	return (thiswillneverbedefinedIhope());
677}
678#endif
679
680/* use this ipv strchr(s, 0) but no side effects in s! */
681#define strnul(s)	((s) + strlen((const void *)s))
682
683#define utf_ptradjx(src,dst) do {					\
684	(dst) = (src) + utf_ptradj(src);				\
685} while (/* CONSTCOND */ 0)
686
687#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
688#define strdupx(d,s,ap) do {						\
689	(d) = strdup_i((s), (ap));					\
690} while (/* CONSTCOND */ 0)
691#define strndupx(d,s,n,ap) do {						\
692	(d) = strndup_i((s), (n), (ap));				\
693} while (/* CONSTCOND */ 0)
694#else
695/* be careful to evaluate arguments only once! */
696#define strdupx(d,s,ap) do {						\
697	const char *strdup_src = (const void *)(s);			\
698	char *strdup_dst = NULL;					\
699									\
700	if (strdup_src != NULL) {					\
701		size_t strdup_len = strlen(strdup_src) + 1;		\
702		strdup_dst = alloc(strdup_len, (ap));			\
703		memcpy(strdup_dst, strdup_src, strdup_len);		\
704	}								\
705	(d) = strdup_dst;						\
706} while (/* CONSTCOND */ 0)
707#define strndupx(d,s,n,ap) do {						\
708	const char *strdup_src = (const void *)(s);			\
709	char *strdup_dst = NULL;					\
710									\
711	if (strdup_src != NULL) {					\
712		size_t strndup_len = (n);				\
713		strdup_dst = alloc(strndup_len + 1, (ap));		\
714		memcpy(strdup_dst, strdup_src, strndup_len);		\
715		strdup_dst[strndup_len] = '\0';				\
716	}								\
717	(d) = strdup_dst;						\
718} while (/* CONSTCOND */ 0)
719#endif
720#define strdup2x(d,s1,s2) do {						\
721	const char *strdup_src = (const void *)(s1);			\
722	const char *strdup_app = (const void *)(s2);			\
723	size_t strndup_len = strlen(strdup_src);			\
724	size_t strndup_ln2 = strlen(strdup_app) + 1;			\
725	char *strdup_dst = alloc(strndup_len + strndup_ln2, ATEMP);	\
726									\
727	memcpy(strdup_dst, strdup_src, strndup_len);			\
728	memcpy(strdup_dst + strndup_len, strdup_app, strndup_ln2);	\
729	(d) = strdup_dst;						\
730} while (/* CONSTCOND */ 0)
731#define strpathx(d,s1,s2,cond) do {					\
732	const char *strdup_src = (const void *)(s1);			\
733	const char *strdup_app = (const void *)(s2);			\
734	size_t strndup_len = strlen(strdup_src) + 1;			\
735	size_t strndup_ln2 = ((cond) || *strdup_app) ?			\
736	    strlen(strdup_app) + 1 : 0;					\
737	char *strdup_dst = alloc(strndup_len + strndup_ln2, ATEMP);	\
738									\
739	memcpy(strdup_dst, strdup_src, strndup_len);			\
740	if (strndup_ln2) {						\
741		strdup_dst[strndup_len - 1] = '/';			\
742		memcpy(strdup_dst + strndup_len, strdup_app,		\
743		    strndup_ln2);					\
744	}								\
745	(d) = strdup_dst;						\
746} while (/* CONSTCOND */ 0)
747
748#ifdef MKSH_SMALL
749#ifndef MKSH_NOPWNAM
750#define MKSH_NOPWNAM		/* defined */
751#endif
752#ifndef MKSH_S_NOVI
753#define MKSH_S_NOVI		1
754#endif
755#endif
756
757#ifndef MKSH_S_NOVI
758#define MKSH_S_NOVI		0
759#endif
760
761#if defined(MKSH_NOPROSPECTOFWORK) && !defined(MKSH_UNEMPLOYED)
762#define MKSH_UNEMPLOYED		1
763#endif
764
765#define NUFILE		32	/* Number of user-accessible files */
766#define FDBASE		10	/* First file usable by Shell */
767
768/*
769 * simple grouping allocator
770 */
771
772
773/* 0. OS API: where to get memory from and how to free it (grouped) */
774
775/* malloc(3)/realloc(3) -> free(3) for use by the memory allocator */
776#define malloc_osi(sz)		malloc(sz)
777#define realloc_osi(p,sz)	realloc((p), (sz))
778#define free_osimalloc(p)	free(p)
779
780/* malloc(3)/realloc(3) -> free(3) for use by mksh code */
781#define malloc_osfunc(sz)	malloc(sz)
782#define realloc_osfunc(p,sz)	realloc((p), (sz))
783#define free_osfunc(p)		free(p)
784
785#if HAVE_MKNOD
786/* setmode(3) -> free(3) */
787#define free_ossetmode(p)	free(p)
788#endif
789
790#ifdef MKSH__NO_PATH_MAX
791/* GNU libc: get_current_dir_name(3) -> free(3) */
792#define free_gnu_gcdn(p)	free(p)
793#endif
794
795
796/* 1. internal structure */
797struct lalloc_common {
798	struct lalloc_common *next;
799};
800
801#ifdef MKSH_ALLOC_CATCH_UNDERRUNS
802struct lalloc_item {
803	struct lalloc_common *next;
804	size_t len;
805	char dummy[8192 - sizeof(struct lalloc_common *) - sizeof(size_t)];
806};
807#endif
808
809/* 2. sizes */
810#ifdef MKSH_ALLOC_CATCH_UNDERRUNS
811#define ALLOC_ITEM	struct lalloc_item
812#define ALLOC_OVERHEAD	0
813#else
814#define ALLOC_ITEM	struct lalloc_common
815#define ALLOC_OVERHEAD	(sizeof(ALLOC_ITEM))
816#endif
817
818/* 3. group structure */
819typedef struct lalloc_common Area;
820
821
822EXTERN Area aperm;		/* permanent object space */
823#define APERM	&aperm
824#define ATEMP	&e->area
825
826/*
827 * flags (the order of these enums MUST match the order in misc.c(options[]))
828 */
829enum sh_flag {
830#define SHFLAGS_ENUMS
831#include "sh_flags.gen"
832	FNFLAGS		/* (place holder: how many flags are there) */
833};
834
835#define Flag(f)	(shell_flags[(int)(f)])
836#define UTFMODE	Flag(FUNNYCODE)
837
838/*
839 * parsing & execution environment
840 *
841 * note that kshlongjmp MUST NOT be passed 0 as second argument!
842 */
843#ifdef MKSH_NO_SIGSETJMP
844#define kshjmp_buf	jmp_buf
845#define kshsetjmp(jbuf)	_setjmp(jbuf)
846#define kshlongjmp	_longjmp
847#else
848#define kshjmp_buf	sigjmp_buf
849#define kshsetjmp(jbuf)	sigsetjmp((jbuf), 0)
850#define kshlongjmp	siglongjmp
851#endif
852
853struct sretrace_info;
854struct yyrecursive_state;
855
856EXTERN struct sretrace_info *retrace_info;
857EXTERN unsigned int subshell_nesting_type;
858
859extern struct env {
860	ALLOC_ITEM alloc_INT;	/* internal, do not touch */
861	Area area;		/* temporary allocation area */
862	struct env *oenv;	/* link to previous environment */
863	struct block *loc;	/* local variables and functions */
864	short *savefd;		/* original redirected fds */
865	struct temp *temps;	/* temp files */
866	/* saved parser recursion state */
867	struct yyrecursive_state *yyrecursive_statep;
868	kshjmp_buf jbuf;	/* long jump back to env creator */
869	uint8_t type;		/* environment type - see below */
870	uint8_t flags;		/* EF_* */
871} *e;
872
873/* struct env.type values */
874#define E_NONE	0	/* dummy environment */
875#define E_PARSE	1	/* parsing command # */
876#define E_FUNC	2	/* executing function # */
877#define E_INCL	3	/* including a file via . # */
878#define E_EXEC	4	/* executing command tree */
879#define E_LOOP	5	/* executing for/while # */
880#define E_ERRH	6	/* general error handler # */
881#define E_GONE	7	/* hidden in child */
882#define E_EVAL	8	/* running eval # */
883/* # indicates env has valid jbuf (see unwind()) */
884
885/* struct env.flag values */
886#define EF_BRKCONT_PASS	BIT(1)	/* set if E_LOOP must pass break/continue on */
887#define EF_FAKE_SIGDIE	BIT(2)	/* hack to get info from unwind to quitenv */
888#define EF_IN_EVAL	BIT(3)	/* inside an eval */
889
890/* Do breaks/continues stop at env type e? */
891#define STOP_BRKCONT(t)	((t) == E_NONE || (t) == E_PARSE || \
892			    (t) == E_FUNC || (t) == E_INCL)
893/* Do returns stop at env type e? */
894#define STOP_RETURN(t)	((t) == E_FUNC || (t) == E_INCL)
895
896/* values for kshlongjmp(e->jbuf, i) */
897/* note that i MUST NOT be zero */
898#define LRETURN	1	/* return statement */
899#define LEXIT	2	/* exit statement */
900#define LERROR	3	/* errorf() called */
901#define LERREXT 4	/* set -e caused */
902#define LINTR	5	/* ^C noticed */
903#define LBREAK	6	/* break statement */
904#define LCONTIN	7	/* continue statement */
905#define LSHELL	8	/* return to interactive shell() */
906#define LAEXPR	9	/* error in arithmetic expression */
907#define LLEAVE	10	/* untrappable exit/error */
908
909/* sort of shell global state */
910EXTERN pid_t procpid;		/* PID of executing process */
911EXTERN int exstat;		/* exit status */
912EXTERN int subst_exstat;	/* exit status of last $(..)/`..` */
913EXTERN struct tbl *vp_pipest;	/* global PIPESTATUS array */
914EXTERN short trap_exstat;	/* exit status before running a trap */
915EXTERN uint8_t trap_nested;	/* running nested traps */
916EXTERN uint8_t shell_flags[FNFLAGS];
917EXTERN uint8_t baseline_flags[FNFLAGS
918#if !defined(MKSH_SMALL) || defined(DEBUG)
919    + 1
920#endif
921    ];
922EXTERN bool as_builtin;		/* direct builtin call */
923EXTERN const char *kshname;	/* $0 */
924EXTERN struct {
925	uid_t kshuid_v;		/* real UID of shell at startup */
926	uid_t ksheuid_v;	/* effective UID of shell */
927	gid_t kshgid_v;		/* real GID of shell at startup */
928	gid_t kshegid_v;	/* effective GID of shell */
929	pid_t kshpgrp_v;	/* process group of shell */
930	pid_t kshppid_v;	/* PID of parent of shell */
931	pid_t kshpid_v;		/* $$, shell PID */
932} rndsetupstate;
933
934#define kshpid		rndsetupstate.kshpid_v
935#define kshpgrp		rndsetupstate.kshpgrp_v
936#define kshuid		rndsetupstate.kshuid_v
937#define ksheuid		rndsetupstate.ksheuid_v
938#define kshgid		rndsetupstate.kshgid_v
939#define kshegid		rndsetupstate.kshegid_v
940#define kshppid		rndsetupstate.kshppid_v
941
942
943/* option processing */
944#define OF_CMDLINE	0x01	/* command line */
945#define OF_SET		0x02	/* set builtin */
946#define OF_SPECIAL	0x04	/* a special variable changing */
947#define OF_INTERNAL	0x08	/* set internally by shell */
948#define OF_FIRSTTIME	0x10	/* as early as possible, once */
949#define OF_ANY		(OF_CMDLINE | OF_SET | OF_SPECIAL | OF_INTERNAL)
950
951/* null value for variable; comparison pointer for unset */
952EXTERN char null[] E_INIT("");
953
954/* string pooling: do we rely on the compiler? */
955#ifndef HAVE_STRING_POOLING
956/* no, we use our own, saves quite some space */
957#elif HAVE_STRING_POOLING == 2
958/* “on demand” */
959#ifdef __GNUC__
960/* only for GCC 4 or later, older ones can get by without */
961#if __GNUC__ < 4
962#undef HAVE_STRING_POOLING
963#endif
964#else
965/* not GCC, default to on */
966#endif
967#elif HAVE_STRING_POOLING == 0
968/* default to on, unless explicitly set to 0 */
969#undef HAVE_STRING_POOLING
970#endif
971
972#ifndef HAVE_STRING_POOLING /* helpers for pooled strings */
973EXTERN const char T4spaces[] E_INIT("    ");
974#define T1space (Treal_sp2 + 5)
975#define Tcolsp (Tf_sD_ + 2)
976#define TC_IFSWS (TinitIFS + 4)
977EXTERN const char TinitIFS[] E_INIT("IFS= \t\n");
978EXTERN const char TFCEDIT_dollaru[] E_INIT("${FCEDIT:-/bin/ed} $_");
979#define Tspdollaru (TFCEDIT_dollaru + 18)
980EXTERN const char Tsgdot[] E_INIT("*=.");
981EXTERN const char Taugo[] E_INIT("augo");
982EXTERN const char Tbracket[] E_INIT("[");
983#define Tdot (Tsgdot + 2)
984#define Talias (Tunalias + 2)
985EXTERN const char Tbadnum[] E_INIT("bad number");
986#define Tbadsubst (Tfg_badsubst + 10)
987EXTERN const char Tbg[] E_INIT("bg");
988EXTERN const char Tbad_bsize[] E_INIT("bad shf/buf/bsize");
989#define Tbsize (Tbad_bsize + 12)
990EXTERN const char Tbad_sig_ss[] E_INIT("%s: bad signal '%s'");
991#define Tbad_sig_s (Tbad_sig_ss + 4)
992EXTERN const char Tsgbreak[] E_INIT("*=break");
993#define Tbreak (Tsgbreak + 2)
994EXTERN const char T__builtin[] E_INIT("-\\builtin");
995#define T_builtin (T__builtin + 1)
996#define Tbuiltin (T__builtin + 2)
997EXTERN const char Toomem[] E_INIT("can't allocate %zu data bytes");
998EXTERN const char Tcant_cd[] E_INIT("restricted shell - can't cd");
999EXTERN const char Tcant_find[] E_INIT("can't find");
1000EXTERN const char Tcant_open[] E_INIT("can't open");
1001#define Tbytes (Toomem + 24)
1002EXTERN const char Tbcat[] E_INIT("!cat");
1003#define Tcat (Tbcat + 1)
1004#define Tcd (Tcant_cd + 25)
1005#define T_command (T_funny_command + 9)
1006#define Tcommand (T_funny_command + 10)
1007EXTERN const char Tsgcontinue[] E_INIT("*=continue");
1008#define Tcontinue (Tsgcontinue + 2)
1009EXTERN const char Tcreate[] E_INIT("create");
1010EXTERN const char TELIF_unexpected[] E_INIT("TELIF unexpected");
1011EXTERN const char TEXECSHELL[] E_INIT("EXECSHELL");
1012EXTERN const char TENV[] E_INIT("ENV");
1013EXTERN const char Tdsgexport[] E_INIT("^*=export");
1014#define Texport (Tdsgexport + 3)
1015#ifdef __OS2__
1016EXTERN const char Textproc[] E_INIT("extproc");
1017#endif
1018EXTERN const char Tfalse[] E_INIT("false");
1019EXTERN const char Tfg[] E_INIT("fg");
1020EXTERN const char Tfg_badsubst[] E_INIT("fileglob: bad substitution");
1021#define Tfile (Tfile_fd + 20)
1022EXTERN const char Tfile_fd[] E_INIT("function definition file");
1023EXTERN const char TFPATH[] E_INIT("FPATH");
1024EXTERN const char T_function[] E_INIT(" function");
1025#define Tfunction (T_function + 1)
1026EXTERN const char T_funny_command[] E_INIT("funny $()-command");
1027EXTERN const char Tgetopts[] E_INIT("getopts");
1028#define Thistory (Tnot_in_history + 7)
1029EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented");
1030EXTERN const char Tinvname[] E_INIT("%s: invalid %s name");
1031EXTERN const char Tjobs[] E_INIT("jobs");
1032EXTERN const char Tjob_not_started[] E_INIT("job not started");
1033EXTERN const char Tmksh[] E_INIT("mksh");
1034#define Tname (Tinvname + 15)
1035EXTERN const char Tno_args[] E_INIT("missing argument");
1036EXTERN const char Tno_OLDPWD[] E_INIT("no OLDPWD");
1037EXTERN const char Tnot_ident[] E_INIT("is not an identifier");
1038EXTERN const char Tnot_in_history[] E_INIT("not in history");
1039EXTERN const char Tnot_found_s[] E_INIT("%s not found");
1040#define Tnot_found (Tnot_found_s + 3)
1041#define Tnot_started (Tjob_not_started + 4)
1042#define TOLDPWD (Tno_OLDPWD + 3)
1043#define Topen (Tcant_open + 6)
1044EXTERN const char To_o_reset[] E_INIT(" -o .reset");
1045#define To_reset (To_o_reset + 4)
1046#define TPATH (TFPATH + 1)
1047#define Tpo (Tset_po + 4)
1048#define Tpv (TpVv + 1)
1049EXTERN const char TpVv[] E_INIT("Vpv");
1050#define TPWD (Tno_OLDPWD + 6)
1051#define Tread (Tshf_read + 4)
1052EXTERN const char Tdsgreadonly[] E_INIT("^*=readonly");
1053#define Treadonly (Tdsgreadonly + 3)
1054EXTERN const char Tredirection_dup[] E_INIT("can't finish (dup) redirection");
1055#define Tredirection (Tredirection_dup + 19)
1056#define Treal_sp1 (Treal_sp2 + 1)
1057EXTERN const char Treal_sp2[] E_INIT(" real ");
1058EXTERN const char TREPLY[] E_INIT("REPLY");
1059EXTERN const char Treq_arg[] E_INIT("requires an argument");
1060EXTERN const char Tselect[] E_INIT("select");
1061#define Tset (Tf_parm + 18)
1062EXTERN const char Tset_po[] E_INIT("set +o");
1063EXTERN const char Tsghset[] E_INIT("*=#set");
1064#define Tsh (Tmksh + 2)
1065#define TSHELL (TEXECSHELL + 4)
1066#define Tshell (Ttoo_many_files + 23)
1067EXTERN const char Tshf_read[] E_INIT("shf_read");
1068EXTERN const char Tshf_write[] E_INIT("shf_write");
1069EXTERN const char Tgsource[] E_INIT("=source");
1070#define Tsource (Tgsource + 1)
1071EXTERN const char Tj_suspend[] E_INIT("j_suspend");
1072#define Tsuspend (Tj_suspend + 2)
1073EXTERN const char Tsynerr[] E_INIT("syntax error");
1074EXTERN const char Ttime[] E_INIT("time");
1075EXTERN const char Ttoo_many_args[] E_INIT("too many arguments");
1076EXTERN const char Ttoo_many_files[] E_INIT("too many open files in shell");
1077EXTERN const char Ttrue[] E_INIT("true");
1078EXTERN const char Ttty_fd_dupof[] E_INIT("dup of tty fd");
1079#define Ttty_fd (Ttty_fd_dupof + 7)
1080EXTERN const char Tdgtypeset[] E_INIT("^=typeset");
1081#define Ttypeset (Tdgtypeset + 2)
1082#define Tugo (Taugo + 1)
1083EXTERN const char Tunalias[] E_INIT("unalias");
1084#define Tunexpected (TELIF_unexpected + 6)
1085EXTERN const char Tunexpected_type[] E_INIT("%s: unexpected %s type %d");
1086EXTERN const char Tunknown_option[] E_INIT("unknown option");
1087EXTERN const char Tunwind[] E_INIT("unwind");
1088#define Tuser_sp1 (Tuser_sp2 + 1)
1089EXTERN const char Tuser_sp2[] E_INIT(" user ");
1090#define Twrite (Tshf_write + 4)
1091EXTERN const char Tf__S[] E_INIT(" %S");
1092#define Tf__d (Tunexpected_type + 22)
1093#define Tf_ss (Tf__ss + 1)
1094EXTERN const char Tf__ss[] E_INIT(" %s%s");
1095#define Tf__sN (Tf_s_s_sN + 5)
1096#define Tf_T (Tf_s_T + 3)
1097EXTERN const char Tf_dN[] E_INIT("%d\n");
1098EXTERN const char Tf_s_[] E_INIT("%s ");
1099EXTERN const char Tf_s_T[] E_INIT("%s %T");
1100EXTERN const char Tf_s_s_sN[] E_INIT("%s %s %s\n");
1101#define Tf_s_s (Tf_sD_s_s + 4)
1102#define Tf__s_s (Tf_sD_s_s + 3)
1103#define Tf_s_sD_s (Tf_cant_ss_s + 6)
1104EXTERN const char Tf_optfoo[] E_INIT("%s%s-%c: %s");
1105EXTERN const char Tf_sD_[] E_INIT("%s: ");
1106EXTERN const char Tf_szs[] E_INIT("%s: %zd %s");
1107EXTERN const char Tf_parm[] E_INIT("%s: parameter not set");
1108EXTERN const char Tf_coproc[] E_INIT("-p: %s");
1109EXTERN const char Tf_cant_s[] E_INIT("%s: can't %s");
1110EXTERN const char Tf_cant_ss_s[] E_INIT("can't %s %s: %s");
1111EXTERN const char Tf_heredoc[] E_INIT("here document '%s' unclosed");
1112#if HAVE_MKNOD
1113EXTERN const char Tf_nonnum[] E_INIT("non-numeric %s %s '%s'");
1114#endif
1115EXTERN const char Tf_S_[] E_INIT("%S ");
1116#define Tf_S (Tf__S + 1)
1117#define Tf_lu (Tf_toolarge + 17)
1118EXTERN const char Tf_toolarge[] E_INIT("%s %s too large: %lu");
1119EXTERN const char Tf_ldfailed[] E_INIT("%s %s(%d, %ld) failed: %s");
1120EXTERN const char Tf_sD_s_sD_s[] E_INIT("%s: %s %s: %s");
1121EXTERN const char Tf_toomany[] E_INIT("too many %ss");
1122EXTERN const char Tf_sd[] E_INIT("%s %d");
1123#define Tf_s (Tf_temp + 28)
1124EXTERN const char Tft_end[] E_INIT("%;");
1125EXTERN const char Tft_R[] E_INIT("%R");
1126#define Tf_d (Tunexpected_type + 23)
1127EXTERN const char Tf_sD_s_qs[] E_INIT("%s: %s '%s'");
1128EXTERN const char Tf_ro[] E_INIT("read-only: %s");
1129EXTERN const char Tf_flags[] E_INIT("%s: flags 0x%X");
1130EXTERN const char Tf_temp[] E_INIT("can't %s temporary file %s: %s");
1131EXTERN const char Tf_ssfaileds[] E_INIT("%s: %s failed: %s");
1132EXTERN const char Tf_sD_sD_s[] E_INIT("%s: %s: %s");
1133EXTERN const char Tf__c_[] E_INIT("-%c ");
1134EXTERN const char Tf_sD_s_s[] E_INIT("%s: %s %s");
1135#define Tf_sN (Tf_s_s_sN + 6)
1136#define Tf_sD_s (Tf_temp + 24)
1137EXTERN const char T_devtty[] E_INIT("/dev/tty");
1138#else /* helpers for string pooling */
1139#define T4spaces "    "
1140#define T1space " "
1141#define Tcolsp ": "
1142#define TC_IFSWS " \t\n"
1143#define TinitIFS "IFS= \t\n"
1144#define TFCEDIT_dollaru "${FCEDIT:-/bin/ed} $_"
1145#define Tspdollaru " $_"
1146#define Tsgdot "*=."
1147#define Taugo "augo"
1148#define Tbracket "["
1149#define Tdot "."
1150#define Talias "alias"
1151#define Tbadnum "bad number"
1152#define Tbadsubst "bad substitution"
1153#define Tbg "bg"
1154#define Tbad_bsize "bad shf/buf/bsize"
1155#define Tbsize "bsize"
1156#define Tbad_sig_ss "%s: bad signal '%s'"
1157#define Tbad_sig_s "bad signal '%s'"
1158#define Tsgbreak "*=break"
1159#define Tbreak "break"
1160#define T__builtin "-\\builtin"
1161#define T_builtin "\\builtin"
1162#define Tbuiltin "builtin"
1163#define Toomem "can't allocate %zu data bytes"
1164#define Tcant_cd "restricted shell - can't cd"
1165#define Tcant_find "can't find"
1166#define Tcant_open "can't open"
1167#define Tbytes "bytes"
1168#define Tbcat "!cat"
1169#define Tcat "cat"
1170#define Tcd "cd"
1171#define T_command "-command"
1172#define Tcommand "command"
1173#define Tsgcontinue "*=continue"
1174#define Tcontinue "continue"
1175#define Tcreate "create"
1176#define TELIF_unexpected "TELIF unexpected"
1177#define TEXECSHELL "EXECSHELL"
1178#define TENV "ENV"
1179#define Tdsgexport "^*=export"
1180#define Texport "export"
1181#ifdef __OS2__
1182#define Textproc "extproc"
1183#endif
1184#define Tfalse "false"
1185#define Tfg "fg"
1186#define Tfg_badsubst "fileglob: bad substitution"
1187#define Tfile "file"
1188#define Tfile_fd "function definition file"
1189#define TFPATH "FPATH"
1190#define T_function " function"
1191#define Tfunction "function"
1192#define T_funny_command "funny $()-command"
1193#define Tgetopts "getopts"
1194#define Thistory "history"
1195#define Tintovfl "integer overflow %zu %c %zu prevented"
1196#define Tinvname "%s: invalid %s name"
1197#define Tjobs "jobs"
1198#define Tjob_not_started "job not started"
1199#define Tmksh "mksh"
1200#define Tname "name"
1201#define Tno_args "missing argument"
1202#define Tno_OLDPWD "no OLDPWD"
1203#define Tnot_ident "is not an identifier"
1204#define Tnot_in_history "not in history"
1205#define Tnot_found_s "%s not found"
1206#define Tnot_found "not found"
1207#define Tnot_started "not started"
1208#define TOLDPWD "OLDPWD"
1209#define Topen "open"
1210#define To_o_reset " -o .reset"
1211#define To_reset ".reset"
1212#define TPATH "PATH"
1213#define Tpo "+o"
1214#define Tpv "pv"
1215#define TpVv "Vpv"
1216#define TPWD "PWD"
1217#define Tread "read"
1218#define Tdsgreadonly "^*=readonly"
1219#define Treadonly "readonly"
1220#define Tredirection_dup "can't finish (dup) redirection"
1221#define Tredirection "redirection"
1222#define Treal_sp1 "real "
1223#define Treal_sp2 " real "
1224#define TREPLY "REPLY"
1225#define Treq_arg "requires an argument"
1226#define Tselect "select"
1227#define Tset "set"
1228#define Tset_po "set +o"
1229#define Tsghset "*=#set"
1230#define Tsh "sh"
1231#define TSHELL "SHELL"
1232#define Tshell "shell"
1233#define Tshf_read "shf_read"
1234#define Tshf_write "shf_write"
1235#define Tgsource "=source"
1236#define Tsource "source"
1237#define Tj_suspend "j_suspend"
1238#define Tsuspend "suspend"
1239#define Tsynerr "syntax error"
1240#define Ttime "time"
1241#define Ttoo_many_args "too many arguments"
1242#define Ttoo_many_files "too many open files in shell"
1243#define Ttrue "true"
1244#define Ttty_fd_dupof "dup of tty fd"
1245#define Ttty_fd "tty fd"
1246#define Tdgtypeset "^=typeset"
1247#define Ttypeset "typeset"
1248#define Tugo "ugo"
1249#define Tunalias "unalias"
1250#define Tunexpected "unexpected"
1251#define Tunexpected_type "%s: unexpected %s type %d"
1252#define Tunknown_option "unknown option"
1253#define Tunwind "unwind"
1254#define Tuser_sp1 "user "
1255#define Tuser_sp2 " user "
1256#define Twrite "write"
1257#define Tf__S " %S"
1258#define Tf__d " %d"
1259#define Tf_ss "%s%s"
1260#define Tf__ss " %s%s"
1261#define Tf__sN " %s\n"
1262#define Tf_T "%T"
1263#define Tf_dN "%d\n"
1264#define Tf_s_ "%s "
1265#define Tf_s_T "%s %T"
1266#define Tf_s_s_sN "%s %s %s\n"
1267#define Tf_s_s "%s %s"
1268#define Tf__s_s " %s %s"
1269#define Tf_s_sD_s "%s %s: %s"
1270#define Tf_optfoo "%s%s-%c: %s"
1271#define Tf_sD_ "%s: "
1272#define Tf_szs "%s: %zd %s"
1273#define Tf_parm "%s: parameter not set"
1274#define Tf_coproc "-p: %s"
1275#define Tf_cant_s "%s: can't %s"
1276#define Tf_cant_ss_s "can't %s %s: %s"
1277#define Tf_heredoc "here document '%s' unclosed"
1278#if HAVE_MKNOD
1279#define Tf_nonnum "non-numeric %s %s '%s'"
1280#endif
1281#define Tf_S_ "%S "
1282#define Tf_S "%S"
1283#define Tf_lu "%lu"
1284#define Tf_toolarge "%s %s too large: %lu"
1285#define Tf_ldfailed "%s %s(%d, %ld) failed: %s"
1286#define Tf_sD_s_sD_s "%s: %s %s: %s"
1287#define Tf_toomany "too many %ss"
1288#define Tf_sd "%s %d"
1289#define Tf_s "%s"
1290#define Tft_end "%;"
1291#define Tft_R "%R"
1292#define Tf_d "%d"
1293#define Tf_sD_s_qs "%s: %s '%s'"
1294#define Tf_ro "read-only: %s"
1295#define Tf_flags "%s: flags 0x%X"
1296#define Tf_temp "can't %s temporary file %s: %s"
1297#define Tf_ssfaileds "%s: %s failed: %s"
1298#define Tf_sD_sD_s "%s: %s: %s"
1299#define Tf__c_ "-%c "
1300#define Tf_sD_s_s "%s: %s %s"
1301#define Tf_sN "%s\n"
1302#define Tf_sD_s "%s: %s"
1303#define T_devtty "/dev/tty"
1304#endif /* end of string pooling */
1305
1306typedef uint8_t Temp_type;
1307/* expanded heredoc */
1308#define TT_HEREDOC_EXP	0
1309/* temporary file used for history editing (fc -e) */
1310#define TT_HIST_EDIT	1
1311/* temporary file used during in-situ command substitution */
1312#define TT_FUNSUB	2
1313
1314/* temp/heredoc files. The file is removed when the struct is freed. */
1315struct temp {
1316	struct temp *next;
1317	struct shf *shf;
1318	/* pid of process parsed here-doc */
1319	pid_t pid;
1320	Temp_type type;
1321	/* actually longer: name (variable length) */
1322	char tffn[3];
1323};
1324
1325/*
1326 * stdio and our IO routines
1327 */
1328
1329#define shl_xtrace	(&shf_iob[0])	/* for set -x */
1330#define shl_stdout	(&shf_iob[1])
1331#define shl_out		(&shf_iob[2])
1332#ifdef DF
1333#define shl_dbg		(&shf_iob[3])	/* for DF() */
1334#endif
1335EXTERN bool shl_stdout_ok;
1336
1337/*
1338 * trap handlers
1339 */
1340typedef struct trap {
1341	const char *name;	/* short name */
1342	const char *mess;	/* descriptive name */
1343	char *trap;		/* trap command */
1344	sig_t cursig;		/* current handler (valid if TF_ORIG_* set) */
1345	sig_t shtrap;		/* shell signal handler */
1346	int signal;		/* signal number */
1347	int flags;		/* TF_* */
1348	volatile sig_atomic_t set; /* trap pending */
1349} Trap;
1350
1351/* values for Trap.flags */
1352#define TF_SHELL_USES	BIT(0)	/* shell uses signal, user can't change */
1353#define TF_USER_SET	BIT(1)	/* user has (tried to) set trap */
1354#define TF_ORIG_IGN	BIT(2)	/* original action was SIG_IGN */
1355#define TF_ORIG_DFL	BIT(3)	/* original action was SIG_DFL */
1356#define TF_EXEC_IGN	BIT(4)	/* restore SIG_IGN just before exec */
1357#define TF_EXEC_DFL	BIT(5)	/* restore SIG_DFL just before exec */
1358#define TF_DFL_INTR	BIT(6)	/* when received, default action is LINTR */
1359#define TF_TTY_INTR	BIT(7)	/* tty generated signal (see j_waitj) */
1360#define TF_CHANGED	BIT(8)	/* used by runtrap() to detect trap changes */
1361#define TF_FATAL	BIT(9)	/* causes termination if not trapped */
1362
1363/* values for setsig()/setexecsig() flags argument */
1364#define SS_RESTORE_MASK	0x3	/* how to restore a signal before an exec() */
1365#define SS_RESTORE_CURR	0	/* leave current handler in place */
1366#define SS_RESTORE_ORIG	1	/* restore original handler */
1367#define SS_RESTORE_DFL	2	/* restore to SIG_DFL */
1368#define SS_RESTORE_IGN	3	/* restore to SIG_IGN */
1369#define SS_FORCE	BIT(3)	/* set signal even if original signal ignored */
1370#define SS_USER		BIT(4)	/* user is doing the set (ie, trap command) */
1371#define SS_SHTRAP	BIT(5)	/* trap for internal use (ALRM, CHLD, WINCH) */
1372
1373#define ksh_SIGEXIT 0		/* for trap EXIT */
1374#define ksh_SIGERR  ksh_NSIG	/* for trap ERR */
1375
1376EXTERN volatile sig_atomic_t trap;	/* traps pending? */
1377EXTERN volatile sig_atomic_t intrsig;	/* pending trap interrupts command */
1378EXTERN volatile sig_atomic_t fatal_trap; /* received a fatal signal */
1379extern Trap sigtraps[ksh_NSIG + 1];
1380
1381/* got_winch = 1 when we need to re-adjust the window size */
1382#ifdef SIGWINCH
1383EXTERN volatile sig_atomic_t got_winch E_INIT(1);
1384#else
1385#define got_winch	true
1386#endif
1387
1388/*
1389 * TMOUT support
1390 */
1391/* values for ksh_tmout_state */
1392enum tmout_enum {
1393	TMOUT_EXECUTING = 0,	/* executing commands */
1394	TMOUT_READING,		/* waiting for input */
1395	TMOUT_LEAVING		/* have timed out */
1396};
1397EXTERN unsigned int ksh_tmout;
1398EXTERN enum tmout_enum ksh_tmout_state;
1399
1400/* For "You have stopped jobs" message */
1401EXTERN bool really_exit;
1402
1403/*
1404 * fast character classes
1405 */
1406
1407/* internal types, do not reference */
1408
1409/* initially empty — filled at runtime from $IFS */
1410#define CiIFS	BIT(0)
1411#define CiCNTRL	BIT(1)	/* \x01‥\x08\x0E‥\x1F\x7F	*/
1412#define CiUPPER	BIT(2)	/* A‥Z				*/
1413#define CiLOWER	BIT(3)	/* a‥z				*/
1414#define CiHEXLT	BIT(4)	/* A‥Fa‥f			*/
1415#define CiOCTAL	BIT(5)	/* 0‥7				*/
1416#define CiQCL	BIT(6)	/* &();|			*/
1417#define CiALIAS	BIT(7)	/* !,.@				*/
1418#define CiQCX	BIT(8)	/* *[\\				*/
1419#define CiVAR1	BIT(9)	/* !*@				*/
1420#define CiQCM	BIT(10)	/* /^~				*/
1421#define CiDIGIT	BIT(11)	/* 89				*/
1422#define CiQC	BIT(12)	/* "'				*/
1423#define CiSPX	BIT(13)	/* \x0B\x0C			*/
1424#define CiCURLY	BIT(14)	/* {}				*/
1425#define CiANGLE	BIT(15)	/* <>				*/
1426#define CiNUL	BIT(16)	/* \x00				*/
1427#define CiTAB	BIT(17)	/* \x09				*/
1428#define CiNL	BIT(18)	/* \x0A				*/
1429#define CiCR	BIT(19)	/* \x0D				*/
1430#define CiSP	BIT(20)	/* \x20				*/
1431#define CiHASH	BIT(21)	/* #				*/
1432#define CiSS	BIT(22)	/* $				*/
1433#define CiPERCT	BIT(23)	/* %				*/
1434#define CiPLUS	BIT(24)	/* +				*/
1435#define CiMINUS	BIT(25)	/* -				*/
1436#define CiCOLON	BIT(26)	/* :				*/
1437#define CiEQUAL	BIT(27)	/* =				*/
1438#define CiQUEST	BIT(28)	/* ?				*/
1439#define CiBRACK	BIT(29)	/* []				*/
1440#define CiUNDER	BIT(30)	/* _				*/
1441#define CiGRAVE	BIT(31)	/* `				*/
1442/* out of space, but one for *@ would make sense, possibly others */
1443
1444/* compile-time initialised, ASCII only */
1445extern const uint32_t tpl_ctypes[128];
1446/* run-time, contains C_IFS as well, full 2⁸ octet range */
1447EXTERN uint32_t ksh_ctypes[256];
1448/* first octet of $IFS, for concatenating "$*" */
1449EXTERN char ifs0;
1450
1451/* external types */
1452
1453/* !%+,-.0‥9:@A‥Z[]_a‥z	valid characters in alias names */
1454#define C_ALIAS	(CiALIAS | CiBRACK | CiCOLON | CiDIGIT | CiLOWER | CiMINUS | CiOCTAL | CiPERCT | CiPLUS | CiUNDER | CiUPPER)
1455/* 0‥9A‥Za‥z		alphanumerical */
1456#define C_ALNUM	(CiDIGIT | CiLOWER | CiOCTAL | CiUPPER)
1457/* 0‥9A‥Z_a‥z		alphanumerical plus underscore (“word character”) */
1458#define C_ALNUX	(CiDIGIT | CiLOWER | CiOCTAL | CiUNDER | CiUPPER)
1459/* A‥Za‥z		alphabetical (upper plus lower) */
1460#define C_ALPHA	(CiLOWER | CiUPPER)
1461/* A‥Z_a‥z		alphabetical plus underscore (identifier lead) */
1462#define C_ALPHX	(CiLOWER | CiUNDER | CiUPPER)
1463/* \x01‥\x7F		7-bit ASCII except NUL */
1464#define C_ASCII (CiALIAS | CiANGLE | CiBRACK | CiCNTRL | CiCOLON | CiCR | CiCURLY | CiDIGIT | CiEQUAL | CiGRAVE | CiHASH | CiLOWER | CiMINUS | CiNL | CiOCTAL | CiPERCT | CiPLUS | CiQC | CiQCL | CiQCM | CiQCX | CiQUEST | CiSP | CiSPX | CiSS | CiTAB | CiUNDER | CiUPPER)
1465/* \x09\x20		tab and space */
1466#define C_BLANK	(CiSP | CiTAB)
1467/* \x09\x20"'		separator for completion */
1468#define C_CFS	(CiQC | CiSP | CiTAB)
1469/* \x00‥\x1F\x7F	POSIX control characters */
1470#define C_CNTRL	(CiCNTRL | CiCR | CiNL | CiNUL | CiSPX | CiTAB)
1471/* 0‥9			decimal digits */
1472#define C_DIGIT	(CiDIGIT | CiOCTAL)
1473/* &();`|			editor x_locate_word() command */
1474#define C_EDCMD	(CiGRAVE | CiQCL)
1475/* \x09\x0A\x20"&'():;<=>`|	editor non-word characters */
1476#define C_EDNWC	(CiANGLE | CiCOLON | CiEQUAL | CiGRAVE | CiNL | CiQC | CiQCL | CiSP | CiTAB)
1477/* "#$&'()*:;<=>?[\\`{|}	editor quotes for tab completion */
1478#define C_EDQ	(CiANGLE | CiCOLON | CiCURLY | CiEQUAL | CiGRAVE | CiHASH | CiQC | CiQCL | CiQCX | CiQUEST | CiSS)
1479/* !‥~			POSIX graphical (alphanumerical plus punctuation) */
1480#define C_GRAPH	(C_PUNCT | CiDIGIT | CiLOWER | CiOCTAL | CiUPPER)
1481/* A‥Fa‥f		hex letter */
1482#define C_HEXLT	CiHEXLT
1483/* \x00 + $IFS		IFS whitespace, IFS non-whitespace, NUL */
1484#define C_IFS	(CiIFS | CiNUL)
1485/* \x09\x0A\x20		IFS whitespace */
1486#define C_IFSWS	(CiNL | CiSP | CiTAB)
1487/* \x09\x0A\x20&();<>|	(for the lexer) */
1488#define C_LEX1	(CiANGLE | CiNL | CiQCL | CiSP | CiTAB)
1489/* a‥z			lowercase letters */
1490#define C_LOWER	CiLOWER
1491/* not alnux or dollar	separator for motion */
1492#define C_MFS	(CiALIAS | CiANGLE | CiBRACK | CiCNTRL | CiCOLON | CiCR | CiCURLY | CiEQUAL | CiGRAVE | CiHASH | CiMINUS | CiNL | CiNUL | CiPERCT | CiPLUS | CiQC | CiQCL | CiQCM | CiQCX | CiQUEST | CiSP | CiSPX | CiTAB)
1493/* 0‥7			octal digit */
1494#define C_OCTAL	CiOCTAL
1495/* !*+?@		pattern magical operator, except space */
1496#define C_PATMO	(CiPLUS | CiQUEST | CiVAR1)
1497/* \x20‥~		POSIX printable characters (graph plus space) */
1498#define C_PRINT	(C_GRAPH | CiSP)
1499/* !"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~	POSIX punctuation */
1500#define C_PUNCT	(CiALIAS | CiANGLE | CiBRACK | CiCOLON | CiCURLY | CiEQUAL | CiGRAVE | CiHASH | CiMINUS | CiPERCT | CiPLUS | CiQC | CiQCL | CiQCM | CiQCX | CiQUEST | CiSS | CiUNDER)
1501/* \x09\x0A"#$&'()*;<=>?[\\]`|	characters requiring quoting, minus space */
1502#define C_QUOTE	(CiANGLE | CiBRACK | CiEQUAL | CiGRAVE | CiHASH | CiNL | CiQC | CiQCL | CiQCX | CiQUEST | CiSS | CiTAB)
1503/* 0‥9A‥Fa‥f		hexadecimal digit */
1504#define C_SEDEC	(CiDIGIT | CiHEXLT | CiOCTAL)
1505/* \x09‥\x0D\x20	POSIX space class */
1506#define C_SPACE	(CiCR | CiNL | CiSP | CiSPX | CiTAB)
1507/* +-=?			substitution operations with word */
1508#define C_SUB1	(CiEQUAL | CiMINUS | CiPLUS | CiQUEST)
1509/* #%			substitution operations with pattern */
1510#define C_SUB2	(CiHASH | CiPERCT)
1511/* A‥Z			uppercase letters */
1512#define C_UPPER	CiUPPER
1513/* !#$*-?@		substitution parameters, other than positional */
1514#define C_VAR1	(CiHASH | CiMINUS | CiQUEST | CiSS | CiVAR1)
1515
1516/* individual chars you might like */
1517#define C_ANGLE	CiANGLE		/* <>	angle brackets */
1518#define C_COLON	CiCOLON		/* :	colon */
1519#define C_CR	CiCR		/* \x0D	ASCII carriage return */
1520#define C_DOLAR	CiSS		/* $	dollar sign */
1521#define C_EQUAL	CiEQUAL		/* =	equals sign */
1522#define C_GRAVE	CiGRAVE		/* `	accent gravis */
1523#define C_HASH	CiHASH		/* #	hash sign */
1524#define C_LF	CiNL		/* \x0A	ASCII line feed */
1525#define C_MINUS	CiMINUS		/* -	hyphen-minus */
1526#ifdef MKSH_WITH_TEXTMODE
1527#define C_NL	(CiNL | CiCR)	/* 	CR or LF under OS/2 TEXTMODE */
1528#else
1529#define C_NL	CiNL		/* 	LF only like under Unix */
1530#endif
1531#define C_NUL	CiNUL		/* \x00	ASCII NUL */
1532#define C_PLUS	CiPLUS		/* +	plus sign */
1533#define C_QC	CiQC		/* "'	quote characters */
1534#define C_QUEST	CiQUEST		/* ?	question mark */
1535#define C_SPC	CiSP		/* \x20	ASCII space */
1536#define C_TAB	CiTAB		/* \x09	ASCII horizontal tabulator */
1537#define C_UNDER	CiUNDER		/* _	underscore */
1538
1539/* identity transform of octet */
1540#if defined(DEBUG) && defined(__GNUC__) && !defined(__ICC) && \
1541    !defined(__INTEL_COMPILER) && !defined(__SUNPRO_C)
1542extern unsigned int eek_ord;
1543#define ORD(c)	((size_t)(c) > 0xFF ? eek_ord : \
1544		    ((unsigned int)(unsigned char)(c)))
1545#define ord(c)	__builtin_choose_expr(				\
1546    __builtin_types_compatible_p(__typeof__(c), char) ||	\
1547    __builtin_types_compatible_p(__typeof__(c), unsigned char),	\
1548    ((unsigned int)(unsigned char)(c)), ({			\
1549	size_t ord_c = (c);					\
1550								\
1551	if (ord_c > (size_t)0xFFU)				\
1552		internal_errorf("%s:%d:ord(%zX)",		\
1553		    __FILE__, __LINE__, ord_c);			\
1554	((unsigned int)(unsigned char)(ord_c));			\
1555}))
1556#else
1557#define ord(c)	((unsigned int)(unsigned char)(c))
1558#define ORD(c)	ord(c) /* may evaluate arguments twice */
1559#endif
1560#if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC)
1561EXTERN unsigned short ebcdic_map[256];
1562EXTERN unsigned char ebcdic_rtt_toascii[256];
1563EXTERN unsigned char ebcdic_rtt_fromascii[256];
1564extern void ebcdic_init(void);
1565/* one-way to-ascii-or-high conversion, for POSIX locale ordering */
1566#define asciibetical(c)	((unsigned int)ebcdic_map[(unsigned char)(c)])
1567/* two-way round-trip conversion, for general use */
1568#define rtt2asc(c)	ebcdic_rtt_toascii[(unsigned char)(c)]
1569#define asc2rtt(c)	ebcdic_rtt_fromascii[(unsigned char)(c)]
1570/* case-independent char comparison */
1571#define ksh_eq(c,u,l)	(ord(c) == ord(u) || ord(c) == ord(l))
1572#else
1573#define asciibetical(c)	ord(c)
1574#define rtt2asc(c)	((unsigned char)(c))
1575#define asc2rtt(c)	((unsigned char)(c))
1576#define ksh_eq(c,u,l)	((ord(c) | 0x20) == ord(l))
1577#endif
1578/* control character foo */
1579#ifdef MKSH_EBCDIC
1580#define ksh_isctrl(c)	(ord(c) < 0x40 || ord(c) == 0xFF)
1581#else
1582#define ksh_isctrl(c)	((ord(c) & 0x7F) < 0x20 || ord(c) == 0x7F)
1583#endif
1584/* new fast character classes */
1585#define ctype(c,t)	tobool(ksh_ctypes[ord(c)] & (t))
1586#define cinttype(c,t)	((c) >= 0 && (c) <= 0xFF ? \
1587			tobool(ksh_ctypes[(unsigned char)(c)] & (t)) : false)
1588/* helper functions */
1589#define ksh_isdash(s)	tobool(ord((s)[0]) == '-' && ord((s)[1]) == '\0')
1590/* invariant distance even in EBCDIC */
1591#define ksh_tolower(c)	(ctype(c, C_UPPER) ? (c) - 'A' + 'a' : (c))
1592#define ksh_toupper(c)	(ctype(c, C_LOWER) ? (c) - 'a' + 'A' : (c))
1593/* strictly speaking rtt2asc() here, but this works even in EBCDIC */
1594#define ksh_numdig(c)	(ord(c) - ORD('0'))
1595#define ksh_numuc(c)	(rtt2asc(c) - rtt2asc('A'))
1596#define ksh_numlc(c)	(rtt2asc(c) - rtt2asc('a'))
1597#define ksh_toctrl(c)	asc2rtt(ord(c) == ORD('?') ? 0x7F : rtt2asc(c) & 0x9F)
1598#define ksh_unctrl(c)	asc2rtt(rtt2asc(c) ^ 0x40U)
1599
1600#ifdef MKSH_SMALL
1601#define SMALLP(x)	/* nothing */
1602#else
1603#define SMALLP(x)	, x
1604#endif
1605
1606/* Argument parsing for built-in commands and getopts command */
1607
1608/* Values for Getopt.flags */
1609#define GF_ERROR	BIT(0)	/* call errorf() if there is an error */
1610#define GF_PLUSOPT	BIT(1)	/* allow +c as an option */
1611#define GF_NONAME	BIT(2)	/* don't print argv[0] in errors */
1612
1613/* Values for Getopt.info */
1614#define GI_MINUS	BIT(0)	/* an option started with -... */
1615#define GI_PLUS		BIT(1)	/* an option started with +... */
1616#define GI_MINUSMINUS	BIT(2)	/* arguments were ended with -- */
1617
1618/* in case some OS defines these */
1619#undef optarg
1620#undef optind
1621
1622typedef struct {
1623	const char *optarg;
1624	int optind;
1625	int uoptind;		/* what user sees in $OPTIND */
1626	int flags;		/* see GF_* */
1627	int info;		/* see GI_* */
1628	unsigned int p;		/* 0 or index into argv[optind - 1] */
1629	char buf[2];		/* for bad option OPTARG value */
1630} Getopt;
1631
1632EXTERN Getopt builtin_opt;	/* for shell builtin commands */
1633EXTERN Getopt user_opt;		/* parsing state for getopts builtin command */
1634
1635/* This for co-processes */
1636
1637/* something that won't (realisticly) wrap */
1638typedef int Coproc_id;
1639
1640struct coproc {
1641	void *job;	/* 0 or job of co-process using input pipe */
1642	int read;	/* pipe from co-process's stdout */
1643	int readw;	/* other side of read (saved temporarily) */
1644	int write;	/* pipe to co-process's stdin */
1645	int njobs;	/* number of live jobs using output pipe */
1646	Coproc_id id;	/* id of current output pipe */
1647};
1648EXTERN struct coproc coproc;
1649
1650#ifndef MKSH_NOPROSPECTOFWORK
1651/* used in jobs.c and by coprocess stuff in exec.c and select() calls */
1652EXTERN sigset_t		sm_default, sm_sigchld;
1653#endif
1654
1655/* name of called builtin function (used by error functions) */
1656EXTERN const char *builtin_argv0;
1657/* is called builtin a POSIX special builtin? (error functions only) */
1658EXTERN bool builtin_spec;
1659
1660/* current working directory */
1661EXTERN char	*current_wd;
1662
1663/* input line size */
1664#ifdef MKSH_SMALL
1665#define LINE		(4096 - ALLOC_OVERHEAD)
1666#else
1667#define LINE		(16384 - ALLOC_OVERHEAD)
1668#endif
1669/* columns and lines of the tty */
1670EXTERN mksh_ari_t x_cols E_INIT(80);
1671EXTERN mksh_ari_t x_lins E_INIT(24);
1672
1673
1674/* Determine the location of the system (common) profile */
1675
1676#ifndef MKSH_DEFAULT_PROFILEDIR
1677#define MKSH_DEFAULT_PROFILEDIR	MKSH_UNIXROOT "/etc"
1678#endif
1679
1680#define MKSH_SYSTEM_PROFILE	MKSH_DEFAULT_PROFILEDIR "/profile"
1681#define MKSH_SUID_PROFILE	MKSH_DEFAULT_PROFILEDIR "/suid_profile"
1682
1683
1684/* Used by v_evaluate() and setstr() to control action when error occurs */
1685#define KSH_UNWIND_ERROR	0	/* unwind the stack (kshlongjmp) */
1686#define KSH_RETURN_ERROR	1	/* return 1/0 for success/failure */
1687
1688/*
1689 * Shell file I/O routines
1690 */
1691
1692#define SHF_BSIZE		512
1693
1694#define shf_fileno(shf)		((shf)->fd)
1695#define shf_setfileno(shf,nfd)	((shf)->fd = (nfd))
1696#define shf_getc_i(shf)		((shf)->rnleft > 0 ? \
1697				    (shf)->rnleft--, (int)ord(*(shf)->rp++) : \
1698				    shf_getchar(shf))
1699#define shf_putc_i(c,shf)	((shf)->wnleft == 0 ? \
1700				    shf_putchar((uint8_t)(c), (shf)) : \
1701				    ((shf)->wnleft--, *(shf)->wp++ = (c)))
1702#define shf_eof(shf)		((shf)->flags & SHF_EOF)
1703#define shf_error(shf)		((shf)->flags & SHF_ERROR)
1704#define shf_errno(shf)		((shf)->errnosv)
1705#define shf_clearerr(shf)	((shf)->flags &= ~(SHF_EOF | SHF_ERROR))
1706
1707/* Flags passed to shf_*open() */
1708#define SHF_RD		0x0001
1709#define SHF_WR		0x0002
1710#define SHF_RDWR	(SHF_RD | SHF_WR)
1711#define SHF_ACCMODE	0x0003		/* mask */
1712#define SHF_GETFL	0x0004		/* use fcntl() to figure RD/WR flags */
1713#define SHF_UNBUF	0x0008		/* unbuffered I/O */
1714#define SHF_CLEXEC	0x0010		/* set close on exec flag */
1715#define SHF_MAPHI	0x0020		/* make fd > FDBASE (and close orig)
1716					 * (shf_open() only) */
1717#define SHF_DYNAMIC	0x0040		/* string: increase buffer as needed */
1718#define SHF_INTERRUPT	0x0080		/* EINTR in read/write causes error */
1719/* Flags used internally */
1720#define SHF_STRING	0x0100		/* a string, not a file */
1721#define SHF_ALLOCS	0x0200		/* shf and shf->buf were alloc()ed */
1722#define SHF_ALLOCB	0x0400		/* shf->buf was alloc()ed */
1723#define SHF_ERROR	0x0800		/* read()/write() error */
1724#define SHF_EOF		0x1000		/* read eof (sticky) */
1725#define SHF_READING	0x2000		/* currently reading: rnleft,rp valid */
1726#define SHF_WRITING	0x4000		/* currently writing: wnleft,wp valid */
1727
1728
1729struct shf {
1730	Area *areap;		/* area shf/buf were allocated in */
1731	unsigned char *rp;	/* read: current position in buffer */
1732	unsigned char *wp;	/* write: current position in buffer */
1733	unsigned char *buf;	/* buffer */
1734	ssize_t bsize;		/* actual size of buf */
1735	ssize_t rbsize;		/* size of buffer (1 if SHF_UNBUF) */
1736	ssize_t rnleft;		/* read: how much data left in buffer */
1737	ssize_t wbsize;		/* size of buffer (0 if SHF_UNBUF) */
1738	ssize_t wnleft;		/* write: how much space left in buffer */
1739	int flags;		/* see SHF_* */
1740	int fd;			/* file descriptor */
1741	int errnosv;		/* saved value of errno after error */
1742};
1743
1744extern struct shf shf_iob[];
1745
1746struct table {
1747	Area *areap;		/* area to allocate entries */
1748	struct tbl **tbls;	/* hashed table items */
1749	size_t nfree;		/* free table entries */
1750	uint8_t tshift;		/* table size (2^tshift) */
1751};
1752
1753/* table item */
1754struct tbl {
1755	/* Area to allocate from */
1756	Area *areap;
1757	/* value */
1758	union {
1759		char *s;			/* string */
1760		mksh_ari_t i;			/* integer */
1761		mksh_uari_t u;			/* unsigned integer */
1762		int (*f)(const char **);	/* built-in command */
1763		struct op *t;			/* "function" tree */
1764	} val;
1765	union {
1766		struct tbl *array;	/* array values */
1767		const char *fpath;	/* temporary path to undef function */
1768	} u;
1769	union {
1770		int field;		/* field with for -L/-R/-Z */
1771		int errnov;		/* CEXEC/CTALIAS */
1772	} u2;
1773	union {
1774		uint32_t hval;		/* hash(name) */
1775		uint32_t index;		/* index for an array */
1776	} ua;
1777	/*
1778	 * command type (see below), base (if INTEGER),
1779	 * offset from val.s of value (if EXPORT)
1780	 */
1781	int type;
1782	/* flags (see below) */
1783	uint32_t flag;
1784
1785	/* actually longer: name (variable length) */
1786	char name[4];
1787};
1788
1789EXTERN struct tbl *vtemp;
1790/* set by isglobal(), global() and local() */
1791EXTERN bool last_lookup_was_array;
1792
1793/* common flag bits */
1794#define ALLOC		BIT(0)	/* val.s has been allocated */
1795#define DEFINED		BIT(1)	/* is defined in block */
1796#define ISSET		BIT(2)	/* has value, vp->val.[si] */
1797#define EXPORT		BIT(3)	/* exported variable/function */
1798#define TRACE		BIT(4)	/* var: user flagged, func: execution tracing */
1799/* (start non-common flags at 8) */
1800/* flag bits used for variables */
1801#define SPECIAL		BIT(8)	/* PATH, IFS, SECONDS, etc */
1802#define INTEGER		BIT(9)	/* val.i contains integer value */
1803#define RDONLY		BIT(10)	/* read-only variable */
1804#define LOCAL		BIT(11)	/* for local typeset() */
1805#define ARRAY		BIT(13)	/* array */
1806#define LJUST		BIT(14)	/* left justify */
1807#define RJUST		BIT(15)	/* right justify */
1808#define ZEROFIL		BIT(16)	/* 0 filled if RJUSTIFY, strip 0s if LJUSTIFY */
1809#define LCASEV		BIT(17)	/* convert to lower case */
1810#define UCASEV_AL	BIT(18) /* convert to upper case / autoload function */
1811#define INT_U		BIT(19)	/* unsigned integer */
1812#define INT_L		BIT(20)	/* long integer (no-op but used as magic) */
1813#define IMPORT		BIT(21)	/* flag to typeset(): no arrays, must have = */
1814#define LOCAL_COPY	BIT(22)	/* with LOCAL - copy attrs from existing var */
1815#define EXPRINEVAL	BIT(23)	/* contents currently being evaluated */
1816#define EXPRLVALUE	BIT(24)	/* useable as lvalue (temp flag) */
1817#define AINDEX		BIT(25) /* array index >0 = ua.index filled in */
1818#define ASSOC		BIT(26) /* ARRAY ? associative : reference */
1819/* flag bits used for taliases/builtins/aliases/keywords/functions */
1820#define KEEPASN		BIT(8)	/* keep command assignments (eg, var=x cmd) */
1821#define FINUSE		BIT(9)	/* function being executed */
1822#define FDELETE		BIT(10)	/* function deleted while it was executing */
1823#define FKSH		BIT(11)	/* function defined with function x (vs x()) */
1824#define SPEC_BI		BIT(12)	/* a POSIX special builtin */
1825#define LOWER_BI	BIT(13)	/* (with LOW_BI) override even w/o flags */
1826#define LOW_BI		BIT(14)	/* external utility overrides built-in one */
1827#define DECL_UTIL	BIT(15)	/* is declaration utility */
1828#define DECL_FWDR	BIT(16) /* is declaration utility forwarder */
1829#define NEXTLOC_BI	BIT(17)	/* needs BF_RESETSPEC on e->loc */
1830
1831/*
1832 * Attributes that can be set by the user (used to decide if an unset
1833 * param should be repoted by set/typeset). Does not include ARRAY or
1834 * LOCAL.
1835 */
1836#define USERATTRIB	(EXPORT | INTEGER | RDONLY | LJUST | RJUST | ZEROFIL | \
1837			    LCASEV | UCASEV_AL | INT_U | INT_L)
1838
1839#define arrayindex(vp)	((unsigned long)((vp)->flag & AINDEX ? \
1840			    (vp)->ua.index : 0))
1841
1842enum namerefflag {
1843	SRF_NOP,
1844	SRF_ENABLE,
1845	SRF_DISABLE
1846};
1847
1848/* command types */
1849#define CNONE		0	/* undefined */
1850#define CSHELL		1	/* built-in */
1851#define CFUNC		2	/* function */
1852#define CEXEC		4	/* executable command */
1853#define CALIAS		5	/* alias */
1854#define CKEYWD		6	/* keyword */
1855#define CTALIAS		7	/* tracked alias */
1856
1857/* Flags for findcom()/comexec() */
1858#define FC_SPECBI	BIT(0)	/* special builtin */
1859#define FC_FUNC		BIT(1)	/* function */
1860#define FC_NORMBI	BIT(2)	/* not special builtin */
1861#define FC_BI		(FC_SPECBI | FC_NORMBI)
1862#define FC_PATH		BIT(3)	/* do path search */
1863#define FC_DEFPATH	BIT(4)	/* use default path in path search */
1864#define FC_WHENCE	BIT(5)	/* for use by command and whence */
1865
1866#define AF_ARGV_ALLOC	0x1	/* argv[] array allocated */
1867#define AF_ARGS_ALLOCED	0x2	/* argument strings allocated */
1868#define AI_ARGV(a,i)	((i) == 0 ? (a).argv[0] : (a).argv[(i) - (a).skip])
1869#define AI_ARGC(a)	((a).ai_argc - (a).skip)
1870
1871/* Argument info. Used for $#, $* for shell, functions, includes, etc. */
1872struct arg_info {
1873	const char **argv;
1874	int flags;	/* AF_* */
1875	int ai_argc;
1876	int skip;	/* first arg is argv[0], second is argv[1 + skip] */
1877};
1878
1879/*
1880 * activation record for function blocks
1881 */
1882struct block {
1883	Area area;		/* area to allocate things */
1884	const char **argv;
1885	char *error;		/* error handler */
1886	char *exit;		/* exit handler */
1887	struct block *next;	/* enclosing block */
1888	struct table vars;	/* local variables */
1889	struct table funs;	/* local functions */
1890	Getopt getopts_state;
1891	int argc;
1892	int flags;		/* see BF_* */
1893};
1894
1895/* Values for struct block.flags */
1896#define BF_DOGETOPTS	BIT(0)	/* save/restore getopts state */
1897#define BF_STOPENV	BIT(1)	/* do not export further */
1898/* BF_RESETSPEC and NEXTLOC_BI must be numerically identical! */
1899#define BF_RESETSPEC	BIT(17)	/* use ->next for set and shift */
1900
1901/*
1902 * Used by ktwalk() and ktnext() routines.
1903 */
1904struct tstate {
1905	struct tbl **next;
1906	ssize_t left;
1907};
1908
1909EXTERN struct table taliases;	/* tracked aliases */
1910EXTERN struct table builtins;	/* built-in commands */
1911EXTERN struct table aliases;	/* aliases */
1912EXTERN struct table keywords;	/* keywords */
1913#ifndef MKSH_NOPWNAM
1914EXTERN struct table homedirs;	/* homedir() cache */
1915#endif
1916
1917struct builtin {
1918	const char *name;
1919	int (*func)(const char **);
1920};
1921
1922extern const struct builtin mkshbuiltins[];
1923
1924/* values for set_prompt() */
1925#define PS1	0	/* command */
1926#define PS2	1	/* command continuation */
1927
1928EXTERN char *path;		/* copy of either PATH or def_path */
1929EXTERN const char *def_path;	/* path to use if PATH not set */
1930EXTERN char *tmpdir;		/* TMPDIR value */
1931EXTERN const char *prompt;
1932EXTERN uint8_t cur_prompt;	/* PS1 or PS2 */
1933EXTERN int current_lineno;	/* LINENO value */
1934
1935/*
1936 * Description of a command or an operation on commands.
1937 */
1938struct op {
1939	const char **args;		/* arguments to a command */
1940	char **vars;			/* variable assignments */
1941	struct ioword **ioact;		/* IO actions (eg, < > >>) */
1942	struct op *left, *right;	/* descendents */
1943	char *str;			/* word for case; identifier for for,
1944					 * select, and functions;
1945					 * path to execute for TEXEC;
1946					 * time hook for TCOM.
1947					 */
1948	int lineno;			/* TCOM/TFUNC: LINENO for this */
1949	short type;			/* operation type, see below */
1950	/* WARNING: newtp(), tcopy() use evalflags = 0 to clear union */
1951	union {
1952		/* TCOM: arg expansion eval() flags */
1953		short evalflags;
1954		/* TFUNC: function x (vs x()) */
1955		short ksh_func;
1956		/* TPAT: termination character */
1957		char charflag;
1958	} u;
1959};
1960
1961/* Tree.type values */
1962#define TEOF		0
1963#define TCOM		1	/* command */
1964#define TPAREN		2	/* (c-list) */
1965#define TPIPE		3	/* a | b */
1966#define TLIST		4	/* a ; b */
1967#define TOR		5	/* || */
1968#define TAND		6	/* && */
1969#define TBANG		7	/* ! */
1970#define TDBRACKET	8	/* [[ .. ]] */
1971#define TFOR		9
1972#define TSELECT		10
1973#define TCASE		11
1974#define TIF		12
1975#define TWHILE		13
1976#define TUNTIL		14
1977#define TELIF		15
1978#define TPAT		16	/* pattern in case */
1979#define TBRACE		17	/* {c-list} */
1980#define TASYNC		18	/* c & */
1981#define TFUNCT		19	/* function name { command; } */
1982#define TTIME		20	/* time pipeline */
1983#define TEXEC		21	/* fork/exec eval'd TCOM */
1984#define TCOPROC		22	/* coprocess |& */
1985
1986/*
1987 * prefix codes for words in command tree
1988 */
1989#define EOS	0	/* end of string */
1990#define CHAR	1	/* unquoted character */
1991#define QCHAR	2	/* quoted character */
1992#define COMSUB	3	/* $() substitution (0 terminated) */
1993#define EXPRSUB	4	/* $(()) substitution (0 terminated) */
1994#define OQUOTE	5	/* opening " or ' */
1995#define CQUOTE	6	/* closing " or ' */
1996#define OSUBST	7	/* opening ${ subst (followed by { or X) */
1997#define CSUBST	8	/* closing } of above (followed by } or X) */
1998#define OPAT	9	/* open pattern: *(, @(, etc. */
1999#define SPAT	10	/* separate pattern: | */
2000#define CPAT	11	/* close pattern: ) */
2001#define ADELIM	12	/* arbitrary delimiter: ${foo:2:3} ${foo/bar/baz} */
2002#define FUNSUB	14	/* ${ foo;} substitution (NUL terminated) */
2003#define VALSUB	15	/* ${|foo;} substitution (NUL terminated) */
2004#define COMASUB	16	/* `…` substitution (COMSUB but expand aliases) */
2005#define FUNASUB	17	/* function substitution but expand aliases */
2006
2007/*
2008 * IO redirection
2009 */
2010struct ioword {
2011	char *ioname;		/* filename (unused if heredoc) */
2012	char *delim;		/* delimiter for <<, <<- */
2013	char *heredoc;		/* content of heredoc */
2014	unsigned short ioflag;	/* action (below) */
2015	short unit;		/* unit (fd) affected */
2016};
2017
2018/* ioword.flag - type of redirection */
2019#define IOTYPE		0xF	/* type: bits 0:3 */
2020#define IOREAD		0x1	/* < */
2021#define IOWRITE		0x2	/* > */
2022#define IORDWR		0x3	/* <>: todo */
2023#define IOHERE		0x4	/* << (here file) */
2024#define IOCAT		0x5	/* >> */
2025#define IODUP		0x6	/* <&/>& */
2026#define IOEVAL		BIT(4)	/* expand in << */
2027#define IOSKIP		BIT(5)	/* <<-, skip ^\t* */
2028#define IOCLOB		BIT(6)	/* >|, override -o noclobber */
2029#define IORDUP		BIT(7)	/* x<&y (as opposed to x>&y) */
2030#define IODUPSELF	BIT(8)	/* x>&x (as opposed to x>&y) */
2031#define IONAMEXP	BIT(9)	/* name has been expanded */
2032#define IOBASH		BIT(10)	/* &> etc. */
2033#define IOHERESTR	BIT(11)	/* <<< (here string) */
2034#define IONDELIM	BIT(12)	/* null delimiter (<<) */
2035
2036/* execute/exchild flags */
2037#define XEXEC	BIT(0)		/* execute without forking */
2038#define XFORK	BIT(1)		/* fork before executing */
2039#define XBGND	BIT(2)		/* command & */
2040#define XPIPEI	BIT(3)		/* input is pipe */
2041#define XPIPEO	BIT(4)		/* output is pipe */
2042#define XXCOM	BIT(5)		/* `...` command */
2043#define XPCLOSE	BIT(6)		/* exchild: close close_fd in parent */
2044#define XCCLOSE	BIT(7)		/* exchild: close close_fd in child */
2045#define XERROK	BIT(8)		/* non-zero exit ok (for set -e) */
2046#define XCOPROC BIT(9)		/* starting a co-process */
2047#define XTIME	BIT(10)		/* timing TCOM command */
2048#define XPIPEST	BIT(11)		/* want PIPESTATUS */
2049
2050/*
2051 * flags to control expansion of words (assumed by t->evalflags to fit
2052 * in a short)
2053 */
2054#define DOBLANK	BIT(0)		/* perform blank interpretation */
2055#define DOGLOB	BIT(1)		/* expand [?* */
2056#define DOPAT	BIT(2)		/* quote *?[ */
2057#define DOTILDE	BIT(3)		/* normal ~ expansion (first char) */
2058#define DONTRUNCOMMAND BIT(4)	/* do not run $(command) things */
2059#define DOASNTILDE BIT(5)	/* assignment ~ expansion (after =, :) */
2060#define DOBRACE BIT(6)		/* used by expand(): do brace expansion */
2061#define DOMAGIC BIT(7)		/* used by expand(): string contains MAGIC */
2062#define DOTEMP	BIT(8)		/* dito: in word part of ${..[%#=?]..} */
2063#define DOVACHECK BIT(9)	/* var assign check (for typeset, set, etc) */
2064#define DOMARKDIRS BIT(10)	/* force markdirs behaviour */
2065#define DOTCOMEXEC BIT(11)	/* not an eval flag, used by sh -c hack */
2066#define DOSCALAR BIT(12)	/* change field handling to non-list context */
2067#define DOHEREDOC BIT(13)	/* change scalar handling to heredoc body */
2068#define DOHERESTR BIT(14)	/* append a newline char */
2069#define DODBMAGIC BIT(15)	/* add magic to expansions for [[ x = $y ]] */
2070
2071#define X_EXTRA	20	/* this many extra bytes in X string */
2072#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
2073#define X_WASTE 15	/* allowed extra bytes to avoid shrinking, */
2074#else
2075#define X_WASTE 255	/* … must be 2ⁿ-1 */
2076#endif
2077
2078typedef struct XString {
2079	/* beginning of string */
2080	char *beg;
2081	/* length of allocated area, minus safety margin */
2082	size_t len;
2083	/* end of string */
2084	char *end;
2085	/* memory area used */
2086	Area *areap;
2087} XString;
2088
2089/* initialise expandable string */
2090#define XinitN(xs,length,area) do {				\
2091	(xs).len = (length);					\
2092	(xs).areap = (area);					\
2093	(xs).beg = alloc((xs).len + X_EXTRA, (xs).areap);	\
2094	(xs).end = (xs).beg + (xs).len;				\
2095} while (/* CONSTCOND */ 0)
2096#define Xinit(xs,xp,length,area) do {				\
2097	XinitN((xs), (length), (area));				\
2098	(xp) = (xs).beg;					\
2099} while (/* CONSTCOND */ 0)
2100
2101/* stuff char into string */
2102#define Xput(xs,xp,c)	(*xp++ = (c))
2103
2104/* check if there are at least n bytes left */
2105#define XcheckN(xs,xp,n) do {					\
2106	ssize_t more = ((xp) + (n)) - (xs).end;			\
2107	if (more > 0)						\
2108		(xp) = Xcheck_grow(&(xs), (xp), (size_t)more);	\
2109} while (/* CONSTCOND */ 0)
2110
2111/* check for overflow, expand string */
2112#define Xcheck(xs,xp)	XcheckN((xs), (xp), 1)
2113
2114/* free string */
2115#define Xfree(xs,xp)	afree((xs).beg, (xs).areap)
2116
2117/* close, return string */
2118#define Xclose(xs,xp)	aresize((xs).beg, (xp) - (xs).beg, (xs).areap)
2119
2120/* beginning of string */
2121#define Xstring(xs,xp)	((xs).beg)
2122
2123#define Xnleft(xs,xp)		((xs).end - (xp))	/* may be less than 0 */
2124#define Xlength(xs,xp)		((xp) - (xs).beg)
2125#define Xsize(xs,xp)		((xs).end - (xs).beg)
2126#define Xsavepos(xs,xp)		((xp) - (xs).beg)
2127#define Xrestpos(xs,xp,n)	((xs).beg + (n))
2128
2129char *Xcheck_grow(XString *, const char *, size_t);
2130
2131/*
2132 * expandable vector of generic pointers
2133 */
2134
2135typedef struct {
2136	/* beginning of allocated area */
2137	void **beg;
2138	/* currently used number of entries */
2139	size_t len;
2140	/* allocated number of entries */
2141	size_t siz;
2142} XPtrV;
2143
2144#define XPinit(x,n)	do {					\
2145	(x).siz = (n);						\
2146	(x).len = 0;						\
2147	(x).beg = alloc2((x).siz, sizeof(void *), ATEMP);	\
2148} while (/* CONSTCOND */ 0)					\
2149
2150#define XPput(x,p)	do {					\
2151	if ((x).len == (x).siz) {				\
2152		(x).beg = aresize2((x).beg, (x).siz,		\
2153		    2 * sizeof(void *), ATEMP);			\
2154		(x).siz <<= 1;					\
2155	}							\
2156	(x).beg[(x).len++] = (p);				\
2157} while (/* CONSTCOND */ 0)
2158
2159#define XPptrv(x)	((x).beg)
2160#define XPsize(x)	((x).len)
2161#define XPclose(x)	aresize2((x).beg, XPsize(x), sizeof(void *), ATEMP)
2162#define XPfree(x)	afree((x).beg, ATEMP)
2163
2164/* for print_columns */
2165
2166struct columnise_opts {
2167	struct shf *shf;
2168	char linesep;
2169	bool do_last;
2170	bool prefcol;
2171};
2172
2173/*
2174 * Lexer internals
2175 */
2176
2177typedef struct source Source;
2178struct source {
2179	/* input buffer */
2180	XString xs;
2181	/* memory area, also checked in reclaim() */
2182	Area *areap;
2183	/* stacked source */
2184	Source *next;
2185	/* input pointer */
2186	const char *str;
2187	/* start of current buffer */
2188	const char *start;
2189	/* input file name */
2190	const char *file;
2191	/* extra data */
2192	union {
2193		/* string[] */
2194		const char **strv;
2195		/* shell file */
2196		struct shf *shf;
2197		/* alias (SF_HASALIAS) */
2198		struct tbl *tblp;
2199		/* (also for SREREAD) */
2200		char *freeme;
2201	} u;
2202	/* flags */
2203	int flags;
2204	/* input type */
2205	int type;
2206	/* line number */
2207	int line;
2208	/* line the error occurred on (0 if not set) */
2209	int errline;
2210	/* buffer for ungetsc() (SREREAD) and alias (SALIAS) */
2211	char ugbuf[2];
2212};
2213
2214/* Source.type values */
2215#define SEOF		0	/* input EOF */
2216#define SFILE		1	/* file input */
2217#define SSTDIN		2	/* read stdin */
2218#define SSTRING		3	/* string */
2219#define SWSTR		4	/* string without \n */
2220#define SWORDS		5	/* string[] */
2221#define SWORDSEP	6	/* string[] separator */
2222#define SALIAS		7	/* alias expansion */
2223#define SREREAD		8	/* read ahead to be re-scanned */
2224#define SSTRINGCMDLINE	9	/* string from "mksh -c ..." */
2225
2226/* Source.flags values */
2227#define SF_ECHO		BIT(0)	/* echo input to shlout */
2228#define SF_ALIAS	BIT(1)	/* faking space at end of alias */
2229#define SF_ALIASEND	BIT(2)	/* faking space at end of alias */
2230#define SF_TTY		BIT(3)	/* type == SSTDIN & it is a tty */
2231#define SF_HASALIAS	BIT(4)	/* u.tblp valid (SALIAS, SEOF) */
2232#define SF_MAYEXEC	BIT(5)	/* special sh -c optimisation hack */
2233
2234typedef union {
2235	int i;
2236	char *cp;
2237	char **wp;
2238	struct op *o;
2239	struct ioword *iop;
2240} YYSTYPE;
2241
2242/* If something is added here, add it to tokentab[] in syn.c as well */
2243#define LWORD		256
2244#define LOGAND		257	/* && */
2245#define LOGOR		258	/* || */
2246#define BREAK		259	/* ;; */
2247#define IF		260
2248#define THEN		261
2249#define ELSE		262
2250#define ELIF		263
2251#define FI		264
2252#define CASE		265
2253#define ESAC		266
2254#define FOR		267
2255#define SELECT		268
2256#define WHILE		269
2257#define UNTIL		270
2258#define DO		271
2259#define DONE		272
2260#define IN		273
2261#define FUNCTION	274
2262#define TIME		275
2263#define REDIR		276
2264#define MDPAREN		277	/* (( )) */
2265#define BANG		278	/* ! */
2266#define DBRACKET	279	/* [[ .. ]] */
2267#define COPROC		280	/* |& */
2268#define BRKEV		281	/* ;| */
2269#define BRKFT		282	/* ;& */
2270#define YYERRCODE	300
2271
2272/* flags to yylex */
2273#define CONTIN		BIT(0)	/* skip new lines to complete command */
2274#define ONEWORD		BIT(1)	/* single word for substitute() */
2275#define ALIAS		BIT(2)	/* recognise alias */
2276#define KEYWORD		BIT(3)	/* recognise keywords */
2277#define LETEXPR		BIT(4)	/* get expression inside (( )) */
2278#define CMDASN		BIT(5)	/* parse x[1 & 2] as one word, for typeset */
2279#define HEREDOC 	BIT(6)	/* parsing a here document body */
2280#define ESACONLY	BIT(7)	/* only accept esac keyword */
2281#define CMDWORD		BIT(8)	/* parsing simple command (alias related) */
2282#define HEREDELIM	BIT(9)	/* parsing <<,<<- delimiter */
2283#define LQCHAR		BIT(10)	/* source string contains QCHAR */
2284
2285#define HERES		10	/* max number of << in line */
2286
2287#ifdef MKSH_EBCDIC
2288#define CTRL_AT	(0x00U)
2289#define CTRL_A	(0x01U)
2290#define CTRL_B	(0x02U)
2291#define CTRL_C	(0x03U)
2292#define CTRL_D	(0x37U)
2293#define CTRL_E	(0x2DU)
2294#define CTRL_F	(0x2EU)
2295#define CTRL_G	(0x2FU)
2296#define CTRL_H	(0x16U)
2297#define CTRL_I	(0x05U)
2298#define CTRL_J	(0x15U)
2299#define CTRL_K	(0x0BU)
2300#define CTRL_L	(0x0CU)
2301#define CTRL_M	(0x0DU)
2302#define CTRL_N	(0x0EU)
2303#define CTRL_O	(0x0FU)
2304#define CTRL_P	(0x10U)
2305#define CTRL_Q	(0x11U)
2306#define CTRL_R	(0x12U)
2307#define CTRL_S	(0x13U)
2308#define CTRL_T	(0x3CU)
2309#define CTRL_U	(0x3DU)
2310#define CTRL_V	(0x32U)
2311#define CTRL_W	(0x26U)
2312#define CTRL_X	(0x18U)
2313#define CTRL_Y	(0x19U)
2314#define CTRL_Z	(0x3FU)
2315#define CTRL_BO	(0x27U)
2316#define CTRL_BK	(0x1CU)
2317#define CTRL_BC	(0x1DU)
2318#define CTRL_CA	(0x1EU)
2319#define CTRL_US	(0x1FU)
2320#define CTRL_QM	(0x07U)
2321#else
2322#define CTRL_AT	(0x00U)
2323#define CTRL_A	(0x01U)
2324#define CTRL_B	(0x02U)
2325#define CTRL_C	(0x03U)
2326#define CTRL_D	(0x04U)
2327#define CTRL_E	(0x05U)
2328#define CTRL_F	(0x06U)
2329#define CTRL_G	(0x07U)
2330#define CTRL_H	(0x08U)
2331#define CTRL_I	(0x09U)
2332#define CTRL_J	(0x0AU)
2333#define CTRL_K	(0x0BU)
2334#define CTRL_L	(0x0CU)
2335#define CTRL_M	(0x0DU)
2336#define CTRL_N	(0x0EU)
2337#define CTRL_O	(0x0FU)
2338#define CTRL_P	(0x10U)
2339#define CTRL_Q	(0x11U)
2340#define CTRL_R	(0x12U)
2341#define CTRL_S	(0x13U)
2342#define CTRL_T	(0x14U)
2343#define CTRL_U	(0x15U)
2344#define CTRL_V	(0x16U)
2345#define CTRL_W	(0x17U)
2346#define CTRL_X	(0x18U)
2347#define CTRL_Y	(0x19U)
2348#define CTRL_Z	(0x1AU)
2349#define CTRL_BO	(0x1BU)
2350#define CTRL_BK	(0x1CU)
2351#define CTRL_BC	(0x1DU)
2352#define CTRL_CA	(0x1EU)
2353#define CTRL_US	(0x1FU)
2354#define CTRL_QM	(0x7FU)
2355#endif
2356
2357#define IDENT	64
2358
2359EXTERN Source *source;		/* yyparse/yylex source */
2360EXTERN YYSTYPE yylval;		/* result from yylex */
2361EXTERN struct ioword *heres[HERES], **herep;
2362EXTERN char ident[IDENT + 1];
2363
2364EXTERN char **history;		/* saved commands */
2365EXTERN char **histptr;		/* last history item */
2366EXTERN mksh_ari_t histsize;	/* history size */
2367
2368/* flags to histsave */
2369#define HIST_FLUSH	0
2370#define HIST_QUEUE	1
2371#define HIST_APPEND	2
2372#define HIST_STORE	3
2373#define HIST_NOTE	4
2374
2375/* user and system time of last j_waitjed job */
2376EXTERN struct timeval j_usrtime, j_systime;
2377
2378#define notok2mul(max,val,c)	(((val) != 0) && ((c) != 0) && \
2379				    (((max) / (c)) < (val)))
2380#define notok2add(max,val,c)	((val) > ((max) - (c)))
2381#define notoktomul(val,cnst)	notok2mul(SIZE_MAX, (val), (cnst))
2382#define notoktoadd(val,cnst)	notok2add(SIZE_MAX, (val), (cnst))
2383#define checkoktoadd(val,cnst) do {					\
2384	if (notoktoadd((val), (cnst)))					\
2385		internal_errorf(Tintovfl, (size_t)(val),		\
2386		    '+', (size_t)(cnst));				\
2387} while (/* CONSTCOND */ 0)
2388
2389
2390/* lalloc.c */
2391void ainit(Area *);
2392void afreeall(Area *);
2393/* these cannot fail and can take NULL (not for ap) */
2394#define alloc(n,ap)		aresize(NULL, (n), (ap))
2395#define alloc2(m,n,ap)		aresize2(NULL, (m), (n), (ap))
2396void *aresize(void *, size_t, Area *);
2397void *aresize2(void *, size_t, size_t, Area *);
2398void afree(void *, Area *);	/* can take NULL */
2399#define aresizeif(z,p,n,ap)	(((p) == NULL) || ((z) < (n)) || \
2400				    (((z) & ~X_WASTE) > ((n) & ~X_WASTE)) ? \
2401				    aresize((p), (n), (ap)) : (p))
2402/* edit.c */
2403#ifndef MKSH_NO_CMDLINE_EDITING
2404int x_bind(const char * SMALLP(bool));
2405int x_bind_check(void);
2406int x_bind_list(void);
2407int x_bind_showall(void);
2408void x_init(void);
2409#ifdef DEBUG_LEAKS
2410void x_done(void);
2411#endif
2412int x_read(char *);
2413#endif
2414void x_mkraw(int, mksh_ttyst *, bool);
2415void x_initterm(const char *);
2416/* eval.c */
2417char *substitute(const char *, int);
2418char **eval(const char **, int);
2419char *evalstr(const char *cp, int);
2420char *evalonestr(const char *cp, int);
2421char *debunk(char *, const char *, size_t);
2422void expand(const char *, XPtrV *, int);
2423int glob_str(char *, XPtrV *, bool);
2424char *do_tilde(char *);
2425/* exec.c */
2426int execute(struct op * volatile, volatile int, volatile int * volatile);
2427int c_builtin(const char **);
2428struct tbl *get_builtin(const char *);
2429struct tbl *findfunc(const char *, uint32_t, bool);
2430int define(const char *, struct op *);
2431const char *builtin(const char *, int (*)(const char **));
2432struct tbl *findcom(const char *, int);
2433void flushcom(bool);
2434int search_access(const char *, int);
2435const char *search_path(const char *, const char *, int, int *);
2436void pr_menu(const char * const *);
2437void pr_list(struct columnise_opts *, char * const *);
2438int herein(struct ioword *, char **);
2439/* expr.c */
2440int evaluate(const char *, mksh_ari_t *, int, bool);
2441int v_evaluate(struct tbl *, const char *, volatile int, bool);
2442/* UTF-8 stuff */
2443size_t utf_mbtowc(unsigned int *, const char *);
2444size_t utf_wctomb(char *, unsigned int);
2445int utf_widthadj(const char *, const char **);
2446size_t utf_mbswidth(const char *) MKSH_A_PURE;
2447const char *utf_skipcols(const char *, int, int *);
2448size_t utf_ptradj(const char *) MKSH_A_PURE;
2449#ifdef MIRBSD_BOOTFLOPPY
2450#define utf_wcwidth(i) wcwidth((wchar_t)(i))
2451#else
2452int utf_wcwidth(unsigned int) MKSH_A_PURE;
2453#endif
2454int ksh_access(const char *, int);
2455struct tbl *tempvar(const char *);
2456/* funcs.c */
2457int c_hash(const char **);
2458int c_pwd(const char **);
2459int c_print(const char **);
2460#ifdef MKSH_PRINTF_BUILTIN
2461int c_printf(const char **);
2462#endif
2463int c_whence(const char **);
2464int c_command(const char **);
2465int c_typeset(const char **);
2466bool valid_alias_name(const char *);
2467int c_alias(const char **);
2468int c_unalias(const char **);
2469int c_let(const char **);
2470int c_jobs(const char **);
2471#ifndef MKSH_UNEMPLOYED
2472int c_fgbg(const char **);
2473#endif
2474int c_kill(const char **);
2475void getopts_reset(int);
2476int c_getopts(const char **);
2477#ifndef MKSH_NO_CMDLINE_EDITING
2478int c_bind(const char **);
2479#endif
2480int c_shift(const char **);
2481int c_umask(const char **);
2482int c_dot(const char **);
2483int c_wait(const char **);
2484int c_read(const char **);
2485int c_eval(const char **);
2486int c_trap(const char **);
2487int c_brkcont(const char **);
2488int c_exitreturn(const char **);
2489int c_set(const char **);
2490int c_unset(const char **);
2491int c_ulimit(const char **);
2492int c_times(const char **);
2493int timex(struct op *, int, volatile int *);
2494void timex_hook(struct op *, char ** volatile *);
2495int c_exec(const char **);
2496int c_test(const char **);
2497#if HAVE_MKNOD
2498int c_mknod(const char **);
2499#endif
2500int c_realpath(const char **);
2501int c_rename(const char **);
2502int c_cat(const char **);
2503int c_sleep(const char **);
2504/* histrap.c */
2505void init_histvec(void);
2506void hist_init(Source *);
2507#if HAVE_PERSISTENT_HISTORY
2508void hist_finish(void);
2509#endif
2510void histsave(int *, const char *, int, bool);
2511#if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
2512bool histsync(void);
2513#endif
2514int c_fc(const char **);
2515void sethistsize(mksh_ari_t);
2516#if HAVE_PERSISTENT_HISTORY
2517void sethistfile(const char *);
2518#endif
2519#if !defined(MKSH_NO_CMDLINE_EDITING) && !MKSH_S_NOVI
2520char **histpos(void) MKSH_A_PURE;
2521int histnum(int);
2522#endif
2523int findhist(int, const char *, bool, bool) MKSH_A_PURE;
2524char **hist_get_newest(bool);
2525void inittraps(void);
2526void alarm_init(void);
2527Trap *gettrap(const char *, bool, bool);
2528void trapsig(int);
2529void intrcheck(void);
2530int fatal_trap_check(void);
2531int trap_pending(void);
2532void runtraps(int intr);
2533void runtrap(Trap *, bool);
2534void cleartraps(void);
2535void restoresigs(void);
2536void settrap(Trap *, const char *);
2537bool block_pipe(void);
2538void restore_pipe(void);
2539int setsig(Trap *, sig_t, int);
2540void setexecsig(Trap *, int);
2541#if HAVE_FLOCK || HAVE_LOCK_FCNTL
2542void mksh_lockfd(int);
2543void mksh_unlkfd(int);
2544#endif
2545/* jobs.c */
2546void j_init(void);
2547void j_exit(void);
2548#ifndef MKSH_UNEMPLOYED
2549void j_change(void);
2550#endif
2551int exchild(struct op *, int, volatile int *, int);
2552void startlast(void);
2553int waitlast(void);
2554int waitfor(const char *, int *);
2555int j_kill(const char *, int);
2556#ifndef MKSH_UNEMPLOYED
2557int j_resume(const char *, int);
2558#endif
2559#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
2560void j_suspend(void);
2561#endif
2562int j_jobs(const char *, int, int);
2563void j_notify(void);
2564pid_t j_async(void);
2565int j_stopped_running(void);
2566/* lex.c */
2567int yylex(int);
2568void yyskiputf8bom(void);
2569void yyerror(const char *, ...)
2570    MKSH_A_NORETURN
2571    MKSH_A_FORMAT(__printf__, 1, 2);
2572Source *pushs(int, Area *);
2573void set_prompt(int, Source *);
2574int pprompt(const char *, int);
2575/* main.c */
2576int include(const char *, int, const char **, bool);
2577int command(const char *, int);
2578int shell(Source * volatile, volatile int);
2579/* argument MUST NOT be 0 */
2580void unwind(int) MKSH_A_NORETURN;
2581void newenv(int);
2582void quitenv(struct shf *);
2583void cleanup_parents_env(void);
2584void cleanup_proc_env(void);
2585void errorf(const char *, ...)
2586    MKSH_A_NORETURN
2587    MKSH_A_FORMAT(__printf__, 1, 2);
2588void errorfx(int, const char *, ...)
2589    MKSH_A_NORETURN
2590    MKSH_A_FORMAT(__printf__, 2, 3);
2591void warningf(bool, const char *, ...)
2592    MKSH_A_FORMAT(__printf__, 2, 3);
2593void bi_errorf(const char *, ...)
2594    MKSH_A_FORMAT(__printf__, 1, 2);
2595void maybe_errorf(int *, int, const char *, ...)
2596    MKSH_A_FORMAT(__printf__, 3, 4);
2597#define errorfz()	errorf(NULL)
2598#define errorfxz(rc)	errorfx((rc), NULL)
2599#define bi_errorfz()	bi_errorf(NULL)
2600void internal_errorf(const char *, ...)
2601    MKSH_A_NORETURN
2602    MKSH_A_FORMAT(__printf__, 1, 2);
2603void internal_warningf(const char *, ...)
2604    MKSH_A_FORMAT(__printf__, 1, 2);
2605void error_prefix(bool);
2606void shellf(const char *, ...)
2607    MKSH_A_FORMAT(__printf__, 1, 2);
2608void shprintf(const char *, ...)
2609    MKSH_A_FORMAT(__printf__, 1, 2);
2610int can_seek(int);
2611void initio(void);
2612void recheck_ctype(void);
2613int ksh_dup2(int, int, bool);
2614short savefd(int);
2615void restfd(int, int);
2616void openpipe(int *);
2617void closepipe(int *);
2618int check_fd(const char *, int, const char **);
2619void coproc_init(void);
2620void coproc_read_close(int);
2621void coproc_readw_close(int);
2622void coproc_write_close(int);
2623int coproc_getfd(int, const char **);
2624void coproc_cleanup(int);
2625struct temp *maketemp(Area *, Temp_type, struct temp **);
2626void ktinit(Area *, struct table *, uint8_t);
2627struct tbl *ktscan(struct table *, const char *, uint32_t, struct tbl ***);
2628/* table, name (key) to search for, hash(n) */
2629#define ktsearch(tp,s,h) ktscan((tp), (s), (h), NULL)
2630struct tbl *ktenter(struct table *, const char *, uint32_t);
2631#define ktdelete(p)	do { p->flag = 0; } while (/* CONSTCOND */ 0)
2632void ktwalk(struct tstate *, struct table *);
2633struct tbl *ktnext(struct tstate *);
2634struct tbl **ktsort(struct table *);
2635#ifdef DF
2636void DF(const char *, ...)
2637    MKSH_A_FORMAT(__printf__, 1, 2);
2638#endif
2639/* misc.c */
2640size_t option(const char *) MKSH_A_PURE;
2641char *getoptions(void);
2642void change_flag(enum sh_flag, int, bool);
2643void change_xtrace(unsigned char, bool);
2644int parse_args(const char **, int, bool *);
2645int getn(const char *, int *);
2646int gmatchx(const char *, const char *, bool);
2647bool has_globbing(const char *) MKSH_A_PURE;
2648int ascstrcmp(const void *, const void *) MKSH_A_PURE;
2649int ascpstrcmp(const void *, const void *) MKSH_A_PURE;
2650void ksh_getopt_reset(Getopt *, int);
2651int ksh_getopt(const char **, Getopt *, const char *);
2652void print_value_quoted(struct shf *, const char *);
2653char *quote_value(const char *);
2654void print_columns(struct columnise_opts *, unsigned int,
2655    void (*)(char *, size_t, unsigned int, const void *),
2656    const void *, size_t, size_t);
2657void strip_nuls(char *, size_t)
2658    MKSH_A_BOUNDED(__string__, 1, 2);
2659ssize_t blocking_read(int, char *, size_t)
2660    MKSH_A_BOUNDED(__buffer__, 2, 3);
2661int reset_nonblock(int);
2662char *ksh_get_wd(void);
2663char *do_realpath(const char *);
2664void simplify_path(char *);
2665void set_current_wd(const char *);
2666int c_cd(const char **);
2667#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
2668char *strdup_i(const char *, Area *);
2669char *strndup_i(const char *, size_t, Area *);
2670#endif
2671int unbksl(bool, int (*)(void), void (*)(int));
2672#ifdef __OS2__
2673/* os2.c */
2674void os2_init(int *, const char ***);
2675void setextlibpath(const char *, const char *);
2676int access_ex(int (*)(const char *, int), const char *, int);
2677int stat_ex(int (*)(const char *, struct stat *), const char *, struct stat *);
2678const char *real_exec_name(const char *);
2679#endif
2680/* shf.c */
2681struct shf *shf_open(const char *, int, int, int);
2682struct shf *shf_fdopen(int, int, struct shf *);
2683struct shf *shf_reopen(int, int, struct shf *);
2684struct shf *shf_sopen(char *, ssize_t, int, struct shf *);
2685int shf_close(struct shf *);
2686int shf_fdclose(struct shf *);
2687char *shf_sclose(struct shf *);
2688int shf_flush(struct shf *);
2689ssize_t shf_read(char *, ssize_t, struct shf *);
2690char *shf_getse(char *, ssize_t, struct shf *);
2691int shf_getchar(struct shf *s);
2692int shf_ungetc(int, struct shf *);
2693#ifdef MKSH_SHF_NO_INLINE
2694int shf_getc(struct shf *);
2695int shf_putc(int, struct shf *);
2696#else
2697#define shf_getc shf_getc_i
2698#define shf_putc shf_putc_i
2699#endif
2700int shf_putchar(int, struct shf *);
2701ssize_t shf_puts(const char *, struct shf *);
2702ssize_t shf_write(const char *, ssize_t, struct shf *);
2703ssize_t shf_fprintf(struct shf *, const char *, ...)
2704    MKSH_A_FORMAT(__printf__, 2, 3);
2705ssize_t shf_snprintf(char *, ssize_t, const char *, ...)
2706    MKSH_A_FORMAT(__printf__, 3, 4)
2707    MKSH_A_BOUNDED(__string__, 1, 2);
2708char *shf_smprintf(const char *, ...)
2709    MKSH_A_FORMAT(__printf__, 1, 2);
2710ssize_t shf_vfprintf(struct shf *, const char *, va_list)
2711    MKSH_A_FORMAT(__printf__, 2, 0);
2712void set_ifs(const char *);
2713/* syn.c */
2714void initkeywords(void);
2715struct op *compile(Source *, bool, bool);
2716bool parse_usec(const char *, struct timeval *);
2717char *yyrecursive(int);
2718void yyrecursive_pop(bool);
2719/* tree.c */
2720void fptreef(struct shf *, int, const char *, ...);
2721char *snptreef(char *, ssize_t, const char *, ...);
2722struct op *tcopy(struct op *, Area *);
2723char *wdcopy(const char *, Area *);
2724const char *wdscan(const char *, int);
2725#define WDS_TPUTS	BIT(0)		/* tputS (dumpwdvar) mode */
2726char *wdstrip(const char *, int);
2727void tfree(struct op *, Area *);
2728void dumpchar(struct shf *, unsigned char);
2729void dumptree(struct shf *, struct op *);
2730void dumpwdvar(struct shf *, const char *);
2731void dumpioact(struct shf *shf, struct op *t);
2732void vistree(char *, size_t, struct op *)
2733    MKSH_A_BOUNDED(__string__, 1, 2);
2734void fpFUNCTf(struct shf *, int, bool, const char *, struct op *);
2735/* var.c */
2736void newblock(void);
2737void popblock(void);
2738void initvar(void);
2739struct block *varsearch(struct block *, struct tbl **, const char *, uint32_t);
2740struct tbl *global(const char *);
2741struct tbl *isglobal(const char *, bool);
2742struct tbl *local(const char *, bool);
2743char *str_val(struct tbl *);
2744int setstr(struct tbl *, const char *, int);
2745struct tbl *setint_v(struct tbl *, struct tbl *, bool);
2746void setint(struct tbl *, mksh_ari_t);
2747void setint_n(struct tbl *, mksh_ari_t, int);
2748struct tbl *typeset(const char *, uint32_t, uint32_t, int, int);
2749void unset(struct tbl *, int);
2750const char *skip_varname(const char *, bool) MKSH_A_PURE;
2751const char *skip_wdvarname(const char *, bool) MKSH_A_PURE;
2752int is_wdvarname(const char *, bool) MKSH_A_PURE;
2753int is_wdvarassign(const char *) MKSH_A_PURE;
2754struct tbl *arraysearch(struct tbl *, uint32_t);
2755char **makenv(void);
2756void change_winsz(void);
2757size_t array_ref_len(const char *) MKSH_A_PURE;
2758char *arrayname(const char *);
2759mksh_uari_t set_array(const char *, bool, const char **);
2760uint32_t hash(const void *) MKSH_A_PURE;
2761uint32_t chvt_rndsetup(const void *, size_t) MKSH_A_PURE;
2762mksh_ari_t rndget(void);
2763void rndset(unsigned long);
2764void rndpush(const void *);
2765void record_match(const char *);
2766
2767enum Test_op {
2768	/* non-operator */
2769	TO_NONOP = 0,
2770	/* unary operators */
2771	TO_STNZE, TO_STZER, TO_ISSET, TO_OPTION,
2772	TO_FILAXST,
2773	TO_FILEXST,
2774	TO_FILREG, TO_FILBDEV, TO_FILCDEV, TO_FILSYM, TO_FILFIFO, TO_FILSOCK,
2775	TO_FILCDF, TO_FILID, TO_FILGID, TO_FILSETG, TO_FILSTCK, TO_FILUID,
2776	TO_FILRD, TO_FILGZ, TO_FILTT, TO_FILSETU, TO_FILWR, TO_FILEX,
2777	/* binary operators */
2778	TO_STEQL, TO_STNEQ, TO_STLT, TO_STGT, TO_INTEQ, TO_INTNE, TO_INTGT,
2779	TO_INTGE, TO_INTLT, TO_INTLE, TO_FILEQ, TO_FILNT, TO_FILOT,
2780	/* not an operator */
2781	TO_NONNULL	/* !TO_NONOP */
2782};
2783typedef enum Test_op Test_op;
2784
2785/* Used by Test_env.isa() (order important - used to index *_tokens[] arrays) */
2786enum Test_meta {
2787	TM_OR,		/* -o or || */
2788	TM_AND,		/* -a or && */
2789	TM_NOT,		/* ! */
2790	TM_OPAREN,	/* ( */
2791	TM_CPAREN,	/* ) */
2792	TM_UNOP,	/* unary operator */
2793	TM_BINOP,	/* binary operator */
2794	TM_END		/* end of input */
2795};
2796typedef enum Test_meta Test_meta;
2797
2798struct t_op {
2799	const char op_text[4];
2800	Test_op op_num;
2801};
2802
2803/* for string reuse */
2804extern const struct t_op u_ops[];
2805extern const struct t_op b_ops[];
2806/* ensure order with funcs.c */
2807#define Tda (u_ops[0].op_text)
2808#define Tdn (u_ops[12].op_text)
2809#define Tdo (u_ops[14].op_text)
2810#define Tdr (u_ops[16].op_text)
2811#define Tdu (u_ops[20].op_text)	/* "-u" */
2812#define Tdx (u_ops[23].op_text)
2813
2814#define Tu (Tdu + 1)	/* "u" */
2815
2816#define TEF_ERROR	BIT(0)		/* set if we've hit an error */
2817#define TEF_DBRACKET	BIT(1)		/* set if [[ .. ]] test */
2818
2819typedef struct test_env {
2820	union {
2821		const char **wp;	/* used by ptest_* */
2822		XPtrV *av;		/* used by dbtestp_* */
2823	} pos;
2824	const char **wp_end;		/* used by ptest_* */
2825	Test_op (*isa)(struct test_env *, Test_meta);
2826	const char *(*getopnd) (struct test_env *, Test_op, bool);
2827	int (*eval)(struct test_env *, Test_op, const char *, const char *, bool);
2828	void (*error)(struct test_env *, int, const char *);
2829	int flags;			/* TEF_* */
2830} Test_env;
2831
2832extern const char * const dbtest_tokens[];
2833
2834Test_op	test_isop(Test_meta, const char *) MKSH_A_PURE;
2835int test_eval(Test_env *, Test_op, const char *, const char *, bool);
2836int test_parse(Test_env *);
2837
2838/* tty_fd is not opened O_BINARY, it's thus never read/written */
2839EXTERN int tty_fd E_INIT(-1);	/* dup'd tty file descriptor */
2840EXTERN bool tty_devtty;		/* true if tty_fd is from /dev/tty */
2841EXTERN mksh_ttyst tty_state;	/* saved tty state */
2842EXTERN bool tty_hasstate;	/* true if tty_state is valid */
2843
2844extern int tty_init_fd(void);	/* initialise tty_fd, tty_devtty */
2845
2846#ifdef __OS2__
2847#define binopen2(path,flags)		__extension__({			\
2848	int binopen2_fd = open((path), (flags) | O_BINARY);		\
2849	if (binopen2_fd >= 0)						\
2850		setmode(binopen2_fd, O_BINARY);				\
2851	(binopen2_fd);							\
2852})
2853#define binopen3(path,flags,mode)	__extension__({			\
2854	int binopen3_fd = open((path), (flags) | O_BINARY, (mode));	\
2855	if (binopen3_fd >= 0)						\
2856		setmode(binopen3_fd, O_BINARY);				\
2857	(binopen3_fd);							\
2858})
2859#else
2860#define binopen2(path,flags)		open((path), (flags) | O_BINARY)
2861#define binopen3(path,flags,mode)	open((path), (flags) | O_BINARY, (mode))
2862#endif
2863
2864#ifdef MKSH_DOSPATH
2865#define mksh_drvltr(s)			__extension__({			\
2866	const char *mksh_drvltr_s = (s);				\
2867	(ctype(mksh_drvltr_s[0], C_ALPHA) && mksh_drvltr_s[1] == ':');	\
2868})
2869#define mksh_abspath(s)			__extension__({			\
2870	const char *mksh_abspath_s = (s);				\
2871	(mksh_cdirsep(mksh_abspath_s[0]) ||				\
2872	    (mksh_drvltr(mksh_abspath_s) &&				\
2873	    mksh_cdirsep(mksh_abspath_s[2])));				\
2874})
2875#define mksh_cdirsep(c)			__extension__({			\
2876	char mksh_cdirsep_c = (c);					\
2877	(mksh_cdirsep_c == '/' || mksh_cdirsep_c == '\\');		\
2878})
2879#define mksh_sdirsep(s)			strpbrk((s), "/\\")
2880#define mksh_vdirsep(s)			__extension__({			\
2881	const char *mksh_vdirsep_s = (s);				\
2882	(((mksh_drvltr(mksh_vdirsep_s) &&				\
2883	    !mksh_cdirsep(mksh_vdirsep_s[2])) ? (!0) :			\
2884	    (mksh_sdirsep(mksh_vdirsep_s) != NULL)) &&			\
2885	    (strcmp(mksh_vdirsep_s, T_builtin) != 0));			\
2886})
2887int getdrvwd(char **, unsigned int);
2888#else
2889#define mksh_abspath(s)			(ord((s)[0]) == ORD('/'))
2890#define mksh_cdirsep(c)			(ord(c) == ORD('/'))
2891#define mksh_sdirsep(s)			strchr((s), '/')
2892#define mksh_vdirsep(s)			vstrchr((s), '/')
2893#endif
2894
2895/* be sure not to interfere with anyone else's idea about EXTERN */
2896#ifdef EXTERN_DEFINED
2897# undef EXTERN_DEFINED
2898# undef EXTERN
2899#endif
2900#undef E_INIT
2901
2902#endif /* !MKSH_INCLUDES_ONLY */
2903