source: git/kernel/oswrapper/feread.cc @ b390e5

spielwiese
Last change on this file since b390e5 was eacca4, checked in by Hans Schoenemann <hannes@…>, 2 years ago
singularhist-> singularhistory and using_history_called
  • Property mode set to 100644
File size: 12.3 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT: input from ttys, simulating fgets
6*/
7
8#include "kernel/mod2.h"
9#include <errno.h>
10
11// ----------------------------------------
12// system settings:
13
14#undef USE_READLINE4
15
16//----------------------------------------
17#ifdef __CYGWIN__
18#define READLINE_STATIC
19#endif
20#include "omalloc/omalloc.h"
21#include "misc/options.h"
22
23#include "kernel/oswrapper/feread.h"
24
25#if defined(HAVE_DYN_RL)
26#include <unistd.h>
27#endif
28
29static char * fe_fgets_stdin_init(const char *pr,char *s, int size);
30char * (*fe_fgets_stdin)(const char *pr,char *s, int size)
31 = fe_fgets_stdin_init;
32
33extern char *iiArithGetCmd(int);
34
35/* ===================================================================*/
36/* =                   static/dymanic readline                      = */
37/* ===================================================================*/
38#if defined(HAVE_READLINE) || defined(HAVE_DYN_RL) || defined(HAVE_LIBREADLINE)
39
40#ifndef STDOUT_FILENO
41#define STDOUT_FILENO 1
42#endif
43
44/* Generator function for command completion.  STATE lets us know whether
45*   to start from scratch; without any state (i.e. STATE == 0), then we
46*   start at the top of the list.
47*/
48#include "Singular/ipid.h"
49extern "C"
50char *command_generator (char *text, int state)
51{
52  STATIC_VAR int list_index, len;
53  STATIC_VAR idhdl h;
54  const char *name;
55
56  /* If this is a new word to complete, initialize now.  This includes
57     saving the length of TEXT for efficiency, and initializing the index
58     variable to 0. */
59  if (state==0)
60  {
61    list_index = 1;
62    len = strlen (text);
63    h=basePack->idroot;
64  }
65
66  /* Return the next name which partially matches from the command list. */
67  while ((name = iiArithGetCmd(list_index))!=NULL)
68  {
69    list_index++;
70
71    if (strncmp (name, text, len) == 0)
72      return (strdup(name));
73  }
74  if (len>1)
75  {
76    while (h!=NULL)
77    {
78      name=h->id;
79      h=h->next;
80      if (strncmp (name, text, len) == 0)
81        return (strdup(name));
82    }
83  }
84  /* If no names matched, then return NULL. */
85  return ((char *)NULL);
86}
87#endif
88
89/* ===================================================================*/
90/* =                      static readline                           = */
91/* ===================================================================*/
92/* some procedure are shared with "dynamic readline" */
93#if (defined(HAVE_READLINE) || defined(HAVE_LIBREADLINE) || defined(HAVE_DYN_RL))
94#include <unistd.h>
95#include <stdio.h>
96#include <stdlib.h>
97#include <sys/types.h>
98#include <sys/file.h>
99#include <sys/stat.h>
100
101// #undef READLINE_READLINE_H_OK
102
103extern "C" {
104  VAR BOOLEAN using_history_called=FALSE;
105  typedef char * (*RL_PROC)(const char*,int);
106  #ifdef READLINE_READLINE_H_OK
107    #include <readline/readline.h>
108    #ifdef HAVE_READLINE_HISTORY_H
109      #include <readline/history.h>
110    #endif
111  #endif
112
113  #ifdef RL_VERSION_MAJOR
114    #if (RL_VERSION_MAJOR >= 4)
115      #define USE_READLINE4
116    #endif
117  #endif
118
119  #ifndef USE_READLINE4
120    #define rl_filename_completion_function filename_completion_function
121    #define rl_completion_matches           completion_matches
122  #endif
123  #ifndef READLINE_READLINE_H_OK
124    /* declare everything we need explicitely and do not rely on includes */
125    EXTERN_VAR char * rl_readline_name;
126    EXTERN_VAR char *rl_line_buffer;
127    char *rl_filename_completion_function(const char*, int);
128    typedef char **CPPFunction ();
129
130    extern char ** rl_completion_matches (const char*, RL_PROC);
131    EXTERN_VAR CPPFunction * rl_attempted_completion_function;
132    EXTERN_VAR FILE * rl_outstream;
133    extern char * readline (const char *);
134    extern void add_history (char *);
135    extern int write_history ();
136    extern void using_history();
137    extern int read_history(char *);
138    extern int history_total_bytes();
139  #endif /* READLINE_READLINE_H_OK */
140
141  typedef char * (*PROC)();
142
143  typedef char **RL_CPPFunction (const char*, int,int);
144}
145
146
147char * fe_fgets_stdin_rl(const char *pr,char *s, int size);
148
149/* Tell the GNU Readline library how to complete.  We want to try to complete
150   on command names  or on filenames if it is preceded by " */
151
152/* Attempt to complete on the contents of TEXT.  START and END show the
153*   region of TEXT that contains the word to complete.  We can use the
154*   entire line in case we want to do some simple parsing.  Return the
155*   array of matches, or NULL if there aren't any.
156*/
157#if defined(HAVE_DYN_RL)
158extern "C"
159{
160  int fe_init_dyn_rl();
161  char *(*fe_filename_completion_function)(); /* 3 */
162  char *(* fe_readline) (char *);             /* 4 */
163  VAR void (*fe_add_history) (char *);            /* 5 */
164  VAR char ** fe_rl_readline_name;                /* 6 */
165  VAR char **fe_rl_line_buffer;                   /* 7 */
166  char **(*fe_completion_matches)(...);          /* 8 */
167  VAR CPPFunction **fe_rl_attempted_completion_function; /* 9 */
168  VAR FILE ** fe_rl_outstream;                    /* 10 */
169  VAR int (*fe_write_history) ();                 /* 11 */
170  VAR int (*fe_history_total_bytes) ();           /* 12 */
171  VAR void (*fe_using_history) ();                /* 13 */
172  VAR int (*fe_read_history) (char *);            /* 14 */
173
174}
175#endif
176char ** singular_completion (char *text, int start, int end)
177{
178  /* If this word is not in a string, then it may be a command
179     to complete.  Otherwise it may be the name of a file in the current
180     directory. */
181#ifdef HAVE_DYN_RL
182  #define x_rl_line_buffer (*fe_rl_line_buffer)
183  #define x_rl_completion_matches (*fe_completion_matches)
184  #define x_rl_filename_completion_function (*fe_filename_completion_function)
185#else
186  #define x_rl_line_buffer rl_line_buffer
187  #define x_rl_completion_matches rl_completion_matches
188  #define x_rl_filename_completion_function rl_filename_completion_function
189#endif
190  if ((start>0) && (x_rl_line_buffer[start-1]=='"'))
191    return x_rl_completion_matches (text, (RL_PROC)x_rl_filename_completion_function);
192  char **m=x_rl_completion_matches (text, (RL_PROC)command_generator);
193#undef x_rl_line_buffer
194#undef x_rl_completion_matches
195  if (m==NULL)
196  {
197    m=(char **)malloc(2*sizeof(char*));
198    m[0]=(char *)malloc(end-start+2);
199    strncpy(m[0],text,end-start+1);
200    m[1]=NULL;
201  }
202  return m;
203}
204
205#ifndef HAVE_DYN_RL
206char * fe_fgets_stdin_rl(const char *pr,char *s, int size)
207{
208  if (!BVERBOSE(V_PROMPT))
209  {
210    pr="";
211  }
212  mflush();
213
214  char *line;
215  line = readline (pr);
216
217  if (line==NULL)
218    return NULL;
219
220  int l=strlen(line);
221  for (int i=l-1;i>=0;i--) line[i]=line[i]&127;
222
223  if (*line!='\0')
224  {
225    add_history (line);
226  }
227  if (l>=size-1)
228  {
229    strncpy(s,line,size);
230  }
231  else
232  {
233    strncpy(s,line,l);
234    s[l]='\n';
235    s[l+1]='\0';
236  }
237  free (line);
238
239  return s;
240}
241#endif
242#endif
243
244/* ===================================================================*/
245/* =                    emulated readline                           = */
246/* ===================================================================*/
247#if !defined(HAVE_READLINE) && defined(HAVE_FEREAD)
248extern "C" {
249char * fe_fgets_stdin_fe(const char *pr,char *s, int size);
250}
251char * fe_fgets_stdin_emu(const char *pr,char *s, int size)
252{
253  if (!BVERBOSE(V_PROMPT))
254  {
255    pr="";
256  }
257  mflush();
258  return fe_fgets_stdin_fe(pr,s,size);
259}
260#endif
261
262/* ===================================================================*/
263/* =                     dynamic readline                           = */
264/* ===================================================================*/
265/* some procedure are shared with "static readline" */
266#if defined(HAVE_DYN_RL)
267char * fe_fgets_stdin_drl(const char *pr,char *s, int size)
268{
269  if (!BVERBOSE(V_PROMPT))
270  {
271    pr="";
272  }
273  mflush();
274
275  char *line;
276  line = (*fe_readline) ((char*)pr);
277
278  if (line==NULL)
279    return NULL;
280
281  int l=strlen(line);
282  for (int i=l-1;i>=0;i--) line[i]=line[i]&127;
283
284  if (*line!='\0')
285  {
286    (*fe_add_history) (line);
287  }
288  if (l>=size-1)
289  {
290    strncpy(s,line,size);
291  }
292  else
293  {
294    strncpy(s,line,l);
295    s[l]='\n';
296    s[l+1]='\0';
297  }
298  free (line);
299
300  return s;
301}
302#endif
303
304/* ===================================================================*/
305/* =                        fgets                                   = */
306/* ===================================================================*/
307char * fe_fgets(const char *pr,char *s, int size)
308{
309  if (BVERBOSE(V_PROMPT))
310  {
311    fputs(pr,stdout);
312  }
313  mflush();
314  errno=0;
315  char *line=fgets(s,size,stdin);
316  if (line!=NULL)
317  {
318    for (int i=strlen(line)-1;i>=0;i--) line[i]=line[i]&127;
319  }
320  else
321  {
322    /* NULL can mean various things... */
323    switch(errno)
324    {
325      case 0:     return NULL;           /*EOF */
326      case EBADF: return NULL;           /* stdin got closed */
327      case EINTR: return strcpy(s,"\n"); /* CTRL-C or other signal */
328      default:                           /* other error */
329      {
330        int errsv = errno;
331        fprintf(stderr,"fgets() failed with errno %d\n%s\n",errsv,strerror(errsv));
332        return NULL;
333      }
334    }
335  }
336  return line;
337}
338
339/* ===================================================================*/
340/* =       init for static rl, dyn. rl, emu. rl                     = */
341/* ===================================================================*/
342static char * fe_fgets_stdin_init(const char *pr,char *s, int size)
343{
344#if (defined(HAVE_READLINE) || defined(HAVE_LIBREADLINE)) && !defined(HAVE_DYN_RL) && !defined(HAVE_FEREAD)
345  /* Allow conditional parsing of the ~/.inputrc file. */
346  rl_readline_name = (char*)"Singular";
347  /* Tell the completer that we want a crack first. */
348#ifdef USE_READLINE4
349  rl_attempted_completion_function = (rl_completion_func_t *)singular_completion;
350#else
351  rl_attempted_completion_function = (CPPFunction *)singular_completion;
352#endif
353
354  /* set the output stream */
355  if(!isatty(STDOUT_FILENO))
356  {
357    #ifdef atarist
358      rl_outstream = fopen( "/dev/tty", "w" );
359    #else
360      char *fn=ttyname(fileno(stdin));//if stdout is not a tty, maybe stdin is?
361      if (fn!=NULL) rl_outstream = fopen( fn, "w" );
362    #endif
363  }
364
365  using_history_called=FALSE;
366  if(isatty(fileno(stdin)))
367  {
368    /* try to read a history */
369    using_history_called=TRUE;
370    using_history();
371    char *p = getenv("SINGULARHIST");
372    if (p==NULL) p=SINGULARHIST_FILE;
373    if (strlen(p) != 0)
374    {
375      read_history (p);
376    }
377    fe_fgets_stdin=fe_fgets_stdin_rl;
378    return(fe_fgets_stdin_rl(pr,s,size));
379  }
380  else
381  {
382    fe_fgets_stdin=fe_fgets;
383    return(fe_fgets(pr,s,size));
384  }
385#endif
386#ifdef HAVE_DYN_RL
387  /* do dynamic loading */
388  int res=fe_init_dyn_rl();
389  using_history_called=FALSE;
390  if (res!=0)
391  {
392    //if (res==1)
393    //  WarnS("dynamic loading of libreadline failed");
394    //else
395    //  Warn("dynamic loading failed: %d\n",res);
396    if (res!=1)
397      Warn("dynamic loading failed: %d\n",res);
398    #ifdef HAVE_FEREAD
399    fe_fgets_stdin=fe_fgets_stdin_emu;
400    #else
401    fe_fgets_stdin=fe_fgets;
402    #endif
403    return fe_fgets_stdin(pr,s,size);
404  }
405  else if (isatty(STDIN_FILENO))/*and could load libreadline: */
406  {
407    /* Allow conditional parsing of the ~/.inputrc file. */
408    *fe_rl_readline_name = "Singular";
409    /* Tell the completer that we want a crack first. */
410    *fe_rl_attempted_completion_function = (CPPFunction *)singular_completion;
411    /* try to read a history */
412    (*fe_using_history)();
413    using_history_called=TRUE;
414    char *p = getenv("SINGULARHIST");
415    if (p != NULL)
416    {
417      (*fe_read_history) (p);
418    }
419
420    /* set the output stream */
421    if(!isatty(STDOUT_FILENO))
422    {
423      #ifdef atarist
424        *fe_rl_outstream = fopen( "/dev/tty", "w" );
425      #else
426        char *fn=ttyname(fileno(stdin));//if stdout is not a tty, maybe stdin is?
427        if (fn!=NULL) *fe_rl_outstream = fopen( fn, "w" );
428      #endif
429    }
430    fe_fgets_stdin=fe_fgets_stdin_drl;
431    return fe_fgets_stdin_drl(pr,s,size);
432  }
433  else
434  {
435    fe_fgets_stdin=fe_fgets;
436    return fe_fgets(pr,s,size);
437  }
438#else
439  #if !defined(HAVE_READLINE) && defined(HAVE_FEREAD)
440    fe_fgets_stdin=fe_fgets_stdin_emu;
441    return(fe_fgets_stdin_emu(pr,s,size));
442  #else
443    fe_fgets_stdin=fe_fgets;
444    return(fe_fgets(pr,s,size));
445  #endif
446#endif
447}
448
449/* ===================================================================*/
450/* =                      batch mode                                = */
451/* ===================================================================*/
452/* dummy (for batch mode): */
453char * fe_fgets_dummy(const char */*pr*/,char */*s*/, int /*size*/)
454{
455  return NULL;
456}
457
Note: See TracBrowser for help on using the repository browser.