home *** CD-ROM | disk | FTP | other *** search
- /*
- * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
- *
- * Article sorting.
- */
-
- #include "config.h"
- #include "articles.h"
-
-
-
- export int subject_match_limit = 20; /* "strncmp" limit for subjects */
- export int match_skip_prefix = 0; /* skip first N bytes in matches */
- export int match_parts_equal = 0; /* match digits as equal */
-
- export int sort_mode = 1; /* default sort mode */
-
- /*
- * String matching macroes.
- *
- * MATCH_DROP(t, a) and MATCH_DROP(t, b) must both be proven false
- * before MATCH_???(t, a, b) is used.
- */
-
- #define MATCH_DROP(table, c) ( c & 0200 || table[c] == 0 )
- #define MATCH_EQ(table, a, b) ( a == b || table[a] == table[b] )
- #define MATCH_LS_EQ(table, a, b) ( a <= b || table[a] <= table[b] )
- #define MATCH_LS(table, a, b) ( a < b || table[a] < table[b] )
- #define MATCH_CMP(table, a, b) (table[a] - table[b])
-
- static char match_subject[128] = {
-
- /* NUL SOH STX ETX EOT ENQ ACK BEL BS TAB NL VT FF CR SO SI */
- 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
-
- /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US */
- 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
-
- /* SP ! " # $ % & ' ( ) * + , - . / */
- 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 99, 00, 00, 00, 00,
- /* ^^ */
-
- /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 00, 00, 00, 00, 00, 00,
-
- /* @ A B C D E F G H I J K L M N O */
- 00, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
-
- /* P Q R S T U V W X Y Z [ \ ] ^ _ */
- 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 00, 00,
-
- /* ` a b c d e f g h i j k l m n o */
- 00, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
-
- /* p q r s t u v w x y z { | } ~ DEL */
- 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 00, 00
- };
-
-
- static order_subj_date(ah1, ah2)
- article_header **ah1, **ah2;
- {
- register char *a = (**ah1).subject, *b = (**ah2).subject;
- register char ca, cb;
- register int p, len;
-
- if (match_skip_prefix) {
- if ((**ah1).subj_length > match_skip_prefix) {
- if ((**ah2).subj_length > match_skip_prefix) {
- a += match_skip_prefix;
- b += match_skip_prefix;
- } else
- return 1;
- } else {
- if ((**ah2).subj_length > match_skip_prefix) {
- return -1;
- }
- }
- }
-
- for (len = 0; ; len++, a++, b++) {
- while ((ca = *a) && MATCH_DROP(match_subject, ca)) a++;
- while ((cb = *b) && MATCH_DROP(match_subject, cb)) b++;
-
- if (ca == NUL) {
- if (cb == NUL) break;
- if (len >= subject_match_limit) break;
- return -1;
- }
-
- if (cb == NUL) {
- if (len >= subject_match_limit) break;
- return 1;
- }
-
- if (p = MATCH_CMP(match_subject, ca, cb)) return p;
- }
-
- if ((**ah1).t_stamp > (**ah2).t_stamp) return 1;
- if ((**ah1).t_stamp < (**ah2).t_stamp) return -1;
- return 0;
- }
-
- /* data_subj_date can only be used after root_t_stamp is set */
-
- static order_date_subj_date(ah1, ah2)
- article_header **ah1, **ah2;
- {
- register time_stamp t1 = (**ah1).root_t_stamp;
- register time_stamp t2 = (**ah2).root_t_stamp;
-
- if (t1 > t2) return 1;
- if (t1 < t2) return -1;
- return order_subj_date(ah1, ah2); /* get original order */
- }
-
-
- static order_arrival(a, b)
- article_header **a, **b;
- {
- register long i;
-
- if ((i = (int)((*a)->a_number - (*b)->a_number)) == 0)
- i = (*a)->fpos - (*b)->fpos;
-
- return (i > 0) ? 1 : (i < 0) ? -1 : 0;
- }
-
- static order_date(ah1, ah2)
- register article_header **ah1, **ah2;
- {
- if ((**ah1).t_stamp > (**ah2).t_stamp) return 1;
- if ((**ah1).t_stamp < (**ah2).t_stamp) return -1;
- return 0;
- }
-
- static order_from_date(ah1, ah2)
- register article_header **ah1, **ah2;
- {
- register int i;
-
- if (i = strcmp((**ah1).sender, (**ah2).sender)) return i;
- return order_date(ah1, ah2);
- }
-
- static flag_type article_equal(ah1, ah2) /* ah1.hdr == ah2.hdr */
- article_header **ah1, **ah2;
- {
- register char *a = (**ah1).subject, *b = (**ah2).subject;
- register int len;
-
- if (match_skip_prefix) {
- if ((**ah1).subj_length > match_skip_prefix) {
- if ((**ah2).subj_length > match_skip_prefix) {
- a += match_skip_prefix;
- b += match_skip_prefix;
- }
- }
- }
-
- for (len = 0;; len++, a++, b++) {
- while (*a && MATCH_DROP(match_subject, *a)) a++;
- while (*b && MATCH_DROP(match_subject, *b)) b++;
-
- if (*a == NUL) {
- if (*b == NUL) break;
- if (len >= subject_match_limit) return A_ALMOST_SAME;
- return 0;
- }
-
- if (*b == NUL) {
- if (len >= subject_match_limit) return A_ALMOST_SAME;
- return 0;
- }
-
- if (!MATCH_EQ(match_subject, *a, *b)) {
- if (len >= subject_match_limit)
- return A_ALMOST_SAME;
- if (match_parts_equal && isdigit(*a) && isdigit(*b))
- return A_ALMOST_SAME;
- return 0;
- }
- }
-
- return A_SAME;
- }
-
- sort_articles(mode)
- int mode;
- {
- register article_header **app;
- register long n;
- register flag_type same;
- fct_type cmp;
-
- for (n = n_articles; --n >= 0;)
- articles[n]->flag &= ~(A_SAME|A_ALMOST_SAME|A_NEXT_SAME);
-
- if (n_articles <= 1) return;
-
- if (mode == -1) mode = sort_mode;
-
- switch (mode) {
- default:
- case 0: /* arrival (no sort) */
- cmp = order_arrival;
- break;
- case 1: /* date-subject-date */
- case 2: /* subject-date */
- cmp = order_subj_date;
- break;
- case 3: /* date only */
- cmp = order_date;
- break;
- case 4: /* sender-date */
- cmp = order_from_date;
- break;
- }
-
- quicksort(articles, n_articles, article_header *, cmp);
-
- articles[0]->root_t_stamp = articles[0]->t_stamp;
- for (n = n_articles - 1, app = articles + 1; --n >= 0; app++) {
- if (same = article_equal(app, app - 1)) {
- app[0]->root_t_stamp = app[-1]->root_t_stamp;
- app[0]->flag |= same;
- app[-1]->flag |= A_NEXT_SAME;
- } else {
- app[0]->root_t_stamp = app[0]->t_stamp;
- }
- }
-
- if (mode == 1)
- quicksort(articles, n_articles, article_header *, order_date_subj_date);
- }
-
-
- /*
- * Eliminate articles with the A_KILL flag set preserving the present ordering.
- * This will only release the last entries in the articles array.
- * Neither strings nor articles headers are released.
- */
-
- elim_articles(list, list_lgt)
- register article_number *list;
- int list_lgt;
- {
- register article_header **srca, **desta;
- register article_number n, count;
- register flag_type same;
- int changed, llen;
-
- count = 0;
- changed = 0, llen = 0;
- for (n = 0, srca = desta = articles; n < n_articles; n++, srca++) {
- if ((*srca)->attr == A_KILL) {
- if (list_lgt > 0) {
- if (n < *list) {
- if (llen) changed = 1;
- } else
- if (n == *list) {
- if (llen) {
- llen++;
- list_lgt--;
- *list++ = -1;
- } else
- ++(*list);
- changed = 1;
- }
- }
- continue;
- }
- if (list_lgt > 0 && n == *list) {
- *list++ = count;
- list_lgt--;
- llen++;
- }
- count++;
- *desta++ = *srca;
- }
- if (list_lgt > 0) {
- if (!llen) *list = 0;
- changed = 1;
- }
- n_articles = count;
-
- if (changed && n_articles > 0) {
- srca = articles;
- srca[0]->flag &= ~(A_SAME|A_ALMOST_SAME|A_NEXT_SAME);
- for (n = n_articles - 1, srca++; --n >= 0; srca++) {
- srca[0]->flag &= ~(A_SAME|A_ALMOST_SAME|A_NEXT_SAME);
- if (same = article_equal(srca, srca - 1)) {
- srca[0]->flag |= same;
- srca[-1]->flag |= A_NEXT_SAME;
- }
- }
- }
-
- return changed;
- }
-