vsnprintf.c (7315B)
1 /* -*-comment-start: "//";comment-end:""-*- 2 * GNU Mes --- Maxwell Equations of Software 3 * Copyright © 2017,2018,2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org> 4 * 5 * This file is part of GNU Mes. 6 * 7 * GNU Mes is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 3 of the License, or (at 10 * your option) any later version. 11 * 12 * GNU Mes is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with GNU Mes. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include <mes/lib.h> 22 #include <ctype.h> 23 #include <stdarg.h> 24 #include <string.h> 25 26 int 27 vsnprintf (char *str, size_t size, char const *format, va_list ap) 28 { 29 char const *p = format; 30 int count = 0; 31 char c; 32 while (*p) 33 if (*p != '%') 34 { 35 c = *p++; 36 if (count < size) 37 *str++ = c; 38 count++; 39 } 40 else 41 { 42 p++; 43 c = *p; 44 int left_p = 0; 45 int precision = -1; 46 int width = -1; 47 if (c == '-') 48 { 49 left_p = 1; 50 c = *++p; 51 } 52 char pad = ' '; 53 if (c == ' ') 54 { 55 pad = c; 56 c = *p++; 57 } 58 if (c == '0') 59 { 60 pad = c; 61 c = *p++; 62 } 63 if (c >= '0' && c <= '9') 64 { 65 width = abtol (&p, 10); 66 c = *p; 67 } 68 else if (c == '*') 69 { 70 width = va_arg (ap, long); 71 c = *++p; 72 } 73 if (c == '.') 74 { 75 c = *++p; 76 if (c >= '0' && c <= '9') 77 { 78 precision = abtol (&p, 10); 79 c = *p; 80 } 81 else if (c == '*') 82 { 83 precision = va_arg (ap, long); 84 c = *++p; 85 } 86 } 87 if (c == 'l') 88 c = *++p; 89 if (c == 'l') 90 c = *++p; 91 if (c == 'l') 92 { 93 eputs ("vsnprintf: skipping second: l\n"); 94 c = *++p; 95 } 96 switch (c) 97 { 98 case '%': 99 { 100 if (count < size) 101 *str++ = *p; 102 count++; 103 break; 104 } 105 case 'c': 106 { 107 c = va_arg (ap, long); 108 if (count < size) 109 *str++ = c; 110 count++; 111 break; 112 } 113 case 'd': 114 case 'i': 115 case 'o': 116 case 'u': 117 case 'x': 118 case 'X': 119 { 120 long d = va_arg (ap, long); 121 int base = c == 'o' ? 8 : c == 'x' || c == 'X' ? 16 : 10; 122 char *s = ntoab (d, base, c != 'u' && c != 'x' && c != 'X'); 123 if (c == 'X') 124 strupr (s); 125 int length = strlen (s); 126 if (precision == -1) 127 precision = length; 128 if (!left_p) 129 { 130 while (width-- > precision) 131 { 132 if (count < size) 133 *str++ = pad; 134 count++; 135 } 136 while (precision > length) 137 { 138 if (count < size) 139 *str++ = '0'; 140 precision--; 141 width--; 142 count++; 143 } 144 } 145 while (*s) 146 { 147 if (precision-- <= 0) 148 break; 149 width--; 150 c = *s++; 151 if (count < size) 152 *str++ = c; 153 count++; 154 } 155 while (width > 0) 156 { 157 width--; 158 if (count < size) 159 *str++ = pad; 160 count++; 161 } 162 break; 163 } 164 case 's': 165 { 166 char *s = va_arg (ap, char *); 167 int length = s ? strlen (s) : 0; 168 if (precision == -1) 169 precision = length; 170 if (!left_p) 171 { 172 while (width-- > precision) 173 { 174 if (count < size) 175 *str++ = pad; 176 count++; 177 } 178 while (width > length) 179 { 180 if (count < size) 181 *str++ = ' '; 182 precision--; 183 width--; 184 count++; 185 } 186 } 187 while (s && *s) 188 { 189 if (precision-- <= 0) 190 break; 191 width--; 192 c = *s++; 193 if (count < size) 194 *str++ = c; 195 count++; 196 } 197 while (width > 0) 198 { 199 width--; 200 if (count < size) 201 *str++ = pad; 202 count++; 203 } 204 break; 205 } 206 case 'f': 207 case 'e': 208 case 'E': 209 case 'g': 210 case 'G': 211 { 212 double d = va_arg8 (ap, double); 213 char *s = dtoab (d, 10, 1); 214 if (c == 'E' || c == 'G') 215 strupr (s); 216 int length = strlen (s); 217 if (precision == -1) 218 precision = length; 219 if (!left_p) 220 { 221 while (width-- > precision) 222 { 223 if (count < size) 224 *str++ = pad; 225 count++; 226 } 227 while (precision > length) 228 { 229 if (count < size) 230 *str++ = ' '; 231 precision--; 232 width--; 233 count++; 234 } 235 } 236 while (*s) 237 { 238 if (precision-- <= 0) 239 break; 240 width--; 241 c = *s++; 242 if (count < size) 243 *str++ = c; 244 count++; 245 } 246 while (width > 0) 247 { 248 width--; 249 if (count < size) 250 *str++ = pad; 251 count++; 252 } 253 break; 254 } 255 case 'n': 256 { 257 int *n = va_arg (ap, int *); 258 *n = count; 259 break; 260 } 261 default: 262 { 263 eputs ("vsnprintf: not supported: %:"); 264 eputc (c); 265 eputs ("\n"); 266 p++; 267 } 268 } 269 p++; 270 } 271 va_end (ap); 272 if (count < size) 273 *str = 0; 274 return count; 275 }