archive_string_sprintf.c revision 229592
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 2003-2007 Tim Kientzle
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes *
141590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
151590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
161590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
171590Srgrimes * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
181590Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
191590Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
201590Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
211590Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
221590Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
231590Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
241590Srgrimes */
251590Srgrimes
261590Srgrimes#include "archive_platform.h"
271590Srgrimes__FBSDID("$FreeBSD: stable/9/contrib/libarchive/libarchive/archive_string_sprintf.c 229592 2012-01-05 12:06:54Z mm $");
281590Srgrimes
291590Srgrimes/*
301590Srgrimes * The use of printf()-family functions can be troublesome
311590Srgrimes * for space-constrained applications.  In addition, correctly
3260833Sjake * implementing this function in terms of vsnprintf() requires
3360833Sjake * two calls (one to determine the size, another to format the
341590Srgrimes * result), which in turn requires duplicating the argument list
351590Srgrimes * using va_copy, which isn't yet universally available. <sigh>
361590Srgrimes *
371590Srgrimes * So, I've implemented a bare minimum of printf()-like capability
381590Srgrimes * here.  This is only used to format error messages, so doesn't
391590Srgrimes * require any floating-point support or field-width handling.
401590Srgrimes */
411590Srgrimes
421590Srgrimes#include <stdio.h>
431590Srgrimes
441590Srgrimes#include "archive_string.h"
451590Srgrimes#include "archive_private.h"
461590Srgrimes
471590Srgrimes/*
481590Srgrimes * Utility functions to format signed/unsigned integers and append
491590Srgrimes * them to an archive_string.
501590Srgrimes */
5174588Sachestatic void
5216438Sacheappend_uint(struct archive_string *as, uintmax_t d, unsigned base)
531590Srgrimes{
541590Srgrimes	static const char *digits = "0123456789abcdef";
551590Srgrimes	if (d >= base)
561590Srgrimes		append_uint(as, d/base, base);
571590Srgrimes	archive_strappend_char(as, digits[d % base]);
581590Srgrimes}
591590Srgrimes
601590Srgrimesstatic void
6111547Sdgappend_int(struct archive_string *as, intmax_t d, unsigned base)
621590Srgrimes{
631590Srgrimes	if (d < 0) {
641590Srgrimes		archive_strappend_char(as, '-');
6577291Sdd		d = -d;
661590Srgrimes	}
671590Srgrimes	append_uint(as, d, base);
681590Srgrimes}
691590Srgrimes
701590Srgrimes
711590Srgrimesvoid
721590Srgrimes__archive_string_sprintf(struct archive_string *as, const char *fmt, ...)
731590Srgrimes{
741590Srgrimes	va_list ap;
751590Srgrimes
761590Srgrimes	va_start(ap, fmt);
771590Srgrimes	archive_string_vsprintf(as, fmt, ap);
781590Srgrimes	va_end(ap);
7960938Sjake}
8011547Sdg
8111547Sdg/*
8236062Sjb * Like 'vsprintf', but ensures the target is big enough, resizing if
831590Srgrimes * necessary.
8460938Sjake */
8511547Sdgvoid
861590Srgrimes__archive_string_vsprintf(struct archive_string *as, const char *fmt,
871590Srgrimes    va_list ap)
881590Srgrimes{
891590Srgrimes	char long_flag;
9036434Sdanny	intmax_t s; /* Signed integer temp. */
9136434Sdanny	uintmax_t u; /* Unsigned integer temp. */
9274588Sache	const char *p, *p2;
9377291Sdd
9477291Sdd	if (__archive_string_ensure(as, 64) == NULL)
9577291Sdd		__archive_errx(1, "Out of memory");
9677291Sdd
971590Srgrimes	if (fmt == NULL) {
981590Srgrimes		as->s[0] = 0;
991590Srgrimes		return;
1001590Srgrimes	}
1011590Srgrimes
10277291Sdd	for (p = fmt; *p != '\0'; p++) {
10311547Sdg		const char *saved_p = p;
1041590Srgrimes
1051590Srgrimes		if (*p != '%') {
10636434Sdanny			archive_strappend_char(as, *p);
10736434Sdanny			continue;
10836434Sdanny		}
10936434Sdanny
11036434Sdanny		p++;
11136434Sdanny
11236434Sdanny		long_flag = '\0';
11336434Sdanny		switch(*p) {
1141590Srgrimes		case 'j':
1151590Srgrimes			long_flag = 'j';
1161590Srgrimes			p++;
1171590Srgrimes			break;
1181590Srgrimes		case 'l':
1191590Srgrimes			long_flag = 'l';
1201590Srgrimes			p++;
1211590Srgrimes			break;
12216438Sache		}
12374588Sache
12416438Sache		switch (*p) {
1251590Srgrimes		case '%':
12677291Sdd			__archive_strappend_char(as, '%');
12777291Sdd			break;
1281590Srgrimes		case 'c':
1291590Srgrimes			s = va_arg(ap, int);
1301590Srgrimes			__archive_strappend_char(as, s);
1311590Srgrimes			break;
1321590Srgrimes		case 'd':
1331590Srgrimes			switch(long_flag) {
1341590Srgrimes			case 'j': s = va_arg(ap, intmax_t); break;
1351590Srgrimes			case 'l': s = va_arg(ap, long); break;
1361590Srgrimes			default:  s = va_arg(ap, int); break;
1371590Srgrimes			}
1381590Srgrimes		        append_int(as, s, 10);
1391590Srgrimes			break;
1401590Srgrimes		case 's':
1411590Srgrimes			p2 = va_arg(ap, char *);
1421590Srgrimes			archive_strcat(as, p2);
1431590Srgrimes			break;
1441590Srgrimes		case 'o': case 'u': case 'x': case 'X':
14577291Sdd			/* Common handling for unsigned integer formats. */
14677291Sdd			switch(long_flag) {
14777291Sdd			case 'j': u = va_arg(ap, uintmax_t); break;
1481590Srgrimes			case 'l': u = va_arg(ap, unsigned long); break;
1491590Srgrimes			default:  u = va_arg(ap, unsigned int); break;
1501590Srgrimes			}
1511590Srgrimes			/* Format it in the correct base. */
1521590Srgrimes			switch (*p) {
1531590Srgrimes			case 'o': append_uint(as, u, 8); break;
1541590Srgrimes			case 'u': append_uint(as, u, 10); break;
15536434Sdanny			default: append_uint(as, u, 16); break;
15636434Sdanny			}
15736434Sdanny			break;
1581590Srgrimes		default:
1591590Srgrimes			/* Rewind and print the initial '%' literally. */
1601590Srgrimes			p = saved_p;
16136434Sdanny			archive_strappend_char(as, *p);
16236434Sdanny		}
16336434Sdanny	}
1641590Srgrimes}
1651590Srgrimes