home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume23 / trn / part10 / mt-read.c < prev    next >
C/C++ Source or Header  |  1991-08-22  |  13KB  |  498 lines

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