Index: stable/11/bin/sh/histedit.c =================================================================== --- stable/11/bin/sh/histedit.c (revision 345616) +++ stable/11/bin/sh/histedit.c (revision 345617) @@ -1,502 +1,523 @@ /*- * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include /* * Editline and history functions (and glue). */ #include "shell.h" #include "parser.h" #include "var.h" #include "options.h" #include "main.h" #include "output.h" #include "mystring.h" #ifndef NO_HISTORY #include "myhistedit.h" #include "error.h" #include "eval.h" #include "memalloc.h" #include "builtins.h" #define MAXHISTLOOPS 4 /* max recursions through fc */ #define DEFEDITOR "ed" /* default editor *should* be $EDITOR */ History *hist; /* history cookie */ EditLine *el; /* editline cookie */ int displayhist; static FILE *el_in, *el_out, *el_err; static char *fc_replace(const char *, char *, char *); static int not_fcnumber(const char *); static int str_to_event(const char *, int); /* * Set history and editing status. Called whenever the status may * have changed (figures out what to do). */ void histedit(void) { #define editing (Eflag || Vflag) if (iflag) { if (!hist) { /* * turn history on */ INTOFF; hist = history_init(); INTON; if (hist != NULL) sethistsize(histsizeval()); else out2fmt_flush("sh: can't initialize history\n"); } if (editing && !el && isatty(0)) { /* && isatty(2) ??? */ /* * turn editing on */ char *term; INTOFF; if (el_in == NULL) el_in = fdopen(0, "r"); if (el_err == NULL) el_err = fdopen(1, "w"); if (el_out == NULL) el_out = fdopen(2, "w"); if (el_in == NULL || el_err == NULL || el_out == NULL) goto bad; term = lookupvar("TERM"); if (term) setenv("TERM", term, 1); else unsetenv("TERM"); el = el_init(arg0, el_in, el_out, el_err); if (el != NULL) { if (hist) el_set(el, EL_HIST, history, hist); el_set(el, EL_PROMPT, getprompt); el_set(el, EL_ADDFN, "sh-complete", "Filename completion", _el_fn_sh_complete); } else { bad: out2fmt_flush("sh: can't initialize editing\n"); } INTON; } else if (!editing && el) { INTOFF; el_end(el); el = NULL; INTON; } if (el) { if (Vflag) el_set(el, EL_EDITOR, "vi"); else if (Eflag) el_set(el, EL_EDITOR, "emacs"); el_set(el, EL_BIND, "^I", "sh-complete", NULL); el_source(el, NULL); } } else { INTOFF; if (el) { /* no editing if not interactive */ el_end(el); el = NULL; } if (hist) { history_end(hist); hist = NULL; } INTON; } } void sethistsize(const char *hs) { int histsize; HistEvent he; if (hist != NULL) { if (hs == NULL || !is_number(hs)) histsize = 100; else histsize = atoi(hs); history(hist, &he, H_SETSIZE, histsize); history(hist, &he, H_SETUNIQUE, 1); } } void setterm(const char *term) { if (rootshell && el != NULL && term != NULL) el_set(el, EL_TERMINAL, term); } int histcmd(int argc, char **argv __unused) { int ch; const char *editor = NULL; HistEvent he; int lflg = 0, nflg = 0, rflg = 0, sflg = 0; int i, retval; const char *firststr, *laststr; int first, last, direction; char *pat = NULL, *repl = NULL; static int active = 0; struct jmploc jmploc; struct jmploc *savehandler; char editfilestr[PATH_MAX]; char *volatile editfile; FILE *efp = NULL; int oldhistnum; if (hist == NULL) error("history not active"); if (argc == 1) error("missing history argument"); while (not_fcnumber(*argptr) && (ch = nextopt("e:lnrs")) != '\0') switch ((char)ch) { case 'e': editor = shoptarg; break; case 'l': lflg = 1; break; case 'n': nflg = 1; break; case 'r': rflg = 1; break; case 's': sflg = 1; break; } savehandler = handler; /* * If executing... */ if (lflg == 0 || editor || sflg) { lflg = 0; /* ignore */ editfile = NULL; /* * Catch interrupts to reset active counter and * cleanup temp files. */ if (setjmp(jmploc.loc)) { active = 0; if (editfile) unlink(editfile); handler = savehandler; longjmp(handler->loc, 1); } handler = &jmploc; if (++active > MAXHISTLOOPS) { active = 0; displayhist = 0; error("called recursively too many times"); } /* * Set editor. */ if (sflg == 0) { if (editor == NULL && (editor = bltinlookup("FCEDIT", 1)) == NULL && (editor = bltinlookup("EDITOR", 1)) == NULL) editor = DEFEDITOR; if (editor[0] == '-' && editor[1] == '\0') { sflg = 1; /* no edit */ editor = NULL; } } } /* * If executing, parse [old=new] now */ if (lflg == 0 && *argptr != NULL && ((repl = strchr(*argptr, '=')) != NULL)) { pat = *argptr; *repl++ = '\0'; argptr++; } /* * determine [first] and [last] */ if (*argptr == NULL) { firststr = lflg ? "-16" : "-1"; laststr = "-1"; } else if (argptr[1] == NULL) { firststr = argptr[0]; laststr = lflg ? "-1" : argptr[0]; } else if (argptr[2] == NULL) { firststr = argptr[0]; laststr = argptr[1]; } else error("too many arguments"); /* * Turn into event numbers. */ first = str_to_event(firststr, 0); last = str_to_event(laststr, 1); if (rflg) { i = last; last = first; first = i; } /* * XXX - this should not depend on the event numbers * always increasing. Add sequence numbers or offset * to the history element in next (diskbased) release. */ direction = first < last ? H_PREV : H_NEXT; /* * If editing, grab a temp file. */ if (editor) { int fd; INTOFF; /* easier */ sprintf(editfilestr, "%s/_shXXXXXX", _PATH_TMP); if ((fd = mkstemp(editfilestr)) < 0) error("can't create temporary file %s", editfile); editfile = editfilestr; if ((efp = fdopen(fd, "w")) == NULL) { close(fd); error("Out of space"); } } /* * Loop through selected history events. If listing or executing, * do it now. Otherwise, put into temp file and call the editor * after. * * The history interface needs rethinking, as the following * convolutions will demonstrate. */ history(hist, &he, H_FIRST); retval = history(hist, &he, H_NEXT_EVENT, first); for (;retval != -1; retval = history(hist, &he, direction)) { if (lflg) { if (!nflg) out1fmt("%5d ", he.num); out1str(he.str); } else { const char *s = pat ? fc_replace(he.str, pat, repl) : he.str; if (sflg) { if (displayhist) { out2str(s); flushout(out2); } evalstring(s, 0); if (displayhist && hist) { /* * XXX what about recursive and * relative histnums. */ oldhistnum = he.num; history(hist, &he, H_ENTER, s); /* * XXX H_ENTER moves the internal * cursor, set it back to the current * entry. */ history(hist, &he, H_NEXT_EVENT, oldhistnum); } } else fputs(s, efp); } /* * At end? (if we were to lose last, we'd sure be * messed up). */ if (he.num == last) break; } if (editor) { char *editcmd; fclose(efp); editcmd = stalloc(strlen(editor) + strlen(editfile) + 2); sprintf(editcmd, "%s %s", editor, editfile); evalstring(editcmd, 0); /* XXX - should use no JC command */ INTON; readcmdfile(editfile); /* XXX - should read back - quick tst */ unlink(editfile); } if (lflg == 0 && active > 0) --active; if (displayhist) displayhist = 0; handler = savehandler; return 0; } static char * fc_replace(const char *s, char *p, char *r) { char *dest; int plen = strlen(p); STARTSTACKSTR(dest); while (*s) { if (*s == *p && strncmp(s, p, plen) == 0) { STPUTS(r, dest); s += plen; *p = '\0'; /* so no more matches */ } else STPUTC(*s++, dest); } STPUTC('\0', dest); dest = grabstackstr(dest); return (dest); } static int not_fcnumber(const char *s) { if (s == NULL) return (0); if (*s == '-') s++; return (!is_number(s)); } static int str_to_event(const char *str, int last) { HistEvent he; const char *s = str; int relative = 0; int i, retval; retval = history(hist, &he, H_FIRST); switch (*s) { case '-': relative = 1; /*FALLTHROUGH*/ case '+': s++; } if (is_number(s)) { i = atoi(s); if (relative) { while (retval != -1 && i--) { retval = history(hist, &he, H_NEXT); } if (retval == -1) retval = history(hist, &he, H_LAST); } else { retval = history(hist, &he, H_NEXT_EVENT, i); if (retval == -1) { /* * the notion of first and last is * backwards to that of the history package */ retval = history(hist, &he, last ? H_FIRST : H_LAST); } } if (retval == -1) error("history number %s not found (internal error)", str); } else { /* * pattern */ retval = history(hist, &he, H_PREV_STR, str); if (retval == -1) error("history pattern not found: %s", str); } return (he.num); } int bindcmd(int argc, char **argv) { + int ret; + FILE *old; + FILE *out; if (el == NULL) error("line editing is disabled"); - return (el_parse(el, argc, __DECONST(const char **, argv))); + + INTOFF; + + out = out1fp(); + if (out == NULL) + error("Out of space"); + + el_get(el, EL_GETFP, 1, &old); + el_set(el, EL_SETFP, 1, out); + + ret = el_parse(el, argc, __DECONST(const char **, argv)); + + el_set(el, EL_SETFP, 1, old); + + fclose(out); + + INTON; + + return ret; } #else #include "error.h" int histcmd(int argc, char **argv) { error("not compiled with history support"); /*NOTREACHED*/ return (0); } int bindcmd(int argc, char **argv) { error("not compiled with line editing support"); return (0); } #endif Index: stable/11/bin/sh/output.c =================================================================== --- stable/11/bin/sh/output.c (revision 345616) +++ stable/11/bin/sh/output.c (revision 345617) @@ -1,375 +1,381 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); /* * Shell output routines. We use our own output routines because: * When a builtin command is interrupted we have to discard * any pending output. * When a builtin command appears in back quotes, we want to * save the output of the command in a region obtained * via malloc, rather than doing a fork and reading the * output of the command via a pipe. */ #include /* defines BUFSIZ */ #include #include #include #include #include #include #include #include "shell.h" #include "syntax.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "var.h" #define OUTBUFSIZ BUFSIZ #define MEM_OUT -2 /* output to dynamically allocated memory */ #define OUTPUT_ERR 01 /* error occurred on output */ static int doformat_wr(void *, const char *, int); struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; struct output errout = {NULL, 0, NULL, 256, 2, 0}; struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; struct output *out1 = &output; struct output *out2 = &errout; void outcslow(int c, struct output *file) { outc(c, file); } void out1str(const char *p) { outstr(p, out1); } void out1qstr(const char *p) { outqstr(p, out1); } void out2str(const char *p) { outstr(p, out2); } void out2qstr(const char *p) { outqstr(p, out2); } void outstr(const char *p, struct output *file) { outbin(p, strlen(p), file); } static void byteseq(int ch, struct output *file) { char seq[4]; seq[0] = '\\'; seq[1] = (ch >> 6 & 0x3) + '0'; seq[2] = (ch >> 3 & 0x7) + '0'; seq[3] = (ch & 0x7) + '0'; outbin(seq, 4, file); } static void outdqstr(const char *p, struct output *file) { const char *end; mbstate_t mbs; size_t clen; wchar_t wc; memset(&mbs, '\0', sizeof(mbs)); end = p + strlen(p); outstr("$'", file); while ((clen = mbrtowc(&wc, p, end - p + 1, &mbs)) != 0) { if (clen == (size_t)-2) { while (p < end) byteseq(*p++, file); break; } if (clen == (size_t)-1) { memset(&mbs, '\0', sizeof(mbs)); byteseq(*p++, file); continue; } if (wc == L'\n') outcslow('\n', file), p++; else if (wc == L'\r') outstr("\\r", file), p++; else if (wc == L'\t') outstr("\\t", file), p++; else if (!iswprint(wc)) { for (; clen > 0; clen--) byteseq(*p++, file); } else { if (wc == L'\'' || wc == L'\\') outcslow('\\', file); outbin(p, clen, file); p += clen; } } outcslow('\'', file); } /* Like outstr(), but quote for re-input into the shell. */ void outqstr(const char *p, struct output *file) { int i; if (p[0] == '\0') { outstr("''", file); return; } for (i = 0; p[i] != '\0'; i++) { if ((p[i] > '\0' && p[i] < ' ' && p[i] != '\n') || (p[i] & 0x80) != 0 || p[i] == '\'') { outdqstr(p, file); return; } } if (p[strcspn(p, "|&;<>()$`\\\" \n*?[~#=")] == '\0' || strcmp(p, "[") == 0) { outstr(p, file); return; } outcslow('\'', file); outstr(p, file); outcslow('\'', file); } void outbin(const void *data, size_t len, struct output *file) { const char *p; p = data; while (len-- > 0) outc(*p++, file); } void emptyoutbuf(struct output *dest) { int offset; if (dest->buf == NULL) { INTOFF; dest->buf = ckmalloc(dest->bufsize); dest->nextc = dest->buf; dest->nleft = dest->bufsize; INTON; } else if (dest->fd == MEM_OUT) { offset = dest->bufsize; INTOFF; dest->bufsize <<= 1; dest->buf = ckrealloc(dest->buf, dest->bufsize); dest->nleft = dest->bufsize - offset; dest->nextc = dest->buf + offset; INTON; } else { flushout(dest); } dest->nleft--; } void flushall(void) { flushout(&output); flushout(&errout); } void flushout(struct output *dest) { if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) return; if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) dest->flags |= OUTPUT_ERR; dest->nextc = dest->buf; dest->nleft = dest->bufsize; } void freestdout(void) { INTOFF; if (output.buf) { ckfree(output.buf); output.buf = NULL; output.nleft = 0; } INTON; } int outiserror(struct output *file) { return (file->flags & OUTPUT_ERR); } void outclearerror(struct output *file) { file->flags &= ~OUTPUT_ERR; } void outfmt(struct output *file, const char *fmt, ...) { va_list ap; va_start(ap, fmt); doformat(file, fmt, ap); va_end(ap); } void out1fmt(const char *fmt, ...) { va_list ap; va_start(ap, fmt); doformat(out1, fmt, ap); va_end(ap); } void out2fmt_flush(const char *fmt, ...) { va_list ap; va_start(ap, fmt); doformat(out2, fmt, ap); va_end(ap); flushout(out2); } void fmtstr(char *outbuf, int length, const char *fmt, ...) { va_list ap; INTOFF; va_start(ap, fmt); vsnprintf(outbuf, length, fmt, ap); va_end(ap); INTON; } static int doformat_wr(void *cookie, const char *buf, int len) { struct output *o; o = (struct output *)cookie; outbin(buf, len, o); return (len); } void doformat(struct output *dest, const char *f, va_list ap) { FILE *fp; if ((fp = fwopen(dest, doformat_wr)) != NULL) { vfprintf(fp, f, ap); fclose(fp); } } +FILE * +out1fp(void) +{ + return fwopen(out1, doformat_wr); +} + /* * Version of write which resumes after a signal is caught. */ int xwrite(int fd, const char *buf, int nbytes) { int ntry; int i; int n; n = nbytes; ntry = 0; for (;;) { i = write(fd, buf, n); if (i > 0) { if ((n -= i) <= 0) return nbytes; buf += i; ntry = 0; } else if (i == 0) { if (++ntry > 10) return nbytes - n; } else if (errno != EINTR) { return -1; } } } Index: stable/11/bin/sh/output.h =================================================================== --- stable/11/bin/sh/output.h (revision 345616) +++ stable/11/bin/sh/output.h (revision 345617) @@ -1,83 +1,85 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)output.h 8.2 (Berkeley) 5/4/95 * $FreeBSD$ */ #ifndef OUTPUT_INCL #include #include +#include struct output { char *nextc; int nleft; char *buf; int bufsize; short fd; short flags; }; extern struct output output; /* to fd 1 */ extern struct output errout; /* to fd 2 */ extern struct output memout; extern struct output *out1; /* &memout if backquote, otherwise &output */ extern struct output *out2; /* &memout if backquote with 2>&1, otherwise &errout */ void outcslow(int, struct output *); void out1str(const char *); void out1qstr(const char *); void out2str(const char *); void out2qstr(const char *); void outstr(const char *, struct output *); void outqstr(const char *, struct output *); void outbin(const void *, size_t, struct output *); void emptyoutbuf(struct output *); void flushall(void); void flushout(struct output *); void freestdout(void); int outiserror(struct output *); void outclearerror(struct output *); void outfmt(struct output *, const char *, ...) __printflike(2, 3); void out1fmt(const char *, ...) __printflike(1, 2); void out2fmt_flush(const char *, ...) __printflike(1, 2); void fmtstr(char *, int, const char *, ...) __printflike(3, 4); void doformat(struct output *, const char *, va_list) __printflike(2, 0); +FILE *out1fp(void); int xwrite(int, const char *, int); #define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c))) #define out1c(c) outc(c, out1); #define out2c(c) outcslow(c, out2); #define OUTPUT_INCL #endif Index: stable/11 =================================================================== --- stable/11 (revision 345616) +++ stable/11 (revision 345617) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r344306