@@ -210,15 +210,83 @@ void __str_base16(char *pb, int val)
210
210
}
211
211
}
212
212
213
- int __format (char * buffer ,
214
- int val ,
215
- int width ,
216
- int zeropad ,
217
- int base ,
218
- int alternate_form )
213
+ /*
214
+ * The specification of snprintf() is defined in C99 7.19.6.5,
215
+ * and its behavior and return value should comply with the
216
+ * following description:
217
+ *
218
+ * - If n is zero, nothing is written.
219
+ * - Writes at most n bytes, including the null character.
220
+ * - On success, the return value should be the length of the
221
+ * entire converted string even if n is insufficient to store it.
222
+ *
223
+ * Therefore, the following code defines a structure called fmtbuf_t
224
+ * to implement formatted output conversion for the functions in the
225
+ * printf() family.
226
+ *
227
+ * @buf: the current position of the buffer.
228
+ * @n : the remaining space of the buffer.
229
+ * @len: the number of characters that would have been written
230
+ * had n been sufficiently large.
231
+ *
232
+ * Once a write operation is performed, buf and n will be
233
+ * respectively incremented and decremented by the actual written
234
+ * size if n is sufficient, and len must be incremented to store
235
+ * the length of the entire converted string.
236
+ */
237
+ typedef struct {
238
+ char * buf ;
239
+ int n ;
240
+ int len ;
241
+ } fmtbuf_t ;
242
+
243
+ void __fmtbuf_write_char (fmtbuf_t * fmtbuf , int val )
244
+ {
245
+ fmtbuf -> len += 1 ;
246
+
247
+ /*
248
+ * Write the given character when n is greater than 1.
249
+ * This means preserving one position for the null character.
250
+ */
251
+ if (fmtbuf -> n <= 1 )
252
+ return ;
253
+
254
+ char ch = val & 0xFF ;
255
+ fmtbuf -> buf [0 ] = ch ;
256
+ fmtbuf -> buf += 1 ;
257
+ fmtbuf -> n -= 1 ;
258
+ }
259
+
260
+ void __fmtbuf_write_str (fmtbuf_t * fmtbuf , char * str , int l )
219
261
{
220
- int bi = 0 ;
221
- char pb [INT_BUF_LEN ];
262
+ fmtbuf -> len += l ;
263
+
264
+ /*
265
+ * Write the given string when n is greater than 1.
266
+ * This means preserving one position for the null character.
267
+ */
268
+ if (fmtbuf -> n <= 1 )
269
+ return ;
270
+
271
+ /*
272
+ * If the remaining space is less than the length of the string,
273
+ * write only n - 1 bytes.
274
+ */
275
+ int sz = fmtbuf -> n - 1 ;
276
+ l = l <= sz ? l : sz ;
277
+ strncpy (fmtbuf -> buf , str , l );
278
+ fmtbuf -> buf += l ;
279
+ fmtbuf -> n -= l ;
280
+ }
281
+
282
+ void __format (fmtbuf_t * fmtbuf ,
283
+ int val ,
284
+ int width ,
285
+ int zeropad ,
286
+ int base ,
287
+ int alternate_form )
288
+ {
289
+ char pb [INT_BUF_LEN ], ch ;
222
290
int pbi ;
223
291
224
292
/* set to zeroes */
@@ -249,24 +317,24 @@ int __format(char *buffer,
249
317
case 8 :
250
318
if (alternate_form ) {
251
319
if (width && zeropad && pb [pbi ] != '0' ) {
252
- buffer [ bi ++ ] = '0' ;
320
+ __fmtbuf_write_char ( fmtbuf , '0' ) ;
253
321
width -= 1 ;
254
322
} else if (pb [pbi ] != '0' )
255
323
pb [-- pbi ] = '0' ;
256
324
}
257
325
break ;
258
326
case 10 :
259
327
if (width && zeropad && pb [pbi ] == '-' ) {
260
- buffer [ bi ++ ] = '-' ;
328
+ __fmtbuf_write_char ( fmtbuf , '-' ) ;
261
329
pbi ++ ;
262
330
width -- ;
263
331
}
264
332
break ;
265
333
case 16 :
266
334
if (alternate_form ) {
267
335
if (width && zeropad && pb [pbi ] != '0' ) {
268
- buffer [ bi ++ ] = '0' ;
269
- buffer [ bi ++ ] = 'x' ;
336
+ __fmtbuf_write_char ( fmtbuf , '0' ) ;
337
+ __fmtbuf_write_char ( fmtbuf , 'x' ) ;
270
338
width -= 2 ;
271
339
} else if (pb [pbi ] != '0' ) {
272
340
pb [-- pbi ] = 'x' ;
@@ -280,28 +348,22 @@ int __format(char *buffer,
280
348
if (width < 0 )
281
349
width = 0 ;
282
350
351
+ ch = zeropad ? '0' : ' ' ;
283
352
while (width ) {
284
- buffer [ bi ++ ] = zeropad ? '0' : ' ' ;
353
+ __fmtbuf_write_char ( fmtbuf , ch ) ;
285
354
width -- ;
286
355
}
287
356
288
- for (; pbi < INT_BUF_LEN ; pbi ++ )
289
- buffer [bi ++ ] = pb [pbi ];
290
-
291
- return bi ;
357
+ __fmtbuf_write_str (fmtbuf , pb + pbi , INT_BUF_LEN - pbi );
292
358
}
293
359
294
- int __format_to_buf (char * buffer , char * format , int * var_args , int size )
360
+ void __format_to_buf (fmtbuf_t * fmtbuf , char * format , int * var_args )
295
361
{
296
- int si = 0 , bi = 0 , pi = 0 ;
297
-
298
- if (size == 0 )
299
- return 0 ;
362
+ int si = 0 , pi = 0 ;
300
363
301
- while (format [si ] && bi < size - 1 ) {
364
+ while (format [si ]) {
302
365
if (format [si ] != '%' ) {
303
- buffer [bi ] = format [si ];
304
- bi ++ ;
366
+ __fmtbuf_write_char (fmtbuf , format [si ]);
305
367
si ++ ;
306
368
} else {
307
369
int w = 0 , zp = 0 , pp = 0 , v = var_args [pi ], l ;
@@ -328,31 +390,27 @@ int __format_to_buf(char *buffer, char *format, int *var_args, int size)
328
390
case 's' :
329
391
/* append param pi as string */
330
392
l = strlen (v );
331
- l = l < size - bi ? l : size - bi ;
332
- strncpy (buffer + bi , v , l );
333
- bi += l ;
393
+ __fmtbuf_write_str (fmtbuf , v , l );
334
394
break ;
335
395
case 'c' :
336
396
/* append param pi as char */
337
- buffer [bi ] = v ;
338
- bi += 1 ;
397
+ __fmtbuf_write_char (fmtbuf , v );
339
398
break ;
340
399
case 'o' :
341
400
/* append param as octal */
342
- bi += __format (buffer + bi , v , w , zp , 8 , pp );
401
+ __format (fmtbuf , v , w , zp , 8 , pp );
343
402
break ;
344
403
case 'd' :
345
404
/* append param as decimal */
346
- bi += __format (buffer + bi , v , w , zp , 10 , 0 );
405
+ __format (fmtbuf , v , w , zp , 10 , 0 );
347
406
break ;
348
407
case 'x' :
349
408
/* append param as hex */
350
- bi += __format (buffer + bi , v , w , zp , 16 , pp );
409
+ __format (fmtbuf , v , w , zp , 16 , pp );
351
410
break ;
352
411
case '%' :
353
412
/* append literal '%' character */
354
- buffer [bi ] = '%' ;
355
- bi ++ ;
413
+ __fmtbuf_write_char (fmtbuf , '%' );
356
414
si ++ ;
357
415
continue ;
358
416
}
@@ -361,26 +419,43 @@ int __format_to_buf(char *buffer, char *format, int *var_args, int size)
361
419
}
362
420
}
363
421
364
- int len = size - 1 > bi ? bi : size - 1 ;
365
- buffer [ len ] = 0 ;
366
- return len ;
422
+ /* If n is still greater than 0, set the null character. */
423
+ if ( fmtbuf -> n )
424
+ fmtbuf -> buf [ 0 ] = 0 ;
367
425
}
368
426
369
427
int printf (char * str , ...)
370
428
{
371
429
char buffer [200 ];
372
- int len = __format_to_buf (buffer , str , & str + 4 , INT_MAX );
373
- return __syscall (__syscall_write , 1 , buffer , len );
430
+ fmtbuf_t fmtbuf ;
431
+
432
+ fmtbuf .buf = buffer ;
433
+ fmtbuf .n = INT_MAX ;
434
+ fmtbuf .len = 0 ;
435
+ __format_to_buf (& fmtbuf , str , & str + 4 );
436
+ return __syscall (__syscall_write , 1 , buffer , fmtbuf .len );
374
437
}
375
438
376
439
int sprintf (char * buffer , char * str , ...)
377
440
{
378
- return __format_to_buf (buffer , str , & str + 4 , INT_MAX );
441
+ fmtbuf_t fmtbuf ;
442
+
443
+ fmtbuf .buf = buffer ;
444
+ fmtbuf .n = INT_MAX ;
445
+ fmtbuf .len = 0 ;
446
+ __format_to_buf (& fmtbuf , str , & str + 4 );
447
+ return fmtbuf .len ;
379
448
}
380
449
381
450
int snprintf (char * buffer , int n , char * str , ...)
382
451
{
383
- return __format_to_buf (buffer , str , & str + 4 , n );
452
+ fmtbuf_t fmtbuf ;
453
+
454
+ fmtbuf .buf = buffer ;
455
+ fmtbuf .n = n ;
456
+ fmtbuf .len = 0 ;
457
+ __format_to_buf (& fmtbuf , str , & str + 4 );
458
+ return fmtbuf .len ;
384
459
}
385
460
386
461
int __free_all ();
0 commit comments