forked from MirBSD/mksh
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsh.h
3147 lines (2919 loc) · 98.6 KB
/
sh.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* $OpenBSD: sh.h,v 1.35 2015/09/10 22:48:58 nicm Exp $ */
/* $OpenBSD: shf.h,v 1.6 2005/12/11 18:53:51 deraadt Exp $ */
/* $OpenBSD: table.h,v 1.8 2012/02/19 07:52:30 otto Exp $ */
/* $OpenBSD: tree.h,v 1.10 2005/03/28 21:28:22 deraadt Exp $ */
/* $OpenBSD: expand.h,v 1.7 2015/09/01 13:12:31 tedu Exp $ */
/* $OpenBSD: lex.h,v 1.13 2013/03/03 19:11:34 guenther Exp $ */
/* $OpenBSD: proto.h,v 1.35 2013/09/04 15:49:19 millert Exp $ */
/* $OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $ */
/* $OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $ */
/*-
* Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
* 2019, 2020, 2021, 2022, 2023
* mirabilos <[email protected]>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un‐
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person’s immediate fault when using the work as intended.
*/
#define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.1032 2024/07/26 18:39:07 tg Exp $"
#ifdef MKSH_USE_AUTOCONF_H
/* things that “should” have been on the command line */
#include "autoconf.h"
#undef MKSH_USE_AUTOCONF_H
#endif
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include <sys/types.h>
#if HAVE_BOTH_TIME_H && HAVE_SELECT_TIME_H
#include <sys/time.h>
#include <time.h>
#elif HAVE_SYS_TIME_H && HAVE_SELECT_TIME_H
#include <sys/time.h>
#elif HAVE_TIME_H
#include <time.h>
#endif
#if HAVE_SYS_BSDTYPES_H
#include <sys/bsdtypes.h>
#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#if HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
#include <sys/ioctl.h>
#if HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#if HAVE_SYS_MKDEV_H
#include <sys/mkdev.h>
#endif
#if HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#if HAVE_SYS_PTEM_H
/* prerequisite */
#include <sys/stream.h>
/* struct winsize */
#include <sys/ptem.h>
#endif
#if defined(HAVE_GETRANDOM) && (HAVE_GETRANDOM)
#include <sys/random.h>
#endif
#if HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#include <sys/stat.h>
#if !HAVE_GETRUSAGE
#include <sys/times.h>
#endif
#include <sys/wait.h>
#ifdef DEBUG
#include <assert.h>
#endif
#if HAVE_SELECT && HAVE_BSTRING_H
#include <bstring.h>
#endif
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#if HAVE_GRP_H
#include <grp.h>
#endif
#if HAVE_IO_H
#include <io.h>
#endif
#if HAVE_LIBGEN_H
#include <libgen.h>
#endif
#if HAVE_LIBUTIL_H
#include <libutil.h>
#endif
#include <limits.h>
#if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC) || HAVE_POSIX_UTF8_LOCALE
#include <locale.h>
#if HAVE_POSIX_UTF8_LOCALE
#include <langinfo.h>
#endif
#endif
#if HAVE_PATHS_H
#include <paths.h>
#endif
#ifdef MKSH_POLL_FOR_PAUSE
#include <poll.h>
#endif
#ifndef MKSH_NOPWNAM
#include <pwd.h>
#endif
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#if HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_STRINGS_H
#include <strings.h>
#endif
#if HAVE_TERMIOS_H
#include <termios.h>
#else
/* shudder… */
#include <termio.h>
#endif
#ifdef _ISC_UNIX
/* XXX imake style */
#include <sys/sioctl.h>
#endif
#if HAVE_ULIMIT_H
#include <ulimit.h>
#endif
#include <unistd.h>
#ifdef MIRBSD_BOOTFLOPPY
#include <wchar.h>
#endif
#undef MBSDINT_H_SKIP_CTAS
#ifndef MKSH_DO_MBI_CTAS
#define MBSDINT_H_SKIP_CTAS
#endif
/* formatting routines assume this */
#define MBSDINT_H_WANT_PTR_IN_SIZET 1
#define MBSDINT_H_WANT_SIZET_IN_LONG 1
/* POSIX guarantees a 32-bit int */
#define MBSDINT_H_WANT_INT32 1
/* the code cannot cope without yet */
#define MBSDINT_H_WANT_SAFEC 1
#include "mbsdcc.h"
#include "mbsdint.h"
/* monkey-patch nil pointer constant */
#undef NULL
#define NULL mbnil
/* conflict with GCC attributes; fixed in later dietlibcs */
#ifdef __dietlibc__
#undef __noinline__
#endif
#undef __attribute__
#if HAVE_ATTRIBUTE_BOUNDED
#define MKSH_A_BOUNDED(x,y,z) __attribute__((__bounded__(x, y, z)))
#else
#define MKSH_A_BOUNDED(x,y,z) /* nothing */
#endif
#if HAVE_ATTRIBUTE_FORMAT
#define MKSH_A_FORMAT(x,y,z) __attribute__((__format__(x, y, z)))
#else
#define MKSH_A_FORMAT(x,y,z) /* nothing */
#endif
#if HAVE_ATTRIBUTE_NORETURN
#define MKSH_A_NORETURN __attribute__((__noreturn__))
#else
#define MKSH_A_NORETURN /* nothing */
#endif
#if HAVE_ATTRIBUTE_UNUSED
#define MKSH_A_UNUSED __attribute__((__unused__))
#else
#define MKSH_A_UNUSED /* nothing */
#endif
#if HAVE_ATTRIBUTE_USED
#define MKSH_A_USED __attribute__((__used__))
#else
#define MKSH_A_USED /* nothing */
#endif
#if defined(MirBSD) && (MirBSD >= 0x09A1) && \
defined(__ELF__) && defined(__GNUC__) && \
!defined(__llvm__) && !defined(__NWCC__)
/*
* We got usable __IDSTRING __COPYRIGHT __RCSID __SCCSID macros
* which work for all cases; no need to redefine them using the
* "portable" macros from below when we might have the "better"
* gcc+ELF specific macros or other system dependent ones.
*/
#else
#undef __IDSTRING
#undef __IDSTRING_CONCAT
#undef __IDSTRING_EXPAND
#undef __COPYRIGHT
#undef __RCSID
#undef __SCCSID
#define __IDSTRING_CONCAT(l,p) __LINTED__ ## l ## _ ## p
#define __IDSTRING_EXPAND(l,p) __IDSTRING_CONCAT(l,p)
#ifdef MKSH_DONT_EMIT_IDSTRING
#define __IDSTRING(prefix,string) /* nothing */
#elif defined(__ELF__) && defined(__GNUC__) && \
!(defined(__GNUC__) && defined(__mips16) && (__GNUC__ >= 8)) && \
!defined(__llvm__) && !defined(__NWCC__) && !defined(NO_ASM)
#define __IDSTRING(prefix,string) \
__asm__(".section .comment" \
"\n .ascii \"@(\"\"#)" #prefix ": \"" \
"\n .asciz \"" string "\"" \
"\n .previous")
#else
#define __IDSTRING(prefix,string) \
static const char __IDSTRING_EXPAND(__LINE__,prefix) [] \
MKSH_A_USED = "@(""#)" #prefix ": " string
#endif
#define __COPYRIGHT(x) __IDSTRING(copyright,x)
#define __RCSID(x) __IDSTRING(rcsid,x)
#define __SCCSID(x) __IDSTRING(sccsid,x)
#endif
#define MKSH_VERSION "R59 2024/07/26"
/* shell types */
typedef unsigned char kby; /* byte */
typedef unsigned int kui; /* wchar; kby or EOF; ⊇k32; etc. */
/* MBSDINT_H_WANT_INT32 guaranteed; u_int rank also guaranteed */
typedef unsigned int k32; /* 32-bit arithmetic (hashes etc.) */
/* for use with/without 32-bit masking */
typedef unsigned long kul; /* long, arithmetic */
typedef signed long ksl; /* signed long, arithmetic */
#define KUL_FM ULONG_MAX
#define KUL_HM LONG_MAX
/* if mbiHUGE is wider than long, then that, else long */
#if mbiHUGE_UBITS > mbiMASK__BITS(ULONG_MAX)
#define MKSH_HAVE_HUGE
typedef mbiHUGE_U kuH;
typedef mbiHUGE_S ksH;
#define KUH_FM mbiHUGE_U_MAX
#define KUH_HM mbiHUGE_S_MAX
#else
#undef MKSH_HAVE_HUGE
typedef kul kuH;
typedef ksl ksH;
#define KUH_FM ULONG_MAX
#define KUH_HM LONG_MAX
#endif
#define KBY(c) ((kby)(KUI(c) & 0xFFU)) /* byte, truncated if necessary */
#define KBI(c) ((kui)(KUI(c) & 0xFFU)) /* byte as u_int, truncated */
#define KUI(u) ((kui)(u)) /* int as u_int, not truncated */
#define K32_HM 0x7FFFFFFFUL
#define K32_FM 0xFFFFFFFFUL
/*XXX TODO:
* arithmetic type need not be long, it can be unsigned int if we can
* guarantee that it’s exactly⚠ 32 bit wide; in the !lksh case, never
* shall a signed integer be needed; for lksh signed arithmetic, only
* I think, the values need to be converted temporarily; !lksh signed
* arithmetic is instead done in unsigned; kul → kua (ksl → ksa lksh)
*/
#ifdef MKSH_LEGACY_MODE
#define KUA_HM LONG_MAX
#define KUA_FM ULONG_MAX
#else
#define KUA_HM K32_HM
#define KUA_FM K32_FM
#endif
/* arithmetic types: shell arithmetics */
/* new arithmetics tbd, using mbiMA_* */
/* older arithmetics, to be replaced later */
#ifdef MKSH_LEGACY_MODE
/*
* POSIX demands these to be the C environment's long type
*/
typedef long mksh_ari_t;
typedef unsigned long mksh_uari_t;
#else
/*
* These types are exactly 32 bit wide; signed and unsigned
* integer wraparound, even across division and modulo, for
* any shell code using them, is guaranteed.
*/
#if HAVE_CAN_INTTYPES
typedef int32_t mksh_ari_t;
typedef uint32_t mksh_uari_t;
#else
/* relies on compile-time asserts and CFLAGS to validate that */
typedef signed int mksh_ari_t;
typedef unsigned int mksh_uari_t;
#define INT32_MIN INT_MIN
#define INT32_MAX INT_MAX
#define UINT32_MAX UINT_MAX
#endif
#endif
/* new arithmetics in preparation */
/* boolean type (no <stdbool.h> deliberately) */
typedef unsigned char Wahr;
#define Ja 1U
#define Nee 0U
#define isWahr(cond) ((cond) ? Ja : Nee)
/* other standard types */
#if !HAVE_SIG_T
#undef sig_t
typedef void (*sig_t)(int);
#endif
#ifdef MKSH_TYPEDEF_SIG_ATOMIC_T
typedef MKSH_TYPEDEF_SIG_ATOMIC_T sig_atomic_t;
#endif
#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
#define MKSH_SHF_NO_INLINE
#endif
/* do not merge these conditionals as neatcc’s preprocessor is simple */
#ifdef __neatcc__
/* parsing of comma operator <,> in expressions broken */
#define MKSH_SHF_NO_INLINE
#endif
/* un-do vendor damage */
#undef BAD /* AIX defines that somewhere */
#undef PRINT /* LynxOS defines that somewhere */
#undef flock /* SCO UnixWare defines that to flock64 but ENOENT */
#ifndef MKSH_INCLUDES_ONLY
/* EBCDIC fun */
/* see the large comment in shf.c for an EBCDIC primer */
#if defined(MKSH_FOR_Z_OS) && defined(__MVS__) && defined(__IBMC__) && defined(__CHARSET_LIB)
# if !__CHARSET_LIB && !defined(MKSH_EBCDIC)
# error "Please compile with Build.sh -E for EBCDIC!"
# endif
# if __CHARSET_LIB && defined(MKSH_EBCDIC)
# error "Please compile without -E argument to Build.sh for ASCII!"
# endif
#endif
/* extra types */
/* getrusage does not exist on OS/2 kLIBC and is stubbed on SerenityOS */
#if !HAVE_GETRUSAGE
#undef rusage
#undef RUSAGE_SELF
#undef RUSAGE_CHILDREN
#define rusage mksh_rusage
#define RUSAGE_SELF 0
#define RUSAGE_CHILDREN -1
struct rusage {
struct timeval ru_utime;
struct timeval ru_stime;
};
extern int ksh_getrusage(int, struct rusage *);
#else
#define ksh_getrusage getrusage
#endif
/* extra macros */
#ifndef timerclear
#define timerclear(tvp) \
do { \
(tvp)->tv_sec = (tvp)->tv_usec = 0; \
} while (/* CONSTCOND */ 0)
#endif
#ifndef timeradd
#define timeradd(tvp,uvp,vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
if ((vvp)->tv_usec >= 1000000) { \
(vvp)->tv_sec++; \
(vvp)->tv_usec -= 1000000; \
} \
} while (/* CONSTCOND */ 0)
#endif
#ifndef timersub
#define timersub(tvp,uvp,vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
if ((vvp)->tv_usec < 0) { \
(vvp)->tv_sec--; \
(vvp)->tv_usec += 1000000; \
} \
} while (/* CONSTCOND */ 0)
#endif
#ifndef timercmp
#define timercmp(tvp,uvp,cmp) (((tvp)->tv_sec == (uvp)->tv_sec) ? \
((tvp)->tv_usec cmp (uvp)->tv_usec) : \
((tvp)->tv_sec cmp (uvp)->tv_sec))
#endif
/* if this breaks, see sh.h,v 1.954 commit message and diff */
#ifndef _POSIX_VDISABLE
/* Linux klibc lacks this definition */
#define _POSIX_VDISABLE 0xFFU /* unsigned (for cc_t) default (BSD) value */
#endif
#define KSH_ISVDIS(x,d) ((x) == _POSIX_VDISABLE ? (d) : KBI(x))
#define KSH_DOVDIS(x) (x) = _POSIX_VDISABLE
#ifndef S_ISFIFO
#define S_ISFIFO(m) ((m & 0170000) == 0010000)
#endif
#ifndef S_ISCHR
#define S_ISCHR(m) ((m & 0170000) == 0020000)
#endif
#ifndef S_ISLNK
#define S_ISLNK(m) ((m & 0170000) == 0120000)
#endif
#ifndef S_ISSOCK
#define S_ISSOCK(m) ((m & 0170000) == 0140000)
#endif
#if !defined(S_ISCDF) && defined(S_CDF)
#define S_ISCDF(m) (S_ISDIR(m) && ((m) & S_CDF))
#endif
#ifndef DEFFILEMODE
#define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
#endif
/* determine ksh_NSIG: first, use the traditional definitions */
#undef ksh_NSIG
#if defined(NSIG)
#define ksh_NSIG (NSIG)
#elif defined(_NSIG)
#define ksh_NSIG (_NSIG)
#elif defined(SIGMAX)
#define ksh_NSIG (SIGMAX + 1)
#elif defined(_SIGMAX)
#define ksh_NSIG (_SIGMAX + 1)
#elif defined(NSIG_MAX)
#define ksh_NSIG (NSIG_MAX)
#elif defined(MKSH_FOR_Z_OS)
#define ksh_NSIG 40
#else
# error Please have your platform define NSIG.
#endif
/* range-check them */
#if (ksh_NSIG < 1)
# error Your NSIG value is not positive.
#undef ksh_NSIG
#endif
/* second, see if the new POSIX definition is available */
#ifdef NSIG_MAX
#if (NSIG_MAX < 2)
/* and usable */
# error Your NSIG_MAX value is too small.
#undef NSIG_MAX
#elif (ksh_NSIG > NSIG_MAX)
/* and realistic */
# error Your NSIG value is larger than your NSIG_MAX value.
#undef NSIG_MAX
#else
/* since it’s usable, prefer it */
#undef ksh_NSIG
#define ksh_NSIG (NSIG_MAX)
#endif
/* if NSIG_MAX is now still defined, use sysconf(_SC_NSIG) at runtime */
#endif
/* third, for cpp without the error directive, default */
#ifndef ksh_NSIG
#define ksh_NSIG 64
#endif
#define ksh_sigmask(sig) (((sig) < 1 || (sig) > 127) ? 255 : 128 + (sig))
#if HAVE_SIGACTION
typedef struct sigaction ksh_sigsaved;
#define ksh_sighandler(saved) (saved.sa_handler)
void ksh_sigrestore(int, ksh_sigsaved *);
#else
typedef sig_t ksh_sigsaved;
#define ksh_sighandler(saved) (saved)
#define ksh_sigrestore(s,svp) ksh_sigset((s), *(svp), NULL)
#endif
#if HAVE_SIGDESCR_NP
#define ksh_sigmess(nr) sigdescr_np(nr)
#elif HAVE_SYS_SIGLIST
#if !HAVE_SYS_SIGLIST_DECL
extern const char * const sys_siglist[];
#endif
#define ksh_sigmess(nr) sys_siglist[nr]
#elif HAVE_STRSIGNAL
#define ksh_sigmess(nr) strsignal(nr)
#else
#define ksh_sigmess(nr) NULL
#endif
#define ksh_sigmessf(mess) (!(mess) || !*(mess))
/* contract: masks the signal, may restart, not oneshot */
void ksh_sigset(int, sig_t, ksh_sigsaved *);
/* OS-dependent additions (functions, variables, by OS) */
#ifdef MKSH_EXE_EXT
#undef MKSH_EXE_EXT
#define MKSH_EXE_EXT ".exe"
#else
#define MKSH_EXE_EXT ""
#endif
#ifdef __OS2__
#define MKSH_UNIXROOT "/@unixroot"
#else
#define MKSH_UNIXROOT ""
#endif
#ifdef MKSH_DOSPATH
#ifndef __GNUC__
# error GCC extensions needed later on
#endif
#define MKSH_PATHSEPS ";"
#define MKSH_PATHSEPC ';'
#else
#define MKSH_PATHSEPS ":"
#define MKSH_PATHSEPC ':'
#endif
#if !HAVE_FLOCK_DECL
extern int flock(int, int);
#endif
#if !HAVE_GETTIMEOFDAY
#define mksh_TIME(tv) do { \
(tv).tv_usec = 0; \
(tv).tv_sec = time(NULL); \
} while (/* CONSTCOND */ 0)
#else
#define mksh_TIME(tv) gettimeofday(&(tv), NULL)
#endif
#if !HAVE_MEMMOVE
#undef memmove
#define memmove rpl_memmove
void *rpl_memmove(void *, const void *, size_t);
#endif
#if !HAVE_REVOKE_DECL
extern int revoke(const char *);
#endif
#ifndef EOVERFLOW
#define EOVERFLOW ERANGE
#endif
#if defined(DEBUG) || !HAVE_STRERROR
#undef strerror
#define strerror /* poisoned */ dontuse_strerror
extern const char *cstrerror(int);
#else
#define cstrerror(errnum) ((const char *)strerror(errnum))
#endif
#if !HAVE_STRLCPY
size_t strlcpy(char *, const char *, size_t);
#endif
#ifdef __INTERIX
/* XXX imake style */
#define makedev mkdev
extern int __cdecl seteuid(uid_t);
extern int __cdecl setegid(gid_t);
#endif
#if defined(__COHERENT__)
#ifndef O_ACCMODE
/* this need not work everywhere, take care */
#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
#endif
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
#undef O_MAYEXEC /* https://lwn.net/Articles/820658/ */
#define O_MAYEXEC 0
#ifdef MKSH__NO_SYMLINK
#undef S_ISLNK
#define S_ISLNK(m) (/* CONSTCOND */ 0)
#define mksh_lstat stat
#else
#define mksh_lstat lstat
#endif
#if HAVE_TERMIOS_H
#define mksh_ttyst struct termios
#define mksh_tcget(fd,st) tcgetattr((fd), (st))
#define mksh_tcset(fd,st) tcsetattr((fd), TCSADRAIN, (st))
#else
#define mksh_ttyst struct termio
#define mksh_tcget(fd,st) ioctl((fd), TCGETA, (st))
#define mksh_tcset(fd,st) ioctl((fd), TCSETAW, (st))
#endif
#ifndef ISTRIP
#define ISTRIP 0
#endif
#ifdef MKSH_EBCDIC
#define KSH_BEL '\a'
#define KSH_ESC 047
#define KSH_ESC_STRING "\047"
#define KSH_VTAB '\v'
#else
/*
* According to the comments in pdksh, \007 seems to be more portable
* than \a (HP-UX cc, Ultrix cc, old pcc, etc.) so we avoid the escape
* sequence if ASCII can be assumed.
*/
#define KSH_BEL 7
#define KSH_ESC 033
#define KSH_ESC_STRING "\033"
#define KSH_VTAB 11
#endif
/* some useful #defines */
#ifdef EXTERN
# define E_INIT(i) = i
#else
# define E_INIT(i)
# define EXTERN extern
# define EXTERN_DEFINED
#endif
/* define bit in flag */
#define BIT(i) (1U << (i))
/* check bit(s) */
#define HAS(v,f) (((v) & (f)) == (f))
#define IS(v,f,t) (((v) & (f)) == (t))
/* array sizing */
#undef NELEM
#define NELEM(a) (sizeof(a) / sizeof((a)[0]))
/*
* Make MAGIC a char that might be printed to make bugs more obvious, but
* not a char that is used often. Also, can't use the high bit as it causes
* portability problems (calling strchr(x, 0x80 | 'x') is error prone).
*
* MAGIC can be followed by MAGIC (to escape the octet itself) or one of:
* ' !)*,-?[]{|}' 0x80|' !*+?@' (probably… hysteric raisins abound)
*
* The |0x80 is likely unsafe on EBCDIC :( though the listed chars are
* low-bit7 at least on cp1047 so YMMV
*/
#define MAGIC KSH_BEL /* prefix for *?[!{,} during expand */
#define ISMAGIC(c) (ord(c) == ORD(MAGIC))
EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */
#ifdef MKSH_LEGACY_MODE
#define KSH_VERSIONNAME_ISLEGACY "LEGACY"
#else
#define KSH_VERSIONNAME_ISLEGACY "MIRBSD"
#endif
#ifdef DEBUG
#define KSH_VERSIONNAME_DEBUG " +DEBUG_dont_ship_to_users"
#else
#define KSH_VERSIONNAME_DEBUG ""
#endif
#ifdef MKSH_WITH_TEXTMODE
#define KSH_VERSIONNAME_TEXTMODE " +TEXTMODE"
#else
#define KSH_VERSIONNAME_TEXTMODE ""
#endif
#ifdef MKSH_EBCDIC
#define KSH_VERSIONNAME_EBCDIC " +EBCDIC"
#else
#define KSH_VERSIONNAME_EBCDIC ""
#endif
#ifndef KSH_VERSIONNAME_VENDOR_EXT
#define KSH_VERSIONNAME_VENDOR_EXT ""
#endif
EXTERN const char initvsn[] E_INIT("KSH_VERSION=@(#)" KSH_VERSIONNAME_ISLEGACY \
" KSH " MKSH_VERSION KSH_VERSIONNAME_DEBUG \
KSH_VERSIONNAME_EBCDIC KSH_VERSIONNAME_TEXTMODE \
KSH_VERSIONNAME_VENDOR_EXT);
#define KSH_VERSION (initvsn + /* "KSH_VERSION=@(#)" */ 16)
EXTERN const char digits_uc[] E_INIT("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
EXTERN const char digits_lc[] E_INIT("0123456789abcdefghijklmnopqrstuvwxyz");
/*
* Evil hack for const correctness due to API brokenness
*/
union mksh_cchack {
char *rw;
const char *ro;
};
union mksh_ccphack {
char **rw;
const char **ro;
};
/* for const debugging */
#if defined(DEBUG)
char *ucstrchr(char *, int);
const char *cstrchr(const char *, int);
#undef strchr
#define strchr poisoned_strchr
#else
#define ucstrchr(s,c) strchr((s), (c))
#define cstrchr(s,c) ((const char *)strchr((s), (c)))
#endif
#define vstrchr(s,c) (cstrchr((s), (c)) != NULL)
#if defined(DEBUG) || !HAVE_STRSTR
char *ucstrstr(char *, const char *);
const char *cstrstr(const char *, const char *);
#define strstr poisoned_strstr
#else
#define ucstrstr(s,c) strstr((s), (c))
#define cstrstr(s,c) ((const char *)strstr((s), (c)))
#endif
#define vstrstr(b,l) (cstrstr((b), (l)) != NULL)
#if defined(DEBUG) || defined(__COVERITY__)
#ifndef DEBUG_LEAKS
#define DEBUG_LEAKS
#endif
#endif
#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 599)
#error Use the documented way to build this.
extern void thiswillneverbedefinedIhope(void);
int
im_sorry_dave(void)
{
/* I’m sorry, Dave. I’m afraid I can’t do that. */
return (thiswillneverbedefinedIhope());
}
#endif
/* use this ipv strchr(s, 0) but no side effects in s! */
#define strnul(s) ((s) + strlen((const void *)s))
/* inspired by jupp, where they are in lowercase though */
#define SC(s) (s), (sizeof(s) / sizeof(s[0]) - 1U)
#define SZ(s) (s), strlen(s)
#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
#define strdupx(d,s,ap) do { \
(d) = strdup_i((s), (ap)); \
} while (/* CONSTCOND */ 0)
#define strndupx(d,s,n,ap) do { \
(d) = strndup_i((s), (n), (ap)); \
} while (/* CONSTCOND */ 0)
#else
/* be careful to evaluate arguments only once! */
#define strdupx(d,s,ap) do { \
const char *strdup_src = (const void *)(s); \
char *strdup_dst = NULL; \
\
if (strdup_src != NULL) { \
size_t strdup_len = strlen(strdup_src) + 1U; \
strdup_dst = alloc(strdup_len, (ap)); \
memcpy(strdup_dst, strdup_src, strdup_len); \
} \
(d) = strdup_dst; \
} while (/* CONSTCOND */ 0)
#define strndupx(d,s,n,ap) do { \
const char *strdup_src = (const void *)(s); \
char *strdup_dst = NULL; \
\
if (strdup_src != NULL) { \
size_t strndup_len = (n); \
strdup_dst = alloc(strndup_len + 1U, (ap)); \
memcpy(strdup_dst, strdup_src, strndup_len); \
strdup_dst[strndup_len] = '\0'; \
} \
(d) = strdup_dst; \
} while (/* CONSTCOND */ 0)
#endif
#define strnbdupx(d,s,n,ap,b) do { \
const char *strdup_src = (const void *)(s); \
char *strdup_dst = NULL; \
\
if (strdup_src != NULL) { \
size_t strndup_len = (n); \
strdup_dst = strndup_len < sizeof(b) ? (b) : \
alloc(strndup_len + 1U, (ap)); \
memcpy(strdup_dst, strdup_src, strndup_len); \
strdup_dst[strndup_len] = '\0'; \
} \
(d) = strdup_dst; \
} while (/* CONSTCOND */ 0)
#define strdup2x(d,s1,s2) do { \
const char *strdup_src = (const void *)(s1); \
const char *strdup_app = (const void *)(s2); \
size_t strndup_len = strlen(strdup_src); \
size_t strndup_ln2 = strlen(strdup_app) + 1U; \
char *strdup_dst = alloc1(strndup_len, strndup_ln2, ATEMP); \
\
memcpy(strdup_dst, strdup_src, strndup_len); \
memcpy(strdup_dst + strndup_len, strdup_app, strndup_ln2); \
(d) = strdup_dst; \
} while (/* CONSTCOND */ 0)
#define strpathx(d,s1,s2,cond) do { \
const char *strdup_src = (const void *)(s1); \
const char *strdup_app = (const void *)(s2); \
size_t strndup_len = strlen(strdup_src) + 1U; \
size_t strndup_ln2 = ((cond) || *strdup_app) ? \
strlen(strdup_app) + 1U : 0; \
char *strdup_dst = alloc1(strndup_len, strndup_ln2, ATEMP); \
\
memcpy(strdup_dst, strdup_src, strndup_len); \
if (strndup_ln2) { \
strdup_dst[strndup_len - 1U] = '/'; \
memcpy(strdup_dst + strndup_len, strdup_app, \
strndup_ln2); \
} \
(d) = strdup_dst; \
} while (/* CONSTCOND */ 0)
#define memstr(d,s) memcpy((d), (s), sizeof(s))
#ifdef MKSH_SMALL
#ifndef MKSH_NOPWNAM
#define MKSH_NOPWNAM /* defined */
#endif
#ifndef MKSH_S_NOVI
#define MKSH_S_NOVI 1
#endif
#endif
#ifndef MKSH_S_NOVI
#define MKSH_S_NOVI 0
#endif
#if defined(MKSH_NOPROSPECTOFWORK) && !defined(MKSH_UNEMPLOYED)
#define MKSH_UNEMPLOYED 1
#endif
/* savedfd data type */
typedef kby ksh_fdsave;
/* savedfd “index is closed” mask */
#define FDICLMASK ((ksh_fdsave)0x80U)
/* savedfd “fd number” mask */
#define FDNUMMASK ((ksh_fdsave)0x7FU)
/* savedfd fd numbers are ≥ FDBASE */
/* savedfd “not saved” number: 0 */
/* savedfd “saved is closed” or savefd error indicator number */
#define FDCLOSED ((ksh_fdsave)0x01U)
/* savefd() to savedfd mapper */
#define FDSAVE(i,sfd) do { \
int FDSAVEsavedfd = (sfd); \
e->savedfd[i] = FDSAVEsavedfd < FDBASE ? FDCLOSED : \
/* ≤ FDMAXNUM checked in savefd() already */ \
(ksh_fdsave)(FDSAVEsavedfd & FDNUMMASK); \
} while (/* CONSTCOND */ 0)
/* savedfd to restfd mapper */
#define FDSVNUM(ep,i) ((kui)((ep)->savedfd[i] & FDNUMMASK))
#define SAVEDFD(ep,i) (FDSVNUM(ep, i) == (kui)FDCLOSED ? \
-1 : (int)FDSVNUM(ep, i))
/* first fd number usable by the shell for its own purposes */
#define FDBASE 10
/* … and last one */
#define FDMAXNUM 127 /* 0x7FU, cf. FDNUMMASK */
/* number of user-accessible file descriptors */
#define NUFILE 10
/*
* simple grouping allocator
*/
/* 0. OS API: where to get memory from and how to free it (grouped) */
/* malloc(3)/realloc(3) -> free(3) for use by the memory allocator */
#define malloc_osi(sz) malloc(sz)
#define realloc_osi(p,sz) realloc((p), (sz))
#define free_osimalloc(p) free(p)
/* malloc(3)/realloc(3) -> free(3) for use by mksh code */
#define malloc_osfunc(sz) malloc(sz)
#define realloc_osfunc(p,sz) realloc((p), (sz))
#define free_osfunc(p) free(p)
#if HAVE_MKNOD
/* setmode(3) -> free(3) */
#define free_ossetmode(p) free(p)
#endif
#if HAVE_GET_CURRENT_DIR_NAME
/* GNU libc: get_current_dir_name(3) -> free(3) */
#define free_gnu_gcdn(p) free(p)
#endif
/* 1. internal structure */
struct lalloc_common {
struct lalloc_common *next;
};
#ifdef MKSH_ALLOC_CATCH_UNDERRUNS
struct lalloc_item {
struct lalloc_common *next;
size_t len;
char dummy[8192 - sizeof(struct lalloc_common *) - sizeof(size_t)];
};
#endif
/* 2. sizes */
#ifdef MKSH_ALLOC_CATCH_UNDERRUNS
#define ALLOC_ITEM struct lalloc_item
#define ALLOC_OVERHEAD 0
#else
#define ALLOC_ITEM struct lalloc_common
#define ALLOC_OVERHEAD (sizeof(ALLOC_ITEM))
#endif
/* 3. group structure */
typedef struct lalloc_common Area;
EXTERN Area aperm; /* permanent object space */
#define APERM &aperm
#define ATEMP &e->area
/*
* flags (the order of these enums MUST match the order in misc.c(options[]))
*/
enum sh_flag {
#define SHFLAGS_ENUMS
#include "sh_flags.gen"
FNFLAGS /* (place holder: how many flags are there) */
};
#define Flag(f) (shell_flags[(int)(f)])
#define UTFMODE Flag(FUNNYCODE)
/*
* parsing & execution environment
*
* note that kshlongjmp MUST NOT be passed 0 as second argument!
*
* kshsetjmp() is to *not* save (and kshlongjmp() to not restore) signals!
*/
#ifdef MKSH_NO_SIGSETJMP
#define kshjmp_buf jmp_buf
#define kshsetjmp(jbuf) _setjmp(jbuf)
#define kshlongjmp _longjmp
#else
#define kshjmp_buf sigjmp_buf
#define kshsetjmp(jbuf) sigsetjmp((jbuf), 0)
#define kshlongjmp siglongjmp
#endif
struct sretrace_info;
struct yyrecursive_state;
EXTERN struct sretrace_info *retrace_info;
EXTERN unsigned int subshell_nesting_type;
extern struct env {
ALLOC_ITEM alloc_INT; /* internal, do not touch */
Area area; /* temporary allocation area */
struct env *oenv; /* link to previous environment */
struct block *loc; /* local variables and functions */
ksh_fdsave *savedfd; /* original fds for redirected fds */
struct temp *temps; /* temp files */
/* saved parser recursion state */
struct yyrecursive_state *yyrecursive_statep;
kshjmp_buf jbuf; /* long jump back to env creator */
kby type; /* environment type - see below */
kby flags; /* EF_* */