Modules

Text_File_Handler

moduleSource
macOSLinuxWindowswasm

#import "Text_File_Handler";

A line reader for simple text and configuration files.

It skips blank lines and # comments, can read a [version] header, and reports problems with the file and line number through the context logger. Use file_to_array or file_to_table to load a whole file, or a Text_File_Handler to go line by line.

ExampleOpen in playground ↗
ok, lines := file_to_array("x", use_data_from_memory = true, data_from_memory = "a\n# c\nb\n");
assert(ok && lines.count == 2);
for line: lines free(line);
array_free(lines);

Procedures#

(handler: *Text_File_Handler, _short_name: string, _full_path: string, _file_data: string, loc := #caller_location)

Starts reading _file_data. _short_name and _full_path only label the messages the handler reports. The text is not copied, so it must outlive the reading; deinit does not free it.

handler: Text_File_Handler;
start_from_memory(*handler, "config", "config", "[2]\nname jai\n");
defer deinit(*handler);
assert(!handler.failed && handler.version == 2);

line, found := consume_next_line(*handler);
assert(found && line == "name jai");
↗
(handler: *Text_File_Handler, short_name: string, full_path: string, optional := false, loc := #caller_location)

Starts reading the file at full_path. The file is read whole into memory, owned by the handler and freed by deinit.

Frees the file the handler read, if any, and empties it. Safe to call twice. Starting the handler again does it too. Lines returned earlier are no longer valid.

(sp: *string) -> (string, bool)

Removes the first line from sp and returns it, and whether there was one. A line ends at \n, \r or \r\n. Nothing is trimmed or skipped: empty lines and comments come out as they are. At the end of the text the result is an empty string and false.

text := "one\r\ntwo\n\nthree";
line, found := consume_next_line(*text);
assert(found && line == "one");
line, found = consume_next_line(*text);
assert(found && line == "two");
line, found = consume_next_line(*text);
assert(found && line == "");
↗
(line: string) -> (left: string, right: string)

Splits line after its first word: the word, and the rest with the spaces before it removed. Both point into line. A line of one word gives an empty rest.

word, rest := break_by_spaces("  set  volume 11 ");
assert(word == "set" && rest == "volume 11");
↗
(handler: Text_File_Handler, format: string, args: ..Any, flags := Log_Flags.NONE, loc := #caller_location)

Logs an error for the handler, as file:line: message, through the context logger. format and args work as in print. The logger receives the ERROR flag together with any flags given. Nothing is written to standard output.

(handler: Text_File_Handler, format: string, args: ..Any, flags := Log_Flags.NONE, loc := #caller_location)

Logs a warning for the handler, as file:line: message, through the context logger. See error.

(filename: string, do_trim := true, skip_blank_lines := true, do_version_number := false, use_data_from_memory := false, data_from_memory := "", loc := #caller_location) -> (success: bool, array: [..] string)

Reads a whole file into an array of lines. Returns whether the file was read and the lines.

ok, lines := file_to_array("list.txt", use_data_from_memory = true, data_from_memory = "a # one\n\nb\n");
assert(ok && lines.count == 2 && lines[0] == "a" && lines[1] == "b");
for line: lines free(line);
array_free(lines);
↗
(filename: string, do_trim := true, skip_blank_lines := true, do_version_number := false, use_data_from_memory := false, data_from_memory := "", loc := #caller_location) -> (success: bool, table: T.Table(string, void))

Like file_to_array, but returns the lines as the keys of a table, so repeated lines are kept once. The second result is the table. The caller frees each key and the table (deinit from Hash_Table). On a failure it is false and an empty table.

ok, table := file_to_table("set.txt", use_data_from_memory = true, data_from_memory = "x\ny\nx\n");
assert(ok && table.count == 2);
↗

Types#

:: struct

Reads a text file line by line, skipping comments and blank lines.

handler: Text_File_Handler;
handler.do_version_number = false;
start_from_memory(*handler, "list", "list", "# fruit\napple # red\n\nbanana\n");
defer deinit(*handler);

line, found := consume_next_line(*handler);
assert(found && line == "apple" && handler.line_number == 2);
line, found = consume_next_line(*handler);
assert(found && line == "banana");
line, found = consume_next_line(*handler);
assert(!found);
↗