/* Management of all the values the user may change (included functional parameters) */ #include "common.h" #include "datalib.h" #include "visual.h" #include "diagram.h" #include "function.h" #include "file.h" #include "help.h" #include "curve.h" #include "param.h" #define DEB_UC 0&DEB /* print using conunt as they changing */ #if DEB_UC #define DEB_UC_A ,int DEB_UC_line #define DEB_UC_P ,(int)__LINE__ #else /* DEB_UC */ #define DEB_UC_A #define DEB_UC_P #endif /* DEB_UC */ #ifdef WIN32 #define IMPLMENU 1 /* Implement method selection via standard menu */ #else #define IMPLMENU 1 #endif extern Global(CharPtr PNTR) ParamTxt; /* defined in text.c */ enum { /* see setup.c, init[], /param */ EDITWINDOW, /* 38 20 ! textwidth textheight */ CONTEXT_C, /* Compiling, please wait... */ EDIT_C, /* Editing functional parameter...*/ EDIT_T, /* Edit... */ METHOD_I /* Method */ } ParamTxtIndex; #define _INT4 0 /* Int4 cannot be used in starter/generator data */ #define _FLOATLO 0 /* FloatLo cannot be used in starter/generator data */ #define _INVERTSWITCH 0 /* Don't invert selected item in switches */ #define COMPUTE_PARAMS 1 /* Call ComputeExpr to compute parameters values */ #if DEB_PAR static FILE * pardeb=NULL; #endif Local(LibHandle) hFuncParLib=0; /* Handle of functional parameters library */ Local(Int2) screenX,screenY; /****************************************/ /* I Compute the value of an expression */ /****************************************/ #define CE_TOKEN 1 /* token expected: number, (, or id */ #define CE_MORE 2 /* exceed characters are ignored */ #define CE_LB 3 /* ( is expected */ #define CE_RB 4 /* ) is expected */ #define CE_FUN 5 /* unknown function */ #define CE_ZERODIV 6 /* zerodivide */ #define CE_LOG 7 /* log(<=0) */ #define CE_SQRT 8 /* sqrt(<0) */ Local(Int2) c_i; /* index to source text */ typedef enum { C_ERR=1, C_EOF, C_NUM, C_ID, C_LB, /* ( */ C_RB, /* ) */ C_PL, /* + */ C_MI, /* - */ C_MU, /* * */ C_DI, /* / */ C_EX, /* ^ */ C_OR, /* || */ C_AND, /* && */ C_NOT, /* ! */ C_LT, /* < */ C_LE, /* <= */ C_GT, /* > */ C_GE, /* >= */ C_EQ, /* == */ C_NE, /* != */ C_XXX /* dummy */ } c_token; Local(c_token) c_t; /* current token */ Local(FloatHi) c_n; /* current number */ Local(Char) c_id[33]; /* current id */ Local(CharPtr) c_DelimChars="()+-*/^"; Local(c_token) c_DelimTokens[]={C_LB,C_RB,C_PL,C_MI,C_MU,C_DI,C_EX}; #define DIM_PRE '%' /* %class is substituted by the dimension of a class */ Local(CharPtr) c_s; /* ptr to source text */ #if COMPUTE_PARAMS Local(Boolean) CompIsExpr; #endif /* COMPUTE_PARAMS */ Local(void) C_Scan(void) { int pos; CharPtr p; Char c; #if COMPUTE_PARAMS Boolean firstchar=c_i==0; #endif /* COMPUTE_PARAMS */ for (; c_s[c_i]==' '; c_i++); /* skip leading blanks */ c=c_s[c_i]; if (!c) { /* EOF? */ c_t=C_EOF; return; } p=StrChr(c_DelimChars,c); if (p) { /* A delimiter? */ c_t=c_DelimTokens[(Int2)(p-c_DelimChars)]; c_i++; #if COMPUTE_PARAMS if (!(firstchar && c=='-')) CompIsExpr=TRUE; #endif /* COMPUTE_PARAMS */ return; } if (IS_DIGIT(c) || c=='.') { /* A number? */ pos=1; /* if c=='.' sscanf may terminate before assigning to pos */ sscanf(c_s+c_i,"%lg%n",&c_n,&pos); c_i+=pos; c_t=C_NUM; return; } if (IS_ALPHA(c)) { sscanf(c_s+c_i,"%32[a-zA-Z0-9]",c_id); c_i+=StrLen(c_id); c_t=C_ID; #if COMPUTE_PARAMS CompIsExpr=TRUE; #endif /* COMPUTE_PARAMS */ return; } if (c==DIM_PRE) { /* %vizual_class or %spec_func(...) */ c_i++; /* skip % */ sscanf(c_s+c_i,"%32[a-zA-Z0-9]",c_id); c_i+=StrLen(c_id); c_t=C_NUM; #if COMPUTE_PARAMS CompIsExpr=TRUE; #endif /* COMPUTE_PARAMS */ if (c_s[c_i]=='(' ) { /* %func(...) */ Boolean lcode; if (!StrCmp(c_id,"CodeT")) { /* %CodeT(x) - code of curve type (x=c) or init point (x=p) */ sscanf(c_s+c_i,"(%c)",c_id); c_i+=3; c_n=GetTypeId(c_id[0]=='p' ? 0 : 1); return; } lcode=StrCmp(c_id,"LCode")==0; if (lcode || !StrCmp(c_id,"Code")) { /* %Code(id) - global code of visual class id */ /* %LCode(id) - local code of visual class id */ sscanf(c_s+c_i,"(%32[a-zA-Z0-9_])",c_id); c_i+=StrLen(c_id)+2; /* +2 is for () */ c_n=GetClassId(c_id); if (lcode) c_n=ClassGlobToLoc((Int2)c_n); return; } } /* %id - dimension of a visual class id */ c_n=*GetClassDim(c_id); return; } if (c=='=' && c_s[c_i+1]=='=') { c_i+=2; c_t=C_EQ; #if COMPUTE_PARAMS CompIsExpr=TRUE; #endif /* COMPUTE_PARAMS */ return; } if (c=='|' && c_s[c_i+1]=='|') { c_i+=2; c_t=C_OR; #if COMPUTE_PARAMS CompIsExpr=TRUE; #endif /* COMPUTE_PARAMS */ return; } if (c=='&' && c_s[c_i+1]=='&') { c_i+=2; c_t=C_AND; #if COMPUTE_PARAMS CompIsExpr=TRUE; #endif /* COMPUTE_PARAMS */ return; } if (c=='!') { if (c_s[c_i+1]=='=') { c_i+=2; c_t=C_NE; } else { c_i++; c_t=C_NOT; } #if COMPUTE_PARAMS CompIsExpr=TRUE; #endif /* COMPUTE_PARAMS */ return; } if (c=='<') { if (c_s[c_i+1]=='=') { c_i+=2; c_t=C_LE; } else { c_i++; c_t=C_LT; } #if COMPUTE_PARAMS CompIsExpr=TRUE; #endif /* COMPUTE_PARAMS */ return; } if (c=='>') { if (c_s[c_i+1]=='=') { c_i+=2; c_t=C_GE; } else { c_i++; c_t=C_GT; } #if COMPUTE_PARAMS CompIsExpr=TRUE; #endif /* COMPUTE_PARAMS */ return; } c_t=C_ERR; /* Unknown token */ } Local(Int2) C_Expr(FloatHiPtr res); Local(CharPtr) stdfun[]={ "abs", "acos", "asin", "atan", "ceil", "cos", "exp", "floor", "log", "log10", "sin", "sqrt", "tan", NULL }; Local(Int2) C_Atom(FloatHiPtr res) { Int2 err,i; if (c_t==C_NUM) { /* number */ *res=c_n; C_Scan(); return 0; } if (c_t==C_LB) { /* (Expr) */ C_Scan(); err=C_Expr(res); if (err) return err; if (c_t==C_RB) { C_Scan(); return 0; } else return CE_RB; } if (c_t==C_ID) { /* function call */ C_Scan(); for (i=0; stdfun[i]; i++) if (!StrCmp(c_id,stdfun[i])) break; if (!stdfun[i]) return CE_FUN; if (c_t!=C_LB) return CE_LB; err=C_Expr(res); if (err) return err; switch (i) { case 0: /* abs */ *res=fabs(*res); break; case 1: /* acos */ *res=acos(*res); break; case 2: /* asin */ *res=asin(*res); break; case 3: /* atan */ *res=atan(*res); break; case 4: /* ceil */ *res=ceil(*res); break; case 5: /* cos */ *res=cos(*res); break; case 6: /* exp */ *res=exp(*res); break; case 7: /* floor */ *res=floor(*res); break; case 8: /* log */ if (*res>0) { *res=log(*res); break; } else return CE_LOG; case 9: /* log10 */ if (*res>0) { *res=log10(*res); break; } else return CE_LOG; case 10: /* sin */ *res=sin(*res); break; case 11: /* sqrt */ if (*res>=0) { *res=sqrt(*res); break; } else return CE_LOG; case 12: /* tan */ *res=tan(*res); break; } return 0; } return CE_TOKEN; } Local(Int2) C_Factor(FloatHiPtr res) { FloatHi res2; Int2 err; err=C_Atom(res); if (err) return err; if (c_t==C_EX) { C_Scan(); err=C_Atom(&res2); if (err) return err; *res=pow(*res,res2); } return 0; } Local(Int2) C_Term(FloatHiPtr res) { FloatHi res2; Int2 err; Boolean mult; err=C_Factor(res); if (err) return err; while ((mult=c_t==C_MU)!=0 || c_t==C_DI) { C_Scan(); err=C_Factor(&res2); if (err) return err; if (mult) *res*=res2; else if (res2==0) return CE_ZERODIV; else *res/=res2; } return 0; } Local(Int2) C_Expr(FloatHiPtr res) { FloatHi res2; Int2 err; Boolean minus,add; if ((minus=c_t==C_MI)!=0) C_Scan(); /* skip leading minus */ err=C_Term(res); if (err) return err; if (minus) *res=-*res; while ((add=c_t==C_PL)!=0 || c_t==C_MI) { C_Scan(); err=C_Term(&res2); if (err) return err; if (add) *res+=res2; else *res-=res2; } return 0; } Local(Int2) C_BExpr(FloatHiPtr res); Local(Int2) C_BFactor(FloatHiPtr res) { FloatHi res2; c_token rel; Int2 err; switch (c_t) { case C_LB: /* (BExpr) */ C_Scan(); err=C_BExpr(res); if (err) return err; if (c_t==C_RB) C_Scan(); else return CE_RB; break; case C_NOT: /* !BFactor */ C_Scan(); err=C_BFactor(res); if (err) return err; *res=*res ? 0.0 : 1.0; break; default: /* Expr [rel Expr] */ err=C_Expr(res); if (err) return err; rel=c_t; if (rel==C_LT || rel==C_LE || rel==C_GT || rel==C_GE || rel==C_NE || rel==C_EQ) { C_Scan(); err=C_Expr(&res2); if (err) return err; switch (rel) { case C_LT: *res=*res< res2; break; case C_LE: *res=*res<=res2; break; case C_GT: *res=*res> res2; break; case C_GE: *res=*res>=res2; break; case C_NE: *res=*res!=res2; break; case C_EQ: *res=*res==res2; break; } } } return 0; } Local(Int2) C_BTerm(FloatHiPtr res) { FloatHi res2; Int2 err; err=C_BFactor(res); if (err) return err; while (c_t==C_AND) { C_Scan(); err=C_BFactor(&res2); if (err) return err; if (*res) *res=res2; } return 0; } Local(Int2) C_BExpr(FloatHiPtr res) { FloatHi res2; Int2 err; err=C_BTerm(res); if (err) return err; while (c_t==C_OR) { C_Scan(); err=C_BTerm(&res2); if (err) return err; if (!*res) *res=res2; } return 0; } Global(Int2) ComputeExpr(CharPtr source, FloatHiPtr res) { Int2 err; if (!source) return CE_MORE; c_s=source; c_i=0; #if COMPUTE_PARAMS CompIsExpr=FALSE; #endif /* COMPUTE_PARAMS */ C_Scan(); err=C_BExpr(res); return err ? err : (c_t==C_EOF ? 0 : CE_MORE); } /**********************/ /* II Show parameters */ /**********************/ #include "document.h" /*--------------------*/ /* Types related data */ /* DON'T CHANGE THE ORDER in Types, TypesLen, TypesAlignment, and TypeCode. Only APPEND new items at THE BOTTOM. */ /* Names */ Local(Char) *Types[]={ "char", "int", #if _INT4 "long", #endif #if _FLOATLO "float", #endif "double", "void*", "char*", "int*", #if _INT4 "long*", #endif #if _FLOATLO "float*", #endif "double*", "FuncPar", NULL }; /* Sizes */ Local(Char) TypesLen[]={ sizeof(char), sizeof(int), #if _INT4 sizeof(long), #endif #if _FLOATLO sizeof(float), #endif sizeof(double), sizeof(void*), sizeof(char*), sizeof(int*), #if _INT4 sizeof(long*), #endif #if _FLOATLO sizeof(float*), #endif sizeof(double*), sizeof(FuncParStruct(void,())) }; /* Alignments */ Local(Char) TypesAlignment[DIM(TypesLen)]={ sizeof(struct {char d; char c;})-sizeof(char), sizeof(struct {char d; int i2;})-sizeof(int), #if _INT4 sizeof(struct {char d; long i4;})-sizeof(long), #endif #if _FLOATLO sizeof(struct {char d; float fl;})-sizeof(float), #endif sizeof(struct {char d; double fh;})-sizeof(double), sizeof(struct {char d; void* vp;})-sizeof(void*), sizeof(struct {char d; char* vp;})-sizeof(char*), sizeof(struct {char d; int* vp;})-sizeof(int*), #if _INT4 sizeof(struct {char d; long* vp;})-sizeof(long*), #endif #if _FLOATLO sizeof(struct {char d; float* vp;})-sizeof(float*), #endif sizeof(struct {char d; double* vp;})-sizeof(double*), sizeof(struct {char d; FuncParStruct(void,()) fpd;})-sizeof(FuncParStruct(void,())) }; /* Internal coding */ typedef enum { CHAR, INTLO, #if _INT4 INTHI, #endif #if _FLOATLO FLOATLO, #endif FLOATHI, VOIDPTR, CHARPTR, INTLOPTR, #if _INT4 INTHIPTR, #endif #if _FLOATLO FLOATLOPTR, #endif FLOATHIPTR, FUNCDESC } TypeCode; /* Notify function (see curve.c) */ Global(void) (*ParamChangeNotify)(void)=NULL; Local(Boolean) IsPointer(TypeCode type) { return VOIDPTR<=type && type<=FLOATHIPTR; } Local(TypeCode) Dereference(TypeCode type) { return (TypeCode)(IsPointer(type) ? type-CHARPTR : type); /* CHARPTR, not VOIDPTR!!! */ } typedef enum { TITLE, /* Title, not changeable */ NUMBER, /* FloatHi value */ NUMBERM, /* FloatHi value that can be additionally selected or deselected */ NUMBERO, /* FloatHi value, not editable */ SWITCH, /* One from a visible list */ SWITCHA, /* One visible from a list */ FUNCTION /* Functional parameter */ } ParamKind; /* Parameter kind */ /* Descriptor of a field (regardless of its visibility) */ typedef struct { Uint2 Offset; /* Offset of the field in data area */ Int2 Dim; /* dimension for arrays and pointers, 1 othervise */ TypeCode Type; /* Type of the field */ Uint1 LocalClass; /* !=0 - a) notify, b) select point puts here */ } FieldDesc, PNTR FieldDescPtr; typedef struct { Int2 SelFieldIndex; /* index of field desc for active/deactive attr */ #if COMPUTE_PARAMS Boolean Expr; /* TRUE if an expression, FALSE if a single number */ Boolean Error; /* after last computation of an expression */ #endif /* COMPUTE_PARAMS */ } NumberDesc; typedef struct { Int2 AltNum; /* number of items in the list */ } SwitchDesc; typedef FuncParStruct(void,()) FuncParStructure, PNTR FuncParStructurePtr; typedef EntryPtr(void,FuncParPtr,()); typedef struct { CharPtr Header; } FuncDesc; /* Descriptor of a single visible value */ typedef struct { CharPtr ExtName; /* external, i.e. visible to the user, name */ Int2 FieldIndex; /* index of field descriptor */ Int2 Index; /* index for arrays and pointers */ ParamKind Kind; /* Kind of the parameter */ union { NumberDesc Number; FuncDesc Function; SwitchDesc Switch; } Specific; } VisibleDesc, PNTR VisibleDescPtr; /* Descriptor of a single invisible value */ typedef struct { CharPtr ExtName; /* external name; used by ParamDataMerge */ Int2 FieldIndex; /* index of field descriptor */ Int2 Index; /* index for arrays and pointers */ } InvisibleDesc, PNTR InvisibleDescPtr; /*------------------------------*/ /* ParameterPanel attached data */ typedef struct { #if IMPLMENU ChoicE Choice; #else PaneL pCurrent; /* with current name */ LisT lList; /* of possible names */ #endif Int2 oldWidth,oldHeight; Int2 Dx,Dy; } ImplElem; typedef struct { /* The following fields must be set before ParameterPanel call */ FieldDescPtr Fields; /* array of fields descriptors */ VisibleDescPtr Visibles; /* array of descriptiors of visible values */ CharPtr PNTR Texts; /* text representations of visible values */ InvisibleDescPtr Invisibles; /* array of descriptiors of invisible values */ CharPtr Data; /* data area where the values of fields are */ CharPtr DynData; /* data area where pointers point to */ Int2 FieldsNum; /* DIM(*Fields) */ Int2 VisiblesNum; /* DIM(*Visibles) */ Int2 InvisiblesNum; /* DIM(*Invisibles) */ Int2 DataLen; /* size of *Data */ Int2 DynDataLen; /* size of *DynData */ Int2 Lines; /* number of visible lines in Doc */ /* The following fields are set by ParameterPanel for its own needs */ Int2 winnum; CharPtr DescFile; /* name of data area description file */ CharPtr Partition; /* DiagramLib's partition with the values of parameters */ DoC Doc; /* DoC object */ TexT Input; ImplElem Impl; /* Methods stuff */ #if IMPLMENU #else Boolean ImplHideList; #endif ColPtr Cols; /* ptr to array of column structures */ Int2 CurItem; /* number of active item */ Int2 Dx,Dy; Boolean Flags; } ParamData, PNTR ParamDataPtr; /* Flags bits */ #define PP_FIRSTRESIZE 1 /* Set by ParameterPanel and remains set until first exit form WinResizeProc */ #define PP_HIDDEN 2 /* Current item has not input focus */ /* DIM MUST be >=5: 0: dummy, 1-2: sta/gen, 3-4: slave sta/gen */ Local(ParamDataPtr) ParamDataPtrs[]={ NULL,NULL,NULL,NULL,NULL }; typedef struct { DoC doc; TexT input; ImplElem Impl; } ImplSaveElem; Local(ImplSaveElem) ImplSave[DIM(ParamDataPtrs)]; #if IMPLMENU #else Local(void) ImplHideListAndUpdate(ParamDataPtr pd) { RecT r; if (pd->ImplHideList) { pd->ImplHideList=FALSE; Hide(pd->Impl.lList); Select(pd->Impl.pCurrent); GetPosition(pd->Impl.pCurrent,&r); InvalRect(&r); Update(); } } #endif Local(ParamDataPtr) AllocateData(CharPtr DescFile); #if CACHEPAR Local(Boolean) DoCache=FALSE; Local(void) FreeData(ParamDataPtr pd, Boolean freeall); #else Local(void) FreeData(ParamDataPtr pd); #endif Local(void) IncreaseUseCounts(ParamDataPtr pd, DataLibPtr DiagramLib DEB_UC_A); Local(void) DecreaseUseCounts(ParamDataPtr pd, Boolean zero, DataLibPtr DiagramLib DEB_UC_A); /*------*/ /* Misc */ ParData parFmt={FALSE,FALSE,FALSE,FALSE,FALSE,0,0}; ColData defcolFmt={0,0,0,0,NULL,'l',FALSE,FALSE,FALSE,FALSE,FALSE}; #define L_COL_INSET (sysCharWidth2) /* left inset val for values */ #define R_COL_INSET (0) /* right inset val for values */ #define EDIT_TEXT ParamTxt[EDIT_T] Local(Int2Ptr) ImplCode; Local(Int2Ptr) ImplMax; Local(CharPtr PNTR) ImplNames[DIM(ParamDataPtrs)-1]; /*-----------------------------*/ /* Access to parameters values */ Local(Int2) LastFieldIndex; Local(TypeCode) LastFieldType; /* Obtains address of parameter's value */ Local(VoidPtr) GetValuePtr(ParamDataPtr pd, Int2 item) { CharPtr vp; Boolean sel_desel; sel_desel=item<0; /* TRUE if not value, but associated sel/desel value is needed */ item=ABS(item); /* DoC numbers items from 1 and 0th item is window's title */ LastFieldIndex=sel_desel ? pd->Visibles[item].Specific.Number.SelFieldIndex : pd->Visibles[item].FieldIndex; LastFieldType=pd->Fields[LastFieldIndex].Type; vp=pd->Data + pd->Fields[LastFieldIndex].Offset; if (IsPointer(LastFieldType)) { LastFieldType=Dereference(LastFieldType); /* points to what */ vp=*(CharPtr PNTR)vp; } vp+=pd->Visibles[item].Index*TypesLen[LastFieldType]; return vp; } /*----------------------------------------*/ /* Hide/Restore/Swap and Merge parameters */ #if DEB_PAR Local(void) PrintParamData(CharPtr title,ParamDataPtr pd); #endif Local(ParamDataPtr) saveParamDataPtrs[DIM(ParamDataPtrs)]; /* Hide/Restore/Swap ParamDataPtrs */ Global(void) ParamDataHRS(ParamDataOper oper, Int2 from) { ParamDataPtr p; Int2 i; for (i=1+from; iVisiblesNum; is++) { kind=s->Visibles[is].Kind; switch (kind) { case NUMBER: case NUMBERM: case SWITCH: case SWITCHA: case FUNCTION: ns=s->Visibles[is].ExtName; fis=s->Visibles[is].FieldIndex; type=s->Fields[fis].Type; for (it=1; itVisiblesNum; it++) if ( !StrCmp(ns,t->Visibles[it].ExtName) && type==t->Fields[t->Visibles[it].FieldIndex].Type) { pt=GetValuePtr(t,it); ps=GetValuePtr(s,is); if (kind==FUNCTION) { /* !!! This may be inappropriate for FuncPar other then SetInitPoint !!! */ if (FuncClear) ((FuncParStructurePtr)pt)->_Selected=FALSE; /* DON'T merge functional parameters at all */ break; /* Usage counts: target and source DecreaseUseCounts(t,FALSE,&DiagramLib DEB_UC_P); IncreaseUseCounts(s,&DiagramLib DEB_UC_P); */ } MemCopy(pt,ps,TypesLen[LastFieldType]); if (kind==NUMBER || kind==NUMBERM) { t->Visibles[it].Specific.Number.Expr=s->Visibles[is].Specific.Number.Expr; t->Visibles[it].Specific.Number.Error=s->Visibles[is].Specific.Number.Error; _MemFree(t->Texts[it]); t->Texts[it]=_StringSave(s->Texts[is]); } break; } } } /* Merge invisible fields */ for (is=0; isInvisiblesNum; is++) { ns=s->Invisibles[is].ExtName; fis=s->Invisibles[is].FieldIndex; type=s->Fields[fis].Type; for (it=0; itInvisiblesNum; it++) if (!StrCmp(ns,t->Invisibles[it].ExtName) && type==t->Fields[fit=t->Invisibles[it].FieldIndex].Type) { pt=t->Data+t->Fields[fit].Offset; ps=s->Data+s->Fields[fis].Offset; if (IsPointer(type)) { type=Dereference(type); /* points to what */ pt=*(CharPtr PNTR)pt; ps=*(CharPtr PNTR)ps; } if (t->Fields[fit].Dim==-2) { /* the source must also have Dim==-2 */ int slen; slen=*(int*)(s->Data+s->Fields[fis+1].Offset); *(CharPtr PNTR)(t->Data+t->Fields[fit].Offset)= pt ? _MemMore(pt,slen) : _MemGet(slen,FALSE); MemMove(*(CharPtr PNTR)(t->Data+t->Fields[fit].Offset), *(CharPtr PNTR)(s->Data+s->Fields[fis].Offset),slen); } else MemCopy(pt,ps,MIN(t->Fields[fit].Dim,s->Fields[fis].Dim)*TypesLen[type]); break; } } } /* Merge parameters with the same visible classes */ Global(void) ParamDataMergeByClass(VoidPtr source, Uint2Ptr sclass, VoidPtr target, Uint2Ptr tclass) { ParamDataPtr s,t; VoidPtr ps,pt; int slen; Int2 is,it,ds,dt; Uint2 cs,ct; TypeCode type; s=(ParamDataPtr)source; t=(ParamDataPtr)target; if (!source || !target) return; for (it=0; itFieldsNum; it++) { ct=t->Fields[it].LocalClass; if (ct) for (is=0; isFieldsNum; is++) { cs=s->Fields[is].LocalClass; if (cs) /* ct>200: specail classes (see class's con file, e.g. ode_g.con) are global */ /* don't merge class 255; it is dummy and used to reset BifDataOk flag only */ if ((ct>200 && ct!=255 && ct==cs) || (ct<=200 && cs<=200 && tclass[ct]==sclass[cs])) { type=t->Fields[it].Type; pt=t->Data+t->Fields[it].Offset; ps=s->Data+s->Fields[is].Offset; if (IsPointer(type)) { type=Dereference(type); /* points to what */ pt=*(CharPtr PNTR)pt; ps=*(CharPtr PNTR)ps; } ds=s->Fields[is].Dim; dt=t->Fields[it].Dim; if (ds==-2 && dt==-2) { slen=*(int*)(s->Data+s->Fields[is+1].Offset); movespec:; _MemFree(pt); *(CharPtr PNTR)(t->Data+t->Fields[it].Offset)=_MemGet(slen,FALSE); *(int*)(t->Data+t->Fields[it+1].Offset)=slen; MemMove(*(CharPtr PNTR)(t->Data+t->Fields[it].Offset),ps,slen); break; } if (ds!=-2 && dt==-2) { slen=ds*TypesLen[type]; goto movespec; } if (ds==-2 && dt!=-2) { slen=*(int*)(s->Data+s->Fields[is+1].Offset); MemCopy(pt,ps,MIN(dt*TypesLen[type],slen)); break; } MemCopy(pt,ps,MIN(dt,ds)*TypesLen[type]); break; } } } } /*------------------------------------------------------*/ /* Routines related to processing functional parameters */ Local(void) ReplaceChars(CharPtr p, Char f, Char t) { for (; p=StrChr(p,f),p; *p++=t); } /* Allocate unique number */ typedef struct { Int2 len; Uint1 byte[1]; } Unique, PNTR UniquePtr; Local(Uint2) AllocateUnique(DataLibPtr DiagramLib) { UniquePtr bits; Int2 i,j; Uint1 b; if (DataLibFind(DiagramLib,UNIQUE_PART)) { bits=_MemNew(sizeof(Unique)); bits->len=1; bits->byte[0]=0xFE; /* bit .... ...1 in byte 0 will be represented as 0, but this means 'no unique number' */ } else { bits=(UniquePtr)DataLibReadVRecord(DiagramLib,UNIQUE_PART); } for (i=0; ilen; i++) if (bits->byte[i]) break; if (i==bits->len) { bits->len++; bits=_MemMore(bits,sizeof(Unique)+i*sizeof(Uint1)); bits->byte[i]=0xFF; } b=bits->byte[i]; for (j=0; b!=1; b>>=1,j++); bits->byte[i]^=(1<len-1)*sizeof(Uint1)); _MemFree(bits); return i*10+j; } /* Free unique number */ Local(void) FreeUnique(short * unique, DataLibPtr DiagramLib) { UniquePtr bits; Int2 i,j; if (*unique) { i=*unique/10; j=*unique%10; bits=(UniquePtr)DataLibReadVRecord(DiagramLib,UNIQUE_PART); if (ilen) { bits->byte[i]|=(1<byte[bits->len-1]==0xFF) { bits->len--; bits=_MemMore(bits,sizeof(Unique)+(bits->len-1)*sizeof(Uint1)); } if (bits->len==1 && bits->byte[0]==0xFE) DataLibDelete(DiagramLib); else DataLibWriteVRecord(DiagramLib,UNIQUE_PART,(CharPtr)bits, sizeof(Unique)+(bits->len-1)*sizeof(Uint1)); } _MemFree(bits); *unique=0; } } /* Invisible char is used to delimit things in C source code for functional parameters. It is substituted by ' ' just prior compilation. Denoted by '$' in comments. */ #define INVCHR '\x01' #define INVSTR "\x01" #define ATTRSTR "\x02" /* represents attributes */ /* Export/Import of reserved unique numbers */ Global(void) ExportUnique(DataLibPtr dgm, FILE PNTR out) { UniquePtr bits; Int2 i; bits=(UniquePtr)DataLibReadVRecord(dgm,NULL); fprintf(out," unique=%i:",(int)bits->len); for (i=0; ilen; i++) fprintf(out," %x",(unsigned)bits->byte[i]); fprintf(out,"\n"); _MemFree(bits); } Global(void) ImportUnique(DataLibPtr dgm, FILE PNTR in) { UniquePtr bits; int l; unsigned int u; Int2 i; fscanf(in," unique=%i:",&l); bits=_MemNew(sizeof(Unique)+(l-1)*sizeof(Uint1)); bits->len=(Int2)l; for (i=0; ibyte[i]=(Uint1)u; } DataLibWriteVRecord(dgm,NULL,(CharPtr)bits, sizeof(Unique)+(bits->len-1)*sizeof(Uint1)); _MemFree(bits); } /* Export/Import the source of functional parameters */ #define INVREP "\n -$$$- \n" #define ATTRREP "\n -###- \n" Global(void) ExportFunPar(DataLibPtr dgm, FILE PNTR out) { CharPtr p; p=DataLibReadVRecord(dgm,NULL); p=StrSubstitute(p,INVSTR,INVREP,FALSE,NULL); p=StrSubstitute(p,ATTRSTR,ATTRREP,FALSE,NULL); fprintf(out,"%s\n"SECPRF" %s\n",p,FUNPAR_PART+1); _MemFree(p); } Global(void) ImportFunPar(DataLibPtr dgm, FILE PNTR in) { CharPtr p; #if _WIN CharPtr q,r; Int2 l; #endif p=ImportCollectLines(in); p[StrLen(p)-1]='\0'; /* get rid of \n appended by ExportFunPar */ #if _WIN p[StrLen(p)-1]='\0'; /* get rid of \r appended by ExportFunPar */ /* Replace \r\n with \n outside function bodies and preserve them in user-typed text */ for (q=p; (r=StrChr(q,'{'),r); q=r) { /* first replace \r\n --> \r\r inside */ r+=3; /* skip "{\r\n", \r must be removed here */ for (l=1; l>0; r++) switch (*r) { case '{': l++; break; case '}': l--; break; case '\r': if (r[1]=='\n') { r[1]='\r'; r++; break; } } } p=StrSubstitute(p,"\r\n","\n",FALSE,NULL); /* kill \r outside */ p=StrSubstitute(p,"\r\r","\r\n",FALSE,NULL); /* replace back inside */ #endif p=StrSubstitute(p,INVREP,INVSTR,FALSE,NULL); p=StrSubstitute(p,ATTRREP,ATTRSTR,FALSE,NULL); DataLibWriteVRecord(dgm,NULL,p,StrLen(p)+1); _MemFree(p); } #undef INVREP #undef ATTRREP /* Builds unique (inside diagram) function name (item!=0) or #include "datafile" directive. */ Local(void) BuildName(CharPtr buf, ParamDataPtr pd, Int2 item, Boolean incldir) { FuncParStructurePtr vp; CharPtr p,q; if (incldir) { p=StrChr(pd->DescFile,' '); if (p) *p='\0'; sprintf(buf,"#include%c\"%s\"",INVCHR,pd->DescFile); if (p) *p=' '; return; } if (item) { vp=(FuncParStructurePtr)GetValuePtr(pd,item); p=pd->Visibles[item].Specific.Function.Header; p=StrChr(p,',')+1; /* p--> begin of name in the header */ q=StrChr(p,','); /* q--> end of name in the header */ sprintf(buf,"%.*s_%u_",(int)(q-p),p,(unsigned int)vp->_Unique); } } /* Fill pointers to functions */ Global(void) ParamFuncPtrs(Boolean clear) { ParamDataPtr pdw; FuncParStructurePtr fp; Char buf[30]; Int2 i,j; if (!hFuncParLib) clear=TRUE; for (i=1; iVisiblesNum; j++) if (pdw->Visibles[j].Kind==FUNCTION) { fp=(FuncParStructurePtr)GetValuePtr(pdw,j); if (clear || !fp->_Unique) fp->_Ptr=NULL; else { BuildName(buf,pdw,j,FALSE); fp->_Ptr=(FuncParPtr)LibraryFuncAddress(hFuncParLib,buf); } } } } } /* Non zero means "don't allow change parameters". It may be during: editing or compilation of func parameters, or computing. */ Local(Int1) ParLock=0; /* Counts chars starting from p up to but not included n-th INVCHR */ Local(Int2) FindEnd(CharPtr p, Int2 n) { CharPtr q; Int2 len; if (n<=0) return 0; len=0; do { q=StrChr(p,INVCHR); if (q) { len+=(Int2)(q-p)+1; p=q+1; } else { return len+(Int2)StrLen(p); } } while (--n); return len-1; } /*----------------------*/ /* Usage counts support */ /* * Usage counts are used to keep track of a source text (and * it's compiled version) of functional parameters (FP). * The following strategy is implemented. * Whenever a copy of (starter's or generator's) data areas * is performed usage counts of target area are decreased * while usage counts of source area are increased. * When data area is destroyed usage counts of it's * functional parameters are decreased. * When both operations (i.e. ++ and --) must be performed * on the same data area at the same time (e.g. data area * is the source and then must be destroied) they are omitted * and an appropriate comment is placed instead * beginning with the words 'Usage counts'). */ #define USECOUNT "00001" #define USECOUNTCOM "/*"USECOUNT"*/" Local(CharPtr) saveptr; Local(Char) savechar; /* Get use count */ Local(Int2) GetUseCount(CharPtr p) { int usecount; do { p+=StrCSpn(p,"/"); /* look for the comment with use count */ if (p[1]=='*') break; } while (*(++p)); sscanf(saveptr=p,"/*%u*/%c",&usecount,&savechar); return usecount; } /* Update use count */ Local(void) UpdateUseCount(Int2 usecount) { #if defined(COMP_GNU) && defined(OS_UNIX_SUN) sprintf(saveptr,"/*%.*i*/",(int)sizeof(USECOUNT)-1,(int)usecount); *(saveptr+StrLen(saveptr))=savechar; #else *(saveptr+sprintf(saveptr,"/*%.*i*/",(int)sizeof(USECOUNT)-1,(int)usecount))=savechar; #endif /* defined(COMP_GNU) && defined(OS_UNIX_SUN) */ } Local(void) IncreaseUseCounts(ParamDataPtr pd, DataLibPtr DiagramLib DEB_UC_A) { FuncParStructurePtr fp; CharPtr q; Char buf[20]; CharPtr Ctext=NULL; Int2 j; for (j=1; jVisiblesNum; j++) if (pd->Visibles[j].Kind==FUNCTION) { fp=(FuncParStructurePtr)GetValuePtr(pd,j); if (fp->_Unique) { BuildName(buf,pd,j,FALSE); if (Ctext==NULL) { DataLibSavePos(DiagramLib); while (!DataLibUp(DiagramLib)); Ctext=DataLibReadVRecord(DiagramLib,FUNPAR_PART); } q=StrStr(Ctext,buf); /* points to function's name */ if (q) { #if DEB_UC int uc; UpdateUseCount((uc=GetUseCount(q))+1); printf("UC+ for %s: %i->%i. Line %i\n",buf,uc,uc+1,DEB_UC_line); } else { printf("UC+ for %s: q=NULL Line %i\n",buf,DEB_UC_line); #else UpdateUseCount(GetUseCount(q)+1); #endif } } } if (Ctext) { DataLibWriteVRecord(DiagramLib,FUNPAR_PART,Ctext,StrLen(Ctext)+1); _MemFree(Ctext); DataLibRestorePos(DiagramLib); } } Local(void) DecreaseUseCounts(ParamDataPtr pd, Boolean zero, DataLibPtr DiagramLib DEB_UC_A) { CharPtr Ctext=NULL; FuncParStructurePtr fp; CharPtr q,r; Char buf[50]; Int2 j,len,usecount; for (j=1; jVisiblesNum; j++) if (pd->Visibles[j].Kind==FUNCTION) { fp=(FuncParStructurePtr)GetValuePtr(pd,j); if (fp->_Unique) { BuildName(buf,pd,j,FALSE); if (Ctext==NULL) { DataLibSavePos(DiagramLib); while (!DataLibUp(DiagramLib)); Ctext=DataLibReadVRecord(DiagramLib,FUNPAR_PART); } q=StrStr(Ctext,buf); /* points to function name, if any */ if (q) { /* name does exist */ usecount=GetUseCount(q); #if DEB_UC printf("UC- for %s: %i->%i. Line %i\n",buf,usecount,usecount-1,DEB_UC_line); #endif if (--usecount) { /* still not zero, don't remove the source */ UpdateUseCount(usecount); } else { /* it is zero now, remove the source */ q=StrChr(q,'\n')+1; /* to 1st char of the body */ len=FindEnd(q,1)-2; /* skip "}\n" */ for (r=q-2; *r!='\n'; r--); len+=q-(r+1)+4; /* 4 is the len of trailing "}\n$\n" */ q=r+1; r=_MemNew(StrLen(Ctext)-len+1); StrNCpy(r,Ctext,(size_t)(q-Ctext)); StrCpy(r+(size_t)(q-Ctext),q+len); _MemFree(Ctext); Ctext=r; FreeUnique(&fp->_Unique,DiagramLib); /* Descrease use count of data struct */ BuildName(buf,pd,0,TRUE); q=StrStr(Ctext,buf); usecount=GetUseCount(q); if (--usecount) { /* still>0 */ UpdateUseCount(usecount); } else { /* zero, remove #include and Co. */ len=FindEnd(q,3)+2; /* 3 INVCHRs: in #incl,#defs,#undefs */ StrCpy(q,q+len); StrTrim(Ctext); /* *Ctext==0 if everything has been erased */ } } } else { FreeUnique(&fp->_Unique,DiagramLib); #if DEB_UC printf("UC- for %s: q=NULL. Line %i\n",buf,DEB_UC_line); #endif } if (zero) { fp->_Unique=0; fp->_Selected=FALSE; UpdateDocument(pd->Doc,j,j); /* it can cope with pd->Doc==NULL */ } } } if (Ctext) { if (*Ctext) DataLibWriteVRecord(DiagramLib,FUNPAR_PART,Ctext,StrLen(Ctext)+1); else { q=DataLibReadVRecord(DiagramLib,LIB_PART); if (*q) { unlink(q); FreeFileName(q); } _MemFree(q); DataLibDeletePartitions(DiagramLib,FUNPAR_PART,LIB_PART,NULL); } _MemFree(Ctext); DataLibRestorePos(DiagramLib); } } /*--------------------------------------*/ /* Compilation of functional parameters */ /* Shows compiler/linker error messages */ Local(void) ShowErrFile(GrouP g) { DoC doc; RecT r; Int2 width; SelectFont(ProgramFont); /* for FileLineMaxWidth */ width=FileLineMaxWidth(ParBuf); if (!width) { GetPosition(g,&r); width=r.right-r.left; } doc=DocumentPanel(g,width,10*LineHeight()); /* ParBuf contains error file name */ DisplayFancy(doc,ParBuf,NULL,NULL,ProgramFont,8); } /* Check compilation errors after recompilation functional parameters library */ Local(Int2) ProcessParsErrors(Boolean error, CharPtr msg, int num) { FILE * source; ParamDataPtr pdw; CharPtr p; Int2 i,j,start; int pos,unique,w; Boolean notfound; Char buf[200]; if (error) { GetParam(SFS_COMPILER,"TARGET"); /* erase lib, if any */ GetParamAppend(SFS_EXTENSIONS,"LIB"); unlink(ParBuf); GetParam(SFS_COMPILER,"SOURCE"); source=FileOpen(GetParamAppend(SFS_EXTENSIONS,"C"),"rt"); /* Find the unique number of an offending function */ for (start=unique=0,i=1; i<=num; i++) { FileGets(buf,sizeof(buf),source); /* Look for unique number (surrounded by underscores) in function's name. We must repeatedly look for it since underscore may occures before _number_ pattern (esp. for Windows, _export keyword preceeds it) */ for (p=buf; (p=StrChr(p,'_'),p); ) { p++; w=pos=0; sscanf(p,"%i_%n",&w,&pos); if (w && pos) { unique=w; start=i; break; } } } FileClose(source); notfound=TRUE; if (unique) { for (i=0; iDoc)); for (j=1; jVisiblesNum; j++) if (pdw->Visibles[j].Kind==FUNCTION && ((FuncParStructurePtr)GetValuePtr(pdw,j))->_Unique==unique) { ((FuncParStructurePtr)GetValuePtr(pdw,j))->_Selected=FALSE; UpdatePar(pdw,j); /* deselect on screen */ myMessageSetUser(ShowErrFile); GetParam(SFS_COMPILER,"LOGFILE"); myWarning("PA_ERRMSG",pdw->Visibles[j].ExtName,(int)(num-start),msg); myMessageSetUser(NULL); notfound=FALSE; break; } } if (notfound) { myMessage(MSG_OK,"%s(%i):\n%s",ParBuf,num,msg); } } else myMessage(MSG_OK,"%s(%i):\n%s",ParBuf,num,msg); } else { /* no errors */ ParamLoadLibs(); /* load library and fill in all functions pointers */ } UnlockAll(); ParLock--; return 0; } Local(ByteStorePtr) defs; Local(ByteStorePtr) undefs; /* Local to GenerateDefsUndefs */ Local(void) OneName(ParamDataPtr pd, CharPtr ExtName, Int2 FieldIndex, Int2 Index) { FieldDescPtr fd; CharPtr p; Int2 i,len; Char trchars[]=" -&"; /* translate to _ */ Char num[20]; Boolean pointer; len=(Int2)StrCSpn(ExtName,"["); /* len of id */ BSWrite(undefs,"#undef ",7); p=StrPBrk(ExtName,trchars) ? _StringSave(ExtName) : ExtName; for (i=0; iFields+FieldIndex; BSWrite(defs,Types[fd->Type],(Int4)StrLen(Types[fd->Type])); BSWrite(defs,"*)((char*)",10); BSWrite(defs,ParBuf,(Int4)StrLen(ParBuf)); sprintf(num,"+%u)",(unsigned int)fd->Offset); BSWrite(defs,num,(Int4)StrLen(num)); pointer=IsPointer(fd->Type); if (pointer) { /* pointer */ sprintf(num,"+%i",(int)Index); BSWrite(defs,num,(Int4)StrLen(num)); } BSPutByte(defs,')'); if (!StrChr(ExtName,'[') && pointer) { BSWrite(defs,"[0]",3); } BSPutByte(defs,'\n'); } Local(void) GenerateDefsUndefs(ParamDataPtr pd) { VisibleDescPtr vd; InvisibleDescPtr id,id1; Int2 i,j; GetParam(SFS_PARAMS,"FUNPAR1"); /* name of form.par */ for (i=1,vd=pd->Visibles+1; iVisiblesNum; i++,vd++) if (vd->Kind!=TITLE && vd->Kind!=FUNCTION) if (!StrChr(vd->ExtName,'[') || StrStr(vd->ExtName,"[0]")) OneName(pd,vd->ExtName,vd->FieldIndex,vd->Index); for (j=0,id=pd->Invisibles; jInvisiblesNum; j++,id++) { /* Skip the name if there is the same visible name */ for (i=1,vd=pd->Visibles+1; iVisiblesNum; i++,vd++) { if (vd->Kind==TITLE || vd->Kind==FUNCTION) continue; if (StrCmp(id->ExtName,vd->ExtName)==0) goto continu; } /* Skip the name if there is the same invisible name */ for (i=j+1,id1=id+1; iInvisiblesNum; i++,id1++) if (StrCmp(id->ExtName,id1->ExtName)==0) goto continu; /* Now put it */ OneName(pd,id->ExtName,id->FieldIndex,id->Index); continu:; } BSPutByte(defs,INVCHR); BSPutByte(defs,'\n'); BSPutByte(undefs,INVCHR); BSPutByte(undefs,'\n'); } /* Prepares for recompilation of functional paramaters library */ Local(void) PrepareToRecompile(Boolean Rebuild) { FILE PNTR source; CharPtr p,q; ParamUnloadLibs(FALSE); /* unload library and invalidate all function pointers */ SetParam(SFS_COMPILER,"SOURCE",GetParam(SFS_FILES,"PAR")); source=FileOpen(GetParamAppend(SFS_EXTENSIONS,"C"),"wt"); p=DataLibReadVRecord(&DiagramLib,FUNPAR_PART); if (Rebuild) { /* Refresh #defines and #undefines for all data structures */ ParamDataPtr pdw; Char buf[100]; CharPtr pd,pu,ps; Int2 usecount,lend,lenu,off,start; start=0; while (TRUE) { sprintf(buf,"#include%c",INVCHR); ps=StrStr(p+start,buf); if (!ps) break; /* all #includes have been processed */ start++; /* next time start from the next char */ sscanf(ps,"#include%*c\"%[^\"]",buf); pdw=AllocateData(buf); BuildName(buf,pdw,0,TRUE); usecount=GetUseCount(ps); /* number of C-functions */ pd=StrChr(ps,'\n')+1; /* to the 1st char of #defines */ lend=FindEnd(pd,1)+2; /* trailing "$\n" */ pu=pd+lend+FindEnd(pd+lend,usecount)+2; lenu=FindEnd(pu,1)+2; defs=BSNew(300); undefs=BSNew(100); GenerateDefsUndefs(pdw); q=_MemNew((size_t)(StrLen(p)-lend-lenu+BSLen(defs)+BSLen(undefs)+1)); StrNCpy(q,p,off=(Int2)(pd-p)); BSMerge(defs,q+off); off+=BSLen(defs); BSFree(defs); StrNCpy(q+off,pd+lend,(Int2)(pu-pd-lend)); off+=(Int2)(pu-pd-lend); BSMerge(undefs,q+off); off+=BSLen(undefs); BSFree(undefs); StrCpy(q+off,pu+lenu); off+=StrLen(pu+lenu); q[off]='\0'; _MemFree(p); p=q; FreeData(pdw,FALSE); /* leave it in the cache */ } /* while */ DataLibWriteVRecord(&DiagramLib,FUNPAR_PART,p,StrLen(p)+1); DataLibFlush(&DiagramLib); } p=CountLinesAndErase_r(p,'\r',NULL); ReplaceChars(p,INVCHR,' '); /* Replace INVCHR by ' ' */ p=StrSubstitute(p,ATTRSTR,GetParam(SFS_COMPILER,"RHSATTR"),TRUE,NULL); /* Generate file to compile */ BuildH(); /* common header */ FilePuts(ParBuf,source); GetParam(SFS_COMPILER,"HEADERPAR"); FilePuts(ParBuf,source); FilePuts(p,source); _MemFree(p); FileClose(source); /* Target library */ p=DataLibReadVRecord(&DiagramLib,LIB_PART); if (*p) { StrCpy(ParBuf,p); } else { AssignFileName(); /* this fills in ParBuf */ GetParamAppend(SFS_EXTENSIONS,"LIB"); DataLibWriteVRecord(&DiagramLib,LIB_PART,ParBuf,StrLen(ParBuf)+1); } _MemFree(p); p=_StringSave(ParBuf); q=StrStr(p,GetParam(SFS_EXTENSIONS,"LIB")); if (q) *q='\0'; SetParam(SFS_COMPILER,"TARGET",p); _MemFree(p); } /* Editor's notify callback */ Local(Int2) EditNotify(CharPtr text) { WindoW win; ParamDataPtr pd; FuncParStructurePtr fp; CharPtr p,q,r; int usecount; Int2 len,textlen,insoff; Char buf[100]; ByteStorePtr bs; Boolean notempty; win=ParentWindow(EditorText()); pd=GetWindowExtra(win); Hide(win); Select(ParentWindow(pd->Doc)); Select(pd->Doc); if (text) { /* OK was pressed */ Remove(win); /* save DiagramLib ptr and goto to the level 0 */ DataLibSavePos(&DiagramLib); while (!DataLibUp(&DiagramLib)); fp=GetValuePtr(pd,pd->CurItem); /* addr of FuncParStructure struct */ if (!fp->_Unique) fp->_Unique=AllocateUnique(&DiagramLib); BuildName(buf,pd,pd->CurItem,FALSE); p=DataLibReadVRecord(&DiagramLib,FUNPAR_PART); StrTrim(text); textlen=(Int2)StrLen(text); notempty=textlen>0; q=StrStr(p,buf); /* point to function name, if any */ if (q) { /* name does exist */ usecount=GetUseCount(q); #if DEB_UC printf("uc- for %s: %i->%i. Line %i\n",buf,usecount,usecount-1,__LINE__); #endif q=StrChr(q,'\n')+1; /* to 1st char of the body */ len=FindEnd(q,1)-2; /* to the last char of the body, skip "}\n" */ if (notempty) { /* decrese use count and replace or duplicate the body */ if (usecount==1) { /* no one else refernce this text, replace it */ r=_MemNew(StrLen(p)-len+textlen+1); StrNCpy(r,p,(size_t)(q-p)); StrCpy(r+(size_t)(q-p),text); StrCat(r,q+len); } else { /* someone else references this text, create private copy */ UpdateUseCount(--usecount); fp->_Unique=AllocateUnique(&DiagramLib); goto first_time; } } else { /* decrease use count and remove function source at all if it is 0 */ if (--usecount) { /* still>0 */ UpdateUseCount(usecount); fp->_Unique=0; r=p; p=NULL; } else { /* zero, remove source */ for (r=q-2; *r!='\n'; r--); len+=q-(r+1)+4; /* 4 is the len of trailing "}\n$\n" */ q=r+1; r=_MemNew(StrLen(p)-len+1); StrNCpy(r,p,(size_t)(q-p)); StrCpy(r+(size_t)(q-p),q+len); FreeUnique(&fp->_Unique,&DiagramLib); /* Now decrease data struct's use count and remove data struct #include and Co. if use count becomes zero. */ BuildName(buf,pd,0,TRUE); q=StrStr(r,buf); usecount=GetUseCount(q); if (--usecount) { /* still>0 */ UpdateUseCount(usecount); } else { /* zero, remove #include and Co. */ len=FindEnd(q,3)+2; /* 3 INVCHRs: in #incl,#defs,#undefs */ StrCpy(q,q+len); StrTrim(r); /* *r==0 if everything has been erased */ } } } } else { /* its 1st time, append function source */ if (notempty) { first_time: /* First of all, look for #include for data struct */ BuildName(buf,pd,0,TRUE); q=StrStr(p,buf); if (q) { /* has been found */ usecount=GetUseCount(q); usecount++; UpdateUseCount(usecount); insoff=(StrChr(StrChr(q,'\n'),INVCHR)+2)-p; } else { /* Create for the first time */ sprintf(buf+StrLen(buf)," "USECOUNTCOM"\n"); /* buf contains #include ...\n */ defs=BSNew(300); undefs=BSNew(100); GenerateDefsUndefs(pd); insoff=(Int2)(StrLen(p)+StrLen(buf)+BSLen(defs)); /*** len=(Int2)(StrLen(buf)+BSLen(defs)+BSLen(undefs));***/ p=_MemMore(p,(size_t)(StrLen(p)+StrLen(buf)+BSLen(defs)+BSLen(undefs)+1)); StrCat(p,buf); len=(Int2)StrLen(p); BSMerge(defs,p+len); len+=BSLen(defs); BSFree(defs); BSMerge(undefs,p+len); len+=BSLen(undefs); BSFree(undefs); p[len]='\0'; } /* Assert: p+insoff is the insert position */ bs=BSNew(100); BuildName(buf,pd,pd->CurItem,FALSE); /* header */ q=pd->Visibles[pd->CurItem].Specific.Function.Header; BSWrite(bs,q,StrChr(q,',')-q); /* type */ BSPutByte(bs,' '); /*** GetParam(SFS_COMPILER,"RHSATTR"); BSWrite(bs,ParBuf,(Int4)StrLen(ParBuf)); ***/ BSWrite(bs,ATTRSTR,StrLen(ATTRSTR)); BSPutByte(bs,' '); BSWrite(bs,buf,(Int4)StrLen(buf));/* real name, i.e. user-defined with unique num appended */ BSWrite(bs,USECOUNTCOM,sizeof(USECOUNTCOM)-1); /* use count */ q=StrChr(q,',')+1; q=StrChr(q,',')+1; /* q--> parameters list */ BSWrite(bs,q,(Int4)StrLen(q)); BSWrite(bs,"{\n",2); /* body */ BSWrite(bs,text,textlen); BSWrite(bs,"}\n"INVSTR"\n",4); /* Get all the text */ r=_MemNew(StrLen(p)+(size_t)BSLen(bs)+1); q=_BSMerge(bs,NULL); StrNCpy(r,p,insoff); StrCpy(r+insoff,q); StrCat(r,p+insoff); _MemFree(q); BSFree(bs); } else { r=p; p=NULL; FreeUnique(&fp->_Unique,&DiagramLib); } } /*** if (!notempty) fp->_Selected=0;***/ fp->_Selected=notempty; _MemFree(p); UpdateDocument(pd->Doc,pd->CurItem,pd->CurItem); /* Save source text */ if (*r) { DataLibWriteVRecord(&DiagramLib,FUNPAR_PART,r,StrLen(r)+1); _MemFree(r); PrepareToRecompile(FALSE); } else { /* all functional parameters have empty texts */ _MemFree(r); ParamUnloadLibs(FALSE); p=DataLibReadVRecord(&DiagramLib,LIB_PART); if (p && *p) { unlink(p); FreeFileName(p); } _MemFree(p); DataLibDeletePartitions(&DiagramLib,FUNPAR_PART,LIB_PART,NULL); notempty=FALSE; /* nothing to compile */ } /* Restore DiagramLib ptr */ DataLibRestorePos(&DiagramLib); /* Flush all data to DiagramLib */ DataLibFlush(&DiagramLib); if (notempty) { /* Compile */ PushContext(0,NULL,ParamTxt[CONTEXT_C]); Compile("MAKERHS",ProcessParsErrors); } else { UnlockAll(); ParLock--; } } else { /* Cancel was pressed */ UnlockAll(); ParLock--; Remove(win); } return 0; /* editor will be terminated */ } /*************/ /* Callbacks */ void HideInput(ParamDataPtr pd); void ShowInput(ParamDataPtr pd); void PanDocProc(DoC Doc); Global(void) ParamLock(Boolean lock) { Int2 i; if (lock) { ParLock++; for (i=0; i0) ParLock--; } void TextProc(TexT t) { ParamDataPtr pd; CharPtr pt; CharPtr pv; #if COMPUTE_PARAMS #else CharPtr legal; #endif WindoW w; size_t len; Int2 pos; Int2 curitem,i; TypeCode type; Char buf[200]; w=ParentWindow(t); pd=(ParamDataPtr)GetWindowExtra(w); curitem=pd->CurItem; sprintf(buf,"%s\t",pd->Visibles[curitem].ExtName); len=(Int2)StrLen(buf); GetTitle(t,pt=buf+len,sizeof(buf)-len); type=pd->Fields[pd->Visibles[curitem].FieldIndex].Type; #if COMPUTE_PARAMS pv=StrChr(pt,' '); if (pv || TextLength(t)>50) { SetTitle(t,pd->Texts[curitem]); pos=(Int2)(pv-pt); SelectText(t,pos,pos); Beep(); return; } #else /* COMPUTE_PARAMS */ switch (type) { case INTLO: case INTLOPTR: #if _INT4 case INTHI: case INTHIPTR: #endif legal="-0123456789"; break; #if _FLOATLO case FLOATLO: case FLOATLOPTR: #endif case FLOATHI: case FLOATHIPTR: legal="-.0123456789eE"; break; } pos=(Int2)StrSpn(pt,legal); if (posTexts[curitem]); SelectText(t,pos,pos); Beep(); return; } #endif /* COMPUTE_PARAMS */ for (i=0; i<2; i++) { pd->Cols[i]=defcolFmt; GetColParams(pd->Doc,curitem,i+1,NULL,&pd->Cols[i].pixWidth,&pd->Cols[i].pixInset,&pd->Cols[i].just); } pd->Cols[1].last=TRUE; ReplaceText(pd->Doc,curitem,buf,&parFmt,pd->Cols,SystemFont); len=TextLength(t)+1; if (len==1) len++; /* treat "" as "0" */ pt=pd->Texts[curitem]=_MemMore(pd->Texts[curitem],len); GetTitle(t,pt,len); if (pt[0]=='\0') StrCpy(pt,"0"); pv=GetValuePtr(pd,curitem); #if COMPUTE_PARAMS { /* begin block */ FloatHi value; if (ComputeExpr(pt,&value)) { value=0.0; pd->Visibles[curitem].Specific.Number.Expr=TRUE; pd->Visibles[curitem].Specific.Number.Error=TRUE; } else { pd->Visibles[curitem].Specific.Number.Expr=CompIsExpr; pd->Visibles[curitem].Specific.Number.Error=FALSE; switch (type) { case INTLO: case INTLOPTR: *(int*)pv=(int)value; break; #if _INT4 case INTHI: case INTHIPTR: *(long*)pv=(long)value; break; #endif #if _FLOATLO case FLOATLO: case FLOATLOPTR: *(float*)pv=(float)value; break; #endif case FLOATHI: case FLOATHIPTR: *(double*)pv=value; break; } } UpdateDocument(pd->Doc,curitem,curitem); } /* end block */ #else /* COMPUTE_PARAMS */ switch (type) { case INTLO: case INTLOPTR: sscanf(pt,"%i",(int*)pv); break; #if _INT4 case INTHI: case INTHIPTR: sscanf(pt,"%li",(long*)pv); break; #endif #if _FLOATLO case FLOATLO: case FLOATLOPTR: sscanf(pt,"%g",(float*)pv); break; #endif case FLOATHI: case FLOATHIPTR: sscanf(pt,"%lg",(double*)pv); break; } #endif /* COMPUTE_PARAMS */ if (pd->Fields[pd->Visibles[curitem].FieldIndex].LocalClass) if (ParamChangeNotify) ParamChangeNotify(); } void TabProc(TexT t) { ParamDataPtr pd; Int2 Lines,delta; if (ParLock) return; pd=(ParamDataPtr)GetWindowExtra(ParentWindow(t)); GetDocParams(pd->Doc,&Lines,NULL); for (delta=1; TRUE; delta++) { if (pd->CurItem+delta>Lines) delta=-pd->CurItem+1; switch (pd->Visibles[pd->CurItem+delta].Kind) { case NUMBER: case NUMBERM: if (!ItemIsVisible(pd->Doc,pd->CurItem+delta,NULL,NULL,NULL)) HideInput(pd); pd->CurItem+=delta; if (!ItemIsVisible(pd->Doc,pd->CurItem,NULL,NULL,NULL)) { BaR bar; bar=GetSlateVScrollBar((SlatE)pd->Doc); SetValue(bar,GetValue(bar)+delta); } PanDocProc(pd->Doc); return; /*** case NUMBERO: case TITLE: case SWITCH: case SWITCHA: case FUNCTION: ***/ default: continue; } } } #define RetProc TabProc void HideInput(ParamDataPtr pd) { Int2 item; if (pd->Flags&PP_HIDDEN) return; /* avoid multiple hiding */ if (pd->CurItem) { switch (pd->Visibles[pd->CurItem].Kind) { case NUMBER: case NUMBERM: Hide(pd->Input); break; case SWITCH: case SWITCHA: item=pd->CurItem; pd->CurItem=0; UpdateDocument(pd->Doc,item,item); pd->CurItem=item; break; } pd->Flags|=PP_HIDDEN; } } void ShowInput(ParamDataPtr pd) { RecT Rect,r; PoinT pt; Int2 pixInset; switch (pd->Visibles[pd->CurItem].Kind) { case NUMBER: case NUMBERM: ItemIsVisible(pd->Doc,pd->CurItem,&pt.y,NULL,NULL); /* Item does visible */ GetColParams(pd->Doc,pd->CurItem,2,&pt.x,NULL,&pixInset,NULL); pt.x++; pt.y++; MapDocPoint(pd->Doc,pt,NULL,NULL,NULL,&Rect); ObjectRect(pd->Doc,&r); /* NOT GetPosition: exclude scroll bar */ Rect.right=r.right #ifdef WIN32 -1 #endif ; UpsetRect(&Rect,L_COL_INSET,0,R_COL_INSET,1); SetPosition(pd->Input,&Rect); SetTitle(pd->Input,pd->Texts[pd->CurItem]); Show(pd->Input); SelectText(pd->Input,10000,10000); break; case SWITCH: case SWITCHA: UpdateDocument(pd->Doc,pd->CurItem,pd->CurItem); break; } pd->Flags&=~PP_HIDDEN; } void ClickDocProc(DoC Doc, PoinT MouseLoc) { ParamDataPtr pd; VoidPtr valptr; CharPtr text,p; Int2 col,oldcur,i; Char buf[100]; if (ParLock) return; pd=(ParamDataPtr)GetWindowExtra(ParentWindow(Doc)); #if IMPLMENU #else ImplHideListAndUpdate(pd); #endif HideInput(pd); /* process previously active */ oldcur=pd->CurItem; MapDocPoint(Doc,MouseLoc,&pd->CurItem,NULL,&col,NULL); /* get currently active */ switch (pd->Visibles[pd->CurItem].Kind) { case NUMBERO: case TITLE: pd->CurItem=oldcur; return; case NUMBERM: if (col==1) { valptr=GetValuePtr(pd,-pd->CurItem); /* addr of sel/desel attrib */ if (*((BoolPtr)valptr)) *((BoolPtr)valptr)=FALSE; else *((BoolPtr)valptr)=TRUE; UpdateDocument(pd->Doc,pd->CurItem,pd->CurItem); if (!oldcur) pd->CurItem=0; return; } break; case NUMBER: if (col<=1) { pd->CurItem=oldcur; return; } break; case SWITCH: if (col<=1) { pd->CurItem=oldcur; return; } valptr=GetValuePtr(pd,pd->CurItem); switch (LastFieldType) { case CHAR: *(CharPtr)valptr=(Char)(col-2); break; case INTLO: *(int*)valptr=(int)(col-2); break; #if _INT4 case INT4: *(long*)valptr=(long)(col-2); break; #endif } break; case SWITCHA: if (col<=1) { pd->CurItem=oldcur; return; } valptr=GetValuePtr(pd,pd->CurItem); switch (LastFieldType) { case CHAR: i=++*(CharPtr)valptr%pd->Visibles[pd->CurItem].Specific.Switch.AltNum; *(CharPtr)valptr=i; break; case INTLO: i=++*(int*)valptr%pd->Visibles[pd->CurItem].Specific.Switch.AltNum; *(int*)valptr=i; break; #if _INT4 case INT4: i=++*(long*)valptr%pd->Visibles[pd->CurItem].Specific.Switch.AltNum; *(long*)valptr=i; break; #endif } for (text=pd->Texts[pd->CurItem]; i; i--) text=StrChr(text,'\t')+1; p=StrChr(text,'\t'); if (p) *p='\0'; sprintf(buf,"%s\t%s",pd->Visibles[pd->CurItem].ExtName,text); if (p) *p='\t'; for (i=0; i<2; i++) { pd->Cols[i]=defcolFmt; GetColParams(pd->Doc,pd->CurItem,i+1,NULL,&pd->Cols[i].pixWidth,&pd->Cols[i].pixInset,&pd->Cols[i].just); } pd->Cols[1].last=TRUE; ReplaceText(pd->Doc,pd->CurItem,buf,&parFmt,pd->Cols,SystemFont); break; case FUNCTION: if (DataLibIsClosed(&DiagramLib)) { /* no open diagram */ myWarning("PA_NODIAG"); return; } valptr=GetValuePtr(pd,pd->CurItem); /* addr of FuncParStructure struct */ if (col==1) { ((FuncParStructure PNTR)valptr)->_Selected^=TRUE; /* reverse */ UpdateDocument(pd->Doc,pd->CurItem,pd->CurItem); if (!oldcur) pd->CurItem=0; } else { /* Edit the body of functional parameters */ WindoW win; GrouP gr; TexT tex; CharPtr p,q; Int2 len; int lenght,height; Char buf[100]; DataLibSavePos(&DiagramLib); while (!DataLibUp(&DiagramLib)); /* goto to the level 0 */ /* Get body's source text, if any */ if (DataLibFind(&DiagramLib,FUNPAR_PART) || !((FuncParStructure PNTR)valptr)->_Unique) { p=text=NULL; } else { p=DataLibReadVRecord(&DiagramLib,FUNPAR_PART); BuildName(buf,pd,pd->CurItem,FALSE); q=StrStr(p,buf); if (q) { q=StrChr(q,'\n')+1; /* to 1st char of the body */ len=FindEnd(q,1)-2; /* skip trailing "}\n" */ text=_MemNew(len+1); StrNCpy(text,q,len); q[len]='\0'; } else text=NULL; } win=FixedWindow(-50,-50,-sysCharWidth,-sysLineHeight,pd->Visibles[pd->CurItem].ExtName,NULL); sscanf(ParamTxt[EDITWINDOW],"%i %i",&lenght,&height); SetWindowExtra(win,pd,NULL); /* for EditNotify callback */ gr=HiddenGroup(win,0,2,NULL); SetGroupMargins(gr,sysCharWidth2,0); q=_StringSave(pd->Visibles[pd->CurItem].Specific.Function.Header); *StrChr(q,',')=' '; /* 1st comma */ *StrChr(q,',')=' '; /* 2nd comma */ StaticPrompt(gr,q,0,0,NULL,'l'); _MemFree(q); PushContext(HLP_FUNCPARAM,NULL,ParamTxt[EDIT_C]); tex=CreateEditor(gr,text,lenght,height,EditNotify,NULL); Show(win); SelectText(tex,0,0); _MemFree(p); _MemFree(text); LockAll(); ParLock++; DataLibRestorePos(&DiagramLib); } return; } ShowInput(pd); } void PanDocProc(DoC Doc) { ParamDataPtr pd; Int2 offset,firstShown; if (ParLock) return; pd=(ParamDataPtr)GetWindowExtra(ParentWindow(Doc)); if (pd->CurItem<=0) return; if (ItemIsVisible(pd->Doc,pd->CurItem,NULL,NULL,NULL)) { switch (pd->Visibles[pd->CurItem].Kind) { case NUMBER: case NUMBERM: HideInput(pd); ShowInput(pd); break; case SWITCH: case SWITCHA: break; } } else { HideInput(pd); GetScrlParams(pd->Doc,&offset,&firstShown,NULL); pd->CurItem=pd->CurItemLines; ShowInput(pd); } } #if _WIN #pragma argsused #endif Boolean GrayDocProc(DoC Doc, Int2 Item, Int2 Row, Int2 Col) { ParamDataPtr pd; VoidPtr valptr; Boolean res=FALSE; pd=(ParamDataPtr)GetWindowExtra(ParentWindow(Doc)); switch (pd->Visibles[Item].Kind) { case TITLE: case NUMBER: case NUMBERM: #if COMPUTE_PARAMS res=Col==1 && pd->Visibles[Item].Specific.Number.Error; #endif /* COMPUTE_PARAMS */ case NUMBERO: case SWITCHA: break; case SWITCH: if (Col>1) { valptr=GetValuePtr(pd,Item); switch (LastFieldType) { case CHAR: res=Col!=*(char*)valptr+2; break; case INTLO: res=Col!=*(int*)valptr+2; break; #if _INT4 case INTHI: res=Col!=*(long*)valptr+2; break; #endif } } break; case FUNCTION: res=Col==2 && !((FuncParStructurePtr)GetValuePtr(pd,Item))->_Unique; break; } return res; } #if _WIN #pragma argsused #endif Boolean InvertDocProc(DoC Doc, Int2 Item, Int2 Row, Int2 Col) { ParamDataPtr pd; VoidPtr valptr; Boolean res=FALSE; pd=(ParamDataPtr)GetWindowExtra(ParentWindow(Doc)); switch (pd->Visibles[Item].Kind) { case TITLE: break; case NUMBERM: if (Col==1) { res=*((BoolPtr)GetValuePtr(pd,-Item)); /* addr of sel/desel attrib */ } case NUMBER: case NUMBERO: break; case SWITCH: #if _INVERTSWITCH if (Item==pd->CurItem) { valptr=GetValuePtr(pd,Item); switch (LastFieldType) { case CHAR: res=Col==*(char*)valptr+2; break; case INTLO: res=Col==*(int*)valptr+2; break; #if _INT4 case INTHI: res=Col==*(long*)valptr+2; break; #endif } } #endif break; case SWITCHA: #if _INVERTSWITCH if (Item==pd->CurItem && Col==2) res=TRUE; #endif break; case FUNCTION: if (Col==1) { valptr=GetValuePtr(pd,Item); /* addr of FuncParStructure struct */ res=((FuncParStructure PNTR)valptr)->_Selected; } break; } return res; } Local(void) CalculateVisibleLines(ParamDataPtr pd) { RecT r; GetPosition(pd->Doc,&r); pd->Lines=(r.bottom-r.top-2-8)/parFmt.minHeight; /* 2 - window margins, 8 - AutonomousPanel's extension */ } /* Dynamically defined any window border's height and width */ void WinResizeProc(WindoW win) { ParamDataPtr pd; RecT r; RecT rd; pd=(ParamDataPtr)GetWindowExtra(win); if (pd->Flags&PP_FIRSTRESIZE) { /* immediately after Create Window */ pd->Flags&=~PP_FIRSTRESIZE; return; } HideInput(pd); Hide(pd->Doc); GetPosition(win,&r); GetPosition(pd->Doc,&rd); LoadRect(&r,-1,rd.top,r.right-r.left-pd->Dx-1,r.bottom-r.top-pd->Dy+rd.top); #if IMPLMENU #else if (pd->Impl.pCurrent) { Hide(pd->Impl.pCurrent); Select(pd->Impl.pCurrent); GetPosition(pd->Impl.pCurrent,&rd); rd.right=r.right-r.left; SetPosition(pd->Impl.pCurrent,&rd); Show(pd->Impl.pCurrent); } #endif SetPosition(pd->Doc,&r); SetValue(GetSlateVScrollBar((SlatE)pd->Doc),0); AdjustDocScroll(pd->Doc); Show(pd->Doc); CalculateVisibleLines(pd); } Local(int) precision=0; /* for sprintf */ Local(int) precisiond=0; /* for controls */ Local(Char) cotest[2]="?"; Local(Char) cochars[]="0123456789.+-e"; Local(void) SetPrecision(void) { int prec; Int2 i,w; GetParam(SFS_PARAMS,"PRECISION"); sscanf(ParBuf,"%i",&precision); for (i=prec=0; iprec) prec=w; } prec*=(precision+6); if (prec%sysCharWidth) precisiond=prec/sysCharWidth+1; else precisiond=prec/sysCharWidth; } /**************************/ /* Create parameter panel */ #if IMPLMENU Local(void) ImplChoiceProc(ChoicE ch) { WindoW win; ParamDataPtr pd; Int2 num; win=ParentWindow(ch); pd=(ParamDataPtr)GetWindowExtra(win); if (ParLock) { SetValue(ch,ImplCode[pd->winnum-1]+1); Beep(); return; } num=GetValue(ch)-1; if (num!=ImplCode[pd->winnum-1]) { HideInput(pd); ImplReload(pd->winnum,num); /* NB: Don't call ShowInput(pd); pd has been changed during ImplReload. */ Select(win); } } #else /* #if IMPLMENU */ Local(void) ImplDrawProc(PaneL p) { ParamDataPtr pd=(ParamDataPtr)GetWindowExtra(ParentWindow(p)); RecT r; Int2 i; Select(p); GetPosition(p,&r); OffsetRect(&r,2,1); i=pd->winnum-1; SelectFont(defcolFmt.font); DrawString(&r,ParamTxt[METHOD_I],'l',FALSE); r.left+=StringWidth(ParamTxt[METHOD_I])+stdCharWidth; if (ImplNames[i]) DrawString(&r,ImplNames[i][ImplCode[i]],'l',FALSE); } #if _WIN #pragma argsused #endif Local(void) ImplReleaseProc(PaneL p, PoinT pt) { ParamDataPtr pd; if (ParLock) return; pd=(ParamDataPtr)GetWindowExtra(ParentWindow(p)); if (pd->ImplHideList) { Hide(pd->Impl.lList); pd->ImplHideList=FALSE; } else { SetValue(pd->Impl.lList,ImplCode[pd->winnum-1]+1); Show(pd->Impl.lList); pd->ImplHideList=TRUE; } } Local(void) ImplListProc(LisT l) { WindoW win; ParamDataPtr pd; Int2 num; if (ParLock) return; win=ParentWindow(l); pd=(ParamDataPtr)GetWindowExtra(win); num=GetValue(l)-1; Hide(l); pd->ImplHideList=FALSE; if (num!=ImplCode[pd->winnum-1]) { ImplReload(pd->winnum,num); Select(win); } } Local(void) ImplDeactWin(WindoW win) { ParamDataPtr pd=(ParamDataPtr)GetWindowExtra(win); ImplHideListAndUpdate(pd); } #endif /* IMPLMENU */ Local(void) ParamWinActivated(WindoW win) { ParamDataPtr pd; Int2 i,n; if (ParLock) return; pd=(ParamDataPtr)GetWindowExtra(win); if (pd->CurItem) { ShowInput(pd); return; } for (n=pd->VisiblesNum,i=pd->CurItem; n>0; n--,i++) { if (i>=pd->VisiblesNum) i=0; if (!ItemIsVisible(pd->Doc,i,NULL,NULL,NULL)) continue; switch (pd->Visibles[i].Kind) { case NUMBER: case NUMBERM: pd->CurItem=i; ShowInput(pd); return; } } } Local(void) ParamWinDeactivated(WindoW win) { ParamDataPtr pd; if (ParLock) return; pd=(ParamDataPtr)GetWindowExtra(win); HideInput(pd); } Local(WindoW) ParameterPanel(Int2 left, Int2 top, WndActnProc WinCloseProc, ParamDataPtr pd, Boolean useold) { #define TEXT_WIDTH 8 /* times sysCharWidth */ #undef TEXT_WIDTH #define TEXT_WIDTH precisiond /* times sysCharWidth */ VoidPtr valptr; WindoW win; GrouP g; RecT r,rw; CharPtr p,q; Int2 i,n,ww,ColNum,Col1w,Colw,DocWidth,DocHeight; Char buf[256]; defcolFmt.font=SystemFont; /* Define max number of columns, width of col #1, and total widht of other columns */ for (i=1,ColNum=Col1w=0,Colw=L_COL_INSET+R_COL_INSET; iVisiblesNum; i++) { switch (pd->Visibles[i].Kind) { case TITLE: continue; case NUMBER: case NUMBERM: case NUMBERO: n=1; ww=TEXT_WIDTH*sysCharWidth; break; case SWITCH: for (p=pd->Texts[i], ww=0, n=0; (q=StrChr(p,'\t'),*p); n++) { if (q) *q='\0'; ww+=StringWidth(p)+sysCharWidth2; if (q) { *q='\t'; p=q+1; } else p+=StrLen(p); } break; case SWITCHA: for (p=pd->Texts[i], ww=0; (q=StrChr(p,'\t'),*p); ) { if (q) *q='\0'; if (wwVisibles[i].ExtName); if (Col1wCols); pd->Cols=_MemNew(ARRAYSIZE(ColData,ColNum+1)); /* Compute width and height of DoC panel */ parFmt.minHeight=sysLineHeight+1; DocWidth=Col1w+Colw; DocHeight=pd->Lines*parFmt.minHeight; ww=pd->winnum; if (useold) { win=ParentWindow(ImplSave[ww].doc); SetWindowExtra(win,pd,NULL); SetTitle(win,pd->Visibles[0].ExtName); pd->Input=ImplSave[ww].input; pd->Doc=ImplSave[ww].doc; pd->Impl=ImplSave[ww].Impl; HideInput(pd); Hide(pd->Doc); Reset(pd->Doc); #if IMPLMENU SetValue(pd->Impl.Choice,ImplCode[ww-1]+1); #else Hide(pd->Impl.lList); pd->ImplHideList=FALSE; #endif if (ImplMax[ww-1]) { #if IMPLMENU #else Select(pd->Impl.pCurrent); GetPosition(pd->Impl.pCurrent,&r); InvalRect(&r); Update(); #endif pd->Lines=MIN(screenY/parFmt.minHeight,pd->VisiblesNum)-1; DocHeight=pd->Lines*parFmt.minHeight; GetPosition(pd->Doc,&r); r.right+=DocWidth-pd->Impl.oldWidth; r.bottom+=DocHeight-pd->Impl.oldHeight; SetPosition(pd->Doc,&r); GetPosition(win,&rw); rw.right+=DocWidth-pd->Impl.oldWidth; rw.bottom+=DocHeight-pd->Impl.oldHeight; pd->Flags=PP_FIRSTRESIZE; SetPosition(win,&rw); pd->Flags&=~PP_FIRSTRESIZE; } } else { /* Create window */ win=DocumentWindow(left,top,-1,-1,pd->Visibles[0].ExtName,WinCloseProc,WinResizeProc); SetWindowExtra(win,pd,NULL); SetActivate(win,ParamWinActivated); SetDeactivate(win,ParamWinDeactivated); if (ImplMax[ww-1]) { #if IMPLMENU MenU menu; menu=PulldownMenu(win,ParamTxt[METHOD_I]); pd->Impl.Choice=ChoiceGroup(menu,ImplChoiceProc); for (n=0; nImpl.Choice,ImplNames[ww-1][n]); SetValue(pd->Impl.Choice,ImplCode[ww-1]+1); #else PoinT nextpos,wpos; SetDeactivate(win,ImplDeactWin); pd->Impl.pCurrent=SimplePanel(win,DocWidth+8+vScrollBarWidth,parFmt.minHeight+2,ImplDrawProc); SetPanelClick(pd->Impl.pCurrent,NULL,NULL,NULL,ImplReleaseProc); GetNextPosition(win,&nextpos); wpos=nextpos; nextpos.y+=2; wpos.x+=StringWidth(ParamTxt[METHOD_I])+stdCharWidth; for (i=n=0; ni) i=StringWidth(ImplNames[ww-1][n]); SetNextPosition(win,wpos); pd->Impl.lList=SingleList(win,i/stdCharWidth+1,MIN(5,ImplMax[ww-1]),ImplListProc); for (n=0; nImpl.lList,ImplNames[ww-1][n]); Hide(pd->Impl.lList); SetNextPosition(win,nextpos); #endif } else { #if IMPLMENU pd->Impl.Choice=NULL; #else pd->Impl.pCurrent=NULL; pd->Impl.lList=NULL; #endif } ImplSave[ww].Impl=pd->Impl; g=HiddenGroup(win,0,0,NULL); SetGroupSpacing(g,0,0); SetGroupMargins(g,0,0); /* Create Document panel */ pd->Input=HiddenText(g,"",TEXT_WIDTH,TextProc,TabProc,RetProc); Hide(pd->Input); pd->Doc=DocumentPanel(g,DocWidth,DocHeight); GetPosition(pd->Doc,&r); InsetRect(&r,-2,-2); /* for window's and panel's margins */ SetPosition(pd->Doc,&r); SetDocProcs(pd->Doc,NULL,NULL,ClickDocProc,PanDocProc); SetDocShade(pd->Doc,NULL,GrayDocProc,InvertDocProc,NULL); ImplSave[ww].doc=pd->Doc; ImplSave[ww].input=pd->Input; } /* if (useold) */ #if IMPLMENU #else pd->ImplHideList=FALSE; #endif /* Create items */ for (i=1; iVisiblesNum; i++) { pd->Cols[0]=defcolFmt; pd->Cols[0].pixWidth=Col1w; switch (pd->Visibles[i].Kind) { case TITLE: /* DON'T change parFmt.minHeight. It is supposed it has the same value for ALL items (used to compute Lines filed. */ sprintf(buf,"%s",pd->Visibles[i].ExtName); pd->Cols[0].pixWidth=DocWidth; pd->Cols[0].just='c'; pd->Cols[0].underline=TRUE; pd->Cols[0].last=TRUE; break; case NUMBER: case NUMBERM: case NUMBERO: sprintf(buf,"%s\t%s",pd->Visibles[i].ExtName,pd->Texts[i]); pd->Cols[1]=defcolFmt; pd->Cols[1].pixWidth=Colw; pd->Cols[1].pixInset=L_COL_INSET; pd->Cols[1].last=TRUE; break; case SWITCH: sprintf(buf,"%s\t%s",pd->Visibles[i].ExtName,pd->Texts[i]); for (p=pd->Texts[i], n=1; (q=StrChr(p,'\t'),*p); n++) { if (q) *q='\0'; pd->Cols[n]=defcolFmt; pd->Cols[n].pixWidth=StringWidth(p)+(sysCharWidth2); pd->Cols[n].pixInset=L_COL_INSET; if (q) { *q='\t'; p=q+1; } else p+=StrLen(p); } pd->Cols[n-1].last=TRUE; break; case SWITCHA: valptr=GetValuePtr(pd,i); switch (LastFieldType) { case CHAR: n=*(char*)valptr; break; case INTLO: n=*(int*)valptr; break; #if _INT4 case INTHI: n=*(long*)valptr; break; #endif } for (p=pd->Texts[i]; n; n--) { q=StrChr(p,'\t'); if (q) p=q+1; else break; } q=StrChr(p,'\t'); if (q) *q='\0'; sprintf(buf,"%s\t%s",pd->Visibles[i].ExtName,p); if (q) *q='\t'; pd->Cols[1]=defcolFmt; pd->Cols[1].pixWidth=Colw; pd->Cols[1].pixInset=L_COL_INSET; pd->Cols[1].last=TRUE; break; case FUNCTION: sprintf(buf,"%s\t%s",pd->Visibles[i].ExtName,EDIT_TEXT); pd->Cols[1]=defcolFmt; pd->Cols[1].pixWidth=Colw; pd->Cols[1].pixInset=L_COL_INSET; pd->Cols[1].last=TRUE; break; } AppendText(pd->Doc,buf,&parFmt,pd->Cols,SystemFont); } pd->CurItem=0; /* no active */ /* Attach data to window */ pd->Flags=PP_FIRSTRESIZE; if (pd->VisiblesNum>1) Show(win); else RealizeWindow(win); pd->Flags&=~PP_FIRSTRESIZE; GetPosition(win,&rw); GetPosition(pd->Doc,&r); pd->Dx=(rw.right-rw.left)-(r.right-r.left); pd->Dy=(rw.bottom-rw.top)-(r.bottom-r.top); if (useold) { /* It does not work without this (in MS Windows at least) */ InvalDocument(pd->Doc); Show(pd->Doc); } else { #if IMPLMENU #else ImplSave[ww].Impl.Dx=pd->Dx; ImplSave[ww].Impl.Dy=pd->Dy; #endif } ImplSave[ww].Impl.oldWidth=DocWidth; ImplSave[ww].Impl.oldHeight=DocHeight; return win; #undef TEXT_WIDTH } /* Retrieves a ptr from starter's data area. This ptr corresponds to the given (local) class. */ Global(FloatHiPtr) GetLocalClassVector(Uint1 localclass) { ParamDataPtr pd; Int2 i; /* Starter is the first! */ pd=ParamDataPtrs[1]; if (!pd) return NULL; for (i=0; iFieldsNum; i++) if (pd->Fields[i].LocalClass==localclass) { if (IsPointer(pd->Fields[i].Type)) return *(FloatHiPtr PNTR)(pd->Data+pd->Fields[i].Offset); else return (FloatHiPtr)(pd->Data+pd->Fields[i].Offset); } return NULL; } /* Retrieves a &ptr for variable-len field from starter's data area. This ptr corresponds to the given (local) class. */ Global(FloatHiPtr PNTR) GetLocalClassVectorIndir(Uint1 localclass) { ParamDataPtr pd; Int2 i; /* Starter is the first! */ pd=ParamDataPtrs[1]; if (!pd) return NULL; for (i=0; iFieldsNum; i++) if (pd->Fields[i].LocalClass==localclass) { if (pd->Fields[i].Dim==-2) /* must be a pointer */ return (FloatHiPtr PNTR)(pd->Data+pd->Fields[i].Offset); break; } return NULL; } /* Updates values in the window after initial point selection */ Global(void) UpdateInitPoint(void) { ParamDataPtr pd; Int2 i,indx; /* Starter is the first! */ pd=ParamDataPtrs[1]; for (i=0; iFieldsNum; i++) if (pd->Fields[i].LocalClass) { indx=GetParIndex(pd,pd->Fields[i].Offset); UpdatePar(pd,indx); } } Global(void) UpdateAllParams(void) { ParamDataPtr pd; Int2 j,indx; for (j=1; jVisiblesNum; indx++) { switch (pd->Visibles[indx].Kind) { case NUMBER: case NUMBERM: case NUMBERO: case SWITCH: case SWITCHA: /** From now (3.9.96) individual component of vectors may be invisible. The following if () is not valid therefore: if (pd->Visibles[indx].Index==0) **/ if (pd->Visibles[indx].FieldIndex>pd->Visibles[indx-1].FieldIndex) UpdatePar(pd,indx); break; case FUNCTION: UpdatePar(pd,indx); case TITLE: break; } } } } /*********************************/ /* III Build structures for Show */ /*********************************/ #if DEB_PAR Local(void) PrintParamData(CharPtr title,ParamDataPtr pd) { FILE *desc; CharPtr vp; int i,j; Char buf[300]; if (!pardeb) pardeb=fopen("deb_par","wt"); fprintf(pardeb,"\n\n***********************************\n%s\n\n",title); fprintf(pardeb,"Data=%p\n",pd->Data); fprintf(pardeb,"DynData=%p\n",pd->DynData); vp=StrChr(pd->DescFile,' '); if (vp) *vp='\0'; if (StrChr(pd->DescFile,DIRDELIMCHR)) *ParBuf='\0'; else GetParam(SFS_PATHS,"KERNEL"); StrCat(ParBuf,pd->DescFile); desc=FileOpen(ParBuf,"rt"); if (vp) *vp=' '; fprintf(pardeb,"DescFile is %s\n\n",pd->DescFile); while (!feof(desc)) { if (FileGets(buf,sizeof(buf),desc)) fprintf(pardeb,"%s",buf); } FileClose(desc); fprintf(pardeb,"\n"); fprintf(pardeb,"\nField descriptors:\n------------------\n"); fprintf(pardeb," # | Offset | Dim | Type |lCl| Value\n"); for (i=0; iFieldsNum; i++) { fprintf(pardeb,"%3i | %6u | %3i | %10s |%3i| ",i, pd->Fields[i].Offset, pd->Fields[i].Dim, Types[pd->Fields[i].Type], (int)pd->Fields[i].LocalClass); vp=pd->Data+pd->Fields[i].Offset; if (IsPointer(pd->Fields[i].Type)) { vp=*(CharPtr PNTR)vp; fprintf(pardeb,"*(%p)=",vp); } for (j=0; jFields[i].Dim; j++) { switch (Dereference(pd->Fields[i].Type)) { case CHAR: fprintf(pardeb,"%i",(int)*vp); break; case INTLO: fprintf(pardeb,"%i",*(int*)vp); break; #if _INT4 case INTHI: fprintf(pardeb,"%li",*(long*)vp); break; #endif #if _FLOATLO case FLOATLO: fprintf(pardeb,"%g",*(float*)vp); break; #endif case FLOATHI: fprintf(pardeb,"%g",*(double*)vp); break; case FUNCDESC: fprintf(pardeb,"_Select=%i, _Unique=%u",(int)((FuncParStructurePtr)vp)->_Selected, (unsigned int)((FuncParStructurePtr)vp)->_Unique); } vp+=TypesLen[Dereference(pd->Fields[i].Type)]; fprintf(pardeb," "); } fprintf(pardeb,"\n"); } fprintf(pardeb,"\nVisible descriptors:\n--------------------\n"); fprintf(pardeb," # | FieldIndex | Index | Kind | ExtName,Text & Specifics\n"); for (i=0; iVisiblesNum; i++) { fprintf(pardeb,"%3i | %10i | %5i | %c | '%s','%s'",i, (int)pd->Visibles[i].FieldIndex,(int)pd->Visibles[i].Index, "tnNosSf"[pd->Visibles[i].Kind], pd->Visibles[i].ExtName,pd->Texts[i] ? pd->Texts[i] : ""); switch (pd->Visibles[i].Kind) { case TITLE: case NUMBERO: case SWITCH: case SWITCHA: break; case NUMBERM: fprintf(pardeb,",SelFieldIndex=%i", (int)pd->Visibles[i].Specific.Number.SelFieldIndex); case NUMBER: fprintf(pardeb,",Expr=%c,Error=%c", "FT"[pd->Visibles[i].Specific.Number.Expr], "FT"[pd->Visibles[i].Specific.Number.Error]); break; case FUNCTION: fprintf(pardeb,",Header='%s'", pd->Visibles[i].Specific.Function.Header); } fprintf(pardeb,"\n"); } fprintf(pardeb,"\nInvisible descriptors:\n----------------------\n"); fprintf(pardeb," # | FieldIndex | Index | ExtName\n"); for (i=0; iInvisiblesNum; i++) { fprintf(pardeb,"%3i | %10i | %5i | '%s'\n",i, (int)pd->Invisibles[i].FieldIndex,(int)pd->Invisibles[i].Index, pd->Invisibles[i].ExtName); } fflush(pardeb); } #endif /* DEB_PAR */ #define BUF 100 /* Buffer size */ #if CACHEPAR Local(ParamDataPtr) CacheLookup(CharPtr DescFile); Local(ParamDataPtr) Cache(ParamDataPtr pdesc); #endif /* CACHEPAR */ /* Reads form the current position from stream up to the delimiter */ Local(Char) fmt[]=" %*[^?]"; Local(CharPtr) ExtractStr(FILE *stream, Char delim) { long fptr; CharPtr p; int len; fmt[5]=delim; fptr=ftell(stream); fscanf(stream,fmt); p=_MemNew((size_t)((len=(int)(ftell(stream)-fptr))+1)); fseek(stream,fptr,SEEK_SET); FileRead(p,len,1,stream); fgetc(stream); /* skip terminating delimiter */ StrTrim(p); return p; } Local(ParamDataPtr) gpd; /* Append a descriptor of invisible parameter to a list */ Local(void) AppendInvisibleDesc(InvisibleDescPtr pInvisible) { if (gpd->InvisiblesNum) { gpd->Invisibles=_MemMore(gpd->Invisibles,ARRAYSIZE(InvisibleDesc,gpd->InvisiblesNum+1)); } else { gpd->Invisibles=_MemNew(sizeof(InvisibleDesc)); } gpd->Invisibles[gpd->InvisiblesNum++]=*pInvisible; } /* Append a descriptor of visible parameter to a list */ Local(void) AppendVisibleDesc(VisibleDescPtr pVisible, CharPtr pText) { if (gpd->VisiblesNum) { gpd->Visibles=_MemMore(gpd->Visibles,ARRAYSIZE(VisibleDesc,gpd->VisiblesNum+1)); gpd->Texts=_MemMore(gpd->Texts,ARRAYSIZE(CharPtr,gpd->VisiblesNum+1)); } else { gpd->Visibles=_MemNew(sizeof(VisibleDesc)); gpd->Texts=_MemNew(sizeof(CharPtr)); } gpd->Texts[gpd->VisiblesNum]=pText; gpd->Visibles[gpd->VisiblesNum++]=*pVisible; } /* Append a descriptor of field to a list */ Local(Int2) AppendFieldDesc(FieldDescPtr pField) { if (gpd->FieldsNum) { gpd->Fields=_MemMore(gpd->Fields,ARRAYSIZE(FieldDesc,gpd->FieldsNum+1)); } else { gpd->Fields=_MemNew(sizeof(FieldDesc)); } gpd->Fields[gpd->FieldsNum]=*pField; return ++gpd->FieldsNum; } /* Align current offset */ Local(Uint2) AlignOffset(Uint2Ptr Offset, TypeCode Type) { Uint2 old; old=*Offset; if (*Offset % TypesAlignment[Type]) *Offset=((*Offset/TypesAlignment[Type])+1)*TypesAlignment[Type]; return *Offset-old; /* number of skipped bytes */ } /* Skip a comment */ Local(void) SkipComment(FILE *desc) { while (1) { /* The solution fscanf(desc,"%*[^*]*"); does not work on Unix if the next char is '*' (it would not be read as [^*] fails in such a case) */ fscanf(desc,"%*[^*]"); fgetc(desc); /* skip '*' */ if (fgetc(desc)=='/') break; } } /* Seeks a $-comment according to a #define'd id */ Local(Boolean) SeekSpecial(FILE *desc, CharPtr sbuf, CharPtr defined) { Char c; Char buf[33]; do { c=sbuf ? *sbuf: fgetc(desc); if (c=='=' || c=='!') { /* Get id after ! or = */ if (sbuf) { StrCpy(buf,sbuf+1); sbuf=NULL; } else fscanf(desc,"%32s",buf); if (c=='=') if (StrCmp(buf,defined)) /* id does not match #define'd name */ fscanf(desc,"%*[^*]*/",buf); else return TRUE; /* id does match, process $-comment */ if (c=='!') if (!StrCmp(buf,defined)) /* id does not match #define'd name */ fscanf(desc,"%*[^*]*/",buf); else return TRUE; /* id does not match, process $-comment */ /* Try the next $-comment */ fscanf(desc," %c",&c); if (c=='/') /* this must be a $-comment */ fscanf(desc,"*$"); else { ungetc(c,desc); break; } } else return TRUE; /* no condition, process $-comment */ } while (1); return FALSE; } /* Replaces all expressions (separated by commas) by thier values. E.g. "%Phase" becomes "5". */ Local(CharPtr) CompExprs(CharPtr s) { Char t[500]; CharPtr p,q; FloatHi e; for (p=s,t[0]='\0'; *p; ) { q=StrChr(p,','); if (q) *q='\0'; e=0.0; ComputeExpr(p,&e); sprintf(t+StringLen(t),"%g",e); if (q) { StrCat(t,","); *q=','; p=q+1; } else break; } return _StringSave(t); } /* Reads data area description file (e.i. struct {...}) and builds its description. Defines for external names of fields will be written to DescFile. After each field there must be a $-comment(with '$' immediately after '*') that has the following structure: 1. Text| Dynamic dimension; ignored for non-pointer fields. Text may be any expression and its operands may refer to dimension of classes (%class_name); >=0 Memory will be allocated from one dynamic pool. -1 Starter/generator takes care of this field: don't allocate/free/store/restore. -2 The size of memory is taken from the next field which must have type int and memory allocated via MemNew; othervise as >=0. -10-n like -1 with exceptions: true dimension is n (that is -(value+10) and n external names for the filed are provided to allow functional parameters change the values of the filed. otherwise it is left to starter or generator (-1. 2. Char Visibility attribute: '+' if field is visible, '-' otherwise. 3. Char Kind of parameter: 'n' number; 'N' number that may be activated/deactivated, in such a case THE NEXT field must be appropriate Boolean to hold the value of activated/deactivated attribute (Boolean, Boolean [], of BoolPtr); 's id1 id2 ...|' switch; 'f' functional parameter. 4. Text| External names of parameter(s). It is a list of names; description a'la class also allowed (see visual.c, III). NB: an external name must differ from name of any field. NB: external names may be used in functional parameres, even if visibility attribute is '-'. NB: '_' replaced by ' '. 5. "Default value(s)" Default value(s separated by commas). 6. Text (optional, may be any expression) Local class number (in the sence of the starter). If present, directs to call ParamChangeNotify() each time the value changed by the user. (In fact this invalidates bifurcation data). Select point also places here appropriate coordinates from point selected. The first $-comment in the file is window's title. Any other $-comment that does not match any field is considered as title in parameter window. Title $-comments must have letter 't' right after '$'. Any line that begins with two slashes is ignored as well as comments that are not $-comments (i.e. they do not have '$' as the first letter. A $-comment is ignored if it has the form $=id and id was not defined or it has the form $!id and id is defined. */ #define SEP '|' /* separator in description comment */ Local(ParamDataPtr) AllocateData(CharPtr DescFile) { FloatHi expr; FILE *desc; CharPtr p; CharPtr q; CharPtr pdef; ByteStorePtr stabs; ByteStorePtr dynbs; ByteStorePtr bs; ParamDataPtr pd; VisibleDesc vd; /* local copy */ InvisibleDesc id; FieldDesc fd; CharPtr txt; int i,n,pos; Int2 ii; Uint2 StaticLen,DynamicLen; TypeCode type; Char c,buf[BUF],field[BUF],kind,formpar[25],defstr[30]; Char def[33]; /* #define'd identifier, if any */ Char pad[MAX(sizeof(FuncParStructure),sizeof(FloatHi))]; union { double fhi; #if _FLOATLO float flo; #endif #if _INT4 long i4; #endif int i2; char c; } defval; /* default value */ Boolean visible,vclass,wrt; #if CACHEPAR if ((pd=CacheLookup(DescFile))!=NULL) return pd; /* got from cache */ #endif gpd=pd=_MemNew(sizeof(ParamData)); pd->DescFile=_StringSave(DescFile); /* Open */ txt=StrChr(DescFile,' '); if (txt) { /* There is a #define'd identifier */ *txt='\0'; sscanf(txt+1," %32s",def); } else *def='\0'; if (StrChr(DescFile,DIRDELIMCHR)) *ParBuf='\0'; else GetParam(SFS_PATHS,"KERNEL"); StrCat(ParBuf,DescFile); desc=FileOpen(ParBuf,"rt"); if (txt) *txt=' '; if (!desc) { myWarning("PA_OPEN",ParBuf); _MemFree(pd->DescFile); _MemFree(pd); return NULL; } /* Some initializations */ pd->FieldsNum=pd->VisiblesNum=pd->InvisiblesNum=0; pd->Invisibles=NULL; StaticLen=DynamicLen=0; stabs=BSNew(100); /* 100 is an arbitrary number */ dynbs=BSNew(100); MemSet(pad,0,sizeof(pad)); /* Get name of formal parameter that points to data area when functional parameters are called by a generator. */ StrCpy(formpar,GetParam(SFS_PARAMS,"FUNPAR1")); /* Process each line of descriptor file */ while (!feof(desc)) { MemSet(&vd,0,sizeof(vd)); MemSet(&fd,0,sizeof(fd)); txt=NULL; *buf='\0'; /* Read type and check it */ fscanf(desc," %[a-zA-Z0-9]",buf); if (!*buf) { /* not id */ if (feof(desc)) break; fscanf(desc,"%s",buf); if (buf[0]=='/') { /* it must be a comment */ if (!StrNCmp(buf,"/*$",3)) { /* unmatched $-comment */ if (buf[3]=='t') { /* it is a title */ if (SeekSpecial(desc,buf+4,def)) { vd.Kind=TITLE; vd.FieldIndex=-1; fscanf(desc," %[^*]*/ ",buf); vd.ExtName=_StringSave(buf); AppendVisibleDesc(&vd,NULL); } } else { /* skip alternative $-comment(s) from prev field */ SkipComment(desc); } } else { /* ignore the comment */ SkipComment(desc); } } continue; } fscanf(desc," %c",&c); if (c=='*') StrCat(buf,"*"); else ungetc(c,desc); for (fd.Type=(TypeCode)0; Types[fd.Type]; fd.Type++) if (!StrCmp(buf,Types[fd.Type])) break; if (!Types[fd.Type]) { /* is not a type name, ignore line */ fscanf(desc,"%*[^\n]\n"); continue; } type=Dereference(fd.Type); /* Read name of a field */ *field='\0'; fscanf(desc," %[a-zA-Z0-9_]",field); if (*field) fscanf(desc," %*[^;[/]"); else { /* not id after typename => FuncPar(...) */ fscanf(desc," ("); /* skip ( */ vd.Specific.Function.Header=ExtractStr(desc,';'); ungetc(';',desc); *(StrChr(vd.Specific.Function.Header,0)-1)='\0'; /* get rid of ) */ } /* Align current offset in the structure and store it */ BSWrite(stabs,&pad,AlignOffset(&StaticLen,fd.Type)); fd.Offset=StaticLen; /* Process dimension, if any */ c=fgetc(desc); if (c=='[') { fscanf(desc," %i ]",&n); } else { ungetc(c,desc); n=1; } fd.Dim=n; /* Advance current offset */ StaticLen+=TypesLen[fd.Type]*n; /* Skip to the begining of a $-comment and process attributes */ fscanf(desc," ; /*"); c=fgetc(desc); if (c!='$') { /* we allow one non $-comment before */ ungetc(c,desc); SkipComment(desc); fscanf(desc," /*$"); } SeekSpecial(desc,NULL,def); /* other (ignored) $-comments will be skipped on next iteration */ /* Attr. #1. Dynamical dimension */ p=ExtractStr(desc,SEP); if (IsPointer(fd.Type)) { ComputeExpr(p,&expr); if ((fd.Dim=(Int2)expr)>0) { /* <0 means "don't allocate memory" */ BSWrite(dynbs,&pad,AlignOffset(&DynamicLen,type)); DynamicLen+=fd.Dim*TypesLen[type]; } } _MemFree(p); /* Append field desc. and store it index */ vd.FieldIndex=AppendFieldDesc(&fd)-1; /* Attr. #2. Visible/invisible */ fscanf(desc," "); visible=fgetc(desc)=='+'; if (!fd.Dim) visible=FALSE; /* Attr. #3. Kind of parameter */ fscanf(desc," %c ",&kind); switch (kind) { case 'n': /* a number */ vd.Kind=NUMBER; break; case 'N': /* activated/deactivated number */ vd.Kind=NUMBERM; /* Sel/Desel attrib MUST be the next field (of kind 'n' and invisible) */ vd.Specific.Number.SelFieldIndex=vd.FieldIndex+1; break; case 'o': /* a number, the user is not allowed to change it */ vd.Kind=NUMBERO; break; case 's': /* switch; s id1 id2 ...| */ vd.Kind=SWITCH; txt=ExtractStr(desc,SEP); for (p=txt; (p=StrChr(p,' '))!=NULL; *p='\t',p++); break; case 'S': /* switch with a single item visible; S id1 id2 ...| */ vd.Kind=SWITCHA; txt=ExtractStr(desc,SEP); for (p=txt, vd.Specific.Switch.AltNum=1; (p=StrChr(p,' '))!=NULL; *p='\t',p++,vd.Specific.Switch.AltNum++); break; case 'f': /* functional parameter */ vd.Kind=FUNCTION; break; default:; } /* Attr. #4. External names; format is the same as for visible classes */ p=ExtractStr(desc,SEP); /* Attr. #5. Default value */ *buf='\0'; /* without this cc does not fill *buf if def value is "" */ i=0; fscanf(desc," \" %[^\"]\"%n",buf,&i); if (!i) /* "" and %[^"] has failed - skip " manualy */ fscanf(desc,"\""); /*** pdef=_StringSave(buf); ***/ pdef=CompExprs(buf); bs=IsPointer(fd.Type) ? (BSWrite(stabs,&pad,TypesLen[fd.Type]),dynbs) : stabs; /* Attr. #6. Notify flag & local class id (if any) */ vclass=FALSE; fscanf(desc," %c",&c); ungetc(c,desc); if (IS_DIGIT(c)) { fscanf(desc,"%i",&i); vclass=TRUE; } if (!vclass && c!='*') { q=ExtractStr(desc,' '); ComputeExpr(q,&expr); i=(int)expr; _MemFree(q); vclass=TRUE; } if (vclass) pd->Fields[vd.FieldIndex].LocalClass=(Uint1)i; /* Process external names and default values */ p=ExpandClassDef(p,EA_DO); /* Build a string with names separated by \n */ if (fd.Dim==-2) { id.Index=0; sscanf(p," %s",buf); id.ExtName=_StringSave(buf); id.FieldIndex=vd.FieldIndex; AppendInvisibleDesc(&id); } if (fd.Dim<=-10) { /* create invisible desc for each name */ fd.Dim=-10-fd.Dim; /* true dimension */ wrt=FALSE; } else wrt=TRUE; for (q=p,i=ii=0; i), then the name is invisible if the value of the is less than 0. */ { CharPtr p; p=StrChr(buf,'('); if (p && !ComputeExpr(p,&val)) { *p='\0'; if (val<0.0) goto invis; } } vd.Index=i; vd.ExtName=_StringSave(buf); if (txt) { /* a switch */ AppendVisibleDesc(&vd,txt); txt=_StringSave(txt); } else { txt=_StringSave(defstr); AppendVisibleDesc(&vd,txt); txt=NULL; } } else { /* There must be one external name for invisibles; thus this will be skipped for i>0 */ /* It is possible for a non-FUNCTION field to have more than one external name. In such a case more than one Invisible descriptors are created */ invis:; id.Index=i; id.ExtName=_StringSave(buf); id.FieldIndex=vd.FieldIndex; AppendInvisibleDesc(&id); if (val>0.0) goto free; /* truly invisible */ } } else { /* no external name for the field */ free:; txt=_MemFree(txt); /* for invisible switches */ if (vd.Kind==FUNCTION) _MemFree(vd.Specific.Function.Header); } } _MemFree(txt); _MemFree(p); _MemFree(pdef); /* Skip end of comment */ fscanf(desc," */"); } /* Erase 'empty' sections (0 is the window's title) */ while (pd->VisiblesNum>1 && pd->Visibles[pd->VisiblesNum-1].Kind==TITLE) { _MemFree(pd->Visibles[--pd->VisiblesNum].ExtName); } for (i=1; iVisiblesNum-1; ) if (/***i==pd->VisiblesNum-1 && pd->Visibles[i].Kind==TITLE ||***/ pd->Visibles[i].Kind==TITLE && pd->Visibles[i+1].Kind==TITLE) { pd->VisiblesNum--; MemCopy(pd->Texts+i,pd->Texts+i+1,ARRAYSIZE(CharPtr,pd->VisiblesNum-i)); pd->Texts=_MemMore(pd->Texts,ARRAYSIZE(CharPtr,pd->VisiblesNum)); _MemFree(pd->Visibles[i].ExtName); MemCopy(pd->Visibles+i,pd->Visibles+i+1,ARRAYSIZE(VisibleDesc,pd->VisiblesNum-i)); pd->Visibles=_MemMore(pd->Visibles,ARRAYSIZE(VisibleDesc,pd->VisiblesNum)); } else i++; /* Allocate memory */ pd->Data=_BSMerge(stabs,NULL); pd->DataLen=(Int2)BSLen(stabs); pd->DynData=_BSMerge(dynbs,NULL); pd->DynDataLen=(Int2)BSLen(dynbs); for (i=DynamicLen=0; iFieldsNum; i++) if (IsPointer(fd.Type=pd->Fields[i].Type)) { if (pd->Fields[i].Dim>0) { /* <0 means "don't allocate memory" */ AlignOffset(&DynamicLen,Dereference(fd.Type)); *(VoidPtr PNTR)(pd->Data+pd->Fields[i].Offset)=pd->DynData+DynamicLen; DynamicLen+=pd->Fields[i].Dim*TypesLen[Dereference(fd.Type)]; } else *(VoidPtr PNTR)(pd->Data+pd->Fields[i].Offset)=NULL; } /* Partition's name for parameters */ pd->Partition=_MemNew(1+StrLen(DescFile)+1); *pd->Partition=HIDDEN_CHAR; /* see datalib.h */ StrCpy(pd->Partition+1,DescFile); /* Close */ FileClose(desc); BSFree(stabs); BSFree(dynbs); #if CACHEPAR pd=Cache(pd); #endif return pd; } Local(Boolean) WholeData=TRUE; /* Read the values of parameters from Diagram DataLib and assign them to fields of Data Area. */ Local(void) RestoreData(ParamDataPtr pd, DataLibPtr dl) { FieldDescPtr fd; VisibleDescPtr vd; CharPtr vp; size_t slen,len1; Uint2 ilen; /* MUST BE Uint2 for compatibility reasons */ Int2 i,j; TypeCode type; Boolean varlen; Char buf[50]; fd=pd->Fields; /* Read len of following data (also used when redrawing curves) */ /* Preserve compatibility */ if (DataLibRead(dl,(CharPtr)&ilen,sizeof(ilen))!=sizeof(ilen)) return; if (ilen) slen=(size_t)ilen; else if (DataLibRead(dl,(CharPtr)&slen,sizeof(slen))!=sizeof(slen)) return; /* Fill in all the fields */ for (i=0; iFieldsNum; fd++,i++) { vp=pd->Data+fd->Offset; type=fd->Type; if (IsPointer(type)) { type=Dereference(type); /* points to what */ vp=*(CharPtr PNTR)vp; varlen=TRUE; } else varlen=FALSE; switch (fd->Dim) { case -1: continue; case -2: _MemFree(vp); *(CharPtr PNTR)(pd->Data+fd->Offset)=DataLibReadVRecord(dl,NULL); *(int*)(pd->Data+(fd+1)->Offset)=(int)DataLibLastVRecLen; slen-=DataLibGetDescLen(DataLibLastVRecLen)+DataLibLastVRecLen; continue; default: if (fd->Dim<=-10) continue; } switch (type) { case CHAR: case INTLO: #if _INT4 case INTHI: #endif #if _FLOATLO case FLOATLO: #endif case FLOATHI: len1=(varlen ? DataLibReadVRecordN : DataLibRead)(dl,vp,fd->Dim*TypesLen[type]); slen-=varlen ? DataLibGetDescLen(DataLibLastVRecLen)+DataLibLastVRecLen : len1; break; case FUNCDESC: DataLibRead(dl,(CharPtr)&((FuncParStructurePtr)vp)->_Unique, sizeof(((FuncParStructurePtr)vp)->_Unique)); DataLibRead(dl,(CharPtr)&((FuncParStructurePtr)vp)->_Selected, sizeof(((FuncParStructurePtr)vp)->_Selected)); slen-=sizeof(((FuncParStructurePtr)vp)->_Unique)+ sizeof(((FuncParStructurePtr)vp)->_Selected); break; } } for (vd=pd->Visibles, j=0; jVisiblesNum; vd++, j++) { switch (vd->Kind) { case NUMBER: case NUMBERM: vp=GetValuePtr(pd,j); switch (LastFieldType) { case CHAR: sprintf(buf,"%i",(int)*(char*)vp); break; case INTLO: sprintf(buf,"%i",(int)*(int*)vp); break; #if _INT4 case INTHI: sprintf(buf,"%li",(long)*(long*)vp); break; #endif #if _FLOATLO case FLOATLO: sprintf(buf,"%g",(float)*(float*)vp); break; #endif case FLOATHI: /*** sprintf(buf,"%g",(double)*(double*)vp);***/ sprintf(buf,"%.*g",precision,(double)*(double*)vp); break; } _MemFree(pd->Texts[j]); /* Free old value */ pd->Texts[j]=_StringSave(buf); break; case NUMBERO: case FUNCTION: case SWITCH: case SWITCHA: case TITLE: break; } } #if COMPUTE_PARAMS /* Now restore expressions for numerical parameters */ while (slen>0) { FloatHi d; if (DataLibRead(dl,(CharPtr)&i,sizeof(i))!=sizeof(i)) break; if (i<0 || i>=pd->VisiblesNum) break; if (WholeData) { _MemFree(pd->Texts[i]); /* Free old value */ pd->Texts[i]=DataLibReadVRecord(dl,NULL); if (ComputeExpr(pd->Texts[i],&d)) { pd->Visibles[i].Specific.Number.Error=TRUE; pd->Visibles[i].Specific.Number.Expr=TRUE; } else { pd->Visibles[i].Specific.Number.Error=FALSE; pd->Visibles[i].Specific.Number.Expr=CompIsExpr; } } else DataLibSkipVRecord(dl); slen-=sizeof(i)+DataLibGetDescLen(DataLibLastVRecLen)+DataLibLastVRecLen; } #endif /* COMPUTE_PARAMS */ } /* These data are stored after the values of parameters */ typedef struct { Int2 left,top,lines; Int2 oldwidth,oldheight; /* screen dimensions */ Boolean hidden; } WinPos; /* Create Data area for starter and generator */ /* if DescFile==NULL only restores data for window winnum */ Global(VoidPtr) CreateDataArea(CharPtr DescFile, Int2 winnum, VoidPtr PNTR DataArea, Boolean useold) { WinPos winpos; WindoW activewin; ParamDataPtr pd; if (DescFile) { activewin=CurrentWindow(); #if DEB_PAR if (!pardeb) pardeb=fopen("deb_par","wt"); #endif /* Build descriptors of fields, visibles, and invisibles */ pd=AllocateData(DescFile); if (!pd) return NULL; /* defaults */ winpos.oldwidth=screenX; winpos.oldheight=screenY; winpos.left=-100; winpos.top=-(winnum-1)*4*sysLineHeight*100/winpos.oldheight; winpos.hidden=FALSE; winpos.lines=MIN(winpos.oldheight/(sysLineHeight+1),pd->VisiblesNum)-1; } else pd=ParamDataPtrs[winnum]; /* Get values of parameters */ if (!DataLibIsClosed(&DiagramLib)) { /* there is a current diagram */ if (DiagramLib.SelectedDirPtr) { /* take from active curve */ DecreaseUseCounts(pd,FALSE,&DiagramLib DEB_UC_P); /* Usage counts: target */ RestoreData(pd,&DiagramLib); IncreaseUseCounts(pd,&DiagramLib DEB_UC_P); /* Usage counts: source */ /* get last windows positions */ DataLibSavePos(&DiagramLib); /* save */ while (!DataLibUp(&DiagramLib)); /* goto to the level 0 */ if (DataLibFind(&DiagramLib,pd->Partition)==0) { SkipParameters(&DiagramLib); DataLibRead(&DiagramLib,(CharPtr)&winpos,sizeof(winpos)); winpos.left=(FloatHi)winpos.left*screenX/winpos.oldwidth; winpos.top=(FloatHi)winpos.top*screenY/winpos.oldheight; } DataLibRestorePos(&DiagramLib); } else { /* no active curve, take defaults */ DataLibSavePos(&DiagramLib); /* save */ while (!DataLibUp(&DiagramLib)); /* goto to the level 0 */ if (DataLibFind(&DiagramLib,pd->Partition)==0) { DecreaseUseCounts(pd,FALSE,&DiagramLib DEB_UC_P); /* Usage counts: target */ RestoreData(pd,&DiagramLib); IncreaseUseCounts(pd,&DiagramLib DEB_UC_P); /* Usage counts: source */ DataLibRead(&DiagramLib,(CharPtr)&winpos,sizeof(winpos)); winpos.left=(FloatHi)winpos.left*screenX/winpos.oldwidth; winpos.top=(FloatHi)winpos.top*screenY/winpos.oldheight; } DataLibRestorePos(&DiagramLib); } } if (DescFile && winnum>=0) { /* Create window */ pd->Lines=winpos.lines; pd->winnum=winnum; if (winnum>=DIM(ParamDataPtrs)) myMessage(MSG_OK,"Too many parameter windows"); else ParamDataPtrs[winnum]=pd; ParameterPanel(winpos.left,winpos.top,NULL,pd,useold); CalculateVisibleLines(pd); winpos.hidden=pd->VisiblesNum<=1; /* only window's title */ Select(activewin); *DataArea=pd->Data; } return pd; } /*************************/ /* IV Destroy data areas */ /*************************/ /* Save the values of parameter to Diagram DataLib */ Local(void) SaveData(ParamDataPtr pd, DataLibPtr dl) { FieldDescPtr fd; #if COMPUTE_PARAMS VisibleDescPtr vd; #endif /* COMPUTE_PARAMS */ CharPtr vp; size_t wl; Int2 i,pass; size_t len,l; Uint2 ilen; /* MUST BE Uint2 for compatibility reasons */ TypeCode type; Boolean varlen; /* pass=0 - count len of saved data; pass=1 - Save values of all the fields */ for (len=pass=0; pass<2; pass++) { fd=pd->Fields; for (i=0; iFieldsNum; fd++,i++) { vp=pd->Data+fd->Offset; type=fd->Type; if (IsPointer(type)) { type=Dereference(type); /* points to what */ vp=*(CharPtr PNTR)vp; varlen=TRUE; } else varlen=FALSE; switch (fd->Dim) { case -1: /* don't save and don't free - just ignore it */ continue; case -2: /* take len from the next field which must by of type int */ wl=(size_t)*(int*)(pd->Data+(fd+1)->Offset); if (pass) DataLibWriteVRecord(dl,NULL,vp,wl); else len+=DataLibGetDescLen(wl)+wl; continue; default: if (fd->Dim<=-10) continue; } switch (type) { case INTLO: #if _INT4 case INTHI: #endif #if _FLOATLO case FLOATLO: #endif case FLOATHI: case CHAR: l=TypesLen[type]*fd->Dim; if (pass) if (varlen) DataLibWriteVRecord(dl,NULL,vp,l); else DataLibWrite(dl,vp,l); else len+=l+(varlen ? DataLibGetDescLen(l) : 0); break; case FUNCDESC: if (pass) { DataLibWrite(dl,(CharPtr)&((FuncParStructurePtr)vp)->_Unique, sizeof(((FuncParStructurePtr)vp)->_Unique)); DataLibWrite(dl,(CharPtr)&((FuncParStructurePtr)vp)->_Selected, sizeof(((FuncParStructurePtr)vp)->_Selected)); } else len+=sizeof(((FuncParStructurePtr)vp)->_Unique)+ sizeof(((FuncParStructurePtr)vp)->_Selected); break; } } #if COMPUTE_PARAMS /* Process expressions given by the user for numerical params */ for (vd=pd->Visibles, i=0; iVisiblesNum; vd++, i++) { switch (vd->Kind) { case NUMBER: case NUMBERM: if (pd->Visibles[i].Specific.Number.Expr) { l=StrLen(pd->Texts[i])+1; if (pass) { DataLibWrite(dl,(CharPtr)&i,sizeof(i)); DataLibWriteVRecord(dl,NULL,pd->Texts[i],l); } else len+=sizeof(i)+DataLibGetDescLen(l)+l; } break; } } #endif /* COMPUTE_PARAMS */ /* write total len of all parameters; it is used to skip them */ if (!pass) { if (lenCols); fd=pd->Fields; for (i=0; iFieldsNum; fd++,i++) if (fd->Dim==-2) _MemFree(*(CharPtr PNTR)(pd->Data+fd->Offset)); #if CACHEPAR if (freeall || !DoCache) { #endif _MemFree(pd->Fields); for (i=0; iVisiblesNum; i++) { _MemFree(pd->Visibles[i].ExtName); switch (pd->Visibles[i].Kind) { case FUNCTION: _MemFree(pd->Visibles[i].Specific.Function.Header); break; } } _MemFree(pd->Visibles); for (i=0; iInvisiblesNum; i++) _MemFree(pd->Invisibles[i].ExtName); _MemFree(pd->Invisibles); _MemFree(pd->Partition); _MemFree(pd->DescFile); #if CACHEPAR } #endif for (i=0; iVisiblesNum; i++) _MemFree(pd->Texts[i]); _MemFree(pd->Texts); _MemFree(pd->Data); _MemFree(pd->DynData); _MemFree(pd); } /* Destroy data area of starter and generator */ Global(void) DestroyDataArea(VoidPtr ParDescPtr, Int2 winnum, Boolean preserve) { #define pd ((ParamDataPtr)ParDescPtr) WinPos winpos; WindoW win; RecT r; ParamDataPtr pdw; if (!pd) return; if (winnum>=0) { ParamDataPtrs[winnum]=NULL; win=ParentWindow(pd->Doc); } if (!DataLibIsClosed(&DiagramLib)) { /* there is a current diagram */ DataLibSavePos(&DiagramLib); /* save */ while (!DataLibUp(&DiagramLib)); /* goto to the level 0 */ if (DataLibFind(&DiagramLib,pd->Partition)==0) { /* Usage counts: target */ pdw=AllocateData(pd->DescFile); WholeData=FALSE; RestoreData(pdw,&DiagramLib); DecreaseUseCounts(pdw,FALSE,&DiagramLib DEB_UC_P); #if CACHEPAR FreeData(pdw,FALSE); #else FreeData(pdw); #endif WholeData=TRUE; if (winnum<0) goto free; DataLibDelete(&DiagramLib); } else if (winnum<0) goto free; DataLibCreate(&DiagramLib,pd->Partition); /* Usage counts: source. In this case increase (it is the source) and descrese (data area to be destroyed) annihilate. */ /* Save values of parameters */ SaveData(pd,&DiagramLib); /* Save window's attributes */ GetPosition(win,&r); winpos.left=r.left; winpos.top=r.top; winpos.lines=pd->Lines; winpos.oldwidth=screenX; winpos.oldheight=screenY; winpos.hidden=!Visible(win); DataLibWrite(&DiagramLib,(CharPtr)&winpos,sizeof(winpos)); /* Restore DataLib position */ free:; DataLibRestorePos(&DiagramLib); } #if CACHEPAR FreeData(pd,FALSE); #else FreeData(pd); #endif if (winnum>=0) { if (!preserve) Remove(win); } #if DEB_PAR /* Don't close it at all. Otherwise deletion a non-active curve will cause fprintf(pardeb...) when pardeb is NULL */ /************************ { Int2 i; Boolean all; for (all=TRUE,i=1; iFieldsNum); for (i=0, fd=pd->Fields; iFieldsNum; i++, fd++) { vp=pd->Data+fd->Offset; type=fd->Type; if (IsPointer(type)) { type=Dereference(type); /* points to what */ vp=*(CharPtr PNTR)vp; } switch (fd->Dim) { case -1: continue; case -2: n=*(int*)(pd->Data+(fd+1)->Offset)/TypesLen[type]; fprintf(out," field%i dim=%i",(int)i,n); for (j=0; jDim<=-10) continue; } switch (type) { case CHAR: case INTLO: #if _INT4 case INTHI: #endif #if _FLOATLO case FLOATLO: #endif case FLOATHI: n=fd->Dim; fprintf(out," field%i dim=%i",(int)i,n); for (j=0; j_Unique, (int)((FuncParStructurePtr)vp)->_Selected); break; } } #if COMPUTE_PARAMS for (vd=pd->Visibles, i=j=0; jVisiblesNum; vd++, j++) { switch (vd->Kind) { case NUMBER: case NUMBERM: if (vd->Specific.Number.Expr) i++; break; } } fprintf(out," expr=%i\n",(int)i); for (vd=pd->Visibles, j=0; jVisiblesNum; vd++, j++) { switch (vd->Kind) { case NUMBER: case NUMBERM: if (vd->Specific.Number.Expr) fprintf(out," num=%i err=%i text=%s\n", (int)j,(int)vd->Specific.Number.Error, pd->Texts[j]); break; } } #endif /* COMPUTE_PARAMS */ /* Window's data */ if (win) fprintf(out," win=%i %i %i %i %i %i\n", (int)winpos.left,(int)winpos.top,(int)winpos.lines, (int)winpos.oldwidth,(int)winpos.oldheight, (int)winpos.hidden); /* Free memory */ #if CACHEPAR FreeData(pd,FALSE); #else FreeData(pd); #endif } Local(void) ReadANumber(CharPtr vp, TypeCode type, FILE PNTR in) { int i; #if _INT4 long l; #endif #if _FLOATLO float f; #endif double d; switch (type) { case CHAR: fscanf(in," %i",&i); *(char*)vp=(char)i; break; case INTLO: fscanf(in," %i",&i); *(int*)vp=i; break; #if _INT4 case INTHI: fscanf(in," %li",&l); *(long)vp=l; break; #endif #if _FLOATLO case FLOATLO: fscanf(in," %g",&f); *(float*)vp=f; break; #endif case FLOATHI: fscanf(in," %lg",&d); *(double*)vp=d; break; } } Global(void) ImportParams(DataLibPtr dgm, CharPtr DescFile, FILE PNTR in, Boolean win) { FieldDescPtr fd; ParamDataPtr pd; WinPos winpos; CharPtr vp; int n,d,dd,ddd,dddd,ddddd; int i,j; TypeCode type; pd=AllocateData(DescFile); fscanf(in," fields=%i\n",&n); /* Fill in all the fields */ for (i=0, fd=pd->Fields; iData+fd->Offset; type=fd->Type; if (IsPointer(type)) { type=Dereference(type); /* points to what */ vp=*(CharPtr PNTR)vp; } switch (fd->Dim) { case -1: continue; case -2: fscanf(in," field%i dim=%i",&dd,&d); vp=_MemGet(d*TypesLen[type],FALSE); for (j=0; jData+fd->Offset)=vp; *(int*)(pd->Data+(fd+1)->Offset)=d*TypesLen[type]; continue; default: if (fd->Dim<=-10) continue; } switch (type) { case CHAR: case INTLO: #if _INT4 case INTHI: #endif #if _FLOATLO case FLOATLO: #endif case FLOATHI: fscanf(in," field%i dim=%i",&dd,&d); for (j=0; j_Unique=(short)dd; ((FuncParStructurePtr)vp)->_Selected=(char)ddd; break; } } #if COMPUTE_PARAMS /* Now restore expressions for numerical parameters */ fscanf(in," expr=%i\n",&n); for (i=0; iVisibles[j].Specific.Number.Expr=TRUE; pd->Visibles[j].Specific.Number.Error=(Boolean)d; _MemFree(pd->Texts[j]); pd->Texts[j]=_StringSave(ParBuf); } #endif /* COMPUTE_PARAMS */ SaveData(pd,dgm); /* Free memory */ #if CACHEPAR FreeData(pd,FALSE); #else FreeData(pd); #endif /* Window's data */ if (win) { fscanf(in," win=%i %i %i %i %i %i\n",&n,&d,&dd,&ddd,&dddd,&ddddd); if (n<0 || n>=screenX) n=10; winpos.left=(Int2)n; if (d<0 || n>=screenRect.bottom) d=10; winpos.top=(Int2)d; if (dd<0 || dd>100) dd=10; winpos.lines=(Int2)dd; if (ddd<0) ddd=screenX; winpos.oldwidth=(Int2)ddd; if (dddd<0) dddd=screenY; winpos.oldheight=(Int2)dddd; if (ddddd!=0 && ddddd!=1) ddddd=0; winpos.hidden=(Boolean)ddddd; DataLibWrite(dgm,(CharPtr)&winpos,sizeof(winpos)); } } /**********************************************************/ /* IIIa, IVa Cache the structures created by AllocateData */ /**********************************************************/ #if CACHEPAR #define CACHEMAX 2*10 /* in fact, we'll always cache pairs of descriptors (sta&gen) */ Local(ParamDataPtr) CacheDesc[CACHEMAX]; Local(Int2) CacheIndx; Local(ParamDataPtr) CacheDup(ParamDataPtr src) { ParamDataPtr dest; Int2 i; dest=_MemNew(sizeof(*src)); *dest=*src; dest->Texts=_MemNew(ARRAYSIZE(CharPtr,src->VisiblesNum)); /* it is filled with zeros */ for (i=0; iVisiblesNum; i++) if (src->Texts[i]) dest->Texts[i]=_StringSave(src->Texts[i]); dest->Data=_MemNew(src->DataLen); MemCopy(dest->Data,src->Data,src->DataLen); dest->DynData=_MemNew(src->DynDataLen); MemCopy(dest->DynData,src->DynData,src->DynDataLen); for (i=0; iFieldsNum; i++) if (IsPointer(src->Fields[i].Type) && src->Fields[i].Dim>0) *(CharPtr PNTR)(dest->Data+dest->Fields[i].Offset)= dest->DynData+(Uint2)(*(CharPtr PNTR)(src->Data+src->Fields[i].Offset)-src->DynData); return dest; } Local(ParamDataPtr) CacheLookup(CharPtr DescFile) { Int2 i; if (DoCache) for (i=0; iDescFile,DescFile)) return CacheDup(CacheDesc[i]); return NULL; } Local(Boolean) CacheIsLocked(Int2 index) { Int2 i; for (i=0; iDescFile,CacheDesc[index]->DescFile)) return TRUE; return FALSE; } Local(ParamDataPtr) Cache(ParamDataPtr pdesc) { Int2 i; if (!DoCache) return pdesc; for (i=0; i=CACHEMAX) CacheIndx=0; } while (CacheIsLocked(CacheIndx)); FreeData(CacheDesc[CacheIndx],TRUE); /* see the note above return CacheDesc[CacheIndx]=pdesc; */ CacheDesc[CacheIndx]=pdesc; return CacheDup(pdesc); } Local(void) CacheInit(void) { for (CacheIndx=0; CacheIndxDoc) return -2; for (i=0; iFieldsNum; i++) if (pd->Fields[i].Offset==Offset) { for (j=1; jVisiblesNum; j++) if (pd->Visibles[j].FieldIndex==i && pd->Visibles[j].Kind!=TITLE) { /* Hide input because it overlays parameter to be updated and updated values may not be visible (true for Motif at least) */ if (pd->CurItem==j) HideInput(pd); return j; } return -1; } return -1; } /* Updates value(s) of parameter */ Global(void) UpdatePar(VoidPtr ppd, Int2 Index) { #define pd ((ParamDataPtr)ppd) CharPtr vp,p,q; VisibleDescPtr vd,vd0; RecT r; Int2 i,j,dim,len,val; Char buf[200]; TypeCode lasttype; Boolean eq; if (!pd->Doc) return; if (Index<0) {UpdateAllParams(); return;} UseWindow(ParentWindow(pd->Doc)); Select(pd->Doc); vp=GetValuePtr(pd,Index); dim=pd->Fields[LastFieldIndex].Dim; len=TypesLen[lasttype=LastFieldType]; vd=vd0=pd->Visibles+Index; for (i=0; iFieldIndex!=vd0->FieldIndex) break; if (iIndex) { vd--; continue; } switch (lasttype) { case CHAR: sprintf(buf,"%i",val=(int)*(char*)vp); break; case INTLO: sprintf(buf,"%i",val=(int)*(int*)vp); break; #if _INT4 case INTHI: sprintf(buf,"%li",(long)*(long*)vp); val=(int)*(long*)vp; break; #endif #if _FLOATLO case FLOATLO: sprintf(buf,"%g",(float)*(float*)vp); break; #endif case FLOATHI: /*** sprintf(buf,"%g",(double)*(double*)vp);***/ sprintf(buf,"%.*g",precision,(double)*(double*)vp); break; case FUNCDESC: UpdateDocument(pd->Doc,Index,Index); return; } switch (vd->Kind) { case SWITCH: UpdateDocument(pd->Doc,Index+i,Index+i); break; case SWITCHA: for (p=pd->Texts[Index+i]; val>0; val--) { q=StrChr(p,'\t'); if (q) p=q+1; else break; } q=StrChr(p,'\t'); if (q) *q='\0'; sprintf(buf,"%s\t%s",vd->ExtName,p); if (q) *q='\t'; goto update; case NUMBERM: case NUMBER: if (vd->Specific.Number.Expr) { FloatHi dval; eq=FALSE; if (ComputeExpr(pd->Texts[Index+i],&dval)) { dval=0.0; vd->Specific.Number.Error=TRUE; } else { vd->Specific.Number.Error=FALSE; switch (lasttype) { case INTLO: eq=*(int*)vp==(int)dval; break; #if _INT4 case INTHI: eq=*(long*)vp==(long)dval; break; #endif #if _FLOATLO case FLOATLO: eq=*(float*)vp==(float)dval; break; #endif case FLOATHI: eq=*(double*)vp==dval; break; } } if (eq) goto update0; } default: _MemFree(pd->Texts[Index+i]); /* Free old value */ pd->Texts[Index+i]=_StringSave(buf); update0: sprintf(buf,"%s\t%s",vd->ExtName,pd->Texts[Index+i]); update: for (j=0; j<2; j++) { pd->Cols[j]=defcolFmt; GetColParams(pd->Doc,Index+i,j+1,&r.left,&pd->Cols[j].pixWidth, &pd->Cols[j].pixInset,&pd->Cols[j].just); } pd->Cols[1].last=TRUE; ReplaceText(pd->Doc,Index+i,buf,&parFmt,pd->Cols,SystemFont); if (ItemIsVisible(pd->Doc,Index+i,&r.top,&r.bottom,NULL)) { if (vd->Kind==NUMBERM) { r.right=r.left+pd->Cols[1].pixWidth; /* GetColParams returns width */ r.left-=pd->Cols[0].pixWidth; InvalRect(&r); } else { r.right=r.left+pd->Cols[1].pixWidth; /* GetColParams returns width */ InvalRect(&r); /* Force update only value, not name */ } } } } Update(); #undef pd } /*************************************************/ /* VI Management of function parameters library */ /*************************************************/ /* All these are called from diagram.c, (dDelete, Activate/Dactivate Diagram) */ /* Free and erase function parameters library */ Global(void) ParamEraseLibs(CharPtr DiagramFile, Boolean OnlyIfOlder) { DataLibVar(DiagramLib); CharPtr libname; Boolean del,nopart; if (!DataLibOpen(&DiagramLib,DiagramFile)) { DataLibSavePos(&DiagramLib); while (!DataLibUp(&DiagramLib)); /* goto to the level 0 */ nopart=DataLibFind(&DiagramLib,LIB_PART); /* MustRecompile may also create it */ if (OnlyIfOlder) del=MustRecompile(&ArchivesLib,&DiagramLib,LIB_PART,FALSE,NULL); else del=TRUE; libname=DataLibReadVRecord(&DiagramLib,LIB_PART); if (del && *libname) { unlink(libname); if (!OnlyIfOlder || nopart) { FreeFileName(libname); DataLibDeletePartitions(&DiagramLib,LIB_PART,NULL); } } _MemFree(libname); DataLibRestorePos(&DiagramLib); DataLibClose(&DiagramLib); } } /* Load function parameters library */ Global(void) ParamLoadLibs(void) { CharPtr p; if (!hFuncParLib && !DataLibIsClosed(&DiagramLib)) { /* save DiagramLib ptr and goto to the level 0 */ DataLibSavePos(&DiagramLib); while (!DataLibUp(&DiagramLib)); /* Read lib name */ p=DataLibReadVRecord(&DiagramLib,LIB_PART); if (*p) { /* partition exists */ GetParam(SFS_CURRENTS,"DIRECTORY"); StrCat(ParBuf,p); SetParam(SFS_LIBRARIES,"PARLIB",ParBuf); if (!access(ParBuf,0)) { hFuncParLib=LibraryLock("PARLIB"); ParamFuncPtrs(FALSE); /* fill in all functions pointers */ } else { /* lib does not exist - recreate it */ _MemFree(p); PrepareToRecompile(TRUE); /* rebuild ALL #defs and #undefs - RHS might be changed */ DataLibRestorePos(&DiagramLib); LockAll(); ParLock++; PushContext(0,NULL,ParamTxt[CONTEXT_C]); Compile("MAKERHS",ProcessParsErrors); return; } } _MemFree(p); /* Restore DiagramLib ptr */ DataLibRestorePos(&DiagramLib); } } /* Unload function parameters library */ Global(void) ParamUnloadLibs(Boolean decrease) { Int2 j; if (hFuncParLib) { ParamFuncPtrs(TRUE); /* invalidate all functions pointer */ hFuncParLib=LibraryUnlock(hFuncParLib); } if (decrease) /* descrease usage counts */ for (j=1; jFields; iFieldsNum; i++, fd++) if (fd->Type==FUNCDESC) { vp=pd->Data+fd->Offset; AddUsage(((FuncParStructurePtr)vp)->_Unique); } /* - free memory */ #if CACHEPAR FreeData(pd,FALSE); #else FreeData(pd); #endif } Local(Int2) oneCurve(DataLibPtr dl) { Int2 i; Int2 method[4]; Char b[BL]; switch (DataLibEnumEvent) { case 1: /* entry to group */ case 2: /* exit from group */ return 0; } /* Parameters of starter and generator (master) */ /* -- first get methods */ DataLibDown(dl); if (DataLibFind(dl,IC_PART)==0) DataLibRead(dl,(CharPtr)method,sizeof(method)); else method[0]=method[1]=0; DataLibUp(dl); FindAndOpenDescFile(dl,SECPRF"data%s"); for (i=0; i<2; i++) { /* starter+generator */ mGetLine(b,method[i]); /* the name of header file */ oneDataArea(b,dl); } DescClose(); return 0; } Global(void) ParamFuncCleanup(DataLibPtr dl) { UniquePtr bits; CharPtr p,q; FieldDescPtr fd; CharPtr vp; ParamDataPtr pd; int i,j,k; short u; Int2 l; Char buf[50]; #if DEB && _UNIX int pos; printf("\n\nParamFuncCleanup checks diagram %s\n",dl->FileName); #endif /* Initialize and save DataLib position */ UseTabNum=0; DataLibSavePos(dl); while (!DataLibUp(dl)); Ftext=DataLibReadVRecord(dl,FUNPAR_PART); #if DEB && _UNIX printf(" Usage counts as they are in the diagram:\n"); for (p=Ftext; p; p+=pos) { if (sscanf(p,"%[^\n]\n%n",ParBuf,&pos)!=1) break; q=StrStr(ParBuf,"/*"); if (!q) continue; if (StrNCmp(q+2+UCL,"*/",2)==0) printf(" [>%s<]\n",ParBuf); } #endif /* Set #includes usage counts to 0 */ for (p=Ftext; p=StrStr(p,"#include"INVSTR),p; p++) { GetUseCount(p); /* just to allow UpdateUseCount */ UpdateUseCount(0); } /* Process default parameters of starters and generators */ StrCpy(buf,GetParam(SFS_EXTENSIONS,"H")); if (DataLibFindBySubstr(dl,buf,TRUE)==0 && dl->DirName[0]==HIDDEN_CHAR) do { oneDataArea(dl->DirName+1,dl); } while (DataLibFindBySubstr(dl,buf,FALSE)==0 && dl->DirName[0]==HIDDEN_CHAR); /* Process all curves */ DataLibEnumEx++; /* extended enumeration */ DataLibEnum(dl,oneCurve,TRUE); DataLibEnumEx--; /* Process currently loaded */ for (i=0; iFields; jFieldsNum; j++, fd++) if (fd->Type==FUNCDESC) { vp=pd->Data+fd->Offset; AddUsage(((FuncParStructurePtr)vp)->_Unique); } } #if DEB && _UNIX printf(" Unique numbers used in curves and default parameters (%i):\n",UseTabNum); printf(" number count\n"); for (i=0; ilen=1; bits->byte[0]=0xFE; /* bit .... ...1 in byte 0 will be represented as 0, but this means 'no unique number' */ } else bits=(UniquePtr)DataLibReadVRecord(dl,UNIQUE_PART); #if DEB && _UNIX printf(" Allocated unique numbers:"); for (i=0; ilen; i++) for (j=i ? 0 : 1; j<8; j++) if ((bits->byte[i]&(1<len; i++) for (j=i ? 0 : 1; j<8; j++) if ((bits->byte[i]&(1<