[Spice-devel] [PATCH usbredir 5/9] Add a goto functionality, and take advantage of it.

Jeremy White jwhite at codeweavers.com
Wed Dec 9 14:17:00 PST 2015


We should now be able to do sane-find-scanner indefinitely.

Signed-off-by: Jeremy White <jwhite at codeweavers.com>
---
 usbredirtestserver/scanjet4370.script   |  12 ++
 usbredirtestserver/usbredirtestserver.c | 224 +++++++++++++++++++++++---------
 2 files changed, 176 insertions(+), 60 deletions(-)

diff --git a/usbredirtestserver/scanjet4370.script b/usbredirtestserver/scanjet4370.script
index 54dec41..feb0a9b 100644
--- a/usbredirtestserver/scanjet4370.script
+++ b/usbredirtestserver/scanjet4370.script
@@ -61,3 +61,15 @@ expect ctrl 80:6:80:0:302:409:ff
 ctrl 80:6:80:0:302:409:16 16 03 68 00 70 00 20 00 73 00 63 00 61 00 6e 00 6a 00 65 00 74 00
 expect ctrl 80:6:80:0:303:409:ff
 ctrl 80:6:80:0:303:409:1e 1e 03 43 00 4e 00 36 00 33 00 57 00 41 00 32 00 33 00 57 00 34 00 30 00 34 00 43 00 4d 00
+
+:find
+# This is the result of a 'sane-find-scanner'
+expect ctrl 80:6:80:0:301:0:2
+ctrl 80:6:80:0:301:0:2 20 03
+expect ctrl 80:6:80:0:301:0:20
+ctrl 80:6:80:0:301:0:20 20 03 68 00 65 00 77 00 6c 00 65 00 74 00 74 00 20 00 70 00 61 00 63 00 6b 00 61 00 72 00 64 00
+expect ctrl 80:6:80:0:302:0:2
+ctrl 80:6:80:0:302:0:2 16 03
+expect ctrl 80:6:80:0:302:0:16
+ctrl 80:6:80:0:302:0:16 16 03 68 00 70 00 20 00 73 00 63 00 61 00 6e 00 6a 00 65 00 74 00
+goto find
diff --git a/usbredirtestserver/usbredirtestserver.c b/usbredirtestserver/usbredirtestserver.c
index 2539182..00c82ae 100644
--- a/usbredirtestserver/usbredirtestserver.c
+++ b/usbredirtestserver/usbredirtestserver.c
@@ -79,10 +79,28 @@ typedef struct {
     int data_len;
 } expect_ctrl_t;
 
+#define MAX_LABELS  10
+#define BUFFER_SIZE 65536
+typedef struct {
+    char buffer[BUFFER_SIZE];
+    int fd;
+    int read_into;
+    int read_from;
+    int prompted;
+
+    char *labels[MAX_LABELS];
+    int label_positions[MAX_LABELS];
+} command_buffer_t;
+
+static command_buffer_t *new_command_buffer(char *fname);
+static int command_buffer_read(command_buffer_t *cmd);
+static char * command_buffer_get(command_buffer_t *cmd);
+static void free_command_buffer(command_buffer_t *cmd);
+
 typedef struct {
     int id;
     int fd;
-    int cmd_fd;
+    command_buffer_t *cmd;
     struct usbredirparser *parser;
     struct usb_redir_interface_info_header interface_info;
     struct usb_redir_ep_info_header ep_info;
@@ -149,71 +167,30 @@ static void usage(int exit_code, char *argv0)
 
 static void usbredirtestserver_cmdline_parse(private_info_t *info, char *buf);
 
-static int read_cmd(private_info_t *info, char *buf, int buf_size, int *pos)
-{
-    char *p;
-    int rc;
-
-    if (info->cmd_fd != -1 && *pos < buf_size) {
-        memset(buf + *pos, 0, buf_size - *pos);
-        rc = read(info->cmd_fd, buf + *pos, buf_size - *pos);
-        if (rc == 0) {
-            close(info->cmd_fd);
-            info->cmd_fd = -1;
-        }
-
-        if (rc < 0)
-            return rc;
-
-        *pos += rc;
-    }
-
-    while (*pos > 0 && ! info->expect_ctrl) {
-        p = strchr(buf, '\n');
-        if (!p && info->cmd_fd == -1)
-            p = buf + strlen(buf);
-
-        if (p) {
-            *p = '\0';
-            usbredirtestserver_cmdline_parse(info, buf);
-            *pos -= (p - buf + 1);
-            memmove(buf, p + 1, *pos);
-            *(buf + *pos) = 0;
-            if (info->cmd_fd == STDIN_FILENO)
-                printf("%d> ", info->id); fflush(stdout);
-        }
-    }
-
-    return 0;
-}
 
 static void run_main_loop(private_info_t *info)
 {
-    char buf[1024];
-    int pos = 0;
     fd_set readfds, writefds;
     int n, nfds;
     struct timeval tv;
 
-    printf("device %d connected\n", info->id);
-
-    if (info->cmd_fd == STDIN_FILENO)
-        printf("%d> ", info->id); fflush(stdout);
+    printf("device %d connected, fd %d\n", info->id, info->fd);
+    printf("running %d\n", running);
 
     while (running && info->fd != -1) {
         FD_ZERO(&readfds);
         FD_ZERO(&writefds);
 
-        if (info->cmd_fd != -1)
-            FD_SET(info->cmd_fd, &readfds);
+        if (info->cmd->fd != -1)
+            FD_SET(info->cmd->fd, &readfds);
 
         FD_SET(info->fd, &readfds);
         if (usbredirparser_has_data_to_write(info->parser)) {
             FD_SET(info->fd, &writefds);
         }
         nfds = info->fd + 1;
-        if (info->cmd_fd > info->fd)
-            nfds = info->cmd_fd + 1;
+        if (info->cmd->fd > info->fd)
+            nfds = info->cmd->fd + 1;
 
         tv.tv_sec = 0;
         tv.tv_usec = 1000;
@@ -226,12 +203,19 @@ static void run_main_loop(private_info_t *info)
             break;
         }
 
-        if ( (info->cmd_fd != -1 && FD_ISSET(info->cmd_fd, &readfds)) ||
-                pos > 0) {
-            if (read_cmd(info, buf, sizeof(buf), &pos))
+        if ( (info->cmd->fd != -1 && FD_ISSET(info->cmd->fd, &readfds))) {
+            if (command_buffer_read(info->cmd) < 0)
                 break;
         }
 
+        while (! info->expect_ctrl) {
+            char *command = command_buffer_get(info->cmd);
+            if (! command)
+                break;
+            usbredirtestserver_cmdline_parse(info, command);
+            free(command);
+        }
+
         if (FD_ISSET(info->fd, &readfds)) {
             if (usbredirparser_do_read(info->parser)) {
                 break;
@@ -261,15 +245,9 @@ void run_one_device(int fd, char *script_file, int id)
 
     memset(&private_info, 0, sizeof(private_info));
 
-    if (script_file) {
-        private_info.cmd_fd = open(script_file, O_RDONLY);
-        if (private_info.cmd_fd < 0) {
-            perror("open script");
-            exit(-2);
-        }
-    }
-    else
-        private_info.cmd_fd = STDIN_FILENO;
+    private_info.cmd = new_command_buffer(script_file);
+    if (! private_info.cmd)
+        exit(-1);
 
     flags = fcntl(fd, F_GETFL);
     if (flags == -1) {
@@ -875,3 +853,129 @@ static void usbredirtestserver_interrupt_packet(void *priv, uint64_t id,
 {
     printf("Interrupt packet id %"PRIu64"\n", id);
 }
+
+/* Functions to track and manage a command buffer.
+   This complexity is largely the result of a desire to have
+   a 'goto' command */
+static command_buffer_t *new_command_buffer(char *script_file)
+{
+    command_buffer_t *cmd = malloc(sizeof(*cmd));
+    if (!cmd)
+        return NULL;
+
+    memset(cmd, 0, sizeof(*cmd));
+    if (script_file) {
+        cmd->fd = open(script_file, O_RDONLY);
+        if (cmd->fd < 0) {
+            perror("open script");
+            free(cmd);
+            return NULL;
+        }
+    }
+    else
+        cmd->fd = STDIN_FILENO;
+
+    return cmd;
+}
+
+static int command_buffer_read(command_buffer_t *cmd)
+{
+    int rc;
+    if (cmd->fd == -1)
+        return 0;
+
+    if (cmd->read_into >= sizeof(cmd->buffer) - 1) {
+        /* Our buffer is full... */
+        fprintf(stderr, "Error: buffer full.\n;");
+        exit(-3);
+    }
+
+    if (cmd->fd == STDIN_FILENO && ! cmd->prompted) {
+        printf("> ");
+        fflush(stdout);
+        cmd->prompted = 1;
+    }
+
+    rc = read(cmd->fd, cmd->buffer + cmd->read_into, sizeof(cmd->buffer) - cmd->read_into - 1);
+    if (rc < 0)
+        return rc;
+
+    if (rc == 0)
+        cmd->fd = -1;
+
+    cmd->read_into += rc;
+
+    return rc;
+}
+
+static int intercept_goto_and_labels(command_buffer_t *cmd, char *command)
+{
+    int i;
+
+    if (command[0] == ':') {
+        for (i = 0; i < MAX_LABELS; i++)
+            if (! cmd->labels[i]) {
+                cmd->labels[i] = strdup(command + 1);
+                cmd->label_positions[i] = cmd->read_from;
+                return 1;
+            }
+            /* If we already have this label, ignore it. */
+            else if (strcmp(cmd->labels[i], command + 1) == 0)
+                return 1;
+    }
+
+    if (strlen(command) > 5 && memcmp(command, "goto ", 5) == 0) {
+        for (i = 0; i < MAX_LABELS; i++)
+            if (cmd->labels[i] && strcmp(cmd->labels[i], command + 5) == 0) {
+                cmd->read_from = cmd->label_positions[i];
+                return 1;
+            }
+
+    }
+
+    return 0;
+}
+
+static char *command_buffer_get(command_buffer_t *cmd)
+{
+    char *p;
+    char *ret;
+    int len;
+
+    if (cmd->read_from >= cmd->read_into)
+        return NULL;
+
+    p = strchr(cmd->buffer + cmd->read_from, '\n');
+    if (!p && cmd->fd == -1)
+        p = cmd->buffer + cmd->read_into;
+
+    if (!p)
+        return NULL;
+
+    len = p - (cmd->buffer + cmd->read_from);
+
+    ret = malloc(len + 1);
+    if (! ret)
+        return NULL;
+
+    memcpy(ret, cmd->buffer + cmd->read_from, len);
+    ret[len] = 0;
+    cmd->prompted = 0;
+    cmd->read_from += len + 1;
+
+    if (intercept_goto_and_labels(cmd, ret)) {
+        free(ret);
+        return command_buffer_get(cmd);
+    }
+
+    return ret;
+}
+
+static void free_command_buffer(command_buffer_t *cmd)
+{
+    int i;
+    for (i = 0; i < MAX_LABELS; i++)
+        if (cmd->labels[i])
+            free(cmd->labels[i]);
+    free(cmd);
+}
-- 
2.1.4



More information about the Spice-devel mailing list