Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * doprnt.c - print formatted output
  3.  */
  4. /* $Header$ */
  5.  
  6. #include    "ctype.h"
  7. #include    "stdio.h"
  8. #include        <stdarg.h>
  9. #include        <string.h>
  10. #include        "loc_incl.h"
  11.  
  12. #define NOFLOAT
  13.  
  14. #define putc(c, p)  (--(p)->_count >= 0 ? \
  15.                     (int) (*(p)->_ptr++ = (c)) : EOF)
  16.  
  17. /* gnum() is used to get the width and precision fields of a format. */
  18. static const char *
  19. gnum(register const char *f, int *ip, va_list *app)
  20. {
  21.         register int    i, c;
  22.  
  23.         if (*f == '*') {
  24.                 *ip = va_arg((*app), int);
  25.                 f++;
  26.         } else {
  27.                 i = 0;
  28.                 while ((c = *f - '0') >= 0 && c <= 9) {
  29.                         i = i*10 + c;
  30.                         f++;
  31.                 }
  32.                 *ip = i;
  33.         }
  34.         return f;
  35. }
  36.  
  37. #if     _EM_WSIZE == _EM_PSIZE
  38. #define set_pointer(flags)                              /* nothing */
  39. #elif   _EM_LSIZE == _EM_PSIZE
  40. #define set_pointer(flags)      (flags |= FL_LONG)
  41. #else
  42. #error garbage pointer size
  43. #define set_pointer(flags)              /* compilation might continue */
  44. #endif
  45.  
  46. /* print an ordinal number */
  47. static char *
  48. o_print(va_list *ap, int flags, char *s, char c, int precision, int is_signed)
  49. {
  50.         long signed_val;
  51.         unsigned long unsigned_val;
  52.         char *old_s = s;
  53.         int base;
  54.  
  55.         switch (flags & (FL_SHORT | FL_LONG)) {
  56.         case FL_SHORT:
  57.                 if (is_signed) {
  58.                         signed_val = (short) va_arg(*ap, int);
  59.                 } else {
  60.                         unsigned_val = (unsigned short) va_arg(*ap, unsigned);
  61.                 }
  62.                 break;
  63.         case FL_LONG:
  64.                 if (is_signed) {
  65.                         signed_val = va_arg(*ap, long);
  66.                 } else {
  67.                         unsigned_val = va_arg(*ap, unsigned long);
  68.                 }
  69.                 break;
  70.         default:
  71.                 if (is_signed) {
  72.                         signed_val = va_arg(*ap, int);
  73.                 } else {
  74.                         unsigned_val = va_arg(*ap, unsigned int);
  75.                 }
  76.                 break;
  77.         }
  78.  
  79.         if (is_signed) {
  80.                 if (signed_val < 0) {
  81.                         *s++ = '-';
  82.                         signed_val = -signed_val;
  83.                 } else if (flags & FL_SIGN) *s++ = '+';
  84.                 else if (flags & FL_SPACE) *s++ = ' ';
  85.                 unsigned_val = signed_val;
  86.         }
  87.         if ((flags & FL_ALT) && (c == 'o')) *s++ = '0';
  88.         if (!unsigned_val && c != 'p') {
  89.                  if (!precision)
  90.                         return s;
  91.         } else if (((flags & FL_ALT) && (c == 'x' || c == 'X'))
  92.                     || c == 'p') {
  93.                 *s++ = '0';
  94.                 *s++ = (c == 'X' ? 'X' : 'x');
  95.         }
  96.  
  97.         switch (c) {
  98.         case 'b':       base = 2;       break;
  99.         case 'o':       base = 8;       break;
  100.         case 'd':
  101.         case 'i':
  102.         case 'u':       base = 10;      break;
  103.         case 'x':
  104.         case 'X':
  105.         case 'p':       base = 16;      break;
  106.         }
  107.  
  108.         s = _i_compute(unsigned_val, base, s, precision);
  109.  
  110.         if (c == 'X')
  111.                 while (old_s != s) {
  112.                         *old_s = toupper(*old_s);
  113.                         old_s++;
  114.                 }
  115.  
  116.         return s;
  117. }
  118.  
  119. int
  120. _doprnt(register const char *fmt, va_list ap, FILE *stream)
  121. {
  122.         register char   *s;
  123.         register int    j;
  124.         int             i, c, width, precision, zfill, flags, between_fill;
  125.         int             nrchars=0;
  126.         const char      *oldfmt;
  127.         char            *s1, buf[1025];
  128.  
  129.         while (c = *fmt++) {
  130.                 if (c != '%') {
  131. #ifdef  CPM
  132.                         if (c == '\n') {
  133.                                 if (putc('\r', stream) == EOF)
  134.                                         return nrchars ? -nrchars : -1;
  135.                                 nrchars++;
  136.                         }
  137. #endif
  138.                         if (putc(c, stream) == EOF)
  139.                                 return nrchars ? -nrchars : -1;
  140.                         nrchars++;
  141.                         continue;
  142.                 }
  143.                 flags = 0;
  144.                 do {
  145.                         switch(*fmt) {
  146.                         case '-':       flags |= FL_LJUST;      break;
  147.                         case '+':       flags |= FL_SIGN;       break;
  148.                         case ' ':       flags |= FL_SPACE;      break;
  149.                         case '#':       flags |= FL_ALT;        break;
  150.                         case '0':       flags |= FL_ZEROFILL;   break;
  151.                         default:        flags |= FL_NOMORE;     continue;
  152.                         }
  153.                         fmt++;
  154.                 } while(!(flags & FL_NOMORE));
  155.  
  156.                 oldfmt = fmt;
  157.                 fmt = gnum(fmt, &width, &ap);
  158.                 if (fmt != oldfmt) flags |= FL_WIDTHSPEC;
  159.  
  160.                 if (*fmt == '.') {
  161.                         fmt++; oldfmt = fmt;
  162.                         fmt = gnum(fmt, &precision, &ap);
  163.                         if (precision >= 0) flags |= FL_PRECSPEC;
  164.                 }
  165.  
  166.                 if ((flags & FL_WIDTHSPEC) && width < 0) {
  167.                         width = -width;
  168.                         flags |= FL_LJUST;
  169.                 }
  170.                 if (!(flags & FL_WIDTHSPEC)) width = 0;
  171.  
  172.                 if (flags & FL_SIGN) flags &= ~FL_SPACE;
  173.  
  174.                 if (flags & FL_LJUST) flags &= ~FL_ZEROFILL;
  175.  
  176.  
  177.                 s = s1 = buf;
  178.  
  179.                 switch (*fmt) {
  180.                 case 'h':       flags |= FL_SHORT; fmt++; break;
  181.                 case 'l':       flags |= FL_LONG; fmt++; break;
  182.                 case 'L':       flags |= FL_LONGDOUBLE; fmt++; break;
  183.                 }
  184.  
  185.                 switch (c = *fmt++) {
  186.                 default:
  187. #ifdef  CPM
  188.                         if (c == '\n') {
  189.                                 if (putc('\r', stream) == EOF)
  190.                                         return nrchars ? -nrchars : -1;
  191.                                 nrchars++;
  192.                         }
  193. #endif
  194.                         if (putc(c, stream) == EOF)
  195.                                 return nrchars ? -nrchars : -1;
  196.                         nrchars++;
  197.                         continue;
  198.                 case 'n':
  199.                         if (flags & FL_SHORT)
  200.                                 *va_arg(ap, short *) = (short) nrchars;
  201.                         else if (flags & FL_LONG)
  202.                                 *va_arg(ap, long *) = (long) nrchars;
  203.                         else
  204.                                 *va_arg(ap, int *) = (int) nrchars;
  205.                         continue;
  206.                 case 's':
  207.                         s1 = va_arg(ap, char *);
  208.                         if (s1 == NULL)
  209.                                 s1 = "(null)";
  210.                         s = s1;
  211.                         while (precision || !(flags & FL_PRECSPEC)) {
  212.                                 if (*s == '\0')
  213.                                         break;
  214.                                 s++;
  215.                                 precision--;
  216.                         }
  217.                         break;
  218.                 case 'p':
  219.                         set_pointer(flags);
  220.                         /* fallthrough */
  221.                 case 'b':
  222.                 case 'o':
  223.                 case 'u':
  224.                 case 'x':
  225.                 case 'X':
  226.                         if (!(flags & FL_PRECSPEC)) precision = 1;
  227.                         else if (c != 'p') flags &= ~FL_ZEROFILL;
  228.                         s = o_print(&ap, flags, s, c, precision, 0);
  229.                         break;
  230.                 case 'd':
  231.                 case 'i':
  232.                         flags |= FL_SIGNEDCONV;
  233.                         if (!(flags & FL_PRECSPEC)) precision = 1;
  234.                         else flags &= ~FL_ZEROFILL;
  235.                         s = o_print(&ap, flags, s, c, precision, 1);
  236.                         break;
  237.                 case 'c':
  238.                         *s++ = va_arg(ap, int);
  239.                         break;
  240. #ifndef NOFLOAT
  241.                 case 'G':
  242.                 case 'g':
  243.                         if ((flags & FL_PRECSPEC) && (precision == 0))
  244.                                 precision = 1;
  245.                 case 'f':
  246.                 case 'E':
  247.                 case 'e':
  248.                         if (!(flags & FL_PRECSPEC))
  249.                                 precision = 6;
  250.  
  251.                         if (precision >= sizeof(buf))
  252.                                 precision = sizeof(buf) - 1;
  253.  
  254.                         flags |= FL_SIGNEDCONV;
  255.                         s = _f_print(&ap, flags, s, c, precision);
  256.                         break;
  257. #endif  /* NOFLOAT */
  258.                 case 'r':
  259.                         ap = va_arg(ap, va_list);
  260.                         fmt = va_arg(ap, char *);
  261.                         continue;
  262.                 }
  263.                 zfill = ' ';
  264.                 if (flags & FL_ZEROFILL) zfill = '0';
  265.                 j = s - s1;
  266.  
  267.                 /* between_fill is true under the following conditions:
  268.                  * 1- the fill character is '0'
  269.                  * and
  270.                  * 2a- the number is of the form 0x... or 0X...
  271.                  * or
  272.                  * 2b- the number contains a sign or space
  273.                  */
  274.                 between_fill = 0;
  275.                 if ((flags & FL_ZEROFILL)
  276.                     && (((c == 'x' || c == 'X') && (flags & FL_ALT) && j > 1)
  277.                         || (c == 'p')
  278.                         || ((flags & FL_SIGNEDCONV)
  279.                             && ( *s1 == '+' || *s1 == '-' || *s1 == ' '))))
  280.                         between_fill++;
  281.  
  282.                 if ((i = width - j) > 0)
  283.                         if (!(flags & FL_LJUST)) {      /* right justify */
  284.                                 nrchars += i;
  285.                                 if (between_fill) {
  286.                                     if (flags & FL_SIGNEDCONV) {
  287.                                         j--; nrchars++;
  288.                                         if (putc(*s1++, stream) == EOF)
  289.                                                 return nrchars ? -nrchars : -1;
  290.                                     } else {
  291.                                         j -= 2; nrchars += 2;
  292.                                         if ((putc(*s1++, stream) == EOF)
  293.                                             || (putc(*s1++, stream) == EOF))
  294.                                                 return nrchars ? -nrchars : -1;
  295.                                     }
  296.                                 }
  297.                                 do {
  298.                                         if (putc(zfill, stream) == EOF)
  299.                                                 return nrchars ? -nrchars : -1;
  300.                                 } while (--i);
  301.                         }
  302.  
  303.                 nrchars += j;
  304.                 while (--j >= 0) {
  305.                         if (putc(*s1++, stream) == EOF)
  306.                                 return nrchars ? -nrchars : -1;
  307.                 }
  308.  
  309.                 if (i > 0) nrchars += i;
  310.                 while (--i >= 0)
  311.                         if (putc(zfill, stream) == EOF)
  312.                                 return nrchars ? -nrchars : -1;
  313.         }
  314.         return nrchars;
  315. }
  316.