Use an enum to replace a couple of magic numbers in ssplit()
[privoxy.git] / ssplit.c
1 const char ssplit_rcs[] = "$Id: ssplit.c,v 1.17 2012/07/23 12:44:30 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/ssplit.c,v $
5  *
6  * Purpose     :  A function to split a string at specified delimiters.
7  *
8  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
9  *                Privoxy team. http://www.privoxy.org/
10  *
11  *                Based on the Internet Junkbuster originally written
12  *                by and Copyright (C) 1997 Anonymous Coders and
13  *                Junkbusters Corporation.  http://www.junkbusters.com
14  *
15  *                This program is free software; you can redistribute it
16  *                and/or modify it under the terms of the GNU General
17  *                Public License as published by the Free Software
18  *                Foundation; either version 2 of the License, or (at
19  *                your option) any later version.
20  *
21  *                This program is distributed in the hope that it will
22  *                be useful, but WITHOUT ANY WARRANTY; without even the
23  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
24  *                PARTICULAR PURPOSE.  See the GNU General Public
25  *                License for more details.
26  *
27  *                The GNU General Public License should be included with
28  *                this file.  If not, you can view it at
29  *                http://www.gnu.org/copyleft/gpl.html
30  *                or write to the Free Software Foundation, Inc., 59
31  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
32  *
33  *********************************************************************/
34
35
36 #include "config.h"
37
38 #include <string.h>
39 #include <stdlib.h>
40
41 #include "ssplit.h"
42 #include "miscutil.h"
43
44 const char ssplit_h_rcs[] = SSPLIT_H_VERSION;
45
46
47 /*********************************************************************
48  *
49  * Function    :  ssplit
50  *
51  * Description :  Split a string using delimiters in `delim'.  Results
52  *                go into `vec'.
53  *
54  * Parameters  :
55  *          1  :  str = string to split.  Will be split in place
56  *                (i.e. do not free until you've finished with vec,
57  *                previous contents will be trashed by the call).
58  *          2  :  delim = array of delimiters (if NULL, uses " \t").
59  *          3  :  vec[] = results vector (aka. array) [out]
60  *          4  :  vec_len = number of usable slots in the vector (aka. array size)
61  *
62  * Returns     :  -1 => Error: vec_len is too small to hold all the
63  *                      data, or str == NULL.
64  *                >=0 => the number of fields put in `vec'.
65  *                On error, vec and str may still have been overwritten.
66  *
67  *********************************************************************/
68 int ssplit(char *str, const char *delim, char *vec[], size_t vec_len)
69 {
70    unsigned char is_delim[256];
71    unsigned char char_type;
72    int vec_count = 0;
73    enum char_type {
74       WANTED     = 0,
75       SEPARATOR  = 1,
76       TERMINATOR = 2,
77    };
78
79
80    if (!str)
81    {
82       return(-1);
83    }
84
85
86    /* Build is_delim array */
87
88    memset(is_delim, '\0', sizeof(is_delim));
89
90    if (!delim)
91    {
92       delim = " \t";  /* default field separators */
93    }
94
95    while (*delim)
96    {
97       is_delim[(unsigned)(unsigned char)*delim++] = SEPARATOR;
98    }
99
100    is_delim[(unsigned)(unsigned char)'\0'] = TERMINATOR;
101    is_delim[(unsigned)(unsigned char)'\n'] = TERMINATOR;
102
103
104    /* Parse string */
105
106    /* Skip leading separators. XXX: Why do they matter? */
107    while (is_delim[(unsigned)(unsigned char)*str] == SEPARATOR)
108    {
109       str++;
110    }
111
112    /* The first pointer is the beginning of string */
113    if (is_delim[(unsigned)(unsigned char)*str] == WANTED)
114    {
115       /*
116        * The first character in this field is not a
117        * delimiter or the end of string, so save it.
118        */
119       if (vec_count >= vec_len)
120       {
121          return(-1); /* overflow */
122       }
123       vec[vec_count++] = str;
124    }
125
126    while ((char_type = is_delim[(unsigned)(unsigned char)*str]) != TERMINATOR)
127    {
128       if (char_type == SEPARATOR)
129       {
130          /* the char is a separator */
131
132          /* null terminate the substring */
133          *str++ = '\0';
134
135          /* Check if we want to save this field */
136          if (is_delim[(unsigned)(unsigned char)*str] == WANTED)
137          {
138             /*
139              * The first character in this field is not a
140              * delimiter or the end of string. So save it.
141              */
142             if (vec_count >= vec_len)
143             {
144                return(-1); /* overflow */
145             }
146             vec[vec_count++] = str;
147          }
148       }
149       else
150       {
151          str++;
152       }
153    }
154    /* null terminate the substring */
155    *str = '\0';
156
157    return(vec_count);
158 }
159
160
161 /*
162   Local Variables:
163   tab-width: 3
164   end:
165 */