1c84f3f3cSopenharmony_ci/* $OpenBSD: misc.c,v 1.41 2015/09/10 22:48:58 nicm Exp $ */ 2c84f3f3cSopenharmony_ci/* $OpenBSD: path.c,v 1.13 2015/09/05 09:47:08 jsg Exp $ */ 3c84f3f3cSopenharmony_ci 4c84f3f3cSopenharmony_ci/*- 5c84f3f3cSopenharmony_ci * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 6c84f3f3cSopenharmony_ci * 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, 7c84f3f3cSopenharmony_ci * 2020 8c84f3f3cSopenharmony_ci * mirabilos <m@mirbsd.org> 9c84f3f3cSopenharmony_ci * Copyright (c) 2015 10c84f3f3cSopenharmony_ci * Daniel Richard G. <skunk@iSKUNK.ORG> 11c84f3f3cSopenharmony_ci * 12c84f3f3cSopenharmony_ci * Provided that these terms and disclaimer and all copyright notices 13c84f3f3cSopenharmony_ci * are retained or reproduced in an accompanying document, permission 14c84f3f3cSopenharmony_ci * is granted to deal in this work without restriction, including un- 15c84f3f3cSopenharmony_ci * limited rights to use, publicly perform, distribute, sell, modify, 16c84f3f3cSopenharmony_ci * merge, give away, or sublicence. 17c84f3f3cSopenharmony_ci * 18c84f3f3cSopenharmony_ci * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 19c84f3f3cSopenharmony_ci * the utmost extent permitted by applicable law, neither express nor 20c84f3f3cSopenharmony_ci * implied; without malicious intent or gross negligence. In no event 21c84f3f3cSopenharmony_ci * may a licensor, author or contributor be held liable for indirect, 22c84f3f3cSopenharmony_ci * direct, other damage, loss, or other issues arising in any way out 23c84f3f3cSopenharmony_ci * of dealing in the work, even if advised of the possibility of such 24c84f3f3cSopenharmony_ci * damage or existence of a defect, except proven that it results out 25c84f3f3cSopenharmony_ci * of said person's immediate fault when using the work as intended. 26c84f3f3cSopenharmony_ci */ 27c84f3f3cSopenharmony_ci 28c84f3f3cSopenharmony_ci#include "sh.h" 29c84f3f3cSopenharmony_ci#if !HAVE_GETRUSAGE 30c84f3f3cSopenharmony_ci#include <sys/times.h> 31c84f3f3cSopenharmony_ci#endif 32c84f3f3cSopenharmony_ci#if HAVE_GRP_H 33c84f3f3cSopenharmony_ci#include <grp.h> 34c84f3f3cSopenharmony_ci#endif 35c84f3f3cSopenharmony_ci 36c84f3f3cSopenharmony_ci__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.302 2020/08/27 19:52:45 tg Exp $"); 37c84f3f3cSopenharmony_ci 38c84f3f3cSopenharmony_ci#define KSH_CHVT_FLAG 39c84f3f3cSopenharmony_ci#ifdef MKSH_SMALL 40c84f3f3cSopenharmony_ci#undef KSH_CHVT_FLAG 41c84f3f3cSopenharmony_ci#endif 42c84f3f3cSopenharmony_ci#ifdef TIOCSCTTY 43c84f3f3cSopenharmony_ci#define KSH_CHVT_CODE 44c84f3f3cSopenharmony_ci#define KSH_CHVT_FLAG 45c84f3f3cSopenharmony_ci#endif 46c84f3f3cSopenharmony_ci 47c84f3f3cSopenharmony_ci/* type bits for unsigned char */ 48c84f3f3cSopenharmony_ciunsigned char chtypes[UCHAR_MAX + 1]; 49c84f3f3cSopenharmony_ci 50c84f3f3cSopenharmony_cistatic const unsigned char *pat_scan(const unsigned char *, 51c84f3f3cSopenharmony_ci const unsigned char *, bool) MKSH_A_PURE; 52c84f3f3cSopenharmony_cistatic int do_gmatch(const unsigned char *, const unsigned char *, 53c84f3f3cSopenharmony_ci const unsigned char *, const unsigned char *, 54c84f3f3cSopenharmony_ci const unsigned char *) MKSH_A_PURE; 55c84f3f3cSopenharmony_cistatic const unsigned char *gmatch_cclass(const unsigned char *, unsigned char) 56c84f3f3cSopenharmony_ci MKSH_A_PURE; 57c84f3f3cSopenharmony_ci#ifdef KSH_CHVT_CODE 58c84f3f3cSopenharmony_cistatic void chvt(const Getopt *); 59c84f3f3cSopenharmony_ci#endif 60c84f3f3cSopenharmony_ci 61c84f3f3cSopenharmony_ci/*XXX this should go away */ 62c84f3f3cSopenharmony_cistatic int make_path(const char *, const char *, char **, XString *, int *); 63c84f3f3cSopenharmony_ci 64c84f3f3cSopenharmony_ci#ifdef SETUID_CAN_FAIL_WITH_EAGAIN 65c84f3f3cSopenharmony_ci/* we don't need to check for other codes, EPERM won't happen */ 66c84f3f3cSopenharmony_ci#define DO_SETUID(func,argvec) do { \ 67c84f3f3cSopenharmony_ci if ((func argvec) && errno == EAGAIN) \ 68c84f3f3cSopenharmony_ci errorf("%s failed with EAGAIN, probably due to a" \ 69c84f3f3cSopenharmony_ci " too low process limit; aborting", #func); \ 70c84f3f3cSopenharmony_ci} while (/* CONSTCOND */ 0) 71c84f3f3cSopenharmony_ci#else 72c84f3f3cSopenharmony_ci#define DO_SETUID(func,argvec) func argvec 73c84f3f3cSopenharmony_ci#endif 74c84f3f3cSopenharmony_ci 75c84f3f3cSopenharmony_ci 76c84f3f3cSopenharmony_ci/* called from XcheckN() to grow buffer */ 77c84f3f3cSopenharmony_cichar * 78c84f3f3cSopenharmony_ciXcheck_grow(XString *xsp, const char *xp, size_t more) 79c84f3f3cSopenharmony_ci{ 80c84f3f3cSopenharmony_ci const char *old_beg = xsp->beg; 81c84f3f3cSopenharmony_ci 82c84f3f3cSopenharmony_ci if (more < xsp->len) 83c84f3f3cSopenharmony_ci more = xsp->len; 84c84f3f3cSopenharmony_ci /* (xsp->len + X_EXTRA) never overflows */ 85c84f3f3cSopenharmony_ci checkoktoadd(more, xsp->len + X_EXTRA); 86c84f3f3cSopenharmony_ci xsp->beg = aresize(xsp->beg, (xsp->len += more) + X_EXTRA, xsp->areap); 87c84f3f3cSopenharmony_ci xsp->end = xsp->beg + xsp->len; 88c84f3f3cSopenharmony_ci return (xsp->beg + (xp - old_beg)); 89c84f3f3cSopenharmony_ci} 90c84f3f3cSopenharmony_ci 91c84f3f3cSopenharmony_ci 92c84f3f3cSopenharmony_ci#define SHFLAGS_DEFNS 93c84f3f3cSopenharmony_ci#define FN(sname,cname,flags,ochar) \ 94c84f3f3cSopenharmony_ci static const struct { \ 95c84f3f3cSopenharmony_ci /* character flag (if any) */ \ 96c84f3f3cSopenharmony_ci char c; \ 97c84f3f3cSopenharmony_ci /* OF_* */ \ 98c84f3f3cSopenharmony_ci unsigned char optflags; \ 99c84f3f3cSopenharmony_ci /* long name of option */ \ 100c84f3f3cSopenharmony_ci char name[sizeof(sname)]; \ 101c84f3f3cSopenharmony_ci } shoptione_ ## cname = { \ 102c84f3f3cSopenharmony_ci ochar, flags, sname \ 103c84f3f3cSopenharmony_ci }; 104c84f3f3cSopenharmony_ci#include "sh_flags.gen" 105c84f3f3cSopenharmony_ci 106c84f3f3cSopenharmony_ci#define OFC(i) (options[i][-2]) 107c84f3f3cSopenharmony_ci#define OFF(i) (((const unsigned char *)options[i])[-1]) 108c84f3f3cSopenharmony_ci#define OFN(i) (options[i]) 109c84f3f3cSopenharmony_ci 110c84f3f3cSopenharmony_ciconst char * const options[] = { 111c84f3f3cSopenharmony_ci#define SHFLAGS_ITEMS 112c84f3f3cSopenharmony_ci#include "sh_flags.gen" 113c84f3f3cSopenharmony_ci}; 114c84f3f3cSopenharmony_ci 115c84f3f3cSopenharmony_ci/* 116c84f3f3cSopenharmony_ci * translate -o option into F* constant (also used for test -o option) 117c84f3f3cSopenharmony_ci */ 118c84f3f3cSopenharmony_cisize_t 119c84f3f3cSopenharmony_cioption(const char *n) 120c84f3f3cSopenharmony_ci{ 121c84f3f3cSopenharmony_ci size_t i = 0; 122c84f3f3cSopenharmony_ci 123c84f3f3cSopenharmony_ci if (ctype(n[0], C_MINUS | C_PLUS) && n[1] && !n[2]) 124c84f3f3cSopenharmony_ci while (i < NELEM(options)) { 125c84f3f3cSopenharmony_ci if (OFC(i) == n[1]) 126c84f3f3cSopenharmony_ci return (i); 127c84f3f3cSopenharmony_ci ++i; 128c84f3f3cSopenharmony_ci } 129c84f3f3cSopenharmony_ci else 130c84f3f3cSopenharmony_ci while (i < NELEM(options)) { 131c84f3f3cSopenharmony_ci if (!strcmp(OFN(i), n)) 132c84f3f3cSopenharmony_ci return (i); 133c84f3f3cSopenharmony_ci ++i; 134c84f3f3cSopenharmony_ci } 135c84f3f3cSopenharmony_ci 136c84f3f3cSopenharmony_ci return ((size_t)-1); 137c84f3f3cSopenharmony_ci} 138c84f3f3cSopenharmony_ci 139c84f3f3cSopenharmony_cistruct options_info { 140c84f3f3cSopenharmony_ci int opt_width; 141c84f3f3cSopenharmony_ci int opts[NELEM(options)]; 142c84f3f3cSopenharmony_ci}; 143c84f3f3cSopenharmony_ci 144c84f3f3cSopenharmony_cistatic void options_fmt_entry(char *, size_t, unsigned int, const void *); 145c84f3f3cSopenharmony_cistatic int printoptions(bool); 146c84f3f3cSopenharmony_cistatic int printoption(size_t); 147c84f3f3cSopenharmony_ci 148c84f3f3cSopenharmony_ci/* format a single select menu item */ 149c84f3f3cSopenharmony_cistatic void 150c84f3f3cSopenharmony_cioptions_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg) 151c84f3f3cSopenharmony_ci{ 152c84f3f3cSopenharmony_ci const struct options_info *oi = (const struct options_info *)arg; 153c84f3f3cSopenharmony_ci 154c84f3f3cSopenharmony_ci shf_snprintf(buf, buflen, "%-*s %s", 155c84f3f3cSopenharmony_ci oi->opt_width, OFN(oi->opts[i]), 156c84f3f3cSopenharmony_ci Flag(oi->opts[i]) ? "on" : "off"); 157c84f3f3cSopenharmony_ci} 158c84f3f3cSopenharmony_ci 159c84f3f3cSopenharmony_cistatic int 160c84f3f3cSopenharmony_ciprintoption(size_t i) 161c84f3f3cSopenharmony_ci{ 162c84f3f3cSopenharmony_ci if (Flag(i) == baseline_flags[i]) 163c84f3f3cSopenharmony_ci return (0); 164c84f3f3cSopenharmony_ci if (!OFN(i)[0]) { 165c84f3f3cSopenharmony_ci#if !defined(MKSH_SMALL) || defined(DEBUG) 166c84f3f3cSopenharmony_ci bi_errorf(Tf_sd, "change in unnamed option", (int)i); 167c84f3f3cSopenharmony_ci#endif 168c84f3f3cSopenharmony_ci return (1); 169c84f3f3cSopenharmony_ci } 170c84f3f3cSopenharmony_ci if (Flag(i) != 0 && Flag(i) != 1) { 171c84f3f3cSopenharmony_ci#if !defined(MKSH_SMALL) || defined(DEBUG) 172c84f3f3cSopenharmony_ci bi_errorf(Tf_s_sD_s, Tdo, OFN(i), "not 0 or 1"); 173c84f3f3cSopenharmony_ci#endif 174c84f3f3cSopenharmony_ci return (1); 175c84f3f3cSopenharmony_ci } 176c84f3f3cSopenharmony_ci shprintf(Tf__s_s, Flag(i) ? Tdo : Tpo, OFN(i)); 177c84f3f3cSopenharmony_ci return (0); 178c84f3f3cSopenharmony_ci} 179c84f3f3cSopenharmony_ci 180c84f3f3cSopenharmony_cistatic int 181c84f3f3cSopenharmony_ciprintoptions(bool verbose) 182c84f3f3cSopenharmony_ci{ 183c84f3f3cSopenharmony_ci size_t i = 0; 184c84f3f3cSopenharmony_ci int rv = 0; 185c84f3f3cSopenharmony_ci 186c84f3f3cSopenharmony_ci if (verbose) { 187c84f3f3cSopenharmony_ci size_t n = 0, len, octs = 0; 188c84f3f3cSopenharmony_ci struct options_info oi; 189c84f3f3cSopenharmony_ci struct columnise_opts co; 190c84f3f3cSopenharmony_ci 191c84f3f3cSopenharmony_ci /* verbose version */ 192c84f3f3cSopenharmony_ci shf_puts("Current option settings\n", shl_stdout); 193c84f3f3cSopenharmony_ci 194c84f3f3cSopenharmony_ci oi.opt_width = 0; 195c84f3f3cSopenharmony_ci while (i < NELEM(options)) { 196c84f3f3cSopenharmony_ci if ((len = strlen(OFN(i)))) { 197c84f3f3cSopenharmony_ci oi.opts[n++] = i; 198c84f3f3cSopenharmony_ci if (len > octs) 199c84f3f3cSopenharmony_ci octs = len; 200c84f3f3cSopenharmony_ci len = utf_mbswidth(OFN(i)); 201c84f3f3cSopenharmony_ci if ((int)len > oi.opt_width) 202c84f3f3cSopenharmony_ci oi.opt_width = (int)len; 203c84f3f3cSopenharmony_ci } 204c84f3f3cSopenharmony_ci ++i; 205c84f3f3cSopenharmony_ci } 206c84f3f3cSopenharmony_ci co.shf = shl_stdout; 207c84f3f3cSopenharmony_ci co.linesep = '\n'; 208c84f3f3cSopenharmony_ci co.prefcol = co.do_last = true; 209c84f3f3cSopenharmony_ci print_columns(&co, n, options_fmt_entry, &oi, 210c84f3f3cSopenharmony_ci octs + 4, oi.opt_width + 4); 211c84f3f3cSopenharmony_ci } else { 212c84f3f3cSopenharmony_ci /* short version like AT&T ksh93 */ 213c84f3f3cSopenharmony_ci shf_puts(Tset, shl_stdout); 214c84f3f3cSopenharmony_ci shf_puts(To_o_reset, shl_stdout); 215c84f3f3cSopenharmony_ci printoption(FSH); 216c84f3f3cSopenharmony_ci printoption(FPOSIX); 217c84f3f3cSopenharmony_ci while (i < FNFLAGS) { 218c84f3f3cSopenharmony_ci if (i != FSH && i != FPOSIX) 219c84f3f3cSopenharmony_ci rv |= printoption(i); 220c84f3f3cSopenharmony_ci ++i; 221c84f3f3cSopenharmony_ci } 222c84f3f3cSopenharmony_ci shf_putc('\n', shl_stdout); 223c84f3f3cSopenharmony_ci } 224c84f3f3cSopenharmony_ci return (rv); 225c84f3f3cSopenharmony_ci} 226c84f3f3cSopenharmony_ci 227c84f3f3cSopenharmony_cichar * 228c84f3f3cSopenharmony_cigetoptions(void) 229c84f3f3cSopenharmony_ci{ 230c84f3f3cSopenharmony_ci size_t i = 0; 231c84f3f3cSopenharmony_ci char c, m[(int)FNFLAGS + 1]; 232c84f3f3cSopenharmony_ci char *cp = m; 233c84f3f3cSopenharmony_ci 234c84f3f3cSopenharmony_ci while (i < NELEM(options)) { 235c84f3f3cSopenharmony_ci if ((c = OFC(i)) && Flag(i)) 236c84f3f3cSopenharmony_ci *cp++ = c; 237c84f3f3cSopenharmony_ci ++i; 238c84f3f3cSopenharmony_ci } 239c84f3f3cSopenharmony_ci strndupx(cp, m, cp - m, ATEMP); 240c84f3f3cSopenharmony_ci return (cp); 241c84f3f3cSopenharmony_ci} 242c84f3f3cSopenharmony_ci 243c84f3f3cSopenharmony_ci/* change a Flag(*) value; takes care of special actions */ 244c84f3f3cSopenharmony_civoid 245c84f3f3cSopenharmony_cichange_flag(enum sh_flag f, int what, bool newset) 246c84f3f3cSopenharmony_ci{ 247c84f3f3cSopenharmony_ci unsigned char oldval = Flag(f); 248c84f3f3cSopenharmony_ci unsigned char newval = (newset ? 1 : 0); 249c84f3f3cSopenharmony_ci 250c84f3f3cSopenharmony_ci if (f == FXTRACE) { 251c84f3f3cSopenharmony_ci change_xtrace(newval, true); 252c84f3f3cSopenharmony_ci return; 253c84f3f3cSopenharmony_ci } else if (f == FPRIVILEGED) { 254c84f3f3cSopenharmony_ci if (!oldval) 255c84f3f3cSopenharmony_ci /* no getting back dropped privs */ 256c84f3f3cSopenharmony_ci return; 257c84f3f3cSopenharmony_ci else if (!newval) { 258c84f3f3cSopenharmony_ci /* turning off -p */ 259c84f3f3cSopenharmony_ci kshegid = kshgid; 260c84f3f3cSopenharmony_ci ksheuid = kshuid; 261c84f3f3cSopenharmony_ci } else if (oldval != 3) 262c84f3f3cSopenharmony_ci /* nor going full sugid */ 263c84f3f3cSopenharmony_ci goto change_flag; 264c84f3f3cSopenharmony_ci 265c84f3f3cSopenharmony_ci /* +++ set group IDs +++ */ 266c84f3f3cSopenharmony_ci#if HAVE_SETRESUGID 267c84f3f3cSopenharmony_ci DO_SETUID(setresgid, (kshegid, kshegid, kshgid)); 268c84f3f3cSopenharmony_ci#else /* !HAVE_SETRESUGID */ 269c84f3f3cSopenharmony_ci /* setgid, setegid don't EAGAIN on Linux */ 270c84f3f3cSopenharmony_ci setgid(kshegid); 271c84f3f3cSopenharmony_ci#ifndef MKSH__NO_SETEUGID 272c84f3f3cSopenharmony_ci setegid(kshegid); 273c84f3f3cSopenharmony_ci#endif /* !MKSH__NO_SETEUGID */ 274c84f3f3cSopenharmony_ci#endif /* !HAVE_SETRESUGID */ 275c84f3f3cSopenharmony_ci 276c84f3f3cSopenharmony_ci /* +++ wipe groups vector +++ */ 277c84f3f3cSopenharmony_ci#if HAVE_SETGROUPS 278c84f3f3cSopenharmony_ci /* setgroups doesn't EAGAIN on Linux */ 279c84f3f3cSopenharmony_ci setgroups(0, NULL); 280c84f3f3cSopenharmony_ci#endif /* HAVE_SETGROUPS */ 281c84f3f3cSopenharmony_ci 282c84f3f3cSopenharmony_ci /* +++ set user IDs +++ */ 283c84f3f3cSopenharmony_ci#if HAVE_SETRESUGID 284c84f3f3cSopenharmony_ci DO_SETUID(setresuid, (ksheuid, ksheuid, kshuid)); 285c84f3f3cSopenharmony_ci#else /* !HAVE_SETRESUGID */ 286c84f3f3cSopenharmony_ci /* seteuid doesn't EAGAIN on Linux */ 287c84f3f3cSopenharmony_ci DO_SETUID(setuid, (ksheuid)); 288c84f3f3cSopenharmony_ci#ifndef MKSH__NO_SETEUGID 289c84f3f3cSopenharmony_ci seteuid(ksheuid); 290c84f3f3cSopenharmony_ci#endif /* !MKSH__NO_SETEUGID */ 291c84f3f3cSopenharmony_ci#endif /* !HAVE_SETRESUGID */ 292c84f3f3cSopenharmony_ci 293c84f3f3cSopenharmony_ci /* +++ privs changed +++ */ 294c84f3f3cSopenharmony_ci } else if ((f == FPOSIX || f == FSH) && newval) { 295c84f3f3cSopenharmony_ci /* Turning on -o posix? */ 296c84f3f3cSopenharmony_ci if (f == FPOSIX) 297c84f3f3cSopenharmony_ci /* C locale required for compliance */ 298c84f3f3cSopenharmony_ci UTFMODE = 0; 299c84f3f3cSopenharmony_ci /* Turning on -o posix or -o sh? */ 300c84f3f3cSopenharmony_ci Flag(FBRACEEXPAND) = 0; 301c84f3f3cSopenharmony_ci#ifndef MKSH_NO_CMDLINE_EDITING 302c84f3f3cSopenharmony_ci } else if ((f == FEMACS || 303c84f3f3cSopenharmony_ci#if !MKSH_S_NOVI 304c84f3f3cSopenharmony_ci f == FVI || 305c84f3f3cSopenharmony_ci#endif 306c84f3f3cSopenharmony_ci f == FGMACS) && newval) { 307c84f3f3cSopenharmony_ci#if !MKSH_S_NOVI 308c84f3f3cSopenharmony_ci Flag(FVI) = 0; 309c84f3f3cSopenharmony_ci#endif 310c84f3f3cSopenharmony_ci Flag(FEMACS) = Flag(FGMACS) = 0; 311c84f3f3cSopenharmony_ci#endif 312c84f3f3cSopenharmony_ci } 313c84f3f3cSopenharmony_ci 314c84f3f3cSopenharmony_ci change_flag: 315c84f3f3cSopenharmony_ci Flag(f) = newval; 316c84f3f3cSopenharmony_ci 317c84f3f3cSopenharmony_ci if (f == FTALKING) { 318c84f3f3cSopenharmony_ci /* Changing interactive flag? */ 319c84f3f3cSopenharmony_ci if ((what == OF_CMDLINE || what == OF_SET) && procpid == kshpid) 320c84f3f3cSopenharmony_ci Flag(FTALKING_I) = newval; 321c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 322c84f3f3cSopenharmony_ci } else if (f == FMONITOR) { 323c84f3f3cSopenharmony_ci if (what != OF_CMDLINE && newval != oldval) 324c84f3f3cSopenharmony_ci j_change(); 325c84f3f3cSopenharmony_ci#endif 326c84f3f3cSopenharmony_ci } 327c84f3f3cSopenharmony_ci} 328c84f3f3cSopenharmony_ci 329c84f3f3cSopenharmony_civoid 330c84f3f3cSopenharmony_cichange_xtrace(unsigned char newval, bool dosnapshot) 331c84f3f3cSopenharmony_ci{ 332c84f3f3cSopenharmony_ci static bool in_xtrace; 333c84f3f3cSopenharmony_ci 334c84f3f3cSopenharmony_ci if (in_xtrace) 335c84f3f3cSopenharmony_ci return; 336c84f3f3cSopenharmony_ci 337c84f3f3cSopenharmony_ci if (!dosnapshot && newval == Flag(FXTRACE)) 338c84f3f3cSopenharmony_ci return; 339c84f3f3cSopenharmony_ci 340c84f3f3cSopenharmony_ci if (Flag(FXTRACE) == 2) { 341c84f3f3cSopenharmony_ci shf_putc('\n', shl_xtrace); 342c84f3f3cSopenharmony_ci Flag(FXTRACE) = 1; 343c84f3f3cSopenharmony_ci shf_flush(shl_xtrace); 344c84f3f3cSopenharmony_ci } 345c84f3f3cSopenharmony_ci 346c84f3f3cSopenharmony_ci if (!dosnapshot && Flag(FXTRACE) == 1) 347c84f3f3cSopenharmony_ci switch (newval) { 348c84f3f3cSopenharmony_ci case 1: 349c84f3f3cSopenharmony_ci return; 350c84f3f3cSopenharmony_ci case 2: 351c84f3f3cSopenharmony_ci goto changed_xtrace; 352c84f3f3cSopenharmony_ci } 353c84f3f3cSopenharmony_ci 354c84f3f3cSopenharmony_ci shf_flush(shl_xtrace); 355c84f3f3cSopenharmony_ci if (shl_xtrace->fd != 2) 356c84f3f3cSopenharmony_ci close(shl_xtrace->fd); 357c84f3f3cSopenharmony_ci if (!newval || (shl_xtrace->fd = savefd(2)) == -1) 358c84f3f3cSopenharmony_ci shl_xtrace->fd = 2; 359c84f3f3cSopenharmony_ci 360c84f3f3cSopenharmony_ci changed_xtrace: 361c84f3f3cSopenharmony_ci if ((Flag(FXTRACE) = newval) == 2) { 362c84f3f3cSopenharmony_ci in_xtrace = true; 363c84f3f3cSopenharmony_ci Flag(FXTRACE) = 0; 364c84f3f3cSopenharmony_ci shf_puts(substitute(str_val(global("PS4")), 0), shl_xtrace); 365c84f3f3cSopenharmony_ci Flag(FXTRACE) = 2; 366c84f3f3cSopenharmony_ci in_xtrace = false; 367c84f3f3cSopenharmony_ci } 368c84f3f3cSopenharmony_ci} 369c84f3f3cSopenharmony_ci 370c84f3f3cSopenharmony_ci/* 371c84f3f3cSopenharmony_ci * Parse command line and set command arguments. Returns the index of 372c84f3f3cSopenharmony_ci * non-option arguments, -1 if there is an error. 373c84f3f3cSopenharmony_ci */ 374c84f3f3cSopenharmony_ciint 375c84f3f3cSopenharmony_ciparse_args(const char **argv, 376c84f3f3cSopenharmony_ci /* OF_FIRSTTIME, OF_CMDLINE, or OF_SET */ 377c84f3f3cSopenharmony_ci int what, 378c84f3f3cSopenharmony_ci bool *setargsp) 379c84f3f3cSopenharmony_ci{ 380c84f3f3cSopenharmony_ci static const char cmd_opts[] = 381c84f3f3cSopenharmony_ci#define SHFLAGS_NOT_SET 382c84f3f3cSopenharmony_ci#define SHFLAGS_OPTCS 383c84f3f3cSopenharmony_ci#include "sh_flags.gen" 384c84f3f3cSopenharmony_ci#undef SHFLAGS_NOT_SET 385c84f3f3cSopenharmony_ci ; 386c84f3f3cSopenharmony_ci static const char set_opts[] = 387c84f3f3cSopenharmony_ci#define SHFLAGS_NOT_CMD 388c84f3f3cSopenharmony_ci#define SHFLAGS_OPTCS 389c84f3f3cSopenharmony_ci#include "sh_flags.gen" 390c84f3f3cSopenharmony_ci#undef SHFLAGS_NOT_CMD 391c84f3f3cSopenharmony_ci ; 392c84f3f3cSopenharmony_ci bool set; 393c84f3f3cSopenharmony_ci const char *opts = what == OF_CMDLINE || what == OF_FIRSTTIME ? 394c84f3f3cSopenharmony_ci cmd_opts : set_opts; 395c84f3f3cSopenharmony_ci const char *array = NULL; 396c84f3f3cSopenharmony_ci Getopt go; 397c84f3f3cSopenharmony_ci size_t i; 398c84f3f3cSopenharmony_ci int optc, arrayset = 0; 399c84f3f3cSopenharmony_ci bool sortargs = false; 400c84f3f3cSopenharmony_ci bool fcompatseen = false; 401c84f3f3cSopenharmony_ci 402c84f3f3cSopenharmony_ci ksh_getopt_reset(&go, GF_ERROR|GF_PLUSOPT); 403c84f3f3cSopenharmony_ci while ((optc = ksh_getopt(argv, &go, opts)) != -1) { 404c84f3f3cSopenharmony_ci set = tobool(!(go.info & GI_PLUS)); 405c84f3f3cSopenharmony_ci switch (optc) { 406c84f3f3cSopenharmony_ci case 'A': 407c84f3f3cSopenharmony_ci if (what == OF_FIRSTTIME) 408c84f3f3cSopenharmony_ci break; 409c84f3f3cSopenharmony_ci arrayset = set ? 1 : -1; 410c84f3f3cSopenharmony_ci array = go.optarg; 411c84f3f3cSopenharmony_ci break; 412c84f3f3cSopenharmony_ci 413c84f3f3cSopenharmony_ci case 'o': 414c84f3f3cSopenharmony_ci if (what == OF_FIRSTTIME) 415c84f3f3cSopenharmony_ci break; 416c84f3f3cSopenharmony_ci if (go.optarg == NULL) { 417c84f3f3cSopenharmony_ci /* 418c84f3f3cSopenharmony_ci * lone -o: print options 419c84f3f3cSopenharmony_ci * 420c84f3f3cSopenharmony_ci * Note that on the command line, -o requires 421c84f3f3cSopenharmony_ci * an option (ie, can't get here if what is 422c84f3f3cSopenharmony_ci * OF_CMDLINE). 423c84f3f3cSopenharmony_ci */ 424c84f3f3cSopenharmony_ci#if !defined(MKSH_SMALL) || defined(DEBUG) 425c84f3f3cSopenharmony_ci if (!set && !baseline_flags[(int)FNFLAGS]) { 426c84f3f3cSopenharmony_ci bi_errorf(Tf_s_s, "too early", 427c84f3f3cSopenharmony_ci Tset_po); 428c84f3f3cSopenharmony_ci return (-1); 429c84f3f3cSopenharmony_ci } 430c84f3f3cSopenharmony_ci#endif 431c84f3f3cSopenharmony_ci if (printoptions(set)) 432c84f3f3cSopenharmony_ci return (-1); 433c84f3f3cSopenharmony_ci break; 434c84f3f3cSopenharmony_ci } 435c84f3f3cSopenharmony_ci i = option(go.optarg); 436c84f3f3cSopenharmony_ci if ((i == FPOSIX || i == FSH) && set && !fcompatseen) { 437c84f3f3cSopenharmony_ci /* 438c84f3f3cSopenharmony_ci * If running 'set -o posix' or 439c84f3f3cSopenharmony_ci * 'set -o sh', turn off the other; 440c84f3f3cSopenharmony_ci * if running 'set -o posix -o sh' 441c84f3f3cSopenharmony_ci * allow both to be set though. 442c84f3f3cSopenharmony_ci */ 443c84f3f3cSopenharmony_ci Flag(FPOSIX) = 0; 444c84f3f3cSopenharmony_ci Flag(FSH) = 0; 445c84f3f3cSopenharmony_ci fcompatseen = true; 446c84f3f3cSopenharmony_ci } 447c84f3f3cSopenharmony_ci if ((i != (size_t)-1) && (set ? 1U : 0U) == Flag(i)) 448c84f3f3cSopenharmony_ci /* 449c84f3f3cSopenharmony_ci * Don't check the context if the flag 450c84f3f3cSopenharmony_ci * isn't changing - makes "set -o interactive" 451c84f3f3cSopenharmony_ci * work if you're already interactive. Needed 452c84f3f3cSopenharmony_ci * if the output of "set +o" is to be used. 453c84f3f3cSopenharmony_ci */ 454c84f3f3cSopenharmony_ci ; 455c84f3f3cSopenharmony_ci else if ((i != (size_t)-1) && (OFF(i) & what)) 456c84f3f3cSopenharmony_ci change_flag((enum sh_flag)i, what, set); 457c84f3f3cSopenharmony_ci else if (!strcmp(go.optarg, To_reset)) { 458c84f3f3cSopenharmony_ci#if !defined(MKSH_SMALL) || defined(DEBUG) 459c84f3f3cSopenharmony_ci if (!baseline_flags[(int)FNFLAGS]) { 460c84f3f3cSopenharmony_ci bi_errorf(Tf_ss, "too early", 461c84f3f3cSopenharmony_ci To_o_reset); 462c84f3f3cSopenharmony_ci return (-1); 463c84f3f3cSopenharmony_ci } 464c84f3f3cSopenharmony_ci#endif 465c84f3f3cSopenharmony_ci /* 466c84f3f3cSopenharmony_ci * ordering, with respect to side effects, 467c84f3f3cSopenharmony_ci * was ensured above by printoptions 468c84f3f3cSopenharmony_ci */ 469c84f3f3cSopenharmony_ci for (i = 0; i < FNFLAGS; ++i) 470c84f3f3cSopenharmony_ci if (Flag(i) != baseline_flags[i]) 471c84f3f3cSopenharmony_ci change_flag((enum sh_flag)i, 472c84f3f3cSopenharmony_ci what, baseline_flags[i]); 473c84f3f3cSopenharmony_ci } else { 474c84f3f3cSopenharmony_ci bi_errorf(Tf_sD_s, go.optarg, 475c84f3f3cSopenharmony_ci Tunknown_option); 476c84f3f3cSopenharmony_ci return (-1); 477c84f3f3cSopenharmony_ci } 478c84f3f3cSopenharmony_ci break; 479c84f3f3cSopenharmony_ci 480c84f3f3cSopenharmony_ci#ifdef KSH_CHVT_FLAG 481c84f3f3cSopenharmony_ci case 'T': 482c84f3f3cSopenharmony_ci if (what != OF_FIRSTTIME) 483c84f3f3cSopenharmony_ci break; 484c84f3f3cSopenharmony_ci#ifndef KSH_CHVT_CODE 485c84f3f3cSopenharmony_ci errorf("no TIOCSCTTY ioctl"); 486c84f3f3cSopenharmony_ci#else 487c84f3f3cSopenharmony_ci change_flag(FTALKING, OF_CMDLINE, true); 488c84f3f3cSopenharmony_ci chvt(&go); 489c84f3f3cSopenharmony_ci break; 490c84f3f3cSopenharmony_ci#endif 491c84f3f3cSopenharmony_ci#endif 492c84f3f3cSopenharmony_ci 493c84f3f3cSopenharmony_ci case '?': 494c84f3f3cSopenharmony_ci return (-1); 495c84f3f3cSopenharmony_ci 496c84f3f3cSopenharmony_ci default: 497c84f3f3cSopenharmony_ci if (what == OF_FIRSTTIME) 498c84f3f3cSopenharmony_ci break; 499c84f3f3cSopenharmony_ci /* -s: sort positional params (AT&T ksh stupidity) */ 500c84f3f3cSopenharmony_ci if (what == OF_SET && optc == 's') { 501c84f3f3cSopenharmony_ci sortargs = true; 502c84f3f3cSopenharmony_ci break; 503c84f3f3cSopenharmony_ci } 504c84f3f3cSopenharmony_ci for (i = 0; i < NELEM(options); i++) 505c84f3f3cSopenharmony_ci if (optc == OFC(i) && 506c84f3f3cSopenharmony_ci (what & OFF(i))) { 507c84f3f3cSopenharmony_ci change_flag((enum sh_flag)i, what, set); 508c84f3f3cSopenharmony_ci break; 509c84f3f3cSopenharmony_ci } 510c84f3f3cSopenharmony_ci if (i == NELEM(options)) 511c84f3f3cSopenharmony_ci internal_errorf("parse_args: '%c'", optc); 512c84f3f3cSopenharmony_ci } 513c84f3f3cSopenharmony_ci } 514c84f3f3cSopenharmony_ci if (!(go.info & GI_MINUSMINUS) && argv[go.optind] && 515c84f3f3cSopenharmony_ci ctype(argv[go.optind][0], C_MINUS | C_PLUS) && 516c84f3f3cSopenharmony_ci argv[go.optind][1] == '\0') { 517c84f3f3cSopenharmony_ci /* lone - clears -v and -x flags */ 518c84f3f3cSopenharmony_ci if (argv[go.optind][0] == '-') { 519c84f3f3cSopenharmony_ci Flag(FVERBOSE) = 0; 520c84f3f3cSopenharmony_ci change_xtrace(0, false); 521c84f3f3cSopenharmony_ci } 522c84f3f3cSopenharmony_ci /* set skips lone - or + option */ 523c84f3f3cSopenharmony_ci go.optind++; 524c84f3f3cSopenharmony_ci } 525c84f3f3cSopenharmony_ci if (setargsp) 526c84f3f3cSopenharmony_ci /* -- means set $#/$* even if there are no arguments */ 527c84f3f3cSopenharmony_ci *setargsp = !arrayset && ((go.info & GI_MINUSMINUS) || 528c84f3f3cSopenharmony_ci argv[go.optind]); 529c84f3f3cSopenharmony_ci 530c84f3f3cSopenharmony_ci if (arrayset) { 531c84f3f3cSopenharmony_ci const char *ccp = NULL; 532c84f3f3cSopenharmony_ci 533c84f3f3cSopenharmony_ci if (array && *array) 534c84f3f3cSopenharmony_ci ccp = skip_varname(array, false); 535c84f3f3cSopenharmony_ci if (!ccp || !(!ccp[0] || (ccp[0] == '+' && !ccp[1]))) { 536c84f3f3cSopenharmony_ci bi_errorf(Tf_sD_s, array, Tnot_ident); 537c84f3f3cSopenharmony_ci return (-1); 538c84f3f3cSopenharmony_ci } 539c84f3f3cSopenharmony_ci } 540c84f3f3cSopenharmony_ci if (sortargs) { 541c84f3f3cSopenharmony_ci for (i = go.optind; argv[i]; i++) 542c84f3f3cSopenharmony_ci ; 543c84f3f3cSopenharmony_ci qsort(&argv[go.optind], i - go.optind, sizeof(void *), 544c84f3f3cSopenharmony_ci ascpstrcmp); 545c84f3f3cSopenharmony_ci } 546c84f3f3cSopenharmony_ci if (arrayset) 547c84f3f3cSopenharmony_ci go.optind += set_array(array, tobool(arrayset > 0), 548c84f3f3cSopenharmony_ci argv + go.optind); 549c84f3f3cSopenharmony_ci 550c84f3f3cSopenharmony_ci return (go.optind); 551c84f3f3cSopenharmony_ci} 552c84f3f3cSopenharmony_ci 553c84f3f3cSopenharmony_ci/* parse a decimal number: returns 0 if string isn't a number, 1 otherwise */ 554c84f3f3cSopenharmony_ciint 555c84f3f3cSopenharmony_cigetn(const char *s, int *ai) 556c84f3f3cSopenharmony_ci{ 557c84f3f3cSopenharmony_ci char c; 558c84f3f3cSopenharmony_ci mksh_ari_u num; 559c84f3f3cSopenharmony_ci bool neg = false; 560c84f3f3cSopenharmony_ci 561c84f3f3cSopenharmony_ci num.u = 0; 562c84f3f3cSopenharmony_ci 563c84f3f3cSopenharmony_ci do { 564c84f3f3cSopenharmony_ci c = *s++; 565c84f3f3cSopenharmony_ci } while (ctype(c, C_SPACE)); 566c84f3f3cSopenharmony_ci 567c84f3f3cSopenharmony_ci switch (c) { 568c84f3f3cSopenharmony_ci case '-': 569c84f3f3cSopenharmony_ci neg = true; 570c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 571c84f3f3cSopenharmony_ci case '+': 572c84f3f3cSopenharmony_ci c = *s++; 573c84f3f3cSopenharmony_ci break; 574c84f3f3cSopenharmony_ci } 575c84f3f3cSopenharmony_ci 576c84f3f3cSopenharmony_ci do { 577c84f3f3cSopenharmony_ci if (!ctype(c, C_DIGIT)) 578c84f3f3cSopenharmony_ci /* not numeric */ 579c84f3f3cSopenharmony_ci return (0); 580c84f3f3cSopenharmony_ci if (num.u > 214748364U) 581c84f3f3cSopenharmony_ci /* overflow on multiplication */ 582c84f3f3cSopenharmony_ci return (0); 583c84f3f3cSopenharmony_ci num.u = num.u * 10U + (unsigned int)ksh_numdig(c); 584c84f3f3cSopenharmony_ci /* now: num.u <= 2147483649U */ 585c84f3f3cSopenharmony_ci } while ((c = *s++)); 586c84f3f3cSopenharmony_ci 587c84f3f3cSopenharmony_ci if (num.u > (neg ? 2147483648U : 2147483647U)) 588c84f3f3cSopenharmony_ci /* overflow for signed 32-bit int */ 589c84f3f3cSopenharmony_ci return (0); 590c84f3f3cSopenharmony_ci 591c84f3f3cSopenharmony_ci if (neg) 592c84f3f3cSopenharmony_ci num.u = -num.u; 593c84f3f3cSopenharmony_ci *ai = num.i; 594c84f3f3cSopenharmony_ci return (1); 595c84f3f3cSopenharmony_ci} 596c84f3f3cSopenharmony_ci 597c84f3f3cSopenharmony_ci/** 598c84f3f3cSopenharmony_ci * pattern simplifications: 599c84f3f3cSopenharmony_ci * - @(x) -> x (not @(x|y) though) 600c84f3f3cSopenharmony_ci * - ** -> * 601c84f3f3cSopenharmony_ci */ 602c84f3f3cSopenharmony_cistatic void * 603c84f3f3cSopenharmony_cisimplify_gmatch_pattern(const unsigned char *sp) 604c84f3f3cSopenharmony_ci{ 605c84f3f3cSopenharmony_ci uint8_t c; 606c84f3f3cSopenharmony_ci unsigned char *cp, *dp; 607c84f3f3cSopenharmony_ci const unsigned char *ps, *se; 608c84f3f3cSopenharmony_ci 609c84f3f3cSopenharmony_ci cp = alloc(strlen((const void *)sp) + 1, ATEMP); 610c84f3f3cSopenharmony_ci goto simplify_gmatch_pat1a; 611c84f3f3cSopenharmony_ci 612c84f3f3cSopenharmony_ci /* foo@(b@(a)r)b@(a|a)z -> foobarb@(a|a)z */ 613c84f3f3cSopenharmony_ci simplify_gmatch_pat1: 614c84f3f3cSopenharmony_ci sp = cp; 615c84f3f3cSopenharmony_ci simplify_gmatch_pat1a: 616c84f3f3cSopenharmony_ci dp = cp; 617c84f3f3cSopenharmony_ci se = strnul(sp); 618c84f3f3cSopenharmony_ci while ((c = *sp++)) { 619c84f3f3cSopenharmony_ci if (!ISMAGIC(c)) { 620c84f3f3cSopenharmony_ci *dp++ = c; 621c84f3f3cSopenharmony_ci continue; 622c84f3f3cSopenharmony_ci } 623c84f3f3cSopenharmony_ci switch ((c = *sp++)) { 624c84f3f3cSopenharmony_ci case 0x80|'@': 625c84f3f3cSopenharmony_ci /* simile for @ */ 626c84f3f3cSopenharmony_ci case 0x80|' ': 627c84f3f3cSopenharmony_ci /* check whether it has only one clause */ 628c84f3f3cSopenharmony_ci ps = pat_scan(sp, se, true); 629c84f3f3cSopenharmony_ci if (!ps || ps[-1] != /*(*/ ')') 630c84f3f3cSopenharmony_ci /* nope */ 631c84f3f3cSopenharmony_ci break; 632c84f3f3cSopenharmony_ci /* copy inner clause until matching close */ 633c84f3f3cSopenharmony_ci ps -= 2; 634c84f3f3cSopenharmony_ci while ((const unsigned char *)sp < ps) 635c84f3f3cSopenharmony_ci *dp++ = *sp++; 636c84f3f3cSopenharmony_ci /* skip MAGIC and closing parenthesis */ 637c84f3f3cSopenharmony_ci sp += 2; 638c84f3f3cSopenharmony_ci /* copy the rest of the pattern */ 639c84f3f3cSopenharmony_ci memmove(dp, sp, strlen((const void *)sp) + 1); 640c84f3f3cSopenharmony_ci /* redo from start */ 641c84f3f3cSopenharmony_ci goto simplify_gmatch_pat1; 642c84f3f3cSopenharmony_ci } 643c84f3f3cSopenharmony_ci *dp++ = MAGIC; 644c84f3f3cSopenharmony_ci *dp++ = c; 645c84f3f3cSopenharmony_ci } 646c84f3f3cSopenharmony_ci *dp = '\0'; 647c84f3f3cSopenharmony_ci 648c84f3f3cSopenharmony_ci /* collapse adjacent asterisk wildcards */ 649c84f3f3cSopenharmony_ci sp = dp = cp; 650c84f3f3cSopenharmony_ci while ((c = *sp++)) { 651c84f3f3cSopenharmony_ci if (!ISMAGIC(c)) { 652c84f3f3cSopenharmony_ci *dp++ = c; 653c84f3f3cSopenharmony_ci continue; 654c84f3f3cSopenharmony_ci } 655c84f3f3cSopenharmony_ci switch ((c = *sp++)) { 656c84f3f3cSopenharmony_ci case '*': 657c84f3f3cSopenharmony_ci while (ISMAGIC(sp[0]) && sp[1] == c) 658c84f3f3cSopenharmony_ci sp += 2; 659c84f3f3cSopenharmony_ci break; 660c84f3f3cSopenharmony_ci } 661c84f3f3cSopenharmony_ci *dp++ = MAGIC; 662c84f3f3cSopenharmony_ci *dp++ = c; 663c84f3f3cSopenharmony_ci } 664c84f3f3cSopenharmony_ci *dp = '\0'; 665c84f3f3cSopenharmony_ci 666c84f3f3cSopenharmony_ci /* return the result, allocated from ATEMP */ 667c84f3f3cSopenharmony_ci return (cp); 668c84f3f3cSopenharmony_ci} 669c84f3f3cSopenharmony_ci 670c84f3f3cSopenharmony_ci/* -------- gmatch.c -------- */ 671c84f3f3cSopenharmony_ci 672c84f3f3cSopenharmony_ci/* 673c84f3f3cSopenharmony_ci * int gmatch(string, pattern) 674c84f3f3cSopenharmony_ci * char *string, *pattern; 675c84f3f3cSopenharmony_ci * 676c84f3f3cSopenharmony_ci * Match a pattern as in sh(1). 677c84f3f3cSopenharmony_ci * pattern character are prefixed with MAGIC by expand. 678c84f3f3cSopenharmony_ci */ 679c84f3f3cSopenharmony_ciint 680c84f3f3cSopenharmony_cigmatchx(const char *s, const char *p, bool isfile) 681c84f3f3cSopenharmony_ci{ 682c84f3f3cSopenharmony_ci const char *se, *pe; 683c84f3f3cSopenharmony_ci char *pnew; 684c84f3f3cSopenharmony_ci int rv; 685c84f3f3cSopenharmony_ci 686c84f3f3cSopenharmony_ci if (s == NULL || p == NULL) 687c84f3f3cSopenharmony_ci return (0); 688c84f3f3cSopenharmony_ci 689c84f3f3cSopenharmony_ci pe = strnul(p); 690c84f3f3cSopenharmony_ci /* 691c84f3f3cSopenharmony_ci * isfile is false iff no syntax check has been done on 692c84f3f3cSopenharmony_ci * the pattern. If check fails, just do a strcmp(). 693c84f3f3cSopenharmony_ci */ 694c84f3f3cSopenharmony_ci if (!isfile && !has_globbing(p)) { 695c84f3f3cSopenharmony_ci size_t len = pe - p + 1; 696c84f3f3cSopenharmony_ci char tbuf[64]; 697c84f3f3cSopenharmony_ci char *t = len <= sizeof(tbuf) ? tbuf : alloc(len, ATEMP); 698c84f3f3cSopenharmony_ci debunk(t, p, len); 699c84f3f3cSopenharmony_ci return (!strcmp(t, s)); 700c84f3f3cSopenharmony_ci } 701c84f3f3cSopenharmony_ci se = strnul(s); 702c84f3f3cSopenharmony_ci 703c84f3f3cSopenharmony_ci /* 704c84f3f3cSopenharmony_ci * since the do_gmatch() engine sucks so much, we must do some 705c84f3f3cSopenharmony_ci * pattern simplifications 706c84f3f3cSopenharmony_ci */ 707c84f3f3cSopenharmony_ci pnew = simplify_gmatch_pattern((const unsigned char *)p); 708c84f3f3cSopenharmony_ci pe = strnul(pnew); 709c84f3f3cSopenharmony_ci 710c84f3f3cSopenharmony_ci rv = do_gmatch((const unsigned char *)s, (const unsigned char *)se, 711c84f3f3cSopenharmony_ci (const unsigned char *)pnew, (const unsigned char *)pe, 712c84f3f3cSopenharmony_ci (const unsigned char *)s); 713c84f3f3cSopenharmony_ci afree(pnew, ATEMP); 714c84f3f3cSopenharmony_ci return (rv); 715c84f3f3cSopenharmony_ci} 716c84f3f3cSopenharmony_ci 717c84f3f3cSopenharmony_ci/** 718c84f3f3cSopenharmony_ci * Returns if p is a syntacticly correct globbing pattern, false 719c84f3f3cSopenharmony_ci * if it contains no pattern characters or if there is a syntax error. 720c84f3f3cSopenharmony_ci * Syntax errors are: 721c84f3f3cSopenharmony_ci * - [ with no closing ] 722c84f3f3cSopenharmony_ci * - imbalanced $(...) expression 723c84f3f3cSopenharmony_ci * - [...] and *(...) not nested (eg, @(a[b|)c], *(a[b|c]d)) 724c84f3f3cSopenharmony_ci */ 725c84f3f3cSopenharmony_ci/*XXX 726c84f3f3cSopenharmony_ci * - if no magic, 727c84f3f3cSopenharmony_ci * if dest given, copy to dst 728c84f3f3cSopenharmony_ci * return ? 729c84f3f3cSopenharmony_ci * - if magic && (no globbing || syntax error) 730c84f3f3cSopenharmony_ci * debunk to dst 731c84f3f3cSopenharmony_ci * return ? 732c84f3f3cSopenharmony_ci * - return ? 733c84f3f3cSopenharmony_ci */ 734c84f3f3cSopenharmony_cibool 735c84f3f3cSopenharmony_cihas_globbing(const char *pat) 736c84f3f3cSopenharmony_ci{ 737c84f3f3cSopenharmony_ci unsigned char c, subc; 738c84f3f3cSopenharmony_ci bool saw_glob = false; 739c84f3f3cSopenharmony_ci unsigned int nest = 0; 740c84f3f3cSopenharmony_ci const unsigned char *p = (const unsigned char *)pat; 741c84f3f3cSopenharmony_ci const unsigned char *s; 742c84f3f3cSopenharmony_ci 743c84f3f3cSopenharmony_ci while ((c = *p++)) { 744c84f3f3cSopenharmony_ci /* regular character? ok. */ 745c84f3f3cSopenharmony_ci if (!ISMAGIC(c)) 746c84f3f3cSopenharmony_ci continue; 747c84f3f3cSopenharmony_ci /* MAGIC + NUL? abort. */ 748c84f3f3cSopenharmony_ci if (!(c = *p++)) 749c84f3f3cSopenharmony_ci return (false); 750c84f3f3cSopenharmony_ci /* some specials */ 751c84f3f3cSopenharmony_ci if (ord(c) == ORD('*') || ord(c) == ORD('?')) { 752c84f3f3cSopenharmony_ci /* easy glob, accept */ 753c84f3f3cSopenharmony_ci saw_glob = true; 754c84f3f3cSopenharmony_ci } else if (ord(c) == ORD('[')) { 755c84f3f3cSopenharmony_ci /* bracket expression; eat negation and initial ] */ 756c84f3f3cSopenharmony_ci if (ISMAGIC(p[0]) && ord(p[1]) == ORD('!')) 757c84f3f3cSopenharmony_ci p += 2; 758c84f3f3cSopenharmony_ci if (ISMAGIC(p[0]) && ord(p[1]) == ORD(']')) 759c84f3f3cSopenharmony_ci p += 2; 760c84f3f3cSopenharmony_ci /* check next string part */ 761c84f3f3cSopenharmony_ci s = p; 762c84f3f3cSopenharmony_ci while ((c = *s++)) { 763c84f3f3cSopenharmony_ci /* regular chars are ok */ 764c84f3f3cSopenharmony_ci if (!ISMAGIC(c)) 765c84f3f3cSopenharmony_ci continue; 766c84f3f3cSopenharmony_ci /* MAGIC + NUL cannot happen */ 767c84f3f3cSopenharmony_ci if (!(c = *s++)) 768c84f3f3cSopenharmony_ci return (false); 769c84f3f3cSopenharmony_ci /* terminating bracket? */ 770c84f3f3cSopenharmony_ci if (ord(c) == ORD(']')) { 771c84f3f3cSopenharmony_ci /* accept and continue */ 772c84f3f3cSopenharmony_ci p = s; 773c84f3f3cSopenharmony_ci saw_glob = true; 774c84f3f3cSopenharmony_ci break; 775c84f3f3cSopenharmony_ci } 776c84f3f3cSopenharmony_ci /* sub-bracket expressions */ 777c84f3f3cSopenharmony_ci if (ord(c) == ORD('[') && ( 778c84f3f3cSopenharmony_ci /* collating element? */ 779c84f3f3cSopenharmony_ci ord(*s) == ORD('.') || 780c84f3f3cSopenharmony_ci /* equivalence class? */ 781c84f3f3cSopenharmony_ci ord(*s) == ORD('=') || 782c84f3f3cSopenharmony_ci /* character class? */ 783c84f3f3cSopenharmony_ci ord(*s) == ORD(':'))) { 784c84f3f3cSopenharmony_ci /* must stop with exactly the same c */ 785c84f3f3cSopenharmony_ci subc = *s++; 786c84f3f3cSopenharmony_ci /* arbitrarily many chars in betwixt */ 787c84f3f3cSopenharmony_ci while ((c = *s++)) 788c84f3f3cSopenharmony_ci /* but only this sequence... */ 789c84f3f3cSopenharmony_ci if (c == subc && ISMAGIC(*s) && 790c84f3f3cSopenharmony_ci ord(s[1]) == ORD(']')) { 791c84f3f3cSopenharmony_ci /* accept, terminate */ 792c84f3f3cSopenharmony_ci s += 2; 793c84f3f3cSopenharmony_ci break; 794c84f3f3cSopenharmony_ci } 795c84f3f3cSopenharmony_ci /* EOS without: reject bracket expr */ 796c84f3f3cSopenharmony_ci if (!c) 797c84f3f3cSopenharmony_ci break; 798c84f3f3cSopenharmony_ci /* continue; */ 799c84f3f3cSopenharmony_ci } 800c84f3f3cSopenharmony_ci /* anything else just goes on */ 801c84f3f3cSopenharmony_ci } 802c84f3f3cSopenharmony_ci } else if ((c & 0x80) && ctype(c & 0x7F, C_PATMO | C_SPC)) { 803c84f3f3cSopenharmony_ci /* opening pattern */ 804c84f3f3cSopenharmony_ci saw_glob = true; 805c84f3f3cSopenharmony_ci ++nest; 806c84f3f3cSopenharmony_ci } else if (ord(c) == ORD(/*(*/ ')')) { 807c84f3f3cSopenharmony_ci /* closing pattern */ 808c84f3f3cSopenharmony_ci if (nest) 809c84f3f3cSopenharmony_ci --nest; 810c84f3f3cSopenharmony_ci } 811c84f3f3cSopenharmony_ci } 812c84f3f3cSopenharmony_ci return (saw_glob && !nest); 813c84f3f3cSopenharmony_ci} 814c84f3f3cSopenharmony_ci 815c84f3f3cSopenharmony_ci/* Function must return either 0 or 1 (assumed by code for 0x80|'!') */ 816c84f3f3cSopenharmony_cistatic int 817c84f3f3cSopenharmony_cido_gmatch(const unsigned char *s, const unsigned char *se, 818c84f3f3cSopenharmony_ci const unsigned char *p, const unsigned char *pe, 819c84f3f3cSopenharmony_ci const unsigned char *smin) 820c84f3f3cSopenharmony_ci{ 821c84f3f3cSopenharmony_ci unsigned char sc, pc, sl = 0; 822c84f3f3cSopenharmony_ci const unsigned char *prest, *psub, *pnext; 823c84f3f3cSopenharmony_ci const unsigned char *srest; 824c84f3f3cSopenharmony_ci 825c84f3f3cSopenharmony_ci if (s == NULL || p == NULL) 826c84f3f3cSopenharmony_ci return (0); 827c84f3f3cSopenharmony_ci if (s > smin && s <= se) 828c84f3f3cSopenharmony_ci sl = s[-1]; 829c84f3f3cSopenharmony_ci while (p < pe) { 830c84f3f3cSopenharmony_ci pc = *p++; 831c84f3f3cSopenharmony_ci sc = s < se ? *s : '\0'; 832c84f3f3cSopenharmony_ci s++; 833c84f3f3cSopenharmony_ci if (!ISMAGIC(pc)) { 834c84f3f3cSopenharmony_ci if (sc != pc) 835c84f3f3cSopenharmony_ci return (0); 836c84f3f3cSopenharmony_ci sl = sc; 837c84f3f3cSopenharmony_ci continue; 838c84f3f3cSopenharmony_ci } 839c84f3f3cSopenharmony_ci switch (ord(*p++)) { 840c84f3f3cSopenharmony_ci case ORD('['): 841c84f3f3cSopenharmony_ci /* BSD cclass extension? */ 842c84f3f3cSopenharmony_ci if (ISMAGIC(p[0]) && ord(p[1]) == ORD('[') && 843c84f3f3cSopenharmony_ci ord(p[2]) == ORD(':') && 844c84f3f3cSopenharmony_ci ctype((pc = p[3]), C_ANGLE) && 845c84f3f3cSopenharmony_ci ord(p[4]) == ORD(':') && 846c84f3f3cSopenharmony_ci ISMAGIC(p[5]) && ord(p[6]) == ORD(']') && 847c84f3f3cSopenharmony_ci ISMAGIC(p[7]) && ord(p[8]) == ORD(']')) { 848c84f3f3cSopenharmony_ci /* zero-length match */ 849c84f3f3cSopenharmony_ci --s; 850c84f3f3cSopenharmony_ci p += 9; 851c84f3f3cSopenharmony_ci /* word begin? */ 852c84f3f3cSopenharmony_ci if (ord(pc) == ORD('<') && 853c84f3f3cSopenharmony_ci !ctype(sl, C_ALNUX) && 854c84f3f3cSopenharmony_ci ctype(sc, C_ALNUX)) 855c84f3f3cSopenharmony_ci break; 856c84f3f3cSopenharmony_ci /* word end? */ 857c84f3f3cSopenharmony_ci if (ord(pc) == ORD('>') && 858c84f3f3cSopenharmony_ci ctype(sl, C_ALNUX) && 859c84f3f3cSopenharmony_ci !ctype(sc, C_ALNUX)) 860c84f3f3cSopenharmony_ci break; 861c84f3f3cSopenharmony_ci /* neither */ 862c84f3f3cSopenharmony_ci return (0); 863c84f3f3cSopenharmony_ci } 864c84f3f3cSopenharmony_ci if (sc == 0 || (p = gmatch_cclass(p, sc)) == NULL) 865c84f3f3cSopenharmony_ci return (0); 866c84f3f3cSopenharmony_ci break; 867c84f3f3cSopenharmony_ci 868c84f3f3cSopenharmony_ci case ORD('?'): 869c84f3f3cSopenharmony_ci if (sc == 0) 870c84f3f3cSopenharmony_ci return (0); 871c84f3f3cSopenharmony_ci if (UTFMODE) { 872c84f3f3cSopenharmony_ci --s; 873c84f3f3cSopenharmony_ci s += utf_ptradj((const void *)s); 874c84f3f3cSopenharmony_ci } 875c84f3f3cSopenharmony_ci break; 876c84f3f3cSopenharmony_ci 877c84f3f3cSopenharmony_ci case ORD('*'): 878c84f3f3cSopenharmony_ci if (p == pe) 879c84f3f3cSopenharmony_ci return (1); 880c84f3f3cSopenharmony_ci s--; 881c84f3f3cSopenharmony_ci do { 882c84f3f3cSopenharmony_ci if (do_gmatch(s, se, p, pe, smin)) 883c84f3f3cSopenharmony_ci return (1); 884c84f3f3cSopenharmony_ci } while (s++ < se); 885c84f3f3cSopenharmony_ci return (0); 886c84f3f3cSopenharmony_ci 887c84f3f3cSopenharmony_ci /** 888c84f3f3cSopenharmony_ci * [+*?@!](pattern|pattern|..) 889c84f3f3cSopenharmony_ci * This is also needed for ${..%..}, etc. 890c84f3f3cSopenharmony_ci */ 891c84f3f3cSopenharmony_ci 892c84f3f3cSopenharmony_ci /* matches one or more times */ 893c84f3f3cSopenharmony_ci case ORD('+') | 0x80: 894c84f3f3cSopenharmony_ci /* matches zero or more times */ 895c84f3f3cSopenharmony_ci case ORD('*') | 0x80: 896c84f3f3cSopenharmony_ci if (!(prest = pat_scan(p, pe, false))) 897c84f3f3cSopenharmony_ci return (0); 898c84f3f3cSopenharmony_ci s--; 899c84f3f3cSopenharmony_ci /* take care of zero matches */ 900c84f3f3cSopenharmony_ci if (ord(p[-1]) == (0x80 | ORD('*')) && 901c84f3f3cSopenharmony_ci do_gmatch(s, se, prest, pe, smin)) 902c84f3f3cSopenharmony_ci return (1); 903c84f3f3cSopenharmony_ci for (psub = p; ; psub = pnext) { 904c84f3f3cSopenharmony_ci pnext = pat_scan(psub, pe, true); 905c84f3f3cSopenharmony_ci for (srest = s; srest <= se; srest++) { 906c84f3f3cSopenharmony_ci if (do_gmatch(s, srest, psub, pnext - 2, smin) && 907c84f3f3cSopenharmony_ci (do_gmatch(srest, se, prest, pe, smin) || 908c84f3f3cSopenharmony_ci (s != srest && 909c84f3f3cSopenharmony_ci do_gmatch(srest, se, p - 2, pe, smin)))) 910c84f3f3cSopenharmony_ci return (1); 911c84f3f3cSopenharmony_ci } 912c84f3f3cSopenharmony_ci if (pnext == prest) 913c84f3f3cSopenharmony_ci break; 914c84f3f3cSopenharmony_ci } 915c84f3f3cSopenharmony_ci return (0); 916c84f3f3cSopenharmony_ci 917c84f3f3cSopenharmony_ci /* matches zero or once */ 918c84f3f3cSopenharmony_ci case ORD('?') | 0x80: 919c84f3f3cSopenharmony_ci /* matches one of the patterns */ 920c84f3f3cSopenharmony_ci case ORD('@') | 0x80: 921c84f3f3cSopenharmony_ci /* simile for @ */ 922c84f3f3cSopenharmony_ci case ORD(' ') | 0x80: 923c84f3f3cSopenharmony_ci if (!(prest = pat_scan(p, pe, false))) 924c84f3f3cSopenharmony_ci return (0); 925c84f3f3cSopenharmony_ci s--; 926c84f3f3cSopenharmony_ci /* Take care of zero matches */ 927c84f3f3cSopenharmony_ci if (ord(p[-1]) == (0x80 | ORD('?')) && 928c84f3f3cSopenharmony_ci do_gmatch(s, se, prest, pe, smin)) 929c84f3f3cSopenharmony_ci return (1); 930c84f3f3cSopenharmony_ci for (psub = p; ; psub = pnext) { 931c84f3f3cSopenharmony_ci pnext = pat_scan(psub, pe, true); 932c84f3f3cSopenharmony_ci srest = prest == pe ? se : s; 933c84f3f3cSopenharmony_ci for (; srest <= se; srest++) { 934c84f3f3cSopenharmony_ci if (do_gmatch(s, srest, psub, pnext - 2, smin) && 935c84f3f3cSopenharmony_ci do_gmatch(srest, se, prest, pe, smin)) 936c84f3f3cSopenharmony_ci return (1); 937c84f3f3cSopenharmony_ci } 938c84f3f3cSopenharmony_ci if (pnext == prest) 939c84f3f3cSopenharmony_ci break; 940c84f3f3cSopenharmony_ci } 941c84f3f3cSopenharmony_ci return (0); 942c84f3f3cSopenharmony_ci 943c84f3f3cSopenharmony_ci /* matches none of the patterns */ 944c84f3f3cSopenharmony_ci case ORD('!') | 0x80: 945c84f3f3cSopenharmony_ci if (!(prest = pat_scan(p, pe, false))) 946c84f3f3cSopenharmony_ci return (0); 947c84f3f3cSopenharmony_ci s--; 948c84f3f3cSopenharmony_ci for (srest = s; srest <= se; srest++) { 949c84f3f3cSopenharmony_ci int matched = 0; 950c84f3f3cSopenharmony_ci 951c84f3f3cSopenharmony_ci for (psub = p; ; psub = pnext) { 952c84f3f3cSopenharmony_ci pnext = pat_scan(psub, pe, true); 953c84f3f3cSopenharmony_ci if (do_gmatch(s, srest, psub, 954c84f3f3cSopenharmony_ci pnext - 2, smin)) { 955c84f3f3cSopenharmony_ci matched = 1; 956c84f3f3cSopenharmony_ci break; 957c84f3f3cSopenharmony_ci } 958c84f3f3cSopenharmony_ci if (pnext == prest) 959c84f3f3cSopenharmony_ci break; 960c84f3f3cSopenharmony_ci } 961c84f3f3cSopenharmony_ci if (!matched && 962c84f3f3cSopenharmony_ci do_gmatch(srest, se, prest, pe, smin)) 963c84f3f3cSopenharmony_ci return (1); 964c84f3f3cSopenharmony_ci } 965c84f3f3cSopenharmony_ci return (0); 966c84f3f3cSopenharmony_ci 967c84f3f3cSopenharmony_ci default: 968c84f3f3cSopenharmony_ci if (sc != p[-1]) 969c84f3f3cSopenharmony_ci return (0); 970c84f3f3cSopenharmony_ci break; 971c84f3f3cSopenharmony_ci } 972c84f3f3cSopenharmony_ci sl = sc; 973c84f3f3cSopenharmony_ci } 974c84f3f3cSopenharmony_ci return (s == se); 975c84f3f3cSopenharmony_ci} 976c84f3f3cSopenharmony_ci 977c84f3f3cSopenharmony_ci/*XXX this is a prime example for bsearch or a const hashtable */ 978c84f3f3cSopenharmony_cistatic const struct cclass { 979c84f3f3cSopenharmony_ci const char *name; 980c84f3f3cSopenharmony_ci uint32_t value; 981c84f3f3cSopenharmony_ci} cclasses[] = { 982c84f3f3cSopenharmony_ci /* POSIX */ 983c84f3f3cSopenharmony_ci { "alnum", C_ALNUM }, 984c84f3f3cSopenharmony_ci { "alpha", C_ALPHA }, 985c84f3f3cSopenharmony_ci { "blank", C_BLANK }, 986c84f3f3cSopenharmony_ci { "cntrl", C_CNTRL }, 987c84f3f3cSopenharmony_ci { "digit", C_DIGIT }, 988c84f3f3cSopenharmony_ci { "graph", C_GRAPH }, 989c84f3f3cSopenharmony_ci { "lower", C_LOWER }, 990c84f3f3cSopenharmony_ci { "print", C_PRINT }, 991c84f3f3cSopenharmony_ci { "punct", C_PUNCT }, 992c84f3f3cSopenharmony_ci { "space", C_SPACE }, 993c84f3f3cSopenharmony_ci { "upper", C_UPPER }, 994c84f3f3cSopenharmony_ci { "xdigit", C_SEDEC }, 995c84f3f3cSopenharmony_ci /* BSD */ 996c84f3f3cSopenharmony_ci /* "<" and ">" are handled inline */ 997c84f3f3cSopenharmony_ci /* GNU bash */ 998c84f3f3cSopenharmony_ci { "ascii", C_ASCII }, 999c84f3f3cSopenharmony_ci { "word", C_ALNUX }, 1000c84f3f3cSopenharmony_ci /* mksh */ 1001c84f3f3cSopenharmony_ci { "sh_alias", C_ALIAS }, 1002c84f3f3cSopenharmony_ci { "sh_edq", C_EDQ }, 1003c84f3f3cSopenharmony_ci { "sh_ifs", C_IFS }, 1004c84f3f3cSopenharmony_ci { "sh_ifsws", C_IFSWS }, 1005c84f3f3cSopenharmony_ci { "sh_nl", C_NL }, 1006c84f3f3cSopenharmony_ci { "sh_quote", C_QUOTE }, 1007c84f3f3cSopenharmony_ci /* sentinel */ 1008c84f3f3cSopenharmony_ci { NULL, 0 } 1009c84f3f3cSopenharmony_ci}; 1010c84f3f3cSopenharmony_ci 1011c84f3f3cSopenharmony_cistatic const unsigned char * 1012c84f3f3cSopenharmony_cigmatch_cclass(const unsigned char *pat, unsigned char sc) 1013c84f3f3cSopenharmony_ci{ 1014c84f3f3cSopenharmony_ci unsigned char c, subc, lc; 1015c84f3f3cSopenharmony_ci const unsigned char *p = pat, *s; 1016c84f3f3cSopenharmony_ci bool found = false; 1017c84f3f3cSopenharmony_ci bool negated = false; 1018c84f3f3cSopenharmony_ci char *subp; 1019c84f3f3cSopenharmony_ci 1020c84f3f3cSopenharmony_ci /* check for negation */ 1021c84f3f3cSopenharmony_ci if (ISMAGIC(p[0]) && ord(p[1]) == ORD('!')) { 1022c84f3f3cSopenharmony_ci p += 2; 1023c84f3f3cSopenharmony_ci negated = true; 1024c84f3f3cSopenharmony_ci } 1025c84f3f3cSopenharmony_ci /* make initial ] non-MAGIC */ 1026c84f3f3cSopenharmony_ci if (ISMAGIC(p[0]) && ord(p[1]) == ORD(']')) 1027c84f3f3cSopenharmony_ci ++p; 1028c84f3f3cSopenharmony_ci /* iterate over bracket expression, debunk()ing on the fly */ 1029c84f3f3cSopenharmony_ci while ((c = *p++)) { 1030c84f3f3cSopenharmony_ci nextc: 1031c84f3f3cSopenharmony_ci /* non-regular character? */ 1032c84f3f3cSopenharmony_ci if (ISMAGIC(c)) { 1033c84f3f3cSopenharmony_ci /* MAGIC + NUL cannot happen */ 1034c84f3f3cSopenharmony_ci if (!(c = *p++)) 1035c84f3f3cSopenharmony_ci break; 1036c84f3f3cSopenharmony_ci /* terminating bracket? */ 1037c84f3f3cSopenharmony_ci if (ord(c) == ORD(']')) { 1038c84f3f3cSopenharmony_ci /* accept and return */ 1039c84f3f3cSopenharmony_ci return (found != negated ? p : NULL); 1040c84f3f3cSopenharmony_ci } 1041c84f3f3cSopenharmony_ci /* sub-bracket expressions */ 1042c84f3f3cSopenharmony_ci if (ord(c) == ORD('[') && ( 1043c84f3f3cSopenharmony_ci /* collating element? */ 1044c84f3f3cSopenharmony_ci ord(*p) == ORD('.') || 1045c84f3f3cSopenharmony_ci /* equivalence class? */ 1046c84f3f3cSopenharmony_ci ord(*p) == ORD('=') || 1047c84f3f3cSopenharmony_ci /* character class? */ 1048c84f3f3cSopenharmony_ci ord(*p) == ORD(':'))) { 1049c84f3f3cSopenharmony_ci /* must stop with exactly the same c */ 1050c84f3f3cSopenharmony_ci subc = *p++; 1051c84f3f3cSopenharmony_ci /* save away start of substring */ 1052c84f3f3cSopenharmony_ci s = p; 1053c84f3f3cSopenharmony_ci /* arbitrarily many chars in betwixt */ 1054c84f3f3cSopenharmony_ci while ((c = *p++)) 1055c84f3f3cSopenharmony_ci /* but only this sequence... */ 1056c84f3f3cSopenharmony_ci if (c == subc && ISMAGIC(*p) && 1057c84f3f3cSopenharmony_ci ord(p[1]) == ORD(']')) { 1058c84f3f3cSopenharmony_ci /* accept, terminate */ 1059c84f3f3cSopenharmony_ci p += 2; 1060c84f3f3cSopenharmony_ci break; 1061c84f3f3cSopenharmony_ci } 1062c84f3f3cSopenharmony_ci /* EOS without: reject bracket expr */ 1063c84f3f3cSopenharmony_ci if (!c) 1064c84f3f3cSopenharmony_ci break; 1065c84f3f3cSopenharmony_ci /* debunk substring */ 1066c84f3f3cSopenharmony_ci strndupx(subp, s, p - s - 3, ATEMP); 1067c84f3f3cSopenharmony_ci debunk(subp, subp, p - s - 3 + 1); 1068c84f3f3cSopenharmony_ci cclass_common: 1069c84f3f3cSopenharmony_ci /* whither subexpression */ 1070c84f3f3cSopenharmony_ci if (ord(subc) == ORD(':')) { 1071c84f3f3cSopenharmony_ci const struct cclass *cls = cclasses; 1072c84f3f3cSopenharmony_ci 1073c84f3f3cSopenharmony_ci /* search for name in cclass list */ 1074c84f3f3cSopenharmony_ci while (cls->name) 1075c84f3f3cSopenharmony_ci if (!strcmp(subp, cls->name)) { 1076c84f3f3cSopenharmony_ci /* found, match? */ 1077c84f3f3cSopenharmony_ci if (ctype(sc, 1078c84f3f3cSopenharmony_ci cls->value)) 1079c84f3f3cSopenharmony_ci found = true; 1080c84f3f3cSopenharmony_ci /* break either way */ 1081c84f3f3cSopenharmony_ci break; 1082c84f3f3cSopenharmony_ci } else 1083c84f3f3cSopenharmony_ci ++cls; 1084c84f3f3cSopenharmony_ci /* that's all here */ 1085c84f3f3cSopenharmony_ci afree(subp, ATEMP); 1086c84f3f3cSopenharmony_ci continue; 1087c84f3f3cSopenharmony_ci } 1088c84f3f3cSopenharmony_ci /* collating element or equivalence class */ 1089c84f3f3cSopenharmony_ci /* Note: latter are treated as former */ 1090c84f3f3cSopenharmony_ci if (ctype(subp[0], C_ASCII) && !subp[1]) 1091c84f3f3cSopenharmony_ci /* [.a.] where a is one ASCII char */ 1092c84f3f3cSopenharmony_ci c = subp[0]; 1093c84f3f3cSopenharmony_ci else 1094c84f3f3cSopenharmony_ci /* force no match */ 1095c84f3f3cSopenharmony_ci c = 0; 1096c84f3f3cSopenharmony_ci /* no longer needed */ 1097c84f3f3cSopenharmony_ci afree(subp, ATEMP); 1098c84f3f3cSopenharmony_ci } else if (!ISMAGIC(c) && (c & 0x80)) { 1099c84f3f3cSopenharmony_ci /* 0x80|' ' is plain (...) */ 1100c84f3f3cSopenharmony_ci if ((c &= 0x7F) != ' ') { 1101c84f3f3cSopenharmony_ci /* check single match NOW */ 1102c84f3f3cSopenharmony_ci if (sc == c) 1103c84f3f3cSopenharmony_ci found = true; 1104c84f3f3cSopenharmony_ci /* next character is (...) */ 1105c84f3f3cSopenharmony_ci } 1106c84f3f3cSopenharmony_ci c = '(' /*)*/; 1107c84f3f3cSopenharmony_ci } 1108c84f3f3cSopenharmony_ci } 1109c84f3f3cSopenharmony_ci /* range expression? */ 1110c84f3f3cSopenharmony_ci if (!(ISMAGIC(p[0]) && ord(p[1]) == ORD('-') && 1111c84f3f3cSopenharmony_ci /* not terminating bracket? */ 1112c84f3f3cSopenharmony_ci (!ISMAGIC(p[2]) || ord(p[3]) != ORD(']')))) { 1113c84f3f3cSopenharmony_ci /* no, check single match */ 1114c84f3f3cSopenharmony_ci if (sc == c) 1115c84f3f3cSopenharmony_ci /* note: sc is never NUL */ 1116c84f3f3cSopenharmony_ci found = true; 1117c84f3f3cSopenharmony_ci /* do the next "first" character */ 1118c84f3f3cSopenharmony_ci continue; 1119c84f3f3cSopenharmony_ci } 1120c84f3f3cSopenharmony_ci /* save lower range bound */ 1121c84f3f3cSopenharmony_ci lc = c; 1122c84f3f3cSopenharmony_ci /* skip over the range operator */ 1123c84f3f3cSopenharmony_ci p += 2; 1124c84f3f3cSopenharmony_ci /* do the same shit as above... almost */ 1125c84f3f3cSopenharmony_ci subc = 0; 1126c84f3f3cSopenharmony_ci if (!(c = *p++)) 1127c84f3f3cSopenharmony_ci break; 1128c84f3f3cSopenharmony_ci /* non-regular character? */ 1129c84f3f3cSopenharmony_ci if (ISMAGIC(c)) { 1130c84f3f3cSopenharmony_ci /* MAGIC + NUL cannot happen */ 1131c84f3f3cSopenharmony_ci if (!(c = *p++)) 1132c84f3f3cSopenharmony_ci break; 1133c84f3f3cSopenharmony_ci /* sub-bracket expressions */ 1134c84f3f3cSopenharmony_ci if (ord(c) == ORD('[') && ( 1135c84f3f3cSopenharmony_ci /* collating element? */ 1136c84f3f3cSopenharmony_ci ord(*p) == ORD('.') || 1137c84f3f3cSopenharmony_ci /* equivalence class? */ 1138c84f3f3cSopenharmony_ci ord(*p) == ORD('=') || 1139c84f3f3cSopenharmony_ci /* character class? */ 1140c84f3f3cSopenharmony_ci ord(*p) == ORD(':'))) { 1141c84f3f3cSopenharmony_ci /* must stop with exactly the same c */ 1142c84f3f3cSopenharmony_ci subc = *p++; 1143c84f3f3cSopenharmony_ci /* save away start of substring */ 1144c84f3f3cSopenharmony_ci s = p; 1145c84f3f3cSopenharmony_ci /* arbitrarily many chars in betwixt */ 1146c84f3f3cSopenharmony_ci while ((c = *p++)) 1147c84f3f3cSopenharmony_ci /* but only this sequence... */ 1148c84f3f3cSopenharmony_ci if (c == subc && ISMAGIC(*p) && 1149c84f3f3cSopenharmony_ci ord(p[1]) == ORD(']')) { 1150c84f3f3cSopenharmony_ci /* accept, terminate */ 1151c84f3f3cSopenharmony_ci p += 2; 1152c84f3f3cSopenharmony_ci break; 1153c84f3f3cSopenharmony_ci } 1154c84f3f3cSopenharmony_ci /* EOS without: reject bracket expr */ 1155c84f3f3cSopenharmony_ci if (!c) 1156c84f3f3cSopenharmony_ci break; 1157c84f3f3cSopenharmony_ci /* debunk substring */ 1158c84f3f3cSopenharmony_ci strndupx(subp, s, p - s - 3, ATEMP); 1159c84f3f3cSopenharmony_ci debunk(subp, subp, p - s - 3 + 1); 1160c84f3f3cSopenharmony_ci /* whither subexpression */ 1161c84f3f3cSopenharmony_ci if (ord(subc) == ORD(':')) { 1162c84f3f3cSopenharmony_ci /* oops, not a range */ 1163c84f3f3cSopenharmony_ci 1164c84f3f3cSopenharmony_ci /* match single previous char */ 1165c84f3f3cSopenharmony_ci if (lc && (sc == lc)) 1166c84f3f3cSopenharmony_ci found = true; 1167c84f3f3cSopenharmony_ci /* match hyphen-minus */ 1168c84f3f3cSopenharmony_ci if (ord(sc) == ORD('-')) 1169c84f3f3cSopenharmony_ci found = true; 1170c84f3f3cSopenharmony_ci /* handle cclass common part */ 1171c84f3f3cSopenharmony_ci goto cclass_common; 1172c84f3f3cSopenharmony_ci } 1173c84f3f3cSopenharmony_ci /* collating element or equivalence class */ 1174c84f3f3cSopenharmony_ci /* Note: latter are treated as former */ 1175c84f3f3cSopenharmony_ci if (ctype(subp[0], C_ASCII) && !subp[1]) 1176c84f3f3cSopenharmony_ci /* [.a.] where a is one ASCII char */ 1177c84f3f3cSopenharmony_ci c = subp[0]; 1178c84f3f3cSopenharmony_ci else 1179c84f3f3cSopenharmony_ci /* force no match */ 1180c84f3f3cSopenharmony_ci c = 0; 1181c84f3f3cSopenharmony_ci /* no longer needed */ 1182c84f3f3cSopenharmony_ci afree(subp, ATEMP); 1183c84f3f3cSopenharmony_ci /* other meaning below */ 1184c84f3f3cSopenharmony_ci subc = 0; 1185c84f3f3cSopenharmony_ci } else if (c == (0x80 | ' ')) { 1186c84f3f3cSopenharmony_ci /* 0x80|' ' is plain (...) */ 1187c84f3f3cSopenharmony_ci c = '(' /*)*/; 1188c84f3f3cSopenharmony_ci } else if (!ISMAGIC(c) && (c & 0x80)) { 1189c84f3f3cSopenharmony_ci c &= 0x7F; 1190c84f3f3cSopenharmony_ci subc = '(' /*)*/; 1191c84f3f3cSopenharmony_ci } 1192c84f3f3cSopenharmony_ci } 1193c84f3f3cSopenharmony_ci /* now do the actual range match check */ 1194c84f3f3cSopenharmony_ci if (lc != 0 /* && c != 0 */ && 1195c84f3f3cSopenharmony_ci asciibetical(lc) <= asciibetical(sc) && 1196c84f3f3cSopenharmony_ci asciibetical(sc) <= asciibetical(c)) 1197c84f3f3cSopenharmony_ci found = true; 1198c84f3f3cSopenharmony_ci /* forced next character? */ 1199c84f3f3cSopenharmony_ci if (subc) { 1200c84f3f3cSopenharmony_ci c = subc; 1201c84f3f3cSopenharmony_ci goto nextc; 1202c84f3f3cSopenharmony_ci } 1203c84f3f3cSopenharmony_ci /* otherwise, just go on with the pattern string */ 1204c84f3f3cSopenharmony_ci } 1205c84f3f3cSopenharmony_ci /* if we broke here, the bracket expression was invalid */ 1206c84f3f3cSopenharmony_ci if (ord(sc) == ORD('[')) 1207c84f3f3cSopenharmony_ci /* initial opening bracket as literal match */ 1208c84f3f3cSopenharmony_ci return (pat); 1209c84f3f3cSopenharmony_ci /* or rather no match */ 1210c84f3f3cSopenharmony_ci return (NULL); 1211c84f3f3cSopenharmony_ci} 1212c84f3f3cSopenharmony_ci 1213c84f3f3cSopenharmony_ci/* Look for next ) or | (if match_sep) in *(foo|bar) pattern */ 1214c84f3f3cSopenharmony_cistatic const unsigned char * 1215c84f3f3cSopenharmony_cipat_scan(const unsigned char *p, const unsigned char *pe, bool match_sep) 1216c84f3f3cSopenharmony_ci{ 1217c84f3f3cSopenharmony_ci int nest = 0; 1218c84f3f3cSopenharmony_ci 1219c84f3f3cSopenharmony_ci for (; p < pe; p++) { 1220c84f3f3cSopenharmony_ci if (!ISMAGIC(*p)) 1221c84f3f3cSopenharmony_ci continue; 1222c84f3f3cSopenharmony_ci if ((*++p == /*(*/ ')' && nest-- == 0) || 1223c84f3f3cSopenharmony_ci (*p == '|' && match_sep && nest == 0)) 1224c84f3f3cSopenharmony_ci return (p + 1); 1225c84f3f3cSopenharmony_ci if ((*p & 0x80) && ctype(*p & 0x7F, C_PATMO | C_SPC)) 1226c84f3f3cSopenharmony_ci nest++; 1227c84f3f3cSopenharmony_ci } 1228c84f3f3cSopenharmony_ci return (NULL); 1229c84f3f3cSopenharmony_ci} 1230c84f3f3cSopenharmony_ci 1231c84f3f3cSopenharmony_ciint 1232c84f3f3cSopenharmony_ciascstrcmp(const void *s1, const void *s2) 1233c84f3f3cSopenharmony_ci{ 1234c84f3f3cSopenharmony_ci const uint8_t *cp1 = s1, *cp2 = s2; 1235c84f3f3cSopenharmony_ci 1236c84f3f3cSopenharmony_ci while (*cp1 == *cp2) { 1237c84f3f3cSopenharmony_ci if (*cp1++ == '\0') 1238c84f3f3cSopenharmony_ci return (0); 1239c84f3f3cSopenharmony_ci ++cp2; 1240c84f3f3cSopenharmony_ci } 1241c84f3f3cSopenharmony_ci return ((int)asciibetical(*cp1) - (int)asciibetical(*cp2)); 1242c84f3f3cSopenharmony_ci} 1243c84f3f3cSopenharmony_ci 1244c84f3f3cSopenharmony_ciint 1245c84f3f3cSopenharmony_ciascpstrcmp(const void *pstr1, const void *pstr2) 1246c84f3f3cSopenharmony_ci{ 1247c84f3f3cSopenharmony_ci return (ascstrcmp(*(const char * const *)pstr1, 1248c84f3f3cSopenharmony_ci *(const char * const *)pstr2)); 1249c84f3f3cSopenharmony_ci} 1250c84f3f3cSopenharmony_ci 1251c84f3f3cSopenharmony_ci/* Initialise a Getopt structure */ 1252c84f3f3cSopenharmony_civoid 1253c84f3f3cSopenharmony_ciksh_getopt_reset(Getopt *go, int flags) 1254c84f3f3cSopenharmony_ci{ 1255c84f3f3cSopenharmony_ci go->optind = 1; 1256c84f3f3cSopenharmony_ci go->optarg = NULL; 1257c84f3f3cSopenharmony_ci go->p = 0; 1258c84f3f3cSopenharmony_ci go->flags = flags; 1259c84f3f3cSopenharmony_ci go->info = 0; 1260c84f3f3cSopenharmony_ci go->buf[1] = '\0'; 1261c84f3f3cSopenharmony_ci} 1262c84f3f3cSopenharmony_ci 1263c84f3f3cSopenharmony_ci 1264c84f3f3cSopenharmony_ci/** 1265c84f3f3cSopenharmony_ci * getopt() used for shell built-in commands, the getopts command, and 1266c84f3f3cSopenharmony_ci * command line options. 1267c84f3f3cSopenharmony_ci * A leading ':' in options means don't print errors, instead return '?' 1268c84f3f3cSopenharmony_ci * or ':' and set go->optarg to the offending option character. 1269c84f3f3cSopenharmony_ci * If GF_ERROR is set (and option doesn't start with :), errors result in 1270c84f3f3cSopenharmony_ci * a call to bi_errorf(). 1271c84f3f3cSopenharmony_ci * 1272c84f3f3cSopenharmony_ci * Non-standard features: 1273c84f3f3cSopenharmony_ci * - ';' is like ':' in options, except the argument is optional 1274c84f3f3cSopenharmony_ci * (if it isn't present, optarg is set to 0). 1275c84f3f3cSopenharmony_ci * Used for 'set -o'. 1276c84f3f3cSopenharmony_ci * - ',' is like ':' in options, except the argument always immediately 1277c84f3f3cSopenharmony_ci * follows the option character (optarg is set to the null string if 1278c84f3f3cSopenharmony_ci * the option is missing). 1279c84f3f3cSopenharmony_ci * Used for 'read -u2', 'print -u2' and fc -40. 1280c84f3f3cSopenharmony_ci * - '#' is like ':' in options, expect that the argument is optional 1281c84f3f3cSopenharmony_ci * and must start with a digit. If the argument doesn't start with a 1282c84f3f3cSopenharmony_ci * digit, it is assumed to be missing and normal option processing 1283c84f3f3cSopenharmony_ci * continues (optarg is set to 0 if the option is missing). 1284c84f3f3cSopenharmony_ci * Used for 'typeset -LZ4'. 1285c84f3f3cSopenharmony_ci * - accepts +c as well as -c IF the GF_PLUSOPT flag is present. If an 1286c84f3f3cSopenharmony_ci * option starting with + is accepted, the GI_PLUS flag will be set 1287c84f3f3cSopenharmony_ci * in go->info. 1288c84f3f3cSopenharmony_ci */ 1289c84f3f3cSopenharmony_ciint 1290c84f3f3cSopenharmony_ciksh_getopt(const char **argv, Getopt *go, const char *optionsp) 1291c84f3f3cSopenharmony_ci{ 1292c84f3f3cSopenharmony_ci char c; 1293c84f3f3cSopenharmony_ci const char *o; 1294c84f3f3cSopenharmony_ci 1295c84f3f3cSopenharmony_ci if (go->p == 0 || (c = argv[go->optind - 1][go->p]) == '\0') { 1296c84f3f3cSopenharmony_ci const char *arg = argv[go->optind], flag = arg ? *arg : '\0'; 1297c84f3f3cSopenharmony_ci 1298c84f3f3cSopenharmony_ci go->p = 1; 1299c84f3f3cSopenharmony_ci if (flag == '-' && ksh_isdash(arg + 1)) { 1300c84f3f3cSopenharmony_ci go->optind++; 1301c84f3f3cSopenharmony_ci go->p = 0; 1302c84f3f3cSopenharmony_ci go->info |= GI_MINUSMINUS; 1303c84f3f3cSopenharmony_ci return (-1); 1304c84f3f3cSopenharmony_ci } 1305c84f3f3cSopenharmony_ci if (arg == NULL || 1306c84f3f3cSopenharmony_ci ((flag != '-' ) && 1307c84f3f3cSopenharmony_ci /* neither a - nor a + (if + allowed) */ 1308c84f3f3cSopenharmony_ci (!(go->flags & GF_PLUSOPT) || flag != '+')) || 1309c84f3f3cSopenharmony_ci (c = arg[1]) == '\0') { 1310c84f3f3cSopenharmony_ci go->p = 0; 1311c84f3f3cSopenharmony_ci return (-1); 1312c84f3f3cSopenharmony_ci } 1313c84f3f3cSopenharmony_ci go->optind++; 1314c84f3f3cSopenharmony_ci go->info &= ~(GI_MINUS|GI_PLUS); 1315c84f3f3cSopenharmony_ci go->info |= flag == '-' ? GI_MINUS : GI_PLUS; 1316c84f3f3cSopenharmony_ci } 1317c84f3f3cSopenharmony_ci go->p++; 1318c84f3f3cSopenharmony_ci if (ctype(c, C_QUEST | C_COLON | C_HASH) || c == ';' || c == ',' || 1319c84f3f3cSopenharmony_ci !(o = cstrchr(optionsp, c))) { 1320c84f3f3cSopenharmony_ci if (optionsp[0] == ':') { 1321c84f3f3cSopenharmony_ci go->buf[0] = c; 1322c84f3f3cSopenharmony_ci go->optarg = go->buf; 1323c84f3f3cSopenharmony_ci } else { 1324c84f3f3cSopenharmony_ci warningf(true, Tf_optfoo, 1325c84f3f3cSopenharmony_ci (go->flags & GF_NONAME) ? "" : argv[0], 1326c84f3f3cSopenharmony_ci (go->flags & GF_NONAME) ? "" : Tcolsp, 1327c84f3f3cSopenharmony_ci c, Tunknown_option); 1328c84f3f3cSopenharmony_ci if (go->flags & GF_ERROR) 1329c84f3f3cSopenharmony_ci bi_errorfz(); 1330c84f3f3cSopenharmony_ci } 1331c84f3f3cSopenharmony_ci return (ORD('?')); 1332c84f3f3cSopenharmony_ci } 1333c84f3f3cSopenharmony_ci /** 1334c84f3f3cSopenharmony_ci * : means argument must be present, may be part of option argument 1335c84f3f3cSopenharmony_ci * or the next argument 1336c84f3f3cSopenharmony_ci * ; same as : but argument may be missing 1337c84f3f3cSopenharmony_ci * , means argument is part of option argument, and may be null. 1338c84f3f3cSopenharmony_ci */ 1339c84f3f3cSopenharmony_ci if (*++o == ':' || *o == ';') { 1340c84f3f3cSopenharmony_ci if (argv[go->optind - 1][go->p]) 1341c84f3f3cSopenharmony_ci go->optarg = argv[go->optind - 1] + go->p; 1342c84f3f3cSopenharmony_ci else if (argv[go->optind]) 1343c84f3f3cSopenharmony_ci go->optarg = argv[go->optind++]; 1344c84f3f3cSopenharmony_ci else if (*o == ';') 1345c84f3f3cSopenharmony_ci go->optarg = NULL; 1346c84f3f3cSopenharmony_ci else { 1347c84f3f3cSopenharmony_ci if (optionsp[0] == ':') { 1348c84f3f3cSopenharmony_ci go->buf[0] = c; 1349c84f3f3cSopenharmony_ci go->optarg = go->buf; 1350c84f3f3cSopenharmony_ci return (ORD(':')); 1351c84f3f3cSopenharmony_ci } 1352c84f3f3cSopenharmony_ci warningf(true, Tf_optfoo, 1353c84f3f3cSopenharmony_ci (go->flags & GF_NONAME) ? "" : argv[0], 1354c84f3f3cSopenharmony_ci (go->flags & GF_NONAME) ? "" : Tcolsp, 1355c84f3f3cSopenharmony_ci c, Treq_arg); 1356c84f3f3cSopenharmony_ci if (go->flags & GF_ERROR) 1357c84f3f3cSopenharmony_ci bi_errorfz(); 1358c84f3f3cSopenharmony_ci return (ORD('?')); 1359c84f3f3cSopenharmony_ci } 1360c84f3f3cSopenharmony_ci go->p = 0; 1361c84f3f3cSopenharmony_ci } else if (*o == ',') { 1362c84f3f3cSopenharmony_ci /* argument is attached to option character, even if null */ 1363c84f3f3cSopenharmony_ci go->optarg = argv[go->optind - 1] + go->p; 1364c84f3f3cSopenharmony_ci go->p = 0; 1365c84f3f3cSopenharmony_ci } else if (*o == '#') { 1366c84f3f3cSopenharmony_ci /* 1367c84f3f3cSopenharmony_ci * argument is optional and may be attached or unattached 1368c84f3f3cSopenharmony_ci * but must start with a digit. optarg is set to 0 if the 1369c84f3f3cSopenharmony_ci * argument is missing. 1370c84f3f3cSopenharmony_ci */ 1371c84f3f3cSopenharmony_ci if (argv[go->optind - 1][go->p]) { 1372c84f3f3cSopenharmony_ci if (ctype(argv[go->optind - 1][go->p], C_DIGIT)) { 1373c84f3f3cSopenharmony_ci go->optarg = argv[go->optind - 1] + go->p; 1374c84f3f3cSopenharmony_ci go->p = 0; 1375c84f3f3cSopenharmony_ci } else 1376c84f3f3cSopenharmony_ci go->optarg = NULL; 1377c84f3f3cSopenharmony_ci } else { 1378c84f3f3cSopenharmony_ci if (argv[go->optind] && 1379c84f3f3cSopenharmony_ci ctype(argv[go->optind][0], C_DIGIT)) { 1380c84f3f3cSopenharmony_ci go->optarg = argv[go->optind++]; 1381c84f3f3cSopenharmony_ci go->p = 0; 1382c84f3f3cSopenharmony_ci } else 1383c84f3f3cSopenharmony_ci go->optarg = NULL; 1384c84f3f3cSopenharmony_ci } 1385c84f3f3cSopenharmony_ci } 1386c84f3f3cSopenharmony_ci return (ord(c)); 1387c84f3f3cSopenharmony_ci} 1388c84f3f3cSopenharmony_ci 1389c84f3f3cSopenharmony_ci/* 1390c84f3f3cSopenharmony_ci * print variable/alias value using necessary quotes 1391c84f3f3cSopenharmony_ci * (POSIX says they should be suitable for re-entry...) 1392c84f3f3cSopenharmony_ci * No trailing newline is printed. 1393c84f3f3cSopenharmony_ci */ 1394c84f3f3cSopenharmony_civoid 1395c84f3f3cSopenharmony_ciprint_value_quoted(struct shf *shf, const char *s) 1396c84f3f3cSopenharmony_ci{ 1397c84f3f3cSopenharmony_ci unsigned char c; 1398c84f3f3cSopenharmony_ci const unsigned char *p = (const unsigned char *)s; 1399c84f3f3cSopenharmony_ci bool inquote = true; 1400c84f3f3cSopenharmony_ci 1401c84f3f3cSopenharmony_ci /* first, special-case empty strings (for re-entrancy) */ 1402c84f3f3cSopenharmony_ci if (!*s) { 1403c84f3f3cSopenharmony_ci shf_putc('\'', shf); 1404c84f3f3cSopenharmony_ci shf_putc('\'', shf); 1405c84f3f3cSopenharmony_ci return; 1406c84f3f3cSopenharmony_ci } 1407c84f3f3cSopenharmony_ci 1408c84f3f3cSopenharmony_ci /* non-empty; check whether any quotes are needed */ 1409c84f3f3cSopenharmony_ci while (rtt2asc(c = *p++) >= 32) 1410c84f3f3cSopenharmony_ci if (ctype(c, C_QUOTE | C_SPC)) 1411c84f3f3cSopenharmony_ci inquote = false; 1412c84f3f3cSopenharmony_ci 1413c84f3f3cSopenharmony_ci p = (const unsigned char *)s; 1414c84f3f3cSopenharmony_ci if (c == 0) { 1415c84f3f3cSopenharmony_ci if (inquote) { 1416c84f3f3cSopenharmony_ci /* nope, use the shortcut */ 1417c84f3f3cSopenharmony_ci shf_puts(s, shf); 1418c84f3f3cSopenharmony_ci return; 1419c84f3f3cSopenharmony_ci } 1420c84f3f3cSopenharmony_ci 1421c84f3f3cSopenharmony_ci /* otherwise, quote nicely via state machine */ 1422c84f3f3cSopenharmony_ci while ((c = *p++) != 0) { 1423c84f3f3cSopenharmony_ci if (c == '\'') { 1424c84f3f3cSopenharmony_ci /* 1425c84f3f3cSopenharmony_ci * multiple single quotes or any of them 1426c84f3f3cSopenharmony_ci * at the beginning of a string look nicer 1427c84f3f3cSopenharmony_ci * this way than when simply substituting 1428c84f3f3cSopenharmony_ci */ 1429c84f3f3cSopenharmony_ci if (inquote) { 1430c84f3f3cSopenharmony_ci shf_putc('\'', shf); 1431c84f3f3cSopenharmony_ci inquote = false; 1432c84f3f3cSopenharmony_ci } 1433c84f3f3cSopenharmony_ci shf_putc('\\', shf); 1434c84f3f3cSopenharmony_ci } else if (!inquote) { 1435c84f3f3cSopenharmony_ci shf_putc('\'', shf); 1436c84f3f3cSopenharmony_ci inquote = true; 1437c84f3f3cSopenharmony_ci } 1438c84f3f3cSopenharmony_ci shf_putc(c, shf); 1439c84f3f3cSopenharmony_ci } 1440c84f3f3cSopenharmony_ci } else { 1441c84f3f3cSopenharmony_ci unsigned int wc; 1442c84f3f3cSopenharmony_ci size_t n; 1443c84f3f3cSopenharmony_ci 1444c84f3f3cSopenharmony_ci /* use $'...' quote format */ 1445c84f3f3cSopenharmony_ci shf_putc('$', shf); 1446c84f3f3cSopenharmony_ci shf_putc('\'', shf); 1447c84f3f3cSopenharmony_ci while ((c = *p) != 0) { 1448c84f3f3cSopenharmony_ci#ifndef MKSH_EBCDIC 1449c84f3f3cSopenharmony_ci if (c >= 0xC2) { 1450c84f3f3cSopenharmony_ci n = utf_mbtowc(&wc, (const char *)p); 1451c84f3f3cSopenharmony_ci if (n != (size_t)-1) { 1452c84f3f3cSopenharmony_ci p += n; 1453c84f3f3cSopenharmony_ci shf_fprintf(shf, "\\u%04X", wc); 1454c84f3f3cSopenharmony_ci continue; 1455c84f3f3cSopenharmony_ci } 1456c84f3f3cSopenharmony_ci } 1457c84f3f3cSopenharmony_ci#endif 1458c84f3f3cSopenharmony_ci ++p; 1459c84f3f3cSopenharmony_ci switch (c) { 1460c84f3f3cSopenharmony_ci /* see unbksl() in this file for comments */ 1461c84f3f3cSopenharmony_ci case KSH_BEL: 1462c84f3f3cSopenharmony_ci c = 'a'; 1463c84f3f3cSopenharmony_ci if (0) 1464c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1465c84f3f3cSopenharmony_ci case '\b': 1466c84f3f3cSopenharmony_ci c = 'b'; 1467c84f3f3cSopenharmony_ci if (0) 1468c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1469c84f3f3cSopenharmony_ci case '\f': 1470c84f3f3cSopenharmony_ci c = 'f'; 1471c84f3f3cSopenharmony_ci if (0) 1472c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1473c84f3f3cSopenharmony_ci case '\n': 1474c84f3f3cSopenharmony_ci c = 'n'; 1475c84f3f3cSopenharmony_ci if (0) 1476c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1477c84f3f3cSopenharmony_ci case '\r': 1478c84f3f3cSopenharmony_ci c = 'r'; 1479c84f3f3cSopenharmony_ci if (0) 1480c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1481c84f3f3cSopenharmony_ci case '\t': 1482c84f3f3cSopenharmony_ci c = 't'; 1483c84f3f3cSopenharmony_ci if (0) 1484c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1485c84f3f3cSopenharmony_ci case KSH_VTAB: 1486c84f3f3cSopenharmony_ci c = 'v'; 1487c84f3f3cSopenharmony_ci if (0) 1488c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1489c84f3f3cSopenharmony_ci case KSH_ESC: 1490c84f3f3cSopenharmony_ci /* take E not e because \e is \ in *roff */ 1491c84f3f3cSopenharmony_ci c = 'E'; 1492c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1493c84f3f3cSopenharmony_ci case '\\': 1494c84f3f3cSopenharmony_ci shf_putc('\\', shf); 1495c84f3f3cSopenharmony_ci 1496c84f3f3cSopenharmony_ci if (0) 1497c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1498c84f3f3cSopenharmony_ci default: 1499c84f3f3cSopenharmony_ci#if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC) 1500c84f3f3cSopenharmony_ci if (ksh_isctrl(c)) 1501c84f3f3cSopenharmony_ci#else 1502c84f3f3cSopenharmony_ci if (!ctype(c, C_PRINT)) 1503c84f3f3cSopenharmony_ci#endif 1504c84f3f3cSopenharmony_ci { 1505c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1506c84f3f3cSopenharmony_ci case '\'': 1507c84f3f3cSopenharmony_ci shf_fprintf(shf, "\\%03o", c); 1508c84f3f3cSopenharmony_ci break; 1509c84f3f3cSopenharmony_ci } 1510c84f3f3cSopenharmony_ci 1511c84f3f3cSopenharmony_ci shf_putc(c, shf); 1512c84f3f3cSopenharmony_ci break; 1513c84f3f3cSopenharmony_ci } 1514c84f3f3cSopenharmony_ci } 1515c84f3f3cSopenharmony_ci inquote = true; 1516c84f3f3cSopenharmony_ci } 1517c84f3f3cSopenharmony_ci if (inquote) 1518c84f3f3cSopenharmony_ci shf_putc('\'', shf); 1519c84f3f3cSopenharmony_ci} 1520c84f3f3cSopenharmony_ci 1521c84f3f3cSopenharmony_ci/* 1522c84f3f3cSopenharmony_ci * Print things in columns and rows - func() is called to format 1523c84f3f3cSopenharmony_ci * the i-th element 1524c84f3f3cSopenharmony_ci */ 1525c84f3f3cSopenharmony_civoid 1526c84f3f3cSopenharmony_ciprint_columns(struct columnise_opts *opts, unsigned int n, 1527c84f3f3cSopenharmony_ci void (*func)(char *, size_t, unsigned int, const void *), 1528c84f3f3cSopenharmony_ci const void *arg, size_t max_oct, size_t max_colz) 1529c84f3f3cSopenharmony_ci{ 1530c84f3f3cSopenharmony_ci unsigned int i, r = 0, c, rows, cols, nspace, max_col; 1531c84f3f3cSopenharmony_ci char *str; 1532c84f3f3cSopenharmony_ci 1533c84f3f3cSopenharmony_ci if (!n) 1534c84f3f3cSopenharmony_ci return; 1535c84f3f3cSopenharmony_ci 1536c84f3f3cSopenharmony_ci if (max_colz > 2147483646) { 1537c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL 1538c84f3f3cSopenharmony_ci internal_warningf("print_columns called with %s=%zu >= INT_MAX", 1539c84f3f3cSopenharmony_ci "max_col", max_colz); 1540c84f3f3cSopenharmony_ci#endif 1541c84f3f3cSopenharmony_ci return; 1542c84f3f3cSopenharmony_ci } 1543c84f3f3cSopenharmony_ci max_col = (unsigned int)max_colz; 1544c84f3f3cSopenharmony_ci 1545c84f3f3cSopenharmony_ci if (max_oct > 2147483646) { 1546c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL 1547c84f3f3cSopenharmony_ci internal_warningf("print_columns called with %s=%zu >= INT_MAX", 1548c84f3f3cSopenharmony_ci "max_oct", max_oct); 1549c84f3f3cSopenharmony_ci#endif 1550c84f3f3cSopenharmony_ci return; 1551c84f3f3cSopenharmony_ci } 1552c84f3f3cSopenharmony_ci ++max_oct; 1553c84f3f3cSopenharmony_ci str = alloc(max_oct, ATEMP); 1554c84f3f3cSopenharmony_ci 1555c84f3f3cSopenharmony_ci /* 1556c84f3f3cSopenharmony_ci * We use (max_col + 2) to consider the separator space. 1557c84f3f3cSopenharmony_ci * Note that no spaces are printed after the last column 1558c84f3f3cSopenharmony_ci * to avoid problems with terminals that have auto-wrap, 1559c84f3f3cSopenharmony_ci * but we need to also take this into account in x_cols. 1560c84f3f3cSopenharmony_ci */ 1561c84f3f3cSopenharmony_ci cols = (x_cols + 1) / (max_col + 2); 1562c84f3f3cSopenharmony_ci 1563c84f3f3cSopenharmony_ci /* if we can only print one column anyway, skip the goo */ 1564c84f3f3cSopenharmony_ci if (cols < 2) { 1565c84f3f3cSopenharmony_ci goto prcols_easy; 1566c84f3f3cSopenharmony_ci while (r < n) { 1567c84f3f3cSopenharmony_ci shf_putc(opts->linesep, opts->shf); 1568c84f3f3cSopenharmony_ci prcols_easy: 1569c84f3f3cSopenharmony_ci (*func)(str, max_oct, r++, arg); 1570c84f3f3cSopenharmony_ci shf_puts(str, opts->shf); 1571c84f3f3cSopenharmony_ci } 1572c84f3f3cSopenharmony_ci goto out; 1573c84f3f3cSopenharmony_ci } 1574c84f3f3cSopenharmony_ci 1575c84f3f3cSopenharmony_ci rows = (n + cols - 1) / cols; 1576c84f3f3cSopenharmony_ci if (opts->prefcol && cols > rows) { 1577c84f3f3cSopenharmony_ci cols = rows; 1578c84f3f3cSopenharmony_ci rows = (n + cols - 1) / cols; 1579c84f3f3cSopenharmony_ci } 1580c84f3f3cSopenharmony_ci 1581c84f3f3cSopenharmony_ci nspace = (x_cols - max_col * cols) / cols; 1582c84f3f3cSopenharmony_ci if (nspace < 2) 1583c84f3f3cSopenharmony_ci nspace = 2; 1584c84f3f3cSopenharmony_ci max_col = -max_col; 1585c84f3f3cSopenharmony_ci goto prcols_hard; 1586c84f3f3cSopenharmony_ci while (r < rows) { 1587c84f3f3cSopenharmony_ci shf_putchar(opts->linesep, opts->shf); 1588c84f3f3cSopenharmony_ci prcols_hard: 1589c84f3f3cSopenharmony_ci for (c = 0; c < cols; c++) { 1590c84f3f3cSopenharmony_ci if ((i = c * rows + r) >= n) 1591c84f3f3cSopenharmony_ci break; 1592c84f3f3cSopenharmony_ci (*func)(str, max_oct, i, arg); 1593c84f3f3cSopenharmony_ci if (i + rows >= n) 1594c84f3f3cSopenharmony_ci shf_puts(str, opts->shf); 1595c84f3f3cSopenharmony_ci else 1596c84f3f3cSopenharmony_ci shf_fprintf(opts->shf, "%*s%*s", 1597c84f3f3cSopenharmony_ci (int)max_col, str, (int)nspace, null); 1598c84f3f3cSopenharmony_ci } 1599c84f3f3cSopenharmony_ci ++r; 1600c84f3f3cSopenharmony_ci } 1601c84f3f3cSopenharmony_ci out: 1602c84f3f3cSopenharmony_ci if (opts->do_last) 1603c84f3f3cSopenharmony_ci shf_putchar(opts->linesep, opts->shf); 1604c84f3f3cSopenharmony_ci afree(str, ATEMP); 1605c84f3f3cSopenharmony_ci} 1606c84f3f3cSopenharmony_ci 1607c84f3f3cSopenharmony_ci/* strip all NUL bytes from buf; output is NUL-terminated if stripped */ 1608c84f3f3cSopenharmony_civoid 1609c84f3f3cSopenharmony_cistrip_nuls(char *buf, size_t len) 1610c84f3f3cSopenharmony_ci{ 1611c84f3f3cSopenharmony_ci char *cp, *dp, *ep; 1612c84f3f3cSopenharmony_ci 1613c84f3f3cSopenharmony_ci if (!len || !(dp = memchr(buf, '\0', len))) 1614c84f3f3cSopenharmony_ci return; 1615c84f3f3cSopenharmony_ci 1616c84f3f3cSopenharmony_ci ep = buf + len; 1617c84f3f3cSopenharmony_ci cp = dp; 1618c84f3f3cSopenharmony_ci 1619c84f3f3cSopenharmony_ci cp_has_nul_byte: 1620c84f3f3cSopenharmony_ci while (cp++ < ep && *cp == '\0') 1621c84f3f3cSopenharmony_ci ; /* nothing */ 1622c84f3f3cSopenharmony_ci while (cp < ep && *cp != '\0') 1623c84f3f3cSopenharmony_ci *dp++ = *cp++; 1624c84f3f3cSopenharmony_ci if (cp < ep) 1625c84f3f3cSopenharmony_ci goto cp_has_nul_byte; 1626c84f3f3cSopenharmony_ci 1627c84f3f3cSopenharmony_ci *dp = '\0'; 1628c84f3f3cSopenharmony_ci} 1629c84f3f3cSopenharmony_ci 1630c84f3f3cSopenharmony_ci/* 1631c84f3f3cSopenharmony_ci * Like read(2), but if read fails due to non-blocking flag, 1632c84f3f3cSopenharmony_ci * resets flag and restarts read. 1633c84f3f3cSopenharmony_ci */ 1634c84f3f3cSopenharmony_cissize_t 1635c84f3f3cSopenharmony_ciblocking_read(int fd, char *buf, size_t nbytes) 1636c84f3f3cSopenharmony_ci{ 1637c84f3f3cSopenharmony_ci ssize_t ret; 1638c84f3f3cSopenharmony_ci bool tried_reset = false; 1639c84f3f3cSopenharmony_ci 1640c84f3f3cSopenharmony_ci while ((ret = read(fd, buf, nbytes)) < 0) { 1641c84f3f3cSopenharmony_ci if (!tried_reset && errno == EAGAIN) { 1642c84f3f3cSopenharmony_ci if (reset_nonblock(fd) > 0) { 1643c84f3f3cSopenharmony_ci tried_reset = true; 1644c84f3f3cSopenharmony_ci continue; 1645c84f3f3cSopenharmony_ci } 1646c84f3f3cSopenharmony_ci errno = EAGAIN; 1647c84f3f3cSopenharmony_ci } 1648c84f3f3cSopenharmony_ci break; 1649c84f3f3cSopenharmony_ci } 1650c84f3f3cSopenharmony_ci return (ret); 1651c84f3f3cSopenharmony_ci} 1652c84f3f3cSopenharmony_ci 1653c84f3f3cSopenharmony_ci/* 1654c84f3f3cSopenharmony_ci * Reset the non-blocking flag on the specified file descriptor. 1655c84f3f3cSopenharmony_ci * Returns -1 if there was an error, 0 if non-blocking wasn't set, 1656c84f3f3cSopenharmony_ci * 1 if it was. 1657c84f3f3cSopenharmony_ci */ 1658c84f3f3cSopenharmony_ciint 1659c84f3f3cSopenharmony_cireset_nonblock(int fd) 1660c84f3f3cSopenharmony_ci{ 1661c84f3f3cSopenharmony_ci int flags; 1662c84f3f3cSopenharmony_ci 1663c84f3f3cSopenharmony_ci if ((flags = fcntl(fd, F_GETFL, 0)) < 0) 1664c84f3f3cSopenharmony_ci return (-1); 1665c84f3f3cSopenharmony_ci if (!(flags & O_NONBLOCK)) 1666c84f3f3cSopenharmony_ci return (0); 1667c84f3f3cSopenharmony_ci flags &= ~O_NONBLOCK; 1668c84f3f3cSopenharmony_ci if (fcntl(fd, F_SETFL, flags) < 0) 1669c84f3f3cSopenharmony_ci return (-1); 1670c84f3f3cSopenharmony_ci return (1); 1671c84f3f3cSopenharmony_ci} 1672c84f3f3cSopenharmony_ci 1673c84f3f3cSopenharmony_ci/* getcwd(3) equivalent, allocates from ATEMP but doesn't resize */ 1674c84f3f3cSopenharmony_cichar * 1675c84f3f3cSopenharmony_ciksh_get_wd(void) 1676c84f3f3cSopenharmony_ci{ 1677c84f3f3cSopenharmony_ci#ifdef MKSH__NO_PATH_MAX 1678c84f3f3cSopenharmony_ci char *rv, *cp; 1679c84f3f3cSopenharmony_ci 1680c84f3f3cSopenharmony_ci if ((cp = get_current_dir_name())) { 1681c84f3f3cSopenharmony_ci strdupx(rv, cp, ATEMP); 1682c84f3f3cSopenharmony_ci free_gnu_gcdn(cp); 1683c84f3f3cSopenharmony_ci } else 1684c84f3f3cSopenharmony_ci rv = NULL; 1685c84f3f3cSopenharmony_ci#else 1686c84f3f3cSopenharmony_ci char *rv; 1687c84f3f3cSopenharmony_ci 1688c84f3f3cSopenharmony_ci if (!getcwd((rv = alloc(PATH_MAX + 1, ATEMP)), PATH_MAX)) { 1689c84f3f3cSopenharmony_ci afree(rv, ATEMP); 1690c84f3f3cSopenharmony_ci rv = NULL; 1691c84f3f3cSopenharmony_ci } 1692c84f3f3cSopenharmony_ci#endif 1693c84f3f3cSopenharmony_ci 1694c84f3f3cSopenharmony_ci return (rv); 1695c84f3f3cSopenharmony_ci} 1696c84f3f3cSopenharmony_ci 1697c84f3f3cSopenharmony_ci#ifndef ELOOP 1698c84f3f3cSopenharmony_ci#define ELOOP E2BIG 1699c84f3f3cSopenharmony_ci#endif 1700c84f3f3cSopenharmony_ci 1701c84f3f3cSopenharmony_cichar * 1702c84f3f3cSopenharmony_cido_realpath(const char *upath) 1703c84f3f3cSopenharmony_ci{ 1704c84f3f3cSopenharmony_ci char *xp, *ip, *tp, *ipath, *ldest = NULL; 1705c84f3f3cSopenharmony_ci XString xs; 1706c84f3f3cSopenharmony_ci size_t pos, len; 1707c84f3f3cSopenharmony_ci int llen; 1708c84f3f3cSopenharmony_ci struct stat sb; 1709c84f3f3cSopenharmony_ci#ifdef MKSH__NO_PATH_MAX 1710c84f3f3cSopenharmony_ci size_t ldestlen = 0; 1711c84f3f3cSopenharmony_ci#define pathlen sb.st_size 1712c84f3f3cSopenharmony_ci#define pathcnd (ldestlen < (pathlen + 1)) 1713c84f3f3cSopenharmony_ci#else 1714c84f3f3cSopenharmony_ci#define pathlen PATH_MAX 1715c84f3f3cSopenharmony_ci#define pathcnd (!ldest) 1716c84f3f3cSopenharmony_ci#endif 1717c84f3f3cSopenharmony_ci /* max. recursion depth */ 1718c84f3f3cSopenharmony_ci int symlinks = 32; 1719c84f3f3cSopenharmony_ci 1720c84f3f3cSopenharmony_ci if (mksh_abspath(upath)) { 1721c84f3f3cSopenharmony_ci /* upath is an absolute pathname */ 1722c84f3f3cSopenharmony_ci strdupx(ipath, upath, ATEMP); 1723c84f3f3cSopenharmony_ci#ifdef MKSH_DOSPATH 1724c84f3f3cSopenharmony_ci } else if (mksh_drvltr(upath)) { 1725c84f3f3cSopenharmony_ci /* upath is a drive-relative pathname */ 1726c84f3f3cSopenharmony_ci if (getdrvwd(&ldest, ord(*upath))) 1727c84f3f3cSopenharmony_ci return (NULL); 1728c84f3f3cSopenharmony_ci /* A:foo -> A:/cwd/foo; A: -> A:/cwd */ 1729c84f3f3cSopenharmony_ci strpathx(ipath, ldest, upath + 2, 0); 1730c84f3f3cSopenharmony_ci#endif 1731c84f3f3cSopenharmony_ci } else { 1732c84f3f3cSopenharmony_ci /* upath is a relative pathname, prepend cwd */ 1733c84f3f3cSopenharmony_ci if ((tp = ksh_get_wd()) == NULL || !mksh_abspath(tp)) 1734c84f3f3cSopenharmony_ci return (NULL); 1735c84f3f3cSopenharmony_ci strpathx(ipath, tp, upath, 1); 1736c84f3f3cSopenharmony_ci afree(tp, ATEMP); 1737c84f3f3cSopenharmony_ci } 1738c84f3f3cSopenharmony_ci 1739c84f3f3cSopenharmony_ci /* ipath and upath are in memory at the same time -> unchecked */ 1740c84f3f3cSopenharmony_ci Xinit(xs, xp, strlen(ip = ipath) + 1, ATEMP); 1741c84f3f3cSopenharmony_ci 1742c84f3f3cSopenharmony_ci /* now jump into the deep of the loop */ 1743c84f3f3cSopenharmony_ci goto beginning_of_a_pathname; 1744c84f3f3cSopenharmony_ci 1745c84f3f3cSopenharmony_ci while (*ip) { 1746c84f3f3cSopenharmony_ci /* skip slashes in input */ 1747c84f3f3cSopenharmony_ci while (mksh_cdirsep(*ip)) 1748c84f3f3cSopenharmony_ci ++ip; 1749c84f3f3cSopenharmony_ci if (!*ip) 1750c84f3f3cSopenharmony_ci break; 1751c84f3f3cSopenharmony_ci 1752c84f3f3cSopenharmony_ci /* get next pathname component from input */ 1753c84f3f3cSopenharmony_ci tp = ip; 1754c84f3f3cSopenharmony_ci while (*ip && !mksh_cdirsep(*ip)) 1755c84f3f3cSopenharmony_ci ++ip; 1756c84f3f3cSopenharmony_ci len = ip - tp; 1757c84f3f3cSopenharmony_ci 1758c84f3f3cSopenharmony_ci /* check input for "." and ".." */ 1759c84f3f3cSopenharmony_ci if (tp[0] == '.') { 1760c84f3f3cSopenharmony_ci if (len == 1) 1761c84f3f3cSopenharmony_ci /* just continue with the next one */ 1762c84f3f3cSopenharmony_ci continue; 1763c84f3f3cSopenharmony_ci else if (len == 2 && tp[1] == '.') { 1764c84f3f3cSopenharmony_ci /* strip off last pathname component */ 1765c84f3f3cSopenharmony_ci /*XXX consider a rooted pathname */ 1766c84f3f3cSopenharmony_ci while (xp > Xstring(xs, xp)) 1767c84f3f3cSopenharmony_ci if (mksh_cdirsep(*--xp)) 1768c84f3f3cSopenharmony_ci break; 1769c84f3f3cSopenharmony_ci /* then continue with the next one */ 1770c84f3f3cSopenharmony_ci continue; 1771c84f3f3cSopenharmony_ci } 1772c84f3f3cSopenharmony_ci } 1773c84f3f3cSopenharmony_ci 1774c84f3f3cSopenharmony_ci /* store output position away, then append slash to output */ 1775c84f3f3cSopenharmony_ci pos = Xsavepos(xs, xp); 1776c84f3f3cSopenharmony_ci /* 1 for the '/' and len + 1 for tp and the NUL from below */ 1777c84f3f3cSopenharmony_ci XcheckN(xs, xp, 1 + len + 1); 1778c84f3f3cSopenharmony_ci Xput(xs, xp, '/'); 1779c84f3f3cSopenharmony_ci 1780c84f3f3cSopenharmony_ci /* append next pathname component to output */ 1781c84f3f3cSopenharmony_ci memcpy(xp, tp, len); 1782c84f3f3cSopenharmony_ci xp += len; 1783c84f3f3cSopenharmony_ci *xp = '\0'; 1784c84f3f3cSopenharmony_ci 1785c84f3f3cSopenharmony_ci /* lstat the current output, see if it's a symlink */ 1786c84f3f3cSopenharmony_ci if (mksh_lstat(Xstring(xs, xp), &sb)) { 1787c84f3f3cSopenharmony_ci /* lstat failed */ 1788c84f3f3cSopenharmony_ci if (errno == ENOENT) { 1789c84f3f3cSopenharmony_ci /* because the pathname does not exist */ 1790c84f3f3cSopenharmony_ci while (mksh_cdirsep(*ip)) 1791c84f3f3cSopenharmony_ci /* skip any trailing slashes */ 1792c84f3f3cSopenharmony_ci ++ip; 1793c84f3f3cSopenharmony_ci /* no more components left? */ 1794c84f3f3cSopenharmony_ci if (!*ip) 1795c84f3f3cSopenharmony_ci /* we can still return successfully */ 1796c84f3f3cSopenharmony_ci break; 1797c84f3f3cSopenharmony_ci /* more components left? fall through */ 1798c84f3f3cSopenharmony_ci } 1799c84f3f3cSopenharmony_ci /* not ENOENT or not at the end of ipath */ 1800c84f3f3cSopenharmony_ci goto notfound; 1801c84f3f3cSopenharmony_ci } 1802c84f3f3cSopenharmony_ci 1803c84f3f3cSopenharmony_ci /* check if we encountered a symlink? */ 1804c84f3f3cSopenharmony_ci if (S_ISLNK(sb.st_mode)) { 1805c84f3f3cSopenharmony_ci#ifndef MKSH__NO_SYMLINK 1806c84f3f3cSopenharmony_ci /* reached maximum recursion depth? */ 1807c84f3f3cSopenharmony_ci if (!symlinks--) { 1808c84f3f3cSopenharmony_ci /* yep, prevent infinite loops */ 1809c84f3f3cSopenharmony_ci errno = ELOOP; 1810c84f3f3cSopenharmony_ci goto notfound; 1811c84f3f3cSopenharmony_ci } 1812c84f3f3cSopenharmony_ci 1813c84f3f3cSopenharmony_ci /* get symlink(7) target */ 1814c84f3f3cSopenharmony_ci if (pathcnd) { 1815c84f3f3cSopenharmony_ci#ifdef MKSH__NO_PATH_MAX 1816c84f3f3cSopenharmony_ci if (notoktoadd(pathlen, 1)) { 1817c84f3f3cSopenharmony_ci errno = ENAMETOOLONG; 1818c84f3f3cSopenharmony_ci goto notfound; 1819c84f3f3cSopenharmony_ci } 1820c84f3f3cSopenharmony_ci#endif 1821c84f3f3cSopenharmony_ci ldest = aresize(ldest, pathlen + 1, ATEMP); 1822c84f3f3cSopenharmony_ci } 1823c84f3f3cSopenharmony_ci llen = readlink(Xstring(xs, xp), ldest, pathlen); 1824c84f3f3cSopenharmony_ci if (llen < 0) 1825c84f3f3cSopenharmony_ci /* oops... */ 1826c84f3f3cSopenharmony_ci goto notfound; 1827c84f3f3cSopenharmony_ci ldest[llen] = '\0'; 1828c84f3f3cSopenharmony_ci 1829c84f3f3cSopenharmony_ci /* 1830c84f3f3cSopenharmony_ci * restart if symlink target is an absolute path, 1831c84f3f3cSopenharmony_ci * otherwise continue with currently resolved prefix 1832c84f3f3cSopenharmony_ci */ 1833c84f3f3cSopenharmony_ci#ifdef MKSH_DOSPATH 1834c84f3f3cSopenharmony_ci assemble_symlink: 1835c84f3f3cSopenharmony_ci#endif 1836c84f3f3cSopenharmony_ci /* append rest of current input path to link target */ 1837c84f3f3cSopenharmony_ci strpathx(tp, ldest, ip, 0); 1838c84f3f3cSopenharmony_ci afree(ipath, ATEMP); 1839c84f3f3cSopenharmony_ci ip = ipath = tp; 1840c84f3f3cSopenharmony_ci if (!mksh_abspath(ipath)) { 1841c84f3f3cSopenharmony_ci#ifdef MKSH_DOSPATH 1842c84f3f3cSopenharmony_ci /* symlink target might be drive-relative */ 1843c84f3f3cSopenharmony_ci if (mksh_drvltr(ipath)) { 1844c84f3f3cSopenharmony_ci if (getdrvwd(&ldest, ord(*ipath))) 1845c84f3f3cSopenharmony_ci goto notfound; 1846c84f3f3cSopenharmony_ci ip += 2; 1847c84f3f3cSopenharmony_ci goto assemble_symlink; 1848c84f3f3cSopenharmony_ci } 1849c84f3f3cSopenharmony_ci#endif 1850c84f3f3cSopenharmony_ci /* symlink target is a relative path */ 1851c84f3f3cSopenharmony_ci xp = Xrestpos(xs, xp, pos); 1852c84f3f3cSopenharmony_ci } else 1853c84f3f3cSopenharmony_ci#endif 1854c84f3f3cSopenharmony_ci { 1855c84f3f3cSopenharmony_ci /* symlink target is an absolute path */ 1856c84f3f3cSopenharmony_ci xp = Xstring(xs, xp); 1857c84f3f3cSopenharmony_ci beginning_of_a_pathname: 1858c84f3f3cSopenharmony_ci /* assert: mksh_abspath(ip == ipath) */ 1859c84f3f3cSopenharmony_ci /* assert: xp == xs.beg => start of path */ 1860c84f3f3cSopenharmony_ci 1861c84f3f3cSopenharmony_ci /* exactly two leading slashes? (SUSv4 3.266) */ 1862c84f3f3cSopenharmony_ci if (ip[1] == ip[0] && !mksh_cdirsep(ip[2])) { 1863c84f3f3cSopenharmony_ci /* keep them, e.g. for UNC pathnames */ 1864c84f3f3cSopenharmony_ci Xput(xs, xp, '/'); 1865c84f3f3cSopenharmony_ci } 1866c84f3f3cSopenharmony_ci#ifdef MKSH_DOSPATH 1867c84f3f3cSopenharmony_ci /* drive letter? */ 1868c84f3f3cSopenharmony_ci if (mksh_drvltr(ip)) { 1869c84f3f3cSopenharmony_ci /* keep it */ 1870c84f3f3cSopenharmony_ci Xput(xs, xp, *ip++); 1871c84f3f3cSopenharmony_ci Xput(xs, xp, *ip++); 1872c84f3f3cSopenharmony_ci } 1873c84f3f3cSopenharmony_ci#endif 1874c84f3f3cSopenharmony_ci } 1875c84f3f3cSopenharmony_ci } 1876c84f3f3cSopenharmony_ci /* otherwise (no symlink) merely go on */ 1877c84f3f3cSopenharmony_ci } 1878c84f3f3cSopenharmony_ci 1879c84f3f3cSopenharmony_ci /* 1880c84f3f3cSopenharmony_ci * either found the target and successfully resolved it, 1881c84f3f3cSopenharmony_ci * or found its parent directory and may create it 1882c84f3f3cSopenharmony_ci */ 1883c84f3f3cSopenharmony_ci if (Xlength(xs, xp) == 0) 1884c84f3f3cSopenharmony_ci /* 1885c84f3f3cSopenharmony_ci * if the resolved pathname is "", make it "/", 1886c84f3f3cSopenharmony_ci * otherwise do not add a trailing slash 1887c84f3f3cSopenharmony_ci */ 1888c84f3f3cSopenharmony_ci Xput(xs, xp, '/'); 1889c84f3f3cSopenharmony_ci Xput(xs, xp, '\0'); 1890c84f3f3cSopenharmony_ci 1891c84f3f3cSopenharmony_ci /* 1892c84f3f3cSopenharmony_ci * if source path had a trailing slash, check if target path 1893c84f3f3cSopenharmony_ci * is not a non-directory existing file 1894c84f3f3cSopenharmony_ci */ 1895c84f3f3cSopenharmony_ci if (ip > ipath && mksh_cdirsep(ip[-1])) { 1896c84f3f3cSopenharmony_ci if (stat(Xstring(xs, xp), &sb)) { 1897c84f3f3cSopenharmony_ci if (errno != ENOENT) 1898c84f3f3cSopenharmony_ci goto notfound; 1899c84f3f3cSopenharmony_ci } else if (!S_ISDIR(sb.st_mode)) { 1900c84f3f3cSopenharmony_ci errno = ENOTDIR; 1901c84f3f3cSopenharmony_ci goto notfound; 1902c84f3f3cSopenharmony_ci } 1903c84f3f3cSopenharmony_ci /* target now either does not exist or is a directory */ 1904c84f3f3cSopenharmony_ci } 1905c84f3f3cSopenharmony_ci 1906c84f3f3cSopenharmony_ci /* return target path */ 1907c84f3f3cSopenharmony_ci afree(ldest, ATEMP); 1908c84f3f3cSopenharmony_ci afree(ipath, ATEMP); 1909c84f3f3cSopenharmony_ci return (Xclose(xs, xp)); 1910c84f3f3cSopenharmony_ci 1911c84f3f3cSopenharmony_ci notfound: 1912c84f3f3cSopenharmony_ci /* save; freeing memory might trash it */ 1913c84f3f3cSopenharmony_ci llen = errno; 1914c84f3f3cSopenharmony_ci afree(ldest, ATEMP); 1915c84f3f3cSopenharmony_ci afree(ipath, ATEMP); 1916c84f3f3cSopenharmony_ci Xfree(xs, xp); 1917c84f3f3cSopenharmony_ci errno = llen; 1918c84f3f3cSopenharmony_ci return (NULL); 1919c84f3f3cSopenharmony_ci 1920c84f3f3cSopenharmony_ci#undef pathlen 1921c84f3f3cSopenharmony_ci#undef pathcnd 1922c84f3f3cSopenharmony_ci} 1923c84f3f3cSopenharmony_ci 1924c84f3f3cSopenharmony_ci/** 1925c84f3f3cSopenharmony_ci * Makes a filename into result using the following algorithm. 1926c84f3f3cSopenharmony_ci * - make result NULL 1927c84f3f3cSopenharmony_ci * - if file starts with '/', append file to result & set cdpathp to NULL 1928c84f3f3cSopenharmony_ci * - if file starts with ./ or ../ append cwd and file to result 1929c84f3f3cSopenharmony_ci * and set cdpathp to NULL 1930c84f3f3cSopenharmony_ci * - if the first element of cdpathp doesn't start with a '/' xx or '.' xx 1931c84f3f3cSopenharmony_ci * then cwd is appended to result. 1932c84f3f3cSopenharmony_ci * - the first element of cdpathp is appended to result 1933c84f3f3cSopenharmony_ci * - file is appended to result 1934c84f3f3cSopenharmony_ci * - cdpathp is set to the start of the next element in cdpathp (or NULL 1935c84f3f3cSopenharmony_ci * if there are no more elements. 1936c84f3f3cSopenharmony_ci * The return value indicates whether a non-null element from cdpathp 1937c84f3f3cSopenharmony_ci * was appended to result. 1938c84f3f3cSopenharmony_ci */ 1939c84f3f3cSopenharmony_cistatic int 1940c84f3f3cSopenharmony_cimake_path(const char *cwd, const char *file, 1941c84f3f3cSopenharmony_ci /* pointer to colon-separated list */ 1942c84f3f3cSopenharmony_ci char **cdpathp, 1943c84f3f3cSopenharmony_ci XString *xsp, 1944c84f3f3cSopenharmony_ci int *phys_pathp) 1945c84f3f3cSopenharmony_ci{ 1946c84f3f3cSopenharmony_ci int rval = 0; 1947c84f3f3cSopenharmony_ci bool use_cdpath = true; 1948c84f3f3cSopenharmony_ci char *plist; 1949c84f3f3cSopenharmony_ci size_t len, plen = 0; 1950c84f3f3cSopenharmony_ci char *xp = Xstring(*xsp, xp); 1951c84f3f3cSopenharmony_ci 1952c84f3f3cSopenharmony_ci if (!file) 1953c84f3f3cSopenharmony_ci file = null; 1954c84f3f3cSopenharmony_ci 1955c84f3f3cSopenharmony_ci if (mksh_abspath(file)) { 1956c84f3f3cSopenharmony_ci *phys_pathp = 0; 1957c84f3f3cSopenharmony_ci use_cdpath = false; 1958c84f3f3cSopenharmony_ci } else { 1959c84f3f3cSopenharmony_ci if (file[0] == '.') { 1960c84f3f3cSopenharmony_ci char c = file[1]; 1961c84f3f3cSopenharmony_ci 1962c84f3f3cSopenharmony_ci if (c == '.') 1963c84f3f3cSopenharmony_ci c = file[2]; 1964c84f3f3cSopenharmony_ci if (mksh_cdirsep(c) || c == '\0') 1965c84f3f3cSopenharmony_ci use_cdpath = false; 1966c84f3f3cSopenharmony_ci } 1967c84f3f3cSopenharmony_ci 1968c84f3f3cSopenharmony_ci plist = *cdpathp; 1969c84f3f3cSopenharmony_ci if (!plist) 1970c84f3f3cSopenharmony_ci use_cdpath = false; 1971c84f3f3cSopenharmony_ci else if (use_cdpath) { 1972c84f3f3cSopenharmony_ci char *pend = plist; 1973c84f3f3cSopenharmony_ci 1974c84f3f3cSopenharmony_ci while (*pend && *pend != MKSH_PATHSEPC) 1975c84f3f3cSopenharmony_ci ++pend; 1976c84f3f3cSopenharmony_ci plen = pend - plist; 1977c84f3f3cSopenharmony_ci *cdpathp = *pend ? pend + 1 : NULL; 1978c84f3f3cSopenharmony_ci } 1979c84f3f3cSopenharmony_ci 1980c84f3f3cSopenharmony_ci if ((!use_cdpath || !plen || !mksh_abspath(plist)) && 1981c84f3f3cSopenharmony_ci (cwd && *cwd)) { 1982c84f3f3cSopenharmony_ci len = strlen(cwd); 1983c84f3f3cSopenharmony_ci XcheckN(*xsp, xp, len); 1984c84f3f3cSopenharmony_ci memcpy(xp, cwd, len); 1985c84f3f3cSopenharmony_ci xp += len; 1986c84f3f3cSopenharmony_ci if (mksh_cdirsep(xp[-1])) 1987c84f3f3cSopenharmony_ci xp--; 1988c84f3f3cSopenharmony_ci *xp++ = '/'; 1989c84f3f3cSopenharmony_ci } 1990c84f3f3cSopenharmony_ci *phys_pathp = Xlength(*xsp, xp); 1991c84f3f3cSopenharmony_ci if (use_cdpath && plen) { 1992c84f3f3cSopenharmony_ci XcheckN(*xsp, xp, plen); 1993c84f3f3cSopenharmony_ci memcpy(xp, plist, plen); 1994c84f3f3cSopenharmony_ci xp += plen; 1995c84f3f3cSopenharmony_ci if (mksh_cdirsep(xp[-1])) 1996c84f3f3cSopenharmony_ci xp--; 1997c84f3f3cSopenharmony_ci *xp++ = '/'; 1998c84f3f3cSopenharmony_ci rval = 1; 1999c84f3f3cSopenharmony_ci } 2000c84f3f3cSopenharmony_ci } 2001c84f3f3cSopenharmony_ci 2002c84f3f3cSopenharmony_ci len = strlen(file) + 1; 2003c84f3f3cSopenharmony_ci XcheckN(*xsp, xp, len); 2004c84f3f3cSopenharmony_ci memcpy(xp, file, len); 2005c84f3f3cSopenharmony_ci 2006c84f3f3cSopenharmony_ci if (!use_cdpath) 2007c84f3f3cSopenharmony_ci *cdpathp = NULL; 2008c84f3f3cSopenharmony_ci 2009c84f3f3cSopenharmony_ci return (rval); 2010c84f3f3cSopenharmony_ci} 2011c84f3f3cSopenharmony_ci 2012c84f3f3cSopenharmony_ci/*- 2013c84f3f3cSopenharmony_ci * Simplify pathnames containing "." and ".." entries. 2014c84f3f3cSopenharmony_ci * 2015c84f3f3cSopenharmony_ci * simplify_path(this) = that 2016c84f3f3cSopenharmony_ci * /a/b/c/./../d/.. /a/b 2017c84f3f3cSopenharmony_ci * //./C/foo/bar/../baz //C/foo/baz 2018c84f3f3cSopenharmony_ci * /foo/ /foo 2019c84f3f3cSopenharmony_ci * /foo/../../bar /bar 2020c84f3f3cSopenharmony_ci * /foo/./blah/.. /foo 2021c84f3f3cSopenharmony_ci * . . 2022c84f3f3cSopenharmony_ci * .. .. 2023c84f3f3cSopenharmony_ci * ./foo foo 2024c84f3f3cSopenharmony_ci * foo/../../../bar ../../bar 2025c84f3f3cSopenharmony_ci * C:/foo/../.. C:/ 2026c84f3f3cSopenharmony_ci * C:. C: 2027c84f3f3cSopenharmony_ci * C:.. C:.. 2028c84f3f3cSopenharmony_ci * C:foo/../../blah C:../blah 2029c84f3f3cSopenharmony_ci * 2030c84f3f3cSopenharmony_ci * XXX consider a rooted pathname: we cannot really 'cd ..' for 2031c84f3f3cSopenharmony_ci * pathnames like: '/', 'c:/', '//foo', '//foo/', '/@unixroot/' 2032c84f3f3cSopenharmony_ci * (no effect), 'c:', 'c:.' (effect is retaining the '../') but 2033c84f3f3cSopenharmony_ci * we need to honour this throughout the shell 2034c84f3f3cSopenharmony_ci */ 2035c84f3f3cSopenharmony_civoid 2036c84f3f3cSopenharmony_cisimplify_path(char *p) 2037c84f3f3cSopenharmony_ci{ 2038c84f3f3cSopenharmony_ci char *dp, *ip, *sp, *tp; 2039c84f3f3cSopenharmony_ci size_t len; 2040c84f3f3cSopenharmony_ci bool needslash; 2041c84f3f3cSopenharmony_ci#ifdef MKSH_DOSPATH 2042c84f3f3cSopenharmony_ci bool needdot = true; 2043c84f3f3cSopenharmony_ci 2044c84f3f3cSopenharmony_ci /* keep drive letter */ 2045c84f3f3cSopenharmony_ci if (mksh_drvltr(p)) { 2046c84f3f3cSopenharmony_ci p += 2; 2047c84f3f3cSopenharmony_ci needdot = false; 2048c84f3f3cSopenharmony_ci } 2049c84f3f3cSopenharmony_ci#else 2050c84f3f3cSopenharmony_ci#define needdot true 2051c84f3f3cSopenharmony_ci#endif 2052c84f3f3cSopenharmony_ci 2053c84f3f3cSopenharmony_ci switch (*p) { 2054c84f3f3cSopenharmony_ci case 0: 2055c84f3f3cSopenharmony_ci return; 2056c84f3f3cSopenharmony_ci case '/': 2057c84f3f3cSopenharmony_ci#ifdef MKSH_DOSPATH 2058c84f3f3cSopenharmony_ci case '\\': 2059c84f3f3cSopenharmony_ci#endif 2060c84f3f3cSopenharmony_ci /* exactly two leading slashes? (SUSv4 3.266) */ 2061c84f3f3cSopenharmony_ci if (p[1] == p[0] && !mksh_cdirsep(p[2])) { 2062c84f3f3cSopenharmony_ci /* keep them, e.g. for UNC pathnames */ 2063c84f3f3cSopenharmony_ci#ifdef MKSH_DOSPATH 2064c84f3f3cSopenharmony_ci *p++ = '/'; 2065c84f3f3cSopenharmony_ci#else 2066c84f3f3cSopenharmony_ci ++p; 2067c84f3f3cSopenharmony_ci#endif 2068c84f3f3cSopenharmony_ci } 2069c84f3f3cSopenharmony_ci needslash = true; 2070c84f3f3cSopenharmony_ci break; 2071c84f3f3cSopenharmony_ci default: 2072c84f3f3cSopenharmony_ci needslash = false; 2073c84f3f3cSopenharmony_ci } 2074c84f3f3cSopenharmony_ci dp = ip = sp = p; 2075c84f3f3cSopenharmony_ci 2076c84f3f3cSopenharmony_ci while (*ip) { 2077c84f3f3cSopenharmony_ci /* skip slashes in input */ 2078c84f3f3cSopenharmony_ci while (mksh_cdirsep(*ip)) 2079c84f3f3cSopenharmony_ci ++ip; 2080c84f3f3cSopenharmony_ci if (!*ip) 2081c84f3f3cSopenharmony_ci break; 2082c84f3f3cSopenharmony_ci 2083c84f3f3cSopenharmony_ci /* get next pathname component from input */ 2084c84f3f3cSopenharmony_ci tp = ip; 2085c84f3f3cSopenharmony_ci while (*ip && !mksh_cdirsep(*ip)) 2086c84f3f3cSopenharmony_ci ++ip; 2087c84f3f3cSopenharmony_ci len = ip - tp; 2088c84f3f3cSopenharmony_ci 2089c84f3f3cSopenharmony_ci /* check input for "." and ".." */ 2090c84f3f3cSopenharmony_ci if (tp[0] == '.') { 2091c84f3f3cSopenharmony_ci if (len == 1) 2092c84f3f3cSopenharmony_ci /* just continue with the next one */ 2093c84f3f3cSopenharmony_ci continue; 2094c84f3f3cSopenharmony_ci else if (len == 2 && tp[1] == '.') { 2095c84f3f3cSopenharmony_ci /* parent level, but how? (see above) */ 2096c84f3f3cSopenharmony_ci if (mksh_abspath(p)) 2097c84f3f3cSopenharmony_ci /* absolute path, only one way */ 2098c84f3f3cSopenharmony_ci goto strip_last_component; 2099c84f3f3cSopenharmony_ci else if (dp > sp) { 2100c84f3f3cSopenharmony_ci /* relative path, with subpaths */ 2101c84f3f3cSopenharmony_ci needslash = false; 2102c84f3f3cSopenharmony_ci strip_last_component: 2103c84f3f3cSopenharmony_ci /* strip off last pathname component */ 2104c84f3f3cSopenharmony_ci while (dp > sp) 2105c84f3f3cSopenharmony_ci if (mksh_cdirsep(*--dp)) 2106c84f3f3cSopenharmony_ci break; 2107c84f3f3cSopenharmony_ci } else { 2108c84f3f3cSopenharmony_ci /* relative path, at its beginning */ 2109c84f3f3cSopenharmony_ci if (needslash) 2110c84f3f3cSopenharmony_ci /* or already dotdot-slash'd */ 2111c84f3f3cSopenharmony_ci *dp++ = '/'; 2112c84f3f3cSopenharmony_ci /* keep dotdot-slash if not absolute */ 2113c84f3f3cSopenharmony_ci *dp++ = '.'; 2114c84f3f3cSopenharmony_ci *dp++ = '.'; 2115c84f3f3cSopenharmony_ci needslash = true; 2116c84f3f3cSopenharmony_ci sp = dp; 2117c84f3f3cSopenharmony_ci } 2118c84f3f3cSopenharmony_ci /* then continue with the next one */ 2119c84f3f3cSopenharmony_ci continue; 2120c84f3f3cSopenharmony_ci } 2121c84f3f3cSopenharmony_ci } 2122c84f3f3cSopenharmony_ci 2123c84f3f3cSopenharmony_ci if (needslash) 2124c84f3f3cSopenharmony_ci *dp++ = '/'; 2125c84f3f3cSopenharmony_ci 2126c84f3f3cSopenharmony_ci /* append next pathname component to output */ 2127c84f3f3cSopenharmony_ci memmove(dp, tp, len); 2128c84f3f3cSopenharmony_ci dp += len; 2129c84f3f3cSopenharmony_ci 2130c84f3f3cSopenharmony_ci /* append slash if we continue */ 2131c84f3f3cSopenharmony_ci needslash = true; 2132c84f3f3cSopenharmony_ci /* try next component */ 2133c84f3f3cSopenharmony_ci } 2134c84f3f3cSopenharmony_ci if (dp == p) { 2135c84f3f3cSopenharmony_ci /* empty path -> dot (or slash, when absolute) */ 2136c84f3f3cSopenharmony_ci if (needslash) 2137c84f3f3cSopenharmony_ci *dp++ = '/'; 2138c84f3f3cSopenharmony_ci else if (needdot) 2139c84f3f3cSopenharmony_ci *dp++ = '.'; 2140c84f3f3cSopenharmony_ci } 2141c84f3f3cSopenharmony_ci *dp = '\0'; 2142c84f3f3cSopenharmony_ci#undef needdot 2143c84f3f3cSopenharmony_ci} 2144c84f3f3cSopenharmony_ci 2145c84f3f3cSopenharmony_civoid 2146c84f3f3cSopenharmony_ciset_current_wd(const char *nwd) 2147c84f3f3cSopenharmony_ci{ 2148c84f3f3cSopenharmony_ci char *allocd = NULL; 2149c84f3f3cSopenharmony_ci 2150c84f3f3cSopenharmony_ci if (nwd == NULL) { 2151c84f3f3cSopenharmony_ci allocd = ksh_get_wd(); 2152c84f3f3cSopenharmony_ci nwd = allocd ? allocd : null; 2153c84f3f3cSopenharmony_ci } 2154c84f3f3cSopenharmony_ci 2155c84f3f3cSopenharmony_ci afree(current_wd, APERM); 2156c84f3f3cSopenharmony_ci strdupx(current_wd, nwd, APERM); 2157c84f3f3cSopenharmony_ci 2158c84f3f3cSopenharmony_ci afree(allocd, ATEMP); 2159c84f3f3cSopenharmony_ci} 2160c84f3f3cSopenharmony_ci 2161c84f3f3cSopenharmony_ciint 2162c84f3f3cSopenharmony_cic_cd(const char **wp) 2163c84f3f3cSopenharmony_ci{ 2164c84f3f3cSopenharmony_ci int optc, rv, phys_path; 2165c84f3f3cSopenharmony_ci bool physical = tobool(Flag(FPHYSICAL)); 2166c84f3f3cSopenharmony_ci /* was a node from cdpath added in? */ 2167c84f3f3cSopenharmony_ci int cdnode; 2168c84f3f3cSopenharmony_ci /* show where we went?, error for $PWD */ 2169c84f3f3cSopenharmony_ci bool printpath = false, eflag = false; 2170c84f3f3cSopenharmony_ci struct tbl *pwd_s, *oldpwd_s; 2171c84f3f3cSopenharmony_ci XString xs; 2172c84f3f3cSopenharmony_ci char *dir, *allocd = NULL, *tryp, *pwd, *cdpath; 2173c84f3f3cSopenharmony_ci 2174c84f3f3cSopenharmony_ci while ((optc = ksh_getopt(wp, &builtin_opt, "eLP")) != -1) 2175c84f3f3cSopenharmony_ci switch (optc) { 2176c84f3f3cSopenharmony_ci case 'e': 2177c84f3f3cSopenharmony_ci eflag = true; 2178c84f3f3cSopenharmony_ci break; 2179c84f3f3cSopenharmony_ci case 'L': 2180c84f3f3cSopenharmony_ci physical = false; 2181c84f3f3cSopenharmony_ci break; 2182c84f3f3cSopenharmony_ci case 'P': 2183c84f3f3cSopenharmony_ci physical = true; 2184c84f3f3cSopenharmony_ci break; 2185c84f3f3cSopenharmony_ci case '?': 2186c84f3f3cSopenharmony_ci return (2); 2187c84f3f3cSopenharmony_ci } 2188c84f3f3cSopenharmony_ci wp += builtin_opt.optind; 2189c84f3f3cSopenharmony_ci 2190c84f3f3cSopenharmony_ci if (Flag(FRESTRICTED)) { 2191c84f3f3cSopenharmony_ci bi_errorf(Tcant_cd); 2192c84f3f3cSopenharmony_ci return (2); 2193c84f3f3cSopenharmony_ci } 2194c84f3f3cSopenharmony_ci 2195c84f3f3cSopenharmony_ci pwd_s = global(TPWD); 2196c84f3f3cSopenharmony_ci oldpwd_s = global(TOLDPWD); 2197c84f3f3cSopenharmony_ci 2198c84f3f3cSopenharmony_ci if (!wp[0]) { 2199c84f3f3cSopenharmony_ci /* no arguments; go home */ 2200c84f3f3cSopenharmony_ci if ((dir = str_val(global("HOME"))) == null) { 2201c84f3f3cSopenharmony_ci bi_errorf("no home directory (HOME not set)"); 2202c84f3f3cSopenharmony_ci return (2); 2203c84f3f3cSopenharmony_ci } 2204c84f3f3cSopenharmony_ci } else if (!wp[1]) { 2205c84f3f3cSopenharmony_ci /* one argument: - or dir */ 2206c84f3f3cSopenharmony_ci if (ksh_isdash(wp[0])) { 2207c84f3f3cSopenharmony_ci dir = str_val(oldpwd_s); 2208c84f3f3cSopenharmony_ci if (dir == null) { 2209c84f3f3cSopenharmony_ci bi_errorf(Tno_OLDPWD); 2210c84f3f3cSopenharmony_ci return (2); 2211c84f3f3cSopenharmony_ci } 2212c84f3f3cSopenharmony_ci printpath = true; 2213c84f3f3cSopenharmony_ci } else { 2214c84f3f3cSopenharmony_ci strdupx(allocd, wp[0], ATEMP); 2215c84f3f3cSopenharmony_ci dir = allocd; 2216c84f3f3cSopenharmony_ci } 2217c84f3f3cSopenharmony_ci } else if (!wp[2]) { 2218c84f3f3cSopenharmony_ci /* two arguments; substitute arg1 in PWD for arg2 */ 2219c84f3f3cSopenharmony_ci size_t ilen, olen, nlen, elen; 2220c84f3f3cSopenharmony_ci char *cp; 2221c84f3f3cSopenharmony_ci 2222c84f3f3cSopenharmony_ci if (!current_wd[0]) { 2223c84f3f3cSopenharmony_ci bi_errorf("can't determine current directory"); 2224c84f3f3cSopenharmony_ci return (2); 2225c84f3f3cSopenharmony_ci } 2226c84f3f3cSopenharmony_ci /* 2227c84f3f3cSopenharmony_ci * Substitute arg1 for arg2 in current path. If the first 2228c84f3f3cSopenharmony_ci * substitution fails because the cd fails we could try to 2229c84f3f3cSopenharmony_ci * find another substitution. For now, we don't. 2230c84f3f3cSopenharmony_ci */ 2231c84f3f3cSopenharmony_ci if ((cp = strstr(current_wd, wp[0])) == NULL) { 2232c84f3f3cSopenharmony_ci bi_errorf(Tbadsubst); 2233c84f3f3cSopenharmony_ci return (2); 2234c84f3f3cSopenharmony_ci } 2235c84f3f3cSopenharmony_ci /*- 2236c84f3f3cSopenharmony_ci * ilen = part of current_wd before wp[0] 2237c84f3f3cSopenharmony_ci * elen = part of current_wd after wp[0] 2238c84f3f3cSopenharmony_ci * because current_wd and wp[1] need to be in memory at the 2239c84f3f3cSopenharmony_ci * same time beforehand the addition can stay unchecked 2240c84f3f3cSopenharmony_ci */ 2241c84f3f3cSopenharmony_ci ilen = cp - current_wd; 2242c84f3f3cSopenharmony_ci olen = strlen(wp[0]); 2243c84f3f3cSopenharmony_ci nlen = strlen(wp[1]); 2244c84f3f3cSopenharmony_ci elen = strlen(current_wd + ilen + olen) + 1; 2245c84f3f3cSopenharmony_ci dir = allocd = alloc(ilen + nlen + elen, ATEMP); 2246c84f3f3cSopenharmony_ci memcpy(dir, current_wd, ilen); 2247c84f3f3cSopenharmony_ci memcpy(dir + ilen, wp[1], nlen); 2248c84f3f3cSopenharmony_ci memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen); 2249c84f3f3cSopenharmony_ci printpath = true; 2250c84f3f3cSopenharmony_ci } else { 2251c84f3f3cSopenharmony_ci bi_errorf(Ttoo_many_args); 2252c84f3f3cSopenharmony_ci return (2); 2253c84f3f3cSopenharmony_ci } 2254c84f3f3cSopenharmony_ci 2255c84f3f3cSopenharmony_ci#ifdef MKSH_DOSPATH 2256c84f3f3cSopenharmony_ci tryp = NULL; 2257c84f3f3cSopenharmony_ci if (mksh_drvltr(dir) && !mksh_cdirsep(dir[2]) && 2258c84f3f3cSopenharmony_ci !getdrvwd(&tryp, ord(*dir))) { 2259c84f3f3cSopenharmony_ci strpathx(dir, tryp, dir + 2, 0); 2260c84f3f3cSopenharmony_ci afree(tryp, ATEMP); 2261c84f3f3cSopenharmony_ci afree(allocd, ATEMP); 2262c84f3f3cSopenharmony_ci allocd = dir; 2263c84f3f3cSopenharmony_ci } 2264c84f3f3cSopenharmony_ci#endif 2265c84f3f3cSopenharmony_ci 2266c84f3f3cSopenharmony_ci#ifdef MKSH__NO_PATH_MAX 2267c84f3f3cSopenharmony_ci /* only a first guess; make_path will enlarge xs if necessary */ 2268c84f3f3cSopenharmony_ci XinitN(xs, 1024, ATEMP); 2269c84f3f3cSopenharmony_ci#else 2270c84f3f3cSopenharmony_ci XinitN(xs, PATH_MAX, ATEMP); 2271c84f3f3cSopenharmony_ci#endif 2272c84f3f3cSopenharmony_ci 2273c84f3f3cSopenharmony_ci cdpath = str_val(global("CDPATH")); 2274c84f3f3cSopenharmony_ci do { 2275c84f3f3cSopenharmony_ci cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path); 2276c84f3f3cSopenharmony_ci if (physical) 2277c84f3f3cSopenharmony_ci rv = chdir(tryp = Xstring(xs, xp) + phys_path); 2278c84f3f3cSopenharmony_ci else { 2279c84f3f3cSopenharmony_ci simplify_path(Xstring(xs, xp)); 2280c84f3f3cSopenharmony_ci rv = chdir(tryp = Xstring(xs, xp)); 2281c84f3f3cSopenharmony_ci } 2282c84f3f3cSopenharmony_ci } while (rv < 0 && cdpath != NULL); 2283c84f3f3cSopenharmony_ci 2284c84f3f3cSopenharmony_ci if (rv < 0) { 2285c84f3f3cSopenharmony_ci if (cdnode) 2286c84f3f3cSopenharmony_ci bi_errorf(Tf_sD_s, dir, "bad directory"); 2287c84f3f3cSopenharmony_ci else 2288c84f3f3cSopenharmony_ci bi_errorf(Tf_sD_s, tryp, cstrerror(errno)); 2289c84f3f3cSopenharmony_ci afree(allocd, ATEMP); 2290c84f3f3cSopenharmony_ci Xfree(xs, xp); 2291c84f3f3cSopenharmony_ci return (2); 2292c84f3f3cSopenharmony_ci } 2293c84f3f3cSopenharmony_ci 2294c84f3f3cSopenharmony_ci rv = 0; 2295c84f3f3cSopenharmony_ci 2296c84f3f3cSopenharmony_ci /* allocd (above) => dir, which is no longer used */ 2297c84f3f3cSopenharmony_ci afree(allocd, ATEMP); 2298c84f3f3cSopenharmony_ci allocd = NULL; 2299c84f3f3cSopenharmony_ci 2300c84f3f3cSopenharmony_ci /* Clear out tracked aliases with relative paths */ 2301c84f3f3cSopenharmony_ci flushcom(false); 2302c84f3f3cSopenharmony_ci 2303c84f3f3cSopenharmony_ci /* 2304c84f3f3cSopenharmony_ci * Set OLDPWD (note: unsetting OLDPWD does not disable this 2305c84f3f3cSopenharmony_ci * setting in AT&T ksh) 2306c84f3f3cSopenharmony_ci */ 2307c84f3f3cSopenharmony_ci if (current_wd[0]) 2308c84f3f3cSopenharmony_ci /* Ignore failure (happens if readonly or integer) */ 2309c84f3f3cSopenharmony_ci setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR); 2310c84f3f3cSopenharmony_ci 2311c84f3f3cSopenharmony_ci if (!mksh_abspath(Xstring(xs, xp))) { 2312c84f3f3cSopenharmony_ci pwd = NULL; 2313c84f3f3cSopenharmony_ci } else if (!physical) { 2314c84f3f3cSopenharmony_ci goto norealpath_PWD; 2315c84f3f3cSopenharmony_ci } else if ((pwd = allocd = do_realpath(Xstring(xs, xp))) == NULL) { 2316c84f3f3cSopenharmony_ci if (eflag) 2317c84f3f3cSopenharmony_ci rv = 1; 2318c84f3f3cSopenharmony_ci norealpath_PWD: 2319c84f3f3cSopenharmony_ci pwd = Xstring(xs, xp); 2320c84f3f3cSopenharmony_ci } 2321c84f3f3cSopenharmony_ci 2322c84f3f3cSopenharmony_ci /* Set PWD */ 2323c84f3f3cSopenharmony_ci if (pwd) { 2324c84f3f3cSopenharmony_ci char *ptmp = pwd; 2325c84f3f3cSopenharmony_ci 2326c84f3f3cSopenharmony_ci set_current_wd(ptmp); 2327c84f3f3cSopenharmony_ci /* Ignore failure (happens if readonly or integer) */ 2328c84f3f3cSopenharmony_ci setstr(pwd_s, ptmp, KSH_RETURN_ERROR); 2329c84f3f3cSopenharmony_ci } else { 2330c84f3f3cSopenharmony_ci set_current_wd(null); 2331c84f3f3cSopenharmony_ci pwd = Xstring(xs, xp); 2332c84f3f3cSopenharmony_ci /* XXX unset $PWD? */ 2333c84f3f3cSopenharmony_ci if (eflag) 2334c84f3f3cSopenharmony_ci rv = 1; 2335c84f3f3cSopenharmony_ci } 2336c84f3f3cSopenharmony_ci if (printpath || cdnode) 2337c84f3f3cSopenharmony_ci shprintf(Tf_sN, pwd); 2338c84f3f3cSopenharmony_ci 2339c84f3f3cSopenharmony_ci afree(allocd, ATEMP); 2340c84f3f3cSopenharmony_ci Xfree(xs, xp); 2341c84f3f3cSopenharmony_ci return (rv); 2342c84f3f3cSopenharmony_ci} 2343c84f3f3cSopenharmony_ci 2344c84f3f3cSopenharmony_ci 2345c84f3f3cSopenharmony_ci#ifdef KSH_CHVT_CODE 2346c84f3f3cSopenharmony_ciextern void chvt_reinit(void); 2347c84f3f3cSopenharmony_ci 2348c84f3f3cSopenharmony_cistatic void 2349c84f3f3cSopenharmony_cichvt(const Getopt *go) 2350c84f3f3cSopenharmony_ci{ 2351c84f3f3cSopenharmony_ci const char *dv = go->optarg; 2352c84f3f3cSopenharmony_ci char *cp = NULL; 2353c84f3f3cSopenharmony_ci int fd; 2354c84f3f3cSopenharmony_ci 2355c84f3f3cSopenharmony_ci switch (*dv) { 2356c84f3f3cSopenharmony_ci case '-': 2357c84f3f3cSopenharmony_ci dv = "/dev/null"; 2358c84f3f3cSopenharmony_ci break; 2359c84f3f3cSopenharmony_ci case '!': 2360c84f3f3cSopenharmony_ci ++dv; 2361c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 2362c84f3f3cSopenharmony_ci default: { 2363c84f3f3cSopenharmony_ci struct stat sb; 2364c84f3f3cSopenharmony_ci 2365c84f3f3cSopenharmony_ci if (stat(dv, &sb)) { 2366c84f3f3cSopenharmony_ci cp = shf_smprintf("/dev/ttyC%s", dv); 2367c84f3f3cSopenharmony_ci dv = cp; 2368c84f3f3cSopenharmony_ci if (stat(dv, &sb)) { 2369c84f3f3cSopenharmony_ci memmove(cp + 1, cp, /* /dev/tty */ 8); 2370c84f3f3cSopenharmony_ci dv = cp + 1; 2371c84f3f3cSopenharmony_ci if (stat(dv, &sb)) { 2372c84f3f3cSopenharmony_ci errorf(Tf_sD_sD_s, "chvt", 2373c84f3f3cSopenharmony_ci "can't find tty", go->optarg); 2374c84f3f3cSopenharmony_ci } 2375c84f3f3cSopenharmony_ci } 2376c84f3f3cSopenharmony_ci } 2377c84f3f3cSopenharmony_ci if (!(sb.st_mode & S_IFCHR)) 2378c84f3f3cSopenharmony_ci errorf(Tf_sD_sD_s, "chvt", "not a char device", dv); 2379c84f3f3cSopenharmony_ci#ifndef MKSH_DISABLE_REVOKE_WARNING 2380c84f3f3cSopenharmony_ci#if HAVE_REVOKE 2381c84f3f3cSopenharmony_ci if (revoke(dv)) 2382c84f3f3cSopenharmony_ci#endif 2383c84f3f3cSopenharmony_ci warningf(false, Tf_sD_s_s, "chvt", 2384c84f3f3cSopenharmony_ci "new shell is potentially insecure, can't revoke", 2385c84f3f3cSopenharmony_ci dv); 2386c84f3f3cSopenharmony_ci#endif 2387c84f3f3cSopenharmony_ci } 2388c84f3f3cSopenharmony_ci } 2389c84f3f3cSopenharmony_ci if ((fd = binopen2(dv, O_RDWR)) < 0) { 2390c84f3f3cSopenharmony_ci sleep(1); 2391c84f3f3cSopenharmony_ci if ((fd = binopen2(dv, O_RDWR)) < 0) { 2392c84f3f3cSopenharmony_ci errorf(Tf_sD_s_s, "chvt", Tcant_open, dv); 2393c84f3f3cSopenharmony_ci } 2394c84f3f3cSopenharmony_ci } 2395c84f3f3cSopenharmony_ci if (go->optarg[0] != '!') { 2396c84f3f3cSopenharmony_ci switch (fork()) { 2397c84f3f3cSopenharmony_ci case -1: 2398c84f3f3cSopenharmony_ci errorf(Tf_sD_s_s, "chvt", "fork", "failed"); 2399c84f3f3cSopenharmony_ci case 0: 2400c84f3f3cSopenharmony_ci break; 2401c84f3f3cSopenharmony_ci default: 2402c84f3f3cSopenharmony_ci exit(0); 2403c84f3f3cSopenharmony_ci } 2404c84f3f3cSopenharmony_ci } 2405c84f3f3cSopenharmony_ci if (setsid() == -1) 2406c84f3f3cSopenharmony_ci errorf(Tf_sD_s_s, "chvt", "setsid", "failed"); 2407c84f3f3cSopenharmony_ci if (go->optarg[0] != '-') { 2408c84f3f3cSopenharmony_ci if (ioctl(fd, TIOCSCTTY, NULL) == -1) 2409c84f3f3cSopenharmony_ci errorf(Tf_sD_s_s, "chvt", "TIOCSCTTY", "failed"); 2410c84f3f3cSopenharmony_ci if (tcflush(fd, TCIOFLUSH)) 2411c84f3f3cSopenharmony_ci errorf(Tf_sD_s_s, "chvt", "TCIOFLUSH", "failed"); 2412c84f3f3cSopenharmony_ci } 2413c84f3f3cSopenharmony_ci ksh_dup2(fd, 0, false); 2414c84f3f3cSopenharmony_ci ksh_dup2(fd, 1, false); 2415c84f3f3cSopenharmony_ci ksh_dup2(fd, 2, false); 2416c84f3f3cSopenharmony_ci if (fd > 2) 2417c84f3f3cSopenharmony_ci close(fd); 2418c84f3f3cSopenharmony_ci rndset((unsigned long)chvt_rndsetup(go, sizeof(Getopt))); 2419c84f3f3cSopenharmony_ci chvt_reinit(); 2420c84f3f3cSopenharmony_ci} 2421c84f3f3cSopenharmony_ci#endif 2422c84f3f3cSopenharmony_ci 2423c84f3f3cSopenharmony_ci#ifdef DEBUG 2424c84f3f3cSopenharmony_cichar * 2425c84f3f3cSopenharmony_cistrchr(char *p, int ch) 2426c84f3f3cSopenharmony_ci{ 2427c84f3f3cSopenharmony_ci for (;; ++p) { 2428c84f3f3cSopenharmony_ci if (*p == ch) 2429c84f3f3cSopenharmony_ci return (p); 2430c84f3f3cSopenharmony_ci if (!*p) 2431c84f3f3cSopenharmony_ci return (NULL); 2432c84f3f3cSopenharmony_ci } 2433c84f3f3cSopenharmony_ci /* NOTREACHED */ 2434c84f3f3cSopenharmony_ci} 2435c84f3f3cSopenharmony_ci 2436c84f3f3cSopenharmony_cichar * 2437c84f3f3cSopenharmony_cistrstr(char *b, const char *l) 2438c84f3f3cSopenharmony_ci{ 2439c84f3f3cSopenharmony_ci char first, c; 2440c84f3f3cSopenharmony_ci size_t n; 2441c84f3f3cSopenharmony_ci 2442c84f3f3cSopenharmony_ci if ((first = *l++) == '\0') 2443c84f3f3cSopenharmony_ci return (b); 2444c84f3f3cSopenharmony_ci n = strlen(l); 2445c84f3f3cSopenharmony_ci strstr_look: 2446c84f3f3cSopenharmony_ci while ((c = *b++) != first) 2447c84f3f3cSopenharmony_ci if (c == '\0') 2448c84f3f3cSopenharmony_ci return (NULL); 2449c84f3f3cSopenharmony_ci if (strncmp(b, l, n)) 2450c84f3f3cSopenharmony_ci goto strstr_look; 2451c84f3f3cSopenharmony_ci return (b - 1); 2452c84f3f3cSopenharmony_ci} 2453c84f3f3cSopenharmony_ci#endif 2454c84f3f3cSopenharmony_ci 2455c84f3f3cSopenharmony_ci#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST) 2456c84f3f3cSopenharmony_cichar * 2457c84f3f3cSopenharmony_cistrndup_i(const char *src, size_t len, Area *ap) 2458c84f3f3cSopenharmony_ci{ 2459c84f3f3cSopenharmony_ci char *dst = NULL; 2460c84f3f3cSopenharmony_ci 2461c84f3f3cSopenharmony_ci if (src != NULL) { 2462c84f3f3cSopenharmony_ci dst = alloc(len + 1, ap); 2463c84f3f3cSopenharmony_ci memcpy(dst, src, len); 2464c84f3f3cSopenharmony_ci dst[len] = '\0'; 2465c84f3f3cSopenharmony_ci } 2466c84f3f3cSopenharmony_ci return (dst); 2467c84f3f3cSopenharmony_ci} 2468c84f3f3cSopenharmony_ci 2469c84f3f3cSopenharmony_cichar * 2470c84f3f3cSopenharmony_cistrdup_i(const char *src, Area *ap) 2471c84f3f3cSopenharmony_ci{ 2472c84f3f3cSopenharmony_ci return (src == NULL ? NULL : strndup_i(src, strlen(src), ap)); 2473c84f3f3cSopenharmony_ci} 2474c84f3f3cSopenharmony_ci#endif 2475c84f3f3cSopenharmony_ci 2476c84f3f3cSopenharmony_ci#if !HAVE_GETRUSAGE 2477c84f3f3cSopenharmony_ci#define INVTCK(r,t) do { \ 2478c84f3f3cSopenharmony_ci r.tv_usec = ((t) % (1000000 / CLK_TCK)) * (1000000 / CLK_TCK); \ 2479c84f3f3cSopenharmony_ci r.tv_sec = (t) / CLK_TCK; \ 2480c84f3f3cSopenharmony_ci} while (/* CONSTCOND */ 0) 2481c84f3f3cSopenharmony_ci 2482c84f3f3cSopenharmony_ciint 2483c84f3f3cSopenharmony_cigetrusage(int what, struct rusage *ru) 2484c84f3f3cSopenharmony_ci{ 2485c84f3f3cSopenharmony_ci struct tms tms; 2486c84f3f3cSopenharmony_ci clock_t u, s; 2487c84f3f3cSopenharmony_ci 2488c84f3f3cSopenharmony_ci if (/* ru == NULL || */ times(&tms) == (clock_t)-1) 2489c84f3f3cSopenharmony_ci return (-1); 2490c84f3f3cSopenharmony_ci 2491c84f3f3cSopenharmony_ci switch (what) { 2492c84f3f3cSopenharmony_ci case RUSAGE_SELF: 2493c84f3f3cSopenharmony_ci u = tms.tms_utime; 2494c84f3f3cSopenharmony_ci s = tms.tms_stime; 2495c84f3f3cSopenharmony_ci break; 2496c84f3f3cSopenharmony_ci case RUSAGE_CHILDREN: 2497c84f3f3cSopenharmony_ci u = tms.tms_cutime; 2498c84f3f3cSopenharmony_ci s = tms.tms_cstime; 2499c84f3f3cSopenharmony_ci break; 2500c84f3f3cSopenharmony_ci default: 2501c84f3f3cSopenharmony_ci errno = EINVAL; 2502c84f3f3cSopenharmony_ci return (-1); 2503c84f3f3cSopenharmony_ci } 2504c84f3f3cSopenharmony_ci INVTCK(ru->ru_utime, u); 2505c84f3f3cSopenharmony_ci INVTCK(ru->ru_stime, s); 2506c84f3f3cSopenharmony_ci return (0); 2507c84f3f3cSopenharmony_ci} 2508c84f3f3cSopenharmony_ci#endif 2509c84f3f3cSopenharmony_ci 2510c84f3f3cSopenharmony_ci/* 2511c84f3f3cSopenharmony_ci * process the string available via fg (get a char) 2512c84f3f3cSopenharmony_ci * and fp (put back a char) for backslash escapes, 2513c84f3f3cSopenharmony_ci * assuming the first call to *fg gets the char di- 2514c84f3f3cSopenharmony_ci * rectly after the backslash; return the character 2515c84f3f3cSopenharmony_ci * (0..0xFF), UCS (wc + 0x100), or -1 if no known 2516c84f3f3cSopenharmony_ci * escape sequence was found 2517c84f3f3cSopenharmony_ci */ 2518c84f3f3cSopenharmony_ciint 2519c84f3f3cSopenharmony_ciunbksl(bool cstyle, int (*fg)(void), void (*fp)(int)) 2520c84f3f3cSopenharmony_ci{ 2521c84f3f3cSopenharmony_ci int wc, i, c, fc, n; 2522c84f3f3cSopenharmony_ci 2523c84f3f3cSopenharmony_ci fc = (*fg)(); 2524c84f3f3cSopenharmony_ci switch (fc) { 2525c84f3f3cSopenharmony_ci case 'a': 2526c84f3f3cSopenharmony_ci wc = KSH_BEL; 2527c84f3f3cSopenharmony_ci break; 2528c84f3f3cSopenharmony_ci case 'b': 2529c84f3f3cSopenharmony_ci wc = '\b'; 2530c84f3f3cSopenharmony_ci break; 2531c84f3f3cSopenharmony_ci case 'c': 2532c84f3f3cSopenharmony_ci if (!cstyle) 2533c84f3f3cSopenharmony_ci goto unknown_escape; 2534c84f3f3cSopenharmony_ci c = (*fg)(); 2535c84f3f3cSopenharmony_ci wc = ksh_toctrl(c); 2536c84f3f3cSopenharmony_ci break; 2537c84f3f3cSopenharmony_ci case 'E': 2538c84f3f3cSopenharmony_ci case 'e': 2539c84f3f3cSopenharmony_ci wc = KSH_ESC; 2540c84f3f3cSopenharmony_ci break; 2541c84f3f3cSopenharmony_ci case 'f': 2542c84f3f3cSopenharmony_ci wc = '\f'; 2543c84f3f3cSopenharmony_ci break; 2544c84f3f3cSopenharmony_ci case 'n': 2545c84f3f3cSopenharmony_ci wc = '\n'; 2546c84f3f3cSopenharmony_ci break; 2547c84f3f3cSopenharmony_ci case 'r': 2548c84f3f3cSopenharmony_ci wc = '\r'; 2549c84f3f3cSopenharmony_ci break; 2550c84f3f3cSopenharmony_ci case 't': 2551c84f3f3cSopenharmony_ci wc = '\t'; 2552c84f3f3cSopenharmony_ci break; 2553c84f3f3cSopenharmony_ci case 'v': 2554c84f3f3cSopenharmony_ci wc = KSH_VTAB; 2555c84f3f3cSopenharmony_ci break; 2556c84f3f3cSopenharmony_ci case '1': 2557c84f3f3cSopenharmony_ci case '2': 2558c84f3f3cSopenharmony_ci case '3': 2559c84f3f3cSopenharmony_ci case '4': 2560c84f3f3cSopenharmony_ci case '5': 2561c84f3f3cSopenharmony_ci case '6': 2562c84f3f3cSopenharmony_ci case '7': 2563c84f3f3cSopenharmony_ci if (!cstyle) 2564c84f3f3cSopenharmony_ci goto unknown_escape; 2565c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 2566c84f3f3cSopenharmony_ci case '0': 2567c84f3f3cSopenharmony_ci if (cstyle) 2568c84f3f3cSopenharmony_ci (*fp)(fc); 2569c84f3f3cSopenharmony_ci /* 2570c84f3f3cSopenharmony_ci * look for an octal number with up to three 2571c84f3f3cSopenharmony_ci * digits, not counting the leading zero; 2572c84f3f3cSopenharmony_ci * convert it to a raw octet 2573c84f3f3cSopenharmony_ci */ 2574c84f3f3cSopenharmony_ci wc = 0; 2575c84f3f3cSopenharmony_ci i = 3; 2576c84f3f3cSopenharmony_ci while (i--) 2577c84f3f3cSopenharmony_ci if (ctype((c = (*fg)()), C_OCTAL)) 2578c84f3f3cSopenharmony_ci wc = (wc << 3) + ksh_numdig(c); 2579c84f3f3cSopenharmony_ci else { 2580c84f3f3cSopenharmony_ci (*fp)(c); 2581c84f3f3cSopenharmony_ci break; 2582c84f3f3cSopenharmony_ci } 2583c84f3f3cSopenharmony_ci break; 2584c84f3f3cSopenharmony_ci case 'U': 2585c84f3f3cSopenharmony_ci i = 8; 2586c84f3f3cSopenharmony_ci if (/* CONSTCOND */ 0) 2587c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 2588c84f3f3cSopenharmony_ci case 'u': 2589c84f3f3cSopenharmony_ci i = 4; 2590c84f3f3cSopenharmony_ci if (/* CONSTCOND */ 0) 2591c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 2592c84f3f3cSopenharmony_ci case 'x': 2593c84f3f3cSopenharmony_ci i = cstyle ? -1 : 2; 2594c84f3f3cSopenharmony_ci /** 2595c84f3f3cSopenharmony_ci * x: look for a hexadecimal number with up to 2596c84f3f3cSopenharmony_ci * two (C style: arbitrary) digits; convert 2597c84f3f3cSopenharmony_ci * to raw octet (C style: UCS if >0xFF) 2598c84f3f3cSopenharmony_ci * u/U: look for a hexadecimal number with up to 2599c84f3f3cSopenharmony_ci * four (U: eight) digits; convert to UCS 2600c84f3f3cSopenharmony_ci */ 2601c84f3f3cSopenharmony_ci wc = 0; 2602c84f3f3cSopenharmony_ci n = 0; 2603c84f3f3cSopenharmony_ci while (n < i || i == -1) { 2604c84f3f3cSopenharmony_ci wc <<= 4; 2605c84f3f3cSopenharmony_ci if (!ctype((c = (*fg)()), C_SEDEC)) { 2606c84f3f3cSopenharmony_ci wc >>= 4; 2607c84f3f3cSopenharmony_ci (*fp)(c); 2608c84f3f3cSopenharmony_ci break; 2609c84f3f3cSopenharmony_ci } 2610c84f3f3cSopenharmony_ci if (ctype(c, C_DIGIT)) 2611c84f3f3cSopenharmony_ci wc += ksh_numdig(c); 2612c84f3f3cSopenharmony_ci else if (ctype(c, C_UPPER)) 2613c84f3f3cSopenharmony_ci wc += ksh_numuc(c) + 10; 2614c84f3f3cSopenharmony_ci else 2615c84f3f3cSopenharmony_ci wc += ksh_numlc(c) + 10; 2616c84f3f3cSopenharmony_ci ++n; 2617c84f3f3cSopenharmony_ci } 2618c84f3f3cSopenharmony_ci if (!n) 2619c84f3f3cSopenharmony_ci goto unknown_escape; 2620c84f3f3cSopenharmony_ci if ((cstyle && wc > 0xFF) || fc != 'x') 2621c84f3f3cSopenharmony_ci /* UCS marker */ 2622c84f3f3cSopenharmony_ci wc += 0x100; 2623c84f3f3cSopenharmony_ci break; 2624c84f3f3cSopenharmony_ci case '\'': 2625c84f3f3cSopenharmony_ci if (!cstyle) 2626c84f3f3cSopenharmony_ci goto unknown_escape; 2627c84f3f3cSopenharmony_ci wc = '\''; 2628c84f3f3cSopenharmony_ci break; 2629c84f3f3cSopenharmony_ci case '\\': 2630c84f3f3cSopenharmony_ci wc = '\\'; 2631c84f3f3cSopenharmony_ci break; 2632c84f3f3cSopenharmony_ci default: 2633c84f3f3cSopenharmony_ci unknown_escape: 2634c84f3f3cSopenharmony_ci (*fp)(fc); 2635c84f3f3cSopenharmony_ci return (-1); 2636c84f3f3cSopenharmony_ci } 2637c84f3f3cSopenharmony_ci 2638c84f3f3cSopenharmony_ci return (wc); 2639c84f3f3cSopenharmony_ci} 2640