#ifndef lint
static char Sccsid[] = "@(#)define.c	3.2    DeltaDate 12/9/90    ExtrDate 12/9/90";
#endif

/*      DEFINE.C	*/
/*      This subroutine is used to define a new data-base.
**	It expects as input the base name (10 characters or less)
**	of all files.
**
**	It will create the definition file  -  name.def
**	the primary file		    -  name.db
**	and the alternate key files         -  name.akN
*/

#include "cardfile.h"
#include "stdio.h"
#include "ascii.h"
#include "patchlevel.h"
#include <ctype.h>

#define	FNAME	0
#define	MAXL	1
#define	REQD	2
#define	SRCH	3
#define	SUBF	4
#define	PAGE	5
#define	LLINE	6
#define	LCOL	7
#define	DLINE	8
#define	DCOL	9
#define	FMT	10

static int	page_def = 1;
static int	lline_def = 2;
static int	col_def = 4;

static char	name_res[TSIZE+1];
static char	mlen_res[3+1];
static char	req_res[1+1];
static char	skey_res[1+1];
static char	sep_res[5+1];
static char	page_res[1+1];
static char	lline_res[2+1];
static char	lcol_res[2+1];
static char	dline_res[2+1];
static char	dcol_res[2+1];
#ifndef NO_RE
static char	fmt_res[MAXFMT+1];
#endif

static struct	Sdata	def_screen[] = {
			{"FIELD NAME", TSIZE, name_res, 0,
			    -1, -1, -1, -1, -1, "^[^:]*$"},
			{"MAXIMUM LENGTH", 3, mlen_res, 0,
			    -1, -1, -1, -1, -1, "^[0-9]*$"},
			{"REQUIRED?", 1, req_res, "N",
			    -1, -1, -1, -1, -1, "[nyNY]"},
			{"SEARCH KEY", 1, skey_res, "Y",
			    -1, 6, 35, -1, -1, "[nyNY]"},
			{"SUBFIELD SEPARATORS", 5, sep_res, 0,
			    -1, -1, -1, -1, -1, "^[^:]$"},
			{"FIELD PAGE", 1, page_res, " ",
			    -1, -1, -1, -1, -1, "^[-0-9]$"},
			{"LABEL LINE", 2, lline_res, "  ",
			    -1, -1, -1, -1, -1, "^[-0-9][0-9]*$"},
			{"LABEL COLUMN", 2, lcol_res, "  ",
			    -1, 12, 35, -1, -1, "^[-0-9][0-9]*$"},
			{"DATA FIELD LINE", 2, dline_res, "  ",
			    -1, -1, -1, -1, -1, "^[-0-9][0-9]*$"},
			{"DATA FIELD COLUMN", 2, dcol_res, 0,
			    -1, 14, 35, -1, -1, "^[-0-9][0-9]*$"},
#ifndef NO_RE
			{"FORMAT", MAXFMT, fmt_res, 0,
			    -1, -1, -1, -1, -1, ""},
#endif
			{0, 0, 0, 0, -1, -1, -1, -1, -1, ""}
		};

static struct  Fdata   fields[MAXFLDS];

db_define(basename)
char    *basename;
{
    int 	i;
    char	first[SWIDTH];
    char	*last = "RETURN to exit";
    struct      Fdata   *fp;
    int 	num_fields, num_ak;
    char	fname[FNSIZE];
    FILE	*filep, *filep2;
    int 	err;
    int 	tsize;
    int		opt_out;

    sprintf(first,"DEFINING %s DATA BASE  -- Cardfile Version %s",
	basename, VERSION);
    if (access((*datadir ? datadir : "."), 06) != 0) {
	printf("Cannot write into %s\n", (*datadir ? datadir : "."));
	sleep(5);
	return(1);
    }
    
    /*
     *	Read each field entered
     */
    num_fields = 0;
    fp = &fields[0];
    tsize = 0;
    sprintf(def_screen[PAGE].S_dfault, "%d", page_def);
    sprintf(def_screen[LLINE].S_dfault, "%d", lline_def);
    sprintf(def_screen[LCOL].S_dfault, "%d", col_def);
    sprintf(def_screen[DLINE].S_dfault, "%d", lline_def);
    while (screen(first, def_screen, last, 0, FALSE)) {
	err = 0;
	strcpy(fp->F_title, def_screen[FNAME].S_result);
	if (fp->F_title[0] == '\0') {
	    msg("TITLE field must be specified");
	    ++err;
	}
	if (strchr(fp->F_title, ':') != NULL) {
	    msg("TITLE field must not include :");
	    ++err;
	}

	fp->F_length = atoi(def_screen[MAXL].S_result);
	if (fp->F_length <= 0 || fp->F_length >= FLDLEN) {
	    msg("LENGTH field must be less than 256");
	    ++err;
	}
	if ((tsize += fp->F_length) > DBSIZE) {
	    msg("Total record length too large");
	    ++err;
	}

#ifdef BSD_STRING
	if (islower(def_screen[REQD].S_result[0]))
	    fp->F_required = toupper(def_screen[REQD].S_result[0]);
	else
	    fp->F_required = def_screen[REQD].S_result[0];
#else
	fp->F_required = toupper(def_screen[REQD].S_result[0]);
#endif
	if (fp->F_required != 'Y' && fp->F_required != 'N') {
	    msg("REQUIRED must be Y or N");
	    ++err;
	}

#ifdef BSD_STRING
	if (islower(def_screen[SRCH].S_result[0]))
	    fp->F_key = toupper(def_screen[SRCH].S_result[0]);
	else
	    fp->F_key = def_screen[SRCH].S_result[0];
#else
	fp->F_key = toupper(def_screen[SRCH].S_result[0]);
#endif
	if (fp->F_key != 'Y' && fp->F_key != 'N') {
	    msg("KEY must be Y or N");
	    ++err;
	}

	strcpy(fp->F_seps, def_screen[SUBF].S_result);
	if (strchr(fp->F_seps, ':') != NULL) {
	    msg("SEPARATORS must not include :");
	    ++err;
	}

#ifndef NO_RE
	strcpy(fp->F_Dfmt, def_screen[FMT].S_result);
#else
	fp->F_Dfmt[0] = '\0';
#endif

	fp->F_page = atoi(def_screen[PAGE].S_result);
	if (fp->F_page == 0) {
	    fp->F_page = -1;
	}

	if (def_screen[LLINE].S_result[0] == '\0') {
	    fp->F_Lrow = -1;
	} else {
	    fp->F_Lrow = atoi(def_screen[LLINE].S_result);
	    if (fp->F_Lrow < 2 || fp->F_Lrow >= MSGLINE) {
		msg("LABEL LINE field must be less than 22");
		++err;
	    }
	}

	if (def_screen[LCOL].S_result[0] == '\0') {
	    fp->F_Lcol = -1;
	} else {
	    fp->F_Lcol = atoi(def_screen[LCOL].S_result);
	    if (fp->F_Lcol < 0 || fp->F_Lcol >= SWIDTH) {
		msg("LABEL COLUMN field must be less than 80");
		++err;
	    }
	}

	if (def_screen[DLINE].S_result[0] == '\0') {
	    fp->F_Drow = -1;
	} else {
	    fp->F_Drow = atoi(def_screen[DLINE].S_result);
	    if (fp->F_Drow < 2 || fp->F_Drow >= MSGLINE) {
		msg("DATA LINE field must be less than 22");
		++err;
	    }
	}

	if (def_screen[DCOL].S_result[0] == '\0') {
	    fp->F_Dcol = -1;
	} else {
	    fp->F_Dcol = atoi(def_screen[DCOL].S_result);
	    if (fp->F_Dcol < 0 || fp->F_Dcol >= SWIDTH) {
		msg("DATA COLUMN field must be less than 80");
		++err;
	    }
	}

	for (i=0; i<num_fields; i++) {
	    if (strcmp(fields[i].F_title, fp->F_title) == 0) {
		msg("Field already defined");
		err++;
		break;
	    }
	}
	if (err)
	    continue;
	/*
	 * Valid field, update defaults
	 */
	lline_def = (fp->F_Lrow > fp->F_Drow ? fp->F_Lrow : fp->F_Drow) + 2;
	if (fp->F_Dcol == -1) {
	    lline_def += ((fp->F_Lcol == -1 ? 4 : fp->F_Lcol) +
			    strlen(fp->F_title) + (fp->F_length > 99 ? 7 : 6) +
			    fp->F_length) / SWIDTH;
	} else {
	    lline_def += (fp->F_Dcol + fp->F_length) / SWIDTH;
	}
	if (lline_def > SLENGTH - 4) {
	    page_def++;
	    lline_def = 2;
	}
	sprintf(def_screen[PAGE].S_dfault, "%d", page_def);
	sprintf(def_screen[LLINE].S_dfault, "%d", lline_def);
	sprintf(def_screen[LCOL].S_dfault, "%d", col_def);
	sprintf(def_screen[DLINE].S_dfault, "%d", lline_def);
	++fp;
	if (++num_fields > MAXFLDS) {
	    msg("Too many fields defined, aborting");
	    return(1);
	}
    }
#ifdef DEBUG
    fprintf(stderr, "%d fields in the %s database\n", num_fields, basename);
    for (i=0; i<num_fields; ++i) {
	fprintf(stderr, "%8d  %s\n", i, fields[i].F_title);
    }
#endif

    if (num_fields == 0) {
	msg("No fields defined, aborting");
	return(1);
    }
    sprintf(fname,"%s%s.def", datadir, basename);
    if ((filep = fopen(fname,"w")) == NULL) {
	msg("Unable to create DEF file");
	return(1);
    }
    sprintf(fname,"%s%s.db", datadir, basename);
    if ((filep2 = fopen(fname,"w")) == NULL) {
	msg("Unable to create DB file");
	sprintf(fname, "%s.def", basename);
	unlink(fname);
	return(1);
    }
    fclose(filep2);
    fprintf(filep, "%s:%d\n", fname, num_fields);
    num_ak = 0;
    for (i=0; i<num_fields; i++) {
	fp = &fields[i];
	if (fp->F_key == 'Y')
	    fp->F_key = '0' + num_ak++;
	fprintf(filep, "%s:%c:%s:%c:%d\n", fp->F_title, fp->F_key,
	    fp->F_seps, fp->F_required, fp->F_length);
    }
    if (num_ak == 0) {
	msg("At least 1 key field must be defined");
	unlink(fname);          /* DB file */
	sprintf(fname, "%s.def", basename);
	unlink(fname);
	return(1);
    }
    fprintf(filep, "%d\n", num_ak);
    num_ak = 0;
    for (i=0; i<num_fields; i++) {
	fp = &fields[i];
	if (fp->F_key != 'N') {         /* Alternate key file required */
	    sprintf(fname,"%s%s.ak%d", datadir, basename, num_ak++);
	    if ((filep2 = fopen(fname,"w")) == NULL) {
		msg("Unable to create AK file\n");
		sprintf(fname, "%s.def", basename);
		unlink(fname);
		return(1);
	    }
	    fclose(filep2);
	    fprintf(filep, "%d:%s\n", i, fname);
	}
    }

    /*
     * Output optional fields if necessary (position and format)
     */
    for (i=0, opt_out=1, fp = &fields[0]; i<num_fields; i++, fp++) {
	if (fp->F_page == -1 && fp->F_Lrow == -1 && fp->F_Lcol == -1 &&
		fp->F_Drow == -1 && fp->F_Dcol == -1 && fp->F_Dfmt[0] == '\0') {
	    continue;
	}
	if (opt_out) {
	    fprintf(filep, "%%%%\n");
	    opt_out = 0;
	}
	fprintf(filep, "%d:%d:%d:%d:%d:%d:%s\n", i, fp->F_page, fp->F_Lrow,
	    fp->F_Lcol, fp->F_Drow, fp->F_Dcol, fp->F_Dfmt);
    }
    fclose(filep);
    return(0);
}
