1 /* SLang_read_line interface --- uses SLang tty stuff */
2 /*
3 Copyright (C) 2004-2017,2018 John E. Davis
4
5 This file is part of the S-Lang Library.
6
7 The S-Lang Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 The S-Lang Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 USA.
21 */
22
23 #include "slinclud.h"
24 #include <errno.h>
25
26 #include "slang.h"
27 #include "_slang.h"
28
29 typedef struct RL_History_Type
30 {
31 struct RL_History_Type *prev, *next;
32 char *buf;
33 unsigned int len;
34 unsigned int point;
35 } RL_History_Type;
36
37 /* Maximum size of display */
38 #define SLRL_DISPLAY_BUFFER_SIZE 4096 /* reasonable size for UTF-8 */
39
40 struct _pSLrline_Type
41 {
42 RL_History_Type *root, *tail, *last;
43 RL_History_Type *saved_line; /* used when browsing the history */
44 char *name; /* the name of this object */
45 unsigned char *buf; /* edit buffer */
46 unsigned int buf_len; /* sizeof buffer */
47 unsigned int point; /* current editing point */
48 unsigned int tab; /* tab width */
49 unsigned int len; /* current line size */
50
51 /* display variables */
52 unsigned int edit_width; /* #cols of display field */
53 int curs_pos; /* current column */
54 int start_column; /* column offset of display */
55 unsigned int hscroll; /* amount to use for horiz scroll */
56 SLFUTURE_CONST char *prompt;
57
58 SLang_Key_Type last_key; /* last key executed by rl */
59
60 /* These two contain an image of what is on the display. They are
61 * used by the default display handling functions. (update_hook is NULL)
62 */
63 unsigned char upd_buf1[SLRL_DISPLAY_BUFFER_SIZE];
64 unsigned char upd_buf2[SLRL_DISPLAY_BUFFER_SIZE];
65 unsigned char *old_upd, *new_upd; /* pointers to previous two buffers */
66 int new_upd_len, old_upd_len; /* length of output buffers */
67 unsigned int last_nonblank_column; /* column of last non-blank char */
68
69 SLKeyMap_List_Type *keymap;
70 int eof_char;
71
72 unsigned int flags; /* */
73
74 int state;
75 #define RLI_LINE_INVALID 0
76 #define RLI_LINE_SET 1
77 #define RLI_LINE_IN_PROGRESS 2
78 #define RLI_LINE_READ 3
79
80 int is_modified;
81
82 int quit;
83 #define RLINE_QUIT_DONE 1
84 #define RLINE_QUIT_ABORT 2
85
86 /* tty variables */
87 unsigned int (*getkey)(void); /* getkey function -- required */
88 void (*tt_goto_column)(int);
89 void (*tt_insert)(char);
90 void (*update_hook)(SLrline_Type *rli,
91 SLFUTURE_CONST char *prompt, SLFUTURE_CONST char *buf, unsigned int len, unsigned int point,
92 VOID_STAR client_data);
93 VOID_STAR update_client_data;
94 void (*update_free_update_data_hook)(SLrline_Type *rli, VOID_STAR client_data);
95 void (*update_clear_hook)(SLrline_Type *rli, VOID_STAR client_data);
96 void (*update_preread_hook)(SLrline_Type *rli, VOID_STAR client_data);
97 void (*update_postread_hook)(SLrline_Type *rli, VOID_STAR client_data);
98 void (*update_display_width_changed_hook)(SLrline_Type *rli, int width, VOID_STAR client_data);
99
100 /* This function is only called when blinking matches */
101 int (*input_pending)(int);
102
103 SLang_Name_Type *completion_callback;
104 SLang_Name_Type *list_completions_callback;
105 };
106
107 static SLang_Name_Type *Default_Completion_Callback;
108 static SLang_Name_Type *Default_List_Completions_Callback;
109
110 static unsigned char Char_Widths[256];
111 static void position_cursor (SLrline_Type *, int);
112
free_history_item(RL_History_Type * h)113 static void free_history_item (RL_History_Type *h)
114 {
115 if (h == NULL)
116 return;
117
118 if (h->buf != NULL)
119 SLang_create_slstring (h->buf);
120 SLfree ((char *)h);
121 }
122
free_history(RL_History_Type * h)123 static void free_history (RL_History_Type *h)
124 {
125 while (h != NULL)
126 {
127 RL_History_Type *next = h->next;
128 free_history_item (h);
129 h = next;
130 }
131 }
132
allocate_history(SLFUTURE_CONST char * str,int point)133 static RL_History_Type *allocate_history (SLFUTURE_CONST char *str, int point)
134 {
135 RL_History_Type *h;
136
137 if (NULL == (h = (RL_History_Type *) SLcalloc (1, sizeof (RL_History_Type)))
138 || (NULL == (h->buf = SLang_create_slstring (str))))
139 {
140 SLfree ((char *)h); /* NULL ok */
141 return NULL;
142 }
143
144 h->len = strlen (str);
145 if ((point < 0) || ((unsigned int)point > h->len))
146 point = h->len;
147 h->point = point;
148 return h;
149 }
150
rl_beep(void)151 static void rl_beep (void)
152 {
153 putc(7, stdout);
154 fflush (stdout);
155 }
156
check_space(SLrline_Type * This_RLI,unsigned int dn)157 static int check_space (SLrline_Type *This_RLI, unsigned int dn)
158 {
159 unsigned char *new_buf;
160 unsigned int new_len;
161
162 new_len = 1 + This_RLI->len + dn;
163
164 if (new_len <= This_RLI->buf_len)
165 return 0;
166
167 if (NULL == (new_buf = (unsigned char *) SLrealloc ((char *)This_RLI->buf, new_len)))
168 return -1;
169
170 This_RLI->buf_len = new_len;
171 This_RLI->buf = new_buf;
172 return 0;
173 }
174
175 /* editing functions */
SLrline_bol(SLrline_Type * This_RLI)176 int SLrline_bol (SLrline_Type *This_RLI)
177 {
178 This_RLI->point = 0;
179 return 0;
180 }
181
SLrline_eol(SLrline_Type * This_RLI)182 int SLrline_eol (SLrline_Type *This_RLI)
183 {
184 This_RLI->point = This_RLI->len;
185 return 0;
186 }
187
rl_right(SLrline_Type * This_RLI)188 static int rl_right (SLrline_Type *This_RLI)
189 {
190 SLuchar_Type *s, *smax;
191 int ignore_combining = 1;
192
193 s = This_RLI->buf + This_RLI->point;
194 smax = This_RLI->buf + This_RLI->len;
195
196 if (s < smax)
197 {
198 if (This_RLI->flags & SL_RLINE_UTF8_MODE)
199 s = SLutf8_skip_chars (s, smax, 1, NULL, ignore_combining);
200 else
201 s++;
202
203 This_RLI->point = s - This_RLI->buf;
204 }
205
206 return 0;
207 }
208
rl_left(SLrline_Type * This_RLI)209 static int rl_left (SLrline_Type *This_RLI)
210 {
211 SLuchar_Type *s, *smin;
212 int ignore_combining = 1;
213
214 smin = This_RLI->buf;
215 s = smin + This_RLI->point;
216
217 if (s > smin)
218 {
219 if (This_RLI->flags & SL_RLINE_UTF8_MODE)
220 s = SLutf8_bskip_chars (smin, s, 1, NULL, ignore_combining);
221 else
222 s--;
223
224 This_RLI->point = s - This_RLI->buf;
225 }
226
227 return 0;
228 }
229
SLrline_move(SLrline_Type * rli,int n)230 int SLrline_move (SLrline_Type *rli, int n)
231 {
232 if (rli == NULL)
233 return -1;
234
235 if (n < 0)
236 {
237 n = -n;
238 while (n && rli->point)
239 {
240 (void) rl_left (rli);
241 n--;
242 }
243 return 0;
244 }
245
246 while (n && (rli->point != rli->len))
247 {
248 (void) rl_right (rli);
249 n--;
250 }
251 return 0;
252 }
253
SLrline_ins(SLrline_Type * This_RLI,SLFUTURE_CONST char * s,unsigned int n)254 int SLrline_ins (SLrline_Type *This_RLI, SLFUTURE_CONST char *s, unsigned int n)
255 {
256 unsigned char *pmin;
257
258 if (-1 == check_space (This_RLI, n + 128))
259 return -1;
260
261 pmin = This_RLI->buf + This_RLI->point;
262 if (This_RLI->len)
263 {
264 unsigned char *p = This_RLI->buf + This_RLI->len;
265 while (p >= pmin)
266 {
267 *(p + n) = *p;
268 p--;
269 }
270 }
271 memcpy ((char *) pmin, s, n);
272
273 This_RLI->len += n;
274 This_RLI->point += n;
275 This_RLI->is_modified = 1;
276
277 return n;
278 }
279
rl_self_insert(SLrline_Type * This_RLI)280 static int rl_self_insert (SLrline_Type *This_RLI)
281 {
282 char buf[8];
283
284 buf[0] = SLang_Last_Key_Char;
285 buf[1] = 0;
286
287 return SLrline_ins (This_RLI, buf, 1);
288 }
289
SLrline_del(SLrline_Type * This_RLI,unsigned int n)290 int SLrline_del (SLrline_Type *This_RLI, unsigned int n)
291 {
292 SLuchar_Type *pmax, *p, *pn;
293 int ignore_combining = 1;
294
295 p = This_RLI->buf + This_RLI->point;
296 pmax = This_RLI->buf + This_RLI->len;
297
298 if (This_RLI->flags & SL_RLINE_UTF8_MODE)
299 {
300 pn = SLutf8_skip_chars (p, pmax, n, NULL, ignore_combining);
301 n = pn - p;
302 }
303 else
304 {
305 if (p + n > pmax) n = (pmax - p);
306 pn = p + n;
307 }
308 This_RLI->len -= n;
309
310 while (pn < pmax)
311 {
312 *p++ = *pn++;
313 }
314 This_RLI->is_modified = 1;
315 return 0;
316 }
317
rl_del(SLrline_Type * This_RLI)318 static int rl_del (SLrline_Type *This_RLI)
319 {
320 return SLrline_del (This_RLI, 1);
321 }
322
rl_quote_insert(SLrline_Type * This_RLI)323 static int rl_quote_insert (SLrline_Type *This_RLI)
324 {
325 /* FIXME. We should not be messing with SLang_Error here */
326 int err = _pSLang_Error;
327 _pSLang_Error = 0;
328 SLang_Last_Key_Char = (*This_RLI->getkey)();
329 if (_pSLang_Error == SL_USER_BREAK)
330 {
331 SLKeyBoard_Quit = 0;
332 SLang_Last_Key_Char = SLang_Abort_Char;
333 }
334 SLang_set_error (err);
335 rl_self_insert (This_RLI);
336 return 0;
337 }
338
rl_trim(SLrline_Type * This_RLI)339 static int rl_trim (SLrline_Type *This_RLI)
340 {
341 unsigned char *p, *pmax, *p1;
342
343 p = This_RLI->buf + This_RLI->point;
344 pmax = This_RLI->buf + This_RLI->len;
345
346 if (p == pmax)
347 {
348 if (p == This_RLI->buf) return 0;
349 p--;
350 }
351
352 if ((*p != ' ') && (*p != '\t')) return 0;
353 p1 = p;
354 while ((p1 < pmax) && ((*p1 == ' ') || (*p1 == '\t'))) p1++;
355 pmax = p1;
356 p1 = This_RLI->buf;
357
358 while ((p >= p1) && ((*p == ' ') || (*p == '\t'))) p--;
359 if (p == pmax) return 0;
360 p++;
361
362 This_RLI->point = (int) (p - p1);
363 return SLrline_del (This_RLI, (int) (pmax - p));
364 }
365
rl_bdel(SLrline_Type * This_RLI)366 static int rl_bdel (SLrline_Type *This_RLI)
367 {
368 if (This_RLI->point)
369 {
370 rl_left (This_RLI);
371 rl_del(This_RLI);
372 }
373 return 0;
374 }
375
rl_delbol(SLrline_Type * This_RLI)376 static int rl_delbol (SLrline_Type *This_RLI)
377 {
378 while (This_RLI->point)
379 {
380 rl_left (This_RLI);
381 rl_del(This_RLI);
382 }
383 return 0;
384 }
385
rl_deleol(SLrline_Type * This_RLI)386 static int rl_deleol (SLrline_Type *This_RLI)
387 {
388 if (This_RLI->point == This_RLI->len) return 0;
389 *(This_RLI->buf + This_RLI->point) = 0;
390 This_RLI->len = This_RLI->point;
391 This_RLI->is_modified = 1;
392 return 0;
393 }
394
395 #if 0
396 static int rl_delete_line (SLrline_Type *This_RLI)
397 {
398 (void) SLrline_bol (This_RLI);
399 rl_deleol (This_RLI);
400 return 0;
401 }
402 #endif
403
rl_enter(SLrline_Type * This_RLI)404 static int rl_enter (SLrline_Type *This_RLI)
405 {
406 if (-1 == check_space (This_RLI, 1))
407 return -1;
408
409 *(This_RLI->buf + This_RLI->len) = 0;
410 This_RLI->quit = RLINE_QUIT_DONE;
411 return 0;
412 }
413
rl_complete(SLrline_Type * rli)414 static int rl_complete (SLrline_Type *rli)
415 {
416 char *line;
417 unsigned int i, n, nbytes;
418 char **strings, *str0, ch0;
419 int start_point, delta;
420 SLang_Array_Type *at;
421 SLang_Name_Type *completion_callback;
422 SLang_Name_Type *list_completions_callback;
423
424 if (NULL == (completion_callback = rli->completion_callback))
425 {
426 completion_callback = Default_Completion_Callback;
427 if (completion_callback == NULL)
428 return SLrline_ins (rli, "\t", 1);
429 }
430 if (NULL == (list_completions_callback = rli->list_completions_callback))
431 list_completions_callback = Default_List_Completions_Callback;
432
433 if (NULL == (line = SLrline_get_line (rli)))
434 return -1;
435
436 if ((-1 == SLang_start_arg_list ())
437 || (-1 == SLang_push_string (line))
438 || (-1 == SLang_push_int (rli->point))
439 || (-1 == SLang_end_arg_list ())
440 || (-1 == SLexecute_function (completion_callback)))
441 {
442 SLfree (line);
443 return -1;
444 }
445
446 SLfree (line);
447
448 if (-1 == SLang_pop_int (&start_point))
449 return -1;
450
451 if (start_point < 0)
452 start_point = 0;
453
454 if (-1 == SLang_pop_array_of_type (&at, SLANG_STRING_TYPE))
455 return -1;
456
457 strings = (char **) at->data;
458 n = at->num_elements;
459
460 if (n == 0)
461 {
462 SLang_free_array (at);
463 return 0;
464 }
465
466 if ((n != 1) && (list_completions_callback != NULL))
467 {
468 if ((-1 == SLang_start_arg_list ())
469 || (-1 == SLang_push_array (at, 0))
470 || (-1 == SLang_end_arg_list ())
471 || (-1 == SLexecute_function (list_completions_callback)))
472 {
473 SLang_free_array (at);
474 return -1;
475 }
476 (void) SLrline_redraw (rli);
477 }
478
479 str0 = strings[0];
480 nbytes = 0;
481 while (0 != (ch0 = str0[nbytes]))
482 {
483 for (i = 1; i < n; i++)
484 {
485 char ch1 = strings[i][nbytes];
486 if (ch0 != ch1)
487 break;
488 }
489 if (i != n)
490 break;
491 nbytes++;
492 }
493
494 delta = start_point - rli->point;
495 if (delta < 0)
496 {
497 (void) SLrline_move (rli, delta);
498 delta = -delta;
499 }
500 (void) SLrline_del (rli, (unsigned int) delta);
501 (void) SLrline_ins (rli, str0, nbytes);
502
503 /* How should the completion be ended?
504 * "foo/ --> "foo/
505 * "foo/bar --> "foo/bar"
506 * "foo --> "foo"
507 * foo --> fooSPACE
508 * foo/bar --> fooSPACE
509 */
510 if ((n == 1)
511 && nbytes && (str0[nbytes-1] != '/') && (str0[nbytes-1] != '\\'))
512 {
513 char qch = ' ';
514
515 if (start_point > 0)
516 {
517 ch0 = rli->buf[start_point-1];
518 if ((ch0 == '"') || (ch0 == '\''))
519 qch = ch0;
520 }
521 if (qch != 0)
522 (void) SLrline_ins (rli, &qch, 1);
523 }
524
525 SLang_free_array (at);
526 return 0;
527 }
528
529 static SLKeyMap_List_Type *RL_Keymap;
530
compute_char_width(SLuchar_Type * b,SLuchar_Type * bmax,int utf8_mode,unsigned int * wp,SLwchar_Type * wchp,int * illegalp)531 static SLuchar_Type *compute_char_width (SLuchar_Type *b, SLuchar_Type *bmax, int utf8_mode, unsigned int *wp, SLwchar_Type *wchp, int *illegalp)
532 {
533 SLwchar_Type wch;
534
535 if (illegalp != NULL) *illegalp = 0;
536
537 if (b >= bmax)
538 {
539 *wp = 0;
540 if (wchp != NULL) *wchp = 0;
541 return b;
542 }
543
544 if (utf8_mode == 0)
545 {
546 *wp = Char_Widths[*b];
547 if (wchp != NULL) *wchp = *b;
548 return b + 1;
549 }
550
551 if (NULL == SLutf8_decode (b, bmax, &wch, NULL))
552 {
553 /* Illegal byte sequence */
554 *wp = 4; /* <XX> */
555 if (wchp != NULL) *wchp = *b;
556 if (illegalp != NULL) *illegalp = 1;
557 return b + 1;
558 }
559
560 /* skip combining */
561 if ((wch >= ' ') && (wch < 127))
562 *wp = 1;
563 else if (wch > 127)
564 *wp = SLwchar_wcwidth (wch);
565 else
566 *wp = 2; /* ^X */
567
568 if (wchp != NULL) *wchp = wch;
569 /* skip combining chars too */
570 return SLutf8_skip_chars (b, bmax, 1, NULL, 1);
571 }
572
573 /* This update is designed for dumb terminals. It assumes only that the
574 * terminal can backspace via ^H, and move cursor to start of line via ^M.
575 * There is a hook so the user can provide a more sophisticated update if
576 * necessary.
577 */
position_cursor(SLrline_Type * This_RLI,int col)578 static void position_cursor (SLrline_Type *This_RLI, int col)
579 {
580 unsigned char *p, *pmax;
581 unsigned int len, dlen;
582 int curs_pos;
583 int dc;
584 int utf8_mode = This_RLI->flags & SL_RLINE_UTF8_MODE;
585
586 if (col == This_RLI->curs_pos)
587 {
588 fflush (stdout);
589 return;
590 }
591
592 if (This_RLI->tt_goto_column != NULL)
593 {
594 (*This_RLI->tt_goto_column)(col);
595 This_RLI->curs_pos = col;
596 fflush (stdout);
597 return;
598 }
599
600 curs_pos = This_RLI->curs_pos;
601 dc = This_RLI->curs_pos - col;
602 if (dc < 0)
603 {
604 p = This_RLI->new_upd;
605 pmax = p + SLRL_DISPLAY_BUFFER_SIZE;
606
607 len = 0;
608 while (((int)len < curs_pos) && (p < pmax))
609 {
610 p = compute_char_width (p, pmax, utf8_mode, &dlen, NULL, NULL);
611 len += dlen;
612 }
613 while (((int)len < col) && (p < pmax))
614 {
615 SLuchar_Type *p1;
616 p1 = compute_char_width (p, pmax, utf8_mode, &dlen, NULL, NULL);
617 while (p < p1)
618 putc((char) *p++, stdout);
619
620 len += dlen;
621 }
622 }
623 else
624 {
625 if (dc < col)
626 {
627 while (dc--) putc(8, stdout);
628 }
629 else
630 {
631 putc('\r', stdout);
632 p = This_RLI->new_upd;
633 pmax = p + SLRL_DISPLAY_BUFFER_SIZE;
634 len = 0;
635 while (((int)len < col) && (p < pmax))
636 {
637 SLuchar_Type *p1;
638 p1 = compute_char_width (p, pmax, utf8_mode, &dlen, NULL, NULL);
639 while (p < p1)
640 putc((char) *p++, stdout);
641 len += dlen;
642 }
643 }
644 }
645 This_RLI->curs_pos = col;
646 fflush (stdout);
647 }
648
erase_eol(SLrline_Type * rli)649 static void erase_eol (SLrline_Type *rli)
650 {
651 int col = rli->curs_pos;
652 int col_max = rli->last_nonblank_column;
653
654 while (col < col_max)
655 {
656 putc(' ', stdout);
657 col++;
658 }
659 rli->curs_pos = col_max;
660 }
661
spit_out(SLrline_Type * rli,SLuchar_Type * p,SLuchar_Type * pmax,int col)662 static void spit_out(SLrline_Type *rli, SLuchar_Type *p, SLuchar_Type *pmax, int col)
663 {
664 int utf8_mode = rli->flags & SL_RLINE_UTF8_MODE;
665 position_cursor (rli, col);
666 while (p < pmax)
667 {
668 SLuchar_Type *p1;
669 unsigned int dcol;
670 p1 = compute_char_width (p, pmax, utf8_mode, &dcol, NULL, NULL);
671 while (p < p1)
672 putc((char) *p++, stdout);
673 col += dcol;
674 }
675 rli->curs_pos = col;
676 }
677
really_update(SLrline_Type * rli,int new_curs_position)678 static void really_update (SLrline_Type *rli, int new_curs_position)
679 {
680 SLuchar_Type *b, *bmax, *p, *pmax;
681 unsigned int col, max_col;
682 int utf8_mode = rli->flags & SL_RLINE_UTF8_MODE;
683
684 col = 0;
685 max_col = rli->edit_width-1;
686 b = rli->old_upd;
687 p = rli->new_upd;
688 bmax = b + rli->old_upd_len;
689 pmax = p + rli->new_upd_len;
690
691 while (col < max_col)
692 {
693 SLwchar_Type pch, bch;
694 SLuchar_Type *p1, *b1;
695 unsigned int plen, blen;
696
697 b1 = compute_char_width (b, bmax, utf8_mode, &blen, &bch, NULL);
698 p1 = compute_char_width (p, pmax, utf8_mode, &plen, &pch, NULL);
699
700 if ((p1 != p) && ((b1-b) == (p1-p))
701 && (bch == pch))
702 {
703 col += plen;
704 b = b1;
705 p = p1;
706 continue;
707 }
708
709 spit_out (rli, p, pmax, col);
710
711 col = rli->curs_pos;
712 if (col < rli->last_nonblank_column)
713 erase_eol (rli);
714 rli->last_nonblank_column = col;
715
716 break;
717 }
718
719 position_cursor (rli, new_curs_position);
720
721 /* update finished, so swap */
722
723 rli->old_upd_len = rli->new_upd_len;
724 p = rli->old_upd;
725 rli->old_upd = rli->new_upd;
726 rli->new_upd = p;
727 }
728
729 static SLuchar_Type *
compute_tabbed_char_width(SLuchar_Type * b,SLuchar_Type * bmax,int utf8_mode,int col,int tab_width,unsigned int * dlenp)730 compute_tabbed_char_width (SLuchar_Type *b, SLuchar_Type *bmax,
731 int utf8_mode, int col, int tab_width,
732 unsigned int *dlenp)
733 {
734 if (b >= bmax)
735 {
736 *dlenp = 0;
737 return bmax;
738 }
739
740 if ((*b == '\t') && tab_width)
741 {
742 *dlenp = tab_width * (col / tab_width + 1) - col;
743 return b+1;
744 }
745
746 return compute_char_width (b, bmax, utf8_mode, dlenp, NULL, NULL);
747 }
748
compute_string_width(SLrline_Type * rli,SLuchar_Type * b,SLuchar_Type * bmax,unsigned int tab_width)749 static unsigned int compute_string_width (SLrline_Type *rli, SLuchar_Type *b, SLuchar_Type *bmax, unsigned int tab_width)
750 {
751 int utf8_mode = rli->flags & SL_RLINE_UTF8_MODE;
752 unsigned int len;
753
754 if (b == NULL)
755 return 0;
756
757 len = 0;
758 while (b < bmax)
759 {
760 unsigned int dlen;
761
762 if ((*b == '\t') && tab_width)
763 {
764 dlen = tab_width * (len / tab_width + 1) - len;
765 b++;
766 }
767 else b = compute_char_width (b, bmax, utf8_mode, &dlen, NULL, NULL);
768
769 len += dlen;
770 }
771 return len;
772 }
773
RLupdate(SLrline_Type * rli)774 static void RLupdate (SLrline_Type *rli)
775 {
776 unsigned int len, dlen, prompt_len = 0, tw = 0, count;
777 unsigned int start_len;
778 int want_cursor_pos;
779 unsigned char *b, *bmax, *b_point, *p, *pmax;
780 int no_echo;
781 int utf8_mode;
782 unsigned int edit_width;
783
784 no_echo = rli->flags & SL_RLINE_NO_ECHO;
785 utf8_mode = rli->flags & SL_RLINE_UTF8_MODE;
786 edit_width = rli->edit_width-1;
787
788 *(rli->buf + rli->len) = 0;
789
790 if (rli->update_hook != NULL)
791 {
792 if (no_echo)
793 (*rli->update_hook) (rli, rli->prompt, "", 0, 0, rli->update_client_data);
794 else
795 (*rli->update_hook) (rli, rli->prompt, (char *)rli->buf, rli->len, rli->point, rli->update_client_data);
796 return;
797 }
798
799 /* expand characters for output buffer --- handle prompt first.
800 * Do two passes --- first to find out where to begin upon horiz
801 * scroll and the second to actually fill the buffer. */
802 len = 0;
803 b = (unsigned char *) rli->prompt;
804 if (b != NULL)
805 {
806 bmax = b + strlen ((char *)b);
807 len += compute_string_width (rli, b, bmax, 0);
808 }
809 prompt_len = len;
810
811 b = (unsigned char *) rli->buf;
812 b_point = (unsigned char *) (rli->buf + rli->point);
813 if (no_echo == 0)
814 len += compute_string_width (rli, b, b_point, rli->tab);
815
816 if (len + rli->hscroll < edit_width) start_len = 0;
817 else if ((rli->start_column > (int)len)
818 || (rli->start_column + (int)edit_width <= (int)len))
819 start_len = (len + rli->hscroll) - edit_width;
820 else start_len = rli->start_column;
821 rli->start_column = start_len;
822
823 /* want_cursor_pos = len - start_len; */
824
825 /* second pass */
826 b = (unsigned char *) rli->prompt;
827 if (b == NULL) b = (unsigned char *) "";
828 bmax = b + strlen ((char *)b);
829 len = 0;
830 count = 2;
831 while ((len < start_len) && (b < bmax))
832 {
833 b = compute_tabbed_char_width (b, bmax, utf8_mode, 0, 0, &dlen);
834 len += dlen;
835 }
836
837 tw = 0;
838 if (b == bmax)
839 {
840 b = (unsigned char *) rli->buf;
841 bmax = b + strlen ((char *)b);
842 tw = rli->tab;
843 while ((len < start_len) && (b < bmax))
844 {
845 b = compute_tabbed_char_width (b, bmax, utf8_mode, 0, tw, &dlen);
846 len += dlen;
847 }
848 count--;
849 }
850
851 len = 0;
852 p = rli->new_upd;
853 pmax = p + SLRL_DISPLAY_BUFFER_SIZE;
854 want_cursor_pos = -1;
855
856 while (count--)
857 {
858 if ((count == 0) && (no_echo))
859 break;
860
861 while ((len < edit_width) && (b < bmax))
862 {
863 SLwchar_Type wch;
864 int is_illegal;
865 SLuchar_Type *b1;
866
867 if (b == b_point)
868 want_cursor_pos = len;
869
870 if ((*b == '\t') && tw)
871 {
872 dlen = tw * ((len + start_len - prompt_len) / tw + 1) - (len + start_len - prompt_len);
873 len += dlen; /* ok since dlen comes out 0 */
874 if (len > edit_width) dlen = len - edit_width;
875 while (dlen-- && (p < pmax)) *p++ = ' ';
876 b++;
877 continue;
878 }
879
880 b1 = compute_char_width (b, bmax, utf8_mode, &dlen, &wch, &is_illegal);
881 if (len + dlen > edit_width)
882 {
883 /* The character is double width and a portion of it exceeds
884 * the edit width
885 */
886 break;
887 }
888
889 if (is_illegal == 0)
890 {
891 if (wch < 32)
892 {
893 if (p < pmax) *p++ = '^';
894 if (p < pmax) *p++ = *b + '@';
895 }
896 else if (wch == 127)
897 {
898 if (p < pmax) *p++ = '^';
899 if (p < pmax) *p++ = '?';
900 }
901 else while (b < b1)
902 {
903 if (p < pmax) *p++ = *b++;
904 }
905 }
906 else
907 {
908 if (p + 4 < pmax)
909 {
910 sprintf ((char *)p, "<%02X>", *b);
911 p += 4;
912 }
913 }
914 b = b1;
915 len += dlen;
916 }
917 /* if (start_len > prompt_len) break; */
918 tw = rli->tab;
919 b = (unsigned char *) rli->buf;
920 bmax = b + strlen ((char *)b);
921 }
922
923 if (want_cursor_pos == -1)
924 want_cursor_pos = len;
925
926 rli->new_upd_len = (int) (p - rli->new_upd);
927 while ((p < pmax) && (len < edit_width))
928 {
929 *p++ = ' ';
930 len++;
931 }
932 really_update (rli, want_cursor_pos);
933 }
934
SLrline_redraw(SLrline_Type * rli)935 void SLrline_redraw (SLrline_Type *rli)
936 {
937 if (rli == NULL)
938 return;
939
940 if (rli->update_hook != NULL)
941 {
942 (*rli->update_hook) (rli, "", "", 0, 0, rli->update_client_data);
943 }
944 else
945 {
946 unsigned char *p;
947 unsigned char *pmax;
948
949 p = rli->new_upd;
950 pmax = p + rli->edit_width;
951 while (p < pmax) *p++ = ' ';
952 rli->new_upd_len = rli->edit_width;
953 rli->last_nonblank_column = rli->edit_width-1;
954 really_update (rli, 0);
955 rli->last_nonblank_column = 0;
956 }
957 RLupdate (rli);
958 }
959
rl_eof_insert(SLrline_Type * This_RLI)960 static int rl_eof_insert (SLrline_Type *This_RLI)
961 {
962 return rl_enter (This_RLI);
963 }
964
965 /* This is very naive. It knows very little about nesting and nothing
966 * about quoting.
967 */
blink_match(SLrline_Type * rli)968 static void blink_match (SLrline_Type *rli)
969 {
970 unsigned char bra, ket;
971 unsigned int delta_column;
972 unsigned char *p, *pmin;
973 int dq_level, sq_level;
974 int level;
975
976 pmin = rli->buf;
977 p = pmin + rli->point;
978 if (pmin == p)
979 return;
980
981 ket = SLang_Last_Key_Char;
982 switch (ket)
983 {
984 case ')':
985 bra = '(';
986 break;
987 case ']':
988 bra = '[';
989 break;
990 case '}':
991 bra = '{';
992 break;
993 default:
994 return;
995 }
996
997 level = 0;
998 sq_level = dq_level = 0;
999
1000 delta_column = 0;
1001 while (p > pmin)
1002 {
1003 char ch;
1004
1005 p--;
1006 delta_column++;
1007 ch = *p;
1008
1009 if (ch == ket)
1010 {
1011 if ((dq_level == 0) && (sq_level == 0))
1012 level++;
1013 }
1014 else if (ch == bra)
1015 {
1016 if ((dq_level != 0) || (sq_level != 0))
1017 continue;
1018
1019 level--;
1020 if (level == 0)
1021 {
1022 rli->point -= delta_column;
1023 RLupdate (rli);
1024 if (rli->input_pending != NULL)
1025 (*rli->input_pending)(10);
1026 rli->point += delta_column;
1027 RLupdate (rli);
1028 break;
1029 }
1030 if (level < 0)
1031 break;
1032 }
1033 else if (ch == '"') dq_level = !dq_level;
1034 else if (ch == '\'') sq_level = !sq_level;
1035 }
1036 }
1037
free_last_key(SLrline_Type * rli)1038 static void free_last_key (SLrline_Type *rli)
1039 {
1040 SLang_Key_Type *last_key;
1041
1042 if (rli == NULL)
1043 return;
1044
1045 last_key = &rli->last_key;
1046 switch (last_key->type)
1047 {
1048 case SLKEY_F_INTERPRET:
1049 if (last_key->f.s != NULL)
1050 {
1051 SLang_free_slstring (last_key->f.s);
1052 last_key->f.s = NULL;
1053 }
1054 break;
1055
1056 case SLKEY_F_SLANG:
1057 if (NULL != last_key->f.slang_fun)
1058 {
1059 SLang_free_function (last_key->f.slang_fun);
1060 last_key->f.slang_fun = NULL;
1061 }
1062 break;
1063 }
1064
1065 last_key->type = 0;
1066 }
1067
save_last_key(SLrline_Type * rli,SLang_Key_Type * key)1068 static int save_last_key (SLrline_Type *rli, SLang_Key_Type *key)
1069 {
1070 SLang_Key_Type *last_key;
1071
1072 if ((rli == NULL) || (key == NULL))
1073 return 0;
1074
1075 free_last_key (rli);
1076
1077 last_key = &rli->last_key;
1078 last_key->type = 0;
1079
1080 switch (key->type)
1081 {
1082 case SLKEY_F_INTERPRET:
1083 if (NULL == (last_key->f.s = SLang_create_slstring (key->f.s)))
1084 return -1;
1085 break;
1086
1087 case SLKEY_F_KEYSYM:
1088 last_key->f.keysym = key->f.keysym;
1089 break;
1090
1091 case SLKEY_F_SLANG:
1092 if (NULL == (last_key->f.slang_fun = SLang_copy_function (key->f.slang_fun)))
1093 return -1;
1094 break;
1095
1096 default:
1097 case SLKEY_F_INTRINSIC:
1098 last_key->f.f = key->f.f;
1099 }
1100
1101 last_key->type = key->type;
1102 memcpy (last_key->str, key->str, sizeof(key->str));
1103 return 0;
1104 }
1105
1106 static SLrline_Type *Active_Rline_Info = NULL;
1107
SLrline_read_line(SLrline_Type * rli,SLFUTURE_CONST char * prompt,unsigned int * lenp)1108 char *SLrline_read_line (SLrline_Type *rli, SLFUTURE_CONST char *prompt, unsigned int *lenp)
1109 {
1110 unsigned char *p, *pmax;
1111 int last_input_char;
1112 unsigned int dummy_len_buf;
1113
1114 if (lenp == NULL)
1115 lenp = &dummy_len_buf;
1116
1117 *lenp = 0;
1118
1119 if (rli == NULL)
1120 return NULL;
1121
1122 if (rli->state == RLI_LINE_IN_PROGRESS)
1123 {
1124 *lenp = 0;
1125 return NULL;
1126 }
1127
1128 if (prompt == NULL)
1129 prompt = "";
1130
1131 if ((rli->prompt == NULL)
1132 || strcmp (rli->prompt, prompt))
1133 {
1134 if (NULL == (prompt = SLmake_string (prompt)))
1135 return NULL;
1136
1137 SLfree ((char *)rli->prompt);
1138 rli->prompt = prompt;
1139 }
1140
1141 rli->quit = 0;
1142 p = rli->old_upd; pmax = p + rli->edit_width;
1143 while (p < pmax) *p++ = ' ';
1144
1145 if (rli->state != RLI_LINE_SET)
1146 {
1147 rli->len = 0;
1148 rli->point = 0;
1149 *rli->buf = 0;
1150 }
1151 rli->state = RLI_LINE_IN_PROGRESS;
1152
1153 if (rli->update_preread_hook != NULL)
1154 (*rli->update_preread_hook)(rli, rli->update_client_data);
1155
1156 rli->curs_pos = rli->start_column = 0;
1157 rli->new_upd_len = rli->old_upd_len = 0;
1158
1159 free_last_key (rli);
1160 if (rli->update_hook == NULL)
1161 putc ('\r', stdout);
1162
1163 rli->is_modified = 0;
1164 rli->last = NULL;
1165
1166 RLupdate (rli);
1167
1168 last_input_char = 0;
1169 while (1)
1170 {
1171 SLang_Key_Type *key;
1172 SLrline_Type *save_rli = Active_Rline_Info;
1173
1174 errno = 0;
1175 key = SLang_do_key (RL_Keymap, (int (*)(void)) rli->getkey);
1176
1177 if ((key == NULL) || (key->f.f == NULL))
1178 {
1179 if ((key == NULL)
1180 && (SLANG_GETKEY_ERROR == (unsigned int)SLang_Last_Key_Char)
1181 #ifdef EINTR
1182 && (errno != EINTR)
1183 #endif
1184 )
1185 return NULL;
1186
1187 rl_beep ();
1188 continue;
1189 }
1190
1191 if ((*key->str != 2) || (key->str[1] != rli->eof_char))
1192 last_input_char = 0;
1193 else
1194 {
1195 if ((rli->len == 0) && (last_input_char != rli->eof_char))
1196 {
1197 rli->buf[rli->len] = 0;
1198 rli->state = RLI_LINE_READ;
1199 *lenp = 0;
1200
1201 if (rli->update_postread_hook != NULL)
1202 (*rli->update_postread_hook)(rli, rli->update_client_data);
1203
1204 return NULL; /* EOF */
1205 }
1206
1207 last_input_char = rli->eof_char;
1208 }
1209
1210 Active_Rline_Info = rli;
1211 if (key->type == SLKEY_F_INTRINSIC)
1212 {
1213 int (*func)(SLrline_Type *);
1214 func = (int (*)(SLrline_Type *)) key->f.f;
1215
1216 (void) (*func)(rli);
1217
1218 RLupdate (rli);
1219
1220 if ((rli->flags & SL_RLINE_BLINK_MATCH)
1221 && (rli->input_pending != NULL))
1222 blink_match (rli);
1223 }
1224 else if (key->type == SLKEY_F_SLANG)
1225 {
1226 (void) SLexecute_function (key->f.slang_fun);
1227 RLupdate (rli);
1228 }
1229 Active_Rline_Info = save_rli;
1230
1231 if (_pSLang_Error) rli->quit = RLINE_QUIT_ABORT;
1232
1233 if (rli->quit)
1234 {
1235 if (rli->quit == RLINE_QUIT_ABORT)
1236 {
1237 rli->len = 0;
1238 }
1239 rli->buf[rli->len] = 0;
1240 rli->state = RLI_LINE_READ;
1241 *lenp = rli->len;
1242
1243 free_history_item (rli->saved_line);
1244 rli->saved_line = NULL;
1245
1246 if (rli->update_postread_hook != NULL)
1247 (*rli->update_postread_hook)(rli, rli->update_client_data);
1248
1249 if (rli->quit == RLINE_QUIT_ABORT)
1250 {
1251 return NULL;
1252 }
1253
1254 return SLmake_nstring ((char *)rli->buf, rli->len);
1255 }
1256 if (key != NULL)
1257 (void) save_last_key (rli, key);
1258 }
1259 }
1260
rl_abort(SLrline_Type * This_RLI)1261 static int rl_abort (SLrline_Type *This_RLI)
1262 {
1263 SLang_set_error (SL_USER_BREAK);
1264 This_RLI->quit = RLINE_QUIT_ABORT;
1265 return 0;
1266 }
1267
1268 /* TTY interface --- ANSI */
1269
ansi_goto_column(int n)1270 static void ansi_goto_column (int n)
1271 {
1272 putc('\r', stdout);
1273 if (n) fprintf(stdout, "\033[%dC", n);
1274 }
1275
rl_select_line(SLrline_Type * rli,RL_History_Type * p)1276 static int rl_select_line (SLrline_Type *rli, RL_History_Type *p)
1277 {
1278 unsigned int len;
1279
1280 len = p->len;
1281 if (-1 == check_space (rli, len))
1282 return -1;
1283
1284 rli->last = p;
1285 strcpy ((char *) rli->buf, p->buf);
1286 rli->point = p->point;
1287 rli->len = len;
1288 rli->is_modified = 0;
1289 return 0;
1290 }
1291
rl_redraw(SLrline_Type * This_RLI)1292 static int rl_redraw (SLrline_Type *This_RLI)
1293 {
1294 SLrline_redraw (This_RLI);
1295 return 0;
1296 }
1297
rl_prev_line(SLrline_Type * This_RLI)1298 static int rl_prev_line (SLrline_Type *This_RLI)
1299 {
1300 RL_History_Type *prev;
1301
1302 if ((This_RLI->is_modified)
1303 || (This_RLI->last == NULL))
1304 {
1305 prev = This_RLI->tail;
1306 }
1307 else
1308 prev = This_RLI->last->prev;
1309
1310 if (prev == NULL)
1311 {
1312 rl_beep ();
1313 return 0;
1314 }
1315
1316 if (prev == This_RLI->tail)
1317 {
1318 This_RLI->buf[This_RLI->len] = 0;
1319 free_history_item (This_RLI->saved_line);
1320 This_RLI->saved_line = allocate_history ((char *)This_RLI->buf, This_RLI->point);
1321 if (This_RLI->saved_line == NULL)
1322 return -1;
1323 }
1324
1325 return rl_select_line (This_RLI, prev);
1326 }
1327
rl_next_line(SLrline_Type * This_RLI)1328 static int rl_next_line (SLrline_Type *This_RLI)
1329 {
1330 RL_History_Type *next;
1331
1332 if ((This_RLI->is_modified)
1333 || (This_RLI->last == NULL))
1334 {
1335 rl_beep ();
1336 return 0;
1337 }
1338
1339 next = This_RLI->last->next;
1340
1341 if (next == NULL)
1342 {
1343 int status = 0;
1344
1345 if (This_RLI->saved_line != NULL)
1346 {
1347 status = rl_select_line (This_RLI, This_RLI->saved_line);
1348 free_history_item (This_RLI->saved_line);
1349 This_RLI->saved_line = NULL;
1350 This_RLI->is_modified = 1;
1351 if (status == 0)
1352 return 0;
1353 }
1354 This_RLI->len = This_RLI->point = 0;
1355 *This_RLI->buf = 0;
1356 This_RLI->last = NULL;
1357 This_RLI->is_modified = 0;
1358 return status;
1359 }
1360
1361 return rl_select_line (This_RLI, next);
1362 }
1363
1364 #define AKEY(name,func) {name,(int (*)(void))func}
1365
1366 static SLKeymap_Function_Type SLReadLine_Functions[] =
1367 {
1368 AKEY("kbd_quit",rl_abort),
1369 AKEY("redraw",rl_redraw),
1370 AKEY("up", rl_prev_line),
1371 AKEY("down", rl_next_line),
1372 AKEY("bol", SLrline_bol),
1373 AKEY("eol", SLrline_eol),
1374 AKEY("right", rl_right),
1375 AKEY("left", rl_left),
1376 AKEY("self_insert", rl_self_insert),
1377 AKEY("bdel", rl_bdel),
1378 AKEY("del", rl_del),
1379 AKEY("deleol", rl_deleol),
1380 AKEY("delbol", rl_delbol),
1381 AKEY("enter", rl_enter),
1382 AKEY("trim", rl_trim),
1383 AKEY("quoted_insert", rl_quote_insert),
1384 AKEY("complete", rl_complete),
1385 AKEY(NULL, NULL),
1386 };
1387
SLrline_close(SLrline_Type * rli)1388 void SLrline_close (SLrline_Type *rli)
1389 {
1390 if (rli == NULL)
1391 return;
1392
1393 if (rli->name != NULL)
1394 {
1395 char hookname[1024];
1396 SLrline_Type *arli = Active_Rline_Info;
1397 Active_Rline_Info = rli;
1398 SLsnprintf (hookname, sizeof(hookname), "%s_rline_close_hook", rli->name);
1399 if (0 == SLang_run_hooks (hookname, 0))
1400 (void) SLang_run_hooks ("rline_close_hook", 1, rli->name);
1401 Active_Rline_Info = arli;
1402 SLang_free_slstring (rli->name);
1403 }
1404
1405 if ((rli->update_free_update_data_hook != NULL)
1406 && (rli->update_client_data != NULL))
1407 (*rli->update_free_update_data_hook)(rli, rli->update_client_data);
1408
1409 free_last_key (rli);
1410 free_history (rli->root);
1411 free_history_item (rli->saved_line);
1412 SLang_free_function (rli->list_completions_callback);
1413 SLang_free_function (rli->completion_callback);
1414 SLfree ((char *)rli->prompt);
1415 SLfree ((char *)rli->buf);
1416 SLfree ((char *)rli);
1417 }
1418
init_keymap(void)1419 static int init_keymap (void)
1420 {
1421 int ch;
1422 char simple[2];
1423 SLkeymap_Type *km;
1424
1425 if (RL_Keymap != NULL)
1426 return 0;
1427
1428 simple[1] = 0;
1429 if (NULL == (km = SLang_create_keymap ("ReadLine", NULL)))
1430 return -1;
1431
1432 km->functions = SLReadLine_Functions;
1433
1434 /* This breaks under some DEC ALPHA compilers (scary!) */
1435 #ifndef __DECC
1436 for (ch = ' '; ch < 256; ch++)
1437 {
1438 simple[0] = (char) ch;
1439 SLkm_define_key (simple, (FVOID_STAR) rl_self_insert, km);
1440 }
1441 #else
1442 ch = ' ';
1443 while (1)
1444 {
1445 simple[0] = (char) ch;
1446 SLkm_define_key (simple, (FVOID_STAR) rl_self_insert, km);
1447 ch = ch + 1;
1448 if (ch == 256) break;
1449 }
1450 #endif /* NOT __DECC */
1451
1452 simple[0] = SLang_Abort_Char;
1453 SLkm_define_key (simple, (FVOID_STAR) rl_abort, km);
1454 #ifdef REAL_UNIX_SYSTEM
1455 simple[0] = (char) 4;
1456 #else
1457 simple[0] = (char) 26;
1458 #endif
1459 SLkm_define_key (simple, (FVOID_STAR) rl_eof_insert, km);
1460
1461 #ifndef IBMPC_SYSTEM
1462 SLkm_define_key ("^[[A", (FVOID_STAR) rl_prev_line, km);
1463 SLkm_define_key ("^[[B", (FVOID_STAR) rl_next_line, km);
1464 SLkm_define_key ("^[[C", (FVOID_STAR) rl_right, km);
1465 SLkm_define_key ("^[[D", (FVOID_STAR) rl_left, km);
1466 SLkm_define_key ("^[OA", (FVOID_STAR) rl_prev_line, km);
1467 SLkm_define_key ("^[OB", (FVOID_STAR) rl_next_line, km);
1468 SLkm_define_key ("^[OC", (FVOID_STAR) rl_right, km);
1469 SLkm_define_key ("^[OD", (FVOID_STAR) rl_left, km);
1470 #else
1471 SLkm_define_key ("^@H", (FVOID_STAR) rl_prev_line, km);
1472 SLkm_define_key ("^@P", (FVOID_STAR) rl_next_line, km);
1473 SLkm_define_key ("^@M", (FVOID_STAR) rl_right, km);
1474 SLkm_define_key ("^@K", (FVOID_STAR) rl_left, km);
1475 SLkm_define_key ("^@S", (FVOID_STAR) rl_del, km);
1476 SLkm_define_key ("^@O", (FVOID_STAR) SLrline_eol, km);
1477 SLkm_define_key ("^@G", (FVOID_STAR) SLrline_bol, km);
1478
1479 SLkm_define_key ("\xE0H", (FVOID_STAR) rl_prev_line, km);
1480 SLkm_define_key ("\xE0P", (FVOID_STAR) rl_next_line, km);
1481 SLkm_define_key ("\xE0M", (FVOID_STAR) rl_right, km);
1482 SLkm_define_key ("\xE0K", (FVOID_STAR) rl_left, km);
1483 SLkm_define_key ("\xE0S", (FVOID_STAR) rl_del, km);
1484 SLkm_define_key ("\xE0O", (FVOID_STAR) SLrline_eol, km);
1485 SLkm_define_key ("\xE0G", (FVOID_STAR) SLrline_bol, km);
1486 #endif
1487 SLkm_define_key ("^C", (FVOID_STAR) rl_abort, km);
1488 SLkm_define_key ("^E", (FVOID_STAR) SLrline_eol, km);
1489 SLkm_define_key ("^G", (FVOID_STAR) rl_abort, km);
1490 SLkm_define_key ("^I", (FVOID_STAR) rl_complete, km);
1491 SLkm_define_key ("^A", (FVOID_STAR) SLrline_bol, km);
1492 SLkm_define_key ("\r", (FVOID_STAR) rl_enter, km);
1493 SLkm_define_key ("\n", (FVOID_STAR) rl_enter, km);
1494 SLkm_define_key ("^K", (FVOID_STAR) rl_deleol, km);
1495 SLkm_define_key ("^L", (FVOID_STAR) rl_deleol, km);
1496 SLkm_define_key ("^U", (FVOID_STAR) rl_delbol, km);
1497 SLkm_define_key ("^V", (FVOID_STAR) rl_del, km);
1498 SLkm_define_key ("^D", (FVOID_STAR) rl_del, km);
1499 SLkm_define_key ("^F", (FVOID_STAR) rl_right, km);
1500 SLkm_define_key ("^B", (FVOID_STAR) rl_left, km);
1501 SLkm_define_key ("^?", (FVOID_STAR) rl_bdel, km);
1502 SLkm_define_key ("^H", (FVOID_STAR) rl_bdel, km);
1503 SLkm_define_key ("^P", (FVOID_STAR) rl_prev_line, km);
1504 SLkm_define_key ("^N", (FVOID_STAR) rl_next_line, km);
1505 SLkm_define_key ("^R", (FVOID_STAR) rl_redraw, km);
1506 SLkm_define_key ("`", (FVOID_STAR) rl_quote_insert, km);
1507 SLkm_define_key ("\033\\", (FVOID_STAR) rl_trim, km);
1508 if (_pSLang_Error)
1509 return -1;
1510 RL_Keymap = km;
1511 return 0;
1512 }
1513
1514 #if SLANG_HAS_MULTILINE_RLINE
1515 typedef struct
1516 {
1517 int max_row;
1518 int max_col;
1519 int num_screen_cols;
1520 int num_screen_rows;
1521 }
1522 RLine_SMG_Update_Type;
1523
alloc_smg_update_data(void)1524 static RLine_SMG_Update_Type *alloc_smg_update_data (void)
1525 {
1526 return (RLine_SMG_Update_Type *)SLcalloc (1, sizeof(RLine_SMG_Update_Type));
1527 }
1528
free_smg_update_data(SLrline_Type * rli,VOID_STAR cd)1529 static void free_smg_update_data (SLrline_Type *rli, VOID_STAR cd)
1530 {
1531 (void) rli;
1532 if (cd != NULL)
1533 SLfree ((char *)cd);
1534 }
1535
check_window_size_and_redraw(SLrline_Type * rli,RLine_SMG_Update_Type * s)1536 static int check_window_size_and_redraw (SLrline_Type *rli, RLine_SMG_Update_Type *s)
1537 {
1538 if ((s->num_screen_cols != SLtt_Screen_Cols)
1539 || (s->num_screen_rows != SLtt_Screen_Rows))
1540 {
1541 SLsmg_reinit_smg ();
1542 rli->edit_width = s->num_screen_cols = SLtt_Screen_Cols;
1543 s->num_screen_rows = SLtt_Screen_Rows;
1544 SLrline_redraw (rli);
1545 return 1;
1546 }
1547 return 0;
1548 }
1549
rline_smg_update(SLrline_Type * rli,SLFUTURE_CONST char * prompt,SLFUTURE_CONST char * buf,unsigned int buflen,unsigned int point,VOID_STAR cd)1550 static void rline_smg_update (SLrline_Type *rli, SLFUTURE_CONST char *prompt,
1551 SLFUTURE_CONST char *buf, unsigned int buflen,
1552 unsigned int point, VOID_STAR cd)
1553 {
1554 int r0, c0, r1, c1;
1555 RLine_SMG_Update_Type *s = (RLine_SMG_Update_Type *) cd;
1556 (void) rli;
1557
1558 if (check_window_size_and_redraw (rli, s))
1559 return;
1560
1561 if ((*buf == 0) && (*prompt == 0))
1562 _pSLtt_cmdline_mode_reset ();
1563
1564 SLsmg_gotorc (0, 0);
1565 SLsmg_write_string (prompt);
1566 r0 = SLsmg_get_row ();
1567 c0 = SLsmg_get_column ();
1568 SLsmg_write_nchars (buf, buflen);
1569 r1 = SLsmg_get_row ();
1570 c1 = SLsmg_get_column ();
1571 if (r1 <= s->max_row)
1572 {
1573 int r = r1, c = c1;
1574 while (r <= s->max_row)
1575 {
1576 SLsmg_gotorc (r, c);
1577 SLsmg_erase_eol ();
1578 c = 0;
1579 r++;
1580 }
1581 }
1582 s->max_row = r1;
1583 s->max_col = c1;
1584 SLsmg_gotorc (r0, c0);
1585 SLsmg_write_nchars (buf, point);
1586 SLsmg_refresh ();
1587 }
1588
rline_smg_preread(SLrline_Type * rli,VOID_STAR cd)1589 static void rline_smg_preread (SLrline_Type *rli, VOID_STAR cd)
1590 {
1591 RLine_SMG_Update_Type *s = (RLine_SMG_Update_Type *) cd;
1592
1593 (void) rli;
1594 _pSLtt_cmdline_mode_reset ();
1595 SLsmg_gotorc (0,0);
1596 SLsmg_erase_eos ();
1597 s->max_row = 0;
1598 s->max_col = 0;
1599 SLsmg_refresh ();
1600 }
1601
rline_smg_postread(SLrline_Type * rli,VOID_STAR cd)1602 static void rline_smg_postread (SLrline_Type *rli, VOID_STAR cd)
1603 {
1604 RLine_SMG_Update_Type *s = (RLine_SMG_Update_Type *) cd;
1605
1606 (void) rli;
1607 SLsmg_gotorc (s->max_row, s->max_col);
1608 SLsmg_refresh ();
1609 }
1610
rline_smg_clear(SLrline_Type * rli,VOID_STAR cd)1611 static void rline_smg_clear (SLrline_Type *rli, VOID_STAR cd)
1612 {
1613 RLine_SMG_Update_Type *s = (RLine_SMG_Update_Type *) cd;
1614
1615 (void) rli;
1616 SLsmg_gotorc (0,0);
1617 SLsmg_cls ();
1618 s->max_row = 0;
1619 s->max_col = 0;
1620 }
1621
rline_smg_display_width_changed(SLrline_Type * rli,int w,VOID_STAR cd)1622 static void rline_smg_display_width_changed (SLrline_Type *rli, int w, VOID_STAR cd)
1623 {
1624 RLine_SMG_Update_Type *s = (RLine_SMG_Update_Type *) cd;
1625 (void) w;
1626
1627 SLtt_get_screen_size ();
1628 (void) check_window_size_and_redraw (rli, s);
1629 }
1630
try_smg_multiline_mode(SLrline_Type * rli)1631 static int try_smg_multiline_mode (SLrline_Type *rli)
1632 {
1633 int status;
1634 RLine_SMG_Update_Type *cd;
1635
1636 status = _pSLtt_init_cmdline_mode ();
1637 if (status <= 0)
1638 return status;
1639
1640 if (NULL == (cd = alloc_smg_update_data ()))
1641 return -1;
1642
1643 (void) SLrline_set_update_hook (rli, rline_smg_update, cd);
1644 rli->update_free_update_data_hook = free_smg_update_data;
1645 rli->update_clear_hook = rline_smg_clear;
1646 rli->update_preread_hook = rline_smg_preread;
1647 rli->update_postread_hook = rline_smg_postread;
1648 rli->update_display_width_changed_hook = rline_smg_display_width_changed;
1649
1650 rli->edit_width = cd->num_screen_cols = SLtt_Screen_Cols;
1651 cd->num_screen_rows = SLtt_Screen_Rows;
1652
1653 if (-1 == _pSLsmg_init_smg_cmdline ())
1654 return -1;
1655
1656 return 1;
1657 }
1658 #endif /* SLANG_HAS_MULTILINE_RLINE */
1659
SLrline_open(unsigned int width,unsigned int flags)1660 SLrline_Type *SLrline_open (unsigned int width, unsigned int flags)
1661 {
1662 SLrline_Type *rli;
1663
1664 if (_pSLutf8_mode)
1665 flags |= SL_RLINE_UTF8_MODE;
1666
1667 if (NULL == (rli = (SLrline_Type *)SLcalloc (1, sizeof (SLrline_Type))))
1668 return NULL;
1669
1670 if (width == 0)
1671 width = 80;
1672
1673 if (width < 256) rli->buf_len = 256;
1674 else rli->buf_len = width;
1675
1676 if (NULL == (rli->buf = (unsigned char *)SLmalloc (rli->buf_len)))
1677 {
1678 SLrline_close (rli);
1679 return NULL;
1680 }
1681 *rli->buf = 0;
1682 #ifdef REAL_UNIX_SYSTEM
1683 rli->eof_char = 4;
1684 #else
1685 rli->eof_char = 26;
1686 #endif
1687
1688 rli->point = 0;
1689 rli->flags = flags;
1690 rli->edit_width = width;
1691 rli->hscroll = width/4;
1692 rli->tab = 8;
1693 rli->getkey = SLang_getkey;
1694 rli->input_pending = SLang_input_pending;
1695 rli->state = RLI_LINE_INVALID;
1696
1697 if (rli->flags & SL_RLINE_USE_ANSI)
1698 {
1699 if (rli->tt_goto_column == NULL) rli->tt_goto_column = ansi_goto_column;
1700 }
1701
1702 if (-1 == init_keymap ())
1703 {
1704 SLrline_close (rli);
1705 return NULL;
1706 }
1707 rli->keymap = RL_Keymap;
1708 rli->old_upd = rli->upd_buf1;
1709 rli->new_upd = rli->upd_buf2;
1710
1711 if (Char_Widths[0] == 0)
1712 {
1713 int ch;
1714 /* FIXME: This does not support UTF-8 */
1715 for (ch = 0; ch < 32; ch++) Char_Widths[ch] = 2;
1716 for (ch = 32; ch < 256; ch++) Char_Widths[ch] = 1;
1717 Char_Widths[127] = 2;
1718 #ifndef IBMPC_SYSTEM
1719 for (ch = 128; ch < 160; ch++) Char_Widths[ch] = 3;
1720 #endif
1721 }
1722 #if SLANG_HAS_MULTILINE_RLINE
1723 if (flags & SL_RLINE_USE_MULTILINE)
1724 {
1725 if (-1 == try_smg_multiline_mode (rli))
1726 {
1727 SLrline_close (rli);
1728 return NULL;
1729 }
1730 }
1731 #endif
1732 return rli;
1733 }
1734
SLrline_open2(SLFUTURE_CONST char * name,unsigned int width,unsigned int flags)1735 SLrline_Type *SLrline_open2 (SLFUTURE_CONST char *name, unsigned int width, unsigned int flags)
1736 {
1737 SLrline_Type *rli;
1738 SLrline_Type *arli;
1739 char hookname [1024];
1740
1741 if (NULL == (rli = SLrline_open (width, flags)))
1742 return NULL;
1743
1744 if (NULL != rli->name)
1745 SLang_free_slstring (rli->name);
1746 if (NULL == (rli->name = SLang_create_slstring (name)))
1747 {
1748 SLrline_close (rli);
1749 return NULL;
1750 }
1751
1752 arli = Active_Rline_Info;
1753 Active_Rline_Info = rli;
1754 SLsnprintf (hookname, sizeof(hookname), "%s_rline_open_hook", name);
1755 if (0 == SLang_run_hooks (hookname, 0))
1756 (void) SLang_run_hooks ("rline_open_hook", 1, name);
1757 Active_Rline_Info = arli;
1758 return rli;
1759 }
1760
SLrline_add_to_history(SLrline_Type * rli,SLFUTURE_CONST char * hist)1761 int SLrline_add_to_history (SLrline_Type *rli, SLFUTURE_CONST char *hist)
1762 {
1763 RL_History_Type *h;
1764
1765 if ((rli == NULL) || (hist == NULL))
1766 return -1;
1767
1768 h = allocate_history (hist, -1);
1769
1770 if (rli->root == NULL)
1771 rli->root = h;
1772
1773 if (rli->tail != NULL)
1774 rli->tail->next = h;
1775
1776 h->prev = rli->tail;
1777 rli->tail = h;
1778 h->next = NULL;
1779
1780 return 0;
1781 }
1782
SLrline_save_line(SLrline_Type * rli)1783 int SLrline_save_line (SLrline_Type *rli)
1784 {
1785 if (rli == NULL)
1786 return -1;
1787
1788 return SLrline_add_to_history (rli, (char *) rli->buf);
1789 }
1790
SLrline_get_keymap(SLrline_Type * rli)1791 SLkeymap_Type *SLrline_get_keymap (SLrline_Type *rli)
1792 {
1793 if (rli == NULL)
1794 return NULL;
1795 return rli->keymap;
1796 }
1797
SLrline_set_update_hook(SLrline_Type * rli,void (* fun)(SLrline_Type *,SLFUTURE_CONST char *,SLFUTURE_CONST char *,unsigned int,unsigned int,VOID_STAR),VOID_STAR client_data)1798 int SLrline_set_update_hook (SLrline_Type *rli,
1799 void (*fun)(SLrline_Type *, SLFUTURE_CONST char *, SLFUTURE_CONST char *, unsigned int, unsigned int, VOID_STAR),
1800 VOID_STAR client_data)
1801 {
1802 if (rli == NULL)
1803 return -1;
1804
1805 rli->update_hook = fun;
1806 rli->update_client_data = client_data;
1807 return 0;
1808 }
1809
SLrline_get_update_client_data(SLrline_Type * rli,VOID_STAR * cdp)1810 int SLrline_get_update_client_data (SLrline_Type *rli, VOID_STAR *cdp)
1811 {
1812 if (rli == NULL)
1813 return -1;
1814 *cdp = rli->update_client_data;
1815 return 0;
1816 }
1817
SLrline_set_free_update_cb(SLrline_Type * rli,void (* fun)(SLrline_Type *,VOID_STAR))1818 void SLrline_set_free_update_cb (SLrline_Type *rli,
1819 void (*fun)(SLrline_Type *, VOID_STAR))
1820 {
1821 if (rli != NULL)
1822 rli->update_free_update_data_hook = fun;
1823 }
1824
SLrline_set_update_clear_cb(SLrline_Type * rli,void (* fun)(SLrline_Type *,VOID_STAR))1825 void SLrline_set_update_clear_cb (SLrline_Type *rli,
1826 void (*fun)(SLrline_Type *, VOID_STAR))
1827 {
1828 if (rli != NULL)
1829 rli->update_clear_hook = fun;
1830 }
1831
SLrline_set_update_preread_cb(SLrline_Type * rli,void (* fun)(SLrline_Type *,VOID_STAR))1832 void SLrline_set_update_preread_cb (SLrline_Type *rli,
1833 void (*fun)(SLrline_Type *, VOID_STAR))
1834 {
1835 if (rli != NULL)
1836 rli->update_preread_hook = fun;
1837 }
1838
SLrline_set_update_postread_cb(SLrline_Type * rli,void (* fun)(SLrline_Type *,VOID_STAR))1839 void SLrline_set_update_postread_cb (SLrline_Type *rli,
1840 void (*fun)(SLrline_Type *, VOID_STAR))
1841 {
1842 if (rli != NULL)
1843 rli->update_postread_hook = fun;
1844 }
1845
SLrline_set_update_width_cb(SLrline_Type * rli,void (* fun)(SLrline_Type *,int,VOID_STAR))1846 void SLrline_set_update_width_cb (SLrline_Type *rli,
1847 void (*fun)(SLrline_Type *, int, VOID_STAR))
1848 {
1849 if (rli != NULL)
1850 rli->update_display_width_changed_hook = fun;
1851 }
1852
1853
SLrline_get_line(SLrline_Type * rli)1854 char *SLrline_get_line (SLrline_Type *rli)
1855 {
1856 if (rli == NULL)
1857 return NULL;
1858 return SLmake_nstring ((char *)rli->buf, rli->len);
1859 }
1860
SLrline_get_point(SLrline_Type * rli,unsigned int * pointp)1861 int SLrline_get_point (SLrline_Type *rli, unsigned int *pointp)
1862 {
1863 if (rli == NULL)
1864 return -1;
1865 *pointp = rli->point;
1866 return 0;
1867 }
1868
SLrline_set_point(SLrline_Type * rli,unsigned int point)1869 int SLrline_set_point (SLrline_Type *rli, unsigned int point)
1870 {
1871 if (rli == NULL)
1872 return -1;
1873
1874 if (rli->state == RLI_LINE_INVALID)
1875 return -1;
1876
1877 if (point > rli->len)
1878 point = rli->len;
1879
1880 rli->point = point;
1881 return 0;
1882 }
1883
SLrline_get_tab(SLrline_Type * rli,unsigned int * p)1884 int SLrline_get_tab (SLrline_Type *rli, unsigned int *p)
1885 {
1886 if (rli == NULL)
1887 return -1;
1888 *p = rli->tab;
1889 return 0;
1890 }
1891
SLrline_set_tab(SLrline_Type * rli,unsigned int tab)1892 int SLrline_set_tab (SLrline_Type *rli, unsigned int tab)
1893 {
1894 if (rli == NULL)
1895 return -1;
1896
1897 rli->tab = tab;
1898 return 0;
1899 }
1900
SLrline_get_hscroll(SLrline_Type * rli,unsigned int * p)1901 int SLrline_get_hscroll (SLrline_Type *rli, unsigned int *p)
1902 {
1903 if (rli == NULL)
1904 return -1;
1905 *p = rli->hscroll;
1906 return 0;
1907 }
1908
SLrline_set_hscroll(SLrline_Type * rli,unsigned int p)1909 int SLrline_set_hscroll (SLrline_Type *rli, unsigned int p)
1910 {
1911 if (rli == NULL)
1912 return -1;
1913 rli->hscroll = p;
1914 return 0;
1915 }
1916
SLrline_set_line(SLrline_Type * rli,SLFUTURE_CONST char * buf)1917 int SLrline_set_line (SLrline_Type *rli, SLFUTURE_CONST char *buf)
1918 {
1919 unsigned int len;
1920
1921 if (rli == NULL)
1922 return -1;
1923
1924 if (buf == NULL)
1925 buf = "";
1926
1927 len = strlen (buf);
1928
1929 buf = SLmake_string (buf);
1930 if (buf == NULL)
1931 return -1;
1932
1933 SLfree ((char *)rli->buf);
1934 rli->buf = (unsigned char *)buf;
1935 rli->buf_len = len;
1936
1937 rli->point = len;
1938 rli->len = len;
1939
1940 rli->state = RLI_LINE_SET;
1941 return 0;
1942 }
1943
SLrline_set_echo(SLrline_Type * rli,int state)1944 int SLrline_set_echo (SLrline_Type *rli, int state)
1945 {
1946 if (rli == NULL)
1947 return -1;
1948
1949 if (state == 0)
1950 rli->flags |= SL_RLINE_NO_ECHO;
1951 else
1952 rli->flags &= ~SL_RLINE_NO_ECHO;
1953
1954 return 0;
1955 }
1956
SLrline_get_echo(SLrline_Type * rli,int * statep)1957 int SLrline_get_echo (SLrline_Type *rli, int *statep)
1958 {
1959 if (rli == NULL)
1960 return -1;
1961
1962 *statep = (0 == (rli->flags & SL_RLINE_NO_ECHO));
1963 return 0;
1964 }
1965
SLrline_set_display_width(SLrline_Type * rli,unsigned int w)1966 int SLrline_set_display_width (SLrline_Type *rli, unsigned int w)
1967 {
1968 unsigned int old_width;
1969
1970 if (rli == NULL)
1971 return -1;
1972 if (w < 1)
1973 w = 80;
1974
1975 old_width = rli->edit_width;
1976 rli->edit_width = w;
1977
1978 if (rli->update_display_width_changed_hook != NULL)
1979 (*rli->update_display_width_changed_hook) (rli, w, rli->update_client_data);
1980 else
1981 {
1982 if (w != old_width)
1983 SLrline_redraw (rli);
1984 }
1985 return 0;
1986 }
1987
1988 /* SLang Interface */
1989
rline_ins_intrinsic(char * str)1990 static void rline_ins_intrinsic (char *str)
1991 {
1992 if (Active_Rline_Info != NULL)
1993 (void) SLrline_ins (Active_Rline_Info, str, strlen (str));
1994 }
1995
rline_del_intrinsic(int * np)1996 static void rline_del_intrinsic (int *np)
1997 {
1998 int n = *np;
1999
2000 if (Active_Rline_Info == NULL)
2001 return;
2002
2003 if (n < 0)
2004 {
2005 (void) SLrline_move (Active_Rline_Info, n);
2006 n = -n;
2007 }
2008
2009 (void) SLrline_del (Active_Rline_Info, (unsigned int) n);
2010 }
2011
get_keymap(void)2012 static SLkeymap_Type *get_keymap (void)
2013 {
2014 SLkeymap_Type *kmap;
2015
2016 if (Active_Rline_Info != NULL)
2017 kmap = SLrline_get_keymap (Active_Rline_Info);
2018 else
2019 kmap = RL_Keymap;
2020
2021 if (kmap != NULL)
2022 return kmap;
2023
2024 _pSLang_verror (SL_APPLICATION_ERROR, "No keymap available for rline interface");
2025 return NULL;
2026 }
2027
rline_setkey_intrinsic(char * keyseq)2028 static void rline_setkey_intrinsic (char *keyseq)
2029 {
2030 char *str;
2031 SLkeymap_Type *kmap;
2032
2033 if (NULL == (kmap = get_keymap ()))
2034 return;
2035
2036 if (SLang_peek_at_stack () == SLANG_REF_TYPE)
2037 {
2038 SLang_Name_Type *nt;
2039
2040 if (NULL == (nt = SLang_pop_function ()))
2041 return;
2042
2043 (void) SLkm_define_slkey (keyseq, nt, kmap);
2044 return;
2045 }
2046
2047 if (-1 == SLang_pop_slstring (&str))
2048 return;
2049
2050 (void) SLang_define_key (keyseq, str, kmap);
2051 SLang_free_slstring (str);
2052 }
2053
rline_unsetkey_intrinsic(char * keyseq)2054 static void rline_unsetkey_intrinsic (char *keyseq)
2055 {
2056 SLkeymap_Type *kmap;
2057
2058 if (NULL != (kmap = get_keymap ()))
2059 SLang_undefine_key (keyseq, kmap);
2060 }
2061
rline_get_point_intrinsic(void)2062 static int rline_get_point_intrinsic (void)
2063 {
2064 unsigned int p;
2065
2066 if ((Active_Rline_Info == NULL)
2067 || (-1 == SLrline_get_point (Active_Rline_Info, &p)))
2068 return 0;
2069
2070 return (int) p;
2071 }
2072
rline_set_point_intrinsic(int * pp)2073 static void rline_set_point_intrinsic (int *pp)
2074 {
2075 int p;
2076 SLrline_Type *rli;
2077
2078 if (NULL == (rli = Active_Rline_Info))
2079 return;
2080
2081 p = *pp;
2082 if (p < 0)
2083 {
2084 p = (int)rli->len + (p + 1);
2085 if (p < 0)
2086 p = 0;
2087 }
2088
2089 if ((unsigned int)p > rli->len)
2090 p = (int)rli->len;
2091
2092 (void) SLrline_set_point (rli, (unsigned int) p);
2093 }
2094
rline_call_intrinsic(char * fun)2095 static void rline_call_intrinsic (char *fun)
2096 {
2097 int (*f)(SLrline_Type *);
2098
2099 if (Active_Rline_Info == NULL)
2100 return;
2101
2102 if (NULL == (f = (int (*)(SLrline_Type *)) (SLang_find_key_function(fun, Active_Rline_Info->keymap))))
2103 {
2104 _pSLang_verror (SL_UndefinedName_Error, "rline internal function %s does not exist", fun);
2105 return;
2106 }
2107
2108 (void) (*f)(Active_Rline_Info);
2109 /* Active_Rline_Info->last_fun = (FVOID_STAR) f; */
2110 }
2111
rline_get_line_intrinsic(void)2112 static void rline_get_line_intrinsic (void)
2113 {
2114 char *s;
2115
2116 if ((Active_Rline_Info == NULL)
2117 || (NULL == (s = SLrline_get_line (Active_Rline_Info))))
2118 {
2119 (void) SLang_push_string ("");
2120 return;
2121 }
2122 (void) SLang_push_malloced_string (s);
2123 }
2124
rline_set_line_intrinsic(char * str)2125 static void rline_set_line_intrinsic (char *str)
2126 {
2127 if (Active_Rline_Info == NULL)
2128 return;
2129
2130 (void) SLrline_set_line (Active_Rline_Info, str);
2131 }
2132
rline_set_completion_callback(void)2133 static void rline_set_completion_callback (void)
2134 {
2135 SLang_Name_Type *nt;
2136
2137 if (NULL == (nt = SLang_pop_function ()))
2138 return;
2139
2140 if (Active_Rline_Info == NULL)
2141 {
2142 SLang_free_function (Default_Completion_Callback);
2143 Default_Completion_Callback = nt;
2144 return;
2145 }
2146 SLang_free_function (Active_Rline_Info->completion_callback);
2147 Active_Rline_Info->completion_callback = nt;
2148 }
2149
rline_set_list_completions_callback(void)2150 static void rline_set_list_completions_callback (void)
2151 {
2152 SLang_Name_Type *nt;
2153
2154 if (NULL == (nt = SLang_pop_function ()))
2155 return;
2156
2157 if (Active_Rline_Info == NULL)
2158 {
2159 SLang_free_function (Default_List_Completions_Callback);
2160 Default_List_Completions_Callback = nt;
2161 return;
2162 }
2163 SLang_free_function (Active_Rline_Info->list_completions_callback);
2164 Active_Rline_Info->list_completions_callback = nt;
2165 }
2166
rline_input_pending_intrinsic(int * tsecsp)2167 static int rline_input_pending_intrinsic (int *tsecsp)
2168 {
2169 int tsecs = *tsecsp;
2170 if (tsecs < 0)
2171 tsecs = 0;
2172
2173 if (Active_Rline_Info == NULL)
2174 return 0;
2175
2176 if (Active_Rline_Info->input_pending == NULL)
2177 return 1;
2178
2179 return Active_Rline_Info->input_pending (tsecs);
2180 }
2181
rline_getkey_intrinsic(void)2182 static int rline_getkey_intrinsic (void)
2183 {
2184 if (Active_Rline_Info == NULL)
2185 return -1;
2186
2187 return (int) Active_Rline_Info->getkey ();
2188 }
2189
rline_bolp_intrinsic(void)2190 static int rline_bolp_intrinsic (void)
2191 {
2192 if (Active_Rline_Info == NULL)
2193 return 0;
2194 return Active_Rline_Info->point == 0;
2195 }
2196
rline_eolp_intrinsic(void)2197 static int rline_eolp_intrinsic (void)
2198 {
2199 if (Active_Rline_Info == NULL)
2200 return 0;
2201 return Active_Rline_Info->point == Active_Rline_Info->len;
2202 }
2203
rline_get_edit_width_intrinsic(void)2204 static int rline_get_edit_width_intrinsic (void)
2205 {
2206 if (Active_Rline_Info == NULL)
2207 return 80;
2208 return Active_Rline_Info->edit_width;
2209 }
2210
rline_get_history_intrinsic(void)2211 static void rline_get_history_intrinsic (void)
2212 {
2213 SLindex_Type i, num;
2214 RL_History_Type *h;
2215 char **data;
2216 SLang_Array_Type *at;
2217
2218 if (Active_Rline_Info == NULL)
2219 {
2220 SLang_push_null ();
2221 return;
2222 }
2223
2224 num = 0;
2225 h = Active_Rline_Info->root;
2226 while (h != NULL)
2227 {
2228 h = h->next;
2229 num++;
2230 }
2231 if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &num, 1)))
2232 return;
2233
2234 data = (char **)at->data;
2235 h = Active_Rline_Info->root;
2236 for (i = 0; i < num; i++)
2237 {
2238 if (NULL == (data[i] = SLang_create_slstring (h->buf)))
2239 {
2240 SLang_free_array (at);
2241 return;
2242 }
2243 h = h->next;
2244 }
2245
2246 (void) SLang_push_array (at, 1);
2247 }
2248
rline_set_history_intrinsic(void)2249 static void rline_set_history_intrinsic (void)
2250 {
2251 int i, num;
2252 char **data;
2253 SLrline_Type *rli;
2254 SLang_Array_Type *at;
2255
2256 if (-1 == SLang_pop_array_of_type (&at, SLANG_STRING_TYPE))
2257 return;
2258
2259 if (NULL == (rli = Active_Rline_Info))
2260 {
2261 SLang_free_array (at);
2262 return;
2263 }
2264
2265 free_history (rli->root);
2266 rli->tail = rli->root = rli->last = NULL;
2267
2268 data = (char **)at->data;
2269 num = at->num_elements;
2270 for (i = 0; i < num; i++)
2271 {
2272 if (-1 == SLrline_add_to_history (rli, data[i]))
2273 break;
2274 }
2275 SLang_free_array (at);
2276 }
2277
find_function_string(SLrline_Type * rli,FVOID_STAR f)2278 static char *find_function_string (SLrline_Type *rli, FVOID_STAR f)
2279 {
2280 SLKeymap_Function_Type *fp;
2281
2282 if ((rli == NULL) || (rli->keymap == NULL))
2283 return NULL;
2284
2285 fp = rli->keymap->functions;
2286 while ((fp != NULL) && (fp->name != NULL))
2287 {
2288 if ((FVOID_STAR) fp->f == f) return (char *) fp->name;
2289 fp++;
2290 }
2291 return NULL;
2292 }
2293
rline_get_last_key_function_intrinsic(void)2294 static void rline_get_last_key_function_intrinsic (void)
2295 {
2296 SLang_Key_Type *last_key;
2297 char *s;
2298
2299 if (Active_Rline_Info == NULL)
2300 {
2301 (void) SLang_push_null ();
2302 return;
2303 }
2304
2305 last_key = &Active_Rline_Info->last_key;
2306 switch (last_key->type)
2307 {
2308 case SLKEY_F_INTERPRET:
2309 if (last_key->f.s != NULL)
2310 {
2311 (void) SLang_push_string (last_key->f.s);
2312 return;
2313 }
2314 break;
2315
2316 case SLKEY_F_INTRINSIC:
2317 if (NULL != (s = find_function_string (Active_Rline_Info, last_key->f.f)))
2318 {
2319 (void) SLang_push_string (s);
2320 return;
2321 }
2322 break;
2323
2324 case SLKEY_F_SLANG:
2325 if (NULL != last_key->f.slang_fun)
2326 {
2327 (void) SLang_push_function (last_key->f.slang_fun);
2328 return;
2329 }
2330 case SLKEY_F_KEYSYM:
2331 (void) SLang_push_uint (last_key->f.keysym);
2332 return;
2333
2334 default:
2335 break;
2336 }
2337
2338 (void) SLang_push_null ();
2339 }
2340
2341 static SLang_Intrin_Fun_Type Intrinsics [] =
2342 {
2343 MAKE_INTRINSIC_S("rline_call", rline_call_intrinsic, VOID_TYPE),
2344 MAKE_INTRINSIC_S("rline_ins", rline_ins_intrinsic, VOID_TYPE),
2345 MAKE_INTRINSIC_I("rline_del", rline_del_intrinsic, VOID_TYPE),
2346 MAKE_INTRINSIC_0("rline_bolp", rline_bolp_intrinsic, INT_TYPE),
2347 MAKE_INTRINSIC_0("rline_eolp", rline_eolp_intrinsic, INT_TYPE),
2348 MAKE_INTRINSIC_0("rline_get_point", rline_get_point_intrinsic, INT_TYPE),
2349 MAKE_INTRINSIC_I("rline_set_point", rline_set_point_intrinsic, VOID_TYPE),
2350 MAKE_INTRINSIC_0("rline_get_edit_width", rline_get_edit_width_intrinsic, INT_TYPE),
2351 MAKE_INTRINSIC_0("rline_get_line", rline_get_line_intrinsic, VOID_TYPE),
2352 MAKE_INTRINSIC_S("rline_set_line", rline_set_line_intrinsic, VOID_TYPE),
2353 MAKE_INTRINSIC_S("rline_setkey", rline_setkey_intrinsic, VOID_TYPE),
2354 MAKE_INTRINSIC_S("rline_unsetkey", rline_unsetkey_intrinsic, VOID_TYPE),
2355 MAKE_INTRINSIC_0("rline_getkey", rline_getkey_intrinsic, INT_TYPE),
2356 MAKE_INTRINSIC_0("rline_set_history", rline_set_history_intrinsic, VOID_TYPE),
2357 MAKE_INTRINSIC_0("rline_get_history", rline_get_history_intrinsic, VOID_TYPE),
2358 MAKE_INTRINSIC_I("rline_input_pending", rline_input_pending_intrinsic, INT_TYPE),
2359 MAKE_INTRINSIC_0("rline_set_completion_callback", rline_set_completion_callback, VOID_TYPE),
2360 MAKE_INTRINSIC_0("rline_set_list_completions_callback", rline_set_list_completions_callback, VOID_TYPE),
2361 MAKE_INTRINSIC_0("rline_get_last_key_function", rline_get_last_key_function_intrinsic, VOID_TYPE),
2362 SLANG_END_INTRIN_FUN_TABLE
2363 };
2364
SLrline_init(SLFUTURE_CONST char * appname,SLFUTURE_CONST char * user_initfile,SLFUTURE_CONST char * sys_initfile)2365 int SLrline_init (SLFUTURE_CONST char *appname, SLFUTURE_CONST char *user_initfile, SLFUTURE_CONST char *sys_initfile)
2366 {
2367 #ifdef __WIN32__
2368 char *home_dir = getenv ("USERPROFILE");
2369 #else
2370 # ifdef VMS
2371 char *home_dir = "SYS$LOGIN:";
2372 # else
2373 char *home_dir = getenv ("HOME");
2374 # endif
2375 #endif
2376 char *file = NULL;
2377 int status;
2378 static char *appname_malloced;
2379
2380 if (sys_initfile == NULL)
2381 sys_initfile = SLRLINE_SYS_INIT_FILE;
2382 if (user_initfile == NULL)
2383 user_initfile = SLRLINE_USER_INIT_FILE;
2384
2385 if (appname == NULL)
2386 appname = "Unknown";
2387
2388 if (NULL == (appname_malloced = SLmake_string (appname)))
2389 return -1;
2390
2391 if (-1 == SLadd_intrinsic_variable ("__RL_APP__", &appname_malloced, SLANG_STRING_TYPE, 1))
2392 return -1;
2393
2394 if (-1 == SLadd_intrin_fun_table (Intrinsics, NULL))
2395 return -1;
2396
2397 if (-1 == init_keymap ())
2398 return -1;
2399 #if SLANG_HAS_MULTILINE_RLINE
2400 /* Initialize the terminal here to allow the user to use termcap sequences */
2401 (void) SLtt_initialize (NULL);
2402 #endif
2403 if (user_initfile != NULL)
2404 {
2405 file = SLpath_find_file_in_path (home_dir, user_initfile);
2406 if (file != NULL)
2407 {
2408 status = SLns_load_file (file, NULL);
2409 SLfree (file);
2410 return status;
2411 }
2412 }
2413
2414 if (sys_initfile != NULL)
2415 {
2416 file = _pSLpath_find_file (sys_initfile, 0);
2417 if (file != NULL)
2418 {
2419 status = SLns_load_file (file, NULL);
2420 SLang_free_slstring (file);
2421 return status;
2422 }
2423 }
2424
2425 return 0;
2426 }
2427