//-----------------------------------------------------------------------------
// Copyright © 2003 - Philip Howard - All rights reserved
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//-----------------------------------------------------------------------------
// package	libh/io
// homepage	http://libh.slashusr.org/
//-----------------------------------------------------------------------------
// author	Philip Howard
// email	libh at ipal dot org
// homepage	http://phil.ipal.org/
//-----------------------------------------------------------------------------
// This file is best viewed using a fixed spaced font such as Courier
// and in a display at least 120 columns wide.
//-----------------------------------------------------------------------------

#include "io_lib.h"

__PROTO_BEGIN__
//-----------------------------------------------------------------------------
// function	get_config_map
//
// purpose	Get a config stream and return a loaded mapping.
//
// arguments	1 (MAP *) optional mapping to load, else one is created
//		2 (FILE *) pointer to open file to read from
//		3 (size_t) size to buffer item name
//		4 (size_t) size to buffer item data
//		5 (int) options as follows:
//			GET_CONFIG_MAP_DUP : allow duplicate entries
//
// returns	(MAP) the given or created mapping
//		(MAP) NULL : error
//
// note		Single or double quotes are supported without nesting them.
//		Quoted strings must be ended by the same quote.  Mismatched
//		quotes within just become data.
//
// note		Sequences of space characters (space and tab) are reduced to
//		a single space character, unless enclosed in quotes.
//
// note		Conversion of character sequences beginning with backslash are
//		supported for both certain escape codes as well as conversion
//		of octal.
//
// note		Conversion of character sequences beginning with percent sign
//		are supported for conversion of cetal/hexadecimal.
//
// note		Conversion of character sequences beginning with carat are
//		supported for encoding of control characters.
//
// note		An end of line is considered to be any combination and order
//		of not more than one instance each of the four line breaking
//		characters:
//			'\n' (newline)
//			'\r' (carriage return)
//			'\f' (form feed)
//			'\v' (vertical tab)
//		If a character is encountered a 2nd time, it is considered to
//		begin a 2nd line ending, and hence an empty line.
//
// note		If the very first character of a line is a '+' then it is a
//		continuation of the previous line as if the preceeding new
//		line sequence and the following '+' were not present.
//-----------------------------------------------------------------------------
#define GET_CONFIG_MAP_DUP	0x0001

MAP
get_config_map (
    MAP		arg_map
    ,
    FILE *	arg_file
    ,
    size_t	arg_name_len
    ,
    size_t	arg_data_len
    ,
    int		arg_options
    )
__PROTO_END__
{
    MAP			this_map	;

    char *		name_ptr	;
    char *		data_ptr	;

    size_t		name_len	;
    size_t		data_len	;

    int			trunc		;


    //-----------------
    // Check arguments.
    //-----------------
    if ( ! arg_file ) {
	arg_file = stdin;
    }
    if ( arg_map ) {
	this_map = arg_map;
    } else {
	if ( ! ( this_map = map_uca_new() ) ) {
	    return NULL;
	}
    }

    //-----------------------
    // Allocate buffer space.
    //-----------------------
    if ( ! ( name_ptr = alloca( arg_name_len ) ) ||
	 ! ( data_ptr = alloca( arg_data_len ) ) ) {
	if ( ! arg_map ) {
	    map_destroy( this_map );
	}
	return NULL;
    }

    //---------------------------------------------
    // Read all config items and load into mapping.
    //---------------------------------------------
    for (;;) {
	int rc;

	rc = get_config_item( name_ptr, arg_name_len, & name_len,
				  data_ptr, arg_data_len, & data_len,
				  arg_file, & trunc );

	if ( rc < 0 ) break;

	if ( rc >= 0 ) {
	    if ( ( ( arg_options & GET_CONFIG_MAP_DUP ) ?
		   ( map_uca_insert_dup( this_map, (unsigned char *) name_ptr, name_len ) ) :
		   ( map_uca_insert( this_map, (unsigned char *) name_ptr, name_len ) )
		 ) >= 0 &&
		 rc >= 2
	       ) {
		map_uca_store( this_map, (unsigned char *) data_ptr, data_len );
	    }
	}
    }

    //--------------------------------------------------
    // Return the (possibly created and) loaded mapping.
    //--------------------------------------------------
    return this_map;
    
}

