]> sigrok.org Git - libsigrok.git/blob - input/csv.c
Initial Comma-separated values (CSV) input support.
[libsigrok.git] / input / csv.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2013 Marc Schink <sigrok-dev@marcschink.de>
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 <stdlib.h>
21 #include <string.h>
22 #include <glib.h>
23 #include "libsigrok.h"
24 #include "libsigrok-internal.h"
25
26 /* Message logging helpers with subsystem-specific prefix string. */
27 #define LOG_PREFIX "input/csv: "
28 #define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
29 #define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
30 #define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
31 #define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
32 #define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
33 #define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
34
35 /*
36  * The CSV input module has the following options:
37  *
38  * single-column: Specifies the column number which stores the sample data for
39  *                single column mode and enables single column mode. Multi
40  *                column mode is used if this parameter is omitted.
41  *
42  * numprobes:     Specifies the number of probes to use. In multi column mode
43  *                the number of probes are the number of columns and in single
44  *                column mode the number of bits (LSB first) beginning at
45  *                'first-probe'.
46  *
47  * delimiter:     Specifies the delimiter for columns. Must be at least one
48  *                character. Comma is used as default delimiter.
49  *
50  * format:        Specifies the format of the sample data in single column mode.
51  *                Available formats are: 'bin', 'hex' and 'oct'. The binary
52  *                format is used by default. This option has no effect in multi
53  *                column mode.
54  *
55  * comment:       Specifies the prefix character(s) for comments. No prefix
56  *                characters are used by default which disables removing of
57  *                comments.
58  *
59  * samplerate:    Samplerate which the sample data was captured with. Default
60  *                value is 0.
61  *
62  * first-probe:   Column number of the first probe in multi column mode and
63  *                position of the bit for the first probe in single column mode.
64  *                Default value is 0.
65  *
66  * header:        Determines if the first line should be treated as header
67  *                and used for probe names in multi column mode. Empty header
68  *                names will be replaced by the probe number. If enabled in
69  *                single column mode the first line will be skipped. Usage of
70  *                header is disabled by default.
71  *
72  * startline:     Line number to start processing sample data. Must be greater
73  *                than 0. The default line number to start processing is 1.
74  */
75
76 /* Single column formats. */
77 enum {
78         FORMAT_BIN,
79         FORMAT_HEX,
80         FORMAT_OCT
81 };
82
83 struct context {
84         /* Current selected samplerate. */
85         uint64_t samplerate;
86
87         /* Number of probes. */
88         gsize num_probes;
89
90         /* Column delimiter character(s). */
91         GString *delimiter;
92
93         /* Comment prefix character(s). */
94         GString *comment;
95
96         /* Determines if sample data is stored in multiple columns. */
97         gboolean multi_column_mode;
98
99         /* Column number of the sample data in single column mode. */
100         gsize single_column;
101
102         /*
103          * Number of the first column to parse. Equivalent to the number of the
104          * first probe in multi column mode and the single column number in
105          * single column mode.
106          */
107         gsize first_column;
108
109         /*
110          * Column number of the first probe in multi column mode and position of
111          * the bit for the first probe in single column mode.
112          */
113         gsize first_probe;
114
115         /* Line number to start processing. */
116         gsize start_line;
117
118         /*
119          * Determines if the first line should be treated as header and used for
120          * probe names in multi column mode.
121          */
122         gboolean header;
123
124         /* Format sample data is stored in single column mode. */
125         int format;
126
127         /* Size of the sample buffer. */
128         gsize sample_buffer_size;
129
130         /* Buffer to store sample data. */
131         uint8_t *sample_buffer;
132
133         GIOChannel *channel;
134
135         /* Buffer for the current line. */
136         GString *buffer;
137
138         /* Current line number. */
139         gsize line_number;
140 };
141
142 static int format_match(const char *filename)
143 {
144         if (!filename) {
145                 sr_err("%s: filename was NULL.", __func__);
146                 return FALSE;
147         }
148
149         if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
150                 sr_err("Input file '%s' does not exist.", filename);
151                 return FALSE;
152         }
153
154         if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
155                 sr_err("Input file '%s' not a regular file.", filename);
156                 return FALSE;
157         }
158
159         return TRUE;
160 }
161
162 static void free_context(struct context *ctx)
163 {
164         if (!ctx)
165                 return;
166
167         if (ctx->delimiter)
168                 g_string_free(ctx->delimiter, TRUE);
169
170         if (ctx->comment)
171                 g_string_free(ctx->comment, TRUE);
172
173         if (ctx->channel) {
174                 g_io_channel_shutdown(ctx->channel, FALSE, NULL);
175                 g_io_channel_unref(ctx->channel);
176         }
177
178         if (ctx->sample_buffer)
179                 g_free(ctx->sample_buffer);
180
181         if (ctx->buffer)
182                 g_string_free(ctx->buffer, TRUE);
183
184         g_free(ctx);
185 }
186
187 static void strip_comment(GString *string, const GString *prefix)
188 {
189         char *ptr;
190
191         if (!prefix->len)
192                 return;
193
194         if (!(ptr = strstr(string->str, prefix->str)))
195                 return;
196
197         g_string_truncate(string, ptr - string->str);
198 }
199
200 static int parse_binstr(const char *str, struct context *ctx)
201 {
202         gsize i, j, length;
203
204         length = strlen(str);
205
206         if (!length) {
207                 sr_err("Column %zu in line %zu is empty.", ctx->single_column,
208                         ctx->line_number);
209                 return SR_ERR;
210         }
211
212         /* Clear buffer in order to set bits only. */
213         memset(ctx->sample_buffer, 0, (ctx->num_probes + 7) >> 3);
214
215         i = ctx->first_probe;
216
217         for (j = 0; i < length && j < ctx->num_probes; i++, j++) {
218                 if (str[length - i - 1] == '1') {
219                         ctx->sample_buffer[j / 8] |= (1 << (j % 8));
220                 } else if (str[length - i - 1] != '0') {
221                         sr_err("Invalid value '%s' in column %zu in line %zu.",
222                                 str, ctx->single_column, ctx->line_number);
223                         return SR_ERR;
224                 }
225         }
226
227         return SR_OK;
228 }
229
230 static int parse_hexstr(const char *str, struct context *ctx)
231 {
232         gsize i, j, k, length;
233         uint8_t value;
234         char c;
235
236         length = strlen(str);
237
238         if (!length) {
239                 sr_err("Column %zu in line %zu is empty.", ctx->single_column,
240                         ctx->line_number);
241                 return SR_ERR;
242         }
243
244         /* Clear buffer in order to set bits only. */
245         memset(ctx->sample_buffer, 0, (ctx->num_probes + 7) >> 3);
246
247         /* Calculate the position of the first hexadecimal digit. */
248         i = ctx->first_probe / 4;
249
250         for (j = 0; i < length && j < ctx->num_probes; i++) {
251                 c = str[length - i - 1];
252
253                 if (!g_ascii_isxdigit(c)) {
254                         sr_err("Invalid value '%s' in column %zu in line %zu.",
255                                 str, ctx->single_column, ctx->line_number);
256                         return SR_ERR;
257                 }
258
259                 value = g_ascii_xdigit_value(c);
260
261                 k = (ctx->first_probe + j) % 4;
262
263                 for (; j < ctx->num_probes && k < 4; k++) {
264                         if (value & (1 << k))
265                                 ctx->sample_buffer[j / 8] |= (1 << (j % 8));
266
267                         j++;
268                 }
269         }
270
271         return SR_OK;
272 }
273
274 static int parse_octstr(const char *str, struct context *ctx)
275 {
276         gsize i, j, k, length;
277         uint8_t value;
278         char c;
279
280         length = strlen(str);
281
282         if (!length) {
283                 sr_err("Column %zu in line %zu is empty.", ctx->single_column,
284                         ctx->line_number);
285                 return SR_ERR;
286         }
287
288         /* Clear buffer in order to set bits only. */
289         memset(ctx->sample_buffer, 0, (ctx->num_probes + 7) >> 3);
290
291         /* Calculate the position of the first octal digit. */
292         i = ctx->first_probe / 3;
293
294         for (j = 0; i < length && j < ctx->num_probes; i++) {
295                 c = str[length - i - 1];
296
297                 if (c < '0' || c > '7') {
298                         sr_err("Invalid value '%s' in column %zu in line %zu.",
299                                 str, ctx->single_column, ctx->line_number);
300                         return SR_ERR;
301                 }
302
303                 value = g_ascii_xdigit_value(c);
304
305                 k = (ctx->first_probe + j) % 3;
306
307                 for (; j < ctx->num_probes && k < 3; k++) {
308                         if (value & (1 << k))
309                                 ctx->sample_buffer[j / 8] |= (1 << (j % 8));
310
311                         j++;
312                 }
313         }
314
315         return SR_OK;
316 }
317
318 static char **parse_line(const struct context *ctx, int max_columns)
319 {
320         const char *str, *remainder;
321         GSList *list, *l;
322         char **columns;
323         char *column;
324         gsize n, k;
325
326         n = 0;
327         k = 0;
328         list = NULL;
329
330         remainder = ctx->buffer->str;
331         str = strstr(remainder, ctx->delimiter->str);
332
333         while (str && max_columns) {
334                 if (n >= ctx->first_column) {
335                         column = g_strndup(remainder, str - remainder);
336                         list = g_slist_prepend(list, g_strstrip(column));
337
338                         max_columns--;
339                         k++;
340                 }
341
342                 remainder = str + ctx->delimiter->len;
343                 str = strstr(remainder, ctx->delimiter->str);
344                 n++;
345         }
346
347         if (ctx->buffer->len && max_columns && n >= ctx->first_column) {
348                 column = g_strdup(remainder);
349                 list = g_slist_prepend(list, g_strstrip(column));
350                 k++;
351         }
352
353         if (!(columns = g_try_new(char *, k + 1)))
354                 return NULL;
355
356         columns[k--] = NULL;
357
358         for (l = list; l; l = l->next)
359                 columns[k--] = l->data;
360
361         g_slist_free(list);
362
363         return columns;
364 }
365
366 static int parse_multi_columns(char **columns, struct context *ctx)
367 {
368         gsize i;
369
370         /* Clear buffer in order to set bits only. */
371         memset(ctx->sample_buffer, 0, (ctx->num_probes + 7) >> 3);
372
373         for (i = 0; i < ctx->num_probes; i++) {
374                 if (columns[i][0] == '1') {
375                         ctx->sample_buffer[i / 8] |= (1 << (i % 8));
376                 } else if (!strlen(columns[i])) {
377                         sr_err("Column %zu in line %zu is empty.",
378                                 ctx->first_probe + i, ctx->line_number);
379                         return SR_ERR;
380                 } else if (columns[i][0] != '0') {
381                         sr_err("Invalid value '%s' in column %zu in line %zu.",
382                                 columns[i], ctx->first_probe + i,
383                                 ctx->line_number);
384                         return SR_ERR;
385                 }
386         }
387
388         return SR_OK;
389 }
390
391 static int parse_single_column(const char *column, struct context *ctx)
392 {
393         int res;
394
395         res = SR_ERR;
396
397         switch(ctx->format) {
398         case FORMAT_BIN:
399                 res = parse_binstr(column, ctx);
400                 break;
401         case FORMAT_HEX:
402                 res = parse_hexstr(column, ctx);
403                 break;
404         case FORMAT_OCT:
405                 res = parse_octstr(column, ctx);
406                 break;
407         }
408
409         return res;
410 }
411
412 static int send_samples(const struct sr_dev_inst *sdi, uint8_t *buffer,
413                         gsize buffer_size, gsize count)
414 {
415         int res;
416         struct sr_datafeed_packet packet;
417         struct sr_datafeed_logic logic;
418         gsize i;
419
420         packet.type = SR_DF_LOGIC;
421         packet.payload = &logic;
422         logic.unitsize = buffer_size;
423         logic.length = buffer_size;
424         logic.data = buffer;
425
426         for (i = 0; i < count; i++) {
427                 if ((res = sr_session_send(sdi, &packet)) != SR_OK)
428                         return res;
429         }
430
431         return SR_OK;
432 }
433
434 static int init(struct sr_input *in, const char *filename)
435 {
436         int res;
437         struct context *ctx;
438         const char *param;
439         GIOStatus status;
440         gsize i, term_pos;
441         char probe_name[SR_MAX_PROBENAME_LEN + 1];
442         struct sr_probe *probe;
443         char **columns;
444         gsize num_columns;
445         char *ptr;
446
447         if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
448                 sr_err("Context malloc failed.");
449                 return SR_ERR_MALLOC;
450         }
451
452         /* Create a virtual device. */
453         in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
454         in->internal = ctx;
455
456         /* Set default samplerate. */
457         ctx->samplerate = 0;
458
459         /*
460          * Enable auto-detection of the number of probes in multi column mode
461          * and enforce the specification of the number of probes in single
462          * column mode.
463          */
464         ctx->num_probes = 0;
465
466         /* Set default delimiter. */
467         if (!(ctx->delimiter = g_string_new(","))) {
468                 sr_err("Delimiter malloc failed.");
469                 free_context(ctx);
470                 return SR_ERR_MALLOC;
471         }
472
473         /*
474          * Set default comment prefix. Note that an empty comment prefix
475          * disables removing of comments.
476          */
477         if (!(ctx->comment = g_string_new(""))) {
478                 sr_err("Comment malloc failed.");
479                 free_context(ctx);
480                 return SR_ERR_MALLOC;
481         }
482
483         /* Enable multi column mode by default. */
484         ctx->multi_column_mode = TRUE;
485
486         /* Use first column as default single column number. */
487         ctx->single_column = 0;
488
489         /*
490          * In multi column mode start parsing sample data at the first column
491          * and in single column mode at the first bit.
492          */
493         ctx->first_probe = 0;
494
495         /* Start at the beginning of the file. */
496         ctx->start_line = 1;
497
498         /* Disable the usage of the first line as header by default. */
499         ctx->header = FALSE;
500
501         /* Set default format for single column mode. */
502         ctx->format = FORMAT_BIN;
503
504         if (!(ctx->buffer = g_string_new(""))) {
505                 sr_err("Line buffer malloc failed.");
506                 free_context(ctx);
507                 return SR_ERR_MALLOC;
508         }
509
510         if (in->param) {
511                 if ((param = g_hash_table_lookup(in->param, "samplerate"))) {
512                         res = sr_parse_sizestring(param, &ctx->samplerate);
513
514                         if (res != SR_OK) {
515                                 sr_err("Invalid samplerate: %s.", param);
516                                 free_context(ctx);
517                                 return SR_ERR_ARG;
518                         }
519                 }
520
521                 if ((param = g_hash_table_lookup(in->param, "numprobes")))
522                         ctx->num_probes = g_ascii_strtoull(param, NULL, 10);
523
524                 if ((param = g_hash_table_lookup(in->param, "delimiter"))) {
525                         if (!strlen(param)) {
526                                 sr_err("Delimiter must be at least one character.");
527                                 free_context(ctx);
528                                 return SR_ERR_ARG;
529                         }
530
531                         if (!g_ascii_strcasecmp(param, "\\t"))
532                                 g_string_assign(ctx->delimiter, "\t");
533                         else
534                                 g_string_assign(ctx->delimiter, param);
535                 }
536
537                 if ((param = g_hash_table_lookup(in->param, "comment")))
538                         g_string_assign(ctx->comment, param);
539
540                 if ((param = g_hash_table_lookup(in->param, "single-column"))) {
541                         ctx->single_column = g_ascii_strtoull(param, &ptr, 10);
542                         ctx->multi_column_mode = FALSE;
543
544                         if (param == ptr) {
545                                 sr_err("Invalid single-colum number: %s.",
546                                         param);
547                                 free_context(ctx);
548                                 return SR_ERR_ARG;
549                         }
550                 }
551
552                 if ((param = g_hash_table_lookup(in->param, "first-probe")))
553                         ctx->first_probe = g_ascii_strtoull(param, NULL, 10);
554
555                 if ((param = g_hash_table_lookup(in->param, "startline"))) {
556                         ctx->start_line = g_ascii_strtoull(param, NULL, 10);
557
558                         if (ctx->start_line < 1) {
559                                 sr_err("Invalid start line: %s.", param);
560                                 free_context(ctx);
561                                 return SR_ERR_ARG;
562                         }
563                 }
564
565                 if ((param = g_hash_table_lookup(in->param, "header")))
566                         ctx->header = sr_parse_boolstring(param);
567
568                 if ((param = g_hash_table_lookup(in->param, "format"))) {
569                         if (!g_ascii_strncasecmp(param, "bin", 3)) {
570                                 ctx->format = FORMAT_BIN;
571                         } else if (!g_ascii_strncasecmp(param, "hex", 3)) {
572                                 ctx->format = FORMAT_HEX;
573                         } else if (!g_ascii_strncasecmp(param, "oct", 3)) {
574                                 ctx->format = FORMAT_OCT;
575                         } else {
576                                 sr_err("Invalid format: %s.", param);
577                                 free_context(ctx);
578                                 return SR_ERR;
579                         }
580                 }
581         }
582
583         if (ctx->multi_column_mode)
584                 ctx->first_column = ctx->first_probe;
585         else
586                 ctx->first_column = ctx->single_column;
587
588         if (!ctx->multi_column_mode && !ctx->num_probes) {
589                 sr_err("Number of probes needs to be specified in single column mode.");
590                 free_context(ctx);
591                 return SR_ERR;
592         }
593
594         if (!(ctx->channel = g_io_channel_new_file(filename, "r", NULL))) {
595                 sr_err("Input file '%s' could not be opened.", filename);
596                 free_context(ctx);
597                 return SR_ERR;
598         }
599
600         while (TRUE) {
601                 ctx->line_number++;
602                 status = g_io_channel_read_line_string(ctx->channel,
603                         ctx->buffer, &term_pos, NULL);
604
605                 if (status == G_IO_STATUS_EOF) {
606                         sr_err("Input file is empty.");
607                         free_context(ctx);
608                         return SR_ERR;
609                 }
610
611                 if (status != G_IO_STATUS_NORMAL) {
612                         sr_err("Error while reading line %zu.",
613                                 ctx->line_number);
614                         free_context(ctx);
615                         return SR_ERR;
616                 }
617
618                 if (ctx->start_line > ctx->line_number) {
619                         sr_spew("Line %zu skipped.", ctx->line_number);
620                         continue;
621                 }
622
623                 /* Remove line termination character(s). */
624                 g_string_truncate(ctx->buffer, term_pos);
625
626                 if (!ctx->buffer->len) {
627                         sr_spew("Blank line %zu skipped.", ctx->line_number);
628                         continue;
629                 }
630
631                 /* Remove trailing comment. */
632                 strip_comment(ctx->buffer, ctx->comment);
633
634                 if (ctx->buffer->len)
635                         break;
636
637                 sr_spew("Comment-only line %zu skipped.", ctx->line_number);
638         }
639
640         /*
641          * In order to determine the number of columns parse the current line
642          * without limiting the number of columns.
643          */
644         if (!(columns = parse_line(ctx, -1))) {
645                 sr_err("Error while parsing line %zu.", ctx->line_number);
646                 free_context(ctx);
647                 return SR_ERR;
648         }
649
650         num_columns = g_strv_length(columns);
651
652         /* Ensure that the first column is not out of bounds. */
653         if (!num_columns) {
654                 sr_err("Column %zu in line %zu is out of bounds.",
655                         ctx->first_column, ctx->line_number);
656                 g_strfreev(columns);
657                 free_context(ctx);
658                 return SR_ERR;
659         }
660
661         if (ctx->multi_column_mode) {
662                 /*
663                  * Detect the number of probes in multi column mode
664                  * automatically if not specified.
665                  */
666                 if (!ctx->num_probes) {
667                         ctx->num_probes = num_columns;
668                         sr_info("Number of auto-detected probes: %zu.",
669                                 ctx->num_probes);
670                 }
671
672                 /*
673                  * Ensure that the number of probes does not exceed the number
674                  * of columns in multi column mode.
675                  */
676                 if (num_columns < ctx->num_probes) {
677                         sr_err("Not enough columns for desired number of probes in line %zu.",
678                                 ctx->line_number);
679                         g_strfreev(columns);
680                         free_context(ctx);
681                         return SR_ERR;
682                 }
683         }
684
685         for (i = 0; i < ctx->num_probes; i++) {
686                 if (ctx->header && ctx->multi_column_mode && strlen(columns[i]))
687                         snprintf(probe_name, sizeof(probe_name), "%s",
688                                 columns[i]);
689                 else
690                         snprintf(probe_name, sizeof(probe_name), "%zu", i);
691
692                 probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE, probe_name);
693
694                 if (!probe) {
695                         sr_err("Probe creation failed.");
696                         free_context(ctx);
697                         g_strfreev(columns);
698                         return SR_ERR;
699                 }
700
701                 in->sdi->probes = g_slist_append(in->sdi->probes, probe);
702         }
703
704         g_strfreev(columns);
705
706         /*
707          * Calculate the minimum buffer size to store the sample data of the
708          * probes.
709          */
710         ctx->sample_buffer_size = (ctx->num_probes + 7) >> 3;
711
712         if (!(ctx->sample_buffer = g_try_malloc(ctx->sample_buffer_size))) {
713                 sr_err("Sample buffer malloc failed.");
714                 free_context(ctx);
715                 return SR_ERR_MALLOC;
716         }
717
718         return SR_OK;
719 }
720
721 static int loadfile(struct sr_input *in, const char *filename)
722 {
723         int res;
724         struct context *ctx;
725         struct sr_datafeed_packet packet;
726         struct sr_datafeed_meta meta;
727         struct sr_config *cfg;
728         GIOStatus status;
729         gboolean read_new_line;
730         gsize term_pos;
731         char **columns;
732         gsize num_columns;
733         int max_columns;
734
735         (void)filename;
736
737         ctx = in->internal;
738
739         /* Send header packet to the session bus. */
740         std_session_send_df_header(in->sdi, LOG_PREFIX);
741
742         if (ctx->samplerate) {
743                 packet.type = SR_DF_META;
744                 packet.payload = &meta;
745                 cfg = sr_config_new(SR_CONF_SAMPLERATE,
746                         g_variant_new_uint64(ctx->samplerate));
747                 meta.config = g_slist_append(NULL, cfg);
748                 sr_session_send(in->sdi, &packet);
749                 sr_config_free(cfg);
750         }
751
752         read_new_line = FALSE;
753
754         /* Limit the number of columns to parse. */
755         if (ctx->multi_column_mode)
756                 max_columns = ctx->num_probes;
757         else
758                 max_columns = 1;
759
760         while (TRUE) {
761                 /*
762                  * Skip reading a new line for the first time if the last read
763                  * line was not a header because the sample data is not parsed
764                  * yet.
765                  */
766                 if (read_new_line || ctx->header) {
767                         ctx->line_number++;
768                         status = g_io_channel_read_line_string(ctx->channel,
769                                 ctx->buffer, &term_pos, NULL);
770
771                         if (status == G_IO_STATUS_EOF)
772                                 break;
773
774                         if (status != G_IO_STATUS_NORMAL) {
775                                 sr_err("Error while reading line %zu.",
776                                         ctx->line_number);
777                                 free_context(ctx);
778                                 return SR_ERR;
779                         }
780
781                         /* Remove line termination character(s). */
782                         g_string_truncate(ctx->buffer, term_pos);
783                 }
784
785                 read_new_line = TRUE;
786
787                 if (!ctx->buffer->len) {
788                         sr_spew("Blank line %zu skipped.", ctx->line_number);
789                         continue;
790                 }
791
792                 /* Remove trailing comment. */
793                 strip_comment(ctx->buffer, ctx->comment);
794
795                 if (!ctx->buffer->len) {
796                         sr_spew("Comment-only line %zu skipped.",
797                                 ctx->line_number);
798                         continue;
799                 }
800
801                 if (!(columns = parse_line(ctx, max_columns))) {
802                         sr_err("Error while parsing line %zu.",
803                                 ctx->line_number);
804                         free_context(ctx);
805                         return SR_ERR;
806                 }
807
808                 num_columns = g_strv_length(columns);
809
810                 /* Ensure that the first column is not out of bounds. */
811                 if (!num_columns) {
812                         sr_err("Column %zu in line %zu is out of bounds.",
813                                 ctx->first_column, ctx->line_number);
814                         g_strfreev(columns);
815                         free_context(ctx);
816                         return SR_ERR;
817                 }
818
819                 /*
820                  * Ensure that the number of probes does not exceed the number
821                  * of columns in multi column mode.
822                  */
823                 if (ctx->multi_column_mode && num_columns < ctx->num_probes) {
824                         sr_err("Not enough columns for desired number of probes in line %zu.",
825                                 ctx->line_number);
826                         g_strfreev(columns);
827                         free_context(ctx);
828                         return SR_ERR;
829                 }
830
831                 if (ctx->multi_column_mode)
832                         res = parse_multi_columns(columns, ctx);
833                 else
834                         res = parse_single_column(columns[0], ctx);
835
836                 if (res != SR_OK) {
837                         g_strfreev(columns);
838                         free_context(ctx);
839                         return SR_ERR;
840                 }
841
842                 g_strfreev(columns);
843
844                 /*
845                  * TODO: Parse sample numbers / timestamps and use it for
846                  * decompression.
847                  */
848
849                 /* Send sample data to the session bus. */
850                 res = send_samples(in->sdi, ctx->sample_buffer,
851                         ctx->sample_buffer_size, 1);
852
853                 if (res != SR_OK) {
854                         sr_err("Sending samples failed.");
855                         free_context(ctx);
856                         return SR_ERR;
857                 }
858         }
859
860         /* Send end packet to the session bus. */
861         packet.type = SR_DF_END;
862         sr_session_send(in->sdi, &packet);
863
864         free_context(ctx);
865
866         return SR_OK;
867 }
868
869 SR_PRIV struct sr_input_format input_csv = {
870         .id = "csv",
871         .description = "Comma-separated values (CSV)",
872         .format_match = format_match,
873         .init = init,
874         .loadfile = loadfile,
875 };