]> sigrok.org Git - libsigrokdecode.git/blob - tests/runtc.c
runtc: Add list of missed lines to coverage output.
[libsigrokdecode.git] / tests / runtc.c
1 /*
2  * This file is part of the libsigrokdecode project.
3  *
4  * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "../libsigrokdecode.h"
21 #include <libsigrok/libsigrok.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <time.h>
31 #include <sys/time.h>
32 #include <sys/resource.h>
33 #include <dirent.h>
34 #include <glib.h>
35 #ifdef __LINUX__
36 #include <sched.h>
37 #endif
38 #include "../config.h"
39
40 int debug = FALSE;
41 int statistics = FALSE;
42 char *coverage_report;
43
44 struct probe {
45         char *name;
46         int probe;
47 };
48
49 struct option {
50         char *key;
51         char *value;
52 };
53
54 struct pd {
55         char *name;
56         GSList *probes;
57         GSList *options;
58 };
59
60 struct output {
61         char *pd;
62         int type;
63         char *class;
64         int class_idx;
65         char *outfile;
66         int outfd;
67 };
68
69 struct cvg {
70         int num_lines;
71         int num_missed;
72         float coverage;
73         GSList *missed_lines;
74 };
75
76
77 struct cvg *get_mod_cov(PyObject *py_cov, char *module_name);
78 void cvg_add(struct cvg *dst, struct cvg *src);
79 struct cvg *cvg_new(void);
80 gboolean find_missed_line(struct cvg *cvg, char *linespec);
81
82
83 static void logmsg(char *prefix, FILE *out, const char *format, va_list args)
84 {
85         if (prefix)
86                 fprintf(out, "%s", prefix);
87         vfprintf(out, format, args);
88         fprintf(out, "\n");
89 }
90
91 static void DBG(const char *format, ...)
92 {
93         va_list args;
94
95         if (!debug)
96                 return;
97         va_start(args, format);
98         logmsg("DBG: runtc: ", stdout, format, args);
99         va_end(args);
100 }
101
102 static void ERR(const char *format, ...)
103 {
104         va_list args;
105
106         va_start(args, format);
107         logmsg("Error: ", stderr, format, args);
108         va_end(args);
109 }
110
111 static int sr_log(void *cb_data, int loglevel, const char *format, va_list args)
112 {
113         (void)cb_data;
114
115         if (loglevel == SR_LOG_ERR || loglevel == SR_LOG_WARN)
116                 logmsg("Error: sr: ", stderr, format, args);
117         else if (debug)
118                 logmsg("DBG: sr: ", stdout, format, args);
119
120         return SRD_OK;
121 }
122
123 static int srd_log(void *cb_data, int loglevel, const char *format, va_list args)
124 {
125         (void)cb_data;
126
127         if (loglevel == SRD_LOG_ERR || loglevel == SRD_LOG_WARN)
128                 logmsg("Error: srd: ", stderr, format, args);
129         else if (debug)
130                 logmsg("DBG: srd: ", stdout, format, args);
131
132         return SRD_OK;
133 }
134
135 static void usage(char *msg)
136 {
137         if (msg)
138                 fprintf(stderr, "%s\n", msg);
139
140         printf("Usage: runtc [-dPpoiOf]\n");
141         printf("  -d  Debug\n");
142         printf("  -P  <protocol decoder>\n");
143         printf("  -p  <probename=probenum> (optional)\n");
144         printf("  -o  <probeoption=value> (optional)\n");
145         printf("  -i <input file>\n");
146         printf("  -O <output-pd:output-type[:output-class]>\n");
147         printf("  -f <output file> (optional)\n");
148         printf("  -c <coverage report> (optional)\n");
149         exit(msg ? 1 : 0);
150
151 }
152
153 /* This is a neutered version of libsigrokdecode's py_str_as_str(). It
154  * does no error checking, but then the only strings it processes are
155  * generated by Python's repr(), so are known good. */
156 static char *py_str_as_str(const PyObject *py_str)
157 {
158         PyObject *py_encstr;
159         char *str, *outstr;
160
161         py_encstr = PyUnicode_AsEncodedString((PyObject *)py_str, "utf-8", NULL);
162         str = PyBytes_AS_STRING(py_encstr);
163         outstr = g_strdup(str);
164         Py_DecRef(py_encstr);
165
166         return outstr;
167 }
168
169 static void srd_cb_py(struct srd_proto_data *pdata, void *cb_data)
170 {
171         struct output *op;
172         PyObject *pydata, *pyrepr;
173         GString *out;
174         char *s;
175
176         DBG("Python output from %s", pdata->pdo->di->inst_id);
177         op = cb_data;
178         pydata = pdata->data;
179         DBG("ptr %p", pydata);
180
181         if (strcmp(pdata->pdo->di->inst_id, op->pd))
182                 /* This is not the PD selected for output. */
183                 return;
184
185         if (!(pyrepr = PyObject_Repr(pydata))) {
186                 ERR("Invalid Python object.");
187                 return;
188         }
189         s = py_str_as_str(pyrepr);
190         Py_DecRef(pyrepr);
191
192         /* Output format for testing is '<ss>-<es> <inst-id>: <repr>\n' */
193         out = g_string_sized_new(128);
194         g_string_printf(out, "%"PRIu64"-%"PRIu64" %s: %s\n",
195                         pdata->start_sample, pdata->end_sample,
196                         pdata->pdo->di->inst_id, s);
197         g_free(s);
198         if (write(op->outfd, out->str, out->len) == -1)
199                 ERR("SRD_OUTPUT_PYTHON callback write failure!");
200         DBG("wrote '%s'", out->str);
201         g_string_free(out, TRUE);
202
203 }
204
205 static void srd_cb_bin(struct srd_proto_data *pdata, void *cb_data)
206 {
207         struct srd_proto_data_binary *pdb;
208         struct output *op;
209         GString *out;
210         unsigned int i;
211
212         DBG("Binary output from %s", pdata->pdo->di->inst_id);
213         op = cb_data;
214         pdb = pdata->data;
215
216         if (strcmp(pdata->pdo->di->inst_id, op->pd))
217                 /* This is not the PD selected for output. */
218                 return;
219
220         if (op->class_idx != -1 && op->class_idx != pdb->bin_class)
221                 /*
222                  * This output takes a specific binary class,
223                  * but not the one that just came in.
224                  */
225                 return;
226
227         out = g_string_sized_new(128);
228         g_string_printf(out, "%"PRIu64"-%"PRIu64" %s:",
229                         pdata->start_sample, pdata->end_sample,
230                         pdata->pdo->di->inst_id);
231         for (i = 0; i < pdb->size; i++) {
232                 g_string_append_printf(out, " %.2x", pdb->data[i]);
233         }
234         g_string_append(out, "\n");
235         if (write(op->outfd, out->str, out->len) == -1)
236                 ERR("SRD_OUTPUT_BINARY callback write failure!");
237
238 }
239
240 static void srd_cb_ann(struct srd_proto_data *pdata, void *cb_data)
241 {
242         struct srd_decoder *dec;
243         struct srd_proto_data_annotation *pda;
244         struct output *op;
245         GString *line;
246         int i;
247         char **dec_ann;
248
249         DBG("Annotation output from %s", pdata->pdo->di->inst_id);
250         op = cb_data;
251         pda = pdata->data;
252         dec = pdata->pdo->di->decoder;
253         if (strcmp(pdata->pdo->di->inst_id, op->pd))
254                 /* This is not the PD selected for output. */
255                 return;
256
257         if (op->class_idx != -1 && op->class_idx != pda->ann_format)
258                 /*
259                  * This output takes a specific annotation class,
260                  * but not the one that just came in.
261                  */
262                 return;
263
264         dec_ann = g_slist_nth_data(dec->annotations, pda->ann_format);
265         line = g_string_sized_new(256);
266         g_string_printf(line, "%"PRIu64"-%"PRIu64" %s: %s:",
267                         pdata->start_sample, pdata->end_sample,
268                         pdata->pdo->di->inst_id, dec_ann[0]);
269         for (i = 0; pda->ann_text[i]; i++)
270                 g_string_append_printf(line, " \"%s\"", pda->ann_text[i]);
271         g_string_append(line, "\n");
272         if (write(op->outfd, line->str, line->len) == -1)
273                 ERR("SRD_OUTPUT_ANN callback write failure!");
274         g_string_free(line, TRUE);
275
276 }
277
278 static void sr_cb(const struct sr_dev_inst *sdi,
279                 const struct sr_datafeed_packet *packet, void *cb_data)
280 {
281         const struct sr_datafeed_logic *logic;
282         struct srd_session *sess;
283         GVariant *gvar;
284         uint64_t samplerate;
285         int num_samples;
286         static int samplecnt = 0;
287
288         sess = cb_data;
289
290         switch (packet->type) {
291         case SR_DF_HEADER:
292                 DBG("Received SR_DF_HEADER");
293                 if (sr_config_get(sdi->driver, sdi, NULL, SR_CONF_SAMPLERATE,
294                                 &gvar) != SR_OK) {
295                         ERR("Getting samplerate failed");
296                         break;
297                 }
298                 samplerate = g_variant_get_uint64(gvar);
299                 g_variant_unref(gvar);
300                 if (srd_session_metadata_set(sess, SRD_CONF_SAMPLERATE,
301                                 g_variant_new_uint64(samplerate)) != SRD_OK) {
302                         ERR("Setting samplerate failed");
303                         break;
304                 }
305                 if (srd_session_start(sess) != SRD_OK) {
306                         ERR("Session start failed");
307                         break;
308                 }
309                 break;
310         case SR_DF_LOGIC:
311                 logic = packet->payload;
312                 num_samples = logic->length / logic->unitsize;
313                 DBG("Received SR_DF_LOGIC: %d samples", num_samples);
314                 srd_session_send(sess, samplecnt, samplecnt + num_samples,
315                                 logic->data, logic->length);
316                 samplecnt += logic->length / logic->unitsize;
317                 break;
318         case SR_DF_END:
319                 DBG("Received SR_DF_END");
320                 break;
321         }
322
323 }
324
325 static int run_testcase(char *infile, GSList *pdlist, struct output *op)
326 {
327         struct srd_session *sess;
328         struct srd_decoder *dec;
329         struct srd_decoder_inst *di, *prev_di;
330         srd_pd_output_callback_t cb;
331         struct pd *pd;
332         struct probe *probe;
333         struct option *option;
334         GVariant *gvar;
335         GHashTable *probes, *opts;
336         GSList *pdl, *l;
337         int idx;
338         int max_probe;
339         char **decoder_class;
340
341         if (op->outfile) {
342                 if ((op->outfd = open(op->outfile, O_CREAT|O_WRONLY, 0600)) == -1) {
343                         ERR("Unable to open %s for writing: %s", op->outfile,
344                                         strerror(errno));
345                         return FALSE;
346                 }
347         }
348
349         if (sr_session_load(infile) != SR_OK)
350                 return FALSE;
351
352         if (srd_session_new(&sess) != SRD_OK)
353                 return FALSE;
354         sr_session_datafeed_callback_add(sr_cb, sess);
355         switch (op->type) {
356         case SRD_OUTPUT_ANN:
357                 cb = srd_cb_ann;
358                 break;
359         case SRD_OUTPUT_BINARY:
360                 cb = srd_cb_bin;
361                 break;
362         case SRD_OUTPUT_PYTHON:
363                 cb = srd_cb_py;
364                 break;
365         default:
366                 return FALSE;
367         }
368         srd_pd_output_callback_add(sess, op->type, cb, op);
369
370         prev_di = NULL;
371         pd = NULL;
372         for (pdl = pdlist; pdl; pdl = pdl->next) {
373                 pd = pdl->data;
374                 if (srd_decoder_load(pd->name) != SRD_OK)
375                         return FALSE;
376
377                 /* Instantiate decoder and pass in options. */
378                 opts = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
379                                 (GDestroyNotify)g_variant_unref);
380                 for (l = pd->options; l; l = l->next) {
381                         option = l->data;
382                         g_hash_table_insert(opts, option->key, option->value);
383                 }
384                 if (!(di = srd_inst_new(sess, pd->name, opts)))
385                         return FALSE;
386                 g_hash_table_destroy(opts);
387
388                 /* Map probes. */
389                 if (pd->probes) {
390                         probes = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
391                                         (GDestroyNotify)g_variant_unref);
392                         max_probe = 0;
393                         for (l = pd->probes; l; l = l->next) {
394                                 probe = l->data;
395                                 if (probe->probe > max_probe)
396                                         max_probe = probe->probe;
397                                 gvar = g_variant_new_int32(probe->probe);
398                                 g_variant_ref_sink(gvar);
399                                 g_hash_table_insert(probes, probe->name, gvar);
400                         }
401                         if (srd_inst_probe_set_all(di, probes,
402                                         (max_probe + 8) / 8) != SRD_OK)
403                                 return FALSE;
404                         g_hash_table_destroy(probes);
405                 }
406
407                 /* If this is not the first decoder in the list, stack it
408                  * on top of the previous one. */
409                 if (prev_di) {
410                         if (srd_inst_stack(sess, prev_di, di) != SRD_OK) {
411                                 ERR("Failed to stack decoder instances.");
412                                 return FALSE;
413                         }
414                 }
415                 prev_di = di;
416         }
417
418         /* Resolve top decoder's class index, so we can match. */
419         dec = srd_decoder_get_by_id(pd->name);
420         if (op->class) {
421                 if (op->type == SRD_OUTPUT_ANN)
422                         l = dec->annotations;
423                 else if (op->type == SRD_OUTPUT_BINARY)
424                         l = dec->binary;
425                 else
426                         /* Only annotations and binary can have a class. */
427                         return FALSE;
428                 idx = 0;
429                 while (l) {
430                         decoder_class = l->data;
431                         if (!strcmp(decoder_class[0], op->class)) {
432                                 op->class_idx = idx;
433                                 break;
434                         } else
435                                 idx++;
436                         l = l->next;
437                 }
438                 if (op->class_idx == -1) {
439                         ERR("Output class '%s' not found in decoder %s.",
440                                         op->class, pd->name);
441                         return FALSE;
442                 } else
443                         DBG("Class %s index is %d", op->class, op->class_idx);
444         }
445
446         sr_session_start();
447         sr_session_run();
448         sr_session_stop();
449
450         srd_session_destroy(sess);
451
452         if (op->outfile)
453                 close(op->outfd);
454
455         return TRUE;
456 }
457
458 static PyObject *start_coverage(GSList *pdlist)
459 {
460         PyObject *py_mod, *py_pdlist, *py_pd, *py_func, *py_args, *py_kwargs, *py_cov;
461         GSList *l;
462         struct pd *pd;
463
464         DBG("Starting coverage.");
465
466         if (!(py_mod = PyImport_ImportModule("coverage")))
467                 return NULL;
468
469         if (!(py_pdlist = PyList_New(0)))
470                 return NULL;
471         for (l = pdlist; l; l = l->next) {
472                 pd = l->data;
473                 py_pd = PyUnicode_FromFormat("*/%s/*.py", pd->name);
474                 if (PyList_Append(py_pdlist, py_pd) < 0)
475                         return NULL;
476                 Py_DecRef(py_pd);
477         }
478         if (!(py_func = PyObject_GetAttrString(py_mod, "coverage")))
479                 return NULL;
480         if (!(py_args = PyTuple_New(0)))
481                 return NULL;
482         if (!(py_kwargs = Py_BuildValue("{sO}", "include", py_pdlist)))
483                 return NULL;
484         if (!(py_cov = PyObject_Call(py_func, py_args, py_kwargs)))
485                 return NULL;
486         if (!(PyObject_CallMethod(py_cov, "start", NULL)))
487                 return NULL;
488         Py_DecRef(py_pdlist);
489         Py_DecRef(py_args);
490         Py_DecRef(py_kwargs);
491         Py_DecRef(py_func);
492
493         return py_cov;
494 }
495
496 struct cvg *get_mod_cov(PyObject *py_cov, char *module_name)
497 {
498         PyObject *py_mod, *py_pathlist, *py_path, *py_func, *py_pd;
499         PyObject *py_result, *py_missed, *py_item;
500         DIR *d;
501         struct dirent *de;
502         struct cvg *cvg_mod;
503         int num_lines, num_missed, linenum, i, j;
504         char *path, *linespec;
505
506         if (!(py_mod = PyImport_ImportModule(module_name)))
507                 return NULL;
508
509         cvg_mod = NULL;
510         py_pathlist = PyObject_GetAttrString(py_mod, "__path__");
511         for (i = 0; i < PyList_Size(py_pathlist); i++) {
512                 py_path = PyList_GetItem(py_pathlist, i);
513         PyUnicode_FSConverter(PyList_GetItem(py_pathlist, i), &py_path);
514                 path = PyBytes_AS_STRING(py_path);
515                 if (!(d = opendir(path))) {
516                         ERR("Invalid module path '%s'", path);
517                         return NULL;
518                 }
519                 while ((de = readdir(d))) {
520                         if (strncmp(de->d_name + strlen(de->d_name) - 3, ".py", 3))
521                                 continue;
522
523                         if (!(py_func = PyObject_GetAttrString(py_cov, "analysis2")))
524                                 return NULL;
525                         if (!(py_pd = PyUnicode_FromFormat("%s/%s", path, de->d_name)))
526                                 return NULL;
527                         if (!(py_result = PyObject_CallFunction(py_func, "O", py_pd)))
528                                 return NULL;
529                         Py_DecRef(py_pd);
530                         Py_DecRef(py_func);
531
532                         if (!cvg_mod)
533                                 cvg_mod = cvg_new();
534                         if (PyTuple_Size(py_result) != 5) {
535                                 ERR("Invalid result from coverage of '%s/%s'", path, de->d_name);
536                                 return NULL;
537                         }
538                         num_lines = PyList_Size(PyTuple_GetItem(py_result, 1));
539                         py_missed = PyTuple_GetItem(py_result, 3);
540                         num_missed = PyList_Size(py_missed);
541                         cvg_mod->num_lines += num_lines;
542                         cvg_mod->num_missed += num_missed;
543                         for (j = 0; j < num_missed; j++) {
544                                 py_item = PyList_GetItem(py_missed, j);
545                                 linenum = PyLong_AsLong(py_item);
546                                 linespec = g_strdup_printf("%s/%s:%d", module_name,
547                                                 de->d_name, linenum);
548                                 cvg_mod->missed_lines = g_slist_append(cvg_mod->missed_lines, linespec);
549                         }
550                         DBG("Coverage for %s/%s: %d lines, %d missed.",
551                                         module_name, de->d_name, num_lines, num_missed);
552                         Py_DecRef(py_result);
553                 }
554         }
555         if (cvg_mod->num_lines)
556                 cvg_mod->coverage = 100 - ((float)cvg_mod->num_missed / (float)cvg_mod->num_lines * 100);
557
558         Py_DecRef(py_mod);
559     Py_DecRef(py_path);
560
561         return cvg_mod;
562 }
563
564 struct cvg *cvg_new(void)
565 {
566         struct cvg *cvg;
567
568         cvg = calloc(1, sizeof(struct cvg));
569
570         return cvg;
571 }
572
573 gboolean find_missed_line(struct cvg *cvg, char *linespec)
574 {
575         GSList *l;
576
577         for (l = cvg->missed_lines; l; l = l->next)
578                 if (!strcmp(l->data, linespec))
579                         return TRUE;
580
581         return FALSE;
582 }
583
584 void cvg_add(struct cvg *dst, struct cvg *src)
585 {
586         GSList *l;
587         char *linespec;
588
589
590         dst->num_lines += src->num_lines;
591         dst->num_missed += src->num_missed;
592         for (l = src->missed_lines; l; l = l->next) {
593                 linespec = l->data;
594                 if (!find_missed_line(dst, linespec))
595                         dst->missed_lines = g_slist_append(dst->missed_lines, linespec);
596         }
597
598 }
599
600 static int report_coverage(PyObject *py_cov, GSList *pdlist)
601 {
602         PyObject *py_func, *py_mod, *py_args, *py_kwargs, *py_outfile, *py_pct;
603         GSList *l, *ml;
604         struct pd *pd;
605         struct cvg *cvg_mod, *cvg_all;
606         float total_coverage;
607         int lines, missed, cnt;
608
609         DBG("Making coverage report.");
610
611         /* Get coverage for each module in the stack. */
612         lines = missed = 0;
613         cvg_all = cvg_new();
614         for (cnt = 0, l = pdlist; l; l = l->next, cnt++) {
615                 pd = l->data;
616                 if (!(cvg_mod = get_mod_cov(py_cov, pd->name)))
617                         return FALSE;
618                 printf("coverage: scope=%s coverage=%.0f%% lines=%d missed=%d "
619                                 "missed_lines=", pd->name, cvg_mod->coverage,
620                                 cvg_mod->num_lines, cvg_mod->num_missed);
621                 for (ml = cvg_mod->missed_lines; ml; ml = ml->next) {
622                         if (ml != cvg_mod->missed_lines)
623                                 printf(",");
624                         printf("%s", (char *)ml->data);
625                 }
626                 printf("\n");
627                 lines += cvg_mod->num_lines;
628                 missed += cvg_mod->num_missed;
629                 cvg_add(cvg_all, cvg_mod);
630                 DBG("Coverage for module %s: %d lines, %d missed", pd->name,
631                                 cvg_mod->num_lines, cvg_mod->num_missed);
632         }
633         lines /= cnt;
634         missed /= cnt;
635         total_coverage = 100 - ((float)missed / (float)lines * 100);
636
637         /* Machine-readable stats on stdout. */
638         printf("coverage: scope=all coverage=%.0f%% lines=%d missed=%d\n",
639                         total_coverage, cvg_all->num_lines, cvg_all->num_missed);
640
641
642         /* Write text report to file. */
643         /* io.open(coverage_report, "w") */
644         if (!(py_mod = PyImport_ImportModule("io")))
645                 return FALSE;
646         if (!(py_func = PyObject_GetAttrString(py_mod, "open")))
647                 return FALSE;
648         if (!(py_args = PyTuple_New(0)))
649                 return FALSE;
650         if (!(py_kwargs = Py_BuildValue("{ssss}", "file", coverage_report,
651                         "mode", "w")))
652                 return FALSE;
653         if (!(py_outfile = PyObject_Call(py_func, py_args, py_kwargs)))
654                 return FALSE;
655         Py_DecRef(py_kwargs);
656         Py_DecRef(py_func);
657
658         /* py_cov.report(file=py_outfile) */
659         if (!(py_func = PyObject_GetAttrString(py_cov, "report")))
660                 return FALSE;
661         if (!(py_kwargs = Py_BuildValue("{sO}", "file", py_outfile)))
662                 return FALSE;
663         if (!(py_pct = PyObject_Call(py_func, py_args, py_kwargs)))
664                 return FALSE;
665         Py_DecRef(py_pct);
666         Py_DecRef(py_kwargs);
667         Py_DecRef(py_func);
668
669         /* py_outfile.close() */
670         if (!(py_func = PyObject_GetAttrString(py_outfile, "close")))
671                 return FALSE;
672         if (!PyObject_Call(py_func, py_args, NULL))
673                 return FALSE;
674         Py_DecRef(py_outfile);
675         Py_DecRef(py_func);
676         Py_DecRef(py_args);
677         Py_DecRef(py_mod);
678
679         return TRUE;
680 }
681
682 int main(int argc, char **argv)
683 {
684         struct sr_context *ctx;
685         PyObject *coverage;
686         GSList *pdlist;
687         struct pd *pd;
688         struct probe *probe;
689         struct option *option;
690         struct output *op;
691         int ret;
692         char c, *opt_infile, **kv, **opstr;
693
694         op = malloc(sizeof(struct output));
695         op->pd = NULL;
696         op->type = -1;
697         op->class = NULL;
698         op->class_idx = -1;
699         op->outfd = 1;
700
701         pdlist = NULL;
702         opt_infile = NULL;
703         pd = NULL;
704         coverage = NULL;
705         while ((c = getopt(argc, argv, "dP:p:o:i:O:f:c:S")) != -1) {
706                 switch(c) {
707                 case 'd':
708                         debug = TRUE;
709                         break;
710                 case 'P':
711                         pd = g_malloc(sizeof(struct pd));
712                         pd->name = g_strdup(optarg);
713                         pd->probes = pd->options = NULL;
714                         pdlist = g_slist_append(pdlist, pd);
715                         break;
716                 case 'p':
717                 case 'o':
718                         if (g_slist_length(pdlist) == 0) {
719                                 /* No previous -P. */
720                                 ERR("Syntax error at '%s'", optarg);
721                                 usage(NULL);
722                         }
723                         kv = g_strsplit(optarg, "=", 0);
724                         if (!kv[0] || (!kv[1] || kv[2])) {
725                                 /* Need x=y. */
726                                 ERR("Syntax error at '%s'", optarg);
727                                 g_strfreev(kv);
728                                 usage(NULL);
729                         }
730                         if (c == 'p') {
731                                 probe = malloc(sizeof(struct probe));
732                                 probe->name = g_strdup(kv[0]);
733                                 probe->probe = strtoul(kv[1], 0, 10);
734                                 /* Apply to last PD. */
735                                 pd->probes = g_slist_append(pd->probes, probe);
736                         } else {
737                                 option = malloc(sizeof(struct option));
738                                 option->key = g_strdup(kv[0]);
739                                 option->value = g_strdup(kv[1]);
740                                 /* Apply to last PD. */
741                                 pd->options = g_slist_append(pd->options, option);
742                         }
743                         break;
744                 case 'i':
745                         opt_infile = optarg;
746                         break;
747                 case 'O':
748                         opstr = g_strsplit(optarg, ":", 0);
749                         if (!opstr[0] || !opstr[1]) {
750                                 /* Need at least abc:def. */
751                                 ERR("Syntax error at '%s'", optarg);
752                                 g_strfreev(opstr);
753                                 usage(NULL);
754                         }
755                         op->pd = g_strdup(opstr[0]);
756                         if (!strcmp(opstr[1], "annotation"))
757                                 op->type = SRD_OUTPUT_ANN;
758                         else if (!strcmp(opstr[1], "binary"))
759                                 op->type = SRD_OUTPUT_BINARY;
760                         else if (!strcmp(opstr[1], "python"))
761                                 op->type = SRD_OUTPUT_PYTHON;
762                         else {
763                                 ERR("Unknown output type '%s'", opstr[1]);
764                                 g_strfreev(opstr);
765                                 usage(NULL);
766                         }
767                         if (opstr[2])
768                                 op->class = g_strdup(opstr[2]);
769                         g_strfreev(opstr);
770                         break;
771                 case 'f':
772                         op->outfile = g_strdup(optarg);
773                         op->outfd = -1;
774                         break;
775                 case 'c':
776                         coverage_report = optarg;
777                         break;
778                 case 'S':
779                         statistics = TRUE;
780                         break;
781                 default:
782                         usage(NULL);
783                 }
784         }
785         if (argc > optind)
786                 usage(NULL);
787         if (g_slist_length(pdlist) == 0)
788                 usage(NULL);
789         if (!opt_infile)
790                 usage(NULL);
791         if (!op->pd || op->type == -1)
792                 usage(NULL);
793
794         sr_log_callback_set(sr_log, NULL);
795         if (sr_init(&ctx) != SR_OK)
796                 return 1;
797
798         srd_log_callback_set(srd_log, NULL);
799         if (srd_init(DECODERS_DIR) != SRD_OK)
800                 return 1;
801
802         if (coverage_report) {
803                 if (!(coverage = start_coverage(pdlist))) {
804                         DBG("Failed to start coverage.");
805                         if (PyErr_Occurred()) {
806                                 PyErr_PrintEx(0);
807                                 PyErr_Clear();
808                         }
809                 }
810         }
811
812         ret = 0;
813         if (!run_testcase(opt_infile, pdlist, op))
814                 ret = 1;
815
816         if (coverage) {
817                 DBG("Stopping coverage.");
818
819                 if (!(PyObject_CallMethod(coverage, "stop", NULL)))
820                         ERR("Failed to stop coverage.");
821                 else if (!(report_coverage(coverage, pdlist)))
822                         ERR("Failed to make coverage report.");
823                 else
824                         DBG("Coverage report in %s", coverage_report);
825
826                 if (PyErr_Occurred()) {
827                         PyErr_PrintEx(0);
828                         PyErr_Clear();
829                 }
830                 Py_DecRef(coverage);
831         }
832
833         srd_exit();
834         sr_exit(ctx);
835
836         return ret;
837 }