_printf.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. #include "asmc_types.h"
  2. #include "stdint.h"
  3. #include "stdarg.h"
  4. #include "stdlib.h"
  5. #include "stddef.h"
  6. #include "string.h"
  7. #include "_digits.h"
  8. // All code in this file was taken from PDClib
  9. /* Status structure required by _print(). */
  10. struct _status_t
  11. {
  12. int base; /* base to which the value shall be converted */
  13. int_fast32_t flags; /* flags and length modifiers */
  14. size_t n; /* print: maximum characters to be written */
  15. /* scan: number matched conversion specifiers */
  16. size_t i; /* number of characters read/written */
  17. size_t current;/* chars read/written in the CURRENT conversion */
  18. char * s; /* *sprintf(): target buffer */
  19. /* *sscanf(): source string */
  20. size_t width; /* specified field width */
  21. int prec; /* specified field precision */
  22. FILE* stream; /* *fprintf() / *fscanf() stream */
  23. va_list arg; /* argument stack */
  24. };
  25. /* Using an integer's bits as flags for both the conversion flags and length
  26. modifiers.
  27. */
  28. /* FIXME: one too many flags to work on a 16-bit machine, join some (e.g. the
  29. width flags) into a combined field.
  30. */
  31. #define E_minus (1<<0)
  32. #define E_plus (1<<1)
  33. #define E_alt (1<<2)
  34. #define E_space (1<<3)
  35. #define E_zero (1<<4)
  36. #define E_done (1<<5)
  37. #define E_char (1<<6)
  38. #define E_short (1<<7)
  39. #define E_long (1<<8)
  40. #define E_llong (1<<9)
  41. #define E_intmax (1<<10)
  42. #define E_size (1<<11)
  43. #define E_ptrdiff (1<<12)
  44. #define E_pointer (1<<13)
  45. #define E_ldouble (1<<14)
  46. #define E_lower (1<<15)
  47. #define E_unsigned (1<<16)
  48. /* This macro delivers a given character to either a memory buffer or a stream,
  49. depending on the contents of 'status' (struct _status_t).
  50. x - the character to be delivered
  51. i - pointer to number of characters already delivered in this call
  52. n - pointer to maximum number of characters to be delivered in this call
  53. s - the buffer into which the character shall be delivered
  54. */
  55. #define PUT( x ) \
  56. do { \
  57. int character = x; \
  58. if ( status->i < status->n ) { \
  59. if ( status->stream != NULL ) \
  60. putc( character, status->stream ); \
  61. else \
  62. status->s[status->i] = character; \
  63. } \
  64. ++(status->i); \
  65. } while ( 0 )
  66. static void intformat( intmax_t value, struct _status_t * status )
  67. {
  68. /* At worst, we need two prefix characters (hex prefix). */
  69. char preface[3];
  70. memset(preface, 0, 3);
  71. size_t preidx = 0;
  72. if ( status->prec < 0 )
  73. {
  74. status->prec = 1;
  75. }
  76. if ( ( status->flags & E_alt ) && ( status->base == 16 || status->base == 8 ) && ( value != 0 ) )
  77. {
  78. /* Octal / hexadecimal prefix for "%#" conversions */
  79. preface[ preidx++ ] = '0';
  80. if ( status->base == 16 )
  81. {
  82. preface[ preidx++ ] = ( status->flags & E_lower ) ? 'x' : 'X';
  83. }
  84. }
  85. if ( value < 0 )
  86. {
  87. /* Negative sign for negative values - at all times. */
  88. preface[ preidx++ ] = '-';
  89. }
  90. else if ( ! ( status->flags & E_unsigned ) )
  91. {
  92. /* plus sign / extra space are only for unsigned conversions */
  93. if ( status->flags & E_plus )
  94. {
  95. preface[ preidx++ ] = '+';
  96. }
  97. else if ( status->flags & E_space )
  98. {
  99. preface[ preidx++ ] = ' ';
  100. }
  101. }
  102. {
  103. /* At this point, status->current has the number of digits queued up.
  104. Determine if we have a precision requirement to pad those.
  105. */
  106. size_t prec_pads = ( (size_t)status->prec > status->current ) ? ( (size_t)status->prec - status->current ) : 0;
  107. if ( ! ( status->flags & ( E_minus | E_zero ) ) )
  108. {
  109. /* Space padding is only done if no zero padding or left alignment
  110. is requested. Calculate the number of characters that WILL be
  111. printed, including any prefixes determined above.
  112. */
  113. /* The number of characters to be printed, plus prefixes if any. */
  114. /* This line contained probably the most stupid, time-wasting bug
  115. I've ever perpetrated. Greetings to Samface, DevL, and all
  116. sceners at Breakpoint 2006.
  117. */
  118. size_t characters = preidx + ( ( status->current > (size_t)status->prec ) ? status->current : (size_t)status->prec );
  119. if ( status->width > characters )
  120. {
  121. size_t i;
  122. for ( i = 0; i < status->width - characters; ++i )
  123. {
  124. PUT( ' ' );
  125. ++(status->current);
  126. }
  127. }
  128. }
  129. /* Now we did the padding, do the prefixes (if any). */
  130. preidx = 0;
  131. while ( preface[ preidx ] != '\0' )
  132. {
  133. PUT( preface[ preidx++ ] );
  134. ++(status->current);
  135. }
  136. /* Do the precision padding if necessary. */
  137. while ( prec_pads-- > 0 )
  138. {
  139. PUT( '0' );
  140. ++(status->current);
  141. }
  142. if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) )
  143. {
  144. /* If field is not left aligned, and zero padding is requested, do
  145. so.
  146. */
  147. while ( status->current < status->width )
  148. {
  149. PUT( '0' );
  150. ++(status->current);
  151. }
  152. }
  153. }
  154. }
  155. /* This function recursively converts a given integer value to a character
  156. stream. The conversion is done under the control of a given status struct
  157. and written either to a character string or a stream, depending on that
  158. same status struct. The status struct also keeps the function from exceeding
  159. snprintf() limits, and enables any necessary padding / prefixing of the
  160. output once the number of characters to be printed is known, which happens
  161. at the lowermost recursion level.
  162. */
  163. #define INT2BASE() \
  164. do \
  165. { \
  166. /* Special case: zero value, zero precision -- no output (but padding) */ \
  167. if ( status->current == 0 && value == 0 && status->prec == 0 ) \
  168. { \
  169. intformat( value, status ); \
  170. } \
  171. else \
  172. { \
  173. /* Registering the character being printed at the end of the function here \
  174. already so it will be taken into account when the deepestmost recursion \
  175. does the prefix / padding stuff. \
  176. */ \
  177. ++(status->current); \
  178. if ( ( value / status->base ) != 0 ) \
  179. { \
  180. /* More digits to be done - recurse deeper */ \
  181. int2base( value / status->base, status ); \
  182. } \
  183. else \
  184. { \
  185. /* We reached the last digit, the deepest point of our recursion, and \
  186. only now know how long the number to be printed actually is. Now we \
  187. have to do the sign, prefix, width, and precision padding stuff \
  188. before printing the numbers while we resurface from the recursion. \
  189. */ \
  190. intformat( value, status ); \
  191. } \
  192. /* Recursion tail - print the current digit. */ \
  193. { \
  194. int digit = value % status->base; \
  195. if ( digit < 0 ) \
  196. { \
  197. digit *= -1; \
  198. } \
  199. if ( status->flags & E_lower ) \
  200. { \
  201. /* Lowercase letters. Same array used for strto...(). */ \
  202. PUT( _digits[ digit ] ); \
  203. } \
  204. else \
  205. { \
  206. /* Uppercase letters. Array only used here, only 0-F. */ \
  207. PUT( _Xdigits[ digit ] ); \
  208. } \
  209. } \
  210. } \
  211. } while ( 0 )
  212. static void int2base( intmax_t value, struct _status_t * status )
  213. {
  214. INT2BASE();
  215. }
  216. static void stringformat( const char * s, struct _status_t * status )
  217. {
  218. if ( status->flags & E_char )
  219. {
  220. status->prec = 1;
  221. }
  222. else
  223. {
  224. if ( status->prec < 0 )
  225. {
  226. status->prec = strlen( s );
  227. }
  228. else
  229. {
  230. int i;
  231. for ( i = 0; i < status->prec; ++i )
  232. {
  233. if ( s[i] == 0 )
  234. {
  235. status->prec = i;
  236. break;
  237. }
  238. }
  239. }
  240. }
  241. if ( ! ( status->flags & E_minus ) && ( status->width > (size_t)status->prec ) )
  242. {
  243. while ( status->current < ( status->width - status->prec ) )
  244. {
  245. PUT( ' ' );
  246. ++(status->current);
  247. }
  248. }
  249. while ( status->prec > 0 )
  250. {
  251. PUT( *(s++) );
  252. --(status->prec);
  253. ++(status->current);
  254. }
  255. if ( status->flags & E_minus )
  256. {
  257. while ( status->width > status->current )
  258. {
  259. PUT( ' ' );
  260. ++(status->current);
  261. }
  262. }
  263. }
  264. const char * _print( const char * spec, struct _status_t * status )
  265. {
  266. const char * orig_spec = spec;
  267. if ( *(++spec) == '%' )
  268. {
  269. /* %% -> print single '%' */
  270. PUT( *spec );
  271. return ++spec;
  272. }
  273. /* Initializing status structure */
  274. status->flags = 0;
  275. status->base = 0;
  276. status->current = 0;
  277. status->width = 0;
  278. status->prec = EOF;
  279. /* First come 0..n flags */
  280. do
  281. {
  282. switch ( *spec )
  283. {
  284. case '-':
  285. /* left-aligned output */
  286. status->flags |= E_minus;
  287. ++spec;
  288. break;
  289. case '+':
  290. /* positive numbers prefixed with '+' */
  291. status->flags |= E_plus;
  292. ++spec;
  293. break;
  294. case '#':
  295. /* alternative format (leading 0x for hex, 0 for octal) */
  296. status->flags |= E_alt;
  297. ++spec;
  298. break;
  299. case ' ':
  300. /* positive numbers prefixed with ' ' */
  301. status->flags |= E_space;
  302. ++spec;
  303. break;
  304. case '0':
  305. /* right-aligned padding done with '0' instead of ' ' */
  306. status->flags |= E_zero;
  307. ++spec;
  308. break;
  309. default:
  310. /* not a flag, exit flag parsing */
  311. status->flags |= E_done;
  312. break;
  313. }
  314. } while ( ! ( status->flags & E_done ) );
  315. /* Optional field width */
  316. if ( *spec == '*' )
  317. {
  318. /* Retrieve width value from argument stack */
  319. int width = va_arg( status->arg, int );
  320. if ( width < 0 )
  321. {
  322. status->flags |= E_minus;
  323. status->width = abs( width );
  324. }
  325. else
  326. {
  327. status->width = width;
  328. }
  329. ++spec;
  330. }
  331. else
  332. {
  333. /* If a width is given, strtol() will return its value. If not given,
  334. strtol() will return zero. In both cases, endptr will point to the
  335. rest of the conversion specifier - just what we need.
  336. */
  337. status->width = (int)strtol( spec, (char**)&spec, 10 );
  338. }
  339. /* Optional precision */
  340. if ( *spec == '.' )
  341. {
  342. ++spec;
  343. if ( *spec == '*' )
  344. {
  345. /* Retrieve precision value from argument stack. A negative value
  346. is as if no precision is given - as precision is initalized to
  347. EOF (negative), there is no need for testing for negative here.
  348. */
  349. status->prec = va_arg( status->arg, int );
  350. ++spec;
  351. }
  352. else
  353. {
  354. char * endptr;
  355. status->prec = (int)strtol( spec, &endptr, 10 );
  356. if ( spec == endptr )
  357. {
  358. /* Decimal point but no number - equals zero */
  359. status->prec = 0;
  360. }
  361. spec = endptr;
  362. }
  363. /* Having a precision cancels out any zero flag. */
  364. status->flags &= ~E_zero;
  365. }
  366. /* Optional length modifier
  367. We step one character ahead in any case, and step back only if we find
  368. there has been no length modifier (or step ahead another character if it
  369. has been "hh" or "ll").
  370. */
  371. switch ( *(spec++) )
  372. {
  373. case 'h':
  374. if ( *spec == 'h' )
  375. {
  376. /* hh -> char */
  377. status->flags |= E_char;
  378. ++spec;
  379. }
  380. else
  381. {
  382. /* h -> short */
  383. status->flags |= E_short;
  384. }
  385. break;
  386. case 'l':
  387. if ( *spec == 'l' )
  388. {
  389. /* ll -> long long */
  390. status->flags |= E_llong;
  391. ++spec;
  392. }
  393. else
  394. {
  395. /* k -> long */
  396. status->flags |= E_long;
  397. }
  398. break;
  399. case 'j':
  400. /* j -> intmax_t, which might or might not be long long */
  401. status->flags |= E_intmax;
  402. break;
  403. case 'z':
  404. /* z -> size_t, which might or might not be unsigned int */
  405. status->flags |= E_size;
  406. break;
  407. case 't':
  408. /* t -> ptrdiff_t, which might or might not be long */
  409. status->flags |= E_ptrdiff;
  410. break;
  411. case 'L':
  412. /* L -> long double */
  413. status->flags |= E_ldouble;
  414. break;
  415. default:
  416. --spec;
  417. break;
  418. }
  419. /* Conversion specifier */
  420. switch ( *spec )
  421. {
  422. case 'd':
  423. /* FALLTHROUGH */
  424. case 'i':
  425. status->base = 10;
  426. break;
  427. case 'o':
  428. status->base = 8;
  429. status->flags |= E_unsigned;
  430. break;
  431. case 'u':
  432. status->base = 10;
  433. status->flags |= E_unsigned;
  434. break;
  435. case 'x':
  436. status->base = 16;
  437. status->flags |= ( E_lower | E_unsigned );
  438. break;
  439. case 'X':
  440. status->base = 16;
  441. status->flags |= E_unsigned;
  442. break;
  443. case 'f':
  444. case 'F':
  445. case 'e':
  446. case 'E':
  447. case 'g':
  448. case 'G':
  449. break;
  450. case 'a':
  451. case 'A':
  452. break;
  453. case 'c':
  454. /* TODO: wide chars. */
  455. {
  456. char c[1];
  457. c[0] = (char)va_arg( status->arg, int );
  458. status->flags |= E_char;
  459. stringformat( c, status );
  460. return ++spec;
  461. }
  462. case 's':
  463. /* TODO: wide chars. */
  464. stringformat( va_arg( status->arg, char * ), status );
  465. return ++spec;
  466. case 'p':
  467. status->base = 16;
  468. status->flags |= ( E_lower | E_unsigned | E_alt | E_pointer );
  469. break;
  470. case 'n':
  471. {
  472. int * val = va_arg( status->arg, int * );
  473. *val = status->i;
  474. return ++spec;
  475. }
  476. default:
  477. /* No conversion specifier. Bad conversion. */
  478. return orig_spec;
  479. }
  480. /* Do the actual output based on our findings */
  481. if ( status->base != 0 )
  482. {
  483. /* Integer conversions */
  484. /* TODO: Check for invalid flag combinations. */
  485. if ( status->flags & E_unsigned )
  486. {
  487. uintmax_t value;
  488. switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_size | E_pointer | E_intmax ) )
  489. {
  490. case E_char:
  491. value = (uintmax_t)(unsigned char)va_arg( status->arg, int );
  492. break;
  493. case E_short:
  494. value = (uintmax_t)(unsigned short)va_arg( status->arg, int );
  495. break;
  496. case 0:
  497. value = (uintmax_t)va_arg( status->arg, unsigned int );
  498. break;
  499. case E_long:
  500. value = (uintmax_t)va_arg( status->arg, unsigned long );
  501. break;
  502. case E_llong:
  503. value = (uintmax_t)va_arg( status->arg, unsigned long long );
  504. break;
  505. case E_size:
  506. value = (uintmax_t)va_arg( status->arg, size_t );
  507. break;
  508. case E_pointer:
  509. value = (uintmax_t)(uintptr_t)va_arg( status->arg, void * );
  510. break;
  511. case E_intmax:
  512. value = va_arg( status->arg, uintmax_t );
  513. break;
  514. default:
  515. puts( "UNSUPPORTED PRINTF FLAG COMBINATION" );
  516. return NULL;
  517. }
  518. INT2BASE();
  519. }
  520. else
  521. {
  522. intmax_t value;
  523. switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_intmax ) )
  524. {
  525. case E_char:
  526. value = (intmax_t)(char)va_arg( status->arg, int );
  527. break;
  528. case E_short:
  529. value = (intmax_t)(short)va_arg( status->arg, int );
  530. break;
  531. case 0:
  532. value = (intmax_t)va_arg( status->arg, int );
  533. break;
  534. case E_long:
  535. value = (intmax_t)va_arg( status->arg, long );
  536. break;
  537. case E_llong:
  538. value = (intmax_t)va_arg( status->arg, long long );
  539. break;
  540. case E_ptrdiff:
  541. value = (intmax_t)va_arg( status->arg, ptrdiff_t );
  542. break;
  543. case E_intmax:
  544. value = va_arg( status->arg, intmax_t );
  545. break;
  546. default:
  547. puts( "UNSUPPORTED PRINTF FLAG COMBINATION" );
  548. return NULL;
  549. }
  550. INT2BASE();
  551. }
  552. if ( status->flags & E_minus )
  553. {
  554. while ( status->current < status->width )
  555. {
  556. PUT( ' ' );
  557. ++(status->current);
  558. }
  559. }
  560. if ( status->i >= status->n && status->n > 0 )
  561. {
  562. status->s[status->n - 1] = '\0';
  563. }
  564. }
  565. return ++spec;
  566. }
  567. int vfprintf( FILE *stream, const char * format, va_list arg )
  568. {
  569. /* TODO: This function should interpret format as multibyte characters. */
  570. struct _status_t status;
  571. status.base = 0;
  572. status.flags = 0;
  573. status.n = SIZE_MAX;
  574. status.i = 0;
  575. status.current = 0;
  576. status.s = NULL;
  577. status.width = 0;
  578. status.prec = EOF;
  579. status.stream = stream;
  580. va_copy( status.arg, arg );
  581. while ( *format != '\0' )
  582. {
  583. const char * rc;
  584. if ( ( *format != '%' ) || ( ( rc = _print( format, &status ) ) == format ) )
  585. {
  586. /* No conversion specifier, print verbatim */
  587. putc( *(format++), stream );
  588. status.i++;
  589. }
  590. else
  591. {
  592. /* Continue parsing after conversion specifier */
  593. format = rc;
  594. }
  595. }
  596. va_end( status.arg );
  597. return status.i;
  598. }
  599. int fprintf( FILE* stream, const char * format, ... )
  600. {
  601. int rc;
  602. va_list ap;
  603. va_start( ap, format );
  604. rc = vfprintf( stream, format, ap );
  605. va_end( ap );
  606. return rc;
  607. }
  608. int printf( const char * format, ... )
  609. {
  610. int rc;
  611. va_list ap;
  612. va_start( ap, format );
  613. rc = vfprintf( stdout, format, ap );
  614. va_end( ap );
  615. return rc;
  616. }
  617. int vsnprintf( char * s, size_t n, const char * format, va_list arg )
  618. {
  619. /* TODO: This function should interpret format as multibyte characters. */
  620. struct _status_t status;
  621. status.base = 0;
  622. status.flags = 0;
  623. status.n = n;
  624. status.i = 0;
  625. status.current = 0;
  626. status.s = s;
  627. status.width = 0;
  628. status.prec = EOF;
  629. status.stream = NULL;
  630. va_copy( status.arg, arg );
  631. while ( *format != '\0' )
  632. {
  633. const char * rc;
  634. if ( ( *format != '%' ) || ( ( rc = _print( format, &status ) ) == format ) )
  635. {
  636. /* No conversion specifier, print verbatim */
  637. if ( status.i < n )
  638. {
  639. s[ status.i ] = *format;
  640. }
  641. status.i++;
  642. format++;
  643. }
  644. else
  645. {
  646. /* Continue parsing after conversion specifier */
  647. format = rc;
  648. }
  649. }
  650. if ( status.i < n )
  651. {
  652. s[ status.i ] = '\0';
  653. }
  654. va_end( status.arg );
  655. return status.i;
  656. }
  657. int vsprintf( char * s, const char * format, va_list arg )
  658. {
  659. return vsnprintf( s, SIZE_MAX, format, arg ); /* TODO: Replace with a non-checking call */
  660. }
  661. int snprintf( char * s, size_t n, const char * format, ...)
  662. {
  663. int rc;
  664. va_list ap;
  665. va_start( ap, format );
  666. rc = vsnprintf( s, n, format, ap );
  667. va_end( ap );
  668. return rc;
  669. }
  670. int sprintf( char * s, const char * format, ...)
  671. {
  672. int rc;
  673. va_list ap;
  674. va_start( ap, format );
  675. rc = vsnprintf( s, SIZE_MAX, format, ap ); /* TODO: replace with non-checking call */
  676. va_end( ap );
  677. return rc;
  678. }
  679. #undef E_minus
  680. #undef E_plus
  681. #undef E_alt
  682. #undef E_space
  683. #undef E_zero
  684. #undef E_done
  685. #undef E_char
  686. #undef E_short
  687. #undef E_long
  688. #undef E_llong
  689. #undef E_intmax
  690. #undef E_size
  691. #undef E_ptrdiff
  692. #undef E_pointer
  693. #undef E_ldouble
  694. #undef E_lower
  695. #undef E_unsigned