home *** CD-ROM | disk | FTP | other *** search
- /*
- * This file forms part of "TKERN" - "Troy's Kernel for Windows".
- *
- * Copyright (C) 1994 Troy Rollo <troy@cbme.unsw.EDU.AU>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /* __formattr does formatted output. It is here to serve all the printf
- * type functions. They call __formatter with the address of a function
- * that __formatter will call when it has a character, and a void pointer
- * which is passwd to that function as the first argument. The character
- * is passed as the second argument.
- *
- * This function can be safely placed in the DLL without sacrificing
- * portability. It basically means that this module can be under GNU
- * Library License without compromising any other programs using the
- * stubs (which are freely redistributable and usable for any purpose
- * whatsoever).
- *
- * Note that this also makes it trivial to design new printf type
- * functions without resorting to sprintf on a large string.
- */
-
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
- #include <ctype.h>
- #include <float.h>
- #include <math.h>
-
- #define FLAG_SHOWSIGN 0x0001
- #define FLAG_LEFT 0x0002
- #define FLAG_ZEROES 0x0004
- #define FLAG_BLANK 0x0008
- #define FLAG_ALTERNATE 0x0010
- #define FLAG_UPPER 0x0020
- #define FLAG_EXPONENTIAL 0x0040
- #define FLAG_MAYEXP 0x0080
-
- #pragma warn -pls
-
- static char buffer[1024];
-
-
- #pragma argsused
- static int
- show_integer( int (*func)(void *a, char b),
- void *func_arg,
- char const *pch,
- char cSign,
- int nWidth,
- int nPrec,
- int nFlags)
- {
- char cFill = ((nFlags & FLAG_ZEROES) ? '0' : ' ');
- int iLen;
- int nChars = 0;
-
- iLen = strlen(pch) + (cSign ? 1 : 0);
- if (iLen > nWidth)
- nWidth = iLen;
- else if (nWidth > iLen &&
- (!(nFlags & FLAG_LEFT) ||
- (nFlags & FLAG_ZEROES)))
- {
- if (cFill == '0' && cSign)
- {
- (*func)(func_arg, cSign);
- cSign = '\0';
- iLen--;
- nWidth--;
- nChars++;
- }
- while (nWidth > iLen)
- {
- nWidth--;
- nChars++;
- (*func)(func_arg, cFill);
- }
- }
- if (cSign)
- {
- (*func)(func_arg, cSign);
- iLen--;
- nWidth--;
- nChars++;
- }
- while (iLen--)
- {
- nWidth--;
- (*func)(func_arg, *pch++);
- nChars++;
- }
- while (nWidth--)
- {
- (*func)(func_arg, ' ');
- nChars++;
- }
- return nChars;
- }
-
-
- static int
- show_long( int (*func)(void *a, char b),
- void *func_arg,
- long number,
- int nWidth,
- int nPrec,
- int nFlags)
- {
- char *pch = buffer;
- char cSign = '\0';
- int nLen;
-
- ltoa(number, buffer, 10);
- if (*pch == '-')
- {
- cSign = '-';
- pch++;
- }
- else if (nFlags & FLAG_SHOWSIGN)
- {
- cSign = '+';
- }
- else if (nFlags & FLAG_BLANK)
- {
- cSign = ' ';
- }
- return show_integer(func, func_arg, pch, cSign, nWidth, nPrec, nFlags);
- }
-
- static int
- show_ulong( int (*func)(void *a, char b),
- void *func_arg,
- long number,
- int nWidth,
- int nPrec,
- int nFlags)
- {
- ultoa(number, buffer, 10);
- return show_integer(func, func_arg, buffer, '\0', nWidth, nPrec, nFlags);
- }
-
- static int
- show_hex( int (*func)(void *a, char b),
- void *func_arg,
- long number,
- int nWidth,
- int nPrec,
- int nFlags)
- {
- ultoa(number, buffer, 16);
- if (nFlags & FLAG_UPPER)
- strupr(buffer);
- return show_integer(func, func_arg, buffer, '\0', nWidth, nPrec, nFlags);
- }
-
- static int
- show_real( int (*func)(void *a, char b),
- void *func_arg,
- long double fValue,
- int nWidth,
- int nPrecision,
- int nFlags,
- int nDigits)
- {
- int aiDigits[LDBL_DIG + 1];
- long double fMantissa;
- int nExponent;
- int nSign = 1;
- int nVisible;
- char achExponent[10];
- int nWritten = 0;
- int iLastDigit;
- int *piStart;
- char *pchStart;
- int i;
-
- if (fValue < 0)
- {
- nSign = -1;
- fValue = -fValue;
- }
- if (fValue)
- nExponent = floor(log10(fValue));
- else
- nExponent = 0;
- fMantissa = fValue / pow(10, nExponent);
-
- aiDigits[0] = 0;
- for (i = 1; i <= nDigits; i++)
- {
- if (fMantissa < 0) /* Rounding error */
- fMantissa = 0;
- aiDigits[i] = floor(fMantissa);
- fMantissa = (fMantissa - aiDigits[i]) * 10;
- }
- for (; i < nDigits; i++)
- {
- aiDigits[i] = 0;
- }
- if (nPrecision == -1)
- nPrecision = 6;
- if (nFlags & FLAG_MAYEXP &&
- nExponent >= 0 &&
- nExponent +
- (nPrecision ? nPrecision + 2 : 1) +
- ((nSign == -1 || (nFlags & FLAG_SHOWSIGN)) ? 1 : 0) > nWidth)
- nFlags |= FLAG_EXPONENTIAL;
- if (nFlags & FLAG_EXPONENTIAL)
- {
- ltoa(nExponent, achExponent, 10);
- nVisible = 1 + (nPrecision ? nPrecision + 2 : 1) + strlen(achExponent);
- }
- else
- {
- if (nExponent < 0)
- {
- nVisible = nPrecision ? nPrecision : 1;
- }
- else
- {
- nVisible = nExponent + (nPrecision ? nPrecision + 2 : 1);
- }
- }
- if (nSign == -1 || nFlags & FLAG_SHOWSIGN)
- nVisible++;
- if (!(nFlags & FLAG_LEFT))
- {
- while (nVisible < nWidth--)
- {
- (*func)(func_arg, ' ');
- nWritten++;
- }
- }
-
- if ((nFlags & FLAG_EXPONENTIAL) || nExponent < nDigits)
- {
- if ((nFlags & FLAG_EXPONENTIAL) || (nExponent < 0))
- {
- iLastDigit = 1 + nPrecision;
- }
- else
- {
- iLastDigit = 1 + nExponent + nPrecision;
- }
- if (iLastDigit < nDigits &&
- aiDigits[iLastDigit+1] >= 5)
- {
- while (aiDigits[iLastDigit] == 9)
- aiDigits[iLastDigit--] = 0;
- aiDigits[iLastDigit]++;
- }
- }
-
- if (nSign == -1)
- {
- (*func)(func_arg, '-');
- nWritten++;
- }
- else if (nFlags & FLAG_SHOWSIGN)
- {
- (*func)(func_arg, '+');
- }
- if (aiDigits[0])
- {
- nExponent++;
- piStart = aiDigits;
- }
- else
- {
- piStart = aiDigits + 1;
- }
- if (nFlags & FLAG_EXPONENTIAL)
- {
- (*func)(func_arg, '0' + *piStart++);
- nWritten++;
- if (nPrecision)
- {
- if (nPrecision > nDigits - 1)
- nPrecision = nDigits - 1;
- (*func)(func_arg, '.');
- nWritten++;
- while(nPrecision--)
- {
- (*func)(func_arg, '0' + *piStart++);
- nWritten++;
- }
- if (nFlags & FLAG_UPPER)
- (*func)(func_arg, 'E');
- else
- (*func)(func_arg, 'e');
- nWritten++;
- for (pchStart = achExponent; *pchStart; pchStart++)
- {
- (*func)(func_arg, *pchStart);
- nWritten++;
- }
- }
- }
- else
- {
- if (nExponent >= 0)
- {
- while (nExponent-- >= 0)
- {
- if (nDigits-- > 0)
- (*func)(func_arg, '0' + *piStart++);
- else
- (*func)(func_arg, '0');
- nWritten++;
- }
- if (nPrecision)
- {
- (*func)(func_arg, '.');
- nWritten++;
- }
- }
- else
- {
- (*func)(func_arg, '0');
- if (nPrecision)
- (*func)(func_arg, '.');
- while (nExponent++ && nPrecision--)
- {
- (*func)(func_arg, '0');
- nWritten++;
- }
- }
- while (nPrecision-- > 0)
- {
- if (nDigits-- > 0)
- (*func)(func_arg, '0 ' + *piStart++);
- else
- (*func)(func_arg, '0');
- nWritten++;
- }
- }
-
- if (nFlags & FLAG_LEFT)
- {
- while (nVisible < nWidth--)
- {
- (*func)(func_arg, ' ');
- nWritten++;
- }
- }
-
- return nWritten;
- }
-
-
- int far _export
- __formatter( int (*func)(void *a, char b),
- void *func_arg,
- char const *format,
- va_list arg)
- {
- int nChars = 0;
- int nPrecision;
- int nWidth;
- int nLong;
- long nIntValue;
- int nFlags;
- int nPad;
- int nLen;
- union
- {
- short nShort;
- int nInt;
- long nLong;
- unsigned short nUShort;
- unsigned int nUInt;
- unsigned long nULong;
-
- float fFloat;
- double fDouble;
- long double fLongDouble;
-
- char cChar;
-
- char *pchString;
-
- void *pvPointer;
- } Value;
-
-
- while (*format)
- {
- if (*format == '%')
- {
- if (*++format == '%')
- {
- (*func)(func_arg, '%');
- nChars++;
- }
- else
- {
- nPrecision = -1;
- nWidth = 0;
- nLong = 0;
- nFlags = 0;
- while (strchr("+-0# ", *format))
- {
- switch(*format++)
- {
- case '+':
- nFlags |= FLAG_SHOWSIGN;
- break;
-
- case '-':
- nFlags |= FLAG_LEFT;
- break;
-
- case '#':
- nFlags |= FLAG_ALTERNATE;
- break;
-
- case '0':
- nFlags |= FLAG_ZEROES;
- break;
-
- case ' ':
- nFlags |= FLAG_BLANK;
- break;
- }
- }
- if (isdigit(*format))
- {
- nWidth = (int) strtol((char *) format, (char **) &format, 10);
- }
- else if (*format == '*')
- {
- nWidth = va_arg(arg, int);
- format++;
- }
- if (*format == '.')
- {
- ++format;
- if (isdigit(*format))
- {
- nPrecision = (int) strtol((char *) format, (char **) &format, 10);
- }
- else if (*format == '*')
- {
- nPrecision = (int) va_arg(arg, int);
- format++;
- }
- }
- while (strchr("lhL", *format))
- {
- if (*format == 'l')
- nLong++;
- else if (*format == 'h')
- nLong--;
- else if (*format == 'L')
- nLong = 2;
- format++;
- }
- switch(*format)
- {
- case 'u':
- case 'U':
- if (nLong < 0)
- {
- Value.nUShort = va_arg( arg,
- unsigned short);
- nChars += show_ulong( func,
- func_arg,
- Value.nUShort,
- nWidth,
- nPrecision,
- nFlags);
- }
- else if (nLong == 0)
- {
- Value.nUInt = va_arg( arg,
- unsigned int);
- nChars += show_ulong( func,
- func_arg,
- Value.nUInt,
- nWidth,
- nPrecision,
- nFlags);
- }
- else
- {
- Value.nULong = va_arg( arg,
- unsigned long);
- nChars += show_ulong( func,
- func_arg,
- Value.nULong,
- nWidth,
- nPrecision,
- nFlags);
- }
- break;
-
- case 'd':
- case 'D':
- case 'i':
- case 'I':
- if (nLong < 0)
- {
- Value.nShort = va_arg( arg,
- short);
- nChars += show_long( func,
- func_arg,
- Value.nShort,
- nWidth,
- nPrecision,
- nFlags);
- }
- else if (nLong == 0)
- {
- Value.nInt = va_arg( arg,
- int);
- nChars += show_long( func,
- func_arg,
- Value.nInt,
- nWidth,
- nPrecision,
- nFlags);
- }
- else
- {
- Value.nLong = va_arg( arg,
- long);
- nChars += show_ulong( func,
- func_arg,
- Value.nLong,
- nWidth,
- nPrecision,
- nFlags);
- }
- break;
-
- case 'n':
- *(va_arg(arg, int *)) = nChars;
- break;
-
- case 's':
- Value.pchString = va_arg( arg,
- char *);
- /* We can't do this in strlen, because we
- * can't guarantee if there is a trailing
- * 0 if we have a precision value
- */
- for (nLen = 0;
- (nPrecision < 0 ||
- nLen < nPrecision) && Value.pchString[nLen];
- nLen++);
- if (nPrecision < 0 || nLen < nPrecision)
- nPrecision = nLen;
- if (!nWidth || nPrecision > nWidth)
- nWidth = nPrecision;
-
- nPad = nWidth - nPrecision;
-
- if (!(nFlags & FLAG_LEFT))
- {
- while (nPad--)
- {
- (*func)(func_arg, ' ');
- nChars++;
- }
- }
- while (nPrecision--)
- {
- (*func)(func_arg, *Value.pchString++);
- nChars++;
- }
- if (nFlags & FLAG_LEFT)
- {
- while (nPad--)
- {
- (*func)(func_arg, ' ');
- nChars++;
- }
- }
- break;
-
- case 'o':
- case 'O':
- break;
-
- case 'x':
- case 'X':
- if (*format == 'X')
- nFlags |= FLAG_UPPER;
- if (nLong < 0)
- {
- Value.nUShort = va_arg( arg,
- unsigned short);
- nChars += show_hex( func,
- func_arg,
- Value.nUShort,
- nWidth,
- nPrecision,
- nFlags);
- }
- else if (nLong == 0)
- {
- Value.nUInt = va_arg( arg,
- unsigned int);
- nChars += show_hex( func,
- func_arg,
- Value.nUInt,
- nWidth,
- nPrecision,
- nFlags);
- }
- else
- {
- Value.nULong = va_arg( arg,
- unsigned long);
- nChars += show_hex( func,
- func_arg,
- Value.nULong,
- nWidth,
- nPrecision,
- nFlags);
- }
- break;
-
- case 'c':
- case 'C':
- Value.cChar = va_arg( arg,
- char);
- (*func)(func_arg, Value.cChar);
- nChars++;
- break;
-
- case 'P':
- case 'p':
- Value.pvPointer = va_arg(arg,
- void *);
- break;
-
- case 'E':
- case 'e':
- nFlags |= FLAG_EXPONENTIAL;
- case 'g':
- case 'G':
- nFlags |= FLAG_MAYEXP;
- case 'F':
- case 'f':
- if (nLong > 1)
- {
- Value.fLongDouble = va_arg( arg,
- long double);
- nChars += show_real( func,
- func_arg,
- Value.fLongDouble,
- nWidth,
- nPrecision,
- nFlags,
- LDBL_DIG);
- }
- else if (nLong > 0)
- {
- Value.fDouble = va_arg( arg,
- double);
- nChars += show_real( func,
- func_arg,
- Value.fDouble,
- nWidth,
- nPrecision,
- nFlags,
- DBL_DIG);
- }
- else
- {
- Value.fFloat = va_arg( arg,
- double);
- nChars += show_real( func,
- func_arg,
- Value.fFloat,
- nWidth,
- nPrecision,
- nFlags,
- FLT_DIG);
- }
- break;
- }
-
- }
- }
- else
- {
- (*func)(func_arg, *format);
- nChars++;
- }
- format++;
- }
- return nChars;
- }