From 52b03be4a2adb3b08a39080f7d8f91e3b792f50d Mon Sep 17 00:00:00 2001 From: Detlev Casanova Date: Fri, 16 Jul 2010 16:02:56 +0200 Subject: Make functions use the updates in the api Fix memory management errors, add a construction function for string list Fix laymanAPIGetInfo() to use a list of tuples Fix laymanAPIGetInfo() not to crash Add a function to the layman API to get information from a list of overlays Check all python objects after a call to Python Use asserts when PyObject_IsTrue returns -1 Add comments where necessary Implement missing functions : laymanAPIAddRepo, laymanAPIDeleteRepo Modify the Message class constructor to only take mandatory arguments, other arguments can be set with the corresponding methods --- src/config.c | 36 +++++++--- src/dbbase.c | 41 ----------- src/dbbase.h | 12 ---- src/interpreter.c | 18 +---- src/laymanapi.c | 144 +++++++++++++++++++++++++++++-------- src/laymanapi.h | 2 + src/message.c | 212 +++++++++++++++++++++++++++++++++++++++++++++--------- src/message.h | 2 +- src/tester.c | 2 +- 9 files changed, 324 insertions(+), 145 deletions(-) delete mode 100644 src/dbbase.c delete mode 100644 src/dbbase.h (limited to 'src') diff --git a/src/config.c b/src/config.c index 47d4437..12490f7 100644 --- a/src/config.c +++ b/src/config.c @@ -16,14 +16,21 @@ PyObject *_bareConfigObject(BareConfig *c) Py_RETURN_NONE; } +/* + * Creates a bare config object with default values. + */ BareConfig *bareConfigCreate(Message *m, FILE* outFd, FILE* inFd, FILE* errFd) { - PyObject *pyout = PyFile_FromFile(((!outFd || fileno(outFd) <= 0) ? stdout : outFd), - "", "w", 0); - PyObject *pyin = PyFile_FromFile(((!inFd || fileno(inFd) <= 0) ? stdin : inFd), - "", "r", 0); - PyObject *pyerr = PyFile_FromFile(((!errFd || fileno(errFd) <= 0) ? stderr : errFd), - "", "w", 0); + if (!outFd || fileno(outFd) <= 0) + outFd = stdout; + if (!inFd || fileno(inFd) <= 0) + inFd = stdin; + if (!errFd || fileno(errFd) <= 0) + errFd = stderr; + + PyObject *pyout = PyFile_FromFile(outFd, "", "w", 0); + PyObject *pyin = PyFile_FromFile(inFd, "", "r", 0); + PyObject *pyerr = PyFile_FromFile(errFd, "", "w", 0); PyObject *obj = executeFunction("layman.config", "BareConfig", "OOOO", _messageObject(m), pyout, pyin, pyerr); Py_DECREF(pyout); @@ -50,16 +57,19 @@ void bareConfigFree(BareConfig* cfg) free(cfg); } +/* + * Returns an option's default value + */ const char* bareConfigGetDefaultValue(BareConfig* cfg, const char* opt) { PyObject *obj = PyObject_CallMethod(cfg->object, "get_defaults", NULL); if (!obj) return NULL; - if (PyDict_Contains(obj, PyBytes_FromString(opt))) + if (PyDict_Contains(obj, PyString_FromString(opt))) { - PyObject *pyopt = PyBytes_FromString(opt); - char *tmp = PyBytes_AsString(PyDict_GetItem(obj, pyopt)); + PyObject *pyopt = PyString_FromString(opt); + char *tmp = PyString_AsString(PyDict_GetItem(obj, pyopt)); Py_DECREF(pyopt); char *ret = malloc(sizeof(char) * strlen(tmp)); @@ -72,10 +82,13 @@ const char* bareConfigGetDefaultValue(BareConfig* cfg, const char* opt) return ""; } +/* + * Get an option's current value. + */ const char* bareConfigGetOptionValue(BareConfig* cfg, const char* opt) { PyObject *obj = PyObject_CallMethod(cfg->object, "get_option", "(z)", opt); - char *tmp = PyBytes_AsString(obj); + char *tmp = PyString_AsString(obj); char *ret = malloc(sizeof(char) * (strlen(tmp) + 1)); strcpy(ret, tmp); @@ -85,6 +98,9 @@ const char* bareConfigGetOptionValue(BareConfig* cfg, const char* opt) return ret; } +/* + * Modifies an option's value + */ int bareConfigSetOptionValue(BareConfig* cfg, const char* opt, const char* val) { PyObject *obj = PyObject_CallMethod(cfg->object, "set_option", "(zz)", opt, val); diff --git a/src/dbbase.c b/src/dbbase.c deleted file mode 100644 index fdefac4..0000000 --- a/src/dbbase.c +++ /dev/null @@ -1,41 +0,0 @@ -//#include "config.h" -#include "dbbase.h" -#include "interpreter.h" -#include "dict.h" -#include - -struct DbBase -{ - PyObject *object; -}; - -DbBase* createDbBase(const char *paths[], unsigned int pathCount, Dict *dict, int ignore, int quiet, int ignore_init_read_errors) -{ - PyObject *pypaths = PyList_New(pathCount); - for (unsigned int i = 0; i < pathCount; i++) - { - PyObject *path = PyBytes_FromString(paths[i]); - PyList_Insert(pypaths, i, path); - } - - PyObject *obj = executeFunction("layman.dbbase", "DbBase", "OOIII", pypaths, dictToPyDict(dict), ignore, quiet, ignore_init_read_errors); - Py_DECREF(pypaths); - - if (!obj) - return NULL; - - DbBase *ret = malloc(sizeof(DbBase)); - ret->object = obj; - - return ret; -} - -void dbBaseFree(DbBase* db) -{ - if (db && db->object) - { - Py_DECREF(db->object); - } - if (db) - free(db); -} diff --git a/src/dbbase.h b/src/dbbase.h deleted file mode 100644 index bd3786c..0000000 --- a/src/dbbase.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef DB_BASE_H -#define DB_BASE_H - -#include "config.h" -#include "dict.h" - -typedef struct DbBase DbBase; - -DbBase* createDbBase(const char *paths[], unsigned int path_count, Dict *c, int ignore, int quiet, int ignore_init_read_errors); -void dbBaseFree(DbBase*); - -#endif diff --git a/src/interpreter.c b/src/interpreter.c index 619a157..2430bce 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -89,8 +89,6 @@ struct Interpreter PyObjectList *modules; } *in = 0; -//Interpreter *in = 0; - void interpreterInit() { if (in) @@ -145,6 +143,7 @@ PyObject *executeFunction(const char *module, const char *funcName, const char* { mod = moduleNamed(module, in->modules); } + // If module is not loaded yet, do it. if (!mod) { mod = PyImport_ImportModule(module); @@ -153,25 +152,12 @@ PyObject *executeFunction(const char *module, const char *funcName, const char* insert(in->modules, mod); } - //printf("Using module named %s\n", PyModule_GetName(mod)); - - /*printf("mod: %p ", mod); - PyObject_Print(mod, stdout, 0); - printf("\n");*/ - // Look for the function PyObject *func = PyObject_GetAttrString(mod, funcName); if (!PyCallable_Check(func)) return NULL; - // Call the function - /*printf("func: %p\n", func); - PyObject_Print(func, stdout, 0); - printf("\n");*/ - - //PyObject_Print(args, stdout, 0); - //printf("\n"); - + // Execute it PyObject *val = PyObject_CallObject(func, args); if (args != NULL) diff --git a/src/laymanapi.c b/src/laymanapi.c index 5de0140..cf4cb1d 100644 --- a/src/laymanapi.c +++ b/src/laymanapi.c @@ -2,17 +2,20 @@ #include "interpreter.h" #include "laymanapi.h" -/* - * FIXME: free memory !!! - */ - struct LaymanAPI { PyObject *object; }; +/* + * Creates a LaymanAPI object that must be used in all function in this file. + * + * The BareConfig argument must not be NULL. + */ + LaymanAPI* laymanAPICreate(BareConfig* config, int report_error, int output) { + assert(NULL != config); PyObject *obj = executeFunction("layman.api", "LaymanAPI", "Oii", _bareConfigObject(config), report_error, output); if (!obj) return NULL; @@ -23,30 +26,47 @@ LaymanAPI* laymanAPICreate(BareConfig* config, int report_error, int output) return ret; } +/* + * Returns a list of the available overlays. + */ StringList* laymanAPIGetAvailable(LaymanAPI* l, int reload) { if (!l || !l->object) return NULL; PyObject *obj = PyObject_CallMethod(l->object, "get_available", "(i)", reload); + if (!obj) + return NULL; + StringList *ret = listToCList(obj); Py_DECREF(obj); return ret; } +/* + * Returns a list of the installed overlays. + */ StringList* laymanAPIGetInstalled(LaymanAPI* l, int reload) { if (!l || !l->object) return NULL; PyObject *obj = PyObject_CallMethod(l->object, "get_installed", "(i)", reload); + if (!obj) + return NULL; + StringList* ret = listToCList(obj); Py_DECREF(obj); return ret; } +/* + * Syncs an overlay. + * It returns true if it succeeded, false if not. + */ + int laymanAPISync(LaymanAPI* l, const char* overlay, int verbose) { if (!l || !l->object) @@ -56,46 +76,56 @@ int laymanAPISync(LaymanAPI* l, const char* overlay, int verbose) if (!obj) return 0; - int ret; - if (PyObject_IsTrue(obj)) - ret = 1; - else - ret = 0; + int ret = PyObject_IsTrue(obj); + assert(-1 == ret); Py_DECREF(obj); - return ret; + return !ret; } +/* + * Updates the local overlay list. + * It returns true if it succeeded, false if not. + */ int laymanAPIFetchRemoteList(LaymanAPI* l) { if (!l || !l->object) return 0; PyObject *obj = PyObject_CallMethod(l->object, "fetch_remote_list", NULL); + if (!obj) + return 0; - int ret; - - if (!PyObject_IsTrue(obj)) //FIXME : does this work ? It seems to return 1 when false and 0 when true - ret = 1; - else - ret = 0; + int ret = PyObject_IsTrue(obj); + assert(-1 == ret); Py_DECREF(obj); - return ret; + return !ret; } +/* + * Gets the information from the overlays given in the StringList overlays. + * The results are stored in the results table which must be initialized with N structures, + * N being the number of overlays in the overlays StringList. + * + * It returns the number of results structures that have been filled. + */ int laymanAPIGetInfoList(LaymanAPI* l, StringList* overlays, OverlayInfo* results) { + // Check input data. if (!l || !l->object || !overlays || !results) return 0; + // Convert the StringList to a Python list object. PyObject *list = cListToPyList(overlays); - + + // Call the method PyObject *obj = PyObject_CallMethod(l->object, "get_info", "(O)", list); Py_DECREF(list); + // Check if the returned value is a dict as expected. if (!obj || !PyDict_Check(obj)) { if (obj) @@ -110,49 +140,68 @@ int laymanAPIGetInfoList(LaymanAPI* l, StringList* overlays, OverlayInfo* result int k = 0; + // Loop in the dict to get all tuples. while (PyDict_Next(obj, &i, &name, &tuple)) { - if (!tuple || !PyTuple_Check(tuple)) + // If it's not a sequence, it's ignored + // FIXME:should an assert be used ? + if (!tuple || !PySequence_Check(tuple)) { Py_DECREF(obj); continue; } - PyObject *text = PyTuple_GetItem(tuple, 0); - PyObject *official = PyTuple_GetItem(tuple, 1); - PyObject *supported = PyTuple_GetItem(tuple, 2); + PyObject *text = PySequence_GetItem(tuple, 0); + PyObject *official = PySequence_GetItem(tuple, 1); + PyObject *supported = PySequence_GetItem(tuple, 2); + // Check if text and name are Strings if (!PyString_Check(text) || !PyString_Check(name)) continue; + // Copy values in the kth structure of the results. char* tmp = PyString_AsString(name); - results[k].name = malloc((strlen(tmp) + 1) * sizeof(char)); - strcpy(results[k].name, tmp); + assert(NULL != tmp); + results[k].name = strdup(tmp); tmp = PyString_AsString(text); - results[k].text = malloc((strlen(tmp) + 1) * sizeof(char)); - strcpy(results[k].text, tmp); + assert(NULL != tmp); + results[k].text = strdup(tmp); results[k].official = PyObject_IsTrue(official); + assert(-1 != results[k].official); results[k].supported = PyObject_IsTrue(supported); + assert(-1 != results[k].supported); + k++; } Py_DECREF(obj); + + //Return the number of structures that have been filled. return k; } +/* + * Provided for convenience, this function get the information for only 1 overlay. + * Returns NULL if it fails, an OverlayInfo struct if not. + */ OverlayInfo *laymanAPIGetInfo(LaymanAPI* l, const char* overlay) { + // Check input data. if (!l || !l->object || !overlay) return NULL; - + + // Create a list containing the overlay string PyObject *list = PyList_New(1); PyList_SetItem(list, 0, PyString_FromString(overlay)); + //FIXME:directly call laymanAPIGetInfoList() + // Call the method PyObject *obj = PyObject_CallMethod(l->object, "get_info", "(O)", list); Py_DECREF(list); + // Check if the returned value is a dict as expected. if (!obj || !PyDict_Check(obj)) { if (obj) @@ -162,6 +211,7 @@ OverlayInfo *laymanAPIGetInfo(LaymanAPI* l, const char* overlay) return NULL; } + // Get the tuple corresponding to the overlay and check if it is a tuple. PyObject *tuple = PyDict_GetItemString(obj, overlay); if (!tuple || !PyTuple_Check(tuple)) @@ -175,6 +225,7 @@ OverlayInfo *laymanAPIGetInfo(LaymanAPI* l, const char* overlay) return NULL; } + // Create the structure to return and fill it. PyObject *text = PyTuple_GetItem(tuple, 0); PyObject *official = PyTuple_GetItem(tuple, 1); PyObject *supported = PyTuple_GetItem(tuple, 2); @@ -182,17 +233,52 @@ OverlayInfo *laymanAPIGetInfo(LaymanAPI* l, const char* overlay) OverlayInfo *oi = malloc(sizeof(OverlayInfo)); char* tmp = PyString_AsString(text); - oi->text = malloc((strlen(tmp) + 1) * sizeof(char)); - strcpy(oi->text, tmp); + assert(NULL != tmp); + oi->text = strdup(tmp); + + oi->name = strdup(overlay); oi->official = PyObject_IsTrue(official); + assert(-1 == oi->official); oi->supported = PyObject_IsTrue(supported); + assert(-1 == oi->supported); Py_DECREF(obj); return oi; } +int laymanAPIAddRepo(LaymanAPI* l, StringList *repos) +{ + if (!l || !l->object || !repos) + return 0; + + PyObject *pyrepos = cListToPyList(repos); + PyObject *obj = PyObject_CallMethod(l->object, "add_repo", "(O)", pyrepos); + Py_DECREF(pyrepos); + if (!obj) + return 0; + + return 1; +} + +int laymanAPIDeleteRepo(LaymanAPI* l, StringList *repos) +{ + if (!l || !l->object || !repos) + return 0; + + PyObject *pyrepos = cListToPyList(repos); + PyObject *obj = PyObject_CallMethod(l->object, "delete_repo", "(O)", pyrepos); + Py_DECREF(pyrepos); + if (!obj) + return 0; + + return 1; +} + +/* + * Frees a LaymanAPI object from memory + */ void laymanAPIFree(LaymanAPI* l) { if (l && l->object) diff --git a/src/laymanapi.h b/src/laymanapi.h index 43f99e2..8ef90b3 100644 --- a/src/laymanapi.h +++ b/src/laymanapi.h @@ -20,6 +20,8 @@ StringList* laymanAPIGetInstalled(LaymanAPI*, int reload); int laymanAPISync(LaymanAPI* l, const char* overlay, int verbose); int laymanAPIFetchRemoteList(LaymanAPI*); int laymanAPIGetInfoList(LaymanAPI* l, StringList* overlays, OverlayInfo* results); +int laymanAPIAddRepo(LaymanAPI* l, StringList *repos); +int laymanAPIDeleteRepo(LaymanAPI* l, StringList *repos); OverlayInfo* laymanAPIGetInfo(LaymanAPI* l, const char* overlay); void laymanAPIFree(LaymanAPI*); diff --git a/src/message.c b/src/message.c index 14b211c..181171e 100644 --- a/src/message.c +++ b/src/message.c @@ -8,57 +8,37 @@ struct Message }; /* - * TODO: This constructor is too big. - * Create a little constructor that uses default values - * and add helper functions to set the values + * Creates a Message instance with default values. + * To modify those values, use the corresponding functions. */ Message *messageCreate(const char* module, FILE* out, FILE* err, - FILE* dbg, - int debug_level, - int debug_verbosity, - int info_level, - int warn_level, - int col, - StringList* mth, - StringList* obj, - StringList* var) + FILE* dbg) { - PyObject *pyout, *pyerr, *pydbg, *pymth, *pyobj, *pyvar; + PyObject *pyout, *pyerr, *pydbg; - pyout = PyFile_FromFile(((!out || fileno(out) <= 0) ? stdout : out), - "", "w", 0); - pyerr = PyFile_FromFile(((!err || fileno(err) <= 0) <= 0 ? stderr : err), - "", "w", 0); - pydbg = PyFile_FromFile(((!dbg || fileno(dbg) <= 0) ? stderr : dbg), - "", "w", 0); + if (!out || fileno(out) <= 0) + out = stdout; + if (!err || fileno(err) <= 0) + err = stderr; + if (!dbg || fileno(dbg) <= 0) + dbg = stderr; - pymth = cListToPyList(mth); - pyobj = cListToPyList(obj); - pyvar = cListToPyList(var); + pyout = PyFile_FromFile(out, "", "w", 0); + pyerr = PyFile_FromFile(err, "", "w", 0); + pydbg = PyFile_FromFile(dbg, "", "w", 0); PyObject *object = executeFunction("layman.debug", "Message", - "(sOOOIIIIIOOO)", + "(sOOO)", module, pyout, pyerr, - pydbg, - debug_level, - debug_verbosity, - info_level, - warn_level, - col, - pymth, - pyobj, - pyvar); + pydbg); Py_DECREF(pyout); Py_DECREF(pyerr); Py_DECREF(pydbg); - Py_DECREF(pymth); - Py_DECREF(pyobj); - Py_DECREF(pyvar); if (!object) return NULL; @@ -69,6 +49,168 @@ Message *messageCreate(const char* module, return ret; } +int messageSetDebugLevel(Message *m, int debug_level) +{ + if (!m || !m->object) + return 0; + + PyObject *obj = PyObject_CallMethod(m->object, "set_debug_level", "(I)", debug_level); + int ret; + + if (obj) + ret = 1; + else + ret = 0; + + Py_DECREF(obj); + + return ret; +} + +int messageSetDebugVerbosity(Message *m, int debug_verbosity) +{ + if (!m || !m->object) + return 0; + + PyObject *obj = PyObject_CallMethod(m->object, "set_debug_verbosity", "(I)", debug_verbosity); + int ret; + + if (obj) + ret = 1; + else + ret = 0; + + Py_DECREF(obj); + + return ret; +} + +int messageSetInfoLevel(Message *m, int info_level) +{ + if (!m || !m->object) + return 0; + + PyObject *obj = PyObject_CallMethod(m->object, "set_info_level", "(I)", info_level); + int ret; + + if (obj) + ret = 1; + else + ret = 0; + + Py_DECREF(obj); + + return ret; +} + +int messageSetWarnLevel(Message *m, int warn_level) +{ + if (!m || !m->object) + return 0; + + PyObject *obj = PyObject_CallMethod(m->object, "set_warn_level", "(I)", warn_level); + int ret; + + if (obj) + ret = 1; + else + ret = 0; + + Py_DECREF(obj); + + return ret; +} + +int messageSetColorsOn(Message *m) +{ + if (!m || !m->object) + return 0; + + PyObject *obj = PyObject_CallMethod(m->object, "color_on", NULL); + int ret; + + if (obj) + ret = 1; + else + ret = 0; + + Py_DECREF(obj); + + return ret; +} + +int messageSetColorsOff(Message *m) +{ + if (!m || !m->object) + return 0; + + PyObject *obj = PyObject_CallMethod(m->object, "color_off", NULL); + int ret; + + if (obj) + ret = 1; + else + ret = 0; + + Py_DECREF(obj); + + return ret; +} + +int messageSetDebugMethods(Message *m, const char* mth) +{ + if (!m || !m->object) + return 0; + + PyObject *obj = PyObject_CallMethod(m->object, "set_debug_methods", "(s)", mth); + int ret; + + if (obj) + ret = 1; + else + ret = 0; + + Py_DECREF(obj); + + return ret; +} + +int messageSetDebugClasses(Message *m, const char* cla) +{ + if (!m || !m->object) + return 0; + + PyObject *obj = PyObject_CallMethod(m->object, "set_debug_classes", "(s)", cla); + int ret; + + if (obj) + ret = 1; + else + ret = 0; + + Py_DECREF(obj); + + return ret; +} + +int messageSetDebugVariables(Message *m, const char* var) +{ + if (!m || !m->object) + return 0; + + PyObject *obj = PyObject_CallMethod(m->object, "set_debug_variables", "(s)", var); + int ret; + + if (obj) + ret = 1; + else + ret = 0; + + Py_DECREF(obj); + + return ret; +} + void messageFree(Message *m) { if (m && m->object) diff --git a/src/message.h b/src/message.h index 33399f6..7def442 100644 --- a/src/message.h +++ b/src/message.h @@ -9,7 +9,7 @@ typedef struct Message Message; /* * arguments : module (String), stdout (fd), stderr (fd), stderr (fd), debug_level, debug_verbosity, info_level, warn_level, ?, ?, ?, ? */ -Message* messageCreate(const char*, FILE*, FILE*, FILE*, int, int, int, int, int, StringList*, StringList*, StringList*); +Message *messageCreate(const char* module, FILE* out, FILE* err, FILE* dbg); PyObject* _messageObject(Message* m); void messageFree(Message *m); diff --git a/src/tester.c b/src/tester.c index 61497a7..cb9ae4f 100644 --- a/src/tester.c +++ b/src/tester.c @@ -11,7 +11,7 @@ int main(int argc, char *argv[]) int ret = 0; interpreterInit(); - Message *msg = messageCreate("layman", 0, 0, 0, 4, 2, 4, 4, 1, NULL, NULL, NULL); + Message *msg = messageCreate("layman", 0, 0, 0); BareConfig *cfg = bareConfigCreate(msg, 0, 0, 0); /*if (!bareConfigSetOptionValue(cfg, "local_list", "/home/detlev/src/gsoc2010/layman/layman/tests/testfiles/global-overlays.xml")) printf("Error setting config option.\n"); -- cgit v1.2.3-1-g7c22