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

  1. /*
  2.  * Read in a GEDCOM file without interpreting the nodes
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <errno.h>
  9. #include "node.h"
  10. #include "read.h"
  11. #include "tags.h"
  12.  
  13. long gedcom_lines;
  14. long current_lineno;
  15. char *current_gedcom;
  16.  
  17. #ifdef MSDOS
  18. char *fgetln(FILE *f, int *size);
  19. #endif
  20.  
  21. struct node *
  22. newnode()
  23. {
  24.   struct node *n;
  25.   if((n = malloc(sizeof(*n))) == NULL)
  26.     out_of_memory();
  27.   memset(n, 0, sizeof(*n));
  28.   return(n);
  29. }
  30.  
  31. /*
  32.  * Read a series of GEDCOM lines at the same level, and chain them
  33.  * onto the given list.  If a line is encountered at a deeper level,
  34.  * then recurse.
  35.  *
  36.  * prev is a pointer to the previous sibling at the current level
  37.  */
  38.  
  39. struct node *
  40. read_gedcom(FILE *f, struct node *prev, int level)
  41. {
  42.   char *line, *rest, *levp, *xrefp, *tagp;
  43.   struct node *node = NULL;
  44.   struct tag *tp;
  45.   int size;
  46.  
  47.   while(prev && (line = fgetln(f, &size))) {
  48.     gedcom_lines++;
  49.     /*
  50.      * Allocate node and copy line into it
  51.      */
  52.     node = newnode();
  53.     node->lineno = ++current_lineno;
  54.     if((node->line = malloc(size+1)) == NULL)
  55.       out_of_memory();
  56.     node->line[size] = '\0';
  57.     do {
  58.       --size;
  59.       switch(line[size]) {
  60.       case '\n':
  61.       case '\r':
  62.     node->line[size] = '\0';
  63.     continue;
  64.     break;
  65.       default:
  66.     node->line[size] = line[size];
  67.     break;
  68.       }
  69.     } while(size);
  70.     line = node->line;
  71.     /*
  72.      * Figure out level number
  73.      */
  74.     rest = line;
  75.     while(*rest == ' ')
  76.       rest++;
  77.     if(*rest == '\0') {
  78.       free(node->line);
  79.       free(node);
  80.       continue;        /* Ignore blank line */
  81.     }
  82.     levp = rest;
  83.     while(*rest >= '0' && *rest <= '9')
  84.       rest++;
  85.     if(*rest != ' ') {
  86.       fprintf(stderr, "%s: %d: Malformed GEDCOM line ignored\n",
  87.           current_gedcom, current_lineno);
  88.       free(node->line);
  89.       free(node);
  90.       continue;
  91.     }
  92.     *rest++ = '\0';
  93.     node->level = atoi(levp);
  94.     /*
  95.      * Extract XREF, if any
  96.      */
  97.     while(*rest == ' ')
  98.       rest++;
  99.     if(*rest == '\0') {
  100.       fprintf(stderr, "%s: %d: Malformed GEDCOM line ignored\n",
  101.           current_gedcom, current_lineno);
  102.       free(node->line);
  103.       free(node);
  104.       continue;
  105.     }
  106.     if(*rest == '@') {
  107.       xrefp = ++rest;
  108.       while(*rest != '\0' && *rest != '@')
  109.     rest++;
  110.       if(*rest != '@') {
  111.     fprintf(stderr, "%s: %d: Non-terminated cross-reference -- line ignored\n",
  112.         current_gedcom, current_lineno);
  113.     free(node->line);
  114.     free(node);
  115.     continue;
  116.       }
  117.       *rest++ = '\0';
  118.     } else {
  119.       xrefp = NULL;
  120.     }
  121.     node->xref = xrefp;
  122.     /*
  123.      * Extract tag
  124.      */
  125.     while(*rest == ' ')
  126.       rest++;
  127.     if(*rest == '\0') {
  128.       fprintf(stderr, "%s: %d: Ignored GEDCOM line with no tag\n",
  129.           current_gedcom, current_lineno);
  130.       free(node->line);
  131.       free(node);
  132.       continue;
  133.     }
  134.     tagp = rest;
  135.     while(*rest != '\0' && *rest != ' ')
  136.       rest++;
  137.     if(*rest)
  138.       *rest++ = '\0';
  139.     if(tp = findtag(tagp, gedcom_tags, gedcom_tags_size))
  140.       node->tag = tp;
  141.     while(*rest == ' ')
  142.       rest++;
  143.     node->rest = rest;
  144.     /*
  145.      * The line is parsed, now take care of linking it in to
  146.      * the data structure
  147.      */
  148.     if(node->level < level) {
  149.       return(node);
  150.     } else if(node->level == level) {
  151.       prev->siblings = node;
  152.       prev = node;
  153.       continue;
  154.     } else {
  155.       if(node->level > level+1)
  156.     fprintf(stderr, "%s: %d: Level number increased by more than one\n",
  157.         current_gedcom, current_lineno);
  158.       prev->children = node;
  159.       node = read_gedcom(f, node, node->level);
  160.       if(node == NULL) {
  161.     fprintf(stderr, "%s: %d GEDCOM file does not end at level 0\n",
  162.         current_gedcom, current_lineno);
  163.     return(NULL);
  164.       }
  165.       if(node->level < level)
  166.     return(node);
  167.       prev->siblings = node;
  168.       prev = prev->siblings;
  169.     }
  170.   }
  171.   if(!feof(f)) {
  172.     if(errno == ENOMEM)
  173.       out_of_memory();
  174.     else
  175.       fprintf(stderr, "%s: %d: Error reading GEDCOM file\n",
  176.           current_gedcom, current_lineno);
  177.   }
  178.   return(NULL);
  179. }
  180.  
  181. void out_of_memory()
  182. {
  183.   fprintf(stderr, "Insufficient memory available for processing.\n");
  184.   exit(1);
  185. }
  186.                    
  187. #ifdef MSDOS
  188. char *fgetln(FILE *f, int *size)
  189. {
  190.    static char *l = NULL;
  191.    char *lp, c;
  192.    static int max = 4;
  193.    int s = 0;
  194.    
  195.     
  196.    if(l == NULL) {
  197.      if((l = malloc(max)) == NULL)
  198.           out_of_memory();
  199.    }
  200.    if(feof(f) || ferror(f)) {
  201.      *size = 0;
  202.      return(NULL);
  203.    }
  204.    lp = l;
  205.    while((c = fgetc(f)) != EOF) {
  206.      if(s >= max-1) {
  207.         max = 2*max;
  208.         if((l = realloc(l, max)) == NULL)
  209.           out_of_memory();
  210.         lp = l + s;   
  211.      }
  212.      *lp++ = c;
  213.      s++;
  214.      if(c == '\n')
  215.         break;
  216.    }
  217.    *lp++ = '\0';
  218.    *size = s;
  219.    if(s == 0)
  220.      return(NULL);
  221.    return(l);
  222. }
  223. #endif
  224.  
  225.                    
  226.