tinyprnt.c

Go to the documentation of this file.
00001 /* tinyprnt.c */
00002 
00003 #if OSK
00004 #define sprintf Sprintf
00005 #endif
00006 
00007 /* This is a limited version of sprintf().  It is useful for Minix-PC and
00008  * Coherent-286 because those systems are both limited to 64k+64k and the
00009  * standard sprintf() is just too damn big.
00010  *
00011  * It should also be useful for OS-9 because OS-9's sprintf() doesn't
00012  * understand the true meaning of asterisks in a format string.  This one
00013  * does.
00014  */
00015 
00016 /* Place-holders in format strings look like "%<pad><clip><type>".
00017  *
00018  * The <pad> adds space to the front (or, if negative, to the back) of the
00019  * output value, to pad it to a given width.  If <pad> is absent, then 0 is
00020  * assumed.  If <pad> is an asterisk, then the next argument is assumed to
00021  * be an (int) which used as the pad width.
00022  *
00023  * The <clip> string can be absent, in which case no clipping is done.
00024  * However, if it is present, then it should be either a "." followed by
00025  * a number, or a "." followed by an asterisk.  The asterisk means that the
00026  * next argument is an (int) which should be used as the pad width.  Clipping
00027  * only affects strings; for other data types it is ignored.
00028  *
00029  * The <type> is one of "s" for strings, "c" for characters (really ints that
00030  * are assumed to be legal char values), "d" for ints, "ld" for long ints, or
00031  * "%" to output a percent sign.
00032  */
00033 
00034 /* NOTE: Variable argument lists are handled by direct stack-twiddling. Sorry! */
00035 
00036 static void cvtnum(buf, num, base)
00037         char            *buf;   /* where to store the number */
00038         unsigned long   num;    /* the number to convert */
00039         int             base;   /* either 8, 10, or 16 */
00040 {
00041         static char     digits[] = "0123456789abcdef";
00042         unsigned long   tmp;
00043 
00044         /* if the number is 0, then just stuff a "0" into the buffer */
00045         if (num == 0L)
00046         {
00047                 buf[0] = '0';
00048                 buf[1] = '\0';
00049                 return;
00050         }
00051 
00052         /* use tmp to figure out how many digits we'll need */
00053         for (tmp = num; tmp > 0; tmp /= base)
00054         {
00055                 buf++;
00056         }
00057 
00058         /* mark the spot that will be the end of the string */
00059         *buf = '\0';
00060 
00061         /* generate all digits, as needed */
00062         for (tmp = num; tmp > 0; tmp /= base)
00063         {
00064                 *--buf = digits[tmp % base];
00065         }
00066 }
00067 
00068 int sprintf(buf, fmt, argref)
00069         char    *buf;   /* where to deposit the formatted output */
00070         char    *fmt;   /* the format string */
00071         int     argref; /* the first argument is located at &argref */
00072 {
00073         char    *argptr;/* pointer to next argument on the stack */
00074         int     pad;    /* value of the pad string */
00075         int     clip;   /* value of the clip string */
00076         long    num;    /* a binary number being converted to ASCII digits */
00077         long    digit;  /* used during conversion */
00078         char    *src, *dst;
00079 
00080         /* make argptr point to the first argument after the format string */
00081         argptr = (char *)&argref;
00082 
00083         /* loop through the whole format string */
00084         while (*fmt)
00085         {
00086                 /* if not part of a place-holder, then copy it literally */
00087                 if (*fmt != '%')
00088                 {
00089                         *buf++ = *fmt++;
00090                         continue;
00091                 }
00092 
00093                 /* found a place-holder!  Get <pad> value */
00094                 fmt++;
00095                 if ('*' == *fmt)
00096                 {
00097                         pad = *((int *)argptr)++;
00098                         fmt++;
00099                 }
00100                 else if (*fmt == '-' || (*fmt >= '0' && *fmt <= '9'))
00101                 {
00102                         pad = atol(fmt);
00103                         do
00104                         {
00105                                 fmt++;
00106                         } while (*fmt >= '0' && *fmt <= '9');
00107                 }
00108                 else
00109                 {
00110                         pad = 0;
00111                 }
00112 
00113                 /* get a <clip> value */
00114                 if (*fmt == '.')
00115                 {
00116                         fmt++;
00117                         if ('*' == *fmt)
00118                         {
00119                                 clip = *((int *)argptr)++;
00120                                 fmt++;
00121                         }
00122                         else if (*fmt >= '0' && *fmt <= '9')
00123                         {
00124                                 clip = atol(fmt);
00125                                 do
00126                                 {
00127                                         fmt++;
00128                                 } while (*fmt >= '0' && *fmt <= '9');
00129                         }
00130                 }
00131                 else
00132                 {
00133                         clip = 0;
00134                 }
00135 
00136                 /* handle <type>, possibly noticing <clip> */
00137                 switch (*fmt++)
00138                 {
00139                   case 'c':
00140                         buf[0] = *((int *)argptr)++;
00141                         buf[1] = '\0';
00142                         break;
00143 
00144                   case 's':
00145                         src = *((char **)argptr)++;
00146                         if (!src)
00147                         {
00148                                 src = "(null)";
00149                         }
00150                         if (clip)
00151                         {
00152                                 strncpy(buf, src, clip);
00153                                 buf[clip] = '\0';
00154                         }
00155                         else
00156                         {
00157                                 strcpy(buf, src);
00158                         }
00159                         break;
00160 
00161                   case 'l':
00162                         fmt++; /* to skip the "d" in "%ld" */
00163                         num = *((long *)argptr)++;
00164                         dst = buf;
00165                         if (num < 0)
00166                         {
00167                                 *dst++ = '-';
00168                                 num = -num;
00169                         }
00170                         cvtnum(dst, num, 10);
00171                         break;
00172 
00173                   case 'x':
00174                         num = *((int *)argptr)++;
00175                         cvtnum(buf, num, 16);
00176                         break;
00177 
00178                   case 'd':
00179                         num = *((int *)argptr)++;
00180                         dst = buf;
00181                         if (num < 0)
00182                         {
00183                                 *dst++ = '-';
00184                                 num = -num;
00185                         }
00186                         cvtnum(dst, num, 10);
00187                         break;
00188 
00189                   default:
00190                         buf[0] = fmt[-1];
00191                         buf[1] = '\0';
00192                 }
00193 
00194                 /* now fix the padding, if the value is too short */
00195                 clip = strlen(buf);
00196                 if (pad < 0)
00197                 {
00198                         /* add spaces after the value */
00199                         pad = -pad - clip;
00200                         for (buf += clip; pad > 0; pad--)
00201                         {
00202                                 *buf++ = ' ';
00203                         }
00204                         *buf = '\0';
00205                 }
00206                 else
00207                 {
00208                         /* add spaces before the value */
00209                         pad -= clip;
00210                         if (pad > 0)
00211                         {
00212                                 src = buf + clip;
00213                                 dst = src + pad;
00214                                 *dst = '\0';
00215                                 while (src > buf)
00216                                 {
00217                                         *--dst = *--src;
00218                                 }
00219                                 while (dst > buf)
00220                                 {
00221                                         *--dst = ' ';
00222                                 }
00223                         }
00224                         buf += strlen(buf);
00225                 }
00226         }
00227 
00228         /* mark the end of the output string */
00229         *buf = '\0';
00230 }

Generated on Fri Apr 14 22:56:53 2006 for minix by  doxygen 1.4.6