src/utils_search.[ch]: Add a module for parsing search strings.
[collection4.git] / src / utils_search.c
1 /**
2  * collection4 - utils_search.c
3  * Copyright (C) 2010  Florian octo Forster
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  * 
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  *
20  * Authors:
21  *   Florian octo Forster <ff at octo.it>
22  **/
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #include "utils_search.h"
30 #include "utils_array.h"
31
32 #include <fcgiapp.h>
33 #include <fcgi_stdio.h>
34
35 struct search_info_s
36 {
37   char *host;
38   char *plugin;
39   char *plugin_instance;
40   char *type;
41   char *type_instance;
42
43   str_array_t *terms;
44 };
45
46 static char *read_quoted_string (const char **buffer) /* {{{ */
47 {
48   const char *ptr = *buffer;
49   char *ret;
50   size_t ret_len;
51
52   if (ptr[0] != '"')
53     return (NULL);
54   ptr++;
55
56   ret_len = 0;
57   while ((*ptr != '"') && (*ptr != 0))
58   {
59     ret_len++;
60
61     if (*ptr == '\\')
62       ptr += 2;
63     else
64       ptr++;
65   }
66
67   if ((ret_len < 1) || (*ptr != '"'))
68     return (NULL);
69
70   ret = malloc (ret_len + 1);
71   if (ret == NULL)
72     return (NULL);
73
74   ptr = *buffer + 1;
75   ret_len = 0;
76   while ((*ptr != '"') && (*ptr != 0))
77   {
78     if (*ptr == '"')
79       break;
80
81     if (*ptr == '\\')
82       ptr++;
83
84     ret[ret_len] = *ptr;
85
86     ptr++;
87     ret_len++;
88   }
89
90   /* terminate string */
91   ret[ret_len] = 0;
92
93   /* "ptr" points to the '"' sign, so advance one more */
94   ptr++;
95   *buffer = ptr;
96
97   return (ret);
98 } /* }}} char *read_quoted_string */
99
100 static char *read_unquoted_word (const char **buffer) /* {{{ */
101 {
102   const char *ptr = *buffer;
103   char *ret;
104   size_t ret_len;
105
106   ret_len = 0;
107   while (!isspace ((int) ptr[ret_len]) && (ptr[ret_len] != 0))
108     ret_len++;
109
110   if (ret_len < 1)
111     return (NULL);
112
113   ret = malloc (ret_len + 1);
114   if (ret == NULL)
115     return (NULL);
116
117   memcpy (ret, ptr, ret_len);
118   ret[ret_len] = 0;
119
120   ptr += ret_len;
121   *buffer = ptr;
122
123   return (ret);
124 } /* }}} char *read_unquoted_word */
125
126 static char *next_token (const char **buffer) /* {{{ */
127 {
128   const char *ptr = *buffer;
129   char *ret;
130
131   while (isspace ((int) (*ptr)))
132     ptr++;
133
134   if (ptr[0] == 0)
135     return (NULL);
136   else if (ptr[0] == '"')
137   {
138     ret = read_quoted_string (&ptr);
139     if (ret != NULL)
140     {
141       *buffer = ptr;
142       return (ret);
143     }
144   }
145
146   ret = read_unquoted_word (&ptr);
147   if (ret != NULL)
148     *buffer = ptr;
149
150   return (ret);
151 } /* }}} char *next_token */
152
153 search_info_t *search_parse (const char *search) /* {{{ */
154 {
155   const char *ptr;
156   char *token;
157   search_info_t *si;
158
159   si = malloc (sizeof (*si));
160   if (si == NULL)
161     return (NULL);
162   memset (si, 0, sizeof (*si));
163
164   si->terms = array_create ();
165   if (si->terms == NULL)
166   {
167     free (si);
168     return (NULL);
169   }
170
171   ptr = search;
172
173   while ((token = next_token (&ptr)) != NULL)
174   {
175     array_append (si->terms, token);
176
177     free (token);
178   }
179
180   return (si);
181 } /* }}} search_info_t *search_parse */
182
183 void search_destroy (search_info_t *si) /* {{{ */
184 {
185   if (si == NULL)
186     return;
187
188   free (si->host);
189   free (si->plugin);
190   free (si->plugin_instance);
191   free (si->type);
192   free (si->type_instance);
193
194   array_destroy (si->terms);
195 } /* }}} void search_destroy */
196
197 /* vim: set sw=2 sts=2 et fdm=marker : */