1 /* Copyright (c) 2003-2004, Roger Dingledine
2  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3  * Copyright (c) 2007-2021, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
5 
6 /**
7  * \file smartlist_split.c
8  * \brief Split a string into a smartlist_t of substrings.
9  **/
10 
11 #include "lib/smartlist_core/smartlist_core.h"
12 #include "lib/smartlist_core/smartlist_split.h"
13 
14 #include "lib/err/torerr.h"
15 #include "lib/string/util_string.h"
16 #include "lib/string/compat_ctype.h"
17 #include "lib/malloc/malloc.h"
18 
19 #include <string.h>
20 
21 /**
22  * Split a string <b>str</b> along all occurrences of <b>sep</b>,
23  * appending the (newly allocated) split strings, in order, to
24  * <b>sl</b>.  Return the number of strings added to <b>sl</b>.
25  *
26  * If <b>flags</b>&amp;SPLIT_SKIP_SPACE is true, remove initial and
27  * trailing space from each entry.
28  * If <b>flags</b>&amp;SPLIT_IGNORE_BLANK is true, remove any entries
29  * of length 0.
30  * If <b>flags</b>&amp;SPLIT_STRIP_SPACE is true, strip spaces from each
31  * split string.
32  *
33  * If <b>max</b>\>0, divide the string into no more than <b>max</b> pieces. If
34  * <b>sep</b> is NULL, split on any sequence of horizontal space.
35  */
36 int
smartlist_split_string(smartlist_t * sl,const char * str,const char * sep,int flags,int max)37 smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
38                        int flags, int max)
39 {
40   const char *cp, *end, *next;
41   int n = 0;
42 
43   raw_assert(sl);
44   raw_assert(str);
45 
46   cp = str;
47   while (1) {
48     if (flags&SPLIT_SKIP_SPACE) {
49       while (TOR_ISSPACE(*cp)) ++cp;
50     }
51 
52     if (max>0 && n == max-1) {
53       end = strchr(cp,'\0');
54     } else if (sep) {
55       end = strstr(cp,sep);
56       if (!end)
57         end = strchr(cp,'\0');
58     } else {
59       for (end = cp; *end && *end != '\t' && *end != ' '; ++end)
60         ;
61     }
62 
63     raw_assert(end);
64 
65     if (!*end) {
66       next = NULL;
67     } else if (sep) {
68       next = end+strlen(sep);
69     } else {
70       next = end+1;
71       while (*next == '\t' || *next == ' ')
72         ++next;
73     }
74 
75     if (flags&SPLIT_SKIP_SPACE) {
76       while (end > cp && TOR_ISSPACE(*(end-1)))
77         --end;
78     }
79     if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) {
80       char *string = tor_strndup(cp, end-cp);
81       if (flags&SPLIT_STRIP_SPACE)
82         tor_strstrip(string, " ");
83       smartlist_add(sl, string);
84       ++n;
85     }
86     if (!next)
87       break;
88     cp = next;
89   }
90 
91   return n;
92 }
93