Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

vsprintf.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /*
  2. * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. *
  19. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <stddef.h>
  25. #include <stdarg.h>
  26. #include <stdio.h>
  27. #include <errno.h>
  28. #include <wchar.h>
  29. #include <ipxe/vsprintf.h>
  30. /** @file */
  31. #define CHAR_LEN 0 /**< "hh" length modifier */
  32. #define SHORT_LEN 1 /**< "h" length modifier */
  33. #define INT_LEN 2 /**< no length modifier */
  34. #define LONG_LEN 3 /**< "l" length modifier */
  35. #define LONGLONG_LEN 4 /**< "ll" length modifier */
  36. #define SIZE_T_LEN 5 /**< "z" length modifier */
  37. static uint8_t type_sizes[] = {
  38. [CHAR_LEN] = sizeof ( char ),
  39. [SHORT_LEN] = sizeof ( short ),
  40. [INT_LEN] = sizeof ( int ),
  41. [LONG_LEN] = sizeof ( long ),
  42. [LONGLONG_LEN] = sizeof ( long long ),
  43. [SIZE_T_LEN] = sizeof ( size_t ),
  44. };
  45. /**
  46. * Use lower-case for hexadecimal digits
  47. *
  48. * Note that this value is set to 0x20 since that makes for very
  49. * efficient calculations. (Bitwise-ORing with @c LCASE converts to a
  50. * lower-case character, for example.)
  51. */
  52. #define LCASE 0x20
  53. /**
  54. * Use "alternate form"
  55. *
  56. * For hexadecimal numbers, this means to add a "0x" or "0X" prefix to
  57. * the number.
  58. */
  59. #define ALT_FORM 0x02
  60. /**
  61. * Use zero padding
  62. *
  63. * Note that this value is set to 0x10 since that allows the pad
  64. * character to be calculated as @c 0x20|(flags&ZPAD)
  65. */
  66. #define ZPAD 0x10
  67. /**
  68. * Format a hexadecimal number
  69. *
  70. * @v end End of buffer to contain number
  71. * @v num Number to format
  72. * @v width Minimum field width
  73. * @v flags Format flags
  74. * @ret ptr End of buffer
  75. *
  76. * Fills a buffer in reverse order with a formatted hexadecimal
  77. * number. The number will be zero-padded to the specified width.
  78. * Lower-case and "alternate form" (i.e. "0x" prefix) flags may be
  79. * set.
  80. *
  81. * There must be enough space in the buffer to contain the largest
  82. * number that this function can format.
  83. */
  84. static char * format_hex ( char *end, unsigned long long num, int width,
  85. int flags ) {
  86. char *ptr = end;
  87. int case_mod = ( flags & LCASE );
  88. int pad = ( ( flags & ZPAD ) | ' ' );
  89. /* Generate the number */
  90. do {
  91. *(--ptr) = "0123456789ABCDEF"[ num & 0xf ] | case_mod;
  92. num >>= 4;
  93. } while ( num );
  94. /* Pad to width */
  95. while ( ( end - ptr ) < width )
  96. *(--ptr) = pad;
  97. /* Add "0x" or "0X" if alternate form specified */
  98. if ( flags & ALT_FORM ) {
  99. *(--ptr) = 'X' | case_mod;
  100. *(--ptr) = '0';
  101. }
  102. return ptr;
  103. }
  104. /**
  105. * Format a decimal number
  106. *
  107. * @v end End of buffer to contain number
  108. * @v num Number to format
  109. * @v width Minimum field width
  110. * @v flags Format flags
  111. * @ret ptr End of buffer
  112. *
  113. * Fills a buffer in reverse order with a formatted decimal number.
  114. * The number will be space-padded to the specified width.
  115. *
  116. * There must be enough space in the buffer to contain the largest
  117. * number that this function can format.
  118. */
  119. static char * format_decimal ( char *end, signed long num, int width,
  120. int flags ) {
  121. char *ptr = end;
  122. int negative = 0;
  123. int zpad = ( flags & ZPAD );
  124. int pad = ( zpad | ' ' );
  125. /* Generate the number */
  126. if ( num < 0 ) {
  127. negative = 1;
  128. num = -num;
  129. }
  130. do {
  131. *(--ptr) = '0' + ( num % 10 );
  132. num /= 10;
  133. } while ( num );
  134. /* Add "-" if necessary */
  135. if ( negative && ( ! zpad ) )
  136. *(--ptr) = '-';
  137. /* Pad to width */
  138. while ( ( end - ptr ) < width )
  139. *(--ptr) = pad;
  140. /* Add "-" if necessary */
  141. if ( negative && zpad )
  142. *ptr = '-';
  143. return ptr;
  144. }
  145. /**
  146. * Print character via a printf context
  147. *
  148. * @v ctx Context
  149. * @v c Character
  150. *
  151. * Call's the printf_context::handler() method and increments
  152. * printf_context::len.
  153. */
  154. static inline void cputchar ( struct printf_context *ctx, unsigned char c ) {
  155. ctx->handler ( ctx, c );
  156. ++ctx->len;
  157. }
  158. /**
  159. * Write a formatted string to a printf context
  160. *
  161. * @v ctx Context
  162. * @v fmt Format string
  163. * @v args Arguments corresponding to the format string
  164. * @ret len Length of formatted string
  165. */
  166. size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
  167. int flags;
  168. int width;
  169. uint8_t *length;
  170. char *ptr;
  171. char tmp_buf[32]; /* 32 is enough for all numerical formats.
  172. * Insane width fields could overflow this buffer. */
  173. wchar_t *wptr;
  174. /* Initialise context */
  175. ctx->len = 0;
  176. for ( ; *fmt ; fmt++ ) {
  177. /* Pass through ordinary characters */
  178. if ( *fmt != '%' ) {
  179. cputchar ( ctx, *fmt );
  180. continue;
  181. }
  182. fmt++;
  183. /* Process flag characters */
  184. flags = 0;
  185. for ( ; ; fmt++ ) {
  186. if ( *fmt == '#' ) {
  187. flags |= ALT_FORM;
  188. } else if ( *fmt == '0' ) {
  189. flags |= ZPAD;
  190. } else {
  191. /* End of flag characters */
  192. break;
  193. }
  194. }
  195. /* Process field width */
  196. width = 0;
  197. for ( ; ; fmt++ ) {
  198. if ( ( ( unsigned ) ( *fmt - '0' ) ) < 10 ) {
  199. width = ( width * 10 ) + ( *fmt - '0' );
  200. } else {
  201. break;
  202. }
  203. }
  204. /* We don't do floating point */
  205. /* Process length modifier */
  206. length = &type_sizes[INT_LEN];
  207. for ( ; ; fmt++ ) {
  208. if ( *fmt == 'h' ) {
  209. length--;
  210. } else if ( *fmt == 'l' ) {
  211. length++;
  212. } else if ( *fmt == 'z' ) {
  213. length = &type_sizes[SIZE_T_LEN];
  214. } else {
  215. break;
  216. }
  217. }
  218. /* Process conversion specifier */
  219. ptr = tmp_buf + sizeof ( tmp_buf ) - 1;
  220. *ptr = '\0';
  221. wptr = NULL;
  222. if ( *fmt == 'c' ) {
  223. if ( length < &type_sizes[LONG_LEN] ) {
  224. cputchar ( ctx, va_arg ( args, unsigned int ) );
  225. } else {
  226. wchar_t wc;
  227. size_t len;
  228. wc = va_arg ( args, wint_t );
  229. len = wcrtomb ( tmp_buf, wc, NULL );
  230. tmp_buf[len] = '\0';
  231. ptr = tmp_buf;
  232. }
  233. } else if ( *fmt == 's' ) {
  234. if ( length < &type_sizes[LONG_LEN] ) {
  235. ptr = va_arg ( args, char * );
  236. } else {
  237. wptr = va_arg ( args, wchar_t * );
  238. }
  239. if ( ( ptr == NULL ) && ( wptr == NULL ) )
  240. ptr = "<NULL>";
  241. } else if ( *fmt == 'p' ) {
  242. intptr_t ptrval;
  243. ptrval = ( intptr_t ) va_arg ( args, void * );
  244. ptr = format_hex ( ptr, ptrval, width,
  245. ( ALT_FORM | LCASE ) );
  246. } else if ( ( *fmt & ~0x20 ) == 'X' ) {
  247. unsigned long long hex;
  248. flags |= ( *fmt & 0x20 ); /* LCASE */
  249. if ( *length >= sizeof ( unsigned long long ) ) {
  250. hex = va_arg ( args, unsigned long long );
  251. } else if ( *length >= sizeof ( unsigned long ) ) {
  252. hex = va_arg ( args, unsigned long );
  253. } else {
  254. hex = va_arg ( args, unsigned int );
  255. }
  256. ptr = format_hex ( ptr, hex, width, flags );
  257. } else if ( ( *fmt == 'd' ) || ( *fmt == 'i' ) ){
  258. signed long decimal;
  259. if ( *length >= sizeof ( signed long ) ) {
  260. decimal = va_arg ( args, signed long );
  261. } else {
  262. decimal = va_arg ( args, signed int );
  263. }
  264. ptr = format_decimal ( ptr, decimal, width, flags );
  265. } else {
  266. *(--ptr) = *fmt;
  267. }
  268. /* Write out conversion result */
  269. if ( wptr == NULL ) {
  270. for ( ; *ptr ; ptr++ ) {
  271. cputchar ( ctx, *ptr );
  272. }
  273. } else {
  274. for ( ; *wptr ; wptr++ ) {
  275. size_t len = wcrtomb ( tmp_buf, *wptr, NULL );
  276. for ( ptr = tmp_buf ; len-- ; ptr++ ) {
  277. cputchar ( ctx, *ptr );
  278. }
  279. }
  280. }
  281. }
  282. return ctx->len;
  283. }
  284. /** Context used by vsnprintf() and friends */
  285. struct sputc_context {
  286. struct printf_context ctx;
  287. /** Buffer for formatted string (used by printf_sputc()) */
  288. char *buf;
  289. /** Buffer length (used by printf_sputc()) */
  290. size_t max_len;
  291. };
  292. /**
  293. * Write character to buffer
  294. *
  295. * @v ctx Context
  296. * @v c Character
  297. */
  298. static void printf_sputc ( struct printf_context *ctx, unsigned int c ) {
  299. struct sputc_context * sctx =
  300. container_of ( ctx, struct sputc_context, ctx );
  301. if ( ctx->len < sctx->max_len )
  302. sctx->buf[ctx->len] = c;
  303. }
  304. /**
  305. * Write a formatted string to a buffer
  306. *
  307. * @v buf Buffer into which to write the string
  308. * @v size Size of buffer
  309. * @v fmt Format string
  310. * @v args Arguments corresponding to the format string
  311. * @ret len Length of formatted string
  312. *
  313. * If the buffer is too small to contain the string, the returned
  314. * length is the length that would have been written had enough space
  315. * been available.
  316. */
  317. int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ) {
  318. struct sputc_context sctx;
  319. size_t len;
  320. size_t end;
  321. /* Hand off to vcprintf */
  322. sctx.ctx.handler = printf_sputc;
  323. sctx.buf = buf;
  324. sctx.max_len = size;
  325. len = vcprintf ( &sctx.ctx, fmt, args );
  326. /* Add trailing NUL */
  327. if ( size ) {
  328. end = size - 1;
  329. if ( len < end )
  330. end = len;
  331. buf[end] = '\0';
  332. }
  333. return len;
  334. }
  335. /**
  336. * Write a formatted string to a buffer
  337. *
  338. * @v buf Buffer into which to write the string
  339. * @v size Size of buffer
  340. * @v fmt Format string
  341. * @v ... Arguments corresponding to the format string
  342. * @ret len Length of formatted string
  343. */
  344. int snprintf ( char *buf, size_t size, const char *fmt, ... ) {
  345. va_list args;
  346. int i;
  347. va_start ( args, fmt );
  348. i = vsnprintf ( buf, size, fmt, args );
  349. va_end ( args );
  350. return i;
  351. }
  352. /**
  353. * Version of vsnprintf() that accepts a signed buffer size
  354. *
  355. * @v buf Buffer into which to write the string
  356. * @v size Size of buffer
  357. * @v fmt Format string
  358. * @v args Arguments corresponding to the format string
  359. * @ret len Length of formatted string
  360. */
  361. int vssnprintf ( char *buf, ssize_t ssize, const char *fmt, va_list args ) {
  362. /* Treat negative buffer size as zero buffer size */
  363. if ( ssize < 0 )
  364. ssize = 0;
  365. /* Hand off to vsnprintf */
  366. return vsnprintf ( buf, ssize, fmt, args );
  367. }
  368. /**
  369. * Version of vsnprintf() that accepts a signed buffer size
  370. *
  371. * @v buf Buffer into which to write the string
  372. * @v size Size of buffer
  373. * @v fmt Format string
  374. * @v ... Arguments corresponding to the format string
  375. * @ret len Length of formatted string
  376. */
  377. int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) {
  378. va_list args;
  379. int len;
  380. /* Hand off to vssnprintf */
  381. va_start ( args, fmt );
  382. len = vssnprintf ( buf, ssize, fmt, args );
  383. va_end ( args );
  384. return len;
  385. }
  386. /**
  387. * Write character to console
  388. *
  389. * @v ctx Context
  390. * @v c Character
  391. */
  392. static void printf_putchar ( struct printf_context *ctx __unused,
  393. unsigned int c ) {
  394. putchar ( c );
  395. }
  396. /**
  397. * Write a formatted string to the console
  398. *
  399. * @v fmt Format string
  400. * @v args Arguments corresponding to the format string
  401. * @ret len Length of formatted string
  402. */
  403. int vprintf ( const char *fmt, va_list args ) {
  404. struct printf_context ctx;
  405. /* Hand off to vcprintf */
  406. ctx.handler = printf_putchar;
  407. return vcprintf ( &ctx, fmt, args );
  408. }
  409. /**
  410. * Write a formatted string to the console.
  411. *
  412. * @v fmt Format string
  413. * @v ... Arguments corresponding to the format string
  414. * @ret len Length of formatted string
  415. */
  416. int printf ( const char *fmt, ... ) {
  417. va_list args;
  418. int i;
  419. va_start ( args, fmt );
  420. i = vprintf ( fmt, args );
  421. va_end ( args );
  422. return i;
  423. }