1 /* 2 * This file is part of the XForms library package. 3 * 4 * XForms is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU Lesser General Public License as 6 * published by the Free Software Foundation; either version 2.1, or 7 * (at your option) any later version. 8 * 9 * XForms is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public License 15 * along with XForms. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 19 #ifndef FLVASPRINTF_H 20 #define FLVASPRINTF_H 21 22 #ifdef HAVE_CONFIG_H 23 #include "config.h" 24 #endif 25 26 #include <stdio.h> 27 #include <stdarg.h> 28 #include "flsnprintf.h" 29 30 #if defined ( HAVE_VASPRINTF ) && ! defined ( HAVE_DECL_VASPRINTF ) 31 int 32 vasprintf( char ** strp, 33 const char * fmt, 34 va_list ap ); 35 #endif 36 37 /* Macro for allocating a buffer and filling it with a string 38 * constructed from a format string and an unspecified number 39 * of arguments. It expects a char pointer first (which will 40 * be set to the address of the memory allocated for the resulting 41 * string) and a (const) char pointer with a printf-like format 42 * string (if the pointer to the format string is NULL memory is 43 * obtained for the empty string). Of course, the function from 44 * which the macro is invoked from must be a variadic function, 45 * called with the appropriate number of types of arguments for 46 * the format string. 47 * 48 * On success the first argument will be set to a buffer long 49 * enough and containing the intended string. If there wasn't 50 * enough memory available an attempted is make to at least 51 * allocate memory for the empty string. If even this fails 52 * the first macro argument is set to NULL. 53 * 54 * Of course it's the responsibility of whatever invoked 55 * this macro to release the memory allocated here at the 56 * appropriate time. 57 * 58 * The best function to use here would be vasprintf(), which 59 * exactly does what we need. Older systems may not have it - 60 * in this case 'HAVE_VASPRINTF isn't defined. Unfortunately, 61 * we can't use the implementation from the flsnprintf.c file 62 * since it doesn't get compiled in the way this file is made 63 * up (and for good reasonsm the way the necessary va_copy() 64 * function gets defined is broken in more than one way). But 65 * we can use fli_vsnprintf() from that file, though with some 66 * difficulties. 67 * 68 * For such systems we need a way to not "use up" the va_list 69 * by initializing it and then passing it to some function 70 * (that's actually the rationale for using a macro here 71 * instead of a function!), so we must do the memory allo- 72 * cation here (if necessary repeatedly) and only call 73 * fli_vsnprintf(). 74 * 75 * So the whole existence of this macro is due to backward 76 * compatibility with old (pre C99) compilers that may have 77 * a uncommon way of defining a va_list. Messy, isnt' it? 78 * 79 * BTW, all locally used variables have names starting with 'l1I_' 80 * since this is a prefix no sane person would ever use - we try to 81 * avoid compiler warnings about local variables shadowing already 82 * defined ones. 83 */ 84 85 #if defined ( HAVE_VASPRINTF ) 86 87 #define EXPAND_FORMAT_STRING( buf, fmt ) \ 88 do { \ 89 if ( ! fmt || ! *fmt ) \ 90 buf = NULL; \ 91 else if ( ! strchr( fmt, '%' ) ) \ 92 { \ 93 if ( ( buf = fl_malloc( strlen( fmt ) + 1 ) ) ) \ 94 strcpy( buf, fmt ); \ 95 } \ 96 else \ 97 { \ 98 va_list l1I_ap; \ 99 \ 100 va_start( l1I_ap, fmt ); \ 101 if ( ! vasprintf( &buf, fmt, l1I_ap ) ) \ 102 buf = NULL; \ 103 va_end( l1I_ap ); \ 104 } \ 105 \ 106 if ( ! buf && ( buf = fl_malloc( 1 ) ) ) \ 107 *buf = '\0'; \ 108 } while ( 0 ) 109 110 #else 111 112 #define EXPAND_FORMAT_STRING( buf, fmt ) \ 113 do { \ 114 if ( ! fmt || ! *fmt ) \ 115 buf = NULL; \ 116 else if ( ! strchr( fmt, '%' ) ) \ 117 { \ 118 if ( ( buf = fl_malloc( strlen( fmt ) + 1 ) ) ) \ 119 strcpy( buf, fmt ); \ 120 } \ 121 else \ 122 { \ 123 int l1I_min_needed = strlen( fmt ) + 1; \ 124 int l1I_len = l1I_min_needed; \ 125 char *l1I_p; \ 126 \ 127 for ( l1I_p = strchr( fmt, '%' ); l1I_p; \ 128 l1I_p = strchr( ++l1I_p, '%' ) ) \ 129 l1I_len += 16; \ 130 \ 131 if ( ( buf = fl_malloc( l1I_len ) ) ) \ 132 { \ 133 while ( 1 ) \ 134 { \ 135 va_list l1I_ap; \ 136 int l1I_written; \ 137 \ 138 va_start( l1I_ap, fmt ); \ 139 l1I_written = fli_vsnprintf( buf, l1I_len, fmt, l1I_ap ); \ 140 va_end( l1I_ap ); \ 141 \ 142 /* Take care: older libc versions returned a negative \ 143 value if the buffer wasn't large enough space while \ 144 newer ones follow C99 and return the length of the \ 145 string needed (without the trailing '\0') */ \ 146 \ 147 if ( l1I_written > -1 && l1I_len > l1I_written ) \ 148 { \ 149 if ( l1I_len != l1I_written + 1 ) \ 150 { \ 151 l1I_p = buf; \ 152 if ( ! ( buf = fl_realloc( l1I_p, \ 153 l1I_written + 1 ) ) ) \ 154 buf = l1I_p; \ 155 } \ 156 break; \ 157 } \ 158 \ 159 l1I_len = l1I_written < 0 ? \ 160 ( 2 * l1I_len ) : ( l1I_written + 16 ); \ 161 l1I_p = buf; \ 162 if ( ! ( buf = fl_realloc( l1I_p, l1I_len ) ) ) \ 163 { \ 164 fl_free( l1I_p ); \ 165 break; \ 166 } \ 167 } \ 168 } \ 169 } \ 170 \ 171 if ( ! buf && ( buf = fl_malloc( 1 ) ) ) \ 172 *buf = '\0'; \ 173 } while ( 0 ) 174 175 #endif 176 177 178 #endif 179 180 181 /* 182 * Local variables: 183 * tab-width: 4 184 * indent-tabs-mode: nil 185 * End: 186 */ 187