/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 2002-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>                   *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * local archive format method
 */

#include <ardirlib.h>
#include <ctype.h>
#include <tm.h>

#define SYMDIR_local	"(._|_.|__.|___|*/)*"

typedef struct State_s			/* method state			*/
{
	Sfio_t*		sp;		/* sfpopen() stream		*/
	unsigned long	count;		/* member count			*/
} State_t;

/*
 * closef
 */

static int
localclose(Ardir_t* ar)
{
	State_t*	state;
	int		r;

	if (!ar || !(state = (State_t*)ar->data))
		r = -1;
	else
	{
		if (!state->sp || sfclose(state->sp))
			r = -1;
		else
			r = 0;
		free(state);
	}
	return r;
}

/*
 * openf
 */

static int
localopen(Ardir_t* ar, char* buf, size_t n)
{
	State_t*	state;
	char*		cmd;
	int		c;

	if (!(ar->flags & ARDIR_LOCAL))
		return -1;
	if (!(state = newof(0, State_t, 1, 0)))
		return -1;
	ar->data = (void*)state;
	cmd = sfprints("${ARDIR:-ar} ${ARDIRFLAGS:-tv} '%s' 2>/dev/null", ar->path);
	if (!(state->sp = sfpopen(NiL, cmd, "r")) || (c = sfgetc(state->sp)) == EOF || sfungetc(state->sp, c) == EOF)
	{
		localclose(ar);
		return -1;
	}
	return 0;
}

/*
 * nextf
 */

static Ardirent_t*
localnext(Ardir_t* ar)
{
	State_t*	state = (State_t*)ar->data;
	register char*	s;
	register char*	t;
	char*		e;
	int		n;

	while (s = sfgetr(state->sp, '\n', 1))
	{
		/*
		 * assume ``junk Mmm ... member''
		 */

		if (!(t = strrchr(s, ' ')))
			continue;
		*t++ = 0;
		if (state->count++ || !strmatch(t, SYMDIR_local))
			while (s = strchr(s, ' '))
			{
				if (isupper(*++s) && islower(s[1]) && islower(s[2]) && s[3] == ' ')
				{
					ar->dirent.mtime = tmdate(s, &e, NiL);
					if (!*e)
					{
						if ((n = strlen(t)) > ar->truncate)
							ar->truncate = n;
						break;
					}
				}
				else
					ar->dirent.size = strtoul(s, NiL, 10);
			}
		ar->dirent.name = t;
		ar->dirent.uid = ar->st.st_uid;
		ar->dirent.gid = ar->st.st_gid;
		ar->dirent.mode = ar->st.st_mode;
		ar->dirent.offset = -1;
		return &ar->dirent;
	}
	if (sferror(state->sp))
		ar->error = errno;
	return 0;
}

Ardirmeth_t ar_local =
{
	"local",
	"local ar archive",
	localopen,
	localnext,
	0,
	0,
	0,
	localclose,
	ar_local_next
};
