+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Generate limit MPs for C types
+ *
+ * (c) 2006 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#if __STDC_VERSION__ >= 199900l
+# include <stdint.h>
+# include <inttypes.h>
+#endif
+
+#include "mp.h"
+#include "mpint.h"
+
+/*----- Data types --------------------------------------------------------*/
+
+/* --- Hack for GCC --- *
+ *
+ * WG14 in their infinite wisdom decided not to use the GCC constant name.
+ */
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91)
+# define EXT __extension__
+#else
+# define EXT
+#endif
+
+#if defined(LONG_LONG_MIN) && !defined(LLONG_MIN)
+# define LLONG_MIN EXT LONG_LONG_MIN
+#endif
+
+#if defined(LONG_LONG_MAX) && !defined(LLONG_MAX)
+# define LLONG_MAX EXT LONG_LONG_MAX
+#endif
+
+#if defined(ULONG_LONG_MAX) && !defined(ULLONG_MAX)
+# define ULLONG_MAX EXT ULONG_LONG_MAX
+#endif
+
+/* --- Choose the largest integer type --- */
+
+#if defined(INTMAX_MAX)
+ typedef intmax_t imax;
+#elif defined(LLONG_MAX)
+ EXT typedef long long imax;
+#else
+ typedef long imax;
+#endif
+
+#if defined(UINTMAX_MAX)
+ typedef uintmax_t umax;
+#elif defined(ULLONG_MAX)
+ EXT typedef unsigned long long umax;
+#else
+ typedef unsigned long umax;
+#endif
+
+/*----- Main code ---------------------------------------------------------*/
+
+#define TABSZ 64
+
+enum { NEG, POS, NSIGN };
+
+umax cmap[TABSZ];
+int gmap[TABSZ][NSIGN];
+struct { int g, s; } qmap[TABSZ];
+int dumpp = 0;
+
+static int n, q;
+
+static void dump(mp *x)
+{
+ int i, w, n;
+
+ fputs(" ", stdout);
+ w = (MPW_BITS + 3)/4;
+ n = 1;
+ while (2 + 2 * n * (4 + w) < 72) n <<= 1;
+ i = 0;
+ for (;;) {
+ printf("0x%0*x", w, x->v[i]);
+ i++;
+ if (i >= MP_LEN(x)) break;
+ fputs(",", stdout);
+ if (i % n) fputs(" ", stdout); else fputs("\n ", stdout);
+ }
+ fputs("\n", stdout);
+}
+
+static void doemit(umax c, int s, int *gg, int *qq)
+{
+ int i;
+ mp *x = MP_NEW;
+
+ for (i = 0; i < n; i++) {
+ if (cmap[i] == c)
+ goto found;
+ }
+
+ assert(i < TABSZ);
+ n = i + 1;
+ cmap[i] = c;
+ gmap[i][POS] = gmap[i][NEG] = -1;
+ if (dumpp) {
+ MP_FROMINT(x, umax, c);
+ printf("static mpw guts_%d[] = {\n", q);
+ dump(x);
+ fputs("};\n\n", stdout);
+ MP_DROP(x);
+ }
+
+found:
+ *gg = i;
+ if (gmap[i][s] < 0) {
+ assert(q < TABSZ);
+ gmap[i][s] = q;
+ qmap[q].g = i;
+ qmap[q].s = s;
+ q++;
+ }
+ *qq = gmap[i][s];
+}
+
+static void emit(imax c, int *gg, int *qq)
+{
+ umax uc;
+ int s;
+
+ if (c >= 0) { uc = c; s = POS; }
+ else { uc = -c; s = NEG; }
+ doemit(uc, s, gg, qq);
+}
+
+static void uemit(umax c, int *gg, int *qq) { doemit(c, POS, gg, qq); }
+
+struct {
+ const char *name;
+ imax min;
+ umax max;
+ int gmin, gmax;
+ int qmin, qmax;
+} tab[] = {
+ { "SCHAR", SCHAR_MIN, SCHAR_MAX },
+ { "CHAR", CHAR_MIN, CHAR_MAX },
+ { "UCHAR", 0, UCHAR_MAX },
+ { "UINT8", 0, 0xff },
+ { "SHRT", SHRT_MIN, SHRT_MAX },
+ { "USHRT", 0, USHRT_MAX },
+ { "UINT16", 0, 0xffff },
+ { "INT", INT_MIN, INT_MAX },
+ { "UINT", 0, UINT_MAX },
+ { "LONG", LONG_MIN, LONG_MAX },
+ { "ULONG", 0, ULONG_MAX },
+ { "UINT32", 0, 0xffffffff },
+#ifdef LLONG_MAX
+ { "LLONG", LLONG_MIN, LLONG_MAX },
+ { "ULLONG", 0, ULLONG_MAX },
+#endif
+ { "SIZET", 0, ~(size_t)0 },
+ { 0 }
+};
+
+static void dogen(void)
+{
+ int i;
+
+ for (i = 0; tab[i].name; i++) {
+ if (tab[i].min)
+ emit(tab[i].min, &tab[i].gmin, &tab[i].qmin);
+ uemit(tab[i].max, &tab[i].gmax, &tab[i].qmax);
+ }
+}
+
+static void cgen(void)
+{
+ int i;
+
+ fputs("\
+/* -*-c-*-\n\
+ *\n\
+ * C integer limits [generated]\n\
+ */\n\
+\n\
+#include \"mplimits.h\"\n\
+\n\
+#define N(x) (sizeof(x)/sizeof(*x))\n\
+#define MPpos(x) { x, x + N(x), N(x), 0, MP_CONST, 0 }\n\
+#define MPneg(x) { x, x + N(x), N(x), 0, MP_CONST|MP_NEG, 0 }\n\
+\n",
+ stdout);
+ dumpp = 1;
+ dogen();
+
+ fputs("mp mp_limits[] = {\n", stdout);
+ for (i = 0; i < q; i++)
+ printf(" MP%s(guts_%d),\n", qmap[i].s ? "pos" : "neg", qmap[i].g);
+ fputs("};\n", stdout);
+}
+
+static void hgen(void)
+{
+ int i;
+
+ fputs("\
+/* -*-c-*-\n\
+ *\n\
+ * C integer limits [generated]\n\
+ */\n\
+\n\
+#ifndef CATACOMB_MPLIMITS_H\n\
+#define CATACOMB_MPLIMITS_H\n\
+\n\
+#ifndef CATACOMB_MP_H\n\
+# include \"mp.h\"\n\
+#endif\n\
+\n\
+extern mp mp_limits[];\n\
+\n",
+ stdout);
+ dogen();
+
+ for (i = 0; tab[i].name; i++) {
+ if (tab[i].min) {
+ printf("#define MP_%s_MIN (&mp_limits[%d])\n",
+ tab[i].name, gmap[tab[i].qmin][NEG]);
+ }
+ printf("#define MP_%s_MAX (&mp_limits[%d])\n",
+ tab[i].name, gmap[tab[i].qmax][POS]);
+ }
+ fputs("\n#endif\n", stdout);
+}
+
+int main(int argc, char *argv[])
+{
+ const char *what = argc == 2 ? argv[1] : "<bogus>";
+
+ switch (what[0]) {
+ case 'c': cgen(); break;
+ case 'h': hgen(); break;
+ default:
+ fprintf(stderr, "unknown action `%s'\n", what);
+ exit(1);
+ }
+ if (fflush(stdout) || fclose(stdout)) {
+ fprintf(stderr, "error writing output: %s\n", strerror(errno));
+ exit(1);
+ }
+ return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/