예제 #1
0
파일: main.c 프로젝트: albfan/rlwrap
void
cleanup_rlwrap_and_exit(int status)
{
  unblock_all_signals();
  DPRINTF0(DEBUG_TERMIO, "Cleaning up");

  if (write_histfile && (histsize==0 ||  history_total_bytes() > 0)) /* avoid creating empty .speling_eror_history file after typo */
    write_history(history_filename);	/* ignore errors */

  close_logfile();

  DPRINTF4(DEBUG_SIGNALS, "command_pid: %d, commands_exit_status: %x, filter_pid: %d, filters_exit_status: %x",
           command_pid, commands_exit_status, filter_pid, filters_exit_status);
  mymicrosleep(10); /* we may have got an EOF or EPIPE because the filter or command died, but this doesn't mean that
                       SIGCHLD has been caught already. Taking a little nap now improves the chance that we will catch it
                       (no grave problem if we miss it, but diagnostics, exit status and transparent signal handling depend on it) */
  if (filter_pid) 
    kill_filter();
  else if (filter_is_dead) {
    int filters_killer = killed_by(filters_exit_status);
    errno = 0;
    mywarn((filters_killer ? "filter was killed by signal %d (%s)": WEXITSTATUS(filters_exit_status) ? "filter died" : "filter exited"), filters_killer, signal_name(filters_killer));
  }     
  if (debug) 
    debug_postmortem();
  
  if (terminal_settings_saved)
    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_terminal_settings) < 0)  /* ignore errors (almost dead anyway) */ 
      ; /* fprintf(stderr, "Arggh\n"); don't use myerror!!*/

  if (!newline_came_last) /* print concluding newline, if necessary */
    my_putstr("\n");
     

  if (status != EXIT_SUCCESS)  /* rlwrap itself has failed, rather than the wrapped command */
    exit(status);              
  else {                      
    int commands_killer = killed_by(commands_exit_status);
    if (commands_killer)
      suicide_by(commands_killer, commands_exit_status); /* command terminated by signal, make rlwrap's
                                                            parent believe rlwrap was killed by it */ 
    else
      exit(WEXITSTATUS(commands_exit_status));           /* propagate command's exit status */
  }
}
예제 #2
0
파일: filter.c 프로젝트: rubicks/rlwrap
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]);
    }
}
예제 #3
0
int i2c_hd44780_pcf8574_init(int fd, i2c_hd44780_pcf8574_pins_map_t pcf8574_pins)
/**
 * \brief     initialisation pcf8574 et hd44780.
 * \details   
 
 Sequence d'initialisation d'un hd44780 :
   - Attendre au moins 15ms depuis le passage a 5V de Vcc,
   - Envoyer l'instruction "Function set" avec la valeur 0011XXXX,
   - Attendre au moins 4.1ms,
   - Envoyer à nouveau l'instruction "Function set" avec la valeur 0011XXXX,
   - Attendre au moins 100 microsecondes,
   - Envoyer à nouveau l'instruction "Function set" avec la valeur 0011XXXX,
   - Si on veut activer le mode 4 bits, envoyer les 4 bits de poids fort de l'instruction
     "Function set" avec la valeur 0010,
   - Configuration du nombre de lignes et de la matrice, en envoyant l'Instruction "Function set"
     avec par exemple la valeur 00111000 (8 bits, 2 lignes, 5x8pixels),
   - Configuration du controle d'affichage, en envoyant l'instruction "Display on/off control" avec par exemple
     la valeur 00001110 (Affichage visible, curseur visible, curseur fixe), // HD44780_CMD_TURN_ON_DISP
   - Effacement de l'ecran, en envoyant l'instruction "Clear display", avec pour valeur 00000001, // HD44780_CMD_CLEAR_HOME
   - Configuration du curseur, en envoyant l'instruction "Entry set mode", avec par exemple pour
     valeur 00000110 (deplacement du curseur vers la droite, pas de decalage du compteur d'adresse). // HD44780_CMD_SET_CSR
   - Fin de l'initialisation, l'ecran est prêt à recevoir les autres instructions permettant l'affichage.
   
 * \param     fd            descripteur de communication avec le pcf8574.
 * \param     pcf8574_pins  mapping hd44780/PCF8574
 */
{
   unsigned char d;
   
   d=0;

   mynanosleep(15 * 1000000); // 15 ms

   BITSET(d, pcf8574_pins[_HD44780_DATA5]);
   BITSET(d, pcf8574_pins[_HD44780_DATA4]);

   mymicrosleep(15000);
   
   // initialisation
   _i2c_hd44780_pcf8574_lowlevel_write(fd, d, pcf8574_pins); // 1er 0x3
   mymicrosleep(5000);

   _i2c_hd44780_pcf8574_lowlevel_write(fd, d, pcf8574_pins); // 2eme 0x3
   mymicrosleep(100);
   
   _i2c_hd44780_pcf8574_lowlevel_write(fd, d, pcf8574_pins); // 4eme 0x3
   mymicrosleep(150);
   
   // passage en mode 4 bits
   BITCLEAR(d, pcf8574_pins[_HD44780_DATA4]);
   _i2c_hd44780_pcf8574_lowlevel_write(fd, d, pcf8574_pins);
   mymicrosleep(1000);

   // préparation divers
   i2c_hd44780_pcf8574_write_byte(fd, HD44780_CMD_SET_INTERFACE, CMND, 1, pcf8574_pins);
   mymicrosleep(50);
   i2c_hd44780_pcf8574_write_byte(fd, HD44780_CMD_EN_DISP, CMND, 1, pcf8574_pins);
   mymicrosleep(50);
   i2c_hd44780_pcf8574_write_byte(fd, HD44780_CMD_CLEAR_HOME, CMND, 1, pcf8574_pins);
   mymicrosleep(1500);
//   mymicrosleep(2000);
   i2c_hd44780_pcf8574_write_byte(fd, HD44780_CMD_SET_CSR, CMND, 1, pcf8574_pins);
   mymicrosleep(50);
   i2c_hd44780_pcf8574_write_byte(fd, HD44780_CMD_TURN_ON_DISP, CMND, 1, pcf8574_pins);
   mymicrosleep(50);

   return 0;
}
예제 #4
0
파일: main.c 프로젝트: v2e4lisp/rlwrap
/*
 * main loop: listen on stdin (for user input) and master pty (for command output),
 * and try to write output_queue to master_pty (if it is not empty)
 * This function never returns.
 */
void
main_loop()
{				
  int nfds;			
  fd_set readfds;	
  fd_set writefds;
  int nread;		
  char buf[BUFFSIZE], *timeoutstr, *old_raw_prompt, *new_output_minus_prompt;
  int promptlen = 0;
  int leave_prompt_alone;
  sigset_t no_signals_blocked;
  int seen_EOF = FALSE;     

   
  struct timespec         select_timeout, *select_timeoutptr;
  struct timespec immediately = { 0, 0 }; /* zero timeout when child is dead */
  struct timespec  wait_a_little = {0, 0xBadf00d }; /* tv_usec field will be filled in when initialising */
  struct timespec  *forever = NULL;
  wait_a_little.tv_nsec = 1000 * 1000 * wait_before_prompt;

  
  sigemptyset(&no_signals_blocked);
  

  init_readline("");
  last_minute_checks();
  pass_through_filter(TAG_OUTPUT,""); /* If something is wrong with filter, get the error NOW */
  set_echo(FALSE);		/* This will also put the terminal in CBREAK mode */
	test_main(); 
  
  /* ------------------------------  main loop  -------------------------------*/
  while (TRUE) {
    /* listen on both stdin and pty_fd */
    FD_ZERO(&readfds);
    FD_SET(STDIN_FILENO, &readfds);
    FD_SET(master_pty_fd, &readfds);

    /* try to write output_queue to master_pty (but only if it is nonempty) */
    FD_ZERO(&writefds);
    if (output_queue_is_nonempty())
      FD_SET(master_pty_fd, &writefds);



    DPRINTF1(DEBUG_AD_HOC, "prompt_is_still_uncooked =  %d", prompt_is_still_uncooked);
    if (command_is_dead || ignore_queued_input) {
      select_timeout = immediately;
      select_timeoutptr = &select_timeout;
      timeoutstr = "immediately";
    } else if (prompt_is_still_uncooked || polling) {
      select_timeout = wait_a_little;
      select_timeoutptr = &select_timeout;
      timeoutstr = "wait_a_little";
    } else {
      select_timeoutptr = forever; /* NULL */
      timeoutstr = "forever";
    }
     
    DPRINTF1(DEBUG_TERMIO, "calling select() with timeout %s",  timeoutstr);
    

    nfds = my_pselect(1 + master_pty_fd, &readfds, &writefds, NULL, select_timeoutptr, &no_signals_blocked);

    DPRINTF3(DEBUG_TERMIO, "select() returned  %d (stdin|pty in|pty out = %03d), within_line_edit=%d", nfds,
	     100*(FD_ISSET(STDIN_FILENO, &readfds)?1:0) + 10*(FD_ISSET(master_pty_fd, &readfds)?1:0) + (FD_ISSET(master_pty_fd, &writefds)?1:0), 
	     within_line_edit);

    assert(!filter_pid || filter_is_dead || kill(filter_pid,0) == 0); 
    assert(command_is_dead || kill(command_pid,0) == 0);
    
    /* check flags that may have been set by signal handlers */
    if (filter_is_dead) 
      filters_last_words(); /* will call myerror with last words */
      	
    if (received_WINCH) {  /* received_WINCH flag means we've had a WINCH while within_line_edit was FALSE */
      DPRINTF0(DEBUG_READLINE, "Starting line edit as a result of WINCH ");
      within_line_edit = TRUE;
      restore_rl_state();
      received_WINCH = FALSE;
      continue;
    }	
    
    if (nfds < 0) {		/* exception  */	
      if (errno == EINTR || errno == 0) {	/* interrupted by signal, or by a cygwin bug (errno == 0) :-( */
	continue;
      }	else
	myerror(FATAL|USE_ERRNO, "select received exception");
    } else if (nfds == 0) {
      
      /* timeout, which can only happen when .. */
      if (ignore_queued_input) {       /* ... we have read all the input keystrokes that should
					  be ignored (i.e. those that accumulated on stdin while we
				          were calling an external editor) */
	ignore_queued_input = FALSE;
	continue;
      } else if (command_is_dead) {                         /* ... or else, if child is dead, ... */
	DPRINTF2(DEBUG_SIGNALS,
		 "select returned 0, command_is_dead=%d, commands_exit_status=%d",
		 command_is_dead, commands_exit_status);
	cleanup_rlwrap_and_exit(EXIT_SUCCESS);
      }	else if (prompt_is_still_uncooked) { /* cooking time? */
	if (we_just_got_a_signal_or_EOF) {
	  we_just_got_a_signal_or_EOF = FALSE;              /* 1. If we got a signal/EOF before cooking time, we don't need special action
                                                                  to preserve the cooked prompt.
							       2. Reset we_just_got_a_signal_or_EOF  after a signal or EOF that didn't kill command */
          continue;
	}	
	if (!skip_rlwrap()) {                        /* ... or else, it is time to cook the prompt */
	  if (pre_given && accepted_lines == 0) {
            /* input_buffer and point have already been set in init_readline() */
	    DPRINTF0(DEBUG_READLINE, "Starting line edit (because of -P option)");
	    within_line_edit = TRUE;
	    restore_rl_state();
	    continue;
	  }
	  
	  if (accepted_lines == 1 && one_shot_rlwrap) 
	    cleanup_rlwrap_and_exit(EXIT_SUCCESS);

			  
	  move_cursor_to_start_of_prompt(ERASE); /* cooked prompt may be shorter than raw prompt, hence the ERASE */
	  /* move and erase before cooking, as we need to move/erase according
	     to the raw prompt */
          cook_prompt_if_necessary();
	  DPRINTF2(DEBUG_READLINE,"After cooking, raw_prompt=%s, cooked=%s",
                   mangle_string_for_debug_log(saved_rl_state.raw_prompt, MANGLE_LENGTH),
                   mangle_string_for_debug_log(saved_rl_state.cooked_prompt, MANGLE_LENGTH));
	  my_putstr(saved_rl_state.cooked_prompt);
	  rlwrap_already_prompted = TRUE;
	}
	prompt_is_still_uncooked = FALSE;
      } else if (polling) {
        completely_mirror_slaves_special_characters();
        if (mirror_arguments)
          mirror_args(command_pid);
        continue;
      } else {
	myerror(FATAL|NOERRNO, "unexpected select() timeout");
      }
    } else if (nfds > 0) {	/* Hah! something to read or write */ 

      /* -------------------------- read pty --------------------------------- */
      /* Always first read and process the slave command's output, even if there is input waiting on stdin 
         (which may happen when pasting a lot of text). E.g. when pasting "a\nb\nc" into "rlwrap cat" we want
         a 
         a
         b
         b
         c
         c

         and not
  
         a
         b
         c
         a
         b
         c
      */ 
      if (FD_ISSET(master_pty_fd, &readfds)) { /* there is something (or nothing, if EOF) to read on master pty: */
        nread = read(master_pty_fd, buf, BUFFSIZE - 1); /* read it */
        DPRINTF1(DEBUG_AD_HOC, "nread: %d", nread);
	if (nread <= 0) { 
	  if (command_is_dead || nread == 0) { /*  we catched a SIGCHLD,  or slave command has closed its stdout */
	    if (promptlen > 0)	/* commands dying words were not terminated by \n ... */
	      my_putchar('\n');	/* provide the missing \n */
	    cleanup_rlwrap_and_exit(EXIT_SUCCESS);
	  } else  if (errno == EINTR) {	/* interrupted by signal ...*/	                     
	    continue;                   /* ... don't worry */
	  } else  if (! seen_EOF) {     /* maybe command has just died (and SIGCHLD, whose handler sets command_is_dead is not  */     
            mymicrosleep(50);           /* yet caught) Therefore we wait a bit,                                                 */
            seen_EOF = TRUE;            /* set a flag                                                                           */   
            continue;                   /* and try one more time (hopefully catching the signal this time round                 */
          } else {
            myerror(FATAL|USE_ERRNO, "read error on master pty"); 
          }
	}
	  
	completely_mirror_slaves_output_settings(); /* some programs (e.g. joe) need this. Gasp!! */	
        mirror_args(command_pid);        
	
        if (skip_rlwrap()) { /* Race condition here! The client may just have finished an emacs session and
			        returned to cooked mode, while its ncurses-riddled output is stil waiting for us to be processed. */
	  write_patiently(STDOUT_FILENO, buf, nread, "to stdout");

	  DPRINTF2(DEBUG_TERMIO, "read from pty and wrote to stdout  %d  bytes in direct mode  <%s>",
                   nread, mangle_string_for_debug_log((buf[nread]='\0', buf), MANGLE_LENGTH));
	  yield();
	  continue;
	}

	DPRINTF2(DEBUG_TERMIO, "read %d bytes from pty into buffer: %s", nread,  mangle_string_for_debug_log((buf[nread]='\0', buf), MANGLE_LENGTH));
        
        remove_padding_and_terminate(buf, nread);
        
	write_logfile(buf);
	if (within_line_edit)	/* client output arrives while we're editing keyboard input:  */
	  save_rl_state();      /* temporarily disable readline and restore the screen state before readline was called */
  

	assert(saved_rl_state.raw_prompt != NULL);


        /* We *always* compute the printable part and the new raw prompt, and *always* print the printable part
           There are four possibilities:
           1. impatient before cooking.         The raw prompt has been printed,  write the new output after it
           2. patient before cooking            No raw prompt has been printed yet, don't print anything
           3. impatient after cooking
             3a  no current prompt              print the new output
             3b  some current prompt            erase it, replace by current raw prompt and print new output
           4. patient after cooking             don't print anything
        */
        
        /* sometimes we want to leave the prompt standing, e.g. after accepting a line, or when a signal arrived */
	leave_prompt_alone =
	     *saved_rl_state.raw_prompt == '\0' /* saved_rl_state.raw_prompt = "" in two distinct cases: when there is actually no prompt,
						   or just after accepting a line, when the cursor is at the end of the prompt. In both
						   cases, we dont't want to move the cursor */
          || prompt_is_still_uncooked /* in this case no prompt has been displayed yet */
          || command_is_dead                    
          || (we_just_got_a_signal_or_EOF && strrchr(buf, '\n')); /* a signal followed by output with a newline in it: treat it as
                                                                     response to user input, so leave the prompt alone */

        DPRINTF3(DEBUG_READLINE, "leave_prompt_alone: %s (raw prompt: %s, prompt_is_still_uncooked: %d)",
                 (leave_prompt_alone? "yes" : "no"), mangle_string_for_debug_log(saved_rl_state.raw_prompt, MANGLE_LENGTH), prompt_is_still_uncooked);
	
        if (!leave_prompt_alone) /* && (!impatient_prompt || !saved_rl_state.cooked_prompt)) */
	  move_cursor_to_start_of_prompt(ERASE);  
	else if (we_just_got_a_signal_or_EOF) {
	  free (saved_rl_state.raw_prompt);
	  saved_rl_state.raw_prompt =  mysavestring(""); /* prevent reprinting the prompt */
	}	

        if (impatient_prompt && !leave_prompt_alone)
          old_raw_prompt =  mysavestring(saved_rl_state.raw_prompt);

        new_output_minus_prompt = process_new_output(buf, &saved_rl_state);	/* chop off the part after the last newline and put this in
										   saved_rl_state.raw_prompt (or append buf if  no newline found)*/

	if (impatient_prompt) {   /* in impatient mode, ALL command output is passed through the OUTPUT filter, including the prompt The
				     prompt, however, is filtered separately at cooking time and then displayed */
	  char *filtered = pass_through_filter(TAG_OUTPUT, buf);
          if(!leave_prompt_alone) {
            my_putstr(old_raw_prompt);
            free(old_raw_prompt);
          }
	  my_putstr(filtered);
	  free (filtered);
	  rlwrap_already_prompted = TRUE;
	} else {
	  my_putstr(new_output_minus_prompt);
	  rlwrap_already_prompted = FALSE;
	}	
	   
	free(new_output_minus_prompt);	

		    
	prompt_is_still_uncooked = TRUE; 
       

	if (within_line_edit)
	  restore_rl_state();

	yield();  /* wait for what client has to say .... */ 
	continue; /* ... and don't attempt to process keyboard input as long as it is talking ,
		     in order to avoid re-printing the current prompt (i.e. unfinished output line) */
      }

      
      /* ----------------------------- key pressed: read stdin -------------------------*/
      if (FD_ISSET(STDIN_FILENO, &readfds)) {	/* key pressed */
	unsigned char byte_read;                /* the readline function names and documentation talk about "characters" and "keys",
						   but we're reading bytes (i.e. unsigned chars) here, and those may very well be
						   part of a multi-byte character. Example: hebrew "aleph" in utf-8 is 0xd790; pressing this key
						   will make us read 2 bytes 0x90 and then 0xd7, (or maybe the other way round depending on endianness??)
						   The readline library hides all this complexity and allows one to just "pass the bytes around" */
	nread = read(STDIN_FILENO, &byte_read, 1);  /* read next byte of input   */
	assert(sizeof(unsigned char) == 1);         /* gets optimised away       */

	if (nread <= 0) 
	  DPRINTF1(DEBUG_TERMIO, "read from stdin returned %d", nread); 
	if (nread < 0)
	  if (errno == EINTR)
	    continue;
	  else
	    myerror(FATAL|USE_ERRNO, "Unexpected error");
	else if (nread == 0)	/* EOF on stdin */
	  cleanup_rlwrap_and_exit(EXIT_SUCCESS);
        else if (ignore_queued_input)
	  continue;             /* do nothing with it*/
	assert(nread == 1);
	DPRINTF2(DEBUG_TERMIO, "read from stdin: byte 0x%02x (%s)", byte_read, mangle_char_for_debug_log(byte_read, TRUE)); 
	if (skip_rlwrap()) {	/* direct mode, just pass it on */
	                        /* remote possibility of a race condition here: when the first half of a multi-byte char is read in
				   direct mode and the second half in readline mode. Oh well... */
	  DPRINTF0(DEBUG_TERMIO, "passing it on (in transparent mode)");	
	  completely_mirror_slaves_terminal_settings(); /* this is of course 1 keypress too late: we should
							   mirror the terminal settings *before* the user presses a key.
							   (maybe using rl_event_hook??)   @@@FIXME  @@@ HOW?*/
          write_patiently(master_pty_fd, &byte_read, 1, "to master pty");
	} else {		/* hand it over to readline */
	  if (!within_line_edit) {	/* start a new line edit    */
	    DPRINTF0(DEBUG_READLINE, "Starting line edit");
	    within_line_edit = TRUE;
	    restore_rl_state();
	  } 
	                                        
	  
	  

	  if (term_eof && byte_read == term_eof && strlen(rl_line_buffer) == 0) {	/* hand a term_eof (usually CTRL-D) directly to command */ 
	    char *sent_EOF = mysavestring("?");
	    *sent_EOF = term_eof;
	    put_in_output_queue(sent_EOF);
	    we_just_got_a_signal_or_EOF = TRUE;
	    free(sent_EOF);
	  }	
	  else {
	    rl_stuff_char(byte_read);  /* stuff it back in readline's input queue */
	    DPRINTF0(DEBUG_TERMIO, "passing it to readline");	
	    DPRINTF2(DEBUG_READLINE, "rl_callback_read_char() (_rl_eof_char=%d, term_eof=%d)", _rl_eof_char, term_eof);
	    rl_callback_read_char();
	  }
	}
      }
    
      /* -------------------------- write pty --------------------------------- */
      if (FD_ISSET(master_pty_fd, &writefds)) {
	flush_output_queue();
	yield(); /*  give  slave command time to respond. If we don't do this,
		     nothing bad will happen, but the "dialogue" on screen will be
		     out of order   */
      }
    }				/* if (ndfs > 0)         */
  }				/* while (1)             */
}				/* void main_loop()      */