diff interps/c-intercal/src/cesspool.c @ 996:859f9b4339e6

<Gregor> tar xf egobot.tar.xz
author HackBot
date Sun, 09 Dec 2012 19:30:08 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interps/c-intercal/src/cesspool.c	Sun Dec 09 19:30:08 2012 +0000
@@ -0,0 +1,933 @@
+/*****************************************************************************
+
+NAME
+    cesspool.c -- storage management and runtime support for INTERCAL
+
+LICENSE TERMS
+    Copyright (C) 1996 Eric S. Raymond
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+***************************************************************************/
+/* LINTLIBRARY */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+#include <limits.h>
+#include <assert.h>
+
+#include "config.h"
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "sizes.h"
+/* AIS: To avoid a separate overloaded/nonoverloaded library, we import
+   the overloading defines here and ignore them if we don't need them. */
+#define MULTITHREAD 0
+#define OVEROPUSED 1
+#include "abcess.h"
+#include "ick_lose.h"
+
+#include "numerals.c"
+
+/* AIS: because BUFSIZ could theoretically be too large for an int... */
+#if BUFSIZ < INT_MAX
+#define INTBUFSIZ (int)BUFSIZ
+#else
+#define INTBUFSIZ (int)INT_MAX
+#endif
+
+/* and likewise, so that we can compare things to INT_MAX */
+#ifndef min
+#define min(x,y) ((x)>(y)?(y):(x))
+#endif
+
+/* and likewise, define SIZE_MAX */
+#ifndef SIZE_MAX
+#ifdef ULLONG_MAX
+#define SIZE_MAX (sizeof(unsigned short    )==sizeof(size_t)?(size_t) USHRT_MAX : \
+		  sizeof(unsigned int      )==sizeof(size_t)?(size_t)  UINT_MAX : \
+		  sizeof(unsigned long     )==sizeof(size_t)?(size_t) ULONG_MAX : \
+		  sizeof(unsigned long long)==sizeof(size_t)?(size_t)ULLONG_MAX : 0)
+#else
+#define SIZE_MAX (sizeof(unsigned short    )==sizeof(size_t)?(size_t) USHRT_MAX : \
+		  sizeof(unsigned int      )==sizeof(size_t)?(size_t)  UINT_MAX : \
+		  sizeof(unsigned long     )==sizeof(size_t)?(size_t) ULONG_MAX : 0)
+#endif
+#endif
+
+/* AIS: These will be set to stdin/stdout at the first opportunity,
+   which is not necessarily here. The annotations are to tell splint
+   that we know what we're doing here with the assignments; the
+   set to stdin/stdout will be done whenever it's necessary.
+*/
+/*@null@*/ FILE* ick_cesspoolin =0;
+/*@null@*/ FILE* ick_cesspoolout=0;
+
+/* AIS: To keep ld happy. This shouldn't ever actually get used, but
+ * give it a sane value just in case it does. (This is referenced by
+ * clc-cset.c, but due to the linking-in of the character sets
+ * themselves the reference should never be used.) */
+/*@observer@*/ /*@dependent@*/ const char* ick_datadir=".";
+
+/**********************************************************************
+ *
+ * The following functions manipulate the nexting stack
+ *
+ *********************************************************************/
+
+unsigned* ick_next; /* AIS: now allocated by ick-wrap.c */
+/*@null@*/ jmp_buf* ick_next_jmpbufs = NULL; /* AIS: for ick_ec, if needed */
+int ick_nextindex = 0;
+
+static int ick_clcsem = 0; /* AIS */
+
+void ick_pushnext(unsigned n)
+{
+    if (ick_nextindex < ick_MAXNEXT)
+	ick_next[ick_nextindex++] = n;
+    else
+	ick_lose(IE123, ick_lineno, (const char *)NULL);
+}
+
+unsigned int ick_popnext(unsigned int n)
+{
+    ick_nextindex -= n;
+    if (ick_nextindex < 0) {
+	ick_nextindex = 0;
+	return (unsigned int)-1;
+    }
+    return ick_next[ick_nextindex];
+}
+
+/* AIS: This is not the ick_resume in ick_ec.h, which is a macro and therefore
+   technically speaking doesn't clash with this function as the header file
+   ick_ec.h isn't included. */
+unsigned int ick_resume(unsigned int n)
+{
+    if (n == 0)
+    {
+	ick_lose(IE621, ick_lineno, (const char *)NULL);
+	/*@-unreachable@*/ return 0; /*@=unreachable@*/
+    }
+    else if ((n = ick_popnext(n)) == (unsigned int)-1)
+    {
+	ick_lose(IE632, ick_lineno, (const char *)NULL);
+	/*@-unreachable@*/ return 0; /*@=unreachable@*/
+    }
+    return(n);
+}
+
+/**********************************************************************
+ *
+ * The following functions implement the INTERCAL I/O model
+ *
+ *********************************************************************/
+
+unsigned int ick_pin(void)
+{
+    char		buf[INTBUFSIZ], *cp;
+    unsigned int	result = 0;
+    size_t n;
+
+    assert(buf != NULL); /* AIS: splint seems unable of figuring this
+			    out for itself */
+
+    if(!ick_cesspoolin) ick_cesspoolin=stdin; /* AIS */
+
+    if (fgets(buf, INTBUFSIZ, ick_cesspoolin) == (char *)NULL)
+	ick_lose(IE562, ick_lineno, (const char *)NULL);
+    n = strlen(buf) - 1;
+    if (n > 0 && buf[n-1] == '\r')
+	--n;
+    buf[n] = '\0';
+
+    if(ick_wimp_mode) {
+	result = (unsigned int)strtoul(buf, (char **)NULL, 10);
+	n = 1;
+    }
+    else
+    {
+	for(n=0,cp = strtok(buf, " ");cp;cp = strtok((char *)NULL, " "),n++)
+	{
+	    int	digit = -1;
+	    const numeral	*np;
+
+	    for (np = ick_numerals; np < ick_numerals + sizeof(ick_numerals)/sizeof(numeral); np++)
+		if (strcmp(np->name, cp) == 0)
+		{
+		    digit = np->value;
+		    break;
+		}
+
+	    if (digit == -1)
+		ick_lose(IE579, ick_lineno, cp);
+
+	    if (result < 429496729 || (result == 429496729 && digit < 6))
+		result = result * 10 + digit;
+	    else
+		ick_lose(IE533, ick_lineno, (const char *)NULL);
+	}
+    }
+    if (!n)
+	ick_lose(IE562, ick_lineno, (const char *)NULL);
+    if (result > (unsigned int)ick_Max_large)
+	ick_lose(IE533, ick_lineno, (const char *)NULL);
+    return(result);
+}
+
+/**********************************************************************
+ *
+ * Butchered Roman ick_numerals implemented by
+ * Michael Ernst, mernst@theory.lcs.mit.edu. May 7, 1990
+ *
+ * The INTERCAL manual hints that 3999 should translate to MMMIM
+ * (compare MMMCMXCIX) without specifying what the translation is.
+ * That may be a typo; in any case, this implementation isn't that
+ * butchered.
+ *
+ *********************************************************************/
+
+#define MAXDIGITS	10		/* max base 10 digits */
+#define MAXROMANS	(MAXDIGITS*4+1)	/* max chars in translation */
+
+/*
+ * The ick_first column tells how many of the succeeding columns are used.
+ * The other columns refer to the columns of br_equiv and br_overbar.
+ */
+static int ick_br_trans[10][5] =
+{
+    {0, 0, 0, 0, 0},
+    {1, 0, 0, 0, 0},
+    {2, 0, 0, 0, 0},
+    {3, 0, 0, 0, 0},
+    {2, 1, 2, 0, 0},        /* or use {4, 0, 0, 0, 0} */
+    {1, 2, 0, 0, 0},
+    {2, 2, 1, 0, 0},
+    {3, 2, 1, 1, 0},
+    {4, 2, 1, 1, 1},
+    {2, 1, 3, 0, 0}
+};
+
+/*
+ * butcher places in the string result the "butchered" Roman numeral for val.
+ * This string should be printed at the beginning of a line; it spans two
+ * lines and already contains newlines.
+ *
+ * 11/24/91 LHH:  Removed unnecessary final newline.
+ */
+
+static void butcher(unsigned long val, /*@out@*/ char *result)
+{
+    int i, j;
+    int digitsig, digitval;
+    char res[MAXROMANS], ovb[MAXROMANS];
+
+    /* We need FOUR columns because of the odd way that M and I interact. */
+    static const char br_equiv[MAXDIGITS][4] =
+    {
+	{'I', 'I', 'V', 'X'}, {'X', 'X', 'L', 'C'},
+	{'C', 'C', 'D', 'M'}, {'M', 'I', 'V', 'X'},
+	{'X', 'X', 'L', 'C'}, {'C', 'C', 'D', 'M'},
+	{'M', 'i', 'v', 'x'}, {'x', 'x', 'l', 'c'},
+	{'c', 'c', 'd', 'm'}, {'m', 'i', 'v', 'x'},
+    };
+
+    static const char br_overbar[MAXDIGITS][4] =
+    {
+	{' ', ' ', ' ', ' '},
+	{' ', ' ', ' ', ' '},
+	{' ', ' ', ' ', ' '},
+	{' ', '_', '_', '_'},
+	{'_', '_', '_', '_'},
+	{'_', '_', '_', '_'},
+	{'_', ' ', ' ', ' '},
+	{' ', ' ', ' ', ' '},
+	{' ', ' ', ' ', ' '},
+	{' ', '_', '_', '_'},
+    };
+
+    if (val == 0)
+/* Final newline will be added by puts.
+	(void) strcpy(result, "_\n \n");
+*/
+	(void) strcpy(result, "_\n");
+    else
+    {
+	res[MAXROMANS-1] = '\0';
+	ovb[MAXROMANS-1] = '\0';
+	i = MAXROMANS-1;
+
+	/* the significance of the current digit is 10 ** digitsig */
+	for (digitsig = 0; (digitsig < MAXDIGITS) && (val > 0); digitsig++)
+	{
+	  digitval = (int)(val % 10);
+	    for (j = ick_br_trans[digitval][0]; j > 0; j--)
+	    {
+		/* printf("In j loop: %d %d\n", j, i); */
+		res[--i] = br_equiv[digitsig][ick_br_trans[digitval][j]];
+		ovb[i] = br_overbar[digitsig][ick_br_trans[digitval][j]];
+	    }
+	    val = val / 10;
+	}
+
+	j = i;
+	while ((*result++ = ovb[j++]) != '\0')
+	    continue;
+	*--result = '\n';
+
+	j = i;
+	while ((*++result = res[j++]) != '\0')
+	    continue;
+/* Final newline will be added by puts.
+	*result++ = '\n';
+*/
+	*result = '\0';
+    }
+}
+
+void ick_clockface(ick_bool mode)
+/* enable or disable ick_clockface mode (output IIII instead of IV) */
+{
+    if (mode)
+    {
+	/* ick_clockface mode */
+	ick_br_trans[4][0] = 4;
+	ick_br_trans[4][1] = 0;
+	ick_br_trans[4][2] = 0;
+    }
+    else
+    {
+	/* normal mode */
+	ick_br_trans[4][0] = 2;
+	ick_br_trans[4][1] = 1;
+	ick_br_trans[4][2] = 2;
+    }
+}
+
+void ick_setclcsemantics(ick_bool mode) /* AIS: CLC-INTERCAL semantics mode? */
+{
+  ick_clcsem=mode;
+}
+
+void ick_pout(unsigned int val)
+/* output in `butchered' Roman ick_numerals; see manual, part 4.4.13 */
+{
+    char	result[2*MAXROMANS+1];
+
+    if(!ick_cesspoolout) ick_cesspoolout=stdout; /* AIS */
+
+    if(ick_wimp_mode) {
+	(void) fprintf(ick_cesspoolout,"%u\n",val);
+    }
+    else {
+	butcher(val, result);
+	(void) fprintf(ick_cesspoolout,"%s\n",result);
+    }
+    (void) fflush(ick_cesspoolout);
+}
+
+/**********************************************************************
+ *
+ * AIS: CLC-INTERCAL bitwise I/O, only used in CLC-INTERCAL semantics
+ * mode. The I/O is done in extended Baudot for a tail ick_array, or in
+ * mingled form for a hybrid ick_array; for the Baudot, we rely on
+ * clc-cset.c and on the Baudot and Latin-1 character sets that are
+ * linked to libick.a (or libickmt.a), so the final executable doesn't
+ * reference the compiler's libraries. clc-cset.c is designed to
+ * handle this all transparently, though, so we don't have to worry
+ * about the details. I wrote the next two functions.
+ *
+ **********************************************************************/
+
+/* AIS: From clc-cset.c */
+extern int ick_clc_cset_convert(const char* in, /*@partial@*/ char* out, const char* incset,
+				const char* outcset, int padstyle, size_t outsize,
+				/*@null@*/ FILE* errsto);
+
+static void clcbinin(unsigned int type, ick_array *a, ick_bool forget)
+{
+  size_t i;
+  int ti;
+  char* buf, *tempcp;
+  /* Allocating one byte per element in the ick_array must be enough,
+   * because the Baudot version cannot possibly be shorter than the
+   * original Latin-1, plus one for the terminating NUL. There is one
+   * potential problem, which is that fgets takes an int for the
+   * number of bytes to read, so we cap the number of bytes to read
+   * at INT_MAX and hope that's enough. */
+  i=a->dims[0]; /* we already know that there's 1 dim only */
+  if(SIZE_MAX/6-2<=a->dims[0])
+    ick_lose(IE252, ick_lineno, (const char*)NULL); /* size is too large */
+  if(!i) i=1;
+  buf=malloc(i+1);
+  if(!buf) ick_lose(IE252, ick_lineno, (const char*)NULL);
+  if(!ick_cesspoolin) ick_cesspoolin=stdin;
+  if(!fgets(buf,(int)(min(a->dims[0],(size_t)INT_MAX)),ick_cesspoolin))
+    strcpy(buf,"\n"); /* EOF inputs the null string in CLC-INTERCAL */
+  tempcp=strrchr(buf,'\n'); /* still working in ASCII at this point */
+  if(!tempcp) /* input too long for the ick_array is an error */
+  {
+    free(buf);
+    ick_lose(IE241, ick_lineno, (const char*)NULL);
+  }
+  *tempcp='\0'; /* chomp the final newline */
+  tempcp=malloc(6*i+12); /* to be on the safe side, even though
+			  * Baudot doesn't use 16-byte chars */
+  if(!tempcp) ick_lose(IE252, ick_lineno, (const char*)NULL);
+  /* Zero the ick_array now. */
+  i=a->dims[0];
+  if(!forget) while(i--)
+		if(type==ick_TAIL)
+		  a->data.tail[i]=0;
+		else
+		  a->data.hybrid[i]=0;
+  ti=ick_clc_cset_convert(buf,tempcp,"latin1","baudot",2,6*a->dims[0]+12,(FILE*)0);
+  /* Negative ti ought to be impossible here; check anyway, and cause
+   * an internal error if it has happened. */
+  if(ti<0) ick_lose(IE778, ick_lineno, (const char*)NULL);
+  i=(size_t)ti;
+  if(i>a->dims[0]) ick_lose(IE241, ick_lineno, (const char*)0);
+  if(!forget) while(i--)
+		if(type==ick_TAIL)
+		  a->data.tail[i]=(ick_type16)tempcp[i]+
+		    (ick_type16)((rand()%256)*256);
+		else
+		  a->data.hybrid[i]=(ick_type32)tempcp[i]+
+		    (ick_type32)((rand()%256)*256);
+  free(tempcp);
+  free(buf);
+}
+
+static void clcbinout(unsigned int type, const ick_array* a)
+{
+  size_t i;
+  int ti;
+  char* buf, *tempcp;
+  if(SIZE_MAX/6-2<=a->dims[0])
+    ick_lose(IE252, ick_lineno, (const char*)NULL); /* size is too large */
+  buf=malloc(a->dims[0]+1);
+  if(!buf) ick_lose(IE252, ick_lineno, (const char*) NULL);
+  i=0; tempcp=buf;
+  while(i<a->dims[0])
+  {
+    /* Values above 31 are invalid in Baudot, so cap them at 33 to
+       avoid integer wraparound trouble. */
+    if(type==ick_TAIL)
+      *tempcp=(char)min(33,a->data.tail[i]);
+    else
+      *tempcp=(char)min(33,a->data.hybrid[i]);
+    i++;
+    if(*tempcp!='\0')
+      tempcp++; /* NULs are ignored for some reason, but
+		 * that's the behaviour the CLC-INTERCAL
+		 * specs specify */
+  }
+  *tempcp='\0';
+  /* tempcp is definitely overkill here, but the *6+6 rule is being
+   * obeyed because that way the code is robust against any future
+   * changes in character sets. */
+  tempcp=malloc(a->dims[0]*6+12);
+  if(!tempcp) ick_lose(IE252, ick_lineno, (const char*) NULL);
+  ti=ick_clc_cset_convert(buf,tempcp,"baudot","latin1",0,6*a->dims[0]+12,(FILE*)0);
+  if(ti<0) ick_lose(IE778, ick_lineno, (const char*)NULL);
+  i=(size_t)ti;
+  tempcp[i]='\0';
+  /* CLC-INTERCAL bails out on invalid characters. C-INTERCAL uses
+   * instead the behaviour of replacing them with character code 26.
+   * (This is actually the purpose of character code 26 in ASCII, I
+   * think, although this is derived from memory; I don't know of any
+   * other system that uses it for this purpose, though, and the
+   * ability to confuse Windows with it is worth what might be lost
+   * through standards compliance, because Windows nonstandardly
+   * treats it as an EOF character.) */
+  while(i--) if(tempcp[i] == '\0') tempcp[i]='\x1a';
+  if(!ick_cesspoolout) ick_cesspoolout=stdout;
+  fprintf(ick_cesspoolout,"%s\n",tempcp);
+  (void) fflush(ick_cesspoolout);
+  free(tempcp);
+  free(buf);
+}
+
+/**********************************************************************
+ *
+ * The following two routines implement bitwise I/O.  They assume
+ * 8 bit characters, but there's no reason more general versions
+ * could not be written.
+ *
+ *********************************************************************/
+
+void ick_binin(unsigned int type, ick_array *a, ick_bool forget)
+{
+  static int lastin = 0;
+  int c, v;
+  size_t i;
+
+  if (a->rank != 1)
+    ick_lose(IE241, ick_lineno, (const char *)NULL);
+
+  if(!ick_cesspoolin) ick_cesspoolin=stdin; /* AIS */
+
+  if(ick_clcsem) {clcbinin(type, a, forget); return;} /* AIS */
+
+  for (i = 0 ; i < a->dims[0] ; i++) {
+    v = ((c=fgetc(ick_cesspoolin)) == EOF) ? 256 :
+      ((unsigned)c - lastin) % 256;
+    lastin = c;
+    if (!forget) {
+      if (type == ick_TAIL)
+	a->data.tail[i] = (ick_type16) v;
+      else
+	a->data.hybrid[i] = (ick_type32) v;
+    }
+  }
+}
+
+void ick_binout(unsigned int type, const ick_array *a)
+{
+  static unsigned int lastout = 0;
+  unsigned int c;
+  size_t i;
+
+  if (a->rank != 1)
+    ick_lose(IE241, ick_lineno, (const char *)NULL);
+
+  if(!ick_cesspoolout) ick_cesspoolout=stdout; /* AIS */
+
+  if(ick_clcsem) {clcbinout(type, a); return;} /* AIS */
+
+  for (i = 0 ; i < a->dims[0] ; i++) {
+    if (type == ick_TAIL)
+      c = lastout - a->data.tail[i];
+    else
+      c = lastout - a->data.hybrid[i];
+    lastout = c;
+    c = (c & 0x0f) << 4 | (c & 0xf0) >> 4;
+    c = (c & 0x33) << 2 | (c & 0xcc) >> 2;
+    c = (c & 0x55) << 1 | (c & 0xaa) >> 1;
+    (void) fputc((int)c,ick_cesspoolout);
+    if (c == 10 /* \n in INTERCAL */ || /* AIS */ ick_instapipe)
+      (void) fflush(ick_cesspoolout);
+  }
+}
+
+/**********************************************************************
+ *
+ * The following assignment function performs IGNORE and type checks
+ *
+ *********************************************************************/
+
+unsigned int ick_assign(char *dest, unsigned int type, ick_bool forget,
+		    unsigned int value)
+{
+  unsigned int retval = 0;
+  if (type == ick_ONESPOT || type == ick_TAIL) {
+    if (value > (unsigned int)ick_Max_small)
+      ick_lose(IE275, ick_lineno, (const char *)NULL);
+    if (forget)
+      retval = value;
+    else {
+      retval = *(ick_type16*)dest;
+      *(ick_type16*)dest = (ick_type16) value;
+    }
+  }
+  else if (type == ick_TWOSPOT || type == ick_HYBRID) {
+    if (forget)
+      retval = value;
+    else {
+      retval = *(ick_type32*)dest;
+      *(ick_type32*)dest = value;
+    }
+  }
+  return retval;
+}
+
+/**********************************************************************
+ *
+ * The following functions implement the INTERCAL ick_array model
+ * If HAVE_STDARG_H is defined, stdarg is used, otherwise varargs.
+ *
+ *********************************************************************/
+
+
+#ifdef HAVE_STDARG_H
+/*@dependent@*/ void *ick_aref(unsigned int type, ...)
+#else
+/*@dependent@*/ void *ick_aref(va_alist) va_dcl
+#endif
+/* return a pointer to the ick_array location specified by args */
+{
+#ifndef HAVE_STDARG_H
+  unsigned int type;
+#endif
+  ick_array *a;
+  unsigned int v;
+  va_list ap;
+  size_t address = 0;
+  unsigned int i;
+
+#ifdef HAVE_STDARG_H
+  va_start(ap, type);
+#else
+  va_start(ap);
+  type = va_arg(ap, unsigned int);
+#endif
+  a = va_arg(ap, ick_array*);
+
+  if (va_arg(ap, unsigned int) != a->rank)
+    ick_lose(IE241, ick_lineno, (const char *)NULL);
+
+  for (i = 0 ; i < a->rank ; i++) {
+    v = va_arg(ap, unsigned int);
+    if (v == 0 || (size_t)v > a->dims[i])
+      ick_lose(IE241, ick_lineno, (const char *)NULL);
+    address = address * a->dims[i] + v - 1;
+  }
+
+  va_end(ap);
+
+  if (type == ick_TAIL)
+    return (void*)&(a->data.tail[address]);
+  else
+    return (void*)&(a->data.hybrid[address]);
+}
+
+#ifdef HAVE_STDARG_H
+void ick_resize(unsigned int type, ...)
+#else
+void ick_resize(va_alist) va_dcl
+#endif
+/* ick_resize an ick_array to the given shape */
+{
+#ifndef HAVE_STDARG_H
+  unsigned int type;
+#endif
+  ick_array *a;
+  ick_bool forget;
+  unsigned int i, r;
+  size_t v;
+  va_list ap;
+  int prod = 1;
+
+#ifdef HAVE_STDARG_H
+ va_start(ap, type);
+#else
+  va_start(ap);
+  type = va_arg(ap, unsigned int);
+#endif
+  a = va_arg(ap, ick_array*);
+  forget = va_arg(ap, ick_bool);
+
+  /* AIS: a->dims is no longer initialised. So initialise it here if
+     it isn't already initialised, with an annotation to explain that
+     we aren't freeing the old pointer (because it was never malloced in
+     the first place and is probably invalid anyway.) */
+  /*@-mustfreeonly@*/
+  if (!a->rank) a->dims = 0;
+  /*@-mustfreeonly@*/
+
+  r = va_arg(ap, unsigned int);
+  if (!forget) {
+    a->rank = r;
+    if (a->dims)
+      free((char*)a->dims);
+    a->dims = malloc(a->rank * sizeof(*(a->dims)));
+    if (a->dims == NULL)
+      ick_lose(IE241, ick_lineno, (const char *)NULL);
+  }
+
+  for (i = 0 ; i < r ; i++) {
+    v = va_arg(ap, size_t);
+    if (v == 0)
+      ick_lose(IE240, ick_lineno, (const char *)NULL);
+    if (!forget) {
+      assert(a->dims != NULL); /* AIS: it isn't, because !forget, but
+				  splint doesn't know that */
+      a->dims[i] = v;
+      prod *= v;
+    }
+  }
+
+  if (!forget) {
+    if (type == ick_TAIL) {
+      if (a->data.tail)
+	free((char *)a->data.tail);
+      a->data.tail   = (ick_type16*)malloc(prod * sizeof(ick_type16));
+      if (a->data.tail == NULL)
+	ick_lose(IE241, ick_lineno, (const char *)NULL);
+    }
+    else {
+      if (a->data.hybrid)
+	free((char *)a->data.hybrid);
+      a->data.hybrid = (ick_type32*)malloc(prod * sizeof(ick_type32));
+      if (a->data.hybrid == NULL)
+	ick_lose(IE241, ick_lineno, (const char *)NULL);
+    }
+  }
+
+  va_end(ap);
+}
+
+/**********************************************************************
+ *
+ * The following functions implement save/retrieve
+ *
+ *********************************************************************/
+
+/*@null@*/ ick_stashbox *ick_first; /* AIS: made non-static so it can be seen by unravel.c */
+
+void ick_stashinit(void)
+{
+  ick_first = NULL;
+}
+
+static /*@null@*/ ick_stashbox *fetch(unsigned int type, unsigned int index)
+/* find a stashed variable in the save stack and extract it */
+{
+  ick_stashbox **pp = &ick_first, *sp = ick_first;
+
+  while (sp != NULL && (sp->type != type || sp->index != index)) {
+    pp = &sp->ick_next;
+    sp = sp->ick_next;
+  }
+  if (sp)
+    *pp = sp->ick_next;
+
+  /* The annotation here is because Splint can't figure out that
+     ick_first can be modified via pp, and because this function
+     is the place where storage marked 'dependent' is initialised
+     and deinitialised. */
+  /*@-globstate@*/ /*@-dependenttrans@*/
+  return (sp);
+  /*@=globstate@*/ /*@=dependenttrans@*/
+}
+
+void ick_stash(unsigned int type, unsigned int index, void *from, ick_overop* oo)
+/* stash away the variable's value */
+{
+  /*@-nullassign@*/
+  ick_overop dummyoo;
+  /*@=nullassign@*/
+  /* create a new ick_stashbox and push it onto the stack */
+  ick_stashbox *sp;
+  dummyoo.get = (ick_type32 (*)(ick_type32))NULL;
+  dummyoo.set = (void (*)(ick_type32, void(*)()))NULL;
+  sp = (ick_stashbox*)malloc(sizeof(ick_stashbox));
+  if (sp == NULL) ick_lose(IE222, ick_lineno, (const char *)NULL);
+  sp->ick_next = ick_first;
+  ick_first = sp;
+
+  /* store the variable in it */
+  ick_first->type = type;
+  ick_first->index = index;
+  if(oo) ick_first->overloadinfo=oo[index]; /* AIS */
+  else ick_first->overloadinfo=dummyoo; /* AIS */
+  if (type == ick_ONESPOT)
+  {
+    memcpy(&ick_first->save.onespot, from, sizeof(ick_type16));
+  }
+  else if (type == ick_TWOSPOT)
+    memcpy(&ick_first->save.twospot, from, sizeof(ick_type32));
+  else if (type == ick_TAIL || type == ick_HYBRID) {
+    ick_array *a = (ick_array*)from;
+    int prod;
+    unsigned int i;
+    ick_first->save.a = (ick_array*)malloc(sizeof(ick_array));
+    if (ick_first->save.a == NULL) ick_lose(IE222, ick_lineno, (const char *)NULL);
+    ick_first->save.a->rank = a->rank;
+    ick_first->save.a->dims = malloc(a->rank * sizeof(*(ick_first->save.a->dims)));
+    if (ick_first->save.a->dims == NULL) ick_lose(IE222, ick_lineno, (const char *)NULL);
+    memcpy(ick_first->save.a->dims, a->dims,
+	   a->rank * sizeof(*(a->dims)));
+    prod = a->rank ? 1 : 0;
+    for (i = 0 ; i < a->rank ; i++) {
+      prod *= a->dims[i];
+    }
+    if (type == ick_TAIL) {
+      ick_first->save.a->data.tail =
+	(ick_type16*)malloc(prod * sizeof(ick_type16));
+      if (ick_first->save.a->data.tail == NULL) ick_lose(IE222, ick_lineno, (const char *)NULL);
+      memcpy(ick_first->save.a->data.tail,
+	     a->data.tail, prod * sizeof(ick_type16));
+    }
+    else {
+      ick_first->save.a->data.hybrid =
+	(ick_type32*)malloc(prod * sizeof(ick_type32));
+      if (ick_first->save.a->data.hybrid == NULL) ick_lose(IE222, ick_lineno, (const char *)NULL);
+      memcpy(ick_first->save.a->data.hybrid,
+	     a->data.hybrid, prod * sizeof(ick_type32));
+    }
+  }
+  return;
+}
+
+void ick_retrieve(void *to, unsigned int type, unsigned int index,
+		  ick_bool forget, ick_overop* oo)
+/* restore the value of a variable from the save stack */
+{
+  ick_stashbox *sp;
+
+  if ((sp = fetch(type, index)) == (ick_stashbox *)NULL)
+    ick_lose(IE436, ick_lineno, (const char *)NULL);
+  else if (!forget) {
+    if(oo) oo[index]=sp->overloadinfo; /* AIS */
+    if (type == ick_ONESPOT)
+      memcpy(to, (const char *)&sp->save.onespot, sizeof(ick_type16));
+    else if (type == ick_TWOSPOT)
+      memcpy(to, (const char *)&sp->save.twospot, sizeof(ick_type32));
+    else if (type == ick_TAIL || type == ick_HYBRID) {
+      ick_array *a = (ick_array*)to;
+      /*@-branchstate@*/ /* it's a union, so one valid is correct */
+
+      if (a->rank) {
+	free(a->dims);
+	if (type == ick_TAIL)
+	  free(a->data.tail);
+	else
+	  free(a->data.hybrid);
+	memcpy(to, (const char*)sp->save.a, sizeof(ick_array));
+      }
+      /*@=branchstate@*/
+      /* AIS: there isn't a memory leak here, because we memcpyd the
+	 pointers elsewhere and so they are yet accessible. You can't
+	 expect Splint to figure out what's going on there, though, thus
+	 the annotations. */
+      /*@-compdestroy@*/
+      free(sp->save.a);
+      /*@=compdestroy@*/
+    }
+  }
+  else if (type == ick_TAIL || type == ick_HYBRID) {
+    free(sp->save.a->dims);
+    if (type == ick_TAIL)
+      free(sp->save.a->data.tail);
+    else
+      free(sp->save.a->data.hybrid);
+    free(sp->save.a);
+  }
+  free(sp);
+}
+
+/**********************************************************************
+ *
+ * The following function is used for random decision making
+ *
+ *********************************************************************/
+
+unsigned int ick_roll(unsigned int n)
+/* return ick_TRUE on n% chance, ick_FALSE otherwise */
+{
+#ifdef USG
+   return((unsigned int)(lrand48() % 100) < n);
+#else
+   return((unsigned int)(rand() % 100) < n);
+#endif /* UNIX */
+}
+
+/**********************************************************************
+ *
+ * AIS: This function is called when two COME FROMs reference the same
+ *      line at runtime. ick_multicome0 is used in a non-multithread
+ *      program; it produces an error. For multicome1, see unravel.c.
+ *
+ *********************************************************************/
+
+int ick_multicome0(int errlineno, jmp_buf pc)
+{
+  /*@-noeffect@*/
+  (void) pc; /* it's ignored by this function */
+  /*@=noeffect@*/
+  ick_lose(IE555, errlineno, (const char *) NULL);
+  /* this line number is quite possibly going to be wildly inaccurate */
+  /*@-unreachable@*/
+  return 0;
+  /*@=unreachable@*/
+}
+
+/**********************************************************************
+ *
+ * AIS: The next two functions are mine, and handle CREATE statements.
+ *
+ **********************************************************************/
+
+struct ick_jictype
+{
+  /*@observer@*/ const char* sig; /* a shallow copy of a constant string */
+  unsigned long target;
+  /*@null@*/ /*@only@*/ struct ick_jictype* next;
+};
+
+/*@null@*/ /*@only@*/ static struct ick_jictype* jiclist = NULL;
+
+/* Return a jic entry that matches the requested signature exactly,
+   creating one if there isn't one yet. */
+static struct ick_jictype* jicextract(/*@observer@*/ const char* sig)
+{
+  struct ick_jictype* jicptr = jiclist;
+  while(jicptr)
+  {
+    if(strcmp(jicptr->sig,sig)==0) return jicptr;
+    if(jicptr->next != NULL) jicptr = jicptr->next;
+    else break;
+  }
+  if(!jicptr)
+  {
+    jiclist=malloc(sizeof *jiclist);
+    jicptr=jiclist;
+  }
+  else
+  {
+    jicptr->next=malloc(sizeof *jiclist);
+    jicptr=jicptr->next;
+  }
+  jicptr->next = NULL;
+  jicptr->sig = sig;
+  jicptr->target = 0;
+  return jicptr;
+}
+
+void ick_registercreation(const char* sig, unsigned long target)
+{
+  jicextract(sig)->target=target;
+}
+
+unsigned long ick_jicmatch(const char* sig)
+{
+  return jicextract(sig)->target;
+}
+
+/* AIS: Used by the JIC code to error out when attempting to access an array */
+ick_type32 ick_ieg277(ick_type32 ignored)
+{
+  /*@-noeffect@*/
+  (void) ignored;
+  /*@=noeffect@*/
+  ick_lose(IE277, ick_lineno, (const char*) NULL);
+}
+
+void ick_ies277(ick_type32 ignored, void(*ignored2)())
+{
+  /*@-noeffect@*/
+  (void) ignored;
+  (void) ignored2;
+  /*@=noeffect@*/
+  ick_lose(IE277, ick_lineno, (const char*) NULL);
+}
+
+/* cesspool.c ends here */