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 #include "omalloc/omalloc.h"
12 #include "misc/options.h"
13 #include "reporter/reporter.h"
14 #include "kernel/oswrapper/feread.h"
15 #include "Singular/fevoices.h"
16 #include "Singular/subexpr.h"
17 #include "Singular/ipshell.h"
18 #include "Singular/sdb.h"
19
20 #include "misc/mylimits.h"
21 #include <unistd.h>
22
23 #ifdef HAVE_PWD_H
24 #include <pwd.h>
25 #endif
26
27 #define fePutChar(c) fputc((unsigned char)(c),stdout)
28 /*0 implementation */
29
30
31 VAR char fe_promptstr[] =" ";
32 VAR FILE *File_Profiling=NULL;
33
34 // line buffer for reading:
35 // minimal value for MAX_FILE_BUFFER: 4*4096 - see Tst/Long/gcd0_l.tst
36 // this is an upper limit for the size of monomials/numbers read via the interpreter
37 #define MAX_FILE_BUFFER 4*4096
38
39 /**************************************************************************
40 * handling of 'voices'
41 **************************************************************************/
42
43 EXTERN_VAR int blocknest; /* scaner.l internal */
44
45 VAR int yy_noeof=0; // the scanner "state"
46 VAR int yy_blocklineno; // to get the lineno of the block start from scanner
47 VAR Voice *currentVoice = NULL;
48 // FILE *feFilePending; /*temp. storage for grammar.y */
49
50 //static const char * BT_name[]={"BT_none","BT_break","BT_proc","BT_example",
51 // "BT_file","BT_execute","BT_if","BT_else"};
52 /*2
53 * the name of the current 'Voice': the procname (or filename)
54 */
55 const char sNoName_fe[]="_";
VoiceName()56 const char * VoiceName()
57 {
58 if ((currentVoice!=NULL)
59 && (currentVoice->filename!=NULL))
60 return currentVoice->filename;
61 return sNoName_fe;
62 }
63
VoiceLine()64 int VoiceLine()
65 {
66 if ((currentVoice!=NULL)
67 && (currentVoice->curr_lineno>=0))
68 return currentVoice->curr_lineno;
69 return -1;
70 }
71
72 /*2
73 * the calling chain of Voices
74 */
VoiceBackTrack()75 void VoiceBackTrack()
76 {
77 Voice *p=currentVoice;
78 while (p->prev!=NULL)
79 {
80 p=p->prev;
81 char *s=p->filename;
82 if (s==NULL)
83 PrintS("-- called from ? --\n");
84 else
85 Print("-- called from %s --\n",s);
86 }
87 }
88
89 /*2
90 * init a new voice similar to the current
91 */
Next()92 void Voice::Next()
93 {
94 Voice *p=new Voice;
95 // OB: ???
96 // Hmm... when Singular is used as batch file
97 // then this voice is never freed
98 omMarkAsStaticAddr(p);
99 if (currentVoice != NULL)
100 {
101 currentVoice->curr_lineno=yylineno;
102 currentVoice->next=p;
103 }
104 p->prev=currentVoice;
105 currentVoice=p;
106 //PrintS("Next:");
107 }
108
Typ()109 feBufferTypes Voice::Typ()
110 {
111 switch(typ)
112 {
113 case BT_proc:
114 case BT_example:
115 case BT_file:
116 return typ;
117 default:
118 if (prev==NULL) return (feBufferTypes)0;
119 return prev->Typ();
120 }
121 }
122
123 /*2
124 * start the file 'fname' (STDIN is stdin) as a new voice (cf.VFile)
125 * return FALSE on success, TRUE if an error occurs (file cannot be opened)
126 */
newFile(char * fname)127 BOOLEAN newFile(char *fname)
128 {
129 currentVoice->Next();
130 //Print(":File%d(%s):%s(%x)\n",
131 // currentVoice->typ,BT_name[currentVoice->typ],fname,currentVoice);
132 currentVoice->filename = omStrDup(fname);
133 omMarkAsStaticAddr(currentVoice->filename);
134 if (strcmp(fname,"STDIN") == 0)
135 {
136 currentVoice->files = stdin;
137 currentVoice->sw = BI_stdin;
138 currentVoice->start_lineno = 1;
139 }
140 else
141 {
142 currentVoice->sw = BI_file; /* needed by exitVoice below */
143 currentVoice->files = feFopen(fname,"r",NULL,TRUE);
144 if (currentVoice->files==NULL)
145 {
146 exitVoice();
147 return TRUE;
148 }
149 currentVoice->start_lineno = 0;
150 }
151 yylineno=currentVoice->start_lineno;
152 //Voice *p=currentVoice;
153 //PrintS("-----------------\ncurr:");
154 //do
155 //{
156 //Print("voice fn:%s\n",p->filename);
157 //p=p->prev;
158 //}
159 //while (p!=NULL);
160 //PrintS("----------------\n");
161 return FALSE;
162 }
163
newBuffer(char * s,feBufferTypes t,procinfo * pi,int lineno)164 void newBuffer(char* s, feBufferTypes t, procinfo* pi, int lineno)
165 {
166 currentVoice->Next();
167 //Print(":Buffer%d(%s):%s(%x)\n",
168 // t,BT_name[t],pname,currentVoice);
169 if (pi!=NULL)
170 {
171 long l=strlen(pi->procname);
172 if (pi->libname!=NULL) l+=strlen(pi->libname);
173 currentVoice->filename = (char *)omAlloc(l+3);
174 *currentVoice->filename='\0';
175 if (pi->libname!=NULL) strcat(currentVoice->filename,pi->libname);
176 strcat(currentVoice->filename,"::");
177 strcat(currentVoice->filename,pi->procname);
178 currentVoice->pi = pi;
179 }
180 else
181 {
182 if(currentVoice->prev!=NULL)
183 {
184 currentVoice->filename = omStrDup(currentVoice->prev->filename);
185 currentVoice->pi = currentVoice->prev->pi;
186 }
187 else
188 {
189 currentVoice->filename = omStrDup("");
190 currentVoice->pi = pi;
191 }
192 }
193 currentVoice->buffer = s;
194 currentVoice->sw = BI_buffer;
195 currentVoice->typ = t;
196 switch (t)
197 {
198 case BT_execute:
199 yylineno-=2;
200 break;
201 case BT_proc:
202 case BT_example:
203 currentVoice->oldb=myynewbuffer();
204 yylineno = lineno+1;
205 break;
206 case BT_if:
207 case BT_else:
208 case BT_break:
209 yylineno = yy_blocklineno-1;
210 break;
211 //case BT_file:
212 default:
213 yylineno = 1;
214 break;
215 }
216 //Print("start body (%s) at line %d\n",BT_name[t],yylineno);
217 currentVoice->start_lineno = yylineno;
218 //printf("start buffer typ %d\n",t);
219 //Voice *p=currentVoice;
220 //PrintS("-----------------\ncurr:");
221 //do
222 //{
223 //Print("voice fn:%s\n",p->filename);
224 //p=p->prev;
225 //}
226 //while (p!=NULL);
227 //PrintS("----------------\n");
228 }
229
230 /*2
231 * exit Buffer of type 'typ':
232 * returns 1 if buffer type could not be found
233 */
exitBuffer(feBufferTypes typ)234 BOOLEAN exitBuffer(feBufferTypes typ)
235 {
236 //printf("exitBuffer: %d(%s),(%x)\n",
237 // typ,BT_name[typ], currentVoice);
238 //Voice *p=currentVoice;
239 //PrintS("-----------------\ncurr:");
240 //do
241 //{
242 //Print("voice fn:%s\n",p->filename);
243 //p=p->prev;
244 //}
245 //while (p!=NULL);
246 //PrintS("----------------\n");
247 if (typ == BT_break) // valid inside for, while. may skip if, else
248 {
249 /*4 first check for valid buffer type, skip if/else*/
250 Voice *p=currentVoice;
251 loop
252 {
253 if ((p->typ != BT_if)
254 &&(p->typ != BT_else))
255 {
256 if (p->typ == BT_break /*typ*/)
257 {
258 while (p != currentVoice)
259 {
260 exitVoice();
261 }
262 exitVoice();
263 return FALSE;
264 }
265 else return TRUE;
266 }
267 if (p->prev==NULL) break;
268 p=p->prev;
269 }
270 /*4 break not inside a for/while: return an error*/
271 if (/*typ*/ BT_break != currentVoice->typ) return 1;
272 return exitVoice();
273 }
274
275 if ((typ == BT_proc)
276 || (typ == BT_example))
277 {
278 Voice *p=currentVoice;
279 loop
280 {
281 if ((p->typ == BT_proc)
282 || (p->typ == BT_example))
283 {
284 while (p != currentVoice)
285 {
286 exitVoice();
287 }
288 exitVoice();
289 return FALSE;
290 }
291 if (p->prev==NULL) break;
292 p=p->prev;
293 }
294 }
295 /*4 return not inside a proc: return an error*/
296 return TRUE;
297 }
298
299 /*2
300 * jump to the beginning of a buffer
301 */
contBuffer(feBufferTypes typ)302 BOOLEAN contBuffer(feBufferTypes typ)
303 {
304 //printf("contBuffer: %d(%s),(%x)\n",
305 // typ,BT_name[typ], currentVoice);
306 if (typ == BT_break) // valid inside for, while. may skip if, else
307 {
308 // first check for valid buffer type
309 Voice *p=currentVoice;
310 loop
311 {
312 if ((p->typ != BT_if)
313 &&(p->typ != BT_else))
314 {
315 if (p->typ == BT_break /*typ*/)
316 {
317 while (p != currentVoice)
318 {
319 exitVoice();
320 }
321 yylineno = currentVoice->start_lineno;
322 currentVoice->fptr=0;
323 return FALSE;
324 }
325 else return TRUE;
326 }
327 if (p->prev==NULL) break;
328 p=p->prev;
329 }
330 }
331 return TRUE;
332 }
333
334 /*2
335 * leave a voice: kill local variables
336 * setup everything from the previous level
337 * return 1 if leaving the top level, 0 otherwise
338 */
exitVoice()339 BOOLEAN exitVoice()
340 {
341 //printf("exitVoice: %d(%s),(%x)\n",
342 // currentVoice->typ,BT_name[currentVoice->typ], currentVoice);
343 //{
344 //Voice *p=currentVoice;
345 //PrintS("-----------------\ncurr:");
346 //do
347 //{
348 //Print("voice fn:%s\n",p->filename);
349 //p=p->prev;
350 //}
351 //while (p!=NULL);
352 //PrintS("----------------\n");
353 //}
354 if (currentVoice!=NULL)
355 {
356 if (currentVoice->oldb!=NULL)
357 {
358 myyoldbuffer(currentVoice->oldb);
359 currentVoice->oldb=NULL;
360 }
361 if (currentVoice->filename!=NULL)
362 {
363 omFree((ADDRESS)currentVoice->filename);
364 currentVoice->filename=NULL;
365 }
366 if (currentVoice->buffer!=NULL)
367 {
368 omFree((ADDRESS)currentVoice->buffer);
369 currentVoice->buffer=NULL;
370 }
371 if ((currentVoice->prev==NULL)
372 &&(currentVoice->sw==BI_file)
373 &&(currentVoice->files!=stdin))
374 {
375 currentVoice->prev=feInitStdin(currentVoice);
376 }
377 if (currentVoice->prev!=NULL)
378 {
379 //printf("exitVoice typ %d(%s)\n",
380 // currentVoice->typ,BT_name[currentVoice->typ]);
381 if (currentVoice->typ==BT_if)
382 {
383 currentVoice->prev->ifsw=2;
384 }
385 else
386 {
387 currentVoice->prev->ifsw=0;
388 }
389 if ((currentVoice->sw == BI_file)
390 && (currentVoice->files!=NULL))
391 {
392 fclose(currentVoice->files);
393 }
394 yylineno=currentVoice->prev->curr_lineno;
395 currentVoice->prev->next=NULL;
396 }
397 Voice *p=currentVoice->prev;
398 delete currentVoice;
399 currentVoice=p;
400 }
401 return currentVoice==NULL;
402 }
403
404 /*2
405 * set prompt_char
406 * only called with currentVoice->sw == BI_stdin
407 */
feShowPrompt(void)408 static void feShowPrompt(void)
409 {
410 fe_promptstr[0]=prompt_char;
411 }
412
413 /*2
414 * print echo (si_echo or TRACE), set my_yylinebuf
415 */
fePrintEcho(char * anf,char *)416 static int fePrintEcho(char *anf, char */*b*/)
417 {
418 char *ss=strrchr(anf,'\n');
419 int len_s;
420 if (ss==NULL)
421 {
422 len_s=strlen(anf);
423 }
424 else
425 {
426 len_s=ss-anf+1;
427 }
428 // my_yylinebuf:
429 int mrc=si_min(len_s,79)-1;
430 strcpy(my_yylinebuf,anf+(len_s-1)-mrc);
431 if (my_yylinebuf[mrc] == '\n') my_yylinebuf[mrc] = '\0';
432 mrc--;
433 // handle echo:
434 if (((si_echo>myynest)
435 && ((currentVoice->typ==BT_proc)
436 || (currentVoice->typ==BT_example)
437 || (currentVoice->typ==BT_file)
438 || (currentVoice->typ==BT_none)
439 )
440 && (strncmp(anf,";return();",10)!=0)
441 )
442 || (traceit&TRACE_SHOW_LINE)
443 || (traceit&TRACE_SHOW_LINE1))
444 {
445 if (currentVoice->typ!=BT_example)
446 {
447 if (currentVoice->filename==NULL)
448 Print("(none) %3d%c ",yylineno,prompt_char);
449 else
450 Print("%s %3d%c ",currentVoice->filename,yylineno,prompt_char);
451 }
452 {
453 fwrite(anf,1,len_s,stdout);
454 mflush();
455 }
456 if (traceit&TRACE_SHOW_LINE)
457 {
458 char c;
459 do
460 {
461 c=fgetc(stdin);
462 if (c=='n') traceit_stop=1;
463 }
464 while(c!='\n');
465 }
466 }
467 else if (traceit&TRACE_SHOW_LINENO)
468 {
469 Print("{%d}",yylineno);
470 mflush();
471 }
472 else if (traceit&TRACE_PROFILING)
473 {
474 if (File_Profiling==NULL)
475 File_Profiling=fopen("smon.out","a");
476 if (File_Profiling==NULL)
477 traceit &= (~TRACE_PROFILING);
478 else
479 {
480 if (currentVoice->filename==NULL)
481 fprintf(File_Profiling,"(none) %d\n",yylineno);
482 else
483 fprintf(File_Profiling,"%s %d\n",currentVoice->filename,yylineno);
484 }
485 }
486 #ifdef HAVE_SDB
487 if ((blocknest==0)
488 && (currentVoice->pi!=NULL)
489 && (currentVoice->pi->trace_flag!=0))
490 {
491 sdb(currentVoice, anf, len_s);
492 }
493 #endif
494 prompt_char = '.';
495 return len_s;
496 }
497
feReadLine(char * b,int l)498 int feReadLine(char* b, int l)
499 {
500 char *s=NULL;
501 int offset = 0; /* will not be used if s==NULL*/
502 // try to read from the buffer into b, max l chars
503 if (currentVoice!=NULL)
504 {
505 if((currentVoice->buffer!=NULL)
506 && (currentVoice->buffer[currentVoice->fptr]!='\0'))
507 {
508 NewBuff:
509 REGISTER int i=0;
510 long startfptr=currentVoice->fptr;
511 long tmp_ptr=currentVoice->fptr;
512 l--;
513 loop
514 {
515 REGISTER char c=
516 b[i]=currentVoice->buffer[tmp_ptr/*currentVoice->fptr*/];
517 i++;
518 if (yy_noeof==noeof_block)
519 {
520 if (c<' ') yylineno++;
521 else if (c=='}') break;
522 }
523 else
524 {
525 if ((c<' ') ||
526 (c==';') ||
527 (c==')')
528 )
529 break;
530 }
531 if (i>=l) break;
532 tmp_ptr++;/*currentVoice->fptr++;*/
533 if(currentVoice->buffer[tmp_ptr/*currentVoice->fptr*/]=='\0') break;
534 }
535 currentVoice->fptr=tmp_ptr;
536 b[i]='\0';
537 if (currentVoice->sw==BI_buffer)
538 {
539 BOOLEAN show_echo=FALSE;
540 char *anf;
541 long len;
542 if (startfptr==0)
543 {
544 anf=currentVoice->buffer;
545 const char *ss=strchr(anf,'\n');
546 if (ss==NULL) len=strlen(anf);
547 else len=ss-anf;
548 show_echo=TRUE;
549 }
550 else if (/*(startfptr>0) &&*/
551 (currentVoice->buffer[startfptr-1]=='\n'))
552 {
553 anf=currentVoice->buffer+startfptr;
554 const char *ss=strchr(anf,'\n');
555 if (ss==NULL) len=strlen(anf);
556 else len=ss-anf;
557 yylineno++;
558 show_echo=TRUE;
559 }
560 if (show_echo)
561 {
562 char *s=(char *)omAlloc(len+2);
563 strncpy(s,anf,len+2);
564 s[len+1]='\0';
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; if (rc<0) rc=0;
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
feInitStdin(Voice * pp)669 Voice * 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 #endif
693
694