aboutsummaryrefslogtreecommitdiff
path: root/sys/libc/printf.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/libc/printf.c')
-rw-r--r--sys/libc/printf.c245
1 files changed, 245 insertions, 0 deletions
diff --git a/sys/libc/printf.c b/sys/libc/printf.c
new file mode 100644
index 00000000..03b155bb
--- /dev/null
+++ b/sys/libc/printf.c
@@ -0,0 +1,245 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+*/
+
+#define import_spp
+#define import_libc
+#define import_xnames
+#define import_stdio
+#define import_ctype
+#define import_stdarg
+#include <iraf.h>
+
+
+/* PRINTF -- Emulation of the UNIX printf facilities with the IRAF FMTIO
+** interface as the backend. All features of the UNIX printf are supported
+** without modification. Additional format codes are supported in conformance
+** with the IRAF printf, e.g., hms format, variable radix, tabstops, etc.,
+** but these are upward compatible with standard UNIX usage.
+*/
+
+#define SZ_FMTSPEC 25 /* max size single format spec */
+#define SZ_OBUF SZ_COMMAND /* sz intermediate buffer */
+#define MAX_PREC 4 /* max "*" deferred args */
+#define NOARG (-1) /* % spec with no data value */
+
+
+/* PRINTF -- Formatted print to the standard output.
+*/
+void
+printf (char *format, ...)
+{
+ va_list argp;
+ void u_doprnt();
+
+ va_start (argp, format);
+ u_doprnt (format, &argp, stdout);
+ va_end (argp);
+}
+
+
+/* FPRINTF -- Formatted print to a file.
+*/
+void
+fprintf (FILE *fp, char *format, ...)
+{
+ va_list argp;
+ void u_doprnt();
+
+ va_start (argp, format);
+ u_doprnt (format, &argp, fp);
+ va_end (argp);
+}
+
+
+/* U_DOPRNT -- Process the format to the output file, taking arguments from
+** the list pointed to by argp as % format specs are encountered in the input.
+** The main point of this routine is to handle the variable number of arguments.
+** The actual encoding is all handled by the IRAF FPRINF and PARG calls.
+** N.B. we assume chars are stacked as ints, and floats are stacked as doubles.
+*/
+void
+u_doprnt (
+ char *format, /* "%w.dC" etc. format spec */
+ va_list *argp, /* pointer to first value arg */
+ FILE *fp /* output file */
+)
+{
+ register int ch; /* next format char reference */
+ XCHAR formspec[SZ_FMTSPEC]; /* copy of single format spec */
+ XCHAR *fsp; /* pointer into formspec */
+ int done, dotseen; /* one when at end of a format */
+ int varprec; /* runtime precision is used */
+ int prec[MAX_PREC]; /* values of prec args */
+
+ void u_doarg ();
+
+
+ while ( (ch = *format++) ) {
+ if (ch == '%') {
+ fsp = formspec;
+ *fsp++ = ch;
+ varprec = 0;
+ dotseen = 0;
+ done = 0;
+
+ while (!done) {
+ ch = *fsp++ = *format++;
+
+ switch (ch) {
+ case EOS:
+ --format;
+ done++;
+ break;
+
+ case 'l':
+ /* arg size modifier; ignored for now */
+ fsp--;
+ break;
+
+ case '*':
+ prec[varprec++] = va_arg ((*argp), int);
+ break;
+
+ case '.':
+ dotseen++;
+ break;
+
+ case 'r': /* nonstandard UNIX */
+ if ((ch = *fsp++ = *format++) == '*') {
+ int radix;
+ int radchar;
+
+ radix = va_arg ((*argp), int);
+ if (radix < 0)
+ radchar = 'A';
+ else if (radix > 9)
+ radchar = radix - 10 + 'A';
+ else
+ radchar = todigit (radix);
+ *(fsp-1) = radchar;
+ } else if (ch == EOS) {
+ --format;
+ break;
+ }
+ /* fall through */
+
+ case 'b': /* nonstandard UNIX */
+ case 'c':
+ case 'd':
+ case 'o':
+ case 'x':
+ case 'u':
+ *fsp = EOS;
+ u_doarg (fp, formspec, &argp, prec, varprec, TY_INT);
+ done++;
+ break;
+
+ case 'E': /* ANSI emulation */
+ *(fsp-1) = 'e';
+ goto rval;
+ case 'G': /* ANSI emulation */
+ *(fsp-1) = 'g';
+ goto rval;
+
+ case 'z': /* nonstandard UNIX */
+ case 'h': /* nonstandard UNIX */
+ case 'H': /* nonstandard UNIX */
+ case 'm': /* nonstandard UNIX */
+ case 'M': /* nonstandard UNIX */
+ case 'e':
+ case 'f':
+ case 'g':
+ /* If no precision was specified, default to 14 digits
+ * for %[efgz] and 3 digits for %[hm].
+ */
+rval: if (!dotseen) {
+ *(fsp-1) = '.';
+ if (ch == 'h' || ch == 'm' ||
+ ch == 'H' || ch == 'M') {
+ *fsp++ = '3';
+ } else {
+ *fsp++ = '1';
+ *fsp++ = '4';
+ }
+ *fsp++ = ch;
+ }
+
+ *fsp = XEOS;
+ u_doarg (fp, formspec, &argp, prec, varprec, TY_DOUBLE);
+ done++;
+ break;
+
+ case 's':
+ *fsp = EOS;
+ u_doarg (fp, formspec, &argp, prec, varprec, TY_CHAR);
+ done++;
+ break;
+
+ case 't': /* nonstandard UNIX */
+ case 'w': /* nonstandard UNIX */
+ *fsp = EOS;
+ u_doarg (fp, formspec, &argp, prec, varprec, NOARG);
+ done++;
+ break;
+
+ case '%':
+ putc (ch, fp);
+ done++;
+ break;
+ }
+ }
+
+ } else
+ putc (ch, fp);
+ }
+}
+
+
+/* U_DOARG -- Encode a single argument acording to the simplified format
+** specification given by formspec. This is the interface to the IRAF
+** formatted output procedures.
+*/
+void
+u_doarg (fp, formspec, argp, prec, varprec, dtype)
+FILE *fp; /* output file */
+XCHAR *formspec; /* format string */
+va_list **argp; /* pointer to data value */
+int prec[]; /* varprec args, if any */
+int varprec; /* number of varprec args */
+int dtype; /* datatype of data value */
+{
+ register int p;
+ XCHAR sbuf[SZ_OBUF+1];
+ XINT fd = fileno (fp);
+ XINT ival;
+ XDOUBLE dval;
+ char *cptr;
+
+
+ /* Pass format string and any variable precision arguments.
+ */
+ FPRINTF (&fd, formspec);
+ for (p=0; p < varprec; p++) {
+ ival = prec[p];
+ PARGI (&ival);
+ }
+
+ /* Pass the data value to be encoded, bump argument pointer by the
+ * size of the data object. If there is no data value the case
+ * is a no-op.
+ */
+ switch (dtype) {
+ case TY_INT:
+ ival = va_arg ((**argp), int);
+ PARGI (&ival);
+ break;
+ case TY_DOUBLE:
+ dval = va_arg ((**argp), double);
+ PARGD (&dval);
+ break;
+ case TY_CHAR:
+ cptr = va_arg ((**argp), char *);
+ PARGSTR (c_strupk (cptr, sbuf, SZ_OBUF));
+ break;
+ }
+}