Esempio n. 1
0
static void
unparse_stmt_catch(Stream * str, struct Stmt_Catch catchstmt, int indent)
{
    Except_Arm *ex;

    stream_add_string(str, "try");
    output(str);
    unparse_stmt(catchstmt.body, indent + 2);
    for (ex = catchstmt.excepts; ex; ex = ex->next) {
	indent_stmt(str, indent);
	stream_add_string(str, "except ");
	if (ex->id >= 0)
	    stream_printf(str, "%s ", prog->var_names[ex->id]);
	stream_add_char(str, '(');
	if (ex->codes)
	    unparse_arglist(str, ex->codes);
	else
	    stream_add_string(str, "ANY");
	stream_add_char(str, ')');
	output(str);
	unparse_stmt(ex->stmt, indent + 2);
    }
    indent_stmt(str, indent);
    stream_add_string(str, "endtry");
    output(str);
}
Esempio n. 2
0
static void
unparse_stmt_cond(Stream * str, struct Stmt_Cond cond, int indent)
{
    Cond_Arm *elseifs;

    stream_add_string(str, "if (");
    unparse_expr(str, cond.arms->condition);
    stream_add_char(str, ')');
    output(str);
    unparse_stmt(cond.arms->stmt, indent + 2);
    for (elseifs = cond.arms->next; elseifs; elseifs = elseifs->next) {
	indent_stmt(str, indent);
	stream_add_string(str, "elseif (");
	unparse_expr(str, elseifs->condition);
	stream_add_char(str, ')');
	output(str);
	unparse_stmt(elseifs->stmt, indent + 2);
    }
    if (cond.otherwise) {
	indent_stmt(str, indent);
	stream_add_string(str, "else");
	output(str);
	unparse_stmt(cond.otherwise, indent + 2);
    }
    indent_stmt(str, indent);
    stream_add_string(str, "endif");
    output(str);
}
Esempio n. 3
0
static void
bracket_le(Stream * str, enum Expr_Kind parent, Expr * child)
{
    if ((fully_parenthesize && expr_prec[child->kind] < expr_prec[EXPR_PROP])
	|| expr_prec[parent] >= expr_prec[child->kind]) {
	stream_add_char(str, '(');
	unparse_expr(str, child);
	stream_add_char(str, ')');
    } else {
	unparse_expr(str, child);
    }
}
Esempio n. 4
0
static void
indent_stmt(Stream * str, int indent)
{
    int i;

    if (indent_code)
	for (i = 0; i < indent; i++)
	    stream_add_char(str, ' ');
}
Esempio n. 5
0
static void
unparse_name_expr(Stream * str, Expr * expr)
{
    /*
     * Handle the right-hand expression in EXPR_PROP and EXPR_VERB.
     * If it's a simple string literal with the syntax of an identifier,
     * just print the name.  Otherwise, use parens and unparse the
     * expression normally.
     */

    if (expr->kind == EXPR_VAR && expr->e.var.type == TYPE_STR
	&& ok_identifier(expr->e.var.v.str)) {
	stream_add_string(str, expr->e.var.v.str);
	return;
    }
    /* We need to use the full unparser */
    stream_add_char(str, '(');
    unparse_expr(str, expr);
    stream_add_char(str, ')');
}
Esempio n. 6
0
static void
unparse_stmt_list(Stream * str, struct Stmt_List list, int indent)
{
    stream_printf(str, "for %s in (", prog->var_names[list.id]);
    unparse_expr(str, list.expr);
    stream_add_char(str, ')');
    output(str);
    unparse_stmt(list.body, indent + 2);
    indent_stmt(str, indent);
    stream_add_string(str, "endfor");
    output(str);
}
Esempio n. 7
0
static void
unparse_arglist(Stream * str, Arg_List * args)
{
    while (args) {
	if (args->kind == ARG_SPLICE)
	    stream_add_char(str, '@');
	unparse_expr(str, args->expr);
	if (args->next)
	    stream_add_string(str, ", ");
	args = args->next;
    }
}
Esempio n. 8
0
static void
unparse_stmt_range(Stream * str, struct Stmt_Range range, int indent)
{
    stream_printf(str, "for %s in [", prog->var_names[range.id]);
    unparse_expr(str, range.from);
    stream_add_string(str, "..");
    unparse_expr(str, range.to);
    stream_add_char(str, ']');
    output(str);
    unparse_stmt(range.body, indent + 2);
    indent_stmt(str, indent);
    stream_add_string(str, "endfor");
    output(str);
}
Esempio n. 9
0
static void
unparse_stmt_fork(Stream * str, struct Stmt_Fork fork_stmt, int indent)
{
    if (fork_stmt.id >= 0)
	stream_printf(str, "fork %s (", prog->var_names[fork_stmt.id]);
    else
	stream_add_string(str, "fork (");
    unparse_expr(str, fork_stmt.time);
    stream_add_char(str, ')');
    output(str);
    unparse_stmt(fork_stmt.body, indent + 2);
    indent_stmt(str, indent);
    stream_add_string(str, "endfork");
    output(str);
}
Esempio n. 10
0
static void
unparse_scatter(Stream * str, Scatter * sc)
{
    while (sc) {
	switch (sc->kind) {
	case SCAT_REST:
	    stream_add_char(str, '@');
	    /* fall thru to ... */
	case SCAT_REQUIRED:
	    stream_add_string(str, prog->var_names[sc->id]);
	    break;
	case SCAT_OPTIONAL:
	    stream_printf(str, "?%s", prog->var_names[sc->id]);
	    if (sc->expr) {
		stream_add_string(str, " = ");
		unparse_expr(str, sc->expr);
	    }
	}
	if (sc->next)
	    stream_add_string(str, ", ");
	sc = sc->next;
    }
}
Esempio n. 11
0
static void
disassemble(Program * prog, Printer p, void *data)
{
    Stream *s = new_stream(100);
    Stream *insn = new_stream(50);
    int i, l;
    unsigned pc;
    Bytecodes bc;
    const char *ptr;
    const char **names = prog->var_names;
    unsigned tmp, num_names = prog->num_var_names;
#   define NAMES(i)	(tmp = i,					\
			 tmp < num_names ? names[tmp]			\
					 : "*** Unknown variable ***")
    Var *literals = prog->literals;

    initialize_tables();
    print = p;
    print_data = data;
    stream_printf(s, "Language version number: %d", (int) prog->version);
    output(s);
    stream_printf(s, "First line number: %d", prog->first_lineno);
    output(s);

    for (i = -1; i < 0 || i < prog->fork_vectors_size; i++) {
	output(s);
	if (i == -1) {
	    stream_printf(s, "Main code vector:");
	    output(s);
	    stream_printf(s, "=================");
	    output(s);
	    bc = prog->main_vector;
	} else {
	    stream_printf(s, "Forked code vector %d:", i);
	    l = stream_length(s);
	    output(s);
	    while (l--)
		stream_add_char(s, '=');
	    output(s);
	    bc = prog->fork_vectors[i];
	}

	stream_printf(s, "[Bytes for labels = %d, literals = %d, ",
		      bc.numbytes_label, bc.numbytes_literal);
	stream_printf(s, "forks = %d, variables = %d, stack refs = %d]",
		      bc.numbytes_fork, bc.numbytes_var_name,
		      bc.numbytes_stack);
	output(s);
	stream_printf(s, "[Maximum stack size = %d]", bc.max_stack);
	output(s);

	max_bytes_width = 5;

	for (pc = 0; pc < bc.size;) {
	    Byte b;
	    unsigned arg;
#	    define ADD_BYTES(n)	(arg = add_bytes(s, bc.vector, pc, n),	\
				 pc += n,				\
				 arg)
	    unsigned a1, a2;

	    new_insn(s, pc);
	    b = add_bytes(s, bc.vector, pc++, 1);
	    if (b != OP_EXTENDED)
		stream_add_string(insn, COUNT_TICK(b) ? " * " : "   ");
	    if (IS_OPTIM_NUM_OPCODE(b))
		stream_printf(insn, "NUM %d", OPCODE_TO_OPTIM_NUM(b));
#ifdef BYTECODE_REDUCE_REF
	    else if (IS_PUSH_CLEAR_n(b))
		stream_printf(insn, "PUSH_CLEAR %s", NAMES(PUSH_CLEAR_n_INDEX(b)));
#endif /* BYTECODE_REDUCE_REF */
	    else if (IS_PUSH_n(b))
		stream_printf(insn, "PUSH %s", NAMES(PUSH_n_INDEX(b)));
	    else if (IS_PUT_n(b))
		stream_printf(insn, "PUT %s", NAMES(PUT_n_INDEX(b)));
	    else if (b == OP_EXTENDED) {
		b = ADD_BYTES(1);
		stream_add_string(insn, COUNT_EOP_TICK(b) ? " * " : "   ");
		stream_add_string(insn, ext_mnemonics[b]);
		switch ((Extended_Opcode) b) {
		case EOP_WHILE_ID:
		    a1 = ADD_BYTES(bc.numbytes_var_name);
		    a2 = ADD_BYTES(bc.numbytes_label);
		    stream_printf(insn, " %s %d", NAMES(a1), a2);
		    break;
		case EOP_EXIT_ID:
		    stream_printf(insn, " %s",
				  NAMES(ADD_BYTES(bc.numbytes_var_name)));
		    /* fall thru */
		case EOP_EXIT:
		    a1 = ADD_BYTES(bc.numbytes_stack);
		    a2 = ADD_BYTES(bc.numbytes_label);
		    stream_printf(insn, " %d %d", a1, a2);
		    break;
		case EOP_PUSH_LABEL:
		case EOP_END_CATCH:
		case EOP_END_EXCEPT:
		case EOP_TRY_FINALLY:
		    stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_label));
		    break;
		case EOP_TRY_EXCEPT:
		    stream_printf(insn, " %d", ADD_BYTES(1));
		    break;
		case EOP_LENGTH:
		    stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_stack));
		    break;
		case EOP_SCATTER:
		    {
			int i, nargs = ADD_BYTES(1);

			a1 = ADD_BYTES(1);
			a2 = ADD_BYTES(1);
			stream_printf(insn, " %d/%d/%d:", nargs, a1, a2);
			for (i = 0; i < nargs; i++) {
			    a1 = ADD_BYTES(bc.numbytes_var_name);
			    a2 = ADD_BYTES(bc.numbytes_label);
			    stream_printf(insn, " %s/%d", NAMES(a1), a2);
			}
			stream_printf(insn, " %d",
				      ADD_BYTES(bc.numbytes_label));
		    }
		    break;
		default:
		    break;
		}
	    } else {
		stream_add_string(insn, mnemonics[b]);
		switch ((Opcode) b) {
		case OP_IF:
		case OP_IF_QUES:
		case OP_EIF:
		case OP_AND:
		case OP_OR:
		case OP_JUMP:
		case OP_WHILE:
		    stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_label));
		    break;
		case OP_FORK:
		    stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_fork));
		    break;
		case OP_FORK_WITH_ID:
		    a1 = ADD_BYTES(bc.numbytes_fork);
		    a2 = ADD_BYTES(bc.numbytes_var_name);
		    stream_printf(insn, " %d %s", a1, NAMES(a2));
		    break;
		case OP_FOR_LIST:
		case OP_FOR_RANGE:
		    a1 = ADD_BYTES(bc.numbytes_var_name);
		    a2 = ADD_BYTES(bc.numbytes_label);
		    stream_printf(insn, " %s %d", NAMES(a1), a2);
		    break;
		case OP_G_PUSH:
#ifdef BYTECODE_REDUCE_REF
		case OP_G_PUSH_CLEAR:
#endif /* BYTECODE_REDUCE_REF */
		case OP_G_PUT:
		    stream_printf(insn, " %s",
				  NAMES(ADD_BYTES(bc.numbytes_var_name)));
		    break;
		case OP_IMM:
		    {
			Var v;

			v = literals[ADD_BYTES(bc.numbytes_literal)];
			switch (v.type) {
			case TYPE_OBJ:
			    stream_printf(insn, " #%d", v.v.obj);
			    break;
			case TYPE_INT:
			    stream_printf(insn, " %d", v.v.num);
			    break;
			case TYPE_STR:
			    stream_add_string(insn, " \"");
			    for (ptr = v.v.str; *ptr; ptr++) {
				if (*ptr == '"' || *ptr == '\\')
				    stream_add_char(insn, '\\');
				stream_add_char(insn, *ptr);
			    }
			    stream_add_char(insn, '"');
			    break;
			case TYPE_ERR:
			    stream_printf(insn, " %s", error_name(v.v.err));
			    break;
			default:
			    stream_printf(insn, " <literal type = %d>",
					  v.type);
			    break;
			}
		    }
		    break;
		case OP_BI_FUNC_CALL:
		    stream_printf(insn, " %s", name_func_by_num(ADD_BYTES(1)));
		default:
		    break;
		}
	    }

	    finish_insn(s, insn);
	}
    }

    free_stream(s);
    free_stream(insn);
}
Esempio n. 12
0
static const char *
translate_pattern(const char *pattern, int *tpatlen)
{
    /* Translate a MOO pattern into a more standard syntax.  Effectively, this
     * just involves converting from `%' escapes into `\' escapes.
     */

    static Stream *s = 0;
    const char *p = pattern;
    char c;

    if (!s)
	s = new_stream(100);

    while (*p) {
	switch (c = *p++) {
	case '%':
	    c = *p++;
	    if (!c)
		goto fail;
	    else if (strchr(".*+?[^$|()123456789bB<>wW", c))
		stream_add_char(s, '\\');
	    stream_add_char(s, c);
	    break;
	case '\\':
	    stream_add_string(s, "\\\\");
	    break;
	case '[':
	    /* Any '%' or '\' characters inside a charset should be copied
	     * over without translation. */
	    stream_add_char(s, c);
	    c = *p++;
	    if (c == '^') {
		stream_add_char(s, c);
		c = *p++;
	    }
	    /* This is the only place a ']' can appear and not be the end of
	     * the charset. */
	    if (c == ']') {
		stream_add_char(s, c);
		c = *p++;
	    }
	    while (c && c != ']') {
		stream_add_char(s, c);
		c = *p++;
	    }
	    if (!c)
		goto fail;
	    else
		stream_add_char(s, c);
	    break;
	default:
	    stream_add_char(s, c);
	    break;
	}
    }

    *tpatlen = stream_length(s);
    return reset_stream(s);

  fail:
    reset_stream(s);
    return 0;
}
Esempio n. 13
0
int
network_process_io(int timeout)
{
    network_handle nh;
    static server_handle sh;
    static Stream *s = 0;
    char buffer[1024];
    int count;
    char *ptr, *end;
    int got_some = 0;

    if (s == 0) {
	int flags;

	s = new_stream(1000);

	if ((flags = fcntl(0, F_GETFL)) < 0
	    || fcntl(0, F_SETFL, flags | NONBLOCK_FLAG) < 0) {
	    log_perror("Setting standard input non-blocking");
	    return 0;
	}
    }
    switch (state) {
    case STATE_CLOSED:
	if (listening) {
	    sh = server_new_connection(slistener, nh, 0);
	    state = STATE_OPEN;
	    got_some = 1;
	} else if (timeout != 0)
	    sleep(timeout);
	break;

    case STATE_OPEN:
	for (;;) {
	    while (!input_suspended
		   && (count = read(0, buffer, sizeof(buffer))) > 0) {
		got_some = 1;
		if (binary) {
		    stream_add_string(s, raw_bytes_to_binary(buffer, count));
		    server_receive_line(sh, reset_stream(s));
		} else
		    for (ptr = buffer, end = buffer + count;
			 ptr < end;
			 ptr++) {
			unsigned char c = *ptr;

			if (isgraph(c) || c == ' ' || c == '\t')
			    stream_add_char(s, c);
			else if (c == '\n')
			    server_receive_line(sh, reset_stream(s));
		    }
	    }

	    if (got_some || timeout == 0)
		goto done;

	    sleep(1);
	    timeout--;
	}
    }

  done:
    return got_some;
}
Esempio n. 14
0
static void
unparse_expr(Stream * str, Expr * expr)
{
    switch (expr->kind) {
    case EXPR_PROP:
	if (expr->e.bin.lhs->kind == EXPR_VAR
	    && expr->e.bin.lhs->e.var.type == TYPE_OBJ
	    && expr->e.bin.lhs->e.var.v.obj == 0
	    && expr->e.bin.rhs->kind == EXPR_VAR
	    && expr->e.bin.rhs->e.var.type == TYPE_STR
	    && ok_identifier(expr->e.bin.rhs->e.var.v.str)) {
	    stream_add_char(str, '$');
	    stream_add_string(str, expr->e.bin.rhs->e.var.v.str);
	} else {
	    bracket_lt(str, EXPR_PROP, expr->e.bin.lhs);
	    if (expr->e.bin.lhs->kind == EXPR_VAR
		&& expr->e.bin.lhs->e.var.type == TYPE_INT)
		/* avoid parsing digits followed by dot as floating-point */
		stream_add_char(str, ' ');
	    stream_add_char(str, '.');
	    unparse_name_expr(str, expr->e.bin.rhs);
	}
	break;

    case EXPR_VERB:
	if (expr->e.verb.obj->kind == EXPR_VAR
	    && expr->e.verb.obj->e.var.type == TYPE_OBJ
	    && expr->e.verb.obj->e.var.v.obj == 0
	    && expr->e.verb.verb->kind == EXPR_VAR
	    && expr->e.verb.verb->e.var.type == TYPE_STR
	    && ok_identifier(expr->e.verb.verb->e.var.v.str)) {
	    stream_add_char(str, '$');
	    stream_add_string(str, expr->e.verb.verb->e.var.v.str);
	} else {
	    bracket_lt(str, EXPR_VERB, expr->e.verb.obj);
	    stream_add_char(str, ':');
	    unparse_name_expr(str, expr->e.verb.verb);
	}
	stream_add_char(str, '(');
	unparse_arglist(str, expr->e.verb.args);
	stream_add_char(str, ')');
	break;

    case EXPR_INDEX:
	bracket_lt(str, EXPR_INDEX, expr->e.bin.lhs);
	stream_add_char(str, '[');
	unparse_expr(str, expr->e.bin.rhs);
	stream_add_char(str, ']');
	break;

    case EXPR_RANGE:
	bracket_lt(str, EXPR_RANGE, expr->e.range.base);
	stream_add_char(str, '[');
	unparse_expr(str, expr->e.range.from);
	stream_add_string(str, "..");
	unparse_expr(str, expr->e.range.to);
	stream_add_char(str, ']');
	break;

	/* left-associative binary operators */
    case EXPR_PLUS:
    case EXPR_MINUS:
    case EXPR_TIMES:
    case EXPR_DIVIDE:
    case EXPR_MOD:
    case EXPR_AND:
    case EXPR_OR:
    case EXPR_EQ:
    case EXPR_NE:
    case EXPR_LT:
    case EXPR_GT:
    case EXPR_LE:
    case EXPR_GE:
    case EXPR_IN:
	bracket_lt(str, expr->kind, expr->e.bin.lhs);
	stream_add_string(str, binop_string[expr->kind]);
	bracket_le(str, expr->kind, expr->e.bin.rhs);
	break;

	/* right-associative binary operators */
    case EXPR_EXP:
	bracket_le(str, expr->kind, expr->e.bin.lhs);
	stream_add_string(str, binop_string[expr->kind]);
	bracket_lt(str, expr->kind, expr->e.bin.rhs);
	break;

    case EXPR_COND:
	bracket_le(str, EXPR_COND, expr->e.cond.condition);
	stream_add_string(str, " ? ");
	unparse_expr(str, expr->e.cond.consequent);
	stream_add_string(str, " | ");
	bracket_le(str, EXPR_COND, expr->e.cond.alternate);
	break;

    case EXPR_NEGATE:
	stream_add_char(str, '-');
	bracket_lt(str, EXPR_NEGATE, expr->e.expr);
	break;

    case EXPR_NOT:
	stream_add_char(str, '!');
	bracket_lt(str, EXPR_NOT, expr->e.expr);
	break;

    case EXPR_VAR:
	stream_add_string(str, value_to_literal(expr->e.var));
	break;

    case EXPR_ASGN:
	unparse_expr(str, expr->e.bin.lhs);
	stream_add_string(str, " = ");
	unparse_expr(str, expr->e.bin.rhs);
	break;

    case EXPR_CALL:
	stream_add_string(str, name_func_by_num(expr->e.call.func));
	stream_add_char(str, '(');
	unparse_arglist(str, expr->e.call.args);
	stream_add_char(str, ')');
	break;

    case EXPR_ID:
	stream_add_string(str, prog->var_names[expr->e.id]);
	break;

    case EXPR_LIST:
	stream_add_char(str, '{');
	unparse_arglist(str, expr->e.list);
	stream_add_char(str, '}');
	break;

    case EXPR_SCATTER:
	stream_add_char(str, '{');
	unparse_scatter(str, expr->e.scatter);
	stream_add_char(str, '}');
	break;

    case EXPR_CATCH:
	stream_add_string(str, "`");
	unparse_expr(str, expr->e.catchexp.tryexp);
	stream_add_string(str, " ! ");
	if (expr->e.catchexp.codes)
	    unparse_arglist(str, expr->e.catchexp.codes);
	else
	    stream_add_string(str, "ANY");
	if (expr->e.catchexp.except) {
	    stream_add_string(str, " => ");
	    unparse_expr(str, expr->e.catchexp.except);
	}
	stream_add_string(str, "'");
	break;

    case EXPR_LENGTH:
	stream_add_string(str, "$");
	break;

    default:
	errlog("UNPARSE_EXPR: Unknown Expr_Kind: %d\n", expr->kind);
	stream_add_string(str, "(?!?!?!?!?)");
	break;
    }
}
Esempio n. 15
0
static void
unparse_stmt(Stmt * stmt, int indent)
{
    Stream *str = new_stream(100);

    while (stmt) {
	indent_stmt(str, indent);
	switch (stmt->kind) {
	case STMT_COND:
	    unparse_stmt_cond(str, stmt->s.cond, indent);
	    break;
	case STMT_LIST:
	    unparse_stmt_list(str, stmt->s.list, indent);
	    break;
	case STMT_RANGE:
	    unparse_stmt_range(str, stmt->s.range, indent);
	    break;
	case STMT_FORK:
	    unparse_stmt_fork(str, stmt->s.fork, indent);
	    break;
	case STMT_EXPR:
	    unparse_expr(str, stmt->s.expr);
	    stream_add_char(str, ';');
	    output(str);
	    break;
	case STMT_WHILE:
	    if (stmt->s.loop.id == -1)
		stream_add_string(str, "while (");
	    else
		stream_printf(str, "while %s (",
			      prog->var_names[stmt->s.loop.id]);
	    unparse_expr(str, stmt->s.loop.condition);
	    stream_add_char(str, ')');
	    output(str);
	    unparse_stmt(stmt->s.loop.body, indent + 2);
	    indent_stmt(str, indent);
	    stream_add_string(str, "endwhile");
	    output(str);
	    break;
	case STMT_RETURN:
	    if (stmt->s.expr) {
		stream_add_string(str, "return ");
		unparse_expr(str, stmt->s.expr);
	    } else
		stream_add_string(str, "return");
	    stream_add_char(str, ';');
	    output(str);
	    break;
	case STMT_TRY_EXCEPT:
	    unparse_stmt_catch(str, stmt->s.catchexp, indent);
	    break;
	case STMT_TRY_FINALLY:
	    stream_add_string(str, "try");
	    output(str);
	    unparse_stmt(stmt->s.finally.body, indent + 2);
	    indent_stmt(str, indent);
	    stream_add_string(str, "finally");
	    output(str);
	    unparse_stmt(stmt->s.finally.handler, indent + 2);
	    indent_stmt(str, indent);
	    stream_add_string(str, "endtry");
	    output(str);
	    break;
	case STMT_BREAK:
	case STMT_CONTINUE:
	    {
		const char *kwd = (stmt->kind == STMT_BREAK ? "break"
				   : "continue");

		if (stmt->s.exit == -1)
		    stream_printf(str, "%s;", kwd);
		else
		    stream_printf(str, "%s %s;", kwd,
				  prog->var_names[stmt->s.exit]);
		output(str);
	    }
	    break;
	default:
	    errlog("UNPARSE_STMT: Unknown Stmt_Kind: %d\n", stmt->kind);
	    stream_add_string(str, "?!?!?!?;");
	    output(str);
	    break;
	}
	stmt = stmt->next;
    }

    free_stream(str);
}
Esempio n. 16
0
void
stream_printf(Stream * s, const char *fmt,...)
{
    char buffer[40];
    va_list args;

    va_start(args, fmt);
    while (*fmt) {
	char c = *fmt;

	if (c == '%') {
	    char pad = ' ';
	    int width = 0, base;
	    const char *string = "";	/* initialized to silence warning */

	    while ((c = *(++fmt)) != '\0') {
		switch (c) {
		case 's':
		    string = va_arg(args, char *);
		    break;
		case 'x':
		    base = 16;
		    goto finish_number;
		case 'o':
		    base = 8;
		    goto finish_number;
		case 'd':
		    base = 10;
		  finish_number:
		    string = itoa(va_arg(args, int), base);
		    break;
		case 'g':
		    sprintf(buffer, dbl_fmt(), va_arg(args, double));
		    if (!strchr(buffer, '.') && !strchr(buffer, 'e'))
			strcat(buffer, ".0");	/* make it look floating */
		    string = buffer;
		    break;
		case '0':
		    if (width == 0) {
			pad = '0';
			continue;
		    }
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		    width = width * 10 + c - '0';
		    continue;
		default:
		    errlog("STREAM_PRINTF: Unknown format directive: %%%c\n",
			   c);
		    goto abort;
		}
		break;
	    }

	    if (width && (width -= strlen(string)) > 0)
		while (width--)
		    stream_add_char(s, pad);
	    stream_add_string(s, string);
	} else