#define IMPL 1
/*
   Curves and Types management
*/

#define MPS 1 /* multi-point curve switchs are supported */

#include "common.h"
#include "datalib.h"
#include "function.h"
#include "diagram.h"
#include "curve.h"
#include "visual.h"
#include "point.h"
#include "help.h"
#include "param.h"
#include "large.h"
#include "userfunc.h"
#define KERNEL
#include "window.h"	/* to #define NOUPDATE only */
#undef KERNEL

extern Global(CharPtr PNTR) CurveTxt;	/* defined in text.c */

enum {		/* see setup.c, init[], /curve */
  ARCH_W,		/* Archive filter */
  IPOINT_W,		/* Inital point */
  PAUSE_W,		/* Pause mode */
  SELCURV_C,
  REDRAW_C,
  STA_C,
  SUS_C,
  LOAD_C,		/* loading the generator */
  SELINIT_C,		/* selecting initial point */
  FILTER_C,		/* Waiting for filter changing */
  PAUSEOPT_C,		/* Waiting for pause mode setting */
  EXPORTING_C,
  IMPORTING_C,
  EXPORT_C,
  CUR_T,
  SUSPEND_B,
  RESUME_B,
  ABORT_B,
  TAKE_B,
  OPTARCHMU_P,		/* Maximum number of untitled curves */
  OPTARCHGF_T,		/* Path filter */
  OPTARCHMF_T,		/* Trace filter */
  OPTARCHCF_T,		/* Coordinates filter */
  OPTARCHFR_P,		/* From */
  OPTARCHTO_P,		/* To */
  OPTARCHST_P,		/* Step */
  PAUSE_T,
  PAUSES_B,
  PAUSEE_B,
  PAUSEN_B,
  PAUSEKEY_T,
  MOUSE_B,
  LIST,			/* 38 20 ! listwidth listheight */
  REDRAW_M,		/* Redraw */
  REDRAWALL_I,		/* All curves */
  REDRAWHI_I,		/* Highlighted */
  REDRAWCL_I,		/* Clear */
  SEPARATOR_I,
  EXPORT_T,		/* Export to file */
  EXPORTOF_B,		/* File list */
  EXPORTPT_T,		/* Points */
  EXPORTPTS_B,		/* Export special points only */
  EXPORTCO_T,		/* Columns */
  EXPORTCON_B,		/* Output title */
  EXPORTFO_P,		/* Format */
  EXPORTSN_T,		/* Selected names */
  LISTN,		/* (6,12) ! lines linelen */
  EXPORTAN_T,		/* Add name */
  EXPORTDN_T,		/* Delete name */
  EXPORTPT_I,		/* <Point type> */
  EXPORTFO_B,		/* overwrite */
  EXPORTFA_B		/* append */
} CurveTxtIndex;

Local(void) FreeCurveResources(DataLibPtr dl, FilePtr fp);
Local(void) DelFromUntLst(DataLibPtr dl, FilePtr fp);

Local(void) RestoreFilter(Boolean takefromcurve);
Local(void) SaveFilter(Boolean free);
Local(CharPtr) FilterPart(void);
Local(void) ReadFilter(DataLibPtr Diagram);
Local(void) SkipFilter(void);
Local(void) WriteFilter(Boolean free);
#if DEB_CT
  Local(void) PrintFilter(CharPtr title);
#endif

Local(void) FillStagenPar(StagenDataPtr sgp, Boolean udf);

Local(void) ReadUdfTable(void);
Local(void) WriteUdfTable(void);
Local(void) FreeUdfTable(void);

Local(LisT) list;

Local(void) DiscardFuncPars(Int2 IndexFrom, Int2 IndexTo);
Local(void) ProcFuncPars(Int2 index, CharPtr b);

Local(void) PrepareToDelete(DataLibPtr dl) {
  FreeCurveResources(dl,dl->CurDirPtr);
  DelFromUntLst(dl,dl->CurDirPtr);
  if (DataLibDown(dl)==0) {
    DataLibDeletePartitions(dl,VA_PART,SP_PART,LP_PART,BD_PART,IC_PART,NULL);
    DataLibUp(dl);
  }
  /* Is the selected curve deleted? */
  if (dl->SelectedDirPtr==dl->CurDirPtr) {
    if (dl==&DiagramLib) DeactivateCurve(FALSE);
    dl->SelectedDirPtr=0;
    DataLibSetSelected(dl);
  }
}

/* Deletes curve pointed by dl->CurDirPtr */
/* it may be dl!=&DiagramLib */
Global(void) DeleteCurve(DataLibPtr dl) {
  PrepareToDelete(dl);
  DataLibDelete(dl);
}

/**************************/
/* Curves type management */
/**************************/

#define TMP	"tmp"	/* names of temporary section and keys */

/* Curve types graph */
typedef struct {	/* vertex description */
  VoidPtr SuccPtr;
  CharPtr DescFile;	/* File with starter-generator descriptor */
  CharPtr HelpInfo;
} Vertex, PNTR VertexPtr;		

typedef struct {	/* node description */
  CharPtr Label;	/* short name */
  CharPtr Title;	/* Full name of init points */
  CharPtr TitleOnCurve;	/* Full name of points on curve*/
  Int2 Type;		/* unique type code */
  Int2 SuccNum;		/* num of successors */
  Int2 CompClass;	/* see &compclass section in class .con file */
  Vertex Successors[1];	/* array with SuccNum elements of Vertex type */
} Node, PNTR NodePtr;

/* Archives filter structures */
typedef struct {	/* filter for points */
  /* Store points: fFrom+fStep*(n-1)<=fTo, n=1,2,3,... */
  /* 0 is for G_points, 1 is for M-points */
  Int2 fFrom[2],fTo[2],fStep[2];
} ArchFilter;


/* Default curve types */
typedef struct {
  NodePtr curveType;
  NodePtr pointType;
  NodePtr newType;
} DefType, PNTR DefTypePtr;

Local(DefTypePtr) DefTypes=NULL;
Local(Int2) DefTypesNum=0;

/*=====================================================*/
/* A set of non-local static variables with file scope */
typedef struct _Locals {
  NodePtr InitPointType;	/* Type of initial point */
  NodePtr CurveType;		/* Type of curve to be computed starting from IP */
  CharPtr DescFile;		/* points to descriptor of loaded stagen */
  CharPtr OldDescFile;		/* prev stagen */
  LibHandle hStarter;
  LibHandle hGenerator;
  StagenPtr pStarter;
  StagenPtr pGenerator;
  LibHandle hDecoder;
  DecoderPtr pDecoder;
  CharPtr HelpInfo;
  PairPtr PNTR coordfilter;	/* Archives: coordinate filter */
  Int2Ptr  specfilter;		/* Archives: special points: dim of class; <0 if Gdim>1 */
  ArchFilter filter;		/* Archives: path and trace filter */
  BoolPtr ClassDimG;		/* for each class: TRUE if G-dim of the class > 1 */
  Uint2 UdfMask;		/* mask of udf appended to defining function */
  Uint4Ptr UdfTable;		/* User Defined funcs unique numbers */
  Int2 UdfTableNum;		/*   the size of the table */
  Int2 NumOfRelevantClasses;
  Int2 locUserFuncIndex;	/* local index of user def funcs class */
  Int2 locUserFuncDim;		/* dim of class of user def funcs class */
  Boolean DimGMore1;		/* TRUE if dim(G-point)>1 */
  Int1 WhoRuns;			/* 1 - starter, 2 - generator */
  Boolean call;			/* was stagen loaded? */
#if IMPL
  Int2 ImplInternalReload;	/* Reload due to choosing of the implementation by the user; 1 - starter, 2 - generator */
#endif	/* IMPL */
	/* +2 is for slave sta/gen */
  Int2 ImplCode[2+2];		/* Implementation Codes for starter and generator */
  Int2 ImplMax[2+2];		/* Max number of implementations (taken from &methods section) */
  CharPtr PNTR ImplNames[2+2];	/* Names of implementations */
  CharPtr ImplHelp[2+2];	/* Help ids */
  struct _Locals PNTR Slave;	/* To 'slave' if &slaveXXX partition is present in desc file */
  StagenData StagenPar;		/* Parameters passed to Starter-Generator */
} Locals, PNTR LocalsPtr;

#if IMPL
#else	/* IMPL */
Local(Int2) ImplInternalReload=0;	/* Reload due to choosing of the implementation by the user; 1 - starter, 2 - generator */
#endif	/* IMPL */

/* l is always used; s is used to save l's copy (see RedrawCurve) */
Local(Locals) l={
  NULL,			/* InitPointType */
  NULL,			/* CurveType */
  NULL,			/* DescFile */
  NULL,			/* OldDescFile */
  NULL,			/* hStarter */
  NULL,			/* hGenerator */
  NULL,			/* pStarter */
  NULL,			/* pGenerator */
  NULL,			/* hDecoder */
  NULL,			/* pDecoder */
  NULL,			/* HelpInfo */
  NULL,			/* coordfilter */
  NULL,			/* specfilter */
  {{1,1},{INT2_MAX,INT2_MAX},{1,1}},	/* filter */
  NULL,			/* ClassDimG */
  0,			/* UdfMask */
  NULL,			/* UdfTable */
  0,			/* UdfTableNum */
  0,			/* NumOfRelevantClasses */
  -1,			/* locUserFuncIndex */
  0,			/* locUserFuncClass */
  FALSE,		/* DimGMore1 */
  0,			/* WhoRuns */
  FALSE,		/* call */
#if IMPL
  0,			/* ImplInternalReload */
#endif	/* IMPL */
  {0,0,0,0},		/* ImplCode */
  {0,0,0,0},		/* ImplMax */
  {NULL,NULL,NULL,NULL},/* ImplNames */
  {NULL,NULL,NULL,NULL},/* ImplHelp */
  NULL,			/* Slave */
  {NULL}		/* StagenPar */
};

Local(Locals) s;

Local(Int2) Point_Curve;	/* separates types of
				   init points and curves
				   in menu */

Local(void) UnloadGen(Boolean full);
Local(Int2) LoadGen(Boolean Full);
Local(Int2) LoadGenLvl=0;	/* >0 when Load/Unload slave sta/gen */
Local(Int2) UnloadLoadGen(void);
Local(void) HideGen(void);
Local(void) RestoreGen(void);
Local(void) SwapGen(Char oper);


/*----------------------*/
/* Select Current Curve */

/* Delete routine (DataLibShow) */
Local(Int2) cDelete(DataLibPtr dlDiag, DataLibNotify post) {
  PrepareToDelete(dlDiag);
  /* Notify DataLibShow that custom deletion has been made */
  /* DataLibShow will delete partition by itself */
  if (post) post(dlDiag,0);
  /* Clear all windows to force user to redraw.
     Redraw updates SpecialPoints list in graphics windows.
     There is no other way of notifing them about curve deletion. */
  ClearAllWindows(0);
  return 0;
}


/* Rename routine (DataLibShow) */
Local(Int2) cRename(DataLibPtr dlDiag, DataLibNotify post) {
  /* in fact we know that dlDiag==&DiagramLib */
  DelFromUntLst(dlDiag,dlDiag->CurDirPtr);
  if (post) post(dlDiag,0);
  return 0;
}

/*===============================*/
/* Export routines (DataLibShow) */

#define DEFFORM	"%#12.6g"

typedef struct {
  CharPtr name;
  Int2 classn;
  Uint2 realId;
  Int2 varn;
} OneName, PNTR OneNamePtr;

typedef struct {
  DataLibNotify Post;		/* pointer to DataLibShow's Post routine */
  DataLibPtr DataLib;		/* DataLib  */
  WindoW parent;
  TexT file;			/* output file name */
  GrouP overapp;		/* overwrite/append */
  GrouP btns;			/* to avoid nested calls to callbacks */
  ButtoN points;		/* which points to export: all(FALSE)|special(TRUE) */
  GrouP path;
  TexT pathFrom,pathTo,pathStep;
  TexT traceFrom,traceTo,traceStep;
  ButtoN outnames;		/* output column names */
  Boolean boutnames;
  TexT format;			/* output format */
  CharPtr form;
  int width;			/* of values */
  LisT selected;		/* list of selected names */
  OneNamePtr names;		/* describes selected names */
  Int2 namesdim;		/* ==DIM(*names) */
  Int2 curselected;		/* in selected */
  LisT add;			/* list of names to add */
  Int2 addoff;
  ButtoN del;			/* del cur name fro selected */
  Int2 level;			/* add names list level (0/1) */
  Boolean bpoints;
  Int2Ptr classN;		/* level==0: local num of classes */
  Uint2Ptr classId;		/* level==0: realIds */
  Int2 curclass;		/* level==1: index to classN */
  Int2Ptr varN;			/* level==1: num of vars */
  Int2 off;
  Int2 pf[3],tf[3];		/* path and trace filters */
} ExportWork, PNTR ExportWorkPtr;

Local(void) cExportTerm(ButtoN b, Int2 res) {
  WindoW w;
  ExportWorkPtr wp;
  Int2 i;
  w=ParentWindow(b);
  wp=GetWindowExtra(w);
  /* Restore (see cExport()) */
  CurDiagram=FALSE;
  WriteFilter(FALSE);
  FreeUdfTable();
  CurDiagram=TRUE;
  UnloadGen(FALSE);
  SwapGen('s');
  _MemFree(wp->classN);
  _MemFree(wp->classId);
  _MemFree(wp->varN);
  _MemFree(wp->form);
  for (i=0; i<wp->namesdim; i++) _MemFree(wp->names[i].name);
  _MemFree(wp->names);
  if (wp->Post) wp->Post(wp->DataLib,res);
  PopContext();
  Select(wp->parent);
  _MemFree(wp);
  Remove(w);
}

Local(void) cExportText(ExportWorkPtr wp, FILE PNTR file) {
  int i,j;
  int gptn,mptn;
  Pointtype pointtype;
  CharPtr Pt;
  PairPtr pp;
  Pair sp;
  Char opn[20];	/* ordinary point name */
  Boolean special,skipG,skipM;
  sprintf(ParBuf,"%s '%s'...",CurveTxt[EXPORTING_C],wp->DataLib->DirName+1);
  PushContext(NULL,NULL,ParBuf);
  
  ClassSaveIndirect();
  for (i=1; i<=l.NumOfRelevantClasses; i++)
    l.StagenPar.IndirectValues[i]=(FloatHiPtr)_MemNew(ARRAYSIZE(FloatHi,l.specfilter[i-1]));
  if (wp->boutnames) {
    for (i=0; i<wp->namesdim; i++)
      fprintf(file," %*s",wp->width,wp->names[i].name);
    fprintf(file,"\n");
  }
  gptn=1;	/* number of G-point */

  StrCpy(opn,GetParam(SFS_CURVES,"EXPORTOP"));
  sp.from=0;
  while (DataLibRead(wp->DataLib,(CharPtr)&pointtype,sizeof(pointtype))==sizeof(pointtype)) {
    special=pointtype && pointtype!=l.StagenPar.ProcFuncNum;
    if (pointtype) {
      DataLibSkipVRecord(wp->DataLib);	/* Message */
      DataLibSkipVRecord(wp->DataLib);	/* Bifurcation data */
    }
    if (l.DimGMore1)
      DataLibRead(&DiagramLib,(CharPtr)&ccd.curveDimG,sizeof(ccd.curveDimG));
    else ccd.curveDimG=1;
    if (wp->bpoints) skipG=!special;
    else skipG=!(wp->pf[0]<=gptn && gptn<=wp->pf[1] && (gptn-wp->pf[0])%wp->pf[2]==0);
    /* Loop through M-points */
    for (mptn=1; mptn<=ccd.curveDimG; mptn++) {
      /* Read M-point according to the curve's filter (ignore it for special points) */
      for (i=0; i<l.NumOfRelevantClasses; i++) {
	if (l.ClassDimG[i]==FALSE && mptn>1) continue;
	pp=pointtype ? (sp.num=-l.specfilter[i],&sp) : l.coordfilter[i];
	j=0;
	if (pp)
	  if (l.StagenPar.IndirectValues[i+1]) {
	    do {
	      DataLibRead(&DiagramLib,(CharPtr)(l.StagenPar.IndirectValues[i+1]+pp[j].from),
			  ARRAYSIZE(FloatHi,ABS(pp[j].num)));
	    } while (pp[j++].num>0);
	  } else
	    do {
	      DataLibSkip(&DiagramLib,ARRAYSIZE(FloatHi,ABS(pp[j].num)));
	    } while (pp[j++].num>0);
      }
      if (skipG) continue;
      if (ccd.curveDimG>1) {
	skipM=!(wp->tf[0]<=mptn && mptn<=wp->tf[1] && (mptn-wp->tf[0])%wp->tf[2]==0);
	if (skipM) continue;
      }
      for (i=0; i<wp->namesdim; i++) {
	if (wp->names[i].classn<0) {	/* point type */
	  if (special) Pt=GetSPname(pointtype,FALSE);
	  else Pt=opn;
	  fprintf(file,"%*s",(int)(StrLen(wp->names[i].name)+1),Pt);
	} else {
	  fprintf(file,wp->form,l.StagenPar.IndirectValues[wp->names[i].classn+1][wp->names[i].varn]);
	}
      }
      fprintf(file,"\n");
    }
    gptn++;
  }

  for (i=1; i<=l.NumOfRelevantClasses; i++)
    _MemFree(l.StagenPar.IndirectValues[i]);
  ClassRestoreIndirect();

  PopContext();
}

Local(void) cExportOk(ButtoN b) {
  FILE PNTR file;
  WindoW w;
  ExportWorkPtr wp;
  int i,n,prec,pos;
  Int2 overapp;
  Boolean err;
  Char c;
  w=ParentWindow(b);
  wp=GetWindowExtra(w);
  Disable(wp->btns);
  if (wp->namesdim==0) {
    myWarning("EC_NOPOINT");
    Enable(wp->btns);
    return;
  }
  /* Get settings */
  if (!wp->bpoints) {
    GetTitle(wp->pathFrom,ParBuf,PAR_BUF);
    if (sscanf(ParBuf,"%i",&n)!=1 || n<=0) n=1;
    wp->pf[0]=(Int2)n;
    GetTitle(wp->pathTo,ParBuf,PAR_BUF);
    if (sscanf(ParBuf,"%i",&n)!=1) n=32000;
    wp->pf[1]=(Int2)n;
    GetTitle(wp->pathStep,ParBuf,PAR_BUF);
    if (sscanf(ParBuf,"%i",&n)!=1 || n<=0) n=1;
    wp->pf[2]=(Int2)n;
  }
  if (IsDimGMore1()) {
    GetTitle(wp->traceFrom,ParBuf,PAR_BUF);
    if (sscanf(ParBuf,"%i",&n)!=1 || n<=0) n=1;
    wp->tf[0]=(Int2)n;
    GetTitle(wp->traceTo,ParBuf,PAR_BUF);
    if (sscanf(ParBuf,"%i",&n)!=1) n=32000;
    wp->tf[1]=(Int2)n;
    GetTitle(wp->traceStep,ParBuf,PAR_BUF);
    if (sscanf(ParBuf,"%i",&n)!=1 || n<=0) n=1;
    wp->tf[2]=(Int2)n;
  }
  wp->boutnames=GetStatus(wp->outnames);
  GetTitle(wp->format,ParBuf,PAR_BUF);
 format:;
  _MemFree(wp->form);
  wp->form=_MemNew(StrLen(ParBuf)+2);
  wp->form[0]=' ';
  StrCpy(wp->form+1,ParBuf);
  err=FALSE;
  i=1;
  if (sscanf(wp->form+i," %c%n",&c,&pos)!=1 || c!='%') err=TRUE;
  else {
    i+=pos;
    for (; StrChr("-+ #0",wp->form[i]); i++);
    sscanf(DEFFORM,"%*[^0-9]%i.%i",&wp->width,&prec);
    pos=0; sscanf(wp->form+i,"%i%n",&wp->width,&pos); i+=pos;
    pos=0; sscanf(wp->form+i,".%i%n",&prec,&pos); i+=pos;
    if (!StrChr("feEgG",wp->form[i])) err=TRUE;
  }
  if (err) {
    StrCpy(ParBuf,DEFFORM);
    goto format;
  }
  GetTitle(wp->file,ParBuf,PAR_BUF);
  StrTrim(ParBuf);
  overapp=GetValue(wp->overapp);
  /* Save settings */
  DataLibSavePos(wp->DataLib);
  while (!DataLibUp(wp->DataLib));
  DataLibDeletePartitions(wp->DataLib,EC_PART,NULL);
  if (DataLibCreate(wp->DataLib,EC_PART)==0) {
    DataLibWriteVRecord(wp->DataLib,NULL,ParBuf,StrLen(ParBuf)+1);
    DataLibWrite(wp->DataLib,(CharPtr)&overapp,sizeof(overapp));
    DataLibWrite(wp->DataLib,(CharPtr)&wp->bpoints,sizeof(wp->bpoints));
    DataLibWrite(wp->DataLib,(CharPtr)wp->pf,sizeof(wp->pf));
    DataLibWrite(wp->DataLib,(CharPtr)wp->tf,sizeof(wp->tf));
    DataLibWrite(wp->DataLib,(CharPtr)&wp->boutnames,sizeof(wp->boutnames));
    DataLibWriteVRecord(wp->DataLib,NULL,wp->form+1,StrLen(wp->form+1)+1);
    DataLibWrite(wp->DataLib,(CharPtr)&wp->namesdim,sizeof(wp->namesdim));
    for (i=0; i<wp->namesdim; i++) {
      DataLibWriteVRecord(wp->DataLib,NULL,wp->names[i].name,StrLen(wp->names[i].name)+1);
      DataLibWrite(wp->DataLib,(CharPtr)&wp->names[i].classn,sizeof(wp->names[0].classn));
      DataLibWrite(wp->DataLib,(CharPtr)&wp->names[i].realId,sizeof(wp->names[0].realId));
      DataLibWrite(wp->DataLib,(CharPtr)&wp->names[i].varn,sizeof(wp->names[0].varn));
    }
  }
  DataLibRestorePos(wp->DataLib);
  /* Open file */
  file=fopen(ParBuf,overapp==1 ? "wt" : "at");
  if (!file) {
    myWarning("_Open",ParBuf);
    Enable(wp->btns);
    return;
  }
  /* Export curve */
  cExportText(wp,file);
  /* That's all */
  fclose(file);
  cExportTerm(b,0);
}

Local(void) cExportCancel(ButtoN b) {
  cExportTerm(b,1);
}

#if _WIN
#pragma argsused
#endif
Local(void) cExportHelp(ButtoN b) {
  Help(NULL);
}

Local(void) cExportOutFile(ButtoN b) {
  WindoW w;
  Char def[PAR_BUF];
  ExportWorkPtr wp;
  w=ParentWindow(b);
  wp=GetWindowExtra(w);
  GetTitle(wp->file,def,PAR_BUF);
  *ParBuf='\0';
  if (myGetOutputFileName(ParBuf,PAR_BUF,def)) {
    SetTitle(wp->file,ParBuf);
  }
  Select(w);
}

#if _WIN
#pragma argsused
#endif
Local(void) AddClassNameCB(LisT list_wp, CharPtr title, CharPtr name,
			  Boolean defvis, Uint2 realId) {
  ExportWorkPtr wp=(ExportWorkPtr)GetObjectExtra(list_wp);
  Int2 i,n;
  for (i=0; i<l.NumOfRelevantClasses; i++)
    if (l.StagenPar.ClassReal[i+1]==realId) {
      if (wp->bpoints || (l.coordfilter[i] && l.coordfilter[i]->num)) {
	ListItem(wp->add,title);
	n=CountItems(wp->add)-2;
	wp->classN[n]=i;
	wp->classId[n]=realId;
      }
      break;
    }
}

#if _WIN
#pragma argsused
#endif
Local(void) AddVarNameCB(LisT list_wp, CharPtr name, Int2 dim) {
  ExportWorkPtr wp=(ExportWorkPtr)GetObjectExtra(list_wp);
  PairPtr pp;
  int i,j,k,ll;
  Int2 n,in;
  in=CountItems(wp->add)-1;
  if (wp->bpoints) {
    if (dim==1) {
      ListItem(wp->add,name);
      wp->varN[in]=wp->off++;
    } else
      for (i=0; i<dim; i++) {
	sprintf(ParBuf,"%s[%i]",name,i);
	ListItem(wp->add,ParBuf);
	wp->varN[in++]=wp->off++;
      } 
  } else {
    n=wp->classN[wp->curclass];
    pp=l.coordfilter[n];
    i=0;
    do {
      j=MAX(pp[i].from,wp->off);
      k=MIN(pp[i].from+ABS(pp[i].num),wp->off+dim)-1;
      if (j<=k) {
	if (dim==1) {
	  ListItem(wp->add,name);
	  wp->varN[in]=wp->off;
	} else
	  for (ll=j; ll<=k; ll++) {
	    sprintf(ParBuf,"%s[%i]",name,ll);
	    ListItem(wp->add,ParBuf);
	    wp->varN[in++]=wp->off+ll;
	  }
      }
    } while (pp[i++].num>0);
    wp->off+=dim;
  }
}

Local(void) CheckNames(ExportWorkPtr wp);

Local(void) ShowRelevantNames(ExportWorkPtr wp) {
  Hide(wp->add);
  Reset(wp->add);
  SetObjectExtra(wp->add,wp,NULL);
  if (wp->level) {
    _MemFree(wp->varN);
    ListItem(wp->add,"..");
    wp->varN=_MemNew(ARRAYSIZE(Uint2,l.specfilter[wp->classN[wp->curclass]]));
    wp->off=0;
    EnumVariables(wp->add,GetNthRelevantClass(wp->classN[wp->curclass]),AddVarNameCB);
  } else {
    _MemFree(wp->classN);
    _MemFree(wp->classId);
    ListItem(wp->add,CurveTxt[EXPORTPT_I]);
    wp->classN=_MemNew(ARRAYSIZE(Int2,l.NumOfRelevantClasses));
    wp->classId=_MemNew(ARRAYSIZE(Uint2,l.NumOfRelevantClasses));
    EnumClasses(wp->add,AddClassNameCB);
  }
  Show(wp->add);
}

Local(void) ShowSelectedNames(ExportWorkPtr wp) {
  Int2 i;
  Hide(wp->selected);
  Reset(wp->selected);
  for (i=0; i<wp->namesdim; i++)
    ListItem(wp->selected,wp->names[i].name);
  SetValue(wp->selected,wp->curselected);
  Show(wp->selected);
}

Local(void) PointsTypeProc(ButtoN points) {
  ExportWorkPtr wp;
  wp=GetWindowExtra(ParentWindow(points));
  wp->bpoints=GetStatus(points);
  if (wp->bpoints) {	/* special points only */
    Hide(wp->path);
  } else {			/* all points */
    Show(wp->path);
    wp->level=0;
    CheckNames(wp);
    ShowSelectedNames(wp);
  }
  ShowRelevantNames(wp);
}

Local(void) DelName(ExportWorkPtr wp) {
  Int2 i;
  _MemFree(wp->names[wp->curselected-1].name);
  if (wp->namesdim==1) {
    Disable(wp->del);
    wp->namesdim=wp->curselected=0;
    wp->names=_MemFree(wp->names);
  } else {
    for (i=wp->curselected-1; i<wp->namesdim; i++)
      wp->names[i]=wp->names[i+1];
    wp->namesdim--;
    wp->names=_MemMore(wp->names,ARRAYSIZE(OneName,wp->namesdim));
    if (wp->curselected>wp->namesdim) wp->curselected=wp->namesdim;
  }
}

Local(void) CheckNames(ExportWorkPtr wp) {
  PairPtr pp;
  Int2 i,j,li;
  for (i=0; i<wp->namesdim; i++) {
    if (wp->names[i].classn<0) continue;	/* <Point type> */
    if (IsClassRelevant(wp->names[i].realId)<=0) {
     del:;
      wp->curselected=i+1;
      DelName(wp);
      i--;
      continue;
    }
    li=ClassGlobToLoc(wp->names[i].realId)-1;
    wp->names[i].classn=li;
    if (wp->bpoints) continue;
    pp=l.coordfilter[li];
    if (pp) {
      j=0;
      do {
	if (pp[j].from<=wp->names[i].varn &&
	    wp->names[i].varn<=pp[j].from+ABS(pp[j].num)) {
	  j=-1;
	  break;
	}
      } while (pp[j++].num<=0);
      if (j>=0) goto del;
    } else goto del;
  }
  wp->curselected=wp->namesdim;
}

Local(void) DelNameProc(ButtoN bn) {
  ExportWorkPtr wp;
  wp=GetWindowExtra(ParentWindow(bn));
  if (wp->curselected>0) {
    DelName(wp);
    ShowSelectedNames(wp);
  } else MsgBeep();
}

Local(void) AddNameProc(LisT lt) {
  ExportWorkPtr wp;
  OneName on;
  Int2 i,n;
  wp=GetWindowExtra(ParentWindow(lt));
  n=GetValue(lt);
  if (wp->level) {
    if (n==1) {
      wp->level=0;
      ShowRelevantNames(wp);
      SetOffset(wp->add,0,wp->addoff);
    } else {
      GetListItem(wp->add,n,ParBuf,PAR_BUF);
      on.name=_StringSave(ParBuf);
      on.classn=wp->classN[wp->curclass];
      on.realId=wp->classId[wp->curclass];
      on.varn=wp->varN[n-2];
     add:;
      if (wp->namesdim++) {
	wp->names=_MemMore(wp->names,ARRAYSIZE(OneName,wp->namesdim));
	for (i=wp->namesdim-2; i>=wp->curselected; i--)
	  wp->names[i+1]=wp->names[i];
	wp->names[wp->curselected]=on;
      } else {
	wp->names=_MemNew(ARRAYSIZE(OneName,1));
	wp->names[0]=on;
      }
      wp->curselected=++wp->curselected;
      ShowSelectedNames(wp);
      Enable(wp->del);
    }
  } else {
    if (n==1) {
      on.name=_StringSave(CurveTxt[EXPORTPT_I]);
      on.classn=on.varn=on.realId=-1;
      goto add;
    } else {
      GetOffset(wp->add,NULL,&wp->addoff);
      wp->curclass=n-2;
      wp->level=1;
      ShowRelevantNames(wp);
    }
  }
}

Local(void) SelectedProc(LisT lt) {
  ExportWorkPtr wp;
  wp=GetWindowExtra(ParentWindow(lt));
  wp->curselected=GetValue(lt);
}

Local(GrouP) myNormalGroup(GrouP prnt, Int2 width, Int2 height, CharPtr title) {
  GrouP g;
  g=NormalGroup(prnt,width,height,title,NULL,NULL);
  SetGroupMargins(g,sysCharWidth,sysLineHeight2);
  SetGroupSpacing(g,sysCharWidth,sysLineHeight2);
  return g;
}

Local(GrouP) myHiddenGroup(GrouP prnt, Int2 width, Int2 height, Boolean inner) {
  GrouP g;
  g=HiddenGroup(prnt,width,height,NULL);
  SetGroupMargins(g,0,0);
  SetGroupSpacing(g,inner ? 2 : sysCharWidth,sysLineHeight2);
  return g;
}

Local(Int2) cExport(DataLibPtr dlDiag, DataLibNotify post) {
  WindoW wE;
  GrouP gM,g,gf,gp,gpp,gppp,gw,gww,gc,gl;
  ExportWorkPtr wp;
  CharPtr p;
  int i,ll,ln;
  CharPtr descfile;
  Int2 overapp;
  wp=_MemNew(sizeof(ExportWork));
  wp->Post=post;
  wp->DataLib=dlDiag;
  wp->parent=CurrentWindow();
  PushContext(HLP_EXPORTCRV,NULL,CurveTxt[EXPORT_C]);
  /* Restore previous settings */
  DataLibSavePos(dlDiag);
  while (!DataLibUp(dlDiag));
  if (DataLibFind(dlDiag,EC_PART)==0) {
    /* for now skip file name */
    _MemFree(DataLibReadVRecord(dlDiag,NULL));
    DataLibRead(dlDiag,(CharPtr)&overapp,sizeof(overapp));
    DataLibRead(dlDiag,(CharPtr)&wp->bpoints,sizeof(wp->bpoints));
    DataLibRead(dlDiag,(CharPtr)wp->pf,sizeof(wp->pf));
    DataLibRead(dlDiag,(CharPtr)wp->tf,sizeof(wp->tf));
    DataLibRead(dlDiag,(CharPtr)&wp->boutnames,sizeof(wp->boutnames));
    wp->form=DataLibReadVRecord(dlDiag,NULL);
    DataLibRead(dlDiag,(CharPtr)&wp->namesdim,sizeof(wp->namesdim));
    wp->names=(OneNamePtr)_MemNew(ARRAYSIZE(OneName,wp->namesdim));
    for (i=0; i<wp->namesdim; i++) {
      wp->names[i].name=DataLibReadVRecord(dlDiag,NULL);
      DataLibRead(dlDiag,(CharPtr)&wp->names[i].classn,sizeof(wp->names[0].classn));
      DataLibRead(dlDiag,(CharPtr)&wp->names[i].realId,sizeof(wp->names[0].realId));
      DataLibRead(dlDiag,(CharPtr)&wp->names[i].varn,sizeof(wp->names[0].varn));
    }
  } else {
    overapp=1;
    wp->pf[0]=wp->pf[2]=1; wp->pf[1]=32000;
    wp->tf[0]=wp->tf[2]=1; wp->tf[1]=32000;
    wp->form=_StringSave(DEFFORM);
  }
  DataLibRestorePos(dlDiag);
  /* Get data from the curve and seek to the points */
  SwapGen('l');
  descfile=FindAndOpenDescFile(dlDiag,SECPRF"call%s");	/* this skips types */
  for (i=0; i<2; i++)		/* skip starter & generator parameters */
    SkipParameters(dlDiag);
  DescClose();
  l.DescFile=descfile;
  l.call=!LoadGen(FALSE);
  /* read Archives filter */
  l.coordfilter=_MemNew(ARRAYSIZE(PairPtr,l.NumOfRelevantClasses));
  l.specfilter=_MemNew(ARRAYSIZE(Int2,l.NumOfRelevantClasses));
  ReadFilter(dlDiag);
  ReadUdfTable();	/* for GetSPname */
  /* Now create dialog box */
  wE=FixedWindow(-50,-50,-sysCharWidth,-sysLineHeight,dlDiag->DirName,NULL);
  gM=InitLargeWindow(wE);
  SetWindowExtra(wE,wp,NULL);
  g=myHiddenGroup(gM,0,5,FALSE);
  /* File group */
  gf=myNormalGroup(g,2,0,CurveTxt[EXPORT_T]);
  StrCpy(ParBuf,dlDiag->DirName+1);
  p=StrChr(ParBuf,' ');
  if (p) *p='\0';
  GetParamAppend(SFS_EXTENSIONS,"EC");
  wp->file=DialogText(gf,ParBuf,22,NULL);
  PushButton(gf,CurveTxt[EXPORTOF_B],cExportOutFile);
  wp->overapp=myHiddenGroup(gf,2,0,FALSE);
  RadioButton(wp->overapp,CurveTxt[EXPORTFO_B]);
  RadioButton(wp->overapp,CurveTxt[EXPORTFA_B]);
  SetValue(wp->overapp,overapp);
  /* Points group */
  gp=myNormalGroup(g,0,3,CurveTxt[EXPORTPT_T]);
  wp->points=CheckBox(gp,CurveTxt[EXPORTPTS_B],PointsTypeProc);
  SetStatus(wp->points,wp->bpoints);
  gpp=myHiddenGroup(gp,0,2,FALSE);
  wp->path=myNormalGroup(gpp,3,0,CurveTxt[OPTARCHGF_T]);
  gw=myHiddenGroup(wp->path,2,0,TRUE);
  StaticPrompt(gw,CurveTxt[OPTARCHFR_P],0,dialogTextHeight,NULL,'r');
  sprintf(ParBuf,"%i",(int)wp->pf[0]);
  wp->pathFrom=DialogText(gw,ParBuf,4,NULL);
  gw=myHiddenGroup(wp->path,2,0,TRUE);
  StaticPrompt(gw,CurveTxt[OPTARCHTO_P],0,dialogTextHeight,NULL,'r');
  sprintf(ParBuf,"%i",(int)wp->pf[1]);
  wp->pathTo=DialogText(gw,ParBuf,4,NULL);
  gw=myHiddenGroup(wp->path,2,0,TRUE);
  StaticPrompt(gw,CurveTxt[OPTARCHST_P],0,dialogTextHeight,NULL,'r');
  sprintf(ParBuf,"%i",(int)wp->pf[2]);
  wp->pathStep=DialogText(gw,ParBuf,4,NULL);
  if (IsDimGMore1()) {
    gppp=myNormalGroup(gpp,3,0,CurveTxt[OPTARCHMF_T]);
    gw=myHiddenGroup(gppp,2,0,TRUE);
    StaticPrompt(gw,CurveTxt[OPTARCHFR_P],0,dialogTextHeight,NULL,'r');
    sprintf(ParBuf,"%i",(int)wp->tf[0]);
    wp->traceFrom=DialogText(gw,ParBuf,4,NULL);
    gw=myHiddenGroup(gppp,2,0,TRUE);
    StaticPrompt(gw,CurveTxt[OPTARCHTO_P],0,dialogTextHeight,NULL,'r');
    sprintf(ParBuf,"%i",(int)wp->tf[1]);
    wp->traceTo=DialogText(gw,ParBuf,4,NULL);
    gw=myHiddenGroup(gppp,2,0,TRUE);
    StaticPrompt(gw,CurveTxt[OPTARCHST_P],0,dialogTextHeight,NULL,'r');
    sprintf(ParBuf,"%i",(int)wp->tf[2]);
    wp->traceStep=DialogText(gw,ParBuf,4,NULL);
  }
  /* Columns group */
  gc=myNormalGroup(g,0,2,CurveTxt[EXPORTCO_T]);
  gw=myHiddenGroup(gc,2,0,FALSE);
  wp->outnames=CheckBox(gw,CurveTxt[EXPORTCON_B],NULL);
  SetStatus(wp->outnames,wp->boutnames);
  gww=myHiddenGroup(gw,2,0,TRUE);
  StaticPrompt(gww,CurveTxt[EXPORTFO_P],0,dialogTextHeight,NULL,'r');
  wp->format=DialogText(gww,wp->form,6,NULL);
  AlignObjects(ALIGN_VERTICAL,wp->outnames,gww,NULL);
  gl=myHiddenGroup(gc,2,0,FALSE);
  gw=myNormalGroup(gl,1,0,CurveTxt[EXPORTSN_T]);
  sscanf(CurveTxt[LISTN],"(%i,%i)",&ln,&ll);
  wp->selected=SingleList(gw,ll,ln,SelectedProc);
  gww=myHiddenGroup(gl,0,2,FALSE);
  gw=myNormalGroup(gww,1,0,CurveTxt[EXPORTAN_T]);
  wp->add=SingleList(gw,ll,ln-2,AddNameProc);
  ShowRelevantNames(wp);
  CheckNames(wp);
  ShowSelectedNames(wp);
  wp->del=PushButton(gww,CurveTxt[EXPORTDN_T],DelNameProc);
  if (wp->namesdim==0) Disable(wp->del);
  wp->btns=TermButtons(gM,g,cExportOk,cExportCancel,cExportHelp);
  ShowLargeWindow(gM);
  SelectText(wp->file,0,0);
  return 0;
}

/* Notification routine called by DataLibShow when the user selects or cancels */
#if _WIN
#pragma argsused
#endif
Local(void) cNotify(DataLibPtr dlDiag, Int2 res) {
  switch (res) {
    case NOTIFY_CANCEL:		/* cancel */
      PopContext();		/* waiting selection */
      UpdateInfoInMainWindow(MWI_CURVE,dlDiag->DirName+1);	/* might be renamed */
      goto term;
    case NOTIFY_DESELECT:	/* deselect */
      DeactivateCurve(FALSE);
      PopContext();		/* waiting selection */
      break;
    case NOTIFY_SELECT:		/* select */
      ActivateCurve();
     term:
      UnlockAll();
  }
}

Local(Boolean) InitRedraw_Status(Int2 index);
Local(void) clearAllWindows(Int2 index);
Local(void) CurveRedraw(Int2 index);

Local(MenuItem) RedrawMenuItems[]={
  {REDRAW_M,	NULL,		NULL},
  {REDRAWALL_I,	CurveRedraw,	InitRedraw_Status},
  {REDRAWHI_I,	CurveRedraw,	InitRedraw_Status},
  {SEPARATOR_I,	NULL,		NULL},
  {REDRAWCL_I,	clearAllWindows,CreateWindow_Status}
};

Local(MenuDesc) RedrawMenu={RedrawMenuItems,DIM(RedrawMenuItems)};

Local(void) CurveRedraw(Int2 index) {
  if (RedrawMenuItems[index].Title==REDRAWALL_I) { /* redraw all */
    RedrawDiagram(0);
  } else {		/* redraw highlighted */
    RedrawCurveProc(0);
  }
}

Local(void) RedrawKeys(Char c) {
  if (c=='r' || c=='R') {
    if (DiagramLib.CurDirPtr) RedrawCurveProc(0);
  }
}

/* Called from the Main Menu */
#if _WIN
#pragma argsused
#endif
Global(void) SelectCurve(Int2 index) {
  LockAll();	/* lock second time because otherwise it would be unlocked
		   immediatedly after return */
  PushContext(HLP_CURVE,RedrawKeys,CurveTxt[SELCURV_C]);
  list=0;
  if (DataLibShow(&DiagramLib,CurveTxt[CUR_T],cNotify,"r-d-e-gmw",
		  cRename,cDelete,cExport,CurveTxt,&RedrawMenu,"W_CURVE")) {	/* failed */
    cNotify(&DiagramLib,NOTIFY_CANCEL);
  } else {
    list=DiagramLib.List;
    SetStatusOfItems(&RedrawMenu);
  }
}

/* Determines status of menu item */
#if _WIN
#pragma argsused
#endif
Global(Boolean) SelectCurve_Status(Int2 index) {
  return CurDiagram;		/* diagram is selected */
}



/***************************************************************/

/* Find descriptor file name for starter-generator and store pointer to it */
Local(void) FindName(void) {
  Int2 i;
  if (l.InitPointType && l.CurveType) {
    for (i=0; i<l.InitPointType->SuccNum; i++)
      if (l.InitPointType->Successors[i].SuccPtr==l.CurveType) {
	l.DescFile=l.InitPointType->Successors[i].DescFile;
	l.HelpInfo=l.InitPointType->Successors[i].HelpInfo;
	return;
      }
  }
  GetParam(SFS_KERNELERRORS,"CT_UNSUPP",l.InitPointType->Title,l.CurveType->TitleOnCurve);
  UpdateInfoInMainWindow(MWI_MESSAGE,ParBuf);
  Beep();
  l.DescFile=NULL;
}


Local(NodePtr) (PNTR CurveTypeIndex)[]=NULL;
Local(Int2) CurveTypeNum=0;
Global(MenuDesc) TypeMenuDesc={NULL,0};

/* Find the index of a Node with given Label */
Local(Int2) FindNodeByLabel(CharPtr label) {
  Int2 k;
  for (k=0; k<CurveTypeNum; k++)
    if (!StrCmp((*CurveTypeIndex)[k]->Label,label)) break;
  if (k==CurveTypeNum) {
    myWarning("CT_REF",label);
    k=0;
  }
  return k;
}

/* Find the index of a Node with given Type */
Local(NodePtr) FindNodeByType(Int2 type) {
  Int2 k;
  for (k=0; k<CurveTypeNum; k++)
    if ((*CurveTypeIndex)[k]->Type==type) break;
  if (k==CurveTypeNum) {
    myWarning("CT_TYPE",(int)type);
    k=0;
  }
  return (*CurveTypeIndex)[k];
}

/* Returns a title of special point */
Global(CharPtr) GetSPname(Pointtype localtype, Boolean Full) {
  NodePtr nd;
  if (localtype>0 && localtype<=l.StagenPar.ProcFuncNum) {
    nd=FindNodeByType(l.StagenPar.DetectedTypes[localtype]);
    return Full ? nd->Title : nd->Label;
  }
  if (localtype&USERPOINT) {
    return UserSPname(localtype&~USERPOINT,l.UdfTable,Full);
  }
  return "?";
}

/* Determines curve's type based on types of a special point
   and a curve it was find on. */
Local(NodePtr) DefaultType(NodePtr curve, NodePtr point) {
  Int2 i;
  for (i=0; i<DefTypesNum; i++) {
    if (DefTypes[i].curveType==curve && DefTypes[i].pointType==point) {
      return DefTypes[i].newType;
    }
  }
  return point->SuccNum ? point->Successors[0].SuccPtr : point;
}

Local(Boolean) OpenDescFile(CharPtr DescFile) {
  StrCpy(ParBuf,DescFile);
  GetParamAppend(SFS_EXTENSIONS,"DESC");
  return DescOpen(ParBuf);
}

Local(CharPtr) OpenDescFileAndFindSection(CharPtr descfile, CharPtr section) {
  Char sec[50];
  if (OpenDescFile(descfile)) {
    sprintf(sec,section,descfile+StrLen(descfile)+1);
    if (FindLine(sec)>=0) return descfile;
    DescClose();
  }
  return NULL;
}

/* It is supposed dgm is seeked to types of init point and curve */
Global(CharPtr) FindAndOpenDescFile(DataLibPtr dgm, CharPtr section) {
  CharPtr descfile;
  Int2 i,j,type[2];
  /* Read type of init and regular points */
  DataLibRead(dgm,(CharPtr)type,sizeof(type));
  /* Find appropriate descriptor */
  for (i=0; i<CurveTypeNum; i++)
    if ((*CurveTypeIndex)[i]->Type==type[0])
      for (j=0; j<(*CurveTypeIndex)[i]->SuccNum; j++)
	if (((NodePtr)((*CurveTypeIndex)[i]->Successors[j].SuccPtr))->Type==type[1]) {
	  descfile=(*CurveTypeIndex)[i]->Successors[j].DescFile;
	  return OpenDescFileAndFindSection(descfile,section);
	}
  return NULL;
}

Local(Boolean) AreStaGenSame(void) {
  CharPtr op,np;
  Boolean r=FALSE;
  if (StrCmp(l.OldDescFile,l.DescFile)==0) {
    op=l.OldDescFile+StrLen(l.OldDescFile)+1;
    np=l.DescFile+StrLen(l.DescFile)+1;
    r=StrCmp(op,np)==0;
  }
  return r;
}

/*------------------------------------------------------------*/
/* Callback, Action and Status functions for Curve Types Menu */

/* Invalidate input bifurcation data */
Global(void) InvalidateBifData(void) {
  if (l.StagenPar.BifDataInOk) {
    l.StagenPar.BifDataInOk=FALSE;
    l.StagenPar.BifDataInPtr=_MemFree(l.StagenPar.BifDataInPtr);
    l.StagenPar.BifDataInLen=0;
  }
}

Local(void) ImplAppendMethods(CharPtr buf) {
  Int2 i,o=2*LoadGenLvl;
  if (l.ImplMax[0+o]*l.ImplMax[1+o]) {
    sprintf(buf+StrLen(buf)," (%s,%s)",l.ImplNames[0+o][l.ImplCode[0+o]],l.ImplNames[1+o][l.ImplCode[1+o]]);
    return;
  }
  for (i=0+o; i<2+o; i++)
    if (l.ImplMax[i]) {
      sprintf(buf+StrLen(buf)," (%s)",l.ImplNames[i][l.ImplCode[i]]);
      break;
    }
}

Local(void) CurveTypeAction(Int2 index) {
  NodePtr pn;
  MWInfoKind info;
#ifdef DEBLHS
{{{{{
double x[4]={1,2,3,4};
double p[1]={2};
double f[4]={0,0,0,0};
double xp[4]={5,6,7,8};
double m[4][4];
double *pd;
typedef EntryPtr(double *,RhsDerPtr,(double *x, double *p, double *t));
typedef EntryPtr(double *,LhsDerPtr,(double *p));
int i,j,k;
MemFill(m,0,sizeof(m));
FillStagenPar(&l.StagenPar,FALSE);
/* RHS */
l.StagenPar.Rhs(x,p,NULL,f);	/* no time */
printf("Rhs:\n{%g,%g,%g,%g}\n",f[0],f[1],f[2],f[3]);
/* RHS' */
pd=((RhsDerPtr)(l.StagenPar.AuxFunc[0]))(x,p,NULL);	/* no time */
printf("Rhs':\n");
for (i=0; i<DIM(x); i++) {
  for (j=0; j<DIM(x)+DIM(p); j++) {
    printf("  (%i,%i):",i,j);
    printf(" %g",pd[i*(DIM(x)+DIM(p))+j]);
  }
  printf("\n");
}
/* LHS */
l.StagenPar.AuxFunc[5](p,m);
printf("Lhs:\n");
for (i=0; i<4; i++) {
  for (j=0; j<4; j++) printf(" %g",m[i][j]);
  printf("\n");
}
/* LHS' */
pd=((LhsDerPtr)(l.StagenPar.AuxFunc[6]))(p);
printf("Lhs':\n");
for (i=0; i<DIM(x); i++) {
  for (j=0; j<DIM(x); j++) {
    printf("  (%i,%i):",i,j);
    for (k=0; k<DIM(p); k++)
      printf(" %i=%g",k,pd[i*DIM(x)*DIM(p)+j*DIM(p)+k]);
  }
  printf("\n");
}
}}}}}
#endif /* DEBLHS */
  pn=(*CurveTypeIndex)[TypeMenuDesc.Menu[index].UserIndex];
  if (index<Point_Curve) {	/* set type of initial point */
    l.InitPointType=pn;
    info=MWI_INITTYPE;
    InvalidateBifData();
  } else {			/* set type of a curve */
    l.CurveType=pn;
    info=MWI_CURVETYPE;
  }
  if (l.InitPointType && l.CurveType) {
    /* No more selected curve */
    DeactivateCurve(FALSE);
    DiagramLib.SelectedDirPtr=0;
    DataLibSetSelected(&DiagramLib);
    FindName();		/* name of desc file of starter-generator */
    if (l.DescFile) {
      PushContext(0,NULL,CurveTxt[LOAD_C]);
      if (l.OldDescFile) {
	if (l.OldDescFile!=l.DescFile) {
	  l.call=!UnloadLoadGen();
	}
      } else l.call=!LoadGen(TRUE);
      PopContext();
      if (l.call==FALSE) {
	UpdateInfoInMainWindow(MWI_INITTYPE,"");
	UpdateInfoInMainWindow(MWI_CURVETYPE,"");
	l.InitPointType=l.CurveType=NULL;
      }
    } else {	/* There is no curve type that matches selected IP type */
      l.DescFile=l.OldDescFile;
      l.CurveType=NULL;
      UpdateInfoInMainWindow(MWI_INITTYPE,l.InitPointType->Title);
      UpdateInfoInMainWindow(MWI_CURVETYPE,"");
      InvalidateBifData();
      l.call=FALSE;
    }
    if (l.call) HelpSetVar(); else pn=NULL;
  } else l.call=FALSE;
  if (pn) {
    if (info==MWI_INITTYPE) StrCpy(ParBuf,pn->Title);
    else {
      StrCpy(ParBuf,pn->TitleOnCurve);
	ImplAppendMethods(ParBuf);
    }
    UpdateInfoInMainWindow(info,ParBuf);
  }
}

Local(Boolean) CurveTypeStatus(Int2 index) {
  Int2 i;
  Int2 nodeindex;
  Boolean res;
  if (!FunctionsHandle) return FALSE;	/* functions are not selected */
  res=TRUE;
  if (index>Point_Curve)
    if (l.InitPointType) {
      nodeindex=TypeMenuDesc.Menu[index].UserIndex;
      if (nodeindex>=0) {
	res=FALSE;
	for (i=0; i<l.InitPointType->SuccNum; i++)
	 if (l.InitPointType->Successors[i].SuccPtr==
	     (*CurveTypeIndex)[nodeindex]
	    ) {res=TRUE; break;}
      }
    } else res=FALSE;
  return res;
}

Local(void) CurveTypeCallback(IteM it) {
  DoMenuAction(&TypeMenuDesc,it);
  SetStatusOfItems(&MainMenu);
}

/* Determines status of menu items enabled when both type are chosen */
#if _WIN
#pragma argsused
#endif
Global(Boolean) TypesSet_Status(Int2 index) {
  return l.call;
}

/* Returns unique code of the type of init point (0) or curve (1) */
Global(Int2) GetTypeId(Int2 n) {
  switch (n) {
    case 0:	/* init point */
      return l.InitPointType ? l.InitPointType->Type : 0;
    case 1:	/* curve */
      return l.CurveType ? l.CurveType->Type : 0;
  }
  return 0;
}

/*----------------------------------------------------------------*/
/* Read in a file with types description and build graph and menu */
/* It is assumed that two top level submenus are
   for init point and curve types */
Global(void) BuildTypeGraph(MenU mParent) {
  DescPtr fpGraph,fpMenu;
  Int2 i,j,k;
  NodePtr pNode;
  CharPtr cp;
  CharPtr PNTR texts;
  MenuItemPtr TypeMenuItems;
  MenuItemPtr pItem;
  int ls_p,le_p,ts_p,te_p,h_p;
  Int2 level;
  Char b[BL];
  MemFill(&l.StagenPar,0,sizeof(l.StagenPar));
  ParamChangeNotify=InvalidateBifData;
  ccd.Computing=FALSE;
  GetParam(SFS_FILES,"CLASSFILECUR");
  if (DescOpen(ParBuf)) {
    /* I. Graph */
    /* Seek to /graph */
    fpGraph=FindLine(SECPRF"graph");
    GetLine(b);
    /* First pass */
    for (CurveTypeNum=0,CurveTypeIndex=NULL; !DescEof() && atoi(b); CurveTypeNum++) {
      CurveTypeIndex=CurveTypeIndex ? _MemMore(CurveTypeIndex,
					       ARRAYSIZE(NodePtr,CurveTypeNum+1)) :
		    _MemNew(sizeof(NodePtr));
      (*CurveTypeIndex)[CurveTypeNum]=pNode=_MemNew(sizeof(Node)-sizeof(Vertex));
      pNode->Type=(Int2)atoi(b);
      sscanf(b,"%*i %n%*s%n %n",&ls_p,&le_p,&ts_p);
      b[le_p]='\0';
      pNode->Label=_StringSave(b+ls_p);
      cp=StrChr(b+ts_p,'|');
      if (cp) {
	*cp++='\0';
	pNode->TitleOnCurve=_StringSave(cp);
      } else
	pNode->TitleOnCurve=_StringSave(b+ts_p);
      pNode->Title=_StringSave(b+ts_p);
      for (pNode->SuccNum=0; GetLine(b) && StrStr(b,"->"); )
	pNode->SuccNum++;
      /*
	There should be -1 instead of -0 in the following statement.
	But in such a case the statement
		pNode->Successors[j].DescFile=StringSave(b+ts_p);
	(see below) causes Windows to hang after quitting the program
	(just run it and quit immediately). 
	The situation should be investigated.
      */
      (*CurveTypeIndex)[CurveTypeNum]=_MemMore(pNode,sizeof(Node)+
					ARRAYSIZE(Vertex,pNode->SuccNum-0));
    }
    /* Second pass */
    DescSeek(fpGraph);
    GetLine(b);
    for (i=0; !DescEof() && atoi(b); i++) {
      pNode=(*CurveTypeIndex)[i];
      for (j=0; GetLine(b) && StrStr(b,"->"); j++) {
	h_p=0;
	sscanf(b,"-> %n%*s%n %n%*s%n %n%*s",&ls_p,&le_p,&ts_p,&te_p,&h_p);
	b[le_p]='\0';
	pNode->Successors[j].SuccPtr=(*CurveTypeIndex)[FindNodeByLabel(b+ls_p)];
	if (h_p) b[te_p]='\0';
	k=StrLen(pNode->Label);
	cp=_MemNew((Int2)(te_p-ts_p+1+k+1+le_p-ls_p+1));
	pNode->Successors[j].DescFile=cp;
	StrCpy(cp,b+ts_p);
	StrCpy(cp+te_p-ts_p+1,pNode->Label);
	StrCpy(cp+te_p-ts_p+1+k+1,b+ls_p);
	pNode->Successors[j].HelpInfo=h_p ? _StringSave(b+h_p) : NULL;
      }
    }
    /* II. Computational classes */
    DescRewind();
    FindLine(SECPRF"compclass");
    k=CountLines();
    if (k!=CurveTypeNum) myWarning("DT_COMPCL");
    for (i=0; i<k; i++) {
      GetLine(b);
      sscanf(b,"%*s%n",&le_p);
      b[le_p]='\0';
      (*CurveTypeIndex)[FindNodeByLabel(b)]->CompClass=atoi(b+le_p+1);
    }
    /* III. Menu */
    DescRewind();
    /* Seek to /menu */
    fpMenu=FindLine(SECPRF"menu");
    GetLine(b);
    /* Pass one: count dim of MenuItem array */
    level=0;
    for (TypeMenuDesc.Num=0; !DescEof() && *b!=SECPRF[0]; TypeMenuDesc.Num++) {
      if (StrChr(b,'{') && !level) Point_Curve=TypeMenuDesc.Num;
      if (StrChr(b,'{')) level++;
      if (StrChr(b,'}')) level--;
      GetLine(b);
    }
    /* Allocate memory for MenuItem array and fill it in */
    DescSeek(fpMenu);
    TypeMenuItems=_MemNew(ARRAYSIZE(MenuItem,TypeMenuDesc.Num));
    texts=_MemNew(ARRAYSIZE(CharPtr,TypeMenuDesc.Num));
    for (i=0; i<TypeMenuDesc.Num; i++) {
      pItem=TypeMenuItems+i;
      GetLine(b);
      /* Translate Label to Title and set a TMPnn key in TMP section */
      pItem->Title=i;
      if (!StrPBrk(b,"{}[]") && StrCmp(b,"-")) {
	cp=StrChr(b,'|');
	if (cp) *cp++='\0';
	k=FindNodeByLabel(b);
	StrCpy(b,cp ? cp : (*CurveTypeIndex)[k]->Title);
	pItem->UserIndex=k;	/* menu -> graph index map */
      } else {
	pItem->UserIndex=-1;	/* submenu does not correspond to any graph node */
      }
      texts[i]=_StringSave(b);
      pItem->Action=CurveTypeAction;
      pItem->EnableDisable=CurveTypeStatus;
    }
    TypeMenuDesc.Menu=TypeMenuItems;
    /* Pass two: create Curve Types Menu */
    CreateMenu((WindoW)mParent,texts,&TypeMenuDesc,CurveTypeCallback);
    /* Clean up */
    for (i=0; i<TypeMenuDesc.Num; i++) {
      _MemFree(texts[i]);
    }
    _MemFree(texts);
    /* IV. Default curve types for 'select an inital point' action */
    if (FindLine(SECPRF"deftypes")>=0) {
      DefTypesNum=CountLines();
      DefTypes=_MemNew(ARRAYSIZE(DefType,DefTypesNum));
      for (i=0; i<DefTypesNum; i++) {
	GetLine(b);
	cp=StrChr(b,' ');
	if (!cp) {
	  myWarning("DT_STR",b);
	  continue;
	}
	*cp='\0';
	DefTypes[i].curveType=(*CurveTypeIndex)[FindNodeByLabel(b)];
	StrCpy(b,cp+1);
	StrTrim(b);
	cp=StrChr(b,' ');
	if (!cp) {
	  myWarning("DT_STR",b);
	  continue;
	}
	*cp='\0';
	DefTypes[i].pointType=(*CurveTypeIndex)[FindNodeByLabel(b)];
	StrCpy(b,cp+1);
	StrTrim(b);
	DefTypes[i].newType=(*CurveTypeIndex)[FindNodeByLabel(b)];
      }
    }
    /* V. Standard linea algebra package */
    /* Seek to /stdlinalg */
    if (FindLine(SECPRF"stdlinalg")>=0)
      ProcFuncPars(_STDLINALG_INDEX,b);
    /* VI. Utilities */
    /* Seek to /utilities */
    if (FindLine(SECPRF"utilities")>=0)
      ProcFuncPars(_UTILITIES_INDEX,b);
    /* VII. Functions which are part of system's specification */
    BuildAuxFunc((Boolean)(FindLine(SECPRF"functions")>=0));
    /* VIII. Max needed order of derivatives */
    MaxDerOrder=-1;
    if (FindLine(SECPRF"derivatives")>=0) {
      GetLine(b);
      sscanf(b,"%i",&MaxDerOrder);
    }
    if (MaxDerOrder<0) MaxDerOrder=DERMAX;
    /* IX. Visual classes (of visible names) */
    FindLine(SECPRF"visiblenames");
    ReadVisibleNames();
    /* X. Help file(s) */
    FindLine(SECPRF"help");
    ReadHelpFile();
    /* XI. Class-specific windows */
    FindLine(SECPRF"windows");
    BuildWindowsList(0);	/* 0 means 'not top-level list of wins */
    /* That's all */
    DescClose();
  } else {
    myWarning("CT_OPEN",ParBuf);
    return;
  }
  GetParam(SFS_FILES,"INITFILE");
  if (DescOpen(ParBuf)) {
    /* I. Markers */
    /* Seek to /markers */
    if (FindLine(SECPRF"markers")>=0)
      ReadMarkers(CountLines());
    /* II. PostScript fonts */
    if (FindLine(SECPRF"psfonts")>=0)
      ReadPsFonts(CountLines());
    /* That's all */
    DescClose();
  } else {
    myWarning("CT_OPEN",ParBuf);
    return;
  }
}

/* Destroy curve types Graph */

Global(void) DestroyTypeGraph(void) {
  NodePtr pNode;
  Int2 i,j;
  for (i=0; i<CurveTypeNum; i++) {
    pNode=(*CurveTypeIndex)[i];
    for (j=0; j<pNode->SuccNum; j++) {
      _MemFree(pNode->Successors[j].DescFile);
      _MemFree(pNode->Successors[j].HelpInfo);
    }
    _MemFree(pNode->Label);
    _MemFree(pNode->Title);
    _MemFree(pNode->TitleOnCurve);
    _MemFree(pNode);
  }
  CurveTypeIndex=_MemFree(CurveTypeIndex);
  TypeMenuDesc.Menu=_MemFree(TypeMenuDesc.Menu);
  l.InitPointType=l.CurveType=NULL;
  l.OldDescFile=NULL;
  DefTypes=_MemFree(DefTypes);
  DefTypesNum=0;
  DiscardFuncPars(NKFP,NKFP+2);
  FreeMarkers();
  FreePsFonts();
  FreeAuxFunc();
  FreeVisibleNames();
  FreeHelpFile(FALSE);	/* only class specific */
  DestroyWindowsList();	/* class specific */
  InvalidateBifData();
}

/* Enumerates all types of special point */
Global(void) EnumSpecialPoints(EnumSpecialPointsCallback cb) {
  Int2 k;
  for (k=0; k<CurveTypeNum; k++)
    cb((*CurveTypeIndex)[k]->Title,
       (*CurveTypeIndex)[k]->Label,
       (*CurveTypeIndex)[k]->Type);
}


Global(CharPtr) TypeHelpInfo(enum TypeHelp kind) {
  CharPtr p=HLP_NOTYPES;
  Int2 i,o=2*LoadGenLvl;
  if (l.call && l.HelpInfo) {
    StrCpy(ParBuf,l.HelpInfo);
    switch (kind) {
      case TH_GENERATOR:
	if (l.ImplMax[1+o]>0 && l.ImplHelp[1+o]) return l.ImplHelp[1+o];
	break;
      default:
	if (l.ImplMax[0+o]>0 && l.ImplHelp[0+o]) StrCpy(ParBuf,l.ImplHelp[0+o]);
	break;
    }
    p=StrTok(ParBuf," ,");
    for (i=0; i<kind; i++)
      p=StrTok(NULL," ,");
  }
  return p;
}

#if DEB_CT

#include "document.h"

#define OUT	"tmp.tmp"	/* name of output file */

  static void CloseProc(WindoW w) {
    Remove(w);
  }

  /* Show Curve Types Graph */
#if _WIN
#pragma argsused
#endif
  Global(void) Debug_CurveTypes(Int2 index) {
    Int2 i,j,k;
    FILE PNTR out;
    NodePtr pn;
    CharPtr ps;
    WindoW w;
    DoC d;
    w=FixedWindow(-50,-50,-5,-5,"Curve Types",CloseProc);
    d=DocumentPanel(w,screenRect.right-4*sysCharWidth,screenRect.bottom*3/4);
    out=fopen(OUT,"wt");
    for (i=0; i<CurveTypeNum; i++) {
      pn=(*CurveTypeIndex)[i];
      fprintf(out,"\n%4s %3i %s\n",
		  pn->Label,
		  (int)pn->Type,
		  pn->Title);
      for (j=0; j<pn->SuccNum; j++)
	fprintf(out,"    ->%3s %s %s\n",
		    ((NodePtr)(pn->Successors[j].SuccPtr))->Label,
		    pn->Successors[j].DescFile,pn->Successors[j].HelpInfo);
    }
    fprintf(out,"\n\n    ");
    for (i=0; i<CurveTypeNum; i++) {
      pn=(*CurveTypeIndex)[i];
      fprintf(out,"%4s",pn->Label);
    }
    fprintf(out,"\n");
    ps=_MemNew(CurveTypeNum*4+1);
    for (i=0; i<CurveTypeNum; i++) {
      pn=(*CurveTypeIndex)[i];
      memset(ps,'.',CurveTypeNum*4);
      ps[CurveTypeNum*4]='\0';
      for (j=0; j<pn->SuccNum; j++)
	for (k=0; k<CurveTypeNum; k++)
	  if ((*CurveTypeIndex)[k]->Type==((NodePtr)(pn->Successors[j].SuccPtr))->Type) {
	    StrNCpy(ps+k*4,"...+",4);
	    break;
	}
      fprintf(out,"%4s%s\n",pn->Label,ps);
    }
    _MemFree(ps);
    fclose(out);
    Show(w);
    DisplayFile(d,OUT,programFont);
  }

#endif	/* DEB_CT */


/************************/
/* Implementation codes */

/*
   An Implementation Code (IC) is a number which specifies
   particular implementation of the same mathematical
   object. ICs may select starters and generators.
   Example: method of integration is given by IC.
*/

/* Constructs the name of a partition with default IC */
Local(void) ImplDefPart(CharPtr DescFile, Int2 sg) {
  CharPtr CurveTypeLabel;
  int compclass;
  CurveTypeLabel=StrChr(StrChr(DescFile,0)+1,0)+1;
  switch (sg) {
    case 1:	/* starter */
      sprintf(ParBuf,"%s%s",ICS_PRE,CurveTypeLabel);
      break;
    case 2:	/* generator */
      compclass=(int)((*CurveTypeIndex)[FindNodeByLabel(CurveTypeLabel)]->CompClass);
      sprintf(ParBuf,"%s%i",ICG_PRE,compclass);
      break;
    }
}

/* Reads ICs from active curve or take the defaults */
Local(void) ImplReadCodes(void) {
  Int2 i,o=2*LoadGenLvl;
  l.ImplCode[0]=l.ImplCode[1]=0;
  l.ImplCode[2]=l.ImplCode[3]=0;
  if (CurDiagram) {
    DataLibSavePos(&DiagramLib);
    if (DiagramLib.SelectedDirPtr) {
      if (DataLibDown(&DiagramLib)) goto end;
      if (DataLibFind(&DiagramLib,IC_PART)) goto end;
      DataLibRead(&DiagramLib,(CharPtr)l.ImplCode,sizeof(l.ImplCode));
    } else {
      while (!DataLibUp(&DiagramLib));	/* goto to the level 0 */
      for (i=0; i<2; i++) {
	ImplDefPart(l.DescFile,i+1);
	if (DataLibFind(&DiagramLib,ParBuf)==0)
	  DataLibRead(&DiagramLib,(CharPtr)&l.ImplCode[i+o],sizeof(l.ImplCode[i+o]));
      }
    }
end:;
    DataLibRestorePos(&DiagramLib);
  }
}

/* Writes current ICs as defaults */
Local(void) ImplWriteCodes(void) {
  Int2 i,o=2*LoadGenLvl;
  if (l.ImplMax[0+o]+l.ImplMax[1+o]==0) return;
  if (CurDiagram) {
    DataLibSavePos(&DiagramLib);
    while (!DataLibUp(&DiagramLib));	/* goto to the level 0 */
    for (i=0; i<2; i++) {
      ImplDefPart(l.OldDescFile,i+1);
      if (DataLibFind(&DiagramLib,ParBuf)==0)
	DataLibDelete(&DiagramLib);
      if (DataLibCreate(&DiagramLib,ParBuf)==0)
	DataLibWrite(&DiagramLib,(CharPtr)&l.ImplCode[i+o],sizeof(l.ImplCode[i+o]));
    }
    DataLibRestorePos(&DiagramLib);
  }
}

/*********************/
/* Forward/Backward */
/*********************/


/* Current Curve Data */
Global(CurrentCurveData) ccd;

/* Parameters passed to Starter-Generator and related data */

Local(Int2) ProcessGPoint(Pointtype type, VoidPtr point, CharPtr msg);

Local(Int2) locGetParIndex(VoidPtr DataArea, Uint2 Offset);
Local(void) locUpdatePar(Int2 Index);

Local(void) StorageInitGCurve(void);
Local(void) StorageTermGCurve(Boolean forward);
/* StorageVAList and StorageSPList MUST be local */
Local(DataLibPtr) StorageVAList=NULL;	/* cur ptr to a curve's subdir with a list of visual attrs */
Local(DataLibPtr) StorageSPList=NULL;	/* cur ptr to a curve's subdir with a list of spec pts */

/* Create default filter callback */
#if _WIN
#pragma argsused
#endif
Local(void) DefFilter(LisT List, CharPtr ClassTitle, CharPtr ClassName,
		      Boolean defvis, Uint2 RealId) {
  PairPtr pp;
  Int2 dim,i;
  for (i=0; i<l.NumOfRelevantClasses; i++)
    if (l.StagenPar.ClassReal[i+1]==RealId) {
      dim=*GetClassDim(ClassName);
      if (defvis && dim) {
	pp=_MemNew(sizeof(Pair));
	pp->from=0;
	pp->num=-dim;	/* - means last pair */
      } else pp=NULL;
      l.coordfilter[i]=pp;
      l.specfilter[i]=dim;
      break;
    }
}

/*--------------*/
/* Aux routines */
typedef GlobalPtr(void,VoidFuncPtr,());
Local(LibHandle) PrevHandle;
Local(Int2) LibFunc(CharPtr line, LibHandle PNTR handle, VoidFuncPtr PNTR adr) {
  int s,e;
  sscanf(line,"%*[^(]%n(%*[^)]%n",&s,&e);
  line[s]=line[e]='\0';
  if (*line=='=') *handle=0;
  else {
    if (StrChr(line,DIRDELIMCHR)) {	/* full path */
      StrCpy(ParBuf,line);
      GetParamAppend(SFS_EXTENSIONS,"LIB");
    } else GetParam(SFS_LIBRARIES,"FORMAT",line);
    SetParam(SFS_LIBRARIES,"LIBNAME",ParBuf);
    PrevHandle=*handle=LibraryLock("LIBNAME");
  }
  *adr=LibraryFuncAddress(PrevHandle,line+s+1);
  return *adr ? 0 : 1;
}

Local(void) DiscardFuncPars(Int2 IndexFrom, Int2 IndexTo) {
  Int2 i,n;
  for (n=IndexFrom; n<IndexTo; n++) {
    if (l.StagenPar.FuncParamsHandle[n])
      for (i=0; i<l.StagenPar.FuncParamsNum[n]; i++)
	LibraryUnlock(l.StagenPar.FuncParamsHandle[n][i]);
    l.StagenPar.FuncParamsHandle[n]=_MemFree(l.StagenPar.FuncParamsHandle[n]);
    l.StagenPar.FuncParams[n]=_MemFree(l.StagenPar.FuncParams[n]);
    l.StagenPar.FuncParamsNum[n]=0;
  }
}

/*--------------------------------------------*/
/* Unload previously loaded starter-generator */

Local(void) ImplFreeNames(void) {
  Int2 i,j,o=2*LoadGenLvl;
  for (i=0+o; i<2+o; i++) {
    if (l.ImplNames[i])
      for (j=0; j<l.ImplMax[i]; j++)
	_MemFree(l.ImplNames[i][j]);
    l.ImplMax[i]=0;
    l.ImplNames[i]=_MemFree(l.ImplNames[i]);
  }
}

Local(void) UnloadGen(Boolean full) {
  CharPtr p;
  Int2 i,o=2*LoadGenLvl;
  if (l.OldDescFile || !full) {	/* LoadGen was called at least once */
    if (l.Slave) {
      LocalsPtr sl;
      sl=_MemNew(sizeof(l));
      *sl=l;
      l=*l.Slave;
      LoadGenLvl++;
      UnloadGen(full);
      LoadGenLvl--;
      l=*sl;
      _MemFree(sl);
      l.Slave=_MemFree(l.Slave);
    }
    /* Free all memory */
    l.StagenPar.DetectedTypes=_MemFree(l.StagenPar.DetectedTypes);
    l.hStarter=LibraryUnlock(l.hStarter);
    l.hGenerator=LibraryUnlock(l.hGenerator);
    DiscardFuncPars(0,NKFP);
    l.hDecoder=LibraryUnlock(l.hDecoder);
    if (l.StagenPar.IndirectValues) _MemFree(l.StagenPar.IndirectValues[0]);
    l.StagenPar.IndirectValues=_MemFree(l.StagenPar.IndirectValues);
    l.StagenPar.ClassDim=_MemFree(l.StagenPar.ClassDim);
    l.StagenPar.ClassReal=_MemFree(l.StagenPar.ClassReal);
    l.ClassDimG=_MemFree(l.ClassDimG);
#if IMPL
    DestroyDataArea(l.StagenPar.StaParDesc,1+o,l.ImplInternalReload>0);
    DestroyDataArea(l.StagenPar.GenParDesc,2+o,l.ImplInternalReload>0);
#else	/* IMPL */
    DestroyDataArea(l.StagenPar.StaParDesc,1+o,ImplInternalReload>0);
    DestroyDataArea(l.StagenPar.GenParDesc,2+o,ImplInternalReload>0);
#endif	/* IMPL */
    l.StagenPar.StaParDesc=NULL;
    l.StagenPar.GenParDesc=NULL;
    l.pStarter=l.pGenerator=NULL;
    l.StagenPar.TestSingMap=_MemFree(l.StagenPar.TestSingMap);
#if IMPL
    switch (l.ImplInternalReload) {
#else	/* IMPL */
    switch (ImplInternalReload) {
#endif	/* IMPL */
      case 0:	/* Routine load of starter & generator */
	if (full) ImplWriteCodes();
      case 1:
      case 2:
	ImplFreeNames();
	break;
    }
    for (i=0+o; i<2+o; i++) l.ImplHelp[i]=_MemFree(l.ImplHelp[i]);
    /* save archives filter */
    p=l.DescFile;
    if (l.OldDescFile) l.DescFile=l.OldDescFile;
    if (!LoadGenLvl) SaveFilter(TRUE);
    l.DescFile=p;
    if (full) {
      l.OldDescFile=NULL;
      if (!LoadGenLvl) FreeUdfTable();
    } else {
      _MemFree(l.StagenPar.StaPtr);
      _MemFree(l.StagenPar.GenPtr);
    }
    l.locUserFuncIndex=-1;
    l.call=FALSE;
  }
}

/* Process a section describing hidden functional parameters */
Local(void) ProcFuncPars(Int2 index, CharPtr b) {
  Int2 i,n;
  l.StagenPar.FuncParamsNum[index]=n=CountLines();
  if (b) {
    l.StagenPar.FuncParams[index]=_MemNew(n*sizeof(FuncParamPtr));
    l.StagenPar.FuncParamsHandle[index]=_MemNew(n*sizeof(LibHandle));
    for (i=0; i<n; i++) {
      GetLine(b);
      LibFunc(b,l.StagenPar.FuncParamsHandle[index]+i,
	    (VoidFuncPtr PNTR)(l.StagenPar.FuncParams[index]+i));
    }
  } /* else LoadGen(FALSE) is in progress */
}

Local(void) mProcFuncPars(Int2 index, CharPtr b, Int2 stagen) {
  Int2 i,n,o=2*LoadGenLvl;
  l.StagenPar.FuncParamsNum[index]=n=mCountLines(l.ImplCode[stagen]);
  if (b) {
    l.StagenPar.FuncParams[index]=_MemNew(n*sizeof(FuncParamPtr));
    l.StagenPar.FuncParamsHandle[index]=_MemNew(n*sizeof(LibHandle));
    for (i=0; i<n; i++) {
      mGetLine(b,l.ImplCode[stagen+o]);
      LibFunc(b,l.StagenPar.FuncParamsHandle[index]+i,
	    (VoidFuncPtr PNTR)(l.StagenPar.FuncParams[index]+i));
    }
  } /* else LoadGen(FALSE) is in progress */
}

/*------------------------*/
/* Load starter-generator */

Local(void) SetSlaveData(const LocalsPtr Master, LocalsPtr Slave) {
  Int2 i,o;
  FillStagenPar(&Slave->StagenPar,FALSE);	/* NO user functions for slave */
  Slave->StagenPar.StdLinAlg=Master->StagenPar.StdLinAlg;
  Slave->StagenPar.StdLinAlgNum=Master->StagenPar.StdLinAlgNum;
  Slave->StagenPar.Utilities=Master->StagenPar.Utilities;
  Slave->StagenPar.UtilitiesNum=Master->StagenPar.UtilitiesNum;
  Slave->StagenPar.pStarter=Slave->pStarter;
  Slave->StagenPar.pGenerator=Slave->pGenerator;
  Slave->StagenPar.pDecoder=Slave->pDecoder;
  o=2*LoadGenLvl;
  for (i=0+o; i<2+o; i++) {
    Master->ImplCode[i]=Slave->ImplCode[i];
    Master->ImplMax[i]=Slave->ImplMax[i];
  }
}

Local(Int2) LoadGen(Boolean Full) {
  CharPtr p,q;
  CharPtr slv1;
  int slv;
  Int2 ret=0,cnt;
  Int2 i,n,k,o=2*LoadGenLvl;
  Int2 testfuncnum=0,procnum=0;
  Uint1 code;
  Boolean Slave=FALSE;
  Char b[BL];
  Char call[20],data[20],help[20],slave[20];
  p=l.DescFile+StrLen(l.DescFile)+1;
  sprintf(call,"%s%s",SECPRF"call",p);
  sprintf(data,"%s%s",SECPRF"data",p);
  sprintf(help,"%s%s",SECPRF"help",p);
  sprintf(slave,"%s%n%s",SECPRF"slave",&slv,p);
  l.Slave=NULL;
  l.StagenPar.Slave=NULL;
  /* Selected sta-gen is now previous one */
  if (Full) l.OldDescFile=l.DescFile;
  if (OpenDescFile(l.DescFile)) {
#if IMPL
    if (l.ImplInternalReload==0) {
#else	/* IMPL */
    if (ImplInternalReload==0) {
#endif	/* IMPL */
      for (i=0+o; i<2+o; i++) {
	l.ImplMax[i]=0;
	l.ImplCode[i]=0;
      }
    }
    ParamSetICs(l.ImplCode,l.ImplMax,l.ImplNames);
    /* Read description file and process it's sections */
    while (!DescEof()) {
      GetLine(b);
      if (StrStr(b,SECPRF)!=b) continue;
      /*
	Lists of implemetation of statrers and generators
	  /methods
	     starter1_name   | starter2_name   | ...
	     generator1_name | generator2_name | ...
	 If there is the only implementation of starter or
	 generator its line should contain the '-' char.
	 IMPORTANT: this section, if any, must be the first in the file.
      */
      if (!StrCmp(b,SECPRF"methods")) {
	if (CountLines()!=2) {
	  myWarning("CT_INVAL",b);
	  return 1;
	}
#if IMPL
	switch (l.ImplInternalReload) {
#else	/* IMPL */
	switch (ImplInternalReload) {
#endif	/* IMPL */
	  case 0:	/* Routine load of starter & generator */
	    ImplReadCodes();
	  case 1:	/* Internal reload of starter */
	  case 2:	/* Internal reload of generator */
	    ImplFreeNames();
	    for (n=0+o; n<2+o; n++) {
	      GetLine(b);
	      if (*b=='-') l.ImplMax[n]=0;
	      else
		for (l.ImplMax[n]=1, p=b;
		     (p=StrChr(p,'|'),p);
		     l.ImplMax[n]++, p++);
	      l.ImplNames[n]=_MemNew(ARRAYSIZE(CharPtr,l.ImplMax[n]));
	      for (i=0, p=b; i<l.ImplMax[n]; i++) {
		q=StrChr(p,'|');
		if (q) *q='\0';
		StrTrim(p);
		l.ImplNames[n][i]=_StringSave(p);
		if (q) p=q+1;
	      }
	    }
	    ParamSetICs(l.ImplCode,l.ImplMax,l.ImplNames);
	    break;
	}
	continue;
      }
      /*
	 Help identifiers for methods.
	   /help
	   point1 curve1 starter1 | point2 curve2 starter2 | ...
	   generator1 | generator2 | ...
      */
      if (!StrCmp(b,help)) {
	if (CountLines()!=2) {
	  myWarning("CT_INVAL",b);
	  return 1;
	}
	for (n=0+o; n<2+o; n++) {
	  mGetLine(b,l.ImplCode[n]);
	  _MemFree(l.ImplHelp[n]);
	  if (*b=='-') l.ImplHelp[n]=NULL;
	  else l.ImplHelp[n]=_StringSave(b);
	}
	continue;
      }
      /*
	 List of types of special points detectable on a curve:
	   /types
	     CurveTypeLabel Map 
	     ...
	 NB: we assume that internal code of types starts from 1. 
	     Zero means regular point.
	 Map is a sequence of '0', '1', and '-' which
	 describes the combination of values of test functions
	 corresponding to the type. The length of the sequence
	 must be equal to the number of test functions.
	 For example:
		ZH 0 1 -
	 means that a point of type ZH is detected when the first
	 test function is zero and the second one is non-zero
	 (the third function is irrelevant).
      */
      if (!StrCmp(b,SECPRF"types")) {
	n=procnum=mCountLines(l.ImplCode[0+o]);
	l.StagenPar.DetectedTypes=_MemNew(ARRAYSIZE(Int2,n+1));
	for (i=1; i<=n; i++) {
	  mGetLine(b,l.ImplCode[0+o]);
	  if (i==1) {
	    /* allocate memory for TestSingMap */
	    p=StrChr(b,' ');
	    cnt=0;
	    if (p)
	      for (; *p; p++) if (*p!=' ') cnt++;
	    if (testfuncnum) {
	      if (testfuncnum!=cnt) myWarning("CT_TFN",l.DescFile);
	    } else testfuncnum=cnt;
	    l.StagenPar.TestSingMap=_MemNew(n*testfuncnum);
	  }
	  p=StrChr(b,' ');
	  if (p) {
	    *p++='\0';
	    for (cnt=0; *p; p++) {
	      if (*p==' ') continue;
	      if (cnt>=testfuncnum) {
		myWarning("CT_TFM",(int)i);
		break;
	      }
	      switch (*p) {
		case '0':
		  code=0;
		  goto code;
		case '1':
		  code=1;
		  goto code;
		case '-':
		  code=-1;
		 code:
		  *(l.StagenPar.TestSingMap+(i-1)*testfuncnum+cnt)=code;
		  cnt++;
		  break;	      	       
		default:
		  myWarning("CT_TFC",*p,(int)i);
	      }
	    }
	  }
	  if (cnt!=testfuncnum) myWarning("CT_TFM",(int)i);
	  k=FindNodeByLabel(b);
	  l.StagenPar.DetectedTypes[i]=(*CurveTypeIndex)[k]->Type;
	}
	continue;
      }
      /*
	 List of classes of visible names for current curve type:
	   /names
	     VisibleClassName 
	     ...
	 NB: we assume that internal number of the first class is 1.
	     Zero used for reference to names from irrelevant classes.
      */
      /* 
	LoadGenLvl>0: We bypass setting of IndirectValues[] in visual
	because:
	1) to preserve pointers and classes definitions for the Master sta/gen,
	2) Slave is not allowed to visualize anything except via
	   Master's ProcessPoint routine.
      */
      if (!StrCmp(b,SECPRF"names")) {
	l.NumOfRelevantClasses=n=mCountLines(l.ImplCode[0+o]);
	l.StagenPar.IndirectValues=_MemNew(ARRAYSIZE(FloatHiPtr,n+1));	/* +1 for irrelevant */
	l.StagenPar.ClassDim=_MemNew(ARRAYSIZE(Int2Ptr,n+1));
	l.StagenPar.ClassReal=_MemNew(ARRAYSIZE(Uint2,n+1));
	l.ClassDimG=_MemNew(ARRAYSIZE(Boolean,n));
	if (LoadGenLvl==0)
	  ClassTableReset();	/* initialize table of class names */
	l.StagenPar.ClassDim[0]=GetClassDim("\1");	/* to get &zero */
	l.DimGMore1=FALSE;
	for (i=1; i<=n; i++) {
	  mGetLine(b,l.ImplCode[0+o]);	/* b is trimmed by GetLine */
	  if (*b=='*') l.ClassDimG[i-1]=l.DimGMore1=TRUE;
	  if (LoadGenLvl==0)
	    ClassTableSetPtr(b,&l.StagenPar.IndirectValues[i],
			     &l.StagenPar.ClassReal[i]);
	  else ClassTableSetPtr(b,NULL,NULL);	/* only strip * and - from name */
	  l.StagenPar.ClassDim[i]=GetClassDim(b);
	  if (!StrCmp(b,VCL_UDF)) {
	    l.locUserFuncIndex=i;
	    l.locUserFuncDim=*l.StagenPar.ClassDim[i];
	  }
	}
	k=ClassTableMaxIrrelevantDim();
	l.StagenPar.IndirectValues[0]=_MemNew(ARRAYSIZE(FloatHi,k));
	if (LoadGenLvl==0)
	  ClassTableSetIrrelevant(&l.StagenPar.IndirectValues[0]);
	continue;
      }
      /* List of functional parameters - defining functions */
      /*   /deffuncs           */
      /*     Deflib(Deffunc)   */
      /*     ...               */
      if (!StrCmp(b,SECPRF"deffuncs")) {
	mProcFuncPars(_DEF_INDEX,Full ? b : NULL,0);
	continue;
      }
      /* List of functional parameters - test functions */
      /*   /testfuncs          */
      /*     Testlib(Testfunc) */
      /*     ...               */
      if (!StrCmp(b,SECPRF"testfuncs")) {
	mProcFuncPars(_TEST_INDEX,Full ? b : NULL,0);
	if (testfuncnum) {
	  if (testfuncnum!=l.StagenPar.TestFuncNum)
	    myWarning("CT_TFN",l.DescFile);
	} else {
	  testfuncnum=l.StagenPar.TestFuncNum;
	}
	continue;
      }
      /* List of functional parameters - adapters */
      /*   /adapters               */
      /*     Adaptlib(Adaptfunc)   */
      /*     ...                   */
      if (!StrCmp(b,SECPRF"adapters")) {
	mProcFuncPars(_ADAPT_INDEX,Full ? b : NULL,0);
	continue;
      }
      /* List of functional parameters - processing functions */
      /*   /procfuncs            */
      /*     Proclib(Procfunc)   */
      /*     ...                 */
      if (!StrCmp(b,SECPRF"procfuncs")) {
	mProcFuncPars(_PROC_INDEX,Full ? b : NULL,0);
	if (procnum!=l.StagenPar.ProcFuncNum)
	  myWarning("CT_PFN",l.DescFile);
	continue;
      }
      /* List of functional parameters - starter's functions */
      /*   /stafuncs           */
      /*     Stalib(Stafunc)   */
      /*     ...               */
      if (!StrCmp(b,SECPRF"stafuncs")) {
	mProcFuncPars(_STA_INDEX,Full ? b : NULL,0);
	continue;
      }
      /* List of functional parameters - generator's functions */
      /*   /genfuncs           */
      /*     Genlib(Genfunc)   */
      /*     ...               */
      if (!StrCmp(b,SECPRF"genfuncs")) {
	mProcFuncPars(_GEN_INDEX,Full ? b : NULL,1);
	continue;
      }

      /* Translation function: */
      /*   /trans               */
      /*     Translib(Decoder)  */
      if (!StrCmp(b,SECPRF"trans")) {
	if (mCountLines(l.ImplCode[0+o])!=1) {
	  myWarning("CT_INVAL",b);
	  return 1;
	}
	for (i=0; i<1; i++) {
	  mGetLine(b,l.ImplCode[0+o]);
	  if (Full && LibFunc(b,&l.hDecoder,(VoidFuncPtr PNTR)(&l.pDecoder)))
	    return 1;
	}
	continue;
      }

      /* Libraries and functions for starter and generator: */
      /*   /call       */
      /*     Starter_Lib(Starter_Func) */
      /*     Generator_Lib(Generator_Func) */
      if (!StrCmp(b,call)) {
	if (CountLines()!=2) {
	  myWarning("CT_INVAL",b);
	  return 1;
	}
	mGetLine(b,l.ImplCode[0+o]);
	if (Full && LibFunc(b,&l.hStarter,(VoidFuncPtr PNTR)(&l.pStarter))) return 1;
	mGetLine(b,l.ImplCode[1+o]);
	if (Full && LibFunc(b,&l.hGenerator,(VoidFuncPtr PNTR)(&l.pGenerator))) return 1;
	continue;
      }

      /*
	  Structure of starter's and generator's data
	  /data
	    starter_typdef_filename
	    generator_typdef_filename
      */
      if (!StrCmp(b,data)) {
	if (CountLines()!=2) {
	  myWarning("CT_INVAL",b);
	  return 1;
	}
	mGetLine(b,l.ImplCode[0+o]);	/* starter's */
	if (LoadGenLvl) StrCat(b," _slv"+(StrChr(b,' ')?1:0));	/* append 'slave' suffix */
	if (Full) {
	  if (LoadGenLvl && DiagramLib.SelectedDirPtr) {
	    DataLibDown(&DiagramLib);
	    DataLibFind(&DiagramLib,SLVPAR_PART);
	  }
	  l.StagenPar.StaParDesc=CreateDataArea(b,1+o,
				&l.StagenPar.StaPtr,
#if IMPL
				l.ImplInternalReload>0);
#else	/* IMPL */
				ImplInternalReload>0);
#endif	/* IMPL */
	  if (!l.StagenPar.StaParDesc) ret=3;
	} else l.StagenPar.StaPtr=_StringSave(b);
	mGetLine(b,l.ImplCode[1+o]);	/* generator's */
	if (LoadGenLvl) StrCat(b," _slv"+(StrChr(b,' ')?1:0));	/* append 'slave' suffix */
	if (Full) {
	  l.StagenPar.GenParDesc=CreateDataArea(b,2+o,
				&l.StagenPar.GenPtr,
#if IMPL
				l.ImplInternalReload>0);
#else	/* IMPL */
				ImplInternalReload>0);
#endif	/* IMPL */
	  if (!l.StagenPar.GenParDesc) ret=3;
	  if (LoadGenLvl && DiagramLib.SelectedDirPtr) {
	    DataLibUp(&DiagramLib);
	  }
	} else l.StagenPar.GenPtr=_StringSave(b);
	if (Full)
	  ParamFuncPtrs(FALSE);	/* after all the windows have been created! */
	continue;
      }
      
      /*
	  'Slave' sta/gen are used to get points for curves of the given type
	  /slave
	    CTL			! short name of 'slave' curve type
      */
      if (!StrCmp(b,slave)) {
	if (mCountLines(l.ImplCode[0+o])!=1) {
	  myWarning("CT_INVAL",b);
	  return 1;
	}
	Slave=TRUE;
	slv1=_StringSave(mGetLine(b,l.ImplCode[0+o]));	/* line 1: type of curve */
	continue;
      }

    }
    DescClose();
    if (Full && !LoadGenLvl) {
      /* restore the archives filters */
      RestoreFilter(TRUE);	/* take it from active curve if possible */
      /* restore UdfTable */
      ReadUdfTable();		/* take it from active curve if possible */
    }
    if (Slave) {
      LocalsPtr sl;
      sl=_MemNew(sizeof(l));
      *sl=l;
      MemFill(&l,0,sizeof(l));
      l.InitPointType=FindNodeByType((*CurveTypeIndex)[FindNodeByLabel(slave+slv)]->Type);
      l.CurveType=FindNodeByType((*CurveTypeIndex)[FindNodeByLabel(slv1)]->Type);
      FindName();
      if (l.DescFile) {
	LocalsPtr slave_l;
	LoadGenLvl++;
	ClassSaveIndirect();
	LoadGen(Full);
	ClassRestoreIndirect();
	slave_l=_MemNew(sizeof(l));
	*slave_l=l;
	l=*sl;
	l.Slave=slave_l;
	l.StagenPar.Slave=&slave_l->StagenPar;
	SetSlaveData(&l,slave_l);
	LoadGenLvl--;
      } else {	/* FindName has issued msg in main windows */
	l=*sl;
      }
      _MemFree(sl);
      _MemFree(slv1);
      ParamSetICs(l.ImplCode,l.ImplMax,l.ImplNames);
    }
    /* Re-evaluate G-dimensions of functions in windows */
    VisualizerReevalGDim();
  } else {
    myWarning("CT_OPEN",ParBuf);
    return 2;
  }
  return ret;
}

Local(void) HideGen(void) {
  Int2 i;
  s=l;
  ParamDataHRS(PD_HIDE,2*LoadGenLvl);
  MemFill(&l,0,sizeof(l));	/* clean all except something */
  l.DescFile=s.DescFile;
  l.HelpInfo=s.HelpInfo;
  l.InitPointType=s.InitPointType;
  l.CurveType=s.CurveType;
  /* To provide 'swap' and 'restore' */
  MemCopy(l.StagenPar.FuncParams+NKFP,
	  s.StagenPar.FuncParams+NKFP,
	  sizeof(FuncParamPtr PNTR)*(DIM(l.StagenPar.FuncParams)-NKFP));
  MemCopy(l.StagenPar.FuncParamsNum+NKFP,
	  s.StagenPar.FuncParamsNum+NKFP,
	  sizeof(Int2)*(DIM(l.StagenPar.FuncParamsNum)-NKFP));
  MemCopy(l.StagenPar.FuncParamsHandle+NKFP,
	  s.StagenPar.FuncParamsHandle+NKFP,
	  sizeof(LibHandle PNTR)*(DIM(l.StagenPar.FuncParamsHandle)-NKFP));
  l.StagenPar.BifDataInOk=s.StagenPar.BifDataInOk;
  l.StagenPar.BifDataInPtr=s.StagenPar.BifDataInPtr;
  l.StagenPar.BifDataInLen=s.StagenPar.BifDataInLen;
#if IMPL
  l.ImplInternalReload=s.ImplInternalReload;
#endif	/* IMPL */
  for (i=0; i<DIM(l.ImplCode); i++) {
    l.ImplCode[i]=s.ImplCode[i];
    l.ImplMax[i]=s.ImplMax[i];
    if (LoadGenLvl) l.ImplNames[i]=s.ImplNames[i];
  }
  ParamSetICs(l.ImplCode,l.ImplMax,l.ImplNames);
}

Local(void) SwapGen(Char oper) {
  Locals w;
  w=s;
  s=l;
  l=w;
  ParamDataHRS(PD_SWAP,2*LoadGenLvl);
  switch (oper) {
    case 'l': MemFill(&l,0,sizeof(l)); break;
    case 's': MemFill(&s,0,sizeof(s)); break;
  }
#if IMPL
  l.ImplInternalReload=s.ImplInternalReload;
#endif	/* IMPL */
  ParamSetICs(l.ImplCode,l.ImplMax,l.ImplNames);
  VisualizerReevalGDim(); /* Re-evaluate G-dimensions of functions in windows */
}

Local(void) RestoreGen(void) {
  l=s;
  ParamDataHRS(PD_RESTORE,2*LoadGenLvl);
  ParamSetICs(l.ImplCode,l.ImplMax,l.ImplNames);
  VisualizerReevalGDim(); /* Re-evaluate G-dimensions of functions in windows */
}

/*-------------*/
/* Gen(B+Load */
Local(Int2) UnloadLoadGen(void) {
  Int2 rc;
  /* 'Hide' old loaded */
  HideGen();
  /* No more selected curve */
  DeactivateCurve(FALSE);
  DiagramLib.SelectedDirPtr=0;
  DataLibSetSelected(&DiagramLib);
  /* Load new */
  rc=LoadGen(TRUE);	/* diagram/defaults params have been taken */
  /* Merge params of old stagen with ones of new */
  if (rc==0) {
    ParamDataMerge(s.StagenPar.StaParDesc,l.StagenPar.StaParDesc,FALSE);
    ParamDataMerge(s.StagenPar.GenParDesc,l.StagenPar.GenParDesc,FALSE);
    ParamDataMergeByClass(s.StagenPar.StaParDesc,s.StagenPar.ClassReal,
			  l.StagenPar.StaParDesc,l.StagenPar.ClassReal);
    ParamDataMergeByClass(s.StagenPar.GenParDesc,s.StagenPar.ClassReal,
			  l.StagenPar.GenParDesc,l.StagenPar.ClassReal);
    UpdateAllParams();
  }
  /* Swap old and new stagens */
  SwapGen(' ');
  /* Unload old */
  UnloadGen(TRUE);
  /* 'Restore' new */
  RestoreGen();
  return rc;
}

Global(Boolean) IsDimGMore1(void) {
  return l.DimGMore1;
}

Global(void) SetDimGMore1(Boolean b) {
  l.DimGMore1=b;
}

/*-------------------------------------------------------*/
/* Reload another implementation of starter or generator */ 

Global(void) ImplReload(Int2 stagen, Int2 method) {
  LocalsPtr sl,wl;
  CallbackPtr sProcessPoint;
  Int2 i,steps=(stagen-1)/2;
  if (steps) {
    for (i=0,wl=&l; i<steps; i++,wl=wl->Slave);
    sl=_MemNew(sizeof(l));
    *sl=l;
    l=*wl;
    sProcessPoint=l.StagenPar.ProcessPoint;
    LoadGenLvl+=steps;
  }
#if IMPL
  l.ImplInternalReload=stagen;
#else	/* IMPL */
  ImplInternalReload=stagen;
#endif	/* IMPL */
  l.ImplCode[stagen-1]=method;
  l.call=!UnloadLoadGen();
#if IMPL
  l.ImplInternalReload=0;
#else	/* IMPL */
  ImplInternalReload=0;
#endif	/* IMPL */
  RefreshMenus();
  if (steps) {
    l.StagenPar.ProcessPoint=sProcessPoint;
    *wl=l;
    l=*sl;
    _MemFree(sl);
    SetSlaveData(&l,wl);
    LoadGenLvl-=steps;
    l.ImplCode[stagen-1]=method;
    ParamSetICs(l.ImplCode,l.ImplMax,l.ImplNames);
    VisualizerReevalGDim();
  } else {
    StrCpy(ParBuf,l.CurveType->TitleOnCurve);
    ImplAppendMethods(ParBuf);
    UpdateInfoInMainWindow(MWI_CURVETYPE,ParBuf);
  }
}


/**********************/
/* Pause mode support */

Local(Int1) SuspendRes;		/* User's choice */
Local(Boolean) WaitAnswer;	/* TRUE while pause */

Local(void) ResumeProc(void) {
  if (!IncompleteAction()) {
    SuspendRes=PS_RESUME;
    WaitAnswer=FALSE;
  }
}

Local(void) StopProc(void) {
  if (!IncompleteAction()) {
    SuspendRes=PS_ABORT;
    WaitAnswer=FALSE;
  }
}

Local(void) TakeProc(void) {
  if (!IncompleteAction())
    if (CurCurve) {
      SuspendRes=PS_TAKE;
      WaitAnswer=FALSE;
    } else {
      myWarning("CT_SWITCH");
    }
}

Local(void) SuspendProc(void) {
  l.StagenPar.SuspendIsPending=1;	/* suspend mode is pending */
}

Local(void) AbortProc(void) {
  l.StagenPar.SuspendIsPending=2;	/* abort is pending */
}

/*===================*/
/* via popup buttons */

Local(Boolean) pauseNo=FALSE;
Local(WindoW) pauseWin=0;
Local(GrouP)  pauseSG,pauseRG;	/* suspend and resume group */

/* callback for 'resume' button */
#if _WIN
#pragma argsused
#endif
Local(void) bResumeProc(ButtoN b) {
  ResumeProc();
}

/* callback for 'abort' button */
#if _WIN
#pragma argsused
#endif
Local(void) bStopProc(ButtoN b) {
  StopProc();
}

/* callback for 'take' button */
#if _WIN
#pragma argsused
#endif
Local(void) bTakeProc(ButtoN b) {
  TakeProc();
}

/* Callback for 'suspend' button */
#if _WIN
#pragma argsused
#endif
Local(void) bSuspendProc(ButtoN b) {
  SuspendProc();
}

/* Callback for 'abort' button */
#if _WIN
#pragma argsused
#endif
Local(void) bAbortProc(ButtoN b) {
  AbortProc();
}

/* Show/Hide 'Suspend/resume' items */
Local(void) bPauseServ(PauseService service) {
  GrouP g;
  switch (service) {
    case ENABLE_PAUSE:
      if (pauseNo) break;
      if (!pauseWin) {	/* first time - create pause/abort window */
	GetParam(SFS_CURVES,"MOUSE");
	if (*ParBuf=='0') {pauseNo=TRUE; break;}
#if _UNIX
	pauseWin=ShadowWindow(-100,-100,-3,-8,NULL);
#else
	pauseWin=ShadowWindow(-100,-100,-1,-1,NULL);
#endif
	g=HiddenGroup(pauseWin,0,0,NULL);
	SetGroupMargins(g,0,0);
	pauseRG=HiddenGroup(g,0,3,NULL);
	SetGroupMargins(pauseRG,0,0);
#if _UNIX
	SetGroupSpacing(pauseRG,3,8);
#else
	SetGroupSpacing(pauseRG,3,3);
#endif
	PushButton(pauseRG,CurveTxt[RESUME_B],bResumeProc);
	PushButton(pauseRG,CurveTxt[ABORT_B],bStopProc);
	PushButton(pauseRG,CurveTxt[TAKE_B],bTakeProc);
	pauseSG=HiddenGroup(g,0,3,NULL);
	SetGroupMargins(pauseSG,0,0);
#if _UNIX
	SetGroupSpacing(pauseSG,3,8);
#else
	SetGroupSpacing(pauseSG,3,3);
#endif
	PushButton(pauseSG,CurveTxt[SUSPEND_B],bSuspendProc);
	PushButton(pauseSG,CurveTxt[ABORT_B],bAbortProc);
	RealizeWindow(pauseWin);
      }
      Hide(pauseRG);
      Show(pauseSG);
      if (Miscdata.Suspend==SUSPEND_EACH) Disable(pauseSG);
      else Enable(pauseSG);
      Show(pauseWin);
      break;
    case DISABLE_PAUSE:
      if (pauseNo) break;
#if _WIN
      Hide(pauseWin);
#endif
#if _UNIX
      Disable(pauseSG);
#endif
      break;
    case ENABLE_RESUME:
      PauseItemsAll(TRUE);
      if (pauseNo) break;
      Hide(pauseSG);
      Show(pauseRG);
      Enable(pauseRG);
      break;
    case DISABLE_RESUME:
      PauseItemsAll(FALSE);
      if (pauseNo) break;
      Hide(pauseRG);
      Show(pauseSG);
      if (Miscdata.Suspend==SUSPEND_EACH) Disable(pauseSG);
      else Enable(pauseSG);
      break;
  }
}


/*------------------------------------------*/
/* Forward/Backward/Continue common routine */

Local(Char) keys[4]={'\0','\0','\0','\0'};
#define keySuspend	keys[0]
#define keyAbort	keys[1]
#define keyResume	keys[2]
#define keyTake		keys[3]

Local(CharPtr) keysExt[]={
  "space",
  "esc",
  "enter",
  "return",
  NULL
};

Local(Char) keysInt[]={' ','\x1b','\x0d','\x0d',
  '\0'};

/* Reads keys' definition for suspend, abort, resume, and take */
Local(void) ReadKeys(void) {
  CharPtr p;
  int pos;
  Int2 i,j;
  Char b[20];
  GetParam(SFS_CURVES,"KEYS");
  for (p=ParBuf,i=0; i<4; p+=pos,i++) {
    sscanf(p," %s%n",b,&pos);
    if (b[1]) {
      StrLower(b);
      for (j=0; keysInt[j]; j++) 
	if (!StrCmp(b,keysExt[j])) {
	  keys[i]=keysInt[j];
	  break;
	}
    } else keys[i]=*b;
  }
}

/* 'Go' mode key callback */
Local(void) GoKey(Char key) {
  if (!keySuspend) ReadKeys();
  if (key==keySuspend) {
    SuspendProc();
    return;
  }
  if (key==keyAbort) {
    AbortProc();
  }
}

/* Key callback for 'wait' mode */

Local(void) WaitKey(Char key) {
  if (!keySuspend) ReadKeys();
  if (key==keyResume) {
    ResumeProc();
    return;
  }
  if (key==keyAbort) {
    StopProc();
    return;
  }
  if (key==keyTake) {
    TakeProc();
  }
}

Local(void) SetInitPoint(FilePtr curvePtr, Int2 pointNum);

/**********************/
/* Exception handling */

#include <signal.h>

#if _WIN && defined(WIN32)
#define Catcher _CatcherPTR
#else
typedef void (PNTR Catcher)();
#endif
Local(Catcher) SysFpeException;
#if _UNIX
Local(Catcher) SysTrapException;
#endif
Local(jmp_buf) retenv;

/* Declarations for Start/End Critical Region */
Local(jmp_buf PNTR) Pretenv=NULL;
Local(CallbackCR) Pcallback=NULL;

/*--------------------*/
/* General exceptions */

#ifdef _UNIX_SGI
Local(void) MyTraps(int sig) {
  if (Pcallback) {
    Pcallback(sig);
  } else {
    switch (sig) {
      case SIGSEGV: StrCpy(ParBuf,"SIGSEGV"); break;
      case SIGILL: StrCpy(ParBuf,"SIGILL"); break;
      case SIGBUS: StrCpy(ParBuf,"SIGBUS"); break;
      default: sprintf(ParBuf,"%i",sig);
    }
    StrCat(ParBuf," signal");
    myMessage(MSG_OK,ParBuf);
  }
  signal(sig,MyTraps);
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
#endif	/* _UNIX_SGI */

#ifdef _UNIX_SOL
Local(void) MyTraps(int sig) {
  if (Pcallback) {
    Pcallback(sig);
  } else {
    switch (sig) {
      case SIGSEGV: StrCpy(ParBuf,"SIGSEGV"); break;
      case SIGILL: StrCpy(ParBuf,"SIGILL"); break;
      case SIGBUS: StrCpy(ParBuf,"SIGBUS"); break;
      default: sprintf(ParBuf,"%i",sig);
    }
    StrCat(ParBuf," signal");
    myMessage(MSG_OK,ParBuf);
  }
  sigrelse(sig);
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
#endif	/* _UNIX_SOL */

#ifdef _UNIX_HP
Local(void) MyTraps(int sig) {
  if (Pcallback) {
    Pcallback(sig);
  } else {
    switch (sig) {
      case SIGSEGV: StrCpy(ParBuf,"SIGSEGV"); break;
      case SIGILL: StrCpy(ParBuf,"SIGILL"); break;
      case SIGBUS: StrCpy(ParBuf,"SIGBUS"); break;
      default: sprintf(ParBuf,"%i",sig);
    }
    StrCat(ParBuf," signal");
    myMessage(MSG_OK,ParBuf);
  }
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
#endif	/* _UNIX_HP */

#ifdef _UNIX_ALF
#include <machine/fpu.h>
Local(void) MyTraps(int sig) {
  if (Pcallback) {
    Pcallback(sig);
  } else {
    switch (sig) {
      case SIGSEGV: StrCpy(ParBuf,"SIGSEGV"); break;
      case SIGILL: StrCpy(ParBuf,"SIGILL"); break;
      case SIGBUS: StrCpy(ParBuf,"SIGBUS"); break;
      default: sprintf(ParBuf,"%i",sig);
    }
    StrCat(ParBuf," signal");
    myMessage(MSG_OK,ParBuf);
  }
  ieee_set_fp_control(IEEE_TRAP_ENABLE_INV|IEEE_TRAP_ENABLE_DZE|IEEE_TRAP_ENABLE_OVF);
  sigrelse(sig);
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
#endif	/* _UNIX_ALF */

#ifdef _UNIX_LNX
Local(void) MyTraps(int sig) {
  if (Pcallback) {
    Pcallback(sig);
  } else {
    switch (sig) {
      case SIGSEGV: StrCpy(ParBuf,"SIGSEGV"); break;
      case SIGILL: StrCpy(ParBuf,"SIGILL"); break;
      case SIGBUS: StrCpy(ParBuf,"SIGBUS"); break;
      default: sprintf(ParBuf,"%i",sig);
    }
    StrCat(ParBuf," signal");
    myMessage(MSG_OK,ParBuf);
  }
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
#endif	/* _UNIX_LNX */

#ifdef _UNIX_R6K
Local(void) MyTraps(int sig, int Code, struct sigcontext *SCP) {
  if (Pcallback) {
    Pcallback(sig);
  } else {
    switch (sig) {
      case SIGSEGV: StrCpy(ParBuf,"SIGSEGV"); break;
      case SIGILL: StrCpy(ParBuf,"SIGILL"); break;
      case SIGBUS: StrCpy(ParBuf,"SIGBUS"); break;
      default: sprintf(ParBuf,"%i",sig);
    }
    StrCat(ParBuf," signal");
    myMessage(MSG_OK,ParBuf);
  }
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
#endif	/* _UNIX_R6K */

/*-----------------------------*/
/* Don't let numerics crash... */

#define INV_EXT	"\nThis may be a result of operations like:\n" \
		"  -  Square root of a negative number,\n"     \
		"  -  0/0,\n"                                  \
		"  -  INF/INF,\n"                              \
		"  -  INF*0,\n"                                \
		"  -  INF-INF"

#ifdef _UNIX_SGI
Local(Catcher) SysSegv,SysIll,SysBus;
#include <ieeefp.h>
Local(fp_except) oldmask;
Local(void) MyFpeException(int sig) {
  fp_except sw;
  if (Pcallback) {
    Pcallback(sig);
  } else {
    sw=fpgetsticky();
    Beep();
    if (sw&FP_X_OFL) myMessage(MSG_OK,"Overflow exception");
    if (sw&FP_X_DZ)  myMessage(MSG_OK,"Divide by zero exception");
    if (sw&FP_X_INV) myMessage(MSG_OK,"Invalid operation exception."INV_EXT);
  }
  signal(SIGFPE,MyFpeException);
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
Local(void) MyTrapException(int sig, int code) {
  if (Pcallback) {
    Pcallback(sig);
  } else {
    if (code==BRK_OVERFLOW) myMessage(MSG_OK,"Integer overflow");
    if (code==BRK_DIVZERO) myMessage(MSG_OK,"Integer divide by zero");
    if (code==BRK_MULOVF) myMessage(MSG_OK,"Integer multiply overflow");
    Beep();
  }
  signal(SIGTRAP,MyTrapException);
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
#endif	/* _UNIX_SGI */

#ifdef _UNIX_SOL
#include <ieeefp.h>
Local(fp_except) oldmask;
Local(struct sigaction) sa;
Local(struct sigaction) SysFpe;
Local(struct sigaction) SysSegv;
Local(struct sigaction) SysIll;
Local(struct sigaction) SysBus;
Local(void) MyFpeException(int sig, siginfo_t * info, void *ptr) {
  if (Pcallback) {
    Pcallback(sig);
  } else {
    switch (info->si_code) {
      case FPE_INTDIV: myMessage(MSG_OK,"Integer divide by zero"); break;
      case FPE_INTOVF: myMessage(MSG_OK,"Integer overflow"); break;
      case FPE_FLTDIV: myMessage(MSG_OK,"Floating point divide by zero"); break;
      case FPE_FLTOVF: myMessage(MSG_OK,"Floating point overflow"); break;
      case FPE_FLTINV: myMessage(MSG_OK,"Invalid floating point operation."INV_EXT); break;
    }
  }
  fpsetsticky(0);
  sigrelse(SIGFPE);
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
#endif	/* _UNIX_SOL */

#ifdef _UNIX_HP
Local(Catcher) SysSegv,SysIll,SysBus;
/***#include <ieeefp.h> on HP: math.h!***/
Local(fp_except) oldmask;
Local(void) MyFpeException(int sig) {
  fp_except sw;
  if (Pcallback) {
    Pcallback(sig);
  } else {
    sw=fpgetsticky();
    Beep();
    if (sw&FP_X_OFL) myMessage(MSG_OK,"Overflow exception");
    if (sw&FP_X_DZ)  myMessage(MSG_OK,"Divide by zero exception");
    if (sw&FP_X_INV) myMessage(MSG_OK,"Invalid operation exception."INV_EXT);
    myMessage(MSG_OK,"Floating-point exception");
  }
  fpsetsticky(FP_X_CLEAR);
  signal(SIGFPE,MyFpeException);
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
#endif	/* _UNIX_HP */

#ifdef _UNIX_ALF
Local(struct sigaction) sa;
Local(struct sigaction) SysFpe;
Local(struct sigaction) SysSegv;
Local(struct sigaction) SysIll;
Local(struct sigaction) SysBus;
Local(void) MyFpeException(int sig, siginfo_t * info, void *ptr) {
  if (Pcallback) {
    Pcallback(sig);
  } else {
    switch (info->si_code) {
      case FPE_INTDIV: myMessage(MSG_OK,"Integer divide by zero"); break;
      case FPE_INTOVF: myMessage(MSG_OK,"Integer overflow"); break;
      case FPE_FLTDIV: myMessage(MSG_OK,"Floating point divide by zero"); break;
      case FPE_FLTOVF: myMessage(MSG_OK,"Floating point overflow"); break;
      case FPE_FLTINV: myMessage(MSG_OK,"Invalid floating point operation."INV_EXT); break;
    }
  }
/*** What's instead of fpsetsticky(0); ? ***/
  ieee_set_fp_control(IEEE_TRAP_ENABLE_INV|IEEE_TRAP_ENABLE_DZE|IEEE_TRAP_ENABLE_OVF);
  sigrelse(SIGFPE);
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
#endif	/* _UNIX_ALF */

#ifdef _UNIX_LNX
Local(Catcher) SysSegv,SysIll,SysBus;
#include <fpu_control.h>
Local(void) MyFpeException(int sig) {
  if (Pcallback) {
    Pcallback(sig);
  } else {
    myMessage(MSG_OK,"Floating-point exception");
  }
  signal(SIGFPE,MyFpeException);
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
Local(void) MyTrapException(int sig) {
  if (Pcallback) {
    Pcallback(sig);
  } else {
    Beep();
  }
  signal(SIGTRAP,MyTrapException);
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
#endif	/* _UNIX_LNX */

#ifdef _UNIX_R6K
#include <fptrap.h>
#include <fpxcp.h>
Local(struct sigaction) sa;
Local(struct sigaction) SysFpe;
Local(struct sigaction) SysSegv;
Local(struct sigaction) SysIll;
Local(struct sigaction) SysBus;
Local(void) MyFpeException(int Signal, int Code, struct sigcontext *SCP) {
  struct fp_sh_info fcp;
  if (Pcallback) {
    Pcallback(sig);
  } else {
    fpstat_t fpscr=FP_INVALID|FP_OVERFLOW|FP_DIV_BY_ZERO;
    fp_sh_info(SCP,&fcp,sizeof(fcp));
    StrCpy(ParBuf,"Floating-point exception:\n");
    if (fcp.trap&FP_INVALID) {
      StrCat(ParBuf," Invalid operation ");
      if (fcp.trap&FP_INV_ISI) StrCat(ParBuf,"(INF-INF)");
      if (fcp.trap&FP_INV_IDI) StrCat(ParBuf,"(INF/INF)");
      if (fcp.trap&FP_INV_ZDZ) StrCat(ParBuf,"(0/0)");
      if (fcp.trap&FP_INV_IMZ) StrCat(ParBuf,"(INF*0)");
      if (fcp.trap&FP_INV_SQRT) StrCat(ParBuf,"(square root of a negative number)");
    }
    if (fcp.trap&FP_OVERFLOW) {
      StrCat(ParBuf,"Overflow");
    }
    if (fcp.trap&FP_DIV_BY_ZERO) {
      StrCat(ParBuf,"Division by 0");
    }
    myMessage(MSG_OK,ParBuf);
  }
  fp_sh_set_stat(SCP,fpscr);
/***  myMessage(MSG_OK,ParBuf);***/
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}
#endif	/* _UNIX_R6K */


#if _WIN

#pragma argsused
#ifdef WIN32
Local(void) _USERENTRY MyFpeException(int sig, int type) {
#else
Local(void) MyFpeException(int sig, int type) {
#endif
  if (Pcallback) {
    Pcallback(sig);
  } else {
    StrCpy(ParBuf,"Floating-point exception\n");
    switch (type) {
      case FPE_INTOVFLOW:	StrCat(ParBuf,"INTO executed with OF flag set\n"); break;
      case FPE_INTDIV0:	StrCat(ParBuf,"Integer divide by zero\n"); break;
      case FPE_INVALID:	StrCat(ParBuf,"Invalid operation\n"); break;
      case FPE_ZERODIVIDE:StrCat(ParBuf,"Division by zero\n"); break;
      case FPE_OVERFLOW:	StrCat(ParBuf,"Numeric overflow\n"); break;
      case FPE_UNDERFLOW:	StrCat(ParBuf,"Numeric underflow\n"); break;
      case FPE_INEXACT:	StrCat(ParBuf,"Precision\n"); break;
      case FPE_STACKFAULT:StrCat(ParBuf,"80x87 Stack overflow\n"); break;
    }
    myMessage(MSG_OK,ParBuf);
  }
#ifdef WIN32
  _fpreset();
#endif
  _clear87();
  _control87(EM_UNDERFLOW|EM_DENORMAL|EM_INEXACT,MCW_EM);
  signal(SIGFPE,MyFpeException);
  if (Pretenv) longjmp(*Pretenv,1);
  else longjmp(retenv,1);
}

Global(int) matherr(struct exception PNTR e) {
  sprintf(ParBuf,"%s(%g)\n",e->name,e->arg1);
  myMessage(MSG_OK,ParBuf);
  e->retval=1;
  return 1;
}

#endif	/* _WIN */

/* Start/End Critical Region */

Global(void) StartCR(jmp_buf PNTR pretenv, CallbackCR callback) {

#ifdef _UNIX_LNX
	  fpu_control_t cw;
#endif	/* _UNIX_LNX */

  Pretenv=pretenv;
  Pcallback=callback;

#ifdef _UNIX_SGI
      oldmask=fpsetmask(FP_X_OFL|FP_X_DZ|FP_X_INV);
      SysFpeException=signal(SIGFPE,MyFpeException);
      SysTrapException=signal(SIGTRAP,MyTrapException);
      SysSegv=signal(SIGSEGV,MyTraps);
      SysIll=signal(SIGILL,MyTraps);
      SysBus=signal(SIGBUS,MyTraps);
#endif	/* _UNIX_SGI */

#ifdef _UNIX_SOL
      sa.sa_flags=SA_SIGINFO;
      MemFill(&sa.sa_mask,0,sizeof(sa.sa_mask));
      sa.sa_sigaction=MyFpeException;
      oldmask=fpsetmask(FP_X_OFL|FP_X_DZ|FP_X_INV);
      sigaction(SIGFPE,&sa,&SysFpe);
      sa.sa_sigaction=MyTraps;
      sigaction(SIGSEGV,&sa,&SysSegv);
      sa.sa_sigaction=MyTraps;
      sigaction(SIGILL,&sa,&SysIll);
      sa.sa_sigaction=MyTraps;
      sigaction(SIGBUS,&sa,&SysBus);
#endif	/* _UNIX_SOL */

#ifdef _UNIX_HP
      oldmask=fpsetmask(FP_X_OFL|FP_X_DZ|FP_X_INV);
      SysFpeException=signal(SIGFPE,MyFpeException);
      SysSegv=signal(SIGSEGV,MyTraps);
      SysIll=signal(SIGILL,MyTraps);
      SysBus=signal(SIGBUS,MyTraps);
#endif	/* _UNIX_HP */

#ifdef _UNIX_ALF
      sa.sa_flags=SA_SIGINFO;
      MemFill(&sa.sa_mask,0,sizeof(sa.sa_mask));
      sa.sa_sigaction=MyFpeException;
      ieee_set_fp_control(IEEE_TRAP_ENABLE_INV|IEEE_TRAP_ENABLE_DZE|IEEE_TRAP_ENABLE_OVF);
      sigaction(SIGFPE,&sa,&SysFpe);
      sa.sa_sigaction=MyTraps;
      sigaction(SIGSEGV,&sa,&SysSegv);
      sa.sa_sigaction=MyTraps;
      sigaction(SIGILL,&sa,&SysIll);
      sa.sa_sigaction=MyTraps;
      sigaction(SIGBUS,&sa,&SysBus);
#endif	/* _UNIX_ALF */

#ifdef _UNIX_LNX
      //__setfpucw(_FPU_IEEE^(_FPU_MASK_IM|_FPU_MASK_OM|_FPU_MASK_ZM));
	  cw = _FPU_IEEE^(_FPU_MASK_IM|_FPU_MASK_OM|_FPU_MASK_ZM);
      _FPU_SETCW(cw);
      SysFpeException=signal(SIGFPE,MyFpeException);
      SysTrapException=signal(SIGTRAP,MyTrapException);
      SysSegv=signal(SIGSEGV,MyTraps);
      SysIll=signal(SIGILL,MyTraps);
      SysBus=signal(SIGBUS,MyTraps);
#endif	/* _UNIX_LNX */

#ifdef _UNIX_R6K
      if (fp_trap(FP_TRAP_SYNC)==FP_TRAP_UNIMPL)
	printf("fp_trap(FP_TRAP_SYNC)==FP_TRAP_UNIMPL\n");
      fp_enable(TRP_INVALID|TRP_DIV_BY_ZERO|TRP_OVERFLOW);
      sa.sa_handler=(void (*)())MyFpeException;
      sigaction(SIGFPE,&sa,&SysFpe);
      sa.sa_handler=(void (*)())MyTraps;
      sigaction(SIGSEGV,&sa,&SysSegv);
      sa.sa_handler=(void (*)())MyTraps;
      sigaction(SIGILL,&sa,&SysIll);
      sa.sa_handler=(void (*)())MyTraps;
      sigaction(SIGBUS,&sa,&SysBus);
#endif	/* _UNIX_R6K */

#if _WIN
#ifdef WIN32
      _fpreset();
#endif
      _clear87();
      _control87(EM_UNDERFLOW|EM_DENORMAL|EM_INEXACT,MCW_EM);
      SysFpeException=signal(SIGFPE,MyFpeException);
#endif	/* _WIN */

}	/* StartCR() */

Global(void) EndCR(void) {

#ifdef _UNIX_LNX
	  fpu_control_t cw;
#endif	/* _UNIX_LNX */

  Pretenv=NULL;
  Pcallback=NULL;

#ifdef _UNIX_SGI
      fpsetmask(oldmask);
      signal(SIGFPE,SysFpeException);
      signal(SIGTRAP,SysTrapException);
      signal(SIGSEGV,SysSegv);
      signal(SIGILL,SysIll);
      signal(SIGBUS,SysBus);
#endif	/* _UNIX_SGI */

#ifdef _UNIX_SOL
      fpsetmask(oldmask);
      sigaction(SIGFPE,&SysFpe,NULL);
      sigaction(SIGSEGV,&SysSegv,NULL);
      sigaction(SIGILL,&SysIll,NULL);
      sigaction(SIGBUS,&SysBus,NULL);
#endif	/* _UNIX_SOL */

#ifdef _UNIX_HP
      fpsetmask(oldmask);
      signal(SIGFPE,SysFpeException);
      signal(SIGSEGV,SysSegv);
      signal(SIGILL,SysIll);
      signal(SIGBUS,SysBus);
#endif	/* _UNIX_HP */

#ifdef _UNIX_ALF
      ieee_set_fp_control(0);
      sigaction(SIGFPE,&SysFpe,NULL);
      sigaction(SIGSEGV,&SysSegv,NULL);
      sigaction(SIGILL,&SysIll,NULL);
      sigaction(SIGBUS,&SysBus,NULL);
#endif	/* _UNIX_ALF */

#ifdef _UNIX_LNX
      //__setfpucw(_FPU_IEEE);
	  cw = _FPU_IEEE;
      _FPU_SETCW(cw);
      signal(SIGFPE,SysFpeException);
      signal(SIGTRAP,SysTrapException);
      signal(SIGSEGV,SysSegv);
      signal(SIGILL,SysIll);
      signal(SIGBUS,SysBus);
#endif	/* _UNIX_LNX */

#ifdef _UNIX_R6K
      fp_trap(FP_TRAP_OFF);
      sigaction(SIGFPE,&SysFpe,NULL);
      sigaction(SIGSEGV,&SysSegv,NULL);
      sigaction(SIGILL,&SysIll,NULL);
      sigaction(SIGBUS,&SysBus,NULL);
#endif	/* _UNIX_R6K */

#if _WIN
      _clear87();
      _control87(MCW_EM,MCW_EM);
      signal(SIGFPE,SysFpeException);
#endif	/* _WIN */

}	/* EndCR */

/********************/
/* Compute umbrella */

Local(void) FillStagenPar(StagenDataPtr sgp, Boolean udf) {
  /* Rhs entry point.
     Store each time because another functions might be selected */
  sgp->Rhs=FunctionsEntry;
  sgp->Der1=DerEntry[0];
  sgp->Der2=DerEntry[1];
  sgp->Der3=DerEntry[2];
  sgp->Der4=DerEntry[3];
  sgp->Der5=DerEntry[4];
  sgp->AuxFunc=AuxFuncs;
  /* Ptrs to parameters update functions */
  sgp->AskParIndex=locGetParIndex;
  /* pointer to callback function for obtaining index of parameter */
  sgp->UpdatePar=locUpdatePar;
  if (udf) {
    /* User defined functions */
    sgp->udFuncNum=UserFuncNum;
    sgp->udFunc=UserFuncInterface;
    sgp->udFuncName=UserFuncName;
  }
}

Local(void) locVisualizerInitGCurve(void) {
  Int2 i;
  VisualizerInitGCurve();
  if (l.locUserFuncIndex>=0 && l.StagenPar.IndirectValues[l.locUserFuncIndex])
    for (i=0; i<l.locUserFuncDim; i++)
      l.StagenPar.IndirectValues[l.locUserFuncIndex][i]=NOUPDATE;
}

Local(void) Go(Boolean forward, Boolean new) {
  CharPtr audf;
  Int2 i;
  Uint2 m;
  ccd.Computing=TRUE;
  UpdateInfoInMainWindow(MWI_MESSAGE,"");
  if (l.call) {
    FillStagenPar(&l.StagenPar,TRUE);
    /* Direct it to the right direction */
    l.StagenPar.Forward=forward;
    /* Set ptr to process point callback */
    l.StagenPar.ProcessPoint=ProcessGPoint;
    /* Record udf appended by the user to the defining function */
    l.UdfMask=0;
    audf=(CharPtr)GetLocalClassVector(GetClassId("SPECCL_AUS"));
    if (audf)
      for (i=0, m=1; i<UserFuncNum; i++, m<<=1)
	if (audf[i]==UDF_APPEND) l.UdfMask|=m;
    /* Call starter and generator at last */
    if (l.pStarter && l.pGenerator) {
      PushContext(0,GoKey,CurveTxt[STA_C]);
      l.StagenPar.SuspendIsPending=0;
      
      StartCR(NULL,NULL);	/* default retenv and handling */
      
      l.WhoRuns=1;		/* starter */
      if (setjmp(retenv)==0) {
	l.StagenPar.Reason=RF_DO;
	if (!l.pStarter(&l.StagenPar)) {
	  Decoder(&l.StagenPar,DECODER_INIT);
	  if (new)
	    StorageInitGCurve();	/* after the generator has been initialized */
	  else {
	  }
	  /* This must be called after StorageInitGCurve.
	     Otherwise ccd.CurrentCurvePtr is not initialized */
	  locVisualizerInitGCurve();
	  l.WhoRuns=2;		/* generator */
	  SuspendRes=PS_RESUME;	/* default */
	  bPauseServ(ENABLE_PAUSE);	/* Show 'pause' button */
	  if (setjmp(retenv)==0) {
	    l.StagenPar.Reason=RF_DO;
	    l.pGenerator(&l.StagenPar);
	  } else {
	    l.WhoRuns=0;		/* ProcessPoint: ignore calls  */
	    l.StagenPar.Reason=RF_CRASH;
	    l.pGenerator(NULL);		/* terminate generator, e.g. free memory, etc. */
	  }
	  bPauseServ(DISABLE_PAUSE);	/* Hide 'pause' button */
	  Decoder(&l.StagenPar,DECODER_TERM);
	  l.StagenPar.Reason=RF_CLEAN;
	  l.pStarter(NULL);		/* terminate starter, e.g. free memory, etc. */
	  StorageTermGCurve(forward);
	  VisualizerTermGCurve();
	  /* Take the last point as initial one */
	  if (SuspendRes==PS_TAKE) {
	    PopContext();
	    SetInitPoint(ccd.CurrentCurvePtr,ccd.pointType ? ccd.CurrentSpecialPoint-1 : -1);
	    PushContext(0,NULL,"");
	  }
	}		/* if (!l.pStarter(&l.StagenPar)) { */
      } else {	/* if (setjmp(retenv)==0) */
        l.WhoRuns=0;		/* ProcessPoint: ignore calls  */
	l.StagenPar.Reason=RF_CRASH;
	l.pStarter(NULL);	/* terminate starter, e.g. free memory, etc. */
      }
      
      EndCR();
      
      PopContext();
    }
    RefreshMenus();
  }
  ccd.Computing=FALSE;
}

/* Show resume button group and wait until one of them will be pressed */
Local(Int1) WaitUntil(void) {
  CurrentCurveData saveccd;
  DataLibPtr saveSPList,saveVAList;
  bPauseServ(ENABLE_RESUME);	/* Show 'resume/abort/take' buttons */
  PushContext(HLP_SUSPEND,WaitKey,CurveTxt[SUS_C]);
  saveccd=ccd;
  if (CurDiagram) {
    DataLibSavePos(&DiagramLib);
    saveSPList=StorageSPList;
    saveVAList=StorageVAList;
  }
  for (WaitAnswer=TRUE; WaitAnswer; myProcessAnEvent());
  if (CurDiagram) {
    DataLibRestorePos(&DiagramLib);
    StorageSPList=saveSPList;
    StorageVAList=saveVAList;
  }
  ccd=saveccd;
  PopContext();
  bPauseServ(DISABLE_RESUME);	/* Hide 'resume/abort/take' buttons */
  return SuspendRes;
}

/*
   This generalized Decoder is called to
   access current curve-specific decoder.
   Decoder's input:  - pointer to a G-point structure produced by generator,
		     - operation to perform:
		       DECODER_INIT - initialize decoder.
			   point is a pointer to StagenData structure.
		       DECODER_TERM - terminate decoder (e.g. free memory, etc.).
		       DECODER_DIM  - return the dimension of G-point (how many M-points it contains).
		       n - n>0, extract n-th V-point from the P-point
			   and put it into l.StagenPar.InderectValues.
   Decoder's return: number of V-points to be extracted or -1 if the function
		     is successful; it is -1 otherwise.
   Curve-specific decoder has additional parameters that specifies a buffer
		     for extructed M-point.
   It seems the following three lines contain no-longer-valid statement. 06.04.95
   Curve-specific decoder should not set any global variable for itself because
   the Visualizer may call it for different G-points randomly.
   This means that a work area of a decoder must be placed into G-point structure.
*/
Global(Int2) Decoder(VoidPtr point, Int2 oper) {
  if (l.locUserFuncIndex>=0)
    l.StagenPar.IndirectValues[l.locUserFuncIndex]=UserFuncValues;
  return l.pDecoder(point,l.StagenPar.IndirectValues,oper);
}

/*------------------------------------------*/
/* Process G-points produced by a generator */
/*     See VISUAL.H for terminology         */

/* For ordinary points (PointType==0) Msg must be NULL */

Global(Int2) curveCurNum;		/* number of current M-point in current G-point */

/*
  Each G-filtered G-point that stored in archives has the following format:
  1. Always, Pointtype.     Point type: 0 for regular points,
			    Local code (1,2,3,...) for specials.
			    Pointtype is a typedefed type (stagen.h).
  2. PointType, Char[].     Text of a message associated with a special point.
  3. PointType, Partition.  Bifurcation data in a form of DataLib Partition.
  4. l.DimGMore1, Int2.     Number of really stored M-points (M-filtered).
  5. Always, FloatHi[].     Filtered coordinates of M-point(s).
  NB: The last point along a curve is indicated by PointTyp==CurveType.
*/

/* This function is called from generators (which are DLLs) */
Local(Int2) ProcessGPoint(Pointtype PointType, VoidPtr Gpoint, CharPtr Msg) {
  DataLibPos SPpos;	/* FilePtr to a special point */
  PairPtr pp;
  Pair sp;
  Int2 i,j;
  Int2 r=0;
  Boolean gOk,mOk,take,debugPt=FALSE,dgmcrv=CurDiagram && MaxUntitled>0;
  Prolog
  if (l.WhoRuns==0) return 0;
  /* Treat generator's 'debug' points in a special manner */
  if (PointType==255) {
    PointType=0;
    debugPt=TRUE;
  }
  /* User defined point? */
  if (PointType&USERPOINT) {
    PointType=USERPOINT | l.UdfMask | (1<<(PointType&~USERPOINT));
    ccd.localpointType=PointType;
  } else {
/***    ccd.localpointType=0;***/
    ccd.localpointType=PointType;
  }
  /* Last point? */
  ccd.lastPoint=PointType==l.StagenPar.ProcFuncNum;
  if (ccd.lastPoint) {		/* Last point */
    if (ccd.pointType) {	/* the last pt is a true special point */
      r=1;
      goto exit;
    } else {			/* prev was ordinary - overwrite it */
      if (dgmcrv) DataLibSeek(&DiagramLib,&ccd.LastOPcoord);
    }
  }
  /* Dimensions of current and prev G-points, and message */
  ccd.curvePrevDimG=ccd.curveDimG;
  ccd.curveDimG=Decoder(Gpoint,DECODER_DIM);	/* ask the number of M-points */
  ccd.pointPrevType=ccd.pointType;
  ccd.pointType=PointType&USERPOINT ?
		l.CurveType->Type :
		l.StagenPar.DetectedTypes[PointType];
  if (ccd.curveLastMsg)		/* make it gray */
    UpdateInfoInMainWindow(MWI_MESSAGE,NULL);
  ccd.curveLastMsg=Msg;
  /* M-curve initialization */
  VisualizerInitMCurve();
  /* Apply G-points filter (Filters are ignored for special points) */
  gOk=take=dgmcrv && !debugPt;
  if (PointType) {
    sp.from=0;
  } else {
    gOk=gOk && (l.filter.fFrom[0]<=ccd.CurGNum && ccd.CurGNum<=l.filter.fTo[0]);
    if (gOk) gOk=(ccd.CurGNum-l.filter.fFrom[0])%l.filter.fStep[0]==0;
    take=FALSE;
  }
  /* assert(dgmcrv && (PointType!=0) */
  /* Get FilePtr to special point to be written */
  if (take) {
    DataLibTell(&DiagramLib,&SPpos);
  }
  if (Msg && !ccd.lastPoint) UpdateInfoInMainWindow(MWI_MESSAGE,Msg);
  /* Check this before if (gOk) because gOk may be FALSE due to the filter */
  if (PointType==0 && dgmcrv) {	/* ordinary point */
    DataLibTell(&DiagramLib,&ccd.LastOPcoord);
    if (ccd.LastSpecialPoint!=ccd.CurrentSpecialPoint) {
      DataLibSavePos(&DiagramLib);
      DataLibRestorePosPtr(&DiagramLib,StorageSPList);
      DataLibTell(&DiagramLib,&ccd.LastOPsp);
      StorageSPList=DataLibSavePosPtr(&DiagramLib);
      DataLibRestorePosPtr(&DiagramLib,StorageVAList);
      DataLibTell(&DiagramLib,&ccd.LastOPva);
      StorageVAList=DataLibSavePosPtr(&DiagramLib);
      DataLibRestorePos(&DiagramLib);
      ccd.LastSpecialPoint=ccd.CurrentSpecialPoint;
    }
  }
  if (gOk) {
    /* Write type of a point */
    DataLibWrite(&DiagramLib,(CharPtr)&PointType,sizeof(PointType));
    /* and a message, if any */
    if (PointType) {
      if (!Msg) Msg="";
      DataLibWriteVRecord(&DiagramLib,NULL,Msg,StrLen(Msg)+1);
      DataLibWriteVRecord(&DiagramLib,
			  NULL,
			  (CharPtr)l.StagenPar.BifDataOutPtr,
/***22.04.97			  PointType&USERPOINT ? 0 :***/
			  l.StagenPar.BifDataOutLen);
    }
    /* and number of M-points for multi-dimensional G-point */
    if (l.DimGMore1) {
      i=PointType ? ccd.curveDimG :
		    (MIN(ccd.curveDimG,l.filter.fTo[1])-l.filter.fFrom[1])/l.filter.fStep[1]+1;
      DataLibWrite(&DiagramLib,(CharPtr)&i,sizeof(i));
    }
  }
  /* Loop through M-points */
  for (curveCurNum=1; curveCurNum<=ccd.curveDimG; curveCurNum++) {
    /* Extract next M-point */
    Decoder(Gpoint,curveCurNum);
    /* Visualize current M-point */
    VisualizerProcMPoint();
    /* Store M-point into current diagram */
    if (gOk) {
      if (l.DimGMore1 && !PointType) {
	/* Apply M-points filter (Filters are ignored for special points) */
	mOk=l.filter.fFrom[1]<=curveCurNum && curveCurNum<=l.filter.fTo[1];
	if (mOk) mOk=(curveCurNum-l.filter.fFrom[1])%l.filter.fStep[1]==0;
      } else mOk=TRUE;
      if (mOk) {
	/* Apply coordianes filter (Filters are ignored for special points) */
	for (i=0; i<l.NumOfRelevantClasses; i++) {
	  if (l.ClassDimG[i]==FALSE && curveCurNum>1) continue;
	  pp=PointType ? (sp.num=-l.specfilter[i],&sp) : l.coordfilter[i];
	  j=0;
	  if (pp)
	    do {
	      DataLibWrite(&DiagramLib,(CharPtr)(l.StagenPar.IndirectValues[i+1]+pp[j].from),
			   ARRAYSIZE(FloatHi,ABS(pp[j].num)));
	    } while (pp[j++].num>0);
	}
      }
    }
  }
  VisualizerTermMCurve();	/* M-curve termination */
  if (!ccd.lastPoint) {
    /* Pause processing */
    while (EventAvail())
    myProcessAnEvent();	/* allow to react to user's moves */
    switch (l.StagenPar.SuspendIsPending) {
      case 0:	/* no pending suspend or abort request */
	switch (Miscdata.Suspend) {
	  case SUSPEND_NEVER:
	    /* nothing to do */
	    break;
	  case SUSPEND_EACH:
	    if (WaitUntil()!=PS_RESUME) r=1;
	    break;
	  case SUSPEND_SPECIAL:
	    if (PointType) {
	      if (WaitUntil()!=PS_RESUME) r=1;
	    }
	    break;
	}
	break;
      case 1:	/* suspend mode is pending */
	if (WaitUntil()!=PS_RESUME) r=1;
	l.StagenPar.SuspendIsPending=0;
	break;
      case 2:	/* abort is pending */
	r=1;
	break;
    }
  }
  /* Store FilePtr to current special point and visualizer's attribs.
     This is done after processing pause mode because the user
     might change attribs during it */
  if (take) {
    DataLibSavePos(&DiagramLib);
    /* add a pointer to the list of special points */
    DataLibRestorePosPtr(&DiagramLib,StorageSPList);
    DataLibWrite(&DiagramLib,(CharPtr)&SPpos,sizeof(SPpos));
    StorageSPList=DataLibSavePosPtr(&DiagramLib);
    /* store segment's visual attribs */
    DataLibRestorePosPtr(&DiagramLib,StorageVAList);
    SaveVisualAttr(&DiagramLib,NULL,NULL,FALSE);
    StorageVAList=DataLibSavePosPtr(&DiagramLib);
    /* restore datalib ptr */
    DataLibRestorePos(&DiagramLib);
  }
  /* Increase counts */
  if (!debugPt) ccd.CurGNum++;
  if (PointType) ccd.CurrentSpecialPoint++;
 exit:;
  Epilog
  return r;
}

/* We suppose that sta and gen don't want to update more than MAXINDEX values during one 'Compute' */
#define MAXINDEX	5

typedef struct {
  Int2 index;
  VoidPtr desc;
} IndexCache;

Local(IndexCache) indexCache[MAXINDEX];
Local(Int2) indxCachePtr=0;

/* Parameter update related functions */
Local(Int2) locGetParIndex(VoidPtr DataArea, Uint2 Offset) {
  VoidPtr desc;
  Int2 Index;
  Prolog
/***  Index=GetParIndex(l.WhoRuns==1 ? l.StagenPar.StaParDesc : l.StagenPar.GenParDesc, Offset);***/
  desc=NULL;
  if (l.StagenPar.StaPtr==DataArea) desc=l.StagenPar.StaParDesc;
  else if (l.StagenPar.GenPtr==DataArea) desc=l.StagenPar.GenParDesc;
  else if (l.Slave) {
    if (l.Slave->StagenPar.StaPtr==DataArea) desc=l.Slave->StagenPar.StaParDesc;
    else if (l.Slave->StagenPar.GenPtr==DataArea) desc=l.Slave->StagenPar.GenParDesc;
  }
  if (desc) {
    indexCache[Index=indxCachePtr].desc=desc;
    indexCache[indxCachePtr++].index=GetParIndex(desc,Offset);
    if (indxCachePtr>=MAXINDEX) indxCachePtr=0;
  } else Index=-1;
  Epilog
  return Index;
}

#undef MAXINDEX

Local(void) locUpdatePar(Int2 Index) {
  Prolog
/***  UpdatePar(l.WhoRuns==1 ? l.StagenPar.StaParDesc : l.StagenPar.GenParDesc, Index);***/
  if (Index>=0) UpdatePar(indexCache[Index].desc,indexCache[Index].index);
  Epilog
}

typedef struct {
  DataLibPos LastOPcoord;	/* see ccd */
  DataLibPos LastOPsp;
  DataLibPos LastOPva;
  Int2 gnum;			/* number of the last point */
  Boolean forward;		/* TRUE - forward, FALSE - backward */
} TermData, PNTR TermDataPtr;	/* fixed part of data in LP_PART partition */

/*-----------------------*/
/* Called from Main menu */

#if _WIN
#pragma argsused
#endif
Global(void) ForwardProc(Int2 index) {
  Go(TRUE,TRUE);
}

#if _WIN
#pragma argsused
#endif
Global(void) BackwardProc(Int2 index) {
  Go(FALSE,TRUE);
}

#if _WIN
#pragma argsused
#endif
Global(Boolean) FBProc_Status(Int2 index) {
  return
    l.call &&
    FunctionsHandle &&		/* functions are selected */
    l.InitPointType &&		/* and type of init point specified */
    l.CurveType;		/* and type of curve specified */
}

#if _WIN
#pragma argsused
#endif
Global(void) ContinueProc(Int2 index) {
  TermData td;
  size_t spl;
  Boolean forward;
/***  InvalidateBifData(); ***/
  /* Go to special subdirs level */
  DataLibDown(&DiagramLib);
  /* Read LastPoint partition and restore corrdinates */
  if (DataLibFind(&DiagramLib,LP_PART)) {	/* no partition */
    DataLibUp(&DiagramLib);
    myWarning("CT_CONT");
    return;
  }
  DataLibRead(&DiagramLib,(CharPtr)&td,sizeof(td));
  forward=td.forward;
  ccd.LastOPcoord=td.LastOPcoord;
  ccd.LastOPsp=td.LastOPsp;
  ccd.LastOPva=td.LastOPva;
  ccd.CurGNum=td.gnum;
  l.StagenPar.ContDataGenPtr=(FloatHiPtr)DataLibReadVRecord(&DiagramLib,NULL);
  l.StagenPar.ContDataGenLen=DataLibLastVRecLen;
  l.StagenPar.ContDataStaPtr=(FloatHiPtr)DataLibReadVRecord(&DiagramLib,NULL);
  l.StagenPar.ContDataStaLen=DataLibLastVRecLen;
  /* Current curve */
  ccd.CurrentCurvePtr=DiagramLib.SelectedDirPtr;
  /* Seek after the end of SpecialPoints list */
  if (DataLibFind(&DiagramLib,SP_PART)) {
    DataLibCreate(&DiagramLib,SP_PART);
    DataLibTell(&DiagramLib,&ccd.LastOPsp);
    spl=0;
  } else {
    spl=DataLibSkipPartition(&DiagramLib);
    DataLibSeek(&DiagramLib,&ccd.LastOPsp);
    spl-=DataLibSkipPartition(&DiagramLib);
  }
  ccd.CurrentSpecialPoint=(Int2)(spl/sizeof(DataLibPos));
  ccd.LastSpecialPoint=ccd.CurrentSpecialPoint;
  DataLibSeek(&DiagramLib,&ccd.LastOPsp);
  StorageSPList=DataLibSavePosPtr(&DiagramLib);
  /* Seek after the end of VisualAttributes list */
  if (DataLibFind(&DiagramLib,VA_PART)) {
    DataLibCreate(&DiagramLib,VA_PART);
    SaveVisualAttr(&DiagramLib,NULL,NULL,FALSE);
    DataLibTell(&DiagramLib,&ccd.LastOPva);
  } else
    DataLibSkipPartition(&DiagramLib);
  DataLibSeek(&DiagramLib,&ccd.LastOPva);
  StorageVAList=DataLibSavePosPtr(&DiagramLib);
  /* Go up and seek at the last ordinary point */
  DataLibUp(&DiagramLib);
  DataLibSeek(&DiagramLib,&ccd.LastOPcoord);
  Go(forward,FALSE);
  /* Clean up. Just in case something was wrong */
  if (l.StagenPar.ContDataGenLen) {
    l.StagenPar.ContDataGenPtr=_MemFree(l.StagenPar.ContDataGenPtr);
    l.StagenPar.ContDataGenLen=0;
  }
  if (l.StagenPar.ContDataStaLen) {
    l.StagenPar.ContDataStaPtr=_MemFree(l.StagenPar.ContDataStaPtr);
    l.StagenPar.ContDataStaLen=0;
  }
  StorageSPList=_MemFree(StorageSPList);
  StorageVAList=_MemFree(StorageVAList);
}

#if _WIN
#pragma argsused
#endif
Global(Boolean) ContinueProc_Status(Int2 index) {
  return CurCurve;	/* There is selected curve */
}


/*----------------*/
/* Activate curve */

Global(Boolean) CurCurve;	/* There is current (selected) curve */

Global(void) ActivateCurve(void) {
#define dlDiag (&DiagramLib)
  Int2 type[2];
  Boolean selected;
  Pointtype pointtype;
  /* assert(LoadGenLvl==0); */
  selected=!DataLibIsClosed(dlDiag) && dlDiag->SelectedDirPtr;
  if (selected) {
    DataLibSeekDir(dlDiag,dlDiag->SelectedDirPtr);
    UpdateInfoInMainWindow(MWI_CURVE,dlDiag->DirName+1);
    CurCurve=TRUE;
    /* Read types and find starter and generator descriptions */
    DataLibRead(dlDiag,(CharPtr)type,sizeof(l.InitPointType->Type)+sizeof(l.CurveType->Type));
   FindStagen:;
    l.InitPointType=FindNodeByType(type[0]);
    l.CurveType=FindNodeByType(type[1]);
    FindName();
    if (l.DescFile) {
      UpdateInfoInMainWindow(MWI_INITTYPE,l.InitPointType->Title);
    } else {
      l.InitPointType=l.CurveType=NULL;
      return;
    }
  }
  InvalidateBifData();
  if (l.InitPointType && l.CurveType) {
    PushContext(0,NULL,CurveTxt[LOAD_C]);
    if (l.OldDescFile) {
/***      if (StrCmp(l.OldDescFile,l.DescFile)==0) {***/
      if (AreStaGenSame()) {
	if (selected) {
	  Int2 ImplS,ImplG,ImplSslv,ImplGslv;
	  Boolean reload=FALSE;
	  if ((l.ImplMax[0]+l.ImplMax[1]) || l.Slave &&(l.ImplMax[2]+l.ImplMax[3])) {
	    ImplS=l.ImplCode[0];
	    ImplG=l.ImplCode[1];
	    ImplSslv=l.ImplCode[2];
	    ImplGslv=l.ImplCode[3];
	    ImplReadCodes();
	    reload=ImplS!=l.ImplCode[0] || ImplG!=l.ImplCode[1] ||
		l.Slave && (ImplSslv!=l.ImplCode[2] || ImplGslv!=l.ImplCode[3]);
	  }
	  if (reload) {
#if IMPL
	    l.ImplInternalReload=1;	/* it might be 2 */
#else	/* IMPL */
	    ImplInternalReload=1;	/* it might be 2 */
#endif	/* IMPL */
	    UnloadGen(TRUE);
	    l.call=!LoadGen(TRUE);
#if IMPL
	    l.ImplInternalReload=0;
#else	/* IMPL */
	    ImplInternalReload=0;
#endif	/* IMPL */
	  } else {
	    /* only restore values of parameters */
	    CreateDataArea(NULL,1,NULL,FALSE);	/* of starter */
	    CreateDataArea(NULL,2,NULL,FALSE);	/* and generator */
	    ParamFuncPtrs(FALSE);
	    UpdateAllParams();
	    RestoreFilter(TRUE);
	    ReadUdfTable();
	  }
	}
      } else {
	UnloadGen(TRUE);
	/* Load current sta-gen */
	l.call=!LoadGen(TRUE);
      }
    } else l.call=!LoadGen(TRUE);
    PopContext();
      StrCpy(ParBuf,l.CurveType->TitleOnCurve);
      ImplAppendMethods(ParBuf);
      UpdateInfoInMainWindow(MWI_CURVETYPE,ParBuf);
    if (CurCurve) {
      /* Get bifurcation data if the first point is a special point */
      DataLibRead(&DiagramLib,(CharPtr)&pointtype,sizeof(pointtype));
      if (pointtype) {	/* yes, it is a special point */
	CharPtr vp;
	vp=DataLibReadVRecord(&DiagramLib,NULL);
	_MemFree(vp);		/* skip message */
	l.StagenPar.BifDataInPtr=(VoidPtr)DataLibReadVRecord(&DiagramLib,NULL);
	l.StagenPar.BifDataInLen=DataLibLastVRecLen;
	l.StagenPar.BifDataInOk=l.StagenPar.BifDataInLen>0;
      } else {
	DataLibSavePos(dlDiag);
	if (DataLibDown(dlDiag)==0 && DataLibFind(dlDiag,BD_PART)==0) {
	  l.StagenPar.BifDataInPtr=(VoidPtr)DataLibReadVRecord(&DiagramLib,NULL);
	  l.StagenPar.BifDataInLen=DataLibLastVRecLen;
	  l.StagenPar.BifDataInOk=l.StagenPar.BifDataInLen>0;
	}
	DataLibRestorePos(dlDiag);
      }
    }
  } else
    if (DataLibIsClosed(dlDiag)) l.call=FALSE;
    else {
      DataLibSavePos(dlDiag);
      while (!DataLibUp(dlDiag));
      if (DataLibFind(dlDiag,SG_PART)==0) {
	DataLibRead(dlDiag,(CharPtr)type,sizeof(l.InitPointType->Type)+sizeof(l.CurveType->Type));
	DataLibRestorePos(dlDiag);
	goto FindStagen;
      } else {
	DataLibRestorePos(dlDiag);
	l.call=FALSE;
      }
    }
#undef dlDiag
}

/* Deactivate curve */
Global(void) DeactivateCurve(Boolean full) {
  if (TermFlag || full) {
    if (!CurCurve && l.InitPointType && l.CurveType && !DataLibIsClosed(&DiagramLib)) {
      DataLibSavePos(&DiagramLib);
      while (!DataLibUp(&DiagramLib));
      if (DataLibFind(&DiagramLib,SG_PART)==0)
	DataLibDelete(&DiagramLib);
      DataLibCreate(&DiagramLib,SG_PART);
      DataLibWrite(&DiagramLib,(CharPtr)&(l.InitPointType->Type),sizeof(l.InitPointType->Type));
      DataLibWrite(&DiagramLib,(CharPtr)&(l.CurveType->Type),sizeof(l.CurveType->Type));
      DataLibRestorePos(&DiagramLib);
    }
    UnloadGen(TRUE);
    l.OldDescFile=NULL;
    l.InitPointType=l.CurveType=NULL;
    UpdateInfoInMainWindow(MWI_INITTYPE,"");
    UpdateInfoInMainWindow(MWI_CURVETYPE,"");
  }
  
  FreeUdfTable();
  UpdateInfoInMainWindow(MWI_CURVE,"");
  UpdateInfoInMainWindow(MWI_MESSAGE,"");
  CurCurve=FALSE;
}

/*-------------*/
/* Store curve */

/*
   Each curve in archives has the following structure.
   1. Absolute type of initial point (see Node.Type).
   2. Absolute type of regular points (see Node.Type).
   3. Values of appropriate starter's parameters (see param.c).
   4. Values of appropriate generator's parameters (see param.c).
   5. Archives filter describing what points and coordinates
      were written to archives.
   6. Table of unique numbers of user defined funcs
      which defines the map local number ==> unique number (userfunc.c).
   7. Points comprising a curve.
*/

/* Create new untitled curve (partition in diagram) */
Local(void) StorageInitGCurve(void) {
  FilePtr newpart;
  FilePtr PNTR p;
  DataLibPtr dlsave;
  Int2 n,i;
  Char buf[200];
  /* assert(LoadGenLvl==0); */
  CurCurve=FALSE;
  StorageSPList=StorageVAList=NULL;
  ccd.CurrentCurvePtr=0;
  ccd.CurrentSpecialPoint=0;
  ccd.LastSpecialPoint=-1;
  if (CurDiagram) {
    if (MaxUntitled>0) {
      /* Create new untitled partition */
      sprintf(buf,"%s  %s->%s (%s)",Untitled,
	l.InitPointType->Title,l.CurveType->TitleOnCurve,
	l.StagenPar.Forward ? "+" : "-");
	ImplAppendMethods(buf);
      if (DataLibCreate(&DiagramLib,buf)) return;
      /* Make new curve the selected one */
      DiagramLib.SelectedDirPtr=DiagramLib.CurDirPtr;
      ccd.CurrentCurvePtr=DiagramLib.CurDirPtr;
      UpdateInfoInMainWindow(MWI_CURVE,buf);
      CurCurve=TRUE;
      /* Create two subdirs for 1) visualizer's attributes, and 2) index of spec. pts */
      DataLibDown(&DiagramLib);
      DataLibCreate(&DiagramLib,SP_PART);
      StorageSPList=DataLibSavePosPtr(&DiagramLib);
      DataLibTell(&DiagramLib,&ccd.LastOPsp);
      DataLibCreate(&DiagramLib,VA_PART);
      SaveVisualAttr(&DiagramLib,NULL,NULL,FALSE);
      StorageVAList=DataLibSavePosPtr(&DiagramLib);
      DataLibTell(&DiagramLib,&ccd.LastOPva);
      /* Create subdir with bif data of the first point */
      if (l.StagenPar.BifDataInOk) {
	DataLibCreate(&DiagramLib,BD_PART);
	DataLibWriteVRecord(&DiagramLib,
			  NULL,
			  (CharPtr)l.StagenPar.BifDataInPtr,
			  l.StagenPar.BifDataInLen);
      }
      /* Create subdir with Implementation Codes */
      if ((l.ImplMax[0]+l.ImplMax[1]) || l.Slave && (l.ImplMax[2]+l.ImplMax[3])) {
	DataLibCreate(&DiagramLib,IC_PART);
	DataLibWrite(&DiagramLib,(CharPtr)l.ImplCode,sizeof(l.ImplCode));
      }
      /* Create subdir with slave sta/gen parameters */
      if (l.Slave) {
	DataLibCreate(&DiagramLib,SLVPAR_PART);
	SaveDataCurve(l.Slave->StagenPar.StaParDesc,&DiagramLib);
	SaveDataCurve(l.Slave->StagenPar.GenParDesc,&DiagramLib);
      }
      DataLibUp(&DiagramLib);
      /* 1.-4. */
      DataLibWrite(&DiagramLib,(CharPtr)&l.InitPointType->Type,sizeof(l.InitPointType->Type));
      DataLibWrite(&DiagramLib,(CharPtr)&l.CurveType->Type,sizeof(l.CurveType->Type));
      SaveDataCurve(l.StagenPar.StaParDesc,&DiagramLib);
      SaveDataCurve(l.StagenPar.GenParDesc,&DiagramLib);
      /* 5. Filter */
      /*    first, adjust current dimensions (UserFunc might be changed) */
      for (i=0; i<l.NumOfRelevantClasses; i++)
	l.specfilter[i]=*l.StagenPar.ClassDim[i+1];
      WriteFilter(FALSE);
      /* 6. Unique number of udf */
      WriteUdfTable();
      DataLibTell(&DiagramLib,&ccd.LastOPcoord);
    }
    /* Now remove excessive untitles curves */
    /* Save DiagramLib ptr and goto to the level 0 */
    newpart=DiagramLib.CurDirPtr;
    DataLibSavePos(&DiagramLib);
    dlsave=DiagramLib.Saved;
    while (!DataLibUp(&DiagramLib));
    /* Read the list of ptrs to untitled partitions */
    p=(FilePtr PNTR)DataLibReadVRecord(&DiagramLib,UNTLST);
    /* Remove excessive partitions and add newly created one */
    n=(Int2)(DataLibLastVRecLen/sizeof(FilePtr));
    if (n>=MaxUntitled) {
      for (i=0; i<n-MAX(MaxUntitled-1,0); i++) {
	FreeCurveResources(&DiagramLib,*p);
	DataLibSeekDir(&DiagramLib,*p);
	DataLibDown(&DiagramLib);
	DataLibDeletePartitions(&DiagramLib,VA_PART,SP_PART,LP_PART,BD_PART,IC_PART,NULL);
	DataLibUp(&DiagramLib);
	DataLibDelete(&DiagramLib);
	if (*p==dlsave->CurDirPtr) dlsave->CurDirPtr=0;
	if (*p==dlsave->SelectedDirPtr) dlsave->SelectedDirPtr=0;
	MemMove(p,p+1,ARRAYSIZE(FilePtr,n-1));
      }
      n=MaxUntitled;
    } else {
      p=_MemMore(p,ARRAYSIZE(FilePtr,n+1));
      n++;
    }
    if (n) p[n-1]=newpart;
    /* Write the list back */
    while (!DataLibUp(&DiagramLib));
    if (n)
      DataLibWriteVRecord(&DiagramLib,UNTLST,(CharPtr)p,ARRAYSIZE(FilePtr,n));
    else
      DataLibDeletePartitions(&DiagramLib,UNTLST,NULL);
    _MemFree(p);
    /* Restore DiagramLib ptr */
    DataLibRestorePos(&DiagramLib);
    DataLibSetSelected(&DiagramLib);
    /* init G-point counter */
    ccd.CurGNum=1;
  }
  if (!CurCurve) ReadUdfTable();
}

/* Terminate creation of a new curve */
Local(void) StorageTermGCurve(Boolean forward) {
  TermData td;
  StorageSPList=_MemFree(StorageSPList);
  StorageVAList=_MemFree(StorageVAList);
  if (CurDiagram && MaxUntitled>0) {
    DataLibSavePos(&DiagramLib);
    /* Store ALL coordiantes of the last point */
    DataLibDown(&DiagramLib);
    DataLibDeletePartitions(&DiagramLib,LP_PART,NULL);
    DataLibCreate(&DiagramLib,LP_PART);
    td.forward=forward;
    td.gnum=ccd.CurGNum;
    td.LastOPcoord=ccd.LastOPcoord;
    td.LastOPsp=ccd.LastOPsp;
    td.LastOPva=ccd.LastOPva;
    DataLibWrite(&DiagramLib,(CharPtr)&td,sizeof(td));
    /* Generator's "continue  data" */
    DataLibWriteVRecord(&DiagramLib,NULL,
			(CharPtr)l.StagenPar.ContDataGenPtr,
			l.StagenPar.ContDataGenLen);
    /* Starter's "continue  data" */
    DataLibWriteVRecord(&DiagramLib,NULL,
			(CharPtr)l.StagenPar.ContDataStaPtr,
			l.StagenPar.ContDataStaLen);
    DataLibRestorePos(&DiagramLib);
    /* Flush at last (this also writes SelectedDirPtr etc.) */
    DataLibFlush(&DiagramLib);
  }
  if (l.StagenPar.ContDataGenLen) {
    _MemFree(l.StagenPar.ContDataGenPtr);
    l.StagenPar.ContDataGenLen=0;
  }
  if (l.StagenPar.ContDataStaLen) {
    _MemFree(l.StagenPar.ContDataStaPtr);
    l.StagenPar.ContDataStaLen=0;
  }
}

/* Delete a reference to partition from Untitled List (if any) */
Local(void) DelFromUntLst(DataLibPtr DiagramLib, FilePtr fp) {
  FilePtr PNTR p;
  Int2 i,j;
  DataLibSavePos(DiagramLib);
  while (!DataLibUp(DiagramLib));
  p=(FilePtr PNTR)DataLibReadVRecord(DiagramLib,UNTLST);
  j=(Int2)(DataLibLastVRecLen/sizeof(FilePtr));
  for (i=0; i<j; i++)
    if (p[i]==fp) {
      MemMove(p+i,p+i+1,ARRAYSIZE(FilePtr,j-(i+1)));
      if (j>1)
	DataLibWriteVRecord(DiagramLib,UNTLST,(CharPtr)p,ARRAYSIZE(FilePtr,j-1));
      else
	DataLibDelete(DiagramLib);
      break;
    }
  _MemFree(p);
  DataLibRestorePos(DiagramLib);
}

/* Free data associated with a curve being deleted */
Local(void) FreeCurveResources(DataLibPtr DiagramLib, FilePtr fp) {
  FilePtr curptr;
  Int2 method[DIM(l.ImplCode)];
  Int2 i;
  Char b[BL];
  /* Save ptr and set it to the curve */
  curptr=DiagramLib->CurDirPtr;
  if (DataLibSeekDir(DiagramLib,fp)) return;	/* cannot seek - incorrect fp */
  /* Read type of init and regular points and  find appropriate descriptor */
  /* -- first get methods */
  for (i=0; i<DIM(method); i++) method[i]=0;	/* defaults */
  if (DataLibDown(DiagramLib)) return;		/* cannot go down */
  if (DataLibFind(DiagramLib,IC_PART)==0)
    DataLibRead(DiagramLib,(CharPtr)method,sizeof(method));
  DataLibUp(DiagramLib);
  if (FindAndOpenDescFile(DiagramLib,SECPRF"data%s")) {
    for (i=0; i<2; i++) 
      if (mGetLine(b,method[i]))
	ParamFreeUDF(b,DiagramLib);	/* 0-starter, 1-generator */
    DescClose();
    if (l.Slave) {
      if (OpenDescFileAndFindSection(l.Slave->DescFile,SECPRF"data%s")) {
	for (i=2; i<4; i++) 
	  if (mGetLine(b,method[i]))
	    ParamFreeUDF(b,DiagramLib);	/* 0-starter, 1-generator */
	DescClose();
      }
    }
    VisualizerFreeCurve(fp);
  }
  /* Restore ptr */
  DataLibSeekDir(DiagramLib,curptr);
}

/*----------------------------------------------*/
/* Manipulation of user defined functions table */
/* 
   This table lists unique (absolute) numbers of
   enabled user defined functions when a curve
   was computed.
*/

Local(void) ReadUdfTable(void) {
  _MemFree(l.UdfTable);
  if (CurCurve) {
    l.UdfTable=(Uint4Ptr)DataLibReadVRecord(&DiagramLib,NULL);
    l.UdfTableNum=(Int2)(DataLibLastVRecLen/sizeof(Uint4));
  } else {
    l.UdfTable=_MemNew(ARRAYSIZE(Uint4,l.UdfTableNum=UserFuncNum));
    MemCopy(l.UdfTable,UserFuncUnique,ARRAYSIZE(Uint4,l.UdfTableNum));
  }
}

Local(void) WriteUdfTable(void) {
  _MemFree(l.UdfTable);
  l.UdfTable=_MemNew(ARRAYSIZE(Uint4,l.UdfTableNum=UserFuncNum));
  MemCopy(l.UdfTable,UserFuncUnique,ARRAYSIZE(Uint4,l.UdfTableNum));
  DataLibWriteVRecord(&DiagramLib,NULL,
		      (CharPtr)l.UdfTable,
		      ARRAYSIZE(Uint4,l.UdfTableNum));
}

Local(void) FreeUdfTable(void) {
  l.UdfTable=_MemFree(l.UdfTable);
  l.UdfTableNum=0;
}

/************************/
/* Redraw current curve */
/************************/

Local(Int2) RedrawResult;

Global(void) RedrawKey(Char key) {
  if (!keySuspend) ReadKeys();
  if (key==keyAbort) RedrawResult=-1;
} 

Global(Int2) RedrawCurve(void) {
  PairPtr pp;
  Pair sp;
  CharPtr Msg;
  Int2 type[2],i,j;
  Pointtype pointtype;
  Boolean saveCurCurve=CurCurve;
  RedrawResult=0;
  CurCurve=TRUE;	/* see Graphics GInit/GTerm/MProcess */
  sp.from=0;
  /* Save current locals */
  HideGen();
  /* save some visualizer's stuff */
  ClassSaveIndirect();
  PushVisualAttr(FALSE);
  /* Current Curve ptr */
  ccd.CurrentCurvePtr=DiagramLib.CurDirPtr;
  /* Read types and perform psudo-load of stagen */
  DataLibRead(&DiagramLib,(CharPtr)type,sizeof(l.InitPointType->Type)+sizeof(l.CurveType->Type));
  l.InitPointType=FindNodeByType(type[0]);
  l.CurveType=FindNodeByType(type[1]);
  FindName();
  LoadGen(FALSE);
  /* skip starter's & generator's parameters */
  SkipParameters(&DiagramLib);	/* starter's */
  SkipParameters(&DiagramLib);	/* generator's */
  /* read curve-specific filter */
  l.coordfilter=_MemNew(ARRAYSIZE(PairPtr,l.NumOfRelevantClasses));
  l.specfilter=_MemNew(ARRAYSIZE(Int2,l.NumOfRelevantClasses));
  ReadFilter(&DiagramLib);
  /* Read udf table */
  ReadUdfTable();
  /* Allocate memory for values */
  for (i=1; i<=l.NumOfRelevantClasses; i++)
/***
    l.StagenPar.IndirectValues[i]=l.locUserFuncIndex==i ?
      UserFuncValues : (FloatHiPtr)_MemNew(ARRAYSIZE(FloatHi,l.specfilter[i-1]));
***/
    l.StagenPar.IndirectValues[i]=(FloatHiPtr)_MemNew(ARRAYSIZE(FloatHi,l.specfilter[i-1]));
  /* Set visualizer's attribs for the 1st segment of curve */
  DataLibSavePos(&DiagramLib);
  if (DataLibDown(&DiagramLib)==0) {
    if (DataLibFind(&DiagramLib,VA_PART)==0) {
      RestoreVisualAttr(&DiagramLib,NULL,NULL);
      StorageVAList=DataLibSavePosPtr(&DiagramLib);
    } else StorageVAList=NULL;
    if (DataLibFind(&DiagramLib,SP_PART)==0) {
      StorageSPList=DataLibSavePosPtr(&DiagramLib);
    } else StorageSPList=NULL;
    DataLibUp(&DiagramLib);
  } else {
    StorageVAList=StorageSPList=NULL;
  }
  DataLibRestorePos(&DiagramLib);
  /* number of current special point */
  ccd.CurrentSpecialPoint=0;
  /* Read each G-points */
  locVisualizerInitGCurve();
  while (DataLibRead(&DiagramLib,(CharPtr)&pointtype,sizeof(pointtype))==sizeof(pointtype)) {
    /* Let the user abort */
    while (EventAvail())
    myProcessAnEvent();
    if (RedrawResult) break;
    ccd.lastPoint=pointtype==l.StagenPar.ProcFuncNum;
    /* Read a message, if any */
    if (pointtype) {
      ccd.curveLastMsg=DataLibReadVRecord(&DiagramLib,NULL);
      if (!ccd.lastPoint)
	UpdateInfoInMainWindow(MWI_MESSAGE,ccd.curveLastMsg);
      DataLibSkipVRecord(&DiagramLib);	/* Bifurcation data */
    } else {
      if (ccd.curveLastMsg)	/* make it gray */
	UpdateInfoInMainWindow(MWI_MESSAGE,NULL);
      ccd.curveLastMsg=NULL;
    }
    Msg=ccd.curveLastMsg;	/* visualizer may assign NULL to ccd.curveLastMsg */
    /* Dimensions of current and prev G-points */
    ccd.curvePrevDimG=ccd.curveDimG;
    /* Types of of current and prev G-points */
    ccd.pointPrevType=ccd.pointType;
    ccd.pointType=pointtype&USERPOINT ?
		  l.CurveType->Type :
		  l.StagenPar.DetectedTypes[pointtype];
    ccd.localpointType=pointtype;
    if (l.DimGMore1)
      DataLibRead(&DiagramLib,(CharPtr)&ccd.curveDimG,sizeof(ccd.curveDimG));
    else ccd.curveDimG=1;
    /* M-curve initialization */
    VisualizerInitMCurve();
    /* Loop through M-points */
    for (curveCurNum=1; curveCurNum<=ccd.curveDimG; curveCurNum++) {
      /* Read M-point according to the curve's filter (ignore it for special points) */
      for (i=0; i<l.NumOfRelevantClasses; i++) {
	if (l.ClassDimG[i]==FALSE && curveCurNum>1) continue;
	pp=pointtype ? (sp.num=-l.specfilter[i],&sp) : l.coordfilter[i];
	j=0;
	if (pp)
	  if (l.StagenPar.IndirectValues[i+1]) {
	    do {
	      DataLibRead(&DiagramLib,(CharPtr)(l.StagenPar.IndirectValues[i+1]+pp[j].from),
			  ARRAYSIZE(FloatHi,ABS(pp[j].num)));
	    } while (pp[j++].num>0);
	  } else
	    do {
	      DataLibSkip(&DiagramLib,ARRAYSIZE(FloatHi,ABS(pp[j].num)));
	    } while (pp[j++].num>0);
      }
      /* Visualize current M-point */
      VisualizerProcMPoint();
    }
    VisualizerTermMCurve();	/* M-curve termination */
    _MemFree(Msg);
    if (pointtype) {
      if (StorageVAList) {
	/* Set attributes for current segment */
	DataLibSavePos(&DiagramLib);
	DataLibRestorePosPtr(&DiagramLib,StorageVAList);
	RestoreVisualAttr(&DiagramLib,NULL,NULL);
	StorageVAList=DataLibSavePosPtr(&DiagramLib);      
	DataLibRestorePos(&DiagramLib);
      }
      ccd.CurrentSpecialPoint++;
    }
  }
  VisualizerTermGCurve();
  /* Free memory for values */
  for (i=1; i<=l.NumOfRelevantClasses; i++)
/***
    if (l.locUserFuncIndex!=i)
***/
      _MemFree(l.StagenPar.IndirectValues[i]);
  FreeUdfTable();
  /* destroy curve-specific filter */
  CurDiagram=FALSE;	/* don't write it */ 
  WriteFilter(TRUE);	/* but only free memory */
  /* Unload psudo-loaded stagen */
  UnloadGen(FALSE);
  CurDiagram=TRUE;
  /* restore current locals */
  RestoreGen();
  /* restore visualizer's data */
  ClassRestoreIndirect();
  PopVisualAttr();
  StorageVAList=_MemFree(StorageVAList);
  StorageSPList=_MemFree(StorageSPList);
  CurCurve=saveCurCurve;
  return RedrawResult;
}

#if _WIN
#pragma argsused
#endif
Global(void) RedrawCurveProc(Int2 index) {
  ccd.Computing=TRUE;
/*** Yuri requested. 07.06.96.  ClearAllWindows(0); ***/
  DataLibSavePos(&DiagramLib);
  DataLibSeekDir(&DiagramLib,DiagramLib.CurDirPtr);
  PushContext(0,RedrawKey,CurveTxt[REDRAW_C]);
  RedrawCurve();
  PopContext();
  DataLibRestorePos(&DiagramLib);
  ccd.Computing=FALSE;
}


/************************************************************/
/* Management of lists of special points and visual attribs */

/* Reads the list of special points */
Global(void) ReadSPList(Int2Ptr num, DataLibPosPtr PNTR list) {
  DataLibSavePos(&DiagramLib);
  DataLibDown(&DiagramLib);
  *num=0;
  *list=NULL;
  if (DataLibFind(&DiagramLib,SP_PART)==0) {
    *num=DataLibSkipPartition(&DiagramLib);
    *list=_MemNew(*num);
    DataLibSeekDir(&DiagramLib,DiagramLib.CurDirPtr);
    DataLibRead(&DiagramLib,(CharPtr)*list,*num);
    *num/=sizeof(DataLibPos);
  }
  DataLibRestorePos(&DiagramLib);
}

/* Frees the list of special points */
#if _WIN
#pragma argsused
#endif
Global(void) FreeSPList(Int2 num, DataLibPosPtr list) {
  _MemFree(list);
}

/* Reads the list of visual attributes */
/* Note, than num must by the value returned by ReadSPList plus 1 */
Global(void) ReadVAList(Int2 num, ByteStorePtr PNTR PNTR list) {
  Int2 i;
  DataLibSavePos(&DiagramLib);
  DataLibDown(&DiagramLib);
  *list=_MemNew(ARRAYSIZE(ByteStorePtr,num));
  if (DataLibFind(&DiagramLib,VA_PART)==0)
    for (i=0; i<num; i++) {
      (*list)[i]=BSNew(0);
      RestoreVisualAttr(&DiagramLib,NULL,(*list)[i]);	/* from dl to BS */
    }
  DataLibRestorePos(&DiagramLib);
}

/* Writes the list of visual attributes */
/* Note, than num must by the value returned by ReadSPList plus 1 */
Global(void) WriteVAList(Int2 num, ByteStorePtr PNTR list) {
  Int2 i;
  DataLibSavePos(&DiagramLib);
  DataLibDown(&DiagramLib);
  DataLibDeletePartitions(&DiagramLib,VA_PART,NULL);
  if (DataLibCreate(&DiagramLib,VA_PART)==0)
  for (i=0; i<num; i++) {
    BSSeek(list[i],0,SEEK_SET);
    SaveVisualAttr(&DiagramLib,list[i],NULL,FALSE);	/* from BS to dl */
  }
  DataLibRestorePos(&DiagramLib);
}

/* Frees the list of visual attributes */
Global(void) FreeVAList(Int2 num, ByteStorePtr PNTR list) {
  Int2 i;
  for (i=0; i<num; i++) {
    BSFree(list[i]);
  }
  _MemFree(list);
}

/************************/
/* Create Option Window */
/************************/
Local(WindoW) CreateOptionWindow(Int2 ti, CharPtr winid) {
  Int2 l=-50,t=-50;
  if (winid) ReadWindowPos(winid,&l,&t);
  return FixedWindow(l,t,-sysCharWidth,-sysLineHeight,CurveTxt[ti],NULL);
}

/*******************/
/* Storage filters */
/*******************/

#if DEB_CT
  Local(void) PrintFilter(CharPtr title) {
    PairPtr pp;
    Int2 i;
    printf("\n%s, CurDiagram=%i\n",title,(int)CurDiagram);
    printf("  G-filter: %i,%i,%i\n",
		(int)l.filter.fFrom[0],
		(int)l.filter.fTo[0],
		(int)l.filter.fStep[0]);
    printf("  M-filter: %i,%i,%i\n",
		(int)l.filter.fFrom[1],
		(int)l.filter.fTo[1],
		(int)l.filter.fStep[1]);
    printf("  c-filter:\n");
    if (l.coordfilter)
      for (i=0; i<l.NumOfRelevantClasses; i++) {
	printf("    class %i:",(int)i);
	pp=l.coordfilter[i];
	if (pp)
	  do {
	    printf(" [%i,%i]",(int)pp->from,ABS((int)pp->num));
	  } while ((pp++)->num>0);
	printf("  specDim=%i\n",(int)l.specfilter[i]);
      }
  }
#endif

/* Build partition name for filter */
Local(CharPtr) FilterPart(void) {
  CharPtr p;
  CharPtr pt,ct;
  Int2 ln,lp,lc;
  ln=StrLen(l.DescFile);
  pt=l.DescFile+ln+1;
  lp=StrLen(pt);
  ct=pt+lp+1;
  lc=StrLen(ct);
  p=_MemNew(sizeof(FILTER_PRE)+ln+1+lp+1+lc+1);
  sprintf(p,"%s%s %s %s",FILTER_PRE,l.DescFile,pt,ct);
  return p;
}

Global(void) DeleteFilters(DataLibPtr dl) {
  while (DataLibFindBySubstr(dl,FILTER_PRE,TRUE)==0)
    DataLibDelete(dl);
}

/* Read current filter (curve type dependent) or set default one */
Local(void) ReadFilter(DataLibPtr Diagram) {
  Int2 i;
  DataLibRead(Diagram,(CharPtr)&l.filter,sizeof(l.filter));
  for (i=0; i<l.NumOfRelevantClasses; i++)
    l.coordfilter[i]=(PairPtr)DataLibReadVRecord(Diagram,NULL);
  DataLibRead(Diagram,(CharPtr)l.specfilter,ARRAYSIZE(Int2,l.NumOfRelevantClasses));
}

/* Skips current filter */
Local(void) SkipFilter(void) {
  Int2 i;
  DataLibSkip(&DiagramLib,sizeof(l.filter));
  for (i=0; i<l.NumOfRelevantClasses; i++)
    DataLibSkipVRecord(&DiagramLib);
  DataLibSkip(&DiagramLib,ARRAYSIZE(Int2,l.NumOfRelevantClasses));
}

/* Write current filter */
Local(void) WriteFilter(Boolean free) {
  PairPtr pp;
  Int2 i,j;
  if (CurDiagram) {
    DataLibWrite(&DiagramLib,(CharPtr)&l.filter,sizeof(l.filter));
    for (i=0; i<l.NumOfRelevantClasses; i++) {
      pp=l.coordfilter[i];
      if (pp) for (j=0; pp[j++].num>0; );
      else j=0;
      DataLibWriteVRecord(&DiagramLib,NULL,(CharPtr)pp,ARRAYSIZE(Pair,j));
    }
    DataLibWrite(&DiagramLib,(CharPtr)l.specfilter,ARRAYSIZE(Int2,l.NumOfRelevantClasses));
  }
  if (free)
    if (l.coordfilter) {
      for (i=0; i<l.NumOfRelevantClasses; i++)
	_MemFree(l.coordfilter[i]);
      l.coordfilter=_MemFree(l.coordfilter);
      l.specfilter=_MemFree(l.specfilter);
    }
}

Local(void) RestoreFilter(Boolean takefromcurve) {
  CharPtr fltpart;
  Boolean sCurDiagram;
  if (CurDiagram) {
    DataLibSavePos(&DiagramLib);
    while (!DataLibUp(&DiagramLib));
    fltpart=FilterPart();
  }
  sCurDiagram=CurDiagram;
  CurDiagram=FALSE;
  WriteFilter(TRUE);
  CurDiagram=sCurDiagram;
  l.coordfilter=_MemNew(ARRAYSIZE(PairPtr,l.NumOfRelevantClasses));
  l.specfilter=_MemNew(ARRAYSIZE(Int2,l.NumOfRelevantClasses));
  if (takefromcurve && CurDiagram && DiagramLib.SelectedDirPtr) {
    /* take it from active curve */
    DataLibRestorePos(&DiagramLib);
    ReadFilter(&DiagramLib);
    DataLibSavePos(&DiagramLib);	/* to fool next RestorePos (see below) */
  } else
  if (!CurDiagram || DataLibFind(&DiagramLib,fltpart)) {	/* no partition, set defaults */
    int from,to,step;
    /* points filter */
    sscanf(GetParam(SFS_CURVES,"FILTER"),"%i,%i,%i",&from,&to,&step);
    l.filter.fFrom[0]=l.filter.fFrom[1]=from;
    l.filter.fStep[0]=l.filter.fStep[1]=step;
    l.filter.fTo[0]=l.filter.fTo[1]=to;
    /* coordinate filter */
    EnumClasses(0,DefFilter);	/* 0 means no LisT */
  } else {
    ReadFilter(&DiagramLib);
  }
  if (CurDiagram) {
    _MemFree(fltpart);
    DataLibRestorePos(&DiagramLib);
  }
}

Local(void) SaveFilter(Boolean free) {
  CharPtr fltpart;
  if (!l.coordfilter) return;
  if (CurDiagram) {
    DataLibSavePos(&DiagramLib);
    while (!DataLibUp(&DiagramLib));
    fltpart=FilterPart();
    if (!DataLibFind(&DiagramLib,fltpart))
      DataLibDelete(&DiagramLib);
    DataLibCreate(&DiagramLib,fltpart);
  }
  WriteFilter(free);
  if (CurDiagram) {
    _MemFree(fltpart);
    DataLibRestorePos(&DiagramLib);
  }
}

Local(TexT) tMaxUnt, tFrom[2], tTo[2], tStep[2];

Local(WindoW) FilterParent;

Local(void) FilterCancelProc(ButtoN b) {
  RestoreFilter(FALSE);		/* don't take from active curve */
  Select(FilterParent);
  Remove(ParentWindow(b));
  UnlockAll();
  PopContext();
}

Local(Boolean) GetAndCheck(TexT text, Int2Ptr value, Int2 defvalue, Int2 minvalue) {
  int num;
  Char buf[20];
  Boolean error=FALSE;
  GetTitle(text,buf,sizeof(buf));
  if (sscanf(buf,"%i",&num)==1) {
    if (num<minvalue || num>INT2_MAX) error=TRUE;
    else *value=(Int2)num;
  } else error=TRUE;
  if (error) {
    myWarning("CT_FLT",buf,(int)defvalue);
    *value=defvalue;
    sprintf(buf,"%i",defvalue);
    SetTitle(text,buf);
  }
  return error;
}

Local(void) FilterOkProc(ButtoN b) {
  Int2 i;
  Boolean error=FALSE;
/***
  GetTitle(tMaxUnt,buf,sizeof(buf));
  if (!StrToInt(buf,&MaxUntitled) || MaxUntitled<0)
    MaxUntitled=0;
***/
  error|=GetAndCheck(tMaxUnt,&MaxUntitled,0,0);
  for (i=0; i<(l.DimGMore1 ? 2 : 1); i++) {
/***
    GetTitle(tFrom[i],buf,sizeof(buf));
    if (!StrToInt(buf,l.filter.fFrom+i) || l.filter.fFrom[i]<=0)
      l.filter.fFrom[i]=1;
***/
    error|=GetAndCheck(tFrom[i],l.filter.fFrom+i,1,1);
/***
    GetTitle(tTo[i],buf,sizeof(buf));
    if (!StrToInt(buf,l.filter.fTo+i))
      l.filter.fTo[i]=INT2_MAX;
***/
    error|=GetAndCheck(tTo[i],l.filter.fTo+i,INT2_MAX,1);
/***
    GetTitle(tStep[i],buf,sizeof(buf));
    if (!StrToInt(buf,l.filter.fStep+i) || l.filter.fStep[i]<=0)
      l.filter.fStep[i]=1;
***/
    error|=GetAndCheck(tStep[i],l.filter.fStep+i,1,1);
  }
  if (error) {
    return;
  }
  MultiNamesList(NULL,NULL);	/* store currently selected, if any */
  SaveFilter(FALSE);
  Select(FilterParent);
  Remove(ParentWindow(b));
  UnlockAll();
  PopContext();
}

#if _WIN
#pragma argsused
#endif
Local(void) FilterHelpProc(ButtoN b) {
  Help(NULL);
}

Local(GrouP) Filters;

Local(void) UntNumProc(TexT t) {
  Char buf[10];
  Int2 mu;
  GetTitle(t,buf,sizeof(buf));
  if (!StrToInt(buf,&mu) || mu<0) mu=0;
  (mu ? Enable : Disable)(Filters);
}

#if _WIN
#pragma argsused
#endif
/* Sets various filters for storage of curves */
Global(void) FilterOptProc(Int2 index) {
  WindoW optwin;
  GrouP g0,g,gg;
  Int2 p;
  Int2Ptr ip;
  TexT PNTR tp;
  Int2 i,j;
  Char buf[10];
  LockAll();	/* lock second time because otherwise it would be unlocked
		   immediatedly after return */
  FilterParent=CurrentWindow();
  /* Create controls */
  optwin=CreateOptionWindow(ARCH_W,NULL);
  g0=HiddenGroup(optwin,0,6,NULL);
  SetGroupMargins(g0,0,0);
  SetGroupSpacing(g0,0,sysLineHeight2);
  g=HiddenGroup(g0,2,0,NULL);
  StaticPrompt(g,CurveTxt[OPTARCHMU_P],0,dialogTextHeight,NULL,'l');
  sprintf(buf,"%i",(int)MaxUntitled);
  tMaxUnt=DialogText(g,buf,4,UntNumProc);
  Filters=HiddenGroup(g0,0,6,NULL);
  SetGroupMargins(Filters,0,0);
  SetGroupSpacing(Filters,0,0);
  for (i=0; i<3; i++) {
    if (i==1 && !l.DimGMore1) continue;
    switch (i) {
      case 0:	/* Path filter */
	p=OPTARCHGF_T;
	break;
      case 1:	/* Trace filter */
	p=OPTARCHMF_T;
	break;
      case 2:	/* Coordinates filter */
	p=OPTARCHCF_T;
	break;
    }
    g=NormalGroup(Filters,3,0,CurveTxt[p],SystemFont,NULL);
    SetGroupMargins(g,sysCharWidth,sysLineHeight);
    SetGroupSpacing(g,sysCharWidth,sysLineHeight2);
    switch (i) {
      case 0:	/* Path filter */
      case 1:	/* Trace filter */
	for (j=0; j<3; j++) {
	  gg=HiddenGroup(g,2,0,NULL);
	  SetGroupMargins(gg,0,0);
	  SetGroupSpacing(gg,5,0);
	  switch (j) {
	    case 0:	/* From */
	      p=OPTARCHFR_P;
	      tp=tFrom+i;
	      ip=l.filter.fFrom+i;
	      break;
	    case 1:	/* To */
	      p=OPTARCHTO_P;
	      tp=tTo+i;
	      ip=l.filter.fTo+i;
	      break;
	    case 2:	/* Step */
	      p=OPTARCHST_P;
	      tp=tStep+i;
	      ip=l.filter.fStep+i;
	  }
	  StaticPrompt(gg,CurveTxt[p],0,dialogTextHeight,NULL,'l');
	  *tp=DialogText(gg,"",3,NULL);
	  sprintf(buf,"%i",(int)*ip);
	  SetTitle(*tp,buf);
	}
	break;
      case 2:	/* Coordinates filter */
	MultiNamesList(g,l.coordfilter);
	SaveFilter(FALSE);
	break;
    }
  }
  if (MaxUntitled<=0) Disable(Filters);
  TermButtons(optwin,g,FilterOkProc,FilterCancelProc,FilterHelpProc);
  PushContext(HLP_FILTER,NULL,CurveTxt[FILTER_C]);
  Show(optwin);
}

/* Determines status of menu item */
#if _WIN
#pragma argsused
#endif
Global(Boolean) FilterOptProc_Status(Int2 index) {
  return CurDiagram && l.call;		/* diagram is selected && types are selected */
}

/******************************/
/* Selection of initial point */

#if MPS
/* Reads from the DiagramLib coordinates of init point
   and takes into account lenght of source and target.
*/
Local(void) ReadAndSkip(FloatHiPtr fp, size_t tlen, size_t slen) {
  size_t read,skip;
  if (!fp) tlen=0;
  if (tlen>slen) {
    read=slen;
    skip=0;
  } else {
    read=tlen;
    skip=slen-tlen;
  }
  DataLibRead(&DiagramLib,(CharPtr)fp,read);
  DataLibSkip(&DiagramLib,skip);
}
#endif	/* MPS */

Local(void) SetInitPoint(FilePtr curvePtr, Int2 pointNum) {
  DataLibPosPtr splist;
  FloatHiPtr fp;
  FloatHiPtr PNTR fpi;
  VoidPtr sta_desc,gen_desc;
  NodePtr savePT,saveCT;
  Int2 spnum,i,j,type[2],dim,d;
#if MPS
  int slen,tlen,tlenrel;
  Boolean match;
#else
  int len;
#endif
  Pointtype pointtype;
  Boolean same;
  Int2 ImplS,ImplG,ImplSslv,ImplGslv;
  /* assert(LoadGenLvl==0);*/
  PushContext(0,NULL,CurveTxt[LOAD_C]);
  /*
     pointNum<0 means that an ordinary point is 'taken' (always on-line).
Oct'96: it seems pointNum cannot be <0.
     curvePtr==0 means a point is 'taken' on-line.
  */
  /* Save visual's Indirect[...].
     Oherwise following LoadGen(FALSE)+UnloadGen(False)
     will make them dangling if l.OldDescFile==l.DescFile */
  ClassSaveIndirect();
  /* Deactivate active curve, if any */
  DeactivateCurve(FALSE);
  InvalidateBifData();	/* before HideGen */
  savePT=l.InitPointType;
  saveCT=l.CurveType;
  if (pointNum>=0) {	/* special pt */
    HideGen();
    /* Psudo-activate the curve that contains selected point */
    /* We need to know something about the curve */
    DiagramLib.SelectedDirPtr=curvePtr;
    DataLibSeekDir(&DiagramLib,curvePtr);
    DataLibRead(&DiagramLib,(CharPtr)type,sizeof(type));
    l.InitPointType=FindNodeByType(type[0]);
    l.CurveType=FindNodeByType(type[1]);
    FindName();
    LoadGen(FALSE);	/* This fills l.StagenPar.StaPar with the name of .h file */
    ImplS=l.ImplCode[0];	/* Save curve's ImplCodes */
    ImplG=l.ImplCode[1];
    ImplSslv=l.ImplCode[2];	/* Save curve's ImplCodes */
    ImplGslv=l.ImplCode[3];
    /* Build parameters area for curve's sta&gen. Don't show them */
    sta_desc=CreateDataArea(l.StagenPar.StaPtr,-1,NULL,FALSE);
    gen_desc=CreateDataArea(l.StagenPar.GenPtr,-2,NULL,FALSE);
    /* Read filter and udfTable */
    l.coordfilter=_MemNew(ARRAYSIZE(PairPtr,l.NumOfRelevantClasses));
    l.specfilter=_MemNew(ARRAYSIZE(Int2,l.NumOfRelevantClasses));
    ReadFilter(&DiagramLib);
    CurCurve=TRUE;	/* fool ReadUdfTable */
    ReadUdfTable();
    CurCurve=FALSE;
    /* Seek the point's data */
    ReadSPList(&spnum,&splist);
    DataLibSeek(&DiagramLib,splist+pointNum);
    FreeSPList(spnum,splist);
    DataLibRead(&DiagramLib,(CharPtr)&pointtype,sizeof(pointtype));
    type[0]=pointtype&USERPOINT ?
	    l.CurveType->Type :
	    l.StagenPar.DetectedTypes[pointtype];/* real type of init point */
    type[1]=type[0];				 /* real type of curve */
    DataLibSkipVRecord(&DiagramLib);
    s.StagenPar.BifDataInPtr=(VoidPtr)DataLibReadVRecord(&DiagramLib,NULL);
    s.StagenPar.BifDataInLen=DataLibLastVRecLen;
    s.StagenPar.BifDataInOk=s.StagenPar.BifDataInLen>0;
    if (l.DimGMore1)	/* get the number of M-points in the G-point */
      DataLibRead(&DiagramLib,(CharPtr)&dim,sizeof(dim));
    else dim=1;
    /* ASSERT: DiagramLib.CurDirPtr points to coordinates */
    /* Swap psudo-loaded and old one */
    SwapGen(' ');
  } else {	/* ordinary */
    type[0]=l.CurveType->Type;
    sta_desc=l.StagenPar.StaParDesc;
    gen_desc=l.StagenPar.GenParDesc;
    HideGen();
    l.OldDescFile=s.OldDescFile;
  }
  ClassRestoreIndirect();
  /* Now load appropriate starter & generator */
  l.InitPointType=FindNodeByType(type[0]);
  l.CurveType=DefaultType(s.CurveType,pointNum>=0 ? l.InitPointType : s.CurveType);
  FindName();
  DiagramLib.SelectedDirPtr=0;
  DataLibSetSelected(&DiagramLib);
  if (l.DescFile) {	/* does exist */
    same=FALSE;
    if (l.OldDescFile) {
/***      if (StrCmp(l.OldDescFile,l.DescFile)==0) {***/
      if (AreStaGenSame()) {
	/* Compare current and curve's ImplCodes */
	if (ImplS==l.ImplCode[0] && ImplG==l.ImplCode[1] &&
	  (!l.Slave || (ImplSslv==l.ImplCode[2] && ImplGslv==l.ImplCode[3])))
	  same=TRUE;
	else {
	  l.ImplCode[0]=ImplS;
	  l.ImplCode[1]=ImplG;
	  l.ImplCode[2]=ImplSslv;
	  l.ImplCode[3]=ImplGslv;
	  ImplWriteCodes();
#if IMPL
	  l.ImplInternalReload=1;	/* it might be 2 */
#else	/* IMPL */
	  ImplInternalReload=1;	/* it might be 2 */
#endif	/* IMPL */
	}
      }
      if (!same) {
	UnloadGen(TRUE);
	l.call=!LoadGen(TRUE);
#if IMPL
	l.ImplInternalReload=0;
#else	/* IMPL */
	ImplInternalReload=0;
#endif	/* IMPL */
      }
    } else l.call=!LoadGen(TRUE);
    UpdateInfoInMainWindow(MWI_INITTYPE,l.InitPointType->Title);
    StrCpy(ParBuf,l.CurveType->TitleOnCurve);
    ImplAppendMethods(ParBuf);
    UpdateInfoInMainWindow(MWI_CURVETYPE,ParBuf);
  } else {
    l.OldDescFile=l.DescFile=s.DescFile;
    l.InitPointType=savePT;
    l.CurveType=saveCT;
    same=TRUE;
  }
  /* Merge params of psudo-loaded stagen with ones of new */
  if (l.call) {
    ParamDataMerge(sta_desc,l.StagenPar.StaParDesc,TRUE);
    ParamDataMerge(gen_desc,l.StagenPar.GenParDesc,TRUE);
    /* Overwrite coordinates of init point in starter's data area: */
    /* Read coordinates and set appropriate starter's parameters */
    /* Now: s is source (psudo-loaded), l is target (new) */
    /* Matching of local classes is via global codes */
#if MPS
#define PRNT_INITPT 0
    fp=GetLocalClassVector(GetClassId("SPECCL_DIM"));
    if (fp) *(int*)fp=(int)dim;
    for (d=0; d<dim; d++)
      for (i=1; i<=s.NumOfRelevantClasses; i++) {
	slen=ARRAYSIZE(FloatHi,s.specfilter[i-1]);
	for  (j=1,match=FALSE; j<=l.NumOfRelevantClasses; j++)
	  if (s.StagenPar.ClassReal[i]==l.StagenPar.ClassReal[j]) {
	    tlen=ARRAYSIZE(FloatHi,l.specfilter[j-1]);
	    tlenrel=l.specfilter[j-1];
	    fpi=GetLocalClassVectorIndir(j);
	    fp=GetLocalClassVector(j);
#if PRNT_INITPT
printf("%i --> %i d=%2i slen=%2i tlen=%2i sDimG=%i lDimG=%i. ",
i,j,d,slen,tlen,s.ClassDimG[i-1],l.ClassDimG[j-1]
);
#endif
	    if (!s.ClassDimG[i-1] && !l.ClassDimG[j-1]) {
	      if (d==0 && fp) {
		ReadAndSkip(fp,(size_t)tlen,(size_t)slen);
		match=TRUE;
#if PRNT_INITPT
printf(" 0-0 read %09p(%i)\n",fp,slen);
#endif
	      }
	      continue;	/* there may be another field with the same class */
	    }
	    if (!s.ClassDimG[i-1] && l.ClassDimG[j-1]) {
	      if (d==0) {
		if (fpi) {			/* a field with Dim==-2 */
		  _MemFree(*fpi);
		  *(int *)(fpi+1)=dim*tlen;	/* the next field is len */
		  *fpi=_MemGet(dim*tlen,FALSE);
		  ReadAndSkip(*fpi,(size_t)tlen,(size_t)slen);
#if PRNT_INITPT
printf(" 0-1 read %09p(%i)\n",*fpi,slen);
#endif
		  match=TRUE;
		}
	      } else {
		if (fpi) {
		  MemCpy(*fpi+d*tlenrel,*fpi,tlen);
#if PRNT_INITPT
printf(" 0-1 move %09p(%i)\n",*fpi+d*tlenrel,slen);
#endif
		  match=TRUE;
		}
	      }
	      continue;	/* there may be another field with the same class */
	    }
	    if (s.ClassDimG[i-1] && !l.ClassDimG[j-1]) {
	      if (d==0) {
		ReadAndSkip(fp,(size_t)tlen,(size_t)slen);
#if PRNT_INITPT
printf(" 1-0 read %09p(%i)\n",fp,slen);
#endif
		match=TRUE;
	      }
	      continue;	/* there may be another field with the same class */
	    }
	    if (s.ClassDimG[i-1] && l.ClassDimG[j-1]) {
	      if (d==0) {
		if (fpi) {			/* a field with Dim==-2 */
		  _MemFree(*fpi);
		  *(int *)(fpi+1)=dim*tlen;	/* the next field is len */
		  *fpi=_MemGet(dim*tlen,FALSE);
		  ReadAndSkip(*fpi,(size_t)tlen,(size_t)slen);
#if PRNT_INITPT
printf(" 1-1 read %09p(%i)\n",*fpi,slen);
#endif
		  match=TRUE;
		}
	      } else {
		if (fpi) {
		  ReadAndSkip(*fpi+d*tlenrel,(size_t)tlen,(size_t)slen);
#if PRNT_INITPT
printf(" 1-1 read %09p(%i)\n",*fpi+d*tlenrel,slen);
#endif
		  match=TRUE;
		}
	      }
	      continue;	/* there may be another field with the same class */
	    }
	  }
	if (!match)
	  if (d==0 || s.ClassDimG[i-1]) {
	    ReadAndSkip(NULL,(size_t)0,(size_t)slen);
#if PRNT_INITPT
printf(" *-* skip %i\n",slen);
#endif
	  }
#if PRNT_INITPT
else printf("\n");
#endif
      }
#else	/* MPS */
    if (l.DimGMore1) {
      fp=GetLocalClassVector(GetClassId("SPECCL_DIM"));
      if (fp) *(int*)fp=(int)dim;
      for (d=0; d<dim; d++)
	for (i=1; i<=s.NumOfRelevantClasses; i++)
	  for  (j=1; j<=l.NumOfRelevantClasses; j++)
	    if (s.StagenPar.ClassReal[i]==l.StagenPar.ClassReal[j]) {
	      fpi=GetLocalClassVectorIndir(j);
	      if (d)
		if (s.ClassDimG[i-1]==FALSE) {
		  if (fpi)
		    MemCpy(*fpi+d*s.specfilter[i-1],*fpi,
				ARRAYSIZE(FloatHi,s.specfilter[i-1]));
		  break;
		} else
		  if (!fpi) {
		    DataLibSkip(&DiagramLib,
				ARRAYSIZE(FloatHi,s.specfilter[i-1]));
		    break;
		  }
	      if (fpi) {		/* a field with Dim==-2 */
		if (!d) {
		  _MemFree(*fpi);
		  len=ARRAYSIZE(FloatHi,dim*s.specfilter[i-1]);
		  *(int *)(fpi+1)=len;	/* the next field is len */
		  *fpi=_MemGet(len,FALSE);
		}		
		DataLibRead(&DiagramLib,(CharPtr)(*fpi+d*s.specfilter[i-1]),
			    ARRAYSIZE(FloatHi,s.specfilter[i-1]));
	      } else {
		fp=GetLocalClassVector(j);
		if (fp)
		  DataLibRead(&DiagramLib,(CharPtr)fp,
			      ARRAYSIZE(FloatHi,s.specfilter[i-1]));
		else
		  DataLibSkip(&DiagramLib,
			      ARRAYSIZE(FloatHi,s.specfilter[i-1]));
	      }
	      break;
	    }
    } else
      for (i=1; i<=s.NumOfRelevantClasses; i++)
	for  (j=1; j<=l.NumOfRelevantClasses; j++)
	  if (s.StagenPar.ClassReal[i]==l.StagenPar.ClassReal[j]) {
	    fp=GetLocalClassVector(j);
	    if (fp)
	      DataLibRead(&DiagramLib,(CharPtr)fp,
			  ARRAYSIZE(FloatHi,s.specfilter[i-1]));
	    else
	      DataLibSkip(&DiagramLib,
			  ARRAYSIZE(FloatHi,s.specfilter[i-1]));
	    break;
	  }
#endif	/* MPS */
    /* Special processing for user special point */
    if (pointtype&USERPOINT) {
      CharPtr audf;
      Uint4 mask;
      Int2 i,j;
      audf=(CharPtr)GetLocalClassVector(GetClassId("SPECCL_AUS"));
      if (audf) {
	mask=pointtype&~USERPOINT;
	MemFill(audf,UDF_IGNORE,UserFuncNum);
	for (i=0; mask; i++, mask>>=1)
	  if (mask&1) {
	    j=UserFuncLookup(s.UdfTable[i]);
	    if (j>=0) {
	      audf[j]=UDF_APPEND;
	    } else {	/* udf is either disabled or deleted */
	      myWarning("UF_NO");
	    }
	  }
      }
    }
    UpdateAllParams();
  }
  if (pointNum>=0) {
    DestroyDataArea(sta_desc,-1,FALSE);
    DestroyDataArea(gen_desc,-2,FALSE);
    /* Swap and unload psudo-loaded */
    SwapGen(' ');
    FreeUdfTable();
    UnloadGen(FALSE);
    /* Swap again to bring loaded gen to l. */
    SwapGen(' ');
  } else {
    if (same) {
      RestoreGen();
    } else {
      SwapGen(' ');
      UnloadGen(TRUE);
      SwapGen(' ');
    }
  }
  /* Refresh all menu items */
  RefreshMenus();
  NotifyAboutNewInitPoint();
  PopContext();
}

/******************/
/* I. From a list */

typedef struct {
  FilePtr DirPtr;		/* curve's partition */
  DataLibPosPtr SPList;		/* a list of special points */
  Int2 SPNum;			/* number of special points */
} CurveDesc, PNTR CurveDescPtr;

Local(Int2) CurveNum;
Local(CurveDescPtr) CurvePtr;

Local(WindoW) CurveParent;

Local(GrouP) InitGroup;

Local(Int2) InitLastType[2];	/* Type of last time loaded cureve */
Local(FilePtr) InitSelected;	/* Save DiagramLib.SelectedDirPtr */

Local(void) InitUnloadGen(void) {
  Int2 i;
  if (InitLastType[0]+InitLastType[1]) {
    for (i=1; i<=l.NumOfRelevantClasses; i++)
      _MemFree(l.StagenPar.IndirectValues[i]);
    UnloadGen(FALSE);
    InitLastType[0]=InitLastType[1]=0;
  }
}

Local(void) InitFree(ButtoN b) {
  Int2 i;
  WindoW win=ParentWindow(b);
  for (i=0; i<CurveNum; i++) {
    FreeSPList(CurvePtr[i].SPNum,CurvePtr[i].SPList);
  }
  Select(CurveParent);
  _MemFree(CurvePtr);
  WriteWindowPos("W_POINT",win);
  Remove(win);
  UnlockAll();
  PopContext();
/***  VisualizerSpecial(VSA_ERASE);***/
}

Local(void) InitCancelProc(ButtoN b) {
  VisualizerSpecial(VSA_ERASE);
  Hide(ParentWindow(b));
  InitUnloadGen();
  RestoreGen();
  ClassRestoreIndirect();
  if (InitSelected) {
    DiagramLib.SelectedDirPtr=InitSelected;
    ActivateCurve();
  }
  InitFree(b);
}

/*
   Returns curve's ptr and number of special point.
   For curves *num is set to -1.
*/
Local(void) InitGetPoint(Int2Ptr curve, Int2Ptr num) {
  Int2 i,i1,j,j1,n;
  *curve=-1;
  *num=-1;
  n=GetValue(list);
  if (!n) return;
  for (i=i1=0, j=j1=1; n>j1; i1++) {
    i=i1;
    j=j1;
    j1+=CurvePtr[i1].SPNum+1;	/* +1 is for Curve name */
  }
  if (n<j1) {
    *curve=i;
    *num=n-j-1;
  } else *curve=i1;	/* line number i1 contains a curve name! */
}


Local(void) InitOkProc(ButtoN b) {
  Int2 cn;
  Int2 num;
  InitGetPoint(&cn,&num);
  if (cn<0 || num<0) return;	/* no active line or curve */
  VisualizerSpecial(VSA_ERASE);
  Hide(ParentWindow(b));
  InitUnloadGen();
  RestoreGen();
  ClassRestoreIndirect();
  SetInitPoint(CurvePtr[cn].DirPtr,num);
  InitFree(b);
}

/*-------------*/
/* Redraw Menu */

Local(void) InitProc(LisT list);

Local(void) InitRedraw(Int2 index);

Local(MenuItem) InitMenuItems[]={
  {REDRAW_M,	NULL,		NULL},
  {REDRAWALL_I,	InitRedraw,	InitRedraw_Status},
  {REDRAWHI_I,	InitRedraw,	InitRedraw_Status},
  {SEPARATOR_I,	NULL,		NULL},
  {REDRAWCL_I,	clearAllWindows,CreateWindow_Status}
};

Local(MenuDesc) InitMenu={InitMenuItems,DIM(InitMenuItems)};

Local(void) InitRedraw(Int2 index) {
  Int2 cn,num;
  VisualizerSpecial(VSA_ERASE);
  InitGetPoint(&cn,&num);
  if (cn<0) return;
  InitUnloadGen();
  RestoreGen();
  ClassRestoreIndirect();
  if (InitMenuItems[index].Title==REDRAWALL_I) { /* redraw all */
    RedrawDiagram(0);
  } else {		/* redraw highlighted */
    DiagramLib.CurDirPtr=CurvePtr[cn].DirPtr;
    RedrawCurveProc(0);
  }
  ClassSaveIndirect();
  HideGen();
  if (num>=0) {
    Unlock(&InitMenu);
    InitProc(list);	/* mark point again */
  }
}

Local(Boolean) InitRedraw_Status(Int2 index) {
  Boolean r=FALSE;
  switch (InitMenuItems[index].Title) {
    case REDRAWALL_I:	/* redraw all */
      r=list && CountItems(list)>0;
      break;
    case REDRAWHI_I:	/* redraw highlighted */
      r=list && GetValue(list)>0;
      break;
  }
  return r;
}

Local(void) clearAllWindows(Int2 index) {
  VisualizerSpecial(VSA_ERASE);
  ClearAllWindows(index);
}

Local(void) InitMenuCallback(IteM item) {
  Disable(InitGroup);
  Lock(&InitMenu);
  DoMenuAction(&InitMenu,item);
  Unlock(&InitMenu);
  Enable(InitGroup);
}

Local(void) InitKeys(Char c) {
  Int2 index;
  if (c=='r' || c=='R') {
    for (index=0; index<DIM(InitMenuItems); index++)
      if (InitMenuItems[index].Title==REDRAWHI_I) {
	InitRedraw(index);
	break;
      }
  }
}

/* Redraw Menu */
/*-------------*/

/* List callback */
Local(void) InitProc(LisT list) {
  Int2 i;
  Int2 cn;
  Int2 num;
  Int2 type[2];
  Pointtype pointtype;
  FloatHiPtr fp;
  if (Locked(&InitMenu)) return;
  SetStatusOfItems(&InitMenu);
  VisualizerSpecial(VSA_ERASE);
  if (dblClick) {
    InitOkProc((ButtoN)list);
    goto exit;
  }
  InitGetPoint(&cn,&num);
  if (cn<0 || num<0) goto exit;	/* no active line or curve */
  DiagramLib.SelectedDirPtr=CurvePtr[cn].DirPtr;
  DataLibSeekDir(&DiagramLib,DiagramLib.SelectedDirPtr);
  DataLibRead(&DiagramLib,(CharPtr)type,sizeof(type));
  if (InitLastType[0]!=type[0] || InitLastType[1]!=type[1]) {
    InitUnloadGen();
    l.InitPointType=FindNodeByType(type[0]);
    l.CurveType=FindNodeByType(type[1]);
    FindName();
    l.call=!LoadGen(FALSE);
    SkipParameters(&DiagramLib);	/* starter's */
    SkipParameters(&DiagramLib);	/* generator's */
    l.coordfilter=_MemNew(ARRAYSIZE(PairPtr,l.NumOfRelevantClasses));
    l.specfilter=_MemNew(ARRAYSIZE(Int2,l.NumOfRelevantClasses));
    ReadFilter(&DiagramLib);
    for (i=1; i<=l.NumOfRelevantClasses; i++)
      l.StagenPar.IndirectValues[i]=(FloatHiPtr)_MemNew(ARRAYSIZE(FloatHi,l.specfilter[i-1]));
    InitLastType[0]=type[0];
    InitLastType[1]=type[1];
  }
  if (l.DimGMore1) goto exit;
  DataLibSeek(&DiagramLib,CurvePtr[cn].SPList+num);
  DataLibRead(&DiagramLib,(CharPtr)&pointtype,sizeof(pointtype)); /* point type */
  DataLibSkipVRecord(&DiagramLib);	/* Message */
  DataLibSkipVRecord(&DiagramLib);	/* Bif data */
  for (i=1; i<=l.NumOfRelevantClasses; i++) {
    fp=l.StagenPar.IndirectValues[i];
    if (fp)
      DataLibRead(&DiagramLib,(CharPtr)fp,
		  ARRAYSIZE(FloatHi,l.specfilter[i-1]));
    else
      DataLibSkip(&DiagramLib,
		  ARRAYSIZE(FloatHi,l.specfilter[i-1]));
  }
  VisualizerSpecial(VSA_DRAW);
/**********
printf("Point:\n");
for (i=1; i<=l.NumOfRelevantClasses; i++) {
  Int2 j;
  CharPtr name;
  printf("%i: dim=%i, relevant(%i)=%i\n",i,l.specfilter[i-1],i-1,GetNthRelevantClass(i-1));
  for (j=0; j<l.specfilter[i-1]; j++) {
    GetNameAndDim(GetNthRelevantClass(i-1),j+1,&name,NULL);
    printf(" %s=%g",name,l.StagenPar.IndirectValues[i][j]);
  }
  printf("\n");
}
**********/
 exit:;
  DiagramLib.SelectedDirPtr=0;
}

#define PREFIX "                "

/* DataLibEnum callback adds one curve and its special points */
Local(Int2) CurvePoints(DataLibPtr dl) {
  CharPtr msg;
  Int2 i,type[2],num;
  Pointtype ptype;
  ClassSaveIndirect();
  if (CurveNum)
    CurvePtr=_MemMore(CurvePtr,ARRAYSIZE(CurveDesc,CurveNum+1));
  else
    CurvePtr=_MemNew(sizeof(CurveDesc));
  DataLibSeekDir(dl,CurvePtr[CurveNum].DirPtr=dl->CurDirPtr);
  ListItem(list,dl->DirName);
  num=CountItems(list);
/***
  s=l;
  MemFill(&l,0,sizeof(l));
***/
  HideGen();
  DataLibRead(&DiagramLib,(CharPtr)type,sizeof(type));
  l.InitPointType=FindNodeByType(type[0]);
  l.CurveType=FindNodeByType(type[1]);
  FindName();
  LoadGen(FALSE);	/* GetSPname needs this */
  /* For user points GetSPname needs l.UdfTable to be filled in from the curve */
  SkipParameters(&DiagramLib);	/* starter's */
  SkipParameters(&DiagramLib);	/* generator's */
  SkipFilter();
  ReadUdfTable();
  /* Now process all special points */
  ReadSPList(&CurvePtr[CurveNum].SPNum,&CurvePtr[CurveNum].SPList);
  for (i=0; i<CurvePtr[CurveNum].SPNum; i++) {
    StrCpy(ParBuf,PREFIX);
    DataLibSeek(dl,CurvePtr[CurveNum].SPList+i);
    DataLibRead(dl,(CharPtr)&ptype,sizeof(ptype));
    StrCat(ParBuf,GetSPname(ptype,FALSE));
    StrCat(ParBuf,": ");
    msg=DataLibReadVRecord(&DiagramLib,NULL);
    StrCat(ParBuf,msg);
    _MemFree(msg);
    ListItem(list,ParBuf);
  }
  FreeUdfTable();
  UnloadGen(FALSE);
/***  l=s;***/
  RestoreGen();
  ClassRestoreIndirect();
  CurveNum++;
  if (dl->SelectedDirPtr==dl->CurDirPtr)
    SetValue(list,num);
  return 0;
}

#if _WIN
#pragma argsused
#endif
Local(void) InitHelpProc(ButtoN b) {
  Help(NULL);
}

#if _WIN
#pragma argsused
#endif
/* Select initial point from the main menu */
Global(void) SelectPointProc(Int2 index) {
  WindoW optwin;
  int width,height;
  PushContext(HLP_INITPOINT,InitKeys,CurveTxt[SELINIT_C]);
  /* Create list */
  CurveParent=CurrentWindow();
  optwin=CreateOptionWindow(IPOINT_W,"W_POINT");
  sscanf(CurveTxt[LIST],"%i %i",&width,&height);
  list=SingleList(optwin,width,height,InitProc);
  /* Fill in it */
  DataLibSavePos(&DiagramLib);
  while (!DataLibUp(&DiagramLib));
  CurveNum=0;
  DataLibEnum(&DiagramLib,CurvePoints,TRUE);
  DataLibRestorePos(&DiagramLib);
  InitGroup=TermButtons(optwin,(GrouP)list,InitOkProc,InitCancelProc,InitHelpProc);
  InitLastType[0]=InitLastType[1]=0;
  InitSelected=DiagramLib.SelectedDirPtr;
  DiagramLib.SelectedDirPtr=0;
  ClassSaveIndirect();
  DeactivateCurve(FALSE);
  InvalidateBifData();	/* before HideGen */
  HideGen();
  VisualizerSpecial(VSA_RESET);
  CreateMenu(optwin,CurveTxt,&InitMenu,InitMenuCallback);
  Show(optwin);
  LockAll();	/* lock second time because otherwise it would be unlocked
		   immediatedly after return */
}


/* Determines status of menu item */
#if _WIN
#pragma argsused
#endif
Global(Boolean) SelectPointProc_Status(Int2 index) {
  return CurDiagram;
}

/*****************************/
/* II. Pointed out by cursor */

Global(Boolean) SetSpecialPoint(FilePtr curvePtr, Int2 pointNum) {
  if (CurDiagram) {
    SetInitPoint(curvePtr,pointNum);
    return TRUE;
  } else return FALSE;
}


/*********************/
/* Pause mode option */
/*********************/

Local(GrouP) gPause;

Local(Uint1) Pmap[3];

Local(ButtoN) bMouse;

Local(WindoW) PauseParent;

Local(void) PauseCancelProc(ButtoN b) {
  Select(PauseParent);
  Remove(ParentWindow(b));
  UnlockAll();
  PopContext();
}

Local(void) PauseOkProc(ButtoN b) {
  Int2 n;
  Uint1 i;
  for (n=GetValue(gPause), i=0; i<DIM(Pmap); i++)
    if (n==Pmap[i]) {
      Miscdata.Suspend=i;
      break;
    }
  ParBuf[1]='\0';
  ParBuf[0]="01"[GetStatus(bMouse)];
  SetParam(SFS_CURVES,"MOUSE",ParBuf);
  if (ParBuf[0]=='0')
    pauseWin=Remove(pauseWin);
  pauseNo=FALSE;
  PauseCancelProc(b);
}

#if _WIN
#pragma argsused
#endif
Local(void) PauseHelpProc(ButtoN b) {
  Help(NULL);
}

#if _WIN
#pragma argsused
#endif
Global(void) PauseOptProc(Int2 index) {
  WindoW optwin;
  GrouP g,gKey;
  PrompT tKeys[4];
  CharPtr p;
  PoinT pt;
  int pos;
  Int2 i,ip;
  LockAll();	/* lock second time because otherwise it would be unlocked
		   immediatedly after return */
  PauseParent=CurrentWindow();
  optwin=CreateOptionWindow(PAUSE_W,NULL);
  g=HiddenGroup(optwin,0,5,NULL);
  SetGroupMargins(g,0,0);
  SetGroupSpacing(g,0,sysLineHeight2);
  gPause=NormalGroup(g,2,0,CurveTxt[PAUSE_T],SystemFont,NULL);
  SetGroupMargins(gPause,sysCharWidth,sysLineHeight2);
  SetGroupSpacing(gPause,sysCharWidth,sysLineHeight2);
  /* If the order has to be changed agree it with Pmap values */
  RadioButton(gPause,CurveTxt[PAUSES_B]);
    Pmap[SUSPEND_SPECIAL]=1;
  RadioButton(gPause,CurveTxt[PAUSEE_B]);
    Pmap[SUSPEND_EACH]=2;
  RadioButton(gPause,CurveTxt[PAUSEN_B]);
    Pmap[SUSPEND_NEVER]=3;
  SetValue(gPause,Pmap[Miscdata.Suspend]);
  /* Show keyboard's key assignments */
  gKey=NormalGroup(g,4,0,CurveTxt[PAUSEKEY_T],SystemFont,NULL);
  SetGroupMargins(gKey,sysCharWidth,sysLineHeight2);
  SetGroupSpacing(gKey,sysCharWidth,sysLineHeight2);
  for (i=0; i<4; i++) {
    switch (i) {
      case 0: ip=SUSPEND_B; break;
      case 1: ip=ABORT_B; break;
      case 2: ip=RESUME_B; break;
      case 3: ip=TAKE_B; break;
    }
    StrCpy(ParBuf,CurveTxt[ip]);
    StrCat(ParBuf,":");
    StaticPrompt(gKey,ParBuf,0,0,NULL,'l');
    GetNextPosition(gKey,&pt);
    pt.x-=3*(sysCharWidth4);
    SetNextPosition(gKey,pt);
    tKeys[i]=StaticPrompt(gKey,"",stdCharWidth<<2,0,NULL,'l');
  }
  GetParam(SFS_CURVES,"KEYS");
  for (i=0, p=ParBuf; i<4; p+=pos+1,i++) {
    pos=0;
    sscanf(p,"%*s%n",&pos);
    if (pos) p[pos]='\0';
    SetTitle(tKeys[i],p);
  }
  bMouse=CheckBox(g,CurveTxt[MOUSE_B],NULL);
  GetParam(SFS_CURVES,"MOUSE");
  SetStatus(bMouse,*ParBuf=='1');
  PushContext(HLP_PAUSEOPT,NULL,CurveTxt[PAUSEOPT_C]);
  /* Terminate buttons */
  TermButtons(optwin,g,PauseOkProc,PauseCancelProc,PauseHelpProc);
  Show(optwin);
}

#if _WIN
#pragma argsused
#endif
Global(Boolean) PauseOptProc_Status(Int2 index) {
  return FunctionsHandle!=NULL;		/* functions are selected */
}


/********/
/* Misc */
/********/

Global(Uint1) ClassGlobToLoc(Int2 RealId) {
  Uint1 i;
  /* 
     IMPORTANT: this function may be called (implicitly)
     DUGING LoadGen, e.g. during building data area
     to compute %LCode(class) function, see LoadGen() and
     param.c. Therefore l.call may be FALSE but
     l.StagenPar.ClassReal!=NULL.
     Table of local visible classes preceeds &data
     section in all .con files.
  */
  if (l.StagenPar.ClassReal)
    for (i=1; i<=l.NumOfRelevantClasses; i++)
      if (l.StagenPar.ClassReal[i]==RealId) return i;
  return RealId>200 ? RealId : 0;
}

Global(Int2) GetLocalClasses(Uint2Ptr PNTR readIds) {
  if (l.call) {
    *readIds=l.StagenPar.ClassReal;
    return l.NumOfRelevantClasses;
  } else return 0;
}


/*****************/
/* Export/Import */
/*****************/

Global(void) ExportDefStaGen(DataLibPtr dgm, FILE PNTR out) {
  Int2 type[2];
  DataLibRead(dgm,(CharPtr)type,sizeof(l.InitPointType->Type)+sizeof(l.CurveType->Type));
  fprintf(out,"   defstagen=%i,%i\n",(int)type[0],(int)type[1]);
}

Global(void) ImportDefStaGen(DataLibPtr dgm, FILE PNTR in) {
  int ip,ic;
  Int2 type[2];
  fscanf(in,"   defstagen=%i,%i\n",&ip,&ic);
  type[0]=(Int2)ip;
  type[1]=(Int2)ic;
  DataLibWrite(dgm,(CharPtr)type,sizeof(l.InitPointType->Type)+sizeof(l.CurveType->Type));
}

Local(void) ReadAndPrintFilter(DataLibPtr dgm, FILE PNTR out) {
  PairPtr pp;
  ArchFilter filter;
  Int2 i,j,k,n;
  DescRewind();
  FindLine(SECPRF"names");
  n=CountLines();
  DataLibRead(dgm,(CharPtr)&filter,sizeof(filter));
  fprintf(out,"   from=%i,%i to=%i,%i step=%i,%i\n",
		filter.fFrom[0],filter.fFrom[1],
		filter.fTo[0],filter.fTo[1],
		filter.fStep[0],filter.fStep[1]);
  fprintf(out,"   n=%i\n",(int)n);
  for (i=0; i<n; i++) {
    pp=(PairPtr)DataLibReadVRecord(dgm,NULL);
    k=DataLibLastVRecLen/sizeof(Pair);
    fprintf(out,"   relclass=%i: %i",(int)i,(int)k);
    for (j=0; j<k; j++)
      fprintf(out," [%i,%i]",(int)pp[j].from,(int)pp[j].num);
    fprintf(out,"\n");
    _MemFree(pp);
  }
  fprintf(out,"   spec=");
  for (i=0; i<n; i++) {
    DataLibRead(dgm,(CharPtr)&k,ARRAYSIZE(Int2,1));
    fprintf(out," %i",(int)k);
  }
  fprintf(out,"\n");
}

Global(void) ExportFilter(DataLibPtr dgm, CharPtr DescFile, FILE PNTR out) {
  OpenDescFile(DescFile);
  ReadAndPrintFilter(dgm,out);
  DescClose();
}

Global(void) ImportFilter(DataLibPtr dgm, CharPtr DescFile, FILE PNTR in) {
  PairPtr pp;
  ArchFilter filter;
  int k,n,f0,f1,t0,t1,s0,s1;
  int i,j;
  Int2 s,ntrue;
  Char bl[BL];
  OpenDescFile(DescFile);
  FindLine(SECPRF"names");
  ntrue=CountLines();
  fscanf(in,"   from=%i,%i to=%i,%i step=%i,%i\n",&f0,&f1,&t0,&t1,&s0,&s1);
  filter.fFrom[0]=(Int2)f0; filter.fFrom[1]=(Int2)f1;
  filter.fTo[0]=(Int2)t0; filter.fTo[1]=(Int2)t1;
  filter.fStep[0]=(Int2)s0; filter.fStep[1]=(Int2)s1;
  DataLibWrite(dgm,(CharPtr)&filter,sizeof(filter));
  fscanf(in,"   n=%i\n",&n);
  for (i=0; i<n; i++) {
    fscanf(in,"   relclass=%*i: %i",&k);
    pp=k ? _MemNew(ARRAYSIZE(Pair,k)) : NULL;
    for (j=0; j<k; j++) {
      fscanf(in," [%i,%i]",&f0,&f1);
      pp[j].from=(Int2)f0; pp[j].num=(Int2)f1;
    }
    DataLibWriteVRecord(dgm,NULL,(CharPtr)pp,ARRAYSIZE(Pair,k));
    _MemFree(pp);
  }
  for (; i<ntrue; i++) {
    DataLibWriteVRecord(dgm,NULL,NULL,ARRAYSIZE(Pair,0));
  }
  fscanf(in,"   spec=");
  for (i=0; i<n; i++) {
    GetLine(bl);	/* skip, get from exported file */
    fscanf(in," %i",&k);
    s=(Int2)k;
    DataLibWrite(dgm,(CharPtr)&s,ARRAYSIZE(Int2,1));
  }
  for (; i<ntrue; i++) {
    GetLine(bl);	/* name of visible class added after the system had been exported */
    if (bl[StrLen(bl)-1]=='-') bl[StrLen(bl)-1]='\0';
    s=(Int2)*GetClassDim(bl);
    DataLibWrite(dgm,(CharPtr)&s,ARRAYSIZE(Int2,1));
  }
  fscanf(in,"\n");
  DescClose();
}

Local(void) exportCurve(DataLibPtr dgm, FILE PNTR out) {
  Pointtype pointtype;
  CharPtr msg;
  FloatHiPtr fp,wp;
  PairPtr pp;
  Pair sp;
  TermData td;
  int i,j,k,n,spcnt;
  Int2 method[4];
  sp.from=0;
  spcnt=0;
  for (i=j=0; i<l.NumOfRelevantClasses; i++)
    if (j<l.specfilter[i]) j=l.specfilter[i];
  fprintf(out,"   cl=%i %i\n",(int)l.NumOfRelevantClasses,j);
  wp=_MemNew(ARRAYSIZE(FloatHi,j));
  while (DataLibRead(dgm,(CharPtr)&pointtype,sizeof(pointtype))==sizeof(pointtype)) {
    fprintf(out,"   p %x\n",(unsigned int)pointtype);
    if (pointtype) {
      msg=DataLibReadVRecord(dgm,NULL);
      fprintf(out,"   msg=%s\n",msg);
      _MemFree(msg);
      fp=(FloatHiPtr)DataLibReadVRecord(dgm,NULL);	/* Bifurcation data */
      n=(int)(DataLibLastVRecLen/sizeof(FloatHi));
      fprintf(out,"   bif=%i",n);
      for (i=0; i<n; i++) {
	if (i && i%5==0) fprintf(out,"\n        ");
	fprintfFloatHi(out,fp[i]);
      }
      fprintf(out,"\n");
      _MemFree(fp);
      spcnt++;
    }
    if (l.DimGMore1)
      DataLibRead(dgm,(CharPtr)&ccd.curveDimG,sizeof(ccd.curveDimG));
    else ccd.curveDimG=1;
    fprintf(out,"   %i\n",(int)ccd.curveDimG);
    /* Loop through M-points */
    for (curveCurNum=1; curveCurNum<=ccd.curveDimG; curveCurNum++) {
      /* Read M-point according to the curve's filter (ignore it for special points) */
      for (i=0; i<l.NumOfRelevantClasses; i++) {
	if (l.ClassDimG[i]==FALSE && curveCurNum>1) {
	  fprintf(out,"   0:\n");
	  continue;
	}
	pp=pointtype ? (sp.num=-l.specfilter[i],&sp) : l.coordfilter[i];
	j=0;
	if (pp)
	  do {
	    n=pp[j].num;
	    fprintf(out,"   %i:",n);
	    if (n<0) n=-n;
	    DataLibRead(dgm,(CharPtr)wp,ARRAYSIZE(FloatHi,n));
	    for (k=0; k<n; k++) {
	      if (k && k%5==0) fprintf(out,"\n    ");
	      fprintfFloatHi(out,wp[k]);
	    }
	    fprintf(out,"\n");
	  } while (pp[j++].num>0);
	else fprintf(out,"   0:\n");
      }
    }
  }
  fprintf(out,"   -\n");
  _MemFree(wp);
  /* Visual attributes */
  DataLibDown(dgm);
  if (DataLibFind(dgm,VA_PART)==0) spcnt++; else spcnt=0;
  fprintf(out,"   a=%i\n",spcnt);
  for (i=0; i<spcnt; i++) ExportVisualAttr(dgm,out);
  /* Last point data (used for expanding the curve) */
  if (DataLibFind(dgm,LP_PART)==0) {
    fprintf(out,"   t=1\n");
    DataLibRead(dgm,(CharPtr)&td,sizeof(td));
    /* we don't export three DataLibPos fields;
       they contain position-dependent pointers
       which will be calculated by when importing the curve.
    */
    fprintf(out,"    %i %i\n",(int)td.gnum,(int)td.forward);
    for (j=0; j<2; j++) {	/* starter's and generator's 'extension' data */
      fp=(FloatHiPtr)DataLibReadVRecord(dgm,NULL);
      n=(int)(DataLibLastVRecLen/sizeof(FloatHi));
      fprintf(out,"    %i:",n);
      for (i=0; i<n; i++) {
	if (i && i%5==0) fprintf(out,"\n    ");
	fprintfFloatHi(out,fp[i]);
      }
      fprintf(out,"\n");
      _MemFree(fp);
    }
  } else fprintf(out,"   t=0\n");
  /* Bif data of the initial point */
  if (DataLibFind(dgm,BD_PART)==0) {
    fp=(FloatHiPtr)DataLibReadVRecord(dgm,NULL);
    n=(int)(DataLibLastVRecLen/sizeof(FloatHi));
    fprintf(out,"   b=%i",n);
    for (i=0; i<n; i++) {
      if (i && i%5==0) fprintf(out,"\n     ");
      fprintfFloatHi(out,fp[i]);
    }
    fprintf(out,"\n");
    _MemFree(fp);
  } else fprintf(out,"   b=0\n");
  /* Methods of starter and generator */
  /* Pack slave sta/gen methods for compatability reason */
  if (DataLibFind(dgm,IC_PART)==0) {
    DataLibRead(dgm,(CharPtr)method,sizeof(method));
    fprintf(out,"   m=%i,%i\n",(int)method[0]+256*method[2],(int)method[1]+256*method[3]);
  } else {
    for (i=0; i<DIM(method); i++) method[i]=0;
    fprintf(out,"   m=-1,-1\n");
  }
  /* Parameters of Slave stagen */
  if (DataLibFind(dgm,SLVPAR_PART)==0) {
    Char b[BL];
    fprintf(out,"   slvpar=1\n");
    OpenDescFileAndFindSection(l.Slave->DescFile,SECPRF"data%s");
    for (i=2; i<4; i++) {		/* starter+generator */
      mGetLine(b,method[i]);	/* the name of header file */
      fprintf(out,"   p %s\n",b);
      ExportParams(dgm,b,out,FALSE);
    }
    DescClose();
  } else {
    fprintf(out,"   slvpar=0\n");
  }
  DataLibUp(dgm);
}

Global(void) ExportCurve(DataLibPtr dgm, FILE PNTR out, Int2 outlevel) {
  CharPtr descfile;
  Uint4Ptr up;
  int n;
  Int2 i,type[2];
  Int2 method[4];
  Char b[BL];
  DataLibPos fpos;
  Boolean saveb;
  sprintf(ParBuf,"%s '%s'...",CurveTxt[EXPORTING_C],dgm->DirName+1);
  PushContext(NULL,NULL,ParBuf);
  SwapGen('l');
  /* Types of init point and curve */
  DataLibRead(dgm,(CharPtr)type,sizeof(type));
  fprintf(out,"   types=%i,%i\n",(int)type[0],(int)type[1]);
  DataLibSeekDir(dgm,dgm->CurDirPtr);	/* rewind */
  /* Parameters of starter and generator (master) */
  /* -- first get methods */
  DataLibDown(dgm);
  if (DataLibFind(dgm,IC_PART)==0)
    DataLibRead(dgm,(CharPtr)method,sizeof(method));
  else method[0]=method[1]=0;
  DataLibUp(dgm);
  descfile=FindAndOpenDescFile(dgm,SECPRF"data%s");
  for (i=0; i<2; i++) {		/* starter+generator */
    mGetLine(b,method[i]);	/* the name of header file */
    fprintf(out,"   p %s\n",b);
    ExportParams(dgm,b,out,FALSE);
  }
  DescClose();
  l.DescFile=descfile;
  LoadGen(FALSE);
  /* Archives filter */
  DataLibTell(dgm,&fpos);
  /* 
     Note: descfile does not contain point type.
     Anyway, the text is ignored by ImportCurve
  */
  fprintf(out,"   f %s\n",descfile);
  ExportFilter(dgm,descfile,out);
  DataLibSeek(dgm,&fpos);
  l.coordfilter=_MemNew(ARRAYSIZE(PairPtr,l.NumOfRelevantClasses));
  l.specfilter=_MemNew(ARRAYSIZE(Int2,l.NumOfRelevantClasses));
  ReadFilter(dgm);
  /* Udf table */
  up=(Uint4Ptr)DataLibReadVRecord(dgm,NULL);
  n=(int)(DataLibLastVRecLen/sizeof(Uint4));
  fprintf(out,"   u=%i",n);
  for (i=0; i<n; i++) fprintf(out," %lu",(unsigned long)up[i]);
  fprintf(out,"\n");
  _MemFree(up);
  /* Curve itself */
  if (outlevel==3) exportCurve(dgm,out);
  /* Restore */
  saveb=CurDiagram; CurDiagram=FALSE;
  WriteFilter(FALSE);
  CurDiagram=saveb;
  UnloadGen(FALSE);
  SwapGen('s');
  PopContext();
}

Local(void) importCurve(DataLibPtr dgm, FILE PNTR in) {
  FloatHiPtr fp,wp;
  DataLibPosPtr splist;
  DataLibPos spcur;
  TermData td;
  int i,j,k,n,nrc,spcnt;
  unsigned int pt;
  Pointtype pointtype;
  fscanf(in,"   cl=%i %i\n",&nrc,&j);
  wp=_MemNew(ARRAYSIZE(FloatHi,j));
  spcnt=0;
  splist=NULL;
  while (fscanf(in,"   p %x\n",&pt)==1) {
    pointtype=(Pointtype)pt;
/***
    DataLibTell(dgm,pointtype ? &spcur : &td.LastOPcoord);
***/
    DataLibTell(dgm,&spcur); td.LastOPcoord=spcur;
    DataLibWrite(dgm,(CharPtr)&pointtype,sizeof(Pointtype));
    if (pointtype) {
      fscanf(in,"   msg=%[^\n]\n",ParBuf);
      DataLibWriteVRecord(dgm,NULL,ParBuf,StrLen(ParBuf)+1);
      fscanf(in,"   bif=%i",&n);
      fp=(FloatHiPtr)_MemNew(ARRAYSIZE(FloatHi,n));
      for (i=0; i<n; i++) fscanf(in," %lg",fp+i);
      fscanf(in,"\n");
      DataLibWriteVRecord(dgm,NULL,(CharPtr)fp,ARRAYSIZE(FloatHi,n));
      _MemFree(fp);
      if (spcnt) splist=_MemMore(splist,ARRAYSIZE(DataLibPos,spcnt+1));
      else splist=_MemNew(ARRAYSIZE(DataLibPos,1));
      splist[spcnt++]=spcur;
    }
    fscanf(in,"   %i\n",&n);
    ccd.curveDimG=(Int2)n;
    if (n>1)
      DataLibWrite(dgm,(CharPtr)&ccd.curveDimG,sizeof(ccd.curveDimG));
    /* Loop through M-points */
    for (curveCurNum=1; curveCurNum<=ccd.curveDimG; curveCurNum++)
      for (i=0; i<nrc; i++)
	do {
	  fscanf(in,"   %i:",&n);
	  j=n;
	  if (n<0) n=-n;
	  for (k=0; k<n; k++) fscanf(in," %lg",wp+k);
	  fscanf(in,"\n");
	  DataLibWrite(dgm,(CharPtr)wp,ARRAYSIZE(FloatHi,n));
	} while (j>0);
  }
  fscanf(in,"%*c\n");	/* skip terminating - */
  _MemFree(wp);
  /* Four special subpartions: */
  DataLibDown(dgm);
  /* 1. FilePtrs to special points */
  DataLibCreate(dgm,SP_PART);
  if (spcnt) {
    DataLibWrite(dgm,(CharPtr)splist,ARRAYSIZE(DataLibPos,spcnt-1));
    DataLibTell(dgm,&td.LastOPsp);
    DataLibWrite(dgm,(CharPtr)(splist+spcnt-1),ARRAYSIZE(DataLibPos,1));
  }
  _MemFree(splist);
  /* 2. Visual attributes */
  fscanf(in,"   a=%i\n",&spcnt);
  if (spcnt) DataLibCreate(dgm,VA_PART);
  for (i=0; i<spcnt; i++) {
    DataLibTell(dgm,&td.LastOPva);
    ImportVisualAttr(dgm,in);
  }
  /* 3. Last point data */
  fscanf(in,"   t=%i\n",&n);
  if (n==1) {
    DataLibCreate(dgm,LP_PART);
    fscanf(in,"    %i %i\n",&i,&j);
    td.gnum=(Int2)i;
    td.forward=(Boolean)j;
    DataLibWrite(dgm,(CharPtr)&td,sizeof(td));
    for (j=0; j<2; j++) {	/* starter's and generator's 'extension' data */
      fscanf(in,"    %i:",&n);
      fp=(FloatHiPtr)_MemNew(ARRAYSIZE(FloatHi,n));
      for (i=0; i<n; i++) {
	fscanf(in," %lg",fp+i);
      }
      fscanf(in,"\n");
      DataLibWriteVRecord(dgm,NULL,(CharPtr)fp,ARRAYSIZE(FloatHi,n));
      _MemFree(fp);
    }
  }
  /* 4. Bif data of the initial point */
  fscanf(in,"   b=%i\n",&n);
  if (n) {
    DataLibCreate(dgm,BD_PART);
    fp=(FloatHiPtr)_MemNew(ARRAYSIZE(FloatHi,n));
    for (i=0; i<n; i++) fscanf(in," %lg",fp+i);
    fscanf(in,"\n");
    DataLibWriteVRecord(dgm,NULL,(CharPtr)fp,ARRAYSIZE(FloatHi,n));
    _MemFree(fp);
  }
  /* 5. Methods of starter and generator */
  /*    Unpack slave stagen methods */
  fscanf(in,"   m=%i,%i",&i,&j);
  if (i>=0) {
    Int2 method[4];
    method[0]=(Int2)(i%256);
    method[1]=(Int2)(j%256);
    method[2]=(Int2)(i/256);
    method[3]=(Int2)(j/256);
    DataLibCreate(dgm,IC_PART);
    DataLibWrite(dgm,(CharPtr)method,sizeof(method));
  }
  /* 6. Parameters of Slave stagen */
  {{/* previous versions don't have slvpar=... line */
    long fp=ftell(in);
    int rc=
  fscanf(in,"   slvpar=%i\n",&i);
    if (rc!=1) {i=0; fseek(in,fp,SEEK_SET);}
  }}
  if (i>0) {
    Char b[BL];
    DataLibCreate(dgm,SLVPAR_PART);
    for (i=0; i<2; i++) {		/* starter+generator */
      fscanf(in,"   p %[^\n]\n",b);	/* the name of header file and defined name (if any) */
      ImportParams(dgm,b,in,FALSE);
    }
  }
  fscanf(in,"\n");
  DataLibUp(dgm);
}

Global(void) ImportCurve(DataLibPtr dgm, FILE PNTR in, Int2 outlevel) {
  Uint4Ptr up;
  unsigned long ul;
  CharPtr p;
  size_t l;
  int n,it,ct;
  Int2 i,type[2];
  Char b[BL];
  sprintf(ParBuf,"%s '%s'...",CurveTxt[IMPORTING_C],dgm->DirName+1);
  PushContext(NULL,NULL,ParBuf);
  /* Types of init point and curve */
  fscanf(in,"   types=%i,%i\n",&it,&ct);
  type[0]=(Int2)it;
  type[1]=(Int2)ct;
  DataLibWrite(dgm,(CharPtr)type,sizeof(type));
  /* Parameters of starter and generator */
  for (i=0; i<2; i++) {		/* starter+generator */
    fscanf(in,"   p %[^\n]\n",b);	/* the name of header file and defined name (if any) */
    p=StrChr(b,'|');
    if (p) {
      *p='\0';
      StrTrim(b);
    }
    ImportParams(dgm,b,in,FALSE);
  }
  /* Archives filter */
  fscanf(in,"   f %s\n",b);
  ImportFilter(dgm,b,in);
  /* Udf table */
  fscanf(in,"   u=%i",&n);
  l=ARRAYSIZE(Uint4,n);
  up=(Uint4Ptr)_MemNew(l);
  for (i=0; i<n; i++) {
    fscanf(in," %lu",&ul);
    up[i]=(Uint4)ul;
  }
  fscanf(in,"\n");
  DataLibWriteVRecord(dgm,NULL,(CharPtr)up,l);
  _MemFree(up);
  /* Curve itself */
  if (outlevel==3) importCurve(dgm,in);
  PopContext();
}
