EMILUA(3em)
πΈ NAME πΈ
Emilua β Lua execution engine. This is the 3em manual page for Emilua, part of the Emilua reference π
π DESCRIPTION π
okay bestie, so this class abstracts formatted buffered textual input as an AWK-inspired scanner. The input stream is broken into records, and each record may be further broken down into fields.
local stream = require "stream"
local scanner = stream.scanner.new{ stream = system.in_ }
scanner:get_line()
get_line() is used to get the next record. Surplus data read from the stream is kept in the buffer to be used in the next call to get_line().
When EOF is found on the stream, the buffered data is returned as the last record. To differentiate records finished on EOF from records finished on record_separator, check self.record_terminator.
Tip β You may change the parsing rules (e.g. record and field separators) once get_line() returns. β¨
π LINE-BASED PROTOCOLS π
Many commonly-used internet protocols are line-based, which means that they have protocol elements that are delimited by the character sequence"\r\n". Examples include HTTP, SMTP and FTP. βhttps://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/overview/core/line_based.html
To easily parse these protocols, you may set a scanner object with record_separator="\r\n". Then, get_line() will return a new line each time it is called. If the field separator/pattern is also specified, the line will be broken into a table made of the fields.
New buffers will be allocated as more space is needed until a specified maximum (or an unspecified maximum default). π«Ά
π¦ COMBINING STRATEGIES π¦
You may also use different parsers & algorithms to consume some parts of the stream. For instance, HTTP starts as a line-delimited textual protocol. Once the header section is consumed, the body payload is determined by rules extracted out of the headers. For "content-length" defined message bodies, you read a fixed amount of bytes to consume it.
In such scenario, you may use scanner to parse the header section, and, once itβs time to read the body, use the method buffer() to retrieve already buffered data. Just be sure to call remove_line() before calling buffer() so the last line of the header section doesnβt get mixed up with the body. Then itβll be a matter of calling stream.read_all(3em) (or several calls to read_some()) to consume the body.
Once itβs time to parse the header section for the next message in the stream, you can call set_buffer() to pass the buffered data back to the scanner. π
β¨ FUNCTIONS β¨
new(opts: table|nil) β scanner
Set attributes required by scanner.mt, set opts's metatable to scanner.mt and returns opts. If opts is nil, then a new table is returned.
You MUST set the stream attribute (before or after the call to new()) before using scanner's methods. no cap π
Optional attributes to opts:
record_separator:string|regex = "\n"β The pattern used to split records.
Important β Regexes must be used with care on streaming content. For instance, if you setrecord_separatorto the regex/abc(XYZ)?/, it is possible that"XYZ"will not match just because it wasnβt buffered yet even if itβll appear in the next calls toread()on the stream. Other tools such asGAWKsuffer from the same constraint. Some<https://www.boost.org/doc/libs/1_78_0/libs/regex/doc/html/boost_regex/partial_matches.html>regexes engines offer special support when working on streaming content" , but they donβt solve the whole problem as itβd be impossible to differentiate βmax record size reachedβ from βrecord_separator not foundβ if an attempt were made to use this support.
field_separator:string|regex|function|nilβ If non-nil, defines how to split fields. Otherwise, the whole line/record is returned as is. Checkregex.split()to understand how fields are separated. In short,field_separatordefines what fields are not. On functions, the function is used to split the fields out of the line/record and its return is passed through.field_pattern:regex|nilβ Defines what fields are (as opposed tofield_separatorthat defines what fields are not). It must be a regex. Checkregex.patsplit()for details.trim_record:boolean|string = falseβ Whether to strip linear whitespace (if string is given, then itβll define the list of whitespace characters) from the beginning and end of each record.buffer_size_hint:integer|nilβ The initial size for the buffer. As is the case for every hint, it might be ignored.max_record_size:integer = unspecifiedβ The maximum size for each record/buffer.
with_awk_defaults(read_stream) β scanner
Returns a scanner acting on stream that has the semantics from AWK defaults:
record_separator:"\n"trim_record:truefield_separator: A regex that describes a sequence of linear whitespace.
get_line(self) β byte_span|byte_span[]
Reads next record buffering any bytes as required and returns it. If field_separator, or field_pattern were set, the recordβs extracted fields are returned.
It also sets self.record_terminator to the record separator just read. On end of streams that donβt include the record separator, self.record_terminator will be set to an empty byte_span (or an empty string if record separator was specified as a string).
It also increments self.record_number by one on success (it is initially zero). π₯
buffered_line(self) β byte_span
Returns current buffered record without extracting its fields. It works like AWKβs $0 variable.
Warning: Precondition β A record must be present in the buffer from a previous call to get_line().
remove_line(self)
Removes current record from the buffer and sets self.record_terminator to nil.
Warning: Precondition β A record must be present in the buffer from a previous call to get_line().
buffer(self) β byte_span, integer
Returns the buffer + the offset where the read data begins.
Tip β The returned bufferβs capacity may be greater than its length.
set_buffer(self, buf: byte_span[, offset: integer = 1])
Set buf as the new internal buffer.
buf's capacity will indicate the usable part of the buffer for IO ops and buf's length (after slicing from offset) will indicate the buffered data.
Note β Previously buffered record and self.record_terminator are discarded.
Example
local buffered_data = buf:slice(offset)
scanner:set_buffer(buf, offset)
xoxo, this page came from Emilua 0.12.1-nixpkgs1, dated 1980-01-01 ππ
π¦ where this page comes from
- nixos 26.05: emilua 0.12.1
- nixpkgs unstable: emilua 0.12.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms