]> sigrok.org Git - libsigrok.git/blob - src/input/csv.c
input/csv: rework user accessible options for consistency
[libsigrok.git] / src / 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  * Copyright (C) 2019 Gerhard Sittig <gerhard.sittig@gmx.net>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "config.h"
22
23 #include <glib.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <libsigrok/libsigrok.h>
28 #include "libsigrok-internal.h"
29 #include "scpi.h"       /* String un-quote for channel name from header line. */
30
31 #define LOG_PREFIX "input/csv"
32
33 #define CHUNK_SIZE      (4 * 1024 * 1024)
34
35 /*
36  * The CSV input module has the following options:
37  *
38  * column_formats: Specifies the data formats and channel counts for the
39  *     input file's text columns. Accepts a comma separated list of tuples
40  *     with: an optional column repeat count ('*' as a wildcard meaning
41  *     "all remaining columns", only applicable to the last field), a format
42  *     specifying character ('x' hexadecimal, 'o' octal, 'b' binary, 'l'
43  *     single-bit logic), and an optional bit count (translating to: logic
44  *     channels communicated in that column). This "column_formats" option
45  *     is most versatile, other forms of specifying the column layout only
46  *     exist for backwards compatibility.
47  *
48  * single_column: Specifies the column number which contains the logic data
49  *     for single-column mode. All logic data is taken from several bits
50  *     which all are kept within that one column. Only exists for backwards
51  *     compatibility, see "column_formats" for more flexibility.
52  *
53  * first_column: Specifies the number of the first column with logic data
54  *     in simple multi-column mode. Only exists for backwards compatibility,
55  *     see "column_formats" for more flexibility.
56  *
57  * logic_channels: Specifies the number of logic channels. Is required in
58  *     simple single-column mode. Is optional in simple multi-column mode
59  *     (and defaults to all remaining columns). Only exists for backwards
60  *     compatibility, see "column_formats" for more flexibility.
61  *
62  * single_format: Specifies the format of the input text in simple single-
63  *     column mode. Available formats are: 'bin' (default), 'hex' and 'oct'.
64  *     Simple multi-column mode always uses single-bit data per column.
65  *     Only exists for backwards compatibility, see "column_formats" for
66  *     more flexibility.
67  *
68  * start_line: Specifies at which line to start processing the input file.
69  *     Allows to skip leading lines which neither are header nor data lines.
70  *     By default all of the input file gets processed.
71  *
72  * header: Boolean option, controls whether the first processed line is used
73  *     to determine channel names. Off by default. Generic channel names are
74  *     used in the absence of header line content.
75  *
76  * samplerate: Specifies the samplerate of the input data. Defaults to 0.
77  *     User specs take precedence over data which optionally gets derived
78  *     from input data.
79  *
80  * column_separator: Specifies the sequence which separates the text file
81  *     columns. Cannot be empty. Defaults to comma.
82  *
83  * comment_leader: Specifies the sequence which starts comments that run
84  *     up to the end of the current text line. Can be empty to disable
85  *     comment support. Defaults to semicolon.
86  *
87  * Typical examples of using these options:
88  * - ... -I csv:column_formats=*l ...
89  *   All columns are single-bit logic data. Identical to the previous
90  *   multi-column mode (the default when no options were given at all).
91  * - ... -I csv:column_formats=3-,*l ...
92  *   Ignore the first three columns, get single-bit logic data from all
93  *   remaining lines (multi-column mode with first-column above 1).
94  * - ... -I csv:column_formats=3-,4l,x8 ...
95  *   Ignore the first three columns, get single-bit logic data from the
96  *   next four columns, then eight-bit data in hex format from the next
97  *   column. More columns may follow in the input text but won't get
98  *   processed. (Mix of previous multi-column as well as single-column
99  *   modes.)
100  * - ... -I csv:column_formats=4x8,b16,5l ...
101  *   Get eight-bit data in hex format from the first four columns, then
102  *   sixteen-bit data in binary format, then five times single-bit data.
103  * - ... -I csv:single_column=2:single_format=bin:logic_channels=8 ...
104  *   Get eight logic bits in binary format from column 2. (Simple
105  *   single-column mode, corresponds to the "-,b8" format.)
106  * - ... -I csv:first_column=6:logic_channels=4 ...
107  *   Get four single-bit logic channels from columns 6 to 9 respectively.
108  *   (Simple multi-column mode, corresponds to the "5-,4b" format.)
109  * - ... -I csv:start_line=20:header=yes:...
110  *   Skip the first 19 text lines. Use line 20 to derive channel names.
111  *   Data starts at line 21.
112  */
113
114 /*
115  * TODO
116  *
117  * - Determine how the text line handling can get improved, regarding
118  *   all of robustness and flexibility and correctness.
119  *   - The current implementation splits on "any run of CR and LF". Which
120  *     translates to: Line numbers are wrong in the presence of empty
121  *     lines in the input stream. See below for an (expensive) fix.
122  *   - Dropping support for CR style end-of-line markers could improve
123  *     the situation a lot. Code could search for and split on LF, and
124  *     trim optional trailing CR. This would result in proper support
125  *     for CRLF (Windows) as well as LF (Unix), and allow for correct
126  *     line number counts.
127  *   - When support for CR-only line termination cannot get dropped,
128  *     then the current implementation is inappropriate. Currently the
129  *     input stream is scanned for the first occurance of either of the
130  *     supported termination styles (which is good). For the remaining
131  *     session a consistent encoding of the text lines is assumed (which
132  *     is acceptable).
133  *   - When line numbers need to be correct and reliable, _and_ the full
134  *     set of previously supported line termination sequences are required,
135  *     and potentially more are to get added for improved compatibility
136  *     with more platforms or generators, then the current approach of
137  *     splitting on runs of termination characters needs to get replaced,
138  *     by the more expensive approach to scan for and count the initially
139  *     determined termination sequence.
140  *
141  * - Add support for analog input data? (optional)
142  *   - Needs a syntax first for user specs which channels (columns) are
143  *     logic and which are analog. May need heuristics(?) to guess from
144  *     input data in the absence of user provided specs.
145  */
146
147 /* Single column formats. */
148 enum single_col_format {
149         FORMAT_NONE,    /* Ignore this column. */
150         FORMAT_BIN,     /* Bin digits for a set of bits (or just one bit). */
151         FORMAT_HEX,     /* Hex digits for a set of bits. */
152         FORMAT_OCT,     /* Oct digits for a set of bits. */
153 };
154
155 static const char *col_format_text[] = {
156         [FORMAT_NONE] = "unknown",
157         [FORMAT_BIN] = "binary",
158         [FORMAT_HEX] = "hexadecimal",
159         [FORMAT_OCT] = "octal",
160 };
161
162 static const char col_format_char[] = {
163         [FORMAT_NONE] = '?',
164         [FORMAT_BIN] = 'b',
165         [FORMAT_HEX] = 'x',
166         [FORMAT_OCT] = 'o',
167 };
168
169 struct column_details {
170         size_t col_nr;
171         enum single_col_format text_format;
172         size_t channel_offset;
173         size_t channel_count;
174 };
175
176 struct context {
177         gboolean started;
178
179         /* Current selected samplerate. */
180         uint64_t samplerate;
181         gboolean samplerate_sent;
182
183         /* Number of logic channels. */
184         size_t logic_channels;
185
186         /* Column delimiter (actually separator), comment leader, EOL sequence. */
187         GString *delimiter;
188         GString *comment;
189         char *termination;
190
191         /* Format specs for input columns, and processing state. */
192         size_t column_seen_count;
193         const char *column_formats;
194         size_t column_want_count;
195         struct column_details *column_details;
196
197         /* Line number to start processing. */
198         size_t start_line;
199
200         /*
201          * Determines if the first line should be treated as header and used for
202          * channel names in multi column mode.
203          */
204         gboolean use_header;
205         gboolean header_seen;
206
207         size_t sample_unit_size;        /**!< Byte count for a single sample. */
208         uint8_t *sample_buffer;         /**!< Buffer for a single sample. */
209
210         uint8_t *datafeed_buffer;       /**!< Queue for datafeed submission. */
211         size_t datafeed_buf_size;
212         size_t datafeed_buf_fill;
213
214         /* Current line number. */
215         size_t line_number;
216
217         /* List of previously created sigrok channels. */
218         GSList *prev_sr_channels;
219 };
220
221 /*
222  * Primitive operations to handle sample sets:
223  * - Keep a buffer for datafeed submission, capable of holding many
224  *   samples (reduces call overhead, improves throughput).
225  * - Have a "current sample set" pointer reference one position in that
226  *   large samples buffer.
227  * - Clear the current sample set before text line inspection, then set
228  *   the bits which are found active in the current line of text input.
229  *   Phrase the API such that call sites can be kept simple. Advance to
230  *   the next sample set between lines, flush the larger buffer as needed
231  *   (when it is full, or upon EOF).
232  */
233
234 static void clear_logic_samples(struct context *inc)
235 {
236         inc->sample_buffer = &inc->datafeed_buffer[inc->datafeed_buf_fill];
237         memset(inc->sample_buffer, 0, inc->sample_unit_size);
238 }
239
240 static void set_logic_level(struct context *inc, size_t ch_idx, int on)
241 {
242         size_t byte_idx, bit_idx;
243         uint8_t bit_mask;
244
245         if (ch_idx >= inc->logic_channels)
246                 return;
247         if (!on)
248                 return;
249
250         byte_idx = ch_idx / 8;
251         bit_idx = ch_idx % 8;
252         bit_mask = 1 << bit_idx;
253         inc->sample_buffer[byte_idx] |= bit_mask;
254 }
255
256 static int flush_logic_samples(const struct sr_input *in)
257 {
258         struct context *inc;
259         struct sr_datafeed_packet packet;
260         struct sr_datafeed_meta meta;
261         struct sr_config *src;
262         uint64_t samplerate;
263         struct sr_datafeed_logic logic;
264         int rc;
265
266         inc = in->priv;
267         if (!inc->datafeed_buf_fill)
268                 return SR_OK;
269
270         if (inc->samplerate && !inc->samplerate_sent) {
271                 packet.type = SR_DF_META;
272                 packet.payload = &meta;
273                 samplerate = inc->samplerate;
274                 src = sr_config_new(SR_CONF_SAMPLERATE, g_variant_new_uint64(samplerate));
275                 meta.config = g_slist_append(NULL, src);
276                 sr_session_send(in->sdi, &packet);
277                 g_slist_free(meta.config);
278                 sr_config_free(src);
279                 inc->samplerate_sent = TRUE;
280         }
281
282         memset(&packet, 0, sizeof(packet));
283         memset(&logic, 0, sizeof(logic));
284         packet.type = SR_DF_LOGIC;
285         packet.payload = &logic;
286         logic.unitsize = inc->sample_unit_size;
287         logic.length = inc->datafeed_buf_fill;
288         logic.data = inc->datafeed_buffer;
289
290         rc = sr_session_send(in->sdi, &packet);
291         if (rc != SR_OK)
292                 return rc;
293
294         inc->datafeed_buf_fill = 0;
295         return SR_OK;
296 }
297
298 static int queue_logic_samples(const struct sr_input *in)
299 {
300         struct context *inc;
301         int rc;
302
303         inc = in->priv;
304         if (!inc->logic_channels)
305                 return SR_OK;
306
307         inc->datafeed_buf_fill += inc->sample_unit_size;
308         if (inc->datafeed_buf_fill == inc->datafeed_buf_size) {
309                 rc = flush_logic_samples(in);
310                 if (rc != SR_OK)
311                         return rc;
312         }
313         return SR_OK;
314 }
315
316 /* Helpers for "column processing". */
317
318 static int split_column_format(const char *spec,
319         size_t *column_count, enum single_col_format *format, size_t *bit_count)
320 {
321         size_t count;
322         char *endp, format_char;
323         enum single_col_format format_code;
324
325         if (!spec || !*spec)
326                 return SR_ERR_ARG;
327
328         /* Get the (optional, decimal, default 1) column count. Accept '*'. */
329         endp = NULL;
330         if (*spec == '*') {
331                 count = 0;
332                 endp = (char *)&spec[1];
333         } else {
334                 count = strtoul(spec, &endp, 10);
335         }
336         if (!endp)
337                 return SR_ERR_ARG;
338         if (endp == spec)
339                 count = 1;
340         if (column_count)
341                 *column_count = count;
342         spec = endp;
343
344         /* Get the (mandatory, single letter) type spec (-/xob/l). */
345         format_char = *spec++;
346         switch (format_char) {
347         case '-':       /* Might conflict with number-parsing. */
348         case '/':
349                 format_char = '-';
350                 format_code = FORMAT_NONE;
351                 break;
352         case 'x':
353                 format_code = FORMAT_HEX;
354                 break;
355         case 'o':
356                 format_code = FORMAT_OCT;
357                 break;
358         case 'b':
359         case 'l':
360                 format_code = FORMAT_BIN;
361                 break;
362         default:        /* includes NUL */
363                 return SR_ERR_ARG;
364         }
365         if (format)
366                 *format = format_code;
367
368         /* Get the (optional, decimal, default 1) bit count. */
369         endp = NULL;
370         count = strtoul(spec, &endp, 10);
371         if (!endp)
372                 return SR_ERR_ARG;
373         if (endp == spec)
374                 count = 1;
375         if (format_char == '-')
376                 count = 0;
377         if (format_char == 'l')
378                 count = 1;
379         if (bit_count)
380                 *bit_count = count;
381         spec = endp;
382
383         /* Input spec must have been exhausted. */
384         if (*spec)
385                 return SR_ERR_ARG;
386
387         return SR_OK;
388 }
389
390 static int make_column_details_from_format(struct context *inc,
391         const char *column_format)
392 {
393         char **formats, *format;
394         size_t format_count, column_count, bit_count;
395         size_t auto_column_count;
396         size_t format_idx, c, b, column_idx, channel_idx;
397         enum single_col_format f;
398         struct column_details *detail;
399         int ret;
400
401         /* Split the input spec, count involved columns and bits. */
402         formats = g_strsplit(column_format, ",", 0);
403         if (!formats) {
404                 sr_err("Cannot parse columns format %s (comma split).", column_format);
405                 return SR_ERR_ARG;
406         }
407         format_count = g_strv_length(formats);
408         if (!format_count) {
409                 sr_err("Cannot parse columns format %s (field count).", column_format);
410                 g_strfreev(formats);
411                 return SR_ERR_ARG;
412         }
413         column_count = bit_count = 0;
414         auto_column_count = 0;
415         for (format_idx = 0; format_idx < format_count; format_idx++) {
416                 format = formats[format_idx];
417                 ret = split_column_format(format, &c, &f, &b);
418                 sr_dbg("fmt %s -> %zu cols, %s fmt, %zu bits, rc %d", format, c, col_format_text[f], b, ret);
419                 if (ret != SR_OK) {
420                         sr_err("Cannot parse columns format %s (field split, %s).", column_format, format);
421                         g_strfreev(formats);
422                         return SR_ERR_ARG;
423                 }
424                 if (f && !c) {
425                         /* User requested "auto-count", must be last format. */
426                         if (formats[format_idx + 1]) {
427                                 sr_err("Auto column count must be last format field.");
428                                 g_strfreev(formats);
429                                 return SR_ERR_ARG;
430                         }
431                         auto_column_count = inc->column_seen_count - column_count;
432                         c = auto_column_count;
433                 }
434                 column_count += c;
435                 bit_count += c * b;
436         }
437         sr_dbg("Column format %s -> %zu columns, %zu logic channels.",
438                 column_format, column_count, bit_count);
439
440         /* Allocate and fill in "column processing" details. */
441         inc->column_want_count = column_count;
442         inc->column_details = g_malloc0_n(column_count, sizeof(inc->column_details[0]));
443         column_idx = channel_idx = 0;
444         for (format_idx = 0; format_idx < format_count; format_idx++) {
445                 format = formats[format_idx];
446                 (void)split_column_format(format, &c, &f, &b);
447                 if (f && !c)
448                         c = auto_column_count;
449                 while (c-- > 0) {
450                         detail = &inc->column_details[column_idx++];
451                         detail->col_nr = column_idx;
452                         detail->text_format = f;
453                         if (detail->text_format) {
454                                 detail->channel_offset = channel_idx;
455                                 detail->channel_count = b;
456                                 channel_idx += b;
457                         }
458                         sr_dbg("detail -> col %zu, fmt %s, ch off/cnt %zu/%zu",
459                                 detail->col_nr, col_format_text[detail->text_format],
460                                 detail->channel_offset, detail->channel_count);
461                 }
462         }
463         inc->logic_channels = channel_idx;
464         g_strfreev(formats);
465
466         return SR_OK;
467 }
468
469 static const struct column_details *lookup_column_details(struct context *inc, size_t nr)
470 {
471         if (!inc || !inc->column_details)
472                 return NULL;
473         if (!nr || nr > inc->column_want_count)
474                 return NULL;
475         return &inc->column_details[nr - 1];
476 }
477
478 /*
479  * Primitive operations for text input: Strip comments off text lines.
480  * Split text lines into columns. Process input text for individual
481  * columns.
482  */
483
484 static void strip_comment(char *buf, const GString *prefix)
485 {
486         char *ptr;
487
488         if (!prefix->len)
489                 return;
490
491         if ((ptr = strstr(buf, prefix->str))) {
492                 *ptr = '\0';
493                 g_strstrip(buf);
494         }
495 }
496
497 /**
498  * @brief Splits a text line into a set of columns.
499  *
500  * @param[in] buf       The input text line to split.
501  * @param[in] inc       The input module's context.
502  *
503  * @returns An array of strings, representing the columns' text.
504  *
505  * This routine splits a text line on previously determined separators.
506  */
507 static char **split_line(char *buf, struct context *inc)
508 {
509         return g_strsplit(buf, inc->delimiter->str, 0);
510 }
511
512 /**
513  * @brief Parse a multi-bit field into several logic channels.
514  *
515  * @param[in] column    The input text, a run of bin/hex/oct digits.
516  * @param[in] inc       The input module's context.
517  * @param[in] details   The column processing details.
518  *
519  * @retval SR_OK        Success.
520  * @retval SR_ERR       Invalid input data (empty, or format error).
521  *
522  * This routine modifies the logic levels in the current sample set,
523  * based on the text input and a user provided format spec.
524  */
525 static int parse_logic(const char *column, struct context *inc,
526         const struct column_details *details)
527 {
528         size_t length, ch_rem, ch_idx, ch_inc;
529         const char *rdptr;
530         char c;
531         gboolean valid;
532         const char *type_text;
533         uint8_t bits;
534
535         /*
536          * Prepare to read the digits from the text end towards the start.
537          * A digit corresponds to a variable number of channels (depending
538          * on the value's radix). Prepare the mapping of text digits to
539          * (a number of) logic channels.
540          */
541         length = strlen(column);
542         if (!length) {
543                 sr_err("Column %zu in line %zu is empty.", details->col_nr,
544                         inc->line_number);
545                 return SR_ERR;
546         }
547         rdptr = &column[length];
548         ch_idx = details->channel_offset;
549         ch_rem = details->channel_count;
550
551         /*
552          * Get another digit and derive up to four logic channels' state from
553          * it. Make sure to not process more bits than the column has channels
554          * associated with it.
555          */
556         while (rdptr > column && ch_rem) {
557                 /* Check for valid digits according to the input radix. */
558                 c = *(--rdptr);
559                 switch (details->text_format) {
560                 case FORMAT_BIN:
561                         valid = g_ascii_isxdigit(c) && c < '2';
562                         ch_inc = 1;
563                         break;
564                 case FORMAT_OCT:
565                         valid = g_ascii_isxdigit(c) && c < '8';
566                         ch_inc = 3;
567                         break;
568                 case FORMAT_HEX:
569                         valid = g_ascii_isxdigit(c);
570                         ch_inc = 4;
571                         break;
572                 default:
573                         valid = FALSE;
574                         break;
575                 }
576                 if (!valid) {
577                         type_text = col_format_text[details->text_format];
578                         sr_err("Invalid text '%s' in %s type column %zu in line %zu.",
579                                 column, type_text, details->col_nr, inc->line_number);
580                         return SR_ERR;
581                 }
582                 /* Use the digit's bits for logic channels' data. */
583                 bits = g_ascii_xdigit_value(c);
584                 switch (details->text_format) {
585                 case FORMAT_HEX:
586                         if (ch_rem >= 4) {
587                                 ch_rem--;
588                                 set_logic_level(inc, ch_idx + 3, bits & (1 << 3));
589                         }
590                         /* FALLTHROUGH */
591                 case FORMAT_OCT:
592                         if (ch_rem >= 3) {
593                                 ch_rem--;
594                                 set_logic_level(inc, ch_idx + 2, bits & (1 << 2));
595                         }
596                         if (ch_rem >= 2) {
597                                 ch_rem--;
598                                 set_logic_level(inc, ch_idx + 1, bits & (1 << 1));
599                         }
600                         /* FALLTHROUGH */
601                 case FORMAT_BIN:
602                         ch_rem--;
603                         set_logic_level(inc, ch_idx + 0, bits & (1 << 0));
604                         break;
605                 case FORMAT_NONE:
606                         /* ShouldNotHappen(TM), but silences compiler warning. */
607                         return SR_ERR;
608                 }
609                 ch_idx += ch_inc;
610         }
611         /*
612          * TODO Determine whether the availability of extra input data
613          * for unhandled logic channels is worth warning here. In this
614          * implementation users are in control, and can have the more
615          * significant bits ignored (which can be considered a feature
616          * and not really a limitation).
617          */
618
619         return SR_OK;
620 }
621
622 /**
623  * @brief Parse routine which ignores the input text.
624  *
625  * This routine exists to unify dispatch code paths, mapping input file
626  * columns' data types to their respective parse routines.
627  */
628 static int parse_ignore(const char *column, struct context *inc,
629         const struct column_details *details)
630 {
631         (void)column;
632         (void)inc;
633         (void)details;
634         return SR_OK;
635 }
636
637 typedef int (*col_parse_cb)(const char *column, struct context *inc,
638         const struct column_details *details);
639
640 static const col_parse_cb col_parse_funcs[] = {
641         [FORMAT_NONE] = parse_ignore,
642         [FORMAT_BIN] = parse_logic,
643         [FORMAT_OCT] = parse_logic,
644         [FORMAT_HEX] = parse_logic,
645 };
646
647 static int init(struct sr_input *in, GHashTable *options)
648 {
649         struct context *inc;
650         size_t single_column, first_column, logic_channels;
651         const char *s;
652         enum single_col_format format;
653         char format_char;
654
655         in->sdi = g_malloc0(sizeof(*in->sdi));
656         in->priv = inc = g_malloc0(sizeof(*inc));
657
658         single_column = g_variant_get_uint32(g_hash_table_lookup(options, "single_column"));
659
660         logic_channels = g_variant_get_uint32(g_hash_table_lookup(options, "logic_channels"));
661
662         inc->delimiter = g_string_new(g_variant_get_string(
663                         g_hash_table_lookup(options, "column_separator"), NULL));
664         if (!inc->delimiter->len) {
665                 sr_err("Column separator cannot be empty.");
666                 return SR_ERR_ARG;
667         }
668
669         s = g_variant_get_string(g_hash_table_lookup(options, "single_format"), NULL);
670         if (g_ascii_strncasecmp(s, "bin", 3) == 0) {
671                 format = FORMAT_BIN;
672         } else if (g_ascii_strncasecmp(s, "hex", 3) == 0) {
673                 format = FORMAT_HEX;
674         } else if (g_ascii_strncasecmp(s, "oct", 3) == 0) {
675                 format = FORMAT_OCT;
676         } else {
677                 sr_err("Invalid single-column format: '%s'", s);
678                 return SR_ERR_ARG;
679         }
680
681         inc->comment = g_string_new(g_variant_get_string(
682                         g_hash_table_lookup(options, "comment_leader"), NULL));
683         if (g_string_equal(inc->comment, inc->delimiter)) {
684                 /*
685                  * Using the same sequence as comment leader and column
686                  * separator won't work. The user probably specified ';'
687                  * as the column separator but did not adjust the comment
688                  * leader. Try DWIM, drop comment strippin support here.
689                  */
690                 sr_warn("Comment leader and column separator conflict, disabling comment support.");
691                 g_string_truncate(inc->comment, 0);
692         }
693
694         inc->samplerate = g_variant_get_uint64(g_hash_table_lookup(options, "samplerate"));
695
696         first_column = g_variant_get_uint32(g_hash_table_lookup(options, "first_column"));
697
698         inc->use_header = g_variant_get_boolean(g_hash_table_lookup(options, "header"));
699
700         inc->start_line = g_variant_get_uint32(g_hash_table_lookup(options, "start_line"));
701         if (inc->start_line < 1) {
702                 sr_err("Invalid start line %zu.", inc->start_line);
703                 return SR_ERR_ARG;
704         }
705
706         /*
707          * Scan flexible, to get prefered format specs which describe
708          * the input file's data formats. As well as some simple specs
709          * for backwards compatibility and user convenience.
710          *
711          * This logic ends up with a copy of the format string, either
712          * user provided or internally derived. Actual creation of the
713          * column processing details gets deferred until the first line
714          * of input data was seen. To support automatic determination of
715          * e.g. channel counts from column counts.
716          */
717         s = g_variant_get_string(g_hash_table_lookup(options, "column_formats"), NULL);
718         if (s && *s) {
719                 inc->column_formats = g_strdup(s);
720                 sr_dbg("User specified column_formats: %s.", s);
721         } else if (single_column && logic_channels) {
722                 format_char = col_format_char[format];
723                 if (single_column == 1) {
724                         inc->column_formats = g_strdup_printf("%c%zu",
725                                 format_char, logic_channels);
726                 } else {
727                         inc->column_formats = g_strdup_printf("%zu-,%c%zu",
728                                 single_column - 1,
729                                 format_char, logic_channels);
730                 }
731                 sr_dbg("Backwards compat single_column, col %zu, fmt %s, bits %zu -> %s.",
732                         single_column, col_format_text[format], logic_channels,
733                         inc->column_formats);
734         } else if (!single_column) {
735                 if (first_column > 1) {
736                         inc->column_formats = g_strdup_printf("%zu-,%zul",
737                                 first_column - 1, logic_channels);
738                 } else {
739                         inc->column_formats = g_strdup_printf("%zul",
740                                 logic_channels);
741                 }
742                 sr_dbg("Backwards compat multi-column, col %zu, chans %zu -> %s.",
743                         first_column, logic_channels,
744                         inc->column_formats);
745         } else {
746                 sr_warn("Unknown or unsupported columns layout spec, assuming simple multi-column mode.");
747                 inc->column_formats = g_strdup("*l");
748         }
749
750         return SR_OK;
751 }
752
753 /*
754  * Check the channel list for consistency across file re-import. See
755  * the VCD input module for more details and motivation.
756  */
757
758 static void keep_header_for_reread(const struct sr_input *in)
759 {
760         struct context *inc;
761
762         inc = in->priv;
763         g_slist_free_full(inc->prev_sr_channels, sr_channel_free_cb);
764         inc->prev_sr_channels = in->sdi->channels;
765         in->sdi->channels = NULL;
766 }
767
768 static int check_header_in_reread(const struct sr_input *in)
769 {
770         struct context *inc;
771
772         if (!in)
773                 return FALSE;
774         inc = in->priv;
775         if (!inc)
776                 return FALSE;
777         if (!inc->prev_sr_channels)
778                 return TRUE;
779
780         if (sr_channel_lists_differ(inc->prev_sr_channels, in->sdi->channels)) {
781                 sr_err("Channel list change not supported for file re-read.");
782                 return FALSE;
783         }
784         g_slist_free_full(in->sdi->channels, sr_channel_free_cb);
785         in->sdi->channels = inc->prev_sr_channels;
786         inc->prev_sr_channels = NULL;
787
788         return TRUE;
789 }
790
791 static const char *delim_set = "\r\n";
792
793 static const char *get_line_termination(GString *buf)
794 {
795         const char *term;
796
797         term = NULL;
798         if (g_strstr_len(buf->str, buf->len, "\r\n"))
799                 term = "\r\n";
800         else if (memchr(buf->str, '\n', buf->len))
801                 term = "\n";
802         else if (memchr(buf->str, '\r', buf->len))
803                 term = "\r";
804
805         return term;
806 }
807
808 static int initial_parse(const struct sr_input *in, GString *buf)
809 {
810         struct context *inc;
811         GString *channel_name;
812         size_t num_columns, ch_idx, ch_name_idx, col_idx, col_nr;
813         size_t line_number, line_idx;
814         int ret;
815         char **lines, *line, **columns, *column;
816         const char *col_caption;
817         gboolean got_caption;
818         const struct column_details *detail;
819
820         ret = SR_OK;
821         inc = in->priv;
822         columns = NULL;
823
824         line_number = 0;
825         if (inc->termination)
826                 lines = g_strsplit(buf->str, inc->termination, 0);
827         else
828                 lines = g_strsplit_set(buf->str, delim_set, 0);
829         for (line_idx = 0; (line = lines[line_idx]); line_idx++) {
830                 line_number++;
831                 if (inc->start_line > line_number) {
832                         sr_spew("Line %zu skipped (before start).", line_number);
833                         continue;
834                 }
835                 if (line[0] == '\0') {
836                         sr_spew("Blank line %zu skipped.", line_number);
837                         continue;
838                 }
839                 strip_comment(line, inc->comment);
840                 if (line[0] == '\0') {
841                         sr_spew("Comment-only line %zu skipped.", line_number);
842                         continue;
843                 }
844
845                 /* Reached first proper line. */
846                 break;
847         }
848         if (!line) {
849                 /* Not enough data for a proper line yet. */
850                 ret = SR_ERR_NA;
851                 goto out;
852         }
853
854         /* See how many columns the current line has. */
855         columns = split_line(line, inc);
856         if (!columns) {
857                 sr_err("Error while parsing line %zu.", line_number);
858                 ret = SR_ERR;
859                 goto out;
860         }
861         num_columns = g_strv_length(columns);
862         if (!num_columns) {
863                 sr_err("Error while parsing line %zu.", line_number);
864                 ret = SR_ERR;
865                 goto out;
866         }
867         sr_dbg("DIAG Got %zu columns in text line: %s.", num_columns, line);
868
869         /*
870          * Track the observed number of columns in the input file. Do
871          * process the previously gathered columns format spec now that
872          * automatic channel count can be dealt with.
873          */
874         inc->column_seen_count = num_columns;
875         ret = make_column_details_from_format(inc, inc->column_formats);
876         if (ret != SR_OK) {
877                 sr_err("Cannot parse columns format using line %zu.", line_number);
878                 goto out;
879         }
880
881         /*
882          * Assume all lines have equal length (column count). Bail out
883          * early on suspicious or insufficient input data (check input
884          * which became available here against previous user specs or
885          * auto-determined properties, regardless of layout variant).
886          */
887         if (num_columns < inc->column_want_count) {
888                 sr_err("Insufficient input text width for desired data amount, got %zu but want %zu columns.",
889                         num_columns, inc->column_want_count);
890                 ret = SR_ERR;
891                 goto out;
892         }
893
894         /*
895          * Determine channel names. Optionally use text from a header
896          * line (when requested by the user, and only works in multi
897          * column mode). In the absence of header text, or in single
898          * column mode, channels are assigned rather generic names.
899          *
900          * Manipulation of the column's caption is acceptable here, the
901          * header line will never get processed another time.
902          */
903         channel_name = g_string_sized_new(64);
904         for (col_idx = 0; col_idx < inc->column_want_count; col_idx++) {
905
906                 col_nr = col_idx + 1;
907                 detail = lookup_column_details(inc, col_nr);
908                 if (detail->text_format == FORMAT_NONE)
909                         continue;
910                 column = columns[col_idx];
911                 col_caption = sr_scpi_unquote_string(column);
912                 got_caption = inc->use_header && *col_caption;
913                 sr_dbg("DIAG col %zu, ch count %zu, text %s.",
914                         col_nr, detail->channel_count, col_caption);
915                 for (ch_idx = 0; ch_idx < detail->channel_count; ch_idx++) {
916                         ch_name_idx = detail->channel_offset + ch_idx;
917                         if (got_caption && detail->channel_count == 1)
918                                 g_string_assign(channel_name, col_caption);
919                         else if (got_caption)
920                                 g_string_printf(channel_name, "%s[%zu]",
921                                         col_caption, ch_idx);
922                         else
923                                 g_string_printf(channel_name, "%zu", ch_name_idx);
924                         sr_dbg("DIAG ch idx %zu, name %s.", ch_name_idx, channel_name->str);
925                         sr_channel_new(in->sdi, ch_name_idx, SR_CHANNEL_LOGIC, TRUE,
926                                 channel_name->str);
927                 }
928         }
929         g_string_free(channel_name, TRUE);
930         if (!check_header_in_reread(in)) {
931                 ret = SR_ERR_DATA;
932                 goto out;
933         }
934
935         /*
936          * Calculate the minimum buffer size to store the set of samples
937          * of all channels (unit size). Determine a larger buffer size
938          * for datafeed submission that is a multiple of the unit size.
939          * Allocate the larger buffer, the "sample buffer" will point
940          * to a location within that large buffer later.
941          */
942         inc->sample_unit_size = (inc->logic_channels + 7) / 8;
943         inc->datafeed_buf_size = CHUNK_SIZE;
944         inc->datafeed_buf_size *= inc->sample_unit_size;
945         inc->datafeed_buffer = g_malloc(inc->datafeed_buf_size);
946         inc->datafeed_buf_fill = 0;
947
948 out:
949         if (columns)
950                 g_strfreev(columns);
951         g_strfreev(lines);
952
953         return ret;
954 }
955
956 /*
957  * Gets called from initial_receive(), which runs until the end-of-line
958  * encoding of the input stream could get determined. Assumes that this
959  * routine receives enough buffered initial input data to either see the
960  * BOM when there is one, or that no BOM will follow when a text line
961  * termination sequence was seen. Silently drops the UTF-8 BOM sequence
962  * from the input buffer if one was seen. Does not care to protect
963  * against multiple execution or dropping the BOM multiple times --
964  * there should be at most one in the input stream.
965  */
966 static void initial_bom_check(const struct sr_input *in)
967 {
968         static const char *utf8_bom = "\xef\xbb\xbf";
969
970         if (in->buf->len < strlen(utf8_bom))
971                 return;
972         if (strncmp(in->buf->str, utf8_bom, strlen(utf8_bom)) != 0)
973                 return;
974         g_string_erase(in->buf, 0, strlen(utf8_bom));
975 }
976
977 static int initial_receive(const struct sr_input *in)
978 {
979         struct context *inc;
980         GString *new_buf;
981         int len, ret;
982         char *p;
983         const char *termination;
984
985         initial_bom_check(in);
986
987         inc = in->priv;
988
989         termination = get_line_termination(in->buf);
990         if (!termination)
991                 /* Don't have a full line yet. */
992                 return SR_ERR_NA;
993
994         p = g_strrstr_len(in->buf->str, in->buf->len, termination);
995         if (!p)
996                 /* Don't have a full line yet. */
997                 return SR_ERR_NA;
998         len = p - in->buf->str - 1;
999         new_buf = g_string_new_len(in->buf->str, len);
1000         g_string_append_c(new_buf, '\0');
1001
1002         inc->termination = g_strdup(termination);
1003
1004         if (in->buf->str[0] != '\0')
1005                 ret = initial_parse(in, new_buf);
1006         else
1007                 ret = SR_OK;
1008
1009         g_string_free(new_buf, TRUE);
1010
1011         return ret;
1012 }
1013
1014 static int process_buffer(struct sr_input *in, gboolean is_eof)
1015 {
1016         struct context *inc;
1017         gsize num_columns;
1018         size_t line_idx, col_idx, col_nr;
1019         const struct column_details *details;
1020         col_parse_cb parse_func;
1021         int ret;
1022         char *p, **lines, *line, **columns, *column;
1023
1024         inc = in->priv;
1025         if (!inc->started) {
1026                 std_session_send_df_header(in->sdi);
1027                 inc->started = TRUE;
1028         }
1029
1030         /*
1031          * Consider empty input non-fatal. Keep accumulating input until
1032          * at least one full text line has become available. Grab the
1033          * maximum amount of accumulated data that consists of full text
1034          * lines, and process what has been received so far, leaving not
1035          * yet complete lines for the next invocation.
1036          *
1037          * Enforce that all previously buffered data gets processed in
1038          * the "EOF" condition. Do not insist in the presence of the
1039          * termination sequence for the last line (may often be missing
1040          * on Windows). A present termination sequence will just result
1041          * in the "execution of an empty line", and does not harm.
1042          */
1043         if (!in->buf->len)
1044                 return SR_OK;
1045         if (is_eof) {
1046                 p = in->buf->str + in->buf->len;
1047         } else {
1048                 p = g_strrstr_len(in->buf->str, in->buf->len, inc->termination);
1049                 if (!p)
1050                         return SR_ERR;
1051                 *p = '\0';
1052                 p += strlen(inc->termination);
1053         }
1054         g_strstrip(in->buf->str);
1055
1056         ret = SR_OK;
1057         lines = g_strsplit(in->buf->str, inc->termination, 0);
1058         for (line_idx = 0; (line = lines[line_idx]); line_idx++) {
1059                 inc->line_number++;
1060                 if (inc->line_number < inc->start_line) {
1061                         sr_spew("Line %zu skipped (before start).", inc->line_number);
1062                         continue;
1063                 }
1064                 if (line[0] == '\0') {
1065                         sr_spew("Blank line %zu skipped.", inc->line_number);
1066                         continue;
1067                 }
1068
1069                 /* Remove trailing comment. */
1070                 strip_comment(line, inc->comment);
1071                 if (line[0] == '\0') {
1072                         sr_spew("Comment-only line %zu skipped.", inc->line_number);
1073                         continue;
1074                 }
1075
1076                 /* Skip the header line, its content was used as the channel names. */
1077                 if (inc->use_header && !inc->header_seen) {
1078                         sr_spew("Header line %zu skipped.", inc->line_number);
1079                         inc->header_seen = TRUE;
1080                         continue;
1081                 }
1082
1083                 /* Split the line into columns, check for minimum length. */
1084                 columns = split_line(line, inc);
1085                 if (!columns) {
1086                         sr_err("Error while parsing line %zu.", inc->line_number);
1087                         g_strfreev(lines);
1088                         return SR_ERR;
1089                 }
1090                 num_columns = g_strv_length(columns);
1091                 if (num_columns < inc->column_want_count) {
1092                         sr_err("Insufficient column count %zu in line %zu.",
1093                                 num_columns, inc->line_number);
1094                         g_strfreev(columns);
1095                         g_strfreev(lines);
1096                         return SR_ERR;
1097                 }
1098
1099                 /* Have the columns of the current text line processed. */
1100                 clear_logic_samples(inc);
1101                 for (col_idx = 0; col_idx < inc->column_want_count; col_idx++) {
1102                         column = columns[col_idx];
1103                         col_nr = col_idx + 1;
1104                         details = lookup_column_details(inc, col_nr);
1105                         if (!details || !details->text_format)
1106                                 continue;
1107                         parse_func = col_parse_funcs[details->text_format];
1108                         if (!parse_func)
1109                                 continue;
1110                         ret = parse_func(column, inc, details);
1111                         if (ret != SR_OK) {
1112                                 g_strfreev(columns);
1113                                 g_strfreev(lines);
1114                                 return SR_ERR;
1115                         }
1116                 }
1117
1118                 /* Send sample data to the session bus (buffered). */
1119                 ret = queue_logic_samples(in);
1120                 if (ret != SR_OK) {
1121                         sr_err("Sending samples failed.");
1122                         g_strfreev(columns);
1123                         g_strfreev(lines);
1124                         return SR_ERR;
1125                 }
1126
1127                 g_strfreev(columns);
1128         }
1129         g_strfreev(lines);
1130         g_string_erase(in->buf, 0, p - in->buf->str);
1131
1132         return ret;
1133 }
1134
1135 static int receive(struct sr_input *in, GString *buf)
1136 {
1137         struct context *inc;
1138         int ret;
1139
1140         g_string_append_len(in->buf, buf->str, buf->len);
1141
1142         inc = in->priv;
1143         if (!inc->column_seen_count) {
1144                 ret = initial_receive(in);
1145                 if (ret == SR_ERR_NA)
1146                         /* Not enough data yet. */
1147                         return SR_OK;
1148                 else if (ret != SR_OK)
1149                         return SR_ERR;
1150
1151                 /* sdi is ready, notify frontend. */
1152                 in->sdi_ready = TRUE;
1153                 return SR_OK;
1154         }
1155
1156         ret = process_buffer(in, FALSE);
1157
1158         return ret;
1159 }
1160
1161 static int end(struct sr_input *in)
1162 {
1163         struct context *inc;
1164         int ret;
1165
1166         if (in->sdi_ready)
1167                 ret = process_buffer(in, TRUE);
1168         else
1169                 ret = SR_OK;
1170         if (ret != SR_OK)
1171                 return ret;
1172
1173         ret = flush_logic_samples(in);
1174         if (ret != SR_OK)
1175                 return ret;
1176
1177         inc = in->priv;
1178         if (inc->started)
1179                 std_session_send_df_end(in->sdi);
1180
1181         return ret;
1182 }
1183
1184 static void cleanup(struct sr_input *in)
1185 {
1186         struct context *inc;
1187
1188         keep_header_for_reread(in);
1189
1190         inc = in->priv;
1191
1192         g_free(inc->termination);
1193         inc->termination = NULL;
1194         g_free(inc->datafeed_buffer);
1195         inc->datafeed_buffer = NULL;
1196 }
1197
1198 static int reset(struct sr_input *in)
1199 {
1200         struct context *inc = in->priv;
1201
1202         cleanup(in);
1203         inc->started = FALSE;
1204         g_string_truncate(in->buf, 0);
1205
1206         return SR_OK;
1207 }
1208
1209 enum option_index {
1210         OPT_COL_FMTS,
1211         OPT_SINGLE_COL,
1212         OPT_FIRST_COL,
1213         OPT_NUM_LOGIC,
1214         OPT_FORMAT,
1215         OPT_START,
1216         OPT_HEADER,
1217         OPT_RATE,
1218         OPT_DELIM,
1219         OPT_COMMENT,
1220         OPT_MAX,
1221 };
1222
1223 static struct sr_option options[] = {
1224         [OPT_COL_FMTS] = {
1225                 "column_formats", "Column format specs",
1226                 "Specifies text columns data types: comma separated list of [<cols>]<fmt>[<bits>], with -/x/o/b/l format specifiers.",
1227                 NULL, NULL,
1228         },
1229         [OPT_SINGLE_COL] = {
1230                 "single_column", "Single column",
1231                 "Enable single-column mode, exclusively use text from the specified column (number starting at 1).",
1232                 NULL, NULL,
1233         },
1234         [OPT_FIRST_COL] = {
1235                 "first_column", "First column",
1236                 "Number of the first column with logic data in simple multi-column mode (number starting at 1, default 1).",
1237                 NULL, NULL,
1238         },
1239         [OPT_NUM_LOGIC] = {
1240                 "logic_channels", "Number of logic channels",
1241                 "Logic channel count, required in simple single-column mode, defaults to \"all remaining columns\" in simple multi-column mode. Obsoleted by 'column_formats'.",
1242                 NULL, NULL,
1243         },
1244         [OPT_FORMAT] = {
1245                 "single_format", "Data format for simple single-column mode.",
1246                 "The number format of single-column mode input data: bin, hex, oct.",
1247                 NULL, NULL,
1248         },
1249         [OPT_START] = {
1250                 "start_line", "Start line",
1251                 "The line number at which to start processing input text (default: 1).",
1252                 NULL, NULL,
1253         },
1254         [OPT_HEADER] = {
1255                 "header", "Get channel names from first line.",
1256                 "Use the first processed line's column captions (when available) as channel names.",
1257                 NULL, NULL,
1258         },
1259         [OPT_RATE] = {
1260                 "samplerate", "Samplerate (Hz)",
1261                 "The input data's sample rate in Hz.",
1262                 NULL, NULL,
1263         },
1264         [OPT_DELIM] = {
1265                 "column_separator", "Column separator",
1266                 "The sequence which separates text columns. Non-empty text, comma by default.",
1267                 NULL, NULL,
1268         },
1269         [OPT_COMMENT] = {
1270                 "comment_leader", "Comment leader character",
1271                 "The text which starts comments at the end of text lines.",
1272                 NULL, NULL,
1273         },
1274         [OPT_MAX] = ALL_ZERO,
1275 };
1276
1277 static const struct sr_option *get_options(void)
1278 {
1279         GSList *l;
1280
1281         if (!options[0].def) {
1282                 options[OPT_COL_FMTS].def = g_variant_ref_sink(g_variant_new_string(""));
1283                 options[OPT_SINGLE_COL].def = g_variant_ref_sink(g_variant_new_uint32(0));
1284                 options[OPT_FIRST_COL].def = g_variant_ref_sink(g_variant_new_uint32(1));
1285                 options[OPT_NUM_LOGIC].def = g_variant_ref_sink(g_variant_new_uint32(0));
1286                 options[OPT_FORMAT].def = g_variant_ref_sink(g_variant_new_string("bin"));
1287                 l = NULL;
1288                 l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("bin")));
1289                 l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("hex")));
1290                 l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("oct")));
1291                 options[OPT_FORMAT].values = l;
1292                 options[OPT_START].def = g_variant_ref_sink(g_variant_new_uint32(1));
1293                 options[OPT_HEADER].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
1294                 options[OPT_RATE].def = g_variant_ref_sink(g_variant_new_uint64(0));
1295                 options[OPT_DELIM].def = g_variant_ref_sink(g_variant_new_string(","));
1296                 options[OPT_COMMENT].def = g_variant_ref_sink(g_variant_new_string(";"));
1297         }
1298
1299         return options;
1300 }
1301
1302 SR_PRIV struct sr_input_module input_csv = {
1303         .id = "csv",
1304         .name = "CSV",
1305         .desc = "Comma-separated values",
1306         .exts = (const char*[]){"csv", NULL},
1307         .options = get_options,
1308         .init = init,
1309         .receive = receive,
1310         .end = end,
1311         .cleanup = cleanup,
1312         .reset = reset,
1313 };