]> sigrok.org Git - libsigrok.git/blame - src/input/csv.c
rigol-dg: Fix reading current output signal duty cycle value.
[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];
660 if (inc->use_header && column && *column)
661 caption = sr_scpi_unquote_string(column);
662 else
663 caption = NULL;
664 if (!caption || !*caption)
665 caption = NULL;
3f1f63f0 666 /*
05719d75
GS
667 * Collect channel creation details here, but defer
668 * actual creation of the channels such that all
669 * logic channels can get created first and analog
670 * channels only get created afterwards.
3f1f63f0 671 */
05719d75 672 detail->channel_names = g_malloc0(detail->channel_count * sizeof(detail->channel_names[0]));
9e7af34e
GS
673 for (create_idx = 0; create_idx < detail->channel_count; create_idx++) {
674 if (caption && detail->channel_count == 1) {
675 g_string_assign(channel_name, caption);
676 } else if (caption) {
677 g_string_printf(channel_name, "%s[%zu]",
678 caption, create_idx);
679 } else {
680 g_string_printf(channel_name, "%zu",
681 detail->channel_offset + create_idx);
682 }
05719d75 683 detail->channel_names[create_idx] = g_string_new_len(channel_name->str, channel_name->len);
9e7af34e 684 }
2142a79b
GS
685 }
686 }
9e7af34e 687 g_string_free(channel_name, TRUE);
2142a79b
GS
688 g_strfreev(formats);
689
05719d75
GS
690 /* Create channels in strict logic to analog order. */
691 channel_type = SR_CHANNEL_LOGIC;
692 for (column_idx = 0; column_idx < inc->column_want_count; column_idx++) {
693 detail = &inc->column_details[column_idx];
694 if (!format_is_logic(detail->text_format))
695 continue;
696 for (create_idx = 0; create_idx < detail->channel_count; create_idx++) {
697 caption = detail->channel_names[create_idx]->str;
698 channel_sdi_nr = g_slist_length(in->sdi->channels);
699 sr_channel_new(in->sdi, channel_sdi_nr, channel_type, TRUE, caption);
700 }
701 }
702 channel_type = SR_CHANNEL_ANALOG;
703 for (column_idx = 0; column_idx < inc->column_want_count; column_idx++) {
704 detail = &inc->column_details[column_idx];
705 if (!format_is_analog(detail->text_format))
706 continue;
707 caption = detail->channel_names[0]->str;
708 channel_sdi_nr = g_slist_length(in->sdi->channels);
709 channel = sr_channel_new(in->sdi, channel_sdi_nr, channel_type, TRUE, caption);
710 channel_idx = channel_sdi_nr - inc->logic_channels;
711 inc->analog_datafeed_digits[channel_idx] = detail->analog_digits;
712 inc->analog_datafeed_channels[channel_idx] = g_slist_append(NULL, channel);
713 }
714
2142a79b
GS
715 return SR_OK;
716}
717
e53f32d2
GS
718static const struct column_details *lookup_column_details(struct context *inc, size_t nr)
719{
720 if (!inc || !inc->column_details)
721 return NULL;
722 if (!nr || nr > inc->column_want_count)
723 return NULL;
212769c3 724
e53f32d2
GS
725 return &inc->column_details[nr - 1];
726}
727
19267272
GS
728/*
729 * Primitive operations for text input: Strip comments off text lines.
730 * Split text lines into columns. Process input text for individual
731 * columns.
732 */
733
41d214f6 734static void strip_comment(char *buf, const GString *prefix)
4a35548b
MS
735{
736 char *ptr;
737
738 if (!prefix->len)
739 return;
740
b2c4dde2 741 if ((ptr = strstr(buf, prefix->str))) {
41d214f6 742 *ptr = '\0';
b2c4dde2
GS
743 g_strstrip(buf);
744 }
4a35548b
MS
745}
746
19267272 747/**
51e60cde 748 * Splits a text line into a set of columns.
19267272 749 *
e53f32d2 750 * @param[in] buf The input text line to split.
19267272
GS
751 * @param[in] inc The input module's context.
752 *
e53f32d2 753 * @returns An array of strings, representing the columns' text.
19267272 754 *
e53f32d2 755 * This routine splits a text line on previously determined separators.
19267272 756 */
e53f32d2 757static char **split_line(char *buf, struct context *inc)
4a35548b 758{
e53f32d2 759 return g_strsplit(buf, inc->delimiter->str, 0);
4a35548b
MS
760}
761
19267272 762/**
51e60cde 763 * Parse a multi-bit field into several logic channels.
19267272 764 *
e53f32d2 765 * @param[in] column The input text, a run of bin/hex/oct digits.
19267272 766 * @param[in] inc The input module's context.
836fac9c 767 * @param[in] details The column processing details.
19267272
GS
768 *
769 * @retval SR_OK Success.
770 * @retval SR_ERR Invalid input data (empty, or format error).
771 *
772 * This routine modifies the logic levels in the current sample set,
e53f32d2 773 * based on the text input and a user provided format spec.
19267272 774 */
836fac9c
GS
775static int parse_logic(const char *column, struct context *inc,
776 const struct column_details *details)
4a35548b 777{
e53f32d2
GS
778 size_t length, ch_rem, ch_idx, ch_inc;
779 const char *rdptr;
4a35548b 780 char c;
e53f32d2
GS
781 gboolean valid;
782 const char *type_text;
783 uint8_t bits;
784
e53f32d2
GS
785 /*
786 * Prepare to read the digits from the text end towards the start.
787 * A digit corresponds to a variable number of channels (depending
788 * on the value's radix). Prepare the mapping of text digits to
789 * (a number of) logic channels.
790 */
791 length = strlen(column);
4a35548b 792 if (!length) {
836fac9c 793 sr_err("Column %zu in line %zu is empty.", details->col_nr,
41d214f6 794 inc->line_number);
4a35548b
MS
795 return SR_ERR;
796 }
e53f32d2 797 rdptr = &column[length];
836fac9c
GS
798 ch_idx = details->channel_offset;
799 ch_rem = details->channel_count;
4a35548b 800
e53f32d2
GS
801 /*
802 * Get another digit and derive up to four logic channels' state from
803 * it. Make sure to not process more bits than the column has channels
804 * associated with it.
805 */
806 while (rdptr > column && ch_rem) {
807 /* Check for valid digits according to the input radix. */
808 c = *(--rdptr);
836fac9c 809 switch (details->text_format) {
e53f32d2
GS
810 case FORMAT_BIN:
811 valid = g_ascii_isxdigit(c) && c < '2';
812 ch_inc = 1;
813 break;
814 case FORMAT_OCT:
815 valid = g_ascii_isxdigit(c) && c < '8';
816 ch_inc = 3;
817 break;
818 case FORMAT_HEX:
819 valid = g_ascii_isxdigit(c);
820 ch_inc = 4;
821 break;
822 default:
823 valid = FALSE;
824 break;
4a35548b 825 }
e53f32d2 826 if (!valid) {
836fac9c 827 type_text = col_format_text[details->text_format];
e53f32d2 828 sr_err("Invalid text '%s' in %s type column %zu in line %zu.",
836fac9c 829 column, type_text, details->col_nr, inc->line_number);
4a35548b 830 return SR_ERR;
e53f32d2
GS
831 }
832 /* Use the digit's bits for logic channels' data. */
833 bits = g_ascii_xdigit_value(c);
836fac9c 834 switch (details->text_format) {
e53f32d2
GS
835 case FORMAT_HEX:
836 if (ch_rem >= 4) {
837 ch_rem--;
838 set_logic_level(inc, ch_idx + 3, bits & (1 << 3));
839 }
840 /* FALLTHROUGH */
841 case FORMAT_OCT:
842 if (ch_rem >= 3) {
843 ch_rem--;
844 set_logic_level(inc, ch_idx + 2, bits & (1 << 2));
845 }
846 if (ch_rem >= 2) {
847 ch_rem--;
848 set_logic_level(inc, ch_idx + 1, bits & (1 << 1));
849 }
850 /* FALLTHROUGH */
851 case FORMAT_BIN:
852 ch_rem--;
853 set_logic_level(inc, ch_idx + 0, bits & (1 << 0));
854 break;
fc3b42e9 855 default:
836fac9c
GS
856 /* ShouldNotHappen(TM), but silences compiler warning. */
857 return SR_ERR;
4a35548b 858 }
e53f32d2 859 ch_idx += ch_inc;
4a35548b 860 }
e53f32d2
GS
861 /*
862 * TODO Determine whether the availability of extra input data
863 * for unhandled logic channels is worth warning here. In this
864 * implementation users are in control, and can have the more
865 * significant bits ignored (which can be considered a feature
866 * and not really a limitation).
867 */
4a35548b
MS
868
869 return SR_OK;
870}
871
43bdef26 872/**
51e60cde 873 * Parse a floating point text into an analog value.
43bdef26
GS
874 *
875 * @param[in] column The input text, a floating point number.
876 * @param[in] inc The input module's context.
877 * @param[in] details The column processing details.
878 *
879 * @retval SR_OK Success.
880 * @retval SR_ERR Invalid input data (empty, or format error).
881 *
882 * This routine modifies the analog values in the current sample set,
883 * based on the text input and a user provided format spec.
884 */
885static int parse_analog(const char *column, struct context *inc,
886 const struct column_details *details)
887{
888 size_t length;
889 double dvalue; float fvalue;
890 csv_analog_t value;
891 int ret;
892
fc3b42e9 893 if (!format_is_analog(details->text_format))
43bdef26
GS
894 return SR_ERR_BUG;
895
896 length = strlen(column);
897 if (!length) {
898 sr_err("Column %zu in line %zu is empty.", details->col_nr,
899 inc->line_number);
900 return SR_ERR;
901 }
902 if (sizeof(value) == sizeof(double)) {
903 ret = sr_atod_ascii(column, &dvalue);
904 value = dvalue;
905 } else if (sizeof(value) == sizeof(float)) {
906 ret = sr_atof_ascii(column, &fvalue);
907 value = fvalue;
908 } else {
909 ret = SR_ERR_BUG;
910 }
911 if (ret != SR_OK) {
912 sr_err("Cannot parse analog text %s in column %zu in line %zu.",
913 column, details->col_nr, inc->line_number);
914 return SR_ERR_DATA;
915 }
916 set_analog_value(inc, details->channel_offset, value);
917
918 return SR_OK;
919}
920
7e4e65bf 921/**
51e60cde 922 * Parse a timestamp text, auto-determine samplerate.
7e4e65bf
GS
923 *
924 * @param[in] column The input text, a floating point number.
925 * @param[in] inc The input module's context.
926 * @param[in] details The column processing details.
927 *
928 * @retval SR_OK Success.
929 * @retval SR_ERR Invalid input data (empty, or format error).
930 *
931 * This routine attempts to automatically determine the input data's
932 * samplerate from text rows' timestamp values. Only simple formats are
933 * supported, user provided values always take precedence.
934 */
935static int parse_timestamp(const char *column, struct context *inc,
936 const struct column_details *details)
937{
938 double ts, rate;
939 int ret;
940
941 if (!format_is_timestamp(details->text_format))
942 return SR_ERR_BUG;
943
944 /*
945 * Implementor's notes on timestamp interpretation. Use a simple
946 * approach for improved maintainability which covers most cases
947 * of input data. There is not much gain in adding complexity,
948 * users can easily provide the rate when auto-detection fails.
949 * - Bail out if samplerate is known already.
950 * - Try to interpret the timestamp (simple float conversion).
951 * If conversion fails then clear all previous knowledge and
952 * bail out (non-fatal, perhaps warn). Silently ignore values
953 * of zero since those could be silent fails -- assume that
954 * genuine data contains at least two adjacent rows with useful
955 * timestamps for the feature to work reliably. Annoying users
956 * with "failed to detect" messages is acceptable here, since
957 * users expecting the feature to work should provide useful
958 * data, and there are easy ways to disable the detection or
959 * ignore the column.
960 * - If there is no previous timestamp, keep the current value
961 * for later reference and bail out.
962 * - If a previous timestamp was seen, determine the difference
963 * between them, and derive the samplerate. Update internal
964 * state (the value automatically gets sent to the datafeed),
965 * and clear previous knowledge. Subsequent calls will ignore
966 * following input data (see above, rate is known).
967 *
968 * TODO Potential future improvements:
969 * - Prefer rationals over floats for improved precision and
970 * reduced rounding errors which result in odd rates.
971 * - Support other formats ("2 ms" or similar)?
972 */
811dcf7e 973 if (inc->calc_samplerate)
7e4e65bf
GS
974 return SR_OK;
975 ret = sr_atod_ascii(column, &ts);
976 if (ret != SR_OK)
977 ts = 0.0;
978 if (!ts) {
811dcf7e 979 sr_info("Cannot convert timestamp text %s in line %zu (or zero value).",
7e4e65bf
GS
980 column, inc->line_number);
981 inc->prev_timestamp = 0.0;
982 return SR_OK;
983 }
984 if (!inc->prev_timestamp) {
985 sr_dbg("First timestamp value %g in line %zu.",
986 ts, inc->line_number);
987 inc->prev_timestamp = ts;
988 return SR_OK;
989 }
990 sr_dbg("Second timestamp value %g in line %zu.", ts, inc->line_number);
991 ts -= inc->prev_timestamp;
992 sr_dbg("Timestamp difference %g in line %zu.",
993 ts, inc->line_number);
994 if (!ts) {
995 sr_warn("Zero timestamp difference in line %zu.",
996 inc->line_number);
997 inc->prev_timestamp = ts;
998 return SR_OK;
999 }
1000 rate = 1.0 / ts;
1001 rate += 0.5;
1002 rate = (uint64_t)rate;
1003 sr_dbg("Rate from timestamp %g in line %zu.", rate, inc->line_number);
811dcf7e 1004 inc->calc_samplerate = rate;
7e4e65bf
GS
1005 inc->prev_timestamp = 0.0;
1006
1007 return SR_OK;
1008}
1009
836fac9c 1010/**
51e60cde 1011 * Parse routine which ignores the input text.
836fac9c
GS
1012 *
1013 * This routine exists to unify dispatch code paths, mapping input file
1014 * columns' data types to their respective parse routines.
1015 */
1016static int parse_ignore(const char *column, struct context *inc,
1017 const struct column_details *details)
1018{
1019 (void)column;
1020 (void)inc;
1021 (void)details;
212769c3 1022
836fac9c
GS
1023 return SR_OK;
1024}
1025
1026typedef int (*col_parse_cb)(const char *column, struct context *inc,
1027 const struct column_details *details);
1028
1029static const col_parse_cb col_parse_funcs[] = {
1030 [FORMAT_NONE] = parse_ignore,
1031 [FORMAT_BIN] = parse_logic,
1032 [FORMAT_OCT] = parse_logic,
1033 [FORMAT_HEX] = parse_logic,
43bdef26 1034 [FORMAT_ANALOG] = parse_analog,
7e4e65bf 1035 [FORMAT_TIME] = parse_timestamp,
836fac9c
GS
1036};
1037
cd7c5f96
GS
1038/*
1039 * BEWARE! Implementor's notes. Sync with feature set and default option
1040 * values required during maintenance of the input module implementation.
1041 *
1042 * When applications invoke .format_match() routines, trying automatic
1043 * determination of an input file's format handler, then no options are
1044 * in effect. Because specifying options requires selection of an input
1045 * module to pass the options to, which obsoletes the format-match check.
1046 *
1047 * Which means that we only need to deal with the default format here,
1048 * which happens to be the simple multi-column format without header
1049 * lines or leading garbage. Which means that the check can be rather
1050 * strict, resulting in high levels of confidence upon match, never
1051 * "accidently" winning for unreadable or unsupported-by-default formats.
1052 *
1053 * This .format_match() logic only needs to become more involved when
1054 * default option values change, or when automatic detection of column
1055 * data types improves. Then the supported-by-default types of input
1056 * data must be considered acceptable here in the format-match check
1057 * as well.
1058 *
1059 * Notice that the format check cannot re-use regular processing logic
1060 * when their implementation assumes proper input data and wll generate
1061 * diagnostics for unexpected input data. Failure to match the format is
1062 * non-fatal here, mismatch must remain silent. It's up to applications
1063 * how large a chunk of data gets passed here (start of the file's
1064 * content). But inspection of the first few hundred bytes will usually
1065 * be GoodEnough(TM) for the format-match purpose. Notice that filenames
1066 * need not necessarily be available to the format-match routine.
1067 *
1068 * This implementation errs on the safe side. Users can always select
1069 * the CSV input module when automatic format detection fails.
1070 */
1071static int format_match(GHashTable *metadata, unsigned int *confidence)
1072{
1073 const int match_confidence = 100;
1074 const char *default_extension = ".csv";
1075 const char *line_termination = "\n";
1076 const char *comment_leader = ";";
1077 const char *column_separator = ",";
1078 const char *binary_charset = "01";
1079
1080 const char *fn;
1081 GString *buf;
1082 size_t fn_len;
1083 GString *tmpbuf;
1084 gboolean status;
1085 size_t line_idx, col_idx;
1086 char *rdptr, **lines, *line;
1087 char **cols, *col;
1088
1089 /* Get the application provided input data properties. */
1090 fn = g_hash_table_lookup(metadata, GINT_TO_POINTER(SR_INPUT_META_FILENAME));
1091 buf = g_hash_table_lookup(metadata, GINT_TO_POINTER(SR_INPUT_META_HEADER));
1092
1093 /* Filenames are a strong hint. Use then when available. */
1094 if (fn && *fn && (fn_len = strlen(fn)) >= strlen(default_extension)) {
1095 if (strcasecmp(&fn[fn_len - strlen(default_extension)], default_extension) == 0) {
1096 *confidence = 10;
1097 return SR_OK;
1098 }
1099 }
1100
1101 /*
1102 * Check file content for compatibility with the input module's
1103 * default format. Which translates to:
1104 * - Must be at least one text line worth of input data. Ignore
1105 * incomplete lines at the end of the available buffer.
1106 * - Must be LF terminated text lines, optional CR-LF sequence.
1107 * (Drop CR-only for simplicity since that's rare and users
1108 * can override the automatic detection.)
1109 * - Strip comments and skip empty lines.
1110 * - Data lines must be binary input (potentially multiple bits
1111 * per column which then get ignored). Presence of comma is
1112 * optional but then must be followed by another data column.
1113 * - No other content is acceptable, there neither are ignored
1114 * columns nor analog data nor timestamps in the default layout.
1115 * (See the above "sync format match with default options"
1116 * comment though during maintenance!)
1117 * Run the check on a copy to not affect the caller's buffer.
1118 */
1119 if (!buf || !buf->len || !buf->str || !*buf->str)
1120 return SR_ERR;
1121 rdptr = g_strstr_len(buf->str, buf->len, line_termination);
1122 if (!rdptr)
1123 return SR_ERR;
1124 tmpbuf = g_string_new_len(buf->str, rdptr + 1 - buf->str);
1125 tmpbuf->str[tmpbuf->len - 1] = '\0';
1126 status = TRUE;
1127 *confidence = match_confidence;
1128 lines = g_strsplit(tmpbuf->str, line_termination, 0);
1129 for (line_idx = 0; status && (line = lines[line_idx]); line_idx++) {
1130 rdptr = strstr(line, comment_leader);
1131 if (rdptr)
1132 *rdptr = '\0';
1133 line = g_strstrip(line);
1134 if (!line || !*line)
1135 continue;
1136 cols = g_strsplit(line, column_separator, 0);
1137 if (!cols) {
1138 status = FALSE;
1139 break;
1140 }
1141 for (col_idx = 0; status && (col = cols[col_idx]); col_idx++) {
1142 if (strspn(col, binary_charset) != strlen(col)) {
1143 status = FALSE;
1144 break;
1145 }
1146 }
1147 g_strfreev(cols);
1148 }
1149 g_strfreev(lines);
1150 g_string_free(tmpbuf, TRUE);
1151
1152 if (!status)
1153 return SR_ERR;
212769c3 1154
cd7c5f96
GS
1155 return SR_OK;
1156}
1157
41d214f6 1158static int init(struct sr_input *in, GHashTable *options)
4a35548b 1159{
41d214f6 1160 struct context *inc;
1a920e33 1161 size_t single_column, first_column, logic_channels;
41d214f6 1162 const char *s;
836fac9c 1163 enum single_col_format format;
1a920e33 1164 char format_char;
4a35548b 1165
836fac9c
GS
1166 in->sdi = g_malloc0(sizeof(*in->sdi));
1167 in->priv = inc = g_malloc0(sizeof(*inc));
4a35548b 1168
72903e9d 1169 single_column = g_variant_get_uint32(g_hash_table_lookup(options, "single_column"));
72903e9d 1170 logic_channels = g_variant_get_uint32(g_hash_table_lookup(options, "logic_channels"));
41d214f6 1171 inc->delimiter = g_string_new(g_variant_get_string(
72903e9d 1172 g_hash_table_lookup(options, "column_separator"), NULL));
836fac9c 1173 if (!inc->delimiter->len) {
72903e9d 1174 sr_err("Column separator cannot be empty.");
41d214f6 1175 return SR_ERR_ARG;
4a35548b 1176 }
72903e9d 1177 s = g_variant_get_string(g_hash_table_lookup(options, "single_format"), NULL);
836fac9c
GS
1178 if (g_ascii_strncasecmp(s, "bin", 3) == 0) {
1179 format = FORMAT_BIN;
1180 } else if (g_ascii_strncasecmp(s, "hex", 3) == 0) {
1181 format = FORMAT_HEX;
1182 } else if (g_ascii_strncasecmp(s, "oct", 3) == 0) {
1183 format = FORMAT_OCT;
41d214f6 1184 } else {
72903e9d 1185 sr_err("Invalid single-column format: '%s'", s);
41d214f6 1186 return SR_ERR_ARG;
4a35548b 1187 }
41d214f6 1188 inc->comment = g_string_new(g_variant_get_string(
72903e9d 1189 g_hash_table_lookup(options, "comment_leader"), NULL));
41d214f6 1190 if (g_string_equal(inc->comment, inc->delimiter)) {
e53f32d2
GS
1191 /*
1192 * Using the same sequence as comment leader and column
72903e9d
GS
1193 * separator won't work. The user probably specified ';'
1194 * as the column separator but did not adjust the comment
e53f32d2
GS
1195 * leader. Try DWIM, drop comment strippin support here.
1196 */
72903e9d 1197 sr_warn("Comment leader and column separator conflict, disabling comment support.");
41d214f6 1198 g_string_truncate(inc->comment, 0);
4a35548b 1199 }
6e8d95a5 1200 inc->samplerate = g_variant_get_uint64(g_hash_table_lookup(options, "samplerate"));
72903e9d 1201 first_column = g_variant_get_uint32(g_hash_table_lookup(options, "first_column"));
de8fe3b5 1202 inc->use_header = g_variant_get_boolean(g_hash_table_lookup(options, "header"));
72903e9d 1203 inc->start_line = g_variant_get_uint32(g_hash_table_lookup(options, "start_line"));
41d214f6 1204 if (inc->start_line < 1) {
6433156c 1205 sr_err("Invalid start line %zu.", inc->start_line);
41d214f6 1206 return SR_ERR_ARG;
4a35548b
MS
1207 }
1208
e53f32d2 1209 /*
1a920e33
GS
1210 * Scan flexible, to get prefered format specs which describe
1211 * the input file's data formats. As well as some simple specs
1212 * for backwards compatibility and user convenience.
1213 *
1214 * This logic ends up with a copy of the format string, either
1215 * user provided or internally derived. Actual creation of the
1216 * column processing details gets deferred until the first line
1217 * of input data was seen. To support automatic determination of
1218 * e.g. channel counts from column counts.
e53f32d2 1219 */
72903e9d 1220 s = g_variant_get_string(g_hash_table_lookup(options, "column_formats"), NULL);
2142a79b 1221 if (s && *s) {
1a920e33 1222 inc->column_formats = g_strdup(s);
72903e9d 1223 sr_dbg("User specified column_formats: %s.", s);
1a920e33
GS
1224 } else if (single_column && logic_channels) {
1225 format_char = col_format_char[format];
1226 if (single_column == 1) {
1227 inc->column_formats = g_strdup_printf("%c%zu",
1228 format_char, logic_channels);
e53f32d2 1229 } else {
1a920e33
GS
1230 inc->column_formats = g_strdup_printf("%zu-,%c%zu",
1231 single_column - 1,
1232 format_char, logic_channels);
e53f32d2 1233 }
72903e9d 1234 sr_dbg("Backwards compat single_column, col %zu, fmt %s, bits %zu -> %s.",
1a920e33
GS
1235 single_column, col_format_text[format], logic_channels,
1236 inc->column_formats);
1237 } else if (!single_column) {
1238 if (first_column > 1) {
1239 inc->column_formats = g_strdup_printf("%zu-,%zul",
1240 first_column - 1, logic_channels);
1241 } else {
1242 inc->column_formats = g_strdup_printf("%zul",
1243 logic_channels);
1244 }
1245 sr_dbg("Backwards compat multi-column, col %zu, chans %zu -> %s.",
1246 first_column, logic_channels,
1247 inc->column_formats);
e53f32d2 1248 } else {
72903e9d 1249 sr_warn("Unknown or unsupported columns layout spec, assuming simple multi-column mode.");
1a920e33 1250 inc->column_formats = g_strdup("*l");
4a35548b
MS
1251 }
1252
41d214f6
BV
1253 return SR_OK;
1254}
4a35548b 1255
affaf540
GS
1256/*
1257 * Check the channel list for consistency across file re-import. See
1258 * the VCD input module for more details and motivation.
1259 */
307b2393
GS
1260static void release_df_channels(struct context *inc, GSList **l)
1261{
1262 size_t idx;
1263
1264 if (!inc->analog_channels || !l)
1265 return;
1266 for (idx = 0; idx < inc->analog_channels; idx++)
1267 g_slist_free(l[idx]);
1268 g_free(l);
1269}
affaf540
GS
1270
1271static void keep_header_for_reread(const struct sr_input *in)
1272{
1273 struct context *inc;
1274
1275 inc = in->priv;
307b2393 1276
affaf540
GS
1277 g_slist_free_full(inc->prev_sr_channels, sr_channel_free_cb);
1278 inc->prev_sr_channels = in->sdi->channels;
1279 in->sdi->channels = NULL;
307b2393
GS
1280
1281 release_df_channels(inc, inc->prev_df_channels);
1282 inc->prev_df_channels = inc->analog_datafeed_channels;
1283 inc->analog_datafeed_channels = NULL;
affaf540
GS
1284}
1285
1286static int check_header_in_reread(const struct sr_input *in)
1287{
1288 struct context *inc;
1289
1290 if (!in)
1291 return FALSE;
1292 inc = in->priv;
1293 if (!inc)
1294 return FALSE;
1295 if (!inc->prev_sr_channels)
1296 return TRUE;
1297
1298 if (sr_channel_lists_differ(inc->prev_sr_channels, in->sdi->channels)) {
1299 sr_err("Channel list change not supported for file re-read.");
1300 return FALSE;
1301 }
307b2393 1302
affaf540
GS
1303 g_slist_free_full(in->sdi->channels, sr_channel_free_cb);
1304 in->sdi->channels = inc->prev_sr_channels;
1305 inc->prev_sr_channels = NULL;
1306
307b2393
GS
1307 release_df_channels(inc, inc->analog_datafeed_channels);
1308 inc->analog_datafeed_channels = inc->prev_df_channels;
1309 inc->prev_df_channels = NULL;
1310
affaf540
GS
1311 return TRUE;
1312}
1313
492dfa90
GS
1314static const char *delim_set = "\r\n";
1315
329733d9 1316static const char *get_line_termination(GString *buf)
41d214f6 1317{
329733d9 1318 const char *term;
4a35548b 1319
41d214f6
BV
1320 term = NULL;
1321 if (g_strstr_len(buf->str, buf->len, "\r\n"))
1322 term = "\r\n";
1323 else if (memchr(buf->str, '\n', buf->len))
1324 term = "\n";
1325 else if (memchr(buf->str, '\r', buf->len))
1326 term = "\r";
4a35548b 1327
41d214f6
BV
1328 return term;
1329}
4a35548b 1330
41d214f6
BV
1331static int initial_parse(const struct sr_input *in, GString *buf)
1332{
1333 struct context *inc;
9e7af34e 1334 size_t num_columns;
3f1f63f0 1335 size_t line_number, line_idx;
41d214f6 1336 int ret;
9e7af34e 1337 char **lines, *line, **columns;
41d214f6
BV
1338
1339 ret = SR_OK;
1340 inc = in->priv;
1341 columns = NULL;
1342
9e7af34e 1343 /* Search for the first line to process (header or data). */
41d214f6 1344 line_number = 0;
ef0b9935
GS
1345 if (inc->termination)
1346 lines = g_strsplit(buf->str, inc->termination, 0);
1347 else
1348 lines = g_strsplit_set(buf->str, delim_set, 0);
e53f32d2 1349 for (line_idx = 0; (line = lines[line_idx]); line_idx++) {
41d214f6
BV
1350 line_number++;
1351 if (inc->start_line > line_number) {
e53f32d2 1352 sr_spew("Line %zu skipped (before start).", line_number);
4a35548b
MS
1353 continue;
1354 }
df0db9fd 1355 if (line[0] == '\0') {
41d214f6
BV
1356 sr_spew("Blank line %zu skipped.", line_number);
1357 continue;
1358 }
df0db9fd
GS
1359 strip_comment(line, inc->comment);
1360 if (line[0] == '\0') {
41d214f6 1361 sr_spew("Comment-only line %zu skipped.", line_number);
4a35548b
MS
1362 continue;
1363 }
1364
41d214f6
BV
1365 /* Reached first proper line. */
1366 break;
1367 }
e53f32d2 1368 if (!line) {
41d214f6 1369 /* Not enough data for a proper line yet. */
60107497 1370 ret = SR_ERR_NA;
41d214f6 1371 goto out;
4a35548b
MS
1372 }
1373
9e7af34e 1374 /* Get the number of columns in the line. */
e53f32d2 1375 columns = split_line(line, inc);
df0db9fd 1376 if (!columns) {
41d214f6
BV
1377 sr_err("Error while parsing line %zu.", line_number);
1378 ret = SR_ERR;
1379 goto out;
4a35548b 1380 }
4a35548b 1381 num_columns = g_strv_length(columns);
4a35548b 1382 if (!num_columns) {
e53f32d2 1383 sr_err("Error while parsing line %zu.", line_number);
41d214f6
BV
1384 ret = SR_ERR;
1385 goto out;
4a35548b 1386 }
51e60cde 1387 sr_dbg("Got %zu columns in text line: %s.", num_columns, line);
e53f32d2 1388
1a920e33 1389 /*
9e7af34e
GS
1390 * Interpret the user provided column format specs. This might
1391 * involve inspection of the now received input text, to support
1392 * e.g. automatic detection of channel counts in the absence of
1393 * user provided specs. Optionally a header line is used to get
1394 * channels' names.
1395 *
1396 * Check the then created channels for consistency across .reset
1397 * and .receive sequences (file re-load).
1a920e33 1398 */
9e7af34e 1399 ret = make_column_details_from_format(in, inc->column_formats, columns);
1a920e33
GS
1400 if (ret != SR_OK) {
1401 sr_err("Cannot parse columns format using line %zu.", line_number);
1402 goto out;
4a35548b 1403 }
affaf540
GS
1404 if (!check_header_in_reread(in)) {
1405 ret = SR_ERR_DATA;
1406 goto out;
1407 }
4a35548b
MS
1408
1409 /*
9e7af34e 1410 * Allocate buffer memory for datafeed submission of sample data.
cd59e6ec
GS
1411 * Calculate the minimum buffer size to store the set of samples
1412 * of all channels (unit size). Determine a larger buffer size
1413 * for datafeed submission that is a multiple of the unit size.
626c388a
GS
1414 * Allocate the larger buffer, the "sample buffer" will point
1415 * to a location within that large buffer later.
fc3b42e9
GS
1416 *
1417 * TODO Move channel creation here, and just store required
1418 * parameters in the format parser above? Could simplify the
1419 * arrangement that logic and analog channels get created in
1420 * strict sequence in their respective groups.
4a35548b 1421 */
43bdef26
GS
1422 if (inc->logic_channels) {
1423 inc->sample_unit_size = (inc->logic_channels + 7) / 8;
1424 inc->datafeed_buf_size = CHUNK_SIZE;
1425 inc->datafeed_buf_size *= inc->sample_unit_size;
1426 inc->datafeed_buffer = g_malloc(inc->datafeed_buf_size);
1427 if (!inc->datafeed_buffer) {
1428 sr_err("Cannot allocate datafeed send buffer (logic).");
1429 ret = SR_ERR_MALLOC;
1430 goto out;
1431 }
1432 inc->datafeed_buf_fill = 0;
1433 }
1434
1435 if (inc->analog_channels) {
1436 size_t sample_size, sample_count;
1437 sample_size = sizeof(inc->analog_datafeed_buffer[0]);
1438 inc->analog_datafeed_buf_size = CHUNK_SIZE;
1439 inc->analog_datafeed_buf_size /= sample_size;
1440 inc->analog_datafeed_buf_size /= inc->analog_channels;
1441 sample_count = inc->analog_channels * inc->analog_datafeed_buf_size;
1442 inc->analog_datafeed_buffer = g_malloc0(sample_count * sample_size);
1443 if (!inc->analog_datafeed_buffer) {
1444 sr_err("Cannot allocate datafeed send buffer (analog).");
1445 ret = SR_ERR_MALLOC;
1446 goto out;
1447 }
1448 inc->analog_datafeed_buf_fill = 0;
43bdef26 1449 }
4a35548b 1450
41d214f6
BV
1451out:
1452 if (columns)
1453 g_strfreev(columns);
1454 g_strfreev(lines);
4a35548b 1455
41d214f6 1456 return ret;
4a35548b
MS
1457}
1458
4439363a
GS
1459/*
1460 * Gets called from initial_receive(), which runs until the end-of-line
1461 * encoding of the input stream could get determined. Assumes that this
1462 * routine receives enough buffered initial input data to either see the
1463 * BOM when there is one, or that no BOM will follow when a text line
1464 * termination sequence was seen. Silently drops the UTF-8 BOM sequence
1465 * from the input buffer if one was seen. Does not care to protect
1466 * against multiple execution or dropping the BOM multiple times --
1467 * there should be at most one in the input stream.
1468 */
1469static void initial_bom_check(const struct sr_input *in)
1470{
1471 static const char *utf8_bom = "\xef\xbb\xbf";
1472
1473 if (in->buf->len < strlen(utf8_bom))
1474 return;
1475 if (strncmp(in->buf->str, utf8_bom, strlen(utf8_bom)) != 0)
1476 return;
1477 g_string_erase(in->buf, 0, strlen(utf8_bom));
1478}
1479
41d214f6 1480static int initial_receive(const struct sr_input *in)
4a35548b 1481{
41d214f6
BV
1482 struct context *inc;
1483 GString *new_buf;
1484 int len, ret;
329733d9
UH
1485 char *p;
1486 const char *termination;
4a35548b 1487
4439363a
GS
1488 initial_bom_check(in);
1489
41d214f6 1490 inc = in->priv;
4a35548b 1491
df0db9fd
GS
1492 termination = get_line_termination(in->buf);
1493 if (!termination)
41d214f6 1494 /* Don't have a full line yet. */
d0181813 1495 return SR_ERR_NA;
4a35548b 1496
df0db9fd
GS
1497 p = g_strrstr_len(in->buf->str, in->buf->len, termination);
1498 if (!p)
41d214f6 1499 /* Don't have a full line yet. */
d0181813 1500 return SR_ERR_NA;
41d214f6
BV
1501 len = p - in->buf->str - 1;
1502 new_buf = g_string_new_len(in->buf->str, len);
1503 g_string_append_c(new_buf, '\0');
4a35548b 1504
41d214f6
BV
1505 inc->termination = g_strdup(termination);
1506
1507 if (in->buf->str[0] != '\0')
1508 ret = initial_parse(in, new_buf);
1509 else
1510 ret = SR_OK;
1511
1512 g_string_free(new_buf, TRUE);
1513
1514 return ret;
1515}
1516
7f4c3a62 1517static int process_buffer(struct sr_input *in, gboolean is_eof)
41d214f6 1518{
41d214f6
BV
1519 struct context *inc;
1520 gsize num_columns;
e53f32d2 1521 size_t line_idx, col_idx, col_nr;
836fac9c
GS
1522 const struct column_details *details;
1523 col_parse_cb parse_func;
ad6a2bee 1524 int ret;
fbefa03f
GS
1525 char *processed_up_to;
1526 char **lines, *line, **columns, *column;
41d214f6 1527
41d214f6 1528 inc = in->priv;
d0181813 1529 if (!inc->started) {
bee2b016 1530 std_session_send_df_header(in->sdi);
d0181813 1531 inc->started = TRUE;
4a35548b
MS
1532 }
1533
4555d3bd
GS
1534 /*
1535 * Consider empty input non-fatal. Keep accumulating input until
1536 * at least one full text line has become available. Grab the
1537 * maximum amount of accumulated data that consists of full text
1538 * lines, and process what has been received so far, leaving not
1539 * yet complete lines for the next invocation.
7f4c3a62
GS
1540 *
1541 * Enforce that all previously buffered data gets processed in
1542 * the "EOF" condition. Do not insist in the presence of the
1543 * termination sequence for the last line (may often be missing
1544 * on Windows). A present termination sequence will just result
1545 * in the "execution of an empty line", and does not harm.
4555d3bd
GS
1546 */
1547 if (!in->buf->len)
1548 return SR_OK;
7f4c3a62 1549 if (is_eof) {
fbefa03f 1550 processed_up_to = in->buf->str + in->buf->len;
7f4c3a62 1551 } else {
fbefa03f
GS
1552 processed_up_to = g_strrstr_len(in->buf->str, in->buf->len,
1553 inc->termination);
1554 if (!processed_up_to)
1555 return SR_OK;
1556 *processed_up_to = '\0';
1557 processed_up_to += strlen(inc->termination);
7f4c3a62 1558 }
4a35548b 1559
fbefa03f 1560 /* Split input text lines and process their columns. */
18078d05 1561 ret = SR_OK;
ef0b9935 1562 lines = g_strsplit(in->buf->str, inc->termination, 0);
e53f32d2 1563 for (line_idx = 0; (line = lines[line_idx]); line_idx++) {
41d214f6 1564 inc->line_number++;
ef0b9935
GS
1565 if (inc->line_number < inc->start_line) {
1566 sr_spew("Line %zu skipped (before start).", inc->line_number);
1567 continue;
1568 }
df0db9fd 1569 if (line[0] == '\0') {
41d214f6 1570 sr_spew("Blank line %zu skipped.", inc->line_number);
4a35548b
MS
1571 continue;
1572 }
1573
1574 /* Remove trailing comment. */
df0db9fd
GS
1575 strip_comment(line, inc->comment);
1576 if (line[0] == '\0') {
41d214f6 1577 sr_spew("Comment-only line %zu skipped.", inc->line_number);
4a35548b
MS
1578 continue;
1579 }
1580
160691b9 1581 /* Skip the header line, its content was used as the channel names. */
de8fe3b5 1582 if (inc->use_header && !inc->header_seen) {
160691b9 1583 sr_spew("Header line %zu skipped.", inc->line_number);
de8fe3b5 1584 inc->header_seen = TRUE;
160691b9
JS
1585 continue;
1586 }
1587
e53f32d2
GS
1588 /* Split the line into columns, check for minimum length. */
1589 columns = split_line(line, inc);
df0db9fd 1590 if (!columns) {
41d214f6 1591 sr_err("Error while parsing line %zu.", inc->line_number);
2355d229 1592 g_strfreev(lines);
4a35548b
MS
1593 return SR_ERR;
1594 }
4a35548b 1595 num_columns = g_strv_length(columns);
e53f32d2
GS
1596 if (num_columns < inc->column_want_count) {
1597 sr_err("Insufficient column count %zu in line %zu.",
1598 num_columns, inc->line_number);
4a35548b 1599 g_strfreev(columns);
2355d229 1600 g_strfreev(lines);
4a35548b
MS
1601 return SR_ERR;
1602 }
1603
836fac9c 1604 /* Have the columns of the current text line processed. */
626c388a 1605 clear_logic_samples(inc);
43bdef26 1606 clear_analog_samples(inc);
e53f32d2
GS
1607 for (col_idx = 0; col_idx < inc->column_want_count; col_idx++) {
1608 column = columns[col_idx];
1609 col_nr = col_idx + 1;
836fac9c
GS
1610 details = lookup_column_details(inc, col_nr);
1611 if (!details || !details->text_format)
1612 continue;
1613 parse_func = col_parse_funcs[details->text_format];
1614 if (!parse_func)
1615 continue;
1616 ret = parse_func(column, inc, details);
e53f32d2
GS
1617 if (ret != SR_OK) {
1618 g_strfreev(columns);
1619 g_strfreev(lines);
1620 return SR_ERR;
1621 }
4a35548b
MS
1622 }
1623
626c388a
GS
1624 /* Send sample data to the session bus (buffered). */
1625 ret = queue_logic_samples(in);
43bdef26 1626 ret += queue_analog_samples(in);
41d214f6 1627 if (ret != SR_OK) {
4a35548b 1628 sr_err("Sending samples failed.");
cd59e6ec 1629 g_strfreev(columns);
2355d229 1630 g_strfreev(lines);
4a35548b
MS
1631 return SR_ERR;
1632 }
cd59e6ec 1633
41d214f6
BV
1634 g_strfreev(columns);
1635 }
1636 g_strfreev(lines);
fbefa03f 1637 g_string_erase(in->buf, 0, processed_up_to - in->buf->str);
41d214f6 1638
7066fd46 1639 return ret;
41d214f6
BV
1640}
1641
7066fd46 1642static int receive(struct sr_input *in, GString *buf)
41d214f6
BV
1643{
1644 struct context *inc;
7066fd46
BV
1645 int ret;
1646
1647 g_string_append_len(in->buf, buf->str, buf->len);
41d214f6
BV
1648
1649 inc = in->priv;
1a920e33 1650 if (!inc->column_seen_count) {
df0db9fd
GS
1651 ret = initial_receive(in);
1652 if (ret == SR_ERR_NA)
7066fd46
BV
1653 /* Not enough data yet. */
1654 return SR_OK;
1655 else if (ret != SR_OK)
1656 return SR_ERR;
1657
1658 /* sdi is ready, notify frontend. */
1659 in->sdi_ready = TRUE;
41d214f6 1660 return SR_OK;
7066fd46
BV
1661 }
1662
7f4c3a62 1663 ret = process_buffer(in, FALSE);
7066fd46
BV
1664
1665 return ret;
1666}
1667
1668static int end(struct sr_input *in)
1669{
1670 struct context *inc;
7066fd46 1671 int ret;
41d214f6 1672
7066fd46 1673 if (in->sdi_ready)
7f4c3a62 1674 ret = process_buffer(in, TRUE);
7066fd46
BV
1675 else
1676 ret = SR_OK;
cd59e6ec
GS
1677 if (ret != SR_OK)
1678 return ret;
1679
626c388a 1680 ret = flush_logic_samples(in);
43bdef26 1681 ret += flush_analog_samples(in);
cd59e6ec
GS
1682 if (ret != SR_OK)
1683 return ret;
7066fd46
BV
1684
1685 inc = in->priv;
3be42bc2 1686 if (inc->started)
bee2b016 1687 std_session_send_df_end(in->sdi);
4a35548b 1688
7066fd46
BV
1689 return ret;
1690}
1691
d5cc282f 1692static void cleanup(struct sr_input *in)
7066fd46 1693{
307b2393 1694 struct context *inc, save_ctx;
7066fd46 1695
307b2393 1696 /* Keep channel references between file re-imports. */
affaf540
GS
1697 keep_header_for_reread(in);
1698
307b2393 1699 /* Release dynamically allocated resources. */
7066fd46
BV
1700 inc = in->priv;
1701
b1f83103 1702 g_free(inc->termination);
539188e5 1703 inc->termination = NULL;
cd59e6ec 1704 g_free(inc->datafeed_buffer);
539188e5 1705 inc->datafeed_buffer = NULL;
43bdef26
GS
1706 g_free(inc->analog_datafeed_buffer);
1707 inc->analog_datafeed_buffer = NULL;
307b2393
GS
1708 g_free(inc->analog_datafeed_digits);
1709 inc->analog_datafeed_digits = NULL;
1710 /* analog_datafeed_channels was released in keep_header_for_reread() */
1711 /* TODO Release channel names (before releasing details). */
1712 g_free(inc->column_details);
1713 inc->column_details = NULL;
1714
1715 /* Clear internal state, but keep what .init() has provided. */
1716 save_ctx = *inc;
1717 memset(inc, 0, sizeof(*inc));
1718 inc->samplerate = save_ctx.samplerate;
1719 inc->delimiter = save_ctx.delimiter;
1720 inc->comment = save_ctx.comment;
1721 inc->column_formats = save_ctx.column_formats;
1722 inc->start_line = save_ctx.start_line;
1723 inc->use_header = save_ctx.use_header;
1724 inc->prev_sr_channels = save_ctx.prev_sr_channels;
1725 inc->prev_df_channels = save_ctx.prev_df_channels;
4a35548b
MS
1726}
1727
ad93bfb0
SA
1728static int reset(struct sr_input *in)
1729{
307b2393 1730 struct context *inc;
ad93bfb0 1731
307b2393 1732 inc = in->priv;
ad93bfb0
SA
1733 cleanup(in);
1734 inc->started = FALSE;
1735 g_string_truncate(in->buf, 0);
1736
1737 return SR_OK;
1738}
1739
c6aa9870 1740enum option_index {
2142a79b 1741 OPT_COL_FMTS,
c6aa9870 1742 OPT_SINGLE_COL,
72903e9d 1743 OPT_FIRST_COL,
c6aa9870 1744 OPT_NUM_LOGIC,
43e1e23a
GS
1745 OPT_SINGLE_FMT,
1746 OPT_START_LINE,
72903e9d 1747 OPT_HEADER,
43e1e23a
GS
1748 OPT_SAMPLERATE,
1749 OPT_COL_SEP,
72903e9d 1750 OPT_COMMENT,
c6aa9870
GS
1751 OPT_MAX,
1752};
1753
41d214f6 1754static struct sr_option options[] = {
72903e9d
GS
1755 [OPT_COL_FMTS] = {
1756 "column_formats", "Column format specs",
43e1e23a 1757 "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
1758 NULL, NULL,
1759 },
1760 [OPT_SINGLE_COL] = {
1761 "single_column", "Single column",
43e1e23a 1762 "Simple single-column mode, exclusively use text from the specified column (number starting at 1). Obsoleted by 'column_formats=4-,x16'.",
72903e9d
GS
1763 NULL, NULL,
1764 },
1765 [OPT_FIRST_COL] = {
1766 "first_column", "First column",
43e1e23a 1767 "First column with logic data in simple multi-column mode (number starting at 1, default 1). Obsoleted by 'column_formats=4-,*l'.",
72903e9d
GS
1768 NULL, NULL,
1769 },
1770 [OPT_NUM_LOGIC] = {
1771 "logic_channels", "Number of logic channels",
43e1e23a 1772 "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
1773 NULL, NULL,
1774 },
43e1e23a 1775 [OPT_SINGLE_FMT] = {
72903e9d 1776 "single_format", "Data format for simple single-column mode.",
43e1e23a 1777 "The input text number format of simple single-column mode: bin, hex, oct. Obsoleted by 'column_formats=x8'.",
72903e9d
GS
1778 NULL, NULL,
1779 },
43e1e23a 1780 [OPT_START_LINE] = {
72903e9d
GS
1781 "start_line", "Start line",
1782 "The line number at which to start processing input text (default: 1).",
1783 NULL, NULL,
1784 },
1785 [OPT_HEADER] = {
1786 "header", "Get channel names from first line.",
31b4a9a2 1787 "Use the first processed line's column captions (when available) as channel names. Enabled by default.",
72903e9d
GS
1788 NULL, NULL,
1789 },
43e1e23a 1790 [OPT_SAMPLERATE] = {
72903e9d 1791 "samplerate", "Samplerate (Hz)",
08eb955a 1792 "The input data's sample rate in Hz. No default value.",
72903e9d
GS
1793 NULL, NULL,
1794 },
43e1e23a 1795 [OPT_COL_SEP] = {
72903e9d
GS
1796 "column_separator", "Column separator",
1797 "The sequence which separates text columns. Non-empty text, comma by default.",
1798 NULL, NULL,
1799 },
1800 [OPT_COMMENT] = {
1801 "comment_leader", "Comment leader character",
08eb955a 1802 "The text which starts comments at the end of text lines, semicolon by default.",
72903e9d
GS
1803 NULL, NULL,
1804 },
c6aa9870 1805 [OPT_MAX] = ALL_ZERO,
41d214f6
BV
1806};
1807
2c240774 1808static const struct sr_option *get_options(void)
41d214f6 1809{
31c41782
UH
1810 GSList *l;
1811
41d214f6 1812 if (!options[0].def) {
1a920e33 1813 options[OPT_COL_FMTS].def = g_variant_ref_sink(g_variant_new_string(""));
e53f32d2 1814 options[OPT_SINGLE_COL].def = g_variant_ref_sink(g_variant_new_uint32(0));
72903e9d 1815 options[OPT_FIRST_COL].def = g_variant_ref_sink(g_variant_new_uint32(1));
e53f32d2 1816 options[OPT_NUM_LOGIC].def = g_variant_ref_sink(g_variant_new_uint32(0));
43e1e23a 1817 options[OPT_SINGLE_FMT].def = g_variant_ref_sink(g_variant_new_string("bin"));
31c41782
UH
1818 l = NULL;
1819 l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("bin")));
1820 l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("hex")));
1821 l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("oct")));
43e1e23a
GS
1822 options[OPT_SINGLE_FMT].values = l;
1823 options[OPT_START_LINE].def = g_variant_ref_sink(g_variant_new_uint32(1));
31b4a9a2 1824 options[OPT_HEADER].def = g_variant_ref_sink(g_variant_new_boolean(TRUE));
43e1e23a
GS
1825 options[OPT_SAMPLERATE].def = g_variant_ref_sink(g_variant_new_uint64(0));
1826 options[OPT_COL_SEP].def = g_variant_ref_sink(g_variant_new_string(","));
72903e9d 1827 options[OPT_COMMENT].def = g_variant_ref_sink(g_variant_new_string(";"));
41d214f6
BV
1828 }
1829
1830 return options;
1831}
1832
d4c93774 1833SR_PRIV struct sr_input_module input_csv = {
4a35548b 1834 .id = "csv",
41d214f6
BV
1835 .name = "CSV",
1836 .desc = "Comma-separated values",
c7bc82ff 1837 .exts = (const char*[]){"csv", NULL},
cd7c5f96 1838 .metadata = { SR_INPUT_META_FILENAME, SR_INPUT_META_HEADER | SR_INPUT_META_REQUIRED },
41d214f6 1839 .options = get_options,
cd7c5f96 1840 .format_match = format_match,
4a35548b 1841 .init = init,
41d214f6 1842 .receive = receive,
7066fd46 1843 .end = end,
41d214f6 1844 .cleanup = cleanup,
ad93bfb0 1845 .reset = reset,
4a35548b 1846};