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

Generated by doxygen 1.7.3