#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
//#include "auto_gdb.c"

void *dynamalloc(int dim, int objsize, void *data, int nels, int lb1, ...)
{
      char *fred, *rslt, *datap;
      int fred_inels = 0;
      int fred_dim_1;
      int lb, ub, ub1;
      int size, thisdim;
      va_list ap;
      /* if objsize needs to be short/word/double aligned,
         do so here (or at point of call)? */
      va_start(ap, lb1);
      ub1 = va_arg(ap, int);
      lb = lb1; ub = ub1;
      for (thisdim = 0; thisdim < dim; thisdim++) {
fprintf(stdout, "Handling dimension %d (%d:%d)\n", thisdim, lb, ub); fflush(stdout);
      fred = (char *)malloc (size=((ub1) - (lb1) + 1) * objsize);
fprintf(stdout, "fred=%p = (char *)malloc (((ub1) - (lb1) + 1) * objsize=%d);\n",
        fred, size); fflush(stdout);
      rslt = fred - (lb1*objsize);
//fprintf(stdout, "fred_inels = %d, nels = %d\n", fred_inels, nels); fflush(stdout);
      datap = (char *)data;
      for (fred_dim_1 = lb1; fred_dim_1 <= ub1; fred_dim_1++) {
         if (fred_inels == nels) break;
         fred_inels += 1;

//         fprintf(stdout, "memmove(fred=%p, datap=%p, objsize=%d);\n",
//                 fred, datap, objsize); fflush(stdout);
	 memmove(fred, datap, objsize);
         
          fred += objsize;
         datap += objsize;
      }
      lb = va_arg(ap, int);
      ub = va_arg(ap, int);
      }
      va_end(ap);
      return((void *)rslt);
}

/* REWRITE THIS: http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variadic-Macros.html#Variadic%20Macros */
/* This may help too: http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Statement-Exprs.html#Statement%20Exprs */
#define ARRAY1(t, name, lb1, ub1, nels) \
        (t *)dynamalloc(1, sizeof(t),name##_data,nels,lb1,ub1)

#define ARRAY2(t, name, lb1, ub1, lb2, ub2, nels) \
        (t **)dynamalloc(2, sizeof(t),name##_data,nels,lb1,ub1,lb2,ub2)

#define ARRAY3(t, name, lb1, ub1, lb2, ub2, lb3, ub3, nels) \
        (t ***)dynamalloc(3, sizeof(t),name##_data,nels,lb1,ub1,lb2,ub2,lb3,ub3)

#define ARRAY4(t, name, lb1, ub1, lb2, ub2, lb3, ub3, lb4, ub4, nels) \
        (t ****)dynamalloc(4, sizeof(t),name##_data,nels,lb1,ub1,lb2,ub2,lb3,ub3,lb4,ub4)

#define UARRAY1(t, lb1, ub1) \
        (t *)dynamalloc(1, sizeof(t),NULL,0,lb1,ub1)

#define UARRAY2(t, lb1, ub1, lb2, ub2) \
        (t **)dynamalloc(2, sizeof(t),NULL,0,lb1,ub1,lb2,ub2)

#define UARRAY3(t, lb1, ub1, lb2, ub2, lb3, ub3) \
        (t ***)dynamalloc(3, sizeof(t),NULL,0,lb1,ub1,lb2,ub2,lb3,ub3)

#define UARRAY4(t, lb1, ub1, lb2, ub2, lb3, ub3, lb4, ub4) \
        (t ****)dynamalloc(4, sizeof(t),NULL,0,lb1,ub1,lb2,ub2,lb3,ub3,lb4,ub4)

#ifdef DBMAIN_ARRAY

static int i = 1000;
static int j = 1005;
static unsigned char fred_data[] = {1, 2, 2, 2, 3, 4};
static unsigned char *fred;
/* This must be output to an init routine, called at the start of main():
   You cannot call it in main itself in case fred is shadowed by a local
 */

static void externs_init(void)
{
  fred = ARRAY1(unsigned char, fred, i, j, 6);
}

int main(int argc, char **argv)
{
//restart_under_gdb(argc, argv);
externs_init();
{
int k = 0;
int l = 1;

unsigned char fred_data[] = {1, 2, 2, 2, 3, 4};
unsigned char *fred = ARRAY1(unsigned char, fred, i, j, 6);

int jim_data[] = {1, 2, 2, 2, 3, 4};
int *jim = ARRAY1(int, jim, i, j, 6);

unsigned char sheila_data[] = {1, 2, 2, 2, 3, 4};
unsigned char **sheila = ARRAY2(unsigned char, sheila, i, j, k, l, 6);

unsigned char *uninit = UARRAY1(unsigned char, i, j);

}
exit(0);
}
#endif
