format.d 47.1 KB
Newer Older
1
/* -*- mode: c; c-basic-offset: 8 -*- */
jjgarcia's avatar
jjgarcia committed
2 3 4 5 6 7 8 9
/*
    format.c -- Format.
*/
/*
    Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
    Copyright (c) 1990, Giuseppe Attardi.
    Copyright (c) 2001, Juan Jose Garcia Ripoll.

10
    ECL is free software; you can redistribute it and/or
jjgarcia's avatar
jjgarcia committed
11 12 13 14 15 16 17
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    See file '../Copyright' for full details.
*/

18
#include <ecl/ecl.h>
19
#include <limits.h>
20
#include <ecl/internal.h>
jjgarcia's avatar
jjgarcia committed
21

22
#if !defined(ECL_CMU_FORMAT)
23

24 25 26 27 28 29 30
/*
 * This code is broken because of several reasons:
 * 1) It does not support Unicode
 * 2) It does not support pretty printing
 * 3) It uses the old version of parse_integer()
 */
#error "The old version of FORMAT is broken"
31

32
#define FMT_MAX_PARAM	8
33 34 35 36 37 38 39
typedef struct format_stack_struct {
  cl_object	stream;
  cl_object	string;
  cl_object	aux_stream;
  cl_object	aux_string;
  cl_index	ctl_index, ctl_end;
  const char	*ctl_str;
40
  cl_object	args, current;
41 42 43 44 45 46 47 48
  jmp_buf	*jmp_buf;
  cl_index	indents;
  cl_index	spare_spaces;
  cl_index	line_length;
  struct { int type, value; } param[FMT_MAX_PARAM];
  int		nparam;
} *format_stack;

49 50 51 52 53 54 55
#if MOST_POSITIVE_FIXNUM < INT_MAX
# define FMT_VALUE_UPPER_LIMIT MOST_POSITIVE_FIXNUM
#else
# define FMT_VALUE_UPPER_LIMIT INT_MAX
#endif

#if MOST_NEGATIVE_FIXNUM > INT_MIN
56
# define FMT_VALUE_LOWER_LIMIT MOST_NEGATIVE_FIXNUM
57
#else
58
# define FMT_VALUE_LOWER_LIMIT INT_MIN
59 60 61
#endif


jjgarcia's avatar
jjgarcia committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
/******************* COMMON ***************************/

#define NONE	0
#define	INT	1
#define	CHAR	2

static const char *fmt_big_numeral[] = {
	"thousand",
	"million",
	"billion",
	"trillion",
	"quadrillion",
	"quintillion",
	"sextillion",
	"septillion",
	"octillion"
};

static const 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"
};

static const 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"
};

98
static void format(format_stack, const char *s, cl_index);
99
static cl_object doformat(cl_narg narg, cl_object strm, cl_object string, cl_va_list args, bool in_formatter);
100 101 102 103

static cl_object
get_aux_stream(void)
{
104
	cl_env_ptr env = ecl_process_env();
105 106
	cl_object stream;

107 108
	ecl_disable_interrupts_env(env);
	if (env->fmt_aux_stream == Cnil) {
109
		stream = ecl_make_string_output_stream(64, 1);
110
	} else {
111 112
		stream = env->fmt_aux_stream;
		env->fmt_aux_stream = Cnil;
113
	}
114
	ecl_enable_interrupts_env(env);
115
	return stream;
116
}
jjgarcia's avatar
jjgarcia committed
117 118

static void
119
fmt_error(format_stack fmt, const char *s)
jjgarcia's avatar
jjgarcia committed
120
{
121
	cl_error(7, @'si::format-error',
122
		 @':format-control', make_constant_base_string(s),
123 124 125
		 @':control-string', fmt->string,
		 @':offset', MAKE_FIXNUM(&fmt->ctl_str[fmt->ctl_index] -
					 (char *)fmt->string->string.self));
jjgarcia's avatar
jjgarcia committed
126 127
}

128
static ecl_character
129
tempstr(format_stack fmt, int s)
jjgarcia's avatar
jjgarcia committed
130
{
131
	return fmt->aux_string->string.self[s];
jjgarcia's avatar
jjgarcia committed
132 133 134
}

static int
135
ctl_advance(format_stack fmt)
jjgarcia's avatar
jjgarcia committed
136
{
137 138 139
	if (fmt->ctl_index >= fmt->ctl_end)
		fmt_error(fmt, "unexpected end of control string");
	return(fmt->ctl_str[fmt->ctl_index++]);
jjgarcia's avatar
jjgarcia committed
140 141
}

142 143 144 145 146 147
static void
fmt_go(format_stack fmt, cl_fixnum n)
{
	cl_object p;
	if (n < 0)
		fmt_error(fmt, "can't goto");
148
	if ((p = ecl_nthcdr(n, fmt->args)) == Cnil)
149 150 151 152 153 154 155 156 157 158
		fmt_error(fmt, "can't goto");
	fmt->current = p;
}

static cl_index
fmt_index(format_stack fmt)
{
	cl_object p = fmt->args, target = fmt->current;
	cl_index n = 0;
	if (target == Cnil)
159
		return ecl_length(p);
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
	while (p != fmt->current) {
		p = CDR(p);
		if (p == Cnil)
			fmt_error(fmt, "Overflow");
		n++;
	}
	return n;
}

static cl_object
fmt_back_up(format_stack fmt)
{
	fmt_go(fmt, fmt_index(fmt) - 1);
}

static bool
fmt_more_args_p(format_stack fmt)
{
	return fmt->current != Cnil;
}

static cl_index
fmt_args_left(format_stack fmt)
{
184
	return ecl_length(fmt->current);
185 186
}

jjgarcia's avatar
jjgarcia committed
187
static cl_object
188
fmt_advance(format_stack fmt)
jjgarcia's avatar
jjgarcia committed
189
{
190 191
	cl_object output, l = fmt->current;
	if (l == Cnil)
192
		fmt_error(fmt, "arguments exhausted");
193 194 195
	output = CAR(l);
	fmt->current = CDR(l);
	return output;
196 197
}

jjgarcia's avatar
jjgarcia committed
198
static void
199
fmt_set_arg_list(format_stack fmt, cl_object l)
200
{
201
	assert_type_proper_list(l);
202
	fmt->current = fmt->args = cl_copy_list(l);
jjgarcia's avatar
jjgarcia committed
203 204 205
}

static int
206
fmt_skip(format_stack fmt)
jjgarcia's avatar
jjgarcia committed
207 208
{
	int c, level = 0;
209

jjgarcia's avatar
jjgarcia committed
210
LOOP:
211
	if (ctl_advance(fmt) != '~')
jjgarcia's avatar
jjgarcia committed
212 213
		goto LOOP;
	for (;;)
214
		switch (c = ctl_advance(fmt)) {
jjgarcia's avatar
jjgarcia committed
215
		case '\'':
216
			ctl_advance(fmt);
jjgarcia's avatar
jjgarcia committed
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239

		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 '@@':
			continue;

		default:
			goto DIRECTIVE;
		}

DIRECTIVE:
	switch (c) {
	case '(':  case '[':  case '<':  case '{':
		level++;
		break;

	case ')':  case ']':  case '>':  case '}':
		if (level == 0)
240
			return(fmt->ctl_index);
jjgarcia's avatar
jjgarcia committed
241 242 243 244 245 246
		else
			--level;
		break;

	case ';':
		if (level == 0)
247
			return(fmt->ctl_index);
jjgarcia's avatar
jjgarcia committed
248 249 250 251 252 253
		break;
	}
	goto LOOP;
}

static void
254
ensure_param(format_stack fmt, int n)
jjgarcia's avatar
jjgarcia committed
255
{
256 257 258 259
	if (fmt->nparam > n)
		fmt_error(fmt, "too many parameters");
	while (n-- > fmt->nparam)
		fmt->param[n].type = NONE;
jjgarcia's avatar
jjgarcia committed
260 261 262
}

static void
263
fmt_not_colon(format_stack fmt, bool colon)
jjgarcia's avatar
jjgarcia committed
264 265
{
	if (colon)
266
		fmt_error(fmt, "illegal :");
jjgarcia's avatar
jjgarcia committed
267 268 269
}

static void
270
fmt_not_atsign(format_stack fmt, bool atsign)
jjgarcia's avatar
jjgarcia committed
271 272
{
	if (atsign)
273
		fmt_error(fmt, "illegal @@");
jjgarcia's avatar
jjgarcia committed
274 275 276
}

static void
277
fmt_not_colon_atsign(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
278 279
{
	if (colon && atsign)
280
		fmt_error(fmt, "illegal :@@");
jjgarcia's avatar
jjgarcia committed
281 282
}

283
static int
284
set_param(format_stack fmt, int i, int t, int v)
jjgarcia's avatar
jjgarcia committed
285
{
286
	if (i >= fmt->nparam || fmt->param[i].type == NONE)
287
		return v;
288 289 290
	else if (fmt->param[i].type != t)
		fmt_error(fmt, "illegal parameter type");
	return fmt->param[i].value;
291
}
jjgarcia's avatar
jjgarcia committed
292

293
static int
294
set_param_positive(format_stack fmt, int i, const char *message)
jjgarcia's avatar
jjgarcia committed
295
{
296
	if (i >= fmt->nparam || fmt->param[i].type == NONE)
297
		return -1;
298 299
	else if (fmt->param[i].type != INT)
		fmt_error(fmt, "illegal parameter type");
jjgarcia's avatar
jjgarcia committed
300
	else {
301 302
		int p = fmt->param[i].value;
		if (p < 0) fmt_error(fmt, message);
303
		return p;
jjgarcia's avatar
jjgarcia committed
304
	}
305
}
jjgarcia's avatar
jjgarcia committed
306 307

static void
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
fmt_copy(format_stack fmt_copy, format_stack fmt)
{
	*fmt_copy = *fmt;
}

static void
fmt_copy1(format_stack fmt_copy, format_stack fmt)
{
	fmt_copy->stream = fmt->stream;
	fmt_copy->ctl_str = fmt->ctl_str;
	fmt_copy->ctl_index = fmt->ctl_index;
	fmt_copy->ctl_end = fmt->ctl_end;
	fmt_copy->jmp_buf = fmt->jmp_buf;
	fmt_copy->indents = fmt->indents;
	fmt_copy->string = fmt->string;
}

325 326 327 328
static void
fmt_prepare_aux_stream(format_stack fmt)
{
	fmt->aux_string->string.fillp = 0;
329 330
	fmt->aux_stream->stream.int0 = ecl_file_column(fmt->stream);
	fmt->aux_stream->stream.int1 = ecl_file_column(fmt->stream);
331 332 333
}


334 335
static void
fmt_ascii(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
336 337 338 339 340
{
	int mincol, colinc, minpad, padchar;
	cl_object x;
	int l, i;

341 342 343 344 345
	ensure_param(fmt, 4);
	mincol = set_param(fmt, 0, INT, 0);
	colinc = set_param(fmt, 1, INT, 1);
	minpad = set_param(fmt, 2, INT, 0);
	padchar = set_param(fmt, 3, CHAR, ' ');
jjgarcia's avatar
jjgarcia committed
346

347
	fmt->aux_string->string.fillp = 0;
348 349
	fmt->aux_stream->stream.int0 = ecl_file_column(fmt->stream);
	fmt->aux_stream->stream.int1 = ecl_file_column(fmt->stream);
350
	x = fmt_advance(fmt);
jjgarcia's avatar
jjgarcia committed
351
	if (colon && Null(x))
352
		writestr_stream("()", fmt->aux_stream);
jjgarcia's avatar
jjgarcia committed
353
	else if (mincol == 0 && minpad == 0) {
354
		ecl_princ(x, fmt->stream);
jjgarcia's avatar
jjgarcia committed
355 356
		return;
	} else
357
		ecl_princ(x, fmt->aux_stream);
358
	l = fmt->aux_string->string.fillp;
jjgarcia's avatar
jjgarcia committed
359 360 361
	for (i = minpad;  l + i < mincol;  i += colinc)
		;
	if (!atsign) {
362
		ecl_write_string(fmt->aux_string, fmt->stream);
jjgarcia's avatar
jjgarcia committed
363
		while (i-- > 0)
364
			ecl_write_char(padchar, fmt->stream);
jjgarcia's avatar
jjgarcia committed
365 366
	} else {
		while (i-- > 0)
367
			ecl_write_char(padchar, fmt->stream);
368
		ecl_write_string(fmt->aux_string, fmt->stream);
jjgarcia's avatar
jjgarcia committed
369 370 371 372
	}
}

static void
373
fmt_S_expression(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
374 375 376 377 378
{
	int mincol, colinc, minpad, padchar;
	cl_object x;
	int l, i;

379 380 381 382 383
	ensure_param(fmt, 4);
	mincol = set_param(fmt, 0, INT, 0);
	colinc = set_param(fmt, 1, INT, 1);
	minpad = set_param(fmt, 2, INT, 0);
	padchar = set_param(fmt, 3, CHAR, ' ');
jjgarcia's avatar
jjgarcia committed
384

385
	fmt_prepare_aux_stream(fmt);
386
	x = fmt_advance(fmt);
jjgarcia's avatar
jjgarcia committed
387
	if (colon && Null(x))
388
		writestr_stream("()", fmt->aux_stream);
jjgarcia's avatar
jjgarcia committed
389
	else if (mincol == 0 && minpad == 0) {
390
		ecl_prin1(x, fmt->stream);
jjgarcia's avatar
jjgarcia committed
391 392
		return;
	} else
393
		ecl_prin1(x, fmt->aux_stream);
394
	l = fmt->aux_string->string.fillp;
jjgarcia's avatar
jjgarcia committed
395 396 397
	for (i = minpad;  l + i < mincol;  i += colinc)
		;
	if (!atsign) {
398
		ecl_write_string(fmt->aux_string, fmt->stream);
jjgarcia's avatar
jjgarcia committed
399
		while (i-- > 0)
400
			ecl_write_char(padchar, fmt->stream);
jjgarcia's avatar
jjgarcia committed
401 402
	} else {
		while (i-- > 0)
403
			ecl_write_char(padchar, fmt->stream);
404
		ecl_write_string(fmt->aux_string, fmt->stream);
jjgarcia's avatar
jjgarcia committed
405 406 407 408 409
	}
}


static void
410
fmt_integer(format_stack fmt, cl_object x, bool colon, bool atsign,
jjgarcia's avatar
jjgarcia committed
411 412
	    int radix, int mincol, int padchar, int commachar)
{
413
	const cl_env_ptr env = ecl_process_env();
jjgarcia's avatar
jjgarcia committed
414 415 416 417
	int l, l1;
	int s;

	if (!FIXNUMP(x) && type_of(x) != t_bignum) {
418
		fmt_prepare_aux_stream(fmt);
419 420
		ecl_bds_bind(env, @'*print-escape*', Cnil);
		ecl_bds_bind(env, @'*print-base*', MAKE_FIXNUM(radix));
421
		si_write_object(x, fmt->aux_stream);
422
		ecl_bds_unwind_n(env, 2);
423
		l = fmt->aux_string->string.fillp;
jjgarcia's avatar
jjgarcia committed
424 425
		mincol -= l;
		while (mincol-- > 0)
426
			ecl_write_char(padchar, fmt->stream);
jjgarcia's avatar
jjgarcia committed
427
		for (s = 0;  l > 0;  --l, s++)
428
			ecl_write_char(tempstr(fmt, s), fmt->stream);
jjgarcia's avatar
jjgarcia committed
429 430
		return;
	}
431
	fmt_prepare_aux_stream(fmt);
432 433
	ecl_bds_bind(env, @'*print-radix*', Cnil);
	ecl_bds_bind(env, @'*print-base*', MAKE_FIXNUM(radix));
434
	si_write_object(x, fmt->aux_stream);
435
	ecl_bds_unwind_n(env, 2);
436
	l = l1 = fmt->aux_string->string.fillp;
jjgarcia's avatar
jjgarcia committed
437
	s = 0;
438
	if (tempstr(fmt, s) == '-')
jjgarcia's avatar
jjgarcia committed
439 440 441 442
		--l1;
	mincol -= l;
	if (colon)
		mincol -= (l1 - 1)/3;
443
	if (atsign && tempstr(fmt, s) != '-')
jjgarcia's avatar
jjgarcia committed
444 445
		--mincol;
	while (mincol-- > 0)
446
		ecl_write_char(padchar, fmt->stream);
447
	if (tempstr(fmt, s) == '-') {
jjgarcia's avatar
jjgarcia committed
448
		s++;
449
		ecl_write_char('-', fmt->stream);
jjgarcia's avatar
jjgarcia committed
450
	} else if (atsign)
451
		ecl_write_char('+', fmt->stream);
jjgarcia's avatar
jjgarcia committed
452
	while (l1-- > 0) {
453
		ecl_write_char(tempstr(fmt, s++), fmt->stream);
jjgarcia's avatar
jjgarcia committed
454
		if (colon && l1 > 0 && l1%3 == 0)
455
			ecl_write_char(commachar, fmt->stream);
jjgarcia's avatar
jjgarcia committed
456 457 458 459
	}
}

static void
460
fmt_decimal(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
461 462 463
{
	int mincol, padchar, commachar;

464 465 466 467 468
	ensure_param(fmt, 3);
	mincol = set_param(fmt, 0, INT, 0);
	padchar = set_param(fmt, 1, CHAR, ' ');
	commachar = set_param(fmt, 2, CHAR, ',');
	fmt_integer(fmt, fmt_advance(fmt), colon, atsign,
jjgarcia's avatar
jjgarcia committed
469 470 471 472
		    10, mincol, padchar, commachar);
}

static void
473
fmt_binary(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
474 475 476
{
	int mincol, padchar, commachar;

477 478 479 480 481
	ensure_param(fmt, 3);
	mincol = set_param(fmt, 0, INT, 0);
	padchar = set_param(fmt, 1, CHAR, ' ');
	commachar = set_param(fmt, 2, CHAR, ',');
	fmt_integer(fmt, fmt_advance(fmt), colon, atsign,
jjgarcia's avatar
jjgarcia committed
482 483 484 485
		    2, mincol, padchar, commachar);
}

static void
486
fmt_octal(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
487 488 489
{
	int mincol, padchar, commachar;

490 491 492 493 494
	ensure_param(fmt, 3);
	mincol = set_param(fmt, 0, INT, 0);
	padchar = set_param(fmt, 1, CHAR, ' ');
	commachar = set_param(fmt, 2, CHAR, ',');
	fmt_integer(fmt, fmt_advance(fmt), colon, atsign,
jjgarcia's avatar
jjgarcia committed
495 496 497 498
		    8, mincol, padchar, commachar);
}

static void
499
fmt_hexadecimal(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
500 501 502
{
	int mincol, padchar, commachar;

503 504 505 506 507
	ensure_param(fmt, 3);
	mincol = set_param(fmt, 0, INT, 0);
	padchar = set_param(fmt, 1, CHAR, ' ');
	commachar = set_param(fmt, 2, CHAR, ',');
	fmt_integer(fmt, fmt_advance(fmt), colon, atsign,
jjgarcia's avatar
jjgarcia committed
508 509 510 511
		    16, mincol, padchar, commachar);
}

static void
512
fmt_write_numeral(format_stack fmt, int s, int i)
jjgarcia's avatar
jjgarcia committed
513
{
514
	writestr_stream(fmt_numeral[tempstr(fmt, s) - '0' + i], fmt->stream);
jjgarcia's avatar
jjgarcia committed
515 516 517
}

static void
518
fmt_write_ordinal(format_stack fmt, int s, int i)
jjgarcia's avatar
jjgarcia committed
519
{
520
	writestr_stream(fmt_ordinal[tempstr(fmt, s) - '0' + i], fmt->stream);
jjgarcia's avatar
jjgarcia committed
521 522 523
}

static bool
524
fmt_thousand(format_stack fmt, int s, int i, bool b, bool o, int t)
jjgarcia's avatar
jjgarcia committed
525
{
526
	if (i == 3 && tempstr(fmt, s) > '0') {
jjgarcia's avatar
jjgarcia committed
527
		if (b)
528
			ecl_write_char(' ', fmt->stream);
529 530
		fmt_write_numeral(fmt, s, 0);
		writestr_stream(" hundred", fmt->stream);
jjgarcia's avatar
jjgarcia committed
531 532 533 534
		--i;
		s++;
		b = TRUE;
		if (o && (s > t))
535
			writestr_stream("th", fmt->stream);
jjgarcia's avatar
jjgarcia committed
536 537 538 539 540
	}
	if (i == 3) {
		--i;
		s++;
	}
541
	if (i == 2 && tempstr(fmt, s) > '0') {
jjgarcia's avatar
jjgarcia committed
542
		if (b)
543
			ecl_write_char(' ', fmt->stream);
544
		if (tempstr(fmt, s) == '1') {
jjgarcia's avatar
jjgarcia committed
545
			if (o && (s + 2 > t))
546
				fmt_write_ordinal(fmt, ++s, 10);
jjgarcia's avatar
jjgarcia committed
547
			else
548
				fmt_write_numeral(fmt, ++s, 10);
jjgarcia's avatar
jjgarcia committed
549 550 551
			return(TRUE);
		} else {
			if (o && (s + 1 > t))
552
				fmt_write_ordinal(fmt, s, 20);
jjgarcia's avatar
jjgarcia committed
553
			else
554
				fmt_write_numeral(fmt, s, 20);
jjgarcia's avatar
jjgarcia committed
555
			s++;
556
			if (tempstr(fmt, s) > '0') {
557
				ecl_write_char('-', fmt->stream);
jjgarcia's avatar
jjgarcia committed
558
				if (o && s + 1 > t)
559
					fmt_write_ordinal(fmt, s, 0);
jjgarcia's avatar
jjgarcia committed
560
				else
561
					fmt_write_numeral(fmt, s, 0);
jjgarcia's avatar
jjgarcia committed
562 563 564 565 566 567
			}
			return(TRUE);
		}
	}
	if (i == 2)
		s++;
568
	if (tempstr(fmt, s) > '0') {
jjgarcia's avatar
jjgarcia committed
569
		if (b)
570
			ecl_write_char(' ', fmt->stream);
jjgarcia's avatar
jjgarcia committed
571
		if (o && s + 1 > t)
572
			fmt_write_ordinal(fmt, s, 0);
jjgarcia's avatar
jjgarcia committed
573
		else
574
			fmt_write_numeral(fmt, s, 0);
jjgarcia's avatar
jjgarcia committed
575 576 577 578 579 580
		return(TRUE);
	}
	return(b);
}

static bool
581
fmt_nonillion(format_stack fmt, int s, int i, bool b, bool o, int t)
jjgarcia's avatar
jjgarcia committed
582 583 584 585
{
	int j;

	for (;  i > 3;  i -= j) {
586 587 588
		b = fmt_thousand(fmt, s, j = (i+2)%3+1, b, FALSE, t);
		if (j != 3 || tempstr(fmt, s) != '0' ||
		    tempstr(fmt, s+1) != '0' || tempstr(fmt, s+2) != '0') {
589
			ecl_write_char(' ', fmt->stream);
590
			writestr_stream(fmt_big_numeral[(i - 1)/3 - 1],
591
					fmt->stream);
jjgarcia's avatar
jjgarcia committed
592 593
			s += j;
			if (o && s > t)
594
				writestr_stream("th", fmt->stream);
jjgarcia's avatar
jjgarcia committed
595 596 597
		} else
			s += j;
	}
598
	return(fmt_thousand(fmt, s, i, b, o, t));
599
}
jjgarcia's avatar
jjgarcia committed
600 601

static void
602
fmt_roman(format_stack fmt, int i, int one, int five, int ten, bool colon)
jjgarcia's avatar
jjgarcia committed
603 604 605 606 607 608 609
{
	int j;

	if (i == 0)
		return;
	if ((!colon && i < 4) || (colon && i < 5))
		for (j = 0;  j < i;  j++)
610
			ecl_write_char(one, fmt->stream);
jjgarcia's avatar
jjgarcia committed
611
	else if (!colon && i == 4) {
612 613
		ecl_write_char(one, fmt->stream);
		ecl_write_char(five, fmt->stream);
jjgarcia's avatar
jjgarcia committed
614
	} else if ((!colon && i < 9) || colon) {
615
		ecl_write_char(five, fmt->stream);
jjgarcia's avatar
jjgarcia committed
616
		for (j = 5;  j < i;  j++)
617
			ecl_write_char(one, fmt->stream);
jjgarcia's avatar
jjgarcia committed
618
	} else if (!colon && i == 9) {
619 620
		ecl_write_char(one, fmt->stream);
		ecl_write_char(ten, fmt->stream);
jjgarcia's avatar
jjgarcia committed
621 622 623 624
	}
}

static void
625
fmt_radix(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
626
{
627
	const cl_env_ptr env = ecl_process_env();
jjgarcia's avatar
jjgarcia committed
628 629 630 631 632 633
	int radix, mincol, padchar, commachar;
	cl_object x;
	int i, j, k;
	int s, t;
	bool b;

634 635
	if (fmt->nparam == 0) {
		x = fmt_advance(fmt);
jjgarcia's avatar
jjgarcia committed
636 637 638 639 640 641 642 643
		assert_type_integer(x);
		if (atsign) {
			if (FIXNUMP(x))
				i = fix(x);
			else
				i = -1;
			if ((!colon && (i <= 0 || i >= 4000)) ||
			    (colon && (i <= 0 || i >= 5000))) {
644
				fmt_integer(fmt, x, FALSE, FALSE, 10, 0, ' ', ',');
jjgarcia's avatar
jjgarcia committed
645 646
				return;
			}
647 648 649 650
			fmt_roman(fmt, i/1000, 'M', '*', '*', colon);
			fmt_roman(fmt, i%1000/100, 'C', 'D', 'M', colon);
			fmt_roman(fmt, i%100/10, 'X', 'L', 'C', colon);
			fmt_roman(fmt, i%10, 'I', 'V', 'X', colon);
jjgarcia's avatar
jjgarcia committed
651 652
			return;
		}
653
		fmt_prepare_aux_stream(fmt);
654 655
		ecl_bds_bind(env, @'*print-radix*', Cnil);
		ecl_bds_bind(env, @'*print-base*', MAKE_FIXNUM(10));
656
		si_write_object(x, fmt->aux_stream);
657
		ecl_bds_unwind_n(env, 2);
jjgarcia's avatar
jjgarcia committed
658
		s = 0;
659 660 661
		i = fmt->aux_string->string.fillp;
		if (i == 1 && tempstr(fmt, s) == '0') {
			writestr_stream("zero", fmt->stream);
jjgarcia's avatar
jjgarcia committed
662
			if (colon)
663
				writestr_stream("th", fmt->stream);
jjgarcia's avatar
jjgarcia committed
664
			return;
665 666
		} else if (tempstr(fmt, s) == '-') {
			writestr_stream("minus ", fmt->stream);
jjgarcia's avatar
jjgarcia committed
667 668 669
			--i;
			s++;
		}
670 671
		t = fmt->aux_string->string.fillp;
		for (; tempstr(fmt, --t) == '0' ;) ;
jjgarcia's avatar
jjgarcia committed
672
		for (b = FALSE;  i > 0;  i -= j) {
673
			b = fmt_nonillion(fmt, s, j = (i+29)%30+1, b,
jjgarcia's avatar
jjgarcia committed
674 675 676 677
					  i<=30&&colon, t);
			s += j;
			if (b && i > 30) {
				for (k = (i - 1)/30;  k > 0;  --k)
678
					writestr_stream(" nonillion",
679
							fmt->stream);
jjgarcia's avatar
jjgarcia committed
680
				if (colon && s > t)
681
					writestr_stream("th", fmt->stream);
jjgarcia's avatar
jjgarcia committed
682 683 684 685
			}
		}
		return;
	}
686 687 688 689 690 691
	ensure_param(fmt, 4);
	radix = set_param(fmt, 0, INT, 10);
	mincol = set_param(fmt, 1, INT, 0);
	padchar = set_param(fmt, 2, CHAR, ' ');
	commachar = set_param(fmt, 3, CHAR, ',');
	x = fmt_advance(fmt);
jjgarcia's avatar
jjgarcia committed
692 693 694
	assert_type_integer(x);
	if (radix < 0 || radix > 36)
		FEerror("~D is illegal as a radix.", 1, MAKE_FIXNUM(radix));
695
	fmt_integer(fmt, x, colon, atsign, radix, mincol, padchar, commachar);
696
}
jjgarcia's avatar
jjgarcia committed
697 698

static void
699
fmt_plural(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
700
{
701
	ensure_param(fmt, 0);
jjgarcia's avatar
jjgarcia committed
702
	if (colon) {
703
		fmt_back_up(fmt);
jjgarcia's avatar
jjgarcia committed
704
	}
705
	if (ecl_eql(fmt_advance(fmt), MAKE_FIXNUM(1))) {
jjgarcia's avatar
jjgarcia committed
706
		if (atsign)
707
			ecl_write_char('y', fmt->stream);
jjgarcia's avatar
jjgarcia committed
708 709 710
	      }
	else
		if (atsign)
711
			writestr_stream("ies", fmt->stream);
jjgarcia's avatar
jjgarcia committed
712
		else
713
			ecl_write_char('s', fmt->stream);
jjgarcia's avatar
jjgarcia committed
714 715 716
}

static void
717
fmt_character(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
718 719 720 721
{
	cl_object x;
	cl_index i;

722 723
	ensure_param(fmt, 0);
	x = fmt_advance(fmt);
724
	x = ecl_check_cl_type(@'format',x,t_character);
725
	if (!colon && !atsign) {
726
		ecl_write_char(CHAR_CODE(x), fmt->stream);
727
	} else {
728
		fmt_prepare_aux_stream(fmt);
729
		ecl_prin1(x, fmt->aux_stream);
730 731 732 733 734
		if (!colon && atsign)
			i = 0;
		else
			i = 2;
		for (;  i < fmt->aux_string->string.fillp;  i++)
735
			ecl_write_char(tempstr(fmt, i), fmt->stream);
736
	}
jjgarcia's avatar
jjgarcia committed
737 738 739
}

static void
740
fmt_fix_float(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
741 742 743 744 745 746 747 748 749 750 751 752
{
	int w, d, k, overflowchar, padchar;
	double f;
	int sign;
	char buff[256], *b, buff1[256];
	int exp;
	int i, j;
	cl_object x;
	int n, m;

	b = buff1 + 1;

753 754 755 756 757 758 759
	fmt_not_colon(fmt, colon);
	ensure_param(fmt, 5);
	w = set_param_positive(fmt, 0, "illegal width");
	d = set_param_positive(fmt, 1, "illegal number of digits");
	k = set_param(fmt, 2, INT, 0);
	overflowchar = set_param(fmt, 3, CHAR, -1);
	padchar = set_param(fmt, 4, CHAR, ' ');
jjgarcia's avatar
jjgarcia committed
760

761
	x = fmt_advance(fmt);
jjgarcia's avatar
jjgarcia committed
762 763 764
	if (FIXNUMP(x) ||
	    type_of(x) == t_bignum ||
	    type_of(x) == t_ratio)
765
		x = ecl_make_singlefloat(ecl_to_float(x));
jjgarcia's avatar
jjgarcia committed
766
	if (!REAL_TYPE(type_of(x))) {
767
		if (fmt->nparam > 1) fmt->nparam = 1;
768
		fmt_back_up(fmt);
769
		fmt_decimal(fmt, colon, atsign);
jjgarcia's avatar
jjgarcia committed
770 771
		return;
	}
772
	if (type_of(x) == t_doublefloat)
jjgarcia's avatar
jjgarcia committed
773 774 775
		n = 16;
	else
		n = 7;
776
	f = ecl_to_double(x);
jjgarcia's avatar
jjgarcia committed
777 778
	edit_double(n, f, &sign, buff, &exp);
	if (exp + k > 100 || exp + k < -100 || d > 100) {
779
		ecl_prin1(x, fmt->stream);
jjgarcia's avatar
jjgarcia committed
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
		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) {
842
			w = set_param(fmt, 0, INT, 0);
jjgarcia's avatar
jjgarcia committed
843
			for (i = 0;  i < w;  i++)
844
				ecl_write_char(overflowchar, fmt->stream);
jjgarcia's avatar
jjgarcia committed
845 846
			return;
		}
847
		if (j < w && d < 0 && b[j-1] == '.') {
jjgarcia's avatar
jjgarcia committed
848 849 850 851 852 853 854 855
			b[j++] = '0';
			b[j] = '\0';
		}
		if (j < w && b[0] == '.') {
			*--b = '0';
			j++;
		}
		for (i = j;  i < w;  i++)
856
			ecl_write_char(padchar, fmt->stream);
jjgarcia's avatar
jjgarcia committed
857 858 859 860 861 862 863 864 865 866 867
	} else {
		if (b[0] == '.') {
			*--b = '0';
			j++;
		}
		if (d < 0 && b[j-1] == '.') {
			b[j++] = '0';
			b[j] = '\0';
		}
	}
	if (sign < 0)
868
		ecl_write_char('-', fmt->stream);
jjgarcia's avatar
jjgarcia committed
869
	else if (atsign)
870
		ecl_write_char('+', fmt->stream);
871
	writestr_stream(b, fmt->stream);
jjgarcia's avatar
jjgarcia committed
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
}

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
889
fmt_exponent1(cl_object stream, int e)
jjgarcia's avatar
jjgarcia committed
890 891 892
{
	if (e == 0)
		return;
893
	fmt_exponent1(stream, e/10);
894
	ecl_write_char('0' + e%10, stream);
jjgarcia's avatar
jjgarcia committed
895 896 897
}

static void
898
fmt_exponent(format_stack fmt, int e)
jjgarcia's avatar
jjgarcia committed
899 900
{
	if (e == 0) {
901
		ecl_write_char('0', fmt->stream);
jjgarcia's avatar
jjgarcia committed
902 903 904 905
		return;
	}
	if (e < 0)
		e = -e;
906
	fmt_exponent1(fmt->stream, e);
jjgarcia's avatar
jjgarcia committed
907 908 909
}

static void
910
fmt_exponential_float(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
911 912 913 914 915 916 917 918 919
{
	int w, d, e, k, overflowchar, padchar, exponentchar;
	double f;
	int sign;
	char buff[256], *b, buff1[256];
	int exp;
	int i, j;
	cl_object x, y;
	int n, m;
920
	cl_type t;
jjgarcia's avatar
jjgarcia committed
921 922 923

	b = buff1 + 1;

924 925 926 927 928 929 930 931 932 933 934
	fmt_not_colon(fmt, colon);
	ensure_param(fmt, 7);
	w = set_param_positive(fmt, 0, "illegal width");
	d = set_param_positive(fmt, 1, "illegal number of digits");
	e = set_param_positive(fmt, 2, "illegal number of digits in exponent");
	k = set_param(fmt, 3, INT, 1);
	overflowchar = set_param(fmt, 4, CHAR, -1);
	padchar = set_param(fmt, 5, CHAR, ' ');
	exponentchar = set_param(fmt, 6, CHAR, -1);

	x = fmt_advance(fmt);
jjgarcia's avatar
jjgarcia committed
935 936 937
	if (FIXNUMP(x) ||
	    type_of(x) == t_bignum ||
	    type_of(x) == t_ratio)
938
		x = ecl_make_singlefloat(ecl_to_float(x));
jjgarcia's avatar
jjgarcia committed
939
	if (!REAL_TYPE(type_of(x))) {
940
		if (fmt->nparam > 1) fmt->nparam = 1;
941
		fmt_back_up(fmt);
942
		fmt_decimal(fmt, colon, atsign);
jjgarcia's avatar
jjgarcia committed
943 944
		return;
	}
945
	if (type_of(x) == t_doublefloat)
jjgarcia's avatar
jjgarcia committed
946 947 948
		n = 16;
	else
		n = 7;
949
	f = ecl_to_double(x);
jjgarcia's avatar
jjgarcia committed
950 951 952 953
	edit_double(n, f, &sign, buff, &exp);
	if (d >= 0) {
		if (k > 0) {
			if (!(k < d + 2))
954
				fmt_error(fmt, "illegal scale factor");
jjgarcia's avatar
jjgarcia committed
955 956 957
			m = d + 1;
		} else {
			if (!(k > -d))
958
				fmt_error(fmt, "illegal scale factor");
jjgarcia's avatar
jjgarcia committed
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
			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[0] == '.') {
			*--b = '0';
			j++;
		}
		for (i = j;  i < w;  i++)
1038
			ecl_write_char(padchar, fmt->stream);
jjgarcia's avatar
jjgarcia committed
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
	} else {
		if (b[j-1] == '.') {
			b[j++] = '0';
			b[j] = '\0';
		}
		if (d < 0 && b[0] == '.') {
			*--b = '0';
			j++;
		}
	}
	if (sign < 0)
1050
		ecl_write_char('-', fmt->stream);
jjgarcia's avatar
jjgarcia committed
1051
	else if (atsign)
1052
		ecl_write_char('+', fmt->stream);
1053
	writestr_stream(b, fmt->stream);
1054
	y = ecl_symbol_value(@'*read-default-float-format*');
jjgarcia's avatar
jjgarcia committed
1055
	if (exponentchar < 0) {
1056 1057 1058 1059
		if (y == @'long-float') {
#ifdef ECL_LONG_FLOAT
			t = t_longfloat;
#else
1060
			t = t_doublefloat;
1061 1062 1063 1064
#endif
		} else if (y == @'double-float') {
			t = t_doublefloat;
		} else if (y == @'single-float') {
1065
			t = t_singlefloat;
1066 1067 1068
		} else {
			t = t_singlefloat;
		}
jjgarcia's avatar
jjgarcia committed
1069 1070
		if (type_of(x) == t)
			exponentchar = 'E';
1071 1072
		else if (type_of(x) == t_singlefloat)
			exponentchar = 'F';
1073 1074 1075 1076
#ifdef ECL_LONG_FLOAT
		else if (type_of(x) == t_longfloat)
			exponentchar = 'L';
#endif
jjgarcia's avatar
jjgarcia committed
1077
		else
1078
			exponentchar = 'D';
jjgarcia's avatar
jjgarcia committed
1079
	}
1080
	ecl_write_char(exponentchar, fmt->stream);
jjgarcia's avatar
jjgarcia committed
1081
	if (exp < 0)
1082
		ecl_write_char('-', fmt->stream);
jjgarcia's avatar
jjgarcia committed
1083
	else
1084
		ecl_write_char('+', fmt->stream);
jjgarcia's avatar
jjgarcia committed
1085 1086
	if (e >= 0)
		for (i = e - fmt_exponent_length(exp);  i > 0;  --i)
1087
			ecl_write_char('0', fmt->stream);
1088
	fmt_exponent(fmt, exp);
jjgarcia's avatar
jjgarcia committed
1089 1090 1091
	return;

OVER:
1092
	w = set_param(fmt, 0, INT, -1);
jjgarcia's avatar
jjgarcia committed
1093
	for (i = 0;  i < w;  i++)
1094
		ecl_write_char(overflowchar, fmt->stream);
jjgarcia's avatar
jjgarcia committed
1095 1096 1097 1098
	return;
}

static void
1099
fmt_general_float(format_stack fmt, bool colon, bool atsign)
jjgarcia's avatar
jjgarcia committed
1100 1101 1102 1103 1104 1105 1106
{
	int w, d, e, k, overflowchar, padchar, exponentchar;
	int sign, exp;
	char buff[256];
	cl_object x;
	int n, ee, ww, q, dd;

1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
	fmt_not_colon(fmt, colon);
	ensure_param(fmt, 7);
	w = set_param_positive(fmt, 0, "illegal width");
	d = set_param_positive(fmt, 1, "illegal number of digits");
	e = set_param_positive(fmt, 2, "illegal number of digits in exponent");
	k = set_param(fmt, 3, INT, 1);
	overflowchar = set_param(fmt, 4, CHAR, -1);
	padchar = set_param(fmt, 5, CHAR, ' ');
	exponentchar = set_param(fmt, 6, CHAR, -1);

	x = fmt_advance(fmt);
jjgarcia's avatar
jjgarcia committed
1118
	if (!REAL_TYPE(type_of(x))) {
1119
		if (fmt->nparam > 1) fmt->nparam = 1;
1120
		fmt_back_up(fmt);
1121
		fmt_decimal(fmt, colon, atsign);
jjgarcia's avatar
jjgarcia committed
1122 1123
		return;
	}
1124
	if (type_of(x) == t_doublefloat)
jjgarcia's avatar
jjgarcia committed
1125 1126 1127
		q = 16;
	else
		q = 7;
1128
	edit_double(q, ecl_to_double(x), &sign, buff, &exp);
jjgarcia's avatar
jjgarcia committed
1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
	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) {
1146 1147 1148 1149 1150 1151 1152
		fmt->nparam = 5;
		fmt->param[0].value = ww;
		fmt->param[1].value = dd;
		fmt->param[1].type = INT;
		fmt->param[2].type = NONE;
		fmt->param[3] = fmt->param[4];
		fmt->param[4] = fmt->param[5];
1153
		fmt_back_up(fmt);
1154
		fmt_fix_float(fmt, colon, atsign);
jjgarcia's avatar
jjgarcia committed
1155 1156
		if (w >= 0)
			while (ww++ < w)
1157
				ecl_write_char(padchar, fmt->stream);
jjgarcia's avatar
jjgarcia committed
1158 1159
		return;
	}
1160 1161
	fmt->param[1].value = d;
	fmt->param[1].type = INT;
1162
	fmt_back_up(fmt);
1163
	fmt_exponential_float(fmt, colon, atsign);
jjgarcia's avatar
jjgarcia committed
1164 1165 1166
}

static void