/** \file * This C source file was generated by $ANTLR version 3.2 debian-5 * * - From the grammar source file : DAAP2SQL.g * - On : 2011-09-11 15:48:50 * - for the tree parser : DAAP2SQLTreeParser * * Editing it, at least manually, is not wise. * * C language generator and runtime by Jim Idle, jimi|hereisanat|idle|dotgoeshere|ws. * * */ // [The "BSD licence"] // Copyright (c) 2005-2009 Jim Idle, Temporal Wave LLC // http://www.temporal-wave.com // http://www.linkedin.com/in/jimidle // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // 3. The name of the author may not be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* ============================================================================= * This is what the grammar programmer asked us to put at the top of every file. */ #include #include #include #include #include #include "logger.h" #include "db.h" #include "daap_query.h" /* End of Header action. * ============================================================================= */ /* ----------------------------------------- * Include the ANTLR3 generated header file. */ #include "DAAP2SQL.h" /* ----------------------------------------- */ /* MACROS that hide the C interface implementations from the * generated code, which makes it a little more understandable to the human eye. * I am very much against using C pre-processor macros for function calls and bits * of code as you cannot see what is happening when single stepping in debuggers * and so on. The exception (in my book at least) is for generated code, where you are * not maintaining it, but may wish to read and understand it. If you single step it, you know that input() * hides some indirect calls, but is always referring to the input stream. This is * probably more readable than ctx->input->istream->input(snarfle0->blarg) and allows me to rejig * the runtime interfaces without changing the generated code too often, without * confusing the reader of the generated output, who may not wish to know the gory * details of the interface inheritance. */ #define CTX ctx /* Aids in accessing scopes for grammar programmers */ #undef SCOPE_TYPE #undef SCOPE_STACK #undef SCOPE_TOP #define SCOPE_TYPE(scope) pDAAP2SQL_##scope##_SCOPE #define SCOPE_STACK(scope) pDAAP2SQL_##scope##Stack #define SCOPE_TOP(scope) ctx->pDAAP2SQL_##scope##Top #define SCOPE_SIZE(scope) ctx->pDAAP2SQL_##scope##Stack_limit #define SCOPE_INSTANCE(scope, i) (ctx->SCOPE_STACK(scope)->get(ctx->SCOPE_STACK(scope),i)) /* Macros for accessing things in the parser */ #undef PARSER #undef RECOGNIZER #undef HAVEPARSEDRULE #undef INPUT #undef STRSTREAM #undef HASEXCEPTION #undef EXCEPTION #undef MATCHT #undef MATCHANYT #undef FOLLOWSTACK #undef FOLLOWPUSH #undef FOLLOWPOP #undef PRECOVER #undef PREPORTERROR #undef LA #undef LT #undef CONSTRUCTEX #undef CONSUME #undef MARK #undef REWIND #undef REWINDLAST #undef PERRORRECOVERY #undef HASFAILED #undef FAILEDFLAG #undef RECOVERFROMMISMATCHEDSET #undef RECOVERFROMMISMATCHEDELEMENT #undef BACKTRACKING #undef ADAPTOR #undef RULEMEMO #undef SEEK #undef INDEX #undef DBG #define PARSER ctx->pTreeParser #define RECOGNIZER PARSER->rec #define PSRSTATE RECOGNIZER->state #define HAVEPARSEDRULE(r) RECOGNIZER->alreadyParsedRule(RECOGNIZER, r) #define INPUT PARSER->ctnstream #define ISTREAM INPUT->tnstream->istream #define STRSTREAM INPUT->tnstream #define HASEXCEPTION() (PSRSTATE->error == ANTLR3_TRUE) #define EXCEPTION PSRSTATE->exception #define MATCHT(t, fs) RECOGNIZER->match(RECOGNIZER, t, fs) #define MATCHANYT() RECOGNIZER->matchAny(RECOGNIZER) #define FOLLOWSTACK PSRSTATE->following #define FOLLOWPUSH(x) FOLLOWSTACK->push(FOLLOWSTACK, ((void *)(&(x))), NULL) #define FOLLOWPOP() FOLLOWSTACK->pop(FOLLOWSTACK) #define PRECOVER() RECOGNIZER->recover(RECOGNIZER) #define PREPORTERROR() RECOGNIZER->reportError(RECOGNIZER) #define LA(n) ISTREAM->_LA(ISTREAM, n) #define LT(n) INPUT->tnstream->_LT(INPUT->tnstream, n) #define CONSTRUCTEX() RECOGNIZER->exConstruct(RECOGNIZER) #define CONSUME() ISTREAM->consume(ISTREAM) #define MARK() ISTREAM->mark(ISTREAM) #define REWIND(m) ISTREAM->rewind(ISTREAM, m) #define REWINDLAST() ISTREAM->rewindLast(ISTREAM) #define PERRORRECOVERY PSRSTATE->errorRecovery #define FAILEDFLAG PSRSTATE->failed #define HASFAILED() (FAILEDFLAG == ANTLR3_TRUE) #define BACKTRACKING PSRSTATE->backtracking #define RECOVERFROMMISMATCHEDSET(s) RECOGNIZER->recoverFromMismatchedSet(RECOGNIZER, s) #define RECOVERFROMMISMATCHEDELEMENT(e) RECOGNIZER->recoverFromMismatchedElement(RECOGNIZER, s) #define ADAPTOR INPUT->adaptor #define RULEMEMO PSRSTATE->ruleMemo #define SEEK(n) ISTREAM->seek(ISTREAM, n) #define INDEX() ISTREAM->index(ISTREAM) #define DBG RECOGNIZER->debugger #define TOKTEXT(tok, txt) tok, (pANTLR3_UINT8)txt /* The 4 tokens defined below may well clash with your own #defines or token types. If so * then for the present you must use different names for your defines as these are hard coded * in the code generator. It would be better not to use such names internally, and maybe * we can change this in a forthcoming release. I deliberately do not #undef these * here as this will at least give you a redefined error somewhere if they clash. */ #define UP ANTLR3_TOKEN_UP #define DOWN ANTLR3_TOKEN_DOWN #define EOR ANTLR3_TOKEN_EOR #define INVALID ANTLR3_TOKEN_INVALID /* ============================================================================= * Functions to create and destroy scopes. First come the rule scopes, followed * by the global declared scopes. */ /* ============================================================================= */ /* ============================================================================= * Start of recognizer */ /** \brief Table of all token names in symbolic order, mainly used for * error reporting. */ pANTLR3_UINT8 DAAP2SQLTokenNames[8+4] = { (pANTLR3_UINT8) "", /* String to print to indicate an invalid token */ (pANTLR3_UINT8) "", (pANTLR3_UINT8) "", (pANTLR3_UINT8) "", (pANTLR3_UINT8) "NEWLINE", (pANTLR3_UINT8) "OPOR", (pANTLR3_UINT8) "OPAND", (pANTLR3_UINT8) "LPAR", (pANTLR3_UINT8) "RPAR", (pANTLR3_UINT8) "STR", (pANTLR3_UINT8) "QUOTE", (pANTLR3_UINT8) "ESCAPED" }; // Forward declare the locally static matching functions we have generated. // static pANTLR3_STRING query (pDAAP2SQL ctx); static DAAP2SQL_expr_return expr (pDAAP2SQL ctx); static void DAAP2SQLFree(pDAAP2SQL ctx); /* For use in tree output where we are accumulating rule labels via label += ruleRef * we need a function that knows how to free a return scope when the list is destroyed. * We cannot just use ANTLR3_FREE because in debug tracking mode, this is a macro. */ static void ANTLR3_CDECL freeScope(void * scope) { ANTLR3_FREE(scope); } /** \brief Name of the grammar file that generated this code */ static const char fileName[] = "DAAP2SQL.g"; /** \brief Return the name of the grammar file that generated this code. */ static const char * getGrammarFileName() { return fileName; } /** \brief Create a new DAAP2SQL parser and return a context for it. * * \param[in] instream Pointer to an input stream interface. * * \return Pointer to new parser context upon success. */ ANTLR3_API pDAAP2SQL DAAP2SQLNew (pANTLR3_COMMON_TREE_NODE_STREAM instream) { // See if we can create a new parser with the standard constructor // return DAAP2SQLNewSSD(instream, NULL); } /** \brief Create a new DAAP2SQL parser and return a context for it. * * \param[in] instream Pointer to an input stream interface. * * \return Pointer to new parser context upon success. */ ANTLR3_API pDAAP2SQL DAAP2SQLNewSSD (pANTLR3_COMMON_TREE_NODE_STREAM instream, pANTLR3_RECOGNIZER_SHARED_STATE state) { pDAAP2SQL ctx; /* Context structure we will build and return */ ctx = (pDAAP2SQL) ANTLR3_CALLOC(1, sizeof(DAAP2SQL)); if (ctx == NULL) { // Failed to allocate memory for parser context // return NULL; } /* ------------------------------------------------------------------- * Memory for basic structure is allocated, now to fill in * the base ANTLR3 structures. We initialize the function pointers * for the standard ANTLR3 parser function set, but upon return * from here, the programmer may set the pointers to provide custom * implementations of each function. * * We don't use the macros defined in DAAP2SQL.h here, in order that you can get a sense * of what goes where. */ /* Create a base Tree parser/recognizer, using the supplied tree node stream */ ctx->pTreeParser = antlr3TreeParserNewStream(ANTLR3_SIZE_HINT, instream, state); /* Install the implementation of our DAAP2SQL interface */ ctx->query = query; ctx->expr = expr; ctx->free = DAAP2SQLFree; ctx->getGrammarFileName = getGrammarFileName; /* Install the scope pushing methods. */ /* Install the token table */ PSRSTATE->tokenNames = DAAP2SQLTokenNames; /* Return the newly built parser to the caller */ return ctx; } /** Free the parser resources */ static void DAAP2SQLFree(pDAAP2SQL ctx) { /* Free any scope memory */ // Free this parser // ctx->pTreeParser->free(ctx->pTreeParser); ANTLR3_FREE(ctx); /* Everything is released, so we can return */ return; } /** Return token names used by this tree parser * * The returned pointer is used as an index into the token names table (using the token * number as the index). * * \return Pointer to first char * in the table. */ static pANTLR3_UINT8 *getTokenNames() { return DAAP2SQLTokenNames; } struct dmap_query_field_map { char *dmap_field; char *db_col; int as_int; }; /* gperf static hash, daap_query.gperf */ #include "daap_query_hash.c" /* Declare the bitsets */ /** Bitset defining follow set for error recovery in rule state: FOLLOW_expr_in_query70 */ static ANTLR3_BITWORD FOLLOW_expr_in_query70_bits[] = { ANTLR3_UINT64_LIT(0x0000000000000002) }; static ANTLR3_BITSET_LIST FOLLOW_expr_in_query70 = { FOLLOW_expr_in_query70_bits, 1 }; /** Bitset defining follow set for error recovery in rule state: FOLLOW_OPAND_in_expr95 */ static ANTLR3_BITWORD FOLLOW_OPAND_in_expr95_bits[] = { ANTLR3_UINT64_LIT(0x0000000000000004) }; static ANTLR3_BITSET_LIST FOLLOW_OPAND_in_expr95 = { FOLLOW_OPAND_in_expr95_bits, 1 }; /** Bitset defining follow set for error recovery in rule state: FOLLOW_expr_in_expr101 */ static ANTLR3_BITWORD FOLLOW_expr_in_expr101_bits[] = { ANTLR3_UINT64_LIT(0x0000000000000260) }; static ANTLR3_BITSET_LIST FOLLOW_expr_in_expr101 = { FOLLOW_expr_in_expr101_bits, 1 }; /** Bitset defining follow set for error recovery in rule state: FOLLOW_expr_in_expr107 */ static ANTLR3_BITWORD FOLLOW_expr_in_expr107_bits[] = { ANTLR3_UINT64_LIT(0x0000000000000008) }; static ANTLR3_BITSET_LIST FOLLOW_expr_in_expr107 = { FOLLOW_expr_in_expr107_bits, 1 }; /** Bitset defining follow set for error recovery in rule state: FOLLOW_OPOR_in_expr118 */ static ANTLR3_BITWORD FOLLOW_OPOR_in_expr118_bits[] = { ANTLR3_UINT64_LIT(0x0000000000000004) }; static ANTLR3_BITSET_LIST FOLLOW_OPOR_in_expr118 = { FOLLOW_OPOR_in_expr118_bits, 1 }; /** Bitset defining follow set for error recovery in rule state: FOLLOW_expr_in_expr124 */ static ANTLR3_BITWORD FOLLOW_expr_in_expr124_bits[] = { ANTLR3_UINT64_LIT(0x0000000000000260) }; static ANTLR3_BITSET_LIST FOLLOW_expr_in_expr124 = { FOLLOW_expr_in_expr124_bits, 1 }; /** Bitset defining follow set for error recovery in rule state: FOLLOW_expr_in_expr130 */ static ANTLR3_BITWORD FOLLOW_expr_in_expr130_bits[] = { ANTLR3_UINT64_LIT(0x0000000000000008) }; static ANTLR3_BITSET_LIST FOLLOW_expr_in_expr130 = { FOLLOW_expr_in_expr130_bits, 1 }; /** Bitset defining follow set for error recovery in rule state: FOLLOW_STR_in_expr140 */ static ANTLR3_BITWORD FOLLOW_STR_in_expr140_bits[] = { ANTLR3_UINT64_LIT(0x0000000000000002) }; static ANTLR3_BITSET_LIST FOLLOW_STR_in_expr140 = { FOLLOW_STR_in_expr140_bits, 1 }; /* ============================================== * Parsing rules */ /** * $ANTLR start query * DAAP2SQL.g:50:1: query returns [ pANTLR3_STRING result ] : e= expr ; */ static pANTLR3_STRING query(pDAAP2SQL ctx) { pANTLR3_STRING result = NULL; DAAP2SQL_expr_return e; #undef RETURN_TYPE_e #define RETURN_TYPE_e DAAP2SQL_expr_return /* Initialize rule variables */ result= NULL; { // DAAP2SQL.g:52:2: (e= expr ) // DAAP2SQL.g:52:4: e= expr { FOLLOWPUSH(FOLLOW_expr_in_query70); e=expr(ctx); FOLLOWPOP(); if (HASEXCEPTION()) { goto rulequeryEx; } { if (!e.valid) { result= NULL; } else { result= e.result->factory->newRaw(e.result->factory); result->append8(result, "("); result->appendS(result, e.result); result->append8(result, ")"); } } } } // This is where rules clean up and exit // goto rulequeryEx; /* Prevent compiler warnings */ rulequeryEx: ; if (HASEXCEPTION()) { PREPORTERROR(); PRECOVER(); } return result; } /* $ANTLR end query */ /** * $ANTLR start expr * DAAP2SQL.g:68:1: expr returns [ pANTLR3_STRING result, int valid ] : ( ^( OPAND a= expr b= expr ) | ^( OPOR a= expr b= expr ) | STR ); */ static DAAP2SQL_expr_return expr(pDAAP2SQL ctx) { DAAP2SQL_expr_return retval; pANTLR3_BASE_TREE STR1; DAAP2SQL_expr_return a; #undef RETURN_TYPE_a #define RETURN_TYPE_a DAAP2SQL_expr_return DAAP2SQL_expr_return b; #undef RETURN_TYPE_b #define RETURN_TYPE_b DAAP2SQL_expr_return /* Initialize rule variables */ retval.result= NULL; retval.valid= 1; STR1 = NULL; retval.start = LT(1); retval.stop = retval.start; { { // DAAP2SQL.g:70:2: ( ^( OPAND a= expr b= expr ) | ^( OPOR a= expr b= expr ) | STR ) ANTLR3_UINT32 alt1; alt1=3; switch ( LA(1) ) { case OPAND: { alt1=1; } break; case OPOR: { alt1=2; } break; case STR: { alt1=3; } break; default: CONSTRUCTEX(); EXCEPTION->type = ANTLR3_NO_VIABLE_ALT_EXCEPTION; EXCEPTION->message = (void *)""; EXCEPTION->decisionNum = 1; EXCEPTION->state = 0; goto ruleexprEx; } switch (alt1) { case 1: // DAAP2SQL.g:70:4: ^( OPAND a= expr b= expr ) { MATCHT(OPAND, &FOLLOW_OPAND_in_expr95); if (HASEXCEPTION()) { goto ruleexprEx; } MATCHT(ANTLR3_TOKEN_DOWN, NULL); if (HASEXCEPTION()) { goto ruleexprEx; } FOLLOWPUSH(FOLLOW_expr_in_expr101); a=expr(ctx); FOLLOWPOP(); if (HASEXCEPTION()) { goto ruleexprEx; } FOLLOWPUSH(FOLLOW_expr_in_expr107); b=expr(ctx); FOLLOWPOP(); if (HASEXCEPTION()) { goto ruleexprEx; } MATCHT(ANTLR3_TOKEN_UP, NULL); if (HASEXCEPTION()) { goto ruleexprEx; } { if (!a.valid || !b.valid) { retval.valid= 0; } else { retval.result= a.result->factory->newRaw(a.result->factory); retval.result->append8(retval.result, "("); retval.result->appendS(retval.result, a.result); retval.result->append8(retval.result, " AND "); retval.result->appendS(retval.result, b.result); retval.result->append8(retval.result, ")"); } } } break; case 2: // DAAP2SQL.g:86:4: ^( OPOR a= expr b= expr ) { MATCHT(OPOR, &FOLLOW_OPOR_in_expr118); if (HASEXCEPTION()) { goto ruleexprEx; } MATCHT(ANTLR3_TOKEN_DOWN, NULL); if (HASEXCEPTION()) { goto ruleexprEx; } FOLLOWPUSH(FOLLOW_expr_in_expr124); a=expr(ctx); FOLLOWPOP(); if (HASEXCEPTION()) { goto ruleexprEx; } FOLLOWPUSH(FOLLOW_expr_in_expr130); b=expr(ctx); FOLLOWPOP(); if (HASEXCEPTION()) { goto ruleexprEx; } MATCHT(ANTLR3_TOKEN_UP, NULL); if (HASEXCEPTION()) { goto ruleexprEx; } { if (!a.valid || !b.valid) { retval.valid= 0; } else { retval.result= a.result->factory->newRaw(a.result->factory); retval.result->append8(retval.result, "("); retval.result->appendS(retval.result, a.result); retval.result->append8(retval.result, " OR "); retval.result->appendS(retval.result, b.result); retval.result->append8(retval.result, ")"); } } } break; case 3: // DAAP2SQL.g:102:4: STR { STR1 = (pANTLR3_BASE_TREE) MATCHT(STR, &FOLLOW_STR_in_expr140); if (HASEXCEPTION()) { goto ruleexprEx; } { pANTLR3_STRING str; pANTLR3_UINT8 field; pANTLR3_UINT8 val; pANTLR3_UINT8 escaped; ANTLR3_UINT8 op; int neg_op; const struct dmap_query_field_map *dqfm; char *end; long long llval; escaped = NULL; retval.result= (STR1->getText(STR1))->factory->newRaw((STR1->getText(STR1))->factory); str = (STR1->getText(STR1))->toUTF8((STR1->getText(STR1))); /* NOTE: the lexer delivers the string without quotes which may not be obvious from the grammar due to embedded code */ /* Make daap.songalbumid:0 a no-op */ if (strcmp((char *)str->chars, "daap.songalbumid:0") == 0) { retval.result->append8(retval.result, "1 = 1"); goto STR_out; } field = str->chars; val = field; while ((*val != '\0') && ((*val == '.') || (*val == '-') || ((*val >= 'a') && (*val <= 'z')) || ((*val >= 'A') && (*val <= 'Z')) || ((*val >= '0') && (*val <= '9')))) { val++; } if (*field == '\0') { DPRINTF(E_LOG, L_DAAP, "No field name found in clause '%s'\n", field); retval.valid= 0; goto STR_result_valid_0; /* ABORT */ } if (*val == '\0') { DPRINTF(E_LOG, L_DAAP, "No operator found in clause '%s'\n", field); retval.valid= 0; goto STR_result_valid_0; /* ABORT */ } op = *val; *val = '\0'; val++; if (op == '!') { if (*val == '\0') { DPRINTF(E_LOG, L_DAAP, "Negation found but operator missing in clause '%s%c'\n", field, op); retval.valid= 0; goto STR_result_valid_0; /* ABORT */ } neg_op = 1; op = *val; val++; } else neg_op = 0; /* Lookup DMAP field in the query field map */ dqfm = daap_query_field_lookup((char *)field, strlen((char *)field)); if (!dqfm) { DPRINTF(E_LOG, L_DAAP, "DMAP field '%s' is not a valid field in queries\n", field); retval.valid= 0; goto STR_result_valid_0; /* ABORT */ } /* Empty values OK for string fields, NOK for integer */ if (*val == '\0') { if (dqfm->as_int) { DPRINTF(E_LOG, L_DAAP, "No value given in clause '%s%s%c'\n", field, (neg_op) ? "!" : "", op); retval.valid= 0; goto STR_result_valid_0; /* ABORT */ } /* Need to check against NULL too */ if (op == ':') retval.result->append8(retval.result, "("); } retval.result->append8(retval.result, dqfm->db_col); /* Int field: check integer conversion */ if (dqfm->as_int) { errno = 0; llval = strtoll((const char *)val, &end, 10); printf("val =%s end=%08x llval=%d\n",val,end,llval); if (((errno == ERANGE) && ((llval == LLONG_MAX) || (llval == LLONG_MIN))) || ((errno != 0) && (llval == 0))) { DPRINTF(E_LOG, L_DAAP, "Value '%s' in clause '%s%s%c%s' does not convert to an integer type\n", val, field, (neg_op) ? "!" : "", op, val); retval.valid= 0; goto STR_result_valid_0; /* ABORT */ } if (end == (char *)val) { DPRINTF(E_LOG, L_DAAP, "Value '%s' in clause '%s%s%c%s' does not represent an integer value\n", val, field, (neg_op) ? "!" : "", op, val); retval.valid= 0; goto STR_result_valid_0; /* ABORT */ } *end = '\0'; /* Cut out potential garbage - we're being kind */ } /* String field: escape string, check for '*' */ else { if (op != ':') { DPRINTF(E_LOG, L_DAAP, "Operation '%c' not valid for string values\n", op); retval.valid= 0; goto STR_result_valid_0; /* ABORT */ } escaped = (pANTLR3_UINT8)db_escape_string((char *)val); if (!escaped) { DPRINTF(E_LOG, L_DAAP, "Could not escape value\n"); retval.valid= 0; goto STR_result_valid_0; /* ABORT */ } val = escaped; if (val[0] == '*') { op = '%'; val[0] = '%'; } if (val[strlen((char *)val) - 1] == '*') { op = '%'; val[strlen((char *)val) - 1] = '%'; } } switch(op) { case ':': if (neg_op) retval.result->append8(retval.result, " <> "); else retval.result->append8(retval.result, " = "); break; case '+': if (neg_op) retval.result->append8(retval.result, " <= "); else retval.result->append8(retval.result, " > "); break; case '-': if (neg_op) retval.result->append8(retval.result, " >= "); else retval.result->append8(retval.result, " < "); break; case '%': retval.result->append8(retval.result, " LIKE "); break; default: if (neg_op) DPRINTF(E_LOG, L_DAAP, "Missing or unknown operator '%c' in clause '%s!%c%s'\n", op, field, op, val); else DPRINTF(E_LOG, L_DAAP, "Unknown operator '%c' in clause '%s%c%s'\n", op, field, op, val); retval.valid= 0; goto STR_result_valid_0; /* ABORT */ break; } if (!dqfm->as_int) retval.result->append8(retval.result, "'"); retval.result->append8(retval.result, (const char *)val); if (!dqfm->as_int) retval.result->append8(retval.result, "'"); /* For empty string value, we need to check against NULL too */ if ((*val == '\0') && (op == ':')) { if (neg_op) retval.result->append8(retval.result, " AND "); else retval.result->append8(retval.result, " OR "); retval.result->append8(retval.result, dqfm->db_col); if (neg_op) retval.result->append8(retval.result, " IS NOT NULL"); else retval.result->append8(retval.result, " IS NULL"); retval.result->append8(retval.result, ")"); } STR_result_valid_0: /* bail out label */ ; if (escaped) free(escaped); STR_out: /* get out of here */ ; } } break; } } } // This is where rules clean up and exit // goto ruleexprEx; /* Prevent compiler warnings */ ruleexprEx: ; if (HASEXCEPTION()) { PREPORTERROR(); PRECOVER(); } return retval; } /* $ANTLR end expr */ /* End of parsing rules * ============================================== */ /* ============================================== * Syntactic predicates */ /* End of syntactic predicates * ============================================== */ /* End of code * ============================================================================= */