[KLF Application][KLF Tools][KLF Backend][KLF Home]
KLatexFormula Project

src/klfbackend/klfdefs.cpp

00001 /***************************************************************************
00002  *   file klfdefs.cpp
00003  *   This file is part of the KLatexFormula Project.
00004  *   Copyright (C) 2011 by Philippe Faist
00005  *   philippe.faist at 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: klfdefs.cpp 603 2011-02-26 23:14:55Z phfaist $ */
00023 
00024 #include <stdlib.h>
00025 #include <stdio.h> // vsprintf(), vsnprintf
00026 #include <stdarg.h> // va_list, va_arg, va_end in klfFmt()
00027 #include <sys/time.h>
00028 
00029 #include <qdir.h>
00030 #include <qfile.h>
00031 #include <qfileinfo.h>
00032 #include <qregexp.h>
00033 #include <qapplication.h>
00034 #include <qmetaobject.h>
00035 
00036 #ifdef KLFBACKEND_QT4
00037 #include <QDebug>
00038 #endif
00039 
00040 #include "klfdefs.h"
00041 #include "klfqt34common.h"
00042 
00744 // INTERNAL
00745 
00769 static char __klf_version_string[] = KLF_VERSION_STRING;
00770 
00771 
00772 KLF_EXPORT const char * klfVersion()
00773 {
00774   return __klf_version_string;
00775 }
00776 
00777 KLF_EXPORT int klfVersionMaj()
00778 {
00779   return KLF_VERSION_MAJ;
00780 }
00781 KLF_EXPORT int klfVersionMin()
00782 {
00783   return KLF_VERSION_MIN;
00784 }
00785 KLF_EXPORT int klfVersionRelease()
00786 {
00787   return KLF_VERSION_REL;
00788 }
00789 
00790 
00791 
00792 
00793 // declared in klfdebug.h
00794 
00795 struct KLFDebugObjectWatcherPrivate
00796 {
00797   QMap<quintptr, QString> refInfos;
00798 };
00799 
00800 // static
00801 KLFDebugObjectWatcher *KLFDebugObjectWatcher::instance = NULL;
00802 // static
00803 KLFDebugObjectWatcher *KLFDebugObjectWatcher::getWatcher()
00804 {
00805   if (instance == NULL)
00806     instance = new KLFDebugObjectWatcher;
00807   return instance;
00808 }
00809 
00810 void KLFDebugObjectWatcher::registerObjectRefInfo(QObject *object, const QString& refinfo)
00811 {
00812   p->refInfos[(quintptr)object] = refinfo;
00813 }
00814 
00815 KLFDebugObjectWatcher::KLFDebugObjectWatcher()
00816   : QObject(qApp)
00817 {
00818   p = new KLFDebugObjectWatcherPrivate;
00819 }
00820 KLFDebugObjectWatcher::~KLFDebugObjectWatcher()
00821 {
00822   delete p;
00823 }
00824 void KLFDebugObjectWatcher::debugObjectDestroyed(QObject *object)
00825 {
00826   quintptr obji = (quintptr) object;
00827   if (p->refInfos.contains(obji)) {
00828     klfDbg(klfFmtCC("Object destroyed: (%s*)%p; object reference name is `%s'",
00829                     (object ? object->metaObject()->className() : "void"),
00830                     object, qPrintable(p->refInfos[obji])));
00831   } else {
00832     klfDbg(klfFmtCC("Object destroyed: (%s*)%p",
00833                     (object ? object->metaObject()->className() : "void"),
00834                     object));
00835   }
00836 }
00837 
00838 
00839 
00840 KLF_EXPORT QByteArray klfShortFuncSignature(const QByteArray& ba_funcname)
00841 {
00842   QString funcname(ba_funcname);
00843   // returns the section between the last space before the first open paren and the first open paren
00844   int iSpc, iParen;
00845 #ifdef KLFBACKEND_QT4
00846   iParen = funcname.indexOf('(');
00847   iSpc = funcname.lastIndexOf(' ', iParen-2);
00848 #else
00849   iParen = funcname.find('(');
00850   iSpc = funcname.findRev(' ', iParen-2);
00851 #endif
00852   // if iSpc is -1, leave it at -1 (eg. constructor signature), the following code still works.
00853   if (iParen == -1 || iSpc > iParen) {
00854     qWarning("klfShortFuncSignature('%s'): Signature parse error!", qPrintable(funcname));
00855     return ba_funcname;
00856   }
00857   // shorten name
00858   QString f = funcname.mid(iSpc+1, iParen-(iSpc+1));
00859   QByteArray data = f.s_toLocal8Bit();
00860   return data;
00861 }
00862 
00863 
00864 
00865 
00866 KLF_EXPORT QByteArray klfFmt(const char * fmt, va_list pp)
00867 {
00868   static const int bufferSize = 8192;
00869   char buffer[bufferSize];
00870   int len;
00871 #if defined(_BSD_SOURCE) || _XOPEN_SOURCE >= 500 || defined(_ISOC99_SOURCE)
00872   // stdio.h provided vsnprintf()
00873   len = vsnprintf(buffer, bufferSize, fmt, pp);
00874   if (len >= bufferSize) {
00875     // output was truncated
00876     qWarning("%s(): output from format string \"%s\" was truncated from %d to %d bytes.",
00877              KLF_FUNC_NAME, fmt, len, (bufferSize-1));
00878     len = bufferSize-1;
00879   }
00880 #else
00881   len = vsprintf(buffer, fmt, pp);
00882 #endif
00883 
00884   if (len < 0) {
00885     qWarning("%s(): vs(n)printf() failed for format \"%s\"", KLF_FUNC_NAME, fmt);
00886     return QByteArray();
00887   }
00888 
00889   // create a QByteArray
00890   QByteArray data;
00891 #ifdef KLFBACKEND_QT4
00892   data = QByteArray(buffer, len);
00893 #else
00894   data.duplicate(buffer, len);
00895 #endif
00896   return data;
00897 }
00898 
00899 KLF_EXPORT QByteArray klfFmt(const char * fmt, ...)
00900 {
00901   va_list pp;
00902   va_start(pp, fmt);
00903   QByteArray data = klfFmt(fmt, pp);
00904   va_end(pp);
00905   return data;
00906 }
00907 
00908 
00909 KLF_EXPORT QString klfTimeOfDay(bool shortfmt)
00910 {
00911   struct timeval tv;
00912   gettimeofday(&tv, NULL);
00913   char temp[128];
00914   if (shortfmt)
00915     sprintf(temp, "%03ld.%06ld", (ulong)tv.tv_sec % 1000, (ulong)tv.tv_usec);
00916   else
00917     sprintf(temp, "%ld.%06ld", (ulong)tv.tv_sec, (ulong)tv.tv_usec);
00918   return QString::fromAscii(temp);
00919 }
00920 
00921 
00922 #ifdef KLF_DEBUG
00923 static int __klf_dbg_block_depth_counter = 0;
00924 #endif
00925 
00926 KLFDebugBlock::KLFDebugBlock(const QString& blockName)
00927   : pBlockName(blockName), pPrintMsg(true)
00928 {
00929 #ifdef KLF_DEBUG
00930   qDebug("%s: [%02d]block begin", qPrintable(pBlockName), ++__klf_dbg_block_depth_counter);
00931 #endif
00932 }
00933 KLFDebugBlock::KLFDebugBlock(bool printmsg, const QString& blockName)
00934   : pBlockName(blockName), pPrintMsg(printmsg)
00935 {
00936 #ifdef KLF_DEBUG
00937   // convention: __klf_dbg_block_depth_counter is incremented/decremented only when displayed
00938   if (printmsg)
00939     qDebug("%s: [%02d]block begin", qPrintable(pBlockName), ++__klf_dbg_block_depth_counter);
00940 #endif
00941 }
00942 KLFDebugBlock::~KLFDebugBlock()
00943 {
00944 #ifdef KLF_DEBUG
00945   // convention: __klf_dbg_block_depth_counter is incremented/decremented only when displayed
00946   if (pPrintMsg)
00947     qDebug("%s: [%02d]block end", qPrintable(pBlockName), __klf_dbg_block_depth_counter--);
00948 #endif
00949 }
00950 KLFDebugBlockTimer::KLFDebugBlockTimer(const QString& blockName)
00951   : KLFDebugBlock(false, blockName)
00952 {
00953 #ifdef KLF_DEBUG
00954   // convention: __klf_dbg_block_depth_counter is incremented/decremented only when displayed
00955   qDebug("+T:%s: %s: [%02d]block begin", KLF_SHORT_TIME, qPrintable(pBlockName), ++__klf_dbg_block_depth_counter);
00956 #endif
00957 }
00958 KLFDebugBlockTimer::~KLFDebugBlockTimer()
00959 {
00960 #ifdef KLF_DEBUG
00961   // convention: __klf_dbg_block_depth_counter is incremented/decremented only when displayed
00962   qDebug("+T:%s: %s: [%02d]block end", KLF_SHORT_TIME, qPrintable(pBlockName), __klf_dbg_block_depth_counter--);
00963 #endif
00964 }
00965 
00966 // the following is defined for both debug and non-debug modes. In non-debug modes, it provides the symbol __klf_dbg_hdr
00967 // for debugging eg. plugins compiled in debug mode (NEEDS TESTING...?)
00968 #ifdef KLFBACKEND_QT4
00969 // QT 4 >>
00970 KLF_EXPORT QDebug __klf_dbg_hdr(QDebug dbg, const char * funcname, const char *refinstance, const char * shorttime)
00971 {
00972   if (shorttime == NULL)
00973     return dbg.nospace()<<funcname<<"():"<<refinstance<<"\n        ";
00974   else
00975     return dbg.nospace()<<"+T:"<<shorttime<<": "<<funcname<<"():"<<refinstance<<"\n        ";
00976 }
00977 // << QT 4
00978 #else
00979 // QT 3 >>
00980 int __klf_dbg_string_obj::operator=(const QString& msg)
00981 {
00982 #  ifdef KLF_DEBUG
00983   qDebug("%s", qPrintable(hdr + msg));
00984 #  endif
00985   return 0;
00986 }
00987 KLF_EXPORT __klf_dbg_string_obj
00988 /* */ __klf_dbg_hdr_qt3(const char *funcname, const char *refinstance, const char *shorttime)
00989 {
00990 #  ifdef KLF_DEBUG
00991   QString s;
00992   if (shorttime == NULL)
00993     s = QString::fromLocal8Bit(funcname) + "():" + refinstance + "\n  ";
00994   else
00995     s = QString::fromLocal8Bit("+T:") + shorttime + ": " + funcname + "(): " + refinstance + "\n  ";
00996   return  __klf_dbg_string_obj(s);
00997 #  else
00998   return  __klf_dbg_string_obj(QString());
00999 #  endif
01000 }
01001 // << QT 3
01002 #endif
01003 
01004 
01005 
01006 
01007 // ----------------------------------------------------------------------
01008 
01009 
01010 
01011 
01012 KLF_EXPORT QString KLFSysInfo::arch()
01013 {
01014   return KLF_CMAKE_ARCH;
01015 }
01016 
01017 KLF_EXPORT KLFSysInfo::Os KLFSysInfo::os()
01018 {
01019 #if defined(Q_OS_LINUX)
01020   return Linux;
01021 #elif defined(Q_OS_DARWIN)
01022   return MacOsX;
01023 #elif defined(Q_OS_WIN32)
01024   return Win32;
01025 #else
01026   return OtherOs;
01027 #endif
01028 }
01029 
01030 KLF_EXPORT QString KLFSysInfo::osString(Os sysos)
01031 {
01032   switch (sysos) {
01033   case Linux: return QLatin1String("linux");
01034   case MacOsX: return QLatin1String("macosx");
01035   case Win32: return QLatin1String("win32");
01036   case OtherOs: return QString();
01037   default: ;
01038   }
01039   qWarning("KLFSysInfo::osString: unknown OS: %d", sysos);
01040   return QString();
01041 }
01042 
01043 
01044 QStringList klf_version_suffixes =
01045   QStringList() << "a" << "alpha" << "b" << "beta" << "p" << "pre" << "preview" << "RC" << "rc"
01046 /* */           << "" // empty suffix or any unrecognized suffix
01047 /* */           << "post" << "dev" << "devel";
01048 
01049 static int __klf_version_compare_suffix_words(QString w1, QString w2)
01050 {
01051   // a list of known words
01052   const QStringList& words = klf_version_suffixes;
01053   // now compare the words
01054   int borderBeforeAfter = words.list_indexOf("");
01055   if (borderBeforeAfter < 0)
01056     qWarning("klfVersionCompare: suffix words list doesn't contain \"\"!");
01057   int i1 = words.list_indexOf(w1);
01058   int i2 = words.list_indexOf(w2);
01059   if (i1 == -1 && i2 == -1)
01060     return QString::compare(w1, w2);
01061   if (i2 == -1)
01062     return i1 < borderBeforeAfter ? -1 : +1;
01063   if (i1 == -1)
01064     return i2 < borderBeforeAfter ? +1 : -1;
01065   // both are recognized words
01066   return i1 - i2;
01067 }
01068 
01069 
01070 KLF_EXPORT int klfVersionCompare(const QString& v1, const QString& v2)
01071 {
01072   qDebug("klfVersionCompare(): Comparing versions %s and %s", qPrintable(v1), qPrintable(v2));
01073   if (v1 == v2)
01074     return 0;
01075   if (v1.isEmpty()) // v1 is empty, but v2 is not empty because of test above
01076     return -1;
01077   if (v2.isEmpty()) // v2 is empty, but not v1 because of test above
01078     return 1;
01079   //           *1     2  *3     4  *5    *6
01080   QRegExp rx1("^(\\d+)(\\.(\\d+)(\\.(\\d+)([a-zA-Z]+\\d*)?)?)?$");
01081   QRegExp rx2(rx1);
01082   if (!rx1.exactMatch(v1)) {
01083     qWarning("klfVersionLessThan: Invalid version number format: %s", qPrintable(v1));
01084     return -200;
01085   }
01086   if (!rx2.exactMatch(v2)) {
01087     qWarning("klfVersionLessThan: Invalid version number format: %s", qPrintable(v2));
01088     return -200;
01089   }
01090   int maj1 = rx1.cap(1).toInt();
01091   int maj2 = rx2.cap(1).toInt();
01092   if (maj1 != maj2)
01093     return maj1 - maj2;
01094   bool hasmin1 = !rx1.cap(2).isEmpty();
01095   bool hasmin2 = !rx2.cap(2).isEmpty();
01096   if ( ! hasmin1 && ! hasmin2 )
01097     return 0; // equal
01098   if ( ! hasmin1 && hasmin2 )
01099     return -1; // 3 < 3.x
01100   if ( hasmin1 && ! hasmin2 )
01101     return +1; // 3.x > 3
01102   int min1 = rx1.cap(3).toInt();
01103   int min2 = rx2.cap(3).toInt();
01104   if ( min1 != min2 )
01105     return min1 - min2;
01106 
01107   bool hasrel1 = !rx1.cap(4).isEmpty();
01108   bool hasrel2 = !rx2.cap(4).isEmpty();
01109   if ( ! hasrel1 && ! hasrel2 )
01110     return 0; // equal
01111   if ( ! hasrel1 && hasrel2 )
01112     return -1; // 3.x < 3.x.y
01113   if ( hasrel1 && ! hasrel2 )
01114     return +1; // 3.x.y > 3.x
01115   int rel1 = rx1.cap(5).toInt();
01116   int rel2 = rx2.cap(5).toInt();
01117   if ( rel1 != rel2 )
01118     return rel1 - rel2;
01119 
01120   QString suffix1 = rx1.cap(6);
01121   QString suffix2 = rx2.cap(6);
01122 
01123   //  qDebug("Suffix1=%s, suffix2=%s", qPrintable(suffix1), qPrintable(suffix2));
01124 
01125   if (suffix1 == suffix2)
01126     return 0; // equal
01127 
01128   //             1          2
01129   QRegExp rxs1("^([a-zA-Z]*)(\\d*)$");
01130   QRegExp rxs2(rxs1);
01131   rxs1.exactMatch(suffix1); // must necessarily match, already matched global regex
01132   rxs2.exactMatch(suffix2);
01133 
01134   QString w1 = rxs1.cap(1);
01135   QString w2 = rxs2.cap(1);
01136   QString ns1 = rxs1.cap(2);
01137   QString ns2 = rxs2.cap(2);
01138 
01139   int cmp = __klf_version_compare_suffix_words(w1, w2);
01140   if (cmp != 0)
01141     return cmp; // words are enough to make the difference
01142 
01143   // the words are the same -> compare ns1<->ns2
01144   if (ns1.isEmpty()) {
01145     if (ns2.isEmpty())
01146       return 0; // equal
01147     // with suffix number compares greater than without
01148     return -1;
01149   }
01150   if (ns2.isEmpty()) {
01151     return +1;
01152   }
01153 
01154   int n1 = ns1.toInt();
01155   int n2 = ns2.toInt();
01156   return n1 - n2;
01157 }
01158 
01159 KLF_EXPORT bool klfVersionCompareLessThan(const QString& v1, const QString& v2)
01160 {
01161   return klfVersionCompare(v1,v2) < 0;
01162 }
01163 
01164 
01165 
01166 // negative limit means "no limit"
01167 static QStringList __search_find_test(const QString& root, const QStringList& pathlist,
01168                                       int level, int limit)
01169 {
01170   if (limit == 0)
01171     return QStringList();
01172 
01173   if (limit < 0)
01174     limit = -1; // normalize negative values to -1 (mostly cosmetic...)
01175 
01176   QStringList newpathlist = pathlist;
01177   // our level: levelpathlist contains items in pathlist from 0 to level-1 inclusive.
01178   QStringList levelpathlist;
01179   int k;
01180   for (k = 0; k < level; ++k) { levelpathlist << newpathlist[k]; }
01181   // the dir/file at our level:
01182   QString flpath = root+levelpathlist.join("/");
01183   QFileInfo flinfo(flpath);
01184   if (flinfo.isDir()) {
01185     QDir d(flpath);
01186     QStringList entries;
01187 #ifdef KLFBACKEND_QT4
01188     entries = d.entryList(QStringList()<<pathlist[level]);
01189 #else
01190     entries = d.entryList(pathlist[level]);
01191 #endif
01192     QStringList hitlist;
01193     for (k = 0; k < (int)entries.size(); ++k) {
01194       newpathlist[level] = entries[k];
01195       hitlist += __search_find_test(root, newpathlist, level+1, limit - hitlist.size());
01196       if (limit >= 0 && (int)hitlist.size() >= limit) // reached limit
01197         break;
01198     }
01199     return hitlist;
01200   }
01201   if (flinfo.exists()) {
01202     return QStringList() << dir_native_separators(root+pathlist.join("/"));
01203   }
01204   return QStringList();
01205 }
01206 
01207 KLF_EXPORT QStringList klfSearchFind(const QString& wildcard_expression, int limit)
01208 {
01209   klfDbg("looking for "+wildcard_expression) ;
01210 
01211   QString expr;
01212 #ifdef KLFBACKEND_QT4
01213   expr = QDir::fromNativeSeparators(wildcard_expression);
01214 #else
01215   expr = wildcard_expression;  expr.replace(QDir::separator(), "/");
01216 #endif
01217   QStringList pathlist = str_split(expr, "/", false);
01218   QString root = "/";
01219   static QRegExp driveregexp("^[A-Za-z]:$");
01220   if (driveregexp.exactMatch(pathlist[0])) {
01221     // Windows System with X: drive letter
01222     root = pathlist[0]+"/";
01223     pathlist.pop_front();
01224   }
01225   return __search_find_test(root, pathlist, 0, limit);
01226 }
01227 
01228 KLF_EXPORT QString klfSearchPath(const QString& programName, const QString& extra_path)
01229 {
01230   static const QString PATH = getenv("PATH");
01231   static const QString pathsep = QString("")+KLF_PATH_SEP;
01232 
01233   QString path = PATH;
01234   if (!extra_path.isEmpty())
01235     path = extra_path + pathsep + path;
01236 
01237   const QStringList paths = str_split(path, pathsep, true);
01238   QString test;
01239   int k, j;
01240   for (k = 0; k < (int)paths.size(); ++k) {
01241     klfDbg("searching in "+paths[k]) ;
01242     QStringList hits = klfSearchFind(paths[k]+"/"+programName);
01243     klfDbg("\t...resulting in hits = "+hits.join(" ;; ")) ;
01244     for (j = 0; j < (int)hits.size(); ++j) {
01245       if ( QFileInfo(hits[j]).isExecutable() ) {
01246         klfDbg("\tFound definitive (executable) hit at "+hits[j]) ;
01247         return hits[j];
01248       }
01249     }
01250   }
01251   return QString::null;
01252 }
01253 
01254 
01255 
01256 
01257 

Generated by doxygen 1.7.3