testutils.c 19.6 KB
Newer Older
K
Karel Zak 已提交
1
/*
2
 * testutils.c: basic test utils
K
Karel Zak 已提交
3
 *
4
 * Copyright (C) 2005-2012 Red Hat, Inc.
K
Karel Zak 已提交
5 6 7 8 9 10
 *
 * See COPYING.LIB for the License of this software
 *
 * Karel Zak <kzak@redhat.com>
 */

11
#include <config.h>
12

K
Karel Zak 已提交
13 14 15
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
16 17
#include <sys/types.h>
#include <sys/stat.h>
A
Atsushi SAKAI 已提交
18
#ifndef WIN32
19
# include <sys/wait.h>
A
Atsushi SAKAI 已提交
20
#endif
21
#ifdef HAVE_REGEX_H
22
# include <regex.h>
23
#endif
24
#include <unistd.h>
25
#include <string.h>
26 27
#include <fcntl.h>
#include <limits.h>
K
Karel Zak 已提交
28
#include "testutils.h"
29
#include "internal.h"
30 31
#include "memory.h"
#include "util.h"
32 33
#include "threads.h"
#include "virterror_internal.h"
34 35
#include "buf.h"
#include "logging.h"
E
Eric Blake 已提交
36
#include "command.h"
37
#include "virrandom.h"
38 39

#if TEST_OOM_TRACE
40
# include <execinfo.h>
41
#endif
K
Karel Zak 已提交
42

43
#ifdef HAVE_PATHS_H
44
# include <paths.h>
45 46
#endif

47 48
#define VIR_FROM_THIS VIR_FROM_NONE

K
Karel Zak 已提交
49
#define GETTIMEOFDAY(T) gettimeofday(T, NULL)
50
#define DIFF_MSEC(T, U)                                 \
51
    ((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
52
      ((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)
K
Karel Zak 已提交
53

E
Eric Blake 已提交
54
#include "virfile.h"
55

56
static unsigned int testDebug = -1;
57
static unsigned int testVerbose = -1;
58

59 60 61
static unsigned int testOOM = 0;
static unsigned int testCounter = 0;

E
Eric Blake 已提交
62 63 64
char *progname;
char *abs_srcdir;

K
Karel Zak 已提交
65 66 67
double
virtTestCountAverage(double *items, int nitems)
{
68 69
    long double sum = 0;
    int i;
K
Karel Zak 已提交
70

71 72
    for (i=1; i < nitems; i++)
        sum += items[i];
K
Karel Zak 已提交
73

74
    return (double) (sum / nitems);
K
Karel Zak 已提交
75 76
}

77

78 79 80 81 82
void virtTestResult(const char *name, int ret, const char *msg, ...)
{
    va_list vargs;
    va_start(vargs, msg);

83 84 85
    if (testCounter == 0 && !virTestGetVerbose())
        fprintf(stderr, "      ");

86 87 88 89 90 91 92 93
    testCounter++;
    if (virTestGetVerbose()) {
        fprintf(stderr, "%3d) %-60s ", testCounter, name);
        if (ret == 0)
            fprintf(stderr, "OK\n");
        else {
            fprintf(stderr, "FAILED\n");
            if (msg) {
94 95 96 97 98
                char *str;
                if (virVasprintf(&str, msg, vargs) == 0) {
                    fprintf(stderr, "%s", str);
                    VIR_FREE(str);
                }
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
            }
        }
    } else {
        if (testCounter != 1 &&
            !((testCounter-1) % 40)) {
            fprintf(stderr, " %-3d\n", (testCounter-1));
            fprintf(stderr, "      ");
        }
        if (ret == 0)
            fprintf(stderr, ".");
        else
            fprintf(stderr, "!");
    }

    va_end(vargs);
}

116
/*
K
Karel Zak 已提交
117
 * Runs test and count average time (if the nloops is grater than 1)
118 119
 *
 * returns: -1 = error, 0 = success
K
Karel Zak 已提交
120 121
 */
int
122
virtTestRun(const char *title, int nloops, int (*body)(const void *data), const void *data)
K
Karel Zak 已提交
123
{
124 125
    int i, ret = 0;
    double *ts = NULL;
126

127 128 129
    if (testCounter == 0 && !virTestGetVerbose())
        fprintf(stderr, "      ");

130
    testCounter++;
131

132
    if (testOOM < 2) {
133 134
        if (virTestGetVerbose())
            fprintf(stderr, "%2d) %-65s ... ", testCounter, title);
135
    }
136

137
    if (nloops > 1 && (VIR_ALLOC_N(ts, nloops) < 0))
138 139 140 141 142 143 144
        return -1;

    for (i=0; i < nloops; i++) {
        struct timeval before, after;

        if (ts)
            GETTIMEOFDAY(&before);
145

146
        virResetLastError();
147
        ret = body(data);
148
        virErrorPtr err = virGetLastError();
149 150 151 152 153 154 155 156 157 158
        if (err) {
            if (virTestGetVerbose() || virTestGetDebug())
                virDispatchError(NULL);
        }

        if (ret != 0) {
            break;
        }

        if (ts) {
159 160 161 162
            GETTIMEOFDAY(&after);
            ts[i] = DIFF_MSEC(&after, &before);
        }
    }
163
    if (testOOM < 2) {
164 165 166 167 168 169
        if (virTestGetVerbose()) {
            if (ret == 0 && ts)
                fprintf(stderr, "OK     [%.5f ms]\n",
                        virtTestCountAverage(ts, nloops));
            else if (ret == 0)
                fprintf(stderr, "OK\n");
170 171
            else if (ret == EXIT_AM_SKIP)
                fprintf(stderr, "SKIP\n");
172 173 174 175 176 177 178 179 180 181
            else
                fprintf(stderr, "FAILED\n");
        } else {
            if (testCounter != 1 &&
                !((testCounter-1) % 40)) {
                fprintf(stderr, " %-3d\n", (testCounter-1));
                fprintf(stderr, "      ");
            }
            if (ret == 0)
                fprintf(stderr, ".");
182 183
            else if (ret == EXIT_AM_SKIP)
                fprintf(stderr, "_");
184 185 186
            else
                fprintf(stderr, "!");
        }
187
    }
188

189
    VIR_FREE(ts);
190
    return ret;
K
Karel Zak 已提交
191
}
192

193 194 195 196 197 198
/* Allocate BUF to the size of FILE. Read FILE into buffer BUF.
   Upon any failure, diagnose it and return -1, but don't bother trying
   to preserve errno. Otherwise, return the number of bytes copied into BUF. */
int
virtTestLoadFile(const char *file, char **buf)
{
199
    FILE *fp = fopen(file, "r");
200
    struct stat st;
201 202
    char *tmp;
    int len, tmplen, buflen;
203

204 205
    if (!fp) {
        fprintf (stderr, "%s: failed to open: %s\n", file, strerror(errno));
206
        return -1;
207
    }
208 209

    if (fstat(fileno(fp), &st) < 0) {
210
        fprintf (stderr, "%s: failed to fstat: %s\n", file, strerror(errno));
211
        VIR_FORCE_FCLOSE(fp);
212 213 214
        return -1;
    }

215 216 217 218
    tmplen = buflen = st.st_size + 1;

    if (VIR_ALLOC_N(*buf, buflen) < 0) {
        fprintf (stderr, "%s: larger than available memory (> %d)\n", file, buflen);
219
        VIR_FORCE_FCLOSE(fp);
220 221 222
        return -1;
    }

223
    tmp = *buf;
224
    (*buf)[0] = '\0';
225
    if (st.st_size) {
226 227 228
        /* read the file line by line */
        while (fgets(tmp, tmplen, fp) != NULL) {
            len = strlen(tmp);
229 230 231
            /* stop on an empty line */
            if (len == 0)
                break;
232 233 234 235 236 237 238 239 240 241
            /* remove trailing backslash-newline pair */
            if (len >= 2 && tmp[len-2] == '\\' && tmp[len-1] == '\n') {
                len -= 2;
                tmp[len] = '\0';
            }
            /* advance the temporary buffer pointer */
            tmp += len;
            tmplen -= len;
        }
        if (ferror(fp)) {
242
            fprintf (stderr, "%s: read failed: %s\n", file, strerror(errno));
243
            VIR_FORCE_FCLOSE(fp);
244
            VIR_FREE(*buf);
245 246
            return -1;
        }
247 248
    }

249
    VIR_FORCE_FCLOSE(fp);
250
    return strlen(*buf);
251 252
}

A
Atsushi SAKAI 已提交
253
#ifndef WIN32
254 255
static
void virtTestCaptureProgramExecChild(const char *const argv[],
256 257 258 259 260 261
                                     int pipefd) {
    int i;
    int open_max;
    int stdinfd = -1;
    const char *const env[] = {
        "LANG=C",
262
# if WITH_DRIVER_MODULES
263
        "LIBVIRT_DRIVER_DIR=" TEST_DRIVER_DIR,
264
# endif
265 266 267
        NULL
    };

268
    if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
269 270 271 272 273
        goto cleanup;

    open_max = sysconf (_SC_OPEN_MAX);
    for (i = 0; i < open_max; i++) {
        if (i != stdinfd &&
274 275 276 277
            i != pipefd) {
            int tmpfd = i;
            VIR_FORCE_CLOSE(tmpfd);
        }
278 279 280 281 282 283
    }

    if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
        goto cleanup;
    if (dup2(pipefd, STDOUT_FILENO) != STDOUT_FILENO)
        goto cleanup;
284
    if (dup2(pipefd, STDERR_FILENO) != STDERR_FILENO)
285 286 287 288
        goto cleanup;

    /* SUS is crazy here, hence the cast */
    execve(argv[0], (char *const*)argv, (char *const*)env);
289 290

 cleanup:
291
    VIR_FORCE_CLOSE(stdinfd);
292 293
}

294 295 296
int
virtTestCaptureProgramOutput(const char *const argv[], char **buf, int maxlen)
{
297
    int pipefd[2];
298
    int len;
299 300 301 302

    if (pipe(pipefd) < 0)
        return -1;

303
    pid_t pid = fork();
304
    switch (pid) {
305
    case 0:
306
        VIR_FORCE_CLOSE(pipefd[0]);
307 308
        virtTestCaptureProgramExecChild(argv, pipefd[1]);

309
        VIR_FORCE_CLOSE(pipefd[1]);
310 311
        _exit(1);

312 313
    case -1:
        return -1;
314

315
    default:
316 317 318
        VIR_FORCE_CLOSE(pipefd[1]);
        len = virFileReadLimFD(pipefd[0], maxlen, buf);
        VIR_FORCE_CLOSE(pipefd[0]);
E
Eric Blake 已提交
319 320
        if (virPidWait(pid, NULL) < 0)
            return -1;
321

322
        return len;
323
    }
324
}
325
#else /* !WIN32 */
326 327 328 329 330
int
virtTestCaptureProgramOutput(const char *const argv[] ATTRIBUTE_UNUSED,
                             char **buf ATTRIBUTE_UNUSED,
                             int maxlen ATTRIBUTE_UNUSED)
{
331 332
    return -1;
}
A
Atsushi SAKAI 已提交
333
#endif /* !WIN32 */
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352


/**
 * @param stream: output stream write to differences to
 * @param expect: expected output text
 * @param actual: actual output text
 *
 * Display expected and actual output text, trimmed to
 * first and last characters at which differences occur
 */
int virtTestDifference(FILE *stream,
                       const char *expect,
                       const char *actual)
{
    const char *expectStart = expect;
    const char *expectEnd = expect + (strlen(expect)-1);
    const char *actualStart = actual;
    const char *actualEnd = actual + (strlen(actual)-1);

353
    if (!virTestGetDebug())
354 355
        return 0;

356
    if (virTestGetDebug() < 2) {
357 358 359 360 361 362
        /* Skip to first character where they differ */
        while (*expectStart && *actualStart &&
               *actualStart == *expectStart) {
            actualStart++;
            expectStart++;
        }
363

364 365 366 367 368 369 370
        /* Work backwards to last character where they differ */
        while (actualEnd > actualStart &&
               expectEnd > expectStart &&
               *actualEnd == *expectEnd) {
            actualEnd--;
            expectEnd--;
        }
371 372 373
    }

    /* Show the trimmed differences */
E
Eric Blake 已提交
374
    fprintf(stream, "\nOffset %d\nExpect [", (int) (expectStart - expect));
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
    if ((expectEnd - expectStart + 1) &&
        fwrite(expectStart, (expectEnd-expectStart+1), 1, stream) != 1)
        return -1;
    fprintf(stream, "]\n");
    fprintf(stream, "Actual [");
    if ((actualEnd - actualStart + 1) &&
        fwrite(actualStart, (actualEnd-actualStart+1), 1, stream) != 1)
        return -1;
    fprintf(stream, "]\n");

    /* Pad to line up with test name ... in virTestRun */
    fprintf(stream, "                                                                      ... ");

    return 0;
}
390

391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
/**
 * @param stream: output stream write to differences to
 * @param expect: expected output text
 * @param actual: actual output text
 *
 * Display expected and actual output text, trimmed to
 * first and last characters at which differences occur
 */
int virtTestDifferenceBin(FILE *stream,
                          const char *expect,
                          const char *actual,
                          size_t length)
{
    size_t start = 0, end = length;
    ssize_t i;

    if (!virTestGetDebug())
        return 0;

    if (virTestGetDebug() < 2) {
        /* Skip to first character where they differ */
        for (i = 0 ; i < length ; i++) {
            if (expect[i] != actual[i]) {
                start = i;
                break;
            }
        }

        /* Work backwards to last character where they differ */
        for (i = (length -1) ; i >= 0 ; i--) {
            if (expect[i] != actual[i]) {
                end = i;
                break;
            }
        }
    }
E
Eric Blake 已提交
427
    /* Round to nearest boundary of 4, except that last word can be short */
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
    start -= (start % 4);
    end += 4 - (end % 4);
    if (end >= length)
        end = length - 1;

    /* Show the trimmed differences */
    fprintf(stream, "\nExpect [ Region %d-%d", (int)start, (int)end);
    for (i = start; i < end ; i++) {
        if ((i % 4) == 0)
            fprintf(stream, "\n    ");
        fprintf(stream, "0x%02x, ", ((int)expect[i])&0xff);
    }
    fprintf(stream, "]\n");
    fprintf(stream, "Actual [ Region %d-%d", (int)start, (int)end);
    for (i = start; i < end ; i++) {
        if ((i % 4) == 0)
            fprintf(stream, "\n    ");
        fprintf(stream, "0x%02x, ", ((int)actual[i])&0xff);
    }
    fprintf(stream, "]\n");

    /* Pad to line up with test name ... in virTestRun */
    fprintf(stream, "                                                                      ... ");

    return 0;
}

455
#if TEST_OOM
456 457 458 459
static void
virtTestErrorFuncQuiet(void *data ATTRIBUTE_UNUSED,
                       virErrorPtr err ATTRIBUTE_UNUSED)
{ }
460
#endif
461

462 463 464 465 466 467 468 469 470 471 472
struct virtTestLogData {
    virBuffer buf;
};

static struct virtTestLogData testLog = { VIR_BUFFER_INITIALIZER };

static int
virtTestLogOutput(const char *category ATTRIBUTE_UNUSED,
                  int priority ATTRIBUTE_UNUSED,
                  const char *funcname ATTRIBUTE_UNUSED,
                  long long lineno ATTRIBUTE_UNUSED,
473
                  const char *timestamp,
474
                  unsigned int flags,
475 476
                  const char *str,
                  void *data)
477 478
{
    struct virtTestLogData *log = data;
479
    virCheckFlags(VIR_LOG_STACK_TRACE, -1);
480 481
    virBufferAsprintf(&log->buf, "%s: %s", timestamp, str);
    return strlen(timestamp) + 2 + strlen(str);
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
}

static void
virtTestLogClose(void *data)
{
    struct virtTestLogData *log = data;

    virBufferFreeAndReset(&log->buf);
}

/* Return a malloc'd string (possibly with strlen of 0) of all data
 * logged since the last call to this function, or NULL on failure.  */
char *
virtTestLogContentAndReset(void)
{
    char *ret;

    if (virBufferError(&testLog.buf))
        return NULL;
    ret = virBufferContentAndReset(&testLog.buf);
    return ret ? ret : strdup("");
}

505
#if TEST_OOM_TRACE
506
static void
507
virtTestErrorHook(int n, void *data ATTRIBUTE_UNUSED)
508 509 510 511 512 513 514 515 516
{
    void *trace[30];
    int ntrace = ARRAY_CARDINALITY(trace);
    int i;
    char **symbols = NULL;

    ntrace = backtrace(trace, ntrace);
    symbols = backtrace_symbols(trace, ntrace);
    if (symbols) {
517
        fprintf(stderr, "Failing allocation %d at:\n", n);
518 519 520 521
        for (i = 0 ; i < ntrace ; i++) {
            if (symbols[i])
                fprintf(stderr, "  TRACE:  %s\n", symbols[i]);
        }
522
        VIR_FREE(symbols);
523 524
    }
}
525
#endif
526

527 528 529 530
static unsigned int
virTestGetFlag(const char *name) {
    char *flagStr;
    unsigned int flag;
531

532
    if ((flagStr = getenv(name)) == NULL)
533 534
        return 0;

535
    if (virStrToLong_ui(flagStr, NULL, 10, &flag) < 0)
536 537
        return 0;

538 539 540 541
    return flag;
}

unsigned int
542
virTestGetDebug(void) {
543 544
    if (testDebug == -1)
        testDebug = virTestGetFlag("VIR_TEST_DEBUG");
545 546
    return testDebug;
}
547

548
unsigned int
549
virTestGetVerbose(void) {
550 551 552 553 554
    if (testVerbose == -1)
        testVerbose = virTestGetFlag("VIR_TEST_VERBOSE");
    return testVerbose || virTestGetDebug();
}

555 556
int virtTestMain(int argc,
                 char **argv,
E
Eric Blake 已提交
557
                 int (*func)(void))
558 559
{
    int ret;
560
    bool abs_srcdir_cleanup = false;
561
#if TEST_OOM
562 563
    int approxAlloc = 0;
    int n;
564
    char *oomStr = NULL;
565
    int oomCount;
566 567 568
    int mp = 0;
    pid_t *workers;
    int worker = 0;
569 570
#endif

E
Eric Blake 已提交
571
    abs_srcdir = getenv("abs_srcdir");
572 573 574 575
    if (!abs_srcdir) {
        abs_srcdir = getcwd(NULL, 0);
        abs_srcdir_cleanup = true;
    }
E
Eric Blake 已提交
576 577 578 579 580 581 582 583
    if (!abs_srcdir)
        exit(EXIT_AM_HARDFAIL);

    progname = argv[0];
    if (STRPREFIX(progname, "./"))
        progname += 2;
    if (argc > 1) {
        fprintf(stderr, "Usage: %s\n", argv[0]);
584 585 586 587
        fputs("effective environment variables:\n"
              "VIR_TEST_VERBOSE set to show names of individual tests\n"
              "VIR_TEST_DEBUG set to show information for debugging failures\n",
              stderr);
E
Eric Blake 已提交
588 589 590
        return EXIT_FAILURE;
    }
    fprintf(stderr, "TEST: %s\n", progname);
591

592
    if (virThreadInitialize() < 0 ||
593 594
        virErrorInitialize() < 0 ||
        virRandomInitialize(time(NULL) ^ getpid()))
595 596
        return 1;

597
    virLogSetFromEnv();
598 599 600 601 602
    if (!getenv("LIBVIRT_DEBUG") && !virLogGetNbOutputs()) {
        if (virLogDefineOutput(virtTestLogOutput, virtTestLogClose, &testLog,
                               0, 0, NULL, 0) < 0)
            return 1;
    }
603

604
#if TEST_OOM
605 606 607 608 609 610 611 612 613 614
    if ((oomStr = getenv("VIR_TEST_OOM")) != NULL) {
        if (virStrToLong_i(oomStr, NULL, 10, &oomCount) < 0)
            oomCount = 0;

        if (oomCount < 0)
            oomCount = 0;
        if (oomCount)
            testOOM = 1;
    }

615 616 617
    if (getenv("VIR_TEST_MP") != NULL) {
        mp = sysconf(_SC_NPROCESSORS_ONLN);
        fprintf(stderr, "Using %d worker processes\n", mp);
618 619 620 621
        if (VIR_ALLOC_N(workers, mp) < 0) {
            ret = EXIT_FAILURE;
            goto cleanup;
        }
622 623
    }

D
Daniel P. Berrange 已提交
624
    /* Run once to prime any static allocations & ensure it passes */
E
Eric Blake 已提交
625
    ret = (func)();
626
    if (ret != EXIT_SUCCESS)
627
        goto cleanup;
628

629
# if TEST_OOM_TRACE
630
    if (virTestGetDebug())
631
        virAllocTestHook(virtTestErrorHook, NULL);
632
# endif
633 634 635 636 637 638

    if (testOOM) {
        /* Makes next test runs quiet... */
        testOOM++;
        virSetErrorFunc(NULL, virtTestErrorFuncQuiet);

D
Daniel P. Berrange 已提交
639 640 641
        virAllocTestInit();

        /* Run again to count allocs, and ensure it passes :-) */
E
Eric Blake 已提交
642
        ret = (func)();
D
Daniel P. Berrange 已提交
643 644 645
        if (ret != EXIT_SUCCESS)
            goto cleanup;

646 647
        approxAlloc = virAllocTestCount();
        testCounter++;
648
        if (virTestGetDebug())
649 650 651 652
            fprintf(stderr, "%d) OOM...\n", testCounter);
        else
            fprintf(stderr, "%d) OOM of %d allocs ", testCounter, approxAlloc);

653 654 655 656 657 658 659 660 661 662 663
        if (mp) {
            int i;
            for (i = 0 ; i < mp ; i++) {
                workers[i] = fork();
                if (workers[i] == 0) {
                    worker = i + 1;
                    break;
                }
            }
        }

664 665
        /* Run once for each alloc, failing a different one
           and validating that the test case failed */
666
        for (n = 0; n < approxAlloc && (!mp || worker) ; n++) {
667 668
            if (mp &&
                (n % mp) != (worker - 1))
669
                continue;
670
            if (!virTestGetDebug()) {
671 672 673 674
                if (mp)
                    fprintf(stderr, "%d", worker);
                else
                    fprintf(stderr, ".");
675 676 677 678
                fflush(stderr);
            }
            virAllocTestOOM(n+1, oomCount);

E
Eric Blake 已提交
679
            if (((func)()) != EXIT_FAILURE) {
680 681 682 683 684
                ret = EXIT_FAILURE;
                break;
            }
        }

685 686 687 688 689 690
        if (mp) {
            if (worker) {
                _exit(ret);
            } else {
                int i, status;
                for (i = 0 ; i < mp ; i++) {
E
Eric Blake 已提交
691
                    if (virPidWait(workers[i], NULL) < 0)
692 693 694 695 696 697
                        ret = EXIT_FAILURE;
                }
                VIR_FREE(workers);
            }
        }

698
        if (virTestGetDebug())
699 700 701 702 703 704 705
            fprintf(stderr, " ... OOM of %d allocs", approxAlloc);

        if (ret == EXIT_SUCCESS)
            fprintf(stderr, " OK\n");
        else
            fprintf(stderr, " FAILED\n");
    }
706
cleanup:
707
#else
E
Eric Blake 已提交
708
    ret = (func)();
709
#endif
710

711 712
    if (abs_srcdir_cleanup)
        VIR_FREE(abs_srcdir);
713
    virResetLastError();
714
    if (!virTestGetVerbose() && ret != EXIT_AM_SKIP) {
E
Eric Blake 已提交
715 716
        if (testCounter == 0 || testCounter % 40)
            fprintf(stderr, "%*s", 40 - (testCounter % 40), "");
717 718
        fprintf(stderr, " %-3d %s\n", testCounter, ret == 0 ? "OK" : "FAIL");
    }
719
    return ret;
720
}
721 722


723
#ifdef HAVE_REGEX_H
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
int virtTestClearLineRegex(const char *pattern,
                           char *str)
{
    regex_t reg;
    char *lineStart = str;
    char *lineEnd = strchr(str, '\n');

    if (regcomp(&reg, pattern, REG_EXTENDED | REG_NOSUB) != 0)
        return -1;

    while (lineStart) {
        int ret;
        if (lineEnd)
            *lineEnd = '\0';


        ret = regexec(&reg, lineStart, 0, NULL, 0);
        //fprintf(stderr, "Match %d '%s' '%s'\n", ret, lineStart, pattern);
        if (ret == 0) {
            if (lineEnd) {
                memmove(lineStart, lineEnd + 1, strlen(lineEnd+1) + 1);
                /* Don't update lineStart - just iterate again on this
                   location */
                lineEnd = strchr(lineStart, '\n');
            } else {
                *lineStart = '\0';
                lineStart = NULL;
            }
        } else {
            if (lineEnd) {
                *lineEnd = '\n';
                lineStart = lineEnd + 1;
                lineEnd = strchr(lineStart, '\n');
            } else {
                lineStart = NULL;
            }
        }
    }

    regfree(&reg);

    return 0;
}
767 768 769 770 771 772 773
#else
int virtTestClearLineRegex(const char *pattern ATTRIBUTE_UNUSED,
                           char *str ATTRIBUTE_UNUSED)
{
    return 0;
}
#endif