Esempio n. 1
0
int
c_read(char **wp)
{
	int c = 0;
	int expand = 1, history = 0;
	int expanding;
	int ecode = 0;
	char *cp;
	int fd = 0;
	struct shf *shf;
	int optc;
	const char *emsg;
	XString cs, xs;
	struct tbl *vp;
	char *xp = NULL;

	while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != -1)
		switch (optc) {
		case 'p':
			if ((fd = coproc_getfd(R_OK, &emsg)) < 0) {
				bi_errorf("-p: %s", emsg);
				return 1;
			}
			break;
		case 'r':
			expand = 0;
			break;
		case 's':
			history = 1;
			break;
		case 'u':
			if (!*(cp = builtin_opt.optarg))
				fd = 0;
			else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) {
				bi_errorf("-u: %s: %s", cp, emsg);
				return 1;
			}
			break;
		case '?':
			return 1;
		}
	wp += builtin_opt.optind;

	if (*wp == NULL)
		*--wp = "REPLY";

	/* Since we can't necessarily seek backwards on non-regular files,
	 * don't buffer them so we can't read too much.
	 */
	shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare);

	if ((cp = strchr(*wp, '?')) != NULL) {
		*cp = 0;
		if (isatty(fd)) {
			/* at&t ksh says it prints prompt on fd if it's open
			 * for writing and is a tty, but it doesn't do it
			 * (it also doesn't check the interactive flag,
			 * as is indicated in the Kornshell book).
			 */
			shellf("%s", cp+1);
		}
	}

	/* If we are reading from the co-process for the first time,
	 * make sure the other side of the pipe is closed first.  This allows
	 * the detection of eof.
	 *
	 * This is not compatible with at&t ksh... the fd is kept so another
	 * coproc can be started with same output, however, this means eof
	 * can't be detected...  This is why it is closed here.
	 * If this call is removed, remove the eof check below, too.
	 * coproc_readw_close(fd);
	 */

	if (history)
		Xinit(xs, xp, 128, ATEMP);
	expanding = 0;
	Xinit(cs, cp, 128, ATEMP);
	for (; *wp != NULL; wp++) {
		for (cp = Xstring(cs, cp); ; ) {
			if (c == '\n' || c == EOF)
				break;
			while (1) {
				c = shf_getc(shf);
				if (c == '\0')
					continue;
				if (c == EOF && shf_error(shf) &&
				    shf_errno(shf) == EINTR) {
					/* Was the offending signal one that
					 * would normally kill a process?
					 * If so, pretend the read was killed.
					 */
					ecode = fatal_trap_check();

					/* non fatal (eg, CHLD), carry on */
					if (!ecode) {
						shf_clearerr(shf);
						continue;
					}
				}
				break;
			}
			if (history) {
				Xcheck(xs, xp);
				Xput(xs, xp, c);
			}
			Xcheck(cs, cp);
			if (expanding) {
				expanding = 0;
				if (c == '\n') {
					c = 0;
					if (Flag(FTALKING_I) && isatty(fd)) {
						/* set prompt in case this is
						 * called from .profile or $ENV
						 */
						set_prompt(PS2, NULL);
						pprompt(prompt, 0);
					}
				} else if (c != EOF)
					Xput(cs, cp, c);
				continue;
			}
			if (expand && c == '\\') {
				expanding = 1;
				continue;
			}
			if (c == '\n' || c == EOF)
				break;
			if (ctype(c, C_IFS)) {
				if (Xlength(cs, cp) == 0 && ctype(c, C_IFSWS))
					continue;
				if (wp[1])
					break;
			}
			Xput(cs, cp, c);
		}
		/* strip trailing IFS white space from last variable */
		if (!wp[1])
			while (Xlength(cs, cp) && ctype(cp[-1], C_IFS) &&
			    ctype(cp[-1], C_IFSWS))
				cp--;
		Xput(cs, cp, '\0');
		vp = global(*wp);
		/* Must be done before setting export. */
		if (vp->flag & RDONLY) {
			shf_flush(shf);
			bi_errorf("%s is read only", *wp);
			return 1;
		}
		if (Flag(FEXPORT))
			typeset(*wp, EXPORT, 0, 0, 0);
		if (!setstr(vp, Xstring(cs, cp), KSH_RETURN_ERROR)) {
		    shf_flush(shf);
		    return 1;
		}
	}

	shf_flush(shf);
	if (history) {
		Xput(xs, xp, '\0');
		source->line++;
		histsave(source->line, Xstring(xs, xp), 1);
		Xfree(xs, xp);
	}
	/* if this is the co-process fd, close the file descriptor
	 * (can get eof if and only if all processes are have died, ie,
	 * coproc.njobs is 0 and the pipe is closed).
	 */
	if (c == EOF && !ecode)
		coproc_read_close(fd);

	return ecode ? ecode : c == EOF;
}
Esempio n. 2
0
static void
getsc_line(Source *s)
{
	char *xp = Xstring(s->xs, xp), *cp;
	bool interactive = Flag(FTALKING) && s->type == SSTDIN;
	bool have_tty = tobool(interactive && (s->flags & SF_TTY));

	/* Done here to ensure nothing odd happens when a timeout occurs */
	XcheckN(s->xs, xp, LINE);
	*xp = '\0';
	s->start = s->str = xp;

	if (have_tty && ksh_tmout) {
		ksh_tmout_state = TMOUT_READING;
		alarm(ksh_tmout);
	}
	if (interactive)
		change_winsz();
#ifndef MKSH_NO_CMDLINE_EDITING
	if (have_tty && (
#if !MKSH_S_NOVI
	    Flag(FVI) ||
#endif
	    Flag(FEMACS) || Flag(FGMACS))) {
		int nread;

		nread = x_read(xp);
		if (nread < 0)
			/* read error */
			nread = 0;
		xp[nread] = '\0';
		xp += nread;
	} else
#endif
	  {
		if (interactive)
			pprompt(prompt, 0);
		else
			s->line++;

		while (/* CONSTCOND */ 1) {
			char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf);

			if (!p && shf_error(s->u.shf) &&
			    shf_errno(s->u.shf) == EINTR) {
				shf_clearerr(s->u.shf);
				if (trap)
					runtraps(0);
				continue;
			}
			if (!p || (xp = p, xp[-1] == '\n'))
				break;
			/* double buffer size */
			/* move past NUL so doubling works... */
			xp++;
			XcheckN(s->xs, xp, Xlength(s->xs, xp));
			/* ...and move back again */
			xp--;
		}
		/*
		 * flush any unwanted input so other programs/builtins
		 * can read it. Not very optimal, but less error prone
		 * than flushing else where, dealing with redirections,
		 * etc.
		 * TODO: reduce size of shf buffer (~128?) if SSTDIN
		 */
		if (s->type == SSTDIN)
			shf_flush(s->u.shf);
	}
	/*
	 * XXX: temporary kludge to restore source after a
	 * trap may have been executed.
	 */
	source = s;
	if (have_tty && ksh_tmout) {
		ksh_tmout_state = TMOUT_EXECUTING;
		alarm(0);
	}
	cp = Xstring(s->xs, xp);
	rndpush(cp);
	s->start = s->str = cp;
	strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp));
	/* Note: if input is all nulls, this is not eof */
	if (Xlength(s->xs, xp) == 0) {
		/* EOF */
		if (s->type == SFILE)
			shf_fdclose(s->u.shf);
		s->str = NULL;
	} else if (interactive && *s->str) {
		if (cur_prompt != PS1)
			histsave(&s->line, s->str, HIST_APPEND, true);
		else if (!ctype(*s->str, C_IFS | C_IFSWS))
			histsave(&s->line, s->str, HIST_QUEUE, true);
#if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
		else
			goto check_for_sole_return;
	} else if (interactive && cur_prompt == PS1) {
 check_for_sole_return:
		cp = Xstring(s->xs, xp);
		while (*cp && ctype(*cp, C_IFSWS))
			++cp;
		if (!*cp) {
			histsave(&s->line, NULL, HIST_FLUSH, true);
			histsync();
		}
#endif
	}
	if (interactive)
		set_prompt(PS2, NULL);
}
Esempio n. 3
0
static void
getsc_line(Source *s)
{
	char *xp = Xstring(s->xs, xp);
	int interactive = Flag(FTALKING) && s->type == SSTDIN;
	int have_tty = interactive && (s->flags & SF_TTY);

	/* Done here to ensure nothing odd happens when a timeout occurs */
	XcheckN(s->xs, xp, LINE);
	*xp = '\0';
	s->start = s->str = xp;

	if (have_tty && ksh_tmout) {
		ksh_tmout_state = TMOUT_READING;
		alarm(ksh_tmout);
	}
#ifdef EDIT
	if (have_tty && (0
# ifdef VI
			 || Flag(FVI)
# endif /* VI */
# ifdef EMACS
			 || Flag(FEMACS) || Flag(FGMACS)
# endif /* EMACS */
		))
	{
		int nread;

		nread = x_read(xp, LINE);
		if (nread < 0)	/* read error */
			nread = 0;
		xp[nread] = '\0';
		xp += nread;
	}
	else
#endif /* EDIT */
	{
		if (interactive) {
			pprompt(prompt, 0);
		} else
			s->line++;

		while (1) {
			char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf);

			if (!p && shf_error(s->u.shf)
			    && shf_errno(s->u.shf) == EINTR)
			{
				shf_clearerr(s->u.shf);
				if (trap)
					runtraps(0);
				continue;
			}
			if (!p || (xp = p, xp[-1] == '\n'))
				break;
			/* double buffer size */
			xp++; /* move past null so doubling works... */
			XcheckN(s->xs, xp, Xlength(s->xs, xp));
			xp--; /* ...and move back again */
		}
		/* flush any unwanted input so other programs/builtins
		 * can read it.  Not very optimal, but less error prone
		 * than flushing else where, dealing with redirections,
		 * etc..
		 * todo: reduce size of shf buffer (~128?) if SSTDIN
		 */
		if (s->type == SSTDIN)
			shf_flush(s->u.shf);
	}
	/* XXX: temporary kludge to restore source after a
	 * trap may have been executed.
	 */
	source = s;
	if (have_tty && ksh_tmout) {
		ksh_tmout_state = TMOUT_EXECUTING;
		alarm(0);
	}
	s->start = s->str = Xstring(s->xs, xp);
	strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp));
	/* Note: if input is all nulls, this is not eof */
	if (Xlength(s->xs, xp) == 0) { /* EOF */
		if (s->type == SFILE)
			shf_fdclose(s->u.shf);
		s->str = NULL;
	} else if (interactive) {
#ifdef HISTORY
		char *p = Xstring(s->xs, xp);
		if (cur_prompt == PS1)
			while (*p && ctype(*p, C_IFS) && ctype(*p, C_IFSWS))
				p++;
		if (*p) {
			s->line++;
			histsave(s->line, s->str, 1);
		}
#endif /* HISTORY */
	}
	if (interactive)
		set_prompt(PS2, (Source *) 0);
}
Esempio n. 4
0
/* GET_COMMAND -- Get command line from the input stream.  If not interactive,
 *   all we do is read the line into the cmdblk buffer.  If called when parsing
 *   command input to an interactive task, we must output a prompt before
 *   reading in the command line.  The prompt changes depending on whether or
 *   not the command is the first in a command block (whether or not we have
 *   closure).  After reading the command, we check if it is a history directive
 *   and process it if so.  Otherwise we must still process it to expand any
 *   history macros.  Ignore all blank or comment lines.  These are
 *   any line in which the first non-blank character is a newline or a
 *   '#'.  This will make some things a bit more efficient, but is
 *   actually to allow the if/else parsing to work properly.
 *
 * N.B.: We must directly or indirectly set ip_cmdblk so that yy_getc takes
 *   the next character from the right place.  This is either done directly
 *   or by a call to yy_startblock.
 */
int
get_command (
  FILE	*fp
)
{
	register char *ip, *op;
	char	raw_cmd[SZ_LINE+1];	/* buffer for raw command line	*/
	char	new_cmd[SZ_CMDBLK+1];	/* temporary for processed cmd	*/
	int	execute=1, temp, status;


	if (!(currentask->t_flags & T_INTERACTIVE)  ||
	    parse_state == PARSE_PARAMS) {

	    /* Ensure that searches through string terminate. */
	    cmdblk[SZ_LINE] = '\0';
	    ip_cmdblk = cmdblk;

	    while (YES) {
 		currentask->t_scriptln++;	/* noninteractive mode	*/

		status = (fgets (cmdblk, SZ_LINE, fp) == NULL ? EOF : OK);
		if (status == EOF) {
		    cmdblk[0] = '\0';
		    break;
		}

		/* Check if this is a blank line. */
		for (ip = cmdblk;  *ip == ' ' || *ip == '\t';  ip++)
		    ;
		if (*ip == '\n' || *ip == '\0')
		    continue;

		/* Check for the #{ ... #} lexmode toggle sequences.  These
		 * are matched only at the beginning of a line.  #{ sets
		 * command mode on the command input stream and #} clears it.
		 */
		if (*ip == '#') {
		    if (ip == cmdblk) {
			if (*(ip+1) == '{') {
			    lex_setcpumode (fp);
			    lexinit();
			} else if (*(ip+1) == '}') {
			    lex_clrcpumode (fp);
			    lexinit();
			}
		    }
		    continue;
		}

		break;
	    }

	    if (cldebug || echocmds())
		eprintf ("%s", status == EOF ? "bye\n" : cmdblk);

	    return (status);
	}

	raw_cmd[SZ_LINE] = '\0';
	while (YES) {
	    /* Prompt the user for a new command if the input buffer is empty.
	     * The CL prompt clears raw mode in case it is left in effect by a
	     * program abort.
	     */
input_:
	    if (c_fstati (fileno(fp), F_UNREAD) == 0) {
		if (c_fstati ((XINT)STDIN, F_RAW) == YES)
		    c_fseti ((XINT)STDIN, F_RAW, NO);
		if (cmdblk_line == 0)
		    pprompt (curpack->pk_name);
		else
		    pprompt (NOCLOSURE);
	    }

	    /* Read the next command line. */
	    if (fgets (raw_cmd, SZ_LINE, fp) == NULL)
		return (EOF);

	    /* Check for the #{ ... #} lexmode toggle sequences.  These
	     * are matched only at the beginning of a line.  #{ sets
	     * command mode on the command input stream and #} clears it.
	     */
	    if (*(ip=raw_cmd) == '#') {
		if (*(ip+1) == '{') {
		    lex_setcpumode (fp);
		    lexinit();
		} else if (*(ip+1) == '}') {
		    lex_clrcpumode (fp);
		    lexinit();
		}
	    }

	    /* Skip leading whitespace. */
	    for (ip=raw_cmd;  *ip == ' ' || *ip == '\t';  ip++)
		;

	    /* For interactive comments, make sure we store them in the
	     * history and the logfile.  This is so that users can add
	     * comments into the logfile interactively.
	     */
	    if (*ip == '#') {
		put_history (raw_cmd);
	  	if (log_commands())
		    put_logfile (raw_cmd);
	    } else if (*ip != '\n' && *ip != '\0') {
		cmdblk_line++;
		break;
	    }
	}

	/* If history directive, transform the directive into an executable
	 * command block using the history data.  Echo the new command as
	 * if the user had typed it, for verification.
	 */
	if (*raw_cmd == HISTCHAR) {
	    /* Use screen style history editing only if the CL parameter
	     * "ehinit" contains the boolean variable "verify" (or if the 
	     * cmd is "ehistory", below).
	     */
	    if (eh_verify)
		execute = edit_history_directive (raw_cmd+1, new_cmd);
	    else {
		execute = process_history_directive (raw_cmd, new_cmd);
		fputs (new_cmd, currentask->t_stdout);
	    }

	} else if (expand_history_macros (raw_cmd, new_cmd)) {
	    fputs (new_cmd, currentask->t_stdout);

	} else {
	    static  char ehist[] = "ehistory";
	    int     n;

	    for (n=0, ip=raw_cmd, op=ehist;  (*ip == *op);  ip++, op++)
		n++;
	    if (n > 0 && isspace (*ip)) {
		while (isspace (*ip))
		    ip++;
		execute = edit_history_directive (ip, new_cmd);
	    }
	}

	/* If user deletes entire line go back and get another command.  */
	for (ip=new_cmd;  isspace (*ip);  ip++)
	    ;
	if (*ip == EOS) {
	    cmdblk_line = 0;
	    execute = 1;
	    goto input_;
	}

	/* Now move the processed command into the cmdblk buffer.  If there
	 * is not enough storage remaining in the cmdblk buffer, we have to
	 * break the actual (large) command block up, calling yy_startblock to
	 * start a new block, but without changing the line number within the
	 * block.  We must not let the history mechanism limit the size of a
	 * command block.
	 */
	op_cmdblk = ip_cmdblk - 1;		/* back up to EOS	*/
	if (strlen (new_cmd) > (cmdblk + SZ_CMDBLK - op_cmdblk)) {
	    temp = cmdblk_line;
	    yy_startblock (LOG);
	    cmdblk_line = temp;
	}
	ip_cmdblk = op = op_cmdblk;
	for (ip=new_cmd;  (*op++ = *ip++) != EOS;  )
	    ;

	/* Save the "raw command" here for use in yy_startblock.  This is
	 * to handle the problem of procedure script parsing overwriting
	 * the raw command in cmdblk.
	 */
	strcpy (raw_cmdblk, cmdblk);

	if (!execute)
	    yy_startblock (NOLOG);

	fflush (currentask->t_stdout);
	return (OK);
}