Beispiel #1
0
/*
 * This executes the QCVM task for a specificly compiled progs.dat
 * using the template passed into it for call-flags and user defined
 * messages IF the procedure type is -execute, otherwise it matches
 * the preprocessor output.
 */
static bool task_trymatch(size_t i, char ***line) {
    bool             success = true;
    bool             process = true;
    int              retval  = EXIT_SUCCESS;
    fs_file_t       *execute;
    char             buffer[4096];
    task_template_t *tmpl = task_tasks[i].tmpl;

    memset  (buffer,0,sizeof(buffer));

    if (!strcmp(tmpl->proceduretype, "-execute")) {
        /*
         * Drop the execution flags for the QCVM if none where
         * actually specified.
         */
        if (!strcmp(tmpl->executeflags, "$null")) {
            util_snprintf(buffer,  sizeof(buffer), "%s %s",
                task_bins[TASK_EXECUTE],
                tmpl->tempfilename
            );
        } else {
            util_snprintf(buffer,  sizeof(buffer), "%s %s %s",
                task_bins[TASK_EXECUTE],
                tmpl->executeflags,
                tmpl->tempfilename
            );
        }

        execute = (fs_file_t*)popen(buffer, "r");
        if (!execute)
            return false;
    } else if (!strcmp(tmpl->proceduretype, "-pp")) {
        /*
         * we're preprocessing, which means we need to read int
         * the produced file and do some really weird shit.
         */
        if (!(execute = fs_file_open(tmpl->tempfilename, "r")))
            return false;

        process = false;
    } else {
        /*
         * we're testing diagnostic output, which means it will be
         * in runhandles[2] (stderr) since that is where the compiler
         * puts it's errors.
         */
        if (!(execute = fs_file_open(task_tasks[i].stderrlogfile, "r")))
            return false;

        process = false;
    }

    /*
     * Now lets read the lines and compare them to the matches we expect
     * and handle accordingly.
     */
    {
        char  *data    = NULL;
        size_t size    = 0;
        size_t compare = 0;

        while (fs_file_getline(&data, &size, execute) != FS_FILE_EOF) {
            if (!strcmp(data, "No main function found\n")) {
                con_err("test failure: `%s` (No main function found) [%s]\n",
                    tmpl->description,
                    tmpl->rulesfile
                );
                if (!process)
                    fs_file_close(execute);
                else
                    pclose((FILE*)execute);
                return false;
            }

            /*
             * Trim newlines from data since they will just break our
             * ability to properly validate matches.
             */
            if  (strrchr(data, '\n'))
                *strrchr(data, '\n') = '\0';

            /*
             * We remove the file/directory and stuff from the error
             * match messages when testing diagnostics.
             */
            if(!strcmp(tmpl->proceduretype, "-diagnostic")) {
                if (strstr(data, "there have been errors, bailing out"))
                    continue; /* ignore it */
                if (strstr(data, ": error: ")) {
                    char *claim = util_strdup(data + (strstr(data, ": error: ") - data) + 9);
                    mem_d(data);
                    data = claim;
                }
            }

            /*
             * We need to ignore null lines for when -pp is used (preprocessor), since
             * the preprocessor is likely to create empty newlines in certain macro
             * instantations, otherwise it's in the wrong nature to ignore empty newlines.
             */
            if (!strcmp(tmpl->proceduretype, "-pp") && !*data)
                continue;

            if (vec_size(tmpl->comparematch) > compare) {
                if (strcmp(data, tmpl->comparematch[compare++])) {
                    success = false;
                }
            } else {
                success = false;
            }

            /*
             * Copy to output vector for diagnostics if execution match
             * fails.
             */
            vec_push(*line, data);

            /* reset */
            data = NULL;
            size = 0;
        }

        if (compare != vec_size(tmpl->comparematch))
            success = false;

        mem_d(data);
        data = NULL;
    }

    if (process)
        retval = pclose((FILE*)execute);
    else
        fs_file_close(execute);

    return success && retval == EXIT_SUCCESS;
}
Beispiel #2
0
static size_t task_schedualize(size_t *pad) {
    char   space[2][64];
    bool   execute  = false;
    char  *data     = NULL;
    char **match    = NULL;
    size_t size     = 0;
    size_t i        = 0;
    size_t j        = 0;
    size_t failed   = 0;

    util_snprintf(space[0], sizeof(space[0]), "%d", (int)vec_size(task_tasks));

    for (; i < vec_size(task_tasks); i++) {
        memset(space[1], 0, sizeof(space[1]));
        util_snprintf(space[1], sizeof(space[1]), "%d", (int)(i + 1));

        con_out("test #%u %*s", i + 1, strlen(space[0]) - strlen(space[1]), "");

        /*
         * Generate a task from thin air if it requires execution in
         * the QCVM.
         */

        /* diagnostic is not executed, but compare tested instead, like preproessor */
        execute = !! (!strcmp(task_tasks[i].tmpl->proceduretype, "-execute")) ||
                     (!strcmp(task_tasks[i].tmpl->proceduretype, "-pp"))      ||
                     (!strcmp(task_tasks[i].tmpl->proceduretype, "-diagnostic"));

        /*
         * We assume it compiled before we actually compiled :).  On error
         * we change the value
         */
        task_tasks[i].compiled = true;

        /*
         * Read data from stdout first and pipe that stuff into a log file
         * then we do the same for stderr.
         */
        while (fs_file_getline(&data, &size, task_tasks[i].runhandles[1]) != FS_FILE_EOF) {
            fs_file_puts(task_tasks[i].stdoutlog, data);

            if (strstr(data, "failed to open file")) {
                task_tasks[i].compiled = false;
                execute                = false;
            }
        }
        while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != FS_FILE_EOF) {
            /*
             * If a string contains an error we just dissalow execution
             * of it in the vm.
             *
             * TODO: make this more percise, e.g if we print a warning
             * that refers to a variable named error, or something like
             * that .. then this will blowup :P
             */
            if (strstr(data, "error") && strcmp(task_tasks[i].tmpl->proceduretype, "-diagnostic")) {
                execute                = false;
                task_tasks[i].compiled = false;
            }

            fs_file_puts (task_tasks[i].stderrlog, data);
            fs_file_flush(task_tasks[i].stderrlog); /* fast flush for read */
        }

        if (!task_tasks[i].compiled && strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
            con_out("failure:   `%s` %*s %*s\n",
                task_tasks[i].tmpl->description,
                (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
                task_tasks[i].tmpl->rulesfile,
                (pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen("(failed to compile)") - pad[2]),
                "(failed to compile)"
            );
            failed++;
            continue;
        }

        if (task_pclose(task_tasks[i].runhandles) != EXIT_SUCCESS && strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
            con_out("failure:   `%s` %*s %*s\n",
                task_tasks[i].tmpl->description,
                (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
                task_tasks[i].tmpl->rulesfile,
                (pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen("(compiler didn't return exit success)") - pad[2]),
                "(compiler didn't return exit success)"
            );
            failed++;
            continue;
        }

        if (!execute) {
            con_out("succeeded: `%s` %*s %*s\n",
                task_tasks[i].tmpl->description,
                (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
                task_tasks[i].tmpl->rulesfile,
                (pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen(task_type(task_tasks[i].tmpl)) - pad[2]),
                task_type(task_tasks[i].tmpl)

            );
            continue;
        }

        /*
         * If we made it here that concludes the task is to be executed
         * in the virtual machine (or the preprocessor output needs to
         * be matched).
         */
        if (!task_trymatch(i, &match)) {
            size_t d = 0;

            con_out("failure:   `%s` %*s %*s\n",
                task_tasks[i].tmpl->description,
                (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
                task_tasks[i].tmpl->rulesfile,
                (pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen(
                    (strcmp(task_tasks[i].tmpl->proceduretype, "-pp"))
                        ? "(invalid results from execution)"
                        : (strcmp(task_tasks[i].tmpl->proceduretype, "-diagnostic"))
                            ? "(invalid results from preprocessing)"
                            : "(invalid results from compiler diagnsotics)"
                ) - pad[2]),
                (strcmp(task_tasks[i].tmpl->proceduretype, "-pp"))
                    ? "(invalid results from execution)"
                    : (strcmp(task_tasks[i].tmpl->proceduretype, "-diagnostic"))
                            ? "(invalid results from preprocessing)"
                            : "(invalid results from compiler diagnsotics)"
            );

            /*
             * Print nicely formatted expected match lists to console error
             * handler for the all the given matches in the template file and
             * what was actually returned from executing.
             */
            con_out("    Expected From %u Matches: (got %u Matches)\n",
                vec_size(task_tasks[i].tmpl->comparematch),
                vec_size(match)
            );
            for (; d < vec_size(task_tasks[i].tmpl->comparematch); d++) {
                char  *select = task_tasks[i].tmpl->comparematch[d];
                size_t length = 60 - strlen(select);

                con_out("        Expected: \"%s\"", select);
                while (length --)
                    con_out(" ");
                con_out("| Got: \"%s\"\n", (d >= vec_size(match)) ? "<<nothing else to compare>>" : match[d]);
            }

            /*
             * Print the non-expected out (since we are simply not expecting it)
             * This will help track down bugs in template files that fail to match
             * something.
             */
            if (vec_size(match) > vec_size(task_tasks[i].tmpl->comparematch)) {
                for (d = 0; d < vec_size(match) - vec_size(task_tasks[i].tmpl->comparematch); d++) {
                    con_out("        Expected: Nothing                                                       | Got: \"%s\"\n",
                        match[d + vec_size(task_tasks[i].tmpl->comparematch)]
                    );
                }
            }


            for (j = 0; j < vec_size(match); j++)
                mem_d(match[j]);
            vec_free(match);
            failed++;
            continue;
        }

        for (j = 0; j < vec_size(match); j++)
            mem_d(match[j]);
        vec_free(match);

        con_out("succeeded: `%s` %*s %*s\n",
            task_tasks[i].tmpl->description,
            (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
            task_tasks[i].tmpl->rulesfile,
            (pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen(task_type(task_tasks[i].tmpl))- pad[2]),
            task_type(task_tasks[i].tmpl)

        );
    }
    mem_d(data);
    return failed;
}
Beispiel #3
0
static bool task_template_parse(const char *file, task_template_t *tmpl, fs_file_t *fp, size_t *pad) {
    char  *data = NULL;
    char  *back = NULL;
    size_t size = 0;
    size_t line = 1;

    if (!tmpl)
        return false;

    /* top down parsing */
    while (fs_file_getline(&back, &size, fp) != FS_FILE_EOF) {
        /* skip whitespace */
        data = back;
        if (*data && (*data == ' ' || *data == '\t'))
            data++;

        switch (*data) {
            /*
             * Handle comments inside task tmpl files.  We're strict
             * about the language for fun :-)
             */
            case '/':
                if (data[1] != '/') {
                    con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl parse error",
                        "invalid character `/`, perhaps you meant `//` ?");

                    mem_d(back);
                    return false;
                }
            case '#':
                break;

            /*
             * Empty newlines are acceptable as well, so we handle that here
             * despite being just odd since there should't be that many
             * empty lines to begin with.
             */
            case '\r':
            case '\n':
                break;


            /*
             * Now begin the actual "tag" stuff.  This works as you expect
             * it to.
             */
            case 'D':
            case 'T':
            case 'C':
            case 'E':
            case 'I':
            case 'F':
                if (data[1] != ':') {
                    con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl parse error",
                        "expected `:` after `%c`",
                        *data
                    );
                    goto failure;
                }
                if (!task_template_generate(tmpl, *data, file, line, &data[3], pad)) {
                    con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl compile error",
                        "failed to generate for given task\n"
                    );
                    goto failure;
                }
                break;

            /*
             * Match requires it's own system since we allow multiple M's
             * for multi-line matching.
             */
            case 'M':
            {
                char *value = &data[3];
                if (data[1] != ':') {
                    con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl parse error",
                        "expected `:` after `%c`",
                        *data
                    );
                    goto failure;
                }

                /*
                 * Value will contain a newline character at the end, we need to strip
                 * this otherwise kaboom, seriously, kaboom :P
                 */
                if (strrchr(value, '\n'))
                    *strrchr(value, '\n')='\0';
                else /* cppcheck: possible null pointer dereference */
                    exit(EXIT_FAILURE);

                vec_push(tmpl->comparematch, util_strdup(value));

                break;
            }

            default:
                con_printmsg(LVL_ERROR, file, line, 0, /*TODO: column for match*/ "tmpl parse error",
                    "invalid tag `%c`", *data
                );
                goto failure;
            /* no break required */
        }

        /* update line and free old sata */
        line++;
        mem_d(back);
        back = NULL;
    }
    if (back)
        mem_d(back);
    return true;

failure:
    mem_d (back);
    return false;
}
Beispiel #4
0
static size_t opts_ini_parse (
    fs_file_t *filehandle,
    char *(*loadhandle)(const char *, const char *, const char *, char **),
    char **errorhandle,
    char **parse_file
) {
    size_t linesize;
    size_t lineno             = 1;
    size_t error              = 0;
    char  *line               = NULL;
    char   section_data[2048] = "";
    char   oldname_data[2048] = "";

    /* parsing and reading variables */
    char *parse_beg;
    char *parse_end;
    char *read_name;
    char *read_value;

    while (fs_file_getline(&line, &linesize, filehandle) != FS_FILE_EOF) {
        parse_beg = line;

        /* handle BOM */
        if (lineno == 1 && (
                (unsigned char)parse_beg[0] == 0xEF &&
                (unsigned char)parse_beg[1] == 0xBB &&
                (unsigned char)parse_beg[2] == 0xBF
            )
        ) {
            parse_beg ++; /* 0xEF */
            parse_beg ++; /* 0xBB */
            parse_beg ++; /* 0xBF */
        }

        if (*(parse_beg = opts_ini_lskip(opts_ini_rstrip(parse_beg))) == ';' || *parse_beg == '#') {
            /* ignore '#' is a perl extension */
        } else if (*parse_beg == '[') {
            /* section found */
            if (*(parse_end = opts_ini_next(parse_beg + 1, ']')) == ']') {
                * parse_end = '\0'; /* terminate bro */
                util_strncpy(section_data, parse_beg + 1, sizeof(section_data));
                section_data[sizeof(section_data) - 1] = '\0';
                *oldname_data                          = '\0';
            } else if (!error) {
                /* otherwise set error to the current line number */
                error = lineno;
            }
        } else if (*parse_beg && *parse_beg != ';') {
            /* not a comment, must be a name value pair :) */
            if (*(parse_end = opts_ini_next(parse_beg, '=')) != '=')
                parse_end = opts_ini_next(parse_beg, ':');

            if (*parse_end == '=' || *parse_end == ':') {
                *parse_end = '\0'; /* terminate bro */
                read_name  = opts_ini_rstrip(parse_beg);
                read_value = opts_ini_lskip(parse_end + 1);
                if (*(parse_end = opts_ini_next(read_value, '\0')) == ';')
                    * parse_end = '\0';
                opts_ini_rstrip(read_value);

                /* valid name value pair, lets call down to handler */
                util_strncpy(oldname_data, read_name, sizeof(oldname_data));
                oldname_data[sizeof(oldname_data) - 1] ='\0';

                if ((*errorhandle = loadhandle(section_data, read_name, read_value, parse_file)) && !error)
                    error = lineno;
            } else if (!strcmp(section_data, "includes")) {
                /* Includes are special */
                if (*(parse_end = opts_ini_next(parse_beg, '=')) == '='
                ||  *(parse_end = opts_ini_next(parse_beg, ':')) == ':') {
                    static const char *invalid_include = "invalid use of include";
                    vec_append(*errorhandle, strlen(invalid_include), invalid_include);
                    error = lineno;
                } else {
                    read_name = opts_ini_rstrip(parse_beg);
                    if ((*errorhandle = loadhandle(section_data, read_name, read_name, parse_file)) && !error)
                        error = lineno;
                }
            } else if (!error) {
                /* otherwise set error to the current line number */
                error = lineno;
            }
        }
        lineno++;
    }
    mem_d(line);
    return error;

}