#![warn(missing_docs)]
//! Parse configuration files.
//!
//! The `confget` library parses configuration files (currently INI-style
//! files only) and allows a program to use the values defined in them.
//! It provides various options for selecting the variable names and
//! values to return and the configuration file sections to fetch them from.
//!
//! The `confget` library may also be used as a command-line tool with
//! the same interface as the C implementation.
//!
//! # Quick-and-easy parsing of INI-style files
//!
//! The [read_ini_file][`crate::read_ini_file`] function will parse
//! an INI-style file and return a hashmap of the values found in its
//! various sections, as well as the name of the first section found in
//! the file (or the one specified in the configuration if
//! the [section_override][`crate::defs::Config::section_override`] option
//! is enabled).
//!
//! ```
//! # use std::error;
//! # use std::fs;
//! # use std::path;
//!
//! # fn main() -> Result<(), Box<dyn error::Error>> {
//! # let tempd_obj = tempfile::tempdir()?;
//! # let confdir: &path::Path = tempd_obj.as_ref();
//! # fs::write(&confdir.join("config.ini"), "var = value\n");
//! // Default configuration except for the filename.
//! let config = confget::Config {
//!     filename: Some(confdir.join("config.ini").to_str().unwrap().to_string()),
//!     ..confget::Config::default()
//! };
//! let (data, first_section) = confget::read_ini_file(&config)?;
//! # Ok(())
//! # }
//! ```
//!
//! For the crate's change history, see
//! the [CHANGES](https://gitlab.com/confget/confget/-/blob/master/CHANGES)
//! file in the source distribution.

#![doc(html_root_url = "https://docs.rs/confget/4.1.0")]
/**
 * Copyright (c) 2021  Peter Pentchev <roam@ringlet.net>
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS 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 AUTHOR OR 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.
 */
use std::error;

use crate::backend::Backend;

pub mod backend;
pub mod defs;
pub mod format;

pub use defs::{ConfgetError, Config};

/// Construct an object of the specified backend type.
///
/// The `backend` member of the [Config][`crate::defs::Config`] object
/// specifies the type of the backend to construct.
///
/// Some backends may perform validation at object creation time;
/// the "ini" one currently does not, so this method will always succeed.
pub fn get_backend<'a>(
    config: &'a defs::Config,
) -> Result<Box<dyn backend::Backend + 'a>, Box<dyn error::Error>> {
    match config.backend {
        defs::BackendKind::Ini => Ok(Box::new(backend::ini::IniBackend { config })),
    }
}

/// Read an INI-style file with the specified configuration.
///
/// Internally constructs an "ini" backend and invokes its
/// [read_file][`crate::backend::Backend::read_file`] method.
/// The [Config][`crate::defs::Config`] object's `filename`
/// member must contain a value.
pub fn read_ini_file(config: &defs::Config) -> Result<backend::DataRead, Box<dyn error::Error>> {
    let ini = backend::ini::IniBackend { config };
    ini.read_file()
}
