/* This program expands the input file several times. This
 * is done in order to obtain large (and maybe huge) files for
 * testing. Note that the input file is stored in memory. It's
 * last line must properly be terminated.
 * Max input line size is 10K.
 *
 * command line options:
 * -i	file to be used for input (else stdin)
 * -o	file to be used for output (else stdout)
 * -c	number of times the file is to be copied
 * -n	add line numbers (default: off)
 * -w   wait nbr of microsecs between batches
 * -W	number of file lines to generate in a batch
 *      This is useful only if -w is specified as well,
 *      default is 1000.
 *
 * Copyright 2010-2016 Rainer Gerhards and Adiscon GmbH.
 *
 * This file is part of rsyslog.
 *
 * Rsyslog is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Rsyslog 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Rsyslog.  If not, see <http://www.gnu.org/licenses/>.
 *
 * A copy of the GPL can be found in the file "COPYING" in this distribution.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>

/* input file is stored in a single-linked list */
struct line {
    struct line *next;
    char *ln;
} *root, *tail;

static FILE *fpIn;
static FILE *fpOut;
static long long nCopies = 1;
static int linenbrs = 0;
static int waitusecs = 0;
static int batchsize = 1000;


/* read the input file and create in-memory representation
 */
static void readFile(void) {
    char *r;
    char lnBuf[10240];
    struct line *node;

    root = tail = NULL;
    r = fgets(lnBuf, sizeof(lnBuf), fpIn);
    while (r != NULL) {
        node = malloc(sizeof(struct line));
        if (node == NULL) {
            perror("malloc node");
            exit(1);
        }
        node->next = NULL;
        node->ln = strdup(lnBuf);
        if (node->ln == NULL) {
            perror("malloc node");
            exit(1);
        }
        if (tail == NULL) {
            tail = root = node;
        } else {
            tail->next = node;
            tail = node;
        }
        r = fgets(lnBuf, sizeof(lnBuf), fpIn);
    }
    if (!feof(fpIn)) {
        perror("fgets");
        fprintf(stderr, "end of read loop, but not end of file!");
        exit(1);
    }
}


static void genCopies(void) {
    long long i;
    long long unsigned lnnbr;
    struct line *node;

    lnnbr = 1;
    for (i = 0; i < nCopies; ++i) {
        if (i % 10000 == 0) fprintf(stderr, "copyrun %lld\n", i);
        if (waitusecs && (i % batchsize == 0)) {
            usleep(waitusecs);
        }
        for (node = root; node != NULL; node = node->next) {
            if (linenbrs)
                fprintf(fpOut, "%12.12llu:%s", lnnbr, node->ln);
            else
                fprintf(fpOut, "%s", node->ln);
            ++lnnbr;
        }
    }
}

void main(int argc, char *argv[]) {
    int opt;
    fpIn = stdin;
    fpOut = stdout;

    while ((opt = getopt(argc, argv, "i:o:c:nw:W:")) != -1) {
        switch (opt) {
            case 'i': /* input file */
                if ((fpIn = fopen(optarg, "r")) == NULL) {
                    perror(optarg);
                    exit(1);
                }
                break;
            case 'o': /* output file */
                if ((fpOut = fopen(optarg, "w")) == NULL) {
                    perror(optarg);
                    exit(1);
                }
                break;
            case 'c':
                nCopies = atoll(optarg);
                break;
            case 'n':
                linenbrs = 1;
                break;
            case 'w':
                waitusecs = atoi(optarg);
                break;
            case 'W':
                batchsize = atoi(optarg);
                break;
            default:
                printf("invalid option '%c' or value missing - terminating...\n", opt);
                exit(1);
                break;
        }
    }

    readFile();
    genCopies();
}
