/* Copyright 1985, Massachusetts Institute of Technology */

/* reads from standard input lines of the form:
	red green blue name
   where red/green/blue are decimal values, and inserts them in a database.
*/
#ifdef notdef
#ifndef lint
static char *rcsid_rgb_c = "$XConsortium: rgb.c,v 11.7 88/09/06 17:51:52 jim Exp $";
#endif
#endif

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>

#include "rgb.h"

static void write_it(int fd, void *ptr, unsigned short len);

/* structure to be used in file */
struct ent {
	unsigned short length;
	RGB	rgb;		/* unsigned short red, green blue; */
	char	*name;
	struct ent *next;
};

char *
SysError()
{
    return ((errno >= 0 && errno < sys_nerr) ? sys_errlist[errno] : "?");
}

char *ProgramName;
unsigned short red, green, blue;
struct ent *buckets[256];	/* 256 hash buckets */
unsigned short bucketlen[256];	/* total length of each bucket */
char line[512];
char name[512];

main(argc, argv)
int argc;
char **argv;
{
    int fd;
    char *dbname;
    struct ent *pent;
    unsigned long offs;
    int namelen;
    int items;
    int lineno;
    int i;
    unsigned char hash;

    (void)memset(bucketlen, 0, 256 * sizeof(unsigned short));
    (void)memset(buckets, 0, 256 * sizeof(struct ent *));
    ProgramName = argv[0];
    if (argc >= 2)
	dbname = argv[1];
    else
	dbname = "rgb";

    strcpy(line, dbname);
    strcat(line, ".bin");
    fd = open(line, O_TRUNC|O_WRONLY|O_CREAT|O_BINARY, 0666);
    if (fd < 0) {
	fprintf (stderr, 
		 "%s:  unable to create binary file \"%s\" (error %d, %s)\n",
		 ProgramName, line, errno, SysError());
	exit (1);
    }

    /* step 1: load memory from file */
    lineno = 0;
    while (fgets(line, sizeof(line), stdin)) {
	lineno++;
	items = sscanf(line, "%u %u %u %[^\n]\n", &red, &green, &blue, name);
	if (items != 4) {
	    fprintf(stderr, "syntax error on line %d\n", lineno);
	    fflush(stderr);
	    continue;
	}
	if (red > 0xff || green > 0xff || blue > 0xff) {
	    fprintf(stderr,
		   "value for \"%s\" out of range: red %u, green %u, blue %u\n",
		   name, red, green, blue);
	    fflush(stderr);
	    continue;
	}
	pent = (struct ent *)malloc(sizeof(struct ent));
	if (!pent) {
	    fprintf(stderr, "malloc of struct ent failed\n");
	    exit(1);
	}
	namelen = strlen(name);
	if (namelen == 0) {
	    fprintf(stderr, "error: name on line %d is NULL\n", lineno);
	    exit(1);
	}
	if (namelen > 256) {
	    fprintf(stderr,
	    	"error: name on line %d is longer that 256 characters\n",
		lineno);
	    exit(1);
	}
	pent->length = namelen;
	namelen = (namelen + 1) & ~1; /* if length is odd, keep trailing null */
	pent->name = (char *)malloc(namelen);
	if (!pent->name) {
	    fprintf(stderr, "malloc of name failed\n");
	    exit(1);
	}
	hash = 0;
	for (i = 0; i < pent->length; i++) {
	    if (isupper(name[i]))
		name[i] = tolower(name[i]);
	    hash = DO_HASH(hash, name[i]);
	}
/*
printf("%d %s %d\n", hash, name, pent->length);
*/
	(void)memcpy(pent->name, name, namelen);
	pent->rgb.red = red;
	pent->rgb.green = green;
	pent->rgb.blue = blue;
	pent->next = buckets[hash];
	buckets[hash] = pent;
	bucketlen[hash] += sizeof(unsigned short) + sizeof(RGB) + namelen;
    }

    /* Now write the bin binary file. */
    /* start by writing out the seek offsets */
    offs = 256 * sizeof(unsigned long);
    for (i = 0; i < 256; i++) {
	if (bucketlen[i]) {
	    write_it(fd, (void *)&offs, sizeof(unsigned long));
	    offs += bucketlen[i] + sizeof(unsigned short);
	} else
	    write_it(fd, "\0\0\0", 4);	/* write out a long zero */
    }
    /* now, write out the buckets */
    for (i = 0; i < 256; i++) {
	pent = buckets[i];
	if (!pent)
	    continue;
	while (pent) {
	    write_it(fd, (void *)pent, sizeof(unsigned short) + sizeof(RGB));
	    namelen = pent->length;
	    namelen = (namelen + 1) & ~1; /* if namelen is odd, make even */
	    write_it(fd, (void *)pent->name, namelen);
	    pent = pent->next;
	}
	write_it(fd, "\0", 2);	/* write end of bucket */
    }
    close(fd);
}

static void
write_it(fd, ptr, len)
int fd;
void *ptr;
unsigned short len;
{

    if (write(fd, ptr, len) < 0) {
	fprintf(stderr, "store failed\n");
	fflush(stderr);
	exit(1);
    }
}

