Gmane
From: Camm Maguire <camm <at> enhanced.com>
Subject: Re: format: comma-interval bug fix
Newsgroups: gmane.lisp.gcl.devel
Date: 2005-08-09 05:19:32 GMT (2 years, 49 weeks, 1 day, 17 hours and 33 minutes ago)
Greetings again!  Likewise in cvs head past t4.  Thanks so much!

Robert Boyer <boyer <at> cs.utexas.edu> writes:

> Below is a slightly revised version of o/format.c that fixes an ANSI
> compliance bug, namely that ~B, ~D, ~X, ~O, and ~R now all take a 5th
> parameter, comma-interval.
> 
> Bob
> 
> -------------------------------------------------------------------------------
> 
> 
> /*
>  Copyright (C) 1994 M. Hagiya, W. Schelter, T. Yuasa
> 
> This file is part of GNU Common Lisp, herein referred to as GCL
> 
> GCL is free software; you can redistribute it and/or modify it under
> the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE as published by
> the Free Software Foundation; either version 2, or (at your option)
> any later version.
> 
> GCL is distributed in the hope that it will be useful, but WITHOUT
> ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public 
> License for more details.
> 
> You should have received a copy of the GNU Library General Public License 
> along with GCL; see the file COPYING.  If not, write to the Free Software
> Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
> 
> */
> 
> /*
> 	format.c
> */
> 
> #include "include.h"
> 
> static int
> fmt_thousand(int,int,bool,bool,int);
> 
> static void
> fmt_exponent1(int);
> 
> static void
> fmt_write_numeral(int,int);
> 
> static void
> fmt_write_ordinal(int,int);
> 
> static int
> fmt_nonillion(int,int,bool,bool,int);
> 
> static void
> fmt_roman(int,int,int,int,int);
> 
> static void
> fmt_integer(object,bool,bool,int,int,int,int,int);
> 
> static void
> fmt_semicolon(bool,bool);
> 
> static void
> fmt_up_and_out(bool,bool);
> 
> static void
> fmt_justification(volatile bool,bool);
> 
> static void
> fmt_iteration(bool,bool);
> 
> static void
> fmt_conditional(bool,bool);
> 
> static void
> fmt_case(bool,bool);
> 
> static void
> fmt_indirection(bool,bool);
> 
> static void
> fmt_asterisk(bool,bool);
> 
> static void
> fmt_tabulate(bool,bool);
> 
> static void
> fmt_newline(bool,bool);
> 
> static void
> fmt_tilde(bool,bool);
> 
> static void
> fmt_bar(bool,bool);
> 
> static void
> fmt_ampersand(bool,bool);
> 
> static void
> fmt_percent(bool,bool);
> 
> static void
> fmt_dollars_float(bool,bool);
> 
> static void
> fmt_general_float(bool,bool);
> 
> static void
> fmt_exponential_float(bool,bool);
> 
> static void
> fmt_fix_float(bool,bool);
> 
> static void
> fmt_character(bool,bool);
> 
> static void
> fmt_plural(bool,bool);
> 
> static void
> fmt_radix(bool,bool);
> 
> static void
> fmt_hexadecimal(bool,bool);
> 
> static void
> fmt_octal(bool,bool);
> 
> static void
> fmt_binary(bool,bool);
> 
> static void
> fmt_error(char *);
> 
> static void
> fmt_ascii(bool, bool);
> 
> static void
> fmt_S_expression(bool, bool);
> 
> static void
> fmt_decimal(bool, bool);
> 
> 
> object sSAindent_formatted_outputA;
> 
> #define	ctl_string	(fmt_string->st.st_self + ctl_origin)
> 
> #define	fmt_old		VOL object old_fmt_stream; \
> 			VOL int old_ctl_origin; \
> 			VOL int old_ctl_index; \
> 			VOL int old_ctl_end; \
> 			object * VOL old_fmt_base; \
> 			VOL int old_fmt_index; \
> 			VOL int old_fmt_end; \
> 			jmp_bufp   VOL old_fmt_jmp_bufp; \
> 			VOL int old_fmt_indents; \
> 			VOL object old_fmt_string ; \
>                         VOL format_parameter *old_fmt_paramp
> #define	fmt_save	old_fmt_stream = fmt_stream; \
> 			old_ctl_origin = ctl_origin; \
> 			old_ctl_index = ctl_index; \
> 			old_ctl_end = ctl_end; \
> 			old_fmt_base = fmt_base; \
> 			old_fmt_index = fmt_index; \
> 			old_fmt_end = fmt_end; \
> 			old_fmt_jmp_bufp = fmt_jmp_bufp; \
> 			old_fmt_indents = fmt_indents; \
> 			old_fmt_string = fmt_string ; \
>                         old_fmt_paramp = fmt_paramp
> #define	fmt_restore	fmt_stream = old_fmt_stream; \
> 			ctl_origin = old_ctl_origin; \
> 			ctl_index = old_ctl_index; \
> 			ctl_end = old_ctl_end; \
> 			fmt_base = old_fmt_base; \
> 			fmt_index = old_fmt_index; \
> 			fmt_end = old_fmt_end; \
> 			fmt_jmp_bufp = old_fmt_jmp_bufp; \
> 			fmt_indents = old_fmt_indents; \
> 			fmt_string = old_fmt_string ; \
>                         fmt_paramp = old_fmt_paramp 
> 
> #define	fmt_restore1	fmt_stream = old_fmt_stream; \
> 			ctl_origin = old_ctl_origin; \
> 			ctl_index = old_ctl_index; \
> 			ctl_end = old_ctl_end; \
> 			fmt_jmp_bufp = old_fmt_jmp_bufp; \
> 			fmt_indents = old_fmt_indents; \
> 			fmt_string = old_fmt_string ; \
>                         fmt_paramp = old_fmt_paramp 
> 
> typedef struct {
> 	  int fmt_param_type;
> 	  int fmt_param_value;
> 	} format_parameter;
> 
> format_parameter fmt_param[100];
> VOL format_parameter *fmt_paramp;
> #define FMT_PARAM (fmt_paramp)
> 
> #ifndef WRITEC_NEWLINE
> #define  WRITEC_NEWLINE(strm) (writec_stream('\n',strm))
> #endif
> 
> object fmt_temporary_stream;
> object fmt_temporary_string;
> 
> int fmt_nparam;
> enum fmt_types {
>   fmt_null,
>   fmt_int,
>   fmt_char};
> 
> char *fmt_big_numeral[] = {
> 	"thousand",
> 	"million",
> 	"billion",
> 	"trillion",
> 	"quadrillion",
> 	"quintillion",
> 	"sextillion",
> 	"septillion",
> 	"octillion"
> };
> 
> char *fmt_numeral[] = {
> 	"zero", "one", "two", "three", "four",
> 	"five", "six", "seven", "eight", "nine",
> 	"ten", "eleven", "twelve", "thirteen", "fourteen",
> 	"fifteen", "sixteen", "seventeen", "eighteen", "nineteen",
> 	"zero", "ten", "twenty", "thirty", "forty",
> 	"fifty", "sixty", "seventy", "eighty", "ninety"
> };
> 
> char *fmt_ordinal[] = {
> 	"zeroth", "first", "second", "third", "fourth",
> 	"fifth", "sixth", "seventh", "eighth", "ninth",
> 	"tenth", "eleventh", "twelfth", "thirteenth", "fourteenth",
> 	"fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth",
> 	"zeroth", "tenth", "twentieth", "thirtieth", "fortieth",
> 	"fiftieth", "sixtieth", "seventieth", "eightieth", "ninetieth"
> };
> 
> 
> int fmt_spare_spaces;
> int fmt_line_length;
> 
> 
> static int
> fmt_tempstr(int s)
> {
> 	return(fmt_temporary_string->st.st_self[s]);
> }
> 
> static int
> ctl_advance(void)
> {
> 	if (ctl_index >= ctl_end)
> 		fmt_error("unexpected end of control string");
> 	return(ctl_string[ctl_index++]);
> }
> 
> static object
> fmt_advance(void)
> {
> 	if (fmt_index >= fmt_end)
> 		fmt_error("arguments exhausted");
> 	return(fmt_base[fmt_index++]);
> }
> 
> 
> static void
> format(object fmt_stream0, int ctl_origin0, int ctl_end0)
> {
> 	int c, i, n;
> 	bool colon, atsign;
> 	object x;
> 	fmt_paramp = fmt_param;
> 
> 	/* could eliminate the no interrupt if made the
> 	   temporary stream on the stack... */
>        {BEGIN_NO_INTERRUPT;
> 	fmt_stream = fmt_stream0;
> 	ctl_origin = ctl_origin0;
> 	ctl_index = 0;
> 	ctl_end = ctl_end0;
> 
> LOOP:
> 	if (ctl_index >= ctl_end)
> 	  { END_NO_INTERRUPT;
> 		return;}
> 	if ((c = ctl_advance()) != '~') {
> 		writec_stream(c, fmt_stream);
> 		goto LOOP;
> 	}
> 	n = 0;
> 	for (;;) {
> 		switch (c = ctl_advance()) {
> 		case ',':
> 			fmt_param[n].fmt_param_type = fmt_null;
> 			break;
> 
> 		case '0':  case '1':  case '2':  case '3':  case '4':
> 		case '5':  case '6':  case '7':  case '8':  case '9':
> 		DIGIT:
> 			i = 0;
> 			do {
> 				i = i*10 + (c - '0');
> 				c = ctl_advance();
> 			} while (isDigit(c));
> 			fmt_param[n].fmt_param_type = fmt_int;
> 			fmt_param[n].fmt_param_value = i;
> 			break;
> 
> 		case '+':
> 			c = ctl_advance();
> 			if (!isDigit(c))
> 				fmt_error("digit expected");
> 			goto DIGIT;
> 
> 		case '-':
> 			c = ctl_advance();
> 			if (!isDigit(c))
> 				fmt_error("digit expected");
> 			i = 0;
> 			do {
> 				i = i*10 + (c - '0');
> 				c = ctl_advance();
> 			} while (isDigit(c));
> 			fmt_param[n].fmt_param_type = fmt_int;
> 			fmt_param[n].fmt_param_value = -i;
> 			break;
> 
> 		case '\'':
> 			fmt_param[n].fmt_param_type = fmt_char;
> 			fmt_param[n].fmt_param_value = ctl_advance();
> 			c = ctl_advance();
> 			break;
> 
> 		case 'v':  case 'V':
> 			x = fmt_advance();
> 			if (type_of(x) == t_fixnum) {
> 				fmt_param[n].fmt_param_type = fmt_int;
> 				fmt_param[n].fmt_param_value = fix(x);
> 			} else if (type_of(x) == t_character) {
> 				fmt_param[n].fmt_param_type = fmt_char;
> 				fmt_param[n].fmt_param_value = x->ch.ch_code;
>                         } else if (x == Cnil) {
>                                  fmt_param[n].fmt_param_type = fmt_null;				
> 			} else
> 				fmt_error("illegal V parameter");
> 			c = ctl_advance();
> 			break;
> 
> 		case '#':
> 			fmt_param[n].fmt_param_type = fmt_int;
> 			fmt_param[n].fmt_param_value = fmt_end - fmt_index;
> 			c = ctl_advance();
> 			break;
> 
> 		default:
> /*			if (n > 0)
> 				fmt_error("illegal ,");
> 			else
> */
>             /* allow (FORMAT NIL "~5,,X" 10) ; ie ,just before directive */ 
> 
> 				goto DIRECTIVE;
> 		}
> 		n++;
> 		if (c != ',')
> 			break;
> 	}
> 
> DIRECTIVE:
> 	colon = atsign = FALSE;
> 	if (c == ':') {
> 		colon = TRUE;
> 		c = ctl_advance();
> 	}
> 	if (c == ' <at> ') {
> 		atsign = TRUE;
> 		c = ctl_advance();
> 	}
> 	fmt_nparam = n;
> 	switch (c) {
> 	case 'a':  case 'A':
> 		fmt_ascii(colon, atsign);
> 		break;
> 
> 	case 's':  case 'S':
> 		fmt_S_expression(colon, atsign);
> 		break;
> 
> 	case 'd':  case 'D':
> 		fmt_decimal(colon, atsign);
> 		break;
> 
> 	case 'b':  case 'B':
> 		fmt_binary(colon, atsign);
> 		break;
> 
> 	case 'o':  case 'O':
> 		fmt_octal(colon, atsign);
> 		break;
> 
> 	case 'x':  case 'X':
> 		fmt_hexadecimal(colon, atsign);
> 		break;
> 
> 	case 'r':  case 'R':
> 		fmt_radix(colon, atsign);
> 		break;
> 
> 	case 'p':  case 'P':
> 		fmt_plural(colon, atsign);
> 		break;
> 
> 	case 'c':  case 'C':
> 		fmt_character(colon, atsign);
> 		break;
> 
> 	case 'f':  case 'F':
> 		fmt_fix_float(colon, atsign);
> 		break;
> 
> 	case 'e':  case 'E':
> 		fmt_exponential_float(colon, atsign);
> 		break;
> 
> 	case 'g':  case 'G':
> 		fmt_general_float(colon, atsign);
> 		break;
> 
> 	case '$':
> 		fmt_dollars_float(colon, atsign);
> 		break;
> 
> 	case '%':
> 		fmt_percent(colon, atsign);
> 		break;
> 
> 	case '&':
> 		fmt_ampersand(colon, atsign);
> 		break;
> 
> 	case '|':
> 		fmt_bar(colon, atsign);
> 		break;
> 
> 	case '~':
> 		fmt_tilde(colon, atsign);
> 		break;
> 
> 	case '\n':
> 	case '\r':	
> 		fmt_newline(colon, atsign);
> 		break;
> 
> 	case 't':  case 'T':
> 		fmt_tabulate(colon, atsign);
> 		break;
> 
> 	case '*':
> 		fmt_asterisk(colon, atsign);
> 		break;
> 
> 	case '?':
> 		fmt_indirection(colon, atsign);
> 		break;
> 
> 	case '(':
> 		fmt_case(colon, atsign);
> 		break;
> 
> 	case '[':
> 		fmt_conditional(colon, atsign);
> 		break;
> 
> 	case '{':
> 		fmt_iteration(colon, atsign);
> 		break;
> 
> 	case '<':
> 		fmt_justification(colon, atsign);
> 		break;
> 
> 	case '^':
> 		fmt_up_and_out(colon, atsign);
> 		break;
> 
> 	case ';':
> 		fmt_semicolon(colon, atsign);
> 		break;
> 
> 	default:
>    {object user_fmt=getf(sSAindent_formatted_outputA->s.s_plist,make_fixnum(c),Cnil);
>     
>     if (user_fmt!=Cnil)
>      {object *oldbase=vs_base;
>       object *oldtop=vs_top;
>       vs_base=vs_top;
>       vs_push(fmt_advance());
>       vs_push(fmt_stream);
>       vs_push(make_fixnum(colon));
>       vs_push(make_fixnum(atsign));
>       if (type_of(user_fmt)==t_symbol) user_fmt=symbol_function(user_fmt);
>       funcall(user_fmt);
>       vs_base=oldbase; vs_top=oldtop; break;}}
> 		fmt_error("illegal directive");
> 	}
> 	goto LOOP;
> }}
> 
> 
> 
> static int
> fmt_skip(void)
> {
> 	int c, level = 0;
> 	
> LOOP:
> 	if (ctl_advance() != '~')
> 		goto LOOP;
> 	for (;;)
> 		switch (c = ctl_advance()) {
> 		case '\'':
> 			ctl_advance();
> 
> 		case ',':
> 		case '0':  case '1':  case '2':  case '3':  case '4':
> 		case '5':  case '6':  case '7':  case '8':  case '9':
> 		case '+':
> 		case '-':
> 		case 'v':  case 'V':
> 		case '#':
> 		case ':':  case ' <at> ':
> 			continue;
> 
> 		default:
> 			goto DIRECTIVE;
> 		}
> 
> DIRECTIVE:
> 	switch (c) {
> 	case '(':  case '[':  case '<':  case '{':
> 		level++;
> 		break;
> 
> 	case ')':  case ']':  case '>':  case '}':
> 		if (level == 0)
> 			return(ctl_index);
> 		else
> 			--level;
> 		break;
> 
> 	case ';':
> 		if (level == 0)
> 			return(ctl_index);
> 		break;
> 	}
> 	goto LOOP;
> }
> 
> 
> static void
> fmt_max_param(int n)
> {
> 	if (fmt_nparam > n)
> 		fmt_error("too many parameters");
> }
> 
> static void
> fmt_not_colon(bool colon)
> {
> 	if (colon)
> 		fmt_error("illegal :");
> }
> 
> static void
> fmt_not_atsign(bool atsign)
> {
> 	if (atsign)
> 		fmt_error("illegal  <at> ");
> }
> 
> static void
> fmt_not_colon_atsign(bool colon, bool atsign)
> {
> 	if (colon && atsign)
> 		fmt_error("illegal : <at> ");
> }
> 
> static void
> fmt_set_param(int i, int *p, int t, int v)
> {
> 	if (i >= fmt_nparam || FMT_PARAM[i].fmt_param_type == fmt_null)
> 		*p = v;
> 	else if (FMT_PARAM[i].fmt_param_type != t)
> 		fmt_error("illegal parameter type");
> 	else
> 		*p = FMT_PARAM[i].fmt_param_value;
> }	
> 
> 
> static void
> fmt_ascii(bool colon, bool atsign)
> {
> 	int mincol=0, colinc=0, minpad=0, padchar=0;
> 	object x;
> 	int l, i;
> 
> 	fmt_max_param(4);
> 	fmt_set_param(0, &mincol, fmt_int, 0);
> 	fmt_set_param(1, &colinc, fmt_int, 1);
> 	fmt_set_param(2, &minpad, fmt_int, 0);
> 	fmt_set_param(3, &padchar, fmt_char, ' ');
> 
> 	fmt_temporary_string->st.st_fillp = 0;
> 	/* fmt_temporary_stream->sm.sm_int0 = file_column(fmt_stream); */
> 	STREAM_FILE_COLUMN(fmt_temporary_stream) = file_column(fmt_stream);
> 	x = fmt_advance();
> 	if (colon && x == Cnil)
> 		writestr_stream("()", fmt_temporary_stream);
> 	else if (mincol == 0 && minpad == 0) {
> 		princ(x, fmt_stream);
> 		return;
> 	} else
> 		princ(x, fmt_temporary_stream);
> 	l = fmt_temporary_string->st.st_fillp;
> 	for (i = minpad;  l + i < mincol;  i += colinc)
> 		;
> 	if (!atsign) {
> 		write_string(fmt_temporary_string, fmt_stream);
> 		while (i-- > 0)
> 			writec_stream(padchar, fmt_stream);
> 	} else {
> 		while (i-- > 0)
> 			writec_stream(padchar, fmt_stream);
> 		write_string(fmt_temporary_string, fmt_stream);
> 	}
> }
> 
> static void
> fmt_S_expression(bool colon, bool atsign)
> {
> 	int mincol=0, colinc=0, minpad=0, padchar=0;
> 	object x;
> 	int l, i;
> 
> 	fmt_max_param(4);
> 	fmt_set_param(0, &mincol, fmt_int, 0);
> 	fmt_set_param(1, &colinc, fmt_int, 1);
> 	fmt_set_param(2, &minpad, fmt_int, 0);
> 	fmt_set_param(3, &padchar, fmt_char, ' ');
> 
> 	fmt_temporary_string->st.st_fillp = 0;
> 	/* fmt_temporary_stream->sm.sm_int0 = file_column(fmt_stream); */
> 	STREAM_FILE_COLUMN(fmt_temporary_stream) = file_column(fmt_stream);
> 	x = fmt_advance();
> 	if (colon && x == Cnil)
> 		writestr_stream("()", fmt_temporary_stream);
> 	else if (mincol == 0 && minpad == 0) {
> 		prin1(x, fmt_stream);
> 		return;
> 	} else
> 		prin1(x, fmt_temporary_stream);
> 	l = fmt_temporary_string->st.st_fillp;
> 	for (i = minpad;  l + i < mincol;  i += colinc)
> 		;
> 	if (!atsign) {
> 		write_string(fmt_temporary_string, fmt_stream);
> 		while (i-- > 0)
> 			writec_stream(padchar, fmt_stream);
> 	} else {
> 		while (i-- > 0)
> 			writec_stream(padchar, fmt_stream);
> 		write_string(fmt_temporary_string, fmt_stream);
> 	}
> }
> 
> static void
> fmt_decimal(bool colon, bool atsign)
> {
> 	int mincol=0, padchar=0, commachar=0, commainterval=0;
> 
> 	fmt_max_param(4);
> 	fmt_set_param(0, &mincol, fmt_int, 0);
> 	fmt_set_param(1, &padchar, fmt_char, ' ');
> 	fmt_set_param(2, &commachar, fmt_char, ',');
> 	fmt_set_param(3, &commainterval, fmt_int, 3);
> 	fmt_integer(fmt_advance(), colon, atsign,
> 		    10, mincol, padchar, commachar, commainterval);
> }
> 
> static void
> fmt_binary(bool colon, bool atsign)
> {
> 	int mincol=0, padchar=0, commachar=0, commainterval=0;
> 
> 	fmt_max_param(4);
> 	fmt_set_param(0, &mincol, fmt_int, 0);
> 	fmt_set_param(1, &padchar, fmt_char, ' ');
> 	fmt_set_param(2, &commachar, fmt_char, ',');
> 	fmt_set_param(3, &commainterval, fmt_int, 3);
> 	fmt_integer(fmt_advance(), colon, atsign,
> 		    2, mincol, padchar, commachar, commainterval);
> }
> 
> static void
> fmt_octal(bool colon, bool atsign)
> {
> 	int mincol=0, padchar=0, commachar=0, commainterval=0;;
> 
> 	fmt_max_param(4);
> 	fmt_set_param(0, &mincol, fmt_int, 0);
> 	fmt_set_param(1, &padchar, fmt_char, ' ');
> 	fmt_set_param(2, &commachar, fmt_char, ',');
> 	fmt_set_param(3, &commainterval, fmt_int, 3);
> 	fmt_integer(fmt_advance(), colon, atsign,
> 		    8, mincol, padchar, commachar, commainterval);
> }
> 
> static void
> fmt_hexadecimal(bool colon, bool atsign)
> {
> 	int mincol=0, padchar=0, commachar=0, commainterval=0;;
> 
> 	fmt_max_param(4);
> 	fmt_set_param(0, &mincol, fmt_int, 0);
> 	fmt_set_param(1, &padchar, fmt_char, ' ');
> 	fmt_set_param(2, &commachar, fmt_char, ',');
> 	fmt_set_param(3, &commainterval, fmt_int, 3);
> 	fmt_integer(fmt_advance(), colon, atsign,
> 		    16, mincol, padchar, commachar, commainterval);
> }
> 
> static void
> fmt_radix(bool colon, bool atsign)
> {
> 	int radix=0, mincol=0, padchar=0, commachar=0, commainterval=0;;
> 	object x;
> 	int i, j, k;
> 	int s, t;
> 	bool b;
> 	extern void (*write_ch_fun)(int), writec_PRINTstream(int);
> 
> 	if (fmt_nparam == 0) {
> 		x = fmt_advance();
> 		check_type_integer(&x);
> 		if (atsign) {
> 			if (type_of(x) == t_fixnum)
> 				i = fix(x);
> 			else
> 				i = -1;
> 			if ((!colon && (i <= 0 || i >= 4000)) ||
> 			    (colon && (i <= 0 || i >= 5000))) {
> 				fmt_integer(x, FALSE, FALSE, 10, 0, ' ', ',', 3);
> 				return;
> 			}
> 			fmt_roman(i/1000, 'M', '*', '*', colon);
> 			fmt_roman(i%1000/100, 'C', 'D', 'M', colon);
> 			fmt_roman(i%100/10, 'X', 'L', 'C', colon);
> 			fmt_roman(i%10, 'I', 'V', 'X', colon);
> 			return;
> 		}
> 		fmt_temporary_string->st.st_fillp = 0;
> 		/* fmt_temporary_stream->sm.sm_int0 = file_column(fmt_stream); */
> 		STREAM_FILE_COLUMN(fmt_temporary_stream) = file_column(fmt_stream);
> 		PRINTstream = fmt_temporary_stream;
> 		PRINTradix = FALSE;
> 		PRINTbase = 10;
> 		write_ch_fun = writec_PRINTstream;
> 		write_object(x, 0);
> 		s = 0;
> 		i = fmt_temporary_string->st.st_fillp;
> 		if (i == 1 && fmt_tempstr(s) == '0') {
> 			writestr_stream("zero", fmt_stream);
> 			if (colon)
> 				writestr_stream("th", fmt_stream);
> 			return;
> 		} else if (fmt_tempstr(s) == '-') {
> 			writestr_stream("minus ", fmt_stream);
> 			--i;
> 			s++;
> 		}
> 		t = fmt_temporary_string->st.st_fillp;
> 		for (;;)
> 			if (fmt_tempstr(--t) != '0')
> 				break;
> 		for (b = FALSE;  i > 0;  i -= j) {
> 			b = fmt_nonillion(s, j = (i+29)%30+1, b,
> 					  i<=30&&colon, t);
> 			s += j;
> 			if (b && i > 30) {
> 				for (k = (i - 1)/30;  k > 0;  --k)
> 					writestr_stream(" nonillion",
> 							fmt_stream);
> 				if (colon && s > t)
> 					writestr_stream("th", fmt_stream);
> 			}
> 		}
> 		return;
> 	}
> 	fmt_max_param(5);
> 	fmt_set_param(0, &radix, fmt_int, 10);
> 	fmt_set_param(1, &mincol, fmt_int, 0);
> 	fmt_set_param(2, &padchar, fmt_char, ' ');
> 	fmt_set_param(3, &commachar, fmt_char, ',');
> 	fmt_set_param(4, &commainterval, fmt_int, 3);
> 	x = fmt_advance();
> 	check_type_integer(&x);
> 	if (radix < 0 || radix > 36) {
> 		vs_push(make_fixnum(radix));
> 		FEerror("~D is illegal as a radix.", 1, vs_head);
> 	}
> 	fmt_integer(x, colon, atsign, radix, mincol, padchar, commachar, commainterval);
> }	
> 
> static void
> fmt_integer(object x, bool colon, bool atsign, int radix, int mincol, int padchar, int commachar, int commainterval)
> {
> 	int l, l1;
> 	int s;
> 	extern void (*write_ch_fun)(int), writec_PRINTstream(int);
> 
> 	if (type_of(x) != t_fixnum && type_of(x) != t_bignum) {
> 		fmt_temporary_string->st.st_fillp = 0;
> 		/* fmt_temporary_stream->sm.sm_int0 = file_column(fmt_stream); */
> 		STREAM_FILE_COLUMN(fmt_temporary_stream) = file_column(fmt_stream);
> 		{SETUP_PRINT_DEFAULT(x);
> 		PRINTstream = fmt_temporary_stream;
> 		PRINTescape = FALSE;
> 		PRINTbase = radix;
> 		write_ch_fun = writec_PRINTstream;
> 		write_object(x, 0);
> 		CLEANUP_PRINT_DEFAULT;}
> 		l = fmt_temporary_string->st.st_fillp;
> 		mincol -= l;
> 		while (mincol-- > 0)
> 			writec_stream(padchar, fmt_stream);
> 		for (s = 0;  l > 0;  --l, s++)
> 			writec_stream(fmt_tempstr(s), fmt_stream);
> 		return;
> 	}
> 	fmt_temporary_string->st.st_fillp = 0;
> 	/* fmt_temporary_stream->sm.sm_int0 = file_column(fmt_stream);*/
> 	STREAM_FILE_COLUMN(fmt_temporary_stream) = file_column(fmt_stream);
> 	PRINTstream = fmt_temporary_stream;
> 	PRINTradix = FALSE;
> 	PRINTbase = radix;
> 	write_ch_fun = writec_PRINTstream;
> 	write_object(x, 0);
> 	l = l1 = fmt_temporary_string->st.st_fillp;
> 	s = 0;
> 	if (fmt_tempstr(s) == '-')
> 		--l1;
> 	mincol -= l;
> 	if (colon)
> 		mincol -= (l1 - 1)/3;
> 	if (atsign && fmt_tempstr(s) != '-')
> 		--mincol;
> 	while (mincol-- > 0)
> 		writec_stream(padchar, fmt_stream);
> 	if (fmt_tempstr(s) == '-') {
> 		s++;
> 		writec_stream('-', fmt_stream);
> 	} else if (atsign)
> 		writec_stream('+', fmt_stream);
> 	while (l1-- > 0) {
> 		writec_stream(fmt_tempstr(s++), fmt_stream);
> 		if (colon && l1 > 0 && l1%(commainterval) == 0)
> 			writec_stream(commachar, fmt_stream);
> 	}
> }
> 
> static int
> fmt_nonillion(int s, int i, bool b, bool o, int t)
> {
> 	int j;
> 
> 	for (;  i > 3;  i -= j) {
> 		b = fmt_thousand(s, j = (i+2)%3+1, b, FALSE, t);
> 		if (j != 3 || fmt_tempstr(s) != '0' ||
> 		    fmt_tempstr(s+1) != '0' || fmt_tempstr(s+2) != '0') {
> 			writec_stream(' ', fmt_stream);
> 			writestr_stream(fmt_big_numeral[(i - 1)/3 - 1],
> 					fmt_stream);
> 			s += j;
> 			if (o && s > t)
> 				writestr_stream("th", fmt_stream);
> 		} else
> 			s += j;
> 	}
> 	return(fmt_thousand(s, i, b, o, t));
> }		
> 
> static int
> fmt_thousand(int s, int i, bool b, bool o, int t)
> {
> 	if (i == 3 && fmt_tempstr(s) > '0') {
> 		if (b)
> 			writec_stream(' ', fmt_stream);
> 		fmt_write_numeral(s, 0);
> 		writestr_stream(" hundred", fmt_stream);
> 		--i;
> 		s++;
> 		b = TRUE;
> 		if (o && s > t)
> 			writestr_stream("th", fmt_stream);
> 	}
> 	if (i == 3) {
> 		--i;
> 		s++;
> 	}
> 	if (i == 2 && fmt_tempstr(s) > '0') {
> 		if (b)
> 			writec_stream(' ', fmt_stream);
> 		if (fmt_tempstr(s) == '1') {
> 			if (o && s + 2 > t)
> 				fmt_write_ordinal(++s, 10);
> 			else
> 				fmt_write_numeral(++s, 10);
> 			return(TRUE);
> 		} else {
> 			if (o && s + 1 > t)
> 				fmt_write_ordinal(s, 20);
> 			else
> 				fmt_write_numeral(s, 20);
> 			s++;
> 			if (fmt_tempstr(s) > '0') {
> 				writec_stream('-', fmt_stream);
> 				if (o && s + 1 > t)
> 					fmt_write_ordinal(s, 0);
> 				else
> 					fmt_write_numeral(s, 0);
> 			}
> 			return(TRUE);
> 		}
> 	}
> 	if (i == 2)
> 		s++;
> 	if (fmt_tempstr(s) > '0') {
> 		if (b)
> 			writec_stream(' ', fmt_stream);
> 		if (o && s + 1 > t)
> 			fmt_write_ordinal(s, 0);
> 		else
> 			fmt_write_numeral(s, 0);
> 		return(TRUE);
> 	}
> 	return(b);
> }
> 	
> static void
> fmt_write_numeral(int s, int i)
> {
> 	writestr_stream(fmt_numeral[fmt_tempstr(s) - '0' + i], fmt_stream);
> }
> 
> static void
> fmt_write_ordinal(int s, int i)
> {
> 	writestr_stream(fmt_ordinal[fmt_tempstr(s) - '0' + i], fmt_stream);
> }
> 
> static void
> fmt_roman(int i, int one, int five, int ten, int colon)
> {
> 	int j;
> 
> 	if (i == 0)
> 		return;
> 	if ((!colon && i < 4) || (colon && i < 5))
> 		for (j = 0;  j < i;  j++)
> 			writec_stream(one, fmt_stream);
> 	else if (!colon && i == 4) {
> 		writec_stream(one, fmt_stream);
> 		writec_stream(five, fmt_stream);
> 	} else if ((!colon && i < 9) || colon) {
> 		writec_stream(five, fmt_stream);
> 		for (j = 5;  j < i;  j++)
> 			writec_stream(one, fmt_stream);
> 	} else if (!colon && i == 9) {
> 		writec_stream(one, fmt_stream);
> 		writec_stream(ten, fmt_stream);
> 	}
> }
> 
> static void
> fmt_plural(bool colon, bool atsign)
> {
> 	fmt_max_param(0);
> 	if (colon) {
> 		if (fmt_index == 0)
> 			fmt_error("can't back up");
> 		--fmt_index;
> 	}
> 	if (eql(fmt_advance(), make_fixnum(1)))
> 		if (atsign)
> 			writec_stream('y', fmt_stream);
> 		else
> 			;
> 	else
> 		if (atsign)
> 			writestr_stream("ies", fmt_stream);
> 		else
> 			writec_stream('s', fmt_stream);
> }
> 
> static void
> fmt_character(bool colon, bool atsign)
> {
> 	object x;
> 	int i;
> 
> 	fmt_max_param(0);
> 	fmt_temporary_string->st.st_fillp = 0;
> 	/* fmt_temporary_stream->sm.sm_int0 = 0;*/
> 	STREAM_FILE_COLUMN(fmt_temporary_stream) = 0;
> 	x = fmt_advance();
> 	check_type_character(&x);
> 	prin1(x, fmt_temporary_stream);
> 	if (!colon && atsign)
> 		i = 0;
> 	else
> 		i = 2;
> 	for (;  i < fmt_temporary_string->st.st_fillp;  i++)
> 		writec_stream(fmt_tempstr(i), fmt_stream);
> }
> 
> static void
> fmt_fix_float(bool colon, bool atsign)
> {
> 	int w=0, d=0, k=0, overflowchar=0, padchar=0;
> 	double f;
> 	int sign;
> 	char buff[256], *b, buff1[256];
> 	int exp;
> 	int i, j;
> 	object x;
> 	int n, m;
> 	vs_mark;
> 
> 	b = buff1 + 1;
> 
> 	fmt_not_colon(colon);
> 	fmt_max_param(5);
> 	fmt_set_param(0, &w, fmt_int, 0);
> 	if (w < 0)
> 		fmt_error("illegal width");
> 	fmt_set_param(0, &w, fmt_int, -1);
> 	fmt_set_param(1, &d, fmt_int, 0);
> 	if (d < 0)
> 		fmt_error("illegal number of digits");
> 	fmt_set_param(1, &d, fmt_int, -1);
> 	fmt_set_param(2, &k, fmt_int, 0);
> 	fmt_set_param(3, &overflowchar, fmt_char, -1);
> 	fmt_set_param(4, &padchar, fmt_char, ' ');
> 
> 	x = fmt_advance();
> 	if (type_of(x) == t_fixnum ||
> 	    type_of(x) == t_bignum ||
> 	    type_of(x) == t_ratio) {
> 		x = make_shortfloat((shortfloat)number_to_double(x));
> 		vs_push(x);
> 	}
> 	if (type_of(x) == t_complex) {
> 		if (w < 0)
> 			prin1(x, fmt_stream);
> 		else {
> 			fmt_nparam = 1;
> 			--fmt_index;
> 			fmt_decimal(colon, atsign);
> 		}
> 		vs_reset;
> 		return;
> 	}
> 	if (type_of(x) == t_longfloat)
> /* 		n = 16; */
> 		n = 17;
> 	else
> /* 		n = 7; */
> 		n = 8;
> 	f = number_to_double(x);
> 	edit_double(n, f, &sign, buff, &exp);
> 	if (exp + k > 100 || exp + k < -100 || d > 100) {
> 		prin1(x, fmt_stream);
> 		vs_reset;
> 		return;
> 	}
> 	if (d >= 0)
> 		m = d + exp + k + 1;
> 	else if (w >= 0) {
> 		if (exp + k >= 0)
> 			m = w - 1;
> 		else
> 			m = w + exp + k - 2;
> 		if (sign < 0 || atsign)
> 			--m;
> 		if (m == 0)
> 			m = 1;
> 	} else
> 		m = n;
> 	if (m <= 0) {
> 		if (m == 0 && buff[0] >= '5') {
> 			exp++;
> 			n = m = 1;
> 			buff[0] = '1';
> 		} else
> 			n = m = 0;
> 	} else if (m < n) {
> 		n = m;
> 		edit_double(n, f, &sign, buff, &exp);
> 	}
> 	while (n >= 0)
> 		if (buff[n - 1] == '0')
> 			--n;
> 		else
> 			break;
> 	exp += k;
> 	j = 0;
> 	if (exp >= 0) {
> 		for (i = 0;  i <= exp;  i++)
> 			b[j++] = i < n ? buff[i] : '0';
> 		b[j++] = '.';
> 		if (d >= 0)
> 			for (m = i + d;  i < m;  i++)
> 				b[j++] = i < n ? buff[i] : '0';
> 		else
> 			for (;  i < n;  i++)
> 				b[j++] = buff[i];
> 	} else {
> 		b[j++] = '.';
> 		if (d >= 0) {
> 			for (i = 0;  i < (-exp) - 1 && i < d;  i++)
> 				b[j++] = '0';
> 			for (m = d - i, i = 0;  i < m;  i++)
> 				b[j++] = i < n ? buff[i] : '0';
> 		} else if (n > 0) {
> 			for (i = 0;  i < (-exp) - 1;  i++)
> 				b[j++] = '0';
> 			for (i = 0;  i < n;  i++)
> 				b[j++] = buff[i];
> 		}
> 	}
> 	b[j] = '\0';
> 	if (w >= 0) {
> 		if (sign < 0 || atsign)
> 			--w;
> 		if (j > w && overflowchar >= 0)
> 			goto OVER;
> 		if (j < w && b[j-1] == '.' && d) {
> 			b[j++] = '0';
> 			b[j] = '\0';
> 		}
> 		if (j < w && b[0] == '.') {
> 			*--b = '0';
> 			j++;
> 		}
> 		for (i = j;  i < w;  i++)
> 			writec_stream(padchar, fmt_stream);
> 	} else {
> 		if (b[0] == '.') {
> 			*--b = '0';
> 			j++;
> 		}
> 		if (d < 0 && b[j-1] == '.') {
> 			b[j++] = '0';
> 			b[j] = '\0';
> 		}
> 	}
> 	if (sign < 0)
> 		writec_stream('-', fmt_stream);
> 	else if (atsign)
> 		writec_stream('+', fmt_stream);
> 	writestr_stream(b, fmt_stream);
> 	vs_reset;
> 	return;
> 
> OVER:
> 	fmt_set_param(0, &w, fmt_int, 0);
> 	for (i = 0;  i < w;  i++)
> 		writec_stream(overflowchar, fmt_stream);
> 	vs_reset;
> 	return;
> }
> 
> static int
> fmt_exponent_length(int e)
> {
> 	int i;
> 
> 	if (e == 0)
> 		return(1);
> 	if (e < 0)
> 		e = -e;
> 	for (i = 0;  e > 0;  i++, e /= 10)
> 		;
> 	return(i);
> }
> 
> static void
> fmt_exponent(int e)
> {
> 	if (e == 0) {
> 		writec_stream('0', fmt_stream);
> 		return;
> 	}
> 	if (e < 0)
> 		e = -e;
> 	fmt_exponent1(e);
> }
> 	
> static void
> fmt_exponent1(int e)
> {
> 	if (e == 0)
> 		return;
> 	fmt_exponent1(e/10);
> 	writec_stream('0' + e%10, fmt_stream);
> }
> 
> static void
> fmt_exponential_float(bool colon, bool atsign)
> {
> 	int w=0, d=0, e=0, k=0, overflowchar=0, padchar=0, exponentchar=0;
> 	double f;
> 	int sign;
> 	char buff[256], *b, buff1[256];
> 	int exp;
> 	int i, j;
> 	object x, y;
> 	int n, m;
> 	enum type t;
> 	vs_mark;
> 
> 	b = buff1 + 1;
> 
> 	fmt_not_colon(colon);
> 	fmt_max_param(7);
> 	fmt_set_param(0, &w, fmt_int, 0);
> 	if (w < 0)
> 		fmt_error("illegal width");
> 	fmt_set_param(0, &w, fmt_int, -1);
> 	fmt_set_param(1, &d, fmt_int, 0);
> 	if (d < 0)
> 		fmt_error("illegal number of digits");
> 	fmt_set_param(1, &d, fmt_int, -1);
> 	fmt_set_param(2, &e, fmt_int, 0);
> 	if (e < 0)
> 		fmt_error("illegal number of digits in exponent");
> 	fmt_set_param(2, &e, fmt_int, -1);
> 	fmt_set_param(3, &k, fmt_int, 1);
> 	fmt_set_param(4, &overflowchar, fmt_char, -1);
> 	fmt_set_param(5, &padchar, fmt_char, ' ');
> 	fmt_set_param(6, &exponentchar, fmt_char, -1);
> 
> 	x = fmt_advance();
> 	if (type_of(x) == t_fixnum ||
> 	    type_of(x) == t_bignum ||
> 	    type_of(x) == t_ratio) {
> 		x = make_shortfloat((shortfloat)number_to_double(x));
> 		vs_push(x);
> 	}
> 	if (type_of(x) == t_complex) {
> 		if (w < 0)
> 			prin1(x, fmt_stream);
> 		else {
> 			fmt_nparam = 1;
> 			--fmt_index;
> 			fmt_decimal(colon, atsign);
> 		}
> 		vs_reset;
> 		return;
> 	}
> 	if (type_of(x) == t_longfloat)
> /* 		n = 16; */
> 		n = 17;
> 	else
> /* 		n = 7; */
> 		n = 8;
> 	f = number_to_double(x);
> 	edit_double(n, f, &sign, buff, &exp);
> 	if (d >= 0) {
> 		if (k > 0) {
> 			if (!(k < d + 2))
> 				fmt_error("illegal scale factor");
> 			m = d + 1;
> 		} else {
> 			if (!(k > -d))
> 				fmt_error("illegal scale factor");
> 			m = d + k;
> 		}
> 	} else if (w >= 0) {
> 		if (k > 0)
> 			m = w - 1;
> 		else
> 			m = w + k - 1;
> 		if (sign < 0 || atsign)
> 			--m;
> 		if (e >= 0)
> 			m -= e + 2;
> 		else
> 			m -= fmt_exponent_length(e - k + 1) + 2;
> 	} else
> 		m = n;
> 	if (m <= 0) {
> 		if (m == 0 && buff[0] >= '5') {
> 			exp++;
> 			n = m = 1;
> 			buff[0] = '1';
> 		} else
> 			n = m = 0;
> 	} else if (m < n) {
> 		n = m;
> 		edit_double(n, f, &sign, buff, &exp);
> 	}
> 	while (n >= 0)
> 		if (buff[n - 1] == '0')
> 			--n;
> 		else
> 			break;
> 	exp = exp - k + 1;
> 	j = 0;
> 	if (k > 0) {
> 		for (i = 0;  i < k;  i++)
> 			b[j++] = i < n ? buff[i] : '0';
> 		b[j++] = '.';
> 		if (d >= 0)
> 			for (m = i + (d - k + 1);  i < m;  i++)
> 				b[j++] = i < n ? buff[i] : '0';
> 		else
> 			for (;  i < n;  i++)
> 				b[j++] = buff[i];
> 	} else {
> 		b[j++] = '.';
> 		if (d >= 0) {
> 			for (i = 0;  i < -k && i < d;  i++)
> 				b[j++] = '0';
> 			for (m = d - i, i = 0;  i < m;  i++)
> 				b[j++] = i < n ? buff[i] : '0';
> 		} else if (n > 0) {
> 			for (i = 0;  i < -k;  i++)
> 				b[j++] = '0';
> 			for (i = 0;  i < n;  i++)
> 				b[j++] = buff[i];
> 		}
> 	}
> 	b[j] = '\0';
> 	if (w >= 0) {
> 		if (sign < 0 || atsign)
> 			--w;
> 		i = fmt_exponent_length(exp);
> 		if (e >= 0) {
> 			if (i > e) {
> 				if (overflowchar >= 0)
> 					goto OVER;
> 				else
> 					e = i;
> 			}
> 			w -= e + 2;
> 		} else
> 			w -= i + 2;
> 		if (j > w && overflowchar >= 0)
> 			goto OVER;
> 		if (j < w && b[j-1] == '.') {
> 			b[j++] = '0';
> 			b[j] = '\0';
> 		}
> 		if (j < w && b[0] == '.') {
> 			*--b = '0';
> 			j++;
> 		}
> 		for (i = j;  i < w;  i++)
> 			writec_stream(padchar, fmt_stream);
> 	} else {
> 		if (b[j-1] == '.') {
> 			b[j++] = '0';
> 			b[j] = '\0';
> 		}
> 		if (d < 0 && b[0] == '.') {
> 			*--b = '0';
> 			j++;
> 		}
> 	}
> 	if (sign < 0)
> 		writec_stream('-', fmt_stream);
> 	else if (atsign)
> 		writec_stream('+', fmt_stream);
> 	writestr_stream(b, fmt_stream);
> 	y = symbol_value(sLAread_default_float_formatA);
> 	if (exponentchar < 0) {
> 		if (y == sLlong_float || y == sLdouble_float
> 		    || y == sLsingle_float 
> 
> 		    )
> 			t = t_longfloat;
> 		else
> 			t = t_shortfloat;
> 		if (type_of(x) == t)
> 			exponentchar = 'E';
> 		else if (type_of(x) == t_shortfloat)
> 			exponentchar = 'S';
> 		else
> 			exponentchar = 'L';
> 	}
> 	writec_stream(exponentchar, fmt_stream);
> 	if (exp < 0)
> 		writec_stream('-', fmt_stream);
> 	else
> 		writec_stream('+', fmt_stream);
> 	if (e >= 0)
> 		for (i = e - fmt_exponent_length(exp);  i > 0;  --i)
> 			writec_stream('0', fmt_stream);
> 	fmt_exponent(exp);
> 	vs_reset;
> 	return;
> 
> OVER:
> 	fmt_set_param(0, &w, fmt_int, -1);
> 	for (i = 0;  i < w;  i++)
> 		writec_stream(overflowchar, fmt_stream);
> 	vs_reset;
> 	return;
> }
> 
> static void
> fmt_general_float(bool colon, bool atsign)
> {
> 	int w=0, d=0, e=0, k, overflowchar, padchar=0, exponentchar;
> 	int sign, exp;
> 	char buff[256];
> 	object x;
> 	int n, ee, ww, q, dd;
> 	vs_mark;
> 
> 	fmt_not_colon(colon);
> 	fmt_max_param(7);
> 	fmt_set_param(0, &w, fmt_int, 0);
> 	if (w < 0)
> 		fmt_error("illegal width");
> 	fmt_set_param(0, &w, fmt_int, -1);
> 	fmt_set_param(1, &d, fmt_int, 0);
> 	if (d < 0)
> 		fmt_error("illegal number of digits");
> 	fmt_set_param(1, &d, fmt_int, -1);
> 	fmt_set_param(2, &e, fmt_int, 0);
> 	if (e < 0)
> 		fmt_error("illegal number of digits in exponent");
> 	fmt_set_param(2, &e, fmt_int, -1);
> 	fmt_set_param(3, &k, fmt_int, 1);
> 	fmt_set_param(4, &overflowchar, fmt_char, -1);
> 	fmt_set_param(5, &padchar, fmt_char, ' ');
> 	fmt_set_param(6, &exponentchar, fmt_char, -1);
> 
> 	x = fmt_advance();
> 	if (type_of(x) == t_complex) {
> 		if (w < 0)
> 			prin1(x, fmt_stream);
> 		else {
> 			fmt_nparam = 1;
> 			--fmt_index;
> 			fmt_decimal(colon, atsign);
> 		}
> 		vs_reset;
> 		return;
> 	}
> 	if (type_of(x) == t_longfloat)
> /* 		q = 16; */
> 		q = 17;
> 	else
> /* 		q = 7; */
> 		q = 8;
> 	edit_double(q, number_to_double(x), &sign, buff, &exp);
> 	n = exp + 1;
> 	while (q >= 0)
> 		if (buff[q - 1] == '0')
> 			--q;
> 		else
> 			break;
> 	if (e >= 0)
> 		ee = e + 2;
> 	else
> 		ee = 4;
> 	ww = w - ee;
> 	if (d < 0) {
> 		d = n < 7 ? n : 7;
> 		d = q > d ? q : d;
> 	}
> 	dd = d - n;
> 	if (0 <= dd && dd <= d) {
> 		FMT_PARAM[0].fmt_param_value = ww;
> 		if (w < 0) FMT_PARAM[0].fmt_param_type = fmt_null;
> 		FMT_PARAM[1].fmt_param_value = dd;
> 		FMT_PARAM[1].fmt_param_type = fmt_int;
> 		FMT_PARAM[2].fmt_param_type = fmt_null;
> 		if (fmt_nparam > 4)
> 		  {FMT_PARAM[3] =    FMT_PARAM[4]; }
> 		else FMT_PARAM[3].fmt_param_type = fmt_null;
> 		if (fmt_nparam > 5)
> 		  {FMT_PARAM[4] = FMT_PARAM[5];}
> 		else FMT_PARAM[4].fmt_param_type = fmt_null;
> 		fmt_nparam = 5;
> 		--fmt_index;
> 		fmt_fix_float(colon, atsign);
> 		if (w >= 0)
> 			while (ww++ < w)
> 				writec_stream(padchar, fmt_stream);
> 		vs_reset;
> 		return;
> 	}
> 	FMT_PARAM[1].fmt_param_value = d;
> 	FMT_PARAM[1].fmt_param_type = fmt_int;
> 	--fmt_index;
> 	fmt_exponential_float(colon, atsign);
> 	vs_reset;
> }
> 
> static void
> fmt_dollars_float(bool colon, bool atsign)
> {
> 	int d=0, n=0, w=0, padchar=0;
> 	double f;
> 	int sign;
> 	char buff[256];
> 	int exp;
> 	int q, i;
> 	object x;
> 	vs_mark;
> 
> 	fmt_max_param(4);
> 	fmt_set_param(0, &d, fmt_int, 2);
> 	if (d < 0)
> 		fmt_error("illegal number of digits");
> 	fmt_set_param(1, &n, fmt_int, 1);
> 	if (n < 0)
> 		fmt_error("illegal number of digits");
> 	fmt_set_param(2, &w, fmt_int, 0);
> 	if (w < 0)
> 		fmt_error("illegal width");
> 	fmt_set_param(3, &padchar, fmt_char, ' ');
> 	x = fmt_advance();
> 	if (type_of(x) == t_complex) {
> 		if (w < 0)
> 			prin1(x, fmt_stream);
> 		else {
> 			fmt_nparam = 1;
> 			FMT_PARAM[0] = FMT_PARAM[2];
> 			--fmt_index;
> 			fmt_decimal(colon, atsign);
> 		}
> 		vs_reset;
> 		return;
> 	}
> /* 	q = 7; */
> 	q = 8;
> 	if (type_of(x) == t_longfloat)
> /* 		q = 16; */
> 		q = 17;
> 	f = number_to_double(x);
> 	edit_double(q, f, &sign, buff, &exp);
> 	if ((q = exp + d + 1) > 0)
> 		edit_double(q, f, &sign, buff, &exp);
> 	exp++;
> 	if (w > 100 || exp > 100 || exp < -100) {
> 		fmt_nparam = 6;
> 		FMT_PARAM[0] = FMT_PARAM[2];
> 		FMT_PARAM[1].fmt_param_value = d + n - 1;
> 		FMT_PARAM[1].fmt_param_type = fmt_int;
> 		FMT_PARAM[2].fmt_param_type =
> 		FMT_PARAM[3].fmt_param_type =
> 		FMT_PARAM[4].fmt_param_type = fmt_null;
> 		FMT_PARAM[5] = FMT_PARAM[3];
> 		--fmt_index;
> 		fmt_exponential_float(colon, atsign);
> 	}
> 	if (exp > n)
> 		n = exp;
> 	if (sign < 0 || atsign)
> 		--w;
> 	if (colon) {
> 		if (sign < 0)
> 			writec_stream('-', fmt_stream);
> 		else if (atsign)
> 			writec_stream('+', fmt_stream);
> 		while (--w > n + d)
> 			writec_stream(padchar, fmt_stream);
> 	} else {
> 		while (--w > n + d)
> 			writec_stream(padchar, fmt_stream);
> 		if (sign < 0)
> 			writec_stream('-', fmt_stream);
> 		else if (atsign)
> 			writec_stream('+', fmt_stream);
> 	}
> 	for (i = n - exp;  i > 0;  --i)
> 		writec_stream('0', fmt_stream);
> 	for (i = 0;  i < exp;  i++)
> 		writec_stream((i < q ? buff[i] : '0'), fmt_stream);
> 	writec_stream('.', fmt_stream);
> 	for (d += i;  i < d;  i++)
> 		writec_stream((i < q ? buff[i] : '0'), fmt_stream);
> 	vs_reset;
> }
> 
> static void
> fmt_percent(bool colon, bool atsign)
> {
> 	int n=0, i;
> 
> 	fmt_max_param(1);
> 	fmt_set_param(0, &n, fmt_int, 1);
> 	fmt_not_colon(colon);
> 	fmt_not_atsign(atsign);
> 	while (n-- > 0) {
>                 WRITEC_NEWLINE(fmt_stream);
> 		if (n == 0)
> 			for (i = fmt_indents;  i > 0;  --i)
> 				writec_stream(' ', fmt_stream);
> 	}
> }
> 
> static void
> fmt_ampersand(bool colon, bool atsign)
> {
> 	int n=0;
> 
> 	fmt_max_param(1);
> 	fmt_set_param(0, &n, fmt_int, 1);
> 	fmt_not_colon(colon);
> 	fmt_not_atsign(atsign);
> 	if (n == 0)
> 		return;
> 	if (file_column(fmt_stream) != 0)
> 	  WRITEC_NEWLINE(fmt_stream);
> 	while (--n > 0)
> 	  	  WRITEC_NEWLINE(fmt_stream);
> 	fmt_indents = 0;
> }
> 
> static void
> fmt_bar(bool colon, bool atsign)
> {
> 	int n=0;
> 
> 	fmt_max_param(1);
> 	fmt_set_param(0, &n, fmt_int, 1);
> 	fmt_not_colon(colon);
> 	fmt_not_atsign(atsign);
> 	while (n-- > 0)
> 		writec_stream('\f', fmt_stream);
> }
> 
> static void
> fmt_tilde(bool colon, bool atsign)
> {
> 	int n=0;
> 
> 	fmt_max_param(1);
> 	fmt_set_param(0, &n, fmt_int, 1);
> 	fmt_not_colon(colon);
> 	fmt_not_atsign(atsign);
> 	while (n-- > 0)
> 		writec_stream('~', fmt_stream);
> }
> 
> static void
> fmt_newline(bool colon, bool atsign)
> {
> 
> 	fmt_max_param(0);
> 	fmt_not_colon_atsign(colon, atsign);
> 	if (atsign)
> 	  WRITEC_NEWLINE(fmt_stream);
> 	while (ctl_index < ctl_end && isspace((int)ctl_string[ctl_index])) {
> 		if (colon)
> 			writec_stream(ctl_string[ctl_index], fmt_stream);
> 		ctl_index++;
> 	}
> }
> 
> static void
> fmt_tabulate(bool colon, bool atsign)
> {
> 	int colnum=0, colinc=0;
> 	int c, i;
> 	
> 	fmt_max_param(2);
> 	fmt_not_colon(colon);
> 	fmt_set_param(0, &colnum, fmt_int, 1);
> 	fmt_set_param(1, &colinc, fmt_int, 1);
> 	if (!atsign) {
> 		c = file_column(fmt_stream);
> 		if (c < 0) {
> 			writestr_stream("  ", fmt_stream);
> 			return;
> 		}
> 		if (c > colnum && colinc <= 0)
> 			return;
> 		while (c > colnum)
> 			colnum += colinc;
> 		for (i = colnum - c;  i > 0;  --i)
> 			writec_stream(' ', fmt_stream);
> 	} else {
> 		for (i = colnum;  i > 0;  --i)
> 			writec_stream(' ', fmt_stream);
> 		c = file_column(fmt_stream);
> 		if (c < 0 || colinc <= 0)
> 			return;
> 		colnum = 0;
> 		while (c > colnum)
> 			colnum += colinc;
> 		for (i = colnum - c;  i > 0;  --i)
> 			writec_stream(' ', fmt_stream);
> 	}
> }
> 
> static void
> fmt_asterisk(bool colon, bool atsign)
> {
> 	int n=0;
> 
> 	fmt_max_param(1);
> 	fmt_not_colon_atsign(colon, atsign);
> 	if (atsign) {
> 		fmt_set_param(0, &n, fmt_int, 0);
> 		if (n < 0 || n >= fmt_end)
> 			fmt_error("can't goto");
> 		fmt_index = n;
> 	} else if (colon) {
> 		fmt_set_param(0, &n, fmt_int, 1);
> 		if (n > fmt_index)
> 			fmt_error("can't back up");
> 		fmt_index -= n;
> 	} else {
> 		fmt_set_param(0, &n, fmt_int, 1);
> 		while (n-- > 0)
> 			fmt_advance();
> 	}
> }	
> 
> static void
> fmt_indirection(bool colon, bool atsign) {
> 	object s, l;
> 	fmt_old;
> 	jmp_buf fmt_jmp_buf0;
> 	int up_colon;
> 
> 	/* to prevent longjmp clobber */
> 	up_colon=(long)&old_fmt_paramp;
> 	fmt_max_param(0);
> 	fmt_not_colon(colon);
> 	s = fmt_advance();
> 	if (type_of(s) != t_string)
> 		fmt_error("control string expected");
> 	if (atsign) {
> 		fmt_save;
> 		fmt_jmp_bufp = &fmt_jmp_buf0;
> 		fmt_string = s;
> 		if ((up_colon = setjmp(*fmt_jmp_bufp))) {
> 			if (--up_colon)
> 				fmt_error("illegal ~:^");
> 		} else
> 			format(fmt_stream, 0, s->st.st_fillp);
> 		fmt_restore1;
> 	} else {
> 		l = fmt_advance();
> 		fmt_save;
> 		fmt_base = vs_top;
> 		fmt_index = 0;
> 		for (fmt_end = 0;  !endp(l);  fmt_end++, l = l->c.c_cdr)
> 			vs_check_push(l->c.c_car);
> 		fmt_jmp_bufp = &fmt_jmp_buf0;
> 		fmt_string = s;
> 		if ((up_colon = setjmp(*fmt_jmp_bufp))) {
> 			if (--up_colon)
> 				fmt_error("illegal ~:^");
> 		} else
> 			format(fmt_stream, 0, s->st.st_fillp);
> 		vs_top = fmt_base;
> 		fmt_restore;
> 	}
> }
> 
> static void
> fmt_case(bool colon, bool atsign)
> {
> 	VOL object x;
> 	VOL int i, j;
> 	fmt_old;
> 	jmp_buf fmt_jmp_buf0;
> 	int up_colon;
> 	bool b;
> 
> 	x = make_string_output_stream(64);
> 	vs_push(x);
> 	i = ctl_index;
> 	j = fmt_skip();
> 	if (ctl_string[--j] != ')' || ctl_string[--j] != '~')
> 		fmt_error("~) expected");
> 	fmt_save;
> 	fmt_jmp_bufp = &fmt_jmp_buf0;
> 	if ((up_colon = setjmp(*fmt_jmp_bufp)))
> 		;
> 	else
> 		format(x, ctl_origin + i, j - i);
> 	fmt_restore1;
> 	x = x->sm.sm_object0;
> 	if (!colon && !atsign)
> 		for (i = 0;  i < x->st.st_fillp;  i++) {
> 		  j = x->st.st_self[i];
> 		  if (isUpper(j))
> 		    j += 'a' - 'A';
> 		  writec_stream(j, fmt_stream);
> 		}
> 	else if (colon && !atsign)
> 		for (b = TRUE, i = 0;  i < x->st.st_fillp;  i++) {
> 		  j = x->st.st_self[i];
> 		  if (isLower(j)) {
> 		    if (b)
> 		      j -= 'a' - 'A';
> 		    b = FALSE;
> 		  } else if (isUpper(j)) {
> 		    if (!b)
> 		      j += 'a' - 'A';
> 		    b = FALSE;
> 		  } else if (!isDigit(j))
> 		    b = TRUE;
> 		  writec_stream(j, fmt_stream);
> 		}
> 	else if (!colon && atsign)
> 		for (b = TRUE, i = 0;  i < x->st.st_fillp;  i++) {
> 		  j = x->st.st_self[i];
> 		  if (isLower(j)) {
> 		    if (b)
> 		      j -= 'a' - 'A';
> 		    b = FALSE;
> 		  } else if (isUpper(j)) {
> 		    if (!b)
> 		      j += 'a' - 'A';
> 		    b = FALSE;
> 		  }
> 		  writec_stream(j, fmt_stream);
> 		}
> 	else
> 		for (i = 0;  i < x->st.st_fillp;  i++) {
> 		  j = x->st.st_self[i];
> 		  if (isLower(j))
> 		    j -= 'a' - 'A';
> 		  writec_stream(j, fmt_stream);
> 		}
> 	vs_popp;
> 	if (up_colon)
> 		longjmp(*fmt_jmp_bufp, up_colon);
> }
> 
> static void
> fmt_conditional(bool colon, bool atsign)
> {
> 	int i, j, k;
> 	object x;
> 	int n=0;
> 	bool done;
> 	fmt_old;
> 
> 	fmt_not_colon_atsign(colon, atsign);
> 	if (colon) {
> 		fmt_max_param(0);
> 		i = ctl_index;
> 		j = fmt_skip();
> 		if (ctl_string[--j] != ';' || ctl_string[--j] != '~')
> 			fmt_error("~; expected");
> 		k = fmt_skip();
> 		if (ctl_string[--k] != ']' || ctl_string[--k] != '~')
> 			fmt_error("~] expected");
> 		if (fmt_advance() == Cnil) {
> 			fmt_save;
> 			format(fmt_stream, ctl_origin + i, j - i);
> 			fmt_restore1;
> 		} else {
> 			fmt_save;
> 			format(fmt_stream, ctl_origin + j + 2, k - (j + 2));
> 			fmt_restore1;
> 		}
> 	} else if (atsign) {
> 		i = ctl_index;
> 		j = fmt_skip();
> 		if (ctl_string[--j] != ']' || ctl_string[--j] != '~')
> 			fmt_error("~] expected");
> 		if (fmt_advance() == Cnil)
> 			;
> 		else {
> 			--fmt_index;
> 			fmt_save;
> 			format(fmt_stream, ctl_origin + i, j - i);
> 			fmt_restore1;
> 		}
> 	} else {
> 		fmt_max_param(1);
> 		if (fmt_nparam == 0) {
> 			x = fmt_advance();
> 			if (type_of(x) != t_fixnum)
> 				fmt_error("illegal argument for conditional");
> 			n = fix(x);
> 		} else
> 			fmt_set_param(0, &n, fmt_int, 0);
> 		i = ctl_index;
> 		for (done = FALSE;;  --n) {
> 			j = fmt_skip();
> 			for (k = j;  ctl_string[--k] != '~';)
> 				;
> 			if (n == 0) {
> 				fmt_save;
> 				format(fmt_stream, ctl_origin + i, k - i);
> 				fmt_restore1;
> 				done = TRUE;
> 			}
> 			i = j;
> 			if (ctl_string[--j] == ']') {
> 				if (ctl_string[--j] != '~')
> 					fmt_error("~] expected");
> 				return;
> 			}
> 			if (ctl_string[j] == ';') {
> 				if (ctl_string[--j] == '~')
> 					continue;
> 				if (ctl_string[j] == ':')
> 					goto ELSE;
> 			}
> 			fmt_error("~; or ~] expected");
> 		}
> 	ELSE:
> 		if (ctl_string[--j] != '~')
> 			fmt_error("~:; expected");
> 		j = fmt_skip();
> 		if (ctl_string[--j] != ']' || ctl_string[--j] != '~')
> 			fmt_error("~] expected");
> 		if (!done) {
> 			fmt_save;
> 			format(fmt_stream, ctl_origin + i, j - i);
> 			fmt_restore1;
> 		}
> 	}
> }	
> 
> static void
> fmt_iteration(bool colon, bool atsign) {
> 	int i,n=0;
> 	VOL int j;
> 	int o;
> 	bool colon_close = FALSE;
> 	object l;
> 	VOL object l0;
> 	fmt_old;
> 	jmp_buf fmt_jmp_buf0;
> 	int up_colon;
> 
> 	/* to prevent longjmp clobber */
> 	up_colon=(long)&old_fmt_paramp;
> 	fmt_max_param(1);
> 	fmt_set_param(0, &n, fmt_int, 1000000);
> 	i = ctl_index;
> 	j = fmt_skip();
> 	if (ctl_string[--j] != '}')
> 		fmt_error("~} expected");
> 	if (ctl_string[--j] == ':') {
> 		colon_close = TRUE;
> 		--j;
> 	}
> 	if (ctl_string[j] != '~')
> 		fmt_error("syntax error");
> 	o = ctl_origin;
> 	if (!colon && !atsign) {
> 		l = fmt_advance();
> 		fmt_save;
> 		fmt_base = vs_top;
> 		fmt_index = 0;
> 		for (fmt_end = 0;  !endp(l);  fmt_end++, l = l->c.c_cdr)
> 			vs_check_push(l->c.c_car);
> 		fmt_jmp_bufp = &fmt_jmp_buf0;
> 		if (colon_close)
> 			goto L1;
> 		while (fmt_index < fmt_end) {
> 		L1:
> 			if (n-- <= 0)
> 				break;
> 			if ((up_colon = setjmp(*fmt_jmp_bufp))) {
> 				if (--up_colon)
> 					fmt_error("illegal ~:^");
> 				break;
> 			}
> 			format(fmt_stream, o + i, j - i);
> 		}
> 		vs_top = fmt_base;
> 		fmt_restore;
> 	} else if (colon && !atsign) {
> 		l0 = fmt_advance();
> 		fmt_save;
> 		fmt_base = vs_top;
> 		fmt_jmp_bufp = &fmt_jmp_buf0;
> 		if (colon_close)
> 			goto L2;
> 		while (!endp(l0)) {
> 		L2:
> 			if (n-- <= 0)
> 				break;
> 			l = l0->c.c_car;
> 			l0 = l0->c.c_cdr;
> 			fmt_index = 0;
> 			for (fmt_end = 0; !endp(l); fmt_end++, l = l->c.c_cdr)
> 				vs_check_push(l->c.c_car);
> 			if ((up_colon = setjmp(*fmt_jmp_bufp))) {
> 				vs_top = fmt_base;
> 				if (--up_colon)
> 					break;
> 				else
> 					continue;
> 			}
> 			format(fmt_stream, o + i, j - i);
> 			vs_top = fmt_base;
> 		}
> 		fmt_restore;
> 	} else if (!colon && atsign) {
> 		fmt_save;
> 		fmt_jmp_bufp = &fmt_jmp_buf0;
> 		if (colon_close)
> 			goto L3;
> 		while (fmt_index < fmt_end) {
> 		L3:
> 			if (n-- <= 0)
> 				break;
> 			if ((up_colon = setjmp(*fmt_jmp_bufp))) {
> 				if (--up_colon)
> 					fmt_error("illegal ~:^");
> 				break;
> 			}
> 			format(fmt_stream, o + i, j - i);
> 		}
> 		fmt_restore1;
> 	} else if (colon && atsign) {
> 		if (colon_close)
> 			goto L4;
> 		while (fmt_index < fmt_end) {
> 		L4:
> 			if (n-- <= 0)
> 				break;
> 			l = fmt_advance();
> 			fmt_save;
> 			fmt_base = vs_top;
> 			fmt_index = 0;
> 			for (fmt_end = 0; !endp(l); fmt_end++, l = l->c.c_cdr)
> 				vs_check_push(l->c.c_car);
> 			fmt_jmp_bufp = &fmt_jmp_buf0;
> 			if ((up_colon = setjmp(*fmt_jmp_bufp))) {
> 				vs_top = fmt_base;
> 				fmt_restore;
> 				if (--up_colon)
> 					break;
> 				else
> 					continue;
> 			}
> 			format(fmt_stream, o + i, j - i);
> 			vs_top = fmt_base;
> 			fmt_restore;
> 		}
> 	}
> }
> 
> #define FORMAT_DIRECTIVE_LIMIT 100
> 
> static void
> fmt_justification(volatile bool colon, bool atsign)
> {
> 	int mincol=0, colinc=0, minpad=0, padchar=0;
> 	object fields[FORMAT_DIRECTIVE_LIMIT];
> 	fmt_old;
> 	jmp_buf fmt_jmp_buf0;
> 	VOL int i,j,n,j0;
> 	int k,l,m,l0;
> 	int up_colon;
> 	VOL int special = 0;
> 	volatile int spare_spaces=0, line_length=0;
> 	vs_mark;
> 
> 	/* to prevent longjmp clobber */
> 	up_colon=(long)&old_fmt_paramp;
> 	fmt_max_param(4);
> 	fmt_set_param(0, &mincol, fmt_int, 0);
> 	fmt_set_param(1, &colinc, fmt_int, 1);
> 	fmt_set_param(2, &minpad, fmt_int, 0);
> 	fmt_set_param(3, &padchar, fmt_char, ' ');
> 
> 	n = 0;
> 	for (;;) {
> 		if (n >= FORMAT_DIRECTIVE_LIMIT)
> 			fmt_error("too many fields");
> 		i = ctl_index;
> 		j0 = j = fmt_skip();
> 		while (ctl_string[--j] != '~')
> 			;
> 		fields[n] = make_string_output_stream(64);
> 		vs_push(fields[n]);
> 		fmt_save;
> 		fmt_jmp_bufp = &fmt_jmp_buf0;
> 		if ((up_colon = setjmp(*fmt_jmp_bufp))) {
> 			--n;
> 			if (--up_colon)
> 				fmt_error("illegal ~:^");
> 			fmt_restore1;
> 			while (ctl_string[--j0] != '>')
> 				j0 = fmt_skip();
> 			if (ctl_string[j0-1] == ' <at> ') {
> 			    j0--;
> 			    if (ctl_string[j0-1] == ':') j0--;
> 			} else
> 			if (ctl_string[j0-1] == ':') {
> 			    j0--;
> 			    if (ctl_string[j0-1] == ' <at> ') j0--;
> 			}
> 			if (ctl_string[--j0] != '~')
> 				fmt_error("~> expected");
> 			break;
> 		}
> 		format(fields[n++], ctl_origin + i, j - i);
> 		fmt_restore1;
> 		if (ctl_string[--j0] == '>') {
> 			if (ctl_string[j0-1] == ' <at> ') {
> 			    j0--;
> 			    if (ctl_string[j0-1] == ':') j0--;
> 			} else
> 			if (ctl_string[j0-1] == ':') {
> 			    j0--;
> 			    if (ctl_string[j0-1] == ' <at> ') j0--;
> 			}
> 			if (ctl_string[--j0] != '~')
> 				fmt_error("~> expected");
> 			break;
> 		} else if (ctl_string[j0] != ';')
> 			fmt_error("~; expected");
> 		else {
> 		    if (ctl_string[j0] == ' <at> ')
> 			--j0;
> 		    if (ctl_string[--j0] == ':') {
> 			if (n != 1)
> 				fmt_error("illegal ~:;");
> 			special = 1;
> 			for (j = j0;  ctl_string[j] != '~';  --j)
> 				;
> 			fmt_save;
> 			format(fmt_stream, ctl_origin + j, j0 - j + 2);
> 			fmt_restore1;
> 			spare_spaces = fmt_spare_spaces;
> 			line_length = fmt_line_length;
> 		    } else {
> 			if (ctl_string[j0] == ' <at> ')
> 			    --j0;
> 			if (ctl_string[j0] != '~')
> 			    fmt_error("~; expected");
> 			sSAprint_line_prefixA->s.s_dbind=fields[n-1]->sm.sm_object0;
> 		    }
> 		}
> 	}
> 	sSAprint_line_prefixA->s.s_dbind=Cnil;
> 	for (i = special, l = 0;  i < n;  i++)
> 		l += fields[i]->sm.sm_object0->st.st_fillp;
> 	m = n - 1 - special;
> 	if (m <= 0 && !colon && !atsign) {
> 		m = 0;
> 		colon = TRUE;
> 	}
> 	if (colon)
> 		m++;
> 	if (atsign)
> 		m++;
> 	l0 = l;
> 	l += minpad * m;
> 	for (k = 0;  mincol + k * colinc < l;  k++)
> 		;
> 	l = mincol + k * colinc;
> 	if (special != 0 &&
> 	    file_column(fmt_stream) + l + spare_spaces >= line_length)
> 		princ(fields[0]->sm.sm_object0, fmt_stream);
> 	l -= l0;
> 	for (i = special;  i < n;  i++) {
> 		if (m > 0 && (i > 0 || colon))
> 			for (j = l / m, l -= j, --m;  j > 0;  --j)
> 				writec_stream(padchar, fmt_stream);
> 		princ(fields[i]->sm.sm_object0, fmt_stream);
> 	}
> 	if (atsign)
> 		for (j = l;  j > 0;  --j)
> 			writec_stream(padchar, fmt_stream);
> 	vs_reset;
> }
> 
> 
> static void
> fmt_up_and_out(bool colon, bool atsign)
> {
> 	int i=0, j=0, k=0;
> 
> 	fmt_max_param(3);
> 	fmt_not_atsign(atsign);
> 	if (fmt_nparam == 0) {
> 		if (fmt_index >= fmt_end)
> 			longjmp(*fmt_jmp_bufp, ++colon);
> 	} else if (fmt_nparam == 1) {
> 		fmt_set_param(0, &i, fmt_int, 0);
> 		if (i == 0)
> 			longjmp(*fmt_jmp_bufp, ++colon);
> 	} else if (fmt_nparam == 2) {
> 		fmt_set_param(0, &i, fmt_int, 0);
> 		fmt_set_param(1, &j, fmt_int, 0);
> 		if (i == j)
> 			longjmp(*fmt_jmp_bufp, ++colon);
> 	} else {
> 		fmt_set_param(0, &i, fmt_int, 0);
> 		fmt_set_param(1, &j, fmt_int, 0);
> 		fmt_set_param(2, &k, fmt_int, 0);
> 		if (i <= j && j <= k)
> 			longjmp(*fmt_jmp_bufp, ++colon);
> 	}
> }
> 
> 
> static void
> fmt_semicolon(bool colon, bool atsign)
> {
> 	fmt_not_atsign(atsign);
> 	if (!colon)
> 		fmt_error("~:; expected");
> 	fmt_max_param(2);
> 	fmt_set_param(0, &fmt_spare_spaces, fmt_int, 0);
> 	fmt_set_param(1, &fmt_line_length, fmt_int, 72);
> }
> 
> DEFUNO_NEW("FORMAT",object,fLformat,LISP
>        ,2,F_ARG_LIMIT,NONE,OO,OO,OO,OO,void,Lformat,(object strm, object control,...),"")
> {       va_list ap; 
>         VOL int nargs= VFUN_NARGS;
> 	VOL object x = OBJNULL;
> 	jmp_buf fmt_jmp_buf0;
> 	bool colon, e;
> 	object *l;
> 	fmt_old;
> 
> 	nargs=nargs-2;
> 	if (nargs < 0)
> 		too_few_arguments();
> 	if (strm == Cnil) {
> 		strm = make_string_output_stream(64);
> 		x = strm->sm.sm_object0;
> 	} else if (strm == Ct)
> 		strm = symbol_value(sLAstandard_outputA);
> 	else if (type_of(strm) == t_string) {
> 		x = strm;
> 		if (!x->st.st_hasfillp)
> 		  FEerror("The string ~S doesn't have a fill-pointer.", 1, x);
> 		strm = make_string_output_stream(0);
> 		strm->sm.sm_object0 = x;
> 	} else
> 		check_type_stream(&strm);
> 
> 	/* check_type_string(&control); */
> 	if (type_of(control) == t_string) {
> 	    fmt_save;
> 	    va_start(ap,control);
> 	    frs_push(FRS_PROTECT, Cnil);
> 	    if (nlj_active) {
> 		    e = TRUE;
> 		    goto L;
> 	    }
> 	{
> 	    COERCE_VA_LIST(l,ap,nargs);
> 	    fmt_base = l;
> 	    fmt_index = 0;
> 	    fmt_end = nargs;
> 	    fmt_jmp_bufp = & fmt_jmp_buf0;
> 	    if (symbol_value(sSAindent_formatted_outputA) != Cnil)
> 		    fmt_indents = file_column(strm);
> 	    else
> 		    fmt_indents = 0;
> 	    fmt_string = control;
> 	    if ((colon = setjmp(*fmt_jmp_bufp))) {
> 		    if (--colon)
> 			    fmt_error("illegal ~:^");
> 		    vs_base = vs_top;
> 		    if (x != OBJNULL)
> 			    vs_push(x);
> 		    else
> 			    vs_push(Cnil);
> 		    e = FALSE;
> 		    goto L;
> 	    }
> 	    format(strm, 0, control->st.st_fillp);
> 	    flush_stream(strm);
> 	}
> 	    e = FALSE;
> L:
> 	    va_end(ap);
> 	    frs_pop();
> 	    fmt_restore;
> 	    if (e) {
> 		    nlj_active = FALSE;
> 		    unwind(nlj_fr, nlj_tag);
> 	    }
> 	} else
> 	switch (type_of(control)) {
> 	    case t_cfun:
> 	    case t_gfun:
> 	    case t_sfun:
> 	    case t_vfun:
> 	    case t_afun:
> 	    case t_closure:
> 	    case t_cclosure:
> 	    case t_symbol:
> 	    case t_cons:
> 		if (nargs >= 64) FEerror("Too plong vl",0);
> 	    {	int i;
> 		object Xxvl[65];
> 		vs_mark;
> 		va_start(ap,control);
> 		
> 		Xxvl[0] = strm;
> 		for (i=1 ; i <= nargs; i++) Xxvl[i]=va_arg(ap,object);
> 		va_end(ap);
> 		IapplyVector(control,nargs+1,Xxvl);
> 		vs_reset;
> 	    }
> 	    	break;
> 	    default:
> 		FEwrong_type_argument(sLstring,control);
> 	}
>     
>     RETURN1 (x ==0 ? Cnil : x);  
> }
> 
> object 
> fLformat_1(object strm, object control,object x) {
>   VFUN_NARGS=3;
>   return FFN(fLformat)(strm,control,x);
> 
> }
> 
> /*  object c_apply_n(long int (*fn) (), int n, object *x); */
> 
> static void
> fmt_error(char *s)
> {
> 	vs_push(make_simple_string(s));
> 	vs_push(make_fixnum(&ctl_string[ctl_index] - fmt_string->st.st_self));
> 	FEerror("Format error: ~A.~%~V <at> TV~%\"~A\"~%",
> 		3, vs_top[-2], vs_top[-1], fmt_string);
> }
> 
> DEFVAR("*INDENT-FORMATTED-OUTPUT*",sSAindent_formatted_outputA,SI,Cnil,"");
> void
> gcl_init_format(void)
> {
> 	fmt_temporary_stream = make_string_output_stream(64);
> 	enter_mark_origin(&fmt_temporary_stream);
> 	fmt_temporary_string = fmt_temporary_stream->sm.sm_object0;
> }
> 
> 
> 

-- 
Camm Maguire			     			camm <at> enhanced.com
==========================================================================
"The earth is but one country, and mankind its citizens."  --  Baha'u'llah