1 /****************************************
2  * *  Computer Algebra System SINGULAR     *
3  * ****************************************/
4 
5 /*
6  * ABSTRACT: ascii links (standard)
7  */
8 
9 #include "kernel/mod2.h"
10 #include "misc/options.h"
11 
12 #include "Singular/tok.h"
13 #include "Singular/subexpr.h"
14 #include "Singular/ipshell.h"
15 #include "Singular/ipid.h"
16 #include "Singular/fevoices.h"
17 #include "kernel/oswrapper/feread.h"
18 #include "Singular/ipshell.h"
19 #include "Singular/links/silink.h"
20 
21 /* declarations */
22 static BOOLEAN DumpAscii(FILE *fd, idhdl h,char ***list_of_libs);
23 static BOOLEAN DumpAsciiIdhdl(FILE *fd, idhdl h,char ***list_of_libs);
24 static const char* GetIdString(idhdl h);
25 static int DumpRhs(FILE *fd, idhdl h);
26 static BOOLEAN DumpQring(FILE *fd, idhdl h);
27 static BOOLEAN DumpNCring(FILE *fd, idhdl h);
28 static BOOLEAN DumpAsciiMaps(FILE *fd, idhdl h, idhdl rhdl);
29 static BOOLEAN CollectLibs(char *name, char ***list_of_libs);
30 //static BOOLEAN DumpLibs(FILE *fd, char ***list_of_libs);
31 
32 EXTERN_VAR si_link_extension si_link_root;
33 
34 /* =============== ASCII ============================================= */
slOpenAscii(si_link l,short flag,leftv)35 BOOLEAN slOpenAscii(si_link l, short flag, leftv /*h*/)
36 {
37   const char *mode;
38   if (flag & SI_LINK_OPEN)
39   {
40     if (l->mode[0] != '\0' && (strcmp(l->mode, "r") == 0))
41       flag = SI_LINK_READ;
42     else flag = SI_LINK_WRITE;
43   }
44 
45   if (flag == SI_LINK_READ) mode = "r";
46   else if (strcmp(l->mode, "w") == 0) mode = "w";
47   else mode = "a";
48 
49 
50   if (l->name[0] == '\0')
51   {
52     // stdin or stdout
53     if (flag == SI_LINK_READ)
54     {
55       l->data = (void *) stdin;
56       mode = "r";
57     }
58     else
59     {
60       l->data = (void *) stdout;
61       mode = "a";
62     }
63   }
64   else
65   {
66     // normal ascii link to a file
67     FILE *outfile;
68     char *filename=l->name;
69 
70     if(filename[0]=='>')
71     {
72       if (filename[1]=='>')
73       {
74         filename+=2;
75         mode = "a";
76       }
77       else
78       {
79         filename++;
80         mode="w";
81       }
82     }
83     outfile=myfopen(filename,mode);
84     if (outfile!=NULL)
85       l->data = (void *) outfile;
86     else
87       return TRUE;
88   }
89 
90   omFree(l->mode);
91   l->mode = omStrDup(mode);
92   SI_LINK_SET_OPEN_P(l, flag);
93   return FALSE;
94 }
95 
slCloseAscii(si_link l)96 BOOLEAN slCloseAscii(si_link l)
97 {
98   SI_LINK_SET_CLOSE_P(l);
99   if (l->name[0] != '\0')
100   {
101     return (fclose((FILE *)l->data)!=0);
102   }
103   return FALSE;
104 }
105 
slReadAscii2(si_link l,leftv pr)106 leftv slReadAscii2(si_link l, leftv pr)
107 {
108   FILE * fp=(FILE *)l->data;
109   char * buf=NULL;
110   if (fp!=NULL && l->name[0] != '\0')
111   {
112     fseek(fp,0L,SEEK_END);
113     long len=ftell(fp);
114     if (len<0) len=0;
115     fseek(fp,0L,SEEK_SET);
116     buf=(char *)omAlloc((int)len+1);
117     if (BVERBOSE(V_READING))
118       Print("//Reading %ld chars\n",len);
119     if (len>0) myfread( buf, len, 1, fp);
120     buf[len]='\0';
121   }
122   else
123   {
124     if (pr->Typ()==STRING_CMD)
125     {
126       buf=(char *)omAlloc(80);
127       fe_fgets_stdin((char *)pr->Data(),buf,80);
128     }
129     else
130     {
131       WerrorS("read(<link>,<string>) expected");
132       buf=omStrDup("");
133     }
134   }
135   leftv v=(leftv)omAlloc0Bin(sleftv_bin);
136   v->rtyp=STRING_CMD;
137   v->data=buf;
138   return v;
139 }
140 
slReadAscii(si_link l)141 leftv slReadAscii(si_link l)
142 {
143   sleftv tmp;
144   memset(&tmp,0,sizeof(sleftv));
145   tmp.rtyp=STRING_CMD;
146   tmp.data=(void*) "? ";
147   return slReadAscii2(l,&tmp);
148 }
149 
slWriteAscii(si_link l,leftv v)150 BOOLEAN slWriteAscii(si_link l, leftv v)
151 {
152   FILE *outfile=(FILE *)l->data;
153   BOOLEAN err=FALSE;
154   char *s;
155   while (v!=NULL)
156   {
157     switch(v->Typ())
158     {
159     case IDEAL_CMD:
160     case MODUL_CMD:
161     case MATRIX_CMD:
162       {
163         ideal I=(ideal)v->Data();
164         for(int i=0;i<IDELEMS(I);i++)
165         {
166           char *s=pString(I->m[i]);
167           fwrite(s,strlen(s),1,outfile);
168           omFree(s);
169           if (i<IDELEMS(I)-1) fwrite(",",1,1,outfile);
170         }
171         break;
172       }
173     default:
174       s = v->String();
175       // free v ??
176       if (s!=NULL)
177       {
178         fputs(s,outfile);
179         fputc('\n',outfile);
180         omFree((ADDRESS)s);
181       }
182       else
183       {
184         WerrorS("cannot convert to string");
185         err=TRUE;
186       }
187     }
188     v = v->next;
189   }
190   fflush(outfile);
191   return err;
192 }
193 
slStatusAscii(si_link l,const char * request)194 const char* slStatusAscii(si_link l, const char* request)
195 {
196   if (strcmp(request, "read") == 0)
197   {
198     if (SI_LINK_R_OPEN_P(l)) return "ready";
199     else return "not ready";
200   }
201   else if (strcmp(request, "write") == 0)
202   {
203     if (SI_LINK_W_OPEN_P(l)) return "ready";
204     else return "not ready";
205   }
206   else return "unknown status request";
207 }
208 
209 /*------------------ Dumping in Ascii format -----------------------*/
210 
slDumpAscii(si_link l)211 BOOLEAN slDumpAscii(si_link l)
212 {
213   FILE *fd = (FILE *) l->data;
214   idhdl h = IDROOT, rh = currRingHdl;
215   char **list_of_libs=NULL;
216   BOOLEAN status = DumpAscii(fd, h, &list_of_libs);
217 
218   if (! status ) status = DumpAsciiMaps(fd, h, NULL);
219 
220   if (currRingHdl != rh) rSetHdl(rh);
221   fprintf(fd, "option(set, intvec(%d, %d));\n", si_opt_1, si_opt_2);
222   char **p=list_of_libs;
223   if (p!=NULL)
224   {
225     while((*p!=NULL) && (*p!=(char*)1))
226     {
227       fprintf(fd,"load(\"%s\",\"try\");\n",*p);
228       p++;
229     }
230     omFree(list_of_libs);
231   }
232   fputs("RETURN();\n",fd);
233   fflush(fd);
234 
235   return status;
236 }
237 
238 // we do that recursively, to dump ids in the the order in which they
239 // were actually defined
DumpAscii(FILE * fd,idhdl h,char *** list_of_libs)240 static BOOLEAN DumpAscii(FILE *fd, idhdl h, char ***list_of_libs)
241 {
242   if (h == NULL) return FALSE;
243 
244   if (DumpAscii(fd, IDNEXT(h),list_of_libs)) return TRUE;
245 
246   // need to set the ring before writing it, otherwise we get in
247   // trouble with minpoly
248   if (IDTYP(h) == RING_CMD)
249     rSetHdl(h);
250 
251   if (DumpAsciiIdhdl(fd, h,list_of_libs)) return TRUE;
252 
253   if (IDTYP(h) == RING_CMD)
254     return DumpAscii(fd, IDRING(h)->idroot,list_of_libs);
255   else
256     return FALSE;
257 }
258 
DumpAsciiMaps(FILE * fd,idhdl h,idhdl rhdl)259 static BOOLEAN DumpAsciiMaps(FILE *fd, idhdl h, idhdl rhdl)
260 {
261   if (h == NULL) return FALSE;
262   if (DumpAsciiMaps(fd, IDNEXT(h), rhdl)) return TRUE;
263 
264   if (IDTYP(h) == RING_CMD)
265     return DumpAsciiMaps(fd, IDRING(h)->idroot, h);
266   else if (IDTYP(h) == MAP_CMD)
267   {
268     char *rhs;
269     rSetHdl(rhdl);
270     rhs = h->String();
271 
272     if (fprintf(fd, "setring %s;\n", IDID(rhdl)) == EOF) return TRUE;
273     if (fprintf(fd, "%s %s = %s, %s;\n", Tok2Cmdname(MAP_CMD), IDID(h),
274                 IDMAP(h)->preimage, rhs) == EOF)
275     {
276       omFree(rhs);
277       return TRUE;
278     }
279     else
280     {
281       omFree(rhs);
282       return FALSE;
283     }
284   }
285   else return FALSE;
286 }
287 
DumpAsciiIdhdl(FILE * fd,idhdl h,char *** list_of_libs)288 static BOOLEAN DumpAsciiIdhdl(FILE *fd, idhdl h, char ***list_of_libs)
289 {
290   const char *type_str = GetIdString(h);
291   int type_id = IDTYP(h);
292 
293   if (type_id == PACKAGE_CMD)
294   {
295     if (strcmp(IDID(h),"Top")==0) return FALSE; // do not dump "Top"
296     if (IDPACKAGE(h)->language==LANG_SINGULAR) return FALSE;
297     if (IDPACKAGE(h)->language==LANG_MIX) return FALSE;
298   }
299   if (type_id == CRING_CMD)
300   {
301     // do not dump the default CRINGs:
302     if (strcmp(IDID(h),"QQ")==0) return FALSE;
303     if (strcmp(IDID(h),"ZZ")==0) return FALSE;
304     #ifdef SINGULAR_4_2
305     if (strcmp(IDID(h),"AE")==0) return FALSE;
306     if (strcmp(IDID(h),"QAE")==0) return FALSE;
307     #endif
308   }
309 
310   // we do not throw an error if a wrong type was attempted to be dumped
311   if (type_str == NULL)
312     return FALSE;
313 
314   // handle nc-rings separately
315   if ((type_id == RING_CMD)&&(rIsNCRing(IDRING(h))))
316     return DumpNCring(fd,h);
317 
318   // handle qrings separately
319   if ((type_id == RING_CMD)&&(IDRING(h)->qideal!=NULL))
320     return DumpQring(fd, h);
321 
322   // C-proc not to be dumped
323   if ((type_id == PROC_CMD) && (IDPROC(h)->language == LANG_C))
324     return FALSE;
325 
326   // handle libraries
327   if ((type_id == PROC_CMD)
328   && (IDPROC(h)->language == LANG_SINGULAR)
329   && (IDPROC(h)->libname!=NULL))
330     return CollectLibs(IDPROC(h)->libname,list_of_libs);
331 
332   // put type and name
333   if (fprintf(fd, "%s %s", type_str, IDID(h)) == EOF)
334     return TRUE;
335   // for matricies, append the dimension
336   if (type_id == MATRIX_CMD)
337   {
338     ideal id = IDIDEAL(h);
339     if (fprintf(fd, "[%d][%d]", id->nrows, id->ncols)== EOF) return TRUE;
340   }
341   else if (type_id == INTMAT_CMD)
342   {
343     if (fprintf(fd, "[%d][%d]", IDINTVEC(h)->rows(), IDINTVEC(h)->cols())
344         == EOF) return TRUE;
345   }
346   else if (type_id == SMATRIX_CMD)
347   {
348     ideal id = IDIDEAL(h);
349     if (fprintf(fd, "[%d][%d]", (int)id->rank, IDELEMS(id))== EOF) return TRUE;
350   }
351 
352   if (type_id == PACKAGE_CMD)
353   {
354     return (fputs(";\n",fd) == EOF);
355   }
356 
357   // write the equal sign
358   if (fputs(" = ",fd) == EOF) return TRUE;
359 
360   // and the right hand side
361   if (DumpRhs(fd, h) == EOF) return TRUE;
362 
363   // semicolon und tschuess
364   if (fputs(";\n",fd) == EOF) return TRUE;
365 
366   return FALSE;
367 }
368 
GetIdString(idhdl h)369 static const char* GetIdString(idhdl h)
370 {
371   int type = IDTYP(h);
372 
373   switch(type)
374   {
375     case LIST_CMD:
376     //{
377     //
378     //
379     //  lists l = IDLIST(h);
380     //  int i, nl = l->nr + 1;
381 //
382     //  for (i=0; i<nl; i++)
383     //    if (GetIdString((idhdl) &(l->m[i])) == NULL) return NULL;
384     //  break;
385     //}
386     case CRING_CMD:
387     #ifdef SINGULAR_4_2
388     case CNUMBER_CMD:
389     case CMATRIX_CMD:
390     #endif
391     case BIGINT_CMD:
392     case PACKAGE_CMD:
393     case INT_CMD:
394     case INTVEC_CMD:
395     case INTMAT_CMD:
396     case STRING_CMD:
397     case RING_CMD:
398     case QRING_CMD:
399     case PROC_CMD:
400     case NUMBER_CMD:
401     case POLY_CMD:
402     case IDEAL_CMD:
403     case VECTOR_CMD:
404     case MODUL_CMD:
405     case MATRIX_CMD:
406     case SMATRIX_CMD:
407       return Tok2Cmdname(type);
408 
409     case MAP_CMD:
410     case LINK_CMD:
411       return NULL;
412 
413     default:
414       Warn("Error dump data of type %s", Tok2Cmdname(IDTYP(h)));
415        return NULL;
416   }
417 }
418 
DumpNCring(FILE * fd,idhdl h)419 static BOOLEAN DumpNCring(FILE *fd, idhdl h)
420 {
421   char *ring_str = h->String();
422   ring r=IDRING(h);
423 
424   if (rIsPluralRing(r))
425   {
426     if (fprintf(fd, "ring temp_ring = %s;\n", ring_str)
427       == EOF) return TRUE;
428     if (fprintf(fd, "ideal temp_C = %s;\n",
429               iiStringMatrix((matrix) r->GetNC()->C, 2, r, n_GetChar(r->cf)))
430       == EOF) return TRUE;
431     if (fprintf(fd, "ideal temp_D = %s;\n",
432               iiStringMatrix((matrix) r->GetNC()->D, 2, r, n_GetChar(r->cf)))
433       == EOF) return TRUE;
434     if (fprintf(fd, "def %s = nc_algebra(temp_C,temp_D);\n",IDID(h)) == EOF)
435       return TRUE;
436     if (fputs("kill temp_ring;\n",fd) == EOF) return TRUE;
437   }
438   if (rIsLPRing(r))
439   {
440     //if (fprintf(fd, "ring %s = %s;\n", IDID(h), ring_str) == EOF) return TRUE;
441     //if (fprintf(fd, "attrib(%s,\"isLetterplaceRing\",%d);\n",IDID(h),r->isLPring) ==EOF) return TRUE;
442     Warn("cannot write LP ring %s",IDID(h));
443     return TRUE;
444   }
445   omFree(ring_str);
446   return FALSE;
447 }
448 
DumpQring(FILE * fd,idhdl h)449 static BOOLEAN DumpQring(FILE *fd, idhdl h)
450 {
451   char *ring_str = h->String();
452   ring r=IDRING(h);
453   if (fprintf(fd, "ring temp_ring = %s;\n", ring_str) == EOF) return TRUE;
454   if (fprintf(fd, "ideal temp_ideal = %s;\n",
455               iiStringMatrix((matrix) r->qideal, 1, currRing, n_GetChar(r->cf)))
456       == EOF) return TRUE;
457   if (fputs("attrib(temp_ideal, \"isSB\", 1);\n",fd) == EOF) return TRUE;
458   if (fprintf(fd, "qring %s = temp_ideal;\n",IDID(h)) == EOF)
459     return TRUE;
460   if (fputs("kill temp_ring;\n",fd) == EOF) return TRUE;
461   else
462   {
463     omFree(ring_str);
464     return FALSE;
465   }
466 }
467 
CollectLibs(char * name,char *** list_of_libs)468 static BOOLEAN CollectLibs(char *name, char *** list_of_libs)
469 {
470   if (*list_of_libs==NULL)
471   {
472     #define MAX_LIBS 256
473     (*list_of_libs)=(char**)omAlloc0(MAX_LIBS*sizeof(char**));
474     (*list_of_libs)[0]=name;
475     (*list_of_libs)[MAX_LIBS-1]=(char*)1;
476     return FALSE;
477   }
478   else
479   {
480     char **p=*list_of_libs;
481     while (((*p)!=NULL)&&((*p!=(char*)1)))
482     {
483       if (strcmp((*p),name)==0) return FALSE;
484       p++;
485     }
486     if (*p==(char*)1)
487     {
488       WerrorS("too many libs");
489       return TRUE;
490     }
491     else
492     {
493       *p=name;
494     }
495   }
496   return FALSE;
497 }
498 
499 
DumpRhs(FILE * fd,idhdl h)500 static int DumpRhs(FILE *fd, idhdl h)
501 {
502   int type_id = IDTYP(h);
503 
504   if (type_id == LIST_CMD)
505   {
506     lists l = IDLIST(h);
507     int i, nl = l->nr;
508 
509     fputs("list(",fd);
510 
511     for (i=0; i<nl; i++)
512     {
513       if (DumpRhs(fd, (idhdl) &(l->m[i])) == EOF) return EOF;
514       fputs(",",fd);
515     }
516     if (nl > 0)
517     {
518       if (DumpRhs(fd, (idhdl) &(l->m[nl])) == EOF) return EOF;
519     }
520     fputs(")",fd);
521   }
522   else  if (type_id == STRING_CMD)
523   {
524     char *pstr = IDSTRING(h);
525     fputc('"', fd);
526     while (*pstr != '\0')
527     {
528       if (*pstr == '"' || *pstr == '\\')  fputc('\\', fd);
529       fputc(*pstr, fd);
530       pstr++;
531     }
532     fputc('"', fd);
533   }
534   else  if (type_id == PROC_CMD)
535   {
536     procinfov pi = IDPROC(h);
537     if (pi->language == LANG_SINGULAR)
538     {
539       /* pi-Libname==NULL */
540       char *pstr = pi->data.s.body;
541       fputc('"', fd);
542       while (*pstr != '\0')
543       {
544         if (*pstr == '"' || *pstr == '\\') fputc('\\', fd);
545         fputc(*pstr, fd);
546         pstr++;
547       }
548       fputc('"', fd);
549     }
550     else fputs("(null)", fd);
551   }
552   else
553   {
554     char *rhs = h->String();
555 
556     if (rhs == NULL) return EOF;
557 
558     BOOLEAN need_klammer=FALSE;
559     if (type_id == INTVEC_CMD) { fputs("intvec(",fd);need_klammer=TRUE; }
560     else if (type_id == IDEAL_CMD) { fputs("ideal(",fd);need_klammer=TRUE; }
561     else if ((type_id == MODUL_CMD)||(type_id == SMATRIX_CMD))
562                                    { fputs("module(",fd);need_klammer=TRUE; }
563     else if (type_id == BIGINT_CMD) { fputs("bigint(",fd);need_klammer=TRUE; }
564 
565     if (fputs(rhs,fd) == EOF) return EOF;
566     omFree(rhs);
567 
568     if ((type_id == RING_CMD) &&
569         IDRING(h)->cf->type==n_algExt)
570     {
571       StringSetS("");
572       p_Write(IDRING(h)->cf->extRing->qideal->m[0],IDRING(h)->cf->extRing);
573       rhs = StringEndS();
574       if (fprintf(fd, "; minpoly = %s", rhs) == EOF) { omFree(rhs); return EOF;}
575       omFree(rhs);
576     }
577     else if (need_klammer) fputc(')',fd);
578   }
579   return 1;
580 }
581 
slGetDumpAscii(si_link l)582 BOOLEAN slGetDumpAscii(si_link l)
583 {
584   if (l->name[0] == '\0')
585   {
586     WerrorS("getdump: Can not get dump from stdin");
587     return TRUE;
588   }
589   else
590   {
591     BOOLEAN status = newFile(l->name);
592     if (status)
593       return TRUE;
594 
595     int old_echo=si_echo;
596     si_echo=0;
597 
598     status=yyparse();
599 
600     si_echo=old_echo;
601 
602     if (status)
603       return TRUE;
604     else
605     {
606       // lets reset the file pointer to the end to reflect that
607       // we are finished with reading
608       FILE *f = (FILE *) l->data;
609       fseek(f, 0L, SEEK_END);
610       return FALSE;
611     }
612   }
613 }
614 
615 
slStandardInit()616 void slStandardInit()
617 {
618   si_link_extension s;
619   si_link_root=(si_link_extension)omAlloc0Bin(s_si_link_extension_bin);
620   si_link_root->Open=slOpenAscii;
621   si_link_root->Close=slCloseAscii;
622   si_link_root->Kill=NULL;
623   si_link_root->Read=slReadAscii;
624   si_link_root->Read2=slReadAscii2;
625   si_link_root->Write=slWriteAscii;
626   si_link_root->Dump=slDumpAscii;
627   si_link_root->GetDump=slGetDumpAscii;
628   si_link_root->Status=slStatusAscii;
629   si_link_root->type="ASCII";
630   s = si_link_root;
631   s->next = NULL;
632 }
633