source: git/kernel/oswrapper/feread.cc @ 8dc39a

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