/*	$NetBSD: stree.c,v 1.15 2009/10/17 22:26:13 christos Exp $	*/

/*
 * Copyright (c) 1992 Carnegie Mellon University
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */
/*
 * stree.c -- SUP Tree Routines
 *
 **********************************************************************
 * HISTORY
 * Revision 1.4  92/08/11  12:06:32  mrt
 * 	Added copyright. Delinted
 * 	[92/08/10            mrt]
 *
 *
 * Revision 1.3  89/08/15  15:30:57  bww
 * 	Changed code in Tlookup to Tsearch for each subpart of path.
 * 	Added indent formatting code to Tprint.
 * 	From "[89/06/24            gm0w]" at CMU.
 * 	[89/08/15            bww]
 *
 * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
 *	Added code to please lint.
 *
 * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
 *	Added code to initialize new fields.  Added Tfree routine.
 *
 * 27-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
 *	Created.
 *
 **********************************************************************
 */

#include <sys/param.h>
#include <assert.h>
#include "supcdefs.h"
#include "supextern.h"
#include "libc.h"
#include "c.h"

static TREE *Tmake(const char *);
static TREE *Trotll(TREE *, TREE *);
static TREE *Trotlh(TREE *, TREE *);
static TREE *Trothl(TREE *, TREE *);
static TREE *Trothh(TREE *, TREE *);
static void Tbalance(TREE **);
static TREE *Tinsertavl(TREE **, const char *, int, int *);
static int Tsubprocess(TREE *, int, int (*f) (TREE *, void *), void *);
static int Tprintone(TREE *, void *);


/*************************************************************
 ***    T R E E   P R O C E S S I N G   R O U T I N E S    ***
 *************************************************************/

void
Tfree(TREE ** t)
{
	if (*t == NULL)
		return;
	Tfree(&((*t)->Tlink));
	Tfree(&((*t)->Texec));
	Tfree(&((*t)->Tlo));
	Tfree(&((*t)->Thi));
	if ((*t)->Tname)
		free((*t)->Tname);
	if ((*t)->Tuser)
		free((*t)->Tuser);
	if ((*t)->Tgroup)
		free((*t)->Tgroup);
	free(*(char **) t);
	*t = NULL;
}

static TREE *
Tmake(const char *p)
{
	TREE *t;
	t = (TREE *) malloc(sizeof(TREE));
	if (t == NULL)
		goaway("Cannot allocate memory");
	t->Tname = (p == NULL) ? NULL : estrdup(p);
	t->Tflags = 0;
	t->Tuid = 0;
	t->Tgid = 0;
	t->Tuser = NULL;
	t->Tgroup = NULL;
	t->Tmode = 0;
	t->Tctime = 0;
	t->Tmtime = 0;
	t->Tlink = NULL;
	t->Texec = NULL;
	t->Tbf = 0;
	t->Tlo = NULL;
	t->Thi = NULL;
	return (t);
}

static TREE *
Trotll(TREE * tp, TREE * tl)
{
	tp->Tlo = tl->Thi;
	tl->Thi = tp;
	tp->Tbf = tl->Tbf = 0;
	return (tl);
}

static TREE *
Trotlh(TREE * tp, TREE * tl)
{
	TREE *th;

	th = tl->Thi;
	tp->Tlo = th->Thi;
	tl->Thi = th->Tlo;
	th->Thi = tp;
	th->Tlo = tl;
	tp->Tbf = tl->Tbf = 0;
	if (th->Tbf == 1)
		tp->Tbf = -1;
	else if (th->Tbf == -1)
		tl->Tbf = 1;
	th->Tbf = 0;
	return (th);
}

static TREE *
Trothl(TREE * tp, TREE * th)
{
	TREE *tl;

	tl = th->Tlo;
	tp->Thi = tl->Tlo;
	th->Tlo = tl->Thi;
	tl->Tlo = tp;
	tl->Thi = th;
	tp->Tbf = th->Tbf = 0;
	if (tl->Tbf == -1)
		tp->Tbf = 1;
	else if (tl->Tbf == 1)
		th->Tbf = -1;
	tl->Tbf = 0;
	return (tl);
}

static TREE *
Trothh(TREE * tp, TREE * th)
{
	tp->Thi = th->Tlo;
	th->Tlo = tp;
	tp->Tbf = th->Tbf = 0;
	return (th);
}

static void
Tbalance(TREE ** t)
{
	if ((*t)->Tbf < 2 && (*t)->Tbf > -2)
		return;
	if ((*t)->Tbf > 0) {
		if ((*t)->Tlo->Tbf > 0)
			*t = Trotll(*t, (*t)->Tlo);
		else
			*t = Trotlh(*t, (*t)->Tlo);
	} else {
		if ((*t)->Thi->Tbf > 0)
			*t = Trothl(*t, (*t)->Thi);
		else
			*t = Trothh(*t, (*t)->Thi);
	}
}

static TREE *
Tinsertavl(TREE ** t, const char *p, int find, int *dh)
{
	TREE *newt;
	int cmp;
	int deltah;

	if (*t == NULL) {
		*t = Tmake(p);
		*dh = 1;
		return (*t);
	}
	if ((cmp = strcmp(p, (*t)->Tname)) == 0) {
		if (!find)
			return (NULL);	/* node already exists */
		*dh = 0;
		return (*t);
	} else if (cmp < 0) {
		if ((newt = Tinsertavl(&((*t)->Tlo), p, find, &deltah)) == NULL)
			return (NULL);
		(*t)->Tbf += deltah;
	} else {
		if ((newt = Tinsertavl(&((*t)->Thi), p, find, &deltah)) == NULL)
			return (NULL);
		(*t)->Tbf -= deltah;
	}
	Tbalance(t);
	if ((*t)->Tbf == 0)
		deltah = 0;
	*dh = deltah;
	return (newt);
}

TREE *
Tinsert(TREE ** t, const char *p, int find)
{
	int deltah;

	if (p != NULL && p[0] == '.' && p[1] == '/') {
		p += 2;
		while (*p == '/')
			p++;
		if (*p == 0)
			p = ".";
	}
	return (Tinsertavl(t, p, find, &deltah));
}

TREE *
Tsearch(TREE * t, const char *p)
{
	TREE *x;
	int cmp;

	x = t;
	while (x) {
		cmp = strcmp(p, x->Tname);
		if (cmp == 0)
			return (x);
		if (cmp < 0)
			x = x->Tlo;
		else
			x = x->Thi;
	}
	return (NULL);
}

TREE *
Tlookup(TREE * t, const char *p)
{
	TREE *x;
	char buf[MAXPATHLEN + 1];
	char *q;

	if (p == NULL)
		return (NULL);
	if (p[0] == '.' && p[1] == '/') {
		p += 2;
		while (*p == '/')
			p++;
		if (*p == 0)
			p = ".";
	}
	if ((x = Tsearch(t, p)) != NULL)
		return (x);
	if (*p != '/' && (x = Tsearch(t, ".")) != NULL)
		return (x);
	(void) strncpy(buf, p, sizeof(buf) - 1);
	buf[MAXPATHLEN] = '\0';
	while ((q = strrchr(buf, '/')) != NULL) {
		while (q >= buf && *(q - 1) == '/')
			q--;
		if (q == buf)
			*(q + 1) = '\0';
		else
			*q = '\0';
		if ((x = Tsearch(t, buf)) != NULL)
			return (x);
		if (q == buf)
			break;
	}
	return (NULL);
}

static int process_level;

static int
Tsubprocess(TREE * t, int reverse, int (*f) (TREE *, void *), void *argp)
{
	int x = SCMOK;
	process_level++;
	if (reverse ? t->Thi : t->Tlo)
		x = Tsubprocess(reverse ? t->Thi : t->Tlo,
		    reverse, f, argp);
	if (x == SCMOK) {
		x = (*f) (t, argp);
		if (x == SCMOK) {
			if (reverse ? t->Tlo : t->Thi)
				x = Tsubprocess(reverse ? t->Tlo : t->Thi,
				    reverse, f, argp);
		}
	}
	process_level--;
	return (x);
}

/* VARARGS2 */
int
Trprocess(TREE * t, int (*f) (TREE *, void *), void *args)
{
	if (t == NULL)
		return (SCMOK);
	process_level = 0;
	return (Tsubprocess(t, TRUE, f, args));
}

/* VARARGS2 */
int
Tprocess(TREE * t, int (*f) (TREE *, void *), void *args)
{
	if (t == NULL)
		return (SCMOK);
	process_level = 0;
	return (Tsubprocess(t, FALSE, f, args));
}

static int 
/*ARGSUSED*/
Tprintone(TREE * t, void *v __unused)
{
	int i;
	for (i = 0; i < (process_level * 2); i++)
		(void) putchar(' ');
	printf("Node at %p name '%s' flags %o hi %p lo %p\n", t, t->Tname, t->Tflags, t->Thi, t->Tlo);
	return (SCMOK);
}

void
Tprint(TREE * t, char *p)
{				/* print tree -- for debugging */
	printf("%s\n", p);
	(void) Tprocess(t, Tprintone, NULL);
	printf("End of tree\n");
	(void) fflush(stdout);
}
