// twinfo.c // // by John D. de Boer #include "twist.h" // Initialisation void InitInfoPara(InfoPara *D) { if (!D) return; D->link=(InfoLink **)handle(0); D->links=0; D->text=NULL; D->len=0; D->tlen=0; } void PurgeInfoPara(InfoPara *D) { if (!D) return; release(D->link); D->link=NULL; D->links=0; old(D->text); D->text=NULL; D->len=0; D->tlen=0; } // void CheckInfoText(const void *VFrom, string S, const Span *L, bool GenErr) { char *At1,*At2,*At3,*Blue,*HL,*Temp; void *VTo; if (!S) return; //AddInfoText(D,"\t",0); while (S) { At1=firstocc('@',S); if (!At1) { /*AddInfoTextOld(D,S,1);*/ old(S); return; } At2=firstocc('@',At1 + 1); if (At2) At3=firstocc('@',At2 + 1); else At3=NULL; //Left=leftstr(S,At1 - S); AddInfoTextOld(D,Left,0); if (At2) Blue=leftstr(At1 + 1,At2 - At1 - 1); else Blue=copyof(At1 + 1); if (At3) { if (At3 - At2 > 1) HL=leftstr(At2 + 1,At3 - At2 - 1); else HL=copyof(Blue); } else if (At2) HL=copyof(At2 + 1); else HL=NULL; Temp=S; if (At3) S=copyof(At3 + 1); else S=NULL; old(Temp); VTo=NULL; if (HL) { VTo=FindPerson(HL,L,0,VFrom); if (!VTo) VTo=FindEvent(HL,L,0,VFrom); if (!VTo && GenErr) FindPerson(HL,L,1,VFrom); AddLinkIn(VTo,VFrom); } //if (Blue) { if (VTo) AddInfoLink(D,Blue,0,VTo); else AddInfoText(D,Blue,0); } old(Blue); old(HL); /*if (!S) InfoCR(D);*/ } } // Preparing info static void AddInfoText(InfoPara *D, char *A, bool CR) { if (!D || !A) return; D->text=cat(1,D->text,A); if (CR) D->text=cat(1,D->text,"\n"); } static void AddInfoTextOld(InfoPara *D, string A, bool CR) { AddInfoText(D,A,CR); old(A); } static void NewLink(InfoPara *D, int ST, int END, void *VTo) { InfoLink L; if (!D) return; L.start=ST; L.end=END; L.link=VTo; minimumsize(D->link,D->links + 1,sizeof(InfoLink)); (*(D->link))[D->links++]=L; } static void AddInfoLink(InfoPara *D, char *A, bool CR, void *VTo) { int L1,L2; if (!D || !A) return; L1=length(D->text); L2=length(A); AddInfoText(D,A,CR); NewLink(D,L1,L1 + L2,VTo); } static void InfoCR(InfoPara *D) { if (!D) return; D->text=cat(1,D->text,"\n"); } static void DoInfoText(InfoPara *D, string S, const Span *L) { char *At1,*At2,*At3,*Left,*Blue,*HL,*Temp; void *VTo; if (!D || !S) return; AddInfoText(D,"\t",0); while (S) { At1=firstocc('@',S); if (!At1) { AddInfoTextOld(D,S,1); return; } At2=firstocc('@',At1 + 1); if (At2) At3=firstocc('@',At2 + 1); else At3=NULL; Left=leftstr(S,At1 - S); AddInfoTextOld(D,Left,0); if (At2) Blue=leftstr(At1 + 1,At2 - At1 - 1); else Blue=copyof(At1 + 1); if (At3) { if (At3 - At2 > 1) HL=leftstr(At2 + 1,At3 - At2 - 1); else HL=copyof(Blue); } else if (At2) HL=copyof(At2 + 1); else HL=NULL; Temp=S; if (At3) S=copyof(At3 + 1); else S=NULL; old(Temp); VTo=NULL; if (HL) { VTo=FindPerson(HL,L,0,NULL); if (!VTo) VTo=FindEvent(HL,L,0,NULL); //if (!VTo && GenErr) { FindPerson(HL,L,1); } /*AddLinkIn(VTo,VFrom);*/ } if (Blue) { if (VTo) AddInfoLink(D,Blue,0,VTo); else AddInfoText(D,Blue,0); } old(Blue); old(HL); if (!S) InfoCR(D); } } // Date strings for info boxes static bool FirstBC; // whether the person was born, or the event started, in the first century B.C. static void SetFirstBC(const Day *D) { short YEAR; FirstBC=0; if (!D) return; jdtodate(D->jd,&YEAR,NULL,NULL); FirstBC=interval(YEAR,-100,-1); } // Preparing person info static string BornStr(const Person *P, bool Circa) { char *S; Place *C; if (P->life.start.guess) S=NULL; else S=cat(2,"Born: ",DateStr(&(P->life.start),1,FirstBC,Circa)); C=P->pob; if (C) { if (!S) S=copyof("Born"); if (firstocc(',',S)) S=cat(1,S,","); S=cat3(1,S," in ",C->name); } if (S) S=cat(1,S,"\n"); return S; } static string DiedStr(const Person *P, bool Circa, char *Died) { char *S; Place *C; if (P->life.end.kind!=timeJD || P->life.end.guess) S=NULL; else S=cat3(4,P->trans ? "Translated" : Died,": ",DateStr(&(P->life.end),P->life.start.guess,FirstBC,Circa)); C=P->pod; if (C) { if (!S) S=copyof(Died); if (firstocc(',',S)) S=cat(1,S,","); S=cat3(1,S," in ",C->name); } if (S) S=cat(1,S,"\n"); return S; } static string NatStr(const Person *P) { Place *N,*C; char *S; if (!P) return NULL; S=NULL; N=P->nation; if (N && N->adj) S=cat3(0,"Nationality: ",N->adj,"\n"); C=P->home; if (C && C!=N) S=cat4(1,S,"Lived in: ",C->name,"\n"); return S; } static void DoParStr(InfoPara *D, char *T, Person *P) { if (!D || !T || !P) return; AddInfoText(D,T,0); AddInfoLink(D,P->name,1,P); } static void DoMarrStr(InfoPara *D, Wedding *W) { Person *P; bool Comma; if (!D || !W) return; P=W->to; AddInfoText(D,"Married to: ",0); if (P) AddInfoLink(D,P->name,0,P); else AddInfoText(D,W->spref,0); Comma=0; if (W->on.kind==timeJD) { AddInfoText(D,W->on.unc==0 ? " on " : " in ",0); AddInfoText(D,DateStr(&(W->on),0,FirstBC,0),0); if (W->on.unc==0) Comma=1; } if (W->at) { AddInfoText(D,Comma ? ", in " : " in ",0); AddInfoText(D,W->at->name,0); } InfoCR(D); } static string OccStr(const Person *P) { int i,N; char *List; N=0; List=NULL; for (i=0;inocc;i++) { char *S; S=OccName(P->occ[i]); if (streqci(S,"other")) continue; if (streqci(S,"family")) continue; N++; if (N==1) List=copyof(S); else List=cat3(1,List,", ",S); } if (!List) return NULL; return cat3(2,N==1 ? "Occupation: " : "Occupations: ",List,"\n"); } static char *PowerWord(int HOW) { switch (HOW) { case powAcceeded: return "Acceded: "; case powAppointed: return "Appointed: "; case powTook: return "Assumed power: "; case powElected: return "Elected: "; case powAbdicated: return "Abdicated: "; case powDeposed: return "Deposed: "; case powRetired: return "Retired from office: "; } return NULL; } static string OfficeStr(int HOW, const Day *D) { char *W; W=PowerWord(HOW); if (!W) return NULL; if (!D || D->kind!=timeJD) return NULL; return cat3(2,W,DateStr(D,0,FirstBC,0),"\n"); } static string OfficeStrs(const Person *P) { int i; char *S,*T; if (!P) return NULL; S=NULL; for (i=0;inrgn;i++) { T=OfficeStr(P->pow[i],&(P->reign[i].start)); if (T) S=cat(1,S,T); T=OfficeStr(P->ret[i],&(P->reign[i].end )); if (T) S=cat(1,S,T); } return S; } static void DoRelatedInfo(InfoPara *D, const listoflinks *L) { int i,j; bool Started,Above; void *VFrom; char *S; if (!D || !L) return; Started=0; for (i=0;inum;i++) { VFrom=(*(L->link))[i]; Above=0; for (j=0;jlinks;j++) if ((*(D->link))[j].link==VFrom) { Above=1; break; } if (Above) continue; if (!Started) AddInfoText(D,"Related Items:",1); Started=1; S= VoidIsPers(VFrom) ? ((Person *)VFrom)->name : ((Event *)VFrom)->name; AddInfoText(D,"\t",0); AddInfoLink(D,S,1,VFrom); } if (Started) InfoCR(D); } void MakePersInfo(const Person *P, InfoPara *D) { int i; char *S; if (!P || !D) return; AddInfoText(D,P->name,1); if (P->aka) AddInfoTextOld(D,cat(0,"a.k.a.: ",P->aka),1); D->tlen=length(D->text); InfoCR(D); SetFirstBC(&(P->life.start)); AddInfoTextOld(D,cat(3,BornStr(P,0),DiedStr(P,0,"Died")),1); S=cat(3,NatStr(P),OccStr(P)); AddInfoTextOld(D,S,1); DoParStr(D,P->fagrand ? "Paternal ancestor: " : "Father: ",P->father); DoParStr(D,P->mogrand ? "Maternal ancestor: " : "Mother: ",P->mother); if (P->father || P->mother) InfoCR(D); for (i=0;inmarr;i++) DoMarrStr(D,(*(P->wed))[i]); if (P->nmarr) InfoCR(D); AddInfoTextOld(D,OfficeStrs(P),1); if (P->info) { DoInfoText(D,copyof(P->info),&(P->life)); InfoCR(D); } DoRelatedInfo(D,&(P->inbnd)); if (P->ref) AddInfoTextOld(D,cat(0,"Reference: ",P->ref),1); if (P->src) AddInfoTextOld(D,cat(0,"Source file: ",P->src),1); D->len=length(D->text); } // Info for HTML pages static string HTMLName(Person *P) { char *S; if (!P) return NULL; S=copyof(P->name); if (P->genser>0) S=cat5(10,"genser),"\">",S,""); return S; } static string ParentString(Person *P, char *Rel) { if (!P) return NULL; return cat3(2,Rel,HTMLName(P),"\n"); } static string MarriageString(Wedding *W) { Person *P; char *S; bool Comma; if (!W) return NULL; P=W->to; S=cat(2,"Married to: ",P ? HTMLName(P) : copyof(W->spref)); Comma=0; if (W->on.kind==timeJD) { S=cat(1,S,W->on.unc==0 ? " on " : " in "); S=cat(1,S,DateStr(&(W->on),0,FirstBC,1)); if (W->on.unc==0) Comma=1; } if (W->at) { S=cat3(1,S,Comma ? ", in " : " in ",W->at->name); } return cat(1,S,"\n"); } static char *startoffirsturl(const char *S) { char *P; if (!S) return NULL; while (1) { P=firstocc('.',S); if (!P) return NULL; if (P>S && letter(P[-1]) && letter(P[1])) break; S= P + 1; } while (P>S && P[-1]!=' ' && P[-1]!=';') P--; return P; } static char *endofurl(const char *S) { if (!S) return NULL; while (S[0]!=0 && S[0]!=' ' && S[0]!=';') S++; return (char *)S; } static string HTMLRef(const char *R) { char *B,*E,*S; if (!R) return NULL; S=NULL; while (R) { B=startoffirsturl(R); if (!B) { S=cat(1,S,(char *)R); return S; } E=endofurl(B); if (!E) return S; S=cat4(5,S,""); S=cat3(3,S,leftstr(B,E - B),"\n"); R=E; } return S; } // should never get here string MakeHTMLInfo(const Person *P) { int i; char *S,*R; if (!P) return NULL; S=NULL; if (P->aka) S=cat3(0,"a.k.a.: ",P->aka,"\n"); SetFirstBC(&(P->life.start)); S=cat3(7,S,BornStr(P,1),DiedStr(P,1,"Passed away")); S=cat(1,S,"\n"); R=ParentString(P->father,P->fagrand ? "Paternal ancestor: " : "Father: "); if (R) S=cat(3,S,R); R=ParentString(P->mother,P->mogrand ? "Maternal ancestor: " : "Mother: "); if (R) S=cat(3,S,R); if (P->father || P->mother) S=cat(1,S,"\n"); for (i=0;inmarr;i++) S=cat(3,S,MarriageString((*(P->wed))[i])); if (P->nmarr) S=cat(1,S,"\n"); //AddInfoTextOld(D,OfficeStrs(P),1); //if (P->info) { DoInfoText(D,copyof(P->info),&(P->life)); InfoCR(D); } //DoRelatedInfo(D,&(P->inbnd)); if (P->ref) S=cat4(1,S,"References:\n",HTMLRef(P->ref),"\n"); i=length(S); if (i>0) S[i - 1]=0; replace(&S,"\n","
\n"); return S; } // Preparing event content static string StartStr(const Event *E) { return cat3(2,ZeroSpan(&(E->date)) ? "Date: " : "Start: ",DateStr(&(E->date.start),1,FirstBC,0),"\n"); } static string EndStr(const Event *E) { if (ZeroSpan(&(E->date))) return NULL; return cat3(2,"End: ",DateStr(&(E->date.end),0,FirstBC,0),"\n"); } static string TwoTravStr(const Travels *T) { Place *C1,*C2; if (!T || T->num!=2 || !T->ad) return NULL; C1=(*(T->ad))[0].city; C2=(*(T->ad))[1].city; return cat5(0,"Location: ",C1->name,"/",C2->name,"\n"); } static string PlaceStr(const Event *E) { Place *C; char *S; if (!E) return NULL; if (E->trav) { S=TwoTravStr(E->trav); if (S) return S; } C=E->place; if (C) return cat3(0,"Location: ",C->name,"\n"); return NULL; } static string EventCats(const Event *E) { int i; string S; if (!E || E->ntype<1) return NULL; S=copyof(E->ntype==1 ? "Event category: " : "Event categories: "); for (i=0;intype;i++) { if (i>0) S=cat(1,S,", "); S=cat(1,S,TypeName(E->type[i])); } return cat(1,S,"\n"); } void MakeEventInfo(const Event *E, InfoPara *D) { if (!E || !D) return; AddInfoText(D,E->name,1); if (E->aka) AddInfoTextOld(D,cat(0,"a.k.a.: ",E->aka),1); D->tlen=length(D->text); InfoCR(D); SetFirstBC(&(E->date.start)); AddInfoTextOld(D,cat(3,StartStr(E),EndStr(E)),1); AddInfoTextOld(D,PlaceStr(E),1); if (E->info) { DoInfoText(D,copyof(E->info),&(E->date)); InfoCR(D); } DoRelatedInfo(D,&(E->inbnd)); if (E->ref) AddInfoTextOld(D,cat(0,"Reference: ",E->ref),1); AddInfoTextOld(D,EventCats(E),0); if (E->src) AddInfoTextOld(D,cat(0,"Source file: ",E->src),1); D->len=length(D->text); }