call python from C++/mql5 - python

I am testing just a small change to this code here: https://github.com/Roffild/RoffildLibrary/blob/master/Libraries/Roffild/PythonDLL/mql_class.c
but it raised exception that I couldn't catch. Anybody has a clue why at least from a look at the code?
I modified a few places to make these 2 new methods compiled ok: the pyMQL_send just crashed without meaning full message while the pyMQL_test raised "SystemError: null argument to internal routine"
_DLLSTD(mqlint) pyMQL_send(const mqllong magic, const mqlstring value,
const mqldouble _DLLOUTARRAY(inputs), const mqlint inputs_size,
mqlstring _DLLOUTSTRING(buffer), const mqlint stringBufferLen)
{
PyObject *arg1 = NULL;
PyObject *arg2 = NULL;
PyObject *arg3 = NULL;
PyObject *result = NULL;
PyObject **items = NULL;
Py_ssize_t x, size;
mqlstring str;
mqlint ret = -1;
PY_THREAD_START_OR(return ret);
PyErr_Clear();
arg1 = PyLong_FromLongLong(magic);
arg2 = PyUnicode_FromWideChar(value, -1);
arg3 = PyTuple_New(inputs_size);
if (arg1 != NULL && arg2 != NULL && arg3 != NULL) {
items = PySequence_Fast_ITEMS(arg3);
for (x = 0; x < inputs_size; x++) {
items[x] = PyFloat_FromDouble(inputs[x]);
}
result = PyObject_CallFunctionObjArgs(__interp->mql_send, arg1, arg2, arg3, NULL);
if (result != NULL) {
Py_DECREF(arg1);
arg1 = PyObject_Str(result);
str = PyUnicode_AsUnicodeAndSize(arg1, &size);
ret = (mqlint)size;
if (size > stringBufferLen) {
size = stringBufferLen;
}
wmemcpy(buffer, str, size);
buffer[size] = 0;
}
}
Py_XDECREF(arg1);
Py_XDECREF(arg2);
Py_XDECREF(arg3);
Py_XDECREF(result);
PY_THREAD_STOP;
return ret;
}
// altered from _getDouble
_DLLSTD(mqlint) pyMQL_test(const mqllong magic, const mqlstring value,
const mqldouble _DLLOUTARRAY(inputs), const mqlint inputs_size,
mqldouble _DLLOUTARRAY(outputs), const mqlint outputs_size)
{
PyObject* arg1 = NULL;
PyObject* arg2 = NULL;
PyObject* arg3 = NULL;
PyObject* result = NULL;
PyObject* seq = NULL;
PyObject** items = NULL;
Py_ssize_t x, size;
mqlint ret = -1;
PY_THREAD_START_OR(return ret);
PyErr_Clear();
arg1 = PyLong_FromLongLong(magic);
arg2 = PyUnicode_FromWideChar(value, -1);
arg3 = PyTuple_New(inputs_size);
if (arg1 != NULL && arg2 != NULL && arg3 != NULL) {
items = PySequence_Fast_ITEMS(arg3);
for (x = 0; x < inputs_size; x++) {
items[x] = PyFloat_FromDouble(inputs[x]);
}
result = PyObject_CallFunctionObjArgs(__interp->mql_test, arg1, arg2, arg3, NULL);
if (result != NULL) {
if (result == Py_None) {
ret = 0;
}
else {
seq = PySequence_Fast(result, "This is not PySequence.");
if (seq != NULL) {
size = PySequence_Fast_GET_SIZE(seq);
ret = (mqlint)size;
if (size > outputs_size) {
size = outputs_size;
}
items = PySequence_Fast_ITEMS(seq);
for (x = 0; x < size; x++) {
outputs[x] = PyFloat_AsDouble(items[x]);
}
}
}
}
}
Py_XDECREF(arg1);
Py_XDECREF(arg2);
Py_XDECREF(arg3);
Py_XDECREF(result);
Py_XDECREF(seq);
PY_THREAD_STOP;
return ret;
}

Related

How to return an array in C into python?

I have been working on a selection sort with C extension on python, which aimed to intake a list in python, sort using C code and return a sorted list in python. Sounds simple, but I just could not get the value of the sorted list correct in python, as I would get a value of 1 when I was trying to print the sorted list.
Here is my code in C:
#include <Python.h>
int selectionSort(int array[], int N){
int i, j, min_element;
for (i = 0; i < N-1; i++) {
min_element = i;
for (j = i+1; j < N; j++)
if (array[j] < array[min_element])
min_element = j;
int temp = array[min_element];
array[min_element] = array[i];
array[i] = temp;
}
return *array;
}
static PyObject* selectSort(PyObject *self, PyObject *args)
{
PyObject* list;
int *array, N;
if (!PyArg_ParseTuple(args, "O", &list))
return NULL;
N = PyObject_Length(list);
if (N < 0)
return NULL;
array = (int *) malloc(sizeof(int *) * N);
if (array == NULL)
return NULL;
for (int index = 0; index < N; index++) {
PyObject *item;
item = PyList_GetItem(list, index);
if (!PyFloat_Check(item))
array[index] = 0;
array[index] = PyFloat_AsDouble(item);
}
return Py_BuildValue("i", selectionSort(array, N));
}
static PyMethodDef myMethods[] = {
{ "selectSort", selectSort, METH_VARARGS, "..." },
{ NULL, NULL, 0, NULL }
};
static struct PyModuleDef myModule = {
PyModuleDef_HEAD_INIT,
"myModule",
"Test Module",
-1,
myMethods
};
PyMODINIT_FUNC PyInit_myModule(void)
{
return PyModule_Create(&myModule);
}
Here is the command line I executed:
>>> import myModule
>>> unsortedList = [1, 4, 3, 90, 22, 34, 32]
>>> sortedList = myModule.selectSort(unsortedList)
>>> print(sortedList)
1
Anyone has any ideas on this? I would really appreciate it! Thanks!
Just change return type from int to int* and return with return array, not return *array.

cannot get C++ PyArray_SimpleNewFromData to complete

I have already looked for instructions to do this. I have used import_Array(). I am using Python 3.10 I have the Windows Visual Studio.
this is my code:
PyObject* switch_rut(PyObject* self, PyObject* args) {
PyArrayObject* inp1;
PyArrayObject* inp2;
PyObject* outp;
double swv;
double* res;
if (!PyArg_ParseTuple(args, "O!O!d:switcher", &PyArray_Type, &inp1, &PyArray_Type, &inp2, &swv)) {
return NULL;
}
if (inp1->nd != 1 || inp1->descr->type_num != PyArray_DOUBLE || inp2->nd != 1 || inp2->descr->type_num != PyArray_DOUBLE || ) {
PyErr_SetString(PyExc_ValueError,
"arrays must be one-dimensional and of type float");
return NULL;
}
if (inp1->dimensions[0] != inp2->dimensions[0]) {
PyErr_SetString(PyExc_ValueError,
"arrays must be of equal length");
return NULL;
}
int* cnt = new int[1];
int nd = 1;
cnt[0] = inp1->dimensions[0];
int acnt = inp1->dimensions[0];
res = new double[acnt];
double ipar1, ipar2, iparr;
for (int i = 0; i < acnt; i++) {
ipar1 = *(double*)(inp1->data + i * inp1->strides[0]);
ipar2 = *(double*)(inp2->data + i * inp2->strides[0]);
iparr = ipar2 * swv + ipar1 * (1 - swv);
res[i] = iparr;
}
outp = PyArray_SimpleNewFromData(nd, cnt, NPY_DOUBLE,reinterpret_cast<void*> res);
return outp;
}
What I was talking about was how to embed Python in C or C++ with Numpy arrays
and how to return a value as a Numpy array.
This is what I used.
PyArray_New(&PyArray_Type, nd, bcnt, NPY_DOUBLE, NULL, (void*) res, 0, NPY_ARRAY_CARRAY, NULL);

How can I use pyopencv_to function?

I have a program written in python with OpenCV. I want to add a feature which is otsu thresholding with mask. So, I get a code from here written in c++. I tried to convert it as python, but it's too slow (because of python). Finally, I make up my mind to use c++ with python. I try to embedding, and I find pyopencv_to() function. But, I can't use it because of PyArray_Check(). When program entered this function, die immediately. It doesn't give any error message. I guess it may be segmentation fault. Many stack overflow's answers says that "use import_array()". But it doesn't work for me.
Here is my code.
convert.cpp
#include <Python.h>
#include "numpy/ndarrayobject.h"
#include "opencv2/core/core.hpp"
#include "convert.hpp"
static PyObject* opencv_error = 0;
static int failmsg(const char *fmt, ...)
{
char str[1000];
va_list ap;
va_start(ap, fmt);
vsnprintf(str, sizeof(str), fmt, ap);
va_end(ap);
PyErr_SetString(PyExc_TypeError, str);
return 0;
}
class PyAllowThreads
{
public:
PyAllowThreads() : _state(PyEval_SaveThread()) {}
~PyAllowThreads()
{
PyEval_RestoreThread(_state);
}
private:
PyThreadState* _state;
};
class PyEnsureGIL
{
public:
PyEnsureGIL() : _state(PyGILState_Ensure()) {}
~PyEnsureGIL()
{
PyGILState_Release(_state);
}
private:
PyGILState_STATE _state;
};
#define ERRWRAP2(expr) \
try \
{ \
PyAllowThreads allowThreads; \
expr; \
} \
catch (const cv::Exception &e) \
{ \
PyErr_SetString(opencv_error, e.what()); \
return 0; \
}
using namespace cv;
static PyObject* failmsgp(const char *fmt, ...)
{
char str[1000];
va_list ap;
va_start(ap, fmt);
vsnprintf(str, sizeof(str), fmt, ap);
va_end(ap);
PyErr_SetString(PyExc_TypeError, str);
return 0;
}
static size_t REFCOUNT_OFFSET = (size_t)&(((PyObject*)0)->ob_refcnt) +
(0x12345678 != *(const size_t*)"\x78\x56\x34\x12\0\0\0\0\0")*sizeof(int);
static inline PyObject* pyObjectFromRefcount(const int* refcount)
{
return (PyObject*)((size_t)refcount - REFCOUNT_OFFSET);
}
static inline int* refcountFromPyObject(const PyObject* obj)
{
return (int*)((size_t)obj + REFCOUNT_OFFSET);
}
class NumpyAllocator : public MatAllocator
{
public:
NumpyAllocator() {}
~NumpyAllocator() {}
void allocate(int dims, const int* sizes, int type, int*& refcount,
uchar*& datastart, uchar*& data, size_t* step)
{
PyEnsureGIL gil;
int depth = CV_MAT_DEPTH(type);
int cn = CV_MAT_CN(type);
const int f = (int)(sizeof(size_t)/8);
int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE :
depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT :
depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT :
depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
int i;
npy_intp _sizes[CV_MAX_DIM+1];
for( i = 0; i < dims; i++ )
_sizes[i] = sizes[i];
if( cn > 1 )
{
/*if( _sizes[dims-1] == 1 )
_sizes[dims-1] = cn;
else*/
_sizes[dims++] = cn;
}
PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum);
if(!o)
CV_Error_(CV_StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims));
refcount = refcountFromPyObject(o);
npy_intp* _strides = PyArray_STRIDES(o);
for( i = 0; i < dims - (cn > 1); i++ )
step[i] = (size_t)_strides[i];
datastart = data = (uchar*)PyArray_DATA(o);
}
void deallocate(int* refcount, uchar*, uchar*)
{
PyEnsureGIL gil;
if( !refcount )
return;
PyObject* o = pyObjectFromRefcount(refcount);
Py_INCREF(o);
Py_DECREF(o);
}
};
NumpyAllocator g_numpyAllocator;
enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 };
int init_numpy() {
import_array();
return 0;
}
const static int numpy_initialized = init_numpy();
int pyopencv_to(const PyObject* o, Mat& m, const char* name, bool allowND)
{
if(!o || o == Py_None)
{
if( !m.data )
m.allocator = &g_numpyAllocator;
return true;
}
if( !PyArray_Check(o) ) // this line makes error without message
{
failmsg("%s is not a numpy array", name);
return false;
}
// NPY_LONG (64 bit) is converted to CV_32S (32 bit)
int typenum = PyArray_TYPE(o);
int type = typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S :
typenum == NPY_USHORT ? CV_16U : typenum == NPY_SHORT ? CV_16S :
typenum == NPY_INT || typenum == NPY_LONG ? CV_32S :
typenum == NPY_FLOAT ? CV_32F :
typenum == NPY_DOUBLE ? CV_64F : -1;
if( type < 0 )
{
failmsg("%s data type = %d is not supported", name, typenum);
return false;
}
int ndims = PyArray_NDIM(o);
if(ndims >= CV_MAX_DIM)
{
failmsg("%s dimensionality (=%d) is too high", name, ndims);
return false;
}
int size[CV_MAX_DIM+1];
size_t step[CV_MAX_DIM+1], elemsize = CV_ELEM_SIZE1(type);
const npy_intp* _sizes = PyArray_DIMS(o);
const npy_intp* _strides = PyArray_STRIDES(o);
bool transposed = false;
for(int i = 0; i < ndims; i++)
{
size[i] = (int)_sizes[i];
step[i] = (size_t)_strides[i];
}
if( ndims == 0 || step[ndims-1] > elemsize ) {
size[ndims] = 1;
step[ndims] = elemsize;
ndims++;
}
if( ndims >= 2 && step[0] < step[1] )
{
std::swap(size[0], size[1]);
std::swap(step[0], step[1]);
transposed = true;
}
if( ndims == 3 && size[2] <= CV_CN_MAX && step[1] == elemsize*size[2] )
{
ndims--;
type |= CV_MAKETYPE(0, size[2]);
}
if( ndims > 2 && !allowND )
{
failmsg("%s has more than 2 dimensions", name);
return false;
}
m = cv::Mat(ndims, size, type, PyArray_DATA(o), step);
if( m.data )
{
m.u->refcount = *refcountFromPyObject(o);
m.addref(); // protect the original numpy array from deallocation
// (since Mat destructor will decrement the reference counter)
};
m.allocator = &g_numpyAllocator;
if( transposed )
{
cv::Mat tmp;
tmp.allocator = &g_numpyAllocator;
transpose(m, tmp);
m = tmp;
}
return true;
}
PyObject* pyopencv_from(const Mat& m)
{
if( !m.data )
Py_RETURN_NONE;
Mat temp, *p = (Mat*)&m;
if(!(p->u->refcount) || p->allocator != &g_numpyAllocator)
{
temp.allocator = &g_numpyAllocator;
ERRWRAP2(m.copyTo(temp));
p = &temp;
}
p->addref();
return pyObjectFromRefcount(&(p->u->refcount));
}
threshold.cpp
#include <Python.h>
#include "opencv2/opencv.hpp"
#include "convert.hpp"
#include "numpy/ndarrayobject.h"
using namespace std;
using namespace cv;
double otsu_8u_with_mask(const Mat1b src, const Mat1b& mask)
{
const int N = 256;
int M = 0;
int i, j, h[N] = { 0 };
for (i = 0; i < src.rows; i++)
{
const uchar* psrc = src.ptr(i);
const uchar* pmask = mask.ptr(i);
for (j = 0; j < src.cols; j++)
{
if (pmask[j])
{
h[psrc[j]]++;
++M;
}
}
}
double mu = 0, scale = 1. / (M);
for (i = 0; i < N; i++)
mu += i * (double)h[i];
mu *= scale;
double mu1 = 0, q1 = 0;
double max_sigma = 0, max_val = 0;
for (i = 0; i < N; i++)
{
double p_i, q2, mu2, sigma;
p_i = h[i] * scale;
mu1 *= q1;
q1 += p_i;
q2 = 1. - q1;
if (std::min(q1, q2) < FLT_EPSILON || std::max(q1, q2) > 1. - FLT_EPSILON)
continue;
mu1 = (mu1 + i * p_i) / q1;
mu2 = (mu - q1 * mu1) / q2;
sigma = q1 * q2*(mu1 - mu2)*(mu1 - mu2);
if (sigma > max_sigma)
{
max_sigma = sigma;
max_val = i;
}
}
return max_val;
}
static PyObject * otsu_with_mask(PyObject *self, PyObject * args) {
PyObject pySrc, pyMask;
Mat src, mask;
import_array();
if (!PyArg_ParseTuple(args, "OO", &pySrc, &pyMask))
return NULL;
pyopencv_to(&pySrc, src, "source");
pyopencv_to(&pyMask, mask, "mask");
double thresh = otsu_8u_with_mask(src, mask);
return Py_BuildValue("i", thresh);
}
static PyMethodDef ThresholdMethods[] = {
{"otsu_with_mask", otsu_with_mask, METH_VARARGS, "Otsu thresholding with mask."},
{ NULL, NULL, 0, NULL}
};
static struct PyModuleDef thresholdModule = {
PyModuleDef_HEAD_INIT,
"customThreshold",
"Thresholding module.",
-1,
ThresholdMethods
};
PyMODINIT_FUNC PyInit_customThreshold(void) {
return PyModule_Create(&thresholdModule);
}
convert.hpp
#ifndef __CONVERT_HPP__
#define __CONVERT_HPP__
#include <Python.h>
#include "opencv2/opencv.hpp"
using namespace cv;
int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>", bool allowND=true);
PyObject* pyopencv_from(const Mat& m);
#endif
Why do you choose to use C++ with Python wrap to do this simple task? I think you could achieve the same result easily using Python only...?
I assume you want to use adaptive thresholding method in OpenCV.
First of all, you can compute the adaptive threshold value of the input gray image. The value can be computed by the following function:
def compute_otsu_value(im_gray):
hist = cv2.calcHist([im_gray], [0], None, [256], [0, 256])
hist_norm = hist.ravel() / hist.max()
cum_sum_mat = hist_norm.cumsum()
fn_min = np.inf
thresh = -1
for i in xrange(1, 256):
p1, p2 = np.hsplit(hist_norm, [i])
q1, q2 = cum_sum_mat[i], cum_sum_mat[255] - cum_sum_mat[i]
if q1 == 0 or q2 == 0:
continue
b1, b2 = np.hsplit(np.arange(256), [i])
m1, m2 = np.sum(p1 * b1) / q1, np.sum(p2 * b2) / q2
v1, v2 = np.sum(((b1-m1)**2)*p1)/q1, np.sum(((b2-m2)**2)*p2)/q2
fn = v1 * q1 + v2 * q2
if fn < fn_min:
fn_min = fn
thresh = i
return thresh
Finally, in the main() function, you can load the input image as a gray image, and get the threshold image accordingly.
im_gray = cv2.imread("input.png", 0)
otsu_value = comput_otsu_values(im_gray)
im_th = cv2.threshold(im_gray, otsu_value, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

How to prevent sys.exit(N) to finish the whole process in embedded python?

I'm using embedded python interpreter in my app (iOS to be detailed).
Sometimes sys.exit(1) is invoked in interpreted script and it finishes the whole app process instead of stopping PyObject_callObject() invocation. I've tried to check errors using PyErr_Occured but it did not help.
How to prevent sys.exit(N) to finish the whole process in embedded python?
NSString *outputFile = nil;
for (int i=0; i<args.count; i++) {
if ([#"-o" isEqualToString:args[i]]) {
outputFile = args[i + 1];
break;
}
}
PyEval_AcquireLock();
PyThreadState *subState = Py_NewInterpreter();
PyObject *pModuleName, *pModule, *pFunc;
// init python
NSString *pythonHome = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:#"/"];
Py_SetProgramName("python");
char *cPythonHome = (char*)[pythonHome UTF8String];
setenv("PYTHONPATH", cPythonHome, 1); // VERY IMPORTANT !!!
Py_SetPythonHome(cPythonHome);
NSString *libsPath = [pythonHome stringByAppendingString:#"lib/python2.7"];
if (!Py_IsInitialized())
Py_Initialize();
// invoke
int result = 0;
NSString *scriptFilename = args[1];
NSString *moduleName = [[scriptFilename lastPathComponent] stringByDeletingPathExtension];
pModuleName = PyString_FromString([moduleName UTF8String]); // module (script) name
pModule = PyImport_Import(pModuleName);
if (PyErr_Occurred())
PyErr_Print();
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, "main__"); // module must have "def main__(args)"
if (pFunc != NULL && PyCallable_Check(pFunc)) {
// prepare args
PyObject *pArgs = PyList_New(args.count-1);
for (int i=0; i<args.count-1; i++) {
NSString *arg_i = args[i + 1]; // skip first argument (it's program name)
PyObject *pEachArg = PyString_FromString([arg_i UTF8String]);
PyList_SetItem(pArgs, i, pEachArg);
// WARNING: don't Py_DECREF for each argument
}
// for some reason arguments should be passed as s Tuple
PyObject *pTuple = PyTuple_New(1);
PyTuple_SetItem(pTuple, 0, pArgs);
// call func
NSLog(#"Invoke %# via main__(args)", scriptFilename);
PyObject *pyResult = PyObject_CallObject(pFunc, pTuple); // process killed here !
if (pyResult == NULL || PyErr_Occurred()) {
// print error
PyErr_Print();
// fix error
PyErr_Clear();
if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
result = 3; // error: system.exit() called
} else
result = 4; // error: unknown exception
}
if (pyResult != NULL)
Py_DECREF(pyResult);
Py_DECREF(pTuple);
Py_DECREF(pArgs);
} else
result = 2; // error: can't find "def main__()" in module
if (pFunc != NULL)
Py_XDECREF(pFunc);
} else
result = 1; // error: can't import module
if (pModule != NULL)
Py_DECREF(pModule);
Py_DECREF(pModuleName);
// restore parent interpreter
Py_EndInterpreter(subState);
PyEval_ReleaseLock();
I had to hack Python sources and create my own function:
int MyPyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, PyCompilerFlags *flags)
{
PyObject *m, *d, *v;
const char *ext;
int set_file_name = 0, ret, len;
m = PyImport_AddModule("__main__");
if (m == NULL)
return -1;
d = PyModule_GetDict(m);
if (PyDict_GetItemString(d, "__file__") == NULL) {
PyObject *f = PyString_FromString(filename);
if (f == NULL)
return -1;
if (PyDict_SetItemString(d, "__file__", f) < 0) {
Py_DECREF(f);
return -1;
}
set_file_name = 1;
Py_DECREF(f);
}
len = strlen(filename);
ext = filename + len - (len > 4 ? 4 : 0);
/*
if (maybe_pyc_file(fp, filename, ext, closeit)) {
// Try to run a pyc file. First, re-open in binary
if (closeit)
fclose(fp);
if ((fp = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "python: Can't reopen .pyc file\n");
ret = -1;
goto done;
}
// Turn on optimization if a .pyo file is given
if (strcmp(ext, ".pyo") == 0)
Py_OptimizeFlag = 1;
v = run_pyc_file(fp, filename, d, d, flags);
} else { */
v = PyRun_FileExFlags(fp, filename, Py_file_input, d, d,
closeit, flags);
//}
if (v == NULL) {
//PyErr_Print(); // crashed here!
ret = -1;
goto done;
}
Py_DECREF(v);
if (Py_FlushLine())
PyErr_Clear();
ret = 0;
done:
if (set_file_name && PyDict_DelItemString(d, "__file__"))
PyErr_Clear();
return ret;
}
I had to use _SimpleFile instead of _SimpleString but i believe you can change _SimpleString in similar way.
The reason was PyErr_Print which caused app crash. The one drawback is that i had to comment pyc file checking and usage as maybe_pyc_file is not exported and is unavailable.
One more note: if SystemExit was raised (by sys.exit(1) f.e.) don't use PyErr_Print. Use the next checking:
if (PyErr_Occurred()) {
pythonSuccess = NO;
if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
NSLog(#"sys.exit() in python");
} else {
// print error
PyErr_Print();
}
// fix error
PyErr_Clear();
}
If you have better solution, let us know.

Parse a string in C and save it to an array of structs

I am quite familiar with Python coding but now I have to do stringparsing in C.
My input:
input = "command1 args1 args2 arg3;command2 args1 args2 args3;cmd3 arg1 arg2 arg3"
My Python solution:
input = "command1 args1 args2 arg3;command2 args1 args2 args3;command3 arg1 arg2 arg3"
compl = input.split(";")
tmplist =[]
tmpdict = {}
for line in compl:
spl = line.split()
tmplist.append(spl)
for l in tmplist:
first, rest = l[0], l[1:]
tmpdict[first] = ' '.join(rest)
print tmpdict
#The Output:
#{'command1': 'args1 args2 arg3', 'command2': 'args1 args2 args3', 'cmd3': 'arg1 arg2 arg3'}
Expected output: Dict with the command as key and the args joined as a string in values
My C solution so far:
I want to save my commands and args in a struct like this:
struct cmdr{
char* command;
char* args[19];
};
I make a struct char* array to save the cmd + args seperated by ";":
struct ari { char* value[200];};
The function:
struct ari inputParser(char* string){
char delimiter[] = ";";
char *ptrsemi;
int i = 0;
struct ari sepcmds;
ptrsemi = strtok(string, delimiter);
while(ptrsemi != NULL) {
sepcmds.value[i] = ptrsemi;
ptrsemi = strtok(NULL, delimiter);
i++;
}
return sepcmds;
Seperate commands and arrays by space and save them in my struct:
First I added a help struct:
struct arraycmd {
struct cmdr lol[10];
};
struct arraycmd parseargs (struct ari z){
struct arraycmd result;
char * pch;
int i;
int j = 0;
for (i=0; i < 200;i++){
j = 0;
if (z.value[i] == NULL){
break;
}
pch = strtok(z.value[i]," ");
while(pch != NULL) {
if (j == 0){
result.lol[i].command = pch;
pch = strtok(NULL, " ");
j++;
} else {
result.lol[i].args[j]= pch;
pch = strtok(NULL, " ");
j++;
}
}
pch = strtok(NULL, " ");
}
return result;
My output function looks like this:
void output(struct arraycmd b){
int i;
int j;
for(i=0; i<200;i++){
if (b.lol[i].command != NULL){
printf("Command %d: %s",i,b.lol[i].command);
}
for (j = 0; j < 200;j++){
if (b.lol[i].args[j] != NULL){
printf(" Arg %d = %s",j,b.lol[i].args[j]);
}
}
printf(" \n");
}
}
But it produces only garbage (Same input as in my python solution) :
(command1 args1 args2 arg3;command2 args1 args2 args3;command3 arg1 arg2 arg3 )
Command 0: command1 Arg 0 = command2 Arg 1 = args1 Arg 2 = args2 Arg 3 = arg3 Arg 19 = command2 Arg 21 = args1 Arg 22 = args2 Arg 23 = args3 Arg 39 = command3 Arg 41 = arg1 Arg 42 = arg2 Arg 43 = arg3
Segmentation fault
So I hope someone can help me to fix this.
check this solution . tested with valgrind no leak .
but i implemented printing inside freeing .u can implement by yourself looking at free function .further u can improve splitter function to achieve better parsing.
#include <stdio.h>
#include <stdlib.h>
typedef struct arr {
char** words;
int count;
} uarr;
#define null 0
typedef struct cmdr {
char* command;
char** argv;
int argc;
} cmd;
typedef struct list {
cmd* listcmd;
int count;
} cmdlist;
uarr splitter(char* str, char delim);
cmdlist* getcommandstruct(char* string);
void freecmdlist(cmdlist* cmdl);
int main(int argc, char** argv) {
char input[] = "command1 arg1 arg2 arg3 arg4;command2 arg1 arg2 ;command3 arg1 arg2 arg3;command4 arg1 arg2 arg3";
cmdlist* cmdl = getcommandstruct((char*) input);
//it will free . also i added print logic inside free u can seperate
freecmdlist(cmdl);
free(cmdl);
return (EXIT_SUCCESS);
}
/**
* THIS FUNCTION U CAN USE FOR GETTING STRUCT
* #param string
* #return
*/
cmdlist* getcommandstruct(char* string) {
cmdlist* cmds = null;
cmd* listcmd = null;
uarr resultx = splitter(string, ';');
//lets allocate
if (resultx.count > 0) {
listcmd = (cmd*) malloc(sizeof (cmd) * resultx.count);
memset(listcmd, 0, sizeof (cmd) * resultx.count);
int i = 0;
for (i = 0; i < resultx.count; i++) {
if (resultx.words[i] != null) {
printf("%s\n", resultx.words[i]);
char* def = resultx.words[i];
uarr defres = splitter(def, ' ');
listcmd[i].argc = defres.count - 1;
listcmd[i].command = defres.words[0];
if (defres.count > 1) {
listcmd[i].argv = (char**) malloc(sizeof (char*) *(defres.count - 1));
int j = 0;
for (; j < defres.count - 1; j++) {
listcmd[i].argv[j] = defres.words[j + 1];
}
}
free(defres.words);
free(def);
}
}
cmds = (cmdlist*) malloc(sizeof (cmdlist));
cmds->count = resultx.count;
cmds->listcmd = listcmd;
}
free(resultx.words);
return cmds;
}
uarr splitter(char* str, char delim) {
char* holder = str;
uarr result = {null, 0};
int count = 0;
while (1) {
if (*holder == delim) {
count++;
}
if (*holder == '\0') {
count++;
break;
};
holder++;
}
if (count > 0) {
char** arr = (char**) malloc(sizeof (char*) *count);
result.words = arr;
result.count = count;
//real split
holder = str;
char* begin = holder;
int index = 0;
while (index < count) {
if (*holder == delim || *holder == '\0') {
int size = holder + 1 - begin;
if (size > 1) {
char* dest = (char*) malloc(size);
memcpy(dest, begin, size);
dest[size - 1] = '\0';
arr[index] = dest;
} else {
arr[index] = null;
}
index++;
begin = holder + 1;
}
holder++;
}
}
return result;
}
void freecmdlist(cmdlist* cmdl) {
if (cmdl != null) {
int i = 0;
for (; i < cmdl->count; i++) {
cmd def = cmdl->listcmd[i];
char* defcommand = def.command;
char** defargv = def.argv;
if (defcommand != null)printf("command=%s\n", defcommand);
free(defcommand);
int j = 0;
for (; j < def.argc; j++) {
char* defa = defargv[j];
if (defa != null)printf("arg[%i] = %s\n", j, defa);
free(defa);
}
free(defargv);
}
free(cmdl->listcmd);
}
}
It may be easier to get your C logic straight in python. This is closer to C, and you can try to transliterate it to C. You can use strncpy instead to extract the strings and copy them to your structures.
str = "command1 args1 args2 arg3;command2 args1 args2 args3;command3 arg1 arg2 arg3\000"
start = 0
state = 'in_command'
structs = []
command = ''
args = []
for i in xrange(len(str)):
ch = str[i]
if ch == ' ' or ch == ';' or ch == '\0':
if state == 'in_command':
command = str[start:i]
elif state == 'in_args':
arg = str[start:i]
args.append(arg)
state = 'in_args'
start = i + 1
if ch == ';' or ch == '\0':
state = 'in_command'
structs.append((command, args))
command = ''
args = []
for s in structs:
print s
Your problem is that you are relying on the pointers in your structures to be initialised to NULL.
They will just be random values, hence the SEGV.
You are also printing 200 commands and 200 arguments when the structure only has 10 commands and 19 arguments.

Categories