home *** CD-ROM | disk | FTP | other *** search
- /* $Header: rt-rn.c,v 4.3.3.1 90/07/28 18:07:55 davison Trn $
- **
- ** $Log: rt-rn.c,v $
- ** Revision 4.3.3.1 90/07/28 18:07:55 davison
- ** Initial Trn Release
- **
- */
-
- #include "EXTERN.h"
- #include "common.h"
- #include "term.h"
- #include "final.h"
- #include "util.h"
- #include "bits.h"
- #include "artio.h"
- #include "ng.h"
- #include "ngdata.h"
- #include "search.h"
- #include "artstate.h"
- #include "backpage.h"
- #include "rthreads.h"
-
- #ifdef USETHREADS
-
- static void find_depth(), cache_tree(), display_tree();
- static char letter();
-
- /* Find the article structure information based on article number.
- */
- void
- find_article( artnum )
- ART_NUM artnum;
- {
- register PACKED_ARTICLE *article;
- register int i;
-
- if( !p_articles ) {
- p_art = Nullart;
- return;
- }
-
- if( !p_art ) {
- p_art = p_articles;
- }
- /* Start looking for the article num from our last known spot in the array.
- ** That way, if we already know where we are, we run into ourselves right
- ** away.
- */
- for( article=p_art, i=p_art-p_articles; i < total.article; article++,i++ ) {
- if( article->num == artnum ) {
- p_art = article;
- return;
- }
- }
- /* Didn't find it, so search the ones before our current position.
- */
- for( article = p_articles; article != p_art; article++ ) {
- if( article->num == artnum ) {
- p_art = article;
- return;
- }
- }
- p_art = Nullart;
- }
-
- static char tree_indent[] = {
- ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0
- };
-
- char letters[] = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz?";
-
- static PACKED_ARTICLE *tree_article;
-
- static int max_depth, max_line = -1;
- static int first_depth, first_line;
- static int my_depth, my_line;
- static bool node_on_line;
- static int node_line_cnt;
-
- static int line_num;
- static int header_indent;
-
- static char *tree_lines[11];
- static char tree_buff[128], *str;
-
- /* Prepare tree display for inclusion in the article header.
- */
- void
- init_tree()
- {
- register PACKED_ARTICLE *article;
-
- #if 000 /* don't do this, since read-status may change */
- if( curr_p_art == tree_article ) {
- return;
- }
- #endif
- while( max_line >= 0 ) { /* free any previous tree data */
- free( tree_lines[max_line--] );
- }
- tree_article = curr_p_art;
-
- if( !curr_p_art ) {
- return;
- }
- article = p_articles + p_roots[curr_p_art->root].articles;
-
- max_depth = max_line = my_depth = my_line = node_line_cnt = 0;
- find_depth( article, 0 );
-
- if( max_depth <= 5 ) {
- first_depth = 0;
- } else {
- if( my_depth+2 > max_depth ) {
- first_depth = max_depth - 5;
- } else if( (first_depth = my_depth - 3) < 0 ) {
- first_depth = 0;
- }
- max_depth = first_depth + 5;
- }
- if( --max_line < max_tree_lines ) {
- first_line = 0;
- } else {
- if( my_line + max_tree_lines/2 > max_line ) {
- first_line = max_line - (max_tree_lines-1);
- } else if( (first_line = my_line - (max_tree_lines-1)/2) < 0 ) {
- first_line = 0;
- }
- max_line = first_line + max_tree_lines-1;
- }
-
- str = tree_buff; /* initialize first line's data */
- *str++ = ' ';
- node_on_line = FALSE;
- line_num = 0;
- /* cache our portion of the tree */
- cache_tree( article, 0, tree_indent );
-
- max_depth = (max_depth-first_depth) * 5; /* turn depth into char width */
- max_line -= first_line; /* turn max_line into count */
- /* shorten tree if lower lines aren't visible */
- if( node_line_cnt < max_line ) {
- max_line = node_line_cnt + 1;
- }
- }
-
- /* A recursive routine to find the maximum tree extents and where we are.
- */
- static void
- find_depth( article, depth )
- PACKED_ARTICLE *article;
- {
- if( depth > max_depth ) {
- max_depth = depth;
- }
- for( ;; ) {
- if( article == tree_article ) {
- my_depth = depth;
- my_line = max_line;
- }
- if( article->child_cnt ) {
- find_depth( article+1, depth+1 );
- } else {
- max_line++;
- }
- if( !article->siblings ) {
- break;
- }
- article += article->siblings;
- }
- }
-
- /* Place the tree display in a maximum of 11 lines x 6 nodes.
- */
- static void
- cache_tree( article, depth, cp )
- PACKED_ARTICLE *article;
- int depth;
- char *cp;
- {
- int depth_mode;
-
- cp[1] = ' ';
- if( depth >= first_depth && depth <= max_depth ) {
- cp += 5;
- depth_mode = 1;
- } else if( depth+1 == first_depth ) {
- depth_mode = 2;
- } else {
- cp = tree_indent;
- depth_mode = 0;
- }
- for( ;; ) {
- switch( depth_mode ) {
- case 1: {
- char ch;
-
- *str++ = (article->flags & ROOT_ARTICLE)? ' ' : '-';
- if( article == tree_article ) {
- *str++ = '*';
- }
- if( was_read( article->num ) ) {
- *str++ = '(';
- ch = ')';
- } else {
- *str++ = '[';
- ch = ']';
- }
- if( article == recent_p_art && article != tree_article ) {
- *str++ = '@';
- }
- *str++ = letter( article );
- *str++ = ch;
- if( article->child_cnt ) {
- *str++ = (article->child_cnt == 1)? '-' : '+';
- }
- if( article->siblings ) {
- *cp = '|';
- } else {
- *cp = ' ';
- }
- node_on_line = TRUE;
- break;
- }
- case 2:
- *tree_buff = (!article->child_cnt)? ' ' :
- (article->child_cnt == 1)? '-' : '+';
- break;
- default:
- break;
- }
- if( article->child_cnt ) {
- cache_tree( article+1, depth+1, cp );
- cp[1] = '\0';
- } else {
- if( !node_on_line && first_line == line_num ) {
- first_line++;
- }
- if( line_num >= first_line ) {
- if( str[-1] == ' ' ) {
- str--;
- }
- *str = '\0';
- tree_lines[line_num-first_line]
- = safemalloc( str-tree_buff + 1 );
- strcpy( tree_lines[line_num - first_line], tree_buff );
- if( node_on_line ) {
- node_line_cnt = line_num - first_line;
- }
- }
- line_num++;
- node_on_line = FALSE;
- }
- if( !article->siblings || line_num > max_line ) {
- break;
- }
- article += article->siblings;
- if( !article->siblings ) {
- *cp = '\\';
- }
- if( !first_depth ) {
- tree_indent[5] = ' ';
- }
- strcpy( tree_buff, tree_indent+5 );
- str = tree_buff + strlen( tree_buff );
- }
- }
-
- /* Output a header line with possible tree display on the right hand side.
- ** Does automatic wrapping of lines that are too long.
- */
- int
- tree_puts( orig_line, header_line, use_underline )
- char *orig_line;
- ART_LINE header_line;
- int use_underline;
- {
- char *buf;
- register char *line, *cp, *end;
- int pad_cnt, wrap_at;
- ART_LINE start_line = header_line;
- int i;
- char ch;
-
- /* Make a modifiable copy of the line */
- buf = safemalloc( strlen( orig_line ) + 2 ); /* yes, I mean "2" */
- strcpy( buf, orig_line );
- line = buf;
-
- /* Change any embedded control characters to spaces */
- for( end = line; *end && *end != '\n'; end++ ) {
- if( (unsigned char)*end < ' ' ) {
- *end = ' ';
- }
- }
- *end = '\0';
-
- if( !*line ) {
- strcpy( line, " " );
- end = line+1;
- }
-
- /* If this is the first subject line, output it with a preceeding [1] */
- if( use_underline && curr_p_art && (unsigned char)*line > ' ' ) {
- #ifdef NOFIREWORKS
- no_sofire();
- #endif
- standout();
- putchar( '[' );
- putchar( letter( curr_p_art ) );
- putchar( ']' );
- un_standout();
- putchar( ' ' );
- header_indent = 4;
- line += 9;
- i = 0;
- } else {
- if( *line != ' ' ) {
- /* A "normal" header line -- output keyword and set header_indent
- ** _except_ for the first line, which is a non-standard header.
- */
- if( !header_line || !(cp = index( line, ':' )) || *++cp != ' ' ) {
- header_indent = 0;
- } else {
- *cp = '\0';
- fputs( line, stdout );
- putchar( ' ' );
- header_indent = ++cp - line;
- line = cp;
- }
- i = 0;
- } else {
- /* Skip whitespace of continuation lines and prepare to indent */
- while( *++line == ' ' ) {
- ;
- }
- i = header_indent;
- }
- }
- for( ; *line; i = header_indent ) {
- #ifdef CLEAREOL
- maybe_eol();
- #endif
- if( i ) {
- putchar( '+' );
- while( --i ) {
- putchar( ' ' );
- }
- }
- /* If no (more) tree lines, wrap at COLS-1 */
- if( max_line < 0 || header_line > max_line+1 ) {
- wrap_at = COLS-1;
- } else {
- wrap_at = COLS - max_depth - 5 - 3;
- }
- /* Figure padding between header and tree output, wrapping long lines */
- pad_cnt = wrap_at - (end - line + header_indent);
- if( pad_cnt <= 0 ) {
- cp = line + wrap_at - header_indent - 1;
- pad_cnt = 1;
- while( cp > line && *cp != ' ' ) {
- if( *--cp == ',' || *cp == '.' || *cp == '-' || *cp == '!' ) {
- cp++;
- break;
- }
- pad_cnt++;
- }
- if( cp == line ) {
- cp += wrap_at - header_indent;
- pad_cnt = 0;
- }
- ch = *cp;
- *cp = '\0';
- /* keep rn's backpager happy */
- vwtary( artline, vrdary( artline - 1 ) );
- artline++;
- } else {
- cp = end;
- ch = '\0';
- }
- if( use_underline ) {
- underprint( line );
- } else {
- fputs( line, stdout );
- }
- *cp = ch;
- /* Skip whitespace in wrapped line */
- while( *cp == ' ' ) {
- cp++;
- }
- line = cp;
- /* Check if we've got any tree lines to output */
- if( wrap_at != COLS-1 && header_line <= max_line ) {
- char *cp1, *cp2;
-
- do {
- putchar( ' ' );
- } while( pad_cnt-- );
- /* Check string for the '*' flagging our current node
- ** and the '@' flagging our prior node.
- */
- cp = tree_lines[header_line];
- cp1 = index( cp, '*' );
- cp2 = index( cp, '@' );
- if( cp1 != Nullch ) {
- *cp1 = '\0';
- }
- if( cp2 != Nullch ) {
- *cp2 = '\0';
- }
- fputs( cp, stdout );
- /* Handle standout output for '*' and '@' marked nodes, then
- ** continue with the rest of the line.
- */
- while( cp1 || cp2 ) {
- standout();
- if( cp1 && (!cp2 || cp1 < cp2) ) {
- cp = cp1;
- cp1 = Nullch;
- *cp++ = '*';
- putchar( *cp++ );
- putchar( *cp++ );
- } else {
- cp = cp2;
- cp2 = Nullch;
- *cp++ = '@';
- }
- putchar( *cp++ );
- un_standout();
- if( *cp ) {
- fputs( cp, stdout );
- }
- }/* while */
- }/* if */
- putchar( '\n' ) FLUSH;
- header_line++;
- }/* for remainder of line */
-
- /* free allocated copy of line */
- free( buf );
-
- /* return number of lines displayed */
- return header_line - start_line;
- }
-
- /* Output any parts of the tree that are left to display. Called at the
- ** end of each header.
- */
- int
- finish_tree( last_line )
- ART_LINE last_line;
- {
- ART_LINE start_line = last_line;
-
- while( last_line <= max_line ) {
- artline++;
- last_line += tree_puts( "+", last_line, 0 );
- vwtary( artline, artpos ); /* keep rn's backpager happy */
- }
- return last_line - start_line;
- }
-
- /* Output the entire article tree for the user.
- */
- void
- entire_tree()
- {
- int j, root;
-
- if( check_page_line() ) {
- return;
- }
- if( !p_art ) {
- #ifdef VERBOSE
- IF( verbose )
- fputs( "\nNo article tree to display.\n", stdout );
- ELSE
- #endif
- #ifdef TERSE
- fputs( "\nNo tree.\n", stdout );
- #endif
- } else {
- root = p_art->root;
- #ifdef NOFIREWORKS
- no_sofire();
- #endif
- standout();
- printf( "T%ld:\n", (long)p_roots[root].root_num );
- un_standout();
- if( check_page_line() ) {
- return;
- }
- putchar( '\n' );
- for( j = 0; j < p_roots[root].subject_cnt; j++ ) {
- sprintf( buf, "[%c] %s\n", letters[j > 9+26+26 ? 9+26+26 : j],
- subject_ptrs[root_subjects[root]+j] );
- if( check_page_line() ) {
- return;
- }
- fputs( buf, stdout );
- }
- if( check_page_line() ) {
- return;
- }
- putchar( '\n' );
- if( check_page_line() ) {
- return;
- }
- putchar( ' ' );
- buf[3] = '\0';
- display_tree( p_articles+p_roots[p_art->root].articles, tree_indent );
-
- if( check_page_line() ) {
- return;
- }
- putchar( '\n' );
- }
- }
-
- /* A recursive routine to output the entire article tree.
- */
- static void
- display_tree( article, cp )
- PACKED_ARTICLE *article;
- char *cp;
- {
- if( cp - tree_indent > COLS || page_line < 0 ) {
- return;
- }
- cp[1] = ' ';
- cp += 5;
- for( ;; ) {
- putchar( (article->flags & ROOT_ARTICLE)? ' ' : '-' );
- if( was_read( article->num ) ) {
- buf[0] = '(';
- buf[2] = ')';
- } else {
- buf[0] = '[';
- buf[2] = ']';
- }
- buf[1] = letter( article );
- if( article == curr_p_art ) {
- standout();
- fputs( buf, stdout );
- un_standout();
- } else if( article == recent_p_art ) {
- putchar( buf[0] );
- standout();
- putchar( buf[1] );
- un_standout();
- putchar( buf[2] );
- } else {
- fputs( buf, stdout );
- }
-
- if( article->siblings ) {
- *cp = '|';
- } else {
- *cp = ' ';
- }
- if( article->child_cnt ) {
- putchar( (article->child_cnt == 1)? '-' : '+' );
- display_tree( article+1, cp );
- cp[1] = '\0';
- } else {
- putchar( '\n' ) FLUSH;
- }
- if( !article->siblings ) {
- break;
- }
- article += article->siblings;
- if( !article->siblings ) {
- *cp = '\\';
- }
- tree_indent[5] = ' ';
- if( check_page_line() ) {
- return;
- }
- fputs( tree_indent+5, stdout );
- }
- }
-
- int
- check_page_line()
- {
- if( page_line < 0 ) {
- return -1;
- }
- if( page_line >= LINES || int_count ) {
- register int cmd = -1;
- if( int_count || (cmd = get_anything()) ) {
- page_line = -1; /* disable further printing */
- if( cmd > 0 ) {
- pushchar( cmd );
- }
- return cmd;
- }
- }
- page_line++;
- return 0;
- }
-
- /* Calculate the subject letter representation. "Place-holder" nodes
- ** are marked with a ' ', others get a letter in the sequence:
- ** ' ', '1'-'9', 'A'-'Z', 'a'-'z', '?'
- */
- static char
- letter( article )
- PACKED_ARTICLE *article;
- {
- register int subj = article->subject;
-
- if( subj < 0 ) {
- return ' ';
- }
- subj -= root_subjects[article->root];
- if( subj < 9+26+26 ) {
- return letters[subj];
- }
- return '?';
- }
-
- /* Find the first unread article in the (possibly selected) root order.
- */
- void
- first_art()
- {
- register int r;
-
- if( !ThreadedGroup ) {
- art = firstart;
- return;
- }
- p_art = Nullart;
- art = lastart+1;
- follow_thread( 'n' );
- }
-
- /* Perform a command over all or a section of the article tree. Most of
- ** the option letters match commands entered from article mode:
- ** n - find the next unread article after current article.
- ** ^N - find the next unread article with the same subject.
- ** N - goto the next article in the thread.
- ** J - junk the entire thread.
- ** k - junk all articles with this same subject.
- ** K - kill all this article's descendants (we know that the caller
- ** killed the current article on the way here).
- ** u - mark entire thread as "unread".
- ** U - mark this article and its descendants as "unread".
- ** f - follow the thread (like 'n'), but don't attempt to find a new thread
- ** if we run off the end.
- */
- void
- follow_thread( cmd )
- char cmd;
- {
- int curr_subj = -1, sel;
- PACKED_ARTICLE *root_limit, *p_art_old = Nullart;
- bool subthread_flag;
-
- reread = FALSE;
-
- if( !p_art ) {
- if( ThreadedGroup && art > lastart ) {
- p_art = root_limit = p_articles;
- goto follow_root;
- }
- art++;
- return;
- }
- if( cmd == 'k' || cmd == Ctl('n') ) {
- if( (curr_subj = p_art->subject) == -1) {
- return;
- }
- p_art_old = p_art;
- }
- sel = (selected_roots[p_art->root] & 1);
- if( cmd == 'U' || cmd == 'K' ) {
- subthread_flag = TRUE;
- p_art_old = p_art;
- } else {
- subthread_flag = FALSE;
- }
- /* The current article is already marked as read for 'K' */
- if( cmd == 'k' || cmd == 'J' || cmd == 'u' ) {
- p_art = p_articles + p_roots[p_art->root].articles;
- art = p_art->num;
- if( cmd == 'u' ) {
- p_art_old = p_art;
- cmd = 'U';
- } else {
- if( !was_read( art )
- && (curr_subj < 0 || curr_subj == p_art->subject) ) {
- set_read( art, sel );
- }
- cmd = 'K';
- }
- }
- if( cmd == 'U' ) {
- if( p_art->subject != -1 ) {
- set_unread( art, sel );
- }
- root_article_cnts[p_art->root] = 1;
- scan_all_roots = FALSE;
- }
- follow_again:
- sel = (selected_roots[p_art->root] & 1);
- root_limit = upper_limit( p_art, subthread_flag );
- for( ;; ) {
- if( ++p_art == root_limit ) {
- break;
- }
- if( !(art = p_art->num) ) {
- continue;
- }
- if( cmd == 'K' || p_art->subject == -1 ) {
- if( !was_read( art )
- && (curr_subj < 0 || curr_subj == p_art->subject) ) {
- set_read( art, sel );
- }
- } else if( cmd == 'U' ) {
- set_unread( art, sel );
- } else if( !was_read( art )
- && (curr_subj < 0 || curr_subj == p_art->subject) ) {
- return;
- } else if( cmd == 'N' ) {
- reread = TRUE;
- return;
- }
- }/* for */
- if( p_art_old ) {
- p_art = p_art_old;
- if( cmd == 'U' && p_art->subject != -1 ) {
- art = p_art->num;
- return;
- }
- p_art_old = Nullart;
- cmd = 'n';
- curr_subj = -1;
- subthread_flag = FALSE;
- goto follow_again;
- }
- if( cmd == 'f' ) {
- p_art = Nullart;
- art = lastart+1;
- return;
- }
- follow_root:
- if( root_limit != p_articles + total.article ) {
- register int r;
-
- for( r = p_art->root; r < total.root; r++ ) {
- if( !selected_root_cnt || selected_roots[r] ) {
- p_art = p_articles + p_roots[r].articles;
- art = p_art->num;
- if( p_art->subject == -1 || (cmd != 'N' && was_read( art )) ) {
- if( cmd != 'N' ) {
- cmd = 'n';
- }
- curr_subj = -1;
- subthread_flag = FALSE;
- goto follow_again;
- }
- return;
- }
- }
- }
- if( !count_roots( FALSE ) && unthreaded ) {
- /* No threaded articles left -- blow everything else away */
- for( art = firstart; art <= lastart; art++ ) {
- oneless( art );
- }
- unthreaded = 0;
- }
- p_art = Nullart;
- art = lastart+1;
- }
-
- /* Go backward in the article tree. Options match commands in article mode:
- ** p - previous unread article.
- ** ^P - previous unread article with same subject.
- ** P - previous article.
- */
- void
- backtrack_thread( cmd )
- char cmd;
- {
- int curr_subj = -1, sel;
- PACKED_ARTICLE *root_limit, *p_art_old = Nullart;
-
- if( art > lastart ) {
- p_art = p_articles + total.article - 1;
- root_limit = Nullart;
- goto backtrack_root;
- }
- if( !p_art ) {
- art--;
- return;
- }
- if( cmd == Ctl('p') ) {
- if( (curr_subj = p_art->subject) == -1) {
- return;
- }
- p_art_old = p_art;
- }
- backtrack_again:
- sel = (selected_roots[p_art->root] & 1);
- root_limit = p_articles + p_roots[p_art->root].articles;
- for( ;; ) {
- if( p_art-- == root_limit ) {
- break;
- }
- if( !(art = p_art->num) ) {
- continue;
- }
- if( p_art->subject == -1 ) {
- set_read( art, sel );
- } else if( !was_read( art )
- && (curr_subj < 0 || curr_subj == p_art->subject) ) {
- return;
- } else if( cmd == 'P' ) {
- reread = TRUE;
- return;
- }
- }/* for */
- if( p_art_old ) {
- p_art = p_art_old;
- p_art_old = Nullart;
- curr_subj = -1;
- goto backtrack_again;
- }
- backtrack_root:
- if( root_limit != p_articles ) {
- register int r;
-
- for( r = p_art->root; r >= 0; r-- ) {
- if( !selected_root_cnt || selected_roots[r] ) {
- art = p_art->num;
- if( cmd != 'P' && was_read( art ) ) {
- goto backtrack_again;
- }
- return;
- }
- p_art = p_articles + p_roots[r].articles - 1;
- }
- }
- p_art = Nullart;
- art = absfirst-1;
- }
-
- /* Find the next root (first if p_art == NULL). If roots are selected,
- ** only choose from selected roots.
- */
- void
- next_root()
- {
- register int r;
-
- reread = FALSE;
-
- if( p_art ) {
- r = p_art->root+1;
- } else {
- r = 0;
- }
- for( ; r < total.root; r++ ) {
- if( !selected_root_cnt || selected_roots[r] ) {
- try_again:
- p_art = p_articles + p_roots[r].articles;
- art = p_art->num;
- if( p_art->subject == -1 || (!reread && was_read( art )) ) {
- follow_thread( reread ? 'N' : 'f' );
- if( art == lastart+1 ) {
- if( scan_all_roots || selected_root_cnt
- || root_article_cnts[r] ) {
- reread = TRUE;
- goto try_again;
- }
- continue;
- }
- }
- return;
- }
- }
- p_art = Nullart;
- art = lastart+1;
- forcelast = TRUE;
- }
-
- /* Find previous root (or last if p_art == NULL). If roots are selected,
- ** only choose from selected roots.
- */
- void
- prev_root()
- {
- register int r;
-
- reread = FALSE;
-
- if( p_art ) {
- r = p_art->root - 1;
- } else {
- r = total.root - 1;
- }
- for( ; r >= 0; r-- ) {
- if( !selected_root_cnt || selected_roots[r] ) {
- try_again:
- p_art = p_articles + p_roots[r].articles;
- art = p_art->num;
- if( p_art->subject == -1 || (!reread && was_read( art )) ) {
- follow_thread( reread ? 'N' : 'f' );
- if( art == lastart+1 ) {
- if( scan_all_roots || selected_root_cnt
- || root_article_cnts[r] ) {
- reread = TRUE;
- goto try_again;
- }
- continue;
- }
- }
- return;
- }
- }
- p_art = Nullart;
- art = lastart+1;
- forcelast = TRUE;
- }
-
- /* Return a pointer value that we will equal when we've reached the end of
- ** the current (sub-)thread.
- */
- PACKED_ARTICLE *
- upper_limit( artp, subthread_flag )
- PACKED_ARTICLE *artp;
- bool subthread_flag;
- {
- if( subthread_flag ) {
- for( ;; ) {
- if( artp->siblings ) {
- return artp + artp->siblings;
- }
- if( !artp->parent ) {
- break;
- }
- artp += artp->parent;
- }
- }
- return p_articles + (artp->root == total.root-1 ?
- total.article : p_roots[artp->root+1].articles);
- }
-
- #endif /* USETHREADS */
-