+ /* Split the input spec, count involved columns and channels. */
+ formats = g_strsplit(column_format, ",", 0);
+ if (!formats) {
+ sr_err("Cannot parse columns format %s (comma split).", column_format);
+ return SR_ERR_ARG;
+ }
+ format_count = g_strv_length(formats);
+ if (!format_count) {
+ sr_err("Cannot parse columns format %s (field count).", column_format);
+ g_strfreev(formats);
+ return SR_ERR_ARG;
+ }
+ column_count = logic_count = analog_count = 0;
+ auto_column_count = 0;
+ for (format_idx = 0; format_idx < format_count; format_idx++) {
+ format = formats[format_idx];
+ ret = split_column_format(format, &c, &f, &b);
+ sr_dbg("fmt %s -> %zu cols, %s fmt, %zu bits, rc %d", format, c, col_format_text[f], b, ret);
+ if (ret != SR_OK) {
+ sr_err("Cannot parse columns format %s (field split, %s).", column_format, format);
+ g_strfreev(formats);
+ return SR_ERR_ARG;
+ }
+ if (f && !c) {
+ /* User requested "auto-count", must be last format. */
+ if (formats[format_idx + 1]) {
+ sr_err("Auto column count must be last format field.");
+ g_strfreev(formats);
+ return SR_ERR_ARG;
+ }
+ auto_column_count = inc->column_seen_count - column_count;
+ c = auto_column_count;
+ }
+ column_count += c;
+ if (format_is_analog(f))
+ analog_count += c;
+ else if (format_is_logic(f))
+ logic_count += c * b;
+ }
+ sr_dbg("Column format %s -> %zu columns, %zu logic, %zu analog channels.",
+ column_format, column_count, logic_count, analog_count);
+
+ /* Allocate and fill in "column processing" details. */
+ inc->column_want_count = column_count;
+ if (inc->column_seen_count < inc->column_want_count) {
+ sr_err("Insufficient input text width for desired data amount, got %zu but want %zu columns.",
+ inc->column_seen_count, inc->column_want_count);
+ g_strfreev(formats);
+ return SR_ERR_ARG;
+ }
+ inc->logic_channels = logic_count;
+ inc->analog_channels = analog_count;
+ inc->analog_datafeed_digits = g_malloc0(inc->analog_channels * sizeof(inc->analog_datafeed_digits[0]));
+ inc->analog_datafeed_channels = g_malloc0(inc->analog_channels * sizeof(inc->analog_datafeed_channels[0]));
+ inc->column_details = g_malloc0_n(column_count, sizeof(inc->column_details[0]));
+ column_idx = channel_idx = analog_idx = 0;
+ channel_name = g_string_sized_new(64);
+ for (format_idx = 0; format_idx < format_count; format_idx++) {
+ /* Process a format field, which can span multiple columns. */
+ format = formats[format_idx];
+ (void)split_column_format(format, &c, &f, &b);
+ if (f && !c)
+ c = auto_column_count;
+ while (c-- > 0) {
+ /* Fill in a column's processing details. */
+ detail = &inc->column_details[column_idx++];
+ detail->col_nr = column_idx;
+ detail->text_format = f;
+ if (format_is_analog(detail->text_format)) {
+ detail->channel_offset = analog_idx;
+ detail->channel_count = 1;
+ detail->analog_digits = b;
+ analog_idx += detail->channel_count;
+ } else if (format_is_logic(detail->text_format)) {
+ detail->channel_offset = channel_idx;
+ detail->channel_count = b;
+ channel_idx += detail->channel_count;
+ } else if (format_is_ignore(detail->text_format)) {
+ /* EMPTY */
+ continue;
+ } else {
+ /*
+ * Neither logic nor analog data, nor ignore.
+ * Format was noted. No channel creation involved.
+ */
+ continue;
+ }
+ /*
+ * Pick most appropriate channel names. Optionally
+ * use text from a header line (when requested by the
+ * user). In the absence of header text, channels are
+ * assigned rather generic names.
+ *
+ * Manipulation of the column's caption (when a header
+ * line is seen) is acceptable, because this header
+ * line won't get processed another time.
+ */
+ column = column_texts[detail->col_nr - 1];
+ if (inc->use_header && column && *column) {
+ column = g_strstrip(column);
+ caption = sr_scpi_unquote_string(column);
+ } else {
+ caption = NULL;
+ }
+ if (!caption || !*caption)
+ caption = NULL;
+ /*
+ * Collect channel creation details here, but defer
+ * actual creation of the channels such that all
+ * logic channels can get created first and analog
+ * channels only get created afterwards.
+ */
+ detail->channel_names = g_malloc0(detail->channel_count * sizeof(detail->channel_names[0]));
+ for (create_idx = 0; create_idx < detail->channel_count; create_idx++) {
+ if (caption && detail->channel_count == 1) {
+ g_string_assign(channel_name, caption);
+ } else if (caption) {
+ g_string_printf(channel_name, "%s[%zu]",
+ caption, create_idx);
+ } else {
+ g_string_printf(channel_name, "%zu",
+ detail->channel_offset + create_idx);
+ }
+ detail->channel_names[create_idx] = g_string_new_len(channel_name->str, channel_name->len);
+ }