A tiny printf for embedded applications - by Kustaa Nyholm
Dependents: lpc1768-picotcp-demo
printf.c
00001 /* 00002 File: printf.c 00003 00004 Copyright (C) 2004 Kustaa Nyholm 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Lesser General Public 00008 License as published by the Free Software Foundation; either 00009 version 2.1 of the License, or (at your option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Lesser General Public License for more details. 00015 00016 You should have received a copy of the GNU Lesser General Public 00017 License along with this library; if not, write to the Free Software 00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 00020 */ 00021 00022 #include "printf.h" 00023 00024 typedef void (*putcf) (void *, char); 00025 static putcf stdout_putf; 00026 static void *stdout_putp; 00027 00028 struct param { 00029 char lz; /**< Leading zeros */ 00030 unsigned int width; /**< field width */ 00031 char sign; /**< The sign to display (if any) */ 00032 char alt; /**< alternate form */ 00033 unsigned int base; /**< number base (e.g.: 8, 10, 16) */ 00034 char uc; /**< Upper case (for base16 only) */ 00035 char *bf; /**< Buffer to output */ 00036 }; 00037 00038 #ifdef PRINTF_LONG_SUPPORT 00039 00040 static void uli2a(unsigned long int num, struct param *p) 00041 { 00042 int n = 0; 00043 unsigned long int d = 1; 00044 char *bf = p->bf; 00045 while (num / d >= p->base) 00046 d *= p->base; 00047 while (d != 0) { 00048 int dgt = num / d; 00049 num %= d; 00050 d /= p->base; 00051 if (n || dgt > 0 || d == 0) { 00052 *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); 00053 ++n; 00054 } 00055 } 00056 *bf = 0; 00057 } 00058 00059 static void li2a(long num, struct param *p) 00060 { 00061 if (num < 0) { 00062 num = -num; 00063 p->sign = '-'; 00064 } 00065 uli2a(num, p); 00066 } 00067 #endif 00068 00069 static void ui2a(unsigned int num, struct param *p) 00070 { 00071 int n = 0; 00072 unsigned int d = 1; 00073 char *bf = p->bf; 00074 while (num / d >= p->base) 00075 d *= p->base; 00076 while (d != 0) { 00077 int dgt = num / d; 00078 num %= d; 00079 d /= p->base; 00080 if (n || dgt > 0 || d == 0) { 00081 *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); 00082 ++n; 00083 } 00084 } 00085 *bf = 0; 00086 } 00087 00088 static void i2a(int num, struct param *p) 00089 { 00090 if (num < 0) { 00091 num = -num; 00092 p->sign = '-'; 00093 } 00094 ui2a(num, p); 00095 } 00096 00097 static int a2d(char ch) 00098 { 00099 if (ch >= '0' && ch <= '9') 00100 return ch - '0'; 00101 else if (ch >= 'a' && ch <= 'f') 00102 return ch - 'a' + 10; 00103 else if (ch >= 'A' && ch <= 'F') 00104 return ch - 'A' + 10; 00105 else 00106 return -1; 00107 } 00108 00109 static char a2i(char ch, char **src, int base, int *nump) 00110 { 00111 char *p = *src; 00112 int num = 0; 00113 int digit; 00114 while ((digit = a2d(ch)) >= 0) { 00115 if (digit > base) 00116 break; 00117 num = num * base + digit; 00118 ch = *p++; 00119 } 00120 *src = p; 00121 *nump = num; 00122 return ch; 00123 } 00124 00125 static void putchw(void *putp, putcf putf, struct param *p) 00126 { 00127 char ch; 00128 int n = p->width; 00129 char *bf = p->bf; 00130 00131 /* Number of filling characters */ 00132 while (*bf++ && n > 0) 00133 n--; 00134 if (p->sign) 00135 n--; 00136 if (p->alt && p->base == 16) 00137 n -= 2; 00138 else if (p->alt && p->base == 8) 00139 n--; 00140 00141 /* Fill with space, before alternate or sign */ 00142 if (!p->lz) { 00143 while (n-- > 0) 00144 putf(putp, ' '); 00145 } 00146 00147 /* print sign */ 00148 if (p->sign) 00149 putf(putp, p->sign); 00150 00151 /* Alternate */ 00152 if (p->alt && p->base == 16) { 00153 putf(putp, '0'); 00154 putf(putp, (p->uc ? 'X' : 'x')); 00155 } else if (p->alt && p->base == 8) { 00156 putf(putp, '0'); 00157 } 00158 00159 /* Fill with zeros, after alternate or sign */ 00160 if (p->lz) { 00161 while (n-- > 0) 00162 putf(putp, '0'); 00163 } 00164 00165 /* Put actual buffer */ 00166 bf = p->bf; 00167 while ((ch = *bf++)) 00168 putf(putp, ch); 00169 } 00170 00171 void tfp_format(void *putp, putcf putf, char *fmt, va_list va) 00172 { 00173 struct param p; 00174 #ifdef PRINTF_LONG_SUPPORT 00175 char bf[23]; 00176 #else 00177 char bf[12]; 00178 #endif 00179 p.bf = bf; 00180 00181 char ch; 00182 00183 while ((ch = *(fmt++))) { 00184 if (ch != '%') { 00185 putf(putp, ch); 00186 } else { 00187 /* Init parameter struct */ 00188 p.lz = 0; 00189 p.alt = 0; 00190 p.width = 0; 00191 p.sign = 0; 00192 #ifdef PRINTF_LONG_SUPPORT 00193 char lng = 0; 00194 #endif 00195 00196 /* Flags */ 00197 while ((ch = *(fmt++))) { 00198 switch (ch) { 00199 case '0': 00200 p.lz = 1; 00201 continue; 00202 case '#': 00203 p.alt = 1; 00204 continue; 00205 default: 00206 break; 00207 } 00208 break; 00209 } 00210 00211 /* Width */ 00212 if (ch >= '0' && ch <= '9') { 00213 ch = a2i(ch, &fmt, 10, &(p.width)); 00214 } 00215 #ifdef PRINTF_LONG_SUPPORT 00216 if (ch == 'l') { 00217 ch = *(fmt++); 00218 lng = 1; 00219 } 00220 #endif 00221 switch (ch) { 00222 case 0: 00223 goto abort; 00224 case 'u': 00225 p.base = 10; 00226 #ifdef PRINTF_LONG_SUPPORT 00227 if (lng) 00228 uli2a(va_arg(va, unsigned long int), &p); 00229 else 00230 #endif 00231 ui2a(va_arg(va, unsigned int), &p); 00232 putchw(putp, putf, &p); 00233 break; 00234 case 'd': 00235 case 'i': 00236 p.base = 10; 00237 #ifdef PRINTF_LONG_SUPPORT 00238 if (lng) 00239 li2a(va_arg(va, unsigned long int), &p); 00240 else 00241 #endif 00242 i2a(va_arg(va, int), &p); 00243 putchw(putp, putf, &p); 00244 break; 00245 case 'x': 00246 case 'X': 00247 p.base = 16; 00248 p.uc = (ch == 'X'); 00249 #ifdef PRINTF_LONG_SUPPORT 00250 if (lng) 00251 uli2a(va_arg(va, unsigned long int), &p); 00252 else 00253 #endif 00254 ui2a(va_arg(va, unsigned int), &p); 00255 putchw(putp, putf, &p); 00256 break; 00257 case 'o': 00258 p.base = 8; 00259 ui2a(va_arg(va, unsigned int), &p); 00260 putchw(putp, putf, &p); 00261 break; 00262 case 'c': 00263 putf(putp, (char)(va_arg(va, int))); 00264 break; 00265 case 's': 00266 p.bf = va_arg(va, char *); 00267 putchw(putp, putf, &p); 00268 p.bf = bf; 00269 break; 00270 case '%': 00271 putf(putp, ch); 00272 default: 00273 break; 00274 } 00275 } 00276 } 00277 abort:; 00278 } 00279 00280 void init_printf(void *putp, void (*putf) (void *, char)) 00281 { 00282 stdout_putf = putf; 00283 stdout_putp = putp; 00284 } 00285 00286 void tfp_printf(char *fmt, ...) 00287 { 00288 va_list va; 00289 va_start(va, fmt); 00290 tfp_format(stdout_putp, stdout_putf, fmt, va); 00291 va_end(va); 00292 } 00293 00294 static void putcp(void *p, char c) 00295 { 00296 *(*((char **)p))++ = c; 00297 } 00298 00299 void tfp_sprintf(char *s, char *fmt, ...) 00300 { 00301 va_list va; 00302 va_start(va, fmt); 00303 tfp_format(&s, putcp, fmt, va); 00304 putcp(&s, 0); 00305 va_end(va); 00306 }
Generated on Mon Jul 18 2022 10:09:47 by 1.7.2