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