1 1.38 christos /* $NetBSD: lex.c,v 1.38 2020/10/02 17:33:13 christos Exp $ */ 2 1.7 cgd 3 1.1 cgd /*- 4 1.5 mycroft * Copyright (c) 1980, 1991, 1993 5 1.5 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.22 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.11 christos #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.7 cgd #if 0 35 1.7 cgd static char sccsid[] = "@(#)lex.c 8.1 (Berkeley) 5/31/93"; 36 1.7 cgd #else 37 1.38 christos __RCSID("$NetBSD: lex.c,v 1.38 2020/10/02 17:33:13 christos Exp $"); 38 1.7 cgd #endif 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.19 wiz #include <sys/ioctl.h> 42 1.1 cgd #include <sys/types.h> 43 1.19 wiz 44 1.1 cgd #include <errno.h> 45 1.21 wiz #include <stdarg.h> 46 1.1 cgd #include <stdlib.h> 47 1.1 cgd #include <string.h> 48 1.19 wiz #include <termios.h> 49 1.1 cgd #include <unistd.h> 50 1.1 cgd 51 1.1 cgd #include "csh.h" 52 1.1 cgd #include "extern.h" 53 1.1 cgd 54 1.1 cgd /* 55 1.1 cgd * These lexical routines read input and form lists of words. 56 1.1 cgd * There is some involved processing here, because of the complications 57 1.1 cgd * of input buffering, and especially because of history substitution. 58 1.1 cgd */ 59 1.1 cgd 60 1.19 wiz static Char *word(void); 61 1.19 wiz static int getC1(int); 62 1.19 wiz static void getdol(void); 63 1.19 wiz static void getexcl(int); 64 1.26 christos static struct Hist *findev(Char *, int); 65 1.19 wiz static void setexclp(Char *); 66 1.19 wiz static int bgetc(void); 67 1.19 wiz static void bfree(void); 68 1.19 wiz static struct wordent *gethent(int); 69 1.19 wiz static int matchs(Char *, Char *); 70 1.19 wiz static int getsel(int *, int *, int); 71 1.19 wiz static struct wordent *getsub(struct wordent *); 72 1.26 christos static Char *subword(Char *, int, int *); 73 1.26 christos static struct wordent *dosub(int, struct wordent *, int); 74 1.1 cgd 75 1.1 cgd /* 76 1.1 cgd * Peekc is a peek character for getC, peekread for readc. 77 1.1 cgd * There is a subtlety here in many places... history routines 78 1.1 cgd * will read ahead and then insert stuff into the input stream. 79 1.1 cgd * If they push back a character then they must push it behind 80 1.1 cgd * the text substituted by the history substitution. On the other 81 1.1 cgd * hand in several places we need 2 peek characters. To make this 82 1.1 cgd * all work, the history routines read with getC, and make use both 83 1.1 cgd * of ungetC and unreadc. The key observation is that the state 84 1.1 cgd * of getC at the call of a history reference is such that calls 85 1.1 cgd * to getC from the history routines will always yield calls of 86 1.1 cgd * readc, unless this peeking is involved. That is to say that during 87 1.1 cgd * getexcl the variables lap, exclp, and exclnxt are all zero. 88 1.1 cgd * 89 1.1 cgd * Getdol invokes history substitution, hence the extra peek, peekd, 90 1.1 cgd * which it can ungetD to be before history substitutions. 91 1.1 cgd */ 92 1.30 christos static int peekc = 0, peekd = 0; 93 1.30 christos static int peekread = 0; 94 1.1 cgd 95 1.1 cgd /* (Tail of) current word from ! subst */ 96 1.1 cgd static Char *exclp = NULL; 97 1.1 cgd 98 1.1 cgd /* The rest of the ! subst words */ 99 1.1 cgd static struct wordent *exclnxt = NULL; 100 1.1 cgd 101 1.1 cgd /* Count of remaining words in ! subst */ 102 1.1 cgd static int exclc = 0; 103 1.1 cgd 104 1.1 cgd /* "Globp" for alias resubstitution */ 105 1.18 simonb Char **alvec, *alvecp; 106 1.5 mycroft int aret = F_SEEK; 107 1.1 cgd 108 1.1 cgd /* 109 1.1 cgd * Labuf implements a general buffer for lookahead during lexical operations. 110 1.1 cgd * Text which is to be placed in the input stream can be stuck here. 111 1.1 cgd * We stick parsed ahead $ constructs during initial input, 112 1.1 cgd * process id's from `$$', and modified variable values (from qualifiers 113 1.1 cgd * during expansion in sh.dol.c) here. 114 1.1 cgd */ 115 1.17 christos static Char labuf[BUFSIZE]; 116 1.1 cgd 117 1.1 cgd /* 118 1.1 cgd * Lex returns to its caller not only a wordlist (as a "var" parameter) 119 1.1 cgd * but also whether a history substitution occurred. This is used in 120 1.1 cgd * the main (process) routine to determine whether to echo, and also 121 1.1 cgd * when called by the alias routine to determine whether to keep the 122 1.1 cgd * argument list. 123 1.1 cgd */ 124 1.26 christos static int hadhist = 0; 125 1.1 cgd 126 1.1 cgd /* 127 1.1 cgd * Avoid alias expansion recursion via \!# 128 1.1 cgd */ 129 1.1 cgd int hleft; 130 1.1 cgd 131 1.30 christos static int getCtmp; 132 1.1 cgd 133 1.19 wiz #define getC(f) ((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f)) 134 1.19 wiz #define ungetC(c) peekc = c 135 1.19 wiz #define ungetD(c) peekd = c 136 1.1 cgd 137 1.1 cgd int 138 1.19 wiz lex(struct wordent *hp) 139 1.1 cgd { 140 1.10 tls struct wordent *wdp; 141 1.19 wiz int c; 142 1.1 cgd 143 1.5 mycroft btell(&lineloc); 144 1.1 cgd hp->next = hp->prev = hp; 145 1.1 cgd hp->word = STRNULL; 146 1.5 mycroft hadhist = 0; 147 1.1 cgd do 148 1.1 cgd c = readc(0); 149 1.1 cgd while (c == ' ' || c == '\t'); 150 1.1 cgd if (c == HISTSUB && intty) 151 1.1 cgd /* ^lef^rit from tty is short !:s^lef^rit */ 152 1.1 cgd getexcl(c); 153 1.1 cgd else 154 1.1 cgd unreadc(c); 155 1.1 cgd wdp = hp; 156 1.1 cgd /* 157 1.1 cgd * The following loop is written so that the links needed by freelex will 158 1.1 cgd * be ready and rarin to go even if it is interrupted. 159 1.1 cgd */ 160 1.1 cgd do { 161 1.10 tls struct wordent *new; 162 1.1 cgd 163 1.30 christos new = xmalloc(sizeof(*wdp)); 164 1.1 cgd new->word = 0; 165 1.1 cgd new->prev = wdp; 166 1.1 cgd new->next = hp; 167 1.1 cgd wdp->next = new; 168 1.1 cgd wdp = new; 169 1.1 cgd wdp->word = word(); 170 1.1 cgd } while (wdp->word[0] != '\n'); 171 1.1 cgd hp->prev = wdp; 172 1.1 cgd return (hadhist); 173 1.1 cgd } 174 1.1 cgd 175 1.1 cgd void 176 1.19 wiz prlex(FILE *fp, struct wordent *sp0) 177 1.1 cgd { 178 1.19 wiz struct wordent *sp; 179 1.1 cgd 180 1.19 wiz sp = sp0->next; 181 1.1 cgd for (;;) { 182 1.19 wiz (void)fprintf(fp, "%s", vis_str(sp->word)); 183 1.1 cgd sp = sp->next; 184 1.1 cgd if (sp == sp0) 185 1.1 cgd break; 186 1.1 cgd if (sp->word[0] != '\n') 187 1.5 mycroft (void) fputc(' ', fp); 188 1.1 cgd } 189 1.1 cgd } 190 1.1 cgd 191 1.29 christos #ifdef EDIT 192 1.29 christos int 193 1.29 christos sprlex(char **s, struct wordent *sp0) 194 1.29 christos { 195 1.29 christos struct wordent *sp; 196 1.29 christos 197 1.29 christos sp = sp0->next; 198 1.29 christos char *os = *s; 199 1.29 christos for (;;) { 200 1.29 christos char *w = vis_str(sp->word); 201 1.29 christos if (os == NULL) { 202 1.29 christos if (asprintf(s, "%s", w) < 0) 203 1.29 christos return -1; 204 1.29 christos os = *s; 205 1.29 christos } else if (*os != '\n') { 206 1.29 christos if (asprintf(s, "%s %s", os, w) < 0) { 207 1.29 christos free(os); 208 1.29 christos return 1; 209 1.29 christos } 210 1.29 christos free(os); 211 1.29 christos os = *s; 212 1.29 christos } 213 1.29 christos sp = sp->next; 214 1.29 christos if (sp == sp0) 215 1.29 christos break; 216 1.29 christos } 217 1.29 christos return 0; 218 1.29 christos } 219 1.29 christos #endif 220 1.29 christos 221 1.1 cgd void 222 1.19 wiz copylex(struct wordent *hp, struct wordent *fp) 223 1.1 cgd { 224 1.10 tls struct wordent *wdp; 225 1.1 cgd 226 1.1 cgd wdp = hp; 227 1.1 cgd fp = fp->next; 228 1.1 cgd do { 229 1.10 tls struct wordent *new; 230 1.1 cgd 231 1.30 christos new = xmalloc(sizeof(*wdp)); 232 1.1 cgd new->prev = wdp; 233 1.1 cgd new->next = hp; 234 1.1 cgd wdp->next = new; 235 1.1 cgd wdp = new; 236 1.1 cgd wdp->word = Strsave(fp->word); 237 1.1 cgd fp = fp->next; 238 1.1 cgd } while (wdp->word[0] != '\n'); 239 1.1 cgd hp->prev = wdp; 240 1.1 cgd } 241 1.1 cgd 242 1.1 cgd void 243 1.19 wiz freelex(struct wordent *vp) 244 1.1 cgd { 245 1.10 tls struct wordent *fp; 246 1.1 cgd 247 1.1 cgd while (vp->next != vp) { 248 1.1 cgd fp = vp->next; 249 1.1 cgd vp->next = fp->next; 250 1.33 christos free(fp->word); 251 1.33 christos free(fp); 252 1.1 cgd } 253 1.1 cgd vp->prev = vp; 254 1.1 cgd } 255 1.1 cgd 256 1.1 cgd static Char * 257 1.19 wiz word(void) 258 1.1 cgd { 259 1.19 wiz Char wbuf[BUFSIZE], *wp; 260 1.30 christos int i, c, c1; 261 1.26 christos int dolflg; 262 1.1 cgd 263 1.1 cgd wp = wbuf; 264 1.17 christos i = BUFSIZE - 4; 265 1.1 cgd loop: 266 1.5 mycroft while ((c = getC(DOALL)) == ' ' || c == '\t') 267 1.5 mycroft continue; 268 1.1 cgd if (cmap(c, _META | _ESC)) 269 1.1 cgd switch (c) { 270 1.1 cgd case '&': 271 1.1 cgd case '|': 272 1.1 cgd case '<': 273 1.1 cgd case '>': 274 1.30 christos *wp++ = (Char)c; 275 1.1 cgd c1 = getC(DOALL); 276 1.1 cgd if (c1 == c) 277 1.30 christos *wp++ = (Char)c1; 278 1.1 cgd else 279 1.1 cgd ungetC(c1); 280 1.1 cgd goto ret; 281 1.1 cgd 282 1.1 cgd case '#': 283 1.1 cgd if (intty) 284 1.1 cgd break; 285 1.1 cgd c = 0; 286 1.1 cgd do { 287 1.1 cgd c1 = c; 288 1.1 cgd c = getC(0); 289 1.1 cgd } while (c != '\n'); 290 1.1 cgd if (c1 == '\\') 291 1.1 cgd goto loop; 292 1.13 mycroft /* FALLTHROUGH */ 293 1.1 cgd 294 1.1 cgd case ';': 295 1.1 cgd case '(': 296 1.1 cgd case ')': 297 1.1 cgd case '\n': 298 1.30 christos *wp++ = (Char)c; 299 1.1 cgd goto ret; 300 1.1 cgd 301 1.1 cgd case '\\': 302 1.1 cgd c = getC(0); 303 1.1 cgd if (c == '\n') { 304 1.1 cgd if (onelflg == 1) 305 1.1 cgd onelflg = 2; 306 1.1 cgd goto loop; 307 1.1 cgd } 308 1.1 cgd if (c != HIST) 309 1.1 cgd *wp++ = '\\', --i; 310 1.1 cgd c |= QUOTE; 311 1.13 mycroft break; 312 1.1 cgd } 313 1.1 cgd c1 = 0; 314 1.1 cgd dolflg = DOALL; 315 1.1 cgd for (;;) { 316 1.1 cgd if (c1) { 317 1.1 cgd if (c == c1) { 318 1.1 cgd c1 = 0; 319 1.1 cgd dolflg = DOALL; 320 1.1 cgd } 321 1.1 cgd else if (c == '\\') { 322 1.1 cgd c = getC(0); 323 1.1 cgd if (c == HIST) 324 1.1 cgd c |= QUOTE; 325 1.1 cgd else { 326 1.1 cgd if (c == '\n') 327 1.1 cgd /* 328 1.1 cgd * if (c1 == '`') c = ' '; else 329 1.1 cgd */ 330 1.1 cgd c |= QUOTE; 331 1.1 cgd ungetC(c); 332 1.1 cgd c = '\\'; 333 1.1 cgd } 334 1.1 cgd } 335 1.1 cgd else if (c == '\n') { 336 1.1 cgd seterror(ERR_UNMATCHED, c1); 337 1.1 cgd ungetC(c); 338 1.1 cgd break; 339 1.1 cgd } 340 1.1 cgd } 341 1.5 mycroft else if (cmap(c, _META | _QF | _QB | _ESC)) { 342 1.1 cgd if (c == '\\') { 343 1.1 cgd c = getC(0); 344 1.1 cgd if (c == '\n') { 345 1.1 cgd if (onelflg == 1) 346 1.1 cgd onelflg = 2; 347 1.1 cgd break; 348 1.1 cgd } 349 1.1 cgd if (c != HIST) 350 1.1 cgd *wp++ = '\\', --i; 351 1.1 cgd c |= QUOTE; 352 1.1 cgd } 353 1.5 mycroft else if (cmap(c, _QF | _QB)) { /* '"` */ 354 1.1 cgd c1 = c; 355 1.1 cgd dolflg = c == '"' ? DOALL : DOEXCL; 356 1.1 cgd } 357 1.1 cgd else if (c != '#' || !intty) { 358 1.1 cgd ungetC(c); 359 1.1 cgd break; 360 1.1 cgd } 361 1.1 cgd } 362 1.1 cgd if (--i > 0) { 363 1.30 christos *wp++ = (Char)c; 364 1.1 cgd c = getC(dolflg); 365 1.1 cgd } 366 1.1 cgd else { 367 1.1 cgd seterror(ERR_WTOOLONG); 368 1.1 cgd wp = &wbuf[1]; 369 1.1 cgd break; 370 1.1 cgd } 371 1.1 cgd } 372 1.1 cgd ret: 373 1.1 cgd *wp = 0; 374 1.1 cgd return (Strsave(wbuf)); 375 1.1 cgd } 376 1.1 cgd 377 1.1 cgd static int 378 1.19 wiz getC1(int flag) 379 1.1 cgd { 380 1.30 christos int c; 381 1.1 cgd 382 1.13 mycroft for (;;) { 383 1.5 mycroft if ((c = peekc) != '\0') { 384 1.1 cgd peekc = 0; 385 1.1 cgd return (c); 386 1.1 cgd } 387 1.1 cgd if (lap) { 388 1.1 cgd if ((c = *lap++) == 0) 389 1.1 cgd lap = 0; 390 1.1 cgd else { 391 1.5 mycroft if (cmap(c, _META | _QF | _QB)) 392 1.1 cgd c |= QUOTE; 393 1.1 cgd return (c); 394 1.1 cgd } 395 1.1 cgd } 396 1.5 mycroft if ((c = peekd) != '\0') { 397 1.1 cgd peekd = 0; 398 1.1 cgd return (c); 399 1.1 cgd } 400 1.1 cgd if (exclp) { 401 1.5 mycroft if ((c = *exclp++) != '\0') 402 1.1 cgd return (c); 403 1.1 cgd if (exclnxt && --exclc >= 0) { 404 1.1 cgd exclnxt = exclnxt->next; 405 1.1 cgd setexclp(exclnxt->word); 406 1.1 cgd return (' '); 407 1.1 cgd } 408 1.1 cgd exclp = 0; 409 1.1 cgd exclnxt = 0; 410 1.1 cgd } 411 1.1 cgd if (exclnxt) { 412 1.1 cgd exclnxt = exclnxt->next; 413 1.1 cgd if (--exclc < 0) 414 1.1 cgd exclnxt = 0; 415 1.1 cgd else 416 1.1 cgd setexclp(exclnxt->word); 417 1.1 cgd continue; 418 1.1 cgd } 419 1.1 cgd c = readc(0); 420 1.1 cgd if (c == '$' && (flag & DODOL)) { 421 1.1 cgd getdol(); 422 1.1 cgd continue; 423 1.1 cgd } 424 1.1 cgd if (c == HIST && (flag & DOEXCL)) { 425 1.1 cgd getexcl(0); 426 1.1 cgd continue; 427 1.1 cgd } 428 1.1 cgd break; 429 1.1 cgd } 430 1.1 cgd return (c); 431 1.1 cgd } 432 1.1 cgd 433 1.1 cgd static void 434 1.19 wiz getdol(void) 435 1.1 cgd { 436 1.19 wiz Char name[4*MAXVARLEN+1], *ep, *np; 437 1.19 wiz int c, sc; 438 1.26 christos int special, toolong; 439 1.1 cgd 440 1.19 wiz special = 0; 441 1.1 cgd np = name, *np++ = '$'; 442 1.1 cgd c = sc = getC(DOEXCL); 443 1.1 cgd if (any("\t \n", c)) { 444 1.1 cgd ungetD(c); 445 1.1 cgd ungetC('$' | QUOTE); 446 1.1 cgd return; 447 1.1 cgd } 448 1.1 cgd if (c == '{') 449 1.30 christos *np++ = (Char)c, c = getC(DOEXCL); 450 1.1 cgd if (c == '#' || c == '?') 451 1.30 christos special++, *np++ = (Char)c, c = getC(DOEXCL); 452 1.30 christos *np++ = (Char)c; 453 1.1 cgd switch (c) { 454 1.1 cgd case '<': 455 1.1 cgd case '$': 456 1.5 mycroft case '!': 457 1.1 cgd if (special) 458 1.1 cgd seterror(ERR_SPDOLLT); 459 1.1 cgd *np = 0; 460 1.1 cgd addla(name); 461 1.1 cgd return; 462 1.1 cgd case '\n': 463 1.1 cgd ungetD(c); 464 1.1 cgd np--; 465 1.1 cgd seterror(ERR_NEWLINE); 466 1.1 cgd *np = 0; 467 1.1 cgd addla(name); 468 1.1 cgd return; 469 1.1 cgd case '*': 470 1.1 cgd if (special) 471 1.1 cgd seterror(ERR_SPSTAR); 472 1.1 cgd *np = 0; 473 1.1 cgd addla(name); 474 1.1 cgd return; 475 1.1 cgd default: 476 1.1 cgd toolong = 0; 477 1.1 cgd if (Isdigit(c)) { 478 1.1 cgd #ifdef notdef 479 1.1 cgd /* let $?0 pass for now */ 480 1.1 cgd if (special) { 481 1.1 cgd seterror(ERR_DIGIT); 482 1.1 cgd *np = 0; 483 1.1 cgd addla(name); 484 1.1 cgd return; 485 1.1 cgd } 486 1.1 cgd #endif 487 1.1 cgd /* we know that np < &name[4] */ 488 1.1 cgd ep = &np[MAXVARLEN]; 489 1.5 mycroft while ((c = getC(DOEXCL)) != '\0'){ 490 1.1 cgd if (!Isdigit(c)) 491 1.1 cgd break; 492 1.1 cgd if (np < ep) 493 1.30 christos *np++ = (Char)c; 494 1.1 cgd else 495 1.1 cgd toolong = 1; 496 1.1 cgd } 497 1.1 cgd } 498 1.1 cgd else if (letter(c)) { 499 1.1 cgd /* we know that np < &name[4] */ 500 1.1 cgd ep = &np[MAXVARLEN]; 501 1.1 cgd toolong = 0; 502 1.5 mycroft while ((c = getC(DOEXCL)) != '\0') { 503 1.1 cgd /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ 504 1.1 cgd if (!letter(c) && !Isdigit(c)) 505 1.1 cgd break; 506 1.1 cgd if (np < ep) 507 1.30 christos *np++ = (Char)c; 508 1.1 cgd else 509 1.1 cgd toolong = 1; 510 1.1 cgd } 511 1.1 cgd } 512 1.1 cgd else { 513 1.1 cgd *np = 0; 514 1.1 cgd seterror(ERR_VARILL); 515 1.1 cgd addla(name); 516 1.1 cgd return; 517 1.1 cgd } 518 1.1 cgd if (toolong) { 519 1.1 cgd seterror(ERR_VARTOOLONG); 520 1.1 cgd *np = 0; 521 1.1 cgd addla(name); 522 1.1 cgd return; 523 1.1 cgd } 524 1.1 cgd break; 525 1.1 cgd } 526 1.1 cgd if (c == '[') { 527 1.30 christos *np++ = (Char)c; 528 1.1 cgd /* 529 1.1 cgd * Name up to here is a max of MAXVARLEN + 8. 530 1.1 cgd */ 531 1.1 cgd ep = &np[2 * MAXVARLEN + 8]; 532 1.1 cgd do { 533 1.1 cgd /* 534 1.1 cgd * Michael Greim: Allow $ expansion to take place in selector 535 1.1 cgd * expressions. (limits the number of characters returned) 536 1.1 cgd */ 537 1.1 cgd c = getC(DOEXCL | DODOL); 538 1.1 cgd if (c == '\n') { 539 1.1 cgd ungetD(c); 540 1.1 cgd np--; 541 1.1 cgd seterror(ERR_NLINDEX); 542 1.1 cgd *np = 0; 543 1.1 cgd addla(name); 544 1.1 cgd return; 545 1.1 cgd } 546 1.1 cgd if (np < ep) 547 1.30 christos *np++ = (Char)c; 548 1.1 cgd } while (c != ']'); 549 1.1 cgd *np = '\0'; 550 1.1 cgd if (np >= ep) { 551 1.1 cgd seterror(ERR_SELOVFL); 552 1.1 cgd addla(name); 553 1.1 cgd return; 554 1.1 cgd } 555 1.1 cgd c = getC(DOEXCL); 556 1.1 cgd } 557 1.1 cgd /* 558 1.1 cgd * Name up to here is a max of 2 * MAXVARLEN + 8. 559 1.1 cgd */ 560 1.1 cgd if (c == ':') { 561 1.1 cgd /* 562 1.1 cgd * if the :g modifier is followed by a newline, then error right away! 563 1.1 cgd * -strike 564 1.1 cgd */ 565 1.19 wiz int amodflag, gmodflag; 566 1.1 cgd 567 1.19 wiz amodflag = 0; 568 1.19 wiz gmodflag = 0; 569 1.5 mycroft do { 570 1.30 christos *np++ = (Char)c, c = getC(DOEXCL); 571 1.5 mycroft if (c == 'g' || c == 'a') { 572 1.5 mycroft if (c == 'g') 573 1.5 mycroft gmodflag++; 574 1.5 mycroft else 575 1.5 mycroft amodflag++; 576 1.30 christos *np++ = (Char)c; c = getC(DOEXCL); 577 1.5 mycroft } 578 1.5 mycroft if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) { 579 1.5 mycroft if (c == 'g') 580 1.5 mycroft gmodflag++; 581 1.5 mycroft else 582 1.5 mycroft amodflag++; 583 1.30 christos *np++ = (Char)c, c = getC(DOEXCL); 584 1.5 mycroft } 585 1.30 christos *np++ = (Char)c; 586 1.5 mycroft /* scan s// [eichin:19910926.0512EST] */ 587 1.5 mycroft if (c == 's') { 588 1.5 mycroft int delimcnt = 2; 589 1.5 mycroft int delim = getC(0); 590 1.30 christos *np++ = (Char)delim; 591 1.5 mycroft 592 1.5 mycroft if (!delim || letter(delim) 593 1.5 mycroft || Isdigit(delim) || any(" \t\n", delim)) { 594 1.5 mycroft seterror(ERR_BADSUBST); 595 1.5 mycroft break; 596 1.5 mycroft } 597 1.30 christos while ((c = getC(0)) != -1) { 598 1.30 christos *np++ = (Char)c; 599 1.5 mycroft if(c == delim) delimcnt--; 600 1.5 mycroft if(!delimcnt) break; 601 1.5 mycroft } 602 1.5 mycroft if(delimcnt) { 603 1.5 mycroft seterror(ERR_BADSUBST); 604 1.5 mycroft break; 605 1.5 mycroft } 606 1.5 mycroft c = 's'; 607 1.5 mycroft } 608 1.5 mycroft if (!any("htrqxes", c)) { 609 1.15 mycroft if ((amodflag || gmodflag) && c == '\n') 610 1.5 mycroft stderror(ERR_VARSYN); /* strike */ 611 1.5 mycroft seterror(ERR_VARMOD, c); 612 1.5 mycroft *np = 0; 613 1.5 mycroft addla(name); 614 1.5 mycroft return; 615 1.5 mycroft } 616 1.1 cgd } 617 1.5 mycroft while ((c = getC(DOEXCL)) == ':'); 618 1.5 mycroft ungetD(c); 619 1.1 cgd } 620 1.1 cgd else 621 1.1 cgd ungetD(c); 622 1.1 cgd if (sc == '{') { 623 1.1 cgd c = getC(DOEXCL); 624 1.1 cgd if (c != '}') { 625 1.1 cgd ungetD(c); 626 1.1 cgd seterror(ERR_MISSING, '}'); 627 1.1 cgd *np = 0; 628 1.1 cgd addla(name); 629 1.1 cgd return; 630 1.1 cgd } 631 1.30 christos *np++ = (Char)c; 632 1.1 cgd } 633 1.1 cgd *np = 0; 634 1.1 cgd addla(name); 635 1.1 cgd return; 636 1.1 cgd } 637 1.1 cgd 638 1.1 cgd void 639 1.19 wiz addla(Char *cp) 640 1.1 cgd { 641 1.19 wiz Char buf[BUFSIZE]; 642 1.1 cgd 643 1.1 cgd if (Strlen(cp) + (lap ? Strlen(lap) : 0) >= 644 1.1 cgd (sizeof(labuf) - 4) / sizeof(Char)) { 645 1.1 cgd seterror(ERR_EXPOVFL); 646 1.1 cgd return; 647 1.1 cgd } 648 1.1 cgd if (lap) 649 1.19 wiz (void)Strcpy(buf, lap); 650 1.19 wiz (void)Strcpy(labuf, cp); 651 1.1 cgd if (lap) 652 1.19 wiz (void)Strcat(labuf, buf); 653 1.1 cgd lap = labuf; 654 1.1 cgd } 655 1.1 cgd 656 1.1 cgd static Char lhsb[32]; 657 1.1 cgd static Char slhs[32]; 658 1.1 cgd static Char rhsb[64]; 659 1.1 cgd static int quesarg; 660 1.1 cgd 661 1.1 cgd static void 662 1.19 wiz getexcl(int sc) 663 1.1 cgd { 664 1.10 tls struct wordent *hp, *ip; 665 1.19 wiz int c, dol, left, right; 666 1.1 cgd 667 1.1 cgd if (sc == 0) { 668 1.1 cgd sc = getC(0); 669 1.1 cgd if (sc != '{') { 670 1.1 cgd ungetC(sc); 671 1.1 cgd sc = 0; 672 1.1 cgd } 673 1.1 cgd } 674 1.1 cgd quesarg = -1; 675 1.1 cgd lastev = eventno; 676 1.1 cgd hp = gethent(sc); 677 1.1 cgd if (hp == 0) 678 1.1 cgd return; 679 1.1 cgd hadhist = 1; 680 1.1 cgd dol = 0; 681 1.1 cgd if (hp == alhistp) 682 1.1 cgd for (ip = hp->next->next; ip != alhistt; ip = ip->next) 683 1.1 cgd dol++; 684 1.1 cgd else 685 1.1 cgd for (ip = hp->next->next; ip != hp->prev; ip = ip->next) 686 1.1 cgd dol++; 687 1.1 cgd left = 0, right = dol; 688 1.1 cgd if (sc == HISTSUB) { 689 1.1 cgd ungetC('s'), unreadc(HISTSUB), c = ':'; 690 1.1 cgd goto subst; 691 1.1 cgd } 692 1.1 cgd c = getC(0); 693 1.1 cgd if (!any(":^$*-%", c)) 694 1.1 cgd goto subst; 695 1.1 cgd left = right = -1; 696 1.1 cgd if (c == ':') { 697 1.1 cgd c = getC(0); 698 1.1 cgd unreadc(c); 699 1.1 cgd if (letter(c) || c == '&') { 700 1.1 cgd c = ':'; 701 1.1 cgd left = 0, right = dol; 702 1.1 cgd goto subst; 703 1.1 cgd } 704 1.1 cgd } 705 1.1 cgd else 706 1.1 cgd ungetC(c); 707 1.1 cgd if (!getsel(&left, &right, dol)) 708 1.1 cgd return; 709 1.1 cgd c = getC(0); 710 1.1 cgd if (c == '*') 711 1.1 cgd ungetC(c), c = '-'; 712 1.1 cgd if (c == '-') { 713 1.1 cgd if (!getsel(&left, &right, dol)) 714 1.1 cgd return; 715 1.1 cgd c = getC(0); 716 1.1 cgd } 717 1.1 cgd subst: 718 1.1 cgd exclc = right - left + 1; 719 1.1 cgd while (--left >= 0) 720 1.1 cgd hp = hp->next; 721 1.1 cgd if (sc == HISTSUB || c == ':') { 722 1.1 cgd do { 723 1.1 cgd hp = getsub(hp); 724 1.1 cgd c = getC(0); 725 1.1 cgd } while (c == ':'); 726 1.1 cgd } 727 1.1 cgd unreadc(c); 728 1.1 cgd if (sc == '{') { 729 1.1 cgd c = getC(0); 730 1.1 cgd if (c != '}') 731 1.1 cgd seterror(ERR_BADBANG); 732 1.1 cgd } 733 1.1 cgd exclnxt = hp; 734 1.1 cgd } 735 1.1 cgd 736 1.1 cgd static struct wordent * 737 1.19 wiz getsub(struct wordent *en) 738 1.1 cgd { 739 1.19 wiz Char orhsb[sizeof(rhsb) / sizeof(Char)]; 740 1.10 tls Char *cp; 741 1.19 wiz int c, delim, sc; 742 1.26 christos int global; 743 1.1 cgd 744 1.5 mycroft do { 745 1.5 mycroft exclnxt = 0; 746 1.5 mycroft global = 0; 747 1.5 mycroft sc = c = getC(0); 748 1.5 mycroft if (c == 'g' || c == 'a') { 749 1.5 mycroft global |= (c == 'g') ? 1 : 2; 750 1.5 mycroft sc = c = getC(0); 751 1.5 mycroft } 752 1.5 mycroft if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) { 753 1.5 mycroft global |= (c == 'g') ? 1 : 2; 754 1.5 mycroft sc = c = getC(0); 755 1.5 mycroft } 756 1.1 cgd 757 1.5 mycroft switch (c) { 758 1.5 mycroft case 'p': 759 1.5 mycroft justpr++; 760 1.5 mycroft return (en); 761 1.5 mycroft case 'x': 762 1.5 mycroft case 'q': 763 1.5 mycroft global |= 1; 764 1.13 mycroft /* FALLTHROUGH */ 765 1.5 mycroft case 'h': 766 1.5 mycroft case 'r': 767 1.5 mycroft case 't': 768 1.5 mycroft case 'e': 769 1.5 mycroft break; 770 1.5 mycroft case '&': 771 1.5 mycroft if (slhs[0] == 0) { 772 1.5 mycroft seterror(ERR_NOSUBST); 773 1.5 mycroft return (en); 774 1.5 mycroft } 775 1.5 mycroft (void) Strcpy(lhsb, slhs); 776 1.5 mycroft break; 777 1.1 cgd #ifdef notdef 778 1.5 mycroft case '~': 779 1.5 mycroft if (lhsb[0] == 0) 780 1.5 mycroft goto badlhs; 781 1.5 mycroft break; 782 1.1 cgd #endif 783 1.5 mycroft case 's': 784 1.5 mycroft delim = getC(0); 785 1.5 mycroft if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) { 786 1.5 mycroft unreadc(delim); 787 1.1 cgd lhsb[0] = 0; 788 1.1 cgd seterror(ERR_BADSUBST); 789 1.1 cgd return (en); 790 1.1 cgd } 791 1.5 mycroft cp = lhsb; 792 1.5 mycroft for (;;) { 793 1.1 cgd c = getC(0); 794 1.5 mycroft if (c == '\n') { 795 1.5 mycroft unreadc(c); 796 1.5 mycroft break; 797 1.5 mycroft } 798 1.5 mycroft if (c == delim) 799 1.5 mycroft break; 800 1.5 mycroft if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) { 801 1.5 mycroft lhsb[0] = 0; 802 1.5 mycroft seterror(ERR_BADSUBST); 803 1.5 mycroft return (en); 804 1.5 mycroft } 805 1.5 mycroft if (c == '\\') { 806 1.5 mycroft c = getC(0); 807 1.5 mycroft if (c != delim && c != '\\') 808 1.5 mycroft *cp++ = '\\'; 809 1.5 mycroft } 810 1.30 christos *cp++ = (Char)c; 811 1.1 cgd } 812 1.5 mycroft if (cp != lhsb) 813 1.5 mycroft *cp++ = 0; 814 1.5 mycroft else if (lhsb[0] == 0) { 815 1.5 mycroft seterror(ERR_LHS); 816 1.5 mycroft return (en); 817 1.1 cgd } 818 1.5 mycroft cp = rhsb; 819 1.19 wiz (void)Strcpy(orhsb, cp); 820 1.5 mycroft for (;;) { 821 1.5 mycroft c = getC(0); 822 1.5 mycroft if (c == '\n') { 823 1.5 mycroft unreadc(c); 824 1.5 mycroft break; 825 1.5 mycroft } 826 1.5 mycroft if (c == delim) 827 1.5 mycroft break; 828 1.1 cgd #ifdef notdef 829 1.5 mycroft if (c == '~') { 830 1.5 mycroft if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) / 831 1.5 mycroft sizeof(Char) - 2]) 832 1.5 mycroft goto toorhs; 833 1.19 wiz (void)Strcpy(cp, orhsb); 834 1.5 mycroft cp = Strend(cp); 835 1.5 mycroft continue; 836 1.5 mycroft } 837 1.1 cgd #endif 838 1.5 mycroft if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) { 839 1.5 mycroft seterror(ERR_RHSLONG); 840 1.5 mycroft return (en); 841 1.5 mycroft } 842 1.5 mycroft if (c == '\\') { 843 1.5 mycroft c = getC(0); 844 1.5 mycroft if (c != delim /* && c != '~' */ ) 845 1.5 mycroft *cp++ = '\\'; 846 1.5 mycroft } 847 1.30 christos *cp++ = (Char)c; 848 1.1 cgd } 849 1.5 mycroft *cp++ = 0; 850 1.5 mycroft break; 851 1.5 mycroft default: 852 1.5 mycroft if (c == '\n') 853 1.5 mycroft unreadc(c); 854 1.5 mycroft seterror(ERR_BADBANGMOD, c); 855 1.5 mycroft return (en); 856 1.1 cgd } 857 1.19 wiz (void)Strcpy(slhs, lhsb); 858 1.5 mycroft if (exclc) 859 1.5 mycroft en = dosub(sc, en, global); 860 1.1 cgd } 861 1.5 mycroft while ((c = getC(0)) == ':'); 862 1.5 mycroft unreadc(c); 863 1.1 cgd return (en); 864 1.1 cgd } 865 1.1 cgd 866 1.1 cgd static struct wordent * 867 1.26 christos dosub(int sc, struct wordent *en, int global) 868 1.1 cgd { 869 1.19 wiz struct wordent lexi, *hp, *wdp; 870 1.19 wiz int i; 871 1.26 christos int didone, didsub; 872 1.19 wiz 873 1.19 wiz didone = 0; 874 1.19 wiz didsub = 0; 875 1.19 wiz i = exclc; 876 1.19 wiz hp = &lexi; 877 1.1 cgd 878 1.1 cgd wdp = hp; 879 1.1 cgd while (--i >= 0) { 880 1.35 dholland struct wordent *new = xcalloc(1, sizeof *new); 881 1.1 cgd 882 1.1 cgd new->word = 0; 883 1.1 cgd new->prev = wdp; 884 1.1 cgd new->next = hp; 885 1.1 cgd wdp->next = new; 886 1.1 cgd wdp = new; 887 1.1 cgd en = en->next; 888 1.5 mycroft if (en->word) { 889 1.5 mycroft Char *tword, *otword; 890 1.5 mycroft 891 1.5 mycroft if ((global & 1) || didsub == 0) { 892 1.5 mycroft tword = subword(en->word, sc, &didone); 893 1.5 mycroft if (didone) 894 1.5 mycroft didsub = 1; 895 1.5 mycroft if (global & 2) { 896 1.5 mycroft while (didone && tword != STRNULL) { 897 1.5 mycroft otword = tword; 898 1.5 mycroft tword = subword(otword, sc, &didone); 899 1.5 mycroft if (Strcmp(tword, otword) == 0) { 900 1.33 christos free(otword); 901 1.5 mycroft break; 902 1.5 mycroft } 903 1.5 mycroft else 904 1.33 christos free(otword); 905 1.5 mycroft } 906 1.5 mycroft } 907 1.5 mycroft } 908 1.5 mycroft else 909 1.5 mycroft tword = Strsave(en->word); 910 1.5 mycroft wdp->word = tword; 911 1.5 mycroft } 912 1.1 cgd } 913 1.1 cgd if (didsub == 0) 914 1.1 cgd seterror(ERR_MODFAIL); 915 1.1 cgd hp->prev = wdp; 916 1.1 cgd return (&enthist(-1000, &lexi, 0)->Hlex); 917 1.1 cgd } 918 1.1 cgd 919 1.1 cgd static Char * 920 1.26 christos subword(Char *cp, int type, int *adid) 921 1.1 cgd { 922 1.19 wiz Char wbuf[BUFSIZE]; 923 1.19 wiz Char *mp, *np, *wp; 924 1.30 christos ssize_t i; 925 1.1 cgd 926 1.5 mycroft *adid = 0; 927 1.1 cgd switch (type) { 928 1.1 cgd case 'r': 929 1.1 cgd case 'e': 930 1.1 cgd case 'h': 931 1.1 cgd case 't': 932 1.1 cgd case 'q': 933 1.1 cgd case 'x': 934 1.1 cgd wp = domod(cp, type); 935 1.1 cgd if (wp == 0) 936 1.1 cgd return (Strsave(cp)); 937 1.1 cgd *adid = 1; 938 1.1 cgd return (wp); 939 1.1 cgd default: 940 1.1 cgd wp = wbuf; 941 1.17 christos i = BUFSIZE - 4; 942 1.1 cgd for (mp = cp; *mp; mp++) 943 1.1 cgd if (matchs(mp, lhsb)) { 944 1.1 cgd for (np = cp; np < mp;) 945 1.1 cgd *wp++ = *np++, --i; 946 1.1 cgd for (np = rhsb; *np; np++) 947 1.1 cgd switch (*np) { 948 1.1 cgd case '\\': 949 1.1 cgd if (np[1] == '&') 950 1.1 cgd np++; 951 1.13 mycroft /* FALLTHROUGH */ 952 1.1 cgd default: 953 1.1 cgd if (--i < 0) { 954 1.1 cgd seterror(ERR_SUBOVFL); 955 1.1 cgd return (STRNULL); 956 1.1 cgd } 957 1.1 cgd *wp++ = *np; 958 1.1 cgd continue; 959 1.1 cgd case '&': 960 1.30 christos i -= (ssize_t)Strlen(lhsb); 961 1.1 cgd if (i < 0) { 962 1.1 cgd seterror(ERR_SUBOVFL); 963 1.1 cgd return (STRNULL); 964 1.1 cgd } 965 1.1 cgd *wp = 0; 966 1.1 cgd (void) Strcat(wp, lhsb); 967 1.1 cgd wp = Strend(wp); 968 1.1 cgd continue; 969 1.1 cgd } 970 1.1 cgd mp += Strlen(lhsb); 971 1.30 christos i -= (ssize_t)Strlen(mp); 972 1.1 cgd if (i < 0) { 973 1.1 cgd seterror(ERR_SUBOVFL); 974 1.1 cgd return (STRNULL); 975 1.1 cgd } 976 1.1 cgd *wp = 0; 977 1.1 cgd (void) Strcat(wp, mp); 978 1.1 cgd *adid = 1; 979 1.1 cgd return (Strsave(wbuf)); 980 1.1 cgd } 981 1.1 cgd return (Strsave(cp)); 982 1.1 cgd } 983 1.1 cgd } 984 1.1 cgd 985 1.19 wiz Char * 986 1.19 wiz domod(Char *cp, int type) 987 1.1 cgd { 988 1.10 tls Char *wp, *xp; 989 1.10 tls int c; 990 1.1 cgd 991 1.1 cgd switch (type) { 992 1.1 cgd case 'x': 993 1.1 cgd case 'q': 994 1.1 cgd wp = Strsave(cp); 995 1.5 mycroft for (xp = wp; (c = *xp) != '\0'; xp++) 996 1.1 cgd if ((c != ' ' && c != '\t') || type == 'q') 997 1.1 cgd *xp |= QUOTE; 998 1.1 cgd return (wp); 999 1.38 christos 1000 1.1 cgd case 'h': 1001 1.1 cgd case 't': 1002 1.37 christos wp = Strrchr(cp, '/'); 1003 1.37 christos if (wp == NULL) 1004 1.37 christos return Strsave(type == 't' ? cp : STRNULL); 1005 1.37 christos if (type == 't') 1006 1.37 christos xp = Strsave(wp + 1); 1007 1.37 christos else 1008 1.1 cgd xp = Strsave(cp), xp[wp - cp] = 0; 1009 1.1 cgd return (xp); 1010 1.37 christos 1011 1.1 cgd case 'e': 1012 1.1 cgd case 'r': 1013 1.38 christos wp = Strend(cp); 1014 1.38 christos for (wp--; wp >= cp && *wp != '/'; wp--) 1015 1.38 christos if (*wp == '.') { 1016 1.38 christos if (type == 'e') 1017 1.38 christos xp = Strsave(wp + 1); 1018 1.38 christos else 1019 1.38 christos xp = Strsave(cp), xp[wp - cp] = 0; 1020 1.38 christos return (xp); 1021 1.38 christos } 1022 1.38 christos return (Strsave(type == 'e' ? STRNULL : cp)); 1023 1.37 christos 1024 1.5 mycroft default: 1025 1.5 mycroft break; 1026 1.1 cgd } 1027 1.1 cgd return (0); 1028 1.1 cgd } 1029 1.1 cgd 1030 1.1 cgd static int 1031 1.19 wiz matchs(Char *str, Char *pat) 1032 1.1 cgd { 1033 1.1 cgd while (*str && *pat && *str == *pat) 1034 1.1 cgd str++, pat++; 1035 1.1 cgd return (*pat == 0); 1036 1.1 cgd } 1037 1.1 cgd 1038 1.1 cgd static int 1039 1.19 wiz getsel(int *al, int *ar, int dol) 1040 1.1 cgd { 1041 1.19 wiz int c, i; 1042 1.26 christos int first; 1043 1.19 wiz 1044 1.19 wiz c = getC(0); 1045 1.19 wiz first = *al < 0; 1046 1.1 cgd 1047 1.1 cgd switch (c) { 1048 1.1 cgd case '%': 1049 1.1 cgd if (quesarg == -1) { 1050 1.1 cgd seterror(ERR_BADBANGARG); 1051 1.1 cgd return (0); 1052 1.1 cgd } 1053 1.1 cgd if (*al < 0) 1054 1.1 cgd *al = quesarg; 1055 1.1 cgd *ar = quesarg; 1056 1.1 cgd break; 1057 1.1 cgd case '-': 1058 1.1 cgd if (*al < 0) { 1059 1.1 cgd *al = 0; 1060 1.1 cgd *ar = dol - 1; 1061 1.1 cgd unreadc(c); 1062 1.1 cgd } 1063 1.1 cgd return (1); 1064 1.1 cgd case '^': 1065 1.1 cgd if (*al < 0) 1066 1.1 cgd *al = 1; 1067 1.1 cgd *ar = 1; 1068 1.1 cgd break; 1069 1.1 cgd case '$': 1070 1.1 cgd if (*al < 0) 1071 1.1 cgd *al = dol; 1072 1.1 cgd *ar = dol; 1073 1.1 cgd break; 1074 1.1 cgd case '*': 1075 1.1 cgd if (*al < 0) 1076 1.1 cgd *al = 1; 1077 1.1 cgd *ar = dol; 1078 1.1 cgd if (*ar < *al) { 1079 1.1 cgd *ar = 0; 1080 1.1 cgd *al = 1; 1081 1.1 cgd return (1); 1082 1.1 cgd } 1083 1.1 cgd break; 1084 1.1 cgd default: 1085 1.1 cgd if (Isdigit(c)) { 1086 1.1 cgd i = 0; 1087 1.1 cgd while (Isdigit(c)) { 1088 1.1 cgd i = i * 10 + c - '0'; 1089 1.1 cgd c = getC(0); 1090 1.1 cgd } 1091 1.1 cgd if (i < 0) 1092 1.1 cgd i = dol + 1; 1093 1.1 cgd if (*al < 0) 1094 1.1 cgd *al = i; 1095 1.1 cgd *ar = i; 1096 1.1 cgd } 1097 1.1 cgd else if (*al < 0) 1098 1.1 cgd *al = 0, *ar = dol; 1099 1.1 cgd else 1100 1.1 cgd *ar = dol - 1; 1101 1.1 cgd unreadc(c); 1102 1.1 cgd break; 1103 1.1 cgd } 1104 1.1 cgd if (first) { 1105 1.1 cgd c = getC(0); 1106 1.1 cgd unreadc(c); 1107 1.1 cgd if (any("-$*", c)) 1108 1.1 cgd return (1); 1109 1.1 cgd } 1110 1.1 cgd if (*al > *ar || *ar > dol) { 1111 1.1 cgd seterror(ERR_BADBANGARG); 1112 1.1 cgd return (0); 1113 1.1 cgd } 1114 1.1 cgd return (1); 1115 1.1 cgd 1116 1.1 cgd } 1117 1.1 cgd 1118 1.1 cgd static struct wordent * 1119 1.19 wiz gethent(int sc) 1120 1.1 cgd { 1121 1.10 tls struct Hist *hp; 1122 1.10 tls Char *np; 1123 1.23 christos char *str; 1124 1.19 wiz int c, event; 1125 1.26 christos int back; 1126 1.1 cgd 1127 1.19 wiz back = 0; 1128 1.1 cgd c = sc == HISTSUB ? HIST : getC(0); 1129 1.1 cgd if (c == HIST) { 1130 1.1 cgd if (alhistp) 1131 1.1 cgd return (alhistp); 1132 1.1 cgd event = eventno; 1133 1.1 cgd } 1134 1.1 cgd else 1135 1.1 cgd switch (c) { 1136 1.1 cgd case ':': 1137 1.1 cgd case '^': 1138 1.1 cgd case '$': 1139 1.1 cgd case '*': 1140 1.1 cgd case '%': 1141 1.1 cgd ungetC(c); 1142 1.1 cgd if (lastev == eventno && alhistp) 1143 1.1 cgd return (alhistp); 1144 1.1 cgd event = lastev; 1145 1.1 cgd break; 1146 1.1 cgd case '#': /* !# is command being typed in (mrh) */ 1147 1.1 cgd if (--hleft == 0) { 1148 1.1 cgd seterror(ERR_HISTLOOP); 1149 1.1 cgd return (0); 1150 1.1 cgd } 1151 1.1 cgd else 1152 1.1 cgd return (¶ml); 1153 1.1 cgd /* NOTREACHED */ 1154 1.1 cgd case '-': 1155 1.1 cgd back = 1; 1156 1.1 cgd c = getC(0); 1157 1.13 mycroft /* FALLTHROUGH */ 1158 1.1 cgd default: 1159 1.1 cgd if (any("(=~", c)) { 1160 1.1 cgd unreadc(c); 1161 1.1 cgd ungetC(HIST); 1162 1.1 cgd return (0); 1163 1.1 cgd } 1164 1.1 cgd np = lhsb; 1165 1.1 cgd event = 0; 1166 1.5 mycroft while (!cmap(c, _ESC | _META | _QF | _QB) && !any("${}:", c)) { 1167 1.1 cgd if (event != -1 && Isdigit(c)) 1168 1.1 cgd event = event * 10 + c - '0'; 1169 1.1 cgd else 1170 1.1 cgd event = -1; 1171 1.1 cgd if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 1172 1.30 christos *np++ = (Char)c; 1173 1.1 cgd c = getC(0); 1174 1.1 cgd } 1175 1.1 cgd unreadc(c); 1176 1.1 cgd if (np == lhsb) { 1177 1.1 cgd ungetC(HIST); 1178 1.1 cgd return (0); 1179 1.1 cgd } 1180 1.1 cgd *np++ = 0; 1181 1.1 cgd if (event != -1) { 1182 1.1 cgd /* 1183 1.1 cgd * History had only digits 1184 1.1 cgd */ 1185 1.1 cgd if (back) 1186 1.1 cgd event = eventno + (alhistp == 0) - (event ? event : 0); 1187 1.1 cgd break; 1188 1.1 cgd } 1189 1.1 cgd hp = findev(lhsb, 0); 1190 1.1 cgd if (hp) 1191 1.1 cgd lastev = hp->Hnum; 1192 1.1 cgd return (&hp->Hlex); 1193 1.1 cgd case '?': 1194 1.1 cgd np = lhsb; 1195 1.1 cgd for (;;) { 1196 1.1 cgd c = getC(0); 1197 1.1 cgd if (c == '\n') { 1198 1.1 cgd unreadc(c); 1199 1.1 cgd break; 1200 1.1 cgd } 1201 1.1 cgd if (c == '?') 1202 1.1 cgd break; 1203 1.1 cgd if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 1204 1.30 christos *np++ = (Char)c; 1205 1.1 cgd } 1206 1.1 cgd if (np == lhsb) { 1207 1.1 cgd if (lhsb[0] == 0) { 1208 1.1 cgd seterror(ERR_NOSEARCH); 1209 1.1 cgd return (0); 1210 1.1 cgd } 1211 1.1 cgd } 1212 1.1 cgd else 1213 1.1 cgd *np++ = 0; 1214 1.1 cgd hp = findev(lhsb, 1); 1215 1.1 cgd if (hp) 1216 1.1 cgd lastev = hp->Hnum; 1217 1.1 cgd return (&hp->Hlex); 1218 1.1 cgd } 1219 1.1 cgd 1220 1.1 cgd for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 1221 1.1 cgd if (hp->Hnum == event) { 1222 1.1 cgd hp->Href = eventno; 1223 1.1 cgd lastev = hp->Hnum; 1224 1.1 cgd return (&hp->Hlex); 1225 1.1 cgd } 1226 1.1 cgd np = putn(event); 1227 1.23 christos str = vis_str(np); 1228 1.33 christos free(np); 1229 1.23 christos seterror(ERR_NOEVENT, str); 1230 1.1 cgd return (0); 1231 1.1 cgd } 1232 1.1 cgd 1233 1.1 cgd static struct Hist * 1234 1.26 christos findev(Char *cp, int anyarg) 1235 1.1 cgd { 1236 1.10 tls struct Hist *hp; 1237 1.1 cgd 1238 1.1 cgd for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 1239 1.19 wiz Char *dp, *p, *q; 1240 1.19 wiz struct wordent *lp; 1241 1.19 wiz int argno; 1242 1.19 wiz 1243 1.19 wiz lp = hp->Hlex.next; 1244 1.19 wiz argno = 0; 1245 1.1 cgd 1246 1.1 cgd /* 1247 1.1 cgd * The entries added by alias substitution don't have a newline but do 1248 1.1 cgd * have a negative event number. Savehist() trims off these entries, 1249 1.1 cgd * but it happens before alias expansion, too early to delete those 1250 1.1 cgd * from the previous command. 1251 1.1 cgd */ 1252 1.1 cgd if (hp->Hnum < 0) 1253 1.1 cgd continue; 1254 1.1 cgd if (lp->word[0] == '\n') 1255 1.1 cgd continue; 1256 1.1 cgd if (!anyarg) { 1257 1.1 cgd p = cp; 1258 1.1 cgd q = lp->word; 1259 1.1 cgd do 1260 1.1 cgd if (!*p) 1261 1.1 cgd return (hp); 1262 1.1 cgd while (*p++ == *q++); 1263 1.1 cgd continue; 1264 1.1 cgd } 1265 1.1 cgd do { 1266 1.1 cgd for (dp = lp->word; *dp; dp++) { 1267 1.1 cgd p = cp; 1268 1.1 cgd q = dp; 1269 1.1 cgd do 1270 1.1 cgd if (!*p) { 1271 1.1 cgd quesarg = argno; 1272 1.1 cgd return (hp); 1273 1.1 cgd } 1274 1.1 cgd while (*p++ == *q++); 1275 1.1 cgd } 1276 1.1 cgd lp = lp->next; 1277 1.1 cgd argno++; 1278 1.1 cgd } while (lp->word[0] != '\n'); 1279 1.1 cgd } 1280 1.5 mycroft seterror(ERR_NOEVENT, vis_str(cp)); 1281 1.1 cgd return (0); 1282 1.1 cgd } 1283 1.1 cgd 1284 1.1 cgd 1285 1.1 cgd static void 1286 1.19 wiz setexclp(Char *cp) 1287 1.1 cgd { 1288 1.1 cgd if (cp && cp[0] == '\n') 1289 1.1 cgd return; 1290 1.1 cgd exclp = cp; 1291 1.1 cgd } 1292 1.1 cgd 1293 1.1 cgd void 1294 1.19 wiz unreadc(int c) 1295 1.1 cgd { 1296 1.1 cgd peekread = c; 1297 1.1 cgd } 1298 1.1 cgd 1299 1.1 cgd int 1300 1.26 christos readc(int wanteof) 1301 1.1 cgd { 1302 1.19 wiz static int sincereal; 1303 1.10 tls int c; 1304 1.1 cgd 1305 1.5 mycroft aret = F_SEEK; 1306 1.5 mycroft if ((c = peekread) != '\0') { 1307 1.1 cgd peekread = 0; 1308 1.1 cgd return (c); 1309 1.1 cgd } 1310 1.1 cgd top: 1311 1.5 mycroft aret = F_SEEK; 1312 1.1 cgd if (alvecp) { 1313 1.5 mycroft aret = A_SEEK; 1314 1.5 mycroft if ((c = *alvecp++) != '\0') 1315 1.1 cgd return (c); 1316 1.5 mycroft if (alvec && *alvec) { 1317 1.5 mycroft alvecp = *alvec++; 1318 1.5 mycroft return (' '); 1319 1.5 mycroft } 1320 1.5 mycroft else { 1321 1.5 mycroft aret = F_SEEK; 1322 1.5 mycroft alvecp = NULL; 1323 1.5 mycroft return('\n'); 1324 1.1 cgd } 1325 1.1 cgd } 1326 1.1 cgd if (alvec) { 1327 1.34 mrg if ((alvecp = *alvec) != NULL) { 1328 1.1 cgd alvec++; 1329 1.1 cgd goto top; 1330 1.1 cgd } 1331 1.1 cgd /* Infinite source! */ 1332 1.1 cgd return ('\n'); 1333 1.1 cgd } 1334 1.1 cgd if (evalp) { 1335 1.5 mycroft aret = E_SEEK; 1336 1.5 mycroft if ((c = *evalp++) != '\0') 1337 1.1 cgd return (c); 1338 1.5 mycroft if (evalvec && *evalvec) { 1339 1.1 cgd evalp = *evalvec++; 1340 1.1 cgd return (' '); 1341 1.1 cgd } 1342 1.5 mycroft aret = F_SEEK; 1343 1.1 cgd evalp = 0; 1344 1.1 cgd } 1345 1.1 cgd if (evalvec) { 1346 1.1 cgd if (evalvec == (Char **) 1) { 1347 1.1 cgd doneinp = 1; 1348 1.1 cgd reset(); 1349 1.1 cgd } 1350 1.34 mrg if ((evalp = *evalvec) != NULL) { 1351 1.1 cgd evalvec++; 1352 1.1 cgd goto top; 1353 1.1 cgd } 1354 1.1 cgd evalvec = (Char **) 1; 1355 1.1 cgd return ('\n'); 1356 1.1 cgd } 1357 1.1 cgd do { 1358 1.1 cgd if (arginp == (Char *) 1 || onelflg == 1) { 1359 1.1 cgd if (wanteof) 1360 1.1 cgd return (-1); 1361 1.1 cgd exitstat(); 1362 1.1 cgd } 1363 1.1 cgd if (arginp) { 1364 1.1 cgd if ((c = *arginp++) == 0) { 1365 1.1 cgd arginp = (Char *) 1; 1366 1.1 cgd return ('\n'); 1367 1.1 cgd } 1368 1.1 cgd return (c); 1369 1.1 cgd } 1370 1.1 cgd reread: 1371 1.1 cgd c = bgetc(); 1372 1.1 cgd if (c < 0) { 1373 1.1 cgd struct termios tty; 1374 1.1 cgd if (wanteof) 1375 1.1 cgd return (-1); 1376 1.1 cgd /* was isatty but raw with ignoreeof yields problems */ 1377 1.1 cgd if (tcgetattr(SHIN, &tty) == 0 && (tty.c_lflag & ICANON)) 1378 1.1 cgd { 1379 1.1 cgd /* was 'short' for FILEC */ 1380 1.8 mycroft pid_t ctpgrp; 1381 1.1 cgd 1382 1.1 cgd if (++sincereal > 25) 1383 1.1 cgd goto oops; 1384 1.1 cgd if (tpgrp != -1 && 1385 1.1 cgd (ctpgrp = tcgetpgrp(FSHTTY)) != -1 && 1386 1.1 cgd tpgrp != ctpgrp) { 1387 1.19 wiz (void)tcsetpgrp(FSHTTY, tpgrp); 1388 1.19 wiz (void)kill(-ctpgrp, SIGHUP); 1389 1.19 wiz (void)fprintf(csherr, "Reset tty pgrp from %ld to %ld\n", 1390 1.16 christos (long)ctpgrp, (long)tpgrp); 1391 1.1 cgd goto reread; 1392 1.1 cgd } 1393 1.1 cgd if (adrof(STRignoreeof)) { 1394 1.1 cgd if (loginsh) 1395 1.19 wiz (void)fprintf(csherr,"\nUse \"logout\" to logout.\n"); 1396 1.1 cgd else 1397 1.19 wiz (void)fprintf(csherr,"\nUse \"exit\" to leave csh.\n"); 1398 1.1 cgd reset(); 1399 1.1 cgd } 1400 1.1 cgd if (chkstop == 0) 1401 1.1 cgd panystop(1); 1402 1.1 cgd } 1403 1.1 cgd oops: 1404 1.1 cgd doneinp = 1; 1405 1.1 cgd reset(); 1406 1.1 cgd } 1407 1.1 cgd sincereal = 0; 1408 1.1 cgd if (c == '\n' && onelflg) 1409 1.1 cgd onelflg--; 1410 1.1 cgd } while (c == 0); 1411 1.1 cgd return (c); 1412 1.1 cgd } 1413 1.1 cgd 1414 1.1 cgd static int 1415 1.19 wiz bgetc(void) 1416 1.1 cgd { 1417 1.1 cgd #ifdef FILEC 1418 1.19 wiz char tbuf[BUFSIZE + 1]; 1419 1.19 wiz Char ttyline[BUFSIZE]; 1420 1.30 christos int buf, off; 1421 1.30 christos ssize_t c, numleft, roomleft; 1422 1.19 wiz 1423 1.19 wiz numleft = 0; 1424 1.19 wiz #else /* FILEC */ 1425 1.19 wiz char tbuf[BUFSIZE + 1]; 1426 1.19 wiz int c, buf, off; 1427 1.19 wiz #endif /* !FILEC */ 1428 1.1 cgd 1429 1.1 cgd if (cantell) { 1430 1.1 cgd if (fseekp < fbobp || fseekp > feobp) { 1431 1.1 cgd fbobp = feobp = fseekp; 1432 1.19 wiz (void)lseek(SHIN, fseekp, SEEK_SET); 1433 1.1 cgd } 1434 1.1 cgd if (fseekp == feobp) { 1435 1.19 wiz int i; 1436 1.1 cgd 1437 1.1 cgd fbobp = feobp; 1438 1.1 cgd do 1439 1.17 christos c = read(SHIN, tbuf, BUFSIZE); 1440 1.1 cgd while (c < 0 && errno == EINTR); 1441 1.1 cgd if (c <= 0) 1442 1.1 cgd return (-1); 1443 1.1 cgd for (i = 0; i < c; i++) 1444 1.1 cgd fbuf[0][i] = (unsigned char) tbuf[i]; 1445 1.1 cgd feobp += c; 1446 1.1 cgd } 1447 1.1 cgd c = fbuf[0][fseekp - fbobp]; 1448 1.1 cgd fseekp++; 1449 1.30 christos return (int)(c); 1450 1.1 cgd } 1451 1.1 cgd 1452 1.1 cgd again: 1453 1.17 christos buf = (int) fseekp / BUFSIZE; 1454 1.1 cgd if (buf >= fblocks) { 1455 1.19 wiz Char **nfbuf; 1456 1.1 cgd 1457 1.36 dholland /* XXX the cast is needed because fblocks is signed */ 1458 1.36 dholland nfbuf = xcalloc((size_t)(fblocks + 2), sizeof(*nfbuf)); 1459 1.1 cgd if (fbuf) { 1460 1.19 wiz (void)blkcpy(nfbuf, fbuf); 1461 1.33 christos free(fbuf); 1462 1.1 cgd } 1463 1.1 cgd fbuf = nfbuf; 1464 1.35 dholland fbuf[fblocks] = xcalloc(BUFSIZE, sizeof(Char)); 1465 1.1 cgd fblocks++; 1466 1.1 cgd if (!intty) 1467 1.1 cgd goto again; 1468 1.1 cgd } 1469 1.1 cgd if (fseekp >= feobp) { 1470 1.17 christos buf = (int) feobp / BUFSIZE; 1471 1.17 christos off = (int) feobp % BUFSIZE; 1472 1.17 christos roomleft = BUFSIZE - off; 1473 1.1 cgd 1474 1.1 cgd #ifdef FILEC 1475 1.1 cgd for (;;) { 1476 1.28 christos if ((editing || filec) && intty) { 1477 1.28 christos #ifdef EDIT 1478 1.28 christos if (editing) { 1479 1.28 christos const char *p; 1480 1.30 christos int d; 1481 1.30 christos if ((p = el_gets(el, &d)) != NULL) { 1482 1.28 christos size_t i; 1483 1.28 christos /* XXX: Truncation */ 1484 1.30 christos numleft = d > BUFSIZE ? BUFSIZE : d; 1485 1.28 christos for (i = 0; *p && i < BUFSIZE; i++, p++) 1486 1.28 christos ttyline[i] = *p; 1487 1.28 christos ttyline[i - (i == BUFSIZE)] = '\0'; 1488 1.28 christos } 1489 1.28 christos } 1490 1.28 christos #endif 1491 1.17 christos c = numleft ? numleft : tenex(ttyline, BUFSIZE); 1492 1.1 cgd if (c > roomleft) { 1493 1.1 cgd /* start with fresh buffer */ 1494 1.17 christos feobp = fseekp = fblocks * BUFSIZE; 1495 1.1 cgd numleft = c; 1496 1.1 cgd goto again; 1497 1.1 cgd } 1498 1.1 cgd if (c > 0) 1499 1.30 christos (void)memcpy(fbuf[buf] + off, ttyline, 1500 1.31 christos (size_t)c * sizeof(**fbuf)); 1501 1.1 cgd numleft = 0; 1502 1.1 cgd } 1503 1.1 cgd else { 1504 1.1 cgd #endif 1505 1.30 christos c = read(SHIN, tbuf, (size_t)roomleft); 1506 1.1 cgd if (c > 0) { 1507 1.1 cgd int i; 1508 1.1 cgd Char *ptr = fbuf[buf] + off; 1509 1.1 cgd 1510 1.1 cgd for (i = 0; i < c; i++) 1511 1.1 cgd ptr[i] = (unsigned char) tbuf[i]; 1512 1.1 cgd } 1513 1.1 cgd #ifdef FILEC 1514 1.1 cgd } 1515 1.1 cgd #endif 1516 1.1 cgd if (c >= 0) 1517 1.1 cgd break; 1518 1.1 cgd if (errno == EWOULDBLOCK) { 1519 1.20 lukem int iooff = 0; 1520 1.1 cgd 1521 1.20 lukem (void)ioctl(SHIN, FIONBIO, (ioctl_t) & iooff); 1522 1.1 cgd } 1523 1.1 cgd else if (errno != EINTR) 1524 1.1 cgd break; 1525 1.27 wiz #ifdef FILEC 1526 1.1 cgd } 1527 1.27 wiz #endif 1528 1.1 cgd if (c <= 0) 1529 1.1 cgd return (-1); 1530 1.1 cgd feobp += c; 1531 1.1 cgd #ifndef FILEC 1532 1.1 cgd goto again; 1533 1.1 cgd #else 1534 1.1 cgd if (filec && !intty) 1535 1.1 cgd goto again; 1536 1.1 cgd #endif 1537 1.1 cgd } 1538 1.19 wiz c = fbuf[buf][(int)fseekp % BUFSIZE]; 1539 1.1 cgd fseekp++; 1540 1.30 christos return (int)(c); 1541 1.1 cgd } 1542 1.1 cgd 1543 1.1 cgd static void 1544 1.19 wiz bfree(void) 1545 1.1 cgd { 1546 1.19 wiz int i, sb; 1547 1.1 cgd 1548 1.1 cgd if (cantell) 1549 1.1 cgd return; 1550 1.1 cgd if (whyles) 1551 1.1 cgd return; 1552 1.19 wiz sb = (int)(fseekp - 1) / BUFSIZE; 1553 1.1 cgd if (sb > 0) { 1554 1.1 cgd for (i = 0; i < sb; i++) 1555 1.33 christos free(fbuf[i]); 1556 1.19 wiz (void)blkcpy(fbuf, &fbuf[sb]); 1557 1.17 christos fseekp -= BUFSIZE * sb; 1558 1.17 christos feobp -= BUFSIZE * sb; 1559 1.1 cgd fblocks -= sb; 1560 1.1 cgd } 1561 1.1 cgd } 1562 1.1 cgd 1563 1.1 cgd void 1564 1.19 wiz bseek(struct Ain *l) 1565 1.5 mycroft { 1566 1.5 mycroft switch (aret = l->type) { 1567 1.19 wiz case A_SEEK: 1568 1.19 wiz alvec = l->a_seek; 1569 1.19 wiz alvecp = l->c_seek; 1570 1.19 wiz return; 1571 1.5 mycroft case E_SEEK: 1572 1.5 mycroft evalvec = l->a_seek; 1573 1.5 mycroft evalp = l->c_seek; 1574 1.5 mycroft return; 1575 1.5 mycroft case F_SEEK: 1576 1.5 mycroft fseekp = l->f_seek; 1577 1.5 mycroft return; 1578 1.5 mycroft default: 1579 1.19 wiz (void)fprintf(csherr, "Bad seek type %d\n", aret); 1580 1.5 mycroft abort(); 1581 1.5 mycroft } 1582 1.5 mycroft } 1583 1.1 cgd 1584 1.5 mycroft void 1585 1.19 wiz btell(struct Ain *l) 1586 1.1 cgd { 1587 1.5 mycroft switch (l->type = aret) { 1588 1.19 wiz case A_SEEK: 1589 1.19 wiz l->a_seek = alvec; 1590 1.19 wiz l->c_seek = alvecp; 1591 1.19 wiz return; 1592 1.5 mycroft case E_SEEK: 1593 1.5 mycroft l->a_seek = evalvec; 1594 1.5 mycroft l->c_seek = evalp; 1595 1.5 mycroft return; 1596 1.5 mycroft case F_SEEK: 1597 1.5 mycroft l->f_seek = fseekp; 1598 1.5 mycroft l->a_seek = NULL; 1599 1.5 mycroft return; 1600 1.5 mycroft default: 1601 1.19 wiz (void)fprintf(csherr, "Bad seek type %d\n", aret); 1602 1.5 mycroft abort(); 1603 1.1 cgd } 1604 1.1 cgd } 1605 1.1 cgd 1606 1.1 cgd void 1607 1.19 wiz btoeof(void) 1608 1.1 cgd { 1609 1.19 wiz (void)lseek(SHIN, (off_t) 0, SEEK_END); 1610 1.5 mycroft aret = F_SEEK; 1611 1.1 cgd fseekp = feobp; 1612 1.5 mycroft alvec = NULL; 1613 1.5 mycroft alvecp = NULL; 1614 1.5 mycroft evalvec = NULL; 1615 1.5 mycroft evalp = NULL; 1616 1.1 cgd wfree(); 1617 1.1 cgd bfree(); 1618 1.1 cgd } 1619 1.1 cgd 1620 1.1 cgd void 1621 1.19 wiz settell(void) 1622 1.1 cgd { 1623 1.1 cgd cantell = 0; 1624 1.1 cgd if (arginp || onelflg || intty) 1625 1.1 cgd return; 1626 1.9 jtc if (lseek(SHIN, (off_t) 0, SEEK_CUR) < 0 || errno == ESPIPE) 1627 1.1 cgd return; 1628 1.36 dholland fbuf = xcalloc(2, sizeof(*fbuf)); 1629 1.1 cgd fblocks = 1; 1630 1.35 dholland fbuf[0] = xcalloc(BUFSIZE, sizeof(Char)); 1631 1.9 jtc fseekp = fbobp = feobp = lseek(SHIN, (off_t) 0, SEEK_CUR); 1632 1.1 cgd cantell = 1; 1633 1.1 cgd } 1634