Esempio n. 1
0
File: deparse.c Progetto: att/ast
static_fn void p_arg(const struct argnod *arg, int endchar, int opts) {
    int flag = -1;

    do {
        if (!arg->argnxt.ap) {
            flag = endchar;
        } else if (opts & PRE) {  // case alternation lists in reverse order
            p_arg(arg->argnxt.ap, '|', opts);
            flag = endchar;
        } else if (opts) {
            flag = ' ';
        }
        const char *cp = arg->argval;
        if (*cp == 0 && (arg->argflag & ARG_EXP) && arg->argchn.ap) {
            int c = (arg->argflag & ARG_RAW) ? '>' : '<';
            sfputc(outfile, c);
            sfputc(outfile, '(');
            p_tree((Shnode_t *)arg->argchn.ap, 0);
            sfputc(outfile, ')');
        } else if (*cp == 0 && opts == POST && arg->argchn.ap) {  // compound assignment
            struct fornod *fp = (struct fornod *)arg->argchn.ap;
            sfprintf(outfile, "%s=(\n", fp->fornam);
            sfnputc(outfile, '\t', ++level);
            p_tree(fp->fortre, 0);
            if (--level) sfnputc(outfile, '\t', level);
            sfputc(outfile, ')');
        } else if ((arg->argflag & ARG_RAW) && (cp[1] || (*cp != '[' && *cp != ']'))) {
            cp = sh_fmtq(cp);
        }
        sfputr(outfile, cp, flag);
        if (flag == '\n') begin_line = 1;
        arg = arg->argnxt.ap;
    } while ((opts & POST) && arg);
}
Esempio n. 2
0
static int paste(int nstream,Sfio_t* streams[],Sfio_t *out, register const char *delim, int dsiz, int dlen, Delim_t* mp)
{
	register const char *cp;
	register int d, n, i, z, more=1;
	register Sfio_t *fp;
	do
	{
		d = (dlen>0?0:-1);
		for(n=more-1,more=0; n < nstream;)
		{
			if(fp=streams[n])
			{
				if(cp = sfgetr(fp,'\n',0))
				{
					if(n==0)
						more = 1;
					else if(!more) /* first stream with output */
					{
						if(dsiz == 1)
							sfnputc(out, *delim, n);
						else if(dlen>0)
						{
							for(d=n; d>dlen; d-=dlen)
								sfwrite(out,delim,dsiz);
							if(d)
							{
								if(mp)
									for (i = z = 0; i < d; i++)
										z += mp[i].len;
								else
									z = d;
								sfwrite(out,delim,z);
							}
						}
						more = n+1;
					}
					if(sfwrite(out,cp,sfvalue(fp)-((n+1)<nstream)) < 0)
						return(-1);
				}
				else
					streams[n] = 0;
			}
			if(++n<nstream && more && d>=0)
			{
				register int c;
				if(d >= dlen)
					d = 0;
				if(mp)
					sfwrite(out,mp[d].chr,mp[d].len);
				else if(c=delim[d])
					sfputc(out,c);
				d++;
			}
			else if(n==nstream && !streams[n-1] && more)
				sfputc(out,'\n');
		}
	} while(more);
	return(0);
}
Esempio n. 3
0
static void p_arg(register const struct argnod *arg,register int endchar,int opts)
{
	register const char *cp;
	register int flag;
	do
	{
		if(!arg->argnxt.ap)
			flag = endchar;
		else if(opts&PRE)
		{
			/* case alternation lists in reverse order */
			p_arg(arg->argnxt.ap,'|',opts);
			flag = endchar;
		}
		else if(opts)
			flag = ' ';
		cp = arg->argval;
		if(*cp==0 && opts==POST && arg->argchn.ap)
		{
			/* compound assignment */
			struct fornod *fp=(struct fornod*)arg->argchn.ap;
			sfprintf(outfile,"%s=(\n",fp->fornam);
			sfnputc(outfile,'\t',++level);
			p_tree(fp->fortre,0);
			if(--level)
				sfnputc(outfile,'\t',level);
			sfputc(outfile,')');
		}
		else if((arg->argflag&ARG_RAW) && (cp[1] || (*cp!='[' && *cp!=']')))
			cp = sh_fmtq(cp);
		sfputr(outfile,cp,flag);
		if(flag=='\n')
			begin_line = 1;
		arg = arg->argnxt.ap;
	}
	while((opts&POST) && arg);
	return;
}
Esempio n. 4
0
File: deparse.c Progetto: att/ast
static_fn void p_switch(const struct regnod *reg) {
    if (level > 1) sfnputc(outfile, '\t', level - 1);
    p_arg(reg->regptr, ')', PRE);
    begin_line = 0;
    sfputc(outfile, '\t');
    if (reg->regcom) p_tree(reg->regcom, 0);
    level++;
    if (reg->regflag) {
        p_keyword(";&", END);
    } else {
        p_keyword(";;", END);
    }
    if (reg->regnxt) p_switch(reg->regnxt);
}
Esempio n. 5
0
File: deparse.c Progetto: att/ast
// Print a keyword.
// Increment indent level for flag==BEGIN.
// Decrement indent level for flag==END.
static_fn void p_keyword(const char *word, int flag) {
    int sep;

    if (flag == END) {
        sep = end_line;
    } else if (*word == '[' || *word == '(') {
        sep = ' ';
    } else {
        sep = '\t';
    }
    if (flag != BEGIN) level--;
    if (begin_line && level) sfnputc(outfile, '\t', level);
    sfputr(outfile, word, sep);
    if (sep == '\n') {
        begin_line = 1;
    } else {
        begin_line = 0;
    }
    if (flag != END) level++;
}
Esempio n. 6
0
/*
 * print a keyword
 * increment indent level for flag==BEGIN
 * decrement indent level for flag==END
 */
static void p_keyword(const char *word,int flag)
{
	register int sep;
	if(flag==END)
		sep = end_line;
	else if(*word=='[' || *word=='(')
		sep = ' ';
	else
		sep = '\t';
	if(flag!=BEGIN)
		level--;
	if(begin_line && level)
		sfnputc(outfile,'\t',level);
	sfputr(outfile,word,sep);
	if(sep=='\n')
		begin_line=1;
	else
		begin_line=0;
	if(flag!=END)
		level++;
}
Esempio n. 7
0
static void banner(const char *string,const char *delim,int width)
{
	register unsigned mask;
	register int c,i,n,j = strlen(string);
	register const char *cp,*dp;
	register unsigned char* map;
	
	map = ccmap(CC_NATIVE, CC_ASCII);
	if(j > width/8)
		error(ERROR_exit(1),"up to %d char%s per arg",width/8,(width/8)==1?"":"s");
	for(i=0; i < CHAR_HEIGHT; i++)
	{
		dp = delim;
		for (n = 0, cp = string; c = ccmapchr(map, *cp++) & 0x07f; dp++)
		{
			if(*dp==0)
				dp = delim;
			if((mask = bandata[c][i])==0)
			{
				n += 8;
				continue;
			}
			for(j=0x80; j>0; j >>=1)
			{
				if(mask&j)
				{
					if(n)
					{
						sfnputc(sfstdout,' ',n);
						n = 0;
					}
					sfputc(sfstdout,*dp);
				}
				else
					n++;
			}
		}
		sfputc(sfstdout,'\n');
	}
}
Esempio n. 8
0
File: deparse.c Progetto: att/ast
// Print script corresponding to shell tree <t>.
static_fn void p_tree(const Shnode_t *t, int tflags) {
    char *cp = NULL;
    int save = end_line;
    int needbrace = (tflags & NEED_BRACE);
    int bracket = 0;

    tflags &= ~NEED_BRACE;
    if (tflags & NO_NEWLINE) {
        end_line = ' ';
    } else {
        end_line = '\n';
    }
    int cmd_type = t->tre.tretyp & COMMSK;
    switch (cmd_type) {
        case TTIME: {
            if (t->tre.tretyp & COMSCAN) {
                p_keyword("!", BEGIN);
            } else {
                p_keyword("time", BEGIN);
            }
            if (t->par.partre) p_tree(t->par.partre, tflags);
            level--;
            break;
        }
        case TCOM: {
            if (begin_line && level > 0) sfnputc(outfile, '\t', level);
            begin_line = 0;
            p_comarg((struct comnod *)t);
            break;
        }
        case TSETIO: {
            if (t->tre.tretyp & FPCL) {
                tflags |= NEED_BRACE;
            } else {
                tflags = NO_NEWLINE | NEED_BRACE;
            }
            p_tree(t->fork.forktre, tflags);
            p_redirect(t->fork.forkio);
            break;
        }
        case TFORK: {
            if (needbrace) tflags |= NEED_BRACE;
            if (t->tre.tretyp & (FAMP | FCOOP)) {
                tflags = NEED_BRACE | NO_NEWLINE;
                end_line = ' ';
            } else if (t->fork.forkio) {
                tflags = NO_NEWLINE;
            }
            p_tree(t->fork.forktre, tflags);
            if (t->fork.forkio) p_redirect(t->fork.forkio);
            if (t->tre.tretyp & FCOOP) {
                sfputr(outfile, "|&", '\n');
                begin_line = 1;
            } else if (t->tre.tretyp & FAMP) {
                sfputr(outfile, "&", '\n');
                begin_line = 1;
            }
            break;
        }
        case TIF: {
            p_keyword("if", BEGIN);
            p_tree(t->if_.iftre, 0);
            p_keyword("then", MIDDLE);
            p_tree(t->if_.thtre, 0);
            if (t->if_.eltre) {
                p_keyword("else", MIDDLE);
                p_tree(t->if_.eltre, 0);
            }
            p_keyword("fi", END);
            break;
        }
        case TWH: {
            if (t->wh.whinc) {
                cp = "for";
            } else if (t->tre.tretyp & COMSCAN) {
                cp = "until";
            } else {
                cp = "while";
            }
            p_keyword(cp, BEGIN);
            if (t->wh.whinc) {
                struct argnod *arg = (t->wh.whtre)->ar.arexpr;
                sfprintf(outfile, "(( %s; ", forinit);
                forinit = "";
                sfputr(outfile, arg->argval, ';');
                arg = (t->wh.whinc)->arexpr;
                sfprintf(outfile, " %s))\n", arg->argval);
            } else {
                p_tree(t->wh.whtre, 0);
            }
            t = t->wh.dotre;
            p_keyword("do", MIDDLE);
            p_tree(t, 0);
            p_keyword("done", END);
            break;
        }
        case TLST: {
            Shnode_t *tr = t->lst.lstrit;
            if (tr->tre.tretyp == TWH && tr->wh.whinc && t->lst.lstlef->tre.tretyp == TARITH) {
                // Arithmetic for statement.
                struct argnod *init = (t->lst.lstlef)->ar.arexpr;
                forinit = init->argval;
                p_tree(t->lst.lstrit, tflags);
                break;
            }
            if (needbrace) p_keyword("{", BEGIN);
            p_tree(t->lst.lstlef, 0);
            if (needbrace) tflags = 0;
            p_tree(t->lst.lstrit, tflags);
            if (needbrace) p_keyword("}", END);
            break;
        }
        case TAND:
        case TORF:
        case TFIL: {
            if (cmd_type == TAND) {
                cp = "&&";
            } else if (cmd_type == TORF) {
                cp = "||";
            } else {
                cp = "|";
            }
            if (t->tre.tretyp & TTEST) {
                tflags |= NO_NEWLINE;
                if (!(tflags & NO_BRACKET)) {
                    p_keyword("[[", BEGIN);
                    tflags |= NO_BRACKET;
                    bracket = 1;
                }
            }
            p_tree(t->lst.lstlef, NEED_BRACE | NO_NEWLINE | (tflags & NO_BRACKET));
            if (tflags & FALTPIPE) {
                Shnode_t *tt = t->lst.lstrit;
                if (tt->tre.tretyp != TFIL || !(tt->lst.lstlef->tre.tretyp & FALTPIPE)) {
                    sfputc(outfile, '\n');
                    return;
                }
            }
            sfputr(outfile, cp, here_doc ? '\n' : ' ');
            if (here_doc) {
                here_body(here_doc);
                here_doc = 0;
            }
            level++;
            p_tree(t->lst.lstrit, tflags | NEED_BRACE);
            if (bracket) p_keyword("]]", END);
            level--;
            break;
        }
        case TPAR: {
            p_keyword("(", BEGIN);
            p_tree(t->par.partre, 0);
            p_keyword(")", END);
            break;
        }
        case TARITH: {
            struct argnod *ap = t->ar.arexpr;
            if (begin_line && level) sfnputc(outfile, '\t', level);
            sfprintf(outfile, "(( %s ))%c", ap->argval, end_line);
            if (!(tflags & NO_NEWLINE)) begin_line = 1;
            break;
        }
        case TFOR: {
            cp = ((t->tre.tretyp & COMSCAN) ? "select" : "for");
            p_keyword(cp, BEGIN);
            sfputr(outfile, t->for_.fornam, ' ');
            if (t->for_.forlst) {
                sfputr(outfile, "in", ' ');
                tflags = end_line;
                end_line = '\n';
                p_comarg(t->for_.forlst);
                end_line = tflags;
            } else {
                sfputc(outfile, '\n');
            }
            begin_line = 1;
            t = t->for_.fortre;
            p_keyword("do", MIDDLE);
            p_tree(t, 0);
            p_keyword("done", END);
            break;
        }
        case TSW: {
            p_keyword("case", BEGIN);
            p_arg(t->sw.swarg, ' ', 0);
            if (t->sw.swlst) {
                begin_line = 1;
                sfputr(outfile, "in", '\n');
                tflags = end_line;
                end_line = '\n';
                p_switch(t->sw.swlst);
                end_line = tflags;
            }
            p_keyword("esac", END);
            break;
        }
        case TFUN: {
            if (t->tre.tretyp & FPOSIX) {
                sfprintf(outfile, "%s", t->funct.functnam);
                p_keyword("()\n", BEGIN);
            } else {
                p_keyword("function", BEGIN);
                tflags = (t->funct.functargs ? ' ' : '\n');
                sfputr(outfile, t->funct.functnam, tflags);
                if (t->funct.functargs) {
                    tflags = end_line;
                    end_line = '\n';
                    p_comarg(t->funct.functargs);
                    end_line = tflags;
                }
            }
            begin_line = 1;
            p_keyword("{\n", MIDDLE);
            begin_line = 1;
            p_tree(t->funct.functtre, 0);
            p_keyword("}", END);
            break;
        }
        case TTST: {  // new test compound command
            if (!(tflags & NO_BRACKET)) p_keyword("[[", BEGIN);
            if ((t->tre.tretyp & TPAREN) == TPAREN) {
                p_keyword("(", BEGIN);
                p_tree(t->lst.lstlef, NO_BRACKET | NO_NEWLINE);
                p_keyword(")", END);
            } else {
                int flags = (t->tre.tretyp) >> TSHIFT;
                if (t->tre.tretyp & TNEGATE) sfputr(outfile, "!", ' ');
                if (t->tre.tretyp & TUNARY) {
                    un_op[1] = flags;
                    sfputr(outfile, un_op, ' ');
                } else {
                    cp = ((char *)(shtab_testops + (flags & 037) - 1)->sh_name);
                }
                p_arg(&(t->lst.lstlef->arg), ' ', 0);
                if (t->tre.tretyp & TBINARY) {
                    assert(cp);
                    sfputr(outfile, cp, ' ');
                    p_arg(&(t->lst.lstrit->arg), ' ', 0);
                }
            }
            if (!(tflags & NO_BRACKET)) p_keyword("]]", END);
        }
        default: { break; }
    }

    while (begin_line && here_doc) {
        here_body(here_doc);
        here_doc = 0;
    }
    end_line = save;
}
Esempio n. 9
0
File: args.c Progetto: att/ast
// Print option settings on standard output.
// If mode is inclusive or of PRINT_*.
// If <mask> is set, only options with this mask value are displayed.
void sh_printopts(Shell_t *shp, Shopt_t oflags, int mode, Shopt_t *mask) {
    const Shtable_t *tp;
    const char *name;
    int on;
    int value;

    if (!(mode & PRINT_NO_HEADER)) sfputr(sfstdout, sh_translate(e_heading), '\n');
    if (mode & PRINT_TABLE) {
        size_t w;
        int c;
        int r;
        int i;

        c = 0;
        for (tp = shtab_options; (value = tp->sh_number); tp++) {
            if (mask && !is_option(mask, value & 0xff)) continue;
            name = tp->sh_name;
            if (name[0] == 'n' && name[1] == 'o' && name[2] != 't') name += 2;
            if (c < (w = strlen(name))) c = w;
        }
        c += 4;
        w = ed_window();
        if (w < 2 * c) w = 2 * c;
        r = w / c;
        i = 0;
        for (tp = shtab_options; (value = tp->sh_number); tp++) {
            if (mask && !is_option(mask, value & 0xff)) continue;
            on = is_option(&oflags, value);
            name = tp->sh_name;
            if (name[0] == 'n' && name[1] == 'o' && name[2] != 't') {
                name += 2;
                on = !on;
            }
            if (++i >= r) {
                i = 0;
                sfprintf(sfstdout, "%s%s\n", on ? "" : "no", name);
            } else {
                sfprintf(sfstdout, "%s%-*s", on ? "" : "no", on ? c : (c - 2), name);
            }
        }
        if (i) sfputc(sfstdout, '\n');
        return;
    }

    if (!(mode & (PRINT_ALL | PRINT_VERBOSE))) {  // only print set options
        if (mode & PRINT_SHOPT) {
            sfwrite(sfstdout, "shopt -s", 3);
        } else {
            sfwrite(sfstdout, "set --default", 13);
        }
    }
    for (tp = shtab_options; (value = tp->sh_number); tp++) {
        if (mask && !is_option(mask, value & 0xff)) continue;
        if (sh_isoption(shp, SH_BASH)) {
            if (!(mode & PRINT_SHOPT) != !(value & SH_BASHOPT)) continue;
        } else if (value & (SH_BASHEXTRA | SH_BASHOPT)) {
            continue;
        }
        on = is_option(&oflags, value);
        name = tp->sh_name;
        if (name[0] == 'n' && name[1] == 'o' && name[2] != 't') {
            name += 2;
            on = !on;
        }
        if (mode & PRINT_VERBOSE) {
            sfputr(sfstdout, name, ' ');
            sfnputc(sfstdout, ' ', 24 - strlen(name));
            sfputr(sfstdout, on ? sh_translate(e_on) : sh_translate(e_off), '\n');
        } else if (mode & PRINT_ALL) {  // print unset options also
            if (mode & PRINT_SHOPT) {
                sfprintf(sfstdout, "shopt -%c %s\n", on ? 's' : 'u', name);
            } else {
                sfprintf(sfstdout, "set %co %s\n", on ? '-' : '+', name);
            }
        } else if (!(value & SH_COMMANDLINE) && is_option(&oflags, value & 0xff)) {
            sfprintf(sfstdout, " %s%s%s", (mode & PRINT_SHOPT) ? "" : "--", on ? "" : "no", name);
        }
    }
    if (!(mode & (PRINT_VERBOSE | PRINT_ALL))) sfputc(sfstdout, '\n');
}
Esempio n. 10
0
static void genvalue(Sfio_t *out, Shclass_t *sp, int indent, Namval_t *npar)
{
	Shfield_t *fp = sp->fields;
	Namval_t *np, **nodes= (Namval_t**)(sp+1);
	register int i,isarray;
	if(out)
	{
		sfwrite(out,"(\n",2);
		indent++;
	}
	for(i=0; i < sp->nelem; i++,fp++)
	{
#if 0
		/* handle recursive case */
#endif
		if(!(np=nodes[i]) && out)
			np = sh_newnode(fp,npar);
		if(np)
		{
			isarray=0;
			if(nv_isattr(np,NV_ARRAY))
			{
				isarray=1;
				if(array_elem(nv_arrayptr(np))==0)
					isarray=2;
				else
					nv_putsub(np,(char*)0,ARRAY_SCAN);
			}
			sfnputc(out,'\t',indent);
			sfputr(out,fp->name,(isarray==2?'\n':'='));
			if(isarray)
			{
				if(isarray==2)
					continue;
				sfwrite(out,"(\n",2);
				sfnputc(out,'\t',++indent);
			}
			while(1)
			{
				char *fmtq;
				if(isarray)
				{
					sfprintf(out,"[%s]",sh_fmtq(nv_getsub(np)));
					sfputc(out,'=');
				}
				if(!(fmtq=nv_getval(np)) || !(fmtq=sh_fmtq(fmtq)))
					fmtq = "";
				sfputr(out,fmtq,'\n');
				if(!nv_nextsub(np))
					break;
				sfnputc(out,'\t',indent);
			}
			if(isarray)
			{
				sfnputc(out,'\t',--indent);
				sfwrite(out,")\n",2);
			}
		}
	}
	if(out)
	{
		if(indent>1)
			sfnputc(out,'\t',indent-1);
		sfputc(out,')');
	}
}
Esempio n. 11
0
File: tsize.c Progetto: att/ast
tmain() {
    UNUSED(argc);
    UNUSED(argv);
    Sfio_t *f, *f2;
    char *s;
    int i, n;
    char buf[16 * 1024];

    if (!(f = sfopen(NULL, tstfile("sf", 0), "w+"))) terror("Can't open file");

    if (sfnputc(f, 'a', 1000) != 1000) terror("Writing");

    if (sfseek(f, (Sfoff_t)0, 0) != 0) terror("Seeking");

    if ((n = (int)sfsize(f)) != 1000) terror("Wrong size %d", n);

    if (!(f2 = sfnew(NULL, NULL, (size_t)SF_UNBOUND, sffileno(f), SF_WRITE))) {
        terror("Can't open stream");
    }

    if (sfseek(f2, (Sfoff_t)1999, 0) != (Sfoff_t)1999) terror("Seeking2");
    sfputc(f2, 'b');
    sfsync(f2);
    if ((n = (int)sfsize(f2)) != 2000) terror("Wrong size2 %d", n);

    if ((n = (int)sfsize(f)) != 1000) terror("Wrong size3 %d", n);

    sfputc(f, 'a');
    sfset(f, SF_SHARE, 1);
    if ((n = (int)sfsize(f)) != 2000) terror("Wrong size4 %d", n);

    if (!(f = sfopen(f, NULL, "srw"))) terror("Can't open string stream");

    sfwrite(f, "0123456789", 10);
    if (sfsize(f) != 10) terror("String size is wrong1");
    sfseek(f, (Sfoff_t)19, 0);
    if (sfsize(f) != 10) terror("String size is wrong2");
    sfputc(f, 'a');
    if (sfsize(f) != 20) terror("String size is wrong3");
    sfseek(f, (Sfoff_t)0, 0);
    if (sfsize(f) != 20) terror("String size is wrong4");
    sfseek(f, (Sfoff_t)0, 0);
    if (!(s = sfreserve(f, SF_UNBOUND, SF_LOCKR)) && sfvalue(f) != 20) {
        terror("String size is wrong5");
    }
    sfread(f, s, 5);
    if (sfsize(f) != 20) terror("String size is wrong6");
    sfwrite(f, "01234567890123456789", 20);
    if (sfsize(f) != 25) terror("String size is wrong7");

    strcpy(buf, "0123456789");
    if (!(f = sfopen(f, buf, "s+"))) terror("Can't open string stream2");
    if (sfset(f, 0, 0) & SF_MALLOC) terror("SF_MALLOC should not have been set");
    if (sfsize(f) != 10) terror("String size is wrong8");
    sfread(f, buf, 5);
    if ((n = (int)sfwrite(f, "0123456789", 10)) != 5) terror("Write wrong amount %d", n);
    if (sfsize(f) != 10) terror("String size is wrong9");

    if (!(f = sfopen(f, tstfile("sf", 0), "w"))) terror("Reopening file1");
    for (i = 0; i < 10000; ++i) {
        if (sfputc(f, '0' + (i % 10)) != '0' + (i % 10)) terror("sfputc failed");
    }

    if (!(f = sfopen(f, tstfile("sf", 0), "r+"))) terror("Reopening file2");
    if (sfsize(f) != 10000) terror("Bad size of file1");

    sfsetbuf(f, buf, 1024);
    for (i = 0; i < 20; ++i) {
        if (!sfreserve(f, 100, 0)) terror("Reserve failed");
    }

    s = buf + 1024;
    for (i = 0; i < 20; ++i) s[i] = '0' + i % 10;
    sfseek(f, (Sfoff_t)(10000 - 10), 0);
    if (sfwrite(f, s, 20) != 20) terror("Write failed");
    if (sfsize(f) != 10010) terror("Bad size of file2");
    sfseek(f, (Sfoff_t)0, 0);
    for (i = 0; i < 10; ++i) {
        if (!(s = sfreserve(f, 1001, 0))) terror("Reserve failed2");
        if (s[0] != '0' + i) terror("Bad data1");
    }
    for (n = 0; n < 1001; ++n) {
        if (s[n] != ((n + i - 1) % 10 + '0')) terror("Bad data");
    }

    /* test to see if a string stream extends ok during writes */
    s = malloc(5);
    f = sfnew(NULL, (void *)s, 5, -1, SF_STRING | SF_READ | SF_WRITE | SF_MALLOC);
    if (!f) terror("Can't create string stream");
    if (sfwrite(f, "01", 2) != 2) terror("Bad write to string stream");
    if (sfwrite(f, "2345678", 7) != 7) terror("Bad write to string stream2");
    if (sfputc(f, 0) != 0) terror("sfputc failed");
    if (sfseek(f, (Sfoff_t)0, 0) != 0) terror("sfseek failed");
    if ((n = (int)sfread(f, buf, 100)) != 10) terror("sfread gets wrong amount of data %d", n);
    if (strcmp(buf, "012345678") != 0) terror("Get wrong data");

    texit(0);
}