ddn.data.cf

CF - Configuration File Format Parser and Writer

This module provides a complete implementation of CF v1.0 specification, including a lexer, parser, and writer. The parser produces CdmDocument from the CDM (Configuration Data Model) for full roundtrip fidelity.

CF is a human-friendly configuration format that supports:

  • Objects with key-value pairs using = or : separators
  • Arrays with [...] syntax
  • Strings: double, single, triple-quoted, and raw
  • Numbers: integers - decimal, hex, octal, binary - and floats
  • Booleans: true and false
  • Null: null
  • Special floats: inf, -inf, nan
  • Temporal types: dates, times, datetimes
  • Comments: hash, double-slash, and block comments
  • Include directive for file inclusion
  • Environment variable substitution

Example:

import ddn.data.cf;

// Parse CF source
auto doc = parseCf(`
  name = "myapp"
  version = 1
  server {
     host = "localhost"
     port = 8080
  }
`);

// Access values via CDM
assert(doc.root["name"].as!string == "myapp");

// Write back to CF
string output = toCf(doc);

Security_Considerations: The CF parser includes features that can have security implications:

Include Directive:
  • By default, enableIncludes is false to prevent unintended file access.
  • When enabled, you MUST provide a fileReader delegate that controls

    which files can be read.

  • Path traversal attacks are mitigated by normalizing paths before validation

    and rejecting `..` sequences when allowParentTraversal is false (default).

  • Absolute paths are rejected by default (allowAbsolutePaths = false).
  • Circular includes are detected and rejected.
  • Include depth is limited to MAX_INCLUDE_DEPTH (32) to prevent stack overflow.
Environment Variable Substitution:
  • By default, enableEnvSubstitution is true but requires an envReader

    delegate to actually resolve variables.

  • Environment variable expansion is limited to MAX_ENV_EXPANSION_SIZE bytes

    to prevent denial-of-service via large expansions.

  • Without an envReader, ${VAR} references resolve to empty strings.
Recommended Secure Configuration:

CfParserConfig cfg;
cfg.enableIncludes = false;  // Disable unless needed
cfg.enableEnvSubstitution = false;  // Disable unless needed
auto doc = parseCf(untrustedInput, "input.cf", cfg);

Types 11

Token types for CF lexical analysis.

These represent all possible token kinds that the lexer can produce, following the CF v1.0 specification.

STRINGString literal (any quote style)
INTEGERInteger literal
FLOATFloating-point literal
DATEDate literal (YYYY-MM-DD)
TIMETime literal (HH:MM:SS)
DATETIMEDateTime literal (ISO 8601)
TRUEBoolean true
FALSEBoolean false
NULLNull value
INFPositive infinity
NEG_INFNegative infinity
NANNot-a-number
INCLUDEFile inclusion directive
ENV_VAREnvironment variable reference `${VAR}`
LBRACELeft brace
RBRACERight brace
LBRACKETLeft bracket
RBRACKETRight bracket
EQUALSEquals sign
COLONColon
COMMAComma
SEMICOLONSemicolon
IDENTIFIERIdentifier (unquoted key)
NEWLINENewline (significant in some contexts)
EOFEnd of file
COMMENTLine comment (hash or double-slash)
BLOCK_COMMENTBlock comment (slash-star)
ERRORLexical error
structLocation

Source location information.

Tracks the position of tokens and nodes within the source file for error reporting and roundtrip preservation.

Fields
size_t lineLine number (1-based)
size_t colColumn number (1-based)
string sourceSource filename or identifier
Methods
string toString() const @safe pureCreates a human-readable string representation of the location.
structToken

A lexical token from CF source.

Represents a single token produced by the lexer, including its type, raw text value, and source location.

Fields
TokenType typeThe type of this token
string valueRaw text of the token as it appears in source
Location locSource location of the token
Methods
string toString() const @safe pureCreates a human-readable string representation of the token.
classCfException : Exception

Base exception class for CF parsing and processing errors.

Includes source location information for precise error reporting.

Fields
Location locationSource location where the error occurred
Constructors
this(string msg, Location loc = Location.init, string file = __FILE__, size_t line = __LINE__)Constructs a CfException with the given message and location.

Exception class for CF parse errors.

Thrown when the parser encounters invalid syntax or unexpected tokens.

Constructors
this(string msg, Location loc = Location.init, string file = __FILE__, size_t line = __LINE__)Constructs a CfParseException with the given message and location.

Exception class for CF lexical errors.

Thrown when the lexer encounters invalid character sequences.

Constructors
this(string msg, Location loc = Location.init, string file = __FILE__, size_t line = __LINE__)Constructs a CfLexerException with the given message and location.
structCfLexer

Lexer for CF source text.

Converts CF source into a stream of tokens, implementing the input range interface. Comments are preserved as tokens to support the roundtrip-preserving document model.

Fields
string source
string filename
size_t pos
size_t line
size_t col
Token currentToken
bool initialized
bool eofReturned
Methods
Token front() @safe pureReturns the current token.
void popFront() @safe pureAdvances to the next token.
bool empty() @safe pureChecks if the token stream is exhausted.
private void advance() @safe pureAdvances the lexer to produce the next token.
private void skipWhitespaceExceptNewline() @safe pureSkips whitespace characters except newlines.
private void lexLineComment() @safe pureLexes a line comment (# or //).
private void lexBlockComment() @safe pureLexes a block comment (slash-star to star-slash).
private void lexString() @safe pureLexes a string literal.
private bool validateAndConsumeEscape() @safe pureValidates and consumes an escape sequence.
private bool consumeHexDigits(size_t n) @safe pureConsumes exactly n hex digits.
private bool isControlChar(char c) @safe pure nothrowChecks if a character is a control character.
private void lexTripleQuotedString(char quote) @safe pureLexes a triple-quoted string.
private void lexRawString() @safe pureLexes a raw string literal (r"..." or r'...').
private void lexNumber() @safe pureLexes a number (integer or float).
private void lexDecimalNumber(size_t startPos, Location startLoc) @safe pureLexes a decimal number.
private void lexHexNumber(size_t startPos, Location startLoc) @safe pureLexes a hexadecimal number.
private void lexOctalNumber(size_t startPos, Location startLoc) @safe pureLexes an octal number.
private void lexBinaryNumber(size_t startPos, Location startLoc) @safe pureLexes a binary number.
private void lexEnvVar() @safe pureLexes an environment variable reference.
private void lexIdentifierOrKeyword() @safe pureLexes an identifier or keyword.
private bool looksLikeTemporalStart() @safe pureChecks if position looks like start of temporal literal.
private bool looksLikeTimeStart() @safe pureChecks if position looks like start of time literal.
private void lexTime() @safe pureLexes a time literal.
private void lexTemporal() @safe pureLexes a temporal literal (date, time, or datetime).
private TokenType classifyKeyword(string text) @safe pureClassifies a text as keyword or identifier.
private Token makeToken(TokenType type, string value) @safe pureCreates a token at the current location.
private Location currentLocation() @safe pureReturns the current source location.
private void consumeChar() @safe pureConsumes a single character and updates position tracking.
private void consumeUtf8Char() @safe pureConsumes a UTF-8 character (possibly multi-byte).
private bool isDigit(char c) @safe pure nothrowChecks if character is a decimal digit.
private bool isHexDigit(char c) @safe pure nothrowChecks if character is a hexadecimal digit.
private bool isOctalDigit(char c) @safe pure nothrowChecks if character is an octal digit.
private bool isIdStart(char c) @safe pure nothrowChecks if character can start an identifier.
private bool isIdStartAt(size_t idx) @safe pureChecks if position has an identifier start character.
private bool isIdContinue(char c) @safe pure nothrowChecks if character can continue an identifier.
private bool isIdContinueAt(size_t idx) @safe pureChecks if position has an identifier continue character.
private bool isZeroWidthChar(dchar c) @safe pure nothrow
Constructors
this(string input, string sourceFilename = "")Constructs a lexer for the given CF source text.

Configuration for the CF parser.

Controls parser behavior including include directive handling and security settings.

Fields
bool enableIncludesWhether to enable include directive processing. Default is `false` for security - enable only when needed with a proper fileReader.
string includeBaseDirBase directory for resolving relative include paths
bool allowAbsolutePathsWhether to allow absolute paths in includes
bool allowParentTraversalWhether to allow parent directory traversal (..) in includes
string delegate(string path) @safe fileReaderFile reader delegate for include resolution
bool enableEnvSubstitutionWhether to enable environment variable substitution
string delegate(string varName) @safe envReaderEnvironment variable reader delegate

Recursive-descent parser for CF source text.

Consumes tokens from a CfLexer and produces a CdmDocument that preserves all metadata needed for roundtrip fidelity including comments, locations, and original formatting.

Example:

auto parser = CfParser!CdmBuilder(`key = "value"`);
auto doc = parser.parseDocument();
assert(doc.root.hasKey("key"));

Fields
CfLexer lexer
Token currentToken
Token peekedToken
bool hasPeeked
bool initialized
size_t nestingDepth
string sourceFilename
CdmComment[] pendingComments
string[] includeStack
size_t includeDepth
bool[string] seenKeys
Builder builder
Methods
Token current() @safe pureReturns the current token without consuming it.
Token peek() @safe purePeeks at the next token without consuming it.
void advance() @safe pureAdvances to the next token.
bool match(TokenType type) @safe pureChecks if the current token matches the expected type.
bool matchAny(TokenType[] types...) @safe pureChecks if the current token matches any of the expected types.
Token expect(TokenType type) @safe pureConsumes the current token if it matches the expected type.
CdmFormat.SeparatorStyle skipSeparators() @safe pureSkips separator tokens between members/elements.
CdmComment[] collectComments() @safe pureCollects pending comments.
void enterNesting() @safe pureIncrements nesting depth with limit check.
void exitNesting() @safe pureDecrements nesting depth.
Builder.Result parseDocument() @safeParses a complete CF document.
void parseObjectMembers(bool explicitBraces = false) @safeParses object members into the given node.
void parseMember(CdmComment[] leadingComments) @safeParses a single key-value member.
void parseValue() @safeParses a value of any type.
void parseObject(bool explicitBraces = true) @trustedParses an object literal.
void parseArray() @safeParses an array literal.
void parseInclude() @safeParses an include directive and merges the included content into the current builder's top-of-stack container.
string normalizeIncludePath(string path) @safe pureNormalizes an include path for security validation.
void validateIncludePath(string normalizedPath, string originalPath, Location loc) @safe pureValidates an include path for security.
void parseStringNode() @safeParses a string node via the builder.
void parseEnvVarNode() @safeParses an environment variable node via the builder.
void parseIntegerNode() @safeParses an integer node via the builder.
void parseFloatNode() @safeParses a float node via the builder.
void parseBooleanNode() @safeParses a boolean node via the builder.
void parseNullNode() @safeParses a null node via the builder.
void parseInfinityNode(bool negative) @safeParses an infinity node via the builder.
void parseNanNode() @safeParses a NaN node via the builder.
void parseDateNode() @safeParses a date node via the builder.
void parseTimeNode() @safeParses a time node via the builder.
void parseDateTimeNode() @safeParses a datetime node via the builder.
private long parseIntegerValue(string raw) @safe pureParses an integer value from raw string.
private double parseFloatValue(string raw) @safe pureParses a float value from raw string.
private CdmFormat.QuoteStyle detectQuoteStyle(string raw) @safe pureDetects quote style from raw string token.
private string parseStringValue(string raw) @safeParses string value from raw token, handling escapes.
private string substituteEnvVars(string s) @safe
private string stripTripleQuotedIndent(string content) @safe pureStrips common indentation from triple-quoted string.
private string[] splitLines(string s) @safe pure
private string decodeEscapes(string s) @safe pureDecodes escape sequences in a string.
private bool allHexDigits(string s) @safe pure nothrow @nogcChecks if all characters in a string are valid hex digits.
private dchar parseHexCodepoint(string hex) @safe pureParses a hex string into a Unicode codepoint.
private void encodeUTF8(ref Appender!string result, dchar c) @safe pureEncodes a Unicode codepoint as UTF-8.
private CdmComment makeComment(Token tok) @safe pureCreates a CdmComment from a token.
private string tokenTypeName(TokenType type) @safe pureConverts TokenType to human-readable name.
private CdmLocation toCdmLoc(Location loc) @safe pureConverts Location to CdmLocation.
private Location toLoc(Location loc) @safe pureConverts Location to Location (identity for compatibility).
Constructors
this(string input, string filename = "", CfParserConfig cfg = CfParserConfig.init)Constructs a parser for the given CF source text.
this(string input, string filename, CfParserConfig cfg, string[] existingStack, size_t depth)Constructs a parser with an existing include stack.

Configuration options for the CF writer.

Controls formatting behavior for output.

Fields
string indentIndentation string (default: 3 spaces per CODE_STYLE)
bool sortKeysSort object keys for deterministic output
bool useHclStyleUse HCL-style (omit `=` before objects)
CdmFormat.SeparatorStyle separatorStyleDefault separator style
CdmFormat.QuoteStyle quoteStyleDefault quote style for new strings
bool minifiedMinified output (no whitespace)
private structCfWriter

Internal CF writer implementation.

Fields
Appender!string output
Methods
void writeDocument(CdmDocument doc) @safeWrites a complete CdmDocument.
void writeMembers(const(CdmMember)[] members, int depth, bool explicit) @safeWrites a sequence of object members.
void writeKey(const CdmMember member) @safeWrites a member key.
void writeSeparator(CdmFormat.SeparatorStyle style, bool isLast) @safeWrites a separator between members.
void writeNode(ref const CdmNode node, int depth) @safeWrites a CdmNode.
void writeObject(ref const CdmNode node, int depth) @safeWrites an object node.
void writeArray(ref const CdmNode node, int depth) @safeWrites an array node.
void writeComments(const(CdmComment)[] comments, int depth) @safeWrites comments.
void writeIndent(int depth) @safeWrites indentation.
void writeVar(ref const var v, int depth) @safeWrites a `var` value in CF format.
private void writeVarObject(ref const var v, int depth) @safeWrites a `var` object in CF format.
private void writeVarArray(ref const var v, int depth) @safeWrites a `var` array in CF format.
private bool isObjectValue(bool isObj) @safe pure nothrow constReturns true if the value is a nested object that should use HCL-style formatting.
void writeVarObjectMembers(ref const var v, int depth) @safeWrites a `var` object as bare key-value pairs (CF/HCL top-level style).
Constructors
this(CfWriterConfig cfg)Constructs a CfWriter with the given configuration.

Functions 12

fnCfLexer tokenize(string input, string filename = "") @safe pureCreates a lexer as an input range for the given CF source.
fnToken[] tokenizeAll(string input, string filename = "") @safe pureTokenizes the entire input and returns all tokens as an array.
fnstring toCf(CdmDocument doc, CfWriterConfig config = CfWriterConfig.init) @safeConverts a `CdmDocument` to CF format string.
fnbool needsQuoting(string key) @safe pure nothrowChecks if a key needs quoting.
fnstring quoteString(string s, CdmFormat.QuoteStyle style) @safe pureQuotes a string with the specified style.
fnauto parseCf(Builder = CdmBuilder)(string source, string filename = "", CfParserConfig config = CfParserConfig.init) @safeParses a CF source string.
fnauto parseCfFile(Builder = CdmBuilder)(string path, CfParserConfig config = CfParserConfig.init)Parses a CF file.
fnCfParserConfig makeEnvConfig() @trustedCreates a CfParserConfig with system environment variable support.
fnauto parseCfWithEnv(Builder = CdmBuilder)(string source, string filename = "") @trustedParses a CF source string with environment variable substitution.
fnauto parseCfWithIncludes(Builder = CdmBuilder)(string source, string filename, string delegate(string path) @safe fileReader) @safeParses a CF source with include support.
fnvar toVar(CdmDocument doc) @safeConverts a CdmDocument to a var for lightweight runtime use.
fnstring varToCf(ref const var v, CfWriterConfig config = CfWriterConfig.init) @safeConverts a `var` value to CF format string.

Variables 3

enumvarMAX_NESTING_DEPTH = 64

Maximum nesting depth for objects and arrays.

This limit prevents stack overflow attacks from deeply nested structures.

enumvarMAX_INCLUDE_DEPTH = 32

Maximum include depth.

This limit prevents excessive include chains.

enumvarMAX_ENV_EXPANSION_SIZE = 1024 * 1024

Maximum size for environment variable expansion.

This limit prevents denial-of-service via excessively large environment variable values. Default is 1 MB.