?? enhance.c
字號(hào):
(void) ioctl(fd, I_PUSH, "ptem"); (void) ioctl(fd, I_PUSH, "ldterm");/* * On BSD based systems other than SunOS 4.x, the following makes the * pseudo-terminal the controlling terminal of the child process. * According to the pseudo-terminal example code in Steven's * Advanced programming in the unix environment, the !defined(CIBAUD) * part of the clause prevents this from being used under SunOS. Since * I only have his code with me, and won't have access to the book, * I don't know why this is necessary. */#elif defined(TIOCSCTTY) && !defined(CIBAUD) if(ioctl(fd, TIOCSCTTY, (char *) 0) < 0) { fprintf(stderr, "%s: Unable to establish controlling terminal (%s).\n", prog, strerror(errno)); close(fd); return -1; };#endif return fd;}/*....................................................................... * Read input from the controlling terminal of the program, using * gl_get_line(), and feed it to the user's program running in a child * process, via the controller side of the pseudo-terminal. Also pass * data received from the user's program via the conroller end of * the pseudo-terminal, to stdout. * * Input: * prog const char * The name of this program. * cntrl int The file descriptor of the controller end of the * pseudo-terminal. * Output: * return int 0 - OK. * 1 - Error. */static int pty_parent(const char *prog, int cntrl){ GetLine *gl = NULL; /* The gl_get_line() resource object */ char *line; /* An input line read from the user */ char *rbuff=NULL; /* A buffer for reading from the pseudo terminal *//* * Allocate the gl_get_line() resource object. */ gl = new_GetLine(PTY_MAX_LINE, PTY_HIST_SIZE); if(!gl) return pty_stop_parent(1, cntrl, gl, rbuff);/* * Allocate a buffer to use to accumulate bytes read from the * pseudo-terminal. */ rbuff = (char *) malloc(PTY_MAX_READ+1); if(!rbuff) return pty_stop_parent(1, cntrl, gl, rbuff); rbuff[0] = '\0';/* * Register an event handler to watch for data appearing from the * user's program on the controller end of the pseudo terminal. */ if(gl_watch_fd(gl, cntrl, GLFD_READ, pty_read_from_program, rbuff)) return pty_stop_parent(1, cntrl, gl, rbuff);/* * Read input lines from the user and pass them on to the user's program, * by writing to the controller end of the pseudo-terminal. */ while((line=gl_get_line(gl, rbuff, NULL, 0))) { if(pty_write_to_fd(cntrl, line, strlen(line))) return pty_stop_parent(1, cntrl, gl, rbuff); rbuff[0] = '\0'; }; return pty_stop_parent(0, cntrl, gl, rbuff);}/*....................................................................... * This is a private return function of pty_parent(), used to release * dynamically allocated resources, close the controller end of the * pseudo-terminal, and wait for the child to exit. It returns the * exit status of the child process, unless the caller reports an * error itself, in which case the caller's error status is returned. * * Input: * waserr int True if the caller is calling this function because * an error occured. * cntrl int The file descriptor of the controller end of the * pseudo-terminal. * gl GetLine * The resource object of gl_get_line(). * rbuff char * The buffer used to accumulate bytes read from * the pseudo-terminal. * Output: * return int The desired exit status of the program. */static int pty_stop_parent(int waserr, int cntrl, GetLine *gl, char *rbuff){ int status; /* The return status of the child process *//* * Close the controller end of the terminal. */ close(cntrl);/* * Delete the resource object. */ gl = del_GetLine(gl);/* * Delete the read buffer. */ if(rbuff) free(rbuff);/* * Wait for the user's program to end. */ (void) wait(&status);/* * Return either our error status, or the return status of the child * program. */ return waserr ? 1 : status;}/*....................................................................... * Run the user's program, with its stdin and stdout connected to the * slave end of the psuedo-terminal. * * Input: * prog const char * The name of this program. * slave int The file descriptor of the slave end of the * pseudo terminal. * argv char *[] The argument vector to pass to the user's program, * where argv[0] is the name of the user's program, * and the last argument is followed by a pointer * to NULL. * Output: * return int If this function returns at all, an error must * have occured when trying to overlay the process * with the user's program. In this case 1 is * returned. */static int pty_child(const char *prog, int slave, char *argv[]){ struct termios attr; /* The terminal attributes *//* * We need to stop the pseudo-terminal from echoing everything that we send it. */ if(tcgetattr(slave, &attr)) { fprintf(stderr, "%s: Can't get pseudo-terminal attributes (%s).\n", prog, strerror(errno)); return 1; }; attr.c_lflag &= ~(ECHO); while(tcsetattr(slave, TCSADRAIN, &attr)) { if(errno != EINTR) { fprintf(stderr, "%s: tcsetattr error: %s\n", prog, strerror(errno)); return 1; }; };/* * Arrange for stdin, stdout and stderr to be connected to the slave device, * ignoring errors that imply that either stdin or stdout is closed. */ while(dup2(slave, STDIN_FILENO) < 0 && errno==EINTR) ; while(dup2(slave, STDOUT_FILENO) < 0 && errno==EINTR) ; while(dup2(slave, STDERR_FILENO) < 0 && errno==EINTR) ;/* * Run the user's program. */ if(execvp(argv[0], argv) < 0) { fprintf(stderr, "%s: Unable to execute %s (%s).\n", prog, argv[0], strerror(errno)); fflush(stderr); _exit(1); }; return 0; /* This should never be reached */}/*....................................................................... * This is the event-handler that is called by gl_get_line() whenever * there is tet waiting to be read from the user's program, via the * controller end of the pseudo-terminal. See libtecla.h for details * about its arguments. */static GL_FD_EVENT_FN(pty_read_from_program){ char *nlptr; /* A pointer to the last newline in the accumulated string */ char *crptr; /* A pointer to the last '\r' in the accumulated string */ char *nextp; /* A pointer to the next unprocessed character *//* * Get the read buffer in which we are accumulating a line to be * forwarded to stdout. */ char *rbuff = (char *) data;/* * New data may arrive while we are processing the current read, and * it is more efficient to display this here than to keep returning to * gl_get_line() and have it display the latest prefix as a prompt, * followed by the current input line, so we loop, delaying a bit at * the end of each iteration to check for more data arriving from * the application, before finally returning to gl_get_line() when * no more input is available. */ do {/* * Get the current length of the output string. */ int len = strlen(rbuff);/* * Read the text from the program. */ int nnew = read(fd, rbuff + len, PTY_MAX_READ - len); if(nnew < 0) return GLFD_ABORT; len += nnew;/* * Nul terminate the accumulated string. */ rbuff[len] = '\0';/* * Find the last newline and last carriage return in the buffer, if any. */ nlptr = strrchr(rbuff, '\n'); crptr = strrchr(rbuff, '\r');/* * We want to output up to just before the last newline or carriage * return. If there are no newlines of carriage returns in the line, * and the buffer is full, then we should output the whole line. In * all cases a new output line will be started after the latest text * has been output. The intention is to leave any incomplete line * in the buffer, for (perhaps temporary) use as the current prompt. */ if(nlptr) { nextp = crptr && crptr < nlptr ? crptr : nlptr; } else if(crptr) { nextp = crptr; } else if(len >= PTY_MAX_READ) { nextp = rbuff + len; } else { nextp = NULL; };/* * Do we have any text to output yet? */ if(nextp) {/* * If there was already some text in rbuff before this function * was called, then it will have been used as a prompt. Arrange * to rewrite this prefix, plus the new suffix, by moving back to * the start of the line. */ if(len > 0) (void) pty_write_to_fd(STDOUT_FILENO, "\r", 1);/* * Write everything up to the last newline to stdout. */ (void) pty_write_to_fd(STDOUT_FILENO, rbuff, nextp - rbuff);/* * Start a new line. */ (void) pty_write_to_fd(STDOUT_FILENO, "\r\n", 2);/* * Skip trailing carriage returns and newlines. */ while(*nextp=='\n' || *nextp=='\r') nextp++;/* * Move any unwritten text following the newline, to the start of the * buffer. */ memmove(rbuff, nextp, len - (nextp - rbuff) + 1); }; } while(pty_master_readable(fd, PTY_READ_TIMEOUT));/* * Make the incomplete line in the output buffer the current prompt. */ gl_replace_prompt(gl, rbuff); return GLFD_REFRESH;}/*....................................................................... * Write a given string to a specified file descriptor. * * Input: * fd int The file descriptor to write to. * string const char * The string to write (of at least 'n' characters). * n int The number of characters to write. * Output: * return int 0 - OK. * 1 - Error. */static int pty_write_to_fd(int fd, const char *string, int n){ int ndone = 0; /* The number of characters written so far *//* * Do as many writes as are needed to write the whole string. */ while(ndone < n) { int nnew = write(fd, string + ndone, n - ndone); if(nnew > 0) ndone += nnew; else if(errno != EINTR) return 1; }; return 0;}/*....................................................................... * This is the signal handler that is called when the child process * that is running the user's program exits for any reason. It closes * the slave end of the terminal, so that gl_get_line() in the parent * process sees an end of file. */static void pty_child_exited(int sig){ raise(SIGINT);}/*....................................................................... * Return non-zero after a given amount of time if there is data waiting * to be read from a given file descriptor. * * Input: * fd int The descriptor to watch. * usec long The number of micro-seconds to wait for input to * arrive before giving up. * Output: * return int 0 - No data is waiting to be read (or select isn't * available). * 1 - Data is waiting to be read. */static int pty_master_readable(int fd, long usec){#if HAVE_SELECT fd_set rfds; /* The set of file descriptors to check */ struct timeval timeout; /* The timeout */ FD_ZERO(&rfds); FD_SET(fd, &rfds); timeout.tv_sec = 0; timeout.tv_usec = usec; return select(fd+1, &rfds, NULL, NULL, &timeout) == 1;#else return 0;#endif}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -