FW: [REQ] generic config struct for parameter value lists

"fred" <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <000501c76a76$d4896dd0$35e0110a@FRED42>
 

-----Original Message-----
From: fred [mailto:[email protected]] 
Sent: 20 March 2007 09:23
To: 'Stipe Tolj'
Subject: RE: [REQ] generic config struct for parameter value lists

I needed such a feature, here is an example:

Here the LHS is a list of reg expressions, match and the substitution expression

mt-dest-addr-regex-subst = "^1([1-9][0-9]{9})$" "$1"
                         = "^0([2-9][0-9]{9})$" "$1"

mo-source-addr-regex-subst = "(^[2-9][0-9]{9})$" "1$1"
                        = "^0([2-9][0-9]{9})$" "1$1" 


All the stuff is in cfg.c, so I'll simply attach my version....


-----Original Message-----
From: Stipe Tolj [mailto:[email protected]]
Sent: 20 March 2007 03:27
To: Kannel Development list
Subject: [REQ] generic config struct for parameter value lists

Hi list,

I have some good input on extending Kannel's config handling abilities:

Currently we have several needs for a config value list, some examples:

   group = smsc
   ...
   accepted-smsc-id = "A;B;C"

   group = sms-service
   ...
   aliases = "key2;key3;key4"

   group = smsbox-route
   ...
   shortcode = "1111;2222;3333"

so, all of these are either of type word-list or id-list, semantically it's a
semicolon seperated list. For some parts we have defined foobar-regex config
directives to handle PCRE/regex for a more simple definition.

The idea now is to create a more generic construct for this, which handles 3
(maybe more?) different ways for any "list-type":

   foobar = "A;B;C"
   foobar-url = "http://somewhere/foobar-list"
   foobar-regex = "<the regex expression>"

so users can *CHOOSE* which way they prefer. And we handle the processing of the
list "transparently" to the logic that requires the list from the config
sections.

I like this concept of abstraction here. Since we would encapsulate the plain,
-url and -regex handling to the scope of gwlib/cfg.{ch] and the other calling
modules simply pull for the list.

Thoughts?

-------------------------------------------------------------------
Kölner Landstrasse 419
40589 Düsseldorf, NRW, Germany

tolj.org system architecture      Kannel Software Foundation (KSF)
http://www.tolj.org/              http://www.kannel.org/

mailto:st_{at}_tolj.org           mailto:stolj_{at}_kannel.org
-------------------------------------------------------------------
cfg.c (text/plain, 23.1 KB)
/* ==================================================================== 
 * The Kannel Software License, Version 1.0 
 * 
 * Copyright (c) 2001-2005 Kannel Group  
 * Copyright (c) 1998-2001 WapIT Ltd.   
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 * 
 * 1. Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer. 
 * 
 * 2. Redistributions in binary form must reproduce the above copyright 
 *    notice, this list of conditions and the following disclaimer in 
 *    the documentation and/or other materials provided with the 
 *    distribution. 
 * 
 * 3. The end-user documentation included with the redistribution, 
 *    if any, must include the following acknowledgment: 
 *       "This product includes software developed by the 
 *        Kannel Group (http://www.kannel.org/)." 
 *    Alternately, this acknowledgment may appear in the software itself, 
 *    if and wherever such third-party acknowledgments normally appear. 
 * 
 * 4. The names "Kannel" and "Kannel Group" must not be used to 
 *    endorse or promote products derived from this software without 
 *    prior written permission. For written permission, please  
 *    contact [email protected]. 
 * 
 * 5. Products derived from this software may not be called "Kannel", 
 *    nor may "Kannel" appear in their name, without prior written 
 *    permission of the Kannel Group. 
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 * ==================================================================== 
 * 
 * This software consists of voluntary contributions made by many 
 * individuals on behalf of the Kannel Group.  For more information on  
 * the Kannel Group, please see <http://www.kannel.org/>. 
 * 
 * Portions of this software are based upon software originally written at  
 * WapIT Ltd., Helsinki, Finland for the Kannel project.  
 */ 

/*
 * cfg.c - configuration file handling
 *
 * Lars Wirzenius
 */


#include "gwlib/gwlib.h"

/* for include dir */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

struct CfgGroup {
    Octstr *name;
    Dict *vars;
    Octstr *configfile; 
    long line; 
};


static CfgGroup *create_group(void)
{
    CfgGroup *grp;
    
    grp = gw_malloc(sizeof(*grp));
    grp->name = NULL;
    grp->vars = dict_create(64, octstr_destroy_item);
    grp->configfile = NULL; 
    grp->line = 0; 
    return grp;
}

static void destroy_group(void *arg)
{
    CfgGroup *grp;
    List *names;
    Octstr *name=0;
   
    if (arg != NULL) 
	{
		grp = arg;
		names = dict_keys(grp->vars);
		while ((name = gwlist_extract_first(names)) != NULL) 
		{
			if(cfg_type_(name)==TYP_OCTSTRARY)
			{
				cfg_destroy_list(grp,name);
			}
            octstr_destroy(name); 
		}
		octstr_destroy(grp->name);
		octstr_destroy(grp->configfile);

		
		dict_destroy(grp->vars);
		gw_free(grp);
    }
}


struct CfgLoc { 
    Octstr *filename; 
    long line_no; 
    Octstr *line; 
}; 


static CfgLoc *cfgloc_create(Octstr *filename) 
{ 
    CfgLoc *cfgloc; 
     
    cfgloc = gw_malloc(sizeof(*cfgloc)); 
    cfgloc->filename = octstr_duplicate(filename); 
    cfgloc->line_no = 0; 
    cfgloc->line = NULL; 
    return cfgloc; 
} 
 
 
static void cfgloc_destroy(CfgLoc *cfgloc) 
{ 
    if (cfgloc != NULL) { 
		octstr_destroy(cfgloc->filename); 
		octstr_destroy(cfgloc->line); 
		gw_free(cfgloc); 
    } 
} 

 
static void destroy_group_list(void *arg)
{
    gwlist_destroy(arg, destroy_group);
}


static void set_group_name(CfgGroup *grp, Octstr *name)
{
    octstr_destroy(grp->name);
    grp->name = octstr_duplicate(name);
}


struct Cfg {
    Octstr *filename;
    Dict *single_groups;
    Dict *multi_groups;
};


static int is_allowed_in_group(Octstr *group, Octstr *variable)
{
    Octstr *groupstr;
    
    groupstr = octstr_imm("group");

    #define OCTSTR(name) \
    	if (octstr_compare(octstr_imm(#name), variable) == 0) \
	    return 1;
    #define OCTSTRARY(name) \
    	if (octstr_compare(octstr_imm(#name), variable) == 0) \
	    return 1;
    #define SINGLE_GROUP(name, fields) \
    	if (octstr_compare(octstr_imm(#name), group) == 0) { \
	    if (octstr_compare(groupstr, variable) == 0) \
		return 1; \
	    fields \
	    return 0; \
	}
    #define MULTI_GROUP(name, fields) \
    	if (octstr_compare(octstr_imm(#name), group) == 0) { \
	    if (octstr_compare(groupstr, variable) == 0) \
		return 1; \
	    fields \
	    return 0; \
	}
    #include "cfg.def"

    return 0;
}


static int is_single_group(Octstr *query)
{
    #define OCTSTR(name)
    #define OCTSTRARY(name) 
    #define SINGLE_GROUP(name, fields) \
    	if (octstr_compare(octstr_imm(#name), query) == 0) \
	    return 1;
    #define MULTI_GROUP(name, fields) \
    	if (octstr_compare(octstr_imm(#name), query) == 0) \
	    return 0;
    #include "cfg.def"
    return 0;
}


static int add_group(Cfg *cfg, CfgGroup *grp)
{
    Octstr *groupname;
    Octstr *name;
    List *names;
    List *list;
    
    groupname = cfg_get(grp, octstr_imm("group"));
    if (groupname == NULL) {
		error(0, "Group does not contain variable 'group'.");
    	return -1;
    }
    set_group_name(grp, groupname);

    names = dict_keys(grp->vars);
    while ((name = gwlist_extract_first(names)) != NULL) 
	{
		if (!is_allowed_in_group(groupname, name)) 
		{
			error(0, "Group '%s' may not contain field '%s'.",
			octstr_get_cstr(groupname), octstr_get_cstr(name));
			octstr_destroy(name);
			octstr_destroy(groupname);
			gwlist_destroy(names, octstr_destroy_item);
			return -1;
		}
		octstr_destroy(name);
    }
    gwlist_destroy(names, NULL);

    if (is_single_group(groupname))
    	dict_put(cfg->single_groups, groupname, grp);
    else {
	list = dict_get(cfg->multi_groups, groupname);
	if (list == NULL) {
	    list = gwlist_create();
	    dict_put(cfg->multi_groups, groupname, list);
	}
    	gwlist_append(list, grp);
    }

    octstr_destroy(groupname);
    return 0;
}


Cfg *cfg_create(Octstr *filename)
{
    Cfg *cfg;
    
    cfg = gw_malloc(sizeof(*cfg));
    cfg->filename = octstr_duplicate(filename);
    cfg->single_groups = dict_create(64, destroy_group);
    cfg->multi_groups = dict_create(64, destroy_group_list);
    return cfg;
}


void cfg_destroy(Cfg *cfg)
{

    if (cfg != NULL) {
		octstr_destroy(cfg->filename);

		dict_destroy(cfg->single_groups);
		dict_destroy(cfg->multi_groups);
		gw_free(cfg);
    }
}


static void parse_value(Octstr *value)
{
    Octstr *temp;
    long len;
    int c;
    
    octstr_strip_blanks(value);

    len = octstr_len(value);
    if (octstr_get_char(value, 0) != '"' || 
        octstr_get_char(value, len - 1) != '"')
	return;

    octstr_delete(value, len - 1, 1);
    octstr_delete(value, 0, 1);

    temp = octstr_duplicate(value);
    octstr_truncate(value, 0);
    
    while (octstr_len(temp) > 0) {
	c = octstr_get_char(temp, 0);
	octstr_delete(temp, 0, 1);
	
    	if (c != '\\' || octstr_len(temp) == 0)
	    octstr_append_char(value, c);
	else {
	    c = octstr_get_char(temp, 0);
	    octstr_delete(temp, 0, 1);

	    switch (c) {
    	    case '\\':
    	    case '"':
	    	octstr_append_char(value, c);
	    	break;
		
    	    default:
	    	octstr_append_char(value, '\\');
	    	octstr_append_char(value, c);
		break;
	    }
	}
    }
    
    octstr_destroy(temp);
}


static List *expand_file(Octstr *file, int forward) 
{
    Octstr *os;
    Octstr *line;
    List *lines; 
    List *expand; 
    long lineno; 
    CfgLoc *loc; 
 
    os = octstr_read_file(octstr_get_cstr(file)); 
    if (os == NULL) 
    	return NULL; 
 
    lines = octstr_split(os, octstr_imm("\n")); 
    lineno = 0; 
    expand = gwlist_create(); 
              
    while ((line = gwlist_extract_first(lines)) != NULL) { 
        ++lineno; 
        loc = cfgloc_create(file); 
        loc->line_no = lineno; 
        loc->line = line; 
        if (forward) 
            gwlist_append(expand, loc); 
        else 
            gwlist_insert(expand, 0, loc); 
    } 
    
    /* 
     * add newline at each end of included files to avoid 
     * concatenating different groups by mistake
     */
    if (lineno > 0) {
        loc = cfgloc_create(file); 
        loc->line_no = lineno;
        loc->line = octstr_create("\n");
        if (forward) 
            gwlist_append(expand, loc); 
        else 
            gwlist_insert(expand, 0, loc); 
    }
         
    gwlist_destroy(lines, octstr_destroy_item); 
    octstr_destroy(os); 
 
    return expand; 
} 
 
 
int cfg_read(Cfg *cfg) 
{ 
    CfgLoc *loc; 
    CfgLoc *loc_inc; 
    List *lines;
    List *expand; 
    List *stack; 
    Octstr *name;
    Octstr *value;
    Octstr *filename; 
    CfgGroup *grp;
	List *valuelist=0;
    long equals;
    long lineno;
    long error_lineno;
    
    loc = loc_inc = NULL;

    /* 
     * expand initial main config file and add it to the recursion 
     * stack to protect against cycling 
     */ 
    if ((lines = expand_file(cfg->filename, 1)) == NULL) { 
        panic(0, "Failed to load main configuration file `%s'. Aborting!", 
              octstr_get_cstr(cfg->filename)); 
    } 
    stack = gwlist_create(); 
    gwlist_insert(stack, 0, octstr_duplicate(cfg->filename)); 

    grp = NULL;
    lineno = 0;
    error_lineno = 0;
    while (error_lineno == 0 && (loc = gwlist_extract_first(lines)) != NULL) 
	{ 
        octstr_strip_blanks(loc->line); 
        if (octstr_len(loc->line) == 0) 
		{ 
            if (grp != NULL && add_group(cfg, grp) == -1) { 
                error_lineno = loc->line_no; 
                destroy_group(grp); 
            } 
            grp = NULL; 
        } 
		else if (octstr_get_char(loc->line, 0) != '#') 
		{ 
            equals = octstr_search_char(loc->line, '=', 0); 
            if (equals == -1) { 
                error(0, "An equals sign ('=') is missing on line %ld of file %s.", 
                      loc->line_no, octstr_get_cstr(loc->filename)); 
                error_lineno = loc->line_no; 
            } 
			else  
             
            /* 
             * check for special config directives, like include or conditional 
             * directives here 
             */ 
            if (octstr_search(loc->line, octstr_imm("include"), 0) != -1) 
			{ 
                filename = octstr_copy(loc->line, equals + 1, octstr_len(loc->line)); 
                parse_value(filename); 
 
                /* check if we are cycling */ 
                if (gwlist_search(stack, filename, octstr_item_match) != NULL) { 
                    panic(0, "Recursive include for config file `%s' detected " 
                             "(on line %ld of file %s).", 
                          octstr_get_cstr(filename), loc->line_no,  
                          octstr_get_cstr(loc->filename)); 
                } else {     
                    List *files = gwlist_create();
                    Octstr *file;
                    struct stat filestat;

                    /* check if included file is a directory */
                    lstat(octstr_get_cstr(filename), &filestat);

                    /* 
                     * is a directory, create a list with files of
                     * this directory and load all as part of the
                     * whole configuration.
                     */
                    if (S_ISDIR(filestat.st_mode)) {
                        DIR *dh;
                        struct dirent *diritem;

                        debug("gwlib.cfg", 0, "Loading include dir `%s' "
                              "(on line %ld of file %s).",  
                              octstr_get_cstr(filename), loc->line_no,  
                              octstr_get_cstr(loc->filename)); 

                        dh = opendir(octstr_get_cstr(filename));
                        while ((diritem = readdir(dh))) {
                            Octstr *fileitem;

                            fileitem = octstr_duplicate(filename);
                            octstr_append(fileitem, octstr_create("/"));
                            octstr_append(fileitem, octstr_create(diritem->d_name));

                            lstat(octstr_get_cstr(fileitem), &filestat);
                            if (!S_ISDIR(filestat.st_mode)) {
                                gwlist_insert(files, 0, fileitem);
                            }
                        }
                        closedir(dh);
                    } 
		    
                    /* is a file, create a list with it */
                    else {
                        gwlist_insert(files, 0, octstr_duplicate(filename));
                    }

                    /* include files */
                    while ((file = gwlist_extract_first(files)) != NULL) 
					{

                        gwlist_insert(stack, 0, octstr_duplicate(file)); 
                        debug("gwlib.cfg", 0, "Loading include file `%s' (on line %ld of file %s).",  
                              octstr_get_cstr(file), loc->line_no,  
                              octstr_get_cstr(loc->filename)); 

                        /*  
                         * expand the given include file and add it to the current 
                         * processed main while loop 
                         */ 
                        if ((expand = expand_file(file, 0)) != NULL) {
                            while ((loc_inc = gwlist_extract_first(expand)) != NULL) 
                                gwlist_insert(lines, 0, loc_inc); 
                        } else { 
                            panic(0, "Failed to load whole configuration. Aborting!"); 
                        } 
                 
                        gwlist_destroy(expand, NULL); 
                        cfgloc_destroy(loc_inc);
                        octstr_destroy(file);
                    }
                    gwlist_destroy(files, octstr_destroy_item);
                } 
                octstr_destroy(filename); 
            }  
             
            /* 
             * this is a "normal" line, so process it accodingly 
             */ 
            else  
			{ 
				int cfg_type;
				if (grp == NULL)
                    grp = create_group(); 

                if (grp->configfile != NULL) 
				{
                    octstr_destroy(grp->configfile); grp->configfile=NULL;
                }
                grp->configfile = octstr_duplicate(cfg->filename); 

                name = octstr_copy(loc->line, 0, equals); 
                octstr_strip_blanks(name); 
                value = octstr_copy(loc->line, equals + 1, octstr_len(loc->line)); 
				
				cfg_type = cfg_type_(name);

				if(octstr_len(name) > 0 )		// a line starting with a name stops/starts an array
				{
					if(cfg_type == TYP_OCTSTRARY )	// consecutive lines starting with '=' are part of this list
					{
						valuelist = gwlist_create(); 
						cfg_set_list(grp, name, valuelist); 
					}
					else if(valuelist) 
					{
						valuelist=0;
					}
				}

				if(valuelist)
				{
					gwlist_insert(valuelist, 0, octstr_duplicate(value)); 
				}
				else
				{
					if(octstr_len(name) ==0)
					{
		                error(0, "line is not an array setting: line %ld file %s.", 
								loc->line_no, octstr_get_cstr(loc->filename)); 
						error_lineno = loc->line_no; 
						break;
					}

					parse_value(value); 
					cfg_set(grp, name, value); 
				}
				
                octstr_destroy(name); 
                octstr_destroy(value); 
			} 
		} 

        cfgloc_destroy(loc); 
    }

    if (grp != NULL && add_group(cfg, grp) == -1) {
        error_lineno = 1; 
        destroy_group(grp); 
    }

    gwlist_destroy(lines, NULL); 
    gwlist_destroy(stack, octstr_destroy_item); 

    if (error_lineno != 0) {
        error(0, "Error found on line %ld of file `%s'.",  
	          error_lineno, octstr_get_cstr(cfg->filename)); 
        return -1; 
    }

    return 0;
}


CfgGroup *cfg_get_single_group(Cfg *cfg, Octstr *name)
{
    return dict_get(cfg->single_groups, name);
}


List *cfg_get_multi_group(Cfg *cfg, Octstr *name)
{
    List *list, *copy;
    long i;
    
    list = dict_get(cfg->multi_groups, name);
    if (list == NULL)
    	return NULL;

    copy = gwlist_create();
    for (i = 0; i < gwlist_len(list); ++i)
    	gwlist_append(copy, gwlist_get(list, i));
    return copy;
}


Octstr *cfg_get_group_name(CfgGroup *grp)
{
    return octstr_duplicate(grp->name);
}

Octstr *cfg_get_configfile(CfgGroup *grp)
{
    return octstr_duplicate(grp->configfile);
}


Octstr *cfg_get_real(CfgGroup *grp, Octstr *varname, const char *file, 
    	    	     long line, const char *func)
{
    Octstr *os;

    if(grp == NULL) 
    	panic(0, "Trying to fetch variable `%s' in non-existing group",
	      octstr_get_cstr(varname));

    if (grp->name != NULL && !is_allowed_in_group(grp->name, varname))
    	panic(0, "Trying to fetch variable `%s' in group `%s', not allowed.",
	      octstr_get_cstr(varname), octstr_get_cstr(grp->name));

    os = dict_get(grp->vars, varname);
    if (os == NULL)
    	return NULL;
    return gw_claim_area_for(octstr_duplicate(os), file, line, func);
}


int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
{
    Octstr *os;
    int ret;
    
    os = cfg_get(grp, varname);
    if (os == NULL)
    	return -1;
    if (octstr_parse_long(n, os, 0, 0) == -1)
    	ret = -1;
    else
    	ret = 0;
    octstr_destroy(os);
    return ret;
}


int cfg_get_longlong(longlong_t *n, CfgGroup *grp, Octstr *varname)
{
    Octstr *os;
    int ret=0;
    
    os = cfg_get(grp, varname);
    if (os == NULL)
    	return -1;
    if (octstr_parse_longlongnumber(n, os, 0) == -1)
		if(errno == EINVAL || errno == ERANGE)
    		ret = -1;
    
    octstr_destroy(os);
    return ret;
}


int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
{
    Octstr *os;

    os = cfg_get(grp, varname);
    if (os == NULL) {
		*n = 0;
    	return -1;
    }
    if (octstr_case_compare(os, octstr_imm("true")) == 0
	|| octstr_case_compare(os, octstr_imm("yes")) == 0
	|| octstr_case_compare(os, octstr_imm("on")) == 0
	|| octstr_case_compare(os, octstr_imm("1")) == 0)
    {	    
	*n = 1;
    } else if (octstr_case_compare(os, octstr_imm("false")) == 0
	|| octstr_case_compare(os, octstr_imm("no")) == 0
	|| octstr_case_compare(os, octstr_imm("off")) == 0
	|| octstr_case_compare(os, octstr_imm("0")) == 0)
    {
		*n = 0;
    }
    else {
		*n = 1;
		warning(0, "bool variable set to strange value, assuming 'true'");
    }
    octstr_destroy(os);
    return 0;
}


List *cfg_get_list(CfgGroup *grp, Octstr *varname)
{
    List *list;
    
    if(grp == NULL) 
    	panic(0, "Trying to fetch variable `%s' in non-existing group",
	      octstr_get_cstr(varname));

    if (grp->name != NULL && !is_allowed_in_group(grp->name, varname))
    	panic(0, "Trying to fetch variable `%s' in group `%s', not allowed.",
	      octstr_get_cstr(varname), octstr_get_cstr(grp->name));

    list = dict_get(grp->vars, varname);
    if (list == NULL)
    	return NULL;


    return list;
}


/**
 * read config lines like
 * source-addr-regex-subst = "(^[2-9][0-9]{9})" "1$1"
 *						   = "(^0[2-9][0-9]{9})" "1$1"
 *
 *
 */
List *cfg_get_lineslist(CfgGroup *grp, Octstr *varname)
{
    Octstr *os;
    List *list;
    
    os = cfg_get(grp, varname);
    if (os == NULL)
    	return NULL;

    list = octstr_split_words(os);
    octstr_destroy(os);
    return list;
}



void cfg_set(CfgGroup *grp, Octstr *varname, Octstr *value)
{
    dict_put(grp->vars, varname, octstr_duplicate(value));
}


void cfg_set_list(CfgGroup *grp, Octstr *varname, List *value)
{
    List *list;
    list = dict_get(grp->vars, varname);
	if(list)
	{
		gwlist_destroy(list,octstr_destroy_item);
		dict_remove(grp->vars, varname);
	}
    dict_put(grp->vars, varname, value);
}

void cfg_destroy_list(CfgGroup *grp, Octstr *name)
{
	List *valuelist=0;
	valuelist = cfg_get_list(grp, name);
	gwlist_destroy(valuelist,octstr_destroy_item);
	dict_remove(grp->vars, name);
}


void grp_dump(CfgGroup *grp)
{
    List *names;
    Octstr *name;
    Octstr *value;
	List *valuelist=0;
	long listlen;
	long i;

    if (grp->name == NULL)
	debug("gwlib.cfg", 0, "  dumping group (name not set):");
    else
	debug("gwlib.cfg", 0, "  dumping group (%s):",
	      octstr_get_cstr(grp->name));
    names = dict_keys(grp->vars);
    while ((name = gwlist_extract_first(names)) != NULL) 
	{
		if(cfg_type_(name)==TYP_OCTSTRARY)
		{
			valuelist = cfg_get_list(grp, name);
			listlen = gwlist_len(valuelist);
			for(i=0;i<listlen;i++)
			{
				value = gwlist_get(valuelist,i);
				debug("gwlib.cfg", 0, "    <%s> = <%s>", 
					octstr_get_cstr(name), octstr_get_cstr(value));
			}

    		octstr_destroy(name);

		}
		else
		{
			value = cfg_get(grp, name);
			debug("gwlib.cfg", 0, "    <%s> = <%s>", 
				octstr_get_cstr(name), octstr_get_cstr(value));
    		octstr_destroy(value);
    		octstr_destroy(name);
		}
    }
    gwlist_destroy(names, NULL);
}


void cfg_dump(Cfg *cfg)
{
    CfgGroup *grp;
    List *list;
    List *names;
    Octstr *name;

    debug("gwlib.cfg", 0, "Dumping Cfg %p", (void *) cfg);
    debug("gwlib.cfg", 0, "  filename = <%s>", 
    	  octstr_get_cstr(cfg->filename));

    names = dict_keys(cfg->single_groups);
    while ((name = gwlist_extract_first(names)) != NULL)
	{
		grp = cfg_get_single_group(cfg, name);
		if (grp != NULL)
			grp_dump(grp);
    	octstr_destroy(name);
    }
    gwlist_destroy(names, NULL);

    names = dict_keys(cfg->multi_groups);
    while ((name = gwlist_extract_first(names)) != NULL) 
	{
		list = cfg_get_multi_group(cfg, name);
		while ((grp = gwlist_extract_first(list)) != NULL)
			grp_dump(grp);

		gwlist_destroy(list, NULL);
    	octstr_destroy(name);
    }
    gwlist_destroy(names, NULL);

    debug("gwlib.cfg", 0, "Dump ends.");
}

void cfg_dump_all(void)
{
    #define OCTSTR(name) \
        printf("%s = <please consult user doc>\n", #name);

    #define OCTSTRARY(name) \
		printf("OCTSTRARY %s <please consult user doc>\n", #name);

    #define SINGLE_GROUP(name, fields) \
        printf("#\n#  Single Group\n#\n"); \
        printf("group = %s\n", #name); \
        fields; \
        printf("\n\n");

    #define MULTI_GROUP(name, fields) \
        printf("#\n#  Multi Group\n#\n"); \
        printf("group = %s\n", #name); \
        fields; \
        printf("\n\n");

    #include "cfg.def"
}

int cfg_type_(Octstr *configname)
{
	#define OCTSTR(name) \
    	if (octstr_compare(octstr_imm(#name), configname) == 0) \
	    return TYP_OCTSTR;
		
	#define OCTSTRARY(name) \
    	if (octstr_compare(octstr_imm(#name), configname) == 0) \
	    return TYP_OCTSTRARY;

    #define SINGLE_GROUP(name, fields) fields

    #define MULTI_GROUP(name, fields)  fields

    #include "cfg.def"

	return TYP_NONE;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.