summaryrefslogtreecommitdiff
path: root/src/libc/src/format.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libc/src/format.c')
-rw-r--r--src/libc/src/format.c467
1 files changed, 467 insertions, 0 deletions
diff --git a/src/libc/src/format.c b/src/libc/src/format.c
new file mode 100644
index 0000000..f62d5dc
--- /dev/null
+++ b/src/libc/src/format.c
@@ -0,0 +1,467 @@
+/*
+ * <format.c>
+ *
+ * Open Hack'Ware BIOS: formated output functions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* functions prototypes are here */
+#include <stdio.h>
+/* va_list is defined here */
+#include <stdarg.h>
+/* size_t is defined here */
+#include <stddef.h>
+/* NULL is defined here */
+#include <stdlib.h>
+/* write is defined here */
+#include <unistd.h>
+/* memcpy is defined here */
+/* memset is defined here */
+/* strlen is defined here */
+#include <string.h>
+
+#define unused __attribute__ (( unused ))
+int console_write (const void *buffer, int len);
+/* XXX: this is a hack to be fixed */
+int serial_write (const void *buffer, int len);
+#define debug_write serial_write
+
+/* Low level output fonctions */
+typedef size_t (*outf_t)(void *private, const unsigned char *buf, size_t len);
+
+/* output to fd */
+#if defined (__USE__vprintf__)
+size_t outfd (void *private, const unsigned char *buf, size_t len)
+{
+ int *fd = private;
+
+ if (*fd == 1 || *fd == 2)
+ return console_write(buf, len);
+
+ return write(*fd, buf, len);
+}
+
+size_t outf_dbg (void *private, const unsigned char *buf, size_t len)
+{
+ int *fd = private;
+
+ if (*fd == 1 || *fd == 2)
+ return debug_write(buf, len);
+
+ return write(*fd, buf, len);
+}
+
+/* output to buffer */
+size_t outbuf (void *private, const unsigned char *buf, size_t len)
+{
+ unsigned char **dst = private;
+
+ memcpy(*dst, buf, len);
+ (*dst) += len;
+ (*dst)[0] = '\0';
+
+ return len;
+}
+
+/* misc formatted output functions */
+/* out one character */
+static size_t outc (outf_t outf, void *private,
+ unsigned int value, size_t maxlen)
+{
+ unsigned char buffer;
+
+ if (maxlen < 1)
+ return 0;
+ buffer = value;
+ if ((*outf)(private, &buffer, 1) == (size_t)-1)
+ return -1;
+
+ return 1;
+}
+
+/* out one int in decimal */
+static size_t outdecs (outf_t outf, void *private,
+ int value, size_t fill, size_t maxlen)
+{
+ unsigned char buffer[12];
+ size_t pos, len;
+ int sign;
+
+ buffer[11] = '\0';
+ pos = 10;
+ if (value == 0) {
+ sign = 0;
+ buffer[pos--] = '0';
+ } else {
+ if (value < 0) {
+ sign = -1;
+ value = -value;
+ } else {
+ sign = 1;
+ }
+ for (; value != 0; pos--) {
+ buffer[pos] = (value % 10) + '0';
+ value = value / 10;
+ }
+ }
+ if (fill != 0)
+ fill -= pos - 10;
+ for (; fill != 0 && pos != 0; fill--) {
+ buffer[pos--] = '0';
+ }
+ if (sign == -1)
+ buffer[pos--] = '-';
+ len = 10 - pos;
+ if (len > maxlen)
+ len = maxlen;
+ if ((*outf)(private, buffer + pos + 1, len) == (size_t)-1)
+ return -1;
+
+ return len;
+}
+
+/* out one unsigned int as decimal */
+static size_t outdecu (outf_t outf, void *private,
+ unsigned int value, size_t fill, size_t maxlen)
+{
+ unsigned char buffer[11];
+ size_t pos, len;
+
+ buffer[10] = '\0';
+ pos = 9;
+ if (value == 0) {
+ buffer[pos--] = '0';
+ } else {
+ for (; value != 0; pos--) {
+ buffer[pos] = (value % 10) + '0';
+ value = value / 10;
+ }
+ }
+ if (fill != 0)
+ fill -= pos - 9;
+ for (; fill != 0 && pos != (size_t)-1; fill--) {
+ buffer[pos--] = '0';
+ }
+ len = 9 - pos;
+ if (len > maxlen)
+ len = maxlen;
+ if ((*outf)(private, buffer + pos + 1, len) == (size_t)-1)
+ return -1;
+
+ return len;
+}
+
+/* out one unsigned int as hexadecimal */
+static size_t outhex (outf_t outf, void *private,
+ unsigned int value, size_t fill, size_t maxlen)
+{
+ unsigned char buffer[9];
+ size_t pos, len;
+ int d;
+
+ buffer[8] = '\0';
+ pos = 7;
+ if (value == 0) {
+ buffer[pos--] = '0';
+ } else {
+ for (; value != 0; pos--) {
+ d = value & 0xF;
+ if (d > 9)
+ d += 'a' - '0' - 10;
+ buffer[pos] = d + '0';
+ value = value >> 4;
+ }
+ }
+ if (fill > 0)
+ fill -= pos - 7;
+ for (; fill != 0 && pos != (size_t)-1; fill--) {
+ buffer[pos--] = '0';
+ }
+ len = 7 - pos;
+ if (len > maxlen)
+ len = maxlen;
+ if ((*outf)(private, buffer + pos + 1, len) == (size_t)-1)
+ return -1;
+
+ return len;
+}
+
+static size_t outstr (outf_t outf, void *private,
+ const unsigned char *str, unused size_t fill,
+ size_t maxlen)
+{
+#define TMPBUF_LEN 256
+#if 0
+ unsigned char tmpbuf[TMPBUF_LEN];
+ size_t len, totlen, tmp;
+#else
+ size_t len, totlen;
+#endif
+
+ if (str == NULL) {
+ /* Avoid crash if given a NULL string */
+ str = "<null>";
+ }
+ len = strlen(str);
+ totlen = 0;
+#if 0
+ if (len < fill) {
+ memset(tmpbuf, ' ', TMPBUF_LEN);
+ fill -= len;
+ for (; fill > 0; fill -= tmp) {
+ tmp = fill;
+ if (tmp > TMPBUF_LEN)
+ tmp = TMPBUF_LEN;
+ totlen += tmp;
+ if (totlen > maxlen) {
+ tmp = maxlen - totlen;
+ totlen = maxlen;
+ }
+ (*outf)(private, tmpbuf, tmp);
+ }
+ }
+#endif
+ totlen += len;
+ if (totlen > maxlen) {
+ len = maxlen - totlen;
+ totlen = maxlen;
+ }
+ if ((*outf)(private, str, len) == (size_t)-1)
+ return -1;
+
+ return totlen;
+}
+
+int _vprintf(outf_t outf, void *private, size_t maxlen,
+ const unsigned char *format, va_list ap)
+{
+ const unsigned char *p, *str;
+ size_t maxfill, totlen, len, tmp;
+ int cur;
+
+ cur = 0;
+ str = format;
+ for (totlen = 0; totlen != maxlen;) {
+ for (p = str; (*p != '%' || cur > 6) && *p != '\0'; p++)
+ continue;
+ len = p - str;
+ if (len + totlen > maxlen)
+ len = maxlen - totlen;
+ tmp = (*outf)(private, str, p - str);
+ if (tmp == (size_t)-1)
+ return -1;
+ totlen += tmp;
+ if (*p == '\0')
+ break;
+ maxfill = -2;
+ str = p;
+ next:
+ p++;
+ switch (*p) {
+ case '\0':
+ /* Invalid format */
+ goto invalid;
+ case '0':
+ if (maxfill >= (size_t)-2) {
+ maxfill = -1;
+ goto next;
+ }
+ /* No break here */
+ case '1' ... '9':
+ switch (maxfill) {
+ case -2:
+ /* Invalid format */
+ goto invalid;
+ case -1:
+ maxfill = *p - '0';
+ break;
+ default:
+ maxfill = (maxfill * 10) + *p - '0';
+ break;
+ }
+ goto next;
+ case 'l':
+ /* Ignore it */
+ goto next;
+ case 'h':
+ /* Ignore it */
+ goto next;
+ case 'd':
+ if (maxfill == (size_t)-2 || maxfill == (size_t)(-1))
+ maxfill = 0;
+ tmp = outdecs(outf, private,
+ va_arg(ap, int), maxfill, maxlen - totlen);
+ break;
+ case 'u':
+ if (maxfill == (size_t)-2 || maxfill == (size_t)(-1))
+ maxfill = 0;
+ tmp = outdecu(outf, private,
+ va_arg(ap, unsigned int), maxfill, maxlen - totlen);
+ break;
+ case 'x':
+ if (maxfill == (size_t)-2 || maxfill == (size_t)(-1))
+ maxfill = 0;
+ tmp = outhex(outf, private,
+ va_arg(ap, unsigned int), maxfill, maxlen - totlen);
+ break;
+ case 'p':
+ if (p != str + 1) {
+ /* Invalid format */
+ goto invalid;
+ } else {
+ if (maxfill == (size_t)-2 || maxfill == (size_t)(-1))
+ maxfill = 0;
+ tmp = outhex(outf, private, va_arg(ap, unsigned int),
+ maxfill, maxlen - totlen);
+ }
+ break;
+ case 'c':
+ if (p != str + 1) {
+ /* Invalid format */
+ goto invalid;
+ } else {
+ tmp = outc(outf, private,
+ va_arg(ap, int), maxlen - totlen);
+ }
+ break;
+ case 's':
+ if (maxfill == (size_t)-2 || maxfill == (size_t)(-1))
+ maxfill = 0;
+ str = va_arg(ap, const unsigned char *);
+ tmp = outstr(outf, private, str, maxfill, maxlen - totlen);
+ break;
+ case '%':
+ if (p != str + 1) {
+ /* Invalid format */
+ goto invalid;
+ } else {
+ tmp = outc(outf, private, '%', maxlen - totlen);
+ }
+ default:
+ invalid:
+ /* Invalid format : display the raw string */
+ len = p - str + 1;
+ if (len + totlen > maxlen)
+ len = maxlen - totlen;
+ tmp = (*outf)(private, str, len);
+ break;
+ }
+ if (tmp == (size_t)-1)
+ return -1;
+ totlen += tmp;
+ str = p + 1;
+ }
+
+ return 0;
+}
+#else /* defined (__USE__vprintf__) */
+size_t outfd (void *private, const unsigned char *buf, size_t len);
+size_t outf_dbg (void *private, const unsigned char *buf, size_t len);
+size_t outbuf (void *private, const unsigned char *buf, size_t len);
+int _vprintf(outf_t outf, void *private, size_t maxlen,
+ const unsigned char *format, va_list ap);
+#endif /* defined (__USE__vprintf__) */
+
+#if defined (__USE_printf__)
+int printf (const char *format, ...)
+{
+ va_list ap;
+ int fd = 1;
+ int ret;
+
+ va_start(ap, format);
+ ret = _vprintf(&outfd, &fd, -1, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif /* defined (__USE_printf__) */
+
+#if defined (__USE_dprintf__)
+int dprintf (const char *format, ...)
+{
+ va_list ap;
+ int fd = 1;
+ int ret;
+
+ va_start(ap, format);
+ ret = _vprintf(&outf_dbg, &fd, -1, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif /* defined (__USE_dprintf__) */
+
+#if defined (__USE_sprintf__)
+int sprintf (char *str, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = _vprintf(&outbuf, &str, -1, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif /* defined (__USE_sprintf__) */
+
+#if defined (__USE_snprintf__)
+int snprintf (char *str, size_t size, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = _vprintf(&outbuf, &str, size, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif /* defined (__USE_snprintf__) */
+
+#if defined (__USE_vprintf__)
+int vprintf (const char *format, va_list ap)
+{
+ int fd = 1;
+
+ return _vprintf(&outfd, &fd, -1, format, ap);
+}
+#endif /* defined (__USE_vprintf__) */
+
+#if defined (__USE_vdprintf__)
+int vdprintf (const char *format, va_list ap)
+{
+ int fd = 1;
+
+ return _vprintf(&outf_dbg, &fd, -1, format, ap);
+}
+#endif /* defined (__USE_vdprintf__) */
+
+#if defined (__USE_vsprintf__)
+int vsprintf (char *str, const char *format, va_list ap)
+{
+ return _vprintf(&outbuf, &str, -1, format, ap);
+}
+#endif /* defined (__USE_vsprintf__) */
+
+#if defined (__USE_vsnprintf__)
+int vsnprintf (char *str, size_t size, const char *format, va_list ap)
+{
+ return _vprintf(&outbuf, &str, size, format, ap);
+}
+#endif /* defined (__USE_vsnprintf__) */