TESTS = $(check_PROGRAMS)
check_PROGRAMS = \
test-spawn \
- test-ls-version
+ test-ls-version \
+ test-multi-match
test_spawn_SOURCES = test-spawn.c tests.h miniexpect.h
test_spawn_CFLAGS = $(PCRE_CFLAGS) -Wall
test_ls_version_CFLAGS = $(PCRE_CFLAGS) -Wall
test_ls_version_LDADD = libminiexpect.la
+test_multi_match_SOURCES = test-multi-match.c tests.h miniexpect.h
+test_multi_match_CFLAGS = $(PCRE_CFLAGS) -Wall
+test_multi_match_LDADD = libminiexpect.la
+
# parallel-tests breaks the ability to put 'valgrind' into
# TESTS_ENVIRONMENT. Hence we have to work around it:
check-valgrind:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
h->pcre_error = 0;
h->buffer = NULL;
h->len = h->alloc = 0;
+ h->next_match = -1;
h->user1 = h->user2 = h->user3 = NULL;
return h;
free (h->buffer);
h->buffer = NULL;
h->alloc = h->len = 0;
+ h->next_match = -1;
}
int
time (&start_t);
- /* Clear the read buffer. */
- /* XXX This is possibly incorrect because it throws away inputs that
- * may not have been matched yet. A better idea is to record the
- * end of the previous match and only throw that away.
- */
- clear_buffer (h);
+ if (h->next_match == -1) {
+ /* Fully clear the buffer, then read. */
+ clear_buffer (h);
+ } else {
+ /* See the comment in the manual about h->next_match. We have
+ * some data remaining in the buffer, so begin by matching that.
+ */
+ memmove (&h->buffer[0], &h->buffer[h->next_match], h->len - h->next_match);
+ h->len -= h->next_match;
+ h->buffer[h->len] = '\0';
+ h->next_match = -1;
+ goto try_match;
+ }
for (;;) {
/* If we've got a timeout then work out how many seconds are left.
fprintf (stderr, "DEBUG: buffer content: %s\n", h->buffer);
#endif
+ try_match:
/* See if there is a full or partial match against any regexp. */
if (regexps) {
size_t i;
if (r >= 0) {
/* A full match. */
+ if (ovector != NULL && ovecsize >= 1 && ovector[1] >= 0)
+ h->next_match = ovector[1];
+ else
+ h->next_match = -1;
return regexps[i].r;
}
regular expression (and maybe some more). C<buffer> is the read
buffer and C<len> is the number of bytes of data in the buffer.
+ ssize_t next_match;
+
+If C<mexp_expect> returns a match, then C<next_match> points to the
+first byte in the buffer I<after> the fully matched expression. (It
+may be C<-1> which means it is invalid). The next time that
+C<mexp_expect> is called, it will start by consuming the data
+C<buffer[next_match...len-1]>. Callers may also need to read from
+that point in the buffer before calling L<read(2)> on the file
+descriptor. Callers may also set this, for example setting it to
+C<-1> in order to ignore the remainder of the buffer. In most cases
+callers can ignore this field, and C<mexp_expect> will just do the
+right thing when called repeatedly.
+
size_t read_size;
Callers may set this to the natural size (in bytes) for reads from the
--- /dev/null
+/* miniexpect test suite
+ * Copyright (C) 2014 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "miniexpect.h"
+#include "tests.h"
+
+int
+main (int argc, char *argv[])
+{
+ mexp_h *h;
+ int status;
+ int r;
+ int rv[5];
+ size_t i;
+ pcre *multi_re = test_compile_re ("multi");
+ pcre *match_re = test_compile_re ("match");
+ pcre *ing_re = test_compile_re ("ing");
+ pcre *str_re = test_compile_re ("str");
+ pcre *s_re = test_compile_re ("s");
+ const int ovecsize = 12;
+ int ovector[ovecsize];
+
+ /* If the subprocess prints multiple things, we should be able to
+ * repeatedly call mexp_expect to match on each one. This didn't
+ * work correctly in earlier versions of the library.
+ */
+ h = mexp_spawnl ("echo", "echo", "multimatchingstrs", NULL);
+ assert (h != NULL);
+
+ for (i = 0; i < 5; ++i) {
+ r = mexp_expect (h,
+ (mexp_regexp[]) {
+ { 100, multi_re },
+ { 101, match_re },
+ { 102, ing_re },
+ { 103, str_re },
+ { 104, s_re },
+ { 0 },
+ }, ovector, ovecsize);
+ switch (r) {
+ case 100: case 101: case 102: case 103: case 104:
+ printf ("iteration %zu: matched %d\n", i, r);
+ rv[i] = r;
+ break;
+ case MEXP_EOF:
+ fprintf (stderr, "error: unexpected EOF in iteration %zu\n", i);
+ exit (EXIT_FAILURE);
+ case MEXP_TIMEOUT:
+ fprintf (stderr, "error: unexpected timeout in iteration %zu\n", i);
+ exit (EXIT_FAILURE);
+ case MEXP_ERROR:
+ perror ("mexp_expect");
+ exit (EXIT_FAILURE);
+ case MEXP_PCRE_ERROR:
+ fprintf (stderr, "error: PCRE error: %d\n", h->pcre_error);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ assert (rv[0] == 100); /* multi */
+ assert (rv[1] == 101); /* match */
+ assert (rv[2] == 102); /* ing */
+ assert (rv[3] == 103); /* str */
+ assert (rv[4] == 104); /* s */
+
+ status = mexp_close (h);
+ if (status != 0 && !test_is_sighup (status)) {
+ fprintf (stderr, "%s: non-zero exit status from subcommand: ", argv[0]);
+ test_diagnose (status);
+ fprintf (stderr, "\n");
+ exit (EXIT_FAILURE);
+ }
+
+ exit (EXIT_SUCCESS);
+}