implemented Setup.hs to build boehm cpp libs and install them;
[hs-boehmgc.git] / gc-7.2 / cord / cordprnt.c
diff --git a/gc-7.2/cord/cordprnt.c b/gc-7.2/cord/cordprnt.c
new file mode 100644 (file)
index 0000000..f4c6386
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* An sprintf implementation that understands cords.  This is probably  */
+/* not terribly portable.  It assumes an ANSI stdarg.h.  It further     */
+/* assumes that I can make copies of va_list variables, and read        */
+/* arguments repeatedly by applying va_arg to the copies.  This         */
+/* could be avoided at some performance cost.                           */
+/* We also assume that unsigned and signed integers of various kinds    */
+/* have the same sizes, and can be cast back and forth.                 */
+/* We assume that void * and char * have the same size.                 */
+/* All this cruft is needed because we want to rely on the underlying   */
+/* sprintf implementation whenever possible.                            */
+
+#include "cord.h"
+#include "ec.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include "gc.h"
+
+#define CONV_SPEC_LEN 50        /* Maximum length of a single   */
+                                /* conversion specification.    */
+#define CONV_RESULT_LEN 50      /* Maximum length of any        */
+                                /* conversion with default      */
+                                /* width and prec.              */
+
+
+static int ec_len(CORD_ec x)
+{
+    return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
+}
+
+/* Possible nonumeric precision values. */
+# define NONE -1
+# define VARIABLE -2
+/* Copy the conversion specification from CORD_pos into the buffer buf  */
+/* Return negative on error.                                            */
+/* Source initially points one past the leading %.                      */
+/* It is left pointing at the conversion type.                          */
+/* Assign field width and precision to *width and *prec.                */
+/* If width or prec is *, VARIABLE is assigned.                         */
+/* Set *left to 1 if left adjustment flag is present.                   */
+/* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to       */
+/* -1 if 'h' is present.                                                */
+static int extract_conv_spec(CORD_pos source, char *buf,
+                             int * width, int *prec, int *left, int * long_arg)
+{
+    register int result = 0;
+    register int current_number = 0;
+    register int saw_period = 0;
+    register int saw_number = 0;
+    register int chars_so_far = 0;
+    register char current;
+
+    *width = NONE;
+    buf[chars_so_far++] = '%';
+    while(CORD_pos_valid(source)) {
+        if (chars_so_far >= CONV_SPEC_LEN) return(-1);
+        current = CORD_pos_fetch(source);
+        buf[chars_so_far++] = current;
+        switch(current) {
+          case '*':
+            saw_number = 1;
+            current_number = VARIABLE;
+            break;
+          case '0':
+            if (!saw_number) {
+                /* Zero fill flag; ignore */
+                break;
+            } /* otherwise fall through: */
+          case '1':
+          case '2':
+          case '3':
+          case '4':
+          case '5':
+          case '6':
+          case '7':
+          case '8':
+          case '9':
+            saw_number = 1;
+            current_number *= 10;
+            current_number += current - '0';
+            break;
+          case '.':
+            saw_period = 1;
+            if(saw_number) {
+                *width = current_number;
+                saw_number = 0;
+            }
+            current_number = 0;
+            break;
+          case 'l':
+          case 'L':
+            *long_arg = 1;
+            current_number = 0;
+            break;
+          case 'h':
+            *long_arg = -1;
+            current_number = 0;
+            break;
+          case ' ':
+          case '+':
+          case '#':
+            current_number = 0;
+            break;
+          case '-':
+            *left = 1;
+            current_number = 0;
+            break;
+          case 'd':
+          case 'i':
+          case 'o':
+          case 'u':
+          case 'x':
+          case 'X':
+          case 'f':
+          case 'e':
+          case 'E':
+          case 'g':
+          case 'G':
+          case 'c':
+          case 'C':
+          case 's':
+          case 'S':
+          case 'p':
+          case 'n':
+          case 'r':
+            goto done;
+          default:
+            return(-1);
+        }
+        CORD_next(source);
+    }
+    return(-1);
+  done:
+    if (saw_number) {
+        if (saw_period) {
+            *prec = current_number;
+        } else {
+            *prec = NONE;
+            *width = current_number;
+        }
+    } else {
+        *prec = NONE;
+    }
+    buf[chars_so_far] = '\0';
+    return(result);
+}
+
+int CORD_vsprintf(CORD * out, CORD format, va_list args)
+{
+    CORD_ec result;
+    register int count;
+    register char current;
+    CORD_pos pos;
+    char conv_spec[CONV_SPEC_LEN + 1];
+
+    CORD_ec_init(result);
+    for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
+        current = CORD_pos_fetch(pos);
+        if (current == '%') {
+            CORD_next(pos);
+            if (!CORD_pos_valid(pos)) return(-1);
+            current = CORD_pos_fetch(pos);
+            if (current == '%') {
+                CORD_ec_append(result, current);
+            } else {
+                int width, prec;
+                int left_adj = 0;
+                int long_arg = 0;
+                CORD arg;
+                size_t len;
+
+                if (extract_conv_spec(pos, conv_spec,
+                                      &width, &prec,
+                                      &left_adj, &long_arg) < 0) {
+                    return(-1);
+                }
+                current = CORD_pos_fetch(pos);
+                switch(current) {
+                    case 'n':
+                        /* Assign length to next arg */
+                        if (long_arg == 0) {
+                            int * pos_ptr;
+                            pos_ptr = va_arg(args, int *);
+                            *pos_ptr = ec_len(result);
+                        } else if (long_arg > 0) {
+                            long * pos_ptr;
+                            pos_ptr = va_arg(args, long *);
+                            *pos_ptr = ec_len(result);
+                        } else {
+                            short * pos_ptr;
+                            pos_ptr = va_arg(args, short *);
+                            *pos_ptr = ec_len(result);
+                        }
+                        goto done;
+                    case 'r':
+                        /* Append cord and any padding  */
+                        if (width == VARIABLE) width = va_arg(args, int);
+                        if (prec == VARIABLE) prec = va_arg(args, int);
+                        arg = va_arg(args, CORD);
+                        len = CORD_len(arg);
+                        if (prec != NONE && len > (size_t)prec) {
+                          if (prec < 0) return(-1);
+                          arg = CORD_substr(arg, 0, prec);
+                          len = prec;
+                        }
+                        if (width != NONE && len < (size_t)width) {
+                          char * blanks = GC_MALLOC_ATOMIC(width-len+1);
+
+                          memset(blanks, ' ', width-len);
+                          blanks[width-len] = '\0';
+                          if (left_adj) {
+                            arg = CORD_cat(arg, blanks);
+                          } else {
+                            arg = CORD_cat(blanks, arg);
+                          }
+                        }
+                        CORD_ec_append_cord(result, arg);
+                        goto done;
+                    case 'c':
+                        if (width == NONE && prec == NONE) {
+                            register char c;
+
+                            c = (char)va_arg(args, int);
+                            CORD_ec_append(result, c);
+                            goto done;
+                        }
+                        break;
+                    case 's':
+                        if (width == NONE && prec == NONE) {
+                            char * str = va_arg(args, char *);
+                            register char c;
+
+                            while ((c = *str++)) {
+                                CORD_ec_append(result, c);
+                            }
+                            goto done;
+                        }
+                        break;
+                    default:
+                        break;
+                }
+                /* Use standard sprintf to perform conversion */
+                {
+                    register char * buf;
+                    va_list vsprintf_args;
+                    int max_size = 0;
+                    int res;
+#                   ifdef __va_copy
+                      __va_copy(vsprintf_args, args);
+#                   else
+#                     if defined(__GNUC__) && !defined(__DJGPP__) /* and probably in other cases */
+                        va_copy(vsprintf_args, args);
+#                     else
+                        vsprintf_args = args;
+#                     endif
+#                   endif
+                    if (width == VARIABLE) width = va_arg(args, int);
+                    if (prec == VARIABLE) prec = va_arg(args, int);
+                    if (width != NONE) max_size = width;
+                    if (prec != NONE && prec > max_size) max_size = prec;
+                    max_size += CONV_RESULT_LEN;
+                    if (max_size >= CORD_BUFSZ) {
+                        buf = GC_MALLOC_ATOMIC(max_size + 1);
+                    } else {
+                        if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
+                            < max_size) {
+                            CORD_ec_flush_buf(result);
+                        }
+                        buf = result[0].ec_bufptr;
+                    }
+                    switch(current) {
+                        case 'd':
+                        case 'i':
+                        case 'o':
+                        case 'u':
+                        case 'x':
+                        case 'X':
+                        case 'c':
+                            if (long_arg <= 0) {
+                              (void) va_arg(args, int);
+                            } else if (long_arg > 0) {
+                              (void) va_arg(args, long);
+                            }
+                            break;
+                        case 's':
+                        case 'p':
+                            (void) va_arg(args, char *);
+                            break;
+                        case 'f':
+                        case 'e':
+                        case 'E':
+                        case 'g':
+                        case 'G':
+                            (void) va_arg(args, double);
+                            break;
+                        default:
+                            return(-1);
+                    }
+                    res = vsprintf(buf, conv_spec, vsprintf_args);
+                    len = (size_t)res;
+                    if ((char *)(GC_word)res == buf) {
+                        /* old style vsprintf */
+                        len = strlen(buf);
+                    } else if (res < 0) {
+                        return(-1);
+                    }
+                    if (buf != result[0].ec_bufptr) {
+                        register char c;
+
+                        while ((c = *buf++)) {
+                            CORD_ec_append(result, c);
+                        }
+                    } else {
+                        result[0].ec_bufptr = buf + len;
+                    }
+                }
+              done:;
+            }
+        } else {
+            CORD_ec_append(result, current);
+        }
+    }
+    count = ec_len(result);
+    *out = CORD_balance(CORD_ec_to_cord(result));
+    return(count);
+}
+
+int CORD_sprintf(CORD * out, CORD format, ...)
+{
+    va_list args;
+    int result;
+
+    va_start(args, format);
+    result = CORD_vsprintf(out, format, args);
+    va_end(args);
+    return(result);
+}
+
+int CORD_fprintf(FILE * f, CORD format, ...)
+{
+    va_list args;
+    int result;
+    CORD out;
+
+    va_start(args, format);
+    result = CORD_vsprintf(&out, format, args);
+    va_end(args);
+    if (result > 0) CORD_put(out, f);
+    return(result);
+}
+
+int CORD_vfprintf(FILE * f, CORD format, va_list args)
+{
+    int result;
+    CORD out;
+
+    result = CORD_vsprintf(&out, format, args);
+    if (result > 0) CORD_put(out, f);
+    return(result);
+}
+
+int CORD_printf(CORD format, ...)
+{
+    va_list args;
+    int result;
+    CORD out;
+
+    va_start(args, format);
+    result = CORD_vsprintf(&out, format, args);
+    va_end(args);
+    if (result > 0) CORD_put(out, stdout);
+    return(result);
+}
+
+int CORD_vprintf(CORD format, va_list args)
+{
+    int result;
+    CORD out;
+
+    result = CORD_vsprintf(&out, format, args);
+    if (result > 0) CORD_put(out, stdout);
+    return(result);
+}