Merge remote-tracking branch 'origin/pr/376'
[collectd.git] / src / utils_parse_option.c
1 /**
2  * collectd - src/utils_parse_option.c
3  * Copyright (C) 2008  Florian Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Author:
19  *   Florian octo Forster <octo at verplant.org>
20  **/
21
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25 #include "utils_parse_option.h"
26
27 int parse_string (char **ret_buffer, char **ret_string)
28 {
29   char *buffer;
30   char *string;
31
32   buffer = *ret_buffer;
33
34   /* Eat up leading spaces. */
35   string = buffer;
36   while (isspace ((int) *string))
37     string++;
38   if (*string == 0)
39     return (1);
40
41   /* A quoted string */
42   if (*string == '"')
43   {
44     char *dst;
45
46     string++;
47     if (*string == 0)
48       return (1);
49
50     dst = string;
51     buffer = string;
52     while ((*buffer != '"') && (*buffer != 0))
53     {
54       /* Un-escape backslashes */
55       if (*buffer == '\\')
56       {
57         buffer++;
58         /* Catch a backslash at the end of buffer */
59         if (*buffer == 0)
60           return (-1);
61       }
62       *dst = *buffer;
63       buffer++;
64       dst++;
65     }
66     /* No quote sign has been found */
67     if (*buffer == 0)
68       return (-1);
69
70     *dst = 0;
71     dst++;
72     *buffer = 0;
73     buffer++;
74
75     /* Check for trailing spaces. */
76     if ((*buffer != 0) && !isspace ((int) *buffer))
77       return (-1);
78   }
79   else /* an unquoted string */
80   {
81     buffer = string;
82     while ((*buffer != 0) && !isspace ((int) *buffer))
83       buffer++;
84     if (*buffer != 0)
85     {
86       *buffer = 0;
87       buffer++;
88     }
89   }
90   
91   /* Eat up trailing spaces */
92   while (isspace ((int) *buffer))
93     buffer++;
94
95   *ret_buffer = buffer;
96   *ret_string = string;
97
98   return (0);
99 } /* int parse_string */
100
101 /*
102  * parse_option
103  * ------------
104  *  Parses an ``option'' as used with the unixsock and exec commands. An
105  *  option is of the form:
106  *    name0="value"
107  *    name1="value with \"quotes\""
108  *    name2="value \\ backslash"
109  *  However, if the value does *not* contain a space character, you can skip
110  *  the quotes.
111  */
112 int parse_option (char **ret_buffer, char **ret_key, char **ret_value)
113 {
114   char *buffer;
115   char *key;
116   char *value;
117   int status;
118
119   buffer = *ret_buffer;
120
121   /* Eat up leading spaces */
122   key = buffer;
123   while (isspace ((int) *key))
124     key++;
125   if (*key == 0)
126     return (1);
127
128   /* Look for the equal sign */
129   buffer = key;
130   while (isalnum ((int) *buffer) || *buffer == '_')
131     buffer++;
132   if ((*buffer != '=') || (buffer == key))
133     return (1);
134   *buffer = 0;
135   buffer++;
136   /* Empty values must be written as "" */
137   if (isspace ((int) *buffer) || (*buffer == 0))
138     return (-1);
139
140   status = parse_string (&buffer, &value);
141   if (status != 0)
142     return (-1);
143
144   /* NB: parse_string will have eaten up all trailing spaces. */
145
146   *ret_buffer = buffer;
147   *ret_key = key;
148   *ret_value = value;
149
150   return (0);
151 } /* int parse_option */
152
153 int escape_string (char *buffer, size_t buffer_size)
154 {
155   char *temp;
156   size_t i;
157   size_t j;
158
159   /* Check if we need to escape at all first */
160   temp = strpbrk (buffer, " \t\"\\");
161   if (temp == NULL)
162     return (0);
163
164   temp = (char *) malloc (buffer_size);
165   if (temp == NULL)
166     return (-1);
167   memset (temp, 0, buffer_size);
168
169   temp[0] = '"';
170   j = 1;
171
172   for (i = 0; i < buffer_size; i++)
173   {
174     if (buffer[i] == 0)
175     {
176       break;
177     }
178     else if ((buffer[i] == '"') || (buffer[i] == '\\'))
179     {
180       if (j > (buffer_size - 4))
181         break;
182       temp[j] = '\\';
183       temp[j + 1] = buffer[i];
184       j += 2;
185     }
186     else
187     {
188       if (j > (buffer_size - 3))
189         break;
190       temp[j] = buffer[i];
191       j++;
192     }
193   }
194
195   assert ((j + 1) < buffer_size);
196   temp[j] = '"';
197   temp[j + 1] = 0;
198
199   sstrncpy (buffer, temp, buffer_size);
200   sfree (temp);
201   return (0);
202 } /* int escape_string */
203
204 /* vim: set sw=2 ts=8 tw=78 et : */