Sindbad~EG File Manager

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

/* M. Beeson, for Mathpert.
Some of the ShowStep machinery, and some of the Term Selection Menu
machinery.  

Original date 4.26.96
Last modified 2.28.99
1.14.00 modified GetActiveArea
1.16.05 moved RemoveAll to opmenus.c
1.18.06 changed handles to pointers, etc.
1.18.06 changed access to papyrus to use document instead of GetWindowLong
1.19.06 extracted this code from file sstep.c; this file is now independent of Windows.
5.6.13 include <stddef.h>
4.11.24 modified opcommand to set first four bytes of 8-byte int to zero
5.15.24 added pPapyrus->selectedline = ActiveLine;  several places in ShowStepFocus
*/
#include <assert.h>
#include <stdlib.h>  /* abs */
#include <stdio.h>   /* sprintf */
#include <string.h>
#include <stddef.h>
#include "globals.h"
#include "graphstr.h"
#include "display.h"
#include "mpdoc.h"
#include "cflags.h"   /* get_selected_equation  */
#include "display1.h" /* block             */
#include "bigrect.h"
#include "lterm.h"    /* select_term       */
#include "automode.h" /* get_activeline    */
#include "autosimp.h" /* GetShowStepOperation, GetShowStepPath, etc.   */
#include "lsubterm.h" /* located_subterm   */
#include "mtext.h"    /* MAXMENUS    */
#include "optable.h"  /* access_optable    */
#include "islinear.h" /* is_linear_system  */
#include "showstepfocus.h" /* ShowStepFocus */
#include "activedoc.h" 

static lterm get_focus(lterm lt, unsigned short *path);
static int same_rectangle(lterm t, lterm q);
static int MoreFoci(lterm lt,lterm ActiveLine,pathlist *,ltermlist *marker);

/*_______________________________________________________________*/
static lterm ActiveLine;
/* This variable holds the located current line from which
Show Step has to select a term.  SetActiveLine sets it.
When reset_heap destroys the term created by SetActiveLine,
there's no way to tell that from here, so
the user of ActiveLine must know that
SetActiveLine has been called recently enough.
*/
/*________________________________________________________________*/
 void SetActiveLine(PDOCDATA pDocData, BIGRECT *s)
/* pDocData is a valid document pointer.
Determine the active line and call locate_term,
and set the static global ActiveLine to the located term
representing the active line.  Return the active area
in *s.  This is called when the
Show Step button on the SpeedBar is pressed.
*/

{ term t,bt,system,vlist;
  int offset,selectedeqn;
  int activeline = get_activeline();
  Papyrus *pPapyrus = pDocData->papyrus;
  if(pPapyrus == NULL)
     assert(0);  // 12.3.14
  GetActiveArea(pPapyrus,s,&offset);
  t = pDocData->DocProverData.history[activeline];
  if(FUNCTOR(t) == AND || FUNCTOR(t) == OR)
     { selectedeqn = get_selected_equation();
       if(selectedeqn < 0)
          { selectedeqn = -selectedeqn;
            if(selectedeqn > ARITY(t))
               assert(0);
            t = ARG(selectedeqn-1,t);
          }
     }
  if(FUNCTOR(t) == AND &&
     LINEUP(t) &&
     !is_linear_system(t,activeline,&vlist)
     /* is_linear_system returns 0 for success */
    )
     /* send a term with functor LINEARSYSTEM to be bblocked */
     { system = make_term(LINEARSYSTEM,2);
       ARGREP(system,0,t);
       ARGREP(system,1,vlist);
       t = system;
     }
  bblock(t,&bt);
  s->left += papyrus_to_xpixel(pPapyrus->leftmargin);
  s->top  += offset;  /* see solution.c for similar lines */
  locate_term(bt,s,&ActiveLine);
  if(pDocData->DocControlData.linebreaks)
     lbreak(&ActiveLine);
}
/*________________________________________________________________________*/
#define MAXLEGAL 10
static int legal_path(actualop code, unsigned short legal[MAXLEGAL], unsigned short required[MAXLEGAL], int *nrequired)
/* When looking for an argument to code, to be used as a 'dowith'
operation, we restrict the path to the subterm by requiring it to
lie on a legal path.  The functors that are allowed on the path to
the arg of code are determined here.  Return the actual dimension
of the array, which must be at most MAXLEGAL.  Return 0 if no
restrictions are to be imposed.
  We may also restrict the path by REQUIRING certain functors
to appear on the path, e.g. diveqn requires a '*' or '/' on the
path, to avoid selecting the first 2 in  2 < 2x.  (If you select
that 2, then "divide both sides by ?" won't come up on the Term
Selection Menu.)  Such functors, if any, are placed in
'required', and the number of them is placed in *nrequired.  The
interpretation is that at least ONE of the members of the required
array must be on the path.
*/

{ if((void  *) code == (void  *) addeqn)
      { legal[0] = '=';
        legal[1] = '+';
        legal[2] = '-';
        required[0] = '-';
        *nrequired = 1;
        return 3;
      }
  if((void  *) code == (void  *) subeqn)
      { legal[0] = '=';
        legal[1] = '+';
        /* '-' is not legal; example, -8y -2 = 8y, subtract the y on the
           right; if '-' is legal we'll get the one on the left.
           A term inside a '-' is going to be added, not subtracted,
           so we should never miss the correct term this way.
        */
        *nrequired = 0;  /* '+' is not required, as in 6x-4 = x we want to subtract x */
        return 2;
      }
   if( (void  *) code == (void  *) addeqn1 ||
       (void  *) code == (void  *) addeqn2
     )
      { legal[0] = '-';
        legal[1] = '<';
        legal[2] = '>';
        legal[3] = LE;
        legal[4] = GE;
        legal[5] = '+';
        legal[6] = AND;  /* because of interval_as_and terms */
        required[0] = '+';
        required[1] = '-';
        *nrequired = 2;
        return 7;
      }
   if( (void  *) code == (void  *) subeqn1 ||
       (void  *) code == (void  *) subeqn2 ||
       (void  *) code == (void  *) cancelterm
     )
      /* '-' is not legal, for the same reasons explained above under
         subeqn.  Also for cancelterm, if the arg of a negative term
         could be cancelled, the whole negative term would have been
         selected. */
      { legal[0] = '=';
        legal[1] = '<';
        legal[2] = '>';
        legal[3] = LE;
        legal[4] = GE;
        legal[5] = '+';
        legal[6] = AND;  /* because of interval_as_and terms */
        *nrequired = 0;  /* so we can subtract x in f(x) > x  */
        return 7;
      }
  if( (void  *) code == (void  *) muleqn)
      { legal[0] = '=';
        legal[1] = DENOM;
        legal[2] = '-';
        legal[3] = '+';
        legal[4] = '*';
        required[0] = '/';
        *nrequired = 1;
        /* (2/3) x = 1 might be multiplied by (3/2) but you
            can't select the arg by Term Selection in that case. */
        return 6;
      }
  if( (void  *) code ==(void  *) mulineq ||
      (void  *) code == (void  *) mulineqsq
    )
      { legal[0] = '<';
        legal[1] = DENOM;
        legal[2] = '-';
        legal[3] = '+';
        legal[4] = '*';
        legal[5] = LE;
        legal[6] = GE;
        legal[7] = '>';
        legal[8] = AND;
        required[0] = '/';
        *nrequired = 1;
        return 9;
      }
  if( (void  *) code == (void  *) diveqn)
      { legal[0] = '=';
        legal[1] = NUMERATOR;
        legal[2] = '-';
        legal[3] = '+';
        legal[4] = '*';
        required[0] = '*';
        /* You might divide (3/2) x = 1 by 3, but ShowStep isn't going to
           do that. */
        *nrequired = 1;
        return 5;
      }
  if( (void  *) code == (void  *) divineq)
      { legal[0] = '<';
        legal[1] = NUMERATOR;
        legal[2] = '-';
        legal[3] = '+';
        legal[4] = '*';
        legal[5] = LE;
        legal[6] = '>';
        legal[7] = GE;
        legal[8] = AND;
        required[0] = '*';
        *nrequired = 1;
        return 9;
      }
  *nrequired = 0;
  return 0;
}

/*________________________________________________________________________*/
 void ShowStepFocus(operation *op)
/*  Get the current document data structure; if
pDocData->DocControlData.showstepflag is 0, do nothing further.
Otherwise, add one more node to the list of lterms in the
selected_term field in the papyrus data structure.   These
terms are the terms that Show Step will show as selected.
The term to add is computed
using the path stored by autosimp, together with information
stored when operators call SetShowStepArg, SetShowStepArgs, etc.
SetActiveLine must have been called recently.
HDoc is passed as the document window handle.
   If only the selected equation of a system is being displayed,
ActiveLine is only that one equation.
*/
{ PDOCDATA pDocData = GetActiveDoc();
  Papyrus *pPapyrus;
  actualop code;
  term arg, arg2;
  unsigned short *path;
  ltermlist *largs, *marker, *ans;
  lterm lt;
  int activeline = get_activeline();
  unsigned short legal[MAXLEGAL];
  unsigned short required[MAXLEGAL];
  int nrequired;
  int nlegal,err,whicheqn;
  if(pDocData->DocControlData.showstepflag == 0)
     return;
  pPapyrus = pDocData->papyrus;
  code = GetShowStepOperation();
  if(code != NULL)
     code_to_op(code,op);
  else
     code = access_optable(op->men)[op->choice-1];
  /* Now code and op are both specified. */
  /* Now, we need to know if this is an operator that is going to do something
     TO the selected term, or WITH the selected term. */
  GetShowStepArgs(&arg,&arg2);
  if(FUNCTOR(arg) == ILLEGAL)
     arg = GetShowStepArg();
  if(FUNCTOR(arg) != ILLEGAL)
     { /* this was a do-with operation.  The automode focus will either
          be the whole active line, or in case it is an OR or AND of equations
          or inequalities, the automode focus might be just one of those
          equations or inequalities.  Except for this, the automode focus
          will be ignored. Showstep must locate and highlight arg instead.
       */
       path = GetShowStepPath();
       if(path[0] == OR || path[0] == VECTOR)
          whicheqn = path[1];
       else if(path[0] == AND && ARITY(ActiveLine) > 2)
          whicheqn = path[1];
       else if(path[0] == AND)
          { if(linterval_as_and(ActiveLine))
               whicheqn = 0;
            else
               whicheqn = path[1];
          }
       else
          whicheqn = 0;
       nlegal = legal_path(code,legal,required,&nrequired);
          /* Where is it legal to look for arg?  Example: if code is addeqn,
             and arg is 5,  and the left side of the equation is 5x-5,
             we don't want to highlight the first 5.  This is what
             legal_path is for. */
       if(whicheqn > 0)
          { /* the automode focus is not the whole active line */
            err = located_subterm(arg,LARG(whicheqn-1,ActiveLine),legal,nlegal,required, nrequired,&largs);
            if(err)
               { /* can't find it on a legal path.  Look for it anywhere in the correct eqn */
                 err = located_subterm(arg,LARG(whicheqn-1,ActiveLine),legal,0, required,0,&largs);
               }
            if(!err)
               {  /* Tack on whicheqn to the front of all paths in largs */
                  /* Actually it has to be whicheqn-1, since paths in selected
                     terms number args starting from 0, while whicheqn starts
                     numbering from 1. */
                 for(marker = largs;marker;marker=marker->next)
                    marker->data.path = cons(whicheqn-1, FUNCTOR(ActiveLine), marker->data.path);
               }
          }
       else
          { err = located_subterm(arg,ActiveLine,legal,nlegal,required,nrequired,&largs);
            if(err && nlegal > 0)
                /* can't find it on a legal path.  Look for it anywhere */
                err = located_subterm(arg,ActiveLine,legal,0,required,0,&largs);
          }
       if(!err)
          { pPapyrus->selected = largs;
            pPapyrus->selectedline = activeline;
          }
       else
          /* arg does not occur on-screen, so it will have to be typed in.
             In that case the automode focus should be selected.
          */
          { lterm lt = get_focus(ActiveLine, GetShowStepPath());
            /* append it */
            ans = (ltermlist *) mallocate(sizeof(ltermlist));
            if(ans == NULL)
              { nospace();
                return;
              }
            ans->data = lt;
            ans->next = NULL;
            if(pPapyrus->selected == NULL)
                pPapyrus->selected = ans;
            else
               { for(marker = pPapyrus->selected; marker->next; marker=marker->next)
                    ;
                 /* marker points to the last node in pPapyrus->selected */
                 marker->next = ans;  /* append it */
               }
            pPapyrus->selectedline = activeline;
          }
       /* Example:   x/3 = (x+1)/4,  the 3 and 4 are both selected. */
       if(!err && FUNCTOR(arg2) != ILLEGAL)  /* arg2 is the 4 */
          { err = located_subterm(arg2,ActiveLine,legal,nlegal,required,nrequired,&largs);
            if(err && nlegal > 0)
               /* can't find it on a legal path.  Look for it anywhere */
               err = located_subterm(arg2,ActiveLine,legal,0,required,0,&largs);
            if(!err)
               { if(pPapyrus->selected == NULL)
                     pPapyrus->selected = largs;
                 else
                    { /* append largs to pPapyrus->selected */
                      for(marker = pPapyrus->selected; marker->next; marker=marker->next)
                         ;
                      /* marker points to the last node in pPapyrus->selected */
                      marker->next = largs;
                    }
                 pPapyrus->selectedline = activeline;
               }
          }
     }
  else
     { lt = get_focus(ActiveLine, GetShowStepPath());
       ans = (ltermlist *) mallocate(sizeof(ltermlist));
       if(ans == NULL)
          { nospace();
            return;
          }
       ans->data = lt;
       ans->next = NULL;
       if(pPapyrus->selected == NULL)
          { pPapyrus->selected = ans;
            marker = pPapyrus->selected;
          }
       else
          { /* append lt to pPapyrus->selected */
            for(marker = pPapyrus->selected; marker && marker->next; marker=marker->next)
                { if(same_rectangle(lt,marker->data))
                     { /* it's already in the list of selected terms, don't duplicate it */
                       free2(ans);
                       return;
                     }
                }
            /* Now marker points to the last node */
            if(same_rectangle(lt,marker->data))
               free2(ans);
            else
               marker->next = ans;  /* append it */
          }
       pPapyrus->selectedline = activeline;
       if(!contextsensitive(code))
          /* If there are other copies of this same focus in ActiveLine,
             add nodes for them too. */
          MoreFoci(lt,ActiveLine,NULL,pPapyrus->selected);
     }
}
/*____________________________________________________________*/
static lterm get_focus(lterm lt, unsigned short *path)
/* lt will be a located term representing the active line.
Get the path to the focus using that path passed as the argument, 
and follow that path through lt to get the (next) focus term.  
If the focus is one half of an interval-as-and, back up to include the
whole interval-as-and.
   path will define a path in the actual term t corresponding to
     located term lt. Normally that will also be a path in lt, but
     there can be the following differences:
         (1) t can be an OR of equations or inequalities, while
             lt is a VECTOR of the equations or inequalities.
         (2) t can be an AND while lt is a vector.
         (3) t can be a fraction (with '/') while lt is a FRACT.
        Path is as in preops.c, containing in path[2n] a functor and
     in path[2n+1] an arity+1.  A null entry terminates the path.
     The null terminator will come at an even position.  For example
     if the focus is the left side of an equation, the path
     is [=,1] and is of length 2.
        In case the desired focus is a subrange, say the first two
     terms of a sum of arity 4, the path would be [+,1,SUBRANGE,2].
     SUBRANGE is defined in autosimp.h to be some value that can't
     possibly be a functor.
  */
{ int i,j;
  pathlist *marker, *p;
   /* this is the kind of path that is part of an lterm, see lterm.h.  Do
      not confuse it with the array of unsigned shorts which serves as a
      path in preops.c and is passed as argument to this function. */

  unsigned short f;
  if(path[0] == 0 || path[1] == 0)
     return lt;
  marker = p = (pathlist *) mallocate(sizeof(pathlist));
  if(!marker)
     { nospace();
       return lt;
     }
  f = FUNCTOR(lt);
  for(i=1; path[i-1]; i+=2)
     { if(path[i-1] == SUBRANGE)
          { /* example:  user has selected the first two terms of
               a sum of arity 4.  The path is [+,1,SUBRANGE,2].
               As explained in select.c  (search for "negative")
               the lterm should come out with path ((0,+),(-1,0)); that
               is a negative arity and zero functor
               should be the last entry.  At this point the path
               already has the node (0,+) on it.
            */
            marker->functor = 0;
            marker->data = -path[i];
            marker->next = NULL;  /* that's all, folks */
            break;
          }
       if(f != path[i-1] &&
           /* lt and the original term t do not correspond exactly;
               there are only the following legal possibilities: */
          !(f == VECTOR && (path[i-1] == AND || path[i-1] == OR)) &&
          !(f == FRACT && path[i-1] == '/') &&
          !(f == OR && path[i-1] == AND)  /* this happens in related_rates */
         )
          assert(0);
       marker->functor = f;
       marker->data = path[i]-1;
       if(path[i] && path[i+1] == SUBRANGE)
          { lterm old_lt = lt;
            lterm uu;
            BIGRECT newrect;
            lt.arity =(unsigned short)(path[i+2]-path[i]+1);
            lt.args = callocate(lt.arity, sizeof(lterm));
            /* It is necessary not to change the ActiveLine lterm */
            if(lt.args == NULL)
               { nospace();
                 return lt;
               }
            for(j = 0;j < ARITY(lt) ;j++)
               { uu = LARG(j+path[i]-1,old_lt);
                 LARGREP(lt,j,uu);
                 if(j == 0) /* || uu.r.top < newrect.top)  provokes an
                                  incorrect warning message, but to avoid
                                  it we write the code as you see it. */
                    newrect.top = uu.r.top;
                 else if(uu.r.top < newrect.top)
                    newrect.top = uu.r.top;
                 if(j == 0 || uu.r.bottom > newrect.bottom)
                    newrect.bottom = uu.r.bottom;
               }
            newrect.left = LARG(0,lt).r.left;
            newrect.right = LARG(ARITY(lt)-1,lt).r.right;
            lt.r = newrect;
          }
       else if(f == AND && linterval_as_and(lt) && path[i+2] == 0)
          { path[i+1] = 0;
            path[i] = 0;
            return lt;  /* return the interval_as_and rather than one of its args */
          }
       else
          lt = LARG(path[i]-1,lt);
       f = FUNCTOR(lt);
       if(path[i+1] && path[i+2])
          { marker->next = (pathlist *) mallocate(sizeof(pathlist));
            if(!marker->next)
               { nospace();
                 return lt;
               }
          }
       else
          { if(path[i+1]) /* and path[i+2]==0 */
               path[i+1]=0;
            marker->next = NULL;
          }
       marker = marker->next;
     }
  lt.path = p;
  return lt;
}


/*_____________________________________________________________________*/
 int GetActiveArea(Papyrus *pPapyrus, BIGRECT *r, int *offset)
/* At entry, hwndLong is the handle to the solution window,
and pPapyrus points to the papyrus associated with that window.
Instantiate r to the rectangle in client coordinates
occcupied by the active line.  That is, make it the
entire width of the solution window, and extending from
lines[activeline].formula.x - 8 to
lines[activeline + 1].formula.x - 8
but in window instead of papyrus coordinates.
Return activeline, the index in the history array
returned by get_activeline, to avoid having to call
get_activeline once during this function and again
right after calling this function.  
  In *offset, return the pixel-coordinate difference between
the top of the active area and the beginning of the
actual formula.  This should theoretically always
be papyrus_to_ypixel(8), but it can be off due to
roundoff error, and we need to know EXACTLY what it is.
*/
{ int activeline = get_activeline();
  if(activeline < 0)
      return activeline;  /* shouldn't happen but avoid a GPF if it does.*/
  r->right = pPapyrus->clientRight;
  r->top = papyrus_to_ypixel(pPapyrus->lines[activeline].formula.x-8 - pPapyrus->top);
  *offset = (int) (papyrus_to_ypixel(pPapyrus->lines[activeline].formula.x - pPapyrus->top) - r->top);
  r->bottom = papyrus_to_ypixel(pPapyrus->lines[activeline].formula.y+8 - pPapyrus->top);
  r->left = 0;
#if 0
  if(r->top < 0)
     /* This can happen if an extremely tall formula is created, which
        more than fills the whole solution window, so its top is
        off-screen. Then truncate the active area. */
     r->top = 0;
  assert(r->top >= 0);  /* pPapyrus->topmargin must be at least 8 */
#endif
  return activeline;
}
/*____________________________________________________________________*/
 int opcommand(int i, int j)
/* return the command ID number for operation menu i, choice j,
with j = 0,...,15.
  Choice j appears in the lowest 4 bits; bit 4 is reserved for
use to tell if this command is generated from hMenuSelect or not
(so it is set to zero here); i+1 in the next bits.   At present,
8 bits suffices for the number of menus but we could use more.
Then to avoid collisions with other command we set the leftmost
two bits to 1 and 0 respectively.  (When we set the leftmost bit only,
there is a collision with a WM_COMMAND message generated when a
maximized MDI child window is restored.)

and the leftmost bit is set to avoid collisions with other commands.
This assumes j < 16, which will be the case because
optable never puts more than 16 operators in a menu.
*/

{ int ans = ((i+1) << 5) | j | 0x8000;  // sets bit 15
  /* Now set bits 14 and 13 to 0  and all bits higher than 15 */
  ans  &= ~0xffff6000;
  return ans;
}

/*________________________________________________________________________*/
 actualop associate(operation op)
/* if op is an operation that is used in automode with 2 arguments, but
in Term Selection mode the same effect is achieved by another
operation which works by having the user select one of the arguments
and then prompt for the other, return the operation used in Term
Selection mode.  Return NULL for failure. Example: if op is "subtract two
equations" then return "subtract selected equation from equation ?"
*/

{ actualop in = access_optable(op.men)[op.choice-1];
  if( (void  *) in == (void  *) addtwoeqns )
     return (actualop) addselectedeqn;
  if( (void  *) in == (void  *) subtwoeqns )
     return (actualop) subselectedeqn;
  if( (void  *) in == (void  *) muleqns )
     return (actualop) mulselectedeqn;
  if( (void  *) in == (void  *) diveqns )
     return (actualop) divselectedeqn;
  if( (void  *) in == (void  *) addmuleqns )
     return (actualop) addmulselectedeqn;
  if( (void  *) in == (void  *) submuleqns )
     return (actualop) submulselectedeqn;
  if( (void  *) in == (void  *) swapeqns )
     return (actualop) swapselectedeqn;
  if( (void  *) in == (void  *) addrows )
     return (actualop) addselectedrow;
  if( (void  *) in == (void  *) subrows )
     return (actualop) subselectedrow;
  if( (void  *) in == (void  *) mulrows )
     return (actualop) mulselectedrow;
  if( (void  *) in == (void  *) divrows )
     return (actualop) divselectedrow;
  if( (void  *) in == (void  *) addmulrows )
     return (actualop) addmulselectedrow;
  if( (void  *) in == (void  *) submulrows )
     return (actualop) submulselectedrow;
  if( (void  *) in == (void  *) swaprows )
     return (actualop) swapselectedrow;
  return NULL;
}

/*______________________________________________________________________________*/
static int same_rectangle(lterm t, lterm q)
/* return 1 if t and q have the same rectangle. */
{ if(t.r.left != q.r.left)
     return 0;
  if(t.r.right != q.r.right)
     return 0;
  if(t.r.top != q.r.top)
     return 0;
  if(t.r.bottom != q.r.bottom)
     return 0;
  return 1;
}
/*______________________________________________________________________________*/
static int MoreFoci(lterm lt,lterm p, pathlist *path, ltermlist *marker)
/* lt is one focus for an operation in p, which is found in ActiveLine at the end
of 'path'.   marker points (initially) to the
last node in pPapyrus->selectedterm.  At recursive calls, marker may not point
to the last node, but somewhere in the list.  Find all other copies of the same
term as lt in p, and add them as nodes to the list pointed to
by marker. Don't add a duplicate of lt.
   Return nonzero if more nodes were added, 0 if not.

*/

{ unsigned short n,i;
  int more_nodes;
  pathlist *q,*lastnode,*firstnode;
  pathlist *qmarker;
  ltermlist *originalmarker;
  originalmarker = marker;
  if(lequals(lt,p))
     { if(same_rectangle(lt,p))
          return 0;
        /* add a new node for p unless it duplicates one of the nodes already in marker */
       while(marker && marker->next)
          { if(same_rectangle(marker->data,p))
               return 0;   /* p is already in the list */
            marker = marker->next;
          }
       /* Now marker points to the last node */
       if(same_rectangle(marker->data,p))
          return 0;
       marker->next = (ltermlist *) mallocate(sizeof(ltermlist));
       marker->next->data = p;
       marker->next->data.path = copy_pathlist(path);
       marker->next->next = NULL;
       return 1;
     }
  if(ATOMIC(p))
     return 0;
  n = ARITY(p);
  q = (pathlist *) mallocate(sizeof(pathlist));
  if(q == NULL)
     { nospace();
       return 0;
     }
  q->functor = FUNCTOR(p);
  q->next = NULL;
  if(path)
     { qmarker = path;
       while(qmarker && qmarker->next)
          qmarker = qmarker->next;
       qmarker->next = q;
       lastnode = qmarker ->next;
       firstnode = path;
     }
  else
     firstnode = lastnode = q;
  more_nodes = 0;
  for(i=0;i<n;i++)
     { lastnode->data = i;
       more_nodes += MoreFoci(lt,LARG(i,p), firstnode ,originalmarker);
       while(marker && marker->next)
          marker = marker->next;
     }
  free2(q);
  if(path)
     qmarker->next = NULL;
  return more_nodes;
}

/*___________________________________________________________________*/
 void InitializeShowStep(void)
/* Make sure that the values of variables ShowStep uses do
not retain any old values, which would now contain garbage.
   Also reset pPapyrus->selected to NULL.
*/
{ PDOCDATA pDocData = GetActiveDoc();
  term arg,arg2;
  Papyrus *pPapyrus;
  if(pDocData == NULL)
     { set_pathtail(NULL);
       return;
     }
  if(pDocData->kind == SYMBOLDOC)
     { /* otherwise there's no solution window and no papyrus */
	    pPapyrus = pDocData->papyrus;
       pPapyrus->selected = NULL;
     }
  set_pathtail(NULL);
  SetShowStepOperation(NULL);
  SETFUNCTOR(arg,ILLEGAL,0);
  SETFUNCTOR(arg2,ILLEGAL,0);
  SetShowStepArgs(arg,arg2);
  SetShowStepArg(arg);
}

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