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