From 69cbb17497ab52620e39874a2323db1aadf6dcbe Mon Sep 17 00:00:00 2001
From: Marius Kintel
Date: Wed, 4 Dec 2013 01:15:19 -0500
Subject: [PATCH 01/16] Killed warnings
---
src/CocoaUtils.mm | 4 ++--
src/modcontext.cc | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/CocoaUtils.mm b/src/CocoaUtils.mm
index 92640fdd..9856b3d7 100644
--- a/src/CocoaUtils.mm
+++ b/src/CocoaUtils.mm
@@ -8,7 +8,7 @@ void CocoaUtils::endApplication()
object:nil];
}
-void CocoaUtils::nslog(const std::string &str, void *userdata)
+void CocoaUtils::nslog(const std::string &str, void * /* userdata */)
{
- NSLog([NSString stringWithUTF8String: str.c_str()]);
+ NSLog(@"%s", str.c_str());
}
diff --git a/src/modcontext.cc b/src/modcontext.cc
index 5b480097..7941cf5c 100644
--- a/src/modcontext.cc
+++ b/src/modcontext.cc
@@ -162,7 +162,7 @@ void ModuleContext::dump(const AbstractModule *mod, const ModuleInstantiation *i
#endif
FileContext::FileContext(const class FileModule &module, const Context *parent)
- : usedlibs(module.usedlibs), ModuleContext(parent)
+ : ModuleContext(parent), usedlibs(module.usedlibs)
{
if (!module.modulePath().empty()) this->document_path = module.modulePath();
}
From f2fe074e1d947f74e34833453cc613e46e5450a6 Mon Sep 17 00:00:00 2001
From: Marius Kintel
Date: Wed, 4 Dec 2013 01:15:34 -0500
Subject: [PATCH 02/16] clang fix: Clang claims to be gcc
---
src/stl-utils.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/stl-utils.cc b/src/stl-utils.cc
index 790fd179..027339cc 100644
--- a/src/stl-utils.cc
+++ b/src/stl-utils.cc
@@ -1,4 +1,4 @@
-#if defined(__APPLE__) && defined(__GNUC__)
+#if defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__)
#include
From 301ef946f05a320768d4b8f974a95e2a04a5fc0d Mon Sep 17 00:00:00 2001
From: Marius Kintel
Date: Thu, 5 Dec 2013 12:20:40 -0500
Subject: [PATCH 03/16] Qt4 patches to make it build on 10.9
---
patches/qt4/patch-libtiff.diff | 18 +
.../patch-src_corelib_global_qglobal.h.diff | 14 +
...ns_bearer_corewlan_qcorewlanengine.mm.diff | 1382 +++++++++++++++++
3 files changed, 1414 insertions(+)
create mode 100644 patches/qt4/patch-libtiff.diff
create mode 100644 patches/qt4/patch-src_corelib_global_qglobal.h.diff
create mode 100644 patches/qt4/patch-src_plugins_bearer_corewlan_qcorewlanengine.mm.diff
diff --git a/patches/qt4/patch-libtiff.diff b/patches/qt4/patch-libtiff.diff
new file mode 100644
index 00000000..5b7f9ec3
--- /dev/null
+++ b/patches/qt4/patch-libtiff.diff
@@ -0,0 +1,18 @@
+--- src/3rdparty/libtiff/libtiff/tif_config.h
++++ src/3rdparty/libtiff/libtiff/tif_config.h
+@@ -317,15 +317,6 @@
+ /* Define to empty if `const' does not conform to ANSI C. */
+ /* #undef const */
+
+-/* Define to `__inline__' or `__inline' if that's what the C compiler
+- calls it, or to nothing if 'inline' is not supported under any name. */
+-#ifndef Q_OS_SYMBIAN
+-#ifndef __cplusplus
+-#undef inline
+-#define inline
+-#endif
+-#endif
+-
+ /* Define to `long int' if does not define. */
+ /* #undef off_t */
+
diff --git a/patches/qt4/patch-src_corelib_global_qglobal.h.diff b/patches/qt4/patch-src_corelib_global_qglobal.h.diff
new file mode 100644
index 00000000..8c55c5a6
--- /dev/null
+++ b/patches/qt4/patch-src_corelib_global_qglobal.h.diff
@@ -0,0 +1,14 @@
+--- src/corelib/global/qglobal.h.orig 2013-06-07 07:16:52.000000000 +0200
++++ src/corelib/global/qglobal.h 2013-10-27 14:05:22.000000000 +0100
+@@ -327,7 +327,10 @@
+ # if !defined(MAC_OS_X_VERSION_10_8)
+ # define MAC_OS_X_VERSION_10_8 MAC_OS_X_VERSION_10_7 + 1
+ # endif
+-# if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_8)
++# if !defined(MAC_OS_X_VERSION_10_9)
++# define MAC_OS_X_VERSION_10_9 MAC_OS_X_VERSION_10_8 + 1
++# endif
++# if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_9)
+ # warning "This version of Mac OS X is unsupported"
+ # endif
+ #endif
diff --git a/patches/qt4/patch-src_plugins_bearer_corewlan_qcorewlanengine.mm.diff b/patches/qt4/patch-src_plugins_bearer_corewlan_qcorewlanengine.mm.diff
new file mode 100644
index 00000000..61b2eef3
--- /dev/null
+++ b/patches/qt4/patch-src_plugins_bearer_corewlan_qcorewlanengine.mm.diff
@@ -0,0 +1,1382 @@
+--- src/plugins/bearer/corewlan/qcorewlanengine.mm
++++ src/plugins/bearer/corewlan/qcorewlanengine.mm
+@@ -52,29 +52,17 @@
+ #include
+
+ #include
+-#include
+-#include
+-#include
+-#include
+-#include
+-
+-#include
+-#include
+-#include
+-#include
+-
+-#include
++
++extern "C" { // Otherwise it won't find CWKeychain* symbols at link time
++#import
++}
++
+ #include "private/qcore_mac_p.h"
+
+ #include
+ #include
+
+-inline QString qt_NSStringToQString(const NSString *nsstr)
+-{ return QCFString::toQString(reinterpret_cast(nsstr)); }
+-
+-inline NSString *qt_QStringToNSString(const QString &qstr)
+-{ return [const_cast(reinterpret_cast(QCFString::toCFStringRef(qstr))) autorelease]; }
+-
++#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+
+ @interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject
+ {
+@@ -86,6 +74,7 @@ inline NSString *qt_QStringToNSString(const QString &qstr)
+ - (void)notificationHandler;//:(NSNotification *)notification;
+ - (void)remove;
+ - (void)setEngine:(QCoreWlanEngine *)coreEngine;
++- (QCoreWlanEngine *)engine;
+ - (void)dealloc;
+
+ @property (assign) QCoreWlanEngine* engine;
+@@ -93,7 +82,6 @@ inline NSString *qt_QStringToNSString(const QString &qstr)
+ @end
+
+ @implementation QT_MANGLE_NAMESPACE(QNSListener)
+-@synthesize engine;
+
+ - (id) init
+ {
+@@ -101,7 +89,7 @@ inline NSString *qt_QStringToNSString(const QString &qstr)
+ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
+ notificationCenter = [NSNotificationCenter defaultCenter];
+ currentInterface = [CWInterface interfaceWithName:nil];
+- [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil];
++ [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:CWPowerDidChangeNotification object:nil];
+ [locker unlock];
+ [autoreleasepool release];
+ return self;
+@@ -120,6 +108,11 @@ inline NSString *qt_QStringToNSString(const QString &qstr)
+ [locker unlock];
+ }
+
++-(QCoreWlanEngine *)engine
++{
++ return engine;
++}
++
+ -(void)remove
+ {
+ [locker lock];
+@@ -133,7 +126,7 @@ inline NSString *qt_QStringToNSString(const QString &qstr)
+ }
+ @end
+
+-QT_MANGLE_NAMESPACE(QNSListener) *listener = 0;
++static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0;
+
+ QT_BEGIN_NAMESPACE
+
+@@ -170,36 +163,28 @@ void QScanThread::run()
+ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
+ QStringList found;
+ mutex.lock();
+- CWInterface *currentInterface = [CWInterface interfaceWithName:qt_QStringToNSString(interfaceName)];
++ CWInterface *currentInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceName)];
+ mutex.unlock();
+
+- if([currentInterface power]) {
++ if (currentInterface.powerOn) {
+ NSError *err = nil;
+- NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys:
+- [NSNumber numberWithBool:YES], kCWScanKeyMerge,
+- [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType,
+- [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil];
+
+- NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err];
+- CWNetwork *apNetwork;
++ NSSet* apSet = [currentInterface scanForNetworksWithName:nil error:&err];
+
+ if (!err) {
+-
+- for(uint row=0; row < [apArray count]; row++ ) {
+- apNetwork = [apArray objectAtIndex:row];
+-
+- const QString networkSsid = qt_NSStringToQString([apNetwork ssid]);
++ for (CWNetwork *apNetwork in apSet) {
++ const QString networkSsid = QCFString::toQString(CFStringRef([apNetwork ssid]));
+ const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid));
+ found.append(id);
+
+ QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined;
+ bool known = isKnownSsid(networkSsid);
+- if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) {
+- if( networkSsid == qt_NSStringToQString( [currentInterface ssid])) {
++ if (currentInterface.serviceActive) {
++ if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) {
+ state = QNetworkConfiguration::Active;
+ }
+ }
+- if(state == QNetworkConfiguration::Undefined) {
++ if (state == QNetworkConfiguration::Undefined) {
+ if(known) {
+ state = QNetworkConfiguration::Discovered;
+ } else {
+@@ -207,7 +192,7 @@ void QScanThread::run()
+ }
+ }
+ QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose;
+- if([[apNetwork securityMode] intValue] == kCWSecurityModeOpen) {
++ if ([apNetwork supportsSecurity:kCWSecurityNone]) {
+ purpose = QNetworkConfiguration::PublicPurpose;
+ } else {
+ purpose = QNetworkConfiguration::PrivatePurpose;
+@@ -237,8 +222,8 @@ void QScanThread::run()
+ interfaceName = ij.value();
+ }
+
+- if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) {
+- if( networkSsid == qt_NSStringToQString([currentInterface ssid])) {
++ if (currentInterface.serviceActive) {
++ if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) {
+ state = QNetworkConfiguration::Active;
+ }
+ }
+@@ -300,14 +285,14 @@ void QScanThread::getUserConfigurations()
+ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
+ userProfiles.clear();
+
+- NSArray *wifiInterfaces = [CWInterface supportedInterfaces];
+- for(uint row=0; row < [wifiInterfaces count]; row++ ) {
++ NSSet *wifiInterfaces = [CWInterface interfaceNames];
++ for (NSString *ifName in wifiInterfaces) {
+
+- CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]];
+- if ( ![wifiInterface power] )
++ CWInterface *wifiInterface = [CWInterface interfaceWithName: ifName];
++ if (!wifiInterface.powerOn)
+ continue;
+
+- NSString *nsInterfaceName = [wifiInterface name];
++ NSString *nsInterfaceName = wifiInterface.ssid;
+ // add user configured system networks
+ SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil);
+ NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]);
+@@ -316,11 +301,11 @@ void QScanThread::getUserConfigurations()
+ NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"];
+
+ NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"];
+- for(NSString *ssidkey in thisSsidarray) {
+- QString thisSsid = qt_NSStringToQString(ssidkey);
++ for (NSString *ssidkey in thisSsidarray) {
++ QString thisSsid = QCFString::toQString(CFStringRef(ssidkey));
+ if(!userProfiles.contains(thisSsid)) {
+ QMap map;
+- map.insert(thisSsid, qt_NSStringToQString(nsInterfaceName));
++ map.insert(thisSsid, QCFString::toQString(CFStringRef(nsInterfaceName)));
+ userProfiles.insert(thisSsid, map);
+ }
+ }
+@@ -329,7 +314,7 @@ void QScanThread::getUserConfigurations()
+
+ // 802.1X user profiles
+ QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist";
+- NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile:qt_QStringToNSString(userProfilePath)] autorelease];
++ NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile: (NSString *)QCFString::toCFStringRef(userProfilePath)] autorelease];
+ if(eapDict != nil) {
+ NSString *profileStr= @"Profiles";
+ NSString *nameStr = @"UserDefinedName";
+@@ -348,15 +333,15 @@ void QScanThread::getUserConfigurations()
+ QString ssid;
+ for(int i = 0; i < dictSize; i++) {
+ if([nameStr isEqualToString:keys[i]]) {
+- networkName = qt_NSStringToQString(objects[i]);
++ networkName = QCFString::toQString(CFStringRef(objects[i]));
+ }
+ if([networkSsidStr isEqualToString:keys[i]]) {
+- ssid = qt_NSStringToQString(objects[i]);
++ ssid = QCFString::toQString(CFStringRef(objects[i]));
+ }
+ if(!userProfiles.contains(networkName)
+ && !ssid.isEmpty()) {
+ QMap map;
+- map.insert(ssid, qt_NSStringToQString(nsInterfaceName));
++ map.insert(ssid, QCFString::toQString(CFStringRef(nsInterfaceName)));
+ userProfiles.insert(networkName, map);
+ }
+ }
+@@ -444,7 +429,7 @@ void QCoreWlanEngine::initialize()
+ QMutexLocker locker(&mutex);
+ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
+
+- if([[CWInterface supportedInterfaces] count] > 0 && !listener) {
++ if ([[CWInterface interfaceNames] count] > 0 && !listener) {
+ listener = [[QT_MANGLE_NAMESPACE(QNSListener) alloc] init];
+ listener.engine = this;
+ hasWifi = true;
+@@ -479,141 +464,68 @@ void QCoreWlanEngine::connectToId(const QString &id)
+ QString interfaceString = getInterfaceFromId(id);
+
+ CWInterface *wifiInterface =
+- [CWInterface interfaceWithName: qt_QStringToNSString(interfaceString)];
++ [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)];
+
+- if ([wifiInterface power]) {
++ if (wifiInterface.powerOn) {
+ NSError *err = nil;
+- NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
+-
+ QString wantedSsid;
+-
+ QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
+
+ const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name));
+ const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name)));
+
+- bool using8021X = false;
+- if (idHash2 != id) {
+- NSArray *array = [CW8021XProfile allUser8021XProfiles];
+-
+- for (NSUInteger i = 0; i < [array count]; ++i) {
+- const QString networkNameHashCheck = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString([[array objectAtIndex:i] userDefinedName])));
+-
+- const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString([[array objectAtIndex:i] ssid])));
+-
+- if (id == networkNameHashCheck || id == ssidHash) {
+- const QString thisName = scanThread->getSsidFromNetworkName(id);
+- if (thisName.isEmpty())
+- wantedSsid = id;
+- else
+- wantedSsid = thisName;
+-
+- [params setValue: [array objectAtIndex:i] forKey:kCWAssocKey8021XProfile];
+- using8021X = true;
+- break;
+- }
++ QString wantedNetwork;
++ QMapIterator > i(scanThread->userProfiles);
++ while (i.hasNext()) {
++ i.next();
++ wantedNetwork = i.key();
++ const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork));
++ if (id == networkNameHash) {
++ wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork);
++ break;
+ }
+ }
+
+- if (!using8021X) {
+- QString wantedNetwork;
+- QMapIterator > i(scanThread->userProfiles);
+- while (i.hasNext()) {
+- i.next();
+- wantedNetwork = i.key();
+- const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork));
+- if (id == networkNameHash) {
+- wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork);
+- break;
+- }
+- }
+- }
+- NSDictionary *scanParameters = [NSDictionary dictionaryWithObjectsAndKeys:
+- [NSNumber numberWithBool:YES], kCWScanKeyMerge,
+- [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType,
+- [NSNumber numberWithInteger:100], kCWScanKeyRestTime,
+- qt_QStringToNSString(wantedSsid), kCWScanKeySSID,
+- nil];
+-
+- NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err];
++ NSSet *scanSet = [wifiInterface scanForNetworksWithName:(NSString *)QCFString::toCFStringRef(wantedSsid) error:&err];
+
+ if(!err) {
+- for(uint row=0; row < [scanArray count]; row++ ) {
+- CWNetwork *apNetwork = [scanArray objectAtIndex:row];
+-
+- if(wantedSsid == qt_NSStringToQString([apNetwork ssid])) {
+-
+- if(!using8021X) {
+- SecKeychainAttribute attributes[3];
+-
+- NSString *account = [apNetwork ssid];
+- NSString *keyKind = @"AirPort network password";
+- NSString *keyName = account;
+-
+- attributes[0].tag = kSecAccountItemAttr;
+- attributes[0].data = (void *)[account UTF8String];
+- attributes[0].length = [account length];
+-
+- attributes[1].tag = kSecDescriptionItemAttr;
+- attributes[1].data = (void *)[keyKind UTF8String];
+- attributes[1].length = [keyKind length];
+-
+- attributes[2].tag = kSecLabelItemAttr;
+- attributes[2].data = (void *)[keyName UTF8String];
+- attributes[2].length = [keyName length];
+-
+- SecKeychainAttributeList attributeList = {3,attributes};
+-
+- SecKeychainSearchRef searchRef;
+- SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef);
+-
+- NSString *password = @"";
+- SecKeychainItemRef searchItem;
+-
+- if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) {
+- UInt32 realPasswordLength;
+- SecKeychainAttribute attributesW[8];
+- attributesW[0].tag = kSecAccountItemAttr;
+- SecKeychainAttributeList listW = {1,attributesW};
+- char *realPassword;
+- OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword);
+-
+- if (status == noErr) {
+- if (realPassword != NULL) {
+-
+- QByteArray pBuf;
+- pBuf.resize(realPasswordLength);
+- pBuf.prepend(realPassword);
+- pBuf.insert(realPasswordLength,'\0');
+-
+- password = [NSString stringWithUTF8String:pBuf];
+- }
+- SecKeychainItemFreeContent(&listW, realPassword);
+- }
+-
+- CFRelease(searchItem);
+- } else {
+- qDebug() << "SecKeychainSearchCopyNext error";
+- }
+- [params setValue: password forKey: kCWAssocKeyPassphrase];
+- } // end using8021X
+-
+-
+- bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err];
++ for (CWNetwork *apNetwork in scanSet) {
++ CFDataRef ssidData = (CFDataRef)[apNetwork ssidData];
++ bool result = false;
++
++ SecIdentityRef identity = 0;
++ // Check first whether we require IEEE 802.1X authentication for the wanted SSID
++ if (CWKeychainCopyEAPIdentity(ssidData, &identity) == errSecSuccess) {
++ CFStringRef username = 0;
++ CFStringRef password = 0;
++ if (CWKeychainCopyEAPUsernameAndPassword(ssidData, &username, &password) == errSecSuccess) {
++ result = [wifiInterface associateToEnterpriseNetwork:apNetwork
++ identity:identity username:(NSString *)username password:(NSString *)password
++ error:&err];
++ CFRelease(username);
++ CFRelease(password);
++ }
++ CFRelease(identity);
++ } else {
++ CFStringRef password = 0;
++ if (CWKeychainCopyPassword(ssidData, &password) == errSecSuccess) {
++ result = [wifiInterface associateToNetwork:apNetwork password:(NSString *)password error:&err];
++ CFRelease(password);
++ }
++ }
+
+- if(!err) {
+- if(!result) {
+- emit connectionError(id, ConnectError);
+- } else {
+- return;
+- }
++ if (!err) {
++ if (!result) {
++ emit connectionError(id, ConnectError);
+ } else {
+- qDebug() <<"associate ERROR"<< qt_NSStringToQString([err localizedDescription ]);
++ return;
+ }
++ } else {
++ qDebug() <<"associate ERROR"<< QCFString::toQString(CFStringRef([err localizedDescription ]));
+ }
+ } //end scan network
+ } else {
+- qDebug() <<"scan ERROR"<< qt_NSStringToQString([err localizedDescription ]);
++ qDebug() <<"scan ERROR"<< QCFString::toQString(CFStringRef([err localizedDescription ]));
+ }
+ emit connectionError(id, InterfaceLookupError);
+ }
+@@ -631,10 +543,10 @@ void QCoreWlanEngine::disconnectFromId(const QString &id)
+ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
+
+ CWInterface *wifiInterface =
+- [CWInterface interfaceWithName: qt_QStringToNSString(interfaceString)];
++ [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)];
+
+ [wifiInterface disassociate];
+- if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) {
++ if (wifiInterface.serviceActive) {
+ locker.unlock();
+ emit connectionError(id, DisconnectionError);
+ locker.relock();
+@@ -654,9 +566,9 @@ void QCoreWlanEngine::doRequestUpdate()
+
+ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
+
+- NSArray *wifiInterfaces = [CWInterface supportedInterfaces];
+- for (uint row = 0; row < [wifiInterfaces count]; ++row) {
+- scanThread->interfaceName = qt_NSStringToQString([wifiInterfaces objectAtIndex:row]);
++ NSSet *wifiInterfaces = [CWInterface interfaceNames];
++ for (NSString *ifName in wifiInterfaces) {
++ scanThread->interfaceName = QCFString::toQString(CFStringRef(ifName));
+ scanThread->start();
+ }
+ locker.unlock();
+@@ -669,8 +581,8 @@ bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName)
+ bool haswifi = false;
+ if(hasWifi) {
+ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
+- CWInterface *defaultInterface = [CWInterface interfaceWithName: qt_QStringToNSString(wifiDeviceName)];
+- if([defaultInterface power]) {
++ CWInterface *defaultInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(wifiDeviceName)];
++ if (defaultInterface.powerOn) {
+ haswifi = true;
+ }
+ [autoreleasepool release];
+@@ -898,7 +810,7 @@ quint64 QCoreWlanEngine::startTime(const QString &identifier)
+ bool ok = false;
+ for(int i = 0; i < dictSize; i++) {
+ if([ssidStr isEqualToString:keys[i]]) {
+- const QString ident = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString(objects[i])));
++ const QString ident = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef(objects[i]))));
+ if(ident == identifier) {
+ ok = true;
+ }
+@@ -944,3 +856,7 @@ quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b)
+ }
+
+ QT_END_NAMESPACE
++
++#else // QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE
++#include "qcorewlanengine_10_6.mm"
++#endif
+diff --git a/src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm b/src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm
+new file mode 100644
+index 0000000..a3bf615
+--- /dev/null
++++ src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm
+@@ -0,0 +1,916 @@
++/****************************************************************************
++**
++** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
++** Contact: http://www.qt-project.org/legal
++**
++** This file is part of the plugins of the Qt Toolkit.
++**
++** $QT_BEGIN_LICENSE:LGPL$
++** Commercial License Usage
++** Licensees holding valid commercial Qt licenses may use this file in
++** accordance with the commercial license agreement provided with the
++** Software or, alternatively, in accordance with the terms contained in
++** a written agreement between you and Digia. For licensing terms and
++** conditions see http://qt.digia.com/licensing. For further information
++** use the contact form at http://qt.digia.com/contact-us.
++**
++** GNU Lesser General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU Lesser
++** General Public License version 2.1 as published by the Free Software
++** Foundation and appearing in the file LICENSE.LGPL included in the
++** packaging of this file. Please review the following information to
++** ensure the GNU Lesser General Public License version 2.1 requirements
++** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
++**
++** In addition, as a special exception, Digia gives you certain additional
++** rights. These rights are described in the Digia Qt LGPL Exception
++** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
++**
++** GNU General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU
++** General Public License version 3.0 as published by the Free Software
++** Foundation and appearing in the file LICENSE.GPL included in the
++** packaging of this file. Please review the following information to
++** ensure the GNU General Public License version 3.0 requirements will be
++** met: http://www.gnu.org/copyleft/gpl.html.
++**
++**
++** $QT_END_LICENSE$
++**
++****************************************************************************/
++
++#include
++
++@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject
++{
++ NSNotificationCenter *notificationCenter;
++ CWInterface *currentInterface;
++ QCoreWlanEngine *engine;
++ NSLock *locker;
++}
++- (void)notificationHandler;//:(NSNotification *)notification;
++- (void)remove;
++- (void)setEngine:(QCoreWlanEngine *)coreEngine;
++- (QCoreWlanEngine *)engine;
++- (void)dealloc;
++
++@property (assign) QCoreWlanEngine* engine;
++
++@end
++
++@implementation QT_MANGLE_NAMESPACE(QNSListener)
++
++- (id) init
++{
++ [locker lock];
++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
++ notificationCenter = [NSNotificationCenter defaultCenter];
++ currentInterface = [CWInterface interfaceWithName:nil];
++ [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil];
++ [locker unlock];
++ [autoreleasepool release];
++ return self;
++}
++
++-(void)dealloc
++{
++ [super dealloc];
++}
++
++-(void)setEngine:(QCoreWlanEngine *)coreEngine
++{
++ [locker lock];
++ if(!engine)
++ engine = coreEngine;
++ [locker unlock];
++}
++
++-(QCoreWlanEngine *)engine
++{
++ return engine;
++}
++
++-(void)remove
++{
++ [locker lock];
++ [notificationCenter removeObserver:self];
++ [locker unlock];
++}
++
++- (void)notificationHandler//:(NSNotification *)notification
++{
++ engine->requestUpdate();
++}
++@end
++
++static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0;
++
++QT_BEGIN_NAMESPACE
++
++void networkChangeCallback(SCDynamicStoreRef/* store*/, CFArrayRef changedKeys, void *info)
++{
++ for ( long i = 0; i < CFArrayGetCount(changedKeys); i++) {
++
++ QString changed = QCFString::toQString(CFStringRef((CFStringRef)CFArrayGetValueAtIndex(changedKeys, i)));
++ if( changed.contains("/Network/Global/IPv4")) {
++ QCoreWlanEngine* wlanEngine = static_cast(info);
++ wlanEngine->requestUpdate();
++ }
++ }
++ return;
++}
++
++
++QScanThread::QScanThread(QObject *parent)
++ :QThread(parent)
++{
++}
++
++QScanThread::~QScanThread()
++{
++}
++
++void QScanThread::quit()
++{
++ wait();
++}
++
++void QScanThread::run()
++{
++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
++ QStringList found;
++ mutex.lock();
++ CWInterface *currentInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceName)];
++ mutex.unlock();
++
++ if([currentInterface power]) {
++ NSError *err = nil;
++ NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys:
++ [NSNumber numberWithBool:YES], kCWScanKeyMerge,
++ [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType,
++ [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil];
++
++ NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err];
++ CWNetwork *apNetwork;
++
++ if (!err) {
++
++ for(uint row=0; row < [apArray count]; row++ ) {
++ apNetwork = [apArray objectAtIndex:row];
++
++ const QString networkSsid = QCFString::toQString(CFStringRef([apNetwork ssid]));
++ const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid));
++ found.append(id);
++
++ QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined;
++ bool known = isKnownSsid(networkSsid);
++ if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) {
++ if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) {
++ state = QNetworkConfiguration::Active;
++ }
++ }
++ if(state == QNetworkConfiguration::Undefined) {
++ if(known) {
++ state = QNetworkConfiguration::Discovered;
++ } else {
++ state = QNetworkConfiguration::Undefined;
++ }
++ }
++ QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose;
++ if([[apNetwork securityMode] intValue] == kCWSecurityModeOpen) {
++ purpose = QNetworkConfiguration::PublicPurpose;
++ } else {
++ purpose = QNetworkConfiguration::PrivatePurpose;
++ }
++
++ found.append(foundNetwork(id, networkSsid, state, interfaceName, purpose));
++
++ }
++ }
++ }
++ // add known configurations that are not around.
++ QMapIterator > i(userProfiles);
++ while (i.hasNext()) {
++ i.next();
++
++ QString networkName = i.key();
++ const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkName));
++
++ if(!found.contains(id)) {
++ QString networkSsid = getSsidFromNetworkName(networkName);
++ const QString ssidId = QString::number(qHash(QLatin1String("corewlan:") + networkSsid));
++ QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined;
++ QString interfaceName;
++ QMapIterator ij(i.value());
++ while (ij.hasNext()) {
++ ij.next();
++ interfaceName = ij.value();
++ }
++
++ if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) {
++ if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) {
++ state = QNetworkConfiguration::Active;
++ }
++ }
++ if(state == QNetworkConfiguration::Undefined) {
++ if( userProfiles.contains(networkName)
++ && found.contains(ssidId)) {
++ state = QNetworkConfiguration::Discovered;
++ }
++ }
++
++ if(state == QNetworkConfiguration::Undefined) {
++ state = QNetworkConfiguration::Defined;
++ }
++
++ found.append(foundNetwork(id, networkName, state, interfaceName, QNetworkConfiguration::UnknownPurpose));
++ }
++ }
++ emit networksChanged();
++ [autoreleasepool release];
++}
++
++QStringList QScanThread::foundNetwork(const QString &id, const QString &name, const QNetworkConfiguration::StateFlags state, const QString &interfaceName, const QNetworkConfiguration::Purpose purpose)
++{
++ QStringList found;
++ QMutexLocker locker(&mutex);
++ QNetworkConfigurationPrivate *ptr = new QNetworkConfigurationPrivate;
++
++ ptr->name = name;
++ ptr->isValid = true;
++ ptr->id = id;
++ ptr->state = state;
++ ptr->type = QNetworkConfiguration::InternetAccessPoint;
++ ptr->bearerType = QNetworkConfiguration::BearerWLAN;
++ ptr->purpose = purpose;
++
++ fetchedConfigurations.append( ptr);
++ configurationInterface.insert(ptr->id, interfaceName);
++
++ locker.unlock();
++ locker.relock();
++ found.append(id);
++ return found;
++}
++
++QList QScanThread::getConfigurations()
++{
++ QMutexLocker locker(&mutex);
++
++ QList foundConfigurations = fetchedConfigurations;
++ fetchedConfigurations.clear();
++
++ return foundConfigurations;
++}
++
++void QScanThread::getUserConfigurations()
++{
++ QMutexLocker locker(&mutex);
++
++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
++ userProfiles.clear();
++
++ NSArray *wifiInterfaces = [CWInterface supportedInterfaces];
++ for(uint row=0; row < [wifiInterfaces count]; row++ ) {
++
++ CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]];
++ if ( ![wifiInterface power] )
++ continue;
++
++ NSString *nsInterfaceName = [wifiInterface name];
++// add user configured system networks
++ SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil);
++ NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]);
++ CFRelease(dynRef);
++ if(airportPlist != nil) {
++ NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"];
++
++ NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"];
++ for(NSString *ssidkey in thisSsidarray) {
++ QString thisSsid = QCFString::toQString(CFStringRef(ssidkey));
++ if(!userProfiles.contains(thisSsid)) {
++ QMap map;
++ map.insert(thisSsid, QCFString::toQString(CFStringRef(nsInterfaceName)));
++ userProfiles.insert(thisSsid, map);
++ }
++ }
++ CFRelease(airportPlist);
++ }
++
++ // 802.1X user profiles
++ QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist";
++ NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile: (NSString *)QCFString::toCFStringRef(userProfilePath)] autorelease];
++ if(eapDict != nil) {
++ NSString *profileStr= @"Profiles";
++ NSString *nameStr = @"UserDefinedName";
++ NSString *networkSsidStr = @"Wireless Network";
++ for (id profileKey in eapDict) {
++ if ([profileStr isEqualToString:profileKey]) {
++ NSDictionary *itemDict = [eapDict objectForKey:profileKey];
++ for (id itemKey in itemDict) {
++
++ NSInteger dictSize = [itemKey count];
++ id objects[dictSize];
++ id keys[dictSize];
++
++ [itemKey getObjects:objects andKeys:keys];
++ QString networkName;
++ QString ssid;
++ for(int i = 0; i < dictSize; i++) {
++ if([nameStr isEqualToString:keys[i]]) {
++ networkName = QCFString::toQString(CFStringRef(objects[i]));
++ }
++ if([networkSsidStr isEqualToString:keys[i]]) {
++ ssid = QCFString::toQString(CFStringRef(objects[i]));
++ }
++ if(!userProfiles.contains(networkName)
++ && !ssid.isEmpty()) {
++ QMap map;
++ map.insert(ssid, QCFString::toQString(CFStringRef(nsInterfaceName)));
++ userProfiles.insert(networkName, map);
++ }
++ }
++ }
++ }
++ }
++ }
++ }
++ [autoreleasepool release];
++}
++
++QString QScanThread::getSsidFromNetworkName(const QString &name)
++{
++ QMutexLocker locker(&mutex);
++
++ QMapIterator > i(userProfiles);
++ while (i.hasNext()) {
++ i.next();
++ QMap map = i.value();
++ QMapIterator ij(i.value());
++ while (ij.hasNext()) {
++ ij.next();
++ const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") +i.key()));
++ if(name == i.key() || name == networkNameHash) {
++ return ij.key();
++ }
++ }
++ }
++ return QString();
++}
++
++QString QScanThread::getNetworkNameFromSsid(const QString &ssid)
++{
++ QMutexLocker locker(&mutex);
++
++ QMapIterator > i(userProfiles);
++ while (i.hasNext()) {
++ i.next();
++ QMap map = i.value();
++ QMapIterator ij(i.value());
++ while (ij.hasNext()) {
++ ij.next();
++ if(ij.key() == ssid) {
++ return i.key();
++ }
++ }
++ }
++ return QString();
++}
++
++bool QScanThread::isKnownSsid(const QString &ssid)
++{
++ QMutexLocker locker(&mutex);
++
++ QMapIterator > i(userProfiles);
++ while (i.hasNext()) {
++ i.next();
++ QMap map = i.value();
++ if(map.keys().contains(ssid)) {
++ return true;
++ }
++ }
++ return false;
++}
++
++
++QCoreWlanEngine::QCoreWlanEngine(QObject *parent)
++: QBearerEngineImpl(parent), scanThread(0)
++{
++ scanThread = new QScanThread(this);
++ connect(scanThread, SIGNAL(networksChanged()),
++ this, SLOT(networksChanged()));
++}
++
++QCoreWlanEngine::~QCoreWlanEngine()
++{
++ while (!foundConfigurations.isEmpty())
++ delete foundConfigurations.takeFirst();
++ [listener remove];
++ [listener release];
++}
++
++void QCoreWlanEngine::initialize()
++{
++ QMutexLocker locker(&mutex);
++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
++
++ if([[CWInterface supportedInterfaces] count] > 0 && !listener) {
++ listener = [[QT_MANGLE_NAMESPACE(QNSListener) alloc] init];
++ listener.engine = this;
++ hasWifi = true;
++ } else {
++ hasWifi = false;
++ }
++ storeSession = NULL;
++
++ startNetworkChangeLoop();
++ [autoreleasepool release];
++}
++
++
++QString QCoreWlanEngine::getInterfaceFromId(const QString &id)
++{
++ QMutexLocker locker(&mutex);
++
++ return scanThread->configurationInterface.value(id);
++}
++
++bool QCoreWlanEngine::hasIdentifier(const QString &id)
++{
++ QMutexLocker locker(&mutex);
++
++ return scanThread->configurationInterface.contains(id);
++}
++
++void QCoreWlanEngine::connectToId(const QString &id)
++{
++ QMutexLocker locker(&mutex);
++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
++ QString interfaceString = getInterfaceFromId(id);
++
++ CWInterface *wifiInterface =
++ [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)];
++
++ if ([wifiInterface power]) {
++ NSError *err = nil;
++ NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
++
++ QString wantedSsid;
++
++ QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
++
++ const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name));
++ const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name)));
++
++ bool using8021X = false;
++ if (idHash2 != id) {
++ NSArray *array = [CW8021XProfile allUser8021XProfiles];
++
++ for (NSUInteger i = 0; i < [array count]; ++i) {
++ const QString networkNameHashCheck = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef([[array objectAtIndex:i] userDefinedName]))));
++
++ const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef([[array objectAtIndex:i] ssid]))));
++
++ if (id == networkNameHashCheck || id == ssidHash) {
++ const QString thisName = scanThread->getSsidFromNetworkName(id);
++ if (thisName.isEmpty())
++ wantedSsid = id;
++ else
++ wantedSsid = thisName;
++
++ [params setValue: [array objectAtIndex:i] forKey:kCWAssocKey8021XProfile];
++ using8021X = true;
++ break;
++ }
++ }
++ }
++
++ if (!using8021X) {
++ QString wantedNetwork;
++ QMapIterator > i(scanThread->userProfiles);
++ while (i.hasNext()) {
++ i.next();
++ wantedNetwork = i.key();
++ const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork));
++ if (id == networkNameHash) {
++ wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork);
++ break;
++ }
++ }
++ }
++ NSDictionary *scanParameters = [NSDictionary dictionaryWithObjectsAndKeys:
++ [NSNumber numberWithBool:YES], kCWScanKeyMerge,
++ [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType,
++ [NSNumber numberWithInteger:100], kCWScanKeyRestTime,
++ (NSString *)QCFString::toCFStringRef(wantedSsid), kCWScanKeySSID,
++ nil];
++
++ NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err];
++
++ if(!err) {
++ for(uint row=0; row < [scanArray count]; row++ ) {
++ CWNetwork *apNetwork = [scanArray objectAtIndex:row];
++
++ if(wantedSsid == QCFString::toQString(CFStringRef([apNetwork ssid]))) {
++
++ if(!using8021X) {
++ SecKeychainAttribute attributes[3];
++
++ NSString *account = [apNetwork ssid];
++ NSString *keyKind = @"AirPort network password";
++ NSString *keyName = account;
++
++ attributes[0].tag = kSecAccountItemAttr;
++ attributes[0].data = (void *)[account UTF8String];
++ attributes[0].length = [account length];
++
++ attributes[1].tag = kSecDescriptionItemAttr;
++ attributes[1].data = (void *)[keyKind UTF8String];
++ attributes[1].length = [keyKind length];
++
++ attributes[2].tag = kSecLabelItemAttr;
++ attributes[2].data = (void *)[keyName UTF8String];
++ attributes[2].length = [keyName length];
++
++ SecKeychainAttributeList attributeList = {3,attributes};
++
++ SecKeychainSearchRef searchRef;
++ SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef);
++
++ NSString *password = @"";
++ SecKeychainItemRef searchItem;
++
++ if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) {
++ UInt32 realPasswordLength;
++ SecKeychainAttribute attributesW[8];
++ attributesW[0].tag = kSecAccountItemAttr;
++ SecKeychainAttributeList listW = {1,attributesW};
++ char *realPassword;
++ OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword);
++
++ if (status == noErr) {
++ if (realPassword != NULL) {
++
++ QByteArray pBuf;
++ pBuf.resize(realPasswordLength);
++ pBuf.prepend(realPassword);
++ pBuf.insert(realPasswordLength,'\0');
++
++ password = [NSString stringWithUTF8String:pBuf];
++ }
++ SecKeychainItemFreeContent(&listW, realPassword);
++ }
++
++ CFRelease(searchItem);
++ } else {
++ qDebug() << "SecKeychainSearchCopyNext error";
++ }
++ [params setValue: password forKey: kCWAssocKeyPassphrase];
++ } // end using8021X
++
++
++ bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err];
++
++ if(!err) {
++ if(!result) {
++ emit connectionError(id, ConnectError);
++ } else {
++ return;
++ }
++ } else {
++ qDebug() <<"associate ERROR"<< QCFString::toQString(CFStringRef([err localizedDescription ]));
++ }
++ }
++ } //end scan network
++ } else {
++ qDebug() <<"scan ERROR"<< QCFString::toQString(CFStringRef([err localizedDescription ]));
++ }
++ emit connectionError(id, InterfaceLookupError);
++ }
++
++ locker.unlock();
++ emit connectionError(id, InterfaceLookupError);
++ [autoreleasepool release];
++}
++
++void QCoreWlanEngine::disconnectFromId(const QString &id)
++{
++ QMutexLocker locker(&mutex);
++
++ QString interfaceString = getInterfaceFromId(id);
++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
++
++ CWInterface *wifiInterface =
++ [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)];
++
++ [wifiInterface disassociate];
++ if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) {
++ locker.unlock();
++ emit connectionError(id, DisconnectionError);
++ locker.relock();
++ }
++ [autoreleasepool release];
++}
++
++void QCoreWlanEngine::requestUpdate()
++{
++ scanThread->getUserConfigurations();
++ doRequestUpdate();
++}
++
++void QCoreWlanEngine::doRequestUpdate()
++{
++ QMutexLocker locker(&mutex);
++
++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
++
++ NSArray *wifiInterfaces = [CWInterface supportedInterfaces];
++ for (uint row = 0; row < [wifiInterfaces count]; ++row) {
++ scanThread->interfaceName = QCFString::toQString(CFStringRef([wifiInterfaces objectAtIndex:row]));
++ scanThread->start();
++ }
++ locker.unlock();
++ [autoreleasepool release];
++}
++
++bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName)
++{
++ QMutexLocker locker(&mutex);
++ bool haswifi = false;
++ if(hasWifi) {
++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
++ CWInterface *defaultInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(wifiDeviceName)];
++ if([defaultInterface power]) {
++ haswifi = true;
++ }
++ [autoreleasepool release];
++ }
++ return haswifi;
++}
++
++
++QNetworkSession::State QCoreWlanEngine::sessionStateForId(const QString &id)
++{
++ QMutexLocker locker(&mutex);
++ QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
++
++ if (!ptr)
++ return QNetworkSession::Invalid;
++
++ if (!ptr->isValid) {
++ return QNetworkSession::Invalid;
++ } else if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
++ return QNetworkSession::Connected;
++ } else if ((ptr->state & QNetworkConfiguration::Discovered) ==
++ QNetworkConfiguration::Discovered) {
++ return QNetworkSession::Disconnected;
++ } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) {
++ return QNetworkSession::NotAvailable;
++ } else if ((ptr->state & QNetworkConfiguration::Undefined) ==
++ QNetworkConfiguration::Undefined) {
++ return QNetworkSession::NotAvailable;
++ }
++
++ return QNetworkSession::Invalid;
++}
++
++QNetworkConfigurationManager::Capabilities QCoreWlanEngine::capabilities() const
++{
++ return QNetworkConfigurationManager::ForcedRoaming;
++}
++
++void QCoreWlanEngine::startNetworkChangeLoop()
++{
++
++ SCDynamicStoreContext dynStoreContext = { 0, this/*(void *)storeSession*/, NULL, NULL, NULL };
++ storeSession = SCDynamicStoreCreate(NULL,
++ CFSTR("networkChangeCallback"),
++ networkChangeCallback,
++ &dynStoreContext);
++ if (!storeSession ) {
++ qWarning() << "could not open dynamic store: error:" << SCErrorString(SCError());
++ return;
++ }
++
++ CFMutableArrayRef notificationKeys;
++ notificationKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
++ CFMutableArrayRef patternsArray;
++ patternsArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
++
++ CFStringRef storeKey;
++ storeKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
++ kSCDynamicStoreDomainState,
++ kSCEntNetIPv4);
++ CFArrayAppendValue(notificationKeys, storeKey);
++ CFRelease(storeKey);
++
++ storeKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
++ kSCDynamicStoreDomainState,
++ kSCCompAnyRegex,
++ kSCEntNetIPv4);
++ CFArrayAppendValue(patternsArray, storeKey);
++ CFRelease(storeKey);
++
++ if (!SCDynamicStoreSetNotificationKeys(storeSession , notificationKeys, patternsArray)) {
++ qWarning() << "register notification error:"<< SCErrorString(SCError());
++ CFRelease(storeSession );
++ CFRelease(notificationKeys);
++ CFRelease(patternsArray);
++ return;
++ }
++ CFRelease(notificationKeys);
++ CFRelease(patternsArray);
++
++ runloopSource = SCDynamicStoreCreateRunLoopSource(NULL, storeSession , 0);
++ if (!runloopSource) {
++ qWarning() << "runloop source error:"<< SCErrorString(SCError());
++ CFRelease(storeSession );
++ return;
++ }
++
++ CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode);
++ return;
++}
++
++QNetworkSessionPrivate *QCoreWlanEngine::createSessionBackend()
++{
++ return new QNetworkSessionPrivateImpl;
++}
++
++QNetworkConfigurationPrivatePointer QCoreWlanEngine::defaultConfiguration()
++{
++ return QNetworkConfigurationPrivatePointer();
++}
++
++bool QCoreWlanEngine::requiresPolling() const
++{
++ return true;
++}
++
++void QCoreWlanEngine::networksChanged()
++{
++ QMutexLocker locker(&mutex);
++
++ QStringList previous = accessPointConfigurations.keys();
++
++ QList foundConfigurations = scanThread->getConfigurations();
++ while (!foundConfigurations.isEmpty()) {
++ QNetworkConfigurationPrivate *cpPriv = foundConfigurations.takeFirst();
++
++ previous.removeAll(cpPriv->id);
++
++ if (accessPointConfigurations.contains(cpPriv->id)) {
++ QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id);
++
++ bool changed = false;
++
++ ptr->mutex.lock();
++
++ if (ptr->isValid != cpPriv->isValid) {
++ ptr->isValid = cpPriv->isValid;
++ changed = true;
++ }
++
++ if (ptr->name != cpPriv->name) {
++ ptr->name = cpPriv->name;
++ changed = true;
++ }
++
++ if (ptr->bearerType != cpPriv->bearerType) {
++ ptr->bearerType = cpPriv->bearerType;
++ changed = true;
++ }
++
++ if (ptr->state != cpPriv->state) {
++ ptr->state = cpPriv->state;
++ changed = true;
++ }
++
++ ptr->mutex.unlock();
++
++ if (changed) {
++ locker.unlock();
++ emit configurationChanged(ptr);
++ locker.relock();
++ }
++
++ delete cpPriv;
++ } else {
++ QNetworkConfigurationPrivatePointer ptr(cpPriv);
++
++ accessPointConfigurations.insert(ptr->id, ptr);
++
++ locker.unlock();
++ emit configurationAdded(ptr);
++ locker.relock();
++ }
++ }
++
++ while (!previous.isEmpty()) {
++ QNetworkConfigurationPrivatePointer ptr =
++ accessPointConfigurations.take(previous.takeFirst());
++
++ locker.unlock();
++ emit configurationRemoved(ptr);
++ locker.relock();
++ }
++
++ locker.unlock();
++ emit updateCompleted();
++
++}
++
++quint64 QCoreWlanEngine::bytesWritten(const QString &id)
++{
++ QMutexLocker locker(&mutex);
++ const QString interfaceStr = getInterfaceFromId(id);
++ return getBytes(interfaceStr,false);
++}
++
++quint64 QCoreWlanEngine::bytesReceived(const QString &id)
++{
++ QMutexLocker locker(&mutex);
++ const QString interfaceStr = getInterfaceFromId(id);
++ return getBytes(interfaceStr,true);
++}
++
++quint64 QCoreWlanEngine::startTime(const QString &identifier)
++{
++ QMutexLocker locker(&mutex);
++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
++ quint64 timestamp = 0;
++
++ NSString *filePath = @"/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist";
++ NSDictionary* plistDict = [[[NSDictionary alloc] initWithContentsOfFile:filePath] autorelease];
++ if(plistDict == nil)
++ return timestamp;
++ NSString *input = @"KnownNetworks";
++ NSString *timeStampStr = @"_timeStamp";
++
++ NSString *ssidStr = @"SSID_STR";
++
++ for (id key in plistDict) {
++ if ([input isEqualToString:key]) {
++
++ NSDictionary *knownNetworksDict = [plistDict objectForKey:key];
++ if(knownNetworksDict == nil)
++ return timestamp;
++ for (id networkKey in knownNetworksDict) {
++ bool isFound = false;
++ NSDictionary *itemDict = [knownNetworksDict objectForKey:networkKey];
++ if(itemDict == nil)
++ return timestamp;
++ NSInteger dictSize = [itemDict count];
++ id objects[dictSize];
++ id keys[dictSize];
++
++ [itemDict getObjects:objects andKeys:keys];
++ bool ok = false;
++ for(int i = 0; i < dictSize; i++) {
++ if([ssidStr isEqualToString:keys[i]]) {
++ const QString ident = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef(objects[i]))));
++ if(ident == identifier) {
++ ok = true;
++ }
++ }
++ if(ok && [timeStampStr isEqualToString:keys[i]]) {
++ timestamp = (quint64)[objects[i] timeIntervalSince1970];
++ isFound = true;
++ break;
++ }
++ }
++ if(isFound)
++ break;
++ }
++ }
++ }
++ [autoreleasepool release];
++ return timestamp;
++}
++
++quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b)
++{
++ struct ifaddrs *ifAddressList, *ifAddress;
++ struct if_data *if_data;
++
++ quint64 bytes = 0;
++ ifAddressList = nil;
++ if(getifaddrs(&ifAddressList) == 0) {
++ for(ifAddress = ifAddressList; ifAddress; ifAddress = ifAddress->ifa_next) {
++ if(interfaceName == ifAddress->ifa_name) {
++ if_data = (struct if_data*)ifAddress->ifa_data;
++ if(b) {
++ bytes = if_data->ifi_ibytes;
++ break;
++ } else {
++ bytes = if_data->ifi_obytes;
++ break;
++ }
++ }
++ }
++ freeifaddrs(ifAddressList);
++ }
++ return bytes;
++}
++
++QT_END_NAMESPACE
From 8c060691d732c95ca5868a26334a1c0381e0f586 Mon Sep 17 00:00:00 2001
From: Marius Kintel
Date: Thu, 5 Dec 2013 12:21:10 -0500
Subject: [PATCH 04/16] Update Mac deployment target to make it build on 10.9,
apply Qt4 patches
---
scripts/macosx-build-dependencies.sh | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh
index 19c97097..d4ca1f7c 100755
--- a/scripts/macosx-build-dependencies.sh
+++ b/scripts/macosx-build-dependencies.sh
@@ -24,7 +24,7 @@ BASEDIR=$PWD/../libraries
OPENSCADDIR=$PWD
SRCDIR=$BASEDIR/src
DEPLOYDIR=$BASEDIR/install
-MAC_OSX_VERSION_MIN=10.6
+MAC_OSX_VERSION_MIN=10.7
OPTION_32BIT=false
OPTION_LLVM=false
OPTION_CLANG=false
@@ -54,6 +54,9 @@ build_qt()
fi
tar xzf qt-everywhere-opensource-src-$version.tar.gz
cd qt-everywhere-opensource-src-$version
+ patch -p0 < $OPENSCADDIR/patches/qt4/patch-src_corelib_global_qglobal.h.diff
+ patch -p0 < $OPENSCADDIR/patches/qt4/patch-libtiff.diff
+ patch -p0 < $OPENSCADDIR/patches/qt4/patch-src_plugins_bearer_corewlan_qcorewlanengine.mm.diff
if $USING_CLANG; then
# FIX for clang
sed -i "" -e "s/::TabletProximityRec/TabletProximityRec/g" src/gui/kernel/qt_cocoa_helpers_mac_p.h
@@ -220,7 +223,7 @@ build_boost()
BOOST_TOOLSET="toolset=clang"
echo "using clang ;" >> tools/build/v2/user-config.jam
fi
- ./b2 -d+2 $BOOST_TOOLSET cflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS" linkflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS -headerpad_max_install_names" install
+ ./b2 -j6 -d+2 $BOOST_TOOLSET cflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS" linkflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS -headerpad_max_install_names" install
install_name_tool -id $DEPLOYDIR/lib/libboost_thread.dylib $DEPLOYDIR/lib/libboost_thread.dylib
install_name_tool -change libboost_system.dylib $DEPLOYDIR/lib/libboost_system.dylib $DEPLOYDIR/lib/libboost_thread.dylib
install_name_tool -change libboost_chrono.dylib $DEPLOYDIR/lib/libboost_chrono.dylib $DEPLOYDIR/lib/libboost_thread.dylib
From 38a342215970396a5590281cd66d0ca9c9ab7e98 Mon Sep 17 00:00:00 2001
From: Marius Kintel
Date: Fri, 6 Dec 2013 00:39:21 -0500
Subject: [PATCH 05/16] #559 fixes for 10.9
---
tests/CMakeLists.txt | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 0477a45d..b84775b8 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,6 +1,6 @@
# instructions - see ../doc/testing.txt
-# set(DEBUG_OSCD 1) # print debug info during cmake
+#set(DEBUG_OSCD 1) # print debug info during cmake
cmake_minimum_required(VERSION 2.8)
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3)
@@ -14,9 +14,16 @@ include(CMakeParseArguments.cmake)
# Detect Lion and force gcc
IF (APPLE)
+ # Somehow, since we build dependencies for 10.7, we need to also build executables
+ # for 10.7. This used to not be necessary, but since 10.9 it apparently is..
+ SET(CMAKE_OSX_DEPLOYMENT_TARGET 10.7)
EXECUTE_PROCESS(COMMAND sw_vers -productVersion OUTPUT_VARIABLE MACOSX_VERSION)
- IF (NOT ${MACOSX_VERSION} VERSION_LESS "10.8.0")
- message("Detected Mountain Lion (10.8) or later")
+ IF (NOT ${MACOSX_VERSION} VERSION_LESS "10.9.0")
+ message("Detected Maverick (10.9) or later")
+ set(CMAKE_C_COMPILER "clang")
+ set(CMAKE_CXX_COMPILER "clang++")
+ ELSEIF (NOT ${MACOSX_VERSION} VERSION_LESS "10.8.0")
+ message("Detected Mountain Lion (10.8)")
set(CMAKE_C_COMPILER "clang")
set(CMAKE_CXX_COMPILER "clang++")
ELSEIF (NOT ${MACOSX_VERSION} VERSION_LESS "10.7.0")
From e3317ecc64659ae8be2a7b02d4df17dad6d875db Mon Sep 17 00:00:00 2001
From: "David Eccles (gringer)"
Date: Fri, 6 Dec 2013 13:14:09 +1300
Subject: [PATCH 06/16] Fail if any polygon points for rotate_extrude are less
than 0
---
src/PolySetCGALEvaluator.cc | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc
index bc9206f3..e5eba2b9 100644
--- a/src/PolySetCGALEvaluator.cc
+++ b/src/PolySetCGALEvaluator.cc
@@ -457,7 +457,13 @@ PolySet *PolySetCGALEvaluator::rotateDxfData(const RotateExtrudeNode &node, DxfD
{
double max_x = 0;
for (size_t j = 0; j < dxf.paths[i].indices.size(); j++) {
- max_x = fmax(max_x, dxf.points[dxf.paths[i].indices[j]][0]);
+ double point_x = dxf.points[dxf.paths[i].indices[j]][0];
+ if(point_x < 0){
+ PRINT("ERROR: all points for rotate_extrude() must have non-negative X coordinates");
+ PRINT((boost::format("[Point %d on path %d has X coordinate %f]") % j % i % point_x).str());
+ return NULL;
+ }
+ max_x = fmax(max_x, point_x);
}
int fragments = get_fragments_from_r(max_x, node.fn, node.fs, node.fa);
From ede5c4b6882692dc28fc7017c4aeb87ec9222f8e Mon Sep 17 00:00:00 2001
From: Marius Kintel
Date: Fri, 6 Dec 2013 00:52:51 -0500
Subject: [PATCH 07/16] delete ps when short-circuiting return, no need for
explicit boost::format
---
src/PolySetCGALEvaluator.cc | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc
index e5eba2b9..599fd7f5 100644
--- a/src/PolySetCGALEvaluator.cc
+++ b/src/PolySetCGALEvaluator.cc
@@ -458,9 +458,10 @@ PolySet *PolySetCGALEvaluator::rotateDxfData(const RotateExtrudeNode &node, DxfD
double max_x = 0;
for (size_t j = 0; j < dxf.paths[i].indices.size(); j++) {
double point_x = dxf.points[dxf.paths[i].indices[j]][0];
- if(point_x < 0){
+ if (point_x < 0) {
PRINT("ERROR: all points for rotate_extrude() must have non-negative X coordinates");
- PRINT((boost::format("[Point %d on path %d has X coordinate %f]") % j % i % point_x).str());
+ PRINTB("[Point %d on path %d has X coordinate %f]", j % i % point_x);
+ delete ps;
return NULL;
}
max_x = fmax(max_x, point_x);
From b131464f954b2d10f6b065b45038652af2379742 Mon Sep 17 00:00:00 2001
From: Marius Kintel
Date: Sun, 8 Dec 2013 13:50:03 -0500
Subject: [PATCH 08/16] #559 CMAKE_OSX_DEPLOYMENT_TARGET needs to be cached
---
tests/CMakeLists.txt | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index b84775b8..f92eddf5 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -14,14 +14,14 @@ include(CMakeParseArguments.cmake)
# Detect Lion and force gcc
IF (APPLE)
- # Somehow, since we build dependencies for 10.7, we need to also build executables
- # for 10.7. This used to not be necessary, but since 10.9 it apparently is..
- SET(CMAKE_OSX_DEPLOYMENT_TARGET 10.7)
EXECUTE_PROCESS(COMMAND sw_vers -productVersion OUTPUT_VARIABLE MACOSX_VERSION)
IF (NOT ${MACOSX_VERSION} VERSION_LESS "10.9.0")
message("Detected Maverick (10.9) or later")
set(CMAKE_C_COMPILER "clang")
set(CMAKE_CXX_COMPILER "clang++")
+ # Somehow, since we build dependencies for 10.7, we need to also build executables
+ # for 10.7. This used to not be necessary, but since 10.9 it apparently is..
+ SET(CMAKE_OSX_DEPLOYMENT_TARGET 10.7 CACHE STRING "Deployment target")
ELSEIF (NOT ${MACOSX_VERSION} VERSION_LESS "10.8.0")
message("Detected Mountain Lion (10.8)")
set(CMAKE_C_COMPILER "clang")
From 88cc7edafd47ec167609c05eb22c3f8eb642d225 Mon Sep 17 00:00:00 2001
From: Marius Kintel
Date: Sun, 8 Dec 2013 15:16:58 -0500
Subject: [PATCH 09/16] #559 Fix Qt font rendering on OS X 10.9
---
patches/qt4/patch-qeventdispatcher.diff | 86 +++++++++++++++++++++++++
patches/qt4/patch-qfontdatabase.diff | 29 +++++++++
2 files changed, 115 insertions(+)
create mode 100644 patches/qt4/patch-qeventdispatcher.diff
create mode 100644 patches/qt4/patch-qfontdatabase.diff
diff --git a/patches/qt4/patch-qeventdispatcher.diff b/patches/qt4/patch-qeventdispatcher.diff
new file mode 100644
index 00000000..89ed4788
--- /dev/null
+++ b/patches/qt4/patch-qeventdispatcher.diff
@@ -0,0 +1,86 @@
+--- src/gui/kernel/qeventdispatcher_mac_p.h 2013-06-07 01:16:59.000000000 -0400
++++ src/gui/kernel/qeventdispatcher_mac_p_new-8184b49c12d887928921ed5b695c8c6f04a07514.h 2013-12-08 14:31:01.000000000 -0500
+@@ -173,6 +173,7 @@
+ #ifdef QT_MAC_USE_COCOA
+ // The following variables help organizing modal sessions:
+ static QStack cocoaModalSessionStack;
++ static QStack cocoaModalSessionStackPendingEnd;
+ static bool currentExecIsNSAppRun;
+ static bool nsAppRunCalledByQt;
+ static bool cleanupModalSessionsNeeded;
+@@ -180,6 +181,7 @@
+ static NSModalSession currentModalSession();
+ static void updateChildrenWorksWhenModal();
+ static void temporarilyStopAllModalSessions();
++ static void stopAllPendingEndModalSessions();
+ static void beginModalSession(QWidget *widget);
+ static void endModalSession(QWidget *widget);
+ static void cancelWaitForMoreEvents();
+--- src/gui/kernel/qeventdispatcher_mac.mm 2013-06-07 01:16:59.000000000 -0400
++++ src/gui/kernel/qeventdispatcher_mac_new-833e02de99494686f8dd7a567f6e19e847508f11.mm 2013-12-08 14:30:59.000000000 -0500
+@@ -603,6 +603,9 @@
+ while ([NSApp runModalSession:session] == NSRunContinuesResponse && !d->interrupt)
+ qt_mac_waitForMoreModalSessionEvents();
+
++ // stop all pending end modal sessions
++ d->stopAllPendingEndModalSessions();
++
+ if (!d->interrupt && session == d->currentModalSessionCached) {
+ // Someone called [NSApp stopModal:] from outside the event
+ // dispatcher (e.g to stop a native dialog). But that call wrongly stopped
+@@ -678,6 +681,9 @@
+ if (!d->interrupt)
+ QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
+
++ // stop all pending end modal sessions
++ d->stopAllPendingEndModalSessions();
++
+ // Since the window that holds modality might have changed while processing
+ // events, we we need to interrupt when we return back the previous process
+ // event recursion to ensure that we spin the correct modal session.
+@@ -781,6 +787,7 @@
+
+ #ifdef QT_MAC_USE_COCOA
+ QStack QEventDispatcherMacPrivate::cocoaModalSessionStack;
++QStack QEventDispatcherMacPrivate::cocoaModalSessionStackPendingEnd;
+ bool QEventDispatcherMacPrivate::currentExecIsNSAppRun = false;
+ bool QEventDispatcherMacPrivate::nsAppRunCalledByQt = false;
+ bool QEventDispatcherMacPrivate::cleanupModalSessionsNeeded = false;
+@@ -828,6 +835,20 @@
+ currentModalSessionCached = 0;
+ }
+
++void QEventDispatcherMacPrivate::stopAllPendingEndModalSessions()
++{
++ // stop all modal sessions pending end
++ int stackSize = cocoaModalSessionStackPendingEnd.size();
++ for (int i=stackSize-1; i>=0; --i) {
++ QCocoaModalSessionInfo &info = cocoaModalSessionStackPendingEnd[i];
++ cocoaModalSessionStackPendingEnd.remove(i);
++ if (info.session) {
++ [NSApp endModalSession:info.session];
++ [(NSWindow *)info.nswindow release];
++ }
++ }
++}
++
+ NSModalSession QEventDispatcherMacPrivate::currentModalSession()
+ {
+ // If we have one or more modal windows, this function will create
+@@ -925,10 +946,12 @@
+ }
+ cocoaModalSessionStack.remove(i);
+ currentModalSessionCached = 0;
+- if (info.session) {
+- [NSApp endModalSession:info.session];
+- [(NSWindow *)info.nswindow release];
+- }
++
++ // Cannot stop the sessions here since we might still be inside a
++ // [NSApp runModalSession:] call. Add the session to the pending end stack and
++ // process the stack after the call to [NSApp runModalSession:] returns.
++ if (info.session)
++ cocoaModalSessionStackPendingEnd.push(info);
+ }
+
+ updateChildrenWorksWhenModal();
diff --git a/patches/qt4/patch-qfontdatabase.diff b/patches/qt4/patch-qfontdatabase.diff
new file mode 100644
index 00000000..c0788906
--- /dev/null
+++ b/patches/qt4/patch-qfontdatabase.diff
@@ -0,0 +1,29 @@
+--- src/gui/text/qfontdatabase.cpp 2013-06-07 01:16:59.000000000 -0400
++++ src/gui/text/qfontdatabase_new-bb2beddc3ae55c4676d190d0ac99aa32d322a6a5.cpp 2013-12-08 14:51:10.000000000 -0500
+@@ -441,6 +441,7 @@
+ #endif
+ #if !defined(QWS) && defined(Q_OS_MAC)
+ bool fixedPitchComputed : 1;
++ QString postscriptName;
+ #endif
+ #ifdef Q_WS_X11
+ bool symbol_checked : 1;
+--- src/gui/text/qfontdatabase_mac.cpp 2013-06-07 01:16:59.000000000 -0400
++++ src/gui/text/qfontdatabase_mac_new-41f29865db84152efb41c048470f713353a0a84c.cpp 2013-12-08 14:51:05.000000000 -0500
+@@ -147,6 +147,7 @@
+ QCFString family_name = (CFStringRef)CTFontDescriptorCopyLocalizedAttribute(font, kCTFontFamilyNameAttribute, NULL);
+ QCFString style_name = (CFStringRef)CTFontDescriptorCopyLocalizedAttribute(font, kCTFontStyleNameAttribute, NULL);
+ QtFontFamily *family = db->family(family_name, true);
++ family->postscriptName = QCFString((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontNameAttribute));
+
+ if (QCFType languages = (CFArrayRef) CTFontDescriptorCopyAttribute(font, kCTFontLanguagesAttribute)) {
+ CFIndex length = CFArrayGetCount(languages);
+@@ -327,7 +328,7 @@
+ if (db->families[k]->name.compare(family_list.at(i), Qt::CaseInsensitive) == 0) {
+ QByteArray family_name = db->families[k]->name.toUtf8();
+ #if defined(QT_MAC_USE_COCOA)
+- QCFType ctFont = CTFontCreateWithName(QCFString(db->families[k]->name), 12, NULL);
++ QCFType ctFont = CTFontCreateWithName(QCFString(db->families[k]->postscriptName), 12, NULL);
+ if (ctFont) {
+ fontName = CTFontCopyFullName(ctFont);
+ goto found;
From eb046015d2fd4fa3e4e3c8844cd6dc8f4d3eca99 Mon Sep 17 00:00:00 2001
From: Marius Kintel
Date: Sun, 8 Dec 2013 15:17:17 -0500
Subject: [PATCH 10/16] #559 Fix Qt font rendering on OS X 10.9
---
src/openscad.cc | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/openscad.cc b/src/openscad.cc
index ece68189..ab842357 100644
--- a/src/openscad.cc
+++ b/src/openscad.cc
@@ -474,6 +474,13 @@ bool QtUseGUI()
int gui(vector &inputFiles, const fs::path &original_path, int argc, char ** argv)
{
+#ifdef Q_OS_MACX
+ if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_8) {
+ // fix Mac OS X 10.9 (mavericks) font issue
+ // https://bugreports.qt-project.org/browse/QTBUG-32789
+ QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande");
+ }
+#endif
QApplication app(argc, argv, true); //useGUI);
#ifdef Q_WS_MAC
app.installEventFilter(new EventFilter(&app));
From 7075d8d9c4dde62798022bdfe02c5d57e997ba43 Mon Sep 17 00:00:00 2001
From: Brody Kenrick
Date: Thu, 5 Dec 2013 15:56:50 +1100
Subject: [PATCH 11/16] Fix for bad boost libraries
Get this error because of a search for a non-existent library on linux64
-----------
[ 69%] Built target tests-cgal
Scanning dependencies of target cgalcachetest
[ 70%] Building CXX object
CMakeFiles/cgalcachetest.dir/cgalcachetest.cc.o
make[2]: *** No rule to make target `/usr/lib/libboost_thread.so',
needed by `cgalcachetest'. Stop.
make[1]: *** [CMakeFiles/cgalcachetest.dir/all] Error 2
make: *** [all] Error 2
[2]+ Done gedit openscad.pro (wd:
~/git/openscad_unicode)
----------
---
tests/CMakeLists.txt | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index f92eddf5..d7ad18a4 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -384,11 +384,45 @@ if("${CGAL_MAJOR_VERSION}.${CGAL_MINOR_VERSION}" VERSION_LESS 3.6)
endif()
inclusion(CGAL_DIR CGAL_INCLUDE_DIRS)
+#Get rid of bad libraries suggested for BOOST dependencies (they don't exist on some machines and cause build failures).
+#/usr/lib/libboost_thread.so;/usr/lib/libboost_system.so;
+string(FIND "${CGAL_3RD_PARTY_LIBRARIES}" "/usr/lib/libboost_system.so" FIND_POSITION )
+if(NOT "-1" STREQUAL ${FIND_POSITION} )
+if(NOT EXISTS "/usr/lib/libboost_system.so")
+ MESSAGE( WARNING "CGAL_3RD_PARTY_LIBRARIES:Found erroneous /usr/lib/libboost_system.so -- stripping" )
+ string(REPLACE "/usr/lib/libboost_system.so" "" CGAL_3RD_PARTY_LIBRARIES ${CGAL_3RD_PARTY_LIBRARIES})
+endif()
+endif()
+string(FIND "${CGAL_3RD_PARTY_LIBRARIES}" "/usr/lib/libboost_thread.so" FIND_POSITION )
+if(NOT "-1" STREQUAL ${FIND_POSITION} )
+if(NOT EXISTS "/usr/lib/libboost_thread.so")
+ MESSAGE( WARNING "CGAL_3RD_PARTY_LIBRARIES:Found erroneous /usr/lib/libboost_thread.so -- stripping" )
+ string(REPLACE "/usr/lib/libboost_thread.so" "" CGAL_3RD_PARTY_LIBRARIES ${CGAL_3RD_PARTY_LIBRARIES})
+endif()
+endif()
if(${CMAKE_CXX_COMPILER} MATCHES ".*clang.*" AND NOT ${CGAL_CXX_FLAGS_INIT} STREQUAL "" )
string(REPLACE "-frounding-math" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
string(REPLACE "--param=ssp-buffer-size=4" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
endif()
+if (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "")
+ # Force pkg-config to look _only_ in the local library folder
+ # in case OPENSCAD_LIBRARIES is set.
+ set(ENV{PKG_CONFIG_PATH} "$ENV{OPENSCAD_LIBRARIES}/lib/pkgconfig")
+ set(ENV{PKG_CONFIG_LIBDIR} "$ENV{OPENSCAD_LIBRARIES}/lib/pkgconfig")
+endif()
+
+# Find libraries (system installed or dependency built) using pkg-config
+find_package(PkgConfig REQUIRED)
+
+#GLib-2
+pkg_search_module(GLIB2 REQUIRED glib-2.0>=2.2.0)
+#Can't use the CXXFlags directly as they are ;-separated
+string(REPLACE ";" " " GLIB2_CFLAGS "${GLIB2_CFLAGS}")
+message(STATUS "glib-2.0 found: ${GLIB2_VERSION}")
+
+add_definitions(${GLIB2_CFLAGS})
+
# Imagemagick
if (SKIP_IMAGEMAGICK)
From 3abf64249fd667f0b7f558ecfbbf35cfe9916a5d Mon Sep 17 00:00:00 2001
From: Brody Kenrick
Date: Thu, 5 Dec 2013 17:56:54 +1100
Subject: [PATCH 12/16] Unicode support for strings
Add suport for using unicode strings in .scad files. Support iterating
across them/accessing them via [] and searching.
--------
Add GLIB (to build for test and normal build -- both with installed and
built locally development files).
Add support for unicode chars to length and search builtin functions and
[] for strings.
Added unicode testing functions.
Ad GLIB to library info page.
---
.gitignore | 1 +
README.md | 1 +
common.pri | 1 +
glib-2.0.pri | 38 ++++++
openscad.pro | 3 +-
scripts/check-dependencies.sh | 17 ++-
scripts/uni-build-dependencies.sh | 1 +
scripts/uni-get-dependencies.sh | 15 +--
src/AboutDialog.html | 1 +
src/PlatformUtils.cc | 3 +
src/func.cc | 49 ++++++--
src/value.cc | 18 ++-
testdata/scad/misc/search-tests-unicode.scad | 116 ++++++++++++++++++
testdata/scad/misc/string-unicode.scad | 36 ++++++
tests/CMakeLists.txt | 6 +-
.../search-tests-unicode-expected.echo | 109 ++++++++++++++++
.../echotest/string-unicode-expected.echo | 104 ++++++++++++++++
17 files changed, 497 insertions(+), 22 deletions(-)
create mode 100644 glib-2.0.pri
create mode 100644 testdata/scad/misc/search-tests-unicode.scad
create mode 100644 testdata/scad/misc/string-unicode.scad
create mode 100644 tests/regression/echotest/search-tests-unicode-expected.echo
create mode 100644 tests/regression/echotest/string-unicode-expected.echo
diff --git a/.gitignore b/.gitignore
index 50dace12..59bac496 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
/*.scad
*.dmg
+*~
*.tar*
Makefile
objects
diff --git a/README.md b/README.md
index 27f12cec..1e97e0f6 100644
--- a/README.md
+++ b/README.md
@@ -93,6 +93,7 @@ Follow the instructions for the platform you're compiling on below.
* [OpenCSG (1.3.2)](http://www.opencsg.org/)
* [GLEW (1.5.4 ->)](http://glew.sourceforge.net/)
* [Eigen (3.0 - 3.2)](http://eigen.tuxfamily.org/)
+* [glib2 (2.2.0)](https://developer.gnome.org/glib/)
* [GCC C++ Compiler (4.2 ->)](http://gcc.gnu.org/)
* [Bison (2.4)](http://www.gnu.org/software/bison/)
* [Flex (2.5.35)](http://flex.sourceforge.net/)
diff --git a/common.pri b/common.pri
index 7153ded7..696c8b1d 100644
--- a/common.pri
+++ b/common.pri
@@ -11,3 +11,4 @@ include(opencsg.pri)
include(glew.pri)
include(eigen.pri)
include(boost.pri)
+include(glib-2.0.pri)
\ No newline at end of file
diff --git a/glib-2.0.pri b/glib-2.0.pri
new file mode 100644
index 00000000..0fbc4e2d
--- /dev/null
+++ b/glib-2.0.pri
@@ -0,0 +1,38 @@
+# Detect glib-2.0, then use this priority list to determine
+# which library to use:
+#
+# Priority
+# 1. GLIB2_INCLUDEPATH / GLIB2_LIBPATH (qmake parameter, not checked it given on commandline)
+# 2. OPENSCAD_LIBRARIES (environment variable)
+# 3. system's standard include paths from pkg-config
+
+glib-2.0 {
+
+# read environment variables
+OPENSCAD_LIBRARIES_DIR = $$(OPENSCAD_LIBRARIES)
+GLIB2_DIR = $$(GLIB2DIR)
+
+!isEmpty(OPENSCAD_LIBRARIES_DIR) {
+ isEmpty(GLIB2_INCLUDEPATH) {
+ GLIB2_INCLUDEPATH_1 = $$OPENSCAD_LIBRARIES_DIR/include/glib-2.0
+ GLIB2_INCLUDEPATH_2 = $$OPENSCAD_LIBRARIES_DIR/lib/glib-2.0/include
+ GLIB2_LIBPATH = $$OPENSCAD_LIBRARIES_DIR/lib
+ }
+}
+
+isEmpty(GLIB2_INCLUDEPATH) {
+ GLIB2_CFLAGS = $$system("pkg-config --cflags glib-2.0")
+} else {
+ GLIB2_CFLAGS = -I$$GLIB2_INCLUDEPATH_1
+ GLIB2_CFLAGS += -I$$GLIB2_INCLUDEPATH_2
+}
+
+isEmpty(GLIB2_LIBPATH) {
+ GLIB2_LIBS = $$system("pkg-config --libs glib-2.0")
+} else {
+ GLIB2_LIBS = -L$$GLIB2_LIBPATH -lglib-2.0
+}
+
+QMAKE_CXXFLAGS += $$GLIB2_CFLAGS
+LIBS += $$GLIB2_LIBS
+}
diff --git a/openscad.pro b/openscad.pro
index b38419ef..ec5af20c 100644
--- a/openscad.pro
+++ b/openscad.pro
@@ -8,7 +8,7 @@
# OPENCSGDIR
# OPENSCAD_LIBRARIES
#
-# Please see the 'Buildling' sections of the OpenSCAD user manual
+# Please see the 'Building' sections of the OpenSCAD user manual
# for updated tips & workarounds.
#
# http://en.wikibooks.org/wiki/OpenSCAD_User_Manual
@@ -156,6 +156,7 @@ CONFIG += cgal
CONFIG += opencsg
CONFIG += boost
CONFIG += eigen
+CONFIG += glib-2.0
#Uncomment the following line to enable QCodeEdit
#CONFIG += qcodeedit
diff --git a/scripts/check-dependencies.sh b/scripts/check-dependencies.sh
index b63c6770..e5871989 100755
--- a/scripts/check-dependencies.sh
+++ b/scripts/check-dependencies.sh
@@ -66,6 +66,21 @@ cgal_sysver()
cgal_sysver_result=`grep "define *CGAL_VERSION *[0-9.]*" $cgalpath | awk '{print $3}'`
}
+glib2_sysver()
+{
+ #Get architecture triplet - e.g. x86_64-linux-gnu
+ glib2archtriplet=`gcc -dumpmachine 2>/dev/null`
+ if [ -z "$VAR" ]; then
+ glib2archtriplet=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null`
+ fi
+ glib2path=$1/lib/$glib2archtriplet/glib-2.0/include/glibconfig.h
+ if [ ! -e $glib2path ]; then return; fi
+ glib2major=`grep "define *GLIB_MAJOR_VERSION *[0-9.]*" $glib2path | awk '{print $3}'`
+ glib2minor=`grep "define *GLIB_MINOR_VERSION *[0-9.]*" $glib2path | awk '{print $3}'`
+ glib2micro=`grep "define *GLIB_MICRO_VERSION *[0-9.]*" $glib2path | awk '{print $3}'`
+ glib2_sysver_result="${glib2major}.${glib2minor}.${glib2micro}"
+}
+
boost_sysver()
{
boostpath=$1/include/boost/version.hpp
@@ -530,7 +545,7 @@ checkargs()
main()
{
- deps="qt4 cgal gmp mpfr boost opencsg glew eigen gcc bison flex make"
+ deps="qt4 cgal gmp mpfr boost opencsg glew eigen glib2 gcc bison flex make"
#deps="$deps curl git" # not technically necessary for build
#deps="$deps python cmake imagemagick" # only needed for tests
#deps="cgal"
diff --git a/scripts/uni-build-dependencies.sh b/scripts/uni-build-dependencies.sh
index e652c473..8d912c35 100755
--- a/scripts/uni-build-dependencies.sh
+++ b/scripts/uni-build-dependencies.sh
@@ -603,5 +603,6 @@ build_boost 1.53.0
build_cgal 4.0.2
build_glew 1.9.0
build_opencsg 1.3.2
+build_glib2 2.38.2
echo "OpenSCAD dependencies built and installed to " $BASEDIR
diff --git a/scripts/uni-get-dependencies.sh b/scripts/uni-get-dependencies.sh
index a0306ef8..d2408c00 100755
--- a/scripts/uni-get-dependencies.sh
+++ b/scripts/uni-get-dependencies.sh
@@ -8,7 +8,7 @@ get_fedora_deps()
{
sudo yum install qt-devel bison flex eigen3-devel python-paramiko \
boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc gcc-c++ pkgconfig \
- opencsg-devel git libXmu-devel curl imagemagick ImageMagick make \
+ opencsg-devel git libXmu-devel curl imagemagick ImageMagick glib2-devel make \
xorg-x11-server-Xvfb
}
@@ -21,7 +21,7 @@ get_altlinux_deps()
{
for i in boost-devel boost-filesystem-devel gcc4.5 gcc4.5-c++ boost-program_options-devel \
boost-thread-devel boost-system-devel boost-regex-devel eigen3 libmpfr libgmp libgmp_cxx-devel qt4-devel libcgal-devel git-core \
- libglew-devel flex bison curl imagemagick; do sudo apt-get install $i; done
+ libglew-devel flex bison curl imagemagick glib2-devel; do sudo apt-get install $i; done
}
get_freebsd_deps()
@@ -29,20 +29,21 @@ get_freebsd_deps()
pkg_add -r bison boost-libs cmake git bash eigen3 flex gmake gmp mpfr \
xorg libGLU libXmu libXi xorg-vfbserver glew \
qt4-corelib qt4-gui qt4-moc qt4-opengl qt4-qmake qt4-rcc qt4-uic \
- opencsg cgal curl imagemagick
+ opencsg cgal curl imagemagick glib2-devel
}
get_netbsd_deps()
{
sudo pkgin install bison boost cmake git bash eigen flex gmake gmp mpfr \
qt4 glew cgal opencsg modular-xorg python27 py27-paramiko curl \
- imagemagick ImageMagick
+ imagemagick ImageMagick glib2-devel
}
get_opensuse_deps()
{
sudo zypper install libeigen3-devel mpfr-devel gmp-devel boost-devel \
- libqt4-devel glew-devel cmake git bison flex cgal-devel opencsg-devel curl
+ libqt4-devel glew-devel cmake git bison flex cgal-devel opencsg-devel curl \
+ glib2-devel
}
get_mageia_deps()
@@ -50,7 +51,7 @@ get_mageia_deps()
sudo urpmi ctags
sudo urpmi task-c-devel task-c++-devel libqt4-devel libgmp-devel \
libmpfr-devel libboost-devel eigen3-devel libglew-devel bison flex \
- cmake imagemagick python curl git x11-server-xvfb
+ cmake imagemagick glib2-devel python curl git x11-server-xvfb
}
get_debian_deps()
@@ -59,7 +60,7 @@ get_debian_deps()
libxmu-dev cmake bison flex git-core libboost-all-dev \
libXi-dev libmpfr-dev libboost-dev libglew-dev \
libeigen3-dev libcgal-dev libopencsg-dev libgmp3-dev libgmp-dev \
- python-paramiko curl imagemagick; do
+ python-paramiko curl imagemagick libglib2.0-dev; do
sudo apt-get -y install $pkg;
done
}
diff --git a/src/AboutDialog.html b/src/AboutDialog.html
index 99e7c3b2..65a54d71 100644
--- a/src/AboutDialog.html
+++ b/src/AboutDialog.html
@@ -64,6 +64,7 @@ Please visit this link for a copy of the license: C++, GCC, clang
python
Nullsoft installer
+GLib
diff --git a/src/PlatformUtils.cc b/src/PlatformUtils.cc
index b02b822e..8b39f6df 100644
--- a/src/PlatformUtils.cc
+++ b/src/PlatformUtils.cc
@@ -1,6 +1,8 @@
#include "PlatformUtils.h"
#include "boosty.h"
+#include
+
bool PlatformUtils::createLibraryPath()
{
std::string path = PlatformUtils::libraryPath();
@@ -114,6 +116,7 @@ std::string PlatformUtils::info()
<< "\nOpenCSG version: " << OPENCSG_VERSION_STRING
<< "\nQt version: " << qtVersion
<< "\nMingW build: " << mingwstatus
+ << "\nGLib version: " << GLIB_MAJOR_VERSION << "." << GLIB_MINOR_VERSION << "." << GLIB_MICRO_VERSION
<< "\nOPENSCADPATH: " << getenv("OPENSCADPATH") << "\n"
;
return s.str();
diff --git a/src/func.cc b/src/func.cc
index 865a2b42..4587f725 100644
--- a/src/func.cc
+++ b/src/func.cc
@@ -45,6 +45,8 @@
#include
#include
+/*Unicode support for string lengths and array accesses*/
+#include
#ifdef __WIN32__
#include
@@ -306,7 +308,11 @@ Value builtin_length(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1) {
if (evalctx->getArgValue(0).type() == Value::VECTOR) return Value(int(evalctx->getArgValue(0).toVector().size()));
- if (evalctx->getArgValue(0).type() == Value::STRING) return Value(int(evalctx->getArgValue(0).toString().size()));
+ if (evalctx->getArgValue(0).type() == Value::STRING) {
+ //Unicode glyph count for the length -- rather than the string (num. of bytes) length.
+ std::string text = evalctx->getArgValue(0).toString();
+ return Value(int( g_utf8_strlen( text.c_str(), text.size() ) ));
+ }
}
return Value();
}
@@ -380,10 +386,17 @@ Value builtin_lookup(const Context *, const EvalContext *evalctx)
num_returns_per_match : int;
index_col_num : int;
+ The search string and searched strings can be unicode strings.
Examples:
Index values return as list:
search("a","abcdabcd");
- - returns [0,4]
+ - returns [0]
+ search("Π","Π"); //A unicode string
+ - returns [0]
+ search("π‘aΠ","aπ‘Ππ‘aπ‘Ππ‘a",0);
+ - returns [[1,3,5,7],[0,4,8],[2,6]]
+ search("a","abcdabcd",0); //Search up to all matches
+ - returns [[0,4]]
search("a","abcdabcd",1);
- returns [0]
search("e","abcdabcd",1);
@@ -433,16 +446,25 @@ Value builtin_search(const Context *, const EvalContext *evalctx)
}
} else if (findThis.type() == Value::STRING) {
unsigned int searchTableSize;
- if (searchTable.type() == Value::STRING) searchTableSize = searchTable.toString().size();
- else searchTableSize = searchTable.toVector().size();
- for (size_t i = 0; i < findThis.toString().size(); i++) {
+ //Unicode glyph count for the length
+ unsigned int findThisSize = g_utf8_strlen( findThis.toString().c_str(), findThis.toString().size() );
+ if (searchTable.type() == Value::STRING) {
+ searchTableSize = g_utf8_strlen( searchTable.toString().c_str(), searchTable.toString().size() );
+ } else {
+ searchTableSize = searchTable.toVector().size();
+ }
+ for (size_t i = 0; i < findThisSize; i++) {
unsigned int matchCount = 0;
Value::VectorType resultvec;
for (size_t j = 0; j < searchTableSize; j++) {
- if ((searchTable.type() == Value::VECTOR &&
- findThis.toString()[i] == searchTable.toVector()[j].toVector()[index_col_num].toString()[0]) ||
- (searchTable.type() == Value::STRING &&
- findThis.toString()[i] == searchTable.toString()[j])) {
+ gchar* ptr_ft = g_utf8_offset_to_pointer(findThis.toString().c_str(), i);
+ gchar* ptr_st = NULL;
+ if(searchTable.type() == Value::VECTOR) {
+ ptr_st = g_utf8_offset_to_pointer(searchTable.toVector()[j].toVector()[index_col_num].toString().c_str(), 0);
+ } else if(searchTable.type() == Value::STRING){
+ ptr_st = g_utf8_offset_to_pointer(searchTable.toString().c_str(), j);
+ }
+ if( (ptr_ft) && (ptr_st) && (g_utf8_get_char(ptr_ft) == g_utf8_get_char(ptr_st)) ) {
Value resultValue((double(j)));
matchCount++;
if (num_returns_per_match == 1) {
@@ -454,7 +476,14 @@ Value builtin_search(const Context *, const EvalContext *evalctx)
if (num_returns_per_match > 1 && matchCount >= num_returns_per_match) break;
}
}
- if (matchCount == 0) PRINTB(" WARNING: search term not found: \"%s\"", findThis.toString()[i]);
+ if (matchCount == 0) {
+ gchar* ptr_ft = g_utf8_offset_to_pointer(findThis.toString().c_str(), i);
+ gchar utf8_of_cp[6] = ""; //A buffer for a single unicode character to be copied into
+ if(ptr_ft) {
+ g_utf8_strncpy( utf8_of_cp, ptr_ft, 1 );
+ }
+ PRINTB(" WARNING: search term not found: \"%s\"", utf8_of_cp );
+ }
if (num_returns_per_match == 0 || num_returns_per_match > 1) {
returnvec.push_back(Value(resultvec));
}
diff --git a/src/value.cc b/src/value.cc
index 5afb650c..c8a88c69 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -36,6 +36,8 @@
#include
#include "boost-utils.h"
#include "boosty.h"
+/*Unicode support for string lengths and array accesses*/
+#include
std::ostream &operator<<(std::ostream &stream, const Filename &filename)
{
@@ -579,14 +581,28 @@ Value Value::operator-() const
}
*/
+/*
+ * bracket operation [] detecting multi-byte unicode.
+ * If the string is multi-byte unicode then the index will offset to the character (2 or 4 byte) and not to the byte.
+ * A 'normal' string with byte chars are a subset of unicode and still work.
+ */
class bracket_visitor : public boost::static_visitor
{
public:
Value operator()(const std::string &str, const double &idx) const {
int i = int(idx);
Value v;
+ //Check that the index is positive and less than the size in bytes
if ((i >= 0) && (i < (int)str.size())) {
- v = Value(str[int(idx)]);
+ //Ensure character (not byte) index is inside the character/glyph array
+ if( (unsigned) i < g_utf8_strlen( str.c_str(), str.size() ) ) {
+ gchar utf8_of_cp[6] = ""; //A buffer for a single unicode character to be copied into
+ gchar* ptr = g_utf8_offset_to_pointer(str.c_str(), i);
+ if(ptr) {
+ g_utf8_strncpy(utf8_of_cp, ptr, 1);
+ }
+ v = std::string(utf8_of_cp);
+ }
// std::cout << "bracket_visitor: " << v << "\n";
}
return v;
diff --git a/testdata/scad/misc/search-tests-unicode.scad b/testdata/scad/misc/search-tests-unicode.scad
new file mode 100644
index 00000000..d863eff9
--- /dev/null
+++ b/testdata/scad/misc/search-tests-unicode.scad
@@ -0,0 +1,116 @@
+//Test search with unicode strings
+
+//Helper function that pretty prints our search test
+//Expected result is checked against execution of a search() invocation and OK/FAIL is indicated
+module test_search_and_echo( exp_res, search_to_find, search_to_search, search_up_to_num_matches = undef)
+{
+ if(undef != search_up_to_num_matches)
+ {
+ assign( test_res = search(search_to_find, search_to_search, search_up_to_num_matches) )
+ echo(str("Expect ", exp_res, " for search(", search_to_find, ", ", search_to_search, ", ", search_up_to_num_matches, ")=", test_res, ". ", (exp_res == test_res)?"OK":"FAIL" ));
+ }
+ else
+ {
+ assign( test_res = search(search_to_find, search_to_search) )
+ echo(str("Expect ", exp_res, " for search(", search_to_find, ", ", search_to_search, ")=", test_res, ". ", (exp_res == test_res)?"OK":"FAIL" ));
+ }
+}
+
+
+//"Normal" text for comparison
+echo ("----- Lookup of 1 byte into 1 byte");
+//Hits - up_to_count 1
+test_search_and_echo( [0], "a","aaaa" );
+test_search_and_echo( [0], "a","aaaa",1 );
+test_search_and_echo( [0,0], "aa","aaaa" );
+test_search_and_echo( [0,0], "aa","aaaa",1 );
+
+
+//Hits - up to count 1+ (incl 0 == all)
+test_search_and_echo( [[0,1,2,3]] , "a","aaaa",0 );
+test_search_and_echo( [[0,1]], "a","aaaa",2 );
+test_search_and_echo( [[0,1,2]], "a","aaaa",3 );
+test_search_and_echo( [[0,1,2,3]] , "a","aaaa",4 );
+test_search_and_echo( [[0,1,2,3],[0,1,2,3]] , "aa","aaaa",0 );
+//Misses
+test_search_and_echo( [], "b","aaaa" );
+test_search_and_echo( [], "b","aaaa",1 );
+test_search_and_echo( [[]], "b","aaaa",0 );
+test_search_and_echo( [[]], "b","aaaa",2 );
+
+test_search_and_echo( [], "bb","aaaa" );
+test_search_and_echo( [], "bb","aaaa",1 );
+test_search_and_echo( [[],[]], "bb","aaaa",0 );
+test_search_and_echo( [[],[]], "bb","aaaa",2 );
+//Miss - empties
+test_search_and_echo( [], "","aaaa" );
+test_search_and_echo( [], "","" );
+test_search_and_echo( [], "a","" );
+
+
+//Unicode tests
+echo ("----- Lookup of multi-byte into 1 byte");
+test_search_and_echo( [], "Π","aaaa" );
+test_search_and_echo( [], "π‘","aaaa" );
+test_search_and_echo( [[]], "Π","aaaa",0 );
+test_search_and_echo( [[]], "π‘","aaaa",0 );
+
+test_search_and_echo( [], "ΠΠ","aaaa" );
+test_search_and_echo( [], "π‘π‘","aaaa" );
+test_search_and_echo( [[],[]], "ΠΠ","aaaa",0 );
+test_search_and_echo( [[],[]], "π‘π‘","aaaa",0 );
+
+echo ("----- Lookup of 1-byte into multi-byte");
+test_search_and_echo( [] , "a","ΠΠΠΠ" );
+test_search_and_echo( [] , "a","π‘π‘π‘π‘" );
+test_search_and_echo( [] , "a","ΠΠΠΠ",1 );
+
+test_search_and_echo( [[]] , "a","π‘π‘π‘π‘",0 );
+test_search_and_echo( [[]] , "a","π‘π‘π‘π‘",2 );
+
+echo ("----- Lookup of 1-byte into mixed multi-byte");
+test_search_and_echo( [0], "a","aΠaΠaΠaΠa" );
+test_search_and_echo( [0], "a","aπ‘aπ‘aπ‘aπ‘a" );
+test_search_and_echo( [0], "a","aπ‘Ππ‘aπ‘Ππ‘a" );
+
+test_search_and_echo( [[0,2,4,6,8]], "a","aΠaΠaΠaΠa",0 );
+test_search_and_echo( [[0,2,4,6,8]], "a","aπ‘aπ‘aπ‘aπ‘a", 0 );
+test_search_and_echo( [[0,4,8]] , "a","aπ‘Ππ‘aπ‘Ππ‘a", 0 );
+
+echo ("----- Lookup of 2-byte into 2-byte");
+test_search_and_echo( [0] , "Π","ΠΠΠΠ" );
+test_search_and_echo( [[0,1,2,3]] , "Π","ΠΠΠΠ",0 );
+
+echo ("----- Lookup of 2-byte into 4-byte");
+test_search_and_echo( [] , "Π","π‘π‘π‘π‘" );
+
+echo ("----- Lookup of 4-byte into 4-byte");
+test_search_and_echo( [0] , "π‘","π‘π‘π‘π‘" );
+test_search_and_echo( [[0,1,2,3]], "π‘","π‘π‘π‘π‘",0 );
+
+echo ("----- Lookup of 4-byte into 2-byte");
+test_search_and_echo( [] , "π‘","ΠΠΠΠ" );
+
+echo ("----- Lookup of 2-byte into mixed multi-byte");
+test_search_and_echo( [1] , "Π","aΠaΠaΠaΠa",1 );
+test_search_and_echo( [] , "Π","aπ‘aπ‘aπ‘aπ‘a", 1 );
+test_search_and_echo( [2] , "Π","aπ‘Ππ‘aπ‘Ππ‘a", 1 );
+
+test_search_and_echo( [[1,3,5,7]] , "Π","aΠaΠaΠaΠa",0 );
+test_search_and_echo( [[]] , "Π","aπ‘aπ‘aπ‘aπ‘a", 0 );
+test_search_and_echo( [[2,6]] , "Π","aπ‘Ππ‘aπ‘Ππ‘a", 0 );
+
+echo ("----- Lookup of 4-byte into mixed multi-byte");
+test_search_and_echo( [] , "π‘","aΠaΠaΠaΠa",1 );
+test_search_and_echo( [1] , "π‘","aπ‘aπ‘aπ‘aπ‘a", 1 );
+
+test_search_and_echo( [[]] , "π‘","aΠaΠaΠaΠa",0 );
+test_search_and_echo( [[1,3,5,7]] , "π‘","aπ‘aπ‘aπ‘aπ‘a", 0 );
+test_search_and_echo( [[1,3,5,7]] , "π‘","aπ‘Ππ‘aπ‘Ππ‘a", 0 );
+
+echo ("----- Lookup of mixed multi-byte into mixed multi-byte");
+test_search_and_echo( [[0,2,4,6,8],[1,3,5,7],[]], "aΠπ‘","aΠaΠaΠaΠa",0 );
+test_search_and_echo( [[0,2,4,6,8],[],[1,3,5,7]], "aΠπ‘","aπ‘aπ‘aπ‘aπ‘a", 0 );
+test_search_and_echo( [[0,4,8],[2,6],[1,3,5,7]] , "aΠπ‘","aπ‘Ππ‘aπ‘Ππ‘a", 0 );
+test_search_and_echo( [[1,3,5,7],[0,4,8],[2,6]] , "π‘aΠ","aπ‘Ππ‘aπ‘Ππ‘a", 0 );
+
diff --git a/testdata/scad/misc/string-unicode.scad b/testdata/scad/misc/string-unicode.scad
new file mode 100644
index 00000000..d8e3e5c9
--- /dev/null
+++ b/testdata/scad/misc/string-unicode.scad
@@ -0,0 +1,36 @@
+//Test how well arrays of unicode string are accessed.
+
+texts_array = [
+"DEADBEEF",
+"ΠΠ΅Π½ΠΈΠ²ΡΠΉ ΡΡΠΆΠΈΠΉ ΠΊΠΎΡ",
+"ΩΨ³ΩΩ Ψ§ΩΨ²ΩΨ¬Ψ¨ΩΩ Ψ§ΩΩΨ·",
+"ζΆζ°ηε§θ²",
+"Àâü ΓΓΓ Γ",
+"πππππ
πππππππππππ",
+"β β β β β
β β β β β β β β β β ",
+"π‘π±ππ",
+];
+
+text_2bytes = "ΠΠ΅Π½ΠΈΠ²ΡΠΉ ΡΡΠΆΠΈΠΉ ΠΊΠΎΡ";
+text_4bytes = "π‘π±ππ";
+
+
+//Test all the normal accesses
+for (text_array_idx = [0:(len(texts_array)-1)])
+{
+ echo( "[", text_array_idx, "] = ", texts_array[text_array_idx], " of len=", len(texts_array[text_array_idx]), ":" );
+ for (text_idx = [0:(len(texts_array[text_array_idx])-1)])
+ {
+ echo( " [", text_idx, ,"]=", texts_array[text_array_idx][text_idx] );
+ }
+}
+
+//Test one past the last element of (x-byte unicode). This will be one past the length but inside the char length of the string
+echo( "Past end of unicode only 2-byte ", text_2bytes[len(text_2bytes)] );
+echo( "Past end of unicode only 4-byte ", text_4bytes[len(text_4bytes)] );
+
+//Test past the last element of (x-byte unicode). Outside both lengths.
+echo( "Past end of both 2-byte ", text_2bytes[ len(text_2bytes) * 2 ] );
+echo( "Past end of both 4-byte ", text_4bytes[ len(text_4bytes) * 4 ] );
+
+
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index d7ad18a4..3c19b77c 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -594,8 +594,8 @@ set(OFFSCREEN_SOURCES
../src/OpenCSGRenderer.cc)
add_library(tests-core STATIC ${CORE_SOURCES})
-target_link_libraries(tests-core ${OPENGL_LIBRARIES})
-set(TESTS-CORE-LIBRARIES ${OPENGL_LIBRARIES} ${Boost_LIBRARIES})
+target_link_libraries(tests-core ${OPENGL_LIBRARIES} ${GLIB2_LIBRARIES} )
+set(TESTS-CORE-LIBRARIES ${OPENGL_LIBRARIES} ${GLIB2_LIBRARIES} ${Boost_LIBRARIES} )
add_library(tests-common STATIC ${COMMON_SOURCES})
target_link_libraries(tests-common tests-core)
@@ -815,8 +815,10 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/dim-all.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-test.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-indexing.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-unicode.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/vector-values.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests-unicode.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/recursion-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests2.scad
diff --git a/tests/regression/echotest/search-tests-unicode-expected.echo b/tests/regression/echotest/search-tests-unicode-expected.echo
new file mode 100644
index 00000000..801bc8c8
--- /dev/null
+++ b/tests/regression/echotest/search-tests-unicode-expected.echo
@@ -0,0 +1,109 @@
+ECHO: "----- Lookup of 1 byte into 1 byte"
+ECHO: "Expect [0] for search(a, aaaa)=[0]. OK"
+ECHO: "Expect [0] for search(a, aaaa, 1)=[0]. OK"
+ECHO: "Expect [0, 0] for search(aa, aaaa)=[0, 0]. OK"
+ECHO: "Expect [0, 0] for search(aa, aaaa, 1)=[0, 0]. OK"
+ECHO: "Expect [[0, 1, 2, 3]] for search(a, aaaa, 0)=[[0, 1, 2, 3]]. OK"
+ECHO: "Expect [[0, 1]] for search(a, aaaa, 2)=[[0, 1]]. OK"
+ECHO: "Expect [[0, 1, 2]] for search(a, aaaa, 3)=[[0, 1, 2]]. OK"
+ECHO: "Expect [[0, 1, 2, 3]] for search(a, aaaa, 4)=[[0, 1, 2, 3]]. OK"
+ECHO: "Expect [[0, 1, 2, 3], [0, 1, 2, 3]] for search(aa, aaaa, 0)=[[0, 1, 2, 3], [0, 1, 2, 3]]. OK"
+ WARNING: search term not found: "b"
+ECHO: "Expect [] for search(b, aaaa)=[]. OK"
+ WARNING: search term not found: "b"
+ECHO: "Expect [] for search(b, aaaa, 1)=[]. OK"
+ WARNING: search term not found: "b"
+ECHO: "Expect [[]] for search(b, aaaa, 0)=[[]]. OK"
+ WARNING: search term not found: "b"
+ECHO: "Expect [[]] for search(b, aaaa, 2)=[[]]. OK"
+ WARNING: search term not found: "b"
+ WARNING: search term not found: "b"
+ECHO: "Expect [] for search(bb, aaaa)=[]. OK"
+ WARNING: search term not found: "b"
+ WARNING: search term not found: "b"
+ECHO: "Expect [] for search(bb, aaaa, 1)=[]. OK"
+ WARNING: search term not found: "b"
+ WARNING: search term not found: "b"
+ECHO: "Expect [[], []] for search(bb, aaaa, 0)=[[], []]. OK"
+ WARNING: search term not found: "b"
+ WARNING: search term not found: "b"
+ECHO: "Expect [[], []] for search(bb, aaaa, 2)=[[], []]. OK"
+ECHO: "Expect [] for search(, aaaa)=[]. OK"
+ECHO: "Expect [] for search(, )=[]. OK"
+ WARNING: search term not found: "a"
+ECHO: "Expect [] for search(a, )=[]. OK"
+ECHO: "----- Lookup of multi-byte into 1 byte"
+ WARNING: search term not found: "Π"
+ECHO: "Expect [] for search(Π, aaaa)=[]. OK"
+ WARNING: search term not found: "π‘"
+ECHO: "Expect [] for search(π‘, aaaa)=[]. OK"
+ WARNING: search term not found: "Π"
+ECHO: "Expect [[]] for search(Π, aaaa, 0)=[[]]. OK"
+ WARNING: search term not found: "π‘"
+ECHO: "Expect [[]] for search(π‘, aaaa, 0)=[[]]. OK"
+ WARNING: search term not found: "Π"
+ WARNING: search term not found: "Π"
+ECHO: "Expect [] for search(ΠΠ, aaaa)=[]. OK"
+ WARNING: search term not found: "π‘"
+ WARNING: search term not found: "π‘"
+ECHO: "Expect [] for search(π‘π‘, aaaa)=[]. OK"
+ WARNING: search term not found: "Π"
+ WARNING: search term not found: "Π"
+ECHO: "Expect [[], []] for search(ΠΠ, aaaa, 0)=[[], []]. OK"
+ WARNING: search term not found: "π‘"
+ WARNING: search term not found: "π‘"
+ECHO: "Expect [[], []] for search(π‘π‘, aaaa, 0)=[[], []]. OK"
+ECHO: "----- Lookup of 1-byte into multi-byte"
+ WARNING: search term not found: "a"
+ECHO: "Expect [] for search(a, ΠΠΠΠ)=[]. OK"
+ WARNING: search term not found: "a"
+ECHO: "Expect [] for search(a, π‘π‘π‘π‘)=[]. OK"
+ WARNING: search term not found: "a"
+ECHO: "Expect [] for search(a, ΠΠΠΠ, 1)=[]. OK"
+ WARNING: search term not found: "a"
+ECHO: "Expect [[]] for search(a, π‘π‘π‘π‘, 0)=[[]]. OK"
+ WARNING: search term not found: "a"
+ECHO: "Expect [[]] for search(a, π‘π‘π‘π‘, 2)=[[]]. OK"
+ECHO: "----- Lookup of 1-byte into mixed multi-byte"
+ECHO: "Expect [0] for search(a, aΠaΠaΠaΠa)=[0]. OK"
+ECHO: "Expect [0] for search(a, aπ‘aπ‘aπ‘aπ‘a)=[0]. OK"
+ECHO: "Expect [0] for search(a, aπ‘Ππ‘aπ‘Ππ‘a)=[0]. OK"
+ECHO: "Expect [[0, 2, 4, 6, 8]] for search(a, aΠaΠaΠaΠa, 0)=[[0, 2, 4, 6, 8]]. OK"
+ECHO: "Expect [[0, 2, 4, 6, 8]] for search(a, aπ‘aπ‘aπ‘aπ‘a, 0)=[[0, 2, 4, 6, 8]]. OK"
+ECHO: "Expect [[0, 4, 8]] for search(a, aπ‘Ππ‘aπ‘Ππ‘a, 0)=[[0, 4, 8]]. OK"
+ECHO: "----- Lookup of 2-byte into 2-byte"
+ECHO: "Expect [0] for search(Π, ΠΠΠΠ)=[0]. OK"
+ECHO: "Expect [[0, 1, 2, 3]] for search(Π, ΠΠΠΠ, 0)=[[0, 1, 2, 3]]. OK"
+ECHO: "----- Lookup of 2-byte into 4-byte"
+ WARNING: search term not found: "Π"
+ECHO: "Expect [] for search(Π, π‘π‘π‘π‘)=[]. OK"
+ECHO: "----- Lookup of 4-byte into 4-byte"
+ECHO: "Expect [0] for search(π‘, π‘π‘π‘π‘)=[0]. OK"
+ECHO: "Expect [[0, 1, 2, 3]] for search(π‘, π‘π‘π‘π‘, 0)=[[0, 1, 2, 3]]. OK"
+ECHO: "----- Lookup of 4-byte into 2-byte"
+ WARNING: search term not found: "π‘"
+ECHO: "Expect [] for search(π‘, ΠΠΠΠ)=[]. OK"
+ECHO: "----- Lookup of 2-byte into mixed multi-byte"
+ECHO: "Expect [1] for search(Π, aΠaΠaΠaΠa, 1)=[1]. OK"
+ WARNING: search term not found: "Π"
+ECHO: "Expect [] for search(Π, aπ‘aπ‘aπ‘aπ‘a, 1)=[]. OK"
+ECHO: "Expect [2] for search(Π, aπ‘Ππ‘aπ‘Ππ‘a, 1)=[2]. OK"
+ECHO: "Expect [[1, 3, 5, 7]] for search(Π, aΠaΠaΠaΠa, 0)=[[1, 3, 5, 7]]. OK"
+ WARNING: search term not found: "Π"
+ECHO: "Expect [[]] for search(Π, aπ‘aπ‘aπ‘aπ‘a, 0)=[[]]. OK"
+ECHO: "Expect [[2, 6]] for search(Π, aπ‘Ππ‘aπ‘Ππ‘a, 0)=[[2, 6]]. OK"
+ECHO: "----- Lookup of 4-byte into mixed multi-byte"
+ WARNING: search term not found: "π‘"
+ECHO: "Expect [] for search(π‘, aΠaΠaΠaΠa, 1)=[]. OK"
+ECHO: "Expect [1] for search(π‘, aπ‘aπ‘aπ‘aπ‘a, 1)=[1]. OK"
+ WARNING: search term not found: "π‘"
+ECHO: "Expect [[]] for search(π‘, aΠaΠaΠaΠa, 0)=[[]]. OK"
+ECHO: "Expect [[1, 3, 5, 7]] for search(π‘, aπ‘aπ‘aπ‘aπ‘a, 0)=[[1, 3, 5, 7]]. OK"
+ECHO: "Expect [[1, 3, 5, 7]] for search(π‘, aπ‘Ππ‘aπ‘Ππ‘a, 0)=[[1, 3, 5, 7]]. OK"
+ECHO: "----- Lookup of mixed multi-byte into mixed multi-byte"
+ WARNING: search term not found: "π‘"
+ECHO: "Expect [[0, 2, 4, 6, 8], [1, 3, 5, 7], []] for search(aΠπ‘, aΠaΠaΠaΠa, 0)=[[0, 2, 4, 6, 8], [1, 3, 5, 7], []]. OK"
+ WARNING: search term not found: "Π"
+ECHO: "Expect [[0, 2, 4, 6, 8], [], [1, 3, 5, 7]] for search(aΠπ‘, aπ‘aπ‘aπ‘aπ‘a, 0)=[[0, 2, 4, 6, 8], [], [1, 3, 5, 7]]. OK"
+ECHO: "Expect [[0, 4, 8], [2, 6], [1, 3, 5, 7]] for search(aΠπ‘, aπ‘Ππ‘aπ‘Ππ‘a, 0)=[[0, 4, 8], [2, 6], [1, 3, 5, 7]]. OK"
+ECHO: "Expect [[1, 3, 5, 7], [0, 4, 8], [2, 6]] for search(π‘aΠ, aπ‘Ππ‘aπ‘Ππ‘a, 0)=[[1, 3, 5, 7], [0, 4, 8], [2, 6]]. OK"
diff --git a/tests/regression/echotest/string-unicode-expected.echo b/tests/regression/echotest/string-unicode-expected.echo
new file mode 100644
index 00000000..b4b848fd
--- /dev/null
+++ b/tests/regression/echotest/string-unicode-expected.echo
@@ -0,0 +1,104 @@
+ECHO: "[", 0, "] = ", "DEADBEEF", " of len=", 8, ":"
+ECHO: " [", 0, "]=", "D"
+ECHO: " [", 1, "]=", "E"
+ECHO: " [", 2, "]=", "A"
+ECHO: " [", 3, "]=", "D"
+ECHO: " [", 4, "]=", "B"
+ECHO: " [", 5, "]=", "E"
+ECHO: " [", 6, "]=", "E"
+ECHO: " [", 7, "]=", "F"
+ECHO: "[", 1, "] = ", "ΠΠ΅Π½ΠΈΠ²ΡΠΉ ΡΡΠΆΠΈΠΉ ΠΊΠΎΡ", " of len=", 17, ":"
+ECHO: " [", 0, "]=", "Π"
+ECHO: " [", 1, "]=", "Π΅"
+ECHO: " [", 2, "]=", "Π½"
+ECHO: " [", 3, "]=", "ΠΈ"
+ECHO: " [", 4, "]=", "Π²"
+ECHO: " [", 5, "]=", "Ρ"
+ECHO: " [", 6, "]=", "ΠΉ"
+ECHO: " [", 7, "]=", " "
+ECHO: " [", 8, "]=", "Ρ"
+ECHO: " [", 9, "]=", "Ρ"
+ECHO: " [", 10, "]=", "ΠΆ"
+ECHO: " [", 11, "]=", "ΠΈ"
+ECHO: " [", 12, "]=", "ΠΉ"
+ECHO: " [", 13, "]=", " "
+ECHO: " [", 14, "]=", "ΠΊ"
+ECHO: " [", 15, "]=", "ΠΎ"
+ECHO: " [", 16, "]=", "Ρ"
+ECHO: "[", 2, "] = ", "ΩΨ³ΩΩ Ψ§ΩΨ²ΩΨ¬Ψ¨ΩΩ Ψ§ΩΩΨ·", " of len=", 18, ":"
+ECHO: " [", 0, "]=", "Ω"
+ECHO: " [", 1, "]=", "Ψ³"
+ECHO: " [", 2, "]=", "Ω"
+ECHO: " [", 3, "]=", "Ω"
+ECHO: " [", 4, "]=", " "
+ECHO: " [", 5, "]=", "Ψ§"
+ECHO: " [", 6, "]=", "Ω"
+ECHO: " [", 7, "]=", "Ψ²"
+ECHO: " [", 8, "]=", "Ω"
+ECHO: " [", 9, "]=", "Ψ¬"
+ECHO: " [", 10, "]=", "Ψ¨"
+ECHO: " [", 11, "]=", "Ω"
+ECHO: " [", 12, "]=", "Ω"
+ECHO: " [", 13, "]=", " "
+ECHO: " [", 14, "]=", "Ψ§"
+ECHO: " [", 15, "]=", "Ω"
+ECHO: " [", 16, "]=", "Ω"
+ECHO: " [", 17, "]=", "Ψ·"
+ECHO: "[", 3, "] = ", "ζΆζ°ηε§θ²", " of len=", 5, ":"
+ECHO: " [", 0, "]=", "ζΆ"
+ECHO: " [", 1, "]=", "ζ°"
+ECHO: " [", 2, "]=", "η"
+ECHO: " [", 3, "]=", "ε§"
+ECHO: " [", 4, "]=", "θ²"
+ECHO: "[", 4, "] = ", "Àâü ΓΓΓ Γ", " of len=", 9, ":"
+ECHO: " [", 0, "]=", "Γ€"
+ECHO: " [", 1, "]=", "ΓΆ"
+ECHO: " [", 2, "]=", "ΓΌ"
+ECHO: " [", 3, "]=", " "
+ECHO: " [", 4, "]=", "Γ"
+ECHO: " [", 5, "]=", "Γ"
+ECHO: " [", 6, "]=", "Γ"
+ECHO: " [", 7, "]=", " "
+ECHO: " [", 8, "]=", "Γ"
+ECHO: "[", 5, "] = ", "πππππ
πππππππππππ", " of len=", 16, ":"
+ECHO: " [", 0, "]=", "π"
+ECHO: " [", 1, "]=", "π"
+ECHO: " [", 2, "]=", "π"
+ECHO: " [", 3, "]=", "π"
+ECHO: " [", 4, "]=", "π
"
+ECHO: " [", 5, "]=", "π"
+ECHO: " [", 6, "]=", "π"
+ECHO: " [", 7, "]=", "π"
+ECHO: " [", 8, "]=", "π"
+ECHO: " [", 9, "]=", "π"
+ECHO: " [", 10, "]=", "π"
+ECHO: " [", 11, "]=", "π"
+ECHO: " [", 12, "]=", "π"
+ECHO: " [", 13, "]=", "π"
+ECHO: " [", 14, "]=", "π"
+ECHO: " [", 15, "]=", "π"
+ECHO: "[", 6, "] = ", "β β β β β
β β β β β β β β β β ", " of len=", 15, ":"
+ECHO: " [", 0, "]=", "β "
+ECHO: " [", 1, "]=", "β "
+ECHO: " [", 2, "]=", "β "
+ECHO: " [", 3, "]=", "β "
+ECHO: " [", 4, "]=", "β
"
+ECHO: " [", 5, "]=", "β "
+ECHO: " [", 6, "]=", "β "
+ECHO: " [", 7, "]=", "β "
+ECHO: " [", 8, "]=", "β "
+ECHO: " [", 9, "]=", "β "
+ECHO: " [", 10, "]=", "β "
+ECHO: " [", 11, "]=", "β "
+ECHO: " [", 12, "]=", "β "
+ECHO: " [", 13, "]=", "β "
+ECHO: " [", 14, "]=", "β "
+ECHO: "[", 7, "] = ", "π‘π±ππ", " of len=", 4, ":"
+ECHO: " [", 0, "]=", "π‘"
+ECHO: " [", 1, "]=", "π±"
+ECHO: " [", 2, "]=", "π"
+ECHO: " [", 3, "]=", "π"
+ECHO: "Past end of unicode only 2-byte ", undef
+ECHO: "Past end of unicode only 4-byte ", undef
+ECHO: "Past end of both 2-byte ", undef
+ECHO: "Past end of both 4-byte ", undef
From c0849eb1d3c98db505eec0396c56276a9a35120f Mon Sep 17 00:00:00 2001
From: Brody Kenrick
Date: Fri, 6 Dec 2013 09:56:22 +1100
Subject: [PATCH 13/16] Update comments/messages for CGAL source of bad boost
libraries
Add comments and change to a status instead of a warning (as we recover
nicely and it is a known issue in CGAL @
https://bugs.launchpad.net/ubuntu/+source/cgal/+bug/1242111)
---
tests/CMakeLists.txt | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 3c19b77c..2533103e 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -383,23 +383,24 @@ if("${CGAL_MAJOR_VERSION}.${CGAL_MINOR_VERSION}" VERSION_LESS 3.6)
message(FATAL_ERROR "CGAL >= 3.6 required")
endif()
inclusion(CGAL_DIR CGAL_INCLUDE_DIRS)
-
-#Get rid of bad libraries suggested for BOOST dependencies (they don't exist on some machines and cause build failures).
-#/usr/lib/libboost_thread.so;/usr/lib/libboost_system.so;
+#Remove bad BOOST libraries from CGAL 3rd party dependencies when they don't exist (such as on 64-bit Ubuntu 13.10).
+#Libs of concern are /usr/lib/libboost_thread.so;/usr/lib/libboost_system.so;
+#Confirmed bug in CGAL @ https://bugs.launchpad.net/ubuntu/+source/cgal/+bug/1242111
string(FIND "${CGAL_3RD_PARTY_LIBRARIES}" "/usr/lib/libboost_system.so" FIND_POSITION )
if(NOT "-1" STREQUAL ${FIND_POSITION} )
-if(NOT EXISTS "/usr/lib/libboost_system.so")
- MESSAGE( WARNING "CGAL_3RD_PARTY_LIBRARIES:Found erroneous /usr/lib/libboost_system.so -- stripping" )
- string(REPLACE "/usr/lib/libboost_system.so" "" CGAL_3RD_PARTY_LIBRARIES ${CGAL_3RD_PARTY_LIBRARIES})
-endif()
+ if(NOT EXISTS "/usr/lib/libboost_system.so")
+ MESSAGE( STATUS "CGAL_3RD_PARTY_LIBRARIES:Removing non-existent /usr/lib/libboost_system.so" )
+ string(REPLACE "/usr/lib/libboost_system.so" "" CGAL_3RD_PARTY_LIBRARIES ${CGAL_3RD_PARTY_LIBRARIES})
+ endif()
endif()
string(FIND "${CGAL_3RD_PARTY_LIBRARIES}" "/usr/lib/libboost_thread.so" FIND_POSITION )
if(NOT "-1" STREQUAL ${FIND_POSITION} )
-if(NOT EXISTS "/usr/lib/libboost_thread.so")
- MESSAGE( WARNING "CGAL_3RD_PARTY_LIBRARIES:Found erroneous /usr/lib/libboost_thread.so -- stripping" )
- string(REPLACE "/usr/lib/libboost_thread.so" "" CGAL_3RD_PARTY_LIBRARIES ${CGAL_3RD_PARTY_LIBRARIES})
-endif()
+ if(NOT EXISTS "/usr/lib/libboost_thread.so")
+ MESSAGE( STATUS "CGAL_3RD_PARTY_LIBRARIES:Removing non-existent /usr/lib/libboost_thread.so" )
+ string(REPLACE "/usr/lib/libboost_thread.so" "" CGAL_3RD_PARTY_LIBRARIES ${CGAL_3RD_PARTY_LIBRARIES})
+ endif()
endif()
+
if(${CMAKE_CXX_COMPILER} MATCHES ".*clang.*" AND NOT ${CGAL_CXX_FLAGS_INIT} STREQUAL "" )
string(REPLACE "-frounding-math" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
string(REPLACE "--param=ssp-buffer-size=4" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
From d2575016b989b9cee5b44c29f10a76d84a7bf182 Mon Sep 17 00:00:00 2001
From: Brody Kenrick
Date: Fri, 6 Dec 2013 17:46:52 +1100
Subject: [PATCH 14/16] Add in missed glib build dependencies for OS X and unix
---
scripts/macosx-build-dependencies.sh | 25 +++++++++++++++++++++++++
scripts/uni-build-dependencies.sh | 25 +++++++++++++++++++++++++
2 files changed, 50 insertions(+)
diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh
index d4ca1f7c..5e26feee 100755
--- a/scripts/macosx-build-dependencies.sh
+++ b/scripts/macosx-build-dependencies.sh
@@ -285,6 +285,30 @@ build_glew()
make GLEW_DEST=$DEPLOYDIR CC=$CC CFLAGS.EXTRA="-no-cpp-precomp -dynamic -fno-common -mmacosx-version-min=$MAC_OSX_VERSION_MIN $GLEW_EXTRA_FLAGS -arch x86_64" LDFLAGS.EXTRA="-mmacosx-version-min=$MAC_OSX_VERSION_MIN $GLEW_EXTRA_FLAGS -arch x86_64" STRIP= install
}
+build_glib2()
+{
+ version="$1"
+ maj_min_version="${version%.*}" #Drop micro
+
+ if [ -e $DEPLOYDIR/lib/glib-2.0 ]; then
+ echo "glib2 already installed. not building"
+ return
+ fi
+
+ echo "Building glib2 $version..."
+ cd "$BASEDIR"/src
+ rm -rf "glib-$version"
+ if [ ! -f "glib-$version.tar.xz" ]; then
+ curl --insecure -LO "http://ftp.gnome.org/pub/gnome/sources/glib/$maj_min_version/glib-$version.tar.xz"
+ fi
+ tar xJf "glib-$version.tar.xz"
+ cd "glib-$version"
+
+ ./configure --prefix="$DEPLOYDIR"
+ make -j$NUMCPU
+ make install
+}
+
build_opencsg()
{
version=$1
@@ -449,6 +473,7 @@ build_boost 1.54.0
# NB! For CGAL, also update the actual download URL in the function
build_cgal 4.3
build_glew 1.10.0
+build_glib2 2.38.1
build_opencsg 1.3.2
if $OPTION_DEPLOY; then
# build_sparkle andymatuschak 0ed83cf9f2eeb425d4fdd141c01a29d843970c20
diff --git a/scripts/uni-build-dependencies.sh b/scripts/uni-build-dependencies.sh
index 8d912c35..ba328b7e 100755
--- a/scripts/uni-build-dependencies.sh
+++ b/scripts/uni-build-dependencies.sh
@@ -409,6 +409,31 @@ build_glew()
GLEW_DEST=$DEPLOYDIR $MAKER install
}
+build_glib2()
+{
+ version="$1"
+ maj_min_version="${version%.*}" #Drop micro
+
+ if [ -e $DEPLOYDIR/lib/glib-2.0 ]; then
+echo "glib2 already installed. not building"
+ return
+fi
+
+echo "Building glib2 $version..."
+ cd "$BASEDIR"/src
+ rm -rf "glib-$version"
+ if [ ! -f "glib-$version.tar.xz" ]; then
+curl --insecure -LO "http://ftp.gnome.org/pub/gnome/sources/glib/$maj_min_version/glib-$version.tar.xz"
+ fi
+tar xJf "glib-$version.tar.xz"
+ cd "glib-$version"
+
+ ./configure --prefix="$DEPLOYDIR"
+ make -j$NUMCPU
+ make install
+
+}
+
build_opencsg()
{
if [ -e $DEPLOYDIR/lib/libopencsg.so ]; then
From d46ce3fb8150fe01c0c07fac11ea2e9a8ed97038 Mon Sep 17 00:00:00 2001
From: Brody Kenrick
Date: Fri, 6 Dec 2013 18:33:42 +1100
Subject: [PATCH 15/16] Add specific tests for unicode len()
---
testdata/scad/misc/string-unicode.scad | 10 +++++++++-
tests/regression/echotest/string-unicode-expected.echo | 3 +++
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/testdata/scad/misc/string-unicode.scad b/testdata/scad/misc/string-unicode.scad
index d8e3e5c9..1386d63d 100644
--- a/testdata/scad/misc/string-unicode.scad
+++ b/testdata/scad/misc/string-unicode.scad
@@ -1,3 +1,12 @@
+//Test length reporting
+text_1bytes_len = "1234";
+text_2bytes_len = "ΠΠΠΠ";
+text_4bytes_len = "π‘π±ππ";
+
+echo( "text_1bytes_len = ", text_1bytes_len, " len = ", len(text_1bytes_len) );
+echo( "text_2bytes_len = ", text_2bytes_len, " len = ", len(text_2bytes_len) );
+echo( "text_4bytes_len = ", text_4bytes_len, " len = ", len(text_4bytes_len) );
+
//Test how well arrays of unicode string are accessed.
texts_array = [
@@ -33,4 +42,3 @@ echo( "Past end of unicode only 4-byte ", text_4bytes[len(text_4bytes)] );
echo( "Past end of both 2-byte ", text_2bytes[ len(text_2bytes) * 2 ] );
echo( "Past end of both 4-byte ", text_4bytes[ len(text_4bytes) * 4 ] );
-
diff --git a/tests/regression/echotest/string-unicode-expected.echo b/tests/regression/echotest/string-unicode-expected.echo
index b4b848fd..a1cd3bec 100644
--- a/tests/regression/echotest/string-unicode-expected.echo
+++ b/tests/regression/echotest/string-unicode-expected.echo
@@ -1,3 +1,6 @@
+ECHO: "text_1bytes_len = ", "1234", " len = ", 4
+ECHO: "text_2bytes_len = ", "ΠΠΠΠ", " len = ", 4
+ECHO: "text_4bytes_len = ", "π‘π±ππ", " len = ", 4
ECHO: "[", 0, "] = ", "DEADBEEF", " of len=", 8, ":"
ECHO: " [", 0, "]=", "D"
ECHO: " [", 1, "]=", "E"
From 7cb3ea77ff090e136eb4a9536a394b3766908d17 Mon Sep 17 00:00:00 2001
From: Marius Kintel
Date: Tue, 10 Dec 2013 23:08:04 -0500
Subject: [PATCH 16/16] Build glib2 and gettext on Mac, Find macro for glib2
---
scripts/macosx-build-dependencies.sh | 36 +++++++++++++++++++---------
tests/CMakeLists.txt | 23 +++++++-----------
tests/FindGLIB2.cmake | 27 +++++++++++++++++++++
3 files changed, 60 insertions(+), 26 deletions(-)
create mode 100644 tests/FindGLIB2.cmake
diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh
index 5e26feee..b61c6561 100755
--- a/scripts/macosx-build-dependencies.sh
+++ b/scripts/macosx-build-dependencies.sh
@@ -285,27 +285,40 @@ build_glew()
make GLEW_DEST=$DEPLOYDIR CC=$CC CFLAGS.EXTRA="-no-cpp-precomp -dynamic -fno-common -mmacosx-version-min=$MAC_OSX_VERSION_MIN $GLEW_EXTRA_FLAGS -arch x86_64" LDFLAGS.EXTRA="-mmacosx-version-min=$MAC_OSX_VERSION_MIN $GLEW_EXTRA_FLAGS -arch x86_64" STRIP= install
}
+build_gettext()
+{
+ version=$1
+ echo "Building gettext $version..."
+
+ cd "$BASEDIR"/src
+ rm -rf "gettext-$version"
+ if [ ! -f "glib-$version.tar.xz" ]; then
+ curl --insecure -LO "http://ftpmirror.gnu.org/gettext/gettext-$version.tar.gz"
+ fi
+ tar xzf "gettext-$version.tar.gz"
+ cd "gettext-$version"
+
+ ./configure --prefix="$DEPLOYDIR"
+ make -j4
+ make install
+}
+
build_glib2()
{
- version="$1"
- maj_min_version="${version%.*}" #Drop micro
+ version=$1
+ echo "Building glib2 $version..."
- if [ -e $DEPLOYDIR/lib/glib-2.0 ]; then
- echo "glib2 already installed. not building"
- return
- fi
-
- echo "Building glib2 $version..."
cd "$BASEDIR"/src
rm -rf "glib-$version"
+ maj_min_version="${version%.*}" #Drop micro
if [ ! -f "glib-$version.tar.xz" ]; then
curl --insecure -LO "http://ftp.gnome.org/pub/gnome/sources/glib/$maj_min_version/glib-$version.tar.xz"
fi
tar xJf "glib-$version.tar.xz"
cd "glib-$version"
- ./configure --prefix="$DEPLOYDIR"
- make -j$NUMCPU
+ ./configure --disable-gtk-doc --disable-man --prefix="$DEPLOYDIR" CFLAGS="-I$DEPLOYDIR/include" LDFLAGS="-L$DEPLOYDIR/lib"
+ make -j4
make install
}
@@ -473,7 +486,8 @@ build_boost 1.54.0
# NB! For CGAL, also update the actual download URL in the function
build_cgal 4.3
build_glew 1.10.0
-build_glib2 2.38.1
+build_gettext 0.18.3.1
+build_glib2 2.38.2
build_opencsg 1.3.2
if $OPTION_DEPLOY; then
# build_sparkle andymatuschak 0ed83cf9f2eeb425d4fdd141c01a29d843970c20
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 2533103e..e5900709 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -366,10 +366,10 @@ if (NOT $ENV{CGALDIR} STREQUAL "")
elseif (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "")
if (EXISTS "$ENV{OPENSCAD_LIBRARIES}/lib/CGAL")
set(CGAL_DIR "$ENV{OPENSCAD_LIBRARIES}/lib/CGAL")
- set(CMAKE_MODULE_PATH "${CGAL_DIR}")
+ set(CMAKE_MODULE_PATH "${CGAL_DIR}" ${CMAKE_MODULE_PATH})
elseif (EXISTS "$ENV{OPENSCAD_LIBRARIES}/include/CGAL")
set(CGAL_DIR "$ENV{OPENSCAD_LIBRARIES}")
- set(CMAKE_MODULE_PATH "${CGAL_DIR}")
+ set(CMAKE_MODULE_PATH "${CGAL_DIR}" ${CMAKE_MODULE_PATH})
endif()
endif()
message(STATUS "CGAL_DIR: " ${CGAL_DIR})
@@ -413,16 +413,9 @@ if (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "")
set(ENV{PKG_CONFIG_LIBDIR} "$ENV{OPENSCAD_LIBRARIES}/lib/pkgconfig")
endif()
-# Find libraries (system installed or dependency built) using pkg-config
-find_package(PkgConfig REQUIRED)
-
-#GLib-2
-pkg_search_module(GLIB2 REQUIRED glib-2.0>=2.2.0)
-#Can't use the CXXFlags directly as they are ;-separated
-string(REPLACE ";" " " GLIB2_CFLAGS "${GLIB2_CFLAGS}")
-message(STATUS "glib-2.0 found: ${GLIB2_VERSION}")
-
-add_definitions(${GLIB2_CFLAGS})
+find_package(GLIB2 2.2.0 REQUIRED)
+add_definitions(${GLIB2_DEFINITIONS})
+inclusion(GLIB2_DIR GLIB2_INCLUDE_DIRS)
# Imagemagick
@@ -595,7 +588,7 @@ set(OFFSCREEN_SOURCES
../src/OpenCSGRenderer.cc)
add_library(tests-core STATIC ${CORE_SOURCES})
-target_link_libraries(tests-core ${OPENGL_LIBRARIES} ${GLIB2_LIBRARIES} )
+target_link_libraries(tests-core)
set(TESTS-CORE-LIBRARIES ${OPENGL_LIBRARIES} ${GLIB2_LIBRARIES} ${Boost_LIBRARIES} )
add_library(tests-common STATIC ${COMMON_SOURCES})
@@ -616,7 +609,7 @@ set(TESTS-NOCGAL-LIBRARIES ${TESTS-CORE-LIBRARIES})
# modulecachetest
#
add_executable(modulecachetest modulecachetest.cc)
-target_link_libraries(modulecachetest tests-nocgal ${TESTS-NOCGAL-LIBRARIES} ${Boost_LIBRARIES})
+target_link_libraries(modulecachetest tests-nocgal ${TESTS-NOCGAL-LIBRARIES})
#
# csgtexttest
@@ -636,7 +629,7 @@ target_link_libraries(cgalcachetest tests-cgal ${TESTS-CGAL-LIBRARIES} ${GLEW_LI
#
add_executable(openscad_nogui ../src/openscad.cc)
set_target_properties(openscad_nogui PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -DEIGEN_DONT_ALIGN -DENABLE_CGAL -DENABLE_OPENCSG ${CGAL_CXX_FLAGS_INIT}")
-target_link_libraries(openscad_nogui tests-offscreen tests-cgal tests-nocgal ${TESTS-CORE-LIBRARIES} ${TESTS-CGAL-LIBRARIES} ${GLEW_LIBRARY} ${Boost_LIBRARIES} ${OPENCSG_LIBRARY} ${COCOA_LIBRARY} )
+target_link_libraries(openscad_nogui tests-offscreen tests-cgal tests-nocgal ${TESTS-CORE-LIBRARIES} ${TESTS-CGAL-LIBRARIES} ${GLEW_LIBRARY} ${OPENCSG_LIBRARY} ${COCOA_LIBRARY} )
#
# GUI binary tests
diff --git a/tests/FindGLIB2.cmake b/tests/FindGLIB2.cmake
new file mode 100644
index 00000000..b27b9a9b
--- /dev/null
+++ b/tests/FindGLIB2.cmake
@@ -0,0 +1,27 @@
+find_package(PkgConfig REQUIRED)
+
+pkg_search_module(GLIB2 REQUIRED glib-2.0)
+#message("GLIB2_LIBRARIES ${GLIB2_LIBRARIES}")
+#message("GLIB2_LIBRARY_DIRS ${GLIB2_LIBRARY_DIRS}")
+#message("GLIB2_LDFLAGS ${GLIB2_LDFLAGS}")
+#message("GLIB2_LDFLAGS_OTHER ${GLIB2_LDFLAGS_OTHER}")
+message("GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS}")
+#message("GLIB2_CFLAGS ${GLIB2_CFLAGS}")
+#message("GLIB2_CFLAGS_OTHER ${GLIB2_CFLAGS_OTHER}")
+#message("GLIB2_LIBDIR ${GLIB2_LIBDIR}")
+
+set(GLIB2_DEFINITIONS ${GLIB2_CFLAGS_OTHER})
+#message("GLIB2_DEFINITIONS ${GLIB2_DEFINITIONS}")
+
+set(GLIB2_LIBRARY_NAMES ${GLIB2_LIBRARIES})
+set(GLIB2_LIBRARIES "")
+foreach(GLIB2_LIB ${GLIB2_LIBRARY_NAMES})
+# message("lib: ${GLIB2_LIB}")
+ set(TMP TMP-NOTFOUND)
+ find_library(TMP NAMES ${GLIB2_LIB}
+ PATHS ${GLIB2_LIBRARY_DIRS}
+ NO_DEFAULT_PATH)
+# message("TMP: ${TMP}")
+ list(APPEND GLIB2_LIBRARIES "${TMP}")
+endforeach()
+message("GLIB2_LIBRARIES: ${GLIB2_LIBRARIES}")