1 /*
2  * Copyright (c) 2006-2018 Ali Mashtizadeh
3  * All rights reserved.
4  */
5 
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <stdarg.h>
9 #include <string.h>
10 #include <stdio.h>
11 
12 // static unsigned long getuint(va_list *ap, int lflag)
13 #define getuint(ap, lflag) \
14     (lflag == 8) ? va_arg(ap, uint64_t) : \
15     (lflag == 4) ? va_arg(ap, uint32_t) : \
16     (lflag == 2) ? va_arg(ap, uint32_t) : \
17     (lflag == 1) ? va_arg(ap, uint32_t) : 0
18 
19 // static long getint(va_list *ap, int lflag)
20 #define getint(ap, lflag) \
21     (lflag == 8) ? va_arg(ap, int64_t) : \
22     (lflag == 4) ? va_arg(ap, int32_t) : \
23     (lflag == 2) ? va_arg(ap, int32_t) : \
24     (lflag == 1) ? va_arg(ap, int32_t) : 0
25 
26 static const char *numberstring_lower = "0123456789abcdef";
27 static const char *numberstring_upper = "0123456789ABCDEF";
28 
printnum(void (* func)(int,void *),void * handle,uint64_t num,int base,int width,int padc)29 static void printnum(void (*func)(int, void*),void *handle,
30                      uint64_t num,int base,int width,int padc)
31 {
32     char buf[64];
33     char *p = buf;
34     int spaces;
35     if (base < 0)
36     {
37         base = -base;
38         do {
39             *p = numberstring_upper[num % base];
40             p++;
41         } while (num /= base);
42     } else {
43         do {
44             *p = numberstring_lower[num % base];
45             p++;
46         } while (num /= base);
47     }
48 
49     // Print spacers (pre-number)
50     spaces = width - (p - buf);
51     if (padc == ' ' || padc == '0') {
52 	while (spaces > 0)
53 	{
54 	    func(padc, handle);
55 	    spaces--;
56 	}
57     }
58 
59     // Print Number
60     while (p != buf) {
61         p--;
62         func((int)*p, handle);
63     }
64 
65     // Print spacers (post-number)
66     if (padc == '-') {
67 	while (spaces > 0)
68 	{
69 	    func(' ', handle);
70 	    spaces--;
71 	}
72     }
73 }
74 
kvprintf(char const * fmt,void (* func)(int,void *),void * handle,va_list ap)75 static int kvprintf(char const *fmt, void (*func)(int,void *), void *handle, va_list ap)
76 {
77     const char *p;
78     int ch;
79     uint64_t unum;
80     int64_t num;
81     int lflag, width, padc;
82 
83     while (1) {
84         while ((ch = *(unsigned char *)fmt++) != '%') {
85             if (ch == '\0') return -1;
86             func(ch, handle);
87         }
88 
89         width = -1;
90         lflag = 4;
91         padc = ' ';
92 again:
93         switch (ch = *(unsigned char *)fmt++) {
94             case '-':
95                 padc = '-';
96                 goto again;
97             case '0':
98                 padc = '0';
99                 goto again;
100             case '1':
101             case '2':
102             case '3':
103             case '4':
104             case '5':
105             case '6':
106             case '7':
107             case '8':
108             case '9':
109                 width = 0;
110                 while (1) {
111                     width = 10 * width + ch - '0';
112                     ch = *fmt;
113                     if (ch < '0' || ch > '9')
114                     {
115                         break;
116                     }
117                     fmt++;
118                     if (ch == '\0')
119                     {
120                         fmt--;
121                         goto again;
122                     }
123                 }
124                 goto again;
125             case 'c':
126                 func(va_arg(ap, int) & 0xff, handle);
127                 break;
128             case 's': {
129 		int spaces;
130 
131 		p = va_arg(ap, char *);
132 		if (p == NULL) {
133 		    func('*', handle);
134 		    func('N', handle);
135 		    func('U', handle);
136 		    func('L', handle);
137 		    func('L', handle);
138 		    func('*', handle);
139 		    break;
140 		}
141 		spaces = width - strlen(p);
142 
143 		if (padc == ' ') {
144 		    while (spaces > 0)
145 		    {
146 			func(' ', handle);
147 			spaces--;
148 		    }
149 		}
150 
151 		while (*p != '\0')
152 		{
153 		    func(*p++, handle);
154 		}
155 
156 		if (padc == '-') {
157 		    while (spaces > 0)
158 		    {
159 			func(' ', handle);
160 			spaces--;
161 		    }
162 		}
163 		break;
164             }
165             case 'd':
166                 num = getint(ap, lflag);
167                 if (num < 0) {
168                     func('-', handle);
169                     unum = -num;
170                 } else {
171                     unum = num;
172                 }
173                 printnum(func, handle, unum, 10, width, padc);
174                 break;
175             case 'u':
176                 unum = getuint(ap, lflag);
177                 printnum(func, handle, unum, 10, width, padc);
178                 break;
179             case 'o':
180                 unum = getuint(ap, lflag);
181                 printnum(func, handle, unum, 8, width, padc);
182                 break;
183             case 'p':
184                 unum = (unsigned long)va_arg(ap, void *);
185                 printnum(func, handle, unum, 8, width, padc);
186                 break;
187             case 'x':
188                 unum = getuint(ap, lflag);
189                 printnum(func, handle, unum, 16, width, padc);
190                 break;
191             case 'X':
192                 unum = getuint(ap, lflag);
193                 printnum(func, handle, unum, -16, width, padc);
194                 break;
195             case 'l':
196                 lflag = 8;
197                 goto again;
198             case '%':
199             default: // Print Literally
200                 func(ch, handle);
201                 break;
202         }
203     }
204     return 0;
205 }
206 
fileputc(int c,void * handle)207 static void fileputc(int c, void* handle)
208 {
209     fputc(c, (FILE *)handle);
210 }
211 
printf(const char * fmt,...)212 int printf(const char *fmt, ...)
213 {
214     int ret;
215     va_list ap;
216 
217     va_start(ap, fmt);
218     ret = kvprintf(fmt, fileputc, (void *)stdout, ap);
219     va_end(ap);
220 
221     return ret;
222 }
223 
fprintf(FILE * stream,const char * fmt,...)224 int fprintf(FILE *stream, const char *fmt, ...)
225 {
226     int ret;
227     va_list ap;
228 
229     va_start(ap, fmt);
230     ret = kvprintf(fmt, fileputc, stream, ap);
231     va_end(ap);
232 
233     return ret;
234 }
235 
236 typedef struct StrState {
237     char	*buf;
238     char	*cur;
239     size_t	maxlen;
240 } StrState;
241 
strputc(int c,void * handle)242 static void strputc(int c, void *handle)
243 {
244     StrState *state = (StrState *)handle;
245 
246     if ((state->maxlen != -1) &&
247 	(state->cur - state->buf >= state->maxlen)) {
248 	state->cur[0] = '\0';
249 	return;
250     }
251 
252     state->cur[0] = c;
253     state->cur++;
254 }
255 
sprintf(char * str,const char * fmt,...)256 int sprintf(char *str, const char *fmt, ...)
257 {
258     int ret;
259     va_list ap;
260     StrState state;
261 
262     state.buf = str;
263     state.cur = str;
264     state.maxlen = -1;
265 
266     va_start(ap, fmt);
267     ret = kvprintf(fmt, strputc, &state, ap);
268     va_end(ap);
269 
270     state.cur[0] = '\0';
271 
272     return ret;
273 }
274 
snprintf(char * str,size_t n,const char * fmt,...)275 int snprintf(char *str, size_t n, const char *fmt, ...)
276 {
277     int ret;
278     va_list ap;
279     StrState state;
280 
281     state.buf = str;
282     state.cur = str;
283     state.maxlen = n;
284 
285     va_start(ap, fmt);
286     ret = kvprintf(fmt, strputc, &state, ap);
287     va_end(ap);
288 
289     state.cur[0] = '\0';
290 
291     return ret;
292 }
293 
294