Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/docdata/
Upload File :
Current File : /usr/home/beeson/MathXpert/docdata/undo.c

/* M. Beeson for Mathpert; implementation of 'undo' */
/*
8.17.94 original date
3.18.99 last modified
2.29.00 modified under TESTCONVERGENCE
3.2.00 added lines involving bindvar and unbindvar
1.18.06 changed handles to pointers
1.21.11 totalautosteps decremented  [undone 11.20.24]
4.19.13  changed GetWindowLong and SetWindowLong to GetWindowLongPtr and SetWindowLongPtr, doubling offsets. 
6.7.13  removed windows.h etc.; code to adjust display after undo changes the document structure is now 
in symproc.c and speedbar.c instead of here.
3.18.23 added lastop = (actualop) NULL  to avoid uninitialized use
2.13.24 made undo remove any hint or finalremark from the papyrus.
2.21.24 made undo remove the selected term when currentline is zero.
5.30.24 made undo "erase" comments and error messages from the papyrus.
        But it won't restore those that were formerly there.
        Made it remove error messages even when the line number is 0
9.14.24 Made it remove finalremark when the line number is 0,
        and set finishedflag to 0.
11.19.24 modified temporarily at "shouldn't have to"
*/

#include <stdlib.h>
#include <stdio.h>  // just for debug statements
#include <stddef.h>
#include <assert.h>
#include "globals.h"
#include "mathpert.h"
#include "graphstr.h"
#include "mpdoc.h"
#include "undo.h"
#include "ops.h"
#include "trig.h"
#include "calc.h"
#include "cflags.h"    /* unpack_flags       */
#include "induct.h"    /* undo_inductionvars */
#include "intsub.h"    /* poppending         */
#include "relrates.h"  /* PUTNUMBERSIN etc   */
#include "operator.h"
#include "probtype.h"
#include "mtext.h"     /* MAXMENUS    */
#include "optable.h"   /* access_optable     */
#include "series.h"
#include "display1.h"  /* next 3 needed by dowith.h */
#include "bigrect.h"
#include "lterm.h"
#include "dowith.h"    /* destroy_ltermlist  */

static int max_cofi_index(term u);
static void restore_pending( void  *lastop, PDOCDATA pDocData, int currentline);
/*________________________________________________________________________*/
int undo(PDOCDATA pDocData)
/* Reset everything in the document to the condition it was in one line ago, given
the document data (pointer).  Return 1 for success, 0 when
all lines have been undone so you can't undo another.
As of 7.6.13,  this function is no longer responsible for invaliding the display;
that must be done after undo is called, at the place calling undo. 
   Specifically we have to reset:
history
assumptions
new variables introduced at the last step by the prover
   (e.g. when we assume cos(x) != 0 a new existential variable is introduced)
undo any let_defns made at the previous line
undo any 'init_parameters' that were done at the previous line
undo the inhibitions (or releases) on any operators made at the last step
undo any changes to global variables (either in the DLL's or mathpert.exe)
reset the old value of selected_equation
and call UpdateOperationsMenus to make sure the right menus are available

The document heap is reset to empty
after each line, and is used only for one-line-duration memory
requirements of the operators.  Permspace is used for memory
of document duration.  Therefore if we reset 'nextperm' we will
take care of the memory used for history[currentline], definitions,
etc.  It is not necessary to destroy any terms.

When Undo is pressed, the document heap should be empty anyway,
because after failed operations, reset_heap is called, EXCEPT
in case there are selected terms on the screen.  In that case
pPapyrus->selected has to be set to NULL and reset_heap called.

This is called to undo the current line; but it is also called
without a valid current line (when automode finishes, it
increments the current line and calls undo to reset things.)  To
ensure that this doesn't cause trouble, we must make sure that
pDocData->history[currentline] is reset to functor and arity 0
after undoing the line.
*/
{ Papyrus *pPapyrus;
  coord papyrus_window_height;
  term t,q;
  unsigned short f;
  int i,k,n,cofi_flag;
  assumption *pending;
  operation *opseq;
  int currentline = get_currentline();  /* the line being undone */
  int problemtype;
  actualop lastop;  /* compiled code of last operator applied */
  pDocData->DocControlData.finishedflag = 0;  /* if we were finished, after undo we aren't */
  if(currentline == 0)
     { destroy_ltermlist(pDocData->papyrus->selected);
        // remove the selected term if there is one
       pDocData->papyrus->selected = NULL;
       pDocData->papyrus->error_buffer[0][0] = '\0';
       pDocData->papyrus->comment_buffer[0][0] = '\0';
       // and remove the final remark if there is one
       pDocData->papyrus->finalremark[0] = '\0';
       return 0;   /* nothing else happens, you can't undo line 0. */
     }
  assert(currentline > 0);
  /* this can't be called before the problem has been entered, when
  currentline is negative, because the Undo button isn't available. */
  problemtype = get_problemtype();
  pending = pDocData->DocControlData.pending;
  opseq = pDocData->DocControlData.opseq;
  if(pending != NULL && pending->line == currentline-1)
     { assert(currentline > 0);
       poppending(&t);
     }
  k = opseq[currentline].choice;
  set_eigenvariable(pDocData->DocControlData.linedatahistory[currentline-1].eigenindex);
  if(k > 0)
    { lastop = access_optable(opseq[currentline].men)[opseq[currentline].choice-1];
      opseq[currentline].choice = 0;
      /* otherwise, if we undo, then go forwards again, then when we hit
         Finished, currentline is artificially incremented and the OLD opseq
         from the first undo is still in place, so we can go into the body
         of the next 'if' and get a GPF accessing history[currentline],
         which at that point is undefined. */
    }
  else
    { lastop = (actualop) NULL;
    }
   /* if lastop changed any global variables not handled below by
      unpack_flags, change them back */
  undo_inhibitions();
  undo_assumptions();
  undo_letdefns();   /* also gets rid of variables introduced by the prover
                        or by operations at the current line.  */
  undo_parameters(currentline);
  if(lastop == completethesquare)
     set_polyvalfactorflag(0);
  if(lastop == findcommondenom)
     { aflag arithflag = get_arithflag();
       arithflag.fract = 1;  /* set to zero by findcommondenom */
       set_arithflag(arithflag);
     }
  if(problemtype==INDUCTION)
     undo_inductionvars();
  q = pDocData->DocProverData.history[currentline];
  if(FUNCTOR(q))
     cofi_flag = contains(q,CONSTANTOFINTEGRATION);
  else
     cofi_flag = 0;
  SETFUNCTOR(pDocData->DocProverData.history[currentline],0,0);
    /* see remarks before the function */
  --currentline;
  set_currentline(currentline);
  unpack_flags(currentline);  /*  restore correct values of global variables */
  pDocData->DocProverData.nextworkspace = pDocData->DocProverData.permhistory[currentline];
    /* 'freeing' permanent memory back to the point used at currentline */
  restore_pending((void  *) lastop, pDocData,currentline);
    /* restore_pending calls permalloc so it must come AFTER
       resetting permhistory. */
  t = pDocData->DocProverData.history[currentline];
  f = FUNCTOR(t);
  if(lastop == comparisontest1 || lastop == comparisontest2)
     { assert(FUNCTOR(t) == SUM);
       bindvar(ARG(2,t));
     }
  else if(lastop == finishcomparisontest1 || lastop == finishcomparisontest2)
     { assert(FUNCTOR(q) == SUM);
       unbindvar(ARG(2,q));
     }
  if(cofi_flag)
    /* reset constant_of_integration_index so that we don't get
       c1, c2, c3,... etc. when we repeatedly undo and then integrate */
     { assert(currentline >= 0);
       /* currentline has already been decremented, so it might be zero */
       set_cofi_index(1+max_cofi_index(t));
     }
  if(f==AND || f==OR)   /* maybe we have to reset selected_equation */
     { n = (int) ARITY(t);
       for(i=0;i<n;i++)
          { if(SELECTED(ARG(i,t))) /* bit set by selecteqn */
               { set_selected_equation(-i-1);
                 break;
               }
          }
       if(i==n)
          set_selected_equation(0);
     }
  if(pDocData->DocControlData.autosteps > 0)
     { --pDocData->DocControlData.autosteps;
      // --pDocData->DocControlData.totalautosteps;
      // you don't get to undo the count of total steps taken in auto mode
     }
     /* User is taking back a step taken in automode, so
        decrement the count of successive steps taken in automode. */

  /* cause the solution window to be repainted; but only the
     part below the current line has to be repainted, unless
     there are scroll bars already */
  /* Since hwnd is the document window, GetWindowLongPtr(hwnd,8) is the
     solution window. */
  pPapyrus = pDocData->papyrus;

  /* Now we need to adjust the papyrus data structure.  The
  papyrus has gotten shorter.  */
  pPapyrus ->lines[currentline+1].comment.y = 0;
  pPapyrus->height = (coord)( pPapyrus->lines[currentline+1].formula.x-16);
  papyrus_window_height = (coord)(pPapyrus->bottom-pPapyrus->top);
  if(pPapyrus->height >= papyrus_window_height)
     { pPapyrus->bottom =(unsigned short)(pPapyrus->height + pPapyrus->bottommargin);
       pPapyrus->top = (coord)(pPapyrus->height - papyrus_window_height + pPapyrus->bottommargin);
     
     }
  else
     { pPapyrus->top = 0;
       pPapyrus->bottom = papyrus_window_height;
       /* Make sure scroll bars are off */
      
     }
  pPapyrus->finalremark[0] ='\0';
  pPapyrus->error_buffer[0][0] = '\0';
  pPapyrus->comment_buffer[0][0] = '\0';
  pPapyrus->hint[0] ='\0';
  if(pPapyrus->selected)
     { pPapyrus->selected = NULL;
       reset_heap(NULL);
     }
#ifdef _WIN32
  UpdateOperationsMenus(pDocData);  /* so correct menus will be available */
#endif 
  return 1;
}
/*______________________________________________________________________*/
static int max_cofi_index(term u)
/* return the maximum index of all constants of integration in u.
If there is none, return 0 */
{ unsigned short i,n;
  int ans = 0;
  int temp;
  if(ATOMIC(u))
     return 0;
  if(FUNCTOR(u) == CONSTANTOFINTEGRATION)
     { assert(ISINTEGER(ARG(0,u)));
       return (int) INTDATA(ARG(0,u));
     }
  n = ARITY(u);
  for(i=0;i<n;i++)
     { temp = max_cofi_index(ARG(i,u));
       if(temp > ans)
          ans = temp;
     }
  return ans;
}

/*___________________________________________________________________*/
static void restore_pending( void  *lastop, PDOCDATA pDocData, int currentline)
/* if lastop is an operation that calls poppending, this
function must examine the history list and find what the pending
item must have been, and call pushpending to restore it.
*/
{ int i;
  term *history;
  term x;
  actualop original;
  if(lastop == (void  *) showcallingproblem)
     { /* in integration by substitition, we must restore 'pending'.
          It will be the previous integral, which we must now fish out
          of 'history'.
       */
       history = pDocData->DocProverData.history;
       for(i=currentline-1; i>=0;i--)
          { if(contains(history[i],INTEGRAL))
                break;
          }
       assert(i>=0);  /* you can't have successfully used showcallingproblem
                         unless there was a preceding integral. */
       pushpending(history[i],i);
       return;
     }
  if(lastop == (void  *) showcallingcubic)
     { /* in solving a cubic we are going back to the lines where the
          discrimant was calculated.   We must restore 'pending'.
          It will be the previous cubic equation, which we must now fish out
          of 'history'.
       */
       history = pDocData->DocProverData.history;
       x = get_eigenvariable();
       for(i=currentline-1; i>=0;i--)
          { if(contains(history[i],FUNCTOR(x)))
                break;
          }
       assert(i>=0);  /* you can't have successfully used showcallingcubic
                         unless there was a preceding equation. */
       pushpending(history[i],i);
       return;
     }
  if(pDocData -> problemtype == TESTCONVERGENCE)
     { if(lastop == (void  *) finishdivergencetest)
          original = divergencetest;
       else if(lastop == (void  *) finishintegraltest)
          original = integraltest;
       else if(lastop == (void  *) finishratiotest)
          original = ratiotest;
       else if(lastop == (void  *) finishroottest)
          original = roottest;
       else if(lastop == (void  *) finishcomparisontest1)
          original = comparisontest1;
       else if(lastop == (void  *) finishcomparisontest2)
          original = comparisontest2;
       else if(lastop == (void  *) finishlimitcomparisontest)
          original = limitcomparisontest;
       else if(lastop == (void  *) finishcondensationtest)
          original = condensationtest;
       else if(lastop == (void  *) statefinalbound1)
          original = finishcomparisontest1;
       else if(lastop == (void  *) statefinalbound2)
          original = finishcomparisontest2;
       else
          return;
       /* look back through opseq for the original convergence test */
       history = pDocData->DocProverData.history;
       for(i=currentline;i>0;i--)
          { if(access_optable(pDocData->DocControlData.opseq[i].men)[pDocData->DocControlData.opseq[i].choice-1] == original)
               break;
          }
       if(i==0)
          assert(0);  /* must find the original operator */
       --i;
       pushpending(history[i],i);
       return;
     }
}

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