Standard library · Network

net/httpd/conf

The reader of the web server config: blocks, settings and values in Salam block syntax, with positions for errors.

import net.httpd.conf

This package reads text written in the block style that net/httpd uses for its config, and gives back a tree. It knows nothing about web servers: it only recognises the shapes, and net/httpd decides which names are valid. You can use it for settings files of your own that look like Salam.

There are two shapes. A setting is a name, an equals sign and one or more values on the same line: max connections = 100. A block is a name, optional strings, a colon, its contents and end: location "/api/": cache = 1h end. A name may be several words (error page), values are strings in double quotes (with \n, \t, \" and \\), strings in backticks (taken as written, so a regular expression needs no doubling of backslashes), numbers with an optional unit such as 64mb or 30d, and plain words such as tls. Comments are // to the end of the line, or /* ... */.

Everything lives in a Doc, a list of nodes that point at each other by number: node 0 is the root, Find and ChildAt move down, and the fields of a node hold its words, labels, values and children. Free the document with Free when you are done with it.

The things people get wrong:

  • A value list ends at the end of the line, at end, or where the next setting starts on the same line, so a = 1 b = 2 is two settings. A bare word at the end of a list is read as a value, which is why listen = 443 tls works.
  • A parse stops at the first error, and ok is then false. The error has the line and the column, and ErrorText puts them in front of the message the way compilers do.
  • Addresses and anything with a colon in it need quotes: listen = "127.0.0.1:8080". Without them the colon would read as the start of a block.
  • A node's words hold its name, so Name joins them with single spaces. Block labels, such as the path of a location, are in labels, not in the name.

Types

Value

struct Value
One value of a setting.
NameTypeDescription
kindint = 0VAL_WORD, VAL_STR or VAL_NUM.
textstr = ""The value as text; strings without their quotes and with escapes resolved.
lineint = 0The line, counting from 1.
colint = 0The column, counting from 1.
net-httpd-conf-Parse.salam
import net.httpd.conf

func main:
    text := `
server:
    site:
        listen = 80 tls
        names = "a.test www.a.test"
        location "/api/": cache = 1h end
    end
end
`
    d := conf.Parse(text)
    println d.ok, d.nodes.len(), conf.Count(d, conf.Root())
    server := conf.Find(d, conf.Root(), "server")
    site := conf.Find(d, server, "site")
    println conf.Name(d, site), conf.Count(d, site), d.nodes.get(site).block
    listen := conf.Find(d, site, "listen")
    v := d.nodes.get(listen).values.get(0)
    println v.text, v.kind == conf.VAL_NUM, v.line, v.col
    w := d.nodes.get(listen).values.get(1)
    println w.text, w.kind == conf.VAL_WORD, conf.ValueText(d, conf.Find(d, site, "names"), 0)
    names := d.nodes.get(conf.Find(d, site, "names")).values.get(0)
    println names.kind == conf.VAL_STR
    loc := conf.ChildAt(d, site, 2)
    n := d.nodes.get(loc)
    println conf.Name(d, loc), n.labels.get(0), n.block, n.words.len(), n.children.len(), n.line, n.col
    conf.Free(d)
end
Outputtrue 7 1 site 3 true 80 true 4 18 tls true a.test www.a.test true location /api/ true 1 1 6 9

Node

struct Node
One setting or block of the tree.
NameTypeDescription
blockbool = falseTrue for a block, false for a setting.
wordsVectorThe words of the name, such as error and page.
labelsVectorThe strings written between the name and the colon of a block.
valuesVectorThe values of a setting.
childrenVectorThe numbers of the nodes inside a block.
lineint = 0The line where it starts.
colint = 0The column where it starts.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam

Doc

struct Doc
A parsed document: all the nodes and the first error.
NameTypeDescription
nodesVectorEvery node; node 0 is the root.
okbool = trueTrue when the text parsed without an error.
errorstr = ""The message of the first error, empty when there is none.
lineint = 0The line of the error.
colint = 0The column of the error.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam

Constants and variables

VAL_WORD

const VAL_WORD: i32 = 0
The kind of a value that is a plain word such as tls or auto.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam

VAL_STR

const VAL_STR: i32 = 1
The kind of a value written in quotes or backticks.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam

VAL_NUM

const VAL_NUM: i32 = 2
The kind of a value that starts with a digit, with or without a unit, such as 8080 or 30d; the text keeps the unit.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam

Functions

Parse

func Parse(text: str): Doc
Parses text and returns the document; check ok before using it.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam

Free

func Free(d &: Doc)
Frees the memory of a document.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam

ErrorText

func ErrorText(d: Doc, file: str): str
The first error as file:line:column: message, or an empty string when the document is valid. The first argument is the name to show for the file.
net-httpd-conf-Errors.salam
import net.httpd.conf

func show(text: str):
    d := conf.Parse(text)
    println d.ok, conf.ErrorText(d, "web.salam"), d.error, d.line, d.col
    conf.Free(d)
end

func main:
    show("server:\n    site:\n")
    show("server:\nend\nend\n")
    show("listen = \n")
    show("names = \"open\n")
    show("listen 80\n")
    show("a = 1 # no\n")
    show("ok = 1\n")
end
Outputfalse web.salam:3:1: missing 'end' for the block opened on line 2 missing 'end' for the block opened on line 2 3 1 false web.salam:3:1: 'end' without a matching block 'end' without a matching block 3 1 false web.salam:1:8: expected a value after '=' expected a value after '=' 1 8 false web.salam:1:9: unterminated string unterminated string 1 9 false web.salam:1:8: expected '=' or ':' after 'listen' expected '=' or ':' after 'listen' 1 8 false web.salam:1:7: unexpected character '#' unexpected character '#' 1 7 true 0 0

Name

func Name(d: Doc, node: int): str
The name of a node: its words joined by single spaces.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam

Root

func Root(): int
The number of the root node, which is 0.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam

Count

func Count(d: Doc, node: int): int
The number of children of a block.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam

ChildAt

func ChildAt(d: Doc, node: int, i: int): int
The node number of the child at a position, counting from 0.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam

Find

func Find(d: Doc, node: int, name: str): int
The node number of the first child of a node with a given name, or -1.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam

ValueText

func ValueText(d: Doc, node: int, i: int): str
The text of the value at a position of a setting.

The example for this item is shown with the ones above: net-httpd-conf-Parse.salam