da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/***********************************************************************
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* This software is part of the ast package *
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner* Copyright (c) 1982-2010 AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* and is licensed under the *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Common Public License, Version 1.0 *
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin* by AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* A copy of the License is available at *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* http://www.opensource.org/licenses/cpl1.0.txt *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Information and Software Systems Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* AT&T Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Florham Park NJ *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* David Korn <dgk@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin***********************************************************************/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#pragma prototyped
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * bash style history expansion
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Author:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Karsten Fleischer
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Omnium Software Engineering
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * An der Luisenburg 7
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * D-51379 Leverkusen
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Germany
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * <K.Fleischer@omnium.de>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "defs.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "edit.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if ! SHOPT_HISTEXPAND
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinNoN(hexpand)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char *modifiers = "htrepqxs&";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int mod_flags[] = { 0, 0, 0, 0, HIST_PRINT, HIST_QUOTE, HIST_QUOTE|HIST_QUOTE_BR, 0, 0 };
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define DONE() {flag |= HIST_ERROR; cp = 0; stakseek(0); goto done;}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstruct subst
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *str[2]; /* [0] is "old", [1] is "new" string */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * parse an /old/new/ string, delimiter expected as first char.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * if "old" not specified, keep sb->str[0]
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * if "new" not specified, set sb->str[1] to empty string
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * read up to third delimeter char, \n or \0, whichever comes first.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return adress is one past the last valid char in s:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * - the address containing \n or \0 or
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * - one char beyond the third delimiter
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char *parse_subst(const char *s, struct subst *sb)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *cp,del;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int off,n = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* build the strings on the stack, mainly for '&' substition in "new" */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin off = staktell();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* init "new" with empty string */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(sb->str[1])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free(sb->str[1]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sb->str[1] = strdup("");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* get delimiter */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin del = *s;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = (char*) s + 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(n < 2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*cp == del || *cp == '\n' || *cp == '\0')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* delimiter or EOL */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(staktell() != off)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* dupe string on stack and rewind stack */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc('\0');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(sb->str[n])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free(sb->str[n]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sb->str[n] = strdup(stakptr(off));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakseek(off);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* if not delimiter, we've reached EOL. Get outta here. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*cp != del)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(*cp == '\\')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*(cp+1) == del) /* quote delimiter */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc(del);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(*(cp+1) == '&' && n == 1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { /* quote '&' only in "new" */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc('&');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc('\\');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(*cp == '&' && n == 1 && sb->str[0])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* substitute '&' with "old" in "new" */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputs(sb->str[0]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc(*cp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* rewind stack */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakseek(off);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * history expansion main routine
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint hist_expand(const char *ln, char **xp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int off, /* stack offset */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin q, /* quotation flags */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p, /* flag */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c, /* current char */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag=0; /* HIST_* flags */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Sfoff_t n, /* history line number, counter, etc. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin i, /* counter */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[2]; /* word range */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *sp, /* stack pointer */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp, /* current char in ln */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *str, /* search string */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *evp, /* event/word designator string, for error msgs */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cc=0, /* copy of current line up to cp; temp ptr */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hc[3], /* default histchars */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *qc="\'\"`"; /* quote characters */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Sfio_t *ref=0, /* line referenced by event designator */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *tmp=0, /* temporary line buffer */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *tmp2=0;/* temporary line buffer */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Histloc_t hl; /* history location */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static Namval_t *np = 0; /* histchars variable */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static struct subst sb = {0,0}; /* substition strings */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static Sfio_t *wm=0; /* word match from !?string? event designator */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!wm)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin wm = sfopen(NULL, NULL, "swr");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hc[0] = '!';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hc[1] = '^';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hc[2] = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((np = nv_open("histchars",sh.var_tree,0)) && (cp = nv_getval(np)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cp[0])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hc[0] = cp[0];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cp[1])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hc[1] = cp[1];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cp[2])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hc[2] = cp[2];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* save shell stack */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(off = staktell())
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sp = stakfreeze(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = (char*)ln;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(cp && *cp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* read until event/quick substitution/comment designator */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((*cp != hc[0] && *cp != hc[1] && *cp != hc[2])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin || (*cp == hc[1] && cp != ln))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*cp == '\\') /* skip escaped designators */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc(*cp++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(*cp == '\'') /* skip quoted designators */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin do
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc(*cp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*++cp && *cp != '\'');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc(*cp++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin continue;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(hc[2] && *cp == hc[2]) /* history comment designator, skip rest of line */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc(*cp++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputs(cp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DONE();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin str = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag &= HIST_EVENT; /* save event flag for returning later */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin evp = cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ref = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*cp == hc[1]) /* shortcut substitution */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= HIST_QUICKSUBST;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto getline;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*cp == hc[0] && *(cp+1) == hc[0]) /* refer to line -1 */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp += 2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto getline;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch(c = *++cp) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case ' ':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '\t':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '\n':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '\0':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '=':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '(':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc(hc[0]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin continue;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '#': /* the line up to current position */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= HIST_HASH;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = staktell(); /* terminate string and dup */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc('\0');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cc = strdup(stakptr(0));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakseek(n); /* remove null byte again */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ref = sfopen(ref, cc, "s"); /* open as file */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = 0; /* skip history file referencing */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '-': /* back reference by number */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!isdigit(*(cp+1)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto string_event;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '0': /* reference by number */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '1':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '2':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '3':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '4':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '5':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '6':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '7':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '8':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '9':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(isdigit(*cp))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = n * 10 + (*cp++) - '0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c == '-')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = -n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '$':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case ':':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '?':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= HIST_QUESTION;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin string_event:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin default:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* read until end of string or word designator/modifier */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin str = cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*cp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((!(flag&HIST_QUESTION) &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*cp == ':' || isspace(*cp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin || *cp == '^' || *cp == '$'
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin || *cp == '*' || *cp == '-'
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin || *cp == '%')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin || ((flag&HIST_QUESTION) && (*cp == '?' || *cp == '\n')))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = *cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = '\0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chingetline:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= HIST_EVENT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(str) /* !string or !?string? event designator */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* search history for string */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hl = hist_find(sh.hist_ptr, str,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sh.hist_ptr->histind,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag&HIST_QUESTION, -1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n = hl.hist_command) == -1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = 0; /* not found */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n < 0) /* determine index for backref */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = sh.hist_ptr->histind + n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* search and use history file if found */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n > 0 && hist_seek(sh.hist_ptr, n) != -1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ref = sh.hist_ptr->histfp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!ref)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* string not found or command # out of range */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = *cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = '\0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT, ERROR_ERROR, "%s: event not found", evp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DONE();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(str) /* string search: restore orig. line */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(flag&HIST_QUESTION)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp++ = c; /* skip second question mark */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* colon introduces either word designators or modifiers */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*(evp = cp) == ':')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[0] = 0; /* -1 means last word, -2 means match from !?string? */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[1] = -1; /* -1 means last word, -2 means suppress last word */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(flag & HIST_QUICKSUBST) /* shortcut substitution */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto getsel;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(n < 2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch(c = *cp++) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '^': /* first word */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[0] = w[1] = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto skip;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto skip2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '$': /* last word */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[n] = -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto skip;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '%': /* match from !?string? event designator */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!str)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[0] = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[1] = -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ref = wm;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[0] = -2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[1] = sftell(ref) + hl.hist_char;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(wm, 0, SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto skip;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin default:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin skip2:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp--;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = 2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '*': /* until last word */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[0] = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[1] = -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin skip:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= HIST_WORDDSGN;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = 2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '-': /* until last word or specified index */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[1] = -2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= HIST_WORDDSGN;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '0':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '1':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '2':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '3':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '4':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '5':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '6':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '7':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '8':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '9': /* specify index */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((*evp == ':') || w[1] == -2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[n] = c - '0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(isdigit(c=*cp++))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[n] = w[n] * 10 + c - '0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= HIST_WORDDSGN;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w[1] = w[0];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = 2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp--;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(w[0] != -2 && w[1] > 0 && w[0] > w[1])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = *cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = '\0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT, ERROR_ERROR, "%s: bad word specifier", evp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DONE();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* no valid word designator after colon, rewind */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(flag & HIST_WORDDSGN) && (*evp == ':'))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = evp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chingetsel:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* open temp buffer, let sfio do the (re)allocation */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin tmp = sfopen(NULL, NULL, "swr");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* push selected words into buffer, squash
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin whitespace into single blank or a newline */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = i = q = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while((c = sfgetc(ref)) > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(isspace(c))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= (c == '\n' ? HIST_NEWLINE : 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin continue;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n >= w[0] && ((w[0] != -2) ? (w[1] < 0 || n <= w[1]) : 1))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(w[0] < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(tmp, 0, SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin i = sftell(tmp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(i > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputc(tmp, flag & HIST_NEWLINE ? '\n' : ' ');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag &= ~HIST_NEWLINE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin do
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cc = strchr(qc, c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin q ^= cc ? 1<<(int)(cc - qc) : 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(p)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputc(tmp, c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while((c = sfgetc(ref)) > 0 && (!isspace(c) || q));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(w[0] == -2 && sftell(ref) > w[1])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= (c == '\n' ? HIST_NEWLINE : 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(w[0] != -2 && w[1] >= 0 && w[1] >= n)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = *cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = '\0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT, ERROR_ERROR, "%s: bad word specifier", evp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DONE();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(w[1] == -2) /* skip last word */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(tmp, i, SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* remove trailing newline */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(sftell(tmp))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(tmp, -1, SEEK_CUR);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(sfgetc(tmp) == '\n')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfungetc(tmp, '\n');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputc(tmp, '\0');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(str)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(wm)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfclose(wm);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin wm = tmp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cc && (flag&HIST_HASH))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* close !# temp file */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfclose(ref);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag &= ~HIST_HASH;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free(cc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cc = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin evp = cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* selected line/words are now in buffer, now go for the modifiers */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*cp == ':' || (flag & HIST_QUICKSUBST))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(flag & HIST_QUICKSUBST)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag &= ~HIST_QUICKSUBST;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = 's';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp--;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = *++cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(tmp, 0, SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin tmp2 = sfopen(tmp2, NULL, "swr");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c == 'g') /* global substitution */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= HIST_GLOBALSUBST;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = *++cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cc = strchr(modifiers, c))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= mod_flags[cc - modifiers];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT, ERROR_ERROR, "%c: unrecognized history modifier", c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DONE();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c == 'h' || c == 'r') /* head or base */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while((c = sfgetc(tmp)) > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { /* remember position of / or . */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((c == '/' && *cp == 'h') || (c == '.' && *cp == 'r'))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = sftell(tmp2);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputc(tmp2, c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { /* rewind to last / or . */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(tmp2, n, SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* end string there */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputc(tmp2, '\0');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(c == 't' || c == 'e') /* tail or suffix */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while((c = sfgetc(tmp)) > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { /* remember position of / or . */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((c == '/' && *cp == 't') || (c == '.' && *cp == 'e'))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = sftell(tmp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* rewind to last / or . */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(tmp, n, SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* copy from there on */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while((c = sfgetc(tmp)) > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputc(tmp2, c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(c == 's' || c == '&')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c == 's')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* preset old with match from !?string? */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!sb.str[0] && wm)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sb.str[0] = strdup(sfsetbuf(wm, (Void_t*)1, 0));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = parse_subst(cp, &sb);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!sb.str[0] || !sb.str[1])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = *cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = '\0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT, ERROR_ERROR,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "%s%s: no previous substitution",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (flag & HIST_QUICKSUBST) ? ":s" : "",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin evp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DONE();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* need pointer for strstr() */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin str = sfsetbuf(tmp, (Void_t*)1, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= HIST_SUBSTITUTE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(flag & HIST_SUBSTITUTE)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* find string */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cc = strstr(str, sb.str[0]))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { /* replace it */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = *cc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cc = '\0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputr(tmp2, str, -1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputr(tmp2, sb.str[1], -1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cc = c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin str = cc + strlen(sb.str[0]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(!sftell(tmp2))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { /* not successfull */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = *cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = '\0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT, ERROR_ERROR,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "%s%s: substitution failed",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (flag & HIST_QUICKSUBST) ? ":s" : "",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin evp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DONE();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* loop if g modifier specified */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!cc || !(flag & HIST_GLOBALSUBST))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag &= ~HIST_SUBSTITUTE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* output rest of line */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputr(tmp2, str, -1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*cp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp--;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(sftell(tmp2))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { /* if any substitions done, swap buffers */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(wm != tmp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfclose(tmp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin tmp = tmp2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin tmp2 = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cc = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*cp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* flush temporary buffer to stack */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(tmp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(tmp, 0, SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(flag & HIST_QUOTE)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc('\'');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while((c = sfgetc(tmp)) > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(isspace(c))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag = flag & ~HIST_NEWLINE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* squash white space to either a
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin blank or a newline */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin do
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag |= (c == '\n' ? HIST_NEWLINE : 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while((c = sfgetc(tmp)) > 0 && isspace(c));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfungetc(tmp, c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = (flag & HIST_NEWLINE) ? '\n' : ' ';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(flag & HIST_QUOTE_BR)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc('\'');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc(c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc('\'');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc(c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if((c == '\'') && (flag & HIST_QUOTE))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc('\'');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc('\\');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc(c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc('\'');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc(c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(flag & HIST_QUOTE)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc('\'');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc('\0');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chindone:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cc && (flag&HIST_HASH))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* close !# temp file */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfclose(ref);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free(cc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cc = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* error? */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(staktell() && !(flag & HIST_ERROR))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *xp = strdup(stakfreeze(1));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* restore shell stack */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(off)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakset(sp,off);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakseek(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* drop temporary files */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(tmp && tmp != wm)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfclose(tmp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(tmp2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfclose(tmp2);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (flag & HIST_ERROR ? HIST_ERROR : flag & HIST_FLAG_RETURN_MASK);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif