GSList *prev_sr_channels;
};
+/*
+ * Primitive operations for text input: Strip comments off text lines.
+ * Split text lines into columns. Process input text for individual
+ * columns.
+ */
+
static void strip_comment(char *buf, const GString *prefix)
{
char *ptr;
if (!prefix->len)
return;
- if ((ptr = strstr(buf, prefix->str)))
+ if ((ptr = strstr(buf, prefix->str))) {
*ptr = '\0';
+ g_strstrip(buf);
+ }
}
+/* TODO Move parse_line() here. */
+
+/**
+ * @brief Parse a text field into multiple bits, binary presentation.
+ *
+ * @param[in] str The input text, a run of 0/1 digits.
+ * @param[in] inc The input module's context.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Invalid input data (empty, or format error).
+ *
+ * This routine modifies the logic levels in the current sample set,
+ * based on the text input which consists of binary digits.
+ */
static int parse_binstr(const char *str, struct context *inc)
{
gsize i, j, length;
return SR_OK;
}
+/**
+ * @brief Parse a text field into multiple bits, hexadecimal presentation.
+ *
+ * @param[in] str The input text, a run of hex digits.
+ * @param[in] inc The input module's context.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Invalid input data (empty, or format error).
+ *
+ * This routine modifies the logic levels in the current sample set,
+ * based on the text input which consists of hexadecimal digits.
+ */
static int parse_hexstr(const char *str, struct context *inc)
{
gsize i, j, k, length;
return SR_OK;
}
+/**
+ * @brief Parse a text field into multiple bits, octal presentation.
+ *
+ * @param[in] str The input text, a run of oct digits.
+ * @param[in] inc The input module's context.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Invalid input data (empty, or format error).
+ *
+ * This routine modifies the logic levels in the current sample set,
+ * based on the text input which consists of octal digits.
+ */
static int parse_octstr(const char *str, struct context *inc)
{
gsize i, j, k, length;
return SR_OK;
}
+static int parse_single_column(const char *column, struct context *inc)
+{
+ switch (inc->format) {
+ case FORMAT_BIN:
+ return parse_binstr(column, inc);
+ case FORMAT_HEX:
+ return parse_hexstr(column, inc);
+ case FORMAT_OCT:
+ return parse_octstr(column, inc);
+ }
+
+ return SR_ERR;
+}
+
/**
* @brief Splits a text line into a set of columns.
*
* @param[in] max_cols The maximum column count, negative to get all of them.
*
* @returns An array of strings, representing the columns' text.
+ *
+ * This routine splits a text line on previously determined separators.
+ * A previously determined set of columns gets isolated (starting at a
+ * first position and spanning a given number of columns). A negative
+ * value for the maximum number of columns results in no restriction on
+ * the result set's length (the first columns still get trimmed off).
*/
static char **parse_line(char *buf, struct context *inc, ssize_t max_cols)
{
GSList *list, *l;
char **columns;
char *column;
- gsize n, k;
+ gsize seen, taken;
- n = 0;
- k = 0;
+ seen = 0;
+ taken = 0;
list = NULL;
remainder = buf;
str = strstr(remainder, inc->delimiter->str);
-
while (str && max_cols) {
- if (n >= inc->first_column) {
+ if (seen >= inc->first_column) {
column = g_strndup(remainder, str - remainder);
list = g_slist_prepend(list, g_strstrip(column));
max_cols--;
- k++;
+ taken++;
}
remainder = str + inc->delimiter->len;
str = strstr(remainder, inc->delimiter->str);
- n++;
+ seen++;
}
- if (buf[0] && max_cols && n >= inc->first_column) {
+ if (buf[0] && max_cols && seen >= inc->first_column) {
column = g_strdup(remainder);
list = g_slist_prepend(list, g_strstrip(column));
- k++;
+ taken++;
}
- if (!(columns = g_try_new(char *, k + 1)))
+ if (!(columns = g_try_new(char *, taken + 1)))
return NULL;
-
- columns[k--] = NULL;
-
+ columns[taken--] = NULL;
for (l = list; l; l = l->next)
- columns[k--] = l->data;
+ columns[taken--] = l->data;
g_slist_free(list);
return columns;
}
+/**
+ * @brief Picks logic levels from multiple binary colomns, one channel per column.
+ *
+ * @param[in] columns The text fields which are kept in the columns.
+ * @param[in] inc The input module's context.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Insufficient input, or syntax errors.
+ *
+ * This routine exclusively handles binary input where one logic channel
+ * occupies one column each. All channels are expected to reside in one
+ * consequtive run of columns.
+ */
static int parse_multi_columns(char **columns, struct context *inc)
{
gsize i;
for (i = 0; i < inc->num_channels; i++) {
column = columns[i];
- if (column[0] == '1') {
+ if (strcmp(column, "1") == 0) {
inc->sample_buffer[i / 8] |= (1 << (i % 8));
} else if (!strlen(column)) {
sr_err("Column %zu in line %zu is empty.",
inc->first_channel + i, inc->line_number);
return SR_ERR;
- } else if (column[0] != '0') {
+ } else if (strcmp(column, "0") != 0) {
sr_err("Invalid value '%s' in column %zu in line %zu.",
column, inc->first_channel + i,
inc->line_number);
return SR_OK;
}
-static int parse_single_column(const char *column, struct context *inc)
-{
- int res;
-
- res = SR_ERR;
-
- switch (inc->format) {
- case FORMAT_BIN:
- res = parse_binstr(column, inc);
- break;
- case FORMAT_HEX:
- res = parse_hexstr(column, inc);
- break;
- case FORMAT_OCT:
- res = parse_octstr(column, inc);
- break;
- }
-
- return res;
-}
-
static int flush_samples(const struct sr_input *in)
{
struct context *inc;
return SR_OK;
}
+enum option_index {
+ OPT_SINGLE_COL,
+ OPT_NUM_LOGIC,
+ OPT_DELIM,
+ OPT_FORMAT,
+ OPT_COMMENT,
+ OPT_RATE,
+ OPT_FIRST_LOGIC,
+ OPT_HEADER,
+ OPT_START,
+ OPT_MAX,
+};
+
static struct sr_option options[] = {
- { "single-column", "Single column", "Enable single-column mode, using the specified column (>= 1); 0: multi-col. mode", NULL, NULL },
- { "numchannels", "Number of logic channels", "The number of (logic) channels (single-col. mode: number of bits beginning at 'first channel', LSB-first)", NULL, NULL },
- { "delimiter", "Column delimiter", "The column delimiter (>= 1 characters)", NULL, NULL },
- { "format", "Data format (single-col. mode)", "The numeric format of the data (single-col. mode): bin, hex, oct", NULL, NULL },
- { "comment", "Comment character(s)", "The comment prefix character(s)", NULL, NULL },
- { "samplerate", "Samplerate (Hz)", "The sample rate (used during capture) in Hz", NULL, NULL },
- { "first-channel", "First channel", "The column number of the first channel (multi-col. mode); bit position for the first channel (single-col. mode)", NULL, NULL },
- { "header", "Interpret first line as header (multi-col. mode)", "Treat the first line as header with channel names (multi-col. mode)", NULL, NULL },
- { "startline", "Start line", "The line number at which to start processing samples (>= 1)", NULL, NULL },
- ALL_ZERO
+ [OPT_SINGLE_COL] = { "single-column", "Single column", "Enable single-column mode, using the specified column (>= 1); 0: multi-col. mode", NULL, NULL },
+ [OPT_NUM_LOGIC] = { "numchannels", "Number of logic channels", "The number of (logic) channels (single-col. mode: number of bits beginning at 'first channel', LSB-first)", NULL, NULL },
+ [OPT_DELIM] = { "delimiter", "Column delimiter", "The column delimiter (>= 1 characters)", NULL, NULL },
+ [OPT_FORMAT] = { "format", "Data format (single-col. mode)", "The numeric format of the data (single-col. mode): bin, hex, oct", NULL, NULL },
+ [OPT_COMMENT] = { "comment", "Comment character(s)", "The comment prefix character(s)", NULL, NULL },
+ [OPT_RATE] = { "samplerate", "Samplerate (Hz)", "The sample rate (used during capture) in Hz", NULL, NULL },
+ [OPT_FIRST_LOGIC] = { "first-channel", "First channel", "The column number of the first channel (multi-col. mode); bit position for the first channel (single-col. mode)", NULL, NULL },
+ [OPT_HEADER] = { "header", "Interpret first line as header (multi-col. mode)", "Treat the first line as header with channel names (multi-col. mode)", NULL, NULL },
+ [OPT_START] = { "startline", "Start line", "The line number at which to start processing samples (>= 1)", NULL, NULL },
+ [OPT_MAX] = ALL_ZERO,
};
static const struct sr_option *get_options(void)
GSList *l;
if (!options[0].def) {
- options[0].def = g_variant_ref_sink(g_variant_new_int32(0));
- options[1].def = g_variant_ref_sink(g_variant_new_int32(0));
- options[2].def = g_variant_ref_sink(g_variant_new_string(","));
- options[3].def = g_variant_ref_sink(g_variant_new_string("bin"));
+ options[OPT_SINGLE_COL].def = g_variant_ref_sink(g_variant_new_int32(0));
+ options[OPT_NUM_LOGIC].def = g_variant_ref_sink(g_variant_new_int32(0));
+ options[OPT_DELIM].def = g_variant_ref_sink(g_variant_new_string(","));
+ options[OPT_FORMAT].def = g_variant_ref_sink(g_variant_new_string("bin"));
l = NULL;
l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("bin")));
l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("hex")));
l = g_slist_append(l, g_variant_ref_sink(g_variant_new_string("oct")));
- options[3].values = l;
- options[4].def = g_variant_ref_sink(g_variant_new_string(";"));
- options[5].def = g_variant_ref_sink(g_variant_new_uint64(0));
- options[6].def = g_variant_ref_sink(g_variant_new_int32(0));
- options[7].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
- options[8].def = g_variant_ref_sink(g_variant_new_int32(1));
+ options[OPT_FORMAT].values = l;
+ options[OPT_COMMENT].def = g_variant_ref_sink(g_variant_new_string(";"));
+ options[OPT_RATE].def = g_variant_ref_sink(g_variant_new_uint64(0));
+ options[OPT_FIRST_LOGIC].def = g_variant_ref_sink(g_variant_new_int32(0));
+ options[OPT_HEADER].def = g_variant_ref_sink(g_variant_new_boolean(FALSE));
+ options[OPT_START].def = g_variant_ref_sink(g_variant_new_int32(1));
}
return options;