1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
|
/*
* input.c - read and store lines of input
*
* This file is part of zsh, the Z shell.
*
* Copyright (c) 1992-1997 Paul Falstad
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and to distribute modified versions of this software for any
* purpose, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* In no event shall Paul Falstad or the Zsh Development Group be liable
* to any party for direct, indirect, special, incidental, or consequential
* damages arising out of the use of this software and its documentation,
* even if Paul Falstad and the Zsh Development Group have been advised of
* the possibility of such damage.
*
* Paul Falstad and the Zsh Development Group specifically disclaim any
* warranties, including, but not limited to, the implied warranties of
* merchantability and fitness for a particular purpose. The software
* provided hereunder is on an "as is" basis, and Paul Falstad and the
* Zsh Development Group have no obligation to provide maintenance,
* support, updates, enhancements, or modifications.
*
*/
/*
* This file deals with input buffering, supplying characters to the
* history expansion code a character at a time. Input is stored on a
* stack, which allows insertion of strings into the input, possibly with
* flags marking the end of alias expansion, with minimal copying of
* strings. The same stack is used to record the fact that the input
* is a history or alias expansion and to store the alias while it is in use.
*
* Input is taken either from zle, if appropriate, or read directly from
* the input file, or may be supplied by some other part of the shell (such
* as `eval' or $(...) substitution). In the last case, it should be
* supplied by pushing a new level onto the stack, via inpush(input_string,
* flag, alias); if the current input really needs to be altered, use
* inputsetline(input_string, flag). `Flag' can include or's of INP_FREE
* (if the input string is to be freed when used), INP_CONT (if the input
* is to continue onto what's already in the input queue), INP_ALIAS
* (push supplied alias onto stack) or INP_HIST (ditto, but used to
* mark history expansion). `alias' is ignored unless INP_ALIAS or
* INP_HIST is supplied. INP_ALIAS is always set if INP_HIST is.
*
* Note that the input string is itself used as the input buffer: it is not
* copied, nor is it every written back to, so using a constant string
* should work. Consequently, when passing areas of memory from the heap
* it is necessary that that heap last as long as the operation of reading
* the string. After the string is read, the stack should be popped with
* inpop(), which effectively flushes any unread input as well as restoring
* the previous input state.
*
* The internal flag INP_ALCONT shows that the stack element was pushed
* by an alias expansion; it should not be needed elsewhere.
*
* The global variable inalmore is set to indicate aliases should
* continue to be expanded because the last alias expansion ended
* in a space. It is only reset after a complete word was read
* without expanding a new alias, in exalias().
*
* PWS 1996/12/10
*/
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#include "zsh.mdh"
#include "input.pro"
/* the shell input fd */
/**/
int SHIN;
/* buffered shell input for non-interactive shells */
/**/
FILE *bshin;
/* != 0 means we are reading input from a string */
/**/
int strin;
/* total # of characters waiting to be read. */
/**/
mod_export int inbufct;
/* the flags controlling the input routines in input.c: see INP_* in zsh.h */
/**/
int inbufflags;
static char *inbuf; /* Current input buffer */
static char *inbufptr; /* Pointer into input buffer */
static char *inbufpush; /* Character at which to re-push alias */
static int inbufleft; /* Characters left in current input
stack element */
/* Input must be stacked since the input queue is used by
* various different parts of the shell.
*/
struct instacks {
char *buf, *bufptr;
Alias alias;
int bufleft, bufct, flags;
};
static struct instacks *instack, *instacktop;
/*
* Input stack size. We need to push the stack for aliases, history
* expansion, and reading from internal strings: only if these operations
* are nested do we need more than one extra level. Thus we shouldn't need
* too much space as a rule. Initially, INSTACK_INITIAL is allocated; if
* more is required, an extra INSTACK_EXPAND is added each time.
*/
#define INSTACK_INITIAL 4
#define INSTACK_EXPAND 4
static int instacksz = INSTACK_INITIAL;
/* Read a line from bshin. Convert tokens and *
* null characters to Meta c^32 character pairs. */
/**/
mod_export char *
shingetline(void)
{
char *line = NULL;
int ll = 0;
int c;
char buf[BUFSIZ];
char *p;
p = buf;
for (;;) {
do {
errno = 0;
c = fgetc(bshin);
} while (c < 0 && errno == EINTR);
if (c < 0 || c == '\n') {
if (c == '\n')
*p++ = '\n';
if (p > buf) {
*p++ = '\0';
line = zrealloc(line, ll + (p - buf));
memcpy(line + ll, buf, p - buf);
}
return line;
}
if (imeta(c)) {
*p++ = Meta;
*p++ = c ^ 32;
} else
*p++ = c;
if (p >= buf + BUFSIZ - 1) {
line = zrealloc(line, ll + (p - buf) + 1);
memcpy(line + ll, buf, p - buf);
ll += p - buf;
line[ll] = '\0';
p = buf;
}
}
}
/* Get the next character from the input.
* Will call inputline() to get a new line where necessary.
*/
/**/
int
ingetc(void)
{
int lastc;
if (lexstop)
return ' ';
for (;;) {
if (inbufleft) {
inbufleft--;
inbufct--;
if (itok(lastc = STOUC(*inbufptr++)))
continue;
if (((inbufflags & INP_LINENO) || !strin) && lastc == '\n')
lineno++;
return lastc;
}
/* If the next element down the input stack is a continuation of
* this, use it.
*/
if (inbufflags & INP_CONT) {
inpoptop();
continue;
}
/*
* Otherwise, see if we have reached the end of input
* (due to an error, or to reading from a single string).
*/
if (strin || errflag) {
lexstop = 1;
return ' ';
}
/* As a last resort, get some more input */
if (inputline())
return ' ';
}
}
/* Read a line from the current command stream and store it as input */
/**/
static int
inputline(void)
{
char *ingetcline, *ingetcpmptl = NULL, *ingetcpmptr = NULL;
/* If reading code interactively, work out the prompts. */
if (interact && isset(SHINSTDIN)) {
if (!isfirstln) {
ingetcpmptl = prompt2;
if (rprompt2)
ingetcpmptr = rprompt2;
}
else {
ingetcpmptl = prompt;
if (rprompt)
ingetcpmptr = rprompt;
}
}
if (!(interact && isset(SHINSTDIN) && SHTTY != -1 && isset(USEZLE))) {
/*
* If not using zle, read the line straight from the input file.
* Possibly we don't get the whole line at once: in that case,
* we get another chunk with the next call to inputline().
*/
if (interact && isset(SHINSTDIN)) {
/*
* We may still be interactive (e.g. running under emacs),
* so output a prompt if necessary. We don't know enough
* about the input device to be able to handle an rprompt,
* though.
*/
char *pptbuf;
int pptlen;
pptbuf = unmetafy(promptexpand(ingetcpmptl, 0, NULL, NULL), &pptlen);
write(2, (WRITE_ARG_2_T)pptbuf, pptlen);
free(pptbuf);
}
ingetcline = shingetline();
} else {
/*
* Since we may have to read multiple lines before getting
* a complete piece of input, we tell zle not to restore the
* original tty settings after reading each chunk. Instead,
* this is done when the history mechanism for the current input
* terminates, which is not until we have the whole input.
* This is supposed to minimise problems on systems that clobber
* typeahead when the terminal settings are altered.
* pws 1998/03/12
*/
ingetcline = (char *)zleread(ingetcpmptl, ingetcpmptr,
ZLRF_HISTORY|ZLRF_NOSETTY);
histdone |= HISTFLAG_SETTY;
}
if (!ingetcline) {
return lexstop = 1;
}
if (errflag) {
free(ingetcline);
return lexstop = errflag = 1;
}
if (isset(VERBOSE)) {
/* Output the whole line read so far. */
zputs(ingetcline, stderr);
fflush(stderr);
}
if (*ingetcline && ingetcline[strlen(ingetcline) - 1] == '\n' &&
interact && isset(SUNKEYBOARDHACK) && isset(SHINSTDIN) &&
SHTTY != -1 && *ingetcline && ingetcline[1] &&
ingetcline[strlen(ingetcline) - 2] == '`') {
/* Junk an unmatched "`" at the end of the line. */
int ct;
char *ptr;
for (ct = 0, ptr = ingetcline; *ptr; ptr++)
if (*ptr == '`')
ct++;
if (ct & 1) {
ptr[-2] = '\n';
ptr[-1] = '\0';
}
}
isfirstch = 1;
/* Put this into the input channel. */
inputsetline(ingetcline, INP_FREE);
return 0;
}
/*
* Put a string in the input queue:
* inbuf is only freeable if the flags include INP_FREE.
*/
/**/
static void
inputsetline(char *str, int flags)
{
if ((inbufflags & INP_FREE) && inbuf) {
free(inbuf);
}
inbuf = inbufptr = str;
inbufleft = strlen(inbuf);
/*
* inbufct must reflect the total number of characters left,
* as it used by other parts of the shell, so we need to take account
* of whether the input stack continues, and whether there
* is an extra space to add on at the end.
*/
if (flags & INP_CONT)
inbufct += inbufleft;
else
inbufct = inbufleft;
inbufflags = flags;
}
/*
* Backup one character of the input.
* The last character can always be backed up, provided we didn't just
* expand an alias or a history reference.
* In fact, the character is ignored and the previous character is used.
* (If that's wrong, the bug is in the calling code. Use the #ifdef DEBUG
* code to check.)
*/
/**/
void
inungetc(int c)
{
if (!lexstop) {
if (inbufptr != inbuf) {
#ifdef DEBUG
/* Just for debugging: enable only if foul play suspected. */
if (inbufptr[-1] != (char) c)
fprintf(stderr, "Warning: backing up wrong character.\n");
#endif
/* Just decrement the pointer: if it's not the same
* character being pushed back, we're in trouble anyway.
*/
inbufptr--;
inbufct++;
inbufleft++;
if (((inbufflags & INP_LINENO) || !strin) && c == '\n')
lineno--;
}
#ifdef DEBUG
else if (!(inbufflags & INP_CONT)) {
/* Just for debugging */
fprintf(stderr, "Attempt to inungetc() at start of input.\n");
}
#endif
else {
/*
* The character is being backed up from a previous input stack
* layer. However, there was an expansion in the middle, so we
* can't back up where we want to. Instead, we just push it
* onto the input stack as an extra character.
*/
char *cback = (char *)zcalloc(2);
cback[0] = (char) c;
inpush(cback, INP_FREE|INP_CONT, NULL);
}
/* If we are back at the start of a segment,
* we may need to restore an alias popped from the stack.
* Note this may be a dummy (history expansion) entry.
*/
if (inbufptr == inbufpush && inbufflags & INP_ALCONT) {
/*
* Go back up the stack over all entries which were alias
* expansions and were pushed with nothing remaining to read.
*/
do {
if (instacktop->alias)
instacktop->alias->inuse = 1;
instacktop++;
} while ((instacktop->flags & INP_ALCONT) && !instacktop->bufleft);
inbufflags = INP_CONT|INP_ALIAS;
inbufleft = 0;
inbuf = inbufptr = "";
}
}
}
/* stuff a whole file into the input queue and print it */
/**/
int
stuff(char *fn)
{
FILE *in;
char *buf;
off_t len;
if (!(in = fopen(unmeta(fn), "r"))) {
zerr("can't open %s", fn, 0);
return 1;
}
fseek(in, 0, 2);
len = ftell(in);
fseek(in, 0, 0);
buf = (char *)zalloc(len + 1);
if (!(fread(buf, len, 1, in))) {
zerr("read error on %s", fn, 0);
fclose(in);
zfree(buf, len + 1);
return 1;
}
fclose(in);
buf[len] = '\0';
fwrite(buf, len, 1, stderr);
fflush(stderr);
inputsetline(metafy(buf, len, META_REALLOC), INP_FREE);
return 0;
}
/* flush input queue */
/**/
void
inerrflush(void)
{
while (!lexstop && inbufct)
ingetc();
}
/* Set some new input onto a new element of the input stack */
/**/
mod_export void
inpush(char *str, int flags, Alias inalias)
{
if (!instack) {
/* Initial stack allocation */
instack = (struct instacks *)zalloc(instacksz*sizeof(struct instacks));
instacktop = instack;
}
instacktop->buf = inbuf;
instacktop->bufptr = inbufptr;
instacktop->bufleft = inbufleft;
instacktop->bufct = inbufct;
inbufflags &= ~INP_ALCONT;
if (flags & (INP_ALIAS|INP_HIST)) {
/*
* Text is expansion for history or alias, so continue
* back to old level when done. Also mark stack top
* as alias continuation so as to back up if necessary,
* and mark alias as in use.
*/
flags |= INP_CONT|INP_ALIAS;
instacktop->flags = inbufflags | INP_ALCONT;
if ((instacktop->alias = inalias))
inalias->inuse = 1;
} else {
/* If we are continuing an alias expansion, record the alias
* expansion in new set of flags (do we need this?)
*/
if (((instacktop->flags = inbufflags) & INP_ALIAS) &&
(flags & INP_CONT))
flags |= INP_ALIAS;
}
instacktop++;
if (instacktop == instack + instacksz) {
/* Expand the stack */
instack = (struct instacks *)
realloc(instack,
(instacksz + INSTACK_EXPAND)*sizeof(struct instacks));
instacktop = instack + instacksz;
instacksz += INSTACK_EXPAND;
}
/*
* We maintain the entry above the highest one with real
* text as a flag to inungetc() that it can stop re-pushing the stack.
*/
instacktop->flags = 0;
inbufpush = inbuf = NULL;
inputsetline(str, flags);
}
/* Remove the top element of the stack */
/**/
static void
inpoptop(void)
{
if (inbuf && (inbufflags & INP_FREE))
free(inbuf);
instacktop--;
inbuf = instacktop->buf;
inbufptr = inbufpush = instacktop->bufptr;
inbufleft = instacktop->bufleft;
inbufct = instacktop->bufct;
inbufflags = instacktop->flags;
if (!(inbufflags & INP_ALCONT))
return;
if (instacktop->alias) {
char *t = instacktop->alias->text;
/* a real alias: mark it as unused. */
instacktop->alias->inuse = 0;
if (*t && t[strlen(t) - 1] == ' ') {
inalmore = 1;
histbackword();
}
}
}
/* Remove the top element of the stack and all its continuations. */
/**/
mod_export void
inpop(void)
{
int remcont;
do {
remcont = inbufflags & INP_CONT;
inpoptop();
} while (remcont);
}
|