]> sigrok.org Git - libsigrok.git/commitdiff
input/csv: unassorted adjustment, mostly "column processing" related
authorGerhard Sittig <redacted>
Tue, 15 Oct 2019 19:11:28 +0000 (21:11 +0200)
committerGerhard Sittig <redacted>
Sat, 21 Dec 2019 17:20:04 +0000 (18:20 +0100)
Reduce "state" in the CSV input module's context. Stick with variables
that are local to routines when knowledge of details need not be global.
Really base the processing of a column's input text on the column's
processing information which was gathered in the setup phase.

Rename few identifiers, to explicitly refer to logic channels (the only
currently supported data type of the CSV input module). Cease feeding
logic data to the session bus when there are no logic channels at all
(currently not really an option). Prepare for simpler dispatching of
parse routines should more data types get added in a future version.

Reduce some "clutter" (overly fragmented stuff that should go together
since it forms logical groups and is not really standalone). Address a
few more minor style nits (sizeof() redundancy, "seemingly inverse"
string comparison phrases).

src/input/csv.c

index 17c253a29d2f29aff5c3cabc6397da1d1fbfecc0..4fc35adbc0997cc8e4ad7c30bf3c71c3a979158e 100644 (file)
@@ -135,31 +135,24 @@ struct context {
        uint64_t samplerate;
        gboolean samplerate_sent;
 
-       /* Number of channels. */
-       size_t num_channels;
+       /* Number of logic channels. */
+       size_t logic_channels;
 
-       /* Column delimiter character(s). */
+       /* Column delimiter (actually separator), comment leader, EOL sequence. */
        GString *delimiter;
-
-       /* Comment prefix character(s). */
        GString *comment;
-
-       /* Termination character(s) used in current stream. */
        char *termination;
 
-       /* Determines if sample data is stored in multiple columns. */
+       /*
+        * Determines if sample data is stored in multiple columns,
+        * which column to start at, and how many columns to expect.
+        */
        gboolean multi_column_mode;
-
-       /* Parameters how to process the columns. */
+       size_t first_column;
        size_t column_want_count;
+       /* Parameters how to process the columns. */
        struct column_details *column_details;
 
-       /* Column number of the sample data in single column mode. */
-       size_t single_column;
-
-       /* Column number of the first channel. */
-       size_t first_column;
-
        /* Line number to start processing. */
        size_t start_line;
 
@@ -170,9 +163,6 @@ struct context {
        gboolean use_header;
        gboolean header_seen;
 
-       /* Format sample data is stored in single column mode. */
-       enum single_col_format format;
-
        size_t sample_unit_size;        /**!< Byte count for a single sample. */
        uint8_t *sample_buffer;         /**!< Buffer for a single sample. */
 
@@ -211,7 +201,7 @@ static void set_logic_level(struct context *inc, size_t ch_idx, int on)
        size_t byte_idx, bit_idx;
        uint8_t bit_mask;
 
-       if (ch_idx >= inc->num_channels)
+       if (ch_idx >= inc->logic_channels)
                return;
        if (!on)
                return;
@@ -270,6 +260,8 @@ static int queue_logic_samples(const struct sr_input *in)
        int rc;
 
        inc = in->priv;
+       if (!inc->logic_channels)
+               return SR_OK;
 
        inc->datafeed_buf_fill += inc->sample_unit_size;
        if (inc->datafeed_buf_fill == inc->datafeed_buf_size) {
@@ -390,7 +382,7 @@ static char **split_line(char *buf, struct context *inc)
  *
  * @param[in] column   The input text, a run of bin/hex/oct digits.
  * @param[in] inc      The input module's context.
- * @param[in] col_nr   The involved column number (1-based).
+ * @param[in] details  The column processing details.
  *
  * @retval SR_OK       Success.
  * @retval SR_ERR      Invalid input data (empty, or format error).
@@ -398,9 +390,9 @@ static char **split_line(char *buf, struct context *inc)
  * This routine modifies the logic levels in the current sample set,
  * based on the text input and a user provided format spec.
  */
-static int parse_column(const char *column, struct context *inc, size_t col_nr)
+static int parse_logic(const char *column, struct context *inc,
+       const struct column_details *details)
 {
-       const struct column_details *col_det;
        size_t length, ch_rem, ch_idx, ch_inc;
        const char *rdptr;
        char c;
@@ -408,16 +400,6 @@ static int parse_column(const char *column, struct context *inc, size_t col_nr)
        const char *type_text;
        uint8_t bits;
 
-       /* See whether and how the columns needs to get processed. */
-       col_det = lookup_column_details(inc, col_nr);
-       if (!col_det) {
-               sr_dbg("Column %zu in line %zu without processing details?",
-                       col_nr, inc->line_number);
-               return SR_ERR;
-       }
-       if (col_det->text_format == FORMAT_NONE)
-               return SR_OK;
-
        /*
         * Prepare to read the digits from the text end towards the start.
         * A digit corresponds to a variable number of channels (depending
@@ -426,13 +408,13 @@ static int parse_column(const char *column, struct context *inc, size_t col_nr)
         */
        length = strlen(column);
        if (!length) {
-               sr_err("Column %zu in line %zu is empty.", col_nr,
+               sr_err("Column %zu in line %zu is empty.", details->col_nr,
                        inc->line_number);
                return SR_ERR;
        }
        rdptr = &column[length];
-       ch_idx = col_det->channel_offset;
-       ch_rem = col_det->channel_count;
+       ch_idx = details->channel_offset;
+       ch_rem = details->channel_count;
 
        /*
         * Get another digit and derive up to four logic channels' state from
@@ -442,7 +424,7 @@ static int parse_column(const char *column, struct context *inc, size_t col_nr)
        while (rdptr > column && ch_rem) {
                /* Check for valid digits according to the input radix. */
                c = *(--rdptr);
-               switch (inc->format) {
+               switch (details->text_format) {
                case FORMAT_BIN:
                        valid = g_ascii_isxdigit(c) && c < '2';
                        ch_inc = 1;
@@ -460,17 +442,14 @@ static int parse_column(const char *column, struct context *inc, size_t col_nr)
                        break;
                }
                if (!valid) {
-                       type_text = col_format_text[inc->format];
+                       type_text = col_format_text[details->text_format];
                        sr_err("Invalid text '%s' in %s type column %zu in line %zu.",
-                               column, type_text, col_nr, inc->line_number);
+                               column, type_text, details->col_nr, inc->line_number);
                        return SR_ERR;
                }
                /* Use the digit's bits for logic channels' data. */
                bits = g_ascii_xdigit_value(c);
-               switch (inc->format) {
-               case FORMAT_NONE:
-                       /* ShouldNotHappen(TM), but silences compiler warning. */
-                       return SR_ERR;
+               switch (details->text_format) {
                case FORMAT_HEX:
                        if (ch_rem >= 4) {
                                ch_rem--;
@@ -491,6 +470,9 @@ static int parse_column(const char *column, struct context *inc, size_t col_nr)
                        ch_rem--;
                        set_logic_level(inc, ch_idx + 0, bits & (1 << 0));
                        break;
+               case FORMAT_NONE:
+                       /* ShouldNotHappen(TM), but silences compiler warning. */
+                       return SR_ERR;
                }
                ch_idx += ch_inc;
        }
@@ -505,34 +487,61 @@ static int parse_column(const char *column, struct context *inc, size_t col_nr)
        return SR_OK;
 }
 
+/**
+ * @brief Parse routine which ignores the input text.
+ *
+ * This routine exists to unify dispatch code paths, mapping input file
+ * columns' data types to their respective parse routines.
+ */
+static int parse_ignore(const char *column, struct context *inc,
+       const struct column_details *details)
+{
+       (void)column;
+       (void)inc;
+       (void)details;
+       return SR_OK;
+}
+
+typedef int (*col_parse_cb)(const char *column, struct context *inc,
+       const struct column_details *details);
+
+static const col_parse_cb col_parse_funcs[] = {
+       [FORMAT_NONE] = parse_ignore,
+       [FORMAT_BIN] = parse_logic,
+       [FORMAT_OCT] = parse_logic,
+       [FORMAT_HEX] = parse_logic,
+};
+
 static int init(struct sr_input *in, GHashTable *options)
 {
        struct context *inc;
+       size_t single_column;
        const char *s;
+       enum single_col_format format;
        int ret;
 
-       in->sdi = g_malloc0(sizeof(struct sr_dev_inst));
-       in->priv = inc = g_malloc0(sizeof(struct context));
+       in->sdi = g_malloc0(sizeof(*in->sdi));
+       in->priv = inc = g_malloc0(sizeof(*inc));
 
-       inc->single_column = g_variant_get_uint32(g_hash_table_lookup(options, "single-column"));
-       inc->multi_column_mode = inc->single_column == 0;
+       single_column = g_variant_get_uint32(g_hash_table_lookup(options, "single-column"));
+       inc->multi_column_mode = single_column == 0;
 
-       inc->num_channels = g_variant_get_uint32(g_hash_table_lookup(options, "numchannels"));
+       inc->logic_channels = g_variant_get_uint32(g_hash_table_lookup(options, "numchannels"));
 
        inc->delimiter = g_string_new(g_variant_get_string(
                        g_hash_table_lookup(options, "delimiter"), NULL));
-       if (inc->delimiter->len == 0) {
+       if (!inc->delimiter->len) {
                sr_err("Column delimiter cannot be empty.");
                return SR_ERR_ARG;
        }
 
        s = g_variant_get_string(g_hash_table_lookup(options, "format"), NULL);
-       if (!g_ascii_strncasecmp(s, "bin", 3)) {
-               inc->format = FORMAT_BIN;
-       } else if (!g_ascii_strncasecmp(s, "hex", 3)) {
-               inc->format = FORMAT_HEX;
-       } else if (!g_ascii_strncasecmp(s, "oct", 3)) {
-               inc->format = FORMAT_OCT;
+       if (g_ascii_strncasecmp(s, "bin", 3) == 0) {
+               format = FORMAT_BIN;
+       } else if (g_ascii_strncasecmp(s, "hex", 3) == 0) {
+               format = FORMAT_HEX;
+       } else if (g_ascii_strncasecmp(s, "oct", 3) == 0) {
+               format = FORMAT_OCT;
        } else {
                sr_err("Invalid format: '%s'", s);
                return SR_ERR_ARG;
@@ -572,25 +581,25 @@ static int init(struct sr_input *in, GHashTable *options)
         * column count here (when the user omitted the spec), and will
         * derive it from the first text line of the input file.
         */
-       if (inc->single_column && inc->num_channels) {
+       if (single_column && inc->logic_channels) {
                sr_dbg("DIAG Got single column (%zu) and channels (%zu).",
-                       inc->single_column, inc->num_channels);
+                       single_column, inc->logic_channels);
                sr_dbg("DIAG -> column %zu, %zu bits in %s format.",
-                       inc->single_column, inc->num_channels,
-                       col_format_text[inc->format]);
+                       single_column, inc->logic_channels,
+                       col_format_text[format]);
                ret = make_column_details_single(inc,
-                       inc->single_column, inc->num_channels, inc->format);
+                       single_column, inc->logic_channels, format);
                if (ret != SR_OK)
                        return ret;
        } else if (inc->multi_column_mode) {
                sr_dbg("DIAG Got multi-column, first column %zu, count %zu.",
-                       inc->first_column, inc->num_channels);
-               if (inc->num_channels) {
+                       inc->first_column, inc->logic_channels);
+               if (inc->logic_channels) {
                        sr_dbg("DIAG -> columns %zu-%zu, 1 bit each.",
                                inc->first_column,
-                               inc->first_column + inc->num_channels - 1);
+                               inc->first_column + inc->logic_channels - 1);
                        ret = make_column_details_multi(inc, inc->first_column,
-                               inc->first_column + inc->num_channels - 1);
+                               inc->first_column + inc->logic_channels - 1);
                        if (ret != SR_OK)
                                return ret;
                } else {
@@ -718,13 +727,13 @@ static int initial_parse(const struct sr_input *in, GString *buf)
        sr_dbg("DIAG Got %zu columns in text line: %s.", num_columns, line);
 
        /* Optionally update incomplete multi-column specs. */
-       if (inc->multi_column_mode && !inc->num_channels) {
-               inc->num_channels = num_columns - inc->first_column + 1;
+       if (inc->multi_column_mode && !inc->logic_channels) {
+               inc->logic_channels = num_columns - inc->first_column + 1;
                sr_dbg("DIAG -> multi-column update: columns %zu-%zu, 1 bit each.",
                        inc->first_column,
-                       inc->first_column + inc->num_channels - 1);
+                       inc->first_column + inc->logic_channels - 1);
                ret = make_column_details_multi(inc, inc->first_column,
-                       inc->first_column + inc->num_channels - 1);
+                       inc->first_column + inc->logic_channels - 1);
                if (ret != SR_OK)
                        goto out;
        }
@@ -790,7 +799,7 @@ static int initial_parse(const struct sr_input *in, GString *buf)
         * Allocate the larger buffer, the "sample buffer" will point
         * to a location within that large buffer later.
         */
-       inc->sample_unit_size = (inc->num_channels + 7) / 8;
+       inc->sample_unit_size = (inc->logic_channels + 7) / 8;
        inc->datafeed_buf_size = CHUNK_SIZE;
        inc->datafeed_buf_size *= inc->sample_unit_size;
        inc->datafeed_buffer = g_malloc(inc->datafeed_buf_size);
@@ -867,6 +876,8 @@ static int process_buffer(struct sr_input *in, gboolean is_eof)
        struct context *inc;
        gsize num_columns;
        size_t line_idx, col_idx, col_nr;
+       const struct column_details *details;
+       col_parse_cb parse_func;
        int ret;
        char *p, **lines, *line, **columns, *column;
 
@@ -941,12 +952,18 @@ static int process_buffer(struct sr_input *in, gboolean is_eof)
                        return SR_ERR;
                }
 
+               /* Have the columns of the current text line processed. */
                clear_logic_samples(inc);
-
                for (col_idx = 0; col_idx < inc->column_want_count; col_idx++) {
                        column = columns[col_idx];
                        col_nr = col_idx + 1;
-                       ret = parse_column(column, inc, col_nr);
+                       details = lookup_column_details(inc, col_nr);
+                       if (!details || !details->text_format)
+                               continue;
+                       parse_func = col_parse_funcs[details->text_format];
+                       if (!parse_func)
+                               continue;
+                       ret = parse_func(column, inc, details);
                        if (ret != SR_OK) {
                                g_strfreev(columns);
                                g_strfreev(lines);