// tttitem.c // // by John D. de Boer #include "twist.h" #include "ttt.h" extern string FileName; extern FSRef *FileRef; extern bool Verbose; // Parsing geographic locations (#c) static void ParsePlace(const char *S, const ParseDefaults *PD) { Place *C,*Former; int T; char *F; if (!S || !*S || !PD) return; C=NewPlace(!PD->delta); if (!C) return; while (S) { T=FirstField(&F,&S); switch (T) { case fName: C->name=copyof(F); break; case fAka: C->aka=copyof(F); break; case fGeoRef: ParseGeoRef(&(C->loc),F); break; case fRadius: C->rad=value(F); break; case fNation: C->adj=copyof(F); break; case fFlag: C->flag=LoadImage(F,FileRef); break; case fRegion: C->sup=FindPlace(F); if (C->sup) C->sup->hassub=1; break; case fReplace: if (PD->delta) break; Former=FindPlace(F); if (Former) Former->rep=C; break; case fColour: ParseColour(&(C->rgb),F); break; case fWater: C->water=1; break; default: if (Verbose) WarnOld(cat(0,"Inapplicable field for a place: ",F)); break; } old(F); } if (PD->delta) CheckPlaceDelta(C); else VerifyNewPlace(C); } // Parsing people (#p) static void ParsePersonDate(const char *S, bool AD, const Day *A, Day *D) { if (begins(S,"age ")) ParseRelDate(S + 4,A,D); else ParseDate(S,AD,D); } static void AddItineraryDate(Travels *T, const Day *D, int TYPE) { if (!T || !D) return; switch (TYPE) { case fDepart: AddDeparture(T,D); break; case fArrive: AddArrival(T,D); break; case fMove: AddDeparture(T,D); AddArrival(T,D); break; } } static Place *ParseWaypoint(const char *S) { GeoRef G; if (!S || !*S) return NULL; ParseGeoRef(&G,S); if (!G.good) return NULL; return CreateWaypoint(&G); } static void AddPowerPeriod(Person *C, const char *F, const ParseDefaults *PD, int HOW) { Span *Sp; if (!range(C->nrgn,MAXREIGN)) return; Sp= C->reign + C->nrgn; InitDay(&(Sp->end)); ParsePersonDate(F,PD->ad,&(C->life.start),&(Sp->start)); C->pow[C->nrgn]=HOW; C->ret[C->nrgn]=powDied; C->nrgn++; } static void EndPowerPeriod(Person *C, const char *F, const ParseDefaults *PD, int HOW) { int RGN; RGN= C->nrgn - 1; if (!range(RGN,MAXREIGN)) return; ParsePersonDate(F,PD->ad,&(C->life.start),&(C->reign[RGN].end)); C->ret[RGN]=HOW; } static void ParsePerson(const char *S, const ParseDefaults *PD) { Person *C; int T; char *F,*SC,*SC2; Day D,*Birth; bool Fem; Place *Pl; if (!S || !*S || !PD) return; C=NewPerson(!PD->delta); if (!C) return; C->src=copyof(FileName); Birth=&(C->life.start); while (S) { T=FirstField(&F,&S); if (T==fDate) T=fDied; switch (T) { case fName: C->name=copyof(F); break; case fFemale: C->sex='F'; break; case fAka: C->aka=copyof(F); break; case fInfo: repentity(F); C->info=copyof(F); break; case fRef: C->ref=copyof(F); break; case fSurname: C->surname=copyof(F); break; case fBorn: SC=firstocc(';',F); if (SC) { *SC=0; SC++; while (*SC==' ') SC++; C->pob=FindPlace(SC); } ParseDate(F,PD->ad,Birth); break; case fGeneration: if (!C->father && !C->mother) break; D= C->father ? C->father->life.start : C->mother->life.start; ParseRelDate(F,&D,Birth); break; case fDied: SC=firstocc(';',F); if (SC) { *SC=0; SC++; while (*SC==' ') SC++; C->pod=FindPlace(SC); } ParsePersonDate(F,PD->ad,Birth,&(C->life.end)); break; case fTrans: ParsePersonDate(F,PD->ad,Birth,&(C->life.end)); C->trans=1; break; case fAcceded: AddPowerPeriod(C,F,PD,powAcceeded); break; case fAppointed: AddPowerPeriod(C,F,PD,powAppointed); break; case fPower: AddPowerPeriod(C,F,PD,powTook); break; case fElected: AddPowerPeriod(C,F,PD,powElected); break; case fAbdicate: EndPowerPeriod(C,F,PD,powAbdicated); break; case fDeposed: EndPowerPeriod(C,F,PD,powDeposed); break; case fRetired: EndPowerPeriod(C,F,PD,powRetired); break; case fMarriage: SC=firstocc(';',F); D.kind=timeInval; Pl=NULL; if (SC) { *SC=0; SC++; while (*SC==' ') SC++; SC2=firstocc(';',SC); if (SC2) { *SC2=0; SC2++; while (*SC2==' ') SC2++; Pl=FindPlace(SC2); } ParsePersonDate(SC,PD->ad,Birth,&D); } AddMarriage(C,copyof(F),D,Pl); break; case fFather: C->faref=copyof(F); ResolveFather(C,0); break; case fMother: C->moref=copyof(F); ResolveMother(C,0); break; case fPatAnc: C->faref=copyof(F); C->fagrand=1; ResolveFather(C,0); break; case fMatAnc: C->moref=copyof(F); C->mogrand=1; ResolveMother(C,0); break; case fOccup: AddOccupation(C,ParseOccupation(F,&Fem)); if (Fem) C->sex='F'; break; case fNation: C->nation=FindPlace(F); break; case fCity: if (C->trav) AddStop(C->trav,FindPlace(F)); else C->home=FindPlace(F); break; case fGeoRef: if (C->trav) AddStop(C->trav,ParseWaypoint(F)); else C->home=ParseWaypoint(F); break; case fDepart: case fArrive: case fMove: if (!C->trav) { Pl= C->home ? C->home : C->nation; //if (!Pl) break; C->trav=NewTravels(Pl); } ParsePersonDate(F,PD->ad,Birth,&D); AddItineraryDate(C->trav,&D,T); break; case fPict: C->pict=NewPictureReference(F,FileRef); break; case fCaption: repentity(F); C->cap=copyof(F); break; default: if (Verbose) WarnOld(cat(0,"Inapplicable field for a person: ",F)); break; } old(F); } if (PD->delta) CheckPersonDelta(C); else VerifyNewPerson(C); } // Parsing historical events (#e) static void ParseEvent(const char *S, const ParseDefaults *PD) { Event *C; int T; char *F; Day D; if (!S || !*S || !PD) return; C=NewEvent(!PD->delta); if (!C) return; C->src=copyof(FileName); while (S) { T=FirstField(&F,&S); if (T==fDied) T=fDate; switch (T) { case fDate: ParseDate(F,PD->ad,&(C->date.start)); break; case fEnd: ParseDate(F,PD->ad,&(C->date.end)); break; case fName: repentity(F); C->name=copyof(F); break; case fAka: repentity(F); C->aka=copyof(F); break; case fPerson: C->persref=copyof(F); ResolveEventPerson(C,0); break; case fType: AddType(C,ParseType(F)); break; case fInfo: repentity(F); C->info=copyof(F); break; case fRef: C->ref=copyof(F); break; case fCity: if (C->trav) AddStop(C->trav,FindPlace(F)); else C->place=FindPlace(F); break; case fGeoRef: if (C->trav) AddStop(C->trav,ParseWaypoint(F)); else C->place=ParseWaypoint(F); break; case fDepart: case fArrive: case fMove: if (!C->trav) C->trav=NewTravels(C->place); ParseDate(F,PD->ad,&D); AddItineraryDate(C->trav,&D,T); break; case fPict: C->pict=NewPictureReference(F,FileRef); break; case fCaption: repentity(F); C->cap=copyof(F); break; default: if (Verbose) WarnOld(cat(0,"Inapplicable field for an event: ",F)); break; } old(F); } if (PD->delta) CheckEventDelta(C); else VerifyNewEvent(C); } // Parsing historical spheres (#s) static void ParseSphere(const char *S, const ParseDefaults *PD) { Sphere *C; Day D; vectorpoly **P; int T; char *F; if (!S || !*S || !PD) return; C=NewSphere(!PD->delta); if (!C) return; while (S) { T=FirstField(&F,&S); if (T==fDied) T=fDate; switch (T) { case fName: C->name=copyof(F); break; case fGeoRef: ParseGeoRef(&(C->loc),F); break; case fRadius: C->rad=value(F); break; case fColour: ParseColour(&(C->rgb),F); break; case fDate: ParseDate(F,PD->ad,&D); NewSphereDate(C,&D); break; case fEnd: ParseDate(F,PD->ad,&D); SphereEndDate(C,&D); break; case fPolygon: P=ParsePolygon(F,FileRef); if (P) AddPolyToSphere(C,P); break; default: if (Verbose) WarnOld(cat(0,"Inapplicable field for a sphere: ",F)); break; } old(F); } if (PD->delta) CheckSphereDelta(C); else VerifyNewSphere(C); } // Parsing "People" and "Events" menu items (#item) static void ParseMenuItem(const char *S, const ParseDefaults *PD) { FilterItem *C; int T; char *F; colour RGB; if (!S || !*S) return; if (PD->delta) return; C=NewFilterItem(); if (!C) return; while (S) { T=FirstField(&F,&S); switch (T) { case fName: FilterItemName(C,F); break; case fOccup: C->people=1; FilterItemMember(C,F); break; case fType: C->people=0; FilterItemMember(C,F); break; case fAka: FilterItemMemberSynonym(C,F); break; case fIcon: FilterItemMemberIcon(C,LoadImage(F,FileRef)); break; case fOff: FilterItemOff(C); break; case fFemale: FilterItemMemberFemale(C); break; case fColour: ParseColour(&RGB,F); FilterItemMemberColour(C,&RGB); break; default: if (Verbose) WarnOld(cat(0,"Inapplicable field for a menu item: ",F)); break; } old(F); } VerifyNewFilterItem(C); } // Parsing map records (#map) static void ParseMap(const char *S, const ParseDefaults *PD) { vectorpolys **C; int T; char *F; if (!S || !*S) return; if (PD->delta) return; while (S) { T=FirstField(&F,&S); switch (T) { case fPolygon: C=ParsePolygons(F,FileRef); if (C) UsePolys(C); break; default: if (Verbose) WarnOld(cat(0,"Inapplicable field for a map item: ",F)); break; } old(F); } } // Parsing items in .ttt files void ParseElement(const char *S, const ParseDefaults *PD) { char *F; long L; if (!S || !*S) return; F=firstoccoflist(" <",S); if (!F) return; L= F - S; if (L<1) return; F=leftstr(S,L); S+=L; while (*S==' ') S++; if (abbrev(F,L,"city", 1)) ParsePlace(S,PD); else if (abbrev(F,L,"person",1)) ParsePerson(S,PD); else if (abbrev(F,L,"event", 1)) ParseEvent(S,PD); else if (abbrev(F,L,"sphere",1)) ParseSphere(S,PD); else if (abbrev(F,L,"item" ,1)) ParseMenuItem(S,PD); else if (abbrev(F,L,"map" ,1)) ParseMap(S,PD); else WarnOld(cat3(0,"Unknown element markup: \"#",F,"\"")); old(F); }