hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

scan.ha (1968B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use bufio;
      5 use io;
      6 use strings;
      7 
      8 export type scanner = struct {
      9 	scan: bufio::scanner,
     10 	lineno: size,
     11 	section: str,
     12 };
     13 
     14 // Creates an INI file scanner. Use [[next]] to read entries. The caller must
     15 // call [[finish]] once they're done with this object.
     16 export fn scan(in: io::handle) scanner = {
     17 	return scanner {
     18 		scan = bufio::newscanner(in),
     19 		lineno = 1,
     20 		...
     21 	};
     22 };
     23 
     24 // Frees resources associated with a [[scanner]].
     25 export fn finish(sc: *scanner) void = {
     26 	bufio::finish(&sc.scan);
     27 	free(sc.section);
     28 };
     29 
     30 // An entry in an INI file: (section, key, value).
     31 export type entry = (const str, const str, const str);
     32 
     33 // Duplicates an [[entry]]. Use [[entry_finish]] to get rid of it.
     34 export fn entry_dup(ent: entry) entry = (
     35 	strings::dup(ent.0),
     36 	strings::dup(ent.1),
     37 	strings::dup(ent.2),
     38 );
     39 
     40 // Frees an [[entry]] previously duplicated with [[entry_dup]].
     41 export fn entry_finish(ent: entry) void = {
     42 	free(ent.0);
     43 	free(ent.1);
     44 	free(ent.2);
     45 };
     46 
     47 // Returns the next entry from an INI file. The return value is borrowed from
     48 // the [[scanner]]. Use [[entry_dup]] to retain a copy.
     49 export fn next(sc: *scanner) (entry | io::EOF | error) = {
     50 	for (const line => bufio::scan_line(&sc.scan)?) {
     51 		defer sc.lineno += 1;
     52 
     53 		const line = strings::trim(line);
     54 		if (len(line) == 0 || strings::hasprefix(line, "#")) {
     55 			continue;
     56 		};
     57 
     58 		if (strings::hasprefix(line, "[")) {
     59 			const end = match (strings::index(line, ']')) {
     60 			case let idx: size =>
     61 				yield idx;
     62 			case void =>
     63 				return sc.lineno: syntaxerr;
     64 			};
     65 			free(sc.section);
     66 			sc.section = strings::dup(strings::sub(line, 1, end));
     67 			continue;
     68 		};
     69 
     70 		const eq = match (strings::index(line, '=')) {
     71 		case let idx: size =>
     72 			yield idx;
     73 		case void =>
     74 			return sc.lineno: syntaxerr;
     75 		};
     76 		return (
     77 			sc.section,
     78 			strings::sub(line, 0, eq),
     79 			strings::sub(line, eq + 1, strings::end),
     80 		);
     81 	};
     82 
     83 	return io::EOF;
     84 };