/*
 *  history.c -- handling the history list
 *
 *	This is the history list implementation to be used if
 *	we are NOT using the GNU readline library!
 *
 *  PMF -- Padrone's MudFrontend, a frontend for (maybe mostly LP-)mud
 *  Thomas Padron-McCarthy (Email: padrone@lysator.liu.se), 1990, 1991
 *  Share and enjoy, but be nice: don't steal my program! Hugo is watching!
 *  This file latest updated: Sept 22, 1991
 *
 */

#include <strings.h>
#include <stdio.h>
#include <ctype.h>
#include "safe_malloc.h"
#include "config.h"
#include "pmf.h"
#include "globals.h"

/* The array "history_list" contains the history list. */
struct event_struct {
    int number;
    char *the_command;
};
static int max_history = 0;
static struct event_struct *history_list = NULL;
static int nr_events = 0;
static int latest_event_nr = 0;

/*---------------------------------------------------------------------------*/

void set_max_history(n)
{
    max_history = n;
    if (nr_events > max_history) {

	copy_bytes_up(&history_list[0], &history_list[nr_events - max_history],
		      max_history * sizeof(struct event_struct));

	nr_events = max_history;
    }
    if (!history_list)
	history_list = (struct event_struct *)
	    safe_malloc(max_history * sizeof(struct event_struct));
    else
	history_list = (struct event_struct *)
	    safe_realloc(history_list, max_history * sizeof(struct event_struct));
} /* set_max_history */

/* Get an event. If not on the list, return NULL. */
char *find_event(number)
  int number;
{

    if (!history_list)
	set_max_history(DEFAULT_MAX_HISTORY);

    if (latest_event_nr - number >= nr_events || number > latest_event_nr)
	return NULL;
    return history_list[number - history_list[0].number].the_command;
} /* find_event */

int search_event(str)
char *str;
{
    int i, len;

    len = strlen(str);
    for (i = nr_events - 1; i >= 0; --i)
	if (!strncmp(str, history_list[i].the_command, len))
	    return history_list[i].number;
    return 0;
} /* search_event */

void print_history(fp, nr_lines)
int nr_lines;
{
    int i;

    if (nr_lines <= 0 || nr_lines > nr_events)
	i = 0;
    else
	i = nr_events - nr_lines;

    for (; i < nr_events; ++i)
	fprintf(fp, "%5d   %s\n",
		history_list[i].number, history_list[i].the_command);
} /* print_history */

/*  Add an event to the history list.
 *  This function should be called after history expansion of the current command!
 */
void add_mud_history(command_line)
  char *command_line;
{

    USER_DEBUG(("add_mud_history(\"%s\")", command_line));

    ++latest_event_nr;
    if (!history_list) {
	set_max_history(DEFAULT_MAX_HISTORY);
    }
    if (nr_events >= max_history) {
	safe_free(history_list[0].the_command);
	/* Move the list one step up. */
	copy_bytes_up(&history_list[0], &history_list[1],
		      (max_history - 1) * sizeof(struct event_struct));
    }
    else
	++nr_events;
    history_list[nr_events - 1].number = latest_event_nr;
    history_list[nr_events - 1].the_command = 
	strcpy(safe_malloc(strlen(command_line) + 1), command_line);

    /* This is a kludge to hide the password! It will probably work most of the time. */
    if (echo_is_off)
	history_list[nr_events - 1].the_command[0] = '\0';

} /* add_mud_history */

/*  Expand history refrences of the type "!N" (where N is a number)
 *  or "!!" in a command line. It will return a a malloc'ed string.
 *  If it returns NULL, no history references were expanded.
 *  This function should be called before add_mud_history of the
 *  current command!
 *  Else, it returns a malloc'ed string.
 */
char *expand_history(command_line)
  char *command_line;
{
    char first_word[MAX_WORD_LENGTH + 1];
    int first_length;
    char *this_expansion, *expanded_line;
    int event_nr;

    USER_DEBUG(("expand_history(\"%s\")", command_line));

    while (isspace(*command_line))
	++command_line;

    /* Get length of the first word in the string (up to space, tab or null). */
    first_length = 0;
    while (command_line[first_length] && !isspace(command_line[first_length]))
	++first_length;
    if (first_length > MAX_WORD_LENGTH)
	return NULL;	/* A very long first word. Surely not a history ref! */

    strncpy(first_word, command_line, first_length);
    first_word[first_length] = '\0';
    if (!strcmp(first_word, "!!"))
	event_nr = latest_event_nr;
    else if (sscanf(first_word, "!-%d", &event_nr) == 1)
	event_nr = latest_event_nr - event_nr + 1;
    else if (sscanf(first_word, "!%d", &event_nr) == 1)
	;
    else if (first_word[0] == '!') {
	event_nr = search_event(first_word + 1);
	if (!event_nr)
	    return NULL;
    }
    else
	return NULL;
    this_expansion = find_event(event_nr);
    if (!this_expansion)
	error("No such event (\"!%d\") in the history list.", event_nr);
    expanded_line = safe_malloc(strlen(this_expansion) + strlen(command_line) + 1);
	/* Yes, some wasted space at the end. */
    strcpy(expanded_line, this_expansion);
    strcat(expanded_line, " ");
    if (command_line[first_length])
	strcat(expanded_line, command_line + first_length + 1);
    USER_DEBUG(("expanded_line == '%s'", expanded_line));
    return expanded_line;
} /* expand_history */

query_max_history() {
    return max_history;
}

query_nr_events() {
    return nr_events;
}

query_latest_event_nr() {
    return latest_event_nr;
}


syntax highlighted by Code2HTML, v. 0.9.1