Graphviz 14.1.2~dev.20260118.1035
Loading...
Searching...
No Matches
sfprint.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <assert.h>
14#include <inttypes.h>
15#include <sfio/sfhdr.h>
16#include <stddef.h>
17#include <stdio.h>
18#include <string.h>
19#include <util/gv_ctype.h>
20#include <util/gv_math.h>
21
22/* The engine for formatting data
23**
24** Written by Kiem-Phong Vo.
25*/
26
27#define HIGHBITI (~((~0u) >> 1))
28#define HIGHBITL (~((~0ull) >> 1))
29
30#define SFFMT_PREFIX (SFFMT_MINUS|SFFMT_SIGN|SFFMT_BLANK)
31
32#define FPRECIS 6 /* default precision for floats */
33
38int sfprint(FILE *f, Sffmt_t *format) {
39 int v = 0, n_s, base, fmt, flags;
40 long long lv;
41 char *sp, *ssp, *endsp, *ep, *endep;
42 int dot, width, precis, n, n_output = 0;
43 int sign, decpt;
44 ssize_t size;
45 double dval;
46 char *tls[2], **ls; /* for %..[separ]s */
47 const char *t_str; /* stuff between () */
48 ssize_t n_str; /* its length */
49
50 Argv_t argv; /* for extf to return value */
51 Sffmt_t *ft; /* format environment */
52
53 int argn; /* arg position and number */
54
55#define SLACK 1024
56 char buf[SF_MAXDIGITS + SLACK];
57 char decimal = 0, thousand = 0;
58
59#define SFputc(f,c) do { \
60 if (putc((c), (f)) == EOF) { \
61 goto done; \
62 } \
63} while (0)
64#define SFnputc(f,c,n) do { \
65 for (int i_ = 0; i_ < (n); ++i_) { \
66 if (putc((c), (f)) == EOF) { \
67 goto done; \
68 } \
69 } \
70 (n) = 0; \
71} while (0)
72#define SFwrite(f,s,n) do { \
73 if ((n) > 0 && fwrite((s), (size_t)(n), 1, (f)) < 1) { \
74 goto done; \
75 } \
76} while (0)
77
78 tls[1] = NULL;
79
80 ft = NULL;
81
82 argn = -1;
83
84 // stack a new environment
85 argv.ft = format;
86 assert(argv.ft != NULL);
87 assert(argv.ft->form != NULL);
88
89 const char *form = argv.ft->form;
90
91 ft = argv.ft;
92
93 while ((n = *form)) {
94 if (n != '%') { /* collect the non-pattern chars */
95 size_t form_len = 1;
96 while (form[form_len] != '\0' && form[form_len] != '%')
97 ++form_len;
98 SFwrite(f, form, form_len);
99 form += form_len;
100 continue;
101 } else
102 form += 1;
103
104 flags = 0;
105 size = width = precis = base = n_s = -1;
106 ssp = _Sfdigits;
107 endep = ep = NULL;
108 endsp = sp = buf + (sizeof(buf) - 1);
109 t_str = NULL;
110 n_str = dot = 0;
111
112 loop_flags: /* LOOP FOR \0, %, FLAGS, WIDTH, PRECISION, BASE, TYPE */
113 switch ((fmt = *form++)) {
114 case '\0':
115 SFputc(f, '%');
116 goto done;
117 case '%':
118 SFputc(f, '%');
119 continue;
120
121 case LEFTP: /* get the type enclosed in balanced parens */
122 t_str = form;
123 for (v = 1;;) {
124 switch (*form++) {
125 case 0: /* not balancable, retract */
126 form = t_str;
127 t_str = NULL;
128 n_str = 0;
129 goto loop_flags;
130 case LEFTP: /* increasing nested level */
131 v += 1;
132 continue;
133 case RIGHTP: /* decreasing nested level */
134 if ((v -= 1) != 0)
135 continue;
136 if (*t_str != '*')
137 n_str = (form - 1) - t_str;
138 else {
139 ++argn;
140
141 FMTSET(ft, form, LEFTP, 0, 0, 0, 0, 0, NULL, 0);
142 n = ft->extf(&argv, ft);
143 if (n < 0)
144 goto done;
145 assert(ft->flags & SFFMT_VALUE);
146 if ((t_str = argv.s) && (n_str = (int)ft->size) < 0)
147 n_str = (ssize_t)strlen(t_str);
148 }
149 goto loop_flags;
150 default:
151 // skip over
152 break;
153 }
154 }
155
156 case '-':
157 flags = (flags & ~SFFMT_ZERO) | SFFMT_LEFT;
158 goto loop_flags;
159 case '0':
160 if (!(flags & SFFMT_LEFT))
161 flags |= SFFMT_ZERO;
162 goto loop_flags;
163 case ' ':
164 if (!(flags & SFFMT_SIGN))
166 goto loop_flags;
167 case '+':
168 flags = (flags & ~SFFMT_BLANK) | SFFMT_SIGN;
169 goto loop_flags;
170 case '#':
172 goto loop_flags;
173 case QUOTE:
174 SFSETLOCALE(decimal, thousand);
175 if (thousand)
177 goto loop_flags;
178
179 case '.':
180 dot += 1;
181 if (dot == 1) { /* so base can be defined without setting precis */
182 if (*form != '.')
183 precis = 0;
184 } else if (dot == 2) {
185 base = 0; /* for %s,%c */
186 if (*form == 'c' || *form == 's')
187 goto loop_flags;
188 if (*form && !gv_isalnum(*form) &&
189 (form[1] == 'c' || form[1] == 's')) {
190 if (*form == '*')
191 goto do_star;
192 else {
193 base = *form++;
194 goto loop_flags;
195 }
196 }
197 }
198
199 if (gv_isdigit(*form)) {
200 fmt = *form++;
201 goto dot_size;
202 } else if (*form != '*')
203 goto loop_flags;
204 do_star:
205 form += 1; /* fall through */
206 case '*':
207 form = _Sffmtintf(form);
208 n = ++argn;
209
210 FMTSET(ft, form, '.', dot, 0, 0, 0, 0, NULL, 0);
211 if (ft->extf(&argv, ft) < 0)
212 goto done;
213 assert(ft->flags & SFFMT_VALUE);
214 v = argv.i;
215 goto dot_set;
216
217 case '1':
218 case '2':
219 case '3':
220 case '4':
221 case '5':
222 case '6':
223 case '7':
224 case '8':
225 case '9':
226 dot_size:
227 for (v = fmt - '0'; gv_isdigit(*form); ++form)
228 v = v * 10 + (*form - '0');
229 dot_set:
230 if (dot == 0) {
231 if ((width = v) < 0) {
232 width = -width;
233 flags = (flags & ~SFFMT_ZERO) | SFFMT_LEFT;
234 }
235 } else if (dot == 1)
236 precis = v;
237 else if (dot == 2)
238 base = v;
239 goto loop_flags;
240
241 case 'I': /* object length */
242 size = 0;
243 flags = (flags & ~SFFMT_TYPES) | SFFMT_IFLAG;
244 if (gv_isdigit(*form)) {
245 for (n = *form; gv_isdigit(n); n = *++form)
246 size = size * 10 + (n - '0');
247 } else if (*form == '*') {
248 form = _Sffmtintf(form + 1);
249 n = ++argn;
250
251 FMTSET(ft, form, 'I', sizeof(int), 0, 0, 0, 0, NULL, 0);
252 if (ft->extf(&argv, ft) < 0)
253 goto done;
254 assert(ft->flags & SFFMT_VALUE);
255 size = argv.i;
256 }
257 goto loop_flags;
258
259 case 'l':
260 size = -1;
261 flags &= ~SFFMT_TYPES;
262 if (*form == 'l') {
263 form += 1;
265 } else
266 flags |= SFFMT_LONG;
267 goto loop_flags;
268 case 'h':
269 size = -1;
270 flags &= ~SFFMT_TYPES;
271 if (*form == 'h') {
272 form += 1;
274 } else
276 goto loop_flags;
277 case 'L':
278 size = -1;
279 flags = (flags & ~SFFMT_TYPES) | SFFMT_LDOUBLE;
280 goto loop_flags;
281
282 case 'j':
283 size = -1;
284 flags = (flags & ~SFFMT_TYPES) | SFFMT_JFLAG;
285 goto loop_flags;
286 case 'z':
287 size = -1;
288 flags = (flags & ~SFFMT_TYPES) | SFFMT_ZFLAG;
289 goto loop_flags;
290 case 't':
291 size = -1;
292 flags = (flags & ~SFFMT_TYPES) | SFFMT_TFLAG;
293 goto loop_flags;
294 default: // continue with logic below
295 break;
296 }
297
298 /* set the correct size */
299 if (flags & (SFFMT_TYPES & ~SFFMT_IFLAG)) {
300 if (_Sftype[fmt] & (SFFMT_INT | SFFMT_UINT)) {
301 size = (flags & SFFMT_LLONG) ? (ssize_t)sizeof(long long) :
302 (flags & SFFMT_LONG) ? (ssize_t)sizeof(long) :
303 (flags & SFFMT_SHORT) ? (ssize_t)sizeof(short) :
304 (flags & SFFMT_SSHORT) ? (ssize_t)sizeof(char) :
305 (flags & SFFMT_JFLAG) ? (ssize_t)sizeof(long long) :
306 (flags & SFFMT_TFLAG) ? (ssize_t)sizeof(ptrdiff_t) :
307 (flags & SFFMT_ZFLAG) ? (ssize_t)sizeof(size_t) : -1;
308 } else if (_Sftype[fmt] & SFFMT_FLOAT) {
309 size = (flags & SFFMT_LDOUBLE) ? (ssize_t)sizeof(long double) :
310 (flags & (SFFMT_LONG | SFFMT_LLONG)) ? (ssize_t)sizeof(double) : -1;
311 }
312 }
313
314 ++argn;
315 FMTSET(ft, form, fmt, size, flags, width, precis, base, t_str, n_str);
316 v = ft->extf(&argv, ft);
317
318 if (v < 0)
319 goto done;
320 else if (v == 0) { // extf did not output
321 FMTGET(ft, form, fmt, size, flags, width, precis, base);
322 assert(ft->flags & SFFMT_VALUE);
323 } else if (v > 0) { // extf output v bytes
324 n_output += v;
325 continue;
326 }
327
328 switch (fmt) { /* PRINTF DIRECTIVES */
329 default: /* unknown directive */
330 form -= 1;
331 argn -= 1;
332 continue;
333
334 case 's':
335 if (base >= 0) { /* list of strings */
336 if (!(ls = argv.sp) || !ls[0])
337 continue;
338 } else {
339 if (!(sp = argv.s))
340 sp = "(null)";
341 ls = tls;
342 tls[0] = sp;
343 }
344 for (sp = *ls;;) {
345 if ((v = size) >= 0) {
346 if (precis >= 0 && v > precis)
347 v = precis;
348 } else if (precis < 0)
349 v = strlen(sp);
350 else { /* precis >= 0 means min(strlen,precis) */
351 for (v = 0; v < precis; ++v)
352 if (sp[v] == 0)
353 break;
354 }
355 if ((n = width - v) > 0) {
356 if (flags & SFFMT_ZERO) {
357 SFnputc(f, '0', n);
358 } else if (!(flags & SFFMT_LEFT)) {
359 SFnputc(f, ' ', n);
360 }
361 }
362 SFwrite(f, sp, v);
363 if (n > 0) {
364 SFnputc(f, ' ', n);
365 }
366 if (!(sp = *++ls))
367 break;
368 else if (base > 0) {
369 SFputc(f, base);
370 }
371 }
372 continue;
373
374 case 'c': /* an array of characters */
375 if (base >= 0) {
376 if (!(sp = argv.s) || !sp[0])
377 continue;
378 } else {
379 fmt = (int) argv.c;
380 sp = buf;
381 buf[0] = fmt;
382 buf[1] = 0;
383 }
384 if (precis <= 0)
385 precis = 1;
386 for (fmt = *sp;;) {
387 if ((n = width - precis) > 0 && !(flags & SFFMT_LEFT)) {
388 SFnputc(f, ' ', n);
389 }
390 v = precis;
391 SFnputc(f, fmt, v);
392 if (n > 0) {
393 SFnputc(f, ' ', n);
394 }
395 if (!(fmt = *++sp))
396 break;
397 else if (base > 0) {
398 SFputc(f, base);
399 }
400 }
401 continue;
402
403 case 'p': /* pointer value */
404 fmt = 'x';
405 base = 16;
406 n_s = 15;
407 n = 4;
408 flags =
411 if (sizeof(void*) > sizeof(int)) {
412 lv = (long long)(intptr_t)argv.vp;
413 goto long_cvt;
414 } else {
415 v = (int)(intptr_t)argv.vp;
416 goto int_cvt;
417 }
418 case 'o':
419 base = 8;
420 n_s = 7;
421 n = 3;
423 goto int_arg;
424 case 'X':
425 ssp = "0123456789ABCDEF";
426 // fall through
427 case 'x':
428 base = 16;
429 n_s = 15;
430 n = 4;
432 goto int_arg;
433 case 'i':
434 fmt = 'd';
435 goto d_format;
436 case 'u':
438 // fall through
439 case 'd':
440 d_format:
441 if (base < 2 || base > SF_RADIX)
442 base = 10;
443 if ((base & (n_s = base - 1)) == 0) {
444 if (base < 8)
445 n = base < 4 ? 1 : 2;
446 else if (base < 32)
447 n = base < 16 ? 3 : 4;
448 else
449 n = base < 64 ? 5 : 6;
450 } else
451 n_s = base == 10 ? -1 : 0;
452
453 int_arg:
454 if ((sizeof(long) > sizeof(int) || sizeof(void*) > sizeof(int))
455 && FMTCMP(size, long long, long long)) {
456 lv = argv.ll;
457 goto long_cvt;
458 } else if ((sizeof(long) > sizeof(int) || sizeof(void*) > sizeof(int))
459 && FMTCMP(size, long, long long)) {
460 if (fmt == 'd')
461 lv = (long long)argv.l;
462 else
463 lv = (long long)(ulong)argv.l;
464 long_cvt:
465 if (lv == 0 && precis == 0)
466 break;
467 if (lv < 0 && fmt == 'd') {
469 if ((unsigned long long)lv == HIGHBITL) { // avoid overflow
470 lv = (long long)(HIGHBITL / (unsigned long long)base);
471 *--sp = _Sfdigits[HIGHBITL -
472 (unsigned long long)lv * (unsigned long long)base];
473 } else
474 lv = -lv;
475 }
476 if (n_s < 0) { /* base 10 */
477 char scratch[41]; // space to print ≤128-bit integer
478 const int nv = snprintf(scratch, sizeof(scratch), "%lld", lv);
479 sp -= nv;
480 memcpy(sp, scratch, (size_t)nv);
481 } else if (n_s > 0) { /* base power-of-2 */
482 do {
483 *--sp = ssp[lv & n_s];
484 } while ((lv = (unsigned long long)lv >> n));
485 } else { /* general base */
486 do {
487 *--sp = ssp[(unsigned long long)lv % (unsigned long long)base];
488 } while ((lv = (unsigned long long)lv / (unsigned long long)base));
489 }
490 } else
491 if (sizeof(short) < sizeof(int) && FMTCMP(size, short, long long)) {
492 if (ft->flags & SFFMT_VALUE) {
493 if (fmt == 'd')
494 v = (int) ((short) argv.h);
495 else
496 v = (int) ((ushort) argv.h);
497 } else {
498 if (fmt == 'd')
499 v = (int) ((short) argv.i);
500 else
501 v = (int) ((ushort) argv.i);
502 }
503 goto int_cvt;
504 } else if (size == sizeof(char)) {
505 if (ft->flags & SFFMT_VALUE) {
506 if (fmt == 'd')
507 v = (int) ((char) argv.c);
508 else
509 v = (int) ((uchar) argv.c);
510 } else {
511 if (fmt == 'd')
512 v = (int) ((char) argv.i);
513 else
514 v = (int) ((uchar) argv.i);
515 }
516 goto int_cvt;
517 } else {
518 v = argv.i;
519 int_cvt:
520 if (v == 0 && precis == 0)
521 break;
522 if (v < 0 && fmt == 'd') {
524 if ((unsigned)v == HIGHBITI) { // avoid overflow
525 v = (int)(HIGHBITI / (unsigned)base);
526 *--sp = _Sfdigits[HIGHBITI - (unsigned)v * (unsigned)base];
527 } else
528 v = -v;
529 }
530 if (n_s < 0) { /* base 10 */
531 char scratch[41]; // space to print ≤128-bit integer
532 const int nv = snprintf(scratch, sizeof(scratch), "%d", v);
533 sp -= nv;
534 memcpy(sp, scratch, (size_t)nv);
535 } else if (n_s > 0) { /* base power-of-2 */
536 do {
537 *--sp = ssp[v & n_s];
538 } while ((v = (unsigned)v >> n));
539 } else { /* n_s == 0, general base */
540 do {
541 *--sp = ssp[(unsigned)v % (unsigned)base];
542 } while ((v = (unsigned)v / (unsigned)base));
543 }
544 }
545
546 if (n_s < 0 && (flags & SFFMT_THOUSAND)
547 && (n = endsp - sp) > 3) {
548 if ((n %= 3) == 0)
549 n = 3;
550 for (ep = buf + SLACK, endep = ep + n;;) {
551 while (ep < endep)
552 *ep++ = *sp++;
553 if (sp == endsp)
554 break;
555 if (sp <= endsp - 3)
556 *ep++ = thousand;
557 endep = ep + 3;
558 }
559 sp = buf + SLACK;
560 endsp = ep;
561 }
562
563 /* zero padding for precision if have room in buffer */
564 if (precis > 0 && (precis -= (endsp - sp)) < (sp - buf) - 64)
565 while (precis-- > 0)
566 *--sp = '0';
567
568 if (flags & SFFMT_ALTER) { /* prefix */
569 if (fmt == 'o') {
570 if (*sp != '0')
571 *--sp = '0';
572 } else {
573 if (width > 0 && (flags & SFFMT_ZERO)) { /* do 0 padding first */
574 if (fmt == 'x' || fmt == 'X')
575 n = 0;
576 else if (dot < 2)
577 n = width;
578 else
579 n = base < 10 ? 2 : 3;
580 n += (flags & (SFFMT_MINUS | SFFMT_SIGN)) ? 1 : 0;
581 n = width - (n + (endsp - sp));
582 while (n-- > 0)
583 *--sp = '0';
584 }
585 if (fmt == 'x' || fmt == 'X') {
586 *--sp = (char) fmt;
587 *--sp = '0';
588 } else if (dot >= 2) { /* base#value notation */
589 *--sp = '#';
590 if (base < 10)
591 *--sp = (char) ('0' + base);
592 else {
593 *--sp = _Sfdec[(base <<= 1) + 1];
594 *--sp = _Sfdec[base];
595 }
596 }
597 }
598 }
599
600 break;
601
602 case 'g':
603 case 'G': /* these ultimately become %e or %f */
604 case 'e':
605 case 'E':
606 case 'f':
607 if (!(ft->flags & SFFMT_VALUE) || FMTCMP(size, double, long double))
608 dval = argv.d;
609 else
610 dval = (double) argv.f;
611
612 if (fmt == 'e' || fmt == 'E') {
613 n = (precis = precis < 0 ? FPRECIS : precis) + 1;
614 {
615 ep = _sfcvt(&dval, imin(n, SF_FDIGITS),
616 &decpt, &sign, SFFMT_EFORMAT);
617 }
618 goto e_format;
619 } else if (fmt == 'f' || fmt == 'F') {
620 precis = precis < 0 ? FPRECIS : precis;
621 {
622 ep = _sfcvt(&dval, imin(precis, SF_FDIGITS),
623 &decpt, &sign, 0);
624 }
625 goto f_format;
626 }
627
628 /* 'g' or 'G' format */
629 precis = precis < 0 ? FPRECIS : precis == 0 ? 1 : precis;
630 {
631 ep = _sfcvt(&dval, imin(precis, SF_FDIGITS),
632 &decpt, &sign, SFFMT_EFORMAT);
633 if (dval == 0.)
634 decpt = 1;
635 else if (*ep == 'I')
636 goto infinite;
637 }
638
639 if (!(flags & SFFMT_ALTER)) { /* zap trailing 0s */
640 if ((n = sfslen()) > precis)
641 n = precis;
642 while ((n -= 1) >= 1 && ep[n] == '0');
643 n += 1;
644 } else
645 n = precis;
646
647 if (decpt < -3 || decpt > precis) {
648 precis = n - 1;
649 goto e_format;
650 } else {
651 precis = n - decpt;
652 goto f_format;
653 }
654
655 e_format: /* build the x.yyyy string */
656 if (gv_isalpha(*ep))
657 goto infinite;
658 sp = endsp = buf + 1; /* reserve space for sign */
659 *endsp++ = *ep ? *ep++ : '0';
660
661 SFSETLOCALE(decimal, thousand);
662 if (precis > 0 || (flags & SFFMT_ALTER))
663 *endsp++ = decimal;
664 ssp = endsp;
665 endep = ep + precis;
666 while ((*endsp++ = *ep++) && ep <= endep);
667 precis -= (endsp -= 1) - ssp;
668
669 /* build the exponent */
670 ep = endep = buf + (sizeof(buf) - 1);
671 if (dval != 0.) {
672 if ((n = decpt - 1) < 0)
673 n = -n;
674 while (n > 9) {
675 v = n;
676 n /= 10;
677 *--ep = (char) ('0' + (v - n * 10));
678 }
679 } else
680 n = 0;
681 *--ep = (char) ('0' + n);
682 if (endep - ep <= 1) /* at least 2 digits */
683 *--ep = '0';
684
685 /* the e/Exponent separator and sign */
686 *--ep = (decpt > 0 || dval == 0.) ? '+' : '-';
687 *--ep = gv_isupper(fmt) ? 'E' : 'e';
688
689 goto end_efg;
690
691 f_format: /* data before the decimal point */
692 if (gv_isalpha(*ep)) {
693 infinite:
694 endsp = (sp = ep) + sfslen();
695 ep = endep;
696 precis = 0;
697 goto end_efg;
698 }
699
700 SFSETLOCALE(decimal, thousand);
701 endsp = sp = buf + 1; /* save a space for sign */
702 endep = ep + decpt;
703 if (decpt > 3 && (flags & SFFMT_THOUSAND)) {
704 if ((n = decpt % 3) == 0)
705 n = 3;
706 while (ep < endep && (*endsp++ = *ep++)) {
707 if (--n == 0 && (ep <= endep - 3)) {
708 *endsp++ = thousand;
709 n = 3;
710 }
711 }
712 } else {
713 while (ep < endep && (*endsp++ = *ep++));
714 }
715 if (endsp == sp)
716 *endsp++ = '0';
717
718 if (precis > 0 || (flags & SFFMT_ALTER))
719 *endsp++ = decimal;
720
721 if ((n = -decpt) > 0) { /* output zeros for negative exponent */
722 ssp = endsp + imin(n, precis);
723 precis -= n;
724 while (endsp < ssp)
725 *endsp++ = '0';
726 }
727
728 ssp = endsp;
729 endep = ep + precis;
730 while ((*endsp++ = *ep++) && ep <= endep);
731 precis -= (endsp -= 1) - ssp;
732 ep = endep;
733 end_efg:
735 if (sign)
737 break;
738 }
739
740 if (flags == 0 && width <= 0)
741 goto do_output;
742
743 if (flags & SFFMT_PREFIX)
744 fmt =
745 (flags & SFFMT_MINUS) ? '-' : (flags & SFFMT_SIGN) ? '+' :
746 ' ';
747
748 n = (endsp - sp) + (endep - ep) + (precis <= 0 ? 0 : precis) +
749 ((flags & SFFMT_PREFIX) ? 1 : 0);
750 if ((v = width - n) <= 0)
751 v = 0;
752 else if (!(flags & SFFMT_ZERO)) { /* right padding */
753 if (flags & SFFMT_LEFT)
754 v = -v;
755 else if (flags & SFFMT_PREFIX) { /* blank padding, output prefix now */
756 *--sp = fmt;
757 flags &= ~SFFMT_PREFIX;
758 }
759 }
760
761 if (flags & SFFMT_PREFIX) { /* put out the prefix */
762 SFputc(f, fmt);
763 if (fmt != ' ')
764 flags |= SFFMT_ZERO;
765 }
766
767 if ((n = v) > 0) { /* left padding */
768 v = (flags & SFFMT_ZERO) ? '0' : ' ';
769 SFnputc(f, v, n);
770 }
771
772 if ((n = precis) > 0 && !(flags & SFFMT_FLOAT)) { /* padding for integer precision */
773 SFnputc(f, '0', n);
774 precis = 0;
775 }
776
777 do_output:
778 if ((n = endsp - sp) > 0)
779 SFwrite(f, sp, n);
780
781 if (flags & (SFFMT_FLOAT | SFFMT_LEFT)) { /* SFFMT_FLOAT: right padding for float precision */
782 if ((n = precis) > 0)
783 SFnputc(f, '0', n);
784
785 /* SFFMT_FLOAT: the exponent of %eE */
786 if ((n = endep - (sp = ep)) > 0)
787 SFwrite(f, sp, n);
788
789 /* SFFMT_LEFT: right padding */
790 if ((n = -v) > 0)
791 SFnputc(f, ' ', n);
792 }
793 }
794
795 done:
796
797 return n_output;
798}
static int flags
Definition gc.c:63
#define dot(v, w)
Definition geom.c:191
node NULL
Definition grammar.y:181
replacements for ctype.h functions
static bool gv_isupper(int c)
Definition gv_ctype.h:27
static bool gv_isalnum(int c)
Definition gv_ctype.h:43
static bool gv_isdigit(int c)
Definition gv_ctype.h:41
static bool gv_isalpha(int c)
Definition gv_ctype.h:29
Arithmetic helper functions.
static int imin(int a, int b)
minimum of two integers
Definition gv_math.h:32
GVIO_API const char * format
Definition gvio.h:51
static int sign(double v)
Definition legal.c:45
char * _sfcvt(void *dv, int n_digit, int *decpt, int *sign, int format)
Definition sfcvt.c:35
#define RIGHTP
Definition sfhdr.h:83
#define FMTCMP(sz, type, maxtype)
Definition sfhdr.h:96
#define LEFTP
Definition sfhdr.h:82
#define FMTGET(ft, frm, fv, sz, flgs, wid, pr, bs)
Definition sfhdr.h:92
#define SFSETLOCALE(decimal, thousand)
Definition sfhdr.h:52
#define SF_MAXDIGITS
Definition sfhdr.h:122
#define _Sftype
Definition sfhdr.h:132
#define ushort
Definition sfhdr.h:47
#define ulong
Definition sfhdr.h:44
#define SF_FDIGITS
Definition sfhdr.h:120
#define _Sfdec
Definition sfhdr.h:127
#define QUOTE
Definition sfhdr.h:84
#define SFFMT_EFORMAT
Definition sfhdr.h:101
#define _Sffmtintf
Definition sfhdr.h:129
#define SF_RADIX
Definition sfhdr.h:116
#define SFFMT_TYPES
Definition sfhdr.h:104
#define uchar
Definition sfhdr.h:41
#define FMTSET(ft, frm, fv, sz, flgs, wid, pr, bs, ts, ns)
Definition sfhdr.h:86
#define SFFMT_MINUS
Definition sfhdr.h:102
#define SFFMT_INT
Definition sfhdr.h:109
#define SFFMT_UINT
Definition sfhdr.h:110
#define SFFMT_FLOAT
Definition sfhdr.h:111
#define _Sfdigits
Definition sfhdr.h:128
#define SFFMT_THOUSAND
Definition sfio.h:56
#define SFFMT_ZFLAG
Definition sfio.h:49
#define SFFMT_BLANK
Definition sfio.h:53
#define SFFMT_SIGN
Definition sfio.h:52
#define SFFMT_LEFT
Definition sfio.h:51
#define SFFMT_ALTER
Definition sfio.h:55
#define SFFMT_LONG
Definition sfio.h:59
ssize_t sfslen(void)
Definition _sfslen.c:15
#define SFFMT_JFLAG
Definition sfio.h:65
#define SFFMT_SSHORT
Definition sfio.h:47
#define SFFMT_SHORT
Definition sfio.h:58
#define SFFMT_IFLAG
Definition sfio.h:64
#define SFFMT_ZERO
Definition sfio.h:54
#define SFFMT_LDOUBLE
Definition sfio.h:61
#define SFFMT_VALUE
Definition sfio.h:62
#define SFFMT_TFLAG
Definition sfio.h:48
#define SFFMT_LLONG
Definition sfio.h:60
#define SFFMT_PREFIX
Definition sfprint.c:30
#define FPRECIS
Definition sfprint.c:32
#define SFputc(f, c)
#define HIGHBITI
Definition sfprint.c:27
#define HIGHBITL
Definition sfprint.c:28
int sfprint(FILE *f, Sffmt_t *format)
Definition sfprint.c:38
#define SFnputc(f, c, n)
#define SLACK
#define SFwrite(f, s, n)
char * form
Definition sfio.h:34
int flags
Definition sfio.h:38
ssize_t size
Definition sfio.h:37
Sffmtext_f extf
Definition sfio.h:32
Definition sfhdr.h:65
short h
Definition sfhdr.h:68
Sffmt_t * ft
Definition sfhdr.h:79
char c
Definition sfhdr.h:77
char ** sp
Definition sfhdr.h:77
void * vp
Definition sfhdr.h:78
long long ll
Definition sfhdr.h:72
double d
Definition sfhdr.h:75
char * s
Definition sfhdr.h:77
long l
Definition sfhdr.h:67
int i
Definition sfhdr.h:66
float f
Definition sfhdr.h:76