diff --git a/baRSS.xcodeproj/project.pbxproj b/baRSS.xcodeproj/project.pbxproj index 9e24bc3..d835bde 100644 --- a/baRSS.xcodeproj/project.pbxproj +++ b/baRSS.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 1968E0AE14B8E8A90E194980 /* PyHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 1968EF7567E06D2A5BB3481A /* PyHandler.m */; }; 544FBD4521064AEB008A260C /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 544FBD4421064AEB008A260C /* Python.framework */; }; 544FBD4721064B2F008A260C /* getFeed.py in Resources */ = {isa = PBXBuildFile; fileRef = 544FBD4621064B2F008A260C /* getFeed.py */; }; 544FBD4921064DF0008A260C /* feedparser521.py in Resources */ = {isa = PBXBuildFile; fileRef = 544FBD4821064DF0008A260C /* feedparser521.py */; }; @@ -17,10 +18,11 @@ 54ACC28C21061B3C0020715F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC28B21061B3C0020715F /* main.m */; }; 54ACC29521061E270020715F /* NewsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC29421061E270020715F /* NewsController.m */; }; 54ACC29821061FBA0020715F /* Preferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC29721061FBA0020715F /* Preferences.m */; }; - 54ED7BDA2107CE5500AC8248 /* PyHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 54ED7BD92107CE5500AC8248 /* PyHandler.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 1968E7919BAA36F042FCB717 /* PyHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyHandler.h; sourceTree = ""; }; + 1968EF7567E06D2A5BB3481A /* PyHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PyHandler.m; sourceTree = ""; }; 544FBD4421064AEB008A260C /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = System/Library/Frameworks/Python.framework; sourceTree = SDKROOT; }; 544FBD4621064B2F008A260C /* getFeed.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = getFeed.py; sourceTree = ""; usesTabs = 0; }; 544FBD4821064DF0008A260C /* feedparser521.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = feedparser521.py; sourceTree = ""; usesTabs = 0; }; @@ -37,7 +39,6 @@ 54ACC29421061E270020715F /* NewsController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NewsController.m; sourceTree = ""; }; 54ACC29621061FBA0020715F /* Preferences.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Preferences.h; sourceTree = ""; }; 54ACC29721061FBA0020715F /* Preferences.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Preferences.m; sourceTree = ""; }; - 54ED7BD92107CE5500AC8248 /* PyHandler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PyHandler.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -60,6 +61,17 @@ name = Frameworks; sourceTree = ""; }; + 549369F421091E6D001AF895 /* python */ = { + isa = PBXGroup; + children = ( + 1968E7919BAA36F042FCB717 /* PyHandler.h */, + 1968EF7567E06D2A5BB3481A /* PyHandler.m */, + 544FBD4621064B2F008A260C /* getFeed.py */, + 544FBD4821064DF0008A260C /* feedparser521.py */, + ); + path = python; + sourceTree = ""; + }; 54ACC27321061B3B0020715F = { isa = PBXGroup; children = ( @@ -80,9 +92,7 @@ 54ACC27E21061B3B0020715F /* baRSS */ = { isa = PBXGroup; children = ( - 54ED7BD92107CE5500AC8248 /* PyHandler.cpp */, - 544FBD4621064B2F008A260C /* getFeed.py */, - 544FBD4821064DF0008A260C /* feedparser521.py */, + 549369F421091E6D001AF895 /* python */, 54ACC27F21061B3B0020715F /* AppDelegate.h */, 54ACC28021061B3B0020715F /* AppDelegate.m */, 54ACC29321061E270020715F /* NewsController.h */, @@ -179,9 +189,9 @@ 54ACC29521061E270020715F /* NewsController.m in Sources */, 54ACC28421061B3B0020715F /* baRSS.xcdatamodeld in Sources */, 54ACC28C21061B3C0020715F /* main.m in Sources */, - 54ED7BDA2107CE5500AC8248 /* PyHandler.cpp in Sources */, 54ACC28121061B3B0020715F /* AppDelegate.m in Sources */, 54ACC29821061FBA0020715F /* Preferences.m in Sources */, + 1968E0AE14B8E8A90E194980 /* PyHandler.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -313,6 +323,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CLANG_WARN_CXX0X_EXTENSIONS = YES; + CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; + CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CODE_SIGN_ENTITLEMENTS = baRSS/baRSS.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; @@ -322,6 +336,11 @@ "$(inherited)", "$(PROJECT_DIR)", ); + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_LABEL = YES; INFOPLIST_FILE = baRSS/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -340,6 +359,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CLANG_WARN_CXX0X_EXTENSIONS = YES; + CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; + CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CODE_SIGN_ENTITLEMENTS = baRSS/baRSS.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; @@ -349,6 +372,11 @@ "$(inherited)", "$(PROJECT_DIR)", ); + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_LABEL = YES; INFOPLIST_FILE = baRSS/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/baRSS/AppDelegate.m b/baRSS/AppDelegate.m index a3895aa..49df037 100644 --- a/baRSS/AppDelegate.m +++ b/baRSS/AppDelegate.m @@ -21,7 +21,7 @@ // SOFTWARE. #import "AppDelegate.h" -#import "PyHandler.cpp" +#import "PyHandler.h" @interface AppDelegate () @property (strong) NSStatusItem *statusItem; @@ -35,20 +35,21 @@ } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { - // Insert code here to initialize your application self.statusItem = [NSStatusBar.systemStatusBar statusItemWithLength:NSVariableStatusItemLength]; self.statusItem.title = @"me"; self.statusItem.menu = self.statusMenu; - int a[] = {2017,8,9,13,9,59,0,0,0}; printf("will init\n"); - pyhandler_init(); + [PyHandler prepare]; printf("done\n"); - printf("%s", pyhandler_getWithDateArr([@"https://feeds.feedburner.com/simpledesktops" UTF8String], NULL, a)); + NSDictionary * obj = [PyHandler getFeed:@"https://feeds.feedburner.com/simpledesktops" withEtag:nil andModified:nil]; + NSLog(@"obj = %@", obj); [self quitClicked:nil]; } + + - (void)applicationWillTerminate:(NSNotification *)aNotification { - // Insert code here to tear down your application + [PyHandler shutdown]; } #pragma mark - Core Data stack diff --git a/baRSS/python/PyHandler.h b/baRSS/python/PyHandler.h new file mode 100644 index 0000000..c336a07 --- /dev/null +++ b/baRSS/python/PyHandler.h @@ -0,0 +1,29 @@ +// +// The MIT License (MIT) +// Copyright (c) 2018 Oleg Geier +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#import + +@interface PyHandler : NSObject ++ (void)prepare; // must be called before getFeed ++ (void)shutdown; ++ (NSDictionary *)getFeed:(NSString *)url withEtag:(NSString *)etag andModified:(NSString *)modified; +@end diff --git a/baRSS/PyHandler.cpp b/baRSS/python/PyHandler.m similarity index 67% rename from baRSS/PyHandler.cpp rename to baRSS/python/PyHandler.m index 1f4cc8e..054be8d 100644 --- a/baRSS/PyHandler.cpp +++ b/baRSS/python/PyHandler.m @@ -20,68 +20,96 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include -#include +#import "PyHandler.h" +#import -static PyObject *parseFeed; +static PyObject *parseFeedModule; -PyObject* appBundlePath() { +@implementation PyHandler + ++ (PyObject*)appBundlePath { CFBundleRef mainBundle = CFBundleGetMainBundle(); CFURLRef appPath = CFBundleCopyResourcesDirectoryURL(mainBundle); CFURLRef absolutePath = CFURLCopyAbsoluteURL(appPath); CFStringRef path = CFURLCopyFileSystemPath(absolutePath, kCFURLPOSIXPathStyle); - const char *resourcePath = CFStringGetCStringPtr(path, CFStringGetSystemEncoding()); + PyObject * pyStr = PyString_FromString(CFStringGetCStringPtr(path, CFStringGetSystemEncoding())); // const char *resourcePath = [[[NSBundle mainBundle] resourcePath] UTF8String]; CFRelease(path); CFRelease(absolutePath); CFRelease(appPath); - return PyString_FromString(resourcePath); + return pyStr; } -void pyhandler_init() { ++ (void)prepare { Py_Initialize(); PyObject *sys = PyImport_Import(PyString_FromString("sys")); PyObject *sys_path_append = PyObject_GetAttrString(PyObject_GetAttrString(sys, "path"), "append"); PyObject *resourcePath = PyTuple_New(1); - PyTuple_SetItem(resourcePath, 0, appBundlePath()); + PyTuple_SetItem(resourcePath, 0, [self appBundlePath]); PyObject_CallObject(sys_path_append, resourcePath); // import MyModule # this is in my project folder PyObject *myModule = PyImport_Import(PyString_FromString("getFeed")); - parseFeed = PyObject_GetAttrString(myModule, "parse"); + parseFeedModule = PyObject_GetAttrString(myModule, "parse"); } -void pyhandler_shutdown() { - PyObject_Free(parseFeed); ++ (void)shutdown { + PyObject_Free(parseFeedModule); Py_Finalize(); } -char* pyhandler_run(PyObject *args) { - if (parseFeed && PyCallable_Check(parseFeed)) { - PyObject *result = PyObject_CallObject(parseFeed, args); ++ (char*)run:(PyObject*)args { + if (parseFeedModule && PyCallable_Check(parseFeedModule)) { + PyObject *result = PyObject_CallObject(parseFeedModule, args); if (result != NULL && PyObject_TypeCheck(result, &PyString_Type)) return PyString_AsString(result); } return NULL; } -char* pyhandler_getWithDateStr(const char * url, const char * etag, void * date) { - return pyhandler_run(Py_BuildValue("(z z z)", url, etag, date)); ++ (char *)run:(const char *)url withEtag:(const char *)etag andDateString:(const char *)date { + if (!Py_IsInitialized()) + return NULL; + return [self run:Py_BuildValue("(z z z)", url, etag, date)]; } -char* pyhandler_getWithDateArr(const char * url, const char * etag, int * d) { ++ (char *)run:(const char *)url withEtag:(const char *)etag andDateArray:(int *)d { + if (!Py_IsInitialized()) + return NULL; if (d == NULL || abs(d[8]) > 1) { // d[8] == tm_isdst (between -1 and 1). Array size must be 9 - return pyhandler_run(Py_BuildValue("(z z z)", url, etag, NULL)); + return [self run:Py_BuildValue("(z z z)", url, etag, NULL)]; } - return pyhandler_run(Py_BuildValue("(z z [iiiiiiiii])", url, etag, - d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8])); + return [self run:Py_BuildValue("(z z [iiiiiiiii])", url, etag, + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8])]; } ++ (NSDictionary *)getFeed:(NSString *)url withEtag:(NSString *)etag andModified:(NSString *)modified { + const char* u = NULL; + const char* e = NULL; + const char* m = NULL; + if (url && url.length > 0) + u = [url UTF8String]; + if (etag && etag.length > 0) + e = [etag UTF8String]; + if (modified && modified.length > 0) + m = [modified UTF8String]; + + char *data = [self run:u withEtag:e andDateString:m]; + printf("JSON result:\n%s\n\n", data); + if (data == NULL) return nil; + + NSError *error = nil; + id object = [NSJSONSerialization JSONObjectWithData: + [[NSString stringWithUTF8String:data] dataUsingEncoding:NSUTF8StringEncoding] + options:0 error:&error]; + + if (error || !object || ![object isKindOfClass:[NSDictionary class]]) { + return nil; + } + return object; +} - - -// @see https://docs.python.org/3/c-api/index.html +// @see: https://docs.python.org/3/c-api/index.html /* PyObject *ObjcToPyObject(id object) { if (object == nil) { @@ -123,5 +151,6 @@ char* pyhandler_getWithDateArr(const char * url, const char * etag, int * d) { NSLog(@"ObjcToPyObject() could not convert Obj-C object to PyObject."); return NULL; } -} */ +}*/ +@end diff --git a/baRSS/feedparser521.py b/baRSS/python/feedparser521.py similarity index 100% rename from baRSS/feedparser521.py rename to baRSS/python/feedparser521.py diff --git a/baRSS/getFeed.py b/baRSS/python/getFeed.py similarity index 93% rename from baRSS/getFeed.py rename to baRSS/python/getFeed.py index 1368825..5333918 100644 --- a/baRSS/getFeed.py +++ b/baRSS/python/getFeed.py @@ -102,13 +102,7 @@ def prepareResult(obj): def parse(url, etag=None, modified=None): - print "mod:", modified if isinstance(modified, list): modified = time.struct_time(modified) - print url - print etag - print modified - return '[{"name":"joe","title":"none"},{"value":24}]' - # d = fp.parse(url, etag=etag, modified=modified) - # return json.dumps(prepareResult(d), separators=(',', ':')) - + d = fp.parse(url, etag=etag, modified=modified) + return json.dumps(prepareResult(d), separators=(',', ':'))