⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 enhance.c

📁 xorp源码hg
💻 C
📖 第 1 页 / 共 2 页
字号:
  (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}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -