[KLF Application][KLF Tools][KLF Backend][KLF Home]
KLatexFormula Project
src/main.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002  *   file main.cpp
00003  *   This file is part of the KLatexFormula Project.
00004  *   Copyright (C) 2011 by Philippe Faist
00005  *   philippe.faist@bluewin.ch
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  ***************************************************************************/
00022 /* $Id: main.cpp 631 2011-04-14 10:14:00Z phfaist $ */
00023 
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027 #include <getopt.h>
00028 
00029 #include <signal.h>
00030 
00031 #include <QApplication>
00032 #include <QDebug>
00033 #include <QTranslator>
00034 #include <QFileInfo>
00035 #include <QDir>
00036 #include <QResource>
00037 #include <QProcess>
00038 #include <QPluginLoader>
00039 #include <QMessageBox>
00040 #include <QLibraryInfo>
00041 #include <QMetaType>
00042 #include <QClipboard>
00043 #include <QFontDatabase>
00044 
00045 #include <klfbackend.h>
00046 
00047 #include <klfutil.h>
00048 #include <klfcolorchooser.h>
00049 #include "klflib.h"
00050 #include "klflibdbengine.h"
00051 #include "klfliblegacyengine.h"
00052 #include "klflibview.h"
00053 #include "klfmain.h"
00054 #include "klfconfig.h"
00055 #include "klfmainwin.h"
00056 #include "klfdbus.h"
00057 #include "klfpluginiface.h"
00058 
00073 // Name of the environment variable to check for paths to extra resources
00074 #ifndef KLF_RESOURCES_ENVNAM
00075 #define KLF_RESOURCES_ENVNAM "KLF_RESOURCES"
00076 #endif
00077 
00078 
00079 // Program Exit Error Codes
00080 #define EXIT_ERR_FILEINPUT 100
00081 #define EXIT_ERR_FILESAVE 101
00082 #define EXIT_ERR_OPT 102
00083 
00084 
00085 // COMMAND-LINE-OPTION SPECIFIC DEFINITIONS
00086 // using getopt.h library (specifically getopt_long())
00087 
00088 // flags
00089 int opt_interactive = -1; // -1: not specified, 0: NOT interactive, 1: interactive
00090 char *opt_input = NULL;
00091 char *opt_latexinput = NULL;
00092 int opt_paste = -1; // -1: don't paste, 1: paste clipboard, 2: paste selection
00093 bool opt_noeval = false;
00094 bool opt_base64arg = false;
00095 char *opt_output = NULL;
00096 char *opt_format = NULL;
00097 char *opt_fgcolor = NULL;
00098 char *opt_bgcolor = NULL;
00099 int opt_dpi = -1;
00100 char *opt_mathmode = NULL;
00101 char *opt_preamble = NULL;
00102 bool opt_quiet = false;
00103 char *opt_redirect_debug = NULL;
00104 bool opt_daemonize = false;
00105 bool opt_dbus_export_mainwin = false;
00106 bool opt_skip_plugins = false;
00107 
00108 int opt_outlinefonts = -1;
00109 int opt_lborderoffset = -1;
00110 int opt_tborderoffset = -1;
00111 int opt_rborderoffset = -1;
00112 int opt_bborderoffset = -1;
00113 
00114 char *opt_tempdir;
00115 char *opt_latex;
00116 char *opt_dvips;
00117 char *opt_gs;
00118 char *opt_epstopdf;
00119 
00120 bool opt_help_requested = false;
00121 FILE * opt_help_fp = stderr;
00122 bool opt_version_requested = false;
00123 FILE * opt_version_fp = stderr;
00124 char *opt_version_format = (char*)"KLatexFormula: Version %k using Qt %q\n";
00125 
00126 char **klf_args;
00127 
00128 int qt_argc;
00129 char *qt_argv[1024];
00130 
00131 // We will occasionally need to strdup some strings to keep persistent copies. Save these copies
00132 // in this array, so that we can free() them in main_exit().
00133 char *opt_strdup_free_list[64] = { NULL };
00134 int opt_strdup_free_list_n = 0;
00135 
00136 
00137 static struct { bool has_error; int retcode; } opt_error;
00138 
00139 // option identifiers
00140 enum {
00141   // if you change short options here, be sure to change the short option list below.
00142   OPT_INTERACTIVE = 'I',
00143   OPT_INPUT = 'i',
00144   OPT_LATEXINPUT = 'l',
00145   OPT_PASTE_CLIPBOARD = 'P',
00146   OPT_PASTE_SELECTION = 'S',
00147   OPT_NOEVAL = 'n',
00148   OPT_BASE64ARG = 'B',
00149   OPT_OUTPUT = 'o',
00150   OPT_FORMAT = 'F',
00151   OPT_FGCOLOR = 'f',
00152   OPT_BGCOLOR = 'b',
00153   OPT_DPI = 'X',
00154   OPT_MATHMODE = 'm',
00155   OPT_PREAMBLE = 'p',
00156   OPT_QUIET = 'q',
00157   OPT_DAEMONIZE = 'd',
00158 
00159   OPT_HELP = 'h',
00160   OPT_VERSION = 'V',
00161 
00162   OPT_QTOPT = 'Q',
00163 
00164   OPT_OUTLINEFONTS = 127,
00165   OPT_LBORDEROFFSET,
00166   OPT_TBORDEROFFSET,
00167   OPT_RBORDEROFFSET,
00168   OPT_BBORDEROFFSET,
00169   OPT_TEMPDIR,
00170   OPT_LATEX,
00171   OPT_DVIPS,
00172   OPT_GS,
00173   OPT_EPSTOPDF,
00174 
00175   OPT_DBUS_EXPORT_MAINWIN,
00176   OPT_SKIP_PLUGINS,
00177   OPT_REDIRECT_DEBUG
00178 };
00179 
00185 static struct option klfcmdl_optlist[] = {
00186   { "interactive", 0, NULL, OPT_INTERACTIVE },
00187   { "input", 1, NULL, OPT_INPUT },
00188   { "latexinput", 1, NULL, OPT_LATEXINPUT },
00189   { "paste-clipboard", 0, NULL, OPT_PASTE_CLIPBOARD },
00190   { "paste-selection", 0, NULL, OPT_PASTE_SELECTION },
00191   { "noeval", 0, NULL, OPT_NOEVAL },
00192   { "base64arg", 0, NULL, OPT_BASE64ARG },
00193   { "output", 1, NULL, OPT_OUTPUT },
00194   { "format", 1, NULL, OPT_FORMAT },
00195   { "fgcolor", 1, NULL, OPT_FGCOLOR },
00196   { "bgcolor", 1, NULL, OPT_BGCOLOR },
00197   { "dpi", 1, NULL, OPT_DPI },
00198   { "mathmode", 1, NULL, OPT_MATHMODE },
00199   { "preamble", 1, NULL, OPT_PREAMBLE },
00200   { "quiet", 2, NULL, OPT_QUIET },
00201   { "redirect-debug", 1, NULL, OPT_REDIRECT_DEBUG },
00202   { "daemonize", 0, NULL, OPT_DAEMONIZE },
00203   { "dbus-export-mainwin", 0, NULL, OPT_DBUS_EXPORT_MAINWIN },
00204   { "skip-plugins", 2, NULL, OPT_SKIP_PLUGINS },
00205   // -----
00206   { "outlinefonts", 2 /*optional arg*/, NULL, OPT_OUTLINEFONTS },
00207   { "lborderoffset", 1, NULL, OPT_LBORDEROFFSET },
00208   { "tborderoffset", 1, NULL, OPT_TBORDEROFFSET },
00209   { "rborderoffset", 1, NULL, OPT_RBORDEROFFSET },
00210   { "bborderoffset", 1, NULL, OPT_BBORDEROFFSET },
00211   // -----
00212   { "tempdir", 1, NULL, OPT_TEMPDIR },
00213   { "latex", 1, NULL, OPT_LATEX },
00214   { "dvips", 1, NULL, OPT_DVIPS },
00215   { "gs", 1, NULL, OPT_GS },
00216   { "epstopdf", 1, NULL, OPT_EPSTOPDF },
00217   // -----
00218   { "help", 2, NULL, OPT_HELP },
00219   { "version", 2, NULL, OPT_VERSION },
00220   // -----
00221   { "qtoption", 1, NULL, OPT_QTOPT },
00222   // ---- end of option list ----
00223   {0, 0, 0, 0}
00224 };
00225 
00226 
00227 
00228 // TRAP SOME SIGNALS TO EXIT GRACEFULLY
00229 
00230 void signal_act(int sig)
00231 {
00232   FILE *ftty = NULL;
00233 #ifdef Q_OS_LINUX
00234   ftty = fopen("/dev/tty", "w");
00235 #endif
00236   if (ftty == NULL)
00237     ftty = stderr;
00238 
00239   if (sig == SIGINT) {
00240     fprintf(ftty, "Interrupt\n");
00241     if (ftty != stderr)  fprintf(stderr, "*** Interrupt\n");
00242 
00243     static long last_sigint_time = 0;
00244     long curtime;
00245     time(&curtime);
00246     bool isInsisted = (curtime - last_sigint_time <= 2); // re-pressed Ctrl-C after less than 2 secs
00247     if (!isInsisted && qApp != NULL) {
00248       qApp->quit();
00249       last_sigint_time = curtime;
00250     } else {
00251       fprintf(ftty, "Exiting\n");
00252       if (ftty != stderr)  fprintf(stderr, "*** Exiting\n");
00253       ::exit(128);
00254     }
00255   }
00256   if (sig == SIGSEGV) {
00257     fprintf(ftty, "Segmentation Fault :-(\n");
00258     if (ftty != stderr)  fprintf(stderr, "** Segmentation Fault :-( **\n");
00259 
00260     qApp->exit(127);
00261 
00262     // next time SIGSEGV is sent, use default handler (exit and dump core)
00263     signal(SIGSEGV, SIG_DFL);
00264   }
00265 }
00266 
00267 
00268 // DEBUG, WARNING AND FATAL MESSAGES HANDLER
00269 
00270 // redirect deboug output to this file (if non-NULL) instead of stderr
00271 static FILE *klf_qt_msg_fp = NULL;
00272 
00273 // in case we want to print messages directly into terminal
00274 static FILE *klf_fp_tty = NULL;
00275 static bool klf_fp_tty_failed = false;
00276 
00277 void klf_qt_message(QtMsgType type, const char *msg)
00278 {
00279   if (opt_quiet)
00280     return;
00281 
00282   FILE *fout = stderr;
00283   if (klf_qt_msg_fp != NULL)  fout = klf_qt_msg_fp;
00284 
00285 #ifdef Q_OS_LINUX
00286   if (klf_fp_tty == NULL && !klf_fp_tty_failed)
00287     if ( !(klf_fp_tty = fopen("/dev/tty", "w")) )
00288       klf_fp_tty_failed = true;
00289 #else
00290   Q_UNUSED(klf_fp_tty_failed) ;
00291 #endif
00292 
00293   switch (type) {
00294   case QtDebugMsg:
00295     // only with debugging enabled
00296 #ifdef KLF_DEBUG
00297     fprintf(fout, "D: %s\n", msg);
00298     fflush(fout);
00299 #endif
00300     break;
00301   case QtWarningMsg:
00302     fprintf(fout, "Warning: %s\n", msg);
00303     fflush(fout);
00304 #ifdef KLF_DEBUG
00305     // in debug mode, also print warning messages to TTY (because they get lost in the debug messages!)
00306     if (klf_fp_tty) fprintf(klf_fp_tty, "Warning: %s\n", msg);
00307 #endif
00308 
00309 #if defined Q_WS_WIN && defined KLF_DEBUG
00310 #  define   SAFECOUNTER_NUM   10
00311     // only show dialog after having created a QApplication
00312     if (qApp != NULL && qApp->inherits("QApplication")) {
00313       static int safecounter = SAFECOUNTER_NUM;
00314       if (safecounter-- >= 0) {
00315         if (!QString::fromLocal8Bit(msg).startsWith("MNG error")) { // ignore these "MNG" errors...
00316           QMessageBox::warning(0, "Warning",
00317                                QString("KLatexFormula System Warning:\n%1")
00318                                .arg(QString::fromLocal8Bit(msg)));
00319         }
00320       }
00321       if (safecounter == -1) {
00322         QMessageBox::information(0, "Information",
00323                                  QString("Shown %1 system warnings. Will stop displaying them.").arg(SAFECOUNTER_NUM));
00324         safecounter = -2;
00325       }
00326       if (safecounter < -2) safecounter = -2;
00327     }
00328 #endif
00329     break;
00330   case QtCriticalMsg:
00331     fprintf(fout, "Error: %s\n", msg);
00332     fflush(fout);
00333 #ifdef Q_WS_WIN
00334     if (qApp != NULL && qApp->inherits("QApplication")) {
00335       QMessageBox::critical(0, QObject::tr("Error", "[[KLF's Qt Message Handler: dialog title]]"),
00336                             QObject::tr("KLatexFormula System Error:\n%1",
00337                                         "[[KLF's Qt Message Handler: dialog text]]")
00338                             .arg(QString::fromLocal8Bit(msg)));
00339     }
00340 #endif
00341     break;
00342   case QtFatalMsg:
00343     fprintf(fout, "Fatal: %s\n", msg);
00344     fflush(fout);
00345 #ifdef Q_WS_WIN
00346     if (qApp != NULL && qApp->inherits("QApplication")) {
00347       QMessageBox::critical(0, QObject::tr("FATAL ERROR",
00348                                            "[[KLF's Qt Message Handler: dialog title]]"),
00349                             QObject::tr("KLatexFormula System FATAL ERROR:\n%1",
00350                                         "[[KLF's Qt Message Handler: dialog text]]")
00351                             .arg(QString::fromLocal8Bit(msg)));
00352     }
00353 #endif
00354     ::exit(255);
00355   default:
00356     fprintf(fout, "?????: %s\n", msg);
00357     fflush(fout);
00358     break;
00359   }
00360 }
00361 
00362 
00363 
00364 
00365 
00366 // UTILITY FUNCTIONS
00367 
00368 
00369 void main_parse_options(int argc, char *argv[]);
00370 
00372 void main_cleanup()
00373 {
00375   // FIXME: under windows, we have a proliferation of qt_temp.XXXXXX files
00376   //   in local plugin directory, what's going on?
00377   QDir pdir(klfconfig.homeConfigDirPlugins);
00378   QStringList qttempfiles = pdir.entryList(QStringList() << "qt_temp.??????", QDir::Files);
00379   foreach(QString s, qttempfiles) {
00380     QFile::remove(pdir.absoluteFilePath(s));
00381   }
00382   // free strdup()'ed strings
00383   while (--opt_strdup_free_list_n >= 0)
00384     free(opt_strdup_free_list[opt_strdup_free_list_n]);
00385 
00386 }
00387 
00389 void main_exit(int code)
00390 {
00391   main_cleanup();
00392   exit(code);
00393 }
00394 
00400 QString main_get_input(char *input, char *latexinput, int paste)
00401 {
00402   QString latex;
00403   if (latexinput != NULL && strlen(latexinput) != 0) {
00404     latex += QString::fromLocal8Bit(latexinput);
00405   }
00406   if (input != NULL && strlen(input) != 0) {
00407     QString fname = QString::fromLocal8Bit(input);
00408     QFile f;
00409     if ( fname == "-" ) {
00410       if ( ! f.open(stdin, QIODevice::ReadOnly) ) {
00411         qCritical("%s", qPrintable(QObject::tr("Can't read standard input (!)")));
00412         main_exit(EXIT_ERR_FILEINPUT);
00413       }
00414     } else {
00415       f.setFileName(fname);
00416       if ( ! f.open(QIODevice::ReadOnly) ) {
00417         qCritical("%s", qPrintable(QObject::tr("Can't read input file `%1'.").arg(fname)));
00418         main_exit(EXIT_ERR_FILEINPUT);
00419       }
00420     }
00421     // now file is opened properly.
00422     QByteArray contents = f.readAll();
00423     // contents is assumed to be local 8 bit encoding.
00424     latex += QString::fromLocal8Bit(contents);
00425   }
00426   if (paste >= 0) {
00427     if (!qApp->inherits("QApplication")) {
00428       qWarning("%s",
00429                qPrintable(QObject::tr("--paste-{clipboard|selection} requires interactive mode. Ignoring option.")));
00430     } else {
00431       if (paste == 1)
00432         latex += QApplication::clipboard()->text();
00433       else
00434         latex += QApplication::clipboard()->text(QClipboard::Selection);
00435     }
00436   }
00437 
00438   return latex;
00439 }
00440 
00443 void main_save(KLFBackend::klfOutput klfoutput, const QString& f_output, QString format)
00444 {
00445   KLFBackend::saveOutputToFile(klfoutput, f_output, format);
00446 }
00447 
00448 void main_load_extra_resources()
00449 {
00450   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00451 
00452   // this function is called with running Q[Core]Application and klfconfig all set up.
00453 
00454   QStringList env = QProcess::systemEnvironment();
00455   QRegExp rgx("^" KLF_RESOURCES_ENVNAM "=");
00456   QStringList klf_resources_l = env.filter(rgx);
00457   QString klf_resources = QString::null;
00458   if (klf_resources_l.size() > 0) {
00459     klf_resources = klf_resources_l[0].replace(rgx, "");
00460   }
00461 
00462   bool klfsettings_can_import = false;
00463 
00464   // Find global system-wide klatexformula rccresources dir
00465   QStringList defaultrccpaths;
00466 #ifdef KLF_SHARE_RCCRESOURCES_DIR
00467   defaultrccpaths << klfPrefixedPath(KLF_SHARE_RCCRESOURCES_DIR); // prefixed by app-dir-path
00468 #endif
00469   defaultrccpaths << klfconfig.globalShareDir+"/rccresources/";
00470   defaultrccpaths << klfconfig.homeConfigDirRCCResources;
00471   klfDbg("RCC search path is "<<defaultrccpaths.join(QString()+KLF_PATH_SEP)) ;
00472   QString rccfilepath;
00473   if ( klf_resources.isNull() ) {
00474     rccfilepath = "";
00475   } else {
00476     rccfilepath = klf_resources;
00477   }
00478   //  printf("DEBUG: Rcc file list is \"%s\"\n", rccfilepath.toLocal8Bit().constData());
00479   QStringList rccfiles = rccfilepath.split(KLF_PATH_SEP, QString::KeepEmptyParts);
00480   int j, k;
00481   for (QStringList::iterator it = rccfiles.begin(); it != rccfiles.end(); ++it) {
00482     if ((*it).isEmpty()) {
00483       // empty split section: meaning that we want default paths at this point
00484       it = rccfiles.erase(it, it+1);
00485       for (j = 0; j < defaultrccpaths.size(); ++j) {
00486         it = rccfiles.insert(it, defaultrccpaths[j]) + 1;
00487       }
00488       // having the default paths added, it is safe for klfsettings to import add-ons to ~/.klf.../rccresources/
00489       klfsettings_can_import = true;
00490       --it; // we already point to the next entry, compensate the ++it in for
00491     }
00492   }
00493   QStringList rccfilesToLoad;
00494   for (j = 0; j < rccfiles.size(); ++j) {
00495     QFileInfo fi(rccfiles[j]);
00496     if (fi.isDir()) {
00497       QDir dir(rccfiles[j]);
00498       QFileInfoList files = dir.entryInfoList(QStringList()<<"*.rcc", QDir::Files);
00499       for (k = 0; k < files.size(); ++k) {
00500         QString f = files[k].canonicalFilePath();
00501         if (!rccfilesToLoad.contains(f))
00502           rccfilesToLoad << f;
00503       }
00504     } else if (fi.isFile() && fi.suffix() == "rcc") {
00505       QString f = fi.canonicalFilePath();
00506       if (!rccfilesToLoad.contains(f))
00507         rccfilesToLoad << f;
00508     }
00509   }
00510   for (j = 0; j < rccfilesToLoad.size(); ++j) {
00511     KLFAddOnInfo addoninfo(rccfilesToLoad[j]);
00512     // resource registered.
00513     klf_addons.append(addoninfo);
00514     klfDbg("registered resource "<<addoninfo.fpath()<<".") ;
00515   }
00516 
00517   // set the global "can-import" flag
00518   klf_addons_canimport = klfsettings_can_import;
00519 
00520   void dumpDir(const QDir&, int = 0);
00521   klfDbg( "dump of :/ :" ) ;
00522   dumpDir(QDir(":/"));
00523 }
00524 
00525 
00526 void dumpDir(const QDir& d, int indent = 0)
00527 {
00528   char sindent[] = "                                                               ";
00529   uint nindent = indent*2; // 2 spaces per indentation
00530   if (nindent < strlen(sindent))
00531     sindent[nindent] = '\0';
00532 
00533   QStringList dchildren = d.entryList(QDir::Dirs);
00534 
00535   int k;
00536   for (k = 0; k < dchildren.size(); ++k) {
00537     // skip system ":/trolltech"
00538     if (indent == 0 && dchildren[k] == "trolltech")
00539       continue;
00540     qDebug("%s%s/", sindent, qPrintable(dchildren[k]));
00541     dumpDir(QDir(d.absoluteFilePath(dchildren[k])), indent+1);
00542   }
00543 
00544   QStringList fchildren = d.entryList(QDir::Files);
00545   for (k = 0; k < fchildren.size(); ++k) {
00546     qDebug("%s%s", sindent, qPrintable(fchildren[k]));
00547   }
00548 }
00549 
00551 class VersionCompareWithPrefixGreaterThan {
00552   int prefixLen;
00553 public:
00555   VersionCompareWithPrefixGreaterThan(const QString& prefix) : prefixLen(prefix.length()) { }
00556   bool operator()(const QString& a, const QString& b) {
00557     return klfVersionCompare(a.mid(prefixLen), b.mid(prefixLen)) > 0;
00558   }
00559 };
00560 
00561 void main_load_plugins(QApplication *app, KLFMainWin *mainWin)
00562 {
00563   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00564 
00565   QStringList baseplugindirs =
00566     QStringList() << klfconfig.homeConfigDirPlugins << klfconfig.globalShareDir+"/plugins";
00567 
00568   klfDbg("base plugins dirs are "<<baseplugindirs) ;
00569 
00570   // first step: copy all resource-located plugin libraries to our local config
00571   // directory because we can only load filesystem-located plugins.
00572   int i, k, j;
00573   for (k = 0; k < klf_addons.size(); ++k) {
00574     QStringList pluginList = klf_addons[k].pluginList();
00575     for (j = 0; j < pluginList.size(); ++j) {
00576       KLFAddOnInfo::PluginSysInfo psinfo = klf_addons[k].pluginSysInfo(pluginList[j]);
00577       klfDbg( "Testing plugin psinfo="<<psinfo<<"\n\tTo our system: qtver="<<qVersion()
00578               <<"; klfver="<<KLF_VERSION_STRING<<"; os="<<KLFSysInfo::osString()
00579               <<"; arch="<<KLFSysInfo::arch() ) ;
00580       if ( psinfo.isCompatibleWithCurrentSystem() ) {
00581         // ok to install plugin
00582         QString resfn = klf_addons[k].rccmountroot() + "/plugins/" + pluginList[j];
00583         QString locsubdir = klf_addons[k].pluginLocalSubDirName(pluginList[j]);
00584         QString locfn = klfconfig.homeConfigDirPlugins + "/" + locsubdir + "/"
00585           + QFileInfo(pluginList[j]).fileName();
00586         QDateTime installedplugin_dt = QFileInfo(locfn).lastModified();
00587         QDateTime resourceplugin_dt = QFileInfo(klf_addons[k].fpath()).lastModified();
00588         qDebug("Comparing resource datetime (%s) with installed plugin datetime (%s)",
00589                qPrintable(resourceplugin_dt.toString()), qPrintable(installedplugin_dt.toString()));
00590         if (  ! QFile::exists( locfn ) ||
00591               installedplugin_dt.isNull() || resourceplugin_dt.isNull() ||
00592               ( resourceplugin_dt > installedplugin_dt )  ) {
00593           // create path to that plugin dir
00594           if (!locsubdir.isEmpty() &&
00595               !QDir(klfconfig.homeConfigDirPlugins + "/plugins/" + locsubdir).exists())
00596             QDir(klfconfig.homeConfigDirPlugins).mkpath(locsubdir);
00597           // remove old version if exists
00598           if (QFile::exists(locfn)) QFile::remove(locfn);
00599           // copy plugin to local plugin dir
00600           klfDbg( "\tcopy "<<resfn<<" to "<<locfn ) ;
00601           bool res = QFile::copy( resfn , locfn );
00602           if ( ! res ) {
00603             qWarning("Unable to copy plugin '%s' to local directory!", qPrintable(pluginList[j]));
00604           } else {
00605             QFile::setPermissions(locfn, QFile::ReadOwner|QFile::WriteOwner|QFile::ExeOwner|
00606                                   QFile::ReadUser|QFile::WriteUser|QFile::ExeUser|
00607                                   QFile::ReadGroup|QFile::ExeGroup|QFile::ReadOther|QFile::ExeOther);
00608             qDebug("Copied plugin %s to local directory %s.", qPrintable(resfn), qPrintable(locfn));
00609           }
00610         }
00611       }
00612       // OK, plugin locally installed.
00613     }
00614   }
00615 
00616   // explore all base plugins dir, eg. /usr/share/klatexformula/plugins, and ~/.klatexformula/plugins/
00617   int n;
00618   for (n = 0; n < baseplugindirs.size(); ++n) {
00619     QString baseplugindir = baseplugindirs[n];
00620     klfDbg("exploring base plugin directory "<<baseplugindir) ;
00621     // build a list of plugin directories to search. We will need to load plugins in our version directory
00622     // + all prior version directories + root plugin path.
00623     QStringList pluginsdirs;
00624     // For each path in pluginsdirs, in this array (at same index pos) we have the relative path from baseplugindir.
00625     QStringList pluginsdirsbaserel;
00626     QDir pdir(baseplugindir);
00627     QStringList pdirlist = pdir.entryList(QStringList()<<"klf*", QDir::Dirs);
00628     // sort plugin dirs so that for a plugin existing in multiple versions, we load the one for the
00629     // most recent first, then ignore the others.
00630     qSort(pdirlist.begin(), pdirlist.end(), VersionCompareWithPrefixGreaterThan("klf"));
00631     for (i = 0; i < pdirlist.size(); ++i) {
00632       klfDbg( "maybe adding plugin dir"<<pdirlist[i]<<"; klfver="<<pdirlist[i].mid(3) ) ;
00633       if (klfVersionCompare(pdirlist[i].mid(3), KLF_VERSION_STRING) <= 0) { // Version OK
00634         pluginsdirs << pdir.absoluteFilePath(pdirlist[i]) ;
00635         pluginsdirsbaserel << pdirlist[i]+"/";
00636       }
00637     }
00638     pluginsdirs << klfconfig.homeConfigDirPlugins ;
00639     pluginsdirsbaserel << "" ;
00640 
00641     klfDbg( "pluginsdirs="<<pluginsdirs ) ;
00642     
00643     for (i = 0; i < pluginsdirs.size(); ++i) {
00644       if ( ! QFileInfo(pluginsdirs[i]).isDir() )
00645         continue;
00646 
00647       QDir thisplugdir(pluginsdirs[i]);
00648       QStringList plugins = thisplugdir.entryList(KLF_DLL_EXT_LIST, QDir::Files);
00649       KLFPluginGenericInterface * pluginInstance;
00650       for (j = 0; j < plugins.size(); ++j) {
00651         QString pluginfname = plugins[j];
00652         QString pluginfnamebaserel = pluginsdirsbaserel[i]+plugins[j];
00653         bool plugin_already_loaded = false;
00654         int k;
00655         for (k = 0; k < klf_plugins.size(); ++k) {
00656           if (QFileInfo(klf_plugins[k].fname).fileName() == pluginfname) {
00657             klfDbg( "Rejecting loading of plugin "<<pluginfname<<" in dir "<<pluginsdirs[i]
00658                     <<"; already loaded." ) ;
00659             plugin_already_loaded = true;
00660             break;
00661           }
00662         }
00663         if (plugin_already_loaded)
00664           continue;
00665         QString pluginpath = thisplugdir.absoluteFilePath(pluginfname);
00666         QPluginLoader pluginLoader(pluginpath, app);
00667         bool loaded = pluginLoader.load();
00668         if (!loaded) {
00669           klfDbg("QPluginLoader failed to load plugin "<<pluginpath<<". Skipping.");
00670           continue;
00671         }
00672         QObject *pluginInstObject = pluginLoader.instance();
00673         if (pluginInstObject == NULL) {
00674           klfDbg("QPluginLoader failed to load plugin "<<pluginpath<<" (object is NULL). Skipping.");
00675           continue;
00676         }
00677         pluginInstance = qobject_cast<KLFPluginGenericInterface *>(pluginInstObject);
00678         if (pluginInstance == NULL) {
00679           klfDbg("QPluginLoader failed to load plugin "<<pluginpath<<" (instance is NULL). Skipping.");
00680           continue;
00681         }
00682         // plugin file successfully loaded.
00683         QString nm = pluginInstance->pluginName();
00684         klfDbg("Successfully loaded plugin library "<<nm<<" ("<<qPrintable(pluginInstance->pluginDescription())
00685                <<") from file "<<pluginfnamebaserel);
00686 
00687         if ( ! klfconfig.Plugins.pluginConfig.contains(nm) ) {
00688           // create default plugin configuration if non-existant
00689           klfconfig.Plugins.pluginConfig[nm] = QMap<QString, QVariant>();
00690           // ask plugin whether it's supposed to be loaded by default
00691           klfconfig.Plugins.pluginConfig[nm]["__loadenabled"] =
00692             pluginInstance->pluginDefaultLoadEnable();
00693         }
00694         bool keepPlugin = true;
00695 
00696         // make sure this plugin wasn't already loaded (eg. in a different klf-version sub-dir)
00697         bool pluginRejected = false;
00698         for (k = 0; k < klf_plugins.size(); ++k) {
00699           if (klf_plugins[k].name == nm) {
00700             klfDbg( "Rejecting loading of plugin "<<nm<<" in "<<pluginfname<<"; already loaded." ) ;
00701             pluginLoader.unload();
00702             pluginRejected = true;
00703             break;
00704           }
00705         }
00706         if (pluginRejected)
00707           continue;
00708 
00709         KLFPluginInfo pluginInfo;
00710         pluginInfo.name = nm;
00711         pluginInfo.title = pluginInstance->pluginTitle();
00712         pluginInfo.description = pluginInstance->pluginDescription();
00713         pluginInfo.author = pluginInstance->pluginAuthor();
00714         pluginInfo.fname = pluginfnamebaserel;
00715         pluginInfo.fpath = pluginpath;
00716         pluginInfo.instance = NULL;
00717 
00718         // if we are configured to load this plugin, load it.
00719         keepPlugin = keepPlugin && klfconfig.Plugins.pluginConfig[nm]["__loadenabled"].toBool();
00720         klfDbg("got plugin info. keeping plugin? "<<keepPlugin);
00721         if ( keepPlugin ) {
00722           KLFPluginConfigAccess pgca = klfconfig.getPluginConfigAccess(nm);
00723           KLFPluginConfigAccess * c = new KLFPluginConfigAccess(pgca);
00724           klfDbg("prepared a configaccess "<<c);
00725           pluginInstance->initialize(app, mainWin, c);
00726           pluginInfo.instance = pluginInstance;
00727           qDebug("\tPlugin %s loaded and initialized.", qPrintable(nm));
00728         } else {
00729           // if we aren't configured to load it, then discard it, but keep info with NULL instance,
00730           // so that user can configure to load or not this plugin in the settings dialog.
00731           delete pluginInstance;
00732           pluginInfo.instance = NULL;
00733           qDebug("\tPlugin %s NOT loaded.", qPrintable(nm));
00734         }
00735         klf_plugins.push_back(pluginInfo);
00736       }
00737     }
00738   }
00739 }
00740 
00741 
00742 
00743 
00744 // function to set up the Q[Core]Application correctly
00745 void main_setup_app(QCoreApplication *a)
00746 {
00747   a->setApplicationName(QLatin1String("KLatexFormula"));
00748   a->setApplicationVersion(QLatin1String(KLF_VERSION_STRING));
00749   a->setOrganizationDomain(QLatin1String("klatexformula.org"));
00750   a->setOrganizationName(QLatin1String("KLatexFormula"));
00751 
00752 #ifdef KLF_LIBKLFTOOLS_STATIC
00753   Q_INIT_RESOURCE(klftoolsres) ;
00754 #endif
00755 #ifdef KLF_LIBKLFAPP_STATIC
00756   Q_INIT_RESOURCE(klfres) ;
00757 #endif
00758 
00759   // add [share dir]/qt-plugins to library path.
00760   // under windows, that is were plugins are packaged with the executable
00761   extern QString klf_share_dir_abspath();
00762   QCoreApplication::addLibraryPath(klf_share_dir_abspath()+"/qt-plugins");
00763 
00764   klfDbg("Library paths are:\n"<<qPrintable(QCoreApplication::libraryPaths().join("\n")));
00765 
00766   qRegisterMetaType< QImage >("QImage");
00767   qRegisterMetaType< KLFStyle >();
00768   qRegisterMetaTypeStreamOperators< KLFStyle >("KLFStyle");
00769   qRegisterMetaType< KLFLibEntry >();
00770   qRegisterMetaTypeStreamOperators< KLFLibEntry >("KLFLibEntry");
00771   qRegisterMetaType< KLFLibResourceEngine::KLFLibEntryWithId >();
00772   qRegisterMetaTypeStreamOperators< KLFLibResourceEngine::KLFLibEntryWithId >
00773     /* */  ("KLFLibResourceEngine::KLFLibEntryWithId");
00774 
00775   // for delayed calls in klflibview.cpp
00776   qRegisterMetaType< QItemSelection >("QItemSelection");
00777   qRegisterMetaType< QItemSelectionModel::SelectionFlags >("QItemSelectionModel::SelectionFlags");
00778 }
00779 
00780 
00781 // OUR MAIN FUNCTION
00782 
00783 int main(int argc, char **argv)
00784 {
00785   int k;
00786   klfDbgT("$$main()$$") ;
00787 
00788   qInstallMsgHandler(klf_qt_message);
00789 
00790   //  // DEBUG: command-line arguments
00791   //  for (int jjj = 0; jjj < argc; ++jjj)
00792   //    qDebug("arg: %s", argv[jjj]);
00793 
00794   // signal acting -- catch SIGINT to exit gracefully
00795   signal(SIGINT, signal_act);
00796   // signal acting -- catch SIGSEGV to attempt graceful exit
00797   signal(SIGSEGV, signal_act);
00798 
00799   klfDbg("about to parse options") ;
00800 
00801   // parse command-line options
00802   main_parse_options(argc, argv);
00803 
00804   klfDbg("options parsed.") ;
00805 
00806   // error handling
00807   if (opt_error.has_error) {
00808     qCritical("Error while parsing command-line arguments.");
00809     qCritical("Use --help to display command-line help.");
00810     main_exit(EXIT_ERR_OPT);
00811   }
00812 
00813   // redirect debug output if requested
00814   if (opt_redirect_debug != NULL) {
00815     // force the file name to end in .klfdebug to make sure we don't overwrite an important file
00816     char fname[1024];
00817     const char * SUFFIX = ".klfdebug";
00818     strcpy(fname, opt_redirect_debug);
00819     if (strncmp(fname+(strlen(fname)-strlen(SUFFIX)), SUFFIX, strlen(SUFFIX)) != 0) {
00820       // fname does not end with SUFFIX
00821       strcat(fname, SUFFIX);
00822     }
00823     // before performing the redirect...
00824     klfDbg("Redirecting debug output to file "<<QString::fromLocal8Bit(fname)) ;
00825     klf_qt_msg_fp = fopen(fname, "w");
00826     KLF_ASSERT_NOT_NULL( klf_qt_msg_fp, "debug output redirection failed." , /* no fail action */; ) ;
00827     if (klf_qt_msg_fp != NULL) {
00828       fprintf(klf_qt_msg_fp, "\n\n"
00829               "-------------------------------------------------\n"
00830               "  KLATEXFORMULA DEBUG OUTPUT\n"
00831               "-------------------------------------------------\n"
00832               "Started on %s\n\n",
00833               qPrintable(QDateTime::currentDateTime().toString(Qt::DefaultLocaleLongDate)));
00834     }
00835   }
00836 
00837   if ( opt_interactive ) {
00838     // save the qt_argv options separately to pass them to daemonized process if needed, before
00839     // QApplication modifies the qt_argv array
00840     QStringList qtargvlist;
00841     for (k = 0; k < qt_argc && qt_argv[k] != NULL; ++k)
00842       qtargvlist << QString::fromLocal8Bit(qt_argv[k]);
00843 
00844     // Create the QApplication
00845     QApplication app(qt_argc, qt_argv);
00846 
00847 #ifdef Q_WS_MAC
00848     extern void __klf_init_the_macpasteboardmime();
00849     __klf_init_the_macpasteboardmime();
00850 #endif
00851 
00852     // add our default application font(s) ;-)
00853     QFileInfoList appFontsInfoList = QDir(":/data/fonts/").entryInfoList(QStringList()<<"*.otf"<<"*.ttf");
00854     int k;
00855     for (k = 0; k < appFontsInfoList.size(); ++k) {
00856       QFontDatabase::addApplicationFont(appFontsInfoList[k].absoluteFilePath());
00857     }
00858 
00859     // main_get_input relies on a Q[Core]Application
00860     QString latexinput = main_get_input(opt_input, opt_latexinput, opt_paste);
00861 
00862     // see if we have to daemonize
00863     if ( opt_daemonize ) {
00864       // try to start detached process, with our arguments. This is preferred to feeding D-BUS input
00865       // to the new process, since we cannot be sure this system supports D-BUS, and we would have
00866       // to wait to see the new process appear, etc. and I really don't see the big advantage over
00867       // cmdl options here.
00868       QString progexe = QCoreApplication::applicationFilePath();
00869       QStringList args;
00870       args << "-I";
00871       if (!latexinput.isNull())
00872         args << "--latexinput="+latexinput;
00873       if (opt_noeval)
00874         args << "--noeval";
00875       if (opt_output != NULL)
00876         args << "--output="+QString::fromLocal8Bit(opt_output);
00877       if (opt_format != NULL)
00878         args << "--format="+QString::fromLocal8Bit(opt_format);
00879       if (opt_fgcolor != NULL)
00880         args << "--fgcolor="+QString::fromLocal8Bit(opt_fgcolor);
00881       if (opt_bgcolor != NULL)
00882         args << "--bgcolor="+QString::fromLocal8Bit(opt_bgcolor);
00883       if (opt_dpi >= 0)
00884         args << "--dpi="+QString::number(opt_dpi);
00885       if (opt_mathmode != NULL)
00886         args << "--mathmode="+QString::fromLocal8Bit(opt_mathmode);
00887       if (opt_preamble != NULL)
00888         args << "--preamble="+QString::fromLocal8Bit(opt_preamble);
00889       if (opt_quiet)
00890         args << "--quiet";
00891       if (opt_redirect_debug != NULL)
00892         args << "--redirect-debug="+QString::fromLocal8Bit(opt_redirect_debug);
00893       if (opt_outlinefonts >= 0)
00894         args << "--outlinefonts="+QString::fromLatin1(opt_outlinefonts?"TRUE":"FALSE");
00895       const struct { char c; int optval; } borderoffsets[] =
00896                                              { {'t', opt_tborderoffset}, {'r', opt_rborderoffset},
00897                                                {'b', opt_bborderoffset}, {'l', opt_lborderoffset},
00898                                                {'\0', -1} };
00899       for (k = 0; borderoffsets[k].c != 0; ++k)
00900         if (borderoffsets[k].optval != -1)
00901           args << (QString::fromLatin1("--")+QLatin1Char(borderoffsets[k].c)+"borderoffset="
00902                    +QString::number(borderoffsets[k].optval)) ;
00903       if (opt_tempdir != NULL)
00904         args << "--tempdir="+QString::fromLocal8Bit(opt_tempdir);
00905       if (opt_latex != NULL)
00906         args << "--latex="+QString::fromLocal8Bit(opt_latex);
00907       if (opt_dvips != NULL)
00908         args << "--dvips="+QString::fromLocal8Bit(opt_dvips);
00909       if (opt_gs != NULL)
00910         args << "--gs="+QString::fromLocal8Bit(opt_gs);
00911       if (opt_epstopdf != NULL)
00912         args << "--epstopdf="+QString::fromLocal8Bit(opt_epstopdf);
00913       for (k = 0; k < qtargvlist.size(); ++k)
00914         args << "--qtoption="+qtargvlist[k];
00915       // add additional args
00916       for (k = 0; klf_args[k] != NULL; ++k)
00917         args << QString::fromLocal8Bit(klf_args[k]);
00918 
00919       klfDbg("Prepared deamonized process' command-line: progexe="<<progexe<<"; args="<<args) ;
00920       // now launch the klatexformula 'daemon' process
00921       qint64 pid;
00922       bool result = QProcess::startDetached(progexe, args, QDir::currentPath(), &pid);
00923       if (result) { // Success
00924         if (!opt_quiet)
00925           fprintf(stderr, "%s",
00926                   qPrintable(QObject::tr("KLatexFormula Daemon Process successfully launched with pid %1\n")
00927                              .arg(pid)));
00928         return 0;
00929       }
00930       qWarning()<<qPrintable(QObject::tr("Failed to launch daemon process. Not daemonizing."));
00931     }
00932 
00933     main_setup_app(&app);
00934 
00935 #if defined(KLF_USE_DBUS)
00936     // see if an instance of KLatexFormula is running...
00937     KLFDBusAppInterface *iface
00938       = new KLFDBusAppInterface("org.klatexformula.KLatexFormula", "/MainApplication",
00939                                 QDBusConnection::sessionBus(), &app);
00940     if (iface->isValid()) {
00941       iface->raiseWindow();
00942       // load everything via DBus
00943       if ( opt_fgcolor != NULL )
00944         iface->setInputData("fgcolor", opt_fgcolor);
00945       if ( opt_bgcolor != NULL )
00946         iface->setInputData("bgcolor", opt_bgcolor);
00947       if ( opt_dpi > 0 )
00948         iface->setInputData("dpi", QString::null, opt_dpi);
00949       if (opt_mathmode != NULL)
00950         iface->setInputData("mathmode", QString::fromLocal8Bit(opt_mathmode));
00951       if (opt_preamble != NULL)
00952         iface->setInputData("preamble", QString::fromLocal8Bit(opt_preamble));
00953       // load latex after preamble, so that the interface doesn't prompt to include missing packages
00954       if ( ! latexinput.isNull() )
00955         iface->setInputData("latex", latexinput);
00956       if (opt_outlinefonts >= 0)
00957         iface->setAlterSetting_i(KLFMainWin::altersetting_OutlineFonts, opt_outlinefonts);
00958       if (opt_lborderoffset != -1)
00959         iface->setAlterSetting_i(KLFMainWin::altersetting_LBorderOffset, opt_lborderoffset);
00960       if (opt_tborderoffset != -1)
00961         iface->setAlterSetting_i(KLFMainWin::altersetting_TBorderOffset, opt_tborderoffset);
00962       if (opt_rborderoffset != -1)
00963         iface->setAlterSetting_i(KLFMainWin::altersetting_RBorderOffset, opt_rborderoffset);
00964       if (opt_bborderoffset != -1)
00965         iface->setAlterSetting_i(KLFMainWin::altersetting_BBorderOffset, opt_bborderoffset);
00966       if (opt_tempdir != NULL)
00967         iface->setAlterSetting_s(KLFMainWin::altersetting_TempDir, QString::fromLocal8Bit(opt_tempdir));
00968       if (opt_latex != NULL)
00969         iface->setAlterSetting_s(KLFMainWin::altersetting_Latex, QString::fromLocal8Bit(opt_latex));
00970       if (opt_dvips != NULL)
00971         iface->setAlterSetting_s(KLFMainWin::altersetting_Dvips, QString::fromLocal8Bit(opt_dvips));
00972       if (opt_gs != NULL)
00973         iface->setAlterSetting_s(KLFMainWin::altersetting_Gs, QString::fromLocal8Bit(opt_gs));
00974       if (opt_epstopdf != NULL)
00975         iface->setAlterSetting_s(KLFMainWin::altersetting_Epstopdf, QString::fromLocal8Bit(opt_epstopdf));
00976       // will actually save only if output is non empty.
00977       if (!opt_noeval || opt_output) {
00978         iface->evaluateAndSave(QString::fromLocal8Bit(opt_output), QString::fromLocal8Bit(opt_format));
00979       }
00980       // and import KLF files if wanted
00981       QStringList flist;
00982       for (int k = 0; klf_args[k] != NULL; ++k)
00983         flist << QString::fromLocal8Bit(klf_args[k]);
00984       iface->openFiles(flist);
00985       main_cleanup();
00986       return 0;
00987     }
00988 #endif
00989 
00990     if ( ! opt_quiet )
00991       fprintf(stderr, "KLatexFormula Version %s by Philippe Faist (c) 2005-2011\n"
00992               "Licensed under the terms of the GNU Public License GPL\n\n",
00993               KLF_VERSION_STRING);
00994 
00995     klfDbgT("$$About to load config$$");
00996   
00997     // now load default config
00998     klfconfig.loadDefaults(); // must be called before 'readFromConfig'
00999     klfconfig.readFromConfig();
01000     klfconfig.detectMissingSettings();
01001 
01002     klfDbgT("$$About to main_load_extra_resources$$");
01003     main_load_extra_resources();
01004 
01005     klfDbgT("$$About to main_reload_translations$$");
01006     klf_reload_translations(&app, klfconfig.UI.locale);
01007 
01008     KLFColorChooser::setUserMaxColors(klfconfig.UI.maxUserColors);
01009     KLFColorChooser::setColorList(klfconfig.UI.userColorList);
01010     KLFColorChooseWidget::setRecentCustomColors(klfconfig.UI.colorChooseWidgetRecent,
01011                                                 klfconfig.UI.colorChooseWidgetCustom);
01012 
01013     klfDbgT("$$About to create lib factories$$");
01014 
01015     // initialize and register some library resource engine + view factories
01016     (void)new KLFLibBasicWidgetFactory(qApp);
01017     (void)new KLFLibDBEngineFactory(qApp);
01018     (void)new KLFLibLegacyEngineFactory(qApp);
01019     (void)new KLFLibDefaultViewFactory(qApp);
01020 
01021     klfDbgT( "$$START LOADING$$" ) ;
01022 
01023     KLFMainWin mainWin;
01024 
01025     if (!klfconfig.UI.useSystemAppFont)
01026       app.setFont(klfconfig.UI.applicationFont);
01027 
01028     mainWin.refreshWindowSizes();
01029 
01030     if (!opt_skip_plugins)
01031       main_load_plugins(&app, &mainWin);
01032 
01033     mainWin.show();
01034 
01035     mainWin.startupFinished();
01036 
01037     klfDbgT( "$$END LOADING$$" ) ;
01038 
01039 #if defined(KLF_USE_DBUS)
01040     new KLFDBusAppAdaptor(&app, &mainWin);
01041     QDBusConnection dbusconn = QDBusConnection::sessionBus();
01042     dbusconn.registerService("org.klatexformula.KLatexFormula");
01043     dbusconn.registerObject("/MainApplication", &app);
01044     if (opt_dbus_export_mainwin)
01045       dbusconn.registerObject("/MainWindow/KLFMainWin", &mainWin, QDBusConnection::ExportAllContents
01046                               | QDBusConnection::ExportChildObjects);
01047 #endif
01048 
01049     // parse command-line given actions
01050 
01051     // consistency check warning
01052     if (opt_output && latexinput.isEmpty()) {
01053       qWarning("%s", qPrintable(QObject::tr("Can't use --output without any input")));
01054     }
01055 
01056     if ( ! latexinput.isNull() )
01057       mainWin.slotSetLatex(latexinput);
01058 
01059     if ( opt_fgcolor != NULL ) {
01060       mainWin.slotSetFgColor(QString::fromLocal8Bit(opt_fgcolor));
01061     }
01062     if ( opt_bgcolor != NULL ) {
01063       mainWin.slotSetBgColor(QString::fromLocal8Bit(opt_bgcolor));
01064     }
01065     if ( opt_dpi > 0 ) {
01066       mainWin.slotSetDPI(opt_dpi);
01067     }
01068     if (opt_mathmode != NULL) {
01069       mainWin.slotSetMathMode(QString::fromLocal8Bit(opt_mathmode));
01070     }
01071     if (opt_preamble != NULL) {
01072       qDebug("opt_preamble != NULL, gui mode, preamble=%s", opt_preamble);
01073       mainWin.slotSetPreamble(QString::fromLocal8Bit(opt_preamble));
01074     }
01075     if (opt_outlinefonts >= 0)
01076       mainWin.alterSetting(KLFMainWin::altersetting_OutlineFonts, opt_outlinefonts);
01077     if (opt_lborderoffset != -1)
01078       mainWin.alterSetting(KLFMainWin::altersetting_LBorderOffset, opt_lborderoffset);
01079     if (opt_tborderoffset != -1)
01080       mainWin.alterSetting(KLFMainWin::altersetting_TBorderOffset, opt_tborderoffset);
01081     if (opt_rborderoffset != -1)
01082       mainWin.alterSetting(KLFMainWin::altersetting_RBorderOffset, opt_rborderoffset);
01083     if (opt_bborderoffset != -1)
01084       mainWin.alterSetting(KLFMainWin::altersetting_BBorderOffset, opt_bborderoffset);
01085     if (opt_tempdir != NULL)
01086       mainWin.alterSetting(KLFMainWin::altersetting_TempDir, QString::fromLocal8Bit(opt_tempdir));
01087     if (opt_latex != NULL)
01088       mainWin.alterSetting(KLFMainWin::altersetting_Latex, QString::fromLocal8Bit(opt_latex));
01089     if (opt_dvips != NULL)
01090       mainWin.alterSetting(KLFMainWin::altersetting_Dvips, QString::fromLocal8Bit(opt_dvips));
01091     if (opt_gs != NULL)
01092       mainWin.alterSetting(KLFMainWin::altersetting_Gs, QString::fromLocal8Bit(opt_gs));
01093     if (opt_epstopdf != NULL)
01094       mainWin.alterSetting(KLFMainWin::altersetting_Epstopdf, QString::fromLocal8Bit(opt_epstopdf));
01095 
01096     if (!opt_noeval && opt_output) {
01097       // will actually save only if output is non empty.
01098       mainWin.slotEvaluateAndSave(QString::fromLocal8Bit(opt_output),
01099                                   QString::fromLocal8Bit(opt_format));
01100     }
01101 
01102 
01103     // IMPORT .klf (or other) files passed as arguments
01104     QStringList flist;
01105     for (int k = 0; klf_args[k] != NULL; ++k)
01106       flist << QString::fromLocal8Bit(klf_args[k]);
01107 
01108     QMetaObject::invokeMethod(&mainWin, "openFiles", Qt::QueuedConnection, Q_ARG(QStringList, flist));
01109 
01110     app.setQuitOnLastWindowClosed(false);
01111     int r = app.exec();
01112     main_cleanup();
01113     klfDbg("application has quit; we have cleaned up main(), ready to return. code="<<r) ;
01114     // and exit.
01115     // DO NOT CALL ::exit() as this prevents KLFMainWin's destructor from being called.
01116     // This includes not calling main_exit().
01117     return r;
01118 
01119   } else {
01120     // NON-INTERACTIVE (BATCH MODE, no X11)
01121 
01122     // Create the QCoreApplication
01123     QCoreApplication app(qt_argc, qt_argv);
01124 
01125     // main_get_input relies on a Q[Core]Application
01126     QString latexinput = main_get_input(opt_input, opt_latexinput, opt_paste);
01127 
01128     main_setup_app(&app);
01129 
01130     // now load default config
01131     klfconfig.loadDefaults(); // must be called before 'readFromConfig'
01132     klfconfig.readFromConfig();
01133     klfconfig.detectMissingSettings();
01134 
01135     main_load_extra_resources();
01136 
01137     klf_reload_translations(&app, klfconfig.UI.locale);
01138 
01139     // show version number ?
01140     if ( opt_version_requested ) {
01141       /* Remember: the format here should NOT change from one version to another, so that it
01142        * can be parsed eg. by scripts if needed. */
01143       QString version_string = QString::fromLocal8Bit(opt_version_format);
01144       version_string.replace(QLatin1String("%k"), QLatin1String(KLF_VERSION_STRING));
01145       version_string.replace(QLatin1String("%q"), QLatin1String(qVersion()));
01146       version_string.replace(QLatin1String("%%"), QLatin1String("%"));
01147       fprintf(opt_version_fp, "%s\n", qPrintable(version_string));
01148       main_exit(0);
01149     }
01150 
01151     // show program help ?
01152     if ( opt_help_requested ) {
01153       QFile cmdlHelpFile(klfFindTranslatedDataFile(":/data/cmdl-help", ".txt"));
01154       if (!cmdlHelpFile.open(QIODevice::ReadOnly)) {
01155         qWarning()<<KLF_FUNC_NAME<<": Can't access command-line-help file :/data/cmdl-help.txt!";
01156         main_exit(-1);
01157       }
01158       QString helpData = QString::fromUtf8(cmdlHelpFile.readAll());
01159       fprintf(opt_help_fp, "%s", helpData.toLocal8Bit().constData());
01160       main_exit(0);
01161     }
01162 
01163     if ( ! opt_quiet )
01164       fprintf(stderr, "KLatexFormula Version %s by Philippe Faist (c) 2005-2011\n"
01165               "Licensed under the terms of the GNU Public License GPL\n\n",
01166               KLF_VERSION_STRING);
01167 
01168     if ( opt_daemonize ) {
01169       qWarning()<<qPrintable(QObject::tr("The option --daemonize can only be used in interactive mode."));
01170     }
01171   
01172     // warn for ignored arguments
01173     for (int kl = 0; klf_args[kl] != NULL; ++kl)
01174       qWarning()<<qPrintable(QObject::tr("[Non-Interactive Mode] Ignoring additional command-line argument: %1")
01175                              .arg(klf_args[kl]));
01176 
01177 
01178     // now process required actions.
01179     KLFBackend::klfInput input;
01180     KLFBackend::klfSettings settings;
01181     KLFBackend::klfOutput klfoutput;
01182 
01183     if ( (opt_input == NULL || !strlen(opt_input)) &&
01184          (opt_latexinput == NULL || !strlen(opt_latexinput)) ) {
01185       // read from stdin by default
01186       opt_input = strdup("-");
01187       opt_strdup_free_list[opt_strdup_free_list_n++] = opt_input;
01188     }
01189 
01190     input.latex = latexinput;
01191 
01192     if (opt_mathmode != NULL) {
01193       input.mathmode = QString::fromLocal8Bit(opt_mathmode);
01194     } else {
01195       input.mathmode = "\\[ ... \\]";
01196     }
01197 
01198     if (opt_preamble != NULL) {
01199       input.preamble = QString::fromLocal8Bit(opt_preamble);
01200     } else {
01201       input.preamble = "";
01202     }
01203 
01204     if ( ! opt_fgcolor ) {
01205       opt_fgcolor = strdup("#000000");
01206       opt_strdup_free_list[opt_strdup_free_list_n++] = opt_fgcolor;
01207     }
01208     QColor fgcolor;
01209     fgcolor.setNamedColor(opt_fgcolor);
01210     input.fg_color = fgcolor.rgb();
01211     if ( ! opt_bgcolor ) {
01212       opt_bgcolor = strdup("-");
01213       opt_strdup_free_list[opt_strdup_free_list_n++] = opt_bgcolor;
01214     }
01215     QColor bgcolor;
01216     if (!strcmp(opt_bgcolor, "-"))
01217       bgcolor.setRgb(255, 255, 255, 0); // white transparent
01218     else
01219       bgcolor.setNamedColor(opt_bgcolor);
01220     input.bg_color = bgcolor.rgba();
01221 
01222     input.dpi = (opt_dpi > 0) ? opt_dpi : 1200;
01223 
01224     settings.outlineFonts = true;
01225     if (opt_outlinefonts >= 0)
01226       settings.outlineFonts = (bool)opt_outlinefonts;
01227     settings.lborderoffset = settings.tborderoffset
01228       = settings.rborderoffset = settings.bborderoffset = 1;
01229     if (opt_lborderoffset != -1)
01230       settings.lborderoffset = opt_lborderoffset;
01231     if (opt_tborderoffset != -1)
01232       settings.tborderoffset = opt_tborderoffset;
01233     if (opt_rborderoffset != -1)
01234       settings.rborderoffset = opt_rborderoffset;
01235     if (opt_bborderoffset != -1)
01236       settings.bborderoffset = opt_bborderoffset;
01237     settings.latexexec = klfconfig.BackendSettings.execLatex;
01238     settings.dvipsexec = klfconfig.BackendSettings.execDvips;
01239     settings.gsexec = klfconfig.BackendSettings.execGs;
01240     settings.epstopdfexec = klfconfig.BackendSettings.execEpstopdf;
01241     settings.tempdir = klfconfig.BackendSettings.tempDir;
01242 
01243     if (opt_tempdir != NULL)
01244       settings.tempdir = QString::fromLocal8Bit(opt_tempdir);
01245     if (opt_latex != NULL)
01246       settings.latexexec = QString::fromLocal8Bit(opt_latex);
01247     if (opt_dvips != NULL)
01248       settings.dvipsexec = QString::fromLocal8Bit(opt_dvips);
01249     if (opt_gs != NULL)
01250       settings.gsexec = QString::fromLocal8Bit(opt_gs);
01251     if (opt_epstopdf != NULL)
01252       settings.epstopdfexec = QString::fromLocal8Bit(opt_epstopdf);
01253 
01254     klfoutput = KLFBackend::getLatexFormula(input, settings);
01255 
01256     if (klfoutput.status != 0) {
01257       // error occurred
01258 
01259       if ( ! opt_quiet )
01260         fprintf(stderr, "%s\n", klfoutput.errorstr.toLocal8Bit().constData());
01261 
01262       main_exit(klfoutput.status);
01263     }
01264 
01265     QString output = QString::fromLocal8Bit(opt_output);
01266     QString format = QString::fromLocal8Bit(opt_format).trimmed().toUpper();
01267     main_save(klfoutput, output, format);
01268 
01269     main_exit( 0 );
01270   }
01271 
01272   main_exit( 0 );
01273 }
01274 
01275 
01276 // PARSE COMMAND-LINE OPTIONS
01277 
01278 FILE *main_msg_get_fp_arg(const char *arg)
01279 {
01280   FILE *fp = NULL;
01281   if (arg != NULL) {
01282     if (arg[0] == '&') { // file descriptor number
01283       int fd = atoi(&arg[1]);
01284       if (fd > 0)
01285         fp = fdopen(fd, "a");
01286       if (fd <= 0 || fp == NULL) {
01287         qWarning("Failed to open file descriptor %d.", fd);
01288         return stderr;
01289       }
01290       return fp;
01291     }
01292     if (!strcmp(arg, "-")) { // stdout
01293       return stdout;
01294     }
01295     // file name
01296     fp = fopen(arg, "a");
01297     if (fp == NULL) {
01298       qWarning("Failed to open file `%s' to print help message.", arg);
01299       return stderr;
01300     }
01301     return fp;
01302   }
01303   return stderr;
01304 }
01305 
01306 static bool __klf_parse_bool_arg(const char * arg, bool defaultvalue)
01307 {
01308   if (arg == NULL)
01309     return defaultvalue;
01310 
01311   QRegExp booltruerx = QRegExp("^\\s*on|y(es)?|1|t(rue)?\\s*", Qt::CaseInsensitive);
01312   QRegExp boolfalserx = QRegExp("^\\s*off|n(o)?|0|f(alse)?\\s*", Qt::CaseInsensitive);
01313 
01314   if ( booltruerx.exactMatch(arg) )
01315     return true;
01316   if ( boolfalserx.exactMatch(arg) )
01317     return false;
01318 
01319   qWarning()<<KLF_FUNC_NAME<<": Can't parse boolean argument: "<<QString(arg);
01320   opt_error.has_error = true;
01321   opt_error.retcode = -1;
01322 
01323   return defaultvalue;
01324 }
01325 
01326 void main_parse_options(int argc, char *argv[])
01327 {
01328   // argument processing
01329   int c;
01330   char *arg = NULL;
01331 
01332   // prepare fake command-line options as will be seen by Q[Core]Application
01333   qt_argc = 1;
01334   qt_argv[0] = argv[0];
01335   qt_argv[1] = NULL;
01336 
01337   // build getopt_long short option list
01338   char klfcmdl_optstring[1024];
01339   int k, j;
01340   for (k = 0, j = 0; klfcmdl_optlist[k].name != NULL; ++k) {
01341     if (klfcmdl_optlist[k].val < 127) { // has short option char
01342       klfcmdl_optstring[j++] = klfcmdl_optlist[k].val;
01343       if (klfcmdl_optlist[k].has_arg)
01344         klfcmdl_optstring[j++] = ':';
01345     }
01346   }
01347   klfcmdl_optstring[j] = '\0'; // terminate C string
01348 
01349   // loop for each option
01350   for (;;) {
01351     // get an option from command line
01352     c = getopt_long(argc, argv, klfcmdl_optstring, klfcmdl_optlist, NULL);
01353     if (c == -1)
01354       break;
01355 
01356     arg = NULL;
01357     if (optarg != NULL) {
01358       if (opt_base64arg) {
01359         // this argument is to be decoded from base64
01360         //
01361         // note that here QByteArray can function without a Q[Core]Application
01362         // (officially? this is just suggested by the fact that they mention it
01363         //  explicitely for QString: 
01364         //  http://doc.trolltech.com/4.4/qcoreapplication.html#details)
01365         QByteArray decoded = QByteArray::fromBase64(optarg);
01366         arg = strdup(decoded.constData());
01367       } else {
01368         arg = strdup(optarg);
01369       }
01370       opt_strdup_free_list[opt_strdup_free_list_n++] = arg;
01371     }
01372     // immediately reset this flag, as it applies to the argument of the next option
01373     // only (which we have just retrieved and possibly decoded)
01374     opt_base64arg = false;
01375 
01376     switch (c) {
01377     case OPT_INTERACTIVE:
01378       opt_interactive = 1;
01379       break;
01380     case OPT_INPUT:
01381       if (opt_interactive == -1) opt_interactive = 0;
01382       opt_input = arg;
01383       break;
01384     case OPT_LATEXINPUT:
01385       if (opt_interactive == -1) opt_interactive = 0;
01386       opt_latexinput = arg;
01387       break;
01388     case OPT_PASTE_CLIPBOARD:
01389       if (opt_interactive <= 0) {
01390         if (opt_interactive == 0)
01391           qWarning("%s", qPrintable(QObject::tr("--paste-clipboard requires interactive mode. Switching.")));
01392         opt_interactive = 1;
01393       }
01394       opt_paste = 1;
01395       break;
01396     case OPT_PASTE_SELECTION:
01397       if (opt_interactive <= 0) {
01398         if (opt_interactive == 0)
01399           qWarning("%s", qPrintable(QObject::tr("--paste-selection requires interactive mode. Switching.")));
01400         opt_interactive = 1;
01401       }
01402       opt_paste = 2;
01403       break;
01404     case OPT_NOEVAL:
01405       opt_noeval = true;
01406       break;
01407     case OPT_BASE64ARG:
01408       opt_base64arg = true;
01409       break;
01410     case OPT_OUTPUT:
01411       opt_output = arg;
01412       break;
01413     case OPT_FORMAT:
01414       opt_format = arg;
01415       break;
01416     case OPT_FGCOLOR:
01417       opt_fgcolor = arg;
01418       break;
01419     case OPT_BGCOLOR:
01420       opt_bgcolor = arg;
01421       break;
01422     case OPT_DPI:
01423       opt_dpi = atoi(arg);
01424       break;
01425     case OPT_MATHMODE:
01426       opt_mathmode = arg;
01427       break;
01428     case OPT_PREAMBLE:
01429 #if defined(Q_WS_MAC)
01430       // NASTY WORKAROUND FOR a mysterious -psn_**** option passed to the application
01431       // when opened using the apple 'open' command-line utility, and thus when the
01432       // application is launched via an icon..
01433       if ( !strncmp(arg, "sn_", 3) )
01434         break;
01435 #endif
01436       opt_preamble = arg;
01437       break;
01438     case OPT_QUIET:
01439       opt_quiet = __klf_parse_bool_arg(arg, true);
01440       break;
01441     case OPT_REDIRECT_DEBUG:
01442       opt_redirect_debug = arg;
01443       break;
01444     case OPT_DAEMONIZE:
01445       opt_daemonize = true;
01446       break;
01447     case OPT_DBUS_EXPORT_MAINWIN:
01448       opt_dbus_export_mainwin = true;
01449       break;
01450     case OPT_SKIP_PLUGINS:
01451       // default value 'true' (default value if option is given)
01452       opt_skip_plugins = __klf_parse_bool_arg(arg, true);
01453       break;
01454     case OPT_OUTLINEFONTS:
01455       opt_outlinefonts = __klf_parse_bool_arg(arg, true);
01456       break;
01457     case OPT_LBORDEROFFSET:
01458       opt_lborderoffset = atoi(arg);
01459       break;
01460     case OPT_TBORDEROFFSET:
01461       opt_tborderoffset = atoi(arg);
01462       break;
01463     case OPT_RBORDEROFFSET:
01464       opt_rborderoffset = atoi(arg);
01465       break;
01466     case OPT_BBORDEROFFSET:
01467       opt_bborderoffset = atoi(arg);
01468       break;
01469     case OPT_TEMPDIR:
01470       opt_tempdir = arg;
01471       break;
01472     case OPT_LATEX:
01473       opt_latex = arg;
01474       break;
01475     case OPT_DVIPS:
01476       opt_dvips = arg;
01477       break;
01478     case OPT_GS:
01479       opt_gs = arg;
01480       break;
01481     case OPT_EPSTOPDF:
01482       opt_epstopdf = arg;
01483       break;
01484     case OPT_HELP:
01485       opt_help_fp = main_msg_get_fp_arg(arg);
01486       opt_help_requested = true;
01487       break;
01488     case OPT_VERSION:
01489       if (arg != NULL) {
01490         char *colonptr = strchr(arg, ':');
01491         if (colonptr != NULL) {
01492           *colonptr = '\0';
01493           opt_version_format = colonptr+1;
01494         }
01495       }
01496       opt_version_fp = main_msg_get_fp_arg(arg);
01497       opt_version_requested = true;
01498       break;
01499     case OPT_QTOPT:
01500       qt_argv[qt_argc] = arg;
01501       qt_argc++;
01502       break;
01503     default:
01504       opt_error.has_error = true;
01505       opt_error.retcode = c;
01506       return;
01507     }
01508   }
01509 
01510   qt_argv[qt_argc] = NULL;
01511 
01512   // possibly pointing on NULL if no extra arguments
01513   klf_args = & argv[optind];
01514 
01515   if (opt_help_requested || opt_version_requested || opt_error.has_error)
01516     opt_interactive = 0;
01517 
01518   if (opt_interactive == -1) {
01519     // interactive (open GUI) by default
01520     opt_interactive = 1;
01521   }
01522   
01523   // Constistency checks
01524   if (opt_noeval && !opt_interactive) {
01525     qWarning("%s", qPrintable(QObject::tr("--noeval is relevant only in interactive mode.")));
01526     opt_noeval = false;
01527   }
01528   if (opt_noeval && opt_output) {
01529     qWarning("%s", qPrintable(QObject::tr("--noeval may not be used when --output is present.")));
01530     opt_noeval = false;
01531   }
01532   if (opt_interactive && opt_format && !opt_output) {
01533     qWarning("%s", qPrintable(QObject::tr("Ignoring --format without --output.")));
01534     opt_format = NULL;
01535   }
01536 
01537   return;
01538 }

Generated by doxygen 1.7.5.1