Blame libgupnp-av/gupnp-search-criteria-parser.c

Packit 712bc5
/*
Packit 712bc5
 * Copyright (C) 2008 OpenedHand Ltd.
Packit 712bc5
 *
Packit 712bc5
 * Authors: Jorn Baayen <jorn@openedhand.com>
Packit 712bc5
 *
Packit 712bc5
 * This library is free software; you can redistribute it and/or
Packit 712bc5
 * modify it under the terms of the GNU Library General Public
Packit 712bc5
 * License as published by the Free Software Foundation; either
Packit 712bc5
 * version 2 of the License, or (at your option) any later version.
Packit 712bc5
 *
Packit 712bc5
 * This library is distributed in the hope that it will be useful,
Packit 712bc5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 712bc5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 712bc5
 * Library General Public License for more details.
Packit 712bc5
 *
Packit 712bc5
 * You should have received a copy of the GNU Library General Public
Packit 712bc5
 * License along with this library; if not, write to the
Packit 712bc5
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit 712bc5
 * Boston, MA 02110-1301, USA.
Packit 712bc5
 */
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * SECTION:gupnp-search-criteria-parser
Packit 712bc5
 * @short_description: A/V search criteria parser
Packit 712bc5
 *
Packit 712bc5
 * #GUPnPSearchCriteriaParser parses ContentDirectory search criteria
Packit 712bc5
 * strings.
Packit 712bc5
 *
Packit 712bc5
 * Note that no signals will be emitted if a wildcard is specified,
Packit 712bc5
 * and that the user is responsible for ensuring precedence of conjunction
Packit 712bc5
 * over disjunction.
Packit 712bc5
 */
Packit 712bc5
Packit 712bc5
#include <string.h>
Packit 712bc5
Packit 712bc5
#include "gupnp-search-criteria-parser.h"
Packit 712bc5
#include "gupnp-av-marshal.h"
Packit 712bc5
Packit 712bc5
/* GType for GUPNPSearchCriteriaOp */
Packit 712bc5
GType
Packit 712bc5
gupnp_search_criteria_op_get_type (void)
Packit 712bc5
{
Packit 712bc5
        static GType type = 0;
Packit 712bc5
Packit 712bc5
        if (type == 0) {
Packit 712bc5
                static const GEnumValue values[] = {
Packit 712bc5
                        { GUPNP_SEARCH_CRITERIA_OP_EQ,
Packit 712bc5
                          "GUPNP_SEARCH_CRITERIA_OP_EQ",
Packit 712bc5
                          "EQ" },
Packit 712bc5
                        { GUPNP_SEARCH_CRITERIA_OP_NEQ,
Packit 712bc5
                          "GUPNP_SEARCH_CRITERIA_OP_NEQ",
Packit 712bc5
                          "NEQ" },
Packit 712bc5
                        { GUPNP_SEARCH_CRITERIA_OP_LESS,
Packit 712bc5
                          "GUPNP_SEARCH_CRITERIA_OP_LESS",
Packit 712bc5
                          "LESS" },
Packit 712bc5
                        { GUPNP_SEARCH_CRITERIA_OP_LEQ,
Packit 712bc5
                          "GUPNP_SEARCH_CRITERIA_OP_LEQ",
Packit 712bc5
                          "LEQ" },
Packit 712bc5
                        { GUPNP_SEARCH_CRITERIA_OP_GREATER,
Packit 712bc5
                          "GUPNP_SEARCH_CRITERIA_OP_GREATER",
Packit 712bc5
                          "GREATER" },
Packit 712bc5
                        { GUPNP_SEARCH_CRITERIA_OP_GEQ,
Packit 712bc5
                          "GUPNP_SEARCH_CRITERIA_OP_GEQ",
Packit 712bc5
                          "GEQ" },
Packit 712bc5
                        { GUPNP_SEARCH_CRITERIA_OP_CONTAINS,
Packit 712bc5
                          "GUPNP_SEARCH_CRITERIA_OP_CONTAINS",
Packit 712bc5
                          "CONTAINS" },
Packit 712bc5
                        { GUPNP_SEARCH_CRITERIA_OP_DOES_NOT_CONTAIN,
Packit 712bc5
                          "GUPNP_SEARCH_CRITERIA_OP_DOES_NOT_CONTAIN",
Packit 712bc5
                          "DOES_NOT_CONTAIN" },
Packit 712bc5
                        { GUPNP_SEARCH_CRITERIA_OP_DERIVED_FROM,
Packit 712bc5
                          "GUPNP_SEARCH_CRITERIA_OP_DERIVED_FROM",
Packit 712bc5
                          "DERIVED_FROM" },
Packit 712bc5
                        { GUPNP_SEARCH_CRITERIA_OP_EXISTS,
Packit 712bc5
                          "GUPNP_SEARCH_CRITERIA_OP_EXISTS",
Packit 712bc5
                          "EXISTS" },
Packit 712bc5
                        { 0, NULL, NULL }
Packit 712bc5
                };
Packit 712bc5
Packit 712bc5
                type = g_enum_register_static
Packit 712bc5
                                (g_intern_static_string (
Packit 712bc5
                                 "GUPnPSearchCriteriaOp"),
Packit 712bc5
                                 values);
Packit 712bc5
        }
Packit 712bc5
Packit 712bc5
        return type;
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/* GUPnPSearchCriteriaParserError */
Packit 712bc5
GQuark
Packit 712bc5
gupnp_search_criteria_parser_error_quark (void)
Packit 712bc5
{
Packit 712bc5
        return g_quark_from_static_string
Packit 712bc5
                ("gupnp-search-criteria-parser-error-quark");
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/* GUPnPSearchCriteriaParser */
Packit 712bc5
G_DEFINE_TYPE (GUPnPSearchCriteriaParser,
Packit 712bc5
               gupnp_search_criteria_parser,
Packit 712bc5
               G_TYPE_OBJECT);
Packit 712bc5
Packit 712bc5
struct _GUPnPSearchCriteriaParserPrivate {
Packit 712bc5
        GScanner *scanner;
Packit 712bc5
};
Packit 712bc5
Packit 712bc5
enum {
Packit 712bc5
        BEGIN_PARENS,
Packit 712bc5
        END_PARENS,
Packit 712bc5
        CONJUNCTION,
Packit 712bc5
        DISJUNCTION,
Packit 712bc5
        EXPRESSION,
Packit 712bc5
        SIGNAL_LAST
Packit 712bc5
};
Packit 712bc5
Packit 712bc5
static guint signals[SIGNAL_LAST];
Packit 712bc5
Packit 712bc5
/* Additional parsable symbols */
Packit 712bc5
enum {
Packit 712bc5
        SYMBOL_ASTERISK = G_TOKEN_LAST + 11,
Packit 712bc5
        SYMBOL_AND      = G_TOKEN_LAST + 12,
Packit 712bc5
        SYMBOL_OR       = G_TOKEN_LAST + 13,
Packit 712bc5
        SYMBOL_TRUE     = G_TOKEN_LAST + 14,
Packit 712bc5
        SYMBOL_FALSE    = G_TOKEN_LAST + 15
Packit 712bc5
};
Packit 712bc5
Packit 712bc5
#define NUM_SYMBOLS 15
Packit 712bc5
Packit 712bc5
struct {
Packit 712bc5
        const char *name;
Packit 712bc5
        int         token;
Packit 712bc5
} symbols[NUM_SYMBOLS] = {
Packit 712bc5
        { "*",
Packit 712bc5
          SYMBOL_ASTERISK },
Packit 712bc5
Packit 712bc5
        { "and",
Packit 712bc5
          SYMBOL_AND },
Packit 712bc5
        { "or",
Packit 712bc5
          SYMBOL_OR },
Packit 712bc5
Packit 712bc5
        { "=",
Packit 712bc5
          GUPNP_SEARCH_CRITERIA_OP_EQ },
Packit 712bc5
        { "!=",
Packit 712bc5
          GUPNP_SEARCH_CRITERIA_OP_NEQ },
Packit 712bc5
        { "<",
Packit 712bc5
          GUPNP_SEARCH_CRITERIA_OP_LESS },
Packit 712bc5
        { "<=",
Packit 712bc5
          GUPNP_SEARCH_CRITERIA_OP_LEQ },
Packit 712bc5
        { ">",
Packit 712bc5
          GUPNP_SEARCH_CRITERIA_OP_GREATER },
Packit 712bc5
        { ">=",
Packit 712bc5
          GUPNP_SEARCH_CRITERIA_OP_GEQ },
Packit 712bc5
Packit 712bc5
        { "contains",
Packit 712bc5
          GUPNP_SEARCH_CRITERIA_OP_CONTAINS },
Packit 712bc5
        { "doesNotContain",
Packit 712bc5
          GUPNP_SEARCH_CRITERIA_OP_DOES_NOT_CONTAIN },
Packit 712bc5
        { "derivedfrom",
Packit 712bc5
          GUPNP_SEARCH_CRITERIA_OP_DERIVED_FROM },
Packit 712bc5
Packit 712bc5
        { "exists",
Packit 712bc5
          GUPNP_SEARCH_CRITERIA_OP_EXISTS },
Packit 712bc5
Packit 712bc5
        { "true",
Packit 712bc5
          SYMBOL_TRUE },
Packit 712bc5
        { "false",
Packit 712bc5
          SYMBOL_FALSE }
Packit 712bc5
};
Packit 712bc5
Packit 712bc5
static void
Packit 712bc5
gupnp_search_criteria_parser_init (GUPnPSearchCriteriaParser *parser)
Packit 712bc5
{
Packit 712bc5
        int i;
Packit 712bc5
Packit 712bc5
        parser->priv = G_TYPE_INSTANCE_GET_PRIVATE
Packit 712bc5
                         (parser,
Packit 712bc5
                          GUPNP_TYPE_SEARCH_CRITERIA_PARSER,
Packit 712bc5
                          GUPnPSearchCriteriaParserPrivate);
Packit 712bc5
Packit 712bc5
        /* Set up GScanner */
Packit 712bc5
        parser->priv->scanner = g_scanner_new (NULL);
Packit 712bc5
Packit 712bc5
        parser->priv->scanner->config->cset_skip_characters  = (char *)" \t\n\r\012"
Packit 712bc5
                                                               "\013\014\015";
Packit 712bc5
        parser->priv->scanner->config->scan_identifier_1char = TRUE;
Packit 712bc5
        parser->priv->scanner->config->cset_identifier_first = (char *) G_CSET_a_2_z
Packit 712bc5
                                                               "_*<>=!@"
Packit 712bc5
                                                               G_CSET_A_2_Z;
Packit 712bc5
        parser->priv->scanner->config->cset_identifier_nth =   (char *)G_CSET_a_2_z
Packit 712bc5
                                                               "_0123456789=:@"
Packit 712bc5
                                                               G_CSET_A_2_Z
Packit 712bc5
                                                               G_CSET_LATINS
Packit 712bc5
                                                               G_CSET_LATINC;
Packit 712bc5
        parser->priv->scanner->config->symbol_2_token        = TRUE;
Packit 712bc5
Packit 712bc5
        /* Add symbols */
Packit 712bc5
        for (i = 0; i < NUM_SYMBOLS; i++) {
Packit 712bc5
                g_scanner_scope_add_symbol (parser->priv->scanner,
Packit 712bc5
                                            0,
Packit 712bc5
                                            symbols[i].name,
Packit 712bc5
                                            GINT_TO_POINTER (symbols[i].token));
Packit 712bc5
        }
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
static void
Packit 712bc5
gupnp_search_criteria_parser_finalize (GObject *object)
Packit 712bc5
{
Packit 712bc5
        GObjectClass *gobject_class;
Packit 712bc5
        GUPnPSearchCriteriaParser *parser;
Packit 712bc5
Packit 712bc5
        parser = GUPNP_SEARCH_CRITERIA_PARSER (object);
Packit 712bc5
Packit 712bc5
        /* Destroy GScanner */
Packit 712bc5
        g_scanner_destroy (parser->priv->scanner);
Packit 712bc5
Packit 712bc5
        gobject_class =
Packit 712bc5
                G_OBJECT_CLASS (gupnp_search_criteria_parser_parent_class);
Packit 712bc5
        gobject_class->dispose (object);
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
static void
Packit 712bc5
gupnp_search_criteria_parser_class_init
Packit 712bc5
                                    (GUPnPSearchCriteriaParserClass *klass)
Packit 712bc5
{
Packit 712bc5
        GObjectClass *object_class;
Packit 712bc5
Packit 712bc5
        object_class = G_OBJECT_CLASS (klass);
Packit 712bc5
Packit 712bc5
        object_class->finalize = gupnp_search_criteria_parser_finalize;
Packit 712bc5
Packit 712bc5
        /**
Packit 712bc5
         * GUPnPSearchCriteriaParser::begin-parens:
Packit 712bc5
         * @parser: The #GUPnPSearchCriteriaParser that received the signal
Packit 712bc5
         *
Packit 712bc5
         * The ::begin_parens signal is emitted to mark the beginning of a
Packit 712bc5
         * parenthetical expression.
Packit 712bc5
         **/
Packit 712bc5
        signals[BEGIN_PARENS] =
Packit 712bc5
                g_signal_new ("begin-parens",
Packit 712bc5
                              GUPNP_TYPE_SEARCH_CRITERIA_PARSER,
Packit 712bc5
                              G_SIGNAL_RUN_LAST,
Packit 712bc5
                              G_STRUCT_OFFSET (GUPnPSearchCriteriaParserClass,
Packit 712bc5
                                               begin_parens),
Packit 712bc5
                              NULL,
Packit 712bc5
                              NULL,
Packit 712bc5
                              g_cclosure_marshal_VOID__VOID,
Packit 712bc5
                              G_TYPE_NONE,
Packit 712bc5
                              0);
Packit 712bc5
Packit 712bc5
        /**
Packit 712bc5
         * GUPnPSearchCriteriaParser::end-parens:
Packit 712bc5
         * @parser: The #GUPnPSearchCriteriaParser that received the signal
Packit 712bc5
         *
Packit 712bc5
         * The ::end_parens signal is emitted to mark the end of a parenthetical
Packit 712bc5
         * expression.
Packit 712bc5
         **/
Packit 712bc5
        signals[END_PARENS] =
Packit 712bc5
                g_signal_new ("end-parens",
Packit 712bc5
                              GUPNP_TYPE_SEARCH_CRITERIA_PARSER,
Packit 712bc5
                              G_SIGNAL_RUN_LAST,
Packit 712bc5
                              G_STRUCT_OFFSET (GUPnPSearchCriteriaParserClass,
Packit 712bc5
                                               end_parens),
Packit 712bc5
                              NULL,
Packit 712bc5
                              NULL,
Packit 712bc5
                              g_cclosure_marshal_VOID__VOID,
Packit 712bc5
                              G_TYPE_NONE,
Packit 712bc5
                              0);
Packit 712bc5
Packit 712bc5
        /**
Packit 712bc5
         * GUPnPSearchCriteriaParser::conjunction:
Packit 712bc5
         * @parser: The #GUPnPSearchCriteriaParser that received the signal
Packit 712bc5
         *
Packit 712bc5
         * The ::conjuction signal is emitted whenever a conjuction marker
Packit 712bc5
         * (and) is parsed.
Packit 712bc5
         **/
Packit 712bc5
        signals[CONJUNCTION] =
Packit 712bc5
                g_signal_new ("conjunction",
Packit 712bc5
                              GUPNP_TYPE_SEARCH_CRITERIA_PARSER,
Packit 712bc5
                              G_SIGNAL_RUN_LAST,
Packit 712bc5
                              G_STRUCT_OFFSET (GUPnPSearchCriteriaParserClass,
Packit 712bc5
                                               conjunction),
Packit 712bc5
                              NULL,
Packit 712bc5
                              NULL,
Packit 712bc5
                              g_cclosure_marshal_VOID__VOID,
Packit 712bc5
                              G_TYPE_NONE,
Packit 712bc5
                              0);
Packit 712bc5
Packit 712bc5
        /**
Packit 712bc5
         * GUPnPSearchCriteriaParser::disjunction:
Packit 712bc5
         * @parser: The #GUPnPSearchCriteriaParser that received the signal
Packit 712bc5
         *
Packit 712bc5
         * The ::disjuction signal is emitted whenever a disjuction marker
Packit 712bc5
         * (or&rpar is parsed.
Packit 712bc5
         **/
Packit 712bc5
        signals[DISJUNCTION] =
Packit 712bc5
                g_signal_new ("disjunction",
Packit 712bc5
                              GUPNP_TYPE_SEARCH_CRITERIA_PARSER,
Packit 712bc5
                              G_SIGNAL_RUN_LAST,
Packit 712bc5
                              G_STRUCT_OFFSET (GUPnPSearchCriteriaParserClass,
Packit 712bc5
                                               disjunction),
Packit 712bc5
                              NULL,
Packit 712bc5
                              NULL,
Packit 712bc5
                              g_cclosure_marshal_VOID__VOID,
Packit 712bc5
                              G_TYPE_NONE,
Packit 712bc5
                              0);
Packit 712bc5
Packit 712bc5
        /**
Packit 712bc5
         * GUPnPSearchCriteriaParser::expression:
Packit 712bc5
         * @parser: The #GUPnPSearchCriteriaParser that received the signal
Packit 712bc5
         * @property: The property
Packit 712bc5
         * @op: The operator as #GUPnPSearchCriteriaOp
Packit 712bc5
         * @value: The value as string
Packit 712bc5
         * @error: Place-holder for any possible errors from handler
Packit 712bc5
         *
Packit 712bc5
         * The ::expression signal is emitted whenever an expression is parsed.
Packit 712bc5
         * Set @error and return %FALSE if an error occurred.
Packit 712bc5
         **/
Packit 712bc5
        signals[EXPRESSION] =
Packit 712bc5
                g_signal_new ("expression",
Packit 712bc5
                              GUPNP_TYPE_SEARCH_CRITERIA_PARSER,
Packit 712bc5
                              G_SIGNAL_RUN_LAST,
Packit 712bc5
                              G_STRUCT_OFFSET (GUPnPSearchCriteriaParserClass,
Packit 712bc5
                                               expression),
Packit 712bc5
                              NULL,
Packit 712bc5
                              NULL,
Packit 712bc5
                              gupnp_av_marshal_BOOLEAN__STRING_UINT_STRING_POINTER,
Packit 712bc5
                              G_TYPE_BOOLEAN,
Packit 712bc5
                              4,
Packit 712bc5
                              G_TYPE_STRING,
Packit 712bc5
                              GUPNP_TYPE_SEARCH_CRITERIA_OP,
Packit 712bc5
                              G_TYPE_STRING,
Packit 712bc5
                              G_TYPE_POINTER);
Packit 712bc5
Packit 712bc5
        g_type_class_add_private (klass,
Packit 712bc5
                                  sizeof (GUPnPSearchCriteriaParserPrivate));
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * gupnp_search_criteria_parser_new:
Packit 712bc5
 *
Packit 712bc5
 * Return value: A new #GUPnPSearchCriteriaParser object.
Packit 712bc5
 **/
Packit 712bc5
GUPnPSearchCriteriaParser *
Packit 712bc5
gupnp_search_criteria_parser_new (void)
Packit 712bc5
{
Packit 712bc5
        return g_object_new (GUPNP_TYPE_SEARCH_CRITERIA_PARSER, NULL);
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/* Scan a relExp portion of a search criteria string */
Packit 712bc5
static gboolean
Packit 712bc5
scan_rel_exp (GUPnPSearchCriteriaParser *parser,
Packit 712bc5
              GError                   **error)
Packit 712bc5
{
Packit 712bc5
        GTokenValue value;
Packit 712bc5
        gboolean ret;
Packit 712bc5
        guint token;
Packit 712bc5
        GUPnPSearchCriteriaOp op;
Packit 712bc5
        char *arg1;
Packit 712bc5
Packit 712bc5
        token = g_scanner_get_next_token (parser->priv->scanner);
Packit 712bc5
        g_assert (token == G_TOKEN_IDENTIFIER); /* Already checked */
Packit 712bc5
Packit 712bc5
        value = g_scanner_cur_value (parser->priv->scanner);
Packit 712bc5
        arg1 = g_strdup (value.v_string);
Packit 712bc5
Packit 712bc5
        token = g_scanner_get_next_token (parser->priv->scanner);
Packit 712bc5
        switch (token) {
Packit 712bc5
        case GUPNP_SEARCH_CRITERIA_OP_EQ:
Packit 712bc5
        case GUPNP_SEARCH_CRITERIA_OP_NEQ:
Packit 712bc5
        case GUPNP_SEARCH_CRITERIA_OP_LESS:
Packit 712bc5
        case GUPNP_SEARCH_CRITERIA_OP_LEQ:
Packit 712bc5
        case GUPNP_SEARCH_CRITERIA_OP_GREATER:
Packit 712bc5
        case GUPNP_SEARCH_CRITERIA_OP_GEQ:
Packit 712bc5
        case GUPNP_SEARCH_CRITERIA_OP_CONTAINS:
Packit 712bc5
        case GUPNP_SEARCH_CRITERIA_OP_DOES_NOT_CONTAIN:
Packit 712bc5
        case GUPNP_SEARCH_CRITERIA_OP_DERIVED_FROM:
Packit 712bc5
                op = token;
Packit 712bc5
Packit 712bc5
                token = g_scanner_get_next_token (parser->priv->scanner);
Packit 712bc5
                if (token != G_TOKEN_STRING) {
Packit 712bc5
                        g_set_error
Packit 712bc5
                                (error,
Packit 712bc5
                                 GUPNP_SEARCH_CRITERIA_PARSER_ERROR,
Packit 712bc5
                                 GUPNP_SEARCH_CRITERIA_PARSER_ERROR_FAILED,
Packit 712bc5
                                 "Expected quoted string at position %u",
Packit 712bc5
                                 g_scanner_cur_position
Packit 712bc5
                                       (parser->priv->scanner));
Packit 712bc5
Packit 712bc5
                        ret = FALSE;
Packit 712bc5
Packit 712bc5
                        break;
Packit 712bc5
                }
Packit 712bc5
Packit 712bc5
                value = g_scanner_cur_value (parser->priv->scanner);
Packit 712bc5
Packit 712bc5
                g_signal_emit (parser, signals[EXPRESSION], 0,
Packit 712bc5
                               arg1, op, value.v_string, error, &ret;;
Packit 712bc5
Packit 712bc5
                break;
Packit 712bc5
Packit 712bc5
        case GUPNP_SEARCH_CRITERIA_OP_EXISTS:
Packit 712bc5
                op = token;
Packit 712bc5
Packit 712bc5
                token = g_scanner_get_next_token (parser->priv->scanner);
Packit 712bc5
                switch (token) {
Packit 712bc5
                case SYMBOL_TRUE:
Packit 712bc5
                        g_signal_emit (parser, signals[EXPRESSION], 0,
Packit 712bc5
                                       arg1, op, "true", error, &ret;;
Packit 712bc5
Packit 712bc5
                        break;
Packit 712bc5
                case SYMBOL_FALSE:
Packit 712bc5
                        g_signal_emit (parser, signals[EXPRESSION], 0,
Packit 712bc5
                                       arg1, op, "false", error, &ret;;
Packit 712bc5
Packit 712bc5
                        break;
Packit 712bc5
                default:
Packit 712bc5
                        g_set_error
Packit 712bc5
                                (error,
Packit 712bc5
                                 GUPNP_SEARCH_CRITERIA_PARSER_ERROR,
Packit 712bc5
                                 GUPNP_SEARCH_CRITERIA_PARSER_ERROR_FAILED,
Packit 712bc5
                                 "Expected boolean value at position %u",
Packit 712bc5
                                 g_scanner_cur_position
Packit 712bc5
                                       (parser->priv->scanner));
Packit 712bc5
Packit 712bc5
                        ret = FALSE;
Packit 712bc5
Packit 712bc5
                        break;
Packit 712bc5
                }
Packit 712bc5
Packit 712bc5
                break;
Packit 712bc5
Packit 712bc5
        default:
Packit 712bc5
                g_set_error (error,
Packit 712bc5
                             GUPNP_SEARCH_CRITERIA_PARSER_ERROR,
Packit 712bc5
                             GUPNP_SEARCH_CRITERIA_PARSER_ERROR_FAILED,
Packit 712bc5
                             "Expected operator at position %u",
Packit 712bc5
                             g_scanner_cur_position
Packit 712bc5
                               (parser->priv->scanner));
Packit 712bc5
Packit 712bc5
                ret = FALSE;
Packit 712bc5
        }
Packit 712bc5
Packit 712bc5
        g_free (arg1);
Packit 712bc5
Packit 712bc5
        return ret;
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
static gboolean
Packit 712bc5
scan_search_exp (GUPnPSearchCriteriaParser *parser,
Packit 712bc5
                 GError                   **error);
Packit 712bc5
Packit 712bc5
/* Scan a Logical operator and the part after that */
Packit 712bc5
static gboolean
Packit 712bc5
scan_logical_op (GUPnPSearchCriteriaParser *parser,
Packit 712bc5
                 GError                   **error)
Packit 712bc5
{
Packit 712bc5
        gboolean ret;
Packit 712bc5
        guint token;
Packit 712bc5
Packit 712bc5
        token = g_scanner_peek_next_token (parser->priv->scanner);
Packit 712bc5
Packit 712bc5
        switch (token) {
Packit 712bc5
                case SYMBOL_AND:
Packit 712bc5
                        g_scanner_get_next_token (parser->priv->scanner);
Packit 712bc5
Packit 712bc5
                        g_signal_emit (parser, signals[CONJUNCTION], 0);
Packit 712bc5
Packit 712bc5
                        ret = scan_search_exp (parser, error);
Packit 712bc5
Packit 712bc5
                        break;
Packit 712bc5
Packit 712bc5
                case SYMBOL_OR:
Packit 712bc5
                        g_scanner_get_next_token (parser->priv->scanner);
Packit 712bc5
Packit 712bc5
                        g_signal_emit (parser, signals[DISJUNCTION], 0);
Packit 712bc5
Packit 712bc5
                        ret = scan_search_exp (parser, error);
Packit 712bc5
Packit 712bc5
                        break;
Packit 712bc5
Packit 712bc5
                default:
Packit 712bc5
Packit 712bc5
                        ret = TRUE;
Packit 712bc5
Packit 712bc5
                        break;
Packit 712bc5
Packit 712bc5
        }
Packit 712bc5
Packit 712bc5
        return ret;
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/* Scan a searchExp portion of a search criteria string */
Packit 712bc5
static gboolean
Packit 712bc5
scan_search_exp (GUPnPSearchCriteriaParser *parser,
Packit 712bc5
                 GError                   **error)
Packit 712bc5
{
Packit 712bc5
        gboolean ret;
Packit 712bc5
        guint token;
Packit 712bc5
Packit 712bc5
        token = g_scanner_peek_next_token (parser->priv->scanner);
Packit 712bc5
        switch (token) {
Packit 712bc5
        case G_TOKEN_LEFT_PAREN:
Packit 712bc5
                g_scanner_get_next_token (parser->priv->scanner);
Packit 712bc5
Packit 712bc5
                g_signal_emit (parser, signals[BEGIN_PARENS], 0);
Packit 712bc5
Packit 712bc5
                ret = scan_search_exp (parser, error);
Packit 712bc5
                if (ret == FALSE)
Packit 712bc5
                        break;
Packit 712bc5
Packit 712bc5
                token = g_scanner_get_next_token (parser->priv->scanner);
Packit 712bc5
                if (token != G_TOKEN_RIGHT_PAREN) {
Packit 712bc5
                        g_set_error
Packit 712bc5
                                (error,
Packit 712bc5
                                 GUPNP_SEARCH_CRITERIA_PARSER_ERROR,
Packit 712bc5
                                 GUPNP_SEARCH_CRITERIA_PARSER_ERROR_FAILED,
Packit 712bc5
                                 "Expected right parenthesis at position %u",
Packit 712bc5
                                 g_scanner_cur_position
Packit 712bc5
                                        (parser->priv->scanner));
Packit 712bc5
Packit 712bc5
                        ret = FALSE;
Packit 712bc5
Packit 712bc5
                        break;
Packit 712bc5
                }
Packit 712bc5
Packit 712bc5
                g_signal_emit (parser, signals[END_PARENS], 0);
Packit 712bc5
Packit 712bc5
                ret = scan_logical_op (parser, error);
Packit 712bc5
Packit 712bc5
                break;
Packit 712bc5
Packit 712bc5
        case G_TOKEN_IDENTIFIER:
Packit 712bc5
                ret = scan_rel_exp (parser, error);
Packit 712bc5
                if (ret == FALSE)
Packit 712bc5
                        break;
Packit 712bc5
Packit 712bc5
                ret = scan_logical_op (parser, error);
Packit 712bc5
Packit 712bc5
                break;
Packit 712bc5
Packit 712bc5
        default:
Packit 712bc5
                g_scanner_get_next_token (parser->priv->scanner);
Packit 712bc5
Packit 712bc5
                g_set_error (error,
Packit 712bc5
                             GUPNP_SEARCH_CRITERIA_PARSER_ERROR,
Packit 712bc5
                             GUPNP_SEARCH_CRITERIA_PARSER_ERROR_FAILED,
Packit 712bc5
                             "Expected property name or left parenthesis at "
Packit 712bc5
                             "position %u",
Packit 712bc5
                             g_scanner_cur_position (parser->priv->scanner));
Packit 712bc5
Packit 712bc5
                ret = FALSE;
Packit 712bc5
        }
Packit 712bc5
Packit 712bc5
        return ret;
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * gupnp_search_criteria_parser_parse_text:
Packit 712bc5
 * @parser: A #GUPnPSearchCriteriaParser
Packit 712bc5
 * @text: The search criteria string to be parsed
Packit 712bc5
 * @error: The location where to store the error information if any, or NULL
Packit 712bc5
 *
Packit 712bc5
 * Parses @text, emitting the various defined signals on the way. If an
Packit 712bc5
 * error occured @error will be set.
Packit 712bc5
 *
Packit 712bc5
 * Return value: TRUE on success.
Packit 712bc5
 **/
Packit 712bc5
gboolean
Packit 712bc5
gupnp_search_criteria_parser_parse_text (GUPnPSearchCriteriaParser *parser,
Packit 712bc5
                                         const char                *text,
Packit 712bc5
                                         GError                   **error)
Packit 712bc5
{
Packit 712bc5
        gboolean ret;
Packit 712bc5
        guint token;
Packit 712bc5
Packit 712bc5
        g_return_val_if_fail (GUPNP_IS_SEARCH_CRITERIA_PARSER (parser),
Packit 712bc5
                              FALSE);
Packit 712bc5
        g_return_val_if_fail (text != NULL, FALSE);
Packit 712bc5
Packit 712bc5
        /* Feed into scanner */
Packit 712bc5
        g_scanner_input_text (parser->priv->scanner, text, strlen (text));
Packit 712bc5
Packit 712bc5
        token = g_scanner_peek_next_token (parser->priv->scanner);
Packit 712bc5
        if (token == SYMBOL_ASTERISK) {
Packit 712bc5
                g_scanner_get_next_token (parser->priv->scanner);
Packit 712bc5
Packit 712bc5
                /* Do nothing. */
Packit 712bc5
Packit 712bc5
                ret = TRUE;
Packit 712bc5
        } else
Packit 712bc5
                ret = scan_search_exp (parser, error);
Packit 712bc5
Packit 712bc5
        if (ret == TRUE) {
Packit 712bc5
                /* Confirm that we have EOF now */
Packit 712bc5
                token = g_scanner_get_next_token (parser->priv->scanner);
Packit 712bc5
                if (token != G_TOKEN_EOF) {
Packit 712bc5
                        g_set_error
Packit 712bc5
                                (error,
Packit 712bc5
                                 GUPNP_SEARCH_CRITERIA_PARSER_ERROR,
Packit 712bc5
                                 GUPNP_SEARCH_CRITERIA_PARSER_ERROR_FAILED,
Packit 712bc5
                                 "Expected EOF at position %u",
Packit 712bc5
                                 g_scanner_cur_position
Packit 712bc5
                                       (parser->priv->scanner));
Packit 712bc5
                }
Packit 712bc5
        }
Packit 712bc5
Packit 712bc5
        return ret;
Packit 712bc5
}