summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <>2010-10-09 03:58:43 +0000
committererdgeist <>2010-10-09 03:58:43 +0000
commitdb52d59bd2769cc4cc81a20bfd58c07ed34d619c (patch)
treec4ec38a65bb95d112879e0bae37d675d608f47a1
parenta468c875f7a35c595b2eb575ad99354e3e9c3662 (diff)
Handle utf8 in readline correctly
-rwxr-xr-xvchat-ui.c142
1 files changed, 87 insertions, 55 deletions
diff --git a/vchat-ui.c b/vchat-ui.c
index d118fc5..136fdee 100755
--- a/vchat-ui.c
+++ b/vchat-ui.c
@@ -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 */
36char *vchat_ui_version = "$Id$"; 37char *vchat_ui_version = "$Id$";
@@ -54,8 +55,6 @@ static WINDOW *output = NULL;
54/* our screen dimensions */ 55/* our screen dimensions */
55static int screensx = 0; 56static int screensx = 0;
56static int screensy = 0; 57static int screensy = 0;
57/* length of last input on line (for clearing) */
58static int lastlen = 0;
59/* current horizontal scrolling offset for input line */ 58/* current horizontal scrolling offset for input line */
60static int scroff = 0; 59static 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
142const 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
155size_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 */
144static void 172static void
145linecomplete (char *line) 173linecomplete (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
187vciredraw (void) 211vciredraw (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
1482removefromfilterlist( int(*test)(filt *flt, void *data, char colour), void *data, char colour) { 1514removefromfilterlist( 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 */