home *** CD-ROM | disk | FTP | other *** search
/ linuxmafia.com 2016 / linuxmafia.com.tar / linuxmafia.com / pub / linux / backup / star-1.3.1.tar.gz / star-1.3.1.tar / star-1.3.1 / lib / format.c < prev    next >
C/C++ Source or Header  |  2001-02-26  |  18KB  |  895 lines

  1. /* @(#)format.c    1.35 01/02/26 Copyright 1985 J. Schilling */
  2. /*
  3.  *    format
  4.  *    common code for printf fprintf & sprintf
  5.  *
  6.  *    allows recursive printf with "%r", used in:
  7.  *    error, comerr, comerrno, errmsg, errmsgno and the like
  8.  *
  9.  *    Copyright (c) 1985 J. Schilling
  10.  */
  11. /*
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2, or (at your option)
  15.  * any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; see the file COPYING.  If not, write to
  24.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  */
  26.  
  27. #include <mconfig.h>
  28. #include <vadefs.h>
  29. #include <strdefs.h>
  30. #include <stdxlib.h>
  31. #if    !defined(HAVE_STDLIB_H) || !defined(HAVE_GCVT)
  32. extern    char    *gcvt __PR((double, int, char *));
  33. #endif
  34. #include <standard.h>
  35. #include <utypes.h>
  36. #include <schily.h>
  37.  
  38. /*
  39.  * As Llong is currently a 'best effort' long long, we usually need to
  40.  * include long long print formats.
  41.  * This may go away, if we implement maxint_t formats.
  42.  */
  43. #define    USE_LONGLONG
  44.  
  45. #ifdef    NO_LONGLONG
  46. #undef    USE_LONGLONG
  47. #endif
  48.  
  49. /*
  50.  * Some CPU's (e.g. PDP-11) cannot do logical shifts.
  51.  * They use rotate instead. Masking the low bits before,
  52.  * makes rotate work too.
  53.  */
  54. #define    allmask(t)    ((unsigned t)~((unsigned t)0))
  55. #define    lowmask(t, x)    ((unsigned t)~((unsigned t)((1 << (x))-1) ))
  56. #define    rshiftmask(t, s)((allmask(t) & lowmask(t, s)) >> (s))
  57.  
  58. #define    CHARMASK    makemask(char)
  59. #define    SHORTMASK    makemask(short)
  60. #define    INTMASK        makemask(int)
  61. #define    LONGMASK    makemask(long)
  62.  
  63. #ifdef    DIVLBYS
  64. extern    long    divlbys();
  65. extern    long    modlbys();
  66. #else
  67. #define    divlbys(val, base)    ((val)/(base))
  68. #define    modlbys(val, base)    ((val)%(base))
  69. #endif
  70.  
  71. /*
  72.  *    We use macros here to avoid the need to link to the international
  73.  *    character routines.
  74.  *    We don't need internationalization for our purpose.
  75.  */
  76. #define    is_dig(c)    (((c) >= '0') && ((c) <= '9'))
  77. #define    is_cap(c)    ((c) >= 'A' && (c) <= 'Z')
  78. #define    to_cap(c)    (is_cap(c) ? c : c - 'a' + 'A')
  79. #define    cap_ty(c)    (is_cap(c) ? 'L' : 'I')
  80.  
  81. #ifdef    HAVE_LONGLONG
  82. typedef union {
  83.     Ullong    ll;
  84.     Ulong    l[2];
  85.     char    c[8];
  86. } quad_u;
  87. #endif
  88.  
  89. typedef struct f_args {
  90.     void  (*outf)__PR((char,long));    /* Func from format(fun, arg)    */
  91.     long    farg;            /* Arg from format (fun, arg)    */
  92.     int    minusflag;        /* Fieldwidth is negative    */
  93.     int    flags;            /* General flags (+-#)        */
  94.     int    fldwidth;        /* Field width as in %3d    */
  95.     int    signific;        /* Significant chars as in %.4d    */
  96.     int    lzero;            /* Left '0' pad flag        */
  97.     char    *buf;            /* Out print buffer        */
  98.     char    *bufp;            /* Write ptr into buffer    */
  99.     char    fillc;            /* Left fill char (' ' or '0')    */
  100.     char    *prefix;        /* Prefix to print before buf    */
  101.     int    prefixlen;        /* Len of prefix ('+','-','0x')    */
  102. } f_args;
  103.  
  104. #define    MINUSFLG    1    /* '-' flag */
  105. #define    PLUSFLG        2    /* '+' flag */
  106. #define    SPACEFLG    4    /* ' ' flag */
  107. #define    HASHFLG        8    /* '#' flag */
  108.  
  109. LOCAL    void    prnum  __PR((Ulong, unsigned, f_args *));
  110. LOCAL    void    prdnum __PR((Ulong, f_args *));
  111. LOCAL    void    pronum __PR((Ulong, f_args *));
  112. LOCAL    void    prxnum __PR((Ulong, f_args *));
  113. LOCAL    void    prXnum __PR((Ulong, f_args *));
  114. #ifdef    USE_LONGLONG
  115. LOCAL    void    prlnum  __PR((Ullong, unsigned, f_args *));
  116. LOCAL    void    prldnum __PR((Ullong, f_args *));
  117. LOCAL    void    prlonum __PR((Ullong, f_args *));
  118. LOCAL    void    prlxnum __PR((Ullong, f_args *));
  119. LOCAL    void    prlXnum __PR((Ullong, f_args *));
  120. #endif
  121. LOCAL    int    prbuf  __PR((const char *, f_args *));
  122. LOCAL    int    prc    __PR((char, f_args *));
  123. LOCAL    int    prstring __PR((const char *, f_args *));
  124.  
  125.  
  126. #ifdef    PROTOTYPES
  127. EXPORT int format(    void (*fun)(char, long),
  128.             long farg,
  129.             const char *fmt,
  130.             va_list args)
  131. #else
  132. EXPORT int format(fun, farg, fmt, args)
  133.     register void    (*fun)();
  134.     register long    farg;
  135.     register char    *fmt;
  136.     va_list        args;
  137. #endif
  138. {
  139.     char buf[512];
  140.     const char *sfmt;
  141.     register int unsflag;
  142.     register long val;
  143.     register char type;
  144.     register char mode;
  145.     register char c;
  146.     int count;
  147.     int i;
  148.     short sh;
  149.     const char *str;
  150.     double dval;
  151. #ifdef    USE_LONGLONG
  152.     Llong llval = 0;
  153. #endif
  154.     Ulong res;
  155.     char *rfmt;
  156.     f_args    fa;
  157.  
  158.     fa.outf = fun;
  159.     fa.farg = farg;
  160.     count = 0;
  161.     /*
  162.      * Main loop over the format string.
  163.      * Increment and check for end of string is made here.
  164.      */
  165.     for(; *fmt != '\0'; fmt++) {
  166.         c = *fmt;
  167.         while (c != '%') {
  168.             if (c == '\0')
  169.                 return (count);
  170.             (*fun)(c, farg);
  171.             c = *(++fmt);
  172.             count++;
  173.         }
  174.  
  175.         /*
  176.          * We reached a '%' sign.
  177.          */
  178.         buf[0] = '\0';
  179.         fa.buf = fa.bufp = buf;
  180.         fa.minusflag = 0;
  181.         fa.flags = 0;
  182.         fa.fldwidth = 0;
  183.         fa.signific = -1;
  184.         fa.lzero = 0;
  185.         fa.fillc = ' ';
  186.         fa.prefixlen = 0;
  187.         sfmt = fmt;
  188.         unsflag = FALSE;
  189.     newflag:
  190.         switch (*(++fmt)) {
  191.  
  192.         case '+':
  193.             fa.flags |= PLUSFLG;
  194.             goto newflag;
  195.  
  196.         case '-':
  197.             fa.minusflag++;
  198.             goto newflag;
  199.  
  200.         case ' ':
  201.             /*
  202.              * If the space and the + flag are present,
  203.              * the space flag will be ignored.
  204.              */
  205.             fa.flags |= SPACEFLG;
  206.             goto newflag;
  207.  
  208.         case '#':
  209.             fa.flags |= HASHFLG;
  210.             goto newflag;
  211.  
  212.         case '0':
  213.             /*
  214.              * '0' is a flag.
  215.              */
  216.             fa.fillc = '0';
  217.             goto newflag;
  218.         }
  219.         if (*fmt == '*') {
  220.             fmt++;
  221.             fa.fldwidth = va_arg(args, int);
  222.             /*
  223.              * A negative fieldwith is a minus flag with a
  224.              * positive fieldwidth.
  225.              */
  226.             if (fa.fldwidth < 0) {
  227.                 fa.fldwidth = -fa.fldwidth;
  228. /*                fa.minusflag ^= 1;*/
  229.                 fa.minusflag = 1;
  230.             }
  231.         } else while (c = *fmt, is_dig(c)) {
  232.             fa.fldwidth *= 10;
  233.             fa.fldwidth += c - '0';
  234.             fmt++;
  235.         }
  236.         if (*fmt == '.') {
  237.             fmt++;
  238.             fa.signific = 0;
  239.             if (*fmt == '*') {
  240.                 fmt++;
  241.                 fa.signific = va_arg(args, int);
  242.                 if (fa.signific < 0)
  243.                     fa.signific = 0;
  244.             } else while (c = *fmt, is_dig(c)) {
  245.                 fa.signific *= 10;
  246.                 fa.signific += c - '0';
  247.                 fmt++;
  248.             }
  249.         }
  250.         if (strchr("UCSIL", *fmt)) {
  251.             /*
  252.              * Enhancements to K&R and ANSI:
  253.              *
  254.              * got a type specifyer
  255.              */
  256.             if (*fmt == 'U') {
  257.                 fmt++;
  258.                 unsflag = TRUE;
  259.             }
  260.             if (!strchr("CSILZODX", *fmt)) {
  261.                 /*
  262.                  * Got only 'U'nsigned specifyer,
  263.                  * use default type and mode.
  264.                  */
  265.                 type = 'I';
  266.                 mode = 'D';
  267.                 fmt--;
  268.             } else if (!strchr("CSIL", *fmt)) {
  269.                 /*
  270.                  * no type, use default
  271.                  */
  272.                 type = 'I';
  273.                 mode = *fmt;
  274.             } else {
  275.                 /*
  276.                  * got CSIL
  277.                  */
  278.                 type = *fmt++;
  279.                 if (!strchr("ZODX", mode = *fmt)) {
  280.                     fmt--;
  281.                     mode = 'D';/* default mode */
  282.                 }
  283.             }
  284.         } else switch(*fmt) {
  285.  
  286.         case 'h':
  287.             type = 'S';        /* convert to type */
  288.             goto getmode;
  289.  
  290.         case 'l':
  291.             type = 'L';        /* convert to type */
  292.  
  293.         getmode:
  294.             if (!strchr("udioxX", *(++fmt))) {
  295. #ifdef    USE_LONGLONG
  296.                 if (*fmt == 'l') {
  297.                     type = 'Q';
  298.                     goto getmode;
  299.                 }
  300. #endif
  301.                 fmt--;
  302.                 mode = 'D';
  303.             } else {
  304.                 mode = *fmt;
  305.                 if (mode != 'x')
  306.                     mode = to_cap(mode);
  307.                 if (mode == 'U')
  308.                     unsflag = TRUE;
  309.                 else if (mode == 'I')    /*XXX */
  310.                     mode = 'D';
  311.             }
  312.             break;
  313.         case 'x':
  314.             mode = 'x';
  315.             goto havemode;
  316.         case 'u':
  317.             unsflag = TRUE;
  318.         case 'o': case 'O':
  319.         case 'd': case 'D':
  320.         case 'i': case 'I':
  321.         case 'X':
  322.         case 'z': case 'Z':
  323.             mode = to_cap(*fmt);
  324.         havemode:
  325.             type = cap_ty(*fmt);
  326.             if (mode == 'I')    /*XXX kann entfallen*/
  327.                 mode = 'D';    /*wenn besseres uflg*/
  328.             break;
  329.         case 'p':
  330.             mode = 'P';
  331.             type = 'L';
  332.             break;
  333.  
  334.         case '%':
  335.             count += prc('%', &fa);
  336.             continue;
  337.         case ' ':
  338.             count += prbuf("", &fa);
  339.             continue;
  340.         case 'c':
  341.             c = va_arg(args, int);
  342.             count += prc(c, &fa);
  343.             continue;
  344.         case 's':
  345.             str = va_arg(args, char *);
  346.             count += prstring(str, &fa);
  347.             continue;
  348.         case 'b':
  349.             str = va_arg(args, char *);
  350.             fa.signific = va_arg(args, int);
  351.             count += prstring(str, &fa);
  352.             continue;
  353.  
  354. #ifndef    NO_FLOATINGPOINT
  355.         case 'e':
  356.             if (fa.signific == -1)
  357.                 fa.signific = 6;
  358.             dval = va_arg(args, double);
  359.             ftoes(buf, dval, 0, fa.signific);
  360.             count += prbuf(buf, &fa);
  361.             continue;
  362.         case 'f':
  363.             if (fa.signific == -1)
  364.                 fa.signific = 6;
  365.             dval = va_arg(args, double);
  366.             ftofs(buf, dval, 0, fa.signific);
  367.             count += prbuf(buf, &fa);
  368.             continue;
  369.         case 'g':
  370.             if (fa.signific == -1)
  371.                 fa.signific = 6;
  372.             if (fa.signific == 0)
  373.                 fa.signific = 1;
  374.             dval = va_arg(args, double);
  375.             gcvt(dval, fa.signific, buf);
  376.             count += prbuf(buf, &fa);
  377.             continue;
  378. #else
  379. #    ifdef    USE_FLOATINGARGS
  380.         case 'e':
  381.         case 'f':
  382.         case 'g':
  383.             dval = va_arg(args, double);
  384.             continue;
  385. #    endif
  386. #endif
  387.  
  388.         case 'r':            /* recursive printf */
  389.         case 'R':            /* recursive printf */
  390.             rfmt  = va_arg(args, char *);
  391.             /*
  392.              * I don't know any portable way to get an arbitrary
  393.              * C object from a var arg list so I use a
  394.              * system-specific routine __va_arg_list() that knows
  395.              * if 'va_list' is an array. You will not be able to
  396.              * assign the value of __va_arg_list() but it works
  397.              * to be used as an argument of a function.
  398.              * It is a requirement for recursive printf to be able
  399.              * to use this function argument. If your system
  400.              * defines va_list to be an array you need to know this
  401.              * via autoconf or another mechanism.
  402.              * It would be nice to have something like
  403.              * __va_arg_list() in stdarg.h
  404.              */
  405.             count += format(fun, farg, rfmt, __va_arg_list(args));
  406.             continue;
  407.  
  408.         case 'n':
  409.             {
  410.                 int    *ip = va_arg(args, int *);
  411.  
  412.                 *ip = count;
  413.             }
  414.             continue;
  415.  
  416.         default:            /* Unknown '%' format */
  417.             sfmt++;            /* Dont't print '%'   */
  418.             count += fmt - sfmt;
  419.             while (sfmt < fmt)
  420.                 (*fun)(*(sfmt++), farg);
  421.             if (*fmt == '\0') {
  422.                 fmt--;
  423.                 continue;
  424.             } else {
  425.                 (*fun)(*fmt, farg);
  426.                 count++;
  427.                 continue;
  428.             }
  429.         }
  430.         /*
  431.          * print numbers:
  432.          * first prepare type 'C'har, 'S'hort, 'I'nt, or 'L'ong
  433.          * or 'Q'ad
  434.          */
  435.         switch(type) {
  436.  
  437.         case 'C':
  438.             c = va_arg(args, int);
  439.             val = c;        /* extend sign here */
  440.             if (unsflag || mode != 'D')
  441. #ifdef    DO_MASK
  442.                 val &= CHARMASK;
  443. #else
  444.                 val = (unsigned char)val;
  445. #endif
  446.             break;
  447.         case 'S':
  448.             sh = va_arg(args, int);
  449.             val = sh;        /* extend sign here */
  450.             if (unsflag || mode != 'D')
  451. #ifdef    DO_MASK
  452.                 val &= SHORTMASK;
  453. #else
  454.                 val = (unsigned short)val;
  455. #endif
  456.             break;
  457.         case 'I':
  458.         default:
  459.             i = va_arg(args, int);
  460.             val = i;        /* extend sign here */
  461.             if (unsflag || mode != 'D')
  462. #ifdef    DO_MASK
  463.                 val &= INTMASK;
  464. #else
  465.                 val = (unsigned int)val;
  466. #endif
  467.             break;
  468.         case 'P':
  469.         case 'L':
  470.             val = va_arg(args, long);
  471.             break;
  472. #ifdef    USE_LONGLONG
  473.         case 'Q':
  474.             llval = va_arg(args, Llong);
  475.             val = llval != 0;
  476.             break;
  477. #endif
  478.         }
  479.  
  480.         /*
  481.          * Final print out, take care of mode:
  482.          * mode is one of: 'O'ctal, 'D'ecimal, or he'X'
  483.          * oder 'Z'weierdarstellung.
  484.          */
  485.         fa.bufp = &buf[sizeof(buf)-1];
  486.         *--fa.bufp = '\0';
  487.  
  488.         if (val == 0 && mode != 'D') {
  489.         printzero:
  490.             /*
  491.              * Printing '0' with fieldwidth 0 results in no chars.
  492.              */
  493.             fa.lzero = -1;
  494.             if (fa.signific >= 0)
  495.                 fa.fillc = ' ';
  496.             count += prstring("0", &fa);
  497.             continue;
  498.         } else switch(mode) {
  499.  
  500.         case 'D':
  501. #ifdef    USE_LONGLONG
  502.             if (type == 'Q') {
  503.                 if (!unsflag && llval < 0) {
  504.                     fa.prefix = "-";
  505.                     fa.prefixlen = 1;
  506.                     llval = -llval;
  507.                 } else if (fa.flags & PLUSFLG) {
  508.                     fa.prefix = "+";
  509.                     fa.prefixlen = 1;
  510.                 } else if (fa.flags & SPACEFLG) {
  511.                     fa.prefix = " ";
  512.                     fa.prefixlen = 1;
  513.                 }
  514.                 if (llval == 0)
  515.                     goto printzero;
  516.                 goto prunsigned;
  517.             }
  518. #endif
  519.             if (!unsflag && val < 0) {
  520.                 fa.prefix = "-";
  521.                 fa.prefixlen = 1;
  522.                 val = -val;
  523.             } else if (fa.flags & PLUSFLG) {
  524.                 fa.prefix = "+";
  525.                 fa.prefixlen = 1;
  526.             } else if (fa.flags & SPACEFLG) {
  527.                 fa.prefix = " ";
  528.                 fa.prefixlen = 1;
  529.             }
  530.             if (val == 0)
  531.                 goto printzero;
  532.         case 'U':
  533.             /* output a long unsigned decimal number */
  534. #ifdef    USE_LONGLONG
  535.         prunsigned:
  536.             if (type == 'Q')
  537.                 prldnum(llval, &fa);
  538.             else
  539. #endif
  540.             prdnum(val, &fa);
  541.             break;
  542.         case 'O':
  543.             /* output a long octal number */
  544.             if (fa.flags & HASHFLG) {
  545.                 fa.prefix = "0";
  546.                 fa.prefixlen = 1;
  547.             }
  548. #ifdef    USE_LONGLONG
  549.             if (type == 'Q') {
  550.                 prlonum(llval, &fa);
  551.             } else
  552. #endif
  553.             {
  554.                 pronum(val & 07, &fa);
  555.                 if ((res = (val>>3) & rshiftmask(long, 3)) != 0)
  556.                     pronum(res, &fa);
  557.             }
  558.             break;
  559.         case 'p':
  560.         case 'x':
  561.             /* output a hex long */
  562.             if (fa.flags & HASHFLG) {
  563.                 fa.prefix = "0x";
  564.                 fa.prefixlen = 2;
  565.             }
  566. #ifdef    USE_LONGLONG
  567.             if (type == 'Q')
  568.                 prlxnum(llval, &fa);
  569.             else
  570. #endif
  571.             {
  572.                 prxnum(val & 0xF, &fa);
  573.                 if ((res = (val>>4) & rshiftmask(long, 4)) != 0)
  574.                     prxnum(res, &fa);
  575.             }
  576.             break;
  577.         case 'P':
  578.         case 'X':
  579.             /* output a hex long */
  580.             if (fa.flags & HASHFLG) {
  581.                 fa.prefix = "0X";
  582.                 fa.prefixlen = 2;
  583.             }
  584. #ifdef    USE_LONGLONG
  585.             if (type == 'Q')
  586.                 prlXnum(llval, &fa);
  587.             else
  588. #endif
  589.             {
  590.                 prXnum(val & 0xF, &fa);
  591.                 if ((res = (val>>4) & rshiftmask(long, 4)) != 0)
  592.                     prXnum(res, &fa);
  593.             }
  594.             break;
  595.         case 'Z':
  596.             /* output a binary long */
  597. #ifdef    USE_LONGLONG
  598.             if (type == 'Q')
  599.                 prlnum(llval, 2, &fa);
  600.             else
  601. #endif
  602.             {
  603.                 prnum(val & 0x1, 2, &fa);
  604.                 if ((res = (val>>1) & rshiftmask(long, 1)) != 0)
  605.                     prnum(res, 2, &fa);
  606.             }
  607.         }
  608.         fa.lzero = -1;
  609.         /*
  610.          * If a precision (fielwidth) is specified
  611.          * on diouXx conversions, the '0' flag is ignored.
  612.          */
  613.         if (fa.signific >= 0)
  614.             fa.fillc = ' ';
  615.         count += prbuf(fa.bufp, &fa);
  616.     }
  617.     return (count);
  618. }
  619.  
  620. /*
  621.  * Routines to print (not negative) numbers in an arbitrary base
  622.  */
  623. LOCAL    unsigned char    dtab[]  = "0123456789abcdef";
  624. LOCAL    unsigned char    udtab[] = "0123456789ABCDEF";
  625.  
  626. LOCAL void prnum(val, base, fa)
  627.     register Ulong val;
  628.     register unsigned base;
  629.     f_args *fa;
  630. {
  631.     register char *p = fa->bufp;
  632.  
  633.     do {
  634.         *--p = dtab[modlbys(val, base)];
  635.         val = divlbys(val, base);
  636.     } while (val > 0);
  637.  
  638.     fa->bufp = p;
  639. }
  640.  
  641. LOCAL void prdnum(val, fa)
  642.     register Ulong val;
  643.     f_args *fa;
  644. {
  645.     register char *p = fa->bufp;
  646.  
  647.     do {
  648.         *--p = dtab[modlbys(val, (unsigned)10)];
  649.         val = divlbys(val, (unsigned)10);
  650.     } while (val > 0);
  651.  
  652.     fa->bufp = p;
  653. }
  654.  
  655. /*
  656.  * We may need to use division here too (PDP-11, non two's complement ...)
  657.  */
  658. LOCAL void pronum(val, fa)
  659.     register Ulong val;
  660.     f_args *fa;
  661. {
  662.     register char *p = fa->bufp;
  663.  
  664.     do {
  665.         *--p = dtab[val & 7];
  666.         val >>= 3;
  667.     } while (val > 0);
  668.  
  669.     fa->bufp = p;
  670. }
  671.  
  672. LOCAL void prxnum(val, fa)
  673.     register Ulong val;
  674.     f_args *fa;
  675. {
  676.     register char *p = fa->bufp;
  677.  
  678.     do {
  679.         *--p = dtab[val & 15];
  680.         val >>= 4;
  681.     } while (val > 0);
  682.  
  683.     fa->bufp = p;
  684. }
  685.  
  686. LOCAL void prXnum(val, fa)
  687.     register Ulong val;
  688.     f_args *fa;
  689. {
  690.     register char *p = fa->bufp;
  691.  
  692.     do {
  693.         *--p = udtab[val & 15];
  694.         val >>= 4;
  695.     } while (val > 0);
  696.  
  697.     fa->bufp = p;
  698. }
  699.  
  700. #ifdef    USE_LONGLONG
  701. LOCAL void prlnum(val, base, fa)
  702.     register Ullong val;
  703.     register unsigned base;
  704.     f_args *fa;
  705. {
  706.     register char *p = fa->bufp;
  707.  
  708.     do {
  709.         *--p = dtab[modlbys(val, base)];
  710.         val = divlbys(val, base);
  711.     } while (val > 0);
  712.  
  713.     fa->bufp = p;
  714. }
  715.  
  716. LOCAL void prldnum(val, fa)
  717.     register Ullong val;
  718.     f_args *fa;
  719. {
  720.     register char *p = fa->bufp;
  721.  
  722.     do {
  723.         *--p = dtab[val % (unsigned)10];
  724.         val = val / (unsigned)10;
  725.     } while (val > 0);
  726.  
  727.     fa->bufp = p;
  728. }
  729.  
  730. LOCAL void prlonum(val, fa)
  731.     register Ullong val;
  732.     f_args *fa;
  733. {
  734.     register char *p = fa->bufp;
  735.  
  736.     do {
  737.         *--p = dtab[val & 7];
  738.         val >>= 3;
  739.     } while (val > 0);
  740.  
  741.     fa->bufp = p;
  742. }
  743.  
  744. LOCAL void prlxnum(val, fa)
  745.     register Ullong val;
  746.     f_args *fa;
  747. {
  748.     register char *p = fa->bufp;
  749.  
  750.     do {
  751.         *--p = dtab[val & 15];
  752.         val >>= 4;
  753.     } while (val > 0);
  754.  
  755.     fa->bufp = p;
  756. }
  757.  
  758. LOCAL void prlXnum(val, fa)
  759.     register Ullong val;
  760.     f_args *fa;
  761. {
  762.     register char *p = fa->bufp;
  763.  
  764.     do {
  765.         *--p = udtab[val & 15];
  766.         val >>= 4;
  767.     } while (val > 0);
  768.  
  769.     fa->bufp = p;
  770. }
  771.  
  772. #endif
  773.  
  774. /*
  775.  * Final buffer print out routine.
  776.  */
  777. LOCAL int prbuf(s, fa)
  778.     register const char *s;
  779.     f_args *fa;
  780. {
  781.     register int diff;
  782.     register int rfillc;
  783.     register long arg            = fa->farg;
  784.     register void (*fun) __PR((char, long))    = fa->outf;
  785.     register int count;
  786.     register int lzero = 0;
  787.  
  788.     count = strlen(s);
  789.  
  790.     /*
  791.      * lzero becomes the number of left fill chars needed to reach signific
  792.      */
  793.     if (fa->lzero < 0 && count < fa->signific)
  794.         lzero = fa->signific - count;
  795.     count += lzero + fa->prefixlen;
  796.     diff = fa->fldwidth - count;
  797.     if (diff > 0)
  798.         count += diff;
  799.  
  800.     if (fa->prefixlen && fa->fillc != ' ') {
  801.         while (*fa->prefix != '\0')
  802.             (*fun)(*fa->prefix++, arg);
  803.     }
  804.     if (!fa->minusflag) {
  805.         rfillc = fa->fillc;
  806.         while (--diff >= 0)
  807.             (*fun)(rfillc, arg);
  808.     }
  809.     if (fa->prefixlen && fa->fillc == ' ') {
  810.         while (*fa->prefix != '\0')
  811.             (*fun)(*fa->prefix++, arg);
  812.     }
  813.     if (lzero > 0) {
  814.         rfillc = '0';
  815.         while (--lzero >= 0)
  816.             (*fun)(rfillc, arg);
  817.     }
  818.     while (*s != '\0')
  819.         (*fun)(*s++, arg);
  820.     if (fa->minusflag) {
  821.         rfillc = ' ';
  822.         while (--diff >= 0)
  823.             (*fun)(rfillc, arg);
  824.     }
  825.     return (count);
  826. }
  827.  
  828. /*
  829.  * Print out one char, allowing prc('\0')
  830.  * Similar to prbuf()
  831.  */
  832. #ifdef    PROTOTYPES
  833.  
  834. LOCAL int prc(char c, f_args *fa)
  835.  
  836. #else
  837. LOCAL int prc(c, fa)
  838.     char    c;
  839.     f_args *fa;
  840. #endif
  841. {
  842.     register int diff;
  843.     register int rfillc;
  844.     register long arg            = fa->farg;
  845.     register void (*fun) __PR((char, long))    = fa->outf;
  846.     register int count;
  847.  
  848.     count = 1;
  849.     diff = fa->fldwidth - 1;
  850.     if (diff > 0)
  851.         count += diff;
  852.  
  853.     if (!fa->minusflag) {
  854.         rfillc = fa->fillc;
  855.         while (--diff >= 0)
  856.             (*fun)(rfillc, arg);
  857.     }
  858.     (*fun)(c, arg);
  859.     if (fa->minusflag) {
  860.         rfillc = ' ';
  861.         while (--diff >= 0)
  862.             (*fun)(rfillc, arg);
  863.     }
  864.     return (count);
  865. }
  866.  
  867. /*
  868.  * String output routine.
  869.  * If fa->signific is >= 0, it uses only fa->signific chars.
  870.  * If fa->signific is 0, print no characters.
  871.  */
  872. LOCAL int prstring(s, fa)
  873.     register const char    *s;
  874.     f_args *fa;
  875. {
  876.     register char    *bp;
  877.     register int    signific;
  878.  
  879.     if (s == NULL)
  880.         return (prbuf("(NULL POINTER)", fa));
  881.  
  882.     if (fa->signific < 0)
  883.         return (prbuf(s, fa));
  884.  
  885.     bp = fa->buf;
  886.     signific = fa->signific;
  887.  
  888.     while (--signific >= 0 && *s != '\0')
  889.         *bp++ = *s++;
  890.     *bp = '\0';
  891.  
  892.     return (prbuf(fa->buf, fa));
  893. }
  894.  
  895.