Annotation of OpenXM_contrib/pari-2.2/src/gp/gp_rl.c, Revision 1.2
1.2 ! noro 1: /* $Id: gp_rl.c,v 1.18 2002/09/05 11:38:39 karim Exp $
1.1 noro 2:
3: Copyright (C) 2000 The PARI group.
4:
5: This file is part of the PARI/GP package.
6:
7: PARI/GP is free software; you can redistribute it and/or modify it under the
8: terms of the GNU General Public License as published by the Free Software
9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
10: ANY WARRANTY WHATSOEVER.
11:
12: Check the License for details. You should have received a copy of it, along
13: with the package; see the file 'COPYING'. If not, write to the Free Software
14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
15:
16: /*******************************************************************/
17: /* */
18: /* INTERFACE TO READLINE COMPLETION */
19: /* */
20: /*******************************************************************/
21: #include "pari.h"
22: #include "../language/anal.h"
23: #include "gp.h"
24:
25: #ifdef READLINE
1.2 ! noro 26: typedef char** (*CF)(char*, char* (*)(void)); /* completion function */
1.1 noro 27: typedef char* (*GF)(char*, int); /* generator function */
28: typedef int (*RLCI)(int, int); /* rl_complete and rl_insert functions */
29:
30: BEGINEXTERN
31: #ifdef HAS_RL_MESSAGE
32: # define USE_VARARGS
33: # define PREFER_STDARG
34: #endif
35: #ifdef READLINE_LIBRARY
36: # include <readline.h>
1.2 ! noro 37: # include <history.h>
1.1 noro 38: #else
39: # include <readline/readline.h>
1.2 ! noro 40: # include <readline/history.h>
1.1 noro 41: #endif
42: #ifndef HAS_RL_MESSAGE
43: extern int rl_message (const char *, ...);
44: extern int rl_clear_message();
45: extern int rl_begin_undo_group(), rl_end_undo_group();
46: extern int rl_read_key();
47: extern int rl_stuff_char();
48: extern char *filename_completion_function(char *text,int state);
49: extern char *username_completion_function(char *text,int state);
50: #endif
51: char **pari_completion(char *text, int start, int end);
52: ENDEXTERN
53:
54: void print_fun_list(char **matches, int nbli);
55: void aide(char *s, int flag);
56:
57: extern default_type gp_default_list[];
58: extern char *keyword_list[];
59: static int add_help_keywords;
60: static entree *current_ep = NULL;
61:
62: static int pari_rl_back;
63: extern RLCI rl_last_func;
64: static int do_args_complete = 1;
65: static int do_matched_insert = 0;
66: static int did_init_matched = 0;
67:
68: #ifdef HAS_RL_SAVE_PROMPT
69: # define SAVE_PROMPT() rl_save_prompt()
70: # define RESTORE_PROMPT() rl_restore_prompt()
71: #else
72: # ifdef HAS_UNDERSCORE_RL_SAVE_PROMPT
73: # define SAVE_PROMPT() _rl_save_prompt()
74: # define RESTORE_PROMPT() _rl_restore_prompt()
75: # else
76: # define SAVE_PROMPT()
77: # define RESTORE_PROMPT()
78: # endif
79: #endif
80:
81: #ifdef HAS_RL_COMPLETION_MATCHES
82: # define COMPLETION_MATCHES ((CF)rl_completion_matches)
83: # define FILE_COMPLETION ((GF)rl_filename_completion_function)
84: # define USER_COMPLETION ((GF)rl_username_completion_function)
85: #else
86: # define COMPLETION_MATCHES ((CF)completion_matches)
87: # define FILE_COMPLETION ((GF)filename_completion_function)
88: # define USER_COMPLETION ((GF)username_completion_function)
89: #endif
90:
91: #define ELECTRIC_PAREN 1
92: #define ARGS_COMPLETE 2
93: static int
94: change_state(char *msg, int *opt, int count)
95: {
96: int c;
97:
98: switch(count)
99: {
100: default: c = 0; break; /* off */
101: case -1: c = 1; break; /* on */
102: case -2: c = 1 - *opt; /* toggle */
103: }
104: *opt = c;
105: SAVE_PROMPT();
1.2 ! noro 106: rl_message("%s: %s.", msg, c? "on": "off");
1.1 noro 107: c = rl_read_key();
108: RESTORE_PROMPT();
109: rl_clear_message();
110: rl_stuff_char(c); return 1;
111: }
112:
113: /* Wrapper around rl_complete to allow toggling insertion of arguments */
114: static int
115: pari_rl_complete(int count, int key)
116: {
117: int ret;
118:
119: pari_rl_back = 0;
120: if (count <= 0)
121: return change_state("complete args", &do_args_complete, count);
122:
123: rl_begin_undo_group();
124: if (rl_last_func == pari_rl_complete)
125: rl_last_func = (RLCI) rl_complete; /* Make repeated TABs different */
126: ret = ((RLCI)rl_complete)(count,key);
127: if (pari_rl_back && (pari_rl_back <= rl_point))
128: rl_point -= pari_rl_back;
129: rl_end_undo_group(); return ret;
130: }
131:
132: static const char paropen[] = "([{";
133: static const char parclose[] = ")]}";
134:
135: /* To allow insertion of () with a point in between. */
136: static int
137: pari_rl_matched_insert(int count, int key)
138: {
139: int i = 0, ret;
140:
141: if (count <= 0)
142: return change_state("electric parens", &do_matched_insert, count);
143: while (paropen[i] && paropen[i] != key) i++;
1.2 ! noro 144: if (!paropen[i] || !do_matched_insert || GP_DATA->flags & EMACS)
1.1 noro 145: return ((RLCI)rl_insert)(count,key);
146: rl_begin_undo_group();
147: ((RLCI)rl_insert)(count,key);
148: ret = ((RLCI)rl_insert)(count,parclose[i]);
149: rl_point -= count;
150: rl_end_undo_group(); return ret;
151: }
152:
153: static int
154: pari_rl_default_matched_insert(int count, int key)
155: {
156: if (!did_init_matched) {
157: did_init_matched = 1;
158: do_matched_insert = 1;
159: }
160: return pari_rl_matched_insert(count, key);
161: }
162:
163: static int
164: pari_rl_forward_sexp(int count, int key)
165: {
166: int deep = 0, dir = 1, move_point = 0, lfail;
167:
168: (void)key;
169: if (count < 0)
170: {
171: count = -count; dir = -1;
172: if (!rl_point) goto fail;
173: rl_point--;
174: }
175: while (count || deep)
176: {
177: move_point = 1; /* Need to move point if moving left. */
178: lfail = 0; /* Do not need to fail left movement yet. */
179: while ( !is_keyword_char(rl_line_buffer[rl_point])
180: && !strchr("\"([{}])",rl_line_buffer[rl_point])
181: && !( (dir == 1)
182: ? (rl_point >= rl_end)
183: : (rl_point <= 0 && (lfail = 1))))
184: rl_point += dir;
185: if (lfail || !rl_line_buffer[rl_point]) goto fail;
186:
187: if (is_keyword_char(rl_line_buffer[rl_point]))
188: {
189: while ( is_keyword_char(rl_line_buffer[rl_point])
190: && (!((dir == 1) ? (rl_point >= rl_end) : (rl_point <= 0))
191: || (move_point = 0)))
192: rl_point += dir;
193: if (!deep) count--;
194: }
195: else if (strchr(paropen,rl_line_buffer[rl_point]))
196: {
197: if (deep == 0 && dir == -1) goto fail; /* We are already out of pars. */
198: rl_point += dir;
199: deep++; if (!deep) count--;
200: }
201: else if (strchr(parclose,rl_line_buffer[rl_point]))
202: {
203: if (deep == 0 && dir == 1)
204: {
205: rl_point++; goto fail; /* Get out of pars. */
206: }
207: rl_point += dir;
208: deep--; if (!deep) count--;
209: }
210: else if (rl_line_buffer[rl_point] == '\"')
211: {
212: int bad = 1;
213:
214: rl_point += dir;
215: while ( ((rl_line_buffer[rl_point] != '\"') || (bad = 0))
216: && (!((dir == 1) ? (rl_point >= rl_end) : (rl_point <= 0))
217: || (move_point = 0)) )
218: rl_point += dir;
219: if (bad) goto fail;
220: rl_point += dir; /* Skip the other delimiter */
221: if (!deep) count--;
222: }
223: else
224: {
225: fail: ding(); return 1;
226: }
227: }
228: if (dir != 1 && move_point) rl_point++;
229: return 1;
230: }
231:
232: static int
233: pari_rl_backward_sexp(int count, int key)
234: {
235: return pari_rl_forward_sexp(-count, key);
236: }
237:
238: /* do we add () at the end of completed word? (is it a function?) */
239: static int
240: add_paren(int end)
241: {
242: entree *ep;
243: char *s;
244:
245: if (end < 0 || rl_line_buffer[end] == '(')
246: return 0; /* not from command_generator or already there */
247: ep = do_alias(current_ep); /* current_ep set in command_generator */
248: if (EpVALENCE(ep) < EpUSER)
249: { /* is it a constant masked as a function (e.g Pi)? */
250: s = ep->help; if (!s) return 1;
251: while (is_keyword_char(*s)) s++;
252: return (*s != '=');
253: }
254: switch(EpVALENCE(ep))
255: {
256: case EpUSER:
257: case EpINSTALL: return 1;
258: }
259: return 0;
260: }
261:
262: static void
263: match_concat(char **matches, char *s)
264: {
1.2 ! noro 265: matches[0] = (char*) gprealloc(matches[0], strlen(matches[0])+strlen(s)+1);
1.1 noro 266: strcat(matches[0],s);
267: }
268:
269: static char **
270: matches_for_emacs(char *text, char **matches)
271: {
272: if (!matches) printf("@");
273: else
274: {
275: int i;
276: printf("%s@", matches[0] + strlen(text));
277: if (matches[1]) print_fun_list(matches+1,0);
278:
279: /* we don't want readline to do anything, but insert some junk
280: * which will be erased by emacs.
281: */
282: for (i=0; matches[i]; i++) free(matches[i]);
283: free(matches);
284: }
285: matches = (char **) gpmalloc(2*sizeof(char *));
286: matches[0] = gpmalloc(2); sprintf(matches[0],"_");
287: matches[1] = NULL; printf("@E_N_D"); pariflush();
288: return matches;
289: }
290:
291: #define add_comma(x) (x==-2) /* from default_generator */
292:
293: /* Attempt to complete on the contents of TEXT. END points to the end of the
294: * word to complete. Return the array of matches, or NULL if there aren't any.
295: */
296: static char **
297: get_matches(int end, char *text, char* f(char*,int))
298: {
299: char **matches;
300:
301: #ifdef HAS_COMPLETION_APPEND_CHAR
302: rl_completion_append_character = ' ';
303: #endif
304: current_ep = NULL;
1.2 ! noro 305: matches = COMPLETION_MATCHES(text, (char *(*)(void))f);
1.1 noro 306: if (matches && !matches[1]) /* a single match */
307: {
308: if (add_paren(end))
309: {
310: match_concat(matches,"()");
311: pari_rl_back = 1;
312: if (rl_point == rl_end)
313: #ifdef HAS_COMPLETION_APPEND_CHAR
314: rl_completion_append_character = '\0'; /* Do not append space. */
315: #else
316: pari_rl_back = 2;
317: #endif
318: }
319: else if (add_comma(end))
320: match_concat(matches,",");
321: }
1.2 ! noro 322: if (GP_DATA->flags & EMACS) matches = matches_for_emacs(text,matches);
1.1 noro 323: return matches;
324: }
325: #undef add_comma
326:
327: static char *
328: add_junk(char *name, char *text, long junk)
329: {
330: char *s = strncpy((char*) gpmalloc(strlen(name)+1+junk),text,junk);
331: strcpy(s+junk,name); return s;
332: }
333:
334: /* Generator function for command completion. STATE lets us know whether
335: * to start from scratch; without any state (i.e. STATE == 0), then we
336: * start at the top of the list.
337: */
338: static char *
339: hashtable_generator (char *text, int state, entree **hash)
340: {
341: static int hashpos, len, junk, n;
342: static entree* ep;
343: static char *TEXT;
344:
345: /* If this is a new word to complete, initialize now:
346: * + indexes hashpos (GP hash list) and n (keywords specific to long help).
347: * + file completion and keyword completion use different word boundaries,
348: * have TEXT point to the keyword start.
349: * + save the length of TEXT for efficiency.
350: */
351: if (!state)
352: {
353: n = hashpos = 0; ep=hash[hashpos];
354: len=strlen(text); junk=len-1;
355: while (junk >= 0 && is_keyword_char(text[junk])) junk--;
356: junk++; len -= junk; TEXT = text + junk;
357: }
358:
359: /* First check the keywords list */
360: if (add_help_keywords)
361: {
362: for ( ; keyword_list[n]; n++)
363: if (!strncmp(keyword_list[n],TEXT,len))
364: {
365: text = add_junk(keyword_list[n],text,junk);
366: n++; return text;
367: }
368: }
369:
370: /* Return the next name which partially matches from the command list. */
371: for(;;)
372: if (!ep)
373: {
374: if (++hashpos >= functions_tblsz) return NULL; /* no names matched */
375: ep = hash[hashpos];
376: }
377: else if (strncmp(ep->name,TEXT,len))
378: ep = ep->next;
379: else
380: break;
381: current_ep = ep;
382: text = add_junk(ep->name,text,junk);
383: ep=ep->next; return text;
384: }
385:
386: static char *
387: command_generator (char *text, int state)
388: {
389: return hashtable_generator(text,state, functions_hash);
390: }
391: static char *
392: member_generator (char *text, int state)
393: {
394: return hashtable_generator(text,state, members_hash);
395: }
396:
397: #define DFLT 0
398: #define ENTREE 1
399:
400: static char *
401: generator(void *list, char *text, int *nn, int len, int typ)
402: {
403: char *def = NULL, *name;
404: int n = *nn;
405:
406: /* Return the next name which partially matches from list.*/
407: switch(typ)
408: {
409: case DFLT :
410: do
411: def = (((default_type *) list)[n++]).name;
412: while (def && strncmp(def,text,len));
413: break;
414:
415: case ENTREE :
416: do
417: def = (((entree *) list)[n++]).name;
418: while (def && strncmp(def,text,len));
419: }
420:
421: *nn = n;
422: if (def)
423: {
424: name = strcpy((char*) gpmalloc(strlen(def)+1), def);
425: return name;
426: }
427: return NULL; /* no names matched */
428: }
429:
430: static char *
431: old_generator(char *text,int state)
432: {
433: static int n,len;
434: static char *res;
435:
436: if (!state) { res = "a"; n=0; len=strlen(text); }
437: if (res)
438: {
439: res = generator((void *)oldfonctions,text,&n,len,ENTREE);
440: if (res) return res;
441: n=0;
442: }
443: return generator((void *)functions_oldgp,text,&n,len,ENTREE);
444: }
445:
446: static char *
447: default_generator(char *text,int state)
448: {
449: static int n,len;
450:
451: if (!state) { n=0; len=strlen(text); }
452: return generator(gp_default_list,text,&n,len,DFLT);
453: }
454:
455: static void
456: rl_print_aide(char *s, int flag)
457: {
458: int p = rl_point, e = rl_end;
459: FILE *save = pari_outfile;
460:
461: rl_point = 0; rl_end = 0; pari_outfile = rl_outstream;
462: SAVE_PROMPT();
1.2 ! noro 463: rl_message("%s",""); /* rl_message("") ==> "zero length format" warning */
1.1 noro 464: aide(s, flag);
465: RESTORE_PROMPT();
466: rl_point = p; rl_end = e; pari_outfile = save;
467: rl_clear_message();
468: #ifdef RL_REFRESH_LINE_OLDPROTO
469: rl_refresh_line();
470: #else
471: rl_refresh_line(0,0);
472: #endif
473: }
474:
475: char **
476: pari_completion(char *text, int START, int END)
477: {
478: int i, first=0, start=START;
479:
480: /* If the line does not begin by a backslash, then it is:
481: * . an old command ( if preceded by "whatnow(" ).
482: * . a default ( if preceded by "default(" ).
483: * . a member function ( if preceded by "." within 4 letters )
484: * . a file name (in current directory) ( if preceded by "read(" )
485: * . a command
486: */
487: if (start >=1 && rl_line_buffer[start] != '~') start--;
488: while (start && is_keyword_char(rl_line_buffer[start])) start--;
489: if (rl_line_buffer[start] == '~')
490: {
491: for(i=start+1;i<=END;i++)
492: if (rl_line_buffer[i] == '/')
493: return get_matches(-1,text,FILE_COMPLETION);
494: return get_matches(-1,text,USER_COMPLETION);
495: }
496:
497: while (rl_line_buffer[first] && isspace((int)rl_line_buffer[first])) first++;
498: switch (rl_line_buffer[first])
499: {
500: case '\\':
501: if (first == start) text = rl_line_buffer+start+2;
502: return get_matches(-1,text,FILE_COMPLETION);
503: case '?':
504: if (rl_line_buffer[first+1] == '?') add_help_keywords = 1;
505: return get_matches(-1,text,command_generator);
506: }
507:
508: while (start && rl_line_buffer[start] != '('
509: && rl_line_buffer[start] != ',') start--;
510: if (rl_line_buffer[start] == '(' && start)
511: {
512: #define MAX_KEYWORD 200
513: int iend, j,k;
514: entree *ep;
515: char buf[MAX_KEYWORD];
516:
517: i = start;
518:
519: while (i && isspace((int)rl_line_buffer[i-1])) i--;
520: iend = i;
521: while (i && is_keyword_char(rl_line_buffer[i-1])) i--;
522:
523: if (iend - i == 7)
524: {
525: if (strncmp(rl_line_buffer + i,"default",7) == 0)
526: return get_matches(-2,text,default_generator);
527: if (strncmp(rl_line_buffer + i,"whatnow",7) == 0)
528: return get_matches(-1,text,old_generator);
529: }
530: if (iend - i >= 4)
531: {
532: if (strncmp(rl_line_buffer + i,"read",4) == 0)
533: return get_matches(-1,text,FILE_COMPLETION);
534: }
535:
536: j = start + 1;
537: while (j <= END && isspace((int)rl_line_buffer[j])) j++;
538: k = END;
539: while (k > j && isspace((int)rl_line_buffer[k])) k--;
1.2 ! noro 540: /* If we are in empty parens, output function help */
1.1 noro 541: if (do_args_complete && k == j
542: && (rl_line_buffer[j] == ')' || !rl_line_buffer[j])
543: && (iend - i < MAX_KEYWORD)
544: && ( strncpy(buf, rl_line_buffer + i, iend - i),
545: buf[iend - i] = 0, 1)
546: && (ep = is_entry(buf)) && ep->help)
547: {
548: rl_print_aide(buf,h_RL);
549: rl_attempted_completion_over = 1;
550: return NULL;
551: }
552: }
553: for(i=END-1;i>=start;i--)
554: if (!is_keyword_char(rl_line_buffer[i]))
555: {
556: if (rl_line_buffer[i] == '.')
557: return get_matches(-1,text,member_generator);
558: break;
559: }
560: add_help_keywords = 0;
561: return get_matches(END,text,command_generator);
562: }
563:
564: /* long help if count < 0 */
565: static int
566: rl_short_help(int count, int key)
567: {
568: int flag = (count < 0 || rl_last_func == rl_short_help)? h_RL|h_LONG: h_RL;
569: int off = rl_point;
570:
571: /* func() with cursor on ')' following completion */
572: if (off && rl_line_buffer[off-1] == '('
573: && !is_keyword_char(rl_line_buffer[off])) off--;
574:
575: while (off && is_keyword_char(rl_line_buffer[off-1])) off--;
576:
577: /* Check for \c type situation. Could check for leading whitespace too... */
578: if (off == 1 && rl_line_buffer[off-1] == '\\') off--;
579: if (off >= 8) { /* Check for default(whatever) */
580: int t = off - 1;
581:
582: while (t >= 7 && isspace((int)rl_line_buffer[t])) t--;
583: if (rl_line_buffer[t--] == '(') {
584: while (t >= 6 && isspace((int)rl_line_buffer[t])) t--;
585: t -= 6;
586: if (t >= 0
587: && strncmp(rl_line_buffer + t, "default", 7) == 0
588: && (t == 0 || !is_keyword_char(rl_line_buffer[t-1])))
589: off = t;
590: }
591: }
592: rl_print_aide(rl_line_buffer + off, flag);
593: return 0;
594: }
595:
596: static int
597: rl_long_help(int count, int key)
598: {
599: (void)count;
600: return rl_short_help(-1,key);
601: }
602:
603: void
1.2 ! noro 604: init_readline(void)
1.1 noro 605: {
606: /* Allow conditional parsing of the ~/.inputrc file. */
607: rl_readline_name = "Pari-GP";
608:
609: /* added ~, ? and , */
610: rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(?,~";
611: rl_special_prefixes = "~";
612:
613: /* custom completer */
614: #ifndef HAS_RL_COMPLETION_FUNC_T
615: # ifndef CPPFunction_defined
616: # define CPPFunction Function
617: # endif
618: # define rl_completion_func_t CPPFunction
619: #endif
620: rl_attempted_completion_function = (rl_completion_func_t*) pari_completion;
621:
622: /* we always want the whole list of completions under emacs */
1.2 ! noro 623: if (GP_DATA->flags & EMACS) rl_completion_query_items = 0x8fff;
1.1 noro 624:
625: #define Bind(a,b,c) (((void(*)(int,Function*,Keymap)) rl_bind_key_in_map)\
626: ((a), (Function*)(b), (c)))
627: #define Defun(a,b,c) (((void(*)(const char*,Function*,int)) rl_add_defun)\
628: ((a), (Function*)(b), (c)))
629:
630: Defun("short-help", rl_short_help, -1);
631: Defun("long-help", rl_long_help, -1);
632: Defun("pari-complete", pari_rl_complete, '\t');
633: Defun("pari-matched-insert", pari_rl_default_matched_insert, -1);
634: Defun("pari-forward-sexp", pari_rl_forward_sexp, -1);
635: Defun("pari-backward-sexp", pari_rl_backward_sexp, -1);
636:
637: Bind('h', rl_short_help, emacs_meta_keymap);
638: Bind('H', rl_long_help, emacs_meta_keymap);
639: Bind('h', rl_short_help, vi_movement_keymap);
640: Bind('H', rl_long_help, vi_movement_keymap);
641: # ifdef HAS_RL_GENERIC_BIND
642: #define KSbind(s,f,k) rl_generic_bind(ISFUNC, (s), (char*)(f), (k))
643:
644: KSbind("OP", rl_short_help, emacs_meta_keymap); /* f1, vt100 */
645: KSbind("[11~", rl_short_help, emacs_meta_keymap); /* f1, xterm */
646: KSbind("OP", rl_short_help, vi_movement_keymap); /* f1, vt100 */
647: KSbind("[11~", rl_short_help, vi_movement_keymap); /* f1, xterm */
648: # endif
649: Bind('(', pari_rl_matched_insert, emacs_standard_keymap);
650: Bind('[', pari_rl_matched_insert, emacs_standard_keymap);
651: Bind(6, pari_rl_forward_sexp, emacs_meta_keymap); /* M-C-f */
652: Bind(2, pari_rl_backward_sexp, emacs_meta_keymap); /* M-C-b */
653:
654: #ifdef EMACS_DOS_KEYMAP
655: Bind(';', rl_short_help, emacs_dos_keymap); /* F1 */
656: Bind('T', rl_long_help, emacs_dos_keymap); /* Shift-F1 */
657: Bind(155, pari_rl_backward_sexp, emacs_dos_keymap); /* Alt-Left */
658: Bind(157, pari_rl_forward_sexp, emacs_dos_keymap); /* Alt-Right*/
659: #endif
1.2 ! noro 660: }
! 661:
! 662: static int
! 663: history_is_new(char *s)
! 664: {
! 665: return (*s && (!history_length ||
! 666: strcmp(s, history_get(history_length)->line)));
! 667: }
! 668:
! 669: static void
! 670: gp_add_history(char *s)
! 671: {
! 672: if (history_is_new(s)) add_history(s);
! 673: }
! 674:
! 675: extern void fix_buffer(Buffer *b, long newlbuf);
! 676: extern int input_loop(filtre_t *F, input_method *IM);
! 677:
! 678: /* Read line; returns a malloc()ed string of the user input or NULL on EOF.
! 679: Increments the buffer size appropriately if needed; fix *endp if so. */
! 680: static char *
! 681: gprl_input(Buffer *b, char **endp, input_method *IM)
! 682: {
! 683: long used = *endp - b->buf;
! 684: long left = b->len - used, l;
! 685: char *s;
! 686:
! 687: if (! (s = readline(IM->prompt)) ) return NULL; /* EOF */
! 688: l = strlen(s);
! 689: if ((ulong)left < l)
! 690: {
! 691: long incr = b->len;
! 692:
! 693: if (incr < l) incr = l;
! 694: fix_buffer(b, b->len + incr);
! 695: *endp = b->buf + used;
! 696: }
! 697: gp_add_history(s); /* Makes a copy */
! 698: return s;
! 699: }
! 700:
! 701: static void
! 702: unblock_SIGINT(void)
! 703: {
! 704: #ifdef USE_SIGRELSE
! 705: sigrelse(SIGINT);
! 706: #elif USE_SIGSETMASK
! 707: sigsetmask(0);
! 708: #endif
! 709: }
! 710:
! 711: /* request one line interactively.
! 712: * Return 0: EOF
! 713: * 1: got one line from readline or infile */
! 714: int
! 715: get_line_from_readline(char *prompt, filtre_t *F)
! 716: {
! 717: const int index = history_length;
! 718: char *s;
! 719: input_method IM;
! 720:
! 721: IM.prompt = prompt;
! 722: IM.getline= &gprl_input;
! 723: IM.free = 1;
! 724: if (! input_loop(F,&IM)) { pariputs("\n"); return 0; }
! 725:
! 726: s = ((Buffer*)F->data)->buf;
! 727: if (*s)
! 728: {
! 729: if (history_length > index+1)
! 730: { /* Multi-line input. Remove incomplete lines */
! 731: int i = history_length;
! 732: while (i > index) {
! 733: HIST_ENTRY *e = remove_history(--i);
! 734: free(e->line); free(e);
! 735: }
! 736: gp_add_history(s);
! 737: }
! 738:
! 739: /* update logfile */
! 740: if (logfile) fprintf(logfile, "%s%s\n",prompt,s);
! 741: }
! 742: unblock_SIGINT(); /* bug in readline 2.0: need to unblock ^C */
! 743: return 1;
1.1 noro 744: }
745: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>