1 /* $NetBSD: misc.c,v 1.15 2011/10/16 17:12:11 joerg Exp $ */
4 * Miscellaneous functions
9 __RCSID("$NetBSD: misc.c,v 1.15 2011/10/16 17:12:11 joerg Exp $");
14 #include <ctype.h> /* for FILECHCONV */
20 # define UCHAR_MAX 0xFF
23 short ctypes
[UCHAR_MAX
+1]; /* type bits for unsigned char */
25 static int do_gmatch
ARGS((const unsigned char *s
, const unsigned char *p
,
26 const unsigned char *se
, const unsigned char *pe
,
28 static const unsigned char *cclass
ARGS((const unsigned char *p
, int sub
));
31 * Fast character classes
35 register const char *s
;
41 for (i
= 0; i
< UCHAR_MAX
+1; i
++)
43 ctypes
[0] |= C_IFS
; /* include \0 in C_IFS */
46 ctypes
[(unsigned char) *s
++] |= t
;
54 for (c
= 'a'; c
<= 'z'; c
++)
56 for (c
= 'A'; c
<= 'Z'; c
++)
58 ctypes
['_'] |= C_ALPHA
;
59 setctypes("0123456789", C_DIGIT
);
60 setctypes(" \t\n|&;<>()", C_LEX1
); /* \0 added automatically */
61 setctypes("*@#!$-?", C_VAR1
);
62 setctypes(" \t\n", C_IFSWS
);
63 setctypes("=-+?", C_SUBOP1
);
64 setctypes("#%", C_SUBOP2
);
65 setctypes(" \n\t\"#$&'()*;<>?[\\`|", C_QUOTE
);
68 /* convert unsigned long to base N string */
72 register unsigned long n
;
78 p
= &buf
[sizeof(buf
)];
81 *--p
= "0123456789ABCDEF"[n
%base
];
89 register const char *s
;
103 /* Allocate a string of size n+1 and copy upto n characters from the possibly
104 * null terminated string s into it. Always returns a null terminated string
109 register const char *s
;
117 ns
= alloc(n
+ 1, ap
);
119 return strncat(ns
, s
, n
);
122 /* called from expand.h:XcheckN() to grow buffer */
124 Xcheck_grow_(xsp
, xp
, more
)
129 char *old_beg
= xsp
->beg
;
131 xsp
->len
+= (size_t)more
> xsp
->len
? (size_t)more
: xsp
->len
;
132 xsp
->beg
= aresize(xsp
->beg
, xsp
->len
+ 8, xsp
->areap
);
133 xsp
->end
= xsp
->beg
+ xsp
->len
;
134 return xsp
->beg
+ (xp
- old_beg
);
137 const struct option goptions
[] = {
138 /* Special cases (see parse_args()): -A, -o, -s.
139 * Options are sorted by their longnames - the order of these
140 * entries MUST match the order of sh_flag F* enumerations in sh.h.
142 { "allexport", 'a', OF_ANY
},
144 { "braceexpand", 0, OF_ANY
}, /* non-standard */
146 { "bgnice", 0, OF_ANY
},
147 { (char *) 0, 'c', OF_CMDLINE
},
149 { "emacs", 0, OF_ANY
},
150 { "emacs-usemeta", 0, OF_ANY
}, /* non-standard */
152 { "errexit", 'e', OF_ANY
},
154 { "gmacs", 0, OF_ANY
},
156 { "ignoreeof", 0, OF_ANY
},
157 { "interactive",'i', OF_CMDLINE
},
158 { "keyword", 'k', OF_ANY
},
159 { "login", 'l', OF_CMDLINE
},
160 { "markdirs", 'X', OF_ANY
},
162 { "monitor", 'm', OF_ANY
},
164 { (char *) 0, 'm', 0 }, /* so FMONITOR not ifdef'd */
166 { "noclobber", 'C', OF_ANY
},
167 { "noexec", 'n', OF_ANY
},
168 { "noglob", 'f', OF_ANY
},
169 { "nohup", 0, OF_ANY
},
170 { "nolog", 0, OF_ANY
}, /* no effect */
172 { "notify", 'b', OF_ANY
},
174 { "nounset", 'u', OF_ANY
},
175 { "physical", 0, OF_ANY
}, /* non-standard */
176 { "posix", 0, OF_ANY
}, /* non-standard */
177 { "privileged", 'p', OF_ANY
},
178 { "restricted", 'r', OF_CMDLINE
},
179 { "stdin", 's', OF_CMDLINE
}, /* pseudo non-standard */
180 { "trackall", 'h', OF_ANY
},
181 { "verbose", 'v', OF_ANY
},
184 { "viraw", 0, OF_ANY
}, /* no effect */
185 { "vi-show8", 0, OF_ANY
}, /* non-standard */
186 { "vi-tabcomplete", 0, OF_ANY
}, /* non-standard */
187 { "vi-esccomplete", 0, OF_ANY
}, /* non-standard */
189 { "xtrace", 'x', OF_ANY
},
190 /* Anonymous flags: used internally by shell only
191 * (not visible to user)
193 { (char *) 0, 0, OF_INTERNAL
}, /* FTALKING_I */
197 * translate -o option into F* constant (also used for test -o option)
205 for (i
= 0; i
< (int)NELEM(goptions
); i
++)
206 if (goptions
[i
].name
&& strcmp(goptions
[i
].name
, n
) == 0)
212 struct options_info
{
217 } opts
[NELEM(goptions
)];
220 static char *options_fmt_entry
ARGS((void *arg
, int i
, char *buf
, int buflen
));
221 static void printoptions
ARGS((int verbose
));
223 /* format a single select menu item */
225 options_fmt_entry(arg
, i
, buf
, buflen
)
231 struct options_info
*oi
= (struct options_info
*) arg
;
233 shf_snprintf(buf
, buflen
, "%-*s %s",
234 oi
->opt_width
, oi
->opts
[i
].name
,
235 Flag(oi
->opts
[i
].flag
) ? "on" : "off");
240 printoptions(verbose
)
246 struct options_info oi
;
249 /* verbose version */
250 shprintf("Current option settings\n");
252 for (i
= n
= oi
.opt_width
= 0; i
< (int)NELEM(goptions
); i
++)
253 if (goptions
[i
].name
) {
254 len
= strlen(goptions
[i
].name
);
255 oi
.opts
[n
].name
= goptions
[i
].name
;
256 oi
.opts
[n
++].flag
= i
;
257 if (len
> oi
.opt_width
)
260 print_columns(shl_stdout
, n
, options_fmt_entry
, &oi
,
261 oi
.opt_width
+ 5, 1);
263 /* short version ala ksh93 */
265 for (i
= 0; i
< (int)NELEM(goptions
); i
++)
266 if (Flag(i
) && goptions
[i
].name
)
267 shprintf(" -o %s", goptions
[i
].name
);
268 shprintf("%s", newline
);
276 char m
[(int) FNFLAGS
+ 1];
277 register char *cp
= m
;
279 for (i
= 0; i
< NELEM(goptions
); i
++)
280 if (goptions
[i
].c
&& Flag(i
))
281 *cp
++ = goptions
[i
].c
;
283 return str_save(m
, ATEMP
);
286 /* change a Flag(*) value; takes care of special actions */
288 change_flag(f
, what
, newval
)
289 enum sh_flag f
; /* flag to change */
290 int what
; /* what is changing the flag (command line vs set) */
299 if (what
!= OF_CMDLINE
&& newval
!= oldval
)
309 || f
== FEMACS
|| f
== FGMACS
318 Flag(FEMACS
) = Flag(FGMACS
) = 0;
324 /* Turning off -p? */
325 if (f
== FPRIVILEGED
&& oldval
&& !newval
) {
329 seteuid(ksheuid
= getuid());
334 } else if (f
== FPOSIX
&& newval
) {
336 Flag(FBRACEEXPAND
) = 0
337 #endif /* BRACE_EXPAND */
340 /* Changing interactive flag? */
342 if ((what
== OF_CMDLINE
|| what
== OF_SET
) && procpid
== kshpid
)
343 Flag(FTALKING_I
) = newval
;
347 /* parse command line & set command arguments. returns the index of
348 * non-option arguments, -1 if there is an error.
351 parse_args(argv
, what
, setargsp
)
353 int what
; /* OF_CMDLINE or OF_SET */
356 static char cmd_opts
[NELEM(goptions
) + 3]; /* o:\0 */
357 static char set_opts
[NELEM(goptions
) + 5]; /* Ao;s\0 */
359 char *array
= (char *) 0;
361 int i
, optc
, set
, sortargs
= 0, arrayset
= 0;
363 /* First call? Build option strings... */
364 if (cmd_opts
[0] == '\0') {
367 /* see cmd_opts[] declaration */
368 strlcpy(cmd_opts
, "o:", sizeof cmd_opts
);
369 p
= cmd_opts
+ strlen(cmd_opts
);
370 /* see set_opts[] declaration */
371 strlcpy(set_opts
, "A:o;s", sizeof set_opts
);
372 q
= set_opts
+ strlen(set_opts
);
373 for (i
= 0; i
< (int)NELEM(goptions
); i
++) {
375 if (goptions
[i
].flags
& OF_CMDLINE
)
376 *p
++ = goptions
[i
].c
;
377 if (goptions
[i
].flags
& OF_SET
)
378 *q
++ = goptions
[i
].c
;
385 if (what
== OF_CMDLINE
) {
387 /* Set FLOGIN before parsing options so user can clear
390 Flag(FLOGIN
) = (argv
[0][0] == '-'
391 || ((p
= ksh_strrchr_dirsep(argv
[0]))
396 ksh_getopt_reset(&go
, GF_ERROR
|GF_PLUSOPT
);
397 while ((optc
= ksh_getopt(argv
, &go
, opts
)) != EOF
) {
398 set
= (go
.info
& GI_PLUS
) ? 0 : 1;
401 arrayset
= set
? 1 : -1;
406 if (go
.optarg
== (char *) 0) {
407 /* lone -o: print options
409 * Note that on the command line, -o requires
410 * an option (ie, can't get here if what is
416 i
= option(go
.optarg
);
417 if (i
>= 0 && set
== Flag(i
))
418 /* Don't check the context if the flag
419 * isn't changing - makes "set -o interactive"
420 * work if you're already interactive. Needed
421 * if the output of "set +o" is to be used.
424 else if (i
>= 0 && (goptions
[i
].flags
& what
))
425 change_flag((enum sh_flag
) i
, what
, set
);
427 bi_errorf("%s: bad option", go
.optarg
);
436 /* -s: sort positional params (at&t ksh stupidity) */
437 if (what
== OF_SET
&& optc
== 's') {
441 for (i
= 0; i
< (int)NELEM(goptions
); i
++)
442 if (optc
== goptions
[i
].c
443 && (what
& goptions
[i
].flags
))
445 change_flag((enum sh_flag
) i
, what
,
449 if (i
== NELEM(goptions
)) {
450 internal_errorf(1, "parse_args: `%c'", optc
);
451 return -1; /* not reached */
455 if (!(go
.info
& GI_MINUSMINUS
) && argv
[go
.optind
]
456 && (argv
[go
.optind
][0] == '-' || argv
[go
.optind
][0] == '+')
457 && argv
[go
.optind
][1] == '\0')
459 /* lone - clears -v and -x flags */
460 if (argv
[go
.optind
][0] == '-' && !Flag(FPOSIX
))
461 Flag(FVERBOSE
) = Flag(FXTRACE
) = 0;
462 /* set skips lone - or + option */
466 /* -- means set $#/$* even if there are no arguments */
467 *setargsp
= !arrayset
&& ((go
.info
& GI_MINUSMINUS
)
470 if (arrayset
&& (!*array
|| *skip_varname(array
, FALSE
))) {
471 bi_errorf("%s: is not an identifier", array
);
475 for (i
= go
.optind
; argv
[i
]; i
++)
477 qsortp((void **) &argv
[go
.optind
], (size_t) (i
- go
.optind
),
481 set_array(array
, arrayset
, argv
+ go
.optind
);
482 for (; argv
[go
.optind
]; go
.optind
++)
489 /* parse a decimal number: returns 0 if string isn't a number, 1 otherwise */
498 n
= strtol(as
, &p
, 10);
500 if (!*as
|| *p
|| INT_MIN
>= n
|| n
>= INT_MAX
)
507 /* getn() that prints error */
513 int rv
= getn(as
, ai
);
516 bi_errorf("%s: bad number", as
);
520 /* -------- gmatch.c -------- */
523 * int gmatch(string, pattern)
524 * char *string, *pattern;
526 * Match a pattern as in sh(1).
527 * pattern character are prefixed with MAGIC by expand.
537 if (s
== NULL
|| p
== NULL
)
541 /* isfile is false iff no syntax check has been done on
542 * the pattern. If check fails, just to a strcmp().
544 if (!isfile
&& !has_globbing(p
, pe
)) {
545 int len
= pe
- p
+ 1;
547 char *t
= len
<= (int)sizeof(tbuf
) ? tbuf
548 : (char *) alloc(len
, ATEMP
);
550 return !strcmp(t
, s
);
552 return do_gmatch((const unsigned char *) s
, (const unsigned char *) se
,
553 (const unsigned char *) p
, (const unsigned char *) pe
,
557 /* Returns if p is a syntacticly correct globbing pattern, false
558 * if it contains no pattern characters or if there is a syntax error.
560 * - [ with no closing ]
561 * - imbalanced $(...) expression
562 * - [...] and *(...) not nested (eg, [a$(b|]c), *(a[b|c]d))
566 if dest given, copy to dst
568 - if magic && (no globbing || syntax error)
574 has_globbing(xp
, xpe
)
575 const char *xp
, *xpe
;
577 const unsigned char *p
= (const unsigned char *) xp
;
578 const unsigned char *pe
= (const unsigned char *) xpe
;
580 int nest
= 0, bnest
= 0;
582 int in_bracket
= 0; /* inside [...] */
584 for (; p
< pe
; p
++) {
587 if ((c
= *++p
) == '*' || c
== '?')
593 if (ISMAGIC(p
[1]) && p
[2] == NOT
)
595 if (ISMAGIC(p
[1]) && p
[2] == ']')
598 /* XXX Do we need to check ranges here? POSIX Q */
599 } else if (c
== ']') {
601 if (bnest
) /* [a*(b]) */
605 } else if ((c
& 0x80) && strchr("*+?@! ", c
& 0x7f)) {
611 } else if (c
== '|') {
612 if (in_bracket
&& !bnest
) /* *(a[foo|bar]) */
614 } else if (c
== /*(*/ ')') {
616 if (!bnest
--) /* *(a[b)c] */
621 /* else must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, MAGIC-]
622 MAGIC-{, MAGIC-,, MAGIC-} */
624 return saw_glob
&& !in_bracket
&& !nest
;
627 /* Function must return either 0 or 1 (assumed by code for 0x80|'!') */
629 do_gmatch(s
, se
, p
, pe
, isfile
)
630 const unsigned char *s
, *p
;
631 const unsigned char *se
, *pe
;
635 const unsigned char *prest
, *psub
, *pnext
;
636 const unsigned char *srest
;
638 if (s
== NULL
|| p
== NULL
)
642 sc
= s
< se
? *s
: '\0';
645 sc
= FILECHCONV((unsigned char)sc
);
646 pc
= FILECHCONV((unsigned char)pc
);
655 if (sc
== 0 || (p
= cclass(p
, sc
)) == NULL
)
669 if (do_gmatch(s
, se
, p
, pe
, isfile
))
675 * [*+?@!](pattern|pattern|..)
677 * Not ifdef'd KSH as this is needed for ${..%..}, etc.
679 case 0x80|'+': /* matches one or more times */
680 case 0x80|'*': /* matches zero or more times */
681 if (!(prest
= pat_scan(p
, pe
, 0)))
684 /* take care of zero matches */
685 if (p
[-1] == (0x80 | '*')
686 && do_gmatch(s
, se
, prest
, pe
, isfile
))
688 for (psub
= p
; ; psub
= pnext
) {
689 pnext
= pat_scan(psub
, pe
, 1);
690 for (srest
= s
; srest
<= se
; srest
++) {
691 if (do_gmatch(s
, srest
,
692 psub
, pnext
- 2, isfile
)
693 && (do_gmatch(srest
, se
,
696 && do_gmatch(srest
, se
,
697 p
- 2, pe
, isfile
))))
705 case 0x80|'?': /* matches zero or once */
706 case 0x80|'@': /* matches one of the patterns */
707 case 0x80|' ': /* simile for @ */
708 if (!(prest
= pat_scan(p
, pe
, 0)))
711 /* Take care of zero matches */
712 if (p
[-1] == (0x80 | '?')
713 && do_gmatch(s
, se
, prest
, pe
, isfile
))
715 for (psub
= p
; ; psub
= pnext
) {
716 pnext
= pat_scan(psub
, pe
, 1);
717 srest
= prest
== pe
? se
: s
;
718 for (; srest
<= se
; srest
++) {
719 if (do_gmatch(s
, srest
,
720 psub
, pnext
- 2, isfile
)
721 && do_gmatch(srest
, se
,
730 case 0x80|'!': /* matches none of the patterns */
731 if (!(prest
= pat_scan(p
, pe
, 0)))
734 for (srest
= s
; srest
<= se
; srest
++) {
737 for (psub
= p
; ; psub
= pnext
) {
738 pnext
= pat_scan(psub
, pe
, 1);
739 if (do_gmatch(s
, srest
,
740 psub
, pnext
- 2, isfile
))
748 if (!matched
&& do_gmatch(srest
, se
,
763 static const unsigned char *
765 const unsigned char *p
;
768 register int c
, d
, not, found
= 0;
769 const unsigned char *orig_p
= p
;
771 if ((not = (ISMAGIC(*p
) && *++p
== NOT
)))
777 if ((c
& 0x80) && !ISMAGIC(c
)) {
778 c
&= 0x7f;/* extended pattern matching: *+?@! */
779 /* XXX the ( char isn't handled as part of [] */
780 if (c
== ' ') /* simile for @: plain (..) */
785 /* No closing ] - act as if the opening [ was quoted */
786 return sub
== '[' ? orig_p
: NULL
;
787 if (ISMAGIC(p
[0]) && p
[1] == '-'
788 && (!ISMAGIC(p
[2]) || p
[3] != ']'))
794 if ((d
& 0x80) && !ISMAGIC(d
))
797 /* POSIX says this is an invalid expression */
802 if (c
== sub
|| (c
<= sub
&& sub
<= d
))
804 } while (!(ISMAGIC(p
[0]) && p
[1] == ']'));
806 return (found
!= not) ? p
+2 : NULL
;
809 /* Look for next ) or | (if match_sep) in *(foo|bar) pattern */
810 const unsigned char *
811 pat_scan(p
, pe
, match_sep
)
812 const unsigned char *p
;
813 const unsigned char *pe
;
818 for (; p
< pe
; p
++) {
821 if ((*++p
== /*(*/ ')' && nest
-- == 0)
822 || (*p
== '|' && match_sep
&& nest
== 0))
824 if ((*p
& 0x80) && strchr("*+?@! ", *p
& 0x7f))
827 return (const unsigned char *) 0;
831 /* -------- qsort.c -------- */
834 * quick sort of array of generic pointers to objects.
836 static void qsort1
ARGS((void **base
, void **lim
, int (*f
)(void *, void *)));
840 void **base
; /* base address */
841 size_t n
; /* elements */
842 int (*f
) ARGS((void *, void *)); /* compare function */
844 qsort1(base
, base
+ n
, f
);
847 #define swap2(a, b) {\
848 register void *t; t = *(a); *(a) = *(b); *(b) = t;\
850 #define swap3(a, b, c) {\
851 register void *t; t = *(a); *(a) = *(c); *(c) = *(b); *(b) = t;\
857 int (*f
) ARGS((void *, void *));
859 register void **i
, **j
;
860 register void **lptr
, **hptr
;
865 n
= (lim
- base
) / 2;
868 hptr
= lptr
= base
+n
;
874 if ((c
= (*f
)(*i
, *lptr
)) == 0) {
887 if ((c
= (*f
)(*hptr
, *j
)) == 0) {
909 if (lptr
-base
>= lim
-hptr
) {
910 qsort1(hptr
+1, lim
, f
);
913 qsort1(base
, lptr
, f
);
929 return (strcmp((char *)p1
, (char *)p2
));
932 /* Initialize a Getopt structure */
934 ksh_getopt_reset(go
, flags
)
939 go
->optarg
= (char *) 0;
947 /* getopt() used for shell built-in commands, the getopts command, and
948 * command line options.
949 * A leading ':' in options means don't print errors, instead return '?'
950 * or ':' and set go->optarg to the offending option character.
951 * If GF_ERROR is set (and option doesn't start with :), errors result in
952 * a call to bi_errorf().
954 * Non-standard features:
955 * - ';' is like ':' in options, except the argument is optional
956 * (if it isn't present, optarg is set to 0).
958 * - ',' is like ':' in options, except the argument always immediately
959 * follows the option character (optarg is set to the null string if
960 * the option is missing).
961 * Used for 'read -u2', 'print -u2' and fc -40.
962 * - '#' is like ':' in options, expect that the argument is optional
963 * and must start with a digit. If the argument doesn't start with a
964 * digit, it is assumed to be missing and normal option processing
965 * continues (optarg is set to 0 if the option is missing).
966 * Used for 'typeset -LZ4'.
967 * - accepts +c as well as -c IF the GF_PLUSOPT flag is present. If an
968 * option starting with + is accepted, the GI_PLUS flag will be set
972 ksh_getopt(argv
, go
, options
)
980 if (go
->p
== 0 || (c
= argv
[go
->optind
- 1][go
->p
]) == '\0') {
981 char *arg
= argv
[go
->optind
], flag
= arg
? *arg
: '\0';
984 if (flag
== '-' && arg
[1] == '-' && arg
[2] == '\0') {
987 go
->info
|= GI_MINUSMINUS
;
990 if (arg
== (char *) 0
991 || ((flag
!= '-' ) /* neither a - nor a + (if + allowed) */
992 && (!(go
->flags
& GF_PLUSOPT
) || flag
!= '+'))
993 || (c
= arg
[1]) == '\0')
999 go
->info
&= ~(GI_MINUS
|GI_PLUS
);
1000 go
->info
|= flag
== '-' ? GI_MINUS
: GI_PLUS
;
1003 if (c
== '?' || c
== ':' || c
== ';' || c
== ',' || c
== '#'
1004 || !(o
= strchr(options
, c
)))
1006 if (options
[0] == ':') {
1008 go
->optarg
= go
->buf
;
1010 warningf(TRUE
, "%s%s-%c: unknown option",
1011 (go
->flags
& GF_NONAME
) ? "" : argv
[0],
1012 (go
->flags
& GF_NONAME
) ? "" : ": ", c
);
1013 if (go
->flags
& GF_ERROR
)
1014 bi_errorf("%s", null
);
1018 /* : means argument must be present, may be part of option argument
1019 * or the next argument
1020 * ; same as : but argument may be missing
1021 * , means argument is part of option argument, and may be null.
1023 if (*++o
== ':' || *o
== ';') {
1024 if (argv
[go
->optind
- 1][go
->p
])
1025 go
->optarg
= argv
[go
->optind
- 1] + go
->p
;
1026 else if (argv
[go
->optind
])
1027 go
->optarg
= argv
[go
->optind
++];
1029 go
->optarg
= (char *) 0;
1031 if (options
[0] == ':') {
1033 go
->optarg
= go
->buf
;
1036 warningf(TRUE
, "%s%s-`%c' requires argument",
1037 (go
->flags
& GF_NONAME
) ? "" : argv
[0],
1038 (go
->flags
& GF_NONAME
) ? "" : ": ", c
);
1039 if (go
->flags
& GF_ERROR
)
1040 bi_errorf("%s", null
);
1044 } else if (*o
== ',') {
1045 /* argument is attached to option character, even if null */
1046 go
->optarg
= argv
[go
->optind
- 1] + go
->p
;
1048 } else if (*o
== '#') {
1049 /* argument is optional and may be attached or unattached
1050 * but must start with a digit. optarg is set to 0 if the
1051 * argument is missing.
1053 if (argv
[go
->optind
- 1][go
->p
]) {
1054 if (digit(argv
[go
->optind
- 1][go
->p
])) {
1055 go
->optarg
= argv
[go
->optind
- 1] + go
->p
;
1058 go
->optarg
= (char *) 0;
1060 if (argv
[go
->optind
] && digit(argv
[go
->optind
][0])) {
1061 go
->optarg
= argv
[go
->optind
++];
1064 go
->optarg
= (char *) 0;
1070 /* print variable/alias value using necessary quotes
1071 * (POSIX says they should be suitable for re-entry...)
1072 * No trailing newline is printed.
1075 print_value_quoted(s
)
1081 /* Test if any quotes are needed */
1082 for (p
= s
; *p
; p
++)
1083 if (ctype(*p
, C_QUOTE
))
1089 for (p
= s
; *p
; p
++) {
1091 shprintf("%s", "'\\'" + 1 - inquote
);
1098 shf_putc(*p
, shl_stdout
);
1105 /* Print things in columns and rows - func() is called to format the ith
1109 print_columns(shf
, n
, func
, arg
, max_width
, prefcol
)
1112 char *(*func
) ARGS((void *, int, char *, int));
1117 char *str
= (char *) alloc(max_width
+ 1, ATEMP
);
1123 /* max_width + 1 for the space. Note that no space
1124 * is printed after the last column to avoid problems
1125 * with terminals that have auto-wrap.
1127 cols
= x_cols
/ (max_width
+ 1);
1130 rows
= (n
+ cols
- 1) / cols
;
1131 if (prefcol
&& n
&& cols
> rows
) {
1140 nspace
= (x_cols
- max_width
* cols
) / cols
;
1143 for (r
= 0; r
< rows
; r
++) {
1144 for (c
= 0; c
< cols
; c
++) {
1147 shf_fprintf(shf
, "%-*s",
1149 (*func
)(arg
, i
, str
, max_width
+ 1));
1151 shf_fprintf(shf
, "%*s", nspace
, null
);
1154 shf_putchar('\n', shf
);
1159 /* Strip any nul bytes from buf - returns new length (nbytes - # of nuls) */
1161 strip_nuls(buf
, nbytes
)
1167 /* nbytes check because some systems (older freebsd's) have a buggy
1170 if (nbytes
&& (dst
= memchr(buf
, '\0', nbytes
))) {
1171 char *end
= buf
+ nbytes
;
1174 for (p
= dst
; p
< end
; p
= q
) {
1175 /* skip a block of nulls */
1176 while (++p
< end
&& *p
== '\0')
1178 /* find end of non-null block */
1179 if (!(q
= memchr(p
, '\0', end
- p
)))
1181 memmove(dst
, p
, q
- p
);
1190 /* Copy at most dsize-1 bytes from src to dst, ensuring dst is null terminated.
1194 str_zcpy(dst
, src
, dsize
)
1200 int len
= strlen(src
);
1204 memcpy(dst
, src
, len
);
1210 /* Like read(2), but if read fails due to non-blocking flag, resets flag
1211 * and restarts read.
1214 blocking_read(fd
, buf
, nbytes
)
1220 int tried_reset
= 0;
1222 while ((ret
= read(fd
, buf
, nbytes
)) < 0) {
1223 if (!tried_reset
&& (errno
== EAGAIN
1225 || errno
== EWOULDBLOCK
1226 #endif /* EWOULDBLOCK */
1230 if (reset_nonblock(fd
) > 0) {
1241 /* Reset the non-blocking flag on the specified file descriptor.
1242 * Returns -1 if there was an error, 0 if non-blocking wasn't set,
1252 if ((flags
= fcntl(fd
, F_GETFL
, 0)) < 0)
1254 /* With luck, the C compiler will reduce this to a constant */
1257 blocking_flags
|= O_NONBLOCK
;
1258 #endif /* O_NONBLOCK */
1260 blocking_flags
|= O_NDELAY
;
1261 #else /* O_NDELAY */
1263 blocking_flags
|= FNDELAY
; /* hope this exists... */
1264 # endif /* O_NONBLOCK */
1265 #endif /* O_NDELAY */
1266 if (!(flags
& blocking_flags
))
1268 flags
&= ~blocking_flags
;
1269 if (fcntl(fd
, F_SETFL
, flags
) < 0)
1275 #ifdef HAVE_SYS_PARAM_H
1276 # include <sys/param.h>
1277 #endif /* HAVE_SYS_PARAM_H */
1279 # define MAXPATHLEN PATH
1280 #endif /* MAXPATHLEN */
1282 #ifdef HPUX_GETWD_BUG
1283 # include "ksh_dir.h"
1286 * Work around bug in hpux 10.x C library - getwd/getcwd dump core
1287 * if current directory is not readable. Done in macro 'cause code
1288 * is needed in GETWD and GETCWD cases.
1290 # define HPUX_GETWD_BUG_CODE \
1292 DIR *d = ksh_opendir("."); \
1294 return (char *) 0; \
1297 #else /* HPUX_GETWD_BUG */
1298 # define HPUX_GETWD_BUG_CODE
1299 #endif /* HPUX_GETWD_BUG */
1301 /* Like getcwd(), except bsize is ignored if buf is 0 (MAXPATHLEN is used) */
1303 ksh_get_wd(buf
, bsize
)
1311 /* Before memory allocated */
1314 /* Assume getcwd() available */
1317 b
= alloc(MAXPATHLEN
+ 1, ATEMP
);
1321 ret
= getcwd(b
, bsize
);
1325 ret
= aresize(b
, strlen(b
) + 1, ATEMP
);
1331 #else /* HAVE_GETCWD */
1332 extern char *getwd
ARGS((char *));
1336 /* Before memory allocated */
1339 if (buf
&& bsize
> MAXPATHLEN
)
1342 b
= alloc(MAXPATHLEN
+ 1, ATEMP
);
1343 if (!getcwd(b
, MAXPATHLEN
)) {
1349 len
= strlen(b
) + 1;
1351 b
= aresize(b
, len
, ATEMP
);
1352 else if (buf
!= b
) {
1357 memcpy(buf
, b
, len
);
1363 #endif /* HAVE_GETCWD */