/*
 * DILOAD.C	
 *
 *	Add records to the history database given information on stdin
 *	in the 'didump' format.  Generally used to recover or transfer
 *	a history file between two machines.
 *
 *	To recover a blown up history file:
 *
 *		rm -f dhistory.new
 *		didump dhistory | diload -f dhistory.new
 *		if ( $status == 0) then
 *		    mv -f dhistory.new dhistory
 *		endif
 *
 *	To transfer between machines:
 *
 *		rm -f dhistory.new
 *		rsh remote -n "/news/dbin/didump /news/dhistory" | \
 *		    diload -f dhistory.new
 *		if ( $status == 0) then
 *		    mv -f dhistory.new dhistory
 *		endif
 *
 * (c)Copyright 1997, Matthew Dillon, All Rights Reserved.  Refer to
 *    the COPYRIGHT file in the base directory of this distribution 
 *    for specific rights granted.
 */

#include "defs.h"

int HistoryEntryValid(History *h);

void
Usage(void)
{
    printf("Loads entries from stdin into dhistory - usually the output from didump\n\n");
    printf("Usage: diload [-f] [-h hsize] [-u] [-v] [-C diablo.config] [-d[n]] [-V] historyfile\n");
    printf("  where:\n");
    printf("\t-f\t\tfast mode - don't do any locking of history\n");
    printf("\t-h hsize\tspecify the number of entries in the hash table\n");
    printf("\t-u\t\tunconditional - override check for an existing history\n");
    printf("\t-v\t\tbe slightly more verbose and show progress\n");
    printf("\t-C file\tspecify diablo.config to use\n");
    printf("\t-d[n]\tset debug [with optional level]\n");
    printf("\t-V\tprint version and exit\n");
    exit(1);
}

int
main(int ac, char **av)
{
    int r = 1;
    int count = 0;
    int failed = 0;
    char buf[1024];
    int flags = 0;
    int uflag = 0;
    int verbose = 0;
    char *fileName = NULL;
    int totalentries = 0;

    LoadDiabloConfig(ac, av);

    {
	int i;

	for (i = 1; i < ac; ++i) {
	    char *ptr = av[i];

	    if (*ptr != '-') {
		if (fileName != NULL) {
		    fprintf(stderr, "Unexpected argument\n");
		    Usage();
		}
		fileName = ptr;
		continue;
	    }
	    ptr += 2;
	    switch(ptr[-1]) {
	    case 'f':
		flags |= HGF_FAST | HGF_NOSEARCH;
		break;
	    case 'h':
		NewHSize = strtol(((*ptr) ? ptr : av[++i]), &ptr, 0);
		if (*ptr == 'k' || *ptr == 'K')
		    NewHSize *= 1024;
		if (*ptr == 'm' || *ptr == 'M')
		    NewHSize *= 1024 * 1024;
		if ((NewHSize ^ (NewHSize - 1)) != (NewHSize << 1) - 1) {
		    fprintf(stderr, "specified history size is not a power of 2\n");
		    exit(1);
		}
		break;
	    case 'u':
		uflag = 1;
		break;
	    case 'v':
		verbose = 1;
		break;
	    /* Common options */
	    case 'C':		/* parsed by LoadDiabloConfig */
		if (*ptr == 0)
		    ++i;
		break;
	    case 'd':
		DebugOpt = 1;
		if (*ptr)
		    DebugOpt = strtol(ptr, NULL, 0);
		break;
	    case 'V':
		PrintVersion();
		break;
	    default:
		Usage();
		break;
	    }
	}
    }

    if (fileName == NULL)
	Usage();

    if (flags & HGF_FAST) {
	struct stat st;

	if (stat(fileName, &st) == 0 && uflag == 0) {
	    fprintf(stderr, "-f history files may not previously exist unless you also specify -u\n");
	    fprintf(stderr, "WARNING! -f -u is NOT suggested!\n");
	    Usage();
	}
	if (uflag)
	    flags &= ~HGF_NOSEARCH;
    }

    HistoryOpen(fileName, flags);

    while (fgets(buf, sizeof(buf), stdin) != NULL) {
	History h = { 0 };
	int n;
	int iter;
	int exp;
	char f1 = 0;

	if (buf[0] == '.') {
	    r = 0;
	    break;
	}

	n = sscanf(buf, "DUMP %x.%x.%x gm=%d ex=%d boff=%d bsize=%d flags=%c",
	    &h.hv.h1,
	    &h.hv.h2,
	    &iter,
	    &h.gmt,
	    &exp,
	    &h.boffset,		/* 0 if old style dump */
	    &h.bsize,		/* 0 if old style dump */
	    &f1			/* 0 if no flags       */
	);
	if (n >= 5) {
	    int r = 0;

	    h.iter = iter;
	    h.exp = exp;
	    if (f1 == 'H')
		h.exp |= EXPF_HEADONLY;
	    if (HistoryEntryValid(&h) < 0)
		++failed;
	    else if ((r = HistoryAdd(NULL, &h)) == 0)
		++count;
	    else if (r != RCTRYAGAIN)
		++failed;
	    else {
		fprintf(stderr, "HistoryAdd: write failed!\n");
		exit(1);
	    }
	} else if (sscanf(buf, "ENTRIES %d", &totalentries) == 1) {
	    ;
	} else {
	    fprintf(stderr, "Format error: %s", buf);
	    break;
	}
	if (verbose && ((count + failed) & 1023) == 0) {
	    if (totalentries > 0)
		printf("%d/%d/%d\r", count, count + failed, totalentries);
	    else
		printf("%d/%d\r", count, count + failed);
	    fflush(stdout);
	}
    }
    printf("diload: %d/%d entries loaded\n", count, count + failed);
    r = HistoryClose();
    if (r == RCOK)
	return(0);
    else
	return(1);
}

int
HistoryEntryValid(History *h)
{
    if (h->gmt == 0)
	return(-1);
    if (h->hv.h1 == 0 && h->hv.h2 == 0)
	return(-1);
    return(0);
}



syntax highlighted by Code2HTML, v. 0.9.1