home *** CD-ROM | disk | FTP | other *** search
/ ftp.freefriends.org / ftp.freefriends.org.tar / ftp.freefriends.org / arnold / Source / mush.rstevens.tar.gz / mush.tar / sort.c < prev    next >
C/C++ Source or Header  |  1994-07-09  |  9KB  |  314 lines

  1. /* sort.c 3.0    (c) copyright 1986,1990 (Dan Heller) */
  2.  
  3. #include "mush.h"
  4. /* #define MYQSORT */
  5.  
  6. /* The size of this array should really be bounded by
  7.  * 2 spaces for each possible different sort criteria
  8.  * (one space for each key letter and one per for 'r'),
  9.  * but 16 leaves room to add to the current list.
  10.  */
  11. static char subsort[16];
  12.  
  13. static int depth, order, ignore_case;
  14. static jmp_buf sortbuf;
  15. static int msg_cmp();
  16. sort(argc, argv, list)
  17. register int argc;
  18. register char *argv[], list[];
  19. {
  20.     SIGRET (*oldint)(), (*oldquit)();
  21.     int n, offset = -1, range = 0;
  22.     long curr_msg_off = msg[current_msg].m_offset;
  23.  
  24.     depth = 0, order = 1, ignore_case = FALSE;
  25.  
  26.     while (argc && *++argv) {
  27.     n = (argv[0][0] == '-' && argv[0][1] != 0);
  28.     while (argv[0][n]) {
  29.         if (depth > sizeof subsort - 2)
  30.         break;
  31.         switch(argv[0][n]) {
  32.         case '-': /* reverse order of next criteria (obsolete) */
  33.             argv[0][n] = 'r'; /* fix it and fall through */
  34.         case 'r': /* reverse order of next criteria */
  35.         case 'd': /* sort by date */
  36.         case 'a': /* sort by author (address) */
  37.         case 's': /* sort by subject (ignore Re:) */
  38.         case 'R': /* sort by subject including Re: */
  39.         case 'l': /* sort by length in bytes */
  40.         case 'S': /* sort by message status */
  41.         case 'p': /* sort by message priority */
  42.             /* skip consecutive repeats of the same flag */
  43.             if (depth < 1 || subsort[depth-1] != argv[0][n])
  44.             subsort[depth++] = argv[0][n];
  45.         when 'i': ignore_case = TRUE;
  46.         otherwise: return help(0, "sort", cmd_help);
  47.         }
  48.         n++;
  49.     }
  50.     }
  51.     if (depth == 0 || subsort[depth-1] == 'r')
  52.     subsort[depth++] = 'S'; /* status sort is the default */
  53.     subsort[depth] = 0;
  54.     depth = 0;    /* start at the beginning */
  55.     if (msg_cnt <= 1) {
  56.     print("Not enough messages to sort.\n");
  57.     return -1;
  58.     }
  59.     turnon(glob_flags, IGN_SIGS);
  60.     on_intr();
  61.  
  62.     if (list && ison(glob_flags, IS_PIPE)) {
  63.     int consec = 1;
  64.     for (n = 0; n < msg_cnt; n++)
  65.         if (msg_bit(list, n)) {
  66.         if (!consec) {
  67.             ok_box("Listed messages not consecutive\n");
  68.             turnoff(glob_flags, IGN_SIGS);
  69.             off_intr();
  70.             return -1;
  71.         }
  72.         if (offset < 0)
  73.             offset = n;
  74.         range++;
  75.         } else if (offset >= 0)
  76.         consec = 0;
  77.     } else
  78.     offset = 0, range = msg_cnt;
  79.  
  80.     if (range < 2)
  81.     print("Range not broad enough to sort anything\n");
  82.     else {
  83.     Debug("Sorting %d messages starting at message %d\n", range, offset+1);
  84.  
  85.     if (setjmp(sortbuf) == 0)
  86.         qsort((char *)&msg[offset], range, sizeof (struct msg), msg_cmp);
  87.     else
  88.         print("WARNING: Sorting interrupted: unpredictable order.\n");
  89.     turnon(glob_flags, DO_UPDATE);
  90.     }
  91.     for (n = 0; n < msg_cnt; n++)
  92.     if (msg[n].m_offset == curr_msg_off)
  93.         break;
  94.     current_msg = n;
  95.     turnoff(glob_flags, IGN_SIGS);
  96.     off_intr();
  97.     /* Break pipes because message lists are invalid */
  98.     return 0 - in_pipe();
  99. }
  100.  
  101. #ifdef MYQSORT
  102. qsort(base, len, siz, compar)
  103. register struct msg *base;
  104. int (*compar)();
  105. {
  106.      register int i, swapping;
  107.      struct msg temp;
  108.  
  109.      do  {
  110.      swapping = 0;
  111.      for (i = 0; i < len-1; ++i) {
  112.          if (compar(base+i, base+i+1) > 0) {
  113.          temp = base[i];
  114.          base[i] = base[i+1];
  115.          base[i+1] = temp;
  116.          swapping = 1;
  117.          }
  118.      }
  119.      } while (swapping);
  120. }
  121. #endif /* MYSORT */
  122.  
  123. status_cmp(msg1, msg2)
  124. register struct msg *msg1, *msg2;
  125. {
  126.     if (msg1->m_flags == msg2->m_flags)
  127.     return msg_cmp(msg1, msg2);
  128.     if (ison(msg1->m_flags, DELETE) && isoff(msg2->m_flags, DELETE))
  129.     return order;
  130.     if (isoff(msg1->m_flags, DELETE) && ison(msg2->m_flags, DELETE))
  131.     return -order;
  132.     if (isoff(msg1->m_flags, OLD) && ison(msg2->m_flags, OLD))
  133.     return -order;
  134.     if (ison(msg1->m_flags, OLD) && isoff(msg2->m_flags, OLD))
  135.     return order;
  136.     if (ison(msg1->m_flags, UNREAD) && isoff(msg2->m_flags, UNREAD))
  137.     return -order;
  138.     if (isoff(msg1->m_flags, UNREAD) && ison(msg2->m_flags, UNREAD))
  139.     return order;
  140.     if (ison(msg1->m_flags,PRESERVE) && isoff(msg2->m_flags,PRESERVE))
  141.     return -order;
  142.     if (isoff(msg1->m_flags,PRESERVE) && ison(msg2->m_flags,PRESERVE))
  143.     return order;
  144.     if (ison(msg1->m_flags,REPLIED) && isoff(msg2->m_flags,REPLIED))
  145.     return -order;
  146.     if (isoff(msg1->m_flags,REPLIED) && ison(msg2->m_flags,REPLIED))
  147.     return order;
  148.     if (ison(msg1->m_flags,SAVED) && isoff(msg2->m_flags,SAVED))
  149.     return -order;
  150.     if (isoff(msg1->m_flags,SAVED) && ison(msg2->m_flags,SAVED))
  151.     return order;
  152.     if (ison(msg1->m_flags,PRINTED) && isoff(msg2->m_flags,PRINTED))
  153.     return -order;
  154.     if (isoff(msg1->m_flags,PRINTED) && ison(msg2->m_flags,PRINTED))
  155.     return order;
  156.     if (ison(msg1->m_flags,FORWARD) && isoff(msg2->m_flags,FORWARD))
  157.     return -order;
  158.     if (isoff(msg1->m_flags,FORWARD) && ison(msg2->m_flags,FORWARD))
  159.     return order;
  160.  
  161.     return pri_cmp(msg1, msg2);
  162. }
  163.  
  164. author_cmp(msg1, msg2)
  165. register struct msg *msg1, *msg2;
  166. {
  167.     char buf1[HDRSIZ], buf2[HDRSIZ];
  168.     int retval;
  169.  
  170.     (void) reply_to(msg1 - msg, 0, buf1); /* "0" for "author only" */
  171.     (void) reply_to(msg2 - msg, 0, buf2);
  172.     Debug("author: msg %d: %s, msg %d: %s\n", msg1-msg, buf1, msg2-msg, buf2);
  173.     if (ignore_case)
  174.     retval = lcase_strncmp(buf1, buf2, -1) * order;
  175.     else
  176.     retval = strcmp(buf1, buf2) * order;
  177.     return retval ? retval : msg_cmp(msg1, msg2);
  178. }
  179.  
  180. /* compare messages according to size (length) */
  181. size_cmp(msg1, msg2)
  182. register struct msg *msg1, *msg2;
  183. {
  184.     int retval;
  185.  
  186.     Debug("sizes: (%d): %d, (%d): %d\"\n",
  187.     msg1-msg, msg1->m_size, msg2-msg, msg2->m_size);
  188.     if (retval = (msg1->m_size - msg2->m_size) * order) /* assign and test */
  189.     return retval;
  190.     return msg_cmp(msg1, msg2);
  191. }
  192.  
  193. /*
  194.  * Subject comparison ignoring Re:  subject_to() appends an Re: if there is
  195.  * any subject whatsoever.
  196.  */
  197. subject_cmp(msg1, msg2)
  198. register struct msg *msg1, *msg2;
  199. {
  200.     char buf1[HDRSIZ], buf2[HDRSIZ];
  201.     register char *p1, *p2;
  202.     int retval;
  203.  
  204.     p1 = subject_to(msg1 - msg, buf1);
  205.     p2 = subject_to(msg2 - msg, buf2);
  206.     if (p1) {
  207.     p1 += 4;
  208.     while (isspace(*p1))
  209.         p1++;
  210.     } else
  211.     p1 = buf1; /* subject_to() makes it an empty string */
  212.     if (p2) {
  213.     p2 += 4;
  214.     while (isspace(*p2))
  215.         p2++;
  216.     } else
  217.     p2 = buf2; /* subject_to() makes it an empty string */
  218.     Debug("subjects: (%d): \"%s\" (%d): \"%s\"\n", msg1-msg, p1, msg2-msg, p2);
  219.     if (ignore_case)
  220.     retval = lcase_strncmp(p1, p2, -1) * order;
  221.     else
  222.     retval = strcmp(p1, p2) * order;
  223.     return retval ? retval : msg_cmp(msg1, msg2);
  224. }
  225.  
  226. /*
  227.  * compare subject strings from two messages.
  228.  * If Re is appended, so be it -- if user wants to ignore Re: use 'R' flag.
  229.  */
  230. subj_with_re(msg1, msg2)
  231. register struct msg *msg1, *msg2;
  232. {
  233.     char buf1[HDRSIZ], buf2[HDRSIZ], *p;
  234.     int retval;
  235.  
  236.     if (!(p = header_field(msg1 - msg, "subject")))
  237.     p = "";
  238.     (void) strcpy(buf1, p);
  239.     if (!(p = header_field(msg2 - msg, "subject")))
  240.     p = "";
  241.     (void) strcpy(buf2, p);
  242.     Debug("subjects: (%d): \"%s\" (%d): \"%s\"\n",
  243.     msg1-msg, buf1, msg2-msg, buf2);
  244.     if (ignore_case)
  245.     retval = lcase_strncmp(buf1, buf2, -1) * order;
  246.     else
  247.     retval = strcmp(buf1, buf2) * order;
  248.     return retval ? retval : msg_cmp(msg1, msg2);
  249. }
  250.  
  251. date_cmp(msg1, msg2)
  252. register struct msg *msg1, *msg2;
  253. {
  254.     long tm1, tm2;
  255.  
  256.     if (ison(glob_flags, DATE_RECV)) {
  257.     (void) sscanf(msg1->m_date_recv, "%ld", &tm1);
  258.     (void) sscanf(msg2->m_date_recv, "%ld", &tm2);
  259.     } else {
  260.     (void) sscanf(msg1->m_date_sent, "%ld", &tm1);
  261.     (void) sscanf(msg2->m_date_sent, "%ld", &tm2);
  262.     }
  263.     return tm1 < tm2 ? -order : (tm1 > tm2) ? order : msg_cmp(msg1, msg2);
  264. }
  265.  
  266. pri_cmp(msg1, msg2)
  267. register struct msg *msg1, *msg2;
  268. {
  269.     int i;
  270.     u_long pr1 = 0, pr2 = 0;
  271.  
  272.     for (i = 0; pr1 == pr2 && i <= MAX_PRIORITY; i++) {
  273.     if (ison(msg1->m_flags, M_PRIORITY(i)))
  274.         turnon(pr1, ULBIT(i));
  275.     if (ison(msg2->m_flags, M_PRIORITY(i)))
  276.         turnon(pr2, ULBIT(i));
  277.     }
  278.     return pr1 > pr2 ? -order : (pr1 < pr2) ? order : msg_cmp(msg1, msg2);
  279. }
  280.  
  281. static
  282. msg_cmp(msg1, msg2)
  283. register struct msg *msg1, *msg2;
  284. {
  285.     int sv_order = order, sv_depth = depth, retval = 0;
  286.  
  287.     if (ison(glob_flags, WAS_INTR))
  288.     longjmp(sortbuf, 1);
  289.     if (msg1 < msg || msg2 < msg) {
  290.     wprint("sort botch trying to sort %d and %d using %s\n",
  291.         msg1-msg, msg2-msg, subsort);
  292.     return 0;
  293.     }
  294.  
  295.     if (subsort[depth] == 'r') {
  296.     order = -1;
  297.     depth++;
  298.     } else
  299.     order = 1;
  300.     switch(subsort[depth++]) {
  301.     case '\0': retval = 0;
  302.     when 'd': retval = date_cmp(msg1, msg2);
  303.     when 'a': retval = author_cmp(msg1, msg2);
  304.     when 's': retval = subject_cmp(msg1, msg2);
  305.     when 'R': retval = subj_with_re(msg1, msg2);
  306.     when 'l': retval = size_cmp(msg1, msg2); /* length compare */
  307.     when 'p': retval = pri_cmp(msg1, msg2);
  308.     otherwise: retval = status_cmp(msg1, msg2);
  309.     }
  310.     depth = sv_depth;
  311.     order = sv_order;
  312.     return retval;
  313. }
  314.