home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / nn.tar / nn-6.5.1 / split.c < prev    next >
C/C++ Source or Header  |  1995-04-29  |  9KB  |  363 lines

  1. /*******************WARNING*********************
  2.  
  3. This is a *MODIFIED* version of Geoff Coller's proof-of-concept NOV
  4. implementation.
  5.  
  6. It has been modified to support threading directly from a file handle
  7. to a NNTP server without a temporary file.
  8.  
  9. This is not a complete distribution.  We have only distributed enough
  10. to support NN's needs.
  11.  
  12. The original version came from world.std.com:/src/news/nov.dist.tar.Z
  13. and was dated 11 Aug 1993.
  14.  
  15. In any case, bugs you find here are probably my fault, as I've trimmed
  16. a fair bit of unused code.
  17.  
  18. -Peter Wemm  <peter@DIALix.oz.au>
  19. */
  20.  
  21. /*
  22.  * Copyright (c) Geoffrey Collyer 1992, 1993.
  23.  * All rights reserved.
  24.  * Written by Geoffrey Collyer.
  25.  * Thanks to UUNET Communications Services Inc for financial support.
  26.  *
  27.  * This software is not subject to any license of the American Telephone
  28.  * and Telegraph Company, the Regents of the University of California, or
  29.  * the Free Software Foundation.
  30.  *
  31.  * Permission is granted to anyone to use this software for any purpose on
  32.  * any computer system, and to alter it and redistribute it freely, subject
  33.  * to the following restrictions:
  34.  *
  35.  * 1. The authors are not responsible for the consequences of use of this
  36.  *    software, no matter how awful, even if they arise from flaws in it.
  37.  *
  38.  * 2. The origin of this software must not be misrepresented, either by
  39.  *    explicit claim or by omission.  Since few users ever read sources,
  40.  *    credits must appear in the documentation.
  41.  *
  42.  * 3. Altered versions must be plainly marked as such, and must not be
  43.  *    misrepresented as being the original software.  Since few users
  44.  *    ever read sources, credits must appear in the documentation.
  45.  *
  46.  * 4. This notice may not be removed or altered.
  47.  */
  48.  
  49. #include "config.h"
  50.  
  51. /*
  52.  * split - divide a string into fields, like awk split()
  53.  */
  54. int                /* number of fields, including overflow */
  55. split(string, fields, nfields, sep)
  56. char *string;
  57. char *fields[];            /* list is not NULL-terminated */
  58. int nfields;            /* number of entries available in fields[] */
  59. char *sep;            /* "" white, "c" single char, "ab" [ab]+ */
  60. {
  61.     register char *p = string;
  62.     register char c;            /* latest character */
  63.     register char sepc = sep[0];
  64.     register char sepc2;
  65.     register int fn;
  66.     register char **fp = fields;
  67.     register char *sepp;
  68.     register int trimtrail;
  69.  
  70.     /* white space */
  71.     if (sepc == '\0') {
  72.         while ((c = *p++) == ' ' || c == '\t')
  73.             continue;
  74.         p--;
  75.         trimtrail = 1;
  76.         sep = " \t";    /* note, code below knows this is 2 long */
  77.         sepc = ' ';
  78.     } else
  79.         trimtrail = 0;
  80.     sepc2 = sep[1];        /* now we can safely pick this up */
  81.  
  82.     /* catch empties */
  83.     if (*p == '\0')
  84.         return(0);
  85.  
  86.     /* single separator */
  87.     if (sepc2 == '\0') {
  88.         fn = nfields;
  89.         for (;;) {
  90.             *fp++ = p;
  91.             fn--;
  92.             if (fn == 0)
  93.                 break;
  94.             while ((c = *p++) != sepc)
  95.                 if (c == '\0')
  96.                     return(nfields - fn);
  97.             *(p-1) = '\0';
  98.         }
  99.         /* we have overflowed the fields vector -- just count them */
  100.         fn = nfields;
  101.         for (;;) {
  102.             while ((c = *p++) != sepc)
  103.                 if (c == '\0')
  104.                     return(fn);
  105.             fn++;
  106.         }
  107.         /* not reached */
  108.     }
  109.  
  110.     /* two separators */
  111.     if (sep[2] == '\0') {
  112.         fn = nfields;
  113.         for (;;) {
  114.             *fp++ = p;
  115.             fn--;
  116.             while ((c = *p++) != sepc && c != sepc2)
  117.                 if (c == '\0') {
  118.                     if (trimtrail && **(fp-1) == '\0')
  119.                         fn++;
  120.                     return(nfields - fn);
  121.                 }
  122.             if (fn == 0)
  123.                 break;
  124.             *(p-1) = '\0';
  125.             while ((c = *p++) == sepc || c == sepc2)
  126.                 continue;
  127.             p--;
  128.         }
  129.         /* we have overflowed the fields vector -- just count them */
  130.         fn = nfields;
  131.         while (c != '\0') {
  132.             while ((c = *p++) == sepc || c == sepc2)
  133.                 continue;
  134.             p--;
  135.             fn++;
  136.             while ((c = *p++) != '\0' && c != sepc && c != sepc2)
  137.                 continue;
  138.         }
  139.         /* might have to trim trailing white space */
  140.         if (trimtrail) {
  141.             p--;
  142.             while ((c = *--p) == sepc || c == sepc2)
  143.                 continue;
  144.             p++;
  145.             if (*p != '\0') {
  146.                 if (fn == nfields+1)
  147.                     *p = '\0';
  148.                 fn--;
  149.             }
  150.         }
  151.         return(fn);
  152.     }
  153.  
  154.     /* n separators */
  155.     fn = 0;
  156.     for (;;) {
  157.         if (fn < nfields)
  158.             *fp++ = p;
  159.         fn++;
  160.         for (;;) {
  161.             c = *p++;
  162.             if (c == '\0')
  163.                 return(fn);
  164.             sepp = sep;
  165.             while ((sepc = *sepp++) != '\0' && sepc != c)
  166.                 continue;
  167.             if (sepc != '\0')    /* it was a separator */
  168.                 break;
  169.         }
  170.         if (fn < nfields)
  171.             *(p-1) = '\0';
  172.         for (;;) {
  173.             c = *p++;
  174.             sepp = sep;
  175.             while ((sepc = *sepp++) != '\0' && sepc != c)
  176.                 continue;
  177.             if (sepc == '\0')    /* it wasn't a separator */
  178.                 break;
  179.         }
  180.         p--;
  181.     }
  182.  
  183.     /* not reached */
  184. }
  185.  
  186. #ifdef TEST_SPLIT
  187.  
  188.  
  189. /*
  190.  * test program
  191.  * pgm        runs regression
  192.  * pgm sep    splits stdin lines by sep
  193.  * pgm str sep    splits str by sep
  194.  * pgm str sep n    splits str by sep n times
  195.  */
  196. int
  197. main(argc, argv)
  198. int argc;
  199. char *argv[];
  200. {
  201.     char buf[512];
  202.     register int n;
  203. #    define    MNF    10
  204.     char *fields[MNF];
  205.  
  206.     if (argc > 4)
  207.         for (n = atoi(argv[3]); n > 0; n--) {
  208.             (void) strcpy(buf, argv[1]);
  209.         }
  210.     else if (argc > 3)
  211.         for (n = atoi(argv[3]); n > 0; n--) {
  212.             (void) strcpy(buf, argv[1]);
  213.             (void) split(buf, fields, MNF, argv[2]);
  214.         }
  215.     else if (argc > 2)
  216.         dosplit(argv[1], argv[2]);
  217.     else if (argc > 1)
  218.         while (fgets(buf, sizeof(buf), stdin) != NULL) {
  219.             buf[strlen(buf)-1] = '\0';    /* stomp newline */
  220.             dosplit(buf, argv[1]);
  221.         }
  222.     else
  223.         regress();
  224.  
  225.     exit(0);
  226. }
  227.  
  228. dosplit(string, seps)
  229. char *string;
  230. char *seps;
  231. {
  232. #    define    NF    5
  233.     char *fields[NF];
  234.     register int nf;
  235.  
  236.     nf = split(string, fields, NF, seps);
  237.     print(nf, NF, fields);
  238. }
  239.  
  240. print(nf, nfp, fields)
  241. int nf;
  242. int nfp;
  243. char *fields[];
  244. {
  245.     register int fn;
  246.     register int bound;
  247.  
  248.     bound = (nf > nfp) ? nfp : nf;
  249.     printf("%d:\t", nf);
  250.     for (fn = 0; fn < bound; fn++)
  251.         printf("\"%s\"%s", fields[fn], (fn+1 < nf) ? ", " : "\n");
  252. }
  253.  
  254. #define    RNF    5        /* some table entries know this */
  255. struct {
  256.     char *str;
  257.     char *seps;
  258.     int nf;
  259.     char *fi[RNF];
  260. } tests[] = {
  261.     "",        " ",    0,    { "" },
  262.     " ",        " ",    2,    { "", "" },
  263.     "x",        " ",    1,    { "x" },
  264.     "xy",        " ",    1,    { "xy" },
  265.     "x y",        " ",    2,    { "x", "y" },
  266.     "abc def  g ",    " ",    5,    { "abc", "def", "", "g", "" },
  267.     "  a bcd",    " ",    4,    { "", "", "a", "bcd" },
  268.     "a b c d e f",    " ",    6,    { "a", "b", "c", "d", "e f" },
  269.     " a b c d ",    " ",    6,    { "", "a", "b", "c", "d " },
  270.  
  271.     "",        " _",    0,    { "" },
  272.     " ",        " _",    2,    { "", "" },
  273.     "x",        " _",    1,    { "x" },
  274.     "x y",        " _",    2,    { "x", "y" },
  275.     "ab _ cd",    " _",    2,    { "ab", "cd" },
  276.     " a_b  c ",    " _",    5,    { "", "a", "b", "c", "" },
  277.     "a b c_d e f",    " _",    6,    { "a", "b", "c", "d", "e f" },
  278.     " a b c d ",    " _",    6,    { "", "a", "b", "c", "d " },
  279.  
  280.     "",        " _~",    0,    { "" },
  281.     " ",        " _~",    2,    { "", "" },
  282.     "x",        " _~",    1,    { "x" },
  283.     "x y",        " _~",    2,    { "x", "y" },
  284.     "ab _~ cd",    " _~",    2,    { "ab", "cd" },
  285.     " a_b  c~",    " _~",    5,    { "", "a", "b", "c", "" },
  286.     "a b_c d~e f",    " _~",    6,    { "a", "b", "c", "d", "e f" },
  287.     "~a b c d ",    " _~",    6,    { "", "a", "b", "c", "d " },
  288.  
  289.     "",        " _~-",    0,    { "" },
  290.     " ",        " _~-",    2,    { "", "" },
  291.     "x",        " _~-",    1,    { "x" },
  292.     "x y",        " _~-",    2,    { "x", "y" },
  293.     "ab _~- cd",    " _~-",    2,    { "ab", "cd" },
  294.     " a_b  c~",    " _~-",    5,    { "", "a", "b", "c", "" },
  295.     "a b_c-d~e f",    " _~-",    6,    { "a", "b", "c", "d", "e f" },
  296.     "~a-b c d ",    " _~-",    6,    { "", "a", "b", "c", "d " },
  297.  
  298.     "",        "  ",    0,    { "" },
  299.     " ",        "  ",    2,    { "", "" },
  300.     "x",        "  ",    1,    { "x" },
  301.     "xy",        "  ",    1,    { "xy" },
  302.     "x y",        "  ",    2,    { "x", "y" },
  303.     "abc def  g ",    "  ",    4,    { "abc", "def", "g", "" },
  304.     "  a bcd",    "  ",    3,    { "", "a", "bcd" },
  305.     "a b c d e f",    "  ",    6,    { "a", "b", "c", "d", "e f" },
  306.     " a b c d ",    "  ",    6,    { "", "a", "b", "c", "d " },
  307.  
  308.     "",        "",    0,    { "" },
  309.     " ",        "",    0,    { "" },
  310.     "x",        "",    1,    { "x" },
  311.     "xy",        "",    1,    { "xy" },
  312.     "x y",        "",    2,    { "x", "y" },
  313.     "abc def  g ",    "",    3,    { "abc", "def", "g" },
  314.     "\t a bcd",    "",    2,    { "a", "bcd" },
  315.     "  a \tb\t c ",    "",    3,    { "a", "b", "c" },
  316.     "a b c d e ",    "",    5,    { "a", "b", "c", "d", "e" },
  317.     "a b\tc d e f",    "",    6,    { "a", "b", "c", "d", "e f" },
  318.     " a b c d e f ",    "",    6,    { "a", "b", "c", "d", "e f " },
  319.  
  320.     NULL,        NULL,    0,    { NULL },
  321. };
  322.  
  323. regress()
  324. {
  325.     char buf[512];
  326.     register int n;
  327.     char *fields[RNF+1];
  328.     register int nf;
  329.     register int i;
  330.     register int printit;
  331.     register char *f;
  332.  
  333.     for (n = 0; tests[n].str != NULL; n++) {
  334.         (void) strcpy(buf, tests[n].str);
  335.         fields[RNF] = NULL;
  336.         nf = split(buf, fields, RNF, tests[n].seps);
  337.         printit = 0;
  338.         if (nf != tests[n].nf) {
  339.             printf("split `%s' by `%s' gave %d fields, not %d\n",
  340.                 tests[n].str, tests[n].seps, nf, tests[n].nf);
  341.             printit = 1;
  342.         } else if (fields[RNF] != NULL) {
  343.             printf("split() went beyond array end\n");
  344.             printit = 1;
  345.         } else {
  346.             for (i = 0; i < nf && i < RNF; i++) {
  347.                 f = fields[i];
  348.                 if (f == NULL)
  349.                     f = "(NULL)";
  350.                 if (strcmp(f, tests[n].fi[i]) != 0) {
  351.                     printf("split `%s' by `%s', field %d is `%s', not `%s'\n",
  352.                         tests[n].str, tests[n].seps,
  353.                         i, fields[i], tests[n].fi[i]);
  354.                     printit = 1;
  355.                 }
  356.             }
  357.         }
  358.         if (printit)
  359.             print(nf, RNF, fields);
  360.     }
  361. }
  362. #endif
  363.