/*$Id: parserow.c,v 1.29 1999/10/07 12:02:54 jens Exp $*/
/*
 * Copyright (c) 1997, 1998, 1999
 *      Jens A. Nilsson, jnilsson@ludd.luth.se. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
 */


#ifdef MEMDEBUG
#include <memdebug.h>
#endif

#include <ctype.h>
#ifdef ULTRIX
#include <sys/types.h>
#endif
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef __NetBSD__
#	include <tzfile.h>
#else
#	ifndef SECSPERMIN
#		define SECSPERMIN 60
#	endif
#	ifndef SECSPERDAY
#		define SECSPERDAY	((long) 60 * 60 * 24)
#	endif
#	ifndef DAYSPERNYEAR
#		define DAYSPERNYEAR 365
#	endif
#endif
#include "strlcpy.h"
#include "parserow.h"
#include "spegla.h"

#ifdef NOPROTOS
char	*strdup(char *);
#endif

static int
parse_file_mode(char *p, struct sp_file *spf)
{
#define ADVANCE(n)	if (*(++(n)) == '\0') return 0

	if (p == NULL || *p == '\0')
		return 0;
	switch (*p) {
	case '-':
		spf->spf_type = PLAINFILE;
		break;
	case 'd':
		spf->spf_type = DIRECTORY;
		break;
	case 'l':
		spf->spf_type = SYMLINK;
		break;
	default:
		return 0;
	}
	ADVANCE(p);
	switch (*p) {
	case 'r':
		spf->spf_mode |= S_IRUSR;
		break;
	case '-':
		break;
	default:
		return 0;
	}
	ADVANCE(p);
	switch (*p) {
	case 'w':
		spf->spf_mode |= S_IWUSR;
		break;
	case '-':
		break;
	default:
		return 0;
	}
	ADVANCE(p);
	switch (*p) {
	case 'x':
		spf->spf_mode |= S_IXUSR;
		break;
	case 's':
		spf->spf_mode |= S_IXUSR | S_ISUID;
		break;
	case 'S':
		spf->spf_mode |= S_ISUID;
		break;
	case '-':
		break;
	default:
		return 0;
	}
	ADVANCE(p);
	switch (*p) {
	case 'r':
		spf->spf_mode |= S_IRGRP;
		break;
	case '-':
		break;
	default:
		return 0;
	}
	ADVANCE(p);
	switch (*p) {
	case 'w':
		spf->spf_mode |= S_IWGRP;
		break;
	case '-':
		break;
	default:
		return 0;
	}
	ADVANCE(p);
	switch (*p) {
	case 'x':
		spf->spf_mode |= S_IXGRP;
		break;
	case 's':
		spf->spf_mode |= S_IXGRP | S_ISGID;
		break;
	case 'S':
		spf->spf_mode |= S_ISGID;
		break;
	case '-':
		break;
	default:
		return 0;
	}
	ADVANCE(p);
	switch (*p) {
	case 'r':
		spf->spf_mode |= S_IROTH;
		break;
	case '-':
		break;
	default:
		return 0;
	}
	ADVANCE(p);
	switch (*p) {
	case 'w':
		spf->spf_mode |= S_IWOTH;
		break;
	case '-':
		break;
	default:
		return 0;
	}
	ADVANCE(p);
	switch (*p) {
	case 'x':
		spf->spf_mode |= S_IXOTH;
		break;
	case 't':
		spf->spf_mode |= S_IXOTH | S_ISVTX;
		break;
	case 'T':
		spf->spf_mode |= S_ISVTX;
		break;
	case '-':
		break;
	default:
		return 0;
	}
	return 1;
#undef ADVANCE
}

struct sp_file *
parse_row(char *row)
{
	struct	sp_file *spf;
	char	*slusk, *endptr;
	char	tmp[PATH_MAX + 24];
	char	*tok, toksep[] = " ";
	struct	tm tiden;
	time_t	now;
	int		i, maybe_size;
	int		rowlen;
	long	size;
	static	const char *months[] = {
		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
	};

	maybe_size = 0;
	rowlen = (int)strlen(row);
	if (rowlen < (sizeof(tmp) - 1)) {
		(void) strlcpy(tmp, row, (size_t)(PATH_MAX + 24));
		row = tmp;
	}

	spf = calloc((size_t)1, sizeof(struct sp_file));
	if (spf == NULL)
		return NULL;

	/* permissions */
	if ((tok = strtok(row, toksep)) == NULL)
		goto ret_bad;

	if (!parse_file_mode(tok, spf))
		goto ret_bad;

	/* link count */
	tok = strtok(NULL, toksep);

	/* group or user */
	tok = strtok(NULL, toksep);

	/* group or size */
	if ((tok = strtok(NULL, toksep)) == NULL)
		goto ret_bad;

	size = strtol(tok, &endptr, 10); /* atoi */
	if (*endptr == ' ' || *endptr == '\0')
		maybe_size = 1;

	/* size or month */
	if ((tok = strtok(NULL, toksep)) == NULL)
		goto ret_bad;

	spf->spf_size = strtol(tok, &endptr, 10); /* atoi */
	if (*endptr == ' ' || *endptr == '\0') {
		/* this was size, advance to month */
		if ((tok = strtok(NULL, toksep)) == NULL)
			goto ret_bad;
	} else {
		/* if we didn't get anything looking like size before,
		 * we're in trouble
		 */
		if (!maybe_size)
			goto ret_bad;
		spf->spf_size = size;
	}

	for (i = 0; i < 12; i++) {
		if (strcmp(tok, months[i]) == 0)
			break; /* we're done */
	}
	if (i == 12)
		goto ret_bad;	/* didn't find any month */

	tiden.tm_mon = i;

	 /* Day */ ;
	if ((tok = strtok(NULL, toksep)) == NULL)
		goto ret_bad;
	if (sscanf(tok, "%d", &tiden.tm_mday) != 1)
		goto ret_bad;

	/* Year */
	if ((tok = strtok(NULL, toksep)) == NULL)
		goto ret_bad;
	spf->spf_tgranul = 0;
	switch (sscanf(tok, "%d:%d:%d", &tiden.tm_hour, &tiden.tm_min, &tiden.tm_sec)) {
	case 1:
		tiden.tm_year = tiden.tm_hour;
		tiden.tm_hour = tiden.tm_min = tiden.tm_sec = 0;
		spf->spf_tgranul = SECSPERDAY;
		break;
	case 2:
		tiden.tm_sec = 0;
		spf->spf_tgranul = SECSPERMIN;
		now = time(NULL);
		tiden.tm_year = localtime(&now)->tm_mon < tiden.tm_mon ?
		    localtime(&now)->tm_year - 1 :
		    localtime(&now)->tm_year;
		break;
	case 3:
		if ((tok = strtok(NULL, toksep)) == NULL)
			goto ret_bad;
		if (sscanf(tok, "%d", &tiden.tm_year) != 1) {
			now = time(NULL);
			tiden.tm_year = localtime(&now)->tm_mon < tiden.tm_mon ?
			    localtime(&now)->tm_year - 1 :
			    localtime(&now)->tm_year;
		}
		break;
	default:
		goto ret_bad;
	}
	if (tiden.tm_year >= 1900)
		tiden.tm_year -= 1900;
	tiden.tm_wday = 0;
	tiden.tm_yday = 0;
	tiden.tm_isdst = -1;	/* viktigt, annars blir det konstigt! */
	spf->spf_time = mktime(&tiden);

	for (i = 0; tok[i] != ' ' && tok[i] != '\0'; i++)
		if (tok + i == row + rowlen)
			break;
	tok += i + 1;
	if (tok == row + rowlen)
		goto ret_bad;

	/* filename */
	if ((spf->spf_type == DIRECTORY) && (tok[strlen(tok) - 1] == '/'))
		tok[strlen(tok) - 1] = '\0';
	if ((spf->spf_mode | S_IXUSR | S_IXGRP | S_IXOTH) &&
	    (tok[strlen(tok) - 1] == '*')) {
		tok[strlen(tok) - 1] = '\0';
	}
	if (spf->spf_type == SYMLINK) {
		if ((slusk = strstr(tok, " -> ")) == NULL)
			goto ret_bad;
		slusk[0] = '\0';
		spf->spf_name = strdup(tok);
		if (spf->spf_name[strlen(spf->spf_name)] == '@')
			spf->spf_name[strlen(spf->spf_name)] = '\0';
		slusk += 4;
		spf->spf_symlink = strdup(slusk);
	} else {
		spf->spf_name = strdup(tok); /* should get eventual spaces */
	}
	return spf;

ret_bad:
	if (spf->spf_name != NULL)
		free(spf->spf_name);
	if (spf->spf_symlink != NULL)
		free(spf->spf_symlink);
	free(spf);
	return NULL;
}


syntax highlighted by Code2HTML, v. 0.9.1