{GPL, other}: Relicense to MIT license.
[collectd.git] / src / utils_parse_option.c
1 /**
2  * collectd - src/utils_parse_option.c
3  * Copyright (C) 2008       Florian Forster
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Florian octo Forster <octo at collectd.org>
25  **/
26
27 #include "collectd.h"
28 #include "common.h"
29 #include "plugin.h"
30 #include "utils_parse_option.h"
31
32 int parse_string (char **ret_buffer, char **ret_string)
33 {
34   char *buffer;
35   char *string;
36
37   buffer = *ret_buffer;
38
39   /* Eat up leading spaces. */
40   string = buffer;
41   while (isspace ((int) *string))
42     string++;
43   if (*string == 0)
44     return (1);
45
46   /* A quoted string */
47   if (*string == '"')
48   {
49     char *dst;
50
51     string++;
52     if (*string == 0)
53       return (1);
54
55     dst = string;
56     buffer = string;
57     while ((*buffer != '"') && (*buffer != 0))
58     {
59       /* Un-escape backslashes */
60       if (*buffer == '\\')
61       {
62         buffer++;
63         /* Catch a backslash at the end of buffer */
64         if (*buffer == 0)
65           return (-1);
66       }
67       *dst = *buffer;
68       buffer++;
69       dst++;
70     }
71     /* No quote sign has been found */
72     if (*buffer == 0)
73       return (-1);
74
75     *dst = 0;
76     dst++;
77     *buffer = 0;
78     buffer++;
79
80     /* Check for trailing spaces. */
81     if ((*buffer != 0) && !isspace ((int) *buffer))
82       return (-1);
83   }
84   else /* an unquoted string */
85   {
86     buffer = string;
87     while ((*buffer != 0) && !isspace ((int) *buffer))
88       buffer++;
89     if (*buffer != 0)
90     {
91       *buffer = 0;
92       buffer++;
93     }
94   }
95   
96   /* Eat up trailing spaces */
97   while (isspace ((int) *buffer))
98     buffer++;
99
100   *ret_buffer = buffer;
101   *ret_string = string;
102
103   return (0);
104 } /* int parse_string */
105
106 /*
107  * parse_option
108  * ------------
109  *  Parses an ``option'' as used with the unixsock and exec commands. An
110  *  option is of the form:
111  *    name0="value"
112  *    name1="value with \"quotes\""
113  *    name2="value \\ backslash"
114  *  However, if the value does *not* contain a space character, you can skip
115  *  the quotes.
116  */
117 int parse_option (char **ret_buffer, char **ret_key, char **ret_value)
118 {
119   char *buffer;
120   char *key;
121   char *value;
122   int status;
123
124   buffer = *ret_buffer;
125
126   /* Eat up leading spaces */
127   key = buffer;
128   while (isspace ((int) *key))
129     key++;
130   if (*key == 0)
131     return (1);
132
133   /* Look for the equal sign */
134   buffer = key;
135   while (isalnum ((int) *buffer) || *buffer == '_')
136     buffer++;
137   if ((*buffer != '=') || (buffer == key))
138     return (1);
139   *buffer = 0;
140   buffer++;
141   /* Empty values must be written as "" */
142   if (isspace ((int) *buffer) || (*buffer == 0))
143     return (-1);
144
145   status = parse_string (&buffer, &value);
146   if (status != 0)
147     return (-1);
148
149   /* NB: parse_string will have eaten up all trailing spaces. */
150
151   *ret_buffer = buffer;
152   *ret_key = key;
153   *ret_value = value;
154
155   return (0);
156 } /* int parse_option */
157
158 int escape_string (char *buffer, size_t buffer_size)
159 {
160   char *temp;
161   size_t i;
162   size_t j;
163
164   /* Check if we need to escape at all first */
165   temp = strpbrk (buffer, " \t\"\\");
166   if (temp == NULL)
167     return (0);
168
169   temp = (char *) malloc (buffer_size);
170   if (temp == NULL)
171     return (-1);
172   memset (temp, 0, buffer_size);
173
174   temp[0] = '"';
175   j = 1;
176
177   for (i = 0; i < buffer_size; i++)
178   {
179     if (buffer[i] == 0)
180     {
181       break;
182     }
183     else if ((buffer[i] == '"') || (buffer[i] == '\\'))
184     {
185       if (j > (buffer_size - 4))
186         break;
187       temp[j] = '\\';
188       temp[j + 1] = buffer[i];
189       j += 2;
190     }
191     else
192     {
193       if (j > (buffer_size - 3))
194         break;
195       temp[j] = buffer[i];
196       j++;
197     }
198   }
199
200   assert ((j + 1) < buffer_size);
201   temp[j] = '"';
202   temp[j + 1] = 0;
203
204   sstrncpy (buffer, temp, buffer_size);
205   sfree (temp);
206   return (0);
207 } /* int escape_string */
208
209 /* vim: set sw=2 ts=8 tw=78 et : */