diff mbox series

[v2] client: handle wide chars for table rows

Message ID 20221010182603.55042-1-xdavidwuph@gmail.com (mailing list archive)
State New
Headers show
Series [v2] client: handle wide chars for table rows | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
prestwoj/iwd-alpine-ci-fetch success Fetch PR
prestwoj/iwd-ci-gitlint success GitLint
prestwoj/iwd-ci-fetch success Fetch PR
prestwoj/iwd-ci-makedistcheck success Make Distcheck
prestwoj/iwd-ci-incremental_build success Incremental build not run PASS
prestwoj/iwd-ci-build success Build - Configure
prestwoj/iwd-alpine-ci-makedistcheck success Make Distcheck
prestwoj/iwd-alpine-ci-incremental_build success Incremental build not run PASS
prestwoj/iwd-alpine-ci-build success Build - Configure
prestwoj/iwd-ci-makecheckvalgrind fail Make FAIL: client/display.c: In function ‘next_line’: client/display.c:408:36: error: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Werror=sign-compare] 408 | for (i = 0; i <= *max && i != s_len; i++) { | ^~ cc1: all warnings being treated as errors make[1]: *** [Makefile:2408: client/display.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1587: all] Error 2
prestwoj/iwd-ci-clang fail Clang IWD - make FAIL: client/display.c:408:29: error: comparison of integers of different signs: 'unsigned int' and 'int' [-Werror,-Wsign-compare] for (i = 0; i <= *max && i != s_len; i++) { ~ ^ ~~~~~ 1 error generated. make[1]: *** [Makefile:2408: client/display.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1587: all] Error 2
prestwoj/iwd-ci-testrunner pending testrunner SKIP
prestwoj/iwd-ci-makecheck pending makecheck SKIP
prestwoj/iwd-alpine-ci-makecheckvalgrind fail Make FAIL: client/display.c: In function 'next_line': client/display.c:408:36: error: comparison of integer expressions of different signedness: 'unsigned int' and 'int' [-Werror=sign-compare] 408 | for (i = 0; i <= *max && i != s_len; i++) { | ^~ cc1: all warnings being treated as errors make[1]: *** [Makefile:2409: client/display.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1588: all] Error 2
prestwoj/iwd-alpine-ci-makecheck pending makecheck SKIP

Commit Message

Pinghao Wu Oct. 10, 2022, 6:26 p.m. UTC
Find out printing width of wide chars via wcwidth().
---
 client/display.c | 18 ++++++++++++++----
 client/main.c    |  3 +++
 2 files changed, 17 insertions(+), 4 deletions(-)

Comments

James Prestwood Oct. 10, 2022, 7:22 p.m. UTC | #1
Hi Pinghao,

On Tue, 2022-10-11 at 02:26 +0800, Pinghao Wu wrote:
> Find out printing width of wide chars via wcwidth().
> ---
>  client/display.c | 18 ++++++++++++++----
>  client/main.c    |  3 +++
>  2 files changed, 17 insertions(+), 4 deletions(-)
> 
> diff --git a/client/display.c b/client/display.c
> index b729ad4c..42b5336e 100644
> --- a/client/display.c
> +++ b/client/display.c
> @@ -30,6 +30,7 @@
>  #include <sys/stat.h>
>  #include <sys/ioctl.h>
>  #include <unistd.h>
> +#include <wchar.h>
>  
>  #include <readline/history.h>
>  #include <readline/readline.h>
> @@ -401,18 +402,27 @@ static char* next_line(char *s, unsigned int
> *max, char **color_out)
>         unsigned int i;
>         int last_space = -1;
>         int last_color = -1;
> +       int s_len = strlen(s);
>  
>         /* Find the last space before 'max', as well as any color */
> -       for (i = 0; i <= *max && s[i] != '\0'; i++) {
> +       for (i = 0; i <= *max && i != s_len; i++) {

I know you didn't write the for-loop originally, but now since you're
incrementing i by some value larger than 1 it makes more sense to use a
while loop and break out if i > *max. In addition I think you could
blow past the i != s_len check.

I think this entire thing could be simplified now with you're changes
by putting l_utf8_get_codepoint into a while loop and always calling
wcwidth() for each character. Then we aren't distinguishing between
ascii and utf-8, just always increment i/max by the needed values (also
taking into account the space/color checks obviously).

>                 if (s[i] == ' ')
>                         last_space = i;
>                 else if (s[i] == 0x1b) {
>                         /* color escape won't count for column width
> */
>                         *max += color_end(s + i);
>                         last_color = i;
> -               /* Add width for non-codepoint UTF-8 bytes */
> -               } else if (((uint8_t)s[i] >> 6) == 2)
> -                       *max += 1;
> +               /* Non-ASCII */
> +               } else if (s[i] & 0x80) {
> +                       wchar_t w;
> +                       int w_mblen = l_utf8_get_codepoint(&s[i],
> s_len - i, &w);
> +                       if (w_mblen > 0) {
> +                               /* Compensate max bytes */
> +                               *max += w_mblen - wcwidth(w);
> +                               /* Skip other bytes of this codepoint
> */
> +                               i += w_mblen - 1;
> +                       }
> +               }
>         }
>  
>         /* Reached the end of the string within the column bounds */
> diff --git a/client/main.c b/client/main.c
> index df5c0a61..7e8dead4 100644
> --- a/client/main.c
> +++ b/client/main.c
> @@ -25,6 +25,7 @@
>  #endif
>  
>  #include <errno.h>
> +#include <locale.h>
>  #include <signal.h>
>  #include <ell/ell.h>
>  
> @@ -50,6 +51,8 @@ int main(int argc, char *argv[])
>  {
>         bool all_done;
>  
> +       setlocale(LC_CTYPE, "");
> +
>         if (!l_main_init())
>                 return EXIT_FAILURE;
>
diff mbox series

Patch

diff --git a/client/display.c b/client/display.c
index b729ad4c..42b5336e 100644
--- a/client/display.c
+++ b/client/display.c
@@ -30,6 +30,7 @@ 
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
+#include <wchar.h>
 
 #include <readline/history.h>
 #include <readline/readline.h>
@@ -401,18 +402,27 @@  static char* next_line(char *s, unsigned int *max, char **color_out)
 	unsigned int i;
 	int last_space = -1;
 	int last_color = -1;
+	int s_len = strlen(s);
 
 	/* Find the last space before 'max', as well as any color */
-	for (i = 0; i <= *max && s[i] != '\0'; i++) {
+	for (i = 0; i <= *max && i != s_len; i++) {
 		if (s[i] == ' ')
 			last_space = i;
 		else if (s[i] == 0x1b) {
 			/* color escape won't count for column width */
 			*max += color_end(s + i);
 			last_color = i;
-		/* Add width for non-codepoint UTF-8 bytes */
-		} else if (((uint8_t)s[i] >> 6) == 2)
-			*max += 1;
+		/* Non-ASCII */
+		} else if (s[i] & 0x80) {
+			wchar_t w;
+			int w_mblen = l_utf8_get_codepoint(&s[i], s_len - i, &w);
+			if (w_mblen > 0) {
+				/* Compensate max bytes */
+				*max += w_mblen - wcwidth(w);
+				/* Skip other bytes of this codepoint */
+				i += w_mblen - 1;
+			}
+		}
 	}
 
 	/* Reached the end of the string within the column bounds */
diff --git a/client/main.c b/client/main.c
index df5c0a61..7e8dead4 100644
--- a/client/main.c
+++ b/client/main.c
@@ -25,6 +25,7 @@ 
 #endif
 
 #include <errno.h>
+#include <locale.h>
 #include <signal.h>
 #include <ell/ell.h>
 
@@ -50,6 +51,8 @@  int main(int argc, char *argv[])
 {
 	bool all_done;
 
+	setlocale(LC_CTYPE, "");
+
 	if (!l_main_init())
 		return EXIT_FAILURE;