📄 rlfe.c
字号:
{ perror("could not set session leader"); } /* Tie us to our new controlling tty. */#ifdef TIOCSCTTY if (ioctl(slave, TIOCSCTTY, NULL)) { perror("could not set new controlling tty"); }#else if ((slave = get_slave_pty(name)) < 0) { perror("ptypair: could not open slave pty"); exit(1); } free(name);#endif /* make slave pty be standard in, out, and error */ dup2(slave, STDIN_FILENO); dup2(slave, STDOUT_FILENO); dup2(slave, STDERR_FILENO); /* at this point the slave pty should be standard input */ if (slave > 2) { close(slave); } /* Try to restore window size; failure isn't critical */ if (ioctl(STDOUT_FILENO, TIOCSWINSZ, &ws) < 0) { perror("could not restore window size"); } /* now start the shell */ { static char* command_args[] = { COMMAND_ARGS, NULL }; if (argc < 1) execvp(COMMAND, command_args); else execvp(argv[0], &argv[0]); } /* should never be reached */ exit(1); } /* parent */ signal (SIGCHLD, sig_child); free(name); /* Note that we only set termios settings for standard input; * the master side of a pty is NOT a tty. */ tcgetattr(STDIN_FILENO, &orig_term); t = orig_term; eof_char = t.c_cc[VEOF]; /* add_special_char(t.c_cc[VEOF]);*/ add_special_char(t.c_cc[VINTR]); add_special_char(t.c_cc[VQUIT]); add_special_char(t.c_cc[VSUSP]);#if defined (VDISCARD) add_special_char(t.c_cc[VDISCARD]);#endif#if 0 t.c_lflag |= (ICANON | ISIG | ECHO | ECHOCTL | ECHOE | \ ECHOK | ECHOKE | ECHONL | ECHOPRT );#else t.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOCTL | ECHOE | \ ECHOK | ECHOKE | ECHONL | ECHOPRT );#endif t.c_iflag |= IGNBRK; t.c_cc[VMIN] = 1; t.c_cc[VTIME] = 0; tcsetattr(STDIN_FILENO, TCSANOW, &t); in_from_inferior_fd = master; out_to_inferior_fd = master; rl_instream = fdopen (master, "r"); rl_getc_function = my_rl_getc; rl_prep_term_function = null_prep_terminal; rl_deprep_term_function = null_deprep_terminal; rl_callback_handler_install (prompt, line_handler);#if 1 rl_directory_completion_hook = rlfe_directory_completion_hook; rl_completion_entry_function = rlfe_filename_completion_function;#else rl_directory_rewrite_hook = rlfe_directory_rewrite_hook;#endif in_from_tty_fd = STDIN_FILENO; FD_ZERO (&in_set); maxfd = in_from_inferior_fd > in_from_tty_fd ? in_from_inferior_fd : in_from_tty_fd; for (;;) { int num; FD_SET (in_from_inferior_fd, &in_set); FD_SET (in_from_tty_fd, &in_set); num = select(maxfd+1, &in_set, NULL, NULL, NULL); if (propagate_sigwinch) { struct winsize ws; if (ioctl (STDIN_FILENO, TIOCGWINSZ, &ws) >= 0) { ioctl (master, TIOCSWINSZ, &ws); } propagate_sigwinch = 0; continue; } if (num <= 0) { perror ("select"); exit (-1); } if (FD_ISSET (in_from_tty_fd, &in_set)) { extern int readline_echoing_p; struct termios term_master; int do_canon = 1; int ioctl_ret; DPRINT1("[tty avail num_keys:%d]\n", num_keys); /* If we can't get tty modes for the master side of the pty, we can't handle non-canonical-mode programs. Always assume the master is in canonical echo mode if we can't tell. */ ioctl_ret = tcgetattr(master, &term_master); if (ioctl_ret >= 0) { DPRINT2 ("echo:%d, canon:%d\n", (term_master.c_lflag & ECHO) != 0, (term_master.c_lflag & ICANON) != 0); do_canon = (term_master.c_lflag & ICANON) != 0; readline_echoing_p = (term_master.c_lflag & ECHO) != 0; } else { if (ioctl_err == 0) DPRINT1("tcgetattr on master fd failed: errno = %d\n", errno); ioctl_err = 1; } if (do_canon == 0 && num_keys == 0) { char ch[10]; int count = read (STDIN_FILENO, ch, sizeof(ch)); write (out_to_inferior_fd, ch, count); } else { if (num_keys == 0) { int i; /* Re-install callback handler for new prompt. */ if (prompt != empty_string) free (prompt); prompt = malloc (buf_count + 1); if (prompt == NULL) prompt = empty_string; else { memcpy (prompt, buf, buf_count); prompt[buf_count] = '\0'; DPRINT1("New prompt '%s'\n", prompt);#if 0 /* ifdef HAVE_RL_ALREADY_PROMPTED -- doesn't work */ rl_already_prompted = buf_count > 0;#else if (buf_count > 0) write (1, "\r", 1);#endif } rl_callback_handler_install (prompt, line_handler); } num_keys++; rl_callback_read_char (); } } else /* input from inferior. */ { int i; int count; int old_count; if (buf_count > (sizeof(buf) >> 2)) buf_count = 0; count = read (in_from_inferior_fd, buf+buf_count, sizeof(buf) - buf_count); if (count <= 0) { DPRINT0 ("(Connection closed by foreign host.)\n"); tcsetattr(STDIN_FILENO, TCSANOW, &orig_term); exit (0); } old_count = buf_count; /* Do some minimal carriage return translation and backspace processing before logging the input line. */ if (logfile) {#ifndef __GNUC__ char *b;#else char b[count + 1];#endif int i, j;#ifndef __GNUC__ b = malloc (count + 1); if (b) {#endif for (i = 0; i < count; i++) b[i] = buf[buf_count + i]; b[i] = '\0'; for (i = j = 0; i <= count; i++) { if (b[i] == '\r') { if (b[i+1] != '\n') b[j++] = '\n'; } else if (b[i] == '\b') { if (i) j--; } else b[j++] = b[i]; } fprintf (logfile, "%s", b);#ifndef __GNUC__ free (b); }#endif } /* Look for any pending echo that we need to suppress. */ while (echo_suppress_start < echo_suppress_limit && count > 0 && buf[buf_count] == echo_suppress_buffer[echo_suppress_start]) { count--; buf_count++; echo_suppress_start++; } /* Write to the terminal anything that was not suppressed. */ if (count > 0) write (1, buf + buf_count, count); /* Finally, look for a prompt candidate. * When we get around to going input (from the keyboard), * we will consider the prompt to be anything since the last * line terminator. So we need to save that text in the * initial part of buf. However, anything before the * most recent end-of-line is not interesting. */ buf_count += count;#if 1 for (i = buf_count; --i >= old_count; )#else for (i = buf_count - 1; i-- >= buf_count - count; )#endif { if (buf[i] == '\n' || buf[i] == '\r') { i++; memmove (buf, buf+i, buf_count - i); buf_count -= i; break; } } DPRINT2("-> i: %d, buf_count: %d\n", i, buf_count); } }}/* * * FILENAME COMPLETION FOR RLFE * */#ifndef PATH_MAX# define PATH_MAX 1024#endif#define DIRSEP '/'#define ISDIRSEP(x) ((x) == '/')#define PATHSEP(x) (ISDIRSEP(x) || (x) == 0)#define DOT_OR_DOTDOT(x) \ ((x)[0] == '.' && (PATHSEP((x)[1]) || \ ((x)[1] == '.' && PATHSEP((x)[2]))))#define FREE(x) if (x) free(x)#define STRDUP(s, x) do { \ s = strdup (x);\ if (s == 0) \ return ((char *)NULL); \ } while (0)static intget_inferior_cwd (path, psize) char *path; size_t psize;{ int n; static char procfsbuf[PATH_MAX] = { '\0' }; if (procfsbuf[0] == '\0') sprintf (procfsbuf, "/proc/%d/cwd", (int)child); n = readlink (procfsbuf, path, psize); if (n < 0) return n; if (n > psize) return -1; path[n] = '\0'; return n;}static intrlfe_directory_rewrite_hook (dirnamep) char **dirnamep;{ char *ldirname, cwd[PATH_MAX], *retdir, *ld; int n, ldlen; ldirname = *dirnamep; if (*ldirname == '/') return 0; n = get_inferior_cwd (cwd, sizeof(cwd) - 1); if (n < 0) return 0; if (n == 0) /* current directory */ { cwd[0] = '.'; cwd[1] = '\0'; n = 1; } /* Minimally canonicalize ldirname by removing leading `./' */ for (ld = ldirname; *ld; ) { if (ISDIRSEP (ld[0])) ld++; else if (ld[0] == '.' && PATHSEP(ld[1])) ld++; else break; } ldlen = (ld && *ld) ? strlen (ld) : 0; retdir = (char *)malloc (n + ldlen + 3); if (retdir == 0) return 0; if (ldlen) sprintf (retdir, "%s/%s", cwd, ld); else strcpy (retdir, cwd); free (ldirname); *dirnamep = retdir; DPRINT1("rl_directory_rewrite_hook returns %s\n", retdir); return 1;}/* Translate *DIRNAMEP to be relative to the inferior's CWD. Leave a trailing slash on the result. */static intrlfe_directory_completion_hook (dirnamep) char **dirnamep;{ char *ldirname, *retdir; int n, ldlen; ldirname = *dirnamep; if (*ldirname == '/') return 0; n = rlfe_directory_rewrite_hook (dirnamep); if (n == 0) return 0; ldirname = *dirnamep; ldlen = (ldirname && *ldirname) ? strlen (ldirname) : 0; if (ldlen == 0 || ldirname[ldlen - 1] != '/') { retdir = (char *)malloc (ldlen + 3); if (retdir == 0) return 0; if (ldlen) strcpy (retdir, ldirname); else retdir[ldlen++] = '.'; retdir[ldlen] = '/'; retdir[ldlen+1] = '\0'; free (ldirname); *dirnamep = retdir; } DPRINT1("rl_directory_completion_hook returns %s\n", retdir); return 1;}static char *rlfe_filename_completion_function (text, state) const char *text; int state;{ static DIR *directory; static char *filename = (char *)NULL; static char *dirname = (char *)NULL, *ud = (char *)NULL; static int flen, udlen; char *temp; struct dirent *dentry; if (state == 0) { if (directory) { closedir (directory); directory = 0; } FREE (dirname); FREE (filename); FREE (ud); if (text && *text) STRDUP (filename, text); else { filename = malloc(1); if (filename == 0) return ((char *)NULL); filename[0] = '\0'; } dirname = (text && *text) ? strdup (text) : strdup ("."); if (dirname == 0) return ((char *)NULL); temp = strrchr (dirname, '/'); if (temp) { strcpy (filename, ++temp); *temp = '\0'; } else { dirname[0] = '.'; dirname[1] = '\0'; } STRDUP (ud, dirname); udlen = strlen (ud); rlfe_directory_completion_hook (&dirname); directory = opendir (dirname); flen = strlen (filename); rl_filename_completion_desired = 1; } dentry = 0; while (directory && (dentry = readdir (directory))) { if (flen == 0) { if (DOT_OR_DOTDOT(dentry->d_name) == 0) break; } else { if ((dentry->d_name[0] == filename[0]) && (strlen (dentry->d_name) >= flen) && (strncmp (filename, dentry->d_name, flen) == 0)) break; } } if (dentry == 0) { if (directory) { closedir (directory); directory = 0; } FREE (dirname); FREE (filename); FREE (ud); dirname = filename = ud = 0; return ((char *)NULL); } if (ud == 0 || (ud[0] == '.' && ud[1] == '\0')) temp = strdup (dentry->d_name); else { temp = malloc (1 + udlen + strlen (dentry->d_name)); strcpy (temp, ud); strcpy (temp + udlen, dentry->d_name); } return (temp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -