/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1989-2006 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                  David Korn <dgk@research.att.com>                   *
*                   Eduardo Krell <ekrell@adexus.cl>                   *
*                                                                      *
***********************************************************************/
#pragma prototyped

#include "3d.h"

/*
 * get next view for path sp
 */

char*
pathnext(char* sp, char* extra, long* visits)
{
	register char*	ep = sp + strlen(sp);
	register char*	cp;
	register char*	tmp;
	register int	shift;
	Map_t*		vpath;
	int		vpathlen;

	message((-4, "pathnext: ++ %s%s%s [0x%08x]", sp, extra ? " + " : state.null, extra ? extra : state.null, visits ? *visits : 0L));

	/*
	 * check for next layer and previous visit
	 */

	if (state.path.level + 1 >= state.limit)
	{
		message((-4, "pathnext: -- %s [limit=%d]", NiL, state.limit));
		return 0;
	}
	ep = sp + (shift = strlen(sp));
	if (!(vpath = search(state.path.table ? state.path.table : &state.vpath, sp, shift, (const char*)visits, T_PREFIX)))
	{
		message((-4, "pathnext: -- %s [0x%08x]", NiL, visits ? *visits : 0L));
		return 0;
	}

	/*
	 * we found a viewpath entry
	 * check if stuff after extra needs to be shifted
	 */

	vpathlen = T_VALSIZE(vpath);
	cp = sp + vpath->keysize;
	shift = vpathlen - (cp - sp);
	if (shift < 0)
	{
		/*
		 * shift left
		 */

		if (cp < ep) strcpy(sp + vpathlen + 1, cp + 1);
	}
	else if (shift > 0)
	{
		/*
		 * shift right extra
		 */

		if (extra)
		{
			for (tmp = extra + strlen(extra); tmp >= extra; tmp--)
				tmp[shift] = *tmp;
			extra += shift;
		}

		/*
		 * shift right cp
		 */

		if (cp < ep)
		{
			for (tmp = ep; tmp > cp; tmp--)
				tmp[shift] = *tmp;
			strcpy(sp + vpathlen + 1, cp + shift + 1);
		}
	}

	/*
	 * insert vpath
	 */

	strncpy(sp, vpath->val, vpathlen);
	sp[vpathlen] = cp < ep ? '/' : 0;
	cp = sp;
	if (extra)
		strcpy(sp = ep + shift, extra);
	state.path.level++;
	message((-4, "pathnext: -- %s [level=%d visits=0x%08x]", cp, state.path.level, visits ? *visits : 0L));
	return sp;
}

/*
 * search for the instance name for path sp
 * and place in instname
 * 0 returned when instances exhausted
 * if create is non-zero, use name before the first slash as instance
 * name, and do not check existence.
 */

int
instance(register char* sp, char* instname, struct stat* st, int create)
{
	register char*	cp;
	register char*	mp;
	register char*	mapnext;
	register int	size;
	int		maps;
	char*		mapend;
	Map_t*		map;

	cp = instname++;
	mapnext = mapend = 0;
	maps = 0;
	if (state.vmap.size)
	{
		while (*--cp != '/');
		if (!create) cp -= 4;
	}
	else cp = sp;
	for (;;)
	{
		if ((mp = mapnext) >= mapend)
		{
			/*
			 * look for next vmap
			 */

			while (cp > sp)
			{
				map = search(&state.vmap, sp, cp - sp, NiL, 0);
				if (cp > sp + 1)
				{
					while (*--cp != '/');
					while (cp > sp && cp[-1] == '/') cp--;
					if (cp == sp) cp++;
				}
				else cp = sp;
				if (map && (!create || *map->val != '/'))
					goto match;
			}
			if (!create)
			{
				strcpy(instname, state.vdefault);
				maps++;
				if (!LSTAT(sp, st))
					goto found;
			}
			return 0;
		match:
			mp = map->val;
			size = T_VALSIZE(map);
			mapend = mp + size;
			if (create)
			{
				while (mp < mapend && *mp!='/') mp++;
				if ((size = mp - map->val) <= 0)
					return 0;
				memcpy(instname, map->val, size);
				instname[size] = 0;
				maps++;
				goto found;
			}
			if (*mp == '/') mp++;
		}
		for (mapnext = mp; mapnext < mapend; mapnext++)
			if (*mapnext == '/')
				break;
		if ((size = mapnext - mp) <= 0) continue;
		memcpy(instname, mp, size = mapnext - mp);
		instname[size] = 0;
		while (mapnext < mapend && *mapnext == '/') mapnext++;
		maps++;
		if (!LSTAT(sp, st))
			goto found;
	}
	/*NOTREACHED*/
 found:
	if (maps > 1)
		state.path.level |= INSTANCE;
	return 1;
}
