1 /**
2  * @file fmt/print.c Formatted printing
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #include <string.h>
7 #include <re_types.h>
8 #include <re_sa.h>
9 #include <re_fmt.h>
10 #include <re_mem.h>
11 #include <math.h>
12 #ifdef _MSC_VER
13 #include <float.h>
14 #ifndef isinf
15 #define isinf(d) (!_finite(d))
16 #endif
17 #ifndef isnan
18 #define isnan(d) _isnan(d)
19 #endif
20 #endif
21 #ifdef SOLARIS
22 #include <ieeefp.h>
23 #undef isinf
24 #define isinf(a) (fpclass((a)) == FP_NINF || fpclass((a)) == FP_PINF)
25 #undef isnan
26 #define isnan(a) isnand((a))
27 #endif
28 
29 
30 enum length_modifier {
31 	LENMOD_NONE      = 0,
32 	LENMOD_LONG      = 1,
33 	LENMOD_LONG_LONG = 2,
34 	LENMOD_SIZE      = 42,
35 };
36 
37 enum {
38 	DEC_SIZE = 42,
39 	NUM_SIZE = 64
40 };
41 
42 static const char prfx_neg[]  = "-";
43 static const char prfx_hex[]  = "0x";
44 static const char str_nil[]  = "(nil)";
45 
46 
write_padded(const char * p,size_t sz,size_t pad,char pch,bool plr,const char * prfx,re_vprintf_h * vph,void * arg)47 static int write_padded(const char *p, size_t sz, size_t pad, char pch,
48 			bool plr, const char *prfx, re_vprintf_h *vph,
49 			void *arg)
50 {
51 	const size_t prfx_len = str_len(prfx);
52 	int err = 0;
53 
54 	pad -= MIN(pad, prfx_len);
55 
56 	if (prfx && pch == '0')
57 		err |= vph(prfx, prfx_len, arg);
58 
59 	while (!plr && (pad-- > sz))
60 		err |= vph(&pch, 1, arg);
61 
62 	if (prfx && pch != '0')
63 		err |= vph(prfx, prfx_len, arg);
64 
65 	if (p && sz)
66 		err |= vph(p, sz, arg);
67 
68 	while (plr && pad-- > sz)
69 		err |= vph(&pch, 1, arg);
70 
71 	return err;
72 }
73 
74 
local_itoa(char * buf,uint64_t n,uint8_t base,bool uc)75 static uint32_t local_itoa(char *buf, uint64_t n, uint8_t base, bool uc)
76 {
77 	char c, *p = buf + NUM_SIZE;
78 	uint32_t len = 1;
79 	const char a = uc ? 'A' : 'a';
80 
81 	*--p = '\0';
82 	do {
83 		const uint64_t dv  = n / base;
84 		const uint64_t mul = dv * base;
85 
86 		c = (char)(n - mul);
87 
88 		if (c < 10)
89 			*--p = '0' + c;
90 		else
91 			*--p = a + (c - 10);
92 
93 		n = dv;
94 		++len;
95 
96 	} while (n != 0);
97 
98 	memmove(buf, p, len);
99 
100 	return len - 1;
101 }
102 
103 
local_ftoa(char * buf,double n,size_t dp)104 static size_t local_ftoa(char *buf, double n, size_t dp)
105 {
106 	char *p = buf;
107 	long long a = (long long)n;
108 	double b = n - (double)a;
109 
110 	b = (b < 0) ? -b : b;
111 
112 	/* integral part */
113 	p += local_itoa(p, (a < 0) ? -a : a, 10, false);
114 
115 	*p++ = '.';
116 
117 	/* decimal digits */
118 	while (dp--) {
119 		char v;
120 
121 		b *= 10;
122 		v  = (char)b;
123 		b -= v;
124 
125 		*p++ = '0' + (char)v;
126 	}
127 
128 	*p = '\0';
129 
130 	return p - buf;
131 }
132 
133 
134 /**
135  * Print a formatted string
136  *
137  * @param fmt Formatted string
138  * @param ap  Variable argument
139  * @param vph Print handler
140  * @param arg Handler argument
141  *
142  * @return 0 if success, otherwise errorcode
143  *
144  * Extensions:
145  *
146  * <pre>
147  *   %b  (char *, size_t)        Buffer string with pointer and length
148  *   %r  (struct pl)             Pointer-length object
149  *   %w  (uint8_t *, size_t)     Binary buffer to hexadecimal format
150  *   %j  (struct sa *)           Socket address - address part only
151  *   %J  (struct sa *)           Socket address and port - like 1.2.3.4:1234
152  *   %H  (re_printf_h *, void *) Print handler with argument
153  *   %v  (char *fmt, va_list *)  Variable argument list
154  *   %m  (int)                   Describe an error code
155  * </pre>
156  *
157  * Reserved for the future:
158  *
159  *   %k
160  *   %y
161  *
162  */
re_vhprintf(const char * fmt,va_list ap,re_vprintf_h * vph,void * arg)163 int re_vhprintf(const char *fmt, va_list ap, re_vprintf_h *vph, void *arg)
164 {
165 	uint8_t base, *bptr;
166 	char pch, ch, num[NUM_SIZE], addr[64], msg[256];
167 	enum length_modifier lenmod = LENMOD_NONE;
168 	struct re_printf pf;
169 	bool fm = false, plr = false;
170 	const struct pl *pl;
171 	size_t pad = 0, fpad = -1, len, i;
172 	const char *str, *p = fmt, *p0 = fmt;
173 	const struct sa *sa;
174 	re_printf_h *ph;
175 	void *ph_arg;
176 	va_list *apl;
177 	int err = 0;
178 	void *ptr;
179 	uint64_t n;
180 	int64_t sn;
181 	bool uc = false;
182 	double dbl;
183 
184 	if (!fmt || !vph)
185 		return EINVAL;
186 
187 	pf.vph = vph;
188 	pf.arg = arg;
189 
190 	for (;*p && !err; p++) {
191 
192 		if (!fm) {
193 			if (*p != '%')
194 				continue;
195 
196 			pch = ' ';
197 			plr = false;
198 			pad = 0;
199 			fpad = -1;
200 			lenmod = LENMOD_NONE;
201 			uc = false;
202 
203 			if (p > p0)
204 				err |= vph(p0, p - p0, arg);
205 
206 			fm = true;
207 			continue;
208 		}
209 
210 		fm = false;
211 		base = 10;
212 
213 		switch (*p) {
214 
215 		case '-':
216 			plr = true;
217 			fm  = true;
218 			break;
219 
220 		case '.':
221 			fpad = pad;
222 			pad = 0;
223 			fm = true;
224 			break;
225 
226 		case '%':
227 			ch = '%';
228 
229 			err |= vph(&ch, 1, arg);
230 			break;
231 
232 		case 'b':
233 			str = va_arg(ap, const char *);
234 			len = va_arg(ap, size_t);
235 
236 			err |= write_padded(str, str ? len : 0, pad, ' ',
237 					    plr, NULL, vph, arg);
238 			break;
239 
240 		case 'c':
241 			ch = va_arg(ap, int);
242 
243 			err |= write_padded(&ch, 1, pad, ' ', plr, NULL,
244 					    vph, arg);
245 			break;
246 
247 		case 'd':
248 		case 'i':
249 			switch (lenmod) {
250 
251 			case LENMOD_SIZE:
252 				sn = va_arg(ap, ssize_t);
253 				break;
254 
255 			default:
256 			case LENMOD_LONG_LONG:
257 				sn = va_arg(ap, signed long long);
258 				break;
259 
260 			case LENMOD_LONG:
261 				sn = va_arg(ap, signed long);
262 				break;
263 
264 			case LENMOD_NONE:
265 				sn = va_arg(ap, signed);
266 				break;
267 			}
268 
269 			len = local_itoa(num, (sn < 0) ? -sn : sn, base,
270 					 false);
271 
272 			err |= write_padded(num, len, pad,
273 					    plr ? ' ' : pch, plr,
274 					    (sn < 0) ? prfx_neg : NULL,
275 					    vph, arg);
276 			break;
277 
278 		case 'f':
279 		case 'F':
280 			dbl = va_arg(ap, double);
281 
282 			if (fpad == (size_t)-1) {
283 				fpad = pad;
284 				pad  = 0;
285 			}
286 
287 			if (isinf(dbl)) {
288 				err |= write_padded("inf", 3, fpad,
289 						    ' ', plr, NULL, vph, arg);
290 			}
291 			else if (isnan(dbl)) {
292 				err |= write_padded("nan", 3, fpad,
293 						    ' ', plr, NULL, vph, arg);
294 			}
295 			else {
296 				len = local_ftoa(num, dbl,
297 						 pad ? min(pad, DEC_SIZE) : 6);
298 
299 				err |= write_padded(num, len, fpad,
300 						    plr ? ' ' : pch, plr,
301 						    (dbl<0) ? prfx_neg : NULL,
302 						    vph, arg);
303 			}
304 			break;
305 
306 		case 'H':
307 			ph     = va_arg(ap, re_printf_h *);
308 			ph_arg = va_arg(ap, void *);
309 
310 			if (ph)
311 				err |= ph(&pf, ph_arg);
312 			break;
313 
314 		case 'l':
315 			++lenmod;
316 			fm = true;
317 			break;
318 
319 		case 'm':
320 			str = str_error(va_arg(ap, int), msg, sizeof(msg));
321 			err |= write_padded(str, str_len(str), pad,
322 					    ' ', plr, NULL, vph, arg);
323 			break;
324 
325 		case 'p':
326 			ptr = va_arg(ap, void *);
327 
328 			if (ptr) {
329 				len = local_itoa(num, (unsigned long int)ptr,
330 						 16, false);
331 				err |= write_padded(num, len, pad,
332 						    plr ? ' ' : pch, plr,
333 						    prfx_hex, vph, arg);
334 			}
335 			else {
336 				err |= write_padded(str_nil,
337 						    sizeof(str_nil) - 1,
338 						    pad, ' ', plr, NULL,
339 						    vph, arg);
340 			}
341 			break;
342 
343 		case 'r':
344 			pl = va_arg(ap, const struct pl *);
345 
346 			err |= write_padded(pl ? pl->p : NULL,
347 					    (pl && pl->p) ? pl->l : 0,
348 					    pad, ' ', plr, NULL, vph, arg);
349 			break;
350 
351 		case 's':
352 			str = va_arg(ap, const char *);
353 			err |= write_padded(str, str_len(str), pad,
354 					    ' ', plr, NULL, vph, arg);
355 			break;
356 
357 		case 'X':
358 			uc = true;
359 			/*@fallthrough@*/
360 		case 'x':
361 			base = 16;
362 			/*@fallthrough@*/
363 		case 'u':
364 			switch (lenmod) {
365 
366 			case LENMOD_SIZE:
367 				n = va_arg(ap, size_t);
368 				break;
369 
370 			default:
371 			case LENMOD_LONG_LONG:
372 				n = va_arg(ap, unsigned long long);
373 				break;
374 
375 			case LENMOD_LONG:
376 				n = va_arg(ap, unsigned long);
377 				break;
378 
379 			case LENMOD_NONE:
380 				n = va_arg(ap, unsigned);
381 				break;
382 			}
383 
384 			len = local_itoa(num, n, base, uc);
385 
386 			err |= write_padded(num, len, pad,
387 					    plr ? ' ' : pch, plr, NULL,
388 					    vph, arg);
389 			break;
390 
391 		case 'v':
392 			str = va_arg(ap, char *);
393 			apl = va_arg(ap, va_list *);
394 
395 			if (!str || !apl)
396 				break;
397 
398 			err |= re_vhprintf(str, *apl, vph, arg);
399 			break;
400 
401 		case 'W':
402 			uc = true;
403 			/*@fallthrough@*/
404 		case 'w':
405 			bptr = va_arg(ap, uint8_t *);
406 			len = va_arg(ap, size_t);
407 
408 			len = bptr ? len : 0;
409 			pch = plr ? ' ' : pch;
410 
411 			while (!plr && pad-- > (len * 2))
412 				err |= vph(&pch, 1, arg);
413 
414 			for (i=0; i<len; i++) {
415 				const uint8_t v = *bptr++;
416 				uint32_t l = local_itoa(num, v, 16, uc);
417 				err |= write_padded(num, l, 2, '0',
418 						    false, NULL, vph, arg);
419 			}
420 
421 			while (plr && pad-- > (len * 2))
422 				err |= vph(&pch, 1, arg);
423 
424 			break;
425 
426 		case 'z':
427 			lenmod = LENMOD_SIZE;
428 			fm = true;
429 			break;
430 
431 		case 'j':
432 			sa = va_arg(ap, struct sa *);
433 			if (!sa)
434 				break;
435 			if (sa_ntop(sa, addr, sizeof(addr))) {
436 				err |= write_padded("?", 1, pad, ' ',
437 						    plr, NULL, vph, arg);
438 				break;
439 			}
440 			err |= write_padded(addr, strlen(addr), pad, ' ',
441 					    plr, NULL, vph, arg);
442 			break;
443 
444 
445 		case 'J':
446 			sa = va_arg(ap, struct sa *);
447 			if (!sa)
448 				break;
449 			if (sa_ntop(sa, addr, sizeof(addr))) {
450 				err |= write_padded("?", 1, pad, ' ',
451 						    plr, NULL, vph, arg);
452 				break;
453 			}
454 
455 #ifdef HAVE_INET6
456 			if (AF_INET6 == sa_af(sa)) {
457 				ch = '[';
458 				err |= vph(&ch, 1, arg);
459 			}
460 #endif
461 			err |= write_padded(addr, strlen(addr), pad, ' ',
462 					    plr, NULL, vph, arg);
463 #ifdef HAVE_INET6
464 			if (AF_INET6 == sa_af(sa)) {
465 				ch = ']';
466 				err |= vph(&ch, 1, arg);
467 			}
468 #endif
469 
470 			ch = ':';
471 			err |= vph(&ch, 1, arg);
472 			len = local_itoa(num, sa_port(sa), 10, false);
473 			err |= write_padded(num, len, pad,
474 					    plr ? ' ' : pch, plr, NULL,
475 					    vph, arg);
476 
477 			break;
478 
479 		default:
480 			if (('0' <= *p) && (*p <= '9')) {
481 				if (!pad && ('0' == *p)) {
482 					pch = '0';
483 				}
484 				else {
485 					pad *= 10;
486 					pad += *p - '0';
487 				}
488 				fm = true;
489 				break;
490 			}
491 
492 			ch = '?';
493 
494 			err |= vph(&ch, 1, arg);
495 			break;
496 		}
497 
498 		if (!fm)
499 			p0 = p + 1;
500 	}
501 
502 	if (!fm && p > p0)
503 		err |= vph(p0, p - p0, arg);
504 
505 	return err;
506 }
507 
508 
print_handler(const char * p,size_t size,void * arg)509 static int print_handler(const char *p, size_t size, void *arg)
510 {
511 	struct pl *pl = arg;
512 
513 	if (size > pl->l)
514 		return ENOMEM;
515 
516 	memcpy((void *)pl->p, p, size);
517 
518 	pl_advance(pl, size);
519 
520 	return 0;
521 }
522 
523 
524 struct dyn_print {
525 	char *str;
526 	char *p;
527 	size_t l;
528 	size_t size;
529 };
530 
531 
print_handler_dyn(const char * p,size_t size,void * arg)532 static int print_handler_dyn(const char *p, size_t size, void *arg)
533 {
534 	struct dyn_print *dp = arg;
535 
536 	if (size > dp->l - 1) {
537 		const size_t new_size = MAX(dp->size + size, dp->size * 2);
538 		char *str = mem_realloc(dp->str, new_size);
539 		if (!str)
540 			return ENOMEM;
541 
542 		dp->str = str;
543 		dp->l += new_size - dp->size;
544 		dp->p = dp->str + new_size - dp->l;
545 		dp->size = new_size;
546 	}
547 
548 	memcpy(dp->p, p, size);
549 
550 	dp->p += size;
551 	dp->l -= size;
552 
553 	return 0;
554 }
555 
556 
557 struct strm_print {
558 	FILE *f;
559 	size_t n;
560 };
561 
print_handler_stream(const char * p,size_t size,void * arg)562 static int print_handler_stream(const char *p, size_t size, void *arg)
563 {
564 	struct strm_print *sp = arg;
565 
566 	if (1 != fwrite(p, size, 1, sp->f))
567 		return ENOMEM;
568 
569 	sp->n += size;
570 
571 	return 0;
572 }
573 
574 
575 /**
576  * Print a formatted string to a file stream, using va_list
577  *
578  * @param stream File stream for the output
579  * @param fmt    Formatted string
580  * @param ap     Variable-arguments list
581  *
582  * @return The number of characters printed, or -1 if error
583  */
re_vfprintf(FILE * stream,const char * fmt,va_list ap)584 int re_vfprintf(FILE *stream, const char *fmt, va_list ap)
585 {
586 	struct strm_print sp;
587 
588 	if (!stream)
589 		return -1;
590 
591 	sp.f = stream;
592 	sp.n = 0;
593 
594 	if (0 != re_vhprintf(fmt, ap, print_handler_stream, &sp))
595 		return -1;
596 
597 	return (int)sp.n;
598 }
599 
600 
601 /**
602  * Print a formatted string to stdout, using va_list
603  *
604  * @param fmt Formatted string
605  * @param ap  Variable-arguments list
606  *
607  * @return The number of characters printed, or -1 if error
608  */
re_vprintf(const char * fmt,va_list ap)609 int re_vprintf(const char *fmt, va_list ap)
610 {
611 	return re_vfprintf(stdout, fmt, ap);
612 }
613 
614 
615 /**
616  * Print a formatted string to a buffer, using va_list
617  *
618  * @param str  Buffer for output string
619  * @param size Size of buffer
620  * @param fmt  Formatted string
621  * @param ap   Variable-arguments list
622  *
623  * @return The number of characters printed, or -1 if error
624  */
re_vsnprintf(char * str,size_t size,const char * fmt,va_list ap)625 int re_vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
626 {
627 	struct pl pl;
628 	int err;
629 
630 	if (!str || !size)
631 		return -1;
632 
633 	pl.p = str;
634 	pl.l = size - 1;
635 
636 	err = re_vhprintf(fmt, ap, print_handler, &pl);
637 
638 	str[size - pl.l - 1] = '\0';
639 
640 	return err ? -1 : (int)(size - pl.l - 1);
641 }
642 
643 
644 /**
645  * Print a formatted string to a dynamically allocated buffer, using va_list
646  *
647  * @param strp Pointer for output string
648  * @param fmt  Formatted string
649  * @param ap   Variable-arguments list
650  *
651  * @return 0 if success, otherwise errorcode
652  */
re_vsdprintf(char ** strp,const char * fmt,va_list ap)653 int re_vsdprintf(char **strp, const char *fmt, va_list ap)
654 {
655 	struct dyn_print dp;
656 	int err;
657 
658 	if (!strp)
659 		return EINVAL;
660 
661 	dp.size = 16;
662 	dp.str  = mem_alloc(dp.size, NULL);
663 	if (!dp.str)
664 		return ENOMEM;
665 
666 	dp.p = dp.str;
667 	dp.l = dp.size;
668 
669 	err = re_vhprintf(fmt, ap, print_handler_dyn, &dp);
670 	if (err)
671 		goto out;
672 
673 	*dp.p = '\0';
674 
675  out:
676 	if (err)
677 		mem_deref(dp.str);
678 	else
679 		*strp = dp.str;
680 
681 	return err;
682 }
683 
684 
685 /**
686  * Print a formatted string
687  *
688  * @param pf  Print backend
689  * @param fmt Formatted string
690  *
691  * @return 0 if success, otherwise errorcode
692  */
re_hprintf(struct re_printf * pf,const char * fmt,...)693 int re_hprintf(struct re_printf *pf, const char *fmt, ...)
694 {
695 	va_list ap;
696 	int err;
697 
698 	if (!pf)
699 		return EINVAL;
700 
701 	va_start(ap, fmt);
702 	err = re_vhprintf(fmt, ap, pf->vph, pf->arg);
703 	va_end(ap);
704 
705 	return err;
706 }
707 
708 
709 /**
710  * Print a formatted string to a file stream
711  *
712  * @param stream File stream for output
713  * @param fmt    Formatted string
714  *
715  * @return The number of characters printed, or -1 if error
716  */
re_fprintf(FILE * stream,const char * fmt,...)717 int re_fprintf(FILE *stream, const char *fmt, ...)
718 {
719 	va_list ap;
720 	int n;
721 
722 	va_start(ap, fmt);
723 	n = re_vfprintf(stream, fmt, ap);
724 	va_end(ap);
725 
726 	return n;
727 }
728 
729 
730 /**
731  * Print a formatted string to stdout
732  *
733  * @param fmt    Formatted string
734  *
735  * @return The number of characters printed, or -1 if error
736  */
re_printf(const char * fmt,...)737 int re_printf(const char *fmt, ...)
738 {
739 	va_list ap;
740 	int n;
741 
742 	va_start(ap, fmt);
743 	n = re_vprintf(fmt, ap);
744 	va_end(ap);
745 
746 	return n;
747 }
748 
749 
750 /**
751  * Print a formatted string to a buffer
752  *
753  * @param str  Buffer for output string
754  * @param size Size of buffer
755  * @param fmt  Formatted string
756  *
757  * @return The number of characters printed, or -1 if error
758  */
re_snprintf(char * str,size_t size,const char * fmt,...)759 int re_snprintf(char *str, size_t size, const char *fmt, ...)
760 {
761 	va_list ap;
762 	int n;
763 
764 	va_start(ap, fmt);
765 	n = re_vsnprintf(str, size, fmt, ap);
766 	va_end(ap);
767 
768 	return n;
769 }
770 
771 
772 /**
773  * Print a formatted string to a buffer
774  *
775  * @param strp Buffer pointer for output string
776  * @param fmt  Formatted string
777  *
778  * @return 0 if success, otherwise errorcode
779  */
re_sdprintf(char ** strp,const char * fmt,...)780 int re_sdprintf(char **strp, const char *fmt, ...)
781 {
782 	va_list ap;
783 	int err;
784 
785 	va_start(ap, fmt);
786 	err = re_vsdprintf(strp, fmt, ap);
787 	va_end(ap);
788 
789 	return err;
790 }
791