Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/automode/
Upload File :
Current File : /usr/home/beeson/MathXpert/automode/cflags.c

/* M. Beeson, control flags for Mathpert
Original date 1990
modified 7.5.99
1.2.00  modified set_parser_decimalchar
1.13.00 modified set_control_flags for _fundamental_theorem topic
1.15.00 modified setting of polyvalnegexpflag for _complex_quadratics, by using COMPLEXTOPIC
5.3.01  changed a comment only
9.4.04  parser_controlflags no longer needs newatom and newfunctor
6.25.05  modified set_control_flags at the beginning
1.18.06 eliminated get_active_doc and hence eliminated Windows dependency
3.17.06 deleted superfluous includes
4.7.06 changed stricmp to _stricmp
4.13.06 modified GetMathpertFolder temporarily
3.24.07 modified GetMathpertFolder so it works with ComputeCheckSums
8.21.07 modified GetMathpertHelpFile so it returns .chm instead of .hlp
9.8.11  cast result of strlen to int  for 64-bit compilation without warnings
5.6.13  include stdef.h and pcontrol. 
        Changed StoreCommandLine to not use stricmp;
5.15.13  added code to cause factoring in denominators and using fractional exponents in POWERSERIES 
6.13.13  modified GetMathpertFolder
6.14.13  corrected GetMathpertFolder
2.5.24  changed default parser_flag.complex to 0
2.24.24  changed include readinit.h to preferences.h
12.7.24  added set_parser_complex
12.31.24 changed get_problemtype() and set_problemtype() to use pActiveDoc
*/

#include <assert.h>
#include <string.h>
#include <stdlib.h>    /* calloc   */
#include <stddef.h>
#include <stdio.h>     /* printf, for debugging messages */
#include "globals.h"
#include "graphstr.h"
#include "display.h"
#include "mpdoc.h"
#include "tdefn.h"
#include "checkarg.h" /* for operator typedef */
#include "ops.h"  /* for prototypes of operators */
#include "probtype.h"  /* set_control_flags needs values of problemtype */
#include "cflags.h"
#include "symbols.h"
#include "prover.h"
#include "mpmem.h"  /* permfree    */
#include "pathtail.h" /* set_pathtail  */
#include "dispfunc.h" /* newfunctor    */
#include "lang.h"
#include "preferences.h"
#include "pcontrol.h"   /* get_parser_flags */
#include "activate.h"   /* activate_symbol_document */
#include "activedoc.h"  /* GetActiveDoc */

static controldata *pDocControlData;
static int find_as_subterm(term t, term q, term *ans);

/*__________________________________________________________________*/
static PDOCDATA pActiveDoc;   // pointer to the currently active document 

PDOCDATA GetActiveDoc(void)
{ return pActiveDoc;
}

void SetActiveDoc(PDOCDATA p)
{ pActiveDoc = p;
}
/*________________________________________________________________*/
int get_checksolutionsflag(void)
  /*  set when false solutions to equations may have
      been introduced, e.g. by taking powers of the equation  */
  { return pDocControlData->checksolutionsflag;
  }

void set_checksolutionsflag(int n)
  { pDocControlData->checksolutionsflag = n;
  }
/*_______________________________________________________*/
int get_logcollectflag(void)
   { return pDocControlData->logcollectflag;
   }
void set_logcollectflag(int n)
   { pDocControlData->logcollectflag = n;
   }
/*_______________________________________________________*/

int get_comdenomflag(void)
   { return pDocControlData->comdenomflag;
   }
void set_comdenomflag(int n)
   { pDocControlData->comdenomflag = n;
   }

/*_______________________________________________________*/
/* Meaning of pDocControlData->radicalflag:
   if 1, convert fractional exponents to radicals;
   if -1, convert radicals to fractional exponents;
   if -2, convert roots but not sqrts to fractional
                                  exponents.
   if 0 do neither
*/
int get_radicalflag(void)
   { return pDocControlData->radicalflag;
   }

void set_radicalflag(int n)
   { pDocControlData->radicalflag = n;
   }


/*_______________________________________________________*/
  /* meaning of pDocControlData->expandflag:
     if zero, expand products and powers only in sums
     if bit 0 is 1, expand also in numerators;
     if bit 4 is 1, expand in denominators;
     if bit 8 is 1 expand everything
     Default value 0x0011
  */

int get_expandflag(void)
   { return pDocControlData->expandflag;
   }

void set_expandflag(int n)
   { pDocControlData->expandflag = n;
   }

/*_______________________________________________________*/
int get_trigexpandflag(void)
   { return pDocControlData->trigexpandflag;
   }
void set_trigexpandflag(int n)
   { pDocControlData->trigexpandflag = n;
   }

/*_______________________________________________________*/
int get_factorflag(void)
   { return pDocControlData->factorflag;
   }

void set_factorflag(int n)
   { pDocControlData->factorflag = n;
   }

/*____________________________________________________________*/
void pack_flags(int line)
/* pack the above four flags into pDocControlData->linedatahistory[line].controlflags */
/* The bits are used in the order listed */
{ unsigned char ans = 0;
  if(pDocControlData->factorflag & 0x0001)
     ans |= 1;
  if(pDocControlData->factorflag & 0x0010)
     ans |= 2;
  if(pDocControlData->factorflag & 0x0100)
     ans |= 4;
  if(pDocControlData->checksolutionsflag)
     ans |= 8;
  if(pDocControlData->comdenomflag)
     ans |= 0x10;
  if(pDocControlData->expandflag & 0x0001)
     ans |= 0x20;
  if(pDocControlData->expandflag & 0x0010)
     ans |= 0x40;
  if(pDocControlData->expandflag & 0x0100)
     ans |= 0x80;
  pDocControlData->linedatahistory[line].controlflags = ans;
}
/*____________________________________________________________*/
void unpack_flags(int line)
/* restore the above four flags from pDocControlData->linedatahistory[line].controlflags */
/* needed by undo, therefore */
{ unsigned char ans = pDocControlData->linedatahistory[line].controlflags;
  pDocControlData->factorflag = pDocControlData->expandflag = pDocControlData->comdenomflag = pDocControlData->checksolutionsflag = 0;
  if(ans & 1)
     pDocControlData->factorflag |= 0x0001;
  if(ans & 2)
     pDocControlData->factorflag |= 0x0010;
  if(ans & 4)
     pDocControlData->factorflag |= 0x0100;
  if(ans & 8)
     pDocControlData->checksolutionsflag = 1;
  if(ans & 0x10)
     pDocControlData->comdenomflag = 1;
  if(ans & 0x20)
     pDocControlData->expandflag |= 0x0001;
  if(ans & 0x40)
     pDocControlData->expandflag |= 0x0010;
  if(ans & 0x80)
     pDocControlData->expandflag |= 0x0100;
}

/*_________________________________________________________________*/

void activate_symbolDLL(controldata *p)
/* Initialize the global control data.
Called when a document is activated, when it has previously been opened. */
{ pDocControlData = p;
  set_model(p->model);
}

/*____________________________________________________________________*/
void set_control_flags(int problemtype, int currenttopic)
/* set the flags that control auto mode simplification appropriately,
depending on the value of 'problemtype' and currenttopic
The possible values of problemtype are in probtype.h, those of
currenttopic are in topics.h.  This function is called
after the  problemtype and currenttopic are determined, and after
'activate' has linked the document data to the DLL variables,
under WM_CREATE, but before the GetProblem dialog.

The relevant flags to be set and their initialized (default) values are:

I.  The polyvalflags in polyval.c  (see polyval.h)
    These include 'complex'; but arithflag is set init_model, not here.
    Do not confuse polyvalorderflag with
    orderflag; polyvalorderflag is documented in polyval.h, search
    for 'orderonly'.  Also do not confuse 'factorflag' with
    polyvalfactorflag; the latter only controls content-factoring in
    polyval.   These flags are documented in polyval.h by the
    corresponding fields of polyvalflag.

II. ringflag and orderflag,  which are maintained in order.c and
    set using set_ringflag and set_orderflag.  Ringflag controls,
    for example, whether we get (2/3) x or (2x/3).  Orderflag
    controls whether polynomials (and other expressions) are written
    in descending or ascending order.

III.  currentline, which is maintained in vaux.c  because definitions
    have to be labelled with the line at which they are made.

IV.  Data maintained in symbols.dll; these are of type controldata
     defined at the top of mpdoc.h and documented in cflags.c.
*/

{ set_currentline(-1);
  set_polyvalfactorflag(1);  // in case it had some other value from a previous document
                             // in autotest or using the Next button
  if(currenttopic == _fundamental_theorem)
     problemtype = INTEGRATION;
     /* set the flags with factoring off, as for integration and differentiation */
     /* this is just a local variable; the document's problemtype remains SIMPLIFY */
  if(currenttopic == _trig_factor ||
     problemtype == COMMON_DENOMINATOR ||
     problemtype == COMPOUND_FRACTIONS ||
     problemtype == ROOTS ||
     (problemtype == SIMPLIFY  &&  ALGEBRA_TOPIC(currenttopic))
    )
     set_ringflag(GAUSSINT);  /* prefer (a+b)/2 to (1/2)(a+b)  */
  else
     set_ringflag(GAUSSRAT);   /* same as the default value in globals.c */
  if(SERIES_TOPIC(currenttopic)) 
     set_orderflag(ASCENDING);
  else
     set_orderflag(DESCENDING);
  pDocControlData->autosteps = 0;
  if(SOLVETYPE(problemtype) || problemtype == INTEGRATION)
     { int ringflag = get_ringflag();
       ringflag  |= ALGINT;    /* factors containing radicals desired */
       set_ringflag(ringflag);
     }
  if( problemtype == SIGMA_NOTATION)
     set_polyvalzeropowerflag(1);
  else
     set_polyvalzeropowerflag(0);
  pDocControlData->comdenomflag = 0;    /* it will be set to 1 below in different places
             for different problem types, and otherwise keep this value */

   /* first set factorflag and expandflag, which must be compatible
      or there will be loops  */
  if( problemtype == TRIG_IDENTITY || currenttopic == _trig_product)
     { pDocControlData->expandflag = 0;
       pDocControlData->factorflag = 0x011;  /* factor in fractions only */
                            /* you have to factor because cancelgcd won't
                               find things like (sin^3-cos^3)/(1+sin cos) */
       set_polyvalfactorflag(0);
       pDocControlData->comdenomflag = 1;
     }
  else if( problemtype == COMMON_DENOMINATOR)
     { pDocControlData->factorflag = 0x011;  /* factor in fractions only */
       pDocControlData->expandflag = 0;
       pDocControlData->comdenomflag = 1;
     }
  else if( problemtype == FACTOR ||
      problemtype == INDUCTION ||
      problemtype == SIMPLIFY ||
      problemtype == COMPOUND_FRACTIONS
    )
     { pDocControlData->factorflag = 0x111;  /* factor everything */
       pDocControlData->expandflag = 0;
       pDocControlData->comdenomflag = 1;

                  /*  don't multiply out products wherever they
                      occur.  If they occur in a sum in a
                      numerator, 'expand' will multiply them
                      out, see 'don't expand'  */

                  /*  examples:
                      don't expand: (n-1)(n-3) + 1/(n-3)
                      don't expand:  n(n+1) + 1/(n+1) + 1/n ;
                      do expand:  (x(x+1) +x )/((x-1)(x-2))
                      don't expand:  y(y-x)/(y^2-x^2)
                  */
     }

     /* When solving equations, we don't turn on factoring
        automatically, because we don't want to factor until the
        right side is zero.  At the beginning of one_step, the
        factor and expand flags will be set.  This way also they
        don't have to be handled by undo.  */

  else if(problemtype == BINOMIAL_THEOREM ||
          problemtype == EXPAND ||
          currenttopic == _complex_arithmetic ||
          currenttopic == _de_moivre
         )
     { pDocControlData->expandflag = 0x0100;   /* expand everything */
       pDocControlData->factorflag = 0;
       set_polyvalfactorflag(0);
     }
  else if(problemtype == INTEGRATION || problemtype == POWERSERIES)
     { /* factor denominators only */
       pDocControlData->factorflag = 0x0010;
       pDocControlData->expandflag = 0;
     }
  else
     { pDocControlData->expandflag = 0;
       pDocControlData->factorflag = 0;
       set_polyvalfactorflag(0);
     }
   /* Now for content-factoring, which is allowed even when full
      factoring is not.  But when solving equations, it causes trouble
      to allow content-factoring when right side isn't zero.  */

  if(SOLVETYPE(problemtype) ||
      problemtype == LINEAR_EQUATIONS ||
      problemtype >= LIMITS   /* don't factor when doing calculus */
    )
      set_polyvalfactorflag(0);

   /* Now for negative exponents */

  if(problemtype==NEGATIVE_EXPONENTS)
     set_polyvalnegexpflag(1);
  else if(COMPLEXTOPIC(currenttopic))
     set_polyvalnegexpflag(2);
  else if(problemtype==ELIMINATE_NEGATIVE_EXPONENTS)
     set_polyvalnegexpflag(-1);
  else
     set_polyvalnegexpflag(0);  /* tolerate them except in denominators,
                           but don't create them on purpose */
   /* Now for fractional exponents versus radicals */
  set_polyvalfractexpflag(0);  /* it may be set to 1 later by
     determine_radicalflag in getprob.c. But if this line isn't here,
     it can retain a nonzero value from a previous problem. */
  if(problemtype==FRACTIONAL_EXPONENTS || problemtype == POWERSERIES)
     pDocControlData->radicalflag = -1;   /* convert to fractional exponents */
  else if(problemtype >= DIFFERENTIATE)
     pDocControlData->radicalflag = -2;  /* convert roots but not sqrts to fractional exponents */
             /* this turns fractional exponents on for all calculus problems
                except LIMITS and DIFFERENTIATE_FROM_DEFN; note this includes
                LHOPITAL.  Square roots will be converted when occurring in
                products with more than one nonconstant term  as x sqrt x, because
                sqrtexp is in autoproduct */
  else if(problemtype==ROOTS)
     pDocControlData->radicalflag = 1;    /* eliminate fractional exponents */
  else
     pDocControlData->radicalflag = 0;   /* tolerate both */
   /* Now what about common denominators? */
  if( problemtype == COMMON_DENOMINATOR ||
      problemtype == COMPOUND_FRACTIONS ||
      problemtype == ROOTS ||
      (problemtype == SIMPLIFY  &&  ALGEBRA_TOPIC(currenttopic))||
      currenttopic == _solve_rational_equation ||
      currenttopic == _solve_root_equation ||
      currenttopic == _solve_linear_equation || /* in Algebra 1 with common
                                             denoms set to LEARNING.  We don't
                                             put fractional equations in the
                                             Mathpert problem set but someone
                                             could enter one. */
      currenttopic == _solve_fractions_and_roots ||
      currenttopic == _solve_polynomial_inequality ||
      currenttopic == _solve_rational_inequality ||
      currenttopic == _solve_root_inequality
    )
       { pDocControlData->comdenomflag = 1;
         /* expandflag is already zero */
       }

  /* if comdenom hasn't been set somewhere above, it keeps the value 0
     that it got at the top of this function */
  /* Now: for some topics we call infer(domain) and so can assume all
  subexpressions are defined. But for some, we do not. */
  set_polyvaldomainflag(domainflag(problemtype, currenttopic));
  if(currenttopic == _int_poly || currenttopic == _simple_int)
     set_polyvalintflag(0);
  else
     set_polyvalintflag(1);
  pDocControlData->mathmode = MENUMODE;
  if(currenttopic == _cubic_one_root ||
     currenttopic == _complex_cubics
    )
     display_off();
  else
     display_on();
  pDocControlData->memoryflag = 0;
  pDocControlData->complex_frozen = 0;
  pDocControlData->checksolutionsflag = 0;
  pDocControlData->logcollectflag = 0;
  pDocControlData->trigexpandflag = 0;  /* set again for each line in autosimp.c */
  set_selected_equation(0);
  set_pending(NULL);
  pDocControlData->successivefailures = 0;
  pDocControlData->localfailures = 0;
  set_polyvalfactorflag2(0);  /* make sure that garbage values don't
                                 corrupt the operation of MathXpert, even
                                 though in principle, polyvalfactorflag2
                                 and polyvallogflag are always reset
                                 to zero after use.  */
  set_polyvallogflag(0);
  pack_flags(0);    /* store the current values so undo can restore them
                       when we undo all the way back to line 0  */
}
/*_________________________________________________________*/
void automode(void)
{ pDocControlData->mathmode = AUTOMODE;
}

void menumode(void)
{ pDocControlData->mathmode = MENUMODE;
}

void selectionmode(void)
{ pDocControlData->mathmode = SELECTIONMODE;
}

int get_mathmode(void)
{  return pDocControlData->mathmode;
}

void set_mathmode(int n)
/* used to set DEMOMODE and AUTOTEST */
{ pDocControlData->mathmode = n;
}

/*________________________________________________________________*/
void get_controldata( controldata *d)
/* Used from outside symbols.dll to retrieve the control flags. */
{ *d = *pDocControlData;
}
/*________________________________________________________________*/
void set_controldata( controldata *d)
/* Used from outside symbols.dll to change the control flags.
Use the separate functions like set_complex_frozen
when possible. */

{  *pDocControlData = *d;
}

/*_______________________________________________________________*/
term get_minmax_interval(void)
{ return pDocControlData->minmax_interval;
}
/*_______________________________________________________________*/
void set_minmax_interval(term p)
{ pDocControlData->minmax_interval = p;
}
/*_______________________________________________________________*/
void set_complex_frozen(int n)
{ pDocControlData->complex_frozen =  n;
}
/*_______________________________________________________________*/
void set_selected_equation(int n)
  /* which of several equations are we working on ?  */
  /* numbered up from 1.  Negative means other equations
     should not be displayed.  Positive means all equations
     should be displayed, but 'add_term' and so on
     work on the selected equation.  Zero means no
     equation is selected */
{ pDocControlData->selected_equation = n;
}

/*_______________________________________________________________*/
int get_selected_equation(void)
{ return pDocControlData->selected_equation;
}

/*________________________________________________________________*/
int get_problemtype(void)
{ if(pActiveDoc)
     return pActiveDoc->problemtype;
  //  assert(0);
  printf("get_problemtype was called on an inactive document\n");
  return SIMPLIFY;  // don't crash, just report it on the console.
}
/*________________________________________________________________*/
void set_problemtype(int p)
{ if(pActiveDoc)
     pActiveDoc->problemtype = p;
  else
     printf("set_problemtype was called on an inactive document\n");
    // assert(0);  but don't crash, just report it to the console.
}
/*________________________________________________________________*/
int get_currenttopic(void)
{ return pDocControlData->currenttopic;
}
/*________________________________________________________________*/
void set_currenttopic(int n)
{ pDocControlData->currenttopic = n;
}
/*_______________________________________________________________*/
inhibition * get_inhibitions(void)
{ return pDocControlData->inhibitions;
}
/*_______________________________________________________________*/
void set_inhibitions(inhibition *p)
{ pDocControlData->inhibitions = p;
}
/*_________________________________________________________*/
void display_on(void)
/* Turn on visible display in display_progress, etc. */
{ pDocControlData->display_on = 1;
}
/*_________________________________________________________*/
void display_off(void)
/* Turn off visible display in display_progress, etc. */
{ pDocControlData->display_on = 0;
}
/*_________________________________________________________*/
int inq_display_on(void)
/* return 1 if display_progress etc. are set to produce visible display */
{ return pDocControlData->display_on ? 1 : 0;
}
/*__________________________________________________________*/
int get_substitutionflag(void)
{ return pDocControlData->substitutionflag;
}
/*__________________________________________________________*/
void  set_substitutionflag(int k)
{ pDocControlData->substitutionflag = k;
}
/*__________________________________________________________*/
void set_factorflags(term t)
/* t is an equation or inequality.  Turn factoring on if
(1) the right side of an equation t is zero, or for an inequality if
either side is zero; or
(2) the right side does not contain the eigenvariable and the
left side is a perfect square.
   Example:  x^2+2x+1 = c; factor and don't move the c left
*/

{ unsigned f = FUNCTOR(t);
  term left, right,temp;
  char buffer[DIMREASONBUFFER];
  int problemtype = get_problemtype();
  term x;
  int stopflag = GetStopFlag();
  assert(INEQUALITY(f));
  x = get_eigenvariable();
  SetStopFlag(1);   /* prevent factorsquareofsum etc. from releasing inhibitions */
  left = ARG(0,t);
  right = ARG(1,t);
  if(f != '=')
     { if(contains(right,FUNCTOR(x)) && !contains(left,FUNCTOR(x)))
          { temp = left;
            left = right;
            right = temp;
          }
     }
  if(problemtype < LIMITS &&
     (
      ZERO(right) ||
      (!contains(right,FUNCTOR(x)) &&                   /* right is constant and */
       ( !factorsquareofsum(left,zero,&temp,buffer) ||  /* left is a square */
         !factorsquareofdif(left,zero,&temp,buffer)
       )
      )
     )
    )
     {  /* turn factoring on */
       pDocControlData->factorflag = 0x0100;       /* set control flags so left side can get factored */
       pDocControlData->expandflag = 0;
       set_polyvalfactorflag(1);
       SetStopFlag(0);
       return;
     }
  pDocControlData->factorflag = pDocControlData->expandflag = 0;
  set_polyvalfactorflag(0);  /* turn off content-factoring too */
  set_pathtail(NULL);     /* trying factoring operators above can set it */
  SetStopFlag(stopflag);  /* turn the inhibit-release mechanism back on */
  return;
}
/*______________________________________________________________________*/
int domainflag(int problemtype, int currenttopic)
/* return 1 if Mathpert SHOULD check that the problem is defined,
0 if it NEED NOT check it.  This depends only on the topic and problemtype.
This is used to set the domainflag using set_polyvaldomainflag;
after it is once initialized, you check it with get_polyvaldomainflag.
If Mathpert has already checked the domain, then some side conditions
don't need to be checked, e.g. that x is defined in 0 x = 0; but if
the domains haven't been checked, these conditions MUST be checked.
*/
{ switch(problemtype)
     { case LIMITS:  /* fall through */
       case LHOPITAL:
          return 1;
     }
  if(currenttopic == _evaluate_trig)
     return 1;
  if(currenttopic == _improper_integrals)
     return 1;
  return 0;
}
/*______________________________________________________________________*/
void set_pending(assumption *p)
{ pDocControlData->pending = p;
}

assumption *get_pending(void)
{ return pDocControlData->pending;
}
/*_____________________________________________________________________*/
/* 'pending'  points to a stack (linked list) of terms.  The nodes of
this stack are of type 'assumption' (see globals.h), which gives a
term, a line number (at which the expression was pushed on the stack),
and a link field; this type is used just for convenience, the entries
aren't really assumptions, just unfinished problems. */
/* permalloc and permfree are used for this list because it has
to live longer than one step; possibly as long as the document.
Therefore also the terms pushed onto this list should not occupy space
on the document heap.  Normally history(currentline) or a subterm of it
is pushed.
*/

void pushpending(term t, int currentline)
{  assumption *p;
   assumption *pending = get_pending();
   term q,ans;
   int err;
   p = permalloc(sizeof(assumption));
   if(p==NULL)
      nospace();
   q = history(currentline);
   err = find_as_subterm(t,q,&ans);
   if(!err)
      p->prop = ans;
   else
      permcopy(t,&p->prop);
   p->line = currentline;
   p->link = pending;
   set_pending(p);
}
/*_______________________________________________________________________*/
 /* return 0 if stack isn't empty, and in that case instantiate t to
a copy of the top element, popping it off and freeing its node */

int poppending(term *t)
/* needed by undo, therefore */
{  assumption *temp;
   assumption *pending = get_pending();
   if(pending==NULL)
      return 1;
   copy(pending ->prop,t);
   temp = pending->link;
   permfree(pending);
   set_pending(temp);
   return 0;
}
/*____________________________________________________________________*/
/* read the top of the pending stack without popping it */
/* Return 1 if the stack is empty, 0 otherwise */

int readpending(term *t)
{ assumption *pending = get_pending();
  if(pending==NULL)
      return 1;
   *t = pending->prop;
   return 0;
}

/*_______________________________________________________________*/
/* see parser.h for the typedef of parser_control */

static parser_control parser_flags = { 2,  /* separator, see display.c */
                                  '.', /* decimalchar      */
                                  1,   /* unwritten_mult   */
                                  1,   /* complex          */
                                  2,   /* long_identifiers */
                                  0,   /* letflag          */
                                  "fFgGhH  "
                                };
/*______________________________________________________________*/
parser_control * get_parser_flags(void)
/* access the parser flags */
{ return &parser_flags;
}
/*______________________________________________________________*/
void set_parser_decimalchar(char c)
/* set decimalchar; used when switching languages */
{ char *rest;
  parser_flags.decimalchar = c;
  bparse(NULL,NULL,"",&rest);  /* this tells the parser that the flags have changed,
                                so next time it should call setup_parser. */
}
/*__________________________________________________________________*/
void set_parser_complex(int flag)
{ parser_flags.complex = flag;
}
/*__________________________________________________________________*/
static int nCmdLineArgs;  /* counting the .exe file, so it's always >= 1 */
#define MAXCOMMANDLINEARGS 2

/* You can only specify file to open on the command line.  You can
specify either a .mxp file or a .hw file but not both.  If the filename
extension is not .hw then a .mxp will be later added and it's assumed
the file is intended as a .mxp file. To accomodate filenames with spaces, it
is assumed that the entire rest of the command line after the exe file name
is the filename being passed as an argument.  */

static char *argv[MAXCOMMANDLINEARGS];

void StoreCommandLine(char *filename)
/* store the path to mathpert.exe; called from WinMain.
Filename is passed in as the complete command line including the
full path to mathpert.exe.  Exception:  if Mathpert was actually
invoked by typing to a command prompt, then the command line is
exactly what was typed, i.e. does not include the path to that folder.
  Allocate the static array argv defined above
and fill in the command line args.   The memory is allocated
by calloc and will never be freed (until Mathpert terminates
and the system gives back the block from which calloc allocates.)
  Accommodating filenames with spaces:  it's assumed that the
.exe file name (and path) does not contain spaces, or if it does, it
is enclosed in quotes.   Whatever follows the exe file name is
assumed to be the argument file (spaces and all).  If it is enclosed
in quotes, the quotes are stripped off before storing.
*/
{ char *next, *marker;
  int exeflag;
  if(filename[0] == '\"')
     { ++filename;   /* it arrives with quotes in Visual C++ at least sometimes */
       next = strchr(filename,'\"');
       assert(next);  /* there must be a closing quote */
       *next = '\0';
       marker = next-1;
       while(marker >= filename && *marker == 32)
          --marker;
       marker[1] = '\0';
       if(marker <= filename+3)
          exeflag = 0;
       else
          { marker -=3;
            exeflag = !strcmp(marker,".exe") || !strcmp(marker,".EXE");
          }
       argv[0] = calloc(strlen(filename)+1 + (exeflag ? 0 : 4),sizeof(char));
       assert(argv[0]);
       strcpy(argv[0],filename);
       if(!exeflag)
          strcat(argv[0],".exe");
       ++next;
       while(*next == 32)
          ++next;  /* skip blanks */
       if(!next[0])
          { nCmdLineArgs = 1;
            return;
          }
     }
  else   /* but without quotes from a Web page, or in Win16, or from the actual command line. */
     { next = strchr(filename,32);
            if(next != NULL && next[1] == '\0')
         /* this happens in Win16!  */
          { next[0] = '\0';
            next = NULL;
          }
       if(next != NULL)
               next[0] = '\0';
       marker = filename + strlen(filename)-1;
       while(marker >= filename && *marker == 32)
          --marker;
       marker[1] = '\0';
       if(marker <= filename+3)
          exeflag = 0;
       else
          { marker -=3;
            exeflag = !strcmp(marker,".exe") || !strcmp(marker,".EXE");
          }
       argv[0] = calloc(strlen(filename)+1 + (exeflag ? 0 : 4),sizeof(char));
       assert(argv[0]);
       strcpy(argv[0],filename);
       if(!exeflag)
          strcat(argv[0],".exe");
       if(next == NULL)
          { nCmdLineArgs = 1;
            return;
          }
       ++next;
     }
  /* Now there was a filename specified on the command line */
  while(*next == 32)
     ++next;  /* skip blanks */
  if(*next == '\0')
     { nCmdLineArgs = 1;
       return;
     }
  argv[1] = calloc(strlen(next)+5,sizeof(char));  /* room to add ".mxp" and a null terminator */
  assert(argv[1]);
  if(*next == '\"')
     { ++next;
       if(next[strlen(next)-1] == '\"')
          next[strlen(next)-1] = '\0';
     }
  strcpy(argv[1],next);
  nCmdLineArgs = 2;
}

/*____________________________________________________________*/
/* Just a note for future reference */
/*
#if 0
#if defined(_WIN32)
  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
  {
    return GetModuleFileNameA(NULL, pathName, (DWORD)pathNameCapacity);
  }
 
#elif defined(__APPLE__)  
  #include <mach-o/dyld.h>
  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
  {
    uint32_t pathNameSize = 0;

    _NSGetExecutablePath(NULL, &pathNameSize);

    if (pathNameSize > pathNameCapacity)
      pathNameSize = pathNameCapacity;

    if (!_NSGetExecutablePath(pathName, &pathNameSize))
    {
      char real[PATH_MAX];

      if (realpath(pathName, real) != NULL)
      {
        pathNameSize = strlen(real);
        strncpy(pathName, real, pathNameSize);
      }

      return pathNameSize;
    }

    return 0;
  }
#else 
  #error provide your own implementation
#endif  
*/
/*_______________________________________________________________*/
#ifdef _MAC
#define PATHCHAR ':'
#else
#define PATHCHAR '\\'
#endif

char * GetMathpertFolder(void)
/* return the full path of the folder containing mathpert.exe, except
as noted below.  This is just argv[0] with "mathpert.exe" stripped off the end.
The PATHCHAR is left on the end so other filesnames can just be strcat'ed on.
   If mathpert has been invoked by typing to a command line, then
the returned string is the empty string (one null terminator only).
It should still be suitable for strcat'ing a filename onto it.
*/

{ int n;
  static char *folder;
  if(folder)
     return folder;
  if(argv[0] == NULL)  
     { // this happens when this is called from ComputeCheckSums
       return "\\home\\mp64\\mathpert\\Debug\\";
     }  
  /* The first time, folder will be NULL and we'll fill it in */
  n = (int) strlen(argv[0])-1;
  folder= calloc(n+1,sizeof(char));
  strcpy(folder,argv[0]);
  while(n >= 0 && folder[n] != PATHCHAR)
     --n;
  if(folder[n] == PATHCHAR)
     folder[n+1] = 0;
  else
     { folder[0] = 0;
       /* Mathpert is in the root directory,
          or has been invoked from the command line
       */
      
       
       folder = "./";
       #ifdef _WIN32
          folder = ".\\";
       #endif
       
     }
  return folder;
}
/*______________________________________________________________________*/
char * GetMathpertHelpFile(void)
/* return the name of the help file to use with the
currently selected language */
{ char *folder;
  int language_number;
  static char *helpfile;
  if(helpfile == NULL)
     { folder = GetMathpertFolder();
       if(folder == NULL)
          assert(0);
       helpfile = (char *) calloc(strlen(folder) + 64, sizeof(char));
     }
  strcpy(helpfile,GetMathpertFolder());
  language_number = get_selected_language();
  if(language_number == CANADIAN)
     language_number = FRENCH;
  strcat(helpfile, english_language_name(language_number));
  strcat(helpfile, ".chm");
  return helpfile;
}

/*______________________________________________________________________*/
char * GetCommandLineArg(int n)
/* return the n-th command line argument.  If n == 0
it returns the path to mathpert.exe, including mathpert.exe.
If n = 1, 2, ..  it returns the command line arguments.
Return NULL if n is too large.
*/
{ if(n < nCmdLineArgs)
     return argv[n];
  return NULL;
}

/*__________________________________________________________________*/
static int find_as_subterm(term t, term q, term *ans)
/* if t is equal to a subterm of q (possibly equal to q) return
that subterm in *ans, returning 0.  If not return 1.
*/
{ unsigned short i,n;
  int err;
  if(equals(t,q))
     { *ans = q;
       return 0;
     }
  if(ATOMIC(q))
     return 1;
  n = ARITY(q);
  for(i=0;i<n;i++)
     { err = find_as_subterm(t,ARG(i,q),ans);
       if(!err)
          return 0;
     }
  return 1;
}


Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists