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