/* New for v2.0: readline support -- daw */

/* all the tab completion support is here in this one file */

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#include <stdio.h>
#include <ctype.h>

extern char *mystrdup();

typedef struct list_s {
	char *word;
	struct list_s *next;
} list_t;

static list_t *complist = 0;	/* tab completion list */

/*
 * the completion generation function for readline.
 * this function will be called repeatedly with the
 * same s -- state=0 the first time, and state!=0 the
 * rest of the time.
 * 
 * it returns a pointer to a match each time, and a
 * (char *) 0 pointer when it's done.
 */
char *
  rltab_generate(s, state)
     char *s;
     int state;
{
	static list_t *p;
	char *match;

	if (state == 0) {
		if (complist == 0)
			return ((char *) 0);
		p = complist->next;
	}
	for (; p; p = p->next)
		if (strncasecmp(s, p->word, strlen(s)) == 0) {
			match = mystrdup(p->word);
			p = p->next;
			return (match);
		}
	return ((char *) 0);
}

static void rltab_add(word)
     char *word;
{
	list_t *p;

	if (complist == 0) {
		/* add dummy header node */
		if ((complist = (list_t *) malloc(sizeof(list_t))) == 0)
			syserr("rltab_add: malloc");
		complist->word = 0;
		if ((complist->next = (list_t *) malloc(sizeof(list_t))) == 0)
			syserr("rltab_add: malloc");
		p = complist->next;
		p->word = mystrdup(word);
		p->next = 0;
		return;
	}

	/* avoid duplicates */
	for (p = complist->next; p; p = p->next)
		if (strcasecmp(p->word, word) == 0)
			return;

	/* add to head of list */
	if ((p = (list_t *) malloc(sizeof(list_t))) == 0)
		syserr("rltab_add: malloc");
	p->word = mystrdup(word);
	p->next = complist->next;
	complist->next = p;
}

void rltab_delete(word)
     char *word;
{
	list_t *p, *q;

	if (complist == 0) {
		tintin_puts("#Delete failed: empty completion list.", 0);
		return;
	}
	for (p = complist; p->next; p = p->next)
		if (strcasecmp(p->next->word, word) == 0) {
			q = p->next;
			p->next = p->next->next;
			free(q->word);
			free(q);
			tintin_puts("#Ok, deleted.", 0);
			return;
		}
	tintin_puts("#Delete failed: word not in completion list.", 0);
}

void rltab_list( /* void */ )
{
	list_t *p;
	int col = 0, ncols = 4;
	char line[128];

	if (complist == 0 || complist->next == 0) {
		tintin_puts("#Empty completion list.", 0);
		return;
	}

	line[0] = '\0';
	for (p = complist->next; p; p = p->next) {
		sprintf(line + strlen(line), "%15.15s ", p->word);
		if (++col == ncols) {
			tintin_puts(line, 0);
			col = 0;
			line[0] = '\0';
		}
	}
	if (line[0])
		tintin_puts(line, 0);
}

static void rltab_purge( /* void */ )
{
	list_t *p, *q;

	if (complist == 0) {
		if ((complist = (list_t *) malloc(sizeof(list_t))) == 0)
			syserr("rltab_purge: malloc");
		complist->word = 0;
		complist->next = 0;
		return;
	}

	for (p = complist->next; p; p = q) {
		q = p->next;
		free(p->word);
		free(p);
	}
	complist->next = 0;
}

void rltab_read( /* void */ )
{
	FILE *f;
	char *s, *t, line[128];

	if ((f = fopen("tab.txt", "r")) == 0) {
		tintin_puts("#Couldn't open tab.txt", 0);
		return;
	}
	rltab_purge();
	while (fgets(line, sizeof(line), f)) {
		/* delete leading and trailing whitespace */
		for (s = line; isspace(*s); s++);
		for (t = s; *t && !isspace(*t); t++);
		*t = '\0';
		rltab_add(s);
	}
	fclose(f);
	tintin_puts("#Read tab.txt, completion list initialized.", 0);
}

void do_tabadd(arg)
     char *arg;
{
	char buf[128];

	if (arg == 0 || *arg == '\0') {
		tintin_puts("#Add failed: no word specified.", 0);
		return;
	}
	get_arg_in_braces(arg, buf, 1);
	rltab_add(buf);
	tintin_puts("#Added.", 0);
}

void do_tabdel(arg)
     char *arg;
{
	char buf[128];

	if (arg == 0 || *arg == '\0') {
		tintin_puts("#Delete failed: no word specified.", 0);
		return;
	}
	get_arg_in_braces(arg, buf, 1);
	rltab_delete(buf);
}

void do_tabsave( /* void */ )
{
	FILE *f;
	list_t *p;

	if (complist == 0 || complist->next == 0) {
		tintin_puts("#Empty completion list, nothing to save.", 0);
		return;
	}
	if ((f = fopen("tab.txt", "w")) == 0) {
		tintin_puts("#Couldn't open tab.txt", 0);
		return;
	}
	for (p = complist->next; p; p = p->next)
		fprintf(f, "%s\n", p->word);
	fclose(f);
	tintin_puts("#Saved to tab.txt.", 0);
}