• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..13-Dec-2021-

README.mdH A D13-Dec-202112.9 KiB398317

khash.hH A D13-Dec-202121.4 KiB643303

kvec.hH A D13-Dec-20214.6 KiB16290

lua_ucl.cH A D13-Dec-202134.5 KiB1,5531,043

lua_ucl.hH A D13-Dec-20212.9 KiB8624

tree.hH A D13-Dec-20219.2 KiB220160

ucl.hH A D13-Dec-202155.5 KiB1,651467

ucl_chartable.hH A D13-Dec-202119.3 KiB269241

ucl_emitter.cH A D13-Dec-202128.3 KiB1,190922

ucl_emitter_streamline.cH A D13-Dec-20214.8 KiB174117

ucl_hash.cH A D13-Dec-202111 KiB498399

ucl_hash.hH A D13-Dec-20213.4 KiB11525

ucl_internal.hH A D13-Dec-202115.2 KiB667386

ucl_msgpack.cH A D13-Dec-202133.5 KiB1,6161,333

ucl_parser.cH A D13-Dec-202168.7 KiB3,1572,488

ucl_schema.cH A D13-Dec-202128.2 KiB1,105938

ucl_sexp.cH A D13-Dec-20215.5 KiB227169

ucl_util.cH A D13-Dec-202183.2 KiB3,9483,193

README.md

1# LIBUCL
2
3[![CircleCI](https://circleci.com/gh/vstakhov/libucl.svg?style=svg)](https://circleci.com/gh/vstakhov/libucl)
4[![Coverity](https://scan.coverity.com/projects/4138/badge.svg)](https://scan.coverity.com/projects/4138)
5[![Coverage Status](https://coveralls.io/repos/github/vstakhov/libucl/badge.svg?branch=master)](https://coveralls.io/github/vstakhov/libucl?branch=master)
6
7**Table of Contents**  *generated with [DocToc](http://doctoc.herokuapp.com/)*
8
9- [Introduction](#introduction)
10- [Basic structure](#basic-structure)
11- [Improvements to the json notation](#improvements-to-the-json-notation)
12	- [General syntax sugar](#general-syntax-sugar)
13	- [Automatic arrays creation](#automatic-arrays-creation)
14	- [Named keys hierarchy](#named-keys-hierarchy)
15	- [Convenient numbers and booleans](#convenient-numbers-and-booleans)
16- [General improvements](#general-improvements)
17	- [Comments](#comments)
18	- [Macros support](#macros-support)
19	- [Variables support](#variables-support)
20	- [Multiline strings](#multiline-strings)
21	- [Single quoted strings](#single-quoted-strings)
22- [Emitter](#emitter)
23- [Validation](#validation)
24- [Performance](#performance)
25- [Conclusion](#conclusion)
26
27## Introduction
28
29This document describes the main features and principles of the configuration
30language called `UCL` - universal configuration language.
31
32If you are looking for the libucl API documentation you can find it at [this page](doc/api.md).
33
34## Basic structure
35
36UCL is heavily infused by `nginx` configuration as the example of a convenient configuration
37system. However, UCL is fully compatible with `JSON` format and is able to parse json files.
38For example, you can write the same configuration in the following ways:
39
40* in nginx like:
41
42```nginx
43param = value;
44section {
45    param = value;
46    param1 = value1;
47    flag = true;
48    number = 10k;
49    time = 0.2s;
50    string = "something";
51    subsection {
52        host = {
53            host = "hostname";
54            port = 900;
55        }
56        host = {
57            host = "hostname";
58            port = 901;
59        }
60    }
61}
62```
63
64* or in JSON:
65
66```json
67{
68    "param": "value",
69    "param1": "value1",
70    "flag": true,
71    "subsection": {
72        "host": [
73        {
74            "host": "hostname",
75            "port": 900
76        },
77        {
78            "host": "hostname",
79            "port": 901
80        }
81        ]
82    }
83}
84```
85
86## Improvements to the json notation.
87
88There are various things that make ucl configuration more convenient for editing than strict json:
89
90### General syntax sugar
91
92* Braces are not necessary to enclose a top object: it is automatically treated as an object:
93
94```json
95"key": "value"
96```
97is equal to:
98```json
99{"key": "value"}
100```
101
102* There is no requirement of quotes for strings and keys, moreover, `:` may be replaced `=` or even be skipped for objects:
103
104```nginx
105key = value;
106section {
107    key = value;
108}
109```
110is equal to:
111```json
112{
113    "key": "value",
114    "section": {
115        "key": "value"
116    }
117}
118```
119
120* No commas mess: you can safely place a comma or semicolon for the last element in an array or an object:
121
122```json
123{
124    "key1": "value",
125    "key2": "value",
126}
127```
128### Automatic arrays creation
129
130* Non-unique keys in an object are allowed and are automatically converted to the arrays internally:
131
132```json
133{
134    "key": "value1",
135    "key": "value2"
136}
137```
138is converted to:
139```json
140{
141    "key": ["value1", "value2"]
142}
143```
144
145### Named keys hierarchy
146
147UCL accepts named keys and organize them into objects hierarchy internally. Here is an example of this process:
148```nginx
149section "blah" {
150	key = value;
151}
152section foo {
153	key = value;
154}
155```
156
157is converted to the following object:
158
159```nginx
160section {
161	blah {
162		key = value;
163	}
164	foo {
165		key = value;
166	}
167}
168```
169
170Plain definitions may be more complex and contain more than a single level of nested objects:
171
172```nginx
173section "blah" "foo" {
174	key = value;
175}
176```
177
178is presented as:
179
180```nginx
181section {
182	blah {
183		foo {
184			key = value;
185		}
186	}
187}
188```
189
190### Convenient numbers and booleans
191
192* Numbers can have suffixes to specify standard multipliers:
193    + `[kKmMgG]` - standard 10 base multipliers (so `1k` is translated to 1000)
194    + `[kKmMgG]b` - 2 power multipliers (so `1kb` is translated to 1024)
195    + `[s|min|d|w|y]` - time multipliers, all time values are translated to float number of seconds, for example `10min` is translated to 600.0 and `10ms` is translated to 0.01
196* Hexadecimal integers can be used by `0x` prefix, for example `key = 0xff`. However, floating point values can use decimal base only.
197* Booleans can be specified as `true` or `yes` or `on` and `false` or `no` or `off`.
198* It is still possible to treat numbers and booleans as strings by enclosing them in double quotes.
199
200## General improvements
201
202### Comments
203
204UCL supports different style of comments:
205
206* single line: `#`
207* multiline: `/* ... */`
208
209Multiline comments may be nested:
210```c
211# Sample single line comment
212/*
213 some comment
214 /* nested comment */
215 end of comment
216*/
217```
218
219### Macros support
220
221UCL supports external macros both multiline and single line ones:
222```nginx
223.macro_name "sometext";
224.macro_name {
225    Some long text
226    ....
227};
228```
229
230Moreover, each macro can accept an optional list of arguments in braces. These
231arguments themselves are the UCL object that is parsed and passed to a macro as
232options:
233
234```nginx
235.macro_name(param=value) "something";
236.macro_name(param={key=value}) "something";
237.macro_name(.include "params.conf") "something";
238.macro_name(#this is multiline macro
239param = [value1, value2]) "something";
240.macro_name(key="()") "something";
241```
242
243UCL also provide a convenient `include` macro to load content from another files
244to the current UCL object. This macro accepts either path to file:
245
246```nginx
247.include "/full/path.conf"
248.include "./relative/path.conf"
249.include "${CURDIR}/path.conf"
250```
251
252or URL (if ucl is built with url support provided by either `libcurl` or `libfetch`):
253
254	.include "http://example.com/file.conf"
255
256`.include` macro supports a set of options:
257
258* `try` (default: **false**) - if this option is `true` than UCL treats errors on loading of
259this file as non-fatal. For example, such a file can be absent but it won't stop the parsing
260of the top-level document.
261* `sign` (default: **false**) - if this option is `true` UCL loads and checks the signature for
262a file from path named `<FILEPATH>.sig`. Trusted public keys should be provided for UCL API after
263parser is created but before any configurations are parsed.
264* `glob` (default: **false**) - if this option is `true` UCL treats the filename as GLOB pattern and load
265all files that matches the specified pattern (normally the format of patterns is defined in `glob` manual page
266for your operating system). This option is meaningless for URL includes.
267* `url` (default: **true**) - allow URL includes.
268* `path` (default: empty) - A UCL_ARRAY of directories to search for the include file.
269Search ends after the first match, unless `glob` is true, then all matches are included.
270* `prefix` (default false) - Put included contents inside an object, instead
271of loading them into the root. If no `key` is provided, one is automatically generated based on each files basename()
272* `key` (default: <empty string>) - Key to load contents of include into. If
273the key already exists, it must be the correct type
274* `target` (default: object) - Specify if the `prefix` `key` should be an
275object or an array.
276* `priority` (default: 0) - specify priority for the include (see below).
277* `duplicate` (default: 'append') - specify policy of duplicates resolving:
278	- `append` - default strategy, if we have new object of higher priority then it replaces old one, if we have new object with less priority it is ignored completely, and if we have two duplicate objects with the same priority then we have a multi-value key (implicit array)
279	- `merge` - if we have object or array, then new keys are merged inside, if we have a plain object then an implicit array is formed (regardless of priorities)
280	- `error` - create error on duplicate keys and stop parsing
281	- `rewrite` - always rewrite an old value with new one (ignoring priorities)
282
283Priorities are used by UCL parser to manage the policy of objects rewriting during including other files
284as following:
285
286* If we have two objects with the same priority then we form an implicit array
287* If a new object has bigger priority then we overwrite an old one
288* If a new object has lower priority then we ignore it
289
290By default, the priority of top-level object is set to zero (lowest priority). Currently,
291you can define up to 16 priorities (from 0 to 15). Includes with bigger priorities will
292rewrite keys from the objects with lower priorities as specified by the policy.
293
294### Variables support
295
296UCL supports variables in input. Variables are registered by a user of the UCL parser and can be presented in the following forms:
297
298* `${VARIABLE}`
299* `$VARIABLE`
300
301UCL currently does not support nested variables. To escape variables one could use double dollar signs:
302
303* `$${VARIABLE}` is converted to `${VARIABLE}`
304* `$$VARIABLE` is converted to `$VARIABLE`
305
306However, if no valid variables are found in a string, no expansion will be performed (and `$$` thus remains unchanged). This may be a subject
307to change in future libucl releases.
308
309### Multiline strings
310
311UCL can handle multiline strings as well as single line ones. It uses shell/perl like notation for such objects:
312```
313key = <<EOD
314some text
315splitted to
316lines
317EOD
318```
319
320In this example `key` will be interpreted as the following string: `some text\nsplitted to\nlines`.
321Here are some rules for this syntax:
322
323* Multiline terminator must start just after `<<` symbols and it must consist of capital letters only (e.g. `<<eof` or `<< EOF` won't work);
324* Terminator must end with a single newline character (and no spaces are allowed between terminator and newline character);
325* To finish multiline string you need to include a terminator string just after newline and followed by a newline (no spaces or other characters are allowed as well);
326* The initial and the final newlines are not inserted to the resulting string, but you can still specify newlines at the beginning and at the end of a value, for example:
327
328```
329key <<EOD
330
331some
332text
333
334EOD
335```
336
337### Single quoted strings
338
339It is possible to use single quoted strings to simplify escaping rules. All values passed in single quoted strings are *NOT* escaped, with two exceptions: a single `'` character just before `\` character, and a newline character just after `\` character that is ignored.
340
341```
342key = 'value'; # Read as value
343key = 'value\n\'; # Read as  value\n\
344key = 'value\''; # Read as value'
345key = 'value\
346bla'; # Read as valuebla
347```
348
349## Emitter
350
351Each UCL object can be serialized to one of the three supported formats:
352
353* `JSON` - canonic json notation (with spaces indented structure);
354* `Compacted JSON` - compact json notation (without spaces or newlines);
355* `Configuration` - nginx like notation;
356* `YAML` - yaml inlined notation.
357
358## Validation
359
360UCL allows validation of objects. It uses the same schema that is used for json: [json schema v4](http://json-schema.org). UCL supports the full set of json schema with the exception of remote references. This feature is unlikely useful for configuration objects. Of course, a schema definition can be in UCL format instead of JSON that simplifies schemas writing. Moreover, since UCL supports multiple values for keys in an object it is possible to specify generic integer constraints `maxValues` and `minValues` to define the limits of values count in a single key. UCL currently is not absolutely strict about validation schemas themselves, therefore UCL users should supply valid schemas (as it is defined in json-schema draft v4) to ensure that the input objects are validated properly.
361
362## Performance
363
364Are UCL parser and emitter fast enough? Well, there are some numbers.
365I got a 19Mb file that consist of ~700 thousand lines of json (obtained via
366http://www.json-generator.com/). Then I checked jansson library that performs json
367parsing and emitting and compared it with UCL. Here are results:
368
369```
370jansson: parsed json in 1.3899 seconds
371jansson: emitted object in 0.2609 seconds
372
373ucl: parsed input in 0.6649 seconds
374ucl: emitted config in 0.2423 seconds
375ucl: emitted json in 0.2329 seconds
376ucl: emitted compact json in 0.1811 seconds
377ucl: emitted yaml in 0.2489 seconds
378```
379
380So far, UCL seems to be significantly faster than jansson on parsing and slightly faster on emitting. Moreover,
381UCL compiled with optimizations (-O3) performs significantly faster:
382```
383ucl: parsed input in 0.3002 seconds
384ucl: emitted config in 0.1174 seconds
385ucl: emitted json in 0.1174 seconds
386ucl: emitted compact json in 0.0991 seconds
387ucl: emitted yaml in 0.1354 seconds
388```
389
390You can do your own benchmarks by running `make check` in libucl top directory.
391
392## Conclusion
393
394UCL has clear design that should be very convenient for reading and writing. At the same time it is compatible with
395JSON language and therefore can be used as a simple JSON parser. Macro logic provides an ability to extend configuration
396language (for example by including some lua code) and comments allow to disable or enable the parts of a configuration
397quickly.
398