summaryrefslogtreecommitdiff
path: root/usr/src/lib/libshell/common/edit/hexpand.c
diff options
context:
space:
mode:
authorAndy Fiddaman <omnios@citrus-it.co.uk>2020-12-27 17:47:37 +0000
committerAndy Fiddaman <omnios@citrus-it.co.uk>2021-01-30 17:13:33 +0000
commitb30d193948be5a7794d7ae3ba0ed9c2f72c88e0f (patch)
tree6a37e590faffb9bb9af66887de645c546445036c /usr/src/lib/libshell/common/edit/hexpand.c
parentdf36e06d12cbf655ddf22339ef8c39fa2b83ebf8 (diff)
downloadillumos-joyent-b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f.tar.gz
13405 ksh93 update to 2012-08-01
13434 sh: mishandles backslash as last character of a block of input 11750 ksh mkdir builtin doesn't honor special file permissions 9199 ksh93 builtin *grep -v mishandles blank lines, blows up libgcrypt-config 6756 sh (and ksh) have issues with ${1+"$@"} 6520 ksh: sleep could wait forever 4860 ksh93: core in printf 3791 /bin/sh's builtin 'rm' busted: 'rm -f' without arguments returns error 1047 ksh overwrites child core files 880 ksh93 coredumps on 'unset' 499 "interrupted system call" when using "tee" builtin in ksh Reviewed by: Robert Mustacchi <rm@fingolfin.org> Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> Reviewed by: Dominik Hassler <hadfl@omnios.org> Approved by: Rich Lowe <richlowe@richlowe.net>
Diffstat (limited to 'usr/src/lib/libshell/common/edit/hexpand.c')
-rw-r--r--usr/src/lib/libshell/common/edit/hexpand.c737
1 files changed, 0 insertions, 737 deletions
diff --git a/usr/src/lib/libshell/common/edit/hexpand.c b/usr/src/lib/libshell/common/edit/hexpand.c
deleted file mode 100644
index 9d434ae673..0000000000
--- a/usr/src/lib/libshell/common/edit/hexpand.c
+++ /dev/null
@@ -1,737 +0,0 @@
-/***********************************************************************
-* *
-* This software is part of the ast package *
-* Copyright (c) 1982-2010 AT&T Intellectual Property *
-* and is licensed under the *
-* Common Public License, Version 1.0 *
-* by AT&T Intellectual Property *
-* *
-* A copy of the License is available at *
-* http://www.opensource.org/licenses/cpl1.0.txt *
-* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
-* *
-* Information and Software Systems Research *
-* AT&T Research *
-* Florham Park NJ *
-* *
-* David Korn <dgk@research.att.com> *
-* *
-***********************************************************************/
-#pragma prototyped
-/*
- * bash style history expansion
- *
- * Author:
- * Karsten Fleischer
- * Omnium Software Engineering
- * An der Luisenburg 7
- * D-51379 Leverkusen
- * Germany
- *
- * <K.Fleischer@omnium.de>
- */
-
-
-#include "defs.h"
-#include "edit.h"
-
-#if ! SHOPT_HISTEXPAND
-
-NoN(hexpand)
-
-#else
-
-static char *modifiers = "htrepqxs&";
-static int mod_flags[] = { 0, 0, 0, 0, HIST_PRINT, HIST_QUOTE, HIST_QUOTE|HIST_QUOTE_BR, 0, 0 };
-
-#define DONE() {flag |= HIST_ERROR; cp = 0; stakseek(0); goto done;}
-
-struct subst
-{
- char *str[2]; /* [0] is "old", [1] is "new" string */
-};
-
-
-/*
- * parse an /old/new/ string, delimiter expected as first char.
- * if "old" not specified, keep sb->str[0]
- * if "new" not specified, set sb->str[1] to empty string
- * read up to third delimeter char, \n or \0, whichever comes first.
- * return adress is one past the last valid char in s:
- * - the address containing \n or \0 or
- * - one char beyond the third delimiter
- */
-
-static char *parse_subst(const char *s, struct subst *sb)
-{
- char *cp,del;
- int off,n = 0;
-
- /* build the strings on the stack, mainly for '&' substition in "new" */
- off = staktell();
-
- /* init "new" with empty string */
- if(sb->str[1])
- free(sb->str[1]);
- sb->str[1] = strdup("");
-
- /* get delimiter */
- del = *s;
-
- cp = (char*) s + 1;
-
- while(n < 2)
- {
- if(*cp == del || *cp == '\n' || *cp == '\0')
- {
- /* delimiter or EOL */
- if(staktell() != off)
- {
- /* dupe string on stack and rewind stack */
- stakputc('\0');
- if(sb->str[n])
- free(sb->str[n]);
- sb->str[n] = strdup(stakptr(off));
- stakseek(off);
- }
- n++;
-
- /* if not delimiter, we've reached EOL. Get outta here. */
- if(*cp != del)
- break;
- }
- else if(*cp == '\\')
- {
- if(*(cp+1) == del) /* quote delimiter */
- {
- stakputc(del);
- cp++;
- }
- else if(*(cp+1) == '&' && n == 1)
- { /* quote '&' only in "new" */
- stakputc('&');
- cp++;
- }
- else
- stakputc('\\');
- }
- else if(*cp == '&' && n == 1 && sb->str[0])
- /* substitute '&' with "old" in "new" */
- stakputs(sb->str[0]);
- else
- stakputc(*cp);
- cp++;
- }
-
- /* rewind stack */
- stakseek(off);
-
- return cp;
-}
-
-/*
- * history expansion main routine
- */
-
-int hist_expand(const char *ln, char **xp)
-{
- int off, /* stack offset */
- q, /* quotation flags */
- p, /* flag */
- c, /* current char */
- flag=0; /* HIST_* flags */
- Sfoff_t n, /* history line number, counter, etc. */
- i, /* counter */
- w[2]; /* word range */
- char *sp, /* stack pointer */
- *cp, /* current char in ln */
- *str, /* search string */
- *evp, /* event/word designator string, for error msgs */
- *cc=0, /* copy of current line up to cp; temp ptr */
- hc[3], /* default histchars */
- *qc="\'\"`"; /* quote characters */
- Sfio_t *ref=0, /* line referenced by event designator */
- *tmp=0, /* temporary line buffer */
- *tmp2=0;/* temporary line buffer */
- Histloc_t hl; /* history location */
- static Namval_t *np = 0; /* histchars variable */
- static struct subst sb = {0,0}; /* substition strings */
- static Sfio_t *wm=0; /* word match from !?string? event designator */
-
- if(!wm)
- wm = sfopen(NULL, NULL, "swr");
-
- hc[0] = '!';
- hc[1] = '^';
- hc[2] = 0;
- if((np = nv_open("histchars",sh.var_tree,0)) && (cp = nv_getval(np)))
- {
- if(cp[0])
- {
- hc[0] = cp[0];
- if(cp[1])
- {
- hc[1] = cp[1];
- if(cp[2])
- hc[2] = cp[2];
- }
- }
- }
-
- /* save shell stack */
- if(off = staktell())
- sp = stakfreeze(0);
-
- cp = (char*)ln;
-
- while(cp && *cp)
- {
- /* read until event/quick substitution/comment designator */
- if((*cp != hc[0] && *cp != hc[1] && *cp != hc[2])
- || (*cp == hc[1] && cp != ln))
- {
- if(*cp == '\\') /* skip escaped designators */
- stakputc(*cp++);
- else if(*cp == '\'') /* skip quoted designators */
- {
- do
- stakputc(*cp);
- while(*++cp && *cp != '\'');
- }
- stakputc(*cp++);
- continue;
- }
-
- if(hc[2] && *cp == hc[2]) /* history comment designator, skip rest of line */
- {
- stakputc(*cp++);
- stakputs(cp);
- DONE();
- }
-
- n = -1;
- str = 0;
- flag &= HIST_EVENT; /* save event flag for returning later */
- evp = cp;
- ref = 0;
-
- if(*cp == hc[1]) /* shortcut substitution */
- {
- flag |= HIST_QUICKSUBST;
- goto getline;
- }
-
- if(*cp == hc[0] && *(cp+1) == hc[0]) /* refer to line -1 */
- {
- cp += 2;
- goto getline;
- }
-
- switch(c = *++cp) {
- case ' ':
- case '\t':
- case '\n':
- case '\0':
- case '=':
- case '(':
- stakputc(hc[0]);
- continue;
- case '#': /* the line up to current position */
- flag |= HIST_HASH;
- cp++;
- n = staktell(); /* terminate string and dup */
- stakputc('\0');
- cc = strdup(stakptr(0));
- stakseek(n); /* remove null byte again */
- ref = sfopen(ref, cc, "s"); /* open as file */
- n = 0; /* skip history file referencing */
- break;
- case '-': /* back reference by number */
- if(!isdigit(*(cp+1)))
- goto string_event;
- cp++;
- /* FALLTHROUGH */
- case '0': /* reference by number */
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- n = 0;
- while(isdigit(*cp))
- n = n * 10 + (*cp++) - '0';
- if(c == '-')
- n = -n;
- break;
- case '$':
- n = -1;
- case ':':
- break;
- case '?':
- cp++;
- flag |= HIST_QUESTION;
- /* FALLTHROUGH */
- string_event:
- default:
- /* read until end of string or word designator/modifier */
- str = cp;
- while(*cp)
- {
- cp++;
- if((!(flag&HIST_QUESTION) &&
- (*cp == ':' || isspace(*cp)
- || *cp == '^' || *cp == '$'
- || *cp == '*' || *cp == '-'
- || *cp == '%')
- )
- || ((flag&HIST_QUESTION) && (*cp == '?' || *cp == '\n')))
- {
- c = *cp;
- *cp = '\0';
- }
- }
- break;
- }
-
-getline:
- flag |= HIST_EVENT;
- if(str) /* !string or !?string? event designator */
- {
-
- /* search history for string */
- hl = hist_find(sh.hist_ptr, str,
- sh.hist_ptr->histind,
- flag&HIST_QUESTION, -1);
- if((n = hl.hist_command) == -1)
- n = 0; /* not found */
- }
- if(n)
- {
- if(n < 0) /* determine index for backref */
- n = sh.hist_ptr->histind + n;
- /* search and use history file if found */
- if(n > 0 && hist_seek(sh.hist_ptr, n) != -1)
- ref = sh.hist_ptr->histfp;
-
- }
- if(!ref)
- {
- /* string not found or command # out of range */
- c = *cp;
- *cp = '\0';
- errormsg(SH_DICT, ERROR_ERROR, "%s: event not found", evp);
- *cp = c;
- DONE();
- }
-
- if(str) /* string search: restore orig. line */
- {
- if(flag&HIST_QUESTION)
- *cp++ = c; /* skip second question mark */
- else
- *cp = c;
- }
-
- /* colon introduces either word designators or modifiers */
- if(*(evp = cp) == ':')
- cp++;
-
- w[0] = 0; /* -1 means last word, -2 means match from !?string? */
- w[1] = -1; /* -1 means last word, -2 means suppress last word */
-
- if(flag & HIST_QUICKSUBST) /* shortcut substitution */
- goto getsel;
-
- n = 0;
- while(n < 2)
- {
- switch(c = *cp++) {
- case '^': /* first word */
- if(n == 0)
- {
- w[0] = w[1] = 1;
- goto skip;
- }
- else
- goto skip2;
- case '$': /* last word */
- w[n] = -1;
- goto skip;
- case '%': /* match from !?string? event designator */
- if(n == 0)
- {
- if(!str)
- {
- w[0] = 0;
- w[1] = -1;
- ref = wm;
- }
- else
- {
- w[0] = -2;
- w[1] = sftell(ref) + hl.hist_char;
- }
- sfseek(wm, 0, SEEK_SET);
- goto skip;
- }
- /* FALLTHROUGH */
- default:
- skip2:
- cp--;
- n = 2;
- break;
- case '*': /* until last word */
- if(n == 0)
- w[0] = 1;
- w[1] = -1;
- skip:
- flag |= HIST_WORDDSGN;
- n = 2;
- break;
- case '-': /* until last word or specified index */
- w[1] = -2;
- flag |= HIST_WORDDSGN;
- n = 1;
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': /* specify index */
- if((*evp == ':') || w[1] == -2)
- {
- w[n] = c - '0';
- while(isdigit(c=*cp++))
- w[n] = w[n] * 10 + c - '0';
- flag |= HIST_WORDDSGN;
- if(n == 0)
- w[1] = w[0];
- n++;
- }
- else
- n = 2;
- cp--;
- break;
- }
- }
-
- if(w[0] != -2 && w[1] > 0 && w[0] > w[1])
- {
- c = *cp;
- *cp = '\0';
- errormsg(SH_DICT, ERROR_ERROR, "%s: bad word specifier", evp);
- *cp = c;
- DONE();
- }
-
- /* no valid word designator after colon, rewind */
- if(!(flag & HIST_WORDDSGN) && (*evp == ':'))
- cp = evp;
-
-getsel:
- /* open temp buffer, let sfio do the (re)allocation */
- tmp = sfopen(NULL, NULL, "swr");
-
- /* push selected words into buffer, squash
- whitespace into single blank or a newline */
- n = i = q = 0;
-
- while((c = sfgetc(ref)) > 0)
- {
- if(isspace(c))
- {
- flag |= (c == '\n' ? HIST_NEWLINE : 0);
- continue;
- }
-
- if(n >= w[0] && ((w[0] != -2) ? (w[1] < 0 || n <= w[1]) : 1))
- {
- if(w[0] < 0)
- sfseek(tmp, 0, SEEK_SET);
- else
- i = sftell(tmp);
-
- if(i > 0)
- sfputc(tmp, flag & HIST_NEWLINE ? '\n' : ' ');
-
- flag &= ~HIST_NEWLINE;
- p = 1;
- }
- else
- p = 0;
-
- do
- {
- cc = strchr(qc, c);
- q ^= cc ? 1<<(int)(cc - qc) : 0;
- if(p)
- sfputc(tmp, c);
- }
- while((c = sfgetc(ref)) > 0 && (!isspace(c) || q));
-
- if(w[0] == -2 && sftell(ref) > w[1])
- break;
-
- flag |= (c == '\n' ? HIST_NEWLINE : 0);
- n++;
- }
- if(w[0] != -2 && w[1] >= 0 && w[1] >= n)
- {
- c = *cp;
- *cp = '\0';
- errormsg(SH_DICT, ERROR_ERROR, "%s: bad word specifier", evp);
- *cp = c;
- DONE();
- }
- else if(w[1] == -2) /* skip last word */
- sfseek(tmp, i, SEEK_SET);
-
- /* remove trailing newline */
- if(sftell(tmp))
- {
- sfseek(tmp, -1, SEEK_CUR);
- if(sfgetc(tmp) == '\n')
- sfungetc(tmp, '\n');
- }
-
- sfputc(tmp, '\0');
-
- if(str)
- {
- if(wm)
- sfclose(wm);
- wm = tmp;
- }
-
- if(cc && (flag&HIST_HASH))
- {
- /* close !# temp file */
- sfclose(ref);
- flag &= ~HIST_HASH;
- free(cc);
- cc = 0;
- }
-
- evp = cp;
-
- /* selected line/words are now in buffer, now go for the modifiers */
- while(*cp == ':' || (flag & HIST_QUICKSUBST))
- {
- if(flag & HIST_QUICKSUBST)
- {
- flag &= ~HIST_QUICKSUBST;
- c = 's';
- cp--;
- }
- else
- c = *++cp;
-
- sfseek(tmp, 0, SEEK_SET);
- tmp2 = sfopen(tmp2, NULL, "swr");
-
- if(c == 'g') /* global substitution */
- {
- flag |= HIST_GLOBALSUBST;
- c = *++cp;
- }
-
- if(cc = strchr(modifiers, c))
- flag |= mod_flags[cc - modifiers];
- else
- {
- errormsg(SH_DICT, ERROR_ERROR, "%c: unrecognized history modifier", c);
- DONE();
- }
-
- if(c == 'h' || c == 'r') /* head or base */
- {
- n = -1;
- while((c = sfgetc(tmp)) > 0)
- { /* remember position of / or . */
- if((c == '/' && *cp == 'h') || (c == '.' && *cp == 'r'))
- n = sftell(tmp2);
- sfputc(tmp2, c);
- }
- if(n > 0)
- { /* rewind to last / or . */
- sfseek(tmp2, n, SEEK_SET);
- /* end string there */
- sfputc(tmp2, '\0');
- }
- }
- else if(c == 't' || c == 'e') /* tail or suffix */
- {
- n = 0;
- while((c = sfgetc(tmp)) > 0)
- { /* remember position of / or . */
- if((c == '/' && *cp == 't') || (c == '.' && *cp == 'e'))
- n = sftell(tmp);
- }
- /* rewind to last / or . */
- sfseek(tmp, n, SEEK_SET);
- /* copy from there on */
- while((c = sfgetc(tmp)) > 0)
- sfputc(tmp2, c);
- }
- else if(c == 's' || c == '&')
- {
- cp++;
-
- if(c == 's')
- {
- /* preset old with match from !?string? */
- if(!sb.str[0] && wm)
- sb.str[0] = strdup(sfsetbuf(wm, (Void_t*)1, 0));
- cp = parse_subst(cp, &sb);
- }
-
- if(!sb.str[0] || !sb.str[1])
- {
- c = *cp;
- *cp = '\0';
- errormsg(SH_DICT, ERROR_ERROR,
- "%s%s: no previous substitution",
- (flag & HIST_QUICKSUBST) ? ":s" : "",
- evp);
- *cp = c;
- DONE();
- }
-
- /* need pointer for strstr() */
- str = sfsetbuf(tmp, (Void_t*)1, 0);
-
- flag |= HIST_SUBSTITUTE;
- while(flag & HIST_SUBSTITUTE)
- {
- /* find string */
- if(cc = strstr(str, sb.str[0]))
- { /* replace it */
- c = *cc;
- *cc = '\0';
- sfputr(tmp2, str, -1);
- sfputr(tmp2, sb.str[1], -1);
- *cc = c;
- str = cc + strlen(sb.str[0]);
- }
- else if(!sftell(tmp2))
- { /* not successfull */
- c = *cp;
- *cp = '\0';
- errormsg(SH_DICT, ERROR_ERROR,
- "%s%s: substitution failed",
- (flag & HIST_QUICKSUBST) ? ":s" : "",
- evp);
- *cp = c;
- DONE();
- }
- /* loop if g modifier specified */
- if(!cc || !(flag & HIST_GLOBALSUBST))
- flag &= ~HIST_SUBSTITUTE;
- }
- /* output rest of line */
- sfputr(tmp2, str, -1);
- if(*cp)
- cp--;
- }
-
- if(sftell(tmp2))
- { /* if any substitions done, swap buffers */
- if(wm != tmp)
- sfclose(tmp);
- tmp = tmp2;
- tmp2 = 0;
- }
- cc = 0;
- if(*cp)
- cp++;
- }
-
- /* flush temporary buffer to stack */
- if(tmp)
- {
- sfseek(tmp, 0, SEEK_SET);
-
- if(flag & HIST_QUOTE)
- stakputc('\'');
-
- while((c = sfgetc(tmp)) > 0)
- {
- if(isspace(c))
- {
- flag = flag & ~HIST_NEWLINE;
-
- /* squash white space to either a
- blank or a newline */
- do
- flag |= (c == '\n' ? HIST_NEWLINE : 0);
- while((c = sfgetc(tmp)) > 0 && isspace(c));
-
- sfungetc(tmp, c);
-
- c = (flag & HIST_NEWLINE) ? '\n' : ' ';
-
- if(flag & HIST_QUOTE_BR)
- {
- stakputc('\'');
- stakputc(c);
- stakputc('\'');
- }
- else
- stakputc(c);
- }
- else if((c == '\'') && (flag & HIST_QUOTE))
- {
- stakputc('\'');
- stakputc('\\');
- stakputc(c);
- stakputc('\'');
- }
- else
- stakputc(c);
- }
- if(flag & HIST_QUOTE)
- stakputc('\'');
- }
- }
-
- stakputc('\0');
-
-done:
- if(cc && (flag&HIST_HASH))
- {
- /* close !# temp file */
- sfclose(ref);
- free(cc);
- cc = 0;
- }
-
- /* error? */
- if(staktell() && !(flag & HIST_ERROR))
- *xp = strdup(stakfreeze(1));
-
- /* restore shell stack */
- if(off)
- stakset(sp,off);
- else
- stakseek(0);
-
- /* drop temporary files */
-
- if(tmp && tmp != wm)
- sfclose(tmp);
- if(tmp2)
- sfclose(tmp2);
-
- return (flag & HIST_ERROR ? HIST_ERROR : flag & HIST_FLAG_RETURN_MASK);
-}
-
-#endif