#ifndef _DWC_CONF_H
#define _DWC_CONF_H

/*--------------------------------------------------------------------------
 *  Copyright (c) 2001-2004 Igor Daniloff. 
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at this directory.
 *------------------------------------------------------------------------*/

/* $Id: dwc_conf.h,v 1.25 2007/08/29 15:32:28 akorkov Exp $ */

#include <stdio.h>
#include "dwc_queue.h"
#include "dwc_macro.h"
#include "dwc_type.h"
#include "dwc_strings.h"
#include "dwc_proto.h"

#ifdef __UNIX_DW
#include <strings.h>
#include "dwc_ipc.h"
#endif /* __UNIX_DW */

#ifdef  __cplusplus
extern "C" {
#endif

/* Internal: Max size of line: <name> <separator> <value> */
#define DWC_LINE_SIZE           (1024)
/* Internal: Max size of <name> in configure file */
#define DWC_NAME_SIZE           (256)

/* Internal: Values of field vtype */
#define DWC_CV_NONE             (0)                /* last line marker */
#define DWC_CV_INT              (DWC_CV_NONE + 1)  /* int value */
#define DWC_CV_COUNT            (DWC_CV_INT + 1)   /* unsigned int value */
#define DWC_CV_BOOL             (DWC_CV_COUNT + 1) /* on/off, yes/no value */
#define DWC_CV_STRING           (DWC_CV_BOOL + 1)  /* asciiz string value */
#define DWC_CV_OCTAL            (DWC_CV_STRING + 1)/* unsigned int value, as octal */
#define DWC_CV_STRING_LIST      (DWC_CV_OCTAL + 1) /* multistring (string list) value, as octal */

/* Internal: Macroses for default value initializers */
#if defined(NOT_GCC_DW)
#define DWC_CDV_VAL( t, v )     { (int) (v) }
#else /* GCC */
#define DWC_CDV_VAL( t, v )     { t : (v) }
#endif /* not GCC */
#define DWC_CDV_INT( v )        DWC_CDV_VAL( vint, (v) )
#define DWC_CDV_BOOL( v )       DWC_CDV_VAL( vbool, (v) )
#define DWC_CDV_COUNT( v )      DWC_CDV_VAL( vcount, (v) )
#define DWC_CDV_OCTAL( v )      DWC_CDV_VAL( vcount, (v) )
#define DWC_CDV_STRING( v )     DWC_CDV_VAL( vstring, (v) )
#define DWC_CDV_STRING_LIST( v ) DWC_CDV_VAL( vstringlist, (v) )

/* Internal: Macroses for waiting value initializers */
#if defined(NOT_GCC_DW)
#define DWC_WV_SVAL( t, v, f )  (t), { (int*) &(v) }, sizeof(v)
#else /* GCC */
#define DWC_WV_SVAL( t, v, f )  (t), { f : &(v) }, sizeof(v)
#endif /* not GCC */
#define DWC_WV_INT( v )         DWC_WV_SVAL( DWC_CV_INT, v, pint )
#define DWC_WV_BOOL( v )        DWC_WV_SVAL( DWC_CV_BOOL, v, pbool )
#define DWC_WV_COUNT( v )       DWC_WV_SVAL( DWC_CV_COUNT, v, pcount )
#define DWC_WV_OCTAL( v )       DWC_WV_SVAL( DWC_CV_OCTAL, v, pcount )
#if defined(NOT_GCC_DW)
#define DWC_WV_STRING( v )      DWC_CV_STRING, { (int*) &(v) }, 0
#define DWC_WV_STRING_LIST( v ) DWC_CV_STRING_LIST, { (int*) &(v) }, 0
#else /* GCC */
#define DWC_WV_STRING( v )      DWC_CV_STRING, { pstring: &(v) }, 0
#define DWC_WV_STRING_LIST( v ) DWC_CV_STRING_LIST, { pstringlist: &(v) }, 0
#endif /* not GCC */

/* Macroses for filling dwc_conf_set_t lines */
#define DWC_CONF_VAL( n,v,d,t )         { (n), DWC_WV_##t( v ), DWC_CDV_##t( d ) }
#define DWC_CONF_INT( n,v,d )           DWC_CONF_VAL( n, v, d, INT )
#define DWC_CONF_BOOL( n,v,d )          DWC_CONF_VAL( n, v, d, BOOL )
#define DWC_CONF_COUNT( n,v,d )         DWC_CONF_VAL( n, v, d, COUNT ) 
#define DWC_CONF_OCTAL( n,v,d )         DWC_CONF_VAL( n, v, d, OCTAL ) 
#define DWC_CONF_STRING( n,v,d )        DWC_CONF_VAL( n, v, d, STRING )
#define DWC_CONF_STRING_LIST( n,v )     DWC_CONF_VAL( n, v, NULL, STRING_LIST )

/* It's definition MUST be last element in all var-lists of dwc_conf_set_t */
#define DWC_CONF_ENDLINE                { NULL, DWC_CV_NONE, { NULL },  0, DWC_CDV_INT(0) }

/* Macros for filling dwc_conf_task_t lines */
#define DWC_CONF_TASK( n,d,r,c,m )      { (n), (d), (r), (c), FALSE, (m) }

/* It's definition MUST be last element in lists of dwc_conf_task_t */
#define DWC_CONF_ENDTASK                { NULL, NULL, NULL, NULL, FALSE, FALSE }

/* Internal: macro for generating valued and pointer types */
#define DWC_CONF_VALSET( ns )   union {\
                                    int                 ns##int;\
                                    dwc_count_t         ns##count;\
                                    dwc_bool_t          ns##bool;\
                                    dwc_string_t        ns##string;\
                                    dwc_multistring_t   ns##stringlist;\
                                    }
                                       
typedef DWC_CONF_VALSET( *p ) dwc_conf_pval_t;
typedef DWC_CONF_VALSET( v )  dwc_conf_val_t;

typedef struct {
    char            *name;      /* variable name */
    int              vtype;     /* type of vptr */
    dwc_conf_pval_t  vptr;      /* ptr to value storage */
    int              vlen;      /* length of vptr storage */
    dwc_conf_val_t   vdefault;  /* default value */
} dwc_conf_set_t;

typedef dwc_bool_t (*dwc_section_reader_t)(FILE * fs, int* line, const char* section, void* data);
typedef void       (*dwc_section_cleaner_t)(const char* section, void* data);

typedef struct {
    char                   *name;
    void                   *data;
    dwc_section_reader_t    read_proc;
    dwc_section_cleaner_t   clean_proc;
    dwc_bool_t              need_clean;
    dwc_bool_t              can_missed;
} dwc_conf_task_t;

#ifdef __UNIX_DW  
extern char * transform_agent_buf(char ** list, int list_len); /* parsing agent-format config */
extern char * get_head(char * str); /* needed for transform_agent_buf */
#endif /* __UNIX_DW */
  
extern void delete_spaces( char *s );
extern void delete_quotes( char *s );

#define DECLARE_PARSER( name )\
extern dwc_bool_t read_##name##_opt ( FILE *fs, int *pline, const char *sec, void *pdata );\
extern void       free_##name##_opt ( const char *sec, void *pdata );
#ifdef __UNIX_DW
#define DECLARE_PARSER_AGENT( name )\
extern dwc_bool_t read_##name##_opt_agent ( char * buf, int *pline, const char *sec, void *pdata );
#endif /* __UNIX_DW */


extern int read_conf ( const char* filename, dwc_conf_task_t* task );
extern int free_conf ( dwc_conf_task_t* task );
extern int read_section ( FILE* fs, int* line, const char* section, dwc_conf_set_t* vars, char sep, char list_sep );
#ifdef __UNIX_DW
extern int read_conf_agent ( const char* address, dwc_conf_task_t* task );
extern int read_section_agent ( char * _buf_fs, int* line, const char* section, dwc_conf_set_t* vars, char sep, char list_sep );
#endif /* __UNIX_DW */

/* Program flow:
    read_conf() calls read_proc() according to section name 
    read_proc() usually just can call the read_section() with prepared vars_list
    If one of read_proc() fails then for already processed sections called clean_proc.  
    clean_proc() SHOULD call DWC_Free for all STRING variables
*/    
/* Reads the set of named variables (vars) from configure file (filename).
   Format of configure file:
    - length of line cannot be greater that DWC_LINE_SIZE
    - each section begin as [SectionName] 
    - beginnig a new section it's end for a previous section
    - each section can have different separators
    - whitespaces are ingored except the case when they are enclosed in double quotes (")
      mean "space" according to the current locale - isspace()
    - lines beginning from # considered as comments    
    - each line are consist from two field <name> and <value> separated by (separator)
      not allowed separators: underscope (_), #, whitespaces, double quote (") or single letter (a-zA-Z)
    - length of name cannot be greater that DWC_NAME_SIZE
    - in name is allowed only next symbols: alphas (a-zA-Z), underscope (_), dot (.)
    - comparision for names and values are case insensitive
    - variables can be only fixed types:
      DWC_CV_INT - signed integer 
      DWC_CV_COUNT - unsigned integer
      DWC_CV_STRING - pointer to char (array of chars not allowed)
        the string would be allocated by read_conf and should be
        freed by DWC_Free()
      DWC_CV_BOOL - boolean, 
        "yes", "on", "true" interpreted as TRUE value,
        "no", "off", "false" interpreted as FALSE value,
      other values - it's error       
*/
/* Example of configure file:
    # Sample conf file

    [Common]
    password = "bad_password"
    
    [Update]
    # URL
    url : www.drweb.ru
    
    # Count of login tries
    try_count : 10
*/    
/* Example of usage:
    extern char            *url;  
    extern unsigned int     tries;
    
    dwc_bool_t read_update( FILE* fs, int *line, const char* sec, void *ignore )
    {
        dwc_conf_set_t   config[] = {
            DWC_CONF_STRING( "host", url, "www.drweb.ru" ),
            DWC_CONF_COUNT( "try_count", tries, 3 ),
            DWC_CONF_ENDLINE };        
        return read_section( fs, line, sec, config, ':', ',' );        
    }
    void clean_update( const char* sec, void *ignore )
    {
        DWC_Free( url );        
    }
    
    ...
        
    int main(void)
    {    
        dwc_conf_task_t  ct[] = {
        ...
        DWC_CONF_TASK( "Update", read_update, clean_update, NULL ),
        ...
        DWC_CONF_ENDTASK }; 
        ...       
        read_conf( "update.conf", ct );
        ...
    }
*/  

#ifdef  __cplusplus
}
#endif

#endif /* _DWC_CONF_H */
