diff --git a/src/aspell/rclaspell.cpp b/src/aspell/rclaspell.cpp index 8bd54197..98d62a6f 100644 --- a/src/aspell/rclaspell.cpp +++ b/src/aspell/rclaspell.cpp @@ -1,17 +1,24 @@ #ifndef TEST_RCLASPELL #ifndef lint -static char rcsid[] = "@(#$Id: rclaspell.cpp,v 1.2 2006-10-09 16:37:08 dockes Exp $ (C) 2006 J.F.Dockes"; +static char rcsid[] = "@(#$Id: rclaspell.cpp,v 1.3 2006-10-11 14:16:25 dockes Exp $ (C) 2006 J.F.Dockes"; #endif +#ifdef HAVE_CONFIG_H +#include "autoconfig.h" +#endif + +#ifdef RCL_USE_ASPELL + #include #include #include -#include "aspell.h" +#include ASPELL_INCLUDE #include "pathut.h" #include "execmd.h" #include "rclaspell.h" +// Stuff that we don't wish to see in the .h (possible sysdeps, etc.) class AspellData { public: AspellData() : m_handle(0) {} @@ -62,22 +69,54 @@ static AspellApi aapi; badnames += #NM + string(" "); \ } -bool Aspell::init(const string &basedir, string &reason) +const char *aspell_progs[] = { +#ifdef ASPELL_PROG + ASPELL_PROG , +#endif + "/usr/local/bin/aspell", + "/usr/bin/aspell" +}; + +bool Aspell::init(string &reason) { - if (m_data == 0) - m_data = new AspellData; - if (m_data->m_handle) { - dlclose(m_data->m_handle); - m_data->m_handle = 0; + delete m_data; + m_data = 0; + // Language: we get this from the configuration, else from the NLS + // environment. The aspell language names used for selecting language + // definition files (used to create dictionaries) are like en, fr + if (!m_config->getConfParam("aspellLanguage", m_lang)) { + string lang = "en"; + const char *cp; + if (cp = getenv("LC_ALL")) + lang = cp; + else if (cp = getenv("LANG")) + lang = cp; + if (!lang.compare("C")) + lang = "en"; + m_lang = lang.substr(0, lang.find_first_of("_")); + } else { + if (!m_lang.compare("disable")) { + reason = "Aspell disabled in recoll configuration file"; + return false; + } } - m_data->m_exec = path_cat(basedir, "bin"); - m_data->m_exec = path_cat(m_data->m_exec, "aspell"); - if (access(m_data->m_exec.c_str(), X_OK) != 0) { - reason = m_data->m_exec + " not found or not executable"; + m_data = new AspellData; + for (unsigned int i = 0; i < sizeof(aspell_progs) / sizeof(char*); i++) { + if (access(aspell_progs[i], X_OK) == 0) { + m_data->m_exec = aspell_progs[i]; + break; + } + } + if (m_data->m_exec.empty()) { + reason = "aspell program not found or not executable"; return false; } - string lib = path_cat(basedir, "lib"); + + // For now, the aspell library has to live under the same prefix as the + // aspell program. + string aspellPrefix = path_getfather(path_getfather(m_data->m_exec)); + string lib = path_cat(aspellPrefix, "lib"); lib = path_cat(lib, "libaspell.so"); if ((m_data->m_handle = dlopen(lib.c_str(), RTLD_LAZY)) == 0) { reason = "Could not open shared library ["; @@ -120,6 +159,7 @@ bool Aspell::init(const string &basedir, string &reason) reason = string("Aspell::init: symbols not found:") + badnames; return false; } + return true; } @@ -130,51 +170,58 @@ bool Aspell::ok() string Aspell::dicPath() { - return path_cat(m_conf->getConfDir(), + return path_cat(m_config->getConfDir(), string("aspdict.") + m_lang + string(".rws")); } bool Aspell::buildDict(Rcl::Db &db, string &reason) { - string term; + if (!ok()) + return false; - // Il faut nettoyer la liste, peut-etre faire un tri unique (verifier), - // puis construire le dico - Rcl::TermIter *tit = db.termWalkOpen(); - if (tit == 0) { - reason = "termWalkOpen failed\n"; - return false; - } - ExecCmd aspell; - list args; - // aspell --lang=[lang] create master [dictApath] - args.push_back(string("--lang=")+ m_lang); - args.push_back("create"); - args.push_back("master"); - args.push_back(dicPath()); - // aspell.setStderr("/dev/null"); - string allterms; - while (db.termWalkNext(tit, term)) { - // Filter out terms beginning with upper case (special stuff) and - // containing numbers - if (term.empty()) - continue; - if ('A' <= term.at(0) && term.at(0) <= 'Z') - continue; - if (term.find_first_of("0123456789+-._@") != string::npos) - continue; - allterms += term + "\n"; - // std::cout << "[" << term << "]" << std::endl; - } - db.termWalkClose(tit); - aspell.doexec(m_data->m_exec, args, &allterms); - return true; + // We create the dictionary by executing the aspell command: + // aspell --lang=[lang] create master [dictApath] + ExecCmd aspell; + list args; + args.push_back(string("--lang=")+ m_lang); + args.push_back("create"); + args.push_back("master"); + args.push_back(dicPath()); + aspell.setStderr("/dev/null"); + + Rcl::TermIter *tit = db.termWalkOpen(); + if (tit == 0) { + reason = "termWalkOpen failed\n"; + return false; + } + string allterms, term; + while (db.termWalkNext(tit, term)) { + // Filter out terms beginning with upper case (special stuff) and + // containing numbers + if (term.empty()) + continue; + if ('A' <= term.at(0) && term.at(0) <= 'Z') + continue; + if (term.find_first_of("0123456789+-._@") != string::npos) + continue; + allterms += term + "\n"; + // std::cout << "[" << term << "]" << std::endl; + } + db.termWalkClose(tit); + if (aspell.doexec(m_data->m_exec, args, &allterms)) { + reason = string("aspell dictionary creation command failed. Check the language data files for lang = ") + m_lang; + return false; + } + return true; } bool Aspell::suggest(Rcl::Db &db, string &term, list &suggestions, string &reason) { + if (!ok()) + return false; + AspellCanHaveError *ret; AspellSpeller *speller; AspellConfig *config; @@ -221,9 +268,16 @@ bool Aspell::suggest(Rcl::Db &db, return true; } +#endif // RCL_USE_ASPELL #else // TEST_RCLASPELL test driver -> +#ifdef HAVE_CONFIG_H +#include "autoconfig.h" +#endif + +#ifdef RCL_USE_ASPELL + #include #include #include @@ -304,11 +358,9 @@ int main(int argc, char **argv) exit(1); } - string lang = "en"; + Aspell aspell(rclconfig); - Aspell aspell(rclconfig, lang); - - if (!aspell.init("/usr/local", reason)) { + if (!aspell.init(reason)) { cerr << "Init failed: " << reason << endl; exit(1); } @@ -331,5 +383,9 @@ int main(int argc, char **argv) } exit(0); } +#else +int main(int argc, char **argv) +{return 1;} +#endif // RCL_USE_ASPELL #endif // TEST_RCLASPELL test driver diff --git a/src/aspell/rclaspell.h b/src/aspell/rclaspell.h index 5a454cac..fd9abba1 100644 --- a/src/aspell/rclaspell.h +++ b/src/aspell/rclaspell.h @@ -1,6 +1,9 @@ #ifndef _RCLASPELL_H_INCLUDED_ #define _RCLASPELL_H_INCLUDED_ -/* @(#$Id: rclaspell.h,v 1.2 2006-10-09 16:37:08 dockes Exp $ (C) 2006 J.F.Dockes */ +/* @(#$Id: rclaspell.h,v 1.3 2006-10-11 14:16:25 dockes Exp $ (C) 2006 J.F.Dockes */ + +/* autoconfig.h must be included before this file */ +#ifdef RCL_USE_ASPELL /** * Aspell speller interface class. @@ -28,15 +31,15 @@ class AspellData; class Aspell { public: - Aspell(RclConfig *cnf, const string &lang) - : m_conf(cnf), m_lang(lang), m_data(0) {}; + Aspell(RclConfig *cnf) + : m_config(cnf), m_data(0) {}; ~Aspell(); /** Check health */ bool ok(); /** Find the aspell command and shared library, init function pointers */ - bool init(const string &basedir, string &reason); + bool init(string &reason); /** Build dictionary out of index term list. This is done at the end * of an indexing pass. */ @@ -48,9 +51,10 @@ class Aspell { private: string dicPath(); - RclConfig *m_conf; + RclConfig *m_config; string m_lang; AspellData *m_data; }; +#endif /* RCL_USE_ASPELL */ #endif /* _RCLASPELL_H_INCLUDED_ */ diff --git a/src/common/autoconfig.h.in b/src/common/autoconfig.h.in index 186fdd4a..82bf7f7a 100644 --- a/src/common/autoconfig.h.in +++ b/src/common/autoconfig.h.in @@ -8,19 +8,3 @@ /* Path to the aspell program */ #undef ASPELL_PROG - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - diff --git a/src/common/rclconfig.h b/src/common/rclconfig.h index c0c0ddef..8f2ec0aa 100644 --- a/src/common/rclconfig.h +++ b/src/common/rclconfig.h @@ -16,7 +16,7 @@ */ #ifndef _RCLCONFIG_H_INCLUDED_ #define _RCLCONFIG_H_INCLUDED_ -/* @(#$Id: rclconfig.h,v 1.21 2006-09-08 09:02:47 dockes Exp $ (C) 2004 J.F.Dockes */ +/* @(#$Id: rclconfig.h,v 1.22 2006-10-11 14:16:25 dockes Exp $ (C) 2004 J.F.Dockes */ #include @@ -41,6 +41,7 @@ class RclConfig { m_conf->get("guesscharset", str, m_keydir); guesscharset = stringToBool(str); } + string getKeyDir() const {return m_keydir;} /** Get generic configuration parameter according to current keydir */ bool getConfParam(const string &name, string &value) diff --git a/src/configure b/src/configure index 323d81f8..013f4b4e 100755 --- a/src/configure +++ b/src/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.53 for Recoll 1.0. +# Generated by GNU Autoconf 2.53 for Recoll 1.6. # # Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 # Free Software Foundation, Inc. @@ -254,8 +254,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='Recoll' PACKAGE_TARNAME='recoll' -PACKAGE_VERSION='1.0' -PACKAGE_STRING='Recoll 1.0' +PACKAGE_VERSION='1.6' +PACKAGE_STRING='Recoll 1.6' PACKAGE_BUGREPORT='' ac_unique_file="index/recollindex.cpp" @@ -719,7 +719,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures Recoll 1.0 to adapt to many kinds of systems. +\`configure' configures Recoll 1.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -776,7 +776,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of Recoll 1.0:";; + short | recursive ) echo "Configuration of Recoll 1.6:";; esac cat <<\_ACEOF @@ -785,6 +785,12 @@ Optional Features: --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-qt4 Use qt version 4 +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-aspell Use aspell spelling package to provide term + expansion to other spellings + Some influential environment variables: CC C compiler command CFLAGS C compiler flags @@ -858,7 +864,7 @@ fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF -Recoll configure 1.0 +Recoll configure 1.6 generated by GNU Autoconf 2.53 Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 @@ -873,7 +879,7 @@ cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by Recoll $as_me 1.0, which was +It was created by Recoll $as_me 1.6, which was generated by GNU Autoconf 2.53. Invocation command line was $ $0 $@ @@ -1150,6 +1156,8 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_config_headers="$ac_config_headers common/autoconfig.h" @@ -1166,6 +1174,102 @@ EOF exit 1 fi +# Use aspell to provide spelling expansions ? +# The default is yes. If we do find an aspell installation, we use it. Else +# we do compile the aspell module using an internal copy of aspell.h +# Only --with-aspell=no will completely disable aspell support + +# Check whether --with-aspell or --without-aspell was given. +if test "${with_aspell+set}" = set; then + withval="$with_aspell" + withAspell=$withval +else + withAspell=yes +fi; +case $withAspell in + no);; + yes) + # Extract the first word of "aspell", so it can be a program name with args. +set dummy aspell; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_path_aspellProg+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $aspellProg in + [\\/]* | ?:[\\/]*) + ac_cv_path_aspellProg="$aspellProg" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_aspellProg="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + ;; +esac +fi +aspellProg=$ac_cv_path_aspellProg + +if test -n "$aspellProg"; then + echo "$as_me:$LINENO: result: $aspellProg" >&5 +echo "${ECHO_T}$aspellProg" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + ;; + *) # The argument should be the path to the aspell program + aspellProg=$withAspell + ;; +esac +# if +if test X$withAspell != Xno ; then + +cat >>confdefs.h <<\_ACEOF +#define RCL_USE_ASPELL 1 +_ACEOF + + if test X$aspellProg != X ; then + aspellBase=`dirname $aspellProg` + aspellBase=`dirname $aspellBase` + if test ! -f $aspellBase/include/aspell.h ; then + { { echo "$as_me:$LINENO: error: aspell.h not found in $aspellBase/include. Specify --with-aspell=no to disable aspell support" >&5 +echo "$as_me: error: aspell.h not found in $aspellBase/include. Specify --with-aspell=no to disable aspell support" >&2;} + { (exit 1); exit 1; }; } + fi + +cat >>confdefs.h <<_ACEOF +#define ASPELL_PROG "$aspellProg" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define ASPELL_INCLUDE "$aspellBase/include/aspell.h" +_ACEOF + + else + # aspell support enabled but no aspell install yet + { echo "$as_me:$LINENO: aspell support enabled but aspell package not found. Compiling with internal aspell interface file" >&5 +echo "$as_me: aspell support enabled but aspell package not found. Compiling with internal aspell interface file" >&6;} + cat >>confdefs.h <<\_ACEOF +#define ASPELL_INCLUDE "aspell-local.h" +_ACEOF + + fi +fi + + ##### Look for iconv. We first look for libiconv in /usr/local/lib:/usr/lib ## then in libc (Linux, solaris) ac_ext=c @@ -2433,38 +2537,7 @@ s/^[^=]*=[ ]*$//; }' fi -# Transform confdefs.h into DEFS. -# Protect against shell expansion while executing Makefile rules. -# Protect against Makefile macro expansion. -# -# If the first sed substitution is executed (which looks for macros that -# take arguments), then we branch to the quote section. Otherwise, -# look for a macro that doesn't take arguments. -cat >confdef2opt.sed <<\_ACEOF -t clear -: clear -s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g -t quote -s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g -t quote -d -: quote -s,[ `~#$^&*(){}\\|;'"<>?],\\&,g -s,\[,\\&,g -s,\],\\&,g -s,\$,$$,g -p -_ACEOF -# We use echo to avoid assuming a particular line-breaking character. -# The extra dot is to prevent the shell from consuming trailing -# line-breaks from the sub-command output. A line-break within -# single-quotes doesn't work because, if this script is created in a -# platform that uses two characters for line-breaks (e.g., DOS), tr -# would break. -ac_LF_and_DOT=`echo; echo .` -DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` -rm -f confdef2opt.sed - +DEFS=-DHAVE_CONFIG_H : ${CONFIG_STATUS=./config.status} @@ -2715,7 +2788,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by Recoll $as_me 1.0, which was +This file was extended by Recoll $as_me 1.6, which was generated by GNU Autoconf 2.53. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -2760,16 +2833,21 @@ Usage: $0 [OPTIONS] [FILE]... --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE Configuration files: $config_files +Configuration headers: +$config_headers + Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -Recoll config.status 1.0 +Recoll config.status 1.6 configured by $0, generated by GNU Autoconf 2.53, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" @@ -2860,6 +2938,7 @@ do "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; "sampleconf/recoll.conf" ) CONFIG_FILES="$CONFIG_FILES sampleconf/recoll.conf" ;; "$QTGUI/recoll.pro" ) CONFIG_FILES="$CONFIG_FILES $QTGUI/recoll.pro" ;; + "common/autoconfig.h" ) CONFIG_HEADERS="$CONFIG_HEADERS common/autoconfig.h" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; @@ -2872,6 +2951,7 @@ done # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Create a temporary directory, and hook for its removal unless debugging. @@ -2940,6 +3020,7 @@ s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t +s,@aspellProg@,$aspellProg,;t t s,@CC@,$CC,;t t s,@CFLAGS@,$CFLAGS,;t t s,@LDFLAGS@,$LDFLAGS,;t t @@ -3150,6 +3231,223 @@ s,@abs_top_builddir@,$ac_abs_top_builddir,;t t done _ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo $f;; + *) # Relative + if test -f "$f"; then + # Build tree + echo $f + elif test -f "$srcdir/$f"; then + # Source tree + echo $srcdir/$f + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if egrep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # egrep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if cmp -s $ac_file $tmp/config.h 2>/dev/null; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { case "$ac_dir" in + [\\/]* | ?:[\\/]* ) as_incr_dir=;; + *) as_incr_dir=.;; +esac +as_dummy="$ac_dir" +for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do + case $as_mkdir_dir in + # Skip DOS drivespec + ?:) as_incr_dir=$as_mkdir_dir ;; + *) + as_incr_dir=$as_incr_dir/$as_mkdir_dir + test -d "$as_incr_dir" || + mkdir "$as_incr_dir" || + { { echo "$as_me:$LINENO: error: cannot create \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; } + ;; + esac +done; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +done +_ACEOF cat >>$CONFIG_STATUS <<\_ACEOF diff --git a/src/configure.ac b/src/configure.ac index 6b615a07..fefab67e 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -1,4 +1,5 @@ -AC_INIT(Recoll, 1.0) +AC_INIT(Recoll, 1.6) +AC_CONFIG_HEADERS([common/autoconfig.h]) AC_PREREQ(2.53) AC_CONFIG_SRCDIR(index/recollindex.cpp) @@ -14,6 +15,44 @@ EOF exit 1 fi +# Use aspell to provide spelling expansions ? +# The default is yes. If we do find an aspell installation, we use it. Else +# we do compile the aspell module using an internal copy of aspell.h +# Only --with-aspell=no will completely disable aspell support +AC_ARG_WITH(aspell, + AC_HELP_STRING([--with-aspell], + [Use aspell spelling package to provide term expansion to other spellings]), + withAspell=$withval, withAspell=yes) +case $withAspell in + no);; + yes) + AC_PATH_PROG(aspellProg, aspell) + ;; + *) # The argument should be the path to the aspell program + aspellProg=$withAspell + ;; +esac +# if +if test X$withAspell != Xno ; then + AC_DEFINE(RCL_USE_ASPELL, 1, [Compile the aspell interface]) + if test X$aspellProg != X ; then + aspellBase=`dirname $aspellProg` + aspellBase=`dirname $aspellBase` + if test ! -f $aspellBase/include/aspell.h ; then + AC_MSG_ERROR([aspell.h not found in $aspellBase/include. Specify --with-aspell=no to disable aspell support]) + fi + AC_DEFINE_UNQUOTED(ASPELL_PROG, "$aspellProg", + [Path to the aspell program]) + AC_DEFINE_UNQUOTED(ASPELL_INCLUDE, "$aspellBase/include/aspell.h", + [Path to the aspell api include file]) + else + # aspell support enabled but no aspell install yet + AC_MSG_NOTICE([aspell support enabled but aspell package not found. Compiling with internal aspell interface file]) + AC_DEFINE(ASPELL_INCLUDE, ["aspell-local.h"]) + fi +fi + + ##### Look for iconv. We first look for libiconv in /usr/local/lib:/usr/lib ## then in libc (Linux, solaris) AC_LANG(C) diff --git a/src/index/indexer.cpp b/src/index/indexer.cpp index f2a850d4..d77b876e 100644 --- a/src/index/indexer.cpp +++ b/src/index/indexer.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: indexer.cpp,v 1.35 2006-09-13 13:53:35 dockes Exp $ (C) 2004 J.F.Dockes"; +static char rcsid[] = "@(#$Id: indexer.cpp,v 1.36 2006-10-11 14:16:25 dockes Exp $ (C) 2004 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -17,6 +17,10 @@ static char rcsid[] = "@(#$Id: indexer.cpp,v 1.35 2006-09-13 13:53:35 dockes Exp * Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +#include "autoconfig.h" +#endif + #include #include #include @@ -42,6 +46,10 @@ static char rcsid[] = "@(#$Id: indexer.cpp,v 1.35 2006-09-13 13:53:35 dockes Exp #include "smallut.h" #include "wipedir.h" +#ifdef RCL_USE_ASPELL +#include "rclaspell.h" +#endif + #ifndef NO_NAMESPACES using namespace std; #endif /* NO_NAMESPACES */ @@ -137,6 +145,8 @@ bool DbIndexer::indexDb(bool resetbefore, list *topdirs) } } + createAspellDict(); + // The close would be done in our destructor, but we want status here if (m_updater) { m_updater->status.phase = DbIxStatus::DBIXS_CLOSING; @@ -171,6 +181,31 @@ bool DbIndexer::createStemDb(const string &lang) return m_db.createStemDb(lang); } +// The language for the aspell dictionary is handled internally by the aspell +// module, either from a configuration variable or the NLS environment. +bool DbIndexer::createAspellDict() +{ + LOGDEB2(("DbIndexer::createAspellDict()\n")); +#ifdef RCL_USE_ASPELL + if (!init()) + return false; + Aspell aspell(m_config); + string reason; + if (!aspell.init(reason)) { + LOGERR(("DbIndexer::createAspellDict: aspell init failed: %s\n", + reason.c_str())); + return false; + } + LOGDEB(("DbIndexer::createAspellDict: creating dictionary\n")); + if (!aspell.buildDict(m_db, reason)) { + LOGERR(("DbIndexer::createAspellDict: aspell buildDict failed: %s\n", + reason.c_str())); + return false; + } +#endif + return true; +} + /** Index individual files, out of a full tree run. No database purging */ diff --git a/src/index/indexer.h b/src/index/indexer.h index 23a3aea2..8af1d2e8 100644 --- a/src/index/indexer.h +++ b/src/index/indexer.h @@ -16,7 +16,7 @@ */ #ifndef _INDEXER_H_INCLUDED_ #define _INDEXER_H_INCLUDED_ -/* @(#$Id: indexer.h,v 1.16 2006-04-30 07:35:18 dockes Exp $ (C) 2004 J.F.Dockes */ +/* @(#$Id: indexer.h,v 1.17 2006-10-11 14:16:26 dockes Exp $ (C) 2004 J.F.Dockes */ #include #include @@ -119,6 +119,9 @@ class DbIndexer : public FsTreeWalkerCB { /** Create stem database for given language */ bool createStemDb(const string &lang); + /** Create misspelling expansion dictionary if aspell i/f is available */ + bool createAspellDict(); + /** Tree walker callback method */ FsTreeWalker::Status processone(const string &, const struct stat *, diff --git a/src/index/recollindex.cpp b/src/index/recollindex.cpp index 7763f883..0ee8c0ce 100644 --- a/src/index/recollindex.cpp +++ b/src/index/recollindex.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: recollindex.cpp,v 1.20 2006-09-08 09:02:47 dockes Exp $ (C) 2004 J.F.Dockes"; +static char rcsid[] = "@(#$Id: recollindex.cpp,v 1.21 2006-10-11 14:16:26 dockes Exp $ (C) 2004 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -17,6 +17,9 @@ static char rcsid[] = "@(#$Id: recollindex.cpp,v 1.20 2006-09-08 09:02:47 dockes * Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +#include "autoconfig.h" +#endif #include #include @@ -39,37 +42,45 @@ using namespace std; ConfIndexer *confindexer; DbIndexer *dbindexer; +static bool makeDbIndexer(RclConfig *config) +{ + if (dbindexer) + delete dbindexer; + // Note that we do not bother to check for multiple databases, + // which are currently a fiction anyway. + string dbdir = config->getDbDir(); + if (dbdir.empty()) { + fprintf(stderr, "makeDbIndexer: no database directory in " + "configuration for %s\n", config->getKeyDir().c_str()); + return false; + } + dbindexer = new DbIndexer(config, dbdir); + return true; +} + // Index a list of files static bool indexfiles(RclConfig *config, const list &filenames) { if (filenames.empty()) return true; - // Note that we do not bother to check for multiple databases, - // which are currently a fiction anyway. config->setKeyDir(path_getfather(*filenames.begin())); - string dbdir = config->getDbDir(); - if (dbdir.empty()) { - LOGERR(("indexfiles: no database directory in " - "configuration for %s\n", filenames.begin()->c_str())); + + makeDbIndexer(config); + if (dbindexer) + return dbindexer->indexFiles(filenames); + else return false; - } - dbindexer = new DbIndexer(config, dbdir); - return dbindexer->indexFiles(filenames); } // Create additional stem database static bool createstemdb(RclConfig *config, const string &lang) { - // Note that we do not bother to check for multiple databases, - // which are currently a fiction anyway. - string dbdir = config->getDbDir(); - if (dbdir.empty()) { - LOGERR(("createstemdb: no database directory in configuration\n")); + makeDbIndexer(config); + if (dbindexer) + return dbindexer->createStemDb(lang); + else return false; - } - dbindexer = new DbIndexer(config, dbdir); - return dbindexer->createStemDb(lang); } static void cleanup() @@ -108,6 +119,7 @@ static int op_flags; #define OPT_i 0x8 #define OPT_s 0x10 #define OPT_c 0x20 +#define OPT_S 0x40 static const char usage [] = "\n" @@ -120,6 +132,10 @@ static const char usage [] = " Index individual files. No database purge or stem database updates\n" "recollindex -s \n" " Build stem database for additional language \n" +#ifdef RCL_USE_ASPELL +"recollindex -S\n" +" Build aspell spelling dictionary.>\n" +#endif "Common options:\n" " -c : specify config directory, overriding $RECOLL_CONFDIR\n" ; @@ -151,6 +167,9 @@ int main(int argc, const char **argv) case 'h': op_flags |= OPT_h; break; case 'i': op_flags |= OPT_i; break; case 's': op_flags |= OPT_s; break; +#ifdef RCL_USE_ASPELL + case 'S': op_flags |= OPT_S; break; +#endif case 'z': op_flags |= OPT_z; break; default: Usage(); break; } @@ -189,6 +208,14 @@ int main(int argc, const char **argv) Usage(); string lang = *argv++; argc--; exit(!createstemdb(config, lang)); +#ifdef RCL_USE_ASPELL + } else if (op_flags & OPT_S) { + makeDbIndexer(config); + if (dbindexer) + exit(!dbindexer->createAspellDict()); + else + exit(1); +#endif } else { confindexer = new ConfIndexer(config, &updater); bool rezero(op_flags & OPT_z); diff --git a/src/mk/commondefs b/src/mk/commondefs index c34dc5c3..ca812bd8 100644 --- a/src/mk/commondefs +++ b/src/mk/commondefs @@ -3,7 +3,7 @@ COMMONCXXFLAGS = -I. -I$(depth)/index \ -I$(depth)/utils -I$(depth)/common \ - -I$(depth)/unac -I$(depth)/bincimapmime \ + -I$(depth)/unac -I$(depth)/bincimapmime -I$(depth)/aspell \ -I/usr/local/include # We happen to be using gcc on all platforms for now. Can be overridden in diff --git a/src/mk/localdefs.in b/src/mk/localdefs.in index 3d7cffa2..5c84ae46 100644 --- a/src/mk/localdefs.in +++ b/src/mk/localdefs.in @@ -10,6 +10,6 @@ datadir = @datadir@ RECOLL_DATADIR = ${datadir}/recoll LOCALCXXFLAGS = $(INCICONV) $(XAPIANCXXFLAGS) \ - -DRECOLL_DATADIR=\"$(RECOLL_DATADIR)\" + -DRECOLL_DATADIR=\"$(RECOLL_DATADIR)\" @DEFS@ CXXFLAGS = -g -O2 -Wall -Wno-unused diff --git a/src/qtgui/images/d_spell.png b/src/qtgui/images/d_spell.png new file mode 100644 index 00000000..270a5b33 Binary files /dev/null and b/src/qtgui/images/d_spell.png differ diff --git a/src/qtgui/images/spell.png b/src/qtgui/images/spell.png new file mode 100644 index 00000000..7129a286 Binary files /dev/null and b/src/qtgui/images/spell.png differ diff --git a/src/qtgui/main.cpp b/src/qtgui/main.cpp index 84f2471c..868b4252 100644 --- a/src/qtgui/main.cpp +++ b/src/qtgui/main.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: main.cpp,v 1.51 2006-09-28 11:55:30 dockes Exp $ (C) 2005 J.F.Dockes"; +static char rcsid[] = "@(#$Id: main.cpp,v 1.52 2006-10-11 14:16:26 dockes Exp $ (C) 2005 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -18,6 +18,8 @@ static char rcsid[] = "@(#$Id: main.cpp,v 1.51 2006-09-28 11:55:30 dockes Exp $ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "autoconfig.h" + #include //#define WITH_KDE @@ -51,6 +53,9 @@ static char rcsid[] = "@(#$Id: main.cpp,v 1.51 2006-09-28 11:55:30 dockes Exp $ #endif #include "rclmain_w.h" #include "guiutils.h" +#ifdef RCL_USE_ASPELL +#include "rclaspell.h" +#endif #ifdef WITH_KDE static const char description[] = @@ -68,6 +73,9 @@ const string recoll_datadir = RECOLL_DATADIR; RclConfig *rclconfig; Rcl::Db *rcldb; +#ifdef RCL_USE_ASPELL +Aspell *aspell; +#endif RclHistory *g_dynconf; int recollNeedsExit; @@ -123,6 +131,10 @@ static void recollCleanup() rcldb = 0; delete rclconfig; rclconfig = 0; +#ifdef RCL_USE_ASPELL + delete aspell; + aspell = 0; +#endif LOGDEB2(("recollCleanup: done\n")); } @@ -214,6 +226,15 @@ int main(int argc, char **argv) } // fprintf(stderr, "recollinit done\n"); +#ifdef RCL_USE_ASPELL + aspell = new Aspell(rclconfig); + aspell->init(reason); + if (!aspell || !aspell->ok()) { + LOGDEB(("Aspell speller creation failed %s\n", reason.c_str())); + aspell = 0; + } +#endif + string historyfile = path_cat(rclconfig->getConfDir(), "history"); g_dynconf = new RclHistory(historyfile); if (!g_dynconf || !g_dynconf->ok()) { diff --git a/src/qtgui/rclmain.ui b/src/qtgui/rclmain.ui index f94f54de..76ef2e4b 100644 --- a/src/qtgui/rclmain.ui +++ b/src/qtgui/rclmain.ui @@ -84,6 +84,7 @@ + @@ -106,6 +107,7 @@ + @@ -251,6 +253,23 @@ Sort parameters + + + toolsSpellAction + + + spell.png + + + Spelling expansion + + + Spelling expansion + + + Spelling expansion tool + + nextPageAction diff --git a/src/qtgui/rclmain_w.cpp b/src/qtgui/rclmain_w.cpp index d939a5d6..6f78b3de 100644 --- a/src/qtgui/rclmain_w.cpp +++ b/src/qtgui/rclmain_w.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: rclmain_w.cpp,v 1.1 2006-09-22 07:41:35 dockes Exp $ (C) 2005 J.F.Dockes"; +static char rcsid[] = "@(#$Id: rclmain_w.cpp,v 1.2 2006-10-11 14:16:26 dockes Exp $ (C) 2005 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -17,6 +17,7 @@ static char rcsid[] = "@(#$Id: rclmain_w.cpp,v 1.1 2006-09-22 07:41:35 dockes Ex * Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "autoconfig.h" #include #include @@ -126,6 +127,14 @@ void RclMain::init() this, SLOT(showAdvSearchDialog())); connect(toolsSort_parametersAction, SIGNAL(activated()), this, SLOT(showSortDialog())); + toolsSpellAction->setIconSet(createIconSet("spell.png")); +#ifdef RCL_USE_ASPELL + connect(toolsSpellAction, SIGNAL(activated()), + this, SLOT(showSpellDialog())); +#else + toolsSpellAction->setEnabled(FALSE); +#endif + connect(preferencesQuery_PrefsAction, SIGNAL(activated()), this, SLOT(showUIPrefs())); @@ -379,6 +388,21 @@ void RclMain::showSortDialog() } +void RclMain::showSpellDialog() +{ + if (spellform == 0) { + spellform = new SpellW(0, tr("Spell expansion"), + WStyle_Customize | WStyle_NormalBorder | + WStyle_Title | WStyle_SysMenu); + spellform->show(); + } else { + // Close and reopen, in hope that makes us visible... + spellform->close(); + spellform->show(); + } + +} + void RclMain::showUIPrefs() { if (uiprefs == 0) { diff --git a/src/qtgui/rclmain_w.h b/src/qtgui/rclmain_w.h index f37ae9ff..88f9a5b6 100644 --- a/src/qtgui/rclmain_w.h +++ b/src/qtgui/rclmain_w.h @@ -27,6 +27,7 @@ #include "uiprefs_w.h" #include "rcldb.h" #include "searchdata.h" +#include "spell_w.h" #include "rclmain.h" @@ -52,6 +53,7 @@ public slots: virtual void previewClosed(QWidget * w); virtual void showAdvSearchDialog(); virtual void showSortDialog(); + virtual void showSpellDialog(); virtual void showAboutDialog(); virtual void startManual(); virtual void showDocHistory(); @@ -73,6 +75,8 @@ private: AdvSearch *asearchform; SortForm *sortform; UIPrefsDialog *uiprefs; + SpellW *spellform; + DocSeqSortSpec sortspecs; int m_searchId; // Serial number of current search for this process. // Used to match to preview windows diff --git a/src/qtgui/recoll.h b/src/qtgui/recoll.h index 10ffd7e0..79ca6077 100644 --- a/src/qtgui/recoll.h +++ b/src/qtgui/recoll.h @@ -16,7 +16,7 @@ */ #ifndef _RECOLL_H_INCLUDED_ #define _RECOLL_H_INCLUDED_ -/* @(#$Id: recoll.h,v 1.16 2006-09-11 09:08:44 dockes Exp $ (C) 2004 J.F.Dockes */ +/* @(#$Id: recoll.h,v 1.17 2006-10-11 14:16:26 dockes Exp $ (C) 2004 J.F.Dockes */ #include #include "rclconfig.h" @@ -34,5 +34,9 @@ extern Rcl::Db *rcldb; extern int recollNeedsExit; extern const std::string recoll_datadir; extern RclHistory *g_dynconf; +#ifdef RCL_USE_ASPELL +class Aspell; +extern Aspell *aspell; +#endif #endif /* _RECOLL_H_INCLUDED_ */ diff --git a/src/qtgui/recoll.pro.in b/src/qtgui/recoll.pro.in index c4b06996..eb103e75 100644 --- a/src/qtgui/recoll.pro.in +++ b/src/qtgui/recoll.pro.in @@ -5,6 +5,7 @@ CONFIG += qt warn_on thread release debug HEADERS += \ advsearch_w.h \ + spell_w.h \ preview_w.h \ rclmain_w.h \ reslist.h \ @@ -21,6 +22,7 @@ SOURCES += \ rclmain_w.cpp \ reslist.cpp \ advsearch_w.cpp \ + spell_w.cpp \ preview_w.cpp \ sort_w.cpp \ ssearch_w.cpp \ @@ -28,6 +30,7 @@ SOURCES += \ FORMS = \ advsearch.ui \ + spell.ui \ preview.ui \ rclmain.ui \ sort.ui \ @@ -40,7 +43,9 @@ IMAGES = images/asearch.png \ images/nextpage.png \ images/d_prevpage.png \ images/prevpage.png \ - images/sortparms.png + images/sortparms.png \ + images/d_spell.png \ + images/spell.png unix { UI_DIR = .ui @@ -52,7 +57,7 @@ unix { $(BSTATIC) @LIBXAPIAN@ @LIBICONV@ $(BDYNAMIC) \ -lz - INCLUDEPATH += ../common ../index ../query ../unac ../utils + INCLUDEPATH += ../common ../index ../query ../unac ../utils ../aspell POST_TARGETDEPS = ../lib/librcl.a } diff --git a/src/qtgui/spell.ui b/src/qtgui/spell.ui new file mode 100644 index 00000000..823e8520 --- /dev/null +++ b/src/qtgui/spell.ui @@ -0,0 +1,156 @@ + +SpellBase + + + SpellBase + + + + 0 + 0 + 0 + 0 + + + + + 5 + 5 + 0 + 0 + + + + + 130 + 30 + + + + Spelling Explorer + + + + unnamed + + + + layout3 + + + + unnamed + + + + layout4 + + + + unnamed + + + + layout3 + + + + unnamed + + + + Label1 + + + NoFrame + + + Plain + + + Enter word + + + baseWordLE + + + + + baseWordLE + + + + 200 + 0 + + + + LineEditPanel + + + Sunken + + + + + expandPB + + + false + + + &Expand + + + Alt+E + + + + + clearPB + + + false + + + &Clear + + + Alt+C + + + + + dismissPB + + + true + + + &Close + + + Alt+C + + + + + + + + + suggsTE + + + + 0 + 200 + + + + + + + + + diff --git a/src/qtgui/spell_w.cpp b/src/qtgui/spell_w.cpp new file mode 100644 index 00000000..cd305707 --- /dev/null +++ b/src/qtgui/spell_w.cpp @@ -0,0 +1,94 @@ +#ifndef lint +static char rcsid[] = "@(#$Id: spell_w.cpp,v 1.1 2006-10-11 14:16:26 dockes Exp $ (C) 2005 J.F.Dockes"; +#endif +/* + * 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. + */ +#include "autoconfig.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "debuglog.h" +#include "recoll.h" +#include "spell_w.h" + +#ifdef RCL_USE_ASPELL +#include "rclaspell.h" +#endif + +void SpellW::init() +{ + // signals and slots connections + connect(baseWordLE, SIGNAL(textChanged(const QString&)), + this, SLOT(wordChanged(const QString&))); + connect(baseWordLE, SIGNAL(returnPressed()), this, SLOT(doExpand())); + connect(expandPB, SIGNAL(clicked()), this, SLOT(doExpand())); + connect(clearPB, SIGNAL(clicked()), baseWordLE, SLOT(clear())); + connect(dismissPB, SIGNAL(clicked()), this, SLOT(close())); +} + +void SpellW::doExpand() +{ +#ifdef RCL_USE_ASPELL + string reason; + if (!aspell || !maybeOpenDb(reason)) { + LOGDEB(("SpellW::doExpand: error aspell %p db: %s\n", aspell, + reason.c_str())); + return; + } + if (!baseWordLE->text().isEmpty()) { + list suggs; + string word = string((const char *)baseWordLE->text().utf8()); + if (!aspell->suggest(*rcldb, word, suggs, reason)) { + LOGERR(("SpellW::doExpand:suggest failed: %s\n", reason.c_str())); + return; + } + suggsTE->clear(); + if (suggs.empty()) { + suggsTE->append(tr("No spelling expansion found")); + } else { + for (list::iterator it = suggs.begin(); + it != suggs.end(); it++) { + suggsTE->append(QString::fromUtf8(it->c_str())); + } + suggsTE->setCursorPosition(0,0); + suggsTE->ensureCursorVisible(); + } + } +#endif +} + +void SpellW::wordChanged(const QString &text) +{ + if (text.isEmpty()) { + expandPB->setEnabled(false); + clearPB->setEnabled(false); + suggsTE->clear(); + } else { + expandPB->setEnabled(true); + clearPB->setEnabled(true); + } +} diff --git a/src/qtgui/spell_w.h b/src/qtgui/spell_w.h new file mode 100644 index 00000000..c96ab605 --- /dev/null +++ b/src/qtgui/spell_w.h @@ -0,0 +1,48 @@ +#ifndef _ASPELL_W_H_INCLUDED_ +#define _ASPELL_W_H_INCLUDED_ +/* @(#$Id: spell_w.h,v 1.1 2006-10-11 14:16:26 dockes Exp $ (C) 2006 J.F.Dockes */ +/* + * 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. + */ + +#include +#include +#include "rcldb.h" +#include "spell.h" + +class SpellW : public SpellBase +{ + Q_OBJECT + +public: + SpellW(QWidget* parent = 0, const char* name = 0, WFlags fl = 0) : + SpellBase(parent,name,fl) {init();} + + ~SpellW(){} + +public slots: + virtual void doExpand(); + virtual void wordChanged(const QString&); + // virtual void textDoubleClicked(int, int); + +signals: + // void wordSelect(QString); + +private: + void init(); +}; + +#endif /* _ASPELL_W_H_INCLUDED_ */ diff --git a/src/sampleconf/recoll.conf.in b/src/sampleconf/recoll.conf.in index ab0d1d7b..d6f84a50 100644 --- a/src/sampleconf/recoll.conf.in +++ b/src/sampleconf/recoll.conf.in @@ -1,4 +1,4 @@ -# @(#$Id: recoll.conf.in,v 1.11 2006-09-13 13:53:35 dockes Exp $ (C) 2004 J.F.Dockes +# @(#$Id: recoll.conf.in,v 1.12 2006-10-11 14:16:26 dockes Exp $ (C) 2004 J.F.Dockes # # Recoll default configuration file. This should be copied to # ~/.recoll/recoll.conf @@ -60,6 +60,13 @@ indexallfilenames = 1 # bigger db # idxabsmlen = 250 +# Language definitions to use when creating the aspell dictionary. +# The value must match a set of aspell language definition files. +# You can type "aspell config" to see where these are installed. +# The default is english: "en" +# You can use a value of "disable" to disable aspell support. +# aspellLanguage = en + # You could specify different parameters for a subdirectory like this: #[~/hungariandocs/plain] #defaultcharset = iso-8859-2 diff --git a/src/utils/smallut.cpp b/src/utils/smallut.cpp index 4dcc1267..cb6d829b 100644 --- a/src/utils/smallut.cpp +++ b/src/utils/smallut.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: smallut.cpp,v 1.16 2006-04-11 06:49:45 dockes Exp $ (C) 2004 J.F.Dockes"; +static char rcsid[] = "@(#$Id: smallut.cpp,v 1.17 2006-10-11 14:16:26 dockes Exp $ (C) 2004 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -242,6 +242,7 @@ bool stringToStrings(const string &s, std::list &tokens) case ' ': case '\t': + case '\n': switch(state) { case SPACE: continue; diff --git a/src/utils/smallut.h b/src/utils/smallut.h index f72091ca..dabea61b 100644 --- a/src/utils/smallut.h +++ b/src/utils/smallut.h @@ -16,7 +16,7 @@ */ #ifndef _SMALLUT_H_INCLUDED_ #define _SMALLUT_H_INCLUDED_ -/* @(#$Id: smallut.h,v 1.16 2006-04-11 06:49:45 dockes Exp $ (C) 2004 J.F.Dockes */ +/* @(#$Id: smallut.h,v 1.17 2006-10-11 14:16:26 dockes Exp $ (C) 2004 J.F.Dockes */ #include #include @@ -38,7 +38,7 @@ extern string stringlistdisp(const list& strs); /** * Parse input string into list of strings. * - * Token delimiter is " \t" except inside dquotes. dquote inside + * Token delimiter is " \t\n" except inside dquotes. dquote inside * dquotes can be escaped with \ etc... */ extern bool stringToStrings(const string &s, list &tokens);