source: git/Singular/links/ssiLink.cc @ 850277

spielwiese
Last change on this file since 850277 was 850277, checked in by Hans Schoenemann <hannes@…>, 10 years ago
chg: moved reading/writing numbers via ssi to coeffs (p.1)
  • Property mode set to 100644
File size: 52.5 KB
Line 
1/****************************************
2 * Computer Algebra System SINGULAR     *
3 ****************************************/
4/***************************************************************
5 * File:    ssiLink.h
6 *  Purpose: declaration of sl_link routines for ssi
7 ***************************************************************/
8#include <stdio.h>
9#include <fcntl.h>
10#include <errno.h>
11#include <unistd.h>
12#include <sys/types.h>
13#include <signal.h>
14#include <sys/types.h>          /* for portability */
15#include <sys/select.h>
16#include <sys/socket.h>
17#include <netinet/in.h>
18#include <ctype.h>   /*for isdigit*/
19#include <netdb.h>
20#include <sys/wait.h>
21#include <time.h>
22
23#include <kernel/mod2.h>
24#include <reporter/si_signals.h>
25// #include "mod2.h"
26
27#include <Singular/tok.h>
28#include <Singular/ipid.h>
29#include <Singular/ipshell.h>
30#include <omalloc/omalloc.h>
31#include <libpolys/polys/monomials/ring.h>
32#include <libpolys/polys/matpol.h>
33#include <libpolys/polys/simpleideals.h>
34#include <libpolys/polys/monomials/p_polys.h>
35#define TRANSEXT_PRIVATES 1 // allow access to transext internals
36#include <libpolys/polys/ext_fields/transext.h>
37#include <libpolys/coeffs/longrat.h>
38#include <libpolys/misc/intvec.h>
39#include <libpolys/coeffs/bigintmat.h>
40#include <libpolys/misc/options.h>
41#include <kernel/timer.h>
42#include <Singular/rlimit.h>
43#include <Singular/subexpr.h>
44#include <Singular/links/silink.h>
45#include <Singular/cntrlc.h>
46#include <Singular/lists.h>
47#include <Singular/blackbox.h>
48#include <libpolys/reporter/s_buff.h>
49#include <Singular/links/ssiLink.h>
50
51#ifdef HAVE_SIMPLEIPC
52#include <Singular/links/simpleipc.h>
53#endif
54
55#define SSI_VERSION 6
56// 5->6: changed newstruct representation
57
58// 64 bit version:
59//#if SIZEOF_LONG == 8
60#if 0
61#define MAX_NUM_SIZE 60
62#define POW_2_28 (1L<<60)
63#define LONG long
64#else
65// 32 bit version:
66#define MAX_NUM_SIZE 28
67#define POW_2_28 (1L<<28)
68#define LONG int
69#endif
70
71#define SSI_BASE 16
72typedef struct
73{
74  s_buff f_read;
75  FILE *f_write;
76  ring r;
77  pid_t pid; /* only valid for fork/tcp mode*/
78  int fd_read,fd_write; /* only valid for fork/tcp mode*/
79  char level;
80  char send_quit_at_exit;
81  char quit_sent;
82
83} ssiInfo;
84
85link_list ssiToBeClosed=NULL;
86volatile BOOLEAN ssiToBeClosed_inactive=TRUE;
87
88// the helper functions:
89void ssiSetCurrRing(const ring r)
90{
91  if (!rEqual(r,currRing,1))
92  {
93    char name[20];
94    int nr=0;
95    do
96    { sprintf(name,"ssiRing%d",nr); nr++; }
97    while(IDROOT->get(name, 0)!=NULL);
98    idhdl h=enterid(omStrDup(name),0,RING_CMD,&IDROOT,FALSE);
99    IDRING(h)=r;
100    r->ref++;
101    rSetHdl(h);
102  }
103}
104// the implementation of the functions:
105void ssiWriteInt(ssiInfo *d,const int i)
106{
107  fprintf(d->f_write,"%d ",i);
108  //if (d->f_debug!=NULL) fprintf(d->f_debug,"int: %d ",i);
109}
110
111void ssiWriteString(ssiInfo *d,const char *s)
112{
113  fprintf(d->f_write,"%d %s ",(int)strlen(s),s);
114  //if (d->f_debug!=NULL) fprintf(d->f_debug,"stringi: %d \"%s\" ",strlen(s),s);
115}
116
117
118void ssiWriteBigInt(const ssiInfo *d, const number n)
119{
120  // syntax is as follows:
121  // case 2 Q:     3 4 <int>
122  //        or     3 3 <mpz_t nominator>
123  if(SR_HDL(n) & SR_INT)
124  {
125    fprintf(d->f_write,"4 %ld ",SR_TO_INT(n));
126    //if (d->f_debug!=NULL) fprintf(d->f_debug,"bigint: short \"%ld\" ",SR_TO_INT(n));
127  }
128  else if (n->s==3)
129  {
130    fputs("3 ",d->f_write);
131    mpz_out_str(d->f_write,10,n->z);
132    fputc(' ',d->f_write);
133    //gmp_fprintf(d->f_write,"3 %Zd ",n->z);
134    //if (d->f_debug!=NULL) gmp_fprintf(d->f_debug,"bigint: gmp \"%Zd\" ",n->z);
135  }
136  else WerrorS("illiegal bigint");
137}
138
139void ssiWritePoly_R(const ssiInfo *d, int typ, poly p, const ring r);
140void ssiWriteNumber_CF(const ssiInfo *d, const number n, const coeffs cf)
141{
142  // syntax is as follows:
143  // case 1 Z/p:   3 <int>
144  // case 2 Q:     3 4 <int>
145  //        or     3 0 <mpz_t nominator> <mpz_t denominator>
146  //        or     3 1  dto.
147  //        or     3 3 <mpz_t nominator>
148  //        or     3 5 <mpz_t raw nom.> <mpz_t raw denom.>
149  //        or     3 6 <mpz_t raw nom.> <mpz_t raw denom.>
150  //        or     3 7 <mpz_t raw nom.>
151  if (getCoeffType(cf)==n_transExt)
152  {
153    fraction f=(fraction)n;
154    ssiWritePoly_R(d,POLY_CMD,NUM(f),cf->extRing);
155    ssiWritePoly_R(d,POLY_CMD,DEN(f),cf->extRing);
156  }
157  else if (getCoeffType(cf)==n_algExt)
158  {
159    ssiWritePoly_R(d,POLY_CMD,(poly)n,cf->extRing);
160  }
161  else if (cf->cfWriteFd!=NULL)
162  {
163    cf->cfWriteFd(n,d->f_write,cf);
164  }
165  else WerrorS("coeff field not implemented");
166}
167
168void ssiWriteNumber(const ssiInfo *d, const number n)
169{
170  ssiWriteNumber_CF(d,n,d->r->cf);
171}
172
173void ssiWriteRing(ssiInfo *d,const ring r)
174{
175  /* 5 <ch> <N> <l1> <v1> ...<lN> <vN> <number of orderings> <ord1> <block0_1> <block1_1> .... */
176  /* ch=-1: transext, coeff ring follows */
177  /* ch=-2: algext, coeff ring and minpoly follows */
178  if (r==currRing) // see recursive calls for transExt/algExt
179  {
180    if (d->r!=NULL) rKill(d->r);
181    d->r=r;
182  }
183  if (r!=NULL)
184  {
185    /*d->*/r->ref++;
186    if (rField_is_Q(r) || rField_is_Zp(r))
187      fprintf(d->f_write,"%d %d ",n_GetChar(r->cf),r->N);
188    else if (rFieldType(r)==n_transExt)
189      fprintf(d->f_write,"-1 %d ",r->N);
190    else if (rFieldType(r)==n_algExt)
191      fprintf(d->f_write,"-2 %d ",r->N);
192    else /*dummy*/
193      fprintf(d->f_write,"0 %d ",r->N);
194
195    int i;
196    for(i=0;i<r->N;i++)
197    {
198      fprintf(d->f_write,"%d %s ",(int)strlen(r->names[i]),r->names[i]);
199    }
200    /* number of orderings:*/
201    i=0;
202    // remember dummy ring: everything 0:
203    if (r->order!=NULL) while (r->order[i]!=0) i++;
204    fprintf(d->f_write,"%d ",i);
205    /* each ordering block: */
206    i=0;
207    if (r->order!=NULL) while(r->order[i]!=0)
208    {
209      fprintf(d->f_write,"%d %d %d ",r->order[i],r->block0[i], r->block1[i]);
210      switch(r->order[i])
211      {
212        case ringorder_a:
213        case ringorder_wp:
214        case ringorder_Wp:
215        case ringorder_ws:
216        case ringorder_Ws:
217        case ringorder_aa:
218        {
219          int ii;
220          for(ii=r->block0[i];ii<=r->block1[i];ii++)
221            fprintf(d->f_write,"%d ",r->wvhdl[i][ii-r->block0[i]]);
222        }
223        break;
224
225        case ringorder_a64:
226        case ringorder_M:
227        case ringorder_L:
228        case ringorder_IS:
229          Werror("ring oder not implemented for ssi:%d",r->order[i]);
230          break;
231
232        default: break;
233      }
234      i++;
235    }
236    if ((rFieldType(r)==n_transExt)
237    || (rFieldType(r)==n_algExt))
238    {
239      ssiWriteRing(d,r->cf->extRing);
240      if  (rFieldType(r)==n_algExt)
241      {
242        ssiWritePoly_R(d,POLY_CMD,r->cf->extRing->qideal->m[0],r->cf->extRing);
243      }
244    }
245  }
246  else /* dummy ring r==NULL*/
247  {
248    fprintf(d->f_write,"0 0 0 "/*,r->ch,r->N, blocks*/);
249  }
250}
251
252void ssiWritePoly_R(const ssiInfo *d, int typ, poly p, const ring r)
253{
254  fprintf(d->f_write,"%d ",pLength(p));//number of terms
255  int i;
256
257  while(p!=NULL)
258  {
259    ssiWriteNumber_CF(d,pGetCoeff(p),r->cf);
260    //nWrite(fich,pGetCoeff(p));
261    fprintf(d->f_write,"%ld ",p_GetComp(p,r));//component
262
263    for(int j=1;j<=rVar(r);j++)
264    {
265      fprintf(d->f_write,"%ld ",p_GetExp(p,j,r ));//x^j
266    }
267    pIter(p);
268  }
269}
270
271void ssiWritePoly(const ssiInfo *d, int typ, poly p)
272{
273  ssiWritePoly_R(d,typ,p,d->r);
274}
275
276void ssiWriteIdeal(ssiInfo *d, int typ,ideal I)
277{
278   // syntax: 7 # of elements <poly 1> <poly2>.....
279   // syntax: 8 <rows> <cols> <poly 1> <poly2>.....
280   matrix M=(matrix)I;
281   int mn;
282   if (typ==MATRIX_CMD)
283   {
284     mn=MATROWS(M)*MATCOLS(M);
285     fprintf(d->f_write,"%d %d ", MATROWS(M),MATCOLS(M));
286   }
287   else
288   {
289     mn=IDELEMS(I);
290     fprintf(d->f_write,"%d ",IDELEMS(I));
291   }
292
293   int i;
294   int tt;
295   if (typ==MODUL_CMD) tt=VECTOR_CMD;
296   else                tt=POLY_CMD;
297
298   for(i=0;i<mn;i++)
299   {
300     ssiWritePoly(d,tt,I->m[i]);
301   }
302}
303
304void ssiWriteCommand(si_link l, command D)
305{
306  ssiInfo *d=(ssiInfo*)l->data;
307  // syntax: <num ops> <operation> <op1> <op2> ....
308  fprintf(d->f_write,"%d %d ",D->argc,D->op);
309  if (D->argc >0) ssiWrite(l, &(D->arg1));
310  if (D->argc < 4)
311  {
312    if (D->argc >1) ssiWrite(l, &(D->arg2));
313    if (D->argc >2) ssiWrite(l, &(D->arg3));
314  }
315}
316
317void ssiWriteProc(ssiInfo *d,procinfov p)
318{
319  if (p->data.s.body==NULL)
320    iiGetLibProcBuffer(p);
321  if (p->data.s.body!=NULL)
322    ssiWriteString(d,p->data.s.body);
323  else
324    ssiWriteString(d,"");
325}
326
327void ssiWriteList(si_link l,lists dd)
328{
329  ssiInfo *d=(ssiInfo*)l->data;
330  int Ll=lSize(dd);
331  fprintf(d->f_write,"%d ",Ll+1);
332  int i;
333  for(i=0;i<=Ll;i++)
334  {
335    ssiWrite(l,&(dd->m[i]));
336  }
337}
338void ssiWriteIntvec(ssiInfo *d,intvec * v)
339{
340  fprintf(d->f_write,"%d ",v->length());
341  int i;
342  for(i=0;i<v->length();i++)
343  {
344    fprintf(d->f_write,"%d ",(*v)[i]);
345  }
346}
347void ssiWriteIntmat(ssiInfo *d,intvec * v)
348{
349  fprintf(d->f_write,"%d %d ",v->rows(),v->cols());
350  int i;
351  for(i=0;i<v->length();i++)
352  {
353    fprintf(d->f_write,"%d ",(*v)[i]);
354  }
355}
356
357void ssiWriteBigintmat(ssiInfo *d,bigintmat * v)
358{
359  fprintf(d->f_write,"%d %d ",v->rows(),v->cols());
360  int i;
361  for(i=0;i<v->length();i++)
362  {
363    ssiWriteBigInt(d,(*v)[i]);
364  }
365}
366
367char *ssiReadString(ssiInfo *d)
368{
369  char *buf;
370  int l;
371  l=s_readint(d->f_read);
372  buf=(char*)omAlloc0(l+1);
373  int c =s_getc(d->f_read); /* skip ' '*/
374  int ll=s_readbytes(buf,l,d->f_read);
375  //if (ll!=l) printf("want %d, got %d bytes\n",l,ll);
376  buf[l]='\0';
377  return buf;
378}
379
380int ssiReadInt(s_buff fich)
381{
382  return s_readint(fich);
383}
384
385number ssiReadBigInt(ssiInfo *d)
386{
387  int sub_type=-1;
388  sub_type=s_readint(d->f_read);
389  switch(sub_type)
390  {
391   case 3:
392     {// read int or mpz_t or mpz_t, mpz_t
393       number n=nlRInit(0);
394       s_readmpz(d->f_read,n->z);
395       n->s=sub_type;
396       return n;
397     }
398   case 4:
399     {
400       int dd;
401       dd=s_readint(d->f_read);
402       return INT_TO_SR(dd);
403     }
404   default:
405       Werror("error in reading bigint: invalid subtype %d",sub_type);
406       return NULL;
407   }
408}
409
410static number ssiReadQNumber(ssiInfo *d)
411{
412  int sub_type=-1;
413  sub_type=s_readint(d->f_read);
414  switch(sub_type)
415  {
416     case 0:
417     case 1:
418       {// read mpz_t, mpz_t
419         number n=nlRInit(0);
420         mpz_init(n->n);
421         s_readmpz(d->f_read,n->z);
422         s_readmpz(d->f_read,n->n);
423         n->s=sub_type;
424         return n;
425       }
426
427     case 3:
428       {// read mpz_t
429         number n=nlRInit(0);
430         s_readmpz(d->f_read,n->z);
431         n->s=3; /*sub_type*/
432         return n;
433       }
434     case 4:
435       {
436         LONG dd=s_readlong(d->f_read);
437         //#if SIZEOF_LONG == 8
438         return INT_TO_SR(dd);
439         //#else
440         //return nlInit(dd,NULL);
441         //#endif
442       }
443     case 5:
444     case 6:
445       {// read raw mpz_t, mpz_t
446         number n=nlRInit(0);
447         mpz_init(n->n);
448         s_readmpz_base (d->f_read,n->z, SSI_BASE);
449         s_readmpz_base (d->f_read,n->n, SSI_BASE);
450         n->s=sub_type-5;
451         return n;
452       }
453     case 8:
454       {// read raw mpz_t
455         number n=nlRInit(0);
456         s_readmpz_base (d->f_read,n->z, SSI_BASE);
457         n->s=sub_type=3; /*subtype-5*/
458         return n;
459       }
460
461     default: Werror("error in reading number: invalid subtype %d",sub_type);
462              return NULL;
463  }
464  return NULL;
465}
466
467poly ssiReadPoly_R(ssiInfo *D, const ring r);
468number ssiReadNumber_CF(ssiInfo *d, const coeffs cf)
469{
470  if (cf->cfReadFd!=NULL)
471  {
472     return cf->cfReadFd(d->f_read,cf);
473  }
474  else if (getCoeffType(cf) == n_transExt)
475  {
476    // poly poly
477    fraction f=(fraction)n_Init(1,cf);
478    p_Delete(&NUM(f),cf->extRing);
479    NUM(f)=ssiReadPoly_R(d,cf->extRing);
480    DEN(f)=ssiReadPoly_R(d,cf->extRing);
481    return (number)f;
482  }
483  else if (getCoeffType(cf) == n_algExt)
484  {
485    // poly
486    return (number)ssiReadPoly_R(d,cf->extRing);
487  }
488  else Werror("coeffs not implemented in ssiReadNumber");
489  return NULL;
490}
491
492number ssiReadNumber(ssiInfo *d)
493{
494  return ssiReadNumber_CF(d,d->r->cf);
495}
496
497ring ssiReadRing(ssiInfo *d)
498{
499/* syntax is <ch> <N> <l1> <v1> ...<lN> <vN> <number of orderings> <ord1> <block0_1> <block1_1> .... */
500  int ch, N,i,l;
501  char **names;
502  ch=s_readint(d->f_read);
503  N=s_readint(d->f_read);
504  if (N!=0)
505  {
506    names=(char**)omAlloc(N*sizeof(char*));
507    for(i=0;i<N;i++)
508    {
509      names[i]=ssiReadString(d);
510    }
511  }
512  // read the orderings:
513  int num_ord; // number of orderings
514  num_ord=s_readint(d->f_read);
515  int *ord=(int *)omAlloc0((num_ord+1)*sizeof(int));
516  int *block0=(int *)omAlloc0((num_ord+1)*sizeof(int));
517  int *block1=(int *)omAlloc0((num_ord+1)*sizeof(int));
518  int **wvhdl=(int**)omAlloc0((num_ord+1)*sizeof(int*));
519  for(i=0;i<num_ord;i++)
520  {
521    ord[i]=s_readint(d->f_read);
522    block0[i]=s_readint(d->f_read);
523    block1[i]=s_readint(d->f_read);
524    switch(ord[i])
525    {
526      case ringorder_a:
527      case ringorder_wp:
528      case ringorder_Wp:
529      case ringorder_ws:
530      case ringorder_Ws:
531      case ringorder_aa:
532      {
533        wvhdl[i]=(int*)omAlloc((block1[i]-block0[i]+1)*sizeof(int));
534        int ii;
535        for(ii=block0[i];ii<=block1[i];ii++)
536          wvhdl[i][ii-block0[i]]=s_readint(d->f_read);
537      }
538      break;
539
540      case ringorder_a64:
541      case ringorder_M:
542      case ringorder_L:
543      case ringorder_IS:
544        Werror("ring oder not implemented for ssi:%d",ord[i]);
545        break;
546
547      default: break;
548    }
549  }
550  if (N==0)
551  {
552    omFree(ord);
553    omFree(block0);
554    omFree(block1);
555    omFree(wvhdl);
556    return NULL;
557  }
558  else if (ch>=0) /* Q, Z/p */
559    return rDefault(ch,N,names,num_ord,ord,block0,block1,wvhdl);
560  else if (ch==-1) /* trans ext. */
561  {
562    TransExtInfo T;
563    T.r=ssiReadRing(d);
564    coeffs cf=nInitChar(n_transExt,&T);
565    return rDefault(cf,N,names,num_ord,ord,block0,block1,wvhdl);
566  }
567  else if (ch==-2) /* alg ext. */
568  {
569    TransExtInfo T;
570    T.r=ssiReadRing(d);
571    T.r->qideal=idInit(1,1);
572    T.r->qideal->m[0]=ssiReadPoly_R(d,T.r);
573    coeffs cf=nInitChar(n_algExt,&T);
574    return rDefault(cf,N,names,num_ord,ord,block0,block1,wvhdl);
575  }
576  else
577  {
578    Werror("ssi: read unknown coeffs type (%d)",ch);
579    return NULL;
580  }
581}
582
583poly ssiReadPoly_R(ssiInfo *D, const ring r)
584{
585// < # of terms> < term1> < .....
586  int n,i,l;
587  n=ssiReadInt(D->f_read);
588  //Print("poly: terms:%d\n",n);
589  poly p;
590  int j;
591  j=0;
592  poly ret=NULL;
593  poly prev=NULL;
594  for(l=0;l<n;l++) // read n terms
595  {
596// coef,comp.exp1,..exp N
597    p=p_Init(r);
598    pSetCoeff0(p,ssiReadNumber_CF(D,r->cf));
599    int d;
600    d=s_readint(D->f_read);
601    p_SetComp(p,d,r);
602    for(i=1;i<=rVar(r);i++)
603    {
604      d=s_readint(D->f_read);
605      p_SetExp(p,i,d,r);
606    }
607    p_Setm(p,r);
608    p_Test(p,r);
609    if (ret==NULL) ret=p;
610    else           pNext(prev)=p;
611    prev=p;
612 }
613 return ret;
614}
615
616poly ssiReadPoly(ssiInfo *D)
617{
618// < # of terms> < term1> < .....
619  return ssiReadPoly_R(D,D->r);
620}
621
622ideal ssiReadIdeal(ssiInfo *d)
623{
624  int n,i;
625  ideal I;
626  n=s_readint(d->f_read);
627  I=idInit(n,1);
628  for(i=0;i<IDELEMS(I);i++) // read n terms
629  {
630    I->m [i]=ssiReadPoly(d);
631  }
632  return I;
633}
634
635matrix ssiReadMatrix(ssiInfo *d)
636{
637  int n,m,i,j;
638  m=s_readint(d->f_read);
639  n=s_readint(d->f_read);
640  matrix M=mpNew(m,n);
641  poly p;
642  for(int i=1;i<=MATROWS(M);i++)
643    for(int j=1;j<=MATCOLS(M);j++)
644    {
645      p=ssiReadPoly(d);
646      MATELEM(M,i,j)=p;
647    }
648  return M;
649}
650
651command ssiReadCommand(si_link l)
652{
653  ssiInfo *d=(ssiInfo*)l->data;
654  // syntax: <num ops> <operation> <op1> <op2> ....
655  command D=(command)omAlloc0(sizeof(*D));
656  int argc,op;
657  argc=s_readint(d->f_read);
658  op=s_readint(d->f_read);
659  D->argc=argc; D->op=op;
660  leftv v;
661  if (argc >0)
662  {
663    v=ssiRead1(l);
664    memcpy(&(D->arg1),v,sizeof(*v));
665    omFreeBin(v,sleftv_bin);
666  }
667  if (argc <4)
668  {
669    if (D->argc >1)
670    {
671      v=ssiRead1(l);
672      memcpy(&(D->arg2),v,sizeof(*v));
673      omFreeBin(v,sleftv_bin);
674    }
675    if (D->argc >2)
676    {
677      v=ssiRead1(l);
678      memcpy(&(D->arg3),v,sizeof(*v));
679      omFreeBin(v,sleftv_bin);
680    }
681  }
682  else
683  {
684    leftv prev=&(D->arg1);
685    argc--;
686    while(argc >0)
687    {
688      v=ssiRead1(l);
689      prev->next=v;
690      prev=v;
691      argc--;
692    }
693  }
694  return D;
695}
696
697procinfov ssiReadProc(ssiInfo *d)
698{
699  char *s=ssiReadString(d);
700  procinfov p=(procinfov)omAlloc0Bin(procinfo_bin);
701  p->language=LANG_SINGULAR;
702  p->libname=omStrDup("");
703  p->procname=omStrDup("");
704  p->data.s.body=s;
705  return p;
706}
707lists ssiReadList(si_link l)
708{
709  ssiInfo *d=(ssiInfo*)l->data;
710  int nr;
711  nr=s_readint(d->f_read);
712  lists L=(lists)omAlloc(sizeof(*L));
713  L->Init(nr);
714
715  int i;
716  leftv v;
717  for(i=0;i<nr;i++)
718  {
719    v=ssiRead1(l);
720    memcpy(&(L->m[i]),v,sizeof(*v));
721    omFreeBin(v,sleftv_bin);
722  }
723  return L;
724}
725intvec* ssiReadIntvec(ssiInfo *d)
726{
727  int nr;
728  nr=s_readint(d->f_read);
729  intvec *v=new intvec(nr);
730  for(int i=0;i<nr;i++)
731  {
732    (*v)[i]=s_readint(d->f_read);
733  }
734  return v;
735}
736intvec* ssiReadIntmat(ssiInfo *d)
737{
738  int r,c;
739  r=s_readint(d->f_read);
740  c=s_readint(d->f_read);
741  intvec *v=new intvec(r,c,0);
742  for(int i=0;i<r*c;i++)
743  {
744    (*v)[i]=s_readint(d->f_read);
745  }
746  return v;
747}
748bigintmat* ssiReadBigintmat(ssiInfo *d)
749{
750  int r,c;
751  r=s_readint(d->f_read);
752  c=s_readint(d->f_read);
753  bigintmat *v=new bigintmat(r,c,coeffs_BIGINT);
754  for(int i=0;i<r*c;i++)
755  {
756    (*v)[i]=ssiReadBigInt(d);
757  }
758  return v;
759}
760
761void ssiReadBlackbox(leftv res, si_link l)
762{
763  ssiInfo *d=(ssiInfo*)l->data;
764  int throwaway;
765  throwaway=s_readint(d->f_read);
766  char *name=ssiReadString(d);
767  int tok;
768  blackboxIsCmd(name,tok);
769  if (tok>MAX_TOK)
770  {
771    blackbox *b=getBlackboxStuff(tok);
772    res->rtyp=tok;
773    b->blackbox_deserialize(&b,&(res->data),l);
774  }
775  else
776  {
777    Werror("blackbox %s not found",name);
778  }
779}
780
781//**************************************************************************/
782
783BOOLEAN ssiOpen(si_link l, short flag, leftv u)
784{
785  if (l!=NULL)
786  {
787    const char *mode;
788    ssiInfo *d=(ssiInfo*)omAlloc0(sizeof(ssiInfo));
789    if (flag & SI_LINK_OPEN)
790    {
791      if (l->mode[0] != '\0' && (strcmp(l->mode, "r") == 0))
792        flag = SI_LINK_READ;
793      else flag = SI_LINK_WRITE;
794    }
795
796    if (flag == SI_LINK_READ) mode = "r";
797    else if (strcmp(l->mode, "w") == 0) mode = "w";
798    else if (strcmp(l->mode, "fork") == 0) mode = "fork";
799    else if (strcmp(l->mode, "tcp") == 0) mode = "tcp";
800    else if (strcmp(l->mode, "connect") == 0) mode = "connect";
801    else mode = "a";
802
803
804    SI_LINK_SET_OPEN_P(l, flag);
805    l->data=d;
806    omFree(l->mode);
807    l->mode = omStrDup(mode);
808
809    if (l->name[0] == '\0')
810    {
811      if (strcmp(mode,"fork")==0)
812      {
813        link_list n=(link_list)omAlloc(sizeof(link_struct));
814        n->u=u;
815        n->l=l;
816        n->next=(void *)ssiToBeClosed;
817        ssiToBeClosed=n;
818
819        int pc[2];
820        int cp[2];
821        pipe(pc);
822        pipe(cp);
823        pid_t pid = fork();
824        if (pid == -1 && errno == EAGAIN)   // RLIMIT_NPROC too low?
825        {
826          raise_rlimit_nproc();
827          pid = fork();
828        }
829        if (pid == -1)
830        {
831          WerrorS("could not fork");
832        }
833        if (pid==0) /*fork: child*/
834        {
835          /* block SIGINT */
836          sigset_t sigint;
837          sigemptyset(&sigint);
838          sigaddset(&sigint, SIGINT);
839          sigprocmask(SIG_BLOCK, &sigint, NULL);
840
841          link_list hh=(link_list)ssiToBeClosed->next;
842          /* we know: l is the first entry in ssiToBeClosed-list */
843          while(hh!=NULL)
844          {
845            SI_LINK_SET_CLOSE_P(hh->l);
846            ssiInfo *dd=(ssiInfo*)hh->l->data;
847            s_close(dd->f_read);
848            s_free(dd->f_read);
849            fclose(dd->f_write);
850            if (dd->r!=NULL) rKill(dd->r);
851            omFreeSize((ADDRESS)dd,(sizeof *dd));
852            hh->l->data=NULL;
853            link_list nn=(link_list)hh->next;
854            omFree(hh);
855            hh=nn;
856          }
857          ssiToBeClosed->next=NULL;
858#ifdef HAVE_SIMPLEIPC
859          memset(sem_acquired, 0, SIPC_MAX_SEMAPHORES*sizeof(sem_acquired[0]));
860#endif   // HAVE_SIMPLEIPC
861          si_close(pc[1]); si_close(cp[0]);
862          d->f_write=fdopen(cp[1],"w");
863          d->f_read=s_open(pc[0]);
864          d->fd_read=pc[0];
865          d->fd_write=cp[1];
866          //d->r=currRing;
867          //if (d->r!=NULL) d->r->ref++;
868          l->data=d;
869          omFree(l->mode);
870          l->mode = omStrDup(mode);
871          singular_in_batchmode=TRUE;
872          SI_LINK_SET_RW_OPEN_P(l);
873          //myynest=0;
874          fe_fgets_stdin=fe_fgets_dummy;
875          if ((u!=NULL)&&(u->rtyp==IDHDL))
876          {
877            idhdl h=(idhdl)u->data;
878            h->lev=0;
879          }
880          loop
881          {
882            leftv h=ssiRead1(l); /*contains an exit.... */
883            if (feErrors != NULL && *feErrors != '\0')
884            {
885              // handle errors:
886              PrintS(feErrors); /* currently quite simple */
887              *feErrors = '\0';
888            }
889            ssiWrite(l,h);
890            h->CleanUp();
891            omFreeBin(h, sleftv_bin);
892          }
893          /* never reached*/
894        }
895        else if (pid>0) /*fork: parent*/
896        {
897          d->pid=pid;
898          si_close(pc[0]); si_close(cp[1]);
899          d->f_write=fdopen(pc[1],"w");
900          d->f_read=s_open(cp[0]);
901          d->fd_read=cp[0];
902          d->fd_write=pc[1];
903          SI_LINK_SET_RW_OPEN_P(l);
904          d->send_quit_at_exit=1;
905          //d->r=currRing;
906          //if (d->r!=NULL) d->r->ref++;
907        }
908        else
909        {
910          Werror("fork failed (%d)",errno);
911          l->data=NULL;
912          omFree(d);
913          return TRUE;
914        }
915      }
916      // ---------------------------------------------------------------------
917      else if (strcmp(mode,"tcp")==0)
918      {
919        int sockfd, newsockfd, portno, clilen;
920        struct sockaddr_in serv_addr, cli_addr;
921        int n;
922        sockfd = socket(AF_INET, SOCK_STREAM, 0);
923        if(sockfd < 0)
924        {
925          WerrorS("ERROR opening socket");
926          l->data=NULL;
927          omFree(d);
928          return TRUE;
929        }
930        memset((char *) &serv_addr,0, sizeof(serv_addr));
931        portno = 1025;
932        serv_addr.sin_family = AF_INET;
933        serv_addr.sin_addr.s_addr = INADDR_ANY;
934        do
935        {
936          portno++;
937          serv_addr.sin_port = htons(portno);
938          if(portno > 50000)
939          {
940            WerrorS("ERROR on binding (no free port available?)");
941            l->data=NULL;
942            omFree(d);
943            return TRUE;
944          }
945        }
946        while(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0);
947        Print("waiting on port %d\n", portno);mflush();
948        listen(sockfd,1);
949        newsockfd = si_accept(sockfd, (struct sockaddr *) &cli_addr, (socklen_t *)&clilen);
950        if(newsockfd < 0)
951        {
952          WerrorS("ERROR on accept");
953          l->data=NULL;
954          omFree(d);
955          return TRUE;
956        }
957        PrintS("client accepted\n");
958        d->fd_read = newsockfd;
959        d->fd_write = newsockfd;
960        d->f_read = s_open(newsockfd);
961        d->f_write = fdopen(newsockfd, "w");
962        SI_LINK_SET_RW_OPEN_P(l);
963        si_close(sockfd);
964      }
965      // no ssi-Link on stdin or stdout
966      else
967      {
968        Werror("invalid mode >>%s<< for ssi",mode);
969        l->data=NULL;
970        omFree(d);
971        return TRUE;
972      }
973    }
974    // =========================================================================
975    else /*l->name=NULL*/
976    {
977      // tcp mode
978      if(strcmp(mode,"tcp")==0)
979      {
980        int sockfd, newsockfd, portno, clilen;
981        struct sockaddr_in serv_addr, cli_addr;
982        int n;
983        sockfd = socket(AF_INET, SOCK_STREAM, 0);
984        if(sockfd < 0)
985        {
986          WerrorS("ERROR opening socket");
987          l->data=NULL;
988          omFree(d);
989          return TRUE;
990        }
991        memset((char *) &serv_addr,0, sizeof(serv_addr));
992        portno = 1025;
993        serv_addr.sin_family = AF_INET;
994        serv_addr.sin_addr.s_addr = INADDR_ANY;
995        do
996        {
997          portno++;
998          serv_addr.sin_port = htons(portno);
999          if(portno > 50000)
1000          {
1001            WerrorS("ERROR on binding (no free port available?)");
1002            l->data=NULL;
1003            return TRUE;
1004          }
1005        }
1006        while(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0);
1007        //Print("waiting on port %d\n", portno);mflush();
1008        listen(sockfd,1);
1009        char* cli_host = (char*)omAlloc(256);
1010        char* path = (char*)omAlloc(1024);
1011        int r = si_sscanf(l->name,"%255[^:]:%s",cli_host,path);
1012        if(r == 0)
1013        {
1014          WerrorS("ERROR: no host specified");
1015          l->data=NULL;
1016          omFree(d);
1017          omFree(path);
1018          omFree(cli_host);
1019          return TRUE;
1020        }
1021        else if(r == 1)
1022        {
1023          WarnS("program not specified, using /usr/local/bin/Singular");
1024          strcpy(path,"/usr/local/bin/Singular");
1025        }
1026        char* ssh_command = (char*)omAlloc(256);
1027        char* ser_host = (char*)omAlloc(64);
1028        gethostname(ser_host,64);
1029        sprintf(ssh_command,"ssh %s %s -q --batch --link=ssi --MPhost=%s --MPport=%d &",cli_host,path,ser_host,portno);
1030        //Print("client on %s started:%s\n",cli_host,path);
1031        omFree(path);
1032        omFree(cli_host);
1033        if (TEST_OPT_PROT) { Print("running >>%s<<\n",ssh_command); }
1034        system(ssh_command);
1035        omFree(ssh_command);
1036        omFree(ser_host);
1037        clilen = sizeof(cli_addr);
1038        newsockfd = si_accept(sockfd, (struct sockaddr *) &cli_addr, (socklen_t *)&clilen);
1039        if(newsockfd < 0)
1040        {
1041          WerrorS("ERROR on accept");
1042          l->data=NULL;
1043          omFree(d);
1044          return TRUE;
1045        }
1046        //PrintS("client accepted\n");
1047        d->fd_read = newsockfd;
1048        d->fd_write = newsockfd;
1049        d->f_read = s_open(newsockfd);
1050        d->f_write = fdopen(newsockfd, "w");
1051        si_close(sockfd);
1052        SI_LINK_SET_RW_OPEN_P(l);
1053        d->send_quit_at_exit=1;
1054        link_list newlink=(link_list)omAlloc(sizeof(link_struct));
1055        newlink->u=u;
1056        newlink->l=l;
1057        newlink->next=(void *)ssiToBeClosed;
1058        ssiToBeClosed=newlink;
1059        fprintf(d->f_write,"98 %d %d %u %u\n",SSI_VERSION,MAX_TOK,si_opt_1,si_opt_2);
1060      }
1061      // ----------------------------------------------------------------------
1062      else if(strcmp(mode,"connect")==0)
1063      {
1064        char* host = (char*)omAlloc(256);
1065        int sockfd, portno, n;
1066        struct sockaddr_in serv_addr;
1067        struct hostent *server;
1068
1069        si_sscanf(l->name,"%255[^:]:%d",host,&portno);
1070        //Print("connect to host %s, port %d\n",host,portno);mflush();
1071        if (portno!=0)
1072        {
1073          sockfd = socket(AF_INET, SOCK_STREAM, 0);
1074          if (sockfd < 0) { WerrorS("ERROR opening socket"); return TRUE; }
1075          server = gethostbyname(host);
1076          if (server == NULL) {  WerrorS("ERROR, no such host");  return TRUE; }
1077          memset((char *) &serv_addr, 0, sizeof(serv_addr));
1078          serv_addr.sin_family = AF_INET;
1079          memcpy((char *)&serv_addr.sin_addr.s_addr,
1080                (char *)server->h_addr,
1081                server->h_length);
1082          serv_addr.sin_port = htons(portno);
1083          if (si_connect(sockfd,(sockaddr*)&serv_addr,sizeof(serv_addr)) < 0)
1084          { Werror("ERROR connecting(errno=%d)",errno); return TRUE; }
1085          //PrintS("connected\n");mflush();
1086          d->f_read=s_open(sockfd);
1087          d->fd_read=sockfd;
1088          d->f_write=fdopen(sockfd,"w");
1089          d->fd_write=sockfd;
1090          SI_LINK_SET_RW_OPEN_P(l);
1091          omFree(host);
1092        }
1093        else
1094        {
1095          l->data=NULL;
1096          omFree(d);
1097          return TRUE;
1098        }
1099      }
1100      // ======================================================================
1101      else
1102      {
1103        // normal link to a file
1104        FILE *outfile;
1105        char *filename=l->name;
1106
1107        if(filename[0]=='>')
1108        {
1109          if (filename[1]=='>')
1110          {
1111            filename+=2;
1112            mode = "a";
1113          }
1114          else
1115          {
1116            filename++;
1117            mode="w";
1118          }
1119        }
1120        outfile=myfopen(filename,mode);
1121        if (outfile!=NULL)
1122        {
1123          if (strcmp(l->mode,"r")==0)
1124          {
1125            fclose(outfile);
1126            d->f_read=s_open_by_name(filename);
1127          }
1128          else
1129          {
1130            d->f_write = outfile;
1131            fprintf(d->f_write,"98 %d %d %u %u\n",SSI_VERSION,MAX_TOK,si_opt_1,si_opt_2);
1132          }
1133        }
1134        else
1135        {
1136          omFree(d);
1137          l->data=NULL;
1138          return TRUE;
1139        }
1140      }
1141    }
1142  }
1143
1144  return FALSE;
1145}
1146
1147//**************************************************************************/
1148BOOLEAN ssiPrepClose(si_link l)
1149{
1150  if (l!=NULL)
1151  {
1152    ssiInfo *d = (ssiInfo *)l->data;
1153    if (d!=NULL)
1154    {
1155      if (d->send_quit_at_exit)
1156      {
1157        fputs("99\n",d->f_write);
1158        fflush(d->f_write);
1159      }
1160      d->quit_sent=1;
1161    }
1162  }
1163  return FALSE;
1164}
1165
1166BOOLEAN ssiClose(si_link l)
1167{
1168  if (l!=NULL)
1169  {
1170    SI_LINK_SET_CLOSE_P(l);
1171    ssiInfo *d = (ssiInfo *)l->data;
1172    if (d!=NULL)
1173    {
1174      if ((d->send_quit_at_exit)
1175      && (d->quit_sent==0))
1176      {
1177        fputs("99\n",d->f_write);
1178        fflush(d->f_write);
1179      }
1180      if (d->r!=NULL) rKill(d->r);
1181      if ((d->pid!=0)
1182      && (si_waitpid(d->pid,NULL,WNOHANG)==0))
1183      {
1184        struct timespec t;
1185        t.tv_sec=0;
1186        t.tv_nsec=100000000; // <=100 ms
1187        struct timespec rem;
1188        int r;
1189        do
1190        {
1191          r = nanosleep(&t, &rem);
1192          t = rem;
1193        } while ((r < 0) && (errno == EINTR)
1194            && (si_waitpid(d->pid,NULL,WNOHANG) == 0));
1195        if ((r == 0) && (si_waitpid(d->pid,NULL,WNOHANG) == 0))
1196        {
1197          kill(d->pid,15);
1198          t.tv_sec=5; // <=5s
1199          t.tv_nsec=0;
1200          do
1201          {
1202            r = nanosleep(&t, &rem);
1203            t = rem;
1204          } while ((r < 0) && (errno == EINTR)
1205              && (si_waitpid(d->pid,NULL,WNOHANG) == 0));
1206          if ((r == 0) && (si_waitpid(d->pid,NULL,WNOHANG) == 0))
1207          {
1208            kill(d->pid,9); // just to be sure
1209            si_waitpid(d->pid,NULL,0);
1210          }
1211        }
1212      }
1213      if (d->f_read!=NULL) s_close(d->f_read);
1214      if (d->f_read!=NULL) s_free(d->f_read);
1215      if (d->f_write!=NULL) fclose(d->f_write);
1216      if ((strcmp(l->mode,"tcp")==0)
1217      || (strcmp(l->mode,"fork")==0))
1218      {
1219        link_list hh=ssiToBeClosed;
1220        if (hh!=NULL)
1221        {
1222          if (hh->l==l)
1223          {
1224             ssiToBeClosed=(link_list)hh->next;
1225             omFreeSize(hh,sizeof(link_struct));
1226          }
1227          else while(hh->next!=NULL)
1228          {
1229            link_list hhh=(link_list)hh->next;
1230            if (hhh->l==l)
1231            {
1232              hh->next=hhh->next;
1233              omFreeSize(hhh,sizeof(link_struct));
1234              break;
1235            }
1236            else
1237              hh=(link_list)hh->next;
1238          }
1239        }
1240      }
1241      omFreeSize((ADDRESS)d,(sizeof *d));
1242    }
1243    l->data=NULL;
1244  }
1245  return FALSE;
1246}
1247
1248//**************************************************************************/
1249leftv ssiRead1(si_link l)
1250{
1251  ssiInfo *d = (ssiInfo *)l->data;
1252  leftv res=(leftv)omAlloc0(sizeof(sleftv));
1253  int t=0;
1254  t=s_readint(d->f_read);
1255  //Print("got type %d\n",t);
1256  switch(t)
1257  {
1258    case 1:res->rtyp=INT_CMD;
1259           res->data=(char *)(long)ssiReadInt(d->f_read);
1260           break;
1261    case 2:res->rtyp=STRING_CMD;
1262           res->data=(char *)ssiReadString(d);
1263           break;
1264    case 3:res->rtyp=NUMBER_CMD;
1265           res->data=(char *)ssiReadNumber(d);
1266           break;
1267    case 4:res->rtyp=BIGINT_CMD;
1268           res->data=(char *)ssiReadBigInt(d);
1269           break;
1270    case 15:
1271    case 5:{
1272             d->r=ssiReadRing(d);
1273             res->rtyp=RING_CMD;
1274             res->data=(char*)d->r;
1275             // we are in the top-level, so set the basering to d->r:
1276             if (d->r!=NULL)
1277             {
1278               d->r->ref++;
1279               ssiSetCurrRing(d->r);
1280             }
1281             if (t==15) return ssiRead1(l);
1282           }
1283           break;
1284    case 6:res->rtyp=POLY_CMD;
1285           if (d->r==NULL) goto no_ring;
1286           res->data=(char*)ssiReadPoly(d);
1287           break;
1288    case 7:res->rtyp=IDEAL_CMD;
1289           if (d->r==NULL) goto no_ring;
1290           res->data=(char*)ssiReadIdeal(d);
1291           break;
1292    case 8:res->rtyp=MATRIX_CMD;
1293           if (d->r==NULL) goto no_ring;
1294           res->data=(char*)ssiReadMatrix(d);
1295           break;
1296    case 9:res->rtyp=VECTOR_CMD;
1297           if (d->r==NULL) goto no_ring;
1298           res->data=(char*)ssiReadPoly(d);
1299           break;
1300    case 10:res->rtyp=MODUL_CMD;
1301           if (d->r==NULL) goto no_ring;
1302           res->data=(char*)ssiReadIdeal(d);
1303           break;
1304    case 11:
1305           {
1306             res->rtyp=COMMAND;
1307             res->data=ssiReadCommand(l);
1308             int nok=res->Eval();
1309             if (nok) WerrorS("error in eval");
1310             break;
1311           }
1312    case 12: /*DEF_CMD*/
1313           {
1314             res->rtyp=0;
1315             res->name=(char *)ssiReadString(d);
1316             int nok=res->Eval();
1317             if (nok) WerrorS("error in name lookup");
1318             break;
1319           }
1320    case 13: res->rtyp=PROC_CMD;
1321             res->data=ssiReadProc(d);
1322             break;
1323    case 14: res->rtyp=LIST_CMD;
1324             res->data=ssiReadList(l);
1325             break;
1326    case 16: res->rtyp=NONE; res->data=NULL;
1327             break;
1328    case 17: res->rtyp=INTVEC_CMD;
1329             res->data=ssiReadIntvec(d);
1330             break;
1331    case 18: res->rtyp=INTMAT_CMD;
1332             res->data=ssiReadIntmat(d);
1333             break;
1334    case 19: res->rtyp=BIGINTMAT_CMD;
1335             res->data=ssiReadBigintmat(d);
1336             break;
1337    case 20: ssiReadBlackbox(res,l);
1338             break;
1339    // ------------
1340    case 98: // version
1341             {
1342                int n98_v,n98_m;
1343                BITSET n98_o1,n98_o2;
1344                n98_v=s_readint(d->f_read);
1345                n98_m=s_readint(d->f_read);
1346                n98_o1=s_readint(d->f_read);
1347                n98_o2=s_readint(d->f_read);
1348                if ((n98_v!=SSI_VERSION) ||(n98_m!=MAX_TOK))
1349                {
1350                  Print("incompatible versions of ssi: %d/%d vs %d/%d",
1351                                  SSI_VERSION,MAX_TOK,n98_v,n98_m);
1352                }
1353                #ifndef SING_NDEBUG
1354                if (TEST_OPT_DEBUG)
1355                  Print("// opening ssi-%d, MAX_TOK=%d\n",n98_v,n98_m);
1356                #endif
1357                si_opt_1=n98_o1;
1358                si_opt_2=n98_o2;
1359                return ssiRead1(l);
1360             }
1361    case 99: ssiClose(l); m2_end(0);
1362    case 0: if (s_iseof(d->f_read))
1363            {
1364              ssiClose(l);
1365              res->rtyp=DEF_CMD;
1366              break;
1367            }
1368    default: Werror("not implemented (t:%d)",t);
1369             omFreeSize(res,sizeof(sleftv));
1370             res=NULL;
1371             break;
1372  }
1373  return res;
1374no_ring: WerrorS("no ring");
1375  omFreeSize(res,sizeof(sleftv));
1376  return NULL;
1377}
1378//**************************************************************************/
1379BOOLEAN ssiSetRing(si_link l, ring r, BOOLEAN send)
1380{
1381  if(SI_LINK_W_OPEN_P(l)==0)
1382     if (slOpen(l,SI_LINK_OPEN|SI_LINK_WRITE,NULL)) return TRUE;
1383  ssiInfo *d = (ssiInfo *)l->data;
1384  if (d->r!=r)
1385  {
1386    if (send)
1387    {
1388      fputs("15 ",d->f_write);
1389      ssiWriteRing(d,r);
1390    }
1391    d->r=r;
1392  }
1393  if (currRing!=r) rChangeCurrRing(r);
1394  return FALSE;
1395}
1396//**************************************************************************/
1397
1398BOOLEAN ssiWrite(si_link l, leftv data)
1399{
1400  if(SI_LINK_W_OPEN_P(l)==0)
1401     if (slOpen(l,SI_LINK_OPEN|SI_LINK_WRITE,NULL)) return TRUE;
1402  ssiInfo *d = (ssiInfo *)l->data;
1403  d->level++;
1404  //FILE *fich=d->f;
1405  while (data!=NULL)
1406  {
1407    int tt=data->Typ();
1408    void *dd=data->Data();
1409    if ((dd==NULL) && (data->name!=NULL) && (tt==0)) tt=DEF_CMD;
1410      // return pure undefined names as def
1411
1412    switch(tt /*data->Typ()*/)
1413    {
1414          case NONE/* nothing*/:fputs("16 ",d->f_write);
1415                          break;
1416          case STRING_CMD: fputs("2 ",d->f_write);
1417                           ssiWriteString(d,(char *)dd);
1418                           break;
1419          case INT_CMD: fputs("1 ",d->f_write);
1420                        ssiWriteInt(d,(int)(long)dd);
1421                        break;
1422          case BIGINT_CMD:fputs("4 ",d->f_write);
1423                        ssiWriteBigInt(d,(number)dd);
1424                        break;
1425          case NUMBER_CMD:
1426                          if (d->r!=currRing)
1427                          {
1428                            fputs("15 ",d->f_write);
1429                            ssiWriteRing(d,currRing);
1430                            if (d->level<=1) fputc('\n',d->f_write);
1431                          }
1432                          fputs("3 ",d->f_write);
1433                          ssiWriteNumber(d,(number)dd);
1434                        break;
1435          case RING_CMD:fputs("5 ",d->f_write);
1436                        ssiWriteRing(d,(ring)dd);
1437                        break;
1438          case POLY_CMD:
1439          case VECTOR_CMD:
1440                        if (d->r!=currRing)
1441                        {
1442                          fputs("15 ",d->f_write);
1443                          ssiWriteRing(d,currRing);
1444                          if (d->level<=1) fputc('\n',d->f_write);
1445                        }
1446                        if(tt==POLY_CMD) fputs("6 ",d->f_write);
1447                        else             fputs("9 ",d->f_write);
1448                        ssiWritePoly(d,tt,(poly)dd);
1449                        break;
1450          case IDEAL_CMD:
1451          case MODUL_CMD:
1452          case MATRIX_CMD:
1453                        if (d->r!=currRing)
1454                        {
1455                          fputs("15 ",d->f_write);
1456                          ssiWriteRing(d,currRing);
1457                          if (d->level<=1) fputc('\n',d->f_write);
1458                        }
1459                        if(tt==IDEAL_CMD)       fputs("7 ",d->f_write);
1460                        else if(tt==MATRIX_CMD) fputs("8 ",d->f_write);
1461                        else                    fputs("10 ",d->f_write);
1462                        ssiWriteIdeal(d,tt,(ideal)dd);
1463                        break;
1464          case COMMAND:
1465                   fputs("11 ",d->f_write);
1466                   ssiWriteCommand(l,(command)dd);
1467                   break;
1468          case DEF_CMD: /* not evaluated stuff in quotes */
1469                   fputs("12 ",d->f_write);
1470                   ssiWriteString(d,data->Name());
1471                   break;
1472          case PROC_CMD:
1473                   fputs("13 ",d->f_write);
1474                   ssiWriteProc(d,(procinfov)dd);
1475                   break;
1476          case LIST_CMD:
1477                   fputs("14 ",d->f_write);
1478                   ssiWriteList(l,(lists)dd);
1479                   break;
1480          case INTVEC_CMD:
1481                   fputs("17 ",d->f_write);
1482                   ssiWriteIntvec(d,(intvec *)dd);
1483                   break;
1484          case INTMAT_CMD:
1485                   fputs("18 ",d->f_write);
1486                   ssiWriteIntmat(d,(intvec *)dd);
1487                   break;
1488          case BIGINTMAT_CMD:
1489                   fputs("19 ",d->f_write);
1490                   ssiWriteBigintmat(d,(bigintmat *)dd);
1491                   break;
1492          default:
1493            if (tt>MAX_TOK)
1494            {
1495              blackbox *b=getBlackboxStuff(tt);
1496              fputs("20 ",d->f_write);
1497              b->blackbox_serialize(b,dd,l);
1498            }
1499            else
1500            {
1501              Werror("not implemented (t:%d, rtyp:%d)",tt, data->rtyp);
1502              d->level=0;
1503              return TRUE;
1504            }
1505            break;
1506    }
1507    if (d->level<=1) { fputc('\n',d->f_write); fflush(d->f_write); }
1508    data=data->next;
1509  }
1510  d->level--;
1511  return FALSE;
1512}
1513
1514BOOLEAN ssiGetDump(si_link l);
1515BOOLEAN ssiDump(si_link l);
1516
1517si_link_extension slInitSsiExtension(si_link_extension s)
1518{
1519  s->Open=ssiOpen;
1520  s->Close=ssiClose;
1521  s->Kill=ssiClose;
1522  s->Read=ssiRead1;
1523  s->Read2=(slRead2Proc)NULL;
1524  s->Write=ssiWrite;
1525  s->Dump=ssiDump;
1526  s->GetDump=ssiGetDump;
1527
1528  s->Status=slStatusSsi;
1529  s->SetRing=ssiSetRing;
1530  s->type="ssi";
1531  return s;
1532}
1533
1534const char* slStatusSsi(si_link l, const char* request)
1535{
1536  ssiInfo *d=(ssiInfo*)l->data;
1537  if (d==NULL) return "not open";
1538  if (((strcmp(l->mode,"fork")==0)
1539  ||(strcmp(l->mode,"tcp")==0)
1540  ||(strcmp(l->mode,"connect")==0))
1541  && (strcmp(request, "read") == 0))
1542  {
1543    fd_set  mask, fdmask;
1544    struct timeval wt;
1545    if (s_isready(d->f_read)) return "ready";
1546    loop
1547    {
1548      /* Don't block. Return socket status immediately. */
1549      wt.tv_sec  = 0;
1550      wt.tv_usec = 0;
1551
1552      FD_ZERO(&mask);
1553      FD_SET(d->fd_read, &mask);
1554      //Print("test fd %d\n",d->fd_read);
1555    /* check with select: chars waiting: no -> not ready */
1556      switch (si_select(d->fd_read+1, &mask, NULL, NULL, &wt))
1557      {
1558        case 0: /* not ready */ return "not ready";
1559        case -1: /*error*/      return "error";
1560        case 1: /*ready ? */    break;
1561      }
1562    /* yes: read 1 char*/
1563    /* if \n, check again with select else ungetc(c), ready*/
1564      int c=s_getc(d->f_read);
1565      //Print("try c=%d\n",c);
1566      if (c== -1) return "eof"; /* eof or error */
1567      else if (isdigit(c))
1568      { s_ungetc(c,d->f_read); return "ready"; }
1569      else if (c>' ')
1570      {
1571        Werror("unknown char in ssiLink(%d)",c);
1572        return "error";
1573      }
1574      /* else: next char */
1575    }
1576  }
1577  else if (strcmp(request, "read") == 0)
1578  {
1579    if (SI_LINK_R_OPEN_P(l) && (!s_iseof(d->f_read)) && (s_isready(d->f_read))) return "ready";
1580    else return "not ready";
1581  }
1582  else if (strcmp(request, "write") == 0)
1583  {
1584    if (SI_LINK_W_OPEN_P(l)) return "ready";
1585    else return "not ready";
1586  }
1587  else return "unknown status request";
1588}
1589
1590int slStatusSsiL(lists L, int timeout)
1591{
1592// input: L: a list with links of type
1593//           ssi-connect, ssi-fork, ssi-tcp, MPtcp-fork or MPtcp-launch.
1594//           Note: Not every entry in L must be set.
1595//        timeout: timeout for select in micro-seconds
1596//           or -1 for infinity
1597//           or 0 for polling
1598// returns: ERROR (via Werror): L has wrong elements or link not open
1599//           -2: select returns an error
1600//           -1: the read state of all links is eof
1601//           0:  timeout (or polling): none ready,
1602//           i>0: (at least) L[i] is ready
1603  si_link l;
1604  ssiInfo *d;
1605  int d_fd;
1606  fd_set  mask, fdmask;
1607  FD_ZERO(&fdmask);
1608  FD_ZERO(&mask);
1609  int max_fd=0; /* 1 + max fd in fd_set */
1610
1611  /* timeout */
1612  struct timeval wt;
1613  struct timeval *wt_ptr=&wt;
1614  int startingtime = getRTimer()/TIMER_RESOLUTION;  // in seconds
1615  if (timeout== -1)
1616  {
1617    wt_ptr=NULL;
1618  }
1619  else
1620  {
1621    wt.tv_sec  = timeout / 1000000;
1622    wt.tv_usec = timeout % 1000000;
1623  }
1624
1625  /* auxiliary variables */
1626  int i;
1627  int j;
1628  int k;
1629  int s;
1630  char fdmaskempty;
1631
1632  /* check the links and fill in fdmask */
1633  /* check ssi links for ungetc_buf */
1634  for(i=L->nr; i>=0; i--)
1635  {
1636    if (L->m[i].Typ()!=DEF_CMD)
1637    {
1638      if (L->m[i].Typ()!=LINK_CMD)
1639      { WerrorS("all elements must be of type link"); return -2;}
1640      l=(si_link)L->m[i].Data();
1641      if(SI_LINK_OPEN_P(l)==0)
1642      { WerrorS("all links must be open"); return -2;}
1643      if (((strcmp(l->m->type,"ssi")!=0) && (strcmp(l->m->type,"MPtcp")!=0))
1644      || ((strcmp(l->mode,"fork")!=0) && (strcmp(l->mode,"tcp")!=0)
1645        && (strcmp(l->mode,"launch")!=0) && (strcmp(l->mode,"connect")!=0)))
1646      {
1647        WerrorS("all links must be of type ssi:fork, ssi:tcp, ssi:connect");
1648        return -2;
1649      }
1650      if (strcmp(l->m->type,"ssi")==0)
1651      {
1652        d=(ssiInfo*)l->data;
1653        d_fd=d->fd_read;
1654        if (!s_isready(d->f_read))
1655        {
1656          FD_SET(d_fd, &fdmask);
1657          if (d_fd > max_fd) max_fd=d_fd;
1658        }
1659        else
1660          return i+1;
1661      }
1662      else
1663      {
1664        Werror("wrong link type >>%s<<",l->m->type);
1665        return -2;
1666      }
1667    }
1668  }
1669  max_fd++;
1670
1671do_select:
1672  /* copy fdmask to mask */
1673  FD_ZERO(&mask);
1674  for(k = 0; k < max_fd; k++)
1675  {
1676    if(FD_ISSET(k, &fdmask))
1677    {
1678      FD_SET(k, &mask);
1679    }
1680  }
1681
1682  /* check with select: chars waiting: no -> not ready */
1683  s = si_select(max_fd, &mask, NULL, NULL, wt_ptr);
1684  if (s==-1)
1685  {
1686    WerrorS("error in select call");
1687    return -2; /*error*/
1688  }
1689  if (s==0)
1690  {
1691    return 0; /*poll: not ready */
1692  }
1693  else /* s>0, at least one ready  (the number of fd which are ready is s)*/
1694  {
1695    j=0;
1696    while (j<=max_fd) { if (FD_ISSET(j,&mask)) break; j++; }
1697    for(i=L->nr; i>=0; i--)
1698    {
1699      if (L->m[i].rtyp==LINK_CMD)
1700      {
1701        l=(si_link)L->m[i].Data();
1702        if (strcmp(l->m->type,"ssi")==0)
1703        {
1704          d=(ssiInfo*)l->data;
1705          d_fd=d->fd_read;
1706          if(j==d_fd) break;
1707        }
1708        else
1709        {
1710          Werror("wrong link type >>%s<<",l->m->type);
1711          return -2;
1712        }
1713      }
1714    }
1715    // only ssi links:
1716    loop
1717    {
1718      /* yes: read 1 char*/
1719      /* if \n, check again with select else ungetc(c), ready*/
1720      /* setting: d: current ssiInfo, j current fd, i current entry in L*/
1721      int c=s_getc(d->f_read);
1722      //Print("try c=%d\n",c);
1723      if (c== -1) /* eof */
1724      {
1725        FD_CLR(j,&fdmask);
1726        fdmaskempty = 1;
1727        for(k = 0; k < max_fd; k++)
1728        {
1729          if(FD_ISSET(k, &fdmask))
1730          {
1731            fdmaskempty = 0;
1732            break;
1733          }
1734        }
1735        if(fdmaskempty)
1736        {
1737          return -1;
1738        }
1739        if(timeout != -1)
1740        {
1741          timeout = si_max(0,
1742             timeout - 1000000*(getRTimer()/TIMER_RESOLUTION - startingtime));
1743          wt.tv_sec  = timeout / 1000000;
1744          wt.tv_usec = (timeout % 1000000);
1745        }
1746        goto do_select;
1747      }
1748
1749      else if (isdigit(c))
1750      { s_ungetc(c,d->f_read); return i+1; }
1751      else if (c>' ')
1752      {
1753        Werror("unknown char in ssiLink(%d)",c);
1754        return -2;
1755      }
1756      /* else: next char */
1757    }
1758  }
1759}
1760
1761int ssiBatch(const char *host, const char * port)
1762/* return 0 on success, >0 else*/
1763{
1764  si_link l=(si_link) omAlloc0Bin(sip_link_bin);
1765  char *buf=(char*)omAlloc(256);
1766  sprintf(buf,"ssi:connect %s:%s",host,port);
1767  slInit(l, buf);
1768  if (slOpen(l,SI_LINK_OPEN,NULL)) return 1;
1769  SI_LINK_SET_RW_OPEN_P(l);
1770
1771  idhdl id = enterid(omStrDup("link_ll"), 0, LINK_CMD, &IDROOT, FALSE);
1772  IDLINK(id) = l;
1773
1774  loop
1775  {
1776    leftv h=ssiRead1(l); /*contains an exit.... */
1777    if (feErrors != NULL && *feErrors != '\0')
1778    {
1779      // handle errors:
1780      PrintS(feErrors); /* currently quite simple */
1781      *feErrors = '\0';
1782    }
1783    ssiWrite(l,h);
1784    h->CleanUp();
1785    omFreeBin(h, sleftv_bin);
1786  }
1787  /* never reached*/
1788  exit(0);
1789}
1790
1791static int ssiReserved_P=0;
1792static int ssiReserved_sockfd;
1793static  struct sockaddr_in ssiResverd_serv_addr;
1794static int  ssiReserved_Clients;
1795int ssiReservePort(int clients)
1796{
1797  if (ssiReserved_P!=0)
1798  {
1799    WerrorS("ERROR already a reverved port requested");
1800    return 0;
1801  }
1802  int portno;
1803  int n;
1804  ssiReserved_sockfd = socket(AF_INET, SOCK_STREAM, 0);
1805  if(ssiReserved_sockfd < 0)
1806  {
1807    WerrorS("ERROR opening socket");
1808    return 0;
1809  }
1810  memset((char *) &ssiResverd_serv_addr,0, sizeof(ssiResverd_serv_addr));
1811  portno = 1025;
1812  ssiResverd_serv_addr.sin_family = AF_INET;
1813  ssiResverd_serv_addr.sin_addr.s_addr = INADDR_ANY;
1814  do
1815  {
1816    portno++;
1817    ssiResverd_serv_addr.sin_port = htons(portno);
1818    if(portno > 50000)
1819    {
1820      WerrorS("ERROR on binding (no free port available?)");
1821      return 0;
1822    }
1823  }
1824  while(bind(ssiReserved_sockfd, (struct sockaddr *) &ssiResverd_serv_addr, sizeof(ssiResverd_serv_addr)) < 0);
1825  ssiReserved_P=portno;
1826  listen(ssiReserved_sockfd,clients);
1827  ssiReserved_Clients=clients;
1828  return portno;
1829}
1830
1831extern si_link_extension si_link_root;
1832si_link ssiCommandLink()
1833{
1834  if (ssiReserved_P==0)
1835  {
1836    WerrorS("ERROR no reverved port requested");
1837    return NULL;
1838  }
1839  struct sockaddr_in cli_addr;
1840  int clilen = sizeof(cli_addr);
1841  int newsockfd = si_accept(ssiReserved_sockfd, (struct sockaddr *) &cli_addr, (socklen_t *)&clilen);
1842  if(newsockfd < 0)
1843  {
1844    Werror("ERROR on accept (errno=%d)",errno);
1845    return NULL;
1846  }
1847  si_link l=(si_link) omAlloc0Bin(sip_link_bin);
1848  si_link_extension s = si_link_root;
1849  si_link_extension prev = s;
1850  while (strcmp(s->type, "ssi") != 0)
1851  {
1852    if (s->next == NULL)
1853    {
1854      prev = s;
1855      s = NULL;
1856      break;
1857    }
1858    else
1859    {
1860      s = s->next;
1861    }
1862  }
1863  if (s != NULL)
1864    l->m = s;
1865  else
1866  {
1867    si_link_extension ns = (si_link_extension)omAlloc0Bin(s_si_link_extension_bin);
1868    prev->next=slInitSsiExtension(ns);
1869    l->m = prev->next;
1870  }
1871  l->name=omStrDup("");
1872  l->mode=omStrDup("tcp");
1873  l->ref=1;
1874  ssiInfo *d=(ssiInfo*)omAlloc0(sizeof(ssiInfo));
1875  l->data=d;
1876  d->fd_read = newsockfd;
1877  d->fd_write = newsockfd;
1878  d->f_read = s_open(newsockfd);
1879  d->f_write = fdopen(newsockfd, "w");
1880  SI_LINK_SET_RW_OPEN_P(l);
1881  ssiReserved_Clients--;
1882  if (ssiReserved_Clients<=0)
1883  {
1884    ssiReserved_P=0;
1885    si_close(ssiReserved_sockfd);
1886  }
1887  return l;
1888}
1889/*---------------------------------------------------------------------*/
1890/**
1891 * @brief additional default signal handler
1892
1893  // some newer Linux version cannot have SIG_IGN for SIGCHLD,
1894  // so use this nice routine here:
1895  //  SuSe 9.x reports -1 always
1896  //  Redhat 9.x/FC x reports sometimes -1
1897  // see also: hpux_system
1898  // also needed by getrusage (timer etc.)
1899
1900 @param[in] sig
1901**/
1902/*---------------------------------------------------------------------*/
1903void sig_chld_hdl(int sig)
1904{
1905  pid_t kidpid;
1906  int status;
1907
1908  loop
1909  {
1910    kidpid = si_waitpid(-1, &status, WNOHANG);
1911    if (kidpid==-1)
1912    {
1913      /* continue on interruption (EINTR): */
1914      if (errno == EINTR) continue;
1915      /* break on anything else (EINVAL or ECHILD according to manpage): */
1916      break;
1917    }
1918    else if (kidpid==0) break; /* no more children to process, so break */
1919
1920    //printf("Child %ld terminated\n", kidpid);
1921    link_list hh=ssiToBeClosed;
1922    while((hh!=NULL)&&(ssiToBeClosed_inactive))
1923    {
1924      if((hh->l!=NULL) && (hh->l->m->Open==ssiOpen))
1925      {
1926        ssiInfo *d = (ssiInfo *)hh->l->data;
1927        if(d->pid==kidpid)
1928        {
1929          if(ssiToBeClosed_inactive)
1930          {
1931            ssiToBeClosed_inactive=FALSE;
1932            slClose(hh->l);
1933            ssiToBeClosed_inactive=TRUE;
1934            break;
1935          }
1936          else break;
1937        }
1938        else hh=(link_list)hh->next;
1939      }
1940      else hh=(link_list)hh->next;
1941    }
1942  }
1943}
1944
1945static BOOLEAN DumpSsiIdhdl(si_link l, idhdl h)
1946{
1947  int type_id = IDTYP(h);
1948
1949  // C-proc not to be dumped, also LIB-proc not
1950  if (type_id == PROC_CMD)
1951  {
1952    if (IDPROC(h)->language == LANG_C) return FALSE;
1953    if (IDPROC(h)->libname != NULL) return FALSE;
1954  }
1955  // do not dump links
1956  if (type_id == LINK_CMD) return FALSE;
1957
1958  // do not dump ssi internal rings: ssiRing*
1959  if ((type_id == RING_CMD) && (strncmp(IDID(h),"ssiRing",7)==0))
1960    return FALSE;
1961
1962  command D=(command)omAlloc0(sizeof(*D));
1963  sleftv tmp;
1964  memset(&tmp,0,sizeof(tmp));
1965  tmp.rtyp=COMMAND;
1966  tmp.data=D;
1967
1968  if (type_id == PACKAGE_CMD)
1969  {
1970    // do not dump Top
1971    if (strcmp(IDID(h), "Top") == 0) return FALSE;
1972    package p=(package)IDDATA(h);
1973    // dump Singular-packages as load("...");
1974    if (p->language==LANG_SINGULAR)
1975    {
1976      D->op=LOAD_CMD;
1977      D->argc=1;
1978      D->arg1.rtyp=STRING_CMD;
1979      D->arg1.data=p->libname;
1980      ssiWrite(l,&tmp);
1981      omFree(D);
1982      return FALSE;
1983    }
1984  }
1985
1986  // handle qrings separately
1987  //if (type_id == QRING_CMD)
1988  //  return DumpSsiQringQring(l, h);
1989
1990  // put type and name
1991  //Print("generic dump:%s,%s\n",IDID(h),Tok2Cmdname(IDTYP(h)));
1992  D->op='=';
1993  D->argc=2;
1994  D->arg1.rtyp=DEF_CMD;
1995  D->arg1.name=IDID(h);
1996  D->arg2.rtyp=IDTYP(h);
1997  D->arg2.data=IDDATA(h);
1998  ssiWrite(l,&tmp);
1999  omFree(D);
2000  return FALSE;
2001}
2002static BOOLEAN ssiDumpIter(si_link l, idhdl h)
2003{
2004  if (h == NULL) return FALSE;
2005
2006  if (ssiDumpIter(l, IDNEXT(h))) return TRUE;
2007
2008  // need to set the ring before writing it, otherwise we get in
2009  // trouble with minpoly
2010  if (IDTYP(h) == RING_CMD || IDTYP(h) == QRING_CMD)
2011    rSetHdl(h);
2012
2013  if (DumpSsiIdhdl(l, h)) return TRUE;
2014
2015  // do not dump ssi internal rings: ssiRing*
2016  // but dump objects of all other rings
2017  if ((IDTYP(h) == RING_CMD || IDTYP(h) == QRING_CMD)
2018  && (strncmp(IDID(h),"ssiRing",7)!=0))
2019    return ssiDumpIter(l, IDRING(h)->idroot);
2020  else
2021    return FALSE;
2022}
2023BOOLEAN ssiDump(si_link l)
2024{
2025  idhdl h = IDROOT, rh = currRingHdl;
2026  BOOLEAN status = ssiDumpIter(l, h);
2027
2028  //if (! status ) status = DumpAsciiMaps(fd, h, NULL);
2029
2030  if (currRingHdl != rh) rSetHdl(rh);
2031  //fprintf(fd, "option(set, intvec(%d, %d));\n", si_opt_1, si_opt_2);
2032
2033  return status;
2034}
2035BOOLEAN ssiGetDump(si_link l)
2036{
2037  ssiInfo *d=(ssiInfo*)l->data;
2038  loop
2039  {
2040    if (!SI_LINK_OPEN_P(l)) break;
2041    if (s_iseof(d->f_read)) break;
2042    leftv h=ssiRead1(l); /*contains an exit.... */
2043    if (feErrors != NULL && *feErrors != '\0')
2044    {
2045      // handle errors:
2046      PrintS(feErrors); /* currently quite simple */
2047      return TRUE;
2048      *feErrors = '\0';
2049    }
2050    h->CleanUp();
2051    omFreeBin(h, sleftv_bin);
2052  }
2053  return FALSE;
2054}
2055// ----------------------------------------------------------------
2056// format
2057// 1 int %d
2058// 2 string <len> %s
2059// 3 number
2060// 4 bigint 4 %d or 3 <mpz_t>
2061// 5 ring
2062// 6 poly
2063// 7 ideal
2064// 8 matrix
2065// 9 vector
2066// 10 module
2067// 11 command
2068// 12 def <len> %s
2069// 13 proc <len> %s
2070// 14 list %d <elem1> ....
2071// 15 setring .......
2072// 16 nothing
2073// 17 intvec <len> ...
2074// 18 intmat
2075// 19 bigintmat <r> <c> ...
2076//
2077// 20 blackbox <name> 1 <len> ...
2078//
2079// 98: verify version: <ssi-version> <MAX_TOK> <OPT1> <OPT2>
2080// 99: quit Singular
Note: See TracBrowser for help on using the repository browser.