summaryrefslogtreecommitdiff
path: root/device/lib/pic14/libc/vfprintf.c
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /device/lib/pic14/libc/vfprintf.c
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'device/lib/pic14/libc/vfprintf.c')
-rw-r--r--device/lib/pic14/libc/vfprintf.c512
1 files changed, 512 insertions, 0 deletions
diff --git a/device/lib/pic14/libc/vfprintf.c b/device/lib/pic14/libc/vfprintf.c
new file mode 100644
index 0000000..f0414a3
--- /dev/null
+++ b/device/lib/pic14/libc/vfprintf.c
@@ -0,0 +1,512 @@
+/*-------------------------------------------------------------------------
+ vfprintf.c - source file for reduced version of printf
+
+ Copyright (C) 1999, Sandeep Dutta <sandeep.dutta AT ieee.org>
+ Modified for pic16 port, by Vangelis Rokas, 2005 <vrokas AT otenet.gr>
+ Bug-fixed and feature-enhanced by Mauro Giachero, 2008 <mauro.giachero AT gmail.com>
+
+ Modifications for PIC14 by
+ Copyright (C) 2019 Gonzalo Pérez de Olaguer Córdoba <salo@gpoc.es>
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+
+ As a special exception, if you link this library with other files,
+ some of which are compiled with SDCC, to produce an executable,
+ this library does not by itself cause the resulting executable to
+ be covered by the GNU General Public License. This exception does
+ not however invalidate any other reasons why the executable file
+ might be covered by the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+/* following formats are supported :-
+ format output type argument-type
+ %% - -
+ %u unsigned int
+ %u* unsigned *
+ %b binary int
+ %lb binary long
+ %hb binary char
+ %d decimal int
+ %lu unsigned long
+ %hu unsigned char
+ %l[di] decimal long
+ %lu[di] unsigned long
+ %h[di] decimal char
+ %hu[di] unsigned char
+ %[xX] hexadecimal int
+ %l[xX] hexadecimal long
+ %h[xX] hexadecimal char
+ %o octal int
+ %lo octal long
+ %ho octal char
+ %c character char
+ %s character generic pointer
+ Also supported are:
+ - the '0', '-' and ' ' alignment modifiers
+ - the '+' and ' ' modifiers
+ - the width field for integral types
+ - the precision field for strings
+*/
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/***********************************************************
+ * The following switches enable some "advanced" features. *
+ * With all the switches enabled: *
+ * ; Statistics: *
+ * ; code size: 2062 (0x080e) bytes ( 1.57%) *
+ * ; 1031 (0x0407) words *
+ * ; udata size: 16 (0x0010) bytes ( 1.25%) *
+ * ; access size: 31 (0x001f) bytes *
+ * With all the switches disabled: *
+ * ; Statistics: *
+ * ; code size: 1278 (0x04fe) bytes ( 0.98%) *
+ * ; 639 (0x027f) words *
+ * ; udata size: 16 (0x0010) bytes ( 1.25%) *
+ * ; access size: 25 (0x0019) bytes *
+ ***********************************************************/
+
+/*
+ * Define this to enable support of the field width, which
+ * allows to specify the minimum number of characters an
+ * integer must use.
+ * Costs ~200 code words and 3 bytes in access RAM.
+ */
+#define FIELD_WIDTH
+/*
+ * Define this to enable support of the precision, which
+ * allows to specify the maximum number of characters a
+ * string can use. Note that this implementation doesn't
+ * use this field for integers (as it should).
+ * Costs ~85 code words and 1 byte in access RAM.
+ */
+#define PRECISION
+/*
+ * Define this to enable support of the '+' and ' ' modifiers,
+ * which specify that a positive signed number must be
+ * preceded respectively with a '+' or a ' ' character.
+ * Costs ~70 code words and 2 words of access RAM
+ */
+#define SIGN_MODIFIERS
+/*
+ * With this macro defined, trying to print a float number
+ * will generate the "<NO FLOAT>" string.
+ * Costs ~25 code words
+ */
+#define FLOAT_PLACEHOLDER
+/*
+ * With this macro defined, printing floats will work.
+ * This also enables PRECISION and disables FLOAT_PLACEHOLDER.
+ */
+#define USE_FLOATS
+/*
+ * This macro enables the use of the 'b' binary specifier and
+ * the use of "%b", "%hb" and "%lb"
+ */
+#define BINARY_SPECIFIER
+/*
+ * This macro enables the use of the 'i' integer specifier and
+ * the use of "%u", "%lu", ... in place of "%ud", "%lud", ... .
+ * costs ~10 code words
+ */
+#define EXTRA_INTEGER
+/*
+ * Two ways to handle putchar and getchar.
+ */
+#define _STATIC_PUTCHAR 0
+#define _STATIC_GETCHAR 0
+
+/*
+ * END OF CONFIGURATION SETTINGS
+ */
+
+#if defined(USE_FLOATS)
+#define PRECISION
+#undef FLOAT_PLACEHOLDER
+/* x_ftoa requires up to 8 digits (integral part) + '.' + 24 digits
+ * (fractional part). Adding a sign and a NUL byte yields 35 byte. */
+# define BUF_SIZE 36
+#elif defined(BINARY_SPECIFIER)
+/* "%lb" = "0" - "11111111111111111111111111111111" */
+# define BUF_SIZE 33
+#else
+/* "%lo" = "0" - "37777777777" or "-20000000000" - "17777777777" */
+# define BUF_SIZE 13
+#endif
+
+/* flags */
+#define _LONG 0x0001
+#define _STR 0x0002
+#define _CHAR 0x0004
+#define _PTR 0x0008
+#define _FLOAT 0x1000 // only when USE_FLOATS or FLOAT_PLACEHOLDER
+#define _UNSIGNED 0x0010
+#define _UPCASE 0x0020
+#define _LEFTALIGN 0x0100 // only when FIELD_WIDTH
+#define _ZEROPAD 0x0200 // only when FIELD_WIDTH
+#define _PRINTSIGN 0x0400 // only when SIGN_MODIFIERS
+#define _PRINTBLANK 0x0800 // only when SIGN_MODIFIERS
+
+/* precision value meaning unset */
+#define _UNSET ((unsigned char)-1)
+
+#if _STATIC_GETCHAR
+
+static const char *_fmt;
+static char ch;
+static void _getchar (void)
+{
+ ch = *_fmt++;
+}
+#define _GETCHAR() _getchar()
+
+#else /* _STATIC_GETCHAR */
+#define _GETCHAR() do { ch = *fmt++; } while(0)
+#endif
+
+#if _STATIC_PUTCHAR
+
+static FILE *_stream;
+static unsigned char count;
+static int _putchar (unsigned char c)
+{
+ if (fputc(c, _stream) < 0)
+ return 1;
+ count++;
+ return 0;
+}
+#define _PUTCHAR(c) do { if (_putchar(c)) goto _error; } while(0)
+
+#else /* _STATIC_PUTCHAR */
+#define _PUTCHAR(c) do { if (fputc(c, stream) < 0) goto _error; count++; } while(0)
+#endif
+
+int
+vfprintf (FILE *stream, const char *fmt, va_list ap)
+{
+ unsigned flags;
+ unsigned char radix; // 2(binary), 8(octal), 10(decimal), 16(hexadecimal) or 0(char)
+
+#if defined(FLOAT_PLACEHOLDER) || defined(USE_FLOATS)
+ float f;
+#endif
+
+#ifdef FIELD_WIDTH
+ unsigned char fieldwidth; // field width in number of characters
+#endif
+
+#ifdef PRECISION
+ unsigned char precision; // precission width in number of characters
+#endif
+
+ const char *cstr;
+ char *str;
+ long val;
+ char buffer[BUF_SIZE];
+
+#if _STATIC_GETCHAR
+ _fmt = fmt;
+#else
+ char ch;
+#endif
+
+#if _STATIC_PUTCHAR
+ _stream = stream;
+ count = 0;
+#else
+ unsigned char count = 0;
+#endif
+
+ while (1)
+ {
+ _GETCHAR();
+ if (ch == 0)
+ return count;
+ if (ch != '%')
+ {
+ _PUTCHAR(ch);
+ continue;
+ }
+ _GETCHAR();
+ if (ch == '%')
+ {
+ _PUTCHAR(ch);
+ continue;
+ }
+
+ flags = 0;
+ radix = 10;
+
+#ifdef FIELD_WIDTH
+ fieldwidth = 0;
+#endif
+
+#ifdef PRECISION
+ // _UNSET is used as an "unlimited" precision marker
+ precision = _UNSET;
+#endif
+
+#ifdef FIELD_WIDTH
+ if (ch == '0')
+ {
+ flags |= _ZEROPAD;
+ _GETCHAR();
+ }
+
+ if (ch == '-')
+ {
+ flags |= _LEFTALIGN;
+ _GETCHAR();
+ }
+#endif
+
+#ifdef SIGN_MODIFIERS
+ if (ch == ' ')
+ {
+ flags |= _PRINTSIGN;
+ flags |= _PRINTBLANK;
+ _GETCHAR();
+ }
+
+ if (ch == '+')
+ {
+ flags |= _PRINTSIGN;
+ _GETCHAR();
+ }
+#endif
+
+#ifdef FIELD_WIDTH
+ if ((ch >= '1') && (ch <= '9'))
+ {
+ while ((ch >= '0') && (ch <= '9'))
+ {
+ fieldwidth = 10 * fieldwidth + (ch) - '0';
+ _GETCHAR();
+ }
+ }
+#endif
+
+#ifdef PRECISION
+ if (ch == '.')
+ {
+ _GETCHAR();
+ precision = 0;
+ while ((ch >= '0') && (ch <= '9'))
+ {
+ precision = 10 * precision + (ch) - '0';
+ _GETCHAR();
+ }
+ }
+#endif
+
+ if (ch == 'l')
+ {
+ flags |= _LONG;
+ _GETCHAR();
+ }
+ else if (ch == 'h')
+ {
+ flags |= _CHAR;
+ _GETCHAR();
+ }
+
+ if (ch == 'u')
+ {
+ flags |= _UNSIGNED;
+ _GETCHAR();
+ }
+
+ if (ch == 's')
+ {
+ flags |= _STR;
+#ifdef FIELD_WIDTH
+ flags &= ~_ZEROPAD; /* Strings are always space-padded */
+#endif
+ }
+ else if (ch == 'p')
+ {
+ flags |= _PTR;
+ flags |= _UNSIGNED;
+ radix = 16;
+ }
+ else if (ch == 'x')
+ radix = 16;
+ else if (ch == 'X')
+ {
+ radix = 16;
+ flags |= _UPCASE;
+ }
+ else if (ch == 'c')
+ radix = 0;
+ else if (ch == 'o')
+ radix = 8;
+#ifdef BINARY_SPECIFIER
+ else if (ch == 'b')
+ radix = 2;
+#endif
+#if defined(FLOAT_PLACEHOLDER) || defined(USE_FLOATS)
+ else if (ch == 'f')
+ {
+ flags |= _FLOAT;
+ }
+#endif
+#ifdef EXTRA_INTEGER
+ else if ((ch == 'd') || (ch == 'i')) /* This is the default */
+ ;
+ else if (flags & _UNSIGNED) /* %u alone is the same as %ud */
+#if _STATIC_GETCHAR
+ --_fmt;
+#else
+ --fmt;
+#endif
+#else
+ else if (ch == 'd')
+ ;
+#endif
+ else
+ {
+ goto _error;
+ }
+
+ /* Here starts the formatting code */
+
+ if (flags & _STR)
+ {
+ str = va_arg (ap, char *);
+ }
+#if defined(USE_FLOATS)
+ else if (flags & _FLOAT)
+ {
+ f = va_arg (ap, float);
+ str = buffer;
+ _ftoa (f, buffer, PREC(PREC_F, precision == _UNSET ? PREC_D : precision));
+ precision = _UNSET;
+ }
+#elif defined(FLOAT_PLACEHOLDER)
+ else if (flags & _FLOAT)
+ {
+ /* read but ignore the argument */
+ f = va_arg (ap, float);
+ str = (char*)"<NO FLOAT>";
+#ifdef PRECISION
+ precision = _UNSET;
+#endif /* PRECISION */
+ }
+#endif /* FLOAT_PLACEHOLDER */
+ else
+ {
+#ifdef PRECISION
+ precision = _UNSET; //FIXME: No support for the precision field on numerals
+#endif
+ val = 0;
+ if (flags & _LONG)
+ {
+ val = va_arg (ap, long);
+ }
+ else if (flags & _PTR)
+ {
+ str = va_arg (ap, void*);
+ val = 0x00ffffffUL & *(unsigned long*)&str;
+ }
+ else if (flags & _CHAR)
+ {
+ val = va_arg (ap, char);
+ if ((radix != 10) || (flags & _UNSIGNED))
+ val = (unsigned char) val; //Avoid unwanted sign extension
+ }
+ else
+ {
+ val = va_arg (ap, int);
+ if ((radix != 10) || (flags & _UNSIGNED))
+ val = (unsigned int) val; //Avoid unwanted sign extension
+ }
+
+ str = buffer + 1; //Reserve space for a forced '+'
+ if (radix)
+ {
+ if (flags & _UNSIGNED)
+ _ultoa (val, buffer + 1, radix);
+ else
+ _ltoa (val, buffer + 1, radix);
+#ifdef SIGN_MODIFIERS
+ if ((flags & _PRINTSIGN) && (*str != '-'))
+ {
+ --str;
+ *str = (flags & _PRINTBLANK ? ' ' : '+');
+ }
+#endif
+ }
+ else
+ {
+ *str = (unsigned char) val;
+ *(str + 1) = '\0';
+ }
+ }
+
+#ifdef FIELD_WIDTH
+ //Count how many pad chars are required in fieldwidth
+ cstr = str;
+ while (fieldwidth && *cstr)
+ {
+ ++cstr;
+ --fieldwidth;
+ }
+ //Left padding
+ if (!(flags & _LEFTALIGN))
+ {
+ ch = flags & _ZEROPAD ? '0' : ' ';
+ while (fieldwidth)
+ {
+ _PUTCHAR(ch);
+ --fieldwidth;
+ }
+ }
+#endif
+
+#ifdef PRECISION
+ while (*str && ((precision == _UNSET) || precision--))
+#else
+ while (*str)
+#endif
+ {
+ ch = *str++;
+ if (radix == 16 && !(flags & _UPCASE))
+ {
+ ch = tolower (ch);
+ }
+ _PUTCHAR(ch);
+ }
+
+#ifdef FIELD_WIDTH
+ //Right padding (with spaces)
+ if (flags & _LEFTALIGN)
+ {
+ while (fieldwidth)
+ {
+ _PUTCHAR(' ');
+ --fieldwidth;
+ }
+ }
+#endif
+
+ }
+
+_error:
+ return EOF;
+}