home *** CD-ROM | disk | FTP | other *** search
/ The Best Internet Programs / BESTINTERNET.bin / latest / ged2ht20 / database.c next >
Encoding:
C/C++ Source or Header  |  1995-04-07  |  12.1 KB  |  574 lines

  1. /*
  2.  * Build lineage-linked database from lines of GEDCOM file.
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <ctype.h>
  9. #include "node.h"
  10. #include "database.h"
  11. #include "index.h"
  12. #include "tags.h"
  13.  
  14. /*
  15.  * Counts of various kinds of top-level records
  16.  */
  17.  
  18. int total_individuals;
  19. int total_families;
  20. int total_events;
  21. int total_sources;
  22. int total_notes;
  23. int total_repositories;
  24. int total_submitters;
  25.  
  26. /*
  27.  * Flag controlling capitalization of surnames
  28.  */
  29.  
  30. int capitalization = 1;
  31.  
  32. /*
  33.  * Arrays for each access to top-level records
  34.  */
  35.  
  36. struct individual_record **all_individuals;
  37. struct family_record **all_families;
  38.  
  39. void extract_xref(struct node *np);
  40.  
  41. /*
  42.  * Pass I: Allocate database records and attach them to the GEDCOM nodes.
  43.  */
  44.  
  45. void
  46. process_records(struct node *np)
  47. {
  48.   for( ; np != NULL; np = np->siblings) {
  49.     if(np->tag == NULL)
  50.       continue;
  51.     switch(np->tag->value) {
  52.     case INDI:
  53.       total_individuals++;
  54.       process_individual_record(np);
  55.       break;
  56.     case FAM:
  57.       total_families++;
  58.       process_family_record(np);
  59.       break;
  60.     case EVEN:
  61.       total_events++;
  62.       process_event_record(np);
  63.       break;
  64.     case NOTE:
  65.       total_notes++;
  66.       process_note_record(np);
  67.       break;
  68.     case SOUR:
  69.       total_sources++;
  70.       process_source_record(np);
  71.       break;
  72.     case REPO:
  73.       total_repositories++;
  74.       process_repository_record(np);
  75.       break;
  76.     case SUBM:
  77.       total_submitters++;
  78.       process_submitter_record(np);
  79.       break;
  80.     default:
  81.       /* Skip unrecognized records */
  82.       break;
  83.     }
  84.   }
  85. }
  86.  
  87. void
  88. process_individual_record(struct node *np)
  89. {
  90.   struct individual_record *ip;
  91.   struct note_structure *ntp;
  92.   struct xref *xp;
  93.  
  94.   if((ip = malloc(sizeof(*ip))) == NULL)
  95.     out_of_memory();
  96.   memset(ip, 0, sizeof(*ip));
  97.   np->hook = ip;
  98.   ip->xref = np->xref;
  99.   index_enter(ip->xref, ip);
  100.   for(np = np->children ; np != NULL; np = np->siblings) {
  101.     if(np->tag == NULL)
  102.       continue;
  103.     switch(np->tag->value) {
  104.     case NAME:
  105.       ip->personal_name = process_name(np);
  106.       break;
  107.     case FAMS:
  108.       xp = process_xref(np);
  109.       if(ip->fams == NULL)
  110.     ip->fams = ip->lastfams = xp;
  111.       else {
  112.     ip->lastfams->next = xp;
  113.     ip->lastfams = xp;
  114.       }
  115.       break;
  116.     case FAMC:
  117.       xp = process_xref(np);
  118.       if(ip->famc == NULL)
  119.     ip->famc = ip->lastfamc = xp;
  120.       else {
  121.     ip->lastfamc->next = xp;
  122.     ip->lastfamc = xp;
  123.       }
  124.       break;
  125.     case SOUR:
  126.       xp = process_xref(np);
  127.       if(ip->sources == NULL)
  128.     ip->sources = ip->lastsource = xp;
  129.       else {
  130.     ip->sources->next = xp;
  131.     ip->lastsource = xp;
  132.       }
  133.       break;
  134.     case REFN:
  135.       ip->refn = np->rest;
  136.       break;
  137.     case RFN:
  138.       ip->rfn = np->rest;
  139.       break;
  140.     case AFN:
  141.       ip->afn = np->rest;
  142.       break;
  143.     case NOTE:
  144.       ntp = process_note(np);
  145.       if(ip->notes == NULL)
  146.     ip->notes = ip->lastnote = ntp;
  147.       else {
  148.     ip->lastnote->next = ntp;
  149.     ip->lastnote = ntp;
  150.       }
  151.       break;
  152.     case TITL:
  153.       ip->title = np->rest;
  154.       break;
  155.     case SEX:
  156.       if(*np->rest == 'M')
  157.     ip->sex = 'M';
  158.       else if(*np->rest == 'F')
  159.     ip->sex = 'F';
  160.       break;
  161.     case CENS: case MARR: case MARB: case MARC: case MARL: case MARS:
  162.     case ENGA: case BAPM: case BARM: case BASM: case BIRT: case BLES:
  163.     case BURI: case CHR: case CHRA: case CONF: case DEAT: case EMIG:
  164.     case GRAD: case IMMI: case NATU: case ORDN: case RETI: case PROB:
  165.     case WILL: case ANUL: case DIV: case DIVF:
  166.       if(ip->events == NULL)
  167.     ip->events = ip->lastevent = process_event(np);
  168.       else {
  169.     ip->lastevent->next = process_event(np);
  170.     ip->lastevent = ip->lastevent->next;
  171.       }
  172.       break;
  173.     default:
  174.       /* Skip unrecognized substructures */
  175.       break;
  176.     }
  177.   }
  178. }
  179.  
  180. void
  181. process_family_record(struct node *np)
  182. {
  183.   struct family_record *frp;
  184.   struct note_structure *ntp;
  185.   struct xref *xp;
  186.  
  187.   if((frp = malloc(sizeof(*frp))) == NULL)
  188.     out_of_memory();
  189.   memset(frp, 0, sizeof(*frp));
  190.   np->hook = frp;
  191.   frp->xref = np->xref;
  192.   index_enter(frp->xref, frp);
  193.   for(np = np->children ; np != NULL; np = np->siblings) {
  194.     if(np->tag == NULL)
  195.       continue;
  196.     switch(np->tag->value) {
  197.     case HUSB:
  198.       frp->husband = process_xref(np);
  199.       break;
  200.     case WIFE:
  201.       frp->wife = process_xref(np);
  202.       break;
  203.     case CHIL:
  204.       xp = process_xref(np);
  205.       if(frp->children == NULL)
  206.     frp->children = frp->lastchild = xp;
  207.       else {
  208.     frp->lastchild->next = xp;
  209.     frp->lastchild = xp;
  210.       }
  211.       break;
  212.     case SOUR:
  213.       xp = process_xref(np);
  214.       if(frp->sources == NULL)
  215.     frp->sources = frp->lastsource = xp;
  216.       else {
  217.     frp->sources->next = xp;
  218.     frp->lastsource = xp;
  219.       }
  220.       break;
  221.     case REFN:
  222.       frp->refn = np->rest;
  223.       break;
  224.     case CENS: case MARR: case MARB: case MARC: case MARL: case MARS:
  225.     case ENGA: case BAPM: case BARM: case BASM: case BIRT: case BLES:
  226.     case BURI: case CHR: case CHRA: case CONF: case DEAT: case EMIG:
  227.     case GRAD: case IMMI: case NATU: case ORDN: case RETI: case PROB:
  228.     case WILL: case ANUL: case DIV: case DIVF:
  229.       if(frp->events == NULL)
  230.     frp->events = frp->lastevent = process_event(np);
  231.       else {
  232.     frp->lastevent->next = process_event(np);
  233.     frp->lastevent = frp->lastevent->next;
  234.       }
  235.       break;
  236.     case NOTE:
  237.       ntp = process_note(np);
  238.       if(frp->notes == NULL)
  239.     frp->notes = frp->lastnote = ntp;
  240.       else {
  241.     frp->lastnote->next = ntp;
  242.     frp->lastnote = ntp;
  243.       }
  244.       break;
  245.     default:
  246.       /* Skip unrecognized substructures */
  247.       break;
  248.     }
  249.   }
  250. }
  251.  
  252. void
  253. process_source_record(struct node *np)
  254. {
  255.   struct source_record *sp;
  256.   struct continuation *cp;
  257.   int cont = 0;
  258.  
  259.   if((sp = malloc(sizeof(*sp))) == NULL)
  260.     out_of_memory();
  261.   memset(sp, 0, sizeof(*sp));
  262.   np->hook = sp;
  263.   sp->xref = np->xref;
  264.   index_enter(sp->xref, sp);
  265.   sp->text = np->rest;
  266.   for(np = np->children ; np != NULL; np = np->siblings) {
  267.     if(np->tag == NULL)
  268.       continue;
  269.     switch(np->tag->value) {
  270.     case CONT:
  271.       if(cont == 0) {
  272.     cont++;
  273.     if((sp->cont = malloc(sizeof(*sp->cont))) == NULL)
  274.       out_of_memory();
  275.     cp = sp->cont;
  276.       } else {
  277.     if((cp->next = malloc(sizeof(*cp->next))) == NULL)
  278.       out_of_memory();
  279.     cp = cp->next;
  280.       }
  281.       memset(cp, 0, sizeof(*cp));
  282.       np->hook = cp;
  283.       cp->text = np->rest;
  284.       break;
  285.     }
  286.   }
  287. }
  288.  
  289. void
  290. process_event_record(struct node *np)
  291. {
  292.  
  293. }
  294.  
  295. void
  296. process_note_record(struct node *np)
  297. {
  298.  
  299. }
  300.  
  301. void
  302. process_repository_record(struct node *np)
  303. {
  304.  
  305. }
  306.  
  307. void
  308. process_submitter_record(struct node *np)
  309. {
  310.  
  311. }
  312.  
  313. struct event_structure *
  314. process_event(struct node *np)
  315. {
  316.   struct event_structure *ep;
  317.   struct place_structure *pp;
  318.  
  319.   if((ep = malloc(sizeof(*ep))) == NULL)
  320.     out_of_memory();
  321.   memset(ep, 0, sizeof(*ep));
  322.   np->hook = ep;
  323.   ep->tag = np->tag;
  324.   for(np = np->children; np != NULL; np = np->siblings) {
  325.     if(np->tag == NULL)
  326.       continue;
  327.     switch(np->tag->value) {
  328.     case DATE:
  329.       ep->date = np->rest;
  330.       break;
  331.     case PLAC:
  332.       if((pp = malloc(sizeof(*pp))) == NULL)
  333.     out_of_memory();
  334.       memset(pp, 0, sizeof(*pp));
  335.       pp->name = np->rest;
  336.       ep->place = pp;
  337.       break;
  338.     default:
  339.       break;
  340.     }
  341.   }
  342.   return(ep);
  343. }
  344.  
  345. struct note_structure *
  346. process_note(struct node *np)
  347. {
  348.   struct note_structure *ntp;
  349.   struct continuation *ntpc;
  350.   int cont = 0;
  351.  
  352.   if((ntp = malloc(sizeof(*ntp))) == NULL)
  353.     out_of_memory();
  354.   memset(ntp, 0, sizeof(*ntp));
  355.   np->hook = ntp;
  356.   ntp->text = np->rest;
  357.   for(np = np->children; np != NULL; np = np->siblings) {
  358.     if(np->tag == NULL)
  359.       continue;
  360.     switch(np->tag->value) {
  361.     case CONT:
  362.       if(cont == 0) {
  363.     cont++;
  364.     if((ntp->cont = malloc(sizeof(*ntp->cont))) == NULL)
  365.       out_of_memory();
  366.     ntpc = ntp->cont;
  367.       } else {
  368.     if((ntpc->next = malloc(sizeof(*ntpc->next))) == NULL)
  369.       out_of_memory();
  370.     ntpc = ntpc->next;
  371.       }
  372.       memset(ntpc, 0, sizeof(*ntpc));
  373.       np->hook = ntpc;
  374.       ntpc->text = np->rest;
  375.       break;
  376.     default:
  377.       break;
  378.     }
  379.   }
  380.   return(ntp);
  381. }
  382.  
  383. struct xref *
  384. process_xref(struct node *np)
  385. {
  386.   struct xref *xp;
  387.  
  388.   extract_xref(np);
  389.   if((xp = malloc(sizeof(*xp))) == NULL)
  390.     out_of_memory();
  391.   memset(xp, 0, sizeof(*xp));
  392.   xp->id = np->rest;
  393.   return(xp);
  394. }
  395.  
  396. struct name_structure *
  397. process_name(struct node *np)
  398. {
  399.   char *cp, *p;
  400.   int i, surname=0;
  401.   struct name_structure *nsp;
  402.  
  403.   for(i = 0, cp = np->rest; *cp != '\0'; cp++, i++);
  404.   if((p = malloc(i+1)) == NULL)
  405.     out_of_memory();
  406.   if((nsp = malloc(sizeof(*nsp))) == NULL)
  407.     out_of_memory();
  408.   memset(nsp, 0, sizeof(*nsp));
  409.   nsp->name = p;
  410.   for(i = 0, cp = np->rest; *cp != '\0'; cp++, i++) {
  411.     if(*cp == '/') {
  412.       surname = 1 - surname;
  413.       if(surname)
  414.     nsp->surname_start = i;
  415.       else
  416.     nsp->surname_end = i;
  417.       *p++ = ' ';
  418.       continue;
  419.     } else {
  420.       if(surname && capitalization)
  421.     *p++ = islower(*cp) ? toupper(*cp) : *cp;
  422.       else
  423.     *p++ = *cp;
  424.     }
  425.   }
  426.   *p = '\0';
  427.   return(nsp);
  428. }
  429.  
  430. /*
  431.  * Pass II: Create lineage-linked structure on database nodes.
  432.  */
  433.  
  434. void
  435. link_records(struct node *np)
  436. {
  437.   struct individual_record **ip;
  438.   struct family_record **fp;
  439.   int i;
  440.  
  441.   if((ip = all_individuals = malloc(total_individuals *
  442.                sizeof(struct individual_record **))) == NULL)
  443.     out_of_memory();
  444.   if((fp = all_families = malloc(total_families *
  445.                sizeof(struct family_record **))) == NULL)
  446.     out_of_memory();
  447.   for( ; np != NULL; np = np->siblings) {
  448.     if(np->tag == NULL)
  449.       continue;
  450.     switch(np->tag->value) {
  451.     case INDI:
  452.       *ip++ = (struct individual_record *)np->hook;
  453.       link_individual_record(np);
  454.       break;
  455.     case FAM:
  456.       *fp++ = (struct family_record *)np->hook;
  457.       link_family_record(np);
  458.       break;
  459.     case SOUR:
  460.     case EVEN:
  461.     case NOTE:
  462.     case REPO:
  463.     case SUBM:
  464.     default:
  465.       /* Skip unrecognized records */
  466.       break;
  467.     }
  468.   }
  469.   qsort(all_individuals, total_individuals,
  470.     sizeof(struct individual_record *),
  471.     (int (*)(const void *, const void *)) compare_name);
  472.   /*
  473.    * Link individuals for the benefit of the output interpreter
  474.    */
  475.   for(i = 0; i < total_individuals-1; i++)
  476.     all_individuals[i]->next = all_individuals[i+1];
  477.   all_individuals[total_individuals-1]->next = NULL;
  478. }
  479.  
  480. void
  481. link_individual_record(struct node *np)
  482. {
  483.   struct individual_record *ip;
  484.   struct xref *xp;
  485.  
  486.   ip = (struct individual_record *)np->hook;
  487.   for(xp = ip->fams; xp != NULL; xp = xp->next)
  488.     xp->pointer.family = index_find(xp->id);
  489.   for(xp = ip->famc; xp != NULL; xp = xp->next)
  490.     xp->pointer.family = index_find(xp->id);
  491.   for(xp = ip->sources; xp != NULL; xp = xp->next)
  492.     xp->pointer.source = index_find(xp->id);
  493. }
  494.  
  495. void
  496. link_family_record(struct node *np)
  497. {
  498.   struct family_record *fp;
  499.   struct xref *xp;
  500.  
  501.   fp = (struct family_record *)np->hook;
  502.   if(xp = fp->husband)
  503.     xp->pointer.family = index_find(xp->id);
  504.   if(xp = fp->wife)
  505.     xp->pointer.family = index_find(xp->id);
  506.   for(xp = fp->children; xp != NULL; xp = xp->next)
  507.     xp->pointer.individual = index_find(xp->id);
  508. }
  509.  
  510. /*
  511.  * Compare personal names for lexicographic order.
  512.  * Used to sort individual records.
  513.  */
  514.  
  515. int compare_name(struct individual_record **ipp1,
  516.          struct individual_record **ipp2)
  517. {
  518.   char *p1, *p2, *ep1, *ep2;
  519.   struct individual_record *ip1 = *ipp1;
  520.   struct individual_record *ip2 = *ipp2;
  521.  
  522.   /*
  523.    * Handle case in which names are missing
  524.    */
  525.   if(ip1->personal_name == NULL) {
  526.     if(ip2->personal_name == NULL) {
  527.       return(0);
  528.     } else {
  529.       return(1);
  530.     }
  531.   } else if(ip2->personal_name == NULL) {
  532.     return(-1);
  533.   }
  534.   /*
  535.    * Normal case -- names present
  536.    */
  537.   p1 = ip1->personal_name->name + ip1->personal_name->surname_start;
  538.   p2 = ip2->personal_name->name + ip2->personal_name->surname_start;
  539.   ep1 = ip1->personal_name->name + ip1->personal_name->surname_end;
  540.   ep2 = ip2->personal_name->name + ip2->personal_name->surname_end;
  541.   while(p1 < ep1 && p2 < ep2) {
  542.     if(*p1 < *p2) {
  543.       return(-1);
  544.     }
  545.     if(*p1 > *p2) {
  546.       return(1);
  547.     }
  548.     p1++;
  549.     p2++;
  550.   }
  551.   if(p1 != ep1) {
  552.     return(-1);
  553.   } else if(p2 != ep2) {
  554.     return(1);
  555.   } else {
  556.     return(strcmp(ip1->personal_name->name, ip2->personal_name->name));
  557.   }
  558. }
  559.  
  560. /*
  561.  * Adjust np->rest in case an XREF constitutes the rest of the GEDCOM line
  562.  */
  563.  
  564. void
  565. extract_xref(struct node *np)
  566. {
  567.   char *cp;
  568.   if(*np->rest == '@') {
  569.     np->rest++;
  570.     for(cp = np->rest; *cp != '\0' && *cp != '@'; cp++);
  571.     *cp = '\0';
  572.   }
  573. }
  574.