shithub: sl

Download patch

ref: 31e59bb74dcaa3273e93a6585e902df407f17ac6
parent: 52d518b5e346b66e9023ec35101480f706810977
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Tue Jan 28 20:02:46 EST 2025

string-width: fix for strings containing \0

--- a/src/print.c
+++ b/src/print.c
@@ -17,18 +17,17 @@
 		FL(hpos)++;
 }
 
-static void
-outs(ios_t *f, const char *s)
+static inline void
+outsn(ios_t *f, const char *s, size_t n)
 {
-	ios_puts(f, s);
-	FL(hpos) += u8_strwidth(s);
+	ios_write(f, s, n);
+	FL(hpos) += u8_strwidth(s, n);
 }
 
-static void
-outsn(ios_t *f, const char *s, size_t n)
+static inline void
+outs(ios_t *f, const char *s)
 {
-	ios_write(f, s, n);
-	FL(hpos) += u8_strwidth(s);
+	outsn(f, s, strlen(s));
 }
 
 static int
@@ -167,8 +166,10 @@
 static inline int
 tinyp(value_t v)
 {
-	if(issymbol(v))
-		return u8_strwidth(symbol_name(v)) < SMALL_STR_LEN;
+	if(issymbol(v)){
+		const char *s = symbol_name(v);
+		return u8_strwidth(s, strlen(s)) < SMALL_STR_LEN;
+	}
 	if(fl_isstring(v))
 		return cv_len(ptr(v)) < SMALL_STR_LEN;
 	return (
@@ -215,8 +216,10 @@
 lengthestimate(value_t v)
 {
 	// get the width of an expression if we can do so cheaply
-	if(issymbol(v))
-		return u8_strwidth(symbol_name(v));
+	if(issymbol(v)){
+		const char *s = symbol_name(v);
+		return u8_strwidth(s, strlen(s));
+	}
 	if(iscprim(v) && ptr(v) != nil && cp_class(ptr(v)) == FL(runetype))
 		return 4;
 	return -1;
--- a/src/string.c
+++ b/src/string.c
@@ -51,7 +51,11 @@
 			return w < 0 ? FL_f : fixnum(w);
 		}
 	}
-	return size_wrap(u8_strwidth(tostring(args[0])));
+	if(!fl_isstring(args[0]))
+		type_error("string", args[0]);
+	char *str = tostring(args[0]);
+	size_t len = cv_len(ptr(args[0]));
+	return size_wrap(u8_strwidth(str, len));
 }
 
 BUILTIN("string-reverse", string_reverse)
--- a/src/utf8.c
+++ b/src/utf8.c
@@ -62,12 +62,12 @@
 }
 
 size_t
-u8_strwidth(const char *s)
+u8_strwidth(const char *s, size_t n)
 {
 	size_t i, w;
 	Rune r;
 
-	for(i = w = 0; s[i];){
+	for(i = w = 0; i < n;){
 		i += chartorune(&r, s+i);
 		w += fl_wcwidth(r);
 	}
--- a/src/utf8.h
+++ b/src/utf8.h
@@ -49,7 +49,7 @@
 char *u8_memchr(char *s, Rune ch, size_t sz, size_t *charn);
 
 /* number of columns occupied by a string */
-size_t u8_strwidth(const char *s) fl_purefn;
+size_t u8_strwidth(const char *s, size_t n) fl_purefn;
 
 /* determine whether a sequence of bytes is valid UTF-8. length is in bytes */
 int u8_isvalid(const char *str, int length) fl_purefn;
--- a/test/unittest.lsp
+++ b/test/unittest.lsp
@@ -514,5 +514,8 @@
 (assert (equal? "" (string-reverse "")))
 (assert (equal? "й" (string-reverse "й")))
 
+(assert (eq? 10 (string-width s)))
+(assert (eq? 0 (string-width "")))
+
 (princ "all tests pass")
 (newline)