Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

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