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

Generated by doxygen 1.7.3