/*
* This file is part of SkunkDB
* Copyright (c) 2001 Gianni Tedesco
*
*    SkunkDB is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    SkunkDB is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with SkunkDB; if not, write to the Free Software
*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/


#include <skunk_app.h>
#include <skunk_hash.h>
#include <skunk_make.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>

#define MAKE_FSYNC
#define MAKE_CLEAN

int ifd;
struct stat st;
char *map=NULL;
int read_input(p_skunkwr);

int read_input(p_skunkwr sdb)
{
	char *cur;
	int state=0;
	char *key=NULL, *val=NULL;
	skunk_ofs_t klen=0, vlen=0;
	
	for (cur=map; (long)cur < ((long)map)+st.st_size; cur++) {
		switch ( state ) {
			case 0:
				key=cur;
				val=NULL;
				klen=0;
				vlen=0;
				state=1;
				break;
			case 1:
				if ( *cur == ':' ) {
					state=2;
					val=++cur;
				}
				klen++;
				break;
			case 2:
				vlen++;
				if ( *cur == '\n' ) {
					if ( !make_add(sdb, key, val, klen, vlen) ) return 0;
					state=0;
				}
		}
	}

	return 1;
}

int main ( int argc, char **argv ) 
{
	int fd, err=SKUNK_OK;
	skunkwr_t sdb;

	/* Check arguments */
	if ( argc < 3 ) {
		printf("Usage: %s <input_file> <output_file>\n", argv[0]);
		return SKUNK_ERR;
	}

	/* Open output file */
	if ( (fd=open(argv[2], O_CREAT|O_TRUNC|O_WRONLY, 0600))<0) {
		perror("open");
		return SKUNK_ERR;
	}

	/* Open input file */
	if ( (ifd=open(argv[1], O_RDONLY)) < 0 ) {
		perror("open");
		close(fd);
		return SKUNK_ERR;
	}

	/* Find size of input file */
	if ( (fstat(ifd, &st)) < 0 ) {
		perror("fstat");
		close(ifd);
		close(fd);
		return SKUNK_ERR;
	}

	/* Memory map input file */
	if ( !(map=mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, ifd, 0)) ) {
		perror("mmap");
		close(ifd);
		close(fd);
		return SKUNK_ERR;
	}

	/* Make the DB */
	if ( !make_init(&sdb, fd, SKUNK_BUFFER) ) {
		fprintf(stderr, "make_init() failed\n");
		return SKUNK_ERR;
	}
	
	/* Read the data */
	printf("Reading input...\n");
	if ( !read_input(&sdb) ) {
		fprintf(stderr, "read_input() failed\n");
		return SKUNK_ERR;
	}
	
	/* Write the DB out */
	printf("Writing DB...\n");
	if ( !make_write(&sdb) ) {
		fprintf(stderr, "make_write() failed\n");
		return SKUNK_ERR;
	}

#ifdef MAKE_CLEAN
	printf("Cleaning up...\n");
	make_close(&sdb);
#endif

#ifdef MAKE_FSYNC
	printf("Syncing to disc...\n");
	
	/* make sure data gets written to disk */
	if ( fsync(fd) ) {
		perror("fsync");
		return SKUNK_ERR;
	}
#endif

	/* some filesystems can report that
	* write() succeeded when it really didn't
	* and the way they let us know is to fail
	* on close() */
	if ( close(fd) ) {
		perror("close");
		return SKUNK_ERR;
	}

	/* Close input file */
	munmap(map, st.st_size);
	close(ifd);
	return err;
}
