inih 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +1 -0
- data/LICENSE +21 -0
- data/README.md +51 -0
- data/ext/inih/extconf.rb +7 -0
- data/ext/inih/ini.c +244 -0
- data/ext/inih/inih.c +79 -0
- data/lib/inih.rb +33 -0
- metadata +51 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ddb0233107d7ad4ce1121c75fd29a94de7d5dc42
|
4
|
+
data.tar.gz: 42fc11b4b2f16e971e61c189b45ecf652ae71ffb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4727253857a6bdc0472b47792631ded48e2a125bfc0acfeb649b19f7869d92e4f02dded4f215e32d9dd8a307ecd29bd5c83c211ec6c404cc902f59afb7c00824
|
7
|
+
data.tar.gz: fcd4cd91b83fb9316a0366818c653e5f3c867f144ebb6c34761a7b904751c32f85251861c4f9f5e280affcdc523e76a6f06aebc053c15e9c4f9cde59ec906dfb
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--no-private --markup-provider=redcarpet --markup=markdown - README.md LICENSE ext/inih/LICENSE
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 William Woodruff <william @ yossarian.net>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
ruby-inih
|
2
|
+
=========
|
3
|
+
|
4
|
+
A Ruby wrapper for [inih](https://github.com/benhoyt/inih), a simple INI parser.
|
5
|
+
|
6
|
+
### Installation
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
$ gem install inih
|
10
|
+
```
|
11
|
+
|
12
|
+
### Example
|
13
|
+
|
14
|
+
Given the following INI data:
|
15
|
+
|
16
|
+
```ini
|
17
|
+
; example.ini
|
18
|
+
[example]
|
19
|
+
foo=bar
|
20
|
+
baz = quux
|
21
|
+
integer = 10
|
22
|
+
float = 3.14
|
23
|
+
bool = true
|
24
|
+
```
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
# load directly from a file
|
28
|
+
INIH.load "example.ini"
|
29
|
+
# => {"example"=>{"foo"=>"bar", "baz"=>"quux", "integer"=>10, "float"=>3.14, "bool"=>true}}
|
30
|
+
|
31
|
+
# parse from a string
|
32
|
+
INIH.parse "[section]\nkey=value"
|
33
|
+
#=> {"section"=>{"key"=>"value"}}
|
34
|
+
```
|
35
|
+
|
36
|
+
Integers, floating-point numbers, and booleans are coerced into their respective Ruby types.
|
37
|
+
|
38
|
+
### TODO
|
39
|
+
|
40
|
+
* Unit tests
|
41
|
+
* Coerce scientific-notation?
|
42
|
+
|
43
|
+
### License
|
44
|
+
|
45
|
+
inih itself is licensed under the BSD License.
|
46
|
+
|
47
|
+
For the exact terms, see the [LICENSE](ext/inih/LICENSE) file.
|
48
|
+
|
49
|
+
ruby-inih is licensed under the MIT License.
|
50
|
+
|
51
|
+
For the exact terms, see the [LICENSE](./LICENSE) file.
|
data/ext/inih/extconf.rb
ADDED
data/ext/inih/ini.c
ADDED
@@ -0,0 +1,244 @@
|
|
1
|
+
/* inih -- simple .INI file parser
|
2
|
+
|
3
|
+
inih is released under the New BSD license (see LICENSE.txt). Go to the project
|
4
|
+
home page for more info:
|
5
|
+
|
6
|
+
https://github.com/benhoyt/inih
|
7
|
+
|
8
|
+
*/
|
9
|
+
|
10
|
+
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
11
|
+
#define _CRT_SECURE_NO_WARNINGS
|
12
|
+
#endif
|
13
|
+
|
14
|
+
#include <stdio.h>
|
15
|
+
#include <ctype.h>
|
16
|
+
#include <string.h>
|
17
|
+
|
18
|
+
#include "ini.h"
|
19
|
+
|
20
|
+
#if !INI_USE_STACK
|
21
|
+
#include <stdlib.h>
|
22
|
+
#endif
|
23
|
+
|
24
|
+
#define MAX_SECTION 50
|
25
|
+
#define MAX_NAME 50
|
26
|
+
|
27
|
+
/* Used by ini_parse_string() to keep track of string parsing state. */
|
28
|
+
typedef struct {
|
29
|
+
const char* ptr;
|
30
|
+
size_t num_left;
|
31
|
+
} ini_parse_string_ctx;
|
32
|
+
|
33
|
+
/* Strip whitespace chars off end of given string, in place. Return s. */
|
34
|
+
static char* rstrip(char* s)
|
35
|
+
{
|
36
|
+
char* p = s + strlen(s);
|
37
|
+
while (p > s && isspace((unsigned char)(*--p)))
|
38
|
+
*p = '\0';
|
39
|
+
return s;
|
40
|
+
}
|
41
|
+
|
42
|
+
/* Return pointer to first non-whitespace char in given string. */
|
43
|
+
static char* lskip(const char* s)
|
44
|
+
{
|
45
|
+
while (*s && isspace((unsigned char)(*s)))
|
46
|
+
s++;
|
47
|
+
return (char*)s;
|
48
|
+
}
|
49
|
+
|
50
|
+
/* Return pointer to first char (of chars) or inline comment in given string,
|
51
|
+
or pointer to null at end of string if neither found. Inline comment must
|
52
|
+
be prefixed by a whitespace character to register as a comment. */
|
53
|
+
static char* find_chars_or_comment(const char* s, const char* chars)
|
54
|
+
{
|
55
|
+
#if INI_ALLOW_INLINE_COMMENTS
|
56
|
+
int was_space = 0;
|
57
|
+
while (*s && (!chars || !strchr(chars, *s)) &&
|
58
|
+
!(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
|
59
|
+
was_space = isspace((unsigned char)(*s));
|
60
|
+
s++;
|
61
|
+
}
|
62
|
+
#else
|
63
|
+
while (*s && (!chars || !strchr(chars, *s))) {
|
64
|
+
s++;
|
65
|
+
}
|
66
|
+
#endif
|
67
|
+
return (char*)s;
|
68
|
+
}
|
69
|
+
|
70
|
+
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
|
71
|
+
static char* strncpy0(char* dest, const char* src, size_t size)
|
72
|
+
{
|
73
|
+
strncpy(dest, src, size);
|
74
|
+
dest[size - 1] = '\0';
|
75
|
+
return dest;
|
76
|
+
}
|
77
|
+
|
78
|
+
/* See documentation in header file. */
|
79
|
+
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
|
80
|
+
void* user)
|
81
|
+
{
|
82
|
+
/* Uses a fair bit of stack (use heap instead if you need to) */
|
83
|
+
#if INI_USE_STACK
|
84
|
+
char line[INI_MAX_LINE];
|
85
|
+
#else
|
86
|
+
char* line;
|
87
|
+
#endif
|
88
|
+
char section[MAX_SECTION] = "";
|
89
|
+
char prev_name[MAX_NAME] = "";
|
90
|
+
|
91
|
+
char* start;
|
92
|
+
char* end;
|
93
|
+
char* name;
|
94
|
+
char* value;
|
95
|
+
int lineno = 0;
|
96
|
+
int error = 0;
|
97
|
+
|
98
|
+
#if !INI_USE_STACK
|
99
|
+
line = (char*)malloc(INI_MAX_LINE);
|
100
|
+
if (!line) {
|
101
|
+
return -2;
|
102
|
+
}
|
103
|
+
#endif
|
104
|
+
|
105
|
+
#if INI_HANDLER_LINENO
|
106
|
+
#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno)
|
107
|
+
#else
|
108
|
+
#define HANDLER(u, s, n, v) handler(u, s, n, v)
|
109
|
+
#endif
|
110
|
+
|
111
|
+
/* Scan through stream line by line */
|
112
|
+
while (reader(line, INI_MAX_LINE, stream) != NULL) {
|
113
|
+
lineno++;
|
114
|
+
|
115
|
+
start = line;
|
116
|
+
#if INI_ALLOW_BOM
|
117
|
+
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
|
118
|
+
(unsigned char)start[1] == 0xBB &&
|
119
|
+
(unsigned char)start[2] == 0xBF) {
|
120
|
+
start += 3;
|
121
|
+
}
|
122
|
+
#endif
|
123
|
+
start = lskip(rstrip(start));
|
124
|
+
|
125
|
+
if (*start == ';' || *start == '#') {
|
126
|
+
/* Per Python configparser, allow both ; and # comments at the
|
127
|
+
start of a line */
|
128
|
+
}
|
129
|
+
#if INI_ALLOW_MULTILINE
|
130
|
+
else if (*prev_name && *start && start > line) {
|
131
|
+
/* Non-blank line with leading whitespace, treat as continuation
|
132
|
+
of previous name's value (as per Python configparser). */
|
133
|
+
if (!HANDLER(user, section, prev_name, start) && !error)
|
134
|
+
error = lineno;
|
135
|
+
}
|
136
|
+
#endif
|
137
|
+
else if (*start == '[') {
|
138
|
+
/* A "[section]" line */
|
139
|
+
end = find_chars_or_comment(start + 1, "]");
|
140
|
+
if (*end == ']') {
|
141
|
+
*end = '\0';
|
142
|
+
strncpy0(section, start + 1, sizeof(section));
|
143
|
+
*prev_name = '\0';
|
144
|
+
}
|
145
|
+
else if (!error) {
|
146
|
+
/* No ']' found on section line */
|
147
|
+
error = lineno;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
else if (*start) {
|
151
|
+
/* Not a comment, must be a name[=:]value pair */
|
152
|
+
end = find_chars_or_comment(start, "=:");
|
153
|
+
if (*end == '=' || *end == ':') {
|
154
|
+
*end = '\0';
|
155
|
+
name = rstrip(start);
|
156
|
+
value = end + 1;
|
157
|
+
#if INI_ALLOW_INLINE_COMMENTS
|
158
|
+
end = find_chars_or_comment(value, NULL);
|
159
|
+
if (*end)
|
160
|
+
*end = '\0';
|
161
|
+
#endif
|
162
|
+
value = lskip(value);
|
163
|
+
rstrip(value);
|
164
|
+
|
165
|
+
/* Valid name[=:]value pair found, call handler */
|
166
|
+
strncpy0(prev_name, name, sizeof(prev_name));
|
167
|
+
if (!HANDLER(user, section, name, value) && !error)
|
168
|
+
error = lineno;
|
169
|
+
}
|
170
|
+
else if (!error) {
|
171
|
+
/* No '=' or ':' found on name[=:]value line */
|
172
|
+
error = lineno;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
#if INI_STOP_ON_FIRST_ERROR
|
177
|
+
if (error)
|
178
|
+
break;
|
179
|
+
#endif
|
180
|
+
}
|
181
|
+
|
182
|
+
#if !INI_USE_STACK
|
183
|
+
free(line);
|
184
|
+
#endif
|
185
|
+
|
186
|
+
return error;
|
187
|
+
}
|
188
|
+
|
189
|
+
/* See documentation in header file. */
|
190
|
+
int ini_parse_file(FILE* file, ini_handler handler, void* user)
|
191
|
+
{
|
192
|
+
return ini_parse_stream((ini_reader)fgets, file, handler, user);
|
193
|
+
}
|
194
|
+
|
195
|
+
/* See documentation in header file. */
|
196
|
+
int ini_parse(const char* filename, ini_handler handler, void* user)
|
197
|
+
{
|
198
|
+
FILE* file;
|
199
|
+
int error;
|
200
|
+
|
201
|
+
file = fopen(filename, "r");
|
202
|
+
if (!file)
|
203
|
+
return -1;
|
204
|
+
error = ini_parse_file(file, handler, user);
|
205
|
+
fclose(file);
|
206
|
+
return error;
|
207
|
+
}
|
208
|
+
|
209
|
+
/* An ini_reader function to read the next line from a string buffer. This
|
210
|
+
is the fgets() equivalent used by ini_parse_string(). */
|
211
|
+
static char* ini_reader_string(char* str, int num, void* stream) {
|
212
|
+
ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream;
|
213
|
+
const char* ctx_ptr = ctx->ptr;
|
214
|
+
size_t ctx_num_left = ctx->num_left;
|
215
|
+
char* strp = str;
|
216
|
+
char c;
|
217
|
+
|
218
|
+
if (ctx_num_left == 0 || num < 2)
|
219
|
+
return NULL;
|
220
|
+
|
221
|
+
while (num > 1 && ctx_num_left != 0) {
|
222
|
+
c = *ctx_ptr++;
|
223
|
+
ctx_num_left--;
|
224
|
+
*strp++ = c;
|
225
|
+
if (c == '\n')
|
226
|
+
break;
|
227
|
+
num--;
|
228
|
+
}
|
229
|
+
|
230
|
+
*strp = '\0';
|
231
|
+
ctx->ptr = ctx_ptr;
|
232
|
+
ctx->num_left = ctx_num_left;
|
233
|
+
return str;
|
234
|
+
}
|
235
|
+
|
236
|
+
/* See documentation in header file. */
|
237
|
+
int ini_parse_string(const char* string, ini_handler handler, void* user) {
|
238
|
+
ini_parse_string_ctx ctx;
|
239
|
+
|
240
|
+
ctx.ptr = string;
|
241
|
+
ctx.num_left = strlen(string);
|
242
|
+
return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler,
|
243
|
+
user);
|
244
|
+
}
|
data/ext/inih/inih.c
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
#include "inih.h"
|
2
|
+
|
3
|
+
VALUE mINIH = Qnil;
|
4
|
+
|
5
|
+
static int mINIH_ini_handler(void *data, const char *sect, const char *name, const char *val);
|
6
|
+
|
7
|
+
/*
|
8
|
+
@overload parse(string)
|
9
|
+
Parse an INI-formatted string into a Hash.
|
10
|
+
@param string [String] the INI-formatted string to parse
|
11
|
+
@return [Hash] the resulting hash
|
12
|
+
@raise [RuntimeError] if a parse error occurs
|
13
|
+
*/
|
14
|
+
static VALUE mINIH_parse(VALUE self, VALUE string);
|
15
|
+
|
16
|
+
/*
|
17
|
+
@overload load(filename)
|
18
|
+
Parse an INI-formatted file into a Hash.
|
19
|
+
@param filename [String] the INI-formatted file to parse
|
20
|
+
@return [Hash] the resulting hash
|
21
|
+
@raise [RuntimeError] if a parse or I/O error occurs
|
22
|
+
*/
|
23
|
+
static VALUE mINIH_load(VALUE self, VALUE filename);
|
24
|
+
|
25
|
+
void Init_inih()
|
26
|
+
{
|
27
|
+
mINIH = rb_define_module("INIH");
|
28
|
+
|
29
|
+
rb_define_singleton_method(mINIH, "parse", mINIH_parse, 1);
|
30
|
+
rb_define_singleton_method(mINIH, "load", mINIH_load, 1);
|
31
|
+
}
|
32
|
+
|
33
|
+
static int mINIH_ini_handler(void *data, const char *sect, const char *name, const char *val)
|
34
|
+
{
|
35
|
+
VALUE sect_s = rb_str_new_cstr(sect);
|
36
|
+
VALUE name_s = rb_str_new_cstr(name);
|
37
|
+
VALUE hash = *((VALUE *) data);
|
38
|
+
VALUE subh = rb_hash_aref(hash, sect_s);
|
39
|
+
|
40
|
+
if (NIL_P(subh)) {
|
41
|
+
subh = rb_hash_new();
|
42
|
+
}
|
43
|
+
|
44
|
+
rb_hash_aset(subh, name_s, rb_str_new_cstr(val));
|
45
|
+
rb_hash_aset(hash, sect_s, subh);
|
46
|
+
|
47
|
+
return 1;
|
48
|
+
}
|
49
|
+
|
50
|
+
static VALUE mINIH_parse(VALUE self, VALUE string)
|
51
|
+
{
|
52
|
+
char *str = StringValueCStr(string);
|
53
|
+
VALUE hash = rb_hash_new();
|
54
|
+
int result;
|
55
|
+
|
56
|
+
if ((result = ini_parse_string(str, mINIH_ini_handler, &hash)) != 0) {
|
57
|
+
rb_raise(rb_eRuntimeError, "parse error, line %d", result);
|
58
|
+
}
|
59
|
+
|
60
|
+
return rb_funcall(mINIH, rb_intern("normalize"), 1, hash);
|
61
|
+
}
|
62
|
+
|
63
|
+
static VALUE mINIH_load(VALUE self, VALUE filename)
|
64
|
+
{
|
65
|
+
char *file = StringValueCStr(filename);
|
66
|
+
VALUE hash = rb_hash_new();
|
67
|
+
int result;
|
68
|
+
|
69
|
+
if ((result = ini_parse(file, mINIH_ini_handler, &hash)) != 0) {
|
70
|
+
if (result < 0) {
|
71
|
+
rb_raise(rb_eRuntimeError, "I/O error");
|
72
|
+
}
|
73
|
+
else {
|
74
|
+
rb_raise(rb_eRuntimeError, "parse error, line %d", result);
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
return rb_funcall(mINIH, rb_intern("normalize"), 1, hash);
|
79
|
+
}
|
data/lib/inih.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../ext/inih/inih"
|
4
|
+
|
5
|
+
# The primary namespace for {INIH}.
|
6
|
+
module INIH
|
7
|
+
# The current version of ruby-inih.
|
8
|
+
VERSION = "0.0.1"
|
9
|
+
|
10
|
+
# Normalize a parsed INI file's values.
|
11
|
+
# @api private
|
12
|
+
def self.normalize(hsh)
|
13
|
+
hsh.map do |k, sect|
|
14
|
+
[k, normalize_sect(sect)]
|
15
|
+
end.to_h
|
16
|
+
end
|
17
|
+
|
18
|
+
# Normalize the values in a section of a parsed INI file.
|
19
|
+
# @api private
|
20
|
+
def self.normalize_sect(sect)
|
21
|
+
sect.map do |k, v|
|
22
|
+
nv = case v
|
23
|
+
when "true" then true
|
24
|
+
when "false" then false
|
25
|
+
when /\A\d+\Z/ then Integer v
|
26
|
+
when /\A\d+\.\d+\Z/ then Float v
|
27
|
+
else v
|
28
|
+
end
|
29
|
+
|
30
|
+
[k, nv]
|
31
|
+
end.to_h
|
32
|
+
end
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: inih
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- William Woodruff
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-07-21 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A native library for parsing INI files.
|
14
|
+
email: william@tuffbizz.com
|
15
|
+
executables: []
|
16
|
+
extensions:
|
17
|
+
- ext/inih/extconf.rb
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".yardopts"
|
21
|
+
- LICENSE
|
22
|
+
- README.md
|
23
|
+
- ext/inih/extconf.rb
|
24
|
+
- ext/inih/ini.c
|
25
|
+
- ext/inih/inih.c
|
26
|
+
- lib/inih.rb
|
27
|
+
homepage: https://github.com/woodruffw/ruby-ini
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
metadata: {}
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 2.6.11
|
48
|
+
signing_key:
|
49
|
+
specification_version: 4
|
50
|
+
summary: inih - a Ruby wrapper for a simple C INI parser
|
51
|
+
test_files: []
|