Switch to unified view

a/src/python/recoll/pyrecoll.cpp b/src/python/recoll/pyrecoll.cpp
...
...
72
    if (self == 0) 
72
    if (self == 0) 
73
    return 0;
73
    return 0;
74
    return (PyObject *)self;
74
    return (PyObject *)self;
75
}
75
}
76
76
77
PyDoc_STRVAR(doc_SearchDataObject,
78
"SearchData([type=AND|OR], [stemlang=somelanguage|null])\n"
79
"\n"
80
"A SearchData object describes a query. It has a number of global\n"
81
"parameters and a chain of search clauses.\n"
82
);
83
77
static int
84
static int
78
SearchData_init(recoll_SearchDataObject *self, PyObject *args, PyObject *kwargs)
85
SearchData_init(recoll_SearchDataObject *self, PyObject *args, PyObject *kwargs)
79
{
86
{
80
    LOGDEB(("SearchData_init\n"));
87
    LOGDEB(("SearchData_init\n"));
81
    static const char* kwlist[] = {"type", NULL};
88
    static const char* kwlist[] = {"type", "stemlang", NULL};
82
    char *stp = 0;
89
    char *stp = 0;
90
    char *steml = 0;
83
91
84
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", (char**)kwlist, &stp))
92
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|sz", (char**)kwlist, 
93
                   &stp, &steml))
85
    return -1;
94
    return -1;
86
    Rcl::SClType tp = Rcl::SCLT_AND;
95
    Rcl::SClType tp = Rcl::SCLT_AND;
87
96
88
    if (stp && strcasecmp(stp, "or")) {
97
    if (stp && strcasecmp(stp, "or")) {
89
    tp = Rcl::SCLT_OR;
98
    tp = Rcl::SCLT_OR;
90
    }
99
    }
100
    string stemlang;
101
    if (steml) {
102
  stemlang = steml;
103
    } else {
104
  stemlang = "english";
105
    }
91
    self->sd = RefCntr<Rcl::SearchData>(new Rcl::SearchData(tp, "english"));
106
    self->sd = RefCntr<Rcl::SearchData>(new Rcl::SearchData(tp, stemlang));
92
    return 0;
107
    return 0;
93
}
108
}
94
109
95
/* Note: addclause necessite And/Or vient du fait que le string peut avoir
110
/* Note: addclause necessite And/Or vient du fait que le string peut avoir
96
   plusieurs mots. A transferer dans l'i/f Python ou pas ? */
111
   plusieurs mots. A transferer dans l'i/f Python ou pas ? */
97
PyDoc_STRVAR(doc_addclause,
112
PyDoc_STRVAR(doc_addclause,
98
"addclause(type='and'|'or'|'excl'|'phrase'|'near'|'sub',\n"
113
"addclause(type='and'|'or'|'filename'|'phrase'|'near'|'path'|'sub',\n"
99
"          qstring=string, slack=int, field=string, stemming=1|0,\n"
114
"          qstring=string, slack=int, field=string, stemming=1|0,\n"
100
"          subSearch=SearchData)\n"
115
"          subSearch=SearchData, exclude=0|1, anchorstart=0|1, anchorend=0|1,\n"
116
"          casesens=0|1, diacsens=0|1)\n"
101
"Adds a simple clause to the SearchData And/Or chain, or a subquery\n"
117
"Adds a simple clause to the SearchData And/Or chain, or a subquery\n"
102
"defined by another SearchData object\n"
118
"defined by another SearchData object\n"
103
);
119
);
104
120
105
/* Forward declaration only, definition needs recoll_searchDataType */
121
/* Forward declaration only, definition needs recoll_searchDataType */
106
static PyObject *
122
static PyObject *
107
SearchData_addclause(recoll_SearchDataObject* self, PyObject *args, 
123
SearchData_addclause(recoll_SearchDataObject* self, PyObject *args, 
108
             PyObject *kwargs);
124
             PyObject *kwargs);
109
110
111
125
112
static PyMethodDef SearchData_methods[] = {
126
static PyMethodDef SearchData_methods[] = {
113
    {"addclause", (PyCFunction)SearchData_addclause, METH_VARARGS|METH_KEYWORDS,
127
    {"addclause", (PyCFunction)SearchData_addclause, METH_VARARGS|METH_KEYWORDS,
114
     doc_addclause},
128
     doc_addclause},
115
    {NULL}  /* Sentinel */
129
    {NULL}  /* Sentinel */
116
};
130
};
117
131
118
PyDoc_STRVAR(doc_SearchDataObject,
119
"SearchData()\n"
120
"\n"
121
"A SearchData object describes a query. It has a number of global\n"
122
"parameters and a chain of search clauses.\n"
123
);
124
static PyTypeObject recoll_SearchDataType = {
132
static PyTypeObject recoll_SearchDataType = {
125
    PyObject_HEAD_INIT(NULL)
133
    PyObject_HEAD_INIT(NULL)
126
    0,                         /*ob_size*/
134
    0,                         /*ob_size*/
127
    "recoll.SearchData",             /*tp_name*/
135
    "recoll.SearchData",             /*tp_name*/
128
    sizeof(recoll_SearchDataObject), /*tp_basicsize*/
136
    sizeof(recoll_SearchDataObject), /*tp_basicsize*/
...
...
172
    LOGERR(("SearchData_addclause: not init??\n"));
180
    LOGERR(("SearchData_addclause: not init??\n"));
173
        PyErr_SetString(PyExc_AttributeError, "sd");
181
        PyErr_SetString(PyExc_AttributeError, "sd");
174
        return 0;
182
        return 0;
175
    }
183
    }
176
    static const char *kwlist[] = {"type", "qstring", "slack", "field", 
184
    static const char *kwlist[] = {"type", "qstring", "slack", "field", 
177
                                   "stemming", "subsearch", NULL};
185
                                   "stemming", "subsearch", 
186
                 "exclude", "anchorstart", "anchorend",
187
                 "casesens", "diacsens",
188
                 NULL};
178
    char *tp = 0;
189
    char *tp = 0;
179
    char *qs = 0; // needs freeing
190
    char *qs = 0; // needs freeing
180
    int slack = 0;
191
    int slack = 0;
181
    char *fld = 0; // needs freeing
192
    char *fld = 0; // needs freeing
182
    int  dostem = 1;
193
    PyObject  *dostem = 0;
183
    recoll_SearchDataObject *sub = 0;
194
    recoll_SearchDataObject *sub = 0;
195
    PyObject *exclude = 0;
196
    PyObject *anchorstart = 0;
197
    PyObject *anchorend = 0;
198
    PyObject *casesens = 0;
199
    PyObject *diacsens = 0;
184
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ses|iesiO!", (char**)kwlist,
200
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ses|iesOO!OOOOO", 
201
                   (char**)kwlist,
185
                     &tp, "utf-8", &qs, &slack,
202
                     &tp, "utf-8", &qs, &slack,
186
                     "utf-8", &fld, &dostem,
203
                     "utf-8", &fld, &dostem,
187
                     &recoll_SearchDataType, &sub))
204
                     &recoll_SearchDataType, &sub,
205
                   &exclude, &anchorstart, &anchorend,
206
                   &casesens, &diacsens
207
      ))
188
    return 0;
208
    return 0;
189
209
190
    Rcl::SearchDataClause *cl = 0;
210
    Rcl::SearchDataClause *cl = 0;
191
211
192
    switch (tp[0]) {
212
    switch (tp[0]) {
...
...
194
    case 'A':
214
    case 'A':
195
    if (strcasecmp(tp, "and"))
215
    if (strcasecmp(tp, "and"))
196
        goto defaultcase;
216
        goto defaultcase;
197
    cl = new Rcl::SearchDataClauseSimple(Rcl::SCLT_AND, qs, fld?fld:"");
217
    cl = new Rcl::SearchDataClauseSimple(Rcl::SCLT_AND, qs, fld?fld:"");
198
    break;
218
    break;
219
    case 'f':
220
    case 'F':
221
  if (strcasecmp(tp, "filename"))
222
      goto defaultcase;
223
  cl = new Rcl::SearchDataClauseFilename(qs);
224
  break;
199
    case 'o':
225
    case 'o':
200
    case 'O':
226
    case 'O':
201
    if (strcasecmp(tp, "or"))
227
    if (strcasecmp(tp, "or"))
202
        goto defaultcase;
228
        goto defaultcase;
203
    cl = new Rcl::SearchDataClauseSimple(Rcl::SCLT_OR, qs, fld?fld:"");
229
    cl = new Rcl::SearchDataClauseSimple(Rcl::SCLT_OR, qs, fld?fld:"");
204
  break;
205
    case 'e':
206
    case 'E':
207
  if (strcasecmp(tp, "excl"))
208
      goto defaultcase;
209
  cl = new Rcl::SearchDataClauseSimple(Rcl::SCLT_OR, qs, fld?fld:"");
210
  cl->setexclude(true);
211
    break;
230
    break;
212
    case 'n':
231
    case 'n':
213
    case 'N':
232
    case 'N':
214
    if (strcasecmp(tp, "near"))
233
    if (strcasecmp(tp, "near"))
215
        goto defaultcase;
234
        goto defaultcase;
216
    cl = new Rcl::SearchDataClauseDist(Rcl::SCLT_NEAR, qs, slack, 
235
    cl = new Rcl::SearchDataClauseDist(Rcl::SCLT_NEAR, qs, slack, 
217
                       fld ? fld : "");
236
                       fld ? fld : "");
218
    break;
237
    break;
219
    case 'p':
238
    case 'p':
220
    case 'P':
239
    case 'P':
221
    if (strcasecmp(tp, "phrase"))
240
    if (!strcasecmp(tp, "phrase")) {
241
      cl = new Rcl::SearchDataClauseDist(Rcl::SCLT_PHRASE, qs, slack, 
242
                         fld ? fld : "");
243
  } else if (!strcasecmp(tp, "path")) {
244
      cl = new Rcl::SearchDataClausePath(qs);
245
  } else {
222
        goto defaultcase;
246
        goto defaultcase;
223
  cl = new Rcl::SearchDataClauseDist(Rcl::SCLT_PHRASE, qs, slack, 
247
  }
224
                     fld ? fld : "");
225
    break;
248
    break;
226
    case 's':
249
    case 's':
227
    case 'S':
250
    case 'S':
228
    if (strcasecmp(tp, "sub"))
251
    if (strcasecmp(tp, "sub"))
229
        goto defaultcase;
252
        goto defaultcase;
...
...
232
    defaultcase:
255
    defaultcase:
233
    default:
256
    default:
234
        PyErr_SetString(PyExc_AttributeError, "Bad tp arg");
257
        PyErr_SetString(PyExc_AttributeError, "Bad tp arg");
235
    return 0;
258
    return 0;
236
    }
259
    }
237
    if (dostem == 0) {
238
  cl->setModifiers(Rcl::SearchDataClause::SDCM_NOSTEMMING);
239
    }
240
241
    PyMem_Free(qs);
260
    PyMem_Free(qs);
242
    PyMem_Free(fld);
261
    PyMem_Free(fld);
262
263
    if (dostem != 0 && !PyObject_IsTrue(dostem)) {
264
  cl->addModifier(Rcl::SearchDataClause::SDCM_NOSTEMMING);
265
    }
266
    if (exclude != 0 && !PyObject_IsTrue(exclude)) {
267
  cl->setexclude(true);
268
    }
269
    if (anchorstart && PyObject_IsTrue(anchorstart)) {
270
  cl->addModifier(Rcl::SearchDataClause::SDCM_ANCHORSTART);
271
    }
272
    if (anchorend && PyObject_IsTrue(anchorend)) {
273
  cl->addModifier(Rcl::SearchDataClause::SDCM_ANCHOREND);
274
    }
275
    if (casesens && PyObject_IsTrue(casesens)) {
276
  cl->addModifier(Rcl::SearchDataClause::SDCM_CASESENS);
277
    }
278
    if (diacsens && PyObject_IsTrue(diacsens)) {
279
  cl->addModifier(Rcl::SearchDataClause::SDCM_DIACSENS);
280
    }
243
    self->sd->addClause(cl);
281
    self->sd->addClause(cl);
244
    Py_RETURN_NONE;
282
    Py_RETURN_NONE;
245
}
283
}
246
284
247
285
...
...
1424
}
1462
}
1425
1463
1426
static PyObject *
1464
static PyObject *
1427
Db_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1465
Db_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1428
{
1466
{
1429
    LOGDEB(("Db_new\n"));
1430
    recoll_DbObject *self;
1467
    recoll_DbObject *self;
1431
1468
1432
    self = (recoll_DbObject *)type->tp_alloc(type, 0);
1469
    self = (recoll_DbObject *)type->tp_alloc(type, 0);
1433
    if (self == 0) 
1470
    if (self == 0) 
1434
    return 0;
1471
    return 0;
...
...
1437
}
1474
}
1438
1475
1439
static int
1476
static int
1440
Db_init(recoll_DbObject *self, PyObject *args, PyObject *kwargs)
1477
Db_init(recoll_DbObject *self, PyObject *args, PyObject *kwargs)
1441
{
1478
{
1442
    LOGDEB(("Db_init\n"));
1443
    static const char *kwlist[] = {"confdir", "extra_dbs", "writable", NULL};
1479
    static const char *kwlist[] = {"confdir", "extra_dbs", "writable", NULL};
1444
    PyObject *extradbs = 0;
1480
    PyObject *extradbs = 0;
1445
    char *confdir = 0;
1481
    char *confdir = 0;
1446
    int writable = 0;
1482
    int writable = 0;
1447
1483
...
...
1457
    string cfd = confdir;
1493
    string cfd = confdir;
1458
    rclconfig = recollinit(0, 0, reason, &cfd);
1494
    rclconfig = recollinit(0, 0, reason, &cfd);
1459
    } else {
1495
    } else {
1460
    rclconfig = recollinit(0, 0, reason, 0);
1496
    rclconfig = recollinit(0, 0, reason, 0);
1461
    }
1497
    }
1498
    LOGDEB(("Db_init\n"));
1499
1462
    if (rclconfig == 0) {
1500
    if (rclconfig == 0) {
1463
    PyErr_SetString(PyExc_EnvironmentError, reason.c_str());
1501
    PyErr_SetString(PyExc_EnvironmentError, reason.c_str());
1464
    return -1;
1502
    return -1;
1465
    }
1503
    }
1466
    if (!rclconfig->ok()) {
1504
    if (!rclconfig->ok()) {
...
...
1784
//////////////////////////////////////////////////////////////////////////
1822
//////////////////////////////////////////////////////////////////////////
1785
// Module methods
1823
// Module methods
1786
static PyObject *
1824
static PyObject *
1787
recoll_connect(PyObject *self, PyObject *args, PyObject *kwargs)
1825
recoll_connect(PyObject *self, PyObject *args, PyObject *kwargs)
1788
{
1826
{
1789
    LOGDEB(("recoll_connect\n"));
1790
    recoll_DbObject *db = (recoll_DbObject *)
1827
    recoll_DbObject *db = (recoll_DbObject *)
1791
    PyObject_Call((PyObject *)&recoll_DbType, args, kwargs);
1828
    PyObject_Call((PyObject *)&recoll_DbType, args, kwargs);
1792
    return (PyObject *)db;
1829
    return (PyObject *)db;
1793
}
1830
}
1794
1831
...
...
1818
#define PyMODINIT_FUNC void
1855
#define PyMODINIT_FUNC void
1819
#endif
1856
#endif
1820
PyMODINIT_FUNC
1857
PyMODINIT_FUNC
1821
initrecoll(void)
1858
initrecoll(void)
1822
{
1859
{
1823
    string reason;
1860
    // Note: we can't call recollinit here, because the confdir is only really
1824
    rclconfig = recollinit(0, 0, reason, 0);
1861
    // known when the first db object is created (it is an optional parameter).
1825
    if (rclconfig == 0) {
1862
    // Using a default here may end up with variables such as stripchars being
1826
  PyErr_SetString(PyExc_EnvironmentError, reason.c_str());
1863
    // wrong
1827
  return;
1828
    }
1829
    if (!rclconfig->ok()) {
1830
  PyErr_SetString(PyExc_EnvironmentError, 
1831
          "Recoll init error: bad environment ?");
1832
  return;
1833
    }
1834
1864
1835
    PyObject* m;
1865
    PyObject* m;
1836
    m = Py_InitModule3("recoll", recollMethods,
1866
    m = Py_InitModule3("recoll", recollMethods, "Recoll extension module.");
1837
                       "Recoll extension module.");
1838
    
1867
    
1839
    if (PyType_Ready(&recoll_DbType) < 0)
1868
    if (PyType_Ready(&recoll_DbType) < 0)
1840
        return;
1869
        return;
1841
    Py_INCREF((PyObject*)&recoll_DbType);
1870
    Py_INCREF((PyObject*)&recoll_DbType);
1842
    PyModule_AddObject(m, "Db", (PyObject *)&recoll_DbType);
1871
    PyModule_AddObject(m, "Db", (PyObject *)&recoll_DbType);