home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume27 / mthreads / part02 / mt-read.c next >
Encoding:
C/C++ Source or Header  |  1993-11-20  |  15.0 KB  |  584 lines

  1. /* $Id: mt-read.c,v 3.0 1992/10/01 00:14:04 davison Trn $
  2. */
  3. /* The authors make no claims as to the fitness or correctness of this software
  4.  * for any use whatsoever, and it is provided as is. Any use of this software
  5.  * is at the user's own risk. 
  6.  */
  7.  
  8. #include "EXTERN.h"
  9. #include "common.h"
  10. #include "thread.h"
  11. #include "mthreads.h"
  12.  
  13. extern long first;
  14.  
  15. static FILE *fp_in;
  16.  
  17. int read_authors _((void));
  18. int read_subjects _((void));
  19. int read_roots _((void));
  20. int read_articles _((void));
  21. int read_ids _((void));
  22. int read_item _((char **, MEM_SIZE));
  23. void tweak_roots _((void));
  24.  
  25. /* Attempt to open the thread file.  If it's there, only grab the totals
  26. ** from the start of the file.  This should give them enough information
  27. ** to decide if they need to read the whole thing into memory.
  28. */
  29. int
  30. init_data(filename)
  31. char *filename;
  32. {
  33.     root_root = Null(ROOT*);
  34.     author_root = Null(AUTHOR*);
  35.     unk_domain.ids = Nullart;
  36.     unk_domain.link = Null(DOMAIN*);
  37.  
  38.     if (filename && (fp_in = fopen(filename, FOPEN_RB)) != Nullfp) {
  39. #ifdef SETBUFFER
  40.     setbuffer(fp_in, rwbuf, RWBUFSIZ);
  41. #else
  42. # ifdef SETVBUF
  43.     setvbuf(fp_in, rwbuf, _IOFBF, RWBUFSIZ);
  44. # endif
  45. #endif
  46.     if (fread((char*)&total,1,sizeof (TOTAL),fp_in) == sizeof (TOTAL)) {
  47.         /* If the data looks ok, return success. */
  48.         if (total.last - total.first >= 0 && total.author > 0
  49.          && total.article > 0 && total.subject > 0 && total.domain > 0
  50.          && total.subject <= total.article && total.author <= total.article
  51.          && total.root <= total.article && total.domain <= total.article
  52.          && total.string1 > 0 && total.string2 > 0) {
  53.         return 1;
  54.         }
  55.     }
  56.     bzero(&total, sizeof (TOTAL));
  57.     total.first = first;
  58.     total.last = first - 1;
  59.     return 1;
  60.     }
  61.     bzero(&total, sizeof (TOTAL));
  62.     return 0;
  63. }
  64.  
  65. /* They want everything.  Read in the packed information and transform it
  66. ** into a set of linked structures that is easily manipulated.
  67. */
  68. int
  69. read_data()
  70. {
  71.     /* If this is an empty thread file, simply return success. */
  72.     if (!total.root) {
  73.     fclose(fp_in);
  74.     return 1;
  75.     }
  76.  
  77.     if (read_authors()
  78.      && read_subjects()
  79.      && read_roots()
  80.      && read_articles()
  81.      && read_ids())
  82.     {
  83.     tweak_roots();
  84.     fclose(fp_in);
  85.     return 1;
  86.     }
  87.     /* Something failed.  Safefree takes care of checking if some items
  88.     ** were already freed.  Any partially-allocated structures were freed
  89.     ** before we got here.  All other structures are cleaned up.
  90.     */
  91.     if (root_root) {
  92.     register ROOT *root, *next_root;
  93.     register SUBJECT *subj, *next_subj;
  94.  
  95.     for (root = root_root; root; root = next_root) {
  96.         for (subj = root->subjects; subj; subj = next_subj) {
  97.         next_subj = subj->link;
  98.         free(subj->str);
  99.         free(subj);
  100.         }
  101.         next_root = root->link;
  102.         free(root);
  103.     }
  104.     root_root = Null(ROOT*);
  105.     }
  106.     if (author_array) {
  107.     register int count;
  108.  
  109.     for (count = total.author; count--;) {
  110.         free(author_array[count]->name);
  111.         free(author_array[count]);
  112.     }
  113.     safefree(&author_array);
  114.     author_root = Null(AUTHOR*);
  115.     }
  116.     if (article_array) {
  117.     register int count;
  118.  
  119.     for (count = total.article; count--;) {
  120.         free(article_array[count]);
  121.     }
  122.     safefree(&article_array);
  123.     }
  124.     safefree(&strings);
  125.     safefree(&subject_cnts);
  126.     safefree(&subject_array);
  127.     safefree(&author_cnts);
  128.     safefree(&root_array);
  129.     safefree(&ids);
  130.     unk_domain.ids = Nullart;
  131.     unk_domain.link = Null(DOMAIN*);
  132.     fclose(fp_in);
  133.     return 0;
  134. }
  135.  
  136. /* They don't want to read the data.  Close the file if we opened it.
  137. */
  138. void
  139. dont_read_data(open_flag)
  140. int open_flag;        /* 0 == not opened, 1 == open failed, 2 == open */
  141. {
  142.     if (open_flag == 2) {
  143.     fclose(fp_in);
  144.     bzero(&total, sizeof (TOTAL));
  145.     }
  146. }
  147.  
  148. #define give_string_to(dest)    /* Comment for makedepend to     \
  149.                 ** ignore the backslash above */ \
  150. {\
  151.     register MEM_SIZE len = strlen(string_ptr) + 1;\
  152.     dest = safemalloc(len);\
  153.     bcopy(string_ptr, dest, (int)len);\
  154.     string_ptr += len;\
  155. }
  156.  
  157. char *subject_strings, *string_end;
  158.  
  159. /* The author information is an array of use-counts, followed by all the
  160. ** null-terminated strings crammed together.  The subject strings are read
  161. ** in at the same time, since they are appended to the end of the author
  162. ** strings.
  163. */
  164. int
  165. read_authors()
  166. {
  167.     register int count, author_tally;
  168.     register char *string_ptr;
  169.     register WORD *authp;
  170.     register AUTHOR *author, *last_author, **author_ptr;
  171.  
  172.     if (!read_item((char **)&author_cnts,
  173.            (MEM_SIZE)(total.author * sizeof (WORD)))
  174.      || !read_item((char **)&strings, total.string1)) {
  175.     /* (Error already logged.) */
  176.     return 0;
  177.     }
  178.  
  179.     string_ptr = strings;
  180.     string_end = string_ptr + total.string1;
  181.     if (string_end[-1] != '\0') {
  182.     log_error("first string table is invalid.\n");
  183.     return 0;
  184.     }
  185.  
  186.     /* We'll use this array to point each article at its proper author
  187.     ** (packed values are saved as indexes).
  188.     */
  189.     author_array = (AUTHOR**)safemalloc(total.author * sizeof (AUTHOR*));
  190.     author_ptr = author_array;
  191.  
  192.     authp = author_cnts;
  193.  
  194.     author_tally = 0;
  195. #ifndef lint
  196.     last_author = (AUTHOR*)&author_root;
  197. #else
  198.     last_author = Null(AUTHOR*);
  199. #endif
  200.     for (count = total.author; count; count--) {
  201.     if (string_ptr >= string_end) {
  202.         break;
  203.     }
  204.     *author_ptr++ = author = (AUTHOR*)safemalloc(sizeof (AUTHOR));
  205.     last_author->link = author;
  206.     give_string_to(author->name);
  207.     author_tally += *authp;
  208.     author->count = *authp++;
  209.     last_author = author;
  210.     }
  211.     last_author->link = Null(AUTHOR*);
  212.  
  213.     subject_strings = string_ptr;
  214.  
  215.     safefree(&author_cnts);
  216.  
  217.     if (count || author_tally > total.article) {
  218.     log_error("author unpacking failed.\n");
  219.     for (; count < total.author; count++) {
  220.         free((*--author_ptr)->name);
  221.         free(*author_ptr);
  222.     }
  223.     safefree(&author_array);
  224.     return 0;
  225.     }
  226.     return 1;
  227. }
  228.  
  229. /* The subject values consist of the crammed-together null-terminated strings
  230. ** (already read in above) and the use-count array.  They were saved in the
  231. ** order that the roots require while being unpacked.
  232. */
  233. int
  234. read_subjects()
  235. {
  236.     if (!read_item((char **)&subject_cnts,
  237.            (MEM_SIZE)(total.subject * sizeof (WORD)))) {
  238.     /* (Error already logged.) */
  239.     return 0;
  240.     }
  241.     return 1;
  242. }
  243.  
  244. /* Read in the packed root structures and recreate the linked list versions,
  245. ** processing each root's subjects as we go.  Defer interpretation of article
  246. ** offsets until we unpack the article structures.
  247. */
  248. int
  249. read_roots()
  250. {
  251.     register int count, subj_tally;
  252.     register char *string_ptr;
  253.     register WORD *subjp;
  254.     ROOT *root, *last_root, **root_ptr;
  255.     SUBJECT *subject, *last_subject, **subj_ptr;
  256.     int ret;
  257.  
  258.     /* Use this array when unpacking the article's subject offset. */
  259.     subject_array = (SUBJECT**)safemalloc(total.subject * sizeof (SUBJECT*));
  260.     subj_ptr = subject_array;
  261.     /* And this array points the article's root offset at the right spot. */
  262.     root_array = (ROOT**)safemalloc(total.root * sizeof (ROOT*));
  263.     root_ptr = root_array;
  264.  
  265.     subjp = subject_cnts;
  266.     string_ptr = subject_strings;    /* string_end is already set */
  267.  
  268.     subj_tally = 0;
  269. #ifndef lint
  270.     last_root = (ROOT*)&root_root;
  271. #else
  272.     last_root = Null(ROOT*);
  273. #endif
  274.     for (count = total.root; count--;) {
  275.     ret = fread((char*)&p_root, 1, sizeof (PACKED_ROOT), fp_in);
  276.     if (ret != sizeof (PACKED_ROOT)) {
  277.         log_error("failed root read -- %d bytes instead of %d.\n",
  278.         ret, sizeof (PACKED_ROOT));
  279.         return 0;
  280.     }
  281.     if (p_root.articles < 0 || p_root.articles >= total.article
  282.      || subj_ptr - subject_array + p_root.subject_cnt > total.subject) {
  283.         log_error("root has invalid values.\n");
  284.         return 0;
  285.     }
  286.     *root_ptr++ = root = (ROOT*)safemalloc(sizeof (ROOT));
  287.     root->link = Null(ROOT*);
  288.     root->articles = Nullart;
  289.     root->seq = p_root.articles;
  290.     root->root_num = p_root.root_num;
  291.     root->thread_cnt = p_root.thread_cnt;
  292.     root->subject_cnt = p_root.subject_cnt;
  293.     last_root->link = root;
  294.     last_root = root;
  295.  
  296. #ifndef lint
  297.     last_subject = (SUBJECT*)&root->subjects;
  298. #else
  299.     last_subject = Null(SUBJECT*);
  300. #endif
  301.     while (p_root.subject_cnt--) {
  302.         if (string_ptr >= string_end) {
  303.         log_error("error unpacking subject strings.\n");
  304.         last_subject->link = Null(SUBJECT*);
  305.         return 0;
  306.         }
  307.         *subj_ptr++ = subject = (SUBJECT*)safemalloc(sizeof (SUBJECT));
  308.         last_subject->link = subject;
  309.         give_string_to(subject->str);
  310.         subj_tally += *subjp;
  311.         subject->count = *subjp++;
  312.         last_subject = subject;
  313.     }
  314.     last_subject->link = Null(SUBJECT*);
  315.     }
  316.     if (subj_ptr != subject_array + total.subject
  317.      || subj_tally > total.article
  318.      || string_ptr != string_end) {
  319.     log_error("subject data is invalid.\n");
  320.     return 0;
  321.     }
  322.     safefree(&subject_cnts);
  323.     safefree(&strings);
  324.  
  325.     return 1;
  326. }
  327.  
  328. bool invalid_data;
  329.  
  330. /* A simple routine that checks the validity of the article's subject value.
  331. ** A -1 means that it is NULL, otherwise it should be an offset into the
  332. ** subject array we just unpacked.
  333. */
  334. SUBJECT *
  335. valid_subject(num, art_num)
  336. WORD num;
  337. long art_num;
  338. {
  339.     if (num == -1) {
  340.     return Null(SUBJECT*);
  341.     }
  342.     if (num < 0 || num >= total.subject) {
  343.     log_error("invalid subject in thread file: %d [%ld]\n", num, art_num);
  344.     invalid_data = TRUE;
  345.     return Null(SUBJECT*);
  346.     }
  347.     return subject_array[num];
  348. }
  349.  
  350. /* Ditto for author checking. */
  351. AUTHOR *
  352. valid_author(num, art_num)
  353. WORD num;
  354. long art_num;
  355. {
  356.     if (num == -1) {
  357.     return Null(AUTHOR*);
  358.     }
  359.     if (num < 0 || num >= total.author) {
  360.     log_error("invalid author in thread file: %d [%ld]\n", num, art_num);
  361.     invalid_data = TRUE;
  362.     return Null(AUTHOR*);
  363.     }
  364.     return author_array[num];
  365. }
  366.  
  367. /* Our parent/sibling information is a relative offset in the article array.
  368. ** zero for none.  Child values are always found in the very next array
  369. ** element if child_cnt is non-zero.
  370. */
  371. ARTICLE *
  372. valid_node(relative_offset, num)
  373. WORD relative_offset;
  374. int num;
  375. {
  376.     if (!relative_offset) {
  377.     return Nullart;
  378.     }
  379.     num += relative_offset;
  380.     if (num < 0 || num >= total.article) {
  381.     log_error("invalid node offset in thread file.\n");
  382.     invalid_data = TRUE;
  383.     return Nullart;
  384.     }
  385.     return article_array[num];
  386. }
  387.  
  388. /* Read the articles into their linked lists.  Point everything everywhere. */
  389. int
  390. read_articles()
  391. {
  392.     register int count;
  393.     register ARTICLE *article, **article_ptr;
  394.     int ret;
  395.  
  396.     /* Build an array to interpret interlinkages of articles. */
  397.     article_array = (ARTICLE**)safemalloc(total.article * sizeof (ARTICLE*));
  398.     article_ptr = article_array;
  399.  
  400.     /* Allocate all the structures up-front so that we can point to unread
  401.     ** siblings as we go.
  402.     */
  403.     for (count = total.article; count--;) {
  404.     *article_ptr++ = (ARTICLE*)safemalloc(sizeof (ARTICLE));
  405.     }
  406.     invalid_data = FALSE;
  407.     article_ptr = article_array;
  408.     for (count = 0; count < total.article; count++) {
  409.     ret = fread((char*)&p_article, 1, sizeof (PACKED_ARTICLE), fp_in);
  410.     if (ret != sizeof (PACKED_ARTICLE)) {
  411.         log_error("failed article read -- %d bytes instead of %d.\n", ret, sizeof (PACKED_ARTICLE));
  412.         return 0;
  413.     }
  414.  
  415.     article = *article_ptr++;
  416.     article->num = p_article.num;
  417.     article->date = p_article.date;
  418.     article->subject = valid_subject(p_article.subject, p_article.num);
  419.     article->author = valid_author(p_article.author, p_article.num);
  420.     article->flags = p_article.flags;
  421.     article->child_cnt = p_article.child_cnt;
  422.     article->parent = valid_node(p_article.parent, count);
  423.     article->children = valid_node(article->child_cnt ? 1 : 0, count);
  424.     article->siblings = valid_node(p_article.siblings, count);
  425.     if (p_article.root < 0 || p_article.root >= total.root) {
  426.         log_error("invalid root offset in thread file.\n");
  427.         return 0;
  428.     }
  429.     article->root = root_array[p_article.root];
  430.     if (invalid_data) {
  431.         /* (Error already logged.) */
  432.         return 0;
  433.     }
  434.     }
  435.  
  436.     /* We're done with most of the pointer arrays. */
  437.     safefree(&root_array);
  438.     safefree(&subject_array);
  439.  
  440.     return 1;
  441. }
  442.  
  443. /* Read the message-id strings and attach them to each article.  The data
  444. ** format consists of the mushed-together null-terminated strings (a domain
  445. ** name followed by all its unique-id prefixes) and then the article offsets
  446. ** to which they belong.  The first domain name was omitted, as it is the
  447. ** ".unknown." domain for those truly weird message-id's without '@'s.
  448. */
  449. int
  450. read_ids()
  451. {
  452.     register DOMAIN *domain, *last;
  453.     register ARTICLE *article;
  454.     register char *string_ptr;
  455.     register int i, count;
  456.  
  457.     if (!read_item(&strings, total.string2)
  458.      || !read_item((char **)&ids,
  459.            (MEM_SIZE)((total.article + total.domain + 1)
  460.                   * sizeof (WORD)))) {
  461.     return 0;
  462.     }
  463.  
  464.     string_ptr = strings;
  465.     string_end = string_ptr + total.string2;
  466.  
  467.     if (string_end[-1] != '\0') {
  468.     log_error("second string table is invalid.\n");
  469.     return 0;
  470.     }
  471.  
  472.     last = &unk_domain;
  473.     for (i = 0, count = total.domain + 1; count--; i++) {
  474.     if (i) {
  475.         if (string_ptr >= string_end) {
  476.         log_error("error unpacking domain strings.\n");
  477.           free_partial:
  478.         last->link = Null(DOMAIN*);
  479.         article = unk_domain.ids;
  480.         while (article) {
  481.             safefree(&article->id);
  482.             article = article->id_link;
  483.         }
  484.         domain = unk_domain.link;
  485.         while (domain) {
  486.             free(domain->name);
  487.             article = domain->ids;
  488.             while (article) {
  489.             safefree(&article->id);
  490.             article = article->id_link;
  491.             }
  492.             last = domain;
  493.             domain = domain->link;
  494.             free(last);
  495.         }
  496.         return 0;
  497.         }
  498.         domain = (DOMAIN*)safemalloc(sizeof (DOMAIN));
  499.         give_string_to(domain->name);
  500.         last->link = domain;
  501.     } else {
  502.         domain = &unk_domain;
  503.     }
  504.     if (ids[i] == -1) {
  505.         domain->ids = Nullart;
  506.     } else {
  507.         if (ids[i] < 0 || ids[i] >= total.article) {
  508.           id_error:
  509.         log_error("error in id array.\n");
  510.         domain->ids = Nullart;
  511.         goto free_partial;
  512.         }
  513.         article = article_array[ids[i]];
  514.         domain->ids = article;
  515.         for (;;) {
  516.         if (string_ptr >= string_end) {
  517.             log_error("error unpacking domain strings.\n");
  518.             article->id = Nullch;
  519.             article->id_link = Nullart;
  520.             goto free_partial;
  521.         }
  522.         give_string_to(article->id);
  523.         article->domain = domain;
  524.         if (++i >= total.article + total.domain + !count) {
  525.             log_error("overran id array unpacking domains.\n");
  526.             article->id_link = Nullart;
  527.             goto free_partial;
  528.         }
  529.         if (ids[i] != -1) {
  530.             if (ids[i] < 0 || ids[i] >= total.article) {
  531.             goto id_error;
  532.             }
  533.             article = article->id_link = article_array[ids[i]];
  534.         } else {
  535.             article->id_link = Nullart;
  536.             break;
  537.         }
  538.         }
  539.     }
  540.     last = domain;
  541.     }
  542.     last->link = Null(DOMAIN*);
  543.     safefree(&ids);
  544.     safefree(&strings);
  545.  
  546.     return 1;
  547. }
  548.  
  549. /* And finally, point all the roots at their root articles and get rid
  550. ** of anything left over that was used to aid our unpacking.
  551. */
  552. void
  553. tweak_roots()
  554. {
  555.     register ROOT *root;
  556.  
  557.     for (root = root_root; root; root = root->link) {
  558.     root->articles = article_array[root->seq];
  559.     }
  560.     safefree(&author_array);
  561.     safefree(&article_array);
  562. }
  563.  
  564. /* A shorthand for reading a chunk of the file into a malloc'ed array.
  565. */
  566. int
  567. read_item(dest, len)
  568. char **dest;
  569. MEM_SIZE len;
  570. {
  571.     int ret;
  572.  
  573.     *dest = safemalloc(len);
  574.     ret = fread(*dest, 1, (int)len, fp_in);
  575.     if (ret != len) {
  576.     log_error("only read %ld bytes instead of %ld.\n",
  577.         (long)ret, (long)len);
  578.     free(*dest);
  579.     *dest = Nullch;
  580.     return 0;
  581.     }
  582.     return 1;
  583. }
  584.