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

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