tacker

a simple web bundler
git clone https://tongong.net/git/tacker.git
Log | Files | Refs | README

commit faeacbedade2cb621e276ae2cc6c1358aea06d33
parent 5c745a502396955c68f7b7aad70a81b169cf883b
Author: tongong <tongong@gmx.net>
Date:   Mon, 20 Jun 2022 13:39:29 +0200

added tests and removed []rune->str conversion etc

My understanding of utf8 was wrong.

Diffstat:
MMakefile | 7+++++--
Mmain.ha | 7++-----
Mpath_helpers.ha | 40++++++++++++++++++++++++++++++++++++++++
Msearchio/searchio.ha | 54+++++++++++++++++++++++-------------------------------
Dstring_helpers.ha | 62--------------------------------------------------------------
5 files changed, 70 insertions(+), 100 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,7 +1,10 @@ PREFIX=/usr/local tacker: *.ha - hare build -o tacker . + hare build -o tacker + +test: + hare test clean: rm -rf tacker @@ -14,4 +17,4 @@ install: tacker uninstall: rm -rf $(DESTDIR)$(PREFIX)/bin/tacker -.PHONY: clean install uninstall +.PHONY: test clean install uninstall diff --git a/main.ha b/main.ha @@ -52,13 +52,10 @@ export fn main() void = { // (because of fmt::fatalf) // defer free(ifile); - let slc = strings::runes(ifile); - defer free(slc); - let extstart = lastdotindex(slc); + let extstart = lastdotindex(ifile); if (extstart == -1) fmt::fatalf("file \"{}\" has broken filetype.", ifile); - let ext = runes_to_str(slc[(extstart + 1)..]); - defer free(ext); + let ext = strings::fromutf8(strings::toutf8(ifile)[(extstart + 1)..]); switch (ext) { case "html" => tacker_html(ifile, ofile); diff --git a/path_helpers.ha b/path_helpers.ha @@ -1,6 +1,7 @@ use fmt; use fs; use os; +use slices; use strings; // All bundled files must be within this directory so that malicious modules @@ -47,3 +48,42 @@ fn resolve_path(path: str, from: str) str = { r, basepath); return r; }; + +// Returns index of the last dot in the filename or -1 if the file contains no +// dot. +fn lastdotindex(filename: str) int = { + const filename = strings::toutf8(filename); + let index = (len(filename) - 1): int; + for (index >= 0 && filename[index] != '.') { + if (filename[index] == '/') return -1; + index -= 1; + }; + return index; +}; + +// return value has to be freed. +fn file_name_bundled(filename: str) str = { + let lastdot = lastdotindex(filename); + // files without extension get the .bundle at the end + if (lastdot == -1) lastdot = len(filename): int; + + const output = strings::dup(filename); + const output = strings::toutf8(output); + + const ext = strings::toutf8(".bundle"); + let bptr: [7]*void = [&ext: *void ...]; + for (let i = 0z; i < len(ext); i += 1) { + bptr[i] = &ext[i]; + }; + slices::insertinto(&output: *[]void, size(u8), lastdot: size, bptr...); + return strings::fromutf8(output); +}; + +@test fn file_name_bundled() void = { + assert(file_name_bundled("test.js") == "test.bundle.js"); + assert(file_name_bundled("test.dot.js") == "test.dot.bundle.js"); + assert(file_name_bundled("no-ext") == "no-ext.bundle"); + assert(file_name_bundled("./dir.a/no-ext") == "./dir.a/no-ext.bundle"); + assert(file_name_bundled("./test.dir/ütf8.html") == + "./test.dir/ütf8.bundle.html"); +}; diff --git a/searchio/searchio.ha b/searchio/searchio.ha @@ -1,31 +1,9 @@ -use fmt; +use bufio; use io; use os; use sort; use strings; -// // reads until end is read and pipes all read bytes to ofile (end itself not) -// // returns true if end is reached, false on EOF -// fn read_until(ifile: io::handle, ofile: io::handle, end: str) bool = { -// let end = strings::toutf8(end); -// let currIndex = 0z; // the current index in the buffer to check -// for (true) { -// const buf: [1]u8 = [' ']; -// if (io::read(ifile, buf) is io::EOF) return false; -// if (buf[0] == end[currIndex]) { -// currIndex += 1; -// if (currIndex == len(end)) return true; -// } else { -// if (currIndex != 0) { -// io::write(ofile, end[..currIndex])!; -// currIndex = 0; -// }; -// io::write(ofile, buf)!; -// }; -// }; -// return false; // unreachable -// }; - // sorted export type pattern = []patternelem; export type patternelem = struct { @@ -68,14 +46,6 @@ export fn compile(s: []str) pattern = { } else break; }; }; - // for (let i = 0z; i < len(p); i+= 1) { - // fmt::print(p[i].index)!; - // for (let j = 0z; j < len(p[i].data); j+= 1) { - // fmt::print(" ")!; - // fmt::print(p[i].data[j])!; - // }; - // fmt::println()!; - // }; return p; }; @@ -135,3 +105,25 @@ export fn search(ifile: io::handle, ofile: io::handle, end: pattern) }; return io::EOF; // unreachable }; + +@test fn searchio() void = { + const input = "inputstreamtesttest word2word1 tertemp"; + const input = &bufio::fixed(strings::toutf8(input), io::mode::READ); + const output = bufio::dynamic(io::mode::WRITE); + const outbuf = &output.buf; + const output = &output; + defer io::close(output)!; + + const p = compile(["temp", "test", "word1"]); + const matches: [_]size = [1, 1, 2, 0]; + let matchesindex = 0; + for (true) { + const m = search(input, output, p); + if (m is size) { + const m = m: size; + assert(matches[matchesindex] == m); + matchesindex += 1; + } else break; + }; + assert("inputstream word2 ter" == strings::fromutf8(*outbuf)); +}; diff --git a/string_helpers.ha b/string_helpers.ha @@ -1,62 +0,0 @@ -use encoding::utf8; -use fmt; -use rt; -use slices; -use strings; -use types; - -// Inverse of strings::runes(). -// why is not something like this in the stdlib? -// why does insertinto take a slice of pointers and not a pointer to a slice? -fn runes_to_str(runes: []rune) str = { - let buffer = alloc([], len(runes) * 4): []u8: *[*]u8; - let index = 0z; - for (let i = 0z; i < len(runes); i += 1) { - const u = encoding::utf8::encoderune(runes[i]); - rt::memcpy(&buffer[index], &u[0], len(u)); - index += len(u); - }; - const s = types::string { - data = buffer, - length = index, - capacity = len(runes) * 4, - }; - return *(&s: *const str); -}; - -// Returns index of the last dot in the filename or -1 if the file contains no -// dot. -fn lastdotindex(filename: []rune) int = { - let index = (len(filename) - 1): int; - for (index >= 0 && filename[index] != '.') { - if (filename[index] == '/') { - index = -1; - break; - }; - index -= 1; - }; - return index; -}; - -// Input is borrowed, return value has to be freed. -// test.js -> test.bundle.js -// test.dot.js -> test.dot.bundle.js -// no-ext -> no-ext.bundle -fn file_name_bundled(ifile: str) str = { - let slc = strings::runes(ifile); - defer free(slc); - let lastdot = lastdotindex(slc); - // files without extension get the .bundle at the end - if (lastdot == -1) lastdot = len(slc): int; - - static let b: []rune = []; - static let bptr: [7]*void = [&b: *void ...]; - if (len(b) == 0) { - b = strings::runes(".bundle"); - for (let i = 0z; i < len(b); i += 1) { - bptr[i] = &b[i]; - }; - }; - slices::insertinto(&slc: *[]void, size(rune), lastdot: size, bptr...); - return runes_to_str(slc); -};