diff --git a/INSTALL.md b/INSTALL.md
index bf60685e..88eacac0 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -19,11 +19,11 @@ libraries:
```bash
sudo apt-get install \
build-essential git autotools-dev autoconf automake libtool gettext gawk \
- gperf antlr3 libantlr3c-dev libconfuse-dev libunistring-dev libsqlite3-dev \
+ gperf libconfuse-dev libunistring-dev libsqlite3-dev libprotobuf-c-dev \
libavcodec-dev libavformat-dev libavfilter-dev libswscale-dev libavutil-dev \
libasound2-dev libmxml-dev libgcrypt20-dev libavahi-client-dev zlib1g-dev \
libevent-dev libplist-dev libsodium-dev libjson-c-dev libwebsockets-dev \
- libcurl4-openssl-dev libprotobuf-c-dev
+ libcurl4-openssl-dev
```
Note that OwnTone will also work with other versions and flavours of
@@ -83,7 +83,7 @@ sudo yum install \
sqlite-devel libconfuse-devel libunistring-devel mxml-devel libevent-devel \
avahi-devel libgcrypt-devel zlib-devel alsa-lib-devel ffmpeg-devel \
libplist-devel libsodium-devel json-c-devel libwebsockets-devel \
- libcurl-devel protobuf-c-devel antlr3 antlr3-C-devel
+ libcurl-devel protobuf-c-devel
```
Clone the OwnTone repo:
@@ -184,12 +184,6 @@ git clone https://github.com/owntone/owntone-server.git
cd owntone-server
```
-Install antlr3 and library using the included script:
-
-```bash
-scripts/antlr35_install.sh -p /usr/local
-```
-
Finally, configure, build and install, adding configure arguments for
optional features:
@@ -229,11 +223,6 @@ dns-sd -B _daap._tcp
Required tools:
-- ANTLR v3 is required to build OwnTone, along with its C runtime
- (libantlr3c). Use a version between 3.1.3 and 3.5 of ANTLR v3 and the
- matching C runtime version. Get it from
-- Java runtime: ANTLR is written in Java and as such a JRE is required to
- run the tool. The JRE is enough, you don't need a full JDK.
- autotools: autoconf 2.63+, automake 1.10+, libtool 2.2. Run `autoreconf -i`
at the top of the source tree to generate the build system.
- gettext: libunistring requires iconv and gettext provides the autotools
@@ -242,8 +231,6 @@ Required tools:
Libraries:
-- libantlr3c (ANTLR3 C runtime, use the same version as antlr3)
- from
- Avahi client libraries (avahi-client), 0.6.24 minimum
from
- sqlite3 3.5.0+ with unlock notify API enabled (read below)
@@ -297,22 +284,6 @@ documentation, look for `SQLITE_ENABLE_UNLOCK_NOTIFY`.
Start by generating the build system by running `autoreconf -i`. This will
generate the configure script and `Makefile.in`.
-The configure script will look for a wrapper called antlr3 in the PATH to
-invoke ANTLR3. If your installation of ANTLR3 does not come with such a
-wrapper, create one as follows:
-
-```bash
-#!/bin/sh
-CLASSPATH=...
-exec /path/to/java -cp $CLASSPATH org.antlr.Tool "$@"
-```
-
-Adjust the `CLASSPATH` as needed so that Java will find all the jars needed
-by ANTLR3.
-
-The parsers will be generated during the build, no manual intervention is
-needed.
-
To display the configure options `run ./configure --help`.
Support for Spotify is optional. Use `--disable-spotify` to disable this feature.
@@ -371,25 +342,6 @@ Use `--disable-install-systemd` if you don't want that.
Using `--enable-install-user` means that `make install` will also add a system
user and group for owntone.
-You may see two kinds of warnings during make.
-First, `/usr/bin/antlr3` may generate a long series of warnings that
-begin like this:
-
-```log
-warning(24): template error: context ...
-```
-
-Second, you may see compiler warnings that look like this:
-
-```log
-RSPLexer.c: In function `mESCAPED':
-RSPLexer.c:2674:16: warning: unused variable `_type' [-Wunused-variable]
- ANTLR3_UINT32 _type;
- ^~~~~
-```
-
-You can safely ignore all of these warnings.
-
After installation:
- edit the configuration file, `/etc/owntone.conf`
diff --git a/configure.ac b/configure.ac
index 4148e6bb..9aca3b9f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -27,22 +27,10 @@ AS_IF([[test -z "$GPERF"]],
AC_MSG_NOTICE([[
GNU gperf not found, but it's output appears to be present.
-If you modify any gperf or ANTLR grammar files (.g), you will need
-to install it.]])],
+If you modify any .gperf files, you will need to install it.]])],
[AC_MSG_ERROR([[GNU gperf required, please install it.]])])
])
-AC_PATH_PROG([ANTLR], [[antlr3]])
-AS_IF([[test -z "$ANTLR"]],
- [AS_IF([[test -f "$srcdir/src/SMARTPLLexer.h"]],
- [AM_MISSING_PROG([ANTLR], [[antlr3]])
- AC_MSG_NOTICE([[
-
-antlr3 not found, but it's output appears to be present.
-If you modify any ANTLR grammar files (.g), you will need to install it.]])],
- [AC_MSG_ERROR([[antlr3 wrapper required, please install it.]])])
- ])
-
dnl Enable all warnings by default.
AM_CPPFLAGS="-Wall"
AC_SUBST([AM_CPPFLAGS])
@@ -174,16 +162,6 @@ PKG_CHECK_EXISTS([libplist],
[OWNTONE_MODULES_CHECK([OWNTONE], [LIBPLIST], [libplist-2.0],
[plist_dict_get_item], [plist/plist.h])])
-
-OWNTONE_FUNC_REQUIRE([OWNTONE], [ANTLR3 C runtime], [ANTLR3C], [antlr3c],
- [antlr3BaseRecognizerNew], [antlr3.h],
- [AC_CHECK_FUNC([[antlr3NewAsciiStringInPlaceStream]],
- [AC_DEFINE([ANTLR3C_NEW_INPUT], 0,
- [define if antlr3 C runtime uses new input routines])],
- [AC_DEFINE([ANTLR3C_NEW_INPUT], 1,
- [define if antlr3 C runtime uses new input routines])])
- ])
-
AM_PATH_LIBGCRYPT([1:1.2.0])
OWNTONE_FUNC_REQUIRE([OWNTONE], [GNU Crypt Library], [LIBGCRYPT], [gcrypt],
[gcry_control], [gcrypt.h])
diff --git a/owntone.spec.in b/owntone.spec.in
index 02910919..5e0d9053 100644
--- a/owntone.spec.in
+++ b/owntone.spec.in
@@ -21,7 +21,7 @@ Source0: https://github.com/owntone/%{name}/archive/%{version}/%{name}-%{version
BuildRequires: gcc, make, systemd, pkgconfig, libunistring-devel
BuildRequires: pkgconfig(zlib), pkgconfig(libconfuse), pkgconfig(mxml)
BuildRequires: pkgconfig(sqlite3) >= 3.5.0, pkgconfig(libevent) >= 2.0.0
-BuildRequires: pkgconfig(json-c), antlr3-C-devel, libgcrypt-devel >= 1.2.0
+BuildRequires: pkgconfig(json-c), libgcrypt-devel >= 1.2.0
BuildRequires: libgpg-error-devel >= 1.6
BuildRequires: pkgconfig(libavformat), pkgconfig(libavcodec)
BuildRequires: pkgconfig(libswscale), pkgconfig(libavutil)
@@ -109,6 +109,9 @@ exit 0
%{_mandir}/man?/*
%changelog
+* Mon Jan 10 2022 Espen Jürgensen - 28.3-1
+ - Remove antlr dependency
+
* Mon Nov 22 2021 Derek Atkins - 28.2-1
- Release tarball is a XZ not GZ file
- Configure always needs protobuf-c, not just for chromecast
diff --git a/scripts/antlr35_install.sh b/scripts/antlr35_install.sh
deleted file mode 100755
index 00b0b839..00000000
--- a/scripts/antlr35_install.sh
+++ /dev/null
@@ -1,255 +0,0 @@
-#!/bin/sh
-
-WORKDIR=~/antlr35.tmp
-
-# programs
-MAKE=${MAKE-make}
-DOWNLOAD="wget --no-check-certificate"
-ALTDOWNLOAD="curl -LO"
-SUDO=sudo
-
-# source
-ANTLR_VERSION=3.5
-
-ANTLR3_SOURCE="https://github.com/antlr/website-antlr3/raw/gh-pages/download"
-ANTLR3_JAR="antlr-3.5.2-complete.jar"
-ANTLR3_URL="$ANTLR3_SOURCE/$ANTLR3_JAR"
-
-LIBANTLR3C="libantlr3c-3.4"
-LIBANTLR3C_SOURCE="https://github.com/antlr/website-antlr3/raw/gh-pages/download/C"
-LIBANTLR3C_TAR="${LIBANTLR3C}.tar.gz"
-LIBANTLR3C_URL="$LIBANTLR3C_SOURCE/$LIBANTLR3C_TAR"
-
-usage() {
- echo
- echo "This script will download, build and install antlr $ANTLR_VERSION"
- echo " (and matching libantlrc) on your computer."
- echo
- echo "Usage: ${0##*/} -h | [ -p ] [ -y ] [ ]"
- echo
- echo "Parameters:"
- echo " -h Show this help"
- echo " -p Install to prefix (default: choose /usr or /usr/local)"
- echo " -y Automatic yes to prompts (run non-interactively with -p)"
- echo " Build directory (default: $WORKDIR)"
- exit 0
-}
-
-GIVEN_PREFIX=
-ALWAYS_YES=
-while [ "$1" != "" ]; do
- case $1 in
- -p | --prefix )
- shift
- GIVEN_PREFIX=$1
- ;;
- -y | --yes )
- ALWAYS_YES=1
- ;;
- -h | --help )
- usage
- exit
- ;;
- * )
- echo "Unrecognized option $1 (try -h for usage)"
- exit 1
- ;;
- esac
- shift
-done
-
-# override build directory? (support ~ expansion)
-[ -n "$1" ] && WORKDIR=$1
-ORIG_DIR=`pwd`
-
-err() {
- echo "$*"
- if [ -n "$FILES_EXIST" ]; then
- echo "Files remain in $WORKDIR..."
- else
- cd "$ORIG_DIR"
- rmdir "$WORKDIR"
- fi
- exit 1
-}
-
-is_yes() {
- case "$1" in
- [N]*|[n]*) return 1;;
- *) ;;
- esac
- return 0
-}
-
-ask_yn() {
- if [ "$ALWAYS_YES" = "1" ]; then
- yn="y"
- else
- read -p "$1" yn
- fi
-}
-
-prog_install() {
- ask_yn "Would you like to install into $PREFIX now? [Y/n] "
- if ! is_yes "$yn"; then
- echo "Build left ready to install from $WORKDIR"
- echo "You can re-run the script (eg. as root) to install into"
- echo " $PREFIX later."
- exit
- fi
- if [ `id -u` -ne 0 ]; then
- ask_yn "Would you like to install with sudo? NOTE: You WILL be asked for your password! [Y/n] "
- if ! is_yes "$yn"; then
- SUDO=
- ask_yn "Continue to install as non-root user? [Y/n] "
- is_yes "$yn" || err "Install cancelled"
- fi
- else
- SUDO=
- fi
- cd $LIBANTLR3C || err "Unable to cd to build libantlr3c build directory!"
- echo "Installing libantlr3c to $PREFIX"
- $SUDO $MAKE install || err "Install of libantlr3c to $PREFIX failed!"
-
- cd "$ORIG_DIR"
- cd $WORKDIR
- echo "Installing antlr3 to $PREFIX"
- $SUDO mkdir -p "$PREFIX_JAVA" || err "Unable to create $PREFIX_JAVA"
- $SUDO install "$ANTLR3_JAR" "$PREFIX_JAVA" || \
- err "Failed to install antlr3 jar to $PREFIX_JAVA"
- $SUDO mkdir -p "$PREFIX/bin" || err "Unable to create $PREFIX/bin"
- $SUDO install -m 755 antlr3 "$PREFIX/bin" || \
- err "Failed to install antlr3 to $PREFIX/bin"
- echo "Install complete (build remains in $WORKDIR)"
-}
-
-echo "This script will download, build and install antlr $ANTLR_VERSION"
-echo " (and matching libantlrc) on your computer."
-echo
-
-# check if make works
-ISGNU=`$MAKE --version 2>/dev/null | grep "GNU Make"`
-if [ -z "$ISGNU" ]; then
- MAKE=gmake
- ISGNU=`$MAKE --version 2>/dev/null | grep "GNU Make"`
-fi
-[ -z "$ISGNU" ] && err "Unable to locate GNU Make, set \$MAKE to it's location and re-run"
-
-if [ -f "$WORKDIR/install_env" ]; then
- echo "Existing build found in $WORKDIR"
- FILES_EXIST=1
- cd $WORKDIR || err "Unable to cd to '$WORKDIR'"
- . install_env
- [ -n "$PREFIX" ] || err "PREFIX is missing in file 'install_env'"
- if [ -n "$GIVEN_PREFIX" ] && [ "$GIVEN_PREFIX" != "$PREFIX" ]; then
- echo "You must rebuild to install into $GIVEN_PREFIX (current build for $PREFIX)"
- ask_yn "Would you like to rebuild for ${GIVEN_PREFIX}? [Y/n] "
- if is_yes "$yn"; then
- rm -f install_env
- PREFIX=
- else
- ask_yn "Would you like to install to ${PREFIX}? [Y/n] "
- ! is_yes "$yn" && err "Install cancelled"
- fi
- fi
- if [ -n "$PREFIX" ]; then
- PREFIX_JAVA=$PREFIX/share/java
- prog_install
- exit 0
- fi
-fi
-
-if [ ! -d "$WORKDIR" ]; then
- ask_yn "Should the script create $WORKDIR and use it for building? [Y/n] "
- is_yes "$yn" || exit
-fi
-
-if [ -n "$GIVEN_PREFIX" ]; then
- PREFIX=$GIVEN_PREFIX
-else
- read -p "Should the script install with prefix /usr or /usr/local? [U/l] " yn
- if [ "$yn" = "l" ]; then
- PREFIX=/usr/local
- else
- PREFIX=/usr
- fi
-fi
-PREFIX_JAVA=$PREFIX/share/java
-
-MACHBITS=`getconf LONG_BIT 2>/dev/null`
-[ "$MACHBITS" = "64" ] && DEF_AN="[Y/n]" || DEF_AN="[y/N]"
-ask_yn "Should the script build libantlr3c for 64 bit? $DEF_AN "
-[ -z "$yn" -a "$MACHBITS" != "64" ] && yn=n
-is_yes "$yn" && ENABLE64BIT="--enable-64bit"
-
-mkdir -p "$WORKDIR" || err "Error creating $WORKDIR"
-# don't quote WORKDIR to catch a WORKDIR that will break the build (eg spaces)
-cd $WORKDIR || err "Unable to cd to '$WORKDIR' (does it include spaces?)"
-
-REMOVE_ON_CANCEL=
-cancel_download() {
- echo "removing $REMOVE_ON_CANCEL"
- [ -n "$REMOVE_ON_CANCEL" ] && rm -f "$REMOVE_ON_CANCEL"
- err "Cancelling download..."
-}
-
-antlr_download() {
- trap cancel_download SIGINT
- $DOWNLOAD --help >/dev/null 2>&1 || DOWNLOAD=$ALTDOWNLOAD
- $DOWNLOAD --help >/dev/null 2>&1 || {
- echo "Unable to find wget or curl commands to download source,"
- echo " please install either one and re-try."
- exit 1
- }
- [ "x$1" = "xreset" ] && rm "$ANTLR3_JAR" "$LIBANTLR3C_TAR"
- if [ ! -f "$ANTLR3_JAR" ]; then
- echo
- echo "Downloading antlr from $ANTLR3_URL"
- echo "Ctrl-C to abort..."
- REMOVE_ON_CANCEL=$ANTLR3_JAR
- $DOWNLOAD "$ANTLR3_URL" || err "Download of $ANTLR3_JAR failed!"
- FILES_EXIST=1
- fi
- if [ ! -f "$LIBANTLR3C_TAR" ]; then
- echo
- echo "Downloading libantlr3c from $LIBANTLR3C_URL"
- echo "Ctrl-C to abort..."
- REMOVE_ON_CANCEL=$LIBANTLR3C_TAR
- $DOWNLOAD "$LIBANTLR3C_URL" || err "Download of $LIBANTLR3C_TAR failed!"
- FILES_EXIST=1
- fi
- trap - SIGINT
-}
-
-# retrieve the source
-if [ -f "$ANTLR3_JAR" -a -f "$LIBANTLR3C_TAR" ]; then
- FILES_EXIST=1
- ask_yn "Files appear to already be downloaded, use them? [Y/n] "
- ! is_yes "$yn" && antlr_download reset
-else
- ask_yn "Should the script download and build antlr and libantlr3c? [Y/n] "
- is_yes "$yn" || exit
- antlr_download
-fi
-
-# build/install libantlr3c
-[ -d "$LIBANTLR3C" ] && rm -rf "$LIBANTLR3C"
-tar xzf "$LIBANTLR3C_TAR" || err "Uncompress of $LIBANTLR3C_TAR failed!"
-cd $LIBANTLR3C || err "Unable to cd to build $LIBANTLR3C build directory!"
-./configure $ENABLE64BIT --prefix=$PREFIX && $MAKE
-[ $? -ne 0 ] && err "Build of libantlr3c failed!"
-
-# install antlr3 jar and wrapper
-cd "$ORIG_DIR"
-cd $WORKDIR
-printf "#!/bin/sh
-export CLASSPATH
-CLASSPATH=\$CLASSPATH:$PREFIX_JAVA/${ANTLR3_JAR}:$PREFIX_JAVA
-/usr/bin/java org.antlr.Tool \$*
-" > antlr3
-
-# save for later install attempts
-echo "PREFIX=$PREFIX" > install_env
-echo
-
-prog_install
diff --git a/scripts/freebsd_install.sh b/scripts/freebsd_install.sh
index f569b692..2e79ed49 100644
--- a/scripts/freebsd_install.sh
+++ b/scripts/freebsd_install.sh
@@ -46,30 +46,6 @@ if [ ! -d $WORKDIR ]; then
fi
cd $WORKDIR
-read -p "Should the script install antlr and libantlr3c? [y/N] " yn
-if [ "$yn" = "y" ]; then
- read -p "Should the script build libantlr3c for 64 bit? [Y/n] " yn
- if [ "$yn" != "n" ]; then
- ENABLE64BIT="--enable-64bit"
- fi
-
- wget --no-check-certificate https://github.com/antlr/website-antlr3/raw/gh-pages/download/antlr-3.4-complete.jar
- wget --no-check-certificate https://github.com/antlr/website-antlr3/raw/gh-pages/download/C/libantlr3c-3.4.tar.gz
-
- sudo install antlr-3.4-complete.jar /usr/local/share/java
- printf "#!/bin/sh
-export CLASSPATH
-CLASSPATH=\$CLASSPATH:/usr/local/share/java/antlr-3.4-complete.jar:/usr/local/share/java
-/usr/local/bin/java org.antlr.Tool \$*
-" > antlr3
- sudo install -m 755 antlr3 /usr/local/bin
-
- tar xzf libantlr3c-3.4.tar.gz
- cd libantlr3c-3.4
- ./configure $ENABLE64BIT && gmake && sudo gmake install
- cd $WORKDIR
-fi
-
read -p "Should the script build owntone? [y/N] " yn
if [ "$yn" = "y" ]; then
git clone https://github.com/owntone/owntone-server.git
diff --git a/src/.gitignore b/src/.gitignore
index 2e610b18..4580a8b5 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,11 +1,5 @@
owntone
-*.tokens
-*Lexer.[ch]
-*Parser.[ch]
-*2SQL.[ch]
-*.u
-
daap_query_hash.h
rsp_query_hash.h
dacp_prop_hash.h
diff --git a/src/DAAP.g b/src/DAAP.g
deleted file mode 100644
index a6013d89..00000000
--- a/src/DAAP.g
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2009-2010 Julien BLACHE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-grammar DAAP;
-
-options {
- output = AST;
- ASTLabelType = pANTLR3_BASE_TREE;
- language = C;
-}
-
-query : expr NEWLINE? EOF -> expr
- ;
-
-expr : aexpr (OPOR^ aexpr)*
- ;
-
-aexpr : crit (OPAND^ crit)*
- ;
-
-crit : LPAR expr RPAR -> expr
- | STR
- ;
-
-QUOTE : '\'';
-LPAR : '(';
-RPAR : ')';
-
-OPAND : '+' | ' ';
-OPOR : ',';
-
-NEWLINE : '\r'? '\n';
-
-/*
-Unescaping adapted from (ported to the C runtime)
-
-*/
-STR
-@init{ pANTLR3_STRING unesc = GETTEXT()->factory->newRaw(GETTEXT()->factory); }
- : QUOTE ( reg = ~('\\' | '\'') { unesc->addc(unesc, reg); }
- | esc = ESCAPED { unesc->appendS(unesc, GETTEXT()); } )+ QUOTE { SETTEXT(unesc); };
-
-fragment
-ESCAPED : '\\'
- ( '\\' { SETTEXT(GETTEXT()->factory->newStr8(GETTEXT()->factory, (pANTLR3_UINT8)"\\")); }
- | '\'' { SETTEXT(GETTEXT()->factory->newStr8(GETTEXT()->factory, (pANTLR3_UINT8)"\'")); }
- )
- ;
diff --git a/src/DAAP2SQL.g b/src/DAAP2SQL.g
deleted file mode 100644
index 55364a1f..00000000
--- a/src/DAAP2SQL.g
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * Copyright (C) 2009-2011 Julien BLACHE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-tree grammar DAAP2SQL;
-
-options {
- tokenVocab = DAAP;
- ASTLabelType = pANTLR3_BASE_TREE;
- language = C;
-}
-
-@header {
- #include
- #include
- #include
- #include
- #include
-
- #include "logger.h"
- #include "db.h"
- #include "daap_query.h"
-}
-
-@members {
- struct dmap_query_field_map {
- char *dmap_field;
- char *db_col;
- int as_int;
- };
-
- /* gperf static hash, daap_query.gperf */
- #include "daap_query_hash.h"
-}
-
-query returns [ pANTLR3_STRING result ]
-@init { $result = NULL; }
- : e = expr
- {
- 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, ")");
- }
- }
- ;
-
-expr returns [ pANTLR3_STRING result, int valid ]
-@init { $result = NULL; $valid = 1; }
- : ^(OPAND a = expr b = expr)
- {
- if ($a.valid && $b.valid)
- {
- $result = $a.result->factory->newRaw($a.result->factory);
- $result->append8($result, "(");
- $result->appendS($result, $a.result);
- $result->append8($result, " AND ");
- $result->appendS($result, $b.result);
- $result->append8($result, ")");
- }
- else if ($a.valid)
- {
- $result = $a.result->factory->newRaw($a.result->factory);
- $result->appendS($result, $a.result);
- }
- else if ($b.valid)
- {
- $result = $b.result->factory->newRaw($b.result->factory);
- $result->appendS($result, $b.result);
- }
- else
- {
- $valid = 0;
- }
- }
- | ^(OPOR a = expr b = expr)
- {
- if ($a.valid && $b.valid)
- {
- $result = $a.result->factory->newRaw($a.result->factory);
- $result->append8($result, "(");
- $result->appendS($result, $a.result);
- $result->append8($result, " OR ");
- $result->appendS($result, $b.result);
- $result->append8($result, ")");
- }
- else if ($a.valid)
- {
- $result = $a.result->factory->newRaw($a.result->factory);
- $result->appendS($result, $a.result);
- }
- else if ($b.valid)
- {
- $result = $b.result->factory->newRaw($b.result->factory);
- $result->appendS($result, $b.result);
- }
- else
- {
- $valid = 0;
- }
- }
- | STR
- {
- 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;
-
- $result = $STR.text->factory->newRaw($STR.text->factory);
-
- str = $STR.text->toUTF8($STR.text);
-
- /* 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)
- {
- $result->append8($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);
- $valid = 0;
- goto STR_result_valid_0; /* ABORT */
- }
-
- if (*val == '\0')
- {
- DPRINTF(E_LOG, L_DAAP, "No operator found in clause '\%s'\n", field);
- $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);
- $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);
- $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);
- $valid = 0;
- goto STR_result_valid_0; /* ABORT */
- }
-
- /* No need to exclude empty artist and album, as the server makes sure there always exists an artist/album. */
- if (neg_op && (op == ':' || op == '@')
- && (strcmp((char *)field, "daap.songalbumartist") == 0
- || strcmp((char *)field, "daap.songartist") == 0
- || strcmp((char *)field, "daap.songalbum") == 0))
- {
- DPRINTF(E_DBG, L_DAAP, "Ignoring clause '\%s\%s\%c'\n", field, (neg_op) ? "!" : "", op);
- $valid = 0;
- goto STR_result_valid_0;
- }
-
- /* Need to check against NULL too */
- if (op == ':' || op == '@')
- $result->append8($result, "(");
- }
-
- /* Int field: check integer conversion */
- if (dqfm->as_int)
- {
- errno = 0;
- llval = strtoll((const char *)val, &end, 10);
-
- 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);
- $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);
- $valid = 0;
- goto STR_result_valid_0; /* ABORT */
- }
-
- *end = '\0'; /* Cut out potential garbage - we're being kind */
-
- /* The server only has media_kind = 1 for music - so remove media_kind = 32 to imporve select query performance. */
- if (llval == 32
- && (strcmp((char *)field, "com.apple.itunes.mediakind") == 0
- || strcmp((char *)field, "com.apple.itunes.extended-media-kind") == 0))
- {
- DPRINTF(E_DBG, L_DAAP, "Ignoring clause '\%s\%s\%c\%s'\n", field, (neg_op) ? "!" : "", op, val);
-
- if (neg_op)
- $result->append8($result, "1 = 1");
- else
- $result->append8($result, "1 = 0");
-
- goto STR_out;
- }
- }
- /* String field: escape string, check for '*' */
- else
- {
- /* With Apple Music 1.0.1.37, we observed some ':' queries using '@' instead, resulting in 'Unknown operator' errors */
- /* Ex: '/databases/1/containers?query=('com.apple.itunes.extended-media-kind@1', ...) */
- if (op != ':' && op != '@')
- {
- DPRINTF(E_LOG, L_DAAP, "Operation '\%c' not valid for string values\n", op);
- $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");
- $valid = 0;
- goto STR_result_valid_0; /* ABORT */
- }
-
- val = escaped;
-
- if (val[0] == '*')
- {
- op = '\%';
- val[0] = '\%';
- }
-
- if (val[0] && val[1] && val[strlen((char *)val) - 1] == '*')
- {
- op = '\%';
- val[strlen((char *)val) - 1] = '\%';
- }
- }
-
- $result->append8($result, dqfm->db_col);
-
- switch(op)
- {
- case '@':
- case ':':
- if (neg_op)
- $result->append8($result, " <> ");
- else
- $result->append8($result, " = ");
- break;
-
- case '+':
- if (neg_op)
- $result->append8($result, " <= ");
- else
- $result->append8($result, " > ");
- break;
-
- case '-':
- if (neg_op)
- $result->append8($result, " >= ");
- else
- $result->append8($result, " < ");
- break;
-
- case '\%':
- $result->append8($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);
- $valid = 0;
- goto STR_result_valid_0; /* ABORT */
- break;
- }
-
- if (!dqfm->as_int)
- $result->append8($result, "'");
-
- $result->append8($result, (const char *)val);
-
- if (!dqfm->as_int)
- $result->append8($result, "'");
-
- /* For empty string value, we need to check against NULL too */
- if ((*val == '\0') && (op == ':' || op == '@'))
- {
- if (neg_op)
- $result->append8($result, " AND ");
- else
- $result->append8($result, " OR ");
-
- $result->append8($result, dqfm->db_col);
-
- if (neg_op)
- $result->append8($result, " IS NOT NULL");
- else
- $result->append8($result, " IS NULL");
-
- $result->append8($result, ")");
- }
-
- STR_result_valid_0: /* bail out label */
- ;
-
- if (escaped)
- free(escaped);
-
- STR_out: /* get out of here */
- ;
- }
- ;
diff --git a/src/Makefile.am b/src/Makefile.am
index 10afdffa..bc1962ef 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -62,28 +62,6 @@ GPERF_FILES = \
GPERF_SRC = $(GPERF_FILES:.gperf=_hash.h)
-ANTLR_GRAMMARS = \
- RSP.g RSP2SQL.g \
- DAAP.g DAAP2SQL.g \
- SMARTPL.g SMARTPL2SQL.g
-
-ANTLR_TOKENS = $(ANTLR_GRAMMARS:.g=.tokens)
-
-ANTLR_DEPS = $(ANTLR_GRAMMARS:%.g=$(srcdir)/%.u)
-
-ANTLR_SRC = \
- RSPLexer.c RSPLexer.h RSPParser.c RSPParser.h \
- RSP2SQL.c RSP2SQL.h \
- DAAPLexer.c DAAPLexer.h DAAPParser.c DAAPParser.h \
- DAAP2SQL.c DAAP2SQL.h \
- SMARTPLLexer.c SMARTPLLexer.h SMARTPLParser.c SMARTPLParser.h \
- SMARTPL2SQL.c SMARTPL2SQL.h
-
-ANTLR_OBJECTS = \
- RSPLexer.$(OBJEXT) RSPParser.$(OBJEXT) RSP2SQL.$(OBJEXT) \
- DAAPLexer.$(OBJEXT) DAAPParser.$(OBJEXT) DAAP2SQL.$(OBJEXT) \
- SMARTPLLexer.$(OBJEXT) SMARTPLParser.$(OBJEXT) SMARTPL2SQL.$(OBJEXT)
-
AM_CPPFLAGS += \
$(OWNTONE_CPPFLAGS) \
$(OWNTONE_OPTS_CPPFLAGS) \
@@ -152,42 +130,16 @@ owntone_SOURCES = main.c \
mxml-compat.h \
outputs/plist_wrap.h \
$(LIBWEBSOCKETS_SRC) \
- $(GPERF_SRC) \
- $(ANTLR_SRC)
+ $(GPERF_SRC)
# built by maintainers, and distributed. Clean with maintainer-clean
BUILT_SOURCES = \
- $(GPERF_SRC) \
- $(ANTLR_SRC) \
- $(ANTLR_TOKENS) \
- $(ANTLR_DEPS)
+ $(GPERF_SRC)
EXTRA_DIST = \
- $(GPERF_FILES) \
- $(ANTLR_GRAMMARS) \
- $(ANTLR_TOKENS) \
- $(ANTLR_DEPS)
-
-# silence unused warnings from antlr generated files
-$(ANTLR_OBJECTS): AM_CPPFLAGS += -Wno-unused
+ $(GPERF_FILES)
# gperf construction rules
%_hash.h: %.gperf
$(AM_V_GEN)$(GPERF) --output-file=$@ $<
-# silent rules for antlr
-antlr_verbose = $(antlr_verbose_@AM_V@)
-antlr_verbose_ = $(antlr_verbose_@AM_DEFAULT_V@)
-antlr_verbose_0 = @echo " GEN " $< "products";
-
-# ANTLR grammar products
-%.tokens %.c %Lexer.c %Parser.c %Lexer.h %Parser.h %.h: %.g
- $(antlr_verbose)$(ANTLR) -Xconversiontimeout 30000 $(ANTLR_OPTIONS) -fo . $<
-
-# ANTLR dependency files (bypass circular dependency of .g on .tokens)
-%.u: %.g
- $(AM_V_GEN)$(ANTLR) -depend -fo . $< > $@
- $(AM_V_at)$(SED) -n -e '/^.*\.g[ ]*:\(.*\)/ { s//\1/;h;d; }' -e '/\.tokens.*:/ { p;d; }' -e '/:/ { G;s/\n/ /;p; }' $@ > $@-t
- $(AM_V_at)mv $@-t $@
-
--include $(ANTLR_DEPS)
diff --git a/src/RSP.g b/src/RSP.g
deleted file mode 100644
index 6a27536c..00000000
--- a/src/RSP.g
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2009-2010 Julien BLACHE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-grammar RSP;
-
-options {
- output = AST;
- ASTLabelType = pANTLR3_BASE_TREE;
- language = C;
-}
-
-query : expr NEWLINE? EOF -> expr
- ;
-
-expr : aexpr (OR^ aexpr)*
- ;
-
-aexpr : crit (AND^ crit)*
- ;
-
-crit : LPAR expr RPAR -> expr
- | strcrit
- | intcrit
- | datecrit
- ;
-
-strcrit : FIELD strop STR -> ^(strop FIELD STR)
- | FIELD NOT strop STR -> ^(NOT ^(strop FIELD STR))
- ;
-
-strop : equal=EQUAL
- | includes=INCLUDES
- | startsw=STARTSW
- | endsw=ENDSW
- ;
-
-intcrit : FIELD intop INT -> ^(intop FIELD INT)
- | FIELD NOT intop INT -> ^(NOT ^(intop FIELD INT))
- ;
-
-intop : equal=EQUAL
- | less=LESS
- | greater=GREATER
- | lte=LTE
- | gte=GTE
- ;
-
-datecrit: FIELD dateop datespec -> ^(dateop FIELD datespec)
- ;
-
-dateop : before=BEFORE
- | after=AFTER
- ;
-
-datespec: dateref
- | INT dateintval dateop dateref -> ^(dateop dateref INT dateintval)
- ;
-
-dateref : date=DATE
- | today=TODAY
- ;
-
-dateintval
- : day=DAY
- | week=WEEK
- | month=MONTH
- | year=YEAR
- ;
-
-QUOTE : '"';
-LPAR : '(';
-RPAR : ')';
-
-AND : 'and';
-OR : 'or';
-NOT : '!';
-
-/* Both string & int */
-EQUAL : '=';
-
-/* String */
-INCLUDES: 'includes';
-STARTSW : 'startswith';
-ENDSW : 'endswith';
-
-/* Int */
-GREATER : '>';
-LESS : '<';
-GTE : '>=';
-LTE : '<=';
-
-/* Date */
-BEFORE : 'before';
-AFTER : 'after';
-DAY : 'day' | 'days';
-WEEK : 'week' | 'weeks';
-MONTH : 'month' | 'months';
-YEAR : 'year' | 'years';
-TODAY : 'today';
-
-NEWLINE : '\r'? '\n';
-
-WS : (' ' | '\t') { $channel = HIDDEN; };
-
-FIELD : 'a'..'z' ('a'..'z' | '_')* 'a'..'z';
-
-INT : DIGIT19 DIGIT09*;
-
-/* YYYY-MM-DD */
-DATE : DIGIT19 DIGIT09 DIGIT09 DIGIT09 '-' ('0' DIGIT19 | '1' '0'..'2') '-' ('0' DIGIT19 | '1'..'2' DIGIT09 | '3' '0'..'1');
-
-/*
-Unescaping adapted from (ported to the C runtime)
-
-*/
-STR
-@init{ pANTLR3_STRING unesc = GETTEXT()->factory->newRaw(GETTEXT()->factory); }
- : QUOTE ( reg = ~('\\' | '"') { unesc->addc(unesc, reg); }
- | esc = ESCAPED { unesc->appendS(unesc, GETTEXT()); } )+ QUOTE { SETTEXT(unesc); }
- ;
-
-fragment
-ESCAPED : '\\'
- ( '\\' { SETTEXT(GETTEXT()->factory->newStr8(GETTEXT()->factory, (pANTLR3_UINT8)"\\")); }
- | '"' { SETTEXT(GETTEXT()->factory->newStr8(GETTEXT()->factory, (pANTLR3_UINT8)"\"")); }
- )
- ;
-
-fragment
-DIGIT09 : '0'..'9';
-
-fragment
-DIGIT19 : '1'..'9';
diff --git a/src/RSP2SQL.g b/src/RSP2SQL.g
deleted file mode 100644
index 78c67593..00000000
--- a/src/RSP2SQL.g
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright (C) 2009-2011 Julien BLACHE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-tree grammar RSP2SQL;
-
-options {
- tokenVocab = RSP;
- ASTLabelType = pANTLR3_BASE_TREE;
- language = C;
-}
-
-@header {
- /* Needs #define _GNU_SOURCE for strptime() */
-
- #include
- #include
- #include
- #include
-
- #include "logger.h"
- #include "db.h"
- #include "misc.h"
- #include "rsp_query.h"
-}
-
-@members {
- #define RSP_TYPE_STRING 0
- #define RSP_TYPE_INT 1
- #define RSP_TYPE_DATE 2
-
- struct rsp_query_field_map {
- char *rsp_field;
- int field_type;
- /* RSP fields are named after the DB columns - or vice versa */
- };
-
- /* gperf static hash, rsp_query.gperf */
- #include "rsp_query_hash.h"
-}
-
-query returns [ pANTLR3_STRING result ]
-@init { $result = NULL; }
- : e = expr
- {
- 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, ")");
- }
- }
- ;
-
-expr returns [ pANTLR3_STRING result, int valid ]
-@init { $result = NULL; $valid = 1; }
- : ^(AND a = expr b = expr)
- {
- if (!$a.valid || !$b.valid)
- {
- $valid = 0;
- }
- else
- {
- $result = $a.result->factory->newRaw($a.result->factory);
- $result->append8($result, "(");
- $result->appendS($result, $a.result);
- $result->append8($result, " AND ");
- $result->appendS($result, $b.result);
- $result->append8($result, ")");
- }
- }
- | ^(OR a = expr b = expr)
- {
- if (!$a.valid || !$b.valid)
- {
- $valid = 0;
- }
- else
- {
- $result = $a.result->factory->newRaw($a.result->factory);
- $result->append8($result, "(");
- $result->appendS($result, $a.result);
- $result->append8($result, " OR ");
- $result->appendS($result, $b.result);
- $result->append8($result, ")");
- }
- }
- | c = strcrit
- {
- $valid = $c.valid;
- $result = $c.result;
- }
- | ^(NOT c = strcrit)
- {
- if (!$c.valid || !$c.result)
- {
- $valid = 0;
- }
- else
- {
- $result = $c.result->factory->newRaw($c.result->factory);
- $result->append8($result, "(NOT ");
- $result->appendS($result, $c.result);
- $result->append8($result, ")");
- }
- }
- | i = intcrit
- {
- $valid = $i.valid;
- $result = $i.result;
- }
- | ^(NOT i = intcrit)
- {
- if (!$i.valid || !$i.result)
- {
- $valid = 0;
- }
- else
- {
- $result = $i.result->factory->newRaw($i.result->factory);
- $result->append8($result, "(NOT ");
- $result->appendS($result, $i.result);
- $result->append8($result, ")");
- }
- }
- | d = datecrit
- {
- $valid = $d.valid;
- $result = $d.result;
- }
- ;
-
-strcrit returns [ pANTLR3_STRING result, int valid ]
-@init { $result = NULL; $valid = 1; }
- : ^(o = strop f = FIELD s = STR)
- {
- char *op;
- const struct rsp_query_field_map *rqfp;
- pANTLR3_STRING field;
- char *escaped;
- ANTLR3_UINT32 optok;
-
- escaped = NULL;
-
- op = NULL;
- optok = $o.op->getType($o.op);
- switch (optok)
- {
- case EQUAL:
- op = " = ";
- break;
-
- case INCLUDES:
- case STARTSW:
- case ENDSW:
- op = " LIKE ";
- break;
- }
-
- field = $f->getText($f);
-
- /* Field lookup */
- rqfp = rsp_query_field_lookup((char *)field->chars, strlen((char *)field->chars));
- if (!rqfp)
- {
- DPRINTF(E_LOG, L_RSP, "Field '\%s' is not a valid field in queries\n", field->chars);
- $valid = 0;
- goto strcrit_valid_0; /* ABORT */
- }
-
- /* Check field type */
- if (rqfp->field_type != RSP_TYPE_STRING)
- {
- DPRINTF(E_LOG, L_RSP, "Field '\%s' is not a string field\n", field->chars);
- $valid = 0;
- goto strcrit_valid_0; /* ABORT */
- }
-
- escaped = db_escape_string((char *)$s->getText($s)->chars);
- if (!escaped)
- {
- DPRINTF(E_LOG, L_RSP, "Could not escape value\n");
- $valid = 0;
- goto strcrit_valid_0; /* ABORT */
- }
-
- $result = field->factory->newRaw(field->factory);
- $result->append8($result, "f.");
- $result->appendS($result, field);
- $result->append8($result, op);
- $result->append8($result, "'");
- if ((optok == INCLUDES) || (optok == STARTSW))
- $result->append8($result, "\%");
-
- $result->append8($result, escaped);
-
- if ((optok == INCLUDES) || (optok == ENDSW))
- $result->append8($result, "\%");
- $result->append8($result, "'");
-
- strcrit_valid_0:
- ;
-
- if (escaped)
- free(escaped);
- }
- ;
-
-strop returns [ pANTLR3_COMMON_TOKEN op ]
-@init { $op = NULL; }
- : n = EQUAL
- { $op = $n->getToken($n); }
- | n = INCLUDES
- { $op = $n->getToken($n); }
- | n = STARTSW
- { $op = $n->getToken($n); }
- | n = ENDSW
- { $op = $n->getToken($n); }
- ;
-
-intcrit returns [ pANTLR3_STRING result, int valid ]
-@init { $result = NULL; $valid = 1; }
- : ^(o = intop f = FIELD i = INT)
- {
- char *op;
- const struct rsp_query_field_map *rqfp;
- pANTLR3_STRING field;
-
- op = NULL;
- switch ($o.op->getType($o.op))
- {
- case EQUAL:
- op = " = ";
- break;
-
- case LESS:
- op = " < ";
- break;
-
- case GREATER:
- op = " > ";
- break;
-
- case LTE:
- op = " <= ";
- break;
-
- case GTE:
- op = " >= ";
- break;
- }
-
- field = $f->getText($f);
-
- /* Field lookup */
- rqfp = rsp_query_field_lookup((char *)field->chars, strlen((char *)field->chars));
- if (!rqfp)
- {
- DPRINTF(E_LOG, L_RSP, "Field '\%s' is not a valid field in queries\n", field->chars);
- $valid = 0;
- goto intcrit_valid_0; /* ABORT */
- }
-
- /* Check field type */
- if (rqfp->field_type != RSP_TYPE_INT)
- {
- DPRINTF(E_LOG, L_RSP, "Field '\%s' is not an integer field\n", field->chars);
- $valid = 0;
- goto intcrit_valid_0; /* ABORT */
- }
-
- $result = field->factory->newRaw(field->factory);
- $result->append8($result, "f.");
- $result->appendS($result, field);
- $result->append8($result, op);
- $result->appendS($result, $i->getText($i));
-
- intcrit_valid_0:
- ;
- }
- ;
-
-intop returns [ pANTLR3_COMMON_TOKEN op ]
-@init { $op = NULL; }
- : n = EQUAL
- { $op = $n->getToken($n); }
- | n = LESS
- { $op = $n->getToken($n); }
- | n = GREATER
- { $op = $n->getToken($n); }
- | n = LTE
- { $op = $n->getToken($n); }
- | n = GTE
- { $op = $n->getToken($n); }
- ;
-
-datecrit returns [ pANTLR3_STRING result, int valid ]
-@init { $result = NULL; $valid = 1; }
- : ^(o = dateop f = FIELD d = datespec)
- {
- char *op;
- const struct rsp_query_field_map *rqfp;
- pANTLR3_STRING field;
- char buf[32];
- int ret;
-
- op = NULL;
- switch ($o.op->getType($o.op))
- {
- case BEFORE:
- op = " < ";
- break;
-
- case AFTER:
- op = " > ";
- break;
- }
-
- field = $f->getText($f);
-
- /* Field lookup */
- rqfp = rsp_query_field_lookup((char *)field->chars, strlen((char *)field->chars));
- if (!rqfp)
- {
- DPRINTF(E_LOG, L_RSP, "Field '\%s' is not a valid field in queries\n", field->chars);
- $valid = 0;
- goto datecrit_valid_0; /* ABORT */
- }
-
- /* Check field type */
- if (rqfp->field_type != RSP_TYPE_DATE)
- {
- DPRINTF(E_LOG, L_RSP, "Field '\%s' is not a date field\n", field->chars);
- $valid = 0;
- goto datecrit_valid_0; /* ABORT */
- }
-
- ret = snprintf(buf, sizeof(buf), "\%ld", $d.date);
- if ((ret < 0) || (ret >= sizeof(buf)))
- {
- DPRINTF(E_LOG, L_RSP, "Date \%ld too large for buffer, oops!\n", $d.date);
- $valid = 0;
- goto datecrit_valid_0; /* ABORT */
- }
-
- $result = field->factory->newRaw(field->factory);
- $result->append8($result, "f.");
- $result->appendS($result, field);
- $result->append8($result, op);
- $result->append8($result, buf);
-
- datecrit_valid_0:
- ;
- }
- ;
-
-dateop returns [ pANTLR3_COMMON_TOKEN op ]
-@init { $op = NULL; }
- : n = BEFORE
- { $op = $n->getToken($n); }
- | n = AFTER
- { $op = $n->getToken($n); }
- ;
-
-datespec returns [ time_t date, int valid ]
-@init { $date = 0; $valid = 1; }
- : r = dateref
- {
- if (!$r.valid)
- $valid = 0;
- else
- $date = $r.date;
- }
- | ^(o = dateop r = dateref m = INT i = dateintval)
- {
- int32_t val;
- int ret;
-
- if (!$r.valid || !$i.valid)
- {
- $valid = 0;
- goto datespec_valid_0; /* ABORT */
- }
-
- ret = safe_atoi32((char *)$m->getText($m)->chars, &val);
- if (ret < 0)
- {
- DPRINTF(E_LOG, L_RSP, "Could not convert '\%s' to integer\n", (char *)$m->getText($m));
- $valid = 0;
- goto datespec_valid_0; /* ABORT */
- }
-
- switch ($o.op->getType($o.op))
- {
- case BEFORE:
- $date = $r.date - (val * $i.period);
- break;
-
- case AFTER:
- $date = $r.date + (val * $i.period);
- break;
- }
-
- datespec_valid_0:
- ;
- }
- ;
-
-dateref returns [ time_t date, int valid ]
-@init { $date = 0; $valid = 1; }
- : n = DATE
- {
- struct tm tm;
- char *ret;
-
- ret = strptime((char *)$n->getText($n), "\%Y-\%m-\%d", &tm);
- if (!ret)
- {
- DPRINTF(E_LOG, L_RSP, "Date '\%s' could not be interpreted\n", (char *)$n->getText($n));
- $valid = 0;
- goto dateref_valid_0; /* ABORT */
- }
- else
- {
- if (*ret != '\0')
- DPRINTF(E_LOG, L_RSP, "Garbage at end of date '\%s' ?!\n", (char *)$n->getText($n));
-
- $date = mktime(&tm);
- if ($date == (time_t) -1)
- {
- DPRINTF(E_LOG, L_RSP, "Date '\%s' could not be converted to an epoch\n", (char *)$n->getText($n));
- $valid = 0;
- goto dateref_valid_0; /* ABORT */
- }
- }
-
- dateref_valid_0:
- ;
- }
- | TODAY
- { $date = time(NULL); }
- ;
-
-dateintval returns [ time_t period, int valid ]
-@init { $period = 0; $valid = 1; }
- : DAY
- { $period = 24 * 60 * 60; }
- | WEEK
- { $period = 7 * 24 * 60 * 60; }
- | MONTH
- { $period = 30 * 24 * 60 * 60; }
- | YEAR
- { $period = 365 * 24 * 60 * 60; }
- ;
diff --git a/src/SMARTPL.g b/src/SMARTPL.g
deleted file mode 100644
index 9275145c..00000000
--- a/src/SMARTPL.g
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2015 Christian Meffert
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-grammar SMARTPL;
-
-options {
- output = AST;
- ASTLabelType = pANTLR3_BASE_TREE;
- language = C;
-}
-
-playlist : STR '{' expression '}' EOF
- ;
-
-expression : aexpr (OR^ aexpr)* (HAVING^ aexpr)? (ORDERBY^ orderexpr)? (LIMIT^ limitexpr)?
- ;
-
-orderexpr : ordertag SORTDIR
- ;
-
-ordertag : STRTAG
- | INTTAG
- | DATETAG
- | ENUMTAG
- | RANDOMTAG
- | (XXX)? NeverUsedRule
- ;
-
-NeverUsedRule: /* antlr3 seems to have a problem with ordertag, introducing the NeverUsedRule fixes it. See: https://stackoverflow.com/questions/20057063/follow-set-in-is-undefined-in-generated-parser */
- ;
-
-XXX : 'XXX' /**/
- ;
-
-limitexpr : INT
- ;
-
-aexpr : nexpr (AND^ nexpr)*
- ;
-
-nexpr : NOT^ crit
- | crit
- ;
-
-crit : LPAR expression RPAR -> expression
- | STRTAG (INCLUDES|IS|STARTSWITH) STR
- | INTTAG INTBOOL INT
- | DATETAG (AFTER|BEFORE) dateval
- | ENUMTAG IS ENUMVAL
- | GROUPTAG INTBOOL INT
- ;
-
-dateval : DATE
- | interval BEFORE DATE
- | interval AFTER DATE
- | interval AGO
- ;
-
-interval : INT DATINTERVAL
- ;
-
-STRTAG : 'artist'
- | 'album_artist'
- | 'album'
- | 'title'
- | 'genre'
- | 'composer'
- | 'path'
- | 'type'
- | 'grouping'
- | 'artist_id'
- | 'album_id'
- | 'songartistid'
- | 'songalbumid'
- | 'codectype'
- | 'comment'
- ;
-
-INTTAG : 'play_count'
- | 'skip_count'
- | 'rating'
- | 'year'
- | 'compilation'
- | 'track'
- | 'disc'
- | 'bitrate'
- | 'bits_per_sample'
- | 'samplerate'
- | 'song_length'
- | 'usermark'
- ;
-
-DATETAG : 'time_added'
- | 'time_modified'
- | 'time_played'
- | 'time_skipped'
- | 'date_released'
- ;
-
-ENUMTAG : 'data_kind'
- | 'media_kind'
- | 'scan_kind'
- ;
-
-GROUPTAG : 'track_count'
- | 'album_count'
- ;
-
-RANDOMTAG : 'random'
- ;
-
-INCLUDES : 'includes'
- ;
-
-IS : 'is'
- ;
-
-STARTSWITH : 'starts with'
- ;
-
-INTBOOL : (GREATER|GREATEREQUAL|LESS|LESSEQUAL|EQUAL)
- ;
-
-fragment
-GREATER : '>'
- ;
-
-fragment
-GREATEREQUAL: '>='
- ;
-
-fragment
-LESS : '<'
- ;
-
-fragment
-LESSEQUAL : '<='
- ;
-
-fragment
-EQUAL : '='
- ;
-
-AFTER : 'after'
- ;
-
-BEFORE : 'before'
- ;
-
-AGO : 'ago'
- ;
-
-AND : 'AND'
- | 'and'
- ;
-
-OR : 'OR'
- | 'or'
- ;
-
-NOT : 'NOT'
- | 'not'
- ;
-
-LPAR : '('
- ;
-
-RPAR : ')'
- ;
-
-DATE : ('0'..'9')('0'..'9')('0'..'9')('0'..'9')'-'('0'..'1')('0'..'9')'-'('0'..'3')('0'..'9')
- | 'today'
- | 'yesterday'
- | 'last week'
- | 'last month'
- | 'last year'
- ;
-
-DATINTERVAL : 'days'
- | 'weeks'
- | 'months'
- | 'years'
- ;
-
-ENUMVAL : 'music'
- | 'movie'
- | 'podcast'
- | 'audiobook'
- | 'tvshow'
- | 'file'
- | 'url'
- | 'spotify'
- | 'pipe'
- | 'files'
- | 'rss'
- ;
-
-ORDERBY : 'order by'
- | 'ORDER BY'
- ;
-
-SORTDIR : 'asc'
- | 'ASC'
- | 'desc'
- | 'DESC'
- ;
-
-LIMIT : 'limit'
- | 'LIMIT'
- ;
-
-HAVING : 'having'
- | 'HAVING'
- ;
-
-STR : '"' ~('"')+ '"'
- ;
-
-INT : ('0'..'9')+
- ;
-
-WHITESPACE : ('\t'|' '|'\r'|'\n'|'\u000C') { $channel = HIDDEN; }
- ;
-
-
diff --git a/src/SMARTPL2SQL.g b/src/SMARTPL2SQL.g
deleted file mode 100644
index 1a763364..00000000
--- a/src/SMARTPL2SQL.g
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * Copyright (C) 2015 Christian Meffert
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-tree grammar SMARTPL2SQL;
-
-options {
- tokenVocab = SMARTPL;
- ASTLabelType = pANTLR3_BASE_TREE;
- language = C;
-}
-
-@header {
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #include "logger.h"
- #include "db.h"
-}
-
-@members {
- static void append_date(pANTLR3_STRING result, const char *datval, char beforeorafter, const char *interval)
- {
- if (strcmp((char *)datval, "today") == 0)
- {
- result->append8(result, "strftime('\%s', datetime('now', 'start of day'");
- }
- else if (strcmp((char *)datval, "yesterday") == 0)
- {
- result->append8(result, "strftime('\%s', datetime('now', 'start of day', '-1 day'");
- }
- else if (strcmp((char *)datval, "last week") == 0)
- {
- result->append8(result, "strftime('\%s', datetime('now', 'start of day', 'weekday 0', '-13 days'");
- }
- else if (strcmp((char *)datval, "last month") == 0)
- {
- result->append8(result, "strftime('\%s', datetime('now', 'start of month', '-1 month'");
- }
- else if (strcmp((char *)datval, "last year") == 0)
- {
- result->append8(result, "strftime('\%s', datetime('now', 'start of year', '-1 year'");
- }
- else
- {
- result->append8(result, "strftime('\%s', datetime(\'");
- result->append8(result, datval);
- result->append8(result, "\'");
- }
-
- if (beforeorafter)
- {
- result->append8(result, ", '");
- result->addc(result, beforeorafter);
- result->append8(result, interval);
- result->addc(result, '\'');
- }
- result->append8(result, ", 'utc'))");
- }
-}
-
-playlist returns [ pANTLR3_STRING title, pANTLR3_STRING query, pANTLR3_STRING orderby, pANTLR3_STRING having, int limit ]
-@init { $title = NULL; $query = NULL; $orderby = NULL; $having = NULL; $limit = -1; }
- : STR '{' e = expression '}'
- {
- pANTLR3_UINT8 val;
- val = $STR.text->toUTF8($STR.text)->chars;
- val++;
- val[strlen((const char *)val) - 1] = '\0';
-
- $title = $STR.text->factory->newRaw($STR.text->factory);
- $title->append8($title, (const char *)val);
-
- $query = $e.result->factory->newRaw($e.result->factory);
- $query->append8($query, "(");
- $query->appendS($query, $e.result);
- $query->append8($query, ")");
-
- $limit = $e.limit;
-
- $orderby = $e.result->factory->newRaw($e.result->factory);
- $orderby->appendS($orderby, $e.orderby);
-
- $having = $e.result->factory->newRaw($e.result->factory);
- $having->appendS($having, $e.having);
- }
- ;
-
-expression returns [ pANTLR3_STRING result, pANTLR3_STRING orderby, pANTLR3_STRING having, int limit ]
-@init { $result = NULL; $orderby = NULL; $having = NULL; $limit = -1; }
- : ^(LIMIT a = expression INT)
- {
- $result = $a.result->factory->newRaw($a.result->factory);
- $result->appendS($result, $a.result);
-
- $having = $a.result->factory->newRaw($a.result->factory);
- $having->appendS($having, $a.having);
-
- $orderby = $a.result->factory->newRaw($a.result->factory);
- $orderby->appendS($orderby, $a.orderby);
-
- $limit = atoi((const char *)$INT.text->chars);
- }
- | ^(ORDERBY a = expression o = ordertag SORTDIR)
- {
- $result = $a.result->factory->newRaw($a.result->factory);
- $result->appendS($result, $a.result);
-
- $having = $a.result->factory->newRaw($a.result->factory);
- $having->appendS($having, $a.having);
-
- $orderby = $o.result->factory->newRaw($o.result->factory);
- $orderby->appendS($orderby, $o.result);
- $orderby->append8($orderby, " ");
- $orderby->appendS($orderby, $SORTDIR.text->toUTF8($SORTDIR.text));
- }
- | ^(HAVING a = expression b = expression)
- {
- $result = $a.result->factory->newRaw($a.result->factory);
- $result->appendS($result, $a.result);
-
- $having = $b.result->factory->newRaw($b.result->factory);
- $having->appendS($having, $b.result);
- }
- | ^(NOT a = expression)
- {
- $result = $a.result->factory->newRaw($a.result->factory);
- $result->append8($result, "NOT(");
- $result->appendS($result, $a.result);
- $result->append8($result, ")");
- }
- | ^(AND a = expression b = expression)
- {
- $result = $a.result->factory->newRaw($a.result->factory);
- $result->append8($result, "(");
- $result->appendS($result, $a.result);
- $result->append8($result, " AND ");
- $result->appendS($result, $b.result);
- $result->append8($result, ")");
- }
- | ^(OR a = expression b = expression)
- {
- $result = $a.result->factory->newRaw($a.result->factory);
- $result->append8($result, "(");
- $result->appendS($result, $a.result);
- $result->append8($result, " OR ");
- $result->appendS($result, $b.result);
- $result->append8($result, ")");
- }
- | STRTAG INCLUDES STR
- {
- pANTLR3_UINT8 val;
- char *tmp;
-
- val = $STR.text->toUTF8($STR.text)->chars;
- val++;
- val[strlen((const char *)val) - 1] = '\0';
-
- tmp = sqlite3_mprintf("\%q", (const char *)val);
-
- $result = $STR.text->factory->newRaw($STR.text->factory);
- $result->append8($result, "f.");
- $result->appendS($result, $STRTAG.text->toUTF8($STRTAG.text));
- $result->append8($result, " LIKE '\%");
- $result->append8($result, tmp);
- $result->append8($result, "\%'");
-
- sqlite3_free(tmp);
- }
- | STRTAG IS STR
- {
- pANTLR3_UINT8 val;
- char *tmp;
-
- val = $STR.text->toUTF8($STR.text)->chars;
- val++;
- val[strlen((const char *)val) - 1] = '\0';
-
- tmp = sqlite3_mprintf("\%q", (const char *)val);
-
- $result = $STR.text->factory->newRaw($STR.text->factory);
- $result->append8($result, "f.");
- $result->appendS($result, $STRTAG.text->toUTF8($STRTAG.text));
- $result->append8($result, " LIKE '");
- $result->append8($result, tmp);
- $result->append8($result, "'");
-
- sqlite3_free(tmp);
- }
- | STRTAG STARTSWITH STR
- {
- pANTLR3_UINT8 val;
- char *tmp;
-
- val = $STR.text->toUTF8($STR.text)->chars;
- val++;
- val[strlen((const char *)val) - 1] = '\0';
-
- tmp = sqlite3_mprintf("\%q", (const char *)val);
-
- $result = $STR.text->factory->newRaw($STR.text->factory);
- $result->append8($result, "f.");
- $result->appendS($result, $STRTAG.text->toUTF8($STRTAG.text));
- $result->append8($result, " LIKE '");
- $result->append8($result, tmp);
- $result->append8($result, "\%'");
-
- sqlite3_free(tmp);
- }
- | INTTAG INTBOOL INT
- {
- $result = $INTTAG.text->factory->newRaw($INTTAG.text->factory);
- $result->append8($result, "f.");
- $result->appendS($result, $INTTAG.text->toUTF8($INTTAG.text));
- $result->append8($result, " ");
- $result->appendS($result, $INTBOOL.text->toUTF8($INTBOOL.text));
- $result->append8($result, " ");
- $result->appendS($result, $INT.text->toUTF8($INT.text));
- }
- | DATETAG AFTER dateval
- {
- $result = $DATETAG.text->factory->newRaw($DATETAG.text->factory);
- $result->append8($result, "f.");
- $result->appendS($result, $DATETAG.text->toUTF8($DATETAG.text));
- $result->append8($result, " > ");
- $result->append8($result, (const char*)$dateval.result->chars);
- }
- | DATETAG BEFORE dateval
- {
- $result = $DATETAG.text->factory->newRaw($DATETAG.text->factory);
- $result->append8($result, "f.");
- $result->appendS($result, $DATETAG.text->toUTF8($DATETAG.text));
- $result->append8($result, " < ");
- $result->append8($result, (const char*)$dateval.result->chars);
- }
- | ENUMTAG IS ENUMVAL
- {
- pANTLR3_UINT8 tag;
- pANTLR3_UINT8 val;
- char str[20];
-
- sprintf(str, "1=1");
-
- tag = $ENUMTAG.text->chars;
- val = $ENUMVAL.text->chars;
- if (strcmp((char *)tag, "media_kind") == 0)
- {
- if (strcmp((char *)val, "music") == 0)
- {
- sprintf(str, "f.media_kind = \%d", MEDIA_KIND_MUSIC);
- }
- else if (strcmp((char *)val, "movie") == 0)
- {
- sprintf(str, "f.media_kind = \%d", MEDIA_KIND_MOVIE);
- }
- else if (strcmp((char *)val, "podcast") == 0)
- {
- sprintf(str, "f.media_kind = \%d", MEDIA_KIND_PODCAST);
- }
- else if (strcmp((char *)val, "audiobook") == 0)
- {
- sprintf(str, "f.media_kind = \%d", MEDIA_KIND_AUDIOBOOK);
- }
- else if (strcmp((char *)val, "tvshow") == 0)
- {
- sprintf(str, "f.media_kind = \%d", MEDIA_KIND_TVSHOW);
- }
- }
- else if (strcmp((char *)tag, "data_kind") == 0)
- {
- if (strcmp((char *)val, "file") == 0)
- {
- sprintf(str, "f.data_kind = \%d", DATA_KIND_FILE);
- }
- else if (strcmp((char *)val, "url") == 0)
- {
- sprintf(str, "f.data_kind = \%d", DATA_KIND_HTTP);
- }
- else if (strcmp((char *)val, "spotify") == 0)
- {
- sprintf(str, "f.data_kind = \%d", DATA_KIND_SPOTIFY);
- }
- else if (strcmp((char *)val, "pipe") == 0)
- {
- sprintf(str, "f.data_kind = \%d", DATA_KIND_PIPE);
- }
- }
- else if (strcmp((char *)tag, "scan_kind") == 0)
- {
- if (strcmp((char *)val, "files") == 0)
- {
- sprintf(str, "f.scan_kind = \%d", SCAN_KIND_FILES);
- }
- else if (strcmp((char *)val, "spotify") == 0)
- {
- sprintf(str, "f.scan_kind = \%d", SCAN_KIND_SPOTIFY);
- }
- else if (strcmp((char *)val, "rss") == 0)
- {
- sprintf(str, "f.scan_kind = \%d", SCAN_KIND_RSS);
- }
- }
-
- $result = $ENUMTAG.text->factory->newRaw($ENUMTAG.text->factory);
- $result->append8($result, str);
- }
- | GROUPTAG INTBOOL INT
- {
- $result = $GROUPTAG.text->factory->newRaw($GROUPTAG.text->factory);
- $result->appendS($result, $GROUPTAG.text->toUTF8($GROUPTAG.text));
- $result->append8($result, " ");
- $result->appendS($result, $INTBOOL.text->toUTF8($INTBOOL.text));
- $result->append8($result, " ");
- $result->appendS($result, $INT.text->toUTF8($INT.text));
- }
- ;
-
-ordertag returns [ pANTLR3_STRING result ]
-@init { $result = NULL; }
- : STRTAG
- {
- $result = $STRTAG.text->factory->newRaw($STRTAG.text->factory);
- $result->append8($result, "f.");
- $result->appendS($result, $STRTAG.text->toUTF8($STRTAG.text));
- }
- | INTTAG
- {
- $result = $INTTAG.text->factory->newRaw($INTTAG.text->factory);
- $result->append8($result, "f.");
- $result->appendS($result, $INTTAG.text->toUTF8($INTTAG.text));
- }
- | DATETAG
- {
- $result = $DATETAG.text->factory->newRaw($DATETAG.text->factory);
- $result->append8($result, "f.");
- $result->appendS($result, $DATETAG.text->toUTF8($DATETAG.text));
- }
- | ENUMTAG
- {
- $result = $ENUMTAG.text->factory->newRaw($ENUMTAG.text->factory);
- $result->append8($result, "f.");
- $result->appendS($result, $ENUMTAG.text->toUTF8($ENUMTAG.text));
- }
- | RANDOMTAG
- {
- $result = $RANDOMTAG.text->factory->newRaw($RANDOMTAG.text->factory);
- $result->append8($result, "random()");
- }
- ;
-
-dateval returns [ pANTLR3_STRING result ]
-@init { $result = NULL; }
- : DATE
- {
- pANTLR3_UINT8 datval;
-
- datval = $DATE.text->chars;
- $result = $DATE.text->factory->newRaw($DATE.text->factory);
-
- append_date($result, (const char *)datval, 0, NULL);
- }
- | interval BEFORE DATE
- {
- $result = $DATE.text->factory->newRaw($DATE.text->factory);
- append_date($result, (const char *)$DATE.text->chars, '-', (const char *)$interval.result->chars);
- }
- | interval AFTER DATE
- {
- $result = $DATE.text->factory->newRaw($DATE.text->factory);
- append_date($result, (const char *)$DATE.text->chars, '+', (const char *)$interval.result->chars);
- }
- | interval AGO
- {
- $result = $AGO.text->factory->newRaw($AGO.text->factory);
- append_date($result, "today", '-', (const char *)$interval.result->chars);
- }
- ;
-
-interval returns [ pANTLR3_STRING result ]
-@init { $result = NULL; }
- : INT DATINTERVAL
- {
- pANTLR3_UINT8 interval;
- int intval;
- char buf[25];
-
- $result = $DATINTERVAL.text->factory->newRaw($DATINTERVAL.text->factory);
-
- // SQL doesnt have a modifer for 'week' but for day/hr/min/sec/month/yr
- interval = $DATINTERVAL.text->chars;
- if (strcmp((char *)interval, "weeks") == 0)
- {
- intval = atoi((const char *)$INT.text->chars) * 7;
- snprintf(buf, sizeof(buf), "\%d days", intval);
-
- $result->append8($result, buf);
- }
- else
- {
- $result->append8($result, (const char *)$INT.text->chars);
- $result->append8($result, " ");
- $result->append8($result, (const char *)$DATINTERVAL.text->chars);
- }
- return $result;
- }
- ;
-
-
diff --git a/src/daap_query.c b/src/daap_query.c
index 42881fe9..79711363 100644
--- a/src/daap_query.c
+++ b/src/daap_query.c
@@ -29,129 +29,9 @@
#include "misc.h"
#include "daap_query.h"
-#include "DAAPLexer.h"
-#include "DAAPParser.h"
-#include "DAAP2SQL.h"
-
char *
daap_query_parse_sql(const char *daap_query)
{
- /* Input DAAP query, fed to the lexer */
- pANTLR3_INPUT_STREAM query;
-
- /* Lexer and the resulting token stream, fed to the parser */
- pDAAPLexer lxr;
- pANTLR3_COMMON_TOKEN_STREAM tkstream;
-
- /* Parser and the resulting AST, fed to the tree parser */
- pDAAPParser psr;
- DAAPParser_query_return qtree;
- pANTLR3_COMMON_TREE_NODE_STREAM nodes;
-
- /* Tree parser and the resulting SQL query string */
- pDAAP2SQL sqlconv;
- pANTLR3_STRING sql;
-
- char *ret = NULL;
-
- if (!daap_query)
- {
- DPRINTF(E_LOG, L_DAAP, "DAAP query is null\n");
- return NULL;
- }
-
- DPRINTF(E_DBG, L_DAAP, "Trying DAAP query -%s-\n", daap_query);
-
-#if ANTLR3C_NEW_INPUT
- query = antlr3StringStreamNew ((pANTLR3_UINT8)daap_query, ANTLR3_ENC_8BIT, (ANTLR3_UINT64)strlen(daap_query), (pANTLR3_UINT8)"DAAP query");
-#else
- query = antlr3NewAsciiStringInPlaceStream ((pANTLR3_UINT8)daap_query, (ANTLR3_UINT64)strlen(daap_query), (pANTLR3_UINT8)"DAAP query");
-#endif
- if (!query)
- {
- DPRINTF(E_DBG, L_DAAP, "Could not create input stream\n");
- return NULL;
- }
-
- lxr = DAAPLexerNew(query);
- if (!lxr)
- {
- DPRINTF(E_DBG, L_DAAP, "Could not create DAAP lexer\n");
- goto lxr_fail;
- }
-
- tkstream = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lxr));
- if (!tkstream)
- {
- DPRINTF(E_DBG, L_DAAP, "Could not create DAAP token stream\n");
- goto tkstream_fail;
- }
-
- psr = DAAPParserNew(tkstream);
- if (!psr)
- {
- DPRINTF(E_DBG, L_DAAP, "Could not create DAAP parser\n");
- goto psr_fail;
- }
-
- qtree = psr->query(psr);
-
- /* Check for parser errors */
- if (psr->pParser->rec->state->errorCount > 0)
- {
- DPRINTF(E_LOG, L_DAAP, "DAAP query parser terminated with %d errors\n", psr->pParser->rec->state->errorCount);
- goto psr_error;
- }
-
- DPRINTF(E_SPAM, L_DAAP, "DAAP query AST:\n\t%s\n", qtree.tree->toStringTree(qtree.tree)->chars);
-
- nodes = antlr3CommonTreeNodeStreamNewTree(qtree.tree, ANTLR3_SIZE_HINT);
- if (!nodes)
- {
- DPRINTF(E_DBG, L_DAAP, "Could not create node stream\n");
- goto psr_error;
- }
-
- sqlconv = DAAP2SQLNew(nodes);
- if (!sqlconv)
- {
- DPRINTF(E_DBG, L_DAAP, "Could not create SQL converter\n");
- goto sql_fail;
- }
-
- sql = sqlconv->query(sqlconv);
-
- /* Check for tree parser errors */
- if (sqlconv->pTreeParser->rec->state->errorCount > 0)
- {
- DPRINTF(E_LOG, L_DAAP, "DAAP query tree parser terminated with %d errors\n", sqlconv->pTreeParser->rec->state->errorCount);
- goto sql_error;
- }
-
- if (sql)
- {
- DPRINTF(E_DBG, L_DAAP, "DAAP SQL query: -%s-\n", sql->chars);
- ret = strdup((char *)sql->chars);
- }
- else
- {
- DPRINTF(E_LOG, L_DAAP, "Invalid DAAP query -%s-\n", daap_query);
- ret = NULL;
- }
-
- sql_error:
- sqlconv->free(sqlconv);
- sql_fail:
- nodes->free(nodes);
- psr_error:
- psr->free(psr);
- psr_fail:
- tkstream->free(tkstream);
- tkstream_fail:
- lxr->free(lxr);
- lxr_fail:
- query->close(query);
-
- return ret;
+ return NULL;
}
diff --git a/src/rsp_query.c b/src/rsp_query.c
index 82db6910..16ac76f8 100644
--- a/src/rsp_query.c
+++ b/src/rsp_query.c
@@ -29,122 +29,8 @@
#include "misc.h"
#include "rsp_query.h"
-#include "RSPLexer.h"
-#include "RSPParser.h"
-#include "RSP2SQL.h"
-
-
char *
rsp_query_parse_sql(const char *rsp_query)
{
- /* Input RSP query, fed to the lexer */
- pANTLR3_INPUT_STREAM query;
-
- /* Lexer and the resulting token stream, fed to the parser */
- pRSPLexer lxr;
- pANTLR3_COMMON_TOKEN_STREAM tkstream;
-
- /* Parser and the resulting AST, fed to the tree parser */
- pRSPParser psr;
- RSPParser_query_return qtree;
- pANTLR3_COMMON_TREE_NODE_STREAM nodes;
-
- /* Tree parser and the resulting SQL query string */
- pRSP2SQL sqlconv;
- pANTLR3_STRING sql;
-
- char *ret = NULL;
-
- DPRINTF(E_DBG, L_RSP, "Trying RSP query -%s-\n", rsp_query);
-
-#if ANTLR3C_NEW_INPUT
- query = antlr3StringStreamNew ((pANTLR3_UINT8)rsp_query, ANTLR3_ENC_8BIT, (ANTLR3_UINT64)strlen(rsp_query), (pANTLR3_UINT8)"RSP query");
-#else
- query = antlr3NewAsciiStringInPlaceStream ((pANTLR3_UINT8)rsp_query, (ANTLR3_UINT64)strlen(rsp_query), (pANTLR3_UINT8)"RSP query");
-#endif
- if (!query)
- {
- DPRINTF(E_DBG, L_RSP, "Could not create input stream\n");
- return NULL;
- }
-
- lxr = RSPLexerNew(query);
- if (!lxr)
- {
- DPRINTF(E_DBG, L_RSP, "Could not create RSP lexer\n");
- goto lxr_fail;
- }
-
- tkstream = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lxr));
- if (!tkstream)
- {
- DPRINTF(E_DBG, L_RSP, "Could not create RSP token stream\n");
- goto tkstream_fail;
- }
-
- psr = RSPParserNew(tkstream);
- if (!psr)
- {
- DPRINTF(E_DBG, L_RSP, "Could not create RSP parser\n");
- goto psr_fail;
- }
-
- qtree = psr->query(psr);
-
- /* Check for parser errors */
- if (psr->pParser->rec->state->errorCount > 0)
- {
- DPRINTF(E_LOG, L_RSP, "RSP query parser terminated with %d errors\n", psr->pParser->rec->state->errorCount);
- goto psr_error;
- }
-
- DPRINTF(E_SPAM, L_RSP, "RSP query AST:\n\t%s\n", qtree.tree->toStringTree(qtree.tree)->chars);
-
- nodes = antlr3CommonTreeNodeStreamNewTree(qtree.tree, ANTLR3_SIZE_HINT);
- if (!nodes)
- {
- DPRINTF(E_DBG, L_RSP, "Could not create node stream\n");
- goto psr_error;
- }
-
- sqlconv = RSP2SQLNew(nodes);
- if (!sqlconv)
- {
- DPRINTF(E_DBG, L_RSP, "Could not create SQL converter\n");
- goto sql_fail;
- }
-
- sql = sqlconv->query(sqlconv);
-
- /* Check for tree parser errors */
- if (sqlconv->pTreeParser->rec->state->errorCount > 0)
- {
- DPRINTF(E_LOG, L_RSP, "RSP query tree parser terminated with %d errors\n", sqlconv->pTreeParser->rec->state->errorCount);
- goto sql_error;
- }
-
- if (sql)
- {
- ret = strdup((char *)sql->chars);
- }
- else
- {
- DPRINTF(E_LOG, L_RSP, "Invalid RSP query\n");
- ret = NULL;
- }
-
- sql_error:
- sqlconv->free(sqlconv);
- sql_fail:
- nodes->free(nodes);
- psr_error:
- psr->free(psr);
- psr_fail:
- tkstream->free(tkstream);
- tkstream_fail:
- lxr->free(lxr);
- lxr_fail:
- query->close(query);
-
- return ret;
+ return NULL;
}
diff --git a/src/smartpl_query.c b/src/smartpl_query.c
index b990fa97..d563c1a7 100644
--- a/src/smartpl_query.c
+++ b/src/smartpl_query.c
@@ -35,183 +35,17 @@
#include "logger.h"
#include "misc.h"
-#include "SMARTPLLexer.h"
-#include "SMARTPLParser.h"
-#include "SMARTPL2SQL.h"
-
-
-static int
-parse_input(struct smartpl *smartpl, pANTLR3_INPUT_STREAM input)
-{
- pSMARTPLLexer lxr;
- pANTLR3_COMMON_TOKEN_STREAM tstream;
- pSMARTPLParser psr;
- SMARTPLParser_playlist_return qtree;
- pANTLR3_COMMON_TREE_NODE_STREAM nodes;
- pSMARTPL2SQL sqlconv;
- SMARTPL2SQL_playlist_return plreturn;
- int ret;
-
- lxr = SMARTPLLexerNew(input);
-
- // Need to check for errors
- if (lxr == NULL)
- {
- DPRINTF(E_LOG, L_SCAN, "Could not create SMARTPL lexer\n");
- ret = -1;
- goto lxr_fail;
- }
-
- tstream = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lxr));
-
- if (tstream == NULL)
- {
- DPRINTF(E_LOG, L_SCAN, "Could not create SMARTPL token stream\n");
- ret = -1;
- goto tkstream_fail;
- }
-
- // Finally, now that we have our lexer constructed, we can create the parser
- psr = SMARTPLParserNew(tstream); // CParserNew is generated by ANTLR3
-
- if (psr == NULL)
- {
- DPRINTF(E_LOG, L_SCAN, "Could not create SMARTPL parser\n");
- ret = -1;
- goto psr_fail;
- }
-
- qtree = psr->playlist(psr);
-
- /* Check for parser errors */
- if (psr->pParser->rec->state->errorCount > 0)
- {
- DPRINTF(E_LOG, L_SCAN, "SMARTPL query parser terminated with %d errors\n", psr->pParser->rec->state->errorCount);
- ret = -1;
- goto psr_error;
- }
-
- DPRINTF(E_DBG, L_SCAN, "SMARTPL query AST:\n\t%s\n", qtree.tree->toStringTree(qtree.tree)->chars);
-
- nodes = antlr3CommonTreeNodeStreamNewTree(qtree.tree, ANTLR3_SIZE_HINT);
- if (!nodes)
- {
- DPRINTF(E_LOG, L_SCAN, "Could not create node stream\n");
- ret = -1;
- goto psr_error;
- }
-
- sqlconv = SMARTPL2SQLNew(nodes);
- if (!sqlconv)
- {
- DPRINTF(E_LOG, L_SCAN, "Could not create SQL converter\n");
- ret = -1;
- goto sql_fail;
- }
-
- plreturn = sqlconv->playlist(sqlconv);
-
- /* Check for tree parser errors */
- if (sqlconv->pTreeParser->rec->state->errorCount > 0)
- {
- DPRINTF(E_LOG, L_SCAN, "SMARTPL query tree parser terminated with %d errors\n", sqlconv->pTreeParser->rec->state->errorCount);
- ret = -1;
- goto sql_error;
- }
-
- if (plreturn.title && plreturn.query)
- {
- DPRINTF(E_DBG, L_SCAN, "SMARTPL SQL title '%s', query: '%s', having: '%s', order by: '%s', limit: %d \n", plreturn.title->chars, plreturn.query->chars, plreturn.having->chars, plreturn.orderby->chars, plreturn.limit);
-
- if (smartpl->title)
- free(smartpl->title);
- smartpl->title = strdup((char *)plreturn.title->chars);
-
- if (smartpl->query_where)
- free(smartpl->query_where);
- smartpl->query_where = strdup((char *)plreturn.query->chars);
-
- if (smartpl->having)
- free(smartpl->having);
- smartpl->having = safe_strdup((char *)plreturn.having->chars);
-
- if (smartpl->order)
- free(smartpl->order);
- smartpl->order = safe_strdup((char *)plreturn.orderby->chars);
-
- smartpl->limit = plreturn.limit;
-
- ret = 0;
- }
- else
- {
- DPRINTF(E_LOG, L_SCAN, "Invalid SMARTPL query\n");
- ret = -1;
- }
-
- sql_error:
- sqlconv->free(sqlconv);
- sql_fail:
- nodes->free(nodes);
- psr_error:
- psr->free(psr);
- psr_fail:
- tstream->free(tstream);
- tkstream_fail:
- lxr->free(lxr);
- lxr_fail:
-
- return ret;
-}
int
smartpl_query_parse_file(struct smartpl *smartpl, const char *file)
{
- pANTLR3_INPUT_STREAM input;
- int ret;
-
-#if ANTLR3C_NEW_INPUT
- input = antlr3FileStreamNew((pANTLR3_UINT8) file, ANTLR3_ENC_8BIT);
-#else
- input = antlr3AsciiFileStreamNew((pANTLR3_UINT8) file);
-#endif
-
- // The input will be created successfully, providing that there is enough memory and the file exists etc
- if (input == NULL)
- {
- DPRINTF(E_LOG, L_SCAN, "Unable to open smart playlist file %s\n", file);
- return -1;
- }
-
- ret = parse_input(smartpl, input);
- input->close(input);
-
- return ret;
+ return -1;
}
int
smartpl_query_parse_string(struct smartpl *smartpl, const char *expression)
{
- pANTLR3_INPUT_STREAM input;
- int ret;
-
-#if ANTLR3C_NEW_INPUT
- input = antlr3StringStreamNew ((pANTLR3_UINT8)expression, ANTLR3_ENC_8BIT, (ANTLR3_UINT64)strlen(expression), (pANTLR3_UINT8)"SMARTPL expression");
-#else
- input = antlr3NewAsciiStringInPlaceStream ((pANTLR3_UINT8)expression, (ANTLR3_UINT64)strlen(expression), (pANTLR3_UINT8)"SMARTPL expression");
-#endif
-
- // The input will be created successfully, providing that there is enough memory and the file exists etc
- if (input == NULL)
- {
- DPRINTF(E_LOG, L_SCAN, "Unable to pars smart pl expression %s\n", expression);
- return -1;
- }
-
- ret = parse_input(smartpl, input);
- input->close(input);
-
- return ret;
+ return -1;
}