/* * create pty pair and fork using my_pty_fork; parent returns immediately; child * executes the part of rlwrap's command line that remains after * read_options_and_command_name() has harvested rlwrap's own options */ static void fork_child(char *command_name, char **argv) { char *arg = argv[optind], *p, **argp; int pid; command_line = mysavestring(arg); for (argp = argv + optind + 1; *argp; argp++) { command_line = append_and_free_old (command_line, " "); command_line = append_and_free_old (command_line, *argp); } pid = my_pty_fork(&master_pty_fd, &saved_terminal_settings, &winsize); if (pid > 0) /* parent: */ return; else { /* child: */ DPRINTF1(DEBUG_TERMIO, "preparing to execute %s", arg); close_open_files_without_writing_buffers(); if (client_term_name) mysetenv("TERM", client_term_name); if (execvp(argv[optind], &argv[optind]) < 0) { if (last_opt > 0 && last_option_didnt_have_optional_argument) { /* e.g. 'rlwrap -a Password: sqlpus' will try to exec 'Password:'******'; !(){}"; *p; p++) /* does arg need shell quoting? */ if (strchr(arg,*p)) { arg = add3strings("'", arg,"'"); /* quote it */ break; } fprintf(stderr, "Did you mean '%s' to be an option argument?\nThen you should write -%c%s, without the space(s)\n", argv[optind], last_opt, arg); } myerror("Cannot execute %s", argv[optind]); /* stillborn child, parent will live on and display child's last gasps */ } } }
char * colour_name_to_ansi_code(const char *colour_name) { if (colour_name && *colour_name && isalpha(*colour_name)) { char *lc_colour_name = mysavestring(lowercase(colour_name)); char *bold_code = (isupper(*colour_name) ? "1" : "0"); #define isit(c) (strcmp(c,lc_colour_name)==0) char *colour_code = isit("black") ? "30" : isit("red") ? "31" : isit("green") ? "32" : isit("yellow") ? "33" : isit("blue") ? "34" : isit("magenta") ? "35" : isit("purple") ? "35" : isit("cyan") ? "36" : isit("white") ? "37" : NULL ; #undef isit if (colour_code) return add3strings(bold_code,";",colour_code); else myerror("unrecognised colour name '%s'. Use e.g. 'yellow' or 'Blue'.", colour_name); } return mysavestring(colour_name); }
void initialise_colour_codes(char *colour) { int attributes, foreground, background; DPRINTF1(DEBUG_READLINE, "initialise_colour_codes(\"%s\")", colour); attributes = foreground = -1; background = 40; /* don't need to specify background; 40 passes the test automatically */ sscanf(colour, "%d;%d;%d", &attributes, &foreground, &background); #define OUTSIDE(lo,hi,val) (val < lo || val > hi) if (OUTSIDE(0,8,attributes) || OUTSIDE(30,37,foreground) || OUTSIDE(40,47,background)) myerror(FATAL|NOERRNO, "\n" " prompt colour spec should be <attr>;<fg>[;<bg>]\n" " where <attr> ranges over [0...8], <fg> over [30...37] and <bg> over [40...47]\n" " example: 0;33 for yellow on current background, 1;31;40 for bold red on black "); colour_start= add3strings("\033[", colour,"m"); colour_end = "\033[0m"; }
/* returns a colourised copy of prompt, trailing space is not colourised */ char* colourise (const char *prompt) { char *prompt_copy, *trailing_space, *colour_end_with_space, *result, *p; prompt_copy = mysavestring(prompt); if (strchr(prompt_copy, '\033') || strchr(prompt_copy, RL_PROMPT_START_IGNORE) ) { /* prompt contains escape codes? */ DPRINTF1(DEBUG_READLINE, "colourise %s: left as-is", prompt); return prompt_copy; /* if so, leave prompt alone */ } for (p = prompt_copy + strlen(prompt_copy); p > prompt_copy && *(p-1) == ' '; p--) ; /* skip back over trailing space */ trailing_space = mysavestring(p); /* p now points at first trailing space, or else the final NULL */ *p = '\0'; colour_end_with_space = add2strings(colour_end, trailing_space); result = add3strings(colour_start, prompt_copy, colour_end_with_space); free (prompt_copy); free(trailing_space); free(colour_end_with_space); DPRINTF1(DEBUG_READLINE, "colourise %s: colour added ", prompt); return result; }
static void munge_file_in_editor(const char *filename, int lineno, int colno) { int ret; char *editor_command1, *editor_command2, *editor_command3, *editor_command4, *line_number_as_string, *column_number_as_string, **possible_editor_commands; /* find out which editor command we have to use */ possible_editor_commands = list4(getenv("RLWRAP_EDITOR"), getenv("EDITOR"), getenv("VISUAL"), "vi +%L"); editor_command1 = first_of(possible_editor_commands); line_number_as_string = as_string(lineno); column_number_as_string = as_string(colno); editor_command2 = search_and_replace("%L", line_number_as_string, editor_command1, 0, NULL, NULL); editor_command3 = search_and_replace("%C", column_number_as_string, editor_command2, 0, NULL, NULL); editor_command4 = strstr(editor_command3, "%F") ? search_and_replace("%F", filename, editor_command3, 0, NULL, NULL) : add3strings(editor_command3, " ", filename); /* call editor, temporarily restoring terminal settings */ if (terminal_settings_saved && (tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_terminal_settings) < 0)) /* reset terminal */ myerror(FATAL|USE_ERRNO, "tcsetattr error on stdin"); DPRINTF1(DEBUG_READLINE, "calling %s", editor_command4); if ((ret = system(editor_command4))) { if (WIFSIGNALED(ret)) { fprintf(stderr, "\n"); myerror(FATAL|NOERRNO, "editor killed by signal"); } else { myerror(FATAL|USE_ERRNO, "failed to invoke editor with '%s'", editor_command4); } } completely_mirror_slaves_terminal_settings(); ignore_queued_input = TRUE; free_multiple(possible_editor_commands, editor_command2, editor_command3, editor_command4, line_number_as_string, column_number_as_string, FMEND); }
void spawn_filter(const char *filter_command) { int input_pipe_fds[2]; int output_pipe_fds[2]; mypipe(input_pipe_fds); filter_input_fd = input_pipe_fds[1]; /* rlwrap writes filter input to this */ mypipe(output_pipe_fds); filter_output_fd = output_pipe_fds[0]; /* rlwrap reads filter output from here */ DPRINTF1(DEBUG_FILTERING, "preparing to spawn filter <%s>", filter_command); assert(!command_pid || signal_handlers_were_installed); /* if there is a command, then signal handlers are installed */ if ((filter_pid = fork()) < 0) myerror(FATAL|USE_ERRNO, "Cannot spawn filter '%s'", filter_command); else if (filter_pid == 0) { /* child */ int signals_to_allow[] = {SIGPIPE, SIGCHLD, SIGALRM, SIGUSR1, SIGUSR2}; char **argv; unblock_signals(signals_to_allow); /* when we run a pager from a filter we want to catch these */ DEBUG_RANDOM_SLEEP; i_am_child = TRUE; /* set environment for filter (it needs to know at least the file descriptors for its input and output) */ if (!getenv("RLWRAP_FILTERDIR")) mysetenv("RLWRAP_FILTERDIR", add2strings(DATADIR,"/rlwrap/filters")); mysetenv("PATH", add3strings(getenv("RLWRAP_FILTERDIR"),":",getenv("PATH"))); mysetenv("RLWRAP_VERSION", VERSION); mysetenv("RLWRAP_COMMAND_PID", as_string(command_pid)); mysetenv("RLWRAP_COMMAND_LINE", command_line); if (impatient_prompt) mysetenv("RLWRAP_IMPATIENT", "1"); mysetenv("RLWRAP_INPUT_PIPE_FD", as_string(input_pipe_fds[0])); mysetenv("RLWRAP_OUTPUT_PIPE_FD", as_string(output_pipe_fds[1])); mysetenv("RLWRAP_MASTER_PTY_FD", as_string(master_pty_fd)); close(filter_input_fd); close(filter_output_fd); if (scan_metacharacters(filter_command, "'|\"><")) { /* if filter_command contains shell metacharacters, let the shell unglue them */ char *exec_command = add3strings("exec", " ", filter_command); argv = list4("sh", "-c", exec_command, NULL); } else { /* if not, split and feed to execvp directly (cheaper, better error message) */ argv = split_with(filter_command, " "); } assert(argv[0]); if(execvp(argv[0], argv) < 0) { char *sorry = add3strings("Cannot exec filter '", argv[0], add2strings("': ", strerror(errno))); write_message(output_pipe_fds[1], TAG_ERROR, sorry, "to stdout"); /* this will kill rlwrap */ mymicrosleep(100 * 1000); /* 100 sec for rlwrap to go away should be enough */ exit (-1); } assert(!"not reached"); } else { DEBUG_RANDOM_SLEEP; signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE - we have othere ways to deal with filter death */ DPRINTF1(DEBUG_FILTERING, "spawned filter with pid %d", filter_pid); close (input_pipe_fds[0]); close (output_pipe_fds[1]); } }
static int munge_line_in_editor(int count, int key) { int line_number = 0, column_number = 0, tmpfile_OK, ret, tmpfile_fd, bytes_read; size_t tmpfilesize; char *p, *tmpdir, *tmpfilename, *text_to_edit; char *editor_command1, *editor_command2, *editor_command3, *editor_command4, *line_number_as_string, *column_number_as_string; char *input, *rewritten_input, *rewritten_input2, **possible_tmpdirs, **possible_editor_commands; if (!multiline_separator) return 0; possible_tmpdirs = list4(getenv("TMPDIR"), getenv("TMP"), getenv("TEMP"), "/tmp"); possible_editor_commands = list4(getenv("RLWRAP_EDITOR"), getenv("EDITOR"), getenv("VISUAL"), "vi +%L"); /* create temporary filename */ #ifdef HAVE_MKSTEMP tmpdir = first_of(possible_tmpdirs); tmpfilename = add3strings(tmpdir, "/rlwrap_", "XXXXXX"); tmpfile_OK = mkstemp(tmpfilename); #else tmpfilename = mymalloc(L_tmpnam); tmpfile_OK = (int)tmpnam(tmpfilename); /* manpage says: Never use this function. Use mkstemp(3) instead */ #endif if (!tmpfile_OK) myerror("could not find unique temporary file name"); /* write current input to it, replacing the newline substitute (multiline_separator) with the real thing */ tmpfile_fd = open(tmpfilename, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); if (tmpfile_fd < 0) myerror("could not create temporary file %s", tmpfilename); text_to_edit = search_and_replace(multiline_separator, "\n", rl_line_buffer, rl_point, &line_number, &column_number); write_patiently(tmpfile_fd, text_to_edit, strlen(text_to_edit), "to temporary file"); if (close(tmpfile_fd) != 0) /* improbable */ myerror("couldn't close temporary file %s", tmpfilename); /* find out which editor command we have to use */ editor_command1 = first_of(possible_editor_commands); line_number_as_string = as_string(line_number); column_number_as_string = as_string(column_number); editor_command2 = search_and_replace("%L", line_number_as_string, editor_command1, 0, NULL, NULL); editor_command3 = search_and_replace("%C", column_number_as_string, editor_command2, 0, NULL, NULL); editor_command4 = add3strings(editor_command3, " ", tmpfilename); /* call editor, temporarily restoring terminal settings */ if (terminal_settings_saved && (tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_terminal_settings) < 0)) /* reset terminal */ myerror("tcsetattr error on stdin"); DPRINTF1(DEBUG_READLINE, "calling %s", editor_command4); if ((ret = system(editor_command4))) { if (WIFSIGNALED(ret)) { fprintf(stderr, "\n"); errno = 0; myerror("editor killed by signal"); } else { myerror("failed to invoke editor with '%s'", editor_command4); } } completely_mirror_slaves_terminal_settings(); ignore_queued_input = TRUE; /* read back edited input, replacing real newline with substitute */ tmpfile_fd = open(tmpfilename, O_RDONLY); if (tmpfile_fd < 0) myerror("could not read temp file %s", tmpfilename); tmpfilesize = filesize(tmpfilename); input = mymalloc(tmpfilesize + 1); bytes_read = read(tmpfile_fd, input, tmpfilesize); if (bytes_read < 0) myerror("unreadable temp file %s", tmpfilename); input[bytes_read] = '\0'; rewritten_input = search_and_replace("\t", " ", input, 0, NULL, NULL); /* rlwrap cannot handle tabs in input lines */ rewritten_input2 = search_and_replace("\n", multiline_separator, rewritten_input, 0, NULL, NULL); for(p = rewritten_input2; *p ;p++) if(*p < ' ') *p = ' '; /* replace all control characters (like \r) by spaces */ rl_delete_text(0, strlen(rl_line_buffer)); rl_point = 0; clear_line(); cr(); my_putstr(saved_rl_state.cooked_prompt); rl_insert_text(rewritten_input2); rl_point = 0; /* leave cursor on predictable place */ rl_done = 1; /* accept line immediately */ /* wash those dishes */ if (unlink(tmpfilename)) myerror("could not delete temporary file %s", tmpfilename); free(editor_command2); free(editor_command3); free(editor_command4); free(line_number_as_string); free(column_number_as_string); free(tmpfilename); free(text_to_edit); free(input); free(rewritten_input); free(rewritten_input2); return_key = (char)'\n'; return 0; }
char * read_options_and_command_name(int argc, char **argv) { int c; char *opt_C = NULL; int option_count = 0; int opt_b = FALSE; int opt_f = FALSE; int remaining = -1; /* remaining number of arguments on command line */ int longindex = -1; /* index of current option in longopts[], set by getopt_long */ full_program_name = mysavestring(argv[0]); program_name = mybasename(full_program_name); /* normally "rlwrap"; needed by myerror() */ rl_basic_word_break_characters = " \t\n\r(){}[],+-=&^%$#@\";|\\"; opterr = 0; /* we do our own error reporting */ while (1) { #ifdef HAVE_GETOPT_LONG c = getopt_long(argc, argv, optstring, longopts, &longindex); #else c = getopt(argc, argv, optstring); #endif if (c == EOF) break; option_count++; last_option_didnt_have_optional_argument = FALSE; remaining = argc - optind; last_opt = c; switch (c) { case 'a': always_readline = TRUE; if (check_optarg('a', remaining)) password_prompt_search_string = mysavestring(optarg); break; case 'A': ansi_colour_aware = TRUE; break; case 'b': rl_basic_word_break_characters = add3strings("\r\n \t", optarg, ""); opt_b = TRUE; break; case 'c': complete_filenames = TRUE; break; case 'C': opt_C = mysavestring(optarg); break; case 'd': #ifdef DEBUG if (option_count > 1) myerror("-d or --debug option has to be the *first* rlwrap option"); if (check_optarg('d', remaining)) debug = atoi(optarg); else debug = DEBUG_DEFAULT; #else myerror ("To use -d( for debugging), configure %s with --enable-debug and rebuild", program_name); #endif break; case 'D': history_duplicate_avoidance_policy=atoi(optarg); if (history_duplicate_avoidance_policy < 0 || history_duplicate_avoidance_policy > 2) myerror("%s option with illegal value %d, should be 0, 1 or 2", current_option('D', longindex), history_duplicate_avoidance_policy); break; case 'f': if (strncmp(optarg, ".", 10) == 0) feed_history_into_completion_list = TRUE; else feed_file_into_completion_list(optarg); opt_f = TRUE; break; case 'F': myerror("The -F (--history-format) option is obsolete. Use -z \"history_format '%s'\" instead", optarg); case 'g': forget_regexp = mysavestring(optarg); match_regexp("just testing", forget_regexp, 1); break; case 'h': usage(EXIT_SUCCESS); /* will call exit() */ case 'H': history_filename = mysavestring(optarg); break; case 'i': if (opt_f) myerror("-i option has to precede -f options"); completion_is_case_sensitive = FALSE; break; case 'I': pass_on_sigINT_as_sigTERM = TRUE; break; case 'l': open_logfile(optarg); break; case 'n': nowarn = TRUE; break; case 'm': #ifndef HAVE_SYSTEM mywarn("the -m option doesn't work on this system"); #endif multiline_separator = (check_optarg('m', remaining) ? mysavestring(optarg) : " \\ "); break; case 'N': commands_children_not_wrapped = TRUE; break; case 'o': one_shot_rlwrap = TRUE; impatient_prompt = FALSE; wait_before_prompt = 200; break; case 'O': prompt_regexp = mysavestring(optarg); match_regexp("just testing", prompt_regexp, 1); break; case 'p': colour_the_prompt = TRUE; initialise_colour_codes(check_optarg('p', remaining) ? colour_name_to_ansi_code(optarg) : colour_name_to_ansi_code("Red")); break; case 'P': pre_given = mysavestring(optarg); always_readline = TRUE; /* pre_given does not work well with transparent mode */ break; case 'q': rl_basic_quote_characters = mysavestring(optarg); break; case 'r': remember_for_completion = TRUE; break; case 'R': renice = TRUE; break; case 's': histsize = atoi(optarg); if (histsize < 0) { write_histfile = 0; histsize = -histsize; } break; case 'S': substitute_prompt = mysavestring(optarg);break; case 't': client_term_name=mysavestring(optarg);break; #ifdef DEBUG case 'T': test_terminal(); exit(EXIT_SUCCESS); #endif case 'v': printf("rlwrap %s\n", VERSION); exit(EXIT_SUCCESS); case 'w': wait_before_prompt = atoi(optarg); if (wait_before_prompt < 0) { wait_before_prompt *= -1; impatient_prompt = FALSE; } break; case 'z': filter_command = mysavestring(optarg); break; case '?': assert(optind > 0); myerror("unrecognised option %s\ntry '%s --help' for more information", argv[optind-1], full_program_name); case ':': assert(optind > 0); myerror ("option %s requires an argument \ntry '%s --help' for more information", argv[optind-1], full_program_name); default: usage(EXIT_FAILURE); } } if (!complete_filenames && !opt_b) { /* use / and . as default breaking characters whenever we don't complete filenames */ rl_basic_word_break_characters = add2strings(rl_basic_word_break_characters, "/."); } if (optind >= argc) { /* rlwrap -a -b -c with no command specified */ if (filter_command) { /* rlwrap -z filter with no command specified */ mysignal(SIGALRM, &handle_sigALRM); /* needed for read_patiently2 */ spawn_filter(filter_command); pass_through_filter(TAG_OUTPUT,""); /* ignore result but allow TAG_OUTPUT_OUT_OF_BAND */ cleanup_rlwrap_and_exit(EXIT_SUCCESS); } else { usage(EXIT_FAILURE); } } if (opt_C) { int countback = atoi(opt_C); /* investigate whether -C option argument is numeric */ if (countback > 0) { /* e.g -C 1 or -C 12 */ if (argc - countback < optind) /* -C 666 */ myerror("when using -C %d you need at least %d non-option arguments", countback, countback); else if (argv[argc - countback][0] == '-') /* -C 2 perl -d blah.pl */ myerror("the last argument minus %d appears to be an option!", countback); else { /* -C 1 perl test.cgi */ command_name = mysavestring(mybasename(argv[argc - countback])); } } else if (countback == 0) { /* -C name1 name2 or -C 0 */ if (opt_C[0] == '0' && opt_C[1] == '\0') /* -C 0 */ myerror("-C 0 makes no sense"); else if (strlen(mybasename(opt_C)) != strlen(opt_C)) /* -C dir/name */ myerror("-C option argument should not contain directory components"); else if (opt_C[0] == '-') /* -C -d (?) */ myerror("-C option needs argument"); else /* -C name */ command_name = opt_C; } else { /* -C -2 */ myerror ("-C option needs string or positive number as argument, perhaps you meant -C %d?", -countback); } } else { /* no -C option given, use command name */ command_name = mysavestring(mybasename(argv[optind])); } assert(command_name != NULL); return command_name; }
/* Read history and completion word lists */ void init_rlwrap() { char *homedir, *histdir, *homedir_prefix, *hostname; time_t now; /* open debug file if necessary */ if (debug) { debug_fp = fopen(DEBUG_FILENAME, "w"); if (!debug_fp) myerror("Couldn't open debug file %s", DEBUG_FILENAME); setbuf(debug_fp, NULL); /* always write debug messages to disk at once */ } hostname = getenv("HOSTNAME") ? getenv("HOSTNAME") : "?"; now = time(NULL); DPRINTF0(DEBUG_ALL, "-*- mode: grep -*-"); DPRINTF3(DEBUG_ALL, "rlwrap version %s, host: %s, time: %s", VERSION, hostname, ctime(&now)); init_terminal(); /* Determine rlwrap home dir and prefix for default history and completion filenames */ homedir = (getenv("RLWRAP_HOME") ? getenv("RLWRAP_HOME") : getenv("HOME")); homedir_prefix = (getenv("RLWRAP_HOME") ? /* is RLWRAP_HOME set? */ add2strings(getenv("RLWRAP_HOME"), "/") : /* use $RLWRAP_HOME/<command>_history */ add2strings(getenv("HOME"), "/.")); /* if not, use ~/.<command>_history */ /* Determine history file name and check its existence and permissions */ if (history_filename) { histdir = mydirname(history_filename); } else { histdir = homedir; history_filename = add3strings(homedir_prefix, command_name, "_history"); } if (write_histfile) { if (access(history_filename, F_OK) == 0) { /* already exists, can we read/write it? */ if (access(history_filename, R_OK | W_OK) != 0) { myerror("cannot read and write %s", history_filename); } } else { /* doesn't exist, can we create it? */ if(access(histdir, W_OK) != 0) { if (errno == ENOENT) { mode_t oldmask = umask(0); if (mkdir(histdir, 0700)) /* rwx------ */ myerror("cannot create directory %s", histdir); umask(oldmask); } else { myerror("cannot create history file in %s", histdir); } } } } else { /* ! write_histfile */ if (access(history_filename, R_OK) != 0) { myerror("cannot read %s", history_filename); } } /* Initialize history */ using_history(); stifle_history(histsize); read_history(history_filename); /* ignore errors here: history file may not yet exist, but will be created on exit */ if (feed_history_into_completion_list) feed_file_into_completion_list(history_filename); /* Determine completion file name (completion files are never written to, and ignored when unreadable or non-existent) */ completion_filename = add3strings(homedir_prefix, command_name, "_completions"); default_completion_filename = add3strings(DATADIR, "/rlwrap/completions/", command_name); rl_readline_name = command_name; /* Initialise completion list (if <completion_filename> is readable) */ if (access(completion_filename, R_OK) == 0) { feed_file_into_completion_list(completion_filename); } else if (access(default_completion_filename, R_OK) == 0) { feed_file_into_completion_list(default_completion_filename); } }
static int munge_line_in_editor(int count, int key) { int line_number = 0, column_number = 0, ret, tmpfile_fd, bytes_read; size_t tmpfilesize; char *p, *tmpfilename, *text_to_edit; char *editor_command1, *editor_command2, *editor_command3, *editor_command4, *line_number_as_string, *column_number_as_string; char *input, *rewritten_input, *rewritten_input2, **possible_editor_commands; if (!multiline_separator) return 0; tmpfile_fd = open_unique_tempfile(multi_line_tmpfile_ext, &tmpfilename); text_to_edit = search_and_replace(multiline_separator, "\n", rl_line_buffer, rl_point, &line_number, &column_number); write_patiently(tmpfile_fd, text_to_edit, strlen(text_to_edit), "to temporary file"); if (close(tmpfile_fd) != 0) /* improbable */ myerror(FATAL|USE_ERRNO, "couldn't close temporary file %s", tmpfilename); /* find out which editor command we have to use */ possible_editor_commands = list4(getenv("RLWRAP_EDITOR"), getenv("EDITOR"), getenv("VISUAL"), "vi +%L"); editor_command1 = first_of(possible_editor_commands); line_number_as_string = as_string(line_number); column_number_as_string = as_string(column_number); editor_command2 = search_and_replace("%L", line_number_as_string, editor_command1, 0, NULL, NULL); editor_command3 = search_and_replace("%C", column_number_as_string, editor_command2, 0, NULL, NULL); editor_command4 = add3strings(editor_command3, " ", tmpfilename); /* call editor, temporarily restoring terminal settings */ if (terminal_settings_saved && (tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_terminal_settings) < 0)) /* reset terminal */ myerror(FATAL|USE_ERRNO, "tcsetattr error on stdin"); DPRINTF1(DEBUG_READLINE, "calling %s", editor_command4); if ((ret = system(editor_command4))) { if (WIFSIGNALED(ret)) { fprintf(stderr, "\n"); myerror(FATAL|NOERRNO, "editor killed by signal"); } else { myerror(FATAL|USE_ERRNO, "failed to invoke editor with '%s'", editor_command4); } } completely_mirror_slaves_terminal_settings(); ignore_queued_input = TRUE; /* read back edited input, replacing real newline with substitute */ tmpfile_fd = open(tmpfilename, O_RDONLY); if (tmpfile_fd < 0) myerror(FATAL|USE_ERRNO, "could not read temp file %s", tmpfilename); tmpfilesize = filesize(tmpfilename); input = mymalloc(tmpfilesize + 1); bytes_read = read(tmpfile_fd, input, tmpfilesize); if (bytes_read < 0) myerror(FATAL|USE_ERRNO, "unreadable temp file %s", tmpfilename); input[bytes_read] = '\0'; rewritten_input = search_and_replace("\t", " ", input, 0, NULL, NULL); /* rlwrap cannot handle tabs in input lines */ rewritten_input2 = search_and_replace("\n", multiline_separator, rewritten_input, 0, NULL, NULL); for(p = rewritten_input2; *p ;p++) if(*p >= 0 && *p < ' ') /* @@@FIXME: works for UTF8, but not UTF16 or UTF32 (Mention this in manpage?)*/ *p = ' '; /* replace all control characters (like \r) by spaces */ rl_delete_text(0, strlen(rl_line_buffer)); rl_point = 0; clear_line(); cr(); my_putstr(saved_rl_state.cooked_prompt); rl_insert_text(rewritten_input2); rl_point = 0; /* leave cursor on predictable place */ rl_done = 1; /* accept line immediately */ /* wash those dishes */ if (unlink(tmpfilename)) myerror(FATAL|USE_ERRNO, "could not delete temporary file %s", tmpfilename); free(editor_command2); free(editor_command3); free(editor_command4); free(line_number_as_string); free(column_number_as_string); free(tmpfilename); free(text_to_edit); free(input); free(rewritten_input); free(rewritten_input2); return_key = (char)'\n'; return 0; }