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 10KB

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