static char rcsid[] = "$Id: history.c,v 1.1 1992/09/14 13:02:14 mike Exp $";

/* $Log: history.c,v $
 * Revision 1.1  1992/09/14  13:02:14  mike
 * Initial revision
 *
 */

/* history.c : general purpose remember lines of text for recall.
 *   It looks like a stack with semi-random access.  The stack is fixed size
 *   with all addations being at the top with a pointer to the interior of
 *   the stack.  Old entries are pushed off the bottom as the stack
 *   overflows.
 *     --Bottom-->|oldest entry| ... |most recent entry|<--Top--
 * Things a history package needs to implement:
 *   Hsize(n): set the size of the history buffer to n bytes.
 *      ??? how get
 *   Hnext():  Move the stack pointer to the next entry (toward Top).
 *     TRUE if successful, FALSE if can't move.
 *   Hprev():  Move the stack pointer to the previous entry (toward Bottom).
 *     TRUE if successful, FALSE if can't move.
 *   Htop():  Move history pointer to Top (most recent entry of the history
 *     stack).
 *   Hbottom():  Move history pointer to Bottom (the oldest entry of the
 *     history stack).
 *   Hcurrent():  Return pointer to current history entry.
 *   Hsearch(direction,matcher) pfi matcher;
 *     Search for a pattern.  Matcher is called for each entry.  If a match
 *       is found, Hsearch returns a pointer to it and leave pointer at the
 *       entry else return NULL and don't move pointer.
 *     The current entry is not matched.
 *     The caller has to mess with the pattern.
 *   Hadd(text):  Add a history entry to the end to the history stack.
 *     Updates the pointer.
 *   ?Hentries() : return the number of entries in the stack.
 * C Durland
 */

/* Copyright 1990, 1991 Craig Durland
 *   Distributed under the terms of the GNU General Public License.
 *   Distributed "as is", without warranties of any kind, but comments,
 *     suggestions and bug reports are welcome.
 */

#include <const.h>
#include "led.h"

#define HBUFSIZE 1000

static char *get_hist();
static int Hentries();

static int nth_hist = 0, num_hists = 0;

void Htop() { nth_hist = num_hists; }
void Hbottom() { nth_hist = 0; }

char *Hcurrent()
{
  char *ptr = get_hist(nth_hist);
  return ptr ? ptr : "";
}

Hnext()
{
  if (nth_hist < num_hists-1) { ++nth_hist; return TRUE; }
  return FALSE;
}

Hprev()
{
  if (0 < nth_hist) { --nth_hist; return TRUE; }
  return FALSE;
}

char *Hsearch(search_forward,matcher) int (*matcher)();
{
  register char *ptr;
  register int j;

  if (search_forward)
  {
    for (j = nth_hist+1; j < num_hists; j++)
      if ((*matcher)(ptr = get_hist(j)))
      {
      found_it:
	nth_hist = j;
      	return ptr;
      }
  }
  else		/* search backwards */
  {
    for (j = nth_hist-1; 0 <= j; j-- )
      if ((*matcher)(ptr = get_hist(j))) goto found_it;
  }
  return NULL;
}

static char history[HBUFSIZE+1];
static int hsize = HBUFSIZE, hidx = 0;

    /* Add test to the Top of the history stack.  If there is enough room in
     *   the stack, just add text.  If not enough room, remove entries from
     *   the Bottom of the stack until there is.
     *   Notes:
     *     Given:  len <= hsize
     *       you can show: len -(hsize -hidx) <= hidx
     *     Given:  len > (hsize -hidx)
     *       you can show: len -(hsize -hidx) > 0
     *     All entries are terminated by '\0' so if i < hidx, there is a
     *       '\0' before i++ reaches hidx.
     */
int Hadd(text) char *text;
{
  int i,j, len = strlen(text) +1;

  if (len < 3) return TRUE;
  if (hsize < len) return FALSE;	/* text won't fit in buffer */
  Htop(); Hprev(); if (strcmp(Hcurrent(),text)==0) return TRUE;

  if (len>(hsize -hidx))	/* not enough room */
  {
    if ((i = len -(hsize -hidx)) < hidx) while (history[i++]) ;
    j = i; i = 0; while (j<hidx) history[i++] = history[j++];
    hidx = i;
  }
  strcpy(&history[hidx],text); hidx += len;
  num_hists = Hentries();
  Htop();
  return TRUE;
}

/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */

static int Hentries()		/* return the number of history lines */
{
  int j, n = 0;

  for (j = 0; j<hidx; j++) if (history[j]=='\0') n++;
  return n;
}

static char *get_hist(n)	/* return the nth line of the history */
{
  int j;

  for (j = 0; j<hidx && 0<n; j++) if (history[j]=='\0') n--;
  return (n==0 && j<hidx) ? &history[j] : NULL;
}
