/* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/tw.init.c,v 3.0 1991/07/04 21:49:28 christos Exp $ */
/*
 * tw.init.c: TwENEX initializations
 */
/*-
 * Copyright (c) 1980, 1991 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include "config.h"
#if !defined(lint) && !defined(pdp11)
static char *rcsid() 
    { return "$Id: tw.init.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; }
#endif

#include "sh.h"
#include "tw.h"

/*
 * Build the command name list (and print the results).  This is a HACK until
 * I can get the rehash command to include its results in the command list.
 */

static int maxcommands = 0;


void
tw_clear_comm_list()
{
    register int i;

    have_sorted = 0;
    if (numcommands != 0) {
/*        for (i = 0; com_list[i]; i++) { */
	for (i = 0; i < numcommands; i++) {
	    xfree((ptr_t) com_list[i]);
	    com_list[i] = NULL;
	}
	numcommands = 0;
    }
}

void
tw_sort_comms()
{				/* could be re-written */
    register int i, forward;

    /* sort the list. */
    qsort((ptr_t) com_list, (size_t) numcommands, sizeof(com_list[0]), 
	  (int (*) __P((const void *, const void *))) fcompare);

    /* get rid of multiple entries */
    for (i = 0, forward = 0; i < numcommands - 1; i++) {
	if (Strcmp(com_list[i], com_list[i + 1]) == 0) {	/* garbage */
	    xfree((ptr_t) com_list[i]);
	    forward++;		/* increase the forward ref. count */
	}
	else if (forward) {
	    com_list[i - forward] = com_list[i];
	}
    }
    /* Fix fencepost error -- Theodore Ts'o <tytso@athena.mit.edu> */
    if (forward)
	com_list[i - forward] = com_list[i];
    numcommands -= forward;
    com_list[numcommands] = (Char *) NULL;

    have_sorted = 1;
}

void
tw_comm_name_add(name)		/* this is going to be called a LOT at startup */
    Char   *name;
{
    register int length;
    register long i;
    register Char **ncl, **p1, **p2;

    if (maxcommands == 0) {
	com_list = (Char **) xmalloc((size_t) (NUMCMDS_START *
						   sizeof(com_list[0])));
	maxcommands = NUMCMDS_START;
	for (i = 0, p2 = com_list; i < maxcommands; i++)
	    *p2++ = NULL;  /* jpn: if need to loop, might as well do it all */
    }
    else if (numcommands >= maxcommands) {
	ncl = (Char **) xmalloc((size_t) ((maxcommands + NUMCMDS_INCR) *
					  sizeof(com_list[0])));
	for (i = 0, p1 = com_list, p2 = ncl; i < numcommands; i++)
	    *p2++ = *p1++;
	for (; i < maxcommands + NUMCMDS_INCR; i++)
	    *p2++ = NULL;
	xfree((ptr_t) com_list);
	com_list = ncl;
#ifdef COMMENT
	com_list = (Char **) xrealloc(com_list, (maxcommands +
				     NUMCMDS_INCR) * sizeof(com_list[0]));
#endif
	maxcommands += NUMCMDS_INCR;
    }

    if (name[0] == '.')
	return;			/* no dot commands... */
    if (name[0] == '#')
	return;			/* no Emacs buffer checkpoints */

    length = Strlen(name) + 1;

    if (name[length - 2] == '~')
	return;			/* and no Emacs backups either */

    com_list[numcommands] = (Char *) xmalloc((size_t) (length *
							   sizeof(Char)));

    copyn(com_list[numcommands], name, MAXNAMLEN);
    numcommands++;
}

void
tw_builtins_add()
{
    register struct biltins *bptr;

    for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
	if (bptr->bname)
	    tw_comm_name_add(str2short(bptr->bname));
    }
}

void
tw_aliases_add()
{
    register struct varent *p;
    register struct varent *c;

    p = &aliases;
    for (;;) {
	while (p->v_left)
	    p = p->v_left;
x:
	if (p->v_parent == 0)	/* is it the header? */
	    return;
	if (p->v_name)
	    tw_comm_name_add(p->v_name);
	if (p->v_right) {
	    p = p->v_right;
	    continue;
	}
	do {
	    c = p;
	    p = p->v_parent;
	} while (p->v_right == c);
	goto x;
    }

}

struct varent *
tw_shell_list_start()
{
    register struct varent *p;
    register struct varent *c;

    p = &shvhed;		/* start at beginning of variable list */

    for (;;) {
	while (p->v_left)
	    p = p->v_left;
x:
	if (p->v_parent == 0)	/* is it the header? */
	    return (NULL);
	if (p->v_name)
	    return (p);		/* found first one */
	if (p->v_right) {
	    p = p->v_right;
	    continue;
	}
	do {
	    c = p;
	    p = p->v_parent;
	} while (p->v_right == c);
	goto x;
    }
}

Char   *
tw_n_shell_var(vptr)
    struct varent **vptr;
{
    register struct varent *p;
    register struct varent *c;
    register Char *cp;

    if ((p = *vptr) == NULL)
	return (NULL);		/* just in case */

    cp = p->v_name;		/* we know that this name is here now */

    /* now find the next one */
    for (;;) {
	if (p->v_right) {	/* if we can go right */
	    p = p->v_right;
	    while (p->v_left)
		p = p->v_left;
	}
	else {			/* else go up */
	    do {
		c = p;
		p = p->v_parent;
	    } while (p->v_right == c);
	}
	if (p->v_parent == 0) {	/* is it the header? */
	    *vptr = NULL;
	    return (cp);
	}
	if (p->v_name) {
	    *vptr = p;		/* save state for the next call */
	    return (cp);
	}
    }

}

Char  **
tw_env_list_start()
{
    return (STR_environ);
}

Char   *
Getenv(str)
    Char   *str;
{
    Char  **var;
    int     len, res;

    len = Strlen(str);
    for (var = STR_environ; var != NULL && *var != NULL; var++)
	if ((*var)[len] == '=') {
	    (*var)[len] = '\0';
	    res = StrQcmp(*var, str);
	    (*var)[len] = '=';
	    if (res == 0)
		return (&((*var)[len + 1]));
	}
    return (NULL);
}

Char   *
tw_n_env_var(evp)
    Char ***evp;
{
    static Char buffer[MAXVARLEN + 1];
    Char   *ps, *pd;

    if (*evp == NULL || **evp == NULL)
	return (NULL);
    for (ps = **evp, pd = buffer;
	 *ps && *ps != '=' && pd <= &buffer[MAXVARLEN]; *pd++ = *ps++);
    *pd = '\0';
    (*evp)++;
    return (buffer);
}
