Bläddra i källkod

Rewrote printf and friends to better support standard C semantics.

tags/v0.9.3
Michael Brown 18 år sedan
förälder
incheckning
2421723a15
4 ändrade filer med 311 tillägg och 168 borttagningar
  1. 1
    0
      src/arch/i386/include/stdint.h
  2. 274
    165
      src/core/vsprintf.c
  3. 35
    3
      src/include/vsprintf.h
  4. 1
    0
      src/net/ethernet.c

+ 1
- 0
src/arch/i386/include/stdint.h Visa fil

@@ -16,6 +16,7 @@ typedef signed long		int32_t;
16 16
 typedef signed long long	int64_t;
17 17
 
18 18
 typedef unsigned long		physaddr_t;
19
+typedef unsigned long		intptr_t;
19 20
 
20 21
 typedef signed char	   s8;
21 22
 typedef unsigned char      u8;

+ 274
- 165
src/core/vsprintf.c Visa fil

@@ -1,213 +1,322 @@
1
+#include <stddef.h>
1 2
 #include <stdarg.h>
2
-#include <gpxe/if_ether.h> /* for ETH_ALEN */
3
-#include "limits.h" /* for CHAR_BIT */
4
-#include "console.h"
5
-#include "errno.h"
6
-#include "vsprintf.h"
7
-
8
-#define LONGLONG_SHIFT	((int)((sizeof(unsigned long long)*CHAR_BIT) - 4))
9
-#define LONG_SHIFT	((int)((sizeof(unsigned long)*CHAR_BIT) - 4))
10
-#define INT_SHIFT	((int)((sizeof(unsigned int)*CHAR_BIT) - 4))
11
-#define SHRT_SHIFT	((int)((sizeof(unsigned short)*CHAR_BIT) - 4))
12
-#define CHAR_SHIFT	((int)((sizeof(unsigned char)*CHAR_BIT) - 4))
3
+#include <console.h>
4
+#include <errno.h>
5
+#include <vsprintf.h>
6
+
7
+#define CHAR_LEN	1
8
+#define SHORT_LEN	2
9
+#define INT_LEN		3
10
+#define LONG_LEN	4
11
+#define LONGLONG_LEN	5
12
+#define SIZE_T_LEN	6
13
+
14
+static uint8_t type_sizes[] = {
15
+	[CHAR_LEN]	= sizeof ( char ),
16
+	[SHORT_LEN]	= sizeof ( short ),
17
+	[INT_LEN]	= sizeof ( int ),
18
+	[LONG_LEN]	= sizeof ( long ),
19
+	[LONGLONG_LEN]	= sizeof ( long long ),
20
+	[SIZE_T_LEN]	= sizeof ( size_t ),
21
+};
13 22
 
14 23
 /** @file */
15 24
 
16 25
 /**
17
- * Write a formatted string to a buffer.
26
+ * A printf context
18 27
  *
19
- * @v buf		Buffer into which to write the string, or NULL
28
+ * Contexts are used in order to be able to share code between
29
+ * vprintf() and vsnprintf(), without requiring the allocation of a
30
+ * buffer for vprintf().
31
+ */
32
+struct printf_context {
33
+	/**
34
+	 * Character handler
35
+	 *
36
+	 * @v ctx	Context
37
+	 * @v c		Character
38
+	 *
39
+	 * This method is called for each character written to the
40
+	 * formatted string.  It must increment @len.
41
+	 */
42
+	void ( * handler ) ( struct printf_context *ctx, unsigned int c );
43
+	/** Length of formatted string */
44
+	size_t len;
45
+	/** Buffer for formatted string (used by printf_sputc()) */
46
+	char *buf;
47
+	/** Buffer length (used by printf_sputc()) */
48
+	size_t max_len;
49
+};
50
+
51
+#define LCASE 0x20
52
+#define ALT_FORM 0x02
53
+
54
+static char * format_hex ( char *buf, unsigned long long num, int width,
55
+			   int flags ) {
56
+	char *ptr = buf;
57
+	int case_mod;
58
+
59
+	/* Generate the number */
60
+	case_mod = flags & LCASE;
61
+	do {
62
+		*ptr++ = "0123456789ABCDEF"[ num & 0xf ] | case_mod;
63
+		num >>= 4;
64
+	} while ( num );
65
+
66
+	/* Zero-pad to width */
67
+	while ( ( ptr - buf ) < width )
68
+		*ptr++ = '0';
69
+
70
+	/* Add "0x" or "0X" if alternate form specified */
71
+	if ( flags & ALT_FORM ) {
72
+		*ptr++ = 'X' | case_mod;
73
+		*ptr++ = '0';
74
+	}
75
+
76
+	return ptr;
77
+}
78
+
79
+static char * format_decimal ( char *buf, signed long num, int width ) {
80
+	char *ptr = buf;
81
+	int negative = 0;
82
+
83
+	/* Generate the number */
84
+	if ( num < 0 ) {
85
+		negative = 1;
86
+		num = -num;
87
+	}
88
+	do {
89
+		*ptr++ = '0' + ( num % 10 );
90
+		num /= 10;
91
+	} while ( num );
92
+
93
+	/* Add "-" if necessary */
94
+	if ( negative )
95
+		*ptr++ = '-';
96
+
97
+	/* Space-pad to width */
98
+	while ( ( ptr - buf ) < width )
99
+		*ptr++ = ' ';
100
+
101
+	return ptr;
102
+}
103
+
104
+
105
+/**
106
+ * Write a formatted string to a printf context
107
+ *
108
+ * @v ctx		Context
20 109
  * @v fmt		Format string
21 110
  * @v args		Arguments corresponding to the format string
22
- * @ret len		Length of string written to buffer (if buf != NULL)
23
- * @ret	0		(if buf == NULL)
24
- * @err None		-
25
- *
26
- * If #buf==NULL, then the string will be written to the console
27
- * directly using putchar().
28
- *
111
+ * @ret len		Length of formatted string
29 112
  */
30
-static int vsprintf(char *buf, const char *fmt, va_list args)
31
-{
32
-	const char *p;
33
-	char *s;
34
-	s = buf;
35
-	for ( ; *fmt != '\0'; ++fmt) {
36
-		if (*fmt != '%') {
37
-			buf ? *s++ = *fmt : putchar(*fmt);
113
+int vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
114
+	int flags;
115
+	int width;
116
+	uint8_t *length;
117
+	int character;
118
+	unsigned long long hex;
119
+	signed long decimal;
120
+	char num_buf[32];
121
+	char *ptr;
122
+
123
+	/* Initialise context */
124
+	ctx->len = 0;
125
+
126
+	for ( ; *fmt ; fmt++ ) {
127
+		/* Pass through ordinary characters */
128
+		if ( *fmt != '%' ) {
129
+			ctx->handler ( ctx, *fmt );
38 130
 			continue;
39 131
 		}
40
-		/* skip width specs */
41 132
 		fmt++;
42
-		while (*fmt >= '0' && *fmt <= '9')
43
-			fmt++;
44
-		if (*fmt == '.')
45
-			fmt++;
46
-		while (*fmt >= '0' && *fmt <= '9')
47
-			fmt++;
48
-		if (*fmt == 's') {
49
-			for(p = va_arg(args, char *); *p != '\0'; p++)
50
-				buf ? *s++ = *p : putchar(*p);
51
-		} else if (*fmt == 'm') {
52
-			for(p = strerror(errno); *p != '\0'; p++)
53
-				buf ? *s++ = *p : putchar(*p);
54
-		} else {	/* Length of item is bounded */
55
-			char tmp[40], *q = tmp;
56
-			int alt = 0;
57
-			int shift = INT_SHIFT;
58
-			if (*fmt == '#') {
59
-				alt = 1;
60
-				fmt++;
61
-			}
62
-			if (*fmt == 'l') {
63
-				shift = LONG_SHIFT;
64
-				fmt++;
133
+		/* Process flag characters */
134
+		flags = 0;
135
+		for ( ; ; fmt++ ) {
136
+			if ( *fmt == '#' ) {
137
+				flags |= ALT_FORM;
138
+			} else if ( *fmt == '0' ) {
139
+				/* We always 0-pad hex and space-pad decimal */
140
+			} else {
141
+				/* End of flag characters */
142
+				break;
65 143
 			}
66
-			if (*fmt == 'l') {
67
-				shift = LONGLONG_SHIFT;
68
-				fmt++;
69
-			}
70
-			if (*fmt == 'h') {
71
-				shift = SHRT_SHIFT;
72
-				fmt++;
73
-				if (*fmt == 'h') {
74
-					shift = CHAR_SHIFT;
75
-					fmt++;
76
-				}
144
+		}
145
+		/* Process field width */
146
+		width = 0;
147
+		for ( ; ; fmt++ ) {
148
+			if ( ( ( unsigned ) ( *fmt - '0' ) ) < 10 ) {
149
+				width = ( width * 10 ) + ( *fmt - '0' );
150
+			} else {
151
+				break;
77 152
 			}
78
-
79
-			/*
80
-			 * Before each format q points to tmp buffer
81
-			 * After each format q points past end of item
82
-			 */
83
-			if ((*fmt | 0x20) == 'x') {
84
-				/* With x86 gcc, sizeof(long) == sizeof(int) */
85
-				unsigned long h;
86
-				int ncase;
87
-				if (shift > LONG_SHIFT) {
88
-					h = va_arg(args, unsigned long long);
89
-				} else if (shift > INT_SHIFT) {
90
-					h = va_arg(args, unsigned long);
91
-				} else {
92
-					h = va_arg(args, unsigned int);
93
-				}
94
-				ncase = (*fmt & 0x20);
95
-				if (alt) {
96
-					*q++ = '0';
97
-					*q++ = 'X' | ncase;
98
-				}
99
-				for ( ; shift >= 0; shift -= 4)
100
-					*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
153
+		}
154
+		/* We don't do floating point */
155
+		/* Process length modifier */
156
+		length = &type_sizes[INT_LEN];
157
+		for ( ; ; fmt++ ) {
158
+			if ( *fmt == 'h' ) {
159
+				length--;
160
+			} else if ( *fmt == 'l' ) {
161
+				length++;
162
+			} else if ( *fmt == 'z' ) {
163
+				length = &type_sizes[SIZE_T_LEN];
164
+			} else {
165
+				break;
101 166
 			}
102
-			else if (*fmt == 'd') {
103
-				char *r, *t;
104
-				long i;
105
-				if (shift > LONG_SHIFT) {
106
-					i = va_arg(args, long long);
107
-				} else if (shift > INT_SHIFT) {
108
-					i = va_arg(args, long);
109
-				} else {
110
-					i = va_arg(args, int);
111
-				}
112
-				if (i < 0) {
113
-					*q++ = '-';
114
-					i = -i;
115
-				}
116
-				t = q;		/* save beginning of digits */
117
-				do {
118
-					*q++ = '0' + (i % 10);
119
-					i /= 10;
120
-				} while (i);
121
-				/* reverse digits, stop in middle */
122
-				r = q;		/* don't alter q */
123
-				while (--r > t) {
124
-					i = *r;
125
-					*r = *t;
126
-					*t++ = i;
127
-				}
167
+		}
168
+		/* Process conversion specifier */
169
+		if ( *fmt == 'c' ) {
170
+			character = va_arg ( args, unsigned int );
171
+			ctx->handler ( ctx, character );
172
+		} else if ( *fmt == 's' ) {
173
+			ptr = va_arg ( args, char * );
174
+			for ( ; *ptr ; ptr++ ) {
175
+				ctx->handler ( ctx, *ptr );
128 176
 			}
129
-			else if (*fmt == '@') {
130
-				unsigned char *r;
131
-				union {
132
-					uint32_t	l;
133
-					unsigned char	c[4];
134
-				} u;
135
-				u.l = va_arg(args, uint32_t);
136
-				for (r = &u.c[0]; r < &u.c[4]; ++r)
137
-					q += sprintf(q, "%d.", *r);
138
-				--q;
177
+		} else if ( *fmt == 'p' ) {
178
+			hex = ( intptr_t ) va_arg ( args, void * );
179
+			ptr = format_hex ( num_buf, hex, width,
180
+					   ( ALT_FORM | LCASE ) );
181
+			do {
182
+				ctx->handler ( ctx, *(--ptr) );
183
+			} while ( ptr != num_buf );
184
+		} else if ( ( *fmt & ~0x20 ) == 'X' ) {
185
+			flags |= ( *fmt & 0x20 ); /* LCASE */
186
+			if ( *length >= sizeof ( unsigned long long ) ) {
187
+				hex = va_arg ( args, unsigned long long );
188
+			} else if ( *length >= sizeof ( unsigned long ) ) {
189
+				hex = va_arg ( args, unsigned long );
190
+			} else {
191
+				hex = va_arg ( args, unsigned int );
139 192
 			}
140
-			else if (*fmt == '!') {
141
-				const char *r;
142
-				p = va_arg(args, char *);
143
-				for (r = p + ETH_ALEN; p < r; ++p)
144
-					q += sprintf(q, "%hhX:", *p);
145
-				--q;
193
+			ptr = format_hex ( num_buf, hex, width, flags );
194
+			do {
195
+				ctx->handler ( ctx, *(--ptr) );
196
+			} while ( ptr != num_buf );
197
+		} else if ( *fmt == 'd' ) {
198
+			if ( *length >= sizeof ( signed long ) ) {
199
+				decimal = va_arg ( args, signed long );
200
+			} else {
201
+				decimal = va_arg ( args, signed int );
146 202
 			}
147
-			else if (*fmt == 'c')
148
-				*q++ = va_arg(args, int);
149
-			else
150
-				*q++ = *fmt;
151
-			/* now output the saved string */
152
-			for (p = tmp; p < q; ++p)
153
-				buf ? *s++ = *p : putchar(*p);
203
+			ptr = format_decimal ( num_buf, decimal, width );
204
+			do {
205
+				ctx->handler ( ctx, *(--ptr) );
206
+			} while ( ptr != num_buf );
207
+		} else {
208
+			ctx->handler ( ctx, *fmt );
154 209
 		}
155 210
 	}
156
-	if (buf)
157
-		*s = '\0';
158
-	return (s - buf);
211
+
212
+	return ctx->len;
159 213
 }
160 214
 
161 215
 /**
162
- * Write a formatted string to a buffer.
216
+ * Write character to buffer
163 217
  *
164
- * @v buf		Buffer into which to write the string, or NULL
165
- * @v fmt		Format string
166
- * @v ...		Arguments corresponding to the format string
167
- * @ret len		Length of string written to buffer (if buf != NULL)
168
- * @ret	0		(if buf == NULL)
169
- * @err None		-
218
+ * @v ctx		Context
219
+ * @v c			Character
220
+ */
221
+static void printf_sputc ( struct printf_context *ctx, unsigned int c ) {
222
+	if ( ++ctx->len < ctx->max_len )
223
+		ctx->buf[ctx->len-1] = c;
224
+}
225
+
226
+/**
227
+ * Write a formatted string to a buffer
170 228
  *
171
- * If #buf==NULL, then the string will be written to the console
172
- * directly using putchar().
229
+ * @v buf		Buffer into which to write the string
230
+ * @v size		Size of buffer
231
+ * @v fmt		Format string
232
+ * @v args		Arguments corresponding to the format string
233
+ * @ret len		Length of formatted string
173 234
  *
235
+ * If the buffer is too small to contain the string, the returned
236
+ * length is the length that would have been written had enough space
237
+ * been available.
174 238
  */
175
-int sprintf(char *buf, const char *fmt, ...)
176
-{
177
-	va_list args;
178
-	int i;
179
-	va_start(args, fmt);
180
-	i=vsprintf(buf, fmt, args);
181
-	va_end(args);
182
-	return i;
239
+int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ) {
240
+	struct printf_context ctx;
241
+	int len;
242
+
243
+	/* Ensure last byte is NUL if a size is specified.  This
244
+	 * catches the case of the buffer being too small, in which
245
+	 * case a trailing NUL would not otherwise be added.
246
+	 */
247
+	if ( size != PRINTF_NO_LENGTH )
248
+		buf[size-1] = '\0';
249
+
250
+	/* Hand off to vcprintf */
251
+	ctx.handler = printf_sputc;
252
+	ctx.buf = buf;
253
+	ctx.max_len = size;
254
+	len = vcprintf ( &ctx, fmt, args );
255
+
256
+	/* Add trailing NUL */
257
+	printf_sputc ( &ctx, '\0' );
258
+
259
+	return len;
183 260
 }
184 261
 
185
-#warning "Remove this buffer-overflow-in-waiting at some point"
262
+/**
263
+ * Write a formatted string to a buffer
264
+ *
265
+ * @v buf		Buffer into which to write the string
266
+ * @v size		Size of buffer
267
+ * @v fmt		Format string
268
+ * @v ...		Arguments corresponding to the format string
269
+ * @ret len		Length of formatted string
270
+ */
186 271
 int snprintf ( char *buf, size_t size, const char *fmt, ... ) {
187 272
 	va_list args;
188 273
 	int i;
189 274
 
190 275
 	va_start ( args, fmt );
191
-	i = vsprintf ( buf, fmt, args );
276
+	i = vsnprintf ( buf, size, fmt, args );
192 277
 	va_end ( args );
193 278
 	return i;
194 279
 }
195 280
 
281
+/**
282
+ * Write character to console
283
+ *
284
+ * @v ctx		Context
285
+ * @v c			Character
286
+ */
287
+static void printf_putchar ( struct printf_context *ctx, unsigned int c ) {
288
+	++ctx->len;
289
+	putchar ( c );
290
+}
291
+
292
+/**
293
+ * Write a formatted string to the console
294
+ *
295
+ * @v fmt		Format string
296
+ * @v args		Arguments corresponding to the format string
297
+ * @ret len		Length of formatted string
298
+ */
299
+int vprintf ( const char *fmt, va_list args ) {
300
+	struct printf_context ctx;
301
+
302
+	/* Hand off to vcprintf */
303
+	ctx.handler = printf_putchar;	
304
+	return vcprintf ( &ctx, fmt, args );	
305
+}
306
+
196 307
 /**
197 308
  * Write a formatted string to the console.
198 309
  *
199 310
  * @v fmt		Format string
200 311
  * @v ...		Arguments corresponding to the format string
201
- * @ret	None		-
202
- * @err None		-
203
- *
312
+ * @ret	len		Length of formatted string
204 313
  */
205
-int printf(const char *fmt, ...)
206
-{
314
+int printf ( const char *fmt, ... ) {
207 315
 	va_list args;
208 316
 	int i;
209
-	va_start(args, fmt);
210
-	i=vsprintf(0, fmt, args);
211
-	va_end(args);
317
+
318
+	va_start ( args, fmt );
319
+	i = vprintf ( fmt, args );
320
+	va_end ( args );
212 321
 	return i;
213 322
 }

+ 35
- 3
src/include/vsprintf.h Visa fil

@@ -44,8 +44,40 @@
44 44
  *
45 45
  */
46 46
 
47
-extern int sprintf ( char *buf, const char *fmt, ... );
48
-extern int snprintf ( char *buf, size_t size, const char *fmt, ... );
49
-extern int printf ( const char *fmt, ... );
47
+#include <stdarg.h>
48
+
49
+#define PRINTF_NO_LENGTH ( ( size_t ) -1 )
50
+
51
+extern int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args );
52
+extern int vprintf ( const char *fmt, va_list args );
53
+
54
+extern int __attribute__ (( format ( printf, 3, 4 ) ))
55
+snprintf ( char *buf, size_t size, const char *fmt, ... );
56
+
57
+extern int __attribute__ (( format ( printf, 1, 2 ) ))
58
+printf ( const char *fmt, ... );
59
+
60
+/**
61
+ * Write a formatted string to a buffer
62
+ *
63
+ * @v buf		Buffer into which to write the string
64
+ * @v fmt		Format string
65
+ * @v ...		Arguments corresponding to the format string
66
+ * @ret len		Length of formatted string
67
+ */
68
+#define sprintf( buf, fmt, ... ) \
69
+	snprintf ( (buf), PRINTF_NO_LENGTH, (fmt), ## __VA_ARGS__ )
70
+
71
+/**
72
+ * Write a formatted string to a buffer
73
+ *
74
+ * @v buf		Buffer into which to write the string
75
+ * @v fmt		Format string
76
+ * @v args		Arguments corresponding to the format string
77
+ * @ret len		Length of formatted string
78
+ */
79
+static inline int vsprintf ( char *buf, const char *fmt, va_list args ) {
80
+	return vsnprintf ( buf, PRINTF_NO_LENGTH, fmt, args );
81
+}
50 82
 
51 83
 #endif /* VSPRINTF_H */

+ 1
- 0
src/net/ethernet.c Visa fil

@@ -20,6 +20,7 @@
20 20
 #include <string.h>
21 21
 #include <byteswap.h>
22 22
 #include <assert.h>
23
+#include <vsprintf.h>
23 24
 #include <gpxe/if_arp.h>
24 25
 #include <gpxe/if_ether.h>
25 26
 #include <gpxe/netdevice.h>

Laddar…
Avbryt
Spara