commit 23d84ae09a8ac2101de2f095e50c8efb3b580738 Author: cfif Date: Mon Jun 2 13:26:42 2025 +0300 Init diff --git a/modular.json b/modular.json new file mode 100644 index 0000000..c71a3ef --- /dev/null +++ b/modular.json @@ -0,0 +1,23 @@ +{ + "dep": [ + { + "type": "git", + "provider": "Smart_Components_Aurus", + "repo": "SerialPortInterface" + }, + + { + "type": "git", + "provider": "Smart_Components_Aurus", + "repo": "SystemDelayInterface" + } + ], + "cmake": { + "inc_dirs": [ + "./" + ], + "srcs": [ + "./**.c" + ] + } +} \ No newline at end of file diff --git a/snprintf.c b/snprintf.c new file mode 100755 index 0000000..0eebfd2 --- /dev/null +++ b/snprintf.c @@ -0,0 +1,16 @@ +#include "stream.h" + +int +debug_sprintf (char *buf, int size, const char *fmt, ...) +{ + stream_buf_t u; + va_list args; + int err; + + stropen (&u, buf, size); + va_start (args, fmt); + err = vprintf (&u, fmt, args); + va_end (args); + strclose (&u); + return err; +} diff --git a/sscanf.c b/sscanf.c new file mode 100755 index 0000000..787eb02 --- /dev/null +++ b/sscanf.c @@ -0,0 +1,46 @@ +#include "stream.h" + +int debug_scanf (const unsigned char *buf, const char *fmt, ...) { + stream_buf_t u; + va_list args; + int err; + + stropen (&u, (unsigned char*) buf, 0); + va_start (args, fmt); + err = vscanf (&u, fmt, args); + va_end (args); + return err; +} + +#ifdef TEST +/* + * Testing sscanf(3). + */ +#undef printf +int printf (const char *format, ...); + +int +main (void) +{ + int i; + short s; + long l; + char a[20], b[20]; + + sscanf (" -123 +123 123xyzwvabcdefghijk ", " %d%ho%lx%5c%s", + &i, &s, &l, a, b); + printf ("i=%d s=%d l=%ld a=`%.5s' b=`%s'\n", + i, s, l, a, b); + + sscanf ("abc0123456789xyz", "abc%[0123456789]xyz", a); + printf ("a =`%s'\n", a); + + sscanf ("abc0123456789xyz", "abc%[0-9]xyz", a); + printf ("a =`%s'\n", a); + + sscanf ("abc0123456789xyz", "abc%[^a-z]xyz", a); + printf ("a =`%s'\n", a); + + return 0; +} +#endif diff --git a/stream.h b/stream.h new file mode 100755 index 0000000..a6edaba --- /dev/null +++ b/stream.h @@ -0,0 +1,91 @@ +#ifndef __STREAM_FAST_H_ +#define __STREAM_FAST_H_ 1 + +#include "SerialPortIO.h" +#include +#include +#define bool_t int + +#define FETCH_BYTE(p) (*(unsigned char*)(p)) + +int debug_printf (tSerialPortIO *portIo, const char *fmt, ...); + +/* + * Поток данных. + * Имеет интерфейс, состоящий из четырех процедур: + * выдача байта, опрос последнего выданного байта, + * прием байта, и опрос первого байта во входящей очереди без удаления. + */ +typedef struct _stream_t { + struct _stream_interface_t *interface; +} stream_t; + +typedef struct _stream_interface_t { + void (*putc) (stream_t *u, short c); + unsigned short (*getc) (stream_t *u); + int (*peekc) (stream_t *u); + void (*flush) (stream_t *u); + bool_t (*eof) (stream_t *u); + void (*close) (stream_t *u); +} stream_interface_t; + +#define to_stream(x) ((stream_t*)&(x)->interface) + +/* + * Методы приходится делать в виде макросов, + * т.к. необходимо приведение типа к родительскому. + */ +#define putchar(x,s) (x)->interface->putc(to_stream (x), s) +#define getchar(x) (x)->interface->getc(to_stream (x)) +#define peekchar(x) (x)->interface->peekc(to_stream (x)) +#define fflush(x) if ((x)->interface->flush) \ + (x)->interface->flush(to_stream (x)) +#define feof(x) ((x)->interface->eof ? \ + (x)->interface->eof(to_stream (x)) : 0) +#define fclose(x) if ((x)->interface->close) \ + (x)->interface->close(to_stream (x)) +#define freceiver(x) ((x)->interface->receiver ? \ + (x)->interface->receiver(to_stream (x)) : 0) + +#define puts(x,str) stream_puts (to_stream (x), str) +#define gets(x,str,n) stream_gets (to_stream (x), str, n) +#define vprintf(x,f,a) stream_vprintf (to_stream (x), f, a) +#define vscanf(x,f,a) stream_vscanf (to_stream (x), f, a) + +/* LY: умышленно вызываем ошибки там, где без необходимости вместо puts() используется printf() */ +#define printf(x,f,...) stream_printf (to_stream (x), f, ##__VA_ARGS__) + +void drain_input (stream_t *u); /* LY: чистит забуферизированный в потоке ввод. */ +int stream_puts (stream_t *u, const char *str); +unsigned char *stream_gets (stream_t *u, unsigned char *str, int len); +//int stream_printf (stream_t *u, const char *fmt, ...); +int stream_vprintf (stream_t *u, const char *fmt, va_list args); + +int stream_scanf (stream_t *u, const char *fmt, ...); +int stream_vscanf (stream_t *u, const char *fmt, va_list argp); + +int debug_sprintf (char *buf, int size, const char *fmt, ...); +//int vsnprintf (unsigned char *buf, int size, const char *fmt, va_list args); +int stream_serial_vprintf (tSerialPortIO *stream, char const *fmt, va_list args); +int debug_scanf (const unsigned char *buf, const char *fmt, ...); + +/* + * Вывод в строку как в поток. + * Для snprintf и т.п. + */ +typedef struct { + const stream_interface_t *interface; + unsigned char *buf; + int size; +} stream_buf_t; + +stream_t *stropen (stream_buf_t *u, unsigned char *buf, int size); +void strclose (stream_buf_t *u); + +/* + * LY: выдает результат vprintf без печати, т.е. считает кол-во символов. + */ +int vprintf_getlen (const char *fmt, va_list args); +extern stream_t null_stream; + +#endif /* __STREAM_FAST_H_ */ diff --git a/stropen.c b/stropen.c new file mode 100755 index 0000000..cea467b --- /dev/null +++ b/stropen.c @@ -0,0 +1,81 @@ +#include "stream.h" + +static void +buf_putchar (stream_buf_t *u, short c) +{ + if (u->size > 1) { + /* TODO: unicode to utf8 conversion. */ + *u->buf++ = c; + --u->size; + } +} + +static unsigned short +buf_getchar (stream_buf_t *u) +{ + /* TODO: utf8 to unicode conversion. */ + unsigned char c = *u->buf; + + if (! c) + return 0; + ++u->buf; + return c; +} + +static int +buf_peekchar (stream_buf_t *u) +{ + /* TODO: utf8 to unicode conversion. */ + unsigned char c = *u->buf; + + if (! c) + return -1; + return c; +} + +static bool_t +buf_feof (stream_buf_t *u) +{ + return ! *u->buf; +} + +static stream_interface_t buf_interface = { + .putc = +#if __STDC__ + (void (*) (stream_t*, short)) +#endif + buf_putchar, + .getc = +#if __STDC__ + (unsigned short (*) (stream_t*)) +#endif + buf_getchar, + .peekc = +#if __STDC__ + (int (*) (stream_t*)) +#endif + buf_peekchar, + .eof = +#if __STDC__ + (bool_t (*) (stream_t*)) +#endif + buf_feof, +}; + +stream_t * +stropen (stream_buf_t *u, unsigned char *buf, int size) +{ + u->interface = &buf_interface; + u->buf = buf; + u->size = size; + return (stream_t*) u; +} + +void +strclose (stream_buf_t *u) +{ + if (u->size > 0) { + *u->buf++ = 0; + --u->size; + } +} diff --git a/vprintf.c b/vprintf.c new file mode 100755 index 0000000..dc21b38 --- /dev/null +++ b/vprintf.c @@ -0,0 +1,1175 @@ +#include "stream.h" +#include + +/* Max number conversion buffer length: a long in base 2, plus NUL byte. */ +#define MAXNBUF (sizeof(long) * 8 + 1) + +static unsigned char *ksprintn (unsigned char *buf, unsigned long v, unsigned char base, + int width, unsigned char *lp); +static unsigned char mkhex (unsigned char ch); + +#if ARCH_HAVE_FPU +static int cvt (double number, int prec, int sharpflag, unsigned char *negp, + unsigned char fmtch, unsigned char *startp, unsigned char *endp); +#endif + +int +stream_vprintf (stream_t *stream, char const *fmt, va_list ap) +{ +#define PUTC(c) { putchar(stream,(unsigned char)(c)); ++retval; } + unsigned char nbuf [MAXNBUF], padding, *q; + const unsigned char *s; + unsigned char c, base, lflag, ladjust, sharpflag, neg, dot, size; + int n, width, dwidth, retval, uppercase, extrazeros, sign; + unsigned long ul; + + if (! stream) + return 0; + if (! fmt) + fmt = "(null)\n"; + + retval = 0; + for (;;) { + while ((c = FETCH_BYTE (fmt++)) != '%') { + if (! c) + return retval; + PUTC (c); + } + padding = ' '; + width = 0; extrazeros = 0; + lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; + sign = 0; dot = 0; uppercase = 0; dwidth = -1; +reswitch: switch (c = FETCH_BYTE (fmt++)) { + case '.': + dot = 1; + padding = ' '; + dwidth = 0; + goto reswitch; + + case '#': + sharpflag = 1; + goto reswitch; + + case '+': + sign = -1; + goto reswitch; + + case '-': + ladjust = 1; + goto reswitch; + + case '%': + PUTC (c); + break; + + case '*': + if (! dot) { + width = va_arg (ap, int); + if (width < 0) { + ladjust = !ladjust; + width = -width; + } + } else { + dwidth = va_arg (ap, int); + } + goto reswitch; + + case '0': + if (! dot) { + padding = '0'; + goto reswitch; + } + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + for (n=0; ; ++fmt) { + n = n * 10 + c - '0'; + c = FETCH_BYTE (fmt); + if (c < '0' || c > '9') + break; + } + if (dot) + dwidth = n; + else + width = n; + goto reswitch; + + case 'b': + ul = va_arg (ap, int); + s = va_arg (ap, const unsigned char*); + q = ksprintn (nbuf, ul, *s++, -1, 0); + while (*q) + PUTC (*q--); + + if (! ul) + break; + size = 0; + while (*s) { + n = *s++; + if ((char) (ul >> (n-1)) & 1) { + PUTC (size ? ',' : '<'); + for (; (n = *s) > ' '; ++s) + PUTC (n); + size = 1; + } else + while (*s > ' ') + ++s; + } + if (size) + PUTC ('>'); + break; + + case 'c': + if (! ladjust && width > 0) + while (width--) + PUTC (' '); + + PUTC (va_arg (ap, int)); + + if (ladjust && width > 0) + while (width--) + PUTC (' '); + break; + + case 'D': + s = va_arg (ap, const unsigned char*); + if (! width) + width = 16; + if (sharpflag) + padding = ':'; + while (width--) { + c = *s++; + PUTC (mkhex (c >> 4)); + PUTC (mkhex (c)); + if (width) + PUTC (padding); + } + break; + + case 'd': + ul = lflag ? va_arg (ap, long) : va_arg (ap, int); + if (! sign) sign = 1; + base = 10; + goto number; + + case 'l': + lflag = 1; + goto reswitch; + + case 'o': + ul = lflag ? va_arg (ap, unsigned long) : + va_arg (ap, unsigned int); + base = 8; + goto nosign; + + case 'p': + ul = (size_t) va_arg (ap, void*); + if (! ul) { + s = (const unsigned char*) "(nil)"; + goto const_string; + } + base = 16; + sharpflag = (width == 0); + goto nosign; + + case 'n': + ul = lflag ? va_arg (ap, unsigned long) : + sign ? (unsigned long) va_arg (ap, int) : + va_arg (ap, unsigned int); + base = 10; + goto number; + + case 'S': +#if __AVR__ + s = va_arg (ap, const unsigned char*); + if (! s) + s = (const unsigned char*) "(null)"; +const_string: + n = 0; + if (! dot) + while (FETCH_BYTE (s+n)) + ++n; + else + while (n 0) + while (width--) + PUTC (' '); + while (n--) + PUTC (FETCH_BYTE (s++)); + if (ladjust && width > 0) + while (width--) + PUTC (' '); + break; +#endif /* LY: AVR, and no break here! */ + + case 's': + s = va_arg (ap, unsigned char*); +#ifdef __AVR__ + if (! s) { + s = (const unsigned char*) "(null)"; + goto const_string; + } +#else + if (! s) + s = (const unsigned char*) "(null)"; +const_string: +#endif + if (! dot) + n = strlen (s); + else + for (n=0; n 0) + while (width--) + PUTC (' '); + while (n--) + PUTC (*s++); + if (ladjust && width > 0) + while (width--) + PUTC (' '); + break; + + case 'r': + /* Saturated counters. */ + base = 10; + if (lflag) { + ul = va_arg (ap, unsigned long); + if (ul == -1) { +cnt_unknown: if (ladjust) + PUTC ('-'); + while (--width > 0) + PUTC (' '); + if (! ladjust) + PUTC ('-'); + break; + } + if (ul >= -2) { + ul = -3; + neg = '>'; + goto nosign; + } + } else { + ul = va_arg (ap, unsigned int); + if (ul == (unsigned short) -1) + goto cnt_unknown; + if (ul >= (unsigned short) -2) { + ul = (unsigned short) -3; + neg = '>'; + goto nosign; + } + } + goto nosign; + + case 'u': + ul = lflag ? va_arg (ap, unsigned long) : + va_arg (ap, unsigned int); + base = 10; + goto nosign; + + case 'x': + case 'X': + ul = lflag ? va_arg (ap, unsigned long) : + va_arg (ap, unsigned int); + base = 16; + uppercase = (c == 'X'); + goto nosign; + case 'z': + case 'Z': + ul = lflag ? va_arg (ap, unsigned long) : + sign ? (unsigned long) va_arg (ap, int) : + va_arg (ap, unsigned int); + base = 16; + uppercase = (c == 'Z'); + goto number; + +nosign: sign = 0; +number: if (sign && ((long) ul != 0L)) { + if ((long) ul < 0L) { + neg = '-'; + ul = -(long) ul; + } else if (sign < 0) + neg = '+'; + } + if (dwidth >= (int) sizeof(nbuf)) { + extrazeros = dwidth - sizeof(nbuf) + 1; + dwidth = sizeof(nbuf) - 1; + } + s = ksprintn (nbuf, ul, base, dwidth, &size); + if (sharpflag && ul != 0) { + if (base == 8) + size++; + else if (base == 16) + size += 2; + } + if (neg) + size++; + + if (! ladjust && width && padding == ' ' && + (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + + if (neg) + PUTC (neg); + + if (sharpflag && ul != 0) { + if (base == 8) { + PUTC ('0'); + } else if (base == 16) { + PUTC ('0'); + PUTC (uppercase ? 'X' : 'x'); + } + } + + if (extrazeros) + do { + PUTC ('0'); + } while (--extrazeros > 0); + + if (! ladjust && width && (width -= size) > 0) + do { + PUTC (padding); + } while (--width > 0); + + for (; *s; --s) { + if (uppercase && *s>='a' && *s<='z') { + PUTC (*s + 'A' - 'a'); + } else { + PUTC (*s); + } + } + + if (ladjust && width && (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + break; +#if ARCH_HAVE_FPU + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': { + double d = va_arg (ap, double); + /* + * don't do unrealistic precision; just pad it with + * zeroes later, so buffer size stays rational. + */ + if (dwidth > DBL_DIG) { + if ((c != 'g' && c != 'G') || sharpflag) + extrazeros = dwidth - DBL_DIG; + dwidth = DBL_DIG; + } else if (dwidth == -1) { + dwidth = (lflag ? DBL_DIG : FLT_DIG); + } + /* + * softsign avoids negative 0 if d is < 0 and + * no significant digits will be shown + */ + if (d < 0) { + neg = 1; + d = -d; + } + /* + * 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. + */ + if (isnan (d) || isinf (d)) { + strcpy_flash (nbuf, isnan (d) ? "NaN" : "Inf"); + size = 3; + extrazeros = 0; + s = nbuf; + } else { + *nbuf = 0; + size = cvt (d, dwidth, sharpflag, &neg, c, + nbuf, nbuf + sizeof(nbuf) - 1); + if (*nbuf) { + s = nbuf; + nbuf [size] = 0; + } else { + s = nbuf + 1; + nbuf [size + 1] = 0; + } + } + if (neg) + size++; + if (! ladjust && width && padding == ' ' && + (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + + if (neg) + PUTC ('-'); + + if (! ladjust && width && (width -= size) > 0) + do { + PUTC (padding); + } while (--width > 0); + + for (; *s; ++s) { + if (extrazeros && (*s == 'e' || *s == 'E')) + do { + PUTC ('0'); + } while (--extrazeros > 0); + + PUTC (*s); + } + if (extrazeros) + do { + PUTC ('0'); + } while (--extrazeros > 0); + + if (ladjust && width && (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + break; + } +#endif + default: + PUTC ('%'); + if (lflag) + PUTC ('l'); + PUTC (c); + break; + } + } +} + +/* + * Put a NUL-terminated ASCII number (base <= 16) in a buffer in reverse + * order; return an optional length and a pointer to the last character + * written in the buffer (i.e., the first character of the string). + * The buffer pointed to by `nbuf' must have length >= MAXNBUF. + */ +static unsigned char * +ksprintn (unsigned char *nbuf, unsigned long ul, unsigned char base, int width, + unsigned char *lenp) +{ + unsigned char *p; + + p = nbuf; + *p = 0; + for (;;) { + *++p = mkhex (ul % base); + ul /= base; + if (--width > 0) + continue; + if (! ul) + break; + } + if (lenp) + *lenp = p - nbuf; + return (p); +} + +static unsigned char +mkhex (unsigned char ch) +{ + ch &= 15; + if (ch > 9) + return ch + 'a' - 10; + return ch + '0'; +} + +#if ARCH_HAVE_FPU +static unsigned char * +cvtround (double fract, int *exp, unsigned char *start, unsigned char *end, unsigned char ch, + unsigned char *negp) +{ + double tmp; + + if (fract) { + modf (fract * 10, &tmp); + } else { + tmp = ch - '0'; + } + 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; + } + } + } else if (*negp) { + /* + * ``"%.3f", (double)-0.0004'' gives you a negative 0. + */ + for (;; --end) { + if (*end == '.') { + --end; + } + if (*end != '0') { + break; + } + if (end == start) { + *negp = 0; + } + } + } + return start; +} + +static unsigned char * +exponent (unsigned char *p, int exp, unsigned char fmtch) +{ + unsigned char expbuf [8], *t; + + *p++ = fmtch; + if (exp < 0) { + exp = -exp; + *p++ = '-'; + } else { + *p++ = '+'; + } + t = expbuf + sizeof(expbuf); + if (exp > 9) { + do { + *--t = exp % 10 + '0'; + } while ((exp /= 10) > 9); + *--t = exp + '0'; + for (; t < expbuf + sizeof(expbuf); *p++ = *t++) + continue; + } else { + *p++ = '0'; + *p++ = exp + '0'; + } + return p; +} + +static int +cvt (double number, int prec, int sharpflag, unsigned char *negp, unsigned char fmtch, + unsigned char *startp, unsigned char *endp) +{ + unsigned char *p, *t; + double fract; + int dotrim, expcnt, gformat; + double integer, tmp; + + expcnt = 0; + 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-- = (int) ((tmp + .01) * 10) + '0'; + } + 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 || sharpflag) { + *t++ = '.'; + } + + /* + * if requires more precision and some fraction left + */ + if (fract) { + if (prec) { + do { + fract = modf (fract * 10, &tmp); + *t++ = (int)tmp + '0'; + } while (--prec && fract); + } + if (fract) { + startp = cvtround (fract, 0, startp, + t - 1, '0', negp); + } + } + for (; prec--; *t++ = '0'); + break; + case 'e': + case 'E': +eformat: if (expcnt) { + *t++ = *++p; + if (prec || sharpflag) { + *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 = cvtround (0, &expcnt, startp, + t - 1, *p, negp); + } + /* + * 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++ = (int)tmp + '0'; + if (prec || sharpflag) { + *t++ = '.'; + } + } else { + *t++ = '0'; + if (prec || sharpflag) { + *t++ = '.'; + } + } + /* + * if requires more precision and some fraction left + */ + if (fract) { + if (prec) { + do { + fract = modf (fract * 10, &tmp); + *t++ = (int)tmp + '0'; + } while (--prec && fract); + } + if (fract) { + startp = cvtround (fract, &expcnt, startp, + t - 1, '0', negp); + } + } + /* + * if requires more precision + */ + for (; prec--; *t++ = '0'); + + /* + * unless alternate flag, trim any g/G format trailing 0's + */ + if (gformat && ! sharpflag) { + 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 || sharpflag) { + dotrim = 1; + *t++ = '.'; + } else { + dotrim = 0; + } + /* + * if requires more precision and some fraction left + */ + while (prec && fract) { + fract = modf (fract * 10, &tmp); + *t++ = (int)tmp + '0'; + prec--; + } + if (fract) { + startp = cvtround (fract, 0, startp, t - 1, '0', negp); + } + /* + * alternate format, adds 0's for precision, else trim 0's + */ + if (sharpflag) { + for (; prec--; *t++ = '0'); + } else if (dotrim) { + while (t > startp && *--t == '0'); + if (*t != '.') { + ++t; + } + } + } + return(t - startp); +} +#endif /* ARCH_HAVE_FPU */ + +#ifdef TEST +/* + * Testing vprintf(3). + */ +#undef printf +#undef fclose +#undef fflush +#undef vprintf +#undef getchar +#undef putchar +#undef gets +#undef puts +#undef feof +#define snprintf snprintf_tmp +#define vsnprintf vsnprintf_tmp +#include +#undef snprintf +#undef vsnprintf + +#ifndef UCHAR_MAX +#define UCHAR_MAX ((unsigned char) -1) +#endif +#ifndef USHRT_MAX +#define USHRT_MAX ((unsigned short) -1) +#endif + +#define fputs(s,f) printstring (s) +#define puts(s) { printstring (s); write (1, "\n", 1); } + +unsigned write (int fd, const void *buf, unsigned count); + +static void +printchar (stream_t *stream, short ch) +{ + write (1, &ch, 1); +} + +static void +printstring (const char *str) +{ + write (1, str, strlen (str)); +} + +int +printf (const char *fmt, ...) +{ + static stream_interface_t output_interface = { + (void (*) (stream_t*, short)) printchar, + 0, 0, + }; + stream_t output = { &output_interface }; + va_list args; + int err; + + va_start (args, fmt); + err = stream_vprintf (&output, fmt, args); + va_end (args); + return err; +} + +static void rfg1 (void); +static void rfg2 (void); +static void rfg3 (void); + +static void fmtchk (const char *fmt) +{ + (void)fputs (fmt, stdout); + (void)printf (":\t`"); + (void)printf (fmt, 0x12); + (void)printf ("'\n"); +} + +static void fmtst1chk (const char *fmt) +{ + (void)fputs (fmt, stdout); + (void)printf (":\t`"); + (void)printf (fmt, 4, 0x12); + (void)printf ("'\n"); +} + +static void fmtst2chk (const char *fmt) +{ + (void)fputs (fmt, stdout); + (void)printf (":\t`"); + (void)printf (fmt, 4, 4, 0x12); + (void)printf ("'\n"); +} + +/* This page is covered by the following copyright: */ + +/* (C) Copyright C E Chew + * + * Feel free to copy, use and distribute this software provided: + * + * 1. you do not pretend that you wrote it + * 2. you leave this copyright notice intact. + */ + +/* + * Extracted from exercise.c for glibc-1.05 bug report by Bruce Evans. + */ + +#define DEC -123 +#define INT 255 +#define UNS (~0) + +/* Formatted Output Test + * + * This exercises the output formatting code. + */ + +static void fp_test (void) +{ + int i, j, k, l; + char buf[7]; + char *prefix = buf; + char tp[20]; + + puts ("\nFormatted output test"); + printf ("prefix 6d 6o 6x 6X 6u\n"); + strcpy (prefix, "%"); + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + for (k = 0; k < 2; k++) { + for (l = 0; l < 2; l++) { + strcpy (prefix, "%"); + if (i == 0) + strcat (prefix, "-"); + if (j == 0) + strcat (prefix, "+"); + if (k == 0) + strcat (prefix, "#"); + if (l == 0) + strcat (prefix, "0"); + printf ("%5s |", prefix); + strcpy (tp, prefix); + strcat (tp, "6d |"); + printf (tp, DEC); + strcpy (tp, prefix); + strcat (tp, "6o |"); + printf (tp, INT); + strcpy (tp, prefix); + strcat (tp, "6x |"); + printf (tp, INT); + strcpy (tp, prefix); + strcat (tp, "6X |"); + printf (tp, INT); + strcpy (tp, prefix); + strcat (tp, "6u |"); + printf (tp, UNS); + printf ("\n"); + } + } + } + } + printf ("%10s\n", (char *)0); + printf ("%-10s\n", (char *)0); +} + +int main () +{ + static char shortstr[] = "Hi, Z."; + static char longstr[] = "Good morning, Doctor Chandra. This is Hal. \ +I am ready for my first lesson today."; + int result = 0; + + fmtchk ("%.4x"); + fmtchk ("%04x"); + fmtchk ("%4.4x"); + fmtchk ("%04.4x"); + fmtchk ("%4.3x"); + fmtchk ("%04.3x"); + + fmtst1chk ("%.*x"); + fmtst1chk ("%0*x"); + fmtst2chk ("%*.*x"); + fmtst2chk ("%0*.*x"); + + printf ("binary format:\t\"%b\"\n", 55, "\20\7b7\6b6\5b5\4b4\3b3\2b2\1b1"); + printf ("nil pointer (padded):\t\"%10p\"\n", (void *)0); + + printf ("decimal negative:\t\"%d\"\n", -2345); + printf ("octal negative:\t\"%o\"\n", -2345); + printf ("hex negative:\t\"%x\"\n", -2345); + printf ("long decimal number:\t\"%ld\"\n", -123456L); + printf ("long octal negative:\t\"%lo\"\n", -2345L); + printf ("long unsigned decimal number:\t\"%lu\"\n", -123456L); + printf ("zero-padded LDN:\t\"%010ld\"\n", -123456L); + printf ("left-adjusted ZLDN:\t\"%-010ld\"\n", -123456L); + printf ("space-padded LDN:\t\"%10ld\"\n", -123456L); + printf ("left-adjusted SLDN:\t\"%-10ld\"\n", -123456L); + + printf ("zero-padded string:\t\"%010s\"\n", shortstr); + printf ("left-adjusted Z string:\t\"%-010s\"\n", shortstr); + printf ("space-padded string:\t\"%10s\"\n", shortstr); + printf ("left-adjusted S string:\t\"%-10s\"\n", shortstr); + printf ("null string:\t\"%s\"\n", (char *)0); + printf ("limited string:\t\"%.22s\"\n", longstr); + + printf ("e-style >= 1:\t\"%e\"\n", 12.34); + printf ("e-style >= .1:\t\"%e\"\n", 0.1234); + printf ("e-style < .1:\t\"%e\"\n", 0.001234); + printf ("e-style big:\t\"%.60e\"\n", 1e20); + printf ("e-style == .1:\t\"%e\"\n", 0.1); + printf ("f-style >= 1:\t\"%f\"\n", 12.34); + printf ("f-style >= .1:\t\"%f\"\n", 0.1234); + printf ("f-style < .1:\t\"%f\"\n", 0.001234); + printf ("g-style >= 1:\t\"%g\"\n", 12.34); + printf ("g-style >= .1:\t\"%g\"\n", 0.1234); + printf ("g-style < .1:\t\"%g\"\n", 0.001234); + printf ("g-style big:\t\"%.60g\"\n", 1e20); + + printf (" %6.5f\n", .099999999860301614); + printf (" %6.5f\n", .1); + printf ("x%5.4fx\n", .5); + + printf ("%#03x\n", 1); + + printf ("something really insane: %.10000f\n", 1.0); + + { + double d = FLT_MIN; + int niter = 17; + + while (niter-- != 0) + printf ("%.17e\n", d / 2); + fflush (stdout); + } + + printf ("%15.5e\n", 4.9406564584124654e-324); + +#define FORMAT "|%12.4f|%12.4e|%12.4g|\n" + printf (FORMAT, 0.0, 0.0, 0.0); + printf (FORMAT, 1.0, 1.0, 1.0); + printf (FORMAT, -1.0, -1.0, -1.0); + printf (FORMAT, 100.0, 100.0, 100.0); + printf (FORMAT, 1000.0, 1000.0, 1000.0); + printf (FORMAT, 10000.0, 10000.0, 10000.0); + printf (FORMAT, 12345.0, 12345.0, 12345.0); + printf (FORMAT, 100000.0, 100000.0, 100000.0); + printf (FORMAT, 123456.0, 123456.0, 123456.0); +#undef FORMAT + + { + char buf[20]; + char buf2[512]; + + printf ("snprintf (\"%%30s\", \"foo\") == %d, \"%.*s\"\n", + snprintf (buf, sizeof (buf), "%30s", "foo"), (int)sizeof (buf), + buf); + printf ("snprintf (\"%%.999999u\", 10) == %d\n", + snprintf (buf2, sizeof (buf2), "%.999999u", 10)); + } + + fp_test (); + + printf ("%e should be 1.234568e+06\n", 1234567.8); + printf ("%f should be 1234567.800000\n", 1234567.8); + printf ("%g should be 1.23457e+06\n", 1234567.8); + printf ("%g should be 123.456\n", 123.456); + printf ("%g should be 1e+06\n", 1000000.0); + printf ("%g should be 10\n", 10.0); + printf ("%g should be 0.02\n", 0.02); + + { + char buf[200]; + + snprintf (buf, sizeof(buf), "%*s%*s%*s", -1, "one", -20, "two", -30, "three"); + + result |= strcmp (buf, + "onetwo three "); + + puts (result != 0 ? "Test failed!" : "Test ok."); + } +#if 0 + { + char buf[200]; + + snprintf (buf, sizeof(buf), "%07Lo", 040000000000ll); + printf ("sprintf (buf, \"%%07Lo\", 040000000000ll) = %s", buf); + + if (strcmp (buf, "40000000000") != 0) { + result = 1; + fputs ("\tFAILED", stdout); + } + puts (""); + } + + printf ("printf (\"%%hhu\", %u) = %hhu\n", UCHAR_MAX + 2, UCHAR_MAX + 2); + printf ("printf (\"%%hu\", %u) = %hu\n", USHRT_MAX + 2, USHRT_MAX + 2); +#endif + puts ("--- Should be no further output. ---"); + rfg1 (); + rfg2 (); +#if 0 + rfg3 (); + { + char bytes[7]; + char buf[20]; + + memset (bytes, '\xff', sizeof bytes); + snprintf (buf, sizeof(buf), "foo%hhn\n", &bytes[3]); + if (bytes[0] != '\xff' || bytes[1] != '\xff' || bytes[2] != '\xff' + || bytes[4] != '\xff' || bytes[5] != '\xff' || bytes[6] != '\xff') { + puts ("%hhn overwrite more bytes"); + result = 1; + } + if (bytes[3] != 3) { + puts ("%hhn wrote incorrect value"); + result = 1; + } + } +#endif + return result != 0; +} + +static void rfg1 (void) +{ + char buf[100]; + + snprintf (buf, sizeof(buf), "%5.s", "xyz"); + if (strcmp (buf, " ") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " "); + snprintf (buf, sizeof(buf), "%5.f", 33.3); + if (strcmp (buf, " 33") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 33"); + snprintf (buf, sizeof(buf), "%8.e", 33.3e7); + if (strcmp (buf, " 3e+08") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 3e+08"); + snprintf (buf, sizeof(buf), "%8.E", 33.3e7); + if (strcmp (buf, " 3E+08") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 3E+08"); + snprintf (buf, sizeof(buf), "%.g", 33.3); + if (strcmp (buf, "3e+01") != 0) + printf ("got: '%s', expected: '%s'\n", buf, "3e+01"); + snprintf (buf, sizeof(buf), "%.G", 33.3); + if (strcmp (buf, "3E+01") != 0) + printf ("got: '%s', expected: '%s'\n", buf, "3E+01"); +} + +static void rfg2 (void) +{ + int prec; + char buf[100]; + + prec = 0; + snprintf (buf, sizeof(buf), "%.*g", prec, 3.3); + if (strcmp (buf, "3") != 0) + printf ("got: '%s', expected: '%s'\n", buf, "3"); + prec = 0; + snprintf (buf, sizeof(buf), "%.*G", prec, 3.3); + if (strcmp (buf, "3") != 0) + printf ("got: '%s', expected: '%s'\n", buf, "3"); + prec = 0; + snprintf (buf, sizeof(buf), "%7.*G", prec, 3.33); + if (strcmp (buf, " 3") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 3"); + prec = 3; + snprintf (buf, sizeof(buf), "%04.*o", prec, 33); + if (strcmp (buf, " 041") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 041"); + prec = 7; + snprintf (buf, sizeof(buf), "%09.*u", prec, 33); + if (strcmp (buf, " 0000033") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 0000033"); + prec = 3; + snprintf (buf, sizeof(buf), "%04.*x", prec, 33); + if (strcmp (buf, " 021") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 021"); + prec = 3; + snprintf (buf, sizeof(buf), "%04.*X", prec, 33); + if (strcmp (buf, " 021") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 021"); +} + +static void rfg3 (void) +{ + char buf[100]; + double g = 5.0000001; + unsigned long l = 1234567890; + double d = 321.7654321; + const char s[] = "test-string"; + int i = 12345; + int h = 1234; + + snprintf (buf, sizeof(buf), + "%1$*5$d %2$*6$hi %3$*7$lo %4$*8$f %9$*12$e %10$*13$g %11$*14$s", + i, h, l, d, 8, 5, 14, 14, d, g, s, 14, 3, 14); + if (strcmp (buf, + " 12345 1234 11145401322 321.765432 3.217654e+02 5 test-string") != 0) + printf ("got: '%s', expected: '%s'\n", buf, + " 12345 1234 11145401322 321.765432 3.217654e+02 5 test-string"); +} +#endif diff --git a/vprintfSerial.c b/vprintfSerial.c new file mode 100644 index 0000000..b261d70 --- /dev/null +++ b/vprintfSerial.c @@ -0,0 +1,1196 @@ +#include "cmsis_os.h" +#include "SerialPortIO.h" +#include "SystemDelayInterface.h" +#include +#include +#include +#include "stream.h" +#include + +/* Max number conversion buffer length: a long in base 2, plus NUL byte. */ +#define MAXNBUF (sizeof(long) * 8 + 1) + +static unsigned char *ksprintn (unsigned char *buf, unsigned long v, unsigned char base, + int width, unsigned char *lp); +static unsigned char mkhex (unsigned char ch); + +#define ARCH_HAVE_FPU 1 + +#if ARCH_HAVE_FPU +static int cvt_f (double number, int prec, int sharpflag, unsigned char *negp, + unsigned char fmtch, unsigned char *startp, unsigned char *endp); +#endif + +int stream_serial_vprintf (tSerialPortIO *stream, char const *fmt, va_list ap) +{ + //#define PUTC(c) { putchar(stream,(unsigned char)(c)); ++retval; } + #define PUTC(c) { unsigned char p = c; stream->transmit(stream->env, &p, 1, SystemWaitForever); ++retval; } + + unsigned char nbuf [MAXNBUF], padding, *q; + const unsigned char *s; + unsigned char c, base, lflag, ladjust, sharpflag, neg, dot, size; + int16_t n, width, dwidth, retval, uppercase, extrazeros, sign; + unsigned long ul; + + if (! stream) + return 0; + if (! fmt) + fmt = "(null)\n"; + + retval = 0; + for (;;) { + while ((c = FETCH_BYTE (fmt++)) != '%') { + if (! c) + return retval; + PUTC (c); + } + padding = ' '; + width = 0; extrazeros = 0; + lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; + sign = 0; dot = 0; uppercase = 0; dwidth = -1; +reswitch: switch (c = FETCH_BYTE (fmt++)) { + case '.': + dot = 1; + padding = ' '; + dwidth = 0; + goto reswitch; + + case '#': + sharpflag = 1; + goto reswitch; + + case '+': + sign = -1; + goto reswitch; + + case '-': + ladjust = 1; + goto reswitch; + + case '%': + PUTC (c); + break; + + case '*': + if (! dot) { + width = va_arg (ap, int); + if (width < 0) { + ladjust = !ladjust; + width = -width; + } + } else { + dwidth = va_arg (ap, int); + } + goto reswitch; + + case '0': + if (! dot) { + padding = '0'; + goto reswitch; + } + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + for (n=0; ; ++fmt) { + n = n * 10 + c - '0'; + c = FETCH_BYTE (fmt); + if (c < '0' || c > '9') + break; + } + if (dot) + dwidth = n; + else + width = n; + goto reswitch; + + case 'b': + ul = va_arg (ap, int); + s = va_arg (ap, const unsigned char*); + q = ksprintn (nbuf, ul, *s++, -1, 0); + while (*q) + PUTC (*q--); + + if (! ul) + break; + size = 0; + while (*s) { + n = *s++; + if ((char) (ul >> (n-1)) & 1) { + PUTC (size ? ',' : '<'); + for (; (n = *s) > ' '; ++s) + PUTC (n); + size = 1; + } else + while (*s > ' ') + ++s; + } + if (size) + PUTC ('>'); + break; + + case 'c': + if (! ladjust && width > 0) + while (width--) + PUTC (' '); + + PUTC (va_arg (ap, int)); + + if (ladjust && width > 0) + while (width--) + PUTC (' '); + break; + + case 'D': + s = va_arg (ap, const unsigned char*); + if (! width) + width = 16; + if (sharpflag) + padding = ':'; + while (width--) { + c = *s++; + PUTC (mkhex (c >> 4)); + PUTC (mkhex (c)); + if (width) + PUTC (padding); + } + break; + + case 'd': + ul = lflag ? va_arg (ap, long) : va_arg (ap, int); + if (! sign) sign = 1; + base = 10; + goto number; + + case 'l': + lflag = 1; + goto reswitch; + + case 'o': + ul = lflag ? va_arg (ap, unsigned long) : + va_arg (ap, unsigned int); + base = 8; + goto nosign; + + case 'p': + ul = (size_t) va_arg (ap, void*); + if (! ul) { + s = (const unsigned char*) "(nil)"; + goto const_string; + } + base = 16; + sharpflag = (width == 0); + goto nosign; + + case 'n': + ul = lflag ? va_arg (ap, unsigned long) : + sign ? (unsigned long) va_arg (ap, int) : + va_arg (ap, unsigned int); + base = 10; + goto number; + + case 'S': +#if __AVR__ + s = va_arg (ap, const unsigned char*); + if (! s) + s = (const unsigned char*) "(null)"; +const_string: + n = 0; + if (! dot) + while (FETCH_BYTE (s+n)) + ++n; + else + while (n 0) + while (width--) + PUTC (' '); + while (n--) + PUTC (FETCH_BYTE (s++)); + if (ladjust && width > 0) + while (width--) + PUTC (' '); + break; +#endif /* LY: AVR, and no break here! */ + + case 's': + s = va_arg (ap, unsigned char*); +#ifdef __AVR__ + if (! s) { + s = (const unsigned char*) "(null)"; + goto const_string; + } +#else + if (! s) + s = (const unsigned char*) "(null)"; +const_string: +#endif + if (! dot) + n = strlen (s); + else + for (n=0; n 0) + while (width--) + PUTC (' '); + while (n--) + PUTC (*s++); + if (ladjust && width > 0) + while (width--) + PUTC (' '); + break; + + case 'r': + /* Saturated counters. */ + base = 10; + if (lflag) { + ul = va_arg (ap, unsigned long); + if (ul == -1) { +cnt_unknown: if (ladjust) + PUTC ('-'); + while (--width > 0) + PUTC (' '); + if (! ladjust) + PUTC ('-'); + break; + } + if (ul >= -2) { + ul = -3; + neg = '>'; + goto nosign; + } + } else { + ul = va_arg (ap, unsigned int); + if (ul == (unsigned short) -1) + goto cnt_unknown; + if (ul >= (unsigned short) -2) { + ul = (unsigned short) -3; + neg = '>'; + goto nosign; + } + } + goto nosign; + + case 'u': + ul = lflag ? va_arg (ap, unsigned long) : + va_arg (ap, unsigned int); + base = 10; + goto nosign; + + case 'x': + case 'X': + ul = lflag ? va_arg (ap, unsigned long) : + va_arg (ap, unsigned int); + base = 16; + uppercase = (c == 'X'); + goto nosign; + case 'z': + case 'Z': + ul = lflag ? va_arg (ap, unsigned long) : + sign ? (unsigned long) va_arg (ap, int) : + va_arg (ap, unsigned int); + base = 16; + uppercase = (c == 'Z'); + goto number; + +nosign: sign = 0; +number: if (sign && ((long) ul != 0L)) { + if ((long) ul < 0L) { + neg = '-'; + ul = -(long) ul; + } else if (sign < 0) + neg = '+'; + } + if (dwidth >= (int) sizeof(nbuf)) { + extrazeros = dwidth - sizeof(nbuf) + 1; + dwidth = sizeof(nbuf) - 1; + } + s = ksprintn (nbuf, ul, base, dwidth, &size); + if (sharpflag && ul != 0) { + if (base == 8) + size++; + else if (base == 16) + size += 2; + } + if (neg) + size++; + + if (! ladjust && width && padding == ' ' && + (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + + if (neg) + PUTC (neg); + + if (sharpflag && ul != 0) { + if (base == 8) { + PUTC ('0'); + } else if (base == 16) { + PUTC ('0'); + PUTC (uppercase ? 'X' : 'x'); + } + } + + if (extrazeros) + do { + PUTC ('0'); + } while (--extrazeros > 0); + + if (! ladjust && width && (width -= size) > 0) + do { + PUTC (padding); + } while (--width > 0); + + for (; *s; --s) { + if (uppercase && *s>='a' && *s<='z') { + PUTC (*s + 'A' - 'a'); + } else { + PUTC (*s); + } + } + + if (ladjust && width && (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + break; +#if ARCH_HAVE_FPU + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': { + double d = va_arg (ap, double); + /* + * don't do unrealistic precision; just pad it with + * zeroes later, so buffer size stays rational. + */ + if (dwidth > DBL_DIG) { + if ((c != 'g' && c != 'G') || sharpflag) + extrazeros = dwidth - DBL_DIG; + dwidth = DBL_DIG; + } else if (dwidth == -1) { + dwidth = (lflag ? DBL_DIG : FLT_DIG); + } + /* + * softsign avoids negative 0 if d is < 0 and + * no significant digits will be shown + */ + if (d < 0) { + neg = 1; + d = -d; + } + /* + * 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. + */ + if (isnan (d) || isinf (d)) { + strcpy (nbuf, isnan (d) ? "NaN" : "Inf"); + size = 3; + extrazeros = 0; + s = nbuf; + } else { + *nbuf = 0; + size = cvt_f (d, dwidth, sharpflag, &neg, c, + nbuf, nbuf + sizeof(nbuf) - 1); + if (*nbuf) { + s = nbuf; + nbuf [size] = 0; + } else { + s = nbuf + 1; + nbuf [size + 1] = 0; + } + } + if (neg) + size++; + if (! ladjust && width && padding == ' ' && + (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + + if (neg) + PUTC ('-'); + + if (! ladjust && width && (width -= size) > 0) + do { + PUTC (padding); + } while (--width > 0); + + for (; *s; ++s) { + if (extrazeros && (*s == 'e' || *s == 'E')) + do { + PUTC ('0'); + } while (--extrazeros > 0); + + PUTC (*s); + } + if (extrazeros) + do { + PUTC ('0'); + } while (--extrazeros > 0); + + if (ladjust && width && (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + break; + } +#endif + default: + PUTC ('%'); + if (lflag) + PUTC ('l'); + PUTC (c); + break; + } + } +} + +/* + * Put a NUL-terminated ASCII number (base <= 16) in a buffer in reverse + * order; return an optional length and a pointer to the last character + * written in the buffer (i.e., the first character of the string). + * The buffer pointed to by `nbuf' must have length >= MAXNBUF. + */ +static unsigned char * +ksprintn (unsigned char *nbuf, unsigned long ul, unsigned char base, int width, + unsigned char *lenp) +{ + unsigned char *p; + + p = nbuf; + *p = 0; + for (;;) { + *++p = mkhex (ul % base); + ul /= base; + if (--width > 0) + continue; + if (! ul) + break; + } + if (lenp) + *lenp = p - nbuf; + return (p); +} + +static unsigned char +mkhex (unsigned char ch) +{ + ch &= 15; + if (ch > 9) + return ch + 'a' - 10; + return ch + '0'; +} + +#if ARCH_HAVE_FPU +static unsigned char * +cvtround_f (double fract, int *exp, unsigned char *start, unsigned char *end, unsigned char ch, + unsigned char *negp) +{ + double tmp; + + if (fract) { + modf (fract * 10, &tmp); + } else { + tmp = ch - '0'; + } + 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; + } + } + } else if (*negp) { + /* + * ``"%.3f", (double)-0.0004'' gives you a negative 0. + */ + for (;; --end) { + if (*end == '.') { + --end; + } + if (*end != '0') { + break; + } + if (end == start) { + *negp = 0; + } + } + } + return start; +} + +static unsigned char * +exponent (unsigned char *p, int exp, unsigned char fmtch) +{ + unsigned char expbuf [8], *t; + + *p++ = fmtch; + if (exp < 0) { + exp = -exp; + *p++ = '-'; + } else { + *p++ = '+'; + } + t = expbuf + sizeof(expbuf); + if (exp > 9) { + do { + *--t = exp % 10 + '0'; + } while ((exp /= 10) > 9); + *--t = exp + '0'; + for (; t < expbuf + sizeof(expbuf); *p++ = *t++) + continue; + } else { + *p++ = '0'; + *p++ = exp + '0'; + } + return p; +} + +static int +cvt_f (double number, int prec, int sharpflag, unsigned char *negp, unsigned char fmtch, + unsigned char *startp, unsigned char *endp) +{ + unsigned char *p, *t; + double fract; + int dotrim, expcnt, gformat; + double integer, tmp; + + expcnt = 0; + 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-- = (int) ((tmp + .01) * 10) + '0'; + } + 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 || sharpflag) { + *t++ = '.'; + } + + /* + * if requires more precision and some fraction left + */ + if (fract) { + if (prec) { + do { + fract = modf (fract * 10, &tmp); + *t++ = (int)tmp + '0'; + } while (--prec && fract); + } + if (fract) { + startp = cvtround_f (fract, 0, startp, + t - 1, '0', negp); + } + } + for (; prec--; *t++ = '0'); + break; + case 'e': + case 'E': +eformat: if (expcnt) { + *t++ = *++p; + if (prec || sharpflag) { + *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 = cvtround_f (0, &expcnt, startp, + t - 1, *p, negp); + } + /* + * 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++ = (int)tmp + '0'; + if (prec || sharpflag) { + *t++ = '.'; + } + } else { + *t++ = '0'; + if (prec || sharpflag) { + *t++ = '.'; + } + } + /* + * if requires more precision and some fraction left + */ + if (fract) { + if (prec) { + do { + fract = modf (fract * 10, &tmp); + *t++ = (int)tmp + '0'; + } while (--prec && fract); + } + if (fract) { + startp = cvtround_f (fract, &expcnt, startp, + t - 1, '0', negp); + } + } + /* + * if requires more precision + */ + for (; prec--; *t++ = '0'); + + /* + * unless alternate flag, trim any g/G format trailing 0's + */ + if (gformat && ! sharpflag) { + 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 || sharpflag) { + dotrim = 1; + *t++ = '.'; + } else { + dotrim = 0; + } + /* + * if requires more precision and some fraction left + */ + while (prec && fract) { + fract = modf (fract * 10, &tmp); + *t++ = (int)tmp + '0'; + prec--; + } + if (fract) { + startp = cvtround_f (fract, 0, startp, t - 1, '0', negp); + } + /* + * alternate format, adds 0's for precision, else trim 0's + */ + if (sharpflag) { + for (; prec--; *t++ = '0'); + } else if (dotrim) { + while (t > startp && *--t == '0'); + if (*t != '.') { + ++t; + } + } + } + return(t - startp); +} +#endif /* ARCH_HAVE_FPU */ + + +int debug_printf (tSerialPortIO *portIo, const char *fmt, ...) { + va_list args; + int err; + + va_start (args, fmt); + err = stream_serial_vprintf(portIo, fmt, args); + va_end (args); + + return err; +} + +#ifdef TEST +/* + * Testing vprintf(3). + */ +#undef printf +#undef fclose +#undef fflush +#undef vprintf +#undef getchar +#undef putchar +#undef gets +#undef puts +#undef feof +#define snprintf snprintf_tmp +#define vsnprintf vsnprintf_tmp +#include +#undef snprintf +#undef vsnprintf + +#ifndef UCHAR_MAX +#define UCHAR_MAX ((unsigned char) -1) +#endif +#ifndef USHRT_MAX +#define USHRT_MAX ((unsigned short) -1) +#endif + +#define fputs(s,f) printstring (s) +#define puts(s) { printstring (s); write (1, "\n", 1); } + +unsigned write (int fd, const void *buf, unsigned count); + +static void +printchar (stream_t *stream, short ch) +{ + write (1, &ch, 1); +} + +static void +printstring (const char *str) +{ + write (1, str, strlen (str)); +} + +int +printf (const char *fmt, ...) +{ + static stream_interface_t output_interface = { + (void (*) (stream_t*, short)) printchar, + 0, 0, + }; + stream_t output = { &output_interface }; + va_list args; + int err; + + va_start (args, fmt); + err = stream_vprintf (&output, fmt, args); + va_end (args); + return err; +} + +static void rfg1 (void); +static void rfg2 (void); +static void rfg3 (void); + +static void fmtchk (const char *fmt) +{ + (void)fputs (fmt, stdout); + (void)printf (":\t`"); + (void)printf (fmt, 0x12); + (void)printf ("'\n"); +} + +static void fmtst1chk (const char *fmt) +{ + (void)fputs (fmt, stdout); + (void)printf (":\t`"); + (void)printf (fmt, 4, 0x12); + (void)printf ("'\n"); +} + +static void fmtst2chk (const char *fmt) +{ + (void)fputs (fmt, stdout); + (void)printf (":\t`"); + (void)printf (fmt, 4, 4, 0x12); + (void)printf ("'\n"); +} + +/* This page is covered by the following copyright: */ + +/* (C) Copyright C E Chew + * + * Feel free to copy, use and distribute this software provided: + * + * 1. you do not pretend that you wrote it + * 2. you leave this copyright notice intact. + */ + +/* + * Extracted from exercise.c for glibc-1.05 bug report by Bruce Evans. + */ + +#define DEC -123 +#define INT 255 +#define UNS (~0) + +/* Formatted Output Test + * + * This exercises the output formatting code. + */ + +static void fp_test (void) +{ + int i, j, k, l; + char buf[7]; + char *prefix = buf; + char tp[20]; + + puts ("\nFormatted output test"); + printf ("prefix 6d 6o 6x 6X 6u\n"); + strcpy (prefix, "%"); + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + for (k = 0; k < 2; k++) { + for (l = 0; l < 2; l++) { + strcpy (prefix, "%"); + if (i == 0) + strcat (prefix, "-"); + if (j == 0) + strcat (prefix, "+"); + if (k == 0) + strcat (prefix, "#"); + if (l == 0) + strcat (prefix, "0"); + printf ("%5s |", prefix); + strcpy (tp, prefix); + strcat (tp, "6d |"); + printf (tp, DEC); + strcpy (tp, prefix); + strcat (tp, "6o |"); + printf (tp, INT); + strcpy (tp, prefix); + strcat (tp, "6x |"); + printf (tp, INT); + strcpy (tp, prefix); + strcat (tp, "6X |"); + printf (tp, INT); + strcpy (tp, prefix); + strcat (tp, "6u |"); + printf (tp, UNS); + printf ("\n"); + } + } + } + } + printf ("%10s\n", (char *)0); + printf ("%-10s\n", (char *)0); +} + +int main () +{ + static char shortstr[] = "Hi, Z."; + static char longstr[] = "Good morning, Doctor Chandra. This is Hal. \ +I am ready for my first lesson today."; + int result = 0; + + fmtchk ("%.4x"); + fmtchk ("%04x"); + fmtchk ("%4.4x"); + fmtchk ("%04.4x"); + fmtchk ("%4.3x"); + fmtchk ("%04.3x"); + + fmtst1chk ("%.*x"); + fmtst1chk ("%0*x"); + fmtst2chk ("%*.*x"); + fmtst2chk ("%0*.*x"); + + printf ("binary format:\t\"%b\"\n", 55, "\20\7b7\6b6\5b5\4b4\3b3\2b2\1b1"); + printf ("nil pointer (padded):\t\"%10p\"\n", (void *)0); + + printf ("decimal negative:\t\"%d\"\n", -2345); + printf ("octal negative:\t\"%o\"\n", -2345); + printf ("hex negative:\t\"%x\"\n", -2345); + printf ("long decimal number:\t\"%ld\"\n", -123456L); + printf ("long octal negative:\t\"%lo\"\n", -2345L); + printf ("long unsigned decimal number:\t\"%lu\"\n", -123456L); + printf ("zero-padded LDN:\t\"%010ld\"\n", -123456L); + printf ("left-adjusted ZLDN:\t\"%-010ld\"\n", -123456L); + printf ("space-padded LDN:\t\"%10ld\"\n", -123456L); + printf ("left-adjusted SLDN:\t\"%-10ld\"\n", -123456L); + + printf ("zero-padded string:\t\"%010s\"\n", shortstr); + printf ("left-adjusted Z string:\t\"%-010s\"\n", shortstr); + printf ("space-padded string:\t\"%10s\"\n", shortstr); + printf ("left-adjusted S string:\t\"%-10s\"\n", shortstr); + printf ("null string:\t\"%s\"\n", (char *)0); + printf ("limited string:\t\"%.22s\"\n", longstr); + + printf ("e-style >= 1:\t\"%e\"\n", 12.34); + printf ("e-style >= .1:\t\"%e\"\n", 0.1234); + printf ("e-style < .1:\t\"%e\"\n", 0.001234); + printf ("e-style big:\t\"%.60e\"\n", 1e20); + printf ("e-style == .1:\t\"%e\"\n", 0.1); + printf ("f-style >= 1:\t\"%f\"\n", 12.34); + printf ("f-style >= .1:\t\"%f\"\n", 0.1234); + printf ("f-style < .1:\t\"%f\"\n", 0.001234); + printf ("g-style >= 1:\t\"%g\"\n", 12.34); + printf ("g-style >= .1:\t\"%g\"\n", 0.1234); + printf ("g-style < .1:\t\"%g\"\n", 0.001234); + printf ("g-style big:\t\"%.60g\"\n", 1e20); + + printf (" %6.5f\n", .099999999860301614); + printf (" %6.5f\n", .1); + printf ("x%5.4fx\n", .5); + + printf ("%#03x\n", 1); + + printf ("something really insane: %.10000f\n", 1.0); + + { + double d = FLT_MIN; + int niter = 17; + + while (niter-- != 0) + printf ("%.17e\n", d / 2); + fflush (stdout); + } + + printf ("%15.5e\n", 4.9406564584124654e-324); + +#define FORMAT "|%12.4f|%12.4e|%12.4g|\n" + printf (FORMAT, 0.0, 0.0, 0.0); + printf (FORMAT, 1.0, 1.0, 1.0); + printf (FORMAT, -1.0, -1.0, -1.0); + printf (FORMAT, 100.0, 100.0, 100.0); + printf (FORMAT, 1000.0, 1000.0, 1000.0); + printf (FORMAT, 10000.0, 10000.0, 10000.0); + printf (FORMAT, 12345.0, 12345.0, 12345.0); + printf (FORMAT, 100000.0, 100000.0, 100000.0); + printf (FORMAT, 123456.0, 123456.0, 123456.0); +#undef FORMAT + + { + char buf[20]; + char buf2[512]; + + printf ("snprintf (\"%%30s\", \"foo\") == %d, \"%.*s\"\n", + snprintf (buf, sizeof (buf), "%30s", "foo"), (int)sizeof (buf), + buf); + printf ("snprintf (\"%%.999999u\", 10) == %d\n", + snprintf (buf2, sizeof (buf2), "%.999999u", 10)); + } + + fp_test (); + + printf ("%e should be 1.234568e+06\n", 1234567.8); + printf ("%f should be 1234567.800000\n", 1234567.8); + printf ("%g should be 1.23457e+06\n", 1234567.8); + printf ("%g should be 123.456\n", 123.456); + printf ("%g should be 1e+06\n", 1000000.0); + printf ("%g should be 10\n", 10.0); + printf ("%g should be 0.02\n", 0.02); + + { + char buf[200]; + + snprintf (buf, sizeof(buf), "%*s%*s%*s", -1, "one", -20, "two", -30, "three"); + + result |= strcmp (buf, + "onetwo three "); + + puts (result != 0 ? "Test failed!" : "Test ok."); + } +#if 0 + { + char buf[200]; + + snprintf (buf, sizeof(buf), "%07Lo", 040000000000ll); + printf ("sprintf (buf, \"%%07Lo\", 040000000000ll) = %s", buf); + + if (strcmp (buf, "40000000000") != 0) { + result = 1; + fputs ("\tFAILED", stdout); + } + puts (""); + } + + printf ("printf (\"%%hhu\", %u) = %hhu\n", UCHAR_MAX + 2, UCHAR_MAX + 2); + printf ("printf (\"%%hu\", %u) = %hu\n", USHRT_MAX + 2, USHRT_MAX + 2); +#endif + puts ("--- Should be no further output. ---"); + rfg1 (); + rfg2 (); +#if 0 + rfg3 (); + { + char bytes[7]; + char buf[20]; + + memset (bytes, '\xff', sizeof bytes); + snprintf (buf, sizeof(buf), "foo%hhn\n", &bytes[3]); + if (bytes[0] != '\xff' || bytes[1] != '\xff' || bytes[2] != '\xff' + || bytes[4] != '\xff' || bytes[5] != '\xff' || bytes[6] != '\xff') { + puts ("%hhn overwrite more bytes"); + result = 1; + } + if (bytes[3] != 3) { + puts ("%hhn wrote incorrect value"); + result = 1; + } + } +#endif + return result != 0; +} + +static void rfg1 (void) +{ + char buf[100]; + + snprintf (buf, sizeof(buf), "%5.s", "xyz"); + if (strcmp (buf, " ") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " "); + snprintf (buf, sizeof(buf), "%5.f", 33.3); + if (strcmp (buf, " 33") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 33"); + snprintf (buf, sizeof(buf), "%8.e", 33.3e7); + if (strcmp (buf, " 3e+08") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 3e+08"); + snprintf (buf, sizeof(buf), "%8.E", 33.3e7); + if (strcmp (buf, " 3E+08") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 3E+08"); + snprintf (buf, sizeof(buf), "%.g", 33.3); + if (strcmp (buf, "3e+01") != 0) + printf ("got: '%s', expected: '%s'\n", buf, "3e+01"); + snprintf (buf, sizeof(buf), "%.G", 33.3); + if (strcmp (buf, "3E+01") != 0) + printf ("got: '%s', expected: '%s'\n", buf, "3E+01"); +} + +static void rfg2 (void) +{ + int prec; + char buf[100]; + + prec = 0; + snprintf (buf, sizeof(buf), "%.*g", prec, 3.3); + if (strcmp (buf, "3") != 0) + printf ("got: '%s', expected: '%s'\n", buf, "3"); + prec = 0; + snprintf (buf, sizeof(buf), "%.*G", prec, 3.3); + if (strcmp (buf, "3") != 0) + printf ("got: '%s', expected: '%s'\n", buf, "3"); + prec = 0; + snprintf (buf, sizeof(buf), "%7.*G", prec, 3.33); + if (strcmp (buf, " 3") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 3"); + prec = 3; + snprintf (buf, sizeof(buf), "%04.*o", prec, 33); + if (strcmp (buf, " 041") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 041"); + prec = 7; + snprintf (buf, sizeof(buf), "%09.*u", prec, 33); + if (strcmp (buf, " 0000033") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 0000033"); + prec = 3; + snprintf (buf, sizeof(buf), "%04.*x", prec, 33); + if (strcmp (buf, " 021") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 021"); + prec = 3; + snprintf (buf, sizeof(buf), "%04.*X", prec, 33); + if (strcmp (buf, " 021") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 021"); +} + +static void rfg3 (void) +{ + char buf[100]; + double g = 5.0000001; + unsigned long l = 1234567890; + double d = 321.7654321; + const char s[] = "test-string"; + int i = 12345; + int h = 1234; + + snprintf (buf, sizeof(buf), + "%1$*5$d %2$*6$hi %3$*7$lo %4$*8$f %9$*12$e %10$*13$g %11$*14$s", + i, h, l, d, 8, 5, 14, 14, d, g, s, 14, 3, 14); + if (strcmp (buf, + " 12345 1234 11145401322 321.765432 3.217654e+02 5 test-string") != 0) + printf ("got: '%s', expected: '%s'\n", buf, + " 12345 1234 11145401322 321.765432 3.217654e+02 5 test-string"); +} +#endif diff --git a/vscanf.c b/vscanf.c new file mode 100755 index 0000000..00e4513 --- /dev/null +++ b/vscanf.c @@ -0,0 +1,276 @@ + +#include "cmsis_os.h" +#include "SerialPortIO.h" +#include +#include +#include +#include "SystemDelayInterface.h" +//#include "BaseTypes.h" +#include +#include "stream.h" + +#define SHORT 0 +#define REGULAR 1 +#define LONG 2 + +#define ISSPACE(c) (c==' ' || c=='\t' || c=='\n') +#define ISDIGIT(c,base) ((c>='0' && c<='9') || (base==16 && \ + (('a'<=c && c<='f') || ('A'<=c && c<='F')))) + +static unsigned char +scan_number (stream_t *stream, void *ptr, unsigned char base, + unsigned short len, unsigned char size) +{ + int c; + long val; + unsigned char negate; + + /* Skip spaces. */ + for (;;) { + c = peekchar (stream); + if (c < 0) + return 0; + if (! ISSPACE ((unsigned char) c)) + break; + getchar (stream); + } + + /* Get sign. */ + negate = 0; + if (c == '-' || c == '+') { + if (c == '-') + negate = 1; + getchar (stream); + len--; + if (len == 0 || feof (stream)) + return 0; + c = peekchar (stream); + } + if (! ISDIGIT (c, base)) + return 0; + + val = 0; + while (len-- > 0) { + /* Scan digits. */ + if (! ISDIGIT (c, base)) + break; + + if (ptr) { + /* Get next digit. */ + if (base == 8) val <<= 3; + else if (base == 10) val *= 10; + else val <<= 4; + + if ('0' <= c && c <= '9') c -= '0'; + else if ('a' <= c && c <= 'f') c -= 'a' - 10; + else c -= 'A' - 10; + + val += c; + } + getchar (stream); + c = peekchar (stream); + if (c < 0) + break; + } + if (! ptr) + return 0; + + if (negate) + val = -val; + + switch (size) { + case SHORT: + *(short*) ptr = val; + break; + + case REGULAR: + *(int*) ptr = val; + break; + + case LONG: + *(long*) ptr = val; + break; + } + return 1; +} + +static unsigned char +match_pattern (unsigned char sym, const char *pattern) +{ + unsigned char next, inversion, cstart, cend; + + inversion = 0; + next = FETCH_BYTE (pattern++); + if (next == '^') { + inversion = 1; + next = FETCH_BYTE (pattern++); + } + while (next != ']') { + if (next == '\0') + return 0; /* unterminated [ */ + + cstart = cend = next; + next = FETCH_BYTE (pattern++); + if (next == '-' && (cend = FETCH_BYTE (pattern)) != ']') { + if (cend == '\0') + return 0; + ++pattern; + next = FETCH_BYTE (pattern++); + } + + if (sym >= cstart && sym <= cend) + return ! inversion; + } + return inversion; +} + +static unsigned char +scan_string (stream_t *stream, char *ptr, unsigned char type, + unsigned short len, const char *pattern) +{ + unsigned char ch = 0; + char *optr; + + optr = ptr; + while (! feof (stream)) { + ch = getchar (stream); + + /* Skip spaces, for 's'-format. */ + if (type != 's' || ! ISSPACE (ch)) + break; + } + while (! feof (stream)) { + if (type == 's') { + if (ISSPACE (ch)) + break; + } else if (type == '[') { + if (! match_pattern (ch, pattern)) + break; + } + if (ptr) + *ptr++ = ch; + if (--len <= 0) + break; + ch = getchar (stream); + } + if (ptr != optr) { + if (type != 'c') + *ptr++ = '\0'; + return 1; + } + return 0; +} + +/* + * Scan and recognize input according to a format + */ +int +stream_vscanf (stream_t *stream, + const char *fmt, /* Format string for the scanf */ + va_list argp) /* Arguments to scanf */ +{ + unsigned char ch, size, base; + unsigned short len; + int nmatch, ic; + void *ptr; + const char *pattern = 0; + + nmatch = 0; + for (;;) switch (ch = FETCH_BYTE (fmt++)) { + case '\0': + return nmatch; + case '%': + ch = FETCH_BYTE (fmt++); + if (ch == '%') + goto def; + if (ch != '*') + ptr = va_arg (argp, void*); + else { + ptr = 0; + ch = FETCH_BYTE (fmt++); + } + len = 0; + size = REGULAR; + while (ch >= '0' && ch <= '9') { + len = len*10 + ch - '0'; + ch = FETCH_BYTE (fmt++); + } + if (len == 0) + len = 30000; + + if (ch == 'l') { + ch = FETCH_BYTE (fmt++); + size = LONG; + } else if (ch == 'h') { + size = SHORT; + ch = FETCH_BYTE (fmt++); + } else if (ch == '[') { + pattern = fmt; + ch = FETCH_BYTE (fmt); + if (ch == '^') + ch = FETCH_BYTE (++fmt); + while (ch != 0 && ch != ']') + ch = FETCH_BYTE (++fmt); + if (ch != 0) + ++fmt; + ch = '['; + } + + if (ch >= 'A' && ch <= 'Z') { + ch = ch + 'a' - 'A'; + size = LONG; + } + + switch (ch) { + case 0: + return -1; + case 'c': + if (len == 30000) + len = 1; + goto string; + case 's': + case '[': +string: if (scan_string (stream, (char*) ptr, ch, len, + pattern) && ptr) + ++nmatch; + break; + case 'o': + base = 8; + goto number; + case 'x': + base = 16; + goto number; + case 'd': + base = 10; +number: if (scan_number (stream, ptr, base, len, size) && ptr) + ++nmatch; + break; + } + + if (feof (stream)) + return nmatch ? nmatch : -1; + break; + + case ' ': + case '\n': + case '\t': + /* Skip spaces. */ + for (;;) { + ic = peekchar (stream); + if (ic < 0) + break; + if (! ISSPACE ((unsigned char) ic)) + break; + getchar (stream); + } + break; + + default: +def: ic = peekchar (stream); + if (ic < 0) + return -1; + if ((unsigned char) ic != ch) + return nmatch; + getchar (stream); + } +}