|
CX Framework
Cross-platform C utility framework
|
Modules | |
| Parsable interface | |
Data Structures | |
| struct | StrPatternDecl |
Macros | |
| #define | strPatternCreate(pat, ...) _strPatternCreate(pat, opt_flags(__VA_ARGS__)) |
| #define | strPatternMatch(pat, s, ...) _strPatternMatch(pat, s, count_macro_args(__VA_ARGS__), (stvp[]) { __VA_ARGS__ }) |
| #define | strPatternMatchAt(io_pos, pat, s, ...) _strPatternMatchAt(io_pos, pat, s, count_macro_args(__VA_ARGS__), (stvp[]) { __VA_ARGS__ }) |
| #define | strParse(s, pat, ...) _strParse(s, pat, count_macro_args(__VA_ARGS__), (stvp[]) { __VA_ARGS__ }) |
| #define | STR_PATTERN(name, patstr, ...) _STR_PATTERN_DECL(name, _strpat_##name, patstr, opt_flags(__VA_ARGS__)) |
| #define | strPat(name) _strPatGet(&name) |
Typedefs | |
| typedef struct StrPattern | StrPattern |
| typedef struct StrPatternDecl | StrPatternDecl |
Enumerations | |
| enum | STRPAT_FLAGS { STRPAT_ExactWS = 0x01 , STRPAT_CaseI = 0x02 } |
| Flags controlling how a pattern is compiled and matched. More... | |
Functions | |
| void | strPatternDestroy (StrPattern **pat) |
Reads structured text by matching it against a pattern written in the same style as a strFormat template. Where strFormat turns values into text, this turns text back into values.
For anything a pattern cannot express - a grammar with counted repetition, or one that needs a decision made in C partway through - use the strscan cursor instead.
A pattern is literal text with three things mixed in:
${...} a placeholder, which matches a value and remembers where it was(...) a group, which can be made optional with ? or offer alternatives with |A backtick escapes the character after it, which is how a pattern matches a literal $, (, ), | or backtick: `$, `(, `), `|, ``.
Whitespace in the literal text matches a run of one or more whitespace bytes, so a single space in the pattern also matches a tab or several spaces. STRPAT_ExactWS turns that off and makes whitespace match exactly as written.
${type[:key][(parseopts)][;default]}
type says what kind of text to match, and is one of:
inf / nantrue/false, yes/no or 1/0, in any casestring, handed to an object that implements the Parsable interfaceThe type controls matching only. What the value is finally converted into is decided by the destination it is bound to, so ${uint:port} can fill a uint16, an int64 or a string without the pattern changing.
Destinations are passed with stvp() and stvpk(), and are matched to placeholders two different ways:
${uint:port} binds to stvpk(port, uint16, &port), by name${uint} binds to stvp(uint16, &port), by positionThe two modes are disjoint, exactly as in strFormat: a keyed placeholder never takes an unkeyed destination, and adding a keyed destination to a call cannot renumber the positional ones.
A key may appear on more than one placeholder when the pattern makes them alternatives of each other; see Optional text and alternatives. One destination then serves all of them.
A key named in the pattern with nothing bound to it is fine and is simply not written - which lets one shared pattern serve callers who want different fields out of it. The reverse is an error: a destination whose key does not appear in the pattern fails the match rather than being quietly ignored, because that is a typo, not a choice.
A placeholder that did not take part in the match leaves its destination untouched, so pre-setting it is how a call-site default is written:
(...) groups elements together. A ? after the closing paren makes the whole group optional, and | inside it offers alternatives:
A placeholder inside a group must be keyed. Positional order stops being meaningful once a field might not appear at all, so an unkeyed placeholder inside a group is a compile error. A skip placeholder is the exception, since it binds nowhere anyway.
Alternatives of the same group may reuse a key, as day and mon do above. Only one alternative can match, so only one of them can produce a value, and a single destination collects it whichever form the text turned out to be in. Repeating a key anywhere the two could match together - twice in one alternative, or inside a group and again outside it - is still a compile error.
A group can carry a key of its own, written after the closing paren and the optional ?. What the destination receives depends on its type:
bool destination gets whether the group matched at allThis is how an absent optional field is told apart from one the caller pre-filled, since a placeholder that did not participate leaves its destination alone.
A group that has no placeholder, no |, no ? and no key cannot affect anything, so it is rejected at compile time. That is deliberate: it turns a pattern containing a literal "(none)" into an error telling the author to write "`(none`)" instead of quietly matching none without the parentheses.
;default covers the case where a field's own text is missing but the literals around it are still there:
If the field does not match, nothing is consumed, the default text is converted into the destination, and matching carries on from the same place - the surrounding literals still have to match. For a string placeholder, "does not match" means the text came out empty.
Groups cover the other case, where the field and its surrounding text are missing. The two do not mix: **;default inside a group is a compile error.** A group already says the contents are optional, and a placeholder that could quietly succeed on nothing would make a branch always match, which would leave later alternatives unreachable for reasons no reader could see in the pattern.
The default text is checked against the placeholder's type when the pattern is compiled, so ${uint:port;https} fails to compile rather than failing on some later call.
(parseopts) is a comma-separated list. Any type accepts:
skip - match the text but never bind it anywhereint and uint accept:
hex, octal, binary, base:# - the number's base, decimal by defaultdigits:# - exactly this many digits, no more and no fewermaxdigits:# - at most this many digitsmin:#, max:# - the value must be in range, or the match failsws - allow whitespace before the numberfloat accepts:
fixed - refuse scientific notationstring accepts:
len:# - exactly this many bytesuntil:<text> - everything up to the next occurrence of some textchars:<set>, notchars:<set> - a run of bytes that are, or are not, in a setword - a run of non-whitespacerest - everything leftquoted - a double-quoted string, with \ escapes removedtrim - remove leading and trailing whitespace from the resultupper, lower - change the case of the resultNumbers are matched strictly by default: no leading whitespace, and no 0x prefix unless hex was asked for. This is the deliberate opposite of strToInt32()'s default, because a parser that quietly accepts a differently-spelled number is a parser two implementations can disagree about.
Matching happens in two passes. The first records only where each field was found; destinations are written afterwards, once the whole pattern has matched. So a failed match writes nothing at all, mirroring strFormat's "a failed format produces no output", and backtracking never has to un-write a value.
A compiled pattern is immutable, and matching writes only to the caller's own state, so one pattern can be matched from any number of threads at once. Compile once and keep it - STR_PATTERN does that for a file-scope pattern, and strParse() is the throwaway form for a pattern used once.
| #define STR_PATTERN | ( | name, | |
| patstr, | |||
| ... | |||
| ) | _STR_PATTERN_DECL(name, _strpat_##name, patstr, opt_flags(__VA_ARGS__)) |
STR_PATTERN(name, "pattern", [flags])
Declares a file-scope pattern that compiles itself the first time it is used.
This is the form for a pattern on a hot path: the compile happens once, on the first match, and every later match reuses it. The compiled pattern is reachable from a global root for the life of the process, so it is not a leak and there is nothing to tear down.
| name | Name for the declaration, passed to strPat() at the match site |
| patstr | Pattern text as a string literal |
| ... | (flags) Optional: STRPAT_FLAGS |
Example:
| #define strParse | ( | s, | |
| pat, | |||
| ... | |||
| ) | _strParse(s, pat, count_macro_args(__VA_ARGS__), (stvp[]) { __VA_ARGS__ }) |
bool strParse(strref s, strref pat, ...)
Compiles a pattern, matches it once, and throws it away.
The convenient form for a one-off parse. Do not put it in a loop - compile the pattern with STR_PATTERN or strPatternCreate() and match that instead.
| s | String to match |
| pat | Pattern text |
| ... | One or more destinations, each wrapped with stvp() or stvpk() |
Example:
| #define strPat | ( | name | ) | _strPatGet(&name) |
| #define strPatternCreate | ( | pat, | |
| ... | |||
| ) | _strPatternCreate(pat, opt_flags(__VA_ARGS__)) |
StrPattern *strPatternCreate(strref pat, [flags])
Compiles a pattern.
| pat | Pattern text |
| ... | (flags) Optional: STRPAT_FLAGS |
Example:
| #define strPatternMatch | ( | pat, | |
| s, | |||
| ... | |||
| ) | _strPatternMatch(pat, s, count_macro_args(__VA_ARGS__), (stvp[]) { __VA_ARGS__ }) |
bool strPatternMatch(StrPattern *pat, strref s, ...)
Matches a compiled pattern against a string and fills in the destinations.
The whole string must match. Nothing is written unless it does.
| pat | Compiled pattern |
| s | String to match |
| ... | One or more destinations, each wrapped with stvp() or stvpk() |
Example:
| #define strPatternMatchAt | ( | io_pos, | |
| pat, | |||
| s, | |||
| ... | |||
| ) | _strPatternMatchAt(io_pos, pat, s, count_macro_args(__VA_ARGS__), (stvp[]) { __VA_ARGS__ }) |
bool strPatternMatchAt(int32 *io_pos, StrPattern *pat, strref s, ...)
Matches a pattern against part of a string, starting where *io_pos says.
Unlike strPatternMatch(), the rest of the string after the pattern is left alone, so this is the form to use when walking through text a piece at a time. On success *io_pos moves to just past what matched; on failure it moves to where the match went wrong, which makes it an error position for free.
| io_pos | Byte offset to start at, updated on return |
| pat | Compiled pattern |
| s | String to match |
| ... | One or more destinations, each wrapped with stvp() or stvpk() |
| typedef struct StrPattern StrPattern |
| typedef struct StrPatternDecl StrPatternDecl |
File-scope pattern declaration, compiled on first use.
Declared by STR_PATTERN and read with strPat(); there is no reason to build one by hand.
| enum STRPAT_FLAGS |
| void strPatternDestroy | ( | StrPattern ** | pat | ) |
Releases a compiled pattern.
| pat | Pointer to the pattern handle, which is set to NULL |