#if !defined(lint) && !defined(SABER)
static char rcsid[] = "$Id: file.c,v 1.2 1992/05/09 22:57:59 epeisach Exp $";
#endif

#include "mkserv.h"

/* This file deals with processing headers of files and
 * other file manipulation required by mkserv 
 */

static get_file_header_magic(char *buf, char *match, 
				   char **entry,
				   int num_only)
{
	char *p, *p1;
	if((p = find_in_string(match, buf)) != NULL) {
		/* We have a revision string. */
		/* Remove any spaces.... */
		p+=strlen(match);
		while(isspace(*p)) p++;
		/* p now pointing to beginning of string... */
		/* Count up length... */
		p1 = p;
		if(num_only) {
			while(isdigit(*p1) || (*p1 == '.')) p1++;
		} else {
			while(isalnum(*p1) || ispunct(*p1)) p1++;
		}
		*p1 = '\0';
		if (p1 - p == 0) {
			/* No version number */ 
			return 0;
		}
		if(*entry) {
			free(*entry);
			*entry = NULL;
		}
			
		*entry = strdup(p);
		if(*entry == NULL) {
			fprintf(stderr, "Out of memory in get_file_header\n");
			return -1;
		}
	}
	return 0;
}

/* 
 * get_file_header(char *filename, struct file_header *fh);
 * Opens filename and reads the data
 * Returns -1 on failure 
 * Returns 0 on success
 */
get_file_header(char *filename, struct file_header * fh)
{
	FILE *f;
	char buf[BUFSIZ];

	free_header(fh);

	/* lose performance, but can profile open's/close */
	if(access(filename, R_OK)) return -1; 

	if((f = fopen(filename, "r")) == NULL) {
		return -1;
	}

	while(fgets(buf, BUFSIZ, f) != NULL) {
		if(get_file_header_magic(buf, "$Revision:", &(fh->version), 1)) {
			fclose(f);
			return -1;
		}
		if(get_file_header_magic(buf, "$Platforms:", &(fh->platforms), 0)) {
			fclose(f);
			return -1;
		}
		if(get_file_header_magic(buf, "$Options:", &(fh->options), 0)) {
			fclose(f);
			return -1;
		}

	}

	fclose(f);
	return 0;
}
	
void free_header(struct file_header *fh)
{
	if(fh->version) {
		free(fh->version);
		fh->version = NULL;
	}

	if(fh->platforms) {
		free(fh->platforms);
		fh->platforms = NULL;
	}
	if(fh->options) {
		free(fh->options);
		fh->options = NULL;
	}
}

/*
 * copy_file(from, to)
 *	copy from one file to another
 *	Keeps mode, owner, and utimes same
 * Returns:
 *	0 if successsful
 *	-1 if failure
 * If copying fails, destination will be unlinked
 */
#ifndef MAXBSIZE
#define MAXBSIZE 10240
#endif

copy_file(char *from_name, char *to_name)
{
	register int from_fd, to_fd;
	register int n;
	char buf[MAXBSIZE];
	struct stat sbuf;
	struct timeval timep[2];

	if((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
		sprintf(buf, "copy_file: In opening %s\n", from_name);
		perror(buf);
		return -1;
	}

	if(fstat(from_fd, &sbuf)) {
		sprintf(buf, "copy_file: In stating %s\n", from_name);
		perror(buf);	
		close(from_fd);
		return -1;
	}

	(void) unlink(to_name);
	if((to_fd = open(to_name, O_WRONLY|O_TRUNC|O_CREAT, 0777)) < 0) {
		sprintf(buf, "copy_file: In opening %s for write", from_name);
		perror(buf);
		close(from_fd);
		return -1;
	}

	n = copy_data(from_fd, to_fd);

	if(close(from_fd) || close(to_fd)) {
		sprintf(buf, "In closing: %s", to_name);
		perror(buf);
	}

	if(n) {
		/* Error case */
		(void) unlink(to_name);
		return -1;
	}

	timep[0].tv_sec = sbuf.st_atime;
	timep[1].tv_sec = sbuf.st_mtime;
	timep[0].tv_usec = timep[1].tv_usec = 0;

	if(utimes(to_name, timep)) {
		sprintf(buf, "In setting times: %s", to_name);
		perror(buf);
		return -1;
	}
	
	if(chmod(to_name, sbuf.st_mode & 07777)) {
		sprintf(buf, "chmod: %s", to_name);
		perror(buf);
		return -1;
	}
	return 0;
}

/* 
 * copy_data(int from_fd, int to_fd)
 * 	Copies the data
 *	Returns 0 on success
 *		-1 on failure
 */
copy_data(int from_fd, int to_fd) 
{
	register int n;
	char buf[MAXBSIZE];

	while ((n = read(from_fd, buf, sizeof(buf))) > 0)
		if (write(to_fd, buf, n) != n) {
			perror("write");
			return -1;
		}
	if (n == -1) {
		perror("read");
		return -1;
	} 
	return 0;
}	

/* tail_file(char *name, char *buf, int bsize)
 * Returns with last line in file to buf 
 * Return status:
 *	0 - success
 *	errno - failure reason 
 * Assumptions:
 *	buf is at least BUFSIZE in length
 */

tail_file(char *name, char *buf)
{
	FILE *f;
	char b[BUFSIZ];

	if((f = fopen(name, "r")) == NULL) return errno;
	bzero(b, BUFSIZ);

	while(fgets(b, BUFSIZ, f) != NULL) {
		/* Very inefficient but works */
		bcopy(b, buf, BUFSIZ);
	}

	(void) fclose(f);
	return 0;
}

/* Will not append a new line */
append_file(char *name, char *line)
{
       FILE *f;

       if((f = fopen(name, "a")) == NULL) {
	       fprintf(stderr, "Could not append to %s\n", name);
	       return -1;
       }
       fprintf(f, "%s", line);
       fclose(f);
       return 0;
}
