source: git/Singular/fevoices.cc @ a9fbf7

spielwiese
Last change on this file since a9fbf7 was a9fbf7, checked in by Erik M. Bray <erik.bray@…>, 7 years ago
Don't try to re-init stdin if we just finished reading from a (non-TTY) stdin Without this, stdin gets closed, but is still set to the currentVoice, leading to instability
  • Property mode set to 100644
File size: 16.2 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT: i/o system
6*/
7#include <kernel/mod2.h>
8
9/* I need myfread in standalone_parser */
10#ifndef STANDALONE_PARSER
11
12#include <omalloc/omalloc.h>
13#include <misc/options.h>
14#include <reporter/reporter.h>
15#include <kernel/oswrapper/feread.h>
16#include <Singular/fevoices.h>
17#include <Singular/subexpr.h>
18#include <Singular/ipshell.h>
19#include <Singular/sdb.h>
20
21#include <stdlib.h>
22#include <stdio.h>
23#include <misc/mylimits.h>
24#include <stdarg.h>
25#include <sys/stat.h>
26#include <ctype.h>
27#include <unistd.h>
28
29#ifdef HAVE_PWD_H
30#include <pwd.h>
31#endif
32
33#define fePutChar(c) fputc((unsigned char)(c),stdout)
34/*0 implementation */
35
36
37char fe_promptstr[] ="  ";
38FILE *File_Profiling=NULL;
39
40// output/print buffer:
41#define INITIAL_PRINT_BUFFER 24*1024L
42// line buffer for reading:
43// minimal value for MAX_FILE_BUFFER: 4*4096 - see Tst/Long/gcd0_l.tst
44// this is an upper limit for the size of monomials/numbers read via the interpreter
45#define MAX_FILE_BUFFER 4*4096
46// static long feBufferLength=INITIAL_PRINT_BUFFER;
47//static char * feBuffer=(char *)omAlloc(INITIAL_PRINT_BUFFER);
48
49/**************************************************************************
50* handling of 'voices'
51**************************************************************************/
52
53extern int blocknest; /* scaner.l internal */
54
55int    yy_noeof=0;     // the scanner "state"
56int    yy_blocklineno; // to get the lineno of the block start from scanner
57Voice  *currentVoice = NULL;
58// FILE   *feFilePending; /*temp. storage for grammar.y */
59
60//static const char * BT_name[]={"BT_none","BT_break","BT_proc","BT_example",
61//                               "BT_file","BT_execute","BT_if","BT_else"};
62/*2
63* the name of the current 'Voice': the procname (or filename)
64*/
65const char sNoName_fe[]="_";
66const char * VoiceName()
67{
68  if ((currentVoice!=NULL)
69  && (currentVoice->filename!=NULL))
70    return currentVoice->filename;
71  return sNoName_fe;
72}
73
74/*2
75* the calling chain of Voices
76*/
77void VoiceBackTrack()
78{
79  Voice *p=currentVoice;
80  while (p->prev!=NULL)
81  {
82    p=p->prev;
83    char *s=p->filename;
84    if (s==NULL)
85      PrintS("-- called from ? --\n");
86    else
87      Print("-- called from %s --\n",s);
88  }
89}
90
91/*2
92* init a new voice similar to the current
93*/
94void Voice::Next()
95{
96  Voice *p=new Voice;
97  // OB: ???
98  // Hmm... when Singular is used as batch file
99  // then this voice is never freed
100  omMarkAsStaticAddr(p);
101  if (currentVoice != NULL)
102  {
103    currentVoice->curr_lineno=yylineno;
104    currentVoice->next=p;
105  }
106  p->prev=currentVoice;
107  currentVoice=p;
108  //PrintS("Next:");
109}
110
111feBufferTypes Voice::Typ()
112{
113  switch(typ)
114  {
115    case BT_proc:
116    case BT_example:
117    case BT_file:
118      return typ;
119    default:
120      if (prev==NULL) return (feBufferTypes)0;
121      return prev->Typ();
122  }
123}
124
125/*2
126* start the file 'fname' (STDIN is stdin) as a new voice (cf.VFile)
127* return FALSE on success, TRUE if an error occurs (file cannot be opened)
128*/
129BOOLEAN newFile(char *fname,FILE* f)
130{
131  currentVoice->Next();
132  //Print(":File%d(%s):%s(%x)\n",
133  //  currentVoice->typ,BT_name[currentVoice->typ],fname,currentVoice);
134  currentVoice->filename   = omStrDup(fname);
135  omMarkAsStaticAddr(currentVoice->filename);
136  if (strcmp(fname,"STDIN") == 0)
137  {
138    currentVoice->files = stdin;
139    currentVoice->sw = BI_stdin;
140    currentVoice->start_lineno = 1;
141  }
142  else
143  {
144    currentVoice->sw = BI_file; /* needed by exitVoice below */
145    if (f!=NULL)
146      currentVoice->files = f;
147    else
148    {
149      currentVoice->files = feFopen(fname,"r",NULL,TRUE);
150      if (currentVoice->files==NULL)
151      {
152        exitVoice();
153        return TRUE;
154      }
155    }
156    currentVoice->start_lineno = 0;
157  }
158  yylineno=currentVoice->start_lineno;
159  //Voice *p=currentVoice;
160  //PrintS("-----------------\ncurr:");
161  //do
162  //{
163  //Print("voice fn:%s\n",p->filename);
164  //p=p->prev;
165  //}
166  //while (p!=NULL);
167  //PrintS("----------------\n");
168  return FALSE;
169}
170
171void newBuffer(char* s, feBufferTypes t, procinfo* pi, int lineno)
172{
173  currentVoice->Next();
174  //Print(":Buffer%d(%s):%s(%x)\n",
175  //  t,BT_name[t],pname,currentVoice);
176  if (pi!=NULL)
177  {
178    long l=strlen(pi->procname);
179    if (pi->libname!=NULL) l+=strlen(pi->libname);
180    currentVoice->filename = (char *)omAlloc(l+3);
181    *currentVoice->filename='\0';
182    if (pi->libname!=NULL) strcat(currentVoice->filename,pi->libname);
183    strcat(currentVoice->filename,"::");
184    strcat(currentVoice->filename,pi->procname);
185    currentVoice->pi       = pi;
186  }
187  else
188  {
189    if(currentVoice->prev!=NULL)
190    {
191      currentVoice->filename = omStrDup(currentVoice->prev->filename);
192      currentVoice->pi       = currentVoice->prev->pi;
193    }
194    else
195    {
196      currentVoice->filename = omStrDup("");
197      currentVoice->pi       = pi;
198    }
199  }
200  currentVoice->buffer   = s;
201  currentVoice->sw       = BI_buffer;
202  currentVoice->typ      = t;
203  switch (t)
204  {
205    case BT_execute:
206                     yylineno-=2;
207                     break;
208    case BT_proc:
209    case BT_example:
210                     currentVoice->oldb=myynewbuffer();
211                     yylineno = lineno+1;
212                     break;
213    case BT_if:
214    case BT_else:
215    case BT_break:
216                     yylineno = yy_blocklineno-1;
217                     break;
218    //case BT_file:
219    default:
220                     yylineno = 1;
221                     break;
222  }
223  //Print("start body (%s) at line %d\n",BT_name[t],yylineno);
224  currentVoice->start_lineno = yylineno;
225  //printf("start buffer typ %d\n",t);
226  //Voice *p=currentVoice;
227  //PrintS("-----------------\ncurr:");
228  //do
229  //{
230  //Print("voice fn:%s\n",p->filename);
231  //p=p->prev;
232  //}
233  //while (p!=NULL);
234  //PrintS("----------------\n");
235}
236
237/*2
238* exit Buffer of type 'typ':
239* returns 1 if buffer type could not be found
240*/
241BOOLEAN exitBuffer(feBufferTypes typ)
242{
243  //printf("exitBuffer: %d(%s),(%x)\n",
244  //  typ,BT_name[typ], currentVoice);
245  //Voice *p=currentVoice;
246  //PrintS("-----------------\ncurr:");
247  //do
248  //{
249  //Print("voice fn:%s\n",p->filename);
250  //p=p->prev;
251  //}
252  //while (p!=NULL);
253  //PrintS("----------------\n");
254  if (typ == BT_break)  // valid inside for, while. may skip if, else
255  {
256    /*4 first check for valid buffer type, skip if/else*/
257    Voice *p=currentVoice;
258    loop
259    {
260      if ((p->typ != BT_if)
261      &&(p->typ != BT_else))
262      {
263        if (p->typ == BT_break /*typ*/)
264        {
265          while (p != currentVoice)
266          {
267            exitVoice();
268          }
269          exitVoice();
270          return FALSE;
271        }
272        else return TRUE;
273      }
274      if (p->prev==NULL) break;
275      p=p->prev;
276    }
277    /*4 break not inside a for/while: return an error*/
278    if (/*typ*/ BT_break != currentVoice->typ) return 1;
279    return exitVoice();
280  }
281
282  if ((typ == BT_proc)
283  || (typ == BT_example))
284  {
285    Voice *p=currentVoice;
286    loop
287    {
288      if ((p->typ == BT_proc)
289      || (p->typ == BT_example))
290      {
291        while (p != currentVoice)
292        {
293          exitVoice();
294        }
295        exitVoice();
296        return FALSE;
297      }
298      if (p->prev==NULL) break;
299      p=p->prev;
300    }
301  }
302  /*4 return not inside a proc: return an error*/
303  return TRUE;
304}
305
306/*2
307* jump to the beginning of a buffer
308*/
309BOOLEAN contBuffer(feBufferTypes typ)
310{
311  //printf("contBuffer: %d(%s),(%x)\n",
312  //  typ,BT_name[typ], currentVoice);
313  if (typ == BT_break)  // valid inside for, while. may skip if, else
314  {
315    // first check for valid buffer type
316    Voice *p=currentVoice;
317    loop
318    {
319      if ((p->typ != BT_if)
320        &&(p->typ != BT_else))
321      {
322        if (p->typ == BT_break /*typ*/)
323        {
324          while (p != currentVoice)
325          {
326            exitVoice();
327          }
328          yylineno = currentVoice->start_lineno;
329          currentVoice->fptr=0;
330          return FALSE;
331        }
332        else return TRUE;
333      }
334      if (p->prev==NULL) break;
335      p=p->prev;
336    }
337  }
338  return TRUE;
339}
340
341/*2
342* leave a voice: kill local variables
343* setup everything from the previous level
344* return 1 if leaving the top level, 0 otherwise
345*/
346BOOLEAN exitVoice()
347{
348  //printf("exitVoice: %d(%s),(%x)\n",
349  //  currentVoice->typ,BT_name[currentVoice->typ], currentVoice);
350  //{
351  //Voice *p=currentVoice;
352  //PrintS("-----------------\ncurr:");
353  //do
354  //{
355  //Print("voice fn:%s\n",p->filename);
356  //p=p->prev;
357  //}
358  //while (p!=NULL);
359  //PrintS("----------------\n");
360  //}
361  if (currentVoice!=NULL)
362  {
363    if (currentVoice->oldb!=NULL)
364    {
365      myyoldbuffer(currentVoice->oldb);
366      currentVoice->oldb=NULL;
367    }
368    if (currentVoice->filename!=NULL)
369    {
370      omFree((ADDRESS)currentVoice->filename);
371      currentVoice->filename=NULL;
372    }
373    if (currentVoice->buffer!=NULL)
374    {
375      omFree((ADDRESS)currentVoice->buffer);
376      currentVoice->buffer=NULL;
377    }
378    if ((currentVoice->prev==NULL)
379    &&(currentVoice->sw==BI_file)
380    &&(currentVoice->files!=stdin))
381    {
382      currentVoice->prev=feInitStdin(currentVoice);
383    }
384    if (currentVoice->prev!=NULL)
385    {
386      //printf("exitVoice typ %d(%s)\n",
387      //  currentVoice->typ,BT_name[currentVoice->typ]);
388      if (currentVoice->typ==BT_if)
389      {
390        currentVoice->prev->ifsw=2;
391      }
392      else
393      {
394        currentVoice->prev->ifsw=0;
395      }
396      if ((currentVoice->sw == BI_file)
397      && (currentVoice->files!=NULL))
398      {
399        fclose(currentVoice->files);
400      }
401      yylineno=currentVoice->prev->curr_lineno;
402      currentVoice->prev->next=NULL;
403    }
404    Voice *p=currentVoice->prev;
405    delete currentVoice;
406    currentVoice=p;
407  }
408  return currentVoice==NULL;
409}
410
411/*2
412* set prompt_char
413* only called with currentVoice->sw == BI_stdin
414*/
415static void feShowPrompt(void)
416{
417  fe_promptstr[0]=prompt_char;
418}
419
420/*2
421* print echo (si_echo or TRACE), set my_yylinebuf
422*/
423static int fePrintEcho(char *anf, char */*b*/)
424{
425  char *ss=strrchr(anf,'\n');
426  int len_s;
427  if (ss==NULL)
428  {
429    len_s=strlen(anf);
430  }
431  else
432  {
433    len_s=ss-anf+1;
434  }
435  // my_yylinebuf:
436  int mrc=si_min(len_s,79)-1;
437  strcpy(my_yylinebuf,anf+(len_s-1)-mrc);
438  if (my_yylinebuf[mrc] == '\n') my_yylinebuf[mrc] = '\0';
439  mrc--;
440  // handle echo:
441  if (((si_echo>myynest)
442    && ((currentVoice->typ==BT_proc)
443      || (currentVoice->typ==BT_example)
444      || (currentVoice->typ==BT_file)
445      || (currentVoice->typ==BT_none)
446    )
447    && (strncmp(anf,";return();",10)!=0)
448   )
449  || (traceit&TRACE_SHOW_LINE)
450  || (traceit&TRACE_SHOW_LINE1))
451  {
452    if (currentVoice->typ!=BT_example)
453    {
454      if (currentVoice->filename==NULL)
455        Print("(none) %3d%c ",yylineno,prompt_char);
456      else
457        Print("%s %3d%c ",currentVoice->filename,yylineno,prompt_char);
458     }
459    {
460      fwrite(anf,1,len_s,stdout);
461      mflush();
462    }
463    if (traceit&TRACE_SHOW_LINE)
464    {
465      while(fgetc(stdin)!='\n');
466    }
467  }
468  else if (traceit&TRACE_SHOW_LINENO)
469  {
470    Print("{%d}",yylineno);
471    mflush();
472  }
473  else if (traceit&TRACE_PROFILING)
474  {
475    if (File_Profiling==NULL)
476      File_Profiling=fopen("smon.out","a");
477    if (File_Profiling==NULL)
478      traceit &= (~TRACE_PROFILING);
479    else
480    {
481      if (currentVoice->filename==NULL)
482        fprintf(File_Profiling,"(none) %d\n",yylineno);
483      else
484        fprintf(File_Profiling,"%s %d\n",currentVoice->filename,yylineno);
485    }
486  }
487#ifdef HAVE_SDB
488  if ((blocknest==0)
489  && (currentVoice->pi!=NULL)
490  && (currentVoice->pi->trace_flag!=0))
491  {
492    sdb(currentVoice, anf, len_s);
493  }
494#endif
495  prompt_char = '.';
496  return len_s;
497}
498
499int feReadLine(char* b, int l)
500{
501  char *s=NULL;
502  int offset = 0; /* will not be used if s==NULL*/
503  // try to read from the buffer into b, max l chars
504  if (currentVoice!=NULL)
505  {
506    if((currentVoice->buffer!=NULL)
507    && (currentVoice->buffer[currentVoice->fptr]!='\0'))
508    {
509  NewBuff:
510      register int i=0;
511      long startfptr=currentVoice->fptr;
512      long tmp_ptr=currentVoice->fptr;
513      l--;
514      loop
515      {
516        register char c=
517        b[i]=currentVoice->buffer[tmp_ptr/*currentVoice->fptr*/];
518        i++;
519        if (yy_noeof==noeof_block)
520        {
521          if (c<' ')  yylineno++;
522          else if (c=='}') break;
523        }
524        else
525        {
526          if ((c<' ') ||
527          (c==';') ||
528          (c==')')
529          )
530            break;
531        }
532        if (i>=l) break;
533        tmp_ptr++;/*currentVoice->fptr++;*/
534        if(currentVoice->buffer[tmp_ptr/*currentVoice->fptr*/]=='\0') break;
535      }
536      currentVoice->fptr=tmp_ptr;
537      b[i]='\0';
538      if (currentVoice->sw==BI_buffer)
539      {
540        if (startfptr==0)
541        {
542          char *anf=currentVoice->buffer;
543          const char *ss=strchr(anf,'\n');
544          long len;
545          if (ss==NULL) len=strlen(anf);
546          else          len=ss-anf;
547          char *s=(char *)omAlloc(len+2);
548          strncpy(s,anf,len+2);
549          s[len+1]='\0';
550          fePrintEcho(s,b);
551          omFree((ADDRESS)s);
552        }
553        else if (/*(startfptr>0) &&*/
554        (currentVoice->buffer[startfptr-1]=='\n'))
555        {
556          char *anf=currentVoice->buffer+startfptr;
557          const char *ss=strchr(anf,'\n');
558          long len;
559          if (ss==NULL) len=strlen(anf);
560          else          len=ss-anf;
561          char *s=(char *)omAlloc(len+2);
562          strncpy(s,anf,len+2);
563          s[len+1]='\0';
564          yylineno++;
565          fePrintEcho(s,b);
566          omFree((ADDRESS)s);
567        }
568      }
569      currentVoice->fptr++;
570      return i;
571    }
572    // no buffer there or e-o-buffer or eoln:
573    if (currentVoice->sw!=BI_buffer)
574    {
575      currentVoice->fptr=0;
576      if (currentVoice->buffer==NULL)
577      {
578        currentVoice->buffer=(char *)omAlloc(MAX_FILE_BUFFER-sizeof(ADDRESS));
579        omMarkAsStaticAddr(currentVoice->buffer);
580      }
581    }
582    offset=0;
583  NewRead:
584    yylineno++;
585    if (currentVoice->sw==BI_stdin)
586    {
587      feShowPrompt();
588      s=fe_fgets_stdin(fe_promptstr,
589                       &(currentVoice->buffer[offset]),
590                       omSizeOfAddr(currentVoice->buffer)-1-offset);
591      //int i=0;
592      //if (s!=NULL)
593      //  while((s[i]!='\0') /*&& (i<MAX_FILE_BUFFER)*/) {s[i] &= (char)127;i++;}
594    }
595    else if (currentVoice->sw==BI_file)
596    {
597      fseek(currentVoice->files,currentVoice->ftellptr,SEEK_SET);
598      s=fgets(currentVoice->buffer+offset,(MAX_FILE_BUFFER-1-sizeof(ADDRESS))-offset,
599              currentVoice->files);
600      if (s!=NULL)
601      {
602        currentVoice->ftellptr=ftell(currentVoice->files);
603        // ftell returns -1 for non-seekable streams, such as pipes
604        if (currentVoice->ftellptr<0)
605          currentVoice->ftellptr=0;
606      }
607    }
608    //else /* BI_buffer */ s==NULL  => return 0
609    // done by the default return
610  }
611  if (s!=NULL)
612  {
613    // handle prot:
614    if (feProt&SI_PROT_I)
615    {
616      fputs(s,feProtFile);
617    }
618    int rc=fePrintEcho(s,b)+1;
619    //s[strlen(s)+1]='\0'; add an second \0 at the end of the string
620    s[rc]='\0';
621    // handel \\ :
622    rc-=3;
623    if ((s[rc]=='\\')&&(currentVoice->sw!=BI_buffer))
624    {
625      s[rc]='\0';
626      offset+=rc;
627      if (offset<(int)omSizeOfAddr(currentVoice->buffer)) goto NewRead;
628    }
629    goto NewBuff;
630  }
631  /* else if (s==NULL) */
632  {
633    const char *err;
634    switch(yy_noeof)
635    {
636      case noeof_brace:
637      case noeof_block:
638        err="{...}";
639        break;
640      case noeof_asstring:
641        err="till `.`";
642        break;
643      case noeof_string:
644        err="string";
645        break;
646      case noeof_bracket:
647        err="(...)";
648        break;
649      case noeof_procname:
650        err="proc";
651        break;
652      case noeof_comment:
653        err="/*...*/";
654        break;
655      default:
656        return 0;
657    }
658    Werror("premature end of file while reading %s",err);
659    return 0;
660  }
661}
662
663/*2
664* init all data structures
665*/
666#ifndef STDIN_FILENO
667#define STDIN_FILENO 0
668#endif
669Voice * feInitStdin(Voice *pp)
670{
671  Voice *p = new Voice;
672  p->files = stdin;
673  p->sw = (isatty(STDIN_FILENO)) ? BI_stdin : BI_file;
674  if ((pp!=NULL) && (pp->sw==BI_stdin) && (pp->files==stdin))
675  {
676    p->files=freopen("/dev/tty","r",stdin);
677    //stdin=p->files;
678    if (p->files==NULL)
679    {
680      p->files = stdin;
681      p->sw = BI_file;
682    }
683    else
684      p->sw = BI_stdin;
685  }
686  p->filename   = omStrDup("STDIN");
687  p->start_lineno   = 1;
688  omMarkAsStaticAddr(p);
689  omMarkAsStaticAddr(p->filename);
690  return p;
691}
692
693
694#else /* ! STANDALONE_PARSER */
695#include <stdio.h>
696
697#endif
698
Note: See TracBrowser for help on using the repository browser.