home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 400-499 / ff473.lzh / CNewsSrc / cnews_src.lzh / libc / split.c < prev    next >
C/C++ Source or Header  |  1990-12-25  |  7KB  |  312 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. /*
  5.  * split - divide a string into fields, like awk split()
  6.  */
  7. int                /* number of fields, including overflow */
  8. split(string, fields, nfields, sep)
  9. char *string;
  10. char *fields[];            /* list is not NULL-terminated */
  11. int nfields;            /* number of entries available in fields[] */
  12. char *sep;            /* "" white, "c" single char, "ab" [ab]+ */
  13. {
  14.     register char *p = string;
  15.     register char c;            /* latest character */
  16.     register char sepc = sep[0];
  17.     register char sepc2;
  18.     register int fn;
  19.     register char **fp = fields;
  20.     register char *sepp;
  21.     register int trimtrail;
  22.  
  23.     /* white space */
  24.     if (sepc == '\0') {
  25.         while ((c = *p++) == ' ' || c == '\t')
  26.             continue;
  27.         p--;
  28.         trimtrail = 1;
  29.         sep = " \t";    /* note, code below knows this is 2 long */
  30.         sepc = ' ';
  31.     } else
  32.         trimtrail = 0;
  33.     sepc2 = sep[1];        /* now we can safely pick this up */
  34.  
  35.     /* catch empties */
  36.     if (*p == '\0')
  37.         return(0);
  38.  
  39.     /* single separator */
  40.     if (sepc2 == '\0') {
  41.         fn = nfields;
  42.         for (;;) {
  43.             *fp++ = p;
  44.             fn--;
  45.             if (fn == 0)
  46.                 break;
  47.             while ((c = *p++) != sepc)
  48.                 if (c == '\0')
  49.                     return(nfields - fn);
  50.             *(p-1) = '\0';
  51.         }
  52.         /* we have overflowed the fields vector -- just count them */
  53.         fn = nfields;
  54.         for (;;) {
  55.             while ((c = *p++) != sepc)
  56.                 if (c == '\0')
  57.                     return(fn);
  58.             fn++;
  59.         }
  60.         /* not reached */
  61.     }
  62.  
  63.     /* two separators */
  64.     if (sep[2] == '\0') {
  65.         fn = nfields;
  66.         for (;;) {
  67.             *fp++ = p;
  68.             fn--;
  69.             while ((c = *p++) != sepc && c != sepc2)
  70.                 if (c == '\0') {
  71.                     if (trimtrail && **(fp-1) == '\0')
  72.                         fn++;
  73.                     return(nfields - fn);
  74.                 }
  75.             if (fn == 0)
  76.                 break;
  77.             *(p-1) = '\0';
  78.             while ((c = *p++) == sepc || c == sepc2)
  79.                 continue;
  80.             p--;
  81.         }
  82.         /* we have overflowed the fields vector -- just count them */
  83.         fn = nfields;
  84.         while (c != '\0') {
  85.             while ((c = *p++) == sepc || c == sepc2)
  86.                 continue;
  87.             p--;
  88.             fn++;
  89.             while ((c = *p++) != '\0' && c != sepc && c != sepc2)
  90.                 continue;
  91.         }
  92.         /* might have to trim trailing white space */
  93.         if (trimtrail) {
  94.             p--;
  95.             while ((c = *--p) == sepc || c == sepc2)
  96.                 continue;
  97.             p++;
  98.             if (*p != '\0') {
  99.                 if (fn == nfields+1)
  100.                     *p = '\0';
  101.                 fn--;
  102.             }
  103.         }
  104.         return(fn);
  105.     }
  106.  
  107.     /* n separators */
  108.     fn = 0;
  109.     for (;;) {
  110.         if (fn < nfields)
  111.             *fp++ = p;
  112.         fn++;
  113.         for (;;) {
  114.             c = *p++;
  115.             if (c == '\0')
  116.                 return(fn);
  117.             sepp = sep;
  118.             while ((sepc = *sepp++) != '\0' && sepc != c)
  119.                 continue;
  120.             if (sepc != '\0')    /* it was a separator */
  121.                 break;
  122.         }
  123.         if (fn < nfields)
  124.             *(p-1) = '\0';
  125.         for (;;) {
  126.             c = *p++;
  127.             sepp = sep;
  128.             while ((sepc = *sepp++) != '\0' && sepc != c)
  129.                 continue;
  130.             if (sepc == '\0')    /* it wasn't a separator */
  131.                 break;
  132.         }
  133.         p--;
  134.     }
  135.  
  136.     /* not reached */
  137. }
  138.  
  139. #ifdef TEST_SPLIT
  140.  
  141.  
  142. /*
  143.  * test program
  144.  * pgm        runs regression
  145.  * pgm sep    splits stdin lines by sep
  146.  * pgm str sep    splits str by sep
  147.  * pgm str sep n    splits str by sep n times
  148.  */
  149. int
  150. main(argc, argv)
  151. int argc;
  152. char *argv[];
  153. {
  154.     char buf[512];
  155.     register int n;
  156. #    define    MNF    10
  157.     char *fields[MNF];
  158.  
  159.     if (argc > 4)
  160.         for (n = atoi(argv[3]); n > 0; n--) {
  161.             (void) strcpy(buf, argv[1]);
  162.         }
  163.     else if (argc > 3)
  164.         for (n = atoi(argv[3]); n > 0; n--) {
  165.             (void) strcpy(buf, argv[1]);
  166.             (void) split(buf, fields, MNF, argv[2]);
  167.         }
  168.     else if (argc > 2)
  169.         dosplit(argv[1], argv[2]);
  170.     else if (argc > 1)
  171.         while (fgets(buf, sizeof(buf), stdin) != NULL) {
  172.             buf[strlen(buf)-1] = '\0';    /* stomp newline */
  173.             dosplit(buf, argv[1]);
  174.         }
  175.     else
  176.         regress();
  177.  
  178.     exit(0);
  179. }
  180.  
  181. dosplit(string, seps)
  182. char *string;
  183. char *seps;
  184. {
  185. #    define    NF    5
  186.     char *fields[NF];
  187.     register int nf;
  188.  
  189.     nf = split(string, fields, NF, seps);
  190.     print(nf, fields);
  191. }
  192.  
  193. print(nf, fields)
  194. int nf;
  195. char *fields[];
  196. {
  197.     register int fn;
  198.  
  199.     printf("%d:\t", nf);
  200.     for (fn = 0; fn < nf; fn++)
  201.         printf("\"%s\"%s", fields[fn], (fn+1 < nf) ? ", " : "\n");
  202. }
  203.  
  204. #define    RNF    5        /* some table entries know this */
  205. struct {
  206.     char *str;
  207.     char *seps;
  208.     int nf;
  209.     char *fi[RNF];
  210. } tests[] = {
  211.     "",        " ",    0,    { "" },
  212.     " ",        " ",    2,    { "", "" },
  213.     "x",        " ",    1,    { "x" },
  214.     "xy",        " ",    1,    { "xy" },
  215.     "x y",        " ",    2,    { "x", "y" },
  216.     "abc def  g ",    " ",    5,    { "abc", "def", "", "g", "" },
  217.     "  a bcd",    " ",    4,    { "", "", "a", "bcd" },
  218.     "a b c d e f",    " ",    6,    { "a", "b", "c", "d", "e f" },
  219.     " a b c d ",    " ",    6,    { "", "a", "b", "c", "d " },
  220.  
  221.     "",        " _",    0,    { "" },
  222.     " ",        " _",    2,    { "", "" },
  223.     "x",        " _",    1,    { "x" },
  224.     "x y",        " _",    2,    { "x", "y" },
  225.     "ab _ cd",    " _",    2,    { "ab", "cd" },
  226.     " a_b  c ",    " _",    5,    { "", "a", "b", "c", "" },
  227.     "a b c_d e f",    " _",    6,    { "a", "b", "c", "d", "e f" },
  228.     " a b c d ",    " _",    6,    { "", "a", "b", "c", "d " },
  229.  
  230.     "",        " _~",    0,    { "" },
  231.     " ",        " _~",    2,    { "", "" },
  232.     "x",        " _~",    1,    { "x" },
  233.     "x y",        " _~",    2,    { "x", "y" },
  234.     "ab _~ cd",    " _~",    2,    { "ab", "cd" },
  235.     " a_b  c~",    " _~",    5,    { "", "a", "b", "c", "" },
  236.     "a b_c d~e f",    " _~",    6,    { "a", "b", "c", "d", "e f" },
  237.     "~a b c d ",    " _~",    6,    { "", "a", "b", "c", "d " },
  238.  
  239.     "",        " _~-",    0,    { "" },
  240.     " ",        " _~-",    2,    { "", "" },
  241.     "x",        " _~-",    1,    { "x" },
  242.     "x y",        " _~-",    2,    { "x", "y" },
  243.     "ab _~- cd",    " _~-",    2,    { "ab", "cd" },
  244.     " a_b  c~",    " _~-",    5,    { "", "a", "b", "c", "" },
  245.     "a b_c-d~e f",    " _~-",    6,    { "a", "b", "c", "d", "e f" },
  246.     "~a-b c d ",    " _~-",    6,    { "", "a", "b", "c", "d " },
  247.  
  248.     "",        "  ",    0,    { "" },
  249.     " ",        "  ",    2,    { "", "" },
  250.     "x",        "  ",    1,    { "x" },
  251.     "xy",        "  ",    1,    { "xy" },
  252.     "x y",        "  ",    2,    { "x", "y" },
  253.     "abc def  g ",    "  ",    4,    { "abc", "def", "g", "" },
  254.     "  a bcd",    "  ",    3,    { "", "a", "bcd" },
  255.     "a b c d e f",    "  ",    6,    { "a", "b", "c", "d", "e f" },
  256.     " a b c d ",    "  ",    6,    { "", "a", "b", "c", "d " },
  257.  
  258.     "",        "",    0,    { "" },
  259.     " ",        "",    0,    { "" },
  260.     "x",        "",    1,    { "x" },
  261.     "xy",        "",    1,    { "xy" },
  262.     "x y",        "",    2,    { "x", "y" },
  263.     "abc def  g ",    "",    3,    { "abc", "def", "g" },
  264.     "\t a bcd",    "",    2,    { "a", "bcd" },
  265.     "  a \tb\t c ",    "",    3,    { "a", "b", "c" },
  266.     "a b\tc d e f",    "",    6,    { "a", "b", "c", "d", "e f" },
  267.     " a b c d e f ",    "",    6,    { "a", "b", "c", "d", "e f " },
  268.  
  269.     NULL,        NULL,    0,    { NULL },
  270. };
  271.  
  272. regress()
  273. {
  274.     char buf[512];
  275.     register int n;
  276.     char *fields[RNF+1];
  277.     register int nf;
  278.     register int i;
  279.     register int printit;
  280.     register char *f;
  281.  
  282.     for (n = 0; tests[n].str != NULL; n++) {
  283.         (void) strcpy(buf, tests[n].str);
  284.         fields[RNF] = NULL;
  285.         nf = split(buf, fields, RNF, tests[n].seps);
  286.         printit = 0;
  287.         if (nf != tests[n].nf) {
  288.             printf("split `%s' by `%s' gave %d fields, not %d\n",
  289.                 tests[n].str, tests[n].seps, nf, tests[n].nf);
  290.             printit = 1;
  291.         } else if (fields[RNF] != NULL) {
  292.             printf("split() went beyond array end\n");
  293.             printit = 1;
  294.         } else {
  295.             for (i = 0; i < nf && i < RNF; i++) {
  296.                 f = fields[i];
  297.                 if (f == NULL)
  298.                     f = "(NULL)";
  299.                 if (strcmp(f, tests[n].fi[i]) != 0) {
  300.                     printf("split `%s' by `%s', field %d is `%s', not `%s'\n",
  301.                         tests[n].str, tests[n].seps,
  302.                         i, fields[i], tests[n].fi[i]);
  303.                     printit = 1;
  304.                 }
  305.             }
  306.         }
  307.         if (printit)
  308.             print(nf, fields);
  309.     }
  310. }
  311. #endif
  312.