Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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