/************************************************************************
 * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is	*
 * provided to you without charge, and with no warranty.  You may give	*
 * away copies of JOVE, including sources, provided that this notice is *
 * included in all the files.						*
 ************************************************************************/

#define NO_PROCDECL	/* kludge to get this file through small v7 compiler */

#include "jove.h"

RCS("$Id: funcdefs.c,v 14.30 1993/02/09 17:44:07 tom Exp tom $")

#include "ctype.h"
#include "maps.h"
#ifdef IPROCS
#   include <signal.h>
#endif

/*
 * First we redefine the DEF_XXX macros and include the command list
 * to declare the routines.
 */
#undef DEF_CMD
#undef DEF_MAJ
#undef DEF_MIN
#undef DEF_MAP
#define	DEF_CMD(name,f,opt)	extern void f __((void));
#define DEF_MAJ(name,n,desc)
#define DEF_MIN(name,n,desc)
#define DEF_MAP(name,map,n)

#include "funcs.inc"

/*
 * Now we redefine the macros to make valid command table entries, and
 * include the command list again.
 */
#undef DEF_CMD
#undef DEF_MAJ
#undef DEF_MIN
#undef DEF_MAP
#define	DEF_CMD(name,f,opt)	{FUNCTION|opt,name,f},
#define	DEF_MAJ(name,n,desc)	{FUNCTION|MAJOR_MODE|ARG(n),name},
#define	DEF_MIN(name,n,desc)	{FUNCTION|MINOR_MODE|ARG(n),name},
#define	DEF_MAP(name,map,n)	{FUNCTION|PREFIX|ARG(n),name,(void(*)__((void)))&Maps[n]},

const Command	commands[] = {
#	include "funcs.inc"
	FUNCTION, 0, 0
};

data_obj *
findcom(prompt)
const char	*prompt;
{
	static struct FIND_CACHE(sizeof commands/sizeof commands[0]) cache ZERO;

	return find_builtin((data_obj *) commands,
			    (struct find_cache *) &cache, prompt);
}

/*
 * Support routine to find a builtin Command or Variable.
 */
data_obj *
find_builtin(objtab, cache, prompt)
const data_obj	*objtab;
struct find_cache *cache;
const char	*prompt;
{
	register const data_obj *dp = objtab;

#define objsize	sizeof(Command)
#ifdef objsize
	/* ...this assumes: */
	ASSERT(sizeof(Command) == sizeof(Variable));
#else
	size_t	objsize = sizeof(Command);

	if ((sizeof(Variable) != sizeof(Command)) /* optimization */&&
	    (dp->Type & VARIABLE))
		objsize = sizeof(Variable);
#endif
	ASSERT((dp->Type & REALTYPEMASK) == FUNCTION ||
	       (dp->Type & REALTYPEMASK) == VARIABLE);

	/* do the address calculation ``by hand''. */
#define address(p, n)	((data_obj *)((char *) p + (n) * objsize))


#define	hash(c)		(islower(c) ? (c) - 'a' + 1 : 0)
    {
	register const char	**names = cache->nametab;

	if (!names[0]) {	/* initialize name- and hash table */

		while (*names = dp->Name) {
			register int	c = *(*names++);

			c = hash(c);
			if (!cache->hashtab[c])
				cache->hashtab[c] = dp;

			dp = address(dp, 1);
		}
		dp = objtab;
	}
	if (!InJoverc)
		return address(dp, complete(names, (dp->Type & FUNCTION) ?
						    CASEIND : NOTHING, prompt));
		/* complete() now always returns a valid index (i.e. >= 0) */
    }
	/* This is for faster startup.	This just reads until a space or a
	   tab or a newline character is reached, and then does a
	   semi-hashed lookup on that string.  This should be much faster
	   than initializing the minibuffer for each line.  The command list
	   must be maintained in alphabetical order for this to work. */
   {
	register char	*cp = Minibuf;	/* yes it is idle now */
	register int	c;
	register int	len,
			found = 0;
	const data_obj	*which;

	/* we "know" since we're in a .joverc that the command
	   is supplied via Inputp.  This avoids some overhead. */

	if (Inputp) {
		while ((c = *Inputp) != '\0') {
			Inputp++;
			if (isspace(c)) {
				if (cp > Minibuf)
					break;
				continue;
			}
			if (c == '\n' || c == '\r') {
				break;
			}
			if (dp->Type & FUNCTION)
				c = tolower(c);
			*cp++ = c;
		}
		*cp = '\0';
	}

	if ((len = cp - Minibuf) == 0)
		complain("[Premature end of line]");

	/* look it up (in the reduced search space) */

	if (c = Minibuf[0], dp = cache->hashtab[hash(c)]) {

		while ((cp = (char *)dp->Name) && (cp[0] <= c)) {

			if (numcomp(cp, Minibuf) == len) {
				if (cp[len] == '\0')	/* exact match */
					return (data_obj *) dp;
				found++;
				which = dp;
			}
			dp = address(dp, 1);
		}
	}
	if (--found)
		complain((found > 0) ?	"[\"%s\" ambiguous]" :
					"[\"%s\" unknown]", Minibuf);
#undef hash
#undef address
#undef objsize

	return (data_obj *) which;
   }
}

/* this is a dummy function for the poor man's version of JOVE */
void
NonExisting()
{
	s_mess("Sorry, \"%f\" is not available...");
}

/*======================================================================
 * $Log: funcdefs.c,v $
 * Revision 14.30  1993/02/09  17:44:07  tom
 * cleanup whitespace; factor out joverc optimization to find_builtin() so
 * that findvar() can use it too; change DEF_MAP() to contain pointer to Keymap.
 *
 * Revision 14.28  1992/10/23  17:57:27  tom
 * change cast in DEF_MAP to full ANSI-prototype.
 *
 * Revision 14.26  1992/08/26  23:56:49  tom
 * add RCS directives.
 *
 */
