]> sigrok.org Git - libsigrok.git/blame - src/input/csv.c
kingst-la2016: style nits, remove not needed include directives
[libsigrok.git] / src / input / csv.c
CommitLineData
4a35548b
MS
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2013 Marc Schink <sigrok-dev@marcschink.de>
e53f32d2 5 * Copyright (C) 2019 Gerhard Sittig <gerhard.sittig@gmx.net>
4a35548b
MS
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
e05f1827
GS
21#include "config.h"
22
cd7c5f96 23#include <ctype.h>
e05f1827 24#include <glib.h>
4a35548b
MS
25#include <stdlib.h>
26#include <string.h>
cd7c5f96 27#include <strings.h>
e05f1827 28
c1aae900 29#include <libsigrok/libsigrok.h>
4a35548b 30#include "libsigrok-internal.h"
f6dcb320 31#include "scpi.h" /* String un-quote for channel name from header line. */
4a35548b 32
3544f848 33#define LOG_PREFIX "input/csv"
4a35548b 34
9a4fd01a 35#define CHUNK_SIZE (4 * 1024 * 1024)
cd59e6ec 36
4a35548b
MS
37/*
38 * The CSV input module has the following options:
39 *
72903e9d
GS
40 * column_formats: Specifies the data formats and channel counts for the
41 * input file's text columns. Accepts a comma separated list of tuples
42 * with: an optional column repeat count ('*' as a wildcard meaning
43 * "all remaining columns", only applicable to the last field), a format
44 * specifying character ('x' hexadecimal, 'o' octal, 'b' binary, 'l'
45 * single-bit logic), and an optional bit count (translating to: logic
08eb955a
GS
46 * channels communicated in that column). The 'a' format marks analog
47 * data, an optionally following number is the digits count (resolution).
7e4e65bf
GS
48 * The 't' format marks timestamp values, which could help in automatic
49 * determination of the input stream's samplerate. This "column_formats"
50 * option is most versatile, other forms of specifying the column layout
51 * only exist for backwards compatibility, and are rather limited. They
52 * exclusively support logic input data in strictly adjacent columns,
53 * with further constraints on column layout for multi-bit data.
4a35548b 54 *
72903e9d
GS
55 * single_column: Specifies the column number which contains the logic data
56 * for single-column mode. All logic data is taken from several bits
57 * which all are kept within that one column. Only exists for backwards
58 * compatibility, see "column_formats" for more flexibility.
4a35548b 59 *
72903e9d
GS
60 * first_column: Specifies the number of the first column with logic data
61 * in simple multi-column mode. Only exists for backwards compatibility,
62 * see "column_formats" for more flexibility.
4a35548b 63 *
72903e9d
GS
64 * logic_channels: Specifies the number of logic channels. Is required in
65 * simple single-column mode. Is optional in simple multi-column mode
66 * (and defaults to all remaining columns). Only exists for backwards
67 * compatibility, see "column_formats" for more flexibility.
4a35548b 68 *
72903e9d
GS
69 * single_format: Specifies the format of the input text in simple single-
70 * column mode. Available formats are: 'bin' (default), 'hex' and 'oct'.
71 * Simple multi-column mode always uses single-bit data per column.
72 * Only exists for backwards compatibility, see "column_formats" for
73 * more flexibility.
4a35548b 74 *
72903e9d
GS
75 * start_line: Specifies at which line to start processing the input file.
76 * Allows to skip leading lines which neither are header nor data lines.
77 * By default all of the input file gets processed.
4a35548b 78 *
72903e9d
GS
79 * header: Boolean option, controls whether the first processed line is used
80 * to determine channel names. Off by default. Generic channel names are
81 * used in the absence of header line content.
4a35548b 82 *
72903e9d
GS
83 * samplerate: Specifies the samplerate of the input data. Defaults to 0.
84 * User specs take precedence over data which optionally gets derived
85 * from input data.
4a35548b 86 *
72903e9d
GS
87 * column_separator: Specifies the sequence which separates the text file
88 * columns. Cannot be empty. Defaults to comma.
89 *
90 * comment_leader: Specifies the sequence which starts comments that run
91 * up to the end of the current text line. Can be empty to disable
92 * comment support. Defaults to semicolon.
93 *
94 * Typical examples of using these options:
95 * - ... -I csv:column_formats=*l ...
96 * All columns are single-bit logic data. Identical to the previous
97 * multi-column mode (the default when no options were given at all).
98 * - ... -I csv:column_formats=3-,*l ...
99 * Ignore the first three columns, get single-bit logic data from all
100 * remaining lines (multi-column mode with first-column above 1).
101 * - ... -I csv:column_formats=3-,4l,x8 ...
102 * Ignore the first three columns, get single-bit logic data from the
103 * next four columns, then eight-bit data in hex format from the next
104 * column. More columns may follow in the input text but won't get
105 * processed. (Mix of previous multi-column as well as single-column
106 * modes.)
107 * - ... -I csv:column_formats=4x8,b16,5l ...
108 * Get eight-bit data in hex format from the first four columns, then
109 * sixteen-bit data in binary format, then five times single-bit data.
110 * - ... -I csv:single_column=2:single_format=bin:logic_channels=8 ...
111 * Get eight logic bits in binary format from column 2. (Simple
112 * single-column mode, corresponds to the "-,b8" format.)
113 * - ... -I csv:first_column=6:logic_channels=4 ...
114 * Get four single-bit logic channels from columns 6 to 9 respectively.
115 * (Simple multi-column mode, corresponds to the "5-,4b" format.)
116 * - ... -I csv:start_line=20:header=yes:...
117 * Skip the first 19 text lines. Use line 20 to derive channel names.
118 * Data starts at line 21.
08eb955a
GS
119 * - ... -I csv:column_formats=*a6 ...
120 * Each column contains an analog value with six significant digits
121 * after the decimal period.
7e4e65bf
GS
122 * - ... -I csv:column_formats=t,2a ...
123 * The first column contains timestamps, the next two columns contain
124 * analog values. The capture's samplerate could get determined from
125 * the timestamp values if not provided by the user by means of the
126 * 'samplerate' option. This assumes a mere number in units of seconds,
127 * and equidistant rows, there is no fancy support for textual unit
128 * suffixes nor gaps in the stream of samples nor other non-linearity,
129 * just '-' ignore the column if the format is not supported).
cb3b8051
GS
130 *
131 * IMPORTANT! Make sure the .format_match() logic matches the default
132 * values for the input module's options. Ideally the format match test
133 * shall pass for all input data that is supported by default.
4a35548b
MS
134 */
135
ccff468b
GS
136/*
137 * TODO
138 *
5a971176
GS
139 * - Add a test suite for input modules in general, and CSV in specific?
140 * Becomes more important with the multitude of options and their
141 * interaction. Could cover edge cases (BOM presence, line termination
142 * absence, etc) and auto-stuff as well (channel names, channel counts,
143 * samplerates, etc).
ccff468b
GS
144 */
145
ce3fe379 146typedef double csv_analog_t;
43bdef26 147
4a35548b 148/* Single column formats. */
ad6a2bee 149enum single_col_format {
e53f32d2
GS
150 FORMAT_NONE, /* Ignore this column. */
151 FORMAT_BIN, /* Bin digits for a set of bits (or just one bit). */
152 FORMAT_HEX, /* Hex digits for a set of bits. */
153 FORMAT_OCT, /* Oct digits for a set of bits. */
43bdef26 154 FORMAT_ANALOG, /* Floating point number for an analog channel. */
7e4e65bf 155 FORMAT_TIME, /* Timestamps. */
e53f32d2
GS
156};
157
158static const char *col_format_text[] = {
159 [FORMAT_NONE] = "unknown",
160 [FORMAT_BIN] = "binary",
161 [FORMAT_HEX] = "hexadecimal",
162 [FORMAT_OCT] = "octal",
43bdef26 163 [FORMAT_ANALOG] = "analog",
7e4e65bf 164 [FORMAT_TIME] = "timestamp",
e53f32d2
GS
165};
166
1a920e33
GS
167static const char col_format_char[] = {
168 [FORMAT_NONE] = '?',
169 [FORMAT_BIN] = 'b',
170 [FORMAT_HEX] = 'x',
171 [FORMAT_OCT] = 'o',
43bdef26 172 [FORMAT_ANALOG] = 'a',
7e4e65bf 173 [FORMAT_TIME] = 't',
1a920e33
GS
174};
175
fc3b42e9
GS
176static gboolean format_is_ignore(enum single_col_format fmt)
177{
178 return fmt == FORMAT_NONE;
179}
180
181static gboolean format_is_logic(enum single_col_format fmt)
182{
183 return fmt >= FORMAT_BIN && fmt <= FORMAT_OCT;
184}
185
186static gboolean format_is_analog(enum single_col_format fmt)
187{
188 return fmt == FORMAT_ANALOG;
189}
190
7e4e65bf
GS
191static gboolean format_is_timestamp(enum single_col_format fmt)
192{
193 return fmt == FORMAT_TIME;
194}
195
e53f32d2
GS
196struct column_details {
197 size_t col_nr;
198 enum single_col_format text_format;
199 size_t channel_offset;
200 size_t channel_count;
a267bf45 201 int analog_digits;
05719d75 202 GString **channel_names;
4a35548b
MS
203};
204
205struct context {
41d214f6
BV
206 gboolean started;
207
7e4e65bf 208 /* Current samplerate, optionally determined from input data. */
4a35548b 209 uint64_t samplerate;
811dcf7e 210 uint64_t calc_samplerate;
7e4e65bf 211 double prev_timestamp;
246aca5f 212 gboolean samplerate_sent;
4a35548b 213
a267bf45 214 /* Number of channels. */
836fac9c 215 size_t logic_channels;
43bdef26 216 size_t analog_channels;
4a35548b 217
836fac9c 218 /* Column delimiter (actually separator), comment leader, EOL sequence. */
4a35548b 219 GString *delimiter;
4a35548b 220 GString *comment;
41d214f6
BV
221 char *termination;
222
1a920e33
GS
223 /* Format specs for input columns, and processing state. */
224 size_t column_seen_count;
225 const char *column_formats;
e53f32d2
GS
226 size_t column_want_count;
227 struct column_details *column_details;
228
4a35548b 229 /* Line number to start processing. */
6433156c 230 size_t start_line;
4a35548b
MS
231
232 /*
233 * Determines if the first line should be treated as header and used for
ba7dd8bb 234 * channel names in multi column mode.
4a35548b 235 */
de8fe3b5
GS
236 gboolean use_header;
237 gboolean header_seen;
4a35548b 238
cd59e6ec
GS
239 size_t sample_unit_size; /**!< Byte count for a single sample. */
240 uint8_t *sample_buffer; /**!< Buffer for a single sample. */
43bdef26 241 csv_analog_t *analog_sample_buffer; /**!< Buffer for one set of analog values. */
4a35548b 242
cd59e6ec
GS
243 uint8_t *datafeed_buffer; /**!< Queue for datafeed submission. */
244 size_t datafeed_buf_size;
245 size_t datafeed_buf_fill;
43bdef26
GS
246 /* "Striped" layout, M samples for N channels each. */
247 csv_analog_t *analog_datafeed_buffer; /**!< Queue for analog datafeed. */
248 size_t analog_datafeed_buf_size;
249 size_t analog_datafeed_buf_fill;
a267bf45 250 int *analog_datafeed_digits;
05719d75 251 GSList **analog_datafeed_channels;
4a35548b 252
4a35548b 253 /* Current line number. */
6433156c 254 size_t line_number;
affaf540
GS
255
256 /* List of previously created sigrok channels. */
257 GSList *prev_sr_channels;
307b2393 258 GSList **prev_df_channels;
4a35548b
MS
259};
260
626c388a
GS
261/*
262 * Primitive operations to handle sample sets:
263 * - Keep a buffer for datafeed submission, capable of holding many
264 * samples (reduces call overhead, improves throughput).
265 * - Have a "current sample set" pointer reference one position in that
266 * large samples buffer.
267 * - Clear the current sample set before text line inspection, then set
268 * the bits which are found active in the current line of text input.
269 * Phrase the API such that call sites can be kept simple. Advance to
270 * the next sample set between lines, flush the larger buffer as needed
271 * (when it is full, or upon EOF).
272 */
273
43bdef26
GS
274static int flush_samplerate(const struct sr_input *in)
275{
276 struct context *inc;
43bdef26
GS
277
278 inc = in->priv;
811dcf7e
GS
279 if (!inc->calc_samplerate && inc->samplerate)
280 inc->calc_samplerate = inc->samplerate;
281 if (inc->calc_samplerate && !inc->samplerate_sent) {
f8a8d4bb
GS
282 (void)sr_session_send_meta(in->sdi, SR_CONF_SAMPLERATE,
283 g_variant_new_uint64(inc->calc_samplerate));
43bdef26
GS
284 inc->samplerate_sent = TRUE;
285 }
286
287 return SR_OK;
288}
289
626c388a
GS
290static void clear_logic_samples(struct context *inc)
291{
43bdef26
GS
292 if (!inc->logic_channels)
293 return;
626c388a
GS
294 inc->sample_buffer = &inc->datafeed_buffer[inc->datafeed_buf_fill];
295 memset(inc->sample_buffer, 0, inc->sample_unit_size);
296}
297
298static void set_logic_level(struct context *inc, size_t ch_idx, int on)
299{
300 size_t byte_idx, bit_idx;
301 uint8_t bit_mask;
302
836fac9c 303 if (ch_idx >= inc->logic_channels)
626c388a
GS
304 return;
305 if (!on)
306 return;
307
308 byte_idx = ch_idx / 8;
309 bit_idx = ch_idx % 8;
310 bit_mask = 1 << bit_idx;
311 inc->sample_buffer[byte_idx] |= bit_mask;
312}
313
314static int flush_logic_samples(const struct sr_input *in)
315{
316 struct context *inc;
317 struct sr_datafeed_packet packet;
318 struct sr_datafeed_logic logic;
319 int rc;
320
321 inc = in->priv;
322 if (!inc->datafeed_buf_fill)
323 return SR_OK;
324
43bdef26
GS
325 rc = flush_samplerate(in);
326 if (rc != SR_OK)
327 return rc;
246aca5f 328
626c388a
GS
329 memset(&packet, 0, sizeof(packet));
330 memset(&logic, 0, sizeof(logic));
331 packet.type = SR_DF_LOGIC;
332 packet.payload = &logic;
333 logic.unitsize = inc->sample_unit_size;
334 logic.length = inc->datafeed_buf_fill;
335 logic.data = inc->datafeed_buffer;
336
337 rc = sr_session_send(in->sdi, &packet);
338 if (rc != SR_OK)
339 return rc;
340
341 inc->datafeed_buf_fill = 0;
212769c3 342
626c388a
GS
343 return SR_OK;
344}
345
346static int queue_logic_samples(const struct sr_input *in)
347{
348 struct context *inc;
349 int rc;
350
351 inc = in->priv;
836fac9c
GS
352 if (!inc->logic_channels)
353 return SR_OK;
626c388a
GS
354
355 inc->datafeed_buf_fill += inc->sample_unit_size;
356 if (inc->datafeed_buf_fill == inc->datafeed_buf_size) {
357 rc = flush_logic_samples(in);
358 if (rc != SR_OK)
359 return rc;
360 }
212769c3 361
626c388a
GS
362 return SR_OK;
363}
364
43bdef26
GS
365static void set_analog_value(struct context *inc, size_t ch_idx, csv_analog_t value);
366
367static void clear_analog_samples(struct context *inc)
368{
369 size_t idx;
370
371 if (!inc->analog_channels)
372 return;
373 inc->analog_sample_buffer = &inc->analog_datafeed_buffer[inc->analog_datafeed_buf_fill];
374 for (idx = 0; idx < inc->analog_channels; idx++)
375 set_analog_value(inc, idx, 0.0);
376}
377
378static void set_analog_value(struct context *inc, size_t ch_idx, csv_analog_t value)
379{
380 if (ch_idx >= inc->analog_channels)
381 return;
382 if (!value)
383 return;
384 inc->analog_sample_buffer[ch_idx * inc->analog_datafeed_buf_size] = value;
385}
386
387static int flush_analog_samples(const struct sr_input *in)
388{
43bdef26
GS
389 struct context *inc;
390 struct sr_datafeed_packet packet;
391 struct sr_datafeed_analog analog;
392 struct sr_analog_encoding encoding;
393 struct sr_analog_meaning meaning;
394 struct sr_analog_spec spec;
395 csv_analog_t *samples;
396 size_t ch_idx;
a267bf45 397 int digits;
43bdef26
GS
398 int rc;
399
400 inc = in->priv;
401 if (!inc->analog_datafeed_buf_fill)
402 return SR_OK;
403
404 rc = flush_samplerate(in);
405 if (rc != SR_OK)
406 return rc;
407
408 samples = inc->analog_datafeed_buffer;
409 for (ch_idx = 0; ch_idx < inc->analog_channels; ch_idx++) {
a267bf45 410 digits = inc->analog_datafeed_digits[ch_idx];
43bdef26
GS
411 sr_analog_init(&analog, &encoding, &meaning, &spec, digits);
412 memset(&packet, 0, sizeof(packet));
413 packet.type = SR_DF_ANALOG;
414 packet.payload = &analog;
415 analog.num_samples = inc->analog_datafeed_buf_fill;
416 analog.data = samples;
417 analog.meaning->channels = inc->analog_datafeed_channels[ch_idx];
418 analog.meaning->mq = 0;
419 analog.meaning->mqflags = 0;
420 analog.meaning->unit = 0;
421 analog.encoding->unitsize = sizeof(samples[0]);
422 analog.encoding->is_signed = TRUE;
423 analog.encoding->is_float = TRUE;
424#ifdef WORDS_BIGENDIAN
425 analog.encoding->is_bigendian = TRUE;
426#else
427 analog.encoding->is_bigendian = FALSE;
428#endif
429 analog.encoding->digits = spec.spec_digits;
430 rc = sr_session_send(in->sdi, &packet);
431 if (rc != SR_OK)
432 return rc;
433 samples += inc->analog_datafeed_buf_size;
434 }
435
436 inc->analog_datafeed_buf_fill = 0;
212769c3 437
43bdef26
GS
438 return SR_OK;
439}
440
441static int queue_analog_samples(const struct sr_input *in)
442{
443 struct context *inc;
444 int rc;
445
446 inc = in->priv;
447 if (!inc->analog_channels)
448 return SR_OK;
449
450 inc->analog_datafeed_buf_fill++;
451 if (inc->analog_datafeed_buf_fill == inc->analog_datafeed_buf_size) {
452 rc = flush_analog_samples(in);
453 if (rc != SR_OK)
454 return rc;
455 }
212769c3 456
43bdef26
GS
457 return SR_OK;
458}
459
2142a79b
GS
460/* Helpers for "column processing". */
461
462static int split_column_format(const char *spec,
463 size_t *column_count, enum single_col_format *format, size_t *bit_count)
464{
465 size_t count;
466 char *endp, format_char;
467 enum single_col_format format_code;
468
469 if (!spec || !*spec)
470 return SR_ERR_ARG;
471
1a920e33 472 /* Get the (optional, decimal, default 1) column count. Accept '*'. */
2142a79b 473 endp = NULL;
1a920e33 474 if (*spec == '*') {
5ada72fc 475 /* Workaround, strtoul("*") won't always yield expected endp. */
1a920e33
GS
476 count = 0;
477 endp = (char *)&spec[1];
478 } else {
479 count = strtoul(spec, &endp, 10);
480 }
2142a79b
GS
481 if (!endp)
482 return SR_ERR_ARG;
483 if (endp == spec)
484 count = 1;
485 if (column_count)
486 *column_count = count;
487 spec = endp;
488
489 /* Get the (mandatory, single letter) type spec (-/xob/l). */
490 format_char = *spec++;
491 switch (format_char) {
5ada72fc 492 case '-':
2142a79b
GS
493 case '/':
494 format_char = '-';
495 format_code = FORMAT_NONE;
496 break;
497 case 'x':
498 format_code = FORMAT_HEX;
499 break;
500 case 'o':
501 format_code = FORMAT_OCT;
502 break;
503 case 'b':
504 case 'l':
505 format_code = FORMAT_BIN;
506 break;
43bdef26
GS
507 case 'a':
508 format_code = FORMAT_ANALOG;
509 break;
7e4e65bf
GS
510 case 't':
511 format_code = FORMAT_TIME;
512 break;
2142a79b
GS
513 default: /* includes NUL */
514 return SR_ERR_ARG;
515 }
516 if (format)
517 *format = format_code;
518
519 /* Get the (optional, decimal, default 1) bit count. */
520 endp = NULL;
521 count = strtoul(spec, &endp, 10);
522 if (!endp)
523 return SR_ERR_ARG;
524 if (endp == spec)
fc3b42e9
GS
525 count = format_is_analog(format_code) ? 3 : 1;
526 if (format_is_ignore(format_code))
2142a79b
GS
527 count = 0;
528 if (format_char == 'l')
529 count = 1;
530 if (bit_count)
531 *bit_count = count;
532 spec = endp;
533
534 /* Input spec must have been exhausted. */
535 if (*spec)
536 return SR_ERR_ARG;
537
538 return SR_OK;
539}
540
9e7af34e
GS
541static int make_column_details_from_format(const struct sr_input *in,
542 const char *column_format, char **column_texts)
2142a79b 543{
9e7af34e 544 struct context *inc;
2142a79b 545 char **formats, *format;
43bdef26 546 size_t format_count, column_count, logic_count, analog_count;
1a920e33 547 size_t auto_column_count;
43bdef26 548 size_t format_idx, c, b, column_idx, channel_idx, analog_idx;
2142a79b
GS
549 enum single_col_format f;
550 struct column_details *detail;
9e7af34e
GS
551 GString *channel_name;
552 size_t create_idx;
553 char *column;
554 const char *caption;
43bdef26 555 int channel_type, channel_sdi_nr;
05719d75 556 void *channel;
2142a79b
GS
557 int ret;
558
9e7af34e
GS
559 inc = in->priv;
560 inc->column_seen_count = g_strv_length(column_texts);
561
05719d75 562 /* Split the input spec, count involved columns and channels. */
2142a79b
GS
563 formats = g_strsplit(column_format, ",", 0);
564 if (!formats) {
565 sr_err("Cannot parse columns format %s (comma split).", column_format);
566 return SR_ERR_ARG;
567 }
568 format_count = g_strv_length(formats);
569 if (!format_count) {
570 sr_err("Cannot parse columns format %s (field count).", column_format);
571 g_strfreev(formats);
572 return SR_ERR_ARG;
573 }
43bdef26 574 column_count = logic_count = analog_count = 0;
1a920e33 575 auto_column_count = 0;
2142a79b
GS
576 for (format_idx = 0; format_idx < format_count; format_idx++) {
577 format = formats[format_idx];
578 ret = split_column_format(format, &c, &f, &b);
579 sr_dbg("fmt %s -> %zu cols, %s fmt, %zu bits, rc %d", format, c, col_format_text[f], b, ret);
580 if (ret != SR_OK) {
581 sr_err("Cannot parse columns format %s (field split, %s).", column_format, format);
582 g_strfreev(formats);
583 return SR_ERR_ARG;
584 }
1a920e33
GS
585 if (f && !c) {
586 /* User requested "auto-count", must be last format. */
587 if (formats[format_idx + 1]) {
588 sr_err("Auto column count must be last format field.");
589 g_strfreev(formats);
590 return SR_ERR_ARG;
591 }
592 auto_column_count = inc->column_seen_count - column_count;
593 c = auto_column_count;
594 }
2142a79b 595 column_count += c;
fc3b42e9 596 if (format_is_analog(f))
43bdef26 597 analog_count += c;
fc3b42e9 598 else if (format_is_logic(f))
43bdef26 599 logic_count += c * b;
2142a79b 600 }
43bdef26
GS
601 sr_dbg("Column format %s -> %zu columns, %zu logic, %zu analog channels.",
602 column_format, column_count, logic_count, analog_count);
2142a79b 603
05719d75 604 /* Allocate and fill in "column processing" details. */
2142a79b 605 inc->column_want_count = column_count;
9e7af34e
GS
606 if (inc->column_seen_count < inc->column_want_count) {
607 sr_err("Insufficient input text width for desired data amount, got %zu but want %zu columns.",
608 inc->column_seen_count, inc->column_want_count);
609 g_strfreev(formats);
610 return SR_ERR_ARG;
611 }
05719d75
GS
612 inc->logic_channels = logic_count;
613 inc->analog_channels = analog_count;
614 inc->analog_datafeed_digits = g_malloc0(inc->analog_channels * sizeof(inc->analog_datafeed_digits[0]));
615 inc->analog_datafeed_channels = g_malloc0(inc->analog_channels * sizeof(inc->analog_datafeed_channels[0]));
2142a79b 616 inc->column_details = g_malloc0_n(column_count, sizeof(inc->column_details[0]));
43bdef26 617 column_idx = channel_idx = analog_idx = 0;
9e7af34e 618 channel_name = g_string_sized_new(64);
2142a79b 619 for (format_idx = 0; format_idx < format_count; format_idx++) {
9e7af34e 620 /* Process a format field, which can span multiple columns. */
2142a79b
GS
621 format = formats[format_idx];
622 (void)split_column_format(format, &c, &f, &b);
1a920e33
GS
623 if (f && !c)
624 c = auto_column_count;
2142a79b 625 while (c-- > 0) {
9e7af34e 626 /* Fill in a column's processing details. */
2142a79b
GS
627 detail = &inc->column_details[column_idx++];
628 detail->col_nr = column_idx;
629 detail->text_format = f;
fc3b42e9 630 if (format_is_analog(detail->text_format)) {
43bdef26
GS
631 detail->channel_offset = analog_idx;
632 detail->channel_count = 1;
a267bf45 633 detail->analog_digits = b;
43bdef26 634 analog_idx += detail->channel_count;
fc3b42e9 635 } else if (format_is_logic(detail->text_format)) {
2142a79b
GS
636 detail->channel_offset = channel_idx;
637 detail->channel_count = b;
43bdef26 638 channel_idx += detail->channel_count;
fc3b42e9
GS
639 } else if (format_is_ignore(detail->text_format)) {
640 /* EMPTY */
9e7af34e 641 continue;
fc3b42e9
GS
642 } else {
643 /*
644 * Neither logic nor analog data, nor ignore.
645 * Format was noted. No channel creation involved.
646 */
647 continue;
648 }
9e7af34e 649 /*
08eb955a 650 * Pick most appropriate channel names. Optionally
9e7af34e
GS
651 * use text from a header line (when requested by the
652 * user). In the absence of header text, channels are
653 * assigned rather generic names.
654 *
655 * Manipulation of the column's caption (when a header
656 * line is seen) is acceptable, because this header
657 * line won't get processed another time.
658 */
659 column = column_texts[detail->col_nr - 1];
4b834894
GS
660 if (inc->use_header && column && *column) {
661 column = g_strstrip(column);
9e7af34e 662 caption = sr_scpi_unquote_string(column);
4b834894 663 } else {
9e7af34e 664 caption = NULL;
4b834894 665 }
9e7af34e
GS
666 if (!caption || !*caption)
667 caption = NULL;
3f1f63f0 668 /*
05719d75
GS
669 * Collect channel creation details here, but defer
670 * actual creation of the channels such that all
671 * logic channels can get created first and analog
672 * channels only get created afterwards.
3f1f63f0 673 */
05719d75 674 detail->channel_names = g_malloc0(detail->channel_count * sizeof(detail->channel_names[0]));
9e7af34e
GS
675 for (create_idx = 0; create_idx < detail->channel_count; create_idx++) {
676 if (caption && detail->channel_count == 1) {
677 g_string_assign(channel_name, caption);
678 } else if (caption) {
679 g_string_printf(channel_name, "%s[%zu]",
680 caption, create_idx);
681 } else {
682 g_string_printf(channel_name, "%zu",
683 detail->channel_offset + create_idx);
684 }
05719d75 685 detail->channel_names[create_idx] = g_string_new_len(channel_name->str, channel_name->len);
9e7af34e 686 }
2142a79b
GS
687 }
688 }
9e7af34e 689 g_string_free(channel_name, TRUE);
2142a79b
GS
690 g_strfreev(formats);
691
05719d75
GS
692 /* Create channels in strict logic to analog order. */
693 channel_type = SR_CHANNEL_LOGIC;
694 for (column_idx = 0; column_idx < inc->column_want_count; column_idx++) {
695 detail = &inc->column_details[column_idx];
696 if (!format_is_logic(detail->text_format))
697 continue;
698 for (create_idx = 0; create_idx < detail->channel_count; create_idx++) {
699 caption = detail->channel_names[create_idx]->str;
700 channel_sdi_nr = g_slist_length(in->sdi->channels);
701 sr_channel_new(in->sdi, channel_sdi_nr, channel_type, TRUE, caption);
702 }
703 }
704 channel_type = SR_CHANNEL_ANALOG;
705 for (column_idx = 0; column_idx < inc->column_want_count; column_idx++) {
706 detail = &inc->column_details[column_idx];
707 if (!format_is_analog(detail->text_format))
708 continue;
709 caption = detail->channel_names[0]->str;
710 channel_sdi_nr = g_slist_length(in->sdi->channels);
711 channel = sr_channel_new(in->sdi, channel_sdi_nr, channel_type, TRUE, caption);
712 channel_idx = channel_sdi_nr - inc->logic_channels;
713 inc->analog_datafeed_digits[channel_idx] = detail->analog_digits;
714 inc->analog_datafeed_channels[channel_idx] = g_slist_append(NULL, channel);
715 }
716
2142a79b
GS
717 return SR_OK;
718}
719
e53f32d2
GS
720static const struct column_details *lookup_column_details(struct context *inc, size_t nr)
721{
722 if (!inc || !inc->column_details)
723 return NULL;
724 if (!nr || nr > inc->column_want_count)
725 return NULL;
212769c3 726
e53f32d2
GS
727 return &inc->column_details[nr - 1];
728}
729
19267272
GS
730/*
731 * Primitive operations for text input: Strip comments off text lines.
732 * Split text lines into columns. Process input text for individual
733 * columns.
734 */
735
41d214f6 736static void strip_comment(char *buf, const GString *prefix)
4a35548b
MS
737{
738 char *ptr;
739
740 if (!prefix->len)
741 return;
742
b2c4dde2 743 if ((ptr = strstr(buf, prefix->str))) {
41d214f6 744 *ptr = '\0';
b2c4dde2
GS
745 g_strstrip(buf);
746 }
4a35548b
MS
747}
748
19267272 749/**
51e60cde 750 * Splits a text line into a set of columns.
19267272 751 *
e53f32d2 752 * @param[in] buf The input text line to split.
19267272
GS
753 * @param[in] inc The input module's context.
754 *
e53f32d2 755 * @returns An array of strings, representing the columns' text.
19267272 756 *
e53f32d2 757 * This routine splits a text line on previously determined separators.
19267272 758 */
e53f32d2 759static char **split_line(char *buf, struct context *inc)
4a35548b 760{
cd11e33c
GS
761 char **fields, *f;
762 size_t l;
763
764 fields = g_strsplit(buf, inc->delimiter->str, 0);
765 if (!fields)
766 return NULL;
767
768 l = g_strv_length(fields);
769 while (l--) {
770 f = fields[l];
771 g_strchomp(f);
772 }
773
774 return fields;
4a35548b
MS
775}
776
19267272 777/**
51e60cde 778 * Parse a multi-bit field into several logic channels.
19267272 779 *
e53f32d2 780 * @param[in] column The input text, a run of bin/hex/oct digits.
19267272 781 * @param[in] inc The input module's context.
836fac9c 782 * @param[in] details The column processing details.
19267272
GS
783 *
784 * @retval SR_OK Success.
785 * @retval SR_ERR Invalid input data (empty, or format error).
786 *
787 * This routine modifies the logic levels in the current sample set,
e53f32d2 788 * based on the text input and a user provided format spec.
19267272 789 */
836fac9c
GS
790static int parse_logic(const char *column, struct context *inc,
791 const struct column_details *details)
4a35548b 792{
e53f32d2
GS
793 size_t length, ch_rem, ch_idx, ch_inc;
794 const char *rdptr;
4a35548b 795 char c;
e53f32d2
GS
796 gboolean valid;
797 const char *type_text;
798 uint8_t bits;
799
e53f32d2
GS
800 /*
801 * Prepare to read the digits from the text end towards the start.
802 * A digit corresponds to a variable number of channels (depending
803 * on the value's radix). Prepare the mapping of text digits to
804 * (a number of) logic channels.
805 */
806 length = strlen(column);
4a35548b 807 if (!length) {
836fac9c 808 sr_err("Column %zu in line %zu is empty.", details->col_nr,
41d214f6 809 inc->line_number);
4a35548b
MS
810 return SR_ERR;
811 }
e53f32d2 812 rdptr = &column[length];
836fac9c
GS
813 ch_idx = details->channel_offset;
814 ch_rem = details->channel_count;
4a35548b 815
e53f32d2
GS
816 /*
817 * Get another digit and derive up to four logic channels' state from
818 * it. Make sure to not process more bits than the column has channels
819 * associated with it.
820 */
821 while (rdptr > column && ch_rem) {
822 /* Check for valid digits according to the input radix. */
823 c = *(--rdptr);
836fac9c 824 switch (details->text_format) {
e53f32d2
GS
825 case FORMAT_BIN:
826 valid = g_ascii_isxdigit(c) && c < '2';
827 ch_inc = 1;
828 break;
829 case FORMAT_OCT:
830 valid = g_ascii_isxdigit(c) && c < '8';
831 ch_inc = 3;
832 break;
833 case FORMAT_HEX:
834 valid = g_ascii_isxdigit(c);
835 ch_inc = 4;
836 break;
837 default:
838 valid = FALSE;
839 break;
4a35548b 840 }
e53f32d2 841 if (!valid) {
836fac9c 842 type_text = col_format_text[details->text_format];
e53f32d2 843 sr_err("Invalid text '%s' in %s type column %zu in line %zu.",
836fac9c 844 column, type_text, details->col_nr, inc->line_number);
4a35548b 845 return SR_ERR;
e53f32d2
GS
846 }
847 /* Use the digit's bits for logic channels' data. */
848 bits = g_ascii_xdigit_value(c);
836fac9c 849 switch (details->text_format) {
e53f32d2
GS
850 case FORMAT_HEX:
851 if (ch_rem >= 4) {
852 ch_rem--;
853 set_logic_level(inc, ch_idx + 3, bits & (1 << 3));
854 }
855 /* FALLTHROUGH */
856 case FORMAT_OCT:
857 if (ch_rem >= 3) {
858 ch_rem--;
859 set_logic_level(inc, ch_idx + 2, bits & (1 << 2));
860 }
861 if (ch_rem >= 2) {
862 ch_rem--;
863 set_logic_level(inc, ch_idx + 1, bits & (1 << 1));
864 }
865 /* FALLTHROUGH */
866 case FORMAT_BIN:
867 ch_rem--;
868 set_logic_level(inc, ch_idx + 0, bits & (1 << 0));
869 break;
fc3b42e9 870 default:
836fac9c
GS
871 /* ShouldNotHappen(TM), but silences compiler warning. */
872 return SR_ERR;
4a35548b 873 }
e53f32d2 874 ch_idx += ch_inc;
4a35548b 875 }
e53f32d2
GS
876 /*
877 * TODO Determine whether the availability of extra input data
878 * for unhandled logic channels is worth warning here. In this
879 * implementation users are in control, and can have the more
880 * significant bits ignored (which can be considered a feature
881 * and not really a limitation).
882 */
4a35548b
MS
883
884 return SR_OK;
885}
886
43bdef26 887/**
51e60cde 888 * Parse a floating point text into an analog value.
43bdef26
GS
889 *
890 * @param[in] column The input text, a floating point number.
891 * @param[in] inc The input module's context.
892 * @param[in] details The column processing details.
893 *
894 * @retval SR_OK Success.
895 * @retval SR_ERR Invalid input data (empty, or format error).
896 *
897 * This routine modifies the analog values in the current sample set,
898 * based on the text input and a user provided format spec.
899 */
900static int parse_analog(const char *column, struct context *inc,
901 const struct column_details *details)
902{
903 size_t length;
904 double dvalue; float fvalue;
905 csv_analog_t value;
906 int ret;
907
fc3b42e9 908 if (!format_is_analog(details->text_format))
43bdef26
GS
909 return SR_ERR_BUG;
910
911 length = strlen(column);
912 if (!length) {
913 sr_err("Column %zu in line %zu is empty.", details->col_nr,
914 inc->line_number);
915 return SR_ERR;
916 }
917 if (sizeof(value) == sizeof(double)) {
918 ret = sr_atod_ascii(column, &dvalue);
919 value = dvalue;
920 } else if (sizeof(value) == sizeof(float)) {
921 ret = sr_atof_ascii(column, &fvalue);
922 value = fvalue;
923 } else {
924 ret = SR_ERR_BUG;
925 }
926 if (ret != SR_OK) {
927 sr_err("Cannot parse analog text %s in column %zu in line %zu.",
928 column, details->col_nr, inc->line_number);
929 return SR_ERR_DATA;
930 }
931 set_analog_value(inc, details->channel_offset, value);
932
933 return SR_OK;
934}
935
7e4e65bf 936/**
51e60cde 937 * Parse a timestamp text, auto-determine samplerate.
7e4e65bf
GS
938 *
939 * @param[in] column The input text, a floating point number.
940 * @param[in] inc The input module's context.
941 * @param[in] details The column processing details.
942 *
943 * @retval SR_OK Success.
944 * @retval SR_ERR Invalid input data (empty, or format error).
945 *
946 * This routine attempts to automatically determine the input data's
947 * samplerate from text rows' timestamp values. Only simple formats are
948 * supported, user provided values always take precedence.
949 */
950static int parse_timestamp(const char *column, struct context *inc,
951 const struct column_details *details)
952{
953 double ts, rate;
954 int ret;
955
956 if (!format_is_timestamp(details->text_format))
957 return SR_ERR_BUG;
958
959 /*
960 * Implementor's notes on timestamp interpretation. Use a simple
961 * approach for improved maintainability which covers most cases
962 * of input data. There is not much gain in adding complexity,
963 * users can easily provide the rate when auto-detection fails.
964 * - Bail out if samplerate is known already.
965 * - Try to interpret the timestamp (simple float conversion).
966 * If conversion fails then clear all previous knowledge and
967 * bail out (non-fatal, perhaps warn). Silently ignore values
968 * of zero since those could be silent fails -- assume that
969 * genuine data contains at least two adjacent rows with useful
970 * timestamps for the feature to work reliably. Annoying users
971 * with "failed to detect" messages is acceptable here, since
972 * users expecting the feature to work should provide useful
973 * data, and there are easy ways to disable the detection or
974 * ignore the column.
975 * - If there is no previous timestamp, keep the current value
976 * for later reference and bail out.
977 * - If a previous timestamp was seen, determine the difference
978 * between them, and derive the samplerate. Update internal
979 * state (the value automatically gets sent to the datafeed),
980 * and clear previous knowledge. Subsequent calls will ignore
981 * following input data (see above, rate is known).
982 *
983 * TODO Potential future improvements:
984 * - Prefer rationals over floats for improved precision and
985 * reduced rounding errors which result in odd rates.
986 * - Support other formats ("2 ms" or similar)?
987 */
811dcf7e 988 if (inc->calc_samplerate)
7e4e65bf
GS
989 return SR_OK;
990 ret = sr_atod_ascii(column, &ts);
991 if (ret != SR_OK)
992 ts = 0.0;
993 if (!ts) {
811dcf7e 994 sr_info("Cannot convert timestamp text %s in line %zu (or zero value).",
7e4e65bf
GS
995 column, inc->line_number);
996 inc->prev_timestamp = 0.0;
997 return SR_OK;
998 }
999 if (!inc->prev_timestamp) {
1000 sr_dbg("First timestamp value %g in line %zu.",
1001 ts, inc->line_number);
1002 inc->prev_timestamp = ts;
1003 return SR_OK;
1004 }
1005 sr_dbg("Second timestamp value %g in line %zu.", ts, inc->line_number);
1006 ts -= inc->prev_timestamp;
1007 sr_dbg("Timestamp difference %g in line %zu.",
1008 ts, inc->line_number);
1009 if (!ts) {
1010 sr_warn("Zero timestamp difference in line %zu.",
1011 inc->line_number);
1012 inc->prev_timestamp = ts;
1013 return SR_OK;
1014 }
1015 rate = 1.0 / ts;
1016 rate += 0.5;
1017 rate = (uint64_t)rate;
1018 sr_dbg("Rate from timestamp %g in line %zu.", rate, inc->line_number);
811dcf7e 1019 inc->calc_samplerate = rate;
7e4e65bf
GS
1020 inc->prev_timestamp = 0.0;
1021
1022 return SR_OK;
1023}
1024
836fac9c 1025/**
51e60cde 1026 * Parse routine which ignores the input text.
836fac9c
GS
1027 *
1028 * This routine exists to unify dispatch code paths, mapping input file
1029 * columns' data types to their respective parse routines.
1030 */
1031static int parse_ignore(const char *column, struct context *inc,
1032 const struct column_details *details)
1033{
1034 (void)column;
1035 (void)inc;
1036 (void)details;
212769c3 1037
836fac9c
GS
1038 return SR_OK;
1039}
1040
1041typedef int (*col_parse_cb)(const char *column, struct context *inc,
1042 const struct column_details *details);
1043
1044static const col_parse_cb col_parse_funcs[] = {
1045 [FORMAT_NONE] = parse_ignore,
1046 [FORMAT_BIN] = parse_logic,
1047 [FORMAT_OCT] = parse_logic,
1048 [FORMAT_HEX] = parse_logic,
43bdef26 1049 [FORMAT_ANALOG] = parse_analog,
7e4e65bf 1050 [FORMAT_TIME] = parse_timestamp,
836fac9c
GS
1051};
1052
cd7c5f96
GS
1053/*
1054 * BEWARE! Implementor's notes. Sync with feature set and default option
1055 * values required during maintenance of the input module implementation.
1056 *
1057 * When applications invoke .format_match() routines, trying automatic
1058 * determination of an input file's format handler, then no options are
1059 * in effect. Because specifying options requires selection of an input
1060 * module to pass the options to, which obsoletes the format-match check.
1061 *
1062 * Which means that we only need to deal with the default format here,
1063 * which happens to be the simple multi-column format without header
1064 * lines or leading garbage. Which means that the check can be rather
1065 * strict, resulting in high levels of confidence upon match, never
1066 * "accidently" winning for unreadable or unsupported-by-default formats.
1067 *
1068 * This .format_match() logic only needs to become more involved when
1069 * default option values change, or when automatic detection of column
1070 * data types improves. Then the supported-by-default types of input
1071 * data must be considered acceptable here in the format-match check
1072 * as well.
1073 *
1074 * Notice that the format check cannot re-use regular processing logic
1075 * when their implementation assumes proper input data and wll generate
1076 * diagnostics for unexpected input data. Failure to match the format is
1077 * non-fatal here, mismatch must remain silent. It's up to applications
1078 * how large a chunk of data gets passed here (start of the file's
1079 * content). But inspection of the first few hundred bytes will usually
1080 * be GoodEnough(TM) for the format-match purpose. Notice that filenames
1081 * need not necessarily be available to the format-match routine.
1082 *
1083 * This implementation errs on the safe side. Users can always select
1084 * the CSV input module when automatic format detection fails.
1085 */
1086static int format_match(GHashTable *metadata, unsigned int *confidence)
1087{
1088 const int match_confidence = 100;
1089 const char *default_extension = ".csv";
1090 const char *line_termination = "\n";
1091 const char *comment_leader = ";";
1092 const char *column_separator = ",";
1093 const char *binary_charset = "01";
1094
1095 const char *fn;
1096 GString *buf;
1097 size_t fn_len;
1098 GString *tmpbuf;
1099 gboolean status;
1100 size_t line_idx, col_idx;
1101 char *rdptr, **lines, *line;
1102 char **cols, *col;
1103
1104 /* Get the application provided input data properties. */
1105 fn = g_hash_table_lookup(metadata, GINT_TO_POINTER(SR_INPUT_META_FILENAME));
1106 buf = g_hash_table_lookup(metadata, GINT_TO_POINTER(SR_INPUT_META_HEADER));
1107
1108 /* Filenames are a strong hint. Use then when available. */
1109 if (fn && *fn && (fn_len = strlen(fn)) >= strlen(default_extension)) {
1110 if (strcasecmp(&fn[fn_len - strlen(default_extension)], default_extension) == 0) {
1111 *confidence = 10;
1112 return SR_OK;
1113 }
1114 }
1115
1116 /*
1117 * Check file content for compatibility with the input module's
1118 * default format. Which translates to:
1119 * - Must be at least one text line worth of input data. Ignore
1120 * incomplete lines at the end of the available buffer.
1121 * - Must be LF terminated text lines, optional CR-LF sequence.
1122 * (Drop CR-only for simplicity since that's rare and users
1123 * can override the automatic detection.)
1124 * - Strip comments and skip empty lines.
1125 * - Data lines must be binary input (potentially multiple bits
1126 * per column which then get ignored). Presence of comma is
1127 * optional but then must be followed by another data column.
1128 * - No other content is acceptable, there neither are ignored
1129 * columns nor analog data nor timestamps in the default layout.
1130 * (See the above "sync format match with default options"
1131 * comment though during maintenance!)
1132 * Run the check on a copy to not affect the caller's buffer.
1133 */
1134 if (!buf || !buf->len || !buf->str || !*buf->str)
1135 return SR_ERR;
1136 rdptr = g_strstr_len(buf->str, buf->len, line_termination);
1137 if (!rdptr)
1138 return SR_ERR;
1139 tmpbuf = g_string_new_len(buf->str, rdptr + 1 - buf->str);
1140 tmpbuf->str[tmpbuf->len - 1] = '\0';
1141 status = TRUE;
1142 *confidence = match_confidence;
1143 lines = g_strsplit(tmpbuf->str, line_termination, 0);
1144 for (line_idx = 0; status && (line = lines[line_idx]); line_idx++) {
1145 rdptr = strstr(line, comment_leader);
1146 if (rdptr)
1147 *rdptr = '\0';
1148 line = g_strstrip(line);
1149 if (!line || !*line)
1150 continue;
1151 cols = g_strsplit(line, column_separator, 0);
1152 if (!cols) {
1153 status = FALSE;
1154 break;
1155 }
1156 for (col_idx = 0; status && (col = cols[col_idx]); col_idx++) {
1157 if (strspn(col, binary_charset) != strlen(col)) {
1158 status = FALSE;
1159 break;
1160 }
1161 }
1162 g_strfreev(cols);
1163 }
1164 g_strfreev(lines);
1165 g_string_free(tmpbuf, TRUE);
1166
1167 if (!status)
1168 return SR_ERR;
212769c3 1169
cd7c5f96
GS
1170 return SR_OK;
1171}
1172
41d214f6 1173static int init(struct sr_input *in, GHashTable *options)
4a35548b 1174{
41d214f6 1175 struct context *inc;
1a920e33 1176 size_t single_column, first_column, logic_channels;
41d214f6 1177 const char *s;
836fac9c 1178 enum single_col_format format;
1a920e33 1179 char format_char;
4a35548b 1180
836fac9c
GS
1181 in->sdi = g_malloc0(sizeof(*in->sdi));
1182 in->priv = inc = g_malloc0(sizeof(*inc));
4a35548b 1183
72903e9d 1184 single_column = g_variant_get_uint32(g_hash_table_lookup(options, "single_column"));
72903e9d 1185 logic_channels = g_variant_get_uint32(g_hash_table_lookup(options, "logic_channels"));
41d214f6 1186 inc->delimiter = g_string_new(g_variant_get_string(
72903e9d 1187 g_hash_table_lookup(options, "column_separator"), NULL));
836fac9c 1188 if (!inc->delimiter->len) {
72903e9d 1189 sr_err("Column separator cannot be empty.");
41d214f6 1190 return SR_ERR_ARG;
4a35548b 1191 }
72903e9d 1192 s = g_variant_get_string(g_hash_table_lookup(options, "single_format"), NULL);
836fac9c
GS
1193 if (g_ascii_strncasecmp(s, "bin", 3) == 0) {
1194 format = FORMAT_BIN;
1195 } else if (g_ascii_strncasecmp(s, "hex", 3) == 0) {
1196 format = FORMAT_HEX;
1197 } else if (g_ascii_strncasecmp(s, "oct", 3) == 0) {
1198 format = FORMAT_OCT;
41d214f6 1199 } else {
72903e9d 1200 sr_err("Invalid single-column format: '%s'", s);
41d214f6 1201 return SR_ERR_ARG;
4a35548b 1202 }
41d214f6 1203 inc->comment = g_string_new(g_variant_get_string(
72903e9d 1204 g_hash_table_lookup(options, "comment_leader"), NULL));
41d214f6 1205 if (g_string_equal(inc->comment, inc->delimiter)) {
e53f32d2
GS
1206 /*
1207 * Using the same sequence as comment leader and column
72903e9d
GS
1208 * separator won't work. The user probably specified ';'
1209 * as the column separator but did not adjust the comment
e53f32d2
GS
1210 * leader. Try DWIM, drop comment strippin support here.
1211 */
72903e9d 1212 sr_warn("Comment leader and column separator conflict, disabling comment support.");
41d214f6 1213 g_string_truncate(inc->comment, 0);
4a35548b 1214 }
6e8d95a5 1215 inc->samplerate = g_variant_get_uint64(g_hash_table_lookup(options, "samplerate"));
72903e9d 1216 first_column = g_variant_get_uint32(g_hash_table_lookup(options, "first_column"));
de8fe3b5 1217 inc->use_header = g_variant_get_boolean(g_hash_table_lookup(options, "header"));
72903e9d 1218 inc->start_line = g_variant_get_uint32(g_hash_table_lookup(options, "start_line"));
41d214f6 1219 if (inc->start_line < 1) {
6433156c 1220 sr_err("Invalid start line %zu.", inc->start_line);
41d214f6 1221 return SR_ERR_ARG;
4a35548b
MS
1222 }
1223
e53f32d2 1224 /*
1a920e33
GS
1225 * Scan flexible, to get prefered format specs which describe
1226 * the input file's data formats. As well as some simple specs
1227 * for backwards compatibility and user convenience.
1228 *
1229 * This logic ends up with a copy of the format string, either
1230 * user provided or internally derived. Actual creation of the
1231 * column processing details gets deferred until the first line
1232 * of input data was seen. To support automatic determination of
1233 * e.g. channel counts from column counts.
e53f32d2 1234 */
72903e9d 1235 s = g_variant_get_string(g_hash_table_lookup(options, "column_formats"), NULL);
2142a79b 1236 if (s && *s) {
1a920e33 1237 inc->column_formats = g_strdup(s);
72903e9d 1238 sr_dbg("User specified column_formats: %s.", s);
1a920e33
GS
1239 } else if (single_column && logic_channels) {
1240 format_char = col_format_char[format];
1241 if (single_column == 1) {
1242 inc->column_formats = g_strdup_printf("%c%zu",
1243 format_char, logic_channels);
e53f32d2 1244 } else {
1a920e33
GS
1245 inc->column_formats = g_strdup_printf("%zu-,%c%zu",
1246 single_column - 1,
1247 format_char, logic_channels);
e53f32d2 1248 }
72903e9d 1249 sr_dbg("Backwards compat single_column, col %zu, fmt %s, bits %zu -> %s.",
1a920e33
GS
1250 single_column, col_format_text[format], logic_channels,
1251 inc->column_formats);
1252 } else if (!single_column) {
1253 if (first_column > 1) {
1254 inc->column_formats = g_strdup_printf("%zu-,%zul",
1255 first_column - 1, logic_channels);
1256 } else {
1257 inc->column_formats = g_strdup_printf("%zul",
1258 logic_channels);
1259 }
1260 sr_dbg("Backwards compat multi-column, col %zu, chans %zu -> %s.",
1261 first_column, logic_channels,
1262 inc->column_formats);
e53f32d2 1263 } else {
72903e9d 1264 sr_warn("Unknown or unsupported columns layout spec, assuming simple multi-column mode.");
1a920e33 1265 inc->column_formats = g_strdup("*l");
4a35548b
MS
1266 }
1267
41d214f6
BV
1268 return SR_OK;
1269}
4a35548b 1270
affaf540
GS
1271/*
1272 * Check the channel list for consistency across file re-import. See
1273 * the VCD input module for more details and motivation.
1274 */
307b2393
GS
1275static void release_df_channels(struct context *inc, GSList **l)
1276{
1277 size_t idx;
1278
1279 if (!inc->analog_channels || !l)
1280 return;
1281 for (idx = 0; idx < inc->analog_channels; idx++)
1282 g_slist_free(l[idx]);
1283 g_free(l);
1284}
affaf540
GS
1285
1286static void keep_header_for_reread(const struct sr_input *in)
1287{
1288 struct context *inc;
1289
1290 inc = in->priv;
307b2393 1291
affaf540
GS
1292 g_slist_free_full(inc->prev_sr_channels, sr_channel_free_cb);
1293 inc->prev_sr_channels = in->sdi->channels;
1294 in->sdi->channels = NULL;
307b2393
GS
1295
1296 release_df_channels(inc, inc->prev_df_channels);
1297 inc->prev_df_channels = inc->analog_datafeed_channels;
1298 inc->analog_datafeed_channels = NULL;
affaf540
GS
1299}
1300
1301static int check_header_in_reread(const struct sr_input *in)
1302{
1303 struct context *inc;
1304
1305 if (!in)
1306 return FALSE;
1307 inc = in->priv;
1308 if (!inc)
1309 return FALSE;
1310 if (!inc->prev_sr_channels)
1311 return TRUE;
1312
1313 if (sr_channel_lists_differ(inc->prev_sr_channels, in->sdi->channels)) {
1314 sr_err("Channel list change not supported for file re-read.");
1315 return FALSE;
1316 }
307b2393 1317
affaf540
GS
1318 g_slist_free_full(in->sdi->channels, sr_channel_free_cb);
1319 in->sdi->channels = inc->prev_sr_channels;
1320 inc->prev_sr_channels = NULL;
1321
307b2393
GS
1322 release_df_channels(inc, inc->analog_datafeed_channels);
1323 inc->analog_datafeed_channels = inc->prev_df_channels;
1324 inc->prev_df_channels = NULL;
1325
affaf540
GS
1326 return TRUE;
1327}
1328
492dfa90
GS
1329static const char *delim_set = "\r\n";
1330
329733d9 1331static const char *get_line_termination(GString *buf)
41d214f6 1332{
329733d9 1333 const char *term;
4a35548b 1334
41d214f6
BV
1335 term = NULL;
1336 if (g_strstr_len(buf->str, buf->len, "\r\n"))
1337 term = "\r\n";
1338 else if (memchr(buf->str, '\n', buf->len))
1339 term = "\n";
1340 else if (memchr(buf->str, '\r', buf->len))
1341 term = "\r";
4a35548b 1342
41d214f6
BV
1343 return term;
1344}
4a35548b 1345
41d214f6
BV
1346static int initial_parse(const struct sr_input *in, GString *buf)
1347{
1348 struct context *inc;
9e7af34e 1349 size_t num_columns;
3f1f63f0 1350 size_t line_number, line_idx;
41d214f6 1351 int ret;
9e7af34e 1352 char **lines, *line, **columns;
41d214f6
BV
1353
1354 ret = SR_OK;
1355 inc = in->priv;
1356 columns = NULL;
1357
9e7af34e 1358 /* Search for the first line to process (header or data). */
41d214f6 1359 line_number = 0;
ef0b9935
GS
1360 if (inc->termination)
1361 lines = g_strsplit(buf->str, inc->termination, 0);
1362 else
1363 lines = g_strsplit_set(buf->str, delim_set, 0);
e53f32d2 1364 for (line_idx = 0; (line = lines[line_idx]); line_idx++) {
41d214f6
BV
1365 line_number++;
1366 if (inc->start_line > line_number) {
e53f32d2 1367 sr_spew("Line %zu skipped (before start).", line_number);
4a35548b
MS
1368 continue;
1369 }
df0db9fd 1370 if (line[0] == '\0') {
41d214f6
BV
1371 sr_spew("Blank line %zu skipped.", line_number);
1372 continue;
1373 }
df0db9fd
GS
1374 strip_comment(line, inc->comment);
1375 if (line[0] == '\0') {
41d214f6 1376 sr_spew("Comment-only line %zu skipped.", line_number);
4a35548b
MS
1377 continue;
1378 }
1379
41d214f6
BV
1380 /* Reached first proper line. */
1381 break;
1382 }
e53f32d2 1383 if (!line) {
41d214f6 1384 /* Not enough data for a proper line yet. */
60107497 1385 ret = SR_ERR_NA;
41d214f6 1386 goto out;
4a35548b
MS
1387 }
1388
9e7af34e 1389 /* Get the number of columns in the line. */
e53f32d2 1390 columns = split_line(line, inc);
df0db9fd 1391 if (!columns) {
41d214f6
BV
1392 sr_err("Error while parsing line %zu.", line_number);
1393 ret = SR_ERR;
1394 goto out;
4a35548b 1395 }
4a35548b 1396 num_columns = g_strv_length(columns);
4a35548b 1397 if (!num_columns) {
e53f32d2 1398 sr_err("Error while parsing line %zu.", line_number);
41d214f6
BV
1399 ret = SR_ERR;
1400 goto out;
4a35548b 1401 }
51e60cde 1402 sr_dbg("Got %zu columns in text line: %s.", num_columns, line);
e53f32d2 1403
1a920e33 1404 /*
9e7af34e
GS
1405 * Interpret the user provided column format specs. This might
1406 * involve inspection of the now received input text, to support
1407 * e.g. automatic detection of channel counts in the absence of
1408 * user provided specs. Optionally a header line is used to get
1409 * channels' names.
1410 *
1411 * Check the then created channels for consistency across .reset
1412 * and .receive sequences (file re-load).
1a920e33 1413 */
9e7af34e 1414 ret = make_column_details_from_format(in, inc->column_formats, columns);
1a920e33
GS
1415 if (ret != SR_OK) {
1416 sr_err("Cannot parse columns format using line %zu.", line_number);
1417 goto out;
4a35548b 1418 }
affaf540
GS
1419 if (!check_header_in_reread(in)) {
1420 ret = SR_ERR_DATA;
1421 goto out;
1422 }
4a35548b
MS
1423
1424 /*
9e7af34e 1425 * Allocate buffer memory for datafeed submission of sample data.
cd59e6ec
GS
1426 * Calculate the minimum buffer size to store the set of samples
1427 * of all channels (unit size). Determine a larger buffer size
1428 * for datafeed submission that is a multiple of the unit size.
626c388a
GS
1429 * Allocate the larger buffer, the "sample buffer" will point
1430 * to a location within that large buffer later.
fc3b42e9
GS
1431 *
1432 * TODO Move channel creation here, and just store required
1433 * parameters in the format parser above? Could simplify the
1434 * arrangement that logic and analog channels get created in
1435 * strict sequence in their respective groups.
4a35548b 1436 */
43bdef26
GS
1437 if (inc->logic_channels) {
1438 inc->sample_unit_size = (inc->logic_channels + 7) / 8;
1439 inc->datafeed_buf_size = CHUNK_SIZE;
1440 inc->datafeed_buf_size *= inc->sample_unit_size;
1441 inc->datafeed_buffer = g_malloc(inc->datafeed_buf_size);
1442 if (!inc->datafeed_buffer) {
1443 sr_err("Cannot allocate datafeed send buffer (logic).");
1444 ret = SR_ERR_MALLOC;
1445 goto out;
1446 }
1447 inc->datafeed_buf_fill = 0;
1448 }
1449
1450 if (inc->analog_channels) {
1451 size_t sample_size, sample_count;
1452 sample_size = sizeof(inc->analog_datafeed_buffer[0]);
1453 inc->analog_datafeed_buf_size = CHUNK_SIZE;
1454 inc->analog_datafeed_buf_size /= sample_size;
1455 inc->analog_datafeed_buf_size /= inc->analog_channels;
1456 sample_count = inc->analog_channels * inc->analog_datafeed_buf_size;
1457 inc->analog_datafeed_buffer = g_malloc0(sample_count * sample_size);
1458 if (!inc->analog_datafeed_buffer) {
1459 sr_err("Cannot allocate datafeed send buffer (analog).");
1460 ret = SR_ERR_MALLOC;
1461 goto out;
1462 }
1463 inc->analog_datafeed_buf_fill = 0;
43bdef26 1464 }
4a35548b 1465
41d214f6
BV
1466out:
1467 if (columns)
1468 g_strfreev(columns);
1469 g_strfreev(lines);
4a35548b 1470
41d214f6 1471 return ret;
4a35548b
MS
1472}
1473
4439363a
GS
1474/*
1475 * Gets called from initial_receive(), which runs until the end-of-line
1476 * encoding of the input stream could get determined. Assumes that this
1477 * routine receives enough buffered initial input data to either see the
1478 * BOM when there is one, or that no BOM will follow when a text line
1479 * termination sequence was seen. Silently drops the UTF-8 BOM sequence
1480 * from the input buffer if one was seen. Does not care to protect
1481 * against multiple execution or dropping the BOM multiple times --
1482 * there should be at most one in the input stream.
1483 */
1484static void initial_bom_check(const struct sr_input *in)
1485{
1486 static const char *utf8_bom = "\xef\xbb\xbf";
1487
1488 if (in->buf->len < strlen(utf8_bom))
1489 return;
1490 if (strncmp(in->buf->str, utf8_bom, strlen(utf8_bom)) != 0)
1491 return;
1492 g_string_erase(in->buf, 0, strlen(utf8_bom));
1493}
1494
41d214f6 1495static int initial_receive(const struct sr_input *in)
4a35548b 1496{
41d214f6
BV
1497 struct context *inc;
1498 GString *new_buf;
1499 int len, ret;
329733d9
UH
1500 char *p;
1501 const char *termination;
4a35548b 1502
4439363a
GS
1503 initial_bom_check(in);
1504
41d214f6 1505 inc = in->priv;
4a35548b 1506
df0db9fd
GS
1507 termination = get_line_termination(in->buf);
1508 if (!termination)
41d214f6 1509 /* Don't have a full line yet. */
d0181813 1510 return SR_ERR_NA;
4a35548b 1511
df0db9fd
GS
1512 p = g_strrstr_len(in->buf->str, in->buf->len, termination);
1513 if (!p)
41d214f6 1514 /* Don't have a full line yet. */
d0181813 1515 return SR_ERR_NA;
41d214f6
BV
1516 len = p - in->buf->str - 1;
1517 new_buf = g_string_new_len(in->buf->str, len);
1518 g_string_append_c(new_buf, '\0');
4a35548b 1519
41d214f6
BV
1520 inc->termination = g_strdup(termination);
1521
1522 if (in->buf->str[0] != '\0')
1523 ret = initial_parse(in, new_buf);
1524 else
1525 ret = SR_OK;
1526
1527 g_string_free(new_buf, TRUE);
1528
1529 return ret;
1530}
1531
7f4c3a62 1532static int process_buffer(struct sr_input *in, gboolean is_eof)
41d214f6 1533{
41d214f6
BV
1534 struct context *inc;
1535 gsize num_columns;
e53f32d2 1536 size_t line_idx, col_idx, col_nr;
836fac9c
GS
1537 const struct column_details *details;
1538 col_parse_cb parse_func;
ad6a2bee 1539 int ret;
fbefa03f
GS
1540 char *processed_up_to;
1541 char **lines, *line, **columns, *column;
41d214f6 1542
41d214f6 1543 inc = in->priv;
d0181813 1544 if (!inc->started) {
bee2b016 1545 std_session_send_df_header(in->sdi);
d0181813 1546 inc->started = TRUE;
4a35548b
MS
1547 }
1548
4555d3bd
GS
1549 /*
1550 * Consider empty input non-fatal. Keep accumulating input until
1551 * at least one full text line has become available. Grab the
1552 * maximum amount of accumulated data that consists of full text
1553 * lines, and process what has been received so far, leaving not
1554 * yet complete lines for the next invocation.
7f4c3a62
GS
1555 *
1556 * Enforce that all previously buffered data gets processed in
1557 * the "EOF" condition. Do not insist in the presence of the
1558 * termination sequence for the last line (may often be missing
1559 * on Windows). A present termination sequence will just result
1560 * in the "execution of an empty line", and does not harm.
4555d3bd
GS
1561 */
1562 if (!in->buf->len)
1563 return SR_OK;
7f4c3a62 1564 if (is_eof) {
fbefa03f 1565 processed_up_to = in->buf->str + in->buf->len;
7f4c3a62 1566 } else {
fbefa03f
GS
1567 processed_up_to = g_strrstr_len(in->buf->str, in->buf->len,
1568 inc->termination);
1569 if (!processed_up_to)
1570 return SR_OK;
1571 *processed_up_to = '\0';
1572 processed_up_to += strlen(inc->termination);
7f4c3a62 1573 }
4a35548b 1574
fbefa03f 1575 /* Split input text lines and process their columns. */
18078d05 1576 ret = SR_OK;
ef0b9935 1577 lines = g_strsplit(in->buf->str, inc->termination, 0);
e53f32d2 1578 for (line_idx = 0; (line = lines[line_idx]); line_idx++) {
41d214f6 1579 inc->line_number++;
ef0b9935
GS
1580 if (inc->line_number < inc->start_line) {
1581 sr_spew("Line %zu skipped (before start).", inc->line_number);
1582 continue;
1583 }
df0db9fd 1584 if (line[0] == '\0') {
41d214f6 1585 sr_spew("Blank line %zu skipped.", inc->line_number);
4a35548b
MS
1586 continue;
1587 }
1588
1589 /* Remove trailing comment. */
df0db9fd
GS
1590 strip_comment(line, inc->comment);
1591 if (line[0] == '\0') {
41d214f6 1592 sr_spew("Comment-only line %zu skipped.", inc->line_number);
4a35548b
MS
1593 continue;
1594 }
1595
160691b9 1596 /* Skip the header line, its content was used as the channel names. */
de8fe3b5 1597 if (inc->use_header && !inc->header_seen) {
160691b9 1598 sr_spew("Header line %zu skipped.", inc->line_number);
de8fe3b5 1599 inc->header_seen = TRUE;
160691b9
JS
1600 continue;
1601 }
1602
e53f32d2
GS
1603 /* Split the line into columns, check for minimum length. */
1604 columns = split_line(line, inc);
df0db9fd 1605 if (!columns) {
41d214f6 1606 sr_err("Error while parsing line %zu.", inc->line_number);
2355d229 1607 g_strfreev(lines);
4a35548b
MS
1608 return SR_ERR;
1609 }
4a35548b 1610 num_columns = g_strv_length(columns);
e53f32d2
GS
1611 if (num_columns < inc->column_want_count) {
1612 sr_err("Insufficient column count %zu in line %zu.",
1613 num_columns, inc->line_number);
4a35548b 1614 g_strfreev(columns);
2355d229 1615 g_strfreev(lines);
4a35548b
MS
1616 return SR_ERR;
1617 }
1618
836fac9c 1619 /* Have the columns of the current text line processed. */
626c388a 1620 clear_logic_samples(inc);
43bdef26 1621 clear_analog_samples(inc);
e53f32d2
GS
1622 for (col_idx = 0; col_idx < inc->column_want_count; col_idx++) {
1623 column = columns[col_idx];
1624 col_nr = col_idx + 1;
836fac9c
GS
1625 details = lookup_column_details(inc, col_nr);
1626 if (!details || !details->text_format)
1627 continue;
1628 parse_func = col_parse_funcs[details->text_format];
1629 if (!parse_func)
1630 continue;
1631 ret = parse_func(column, inc, details);
e53f32d2
GS
1632 if (ret != SR_OK) {
1633 g_strfreev(columns);
1634 g_strfreev(lines);
1635 return SR_ERR;
1636 }
4a35548b
MS
1637 }
1638
626c388a
GS
1639 /* Send sample data to the session bus (buffered). */
1640 ret = queue_logic_samples(in);
43bdef26 1641 ret += queue_analog_samples(in);
41d214f6 1642 if (ret != SR_OK) {
4a35548b 1643 sr_err("Sending samples failed.");
cd59e6ec 1644 g_strfreev(columns);
2355d229 1645 g_strfreev(lines);
4a35548b
MS
1646 return SR_ERR;
1647 }
cd59e6ec 1648
41d214f6
BV
1649 g_strfreev(columns);
1650 }
1651 g_strfreev(lines);
fbefa03f 1652 g_string_erase(in->buf, 0, processed_up_to - in->buf->str);
41d214f6 1653
7066fd46 1654 return ret;
41d214f6
BV
1655}
1656
7066fd46 1657static int receive(struct sr_input *in, GString *buf)
41d214f6
BV
1658{
1659 struct context *inc;
7066fd46
BV
1660 int ret;
1661
1662 g_string_append_len(in->buf, buf->str, buf->len);
41d214f6
BV
1663
1664 inc = in->priv;
1a920e33 1665 if (!inc->column_seen_count) {
df0db9fd
GS
1666 ret = initial_receive(in);
1667 if (ret == SR_ERR_NA)
7066fd46
BV
1668 /* Not enough data yet. */
1669 return SR_OK;
1670 else if (ret != SR_OK)
1671 return SR_ERR;
1672
1673 /* sdi is ready, notify frontend. */
1674 in->sdi_ready = TRUE;
41d214f6 1675 return SR_OK;
7066fd46
BV
1676 }
1677
7f4c3a62 1678 ret = process_buffer(in, FALSE);
7066fd46
BV
1679
1680 return ret;
1681}
1682
1683static int end(struct sr_input *in)
1684{
1685 struct context *inc;
7066fd46 1686 int ret;
41d214f6 1687
7066fd46 1688 if (in->sdi_ready)
7f4c3a62 1689 ret = process_buffer(in, TRUE);
7066fd46
BV
1690 else
1691 ret = SR_OK;
cd59e6ec
GS
1692 if (ret != SR_OK)
1693 return ret;
1694
626c388a 1695 ret = flush_logic_samples(in);
43bdef26 1696 ret += flush_analog_samples(in);
cd59e6ec
GS
1697 if (ret != SR_OK)
1698 return ret;
7066fd46
BV
1699
1700 inc = in->priv;
3be42bc2 1701 if (inc->started)
bee2b016 1702 std_session_send_df_end(in->sdi);
4a35548b 1703
7066fd46
BV
1704 return ret;
1705}
1706
d5cc282f 1707static void cleanup(struct sr_input *in)
7066fd46 1708{
307b2393 1709 struct context *inc, save_ctx;
7066fd46 1710
307b2393 1711 /* Keep channel references between file re-imports. */
affaf540
GS
1712 keep_header_for_reread(in);
1713
307b2393 1714 /* Release dynamically allocated resources. */
7066fd46
BV
1715 inc = in->priv;
1716
b1f83103 1717 g_free(inc->termination);
539188e5 1718 inc->termination = NULL;
cd59e6ec 1719 g_free(inc->datafeed_buffer);
539188e5 1720 inc->datafeed_buffer = NULL;
43bdef26
GS
1721 g_free(inc->analog_datafeed_buffer);
1722 inc->analog_datafeed_buffer = NULL;
307b2393
GS
1723 g_free(inc->analog_datafeed_digits);
1724 inc->analog_datafeed_digits = NULL;
1725 /* analog_datafeed_channels was released in keep_header_for_reread() */
1726 /* TODO Release channel names (before releasing details). */
1727 g_free(inc->column_details);
1728 inc->column_details = NULL;
1729
1730 /* Clear internal state, but keep what .init() has provided. */
1731 save_ctx = *inc;
1732 memset(inc, 0, sizeof(*inc));
1733 inc->samplerate = save_ctx.samplerate;
1734 inc->delimiter = save_ctx.delimiter;
1735 inc->comment = save_ctx.comment;
1736 inc->column_formats = save_ctx.column_formats;
1737 inc->start_line = save_ctx.start_line;
1738 inc->use_header = save_ctx.use_header;
1739 inc->prev_sr_channels = save_ctx.prev_sr_channels;
1740 inc->prev_df_channels = save_ctx.prev_df_channels;
4a35548b
MS
1741}
1742
ad93bfb0
SA
1743static int reset(struct sr_input *in)
1744{
307b2393 1745 struct context *inc;
ad93bfb0 1746
307b2393 1747 inc = in->priv;
ad93bfb0
SA
1748 cleanup(in);
1749 inc->started = FALSE;
1750 g_string_truncate(in->buf, 0);
1751
1752 return SR_OK;
1753}
1754
c6aa9870 1755enum option_index {
2142a79b 1756 OPT_COL_FMTS,
c6aa9870 1757 OPT_SINGLE_COL,
72903e9d 1758 OPT_FIRST_COL,
c6aa9870 1759 OPT_NUM_LOGIC,
43e1e23a
GS
1760 OPT_SINGLE_FMT,
1761 OPT_START_LINE,
72903e9d 1762 OPT_HEADER,
43e1e23a
GS
1763 OPT_SAMPLERATE,
1764 OPT_COL_SEP,
72903e9d 1765 OPT_COMMENT,
c6aa9870
GS
1766 OPT_MAX,
1767};
1768
41d214f6 1769static struct sr_option options[] = {
72903e9d
GS
1770 [OPT_COL_FMTS] = {
1771 "column_formats", "Column format specs",
43e1e23a 1772 "Text columns data types. A comma separated list of [<cols>]<fmt>[<bits>] items. * for all remaining columns. - ignores columns, x/o/b/l logic data, a (and digits) analog data, t timestamps.",
72903e9d
GS
1773 NULL, NULL,
1774 },
1775 [OPT_SINGLE_COL] = {
1776 "single_column", "Single column",
43e1e23a 1777 "Simple single-column mode, exclusively use text from the specified column (number starting at 1). Obsoleted by 'column_formats=4-,x16'.",
72903e9d
GS
1778 NULL, NULL,
1779 },
1780 [OPT_FIRST_COL] = {
1781 "first_column", "First column",
43e1e23a 1782 "First column with logic data in simple multi-column mode (number starting at 1, default 1). Obsoleted by 'column_formats=4-,*l'.",
72903e9d
GS
1783 NULL, NULL,
1784 },
1785 [OPT_NUM_LOGIC] = {
1786 "logic_channels", "Number of logic channels",
43e1e23a 1787 "Logic channel count, required in simple single-column mode, defaults to \"all remaining columns\" in simple multi-column mode. Obsoleted by 'column_formats=8l'.",
72903e9d
GS
1788 NULL, NULL,
1789 },
43e1e23a 1790 [OPT_SINGLE_FMT] = {
72903e9d 1791 "single_format", "Data format for simple single-column mode.",
43e1e23a 1792 "The input text number format of simple single-column mode: bin, hex, oct. Obsoleted by 'column_formats=x8'.",
72903e9d
GS
1793 NULL, NULL,
1794 },
43e1e23a 1795 [OPT_START_LINE] = {
72903e9d
GS
1796 "start_line", "Start line",
1797 "The line number at which to start processing input text (default: 1).",
1798 NULL, NULL,
1799 },
1800 [OPT_HEADER] = {
1801 "header", "Get channel names from first line.",
31b4a9a2 1802 "Use the first processed line's column captions (when available) as channel names. Enabled by default.",
72903e9d
GS
1803 NULL, NULL,
1804 },
43e1e23a 1805 [OPT_SAMPLERATE] = {
72903e9d 1806 "samplerate", "Samplerate (Hz)",
08eb955a 1807 "The input data's sample rate in Hz. No default value.",
72903e9d
GS
1808 NULL, NULL,
1809 },
43e1e23a 1810 [OPT_COL_SEP] = {
72903e9d
GS
1811 "column_separator", "Column separator",
1812 "The sequence which separates text columns. Non-empty text, comma by default.",
1813 NULL, NULL,
1814 },
1815 [OPT_COMMENT] = {
1816 "comment_leader", "Comment leader character",
08eb955a 1817 "The text which starts comments at the end of text lines, semicolon by default.",
72903e9d
GS
1818 NULL, NULL,
1819 },
c6aa9870 1820 [OPT_MAX] = ALL_ZERO,
41d214f6
BV
1821};
1822
2c240774 1823static const struct sr_option *get_options(void)
41d214f6 1824{
31c41782
UH
1825 GSList *l;
1826
41d214f6 1827 if (!options[0].def) {
1a920e33 1828 options[OPT_COL_FMTS].def = g_variant_ref_sink(g_variant_new_string(""));
e53f32d2 1829 options[OPT_SINGLE_COL].def = g_variant_ref_sink(g_variant_new_uint32(0));
72903e9d 1830 options[OPT_FIRST_COL].def = g_variant_ref_sink(g_variant_new_uint32(1));
e53f32d2 1831 options[OPT_NUM_LOGIC].def = g_variant_ref_sink(g_variant_new_uint32(0));
43e1e23a 1832 options[OPT_SINGLE_FMT].def = g_variant_ref_sink(g_variant_new_string("bin"));
31c41782
UH
1833 l = NULL;
1834 l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("bin")));
1835 l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("hex")));
1836 l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("oct")));
43e1e23a
GS
1837 options[OPT_SINGLE_FMT].values = l;
1838 options[OPT_START_LINE].def = g_variant_ref_sink(g_variant_new_uint32(1));
31b4a9a2 1839 options[OPT_HEADER].def = g_variant_ref_sink(g_variant_new_boolean(TRUE));
43e1e23a
GS
1840 options[OPT_SAMPLERATE].def = g_variant_ref_sink(g_variant_new_uint64(0));
1841 options[OPT_COL_SEP].def = g_variant_ref_sink(g_variant_new_string(","));
72903e9d 1842 options[OPT_COMMENT].def = g_variant_ref_sink(g_variant_new_string(";"));
41d214f6
BV
1843 }
1844
1845 return options;
1846}
1847
d4c93774 1848SR_PRIV struct sr_input_module input_csv = {
4a35548b 1849 .id = "csv",
41d214f6
BV
1850 .name = "CSV",
1851 .desc = "Comma-separated values",
c7bc82ff 1852 .exts = (const char*[]){"csv", NULL},
cd7c5f96 1853 .metadata = { SR_INPUT_META_FILENAME, SR_INPUT_META_HEADER | SR_INPUT_META_REQUIRED },
41d214f6 1854 .options = get_options,
cd7c5f96 1855 .format_match = format_match,
4a35548b 1856 .init = init,
41d214f6 1857 .receive = receive,
7066fd46 1858 .end = end,
41d214f6 1859 .cleanup = cleanup,
ad93bfb0 1860 .reset = reset,
4a35548b 1861};