1 // Copyright 2012 Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // * Neither the name of Google Inc. nor the names of its contributors 14 // may be used to endorse or promote products derived from this software 15 // without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #include "text.h" 30 31 #include <assert.h> 32 #include <errno.h> 33 #include <stdarg.h> 34 #include <stdlib.h> 35 #include <stdio.h> 36 37 #include "error.h" 38 39 40 /// Calculates the length of a formatting string with its replacements. 41 /// 42 /// \param format The formatting string. 43 /// \param ap List of arguments to apply to the formatting string. 44 /// 45 /// \return -1 if there is an error; or the final length otherwise. 46 static int 47 calculate_length(const char* format, va_list ap) 48 { 49 va_list ap2; 50 51 char buffer[1]; 52 va_copy(ap2, ap); 53 const int needed = vsnprintf(buffer, sizeof(buffer), format, ap); 54 va_end(ap2); 55 return needed; 56 } 57 58 59 /// Generates a string from a format string and its replacements. 60 /// 61 /// \param [out] output Pointer to the dynamically-allocated string with the 62 /// result of the operation. The caller must release this with free(). 63 /// \param format The formatting string. 64 /// \param ... Arguments to apply to the formatting string. 65 /// 66 /// \return OK if the string could be formatted; an error otherwise. 67 kyua_error_t 68 kyua_text_printf(char** output, const char* format, ...) 69 { 70 kyua_error_t error; 71 va_list ap; 72 73 va_start(ap, format); 74 error = kyua_text_vprintf(output, format, ap); 75 va_end(ap); 76 77 return error; 78 } 79 80 81 /// Generates a string from a format string and its replacements. 82 /// 83 /// \param [out] output Pointer to the dynamically-allocated string with the 84 /// result of the operation. The caller must release this with free(). 85 /// \param format The formatting string. 86 /// \param ap List of to apply to the formatting string. 87 /// 88 /// \return OK if the string could be formatted; an error otherwise. 89 kyua_error_t 90 kyua_text_vprintf(char** output, const char* format, va_list ap) 91 { 92 va_list ap2; 93 94 va_copy(ap2, ap); 95 const int length = calculate_length(format, ap2); 96 va_end(ap2); 97 if (length < 0) 98 return kyua_libc_error_new(errno, "Could not calculate length of " 99 "string with format '%s'", format); 100 101 char* buffer = (char*)malloc(length + 1); 102 if (buffer == NULL) 103 return kyua_oom_error_new(); 104 105 va_copy(ap2, ap); 106 const int printed_length = vsnprintf(buffer, length + 1, format, ap2); 107 va_end(ap2); 108 assert(printed_length == length); 109 if (printed_length < 0) { 110 free(buffer); 111 return kyua_libc_error_new(errno, "Could generate string with format " 112 "'%s'", format); 113 } 114 115 *output = buffer; 116 return kyua_error_ok(); 117 } 118