/*	Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include "funcdef.h"

#include "sysdef.h"
#ifndef _DEBUG_MALLOC_INC
#define local_free free
#else 
static void
local_free (p)
     void * p;
{
  free (p);
}
#endif /* def _DEBUG_MALLOC_INC */
#define obstack_chunk_alloc ck_malloc
#define obstack_chunk_free local_free
#include "obstack.h"
#include "global.h"
#include "cell.h"
#include "ref.h"
#include "window.h"
#include "io-term.h"
#include "io-abstract.h"

#define ROW_BUF 3
#define COL_BUF 2
#define MAX MAX_ROW
#define MIN MIN_ROW
static struct obstack find_stack;

#if 1
#define malloc_chain_check(x)
#endif

#ifdef __GNUC__
#define inline __inline__
#else
#define inline
#endif

#ifdef TEST_ME
typedef unsigned char CELLREF;
typedef unsigned int size_t;
#define ck_malloc malloc
extern void *malloc ();
#define MIN 1
#define MAX 65535
#endif

struct list
{
  CELLREF lo, hi;
  struct list *next;
  char mem[1];
};

struct find
{
  struct find *next;
  CELLREF lo, hi, cur;
  struct list **start;
  struct list *curptr;
  CELLREF left;
  void *ret;
  char fini;
  int ele;
};

struct find *finds = 0;

#ifdef __STDC__
static inline void
flush (struct list *ptr)
#else
static inline void
flush (ptr)
     struct list *ptr;
#endif
{
  struct list *nxt;

  while (ptr)
    {
      nxt = ptr->next;
      free (ptr);
      ptr = nxt;
    }
}

#ifdef __STDC__
static inline void
resync (struct list *tofree, struct list *new, int ele)
#else
static inline void
resync (tofree, new, ele)
     struct list *tofree;
     struct list *new;
     int ele;
#endif
{
  struct find *findp;

  if (ele == sizeof (struct cell)
      && my_cell
      && (char *) my_cell >= tofree->mem
      && (char *) my_cell <= tofree->mem + ele * (1 + tofree->hi - tofree->lo))
    my_cell = (struct cell *) (new->mem + ele * (cur_row - new->lo));

  for (findp = finds; findp; findp = findp->next)
    {
      if (tofree == findp->curptr)
	{
	  CELLREF hi;
	  findp->curptr = new;
	  findp->ret = new->mem + (findp->cur - new->lo) * ele;
	  hi = (findp->hi < new->hi ? findp->hi : new->hi);
	  if (findp->cur < hi)
	    findp->left = hi - findp->cur;
	}
    }

  free (tofree);
}

#ifdef __STDC__
static inline void *
find (CELLREF pos, struct list *ptr, int ele)
#else
static inline void *
find (pos, ptr, ele)
     CELLREF pos;
     struct list *ptr;
     int ele;
#endif
{
  for (; ptr; ptr = ptr->next)
    {
      if (ptr->lo > pos)
	break;
      if (ptr->hi >= pos)
	return ptr->mem + (pos - ptr->lo) * ele;
    }
  return 0;
}

#ifdef __STDC__
static inline void *
make (CELLREF pos, struct list **prevp, int ele, int buf)
#else
static inline void *
make (pos, prevp, ele, buf)
     CELLREF pos;
     struct list **prevp;
     int ele;
     int buf;
#endif
{
  CELLREF lo, hi;
  size_t size;
  struct list *ptr;

  while (*prevp && (*prevp)->next && (*prevp)->next->lo < pos)
    prevp = &((*prevp)->next);

  /* Was it easy? */
  if (*prevp && (*prevp)->lo <= pos && (*prevp)->hi >= pos)
    return (*prevp)->mem + (pos - (*prevp)->lo) * ele;

  lo = (pos < MIN + buf) ? MIN : pos - buf;
  hi = (pos > MAX - buf) ? MAX : pos + buf;

  if (!*prevp
      || ((*prevp)->hi < lo - 1
	  && (!(*prevp)->next
	      || (*prevp)->next->lo - 1 > hi)))
    {
      /* Allocate a whole new structure */
      size = (1 + hi - lo) * ele;
      ptr = ck_malloc (sizeof (struct list) + size);
      ptr->lo = lo;
      ptr->hi = hi;
      if (*prevp && (*prevp)->hi < lo)
	{
	  ptr->next = (*prevp)->next;
	  (*prevp)->next = ptr;
	}
      else
	{
	  ptr->next = *prevp;
	  *prevp = ptr;
	}
      bzero (ptr->mem, size);
      malloc_chain_check (1);
    }
  else if ((*prevp)->lo > lo)
    {
      /* Stretch one down a bit to fit */
      hi = (*prevp)->hi;
      size = (1 + hi - lo) * ele;
      ptr = ck_malloc (sizeof (struct list) + size);
      ptr->lo = lo;
      ptr->hi = hi;
      ptr->next = (*prevp)->next;
      bcopy ((*prevp)->mem, ptr->mem + ((*prevp)->lo - ptr->lo) * ele, (1 + (*prevp)->hi - (*prevp)->lo) * ele);
      bzero (ptr->mem, ((*prevp)->lo - ptr->lo) * ele);
      resync (*prevp, ptr, ele);
      *prevp = ptr;
      malloc_chain_check (1);
    }
  else if ((*prevp)->hi < hi && (*prevp)->next && (*prevp)->next->lo <= hi)
    {
      /* Merge this one and the one after it */
      size = (1 + (*prevp)->next->hi - (*prevp)->lo) * ele;
      ptr = ck_malloc (sizeof (struct list) + size);
      ptr->lo = (*prevp)->lo;
      ptr->hi = (*prevp)->next->hi;
      ptr->next = (*prevp)->next->next;
      bcopy ((*prevp)->mem, ptr->mem, (1 + (*prevp)->hi - (*prevp)->lo) * ele);
      bzero (ptr->mem + (1 + (*prevp)->hi - ptr->lo) * ele, ((*prevp)->next->lo - (*prevp)->hi) * ele);
      bcopy ((*prevp)->next->mem,
	     ptr->mem + ((*prevp)->next->lo - ptr->lo) * ele,
	     (1 + (*prevp)->next->hi - (*prevp)->next->lo) * ele);
      resync ((*prevp)->next, ptr, ele);
      resync (*prevp, ptr, ele);
      *prevp = ptr;
      malloc_chain_check (1);
    }
  else if ((*prevp)->hi < hi)
    {
      /* stretch this one up a bit */
      size = (1 + hi - (*prevp)->lo) * ele;
      ptr = ck_malloc (sizeof (struct list) + size);
      ptr->lo = (*prevp)->lo;
      ptr->hi = hi;
      ptr->next = (*prevp)->next;
      bcopy ((*prevp)->mem, ptr->mem, (1 + (*prevp)->hi - (*prevp)->lo) * ele);
      bzero (ptr->mem + (1 + (*prevp)->hi - ptr->lo) * ele, (hi - (*prevp)->hi) * ele);
      resync (*prevp, ptr, ele);
      *prevp = ptr;
      malloc_chain_check (1);
    }
  else
    ptr = *prevp;
#ifdef TEST
  if (ptr->lo > pos || ptr->hi < pos)
    panic ("Make at %u not in %u %u", pos, ptr->lo, ptr->hi);
#endif

  return ptr->mem + (pos - ptr->lo) * ele;
}

#ifdef __STDC__
static inline void *
find_rng (struct list **start, CELLREF lo, CELLREF hi, int ele)
#else
static inline void *
find_rng (start, lo, hi, ele)
     struct list **start;
     CELLREF lo;
     CELLREF hi;
     int ele;
#endif
{
  struct list *ptr;
  struct find *f;

  f = (struct find *)obstack_alloc (&find_stack, sizeof (struct find));
  f->lo = lo;
  f->hi = hi;
  f->ele = ele;
  f->start = start;
  for (ptr = *start; ptr; ptr = ptr->next)
    if (ptr->hi >= lo)
      break;
  if (ptr && ptr->lo <= hi)
    {
      f->cur = (ptr->lo > lo ? ptr->lo : lo);
      f->curptr = ptr;
      f->ret = ptr->mem + (f->cur - ptr->lo) * ele;
      f->left = 1 + (f->hi < ptr->hi ? f->hi : ptr->hi) - f->cur;
      f->fini = 0;
    }
  else
    f->fini = 1;
  f->next = finds;
  finds = f;
  return f;
}

#ifdef __STDC__
static inline void *
make_rng (struct list **start, CELLREF lo, CELLREF hi, int ele, int buf)
#else
static inline void *
make_rng (start, lo, hi, ele, buf)
     struct list **start;
     CELLREF lo;
     CELLREF hi;
     int ele;
     int buf;
#endif
{
  struct list **prevp;
  struct list *ptr;
  size_t size;
  struct find *f;

  f = (struct find *)obstack_alloc (&find_stack, sizeof (struct find));
  f->lo = f->cur = lo;
  f->hi = hi;
  f->left = 1 + hi - lo;
  f->fini = 0;
  f->ele = ele;
  f->start = start;

  lo = lo <= MIN + buf ? MIN : lo - buf;
  hi = hi >= MAX - buf ? MAX : hi + buf;

  for (prevp = start; *prevp && (*prevp)->hi < lo - 1; prevp = &((*prevp)->next))
    ;
  ptr = *prevp;
  if (!*prevp || (*prevp)->lo - 1 > hi)
    {
      /* Allocate the whole thing */
      size = (1 + hi - lo) * ele;
      ptr = ck_malloc (sizeof (struct list) + size);
      ptr->lo = lo;
      ptr->hi = hi;
      ptr->next = *prevp;
      bzero (ptr->mem, size);
      if (*prevp && (*prevp)->hi < lo)
	{
	  ptr->next = (*prevp)->next;
	  (*prevp)->next = ptr;
	}
      else
	{
	  ptr->next = *prevp;
	  *prevp = ptr;
	}
      *prevp = ptr;
      malloc_chain_check (1);
    }
  else
    {
      if ((*prevp)->lo > lo)
	{
	  /* Stretch this one down a bit */
	  size = (1 + (*prevp)->hi - lo) * ele;
	  ptr = ck_malloc (sizeof (struct list) + size);
	  ptr->lo = lo;
	  ptr->hi = (*prevp)->hi;
	  ptr->next = (*prevp)->next;
	  bcopy ((*prevp)->mem,
		 ptr->mem + ((*prevp)->lo - ptr->lo) * ele,
		 (1 + (*prevp)->hi - (*prevp)->lo) * ele);
	  bzero (ptr->mem, ((*prevp)->lo - lo) * ele);
	  resync (*prevp, ptr, ele);
	  *prevp = ptr;
	  malloc_chain_check (1);
	}
      while ((*prevp)->hi < hi && (*prevp)->next && (*prevp)->next->lo <= hi)
	{
	  /* Merge this one and the one after it */
	  /* Repeat as needed */
	  size = (1 + (*prevp)->next->hi - (*prevp)->lo) * ele;
	  ptr = ck_malloc (sizeof (struct list) + size);
	  ptr->lo = (*prevp)->lo;
	  ptr->hi = (*prevp)->next->hi;
	  ptr->next = (*prevp)->next->next;
	  bcopy ((*prevp)->mem, ptr->mem, (1 + (*prevp)->hi - (*prevp)->lo) * ele);
	  bzero (ptr->mem + (1 + (*prevp)->hi - ptr->lo) * ele, ((*prevp)->next->lo - (*prevp)->hi) * ele);
	  bcopy ((*prevp)->next->mem,
		 ptr->mem + ((*prevp)->next->lo - ptr->lo) * ele,
		 (1 + (*prevp)->next->hi - (*prevp)->next->lo) * ele);
	  resync ((*prevp)->next, ptr, ele);
	  resync (*prevp, ptr, ele);
	  *prevp = ptr;
	  malloc_chain_check (1);
	}
      if ((*prevp)->hi < hi)
	{
	  /* stretch this one up a bit */
	  size = (1 + hi - (*prevp)->lo) * ele;
	  ptr = ck_malloc (sizeof (struct list) + size);
	  ptr->lo = (*prevp)->lo;
	  ptr->hi = hi;
	  ptr->next = (*prevp)->next;
	  bcopy ((*prevp)->mem, ptr->mem, (1 + (*prevp)->hi - (*prevp)->lo) * ele);
	  bzero (ptr->mem + (1 + (*prevp)->hi - ptr->lo) * ele, (hi - (*prevp)->hi) * ele);
	  resync (*prevp, ptr, ele);
	  *prevp = ptr;
	  malloc_chain_check (1);
	}
    }
#ifdef TEST
  if (ptr->lo > f->lo || ptr->hi < f->hi)
    panic ("Vector of %u-%u not big enough for %u-%u", (*prevp)->lo, (*prevp)->hi, f->lo, f->hi);
#endif
  f->curptr = ptr;
  f->ret = ptr->mem + (f->cur - ptr->lo) * ele;
  f->next = finds;
  finds = f;
  return f;
}

#ifdef __STDC__
static inline void *
next_rng (struct find *f, CELLREF *posp)
#else
static inline void *
next_rng (f, posp)
     struct find *f;
     CELLREF *posp;
#endif
{
  void *ret;
  struct find *next;

  if (!f)
    return 0;
  if (!f->fini)
    {
      if (f->left)
	{
	  --(f->left);
	fini:
	  if (posp)
	    *posp = f->cur;
	  f->cur++;
	  ret = f->ret;
	  f->ret = (char *) (f->ret) + f->ele;
	  return ret;
	}
      if (f->curptr->hi < f->hi)
	{
	  f->curptr = f->curptr->next;
	  if (f->curptr && f->curptr->lo <= f->hi)
	    {
	      f->ret = f->curptr->mem;
	      f->left = (f->hi < f->curptr->hi ? f->hi : f->curptr->hi) - f->curptr->lo;
	      f->cur = f->curptr->lo;
	      goto fini;
	    }
	}
    }
  next = f->next;
  obstack_free (&find_stack, f);
  finds = next;
  return 0;
}


struct cf
  {
    struct cf *next;
    struct find *rows, *cols;
    int make;
  };

static struct cf *fp;
static struct list *the_cols;

static struct find *w_find;
static struct find *h_find;
static struct list *wids, *hgts;


void 
init_cells ()
{
  obstack_begin (&find_stack, sizeof (struct find) * 15);
  the_cols = 0;
  wids = 0;
  hgts = 0;
}

#ifdef __STDC__
void 
flush_everything (void)
#else
void 
flush_everything ()
#endif
{
  struct list *ptr, *nxt;
  int n;

  flush_variables ();
  for (ptr = the_cols; ptr; ptr = nxt)
    {
      nxt = ptr->next;
      for (n = 0; n <= ptr->hi - ptr->lo; n++)
	flush (*(struct list **) (ptr->mem + (n * sizeof (struct list *))));
      free (ptr);
    }
  the_cols = 0;
  flush (wids);
  wids = 0;
  flush (hgts);
  hgts = 0;
  flush_fonts ();
}

#if __STDC__
struct cell *
find_cell (CELLREF row, CELLREF col)
#else
struct cell *
find_cell (row, col)
     CELLREF row;
     CELLREF col;
#endif
{
  void **v;

  v = find (col, the_cols, sizeof (void *));
  return v ? find (row, *v, sizeof (struct cell)) : 0;
}

#if __STDC__
struct cell *
find_or_make_cell (CELLREF row, CELLREF col)
#else
struct cell *
find_or_make_cell (row, col)
     CELLREF row;
     CELLREF col;
#endif
{
  struct list **v;

  v = make (col, &the_cols, sizeof (struct list *), COL_BUF);
  return make (row, v, sizeof (struct cell), ROW_BUF);
}

#ifdef __STDC__
void
find_cells_in_range (struct rng *r)
#else
void
find_cells_in_range (r)
     struct rng *r;
#endif
{
  struct cf *new;
  struct list **firstcol;

  new = (struct cf *)obstack_alloc (&find_stack, sizeof (struct cf));
  new->make = 0;
  new->next = fp;
  fp = new;
  new->rows = find_rng (&the_cols, r->lc, r->hc, sizeof (void *));
  firstcol = next_rng (new->rows, 0);
  if (firstcol)
    new->cols = find_rng (firstcol, r->lr, r->hr, sizeof (struct cell));
  else
    new->cols = 0;
}

#ifdef __STDC__
void
make_cells_in_range (struct rng *r)
#else
void
make_cells_in_range (r)
     struct rng *r;
#endif
{
  struct cf *new;
  struct list **firstcol;

  new = (struct cf *)obstack_alloc (&find_stack, sizeof (struct cf));
  new->make = 1;
  new->next = fp;
  fp = new;
  new->rows = make_rng (&the_cols, r->lc, r->hc, sizeof (void *), ROW_BUF);
  firstcol = next_rng (new->rows, 0);
  new->cols = make_rng (firstcol, r->lr, r->hr, sizeof (struct cell), COL_BUF);
}

#ifdef __STDC__
struct cell *
next_cell_in_range (void)
#else
struct cell *
next_cell_in_range ()
#endif
{
  struct cell *ret;
  void *new_row;

  for (;;)
    {
      if (ret = next_rng (fp->cols, 0))
	return ret;
      new_row = next_rng (fp->rows, 0);
      if (!new_row)
	{
	  struct cf *old;

	  old = fp->next;
	  obstack_free (&find_stack, fp);
	  fp = old;
	  return 0;
	}
      fp->cols = fp->make ? make_rng (new_row, fp->cols->lo, fp->cols->hi, sizeof (struct cell), ROW_BUF)
      : find_rng (new_row, fp->cols->lo, fp->cols->hi, sizeof (struct cell));
    }
}

#ifdef __STDC__
struct cell *
next_row_col_in_range (CELLREF *rowp, CELLREF *colp)
#else
struct cell *
next_row_col_in_range (rowp, colp)
     CELLREF *rowp;
     CELLREF *colp;
#endif
{
  struct cell *ret;
  struct list **new_row;

  for (;;)
    {
      if (ret = next_rng (fp->cols, rowp))
	{
	  *colp = fp->rows->cur - 1;
	  return ret;
	}
      new_row = next_rng (fp->rows, colp);
      if (!new_row)
	{
	  struct cf *old;

	  old = fp->next;
	  obstack_free (&find_stack, fp);
	  fp = old;
	  return 0;
	}
      fp->cols = fp->make ? make_rng (new_row, fp->cols->lo, fp->cols->hi, sizeof (struct cell), ROW_BUF)
      : find_rng (new_row, fp->cols->lo, fp->cols->hi, sizeof (struct cell));
    }
}

#ifdef __STDC__
void
no_more_cells (void)
#else
void
no_more_cells ()
#endif
{
  struct cf *old;

/* This relies on knowing that the obstack contains
 * the current find (struct cf) underneath two associated
 * `struct find's.
 * Here, we pop all those frames, and then free them at once.
 */

  old = fp->next;
  finds = finds->next->next;
  obstack_free (&find_stack, fp);
  fp = old;
}

#ifdef __STDC__
CELLREF
max_row (CELLREF col)
#else
CELLREF
max_row (col)
     CELLREF col;
#endif
{
  struct list **ptr;

  ptr = find (col, the_cols, sizeof (void *));
  if (!ptr || !*ptr)
    return MIN;
  while ((*ptr)->next)
    ptr = &((*ptr)->next);
  return (*ptr)->hi;
}

#ifdef __STDC__
CELLREF
max_col (CELLREF row)
#else
CELLREF
max_col (row)
     CELLREF row;
#endif
{
  struct list *ptr;

  if (!the_cols)
    return MIN;
  for (ptr = the_cols; ptr->next; ptr = ptr->next)
    ;
  return ptr->hi;
}

#ifdef __STDC__
CELLREF 
highest_row (void)
#else
CELLREF 
highest_row ()
#endif
{
  void *f;
  struct list **ptr;
  CELLREF hi = MIN;

  f = find_rng (&the_cols, MIN, MAX, sizeof (void *));
  while (ptr = next_rng (f, 0))
    {
      if (*ptr)
	{
	  while ((*ptr)->next)
	    ptr = &((*ptr)->next);
	  if ((*ptr)->hi > hi)
	    hi = (*ptr)->hi;
	}
    }
  return hi;
}


#ifdef __STDC__
CELLREF 
highest_col (void)
#else
CELLREF 
highest_col ()
#endif
{
  struct list *ptr;

  if (!the_cols)
    return MIN;
  for (ptr = the_cols; ptr->next; ptr = ptr->next)
    ;
  return ptr->hi;
}


/* Routines for dealing with the widths of columns. . . */

#ifdef __STDC__
int 
get_width (CELLREF col)
#else
int 
get_width (col)
     CELLREF col;
#endif
{
  int *ptr;

  ptr = find (col, wids, sizeof (int));
  if (!ptr || !*ptr)
    return default_width;
  return (*ptr) - 1;
}


#ifdef __STDC__
int 
get_nodef_width (CELLREF col)
#else
int 
get_nodef_width (col)
     CELLREF col;
#endif
{
  int *ptr;

  ptr = find (col, wids, sizeof (int));
  return ptr ? *ptr : 0;
}

#ifdef __STDC__
void 
set_width (CELLREF col, int wid)
#else
void 
set_width (col, wid)
     CELLREF col;
     int wid;
#endif
{
  int *ptr;

  ptr = make (col, &wids, sizeof (int), COL_BUF);
  *ptr = wid;
}

#ifdef __STDC__
void 
find_widths (CELLREF lo, CELLREF hi)
#else
void 
find_widths (lo, hi)
     CELLREF lo;
     CELLREF hi;
#endif
{
  w_find = find_rng (&wids, lo, hi, sizeof (int));
}

#ifdef __STDC__
int 
next_width (CELLREF *posp)
#else
int 
next_width (posp)
     CELLREF *posp;
#endif
{
  int *ptr;

  do
    ptr = next_rng (w_find, posp);
  while (ptr && !*ptr);
  return ptr ? *ptr : 0;
}

#ifdef __STDC__
static void
do_shift (int over, CELLREF lo, CELLREF hi, struct list **start, int buf)
#else
static void
do_shift (over, lo, hi, start, buf)
     int over;
     CELLREF lo;
     CELLREF hi;
     struct list **start;
     int buf;
#endif
{
  CELLREF pos;
  int w;
  int *ptr;
  int inc;
  struct list *p;

  if (!*start)
    return;
  for (p = *start; p->next; p = p->next)
    ;

  if (hi > p->hi)
    hi = p->hi;

  if (over > 0)
    {
      pos = hi;
      hi = lo;
      lo = pos;
      inc = -1;
    }
  else
    inc = 1;

  if (inc > 0)
    {
      if (lo > hi)
	return;
    }
  else if (hi > lo)
    return;

  for (pos = lo;; pos += inc)
    {
      ptr = find (pos, *start, sizeof (int));
      w = ptr ? *ptr : 0;
      ptr = w ? make (pos + over, start, sizeof (int), buf) :
        find (pos + over, *start, sizeof (int));
      if (w || (ptr && *ptr))
	*ptr = w;
      if (pos == hi)
	break;
    }
  for (pos = hi + over;;)
    {
      pos += inc;
      ptr = find (pos, *start, sizeof (int));
      if (ptr)
	*ptr = 0;
      if (pos == hi)
	break;
    }
}

#ifdef __STDC__
void 
shift_widths (int over, CELLREF lo, CELLREF hi)
#else
void 
shift_widths (over, lo, hi)
     int over;
     CELLREF lo;
     CELLREF hi;
#endif
{
  do_shift (over, lo, hi, &wids, COL_BUF);
}


/* This inserts lines in which formulas can be displayed. 
 * It probably ought to be 1 or 0.
 */
int display_formula_mode = 0;

/* Routines for dealing with the height of rows 
 */
#ifdef __STDC__
int 
get_height (CELLREF row)
#else
int 
get_height (row)
     CELLREF row;
#endif
{
  int *ptr;

  ptr = find (row, hgts, sizeof (int));
  if (!ptr || !*ptr)
    return default_height;
  return *ptr - 1 + (display_formula_mode && using_curses);
}

#ifdef __STDC__
int 
get_nodef_height (CELLREF row)
#else
int 
get_nodef_height (row)
     CELLREF row;
#endif
{
  int *ptr;

  ptr = find (row, hgts, sizeof (int));
  return ptr ? *ptr : 0;
}

#ifdef __STDC__
void 
set_height (CELLREF row, int hgt)
#else
void 
set_height (row, hgt)
     CELLREF row;
     int hgt;
#endif
{
  int *ptr;

  ptr = make (row, &hgts, sizeof (int), ROW_BUF);
  *ptr = hgt;
}

float height_scale = 1.;
float width_scale = 1.;

float user_height_scale = 1.;
float user_width_scale = 1.;

#ifdef __STDC__
void
set_user_scales (double hs, double ws)
#else
void
set_user_scales (hs, ws)
     double hs;
     double ws;
#endif
{
  user_height_scale = hs;
  user_width_scale = ws;
  io_repaint ();
}

#ifdef __STDC__
int
get_scaled_height (CELLREF r)
#else
int
get_scaled_height (r)
     CELLREF r;
#endif
{
  return ((user_height_scale <= 0.)
	  ? 1
	  :  (int) (get_height (r) * height_scale * user_height_scale));
}

#ifdef __STDC__
int
get_scaled_width (CELLREF c)
#else
int
get_scaled_width (c)
     CELLREF c;
#endif
{
  return ((user_width_scale <= 0.)
	  ? 1
	  : (int)(get_width (c) * width_scale * user_width_scale));
}


#ifdef __STDC__
void 
find_heights (CELLREF lo, CELLREF hi)
#else
void 
find_heights (lo, hi)
     CELLREF lo;
     CELLREF hi;
#endif
{
  h_find = find_rng (&hgts, lo, hi, sizeof (int));
}

#ifdef __STDC__
int 
next_height (CELLREF *posp)
#else
int 
next_height (posp)
     CELLREF *posp;
#endif
{
  int *ptr;

  do
    ptr = next_rng (h_find, posp);
  while (ptr && !*ptr);
  return ptr ? *ptr : 0;
}

#ifdef __STDC__
void 
shift_heights (int dn, CELLREF lo, CELLREF hi)
#else
void 
shift_heights (dn, lo, hi)
     int dn;
     CELLREF lo;
     CELLREF hi;
#endif
{
  do_shift (dn, lo, hi, &hgts, ROW_BUF);
}

#ifdef TEST
extern char *bname[];

extern void dbg_print_ref_fm ();
extern void dbg_print_ref_to ();
extern void dbg_print_formula ();

void
dbg_print_cell (cp)
     CELL *cp;
{
  char *ptr1, *ptr2;
  char tmpbuf[30];

  switch (GET_TYP (cp))
    {
    case 0:
      ptr1 = "(null)";
      ptr2 = "";
      break;
    case TYP_FLT:
      sprintf (tmpbuf, "Float: %.16g", cp->cell_flt);
      ptr1 = tmpbuf;
      ptr2 = "";
      break;
    case TYP_INT:
      sprintf (tmpbuf, "Int: %ld", cp->cell_int);
      ptr1 = tmpbuf;
      ptr2 = "";
      break;
    case TYP_ERR:
      sprintf (tmpbuf, "Error: %d: ", cp->cell_err);
      ptr1 = tmpbuf;
      ptr2 = ename[cp->cell_err];
      break;
    case TYP_BOL:
      sprintf (tmpbuf, "Bool: %d: ", cp->cell_bol);
      ptr1 = tmpbuf;
      ptr2 = bname[cp->cell_bol];
      break;
    case TYP_STR:
      sprintf (tmpbuf, "String: %p: ", cp->cell_str);
      ptr1 = tmpbuf;
      ptr2 = cp->cell_str;
      break;
    default:
      sprintf (tmpbuf, "Unknown: %d", GET_TYP (cp));
      ptr1 = tmpbuf;
      ptr2 = "";
      break;
    }
  io_text_line ("    Cell %p:  flg %#lx  fm %p  to %p  fa %p  cy %d  val %s%s",
		cp, cp->cell_flags, cp->cell_refs_from, cp->cell_refs_to,
		cp->cell_formula, cp->cell_cycle, ptr1, ptr2);
  dbg_print_ref_fm (cp->cell_refs_from);
  dbg_print_ref_to (cp->cell_refs_to);
  dbg_print_formula (cp->cell_formula);
}


void 
dbg_print_list (ptr, ele, txt, prsub)
     struct list *ptr;
     int ele;
     char *txt;
     void (*prsub) ();
{
  CELLREF pos;

  while (ptr)
    {
      io_text_line ("%s %p: lo %u  hi %u  nxt %p  mem %p", txt, ptr, ptr->lo, ptr->hi, ptr->next, &(ptr->mem[0]));
      pos = ptr->lo;
      for (;;)
	{
	  (*prsub) (ptr->mem + ele * (pos - ptr->lo));
	  if (pos == ptr->hi)
	    break;
	  pos++;
	}
      ptr = ptr->next;
    }
}

static void 
dbg_pr_row (p)
     VOIDSTAR p;
{
  io_text_line ("  %p", p);
}

void 
dbg_print_rows (pos)
     CELLREF pos;
{
  dbg_print_list (the_cols, sizeof (struct list *), "row", dbg_pr_row);
}

static void 
dbg_pr_all (p)
     VOIDSTAR p;
{
  struct list **ptr;

  io_text_line ("  %p", p);
  ptr = p;
  dbg_print_list (*ptr, sizeof (struct cell), "  col",
		    (void (*)(void *)) dbg_print_cell);
}

void 
dbg_print_array ()
{
  dbg_print_list (the_cols, sizeof (struct list *), "row", dbg_pr_all);
}

void 
dbg_print_cols (pos)
     CELLREF pos;
{
  /* struct list **ptr;

	ptr=find(...);
	if(...); */
}

#endif

#ifdef TEST_ME
main ()
{
  char buf[100];
  static void *vec[10];
  static siz[10];
  char *ret;
  int n;
  int t;
  int hi, lo;
  CELLREF pos;
  int z;


  while (printf ("-->"), gets (buf))
    {
      n = buf[1] - '0';
      switch (buf[0])
	{
	case 'i':
	  if (sscanf (&buf[2], "%d %d", &siz[n], &t) < 1)
	    {
	      printf ("No size?\n");
	      break;
	    }
	  vec[n] = list_init (siz[n], t);
	  printf ("vec %d init'd to %lx with siz %u and buf %d\n", n, vec[n], siz[n], t);
	  break;

	case 'f':
	  ret = find (vec[n], atoi (&buf[2]));
	  if (ret)
	    {
	      printf ("Found at %lx  ", ret);
	      for (t = 0; t < siz[n]; t++)
		printf ("%x ", ret[t]);
	      printf ("\n");
	    }
	  else
	    printf ("Not found\n");
	  break;

	case 'F':
	  if (sscanf (&buf[2], "%d %d", &lo, &hi) != 2)
	    {
	      printf ("Faild to scan\n");
	      break;
	    }
	  find_rng (vec[n], lo, hi);
	  while (ret = next_rng (&pos))
	    {
	      printf ("Found %u at %lx  ", pos, ret);
	      for (t = 0; t < siz[n]; t++)
		printf ("%x ", ret[t]);
	      printf ("\n");
	    }
	  break;

	case 'm':
	  ret = make (vec[n], atoi (&buf[2]));
	  if (ret)
	    {
	      z = atoi (&buf[4]);
	      printf ("Made at %lx  ", ret);
	      for (t = 0; t < siz[n]; t++)
		{
		  printf ("%x(%x) ", ret[t], z);
		  ret[t] = z;
		}
	      printf ("\n");
	    }
	  else
	    printf ("Failed!!\n");
	  break;

	case 'M':
	  z = 0;
	  if (sscanf (&buf[2], "%d %d %d", &lo, &hi, &z) < 2)
	    {
	      printf ("Scan failed\n");
	      break;
	    }
	  make_rng (vec[n], lo, hi);
	  while (ret = next_rng (&pos))
	    {
	      printf ("Found %u at %lx  ", pos, ret);
	      for (t = 0; t < siz[n]; t++)
		{
		  printf ("%x(%x) ", ret[t], z);
		  ret[t] = z;
		}
	      if (z)
		z++;
	      printf ("\n");
	    }
	  break;

	case 'q':
	  exit (0);

	default:
	  printf ("Unknown command!\n");
	}
    }
}

#endif
