A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

Implement a much more capable vuprintf()

New support as well as some buggy support fixed.

Still no floating point support if ever that would be desired.

Support (*):
* Flags: '-', '+', ' ', '#', '0'

* Width and precision: 'n', '.n', '*' and '.*'

* Length modifiers: 'hh', 'h', 'j', 'l', 'll', 't', 'z'

* Radix: 'c', 'd', 'i', 'n', 'o', 'p/P', 's', 'u', 'x/X'

(*) Provision exists to switch lesser-used stuff on or off or when
certain functionality isn't desired (bootloader?). The compulsory
radixes are everything but 'o', 'n', 'p/P' and 'x/X' with length
modifiers being optional. The default setup is 'l', 'z', 'c', 'd',
'p/P', 's', 'u', 'x/X'.

* Move fdprintf() to its own file. It was in a strange place.

* Make callers compatible and fix a couple snprintf() bugs while
at it.

Could smush it down in size but I'm gonna get over the binsize
neurosis and just the let optimizer do its thing.

Change-Id: Ibdc613a9b6775802c188b29b9dd46c568c94f7c3

+1149 -357
+2 -1
firmware/SOURCES
··· 204 204 common/dircache.c 205 205 #endif /* HAVE_DIRCACHE */ 206 206 common/pathfuncs.c 207 - common/format.c 207 + common/fdprintf.c 208 208 common/linked_list.c 209 209 common/strcasecmp.c 210 210 common/strcasestr.c ··· 214 214 common/structec.c 215 215 common/timefuncs.c 216 216 common/unicode.c 217 + common/vuprintf.c 217 218 218 219 /* Display */ 219 220 scroll_engine.c
+56
firmware/common/fdprintf.c
··· 1 + /*************************************************************************** 2 + * __________ __ ___. 3 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + * \/ \/ \/ \/ \/ 8 + * $Id$ 9 + * 10 + * Copyright (C) 2002 by Felix Arends 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License 14 + * as published by the Free Software Foundation; either version 2 15 + * of the License, or (at your option) any later version. 16 + * 17 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 + * KIND, either express or implied. 19 + * 20 + ****************************************************************************/ 21 + #include <limits.h> 22 + #include "file.h" 23 + #include "vuprintf.h" 24 + 25 + struct for_fprintf { 26 + int fd; /* where to store it */ 27 + int rem; /* amount remaining */ 28 + }; 29 + 30 + static int fprfunc(void *pr, int letter) 31 + { 32 + struct for_fprintf *fpr = (struct for_fprintf *)pr; 33 + 34 + /* TODO: add a small buffer to reduce write() calls */ 35 + if (write(fpr->fd, &(char){ letter }, 1) > 0) { 36 + return --fpr->rem; 37 + } 38 + 39 + return -1; 40 + } 41 + 42 + int fdprintf(int fd, const char *fmt, ...) 43 + { 44 + int bytes; 45 + struct for_fprintf fpr; 46 + va_list ap; 47 + 48 + fpr.fd = fd; 49 + fpr.rem = INT_MAX; 50 + 51 + va_start(ap, fmt); 52 + bytes = vuprintf(fprfunc, &fpr, fmt, ap); 53 + va_end(ap); 54 + 55 + return bytes; 56 + }
-267
firmware/common/format.c
··· 1 - /*************************************************************************** 2 - * __________ __ ___. 3 - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 - * \/ \/ \/ \/ \/ 8 - * $Id$ 9 - * 10 - * Copyright (C) 2002 by Gary Czvitkovicz 11 - * 12 - * This program is free software; you can redistribute it and/or 13 - * modify it under the terms of the GNU General Public License 14 - * as published by the Free Software Foundation; either version 2 15 - * of the License, or (at your option) any later version. 16 - * 17 - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 - * KIND, either express or implied. 19 - * 20 - ****************************************************************************/ 21 - 22 - 23 - #include <stdarg.h> 24 - #include <stdbool.h> 25 - #include <limits.h> 26 - #include <string.h> 27 - #include "file.h" 28 - #include "format.h" 29 - 30 - static const char hexdigit[] = "0123456789ABCDEF"; 31 - 32 - void format( 33 - /* call 'push()' for each output letter */ 34 - int (*push)(void *userp, unsigned char data), 35 - void *userp, 36 - const char *fmt, 37 - va_list ap) 38 - { 39 - char *str; 40 - char tmpbuf[12], pad; 41 - int ch, width, val, sign, precision; 42 - long lval, lsign; 43 - unsigned int uval; 44 - unsigned long ulval; 45 - size_t uszval; 46 - ssize_t szval, szsign; 47 - bool ok = true; 48 - 49 - tmpbuf[sizeof tmpbuf - 1] = '\0'; 50 - 51 - while ((ch = *fmt++) != '\0' && ok) 52 - { 53 - if (ch == '%') 54 - { 55 - ch = *fmt++; 56 - pad = ' '; 57 - if (ch == '0') 58 - pad = '0'; 59 - 60 - width = 0; 61 - while (ch >= '0' && ch <= '9') 62 - { 63 - width = 10*width + ch - '0'; 64 - ch = *fmt++; 65 - } 66 - 67 - precision = 0; 68 - if(ch == '.') 69 - { 70 - ch = *fmt++; 71 - while (ch >= '0' && ch <= '9') 72 - { 73 - precision = 10*precision + ch - '0'; 74 - ch = *fmt++; 75 - } 76 - } else { 77 - precision = INT_MAX; 78 - } 79 - 80 - str = tmpbuf + sizeof tmpbuf - 1; 81 - switch (ch) 82 - { 83 - case 'c': 84 - *--str = va_arg (ap, int); 85 - break; 86 - 87 - case 's': 88 - str = va_arg (ap, char*); 89 - break; 90 - 91 - case 'd': 92 - val = sign = va_arg (ap, int); 93 - if (val < 0) 94 - val = -val; 95 - do 96 - { 97 - *--str = (val % 10) + '0'; 98 - val /= 10; 99 - } 100 - while (val > 0); 101 - if (sign < 0) 102 - *--str = '-'; 103 - break; 104 - 105 - case 'u': 106 - uval = va_arg(ap, unsigned int); 107 - do 108 - { 109 - *--str = (uval % 10) + '0'; 110 - uval /= 10; 111 - } 112 - while (uval > 0); 113 - break; 114 - case 'p': 115 - case 'P': 116 - /* for pointers prepend 0x and act like 'X' */ 117 - push(userp, '0'); 118 - push(userp, 'x'); 119 - /* fall through */ 120 - case 'x': 121 - case 'X': 122 - pad='0'; 123 - uval = va_arg (ap, int); 124 - do 125 - { 126 - *--str = hexdigit[uval & 0xf]; 127 - uval >>= 4; 128 - } 129 - while (uval); 130 - break; 131 - 132 - case 'l': 133 - ch = *fmt++; 134 - switch(ch) { 135 - case 'x': 136 - case 'X': 137 - pad='0'; 138 - ulval = va_arg (ap, long); 139 - do 140 - { 141 - *--str = hexdigit[ulval & 0xf]; 142 - ulval >>= 4; 143 - } 144 - while (ulval); 145 - break; 146 - case 'd': 147 - lval = lsign = va_arg (ap, long); 148 - if (lval < 0) 149 - lval = -lval; 150 - do 151 - { 152 - *--str = (lval % 10) + '0'; 153 - lval /= 10; 154 - } 155 - while (lval > 0); 156 - if (lsign < 0) 157 - *--str = '-'; 158 - break; 159 - 160 - case 'u': 161 - ulval = va_arg(ap, unsigned long); 162 - do 163 - { 164 - *--str = (ulval % 10) + '0'; 165 - ulval /= 10; 166 - } 167 - while (ulval > 0); 168 - break; 169 - 170 - default: 171 - *--str = 'l'; 172 - *--str = ch; 173 - } 174 - 175 - break; 176 - 177 - case 'z': 178 - ch = *fmt++; 179 - switch(ch) { 180 - case 'd': 181 - szval = szsign = va_arg (ap, ssize_t); 182 - if (szval < 0) 183 - szval = -szval; 184 - do 185 - { 186 - *--str = (szval % 10) + '0'; 187 - szval /= 10; 188 - } 189 - while (szval > 0); 190 - if (szsign < 0) 191 - *--str = '-'; 192 - break; 193 - 194 - case 'u': 195 - uszval = va_arg(ap, size_t); 196 - do 197 - { 198 - *--str = (uszval % 10) + '0'; 199 - uszval /= 10; 200 - } 201 - while (uszval > 0); 202 - break; 203 - 204 - default: 205 - *--str = 'z'; 206 - *--str = ch; 207 - } 208 - 209 - break; 210 - 211 - default: 212 - *--str = ch; 213 - break; 214 - } 215 - 216 - if (width > 0) 217 - { 218 - width -= strlen (str); 219 - while (width-- > 0 && ok) 220 - ok=push(userp, pad); 221 - } 222 - while (*str != '\0' && ok && precision--) 223 - ok=push(userp, *str++); 224 - } 225 - else 226 - ok=push(userp, ch); 227 - } 228 - } 229 - 230 - struct for_fprintf { 231 - int fd; /* where to store it */ 232 - int bytes; /* amount stored */ 233 - }; 234 - 235 - static int fprfunc(void *pr, unsigned char letter) 236 - { 237 - struct for_fprintf *fpr = (struct for_fprintf *)pr; 238 - int rc = write(fpr->fd, &letter, 1); 239 - 240 - if(rc > 0) { 241 - fpr->bytes++; /* count them */ 242 - return true; /* we are ok */ 243 - } 244 - 245 - return false; /* failure */ 246 - } 247 - 248 - 249 - int fdprintf(int fd, const char *fmt, ...) 250 - { 251 - va_list ap; 252 - struct for_fprintf fpr; 253 - 254 - fpr.fd=fd; 255 - fpr.bytes=0; 256 - 257 - va_start(ap, fmt); 258 - format(fprfunc, &fpr, fmt, ap); 259 - va_end(ap); 260 - 261 - return fpr.bytes; /* return 0 on error */ 262 - } 263 - 264 - void vuprintf(int (*push)(void *userp, unsigned char data), void *userp, const char *fmt, va_list ap) 265 - { 266 - format(push, userp, fmt, ap); 267 - }
+974
firmware/common/vuprintf.c
··· 1 + /*************************************************************************** 2 + * __________ __ ___. 3 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + * \/ \/ \/ \/ \/ 8 + * $Id$ 9 + * 10 + * Copyright (C) 2002 by Gary Czvitkovicz 11 + * Copyright (C) 2017 by Michael A. Sevakis 12 + * 13 + * This program is free software; you can redistribute it and/or 14 + * modify it under the terms of the GNU General Public License 15 + * as published by the Free Software Foundation; either version 2 16 + * of the License, or (at your option) any later version. 17 + * 18 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 + * KIND, either express or implied. 20 + * 21 + ****************************************************************************/ 22 + #include <sys/types.h> 23 + #include <limits.h> 24 + #include <string.h> 25 + #include "system.h" 26 + #include "vuprintf.h" 27 + 28 + #if 0 29 + /* turn everything on */ 30 + #define FMT_LENMOD (0xffffffff) 31 + #define FMT_RADIX (0xffffffff) 32 + #endif 33 + 34 + /* these are the defaults if no other preference is given */ 35 + #ifndef FMT_LENMOD 36 + #define FMT_LENMOD (FMT_LENMOD_l | \ 37 + FMT_LENMOD_z) 38 + #endif /* FMT_LENMOD */ 39 + 40 + #ifndef FMT_RADIX 41 + #define FMT_RADIX (FMT_RADIX_c | \ 42 + FMT_RADIX_d | \ 43 + FMT_RADIX_p | \ 44 + FMT_RADIX_s | \ 45 + FMT_RADIX_u | \ 46 + FMT_RADIX_x) 47 + #endif /* FMT_RADIX */ 48 + 49 + /** Length modifier and radix flags **/ 50 + 51 + /* compulsory length modifiers: NONE 52 + * however a compatible 'l' or 'll' must be defined if another requires it */ 53 + #define FMT_LENMOD_h 0x001 /* signed/unsigned short (%h<radix>) */ 54 + #define FMT_LENMOD_hh 0x002 /* signed/unsigned char (%hh<radix>) */ 55 + #define FMT_LENMOD_j 0x004 /* intmax_t/uintmax_t (%j<radix>) */ 56 + #define FMT_LENMOD_l 0x008 /* signed/unsigned long (%l<radix>) */ 57 + #define FMT_LENMOD_ll 0x010 /* signed/unsigned long long (%ll<radix>) */ 58 + #define FMT_LENMOD_t 0x020 /* signed/unsigned ptrdiff_t (%t<radix>) */ 59 + #define FMT_LENMOD_z 0x040 /* size_t/ssize_t (%z<radix>) */ 60 + #define FMT_LENMOD_L 0x080 /* long double (instead of double) */ 61 + 62 + /* compulsory radixes: c, d, i, u, s */ 63 + #define FMT_RADIX_c 0x001 /* single character (%c) */ 64 + #define FMT_RADIX_d 0x002 /* signed integer type, decimal (%d %i) */ 65 + #define FMT_RADIX_n 0x004 /* bytes output so far (%n) */ 66 + #define FMT_RADIX_o 0x008 /* unsigned integer type, octal (%o) */ 67 + #define FMT_RADIX_p 0x010 /* pointer (%p %P) */ 68 + #define FMT_RADIX_s 0x020 /* string (%s) */ 69 + #define FMT_RADIX_u 0x040 /* unsigned integer type, decimal (%u) */ 70 + #define FMT_RADIX_x 0x080 /* unsigned integer type, hex (%x %X) */ 71 + #define FMT_RADIX_a 0x100 /* hex floating point "[-]0xh.hhhhp�d" */ 72 + #define FMT_RADIX_e 0x200 /* floating point with exponent "[-]d.ddde�dd" */ 73 + #define FMT_RADIX_f 0x400 /* floating point "[-]ddd.ddd" */ 74 + #define FMT_RADIX_g 0x800 /* floating point exponent or decimal depending 75 + upon value and precision */ 76 + 77 + /* avoid defining redundant functions if two or more types can use the same 78 + * something not getting a macro means it gets assigned its own value and 79 + * formatter */ 80 + 81 + /* l */ 82 + #if LONG_MIN == INT_MIN && LONG_MAX == INT_MAX 83 + #define val_ld val_d 84 + #define format_ld format_d 85 + #define branch_fmt_ld branch_fmt_d 86 + #elif !(FMT_LENMOD & FMT_LENMOD_l) /* unique */ 87 + #define val_ld 88 + #endif /* LONG_ */ 89 + 90 + #if ULONG_MAX == UINT_MAX 91 + #define val_lu val_u 92 + #define format_lu format_u 93 + #define branch_fmt_lu branch_fmt_u 94 + #elif !(FMT_LENMOD & FMT_LENMOD_l) /* unique */ 95 + #define val_lu 96 + #endif /* ULONG_ */ 97 + 98 + /* ll */ 99 + #if LLONG_MIN == INT_MIN && LLONG_MAX == INT_MAX 100 + #define val_lld val_d 101 + #define format_lld format_d 102 + #define branch_fmt_lld branch_fmt_d 103 + #elif LLONG_MIN == LONG_MIN && LLONG_MAX == LONG_MAX 104 + #define val_lld val_ld 105 + #define format_lld format_ld 106 + #define branch_fmt_lld branch_fmt_ld 107 + #elif !(FMT_LENMOD & FMT_LENMOD_ll) /* unique */ 108 + #define val_lld 109 + #endif /* LLONG_ */ 110 + 111 + #if ULLONG_MAX == UINT_MAX 112 + #define val_llu val_u 113 + #define format_llu format_u 114 + #define branch_fmt_llu branch_fmt_u 115 + #elif ULLONG_MAX == ULONG_MAX 116 + #define val_llu val_lu 117 + #define format_llu format_lu 118 + #define branch_fmt_llu branch_fmt_lu 119 + #elif !(FMT_LENMOD & FMT_LENMOD_ll) /* unique */ 120 + #define val_llu 121 + #endif /* ULLONG_ */ 122 + 123 + /* char/short parameter type promotions */ 124 + #define SCHAR_INT_ARG int 125 + #define UCHAR_INT_ARG int 126 + #define SSHRT_INT_ARG int 127 + #if USHRT_MAX == UINT_MAX 128 + #define USHRT_INT_ARG unsigned int 129 + #else 130 + #define USHRT_INT_ARG int 131 + #endif 132 + 133 + /* some macros to have conditional work inside macros */ 134 + #if (FMT_LENMOD & FMT_LENMOD_l) 135 + #define IF_FMT_LENMOD_l(...) __VA_ARGS__ 136 + #else 137 + #define IF_FMT_LENMOD_l(...) 138 + #endif 139 + 140 + #if (FMT_LENMOD & FMT_LENMOD_ll) 141 + #define IF_FMT_LENMOD_ll(...) __VA_ARGS__ 142 + #else 143 + #define IF_FMT_LENMOD_ll(...) 144 + #endif 145 + 146 + #if (FMT_RADIX & FMT_RADIX_o) 147 + #define IF_FMT_RADIX_o(...) __VA_ARGS__ 148 + #else 149 + #define IF_FMT_RADIX_o(...) 150 + #endif 151 + 152 + #if (FMT_RADIX & FMT_RADIX_x) 153 + #define IF_FMT_RADIX_x(...) __VA_ARGS__ 154 + #else 155 + #define IF_FMT_RADIX_x(...) 156 + #endif 157 + 158 + /* synthesize multicharacter constant */ 159 + #define LENMOD2(cv, ch) \ 160 + (((cv) << CHAR_BIT) | (ch)) 161 + 162 + #define LENMOD_NONE 0 163 + 164 + #if (FMT_LENMOD & FMT_LENMOD_h) 165 + #define LENMOD_h 'h' 166 + #endif 167 + #if (FMT_LENMOD & FMT_LENMOD_hh) 168 + #define LENMOD_hh LENMOD2('h', 'h') /* 'hh' */ 169 + #endif 170 + #if (FMT_LENMOD & FMT_LENMOD_j) 171 + #define LENMOD_j 'j' 172 + #endif 173 + #if (FMT_LENMOD & FMT_LENMOD_l) 174 + #define LENMOD_l 'l' 175 + #endif 176 + #if (FMT_LENMOD & FMT_LENMOD_ll) 177 + #undef FMT_MAX_L 178 + #define LENMOD_ll LENMOD2('l', 'l') /* 'll' */ 179 + #endif 180 + #if (FMT_LENMOD & FMT_LENMOD_t) 181 + #define LENMOD_t 't' 182 + #endif 183 + #if (FMT_LENMOD & FMT_LENMOD_z) 184 + #define LENMOD_z 'z' 185 + #endif 186 + 187 + /* select type-compatible length modifier 188 + * (a bit hacky; it should be range-based) */ 189 + #define LENMOD_INTCOMPAT_SEL(type, signd) \ 190 + ({ int __lenmod; \ 191 + size_t __size = sizeof (type); \ 192 + if (__size == ((signd) ? sizeof (int) : \ 193 + sizeof (unsigned int))) { \ 194 + __lenmod = LENMOD_NONE; \ 195 + } \ 196 + else if (__size == ((signd) ? sizeof (long) : \ 197 + sizeof (unsigned long))) { \ 198 + IF_FMT_LENMOD_l(__lenmod = LENMOD_l;) \ 199 + } \ 200 + else if (__size == ((signd) ? sizeof (long long) : \ 201 + sizeof (unsigned long long))) { \ 202 + IF_FMT_LENMOD_ll(__lenmod = LENMOD_ll;) \ 203 + } \ 204 + __lenmod; }) 205 + 206 + /* call formatting function for the compatible integer type */ 207 + #define LENMOD_INTCOMPAT_CALL(inteqv, val, fmt_buf, x, signd) \ 208 + ({ const char *__buf; \ 209 + switch (inteqv) { \ 210 + case LENMOD_NONE: \ 211 + __buf = (signd) ? \ 212 + format_d((val), (fmt_buf), (x)) : \ 213 + format_u((val), (fmt_buf), (x)); \ 214 + break; \ 215 + IF_FMT_LENMOD_l( \ 216 + case LENMOD_l: \ 217 + __buf = (signd) ? \ 218 + format_ld((val), (fmt_buf), (x)) : \ 219 + format_lu((val), (fmt_buf), (x)); \ 220 + break; \ 221 + ) \ 222 + IF_FMT_LENMOD_ll( \ 223 + case LENMOD_ll: \ 224 + __buf = (signd) ? \ 225 + format_lld((val), (fmt_buf), (x)) : \ 226 + format_llu((val), (fmt_buf), (x)); \ 227 + break; \ 228 + ) \ 229 + } \ 230 + __buf; \ 231 + }) 232 + 233 + /* execute formatting branch for the compatible integer type */ 234 + #define LENMOD_INTCOMPAT_BRANCH(inteqv, val, signd) \ 235 + ({ switch (inteqv) { \ 236 + case LENMOD_NONE: \ 237 + if (signd) { \ 238 + val_d = (val); \ 239 + goto branch_fmt_d; \ 240 + } \ 241 + else { \ 242 + val_u = (val); \ 243 + goto branch_fmt_u; \ 244 + } \ 245 + IF_FMT_LENMOD_l( \ 246 + case LENMOD_l: \ 247 + if (signd) { \ 248 + val_ld = (val); \ 249 + goto branch_fmt_ld; \ 250 + } \ 251 + else { \ 252 + val_lu = (val); \ 253 + goto branch_fmt_lu; \ 254 + } \ 255 + ) \ 256 + IF_FMT_LENMOD_ll( \ 257 + case LENMOD_ll: \ 258 + if (signd) { \ 259 + val_lld = (val); \ 260 + goto branch_fmt_lld; \ 261 + } \ 262 + else { \ 263 + val_llu = (val); \ 264 + goto branch_fmt_llu; \ 265 + } \ 266 + ) \ 267 + } \ 268 + }) 269 + 270 + #define CONVERT_RADIX_10_SIGN(val, fmt_buf, p, signchar, type) \ 271 + do { \ 272 + if (val) { \ 273 + unsigned type v; \ 274 + \ 275 + if (val < 0) { \ 276 + v = (typeof (v))-(val + 1) + 1; \ 277 + signchar = '-'; \ 278 + } \ 279 + else { \ 280 + v = val; \ 281 + } \ 282 + \ 283 + do { \ 284 + *--p = (v % 10) + '0'; \ 285 + v /= 10; \ 286 + } while (v); \ 287 + } \ 288 + \ 289 + if (signchar) { \ 290 + p[-1] = signchar; \ 291 + fmt_buf->length = 1; \ 292 + break; \ 293 + } \ 294 + \ 295 + fmt_buf->length = 0; \ 296 + } while (0) 297 + 298 + #define CONVERT_RADIX_8(val, fmt_buf, p) \ 299 + do { \ 300 + if (val) { \ 301 + typeof (val) v = val; \ 302 + \ 303 + do { \ 304 + *--p = (v % 010) + '0'; \ 305 + v /= 010; \ 306 + } while (v); \ 307 + } \ 308 + \ 309 + if (fmt_buf->length) { \ 310 + *--p = '0'; \ 311 + fmt_buf->length = 0; \ 312 + } \ 313 + } while (0) 314 + 315 + #define CONVERT_RADIX_10(val, fmt_buf, p) \ 316 + do { \ 317 + if (val) { \ 318 + typeof (val) v = val; \ 319 + \ 320 + do { \ 321 + *--p = (v % 10) + '0'; \ 322 + v /= 10; \ 323 + } while (v); \ 324 + } \ 325 + \ 326 + fmt_buf->length = 0; \ 327 + } while (0) 328 + 329 + #define CONVERT_RADIX_16(val, fmt_buf, p, x) \ 330 + do { \ 331 + if (val) { \ 332 + const int h = x - 'X' - 0xA \ 333 + + 'A' - '0'; \ 334 + typeof (val) v = val; \ 335 + \ 336 + do { \ 337 + unsigned int d = v % 0x10; \ 338 + if (d >= 0xA) { \ 339 + d += h; \ 340 + } \ 341 + *--p = d + '0'; \ 342 + v /= 0x10; \ 343 + } while (v); \ 344 + \ 345 + if (fmt_buf->length) { \ 346 + p[-1] = x; \ 347 + p[-2] = '0'; \ 348 + fmt_buf->length = 2; \ 349 + break; \ 350 + } \ 351 + } \ 352 + \ 353 + fmt_buf->length = 0; \ 354 + } while (0) 355 + 356 + #define CONVERT_RADIX_NOSIGN(val, fmt_buf, p, x) \ 357 + switch (x) \ 358 + { \ 359 + IF_FMT_RADIX_o( case 'o': \ 360 + CONVERT_RADIX_8(val, fmt_buf, p); \ 361 + break; ) \ 362 + case 'u': \ 363 + CONVERT_RADIX_10(val, fmt_buf, p); \ 364 + break; \ 365 + IF_FMT_RADIX_x( default: \ 366 + CONVERT_RADIX_16(val, fmt_buf, p, x); \ 367 + break; ) \ 368 + } 369 + 370 + struct fmt_buf { 371 + const char *fmt_start; /* second character of formatter after '%' */ 372 + size_t length; /* length of formatted text (non-numeric) 373 + or prefix (numeric) */ 374 + char buf[24]; /* work buffer */ 375 + char bufend[1]; /* buffer end marker and guard '0' */ 376 + }; 377 + 378 + /* %d %i */ 379 + static inline const char * format_d(int val, 380 + struct fmt_buf *fmt_buf, 381 + int signchar) 382 + { 383 + char *p = fmt_buf->bufend; 384 + CONVERT_RADIX_10_SIGN(val, fmt_buf, p, signchar, int); 385 + return p; 386 + } 387 + 388 + /* %o %u %x %X */ 389 + static inline const char * format_u(unsigned int val, 390 + struct fmt_buf *fmt_buf, 391 + int radixchar) 392 + { 393 + char *p = fmt_buf->bufend; 394 + CONVERT_RADIX_NOSIGN(val, fmt_buf, p, radixchar); 395 + return p; 396 + } 397 + 398 + #if (FMT_LENMOD & FMT_LENMOD_l) 399 + #ifndef format_ld 400 + /* %ld %li */ 401 + static inline const char * format_ld(long val, 402 + struct fmt_buf *fmt_buf, 403 + int signchar) 404 + { 405 + char *p = fmt_buf->bufend; 406 + CONVERT_RADIX_10_SIGN(val, fmt_buf, p, signchar, long); 407 + return p; 408 + } 409 + #endif /* format_ld */ 410 + 411 + #ifndef format_lu 412 + /* %lo %lu %lx %lX */ 413 + static inline const char * format_lu(unsigned long val, 414 + struct fmt_buf *fmt_buf, 415 + int radixchar) 416 + { 417 + char *p = fmt_buf->bufend; 418 + CONVERT_RADIX_NOSIGN(val, fmt_buf, p, radixchar); 419 + return p; 420 + } 421 + #endif /* format_lu */ 422 + #endif /* FMT_LENMOD_l */ 423 + 424 + #if (FMT_LENMOD & FMT_LENMOD_ll) 425 + #ifndef format_lld 426 + /* %lld %lli */ 427 + static inline const char * format_lld(long long val, 428 + struct fmt_buf *fmt_buf, 429 + int signchar) 430 + { 431 + char *p = fmt_buf->bufend; 432 + CONVERT_RADIX_10_SIGN(val, fmt_buf, p, signchar, long long); 433 + return p; 434 + } 435 + #endif /* format_lld */ 436 + 437 + #ifndef format_llu 438 + /* %llo %llu %llx %llX */ 439 + static inline const char * format_llu(unsigned long long val, 440 + struct fmt_buf *fmt_buf, 441 + int radixchar) 442 + { 443 + char *p = fmt_buf->bufend; 444 + CONVERT_RADIX_NOSIGN(val, fmt_buf, p, radixchar); 445 + return p; 446 + } 447 + #endif /* format_llu */ 448 + #endif /* FMT_LENMOD_ll */ 449 + 450 + /* %c */ 451 + static inline const char * format_c(int c, 452 + struct fmt_buf *fmt_buf, 453 + int lenmod) 454 + { 455 + if (lenmod != LENMOD_NONE) { 456 + return NULL; /* wchar_t support for now */ 457 + } 458 + 459 + char *p = fmt_buf->bufend; 460 + fmt_buf->length = 1; 461 + *--p = (unsigned char)c; 462 + return p; 463 + } 464 + 465 + /* %s */ 466 + static inline const char * format_s(const void *str, 467 + struct fmt_buf *fmt_buf, 468 + int precision, 469 + int lenmod) 470 + { 471 + if (lenmod != LENMOD_NONE) { 472 + return NULL; /* wchar_t support for now */ 473 + } 474 + 475 + /* string length may be specified by precision instead of \0- 476 + terminated; however, don't go past a \0 if one is there */ 477 + const char *s = str; 478 + size_t len = precision >= 0 ? precision : -1; 479 + 480 + const char *nil = memchr(s, '\0', len); 481 + if (nil) { 482 + len = nil - s; 483 + } 484 + 485 + fmt_buf->length = len; 486 + return s; 487 + } 488 + 489 + #if (FMT_RADIX & FMT_RADIX_n) 490 + /* %n */ 491 + static inline bool format_n(void *np, 492 + int count, 493 + int lenmod) 494 + { 495 + if (lenmod != LENMOD_NONE) { 496 + return false; /* int only for now */ 497 + } 498 + 499 + *(int *)np = count; 500 + return true; 501 + } 502 + #endif /* FMT_RADIX_n */ 503 + 504 + #if (FMT_RADIX & FMT_RADIX_p) 505 + /* %p %P */ 506 + static inline const char * format_p(const void *p, 507 + struct fmt_buf *fmt_buf, 508 + int radixchar, 509 + bool *numericp) 510 + { 511 + if (p) { 512 + /* format as %#x or %#X */ 513 + *numericp = true; 514 + radixchar -= 'P' - 'X'; 515 + fmt_buf->length = 2; 516 + return LENMOD_INTCOMPAT_CALL(LENMOD_INTCOMPAT_SEL(uintptr_t, false), 517 + (uintptr_t)p, fmt_buf, radixchar, false); 518 + } 519 + else { 520 + /* format as %s */ 521 + fmt_buf->length = 5; 522 + return "(nil)"; 523 + } 524 + } 525 + #endif /* FMT_RADIX_p */ 526 + 527 + /* parse fixed width or precision field */ 528 + static const char * parse_number_spec(const char *fmt, 529 + int ch, 530 + int *out) 531 + { 532 + int i = ch - '0'; 533 + 534 + while (1) { 535 + ch = *fmt - '0'; 536 + 537 + if (ch < 0 || ch > 9 || i > INT_MAX / 10 || 538 + (i == INT_MAX / 10 && ch > INT_MAX % 10)) { 539 + break; 540 + } 541 + 542 + i = i * 10 + ch; 543 + fmt++; 544 + } 545 + 546 + *out = i; 547 + return fmt; 548 + } 549 + 550 + int vuprintf(vuprintf_push_cb push, /* call 'push()' for each output letter */ 551 + void *userp, 552 + const char *fmt, 553 + va_list ap) 554 + { 555 + #define PUSHCHAR(ch) \ 556 + do { \ 557 + int __ch = (ch); \ 558 + int __rc = push(userp, __ch); \ 559 + count += __rc >= 0; \ 560 + if (__rc <= 0) { \ 561 + goto done; \ 562 + } \ 563 + } while (0) 564 + 565 + int count = 0; 566 + int ch; 567 + 568 + /* macrofied identifiers share a variable with another */ 569 + unsigned int val_d; 570 + unsigned int val_u; 571 + #ifndef val_ld 572 + unsigned long val_ld; 573 + #endif 574 + #ifndef val_lu 575 + unsigned long val_lu; 576 + #endif 577 + #ifndef val_lld 578 + unsigned long long val_lld; 579 + #endif 580 + #ifndef val_llu 581 + unsigned long long val_llu; 582 + #endif 583 + 584 + struct fmt_buf fmt_buf; 585 + fmt_buf.bufend[0] = '0'; 586 + 587 + while (1) { 588 + while (1) { 589 + if ((ch = *fmt++) == '\0') { 590 + goto done; 591 + } 592 + 593 + if (ch == '%' && (ch = *fmt++) != '%') { 594 + break; 595 + } 596 + 597 + PUSHCHAR(ch); 598 + } 599 + 600 + /* set to defaults */ 601 + fmt_buf.fmt_start = fmt; 602 + 603 + int signchar = 0; 604 + unsigned int width = 0; 605 + int lenmod = LENMOD_NONE; 606 + size_t length = 0; 607 + size_t pfxlen = 0; 608 + bool numeric = false; 609 + int alignchar = '0' + 1; 610 + int precision = -1; 611 + const char *buf = NULL; 612 + 613 + /*** flags ***/ 614 + while (1) { 615 + switch (ch) 616 + { 617 + case ' ': /* <space> before non-negative value (signed conversion) */ 618 + case '+': /* '+' before non-negative value (signed conversion) */ 619 + /* '+' overrides ' ' */ 620 + if (ch > signchar) { 621 + signchar = ch; 622 + } 623 + break; 624 + case '-': /* left-justify in field */ 625 + case '0': /* zero-pad to fill field */ 626 + /* '-' overrides '0' */ 627 + if (ch < alignchar) { 628 + alignchar = ch; 629 + } 630 + break; 631 + case '#': /* number prefix (nonzero %o:'0' %x/%X:'0x') */ 632 + /* indicate; formatter updates with actual length */ 633 + pfxlen = 1; 634 + break; 635 + #if 0 636 + case '\'': /* digit grouping (non-monetary) */ 637 + break; 638 + #endif 639 + default: 640 + goto flags_done; 641 + } 642 + 643 + ch = *fmt++; 644 + } 645 + flags_done: 646 + 647 + /*** width ***/ 648 + if (ch == '*') { 649 + /* variable width */ 650 + int w = va_arg(ap, int); 651 + if (w < 0) { 652 + /* negative width is width with implied '-' */ 653 + width = (unsigned int)-(w + 1) + 1; 654 + alignchar = '-'; 655 + } 656 + else { 657 + width = w; 658 + } 659 + 660 + ch = *fmt++; 661 + } 662 + else if (ch >= '1' && ch <= '9') { 663 + /* fixed width */ 664 + fmt = parse_number_spec(fmt, ch, &width); 665 + ch = *fmt++; 666 + } 667 + 668 + /*** precision ***/ 669 + if (ch == '.') { 670 + ch = *fmt++; 671 + 672 + if (ch == '*') { 673 + /* variable precision; negative precision is ignored */ 674 + precision = va_arg (ap, int); 675 + ch = *fmt++; 676 + } 677 + else if (ch >= '0' && ch <= '9') { 678 + /* fixed precision */ 679 + fmt = parse_number_spec(fmt, ch, &precision); 680 + ch = *fmt++; 681 + } 682 + } 683 + 684 + /*** length modifier ***/ 685 + #if FMT_LENMOD 686 + switch (ch) 687 + { 688 + #if (FMT_LENMOD & (FMT_LENMOD_h | FMT_LENMOD_hh)) 689 + case 'h': 690 + #endif 691 + #if (FMT_LENMOD & FMT_LENMOD_j) 692 + case 'j': 693 + #endif 694 + #if (FMT_LENMOD & (FMT_LENMOD_l | FMT_LENMOD_ll)) 695 + case 'l': 696 + #endif 697 + #if (FMT_LENMOD & FMT_LENMOD_t) 698 + case 't': 699 + #endif 700 + #if (FMT_LENMOD & FMT_LENMOD_z) 701 + case 'z': 702 + #endif 703 + lenmod = ch; 704 + ch = *fmt++; 705 + #if (FMT_LENMOD & (FMT_LENMOD_hh | FMT_LENMOD_ll)) 706 + /* doesn't matter if jj, tt or zz happen; they will be rejected 707 + by the radix handler */ 708 + if (ch == lenmod) { 709 + lenmod = LENMOD2(lenmod, ch); 710 + ch = *fmt++; 711 + } 712 + #endif 713 + } 714 + #endif /* FMT_LENMOD */ 715 + 716 + /*** radix ***/ 717 + switch (ch) 718 + { 719 + /** non-numeric **/ 720 + case 'c': 721 + buf = format_c(va_arg(ap, int), &fmt_buf, lenmod); 722 + break; 723 + #if (FMT_RADIX & FMT_RADIX_n) 724 + case 'n': 725 + if (format_n(va_arg(ap, void *), count, lenmod)) { 726 + continue; /* no output */ 727 + } 728 + break; 729 + #endif 730 + case 's': 731 + buf = format_s(va_arg(ap, const void *), &fmt_buf, 732 + precision, lenmod); 733 + break; 734 + 735 + /** non-integer **/ 736 + #if (FMT_RADIX & FMT_RADIX_p) 737 + case 'p': 738 + case 'P': 739 + buf = format_p(va_arg(ap, void *), &fmt_buf, ch, 740 + &numeric); 741 + break; 742 + #endif 743 + 744 + /** signed integer **/ 745 + case 'd': 746 + case 'i': 747 + fmt_buf.length = pfxlen; 748 + 749 + switch (lenmod) 750 + { 751 + case LENMOD_NONE: 752 + val_d = va_arg(ap, signed int); 753 + goto branch_fmt_d; 754 + #if (FMT_LENMOD & FMT_LENMOD_h) 755 + case LENMOD_h: 756 + val_d = (signed short)va_arg(ap, SSHRT_INT_ARG); 757 + goto branch_fmt_d; 758 + #endif 759 + #if (FMT_LENMOD & FMT_LENMOD_hh) 760 + case LENMOD_hh: 761 + val_d = (signed char)va_arg(ap, SCHAR_INT_ARG); 762 + goto branch_fmt_d; 763 + #endif 764 + #if (FMT_LENMOD & FMT_LENMOD_j) 765 + case LENMOD_j: 766 + LENMOD_INTCOMPAT_BRANCH(LENMOD_INTCOMPAT_SEL(intmax_t, true), 767 + va_arg(ap, intmax_t), true); 768 + #endif 769 + #if (FMT_LENMOD & FMT_LENMOD_l) 770 + case LENMOD_l: 771 + val_ld = va_arg(ap, signed long); 772 + goto branch_fmt_ld; 773 + #endif 774 + #if (FMT_LENMOD & FMT_LENMOD_ll) 775 + case LENMOD_ll: 776 + val_lld = va_arg(ap, signed long long); 777 + goto branch_fmt_lld; 778 + #endif 779 + #if (FMT_LENMOD & FMT_LENMOD_t) 780 + case LENMOD_t: 781 + LENMOD_INTCOMPAT_BRANCH(LENMOD_INTCOMPAT_SEL(ptrdiff_t, true), 782 + va_arg(ap, ptrdiff_t), true); 783 + #endif 784 + #if (FMT_LENMOD & FMT_LENMOD_z) 785 + case LENMOD_z: 786 + LENMOD_INTCOMPAT_BRANCH(LENMOD_INTCOMPAT_SEL(ssize_t, true), 787 + va_arg(ap, ssize_t), true); 788 + #endif 789 + } 790 + 791 + /* macrofied labels share a formatter with another */ 792 + if (0) { 793 + branch_fmt_d: 794 + buf = format_d(val_d, &fmt_buf, signchar); 795 + } else if (0) { 796 + #ifndef val_ld 797 + branch_fmt_ld: 798 + buf = format_ld(val_ld, &fmt_buf, signchar); 799 + #endif 800 + } else if (0) { 801 + #ifndef val_lld 802 + branch_fmt_lld: 803 + buf = format_lld(val_lld, &fmt_buf, signchar); 804 + #endif 805 + } 806 + 807 + numeric = true; 808 + break; 809 + 810 + /** unsigned integer **/ 811 + #if (FMT_RADIX & FMT_RADIX_o) 812 + case 'o': 813 + #endif 814 + case 'u': 815 + #if (FMT_RADIX & FMT_RADIX_x) 816 + case 'x': 817 + case 'X': 818 + #endif 819 + fmt_buf.length = pfxlen; 820 + 821 + switch (lenmod) 822 + { 823 + case LENMOD_NONE: 824 + val_u = va_arg(ap, unsigned int); 825 + goto branch_fmt_u; 826 + #if (FMT_LENMOD & FMT_LENMOD_h) 827 + case LENMOD_h: 828 + val_u = (unsigned short)va_arg(ap, USHRT_INT_ARG); 829 + goto branch_fmt_u; 830 + #endif 831 + #if (FMT_LENMOD & FMT_LENMOD_hh) 832 + case LENMOD_hh: 833 + val_u = (unsigned char)va_arg(ap, UCHAR_INT_ARG); 834 + goto branch_fmt_u; 835 + #endif 836 + #if (FMT_LENMOD & FMT_LENMOD_j) 837 + case LENMOD_j: 838 + LENMOD_INTCOMPAT_BRANCH(LENMOD_INTCOMPAT_SEL(uintmax_t, false), 839 + va_arg(ap, uintmax_t), false); 840 + #endif 841 + #if (FMT_LENMOD & FMT_LENMOD_l) 842 + case LENMOD_l: 843 + val_lu = va_arg(ap, unsigned long); 844 + goto branch_fmt_lu; 845 + #endif 846 + #if (FMT_LENMOD & FMT_LENMOD_ll) 847 + case LENMOD_ll: 848 + val_llu = va_arg(ap, unsigned long long); 849 + goto branch_fmt_llu; 850 + #endif 851 + #if (FMT_LENMOD & (FMT_LENMOD_t | FMT_LENMOD_z)) 852 + /* format "uptrdiff_t" as size_t (unless it becomes standard) */ 853 + #if (FMT_LENMOD & FMT_LENMOD_t) 854 + case LENMOD_t: 855 + #endif 856 + #if (FMT_LENMOD & FMT_LENMOD_z) 857 + case LENMOD_z: 858 + #endif 859 + LENMOD_INTCOMPAT_BRANCH(LENMOD_INTCOMPAT_SEL(size_t, false), 860 + va_arg(ap, size_t), false); 861 + #endif 862 + } 863 + 864 + /* macrofied labels share a formatter with another */ 865 + if (0) { 866 + branch_fmt_u: 867 + buf = format_u(val_u, &fmt_buf, ch); 868 + } else if (0) { 869 + #ifndef val_lu 870 + branch_fmt_lu: 871 + buf = format_lu(val_lu, &fmt_buf, ch); 872 + #endif 873 + } else if (0) { 874 + #ifndef val_llu 875 + branch_fmt_llu: 876 + buf = format_llu(val_llu, &fmt_buf, ch); 877 + #endif 878 + } 879 + 880 + numeric = true; 881 + break; 882 + } 883 + 884 + if (buf) { 885 + /** padding **/ 886 + if (numeric) { 887 + /* numeric formats into fmt_buf.buf */ 888 + pfxlen = fmt_buf.length; 889 + length = fmt_buf.bufend - buf; 890 + 891 + size_t size = pfxlen + length; 892 + 893 + if (precision >= 0) { 894 + /* explicit precision */ 895 + precision -= (int)length; 896 + 897 + if (precision > 0) { 898 + size += precision; 899 + } 900 + 901 + width -= MIN(width, size); 902 + } 903 + else { 904 + /* default precision */ 905 + if (!length) { 906 + length = 1; 907 + size++; 908 + } 909 + 910 + width -= MIN(width, size); 911 + 912 + if (alignchar == '0') { 913 + /* width zero-fill */ 914 + precision = width; 915 + width = 0; 916 + } 917 + } 918 + } 919 + else { 920 + /* non-numeric: supress prefix and precision; keep length and 921 + width */ 922 + pfxlen = 0; 923 + precision = 0; 924 + length = fmt_buf.length; 925 + width -= MIN(width, length); 926 + } 927 + } 928 + else { 929 + /* format not accepted; print it literally */ 930 + buf = fmt_buf.fmt_start - 2; 931 + length = fmt - buf; 932 + width = 0; 933 + pfxlen = 0; 934 + precision = 0; 935 + } 936 + 937 + /** push all the stuff **/ 938 + 939 + if (alignchar != '-') { 940 + /* left padding */ 941 + while (width > 0) { 942 + PUSHCHAR(' '); 943 + width--; 944 + } 945 + } 946 + 947 + /* prefix */ 948 + while (pfxlen > 0) { 949 + PUSHCHAR(buf[-pfxlen]); 950 + pfxlen--; 951 + } 952 + 953 + /* 0-padding */ 954 + while (precision > 0) { 955 + PUSHCHAR('0'); 956 + precision--; 957 + } 958 + 959 + /* field */ 960 + while (length > 0) { 961 + PUSHCHAR(*buf++); 962 + length--; 963 + } 964 + 965 + /* right padding */ 966 + while (width > 0) { 967 + PUSHCHAR(' '); 968 + width--; 969 + } 970 + } 971 + 972 + done: 973 + return count; 974 + }
-37
firmware/include/format.h
··· 1 - /*************************************************************************** 2 - * __________ __ ___. 3 - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 - * \/ \/ \/ \/ \/ 8 - * $Id$ 9 - * 10 - * Copyright (C) 2002 by Felix Arends 11 - * 12 - * This program is free software; you can redistribute it and/or 13 - * modify it under the terms of the GNU General Public License 14 - * as published by the Free Software Foundation; either version 2 15 - * of the License, or (at your option) any later version. 16 - * 17 - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 - * KIND, either express or implied. 19 - * 20 - ****************************************************************************/ 21 - 22 - #ifndef __FORMAT_H__ 23 - #define __FORMAT_H__ 24 - 25 - void format( 26 - /* call 'push()' for each output letter */ 27 - int (*push)(void *userp, unsigned char data), 28 - void *userp, 29 - const char *fmt, 30 - va_list ap); 31 - 32 - /* callback function is called for every output character (byte) with userp and 33 - * should return 0 when ch is a char other than '\0' that should stop printing */ 34 - void vuprintf(int (*push)(void *userp, unsigned char data), 35 - void *userp, const char *fmt, va_list ap); 36 - 37 - #endif /* __FORMAT_H__ */
+45
firmware/include/vuprintf.h
··· 1 + /*************************************************************************** 2 + * __________ __ ___. 3 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + * \/ \/ \/ \/ \/ 8 + * $Id$ 9 + * 10 + * Copyright (C) 2002 by Felix Arends 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License 14 + * as published by the Free Software Foundation; either version 2 15 + * of the License, or (at your option) any later version. 16 + * 17 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 + * KIND, either express or implied. 19 + * 20 + ****************************************************************************/ 21 + 22 + #ifndef __VUPRINTF_H__ 23 + #define __VUPRINTF_H__ 24 + 25 + #include <stdarg.h> 26 + 27 + /* callback function is called for every output character (byte) in the 28 + * output with userp 29 + * 30 + * it must return > 0 to continue (increments counter) 31 + * it may return 0 to stop (increments counter) 32 + * it may return < 0 to stop (does not increment counter) 33 + * a zero in the format string stops (does not increment counter) 34 + * 35 + * caller is reponsible for stopping formatting in order to keep the return 36 + * value from overflowing (assuming they have a reason to care) 37 + */ 38 + typedef int (* vuprintf_push_cb)(void *userp, int c); 39 + 40 + /* 41 + * returns the number of times push() was called and returned >= 0 42 + */ 43 + int vuprintf(vuprintf_push_cb push, void *userp, const char *fmt, va_list ap); 44 + 45 + #endif /* __VUPRINTF_H__ */
+65 -45
firmware/libc/sprintf.c
··· 18 18 * KIND, either express or implied. 19 19 * 20 20 ****************************************************************************/ 21 - 22 - /* 23 - * Minimal printf and snprintf formatting functions 24 - * 25 - * These support %c %s %d and %x 26 - * Field width and zero-padding flag only 27 - */ 28 - 29 21 #include <stdio.h> 30 - #include <stdarg.h> 31 - #include <stdbool.h> 32 22 #include <limits.h> 33 - #include "format.h" 23 + #include <errno.h> 24 + #include "vuprintf.h" 34 25 35 26 /* ALSA library requires a more advanced snprintf, so let's not 36 27 override it in simulator for Linux. Note that Cygwin requires 37 28 our snprintf or it produces garbled output after a while. */ 38 29 39 30 struct for_snprintf { 40 - unsigned char *ptr; /* where to store it */ 41 - size_t bytes; /* amount already stored */ 42 - size_t max; /* max amount to store */ 31 + char *ptr; /* where to store it */ 32 + int rem; /* unwritten buffer remaining */ 43 33 }; 44 34 45 - static int sprfunc(void *ptr, unsigned char letter) 35 + static int sprfunc(void *ptr, int letter) 46 36 { 47 37 struct for_snprintf *pr = (struct for_snprintf *)ptr; 48 - if(pr->bytes < pr->max) { 49 - *pr->ptr = letter; 50 - pr->ptr++; 51 - pr->bytes++; 52 - return true; 38 + 39 + if (pr->rem > 0) { 40 + if (--pr->rem == 0) { 41 + return 0; 42 + } 43 + 44 + *pr->ptr++ = letter; 45 + return 1; 46 + } 47 + else { 48 + if (pr->rem == -INT_MAX) { 49 + pr->rem = 1; 50 + return -1; 51 + } 52 + 53 + --pr->rem; 54 + return 1; 53 55 } 54 - return false; /* filled buffer */ 55 56 } 56 57 57 - 58 - int snprintf(char *buf, size_t size, const char *fmt, ...) 58 + int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) 59 59 { 60 - va_list ap; 61 - struct for_snprintf pr; 60 + if (size <= INT_MAX) { 61 + int bytes; 62 + struct for_snprintf pr; 62 63 63 - pr.ptr = (unsigned char *)buf; 64 - pr.bytes = 0; 65 - pr.max = size; 64 + pr.ptr = buf; 65 + pr.rem = size; 66 66 67 - va_start(ap, fmt); 68 - format(sprfunc, &pr, fmt, ap); 69 - va_end(ap); 67 + bytes = vuprintf(sprfunc, &pr, fmt, ap); 70 68 71 - /* make sure it ends with a trailing zero */ 72 - pr.ptr[(pr.bytes < pr.max) ? 0 : -1] = '\0'; 73 - 74 - return pr.bytes; 69 + if (size) { 70 + *pr.ptr = '\0'; 71 + } 72 + else if (pr.rem > 0) { 73 + goto overflow; 74 + } 75 + 76 + return bytes; 77 + } 78 + 79 + overflow: 80 + errno = EOVERFLOW; 81 + return -1; 75 82 } 76 83 77 - int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) 84 + int snprintf(char *buf, size_t size, const char *fmt, ...) 78 85 { 79 - struct for_snprintf pr; 86 + if (size <= INT_MAX) { 87 + int bytes; 88 + struct for_snprintf pr; 89 + va_list ap; 90 + 91 + pr.ptr = buf; 92 + pr.rem = size; 80 93 81 - pr.ptr = (unsigned char *)buf; 82 - pr.bytes = 0; 83 - pr.max = size; 94 + va_start(ap, fmt); 95 + bytes = vuprintf(sprfunc, &pr, fmt, ap); 96 + va_end(ap); 97 + 98 + if (size) { 99 + *pr.ptr = '\0'; 100 + } 101 + else if (pr.rem > 0) { 102 + goto overflow; 103 + } 84 104 85 - format(sprfunc, &pr, fmt, ap); 105 + return bytes; 106 + } 86 107 87 - /* make sure it ends with a trailing zero */ 88 - pr.ptr[(pr.bytes < pr.max) ? 0 : -1] = '\0'; 89 - 90 - return pr.bytes; 108 + overflow: 109 + errno = EOVERFLOW; 110 + return -1; 91 111 }
+6 -6
firmware/logf.c
··· 38 38 #endif 39 39 #include "logf.h" 40 40 #include "serial.h" 41 - #include "format.h" 41 + #include "vuprintf.h" 42 42 43 43 #ifdef HAVE_USBSTACK 44 44 #include "usb_core.h" ··· 193 193 } 194 194 } 195 195 196 - static int logf_push(void *userp, unsigned char c) 196 + static int logf_push(void *userp, int c) 197 197 { 198 198 (void)userp; 199 199 ··· 210 210 } 211 211 #endif 212 212 213 - return true; 213 + return 1; 214 214 } 215 215 216 216 void _logf(const char *fmt, ...) ··· 310 310 #endif 311 311 312 312 #ifdef ROCKBOX_HAS_LOGDISKF 313 - static int logdiskf_push(void *userp, unsigned char c) 313 + static int logdiskf_push(void *userp, int c) 314 314 { 315 315 (void)userp; 316 316 ··· 319 319 { 320 320 strcpy(&logdiskfbuffer[logdiskfindex-8], "LOGFULL"); 321 321 logdiskfindex=MAX_LOGDISKF_SIZE; 322 - return false; 322 + return 0; 323 323 } 324 324 logdiskfbuffer[logdiskfindex++] = c; 325 325 326 - return true; 326 + return 1; 327 327 } 328 328 329 329 static void flush_buffer(void);
+1 -1
firmware/target/arm/s3c2440/uart-s3c2440.c
··· 60 60 } 61 61 62 62 63 - static int uart_push(void *user_data, unsigned char ch) 63 + static int uart_push(void *user_data, int ch) 64 64 { 65 65 (void)user_data; 66 66