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

/*      CHANGE.C		*/
/*      This module is used to find and change records
**	in the data base matching the selection criteria.
**	The user may select multiple values of one field
**	which will be or'd and/or multiple fields which will
**	be and'd. In other words, if field 1 is specified
**	as value1:value2 and field3 is specified as value3.
**	Records with field1==(value1 || value2) && field3==value3
**	will be selected for changing.
**	It calls findrcds.c to do all the work of finding them.
**	It does not actually change records, the flag(first)
**	field is set to 'D' in the current record and a new
**	record is added. To physically delete the old record,
**	the data base must be compressed.
*/

#include <stdio.h>
#include <errno.h>
#include "ascii.h"
#include "cardfile.h"

char	*malloc(), *getfield();
extern	int	readonly;


static struct Sdata disp_screen[MAXFLDS+1];

change(fields, dbname)
struct  Fdata   fields[];
char    *dbname;
{
    char	first[SWIDTH];
    struct Fdata *fp;
    struct Sdata *sp;
    int 	processc();

    if (readonly) {
	msg("Database is readonly");
	return(1);
    }
    sprintf(first, "Select Records from the %s Data Base to be Changed",
	dbname);
    for (fp = fields, sp = disp_screen ; fp->F_title[0] != 0; ++fp, ++sp) {
	sp->S_title = fp->F_title;
	sp->S_length = fp->F_length;
	sp->S_result = (char*)malloc((unsigned)fp->F_length+1);
	sp->S_page = fp->F_page;
	sp->S_Lrow = fp->F_Lrow;
	sp->S_Lcol = fp->F_Lcol;
	sp->S_Drow = fp->F_Drow;
	sp->S_Dcol = fp->F_Dcol;
	sp->S_Dfmt = fp->F_Dfmt;
    }
    sp->S_title = 0;

    findrcds(fields, dbname, processc, first);
    for (sp = disp_screen ; sp->S_title != 0; ++sp) {
	free(sp->S_result);
    }
    return(0);
}


processc(fields, rcd, dbfile, dbname)
struct  Fdata   *fields;
char    *rcd;
FILE    *dbfile;
char    *dbname;
{
    char	c, save[DBSIZE+1];
    long	offset, ftell();
    char	*strchr();
    struct      Sdata   *sp;
    char	*first = "Record to be CHANGED";
    char	*last = "RETURN for next, ESC to abort, Ctrl-C to Change, Ctrl-B to reverse";
    extern char	lastchar;
    
    strcpy(save, rcd);
    *strchr(save, '\n') = '\0';          /* truncate \n */
    getfield(save, ":");
    for (sp = disp_screen; sp->S_title != 0; ++sp) {
	sp->S_dfault = getfield(NULL, ":");
    }
    screen(first, disp_screen, last, NULL, TRUE);
    noecho();
    c = lastchar;
    do {
	if (c == LF || c == CR)
	    break;
	if (c == ETX) {         /* CTL-C entered */
	    offset = ftell(dbfile) - strlen(rcd);
	    *strchr(rcd, '\n') = '\0';          /* truncate \n */
	    if (doadd(dbname, fields, rcd, dbfile) == 0) {
		fseek(dbfile, offset, 0);
		putc('D', dbfile);
	    }
	    break;
	}
	if (c == ESC) {
	    echo();
	    return(1);
	}
	if (c == STX) {			/* CTRL-B */
	    echo();
	    return(-1);
	}
	rawputchar(BEL);
    } while (c=rawgetchar());
    echo();
    return(0);
}

doadd(dbname, fields, rcd, filep)
char    *dbname;
struct  Fdata   *fields;
char    *rcd;
FILE    *filep;
{
    struct      Sdata   *sp;
    struct      Fdata   *fp;
    int 	err = 0;
    char	buffer[BUFSIZE+1];
    char	outline[DBSIZE+1];
    long	offset, ftell();

    fseek(filep, 0L, 2);     /* end of file */
    fp = fields;
    getfield(rcd, ":");         /* step past flag */
    sp = disp_screen;
    while(fp->F_title[0]) {
	sp->S_dfault = getfield(0, ":");
	++fp;
	++sp;
    }
    outline[0] = '\0';
    while (screen("Enter changes", disp_screen, 0, 0, FALSE) > 0) {
	err = 0;
	fp = fields;
	sp = disp_screen;
	while(fp->F_title[0]) {
	    if (sp->S_result[0] == '\0' && fp->F_required == 'Y') {
		sprintf(outline, "Required field %s missing", fp->F_title);
		msg(outline);
		err++;
	    }
	    if (strchr(sp->S_result, ':')) {
		msg("A : is not allowed in any field");
		++err;
	    }
	    if (strlen(outline) + strlen(sp->S_result) >= DBSIZE) {
		msg("Record too long");
		++err;
		break;
	    }
	    strcat(outline, sp->S_result);
	    strcat(outline, ":");
	    ++fp;
	    ++sp;
	}
	if (err == 0)
	    break;
	outline[0] = '\0';
    }
    if (err > 0 || outline[0] == '\0') {
	return(1);
    }
    outline[strlen(outline)-1] = '\0';  /* truncate trailing : */
    offset = ftell(filep);
    if (fprintf(filep, " :%s\n", outline) == EOF) {
	msg("Error writing DB file");
	getout();
    }
    buffer[0] = '\0';
    buildak(dbname, outline, offset, fields, buffer);
    writeak(dbname, buffer);
    return(0);
}
