testutils.c 18.8 KB
Newer Older
K
Karel Zak 已提交
1
/*
2
 * testutils.c: basic test utils
K
Karel Zak 已提交
3
 *
4
 * Copyright (C) 2005-2011 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"
36 37

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

41
#ifdef HAVE_PATHS_H
42
# include <paths.h>
43 44
#endif

K
Karel Zak 已提交
45
#define GETTIMEOFDAY(T) gettimeofday(T, NULL)
46
#define DIFF_MSEC(T, U)                                 \
47
    ((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
48
      ((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)
K
Karel Zak 已提交
49

50 51
#include "files.h"

52
static unsigned int testDebug = -1;
53
static unsigned int testVerbose = -1;
54

55 56 57
static unsigned int testOOM = 0;
static unsigned int testCounter = 0;

E
Eric Blake 已提交
58 59 60
char *progname;
char *abs_srcdir;

K
Karel Zak 已提交
61 62 63
double
virtTestCountAverage(double *items, int nitems)
{
64 65
    long double sum = 0;
    int i;
K
Karel Zak 已提交
66

67 68
    for (i=1; i < nitems; i++)
        sum += items[i];
K
Karel Zak 已提交
69

70
    return (double) (sum / nitems);
K
Karel Zak 已提交
71 72
}

73
ATTRIBUTE_FMT_PRINTF(3,4)
74 75 76 77 78
void virtTestResult(const char *name, int ret, const char *msg, ...)
{
    va_list vargs;
    va_start(vargs, msg);

79 80 81
    if (testCounter == 0 && !virTestGetVerbose())
        fprintf(stderr, "      ");

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
    testCounter++;
    if (virTestGetVerbose()) {
        fprintf(stderr, "%3d) %-60s ", testCounter, name);
        if (ret == 0)
            fprintf(stderr, "OK\n");
        else {
            fprintf(stderr, "FAILED\n");
            if (msg) {
                vfprintf(stderr, msg, vargs);
            }
        }
    } 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);
}

108
/*
K
Karel Zak 已提交
109
 * Runs test and count average time (if the nloops is grater than 1)
110 111
 *
 * returns: -1 = error, 0 = success
K
Karel Zak 已提交
112 113
 */
int
114
virtTestRun(const char *title, int nloops, int (*body)(const void *data), const void *data)
K
Karel Zak 已提交
115
{
116 117
    int i, ret = 0;
    double *ts = NULL;
118

119 120 121
    if (testCounter == 0 && !virTestGetVerbose())
        fprintf(stderr, "      ");

122
    testCounter++;
123

124
    if (testOOM < 2) {
125 126
        if (virTestGetVerbose())
            fprintf(stderr, "%2d) %-65s ... ", testCounter, title);
127
    }
128 129 130 131 132 133 134 135 136 137

    if (nloops > 1 && (ts = calloc(nloops,
                                   sizeof(double)))==NULL)
        return -1;

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

        if (ts)
            GETTIMEOFDAY(&before);
138

139
        virResetLastError();
140
        ret = body(data);
141
        virErrorPtr err = virGetLastError();
142 143 144 145 146 147 148 149 150 151
        if (err) {
            if (virTestGetVerbose() || virTestGetDebug())
                virDispatchError(NULL);
        }

        if (ret != 0) {
            break;
        }

        if (ts) {
152 153 154 155
            GETTIMEOFDAY(&after);
            ts[i] = DIFF_MSEC(&after, &before);
        }
    }
156
    if (testOOM < 2) {
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
        if (virTestGetVerbose()) {
            if (ret == 0 && ts)
                fprintf(stderr, "OK     [%.5f ms]\n",
                        virtTestCountAverage(ts, nloops));
            else if (ret == 0)
                fprintf(stderr, "OK\n");
            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, ".");
            else
                fprintf(stderr, "!");
        }
176
    }
177

178
    free(ts);
179
    return ret;
K
Karel Zak 已提交
180
}
181

182 183 184 185 186 187
/* 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)
{
188
    FILE *fp = fopen(file, "r");
189
    struct stat st;
190 191
    char *tmp;
    int len, tmplen, buflen;
192

193 194
    if (!fp) {
        fprintf (stderr, "%s: failed to open: %s\n", file, strerror(errno));
195
        return -1;
196
    }
197 198

    if (fstat(fileno(fp), &st) < 0) {
199
        fprintf (stderr, "%s: failed to fstat: %s\n", file, strerror(errno));
200
        VIR_FORCE_FCLOSE(fp);
201 202 203
        return -1;
    }

204 205 206 207
    tmplen = buflen = st.st_size + 1;

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

212
    tmp = *buf;
213
    (*buf)[0] = '\0';
214
    if (st.st_size) {
215 216 217
        /* read the file line by line */
        while (fgets(tmp, tmplen, fp) != NULL) {
            len = strlen(tmp);
218 219 220
            /* stop on an empty line */
            if (len == 0)
                break;
221 222 223 224 225 226 227 228 229 230
            /* 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)) {
231
            fprintf (stderr, "%s: read failed: %s\n", file, strerror(errno));
232
            VIR_FORCE_FCLOSE(fp);
233
            free(*buf);
234 235
            return -1;
        }
236 237
    }

238
    VIR_FORCE_FCLOSE(fp);
239
    return strlen(*buf);
240 241
}

A
Atsushi SAKAI 已提交
242
#ifndef WIN32
243 244
static
void virtTestCaptureProgramExecChild(const char *const argv[],
245 246 247 248 249 250
                                     int pipefd) {
    int i;
    int open_max;
    int stdinfd = -1;
    const char *const env[] = {
        "LANG=C",
251
# if WITH_DRIVER_MODULES
252
        "LIBVIRT_DRIVER_DIR=" TEST_DRIVER_DIR,
253
# endif
254 255 256
        NULL
    };

257
    if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
258 259 260 261 262
        goto cleanup;

    open_max = sysconf (_SC_OPEN_MAX);
    for (i = 0; i < open_max; i++) {
        if (i != stdinfd &&
263 264 265 266
            i != pipefd) {
            int tmpfd = i;
            VIR_FORCE_CLOSE(tmpfd);
        }
267 268 269 270 271 272
    }

    if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
        goto cleanup;
    if (dup2(pipefd, STDOUT_FILENO) != STDOUT_FILENO)
        goto cleanup;
273
    if (dup2(pipefd, STDERR_FILENO) != STDERR_FILENO)
274 275 276 277
        goto cleanup;

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

 cleanup:
280
    VIR_FORCE_CLOSE(stdinfd);
281 282
}

283 284 285
int
virtTestCaptureProgramOutput(const char *const argv[], char **buf, int maxlen)
{
286
    int pipefd[2];
287
    int len;
288 289 290 291 292 293

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

    int pid = fork();
    switch (pid) {
294
    case 0:
295
        VIR_FORCE_CLOSE(pipefd[0]);
296 297
        virtTestCaptureProgramExecChild(argv, pipefd[1]);

298
        VIR_FORCE_CLOSE(pipefd[1]);
299 300
        _exit(1);

301 302
    case -1:
        return -1;
303

304
    default:
305 306 307 308
        VIR_FORCE_CLOSE(pipefd[1]);
        len = virFileReadLimFD(pipefd[0], maxlen, buf);
        VIR_FORCE_CLOSE(pipefd[0]);
        waitpid(pid, NULL, 0);
309

310
        return len;
311
    }
312
}
313
#else /* !WIN32 */
314 315 316 317 318
int
virtTestCaptureProgramOutput(const char *const argv[] ATTRIBUTE_UNUSED,
                             char **buf ATTRIBUTE_UNUSED,
                             int maxlen ATTRIBUTE_UNUSED)
{
319 320
    return -1;
}
A
Atsushi SAKAI 已提交
321
#endif /* !WIN32 */
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340


/**
 * @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);

341
    if (!virTestGetDebug())
342 343
        return 0;

344
    if (virTestGetDebug() < 2) {
345 346 347 348 349 350
        /* Skip to first character where they differ */
        while (*expectStart && *actualStart &&
               *actualStart == *expectStart) {
            actualStart++;
            expectStart++;
        }
351

352 353 354 355 356 357 358
        /* Work backwards to last character where they differ */
        while (actualEnd > actualStart &&
               expectEnd > expectStart &&
               *actualEnd == *expectEnd) {
            actualEnd--;
            expectEnd--;
        }
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
    }

    /* Show the trimmed differences */
    fprintf(stream, "\nExpect [");
    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;
}
378

379 380 381 382 383 384 385 386 387 388 389 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
/**
 * @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 已提交
415
    /* Round to nearest boundary of 4, except that last word can be short */
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
    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;
}

443
#if TEST_OOM
444 445 446 447
static void
virtTestErrorFuncQuiet(void *data ATTRIBUTE_UNUSED,
                       virErrorPtr err ATTRIBUTE_UNUSED)
{ }
448
#endif
449

450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
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,
                  const char *str, int len, void *data)
{
    struct virtTestLogData *log = data;
    virBufferAdd(&log->buf, str, len);
    return len;
}

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("");
}

489
#if TEST_OOM_TRACE
490
static void
491
virtTestErrorHook(int n, void *data ATTRIBUTE_UNUSED)
492 493 494 495 496 497 498 499 500
{
    void *trace[30];
    int ntrace = ARRAY_CARDINALITY(trace);
    int i;
    char **symbols = NULL;

    ntrace = backtrace(trace, ntrace);
    symbols = backtrace_symbols(trace, ntrace);
    if (symbols) {
501
        fprintf(stderr, "Failing allocation %d at:\n", n);
502 503 504 505 506 507 508
        for (i = 0 ; i < ntrace ; i++) {
            if (symbols[i])
                fprintf(stderr, "  TRACE:  %s\n", symbols[i]);
        }
        free(symbols);
    }
}
509
#endif
510

511 512 513 514
static unsigned int
virTestGetFlag(const char *name) {
    char *flagStr;
    unsigned int flag;
515

516
    if ((flagStr = getenv(name)) == NULL)
517 518
        return 0;

519
    if (virStrToLong_ui(flagStr, NULL, 10, &flag) < 0)
520 521
        return 0;

522 523 524 525
    return flag;
}

unsigned int
526
virTestGetDebug(void) {
527 528
    if (testDebug == -1)
        testDebug = virTestGetFlag("VIR_TEST_DEBUG");
529 530
    return testDebug;
}
531

532
unsigned int
533
virTestGetVerbose(void) {
534 535 536 537 538
    if (testVerbose == -1)
        testVerbose = virTestGetFlag("VIR_TEST_VERBOSE");
    return testVerbose || virTestGetDebug();
}

539 540
int virtTestMain(int argc,
                 char **argv,
E
Eric Blake 已提交
541
                 int (*func)(void))
542 543
{
    int ret;
544
    bool abs_srcdir_cleanup = false;
545
#if TEST_OOM
546 547
    int approxAlloc = 0;
    int n;
548
    char *oomStr = NULL;
549
    int oomCount;
550 551 552
    int mp = 0;
    pid_t *workers;
    int worker = 0;
553 554
#endif

E
Eric Blake 已提交
555
    abs_srcdir = getenv("abs_srcdir");
556 557 558 559
    if (!abs_srcdir) {
        abs_srcdir = getcwd(NULL, 0);
        abs_srcdir_cleanup = true;
    }
E
Eric Blake 已提交
560 561 562 563 564 565 566 567 568 569 570
    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]);
        return EXIT_FAILURE;
    }
    fprintf(stderr, "TEST: %s\n", progname);
571

572
    if (virThreadInitialize() < 0 ||
573 574
        virErrorInitialize() < 0 ||
        virRandomInitialize(time(NULL) ^ getpid()))
575 576
        return 1;

577
    virLogSetFromEnv();
578 579 580 581 582
    if (!getenv("LIBVIRT_DEBUG") && !virLogGetNbOutputs()) {
        if (virLogDefineOutput(virtTestLogOutput, virtTestLogClose, &testLog,
                               0, 0, NULL, 0) < 0)
            return 1;
    }
583

584
#if TEST_OOM
585 586 587 588 589 590 591 592 593 594
    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;
    }

595 596 597
    if (getenv("VIR_TEST_MP") != NULL) {
        mp = sysconf(_SC_NPROCESSORS_ONLN);
        fprintf(stderr, "Using %d worker processes\n", mp);
598 599 600 601
        if (VIR_ALLOC_N(workers, mp) < 0) {
            ret = EXIT_FAILURE;
            goto cleanup;
        }
602 603
    }

D
Daniel P. Berrange 已提交
604
    /* Run once to prime any static allocations & ensure it passes */
E
Eric Blake 已提交
605
    ret = (func)();
606
    if (ret != EXIT_SUCCESS)
607
        goto cleanup;
608

609
# if TEST_OOM_TRACE
610
    if (virTestGetDebug())
611
        virAllocTestHook(virtTestErrorHook, NULL);
612
# endif
613 614 615 616 617 618

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

D
Daniel P. Berrange 已提交
619 620 621
        virAllocTestInit();

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

626 627
        approxAlloc = virAllocTestCount();
        testCounter++;
628
        if (virTestGetDebug())
629 630 631 632
            fprintf(stderr, "%d) OOM...\n", testCounter);
        else
            fprintf(stderr, "%d) OOM of %d allocs ", testCounter, approxAlloc);

633 634 635 636 637 638 639 640 641 642 643
        if (mp) {
            int i;
            for (i = 0 ; i < mp ; i++) {
                workers[i] = fork();
                if (workers[i] == 0) {
                    worker = i + 1;
                    break;
                }
            }
        }

644 645
        /* Run once for each alloc, failing a different one
           and validating that the test case failed */
646
        for (n = 0; n < approxAlloc && (!mp || worker) ; n++) {
647 648
            if (mp &&
                (n % mp) != (worker - 1))
649
                continue;
650
            if (!virTestGetDebug()) {
651 652 653 654
                if (mp)
                    fprintf(stderr, "%d", worker);
                else
                    fprintf(stderr, ".");
655 656 657 658
                fflush(stderr);
            }
            virAllocTestOOM(n+1, oomCount);

E
Eric Blake 已提交
659
            if (((func)()) != EXIT_FAILURE) {
660 661 662 663 664
                ret = EXIT_FAILURE;
                break;
            }
        }

665 666 667 668 669 670 671 672 673 674 675 676 677 678
        if (mp) {
            if (worker) {
                _exit(ret);
            } else {
                int i, status;
                for (i = 0 ; i < mp ; i++) {
                    waitpid(workers[i], &status, 0);
                    if (WEXITSTATUS(status) != EXIT_SUCCESS)
                        ret = EXIT_FAILURE;
                }
                VIR_FREE(workers);
            }
        }

679
        if (virTestGetDebug())
680 681 682 683 684 685 686
            fprintf(stderr, " ... OOM of %d allocs", approxAlloc);

        if (ret == EXIT_SUCCESS)
            fprintf(stderr, " OK\n");
        else
            fprintf(stderr, " FAILED\n");
    }
687
cleanup:
688
#else
E
Eric Blake 已提交
689
    ret = (func)();
690
#endif
691

692 693
    if (abs_srcdir_cleanup)
        VIR_FREE(abs_srcdir);
694
    virResetLastError();
695
    if (!virTestGetVerbose() && ret != EXIT_AM_SKIP) {
E
Eric Blake 已提交
696 697
        if (testCounter == 0 || testCounter % 40)
            fprintf(stderr, "%*s", 40 - (testCounter % 40), "");
698 699
        fprintf(stderr, " %-3d %s\n", testCounter, ret == 0 ? "OK" : "FAIL");
    }
700
    return ret;
701
}
702 703


704
#ifdef HAVE_REGEX_H
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
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;
}
748 749 750 751 752 753 754
#else
int virtTestClearLineRegex(const char *pattern ATTRIBUTE_UNUSED,
                           char *str ATTRIBUTE_UNUSED)
{
    return 0;
}
#endif