Esempio n. 1
0
File: tungetc.c Progetto: att/ast
tmain() {
    UNUSED(argc);
    UNUSED(argv);
    Sfio_t *f;
    char *str, *alpha, *s;
    char buf[128];
    int n;

    str = "0123456789";
    alpha = "abcdefghijklmnop";

    if (!(f = sfopen(NULL, alpha, "s"))) terror("Opening stream");

    for (n = 9; n >= 0; --n) {
        if (sfungetc(f, n + '0') != n + '0') terror("Ungetc");
    }

    if (!(s = sfreserve(f, SF_UNBOUND, 0)) || sfvalue(f) != 10) terror("Peek stream1");
    if (strncmp(s, str, 10) != 0) terror("Bad data1");

    if (!(s = sfreserve(f, SF_UNBOUND, 0)) || sfvalue(f) != (ssize_t)strlen(alpha)) {
        terror("Peek stream2");
    }
    if (strncmp(s, alpha, strlen(alpha)) != 0) terror("Bad data2");

    sfseek(f, (Sfoff_t)0, 0);
    for (n = 9; n >= 0; --n) {
        if (sfungetc(f, n + '0') != n + '0') terror("Ungetc2");
    }
    if (sfgetc(f) != '0') terror("Sfgetc");
    sfseek(f, (Sfoff_t)0, 0);
    if (!(s = sfreserve(f, SF_UNBOUND, 0)) || sfvalue(f) != (ssize_t)strlen(alpha)) {
        terror("Peek stream3");
    }
    if (strncmp(s, alpha, strlen(alpha)) != 0) terror("Bad data2");

    sfseek(f, (Sfoff_t)0, 0);
    if (sfungetc(f, '0') != '0') terror("Ungetc3");

    strcpy(buf, "0123456789\n");
    if (!(f = sfopen(f, buf, "s+"))) terror("Reopening  string");
    if (sfungetc(f, '\n') != '\n') terror("Can't unget new-line2");
    if (sfungetc(f, 'd') != 'd') terror("Can't unget d");
    if (sfungetc(f, 'c') != 'c') terror("Can't unget c");
    if (sfungetc(f, '\n') != '\n') terror("Can't unget new-line");
    if (sfungetc(f, 'b') != 'b') terror("Can't unget b");
    if (sfungetc(f, 'a') != 'a') terror("Can't unget a");

    if (!(s = sfgetr(f, '\n', 1)) || strcmp(s, "ab") != 0) terror("Did not get ab");
    if (!(s = sfgetr(f, '\n', 1)) || strcmp(s, "cd") != 0) terror("Did not get cd");
    if (!(s = sfgetr(f, '\n', 1)) || strcmp(s, "0123456789") != 0) terror("Did not get 0123456789");

    texit(0);
}
Esempio n. 2
0
int
pzfile(Pz_t* pz)
{
	unsigned char*	s;
	int		i;
	int		j;
	size_t		n;

	/*
	 * 0 or more nul's mean clean EOF
	 */

	while (!(i = sfgetc(pz->io)));
	if (pz->disc->errorf)
		(*pz->disc->errorf)(pz, pz->disc, -1, "%s: pzfile: i=%02x", pz->path, i);
	if (i == -1)
		return 0;
	if (i == PZ_MARK_TAIL)
	{
		/*
		 * file trailer
		 */

		while ((n = sfgetu(pz->io)) && !sferror(pz->io) && !sfeof(pz->io) && (s = (unsigned char*)sfreserve(pz->io, n, 0)))
			if (pz->disc->eventf && (*pz->disc->eventf)(pz, PZ_TAILREAD, s, n, pz->disc) < 0)
				return -1;
		if ((i = sfgetc(pz->io)) == -1)
			return 0;
	}
	j = sfgetc(pz->io);
	if (pz->disc->errorf)
		(*pz->disc->errorf)(pz, pz->disc, -1, "%s: pzfile: i=%02x j=%02x", pz->path, i, j);
	if (i == PZ_MAGIC_1 && j == PZ_MAGIC_2)
	{
		/*
		 * next file header
		 */

		sfungetc(pz->io, j);
		sfungetc(pz->io, i);
		return pzopen(pz->disc, (char*)pz, PZ_AGAIN) ? 1 : -1;
	}
	if (pz->disc->errorf)
		(*pz->disc->errorf)(pz, pz->disc, 2, "%s: data corrupted", pz->path);
	return -1;
}
Esempio n. 3
0
wint_t
ungetwc(wint_t c, Sfio_t* f)
{
	register unsigned char*	s = (unsigned char*)&c;
	register unsigned char*	e = s + sizeof(c);

	STDIO_INT(f, "ungetwc", wint_t, (wint_t, Sfio_t*), (c, f))

	FWIDE(f, WEOF);
	while (s < e)
		if (sfungetc(f, *s++) == EOF)
			return WEOF;
	return c;
}
Esempio n. 4
0
static int read_tree(Namval_t* np, Sfio_t *iop, int n, Namfun_t *dp)
{
	Sfio_t	*sp;
	char	*cp;
	int	c;
	if(n>=0)
		return(-1);
	while((c = sfgetc(iop)) &&  isblank(c));
	sfungetc(iop,c);
	sfprintf(sh.strbuf,"%s=%c",nv_name(np),0);
	cp = sfstruse(sh.strbuf);
	sp = sfopen((Sfio_t*)0,cp,"s");
	sfstack(iop,sp);
	c=sh_eval(iop,SH_READEVAL);
	return(c);
}
Esempio n. 5
0
/* is there stuff left?  if not, go to next file */
static int advFile(generalStream_s *gs)
{
  if (gs->fpLen == -1) {
    int c = sfgetc(gs->fp);
    if (c == EOF)
      return 0;
    sfungetc(gs->fp, c);
    return 1;
  } else {
    if (sftell(gs->fp) == gs->fpLen) {
      while (++gs->count < gs->numFilesinStream) {
	HRSclosefile(gs->fp);
	gs->fp = HRSopenfile(gs->fileNames[gs->count], "r");
	gs->fpLen = sfsize(gs->fp);
	if (gs->fpLen != 0)
	  return 1;
      }
      return 0;
    }

    return 1;
  }
  
}
Esempio n. 6
0
static void
flatten(const char* path, Sfio_t* ip, Sfio_t* op)
{
	register int	c;
	register int	q;
	register int	p;
	register int	b;
	register char*	s;

	char		tag[256];

	b = p = 0;
	for (;;)
	{
		switch (c = sfgetc(ip))
		{
		case EOF:
			break;
		case '<':
			q = 0;
			s = tag;
			for (;;)
			{
				switch (c = sfgetc(ip))
				{
				case EOF:
					return;
				case '>':
					sfungetc(ip, c);
					break;
				default:
					if (isspace(c))
						break;
					if (s < &tag[sizeof(tag)-1])
						*s++ = islower(c) ? toupper(c) : c;
					continue;
				}
				break;
			}
			*s = 0;
			q = 0;
			for (;;)
			{
				switch (c = sfgetc(ip))
				{
				case EOF:
					return;
				case '\'':
				case '"':
					if (q == c)
						q = 0;
					else if (q == 0)
						q = c;
					continue;
				case '>':
					if (q == 0)
						break;
					continue;
				default:
					continue;
				}
				break;
			}
			s = tag;
			if (s[0] == 'T' && s[1] == 'D' && s[2] == 0)
				p = 1;
			else if (s[0] == '/' && s[1] == 'T')
			{
				if (s[2] == 'D' && s[3] == 0)
				{
					b = p = 0;
					sfputc(op, ';');
				}
				else if (s[2] == 'R' && s[3] == 0)
					sfputc(op, '\n');
			}
			continue;
		default:
			if (p)
			{
				if (isspace(c))
				{
					if (b)
						continue;
					b = 1;
					c = ' ';
				}
				else
					b = 0;
				sfputc(op, c);
			}
			continue;
		}
		break;
	}
}
Esempio n. 7
0
static int
ncsl(register Sfio_t* sp)
{
	register int		c;
	register int		data;
	register unsigned long	line;
	int			quote;

	line = 0;
	data = 0;
 again:
	for (;;) switch (c = sfgetc(sp))
	{
	case EOF:
		return(line);
	case ' ':
	case '\f':
	case '\t':
		break;
	case '\n':
	newline:
		if (data)
		{
			if (data > 0) line++;
			data = 0;
		}
		break;
	case '/':
		if (data < 0) goto again;
		switch (c = sfgetc(sp))
		{
		case '/':
			for (;;) switch (c = sfgetc(sp))
			{
			case EOF:
				goto again;
			case '\n':
				goto newline;
			default:
				if (JUNK(c))
				{
					data = -1;
					goto again;
				}
				break;
			}
			break;
		case '*':
			for (;;) switch (c = sfgetc(sp))
			{
			case EOF:
			case '*':
				for (;;)
				{
					switch (c = sfgetc(sp))
					{
					case EOF:
					case '/':
						goto again;
					case '*':
						continue;
					default:
						if (JUNK(c))
						{
							data = -1;
							goto again;
						}
						break;
					}
					break;
				}
				break;
			default:
				if (JUNK(c))
				{
					data = -1;
					goto again;
				}
				break;
			}
			break;
		case EOF:
			break;
		default:
			if (!data) data = 1;
			sfungetc(sp, c);
			break;
		}
		break;
	case '"':
	case '\'':
		if (data < 0) goto again;
		data = 1;
		quote = c;
		for (;;) switch (c = sfgetc(sp))
		{
		case EOF:
			goto again;
		case '"':
		case '\'':
			if (c == quote) goto again;
			break;
		case '\n':
			goto newline;
		case '\\':
			switch (c = sfgetc(sp))
			{
			case EOF:
				goto again;
			case '\n':
				line++;
				continue;
			}
			/*FALLTHROUGH*/
		default:
			if (JUNK(c))
			{
				data = -1;
				goto again;
			}
			break;
		}
		break;
	default:
		if (JUNK(c)) data = -1;
		else if (!data) data = 1;
		break;
	}
	/*NOTREACHED*/
}
Esempio n. 8
0
int
pzinflate(register Pz_t* pz, Sfio_t* op)
{
	register Pzpart_t*	pp;
	register int		i;
	register int		j;
	register int		k;
	register size_t		n;
	register size_t		m;
	register unsigned char*	pat;
	ssize_t			r;
	Pzwrite_f		writef;

	if (!(pz->flags & PZ_READ))
	{
		if (pz->disc->errorf)
			(*pz->disc->errorf)(pz, pz->disc, ERROR_SYSTEM|2, "%s: cannot inflate -- not open for read", pz->path);
		return -1;
	}
	if (pz->flags & PZ_SPLIT)
		return pzssplit(pz);
	if (pz->flags & PZ_FORCE)
	{
		if (writef = pz->disc->writef)
		{
			n = pz->part->row;
			do
			{
				if (!(pat = (unsigned char*)sfreserve(pz->io, n, 0)))
				{
					if (sfvalue(pz->io))
					{
						if (pz->disc->errorf)
							(*pz->disc->errorf)(pz, pz->disc, 2, "%s: data corrupted", pz->path);
						return -1;
					}
					break;
				}
			} while ((r = (*writef)(pz, op, pat, pz->disc)) >= 0);
			if (r < 0)
				return -1;
		}
		else if (sfmove(pz->io, op, SF_UNBOUND, -1) < 0 || sferror(pz->io))
		{
			if (pz->disc->errorf)
				(*pz->disc->errorf)(pz, pz->disc, 2, "%s: data corrupted", pz->path);
			return -1;
		}
		if (sfsync(op))
		{
			if (pz->disc->errorf)
				(*pz->disc->errorf)(pz, pz->disc, 2, "%s: output write error", pz->path);
			return -1;
		}
		return 0;
	}

	/*
	 * copy the prefix
	 */

	if (pz->prefix.count)
	{
		if (!pz->prefix.skip && pz->prefix.data && sfwrite(op, pz->prefix.data, pz->prefix.count) != pz->prefix.count)
		{
			if (pz->disc->errorf)
				(*pz->disc->errorf)(pz, pz->disc, 2, "%s: output write error", pz->path);
			return -1;
		}
		pz->prefix.count = 0;
	}
	if ((pz->split.flags & (PZ_SPLIT_INFLATE|PZ_SPLIT_PART)) == PZ_SPLIT_INFLATE)
		i = pzsinflate(pz, op);
	else
	{
		/*
		 * inflate each file
		 */

		do
		{
			/*
			 * inflate each window
			 */

			pp = pz->part;
			pat = pz->pat;
			while (m = sfgetu(pz->io))
			{
				/*
				 * hi frequency data in pz->buf
				 */

				if (pp->nmap)
				{
					if (m > pz->win || (m % pp->nmap) || sfread(pz->io, pz->buf, m) != m)
					{
						if (pz->disc->errorf)
							(*pz->disc->errorf)(pz, pz->disc, ERROR_SYSTEM|2, "%s: data corrupted", pz->path);
						return -1;
					}
					n = m / pp->nmap;
					m = 0;
					j = 0;
					k = 0;
					for (i = 0; i < pp->nmap; i++)
					{
						if (i > 0 && pp->lab[i] == pp->lab[i - 1])
							j++;
						else
							j = m;
						if (!pp->value || pp->value[i] < 0)
							pp->mix[k++] = pz->buf + j;
						m += n;
					}
				}
				else if (m != 1)
				{
					if (pz->disc->errorf)
						(*pz->disc->errorf)(pz, pz->disc, ERROR_SYSTEM|2, "%s: data corrupted", pz->path);
					return -1;
				}

				/*
				 * lo frequency
				 */

				m = sfgetu(pz->io);
				if (m < pp->row || sfread(pz->io, pat, pp->row) != pp->row)
				{
					if (pz->disc->errorf)
						(*pz->disc->errorf)(pz, pz->disc, ERROR_SYSTEM|2, "%s: data corrupted", pz->path);
					return -1;
				}
				m -= pp->row;
				if (sfread(pz->io, pz->nxt = pz->val, m) != m)
				{
					if (pz->disc->errorf)
						(*pz->disc->errorf)(pz, pz->disc, ERROR_SYSTEM|2, "%s: data corrupted", pz->path);
					return -1;
				}

				/*
				 * restore lo+hi on op
				 */

				if (restore(pz, pp, pz->io, op, pat, pz->wrk, pp->row, k, pp->map, pp->mix, pp->inc))
					return -1;
			}
			if (!(pz->flags & PZ_SECTION))
			{
				if ((k = sfgetc(pz->io)) == PZ_MARK_PART)
				{
					if ((m = sfgetu(pz->io)) && !sferror(pz->io) && !sfeof(pz->io) && (pat = (unsigned char*)sfreserve(pz->io, m, 0)))
						sfwrite(op, pat, m);
				}
				else if (k != EOF)
					sfungetc(pz->io, k);
			}
			if (sferror(op))
			{
				if (pz->disc->errorf)
					(*pz->disc->errorf)(pz, pz->disc, ERROR_SYSTEM|2, "write error");
				return -1;
			}
		} while ((i = !(pz->flags & PZ_SECTION)) && (i = pzfile(pz)) > 0);
	}
	if (i >= 0 && !(pz->split.flags & PZ_SPLIT_PART) && sfsync(op))
	{
		if (pz->disc->errorf)
			(*pz->disc->errorf)(pz, pz->disc, ERROR_SYSTEM|2, "write error");
		return -1;
	}
	return i;
}
Esempio n. 9
0
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++;
		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;
		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(shgd->hist_ptr, str,
				       shgd->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 = shgd->hist_ptr->histind + n;
			/* search and use history file if found */
			if(n > 0 && hist_seek(shgd->hist_ptr, n) != -1)
				ref = shgd->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;
				}
			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);
}