Skip to content

Commit

Permalink
input: unbreak automatic format detection when reading from stdin
Browse files Browse the repository at this point in the history
The combination of reading from stdin and automatic file format match
could result in the execution of an input module's .end() callback
before its .receive() ever executed. Which then suffers from an sdi
which is not yet ready, and no data was sent to the sigrok session.
Fix that.

Unfortunately the input module's accumulator is hidden behind the
libsigrok API. That's why applications cannot defer the forwarding
of the first data chunk from the input file. Insert a .receive() call
with a zero length instead before more file content is consumed. All
existing input modules are prepared to handle this call sequence.
  • Loading branch information
gsigh committed Apr 23, 2022
1 parent 525f481 commit 2b29fb3
Showing 1 changed file with 23 additions and 3 deletions.
26 changes: 23 additions & 3 deletions input.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ static void load_input_file_module(struct df_arg_desc *df_arg)
ssize_t len;
char *mod_id;
gboolean is_stdin;
gboolean push_scan_data;

if (!sr_input_list())
g_critical("No supported input formats available.");
Expand All @@ -56,6 +57,7 @@ static void load_input_file_module(struct df_arg_desc *df_arg)
}

is_stdin = strcmp(opt_input_file, "-") == 0;
push_scan_data = FALSE;
fd = 0;
buf = g_string_sized_new(CHUNK_SIZE);
if (mod_id) {
Expand Down Expand Up @@ -108,6 +110,7 @@ static void load_input_file_module(struct df_arg_desc *df_arg)
g_strerror(errno));
buf->len = len;
sr_input_scan_buffer(buf, &in);
push_scan_data = TRUE;
}
if (!in)
g_critical("Error: no input module found for this file.");
Expand All @@ -116,15 +119,33 @@ static void load_input_file_module(struct df_arg_desc *df_arg)
df_arg->session = session;
sr_session_datafeed_callback_add(session, datafeed_in, df_arg);

/*
* Implementation detail: The combination of reading from stdin
* and automatic file format detection may have pushed the first
* chunk of input data into the input module's data accumulator,
* _bypassing_ the .receive() callback. It is essential to call
* .receive() before calling .end() for files of size smaller than
* CHUNK_SIZE (which is a typical case). So that sdi becomes ready.
* Fortunately all input modules accept .receive() calls with
* a zero length, and inspect whatever was accumulated so far.
*
* After that optional initial push of data which was queued
* above during format detection, continue reading remaining
* chunks from the input file until EOF is seen.
*/
got_sdi = FALSE;
while (TRUE) {
g_string_truncate(buf, 0);
len = read(fd, buf->str, CHUNK_SIZE);
if (push_scan_data)
len = 0;
else
len = read(fd, buf->str, CHUNK_SIZE);
if (len < 0)
g_critical("Read failed: %s", g_strerror(errno));
if (len == 0)
if (len == 0 && !push_scan_data)
/* End of file or stream. */
break;
push_scan_data = FALSE;
buf->len = len;
if (sr_input_send(in, buf) != SR_OK)
break;
Expand All @@ -148,7 +169,6 @@ static void load_input_file_module(struct df_arg_desc *df_arg)

df_arg->session = NULL;
sr_session_destroy(session);

}

void load_input_file(gboolean do_props)
Expand Down

0 comments on commit 2b29fb3

Please sign in to comment.