hare

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

escape.ha (1411B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use ascii;
      5 use encoding::utf8;
      6 use io;
      7 use memio;
      8 use strings;
      9 
     10 fn is_safe(s: str) bool = {
     11 	const iter = strings::iter(s);
     12 	for (true) {
     13 		const rn = match (strings::next(&iter)) {
     14 		case let rn: rune =>
     15 			yield rn;
     16 		case void =>
     17 			break;
     18 		};
     19 
     20 
     21 		switch (rn) {
     22 		case '@', '%', '+', '=', ':', ',', '.', '/', '-' =>
     23 			void;
     24 		case =>
     25 			if (!ascii::isalnum(rn) || ascii::isspace(rn)) {
     26 				return false;
     27 			};
     28 		};
     29 	};
     30 	return true;
     31 };
     32 
     33 // Quotes a shell string and writes it to the provided I/O handle.
     34 export fn quote(sink: io::handle, s: str) (size | io::error) = {
     35 	if (len(s) == 0) {
     36 		return io::writeall(sink, strings::toutf8(`''`))?;
     37 	};
     38 	if (is_safe(s)) {
     39 		return io::writeall(sink, strings::toutf8(s))?;
     40 	};
     41 
     42 	let z = io::writeall(sink, ['\''])?;
     43 
     44 	const iter = strings::iter(s);
     45 	for (true) {
     46 		const rn = match (strings::next(&iter)) {
     47 		case let rn: rune =>
     48 			yield rn;
     49 		case void =>
     50 			break;
     51 		};
     52 
     53 		if (rn == '\'') {
     54 			z += io::writeall(sink, strings::toutf8(`'"'"'`))?;
     55 		} else {
     56 			z += io::writeall(sink, utf8::encoderune(rn))?;
     57 		};
     58 	};
     59 
     60 	z += io::writeall(sink, ['\''])?;
     61 	return z;
     62 };
     63 
     64 // Quotes a shell string and returns a new string. The caller must free the
     65 // return value.
     66 export fn quotestr(s: str) str = {
     67 	const sink = memio::dynamic();
     68 	quote(&sink, s)!;
     69 	return memio::string(&sink)!;
     70 };