1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm 26228753Smm#include "archive_platform.h" 27229592Smm__FBSDID("$FreeBSD$"); 28228753Smm 29228753Smm/* 30228753Smm * The use of printf()-family functions can be troublesome 31228753Smm * for space-constrained applications. In addition, correctly 32228753Smm * implementing this function in terms of vsnprintf() requires 33228753Smm * two calls (one to determine the size, another to format the 34228753Smm * result), which in turn requires duplicating the argument list 35228753Smm * using va_copy, which isn't yet universally available. <sigh> 36228753Smm * 37228753Smm * So, I've implemented a bare minimum of printf()-like capability 38228753Smm * here. This is only used to format error messages, so doesn't 39228753Smm * require any floating-point support or field-width handling. 40228753Smm */ 41228753Smm 42228753Smm#include <stdio.h> 43228753Smm 44228753Smm#include "archive_string.h" 45228753Smm#include "archive_private.h" 46228753Smm 47228753Smm/* 48228753Smm * Utility functions to format signed/unsigned integers and append 49228753Smm * them to an archive_string. 50228753Smm */ 51228753Smmstatic void 52228753Smmappend_uint(struct archive_string *as, uintmax_t d, unsigned base) 53228753Smm{ 54228753Smm static const char *digits = "0123456789abcdef"; 55228753Smm if (d >= base) 56228753Smm append_uint(as, d/base, base); 57228753Smm archive_strappend_char(as, digits[d % base]); 58228753Smm} 59228753Smm 60228753Smmstatic void 61228753Smmappend_int(struct archive_string *as, intmax_t d, unsigned base) 62228753Smm{ 63228753Smm if (d < 0) { 64228753Smm archive_strappend_char(as, '-'); 65228753Smm d = -d; 66228753Smm } 67228753Smm append_uint(as, d, base); 68228753Smm} 69228753Smm 70228753Smm 71228753Smmvoid 72228753Smm__archive_string_sprintf(struct archive_string *as, const char *fmt, ...) 73228753Smm{ 74228753Smm va_list ap; 75228753Smm 76228753Smm va_start(ap, fmt); 77228753Smm archive_string_vsprintf(as, fmt, ap); 78228753Smm va_end(ap); 79228753Smm} 80228753Smm 81228753Smm/* 82228753Smm * Like 'vsprintf', but ensures the target is big enough, resizing if 83228753Smm * necessary. 84228753Smm */ 85228753Smmvoid 86228753Smm__archive_string_vsprintf(struct archive_string *as, const char *fmt, 87228753Smm va_list ap) 88228753Smm{ 89228753Smm char long_flag; 90228753Smm intmax_t s; /* Signed integer temp. */ 91228753Smm uintmax_t u; /* Unsigned integer temp. */ 92228753Smm const char *p, *p2; 93228753Smm 94228753Smm if (__archive_string_ensure(as, 64) == NULL) 95228753Smm __archive_errx(1, "Out of memory"); 96228753Smm 97228753Smm if (fmt == NULL) { 98228753Smm as->s[0] = 0; 99228753Smm return; 100228753Smm } 101228753Smm 102228753Smm for (p = fmt; *p != '\0'; p++) { 103228753Smm const char *saved_p = p; 104228753Smm 105228753Smm if (*p != '%') { 106228753Smm archive_strappend_char(as, *p); 107228753Smm continue; 108228753Smm } 109228753Smm 110228753Smm p++; 111228753Smm 112228753Smm long_flag = '\0'; 113228753Smm switch(*p) { 114228753Smm case 'j': 115228753Smm long_flag = 'j'; 116228753Smm p++; 117228753Smm break; 118228753Smm case 'l': 119228753Smm long_flag = 'l'; 120228753Smm p++; 121228753Smm break; 122228753Smm } 123228753Smm 124228753Smm switch (*p) { 125228753Smm case '%': 126228753Smm __archive_strappend_char(as, '%'); 127228753Smm break; 128228753Smm case 'c': 129228753Smm s = va_arg(ap, int); 130228753Smm __archive_strappend_char(as, s); 131228753Smm break; 132228753Smm case 'd': 133228753Smm switch(long_flag) { 134228753Smm case 'j': s = va_arg(ap, intmax_t); break; 135228753Smm case 'l': s = va_arg(ap, long); break; 136228753Smm default: s = va_arg(ap, int); break; 137228753Smm } 138228753Smm append_int(as, s, 10); 139228753Smm break; 140228753Smm case 's': 141228753Smm p2 = va_arg(ap, char *); 142228753Smm archive_strcat(as, p2); 143228753Smm break; 144228753Smm case 'o': case 'u': case 'x': case 'X': 145228753Smm /* Common handling for unsigned integer formats. */ 146228753Smm switch(long_flag) { 147228753Smm case 'j': u = va_arg(ap, uintmax_t); break; 148228753Smm case 'l': u = va_arg(ap, unsigned long); break; 149228753Smm default: u = va_arg(ap, unsigned int); break; 150228753Smm } 151228753Smm /* Format it in the correct base. */ 152228753Smm switch (*p) { 153228753Smm case 'o': append_uint(as, u, 8); break; 154228753Smm case 'u': append_uint(as, u, 10); break; 155228753Smm default: append_uint(as, u, 16); break; 156228753Smm } 157228753Smm break; 158228753Smm default: 159228753Smm /* Rewind and print the initial '%' literally. */ 160228753Smm p = saved_p; 161228753Smm archive_strappend_char(as, *p); 162228753Smm } 163228753Smm } 164228753Smm} 165