home *** CD-ROM | disk | FTP | other *** search
- /* $Header: mt-read.c,v 4.3.3.2 91/01/16 02:49:15 davison Trn $
- **
- ** $Log: mt-read.c,v $
- ** Revision 4.3.3.2 91/01/16 02:49:15 davison
- ** Changed Free() to safefree(). Tweaked fopen for possible binary open mode.
- **
- ** Revision 4.3.3.1 90/07/24 23:51:12 davison
- ** Initial Trn Release
- **
- */
-
- #include "EXTERN.h"
- #include "common.h"
- #include "mthreads.h"
-
- static FILE *fp_in;
-
- void tweak_roots();
-
- /* Attempt to open the thread file. If it's there, only grab the totals
- ** from the start of the file. This should give them enough information
- ** to decide if they need to read the whole thing into memory.
- */
- int
- init_data( filename )
- char *filename;
- {
- root_root = Null(ROOT*);
- author_root = Null(AUTHOR*);
- unk_domain.ids = Nullart;
- unk_domain.link = Null(DOMAIN*);
-
- if( (fp_in = fopen( filename, FOPEN_RB )) == Nullfp ) {
- bzero( &total, sizeof (TOTAL) );
- return 0;
- }
- if( fread( &total, 1, sizeof (TOTAL), fp_in ) < sizeof (TOTAL) ) {
- fclose( fp_in );
- bzero( &total, sizeof (TOTAL) );
- return 0;
- }
- return 1;
- }
-
- /* They want everything. Read in the packed information and transform it
- ** into a set of linked structures that is easily manipulated.
- */
- int
- read_data()
- {
- if( read_authors()
- && read_subjects()
- && read_roots()
- && read_articles()
- && read_ids() )
- {
- tweak_roots();
- fclose( fp_in );
- return 1;
- }
- /* Something failed. Safefree takes care of checking if we're partially
- ** allocated. Any linked-list structures we created were freed before
- ** we got here.
- */
- safefree( &strings );
- safefree( &subject_cnts );
- safefree( &author_cnts );
- safefree( &root_array );
- safefree( &subject_array );
- safefree( &article_array );
- safefree( &ids );
- fclose( fp_in );
- return 0;
- }
-
- /* They don't want to read the data. Close the file if we opened it.
- */
- void
- dont_read_data( open_flag )
- int open_flag; /* 0 == not opened, 1 == open failed, 2 == open */
- {
- if( open_flag == 2 ) {
- fclose( fp_in );
- }
- }
-
- #define give_string_to( dest ) /* Comment for makedepend to \
- ** ignore the backslash above */ \
- {\
- register MEM_SIZE len = strlen( string_ptr ) + 1;\
- dest = safemalloc( len );\
- bcopy( string_ptr, dest, (int)len );\
- string_ptr += len;\
- }
-
- char *subject_strings;
-
- /* The author information is an array of use-counts, followed by all the
- ** null-terminated strings crammed together. The subject strings are read
- ** in at the same time, since they are appended to the end of the author
- ** strings.
- */
- int
- read_authors()
- {
- register int count;
- register char *string_ptr;
- register WORD *authp;
- register AUTHOR *author, *last_author, **author_ptr;
-
- if( !read_item( &author_cnts, (MEM_SIZE)total.author * sizeof (WORD) )
- || !read_item( &strings, total.string1 ) ) {
- return 0;
- }
-
- /* We'll use this array to point each article at its proper author
- ** (packed values are saved as indexes).
- */
- author_array = (AUTHOR**)safemalloc( total.author * sizeof (AUTHOR*) );
- author_ptr = author_array;
-
- authp = author_cnts;
- string_ptr = strings;
-
- last_author = Null(AUTHOR*);
- for( count = total.author; count--; ) {
- *author_ptr++ = author = (AUTHOR*)safemalloc( sizeof (AUTHOR) );
- if( !last_author ) {
- author_root = author;
- } else {
- last_author->link = author;
- }
- give_string_to( author->name );
- author->count = *authp++;
- last_author = author;
- }
- last_author->link = Null(AUTHOR*);
-
- subject_strings = string_ptr;
-
- free( author_cnts );
- author_cnts = Null(WORD*);
-
- return 1;
- }
-
- /* The subject values consist of the crammed-together null-terminated strings
- ** (already read in above) and the use-count array. They were saved in the
- ** order that the roots will need when they are unpacked.
- */
- int
- read_subjects()
- {
- if( !read_item( &subject_cnts, (MEM_SIZE)total.subject * sizeof (WORD) ) ) {
- return 0;
- }
- return 1;
- }
-
- /* Read in the packed root structures and recreate the linked list versions,
- ** processing each root's subjects as we go. Defer interpretation of article
- ** offsets until we unpack the article structures.
- */
- int
- read_roots()
- {
- register int count;
- register char *string_ptr;
- register WORD *subjp;
- ROOT *root, *last_root, **root_ptr;
- SUBJECT *subject, *last_subject, **subj_ptr;
- int ret;
-
- /* Use this array when unpacking the article's subject offsets. */
- subject_array = (SUBJECT**)safemalloc( total.subject * sizeof (SUBJECT*) );
- subj_ptr = subject_array;
- /* And this array points the article's root offsets that the right spot. */
- root_array = (ROOT**)safemalloc( total.root * sizeof (ROOT*) );
- root_ptr = root_array;
-
- subjp = subject_cnts;
- string_ptr = subject_strings;
-
- #ifndef lint
- last_root = (ROOT*)&root_root;
- #else
- last_root = Null(ROOT*);
- #endif
- for( count = total.root; count--; ) {
- ret = fread( &p_root, 1, sizeof (PACKED_ROOT), fp_in );
- if( ret != sizeof (PACKED_ROOT) ) {
- log_error( "failed root read -- %d bytes instead of %d.\n",
- ret, sizeof (PACKED_ROOT) );
- ret = 0;
- /* Free the roots we've read so far and their subjects. */
- while( root_ptr != root_array ) {
- free( *--root_ptr );
- }
- while( subj_ptr != subject_array ) {
- free( (*--subj_ptr)->str );
- free( *subj_ptr );
- }
- goto finish_up;
- }
- *root_ptr++ = root = (ROOT*)safemalloc( sizeof (ROOT) );
- root->link = Null(ROOT*);
- root->seq = p_root.articles;
- root->root_num = p_root.root_num;
- root->thread_cnt = p_root.thread_cnt;
- root->subject_cnt = p_root.subject_cnt;
- last_subject = Null(SUBJECT*);
- while( p_root.subject_cnt-- ) {
- *subj_ptr++ = subject = (SUBJECT*)safemalloc( sizeof (SUBJECT) );
- if( !last_subject ) {
- root->subjects = subject;
- } else {
- last_subject->link = subject;
- }
- give_string_to( subject->str );
- subject->count = *subjp++;
- last_subject = subject;
- }
- last_subject->link = Null(SUBJECT*);
- last_root->link = root;
- last_root = root;
- }
- ret = 1;
-
- finish_up:
- free( subject_cnts );
- free( strings );
- subject_cnts = Null(WORD*);
- strings = Nullch;
-
- return ret;
- }
-
- /* A simple routine that checks the validity of the article's subject value.
- ** A -1 means that it is NULL, otherwise it should be an offset into the
- ** subject array we just unpacked.
- */
- SUBJECT *
- valid_subject( num, art_num )
- WORD num;
- long art_num;
- {
- if( num == -1 ) {
- return Null(SUBJECT*);
- }
- if( num < 0 || num >= total.subject ) {
- log_error( "Invalid subject in data file: %d [%ld]\n", num, art_num );
- return Null(SUBJECT*);
- }
- return subject_array[num];
- }
-
- /* Ditto for author checking. */
- AUTHOR *
- valid_author( num, art_num )
- WORD num;
- long art_num;
- {
- if( num == -1 ) {
- return Null(AUTHOR*);
- }
- if( num < 0 || num >= total.author ) {
- log_error( "Invalid author in data file: %d [%ld]\n", num, art_num );
- return Null(AUTHOR*);
- }
- return author_array[num];
- }
-
- /* Our parent/sibling information is a relative offset in the article array.
- ** zero for none. Child values are always found in the very next array
- ** element if child_cnt is non-zero.
- */
- #define valid_node( rel, num ) (!(rel)? Nullart : article_array[(rel)+(num)])
-
- /* Read the articles into their linked lists. Point everything everywhere. */
- int
- read_articles()
- {
- register int count;
- register ARTICLE *article, **article_ptr;
- int ret;
-
- /* Build an array to interpret interlinkages of articles. */
- article_array = (ARTICLE**)safemalloc( total.article * sizeof (ARTICLE*) );
- article_ptr = article_array;
-
- /* Allocate all the structures up-front so that we can point to un-read
- ** siblings as we go.
- */
- for( count = total.article; count--; ) {
- *article_ptr++ = (ARTICLE*)safemalloc( sizeof (ARTICLE) );
- }
- article_ptr = article_array;
- for( count = 0; count < total.article; count++ ) {
- ret = fread( &p_article, 1, sizeof (PACKED_ARTICLE), fp_in );
- if( ret != sizeof (PACKED_ARTICLE) ) {
- log_error( "failed article read -- %d bytes instead of %d.\n", ret, sizeof (PACKED_ARTICLE) );
- ret = 0;
- goto finish_up;
- }
- article = *article_ptr++;
- article->num = p_article.num;
- article->date = p_article.date;
- article->subject = valid_subject( p_article.subject, p_article.num );
- article->author = valid_author( p_article.author, p_article.num );
- article->flags = p_article.flags;
- article->child_cnt = p_article.child_cnt;
- article->parent = valid_node( p_article.parent, count );
- article->children = article->child_cnt?article_array[count+1]:Nullart;
- article->siblings = valid_node( p_article.siblings, count );
- article->root = root_array[p_article.root];
- }
- ret = 1;
-
- finish_up:
- /* We're done with most of the pointer arrays. */
- free( root_array );
- free( subject_array );
- free( author_array );
- root_array = Null(ROOT**);
- subject_array = Null(SUBJECT**);
- author_array = Null(AUTHOR**);
-
- return ret;
- }
-
- /* Read the message-id strings and attach them to each article. The data
- ** format consists of the mushed-together null-terminated strings (a domain
- ** name followed by all its unique-id prefixes) and then the article offsets
- ** to which they belong. The first domain name was omitted, as it is the
- ** ".unknown." domain for those truly weird message-id's without '@'s.
- */
- int
- read_ids()
- {
- register DOMAIN *domain, *last;
- register ARTICLE *article;
- register char *string_ptr;
- register int i, count;
-
- if( !read_item( &strings, total.string2 ) ) {
- return 0;
- }
- if( !read_item( &ids,
- (MEM_SIZE)(total.article+total.domain+1) * sizeof (WORD) ) ) {
- return 0;
- }
- string_ptr = strings;
-
- last = Null(DOMAIN*);
- for( i = 0, count = total.domain + 1; count--; i++ ) {
- if( i ) {
- domain = (DOMAIN*)safemalloc( sizeof (DOMAIN) );
- give_string_to( domain->name );
- } else {
- domain = &unk_domain;
- }
- if( ids[i] == -1 ) {
- domain->ids = Nullart;
- } else {
- article = article_array[ids[i]];
- domain->ids = article;
- for( ;; ) {
- give_string_to( article->id );
- article->domain = domain;
- if( ids[++i] != -1 ) {
- article = article->id_link = article_array[ids[i]];
- } else {
- article->id_link = Nullart;
- break;
- }
- }
- }
- if( last ) {
- last->link = domain;
- }
- last = domain;
- }
- last->link = Null(DOMAIN*);
- free( ids );
- free( strings );
- ids = Null(WORD*);
- strings = Nullch;
-
- return 1;
- }
-
- /* And finally, point all the roots at their root articles and get rid
- ** of anything left over that was used to aid our unpacking.
- */
- void
- tweak_roots()
- {
- register ROOT *root;
-
- for( root = root_root; root; root = root->link ) {
- root->articles = article_array[root->seq];
- }
- free( article_array );
- article_array = Null(ARTICLE**);
- }
-
- /* A short-hand for reading a chunk of the file into a malloc'ed array.
- */
- int
- read_item( dest, len )
- char **dest;
- MEM_SIZE len;
- {
- int ret;
-
- *dest = safemalloc( len );
- ret = fread( *dest, 1, (int)len, fp_in );
- if( ret != len ) {
- log_error( "Only read %ld bytes instead of %ld.\n",
- (long)ret, (long)len );
- free( *dest );
- *dest = Nullch;
- return 0;
- }
- return 1;
- }
-
- /* Interpret rn's '%X' and '%x' path prefixes without including all their
- ** source. Names that don't start with '%' or '/' are prefixed with the
- ** SPOOL directory.
- */
- char *
- file_exp( name )
- char *name;
- {
- static char name_buff[256];
-
- if( *name == '/' ) { /* fully qualified names are left alone */
- return name;
- } else if( *name != '%' ) { /* all normal names are relative to SPOOL */
- sprintf( name_buff, "%s/%s", SPOOL, name );
- } else { /* interpret %x (LIB) & %X (RNLIB) */
- if( name[1] == 'x' ) {
- strcpy( name_buff, LIB );
- } else if( name[1] == 'X' ) {
- strcpy( name_buff, RNLIB );
- } else {
- log_entry( "Unknown expansion: %s", name );
- exit( 1 );
- }
- strcat( name_buff, name+2 );
- }
- return name_buff;
- }
-
- #ifndef lint
- /* A malloc that bombs-out when memory is exhausted. */
- char *
- safemalloc( amount )
- MEM_SIZE amount;
- {
- register char *cp;
- extern char *malloc();
-
- if( (cp = malloc( amount )) == Nullch ) {
- log_error( "malloc(%ld) failed.\n", (long)amount );
- exit( 1 );
- }
- return cp;
- }
- #endif
-
- /* Create a malloc'ed copy of a string. */
- char *
- savestr( str )
- char *str;
- {
- register MEM_SIZE len = strlen( str ) + 1;
- register char *newaddr = safemalloc( len );
-
- bcopy( str, newaddr, (int)len );
-
- return newaddr;
- }
-
- #ifndef lint
- /* Free some memory if it hasn't already been freed. */
- void
- safefree( pp )
- char **pp;
- {
- if( *pp ) {
- free( *pp );
- *pp = Nullch;
- }
- }
- #endif
-