home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / trn_12.zip / src / mt-read.c < prev    next >
C/C++ Source or Header  |  1993-12-04  |  16KB  |  595 lines

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