source: git/Singular/misc_ip.cc @ 3c0710

spielwiese
Last change on this file since 3c0710 was 3c0710, checked in by Hans Schoenemann <hannes@…>, 7 years ago
4-1-0: sources
  • Property mode set to 100644
File size: 33.8 KB
Line 
1/*****************************************************************************\
2 * Computer Algebra System SINGULAR
3\*****************************************************************************/
4/** @file misc_ip.cc
5 *
6 * This file provides miscellaneous functionality.
7 *
8 * For more general information, see the documentation in misc_ip.h.
9 *
10 **/
11/*****************************************************************************/
12
13// include header files
14#define PLURAL_INTERNAL_DECLARATIONS 1
15
16#include <kernel/mod2.h>
17#include <misc/sirandom.h>
18
19#include <reporter/si_signals.h>
20
21#include <factory/factory.h>
22
23#include <coeffs/si_gmp.h>
24#include <coeffs/coeffs.h>
25#include <coeffs/OPAE.h>
26#include <coeffs/OPAEQ.h>
27#include <coeffs/OPAEp.h>
28#include <coeffs/flintcf_Q.h>
29#include <coeffs/flintcf_Zn.h>
30
31#include <polys/ext_fields/algext.h>
32#include <polys/ext_fields/transext.h>
33#include <polys/nc/gb_hack.h>
34
35#ifdef HAVE_SIMPLEIPC
36#include <Singular/links/simpleipc.h>
37#endif
38
39#include "misc_ip.h"
40#include "ipid.h"
41#include "feOpt.h"
42#include "links/silink.h"
43#include "mod_lib.h"
44#include <Singular/distrib.h>
45
46static FORCE_INLINE void number2mpz(number n, mpz_t m){ number2mpz(n, coeffs_BIGINT, m); }
47static FORCE_INLINE number mpz2number(mpz_t m){ return mpz2number(m, coeffs_BIGINT); }
48
49
50void setListEntry(lists L, int index, mpz_t n)
51{ /* assumes n > 0 */
52  /* try to fit nn into an int: */
53  if (mpz_size1(n)<=1)
54  {
55    int ui=(int)mpz_get_si(n);
56    if ((((ui<<3)>>3)==ui)
57    && (mpz_cmp_si(n,(long)ui)==0))
58    {
59      L->m[index].rtyp = INT_CMD; L->m[index].data = (void*)(long)ui;
60      return;
61    }
62  }
63  number nn = mpz2number(n);
64  L->m[index].rtyp = BIGINT_CMD; L->m[index].data = (void*)nn;
65}
66
67void setListEntry_ui(lists L, int index, unsigned long ui)
68{ /* assumes n > 0 */
69  /* try to fit nn into an int: */
70  int i=(int)ui;
71  if ((((unsigned long)i)==ui) && (((i<<3)>>3)==i))
72  {
73    L->m[index].rtyp = INT_CMD; L->m[index].data = (void*)(long)i;
74  }
75  else
76  {
77    number nn = n_Init(ui, coeffs_BIGINT);
78    L->m[index].rtyp = BIGINT_CMD; L->m[index].data = (void*)nn;
79  }
80}
81
82/* Factoring with Pollard's rho method. stolen from GMP/demos */
83static unsigned add[] = {4, 2, 4, 2, 4, 6, 2, 6};
84
85static int factor_using_division (mpz_t t, unsigned int limit,lists primes, int *multiplicities,int &index, unsigned long bound)
86{
87  mpz_t q, r;
88  unsigned long int f;
89  int ai;
90  unsigned *addv = add;
91  unsigned int failures;
92  int bound_not_reached=1;
93
94  mpz_init (q);
95  mpz_init (r);
96
97  f = mpz_scan1 (t, 0);
98  mpz_div_2exp (t, t, f);
99  if (f>0)
100  {
101    setListEntry_ui(primes, index, 2);
102    multiplicities[index++] = f;
103  }
104
105  f=0;
106  loop
107  {
108    mpz_tdiv_qr_ui (q, r, t, 3);
109    if (mpz_cmp_ui (r, 0) != 0)
110        break;
111    mpz_set (t, q);
112    f++;
113  }
114  if (f>0)
115  {
116    setListEntry_ui(primes, index, 3);
117    multiplicities[index++] = f;
118  }
119  f=0;
120  loop
121  {
122    mpz_tdiv_qr_ui (q, r, t, 5);
123    if (mpz_cmp_ui (r, 0) != 0)
124        break;
125    mpz_set (t, q);
126    f++;
127  }
128  if (f>0)
129  {
130    setListEntry_ui(primes, index, 5);
131    multiplicities[index++] = f;
132  }
133
134  failures = 0;
135  f = 7;
136  ai = 0;
137  unsigned long last_f=0;
138  while (mpz_cmp_ui (t, 1) != 0)
139  {
140    mpz_tdiv_qr_ui (q, r, t, f);
141    if (mpz_cmp_ui (r, 0) != 0)
142    {
143      f += addv[ai];
144      if (mpz_cmp_ui (t, f) < 0)
145        break;
146      ai = (ai + 1) & 7;
147      failures++;
148      if (failures > limit)
149        break;
150      if ((bound!=0) && (f>bound))
151      {
152        bound_not_reached=0;
153        break;
154      }
155    }
156    else
157    {
158      mpz_swap (t, q);
159      if (f!=last_f)
160      {
161        setListEntry_ui(primes, index, f);
162        multiplicities[index]++;
163        index++;
164      }
165      else
166      {
167        multiplicities[index-1]++;
168      }
169      last_f=f;
170      failures = 0;
171    }
172  }
173
174  mpz_clear (q);
175  mpz_clear (r);
176  //printf("bound=%d,f=%d,failures=%d, reached=%d\n",bound,f,failures,bound_not_reached);
177  return bound_not_reached;
178}
179
180static void factor_using_pollard_rho (mpz_t n, unsigned long a, lists primes, int * multiplicities,int &index)
181{
182  mpz_t x, x1, y, P;
183  mpz_t t1, t2;
184  mpz_t last_f;
185  unsigned long long k, l, i;
186
187  mpz_init (t1);
188  mpz_init (t2);
189  mpz_init_set_si (last_f, 0);
190  mpz_init_set_si (y, 2);
191  mpz_init_set_si (x, 2);
192  mpz_init_set_si (x1, 2);
193  mpz_init_set_ui (P, 1);
194  k = 1;
195  l = 1;
196
197  while (mpz_cmp_ui (n, 1) != 0)
198  {
199    loop
200    {
201      do
202      {
203        mpz_mul (t1, x, x);
204        mpz_mod (x, t1, n);
205        mpz_add_ui (x, x, a);
206        mpz_sub (t1, x1, x);
207        mpz_mul (t2, P, t1);
208        mpz_mod (P, t2, n);
209
210        if (k % 32 == 1)
211        {
212          mpz_gcd (t1, P, n);
213          if (mpz_cmp_ui (t1, 1) != 0)
214            goto factor_found;
215          mpz_set (y, x);
216        }
217      }
218      while (--k != 0);
219
220      mpz_gcd (t1, P, n);
221      if (mpz_cmp_ui (t1, 1) != 0)
222        goto factor_found;
223
224      mpz_set (x1, x);
225      k = l;
226      l = 2 * l;
227      for (i = 0; i < k; i++)
228      {
229        mpz_mul (t1, x, x);
230        mpz_mod (x, t1, n);
231        mpz_add_ui (x, x, a);
232      }
233      mpz_set (y, x);
234    }
235
236  factor_found:
237    do
238    {
239      mpz_mul (t1, y, y);
240      mpz_mod (y, t1, n);
241      mpz_add_ui (y, y, a);
242      mpz_sub (t1, x1, y);
243      mpz_gcd (t1, t1, n);
244    }
245    while (mpz_cmp_ui (t1, 1) == 0);
246
247    mpz_divexact (n, n, t1);        /* divide by t1, before t1 is overwritten */
248
249    if (!mpz_probab_prime_p (t1, 10))
250    {
251      do
252      {
253        mp_limb_t a_limb;
254        mpn_random (&a_limb, (mp_size_t) 1);
255        a = a_limb;
256      }
257      while (a == 0);
258
259      factor_using_pollard_rho (t1, a, primes,multiplicities,index);
260    }
261    else
262    {
263      if (mpz_cmp(t1,last_f)==0)
264      {
265        multiplicities[index-1]++;
266      }
267      else
268      {
269        mpz_set(last_f,t1);
270        setListEntry(primes, index, t1);
271        multiplicities[index++] = 1;
272      }
273    }
274    mpz_mod (x, x, n);
275    mpz_mod (x1, x1, n);
276    mpz_mod (y, y, n);
277    if (mpz_probab_prime_p (n, 10))
278    {
279      if (mpz_cmp(n,last_f)==0)
280      {
281        multiplicities[index-1]++;
282      }
283      else
284      {
285        mpz_set(last_f,n);
286        setListEntry(primes, index, n);
287        multiplicities[index++] = 1;
288      }
289      mpz_set_ui(n,1);
290      break;
291    }
292  }
293
294  mpz_clear (P);
295  mpz_clear (t2);
296  mpz_clear (t1);
297  mpz_clear (x1);
298  mpz_clear (x);
299  mpz_clear (y);
300  mpz_clear (last_f);
301}
302
303static void factor_gmp (mpz_t t,lists primes,int *multiplicities,int &index,unsigned long bound)
304{
305  unsigned int division_limit;
306
307  if (mpz_sgn (t) == 0)
308    return;
309
310  /* Set the trial division limit according the size of t.  */
311  division_limit = mpz_sizeinbase (t, 2);
312  if (division_limit > 1000)
313    division_limit = 1000 * 1000;
314  else
315    division_limit = division_limit * division_limit;
316
317  if (factor_using_division (t, division_limit,primes,multiplicities,index,bound))
318  {
319    if (mpz_cmp_ui (t, 1) != 0)
320    {
321      if (mpz_probab_prime_p (t, 10))
322      {
323        setListEntry(primes, index, t);
324        multiplicities[index++] = 1;
325        mpz_set_ui(t,1);
326      }
327      else
328        factor_using_pollard_rho (t, 1L, primes,multiplicities,index);
329    }
330  }
331}
332/* n and pBound are assumed to be bigint numbers */
333lists primeFactorisation(const number n, const int pBound)
334{
335  int i;
336  int index=0;
337  mpz_t nn; number2mpz(n, nn);
338  lists primes = (lists)omAllocBin(slists_bin); primes->Init(1000);
339  int* multiplicities = (int*)omAlloc0(1000*sizeof(int));
340  int positive=1;
341
342  if (!n_IsZero(n, coeffs_BIGINT))
343  {
344    if (!n_GreaterZero(n, coeffs_BIGINT))
345    {
346      positive=-1;
347      mpz_neg(nn,nn);
348    }
349    factor_gmp(nn,primes,multiplicities,index,pBound);
350  }
351
352  lists primesL = (lists)omAllocBin(slists_bin);
353  primesL->Init(index);
354  for (i = 0; i < index; i++)
355  {
356    primesL->m[i].rtyp = primes->m[i].rtyp;
357    primesL->m[i].data = primes->m[i].data;
358    primes->m[i].rtyp=0;
359    primes->m[i].data=NULL;
360  }
361  primes->Clean(NULL);
362
363  lists multiplicitiesL = (lists)omAllocBin(slists_bin);
364  multiplicitiesL->Init(index);
365  for (i = 0; i < index; i++)
366  {
367    multiplicitiesL->m[i].rtyp = INT_CMD;
368    multiplicitiesL->m[i].data = (void*)(long)multiplicities[i];
369  }
370  omFree(multiplicities);
371
372  lists L=(lists)omAllocBin(slists_bin);
373  L->Init(3);
374  if (positive==-1) mpz_neg(nn,nn);
375  L->m[0].rtyp = LIST_CMD; L->m[0].data = (void*)primesL;
376  L->m[1].rtyp = LIST_CMD; L->m[1].data = (void*)multiplicitiesL;
377  setListEntry(L, 2, nn);
378
379  mpz_clear(nn);
380
381  return L;
382}
383
384#include <omalloc/omalloc.h>
385#include <misc/mylimits.h>
386
387#include <misc/options.h>
388#include <misc/intvec.h>
389
390#include <polys/monomials/ring.h>
391#include <polys/templates/p_Procs.h>
392
393#include <kernel/GBEngine/kstd1.h>
394#include <kernel/oswrapper/timer.h>
395#include <resources/feResource.h>
396#include <kernel/oswrapper/feread.h>
397
398#include "subexpr.h"
399#include "cntrlc.h"
400#include "ipid.h"
401#include "ipshell.h"
402
403#include "fehelp.h"
404
405#ifdef HAVE_STATIC
406#undef HAVE_DYN_RL
407#endif
408
409//#ifdef HAVE_LIBPARSER
410//#  include "libparse.h"
411//#endif /* HAVE_LIBPARSER */
412
413
414/*2
415* the renice routine for very large jobs
416* works only on unix machines,
417* testet on : linux, HP 9.0
418*
419*#include <sys/times.h>
420*#include <sys/resource.h>
421*extern "C" int setpriority(int,int,int);
422*void very_nice()
423*{
424*#ifndef NO_SETPRIORITY
425*  setpriority(PRIO_PROCESS,0,19);
426*#endif
427*  sleep(10);
428*}
429*/
430
431#include <string.h>
432#include <unistd.h>
433#include <stdio.h>
434#include <stddef.h>
435#include <stdlib.h>
436#include <time.h>
437
438
439void singular_example(char *str)
440{
441  assume(str!=NULL);
442  char *s=str;
443  while (*s==' ') s++;
444  char *ss=s;
445  while (*ss!='\0') ss++;
446  while (*ss<=' ')
447  {
448    *ss='\0';
449    ss--;
450  }
451  idhdl h=IDROOT->get(s,myynest);
452  if ((h!=NULL) && (IDTYP(h)==PROC_CMD))
453  {
454    char *lib=iiGetLibName(IDPROC(h));
455    if((lib!=NULL)&&(*lib!='\0'))
456    {
457      Print("// proc %s from lib %s\n",s,lib);
458      s=iiGetLibProcBuffer(IDPROC(h), 2);
459      if (s!=NULL)
460      {
461        if (strlen(s)>5)
462        {
463          iiEStart(s,IDPROC(h));
464          omFree((ADDRESS)s);
465          return;
466        }
467        else omFree((ADDRESS)s);
468      }
469    }
470  }
471  else
472  {
473    char sing_file[MAXPATHLEN];
474    FILE *fd=NULL;
475    char *res_m=feResource('m', 0);
476    if (res_m!=NULL)
477    {
478      sprintf(sing_file, "%s/%s.sing", res_m, s);
479      fd = feFopen(sing_file, "r");
480    }
481    if (fd != NULL)
482    {
483
484      int old_echo = si_echo;
485      int length, got;
486      char* s;
487
488      fseek(fd, 0, SEEK_END);
489      length = ftell(fd);
490      fseek(fd, 0, SEEK_SET);
491      s = (char*) omAlloc((length+20)*sizeof(char));
492      got = fread(s, sizeof(char), length, fd);
493      fclose(fd);
494      if (got != length)
495      {
496        Werror("Error while reading file %s", sing_file);
497      }
498      else
499      {
500        s[length] = '\0';
501        strcat(s, "\n;return();\n\n");
502        si_echo = 2;
503        iiEStart(s, NULL);
504        si_echo = old_echo;
505      }
506      omFree(s);
507    }
508    else
509    {
510      Werror("no example for %s", str);
511    }
512  }
513}
514
515
516const struct soptionStruct optionStruct[]=
517{
518  {"prot",         Sy_bit(OPT_PROT),           ~Sy_bit(OPT_PROT)   },
519  {"redSB",        Sy_bit(OPT_REDSB),          ~Sy_bit(OPT_REDSB)   },
520  {"notBuckets",   Sy_bit(OPT_NOT_BUCKETS),    ~Sy_bit(OPT_NOT_BUCKETS)   },
521  {"notSugar",     Sy_bit(OPT_NOT_SUGAR),      ~Sy_bit(OPT_NOT_SUGAR)   },
522  {"interrupt",    Sy_bit(OPT_INTERRUPT),      ~Sy_bit(OPT_INTERRUPT)   },
523  {"sugarCrit",    Sy_bit(OPT_SUGARCRIT),      ~Sy_bit(OPT_SUGARCRIT)   },
524  {"teach",        Sy_bit(OPT_DEBUG),          ~Sy_bit(OPT_DEBUG)  },
525  {"notSyzMinim",  Sy_bit(OPT_NO_SYZ_MINIM),   ~Sy_bit(OPT_NO_SYZ_MINIM)  },
526  /* 9 return SB in syz, quotient, intersect */
527  {"returnSB",     Sy_bit(OPT_RETURN_SB),      ~Sy_bit(OPT_RETURN_SB)  },
528  {"fastHC",       Sy_bit(OPT_FASTHC),         ~Sy_bit(OPT_FASTHC)  },
529  /* 11-19 sort in L/T */
530  {"staircaseBound",Sy_bit(OPT_STAIRCASEBOUND),~Sy_bit(OPT_STAIRCASEBOUND)  },
531  {"multBound",    Sy_bit(OPT_MULTBOUND),      ~Sy_bit(OPT_MULTBOUND)  },
532  {"degBound",     Sy_bit(OPT_DEGBOUND),       ~Sy_bit(OPT_DEGBOUND)  },
533  /* 25 no redTail(p)/redTail(s) */
534  {"redTail",      Sy_bit(OPT_REDTAIL),        ~Sy_bit(OPT_REDTAIL)  },
535  {"redThrough",   Sy_bit(OPT_REDTHROUGH),     ~Sy_bit(OPT_REDTHROUGH)  },
536  {"lazy",         Sy_bit(OPT_OLDSTD),         ~Sy_bit(OPT_OLDSTD)  },
537  {"intStrategy",  Sy_bit(OPT_INTSTRATEGY),    ~Sy_bit(OPT_INTSTRATEGY)  },
538  {"infRedTail",   Sy_bit(OPT_INFREDTAIL),     ~Sy_bit(OPT_INFREDTAIL)  },
539  /* 30: use not regularity for syz */
540  {"notRegularity",Sy_bit(OPT_NOTREGULARITY),  ~Sy_bit(OPT_NOTREGULARITY)  },
541  {"weightM",      Sy_bit(OPT_WEIGHTM),        ~Sy_bit(OPT_WEIGHTM)  },
542/*special for "none" and also end marker for showOption:*/
543  {"ne",           0,                          0 }
544};
545
546const struct soptionStruct verboseStruct[]=
547{
548  {"mem",      Sy_bit(V_SHOW_MEM),  ~Sy_bit(V_SHOW_MEM)   },
549  {"yacc",     Sy_bit(V_YACC),      ~Sy_bit(V_YACC)       },
550  {"redefine", Sy_bit(V_REDEFINE),  ~Sy_bit(V_REDEFINE)   },
551  {"reading",  Sy_bit(V_READING),   ~Sy_bit(V_READING)    },
552  {"loadLib",  Sy_bit(V_LOAD_LIB),  ~Sy_bit(V_LOAD_LIB)   },
553  {"debugLib", Sy_bit(V_DEBUG_LIB), ~Sy_bit(V_DEBUG_LIB)  },
554  {"loadProc", Sy_bit(V_LOAD_PROC), ~Sy_bit(V_LOAD_PROC)  },
555  {"defRes",   Sy_bit(V_DEF_RES),   ~Sy_bit(V_DEF_RES)    },
556  {"usage",    Sy_bit(V_SHOW_USE),  ~Sy_bit(V_SHOW_USE)   },
557  {"Imap",     Sy_bit(V_IMAP),      ~Sy_bit(V_IMAP)       },
558  {"prompt",   Sy_bit(V_PROMPT),    ~Sy_bit(V_PROMPT)     },
559  {"length",   Sy_bit(V_LENGTH),    ~Sy_bit(V_LENGTH)     },
560  {"notWarnSB",Sy_bit(V_NSB),       ~Sy_bit(V_NSB)        },
561  {"contentSB",Sy_bit(V_CONTENTSB), ~Sy_bit(V_CONTENTSB)  },
562  {"cancelunit",Sy_bit(V_CANCELUNIT),~Sy_bit(V_CANCELUNIT)},
563  {"modpsolve",Sy_bit(V_MODPSOLVSB),~Sy_bit(V_MODPSOLVSB)},
564  {"geometricSB",Sy_bit(V_UPTORADICAL),~Sy_bit(V_UPTORADICAL)},
565  {"findMonomials",Sy_bit(V_FINDMONOM),~Sy_bit(V_FINDMONOM)},
566  {"coefStrat",Sy_bit(V_COEFSTRAT), ~Sy_bit(V_COEFSTRAT)},
567  {"qringNF",  Sy_bit(V_QRING),     ~Sy_bit(V_QRING)},
568  {"warn",     Sy_bit(V_ALLWARN),   ~Sy_bit(V_ALLWARN)},
569  {"intersectSyz",Sy_bit(V_INTERSECT_SYZ), ~Sy_bit(V_INTERSECT_SYZ)},
570  {"intersectElim",Sy_bit(V_INTERSECT_ELIM), ~Sy_bit(V_INTERSECT_ELIM)},
571/*special for "none" and also end marker for showOption:*/
572  {"ne",         0,          0 }
573};
574
575BOOLEAN setOption(leftv res, leftv v)
576{
577  const char *n;
578  do
579  {
580    if (v->Typ()==STRING_CMD)
581    {
582      n=(const char *)v->CopyD(STRING_CMD);
583    }
584    else
585    {
586      if (v->name==NULL)
587        return TRUE;
588      if (v->rtyp==0)
589      {
590        n=v->name;
591        v->name=NULL;
592      }
593      else
594      {
595        n=omStrDup(v->name);
596      }
597    }
598
599    int i;
600
601    if(strcmp(n,"get")==0)
602    {
603      intvec *w=new intvec(2);
604      (*w)[0]=si_opt_1;
605      (*w)[1]=si_opt_2;
606      res->rtyp=INTVEC_CMD;
607      res->data=(void *)w;
608      goto okay;
609    }
610    if(strcmp(n,"set")==0)
611    {
612      if((v->next!=NULL)
613      &&(v->next->Typ()==INTVEC_CMD))
614      {
615        v=v->next;
616        intvec *w=(intvec*)v->Data();
617        si_opt_1=(*w)[0];
618        si_opt_2=(*w)[1];
619#if 0
620        if (TEST_OPT_INTSTRATEGY && (currRing!=NULL)
621        && rField_has_simple_inverse()
622        && !rField_is_Ring(currRing)
623        ) {
624          si_opt_1 &=~Sy_bit(OPT_INTSTRATEGY);
625        }
626#endif
627        goto okay;
628      }
629    }
630    if(strcmp(n,"none")==0)
631    {
632      si_opt_1=0;
633      si_opt_2=0;
634      goto okay;
635    }
636    for (i=0; (i==0) || (optionStruct[i-1].setval!=0); i++)
637    {
638      if (strcmp(n,optionStruct[i].name)==0)
639      {
640        if (optionStruct[i].setval & validOpts)
641        {
642          si_opt_1 |= optionStruct[i].setval;
643          // optOldStd disables redthrough
644          if (optionStruct[i].setval == Sy_bit(OPT_OLDSTD))
645            si_opt_1 &= ~Sy_bit(OPT_REDTHROUGH);
646        }
647        else
648          Warn("cannot set option");
649#if 0
650        if (TEST_OPT_INTSTRATEGY && (currRing!=NULL)
651        && rField_has_simple_inverse()
652        && !rField_is_Ring(currRing)
653        ) {
654          test &=~Sy_bit(OPT_INTSTRATEGY);
655        }
656#endif
657        goto okay;
658      }
659      else if ((strncmp(n,"no",2)==0)
660      && (strcmp(n+2,optionStruct[i].name)==0))
661      {
662        if (optionStruct[i].setval & validOpts)
663        {
664          si_opt_1 &= optionStruct[i].resetval;
665        }
666        else
667          Warn("cannot clear option");
668        goto okay;
669      }
670    }
671    for (i=0; (i==0) || (verboseStruct[i-1].setval!=0); i++)
672    {
673      if (strcmp(n,verboseStruct[i].name)==0)
674      {
675        si_opt_2 |= verboseStruct[i].setval;
676        #ifdef YYDEBUG
677        #if YYDEBUG
678        /*debugging the bison grammar --> grammar.cc*/
679        extern int    yydebug;
680        if (BVERBOSE(V_YACC)) yydebug=1;
681        else                  yydebug=0;
682        #endif
683        #endif
684        goto okay;
685      }
686      else if ((strncmp(n,"no",2)==0)
687      && (strcmp(n+2,verboseStruct[i].name)==0))
688      {
689        si_opt_2 &= verboseStruct[i].resetval;
690        #ifdef YYDEBUG
691        #if YYDEBUG
692        /*debugging the bison grammar --> grammar.cc*/
693        extern int    yydebug;
694        if (BVERBOSE(V_YACC)) yydebug=1;
695        else                  yydebug=0;
696        #endif
697        #endif
698        goto okay;
699      }
700    }
701    Werror("unknown option `%s`",n);
702  okay:
703    if (currRing != NULL)
704      currRing->options = si_opt_1 & TEST_RINGDEP_OPTS;
705    omFree((ADDRESS)n);
706    v=v->next;
707  } while (v!=NULL);
708
709   // set global variable to show memory usage
710  extern int om_sing_opt_show_mem;
711  if (BVERBOSE(V_SHOW_MEM)) om_sing_opt_show_mem = 1;
712  else om_sing_opt_show_mem = 0;
713
714  return FALSE;
715}
716
717char * showOption()
718{
719  int i;
720  BITSET tmp;
721
722  StringSetS("//options:");
723  if ((si_opt_1!=0)||(si_opt_2!=0))
724  {
725    tmp=si_opt_1;
726    if(tmp)
727    {
728      for (i=0; optionStruct[i].setval!=0; i++)
729      {
730        if (optionStruct[i].setval & tmp)
731        {
732          StringAppend(" %s",optionStruct[i].name);
733          tmp &=optionStruct[i].resetval;
734        }
735      }
736      for (i=0; i<32; i++)
737      {
738        if (tmp & Sy_bit(i)) StringAppend(" %d",i);
739      }
740    }
741    tmp=si_opt_2;
742    if (tmp)
743    {
744      for (i=0; verboseStruct[i].setval!=0; i++)
745      {
746        if (verboseStruct[i].setval & tmp)
747        {
748          StringAppend(" %s",verboseStruct[i].name);
749          tmp &=verboseStruct[i].resetval;
750        }
751      }
752      for (i=1; i<32; i++)
753      {
754        if (tmp & Sy_bit(i)) StringAppend(" %d",i+32);
755      }
756    }
757    return StringEndS();
758  }
759  StringAppendS(" none");
760  return StringEndS();
761}
762
763/* version strings */
764#ifdef HAVE_FLINT
765extern "C"
766{
767#ifndef __GMP_BITS_PER_MP_LIMB
768#define __GMP_BITS_PER_MP_LIMB GMP_LIMB_BITS
769#endif
770#include <flint/flint.h>
771}
772#endif
773
774#ifndef MAKE_DISTRIBUTION
775const char *singular_date=__DATE__ " " __TIME__;
776#endif
777
778char * versionString(/*const bool bShowDetails = false*/ )
779{
780  StringSetS("");
781  StringAppend("Singular for %s version %s (%d, %d bit) %s #%s",
782               S_UNAME, VERSION, // SINGULAR_VERSION,
783               SINGULAR_VERSION, sizeof(void*)*8,
784#ifdef MAKE_DISTRIBUTION
785               VERSION_DATE, GIT_VERSION);
786#else
787               singular_date, GIT_VERSION);
788#endif
789  StringAppendS("\nwith\n\t");
790
791#if defined(mpir_version)
792              StringAppend("MPIR(%s)~GMP(%s),", mpir_version, gmp_version);
793#elif defined(gmp_version)
794              // #if defined (__GNU_MP_VERSION) && defined (__GNU_MP_VERSION_MINOR)
795              //              StringAppend("GMP(%d.%d),",__GNU_MP_VERSION,__GNU_MP_VERSION_MINOR);
796              StringAppend("GMP(%s),", gmp_version);
797#endif
798#ifdef HAVE_NTL
799#include <NTL/version.h>
800              StringAppend("NTL(%s),",NTL_VERSION);
801#endif
802
803#ifdef HAVE_FLINT
804              StringAppend("FLINT(%s),",version);
805#endif
806              StringAppend("factory(%s),\n\t", factoryVersion);
807#if defined(HAVE_DYN_RL)
808              if (fe_fgets_stdin==fe_fgets_dummy)
809                StringAppendS("no input,");
810              else if (fe_fgets_stdin==fe_fgets)
811                StringAppendS("fgets,");
812              if (fe_fgets_stdin==fe_fgets_stdin_drl)
813                StringAppendS("dynamic readline,");
814              #ifdef HAVE_FEREAD
815              else if (fe_fgets_stdin==fe_fgets_stdin_emu)
816                StringAppendS("emulated readline,");
817              #endif
818              else
819                StringAppendS("unknown fgets method,");
820#else
821  #if defined(HAVE_READLINE) && !defined(FEREAD)
822              StringAppendS("static readline,");
823  #else
824    #ifdef HAVE_FEREAD
825              StringAppendS("emulated readline,");
826    #else
827              StringAppendS("fgets,");
828    #endif
829  #endif
830#endif
831#ifdef HAVE_PLURAL
832              StringAppendS("Plural,");
833#endif
834#ifdef HAVE_DBM
835              StringAppendS("DBM,\n\t");
836#else
837              StringAppendS("\n\t");
838#endif
839#ifdef HAVE_DYNAMIC_LOADING
840              StringAppendS("dynamic modules,");
841#endif
842              if (p_procs_dynamic) StringAppendS("dynamic p_Procs,");
843#if YYDEBUG
844              StringAppendS("YYDEBUG=1,");
845#endif
846#ifdef HAVE_ASSUME
847             StringAppendS("ASSUME,");
848#endif
849#ifdef MDEBUG
850              StringAppend("MDEBUG=%d,",MDEBUG);
851#endif
852#ifdef OM_CHECK
853              StringAppend("OM_CHECK=%d,",OM_CHECK);
854#endif
855#ifdef OM_TRACK
856              StringAppend("OM_TRACK=%d,",OM_TRACK);
857#endif
858#ifdef OM_NDEBUG
859              StringAppendS("OM_NDEBUG,");
860#endif
861#ifdef SING_NDEBUG
862              StringAppendS("SING_NDEBUG,");
863#endif
864#ifdef PDEBUG
865              StringAppendS("PDEBUG,");
866#endif
867#ifdef KDEBUG
868              StringAppendS("KDEBUG,");
869#endif
870#ifdef __OPTIMIZE__
871              StringAppendS("CC:OPTIMIZE,");
872#endif
873#ifdef __OPTIMIZE_SIZE__
874              StringAppendS("CC:OPTIMIZE_SIZE,");
875#endif
876#ifdef __NO_INLINE__
877              StringAppendS("CC:NO_INLINE,");
878#endif
879#ifdef HAVE_EIGENVAL
880              StringAppendS("eigenvalues,");
881#endif
882#ifdef HAVE_GMS
883              StringAppendS("Gauss-Manin system,");
884#endif
885#ifdef HAVE_RATGRING
886              StringAppendS("ratGB,");
887#endif
888              StringAppend("random=%d\n",siRandomStart);
889
890#define SI_SHOW_BUILTIN_MODULE(name) StringAppend(" %s", #name);
891              StringAppendS("built-in modules: {");
892              SI_FOREACH_BUILTIN(SI_SHOW_BUILTIN_MODULE)
893              StringAppendS("}\n");
894#undef SI_SHOW_BUILTIN_MODULE
895
896              StringAppend("AC_CONFIGURE_ARGS = %s,\n"
897                           "CC = %s,FLAGS : %s,\n"
898                           "CXX = %s,FLAGS : %s,\n"
899                           "DEFS : %s,CPPFLAGS : %s,\n"
900                           "LDFLAGS : %s,LIBS : %s "
901#ifdef __GNUC__
902              "(ver: " __VERSION__ ")"
903#endif
904              "\n",AC_CONFIGURE_ARGS, CC,CFLAGS, CXX,CXXFLAGS,  DEFS,CPPFLAGS,  LDFLAGS,LIBS);
905              feStringAppendResources(0);
906              feStringAppendBrowsers(0);
907              StringAppendS("\n");
908              return StringEndS();
909}
910
911#ifdef PDEBUG
912#if (OM_TRACK > 2) && defined(OM_TRACK_CUSTOM)
913void p_SetRingOfLeftv(leftv l, ring r)
914{
915  switch(l->rtyp)
916  {
917    case INT_CMD:
918    case BIGINT_CMD:
919    case IDHDL:
920    case DEF_CMD:
921      break;
922    case POLY_CMD:
923    case VECTOR_CMD:
924    {
925      poly p=(poly)l->data;
926      while(p!=NULL) { p_SetRingOfLm(p,r); pIter(p); }
927      break;
928    }
929    case IDEAL_CMD:
930    case MODUL_CMD:
931    case MATRIX_CMD:
932    {
933      ideal I=(ideal)l->data;
934      int i;
935      for(i=IDELEMS(I)-1;i>=0;i--)
936      {
937        poly p=I->m[i];
938        while(p!=NULL) { p_SetRingOfLm(p,r); pIter(p); }
939      }
940      break;
941    }
942    case COMMAND:
943    {
944      command d=(command)l->data;
945      p_SetRingOfLeftv(&d->arg1, r);
946      if (d->argc>1) p_SetRingOfLeftv(&d->arg2, r);
947      if (d->argc>2) p_SetRingOfLeftv(&d->arg3, r);
948      break;
949    }
950    default:
951     printf("type %d not yet implementd in p_SetRingOfLeftv\n",l->rtyp);
952     break;
953  }
954}
955#endif
956#endif
957
958#if 0 /* debug only */
959void listall(int showproc)
960{
961      idhdl hh=basePack->idroot;
962      PrintS("====== Top ==============\n");
963      while (hh!=NULL)
964      {
965        if (showproc || (IDTYP(hh)!=PROC_CMD))
966        {
967          if (IDDATA(hh)==(void *)currRing) PrintS("(R)");
968          else if (IDDATA(hh)==(void *)currPack) PrintS("(P)");
969          else PrintS("   ");
970          Print("::%s, typ %s level %d data %lx",
971                 IDID(hh),Tok2Cmdname(IDTYP(hh)),IDLEV(hh),(long)IDDATA(hh));
972          if (IDTYP(hh)==RING_CMD)
973            Print(" ref: %d\n",IDRING(hh)->ref);
974          else
975            PrintLn();
976        }
977        hh=IDNEXT(hh);
978      }
979      hh=basePack->idroot;
980      while (hh!=NULL)
981      {
982        if (IDDATA(hh)==(void *)basePack)
983          Print("(T)::%s, typ %s level %d data %lx\n",
984          IDID(hh),Tok2Cmdname(IDTYP(hh)),IDLEV(hh),(long)IDDATA(hh));
985        else
986        if ((IDTYP(hh)==RING_CMD)
987        || (IDTYP(hh)==PACKAGE_CMD))
988        {
989          Print("====== %s ==============\n",IDID(hh));
990          idhdl h2=IDRING(hh)->idroot;
991          while (h2!=NULL)
992          {
993            if (showproc || (IDTYP(h2)!=PROC_CMD))
994            {
995              if ((IDDATA(h2)==(void *)currRing)
996              && (IDTYP(h2)==RING_CMD))
997                PrintS("(R)");
998              else if (IDDATA(h2)==(void *)currPack) PrintS("(P)");
999              else PrintS("   ");
1000              Print("%s::%s, typ %s level %d data %lx\n",
1001              IDID(hh),IDID(h2),Tok2Cmdname(IDTYP(h2)),IDLEV(h2),(long)IDDATA(h2));
1002            }
1003            h2=IDNEXT(h2);
1004          }
1005        }
1006        hh=IDNEXT(hh);
1007      }
1008      Print("currRing:%lx, currPack:%lx,basePack:%lx\n",(long)currRing,(long)currPack,(long)basePack);
1009      iiCheckPack(currPack);
1010}
1011#endif
1012
1013#ifndef SING_NDEBUG
1014void checkall()
1015{
1016      idhdl hh=basePack->idroot;
1017      while (hh!=NULL)
1018      {
1019        omCheckAddr(hh);
1020        omCheckAddr((ADDRESS)IDID(hh));
1021        if (RingDependend(IDTYP(hh)))
1022        {
1023          Print("%s typ %d in Top (should be in ring)\n",IDID(hh),IDTYP(hh));
1024        }
1025        hh=IDNEXT(hh);
1026      }
1027      hh=basePack->idroot;
1028      while (hh!=NULL)
1029      {
1030        if (IDTYP(hh)==PACKAGE_CMD)
1031        {
1032          idhdl h2=IDPACKAGE(hh)->idroot;
1033          if (IDPACKAGE(hh)!=basePack)
1034          {
1035            while (h2!=NULL)
1036            {
1037              omCheckAddr(h2);
1038              omCheckAddr((ADDRESS)IDID(h2));
1039              if (RingDependend(IDTYP(h2)))
1040              {
1041                Print("%s typ %d in %s (should be in ring)\n",IDID(h2),IDTYP(h2),IDID(hh));
1042              }
1043              h2=IDNEXT(h2);
1044            }
1045          }
1046        }
1047        hh=IDNEXT(hh);
1048      }
1049}
1050#endif
1051
1052#include <sys/types.h>
1053#include <sys/stat.h>
1054#include <unistd.h>
1055
1056extern "C"
1057int singular_fstat(int fd, struct stat *buf)
1058{
1059  return si_fstat(fd,buf);
1060}
1061
1062/*2
1063* the global exit routine of Singular
1064*/
1065extern "C" {
1066/* Note: We cannot use a mutex here because mutexes are not async-safe, but
1067 * m2_end is called by sig_term_hdl(). Anyway, the race condition in the first
1068 * few lines of m2_end() should not matter.
1069 */
1070volatile BOOLEAN m2_end_called = FALSE;
1071
1072void m2_end(int i)
1073{
1074  if (!m2_end_called)
1075  {
1076    extern FILE* File_Profiling;
1077    if (File_Profiling!=NULL) { fclose(File_Profiling); File_Profiling=NULL; }
1078    m2_end_called = TRUE;
1079#ifdef HAVE_SIMPLEIPC
1080    for (int j = SIPC_MAX_SEMAPHORES-1; j >= 0; j--)
1081    {
1082      if (semaphore[j] != NULL)
1083      {
1084        while (sem_acquired[j] > 0)
1085        {
1086#if PORTABLE_SEMAPHORES
1087          sem_post(semaphore[j]->sig);
1088#else
1089          sem_post(semaphore[j]);
1090#endif
1091          sem_acquired[j]--;
1092        }
1093      }
1094    }
1095#endif   // HAVE_SIMPLEIPC
1096    fe_reset_input_mode();
1097    monitor(NULL,0);
1098#ifdef PAGE_TEST
1099    mmEndStat();
1100#endif
1101    fe_reset_input_mode();
1102    if (ssiToBeClosed_inactive)
1103    {
1104      link_list hh=ssiToBeClosed;
1105      while(hh!=NULL)
1106      {
1107        //Print("close %s\n",hh->l->name);
1108        slPrepClose(hh->l);
1109        hh=(link_list)hh->next;
1110      }
1111      ssiToBeClosed_inactive=FALSE;
1112
1113      idhdl h = currPack->idroot;
1114      while(h != NULL)
1115      {
1116        if(IDTYP(h) == LINK_CMD)
1117        {
1118          idhdl hh=h->next;
1119          //Print("kill %s\n",IDID(h));
1120          killhdl(h, currPack);
1121          h = hh;
1122        }
1123        else
1124        {
1125          h = h->next;
1126        }
1127      }
1128      hh=ssiToBeClosed;
1129      while(hh!=NULL)
1130      {
1131        //Print("close %s\n",hh->l->name);
1132        slClose(hh->l);
1133        hh=ssiToBeClosed;
1134      }
1135    }
1136    if (!singular_in_batchmode)
1137    {
1138      if (i<=0)
1139      {
1140        if (TEST_V_QUIET)
1141        {
1142          if (i==0)
1143            printf("Auf Wiedersehen.\n");
1144          else
1145            printf("\n$Bye.\n");
1146        }
1147        //#ifdef sun
1148        //  #ifndef __svr4__
1149        //    _cleanup();
1150        //    _exit(0);
1151        //  #endif
1152        //#endif
1153        i=0;
1154      }
1155      else
1156      {
1157        printf("\nhalt %d\n",i);
1158      }
1159    }
1160    exit(i);
1161  }
1162}
1163}
1164
1165extern "C"
1166{
1167  void omSingOutOfMemoryFunc()
1168  {
1169    fprintf(stderr, "\nSingular error: no more memory\n");
1170    omPrintStats(stderr);
1171    m2_end(14);
1172    /* should never get here */
1173    exit(1);
1174  }
1175}
1176
1177#ifdef SINGULAR_4_2
1178static n_coeffType n_pAE=n_unknown;
1179static BOOLEAN ii_pAE_init(leftv res,leftv a)
1180{
1181  if (a->Typ()!=INT_CMD)
1182  {
1183    WerrorS("`int` expected");
1184    return TRUE;
1185  }
1186  else
1187  {
1188    res->rtyp=CRING_CMD;
1189    res->data=(void*)nInitChar(n_pAE,(void*)a->Data());
1190    return FALSE;
1191  }
1192}
1193#endif
1194#ifdef HAVE_FLINT
1195static n_coeffType n_FlintZn=n_unknown;
1196static BOOLEAN ii_FlintZn_init(leftv res,leftv a)
1197{
1198  if ((a->Typ()!=INT_CMD)
1199  ||(a->next==NULL)
1200  ||(a->next->Typ()!=STRING_CMD))
1201  {
1202    WerrorS("`int`i,`string` expected");
1203    return TRUE;
1204  }
1205  else
1206  {
1207    flintZn_struct p;
1208    p.ch=(int)(long)a->Data();
1209    p.name=(char*)a->next->Data();
1210    res->rtyp=CRING_CMD;
1211    res->data=(void*)nInitChar(n_FlintZn,(void*)&p);
1212    return FALSE;
1213  }
1214}
1215#endif
1216/*2
1217* initialize components of Singular
1218*/
1219void siInit(char *name)
1220{
1221// factory default settings: -----------------------------------------------
1222  On(SW_USE_EZGCD);
1223  On(SW_USE_CHINREM_GCD);
1224  //On(SW_USE_FF_MOD_GCD);
1225  On(SW_USE_EZGCD_P);
1226  On(SW_USE_QGCD);
1227  Off(SW_USE_NTL_SORT); // may be changed by an command line option
1228  factoryError=WerrorS;
1229
1230// memory initialization: -----------------------------------------------
1231    om_Opts.OutOfMemoryFunc = omSingOutOfMemoryFunc;
1232#ifndef OM_NDEBUG
1233#ifndef __OPTIMIZE__
1234    om_Opts.ErrorHook = dErrorBreak;
1235#else
1236    om_Opts.Keep = 0; /* !OM_NDEBUG, __OPTIMIZE__*/
1237#endif
1238#else
1239    om_Opts.Keep = 0; /* OM_NDEBUG */
1240#endif
1241    omInitInfo();
1242
1243// options ---------------------------------------------------------------
1244  si_opt_1=0;
1245// interpreter tables etc.: -----------------------------------------------
1246  memset(&sLastPrinted,0,sizeof(sleftv));
1247  sLastPrinted.rtyp=NONE;
1248
1249  extern int iiInitArithmetic(); iiInitArithmetic(); // iparith.cc
1250
1251  basePack=(package)omAlloc0(sizeof(*basePack));
1252  currPack=basePack;
1253  idhdl h;
1254  h=enterid("Top", 0, PACKAGE_CMD, &IDROOT, TRUE);
1255  IDPACKAGE(h)->language = LANG_TOP;
1256  IDPACKAGE(h)=basePack;
1257  currPackHdl=h;
1258  basePackHdl=h;
1259
1260  coeffs_BIGINT = nInitChar(n_Q,(void*)1);
1261
1262#if 1
1263   // def HAVE_POLYEXTENSIONS
1264  if(TRUE)
1265  {
1266    n_coeffType type;
1267    #ifdef SINGULAR_4_2
1268    type = nRegister(n_polyExt, n2pInitChar);
1269    assume(type == n_polyExt);
1270    #endif
1271
1272    type = nRegister(n_algExt, naInitChar);
1273    assume(type == n_algExt);
1274
1275    type = nRegister(n_transExt, ntInitChar);
1276    assume(type == n_transExt);
1277
1278    (void)type;
1279  }
1280#endif
1281
1282// random generator: -----------------------------------------------
1283  int t=initTimer();
1284  if (t==0) t=1;
1285  initRTimer();
1286  siSeed=t;
1287  factoryseed(t);
1288  siRandomStart=t;
1289  feOptSpec[FE_OPT_RANDOM].value = (void*) ((long)siRandomStart);
1290
1291// ressource table: ----------------------------------------------------
1292  // Don't worry: ifdef OM_NDEBUG, then all these calls are undef'ed
1293  // hack such that all shared' libs in the bindir are loaded correctly
1294  feInitResources(name);
1295
1296// singular links: --------------------------------------------------
1297  slStandardInit();
1298  myynest=0;
1299// semapohore 0 -----------------------------------------------------
1300  int cpus=2;
1301  int cpu_n;
1302  #ifdef _SC_NPROCESSORS_ONLN
1303  if ((cpu_n=sysconf(_SC_NPROCESSORS_ONLN))>cpus) cpus=cpu_n;
1304  #elif defined(_SC_NPROCESSORS_CONF)
1305  if ((cpu_n=sysconf(_SC_NPROCESSORS_CONF))>cpus) cpus=cpu_n;
1306  #endif
1307  feSetOptValue(FE_OPT_CPUS, cpus);
1308
1309// default coeffs
1310  {
1311    idhdl h;
1312    h=enterid(omStrDup("QQ"),0/*level*/, CRING_CMD,&(basePack->idroot),FALSE /*init*/,FALSE /*search*/);
1313    IDDATA(h)=(char*)nInitChar(n_Q,NULL);
1314    h=enterid(omStrDup("ZZ"),0/*level*/, CRING_CMD,&(basePack->idroot),FALSE /*init*/,FALSE /*search*/);
1315    IDDATA(h)=(char*)nInitChar(n_Z,NULL);
1316    //h=enterid(omStrDup("RR"),0/*level*/, CRING_CMD,&(basePack->idroot),FALSE /*init*/,FALSE /*search*/);
1317    //IDDATA(h)=(char*)nInitChar(n_R,NULL);
1318    //h=enterid(omStrDup("CC"),0/*level*/, CRING_CMD,&(basePack->idroot),FALSE /*init*/,FALSE /*search*/);
1319    //IDDATA(h)=(char*)nInitChar(n_long_C,NULL);
1320    n_coeffType t;
1321#ifdef SINGULAR_4_2
1322    t=nRegister(n_unknown,n_AEInitChar);
1323    if (t!=n_unknown)
1324    {
1325      h=enterid(omStrDup("AE"),0/*level*/, CRING_CMD,&(basePack->idroot),FALSE /*init*/,FALSE /*search*/);
1326      IDDATA(h)=(char*)nInitChar(t,NULL);
1327    }
1328    t=nRegister(n_unknown,n_QAEInitChar);
1329    if (t!=n_unknown)
1330    {
1331      h=enterid(omStrDup("QAE"),0/*level*/, CRING_CMD,&(basePack->idroot),FALSE /*init*/,FALSE /*search*/);
1332      IDDATA(h)=(char*)nInitChar(t,NULL);
1333    }
1334    n_pAE=nRegister(n_unknown,n_pAEInitChar);
1335    if (n_pAE!=n_unknown)
1336    {
1337      iiAddCproc("kernel","pAE",FALSE,ii_pAE_init);
1338    }
1339#endif
1340    #ifdef HAVE_FLINT
1341    t=nRegister(n_unknown,flintQ_InitChar);
1342    if (t!=n_unknown)
1343    {
1344      h=enterid(omStrDup("flint_poly_Q"),0/*level*/, CRING_CMD,&(basePack->idroot),FALSE /*init*/,FALSE /*search*/);
1345      IDDATA(h)=(char*)nInitChar(t,NULL);
1346    }
1347    n_FlintZn=nRegister(n_unknown,flintZn_InitChar);
1348    if (n_FlintZn!=n_unknown)
1349    {
1350      iiAddCproc("kernel","flintZ",FALSE,ii_FlintZn_init);
1351    }
1352    #endif
1353  }
1354// setting routines for PLURAL QRINGS:
1355// allowing to use libpolys without libSingular(kStd)
1356#ifdef HAVE_PLURAL
1357  nc_NF=k_NF;
1358  gnc_gr_bba=k_gnc_gr_bba;
1359  gnc_gr_mora=k_gnc_gr_mora;
1360  sca_bba=k_sca_bba;
1361  sca_mora=k_sca_mora;
1362  sca_gr_bba=k_sca_gr_bba;
1363#endif
1364// loading standard.lib -----------------------------------------------
1365  if (! feOptValue(FE_OPT_NO_STDLIB))
1366  {
1367    BITSET save1,save2;
1368    SI_SAVE_OPT(save1,save2);
1369    si_opt_2 &= ~Sy_bit(V_LOAD_LIB);
1370    iiLibCmd(omStrDup("standard.lib"), TRUE,TRUE,TRUE);
1371    SI_RESTORE_OPT(save1,save2);
1372  }
1373  errorreported = 0;
1374}
Note: See TracBrowser for help on using the repository browser.