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