Git Product home page Git Product logo

rust-ini's Introduction

INI in Rust

Build & Test crates.io doc.rs

INI is an informal standard for configuration files for some platforms or software. INI files are simple text files with a basic structure composed of "sections" and "properties".

This is an INI file parser in Rust.

[dependencies]
rust-ini = "0.21"

Usage

  • Create a Ini configuration file.
extern crate ini;
use ini::Ini;

fn main() {
    let mut conf = Ini::new();
    conf.with_section(None::<String>)
        .set("encoding", "utf-8");
    conf.with_section(Some("User"))
        .set("given_name", "Tommy")
        .set("family_name", "Green")
        .set("unicode", "Raspberry树莓");
    conf.with_section(Some("Book"))
        .set("name", "Rust cool");
    conf.write_to_file("conf.ini").unwrap();
}

Then you will get conf.ini

encoding=utf-8

[User]
given_name=Tommy
family_name=Green
unicode=Raspberry\x6811\x8393

[Book]
name=Rust cool
  • Read from file conf.ini
use ini::Ini;

fn main() {
    let conf = Ini::load_from_file("conf.ini").unwrap();

    let section = conf.section(Some("User")).unwrap();
    let tommy = section.get("given_name").unwrap();
    let green = section.get("family_name").unwrap();

    println!("{:?} {:?}", tommy, green);

    // iterating
    for (sec, prop) in &conf {
        println!("Section: {:?}", sec);
        for (key, value) in prop.iter() {
            println!("{:?}:{:?}", key, value);
        }
    }
}
  • More details could be found in examples.

License

The MIT License (MIT)

Copyright (c) 2014 Y. T. CHUNG

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

rust-ini's People

Contributors

aegoroff avatar alexxroche avatar arucil avatar ccll avatar chocobo1 avatar crapstone avatar dinduks avatar dns2utf8 avatar gautamg795 avatar gnomeddev avatar hmvp avatar joshuachp avatar jplatte avatar loewenheim avatar mitsuhiko avatar nooberfsh avatar ovibos avatar piranha avatar rhi-gray avatar rouhim avatar ryanwohara avatar sebastiengllmt avatar simonteixidor avatar sirhcel avatar sylvestre avatar taiki-e avatar thommay avatar tshepang avatar xxchan avatar zonyitoo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rust-ini's Issues

Wrong parsing result with 'inline-comment' feature

With 'inline-comment' feature enabled, the library will parse the following data wrong:

[section]
key=val#a

Library will give:

Section: Some("section")
key:val  <-- error here, should be "val#a"

The problem is at:

self.parse_str_until(&[Some('\n'), Some('\r'), Some(';'), Some('#'), None])

The delimiter for comments should include at least one space, for example " #" and " ;" instead of just a single character.

From https://en.wikipedia.org/wiki/INI_file#Comments_2:

In some implementations, a comment may begin anywhere on a line after a space (inline comments), including on the same line after properties or section declarations.

Attaching a test case for it:

    #[test]
    #[cfg(feature = "inline-comment")]
    fn inline_comment() {
        let input = "
[section name] # comment in section line
name = hello # abcdefg
gender = mail  ; abdddd
address = web#url ;# eeeeee
";
        let ini = Ini::load_from_str(input).unwrap();
        assert_eq!(ini.get_from(Some("section name"), "name").unwrap(), "hello");
        assert_eq!(ini.get_from(Some("section name"), "gender").unwrap(), "mail");
        assert_eq!(ini.get_from(Some("section name"), "address").unwrap(), "web#url");
    }

[REGRESSION] Setting/Getting values fails when upgrading from version 0.13 to 0.14 or 0.15

The following test succeeded using version 0.13, but fails with versions 0.14 and 0.15.

#[test]
fn test_set_get() {
    let section = "PHP";
    let key = "engine";
    let value = "On";
    let new_value = "Off";

    // create a new configuration
    let mut conf = Ini::new();
    conf.with_section(Some(section)).set(key, value);

    // assert the value is the one expected
    let v = conf.get_from(Some(section), key).unwrap();
    assert_eq!(v, value);

    // update the section/key with a new value
    conf.set_to(Some(section), key.to_string(), new_value.to_string());

    // assert the new value was set
    let v = conf.get_from(Some(section), key).unwrap();
    assert_eq!(v, new_value);
}

Error message:

test php::conf::tests::test_ini ... thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `"On"`,
 right: `"Off"`'
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
FAILED

Unstable features

Unable to compile as dependency atm
/rust-ini-0.4.3/src/lib.rs:48:1: 48:16 error: unstable feature

Maybe it should returns error when there are lines without `=`

given the following example:

use ini::Ini;
fn main() {
    let tmp = Ini::load_from_str(
        r#"
"[options]
PgpFetch
DevelSuffixes = -git"#,
    );
    println!("{tmp:?}");
}

Currently what it returns: Ok(Ini { sections: {None: Properties { data: {"\"[options]\nPgpFetch\nDevelSuffixes": "-git"} }} }).
The first line doesn't contains =, I think it should returns error rather than return a property key which contains \n.

include LICENSE text

It would be very useful for us (Fedora) to have license text as a file in crate in order to package this project.

Thanks!

fails on .ini files with comment in the final line

minimal failing example:

// parse.rs
extern crate ini;
use ini::Ini;

  pub fn main() {

  let conf = Ini::load_from_file("fvwm.desktop");
  match conf {
      Ok(c) => {
           println!("ok for file {}", f);
           for (sec, prop) in c.iter() {
              println!("Section: {:?}", sec);
              for (key, value) in prop.iter() {
                  println!("{:?}:{:?}", key, value);
              }
          }
      }
      Err(e) => {
          println!("error in file {}: {}", f, e);
      }
  }

and input file (in the same directory)

## fvwm.desktop ##

[Desktop Entry]
Name=Fvwm
Comment=Fvwm
Exec=fvwm2
Terminal=False
TryExec=fvwm2
Type=Application

[Window Manager]
SessionManaged=true

##

then doing

cargo run

fails with error

error: 14:0 Expecting "[Some('=')]" but found EOF.

now github issue markdown doesn't do line numbers, but that's the last line. removing it makes everything work.

i haven't looked into the source yet, but if you need i could look into providing a patch sometime around the weekend maybe.

cargo build error

I got this after 'cargo build' :

 Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading rust-ini v0.8.0
 Compiling log v0.3.1
 Compiling rust-ini v0.8.0
 /Users/igork/.cargo/registry/src/github.com-1ecc6299db9ec823/rust-ini-0.8.0/src/lib.rs:46:1: 46:16 error: unstable feature
/Users/igork/.cargo/registry/src/github.com-1ecc6299db9ec823/rust-ini-0.8.0/src/lib.rs:46 #![feature(io)]
                                                                                             ^~~~~~~~~~~~~~~
note: this feature may not be used in the stable release channel
error: aborting due to previous error
Could not compile `rust-ini`.

Incorrect parsing section names that contain brackets i.e. []

simple test

        let config = r###"
[[*]]
a = b
c = d
"###;
        let conf = Ini::load_from_str(config).unwrap();

        for (sec, prop) in &conf {
            println!("Section: {:?}", sec);
            for (key, value) in prop.iter() {
                println!("{:?}:{:?}", key, value);
            }
        }

Outputs

Section: Some("[*")
"]\na":"b"
"c":"d"

instead of

Section: Some("[*]")
"a":"b"
"c":"d"

a way to remove a key-value pair

Using the following as an example

[section]
key = value-1
key = value-2

How do I remove key = value-2?

Closest I could get is Properties::remove, but that removes the first pair (according to docs).

Hi, Can you add new features?

Hi, can you add two features? Modify the content, increase the content, such as:

i["User", "name"] the original value is "hi", change its value to "hey" and writed file

Add one at the end of the conf.ini file
[add]
Name=ok

This user is more convenient to operate ini? Thank you!

Creating new config with_section(None) seems broken

the example code below
Usage
Create a Ini configuration file.
results in the following error:
error[E0283]: type annotations needed
96 | conf.with_section(None)
| ^^^^^^^^^^^^ cannot infer type for type parameter S declared on the associated function with_section
|
= note: cannot satisfy _: std::convert::Into<std::string::String>

Please excuse if the fault is on my side,
i am a bit new to Rust, thus i have no idea yet how to suggest a fix.

install in rust-1.0.0-beta with Cargo is failed

% rustc --version
rustc 1.0.0-beta (9854143cb 2015-04-02) (built 2015-04-02)
% cargo build
    Updating registry `https://github.com/rust-lang/crates.io-index`
   Compiling rust-ini v0.4.3
/home/biziwalker/.cargo/registry/src/github.com-1ecc6299db9ec823/rust-ini-0.4.3/src/lib.rs:48:1: 48:16 error: unstable feature
/home/biziwalker/.cargo/registry/src/github.com-1ecc6299db9ec823/rust-ini-0.4.3/src/lib.rs:48 #![feature(io)]
                                                                                              ^~~~~~~~~~~~~~~
note: this feature may not be used in the beta release channel
/home/biziwalker/.cargo/registry/src/github.com-1ecc6299db9ec823/rust-ini-0.4.3/src/lib.rs:49:1: 49:18 error: unstable feature
/home/biziwalker/.cargo/registry/src/github.com-1ecc6299db9ec823/rust-ini-0.4.3/src/lib.rs:49 #![feature(core)]
                                                                                              ^~~~~~~~~~~~~~~~~
note: this feature may not be used in the beta release channel
error: aborting due to 2 previous errors
Could not compile `rust-ini`.

get() to return Option<String> instead of String

Currently there seems to be no way to check if a certain key exists in the ini.

Rust provieds methods like find() and contains_key() on HashMaps to allow non-failing access to keys that might not exist. I'd love to see this in rust-ini either through a new method (find?) or changing the behavior of get().

I think I'm able to provide a PR for both solutions but I wanted to ask what way you'd prefer first ;)

Ini method general_section() panics

Describe the bug

The Ini method general_section panics when there is no general section in *.ini file.

pub fn general_section(&self) -> &Properties

Step to reproduce -

sample.ini

[normal]
sound-file=/usr/share/sounds/freedesktop/stereo/dialog-information.oga

[critical]
border-color=FAB387ff
default-timeout=20
sound-file=/usr/share/sounds/freedesktop/stereo/dialog-warning.oga

main.rs

use ini::{Ini, Error};

fn main() {    

    let conf: Result<Ini, Error> = Ini::load_from_file(r"C:\Projects\test\sample.ini");

    if let Ok(ini) = conf {
        
        let properties = ini.general_section();

        if !properties.is_empty() {
            for property in properties.iter() {
                println!("{} {}", property.0, property.1);
            }
        }
    }
}

output

C:\Projects\rust-ini-test>cargo run
   Compiling concepts v0.1.0 (C:\Projects\rust-ini-test)
    Finished dev [unoptimized + debuginfo] target(s) in 2.97s
     Running `target\debug\rust-ini-test.exe`
thread 'main' panicked at 'There is no general section in this Ini', C:\Users\test\.cargo\registry\src\github.com-1ecc6299db9ec823\rust-ini-0.18.0\src\lib.rs:530:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\rust-ini-test.exe` (exit code: 101)

Possible Fix

The Ini method general_section should return Option of Properties

pub fn general_section(&self) -> Option<&Properties>

EscapePolicy::Basics escapes unicode

It seems both EscapePolicy::Basics and EscapePolicy::BasicsUnicode escape non-ascii unicode characters. EscapePolicy::Nothing does not escape unicode, but doesn't escape anything else either.

For example, have a in.ini files with some unicode in it:

some-key=åäö

And a main.rs file which reads and writes the ini:

use ini::Ini;
use ini::ini::EscapePolicy;

fn main() {
    let ini = Ini::load_from_file("in.ini").unwrap();
    ini.write_to_file_policy("basics.ini", EscapePolicy::Basics).unwrap();
    ini.write_to_file_policy("basics_unicode.ini", EscapePolicy::BasicsUnicode).unwrap();
}

Both basics.ini and basics_unicode.ini end up the same:

some-key=\x00e5\x00e4\x00f6

I would have expected basics.ini to leave the unicode stuff as is.

panic on unwrap() on None

I did some fuzzing of this library, since my software depends on it, and found a panic.

thread '' panicked at 'called Option::unwrap() on a None value', /home/capitol/projects/rust-ini/src/lib.rs:1136:72

full stacktrace:

    #0 0x555d7fff3d81 in __sanitizer_print_stack_trace /rustc/llvm/src/llvm-project/compiler-rt/lib/asan/asan_stack.cpp:86:3
    #1 0x555d80400ec1 in fuzzer::PrintStackTrace() /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/libfuzzer/FuzzerUtil.cpp:210:38
    #2 0x555d803e55ae in fuzzer::Fuzzer::CrashCallback() /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/libfuzzer/FuzzerLoop.cpp:233:18
    #3 0x555d803e543b in fuzzer::Fuzzer::StaticCrashSignalCallback() /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/libfuzzer/FuzzerLoop.cpp:204:19
    #4 0x555d80419c0f in fuzzer::CrashHandler(int, siginfo_t*, void*) /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/libfuzzer/FuzzerUtilPosix.cpp:46:36
    #5 0x7f45fc6d520f  (/lib/x86_64-linux-gnu/libc.so.6+0x4620f)
    #6 0x7f45fc6d518a in __libc_signal_restore_set /build/glibc-YYA7BZ/glibc-2.31/signal/../sysdeps/unix/sysv/linux/internal-signals.h:86:3
    #7 0x7f45fc6d518a in raise /build/glibc-YYA7BZ/glibc-2.31/signal/../sysdeps/unix/sysv/linux/raise.c:48:3
    #8 0x7f45fc6b4858 in abort /build/glibc-YYA7BZ/glibc-2.31/stdlib/abort.c:79:7
    #9 0x555d805db7f6 in std::sys::unix::abort_internal::h5c8b2a90c624abaf /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/std/src/sys/unix/mod.rs:167:14
    #10 0x555d805c48d5 in std::process::abort::hb13208ae9f5b7133 /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/std/src/process.rs:1623:5
    #11 0x555d803b63b2 in libfuzzer_sys::initialize::_$u7b$$u7b$closure$u7d$$u7d$::h9884bbdda40e438c /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/src/lib.rs:51:9
    #12 0x555d805cbb97 in std::panicking::rust_panic_with_hook::h2f4c96dfd8ba524a /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/std/src/panicking.rs:573:17
    #13 0x555d805cb748 in std::panicking::begin_panic_handler::_$u7b$$u7b$closure$u7d$$u7d$::h7740abbe2875cb4d /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/std/src/panicking.rs:476:9
    #14 0x555d805c6bcb in std::sys_common::backtrace::__rust_end_short_backtrace::hcad001df0a36db28 /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/std/src/sys_common/backtrace.rs:153:18
    #15 0x555d805cb708 in rust_begin_unwind /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/std/src/panicking.rs:475:5
    #16 0x555d80630fd0 in core::panicking::panic_fmt::hb15d6f55e8472f62 /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/core/src/panicking.rs:85:14
    #17 0x555d80630f1c in core::panicking::panic::h5d1c61fed2502a5f /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/core/src/panicking.rs:50:5
    #18 0x555d80094eb2 in core::option::Option$LT$T$GT$::unwrap::ha3721cb89adcd423 /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:370:21
    #19 0x555d80039350 in ini::Parser::parse_str_until::h49d14f32501f49c2 /home/capitol/projects/rust-ini/src/lib.rs:1136:54
    #20 0x555d8003a0ce in ini::Parser::parse_str_until_eol::h6c910d3fa3aa74a5 /home/capitol/projects/rust-ini/src/lib.rs:1191:9
    #21 0x555d80039b1a in ini::Parser::parse_val::h89482f840fd70cb3 /home/capitol/projects/rust-ini/src/lib.rs:1185:18
    #22 0x555d800352c4 in ini::Parser::parse::ha575ed2e1dcde280 /home/capitol/projects/rust-ini/src/lib.rs:1052:27
    #23 0x555d80024eb8 in ini::Ini::read_from_opt::h5289cf39f9166deb /home/capitol/projects/rust-ini/src/lib.rs:813:15
    #24 0x555d800254f7 in ini::Ini::read_from::hd4d9745572fb4c83 /home/capitol/projects/rust-ini/src/lib.rs:798:9
    #25 0x555d8001e630 in rust_fuzzer_test_input /home/capitol/projects/rust-ini/fuzz/fuzz_targets/fuzz_target_1.rs:9:5
    #26 0x555d803b5d9c in libfuzzer_sys::test_input_wrap::_$u7b$$u7b$closure$u7d$$u7d$::hb028caf01b44ed44 /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/src/lib.rs:27:9
    #27 0x555d8041d8f7 in std::panicking::try::do_call::h9a75dbb80adec165 /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:373:40
    #28 0x555d8041ddba in __rust_try (/home/capitol/projects/rust-ini/fuzz/target/x86_64-unknown-linux-gnu/debug/fuzz_target_1+0x5cddba)
    #29 0x555d8041d475 in std::panicking::try::h5bb8fed7e70217bf /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:337:19
    #30 0x555d8041a516 in std::panic::catch_unwind::h5bdd326b915b312d /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:379:14
    #31 0x555d803b56e1 in LLVMFuzzerTestOneInput /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/src/lib.rs:25:22
    #32 0x555d803e71ee in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/libfuzzer/FuzzerLoop.cpp:559:17
    #33 0x555d803e69f9 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/libfuzzer/FuzzerLoop.cpp:471:18
    #34 0x555d803e7de0 in fuzzer::Fuzzer::MutateAndTestOne() /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/libfuzzer/FuzzerLoop.cpp:702:25
    #35 0x555d803e8ac7 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/libfuzzer/FuzzerLoop.cpp:838:21
    #36 0x555d803be8c6 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/libfuzzer/FuzzerDriver.cpp:851:10
    #37 0x555d803b53e3 in main /home/capitol/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.4/libfuzzer/FuzzerMain.cpp:20:30
    #38 0x7f45fc6b60b2 in __libc_start_main /build/glibc-YYA7BZ/glibc-2.31/csu/../csu/libc-start.c:308:16
    #39 0x555d7ff70add in _start (/home/capitol/projects/rust-ini/fuzz/target/x86_64-unknown-linux-gnu/debug/fuzz_target_1+0x120add)

Can be reproduced with this unit test:

    use std::io::Cursor;

    #[test]
    fn unwrap_none() {
        let mut d:Vec<u8> = vec![10, 8, 68, 8, 61, 10, 126, 126, 61, 49, 10, 62, 8, 8, 61, 10, 91, 93, 93, 36, 91, 61, 10, 75, 91, 10, 10, 10, 61, 92, 120, 68, 70, 70, 70, 70, 70, 126, 61, 10, 0, 0, 61, 10, 38, 46, 49, 61, 0, 39, 0, 0, 46, 92, 120, 46, 36, 91, 91, 1, 0, 0, 16, 0, 0, 0, 0, 0, 0];
        let mut file = Cursor::new(d);
        Ini::read_from(&mut file);
    }

Support for duplicate sections

Let's say I want to parse such ini file:

[Peer]
foo = a
bar = b

[Peer]
foo = c
bar = d

[Peer]
foo = e
bar = f

Currently I can only access last section's values when I iterate over whole ini file.

Multiline options panic if they are the last ones

Hi,

The following ini file should work, but panics with an Err value: Error { line: 3, col: 0, msg: "Expecting "[Some('=')]" but found EOF." }

[Section]
Option=This is an example
  text going over several lines.

If I add another (one line) option at the very end, it works again.

Insert Duplicate Section?

I am testing support for duplicate sections, and I can not figure out how to add a new section with the same name as an old section. I actually don't think it's exposed in your API currently.

Parsing duplicate sections from files works fine, but adding same named sections does not (using with_section). I recommend adding a new method for instantiating sections, or a boolean on with_section that flags creation of a section--not retrieval / insertion into a pre-existing section.

@zonyitoo very close to having full support for #49! Instead of re-opening it, I figured I'd file another bug report.

Home page example is broken

extern crate ini;
use ini::Ini;

fn main() {
    let conf = Ini::load_from_file("conf.ini").unwrap();

    let section = conf.section("User");
    let tommy = section.get("given_name").unwrap();
    let green = section.get("family_name").unwrap();

    println!("{} {}", tommy, green);

    // iterating
    for (sec, prop) in conf.iter() {
        println!("Section: {}", sec);
        for (key, value) in prop.iter() {
            println!("{}:{}", key, value);
        }
    }
}

gives me

... error: cannot borrow immutable local variable `conf` as mutable
...     let section = conf.section("User");
                      ^~~~
error: aborting due to previous error

Sectionless files are not supported

Seems rust-ini is unable to parse an INI that has no sections and just lists key-value pairs.

I figured it's possible to work around this using .general() section, but this solution limits interoperability.

I have external INI produced by another program in format that has no sections whatsoever, and rust-ini is unable to read that file.

I'd like to be able to refer to any 'top-level' non-sectioned keys.

Custom formatter

First of, thank you for this library. It really works like a charm.

I used this library to retrieve and store data for a .Xrc file. Kind of like you may have seen a .npmrc with npm.
My concern is that the output formatting I expect is a little different than the current output from this lib.

I would like to go from this:

[section]
key=value

To this:

[section]
    key = "value"

Notice the subtle differences:

  • The value has double-quotes around it
  • Each key-value pair inside a section is indented
  • The spaces between "=" and key/value

Expecting \"[Some(\'\\\'\')]\" but found EOF.

I get this error:
Error { line: 3, col: 0, msg: "Expecting \"[Some(\'\\\'\')]\" but found EOF." }

With the following input:

[Test]
Comment[tr]=İnternet'e erişin
Comment[uk]=Доступ до Інтернету

Any idea what could cause this problem?
This comes from a google-chrome.desktop file.

Empty Section on config file

Hi,
This was raised originally in Nushell nushell/nushell#9556,

  1. Create sample ini
[placeholder]
aws_access_key_id=AAAAAAAAAAAAAAAAAAAAA
aws_secret_access_key=BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
aws_session_token=BBBBBBBBBBBBBBBBBBBBBBBB
region=us-east-1
output=json
[default]
aws_access_key_id=AAAAAAAAAAAAAAAAAA
aws_secret_access_key=AAAAAAAAAAAAAAAAAAAAAAA
aws_session_token=BBBBBBBBBBBBBBBBBBBBBBBB
region=us-east-1
output=json
  1. Get sections
    let i = Ini::load_from_file("conf.ini").unwrap();
    for (sec, prop) in i.iter() {
        println!("Section: {:?}", sec);

Outputs:

Section: None
Section: Some("placeholder")
Section: Some("default")

Expected behavior:

Sections placeholder and default but not None section.

Thanks!

How to get section/key in case-insensitive way?

Hi.

I have a INI file with some case issues, for example:

[NFe_PB_P]
NfeConsultaProtocolo_4.00=https://nfe.sefaz.ba.gov.br/webservices/NFeConsultaProtocolo4/NFeConsultaProtocolo4.asmx

however, when I try to get it as following:

ini.get_from(Some("nfe_ba_p"), "nfeconsultaprotocolo_4.00");

it always returns None.

Is there any option to Ini work in case-insensitive way?

Thank you!

Add support for opening a `File`

Currently the Ini struct can only be created anew, from a path or from a string. Could you kindly add a function to open a configuration file from a File struct, please?

Allow IO errors to percolate up to the caller

Specific IO errors can be helpful. Instead of creating an ini::Error from them when a function could encounter either an IO error or a parsing error, they can be passed back up so that the caller can instruct the user on how to deal with them, create a default ini file, etc.

add section name to Properties?

been thinking about how to display the section's name in case of an error and before I figured out that you can just pass the string you used in Ini::section I added a name field to Properties, was about to make a PR when I got enlightened

but this still could be useful, if you wanna add this I can submit the PR

`Ini::section` and `Ini::index` abuse a soundness hole

The relevant code is

    pub fn section<'a: 'i, 'p>(&'a self, name: Option<&'p str>) -> Option<&'i Properties<'pk, 'pv>> {
        self.sections.get(&name.map(|s| s.into()))
    }

You access the sections HashMap, which has the type &'a HashMap<Option<Cow<'i, str>, _>, and you try to access it with an Option<Cow<'p, str>>. The lifetime mismatch is not detected by Rust 1.5, but will be detected by future versions of rustc.

index has a similar problem.

The only fix I am aware of is to turn the Cow to an owned one.

Reading a Windows-like path doesn't return the path separator.

When reading an ini file with unix-like path separator, it returns the path correctly.

[data]
test=/path/file.ext
use ini::Ini;

fn main() {
    let conf = Ini::load_from_file("file.ini").unwrap();
    let section = conf.section(Some("data")).unwrap();
    let test = section.get("test").unwrap();

    println!("{:?}", test); // /path/file.ext
}

But, if we use the Windows-like path separator, it returns a string with any path separator

[data]
test=C:\path\file.ext
use ini::Ini;

fn main() {
    let conf = Ini::load_from_file("file.ini").unwrap();
    let section = conf.section(Some("data")).unwrap();
    let test = section.get("test").unwrap();

    println!("{:?}", test); // C:pathfile.ext
}

And, with this last, we expect to return a string with double backward slash: C:\\path\\file.ext

Implement debug disabling via features

Hi!
Could you please implement similar functionality as in this commit:
sfackler/rust-postgres@d99843b

This way your code will not flood my log with lines like:

2018-02-16, 06:44:13.251 [DEBUG] ini::ini: line:0, col:1
2018-02-16, 06:44:13.251 [DEBUG] ini::ini: Got section: postgres
2018-02-16, 06:44:13.251 [DEBUG] ini::ini: line:1, col:1
2018-02-16, 06:44:13.251 [DEBUG] ini::ini: parse comment
2018-02-16, 06:44:13.251 [DEBUG] ini::ini: line:2, col:1
2018-02-16, 06:44:13.251 [DEBUG] ini::ini: Got key: host
2018-02-16, 06:44:13.251 [DEBUG] ini::ini: line:2, col:5

unable to create empty section using just .with_section()

I've tried a few combinations:

 let mut conf = Ini::new();
    conf.with_section(Some("empty_section")); // to be filled later by another program
    conf.write_to_file("conf.ini").unwrap();

-> produces an empty ini file

   let mut conf = Ini::new();
    conf.with_section(Some("fill_later"))
     set("","");
    conf.write_to_file("conf.ini").unwrap();

->

[fill_later]
=
# N.B. the section isn't empty because it has "="
   let mut conf = Ini::new();
    conf.with_section(Some("fill_later"))
    .set(None::<&str>,None::<&str>);
    conf.write_to_file("conf.ini").unwrap();

->

error[E0277]: the trait bound `std::string::String: std::convert::From<std::option::Option<&str>>` is not satisfied
  --> src/cnf.rs:14:10
   |
14 |         .set(None::<&str>,None::<&str>);
   |          ^^^ the trait `std::convert::From<std::option::Option<&str>>` is not implemented for `std::string::String`
   |
   = help: the following implementations were found:
             <std::string::String as std::convert::From<&mut str>>
             <std::string::String as std::convert::From<&std::string::String>>
             <std::string::String as std::convert::From<&str>>
             <std::string::String as std::convert::From<std::borrow::Cow<'a, str>>>
             <std::string::String as std::convert::From<std::boxed::Box<str>>>
   = note: required because of the requirements on the impl of `std::convert::Into<std::string::String>` for `std::option::Option<&str>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.

Work around with load_from_str

    let input = "[this_works]\n";
    let mut conf = Ini::load_from_str(input).unwrap();
    conf.with_section(Some("but this is still missing"));
    conf.write_to_file(conf_file).unwrap();

->

[this_works]

but .with_section() does not.

work around with delete_from

   let mut conf = Ini::new();
    conf.with_section(Some("pointless delete_from"));
     .set("rm","this");
    conf.delete_from(Some("pointless delete_from"),"rm");
    conf.write_to_file(conf_file).unwrap();

This is what I was trying to achieve, but without the .set() and .delete_from;

Order is not the same every run

I iter() over sections. Expected that order will be the same like in file, but it different every time.

Is it expected behavior for sections?

Cargo to README

Please add an info to README how to connect your library via Cargo

Support UTF-8 BOM

I'm currently unable to parse an ini that contains a starting UTF-8 BOM (byte order marker) EF BB BF. Since it's not whitespace, the parser treats it as beginning of a key.

Example:

[song]
artist=Billy Joel
name=Piano Man
year=1973

This causes the first section marker to be ignored and instead interpreted as a section-less key of [song]\r\nartist.

rust-ini/src/lib.rs

Lines 1011 to 1018 in 062bff9

/// Parse the whole INI input
pub fn parse(&mut self) -> Result<Ini, ParseError> {
let mut result = Ini::new();
let mut curkey: String = "".into();
let mut cursec: Option<String> = None;
self.parse_whitespace();
while let Some(cur_ch) = self.ch {

Special characters (#) are not parsed properly

Hi,

It seems that if the value contains a special character, it is trimmed. E.g.

[playlist]
numberofentries=1
File1=somepath
Title1=Something: Name (#1  ): More / text.
Version=2

The Title1 value will be read only as Something: Name (.

If I compare the output to other languages' libraries (python, smalltalk), the value is (correctly) parsed in full.

Thanks!

Introduce CHANGELOG

Unless I missed it, this repository doesn't have a CHANGELOG. CHANGELOGs are essential to list the addition, changes and fixes between different versions. It would be great to add one while keeping it updated.

Support for semicolon separated lists

.desktop files use semicolon separated lists like this:

[Desktop Entry]
Name=Document Viewer
Comment=View multi-page documents
# Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
Keywords=pdf;ps;postscript;dvi;xps;djvu;tiff;document;presentation;viewer;evince;

When parsing the Keywords property only the first item is returned for some reason. It seems it should either return the string with all the keywords or parse and return the vector of the individual keywords.

Implement DoubleEndedIterator Trait

Is it possible for you to implement DoubleEndedIterator? It seems to be required if I want to use iter().rev(). While it's not too important, I'd like to be able to support curtain behavior in my project, which means I need this trait to be added.

Support array like string

Hello!

I've noticed an error when parsing a setup.cfg (you can find it here).
Outside of inline comments not supported (not a big deal), you raise an error when reading array like string: https://github.com/pypa/setuptools/blob/main/setup.cfg#L9 .

This would be great feature to add as many python projects use this kind of string.

Error: Error: 17:0 expecting "[Some('='), Some(':')]" but found EOF.

Thanks !

Preserve double quotes when writing to file

I have a INI file with the following content:

[Session]
session.trans_sid_tags="a=href,area=href,frame=src,form="

But when I use the Ini::write_fo_file method, the double quotes get lost, and the new content of the file will be:

[Session]
session.trans_sid_tags=a=href,area=href,frame=src,form=

I'd like to be able to preserve the double quotes as they existed in the original file.

Array Support and Iterator of that

Hello,
a little feature request. The support of array in ini-files will be nice:

[section]
option[]=1
option[]=2
option[]=3
option[]=4

ini["section"]["option"][0]
ini["section"]["option"][1]
...

And an iterator over that array will be nice, too.

for test in ini[section][option].iter()

thx

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.