@@ -12,45 +12,124 @@ in the source distribution for its full text.
1212
1313#include <assert.h>
1414#include <stdlib.h>
15+ #include <stdio.h>
1516#include <string.h>
17+ #include <wchar.h>
18+ #include <wctype.h>
19+ #include <locale.h>
1620
21+ #include "CRT.h"
1722#include "Macros.h"
1823#include "Panel.h"
1924#include "ProvideCurses.h"
2025
2126
22- static void CommandScreen_scan (InfoScreen * this ) {
23- Panel * panel = this -> display ;
24- int idx = MAXIMUM (Panel_getSelectedIndex (panel ), 0 );
25- Panel_prune (panel );
26-
27- const char * p = Process_getCommand (this -> process );
28- char line [COLS + 1 ];
29- int line_offset = 0 , last_spc = -1 , len ;
30- for (; * p != '\0' ; p ++ , line_offset ++ ) {
31- assert (line_offset >= 0 && (size_t )line_offset < sizeof (line ));
32- line [line_offset ] = * p ;
33- if (* p == ' ' ) {
34- last_spc = line_offset ;
27+ static int CommandScreen_scanAscii (InfoScreen * this , const char * p , size_t total , char * line ) {
28+ int line_offset = 0 , line_size = 0 , last_spc_offset = -1 ;
29+ for (size_t i = 0 ; i < total ; i ++ , line_offset ++ ) {
30+ assert (line_offset >= 0 && (size_t )line_offset <= total );
31+ char c = line [line_offset ] = p [i ];
32+ if (c == ' ' ) {
33+ last_spc_offset = line_offset ;
3534 }
3635
3736 if (line_offset == COLS ) {
38- len = (last_spc == -1 ) ? line_offset : last_spc ;
39- line [len ] = '\0' ;
37+ line_size = (last_spc_offset == -1 ) ? line_offset : last_spc_offset ;
38+ line [line_size ] = '\0' ;
4039 InfoScreen_addLine (this , line );
4140
42- line_offset -= len ;
43- last_spc = -1 ;
44- memcpy (line , p - line_offset , line_offset + 1 );
41+ line_offset -= line_size ;
42+ last_spc_offset = -1 ;
43+ memcpy (line , p + i - line_offset , line_offset + 1 );
44+ }
45+ }
46+
47+ return line_offset ;
48+ }
49+
50+ #ifdef HAVE_LIBNCURSESW
51+
52+ static int CommandScreen_scanWide (InfoScreen * this , const char * p , size_t total , char * line ) {
53+ mbstate_t state ;
54+ memset (& state , 0 , sizeof (state ));
55+ int line_cols = 0 , line_offset = 0 , line_size = 0 , width = 1 ;
56+ int last_spc_cols = -1 , last_spc_offset = -1 ;
57+ for (size_t i = 0 , bytes = 1 ; i < total ; bytes = 1 , width = 1 ) {
58+ assert (line_offset >= 0 && (size_t )line_offset <= total );
59+ unsigned char c = (unsigned char )p [i ];
60+ if (c < 0x80 ) { // skip mbrtowc for ASCII characters
61+ line [line_offset ] = c ;
62+ if (c == ' ' ) {
63+ last_spc_offset = line_offset ;
64+ last_spc_cols = line_cols ;
65+ }
66+ } else {
67+ wchar_t wc ;
68+ bytes = mbrtowc (& wc , p + i , total - i , & state );
69+ if (bytes != (size_t )-1 && bytes != (size_t )-2 ) {
70+ width = wcwidth (wc );
71+ width = MAXIMUM (width , 1 );
72+ } else {
73+ bytes = 1 ;
74+ }
75+ memcpy (line + line_offset , p + i , bytes );
76+ }
77+
78+ i += bytes ;
79+ line_offset += bytes ;
80+ line_cols += width ;
81+ if (line_cols < COLS ) {
82+ continue ;
83+ }
84+
85+ if (last_spc_offset >= 0 ) { // wrap by last space
86+ line_size = last_spc_offset ;
87+ line_cols -= last_spc_cols ;
88+ last_spc_offset = last_spc_cols = -1 ;
89+ } else if (line_cols > COLS ) { // wrap current wide char to next line
90+ line_size = line_offset - (int ) bytes ;
91+ line_cols = width ;
92+ } else { // wrap by current character
93+ line_size = line_offset ;
94+ line_cols = 0 ;
95+ }
96+
97+ line [line_size ] = '\0' ;
98+ InfoScreen_addLine (this , line );
99+ line_offset -= line_size ;
100+ if (line_offset > 0 ) {
101+ memcpy (line , p + i - line_offset , line_offset + 1 );
45102 }
46103 }
47104
105+ return line_offset ;
106+ }
107+
108+ #endif // HAVE_LIBNCURSESW
109+
110+ static void CommandScreen_scan (InfoScreen * this ) {
111+ Panel * panel = this -> display ;
112+ int idx = Panel_getSelectedIndex (panel );
113+ Panel_prune (panel );
114+
115+ const char * p = Process_getCommand (this -> process );
116+ assert (p != NULL );
117+ size_t total = strlen (p );
118+ char line [total + 1 ];
119+
120+ int line_offset =
121+ #ifdef HAVE_LIBNCURSESW
122+ CRT_utf8 ? CommandScreen_scanWide (this , p , total , line ) :
123+ #endif
124+ CommandScreen_scanAscii (this , p , total , line );
125+
126+ assert (line_offset >= 0 && (size_t )line_offset <= total );
48127 if (line_offset > 0 ) {
49128 line [line_offset ] = '\0' ;
50129 InfoScreen_addLine (this , line );
51130 }
52131
53- Panel_setSelected (panel , idx );
132+ Panel_setSelected (panel , MAXIMUM ( idx , 0 ) );
54133}
55134
56135static void CommandScreen_draw (InfoScreen * this ) {
0 commit comments