# HG changeset patch # User Michael Spacefalcon # Date 1384451493 0 # Node ID 7e45ada9c3656710071c6f7e052425e9430c614d # Parent ea819b60fe0da5087dc8c5d3f45033c0ad834258 gsm-fw: sprintf overhaul in preparation for adding %f format support diff -r ea819b60fe0d -r 7e45ada9c365 gsm-fw/sprintf/Makefile --- a/gsm-fw/sprintf/Makefile Tue Nov 12 16:57:08 2013 +0000 +++ b/gsm-fw/sprintf/Makefile Thu Nov 14 17:51:33 2013 +0000 @@ -3,7 +3,7 @@ AR= arm-elf-ar RANLIB= arm-elf-ranlib -OBJS= doprnt.o sprintf.o vsprintf.o +OBJS= integer.o sprintf.o vspcore.o all: libsprintf.a diff -r ea819b60fe0d -r 7e45ada9c365 gsm-fw/sprintf/defs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/sprintf/defs.h Thu Nov 14 17:51:33 2013 +0000 @@ -0,0 +1,20 @@ +/* + * Embedded [v]sprintf() implementation by Michael Spacefalcon, + * loosely based on the 4.3BSD-Tahoe version. + * + * This header file contains some internal definitions used by + * different pieces of what used to be one giant _doprnt() + * function/module. + */ + +#define todigit(c) ((c) - '0') +#define tochar(n) ((n) + '0') + +#define LONGINT 0x01 /* long integer */ +#define LONGDBL 0x02 /* long double; unimplemented */ +#define SHORTINT 0x04 /* short integer */ +#define ALT 0x08 /* alternate form */ +#define LADJUST 0x10 /* left adjustment */ +#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ +#define HEXPREFIX 0x40 /* add 0x or 0X prefix */ +#define UPPERCASE 0x80 /* uppercase forms */ diff -r ea819b60fe0d -r 7e45ada9c365 gsm-fw/sprintf/doprnt.c --- a/gsm-fw/sprintf/doprnt.c Tue Nov 12 16:57:08 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,299 +0,0 @@ -/* the guts of printf - this implementation came from 4.3BSD-Tahoe */ - -#include -#include -#include - -#define PUTC(ch) (*(*outptrp)++ = (ch)) - -#define ARG() \ - _ulong = flags&LONGINT ? va_arg(argp, long) : va_arg(argp, int); - -#define BUF 256 - -#define todigit(c) ((c) - '0') -#define tochar(n) ((n) + '0') - -/* have to deal with the negative buffer count kludge */ -#define NEGATIVE_COUNT_KLUDGE - -#define LONGINT 0x01 /* long integer */ -#define LONGDBL 0x02 /* long double; unimplemented */ -#define SHORTINT 0x04 /* short integer */ -#define ALT 0x08 /* alternate form */ -#define LADJUST 0x10 /* left adjustment */ -#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ -#define HEXPREFIX 0x40 /* add 0x or 0X prefix */ - -_doprnt(fmt0, argp, outptrp) - u_char *fmt0; - va_list argp; - char **outptrp; -{ - register u_char *fmt; /* format string */ - register int ch; /* character from fmt */ - register int cnt; /* return value accumulator */ - register int n; /* random handy integer */ - register char *t; /* buffer pointer */ - u_long _ulong; /* integer arguments %[diouxX] */ - int base; /* base for [diouxX] conversion */ - int dprec; /* decimal precision in [diouxX] */ - int fieldsz; /* field size expanded by sign, etc */ - int flags; /* flags as above */ - int prec; /* precision from format (%.3d), or -1 */ - int realsz; /* field size expanded by decimal precision */ - int size; /* size of converted field or string */ - int width; /* width from format (%8d), or 0 */ - char sign; /* sign prefix (' ', '+', '-', or \0) */ - char softsign; /* temporary negative sign for floats */ - char *digs; /* digits for [diouxX] conversion */ - char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ - - fmt = fmt0; - digs = "0123456789abcdef"; - for (cnt = 0;; ++fmt) { - for (; (ch = *fmt) && ch != '%'; ++cnt, ++fmt) - PUTC(ch); - if (!ch) - return (cnt); - - flags = 0; dprec = 0; width = 0; - prec = -1; - sign = '\0'; - -rflag: switch (*++fmt) { - case ' ': - /* - * ``If the space and + flags both appear, the space - * flag will be ignored.'' - * -- ANSI X3J11 - */ - if (!sign) - sign = ' '; - goto rflag; - case '#': - flags |= ALT; - goto rflag; - case '*': - /* - * ``A negative field width argument is taken as a - * - flag followed by a positive field width.'' - * -- ANSI X3J11 - * They don't exclude field widths read from args. - */ - if ((width = va_arg(argp, int)) >= 0) - goto rflag; - width = -width; - /* FALLTHROUGH */ - case '-': - flags |= LADJUST; - goto rflag; - case '+': - sign = '+'; - goto rflag; - case '.': - if (*++fmt == '*') - n = va_arg(argp, int); - else { - n = 0; - while (isascii(*fmt) && isdigit(*fmt)) - n = 10 * n + todigit(*fmt++); - --fmt; - } - prec = n < 0 ? -1 : n; - goto rflag; - case '0': - /* - * ``Note that 0 is taken as a flag, not as the - * beginning of a field width.'' - * -- ANSI X3J11 - */ - flags |= ZEROPAD; - goto rflag; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - n = 0; - do { - n = 10 * n + todigit(*fmt); - } while (isascii(*++fmt) && isdigit(*fmt)); - width = n; - --fmt; - goto rflag; - case 'L': - flags |= LONGDBL; - goto rflag; - case 'h': - flags |= SHORTINT; - goto rflag; - case 'l': - flags |= LONGINT; - goto rflag; - case 'c': - *(t = buf) = va_arg(argp, int); - size = 1; - sign = '\0'; - goto pforw; - case 'D': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'd': - case 'i': - ARG(); - if ((long)_ulong < 0) { - _ulong = -_ulong; - sign = '-'; - } - base = 10; - goto number; - case 'n': - if (flags & LONGINT) - *va_arg(argp, long *) = cnt; - else if (flags & SHORTINT) - *va_arg(argp, short *) = cnt; - else - *va_arg(argp, int *) = cnt; - break; - case 'O': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'o': - ARG(); - base = 8; - goto nosign; - case 'p': - /* - * ``The argument shall be a pointer to void. The - * value of the pointer is converted to a sequence - * of printable characters, in an implementation- - * defined manner.'' - * -- ANSI X3J11 - */ - /* NOSTRICT */ - _ulong = (u_long)va_arg(argp, void *); - base = 16; - goto nosign; - case 's': - if (!(t = va_arg(argp, char *))) - t = "(null)"; - if (prec >= 0) { - /* - * can't use strlen; can only look for the - * NUL in the first `prec' characters, and - * strlen() will go further. - */ - char *p; - - for (p = t, size = 0; size < prec; p++, size++) - if (*p == '\0') - break; - } else - size = strlen(t); - sign = '\0'; - goto pforw; - case 'U': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'u': - ARG(); - base = 10; - goto nosign; - case 'X': - digs = "0123456789ABCDEF"; - /* FALLTHROUGH */ - case 'x': - ARG(); - base = 16; - /* leading 0x/X only if non-zero */ - if (flags & ALT && _ulong != 0) - flags |= HEXPREFIX; - - /* unsigned conversions */ -nosign: sign = '\0'; - /* - * ``... diouXx conversions ... if a precision is - * specified, the 0 flag will be ignored.'' - * -- ANSI X3J11 - */ -number: if ((dprec = prec) >= 0) - flags &= ~ZEROPAD; - - /* - * ``The result of converting a zero value with an - * explicit precision of zero is no characters.'' - * -- ANSI X3J11 - */ - t = buf + BUF; - if (_ulong != 0 || prec != 0) { - do { - *--t = digs[_ulong % base]; - _ulong /= base; - } while (_ulong); - digs = "0123456789abcdef"; - if (flags & ALT && base == 8 && *t != '0') - *--t = '0'; /* octal leading 0 */ - } - size = buf + BUF - t; - -pforw: - /* - * All reasonable formats wind up here. At this point, - * `t' points to a string which (if not flags&LADJUST) - * should be padded out to `width' places. If - * flags&ZEROPAD, it should first be prefixed by any - * sign or other prefix; otherwise, it should be blank - * padded before the prefix is emitted. After any - * left-hand padding and prefixing, emit zeroes - * required by a decimal [diouxX] precision, then print - * the string proper, then emit zeroes required by any - * leftover floating precision; finally, if LADJUST, - * pad with blanks. - */ - - /* - * compute actual size, so we know how much to pad - * fieldsz excludes decimal prec; realsz includes it - */ - fieldsz = size; - if (sign) - fieldsz++; - if (flags & HEXPREFIX) - fieldsz += 2; - realsz = dprec > fieldsz ? dprec : fieldsz; - - /* right-adjusting blank padding */ - if ((flags & (LADJUST|ZEROPAD)) == 0 && width) - for (n = realsz; n < width; n++) - PUTC(' '); - /* prefix */ - if (sign) - PUTC(sign); - if (flags & HEXPREFIX) { - PUTC('0'); - PUTC((char)*fmt); - } - /* right-adjusting zero padding */ - if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) - for (n = realsz; n < width; n++) - PUTC('0'); - /* leading zeroes from decimal precision */ - for (n = fieldsz; n < dprec; n++) - PUTC('0'); - - for (n = size; --n >= 0; ) - PUTC(*t++); - /* left-adjusting padding (always blank) */ - if (flags & LADJUST) - for (n = realsz; n < width; n++) - PUTC(' '); - /* finally, adjust cnt */ - cnt += width > realsz ? width : realsz; - break; - case '\0': /* "%?" prints ?, unless ? is NULL */ - return (cnt); - default: - PUTC((char)*fmt); - cnt++; - } - } - /* NOTREACHED */ -} diff -r ea819b60fe0d -r 7e45ada9c365 gsm-fw/sprintf/integer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/sprintf/integer.c Thu Nov 14 17:51:33 2013 +0000 @@ -0,0 +1,54 @@ +/* + * Embedded [v]sprintf() implementation by Michael Spacefalcon, + * loosely based on the 4.3BSD-Tahoe version. + * + * This module contains the integer conversion functions. + */ + +#include +#include +#include "defs.h" + +extern u_char * _sprintf_field(u_char *op, int width, int flags, int sign, + u_char *body, int size, int dprec, int fpprec); + +static const char lcdigits[] = "0123456789abcdef"; +static const char ucdigits[] = "0123456789ABCDEF"; + +u_char * +_sprintf_integer(u_char *op, int width, int flags, int sign, + unsigned number, int base, int prec) +{ + const char *digits; + char buf[12]; + char *t, *endp; + + /* + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ + if (prec >= 0) + flags &= ~ZEROPAD; + + if (flags & UPPERCASE) + digits = ucdigits; + else + digits = lcdigits; + + /* + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + */ + t = endp = buf + sizeof(buf); + if (number != 0 || prec != 0) { + do { + *--t = digits[number % base]; + number /= base; + } while (number); + if (flags & ALT && base == 8 && *t != '0') + *--t = '0'; /* octal leading 0 */ + } + return _sprintf_field(op, width, flags, sign, t, endp - t, prec, 0); +} diff -r ea819b60fe0d -r 7e45ada9c365 gsm-fw/sprintf/old/doprnt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/sprintf/old/doprnt.c Thu Nov 14 17:51:33 2013 +0000 @@ -0,0 +1,299 @@ +/* the guts of printf - this implementation came from 4.3BSD-Tahoe */ + +#include +#include +#include + +#define PUTC(ch) (*(*outptrp)++ = (ch)) + +#define ARG() \ + _ulong = flags&LONGINT ? va_arg(argp, long) : va_arg(argp, int); + +#define BUF 256 + +#define todigit(c) ((c) - '0') +#define tochar(n) ((n) + '0') + +/* have to deal with the negative buffer count kludge */ +#define NEGATIVE_COUNT_KLUDGE + +#define LONGINT 0x01 /* long integer */ +#define LONGDBL 0x02 /* long double; unimplemented */ +#define SHORTINT 0x04 /* short integer */ +#define ALT 0x08 /* alternate form */ +#define LADJUST 0x10 /* left adjustment */ +#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ +#define HEXPREFIX 0x40 /* add 0x or 0X prefix */ + +_doprnt(fmt0, argp, outptrp) + u_char *fmt0; + va_list argp; + char **outptrp; +{ + register u_char *fmt; /* format string */ + register int ch; /* character from fmt */ + register int cnt; /* return value accumulator */ + register int n; /* random handy integer */ + register char *t; /* buffer pointer */ + u_long _ulong; /* integer arguments %[diouxX] */ + int base; /* base for [diouxX] conversion */ + int dprec; /* decimal precision in [diouxX] */ + int fieldsz; /* field size expanded by sign, etc */ + int flags; /* flags as above */ + int prec; /* precision from format (%.3d), or -1 */ + int realsz; /* field size expanded by decimal precision */ + int size; /* size of converted field or string */ + int width; /* width from format (%8d), or 0 */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ + char softsign; /* temporary negative sign for floats */ + char *digs; /* digits for [diouxX] conversion */ + char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ + + fmt = fmt0; + digs = "0123456789abcdef"; + for (cnt = 0;; ++fmt) { + for (; (ch = *fmt) && ch != '%'; ++cnt, ++fmt) + PUTC(ch); + if (!ch) + return (cnt); + + flags = 0; dprec = 0; width = 0; + prec = -1; + sign = '\0'; + +rflag: switch (*++fmt) { + case ' ': + /* + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + /* + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + if ((width = va_arg(argp, int)) >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '.': + if (*++fmt == '*') + n = va_arg(argp, int); + else { + n = 0; + while (isascii(*fmt) && isdigit(*fmt)) + n = 10 * n + todigit(*fmt++); + --fmt; + } + prec = n < 0 ? -1 : n; + goto rflag; + case '0': + /* + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + flags |= ZEROPAD; + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + todigit(*fmt); + } while (isascii(*++fmt) && isdigit(*fmt)); + width = n; + --fmt; + goto rflag; + case 'L': + flags |= LONGDBL; + goto rflag; + case 'h': + flags |= SHORTINT; + goto rflag; + case 'l': + flags |= LONGINT; + goto rflag; + case 'c': + *(t = buf) = va_arg(argp, int); + size = 1; + sign = '\0'; + goto pforw; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + ARG(); + if ((long)_ulong < 0) { + _ulong = -_ulong; + sign = '-'; + } + base = 10; + goto number; + case 'n': + if (flags & LONGINT) + *va_arg(argp, long *) = cnt; + else if (flags & SHORTINT) + *va_arg(argp, short *) = cnt; + else + *va_arg(argp, int *) = cnt; + break; + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + ARG(); + base = 8; + goto nosign; + case 'p': + /* + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + /* NOSTRICT */ + _ulong = (u_long)va_arg(argp, void *); + base = 16; + goto nosign; + case 's': + if (!(t = va_arg(argp, char *))) + t = "(null)"; + if (prec >= 0) { + /* + * can't use strlen; can only look for the + * NUL in the first `prec' characters, and + * strlen() will go further. + */ + char *p; + + for (p = t, size = 0; size < prec; p++, size++) + if (*p == '\0') + break; + } else + size = strlen(t); + sign = '\0'; + goto pforw; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + ARG(); + base = 10; + goto nosign; + case 'X': + digs = "0123456789ABCDEF"; + /* FALLTHROUGH */ + case 'x': + ARG(); + base = 16; + /* leading 0x/X only if non-zero */ + if (flags & ALT && _ulong != 0) + flags |= HEXPREFIX; + + /* unsigned conversions */ +nosign: sign = '\0'; + /* + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ +number: if ((dprec = prec) >= 0) + flags &= ~ZEROPAD; + + /* + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + */ + t = buf + BUF; + if (_ulong != 0 || prec != 0) { + do { + *--t = digs[_ulong % base]; + _ulong /= base; + } while (_ulong); + digs = "0123456789abcdef"; + if (flags & ALT && base == 8 && *t != '0') + *--t = '0'; /* octal leading 0 */ + } + size = buf + BUF - t; + +pforw: + /* + * All reasonable formats wind up here. At this point, + * `t' points to a string which (if not flags&LADJUST) + * should be padded out to `width' places. If + * flags&ZEROPAD, it should first be prefixed by any + * sign or other prefix; otherwise, it should be blank + * padded before the prefix is emitted. After any + * left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print + * the string proper, then emit zeroes required by any + * leftover floating precision; finally, if LADJUST, + * pad with blanks. + */ + + /* + * compute actual size, so we know how much to pad + * fieldsz excludes decimal prec; realsz includes it + */ + fieldsz = size; + if (sign) + fieldsz++; + if (flags & HEXPREFIX) + fieldsz += 2; + realsz = dprec > fieldsz ? dprec : fieldsz; + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0 && width) + for (n = realsz; n < width; n++) + PUTC(' '); + /* prefix */ + if (sign) + PUTC(sign); + if (flags & HEXPREFIX) { + PUTC('0'); + PUTC((char)*fmt); + } + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) + for (n = realsz; n < width; n++) + PUTC('0'); + /* leading zeroes from decimal precision */ + for (n = fieldsz; n < dprec; n++) + PUTC('0'); + + for (n = size; --n >= 0; ) + PUTC(*t++); + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + for (n = realsz; n < width; n++) + PUTC(' '); + /* finally, adjust cnt */ + cnt += width > realsz ? width : realsz; + break; + case '\0': /* "%?" prints ?, unless ? is NULL */ + return (cnt); + default: + PUTC((char)*fmt); + cnt++; + } + } + /* NOTREACHED */ +} diff -r ea819b60fe0d -r 7e45ada9c365 gsm-fw/sprintf/old/doprnt.c.43tahoe --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/sprintf/old/doprnt.c.43tahoe Thu Nov 14 17:51:33 2013 +0000 @@ -0,0 +1,665 @@ +/* + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)doprnt.c 5.35 (Berkeley) 6/27/88"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include + +/* 11-bit exponent (VAX G floating point) is 308 decimal digits */ +#define MAXEXP 308 +/* 128 bit fraction takes up 39 decimal digits; max reasonable precision */ +#define MAXFRACT 39 + +#define DEFPREC 6 + +#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ + +#define PUTC(ch) (void) putc(ch, fp) + +#define ARG() \ + _ulong = flags&LONGINT ? va_arg(argp, long) : \ + flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int); + +#define todigit(c) ((c) - '0') +#define tochar(n) ((n) + '0') + +/* have to deal with the negative buffer count kludge */ +#define NEGATIVE_COUNT_KLUDGE + +#define LONGINT 0x01 /* long integer */ +#define LONGDBL 0x02 /* long double; unimplemented */ +#define SHORTINT 0x04 /* short integer */ +#define ALT 0x08 /* alternate form */ +#define LADJUST 0x10 /* left adjustment */ +#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ +#define HEXPREFIX 0x40 /* add 0x or 0X prefix */ + +_doprnt(fmt0, argp, fp) + u_char *fmt0; + va_list argp; + register FILE *fp; +{ + register u_char *fmt; /* format string */ + register int ch; /* character from fmt */ + register int cnt; /* return value accumulator */ + register int n; /* random handy integer */ + register char *t; /* buffer pointer */ + double _double; /* double precision arguments %[eEfgG] */ + u_long _ulong; /* integer arguments %[diouxX] */ + int base; /* base for [diouxX] conversion */ + int dprec; /* decimal precision in [diouxX] */ + int fieldsz; /* field size expanded by sign, etc */ + int flags; /* flags as above */ + int fpprec; /* `extra' floating precision in [eEfgG] */ + int prec; /* precision from format (%.3d), or -1 */ + int realsz; /* field size expanded by decimal precision */ + int size; /* size of converted field or string */ + int width; /* width from format (%8d), or 0 */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ + char softsign; /* temporary negative sign for floats */ + char *digs; /* digits for [diouxX] conversion */ + char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ + + if (fp->_flag & _IORW) { + fp->_flag |= _IOWRT; + fp->_flag &= ~(_IOEOF|_IOREAD); + } + if ((fp->_flag & _IOWRT) == 0) + return (EOF); + + fmt = fmt0; + digs = "0123456789abcdef"; + for (cnt = 0;; ++fmt) { + n = fp->_cnt; + for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%'; + ++cnt, ++fmt) + if (--n < 0 +#ifdef NEGATIVE_COUNT_KLUDGE + && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz) +#endif + || ch == '\n' && fp->_flag & _IOLBF) { + fp->_cnt = n; + fp->_ptr = t; + (void) _flsbuf((u_char)ch, fp); + n = fp->_cnt; + t = (char *)fp->_ptr; + } else + *t++ = ch; + fp->_cnt = n; + fp->_ptr = t; + if (!ch) + return (cnt); + + flags = 0; dprec = 0; fpprec = 0; width = 0; + prec = -1; + sign = '\0'; + +rflag: switch (*++fmt) { + case ' ': + /* + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + /* + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + if ((width = va_arg(argp, int)) >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '.': + if (*++fmt == '*') + n = va_arg(argp, int); + else { + n = 0; + while (isascii(*fmt) && isdigit(*fmt)) + n = 10 * n + todigit(*fmt++); + --fmt; + } + prec = n < 0 ? -1 : n; + goto rflag; + case '0': + /* + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + flags |= ZEROPAD; + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + todigit(*fmt); + } while (isascii(*++fmt) && isdigit(*fmt)); + width = n; + --fmt; + goto rflag; + case 'L': + flags |= LONGDBL; + goto rflag; + case 'h': + flags |= SHORTINT; + goto rflag; + case 'l': + flags |= LONGINT; + goto rflag; + case 'c': + *(t = buf) = va_arg(argp, int); + size = 1; + sign = '\0'; + goto pforw; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + ARG(); + if ((long)_ulong < 0) { + _ulong = -_ulong; + sign = '-'; + } + base = 10; + goto number; + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + _double = va_arg(argp, double); + /* + * don't do unrealistic precision; just pad it with + * zeroes later, so buffer size stays rational. + */ + if (prec > MAXFRACT) { + if (*fmt != 'g' && *fmt != 'G' || (flags&ALT)) + fpprec = prec - MAXFRACT; + prec = MAXFRACT; + } + else if (prec == -1) + prec = DEFPREC; + /* + * softsign avoids negative 0 if _double is < 0 and + * no significant digits will be shown + */ + if (_double < 0) { + softsign = '-'; + _double = -_double; + } + else + softsign = 0; + /* + * cvt may have to round up past the "start" of the + * buffer, i.e. ``intf("%.2f", (double)9.999);''; + * if the first char isn't NULL, it did. + */ + *buf = NULL; + size = cvt(_double, prec, flags, &softsign, *fmt, buf, + buf + sizeof(buf)); + if (softsign) + sign = '-'; + t = *buf ? buf : buf + 1; + goto pforw; + case 'n': + if (flags & LONGINT) + *va_arg(argp, long *) = cnt; + else if (flags & SHORTINT) + *va_arg(argp, short *) = cnt; + else + *va_arg(argp, int *) = cnt; + break; + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + ARG(); + base = 8; + goto nosign; + case 'p': + /* + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + /* NOSTRICT */ + _ulong = (u_long)va_arg(argp, void *); + base = 16; + goto nosign; + case 's': + if (!(t = va_arg(argp, char *))) + t = "(null)"; + if (prec >= 0) { + /* + * can't use strlen; can only look for the + * NUL in the first `prec' characters, and + * strlen() will go further. + */ + char *p, *memchr(); + + if (p = memchr(t, 0, prec)) { + size = p - t; + if (size > prec) + size = prec; + } else + size = prec; + } else + size = strlen(t); + sign = '\0'; + goto pforw; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + ARG(); + base = 10; + goto nosign; + case 'X': + digs = "0123456789ABCDEF"; + /* FALLTHROUGH */ + case 'x': + ARG(); + base = 16; + /* leading 0x/X only if non-zero */ + if (flags & ALT && _ulong != 0) + flags |= HEXPREFIX; + + /* unsigned conversions */ +nosign: sign = '\0'; + /* + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ +number: if ((dprec = prec) >= 0) + flags &= ~ZEROPAD; + + /* + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + */ + t = buf + BUF; + if (_ulong != 0 || prec != 0) { + do { + *--t = digs[_ulong % base]; + _ulong /= base; + } while (_ulong); + digs = "0123456789abcdef"; + if (flags & ALT && base == 8 && *t != '0') + *--t = '0'; /* octal leading 0 */ + } + size = buf + BUF - t; + +pforw: + /* + * All reasonable formats wind up here. At this point, + * `t' points to a string which (if not flags&LADJUST) + * should be padded out to `width' places. If + * flags&ZEROPAD, it should first be prefixed by any + * sign or other prefix; otherwise, it should be blank + * padded before the prefix is emitted. After any + * left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print + * the string proper, then emit zeroes required by any + * leftover floating precision; finally, if LADJUST, + * pad with blanks. + */ + + /* + * compute actual size, so we know how much to pad + * fieldsz excludes decimal prec; realsz includes it + */ + fieldsz = size + fpprec; + if (sign) + fieldsz++; + if (flags & HEXPREFIX) + fieldsz += 2; + realsz = dprec > fieldsz ? dprec : fieldsz; + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0 && width) + for (n = realsz; n < width; n++) + PUTC(' '); + /* prefix */ + if (sign) + PUTC(sign); + if (flags & HEXPREFIX) { + PUTC('0'); + PUTC((char)*fmt); + } + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) + for (n = realsz; n < width; n++) + PUTC('0'); + /* leading zeroes from decimal precision */ + for (n = fieldsz; n < dprec; n++) + PUTC('0'); + + /* the string or number proper */ + if (fp->_cnt - (n = size) >= 0 && + (fp->_flag & _IOLBF) == 0) { + fp->_cnt -= n; + bcopy(t, (char *)fp->_ptr, n); + fp->_ptr += n; + } else + while (--n >= 0) + PUTC(*t++); + /* trailing f.p. zeroes */ + while (--fpprec >= 0) + PUTC('0'); + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + for (n = realsz; n < width; n++) + PUTC(' '); + /* finally, adjust cnt */ + cnt += width > realsz ? width : realsz; + break; + case '\0': /* "%?" prints ?, unless ? is NULL */ + return (cnt); + default: + PUTC((char)*fmt); + cnt++; + } + } + /* NOTREACHED */ +} + +static +cvt(number, prec, flags, signp, fmtch, startp, endp) + double number; + register int prec; + int flags; + u_char fmtch; + char *signp, *startp, *endp; +{ + register char *p, *t; + register double fract; + int dotrim, expcnt, gformat; + double integer, tmp, modf(); + char *exponent(), *round(); + + dotrim = expcnt = gformat = 0; + fract = modf(number, &integer); + + /* get an extra slot for rounding. */ + t = ++startp; + + /* + * get integer portion of number; put into the end of the buffer; the + * .01 is added for modf(356.0 / 10, &integer) returning .59999999... + */ + for (p = endp - 1; integer; ++expcnt) { + tmp = modf(integer / 10, &integer); + *p-- = tochar((int)((tmp + .01) * 10)); + } + switch(fmtch) { + case 'f': + /* reverse integer into beginning of buffer */ + if (expcnt) + for (; ++p < endp; *t++ = *p); + else + *t++ = '0'; + /* + * if precision required or alternate flag set, add in a + * decimal point. + */ + if (prec || flags&ALT) + *t++ = '.'; + /* if requires more precision and some fraction left */ + if (fract) { + if (prec) + do { + fract = modf(fract * 10, &tmp); + *t++ = tochar((int)tmp); + } while (--prec && fract); + if (fract) + startp = round(fract, (int *)NULL, startp, + t - 1, (char)0, signp); + } + for (; prec--; *t++ = '0'); + break; + case 'e': + case 'E': +eformat: if (expcnt) { + *t++ = *++p; + if (prec || flags&ALT) + *t++ = '.'; + /* if requires more precision and some integer left */ + for (; prec && ++p < endp; --prec) + *t++ = *p; + /* + * if done precision and more of the integer component, + * round using it; adjust fract so we don't re-round + * later. + */ + if (!prec && ++p < endp) { + fract = 0; + startp = round((double)0, &expcnt, startp, + t - 1, *p, signp); + } + /* adjust expcnt for digit in front of decimal */ + --expcnt; + } + /* until first fractional digit, decrement exponent */ + else if (fract) { + /* adjust expcnt for digit in front of decimal */ + for (expcnt = -1;; --expcnt) { + fract = modf(fract * 10, &tmp); + if (tmp) + break; + } + *t++ = tochar((int)tmp); + if (prec || flags&ALT) + *t++ = '.'; + } + else { + *t++ = '0'; + if (prec || flags&ALT) + *t++ = '.'; + } + /* if requires more precision and some fraction left */ + if (fract) { + if (prec) + do { + fract = modf(fract * 10, &tmp); + *t++ = tochar((int)tmp); + } while (--prec && fract); + if (fract) + startp = round(fract, &expcnt, startp, + t - 1, (char)0, signp); + } + /* if requires more precision */ + for (; prec--; *t++ = '0'); + + /* unless alternate flag, trim any g/G format trailing 0's */ + if (gformat && !(flags&ALT)) { + while (t > startp && *--t == '0'); + if (*t == '.') + --t; + ++t; + } + t = exponent(t, expcnt, fmtch); + break; + case 'g': + case 'G': + /* a precision of 0 is treated as a precision of 1. */ + if (!prec) + ++prec; + /* + * ``The style used depends on the value converted; style e + * will be used only if the exponent resulting from the + * conversion is less than -4 or greater than the precision.'' + * -- ANSI X3J11 + */ + if (expcnt > prec || !expcnt && fract && fract < .0001) { + /* + * g/G format counts "significant digits, not digits of + * precision; for the e/E format, this just causes an + * off-by-one problem, i.e. g/G considers the digit + * before the decimal point significant and e/E doesn't + * count it as precision. + */ + --prec; + fmtch -= 2; /* G->E, g->e */ + gformat = 1; + goto eformat; + } + /* + * reverse integer into beginning of buffer, + * note, decrement precision + */ + if (expcnt) + for (; ++p < endp; *t++ = *p, --prec); + else + *t++ = '0'; + /* + * if precision required or alternate flag set, add in a + * decimal point. If no digits yet, add in leading 0. + */ + if (prec || flags&ALT) { + dotrim = 1; + *t++ = '.'; + } + else + dotrim = 0; + /* if requires more precision and some fraction left */ + if (fract) { + if (prec) { + do { + fract = modf(fract * 10, &tmp); + *t++ = tochar((int)tmp); + } while(!tmp); + while (--prec && fract) { + fract = modf(fract * 10, &tmp); + *t++ = tochar((int)tmp); + } + } + if (fract) + startp = round(fract, (int *)NULL, startp, + t - 1, (char)0, signp); + } + /* alternate format, adds 0's for precision, else trim 0's */ + if (flags&ALT) + for (; prec--; *t++ = '0'); + else if (dotrim) { + while (t > startp && *--t == '0'); + if (*t != '.') + ++t; + } + } + return(t - startp); +} + +static char * +round(fract, exp, start, end, ch, signp) + double fract; + int *exp; + register char *start, *end; + char ch, *signp; +{ + double tmp; + + if (fract) + (void)modf(fract * 10, &tmp); + else + tmp = todigit(ch); + if (tmp > 4) + for (;; --end) { + if (*end == '.') + --end; + if (++*end <= '9') + break; + *end = '0'; + if (end == start) { + if (exp) { /* e/E; increment exponent */ + *end = '1'; + ++*exp; + } + else { /* f; add extra digit */ + *--end = '1'; + --start; + } + break; + } + } + /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ + else if (*signp == '-') + for (;; --end) { + if (*end == '.') + --end; + if (*end != '0') + break; + if (end == start) + *signp = 0; + } + return(start); +} + +static char * +exponent(p, exp, fmtch) + register char *p; + register int exp; + u_char fmtch; +{ + register char *t; + char expbuf[MAXEXP]; + + *p++ = fmtch; + if (exp < 0) { + exp = -exp; + *p++ = '-'; + } + else + *p++ = '+'; + t = expbuf + MAXEXP; + if (exp > 9) { + do { + *--t = tochar(exp % 10); + } while ((exp /= 10) > 9); + *--t = tochar(exp); + for (; t < expbuf + MAXEXP; *p++ = *t++); + } + else { + *p++ = '0'; + *p++ = tochar(exp); + } + return(p); +} diff -r ea819b60fe0d -r 7e45ada9c365 gsm-fw/sprintf/old/sprintf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/sprintf/old/sprintf.c Thu Nov 14 17:51:33 2013 +0000 @@ -0,0 +1,16 @@ +#include + +int +sprintf(char *strdest, char *fmt, ...) +{ + va_list ap; + char *strptr; + int len; + + strptr = strdest; + va_start(ap, fmt); + len = _doprnt(fmt, ap, &strptr); + va_end(ap); + *strptr = '\0'; + return(len); +} diff -r ea819b60fe0d -r 7e45ada9c365 gsm-fw/sprintf/old/vsprintf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/sprintf/old/vsprintf.c Thu Nov 14 17:51:33 2013 +0000 @@ -0,0 +1,15 @@ +#include + +int +vsprintf(str, fmt, ap) + va_list ap; + char *str, *fmt; +{ + char *strptr; + int len; + + strptr = str; + len = _doprnt(fmt, ap, &strptr); + *strptr = '\0'; + return(len); +} diff -r ea819b60fe0d -r 7e45ada9c365 gsm-fw/sprintf/sprintf.c --- a/gsm-fw/sprintf/sprintf.c Tue Nov 12 16:57:08 2013 +0000 +++ b/gsm-fw/sprintf/sprintf.c Thu Nov 14 17:51:33 2013 +0000 @@ -4,13 +4,10 @@ sprintf(char *strdest, char *fmt, ...) { va_list ap; - char *strptr; int len; - strptr = strdest; va_start(ap, fmt); - len = _doprnt(fmt, ap, &strptr); + len = vsprintf(strdest, fmt, ap); va_end(ap); - *strptr = '\0'; return(len); } diff -r ea819b60fe0d -r 7e45ada9c365 gsm-fw/sprintf/vspcore.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/sprintf/vspcore.c Thu Nov 14 17:51:33 2013 +0000 @@ -0,0 +1,287 @@ +/* + * Embedded [v]sprintf() implementation by Michael Spacefalcon, + * loosely based on the 4.3BSD-Tahoe version. + * + * This module contains the core of the vsprintf() function, which may + * be either used directly by user code or called by the sprintf() + * trivial wrapper. + */ + +#include +#include +#include +#include "defs.h" + +extern u_char * _sprintf_integer(u_char *op, int width, int flags, int sign, + unsigned number, int base, int prec); +extern u_char * _sprintf_percent_f(u_char *op, int width, int flags, int sign, + double number, int prec); + +u_char * +_sprintf_field(u_char *op, int width, int flags, int sign, + u_char *body, int size, int dprec, int fpprec) +{ + int fieldsz; /* field size expanded by sign, etc */ + int realsz; /* field size expanded by decimal precision */ + int n; /* scratch */ + + /* + * All reasonable formats wind up here. At this point, + * `body' points to a string which (if not flags&LADJUST) + * should be padded out to `width' places. If + * flags&ZEROPAD, it should first be prefixed by any + * sign or other prefix; otherwise, it should be blank + * padded before the prefix is emitted. After any + * left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print + * the string proper, then emit zeroes required by any + * leftover floating precision; finally, if LADJUST, + * pad with blanks. + */ + + /* + * compute actual size, so we know how much to pad + * fieldsz excludes decimal prec; realsz includes it + */ + fieldsz = size + fpprec; + if (sign) + fieldsz++; + if (flags & HEXPREFIX) + fieldsz += 2; + realsz = dprec > fieldsz ? dprec : fieldsz; + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0 && width) + for (n = realsz; n < width; n++) + *op++ = ' '; + /* prefix */ + if (sign) + *op++ = sign; + if (flags & HEXPREFIX) { + *op++ = '0'; + *op++ = (flags & UPPERCASE) ? 'X' : 'x'; + } + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) + for (n = realsz; n < width; n++) + *op++ = '0'; + /* leading zeroes from decimal precision */ + for (n = fieldsz; n < dprec; n++) + *op++ = '0'; + + /* the string or number proper */ + bcopy(body, op, size); + op += size; + /* trailing f.p. zeroes */ + while (--fpprec >= 0) + *op++ = '0'; + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + for (n = realsz; n < width; n++) + *op++ = ' '; + + return(op); +} + +int +vsprintf(buf0, fmt0, argp) + u_char *buf0, *fmt0; + va_list argp; +{ + u_char *op; /* output buffer working ptr */ + u_char *fmt; /* format string working ptr */ + int ch; /* character from fmt */ + int n; /* scratch integer */ + char *t; /* scratch pointer */ + int flags; /* flags as above */ + int prec; /* precision from format (%.3d), or -1 */ + int width; /* width from format (%8d), or 0 */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ + unsigned un; /* unsigned number for conversion */ + + op = buf0; + for (fmt = fmt0; ; ++fmt) { + for (; (ch = *fmt) && ch != '%'; ++fmt) + *op++ = ch; + if (!ch) { +out: *op = '\0'; + return (op - buf0); + } + + flags = 0; width = 0; + prec = -1; + sign = '\0'; + +rflag: switch (*++fmt) { + case ' ': + /* + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + /* + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + if ((width = va_arg(argp, int)) >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '.': + if (*++fmt == '*') + n = va_arg(argp, int); + else { + n = 0; + while (isascii(*fmt) && isdigit(*fmt)) + n = 10 * n + todigit(*fmt++); + --fmt; + } + prec = n < 0 ? -1 : n; + goto rflag; + case '0': + /* + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + flags |= ZEROPAD; + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + todigit(*fmt); + } while (isascii(*++fmt) && isdigit(*fmt)); + width = n; + --fmt; + goto rflag; + case 'L': + flags |= LONGDBL; + goto rflag; + case 'h': + flags |= SHORTINT; + goto rflag; + case 'l': + flags |= LONGINT; + goto rflag; + case 'c': + /* + * XXX reusing a variable of type char + * for an unrelated purpose + */ + sign = (char) va_arg(argp, int); + op = _sprintf_field(op, width, flags, 0, &sign, 1, + 0, 0); + break; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + n = va_arg(argp, int); + if (n < 0) { + un = -n; + sign = '-'; + } else + un = n; + op = _sprintf_integer(op, width, flags, sign, un, 10, + prec); + break; +#if 0 // not yet implemented + case 'f': + op = _sprintf_percent_f(op, width, flags, sign, + va_arg(argp, double), prec); + break; +#endif + case 'n': + n = op - buf0; + if (flags & LONGINT) + *va_arg(argp, long *) = n; + else if (flags & SHORTINT) + *va_arg(argp, short *) = n; + else + *va_arg(argp, int *) = n; + break; + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + un = va_arg(argp, unsigned); + op = _sprintf_integer(op, width, flags, 0, un, 8, prec); + break; + case 'p': + /* + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + /* NOSTRICT */ + un = (unsigned)va_arg(argp, void *); + op = _sprintf_integer(op, width, flags | HEXPREFIX, 0, + un, 16, prec); + break; + case 's': + if (!(t = va_arg(argp, char *))) + t = "(null)"; + if (prec >= 0) { + /* + * can't use strlen; can only look for the + * NUL in the first `prec' characters, and + * strlen() will go further. + */ + char *p, *memchr(); + + if (p = memchr(t, 0, prec)) { + n = p - t; + if (n > prec) + n = prec; + } else + n = prec; + } else + n = strlen(t); + op = _sprintf_field(op, width, flags, 0, t, n, 0, 0); + break; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + un = va_arg(argp, unsigned); + op = _sprintf_integer(op, width, flags, 0, un, 10, + prec); + break; + case 'X': + flags |= UPPERCASE; + /* FALLTHROUGH */ + case 'x': + un = va_arg(argp, unsigned); + /* leading 0x/X only if non-zero */ + if (flags & ALT && un != 0) + flags |= HEXPREFIX; + op = _sprintf_integer(op, width, flags, 0, un, 16, + prec); + break; + case '\0': /* "%?" prints ?, unless ? is NULL */ + goto out; + default: + *op++ = *fmt; + } + } + /* NOTREACHED */ +} diff -r ea819b60fe0d -r 7e45ada9c365 gsm-fw/sprintf/vsprintf.c --- a/gsm-fw/sprintf/vsprintf.c Tue Nov 12 16:57:08 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -#include - -int -vsprintf(str, fmt, ap) - va_list ap; - char *str, *fmt; -{ - char *strptr; - int len; - - strptr = str; - len = _doprnt(fmt, ap, &strptr); - *strptr = '\0'; - return(len); -}