]> sigrok.org Git - libsigrok.git/blame_incremental - src/input/csv.c
input/csv: robustness nits in column format dispatching
[libsigrok.git] / src / input / csv.c
... / ...
CommitLineData
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). The 'a' format marks analog
45 * data, an optionally following number is the digits count (resolution).
46 * This "column_formats" option is most versatile, other forms of
47 * specifying the column layout only exist for backwards compatibility,
48 * and are rather limited. They exclusively support logic input data in
49 * strictly adjacent columns, with further constraints on column layout
50 * for multi-bit data.
51 *
52 * single_column: Specifies the column number which contains the logic data
53 * for single-column mode. All logic data is taken from several bits
54 * which all are kept within that one column. Only exists for backwards
55 * compatibility, see "column_formats" for more flexibility.
56 *
57 * first_column: Specifies the number of the first column with logic data
58 * in simple multi-column mode. Only exists for backwards compatibility,
59 * see "column_formats" for more flexibility.
60 *
61 * logic_channels: Specifies the number of logic channels. Is required in
62 * simple single-column mode. Is optional in simple multi-column mode
63 * (and defaults to all remaining columns). Only exists for backwards
64 * compatibility, see "column_formats" for more flexibility.
65 *
66 * single_format: Specifies the format of the input text in simple single-
67 * column mode. Available formats are: 'bin' (default), 'hex' and 'oct'.
68 * Simple multi-column mode always uses single-bit data per column.
69 * Only exists for backwards compatibility, see "column_formats" for
70 * more flexibility.
71 *
72 * start_line: Specifies at which line to start processing the input file.
73 * Allows to skip leading lines which neither are header nor data lines.
74 * By default all of the input file gets processed.
75 *
76 * header: Boolean option, controls whether the first processed line is used
77 * to determine channel names. Off by default. Generic channel names are
78 * used in the absence of header line content.
79 *
80 * samplerate: Specifies the samplerate of the input data. Defaults to 0.
81 * User specs take precedence over data which optionally gets derived
82 * from input data.
83 *
84 * column_separator: Specifies the sequence which separates the text file
85 * columns. Cannot be empty. Defaults to comma.
86 *
87 * comment_leader: Specifies the sequence which starts comments that run
88 * up to the end of the current text line. Can be empty to disable
89 * comment support. Defaults to semicolon.
90 *
91 * Typical examples of using these options:
92 * - ... -I csv:column_formats=*l ...
93 * All columns are single-bit logic data. Identical to the previous
94 * multi-column mode (the default when no options were given at all).
95 * - ... -I csv:column_formats=3-,*l ...
96 * Ignore the first three columns, get single-bit logic data from all
97 * remaining lines (multi-column mode with first-column above 1).
98 * - ... -I csv:column_formats=3-,4l,x8 ...
99 * Ignore the first three columns, get single-bit logic data from the
100 * next four columns, then eight-bit data in hex format from the next
101 * column. More columns may follow in the input text but won't get
102 * processed. (Mix of previous multi-column as well as single-column
103 * modes.)
104 * - ... -I csv:column_formats=4x8,b16,5l ...
105 * Get eight-bit data in hex format from the first four columns, then
106 * sixteen-bit data in binary format, then five times single-bit data.
107 * - ... -I csv:single_column=2:single_format=bin:logic_channels=8 ...
108 * Get eight logic bits in binary format from column 2. (Simple
109 * single-column mode, corresponds to the "-,b8" format.)
110 * - ... -I csv:first_column=6:logic_channels=4 ...
111 * Get four single-bit logic channels from columns 6 to 9 respectively.
112 * (Simple multi-column mode, corresponds to the "5-,4b" format.)
113 * - ... -I csv:start_line=20:header=yes:...
114 * Skip the first 19 text lines. Use line 20 to derive channel names.
115 * Data starts at line 21.
116 * - ... -I csv:column_formats=*a6 ...
117 * Each column contains an analog value with six significant digits
118 * after the decimal period.
119 */
120
121/*
122 * TODO
123 *
124 * - Extend support for analog input data.
125 * - Determine why analog samples of 'double' data type get scrambled
126 * in sigrok-cli screen output. Is analog.encoding->unitsize not
127 * handled properly? A sigrok-cli or libsigrok (src/output) issue?
128 * - Reconsider the channel creation after format processing. Current
129 * logic may "bleed" channel names into the analog group when logic
130 * channels' columns follow analog columns (seen with "-,2a,x8").
131 * Trying to sort it out, a naive change used to map logic channels'
132 * data to incorrect bitmap positions. The whole channel numbering
133 * needs reconsideration. Probably it's easiest to first create _all_
134 * logic channels so that they have adjacent numbers starting at 0
135 * (addressing logic bits), then all analog channels (again adjacent)
136 * to simplify the calculation of their index in the sample set as
137 * well as their sdi channel index from the "analog column index".
138 * - Optionally get sample rate from timestamp column. Just best-effort
139 * approach, not necessarily reliable. Users can always specify rates.
140 * - Add a test suite for input modules in general, and CSV in specific?
141 * Becomes more important with the multitude of options and their
142 * interaction. Could cover edge cases (BOM presence, line termination
143 * absence, etc) and auto-stuff as well (channel names, channel counts,
144 * samplerates, etc).
145 */
146
147typedef float csv_analog_t; /* 'double' currently is flawed. */
148
149/* Single column formats. */
150enum single_col_format {
151 FORMAT_NONE, /* Ignore this column. */
152 FORMAT_BIN, /* Bin digits for a set of bits (or just one bit). */
153 FORMAT_HEX, /* Hex digits for a set of bits. */
154 FORMAT_OCT, /* Oct digits for a set of bits. */
155 FORMAT_ANALOG, /* Floating point number for an analog channel. */
156};
157
158static const char *col_format_text[] = {
159 [FORMAT_NONE] = "unknown",
160 [FORMAT_BIN] = "binary",
161 [FORMAT_HEX] = "hexadecimal",
162 [FORMAT_OCT] = "octal",
163 [FORMAT_ANALOG] = "analog",
164};
165
166static const char col_format_char[] = {
167 [FORMAT_NONE] = '?',
168 [FORMAT_BIN] = 'b',
169 [FORMAT_HEX] = 'x',
170 [FORMAT_OCT] = 'o',
171 [FORMAT_ANALOG] = 'a',
172};
173
174static gboolean format_is_ignore(enum single_col_format fmt)
175{
176 return fmt == FORMAT_NONE;
177}
178
179static gboolean format_is_logic(enum single_col_format fmt)
180{
181 return fmt >= FORMAT_BIN && fmt <= FORMAT_OCT;
182}
183
184static gboolean format_is_analog(enum single_col_format fmt)
185{
186 return fmt == FORMAT_ANALOG;
187}
188
189struct column_details {
190 size_t col_nr;
191 enum single_col_format text_format;
192 size_t channel_offset;
193 size_t channel_count;
194 size_t channel_index;
195 int analog_digits;
196};
197
198struct context {
199 gboolean started;
200
201 /* Current selected samplerate. */
202 uint64_t samplerate;
203 gboolean samplerate_sent;
204
205 /* Number of channels. */
206 size_t logic_channels;
207 size_t analog_channels;
208
209 /* Column delimiter (actually separator), comment leader, EOL sequence. */
210 GString *delimiter;
211 GString *comment;
212 char *termination;
213
214 /* Format specs for input columns, and processing state. */
215 size_t column_seen_count;
216 const char *column_formats;
217 size_t column_want_count;
218 struct column_details *column_details;
219
220 /* Line number to start processing. */
221 size_t start_line;
222
223 /*
224 * Determines if the first line should be treated as header and used for
225 * channel names in multi column mode.
226 */
227 gboolean use_header;
228 gboolean header_seen;
229
230 size_t sample_unit_size; /**!< Byte count for a single sample. */
231 uint8_t *sample_buffer; /**!< Buffer for a single sample. */
232 csv_analog_t *analog_sample_buffer; /**!< Buffer for one set of analog values. */
233
234 uint8_t *datafeed_buffer; /**!< Queue for datafeed submission. */
235 size_t datafeed_buf_size;
236 size_t datafeed_buf_fill;
237 /* "Striped" layout, M samples for N channels each. */
238 csv_analog_t *analog_datafeed_buffer; /**!< Queue for analog datafeed. */
239 size_t analog_datafeed_buf_size;
240 size_t analog_datafeed_buf_fill;
241 GSList **analog_datafeed_channels;
242 int *analog_datafeed_digits;
243
244 /* Current line number. */
245 size_t line_number;
246
247 /* List of previously created sigrok channels. */
248 GSList *prev_sr_channels;
249};
250
251/*
252 * Primitive operations to handle sample sets:
253 * - Keep a buffer for datafeed submission, capable of holding many
254 * samples (reduces call overhead, improves throughput).
255 * - Have a "current sample set" pointer reference one position in that
256 * large samples buffer.
257 * - Clear the current sample set before text line inspection, then set
258 * the bits which are found active in the current line of text input.
259 * Phrase the API such that call sites can be kept simple. Advance to
260 * the next sample set between lines, flush the larger buffer as needed
261 * (when it is full, or upon EOF).
262 */
263
264static int flush_samplerate(const struct sr_input *in)
265{
266 struct context *inc;
267 struct sr_datafeed_packet packet;
268 struct sr_datafeed_meta meta;
269 struct sr_config *src;
270
271 inc = in->priv;
272 if (inc->samplerate && !inc->samplerate_sent) {
273 packet.type = SR_DF_META;
274 packet.payload = &meta;
275 src = sr_config_new(SR_CONF_SAMPLERATE, g_variant_new_uint64(inc->samplerate));
276 meta.config = g_slist_append(NULL, src);
277 sr_session_send(in->sdi, &packet);
278 g_slist_free(meta.config);
279 sr_config_free(src);
280 inc->samplerate_sent = TRUE;
281 }
282
283 return SR_OK;
284}
285
286static void clear_logic_samples(struct context *inc)
287{
288 if (!inc->logic_channels)
289 return;
290 inc->sample_buffer = &inc->datafeed_buffer[inc->datafeed_buf_fill];
291 memset(inc->sample_buffer, 0, inc->sample_unit_size);
292}
293
294static void set_logic_level(struct context *inc, size_t ch_idx, int on)
295{
296 size_t byte_idx, bit_idx;
297 uint8_t bit_mask;
298
299 if (ch_idx >= inc->logic_channels)
300 return;
301 if (!on)
302 return;
303
304 byte_idx = ch_idx / 8;
305 bit_idx = ch_idx % 8;
306 bit_mask = 1 << bit_idx;
307 inc->sample_buffer[byte_idx] |= bit_mask;
308}
309
310static int flush_logic_samples(const struct sr_input *in)
311{
312 struct context *inc;
313 struct sr_datafeed_packet packet;
314 struct sr_datafeed_logic logic;
315 int rc;
316
317 inc = in->priv;
318 if (!inc->datafeed_buf_fill)
319 return SR_OK;
320
321 rc = flush_samplerate(in);
322 if (rc != SR_OK)
323 return rc;
324
325 memset(&packet, 0, sizeof(packet));
326 memset(&logic, 0, sizeof(logic));
327 packet.type = SR_DF_LOGIC;
328 packet.payload = &logic;
329 logic.unitsize = inc->sample_unit_size;
330 logic.length = inc->datafeed_buf_fill;
331 logic.data = inc->datafeed_buffer;
332
333 rc = sr_session_send(in->sdi, &packet);
334 if (rc != SR_OK)
335 return rc;
336
337 inc->datafeed_buf_fill = 0;
338 return SR_OK;
339}
340
341static int queue_logic_samples(const struct sr_input *in)
342{
343 struct context *inc;
344 int rc;
345
346 inc = in->priv;
347 if (!inc->logic_channels)
348 return SR_OK;
349
350 inc->datafeed_buf_fill += inc->sample_unit_size;
351 if (inc->datafeed_buf_fill == inc->datafeed_buf_size) {
352 rc = flush_logic_samples(in);
353 if (rc != SR_OK)
354 return rc;
355 }
356 return SR_OK;
357}
358
359static void set_analog_value(struct context *inc, size_t ch_idx, csv_analog_t value);
360
361static void clear_analog_samples(struct context *inc)
362{
363 size_t idx;
364
365 if (!inc->analog_channels)
366 return;
367 inc->analog_sample_buffer = &inc->analog_datafeed_buffer[inc->analog_datafeed_buf_fill];
368 for (idx = 0; idx < inc->analog_channels; idx++)
369 set_analog_value(inc, idx, 0.0);
370}
371
372static void set_analog_value(struct context *inc, size_t ch_idx, csv_analog_t value)
373{
374 if (ch_idx >= inc->analog_channels)
375 return;
376 if (!value)
377 return;
378 inc->analog_sample_buffer[ch_idx * inc->analog_datafeed_buf_size] = value;
379}
380
381static int flush_analog_samples(const struct sr_input *in)
382{
383 struct context *inc;
384 struct sr_datafeed_packet packet;
385 struct sr_datafeed_analog analog;
386 struct sr_analog_encoding encoding;
387 struct sr_analog_meaning meaning;
388 struct sr_analog_spec spec;
389 csv_analog_t *samples;
390 size_t ch_idx;
391 int digits;
392 int rc;
393
394 inc = in->priv;
395 if (!inc->analog_datafeed_buf_fill)
396 return SR_OK;
397
398 rc = flush_samplerate(in);
399 if (rc != SR_OK)
400 return rc;
401
402 samples = inc->analog_datafeed_buffer;
403 for (ch_idx = 0; ch_idx < inc->analog_channels; ch_idx++) {
404 digits = inc->analog_datafeed_digits[ch_idx];
405 sr_analog_init(&analog, &encoding, &meaning, &spec, digits);
406 memset(&packet, 0, sizeof(packet));
407 packet.type = SR_DF_ANALOG;
408 packet.payload = &analog;
409 analog.num_samples = inc->analog_datafeed_buf_fill;
410 analog.data = samples;
411 analog.meaning->channels = inc->analog_datafeed_channels[ch_idx];
412 analog.meaning->mq = 0;
413 analog.meaning->mqflags = 0;
414 analog.meaning->unit = 0;
415 analog.encoding->unitsize = sizeof(samples[0]);
416 analog.encoding->is_signed = TRUE;
417 analog.encoding->is_float = TRUE;
418#ifdef WORDS_BIGENDIAN
419 analog.encoding->is_bigendian = TRUE;
420#else
421 analog.encoding->is_bigendian = FALSE;
422#endif
423 analog.encoding->digits = spec.spec_digits;
424 rc = sr_session_send(in->sdi, &packet);
425 if (rc != SR_OK)
426 return rc;
427 samples += inc->analog_datafeed_buf_size;
428 }
429
430 inc->analog_datafeed_buf_fill = 0;
431 return SR_OK;
432}
433
434static int queue_analog_samples(const struct sr_input *in)
435{
436 struct context *inc;
437 int rc;
438
439 inc = in->priv;
440 if (!inc->analog_channels)
441 return SR_OK;
442
443 inc->analog_datafeed_buf_fill++;
444 if (inc->analog_datafeed_buf_fill == inc->analog_datafeed_buf_size) {
445 rc = flush_analog_samples(in);
446 if (rc != SR_OK)
447 return rc;
448 }
449 return SR_OK;
450}
451
452/* Helpers for "column processing". */
453
454static int split_column_format(const char *spec,
455 size_t *column_count, enum single_col_format *format, size_t *bit_count)
456{
457 size_t count;
458 char *endp, format_char;
459 enum single_col_format format_code;
460
461 if (!spec || !*spec)
462 return SR_ERR_ARG;
463
464 /* Get the (optional, decimal, default 1) column count. Accept '*'. */
465 endp = NULL;
466 if (*spec == '*') {
467 /* Workaround, strtoul("*") won't always yield expected endp. */
468 count = 0;
469 endp = (char *)&spec[1];
470 } else {
471 count = strtoul(spec, &endp, 10);
472 }
473 if (!endp)
474 return SR_ERR_ARG;
475 if (endp == spec)
476 count = 1;
477 if (column_count)
478 *column_count = count;
479 spec = endp;
480
481 /* Get the (mandatory, single letter) type spec (-/xob/l). */
482 format_char = *spec++;
483 switch (format_char) {
484 case '-':
485 case '/':
486 format_char = '-';
487 format_code = FORMAT_NONE;
488 break;
489 case 'x':
490 format_code = FORMAT_HEX;
491 break;
492 case 'o':
493 format_code = FORMAT_OCT;
494 break;
495 case 'b':
496 case 'l':
497 format_code = FORMAT_BIN;
498 break;
499 case 'a':
500 format_code = FORMAT_ANALOG;
501 break;
502 default: /* includes NUL */
503 return SR_ERR_ARG;
504 }
505 if (format)
506 *format = format_code;
507
508 /* Get the (optional, decimal, default 1) bit count. */
509 endp = NULL;
510 count = strtoul(spec, &endp, 10);
511 if (!endp)
512 return SR_ERR_ARG;
513 if (endp == spec)
514 count = format_is_analog(format_code) ? 3 : 1;
515 if (format_is_ignore(format_code))
516 count = 0;
517 if (format_char == 'l')
518 count = 1;
519 if (bit_count)
520 *bit_count = count;
521 spec = endp;
522
523 /* Input spec must have been exhausted. */
524 if (*spec)
525 return SR_ERR_ARG;
526
527 return SR_OK;
528}
529
530static int make_column_details_from_format(const struct sr_input *in,
531 const char *column_format, char **column_texts)
532{
533 struct context *inc;
534 char **formats, *format;
535 size_t format_count, column_count, logic_count, analog_count;
536 size_t auto_column_count;
537 size_t format_idx, c, b, column_idx, channel_idx, analog_idx;
538 enum single_col_format f;
539 struct column_details *detail;
540 GString *channel_name;
541 size_t create_idx;
542 char *column;
543 const char *caption;
544 int channel_type, channel_sdi_nr;
545 int ret;
546
547 inc = in->priv;
548 inc->column_seen_count = g_strv_length(column_texts);
549
550 /* Split the input spec, count involved columns and bits. */
551 formats = g_strsplit(column_format, ",", 0);
552 if (!formats) {
553 sr_err("Cannot parse columns format %s (comma split).", column_format);
554 return SR_ERR_ARG;
555 }
556 format_count = g_strv_length(formats);
557 if (!format_count) {
558 sr_err("Cannot parse columns format %s (field count).", column_format);
559 g_strfreev(formats);
560 return SR_ERR_ARG;
561 }
562 column_count = logic_count = analog_count = 0;
563 auto_column_count = 0;
564 for (format_idx = 0; format_idx < format_count; format_idx++) {
565 format = formats[format_idx];
566 ret = split_column_format(format, &c, &f, &b);
567 sr_dbg("fmt %s -> %zu cols, %s fmt, %zu bits, rc %d", format, c, col_format_text[f], b, ret);
568 if (ret != SR_OK) {
569 sr_err("Cannot parse columns format %s (field split, %s).", column_format, format);
570 g_strfreev(formats);
571 return SR_ERR_ARG;
572 }
573 if (f && !c) {
574 /* User requested "auto-count", must be last format. */
575 if (formats[format_idx + 1]) {
576 sr_err("Auto column count must be last format field.");
577 g_strfreev(formats);
578 return SR_ERR_ARG;
579 }
580 auto_column_count = inc->column_seen_count - column_count;
581 c = auto_column_count;
582 }
583 column_count += c;
584 if (format_is_analog(f))
585 analog_count += c;
586 else if (format_is_logic(f))
587 logic_count += c * b;
588 }
589 sr_dbg("Column format %s -> %zu columns, %zu logic, %zu analog channels.",
590 column_format, column_count, logic_count, analog_count);
591
592 /* Allocate and fill in "column processing" details. Create channels. */
593 inc->column_want_count = column_count;
594 if (inc->column_seen_count < inc->column_want_count) {
595 sr_err("Insufficient input text width for desired data amount, got %zu but want %zu columns.",
596 inc->column_seen_count, inc->column_want_count);
597 g_strfreev(formats);
598 return SR_ERR_ARG;
599 }
600 inc->column_details = g_malloc0_n(column_count, sizeof(inc->column_details[0]));
601 column_idx = channel_idx = analog_idx = 0;
602 channel_name = g_string_sized_new(64);
603 for (format_idx = 0; format_idx < format_count; format_idx++) {
604 /* Process a format field, which can span multiple columns. */
605 format = formats[format_idx];
606 (void)split_column_format(format, &c, &f, &b);
607 if (f && !c)
608 c = auto_column_count;
609 while (c-- > 0) {
610 /* Fill in a column's processing details. */
611 detail = &inc->column_details[column_idx++];
612 detail->col_nr = column_idx;
613 detail->text_format = f;
614 if (format_is_analog(detail->text_format)) {
615 detail->channel_offset = analog_idx;
616 detail->channel_count = 1;
617 detail->analog_digits = b;
618 analog_idx += detail->channel_count;
619 } else if (format_is_logic(detail->text_format)) {
620 detail->channel_offset = channel_idx;
621 detail->channel_count = b;
622 channel_idx += detail->channel_count;
623 } else if (format_is_ignore(detail->text_format)) {
624 /* EMPTY */
625 continue;
626 } else {
627 /*
628 * Neither logic nor analog data, nor ignore.
629 * Format was noted. No channel creation involved.
630 */
631 continue;
632 }
633 /*
634 * Pick most appropriate channel names. Optionally
635 * use text from a header line (when requested by the
636 * user). In the absence of header text, channels are
637 * assigned rather generic names.
638 *
639 * Manipulation of the column's caption (when a header
640 * line is seen) is acceptable, because this header
641 * line won't get processed another time.
642 */
643 column = column_texts[detail->col_nr - 1];
644 if (inc->use_header && column && *column)
645 caption = sr_scpi_unquote_string(column);
646 else
647 caption = NULL;
648 if (!caption || !*caption)
649 caption = NULL;
650 /*
651 * TODO Need we first create _all_ logic channels,
652 * before creating analog channels? Just store the
653 * parameters here (index, type, name) and have the
654 * creation sequence done outside of the format
655 * spec parse loop.
656 */
657 for (create_idx = 0; create_idx < detail->channel_count; create_idx++) {
658 if (caption && detail->channel_count == 1) {
659 g_string_assign(channel_name, caption);
660 } else if (caption) {
661 g_string_printf(channel_name, "%s[%zu]",
662 caption, create_idx);
663 } else {
664 g_string_printf(channel_name, "%zu",
665 detail->channel_offset + create_idx);
666 }
667 if (format_is_analog(detail->text_format)) {
668 channel_sdi_nr = logic_count + detail->channel_offset + create_idx;
669 channel_type = SR_CHANNEL_ANALOG;
670 detail->channel_index = g_slist_length(in->sdi->channels);
671 } else if (format_is_logic(detail->text_format)) {
672 channel_sdi_nr = detail->channel_offset + create_idx;
673 channel_type = SR_CHANNEL_LOGIC;
674 } else {
675 continue;
676 }
677 sr_channel_new(in->sdi, channel_sdi_nr,
678 channel_type, TRUE, channel_name->str);
679 }
680 }
681 }
682 inc->logic_channels = channel_idx;
683 inc->analog_channels = analog_idx;
684 g_string_free(channel_name, TRUE);
685 g_strfreev(formats);
686
687 return SR_OK;
688}
689
690static const struct column_details *lookup_column_details(struct context *inc, size_t nr)
691{
692 if (!inc || !inc->column_details)
693 return NULL;
694 if (!nr || nr > inc->column_want_count)
695 return NULL;
696 return &inc->column_details[nr - 1];
697}
698
699/*
700 * Primitive operations for text input: Strip comments off text lines.
701 * Split text lines into columns. Process input text for individual
702 * columns.
703 */
704
705static void strip_comment(char *buf, const GString *prefix)
706{
707 char *ptr;
708
709 if (!prefix->len)
710 return;
711
712 if ((ptr = strstr(buf, prefix->str))) {
713 *ptr = '\0';
714 g_strstrip(buf);
715 }
716}
717
718/**
719 * @brief Splits a text line into a set of columns.
720 *
721 * @param[in] buf The input text line to split.
722 * @param[in] inc The input module's context.
723 *
724 * @returns An array of strings, representing the columns' text.
725 *
726 * This routine splits a text line on previously determined separators.
727 */
728static char **split_line(char *buf, struct context *inc)
729{
730 return g_strsplit(buf, inc->delimiter->str, 0);
731}
732
733/**
734 * @brief Parse a multi-bit field into several logic channels.
735 *
736 * @param[in] column The input text, a run of bin/hex/oct digits.
737 * @param[in] inc The input module's context.
738 * @param[in] details The column processing details.
739 *
740 * @retval SR_OK Success.
741 * @retval SR_ERR Invalid input data (empty, or format error).
742 *
743 * This routine modifies the logic levels in the current sample set,
744 * based on the text input and a user provided format spec.
745 */
746static int parse_logic(const char *column, struct context *inc,
747 const struct column_details *details)
748{
749 size_t length, ch_rem, ch_idx, ch_inc;
750 const char *rdptr;
751 char c;
752 gboolean valid;
753 const char *type_text;
754 uint8_t bits;
755
756 /*
757 * Prepare to read the digits from the text end towards the start.
758 * A digit corresponds to a variable number of channels (depending
759 * on the value's radix). Prepare the mapping of text digits to
760 * (a number of) logic channels.
761 */
762 length = strlen(column);
763 if (!length) {
764 sr_err("Column %zu in line %zu is empty.", details->col_nr,
765 inc->line_number);
766 return SR_ERR;
767 }
768 rdptr = &column[length];
769 ch_idx = details->channel_offset;
770 ch_rem = details->channel_count;
771
772 /*
773 * Get another digit and derive up to four logic channels' state from
774 * it. Make sure to not process more bits than the column has channels
775 * associated with it.
776 */
777 while (rdptr > column && ch_rem) {
778 /* Check for valid digits according to the input radix. */
779 c = *(--rdptr);
780 switch (details->text_format) {
781 case FORMAT_BIN:
782 valid = g_ascii_isxdigit(c) && c < '2';
783 ch_inc = 1;
784 break;
785 case FORMAT_OCT:
786 valid = g_ascii_isxdigit(c) && c < '8';
787 ch_inc = 3;
788 break;
789 case FORMAT_HEX:
790 valid = g_ascii_isxdigit(c);
791 ch_inc = 4;
792 break;
793 default:
794 valid = FALSE;
795 break;
796 }
797 if (!valid) {
798 type_text = col_format_text[details->text_format];
799 sr_err("Invalid text '%s' in %s type column %zu in line %zu.",
800 column, type_text, details->col_nr, inc->line_number);
801 return SR_ERR;
802 }
803 /* Use the digit's bits for logic channels' data. */
804 bits = g_ascii_xdigit_value(c);
805 switch (details->text_format) {
806 case FORMAT_HEX:
807 if (ch_rem >= 4) {
808 ch_rem--;
809 set_logic_level(inc, ch_idx + 3, bits & (1 << 3));
810 }
811 /* FALLTHROUGH */
812 case FORMAT_OCT:
813 if (ch_rem >= 3) {
814 ch_rem--;
815 set_logic_level(inc, ch_idx + 2, bits & (1 << 2));
816 }
817 if (ch_rem >= 2) {
818 ch_rem--;
819 set_logic_level(inc, ch_idx + 1, bits & (1 << 1));
820 }
821 /* FALLTHROUGH */
822 case FORMAT_BIN:
823 ch_rem--;
824 set_logic_level(inc, ch_idx + 0, bits & (1 << 0));
825 break;
826 default:
827 /* ShouldNotHappen(TM), but silences compiler warning. */
828 return SR_ERR;
829 }
830 ch_idx += ch_inc;
831 }
832 /*
833 * TODO Determine whether the availability of extra input data
834 * for unhandled logic channels is worth warning here. In this
835 * implementation users are in control, and can have the more
836 * significant bits ignored (which can be considered a feature
837 * and not really a limitation).
838 */
839
840 return SR_OK;
841}
842
843/**
844 * @brief Parse a floating point text into an analog value.
845 *
846 * @param[in] column The input text, a floating point number.
847 * @param[in] inc The input module's context.
848 * @param[in] details The column processing details.
849 *
850 * @retval SR_OK Success.
851 * @retval SR_ERR Invalid input data (empty, or format error).
852 *
853 * This routine modifies the analog values in the current sample set,
854 * based on the text input and a user provided format spec.
855 */
856static int parse_analog(const char *column, struct context *inc,
857 const struct column_details *details)
858{
859 size_t length;
860 double dvalue; float fvalue;
861 csv_analog_t value;
862 int ret;
863
864 if (!format_is_analog(details->text_format))
865 return SR_ERR_BUG;
866
867 length = strlen(column);
868 if (!length) {
869 sr_err("Column %zu in line %zu is empty.", details->col_nr,
870 inc->line_number);
871 return SR_ERR;
872 }
873 if (sizeof(value) == sizeof(double)) {
874 ret = sr_atod_ascii(column, &dvalue);
875 value = dvalue;
876 } else if (sizeof(value) == sizeof(float)) {
877 ret = sr_atof_ascii(column, &fvalue);
878 value = fvalue;
879 } else {
880 ret = SR_ERR_BUG;
881 }
882 if (ret != SR_OK) {
883 sr_err("Cannot parse analog text %s in column %zu in line %zu.",
884 column, details->col_nr, inc->line_number);
885 return SR_ERR_DATA;
886 }
887 set_analog_value(inc, details->channel_offset, value);
888
889 return SR_OK;
890}
891
892/**
893 * @brief Parse routine which ignores the input text.
894 *
895 * This routine exists to unify dispatch code paths, mapping input file
896 * columns' data types to their respective parse routines.
897 */
898static int parse_ignore(const char *column, struct context *inc,
899 const struct column_details *details)
900{
901 (void)column;
902 (void)inc;
903 (void)details;
904 return SR_OK;
905}
906
907typedef int (*col_parse_cb)(const char *column, struct context *inc,
908 const struct column_details *details);
909
910static const col_parse_cb col_parse_funcs[] = {
911 [FORMAT_NONE] = parse_ignore,
912 [FORMAT_BIN] = parse_logic,
913 [FORMAT_OCT] = parse_logic,
914 [FORMAT_HEX] = parse_logic,
915 [FORMAT_ANALOG] = parse_analog,
916};
917
918static int init(struct sr_input *in, GHashTable *options)
919{
920 struct context *inc;
921 size_t single_column, first_column, logic_channels;
922 const char *s;
923 enum single_col_format format;
924 char format_char;
925
926 in->sdi = g_malloc0(sizeof(*in->sdi));
927 in->priv = inc = g_malloc0(sizeof(*inc));
928
929 single_column = g_variant_get_uint32(g_hash_table_lookup(options, "single_column"));
930 logic_channels = g_variant_get_uint32(g_hash_table_lookup(options, "logic_channels"));
931 inc->delimiter = g_string_new(g_variant_get_string(
932 g_hash_table_lookup(options, "column_separator"), NULL));
933 if (!inc->delimiter->len) {
934 sr_err("Column separator cannot be empty.");
935 return SR_ERR_ARG;
936 }
937 s = g_variant_get_string(g_hash_table_lookup(options, "single_format"), NULL);
938 if (g_ascii_strncasecmp(s, "bin", 3) == 0) {
939 format = FORMAT_BIN;
940 } else if (g_ascii_strncasecmp(s, "hex", 3) == 0) {
941 format = FORMAT_HEX;
942 } else if (g_ascii_strncasecmp(s, "oct", 3) == 0) {
943 format = FORMAT_OCT;
944 } else {
945 sr_err("Invalid single-column format: '%s'", s);
946 return SR_ERR_ARG;
947 }
948 inc->comment = g_string_new(g_variant_get_string(
949 g_hash_table_lookup(options, "comment_leader"), NULL));
950 if (g_string_equal(inc->comment, inc->delimiter)) {
951 /*
952 * Using the same sequence as comment leader and column
953 * separator won't work. The user probably specified ';'
954 * as the column separator but did not adjust the comment
955 * leader. Try DWIM, drop comment strippin support here.
956 */
957 sr_warn("Comment leader and column separator conflict, disabling comment support.");
958 g_string_truncate(inc->comment, 0);
959 }
960 inc->samplerate = g_variant_get_uint64(g_hash_table_lookup(options, "samplerate"));
961 first_column = g_variant_get_uint32(g_hash_table_lookup(options, "first_column"));
962 inc->use_header = g_variant_get_boolean(g_hash_table_lookup(options, "header"));
963 inc->start_line = g_variant_get_uint32(g_hash_table_lookup(options, "start_line"));
964 if (inc->start_line < 1) {
965 sr_err("Invalid start line %zu.", inc->start_line);
966 return SR_ERR_ARG;
967 }
968
969 /*
970 * Scan flexible, to get prefered format specs which describe
971 * the input file's data formats. As well as some simple specs
972 * for backwards compatibility and user convenience.
973 *
974 * This logic ends up with a copy of the format string, either
975 * user provided or internally derived. Actual creation of the
976 * column processing details gets deferred until the first line
977 * of input data was seen. To support automatic determination of
978 * e.g. channel counts from column counts.
979 */
980 s = g_variant_get_string(g_hash_table_lookup(options, "column_formats"), NULL);
981 if (s && *s) {
982 inc->column_formats = g_strdup(s);
983 sr_dbg("User specified column_formats: %s.", s);
984 } else if (single_column && logic_channels) {
985 format_char = col_format_char[format];
986 if (single_column == 1) {
987 inc->column_formats = g_strdup_printf("%c%zu",
988 format_char, logic_channels);
989 } else {
990 inc->column_formats = g_strdup_printf("%zu-,%c%zu",
991 single_column - 1,
992 format_char, logic_channels);
993 }
994 sr_dbg("Backwards compat single_column, col %zu, fmt %s, bits %zu -> %s.",
995 single_column, col_format_text[format], logic_channels,
996 inc->column_formats);
997 } else if (!single_column) {
998 if (first_column > 1) {
999 inc->column_formats = g_strdup_printf("%zu-,%zul",
1000 first_column - 1, logic_channels);
1001 } else {
1002 inc->column_formats = g_strdup_printf("%zul",
1003 logic_channels);
1004 }
1005 sr_dbg("Backwards compat multi-column, col %zu, chans %zu -> %s.",
1006 first_column, logic_channels,
1007 inc->column_formats);
1008 } else {
1009 sr_warn("Unknown or unsupported columns layout spec, assuming simple multi-column mode.");
1010 inc->column_formats = g_strdup("*l");
1011 }
1012
1013 return SR_OK;
1014}
1015
1016/*
1017 * Check the channel list for consistency across file re-import. See
1018 * the VCD input module for more details and motivation.
1019 */
1020
1021static void keep_header_for_reread(const struct sr_input *in)
1022{
1023 struct context *inc;
1024
1025 inc = in->priv;
1026 g_slist_free_full(inc->prev_sr_channels, sr_channel_free_cb);
1027 inc->prev_sr_channels = in->sdi->channels;
1028 in->sdi->channels = NULL;
1029}
1030
1031static int check_header_in_reread(const struct sr_input *in)
1032{
1033 struct context *inc;
1034
1035 if (!in)
1036 return FALSE;
1037 inc = in->priv;
1038 if (!inc)
1039 return FALSE;
1040 if (!inc->prev_sr_channels)
1041 return TRUE;
1042
1043 if (sr_channel_lists_differ(inc->prev_sr_channels, in->sdi->channels)) {
1044 sr_err("Channel list change not supported for file re-read.");
1045 return FALSE;
1046 }
1047 g_slist_free_full(in->sdi->channels, sr_channel_free_cb);
1048 in->sdi->channels = inc->prev_sr_channels;
1049 inc->prev_sr_channels = NULL;
1050
1051 return TRUE;
1052}
1053
1054static const char *delim_set = "\r\n";
1055
1056static const char *get_line_termination(GString *buf)
1057{
1058 const char *term;
1059
1060 term = NULL;
1061 if (g_strstr_len(buf->str, buf->len, "\r\n"))
1062 term = "\r\n";
1063 else if (memchr(buf->str, '\n', buf->len))
1064 term = "\n";
1065 else if (memchr(buf->str, '\r', buf->len))
1066 term = "\r";
1067
1068 return term;
1069}
1070
1071static int initial_parse(const struct sr_input *in, GString *buf)
1072{
1073 struct context *inc;
1074 size_t num_columns;
1075 size_t line_number, line_idx;
1076 int ret;
1077 char **lines, *line, **columns;
1078
1079 ret = SR_OK;
1080 inc = in->priv;
1081 columns = NULL;
1082
1083 /* Search for the first line to process (header or data). */
1084 line_number = 0;
1085 if (inc->termination)
1086 lines = g_strsplit(buf->str, inc->termination, 0);
1087 else
1088 lines = g_strsplit_set(buf->str, delim_set, 0);
1089 for (line_idx = 0; (line = lines[line_idx]); line_idx++) {
1090 line_number++;
1091 if (inc->start_line > line_number) {
1092 sr_spew("Line %zu skipped (before start).", line_number);
1093 continue;
1094 }
1095 if (line[0] == '\0') {
1096 sr_spew("Blank line %zu skipped.", line_number);
1097 continue;
1098 }
1099 strip_comment(line, inc->comment);
1100 if (line[0] == '\0') {
1101 sr_spew("Comment-only line %zu skipped.", line_number);
1102 continue;
1103 }
1104
1105 /* Reached first proper line. */
1106 break;
1107 }
1108 if (!line) {
1109 /* Not enough data for a proper line yet. */
1110 ret = SR_ERR_NA;
1111 goto out;
1112 }
1113
1114 /* Get the number of columns in the line. */
1115 columns = split_line(line, inc);
1116 if (!columns) {
1117 sr_err("Error while parsing line %zu.", line_number);
1118 ret = SR_ERR;
1119 goto out;
1120 }
1121 num_columns = g_strv_length(columns);
1122 if (!num_columns) {
1123 sr_err("Error while parsing line %zu.", line_number);
1124 ret = SR_ERR;
1125 goto out;
1126 }
1127 sr_dbg("DIAG Got %zu columns in text line: %s.", num_columns, line);
1128
1129 /*
1130 * Interpret the user provided column format specs. This might
1131 * involve inspection of the now received input text, to support
1132 * e.g. automatic detection of channel counts in the absence of
1133 * user provided specs. Optionally a header line is used to get
1134 * channels' names.
1135 *
1136 * Check the then created channels for consistency across .reset
1137 * and .receive sequences (file re-load).
1138 */
1139 ret = make_column_details_from_format(in, inc->column_formats, columns);
1140 if (ret != SR_OK) {
1141 sr_err("Cannot parse columns format using line %zu.", line_number);
1142 goto out;
1143 }
1144 if (!check_header_in_reread(in)) {
1145 ret = SR_ERR_DATA;
1146 goto out;
1147 }
1148
1149 /*
1150 * Allocate buffer memory for datafeed submission of sample data.
1151 * Calculate the minimum buffer size to store the set of samples
1152 * of all channels (unit size). Determine a larger buffer size
1153 * for datafeed submission that is a multiple of the unit size.
1154 * Allocate the larger buffer, the "sample buffer" will point
1155 * to a location within that large buffer later.
1156 *
1157 * TODO Move channel creation here, and just store required
1158 * parameters in the format parser above? Could simplify the
1159 * arrangement that logic and analog channels get created in
1160 * strict sequence in their respective groups.
1161 */
1162 if (inc->logic_channels) {
1163 inc->sample_unit_size = (inc->logic_channels + 7) / 8;
1164 inc->datafeed_buf_size = CHUNK_SIZE;
1165 inc->datafeed_buf_size *= inc->sample_unit_size;
1166 inc->datafeed_buffer = g_malloc(inc->datafeed_buf_size);
1167 if (!inc->datafeed_buffer) {
1168 sr_err("Cannot allocate datafeed send buffer (logic).");
1169 ret = SR_ERR_MALLOC;
1170 goto out;
1171 }
1172 inc->datafeed_buf_fill = 0;
1173 }
1174
1175 if (inc->analog_channels) {
1176 size_t sample_size, sample_count;
1177 size_t detail_idx;
1178 struct column_details *detail;
1179 int *digits_item;
1180 void *channel;
1181 sample_size = sizeof(inc->analog_datafeed_buffer[0]);
1182 inc->analog_datafeed_buf_size = CHUNK_SIZE;
1183 inc->analog_datafeed_buf_size /= sample_size;
1184 inc->analog_datafeed_buf_size /= inc->analog_channels;
1185 sample_count = inc->analog_channels * inc->analog_datafeed_buf_size;
1186 inc->analog_datafeed_buffer = g_malloc0(sample_count * sample_size);
1187 if (!inc->analog_datafeed_buffer) {
1188 sr_err("Cannot allocate datafeed send buffer (analog).");
1189 ret = SR_ERR_MALLOC;
1190 goto out;
1191 }
1192 inc->analog_datafeed_buf_fill = 0;
1193 inc->analog_datafeed_channels = g_malloc0(inc->analog_channels * sizeof(inc->analog_datafeed_channels[0]));
1194 inc->analog_datafeed_digits = g_malloc0(inc->analog_channels * sizeof(inc->analog_datafeed_digits[0]));
1195 digits_item = inc->analog_datafeed_digits;
1196 for (detail_idx = 0; detail_idx < inc->column_want_count; detail_idx++) {
1197 detail = &inc->column_details[detail_idx];
1198 if (!format_is_analog(detail->text_format))
1199 continue;
1200 channel = g_slist_nth_data(in->sdi->channels, detail->channel_index);
1201 inc->analog_datafeed_channels[detail->channel_offset] = g_slist_append(NULL, channel);
1202 *digits_item++ = detail->analog_digits;
1203 }
1204 }
1205
1206out:
1207 if (columns)
1208 g_strfreev(columns);
1209 g_strfreev(lines);
1210
1211 return ret;
1212}
1213
1214/*
1215 * Gets called from initial_receive(), which runs until the end-of-line
1216 * encoding of the input stream could get determined. Assumes that this
1217 * routine receives enough buffered initial input data to either see the
1218 * BOM when there is one, or that no BOM will follow when a text line
1219 * termination sequence was seen. Silently drops the UTF-8 BOM sequence
1220 * from the input buffer if one was seen. Does not care to protect
1221 * against multiple execution or dropping the BOM multiple times --
1222 * there should be at most one in the input stream.
1223 */
1224static void initial_bom_check(const struct sr_input *in)
1225{
1226 static const char *utf8_bom = "\xef\xbb\xbf";
1227
1228 if (in->buf->len < strlen(utf8_bom))
1229 return;
1230 if (strncmp(in->buf->str, utf8_bom, strlen(utf8_bom)) != 0)
1231 return;
1232 g_string_erase(in->buf, 0, strlen(utf8_bom));
1233}
1234
1235static int initial_receive(const struct sr_input *in)
1236{
1237 struct context *inc;
1238 GString *new_buf;
1239 int len, ret;
1240 char *p;
1241 const char *termination;
1242
1243 initial_bom_check(in);
1244
1245 inc = in->priv;
1246
1247 termination = get_line_termination(in->buf);
1248 if (!termination)
1249 /* Don't have a full line yet. */
1250 return SR_ERR_NA;
1251
1252 p = g_strrstr_len(in->buf->str, in->buf->len, termination);
1253 if (!p)
1254 /* Don't have a full line yet. */
1255 return SR_ERR_NA;
1256 len = p - in->buf->str - 1;
1257 new_buf = g_string_new_len(in->buf->str, len);
1258 g_string_append_c(new_buf, '\0');
1259
1260 inc->termination = g_strdup(termination);
1261
1262 if (in->buf->str[0] != '\0')
1263 ret = initial_parse(in, new_buf);
1264 else
1265 ret = SR_OK;
1266
1267 g_string_free(new_buf, TRUE);
1268
1269 return ret;
1270}
1271
1272static int process_buffer(struct sr_input *in, gboolean is_eof)
1273{
1274 struct context *inc;
1275 gsize num_columns;
1276 size_t line_idx, col_idx, col_nr;
1277 const struct column_details *details;
1278 col_parse_cb parse_func;
1279 int ret;
1280 char *p, **lines, *line, **columns, *column;
1281
1282 inc = in->priv;
1283 if (!inc->started) {
1284 std_session_send_df_header(in->sdi);
1285 inc->started = TRUE;
1286 }
1287
1288 /*
1289 * Consider empty input non-fatal. Keep accumulating input until
1290 * at least one full text line has become available. Grab the
1291 * maximum amount of accumulated data that consists of full text
1292 * lines, and process what has been received so far, leaving not
1293 * yet complete lines for the next invocation.
1294 *
1295 * Enforce that all previously buffered data gets processed in
1296 * the "EOF" condition. Do not insist in the presence of the
1297 * termination sequence for the last line (may often be missing
1298 * on Windows). A present termination sequence will just result
1299 * in the "execution of an empty line", and does not harm.
1300 */
1301 if (!in->buf->len)
1302 return SR_OK;
1303 if (is_eof) {
1304 p = in->buf->str + in->buf->len;
1305 } else {
1306 p = g_strrstr_len(in->buf->str, in->buf->len, inc->termination);
1307 if (!p)
1308 return SR_ERR;
1309 *p = '\0';
1310 p += strlen(inc->termination);
1311 }
1312 g_strstrip(in->buf->str);
1313
1314 ret = SR_OK;
1315 lines = g_strsplit(in->buf->str, inc->termination, 0);
1316 for (line_idx = 0; (line = lines[line_idx]); line_idx++) {
1317 inc->line_number++;
1318 if (inc->line_number < inc->start_line) {
1319 sr_spew("Line %zu skipped (before start).", inc->line_number);
1320 continue;
1321 }
1322 if (line[0] == '\0') {
1323 sr_spew("Blank line %zu skipped.", inc->line_number);
1324 continue;
1325 }
1326
1327 /* Remove trailing comment. */
1328 strip_comment(line, inc->comment);
1329 if (line[0] == '\0') {
1330 sr_spew("Comment-only line %zu skipped.", inc->line_number);
1331 continue;
1332 }
1333
1334 /* Skip the header line, its content was used as the channel names. */
1335 if (inc->use_header && !inc->header_seen) {
1336 sr_spew("Header line %zu skipped.", inc->line_number);
1337 inc->header_seen = TRUE;
1338 continue;
1339 }
1340
1341 /* Split the line into columns, check for minimum length. */
1342 columns = split_line(line, inc);
1343 if (!columns) {
1344 sr_err("Error while parsing line %zu.", inc->line_number);
1345 g_strfreev(lines);
1346 return SR_ERR;
1347 }
1348 num_columns = g_strv_length(columns);
1349 if (num_columns < inc->column_want_count) {
1350 sr_err("Insufficient column count %zu in line %zu.",
1351 num_columns, inc->line_number);
1352 g_strfreev(columns);
1353 g_strfreev(lines);
1354 return SR_ERR;
1355 }
1356
1357 /* Have the columns of the current text line processed. */
1358 clear_logic_samples(inc);
1359 clear_analog_samples(inc);
1360 for (col_idx = 0; col_idx < inc->column_want_count; col_idx++) {
1361 column = columns[col_idx];
1362 col_nr = col_idx + 1;
1363 details = lookup_column_details(inc, col_nr);
1364 if (!details || !details->text_format)
1365 continue;
1366 parse_func = col_parse_funcs[details->text_format];
1367 if (!parse_func)
1368 continue;
1369 ret = parse_func(column, inc, details);
1370 if (ret != SR_OK) {
1371 g_strfreev(columns);
1372 g_strfreev(lines);
1373 return SR_ERR;
1374 }
1375 }
1376
1377 /* Send sample data to the session bus (buffered). */
1378 ret = queue_logic_samples(in);
1379 ret += queue_analog_samples(in);
1380 if (ret != SR_OK) {
1381 sr_err("Sending samples failed.");
1382 g_strfreev(columns);
1383 g_strfreev(lines);
1384 return SR_ERR;
1385 }
1386
1387 g_strfreev(columns);
1388 }
1389 g_strfreev(lines);
1390 g_string_erase(in->buf, 0, p - in->buf->str);
1391
1392 return ret;
1393}
1394
1395static int receive(struct sr_input *in, GString *buf)
1396{
1397 struct context *inc;
1398 int ret;
1399
1400 g_string_append_len(in->buf, buf->str, buf->len);
1401
1402 inc = in->priv;
1403 if (!inc->column_seen_count) {
1404 ret = initial_receive(in);
1405 if (ret == SR_ERR_NA)
1406 /* Not enough data yet. */
1407 return SR_OK;
1408 else if (ret != SR_OK)
1409 return SR_ERR;
1410
1411 /* sdi is ready, notify frontend. */
1412 in->sdi_ready = TRUE;
1413 return SR_OK;
1414 }
1415
1416 ret = process_buffer(in, FALSE);
1417
1418 return ret;
1419}
1420
1421static int end(struct sr_input *in)
1422{
1423 struct context *inc;
1424 int ret;
1425
1426 if (in->sdi_ready)
1427 ret = process_buffer(in, TRUE);
1428 else
1429 ret = SR_OK;
1430 if (ret != SR_OK)
1431 return ret;
1432
1433 ret = flush_logic_samples(in);
1434 ret += flush_analog_samples(in);
1435 if (ret != SR_OK)
1436 return ret;
1437
1438 inc = in->priv;
1439 if (inc->started)
1440 std_session_send_df_end(in->sdi);
1441
1442 return ret;
1443}
1444
1445static void cleanup(struct sr_input *in)
1446{
1447 struct context *inc;
1448
1449 keep_header_for_reread(in);
1450
1451 inc = in->priv;
1452
1453 g_free(inc->termination);
1454 inc->termination = NULL;
1455 g_free(inc->datafeed_buffer);
1456 inc->datafeed_buffer = NULL;
1457 g_free(inc->analog_datafeed_buffer);
1458 inc->analog_datafeed_buffer = NULL;
1459}
1460
1461static int reset(struct sr_input *in)
1462{
1463 struct context *inc = in->priv;
1464
1465 cleanup(in);
1466 inc->started = FALSE;
1467 g_string_truncate(in->buf, 0);
1468
1469 return SR_OK;
1470}
1471
1472enum option_index {
1473 OPT_COL_FMTS,
1474 OPT_SINGLE_COL,
1475 OPT_FIRST_COL,
1476 OPT_NUM_LOGIC,
1477 OPT_FORMAT,
1478 OPT_START,
1479 OPT_HEADER,
1480 OPT_RATE,
1481 OPT_DELIM,
1482 OPT_COMMENT,
1483 OPT_MAX,
1484};
1485
1486static struct sr_option options[] = {
1487 [OPT_COL_FMTS] = {
1488 "column_formats", "Column format specs",
1489 "Specifies text columns data types: A comma separated list of [<cols>]<fmt>[<bits>] items, with - to ignore columns, x/o/b/l for logic data, a (and resolution) for analog data.",
1490 NULL, NULL,
1491 },
1492 [OPT_SINGLE_COL] = {
1493 "single_column", "Single column",
1494 "Enable single-column mode, exclusively use text from the specified column (number starting at 1). Obsoleted by 'column_formats'.",
1495 NULL, NULL,
1496 },
1497 [OPT_FIRST_COL] = {
1498 "first_column", "First column",
1499 "Number of the first column with logic data in simple multi-column mode (number starting at 1, default 1). Obsoleted by 'column_formats'.",
1500 NULL, NULL,
1501 },
1502 [OPT_NUM_LOGIC] = {
1503 "logic_channels", "Number of logic channels",
1504 "Logic channel count, required in simple single-column mode, defaults to \"all remaining columns\" in simple multi-column mode. Obsoleted by 'column_formats'.",
1505 NULL, NULL,
1506 },
1507 [OPT_FORMAT] = {
1508 "single_format", "Data format for simple single-column mode.",
1509 "The number format of single-column mode input data: bin, hex, oct. Obsoleted by 'column_formats'.",
1510 NULL, NULL,
1511 },
1512 [OPT_START] = {
1513 "start_line", "Start line",
1514 "The line number at which to start processing input text (default: 1).",
1515 NULL, NULL,
1516 },
1517 [OPT_HEADER] = {
1518 "header", "Get channel names from first line.",
1519 "Use the first processed line's column captions (when available) as channel names. Off by default",
1520 NULL, NULL,
1521 },
1522 [OPT_RATE] = {
1523 "samplerate", "Samplerate (Hz)",
1524 "The input data's sample rate in Hz. No default value.",
1525 NULL, NULL,
1526 },
1527 [OPT_DELIM] = {
1528 "column_separator", "Column separator",
1529 "The sequence which separates text columns. Non-empty text, comma by default.",
1530 NULL, NULL,
1531 },
1532 [OPT_COMMENT] = {
1533 "comment_leader", "Comment leader character",
1534 "The text which starts comments at the end of text lines, semicolon by default.",
1535 NULL, NULL,
1536 },
1537 [OPT_MAX] = ALL_ZERO,
1538};
1539
1540static const struct sr_option *get_options(void)
1541{
1542 GSList *l;
1543
1544 if (!options[0].def) {
1545 options[OPT_COL_FMTS].def = g_variant_ref_sink(g_variant_new_string(""));
1546 options[OPT_SINGLE_COL].def = g_variant_ref_sink(g_variant_new_uint32(0));
1547 options[OPT_FIRST_COL].def = g_variant_ref_sink(g_variant_new_uint32(1));
1548 options[OPT_NUM_LOGIC].def = g_variant_ref_sink(g_variant_new_uint32(0));
1549 options[OPT_FORMAT].def = g_variant_ref_sink(g_variant_new_string("bin"));
1550 l = NULL;
1551 l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("bin")));
1552 l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("hex")));
1553 l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("oct")));
1554 options[OPT_FORMAT].values = l;
1555 options[OPT_START].def = g_variant_ref_sink(g_variant_new_uint32(1));
1556 options[OPT_HEADER].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
1557 options[OPT_RATE].def = g_variant_ref_sink(g_variant_new_uint64(0));
1558 options[OPT_DELIM].def = g_variant_ref_sink(g_variant_new_string(","));
1559 options[OPT_COMMENT].def = g_variant_ref_sink(g_variant_new_string(";"));
1560 }
1561
1562 return options;
1563}
1564
1565SR_PRIV struct sr_input_module input_csv = {
1566 .id = "csv",
1567 .name = "CSV",
1568 .desc = "Comma-separated values",
1569 .exts = (const char*[]){"csv", NULL},
1570 .options = get_options,
1571 .init = init,
1572 .receive = receive,
1573 .end = end,
1574 .cleanup = cleanup,
1575 .reset = reset,
1576};