Beispiel #1
0
char *
MR_trace_readline(const char *prompt, FILE *in, FILE *out)
{
#if (defined(isatty) || defined(MR_HAVE_ISATTY)) \
 && (defined(fileno) || defined(MR_HAVE_FILENO)) \
 && !defined(MR_NO_USE_READLINE)
    char    *line;
    MR_bool in_isatty;
    char    *last_nl;

    in_isatty = isatty(fileno(in));
    if (in_isatty || MR_force_readline) {
        rl_instream = in;
        rl_outstream = out;

        /*
        ** The cast to (void *) silences a spurious "assignment from
        ** incompatible pointer type" warning (old versions of readline
        ** are very sloppy about declaring the types of function pointers).
        */

        rl_completion_entry_function = (void *) &MR_trace_line_completer;
        rl_readline_name = "mdb";

        if (!in_isatty) {
            /*
            ** This is necessary for tests/debugger/completion, otherwise
            ** we get lots of messages about readline not being able to get
            ** the terminal settings. This is possibly a bit flaky, but it is
            ** only used by our tests.
            */
            rl_prep_term_function = (void *) MR_dummy_prep_term_function;
            rl_deprep_term_function = (void *) MR_dummy_deprep_term_function;
        }

        /*
        ** If the prompt contains newlines then readline doesn't
        ** display it properly.
        */
        last_nl = strrchr(prompt, '\n');
        if (last_nl != NULL) {
            char    *real_prompt;
            char    *pre_prompt;

            real_prompt = (char *) MR_malloc(strlen(last_nl));
            strcpy(real_prompt, last_nl + 1);
            pre_prompt = (char *) MR_malloc(last_nl - prompt + 2);
            strncpy(pre_prompt, prompt, last_nl - prompt + 1);
            pre_prompt[last_nl - prompt + 1] = '\0';
            fputs(pre_prompt, out);
            line = readline((char *) real_prompt);
            MR_free(real_prompt);
            MR_free(pre_prompt);
        } else {
            line = readline((char *) prompt);
        }

        /*
        ** readline() allocates with malloc(), and we want to return something
        ** allocated with MR_malloc(), but that's OK, because MR_malloc() and
        ** malloc() are interchangable.
        */
#if 0
        {
            char *tmp = line;

            line = MR_copy_string(line);
            free(tmp);
        }
#endif

        if (line != NULL && line[0] != '\0') {
            add_history(line);
        }

        return line;
    }
#endif /* have isatty && have fileno && !MR_NO_USE_READLINE */

    /* otherwise, don't use readline */
    fprintf(out, "%s", prompt);
    fflush(out);
    return MR_trace_readline_raw(in);
}
Beispiel #2
0
void
MR_trace_record_label_exec_counts(void *dummy)
{
    FILE        *fp;
    char        *name;
    unsigned    name_len;
    MR_bool     summarize;
    MR_bool     keep;
    char        *slash;
    const char  *program_name;

    program_name = MR_copy_string(MR_progname);
    slash = strrchr(program_name, '/');
    if (slash != NULL) {
        program_name = slash + 1;
    }

    summarize = MR_FALSE;
    keep = MR_FALSE;
    if (MR_trace_count_summary_file != NULL) {
        if (MR_FILE_EXISTS(MR_trace_count_summary_file)) {
            int     i;

            /* 30 bytes must be enough for the dot, the value of i, and '\0' */
            name_len = strlen(MR_trace_count_summary_file) + 30;
            name = MR_malloc(name_len);

            fp = NULL;
            /* search for a suffix that doesn't exist yet */
            for (i = 1; i <= MR_trace_count_summary_max; i++) {
                snprintf(name, name_len, "%s.%d",
                    MR_trace_count_summary_file, i);
                if (! MR_FILE_EXISTS(name)) {
                    /* file doesn't exist, commit to this one */
                    if (i == MR_trace_count_summary_max) {
                        summarize = MR_TRUE;
                    }

                    break;
                }
            }
        } else {
            /*
            ** The summary file doesn't yet exist, create it.
            */
            name = MR_copy_string(MR_trace_count_summary_file);
        }
    } else if (MR_trace_counts_file) {
        name = MR_copy_string(MR_trace_counts_file);
        keep = MR_TRUE;
    } else {
        char    *s;

        /*
        ** If no trace counts file name is provided, then we generate
        ** a file name.
        */

        /* 100 bytes must be enough for the process id, dots and '\0' */
        name_len = strlen(MERCURY_TRACE_COUNTS_PREFIX) + strlen(program_name)
            + 100;
        name = MR_malloc(name_len);
        snprintf(name, name_len, ".%s.%s.%d", MERCURY_TRACE_COUNTS_PREFIX,
            program_name, getpid());

        /* make sure name is an acceptable filename */
        for (s = name; *s != '\0'; s++) {
            if (*s == '/') {
                *s = '_';
            }
        }
    }

    fp = fopen(name, "w");
    if (fp != NULL) {
        unsigned    num_written;

        num_written = MR_trace_write_label_exec_counts(fp,
            program_name, MR_coverage_test_enabled);
        (void) fclose(fp);

        if (num_written == 0 && !keep) {
            /*
            ** We did not write out any trace counts, so there is nothing
            ** to gather.
            */

            (void) unlink(name);
            summarize = MR_FALSE;
        }
    } else {
        fprintf(stderr, "%s: %s\n", name, strerror(errno));
        /*
        ** You can't summarize a file list if you can't create
        ** one of its files.
        */
        summarize = MR_FALSE;
    }

    free(name);

    if (summarize) {
        char        *cmd;
        unsigned    cmd_len;
        int         summary_status;
        int         mv_status;
        int         unlink_status;
        int         i;
        const char  *old_options;

        /* 30 bytes must be enough for the dot, the value of i, and space */
        name_len = strlen(MR_trace_count_summary_file) + 30;
        name = MR_malloc(name_len);

        cmd_len = strlen(MR_trace_count_summary_cmd) + 4;
        cmd_len += strlen(MR_trace_count_summary_file)
            + strlen(TEMP_SUFFIX) + 1;
        cmd_len += (MR_trace_count_summary_max + 1) * name_len;
        cmd_len += 100;

        cmd = MR_malloc(cmd_len);

        strcpy(cmd, MR_trace_count_summary_cmd);
        strcat(cmd, " -o ");
        strcat(cmd, MR_trace_count_summary_file);
        strcat(cmd, TEMP_SUFFIX);
        strcat(cmd, " ");
        strcat(cmd, MR_trace_count_summary_file);

        for (i = 1; i <= MR_trace_count_summary_max; i++) {
            snprintf(name, name_len, "%s.%d", MR_trace_count_summary_file, i);
            strcat(cmd, " ");
            strcat(cmd, name);
        }

        strcat(cmd, " > /dev/null 2>&1");

        old_options = getenv("MERCURY_OPTIONS");
        if (old_options != NULL) {
            (void) MR_setenv("MERCURY_OPTIONS", "", MR_TRUE);
            summary_status = system(cmd);
            (void) MR_setenv("MERCURY_OPTIONS", old_options, MR_TRUE);
        } else {
            summary_status = system(cmd);
        }

        if (summary_status == 0) {
            strcpy(cmd, "mv ");
            strcat(cmd, MR_trace_count_summary_file);
            strcat(cmd, TEMP_SUFFIX);
            strcat(cmd, " ");
            strcat(cmd, MR_trace_count_summary_file);
            mv_status = system(cmd);

            if (mv_status == 0) {
                /* delete all files whose data is now in the summary file */
                for (i = 1; i <= MR_trace_count_summary_max; i++) {
                    snprintf(name, name_len, "%s.%d",
                        MR_trace_count_summary_file, i);
                    unlink_status = unlink(name);
                    if (unlink_status != 0) {
                        MR_fatal_error(
                            "couldn't create summary of trace data");
                    }
                }
            } else {
                MR_fatal_error("couldn't create summary of trace data");
            }
        } else {
            MR_fatal_error("couldn't create summary of trace data");
        }

        free(name);
        free(cmd);
    }
}
Beispiel #3
0
char *
MR_trace_readline_from_script(FILE *fp, char **args, int num_args)
{
    char    *line = NULL;
    size_t  line_length;
    int     line_index;
    size_t  expanded_line_length;
    char    *expanded_line;
    int     expanded_line_index;
    int     arg_num;
    size_t  arg_length;
    char    *arg;

    do {
        if (line != NULL) {
            MR_free(line);
        }
        line = MR_trace_readline_raw(fp);
        if (line == NULL) {
            return NULL;
        }
        /*
        ** Ignore lines starting with '#'.
        */
    } while (*line == '#');

    line_length = strlen(line);

    expanded_line_length = line_length;
    expanded_line = (char*) MR_malloc(line_length + 1);
    expanded_line[0] = '\0';
    expanded_line_index = 0;

    for (line_index = 0; line_index < line_length; line_index++) {
        if ((line[line_index] == '$') &&
            (line_index < (line_length - 1)) &&
            (line[line_index + 1] >= '1') &&
            (line[line_index + 1] <= '9'))
        {
            arg_num = (int)(line[line_index + 1] - '1');
            if (arg_num < num_args) {
                arg = args[arg_num];
                arg_length = strlen(arg);
                /*
                ** Subtract 2 for the "$n" which will not occur
                ** in the expanded string.
                */
                expanded_line_length += arg_length - 2;
                expanded_line = MR_realloc(expanded_line,
                    expanded_line_length + 1);
                expanded_line[expanded_line_index] = '\0';
                strcat(expanded_line, arg);
                expanded_line_index += arg_length;
            }
            /* Skip the digit after the '$'. */
            line_index++;
        } else {
            expanded_line[expanded_line_index] = line[line_index];
            expanded_line_index++;
        }
    }

    MR_free(line);
    expanded_line[expanded_line_index] = '\0';

    return expanded_line;
}
Beispiel #4
0
const char *
MR_trace_source_open_server(MR_TraceSourceServer *server,
    const char *window_cmd, int timeout, MR_bool verbose)
{
    const char  *real_window_cmd;
    const char  *real_server_cmd;
    char        *name;
    const char  *msg;
    char        system_call[MR_SYSCALL_BUFFER_SIZE];
    int         status;
    size_t      base_len;
    size_t      i;

    if (window_cmd != NULL) {
        real_window_cmd = window_cmd;
    } else {
        real_window_cmd = MR_DEFAULT_SOURCE_WINDOW_COMMAND;
    }

    if (server->server_cmd != NULL) {
        real_server_cmd = server->server_cmd;
    } else {
        real_server_cmd = MR_DEFAULT_SOURCE_SERVER_COMMAND;
    }

    // 1) check that display is set;
    // 2) check that server is valid;
    // 3) start a server with a unique name;
    // 4) wait until the server is found;
    // 5) (if required) split the window.

    msg = MR_trace_source_check_display();
    if (msg != NULL) {
        return msg;
    }

    msg = MR_trace_source_check_server_cmd(real_server_cmd, verbose);
    if (msg != NULL) {
        return msg;
    }

    // If possible, we generate a unique name of the form
    // '<basename>.<hostname>.<pid>', but if the required functions
    // aren't available, we fall back to appending numbers to the
    // basename in sequence until one is found that is not being used.
    // This is quite a slow way of doing things, and there is also a
    // race condition, but it is difficult to see a better way.
    // We should let the server pick a unique name for itself, but
    // how would you communicate this name back to this process?

    base_len = strlen(MR_SOURCE_SERVER_BASENAME);

#if defined(MR_HAVE_GETPID) && defined(MR_HAVE_GETHOSTNAME)
    // Need to leave enough room for the pid, two '.'s and the
    // terminating zero.

    name = MR_malloc(base_len + MR_SERVER_HOSTNAME_CHARS + 32);
    strcpy(name, MR_SOURCE_SERVER_BASENAME);

    // Append the '.' and hostname.

    name[base_len] = '.';
    gethostname(name + base_len + 1, MR_SERVER_HOSTNAME_CHARS);
    // Do this just in case gethostname didn't terminate the string:
    name[base_len + 1 + MR_SERVER_HOSTNAME_CHARS] = '\0';

    // Find the end of the string and append the '.' and pid.

    i = base_len + 1 + strlen(name + base_len + 1);
    sprintf(name + i, ".%ld", (long) getpid());
#else
    i = 0;
    // Need to leave enough room for a '.', the integer and the
    // terminating zero.

    name = MR_malloc(base_len + 10);
    do {
        i++;
        sprintf(name, "%s.%lu", MR_SOURCE_SERVER_BASENAME, (unsigned long)i);
        // This should fail if there is no server with this name.
        msg = MR_trace_source_check_server(real_server_cmd, name, verbose);
    } while (msg == NULL);
#endif

    server->server_name = name;

    // Start the server in read-only mode, to discourage the user
    // from trying to edit the source.

    sprintf(system_call, "%s %s -R --servername \"%s\" %s &", real_window_cmd,
        real_server_cmd, name, (verbose ? "" : "> /dev/null 2>&1"));
    MR_verbose_system_call(system_call, verbose);

    // We need to wait until the source server has registered itself
    // with the X server. If we don't, we may execute remote commands
    // before the server has started up, and this will result in vim
    // (rather inconveniently) starting its own server on mdb's terminal.

    msg = MR_trace_source_attach(server, timeout, verbose);

    if (msg != NULL) {
        // Something went wrong, so we should free the server name
        // we allocated just above.

        MR_free(server->server_name);
        server->server_name = NULL;
        return msg;
    }

    if (server->split) {
        // Split the window.
        status = MR_trace_source_send(real_server_cmd, server->server_name,
            MR_SOURCE_SERVER_RESET_STRING MR_SOURCE_SERVER_SPLIT_STRING,
            verbose);
        if (status != 0) {
            server->split = MR_FALSE;
            return "warning: unable to split source window";
        }
    }

    return NULL;
}