]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/spotlight_rawquery_parser.c
Support unix dates and comparison with dates for attributes
[netatalk.git] / etc / afpd / spotlight_rawquery_parser.c
index c9a94c9d69799354a785b2d08c4b902f86e8ed0b..ac9a521af478ba56f071c5fda4513ca142fe812e 100644 (file)
 /* Line 268 of yacc.c  */
 #line 1 "spotlight_rawquery_parser.y"
 
+  #include <atalk/standards.h>
+
   #include <stdbool.h>
   #include <stdio.h>
   #include <string.h>
+  #include <time.h>
+
   #include <gio/gio.h>
+
   #include <atalk/talloc.h>
   #include <atalk/logger.h>
+  #include <atalk/errchk.h>
+
   #include "spotlight_SPARQL_map.h"
   #include "spotlight.h"
 
   extern YY_BUFFER_STATE yy_scan_string( const char *str);
   extern void yy_delete_buffer ( YY_BUFFER_STATE buffer );
 
-  static const char *map_expr(const char *attr, const char *val);
-  static const char *map_daterange(const char *dateattr, const char *date1, const char *date2);
-
+  /* forward declarations */
+  static const char *map_expr(const char *attr, char op, const char *val);
+  static const char *map_daterange(const char *dateattr, time_t date1, time_t date2);
+  static time_t isodate2unix(const char *s);
+ /* global vars, eg needed by the lexer */
   slq_t *ssp_slq;
-  gchar *ssp_result;
+
+  /* local vars */
+  static gchar *ssp_result;
 
 
 
 /* Line 268 of yacc.c  */
-#line 98 "spotlight_rawquery_parser.c"
+#line 110 "spotlight_rawquery_parser.c"
 
 /* Enabling traces.  */
 #ifndef YYDEBUG
    /* Put the tokens into the symbol table, so that GDB and other debuggers
       know about them.  */
    enum yytokentype {
-     DATE = 258,
-     WORD = 259,
+     WORD = 258,
+     BOOL = 259,
      FUNC_INRANGE = 260,
-     DATE_SPEC = 261,
+     DATE_ISO = 261,
      OBRACE = 262,
      CBRACE = 263,
      EQUAL = 264,
-     COMMA = 265,
-     QUOTE = 266,
-     AND = 267,
-     OR = 268
+     UNEQUAL = 265,
+     GT = 266,
+     LT = 267,
+     COMMA = 268,
+     QUOTE = 269,
+     AND = 270,
+     OR = 271
    };
 #endif
 /* Tokens.  */
-#define DATE 258
-#define WORD 259
+#define WORD 258
+#define BOOL 259
 #define FUNC_INRANGE 260
-#define DATE_SPEC 261
+#define DATE_ISO 261
 #define OBRACE 262
 #define CBRACE 263
 #define EQUAL 264
-#define COMMA 265
-#define QUOTE 266
-#define AND 267
-#define OR 268
+#define UNEQUAL 265
+#define GT 266
+#define LT 267
+#define COMMA 268
+#define QUOTE 269
+#define AND 270
+#define OR 271
 
 
 
@@ -155,15 +173,17 @@ typedef union YYSTYPE
 {
 
 /* Line 293 of yacc.c  */
-#line 33 "spotlight_rawquery_parser.y"
+#line 45 "spotlight_rawquery_parser.y"
 
     int ival;
     const char *sval;
+    bool bval;
+    time_t tval;
 
 
 
 /* Line 293 of yacc.c  */
-#line 167 "spotlight_rawquery_parser.c"
+#line 187 "spotlight_rawquery_parser.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -173,22 +193,22 @@ typedef union YYSTYPE
 /* "%code provides" blocks.  */
 
 /* Line 340 of yacc.c  */
-#line 27 "spotlight_rawquery_parser.y"
+#line 39 "spotlight_rawquery_parser.y"
 
-  extern const gchar *map_spotlight_to_sparql_query(slq_t *slq);
+  #define SPRAW_TIME_OFFSET 978307200
+  extern int map_spotlight_to_sparql_query(slq_t *slq, gchar **sparql_result);
   extern slq_t *ssp_slq;
-  extern gchar *ssp_result;
 
 
 
 /* Line 340 of yacc.c  */
-#line 186 "spotlight_rawquery_parser.c"
+#line 206 "spotlight_rawquery_parser.c"
 
 /* Copy the second part of user declarations.  */
 
 
 /* Line 343 of yacc.c  */
-#line 192 "spotlight_rawquery_parser.c"
+#line 212 "spotlight_rawquery_parser.c"
 
 #ifdef short
 # undef short
@@ -407,20 +427,20 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  2
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   37
+#define YYLAST   56
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  14
+#define YYNTOKENS  17
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  6
+#define YYNNTS  7
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  12
+#define YYNRULES  18
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  35
+#define YYNSTATES  47
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   268
+#define YYMAXUTOK   271
 
 #define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -454,7 +474,8 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    13
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16
 };
 
 #if YYDEBUG
@@ -462,25 +483,28 @@ static const yytype_uint8 yytranslate[] =
    YYRHS.  */
 static const yytype_uint8 yyprhs[] =
 {
-       0,     0,     3,     4,     7,     9,    13,    15,    17,    21,
-      25,    29,    35
+       0,     0,     3,     4,     7,     9,    11,    15,    17,    19,
+      23,    27,    31,    37,    43,    49,    55,    64,    69
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      15,     0,    -1,    -1,    15,    16,    -1,    17,    -1,    18,
-      13,    18,    -1,    18,    -1,    19,    -1,     7,    17,     8,
-      -1,    17,    12,    17,    -1,    17,    13,    17,    -1,     4,
-       9,    11,     4,    11,    -1,     5,     7,     4,    10,     6,
-       7,     3,     8,    10,     6,     7,     3,     8,     8,    -1
+      18,     0,    -1,    -1,    18,    19,    -1,    20,    -1,     4,
+      -1,    21,    16,    21,    -1,    21,    -1,    22,    -1,     7,
+      20,     8,    -1,    20,    15,    20,    -1,    20,    16,    20,
+      -1,     3,     9,    14,     3,    14,    -1,     3,    10,    14,
+       3,    14,    -1,     3,    12,    14,     3,    14,    -1,     3,
+      11,    14,     3,    14,    -1,     5,     7,     3,    13,    23,
+      13,    23,     8,    -1,     6,     7,     3,     8,    -1,     3,
+      -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,    51,    51,    53,    57,    67,    73,    74,    75,    76,
-      77,    86,    90
+       0,    67,    67,    69,    73,    83,    89,    95,    96,    97,
+      98,    99,   108,   109,   110,   111,   115,   119,   120
 };
 #endif
 
@@ -489,9 +513,10 @@ static const yytype_uint8 yyrline[] =
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "DATE", "WORD", "FUNC_INRANGE",
-  "DATE_SPEC", "OBRACE", "CBRACE", "EQUAL", "COMMA", "QUOTE", "AND", "OR",
-  "$accept", "input", "line", "expr", "match", "function", 0
+  "$end", "error", "$undefined", "WORD", "BOOL", "FUNC_INRANGE",
+  "DATE_ISO", "OBRACE", "CBRACE", "EQUAL", "UNEQUAL", "GT", "LT", "COMMA",
+  "QUOTE", "AND", "OR", "$accept", "input", "line", "expr", "match",
+  "function", "date", 0
 };
 #endif
 
@@ -501,22 +526,22 @@ static const char *const yytname[] =
 static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268
+     265,   266,   267,   268,   269,   270,   271
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    14,    15,    15,    16,    17,    17,    17,    17,    17,
-      17,    18,    19
+       0,    17,    18,    18,    19,    20,    20,    20,    20,    20,
+      20,    20,    21,    21,    21,    21,    22,    23,    23
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     0,     2,     1,     3,     1,     1,     3,     3,
-       3,     5,    14
+       0,     2,     0,     2,     1,     1,     3,     1,     1,     3,
+       3,     3,     5,     5,     5,     5,     8,     4,     1
 };
 
 /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
@@ -524,33 +549,35 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       2,     0,     1,     0,     0,     0,     3,     4,     6,     7,
-       0,     0,     0,     0,     0,     0,     0,     0,     8,     9,
-      10,     5,     0,     0,    11,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,    12
+       2,     0,     1,     0,     5,     0,     0,     3,     4,     7,
+       8,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     9,    10,    11,     6,     0,
+       0,     0,     0,     0,    12,    13,    15,    14,    18,     0,
+       0,     0,     0,     0,     0,    17,    16
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
-      -1,     1,     6,     7,     8,     9
+      -1,     1,     7,     8,     9,    10,    40
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -7
+#define YYPACT_NINF -10
 static const yytype_int8 yypact[] =
 {
-      -7,     6,    -7,    -6,    -2,    -3,    -7,     2,     5,    -7,
-      -4,    15,     4,    -3,    -3,    16,    17,    12,    -7,    10,
-      -7,    -7,    13,    19,    -7,    20,    23,    21,    18,    24,
-      25,    28,    26,    27,    -7
+     -10,    10,   -10,     9,   -10,    -2,    -1,   -10,     8,    -9,
+     -10,     2,    12,    13,    14,    26,    -7,    -1,    -1,    27,
+      28,    29,    30,    31,    22,   -10,    20,   -10,   -10,    23,
+      24,    25,    32,    19,   -10,   -10,   -10,   -10,   -10,    33,
+      34,    38,    19,    35,    36,   -10,   -10
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-      -7,    -7,    -7,    -5,    22,    -7
+     -10,   -10,   -10,    -6,    37,   -10,     0
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -559,34 +586,39 @@ static const yytype_int8 yypgoto[] =
 #define YYTABLE_NINF -1
 static const yytype_uint8 yytable[] =
 {
-      12,     3,     4,    10,     5,    11,     2,    16,    19,    20,
-       3,     4,    18,     5,    13,    14,    13,    14,    15,    17,
-       3,    22,    23,    14,    24,    25,    27,    26,    29,    28,
-      30,    32,    31,     0,    33,    34,     0,    21
+      16,    25,     3,     4,     5,    15,     6,    19,    17,    18,
+       2,    26,    27,     3,     4,     5,    20,     6,    11,    12,
+      13,    14,    38,    17,    18,    39,    21,    22,    23,    24,
+       3,    29,    30,    31,    32,    33,    18,    34,    35,    36,
+      41,    43,    44,    45,    46,     0,    37,    42,     0,     0,
+       0,     0,     0,     0,     0,     0,    28
 };
 
 #define yypact_value_is_default(yystate) \
-  ((yystate) == (-7))
+  ((yystate) == (-10))
 
 #define yytable_value_is_error(yytable_value) \
   YYID (0)
 
 static const yytype_int8 yycheck[] =
 {
-       5,     4,     5,     9,     7,     7,     0,    11,    13,    14,
-       4,     5,     8,     7,    12,    13,    12,    13,    13,     4,
-       4,     4,    10,    13,    11,     6,     3,     7,    10,     8,
-       6,     3,     7,    -1,     8,     8,    -1,    15
+       6,     8,     3,     4,     5,     7,     7,    16,    15,    16,
+       0,    17,    18,     3,     4,     5,    14,     7,     9,    10,
+      11,    12,     3,    15,    16,     6,    14,    14,    14,     3,
+       3,     3,     3,     3,     3,    13,    16,    14,    14,    14,
+       7,     3,    42,     8,     8,    -1,    14,    13,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    19
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,    15,     0,     4,     5,     7,    16,    17,    18,    19,
-       9,     7,    17,    12,    13,    13,    11,     4,     8,    17,
-      17,    18,     4,    10,    11,     6,     7,     3,     8,    10,
-       6,     7,     3,     8,     8
+       0,    18,     0,     3,     4,     5,     7,    19,    20,    21,
+      22,     9,    10,    11,    12,     7,    20,    15,    16,    16,
+      14,    14,    14,    14,     3,     8,    20,    20,    21,     3,
+       3,     3,     3,    13,    14,    14,    14,    14,     3,     6,
+      23,     7,    13,     3,    23,     8,     8
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -1423,7 +1455,7 @@ yyreduce:
         case 4:
 
 /* Line 1806 of yacc.c  */
-#line 57 "spotlight_rawquery_parser.y"
+#line 73 "spotlight_rawquery_parser.y"
     {
     ssp_result = talloc_asprintf(ssp_slq,
                                  "SELECT DISTINCT ?url WHERE "
@@ -1436,7 +1468,19 @@ yyreduce:
   case 5:
 
 /* Line 1806 of yacc.c  */
-#line 67 "spotlight_rawquery_parser.y"
+#line 83 "spotlight_rawquery_parser.y"
+    {
+    if ((yyvsp[(1) - (1)].bval) == false)
+        YYACCEPT;
+    else
+        YYABORT;
+}
+    break;
+
+  case 6:
+
+/* Line 1806 of yacc.c  */
+#line 89 "spotlight_rawquery_parser.y"
     {
     if (strcmp((yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].sval)) != 0)
         (yyval.sval) = talloc_asprintf(ssp_slq, "{ %s } UNION { %s }", (yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].sval));
@@ -1445,38 +1489,38 @@ yyreduce:
 }
     break;
 
-  case 6:
+  case 7:
 
 /* Line 1806 of yacc.c  */
-#line 73 "spotlight_rawquery_parser.y"
-    {(yyval.sval) = (yyvsp[(1) - (1)].sval);}
+#line 95 "spotlight_rawquery_parser.y"
+    {(yyval.sval) = (yyvsp[(1) - (1)].sval); if ((yyval.sval) == NULL) YYABORT;}
     break;
 
-  case 7:
+  case 8:
 
 /* Line 1806 of yacc.c  */
-#line 74 "spotlight_rawquery_parser.y"
+#line 96 "spotlight_rawquery_parser.y"
     {(yyval.sval) = (yyvsp[(1) - (1)].sval);}
     break;
 
-  case 8:
+  case 9:
 
 /* Line 1806 of yacc.c  */
-#line 75 "spotlight_rawquery_parser.y"
+#line 97 "spotlight_rawquery_parser.y"
     {(yyval.sval) = talloc_asprintf(ssp_slq, "%s", (yyvsp[(2) - (3)].sval));}
     break;
 
-  case 9:
+  case 10:
 
 /* Line 1806 of yacc.c  */
-#line 76 "spotlight_rawquery_parser.y"
+#line 98 "spotlight_rawquery_parser.y"
     {(yyval.sval) = talloc_asprintf(ssp_slq, "%s . %s", (yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].sval));}
     break;
 
-  case 10:
+  case 11:
 
 /* Line 1806 of yacc.c  */
-#line 77 "spotlight_rawquery_parser.y"
+#line 99 "spotlight_rawquery_parser.y"
     {
     if (strcmp((yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].sval)) != 0)
         (yyval.sval) = talloc_asprintf(ssp_slq, "{ %s } UNION { %s }", (yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].sval));
@@ -1485,24 +1529,59 @@ yyreduce:
 }
     break;
 
-  case 11:
+  case 12:
 
 /* Line 1806 of yacc.c  */
-#line 86 "spotlight_rawquery_parser.y"
-    {(yyval.sval) = map_expr((yyvsp[(1) - (5)].sval), (yyvsp[(4) - (5)].sval));}
+#line 108 "spotlight_rawquery_parser.y"
+    {(yyval.sval) = map_expr((yyvsp[(1) - (5)].sval), '=', (yyvsp[(4) - (5)].sval));}
     break;
 
-  case 12:
+  case 13:
 
 /* Line 1806 of yacc.c  */
-#line 90 "spotlight_rawquery_parser.y"
-    {(yyval.sval) = map_daterange((yyvsp[(3) - (14)].sval), (yyvsp[(7) - (14)].sval), (yyvsp[(12) - (14)].sval));}
+#line 109 "spotlight_rawquery_parser.y"
+    {(yyval.sval) = map_expr((yyvsp[(1) - (5)].sval), '!', (yyvsp[(4) - (5)].sval));}
     break;
 
+  case 14:
 
+/* Line 1806 of yacc.c  */
+#line 110 "spotlight_rawquery_parser.y"
+    {(yyval.sval) = map_expr((yyvsp[(1) - (5)].sval), '<', (yyvsp[(4) - (5)].sval));}
+    break;
+
+  case 15:
+
+/* Line 1806 of yacc.c  */
+#line 111 "spotlight_rawquery_parser.y"
+    {(yyval.sval) = map_expr((yyvsp[(1) - (5)].sval), '>', (yyvsp[(4) - (5)].sval));}
+    break;
+
+  case 16:
+
+/* Line 1806 of yacc.c  */
+#line 115 "spotlight_rawquery_parser.y"
+    {(yyval.sval) = map_daterange((yyvsp[(3) - (8)].sval), (yyvsp[(5) - (8)].tval), (yyvsp[(7) - (8)].tval));}
+    break;
+
+  case 17:
+
+/* Line 1806 of yacc.c  */
+#line 119 "spotlight_rawquery_parser.y"
+    {(yyval.tval) = isodate2unix((yyvsp[(3) - (4)].sval));}
+    break;
+
+  case 18:
 
 /* Line 1806 of yacc.c  */
-#line 1506 "spotlight_rawquery_parser.c"
+#line 120 "spotlight_rawquery_parser.y"
+    {(yyval.tval) = atoi((yyvsp[(1) - (1)].sval)) + SPRAW_TIME_OFFSET;}
+    break;
+
+
+
+/* Line 1806 of yacc.c  */
+#line 1585 "spotlight_rawquery_parser.c"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -1733,40 +1812,86 @@ yyreturn:
 
 
 /* Line 2067 of yacc.c  */
-#line 93 "spotlight_rawquery_parser.y"
+#line 123 "spotlight_rawquery_parser.y"
 
 
-const char *map_daterange(const char *dateattr, const char *date1, const char *date2)
+static time_t isodate2unix(const char *s)
 {
+    struct tm tm;
+
+    if (strptime(s, "%Y-%m-%dT%H:%M:%SZ", &tm) == NULL)
+        return (time_t)-1;
+    return mktime(&tm);
+}
+
+const char *map_daterange(const char *dateattr, time_t date1, time_t date2)
+{
+    EC_INIT;
     char *result = NULL;
     struct spotlight_sparql_map *p;
+    struct tm *tmp;
+    char buf1[64], buf2[64];
+
+    EC_NULL( tmp = localtime(&date1) );
+    strftime(buf1, sizeof(buf1), "%Y-%m-%dT%H:%M:%SZ", tmp);
+    EC_NULL( tmp = localtime(&date2) );
+    strftime(buf2, sizeof(buf2), "%Y-%m-%dT%H:%M:%SZ", tmp);
 
     for (p = spotlight_sparql_map; p->ssm_spotlight_attr; p++) {
         if (strcmp(dateattr, p->ssm_spotlight_attr) == 0) {
             result = talloc_asprintf(ssp_slq,
                                      "?x %s ?d FILTER (?d > '%s' && ?d < '%s')",
                                      p->ssm_sparql_attr,
-                                     date1,
-                                     date2);
+                                     buf1,
+                                     buf2);
         }
     }
 
-
+EC_CLEANUP:
+    if (ret != 0)
+        return NULL;
     return result;
 }
 
-const char *map_expr(const char *attr, const char *val)
+const char *map_expr(const char *attr, char op, const char *val)
 {
+    EC_INIT;
     char *result = NULL;
     struct spotlight_sparql_map *p;
+    time_t t;
+    struct tm *tmp;
+    char buf1[64];
 
     for (p = spotlight_sparql_map; p->ssm_spotlight_attr; p++) {
         if (strcmp(p->ssm_spotlight_attr, attr) == 0) {
-            result = talloc_asprintf(ssp_slq, p->ssm_sparql_query_fmtstr, val);
+            switch (p->ssm_type) {
+            case ssmt_bool:
+                result = talloc_asprintf(ssp_slq, "?x %s '%s'", p->ssm_sparql_attr, val);
+                break;
+            case ssmt_num:
+                result = talloc_asprintf(ssp_slq, "?x %s ?y FILTER(?y %c '%s')", p->ssm_sparql_attr, op, val);
+                break;
+            case ssmt_str:
+                result = talloc_asprintf(ssp_slq, "?x %s ?y FILTER(regex(?y, '%s'))", p->ssm_sparql_attr, val);
+                break;
+            case ssmt_fts:
+                result = talloc_asprintf(ssp_slq, "?x %s '%s'", p->ssm_sparql_attr, val);
+                break;
+            case ssmt_date:
+                t = atoi(val) + SPRAW_TIME_OFFSET;
+                EC_NULL( tmp = localtime(&t) );
+                strftime(buf1, sizeof(buf1), "%Y-%m-%dT%H:%M:%SZ", tmp);
+                result = talloc_asprintf(ssp_slq, "?x %s ?y FILTER(?y %c '%s')", p->ssm_sparql_attr, op, buf1);
+                break;
+            default:
+                yyerror("unknown Spotlight attribute type");
+                EC_FAIL;
+            }
             break;
         }
     }
 
+EC_CLEANUP:
     return result;
 }
 
@@ -1784,24 +1909,39 @@ int yywrap()
     return 1;
 } 
 
-const gchar *map_spotlight_to_sparql_query(slq_t *slq)
+/**
+ * Map a Spotlight RAW query string to a SPARQL query string
+ *
+ * @param[in]     slq            Spotlight query handle
+ * @param[out]    sparql_result  Mapped SPARQL query, string is allocated in
+ *                               talloc context of slq
+ * @return        0 on success, -1 on error
+ **/
+int map_spotlight_to_sparql_query(slq_t *slq, gchar **sparql_result)
 {
-    YY_BUFFER_STATE s;
+    EC_INIT;
+    YY_BUFFER_STATE s = NULL;
+    ssp_result = NULL;
 
     ssp_slq = slq;
     s = yy_scan_string(slq->slq_qstring);
 
-    LOG(log_debug, logtype_sl, "map_spotlight_to_sparql_query: %s", slq->slq_qstring);
+    EC_ZERO( yyparse() );
 
-    yyparse();
-    yy_delete_buffer(s);
-
-    return ssp_result;
+EC_CLEANUP:
+    if (s)
+        yy_delete_buffer(s);
+    if (ret == 0)
+        *sparql_result = ssp_result;
+    else
+        *sparql_result = NULL;
+    EC_EXIT;
 }
 
 #ifdef MAIN
 int main(int argc, char **argv)
 {
+    int ret;
     YY_BUFFER_STATE s;
 
     if (argc != 2) {
@@ -1816,11 +1956,12 @@ int main(int argc, char **argv)
 
     s = yy_scan_string(argv[1]);
 
-    yyparse();
+    ret = yyparse();
 
     yy_delete_buffer(s);
 
-    printf("SPARQL: %s\n", ssp_result);
+    if (ret == 0)
+        printf("SPARQL: %s\n", ssp_result ? ssp_result : "(empty)");
 
     return 0;
 }