Пример #1
0
void
BetterStream::_vprintf (unsigned char in_progmem, const char *fmt, va_list ap)
{
        unsigned char c;        /* holds a char from the format string */
        unsigned char flags;
        unsigned char width;
        unsigned char prec;
        unsigned char buf[11];  /* size for -1 in octal, without '\0'   */

        for (;;) {

                /*
                 * Process non-format characters
                 */
                for (;;) {
                        c = GETBYTE (in_progmem, 1, fmt);
                        if (!c) return;
                        if (c == '%') {
                                c = GETBYTE (in_progmem, 1, fmt);
                                if (c != '%') break;
                        }
                        /* emit cr before lf to make most terminals happy */
                        if (c == '\n')
                                write('\r');
                        write(c);
                }

                flags = 0;
                width = 0;
                prec = 0;
                
                /*
                 * Process format adjustment characters, precision, width.
                 */
                do {
                        if (flags < FL_WIDTH) {
                                switch (c) {
                                case '0':
                                        flags |= FL_ZFILL;
                                        continue;
                                case '+':
                                        flags |= FL_PLUS;
                                        /* FALLTHROUGH */
                                case ' ':
                                        flags |= FL_SPACE;
                                        continue;
                                case '-':
                                        flags |= FL_LPAD;
                                        continue;
                                case '#':
                                        flags |= FL_ALT;
                                        continue;
                                }
                        }

                        if (flags < FL_LONG) {
                                if (c >= '0' && c <= '9') {
                                        c -= '0';
                                        if (flags & FL_PREC) {
                                                prec = 10*prec + c;
                                                continue;
                                        }
                                        width = 10*width + c;
                                        flags |= FL_WIDTH;
                                        continue;
                                }
                                if (c == '.') {
                                        if (flags & FL_PREC)
                                                return;
                                        flags |= FL_PREC;
                                        continue;
                                }
                                if (c == 'l') {
                                        flags |= FL_LONG;
                                        continue;
                                }
                                if (c == 'h')
                                        continue;
                        }
            
                        break;
                } while ( (c = GETBYTE (in_progmem, 1, fmt)) != 0);

                /*
                 * Handle floating-point formats E, F, G, e, f, g.
                 */
                if (c >= 'E' && c <= 'G') {
                        flags |= FL_FLTUPP;
                        c += 'e' - 'E';
                        goto flt_oper;

                } else if (c >= 'e' && c <= 'g') {

                        int exp;                /* exponent of master decimal digit     */
                        int n;
                        unsigned char vtype;    /* result of float value parse  */
                        unsigned char sign;     /* sign character (or 0)        */
                        unsigned char ndigs;

                        flags &= ~FL_FLTUPP;

                flt_oper:
                        if (!(flags & FL_PREC))
                                prec = 6;
                        flags &= ~(FL_FLTEXP | FL_FLTFIX);
                        if (c == 'e')
                                flags |= FL_FLTEXP;
                        else if (c == 'f')
                                flags |= FL_FLTFIX;
                        else if (prec > 0)
                                prec -= 1;

                        if (flags & FL_FLTFIX) {
                                vtype = 7;              /* 'prec' arg for 'ftoa_engine' */
                                ndigs = prec < 60 ? prec + 1 : 60;
                        } else {
                                if (prec > 7) prec = 7;
                                vtype = prec;
                                ndigs = 0;
                        }
                        exp = __ftoa_engine (va_arg(ap,double), (char *)buf, vtype, ndigs);
                        vtype = buf[0];
    
                        sign = 0;
                        if ((vtype & FTOA_MINUS) && !(vtype & FTOA_NAN))
                                sign = '-';
                        else if (flags & FL_PLUS)
                                sign = '+';
                        else if (flags & FL_SPACE)
                                sign = ' ';

                        if (vtype & (FTOA_NAN | FTOA_INF)) {
                                const char *p;
                                ndigs = sign ? 4 : 3;
                                if (width > ndigs) {
                                        width -= ndigs;
                                        if (!(flags & FL_LPAD)) {
                                                do {
                                                        write(' ');
                                                } while (--width);
                                        }
                                } else {
                                        width = 0;
                                }
                                if (sign)
                                        write(sign);
                                p = PSTR("inf");
                                if (vtype & FTOA_NAN)
                                        p = PSTR("nan");
                                while ( (ndigs = pgm_read_byte((const prog_char *)p)) != 0) {
                                        if (flags & FL_FLTUPP)
                                                ndigs += 'I' - 'i';
                                        write(ndigs);
                                        p++;
                                }
                                goto tail;
                        }

                        /* Output format adjustment, number of decimal digits in buf[] */
                        if (flags & FL_FLTFIX) {
                                ndigs += exp;
                                if ((vtype & FTOA_CARRY) && buf[1] == '1')
                                        ndigs -= 1;
                                if ((signed char)ndigs < 1)
                                        ndigs = 1;
                                else if (ndigs > 8)
                                        ndigs = 8;
                        } else if (!(flags & FL_FLTEXP)) {              /* 'g(G)' format */
                                if (exp <= prec && exp >= -4)
                                        flags |= FL_FLTFIX;
                                while (prec && buf[1+prec] == '0')
                                        prec--;
                                if (flags & FL_FLTFIX) {
                                        ndigs = prec + 1;               /* number of digits in buf */
                                        prec = prec > exp
                                                ? prec - exp : 0;       /* fractional part length  */
                                }
                        }
    
                        /* Conversion result length, width := free space length */
                        if (flags & FL_FLTFIX)
                                n = (exp>0 ? exp+1 : 1);
                        else
                                n = 5;          /* 1e+00 */
                        if (sign) n += 1;
                        if (prec) n += prec + 1;
                        width = width > n ? width - n : 0;
    
                        /* Output before first digit    */
                        if (!(flags & (FL_LPAD | FL_ZFILL))) {
                                while (width) {
                                        write(' ');
                                        width--;
                                }
                        }
                        if (sign) write(sign);
                        if (!(flags & FL_LPAD)) {
                                while (width) {
                                        write('0');
                                        width--;
                                }
                        }
    
                        if (flags & FL_FLTFIX) {                /* 'f' format           */

                                n = exp > 0 ? exp : 0;          /* exponent of left digit */
                                do {
                                        if (n == -1)
                                                write('.');
                                        flags = (n <= exp && n > exp - ndigs)
                                                ? buf[exp - n + 1] : '0';
                                        if (--n < -prec)
                                                break;
                                        write(flags);
                                } while (1);
                                if (n == exp
                                    && (buf[1] > '5'
                                        || (buf[1] == '5' && !(vtype & FTOA_CARRY))) )
                                        {
                                                flags = '1';
                                        }
                                write(flags);
        
                        } else {                                /* 'e(E)' format        */

                                /* mantissa     */
                                if (buf[1] != '1')
                                        vtype &= ~FTOA_CARRY;
                                write(buf[1]);
                                if (prec) {
                                        write('.');
                                        sign = 2;
                                        do {
                                                write(buf[sign++]);
                                        } while (--prec);
                                }

                                /* exponent     */
                                write(flags & FL_FLTUPP ? 'E' : 'e');
                                ndigs = '+';
                                if (exp < 0 || (exp == 0 && (vtype & FTOA_CARRY) != 0)) {
                                        exp = -exp;
                                        ndigs = '-';
                                }
                                write(ndigs);
                                for (ndigs = '0'; exp >= 10; exp -= 10)
                                        ndigs += 1;
                                write(ndigs);
                                write('0' + exp);
                        }

                        goto tail;
                }

                /*
                 * Handle string formats c, s, S.
                 */
                {
                        const char * pnt;
                        size_t size;

                        switch (c) {

                        case 'c':
                                buf[0] = va_arg (ap, int);
                                pnt = (char *)buf;
                                size = 1;
                                goto no_pgmstring;

                        case 's':
                                pnt = va_arg (ap, char *);
                                size = strnlen (pnt, (flags & FL_PREC) ? prec : ~0);
                        no_pgmstring:
                                flags &= ~FL_PGMSTRING;
                                goto str_lpad;

                        case 'S':
                        // pgmstring: // not yet used
                                pnt = va_arg (ap, char *);
                                size = strnlen_P (pnt, (flags & FL_PREC) ? prec : ~0);
                                flags |= FL_PGMSTRING;

                        str_lpad:
                                if (!(flags & FL_LPAD)) {
                                        while (size < width) {
                                                write(' ');
                                                width--;
                                        }
                                }
                                while (size) {
                                        write(GETBYTE (flags, FL_PGMSTRING, pnt));
                                        if (width) width -= 1;
                                        size -= 1;
                                }
                                goto tail;
                        }
                }

                /*
                 * Handle integer formats variations for d/i, u, o, p, x, X.
                 */
                if (c == 'd' || c == 'i') {
                        long x = (flags & FL_LONG) ? va_arg(ap,long) : va_arg(ap,int);
                        flags &= ~(FL_NEGATIVE | FL_ALT);
                        if (x < 0) {
                                x = -x;
                                flags |= FL_NEGATIVE;
                        }
                        c = __ultoa_invert (x, (char *)buf, 10) - (char *)buf;

                } else {
Пример #2
0
int
vfprintf (FILE * stream, const char *fmt, va_list ap)
{
    unsigned char c;		/* holds a char from the format string */
    unsigned char flags;
    unsigned char buf[11];	/* size for -1 in octal, without '\0'	*/

    stream->len = 0;

    if ((stream->flags & __SWR) == 0)
	return EOF;

    for (;;) {

	for (;;) {
	    c = *fmt++;
	    if (!c) goto ret;
	    if (c == '%') {
		c = *fmt++;
		if (c != '%') break;
	    }
	    putc (c, stream);
	}

	for (flags = 0;
	     !(flags & FL_LONG);	/* 'll' will detect as error	*/
	     c = *fmt++)
	{
	    if (c && strchr(" +-.0123456789h", c))
		continue;
	    if (c == '#') {
		flags |= FL_ALT;
		continue;
	    }
	    if (c == 'l') {
		flags |= FL_LONG;
		continue;
	    }
	    break;
	}

	/* Only a format character is valid.	*/

	if (c && strchr("EFGefg", c)) {
	    (void) va_arg (ap, double);
	    putc ('?', stream);
	    continue;
	}

	{
	    const char * pnt;

	    switch (c) {

	      case 'c':
		putc (va_arg (ap, int), stream);
		continue;

	      case 'S':
		/* FALLTHROUGH */
	      case 's':
		pnt = va_arg (ap, char *);
	        while ( (c = *pnt++) != 0)
		    putc (c, stream);
		continue;
	    }
	}

	if (c == 'd' || c == 'i') {
	    long x = (flags & FL_LONG) ? va_arg(ap,long) : va_arg(ap,int);
	    flags &= ~FL_ALT;
	    if (x < 0) {
		x = -x;
		/* `putc ('-', stream)' will considarably inlarge stack size.
		   So flag is used.	*/
		flags |= FL_NEGATIVE;
	    }
	    c = __ultoa_invert (x, (char *)buf, 10) - (char *)buf;

	} else {