summaryrefslogtreecommitdiff
path: root/libc/stdio/printf.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/stdio/printf.c')
-rw-r--r--libc/stdio/printf.c387
1 files changed, 387 insertions, 0 deletions
diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c
new file mode 100644
index 000000000..873f1cb41
--- /dev/null
+++ b/libc/stdio/printf.c
@@ -0,0 +1,387 @@
+/*
+ * This file based on printf.c from 'Dlibs' on the atari ST (RdeBath)
+ *
+ *
+ * Dale Schumacher 399 Beacon Ave.
+ * (alias: Dalnefre') St. Paul, MN 55104
+ * dal@syntel.UUCP United States of America
+ * "It's not reality that's important, but how you perceive things."
+ */
+
+/* Altered to use stdarg, made the core function vfprintf.
+ * Hooked into the stdio package using 'inside information'
+ * Altered sizeof() assumptions, now assumes all integers except chars
+ * will be either
+ * sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short)
+ *
+ * -RDB
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef __STDC__
+#include <stdarg.h>
+#define va_strt va_start
+#else
+#include <varargs.h>
+#define va_strt(p,i) va_start(p)
+#endif
+
+#include "stdio.h"
+
+#ifdef L_printf
+
+#ifdef __STDC__
+int printf(const char * fmt, ...)
+#else
+int printf(fmt, va_alist)
+__const char *fmt;
+va_dcl
+#endif
+{
+ va_list ptr;
+ int rv;
+
+ va_strt(ptr, fmt);
+ rv = vfprintf(stdout,fmt,ptr);
+ va_end(ptr);
+ return rv;
+}
+#endif
+
+#ifdef L_sprintf
+#ifdef __STDC__
+int sprintf(char * sp, const char * fmt, ...)
+#else
+int sprintf(sp, fmt, va_alist)
+char * sp;
+__const char *fmt;
+va_dcl
+#endif
+{
+static FILE string[1] =
+{
+ {0, 0, (char*)(unsigned) -1, 0, (char*) (unsigned) -1, -1,
+ _IOFBF | __MODE_WRITE}
+};
+
+ va_list ptr;
+ int rv;
+ va_strt(ptr, fmt);
+ string->bufpos = sp;
+ rv = vfprintf(string,fmt,ptr);
+ va_end(ptr);
+ *(string->bufpos) = 0;
+ return rv;
+}
+#endif
+
+#ifdef L_fprintf
+#ifdef __STDC__
+int fprintf(FILE * fp, const char * fmt, ...)
+#else
+int fprintf(fp, fmt, va_alist)
+FILE * fp;
+__const char *fmt;
+va_dcl
+#endif
+{
+ va_list ptr;
+ int rv;
+ va_strt(ptr, fmt);
+ rv = vfprintf(fp,fmt,ptr);
+ va_end(ptr);
+ return rv;
+}
+#endif
+
+#ifdef L_vprintf
+int vprintf(fmt, ap)
+__const char *fmt;
+va_list ap;
+{
+ return vfprintf(stdout,fmt,ap);
+}
+#endif
+
+#ifdef L_vsprintf
+int vsprintf(sp, fmt, ap)
+char * sp;
+__const char *fmt;
+va_list ap;
+{
+static FILE string[1] =
+{
+ {0, 0, (char*)(unsigned) -1, 0, (char*) (unsigned) -1, -1,
+ _IOFBF | __MODE_WRITE}
+};
+
+ int rv;
+ string->bufpos = sp;
+ rv = vfprintf(string,fmt,ap);
+ *(string->bufpos) = 0;
+ return rv;
+}
+#endif
+
+#ifdef L_vfprintf
+
+#if FLOATS
+int _vfprintf_fp_ref = 1;
+#else
+int _vfprintf_fp_ref = 0;
+#endif
+
+static int
+prtfld(op, buf, ljustf, sign, pad, width, preci, buffer_mode)
+register FILE *op;
+register unsigned char *buf;
+int ljustf;
+register char sign;
+char pad;
+register int width;
+int preci;
+int buffer_mode;
+/*
+ * Output the given field in the manner specified by the arguments. Return
+ * the number of characters output.
+ */
+{
+ register int cnt = 0, len;
+ register unsigned char ch;
+
+ len = strlen(buf);
+
+ if (*buf == '-')
+ sign = *buf++;
+ else if (sign)
+ len++;
+
+ if ((preci != -1) && (len > preci)) /* limit max data width */
+ len = preci;
+
+ if (width < len) /* flexible field width or width overflow */
+ width = len;
+
+ /*
+ * at this point: width = total field width len = actual data width
+ * (including possible sign character)
+ */
+ cnt = width;
+ width -= len;
+
+ while (width || len)
+ {
+ if (!ljustf && width) /* left padding */
+ {
+ if (len && sign && (pad == '0'))
+ goto showsign;
+ ch = pad;
+ --width;
+ }
+ else if (len)
+ {
+ if (sign)
+ {
+ showsign:ch = sign; /* sign */
+ sign = '\0';
+ }
+ else
+ ch = *buf++; /* main field */
+ --len;
+ }
+ else
+ {
+ ch = pad; /* right padding */
+ --width;
+ }
+ putc(ch, op);
+ if( ch == '\n' && buffer_mode == _IOLBF ) fflush(op);
+ }
+
+ return (cnt);
+}
+
+int
+vfprintf(op, fmt, ap)
+FILE *op;
+register __const char *fmt;
+register va_list ap;
+{
+ register int i, cnt = 0, ljustf, lval;
+ int preci, dpoint, width;
+ char pad, sign, radix, hash;
+ register char *ptmp;
+ char tmp[64], *ltostr(), *ultostr();
+ int buffer_mode;
+
+ /* This speeds things up a bit for unbuffered */
+ buffer_mode = (op->mode&__MODE_BUF);
+ op->mode &= (~__MODE_BUF);
+
+ while (*fmt)
+ {
+ if (*fmt == '%')
+ {
+ if( buffer_mode == _IONBF ) fflush(op);
+ ljustf = 0; /* left justify flag */
+ sign = '\0'; /* sign char & status */
+ pad = ' '; /* justification padding char */
+ width = -1; /* min field width */
+ dpoint = 0; /* found decimal point */
+ preci = -1; /* max data width */
+ radix = 10; /* number base */
+ ptmp = tmp; /* pointer to area to print */
+ hash = 0;
+ lval = (sizeof(int)==sizeof(long)); /* long value flaged */
+ fmtnxt:
+ i = 0;
+ for(;;)
+ {
+ ++fmt;
+ if(*fmt < '0' || *fmt > '9' ) break;
+ i = (i * 10) + (*fmt - '0');
+ if (dpoint)
+ preci = i;
+ else if (!i && (pad == ' '))
+ {
+ pad = '0';
+ goto fmtnxt;
+ }
+ else
+ width = i;
+ }
+
+ switch (*fmt)
+ {
+ case '\0': /* early EOS */
+ --fmt;
+ goto charout;
+
+ case '-': /* left justification */
+ ljustf = 1;
+ goto fmtnxt;
+
+ case ' ':
+ case '+': /* leading sign flag */
+ sign = *fmt;
+ goto fmtnxt;
+
+ case '*': /* parameter width value */
+ i = va_arg(ap, int);
+ if (dpoint)
+ preci = i;
+ else
+ width = i;
+ goto fmtnxt;
+
+ case '.': /* secondary width field */
+ dpoint = 1;
+ goto fmtnxt;
+
+ case 'l': /* long data */
+ lval = 1;
+ goto fmtnxt;
+
+ case 'h': /* short data */
+ lval = 0;
+ goto fmtnxt;
+
+ case 'd': /* Signed decimal */
+ case 'i':
+ ptmp = ltostr((long) ((lval)
+ ? va_arg(ap, long)
+ : va_arg(ap, short)),
+ 10, 0);
+ goto printit;
+
+ case 'b': /* Unsigned binary */
+ radix = 2;
+ goto usproc;
+
+ case 'o': /* Unsigned octal */
+ radix = 8;
+ goto usproc;
+
+ case 'p': /* Pointer */
+ lval = (sizeof(char*) == sizeof(long));
+ pad = '0';
+ width = 6;
+ preci = 8;
+ /* fall thru */
+
+ case 'x': /* Unsigned hexadecimal */
+ case 'X':
+ radix = 16;
+ /* fall thru */
+
+ case 'u': /* Unsigned decimal */
+ usproc:
+ ptmp = ultostr((unsigned long) ((lval)
+ ? va_arg(ap, unsigned long)
+ : va_arg(ap, unsigned short)),
+ radix, (*fmt == 'X') ? 1 : 0);
+ if( hash && radix == 8 ) { width = strlen(ptmp)+1; pad='0'; }
+ goto printit;
+
+ case '#':
+ hash=1;
+ goto fmtnxt;
+
+ case 'c': /* Character */
+ ptmp[0] = va_arg(ap, int);
+ ptmp[1] = '\0';
+ goto nopad;
+
+ case 's': /* String */
+ ptmp = va_arg(ap, char*);
+ nopad:
+ sign = '\0';
+ pad = ' ';
+ printit:
+ cnt += prtfld(op, ptmp, ljustf,
+ sign, pad, width, preci, buffer_mode);
+ break;
+
+#if FLOATS
+ case 'e': /* float */
+ case 'f':
+ case 'g':
+ case 'E':
+ case 'G':
+ fprintf(stderr, "LIBM:PRINTF");
+ gcvt(va_arg(ap, double), preci, ptmp);
+ preci = -1;
+ goto printit;
+#else
+ case 'e': /* float */
+ case 'f':
+ case 'g':
+ case 'E':
+ case 'G':
+ fprintf(stderr, "LIBC:PRINTF");
+ exit(-1);
+#endif
+
+ default: /* unknown character */
+ goto charout;
+ }
+ }
+ else
+ {
+ charout:
+ putc(*fmt, op); /* normal char out */
+ ++cnt;
+ if( *fmt == '\n' && buffer_mode == _IOLBF ) fflush(op);
+ }
+ ++fmt;
+ }
+ op->mode |= buffer_mode;
+ if( buffer_mode == _IONBF ) fflush(op);
+ if( buffer_mode == _IOLBF ) op->bufwrite = op->bufstart;
+ return (cnt);
+}
+#endif