/* Help subsystem */ #include "common.h" #define DEBHELP 0 #define FIT 1 /* Formulae In Texts (see DrawPicture) */ #if _WIN #else /* LINUX: ungetc,SaveState,...,RestoreState: ftell in RestoreState discards push-back chars */ #define ungetc(c,f) fseek(f,-1L,SEEK_CUR) #endif #include "corefunc.h" #include "inter.h" #include "conthelp.h" Entry(void) ConthelpTerm(void); #define MAXTOPIC 20 #define MX 4 /* Help window's margins */ #define MY 4 #if _WIN #define R(x) floor((x)+0.5) Local(void) myLine(Int2 x1, Int2 y1, Int2 x2, Int2 y2) { FloatLo deltaX,deltaY,delta; if (x1==x2) deltaX=2; /* max possible value */ else deltaX=1.0+(x2>x1 ? 1.0 : -1.0)/(x2-x1); if (y1==y2) deltaY=2; /* max possible value */ else deltaY=1.0+(y2>y1 ? 1.0 : -1.0)/(y2-y1); delta=MIN(deltaX,deltaY); MoveTo(x1,y1); LineTo(R(x1+(x2-x1)*delta),R(y1+(y2-y1)*delta)); } #else #if _UNIX Local(void) myLine(Int2 x1, Int2 y1, Int2 x2, Int2 y2) { if (x1==x2) if (y1>y2) y1++; else y2++; MoveTo(x1,y1); LineTo(x2,y2); } #else /* _MAC */ #define myLine(x1,y1,x2,y2) {MoveTo(x1,y1); LineTo(x2,y2);} #endif #endif #define myFrameArc FrameArc Local(Int2) moveX,moveY; Local(void) myMoveTo(Int2 x, Int2 y) { moveX=x; moveY=y; } Local(void) myLineTo(Int2 x, Int2 y) { myLine(moveX,moveY,x,y); moveX=x; moveY=y; } typedef struct { /* Index endtry */ CharPtr key; /* topic's key; used in \jump */ CharPtr extkey; /* external (i.e. visible to user) key */ CharPtr cond; /* topic's visibility condition */ long pos; /* in file */ } HelpEntry, PNTR HelpEntryPtr; /* Help file table */ typedef struct { FILE *stream; CharPtr name; HelpEntryPtr index; Int2 n; /* DIM(index) */ } FileElem, PNTR FileElemPtr; Local(FileElemPtr) FileTable; Local(Int2) FileTableNum; /* Font table */ typedef struct { FonT font; CharPtr name; } FontElem, PNTR FontElemPtr; Local(FontElem) FontTable[]={ {0,"*"}, {0,"math"}, {0,"mathl"}, {0,"matht"}, {0,"scrt"}, {0,"scrm"}, {0,"b*"}, {0,"b*"}, {0,"prog"} }; Local(Int2) FontTableNum; /* Color table */ typedef struct { Uint1 r,g,b; CharPtr name; } ColorElem, PNTR ColorElemPtr; Local(ColorElem) ColorTable[]={ { 0, 0, 0,"black"}, {255, 0, 0,"red"}, { 0,255, 0,"green"}, { 0, 0,255,"blue"}, { 0,255,255,"cyan"}, {255, 0,255,"magenta"}, {255,255, 0,"yellow"}, {127,127,127,"gray"}, {255,255,255,"white"} }; Local(Int2) ColorTableNum; Local(int) JumpColorR,JumpColorG,JumpColorB; /* \jump variables. May be used in the place of a key and must be preceeded by '*' */ typedef struct { CharPtr varname; /* prefix '*' included */ CharPtr value; } JumpVar, PNTR JumpVarPtr; Local(JumpVarPtr) JumpVarTable; Local(Int2) JumpVarTableNum; typedef struct { Uint1 font; Uint1 color; Int2 lindent; /* left */ Int2 findent; /* first line */ Int1 bspace; /* before paragraph */ Int1 aspace; /* after paragraph */ Uint1 tab[2]; /* tab stops relative to left margin */ Boolean parstart; } State, PNTR StatePtr; typedef struct { /* Jump descriptor */ long filepos; /* after SC_JUMP in the file */ RecT area; /* sensitive area on the page */ Int1 file; } JumpDesc, PNTR JumpDescPtr; typedef struct { /* \include's stack of return data */ long filepos; /* where to return */ Int1 file; /* file to return */ } RetElem, PNTR RetElemPtr; typedef struct { long filepos; StatePtr state; /* stack of state elements */ RetElemPtr retstack; /* \include's return stack */ Int2 num; /* DIM(state) */ Int2 retnum; /* DIM(retstack) */ Int1 file; /* subscript to help file table */ } Page, PNTR PagePtr; typedef struct { PagePtr pages; /* list of pages */ HelpEntryPtr title; /* window's title */ Int1 flags; #define TF_REPAGE 1 /* Repage during processing of Back */ Int2 num; /* of shown pages */ Int2 cur; /* page */ Int2 max; } Topic, PNTR TopicPtr; Local(TopicPtr) TopicStack; Local(Int2) TopicNum; Local(Int2) TopicCur; Local(WindoW) hWindow=NULL,hSearch=NULL; Local(GrouP) gMain; /* contains everything */ Local(PaneL) hPanel; Local(RecT) WinRect,PanRect; Local(ButtoN) bPgUp,bPgDn,bBack; Local(TopicPtr) topic; Local(Page) cstate={0L,NULL,NULL,0,0}; Local(StatePtr) state; /* cstate.state+cstate.num-1 */ Local(FILE *) file; Local(Int2) lineHeight,lineAscent,lineDescent; /* of current font */ Local(void) setTitle(Int2 t) { HelpEntryPtr pt; Char b[100]; pt=TopicStack[t].title; if (pt&&pt->extkey[0]!='-') sprintf(b,"Help - %.90s",pt->extkey); else sprintf(b,"Help"); SetTitle(hWindow,b); } /* The units are sysCharWidth and sysLineHeight */ #define Hdistance(v) ((Int2)(v*sysCharWidth)) #define Vdistance(v) ((Int2)(v*sysLineHeight)) Local(void) setFont(Uint1 i) { SelectFont(FontTable[i].font); lineHeight=LineHeight(); lineAscent=Ascent(); lineDescent=Descent(); } #define setColor(i) SelectColor(ColorTable[i].r,ColorTable[i].g,ColorTable[i].b) Local(Int1) pass; /* 0 - calculate dimensions, 1 - draw */ Local(Int1) maxpass=2; /* usually; 1 while ResizeProc is in progress */ Local(void) SaveState(PagePtr sptr) { sptr->filepos=ftell(file); sptr->num=cstate.num; sptr->state=MemNew(ARRAYSIZE(State,cstate.num)); MemCopy(sptr->state,cstate.state,ARRAYSIZE(State,cstate.num)); sptr->retnum=cstate.retnum; sptr->retstack=MemNew(ARRAYSIZE(RetElem,cstate.retnum)); MemCopy(sptr->retstack,cstate.retstack,ARRAYSIZE(RetElem,cstate.retnum)); sptr->file=cstate.file; } Local(void) RestoreState(PagePtr sptr) { MemFree(cstate.state); cstate.state=sptr->state; sptr->state=NULL; cstate.num=sptr->num; sptr->num=0; MemFree(cstate.retstack); cstate.retstack=sptr->retstack; sptr->retstack=NULL; cstate.retnum=sptr->retnum; sptr->retnum=0; cstate.file=sptr->file; /* don't change cstate.filepos */ state=cstate.state+cstate.num-1; setFont(state->font); setColor(state->color); file=FileTable[cstate.file].stream; fseek(file,sptr->filepos,SEEK_SET); } Local(void) CopyState(PagePtr dst, PagePtr src) { MemFree(dst->state); MemFree(dst->retstack); MemCopy(dst,src,ARRAYSIZE(Page,1)); dst->state=MemNew(ARRAYSIZE(State,src->num)); MemCopy(dst->state,src->state,ARRAYSIZE(State,src->num)); dst->retstack=MemNew(ARRAYSIZE(RetElem,src->retnum)); MemCopy(dst->retstack,src->retstack,ARRAYSIZE(RetElem,src->retnum)); } Local(void) FreeState(PagePtr sptr) { sptr->state=MemFree(sptr->state); sptr->retstack=MemFree(sptr->retstack); sptr->num=sptr->retnum=0; } Local(void) FreeTopic(TopicPtr tptr) { Int2 i; for (i=0; inum; i++) FreeState(tptr->pages+i); tptr->pages=MemFree(tptr->pages); tptr->num=tptr->cur=tptr->max=0; } /***********************************************************/ typedef struct{ long fileptr; int object_code; int depth; int color; int fill_color; int area_fill; int line_style; /* font for P_TEXT */ #define TEXT_font line_style int thickness; /* font_size for P_TEXT */ #define TEXT_font_size thickness } ObjRef, PNTR ObjRefPtr; Local(int) Dx,Dy; #define round(x) ((Int2)floor((x)+0.5)) Local(int) fig_resolution; /* qsort callback */ Local(int) CmpEntries(const void * e1, const void * e2) { int cmp; cmp=StrCmp(((HelpEntryPtr)e1)->key,((HelpEntryPtr)e2)->key); return cmp; } /***********************************************************/ Callback(void) SearchCloseProc(ButtoN b); struct _fontCache { struct _fontCache PNTR next; CharPtr name; FonT font; } PNTR fontCache, PNTR fontCur; Local(ByteStorePtr) jumps=NULL; Callback(void) CloseProc(ButtoN b) { Int2 i,j; RecT r; Char buf[100]; if (hSearch) { SearchCloseProc(0); } WriteWindowPos("W_HELP",hWindow); GetPosition(hPanel,&r); sprintf(buf,"%g,%g",(double)(r.right-r.left+1)/screenRect.right, (double)(r.bottom-r.top+1)/screenRect.bottom); SetParam(SFS_CURRENTS,"S_HELP",buf); Remove(hWindow); hWindow=NULL; for (i=0; inext; MemFree(fontCache->name); DeleteFont(fontCache->font); MemFree(fontCache); } for (i=0; ifilepos); printf(" file=%i\n",page->file); printf(" states=\n"); if (page->num && !page->state) { if (Message(MSG_OKC,"state==NULL but num!=0")==ANS_CANCEL) i=1/sin(0.0); } for (i=0; inum; i++) { printf(" %i) font=%i, color=%i, indents=(%i,%i), spaces=(%i,%i)\n", i,page->state[i].font,page->state[i].color, page->state[i].lindent,page->state[i].findent, page->state[i].bspace,page->state[i].aspace ); } printf(" retstack=\n"); if (page->retnum && !page->retstack) { if (Message(MSG_OKC,"retstack==NULL but retnum!=0")==ANS_CANCEL) i=1/sin(0.0); } for (i=0; iretnum; i++) { printf(" %i) filepos=%lx, file=%i\n", i,page->retstack[i].filepos,page->retstack[i].file); } } #endif /* DEBHELP */ Local(SpecialCode) Statement(Int2 code) { float f; long newpos; Int2 i; Char buf[100]; switch (code) { case SC_F: /* font: \f [*|id] */ fscanf(file," %[a-zA-Z0-9*]",buf); for (i=0; ifont=i; setFont(i); break; } return 0; case SC_BF: /* bold font: \bf */ state->font=BOLD_FONT; setFont(BOLD_FONT); return 0; case SC_CF: /* color: \cf [*|id] */ fscanf(file," %[a-zA-Z0-9*]",buf); for (i=0; icolor=i; setColor(i); break; } return 0; case SC_LI: /* left ident: \li n */ fscanf(file,"%f",&f); state->lindent=Hdistance(f); state->findent=state->lindent; return SC_LI; case SC_FI: /* first (line) ident: \fi n */ fscanf(file,"%f",&f); state->findent=state->lindent+Hdistance(f); return 0; case SC_PAR: /* end of paragraph: \par */ return SC_PAR; case SC_SB: /* spacing before: \sb n */ fscanf(file,"%f",&f); state->bspace=Vdistance(f); return 0; case SC_SA: /* spacing after: \sa n */ fscanf(file,"%f",&f); state->aspace=Vdistance(f); return 0; case SC_CENTER: /* centrate: \qc */ case SC_RIGHT: /* align right: \qr */ case SC_DESC: /* description: \desc n */ return code; case SC_STAB: /* set tab stops: \tabs t1 t2 */ for (i=0; itab); i++) { fscanf(file,"%f",&f); state->tab[i]=Hdistance(f); } return 0; case SC_TAB: /* tab: \> */ case SC_PICTURE: case SC_JUMP: case SC_LEVEL: /* check level of current scope: \level id */ return code; case SC_INCLUDE: if (cstate.retnum++) cstate.retstack=MemMore(cstate.retstack,ARRAYSIZE(RetElem,cstate.retnum)); else cstate.retstack=MemNew(ARRAYSIZE(RetElem,1)); cstate.retstack[cstate.retnum-1].file=cstate.file; fscanf(file,"%c",buf); if (*buf=='l') { /* from the same file */ fread(&newpos,sizeof(newpos),1,file); } else { /* from another file */ fscanf(file," %[*a-zA-Z0-9_]",buf); FarJump(buf,&newpos); } cstate.retstack[cstate.retnum-1].filepos=ftell(file); file=FileTable[cstate.file].stream; fseek(file,newpos,SEEK_SET); return 0; case SC_VERBATIM: /* print lines 'as they are': \verbatim n */ fscanf(file,"%i",&verbatim); fgets(buf,sizeof(buf),file); /* skip to eol */ return SC_VERBATIM; case SC_END: /* end of topic: \end */ if (cstate.retnum) { cstate.retnum--; cstate.file=cstate.retstack[cstate.retnum].file; newpos=cstate.retstack[cstate.retnum].filepos; cstate.retstack=cstate.retnum ? MemMore(cstate.retstack,ARRAYSIZE(RetElem,cstate.retnum)) : MemFree(cstate.retstack); file=FileTable[cstate.file].stream; fseek(file,newpos,SEEK_SET); return 0; } else return SC_END; } return -1; } Local(void) ScopeStart(void) { cstate.state=MemMore(cstate.state,ARRAYSIZE(State,cstate.num+1)); MemCopy(cstate.state+cstate.num,cstate.state+cstate.num-1,ARRAYSIZE(State,1)); state=cstate.state+cstate.num++; } Local(void) ScopeEnd(void) { if (cstate.num) { cstate.state=MemMore(cstate.state,ARRAYSIZE(State,--cstate.num)); state=cstate.state+cstate.num-1; setFont(state->font); setColor(state->color); } else Message(MSG_OK,"Unbalanced }"); } /*-----------------------------------*/ /* Process a mathematical expression */ typedef struct { Int2 aleft,atop; /* absolute left and top; all other distances are offset from them */ Int2 top; Int2 base; Int2 bottom; Int2 height; /* max bottom */ Int2 width; } MathState, PNTR MathStatePtr; Local(void) ProcessStatements(void) { Uchar c; while (TRUE) { fscanf(file," %c",&c); if (c>(Uchar)SS_) Statement(c); else { ungetc(c,file); return; } } } Local(Boolean) MathFormula(MathStatePtr msp); Local(Boolean) MathSimple(MathStatePtr msp); Local(void) MathInitMs(MathStatePtr msp) { msp->top=0; msp->base=0; msp->bottom=msp->height=0; } Local(void) MathOffsetMs(MathStatePtr msp) { if (msp->top<0) { msp->base-=msp->top; msp->bottom-=msp->top; msp->top=0; } if (msp->bottom>msp->height) msp->height=msp->bottom; } Local(void) MathToken(MathStatePtr msp, CharPtr token) { msp->bottom=msp->base+lineDescent; msp->top=msp->bottom-lineHeight; MathOffsetMs(msp); if (pass==1) { MoveTo(msp->aleft+msp->width,msp->atop+msp->base); PaintString(token); } msp->width+=StringWidth(token); } Local(Int2) InScript=0; Local(Boolean) MathAtom(MathStatePtr msp) { Char c[50]; ProcessStatements(); fscanf(file," %c",c); if (StrChr("#}$",*c)) { if (*c=='}') ungetc(*c,file); return FALSE; } if (*c=='{') { ScopeStart(); ProcessStatements(); MathFormula(msp); ScopeEnd(); *c=fgetc(file); return *c=='}'; } c[1]='\0'; if (IS_ALPHANUM(c[0])) fscanf(file,"%[a-zA-Z0-9]",c+1); else setFont(InScript ? SCRM_FONT : FORMM_FONT); MathToken(msp,c); if (!IS_ALPHANUM(c[0])) setFont(state->font); return TRUE; } Local(void) addLeading(MathStatePtr msp) { msp->top-=8; MathOffsetMs(msp); } Local(int) lcw=0, lcw2, lcw_2; Local(Int2) LargeChar(MathStatePtr msp, Char c) { RecT rect; PoinT pts,pte; Int2 x,yt,yb,height,height_2; if (pass==1) { height=msp->bottom-msp->top+1; if (height&1) height++; height_2=height>>1; x=msp->aleft+msp->width; yt=msp->atop+(msp->top+msp->bottom)/2; } switch (c) { case '|': if (pass==1) { x+=lcw_2; yt-=height_2; yb=yt+height; myLine(x,yt+1,x,yb); } else addLeading(msp); return lcw; case '(': if (pass==1) { x++; yt-=height_2-lcw; yb=yt+height-lcw2; myLine(x,yt,x,yb); LoadRect(&rect,x,yt-lcw,x+lcw,yt+lcw); LoadPt(&pts,x,yt); LoadPt(&pte,x+lcw_2,yt-lcw); myFrameArc(&rect,pts,pte); OffsetRect(&rect,0,yb-yt); LoadPt(&pts,x+lcw_2,yb+lcw); LoadPt(&pte,x,yb); myFrameArc(&rect,pts,pte); } else addLeading(msp); return lcw; case ')': if (pass==1) { x+=lcw-2; yt-=height_2-lcw; yb=yt+height-lcw2; myLine(x,yt,x,yb); LoadRect(&rect,x-lcw+1,yt-lcw,x+1,yt+lcw); LoadPt(&pts,x-lcw_2,yt-lcw); LoadPt(&pte,x,yt); myFrameArc(&rect,pts,pte); OffsetRect(&rect,0,yb-yt); LoadPt(&pts,x,yb); LoadPt(&pte,x-lcw_2,yb+lcw); myFrameArc(&rect,pts,pte); } else addLeading(msp); return lcw; case '[': if (pass==1) { x++; yt-=height_2; yb=yt+height; myLine(x,yt,x,yb); myLine(x,yt,x+lcw-1,yt); myLine(x,yb,x+lcw-1,yb); } else addLeading(msp); return lcw; case ']': if (pass==1) { x+=lcw-1; yt-=height_2; yb=yt+height; myLine(x,yt,x,yb); myLine(x,yt,x-lcw+1,yt); myLine(x,yb,x-lcw+1,yb); } else addLeading(msp); return lcw; case '{': if (pass==1) { x+=lcw; yt-=height_2-lcw_2; yb=yt+height_2-lcw; #if _UNIX myLine(x,yt,x,yb-1); #else myLine(x,yt,x,yb); #endif LoadRect(&rect,x,yt-lcw_2,x+lcw,yt+lcw_2); LoadPt(&pts,x,yt); LoadPt(&pte,x+lcw_2,yt-lcw_2); myFrameArc(&rect,pts,pte); OffsetRect(&rect,-lcw,height_2-lcw); LoadPt(&pts,x,yb); LoadPt(&pte,x-lcw_2,yb+lcw_2); myFrameArc(&rect,pts,pte); OffsetRect(&rect,0,lcw); LoadPt(&pts,x-lcw_2,yb+lcw_2); LoadPt(&pte,x,yb+lcw); myFrameArc(&rect,pts,pte); yt=yb+lcw; yb=yt+height_2-lcw; myLine(x,yt,x,yb); OffsetRect(&rect,lcw,height_2-lcw); LoadPt(&pts,x+lcw_2,yb+lcw_2); LoadPt(&pte,x,yb); myFrameArc(&rect,pts,pte); } else addLeading(msp); return lcw2; case '}': if (pass==1) { x+=lcw; yt-=height_2-lcw_2; yb=yt+height_2-lcw; myLine(x,yt,x,yb); LoadRect(&rect,x-lcw,yt-lcw_2,x,yt+lcw_2); LoadPt(&pts,x-lcw_2,yt-lcw_2); LoadPt(&pte,x,yt); myFrameArc(&rect,pts,pte); OffsetRect(&rect,lcw,height_2-lcw); LoadPt(&pts,x+lcw_2,yb+lcw_2); LoadPt(&pte,x,yb); myFrameArc(&rect,pts,pte); OffsetRect(&rect,0,lcw); LoadPt(&pts,x,yb+lcw); LoadPt(&pte,x+lcw_2,yb+lcw_2); myFrameArc(&rect,pts,pte); yt=yb+lcw; yb=yt+height_2-lcw; myLine(x,yt,x,yb); OffsetRect(&rect,-lcw,height_2-lcw); LoadPt(&pts,x,yb); LoadPt(&pte,x-lcw_2,yb+lcw_2); myFrameArc(&rect,pts,pte); } else addLeading(msp); return lcw2; } return 0; } /* table: row colalign hmincell wspace */ Local(Boolean) MathTable(MathStatePtr msp, Int2 code) { MathState ms; Page ss; Int2Ptr colwidth,rowheight,rowbase,cellwidth; int row,height,width; FloatLo hmincell,wspace; Int2 col,ahmin,aspace,i,j,d,ii,jj,maxdescent; Int1 savepass; Char colalign[30]; fscanf(file," %i %[lcr] %f %f",&row,colalign,&hmincell,&wspace); col=(Int2)StrLen(colalign); if (pass==1) SaveState(&ss); ProcessStatements(); colwidth=MemNew(col*sizeof(*colwidth)); rowheight=MemNew(row*sizeof(*rowheight)); rowbase=MemNew(row*sizeof(*rowbase)); cellwidth=MemNew(col*row*sizeof(*cellwidth)); ahmin=Vdistance(hmincell); aspace=Hdistance(wspace); savepass=pass; pass=0; for (i=0; ibottom+msp->top-1)/2; if (d<0) { d=2*msp->base-msp->top-msp->bottom; msp->top=msp->base-(height+d)/2; msp->bottom=msp->base+(height-d)/2; } else { msp->top-=d; msp->bottom+=d; } MathOffsetMs(msp); if (msp->heightheight=height; if (pass==0) { switch (code) { case SS_MATRIX: width+=LargeChar(msp,'(')+LargeChar(msp,')'); break; case SS_DETERMINANT: /* det */ width+=2*LargeChar(msp,'|'); break; case SS_SYSTEM: width+=LargeChar(msp,'{'); break; case SS_TABLE: break; } msp->width+=width; } else { /*** i=msp->aleft+msp->width;***/ switch (code) { case SS_MATRIX: msp->width+=LargeChar(msp,'('); break; case SS_DETERMINANT: /* det */ msp->width+=LargeChar(msp,'|'); break; case SS_SYSTEM: msp->width+=LargeChar(msp,'{'); break; case SS_TABLE: break; } RestoreState(&ss); MemCopy(&ms,msp,sizeof(ms)); for (i=ii=0; itop+msp->bottom)/2-height/2+ii+rowbase[i]; ms.top=ms.base; ms.bottom=ms.height=ms.base; ms.width=msp->width+jj; d=jwidth+=width; switch (code) { case SS_MATRIX: msp->width+=LargeChar(msp,')'); break; case SS_DETERMINANT: msp->width+=LargeChar(msp,'|'); break; case SS_SYSTEM: break; case SS_TABLE: break; } } MemFree(colwidth); MemFree(rowheight); MemFree(rowbase); MemFree(cellwidth); return TRUE; } /* \int, \sum, \prod: (three=TRUE) \lim, \max, \min, \sup, \inf: (three=FALSE) */ Local(Boolean) Math3(MathStatePtr msp, Int2 code, Int2 i, Boolean three) { MathState mstop,msbot,msbody; Page ss; Int2 w,h,a,d,o,dspec,saveheight,savebase; Int2 ht,hb,ht2,hb2,wt,wb,wmax; Uint1 oldfont; Int1 savepass; Char p[10]; ProcessStatements(); oldfont=state->font; setFont(InScript ? SpecialTable[i].sfont : SpecialTable[i].font); if (i) { p[0]=SpecialTable[i].code; p[1]='\0'; } else switch( code) { case SS_LIM: StrCpy(p,"lim"); break; case SS_MIN: StrCpy(p,"min"); break; case SS_MAX: StrCpy(p,"max"); break; case SS_SUP: StrCpy(p,"sup"); break; case SS_INF: StrCpy(p,"inf"); break; } w=StringWidth(p); h=FontHeight(); dspec=lineDescent; setFont(state->font=SCRT_FONT); InScript++; MemCopy(&mstop,msp,sizeof(mstop)); MathInitMs(&mstop); MemCopy(&msbot,msp,sizeof(msbot)); MathInitMs(&msbot); InScript--; setFont(state->font=oldfont); MemCopy(&msbody,msp,sizeof(msbody)); MathInitMs(&msbody); if (pass==1) { SaveState(&ss); setFont(state->font=SCRT_FONT); InScript++; savepass=pass; pass=0; if (!MathAtom(&msbot)) return FALSE; /* just to compute rectangle */ if (msbot.width==msp->width) msbot.height=0; if (three && !MathAtom(&mstop)) return FALSE; /* just to compute rectangle */ if (mstop.width==msp->width) mstop.height=0; InScript--; setFont(state->font=oldfont); if (!MathAtom(&msbody)) return FALSE; /* just to compute rectangle */ pass=savepass; RestoreState(&ss); wt=(mstop.width-msp->width-w)/2; wb=(msbot.width-msp->width-w)/2; wmax=MAX(wt,wb); wmax=MAX(wmax,0); /* both may be empty, i.e. {} */ d=(h-(msbody.base-msbody.top))/2; d=MAX(d,dspec); /* from base to bottom of int,sum, etc. */ a=h-d; ht=mstop.height+((a)-(msp->base-msp->top))-(d-dspec); hb=msbot.height+(d-(msp->bottom-msp->base)); ht2=msbody.base-(msp->base-msp->top); /*** hb2=(msbody.bottom-msbody.base)-(msp->bottom-msp->base);***/ setFont(InScript ? SpecialTable[i].sfont : SpecialTable[i].font); MoveTo(msp->aleft+msp->width+wmax,msp->atop+msp->base+d-dspec); PaintString(p); mstop.width=msp->width+wmax-wt; o=msp->top-ht; mstop.top+=o; mstop.base+=o; mstop.bottom+=o; msbot.width=msp->width+wmax-wb; o=msp->bottom+hb-msbot.height; msbot.top+=o; msbot.base+=o; msbot.bottom+=o; msbody.width=msp->width; o=msp->top-ht2; msbody.top+=o; msbody.base+=o; msbody.bottom+=o; } setFont(state->font=SCRT_FONT); InScript++; wb=msbot.width; saveheight=msbot.height; MathAtom(&msbot); if (pass==1) msbot.height=saveheight; if (msbot.width==wb) msbot.height=0; wt=mstop.width; if (three) { saveheight=mstop.height; MathAtom(&mstop); if (pass==1) mstop.height=saveheight; } if (mstop.width==wt) mstop.height=0; InScript--; setFont(state->font=oldfont); wt=(mstop.width-msp->width-w)/2; wb=(msbot.width-msp->width-w)/2; wmax=MAX(wt,wb); wmax=MAX(wmax,0); msbody.width=msp->width+2*wmax+w; saveheight=msbody.height; savebase=msbody.base-msbody.top; MathAtom(&msbody); if (pass==1) { msbody.height=saveheight; msbody.base=savebase; } d=(h-(msbody.base-msbody.top))/2; d=MAX(d,dspec); /* from base to bottom of int,sum, etc. */ a=h-d; ht=mstop.height+((a)-(msp->base-msp->top))-(d-dspec); hb=msbot.height+(d-(msp->bottom-msp->base)); ht2=msbody.base-(msp->base-msp->top); hb2=(msbody.height-msbody.base)-(msp->bottom-msp->base); msp->top-=MAX(ht,ht2); msp->bottom+=MAX(hb,hb2); msp->width=msbody.width; MathOffsetMs(msp); return TRUE; } Local(Boolean) Accent(MathStatePtr msp, Int2 code) { MathState ms; Page ss; Int2 w,h,hu,hl,top,o,al,at; Uint1 savepass; Char c; fscanf(file," %c",&c); ungetc(c,file); MathInitMs(&ms); ms.width=0; SaveState(&ss); savepass=pass; pass=0; if (!MathSimple(&ms)) return FALSE; pass=savepass; RestoreState(&ss); if (c=='#') setFont(InScript ? SCRM_FONT : FORMM_FONT); w=ms.width; top=msp->base-lineAscent; /* Here we are victims of Vibrant's inability to retrieve metrics of individual characters (although Modif does provide these data and so does Windows for True Type fonts). */ /* h is the height of a bounding rectangle, hu is its offset for upper case letters and hl is its offset for lower case letters. */ #if _WIN h=lineDescent; hu=h-1; hl=0; #endif #if _UNIX h=lineDescent; hu=h+1; hl=(h>>1)+2; #endif #if _MAC h=???; h1=???; #endif if (c=='#') setFont(state->font); /* consider all greek letters as tall */ top-=(IS_UPPER(c) || StrChr("bdfhklt#",c)) ? hu : hl; if (pass==1) { /* left top corner of a rectangle an accent fits in */ al=msp->aleft+msp->width; at=msp->atop+top; } switch (code) { case SS_HAT: if (pass==1) { al+=w/2; myLine(al,at+1,al-(h-1),at+h); myLine(al,at+1,al+(h-1),at+h); } o=h; break; case SS_TILDE: if (pass==1) { if (w<3*(h-1)) { al-=(3*(h-1)-w)>>1; w=3*(h-1); } myLine(al,at+h,al+h-2,at+2); myLine(al+h-2,at+2,al+w-(h-1),at+h); myLine(al+w-(h-1),at+h,al+w,at+1); } o=h; break; case SS_BAR: case SS_BARDOT: if (pass==1) { myLine(al,at+h,al+w,at+h); } o=1; if (code==SS_BAR) break; case SS_DOT: if (pass==1) { al+=w/2; at+=h; if (code==SS_BARDOT) at-=2; MoveTo(al-1,at); LineTo(al+1,at); MoveTo(al-1,at-1); LineTo(al+1,at-1); } o=2; break; } MathSimple(msp); msp->top-=o; msp->height+=o; MathOffsetMs(msp); return TRUE; } /* \sqrt */ Local(Boolean) Root(MathStatePtr msp) { MathState ms; Page ss; Int1 savepass; ProcessStatements(); msp->width++; MemCopy(&ms,msp,sizeof(ms)); MathInitMs(&ms); ms.base=ms.bottom=lineAscent; /* to align stuff like #sqrt {#determinant...}} */ if (pass==1) { SaveState(&ss); savepass=pass; pass=0; if (!MathSimple(&ms)) return FALSE; /* calculate dimensions */ pass=savepass; RestoreState(&ss); ms.top=msp->base-ms.base; ms.bottom=msp->base+ms.height-ms.base; ms.base=msp->base; MoveTo(ms.aleft+msp->width,ms.atop+((ms.top+ms.bottom)>>1)); LineTo(ms.aleft+msp->width+(lcw>>1),ms.atop+ms.bottom-1); LineTo(ms.aleft+msp->width+lcw,ms.atop+ms.top-2); LineTo(ms.aleft+msp->width+lcw+ms.width-msp->width,ms.atop+ms.top-2); ms.width=msp->width; } ms.width+=lcw; MathSimple(&ms); if (pass==0) { addLeading(&ms); } msp->top=msp->base-ms.base; msp->bottom=msp->base+ms.height-ms.base; msp->width=ms.width; MathOffsetMs(msp); return TRUE; } /* \bracketsxy where x=.|({[ y=.|)}] */ Local(Boolean) Brackets(MathStatePtr msp) { MathState ms; Page ss; Int1 savepass; char left,right; fscanf(file," %c %c",&left,&right); MemCopy(&ms,msp,sizeof(ms)); MathInitMs(&ms); savepass=pass; if (pass==1) { SaveState(&ss); pass=0; } if (!MathSimple(&ms)) return FALSE; /* calculate dimensions */ msp->top=msp->base-ms.base; msp->bottom=msp->base+ms.height-ms.base; MathOffsetMs(msp); if (savepass==1) { pass=savepass; RestoreState(&ss); msp->width+=LargeChar(msp,left); MathSimple(msp); msp->top=msp->base-ms.base; msp->bottom=msp->base+ms.height-ms.base; msp->width+=LargeChar(msp,right); } else { msp->width=ms.width+LargeChar(msp,left)+LargeChar(msp,right); } return TRUE; } /* \frac */ Local(Int2) fracchar=0; Local(Boolean) Fraction(MathStatePtr msp) { MathState msnumer,msdenom; Page ss; Int2 wn,wd,wf,w,dn,dd,ww,hn,hd; Int1 savepass; Char c[2]; msp->width+=2; /* space before a fraction */ MemCopy(&msnumer,msp,sizeof(msnumer)); MathInitMs(&msnumer); MemCopy(&msdenom,msp,sizeof(msdenom)); MathInitMs(&msdenom); savepass=pass; if (pass==1) { SaveState(&ss); pass=0; } if (!MathSimple(&msnumer)) return FALSE; /* calculate dimensions */ if (!MathSimple(&msdenom)) return FALSE; /* calculate dimensions */ setFont(InScript ? SpecialTable[fracchar].sfont : SpecialTable[fracchar].font); c[0]=SpecialTable[fracchar].code; c[1]='\0'; wf=StringWidth(c); /* distance from base line to the bottom of numerator */ dn=lineDescent+1; /* distance from base line to the top of denominator; choosen rather arbitrary */ dd=lineDescent; wn=msnumer.width-msp->width; wd=msdenom.width-msp->width; w=MAX(wn,wd); w=MAX(w,wf); hn=msnumer.height; hd=msdenom.height; setFont(state->font); if (savepass==1) { pass=savepass; RestoreState(&ss); setFont(InScript ? SpecialTable[fracchar].sfont : SpecialTable[fracchar].font); for (ww=0; TRUE; ) { MoveTo(msp->aleft+msp->width+ww,msp->atop+msp->base); PaintString(c); ww+=wf; if (ww>=w) break; if (w-wwfont); msnumer.width=msp->width+(w-wn)/2; ww=(msp->base-dn)-hn; msnumer.top+=ww; msnumer.base+=ww; msnumer.bottom+=ww; MathSimple(&msnumer); msdenom.width=msp->width+(w-wd)/2; ww=(msp->base-dd); msdenom.top+=ww; msdenom.base+=ww; msdenom.bottom+=ww; MathSimple(&msdenom); } msp->top=(msp->base-dn)-hn; msp->bottom=(msp->base-dd)+hd; MathOffsetMs(msp); msp->width+=w; msp->width+=2; /* space after a fraction */ return TRUE; } Local(Boolean) MathSimple(MathStatePtr msp) { MathState msuper,msub; Page ss; Int2 code,d,i,ii,jj,j; Char c[50]; Int1 script,savepass; Uint1 oldfont; ProcessStatements(); fscanf(file," %c",c); if (*c=='#') { code=fgetc(file); if (codefont); goto ss; } switch (code) { case SS_SPACE1: msp->width+=StringWidth(" ")>>1; return TRUE; case SS_SPACE2: msp->width+=StringWidth(" "); return TRUE; case SS_SPACE3: msp->width+=3*StringWidth(" ")/2; return TRUE; case SS_SPACE_1: msp->width-=StringWidth(" ")>>1; return TRUE; case SS_MATRIX: case SS_DETERMINANT: case SS_SYSTEM: case SS_TABLE: return MathTable(msp,code); case SS_SQRT: return Root(msp); case SS_BRACKETS: return Brackets(msp); case SS_FRAC: return Fraction(msp); case SS_INT: case SS_SUM: case SS_PROD: case SS_INTL: case SS_SUML: case SS_PRODL: i=fgetc(file); return Math3(msp,code,i,TRUE); case SS_LIM: case SS_MIN: case SS_MAX: case SS_INF: case SS_SUP: return Math3(msp,code,0,FALSE); case SS_HAT: case SS_TILDE: case SS_BAR: case SS_DOT: case SS_BARDOT: return Accent(msp,code); } return FALSE; } else { ungetc(*c,file); if (!MathAtom(msp)) return FALSE; ProcessStatements(); ss: fscanf(file," %c",c); script=0; if (*c=='^') { oldfont=state->font; setFont(state->font=SCRT_FONT); InScript++; ProcessStatements(); ii=lineDescent; jj=lineAscent; MemCopy(&msuper,msp,sizeof(msuper)); MathInitMs(&msuper); if (pass==1) { SaveState(&ss); savepass=pass; pass=0; if (!MathAtom(&msuper)) return FALSE; /* just to compute superscript's height */ pass=savepass; RestoreState(&ss); i=(msp->top+msp->base)/2+ii; j=msp->top+jj+(msuper.height-msuper.base); d=MIN(i,j)-msuper.height; if (d>0) { msuper.top+=d; msuper.base+=d; msuper.bottom+=d; } msuper.width=msp->width; } if (!MathAtom(&msuper)) return FALSE; if (pass==1) msuper.height-=d; i=(msp->top+msp->base)/2+ii; j=msp->top+jj+(msuper.height-msuper.base); d=msuper.height-MIN(i,j); if (d>0) { msp->top+=d; msp->base+=d; msp->bottom+=d; } if (msp->heightbottom) msp->height=msp->bottom; setFont(state->font=oldfont); InScript--; ProcessStatements(); fscanf(file," %c",c); script=1; } if (*c=='_') { oldfont=state->font; setFont(state->font=SCRT_FONT); InScript++; ProcessStatements(); ii=-Leading(); jj=0; MemCopy(&msub,msp,sizeof(msub)); MathInitMs(&msub); if (pass==1) { Page ss; SaveState(&ss); savepass=pass; pass=0; if (!MathAtom(&msub)) return FALSE; /* just to compute rectangle */ pass=savepass; RestoreState(&ss); i=(msp->top+msp->base)/2+ii; j=msp->bottom+jj-msub.height/2; d=MAX(i,j); msub.base+=d; msub.bottom+=d; msub.top+=d; msub.width=msp->width; } if (!MathAtom(&msub)) return FALSE; if (pass==1) msub.height-=d; i=(msp->top+msp->base)/2+ii; j=msp->bottom+jj-msub.height/2; d=MAX(i,j)+msub.height; if (msp->heightheight=d; setFont(state->font=oldfont); InScript--; script|=2; } switch (script) { /* ^ _ */ case 0: /* n n */ ungetc(*c,file); break; case 1: /* y n */ msp->width=msuper.width; ungetc(*c,file); break; case 2: /* n y */ msp->width=msub.width; break; case 3: /* y y */ msp->width=MAX(msuper.width,msub.width); } return TRUE; } } Local(Boolean) MathFormula(MathStatePtr msp) { while (TRUE) if (!MathSimple(msp)) return FALSE; } Local(void) Math(MathStatePtr msp) { ScopeStart(); setFont(state->font=FORMT_FONT); ProcessStatements(); if (pass==0 && msp->base==0) { msp->base=lineHeight-lineDescent; } msp->top=msp->base-(lineHeight-lineDescent); msp->bottom=msp->height=msp->base+lineDescent; msp->width=0; MathFormula(msp); ScopeEnd(); } /* */ /*-----------------------------------*/ Local(FloatLo) PicW,PicH; Local(Int2) PicX(int x) { return round(x*PicW/Dx); } Local(Int2) PicY(int y) { return round(y*PicH/Dy); } Local(void) PicColor(int color) { #if _MAC if (!Nlm_hasColorQD) { (color==7 ? White : Black)(); return; } #endif #if _UNIX if (!Nlm_hasColor) { (color==7 ? White : Black)(); return; } #endif switch (color) { case 0: Black(); break; case 1: Blue(); break; case 2: Green(); break; case 3: Cyan(); break; case 4: Red(); break; case 5: Magenta(); break; case 6: Yellow(); break; case 7: White(); break; default: Black(); } } /* see xfig (protocol 3.1) sources */ #define THRESHOLD 5*15 /* 15=ZOOM_FACTOR */ #define STACK_DEPTH 20 static struct { FloatLo x1,y1,x2,y2,x3,y3,x4,y4; } stack[STACK_DEPTH]; #define Push(a,b,c,d,e,f,g,h) stack[stackn].x1=a; \ stack[stackn].y1=b; \ stack[stackn].x2=c; \ stack[stackn].y2=d; \ stack[stackn].x3=e; \ stack[stackn].y3=f; \ stack[stackn].x4=g; \ stack[stackn].y4=h; \ stackn++; #define Pop(a,b,c,d,e,f,g,h) stackn--; \ a=stack[stackn].x1; \ b=stack[stackn].y1; \ c=stack[stackn].x2; \ d=stack[stackn].y2; \ e=stack[stackn].x3; \ f=stack[stackn].y3; \ g=stack[stackn].x4; \ h=stack[stackn].y4; Local(void) DrawPicture(MathStatePtr msp) { RecT rt; PoinT ps,pe; ObjRef or; FloatLo w,x1,y1,x2,y2,cx1,cy1,cx2,cy2,cx3,cy3,cx4,cy4,threshold; #if FIT FloatLo aL=0,aR=0,aT=0,aB=0; #endif int n,pn,i,j,lx,ly,rx,ry,stackn; Boolean open,first; Char text[100]; fscanf(file,"%i %g %i %i",&fig_resolution,&w,&Dx,&Dy); GetPosition(hPanel,&rt); PicW=(rt.right-rt.left+1)*w; PicH=PicW*Dy/Dx; i=cstate.state[cstate.num-1].bspace+cstate.state[cstate.num-1].aspace; if (PicH>rt.bottom-rt.top-i) { PicH=rt.bottom-rt.top-i; PicW=PicH*Dx/Dy; } #if FIT { #else /* FIT */ if (pass==0) { msp->width=0; } else { #endif /* FIT */ ScopeStart(); fscanf(file,"%i",&n); /* number of objects */ for (i=0; i>1; ly=(ry+ly)>>1; LoadRect(&rt,PicX(lx)-MIN_R,PicY(ly)-MIN_R,PicX(lx)+MIN_R,PicY(ly)+MIN_R); } else LoadRect(&rt,PicX(lx),PicY(ly),PicX(rx),PicY(ry)); #undef MIN_R OffsetRect(&rt,msp->aleft,msp->atop); if (pn) { /* fill */ if (or.fill_color<0) InvertColors(); /* background */ else PicColor(or.fill_color); PaintOval(&rt); if (or.fill_color<0) InvertColors(); /* background */ PicColor(or.color); } FrameOval(&rt); break; case P_POLYLINE: fscanf(file,"%i",&pn); fscanf(file,"%i %i",&lx,&ly); lx=PicX(lx); ly=PicY(ly); for (j=1; jaleft,ly+msp->atop,rx+msp->aleft,ry+msp->atop); lx=rx; ly=ry; } break; case P_SPLINE: open=TRUE; goto spline; case -P_SPLINE: open=FALSE; spline: first=!open; fscanf(file,"%i",&pn); fscanf(file,"%g %g",&x1,&y1); fscanf(file,"%g %g",&x2,&y2); threshold=((Dx+0.0)/PicW*MAX(1,or.thickness>>1))*(fig_resolution/80); /* Borrowed from xfig sources, see u_draw.c */ cx1=(x1+x2)/2; cy1=(y1+y2)/2; cx2=(cx1+x2)/2; cy2=(cy1+y2)/2; #if FIT if (pass==1) #endif /* FIT */ if (open) myMoveTo(msp->aleft+PicX(round(x1)),msp->atop+PicY(round(y1))); for (j=2; j0) { FloatLo x1,y1,x2,y2,x3,y3,x4,y4,xmid,ymid; Pop(x1,y1,x2,y2,x3,y3,x4,y4); xmid=(x2+x3)/2; ymid=(y2+y3)/2; if (fabs(x1-xmid)aleft+PicX(round(x1)),msp->atop+PicY(round(y1))); myLineTo(msp->aleft+PicX(round(xmid)),msp->atop+PicY(round(ymid))); } else { Push(xmid,ymid,(xmid+x3)/2,(ymid+y3)/2,(x3+x4)/2,(y3+y4)/2,x4,y4); Push(x1,y1,(x1+x2)/2,(y1+y2)/2,(x2+xmid)/2,(y2+ymid)/2,xmid,ymid); } } cx1=cx4; cy1=cy4; cx2=(cx1+x2)/2; cy2=(cy1+y2)/2; } #if FIT if (pass==0) break; #endif /* FIT */ if (open) { myLineTo(msp->aleft+PicX(round(cx1)),msp->atop+PicY(round(cy1))); myLineTo(msp->aleft+PicX(round(x2)),msp->atop+PicY(round(y2))); } else { myLineTo(msp->aleft+PicX(round(cx4)),msp->atop+PicY(round(cy4))); } break; case P_TEXT: /* PicY(y) is a linea function! */ j=PicY(72*or.TEXT_font_size)*2.54/(fig_resolution/80); switch (or.TEXT_font) { case 1: sprintf(text,"times,%i,i",j); break; case 2: sprintf(text,"times,%i,b",j); break; case 3: sprintf(text,"times,%i,bi",j); break; case 32: sprintf(text,"symbol,%i",j); break; case 0: default: sprintf(text,"times,%i",j); break; } for (fontCur=fontCache; fontCur; fontCur=fontCur->next) if (!StrCmp(text,fontCur->name)) break; if (!fontCur) { fontCur=MemNew(sizeof(*fontCur)); fontCur->next=fontCache; fontCache=fontCur; fontCur->name=StringSave(text); fontCur->font=ParseFont(text); } #if FIT {{ MathState ms; long ftp; int x,y,lx,ly; Int2 h,l; enum Pcode { /* Preserve the position of : L-left, R-right, T-top, B-bottom, M-middle */ LT,LB,RT,RB, LM,RM,MT,MB,MM } base=LB; struct { Char tcode[3]; enum Pcode pcode; } Tab[]={ {{'l','t','\0'},LT}, {{'l','b','\0'},LB}, {{'r','t','\0'},RT}, {{'r','b','\0'},RB}, {{'l','m','\0'},LM}, {{'r','m','\0'},RM}, {{'m','t','\0'},MT}, {{'m','b','\0'},MB}, {{'m','m','\0'},MM} }; char c; fscanf(file,"%i %i %i %i %c",&ly,&lx,&x,&y,&c); if (c=='\\') { Char buf[3]; buf[0]=fgetc(file); buf[1]=fgetc(file); buf[2]='\0'; for (j=0; jaleft+PicX(x)-l; ms.atop=msp->atop+PicY(y)-h; if (pass==1) Math(&ms); if (ms.aleftaleft+PicW)>aR) aR=ms.aleft+ms.width-(msp->aleft+PicW); if (ms.atop+ms.height-(msp->atop+PicH)>aB) aB=ms.atop+ms.height-(msp->atop+PicH); fscanf(file,"%*[^\n]"); /* skip trailing $ */ } else { /* ASCII text */ ungetc(c,file); fscanf(file," %[^\n]",text); if (pass==0) break; SelectFont(fontCur->font); h=LineHeight(); l=StringWidth(text); switch (base) { case LT: y-=ly; l=0; break; case LB: l=h=0; break; case RT: x+=lx; y-=ly; break; case RB: x+=lx; h=0; } MoveTo(msp->aleft+PicX(x)-l,msp->atop+PicY(y)+h); PaintString(text); } }} #else /* FIT */ fscanf(file,"%*i %*i %i %i %[^\n]",&lx,&ly,text); SelectFont(fontCur->font); MoveTo(msp->aleft+PicX(lx),msp->atop+PicY(ly)); PaintString(text); #endif /* FIT */ break; case P_ARC: case -P_ARC: fscanf(file,"%i %i %i %i",&lx,&ly,&rx,&ry); LoadRect(&rt,PicX(lx),PicY(ly),PicX(rx)+1,PicY(ry)+1); OffsetRect(&rt,msp->aleft,msp->atop); fscanf(file,"%i %i %i %i",&lx,&ly,&rx,&ry); #if FIT if (pass==0) break; #endif /* FIT */ LoadPt(&ps,msp->aleft+PicX(lx),msp->atop+PicY(ly)); LoadPt(&pe,msp->aleft+PicX(rx),msp->atop+PicY(ry)); if (or.object_code==P_ARC) myFrameArc(&rt,ps,pe); else myFrameArc(&rt,pe,ps); break; } } ScopeEnd(); WidePen(0); Solid(); } fscanf(file,"%*[^\001]\001"); /* skip up to the end */ #if FIT if (aR) aR+=sysCharWidth/2; if (aB) aB+=sysLineHeight/2; msp->width=PicW-aL+aR; msp->height=PicH-aT+aB; #else msp->width=PicW; msp->height=PicH; #endif } #undef THRESHOLD #undef STACK_DEPTH #undef Push #undef Pop Local(long) stoppos; Local(Boolean) InDraw=FALSE; /* To prevent recursive call of DrawProc */ Callback(void) DrawProc(PaneL help) { #define level cstate.num long tpos,unfit; JumpDesc jumpdesc; Page lstate,ss,verbatimstate; MathState ms,mss; RecT r; int desclevel; Int2 descmax; Int2 w,h,lh,lw,base,bottom,curtab,stoplevel,tokens,extra,extra1,extraw,lines,iw; Int1 descpass; SpecialCode sc,sc_align; Uint1 savepass; Uchar token[500],c; Boolean pagego,linego,blank,par,lpar,stop; if (InDraw || TopicNum==0) return; else InDraw=TRUE; Select(hWindow); Select(help); GetPosition(help,&r); if (maxpass==2) { InvertColors(); InsetRect(&r,-MX,-1); PaintRect(&r); InsetRect(&r,MX,1); InvertColors(); MoveTo(r.left,r.top); LineTo(r.right,r.top); ClipRect(&r); } else stop=FALSE; topic=TopicStack+TopicCur; if (topic->num) CopyState(&cstate,topic->pages+topic->cur); else { topic->pages=MemNew(ARRAYSIZE(Page,1)); topic->num=1; CopyState(topic->pages,&cstate); } state=cstate.state+cstate.num-1; file=FileTable[cstate.file].stream; (topic->cur ? Enable : Disable)(bPgUp); fseek(file,cstate.filepos,SEEK_SET); setFont(state->font); setColor(state->color); BSFree(jumps); jumps=BSNew(5*sizeof(JumpDesc)); pagego=TRUE; par=state->parstart; w=r.left+state->lindent; /* just in case par==FALSE */ h=r.top; /* total height of processed lines */ h+=3; /* needed when a picture is at the top of page */ stoplevel=-1; desclevel=0; verbatim=0; MemFill(&verbatimstate,0,sizeof(verbatimstate)); lines=0; while (pagego) { for (pass=0; pass0) { extra1=extra%tokens; extra/=tokens; } else { extra=extra1=0; } extraw=0; } curtab=0; linego=TRUE; blank=FALSE; do { tpos=ftell(file); if (maxpass==1 && tpos>=stoppos) stop=TRUE; scope: fscanf(file," %c",token); token[1]='\0'; switch (*token) { case '{': /* start of scope */ ScopeStart(); continue; case '}': /* end of scope */ if (verbatim) goto def; ScopeEnd(); if (stoplevel==level) goto doalign; continue; case '$': /* math environment */ if (par) { if (pass==0) { h+=state->bspace; } par=FALSE; w=r.left+state->findent; } if (pass==1) { if (unfit==tpos) { fseek(file,tpos,SEEK_SET); linego=FALSE; break; } ms.aleft=w; ms.atop=h; } if (blank) { lw=StringWidth(" "); if (pass==1) { lw+=extra; extraw+=extra1; if (extraw>=tokens && tokens>0) { extraw-=tokens; lw++; } ms.aleft+=lw; w+=lw; } } Math(&ms); if (blank && pass==0) ms.width+=lw; if (w+ms.widthbottom) bottom=ms.height-ms.base; if (ms.base>base) base=ms.base; if (base+bottom>lh) lh=base+bottom; } else { /* already painted */ } w+=ms.width; } else { if (pass==0) { ms=mss; /* undo last formula which does not fit the line */ unfit=tpos; } fseek(file,tpos,SEEK_SET); linego=FALSE; } blank=TRUE; break; default: /* statement or ordinary token */ if (*token>(Uchar) SS_) { /* statement */ switch (sc=Statement(*token)) { case 0: continue; case SC_VERBATIM: tpos=ftell(file); if (pass==0) { CopyState(&verbatimstate,&lstate); } if (pass==0) h+=state->bspace; case SC_PAR: if (pass==0) { lh+=state->aspace; } par=TRUE; linego=FALSE; if (sc==SC_VERBATIM) goto def; break; case SC_TAB: if (desclevel) { if (descmax\par and \>\jump correctly */ *token=fgetc(file); if (*token!=(Uchar)SC_PAR) { ungetc(*token,file); #endif /*** sprintf((CharPtr)token,"%%*[^%c%c]%%c",(Uchar)SC_PAR,(Uchar)SC_JUMP);***/ sprintf((CharPtr)token,"%%*[^%c%c%c]%%c",(Uchar)SC_PAR,(Uchar)SC_JUMP,(Uchar)SC_INCLUDE); do { #if _UNIX /* process \>\par and \>\jump correctly */ c=fgetc(file); if (c==(Uchar)SC_PAR) break; if (c==(Uchar)SC_JUMP) goto jmp; if (c==(Uchar)SC_INCLUDE) goto jmp; ungetc(c,file); #endif fscanf(file,(CharPtr)token,&c); /* skip up to SC_PAR or SC_JUMP */ if (c==(Uchar)SC_PAR) break; #if _UNIX jmp:; #endif c=fgetc(file); if (c=='l') fseek(file,sizeof(long),SEEK_CUR); /* these may be any bytes, SC_PAR included */ } while (TRUE); #if _UNIX } #endif if (!--desclevel) goto descend; w=0; } else { if (par) { if (pass==0) h+=state->bspace; par=FALSE; } w=r.left+state->lindent+state->tab[curtab++]; if (curtab>=DIM(state->tab)) curtab=0; if (pass==0) tokens=0; } blank=FALSE; break; case SC_RIGHT: case SC_CENTER: sc_align=sc; fscanf(file," %c",token); ungetc(*token,file); if (*token!='{'){ break; /* no {, ignore */ } if (par) { if (pass==0) h+=state->bspace; par=FALSE; } if (maxpass==2) SaveState(&ss); savepass=pass; pass=0; w=0; stoplevel=level; goto scope; doalign: stoplevel=-1; pass=savepass; if (maxpass==2) RestoreState(&ss); w=sc_align==SC_RIGHT ? r.right-w : (r.left+r.right-w)/2; if (wlindent; par=FALSE; break; descend: pass=descpass; RestoreState(&ss); state->findent=state->lindent; state->lindent+=descmax+sysCharWidth; state->tab[0]=0; w=r.left+state->findent; par=TRUE; blank=FALSE; break; case SC_LI: if (desclevel>0) { w+=state->lindent; } break; case SC_END: if (pass==0 && maxpass==2) { linego=FALSE; par=TRUE; } else { topic->max=topic->num; Disable(bPgDn); if (cstate.num!=1) Message(MSG_OK,"Unclosed {"); FreeState(&lstate); goto ret; } break; case SC_PICTURE: ms.aleft=w; ms.atop=h; DrawPicture(&ms); w+=ms.width; lh=ms.height; if (w>=r.right && blank) { fseek(file,tpos,SEEK_SET); linego=FALSE; } break; case SC_JUMP: if (pass==1) { jumpdesc.filepos=ftell(file); jumpdesc.file=cstate.file; } /* now skip flag byte and key */ fscanf(file,"%c",token); /* flag */ if (*token=='l') fseek(file,sizeof(long),SEEK_CUR); else fscanf(file," %*s",token); if (blank) { token[0]=' '; iw=1; } else iw=0; fscanf(file," %c",token+iw); if (token[iw]=='{') fscanf(file,"%[^}]} ",token+iw); else fscanf(file,"%[^ \n\t] ",token+iw+1); if (par) { if (pass==0) h+=state->bspace; par=FALSE; w=r.left+state->findent; } ScopeStart(); setFont(JUMP_FONT); SelectColor(JumpColorR,JumpColorG,JumpColorB); goto proctoken; case SC_LEVEL: fscanf(file,"%s",token); if (level) { Char b[80]; sprintf(b,"\\level %s: %i (pass=%i)\n",token,(int)level,(int)pass); Message(MSG_OK,b); } break; default: fscanf(file," %c",token); /* just ignore \ */ goto def; } break; } else sc=(SpecialCode)0; def: /* ordinary token */ if (par) { if (pass==0) { if (verbatim==0) h+=state->bspace; } par=FALSE; w=r.left+state->findent; } if (verbatim>0) { fseek(file,tpos,SEEK_SET); setFont(PROG_FONT); if (pass==1) { verbatim--; fgets((CharPtr)token,sizeof(token),file); lw=(Int2)StrLen((CharPtr)token)-1; if (token[lw]=='\n') token[lw]='\0'; lh=lineHeight; base=lineHeight-lineDescent; if (verbatim==0) verbatim=12345; /* to process the last line */ } else { for (lw=verbatim; lw; lw--) fgets((CharPtr)token,sizeof(token),file); lh=(lineHeight)*verbatim; base=lh-lineDescent; } blank=FALSE; par=TRUE; linego=FALSE; goto proctoken; } if (blank && !StrChr(".,:;!?)]}",*token)) { token[2]='\0'; token[1]=token[0]; token[0]=' '; } while (TRUE) { #ifdef _UNIX_LNX fscanf(file, "%[a-zA-Z0-9+='\"(),.!?;:/|[-]",token+StrLen((CharPtr)token)); #else fscanf(file,"%[]a-zA-Z0-9+='\"(),.!?;:/|[-]",token+StrLen((CharPtr)token)); #endif /* _UNIX_LNX */ c=(Uchar)fgetc(file); #ifdef _UNIX_LNX if (c==']') { StrCat((CharPtr)token,"]"); continue; } #endif /* _UNIX_LNX */ if (c==SC_PS) { StrCat((CharPtr)token," "); continue; } if (c==SC_CAT) { Int2 l=StrLen((CharPtr)token); token[l]=(Char)fgetc(file); token[l+1]='\0'; continue; } ungetc(c,file); break; } proctoken: lw=StringWidth((CharPtr)token); if (w+lw=0 || desclevel) { if (pass==0) { tokens++; if (lineHeight>lh) { lh=lineHeight; base=lineHeight-lineDescent; if (base>ms.base) ms.base=base; } } else { if (blank) { w+=extra; extraw+=extra1; if (extraw>=tokens && tokens>0) { extraw-=tokens; w++; } } MoveTo(w,h+base); PaintString((CharPtr)token); if (sc==SC_JUMP) { LoadRect(&jumpdesc.area,w,h+base-lineAscent, w+lw,h+base+lineDescent); BSWrite(jumps,&jumpdesc,sizeof(jumpdesc)); MoveTo(w+(blank?StringWidth(" "):0),h+base+1); /* underline */ LineTo(w+lw,h+base+1); } } w+=lw; } else { fseek(file,tpos,SEEK_SET); linego=FALSE; } blank=TRUE; if (sc==SC_JUMP) ScopeEnd(); } /* switch */ } while (linego); if (pass==0) if (par) tokens=1; else extra=r.right-1-w; if (h+lhlindent; if (pass==1 || maxpass==1) { h+=lh; if (verbatim==0) lines++; } if (verbatim>0) { FreeState(&verbatimstate); } if (maxpass==1 || verbatim==12345) verbatim=0; if (maxpass==1) { FreeState(&lstate); if (stop) { maxpass=2; /* force to quit the loop in Repage */ goto ret; } } } else { if (verbatim>0) { FreeState(&lstate); RestoreState(&verbatimstate); /* to \verbatim */ } else RestoreState(&lstate); /* pass==0 */ pagego=FALSE; break; /* for */ } } /* for */ } /* while */ if (topic->cur+1==topic->num) { topic->pages=MemMore(topic->pages,ARRAYSIZE(Page,topic->num+1)); MemFill(topic->pages+topic->num,0,ARRAYSIZE(Page,1)); cstate.filepos=ftell(file); cstate.state[cstate.num-1].parstart=lpar; CopyState(topic->pages+topic->num,&cstate); topic->num++; } Enable(bPgDn); ret: InDraw=FALSE; #undef level } Local(void) InitCState(long filepos) { FreeState(&cstate); cstate.num=1; cstate.filepos=filepos; cstate.state=(StatePtr)MemNew(ARRAYSIZE(State,1)); cstate.state[0].font=TEXT_FONT; cstate.state[0].parstart=TRUE; cstate.state[0].bspace=Vdistance(0.5); /* Others are 0s */ } Local(void) ReadIndex(Int2 fi) { Int2 i; Char buf[300]; file=FileTable[fi].stream; rewind(file); fread(&FileTable[fi].n,sizeof(FileTable[fi].n),1,file); FileTable[fi].index=(HelpEntryPtr)MemNew(ARRAYSIZE(HelpEntry,FileTable[fi].n)); for (i=0; i0 && !StrCmp(key,TopicStack[TopicCur].title->key); } Local(void) AllocateTopic(void) { if (TopicNum>=MAXTOPIC) { FreeTopic(TopicStack); TopicCur=TopicNum-1; MemCopy(TopicStack,TopicStack+1,ARRAYSIZE(Topic,TopicCur)); } else { TopicCur=TopicNum; TopicStack=MemMore(TopicStack,ARRAYSIZE(Topic,++TopicNum)); } topic=TopicStack+TopicCur; MemFill(topic,0,sizeof(Topic)); InitCState(0); } Local(HelpEntryPtr) FarJump(CharPtr key, long * pos) { HelpEntryPtr hep; Int2 i,j; if (key && *key) { /* Is key a variable? */ if (*key=='*') /* \jump variable, look for its value */ for (i=0; i=FileTableNum) j=0; if (FileTable[j].stream) if ((hep=SearchIndex(j,key))!=NULL) { cstate.file=j; *pos=hep->pos; return hep; } } } return FarJump("kh_Empty",pos); } Local(JumpDesc) jdclick; Callback(void) ClickProc(PaneL panel, PoinT pt) { BSSeek(jumps,0,SEEK_SET); while (BSRead(jumps,&jdclick,sizeof(jdclick))==sizeof(jdclick)) if (PtInRect(pt,&jdclick.area)) { Select(panel); InvertMode(); Dotted(); SelectColor(JumpColorR,JumpColorG,JumpColorB); FrameRect(&jdclick.area); jdclick.file=1; return; } jdclick.file=0; } Callback(void) ReleaseProc(PaneL panel, PoinT pt) { HelpEntryPtr hep; JumpDesc jd; Char c,key[100]; BSSeek(jumps,0,SEEK_SET); while (BSRead(jumps,&jd,sizeof(jd))==sizeof(jd)) if (PtInRect(pt,&jd.area)) { AllocateTopic(); file=FileTable[jd.file].stream; fseek(file,jd.filepos,SEEK_SET); fscanf(file,"%c",&c); if (c=='l') { /* local jump */ cstate.file=jd.file; /* might be in INCLUDEed topic */ fread(&cstate.filepos,sizeof(cstate.filepos),1,file); hep=SearchIndexPos(cstate.file,cstate.filepos); } else { /* global jump */ fscanf(file," %[*a-zA-Z0-9_]",key); hep=FarJump(key,&cstate.filepos); } topic->title=hep; setTitle(TopicCur); DrawProc(panel); Enable(bBack); return; } if (jdclick.file) { Select(panel); InvertMode(); Dotted(); SelectColor(JumpColorR,JumpColorG,JumpColorB); FrameRect(&jdclick.area); } } Local(void) RepageTopic(void) { long beginptr; Int2 cur; cur=topic->cur; beginptr=topic->pages[0].filepos; if (curnum-1) if (topic->pages[cur+1].retstack) /* file may be different due to \include */ cstate.file=topic->pages[cur+1].retstack[0].file; stoppos=topic->pages[cur].filepos; FreeTopic(topic); InitCState(beginptr); if (cur) { maxpass=1; do { DrawProc(hPanel); /* mark out a page, don't draw */ topic->cur++; } while (maxpass==1 && topic->max==0); topic->cur--; maxpass=2; } topic->flags&=~TF_REPAGE; } Local(Boolean) IgnoreResize; #if _WIN #pragma argsused #endif Callback(void) ResizeProc(WindoW w) { RecT r; Int2 i,deltaW,deltaH; Select(hPanel); GetPosition(hWindow,&r); deltaW=(r.right-r.left)-(WinRect.right-WinRect.left); deltaH=(r.bottom-r.top)-(WinRect.bottom-WinRect.top); WinRect=r; PanRect.right+=deltaW; PanRect.bottom+=deltaH; Hide(hPanel); /* otherwise SetPosition would cause redraw */ SetPosition(hPanel,&PanRect); if (IgnoreResize && TopicNum==0) { /* the first entry after Show and there was no resize */ IgnoreResize=FALSE; } else { if (PanRect.right>PanRect.left && PanRect.bottom>PanRect.top) { for (i=0; ipages) RepageTopic(); } } Show(hPanel); } #if _WIN #pragma argsused #endif Callback(void) PgDnProc(ButtoN b) { if (!topic->max || topic->curmax-1) { #if _UNIX Select(hWindow); /* needed when PgDn after Search */ #endif topic->cur++; DrawProc(hPanel); } } #if _WIN #pragma argsused #endif Callback(void) PgUpProc(ButtoN b) { if (topic->cur) { #if _UNIX Select(hWindow); /* needed when PgUp after Search */ #endif topic->cur--; DrawProc(hPanel); } } #if _WIN #pragma argsused #endif Callback(void) BackProc(ButtoN b) { if (TopicCur) { #if _UNIX Select(hWindow); /* needed when PgBack after Search */ #endif FreeTopic(topic); FreeState(&cstate); /* DrawProc will fill cstate from the prev topic */ TopicStack=MemMore(TopicStack,ARRAYSIZE(Topic,--TopicNum)); TopicCur--; topic=TopicStack+TopicCur; if (topic->flags&TF_REPAGE) RepageTopic(); setTitle(TopicCur); DrawProc(hPanel); } (TopicCur ? Enable : Disable)(bBack); } typedef struct { /* desc of list's elem */ Int2 ss; /* subscript to FileTable[file].index */ Int1 fi; /* subscript to FileTable */ Boolean inlist; } ListElem, PNTR ListElemPtr; typedef struct { /* work data of Search callbacks */ LisT list; TexT text; ListElemPtr items; Int2 n; } SearchData, PNTR SearchDataPtr; Local(CharPtr) CondT; Local(int) CondI; Local(Boolean) CondExpr(void); Local(Boolean) CondFactor(void) { int pos; Int2 i; Boolean e; Char c,buf[100]; if (sscanf(CondT+CondI," %c%n",&c,&pos)==1) { if (c=='(') { CondI+=pos; e=CondExpr(); sscanf(CondT+CondI," %c%n",&c,&pos); /* must be ) */ CondI+=pos; return e; } if (sscanf(CondT+CondI," %[^=]=%n",buf,&pos)==1) { CondI+=pos; for (i=0; in; i++) if (dp->items[i].inlist) { li++; key=FileTable[dp->items[i].fi].index[dp->items[i].ss].extkey; if (StrStr(key,p)) { SetValue(dp->list,li); break; } } MemFree(p); } #if _WIN #pragma argsused #endif Callback(void) SearchCloseProc(ButtoN b) { /* don't use b! */ SearchDataPtr dp; dp=GetWindowExtra(hSearch); MemFree(dp->items); MemFree(dp); WriteWindowPos("W_HELPS",hSearch); Remove(hSearch); hSearch=NULL; if (b && hWindow) Select(hWindow); } Callback(void) SearchShowProc(ButtoN b) { SearchDataPtr dp; CharPtr keyptr; RecT r; Int2 i,li; dp=GetWindowExtra(ParentWindow(b)); li=GetValue(dp->list); if (!li) return; for (i=0; in; i++) if (dp->items[i].inlist) if (!--li) { keyptr=FileTable[dp->items[i].fi].index[dp->items[i].ss].key; if (SameTopic(keyptr)) return; AllocateTopic(); topic->title=FarJump(keyptr,&cstate.filepos); setTitle(TopicCur); break; } #if _WIN UseWindow(hWindow); #endif Select(hPanel); GetPosition(hPanel,&r); InvalRect(&r); Select(hWindow); Update(); Enable(bBack); } Callback(void) SearchListProc(LisT l) { SearchDataPtr dp; Int2 i,li; Boolean dbl=dblClick; /* it would not survive up to SearchShowProc call */ dp=GetWindowExtra(ParentWindow(l)); li=GetValue(l); if (li==0) return; for (i=0; in; i++) if (dp->items[i].inlist) if (!--li) break; SetTitle(dp->text,FileTable[dp->items[i].fi].index[dp->items[i].ss].extkey); if (dbl) { SearchShowProc((ButtoN)l); } } /* Several functions for search request processing. Called by SearchEOTProc */ typedef enum {SN_E,SN_T,SN_F} NodeKind; /* expr, term, factor */ typedef enum {SN_FE,SN_FN,SN_FT} FactorKind; /* (expr), !term, text */ typedef struct _SearchNode { struct _SearchNode PNTR next; union { struct { struct _SearchNode PNTR terms; } expr; struct { struct _SearchNode PNTR factors; } term; struct { union { struct _SearchNode PNTR expr; struct _SearchNode PNTR factor; CharPtr text; } ptr; FactorKind kind; } factor; } n; NodeKind kind; } SearchNode, PNTR SearchNodePtr; Local(CharPtr) Request; Local(SearchNodePtr) ParseSearchExpr(void); Local(SearchNodePtr) ParseSearchFactor(void) { SearchNodePtr factor,expr,nfactor; int pos; Char c,buf[PAR_BUF]; factor=(SearchNodePtr)MemNew(sizeof(SearchNode)); factor->kind=SN_F; if (sscanf(Request," %c%n",&c,&pos)==1) { switch (c) { case '(': Request+=pos; factor->n.factor.kind=SN_FE; expr=ParseSearchExpr(); if (!expr) goto error; factor->n.factor.ptr.expr=expr; if (sscanf(Request," %c%n",&c,&pos)==1 && c==')') Request+=pos; break; case '!': Request+=pos; factor->n.factor.kind=SN_FN; nfactor=ParseSearchFactor(); if (!nfactor) goto error; factor->n.factor.ptr.factor=nfactor; break; default: factor->n.factor.kind=SN_FT; if (sscanf(Request," %[^|&(!)]%n",buf,&pos)==1) { Request+=pos; StrTrim(buf); factor->n.factor.ptr.text=StringSave(buf); } else goto error; } } else goto error; return factor; error: return MemFree(factor); } Local(SearchNodePtr) ParseSearchTerm(void) { SearchNodePtr term,factor; int pos; Char c; term=(SearchNodePtr)MemNew(sizeof(SearchNode)); term->kind=SN_T; term->n.term.factors=ParseSearchFactor(); while (sscanf(Request," %c%n",&c,&pos)==1 && c=='&') { Request+=pos; factor=ParseSearchFactor(); if (!factor) break; factor->next=term->n.term.factors; term->n.term.factors=factor; } return term; } Local(SearchNodePtr) ParseSearchExpr(void) { SearchNodePtr expr,term; int pos; Char c; expr=(SearchNodePtr)MemNew(sizeof(SearchNode)); expr->kind=SN_E; expr->n.expr.terms=ParseSearchTerm(); while (sscanf(Request," %c%n",&c,&pos)==1 && c=='|') { Request+=pos; term=ParseSearchTerm(); if (!term) break; term->next=expr->n.expr.terms; expr->n.expr.terms=term; } return expr; } Local(SearchNodePtr) ParseSearchRequest(CharPtr request) { if (!request || *request=='\0') return NULL; Request=request; return ParseSearchExpr(); } Local(Boolean) MatchWithExpr(SearchNodePtr pr); Local(Boolean) MatchWithFactor(SearchNodePtr pr) { switch (pr->n.factor.kind) { case SN_FE: return MatchWithExpr(pr->n.factor.ptr.expr); case SN_FN: return !MatchWithFactor(pr->n.factor.ptr.factor); case SN_FT: return (Boolean)(StrStr(Request,pr->n.factor.ptr.text)!=NULL); } return TRUE; } Local(Boolean) MatchWithTerm(SearchNodePtr pr) { SearchNodePtr prw; for (prw=pr->n.term.factors; prw; prw=prw->next) if (!MatchWithFactor(prw)) return FALSE; return TRUE; } Local(Boolean) MatchWithExpr(SearchNodePtr pr) { SearchNodePtr prw; prw=pr->n.expr.terms; if (!prw) return TRUE; for (; prw; prw=prw->next) if (MatchWithTerm(prw)) return TRUE; return FALSE; } Local(Boolean) MatchWithSearchRequest(SearchNodePtr pr, CharPtr t) { if (!t || *t=='\0') return TRUE; if (!pr) return TRUE; Request=t; return MatchWithExpr(pr); } Local(void) FreeSearchRequest(SearchNodePtr pr) { if (pr) { FreeSearchRequest(pr->next); switch (pr->kind) { case SN_E: FreeSearchRequest(pr->n.expr.terms); break; case SN_T: FreeSearchRequest(pr->n.term.factors); break; case SN_F: switch (pr->n.factor.kind) { case SN_FE: FreeSearchRequest(pr->n.factor.ptr.expr); break; case SN_FN: FreeSearchRequest(pr->n.factor.ptr.factor); break; case SN_FT: MemFree(pr->n.factor.ptr.text); break; } break; } MemFree(pr); } } Callback(void) SearchEOTProc(ButtoN b) { /* The user has pressed Enter - recreate list */ SearchDataPtr dp; CharPtr p,q; SearchNodePtr pr; size_t len; Int2 i; dp=GetWindowExtra(ParentWindow(b)); len=TextLength(dp->text)+1; p=MemNew(len); GetTitle(dp->text,p,len); StrTrim(p); if (len>=PAR_BUF) p[PAR_BUF-1]='\0'; Hide(dp->list); Reset(dp->list); pr=ParseSearchRequest(p); for (i=0; in; i++) { q=FileTable[dp->items[i].fi].index[dp->items[i].ss].extkey; if (MatchWithSearchRequest(pr,q) && /*** StrStr(q,p) && ***/ *q!='-' && Condition(dp->items[i].fi,dp->items[i].ss)) { ListItem(dp->list,q); dp->items[i].inlist=TRUE; } else dp->items[i].inlist=FALSE; } Show(dp->list); MemFree(p); FreeSearchRequest(pr); SetValue(dp->list,1); Select(dp->list); } #ifdef WIN32 static int _USERENTRY ExtkeysCmp(const void * e1, const void * e2) { #else Entry(int) ExtkeysCmp(const void * e1, const void * e2) { #endif #define E1 ((ListElemPtr)e1) #define E2 ((ListElemPtr)e2) return StrICmp(FileTable[E1->fi].index[E1->ss].extkey, FileTable[E2->fi].index[E2->ss].extkey); #undef E1 #undef E2 } #if _WIN #pragma argsused #endif Callback(void) SearchProc(ButtoN b) { SearchDataPtr dp; CharPtr q; GrouP gm,g; ButtoN bo,bc; PoinT pt,pt1; RecT rb,r; Int2 i,j,k,n,space; if (hSearch) { Select(hSearch); return; } dp=MemNew(sizeof(SearchData)); ReadWindowPos("W_HELPS",&i,&j); hSearch=FixedWindow(i,j,-sysCharWidth,-sysLineHeight,"Help topic search",NULL); SetWindowExtra(hSearch,dp,NULL); gm=HiddenGroup(hSearch,0,5,NULL); SetGroupSpacing(gm,0,sysLineHeight); dp->text=DialogText(gm,"",28,SearchTextProc); dp->list=SingleList(gm,30,20,SearchListProc); for (i=n=0; in=n; dp->items=MemNew(ARRAYSIZE(ListElem,n)); for (i=k=0; iitems[k].ss=j; dp->items[k].fi=i; dp->items[k].inlist=TRUE&&Condition(i,j); } qsort(dp->items,n,ARRAYSIZE(ListElem,1),ExtkeysCmp); for (i=0; iitems[i].fi].index[dp->items[i].ss].extkey; if (*q!='-' && dp->items[i].inlist) ListItem(dp->list,q); else dp->items[i].inlist=FALSE; } g=HiddenGroup(gm,3,0,NULL); GetNextPosition(g,&pt); LoadPt(&pt1,-1000,-1000); SetNextPosition(g,pt1); DefaultButton(g,"",SearchEOTProc); /* put it outside window */ SetNextPosition(g,pt); bo=PushButton(g,"Show topic",SearchShowProc); bc=PushButton(g,"Close",SearchCloseProc); AlignObjects(ALIGN_RIGHT,(HANDLE)dp->text,(HANDLE)dp->list,NULL); GetPosition(gm,&r); space=r.right-r.left; GetPosition(bc,&r); space-=r.right-r.left; GetPosition(bo,&rb); space-=rb.right-rb.left; space/=3; OffsetRect(&rb,space,0); SetPosition(bo,&rb); OffsetRect(&r,2*space,0); SetPosition(bc,&r); Show(hSearch); Select(hSearch); /* Motif: make is current */ SelectText(dp->text,0,0); } Entry(Int2) ConthelpKey(CharPtr key); #if _WIN #pragma argsused #endif Callback(void) HelpProc(ButtoN b) { ConthelpKey("kh_HelpWin"); } /*********************************************************/ Local(Boolean) initialized=FALSE; /* Initializes help subsystem. Called once after loading */ Entry(Int2) ConthelpInit(CharPtr files) { CharPtr p,q,r; GrouP gB; Int2 i,h,w; double rw,rh; if (initialized) return 1; initialized=TRUE; FileTable=MemNew(ARRAYSIZE(FileElem,1)); q=StringTok(files," "); if (StringChr(q,DIRDELIMCHR)) FileTable[0].name=StringSave(q); else { r=StringCat(GetParamString(SFS_PATHS,"KERNEL"),q); FileTable[0].name=StringSave(r); } for (FileTableNum=1; q=StringTok(NULL," "), q!=NULL; FileTableNum++) { FileTable=MemMore(FileTable,ARRAYSIZE(FileElem,FileTableNum+1)); if (StringChr(q,DIRDELIMCHR)) FileTable[FileTableNum].name=StringSave(q); else { r=StringCat(GetParamString(SFS_PATHS,"KERNEL"),q); FileTable[FileTableNum].name=StringSave(r); } } for (i=0; ipos); cstate.file=i; #if _UNIX /* Motif: XSetInputFocus in Select(window) (when HelpKey is called right after HelpInit) causes X Error of failed request: BadMatch (invalid parameter attributes) Major opcode of failed request: 42 (X_SetInputFocus) Serial number of failed request: 3042 Current serial number in output stream: 3043 */ if (hWindow!=CurrentWindow()) #endif /* #if _UNIX */ Select(hWindow); Select(hPanel); GetPosition(hPanel,&r); InvalRect(&r); Update(); (TopicCur ? Enable : Disable)(bBack); break; } } return ret; } /* Shows the search dialog box if it is not shown already */ #if _WIN #pragma argsused #endif Entry(Int2) ConthelpSearch(VoidPtr dummy) { if (hSearch) { Select(hSearch); } else { SearchProc(0); } return 0; } /* Sets the value of a help-variable */ Entry(Int2) ConthelpSetVar(CharPtr var, CharPtr value) { Int2 i; if (JumpVarTableNum) { for (i=0; i