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

Generated by doxygen 1.7.3