1 1.24 mlelstv /* $NetBSD: lex.c,v 1.24 2019/09/26 11:01:09 mlelstv Exp $ */ 2 1.2 tls 3 1.1 jtc /* 4 1.1 jtc * lexical analysis and source input 5 1.1 jtc */ 6 1.9 agc #include <sys/cdefs.h> 7 1.9 agc 8 1.9 agc #ifndef lint 9 1.24 mlelstv __RCSID("$NetBSD: lex.c,v 1.24 2019/09/26 11:01:09 mlelstv Exp $"); 10 1.9 agc #endif 11 1.9 agc 12 1.1 jtc 13 1.1 jtc #include "sh.h" 14 1.1 jtc #include <ctype.h> 15 1.1 jtc 16 1.6 hubertf 17 1.6 hubertf /* Structure to keep track of the lexing state and the various pieces of info 18 1.6 hubertf * needed for each particular state. 19 1.6 hubertf */ 20 1.6 hubertf typedef struct lex_state Lex_state; 21 1.6 hubertf struct lex_state { 22 1.6 hubertf int ls_state; 23 1.6 hubertf union { 24 1.6 hubertf /* $(...) */ 25 1.6 hubertf struct scsparen_info { 26 1.6 hubertf int nparen; /* count open parenthesis */ 27 1.6 hubertf int csstate; /* XXX remove */ 28 1.6 hubertf #define ls_scsparen ls_info.u_scsparen 29 1.6 hubertf } u_scsparen; 30 1.6 hubertf 31 1.6 hubertf /* $((...)) */ 32 1.6 hubertf struct sasparen_info { 33 1.6 hubertf int nparen; /* count open parenthesis */ 34 1.6 hubertf int start; /* marks start of $(( in output str */ 35 1.6 hubertf #define ls_sasparen ls_info.u_sasparen 36 1.6 hubertf } u_sasparen; 37 1.6 hubertf 38 1.6 hubertf /* ((...)) */ 39 1.6 hubertf struct sletparen_info { 40 1.6 hubertf int nparen; /* count open parenthesis */ 41 1.6 hubertf #define ls_sletparen ls_info.u_sletparen 42 1.6 hubertf } u_sletparen; 43 1.6 hubertf 44 1.6 hubertf /* `...` */ 45 1.6 hubertf struct sbquote_info { 46 1.6 hubertf int indquotes; /* true if in double quotes: "`...`" */ 47 1.6 hubertf #define ls_sbquote ls_info.u_sbquote 48 1.6 hubertf } u_sbquote; 49 1.6 hubertf 50 1.6 hubertf Lex_state *base; /* used to point to next state block */ 51 1.6 hubertf } ls_info; 52 1.6 hubertf }; 53 1.6 hubertf 54 1.6 hubertf typedef struct State_info State_info; 55 1.6 hubertf struct State_info { 56 1.6 hubertf Lex_state *base; 57 1.6 hubertf Lex_state *end; 58 1.6 hubertf }; 59 1.6 hubertf 60 1.6 hubertf 61 1.1 jtc static void readhere ARGS((struct ioword *iop)); 62 1.2 tls static int getsc__ ARGS((void)); 63 1.1 jtc static void getsc_line ARGS((Source *s)); 64 1.6 hubertf static int getsc_bn ARGS((void)); 65 1.1 jtc static char *get_brace_var ARGS((XString *wsp, char *wp)); 66 1.1 jtc static int arraysub ARGS((char **strp)); 67 1.2 tls static const char *ungetsc ARGS((int c)); 68 1.2 tls static void gethere ARGS((void)); 69 1.6 hubertf static Lex_state *push_state_ ARGS((State_info *si, Lex_state *old_end)); 70 1.6 hubertf static Lex_state *pop_state_ ARGS((State_info *si, Lex_state *old_end)); 71 1.2 tls 72 1.2 tls static int backslash_skip; 73 1.2 tls static int ignore_backslash_newline; 74 1.2 tls 75 1.2 tls /* optimized getsc_bn() */ 76 1.2 tls #define getsc() (*source->str != '\0' && *source->str != '\\' \ 77 1.2 tls && !backslash_skip ? *source->str++ : getsc_bn()) 78 1.2 tls /* optimized getsc__() */ 79 1.2 tls #define getsc_() ((*source->str != '\0') ? *source->str++ : getsc__()) 80 1.1 jtc 81 1.6 hubertf #define STATE_BSIZE 32 82 1.6 hubertf 83 1.6 hubertf #define PUSH_STATE(s) do { \ 84 1.6 hubertf if (++statep == state_info.end) \ 85 1.6 hubertf statep = push_state_(&state_info, statep); \ 86 1.6 hubertf state = statep->ls_state = (s); \ 87 1.6 hubertf } while (0) 88 1.6 hubertf 89 1.6 hubertf #define POP_STATE() do { \ 90 1.6 hubertf if (--statep == state_info.base) \ 91 1.6 hubertf statep = pop_state_(&state_info, statep); \ 92 1.6 hubertf state = statep->ls_state; \ 93 1.6 hubertf } while (0) 94 1.6 hubertf 95 1.6 hubertf 96 1.1 jtc 97 1.1 jtc /* 98 1.1 jtc * Lexical analyzer 99 1.1 jtc * 100 1.1 jtc * tokens are not regular expressions, they are LL(1). 101 1.1 jtc * for example, "${var:-${PWD}}", and "$(size $(whence ksh))". 102 1.1 jtc * hence the state stack. 103 1.1 jtc */ 104 1.1 jtc 105 1.1 jtc int 106 1.1 jtc yylex(cf) 107 1.1 jtc int cf; 108 1.1 jtc { 109 1.6 hubertf Lex_state states[STATE_BSIZE], *statep; 110 1.6 hubertf State_info state_info; 111 1.23 kamil int c, state; 112 1.1 jtc XString ws; /* expandable output word */ 113 1.23 kamil char *wp; /* output word pointer */ 114 1.6 hubertf char *sp, *dp; 115 1.6 hubertf int c2; 116 1.1 jtc 117 1.1 jtc 118 1.1 jtc Again: 119 1.6 hubertf states[0].ls_state = -1; 120 1.6 hubertf states[0].ls_info.base = (Lex_state *) 0; 121 1.6 hubertf statep = &states[1]; 122 1.6 hubertf state_info.base = states; 123 1.6 hubertf state_info.end = &states[STATE_BSIZE]; 124 1.6 hubertf 125 1.1 jtc Xinit(ws, wp, 64, ATEMP); 126 1.1 jtc 127 1.2 tls backslash_skip = 0; 128 1.2 tls ignore_backslash_newline = 0; 129 1.2 tls 130 1.1 jtc if (cf&ONEWORD) 131 1.6 hubertf state = SWORD; 132 1.2 tls #ifdef KSH 133 1.1 jtc else if (cf&LETEXPR) { 134 1.1 jtc *wp++ = OQUOTE; /* enclose arguments in (double) quotes */ 135 1.6 hubertf state = SLETPAREN; 136 1.6 hubertf statep->ls_sletparen.nparen = 0; 137 1.2 tls } 138 1.2 tls #endif /* KSH */ 139 1.2 tls else { /* normal lexing */ 140 1.6 hubertf state = (cf & HEREDELIM) ? SHEREDELIM : SBASE; 141 1.1 jtc while ((c = getsc()) == ' ' || c == '\t') 142 1.1 jtc ; 143 1.2 tls if (c == '#') { 144 1.2 tls ignore_backslash_newline++; 145 1.1 jtc while ((c = getsc()) != '\0' && c != '\n') 146 1.1 jtc ; 147 1.2 tls ignore_backslash_newline--; 148 1.2 tls } 149 1.1 jtc ungetsc(c); 150 1.1 jtc } 151 1.1 jtc if (source->flags & SF_ALIAS) { /* trailing ' ' in alias definition */ 152 1.1 jtc source->flags &= ~SF_ALIAS; 153 1.1 jtc /* In POSIX mode, a trailing space only counts if we are 154 1.1 jtc * parsing a simple command 155 1.1 jtc */ 156 1.1 jtc if (!Flag(FPOSIX) || (cf & CMDWORD)) 157 1.1 jtc cf |= ALIAS; 158 1.1 jtc } 159 1.1 jtc 160 1.6 hubertf /* Initial state: one of SBASE SHEREDELIM SWORD SASPAREN */ 161 1.6 hubertf statep->ls_state = state; 162 1.6 hubertf 163 1.1 jtc /* collect non-special or quoted characters to form word */ 164 1.6 hubertf while (!((c = getsc()) == 0 165 1.6 hubertf || ((state == SBASE || state == SHEREDELIM) 166 1.6 hubertf && ctype(c, C_LEX1)))) 167 1.1 jtc { 168 1.1 jtc Xcheck(ws, wp); 169 1.1 jtc switch (state) { 170 1.1 jtc case SBASE: 171 1.1 jtc if (c == '[' && (cf & (VARASN|ARRAYVAR))) { 172 1.1 jtc *wp = EOS; /* temporary */ 173 1.21 kamil if (is_wdvarname(Xstring(ws, wp), false)) 174 1.1 jtc { 175 1.1 jtc char *p, *tmp; 176 1.1 jtc 177 1.1 jtc if (arraysub(&tmp)) { 178 1.1 jtc *wp++ = CHAR; 179 1.1 jtc *wp++ = c; 180 1.1 jtc for (p = tmp; *p; ) { 181 1.1 jtc Xcheck(ws, wp); 182 1.1 jtc *wp++ = CHAR; 183 1.1 jtc *wp++ = *p++; 184 1.1 jtc } 185 1.1 jtc afree(tmp, ATEMP); 186 1.1 jtc break; 187 1.1 jtc } else { 188 1.1 jtc Source *s; 189 1.1 jtc 190 1.1 jtc s = pushs(SREREAD, 191 1.1 jtc source->areap); 192 1.1 jtc s->start = s->str 193 1.1 jtc = s->u.freeme = tmp; 194 1.1 jtc s->next = source; 195 1.1 jtc source = s; 196 1.1 jtc } 197 1.1 jtc } 198 1.1 jtc *wp++ = CHAR; 199 1.1 jtc *wp++ = c; 200 1.1 jtc break; 201 1.1 jtc } 202 1.1 jtc /* fall through.. */ 203 1.1 jtc Sbase1: /* includes *(...|...) pattern (*+?@!) */ 204 1.1 jtc #ifdef KSH 205 1.1 jtc if (c == '*' || c == '@' || c == '+' || c == '?' 206 1.1 jtc || c == '!') 207 1.1 jtc { 208 1.1 jtc c2 = getsc(); 209 1.1 jtc if (c2 == '(' /*)*/ ) { 210 1.1 jtc *wp++ = OPAT; 211 1.1 jtc *wp++ = c; 212 1.6 hubertf PUSH_STATE(SPATTERN); 213 1.1 jtc break; 214 1.1 jtc } 215 1.1 jtc ungetsc(c2); 216 1.1 jtc } 217 1.1 jtc #endif /* KSH */ 218 1.1 jtc /* fall through.. */ 219 1.1 jtc Sbase2: /* doesn't include *(...|...) pattern (*+?@!) */ 220 1.1 jtc switch (c) { 221 1.1 jtc case '\\': 222 1.1 jtc c = getsc(); 223 1.2 tls if (c) /* trailing \ is lost */ 224 1.2 tls *wp++ = QCHAR, *wp++ = c; 225 1.1 jtc break; 226 1.1 jtc case '\'': 227 1.1 jtc *wp++ = OQUOTE; 228 1.2 tls ignore_backslash_newline++; 229 1.6 hubertf PUSH_STATE(SSQUOTE); 230 1.1 jtc break; 231 1.1 jtc case '"': 232 1.1 jtc *wp++ = OQUOTE; 233 1.6 hubertf PUSH_STATE(SDQUOTE); 234 1.1 jtc break; 235 1.1 jtc default: 236 1.1 jtc goto Subst; 237 1.1 jtc } 238 1.1 jtc break; 239 1.1 jtc 240 1.1 jtc Subst: 241 1.1 jtc switch (c) { 242 1.14 hauke Lex_state *s; 243 1.14 hauke Lex_state *base; 244 1.14 hauke 245 1.1 jtc case '\\': 246 1.1 jtc c = getsc(); 247 1.1 jtc switch (c) { 248 1.12 christos case '\\': 249 1.1 jtc case '$': case '`': 250 1.1 jtc *wp++ = QCHAR, *wp++ = c; 251 1.1 jtc break; 252 1.12 christos case '"': 253 1.12 christos if ((cf & HEREDOC) == 0) { 254 1.12 christos *wp++ = QCHAR, *wp++ = c; 255 1.12 christos break; 256 1.12 christos } 257 1.24 mlelstv /* FALLTHROUGH */ 258 1.1 jtc default: 259 1.1 jtc Xcheck(ws, wp); 260 1.2 tls if (c) { /* trailing \ is lost */ 261 1.2 tls *wp++ = CHAR, *wp++ = '\\'; 262 1.2 tls *wp++ = CHAR, *wp++ = c; 263 1.2 tls } 264 1.1 jtc break; 265 1.1 jtc } 266 1.1 jtc break; 267 1.1 jtc case '$': 268 1.1 jtc c = getsc(); 269 1.1 jtc if (c == '(') /*)*/ { 270 1.1 jtc c = getsc(); 271 1.1 jtc if (c == '(') /*)*/ { 272 1.6 hubertf PUSH_STATE(SASPAREN); 273 1.6 hubertf statep->ls_sasparen.nparen = 2; 274 1.6 hubertf statep->ls_sasparen.start = 275 1.6 hubertf Xsavepos(ws, wp); 276 1.1 jtc *wp++ = EXPRSUB; 277 1.1 jtc } else { 278 1.1 jtc ungetsc(c); 279 1.6 hubertf PUSH_STATE(SCSPAREN); 280 1.6 hubertf statep->ls_scsparen.nparen = 1; 281 1.6 hubertf statep->ls_scsparen.csstate = 0; 282 1.1 jtc *wp++ = COMSUB; 283 1.1 jtc } 284 1.1 jtc } else if (c == '{') /*}*/ { 285 1.1 jtc *wp++ = OSUBST; 286 1.6 hubertf *wp++ = '{'; /*}*/ 287 1.1 jtc wp = get_brace_var(&ws, wp); 288 1.6 hubertf c = getsc(); 289 1.6 hubertf /* allow :# and :% (ksh88 compat) */ 290 1.6 hubertf if (c == ':') { 291 1.6 hubertf *wp++ = CHAR, *wp++ = c; 292 1.6 hubertf c = getsc(); 293 1.6 hubertf } 294 1.1 jtc /* If this is a trim operation, 295 1.6 hubertf * treat (,|,) specially in STBRACE. 296 1.1 jtc */ 297 1.1 jtc if (c == '#' || c == '%') { 298 1.6 hubertf ungetsc(c); 299 1.6 hubertf PUSH_STATE(STBRACE); 300 1.1 jtc } else { 301 1.1 jtc ungetsc(c); 302 1.6 hubertf PUSH_STATE(SBRACE); 303 1.1 jtc } 304 1.1 jtc } else if (ctype(c, C_ALPHA)) { 305 1.1 jtc *wp++ = OSUBST; 306 1.6 hubertf *wp++ = 'X'; 307 1.1 jtc do { 308 1.1 jtc Xcheck(ws, wp); 309 1.1 jtc *wp++ = c; 310 1.1 jtc c = getsc(); 311 1.1 jtc } while (ctype(c, C_ALPHA|C_DIGIT)); 312 1.1 jtc *wp++ = '\0'; 313 1.1 jtc *wp++ = CSUBST; 314 1.6 hubertf *wp++ = 'X'; 315 1.1 jtc ungetsc(c); 316 1.1 jtc } else if (ctype(c, C_DIGIT|C_VAR1)) { 317 1.1 jtc Xcheck(ws, wp); 318 1.1 jtc *wp++ = OSUBST; 319 1.6 hubertf *wp++ = 'X'; 320 1.1 jtc *wp++ = c; 321 1.1 jtc *wp++ = '\0'; 322 1.1 jtc *wp++ = CSUBST; 323 1.6 hubertf *wp++ = 'X'; 324 1.1 jtc } else { 325 1.1 jtc *wp++ = CHAR, *wp++ = '$'; 326 1.1 jtc ungetsc(c); 327 1.1 jtc } 328 1.1 jtc break; 329 1.1 jtc case '`': 330 1.6 hubertf PUSH_STATE(SBQUOTE); 331 1.1 jtc *wp++ = COMSUB; 332 1.1 jtc /* Need to know if we are inside double quotes 333 1.1 jtc * since sh/at&t-ksh translate the \" to " in 334 1.13 apb * "`..\"..`". POSIX also requires this. 335 1.13 apb * An earlier version of ksh misinterpreted 336 1.13 apb * the POSIX specification and performed 337 1.13 apb * removal of backslash escapes only if 338 1.13 apb * posix mode was not in effect. 339 1.1 jtc */ 340 1.6 hubertf statep->ls_sbquote.indquotes = 0; 341 1.14 hauke s = statep; 342 1.14 hauke base = state_info.base; 343 1.13 apb while (1) { 344 1.13 apb for (; s != base; s--) { 345 1.13 apb if (s->ls_state == SDQUOTE) { 346 1.13 apb statep->ls_sbquote.indquotes = 1; 347 1.13 apb break; 348 1.6 hubertf } 349 1.6 hubertf } 350 1.13 apb if (s != base) 351 1.13 apb break; 352 1.13 apb if (!(s = s->ls_info.base)) 353 1.13 apb break; 354 1.13 apb base = s-- - STATE_BSIZE; 355 1.6 hubertf } 356 1.1 jtc break; 357 1.1 jtc default: 358 1.1 jtc *wp++ = CHAR, *wp++ = c; 359 1.1 jtc } 360 1.1 jtc break; 361 1.1 jtc 362 1.1 jtc case SSQUOTE: 363 1.1 jtc if (c == '\'') { 364 1.6 hubertf POP_STATE(); 365 1.1 jtc *wp++ = CQUOTE; 366 1.2 tls ignore_backslash_newline--; 367 1.1 jtc } else 368 1.1 jtc *wp++ = QCHAR, *wp++ = c; 369 1.1 jtc break; 370 1.1 jtc 371 1.1 jtc case SDQUOTE: 372 1.1 jtc if (c == '"') { 373 1.6 hubertf POP_STATE(); 374 1.1 jtc *wp++ = CQUOTE; 375 1.1 jtc } else 376 1.1 jtc goto Subst; 377 1.1 jtc break; 378 1.1 jtc 379 1.6 hubertf case SCSPAREN: /* $( .. ) */ 380 1.1 jtc /* todo: deal with $(...) quoting properly 381 1.1 jtc * kludge to partly fake quoting inside $(..): doesn't 382 1.1 jtc * really work because nested $(..) or ${..} inside 383 1.1 jtc * double quotes aren't dealt with. 384 1.1 jtc */ 385 1.6 hubertf switch (statep->ls_scsparen.csstate) { 386 1.1 jtc case 0: /* normal */ 387 1.1 jtc switch (c) { 388 1.1 jtc case '(': 389 1.6 hubertf statep->ls_scsparen.nparen++; 390 1.1 jtc break; 391 1.1 jtc case ')': 392 1.6 hubertf statep->ls_scsparen.nparen--; 393 1.1 jtc break; 394 1.1 jtc case '\\': 395 1.6 hubertf statep->ls_scsparen.csstate = 1; 396 1.1 jtc break; 397 1.1 jtc case '"': 398 1.6 hubertf statep->ls_scsparen.csstate = 2; 399 1.1 jtc break; 400 1.1 jtc case '\'': 401 1.6 hubertf statep->ls_scsparen.csstate = 4; 402 1.2 tls ignore_backslash_newline++; 403 1.1 jtc break; 404 1.1 jtc } 405 1.1 jtc break; 406 1.1 jtc 407 1.1 jtc case 1: /* backslash in normal mode */ 408 1.1 jtc case 3: /* backslash in double quotes */ 409 1.6 hubertf --statep->ls_scsparen.csstate; 410 1.1 jtc break; 411 1.1 jtc 412 1.1 jtc case 2: /* double quotes */ 413 1.1 jtc if (c == '"') 414 1.6 hubertf statep->ls_scsparen.csstate = 0; 415 1.1 jtc else if (c == '\\') 416 1.6 hubertf statep->ls_scsparen.csstate = 3; 417 1.1 jtc break; 418 1.1 jtc 419 1.1 jtc case 4: /* single quotes */ 420 1.2 tls if (c == '\'') { 421 1.6 hubertf statep->ls_scsparen.csstate = 0; 422 1.2 tls ignore_backslash_newline--; 423 1.2 tls } 424 1.1 jtc break; 425 1.1 jtc } 426 1.6 hubertf if (statep->ls_scsparen.nparen == 0) { 427 1.6 hubertf POP_STATE(); 428 1.1 jtc *wp++ = 0; /* end of COMSUB */ 429 1.1 jtc } else 430 1.1 jtc *wp++ = c; 431 1.1 jtc break; 432 1.1 jtc 433 1.6 hubertf case SASPAREN: /* $(( .. )) */ 434 1.1 jtc /* todo: deal with $((...); (...)) properly */ 435 1.1 jtc /* XXX should nest using existing state machine 436 1.1 jtc * (embed "..", $(...), etc.) */ 437 1.1 jtc if (c == '(') 438 1.6 hubertf statep->ls_sasparen.nparen++; 439 1.1 jtc else if (c == ')') { 440 1.6 hubertf statep->ls_sasparen.nparen--; 441 1.6 hubertf if (statep->ls_sasparen.nparen == 1) { 442 1.1 jtc /*(*/ 443 1.1 jtc if ((c2 = getsc()) == ')') { 444 1.6 hubertf POP_STATE(); 445 1.1 jtc *wp++ = 0; /* end of EXPRSUB */ 446 1.1 jtc break; 447 1.1 jtc } else { 448 1.6 hubertf char *s; 449 1.6 hubertf 450 1.1 jtc ungetsc(c2); 451 1.1 jtc /* mismatched parenthesis - 452 1.1 jtc * assume we were really 453 1.1 jtc * parsing a $(..) expression 454 1.1 jtc */ 455 1.6 hubertf s = Xrestpos(ws, wp, 456 1.6 hubertf statep->ls_sasparen.start); 457 1.6 hubertf memmove(s + 1, s, wp - s); 458 1.6 hubertf *s++ = COMSUB; 459 1.6 hubertf *s = '('; /*)*/ 460 1.1 jtc wp++; 461 1.6 hubertf statep->ls_scsparen.nparen = 1; 462 1.6 hubertf statep->ls_scsparen.csstate = 0; 463 1.6 hubertf state = statep->ls_state 464 1.6 hubertf = SCSPAREN; 465 1.6 hubertf 466 1.1 jtc } 467 1.1 jtc } 468 1.1 jtc } 469 1.1 jtc *wp++ = c; 470 1.1 jtc break; 471 1.1 jtc 472 1.1 jtc case SBRACE: 473 1.1 jtc /*{*/ 474 1.1 jtc if (c == '}') { 475 1.6 hubertf POP_STATE(); 476 1.1 jtc *wp++ = CSUBST; 477 1.6 hubertf *wp++ = /*{*/ '}'; 478 1.1 jtc } else 479 1.1 jtc goto Sbase1; 480 1.1 jtc break; 481 1.1 jtc 482 1.1 jtc case STBRACE: 483 1.6 hubertf /* Same as SBRACE, except (,|,) treated specially */ 484 1.1 jtc /*{*/ 485 1.1 jtc if (c == '}') { 486 1.6 hubertf POP_STATE(); 487 1.1 jtc *wp++ = CSUBST; 488 1.6 hubertf *wp++ = /*{*/ '}'; 489 1.1 jtc } else if (c == '|') { 490 1.1 jtc *wp++ = SPAT; 491 1.6 hubertf } else if (c == '(') { 492 1.6 hubertf *wp++ = OPAT; 493 1.6 hubertf *wp++ = ' '; /* simile for @ */ 494 1.6 hubertf PUSH_STATE(SPATTERN); 495 1.1 jtc } else 496 1.1 jtc goto Sbase1; 497 1.1 jtc break; 498 1.1 jtc 499 1.1 jtc case SBQUOTE: 500 1.1 jtc if (c == '`') { 501 1.1 jtc *wp++ = 0; 502 1.6 hubertf POP_STATE(); 503 1.1 jtc } else if (c == '\\') { 504 1.1 jtc switch (c = getsc()) { 505 1.1 jtc case '\\': 506 1.1 jtc case '$': case '`': 507 1.1 jtc *wp++ = c; 508 1.1 jtc break; 509 1.1 jtc case '"': 510 1.6 hubertf if (statep->ls_sbquote.indquotes) { 511 1.1 jtc *wp++ = c; 512 1.1 jtc break; 513 1.1 jtc } 514 1.1 jtc /* fall through.. */ 515 1.1 jtc default: 516 1.2 tls if (c) { /* trailing \ is lost */ 517 1.2 tls *wp++ = '\\'; 518 1.2 tls *wp++ = c; 519 1.2 tls } 520 1.1 jtc break; 521 1.1 jtc } 522 1.1 jtc } else 523 1.1 jtc *wp++ = c; 524 1.1 jtc break; 525 1.1 jtc 526 1.1 jtc case SWORD: /* ONEWORD */ 527 1.1 jtc goto Subst; 528 1.1 jtc 529 1.2 tls #ifdef KSH 530 1.6 hubertf case SLETPAREN: /* LETEXPR: (( ... )) */ 531 1.1 jtc /*(*/ 532 1.1 jtc if (c == ')') { 533 1.6 hubertf if (statep->ls_sletparen.nparen > 0) 534 1.6 hubertf --statep->ls_sletparen.nparen; 535 1.1 jtc /*(*/ 536 1.1 jtc else if ((c2 = getsc()) == ')') { 537 1.1 jtc c = 0; 538 1.1 jtc *wp++ = CQUOTE; 539 1.1 jtc goto Done; 540 1.1 jtc } else 541 1.1 jtc ungetsc(c2); 542 1.1 jtc } else if (c == '(') 543 1.1 jtc /* parenthesis inside quotes and backslashes 544 1.1 jtc * are lost, but at&t ksh doesn't count them 545 1.1 jtc * either 546 1.1 jtc */ 547 1.6 hubertf ++statep->ls_sletparen.nparen; 548 1.1 jtc goto Sbase2; 549 1.2 tls #endif /* KSH */ 550 1.1 jtc 551 1.1 jtc case SHEREDELIM: /* <<,<<- delimiter */ 552 1.1 jtc /* XXX chuck this state (and the next) - use 553 1.1 jtc * the existing states ($ and \`..` should be 554 1.1 jtc * stripped of their specialness after the 555 1.1 jtc * fact). 556 1.1 jtc */ 557 1.1 jtc /* here delimiters need a special case since 558 1.1 jtc * $ and `..` are not to be treated specially 559 1.1 jtc */ 560 1.1 jtc if (c == '\\') { 561 1.1 jtc c = getsc(); 562 1.2 tls if (c) { /* trailing \ is lost */ 563 1.1 jtc *wp++ = QCHAR; 564 1.1 jtc *wp++ = c; 565 1.1 jtc } 566 1.1 jtc } else if (c == '\'') { 567 1.6 hubertf PUSH_STATE(SSQUOTE); 568 1.1 jtc *wp++ = OQUOTE; 569 1.2 tls ignore_backslash_newline++; 570 1.1 jtc } else if (c == '"') { 571 1.6 hubertf state = statep->ls_state = SHEREDQUOTE; 572 1.1 jtc *wp++ = OQUOTE; 573 1.1 jtc } else { 574 1.1 jtc *wp++ = CHAR; 575 1.1 jtc *wp++ = c; 576 1.1 jtc } 577 1.1 jtc break; 578 1.1 jtc 579 1.1 jtc case SHEREDQUOTE: /* " in <<,<<- delimiter */ 580 1.1 jtc if (c == '"') { 581 1.1 jtc *wp++ = CQUOTE; 582 1.6 hubertf state = statep->ls_state = SHEREDELIM; 583 1.1 jtc } else { 584 1.2 tls if (c == '\\') { 585 1.2 tls switch (c = getsc()) { 586 1.2 tls case '\\': case '"': 587 1.2 tls case '$': case '`': 588 1.2 tls break; 589 1.2 tls default: 590 1.2 tls if (c) { /* trailing \ lost */ 591 1.2 tls *wp++ = CHAR; 592 1.2 tls *wp++ = '\\'; 593 1.2 tls } 594 1.2 tls break; 595 1.2 tls } 596 1.2 tls } 597 1.1 jtc *wp++ = CHAR; 598 1.1 jtc *wp++ = c; 599 1.1 jtc } 600 1.1 jtc break; 601 1.1 jtc 602 1.1 jtc case SPATTERN: /* in *(...|...) pattern (*+?@!) */ 603 1.1 jtc if ( /*(*/ c == ')') { 604 1.1 jtc *wp++ = CPAT; 605 1.6 hubertf POP_STATE(); 606 1.6 hubertf } else if (c == '|') { 607 1.1 jtc *wp++ = SPAT; 608 1.6 hubertf } else if (c == '(') { 609 1.6 hubertf *wp++ = OPAT; 610 1.6 hubertf *wp++ = ' '; /* simile for @ */ 611 1.6 hubertf PUSH_STATE(SPATTERN); 612 1.6 hubertf } else 613 1.1 jtc goto Sbase1; 614 1.1 jtc break; 615 1.1 jtc } 616 1.1 jtc } 617 1.1 jtc Done: 618 1.1 jtc Xcheck(ws, wp); 619 1.6 hubertf if (statep != &states[1]) 620 1.6 hubertf /* XXX figure out what is missing */ 621 1.1 jtc yyerror("no closing quote\n"); 622 1.1 jtc 623 1.1 jtc /* This done to avoid tests for SHEREDELIM wherever SBASE tested */ 624 1.1 jtc if (state == SHEREDELIM) 625 1.1 jtc state = SBASE; 626 1.1 jtc 627 1.6 hubertf dp = Xstring(ws, wp); 628 1.6 hubertf if ((c == '<' || c == '>') && state == SBASE 629 1.6 hubertf && ((c2 = Xlength(ws, wp)) == 0 630 1.6 hubertf || (c2 == 2 && dp[0] == CHAR && digit(dp[1])))) 631 1.6 hubertf { 632 1.6 hubertf struct ioword *iop = 633 1.6 hubertf (struct ioword *) alloc(sizeof(*iop), ATEMP); 634 1.6 hubertf 635 1.6 hubertf if (c2 == 2) 636 1.6 hubertf iop->unit = dp[1] - '0'; 637 1.6 hubertf else 638 1.6 hubertf iop->unit = c == '>'; /* 0 for <, 1 for > */ 639 1.6 hubertf 640 1.6 hubertf c2 = getsc(); 641 1.6 hubertf /* <<, >>, <> are ok, >< is not */ 642 1.6 hubertf if (c == c2 || (c == '<' && c2 == '>')) { 643 1.6 hubertf iop->flag = c == c2 ? 644 1.6 hubertf (c == '>' ? IOCAT : IOHERE) : IORDWR; 645 1.7 hubertf if (iop->flag == IOHERE) { 646 1.7 hubertf if ((c2 = getsc()) == '-') { 647 1.6 hubertf iop->flag |= IOSKIP; 648 1.7 hubertf } else { 649 1.6 hubertf ungetsc(c2); 650 1.7 hubertf } 651 1.7 hubertf } 652 1.6 hubertf } else if (c2 == '&') 653 1.6 hubertf iop->flag = IODUP | (c == '<' ? IORDUP : 0); 654 1.6 hubertf else { 655 1.6 hubertf iop->flag = c == '>' ? IOWRITE : IOREAD; 656 1.6 hubertf if (c == '>' && c2 == '|') 657 1.6 hubertf iop->flag |= IOCLOB; 658 1.6 hubertf else 659 1.6 hubertf ungetsc(c2); 660 1.6 hubertf } 661 1.6 hubertf 662 1.6 hubertf iop->name = (char *) 0; 663 1.6 hubertf iop->delim = (char *) 0; 664 1.6 hubertf iop->heredoc = (char *) 0; 665 1.6 hubertf Xfree(ws, wp); /* free word */ 666 1.6 hubertf yylval.iop = iop; 667 1.6 hubertf return REDIR; 668 1.1 jtc } 669 1.1 jtc 670 1.6 hubertf if (wp == dp && state == SBASE) { 671 1.1 jtc Xfree(ws, wp); /* free word */ 672 1.1 jtc /* no word, process LEX1 character */ 673 1.1 jtc switch (c) { 674 1.1 jtc default: 675 1.1 jtc return c; 676 1.1 jtc 677 1.1 jtc case '|': 678 1.1 jtc case '&': 679 1.1 jtc case ';': 680 1.1 jtc if ((c2 = getsc()) == c) 681 1.1 jtc c = (c == ';') ? BREAK : 682 1.1 jtc (c == '|') ? LOGOR : 683 1.1 jtc (c == '&') ? LOGAND : 684 1.1 jtc YYERRCODE; 685 1.1 jtc #ifdef KSH 686 1.1 jtc else if (c == '|' && c2 == '&') 687 1.1 jtc c = COPROC; 688 1.1 jtc #endif /* KSH */ 689 1.1 jtc else 690 1.1 jtc ungetsc(c2); 691 1.1 jtc return c; 692 1.1 jtc 693 1.1 jtc case '\n': 694 1.1 jtc gethere(); 695 1.1 jtc if (cf & CONTIN) 696 1.1 jtc goto Again; 697 1.1 jtc return c; 698 1.1 jtc 699 1.1 jtc case '(': /*)*/ 700 1.2 tls #ifdef KSH 701 1.1 jtc if ((c2 = getsc()) == '(') /*)*/ 702 1.6 hubertf /* XXX need to handle ((...); (...)) */ 703 1.1 jtc c = MDPAREN; 704 1.1 jtc else 705 1.1 jtc ungetsc(c2); 706 1.2 tls #endif /* KSH */ 707 1.1 jtc return c; 708 1.1 jtc /*(*/ 709 1.1 jtc case ')': 710 1.1 jtc return c; 711 1.1 jtc } 712 1.1 jtc } 713 1.1 jtc 714 1.1 jtc *wp++ = EOS; /* terminate word */ 715 1.1 jtc yylval.cp = Xclose(ws, wp); 716 1.2 tls if (state == SWORD 717 1.2 tls #ifdef KSH 718 1.6 hubertf || state == SLETPAREN 719 1.2 tls #endif /* KSH */ 720 1.2 tls ) /* ONEWORD? */ 721 1.1 jtc return LWORD; 722 1.1 jtc ungetsc(c); /* unget terminator */ 723 1.1 jtc 724 1.1 jtc /* copy word to unprefixed string ident */ 725 1.1 jtc for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; ) 726 1.1 jtc *dp++ = *sp++; 727 1.10 mycroft /* Make sure the ident array stays '\0' padded */ 728 1.1 jtc memset(dp, 0, (ident+IDENT) - dp + 1); 729 1.1 jtc if (c != EOS) 730 1.1 jtc *ident = '\0'; /* word is not unquoted */ 731 1.1 jtc 732 1.1 jtc if (*ident != '\0' && (cf&(KEYWORD|ALIAS))) { 733 1.1 jtc struct tbl *p; 734 1.1 jtc int h = hash(ident); 735 1.1 jtc 736 1.1 jtc /* { */ 737 1.22 kamil if ((cf & KEYWORD) && (p = mytsearch(&keywords, ident, h)) 738 1.1 jtc && (!(cf & ESACONLY) || p->val.i == ESAC || p->val.i == '}')) 739 1.1 jtc { 740 1.1 jtc afree(yylval.cp, ATEMP); 741 1.1 jtc return p->val.i; 742 1.1 jtc } 743 1.22 kamil if ((cf & ALIAS) && (p = mytsearch(&aliases, ident, h)) 744 1.1 jtc && (p->flag & ISSET)) 745 1.1 jtc { 746 1.23 kamil Source *s; 747 1.1 jtc 748 1.1 jtc for (s = source; s->type == SALIAS; s = s->next) 749 1.1 jtc if (s->u.tblp == p) 750 1.1 jtc return LWORD; 751 1.1 jtc /* push alias expansion */ 752 1.1 jtc s = pushs(SALIAS, source->areap); 753 1.1 jtc s->start = s->str = p->val.s; 754 1.1 jtc s->u.tblp = p; 755 1.1 jtc s->next = source; 756 1.1 jtc source = s; 757 1.1 jtc afree(yylval.cp, ATEMP); 758 1.1 jtc goto Again; 759 1.1 jtc } 760 1.1 jtc } 761 1.1 jtc 762 1.1 jtc return LWORD; 763 1.1 jtc } 764 1.1 jtc 765 1.1 jtc static void 766 1.1 jtc gethere() 767 1.1 jtc { 768 1.23 kamil struct ioword **p; 769 1.1 jtc 770 1.1 jtc for (p = heres; p < herep; p++) 771 1.1 jtc readhere(*p); 772 1.1 jtc herep = heres; 773 1.1 jtc } 774 1.1 jtc 775 1.1 jtc /* 776 1.1 jtc * read "<<word" text into temp file 777 1.1 jtc */ 778 1.1 jtc 779 1.1 jtc static void 780 1.1 jtc readhere(iop) 781 1.6 hubertf struct ioword *iop; 782 1.1 jtc { 783 1.23 kamil int c; 784 1.1 jtc char *volatile eof; 785 1.1 jtc char *eofp; 786 1.2 tls int skiptabs; 787 1.6 hubertf XString xs; 788 1.6 hubertf char *xp; 789 1.6 hubertf int xpos; 790 1.1 jtc 791 1.1 jtc eof = evalstr(iop->delim, 0); 792 1.1 jtc 793 1.2 tls if (!(iop->flag & IOEVAL)) 794 1.2 tls ignore_backslash_newline++; 795 1.2 tls 796 1.6 hubertf Xinit(xs, xp, 256, ATEMP); 797 1.6 hubertf 798 1.1 jtc for (;;) { 799 1.1 jtc eofp = eof; 800 1.1 jtc skiptabs = iop->flag & IOSKIP; 801 1.6 hubertf xpos = Xsavepos(xs, xp); 802 1.2 tls while ((c = getsc()) != 0) { 803 1.1 jtc if (skiptabs) { 804 1.1 jtc if (c == '\t') 805 1.1 jtc continue; 806 1.1 jtc skiptabs = 0; 807 1.1 jtc } 808 1.1 jtc if (c != *eofp) 809 1.1 jtc break; 810 1.6 hubertf Xcheck(xs, xp); 811 1.6 hubertf Xput(xs, xp, c); 812 1.1 jtc eofp++; 813 1.1 jtc } 814 1.1 jtc /* Allow EOF here so commands with out trailing newlines 815 1.1 jtc * will work (eg, ksh -c '...', $(...), etc). 816 1.1 jtc */ 817 1.6 hubertf if (*eofp == '\0' && (c == 0 || c == '\n')) { 818 1.6 hubertf xp = Xrestpos(xs, xp, xpos); 819 1.1 jtc break; 820 1.6 hubertf } 821 1.1 jtc ungetsc(c); 822 1.2 tls while ((c = getsc()) != '\n') { 823 1.1 jtc if (c == 0) 824 1.1 jtc yyerror("here document `%s' unclosed\n", eof); 825 1.6 hubertf Xcheck(xs, xp); 826 1.6 hubertf Xput(xs, xp, c); 827 1.1 jtc } 828 1.6 hubertf Xcheck(xs, xp); 829 1.6 hubertf Xput(xs, xp, c); 830 1.1 jtc } 831 1.6 hubertf Xput(xs, xp, '\0'); 832 1.6 hubertf iop->heredoc = Xclose(xs, xp); 833 1.6 hubertf 834 1.2 tls if (!(iop->flag & IOEVAL)) 835 1.2 tls ignore_backslash_newline--; 836 1.1 jtc } 837 1.1 jtc 838 1.1 jtc void 839 1.1 jtc yyerror(const char *fmt, ...) 840 1.1 jtc { 841 1.1 jtc va_list va; 842 1.1 jtc 843 1.1 jtc /* pop aliases and re-reads */ 844 1.1 jtc while (source->type == SALIAS || source->type == SREREAD) 845 1.1 jtc source = source->next; 846 1.1 jtc source->str = null; /* zap pending input */ 847 1.1 jtc 848 1.21 kamil error_prefix(true); 849 1.19 kamil va_start(va, fmt); 850 1.1 jtc shf_vfprintf(shl_out, fmt, va); 851 1.1 jtc va_end(va); 852 1.15 joerg errorf("%s", null); 853 1.1 jtc } 854 1.1 jtc 855 1.1 jtc /* 856 1.1 jtc * input for yylex with alias expansion 857 1.1 jtc */ 858 1.1 jtc 859 1.1 jtc Source * 860 1.1 jtc pushs(type, areap) 861 1.1 jtc int type; 862 1.1 jtc Area *areap; 863 1.1 jtc { 864 1.23 kamil Source *s; 865 1.1 jtc 866 1.1 jtc s = (Source *) alloc(sizeof(Source), areap); 867 1.1 jtc s->type = type; 868 1.1 jtc s->str = null; 869 1.1 jtc s->start = NULL; 870 1.1 jtc s->line = 0; 871 1.1 jtc s->errline = 0; 872 1.1 jtc s->file = NULL; 873 1.1 jtc s->flags = 0; 874 1.1 jtc s->next = NULL; 875 1.1 jtc s->areap = areap; 876 1.1 jtc if (type == SFILE || type == SSTDIN) { 877 1.1 jtc char *dummy; 878 1.1 jtc Xinit(s->xs, dummy, 256, s->areap); 879 1.1 jtc } else 880 1.1 jtc memset(&s->xs, 0, sizeof(s->xs)); 881 1.1 jtc return s; 882 1.1 jtc } 883 1.1 jtc 884 1.1 jtc static int 885 1.2 tls getsc__() 886 1.1 jtc { 887 1.23 kamil Source *s = source; 888 1.23 kamil int c; 889 1.1 jtc 890 1.1 jtc while ((c = *s->str++) == 0) { 891 1.1 jtc s->str = NULL; /* return 0 for EOF by default */ 892 1.1 jtc switch (s->type) { 893 1.1 jtc case SEOF: 894 1.1 jtc s->str = null; 895 1.1 jtc return 0; 896 1.1 jtc 897 1.1 jtc case SSTDIN: 898 1.1 jtc case SFILE: 899 1.1 jtc getsc_line(s); 900 1.1 jtc break; 901 1.1 jtc 902 1.1 jtc case SWSTR: 903 1.1 jtc break; 904 1.1 jtc 905 1.1 jtc case SSTRING: 906 1.1 jtc break; 907 1.1 jtc 908 1.1 jtc case SWORDS: 909 1.1 jtc s->start = s->str = *s->u.strv++; 910 1.1 jtc s->type = SWORDSEP; 911 1.1 jtc break; 912 1.1 jtc 913 1.1 jtc case SWORDSEP: 914 1.1 jtc if (*s->u.strv == NULL) { 915 1.1 jtc s->start = s->str = newline; 916 1.1 jtc s->type = SEOF; 917 1.1 jtc } else { 918 1.1 jtc s->start = s->str = space; 919 1.1 jtc s->type = SWORDS; 920 1.1 jtc } 921 1.1 jtc break; 922 1.1 jtc 923 1.1 jtc case SALIAS: 924 1.1 jtc if (s->flags & SF_ALIASEND) { 925 1.1 jtc /* pass on an unused SF_ALIAS flag */ 926 1.1 jtc source = s->next; 927 1.1 jtc source->flags |= s->flags & SF_ALIAS; 928 1.1 jtc s = source; 929 1.1 jtc } else if (*s->u.tblp->val.s 930 1.5 christos && isspace((unsigned char)strchr(s->u.tblp->val.s, 0)[-1])) 931 1.1 jtc { 932 1.1 jtc source = s = s->next; /* pop source stack */ 933 1.2 tls /* Note that this alias ended with a space, 934 1.2 tls * enabling alias expansion on the following 935 1.2 tls * word. 936 1.2 tls */ 937 1.1 jtc s->flags |= SF_ALIAS; 938 1.1 jtc } else { 939 1.2 tls /* At this point, we need to keep the current 940 1.2 tls * alias in the source list so recursive 941 1.2 tls * aliases can be detected and we also need 942 1.2 tls * to return the next character. Do this 943 1.2 tls * by temporarily popping the alias to get 944 1.2 tls * the next character and then put it back 945 1.2 tls * in the source list with the SF_ALIASEND 946 1.2 tls * flag set. 947 1.1 jtc */ 948 1.2 tls source = s->next; /* pop source stack */ 949 1.2 tls source->flags |= s->flags & SF_ALIAS; 950 1.2 tls c = getsc__(); 951 1.2 tls if (c) { 952 1.2 tls s->flags |= SF_ALIASEND; 953 1.2 tls s->ugbuf[0] = c; s->ugbuf[1] = '\0'; 954 1.2 tls s->start = s->str = s->ugbuf; 955 1.2 tls s->next = source; 956 1.2 tls source = s; 957 1.2 tls } else { 958 1.2 tls s = source; 959 1.2 tls /* avoid reading eof twice */ 960 1.2 tls s->str = NULL; 961 1.2 tls break; 962 1.2 tls } 963 1.1 jtc } 964 1.1 jtc continue; 965 1.1 jtc 966 1.1 jtc case SREREAD: 967 1.2 tls if (s->start != s->ugbuf) /* yuck */ 968 1.1 jtc afree(s->u.freeme, ATEMP); 969 1.1 jtc source = s = s->next; 970 1.1 jtc continue; 971 1.1 jtc } 972 1.1 jtc if (s->str == NULL) { 973 1.1 jtc s->type = SEOF; 974 1.1 jtc s->start = s->str = null; 975 1.1 jtc return '\0'; 976 1.1 jtc } 977 1.1 jtc if (s->flags & SF_ECHO) { 978 1.1 jtc shf_puts(s->str, shl_out); 979 1.1 jtc shf_flush(shl_out); 980 1.1 jtc } 981 1.1 jtc } 982 1.1 jtc return c; 983 1.1 jtc } 984 1.1 jtc 985 1.1 jtc static void 986 1.1 jtc getsc_line(s) 987 1.1 jtc Source *s; 988 1.1 jtc { 989 1.1 jtc char *xp = Xstring(s->xs, xp); 990 1.1 jtc int interactive = Flag(FTALKING) && s->type == SSTDIN; 991 1.1 jtc int have_tty = interactive && (s->flags & SF_TTY); 992 1.1 jtc 993 1.1 jtc /* Done here to ensure nothing odd happens when a timeout occurs */ 994 1.1 jtc XcheckN(s->xs, xp, LINE); 995 1.1 jtc *xp = '\0'; 996 1.1 jtc s->start = s->str = xp; 997 1.1 jtc 998 1.1 jtc #ifdef KSH 999 1.1 jtc if (have_tty && ksh_tmout) { 1000 1.1 jtc ksh_tmout_state = TMOUT_READING; 1001 1.1 jtc alarm(ksh_tmout); 1002 1.1 jtc } 1003 1.1 jtc #endif /* KSH */ 1004 1.1 jtc #ifdef EDIT 1005 1.1 jtc if (have_tty && (0 1006 1.1 jtc # ifdef VI 1007 1.1 jtc || Flag(FVI) 1008 1.1 jtc # endif /* VI */ 1009 1.1 jtc # ifdef EMACS 1010 1.1 jtc || Flag(FEMACS) || Flag(FGMACS) 1011 1.1 jtc # endif /* EMACS */ 1012 1.1 jtc )) 1013 1.1 jtc { 1014 1.1 jtc int nread; 1015 1.1 jtc 1016 1.1 jtc nread = x_read(xp, LINE); 1017 1.1 jtc if (nread < 0) /* read error */ 1018 1.1 jtc nread = 0; 1019 1.1 jtc xp[nread] = '\0'; 1020 1.1 jtc xp += nread; 1021 1.1 jtc } 1022 1.1 jtc else 1023 1.1 jtc #endif /* EDIT */ 1024 1.1 jtc { 1025 1.1 jtc if (interactive) { 1026 1.1 jtc pprompt(prompt, 0); 1027 1.1 jtc } else 1028 1.1 jtc s->line++; 1029 1.1 jtc 1030 1.1 jtc while (1) { 1031 1.1 jtc char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf); 1032 1.1 jtc 1033 1.1 jtc if (!p && shf_error(s->u.shf) 1034 1.1 jtc && shf_errno(s->u.shf) == EINTR) 1035 1.1 jtc { 1036 1.1 jtc shf_clearerr(s->u.shf); 1037 1.1 jtc if (trap) 1038 1.1 jtc runtraps(0); 1039 1.1 jtc continue; 1040 1.1 jtc } 1041 1.1 jtc if (!p || (xp = p, xp[-1] == '\n')) 1042 1.1 jtc break; 1043 1.1 jtc /* double buffer size */ 1044 1.1 jtc xp++; /* move past null so doubling works... */ 1045 1.1 jtc XcheckN(s->xs, xp, Xlength(s->xs, xp)); 1046 1.1 jtc xp--; /* ...and move back again */ 1047 1.1 jtc } 1048 1.1 jtc /* flush any unwanted input so other programs/builtins 1049 1.1 jtc * can read it. Not very optimal, but less error prone 1050 1.1 jtc * than flushing else where, dealing with redirections, 1051 1.1 jtc * etc.. 1052 1.1 jtc * todo: reduce size of shf buffer (~128?) if SSTDIN 1053 1.1 jtc */ 1054 1.1 jtc if (s->type == SSTDIN) 1055 1.1 jtc shf_flush(s->u.shf); 1056 1.1 jtc } 1057 1.1 jtc /* XXX: temporary kludge to restore source after a 1058 1.1 jtc * trap may have been executed. 1059 1.1 jtc */ 1060 1.1 jtc source = s; 1061 1.1 jtc #ifdef KSH 1062 1.1 jtc if (have_tty && ksh_tmout) 1063 1.1 jtc { 1064 1.1 jtc ksh_tmout_state = TMOUT_EXECUTING; 1065 1.1 jtc alarm(0); 1066 1.1 jtc } 1067 1.1 jtc #endif /* KSH */ 1068 1.1 jtc s->start = s->str = Xstring(s->xs, xp); 1069 1.1 jtc strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp)); 1070 1.1 jtc /* Note: if input is all nulls, this is not eof */ 1071 1.1 jtc if (Xlength(s->xs, xp) == 0) { /* EOF */ 1072 1.1 jtc if (s->type == SFILE) 1073 1.1 jtc shf_fdclose(s->u.shf); 1074 1.1 jtc s->str = NULL; 1075 1.1 jtc } else if (interactive) { 1076 1.1 jtc #ifdef HISTORY 1077 1.1 jtc char *p = Xstring(s->xs, xp); 1078 1.1 jtc if (cur_prompt == PS1) 1079 1.1 jtc while (*p && ctype(*p, C_IFS) && ctype(*p, C_IFSWS)) 1080 1.1 jtc p++; 1081 1.1 jtc if (*p) { 1082 1.1 jtc # ifdef EASY_HISTORY 1083 1.1 jtc if (cur_prompt == PS2) 1084 1.1 jtc histappend(Xstring(s->xs, xp), 1); 1085 1.1 jtc else 1086 1.1 jtc # endif /* EASY_HISTORY */ 1087 1.1 jtc { 1088 1.1 jtc s->line++; 1089 1.1 jtc histsave(s->line, s->str, 1); 1090 1.1 jtc } 1091 1.1 jtc } 1092 1.1 jtc #endif /* HISTORY */ 1093 1.1 jtc } 1094 1.1 jtc if (interactive) 1095 1.1 jtc set_prompt(PS2, (Source *) 0); 1096 1.1 jtc } 1097 1.1 jtc 1098 1.1 jtc void 1099 1.1 jtc set_prompt(to, s) 1100 1.1 jtc int to; 1101 1.1 jtc Source *s; 1102 1.1 jtc { 1103 1.1 jtc cur_prompt = to; 1104 1.1 jtc 1105 1.1 jtc switch (to) { 1106 1.1 jtc case PS1: /* command */ 1107 1.1 jtc #ifdef KSH 1108 1.1 jtc /* Substitute ! and !! here, before substitutions are done 1109 1.1 jtc * so ! in expanded variables are not expanded. 1110 1.1 jtc * NOTE: this is not what at&t ksh does (it does it after 1111 1.1 jtc * substitutions, POSIX doesn't say which is to be done. 1112 1.1 jtc */ 1113 1.1 jtc { 1114 1.1 jtc struct shf *shf; 1115 1.10 mycroft char * volatile ps1; 1116 1.1 jtc Area *saved_atemp; 1117 1.1 jtc 1118 1.1 jtc ps1 = str_val(global("PS1")); 1119 1.1 jtc shf = shf_sopen((char *) 0, strlen(ps1) * 2, 1120 1.1 jtc SHF_WR | SHF_DYNAMIC, (struct shf *) 0); 1121 1.1 jtc while (*ps1) { 1122 1.1 jtc if (*ps1 != '!' || *++ps1 == '!') 1123 1.1 jtc shf_putchar(*ps1++, shf); 1124 1.1 jtc else 1125 1.1 jtc shf_fprintf(shf, "%d", 1126 1.1 jtc s ? s->line + 1 : 0); 1127 1.1 jtc } 1128 1.1 jtc ps1 = shf_sclose(shf); 1129 1.1 jtc saved_atemp = ATEMP; 1130 1.1 jtc newenv(E_ERRH); 1131 1.1 jtc if (ksh_sigsetjmp(e->jbuf, 0)) { 1132 1.1 jtc prompt = safe_prompt; 1133 1.1 jtc /* Don't print an error - assume it has already 1134 1.1 jtc * been printed. Reason is we may have forked 1135 1.1 jtc * to run a command and the child may be 1136 1.1 jtc * unwinding its stack through this code as it 1137 1.1 jtc * exits. 1138 1.1 jtc */ 1139 1.1 jtc } else 1140 1.1 jtc prompt = str_save(substitute(ps1, 0), 1141 1.1 jtc saved_atemp); 1142 1.1 jtc quitenv(); 1143 1.1 jtc } 1144 1.1 jtc #else /* KSH */ 1145 1.1 jtc prompt = str_val(global("PS1")); 1146 1.1 jtc #endif /* KSH */ 1147 1.1 jtc break; 1148 1.1 jtc 1149 1.1 jtc case PS2: /* command continuation */ 1150 1.1 jtc prompt = str_val(global("PS2")); 1151 1.1 jtc break; 1152 1.1 jtc } 1153 1.1 jtc } 1154 1.1 jtc 1155 1.1 jtc /* See also related routine, promptlen() in edit.c */ 1156 1.1 jtc void 1157 1.1 jtc pprompt(cp, ntruncate) 1158 1.1 jtc const char *cp; 1159 1.1 jtc int ntruncate; 1160 1.1 jtc { 1161 1.1 jtc #if 0 1162 1.1 jtc char nbuf[32]; 1163 1.1 jtc int c; 1164 1.1 jtc 1165 1.1 jtc while (*cp != 0) { 1166 1.1 jtc if (*cp != '!') 1167 1.1 jtc c = *cp++; 1168 1.1 jtc else if (*++cp == '!') 1169 1.1 jtc c = *cp++; 1170 1.1 jtc else { 1171 1.1 jtc int len; 1172 1.1 jtc char *p; 1173 1.1 jtc 1174 1.1 jtc shf_snprintf(p = nbuf, sizeof(nbuf), "%d", 1175 1.1 jtc source->line + 1); 1176 1.1 jtc len = strlen(nbuf); 1177 1.1 jtc if (ntruncate) { 1178 1.1 jtc if (ntruncate >= len) { 1179 1.1 jtc ntruncate -= len; 1180 1.1 jtc continue; 1181 1.1 jtc } 1182 1.1 jtc p += ntruncate; 1183 1.1 jtc len -= ntruncate; 1184 1.1 jtc ntruncate = 0; 1185 1.1 jtc } 1186 1.1 jtc shf_write(p, len, shl_out); 1187 1.1 jtc continue; 1188 1.1 jtc } 1189 1.1 jtc if (ntruncate) 1190 1.1 jtc --ntruncate; 1191 1.1 jtc else 1192 1.1 jtc shf_putc(c, shl_out); 1193 1.1 jtc } 1194 1.1 jtc #endif /* 0 */ 1195 1.2 tls shf_puts(cp + ntruncate, shl_out); 1196 1.2 tls shf_flush(shl_out); 1197 1.1 jtc } 1198 1.1 jtc 1199 1.1 jtc /* Read the variable part of a ${...} expression (ie, up to but not including 1200 1.1 jtc * the :[-+?=#%] or close-brace. 1201 1.1 jtc */ 1202 1.1 jtc static char * 1203 1.1 jtc get_brace_var(wsp, wp) 1204 1.1 jtc XString *wsp; 1205 1.1 jtc char *wp; 1206 1.1 jtc { 1207 1.1 jtc enum parse_state { 1208 1.1 jtc PS_INITIAL, PS_SAW_HASH, PS_IDENT, 1209 1.1 jtc PS_NUMBER, PS_VAR1, PS_END 1210 1.1 jtc } 1211 1.1 jtc state; 1212 1.1 jtc char c; 1213 1.1 jtc 1214 1.1 jtc state = PS_INITIAL; 1215 1.1 jtc while (1) { 1216 1.2 tls c = getsc(); 1217 1.1 jtc /* State machine to figure out where the variable part ends. */ 1218 1.1 jtc switch (state) { 1219 1.1 jtc case PS_INITIAL: 1220 1.1 jtc if (c == '#') { 1221 1.1 jtc state = PS_SAW_HASH; 1222 1.1 jtc break; 1223 1.1 jtc } 1224 1.1 jtc /* fall through.. */ 1225 1.1 jtc case PS_SAW_HASH: 1226 1.1 jtc if (letter(c)) 1227 1.1 jtc state = PS_IDENT; 1228 1.1 jtc else if (digit(c)) 1229 1.1 jtc state = PS_NUMBER; 1230 1.1 jtc else if (ctype(c, C_VAR1)) 1231 1.1 jtc state = PS_VAR1; 1232 1.1 jtc else 1233 1.1 jtc state = PS_END; 1234 1.1 jtc break; 1235 1.1 jtc case PS_IDENT: 1236 1.1 jtc if (!letnum(c)) { 1237 1.1 jtc state = PS_END; 1238 1.1 jtc if (c == '[') { 1239 1.1 jtc char *tmp, *p; 1240 1.1 jtc 1241 1.1 jtc if (!arraysub(&tmp)) 1242 1.1 jtc yyerror("missing ]\n"); 1243 1.1 jtc *wp++ = c; 1244 1.1 jtc for (p = tmp; *p; ) { 1245 1.1 jtc Xcheck(*wsp, wp); 1246 1.1 jtc *wp++ = *p++; 1247 1.1 jtc } 1248 1.1 jtc afree(tmp, ATEMP); 1249 1.2 tls c = getsc(); /* the ] */ 1250 1.1 jtc } 1251 1.1 jtc } 1252 1.1 jtc break; 1253 1.1 jtc case PS_NUMBER: 1254 1.1 jtc if (!digit(c)) 1255 1.1 jtc state = PS_END; 1256 1.1 jtc break; 1257 1.1 jtc case PS_VAR1: 1258 1.1 jtc state = PS_END; 1259 1.1 jtc break; 1260 1.1 jtc case PS_END: /* keep gcc happy */ 1261 1.1 jtc break; 1262 1.1 jtc } 1263 1.1 jtc if (state == PS_END) { 1264 1.1 jtc *wp++ = '\0'; /* end of variable part */ 1265 1.1 jtc ungetsc(c); 1266 1.1 jtc break; 1267 1.1 jtc } 1268 1.1 jtc Xcheck(*wsp, wp); 1269 1.1 jtc *wp++ = c; 1270 1.1 jtc } 1271 1.1 jtc return wp; 1272 1.1 jtc } 1273 1.1 jtc 1274 1.1 jtc /* 1275 1.1 jtc * Save an array subscript - returns true if matching bracket found, false 1276 1.1 jtc * if eof or newline was found. 1277 1.1 jtc * (Returned string double null terminated) 1278 1.1 jtc */ 1279 1.1 jtc static int 1280 1.1 jtc arraysub(strp) 1281 1.1 jtc char **strp; 1282 1.1 jtc { 1283 1.1 jtc XString ws; 1284 1.1 jtc char *wp; 1285 1.1 jtc char c; 1286 1.1 jtc int depth = 1; /* we are just past the initial [ */ 1287 1.1 jtc 1288 1.1 jtc Xinit(ws, wp, 32, ATEMP); 1289 1.1 jtc 1290 1.1 jtc do { 1291 1.2 tls c = getsc(); 1292 1.1 jtc Xcheck(ws, wp); 1293 1.1 jtc *wp++ = c; 1294 1.1 jtc if (c == '[') 1295 1.1 jtc depth++; 1296 1.1 jtc else if (c == ']') 1297 1.1 jtc depth--; 1298 1.1 jtc } while (depth > 0 && c && c != '\n'); 1299 1.1 jtc 1300 1.1 jtc *wp++ = '\0'; 1301 1.1 jtc *strp = Xclose(ws, wp); 1302 1.1 jtc 1303 1.1 jtc return depth == 0 ? 1 : 0; 1304 1.1 jtc } 1305 1.1 jtc 1306 1.1 jtc /* Unget a char: handles case when we are already at the start of the buffer */ 1307 1.1 jtc static const char * 1308 1.2 tls ungetsc(c) 1309 1.1 jtc int c; 1310 1.1 jtc { 1311 1.2 tls if (backslash_skip) 1312 1.2 tls backslash_skip--; 1313 1.1 jtc /* Don't unget eof... */ 1314 1.1 jtc if (source->str == null && c == '\0') 1315 1.1 jtc return source->str; 1316 1.1 jtc if (source->str > source->start) 1317 1.1 jtc source->str--; 1318 1.1 jtc else { 1319 1.1 jtc Source *s; 1320 1.1 jtc 1321 1.1 jtc s = pushs(SREREAD, source->areap); 1322 1.2 tls s->ugbuf[0] = c; s->ugbuf[1] = '\0'; 1323 1.2 tls s->start = s->str = s->ugbuf; 1324 1.1 jtc s->next = source; 1325 1.1 jtc source = s; 1326 1.1 jtc } 1327 1.1 jtc return source->str; 1328 1.1 jtc } 1329 1.1 jtc 1330 1.2 tls 1331 1.1 jtc /* Called to get a char that isn't a \newline sequence. */ 1332 1.1 jtc static int 1333 1.2 tls getsc_bn ARGS((void)) 1334 1.1 jtc { 1335 1.2 tls int c, c2; 1336 1.2 tls 1337 1.2 tls if (ignore_backslash_newline) 1338 1.2 tls return getsc_(); 1339 1.2 tls 1340 1.2 tls if (backslash_skip == 1) { 1341 1.2 tls backslash_skip = 2; 1342 1.2 tls return getsc_(); 1343 1.2 tls } 1344 1.2 tls 1345 1.2 tls backslash_skip = 0; 1346 1.1 jtc 1347 1.1 jtc while (1) { 1348 1.1 jtc c = getsc_(); 1349 1.2 tls if (c == '\\') { 1350 1.2 tls if ((c2 = getsc_()) == '\n') 1351 1.2 tls /* ignore the \newline; get the next char... */ 1352 1.2 tls continue; 1353 1.2 tls ungetsc(c2); 1354 1.2 tls backslash_skip = 1; 1355 1.1 jtc } 1356 1.2 tls return c; 1357 1.1 jtc } 1358 1.6 hubertf } 1359 1.6 hubertf 1360 1.6 hubertf static Lex_state * 1361 1.6 hubertf push_state_(si, old_end) 1362 1.6 hubertf State_info *si; 1363 1.6 hubertf Lex_state *old_end; 1364 1.6 hubertf { 1365 1.6 hubertf Lex_state *new = alloc(sizeof(Lex_state) * STATE_BSIZE, ATEMP); 1366 1.6 hubertf 1367 1.6 hubertf new[0].ls_info.base = old_end; 1368 1.6 hubertf si->base = &new[0]; 1369 1.6 hubertf si->end = &new[STATE_BSIZE]; 1370 1.6 hubertf return &new[1]; 1371 1.6 hubertf } 1372 1.6 hubertf 1373 1.6 hubertf static Lex_state * 1374 1.6 hubertf pop_state_(si, old_end) 1375 1.6 hubertf State_info *si; 1376 1.6 hubertf Lex_state *old_end; 1377 1.6 hubertf { 1378 1.6 hubertf Lex_state *old_base = si->base; 1379 1.6 hubertf 1380 1.6 hubertf si->base = old_end->ls_info.base - STATE_BSIZE; 1381 1.6 hubertf si->end = old_end->ls_info.base; 1382 1.6 hubertf 1383 1.6 hubertf afree(old_base, ATEMP); 1384 1.6 hubertf 1385 1.8 simonb return si->base + STATE_BSIZE - 1; 1386 1.1 jtc } 1387