home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d145 / csh.lha / Csh / sets / sets.c < prev   
C/C++ Source or Header  |  1988-05-26  |  5KB  |  243 lines

  1. /*
  2.  * sets - performs set operations on two sets of arguments and
  3.  *        prints the result on the standard output stream
  4.  * 
  5.  * usage: sets    [-p[aths]]  e1 e2 ... en \-u[nion] e1 e2 ... en
  6.  *                    OR
  7.  *                     e1 e2 ... en \-d[ifference] e1 e2 ... en
  8.  *                    OR
  9.  *                     e1 e2 ... en \-i[ntersection] e1 e2 ... en
  10.  *
  11.  * This code may be freely distributed provided this comment
  12.  * is not removed or substantially altered.  Please mail me any
  13.  * fixes, changes, or enhancements.
  14.  *
  15.  * Christopher Tweed, EdCAAD, University of Edinburgh, Scotland.
  16.  * chris@caad.ed.ac.uk
  17.  * ..mcvax!ukc!edcaad!chris
  18.  *
  19.  * 3 December 1987.
  20.  * 
  21.  */
  22.  
  23. #include <stdio.h>
  24. #include <string.h>
  25.  
  26. #define MAXSET    256    /* maximum size of a set */
  27.  
  28. #define STREQ(s1, s2)    (strcmp((s1), (s2)) == 0)
  29. #define NOT(p)        ((p) == FALSE)
  30. #define NAME(s)        ((ignorep == TRUE) ? nopath(s) : s)
  31.  
  32. typedef enum { FALSE=0, TRUE } BOOLEAN;
  33. typedef enum { NULL_OP=0, UNION, DIFF, INTERSECT } OPERATOR;
  34.  
  35. extern    int     strcmp();
  36. static    void    too_many();
  37. static    void    usage();
  38. static    char    *nopath();
  39. static    BOOLEAN    member();
  40. static    BOOLEAN    ignorep = TRUE;
  41.  
  42. main(argc, argv)
  43. int argc;
  44. char *argv[];
  45. {
  46.     int i, j;            /* general purpose */
  47.     BOOLEAN second = FALSE;        /* flag set after operator */
  48.     char *set1[MAXSET];        /* the first set */
  49.     int n1 = 0;            /* number of elements in first set */
  50.     char *set2[MAXSET];        /* the second set */
  51.     int n2 = 0;            /* number of elements in second set */
  52.     int n;                /* number in each set */
  53.     register OPERATOR op = NULL_OP;    /* set operation to perform */
  54.  
  55.     if (argc < 2) {
  56.         fprintf(stderr, "not enough arguments\n");
  57.         usage(argv[0]);        /* EXITS */
  58.     }
  59.  
  60.     n2 = n1 = 0;
  61.     /* collect sets */
  62.     while(--argc) {
  63.         if (argv[1][0] == '-') {
  64.         second = TRUE;            /* found an operator */
  65.         switch (argv[1][1]) {
  66.             case 'u':            /* set union */
  67.             op = UNION;
  68.             break;
  69.             case 'd':            /* set difference */
  70.             op = DIFF;
  71.             break;
  72.             case 'i':            /* set intersection */
  73.             op = INTERSECT;
  74.             break;
  75.             case 'p':            /* don't ignore paths */
  76.             ignorep = FALSE;
  77.             break;
  78.             default:
  79.             fprintf(stderr, "illegal set operator %c\n",
  80.                      argv[1][1]);
  81.             usage(argv[0]);    /* EXITS */
  82.         }
  83.         } else {
  84.         if (second == TRUE) {
  85.             if (n2 == MAXSET)
  86.             too_many();    /* EXITS */
  87.             set2[n2++] = argv[1];
  88.         } else {
  89.             if (n1 == MAXSET)
  90.             too_many();    /* EXITS */
  91.             set1[n1++] = argv[1];
  92.         }
  93.         }
  94.         argv++;
  95.     }
  96.  
  97.     if (op == NULL_OP) {
  98.         fprintf(stderr, "missing operator\n");
  99.         usage(argv[0]);
  100.     }
  101.  
  102.     /* remove duplicates */
  103.     n1 = nodups(set1, n1);
  104.     n2 = nodups(set2, n2);
  105.     /*
  106.      * do set operation and print result
  107.      *
  108.      */
  109.     n = (op == UNION) ? (n1 + n2) : n1;
  110.     for (i = 0; i < n; i++) {
  111.         switch(op) {
  112.         case UNION:
  113.             j = i - n1;
  114.             if (i < n1)
  115.             printf("%s ", set1[i]);
  116.             else if (NOT(member(set2[j], set1, n1)))
  117.             printf("%s ", set2[j]);
  118.             break;
  119.         case DIFF:
  120.             if (member(set1[i], set2, n2) == FALSE) {
  121.             printf("%s ", set1[i]);
  122.             }
  123.             break;
  124.         case INTERSECT:
  125.             if (member(set1[i], set2, n2) == TRUE) {
  126.             printf("%s ", set1[i]);
  127.             }
  128.             break;
  129.         }
  130.     }
  131.  
  132.     printf("\n");
  133.     exit(0);
  134. }
  135.  
  136. /*
  137.  * nodups(set, n)
  138.  *
  139.  * removes duplicates from set of n elements and returns number
  140.  * of remaining elements in the set
  141.  *
  142.  */
  143.  
  144. int
  145. nodups(set, n)
  146. char *set[];
  147. int n;
  148. {
  149.     register int i;
  150.     register int j;
  151.     register int k;
  152.     register int nn = n;
  153.  
  154.     /*
  155.      * start at the top of the list
  156.      *
  157.      */
  158.     for(i=n-1; i>0; i--)
  159.         for(j=0; j<i; j++) {
  160.         if (set[i][0] == set[j][0] && STREQ(set[i], set[j])) {
  161.             set[i] = NULL;    /* cancel the duplicate */
  162.             /*
  163.              * move everything above
  164.              * the duplicate down one
  165.              *
  166.              */
  167.             for(k=i+1; k<nn; k++) {
  168.             set[k-1] = set[k];
  169.             set[k] = NULL;
  170.             }
  171.             nn--;
  172.             break;
  173.         }
  174.         }
  175.     return nn;
  176. }
  177.  
  178. /*
  179.  * member(s, set, n)
  180.  *
  181.  * returns TRUE if string s is a member of set which has n members
  182.  * otherwise return FALSE
  183.  *
  184.  */
  185.  
  186. static BOOLEAN
  187. member(s, set, n)
  188. register char *s, *set[];
  189. register int n;
  190. {
  191.     register int i;
  192.  
  193.     for (i = 0; i < n; i++)
  194.         if (STREQ(NAME(s), NAME(set[i])))
  195.         return TRUE;
  196.  
  197.     return FALSE;
  198. }
  199.  
  200. /*
  201.  * nopath(s)
  202.  *
  203.  * Strips leading path from s if necessary; otherwise
  204.  * returns s.
  205.  *
  206.  */
  207.  
  208. static char *
  209. nopath(s)
  210. char *s;
  211. {
  212.     char *p;
  213.  
  214. #ifdef AMIGA
  215.     if ((p = strrchr(s, '/')) || (p = strrchr(s, ':')))
  216. #else
  217.     if (p=strrchr(s, '/'))
  218. #endif
  219.         return ++p;
  220.     else
  221.         return s;
  222. }
  223.  
  224. static void
  225. too_many()
  226. {
  227.     fprintf(stderr, "too many members\n");
  228.     exit(1);
  229. }
  230.  
  231. static void
  232. usage(prog)
  233. char *prog;
  234. {
  235.     char *set = "e1 e2 ... en";
  236.  
  237.     fprintf(stderr, "%s\t%s -u[nion] %s\n", prog, set, set);
  238.     fprintf(stderr, "\t%s -d[ifference] %s\n", set, set);
  239.     fprintf(stderr, "\t%s -i[ntersection] %s\n", set, set);
  240.     fprintf(stderr, "\t-p[aths]\t/* don't ignore leading paths */\n");
  241.     exit(1);
  242. }
  243.