[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Changes to m4/src/format.c [branch-1_4]
From: |
Gary V . Vaughan |
Subject: |
Changes to m4/src/format.c [branch-1_4] |
Date: |
Sun, 01 May 2005 07:54:17 -0400 |
Index: m4/src/format.c
diff -u /dev/null m4/src/format.c:1.1.1.1.2.1
--- /dev/null Sun May 1 11:54:17 2005
+++ m4/src/format.c Sun May 1 11:54:12 2005
@@ -0,0 +1,747 @@
+/* GNU m4 -- A simple macro processor
+
+ Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
+
+ This program 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 of the License, or
+ (at your option) any later version.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA
+*/
+
+/* printf like formatting for m4. */
+
+#include "m4.h"
+
+#ifdef HAVE_EFGCVT
+
+/* Various constants for floating point formatting. */
+#define MAXFIELD 128 /* size of buffer for formatted text */
+/* The following two are hardware dependant. */
+#define ECVTMAX 18 /* max number of significant digits for
%e */
+#define FCVTMAX (18+38+4) /* max number of significant digits
for %f */
+
+/* Externs used herein. */
+#if HAVE_EFGCVT <= 1
+extern char *ecvt (), *fcvt (), *gcvt ();
+#endif
+
+#ifndef STDC_HEADERS
+extern int atoi ();
+extern long atol ();
+extern double atof ();
+#endif /* STDC_HEADERS */
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+static char const digits[] = "0123456789abcdef";
+static char const Digits[] = "0123456789ABCDEF";
+
+/* STR has dimension MAXFIELD (?). */
+
+static char *
+ulong_to_str (register unsigned long val, char *str, int base,
+ const char *digits)
+{
+ register char *s = &str[MAXFIELD];
+
+ *--s = '\0';
+ do
+ {
+ *--s = digits[val % base];
+ val /= base;
+ }
+ while (val > 0);
+
+ return s;
+}
+
+/*-----------------------------------------.
+| Clear trailing zeroes, return argument. |
+`-----------------------------------------*/
+
+static char *
+clr0 (char *s)
+{
+ register char *t;
+
+ for (t = s + strlen (s); *--t == '0' && t > s;)
+ *t = '\0';
+ return s;
+}
+
+#endif /* HAVE_EFGCVT */
+
+/* Simple varargs substitute. */
+
+#define ARG_INT(argc, argv) \
+ ((argc == 0) ? 0 : \
+ (--argc, argv++, atoi (TOKEN_DATA_TEXT (argv[-1]))))
+
+#define ARG_UINT(argc, argv) \
+ ((argc == 0) ? 0 : \
+ (--argc, argv++, (unsigned int) atoi (TOKEN_DATA_TEXT (argv[-1]))))
+
+#define ARG_LONG(argc, argv) \
+ ((argc == 0) ? 0 : \
+ (--argc, argv++, atol (TOKEN_DATA_TEXT (argv[-1]))))
+
+#define ARG_ULONG(argc, argv) \
+ ((argc == 0) ? 0 : \
+ (--argc, argv++, (unsigned long) atol (TOKEN_DATA_TEXT (argv[-1]))))
+
+#define ARG_STR(argc, argv) \
+ ((argc == 0) ? "" : \
+ (--argc, argv++, TOKEN_DATA_TEXT (argv[-1])))
+
+#define ARG_DOUBLE(argc, argv) \
+ ((argc == 0) ? 0 : \
+ (--argc, argv++, atof (TOKEN_DATA_TEXT (argv[-1]))))
+
+
+/*------------------------------------------------------------------------.
+| The main formatting function. Output is placed on the obstack OBS, the |
+| first argument in ARGV is the formatting string, and the rest is |
+| arguments for the string. |
+`------------------------------------------------------------------------*/
+
+void
+format (struct obstack *obs, int argc, token_data **argv)
+{
+#ifdef HAVE_EFGCVT
+
+ const char *fmt; /* format control string */
+ int c; /* a simple character */
+ char fc; /* format code */
+
+ /* Flags. */
+ char flags; /* 1 iff treating flags */
+ char ljust; /* left justification */
+ char mandsign; /* mandatory sign */
+ char noplus; /* use space if no sign */
+ char alternate; /* use alternate form */
+ char zeropad; /* do zero padding */
+ char plus; /* plus-sign, according to mandatory and noplus
*/
+
+ /* Precision specifiers. */
+ int width; /* minimum field width */
+ int prec; /* precision */
+ int maxch; /* maximum no. of chars to print */
+ char lflag; /* long flag */
+ char hflag; /* short flag */
+
+ /* Different parts of each specification. */
+ char sign; /* wanted sign, iff any */
+ int ppad; /* pre-prefix zero padding */
+ const char *prefix; /* value prefix */
+ int lpad; /* zero padding on the left */
+ register char *s; /* ptr to formatted text */
+ int rpad; /* zero padding on the rigth*/
+ const char *suffix; /* value suffix */
+
+ /* Buffer and stuff. */
+ char str[MAXFIELD]; /* buffer for formatted text */
+ int length; /* length of str */
+ int padding; /* padding at the left or rigth */
+ register int i; /* an index */
+
+/* Length of trailing string in str. */
+#define LENGTH(s) (&str[MAXFIELD-1] - (s))
+#define HAS_SIGN (sign != '\0')
+
+ fmt = ARG_STR (argc, argv);
+ for (;;)
+ {
+ while ((c = *fmt++) != '%')
+ {
+ if (c == 0)
+ return;
+ obstack_1grow (obs, c);
+ }
+ if (*fmt == '%')
+ {
+ obstack_1grow (obs, '%');
+ fmt++;
+ continue;
+ }
+
+ /* Parse flags. */
+ flags = 1;
+ ljust = mandsign = noplus = alternate = zeropad = 0;
+ do
+ {
+ switch (*fmt)
+ {
+ case '-': /* left justification */
+ ljust = 1;
+ break;
+
+ case '+': /* mandatory sign */
+ mandsign = 1;
+ break;
+
+ case ' ': /* space instead of positive sign */
+ noplus = 1;
+ break;
+
+ case '0': /* zero padding */
+ zeropad = 1;
+ break;
+
+ case '#': /* alternate output */
+ alternate = 1;
+ break;
+
+ default:
+ flags = 0;
+ break;
+ }
+ }
+ while (flags && fmt++);
+
+ plus = '\0'; /* what to use as a plus ??? */
+ if (mandsign)
+ plus = '+';
+ else if (noplus)
+ plus = ' ';
+
+ if (ljust)
+ zeropad = 0;
+
+ /* Minimum field width. */
+ width = -1;
+ if (*fmt == '*')
+ {
+ width = ARG_INT (argc, argv);
+ fmt++;
+ }
+ else if (isdigit (*fmt))
+ {
+ width = 0;
+ do
+ {
+ width = width * 10 + *fmt++ - '0';
+ }
+ while (isdigit (*fmt));
+ }
+
+ /* Maximum precision. */
+ prec = -1;
+ if (*fmt == '.')
+ {
+ if (*(++fmt) == '*')
+ {
+ prec = ARG_INT (argc, argv);
+ ++fmt;
+ }
+ else if (isdigit (*fmt))
+ {
+ prec = 0;
+ do
+ {
+ prec = prec * 10 + *fmt++ - '0';
+ }
+ while (isdigit (*fmt))
+ ;
+ }
+ }
+
+ /* Length modifiers. */
+ lflag = (*fmt == 'l');
+ hflag = (*fmt == 'h');
+ if (lflag || hflag)
+ fmt++;
+
+ sign = '\0';
+ ppad = lpad = rpad = 0;
+ maxch = -1;
+ prefix = suffix = "";
+
+ switch (fc = *fmt++)
+ {
+
+ case '\0':
+ return;
+
+ case 'c':
+ c = ARG_INT (argc, argv);
+ str[0] = (unsigned char) c;
+ str[1] = '\0';
+ s = str;
+ break;
+
+ case 's':
+ s = ARG_STR (argc, argv);
+ maxch = prec;
+ break;
+
+ case 'd':
+ case 'i':
+ if (lflag)
+ {
+ long val = ARG_LONG (argc, argv);
+ if (val < 0)
+ {
+ val = -val; /* does not work for MINLONG */
+ sign = '-';
+ }
+ else
+ sign = plus;
+ s = ulong_to_str ((unsigned long) val, str, 10, digits);
+ }
+ else
+ {
+ int val = ARG_INT (argc, argv);
+ if (hflag)
+ val = (short) val;
+ if (val < 0)
+ {
+ val = -val; /* does not work for MININT */
+ sign = '-';
+ }
+ else
+ sign = plus;
+ s = ulong_to_str ((unsigned long) val, str, 10, digits);
+ }
+ if (zeropad)
+ lpad = width - LENGTH (s) - HAS_SIGN;
+ break;
+
+ case 'o':
+ if (lflag)
+ {
+ unsigned long val = ARG_ULONG (argc, argv);
+ s = ulong_to_str ((unsigned long) val, str, 8, digits);
+ }
+ else
+ {
+ unsigned int val = ARG_UINT (argc, argv);
+ if (hflag)
+ val = (unsigned short) val;
+ s = ulong_to_str ((unsigned long) val, str, 8, digits);
+ }
+ if (alternate)
+ prefix = "0";
+ if (zeropad)
+ lpad = width - LENGTH (s) - alternate;
+ break;
+
+ case 'x':
+ case 'X':
+ if (lflag)
+ {
+ unsigned long val = ARG_ULONG (argc, argv);
+ s = ulong_to_str ((unsigned long) val, str, 16,
+ (fc == 'x') ? digits : Digits);
+ }
+ else
+ {
+ unsigned int val = ARG_UINT (argc, argv);
+ if (hflag)
+ val = (unsigned short) val;
+ s = ulong_to_str ((unsigned long) val, str, 16,
+ (fc == 'x') ? digits : Digits);
+ }
+ if (alternate)
+ prefix = (fc == 'X') ? "0X" : "0x";
+ if (zeropad)
+ lpad = width - LENGTH (s) - 2*alternate;
+ break;
+
+ case 'u':
+ if (lflag)
+ {
+ unsigned long val = ARG_ULONG (argc, argv);
+ s = ulong_to_str ((unsigned long) val, str, 10, digits);
+ }
+ else
+ {
+ unsigned int val = ARG_UINT (argc, argv);
+ if (hflag)
+ val = (unsigned short) val;
+ s = ulong_to_str ((unsigned long) val, str, 10, digits);
+ }
+ if (zeropad)
+ lpad = width - LENGTH (s);
+ break;
+
+ case 'e':
+ case 'E':
+ {
+ char *t;
+ int sgn, decpt, exp, n;
+ double val = ARG_DOUBLE (argc, argv);
+
+ if (prec < 0)
+ prec = 6;
+ t = clr0 (ecvt (val, min (prec + 1, ECVTMAX), &decpt, &sgn));
+ sign = sgn ? '-' : plus;
+
+ n = prec;
+ s = str;
+ exp = (t[0] == '0' && t[1] == '\0') ? 0 : decpt - 1;
+
+ *s++ = *t++;
+ if (n > 0 || alternate)
+ *s++ = '.';
+ while (*t != '\0' && --n >= 0)
+ *s++ = *t++;
+ *s = '\0';
+ rpad = n;
+
+ sgn = 0;
+ if (exp < 0)
+ {
+ exp = -exp;
+ sgn = 1;
+ }
+ t = ulong_to_str ((unsigned long) exp, str, 10, digits);
+ if (exp < 10)
+ *--t = '0'; /* always at least two digits */
+ *--t = sgn ? '-' : '+';
+ *--t = fc;
+
+ if (zeropad)
+ {
+ lpad = width - HAS_SIGN - (s - str) - LENGTH (t);
+ if (rpad > 0)
+ lpad -= rpad;
+ }
+
+ suffix = t;
+ s = str;
+ }
+ break;
+
+ case 'f':
+ {
+ const char *t;
+ int sgn, decpt, n;
+ double val = ARG_DOUBLE (argc, argv);
+
+ if (prec < 0)
+ prec = 6;
+
+ /* FIXME: For the following line, Dave Anglin reports
+ ``warning: passing arg 1 of `clr0' discards `const' from
+ pointer target type''. I suspect fcvt might be declared
+ as returning const on some systems. Pouah! I should
+ revise this whole module, one of these days... */
+
+ t = clr0 (fcvt (val, min (prec, FCVTMAX), &decpt, &sgn));
+
+ sign = sgn ? '-' : plus;
+
+ n = prec;
+ s = str;
+
+ if (decpt <= 0)
+ {
+ prefix = (n > 0 || alternate) ? "0." : "0";
+ lpad = min (-decpt, prec);
+ n -= lpad;
+ }
+ else
+ {
+ while (--decpt >= 0)
+ *s++ = *t++;
+ if (n > 0 || alternate)
+ *s++ = '.';
+ }
+ while (*t && --n >= 0)
+ *s++ = *t++;
+
+ *s = '\0';
+ rpad = n;
+
+ if (zeropad)
+ ppad = width - HAS_SIGN - (prefix[1] ? 2 : 1) - lpad -
+ (s - str) - rpad;
+
+ s = str;
+ }
+ break;
+
+ default:
+ continue;
+ }
+
+ if (lpad < 0)
+ lpad = 0;
+ if (rpad < 0)
+ rpad = 0;
+ if (width < 0)
+ width = 0;
+
+ i = strlen (s);
+ if (maxch <= 0 || maxch > i)
+ maxch = i;
+
+ length = (HAS_SIGN + ppad + strlen (prefix) + lpad + maxch
+ + rpad + strlen (suffix));
+ padding = 0;
+ if (width != 0)
+ {
+ padding = width - length;
+ }
+
+ if (ljust == 0) /* left padding */
+ for (i = padding; --i >= 0;)
+ obstack_1grow (obs, ' ');
+ if (HAS_SIGN) /* sign */
+ obstack_1grow (obs, sign);
+ for (i = ppad; --i >= 0;) /* pre-prefix zero padding */
+ obstack_1grow (obs, '0');
+ for (; *prefix; ++prefix) /* prefix */
+ obstack_1grow (obs, *prefix);
+ for (i = lpad; --i >= 0;) /* left zero padding */
+ obstack_1grow (obs, '0');
+ for (i = maxch; --i >= 0; ++s) /* actual text */
+ obstack_1grow (obs, *s);
+ for (i = rpad; --i >= 0;) /* right zero padding */
+ obstack_1grow (obs, '0');
+ for (; *suffix; ++suffix) /* suffix */
+ obstack_1grow (obs, *suffix);
+ if (ljust != 0) /* right padding */
+ for (i = padding; --i >= 0;)
+ obstack_1grow (obs, ' ');
+ }
+
+#else /* not HAVE_EFGCVT */
+
+ char *fmt; /* format control string */
+ const char *fstart; /* beginning of current format spec */
+ int c; /* a simple character */
+
+ /* Flags. */
+ char flags; /* 1 iff treating flags */
+
+ /* Precision specifiers. */
+ int width; /* minimum field width */
+ int prec; /* precision */
+ char lflag; /* long flag */
+ char hflag; /* short flag */
+
+ /* Buffer and stuff. */
+ char str[256]; /* buffer for formatted text */
+ enum {INT, UINT, LONG, ULONG, DOUBLE, STR} datatype;
+
+ fmt = ARG_STR (argc, argv);
+ for (;;)
+ {
+ while ((c = *fmt++) != '%')
+ {
+ if (c == 0)
+ return;
+ obstack_1grow (obs, c);
+ }
+
+ fstart = fmt - 1;
+
+ if (*fmt == '%')
+ {
+ obstack_1grow (obs, '%');
+ fmt++;
+ continue;
+ }
+
+ /* Parse flags. */
+ flags = 1;
+ do
+ {
+ switch (*fmt)
+ {
+ case '-': /* left justification */
+ case '+': /* mandatory sign */
+ case ' ': /* space instead of positive sign */
+ case '0': /* zero padding */
+ case '#': /* alternate output */
+ break;
+
+ default:
+ flags = 0;
+ break;
+ }
+ }
+ while (flags && fmt++);
+
+ /* Minimum field width. */
+ width = -1;
+ if (*fmt == '*')
+ {
+ width = ARG_INT (argc, argv);
+ fmt++;
+ }
+ else if (isdigit (*fmt))
+ {
+ do
+ {
+ fmt++;
+ }
+ while (isdigit (*fmt));
+ }
+
+ /* Maximum precision. */
+ prec = -1;
+ if (*fmt == '.')
+ {
+ if (*(++fmt) == '*')
+ {
+ prec = ARG_INT (argc, argv);
+ ++fmt;
+ }
+ else if (isdigit (*fmt))
+ {
+ do
+ {
+ fmt++;
+ }
+ while (isdigit (*fmt));
+ }
+ }
+
+ /* Length modifiers. */
+ lflag = (*fmt == 'l');
+ hflag = (*fmt == 'h');
+ if (lflag || hflag)
+ fmt++;
+
+ switch (*fmt++)
+ {
+
+ case '\0':
+ return;
+
+ case 'c':
+ datatype = INT;
+ break;
+
+ case 's':
+ datatype = STR;
+ break;
+
+ case 'd':
+ case 'i':
+ if (lflag)
+ {
+ datatype = LONG;
+ }
+ else
+ {
+ datatype = INT;
+ }
+ break;
+
+ case 'o':
+ case 'x':
+ case 'X':
+ case 'u':
+ if (lflag)
+ {
+ datatype = ULONG;
+ }
+ else
+ {
+ datatype = UINT;
+ }
+ break;
+
+ case 'e':
+ case 'E':
+ case 'f':
+ datatype = DOUBLE;
+ break;
+
+ default:
+ continue;
+ }
+
+ c = *fmt;
+ *fmt = '\0';
+
+ switch(datatype)
+ {
+ case INT:
+ if (width != -1 && prec != -1)
+ sprintf (str, fstart, width, prec, ARG_INT(argc, argv));
+ else if (width != -1)
+ sprintf (str, fstart, width, ARG_INT(argc, argv));
+ else if (prec != -1)
+ sprintf (str, fstart, prec, ARG_INT(argc, argv));
+ else
+ sprintf (str, fstart, ARG_INT(argc, argv));
+ break;
+
+ case UINT:
+ if (width != -1 && prec != -1)
+ sprintf (str, fstart, width, prec, ARG_UINT(argc, argv));
+ else if (width != -1)
+ sprintf (str, fstart, width, ARG_UINT(argc, argv));
+ else if (prec != -1)
+ sprintf (str, fstart, prec, ARG_UINT(argc, argv));
+ else
+ sprintf (str, fstart, ARG_UINT(argc, argv));
+ break;
+
+ case LONG:
+ if (width != -1 && prec != -1)
+ sprintf (str, fstart, width, prec, ARG_LONG(argc, argv));
+ else if (width != -1)
+ sprintf (str, fstart, width, ARG_LONG(argc, argv));
+ else if (prec != -1)
+ sprintf (str, fstart, prec, ARG_LONG(argc, argv));
+ else
+ sprintf (str, fstart, ARG_LONG(argc, argv));
+ break;
+
+ case ULONG:
+ if (width != -1 && prec != -1)
+ sprintf (str, fstart, width, prec, ARG_ULONG(argc, argv));
+ else if (width != -1)
+ sprintf (str, fstart, width, ARG_ULONG(argc, argv));
+ else if (prec != -1)
+ sprintf (str, fstart, prec, ARG_ULONG(argc, argv));
+ else
+ sprintf (str, fstart, ARG_ULONG(argc, argv));
+ break;
+
+ case DOUBLE:
+ if (width != -1 && prec != -1)
+ sprintf (str, fstart, width, prec, ARG_DOUBLE(argc, argv));
+ else if (width != -1)
+ sprintf (str, fstart, width, ARG_DOUBLE(argc, argv));
+ else if (prec != -1)
+ sprintf (str, fstart, prec, ARG_DOUBLE(argc, argv));
+ else
+ sprintf (str, fstart, ARG_DOUBLE(argc, argv));
+ break;
+
+ case STR:
+ if (width != -1 && prec != -1)
+ sprintf (str, fstart, width, prec, ARG_STR(argc, argv));
+ else if (width != -1)
+ sprintf (str, fstart, width, ARG_STR(argc, argv));
+ else if (prec != -1)
+ sprintf (str, fstart, prec, ARG_STR(argc, argv));
+ else
+ sprintf (str, fstart, ARG_STR(argc, argv));
+ break;
+ }
+
+ *fmt = c;
+
+ obstack_grow (obs, str, strlen (str));
+ }
+
+#endif /* not HAVE_EFGCVT */
+}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Changes to m4/src/format.c [branch-1_4],
Gary V . Vaughan <=