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