static char rcsid[] = "@(#)$Id: rc_delay.c,v 1.5 2006/04/09 07:37:08 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.5 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI>
 *      or  Kari Hurtta <elm@elmme-mailer.org>
 *****************************************************************************/

#include "headers.h"
#include "rc_imp.h"
#include "save_opts.h"

DEBUG_VAR(Debug,__FILE__,"config");

enum xx { line_normal, line_negate, line_continue };

struct rec1 {
    int lcl;
    char *value; 
    int lineno; 
    char *filename;
    enum xx negate_continue;
};

static void replay_rec P_((struct rec1 *rec,
			  struct rc_save_info_rec * real));
static void replay_rec(rec,real)
     struct rec1 *rec;
     struct rc_save_info_rec * real;
{
    switch (rec->negate_continue) {

    case line_normal:
	rc_eval_tail(real,rec->lcl,rec->value,rec->lineno,rec->filename,0);
	break;

    case line_negate:
	rc_eval_tail(real,rec->lcl,rec->value,rec->lineno,rec->filename,1);
	break;

    case line_continue:
	
	if (RCTYPE_magic != real->dt_type->magic)
	    panic("RC PANIC",__FILE__,__LINE__,"replay_rec",
		  "Bad config item type",0);
 
	real->dt_type->parse_cline(real,rec->lcl,rec->value,rec->lineno,
				   rec->filename);
	break;
    }
}

static struct rc_save {
    struct rc_save_info_rec * real;        
    struct rc_save_info_rec * delayed;  

    struct rec1  * lines;
    int            line_count;

    struct rc_save  * next;
} * root = NULL;

void  mark_delayed_changed(A)
     void *A;
{
    struct rc_save *x;

    for (x = root; x; x = x->next) {
	if (x->real && x->real->val.dummy == A) {

	    DPRINT(Debug,10,(&Debug,
			     "mark_delayed_changed: %p: %p\n",
			     x,A));

	    mark_XX(x->real);

	    if (x->delayed)
		mark_XX(x->delayed);
	    else {
		DPRINT(Debug,10,(&Debug,
				 "mark_delayed_changed: %p: %p -- no delayed registered\n",
				 x,A));
		
	    }

	}
    }

}

void  mark_fdelayed_changed(A)
     option_func *A;
{
    struct rc_save *x;

    for (x = root; x; x = x->next) {
	if (x->real && x->real->func_val == A) {

	    DPRINT(Debug,10,(&Debug,
			     "mark_fdelayed_changed: %p: %p\n",
			     x,A));

	    mark_XX(x->real);

	    if (x->delayed)
		mark_XX(x->delayed);
	    else {
		DPRINT(Debug,10,(&Debug,
				 "mark_fdelayed_changed: %p: %p -- no delayed registered\n",
				 x,A));		
	    }
	}
    }

}



static struct rc_save * new_record P_((void));
static struct rc_save * new_record()
{
    struct rc_save * x = safe_malloc(sizeof (*x));

    bzero((void *)x,sizeof (*x));

    x->real     = NULL;
    x->delayed  = NULL;

    x->next     = root;
    root        = x;

    return x;
}

static void replay_saved P_((struct rc_save *p));
static void replay_saved(p)
     struct rc_save *p;
{
    int i;

    for (i = 0; i < p->line_count; i++) {
	replay_rec(& (p->lines[i]), p->real);
    }

    for (i = 0; i < p->line_count; i++) {
	if (p->lines[i].value)
	    free(p->lines[i].value);
	p->lines[i].value = NULL;

	if (p->lines[i].filename)
	    free(p->lines[i].filename);
	p->lines[i].filename = NULL;       
    }

    if (p->lines)
	free(p->lines);
    p->lines      = NULL;
    p->line_count = 0;
}

static void add_delayed P_((struct rc_save *p));
static void add_delayed(p)
     struct rc_save *p;
{
    int x;

    for (x = 0; x < NUMBER_OF_SAVEABLE_OPTIONS; x++) {
	if (0 == strcmp(save_info[x].name,p->real->name)) {

	    if (save_info[x].dt_type != &rc_DT_DELAY)
		panic("RC PANIC",__FILE__,__LINE__,"add_delayed",
		      "Option is not delayed",0);

	    p->delayed = & (save_info[x]);
	    return;
	}

    }
    
    panic("RC PANIC",__FILE__,__LINE__,"add_delayed",
	  "Deleayed option not found",0);
}

static void register_delayed1 P_((struct rc_save_info_rec *option_real));
static void register_delayed1(option_real)
     struct rc_save_info_rec *option_real;
{
    struct rc_save *p;

    for (p = root; p; p = p->next) {
	if (option_real == p->real)
	    panic("RC PANIC",__FILE__,__LINE__,"register_delayed1",
		  "Duplicate registeration",0);
	if (p->delayed &&
	    0 == strcmp(option_real->name,p->delayed->name)) {
	    
	    if (p->real)
		panic("RC PANIC",__FILE__,__LINE__,"register_delayed1",
		      "Duplicate name",0);
	    p->real = option_real;	    

	    replay_saved(p);
	    
	    return;
	}
    }
    p = new_record();
    p->real = option_real;

    add_delayed(p);
}


void register_delayed(rc_options,rc_option_count)
     struct rc_save_info_rec * rc_options;
     int rc_option_count;
{
    int i;

    for (i = 0; i < rc_option_count; i++) {
	register_delayed1(& (rc_options[i]) );
    }
}

static struct rc_save * register_delayed2 P_((struct rc_save_info_rec *option_proxy));
static struct rc_save * register_delayed2(option_proxy)
     struct rc_save_info_rec *option_proxy;
{
    struct rc_save *p;
    
    for (p = root; p; p = p->next) {
	if (option_proxy == p->delayed)
	    return p;

	if (p->real &&
	    0 == strcmp(option_proxy->name,p->real->name)) {
	    
	    if (p->delayed)
		panic("RC PANIC",__FILE__,__LINE__,"register_delayed2",
		      "Duplicate name",0);
	    p->delayed = option_proxy;
	    
	    return p;
	}
    }

    p = new_record();
    p->delayed = option_proxy;

    return p;
}

#ifdef ANSI_C
static rc_parse_line dt_DELAY_parse_line;
#endif
static int dt_DELAY_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{
    int ret = 1;
    struct rc_save *p = register_delayed2(r);
    
    if (p->real && p->line_count)
	panic("RC PANIC",__FILE__,__LINE__,"dt_DELAY_parse_line",
	      "Bad state",0);
    
    if (p->real) {
	
	ret = rc_eval_tail(p->real,lcl,value,lineno,filename,negate);
		
    } else {

	p->lines = safe_realloc(p->lines,
				(p->line_count + 1) * sizeof (p->lines[0]));
	
	bzero((void *)& (p->lines[p->line_count]), 
	      sizeof (p->lines[p->line_count]) );
	
	p->lines[p->line_count].lcl    = lcl;
	p->lines[p->line_count].value  = safe_strdup(value);
	p->lines[p->line_count].lineno = lineno;
	p->lines[p->line_count].filename  = safe_strdup(filename);
	p->lines[p->line_count].negate_continue = negate ? 
	    line_negate : line_normal;
	
	p->line_count++;
	ret = 1;
	
    }
    return ret;
}

#ifdef ANSI_C
static rc_parse_cline dt_DELAY_parse_cline;
#endif
static int dt_DELAY_parse_cline(r,lcl,value,lineno,filename)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
{     
    int ret = 1;
    struct rc_save *p = register_delayed2(r);
    
    if (p->real && p->line_count)
	panic("RC PANIC",__FILE__,__LINE__,"dt_DELAY_parse_cline",
	      "Bad state",0);
    
    if (p->real) {

	if (RCTYPE_magic != p->real->dt_type->magic)
	    panic("RC PANIC",__FILE__,__LINE__,"dt_DELAY_parse_cline",
		  "Bad config item type",0);

	
	ret = p->real->dt_type->parse_cline(p->real,lcl,value,lineno,
					    filename);
		
    } else {
	
	if (!p->line_count)
	    panic("RC PANIC",__FILE__,__LINE__,"dt_DELAY_parse_cline",
		  "Bad state",0);
    

	p->lines = safe_realloc(p->lines,
				(p->line_count + 1) * sizeof (p->lines[0]));
	
	bzero((void *)& (p->lines[p->line_count]), 
	      sizeof (p->lines[p->line_count]) );
	
	p->lines[p->line_count].lcl    = lcl;
	p->lines[p->line_count].value  = safe_strdup(value);
	p->lines[p->line_count].lineno = lineno;
	p->lines[p->line_count].filename  = safe_strdup(filename);
	p->lines[p->line_count].negate_continue = line_continue;
	
	p->line_count++;
	ret = 1;
	
    }
    return ret;
    
}

#if ANSI_C
static rc_print_value dt_DELAY_print_value;
#endif
static void dt_DELAY_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{
    struct rc_save *p = register_delayed2(r);

    if (p->real && p->line_count)
	panic("RC PANIC",__FILE__,__LINE__,"dt_DELAY_print_value",
	      "Bad state",0);
    
    if (p->real) {
     
	if (RCTYPE_magic != p->real->dt_type->magic)
	    panic("RC PANIC",__FILE__,__LINE__,"dt_DELAY_print_value",
		  "Bad config item type",0);

	
	p->real->dt_type->print_value(F,p->real,comment);

    } else if (p->line_count) {
	int i,start = 0;

	for (i = 0; i < p->line_count; i++) {
	    if (line_normal == p->lines[i].negate_continue)
		start = i;
	}

	for (i = start; i < p->line_count; i++) {

	    if (comment)
		fprintf(F, "### ");

	    switch (p->lines[i].negate_continue) {
	    case line_normal:
		fprintf(F, "%s = %s\n", r->name, p->lines[i].value);

		break;

	    case line_continue:
		if (0 == i)
		    panic("RC PANIC",__FILE__,__LINE__,"dt_DELAY_print_value",
			  "Bad state",0);
		    
		fprintf(F, "\t%s\n", p->lines[i].value);

		break;

	    case line_negate:
		/* unsupported */
		fprintf(F, "# !%s = %s\n", r->name, p->lines[i].value);
		break;
	    }
	}

    } 
}

#if ANSI_C
static rc_get_value dt_DELAY_get_value;
#endif
static char * dt_DELAY_get_value(r)
     struct rc_save_info_rec *r;
{
    struct rc_save *p = register_delayed2(r);

    if (p->real && p->line_count)
	panic("RC PANIC",__FILE__,__LINE__,"dt_DELAY_get_value",
	      "Bad state",0);
    
    if (p->real) {
     
	if (RCTYPE_magic != p->real->dt_type->magic)
	    panic("RC PANIC",__FILE__,__LINE__,"dt_DELAY_get_value",
		  "Bad config item type",0);

	return p->real->dt_type->get_value(p->real);
    } else if (p->line_count) {

	int i,start = 0;

	for (i = 0; i < p->line_count; i++) {
	    if (line_normal == p->lines[i].negate_continue)
		start = i;
	}

	if (start == p->line_count-1 &&
	    line_normal == p->lines[start].negate_continue)
	    return p->lines[start].value;
    }


    return "*bad*";
}



struct rc_type rc_DT_DELAY = { RCTYPE_magic,
			       dt_DELAY_parse_line, dt_DELAY_parse_cline,
			       dt_DELAY_print_value, dt_DELAY_get_value };

/*
 * Local Variables:
 *  mode:c
 *  c-basic-offset:4
 *  buffer-file-coding-system: iso-8859-1
 * End:
 */


syntax highlighted by Code2HTML, v. 0.9.1