diff options
author | erdgeist <> | 2010-10-09 03:58:43 +0000 |
---|---|---|
committer | erdgeist <> | 2010-10-09 03:58:43 +0000 |
commit | db52d59bd2769cc4cc81a20bfd58c07ed34d619c (patch) | |
tree | c4ec38a65bb95d112879e0bae37d675d608f47a1 | |
parent | a468c875f7a35c595b2eb575ad99354e3e9c3662 (diff) |
Handle utf8 in readline correctly
-rwxr-xr-x | vchat-ui.c | 142 |
1 files changed, 87 insertions, 55 deletions
@@ -31,6 +31,7 @@ | |||
31 | #include <openssl/pem.h> | 31 | #include <openssl/pem.h> |
32 | #include <regex.h> | 32 | #include <regex.h> |
33 | #include "vchat.h" | 33 | #include "vchat.h" |
34 | #include <wchar.h> | ||
34 | 35 | ||
35 | /* version of this module */ | 36 | /* version of this module */ |
36 | char *vchat_ui_version = "$Id$"; | 37 | char *vchat_ui_version = "$Id$"; |
@@ -54,8 +55,6 @@ static WINDOW *output = NULL; | |||
54 | /* our screen dimensions */ | 55 | /* our screen dimensions */ |
55 | static int screensx = 0; | 56 | static int screensx = 0; |
56 | static int screensy = 0; | 57 | static int screensy = 0; |
57 | /* length of last input on line (for clearing) */ | ||
58 | static int lastlen = 0; | ||
59 | /* current horizontal scrolling offset for input line */ | 58 | /* current horizontal scrolling offset for input line */ |
60 | static int scroff = 0; | 59 | static int scroff = 0; |
61 | /* cache for stepping value of horizontal scrolling */ | 60 | /* cache for stepping value of horizontal scrolling */ |
@@ -140,6 +139,35 @@ togglequery() { | |||
140 | } | 139 | } |
141 | } | 140 | } |
142 | 141 | ||
142 | const char * skip_to_character( const char * string, size_t offset ) { | ||
143 | mbstate_t mbs; | ||
144 | memset(&mbs, 0, sizeof(mbs)); | ||
145 | |||
146 | while( offset-- > 0 ) { | ||
147 | size_t ch_size = mbrlen( string, MB_CUR_MAX, &mbs ); | ||
148 | if( ch_size < 0 ) return NULL; | ||
149 | if( !ch_size ) break; | ||
150 | string += ch_size; | ||
151 | } | ||
152 | return string; | ||
153 | } | ||
154 | |||
155 | size_t offset_to_character( const char * string, size_t offset ) { | ||
156 | mbstate_t mbs; | ||
157 | memset(&mbs, 0, sizeof(mbs)); | ||
158 | const char * string_offset = string + offset; | ||
159 | size_t nchars = 0; | ||
160 | |||
161 | while( string < string_offset ) { | ||
162 | size_t ch_size = mbrlen( string, MB_CUR_MAX, &mbs ); | ||
163 | if( ch_size < 0 ) return -1; | ||
164 | if( !ch_size ) break; | ||
165 | string += ch_size; | ||
166 | nchars++; | ||
167 | } | ||
168 | return nchars; | ||
169 | } | ||
170 | |||
143 | /* readlines callback when a line is completed */ | 171 | /* readlines callback when a line is completed */ |
144 | static void | 172 | static void |
145 | linecomplete (char *line) | 173 | linecomplete (char *line) |
@@ -150,35 +178,31 @@ linecomplete (char *line) | |||
150 | /* send linefeed, return pointer, reset cursors */ | 178 | /* send linefeed, return pointer, reset cursors */ |
151 | waddch (input, '\n'); | 179 | waddch (input, '\n'); |
152 | wmove (input, 0, 0); | 180 | wmove (input, 0, 0); |
153 | rl_point = 0; | ||
154 | scroff = 0; | 181 | scroff = 0; |
155 | 182 | ||
156 | if (line) { | 183 | if (line) { |
157 | i = strlen(line)-1; | 184 | i = strlen(line) - 1; |
158 | while (line[i] == ' ') line[i--]='\0'; | 185 | while (line[i] == ' ') line[i--]='\0'; |
159 | 186 | ||
160 | if (line[0] && strchr(line,' ') == NULL && line[i] == ':') | 187 | if (line[0] && strchr(line,' ') == NULL && line[i] == ':') |
161 | line[i--] = '\0'; | 188 | line[i--] = '\0'; |
162 | |||
163 | /* empty line? nada. */ | ||
164 | if (!line[0]) | ||
165 | return; | ||
166 | 189 | ||
190 | /* empty line? nada. */ | ||
191 | if (line[0]) { | ||
167 | /* add line to history and have it handled in vchat-protocol.c */ | 192 | /* add line to history and have it handled in vchat-protocol.c */ |
168 | add_history (line); | 193 | add_history (line); |
169 | handleline (line); | 194 | handleline (line); |
170 | free (line); | 195 | } |
171 | 196 | free (line); | |
172 | /* If in query mode, feed query prefix */ | 197 | rl_reset_line_state(); |
173 | if (( c = querypartner )) | 198 | rl_point = rl_end = rl_done = 0; |
174 | while( *c ) rl_stuff_char( *c++ ); | 199 | |
175 | 200 | /* If in query mode, feed query prefix */ | |
176 | /* wipe input line and reset cursor */ | 201 | if (( c = querypartner )) |
177 | wmove (input, 0, 0); | 202 | while( *c ) rl_stuff_char( *c++ ); |
178 | for (i = 0; i < getmaxx(input) - 1; i++) | 203 | |
179 | waddch (input, ' '); | 204 | /* wipe input line and reset cursor */ |
180 | wmove (input, 0, 0); | 205 | wrefresh (input); |
181 | wrefresh (input); | ||
182 | } | 206 | } |
183 | } | 207 | } |
184 | 208 | ||
@@ -187,36 +211,48 @@ static void | |||
187 | vciredraw (void) | 211 | vciredraw (void) |
188 | { | 212 | { |
189 | int i; | 213 | int i; |
214 | size_t readline_point; | ||
215 | |||
216 | /* readline offers us information we don't need | ||
217 | so ignore outabound cursor positions */ | ||
218 | if( rl_point < 0 ) rl_point = 0; | ||
219 | //if( rl_point > rl_end ) rl_point = rl_end; | ||
220 | |||
221 | readline_point = offset_to_character( rl_line_buffer, rl_point ); | ||
222 | |||
190 | /* hscroll value cache set up? */ | 223 | /* hscroll value cache set up? */ |
191 | if (!hscroll) | 224 | if (!hscroll) { |
192 | { | 225 | /* check config-option or set hardcoded default */ |
193 | /* check config-option or set hardcoded default */ | 226 | hscroll = getintoption (CF_HSCROLL); |
194 | hscroll = getintoption (CF_HSCROLL); | 227 | if (!hscroll) |
195 | if (!hscroll) | 228 | hscroll = 15; |
196 | hscroll = 5; | 229 | } |
197 | } | ||
198 | 230 | ||
199 | /* calculate horizontal scrolling offset */ | 231 | /* calculate horizontal scrolling offset */ |
200 | if (rl_point - scroff < 0) | 232 | |
201 | scroff = rl_point - 4; | 233 | /* Case 1: readline is left of current scroll offset: Adjust to left to reveal more text */ |
202 | if (rl_point - scroff > getmaxx(input) - 1 ) | 234 | if( readline_point < scroff ) |
203 | scroff = rl_point - getmaxx(input) + 1; | 235 | scroff = readline_point - hscroll; |
204 | if (rl_point - scroff > getmaxx(input) - 1 - (hscroll - 2)) | 236 | if( scroff < 1 ) |
205 | scroff += hscroll; | ||
206 | else if (rl_point - scroff < getmaxx(input) - 1 - (hscroll + 2)) | ||
207 | scroff -= hscroll; | ||
208 | if (scroff < 0) | ||
209 | scroff = 0; | 237 | scroff = 0; |
210 | 238 | ||
239 | /* Case 2: readline just hit the last char on the line: Adjust to right to leave more space on screen */ | ||
240 | if( readline_point >= scroff + getmaxx(input) - 1 ) | ||
241 | scroff = readline_point - getmaxx(input) + hscroll; | ||
242 | |||
211 | /* wipe input line */ | 243 | /* wipe input line */ |
212 | wmove (input, 0, 0); | 244 | wmove (input, 0, 0); |
213 | for (i = 0; i < getmaxx(input) - 1; i++) | 245 | for (i = 0; i < getmaxx(input) - 1; i++) |
214 | waddch (input, ' '); | 246 | waddch (input, ' '); |
215 | 247 | ||
216 | /* show current line, move cursor, redraw! */ | 248 | /* show current line, move cursor, redraw! */ |
217 | mvwaddnstr (input, 0, 0, &rl_line_buffer[scroff], getmaxx(input) - 1 ); | 249 | const char *start_line = skip_to_character( rl_line_buffer, scroff ); |
218 | wmove (input, 0, rl_point - scroff); | 250 | const char *end_line = skip_to_character( start_line, getmaxx(input) - 1 ); |
251 | |||
252 | mvwaddnstr (input, 0, 0, start_line, end_line - start_line ); | ||
253 | wmove (input, 0, readline_point - scroff ); | ||
219 | wrefresh (input); | 254 | wrefresh (input); |
255 | |||
220 | } | 256 | } |
221 | 257 | ||
222 | /* called by the eventloop in vchat-client.c */ | 258 | /* called by the eventloop in vchat-client.c */ |
@@ -1375,17 +1411,15 @@ nickprompt (void) | |||
1375 | while (!nick || !nick[0]) | 1411 | while (!nick || !nick[0]) |
1376 | { | 1412 | { |
1377 | if (nick) | 1413 | if (nick) |
1378 | free (nick); | 1414 | free (nick); |
1379 | nick = readline(""); | 1415 | nick = readline(""); |
1380 | } | 1416 | } |
1381 | setstroption(CF_NICK,nick); | 1417 | setstroption(CF_NICK,nick); |
1382 | 1418 | ||
1383 | /* try to get readlines stats clean again */ | 1419 | /* try to get readlines stats clean again */ |
1384 | //rl_free_line_state (); | 1420 | //rl_free_line_state (); |
1385 | rl_point = 0; | 1421 | memset( rl_line_buffer, 0, rl_end ); |
1386 | rl_done = 0; | 1422 | rl_point = rl_end = rl_done = 0; |
1387 | rl_line_buffer[0] = 0; | ||
1388 | lastlen = 23; | ||
1389 | 1423 | ||
1390 | /* wipe input line and reset cursor */ | 1424 | /* wipe input line and reset cursor */ |
1391 | rl_kill_full_line(0,0); | 1425 | rl_kill_full_line(0,0); |
@@ -1422,7 +1456,7 @@ passprompt (char *buf, int size, int rwflag, void *userdata) | |||
1422 | { | 1456 | { |
1423 | int i; | 1457 | int i; |
1424 | char *passphrase = NULL; | 1458 | char *passphrase = NULL; |
1425 | 1459 | ||
1426 | /* use special non-revealing redraw function */ | 1460 | /* use special non-revealing redraw function */ |
1427 | /* FIXME: passphrase isn't protected against e.g. swapping */ | 1461 | /* FIXME: passphrase isn't protected against e.g. swapping */ |
1428 | rl_redisplay_function = vcnredraw; | 1462 | rl_redisplay_function = vcnredraw; |
@@ -1432,7 +1466,7 @@ passprompt (char *buf, int size, int rwflag, void *userdata) | |||
1432 | while (!passphrase || !passphrase[0]) | 1466 | while (!passphrase || !passphrase[0]) |
1433 | { | 1467 | { |
1434 | if (passphrase) | 1468 | if (passphrase) |
1435 | free (passphrase); | 1469 | free (passphrase); |
1436 | passphrase = readline (""); | 1470 | passphrase = readline (""); |
1437 | } | 1471 | } |
1438 | 1472 | ||
@@ -1445,11 +1479,9 @@ passprompt (char *buf, int size, int rwflag, void *userdata) | |||
1445 | 1479 | ||
1446 | /* try to get readlines stats clean again */ | 1480 | /* try to get readlines stats clean again */ |
1447 | //rl_free_line_state (); | 1481 | //rl_free_line_state (); |
1448 | rl_point = 0; | 1482 | memset( rl_line_buffer, 0, rl_end ); |
1449 | rl_done = 0; | 1483 | rl_point = rl_end = rl_done = 0; |
1450 | rl_line_buffer[0] = 0; | 1484 | |
1451 | lastlen = 23; | ||
1452 | |||
1453 | /* wipe input line and reset cursor */ | 1485 | /* wipe input line and reset cursor */ |
1454 | wmove (input, 0, 0); | 1486 | wmove (input, 0, 0); |
1455 | for (i = 0; i < getmaxx(input) - 1; i++) | 1487 | for (i = 0; i < getmaxx(input) - 1; i++) |
@@ -1482,7 +1514,7 @@ static int | |||
1482 | removefromfilterlist( int(*test)(filt *flt, void *data, char colour), void *data, char colour) { | 1514 | removefromfilterlist( int(*test)(filt *flt, void *data, char colour), void *data, char colour) { |
1483 | filt **flt = &filterlist, *tmp; | 1515 | filt **flt = &filterlist, *tmp; |
1484 | int removed = 0, stop = 0; | 1516 | int removed = 0, stop = 0; |
1485 | 1517 | ||
1486 | while( *flt && !stop ) { | 1518 | while( *flt && !stop ) { |
1487 | switch( test( *flt, data, colour ) ) { | 1519 | switch( test( *flt, data, colour ) ) { |
1488 | case RMFILTER_RMANDSTOP: /* remove */ | 1520 | case RMFILTER_RMANDSTOP: /* remove */ |