1c84f3f3cSopenharmony_ci/* $OpenBSD: eval.c,v 1.40 2013/09/14 20:09:30 millert Exp $ */ 2c84f3f3cSopenharmony_ci 3c84f3f3cSopenharmony_ci/*- 4c84f3f3cSopenharmony_ci * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 5c84f3f3cSopenharmony_ci * 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 6c84f3f3cSopenharmony_ci * 2019, 2020 7c84f3f3cSopenharmony_ci * mirabilos <m@mirbsd.org> 8c84f3f3cSopenharmony_ci * 9c84f3f3cSopenharmony_ci * Provided that these terms and disclaimer and all copyright notices 10c84f3f3cSopenharmony_ci * are retained or reproduced in an accompanying document, permission 11c84f3f3cSopenharmony_ci * is granted to deal in this work without restriction, including un- 12c84f3f3cSopenharmony_ci * limited rights to use, publicly perform, distribute, sell, modify, 13c84f3f3cSopenharmony_ci * merge, give away, or sublicence. 14c84f3f3cSopenharmony_ci * 15c84f3f3cSopenharmony_ci * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 16c84f3f3cSopenharmony_ci * the utmost extent permitted by applicable law, neither express nor 17c84f3f3cSopenharmony_ci * implied; without malicious intent or gross negligence. In no event 18c84f3f3cSopenharmony_ci * may a licensor, author or contributor be held liable for indirect, 19c84f3f3cSopenharmony_ci * direct, other damage, loss, or other issues arising in any way out 20c84f3f3cSopenharmony_ci * of dealing in the work, even if advised of the possibility of such 21c84f3f3cSopenharmony_ci * damage or existence of a defect, except proven that it results out 22c84f3f3cSopenharmony_ci * of said person's immediate fault when using the work as intended. 23c84f3f3cSopenharmony_ci */ 24c84f3f3cSopenharmony_ci 25c84f3f3cSopenharmony_ci#include "sh.h" 26c84f3f3cSopenharmony_ci 27c84f3f3cSopenharmony_ci__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.231 2020/05/05 21:34:27 tg Exp $"); 28c84f3f3cSopenharmony_ci 29c84f3f3cSopenharmony_ci/* 30c84f3f3cSopenharmony_ci * string expansion 31c84f3f3cSopenharmony_ci * 32c84f3f3cSopenharmony_ci * first pass: quoting, IFS separation, ~, ${}, $() and $(()) substitution. 33c84f3f3cSopenharmony_ci * second pass: alternation ({,}), filename expansion (*?[]). 34c84f3f3cSopenharmony_ci */ 35c84f3f3cSopenharmony_ci 36c84f3f3cSopenharmony_ci/* expansion generator state */ 37c84f3f3cSopenharmony_citypedef struct { 38c84f3f3cSopenharmony_ci /* not including an "int type;" member, see expand() */ 39c84f3f3cSopenharmony_ci /* string */ 40c84f3f3cSopenharmony_ci const char *str; 41c84f3f3cSopenharmony_ci /* source */ 42c84f3f3cSopenharmony_ci union { 43c84f3f3cSopenharmony_ci /* string[] */ 44c84f3f3cSopenharmony_ci const char **strv; 45c84f3f3cSopenharmony_ci /* file */ 46c84f3f3cSopenharmony_ci struct shf *shf; 47c84f3f3cSopenharmony_ci } u; 48c84f3f3cSopenharmony_ci /* variable in ${var...} */ 49c84f3f3cSopenharmony_ci struct tbl *var; 50c84f3f3cSopenharmony_ci /* split "$@" / call waitlast in $() */ 51c84f3f3cSopenharmony_ci bool split; 52c84f3f3cSopenharmony_ci} Expand; 53c84f3f3cSopenharmony_ci 54c84f3f3cSopenharmony_ci#define XBASE 0 /* scanning original string */ 55c84f3f3cSopenharmony_ci#define XARGSEP 1 /* ifs0 between "$*" */ 56c84f3f3cSopenharmony_ci#define XARG 2 /* expanding $*, $@ */ 57c84f3f3cSopenharmony_ci#define XCOM 3 /* expanding $() */ 58c84f3f3cSopenharmony_ci#define XNULLSUB 4 /* "$@" when $# is 0, so don't generate word */ 59c84f3f3cSopenharmony_ci#define XSUB 5 /* expanding ${} string */ 60c84f3f3cSopenharmony_ci#define XSUBMID 6 /* middle of expanding ${}; must be XSUB+1 */ 61c84f3f3cSopenharmony_ci#define XSUBPAT 7 /* expanding [[ x = ${} ]] string */ 62c84f3f3cSopenharmony_ci#define XSUBPATMID 8 /* middle, must be XSUBPAT+1 */ 63c84f3f3cSopenharmony_ci 64c84f3f3cSopenharmony_ci#define isXSUB(t) ((t) == XSUB || (t) == XSUBPAT) 65c84f3f3cSopenharmony_ci 66c84f3f3cSopenharmony_ci/* States used for field splitting */ 67c84f3f3cSopenharmony_ci#define IFS_WORD 0 /* word has chars (or quotes except "$@") */ 68c84f3f3cSopenharmony_ci#define IFS_WS 1 /* have seen IFS white-space */ 69c84f3f3cSopenharmony_ci#define IFS_NWS 2 /* have seen IFS non-white-space */ 70c84f3f3cSopenharmony_ci#define IFS_IWS 3 /* beginning of word, ignore IFS WS */ 71c84f3f3cSopenharmony_ci#define IFS_QUOTE 4 /* beg.w/quote, become IFS_WORD unless "$@" */ 72c84f3f3cSopenharmony_ci 73c84f3f3cSopenharmony_ci#define STYPE_CHAR 0xFF 74c84f3f3cSopenharmony_ci#define STYPE_DBL 0x100 75c84f3f3cSopenharmony_ci#define STYPE_AT 0x200 76c84f3f3cSopenharmony_ci#define STYPE_SINGLE 0x2FF 77c84f3f3cSopenharmony_ci#define STYPE_MASK 0x300 78c84f3f3cSopenharmony_ci 79c84f3f3cSopenharmony_cistatic int varsub(Expand *, const char *, const char *, unsigned int *, int *); 80c84f3f3cSopenharmony_cistatic int comsub(Expand *, const char *, int); 81c84f3f3cSopenharmony_cistatic char *valsub(struct op *, Area *); 82c84f3f3cSopenharmony_cistatic char *trimsub(char *, char *, int); 83c84f3f3cSopenharmony_cistatic void glob(char *, XPtrV *, bool); 84c84f3f3cSopenharmony_cistatic void globit(XString *, char **, char *, XPtrV *, int); 85c84f3f3cSopenharmony_cistatic const char *maybe_expand_tilde(const char *, XString *, char **, bool); 86c84f3f3cSopenharmony_ci#ifndef MKSH_NOPWNAM 87c84f3f3cSopenharmony_cistatic char *homedir(char *); 88c84f3f3cSopenharmony_ci#endif 89c84f3f3cSopenharmony_cistatic void alt_expand(XPtrV *, char *, char *, char *, int); 90c84f3f3cSopenharmony_cistatic int utflen(const char *) MKSH_A_PURE; 91c84f3f3cSopenharmony_cistatic void utfincptr(const char *, mksh_ari_t *); 92c84f3f3cSopenharmony_ci 93c84f3f3cSopenharmony_ci/* UTFMODE functions */ 94c84f3f3cSopenharmony_cistatic int 95c84f3f3cSopenharmony_ciutflen(const char *s) 96c84f3f3cSopenharmony_ci{ 97c84f3f3cSopenharmony_ci size_t n; 98c84f3f3cSopenharmony_ci 99c84f3f3cSopenharmony_ci if (UTFMODE) { 100c84f3f3cSopenharmony_ci n = 0; 101c84f3f3cSopenharmony_ci while (*s) { 102c84f3f3cSopenharmony_ci s += utf_ptradj(s); 103c84f3f3cSopenharmony_ci ++n; 104c84f3f3cSopenharmony_ci } 105c84f3f3cSopenharmony_ci } else 106c84f3f3cSopenharmony_ci n = strlen(s); 107c84f3f3cSopenharmony_ci 108c84f3f3cSopenharmony_ci if (n > 2147483647) 109c84f3f3cSopenharmony_ci n = 2147483647; 110c84f3f3cSopenharmony_ci return ((int)n); 111c84f3f3cSopenharmony_ci} 112c84f3f3cSopenharmony_ci 113c84f3f3cSopenharmony_cistatic void 114c84f3f3cSopenharmony_ciutfincptr(const char *s, mksh_ari_t *lp) 115c84f3f3cSopenharmony_ci{ 116c84f3f3cSopenharmony_ci const char *cp = s; 117c84f3f3cSopenharmony_ci 118c84f3f3cSopenharmony_ci while ((*lp)--) 119c84f3f3cSopenharmony_ci cp += utf_ptradj(cp); 120c84f3f3cSopenharmony_ci *lp = cp - s; 121c84f3f3cSopenharmony_ci} 122c84f3f3cSopenharmony_ci 123c84f3f3cSopenharmony_ci/* compile and expand word */ 124c84f3f3cSopenharmony_cichar * 125c84f3f3cSopenharmony_cisubstitute(const char *cp, int f) 126c84f3f3cSopenharmony_ci{ 127c84f3f3cSopenharmony_ci struct source *s, *sold; 128c84f3f3cSopenharmony_ci 129c84f3f3cSopenharmony_ci sold = source; 130c84f3f3cSopenharmony_ci s = pushs(SWSTR, ATEMP); 131c84f3f3cSopenharmony_ci s->start = s->str = cp; 132c84f3f3cSopenharmony_ci source = s; 133c84f3f3cSopenharmony_ci if (yylex(ONEWORD) != LWORD) 134c84f3f3cSopenharmony_ci internal_errorf(Tbadsubst); 135c84f3f3cSopenharmony_ci source = sold; 136c84f3f3cSopenharmony_ci afree(s, ATEMP); 137c84f3f3cSopenharmony_ci return (evalstr(yylval.cp, f)); 138c84f3f3cSopenharmony_ci} 139c84f3f3cSopenharmony_ci 140c84f3f3cSopenharmony_ci/* 141c84f3f3cSopenharmony_ci * expand arg-list 142c84f3f3cSopenharmony_ci */ 143c84f3f3cSopenharmony_cichar ** 144c84f3f3cSopenharmony_cieval(const char **ap, int f) 145c84f3f3cSopenharmony_ci{ 146c84f3f3cSopenharmony_ci XPtrV w; 147c84f3f3cSopenharmony_ci 148c84f3f3cSopenharmony_ci if (*ap == NULL) { 149c84f3f3cSopenharmony_ci union mksh_ccphack vap; 150c84f3f3cSopenharmony_ci 151c84f3f3cSopenharmony_ci vap.ro = ap; 152c84f3f3cSopenharmony_ci return (vap.rw); 153c84f3f3cSopenharmony_ci } 154c84f3f3cSopenharmony_ci XPinit(w, 32); 155c84f3f3cSopenharmony_ci /* space for shell name */ 156c84f3f3cSopenharmony_ci XPput(w, NULL); 157c84f3f3cSopenharmony_ci while (*ap != NULL) 158c84f3f3cSopenharmony_ci expand(*ap++, &w, f); 159c84f3f3cSopenharmony_ci XPput(w, NULL); 160c84f3f3cSopenharmony_ci return ((char **)XPclose(w) + 1); 161c84f3f3cSopenharmony_ci} 162c84f3f3cSopenharmony_ci 163c84f3f3cSopenharmony_ci/* 164c84f3f3cSopenharmony_ci * expand string 165c84f3f3cSopenharmony_ci */ 166c84f3f3cSopenharmony_cichar * 167c84f3f3cSopenharmony_cievalstr(const char *cp, int f) 168c84f3f3cSopenharmony_ci{ 169c84f3f3cSopenharmony_ci XPtrV w; 170c84f3f3cSopenharmony_ci char *dp = null; 171c84f3f3cSopenharmony_ci 172c84f3f3cSopenharmony_ci XPinit(w, 1); 173c84f3f3cSopenharmony_ci expand(cp, &w, f); 174c84f3f3cSopenharmony_ci if (XPsize(w)) 175c84f3f3cSopenharmony_ci dp = *XPptrv(w); 176c84f3f3cSopenharmony_ci XPfree(w); 177c84f3f3cSopenharmony_ci return (dp); 178c84f3f3cSopenharmony_ci} 179c84f3f3cSopenharmony_ci 180c84f3f3cSopenharmony_ci/* 181c84f3f3cSopenharmony_ci * expand string - return only one component 182c84f3f3cSopenharmony_ci * used from iosetup to expand redirection files 183c84f3f3cSopenharmony_ci */ 184c84f3f3cSopenharmony_cichar * 185c84f3f3cSopenharmony_cievalonestr(const char *cp, int f) 186c84f3f3cSopenharmony_ci{ 187c84f3f3cSopenharmony_ci XPtrV w; 188c84f3f3cSopenharmony_ci char *rv; 189c84f3f3cSopenharmony_ci 190c84f3f3cSopenharmony_ci XPinit(w, 1); 191c84f3f3cSopenharmony_ci expand(cp, &w, f); 192c84f3f3cSopenharmony_ci switch (XPsize(w)) { 193c84f3f3cSopenharmony_ci case 0: 194c84f3f3cSopenharmony_ci rv = null; 195c84f3f3cSopenharmony_ci break; 196c84f3f3cSopenharmony_ci case 1: 197c84f3f3cSopenharmony_ci rv = (char *) *XPptrv(w); 198c84f3f3cSopenharmony_ci break; 199c84f3f3cSopenharmony_ci default: 200c84f3f3cSopenharmony_ci rv = evalstr(cp, f & ~DOGLOB); 201c84f3f3cSopenharmony_ci break; 202c84f3f3cSopenharmony_ci } 203c84f3f3cSopenharmony_ci XPfree(w); 204c84f3f3cSopenharmony_ci return (rv); 205c84f3f3cSopenharmony_ci} 206c84f3f3cSopenharmony_ci 207c84f3f3cSopenharmony_ci/* for nested substitution: ${var:=$var2} */ 208c84f3f3cSopenharmony_citypedef struct SubType { 209c84f3f3cSopenharmony_ci struct tbl *var; /* variable for ${var..} */ 210c84f3f3cSopenharmony_ci struct SubType *prev; /* old type */ 211c84f3f3cSopenharmony_ci struct SubType *next; /* poped type (to avoid re-allocating) */ 212c84f3f3cSopenharmony_ci size_t base; /* start position of expanded word */ 213c84f3f3cSopenharmony_ci unsigned short stype; /* [=+-?%#] action after expanded word */ 214c84f3f3cSopenharmony_ci short f; /* saved value of f (DOPAT, etc) */ 215c84f3f3cSopenharmony_ci uint8_t quotep; /* saved value of quote (for ${..[%#]..}) */ 216c84f3f3cSopenharmony_ci uint8_t quotew; /* saved value of quote (for ${..[+-=]..}) */ 217c84f3f3cSopenharmony_ci} SubType; 218c84f3f3cSopenharmony_ci 219c84f3f3cSopenharmony_civoid 220c84f3f3cSopenharmony_ciexpand( 221c84f3f3cSopenharmony_ci /* input word */ 222c84f3f3cSopenharmony_ci const char *ccp, 223c84f3f3cSopenharmony_ci /* output words */ 224c84f3f3cSopenharmony_ci XPtrV *wp, 225c84f3f3cSopenharmony_ci /* DO* flags */ 226c84f3f3cSopenharmony_ci int f) 227c84f3f3cSopenharmony_ci{ 228c84f3f3cSopenharmony_ci int c = 0; 229c84f3f3cSopenharmony_ci /* expansion type */ 230c84f3f3cSopenharmony_ci int type; 231c84f3f3cSopenharmony_ci /* quoted */ 232c84f3f3cSopenharmony_ci int quote = 0; 233c84f3f3cSopenharmony_ci /* destination string and live pointer */ 234c84f3f3cSopenharmony_ci XString ds; 235c84f3f3cSopenharmony_ci char *dp; 236c84f3f3cSopenharmony_ci /* source */ 237c84f3f3cSopenharmony_ci const char *sp; 238c84f3f3cSopenharmony_ci /* second pass flags */ 239c84f3f3cSopenharmony_ci int fdo; 240c84f3f3cSopenharmony_ci /* have word */ 241c84f3f3cSopenharmony_ci int word; 242c84f3f3cSopenharmony_ci /* field splitting of parameter/command substitution */ 243c84f3f3cSopenharmony_ci int doblank; 244c84f3f3cSopenharmony_ci /* expansion variables */ 245c84f3f3cSopenharmony_ci Expand x = { 246c84f3f3cSopenharmony_ci NULL, { NULL }, NULL, 0 247c84f3f3cSopenharmony_ci }; 248c84f3f3cSopenharmony_ci SubType st_head, *st; 249c84f3f3cSopenharmony_ci /* record number of trailing newlines in COMSUB */ 250c84f3f3cSopenharmony_ci int newlines = 0; 251c84f3f3cSopenharmony_ci bool saw_eq, make_magic; 252c84f3f3cSopenharmony_ci unsigned int tilde_ok; 253c84f3f3cSopenharmony_ci size_t len; 254c84f3f3cSopenharmony_ci char *cp; 255c84f3f3cSopenharmony_ci 256c84f3f3cSopenharmony_ci if (ccp == NULL) 257c84f3f3cSopenharmony_ci internal_errorf("expand(NULL)"); 258c84f3f3cSopenharmony_ci /* for alias, readonly, set, typeset commands */ 259c84f3f3cSopenharmony_ci if ((f & DOVACHECK) && is_wdvarassign(ccp)) { 260c84f3f3cSopenharmony_ci f &= ~(DOVACHECK | DOBLANK | DOGLOB | DOTILDE); 261c84f3f3cSopenharmony_ci f |= DOASNTILDE | DOSCALAR; 262c84f3f3cSopenharmony_ci } 263c84f3f3cSopenharmony_ci if (Flag(FNOGLOB)) 264c84f3f3cSopenharmony_ci f &= ~DOGLOB; 265c84f3f3cSopenharmony_ci if (Flag(FMARKDIRS)) 266c84f3f3cSopenharmony_ci f |= DOMARKDIRS; 267c84f3f3cSopenharmony_ci if (Flag(FBRACEEXPAND) && (f & DOGLOB)) 268c84f3f3cSopenharmony_ci f |= DOBRACE; 269c84f3f3cSopenharmony_ci 270c84f3f3cSopenharmony_ci /* init destination string */ 271c84f3f3cSopenharmony_ci Xinit(ds, dp, 128, ATEMP); 272c84f3f3cSopenharmony_ci type = XBASE; 273c84f3f3cSopenharmony_ci sp = ccp; 274c84f3f3cSopenharmony_ci fdo = 0; 275c84f3f3cSopenharmony_ci saw_eq = false; 276c84f3f3cSopenharmony_ci /* must be 1/0 */ 277c84f3f3cSopenharmony_ci tilde_ok = (f & (DOTILDE | DOASNTILDE)) ? 1 : 0; 278c84f3f3cSopenharmony_ci doblank = 0; 279c84f3f3cSopenharmony_ci make_magic = false; 280c84f3f3cSopenharmony_ci word = (f&DOBLANK) ? IFS_WS : IFS_WORD; 281c84f3f3cSopenharmony_ci /* clang doesn't know OSUBST comes before CSUBST */ 282c84f3f3cSopenharmony_ci memset(&st_head, 0, sizeof(st_head)); 283c84f3f3cSopenharmony_ci st = &st_head; 284c84f3f3cSopenharmony_ci 285c84f3f3cSopenharmony_ci while (/* CONSTCOND */ 1) { 286c84f3f3cSopenharmony_ci Xcheck(ds, dp); 287c84f3f3cSopenharmony_ci 288c84f3f3cSopenharmony_ci switch (type) { 289c84f3f3cSopenharmony_ci case XBASE: 290c84f3f3cSopenharmony_ci /* original prefixed string */ 291c84f3f3cSopenharmony_ci c = ord(*sp++); 292c84f3f3cSopenharmony_ci switch (c) { 293c84f3f3cSopenharmony_ci case EOS: 294c84f3f3cSopenharmony_ci c = 0; 295c84f3f3cSopenharmony_ci break; 296c84f3f3cSopenharmony_ci case CHAR: 297c84f3f3cSopenharmony_ci c = ord(*sp++); 298c84f3f3cSopenharmony_ci break; 299c84f3f3cSopenharmony_ci case QCHAR: 300c84f3f3cSopenharmony_ci /* temporary quote */ 301c84f3f3cSopenharmony_ci quote |= 2; 302c84f3f3cSopenharmony_ci c = ord(*sp++); 303c84f3f3cSopenharmony_ci break; 304c84f3f3cSopenharmony_ci case OQUOTE: 305c84f3f3cSopenharmony_ci if (word != IFS_WORD) 306c84f3f3cSopenharmony_ci word = IFS_QUOTE; 307c84f3f3cSopenharmony_ci tilde_ok = 0; 308c84f3f3cSopenharmony_ci quote = 1; 309c84f3f3cSopenharmony_ci continue; 310c84f3f3cSopenharmony_ci case CQUOTE: 311c84f3f3cSopenharmony_ci if (word == IFS_QUOTE) 312c84f3f3cSopenharmony_ci word = IFS_WORD; 313c84f3f3cSopenharmony_ci quote = st->quotew; 314c84f3f3cSopenharmony_ci continue; 315c84f3f3cSopenharmony_ci case COMASUB: 316c84f3f3cSopenharmony_ci case COMSUB: 317c84f3f3cSopenharmony_ci case FUNASUB: 318c84f3f3cSopenharmony_ci case FUNSUB: 319c84f3f3cSopenharmony_ci case VALSUB: 320c84f3f3cSopenharmony_ci tilde_ok = 0; 321c84f3f3cSopenharmony_ci if (f & DONTRUNCOMMAND) { 322c84f3f3cSopenharmony_ci word = IFS_WORD; 323c84f3f3cSopenharmony_ci *dp++ = '$'; 324c84f3f3cSopenharmony_ci switch (c) { 325c84f3f3cSopenharmony_ci case COMASUB: 326c84f3f3cSopenharmony_ci case COMSUB: 327c84f3f3cSopenharmony_ci *dp++ = '('; 328c84f3f3cSopenharmony_ci c = ORD(')'); 329c84f3f3cSopenharmony_ci break; 330c84f3f3cSopenharmony_ci case FUNASUB: 331c84f3f3cSopenharmony_ci case FUNSUB: 332c84f3f3cSopenharmony_ci case VALSUB: 333c84f3f3cSopenharmony_ci *dp++ = '{'; 334c84f3f3cSopenharmony_ci *dp++ = c == VALSUB ? '|' : ' '; 335c84f3f3cSopenharmony_ci c = ORD('}'); 336c84f3f3cSopenharmony_ci break; 337c84f3f3cSopenharmony_ci } 338c84f3f3cSopenharmony_ci while (*sp != '\0') { 339c84f3f3cSopenharmony_ci Xcheck(ds, dp); 340c84f3f3cSopenharmony_ci *dp++ = *sp++; 341c84f3f3cSopenharmony_ci } 342c84f3f3cSopenharmony_ci if ((unsigned int)c == ORD(/*{*/'}')) 343c84f3f3cSopenharmony_ci *dp++ = ';'; 344c84f3f3cSopenharmony_ci *dp++ = c; 345c84f3f3cSopenharmony_ci } else { 346c84f3f3cSopenharmony_ci type = comsub(&x, sp, c); 347c84f3f3cSopenharmony_ci if (type != XBASE && (f & DOBLANK)) 348c84f3f3cSopenharmony_ci doblank++; 349c84f3f3cSopenharmony_ci sp = strnul(sp) + 1; 350c84f3f3cSopenharmony_ci newlines = 0; 351c84f3f3cSopenharmony_ci } 352c84f3f3cSopenharmony_ci continue; 353c84f3f3cSopenharmony_ci case EXPRSUB: 354c84f3f3cSopenharmony_ci tilde_ok = 0; 355c84f3f3cSopenharmony_ci if (f & DONTRUNCOMMAND) { 356c84f3f3cSopenharmony_ci word = IFS_WORD; 357c84f3f3cSopenharmony_ci *dp++ = '$'; *dp++ = '('; *dp++ = '('; 358c84f3f3cSopenharmony_ci while (*sp != '\0') { 359c84f3f3cSopenharmony_ci Xcheck(ds, dp); 360c84f3f3cSopenharmony_ci *dp++ = *sp++; 361c84f3f3cSopenharmony_ci } 362c84f3f3cSopenharmony_ci *dp++ = ')'; *dp++ = ')'; 363c84f3f3cSopenharmony_ci } else { 364c84f3f3cSopenharmony_ci struct tbl v; 365c84f3f3cSopenharmony_ci 366c84f3f3cSopenharmony_ci v.flag = DEFINED|ISSET|INTEGER; 367c84f3f3cSopenharmony_ci /* not default */ 368c84f3f3cSopenharmony_ci v.type = 10; 369c84f3f3cSopenharmony_ci v.name[0] = '\0'; 370c84f3f3cSopenharmony_ci v_evaluate(&v, substitute(sp, 0), 371c84f3f3cSopenharmony_ci KSH_UNWIND_ERROR, true); 372c84f3f3cSopenharmony_ci sp = strnul(sp) + 1; 373c84f3f3cSopenharmony_ci x.str = str_val(&v); 374c84f3f3cSopenharmony_ci type = XSUB; 375c84f3f3cSopenharmony_ci if (f & DOBLANK) 376c84f3f3cSopenharmony_ci doblank++; 377c84f3f3cSopenharmony_ci } 378c84f3f3cSopenharmony_ci continue; 379c84f3f3cSopenharmony_ci case OSUBST: { 380c84f3f3cSopenharmony_ci /* ${{#}var{:}[=+-?#%]word} */ 381c84f3f3cSopenharmony_ci /*- 382c84f3f3cSopenharmony_ci * format is: 383c84f3f3cSopenharmony_ci * OSUBST [{x] plain-variable-part \0 384c84f3f3cSopenharmony_ci * compiled-word-part CSUBST [}x] 385c84f3f3cSopenharmony_ci * This is where all syntax checking gets done... 386c84f3f3cSopenharmony_ci */ 387c84f3f3cSopenharmony_ci /* skip the { or x (}) */ 388c84f3f3cSopenharmony_ci const char *varname = ++sp; 389c84f3f3cSopenharmony_ci unsigned int stype; 390c84f3f3cSopenharmony_ci int slen = 0; 391c84f3f3cSopenharmony_ci 392c84f3f3cSopenharmony_ci /* skip variable */ 393c84f3f3cSopenharmony_ci sp = cstrchr(sp, '\0') + 1; 394c84f3f3cSopenharmony_ci type = varsub(&x, varname, sp, &stype, &slen); 395c84f3f3cSopenharmony_ci if (type < 0) { 396c84f3f3cSopenharmony_ci char *beg, *end, *str; 397c84f3f3cSopenharmony_ci unwind_substsyn: 398c84f3f3cSopenharmony_ci /* restore sp */ 399c84f3f3cSopenharmony_ci sp = varname - 2; 400c84f3f3cSopenharmony_ci beg = wdcopy(sp, ATEMP); 401c84f3f3cSopenharmony_ci end = (wdscan(cstrchr(sp, '\0') + 1, 402c84f3f3cSopenharmony_ci CSUBST) - sp) + beg; 403c84f3f3cSopenharmony_ci /* ({) the } or x is already skipped */ 404c84f3f3cSopenharmony_ci if (end < wdscan(beg, EOS)) 405c84f3f3cSopenharmony_ci *end = EOS; 406c84f3f3cSopenharmony_ci str = snptreef(NULL, 64, Tf_S, beg); 407c84f3f3cSopenharmony_ci afree(beg, ATEMP); 408c84f3f3cSopenharmony_ci errorf(Tf_sD_s, str, Tbadsubst); 409c84f3f3cSopenharmony_ci } 410c84f3f3cSopenharmony_ci if (f & DOBLANK) 411c84f3f3cSopenharmony_ci doblank++; 412c84f3f3cSopenharmony_ci tilde_ok = 0; 413c84f3f3cSopenharmony_ci if (word == IFS_QUOTE && type != XNULLSUB) 414c84f3f3cSopenharmony_ci word = IFS_WORD; 415c84f3f3cSopenharmony_ci if (type == XBASE) { 416c84f3f3cSopenharmony_ci /* expand? */ 417c84f3f3cSopenharmony_ci if (!st->next) { 418c84f3f3cSopenharmony_ci SubType *newst; 419c84f3f3cSopenharmony_ci 420c84f3f3cSopenharmony_ci newst = alloc(sizeof(SubType), ATEMP); 421c84f3f3cSopenharmony_ci newst->next = NULL; 422c84f3f3cSopenharmony_ci newst->prev = st; 423c84f3f3cSopenharmony_ci st->next = newst; 424c84f3f3cSopenharmony_ci } 425c84f3f3cSopenharmony_ci st = st->next; 426c84f3f3cSopenharmony_ci st->stype = stype; 427c84f3f3cSopenharmony_ci st->base = Xsavepos(ds, dp); 428c84f3f3cSopenharmony_ci st->f = f; 429c84f3f3cSopenharmony_ci if (x.var == vtemp) { 430c84f3f3cSopenharmony_ci st->var = tempvar(vtemp->name); 431c84f3f3cSopenharmony_ci st->var->flag &= ~INTEGER; 432c84f3f3cSopenharmony_ci /* can't fail here */ 433c84f3f3cSopenharmony_ci setstr(st->var, 434c84f3f3cSopenharmony_ci str_val(x.var), 435c84f3f3cSopenharmony_ci KSH_RETURN_ERROR | 0x4); 436c84f3f3cSopenharmony_ci } else 437c84f3f3cSopenharmony_ci st->var = x.var; 438c84f3f3cSopenharmony_ci 439c84f3f3cSopenharmony_ci st->quotew = st->quotep = quote; 440c84f3f3cSopenharmony_ci /* skip qualifier(s) */ 441c84f3f3cSopenharmony_ci if (stype) 442c84f3f3cSopenharmony_ci sp += slen; 443c84f3f3cSopenharmony_ci switch (stype & STYPE_SINGLE) { 444c84f3f3cSopenharmony_ci case ORD('#') | STYPE_AT: 445c84f3f3cSopenharmony_ci case ORD('Q') | STYPE_AT: 446c84f3f3cSopenharmony_ci break; 447c84f3f3cSopenharmony_ci case ORD('0'): { 448c84f3f3cSopenharmony_ci char *beg, *mid, *end, *stg; 449c84f3f3cSopenharmony_ci mksh_ari_t from = 0, num = -1, flen, finc = 0; 450c84f3f3cSopenharmony_ci 451c84f3f3cSopenharmony_ci beg = wdcopy(sp, ATEMP); 452c84f3f3cSopenharmony_ci mid = beg + (wdscan(sp, ADELIM) - sp); 453c84f3f3cSopenharmony_ci stg = beg + (wdscan(sp, CSUBST) - sp); 454c84f3f3cSopenharmony_ci mid[-2] = EOS; 455c84f3f3cSopenharmony_ci if (ord(mid[-1]) == ORD(/*{*/ '}')) { 456c84f3f3cSopenharmony_ci sp += mid - beg - 1; 457c84f3f3cSopenharmony_ci end = NULL; 458c84f3f3cSopenharmony_ci } else { 459c84f3f3cSopenharmony_ci end = mid + 460c84f3f3cSopenharmony_ci (wdscan(mid, ADELIM) - mid); 461c84f3f3cSopenharmony_ci if (ord(end[-1]) != ORD(/*{*/ '}')) 462c84f3f3cSopenharmony_ci /* more than max delimiters */ 463c84f3f3cSopenharmony_ci goto unwind_substsyn; 464c84f3f3cSopenharmony_ci end[-2] = EOS; 465c84f3f3cSopenharmony_ci sp += end - beg - 1; 466c84f3f3cSopenharmony_ci } 467c84f3f3cSopenharmony_ci evaluate(substitute(stg = wdstrip(beg, 0), 0), 468c84f3f3cSopenharmony_ci &from, KSH_UNWIND_ERROR, true); 469c84f3f3cSopenharmony_ci afree(stg, ATEMP); 470c84f3f3cSopenharmony_ci if (end) { 471c84f3f3cSopenharmony_ci evaluate(substitute(stg = wdstrip(mid, 0), 0), 472c84f3f3cSopenharmony_ci &num, KSH_UNWIND_ERROR, true); 473c84f3f3cSopenharmony_ci afree(stg, ATEMP); 474c84f3f3cSopenharmony_ci } 475c84f3f3cSopenharmony_ci afree(beg, ATEMP); 476c84f3f3cSopenharmony_ci beg = str_val(st->var); 477c84f3f3cSopenharmony_ci flen = utflen(beg); 478c84f3f3cSopenharmony_ci if (from < 0) { 479c84f3f3cSopenharmony_ci if (-from < flen) 480c84f3f3cSopenharmony_ci finc = flen + from; 481c84f3f3cSopenharmony_ci } else 482c84f3f3cSopenharmony_ci finc = from < flen ? from : flen; 483c84f3f3cSopenharmony_ci if (UTFMODE) 484c84f3f3cSopenharmony_ci utfincptr(beg, &finc); 485c84f3f3cSopenharmony_ci beg += finc; 486c84f3f3cSopenharmony_ci flen = utflen(beg); 487c84f3f3cSopenharmony_ci if (num < 0 || num > flen) 488c84f3f3cSopenharmony_ci num = flen; 489c84f3f3cSopenharmony_ci if (UTFMODE) 490c84f3f3cSopenharmony_ci utfincptr(beg, &num); 491c84f3f3cSopenharmony_ci strndupx(x.str, beg, num, ATEMP); 492c84f3f3cSopenharmony_ci goto do_CSUBST; 493c84f3f3cSopenharmony_ci } 494c84f3f3cSopenharmony_ci case ORD('/') | STYPE_AT: 495c84f3f3cSopenharmony_ci case ORD('/'): { 496c84f3f3cSopenharmony_ci char *s, *p, *d, *sbeg; 497c84f3f3cSopenharmony_ci char *pat = NULL, *rrep; 498c84f3f3cSopenharmony_ci char fpat = 0, *tpat1, *tpat2; 499c84f3f3cSopenharmony_ci char *ws, *wpat, *wrep, tch; 500c84f3f3cSopenharmony_ci size_t rreplen; 501c84f3f3cSopenharmony_ci 502c84f3f3cSopenharmony_ci s = ws = wdcopy(sp, ATEMP); 503c84f3f3cSopenharmony_ci p = s + (wdscan(sp, ADELIM) - sp); 504c84f3f3cSopenharmony_ci d = s + (wdscan(sp, CSUBST) - sp); 505c84f3f3cSopenharmony_ci p[-2] = EOS; 506c84f3f3cSopenharmony_ci if (ord(p[-1]) == ORD(/*{*/ '}')) 507c84f3f3cSopenharmony_ci d = NULL; 508c84f3f3cSopenharmony_ci else 509c84f3f3cSopenharmony_ci d[-2] = EOS; 510c84f3f3cSopenharmony_ci sp += (d ? d : p) - s - 1; 511c84f3f3cSopenharmony_ci if (!(stype & STYPE_MASK) && 512c84f3f3cSopenharmony_ci s[0] == CHAR && 513c84f3f3cSopenharmony_ci ctype(s[1], C_SUB2)) 514c84f3f3cSopenharmony_ci fpat = s[1]; 515c84f3f3cSopenharmony_ci wpat = s + (fpat ? 2 : 0); 516c84f3f3cSopenharmony_ci if (!(wrep = d ? p : NULL)) { 517c84f3f3cSopenharmony_ci rrep = null; 518c84f3f3cSopenharmony_ci rreplen = 0; 519c84f3f3cSopenharmony_ci } else if (!(stype & STYPE_AT)) { 520c84f3f3cSopenharmony_ci rrep = evalstr(wrep, 521c84f3f3cSopenharmony_ci DOTILDE | DOSCALAR); 522c84f3f3cSopenharmony_ci rreplen = strlen(rrep); 523c84f3f3cSopenharmony_ci } else { 524c84f3f3cSopenharmony_ci rrep = NULL; 525c84f3f3cSopenharmony_ci /* shut up GCC */ 526c84f3f3cSopenharmony_ci rreplen = 0; 527c84f3f3cSopenharmony_ci } 528c84f3f3cSopenharmony_ci 529c84f3f3cSopenharmony_ci /* prepare string on which to work */ 530c84f3f3cSopenharmony_ci strdupx(s, str_val(st->var), ATEMP); 531c84f3f3cSopenharmony_ci sbeg = s; 532c84f3f3cSopenharmony_ci again_search: 533c84f3f3cSopenharmony_ci pat = evalstr(wpat, 534c84f3f3cSopenharmony_ci DOTILDE | DOSCALAR | DOPAT); 535c84f3f3cSopenharmony_ci /* check for special cases */ 536c84f3f3cSopenharmony_ci if (!*pat && !fpat) { 537c84f3f3cSopenharmony_ci /* 538c84f3f3cSopenharmony_ci * empty unanchored 539c84f3f3cSopenharmony_ci * pattern => reject 540c84f3f3cSopenharmony_ci */ 541c84f3f3cSopenharmony_ci goto no_repl; 542c84f3f3cSopenharmony_ci } 543c84f3f3cSopenharmony_ci if ((stype & STYPE_MASK) && 544c84f3f3cSopenharmony_ci gmatchx(null, pat, false)) { 545c84f3f3cSopenharmony_ci /* 546c84f3f3cSopenharmony_ci * pattern matches empty 547c84f3f3cSopenharmony_ci * string => don't loop 548c84f3f3cSopenharmony_ci */ 549c84f3f3cSopenharmony_ci stype &= ~STYPE_MASK; 550c84f3f3cSopenharmony_ci } 551c84f3f3cSopenharmony_ci 552c84f3f3cSopenharmony_ci /* first see if we have any match at all */ 553c84f3f3cSopenharmony_ci if (ord(fpat) == ORD('#')) { 554c84f3f3cSopenharmony_ci /* anchor at the beginning */ 555c84f3f3cSopenharmony_ci tpat1 = shf_smprintf("%s%c*", pat, MAGIC); 556c84f3f3cSopenharmony_ci tpat2 = tpat1; 557c84f3f3cSopenharmony_ci } else if (ord(fpat) == ORD('%')) { 558c84f3f3cSopenharmony_ci /* anchor at the end */ 559c84f3f3cSopenharmony_ci tpat1 = shf_smprintf("%c*%s", MAGIC, pat); 560c84f3f3cSopenharmony_ci tpat2 = pat; 561c84f3f3cSopenharmony_ci } else { 562c84f3f3cSopenharmony_ci /* float */ 563c84f3f3cSopenharmony_ci tpat1 = shf_smprintf("%c*%s%c*", MAGIC, pat, MAGIC); 564c84f3f3cSopenharmony_ci tpat2 = tpat1 + 2; 565c84f3f3cSopenharmony_ci } 566c84f3f3cSopenharmony_ci again_repl: 567c84f3f3cSopenharmony_ci /* 568c84f3f3cSopenharmony_ci * this would not be necessary if gmatchx would return 569c84f3f3cSopenharmony_ci * the start and end values of a match found, like re* 570c84f3f3cSopenharmony_ci */ 571c84f3f3cSopenharmony_ci if (!gmatchx(sbeg, tpat1, false)) 572c84f3f3cSopenharmony_ci goto end_repl; 573c84f3f3cSopenharmony_ci d = strnul(s); 574c84f3f3cSopenharmony_ci /* now anchor the beginning of the match */ 575c84f3f3cSopenharmony_ci if (ord(fpat) != ORD('#')) 576c84f3f3cSopenharmony_ci while (sbeg <= d) { 577c84f3f3cSopenharmony_ci if (gmatchx(sbeg, tpat2, false)) 578c84f3f3cSopenharmony_ci break; 579c84f3f3cSopenharmony_ci else 580c84f3f3cSopenharmony_ci sbeg++; 581c84f3f3cSopenharmony_ci } 582c84f3f3cSopenharmony_ci /* now anchor the end of the match */ 583c84f3f3cSopenharmony_ci p = d; 584c84f3f3cSopenharmony_ci if (ord(fpat) != ORD('%')) 585c84f3f3cSopenharmony_ci while (p >= sbeg) { 586c84f3f3cSopenharmony_ci bool gotmatch; 587c84f3f3cSopenharmony_ci 588c84f3f3cSopenharmony_ci c = ord(*p); 589c84f3f3cSopenharmony_ci *p = '\0'; 590c84f3f3cSopenharmony_ci gotmatch = tobool(gmatchx(sbeg, pat, false)); 591c84f3f3cSopenharmony_ci *p = c; 592c84f3f3cSopenharmony_ci if (gotmatch) 593c84f3f3cSopenharmony_ci break; 594c84f3f3cSopenharmony_ci p--; 595c84f3f3cSopenharmony_ci } 596c84f3f3cSopenharmony_ci 597c84f3f3cSopenharmony_ci /* record partial string as match */ 598c84f3f3cSopenharmony_ci tch = *p; 599c84f3f3cSopenharmony_ci *p = '\0'; 600c84f3f3cSopenharmony_ci record_match(sbeg); 601c84f3f3cSopenharmony_ci *p = tch; 602c84f3f3cSopenharmony_ci /* get replacement string, if necessary */ 603c84f3f3cSopenharmony_ci if ((stype & STYPE_AT) && 604c84f3f3cSopenharmony_ci rrep != null) { 605c84f3f3cSopenharmony_ci afree(rrep, ATEMP); 606c84f3f3cSopenharmony_ci /* might access match! */ 607c84f3f3cSopenharmony_ci rrep = evalstr(wrep, 608c84f3f3cSopenharmony_ci DOTILDE | DOSCALAR); 609c84f3f3cSopenharmony_ci rreplen = strlen(rrep); 610c84f3f3cSopenharmony_ci } 611c84f3f3cSopenharmony_ci 612c84f3f3cSopenharmony_ci /* 613c84f3f3cSopenharmony_ci * string: 614c84f3f3cSopenharmony_ci * |--------|---------|-------\0 615c84f3f3cSopenharmony_ci * s n1 sbeg n2 p n3 d 616c84f3f3cSopenharmony_ci * 617c84f3f3cSopenharmony_ci * replacement: 618c84f3f3cSopenharmony_ci * |------------| 619c84f3f3cSopenharmony_ci * rrep rreplen 620c84f3f3cSopenharmony_ci */ 621c84f3f3cSopenharmony_ci 622c84f3f3cSopenharmony_ci /* move strings around and replace */ 623c84f3f3cSopenharmony_ci { 624c84f3f3cSopenharmony_ci size_t n1 = sbeg - s; 625c84f3f3cSopenharmony_ci size_t n2 = p - sbeg; 626c84f3f3cSopenharmony_ci size_t n3 = d - p; 627c84f3f3cSopenharmony_ci /* move part3 to the front, OR… */ 628c84f3f3cSopenharmony_ci if (rreplen < n2) 629c84f3f3cSopenharmony_ci memmove(sbeg + rreplen, 630c84f3f3cSopenharmony_ci p, n3 + 1); 631c84f3f3cSopenharmony_ci /* … adjust size, move to back */ 632c84f3f3cSopenharmony_ci if (rreplen > n2) { 633c84f3f3cSopenharmony_ci s = aresize(s, 634c84f3f3cSopenharmony_ci n1 + rreplen + n3 + 1, 635c84f3f3cSopenharmony_ci ATEMP); 636c84f3f3cSopenharmony_ci memmove(s + n1 + rreplen, 637c84f3f3cSopenharmony_ci s + n1 + n2, 638c84f3f3cSopenharmony_ci n3 + 1); 639c84f3f3cSopenharmony_ci } 640c84f3f3cSopenharmony_ci /* insert replacement */ 641c84f3f3cSopenharmony_ci if (rreplen) 642c84f3f3cSopenharmony_ci memcpy(s + n1, rrep, rreplen); 643c84f3f3cSopenharmony_ci /* continue after the place */ 644c84f3f3cSopenharmony_ci sbeg = s + n1 + rreplen; 645c84f3f3cSopenharmony_ci } 646c84f3f3cSopenharmony_ci if (stype & STYPE_AT) { 647c84f3f3cSopenharmony_ci afree(tpat1, ATEMP); 648c84f3f3cSopenharmony_ci afree(pat, ATEMP); 649c84f3f3cSopenharmony_ci goto again_search; 650c84f3f3cSopenharmony_ci } else if (stype & STYPE_DBL) 651c84f3f3cSopenharmony_ci goto again_repl; 652c84f3f3cSopenharmony_ci end_repl: 653c84f3f3cSopenharmony_ci afree(tpat1, ATEMP); 654c84f3f3cSopenharmony_ci x.str = s; 655c84f3f3cSopenharmony_ci no_repl: 656c84f3f3cSopenharmony_ci afree(pat, ATEMP); 657c84f3f3cSopenharmony_ci if (rrep != null) 658c84f3f3cSopenharmony_ci afree(rrep, ATEMP); 659c84f3f3cSopenharmony_ci afree(ws, ATEMP); 660c84f3f3cSopenharmony_ci goto do_CSUBST; 661c84f3f3cSopenharmony_ci } 662c84f3f3cSopenharmony_ci case ORD('#'): 663c84f3f3cSopenharmony_ci case ORD('%'): 664c84f3f3cSopenharmony_ci /* ! DOBLANK,DOBRACE */ 665c84f3f3cSopenharmony_ci f = (f & DONTRUNCOMMAND) | 666c84f3f3cSopenharmony_ci DOPAT | DOTILDE | 667c84f3f3cSopenharmony_ci DOTEMP | DOSCALAR; 668c84f3f3cSopenharmony_ci tilde_ok = 1; 669c84f3f3cSopenharmony_ci st->quotew = quote = 0; 670c84f3f3cSopenharmony_ci /* 671c84f3f3cSopenharmony_ci * Prepend open pattern (so | 672c84f3f3cSopenharmony_ci * in a trim will work as 673c84f3f3cSopenharmony_ci * expected) 674c84f3f3cSopenharmony_ci */ 675c84f3f3cSopenharmony_ci if (!Flag(FSH)) { 676c84f3f3cSopenharmony_ci *dp++ = MAGIC; 677c84f3f3cSopenharmony_ci *dp++ = ORD(0x80 | '@'); 678c84f3f3cSopenharmony_ci } 679c84f3f3cSopenharmony_ci break; 680c84f3f3cSopenharmony_ci case ORD('='): 681c84f3f3cSopenharmony_ci /* 682c84f3f3cSopenharmony_ci * Tilde expansion for string 683c84f3f3cSopenharmony_ci * variables in POSIX mode is 684c84f3f3cSopenharmony_ci * governed by Austinbug 351. 685c84f3f3cSopenharmony_ci * In non-POSIX mode historic 686c84f3f3cSopenharmony_ci * ksh behaviour (enable it!) 687c84f3f3cSopenharmony_ci * us followed. 688c84f3f3cSopenharmony_ci * Not doing tilde expansion 689c84f3f3cSopenharmony_ci * for integer variables is a 690c84f3f3cSopenharmony_ci * non-POSIX thing - makes 691c84f3f3cSopenharmony_ci * sense though, since ~ is 692c84f3f3cSopenharmony_ci * a arithmetic operator. 693c84f3f3cSopenharmony_ci */ 694c84f3f3cSopenharmony_ci if (!(x.var->flag & INTEGER)) 695c84f3f3cSopenharmony_ci f |= DOASNTILDE | DOTILDE; 696c84f3f3cSopenharmony_ci f |= DOTEMP | DOSCALAR; 697c84f3f3cSopenharmony_ci /* 698c84f3f3cSopenharmony_ci * These will be done after the 699c84f3f3cSopenharmony_ci * value has been assigned. 700c84f3f3cSopenharmony_ci */ 701c84f3f3cSopenharmony_ci f &= ~(DOBLANK|DOGLOB|DOBRACE); 702c84f3f3cSopenharmony_ci tilde_ok = 1; 703c84f3f3cSopenharmony_ci break; 704c84f3f3cSopenharmony_ci case ORD('?'): 705c84f3f3cSopenharmony_ci if (*sp == CSUBST) 706c84f3f3cSopenharmony_ci errorf("%s: parameter null or not set", 707c84f3f3cSopenharmony_ci st->var->name); 708c84f3f3cSopenharmony_ci f &= ~DOBLANK; 709c84f3f3cSopenharmony_ci f |= DOTEMP; 710c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 711c84f3f3cSopenharmony_ci default: 712c84f3f3cSopenharmony_ci /* '-' '+' '?' */ 713c84f3f3cSopenharmony_ci if (quote) 714c84f3f3cSopenharmony_ci word = IFS_WORD; 715c84f3f3cSopenharmony_ci else if (dp == Xstring(ds, dp)) 716c84f3f3cSopenharmony_ci word = IFS_IWS; 717c84f3f3cSopenharmony_ci /* Enable tilde expansion */ 718c84f3f3cSopenharmony_ci tilde_ok = 1; 719c84f3f3cSopenharmony_ci f |= DOTILDE; 720c84f3f3cSopenharmony_ci } 721c84f3f3cSopenharmony_ci } else 722c84f3f3cSopenharmony_ci /* skip word */ 723c84f3f3cSopenharmony_ci sp += wdscan(sp, CSUBST) - sp; 724c84f3f3cSopenharmony_ci continue; 725c84f3f3cSopenharmony_ci } 726c84f3f3cSopenharmony_ci case CSUBST: 727c84f3f3cSopenharmony_ci /* only get here if expanding word */ 728c84f3f3cSopenharmony_ci do_CSUBST: 729c84f3f3cSopenharmony_ci /* ({) skip the } or x */ 730c84f3f3cSopenharmony_ci sp++; 731c84f3f3cSopenharmony_ci /* in case of ${unset:-} */ 732c84f3f3cSopenharmony_ci tilde_ok = 0; 733c84f3f3cSopenharmony_ci *dp = '\0'; 734c84f3f3cSopenharmony_ci quote = st->quotep; 735c84f3f3cSopenharmony_ci f = st->f; 736c84f3f3cSopenharmony_ci if (f & DOBLANK) 737c84f3f3cSopenharmony_ci doblank--; 738c84f3f3cSopenharmony_ci switch (st->stype & STYPE_SINGLE) { 739c84f3f3cSopenharmony_ci case ORD('#'): 740c84f3f3cSopenharmony_ci case ORD('%'): 741c84f3f3cSopenharmony_ci if (!Flag(FSH)) { 742c84f3f3cSopenharmony_ci /* Append end-pattern */ 743c84f3f3cSopenharmony_ci *dp++ = MAGIC; 744c84f3f3cSopenharmony_ci *dp++ = ')'; 745c84f3f3cSopenharmony_ci } 746c84f3f3cSopenharmony_ci *dp = '\0'; 747c84f3f3cSopenharmony_ci dp = Xrestpos(ds, dp, st->base); 748c84f3f3cSopenharmony_ci /* 749c84f3f3cSopenharmony_ci * Must use st->var since calling 750c84f3f3cSopenharmony_ci * global would break things 751c84f3f3cSopenharmony_ci * like x[i+=1]. 752c84f3f3cSopenharmony_ci */ 753c84f3f3cSopenharmony_ci x.str = trimsub(str_val(st->var), 754c84f3f3cSopenharmony_ci dp, st->stype); 755c84f3f3cSopenharmony_ci if (x.str[0] != '\0') { 756c84f3f3cSopenharmony_ci word = IFS_IWS; 757c84f3f3cSopenharmony_ci type = XSUB; 758c84f3f3cSopenharmony_ci } else if (quote) { 759c84f3f3cSopenharmony_ci word = IFS_WORD; 760c84f3f3cSopenharmony_ci type = XSUB; 761c84f3f3cSopenharmony_ci } else { 762c84f3f3cSopenharmony_ci if (dp == Xstring(ds, dp)) 763c84f3f3cSopenharmony_ci word = IFS_IWS; 764c84f3f3cSopenharmony_ci type = XNULLSUB; 765c84f3f3cSopenharmony_ci } 766c84f3f3cSopenharmony_ci if (f & DOBLANK) 767c84f3f3cSopenharmony_ci doblank++; 768c84f3f3cSopenharmony_ci st = st->prev; 769c84f3f3cSopenharmony_ci continue; 770c84f3f3cSopenharmony_ci case ORD('='): 771c84f3f3cSopenharmony_ci /* 772c84f3f3cSopenharmony_ci * Restore our position and substitute 773c84f3f3cSopenharmony_ci * the value of st->var (may not be 774c84f3f3cSopenharmony_ci * the assigned value in the presence 775c84f3f3cSopenharmony_ci * of integer/right-adj/etc attributes). 776c84f3f3cSopenharmony_ci */ 777c84f3f3cSopenharmony_ci dp = Xrestpos(ds, dp, st->base); 778c84f3f3cSopenharmony_ci /* 779c84f3f3cSopenharmony_ci * Must use st->var since calling 780c84f3f3cSopenharmony_ci * global would cause with things 781c84f3f3cSopenharmony_ci * like x[i+=1] to be evaluated twice. 782c84f3f3cSopenharmony_ci */ 783c84f3f3cSopenharmony_ci /* 784c84f3f3cSopenharmony_ci * Note: not exported by FEXPORT 785c84f3f3cSopenharmony_ci * in AT&T ksh. 786c84f3f3cSopenharmony_ci */ 787c84f3f3cSopenharmony_ci /* 788c84f3f3cSopenharmony_ci * XXX POSIX says readonly is only 789c84f3f3cSopenharmony_ci * fatal for special builtins (setstr 790c84f3f3cSopenharmony_ci * does readonly check). 791c84f3f3cSopenharmony_ci */ 792c84f3f3cSopenharmony_ci len = strlen(dp) + 1; 793c84f3f3cSopenharmony_ci setstr(st->var, 794c84f3f3cSopenharmony_ci debunk(alloc(len, ATEMP), 795c84f3f3cSopenharmony_ci dp, len), KSH_UNWIND_ERROR); 796c84f3f3cSopenharmony_ci x.str = str_val(st->var); 797c84f3f3cSopenharmony_ci type = XSUB; 798c84f3f3cSopenharmony_ci if (f & DOBLANK) 799c84f3f3cSopenharmony_ci doblank++; 800c84f3f3cSopenharmony_ci st = st->prev; 801c84f3f3cSopenharmony_ci word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS; 802c84f3f3cSopenharmony_ci continue; 803c84f3f3cSopenharmony_ci case ORD('?'): 804c84f3f3cSopenharmony_ci dp = Xrestpos(ds, dp, st->base); 805c84f3f3cSopenharmony_ci 806c84f3f3cSopenharmony_ci errorf(Tf_sD_s, st->var->name, 807c84f3f3cSopenharmony_ci debunk(dp, dp, strlen(dp) + 1)); 808c84f3f3cSopenharmony_ci break; 809c84f3f3cSopenharmony_ci case ORD('#') | STYPE_AT: 810c84f3f3cSopenharmony_ci x.str = shf_smprintf("%08X", 811c84f3f3cSopenharmony_ci (unsigned int)hash(str_val(st->var))); 812c84f3f3cSopenharmony_ci goto common_CSUBST; 813c84f3f3cSopenharmony_ci case ORD('Q') | STYPE_AT: { 814c84f3f3cSopenharmony_ci struct shf shf; 815c84f3f3cSopenharmony_ci 816c84f3f3cSopenharmony_ci shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf); 817c84f3f3cSopenharmony_ci print_value_quoted(&shf, str_val(st->var)); 818c84f3f3cSopenharmony_ci x.str = shf_sclose(&shf); 819c84f3f3cSopenharmony_ci goto common_CSUBST; 820c84f3f3cSopenharmony_ci } 821c84f3f3cSopenharmony_ci case ORD('0'): 822c84f3f3cSopenharmony_ci case ORD('/') | STYPE_AT: 823c84f3f3cSopenharmony_ci case ORD('/'): 824c84f3f3cSopenharmony_ci common_CSUBST: 825c84f3f3cSopenharmony_ci dp = Xrestpos(ds, dp, st->base); 826c84f3f3cSopenharmony_ci type = XSUB; 827c84f3f3cSopenharmony_ci word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS; 828c84f3f3cSopenharmony_ci if (f & DOBLANK) 829c84f3f3cSopenharmony_ci doblank++; 830c84f3f3cSopenharmony_ci st = st->prev; 831c84f3f3cSopenharmony_ci continue; 832c84f3f3cSopenharmony_ci /* default: '-' '+' */ 833c84f3f3cSopenharmony_ci } 834c84f3f3cSopenharmony_ci st = st->prev; 835c84f3f3cSopenharmony_ci type = XBASE; 836c84f3f3cSopenharmony_ci continue; 837c84f3f3cSopenharmony_ci 838c84f3f3cSopenharmony_ci case OPAT: 839c84f3f3cSopenharmony_ci /* open pattern: *(foo|bar) */ 840c84f3f3cSopenharmony_ci /* Next char is the type of pattern */ 841c84f3f3cSopenharmony_ci make_magic = true; 842c84f3f3cSopenharmony_ci c = ord(*sp++) | 0x80U; 843c84f3f3cSopenharmony_ci break; 844c84f3f3cSopenharmony_ci 845c84f3f3cSopenharmony_ci case SPAT: 846c84f3f3cSopenharmony_ci /* pattern separator (|) */ 847c84f3f3cSopenharmony_ci make_magic = true; 848c84f3f3cSopenharmony_ci c = ORD('|'); 849c84f3f3cSopenharmony_ci break; 850c84f3f3cSopenharmony_ci 851c84f3f3cSopenharmony_ci case CPAT: 852c84f3f3cSopenharmony_ci /* close pattern */ 853c84f3f3cSopenharmony_ci make_magic = true; 854c84f3f3cSopenharmony_ci c = ORD(/*(*/ ')'); 855c84f3f3cSopenharmony_ci break; 856c84f3f3cSopenharmony_ci } 857c84f3f3cSopenharmony_ci break; 858c84f3f3cSopenharmony_ci 859c84f3f3cSopenharmony_ci case XNULLSUB: 860c84f3f3cSopenharmony_ci /* 861c84f3f3cSopenharmony_ci * Special case for "$@" (and "${foo[@]}") - no 862c84f3f3cSopenharmony_ci * word is generated if $# is 0 (unless there is 863c84f3f3cSopenharmony_ci * other stuff inside the quotes). 864c84f3f3cSopenharmony_ci */ 865c84f3f3cSopenharmony_ci type = XBASE; 866c84f3f3cSopenharmony_ci if (f & DOBLANK) { 867c84f3f3cSopenharmony_ci doblank--; 868c84f3f3cSopenharmony_ci if (dp == Xstring(ds, dp) && word != IFS_WORD) 869c84f3f3cSopenharmony_ci word = IFS_IWS; 870c84f3f3cSopenharmony_ci } 871c84f3f3cSopenharmony_ci continue; 872c84f3f3cSopenharmony_ci 873c84f3f3cSopenharmony_ci case XSUBPAT: 874c84f3f3cSopenharmony_ci case XSUBPATMID: 875c84f3f3cSopenharmony_ci XSUBPAT_beg: 876c84f3f3cSopenharmony_ci switch ((c = ord(*x.str++))) { 877c84f3f3cSopenharmony_ci case 0: 878c84f3f3cSopenharmony_ci goto XSUB_end; 879c84f3f3cSopenharmony_ci case ORD('\\'): 880c84f3f3cSopenharmony_ci if ((c = ord(*x.str)) == 0) 881c84f3f3cSopenharmony_ci /* keep backslash at EOS */ 882c84f3f3cSopenharmony_ci c = ORD('\\'); 883c84f3f3cSopenharmony_ci else 884c84f3f3cSopenharmony_ci ++x.str; 885c84f3f3cSopenharmony_ci quote |= 2; 886c84f3f3cSopenharmony_ci break; 887c84f3f3cSopenharmony_ci /* ctype(c, C_PATMO) */ 888c84f3f3cSopenharmony_ci case ORD('!'): 889c84f3f3cSopenharmony_ci case ORD('*'): 890c84f3f3cSopenharmony_ci case ORD('+'): 891c84f3f3cSopenharmony_ci case ORD('?'): 892c84f3f3cSopenharmony_ci case ORD('@'): 893c84f3f3cSopenharmony_ci if (ord(*x.str) == ORD('('/*)*/)) { 894c84f3f3cSopenharmony_ci ++x.str; 895c84f3f3cSopenharmony_ci c |= 0x80U; 896c84f3f3cSopenharmony_ci make_magic = true; 897c84f3f3cSopenharmony_ci } 898c84f3f3cSopenharmony_ci break; 899c84f3f3cSopenharmony_ci case ORD('('): 900c84f3f3cSopenharmony_ci c = ORD(' ') | 0x80U; 901c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 902c84f3f3cSopenharmony_ci case ORD('|'): 903c84f3f3cSopenharmony_ci case ORD(')'): 904c84f3f3cSopenharmony_ci make_magic = true; 905c84f3f3cSopenharmony_ci break; 906c84f3f3cSopenharmony_ci } 907c84f3f3cSopenharmony_ci break; 908c84f3f3cSopenharmony_ci 909c84f3f3cSopenharmony_ci case XSUB: 910c84f3f3cSopenharmony_ci if (!quote && (f & DODBMAGIC)) { 911c84f3f3cSopenharmony_ci const char *cs = x.str; 912c84f3f3cSopenharmony_ci int level = 0; 913c84f3f3cSopenharmony_ci 914c84f3f3cSopenharmony_ci while ((c = *cs++)) 915c84f3f3cSopenharmony_ci switch (c) { 916c84f3f3cSopenharmony_ci case '\\': 917c84f3f3cSopenharmony_ci if ((c = *cs)) 918c84f3f3cSopenharmony_ci ++cs; 919c84f3f3cSopenharmony_ci break; 920c84f3f3cSopenharmony_ci case ORD('('): 921c84f3f3cSopenharmony_ci ++level; 922c84f3f3cSopenharmony_ci break; 923c84f3f3cSopenharmony_ci case ORD(')'): 924c84f3f3cSopenharmony_ci --level; 925c84f3f3cSopenharmony_ci break; 926c84f3f3cSopenharmony_ci } 927c84f3f3cSopenharmony_ci /* balanced parentheses? */ 928c84f3f3cSopenharmony_ci if (!level) { 929c84f3f3cSopenharmony_ci type = XSUBPAT; 930c84f3f3cSopenharmony_ci goto XSUBPAT_beg; 931c84f3f3cSopenharmony_ci } 932c84f3f3cSopenharmony_ci } 933c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 934c84f3f3cSopenharmony_ci case XSUBMID: 935c84f3f3cSopenharmony_ci if ((c = ord(*x.str++)) == 0) { 936c84f3f3cSopenharmony_ci XSUB_end: 937c84f3f3cSopenharmony_ci type = XBASE; 938c84f3f3cSopenharmony_ci if (f & DOBLANK) 939c84f3f3cSopenharmony_ci doblank--; 940c84f3f3cSopenharmony_ci continue; 941c84f3f3cSopenharmony_ci } 942c84f3f3cSopenharmony_ci break; 943c84f3f3cSopenharmony_ci 944c84f3f3cSopenharmony_ci case XARGSEP: 945c84f3f3cSopenharmony_ci type = XARG; 946c84f3f3cSopenharmony_ci quote = 1; 947c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 948c84f3f3cSopenharmony_ci case XARG: 949c84f3f3cSopenharmony_ci if ((c = ord(*x.str++)) == '\0') { 950c84f3f3cSopenharmony_ci /* 951c84f3f3cSopenharmony_ci * force null words to be created so 952c84f3f3cSopenharmony_ci * set -- "" 2 ""; echo "$@" will do 953c84f3f3cSopenharmony_ci * the right thing 954c84f3f3cSopenharmony_ci */ 955c84f3f3cSopenharmony_ci if (quote && x.split) 956c84f3f3cSopenharmony_ci word = IFS_WORD; 957c84f3f3cSopenharmony_ci if ((x.str = *x.u.strv++) == NULL) { 958c84f3f3cSopenharmony_ci type = XBASE; 959c84f3f3cSopenharmony_ci if (f & DOBLANK) 960c84f3f3cSopenharmony_ci doblank--; 961c84f3f3cSopenharmony_ci continue; 962c84f3f3cSopenharmony_ci } 963c84f3f3cSopenharmony_ci c = ord(ifs0); 964c84f3f3cSopenharmony_ci if ((f & DOHEREDOC)) { 965c84f3f3cSopenharmony_ci /* pseudo-field-split reliably */ 966c84f3f3cSopenharmony_ci if (c == 0) 967c84f3f3cSopenharmony_ci c = ORD(' '); 968c84f3f3cSopenharmony_ci break; 969c84f3f3cSopenharmony_ci } 970c84f3f3cSopenharmony_ci if ((f & DOSCALAR)) { 971c84f3f3cSopenharmony_ci /* do not field-split */ 972c84f3f3cSopenharmony_ci if (x.split) { 973c84f3f3cSopenharmony_ci c = ORD(' '); 974c84f3f3cSopenharmony_ci break; 975c84f3f3cSopenharmony_ci } 976c84f3f3cSopenharmony_ci if (c == 0) 977c84f3f3cSopenharmony_ci continue; 978c84f3f3cSopenharmony_ci } 979c84f3f3cSopenharmony_ci if (c == 0) { 980c84f3f3cSopenharmony_ci if (quote && !x.split) 981c84f3f3cSopenharmony_ci continue; 982c84f3f3cSopenharmony_ci if (!quote && word == IFS_WS) 983c84f3f3cSopenharmony_ci continue; 984c84f3f3cSopenharmony_ci /* this is so we don't terminate */ 985c84f3f3cSopenharmony_ci c = ORD(' '); 986c84f3f3cSopenharmony_ci /* now force-emit a word */ 987c84f3f3cSopenharmony_ci goto emit_word; 988c84f3f3cSopenharmony_ci } 989c84f3f3cSopenharmony_ci if (quote && x.split) { 990c84f3f3cSopenharmony_ci /* terminate word for "$@" */ 991c84f3f3cSopenharmony_ci type = XARGSEP; 992c84f3f3cSopenharmony_ci quote = 0; 993c84f3f3cSopenharmony_ci } 994c84f3f3cSopenharmony_ci } 995c84f3f3cSopenharmony_ci break; 996c84f3f3cSopenharmony_ci 997c84f3f3cSopenharmony_ci case XCOM: 998c84f3f3cSopenharmony_ci if (x.u.shf == NULL) { 999c84f3f3cSopenharmony_ci /* $(<...) failed */ 1000c84f3f3cSopenharmony_ci subst_exstat = 1; 1001c84f3f3cSopenharmony_ci /* fake EOF */ 1002c84f3f3cSopenharmony_ci c = -1; 1003c84f3f3cSopenharmony_ci } else if (newlines) { 1004c84f3f3cSopenharmony_ci /* spit out saved NLs */ 1005c84f3f3cSopenharmony_ci c = ORD('\n'); 1006c84f3f3cSopenharmony_ci --newlines; 1007c84f3f3cSopenharmony_ci } else { 1008c84f3f3cSopenharmony_ci while ((c = shf_getc(x.u.shf)) == 0 || 1009c84f3f3cSopenharmony_ci cinttype(c, C_NL)) { 1010c84f3f3cSopenharmony_ci#ifdef MKSH_WITH_TEXTMODE 1011c84f3f3cSopenharmony_ci if (c == ORD('\r')) { 1012c84f3f3cSopenharmony_ci c = shf_getc(x.u.shf); 1013c84f3f3cSopenharmony_ci switch (c) { 1014c84f3f3cSopenharmony_ci case ORD('\n'): 1015c84f3f3cSopenharmony_ci break; 1016c84f3f3cSopenharmony_ci default: 1017c84f3f3cSopenharmony_ci shf_ungetc(c, x.u.shf); 1018c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1019c84f3f3cSopenharmony_ci case -1: 1020c84f3f3cSopenharmony_ci c = ORD('\r'); 1021c84f3f3cSopenharmony_ci break; 1022c84f3f3cSopenharmony_ci } 1023c84f3f3cSopenharmony_ci } 1024c84f3f3cSopenharmony_ci#endif 1025c84f3f3cSopenharmony_ci if (c == ORD('\n')) 1026c84f3f3cSopenharmony_ci /* save newlines */ 1027c84f3f3cSopenharmony_ci newlines++; 1028c84f3f3cSopenharmony_ci } 1029c84f3f3cSopenharmony_ci if (newlines && c != -1) { 1030c84f3f3cSopenharmony_ci shf_ungetc(c, x.u.shf); 1031c84f3f3cSopenharmony_ci c = ORD('\n'); 1032c84f3f3cSopenharmony_ci --newlines; 1033c84f3f3cSopenharmony_ci } 1034c84f3f3cSopenharmony_ci } 1035c84f3f3cSopenharmony_ci if (c == -1) { 1036c84f3f3cSopenharmony_ci newlines = 0; 1037c84f3f3cSopenharmony_ci if (x.u.shf) 1038c84f3f3cSopenharmony_ci shf_close(x.u.shf); 1039c84f3f3cSopenharmony_ci if (x.split) 1040c84f3f3cSopenharmony_ci subst_exstat = waitlast(); 1041c84f3f3cSopenharmony_ci type = XBASE; 1042c84f3f3cSopenharmony_ci if (f & DOBLANK) 1043c84f3f3cSopenharmony_ci doblank--; 1044c84f3f3cSopenharmony_ci continue; 1045c84f3f3cSopenharmony_ci } 1046c84f3f3cSopenharmony_ci break; 1047c84f3f3cSopenharmony_ci } 1048c84f3f3cSopenharmony_ci 1049c84f3f3cSopenharmony_ci /* check for end of word or IFS separation */ 1050c84f3f3cSopenharmony_ci if (c == 0 || (!quote && (f & DOBLANK) && doblank && 1051c84f3f3cSopenharmony_ci !make_magic && ctype(c, C_IFS))) { 1052c84f3f3cSopenharmony_ci /*- 1053c84f3f3cSopenharmony_ci * How words are broken up: 1054c84f3f3cSopenharmony_ci * | value of c 1055c84f3f3cSopenharmony_ci * word | ws nws 0 1056c84f3f3cSopenharmony_ci * ----------------------------------- 1057c84f3f3cSopenharmony_ci * IFS_WORD w/WS w/NWS w 1058c84f3f3cSopenharmony_ci * IFS_WS -/WS -/NWS - 1059c84f3f3cSopenharmony_ci * IFS_NWS -/NWS w/NWS - 1060c84f3f3cSopenharmony_ci * IFS_IWS -/WS w/NWS - 1061c84f3f3cSopenharmony_ci * (w means generate a word) 1062c84f3f3cSopenharmony_ci */ 1063c84f3f3cSopenharmony_ci if ((word == IFS_WORD) || (word == IFS_QUOTE) || (c && 1064c84f3f3cSopenharmony_ci (word == IFS_IWS || word == IFS_NWS) && 1065c84f3f3cSopenharmony_ci !ctype(c, C_IFSWS))) { 1066c84f3f3cSopenharmony_ci emit_word: 1067c84f3f3cSopenharmony_ci if (f & DOHERESTR) 1068c84f3f3cSopenharmony_ci *dp++ = '\n'; 1069c84f3f3cSopenharmony_ci *dp++ = '\0'; 1070c84f3f3cSopenharmony_ci cp = Xclose(ds, dp); 1071c84f3f3cSopenharmony_ci if (fdo & DOBRACE) 1072c84f3f3cSopenharmony_ci /* also does globbing */ 1073c84f3f3cSopenharmony_ci alt_expand(wp, cp, cp, 1074c84f3f3cSopenharmony_ci cp + Xlength(ds, (dp - 1)), 1075c84f3f3cSopenharmony_ci fdo | (f & DOMARKDIRS)); 1076c84f3f3cSopenharmony_ci else if (fdo & DOGLOB) 1077c84f3f3cSopenharmony_ci glob(cp, wp, tobool(f & DOMARKDIRS)); 1078c84f3f3cSopenharmony_ci else if ((f & DOPAT) || !(fdo & DOMAGIC)) 1079c84f3f3cSopenharmony_ci XPput(*wp, cp); 1080c84f3f3cSopenharmony_ci else 1081c84f3f3cSopenharmony_ci XPput(*wp, debunk(cp, cp, 1082c84f3f3cSopenharmony_ci strlen(cp) + 1)); 1083c84f3f3cSopenharmony_ci fdo = 0; 1084c84f3f3cSopenharmony_ci saw_eq = false; 1085c84f3f3cSopenharmony_ci /* must be 1/0 */ 1086c84f3f3cSopenharmony_ci tilde_ok = (f & (DOTILDE | DOASNTILDE)) ? 1 : 0; 1087c84f3f3cSopenharmony_ci if (c == 0) 1088c84f3f3cSopenharmony_ci return; 1089c84f3f3cSopenharmony_ci Xinit(ds, dp, 128, ATEMP); 1090c84f3f3cSopenharmony_ci } else if (c == 0) { 1091c84f3f3cSopenharmony_ci return; 1092c84f3f3cSopenharmony_ci } else if (isXSUB(type) && ctype(c, C_IFS) && 1093c84f3f3cSopenharmony_ci !ctype(c, C_IFSWS) && Xlength(ds, dp) == 0) { 1094c84f3f3cSopenharmony_ci *(cp = alloc(1, ATEMP)) = '\0'; 1095c84f3f3cSopenharmony_ci XPput(*wp, cp); 1096c84f3f3cSopenharmony_ci ++type; 1097c84f3f3cSopenharmony_ci } 1098c84f3f3cSopenharmony_ci if (word != IFS_NWS) 1099c84f3f3cSopenharmony_ci word = ctype(c, C_IFSWS) ? IFS_WS : IFS_NWS; 1100c84f3f3cSopenharmony_ci } else { 1101c84f3f3cSopenharmony_ci if (isXSUB(type)) 1102c84f3f3cSopenharmony_ci ++type; 1103c84f3f3cSopenharmony_ci 1104c84f3f3cSopenharmony_ci /* age tilde_ok info - ~ code tests second bit */ 1105c84f3f3cSopenharmony_ci tilde_ok <<= 1; 1106c84f3f3cSopenharmony_ci /* mark any special second pass chars */ 1107c84f3f3cSopenharmony_ci if (!quote) 1108c84f3f3cSopenharmony_ci switch (ord(c)) { 1109c84f3f3cSopenharmony_ci case ORD('['): 1110c84f3f3cSopenharmony_ci case ORD('!'): 1111c84f3f3cSopenharmony_ci case ORD('-'): 1112c84f3f3cSopenharmony_ci case ORD(']'): 1113c84f3f3cSopenharmony_ci /* 1114c84f3f3cSopenharmony_ci * For character classes - doesn't hurt 1115c84f3f3cSopenharmony_ci * to have magic !,-,]s outside of 1116c84f3f3cSopenharmony_ci * [...] expressions. 1117c84f3f3cSopenharmony_ci */ 1118c84f3f3cSopenharmony_ci if (f & (DOPAT | DOGLOB)) { 1119c84f3f3cSopenharmony_ci fdo |= DOMAGIC; 1120c84f3f3cSopenharmony_ci if ((unsigned int)c == ORD('[')) 1121c84f3f3cSopenharmony_ci fdo |= f & DOGLOB; 1122c84f3f3cSopenharmony_ci *dp++ = MAGIC; 1123c84f3f3cSopenharmony_ci } 1124c84f3f3cSopenharmony_ci break; 1125c84f3f3cSopenharmony_ci case ORD('*'): 1126c84f3f3cSopenharmony_ci case ORD('?'): 1127c84f3f3cSopenharmony_ci if (f & (DOPAT | DOGLOB)) { 1128c84f3f3cSopenharmony_ci fdo |= DOMAGIC | (f & DOGLOB); 1129c84f3f3cSopenharmony_ci *dp++ = MAGIC; 1130c84f3f3cSopenharmony_ci } 1131c84f3f3cSopenharmony_ci break; 1132c84f3f3cSopenharmony_ci case ORD('{'): 1133c84f3f3cSopenharmony_ci case ORD('}'): 1134c84f3f3cSopenharmony_ci case ORD(','): 1135c84f3f3cSopenharmony_ci if ((f & DOBRACE) && 1136c84f3f3cSopenharmony_ci (ord(c) == ORD('{' /*}*/) || 1137c84f3f3cSopenharmony_ci (fdo & DOBRACE))) { 1138c84f3f3cSopenharmony_ci fdo |= DOBRACE|DOMAGIC; 1139c84f3f3cSopenharmony_ci *dp++ = MAGIC; 1140c84f3f3cSopenharmony_ci } 1141c84f3f3cSopenharmony_ci break; 1142c84f3f3cSopenharmony_ci case ORD('='): 1143c84f3f3cSopenharmony_ci /* Note first unquoted = for ~ */ 1144c84f3f3cSopenharmony_ci if (!(f & DOTEMP) && (!Flag(FPOSIX) || 1145c84f3f3cSopenharmony_ci (f & DOASNTILDE)) && !saw_eq) { 1146c84f3f3cSopenharmony_ci saw_eq = true; 1147c84f3f3cSopenharmony_ci tilde_ok = 1; 1148c84f3f3cSopenharmony_ci } 1149c84f3f3cSopenharmony_ci break; 1150c84f3f3cSopenharmony_ci case ORD(':'): 1151c84f3f3cSopenharmony_ci /* : */ 1152c84f3f3cSopenharmony_ci /* Note unquoted : for ~ */ 1153c84f3f3cSopenharmony_ci if (!(f & DOTEMP) && (f & DOASNTILDE)) 1154c84f3f3cSopenharmony_ci tilde_ok = 1; 1155c84f3f3cSopenharmony_ci break; 1156c84f3f3cSopenharmony_ci case ORD('~'): 1157c84f3f3cSopenharmony_ci /* 1158c84f3f3cSopenharmony_ci * tilde_ok is reset whenever 1159c84f3f3cSopenharmony_ci * any of ' " $( $(( ${ } are seen. 1160c84f3f3cSopenharmony_ci * Note that tilde_ok must be preserved 1161c84f3f3cSopenharmony_ci * through the sequence ${A=a=}~ 1162c84f3f3cSopenharmony_ci */ 1163c84f3f3cSopenharmony_ci if (type == XBASE && 1164c84f3f3cSopenharmony_ci (f & (DOTILDE | DOASNTILDE)) && 1165c84f3f3cSopenharmony_ci (tilde_ok & 2)) { 1166c84f3f3cSopenharmony_ci const char *tcp; 1167c84f3f3cSopenharmony_ci char *tdp = dp; 1168c84f3f3cSopenharmony_ci 1169c84f3f3cSopenharmony_ci tcp = maybe_expand_tilde(sp, 1170c84f3f3cSopenharmony_ci &ds, &tdp, 1171c84f3f3cSopenharmony_ci tobool(f & DOASNTILDE)); 1172c84f3f3cSopenharmony_ci if (tcp) { 1173c84f3f3cSopenharmony_ci if (dp != tdp) 1174c84f3f3cSopenharmony_ci word = IFS_WORD; 1175c84f3f3cSopenharmony_ci dp = tdp; 1176c84f3f3cSopenharmony_ci sp = tcp; 1177c84f3f3cSopenharmony_ci continue; 1178c84f3f3cSopenharmony_ci } 1179c84f3f3cSopenharmony_ci } 1180c84f3f3cSopenharmony_ci break; 1181c84f3f3cSopenharmony_ci } 1182c84f3f3cSopenharmony_ci else 1183c84f3f3cSopenharmony_ci /* undo temporary */ 1184c84f3f3cSopenharmony_ci quote &= ~2; 1185c84f3f3cSopenharmony_ci 1186c84f3f3cSopenharmony_ci if (make_magic) { 1187c84f3f3cSopenharmony_ci make_magic = false; 1188c84f3f3cSopenharmony_ci fdo |= DOMAGIC | (f & DOGLOB); 1189c84f3f3cSopenharmony_ci *dp++ = MAGIC; 1190c84f3f3cSopenharmony_ci } else if (ISMAGIC(c)) { 1191c84f3f3cSopenharmony_ci fdo |= DOMAGIC; 1192c84f3f3cSopenharmony_ci *dp++ = MAGIC; 1193c84f3f3cSopenharmony_ci } 1194c84f3f3cSopenharmony_ci /* save output char */ 1195c84f3f3cSopenharmony_ci *dp++ = c; 1196c84f3f3cSopenharmony_ci word = IFS_WORD; 1197c84f3f3cSopenharmony_ci } 1198c84f3f3cSopenharmony_ci } 1199c84f3f3cSopenharmony_ci} 1200c84f3f3cSopenharmony_ci 1201c84f3f3cSopenharmony_cistatic bool 1202c84f3f3cSopenharmony_cihasnonempty(const char **strv) 1203c84f3f3cSopenharmony_ci{ 1204c84f3f3cSopenharmony_ci size_t i = 0; 1205c84f3f3cSopenharmony_ci 1206c84f3f3cSopenharmony_ci while (strv[i]) 1207c84f3f3cSopenharmony_ci if (*strv[i++]) 1208c84f3f3cSopenharmony_ci return (true); 1209c84f3f3cSopenharmony_ci return (false); 1210c84f3f3cSopenharmony_ci} 1211c84f3f3cSopenharmony_ci 1212c84f3f3cSopenharmony_ci/* 1213c84f3f3cSopenharmony_ci * Prepare to generate the string returned by ${} substitution. 1214c84f3f3cSopenharmony_ci */ 1215c84f3f3cSopenharmony_cistatic int 1216c84f3f3cSopenharmony_civarsub(Expand *xp, const char *sp, const char *word, 1217c84f3f3cSopenharmony_ci /* becomes qualifier type */ 1218c84f3f3cSopenharmony_ci unsigned int *stypep, 1219c84f3f3cSopenharmony_ci /* becomes qualifier type len (=, :=, etc.) valid iff *stypep != 0 */ 1220c84f3f3cSopenharmony_ci int *slenp) 1221c84f3f3cSopenharmony_ci{ 1222c84f3f3cSopenharmony_ci unsigned int c; 1223c84f3f3cSopenharmony_ci int state; /* next state: XBASE, XARG, XSUB, XNULLSUB */ 1224c84f3f3cSopenharmony_ci unsigned int stype; /* substitution type */ 1225c84f3f3cSopenharmony_ci int slen = 0; 1226c84f3f3cSopenharmony_ci const char *p; 1227c84f3f3cSopenharmony_ci struct tbl *vp; 1228c84f3f3cSopenharmony_ci bool zero_ok = false; 1229c84f3f3cSopenharmony_ci int sc; 1230c84f3f3cSopenharmony_ci XPtrV wv; 1231c84f3f3cSopenharmony_ci 1232c84f3f3cSopenharmony_ci if ((stype = ord(sp[0])) == '\0') 1233c84f3f3cSopenharmony_ci /* Bad variable name */ 1234c84f3f3cSopenharmony_ci return (-1); 1235c84f3f3cSopenharmony_ci 1236c84f3f3cSopenharmony_ci xp->var = NULL; 1237c84f3f3cSopenharmony_ci 1238c84f3f3cSopenharmony_ci /* entirety of named array? */ 1239c84f3f3cSopenharmony_ci if ((p = cstrchr(sp, '[')) && (sc = ord(p[1])) && 1240c84f3f3cSopenharmony_ci ord(p[2]) == ORD(']')) 1241c84f3f3cSopenharmony_ci /* keep p (for ${!foo[1]} below)! */ 1242c84f3f3cSopenharmony_ci switch (sc) { 1243c84f3f3cSopenharmony_ci case ORD('*'): 1244c84f3f3cSopenharmony_ci sc = 3; 1245c84f3f3cSopenharmony_ci break; 1246c84f3f3cSopenharmony_ci case ORD('@'): 1247c84f3f3cSopenharmony_ci sc = 7; 1248c84f3f3cSopenharmony_ci break; 1249c84f3f3cSopenharmony_ci default: 1250c84f3f3cSopenharmony_ci /* bit2 = @, bit1 = array, bit0 = enabled */ 1251c84f3f3cSopenharmony_ci sc = 0; 1252c84f3f3cSopenharmony_ci } 1253c84f3f3cSopenharmony_ci else 1254c84f3f3cSopenharmony_ci /* $* and $@ checked below */ 1255c84f3f3cSopenharmony_ci sc = 0; 1256c84f3f3cSopenharmony_ci 1257c84f3f3cSopenharmony_ci /*- 1258c84f3f3cSopenharmony_ci * ${%var}, string width (-U: screen columns, +U: octets) 1259c84f3f3cSopenharmony_ci * ${#var}, string length (-U: characters, +U: octets) or array size 1260c84f3f3cSopenharmony_ci * ${!var}, variable name 1261c84f3f3cSopenharmony_ci * ${*…} -> set flag for argv 1262c84f3f3cSopenharmony_ci * ${@…} -> set flag for argv 1263c84f3f3cSopenharmony_ci */ 1264c84f3f3cSopenharmony_ci if (ctype(stype, C_SUB2 | CiVAR1)) { 1265c84f3f3cSopenharmony_ci switch (stype) { 1266c84f3f3cSopenharmony_ci case ORD('*'): 1267c84f3f3cSopenharmony_ci if (!sc) 1268c84f3f3cSopenharmony_ci sc = 1; 1269c84f3f3cSopenharmony_ci goto nopfx; 1270c84f3f3cSopenharmony_ci case ORD('@'): 1271c84f3f3cSopenharmony_ci if (!sc) 1272c84f3f3cSopenharmony_ci sc = 5; 1273c84f3f3cSopenharmony_ci goto nopfx; 1274c84f3f3cSopenharmony_ci } 1275c84f3f3cSopenharmony_ci /* varname required */ 1276c84f3f3cSopenharmony_ci if ((c = ord(sp[1])) == '\0') { 1277c84f3f3cSopenharmony_ci if (stype == ORD('%')) 1278c84f3f3cSopenharmony_ci /* $% */ 1279c84f3f3cSopenharmony_ci return (-1); 1280c84f3f3cSopenharmony_ci /* $# or $! */ 1281c84f3f3cSopenharmony_ci goto nopfx; 1282c84f3f3cSopenharmony_ci } 1283c84f3f3cSopenharmony_ci /* can’t have any modifiers for ${#…} or ${%…} or ${!…} */ 1284c84f3f3cSopenharmony_ci if (*word != CSUBST) 1285c84f3f3cSopenharmony_ci return (-1); 1286c84f3f3cSopenharmony_ci /* check for argv past prefix */ 1287c84f3f3cSopenharmony_ci if (!sc) switch (c) { 1288c84f3f3cSopenharmony_ci case ORD('*'): 1289c84f3f3cSopenharmony_ci sc = 1; 1290c84f3f3cSopenharmony_ci break; 1291c84f3f3cSopenharmony_ci case ORD('@'): 1292c84f3f3cSopenharmony_ci sc = 5; 1293c84f3f3cSopenharmony_ci break; 1294c84f3f3cSopenharmony_ci } 1295c84f3f3cSopenharmony_ci /* skip past prefix */ 1296c84f3f3cSopenharmony_ci ++sp; 1297c84f3f3cSopenharmony_ci /* determine result */ 1298c84f3f3cSopenharmony_ci switch (stype) { 1299c84f3f3cSopenharmony_ci case ORD('!'): 1300c84f3f3cSopenharmony_ci if (sc & 2) { 1301c84f3f3cSopenharmony_ci stype = 0; 1302c84f3f3cSopenharmony_ci XPinit(wv, 32); 1303c84f3f3cSopenharmony_ci vp = global(arrayname(sp)); 1304c84f3f3cSopenharmony_ci do { 1305c84f3f3cSopenharmony_ci if (vp->flag & ISSET) 1306c84f3f3cSopenharmony_ci XPput(wv, shf_smprintf(Tf_lu, 1307c84f3f3cSopenharmony_ci arrayindex(vp))); 1308c84f3f3cSopenharmony_ci } while ((vp = vp->u.array)); 1309c84f3f3cSopenharmony_ci goto arraynames; 1310c84f3f3cSopenharmony_ci } 1311c84f3f3cSopenharmony_ci xp->var = global(sp); 1312c84f3f3cSopenharmony_ci /* use saved p from above */ 1313c84f3f3cSopenharmony_ci xp->str = p ? shf_smprintf("%s[%lu]", xp->var->name, 1314c84f3f3cSopenharmony_ci arrayindex(xp->var)) : xp->var->name; 1315c84f3f3cSopenharmony_ci break; 1316c84f3f3cSopenharmony_ci#ifdef DEBUG 1317c84f3f3cSopenharmony_ci default: 1318c84f3f3cSopenharmony_ci internal_errorf("stype mismatch"); 1319c84f3f3cSopenharmony_ci /* NOTREACHED */ 1320c84f3f3cSopenharmony_ci#endif 1321c84f3f3cSopenharmony_ci case ORD('%'): 1322c84f3f3cSopenharmony_ci /* cannot do this on an array */ 1323c84f3f3cSopenharmony_ci if (sc) 1324c84f3f3cSopenharmony_ci return (-1); 1325c84f3f3cSopenharmony_ci p = str_val(global(sp)); 1326c84f3f3cSopenharmony_ci zero_ok = p != null; 1327c84f3f3cSopenharmony_ci /* partial utf_mbswidth reimplementation */ 1328c84f3f3cSopenharmony_ci sc = 0; 1329c84f3f3cSopenharmony_ci while (*p) { 1330c84f3f3cSopenharmony_ci if (!UTFMODE || 1331c84f3f3cSopenharmony_ci (wv.len = utf_mbtowc(&c, p)) == (size_t)-1) 1332c84f3f3cSopenharmony_ci /* not UTFMODE or not UTF-8 */ 1333c84f3f3cSopenharmony_ci c = rtt2asc(*p++); 1334c84f3f3cSopenharmony_ci else 1335c84f3f3cSopenharmony_ci /* UTFMODE and UTF-8 */ 1336c84f3f3cSopenharmony_ci p += wv.len; 1337c84f3f3cSopenharmony_ci /* c == char or wchar at p++ */ 1338c84f3f3cSopenharmony_ci if ((slen = utf_wcwidth(c)) == -1) { 1339c84f3f3cSopenharmony_ci /* 646, 8859-1, 10646 C0/C1 */ 1340c84f3f3cSopenharmony_ci sc = -1; 1341c84f3f3cSopenharmony_ci break; 1342c84f3f3cSopenharmony_ci } 1343c84f3f3cSopenharmony_ci sc += slen; 1344c84f3f3cSopenharmony_ci } 1345c84f3f3cSopenharmony_ci if (0) 1346c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1347c84f3f3cSopenharmony_ci case ORD('#'): 1348c84f3f3cSopenharmony_ci switch (sc & 3) { 1349c84f3f3cSopenharmony_ci case 3: 1350c84f3f3cSopenharmony_ci vp = global(arrayname(sp)); 1351c84f3f3cSopenharmony_ci if (vp->flag & (ISSET|ARRAY)) 1352c84f3f3cSopenharmony_ci zero_ok = true; 1353c84f3f3cSopenharmony_ci sc = 0; 1354c84f3f3cSopenharmony_ci do { 1355c84f3f3cSopenharmony_ci if (vp->flag & ISSET) 1356c84f3f3cSopenharmony_ci sc++; 1357c84f3f3cSopenharmony_ci } while ((vp = vp->u.array)); 1358c84f3f3cSopenharmony_ci break; 1359c84f3f3cSopenharmony_ci case 1: 1360c84f3f3cSopenharmony_ci sc = e->loc->argc; 1361c84f3f3cSopenharmony_ci break; 1362c84f3f3cSopenharmony_ci default: 1363c84f3f3cSopenharmony_ci p = str_val(global(sp)); 1364c84f3f3cSopenharmony_ci zero_ok = p != null; 1365c84f3f3cSopenharmony_ci sc = utflen(p); 1366c84f3f3cSopenharmony_ci break; 1367c84f3f3cSopenharmony_ci } 1368c84f3f3cSopenharmony_ci /* ${%var} also here */ 1369c84f3f3cSopenharmony_ci if (Flag(FNOUNSET) && sc == 0 && !zero_ok) 1370c84f3f3cSopenharmony_ci errorf(Tf_parm, sp); 1371c84f3f3cSopenharmony_ci xp->str = shf_smprintf(Tf_d, sc); 1372c84f3f3cSopenharmony_ci break; 1373c84f3f3cSopenharmony_ci } 1374c84f3f3cSopenharmony_ci /* unqualified variable/string substitution */ 1375c84f3f3cSopenharmony_ci *stypep = 0; 1376c84f3f3cSopenharmony_ci return (XSUB); 1377c84f3f3cSopenharmony_ci } 1378c84f3f3cSopenharmony_ci nopfx: 1379c84f3f3cSopenharmony_ci 1380c84f3f3cSopenharmony_ci /* check for qualifiers in word part */ 1381c84f3f3cSopenharmony_ci stype = 0; 1382c84f3f3cSopenharmony_ci /*slen = 0;*/ 1383c84f3f3cSopenharmony_ci c = word[/*slen +*/ 0] == CHAR ? ord(word[/*slen +*/ 1]) : 0; 1384c84f3f3cSopenharmony_ci if (c == ORD(':')) { 1385c84f3f3cSopenharmony_ci slen += 2; 1386c84f3f3cSopenharmony_ci stype = STYPE_DBL; 1387c84f3f3cSopenharmony_ci c = word[slen + 0] == CHAR ? ord(word[slen + 1]) : 0; 1388c84f3f3cSopenharmony_ci } 1389c84f3f3cSopenharmony_ci if (!stype && c == ORD('/')) { 1390c84f3f3cSopenharmony_ci slen += 2; 1391c84f3f3cSopenharmony_ci stype = c; 1392c84f3f3cSopenharmony_ci if (word[slen] == ADELIM && 1393c84f3f3cSopenharmony_ci ord(word[slen + 1]) == c) { 1394c84f3f3cSopenharmony_ci slen += 2; 1395c84f3f3cSopenharmony_ci stype |= STYPE_DBL; 1396c84f3f3cSopenharmony_ci } 1397c84f3f3cSopenharmony_ci } else if (stype == STYPE_DBL && (c == ORD(' ') || c == ORD('0'))) { 1398c84f3f3cSopenharmony_ci stype |= ORD('0'); 1399c84f3f3cSopenharmony_ci } else if (ctype(c, C_SUB1)) { 1400c84f3f3cSopenharmony_ci slen += 2; 1401c84f3f3cSopenharmony_ci stype |= c; 1402c84f3f3cSopenharmony_ci } else if (ctype(c, C_SUB2)) { 1403c84f3f3cSopenharmony_ci /* Note: ksh88 allows :%, :%%, etc */ 1404c84f3f3cSopenharmony_ci slen += 2; 1405c84f3f3cSopenharmony_ci stype = c; 1406c84f3f3cSopenharmony_ci if (word[slen + 0] == CHAR && ord(word[slen + 1]) == c) { 1407c84f3f3cSopenharmony_ci stype |= STYPE_DBL; 1408c84f3f3cSopenharmony_ci slen += 2; 1409c84f3f3cSopenharmony_ci } 1410c84f3f3cSopenharmony_ci } else if (c == ORD('@')) { 1411c84f3f3cSopenharmony_ci /* @x where x is command char */ 1412c84f3f3cSopenharmony_ci switch (c = ord(word[slen + 2]) == CHAR ? 1413c84f3f3cSopenharmony_ci ord(word[slen + 3]) : 0) { 1414c84f3f3cSopenharmony_ci case ORD('#'): 1415c84f3f3cSopenharmony_ci case ORD('/'): 1416c84f3f3cSopenharmony_ci case ORD('Q'): 1417c84f3f3cSopenharmony_ci break; 1418c84f3f3cSopenharmony_ci default: 1419c84f3f3cSopenharmony_ci return (-1); 1420c84f3f3cSopenharmony_ci } 1421c84f3f3cSopenharmony_ci stype |= STYPE_AT | c; 1422c84f3f3cSopenharmony_ci slen += 4; 1423c84f3f3cSopenharmony_ci } else if (stype) 1424c84f3f3cSopenharmony_ci /* : is not ok */ 1425c84f3f3cSopenharmony_ci return (-1); 1426c84f3f3cSopenharmony_ci if (!stype && *word != CSUBST) 1427c84f3f3cSopenharmony_ci return (-1); 1428c84f3f3cSopenharmony_ci 1429c84f3f3cSopenharmony_ci if (!sc) { 1430c84f3f3cSopenharmony_ci xp->var = global(sp); 1431c84f3f3cSopenharmony_ci xp->str = str_val(xp->var); 1432c84f3f3cSopenharmony_ci /* can't assign things like $! or $1 */ 1433c84f3f3cSopenharmony_ci if ((stype & STYPE_SINGLE) == ORD('=') && 1434c84f3f3cSopenharmony_ci !*xp->str && ctype(*sp, C_VAR1 | C_DIGIT)) 1435c84f3f3cSopenharmony_ci return (-1); 1436c84f3f3cSopenharmony_ci state = XSUB; 1437c84f3f3cSopenharmony_ci } else { 1438c84f3f3cSopenharmony_ci /* can’t assign/trim a vector (yet) */ 1439c84f3f3cSopenharmony_ci switch (stype & STYPE_SINGLE) { 1440c84f3f3cSopenharmony_ci case ORD('-'): 1441c84f3f3cSopenharmony_ci case ORD('+'): 1442c84f3f3cSopenharmony_ci /* allowed ops */ 1443c84f3f3cSopenharmony_ci case 0: 1444c84f3f3cSopenharmony_ci /* or no ops */ 1445c84f3f3cSopenharmony_ci break; 1446c84f3f3cSopenharmony_ci /* case ORD('='): 1447c84f3f3cSopenharmony_ci case ORD('?'): 1448c84f3f3cSopenharmony_ci case ORD('#'): 1449c84f3f3cSopenharmony_ci case ORD('%'): 1450c84f3f3cSopenharmony_ci case ORD('/'): 1451c84f3f3cSopenharmony_ci case ORD('/') | STYPE_AT: 1452c84f3f3cSopenharmony_ci case ORD('0'): 1453c84f3f3cSopenharmony_ci case ORD('#') | STYPE_AT: 1454c84f3f3cSopenharmony_ci case ORD('Q') | STYPE_AT: 1455c84f3f3cSopenharmony_ci */ default: 1456c84f3f3cSopenharmony_ci return (-1); 1457c84f3f3cSopenharmony_ci } 1458c84f3f3cSopenharmony_ci /* do what we can */ 1459c84f3f3cSopenharmony_ci if (sc & 2) { 1460c84f3f3cSopenharmony_ci XPinit(wv, 32); 1461c84f3f3cSopenharmony_ci vp = global(arrayname(sp)); 1462c84f3f3cSopenharmony_ci do { 1463c84f3f3cSopenharmony_ci if (vp->flag & ISSET) 1464c84f3f3cSopenharmony_ci XPput(wv, str_val(vp)); 1465c84f3f3cSopenharmony_ci } while ((vp = vp->u.array)); 1466c84f3f3cSopenharmony_ci arraynames: 1467c84f3f3cSopenharmony_ci if ((c = (XPsize(wv) == 0))) 1468c84f3f3cSopenharmony_ci XPfree(wv); 1469c84f3f3cSopenharmony_ci else { 1470c84f3f3cSopenharmony_ci XPput(wv, NULL); 1471c84f3f3cSopenharmony_ci xp->u.strv = (const char **)XPptrv(wv); 1472c84f3f3cSopenharmony_ci } 1473c84f3f3cSopenharmony_ci } else { 1474c84f3f3cSopenharmony_ci if ((c = (e->loc->argc == 0))) 1475c84f3f3cSopenharmony_ci xp->var = global(sp); 1476c84f3f3cSopenharmony_ci else 1477c84f3f3cSopenharmony_ci xp->u.strv = (const char **)e->loc->argv + 1; 1478c84f3f3cSopenharmony_ci /* POSIX 2009? */ 1479c84f3f3cSopenharmony_ci zero_ok = true; 1480c84f3f3cSopenharmony_ci } 1481c84f3f3cSopenharmony_ci /* have we got any elements? */ 1482c84f3f3cSopenharmony_ci if (c) { 1483c84f3f3cSopenharmony_ci /* no */ 1484c84f3f3cSopenharmony_ci xp->str = null; 1485c84f3f3cSopenharmony_ci state = sc & 4 ? XNULLSUB : XSUB; 1486c84f3f3cSopenharmony_ci } else { 1487c84f3f3cSopenharmony_ci /* yes → load first */ 1488c84f3f3cSopenharmony_ci xp->str = *xp->u.strv++; 1489c84f3f3cSopenharmony_ci /* $@ or ${foo[@]} */ 1490c84f3f3cSopenharmony_ci xp->split = tobool(sc & 4); 1491c84f3f3cSopenharmony_ci state = XARG; 1492c84f3f3cSopenharmony_ci } 1493c84f3f3cSopenharmony_ci } 1494c84f3f3cSopenharmony_ci 1495c84f3f3cSopenharmony_ci c = stype & STYPE_CHAR; 1496c84f3f3cSopenharmony_ci /* test the compiler's code generator */ 1497c84f3f3cSopenharmony_ci if ((!(stype & STYPE_AT) && (ctype(c, C_SUB2) || 1498c84f3f3cSopenharmony_ci (((stype & STYPE_DBL) ? *xp->str == '\0' : xp->str == null) && 1499c84f3f3cSopenharmony_ci (state != XARG || (ifs0 || xp->split ? 1500c84f3f3cSopenharmony_ci (xp->u.strv[0] == NULL) : !hasnonempty(xp->u.strv))) ? 1501c84f3f3cSopenharmony_ci ctype(c, C_EQUAL | C_MINUS | C_QUEST) : c == ORD('+')))) || 1502c84f3f3cSopenharmony_ci stype == (ORD('0') | STYPE_DBL) || 1503c84f3f3cSopenharmony_ci stype == (ORD('#') | STYPE_AT) || 1504c84f3f3cSopenharmony_ci stype == (ORD('Q') | STYPE_AT) || 1505c84f3f3cSopenharmony_ci (stype & STYPE_CHAR) == ORD('/')) 1506c84f3f3cSopenharmony_ci /* expand word instead of variable value */ 1507c84f3f3cSopenharmony_ci state = XBASE; 1508c84f3f3cSopenharmony_ci if (Flag(FNOUNSET) && xp->str == null && !zero_ok && 1509c84f3f3cSopenharmony_ci (ctype(c, C_SUB2) || (state != XBASE && c != ORD('+')))) 1510c84f3f3cSopenharmony_ci errorf(Tf_parm, sp); 1511c84f3f3cSopenharmony_ci *stypep = stype; 1512c84f3f3cSopenharmony_ci *slenp = slen; 1513c84f3f3cSopenharmony_ci return (state); 1514c84f3f3cSopenharmony_ci} 1515c84f3f3cSopenharmony_ci 1516c84f3f3cSopenharmony_ci/* 1517c84f3f3cSopenharmony_ci * Run the command in $(...) and read its output. 1518c84f3f3cSopenharmony_ci */ 1519c84f3f3cSopenharmony_cistatic int 1520c84f3f3cSopenharmony_cicomsub(Expand *xp, const char *cp, int fn) 1521c84f3f3cSopenharmony_ci{ 1522c84f3f3cSopenharmony_ci Source *s, *sold; 1523c84f3f3cSopenharmony_ci struct op *t; 1524c84f3f3cSopenharmony_ci struct shf *shf; 1525c84f3f3cSopenharmony_ci bool doalias = false; 1526c84f3f3cSopenharmony_ci uint8_t old_utfmode = UTFMODE; 1527c84f3f3cSopenharmony_ci 1528c84f3f3cSopenharmony_ci switch (fn) { 1529c84f3f3cSopenharmony_ci case COMASUB: 1530c84f3f3cSopenharmony_ci fn = COMSUB; 1531c84f3f3cSopenharmony_ci if (0) 1532c84f3f3cSopenharmony_ci /* FALLTHROUGH */ 1533c84f3f3cSopenharmony_ci case FUNASUB: 1534c84f3f3cSopenharmony_ci fn = FUNSUB; 1535c84f3f3cSopenharmony_ci doalias = true; 1536c84f3f3cSopenharmony_ci } 1537c84f3f3cSopenharmony_ci 1538c84f3f3cSopenharmony_ci s = pushs(SSTRING, ATEMP); 1539c84f3f3cSopenharmony_ci s->start = s->str = cp; 1540c84f3f3cSopenharmony_ci sold = source; 1541c84f3f3cSopenharmony_ci t = compile(s, true, doalias); 1542c84f3f3cSopenharmony_ci afree(s, ATEMP); 1543c84f3f3cSopenharmony_ci source = sold; 1544c84f3f3cSopenharmony_ci 1545c84f3f3cSopenharmony_ci UTFMODE = old_utfmode; 1546c84f3f3cSopenharmony_ci 1547c84f3f3cSopenharmony_ci if (t == NULL) 1548c84f3f3cSopenharmony_ci return (XBASE); 1549c84f3f3cSopenharmony_ci 1550c84f3f3cSopenharmony_ci /* no waitlast() unless specifically enabled later */ 1551c84f3f3cSopenharmony_ci xp->split = false; 1552c84f3f3cSopenharmony_ci 1553c84f3f3cSopenharmony_ci if (t->type == TCOM && 1554c84f3f3cSopenharmony_ci *t->args == NULL && *t->vars == NULL && t->ioact != NULL) { 1555c84f3f3cSopenharmony_ci /* $(<file) */ 1556c84f3f3cSopenharmony_ci struct ioword *io = *t->ioact; 1557c84f3f3cSopenharmony_ci char *name; 1558c84f3f3cSopenharmony_ci 1559c84f3f3cSopenharmony_ci switch (io->ioflag & IOTYPE) { 1560c84f3f3cSopenharmony_ci case IOREAD: 1561c84f3f3cSopenharmony_ci shf = shf_open(name = evalstr(io->ioname, DOTILDE), 1562c84f3f3cSopenharmony_ci O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC); 1563c84f3f3cSopenharmony_ci if (shf == NULL) 1564c84f3f3cSopenharmony_ci warningf(!Flag(FTALKING), Tf_sD_s_sD_s, 1565c84f3f3cSopenharmony_ci name, Tcant_open, "$(<...) input", 1566c84f3f3cSopenharmony_ci cstrerror(errno)); 1567c84f3f3cSopenharmony_ci break; 1568c84f3f3cSopenharmony_ci case IOHERE: 1569c84f3f3cSopenharmony_ci if (!herein(io, &name)) { 1570c84f3f3cSopenharmony_ci xp->str = name; 1571c84f3f3cSopenharmony_ci /* as $(…) requires, trim trailing newlines */ 1572c84f3f3cSopenharmony_ci name = strnul(name); 1573c84f3f3cSopenharmony_ci while (name > xp->str && name[-1] == '\n') 1574c84f3f3cSopenharmony_ci --name; 1575c84f3f3cSopenharmony_ci *name = '\0'; 1576c84f3f3cSopenharmony_ci return (XSUB); 1577c84f3f3cSopenharmony_ci } 1578c84f3f3cSopenharmony_ci shf = NULL; 1579c84f3f3cSopenharmony_ci break; 1580c84f3f3cSopenharmony_ci default: 1581c84f3f3cSopenharmony_ci errorf(Tf_sD_s, T_funny_command, 1582c84f3f3cSopenharmony_ci snptreef(NULL, 32, Tft_R, io)); 1583c84f3f3cSopenharmony_ci } 1584c84f3f3cSopenharmony_ci } else if (fn == FUNSUB) { 1585c84f3f3cSopenharmony_ci int ofd1; 1586c84f3f3cSopenharmony_ci struct temp *tf = NULL; 1587c84f3f3cSopenharmony_ci 1588c84f3f3cSopenharmony_ci /* 1589c84f3f3cSopenharmony_ci * create a temporary file, open for reading and writing, 1590c84f3f3cSopenharmony_ci * with an shf open for reading (buffered) but yet unused 1591c84f3f3cSopenharmony_ci */ 1592c84f3f3cSopenharmony_ci maketemp(ATEMP, TT_FUNSUB, &tf); 1593c84f3f3cSopenharmony_ci if (!tf->shf) { 1594c84f3f3cSopenharmony_ci errorf(Tf_temp, 1595c84f3f3cSopenharmony_ci Tcreate, tf->tffn, cstrerror(errno)); 1596c84f3f3cSopenharmony_ci } 1597c84f3f3cSopenharmony_ci /* extract shf from temporary file, unlink and free it */ 1598c84f3f3cSopenharmony_ci shf = tf->shf; 1599c84f3f3cSopenharmony_ci unlink(tf->tffn); 1600c84f3f3cSopenharmony_ci afree(tf, ATEMP); 1601c84f3f3cSopenharmony_ci /* save stdout and let it point to the tempfile */ 1602c84f3f3cSopenharmony_ci ofd1 = savefd(1); 1603c84f3f3cSopenharmony_ci ksh_dup2(shf_fileno(shf), 1, false); 1604c84f3f3cSopenharmony_ci /* 1605c84f3f3cSopenharmony_ci * run tree, with output thrown into the tempfile, 1606c84f3f3cSopenharmony_ci * in a new function block 1607c84f3f3cSopenharmony_ci */ 1608c84f3f3cSopenharmony_ci valsub(t, NULL); 1609c84f3f3cSopenharmony_ci subst_exstat = exstat & 0xFF; 1610c84f3f3cSopenharmony_ci /* rewind the tempfile and restore regular stdout */ 1611c84f3f3cSopenharmony_ci lseek(shf_fileno(shf), (off_t)0, SEEK_SET); 1612c84f3f3cSopenharmony_ci restfd(1, ofd1); 1613c84f3f3cSopenharmony_ci } else if (fn == VALSUB) { 1614c84f3f3cSopenharmony_ci xp->str = valsub(t, ATEMP); 1615c84f3f3cSopenharmony_ci subst_exstat = exstat & 0xFF; 1616c84f3f3cSopenharmony_ci return (XSUB); 1617c84f3f3cSopenharmony_ci } else { 1618c84f3f3cSopenharmony_ci int ofd1, pv[2]; 1619c84f3f3cSopenharmony_ci 1620c84f3f3cSopenharmony_ci openpipe(pv); 1621c84f3f3cSopenharmony_ci shf = shf_fdopen(pv[0], SHF_RD, NULL); 1622c84f3f3cSopenharmony_ci ofd1 = savefd(1); 1623c84f3f3cSopenharmony_ci if (pv[1] != 1) { 1624c84f3f3cSopenharmony_ci ksh_dup2(pv[1], 1, false); 1625c84f3f3cSopenharmony_ci close(pv[1]); 1626c84f3f3cSopenharmony_ci } 1627c84f3f3cSopenharmony_ci execute(t, XXCOM | XPIPEO | XFORK, NULL); 1628c84f3f3cSopenharmony_ci restfd(1, ofd1); 1629c84f3f3cSopenharmony_ci startlast(); 1630c84f3f3cSopenharmony_ci /* waitlast() */ 1631c84f3f3cSopenharmony_ci xp->split = true; 1632c84f3f3cSopenharmony_ci } 1633c84f3f3cSopenharmony_ci 1634c84f3f3cSopenharmony_ci xp->u.shf = shf; 1635c84f3f3cSopenharmony_ci return (XCOM); 1636c84f3f3cSopenharmony_ci} 1637c84f3f3cSopenharmony_ci 1638c84f3f3cSopenharmony_ci/* 1639c84f3f3cSopenharmony_ci * perform #pattern and %pattern substitution in ${} 1640c84f3f3cSopenharmony_ci */ 1641c84f3f3cSopenharmony_cistatic char * 1642c84f3f3cSopenharmony_citrimsub(char *str, char *pat, int how) 1643c84f3f3cSopenharmony_ci{ 1644c84f3f3cSopenharmony_ci char *end = strnul(str); 1645c84f3f3cSopenharmony_ci char *p, c; 1646c84f3f3cSopenharmony_ci 1647c84f3f3cSopenharmony_ci switch (how & (STYPE_CHAR | STYPE_DBL)) { 1648c84f3f3cSopenharmony_ci case ORD('#'): 1649c84f3f3cSopenharmony_ci /* shortest match at beginning */ 1650c84f3f3cSopenharmony_ci for (p = str; p <= end; p += utf_ptradj(p)) { 1651c84f3f3cSopenharmony_ci c = *p; *p = '\0'; 1652c84f3f3cSopenharmony_ci if (gmatchx(str, pat, false)) { 1653c84f3f3cSopenharmony_ci record_match(str); 1654c84f3f3cSopenharmony_ci *p = c; 1655c84f3f3cSopenharmony_ci return (p); 1656c84f3f3cSopenharmony_ci } 1657c84f3f3cSopenharmony_ci *p = c; 1658c84f3f3cSopenharmony_ci } 1659c84f3f3cSopenharmony_ci break; 1660c84f3f3cSopenharmony_ci case ORD('#') | STYPE_DBL: 1661c84f3f3cSopenharmony_ci /* longest match at beginning */ 1662c84f3f3cSopenharmony_ci for (p = end; p >= str; p--) { 1663c84f3f3cSopenharmony_ci c = *p; *p = '\0'; 1664c84f3f3cSopenharmony_ci if (gmatchx(str, pat, false)) { 1665c84f3f3cSopenharmony_ci record_match(str); 1666c84f3f3cSopenharmony_ci *p = c; 1667c84f3f3cSopenharmony_ci return (p); 1668c84f3f3cSopenharmony_ci } 1669c84f3f3cSopenharmony_ci *p = c; 1670c84f3f3cSopenharmony_ci } 1671c84f3f3cSopenharmony_ci break; 1672c84f3f3cSopenharmony_ci case ORD('%'): 1673c84f3f3cSopenharmony_ci /* shortest match at end */ 1674c84f3f3cSopenharmony_ci p = end; 1675c84f3f3cSopenharmony_ci while (p >= str) { 1676c84f3f3cSopenharmony_ci if (gmatchx(p, pat, false)) 1677c84f3f3cSopenharmony_ci goto trimsub_match; 1678c84f3f3cSopenharmony_ci if (UTFMODE) { 1679c84f3f3cSopenharmony_ci char *op = p; 1680c84f3f3cSopenharmony_ci while ((p-- > str) && ((rtt2asc(*p) & 0xC0) == 0x80)) 1681c84f3f3cSopenharmony_ci ; 1682c84f3f3cSopenharmony_ci if ((p < str) || (p + utf_ptradj(p) != op)) 1683c84f3f3cSopenharmony_ci p = op - 1; 1684c84f3f3cSopenharmony_ci } else 1685c84f3f3cSopenharmony_ci --p; 1686c84f3f3cSopenharmony_ci } 1687c84f3f3cSopenharmony_ci break; 1688c84f3f3cSopenharmony_ci case ORD('%') | STYPE_DBL: 1689c84f3f3cSopenharmony_ci /* longest match at end */ 1690c84f3f3cSopenharmony_ci for (p = str; p <= end; p++) 1691c84f3f3cSopenharmony_ci if (gmatchx(p, pat, false)) { 1692c84f3f3cSopenharmony_ci trimsub_match: 1693c84f3f3cSopenharmony_ci record_match(p); 1694c84f3f3cSopenharmony_ci strndupx(end, str, p - str, ATEMP); 1695c84f3f3cSopenharmony_ci return (end); 1696c84f3f3cSopenharmony_ci } 1697c84f3f3cSopenharmony_ci break; 1698c84f3f3cSopenharmony_ci } 1699c84f3f3cSopenharmony_ci 1700c84f3f3cSopenharmony_ci /* no match, return string */ 1701c84f3f3cSopenharmony_ci return (str); 1702c84f3f3cSopenharmony_ci} 1703c84f3f3cSopenharmony_ci 1704c84f3f3cSopenharmony_ci/* 1705c84f3f3cSopenharmony_ci * glob 1706c84f3f3cSopenharmony_ci * Name derived from V6's /etc/glob, the program that expanded filenames. 1707c84f3f3cSopenharmony_ci */ 1708c84f3f3cSopenharmony_ci 1709c84f3f3cSopenharmony_ci/* XXX cp not const 'cause slashes are temporarily replaced with NULs... */ 1710c84f3f3cSopenharmony_cistatic void 1711c84f3f3cSopenharmony_ciglob(char *cp, XPtrV *wp, bool markdirs) 1712c84f3f3cSopenharmony_ci{ 1713c84f3f3cSopenharmony_ci int oldsize = XPsize(*wp); 1714c84f3f3cSopenharmony_ci 1715c84f3f3cSopenharmony_ci if (glob_str(cp, wp, markdirs) == 0) 1716c84f3f3cSopenharmony_ci XPput(*wp, debunk(cp, cp, strlen(cp) + 1)); 1717c84f3f3cSopenharmony_ci else 1718c84f3f3cSopenharmony_ci qsort(XPptrv(*wp) + oldsize, XPsize(*wp) - oldsize, 1719c84f3f3cSopenharmony_ci sizeof(void *), ascpstrcmp); 1720c84f3f3cSopenharmony_ci} 1721c84f3f3cSopenharmony_ci 1722c84f3f3cSopenharmony_ci#define GF_NONE 0 1723c84f3f3cSopenharmony_ci#define GF_EXCHECK BIT(0) /* do existence check on file */ 1724c84f3f3cSopenharmony_ci#define GF_GLOBBED BIT(1) /* some globbing has been done */ 1725c84f3f3cSopenharmony_ci#define GF_MARKDIR BIT(2) /* add trailing / to directories */ 1726c84f3f3cSopenharmony_ci 1727c84f3f3cSopenharmony_ci/* 1728c84f3f3cSopenharmony_ci * Apply file globbing to cp and store the matching files in wp. Returns 1729c84f3f3cSopenharmony_ci * the number of matches found. 1730c84f3f3cSopenharmony_ci */ 1731c84f3f3cSopenharmony_ciint 1732c84f3f3cSopenharmony_ciglob_str(char *cp, XPtrV *wp, bool markdirs) 1733c84f3f3cSopenharmony_ci{ 1734c84f3f3cSopenharmony_ci int oldsize = XPsize(*wp); 1735c84f3f3cSopenharmony_ci XString xs; 1736c84f3f3cSopenharmony_ci char *xp; 1737c84f3f3cSopenharmony_ci 1738c84f3f3cSopenharmony_ci Xinit(xs, xp, 256, ATEMP); 1739c84f3f3cSopenharmony_ci globit(&xs, &xp, cp, wp, markdirs ? GF_MARKDIR : GF_NONE); 1740c84f3f3cSopenharmony_ci Xfree(xs, xp); 1741c84f3f3cSopenharmony_ci 1742c84f3f3cSopenharmony_ci return (XPsize(*wp) - oldsize); 1743c84f3f3cSopenharmony_ci} 1744c84f3f3cSopenharmony_ci 1745c84f3f3cSopenharmony_cistatic void 1746c84f3f3cSopenharmony_ciglobit(XString *xs, /* dest string */ 1747c84f3f3cSopenharmony_ci char **xpp, /* ptr to dest end */ 1748c84f3f3cSopenharmony_ci char *sp, /* source path */ 1749c84f3f3cSopenharmony_ci XPtrV *wp, /* output list */ 1750c84f3f3cSopenharmony_ci int check) /* GF_* flags */ 1751c84f3f3cSopenharmony_ci{ 1752c84f3f3cSopenharmony_ci char *np; /* next source component */ 1753c84f3f3cSopenharmony_ci char *xp = *xpp; 1754c84f3f3cSopenharmony_ci char *se; 1755c84f3f3cSopenharmony_ci char odirsep; 1756c84f3f3cSopenharmony_ci 1757c84f3f3cSopenharmony_ci /* This to allow long expansions to be interrupted */ 1758c84f3f3cSopenharmony_ci intrcheck(); 1759c84f3f3cSopenharmony_ci 1760c84f3f3cSopenharmony_ci if (sp == NULL) { 1761c84f3f3cSopenharmony_ci /* end of source path */ 1762c84f3f3cSopenharmony_ci /* 1763c84f3f3cSopenharmony_ci * We only need to check if the file exists if a pattern 1764c84f3f3cSopenharmony_ci * is followed by a non-pattern (eg, foo*x/bar; no check 1765c84f3f3cSopenharmony_ci * is needed for foo* since the match must exist) or if 1766c84f3f3cSopenharmony_ci * any patterns were expanded and the markdirs option is set. 1767c84f3f3cSopenharmony_ci * Symlinks make things a bit tricky... 1768c84f3f3cSopenharmony_ci */ 1769c84f3f3cSopenharmony_ci if ((check & GF_EXCHECK) || 1770c84f3f3cSopenharmony_ci ((check & GF_MARKDIR) && (check & GF_GLOBBED))) { 1771c84f3f3cSopenharmony_ci#define stat_check() (stat_done ? stat_done : (stat_done = \ 1772c84f3f3cSopenharmony_ci stat(Xstring(*xs, xp), &statb) < 0 ? -1 : 1)) 1773c84f3f3cSopenharmony_ci struct stat lstatb, statb; 1774c84f3f3cSopenharmony_ci /* -1: failed, 1 ok, 0 not yet done */ 1775c84f3f3cSopenharmony_ci int stat_done = 0; 1776c84f3f3cSopenharmony_ci 1777c84f3f3cSopenharmony_ci if (mksh_lstat(Xstring(*xs, xp), &lstatb) < 0) 1778c84f3f3cSopenharmony_ci return; 1779c84f3f3cSopenharmony_ci /* 1780c84f3f3cSopenharmony_ci * special case for systems which strip trailing 1781c84f3f3cSopenharmony_ci * slashes from regular files (eg, /etc/passwd/). 1782c84f3f3cSopenharmony_ci * SunOS 4.1.3 does this... 1783c84f3f3cSopenharmony_ci */ 1784c84f3f3cSopenharmony_ci if ((check & GF_EXCHECK) && xp > Xstring(*xs, xp) && 1785c84f3f3cSopenharmony_ci mksh_cdirsep(xp[-1]) && !S_ISDIR(lstatb.st_mode) && 1786c84f3f3cSopenharmony_ci (!S_ISLNK(lstatb.st_mode) || 1787c84f3f3cSopenharmony_ci stat_check() < 0 || !S_ISDIR(statb.st_mode))) 1788c84f3f3cSopenharmony_ci return; 1789c84f3f3cSopenharmony_ci /* 1790c84f3f3cSopenharmony_ci * Possibly tack on a trailing / if there isn't already 1791c84f3f3cSopenharmony_ci * one and if the file is a directory or a symlink to a 1792c84f3f3cSopenharmony_ci * directory 1793c84f3f3cSopenharmony_ci */ 1794c84f3f3cSopenharmony_ci if (((check & GF_MARKDIR) && (check & GF_GLOBBED)) && 1795c84f3f3cSopenharmony_ci xp > Xstring(*xs, xp) && !mksh_cdirsep(xp[-1]) && 1796c84f3f3cSopenharmony_ci (S_ISDIR(lstatb.st_mode) || 1797c84f3f3cSopenharmony_ci (S_ISLNK(lstatb.st_mode) && stat_check() > 0 && 1798c84f3f3cSopenharmony_ci S_ISDIR(statb.st_mode)))) { 1799c84f3f3cSopenharmony_ci *xp++ = '/'; 1800c84f3f3cSopenharmony_ci *xp = '\0'; 1801c84f3f3cSopenharmony_ci } 1802c84f3f3cSopenharmony_ci } 1803c84f3f3cSopenharmony_ci strndupx(np, Xstring(*xs, xp), Xlength(*xs, xp), ATEMP); 1804c84f3f3cSopenharmony_ci XPput(*wp, np); 1805c84f3f3cSopenharmony_ci return; 1806c84f3f3cSopenharmony_ci } 1807c84f3f3cSopenharmony_ci 1808c84f3f3cSopenharmony_ci if (xp > Xstring(*xs, xp)) 1809c84f3f3cSopenharmony_ci *xp++ = '/'; 1810c84f3f3cSopenharmony_ci while (mksh_cdirsep(*sp)) { 1811c84f3f3cSopenharmony_ci Xcheck(*xs, xp); 1812c84f3f3cSopenharmony_ci *xp++ = *sp++; 1813c84f3f3cSopenharmony_ci } 1814c84f3f3cSopenharmony_ci np = mksh_sdirsep(sp); 1815c84f3f3cSopenharmony_ci if (np != NULL) { 1816c84f3f3cSopenharmony_ci se = np; 1817c84f3f3cSopenharmony_ci /* don't assume '/', can be multiple kinds */ 1818c84f3f3cSopenharmony_ci odirsep = *np; 1819c84f3f3cSopenharmony_ci *np++ = '\0'; 1820c84f3f3cSopenharmony_ci } else { 1821c84f3f3cSopenharmony_ci odirsep = '\0'; /* keep gcc quiet */ 1822c84f3f3cSopenharmony_ci se = strnul(sp); 1823c84f3f3cSopenharmony_ci } 1824c84f3f3cSopenharmony_ci 1825c84f3f3cSopenharmony_ci 1826c84f3f3cSopenharmony_ci /* 1827c84f3f3cSopenharmony_ci * Check if sp needs globbing - done to avoid pattern checks for strings 1828c84f3f3cSopenharmony_ci * containing MAGIC characters, open [s without the matching close ], 1829c84f3f3cSopenharmony_ci * etc. (otherwise opendir() will be called which may fail because the 1830c84f3f3cSopenharmony_ci * directory isn't readable - if no globbing is needed, only execute 1831c84f3f3cSopenharmony_ci * permission should be required (as per POSIX)). 1832c84f3f3cSopenharmony_ci */ 1833c84f3f3cSopenharmony_ci if (!has_globbing(sp)) { 1834c84f3f3cSopenharmony_ci XcheckN(*xs, xp, se - sp + 1); 1835c84f3f3cSopenharmony_ci debunk(xp, sp, Xnleft(*xs, xp)); 1836c84f3f3cSopenharmony_ci xp = strnul(xp); 1837c84f3f3cSopenharmony_ci *xpp = xp; 1838c84f3f3cSopenharmony_ci globit(xs, xpp, np, wp, check); 1839c84f3f3cSopenharmony_ci } else { 1840c84f3f3cSopenharmony_ci DIR *dirp; 1841c84f3f3cSopenharmony_ci struct dirent *d; 1842c84f3f3cSopenharmony_ci char *name; 1843c84f3f3cSopenharmony_ci size_t len, prefix_len; 1844c84f3f3cSopenharmony_ci 1845c84f3f3cSopenharmony_ci /* xp = *xpp; copy_non_glob() may have re-alloc'd xs */ 1846c84f3f3cSopenharmony_ci *xp = '\0'; 1847c84f3f3cSopenharmony_ci prefix_len = Xlength(*xs, xp); 1848c84f3f3cSopenharmony_ci dirp = opendir(prefix_len ? Xstring(*xs, xp) : Tdot); 1849c84f3f3cSopenharmony_ci if (dirp == NULL) 1850c84f3f3cSopenharmony_ci goto Nodir; 1851c84f3f3cSopenharmony_ci while ((d = readdir(dirp)) != NULL) { 1852c84f3f3cSopenharmony_ci name = d->d_name; 1853c84f3f3cSopenharmony_ci if (name[0] == '.' && 1854c84f3f3cSopenharmony_ci (name[1] == 0 || (name[1] == '.' && name[2] == 0))) 1855c84f3f3cSopenharmony_ci /* always ignore . and .. */ 1856c84f3f3cSopenharmony_ci continue; 1857c84f3f3cSopenharmony_ci if ((*name == '.' && *sp != '.') || 1858c84f3f3cSopenharmony_ci !gmatchx(name, sp, true)) 1859c84f3f3cSopenharmony_ci continue; 1860c84f3f3cSopenharmony_ci 1861c84f3f3cSopenharmony_ci len = strlen(d->d_name) + 1; 1862c84f3f3cSopenharmony_ci XcheckN(*xs, xp, len); 1863c84f3f3cSopenharmony_ci memcpy(xp, name, len); 1864c84f3f3cSopenharmony_ci *xpp = xp + len - 1; 1865c84f3f3cSopenharmony_ci globit(xs, xpp, np, wp, (check & GF_MARKDIR) | 1866c84f3f3cSopenharmony_ci GF_GLOBBED | (np ? GF_EXCHECK : GF_NONE)); 1867c84f3f3cSopenharmony_ci xp = Xstring(*xs, xp) + prefix_len; 1868c84f3f3cSopenharmony_ci } 1869c84f3f3cSopenharmony_ci closedir(dirp); 1870c84f3f3cSopenharmony_ci Nodir: 1871c84f3f3cSopenharmony_ci ; 1872c84f3f3cSopenharmony_ci } 1873c84f3f3cSopenharmony_ci 1874c84f3f3cSopenharmony_ci if (np != NULL) 1875c84f3f3cSopenharmony_ci *--np = odirsep; 1876c84f3f3cSopenharmony_ci} 1877c84f3f3cSopenharmony_ci 1878c84f3f3cSopenharmony_ci/* remove MAGIC from string */ 1879c84f3f3cSopenharmony_cichar * 1880c84f3f3cSopenharmony_cidebunk(char *dp, const char *sp, size_t dlen) 1881c84f3f3cSopenharmony_ci{ 1882c84f3f3cSopenharmony_ci char *d; 1883c84f3f3cSopenharmony_ci const char *s; 1884c84f3f3cSopenharmony_ci 1885c84f3f3cSopenharmony_ci if ((s = cstrchr(sp, MAGIC))) { 1886c84f3f3cSopenharmony_ci if (s - sp >= (ssize_t)dlen) 1887c84f3f3cSopenharmony_ci return (dp); 1888c84f3f3cSopenharmony_ci memmove(dp, sp, s - sp); 1889c84f3f3cSopenharmony_ci for (d = dp + (s - sp); *s && (d - dp < (ssize_t)dlen); s++) 1890c84f3f3cSopenharmony_ci if (!ISMAGIC(*s) || !(*++s & 0x80) || 1891c84f3f3cSopenharmony_ci !ctype(*s & 0x7F, C_PATMO | C_SPC)) 1892c84f3f3cSopenharmony_ci *d++ = *s; 1893c84f3f3cSopenharmony_ci else { 1894c84f3f3cSopenharmony_ci /* extended pattern operators: *+?@! */ 1895c84f3f3cSopenharmony_ci if ((*s & 0x7f) != ' ') 1896c84f3f3cSopenharmony_ci *d++ = *s & 0x7f; 1897c84f3f3cSopenharmony_ci if (d - dp < (ssize_t)dlen) 1898c84f3f3cSopenharmony_ci *d++ = '('; 1899c84f3f3cSopenharmony_ci } 1900c84f3f3cSopenharmony_ci *d = '\0'; 1901c84f3f3cSopenharmony_ci } else if (dp != sp) 1902c84f3f3cSopenharmony_ci strlcpy(dp, sp, dlen); 1903c84f3f3cSopenharmony_ci return (dp); 1904c84f3f3cSopenharmony_ci} 1905c84f3f3cSopenharmony_ci 1906c84f3f3cSopenharmony_ci/* 1907c84f3f3cSopenharmony_ci * Check if p is an unquoted name, possibly followed by a / or :. If so 1908c84f3f3cSopenharmony_ci * puts the expanded version in *dcp,dp and returns a pointer in p just 1909c84f3f3cSopenharmony_ci * past the name, otherwise returns 0. 1910c84f3f3cSopenharmony_ci */ 1911c84f3f3cSopenharmony_cistatic const char * 1912c84f3f3cSopenharmony_cimaybe_expand_tilde(const char *p, XString *dsp, char **dpp, bool isassign) 1913c84f3f3cSopenharmony_ci{ 1914c84f3f3cSopenharmony_ci XString ts; 1915c84f3f3cSopenharmony_ci char *dp = *dpp; 1916c84f3f3cSopenharmony_ci char *tp; 1917c84f3f3cSopenharmony_ci const char *r; 1918c84f3f3cSopenharmony_ci 1919c84f3f3cSopenharmony_ci Xinit(ts, tp, 16, ATEMP); 1920c84f3f3cSopenharmony_ci /* : only for DOASNTILDE form */ 1921c84f3f3cSopenharmony_ci while (p[0] == CHAR && /* not cdirsep */ p[1] != '/' && 1922c84f3f3cSopenharmony_ci (!isassign || p[1] != ':')) { 1923c84f3f3cSopenharmony_ci Xcheck(ts, tp); 1924c84f3f3cSopenharmony_ci *tp++ = p[1]; 1925c84f3f3cSopenharmony_ci p += 2; 1926c84f3f3cSopenharmony_ci } 1927c84f3f3cSopenharmony_ci *tp = '\0'; 1928c84f3f3cSopenharmony_ci r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ? 1929c84f3f3cSopenharmony_ci do_tilde(Xstring(ts, tp)) : NULL; 1930c84f3f3cSopenharmony_ci Xfree(ts, tp); 1931c84f3f3cSopenharmony_ci if (r) { 1932c84f3f3cSopenharmony_ci while (*r) { 1933c84f3f3cSopenharmony_ci Xcheck(*dsp, dp); 1934c84f3f3cSopenharmony_ci if (ISMAGIC(*r)) 1935c84f3f3cSopenharmony_ci *dp++ = MAGIC; 1936c84f3f3cSopenharmony_ci *dp++ = *r++; 1937c84f3f3cSopenharmony_ci } 1938c84f3f3cSopenharmony_ci *dpp = dp; 1939c84f3f3cSopenharmony_ci r = p; 1940c84f3f3cSopenharmony_ci } 1941c84f3f3cSopenharmony_ci return (r); 1942c84f3f3cSopenharmony_ci} 1943c84f3f3cSopenharmony_ci 1944c84f3f3cSopenharmony_ci/* 1945c84f3f3cSopenharmony_ci * tilde expansion 1946c84f3f3cSopenharmony_ci * 1947c84f3f3cSopenharmony_ci * based on a version by Arnold Robbins 1948c84f3f3cSopenharmony_ci */ 1949c84f3f3cSopenharmony_cichar * 1950c84f3f3cSopenharmony_cido_tilde(char *cp) 1951c84f3f3cSopenharmony_ci{ 1952c84f3f3cSopenharmony_ci char *dp = null; 1953c84f3f3cSopenharmony_ci#ifndef MKSH_NOPWNAM 1954c84f3f3cSopenharmony_ci bool do_simplify = true; 1955c84f3f3cSopenharmony_ci#endif 1956c84f3f3cSopenharmony_ci 1957c84f3f3cSopenharmony_ci if (cp[0] == '\0') 1958c84f3f3cSopenharmony_ci dp = str_val(global("HOME")); 1959c84f3f3cSopenharmony_ci else if (cp[0] == '+' && cp[1] == '\0') 1960c84f3f3cSopenharmony_ci dp = str_val(global(TPWD)); 1961c84f3f3cSopenharmony_ci else if (ksh_isdash(cp)) 1962c84f3f3cSopenharmony_ci dp = str_val(global(TOLDPWD)); 1963c84f3f3cSopenharmony_ci#ifndef MKSH_NOPWNAM 1964c84f3f3cSopenharmony_ci else { 1965c84f3f3cSopenharmony_ci dp = homedir(cp); 1966c84f3f3cSopenharmony_ci do_simplify = false; 1967c84f3f3cSopenharmony_ci } 1968c84f3f3cSopenharmony_ci#endif 1969c84f3f3cSopenharmony_ci 1970c84f3f3cSopenharmony_ci /* if parameters aren't set, don't expand ~ */ 1971c84f3f3cSopenharmony_ci if (dp == NULL || dp == null) 1972c84f3f3cSopenharmony_ci return (NULL); 1973c84f3f3cSopenharmony_ci 1974c84f3f3cSopenharmony_ci /* simplify parameters as if cwd upon entry */ 1975c84f3f3cSopenharmony_ci#ifndef MKSH_NOPWNAM 1976c84f3f3cSopenharmony_ci if (do_simplify) 1977c84f3f3cSopenharmony_ci#endif 1978c84f3f3cSopenharmony_ci { 1979c84f3f3cSopenharmony_ci strdupx(dp, dp, ATEMP); 1980c84f3f3cSopenharmony_ci simplify_path(dp); 1981c84f3f3cSopenharmony_ci } 1982c84f3f3cSopenharmony_ci return (dp); 1983c84f3f3cSopenharmony_ci} 1984c84f3f3cSopenharmony_ci 1985c84f3f3cSopenharmony_ci#ifndef MKSH_NOPWNAM 1986c84f3f3cSopenharmony_ci/* 1987c84f3f3cSopenharmony_ci * map userid to user's home directory. 1988c84f3f3cSopenharmony_ci * note that 4.3's getpw adds more than 6K to the shell, 1989c84f3f3cSopenharmony_ci * and the YP version probably adds much more. 1990c84f3f3cSopenharmony_ci * we might consider our own version of getpwnam() to keep the size down. 1991c84f3f3cSopenharmony_ci */ 1992c84f3f3cSopenharmony_cistatic char * 1993c84f3f3cSopenharmony_cihomedir(char *name) 1994c84f3f3cSopenharmony_ci{ 1995c84f3f3cSopenharmony_ci struct tbl *ap; 1996c84f3f3cSopenharmony_ci 1997c84f3f3cSopenharmony_ci ap = ktenter(&homedirs, name, hash(name)); 1998c84f3f3cSopenharmony_ci if (!(ap->flag & ISSET)) { 1999c84f3f3cSopenharmony_ci struct passwd *pw; 2000c84f3f3cSopenharmony_ci 2001c84f3f3cSopenharmony_ci pw = getpwnam(name); 2002c84f3f3cSopenharmony_ci if (pw == NULL) 2003c84f3f3cSopenharmony_ci return (NULL); 2004c84f3f3cSopenharmony_ci strdupx(ap->val.s, pw->pw_dir, APERM); 2005c84f3f3cSopenharmony_ci ap->flag |= DEFINED|ISSET|ALLOC; 2006c84f3f3cSopenharmony_ci } 2007c84f3f3cSopenharmony_ci return (ap->val.s); 2008c84f3f3cSopenharmony_ci} 2009c84f3f3cSopenharmony_ci#endif 2010c84f3f3cSopenharmony_ci 2011c84f3f3cSopenharmony_cistatic void 2012c84f3f3cSopenharmony_cialt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo) 2013c84f3f3cSopenharmony_ci{ 2014c84f3f3cSopenharmony_ci unsigned int count = 0; 2015c84f3f3cSopenharmony_ci char *brace_start, *brace_end, *comma = NULL; 2016c84f3f3cSopenharmony_ci char *field_start; 2017c84f3f3cSopenharmony_ci char *p = exp_start; 2018c84f3f3cSopenharmony_ci 2019c84f3f3cSopenharmony_ci /* search for open brace */ 2020c84f3f3cSopenharmony_ci while ((p = strchr(p, MAGIC)) && ord(p[1]) != ORD('{' /*}*/)) 2021c84f3f3cSopenharmony_ci p += 2; 2022c84f3f3cSopenharmony_ci brace_start = p; 2023c84f3f3cSopenharmony_ci 2024c84f3f3cSopenharmony_ci /* find matching close brace, if any */ 2025c84f3f3cSopenharmony_ci if (p) { 2026c84f3f3cSopenharmony_ci comma = NULL; 2027c84f3f3cSopenharmony_ci count = 1; 2028c84f3f3cSopenharmony_ci p += 2; 2029c84f3f3cSopenharmony_ci while (*p && count) { 2030c84f3f3cSopenharmony_ci if (ISMAGIC(*p++)) { 2031c84f3f3cSopenharmony_ci if (ord(*p) == ORD('{' /*}*/)) 2032c84f3f3cSopenharmony_ci ++count; 2033c84f3f3cSopenharmony_ci else if (ord(*p) == ORD(/*{*/ '}')) 2034c84f3f3cSopenharmony_ci --count; 2035c84f3f3cSopenharmony_ci else if (*p == ',' && count == 1) 2036c84f3f3cSopenharmony_ci comma = p; 2037c84f3f3cSopenharmony_ci ++p; 2038c84f3f3cSopenharmony_ci } 2039c84f3f3cSopenharmony_ci } 2040c84f3f3cSopenharmony_ci } 2041c84f3f3cSopenharmony_ci /* no valid expansions... */ 2042c84f3f3cSopenharmony_ci if (!p || count != 0) { 2043c84f3f3cSopenharmony_ci /* 2044c84f3f3cSopenharmony_ci * Note that given a{{b,c} we do not expand anything (this is 2045c84f3f3cSopenharmony_ci * what AT&T ksh does. This may be changed to do the {b,c} 2046c84f3f3cSopenharmony_ci * expansion. } 2047c84f3f3cSopenharmony_ci */ 2048c84f3f3cSopenharmony_ci if (fdo & DOGLOB) 2049c84f3f3cSopenharmony_ci glob(start, wp, tobool(fdo & DOMARKDIRS)); 2050c84f3f3cSopenharmony_ci else 2051c84f3f3cSopenharmony_ci XPput(*wp, debunk(start, start, end - start)); 2052c84f3f3cSopenharmony_ci return; 2053c84f3f3cSopenharmony_ci } 2054c84f3f3cSopenharmony_ci brace_end = p; 2055c84f3f3cSopenharmony_ci if (!comma) { 2056c84f3f3cSopenharmony_ci alt_expand(wp, start, brace_end, end, fdo); 2057c84f3f3cSopenharmony_ci return; 2058c84f3f3cSopenharmony_ci } 2059c84f3f3cSopenharmony_ci 2060c84f3f3cSopenharmony_ci /* expand expression */ 2061c84f3f3cSopenharmony_ci field_start = brace_start + 2; 2062c84f3f3cSopenharmony_ci count = 1; 2063c84f3f3cSopenharmony_ci for (p = brace_start + 2; p != brace_end; p++) { 2064c84f3f3cSopenharmony_ci if (ISMAGIC(*p)) { 2065c84f3f3cSopenharmony_ci if (ord(*++p) == ORD('{' /*}*/)) 2066c84f3f3cSopenharmony_ci ++count; 2067c84f3f3cSopenharmony_ci else if ((ord(*p) == ORD(/*{*/ '}') && --count == 0) || 2068c84f3f3cSopenharmony_ci (*p == ',' && count == 1)) { 2069c84f3f3cSopenharmony_ci char *news; 2070c84f3f3cSopenharmony_ci int l1, l2, l3; 2071c84f3f3cSopenharmony_ci 2072c84f3f3cSopenharmony_ci /* 2073c84f3f3cSopenharmony_ci * addition safe since these operate on 2074c84f3f3cSopenharmony_ci * one string (separate substrings) 2075c84f3f3cSopenharmony_ci */ 2076c84f3f3cSopenharmony_ci l1 = brace_start - start; 2077c84f3f3cSopenharmony_ci l2 = (p - 1) - field_start; 2078c84f3f3cSopenharmony_ci l3 = end - brace_end; 2079c84f3f3cSopenharmony_ci news = alloc(l1 + l2 + l3 + 1, ATEMP); 2080c84f3f3cSopenharmony_ci memcpy(news, start, l1); 2081c84f3f3cSopenharmony_ci memcpy(news + l1, field_start, l2); 2082c84f3f3cSopenharmony_ci memcpy(news + l1 + l2, brace_end, l3); 2083c84f3f3cSopenharmony_ci news[l1 + l2 + l3] = '\0'; 2084c84f3f3cSopenharmony_ci alt_expand(wp, news, news + l1, 2085c84f3f3cSopenharmony_ci news + l1 + l2 + l3, fdo); 2086c84f3f3cSopenharmony_ci field_start = p + 1; 2087c84f3f3cSopenharmony_ci } 2088c84f3f3cSopenharmony_ci } 2089c84f3f3cSopenharmony_ci } 2090c84f3f3cSopenharmony_ci return; 2091c84f3f3cSopenharmony_ci} 2092c84f3f3cSopenharmony_ci 2093c84f3f3cSopenharmony_ci/* helper function due to setjmp/longjmp woes */ 2094c84f3f3cSopenharmony_cistatic char * 2095c84f3f3cSopenharmony_civalsub(struct op *t, Area *ap) 2096c84f3f3cSopenharmony_ci{ 2097c84f3f3cSopenharmony_ci char * volatile cp = NULL; 2098c84f3f3cSopenharmony_ci struct tbl * volatile vp = NULL; 2099c84f3f3cSopenharmony_ci 2100c84f3f3cSopenharmony_ci newenv(E_FUNC); 2101c84f3f3cSopenharmony_ci newblock(); 2102c84f3f3cSopenharmony_ci if (ap) 2103c84f3f3cSopenharmony_ci vp = local(TREPLY, false); 2104c84f3f3cSopenharmony_ci if (!kshsetjmp(e->jbuf)) 2105c84f3f3cSopenharmony_ci execute(t, XXCOM | XERROK, NULL); 2106c84f3f3cSopenharmony_ci if (vp) 2107c84f3f3cSopenharmony_ci strdupx(cp, str_val(vp), ap); 2108c84f3f3cSopenharmony_ci quitenv(NULL); 2109c84f3f3cSopenharmony_ci 2110c84f3f3cSopenharmony_ci return (cp); 2111c84f3f3cSopenharmony_ci} 2112