]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/spotlight_rawquery_parser.y
Better parsing
[netatalk.git] / etc / afpd / spotlight_rawquery_parser.y
1 %{
2   #include <stdbool.h>
3   #include <stdio.h>
4   #include <string.h>
5   #include <gio/gio.h>
6   #include <atalk/talloc.h>
7   #include <atalk/logger.h>
8   #include <atalk/errchk.h>
9   #include "spotlight_SPARQL_map.h"
10   #include "spotlight.h"
11
12   struct yy_buffer_state;
13   typedef struct yy_buffer_state *YY_BUFFER_STATE;
14   extern int yylex (void);
15   extern void yyerror (char const *);
16   extern void *yyterminate(void);
17   extern YY_BUFFER_STATE yy_scan_string( const char *str);
18   extern void yy_delete_buffer ( YY_BUFFER_STATE buffer );
19
20   /* forward declarations */
21   static const char *map_expr(const char *attr, char op, const char *val);
22   static const char *map_daterange(const char *dateattr, const char *date1, const char *date2);
23
24   /* global vars, eg needed by the lexer */
25   slq_t *ssp_slq;
26
27   /* local vars */
28   static gchar *ssp_result;
29
30 %}
31
32 %code provides {
33   extern int map_spotlight_to_sparql_query(slq_t *slq, gchar **sparql_result);
34   extern slq_t *ssp_slq;
35 }
36
37 %union {
38     int ival;
39     const char *sval;
40     bool bval;
41 }
42
43 %expect 1
44 %error-verbose
45
46 %type <sval> match expr line function
47 %token <sval> DATE
48 %token <sval> WORD
49 %token <bval> BOOL
50 %token FUNC_INRANGE
51 %token DATE_SPEC
52 %token OBRACE CBRACE EQUAL UNEQUAL GT LT COMMA QUOTE
53 %left AND
54 %left OR
55 %%
56
57 input:
58 /* empty */
59 | input line
60 ;
61      
62 line:
63 expr                           {
64     ssp_result = talloc_asprintf(ssp_slq,
65                                  "SELECT DISTINCT ?url WHERE "
66                                  "{ ?x nie:url ?url FILTER(fn:starts-with(?url, 'file://%s/')) . %s}",
67                                  ssp_slq->slq_vol->v_path, $1);
68     $$ = ssp_result;
69 }
70 ;
71
72 expr:
73 BOOL                             {
74     if ($1 == false)
75         YYACCEPT;
76     else
77         YYABORT;
78 }
79 | match OR match                 {
80     if (strcmp($1, $3) != 0)
81         $$ = talloc_asprintf(ssp_slq, "{ %s } UNION { %s }", $1, $3);
82     else
83         $$ = talloc_asprintf(ssp_slq, "%s", $1);
84 }
85 | match                        {$$ = $1; if ($$ == NULL) YYABORT;}
86 | function                     {$$ = $1;}
87 | OBRACE expr CBRACE           {$$ = talloc_asprintf(ssp_slq, "%s", $2);}
88 | expr AND expr                {$$ = talloc_asprintf(ssp_slq, "%s . %s", $1, $3);}
89 | expr OR expr                 {
90     if (strcmp($1, $3) != 0)
91         $$ = talloc_asprintf(ssp_slq, "{ %s } UNION { %s }", $1, $3);
92     else
93         $$ = talloc_asprintf(ssp_slq, "%s", $1);
94 }
95 ;
96
97 match:
98 WORD EQUAL QUOTE WORD QUOTE     {$$ = map_expr($1, '=', $4);}
99 | WORD UNEQUAL QUOTE WORD QUOTE {$$ = map_expr($1, '!', $4);}
100 | WORD LT QUOTE WORD QUOTE      {$$ = map_expr($1, '<', $4);}
101 | WORD GT QUOTE WORD QUOTE      {$$ = map_expr($1, '>', $4);}
102 ;
103
104 function:
105 FUNC_INRANGE OBRACE WORD COMMA DATE_SPEC OBRACE DATE CBRACE COMMA DATE_SPEC OBRACE DATE CBRACE CBRACE {$$ = map_daterange($3, $7, $12);}
106 ;
107
108 %%
109
110 const char *map_daterange(const char *dateattr, const char *date1, const char *date2)
111 {
112     char *result = NULL;
113     struct spotlight_sparql_map *p;
114
115     for (p = spotlight_sparql_map; p->ssm_spotlight_attr; p++) {
116         if (strcmp(dateattr, p->ssm_spotlight_attr) == 0) {
117             result = talloc_asprintf(ssp_slq,
118                                      "?x %s ?d FILTER (?d > '%s' && ?d < '%s')",
119                                      p->ssm_sparql_attr,
120                                      date1,
121                                      date2);
122         }
123     }
124
125
126     return result;
127 }
128
129 const char *map_expr(const char *attr, char op, const char *val)
130 {
131     EC_INIT;
132     char *result = NULL;
133     struct spotlight_sparql_map *p;
134
135     for (p = spotlight_sparql_map; p->ssm_spotlight_attr; p++) {
136         if (strcmp(p->ssm_spotlight_attr, attr) == 0) {
137             switch (p->ssm_type) {
138             case ssmt_bool:
139                 result = talloc_asprintf(ssp_slq, "?x %s '%s'", p->ssm_sparql_attr, val);
140                 break;
141             case ssmt_num:
142                 result = talloc_asprintf(ssp_slq, "?x %s ?y FILTER(?y %c '%s')", p->ssm_sparql_attr, op, val);
143                 break;
144             case ssmt_str:
145                 result = talloc_asprintf(ssp_slq, "?x %s ?y FILTER(regex(?y, '%s'))", p->ssm_sparql_attr, val);
146                 break;
147             case ssmt_fts:
148                 result = talloc_asprintf(ssp_slq, "?x %s '%s'", p->ssm_sparql_attr, val);
149                 break;
150             case ssmt_date:
151                 yyerror("enexpected ssmt_date");
152                 EC_FAIL;
153             default:
154                 yyerror("unknown Spotlight attribute type");
155                 EC_FAIL;
156             }
157             break;
158         }
159     }
160
161 EC_CLEANUP:
162     return result;
163 }
164
165 void yyerror(const char *str)
166 {
167 #ifdef MAIN
168     printf("yyerror: %s\n", str);
169 #else
170     LOG(log_error, logtype_sl, "yyerror: %s", str);
171 #endif
172 }
173  
174 int yywrap()
175 {
176     return 1;
177
178
179 /**
180  * Map a Spotlight RAW query string to a SPARQL query string
181  *
182  * @param[in]     slq            Spotlight query handle
183  * @param[out]    sparql_result  Mapped SPARQL query, string is allocated in
184  *                               talloc context of slq
185  * @return        0 on success, -1 on error
186  **/
187 int map_spotlight_to_sparql_query(slq_t *slq, gchar **sparql_result)
188 {
189     EC_INIT;
190     YY_BUFFER_STATE s = NULL;
191     ssp_result = NULL;
192
193     ssp_slq = slq;
194     s = yy_scan_string(slq->slq_qstring);
195
196     EC_ZERO( yyparse() );
197
198 EC_CLEANUP:
199     if (s)
200         yy_delete_buffer(s);
201     if (ret == 0)
202         *sparql_result = ssp_result;
203     else
204         *sparql_result = NULL;
205     EC_EXIT;
206 }
207
208 #ifdef MAIN
209 int main(int argc, char **argv)
210 {
211     int ret;
212     YY_BUFFER_STATE s;
213
214     if (argc != 2) {
215         printf("usage: %s QUERY\n", argv[0]);
216         return 1;
217     }
218
219     ssp_slq = talloc_zero(NULL, slq_t);
220     struct vol *vol = talloc_zero(ssp_slq, struct vol);
221     vol->v_path = "/Volumes/test";
222     ssp_slq->slq_vol = vol;
223
224     s = yy_scan_string(argv[1]);
225
226     ret = yyparse();
227
228     yy_delete_buffer(s);
229
230     if (ret == 0)
231         printf("SPARQL: %s\n", ssp_result ? ssp_result : "(empty)");
232
233     return 0;
234
235 #endif