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

📄 command.c

📁 multi-tabed terminal based on rxvt
💻 C
📖 第 1 页 / 共 5 页
字号:
    }    else if ( ndead_childs > 0 )    {	/*	 * This is problematic. The number of processes that were promised as	 * "dead" on entry to this function is not actually the number of	 * processes that are dead!	 *	 * NOTE: It is OK for r->ndead_childs > 0, as r->ndead_childs could be	 * externally modified while we are in this function.	 *	 * We should only get here when one of our child processes that is NOT	 * running in a tab dies. For instance, when we print something with our	 * "PrintPipe" macro. If we get here for any other reason, we're in deep	 * trouble.	 */	rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND,  "Spurious dead child signal received\n"));	/*	 * We should reset r->ndead_childs to 0. But there is a possible race	 * condition with doing that. Suppose we received a dead child signal	 * *after* looping over all childs, but just before getting here!	 *	 * To avoid this we only reduce r->ndead_childs by the number of	 * processes we failed to catch as dead. Further, when we get EIO errors	 * reading from a child, we call this function to see if the child is	 * dead or not.	 */	r->ndead_childs -= ndead_childs;    }    rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND,  "Exit rxvt_mark_dead_childs(): %d children are dead\n", r->ndead_childs));}/* * Cleans out tabs which have died but have not been cleaned up. (i.e. dead && * hold == 1) * * NOTE: This function MUST NOT be called from rxvt_cmd_getc(), because it could * redirect command buffer input of the tabs. *//* INTPROTO */voidrxvt_clean_cmd_page (rxvt_t* r){    int		i;    rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND,  "rxvt_clean_cmd_page()\n" ));    if( r->ndead_childs )	rxvt_mark_dead_childs( r );   /*    * We had better not get here unless we need to clean up dead children. Make    * sure we don't proceed when we receive spurious dead child messages (e.g.    * from when the print pipe dies).    */    if( !r->cleanDeadChilds )	return;    /*     * We start from the last child because we need to move ahead after     * removing dead child. This makes it much safer.     *     * Why do we need to restart dead value from LTAB(r) again? Because a     * child may have died when we do something following and changed the     * value of r->ndead_childs! This child may be later than any dead children     * we have examined.     */    for (i = LTAB(r); i >= 0; i--)    {	if( PVTS(r, i)->dead && PVTS(r, i)->hold == 1 )	{	    rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, 			"Tab %d exit %s (status %d). holdOption: %d\n",			i, WIFEXITED(PVTS(r,i)->status) ? "success" : "failure",			PVTS(r,i)->status,			PVTS(r,i)->holdOption));	    /*	     * Process in tab i has died, and needs to be cleaned up.	     */	    if( SHOULD_HOLD( r, i ) )	    {		const int	maxLen = 1024;		const char	*msg;		rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND,			    "Hold child %d after it died\n", i));		/* increase hold number, so next iteration will skip it */		PVTS(r, i)->hold++;		/*		 * Process any pending data from the child.		 */		do		  {		    unsigned char *last_escfail = NULL;		    /*		     * Process information in the child's output buffer.		     */		    while( PVTS(r, i)->cmdbuf_ptr < PVTS(r, i)->cmdbuf_endp )		    {			rxvt_process_getc( r, i, *(PVTS(r,i)->cmdbuf_ptr++) );			/* Incomplete escape sequence. */			if( PVTS(r, i)->cmdbuf_escfail )			{			    /*			     * See if reading from the child's fd will complete			     * this escape seqeunce.			     */			    if( IS_NULL( last_escfail ) )				last_escfail = PVTS(r, i)->cmdbuf_escfail;			    else			    {				/* Really incomplete escape sequence */				rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "Incomplete escape sequence '%.*s'\n", 					      PVTS(r, i)->cmdbuf_escfail - PVTS(r, i)->cmdbuf_escstart + 1, 					      PVTS(r, i)->cmdbuf_escstart+1));				SET_NULL( last_escfail );				SET_NULL( PVTS(r, i)->cmdbuf_escstart );				SET_NULL( PVTS(r, i)->cmdbuf_escfail );				/* Skip the escape char */				PVTS(r, i)->cmdbuf_ptr++;			    }			} /* if( PVTS(r, i)->cmdbuf_escfail ) */		    }		    /*		     * Write out pending data in the child's input buffer.		     */		    if (PVTS(r, i)->v_bufstr < PVTS(r, i)->v_bufptr)			rxvt_cmd_write(r, i, NULL, 0);		    /* Make place for new data */		    rxvt_check_cmdbuf( r, i );		    /* Read any remaining data from childs fd */		    rxvt_read_child_cmdfd( r, i,			    BUFSIZ - 1 -				(PVTS(r, i)->cmdbuf_endp					- PVTS(r, i)->cmdbuf_base) );		  }		while( rxvt_cmdbuf_has_input( r, i) );		/*		 * print holdExitText on screen if defined.		 */		msg = getProfileOption( r, PVTS(r,i)->profileNum,				Rs_holdExitTxt );		if( NOT_NULL( msg ) && *msg )		{		    unsigned char   buffer[maxLen];		    int		    len;		    rxvt_percent_interpolate( r, i, msg, STRLEN(msg),			    (char*) buffer, maxLen );		    len = rxvt_str_escaped( (char*) buffer );		    rxvt_cmd_write(r, i, buffer, len );		    if( PVTS(r, i)->cmdbuf_ptr < PVTS(r, i)->cmdbuf_endp )			rxvt_process_getc( r, i, *(PVTS(r,i)->cmdbuf_ptr++) );		}		/*		 * Update title to show tab has finished.		 */		msg = getProfileOption( r, PVTS(r,i)->profileNum,				Rs_holdExitTtl );		if( NOT_NULL( msg ) && *msg )		{		    unsigned char    tabTitle[maxLen];		    rxvt_percent_interpolate( r, i, msg, STRLEN(msg),			    (char*) tabTitle, maxLen );		    rxvt_str_escaped( (char*) tabTitle );		    rxvt_tabbar_set_title( r, i, tabTitle );		}	    } /* if( SHOULD_HOLD( r, i ) ) */	    else		rxvt_remove_page( r, i );	}    } /* for(i) */    r->cleanDeadChilds = 0; /* Dead child cleanup complete. */}/* Returns true if there is input pending in PVTS(r, page)->cmdbuf *//* INTPROTO */int static inlinerxvt_cmdbuf_has_input( rxvt_t *r, int page ){    return PVTS(r, page)->cmdbuf_escfail ?	PVTS(r, page)->cmdbuf_escfail < PVTS(r, page)->cmdbuf_endp	    :	PVTS(r, page)->cmdbuf_ptr < PVTS(r, page)->cmdbuf_endp;}/* * Find a tab with some output, and return it. * * Bug #1102791 (Carsten Menke): A really busy tab could starve all others. So * use a round robin to go through all tabs. *//* INTPROTO */intrxvt_find_cmd_child (rxvt_t* r){    register int    k;    static int	    lastProcessed = 0;  /* tab we processed last time */    rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND,  "rxvt_find_cmd_child()\n" ));    /*     * See if the active tab has input before anything else.     */    if( rxvt_cmdbuf_has_input( r, ATAB(r) ) )	return ATAB(r);    /*     * Now look for data from other tabs. Remember the tab we found data from so     * that we can start from the next tab on the next call to this function.     */    if( lastProcessed > LTAB(r) )   /* Sanity check */	lastProcessed = LTAB(r);    /* start from the next tab of last processed tab */    k = lastProcessed + 1;    do      {	if( k > LTAB(r) )	/* round-robin */	    k = 0;	assert( PVTS(r, k)->cmdbuf_base <= PVTS(r, k)->cmdbuf_endp );	/* already have something in some page's buffer */	if( rxvt_cmdbuf_has_input(r, k) )	{	    lastProcessed = k;	    return k;	}      }    while (k++ != lastProcessed);	/* until we hit the last child again */    return -1; /* not found */}/* INTPROTO */voidrxvt_check_cmdbuf (rxvt_t* r, int page){    assert( PVTS(r, page)->cmdbuf_base <= PVTS(r, page)->cmdbuf_endp );    if(	  IS_NULL( PVTS(r, page)->cmdbuf_escstart )		    &&	  PVTS(r, page)->cmdbuf_ptr == PVTS(r, page)->cmdbuf_endp      )    {	/*	 * If there is no data in the buffer, reset it to the beginning	 * of the buffer.	 */	PVTS(r, page)->cmdbuf_ptr   = PVTS(r, page)->cmdbuf_endp				    = PVTS(r, page)->cmdbuf_base;    }    else if(	     (PVTS(r, page)->cmdbuf_endp - PVTS(r, page)->cmdbuf_base)		== (BUFSIZ-1)						 &&	     (	       PVTS(r, page)->cmdbuf_escstart ?		(PVTS(r, page)->cmdbuf_escstart > PVTS(r,page)->cmdbuf_base) :		(PVTS(r, page)->cmdbuf_ptr > PVTS(r, page)->cmdbuf_base)	     )	   )    {	/*	 * If there is space at beginning of the buffer, but not space at the	 * end of the buffer, move the content of buffer forward to free space	 */	unsigned char	*start;	unsigned int	n, len;	start = PVTS(r, page)->cmdbuf_escstart ?	    PVTS(r, page)->cmdbuf_escstart : PVTS(r, page)->cmdbuf_ptr;	n   = start - PVTS(r, page)->cmdbuf_base;	len = PVTS(r, page)->cmdbuf_endp - start;	assert( n == BUFSIZ - 1 - len );	assert( start < PVTS(r, page)->cmdbuf_endp );	MEMMOVE( PVTS(r, page)->cmdbuf_base, start, len );	PVTS(r, page)->cmdbuf_ptr   -= n;	PVTS(r, page)->cmdbuf_endp  -= n;	if( PVTS(r, page)->cmdbuf_escstart )	    PVTS(r, page)->cmdbuf_escstart -= n;	if( PVTS(r, page)->cmdbuf_escfail )	    PVTS(r, page)->cmdbuf_escfail -= n;    }}/* * This function returns the number of bytes being read from a child *//* INTPROTO */intrxvt_read_child_cmdfd (rxvt_t* r, int page, unsigned int count){    int		    n = 0, bread = 0;    struct	    timeval  tp;    while( count )    {	int readErrno;	rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND,  "read maximal %u bytes\n", count));	/*	 * 2006-08-23 gi1242: O_NDELAY is set here, so we need not worry about	 * calls to read() blocking.	 */	errno = PVTS(r, page)->gotEIO = 0;	n = read( PVTS(r, page)->cmd_fd, PVTS(r, page)->cmdbuf_endp, count );	readErrno = errno;	rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND,  "read %d bytes\n", n));	if (n > 0)	{	    /* Update count and buffer pointer */	    count -= n;	    bread += n;	    PVTS(r, page)->cmdbuf_endp += n;	}	else if (0 == n)	{	    /* rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND,  "Should not happen?\n")); */	    /* 2006-08-23 gi1242: Could happen if we have no more data. */	    break;	}	else /* if (n < 0) */	{	    /*	     * We do not update count and buffer pointer and continue	     * trying read more data in the next loop iteration.	     */	    rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND,  "%s\n", strerror(readErrno)));	    assert( readErrno != EBADF && readErrno != EFAULT &&		    readErrno != EISDIR );	    /* See if this process is dead */	    switch (readErrno)	    {		case EIO:		    r->gotEIO = PVTS(r, page)->gotEIO = 1;		case EINTR:		    rxvt_mark_dead_childs(r);		    break;	    }	    /*	     * 2006-08-31 gi1242: Old code would only break out on EAGAIN or	     * EINVAL.	     */	    break;	}    }	/* while (count) */    if (bread != 0)    {	gettimeofday( &tp, NULL);	rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND,		    "output produced on epoch %i\n", tp.tv_sec));    }    PVTS(r, page)->monitor_nbytes_read += bread;    PVTS(r, page)->nbytes_last_read = bread;    return bread;}/* INTPROTO */voidrxvt_monitor_tab(rxvt_t* r,int i){    struct timeval  tp;    struct timeval  monitor_timeout_time;    short  execute_action = 0;    int	   monitor_timeout = 2000;        /* return, if no monitoring is activated */    if ((IS_NULL(&PVTS(r, i)->monitor_tab)) || 	(PVTS(r, i)->monitor_tab == TAB_MON_OFF) ||	(PVTS(r, i)->monitor_tab == TAB_MON_NOTIFICATION))	return;    monitor_timeout_time = PVTS(r, i)->monitor_start;    /* set configured monitor_timeout milliseconds , if configured */    if( r->h->rs[Rs_monitorTimeout] )	monitor_timeout = atoi( r->h->rs[Rs_monitorTimeout] );    monitor_timeout_time.tv_sec += (int) monitor_timeout/1000;    monitor_timeout_time.tv_usec +=	(monitor_timeout - (((int) monitor_timeout/1000) * 1000)) * 1000;    /* get current epoch time */    gettimeofday( &tp, NULL);    /* monitor-type "AUTO" : determine which type of monitoring is needed */    if ((PVTS(r, i)->monitor_tab == TAB_MON_AUTO) && 	(timercmp(&monitor_timeout_time,&tp, <)))    {	if(PVTS(r, i)->monitor_nbytes_read > 0)	{	    PVTS(r, i)->monitor_tab = TAB_MON_INACTIVITY;	    rxvt_msg (DBG_INFO, DBG_MACROS,		    "Macro MonitorTab: decided to monitor inactivity on tab %i",		    i);	}	else	{	    PVTS(r, i)->monitor_tab = TAB_MON_ACTIVITY;	    rxvt_msg (DBG_INFO, DBG_MACROS,  	       "Macro MonitorTab: decided to monitor activity on tab %i", i);	}	PVTS(r, i)->monitor_nbytes_read = 0 ;	PVTS(r, i)->monitor_start = tp;    }    /* monitor-type "INACTIVITY" : detect inactivity */    else if ((PVTS(r, i)->monitor_tab == TAB_MON_INACTIVITY) &&	    (timercmp(&monitor_timeout_time,&tp, <)))    {	/* inactivity detected */	if (PVTS( r, i)->monitor_nbytes_read == 0)	{	    rxvt_msg (DBG_INFO, DBG_MACROS,		    "Macro MonitorTab: detected inactivity on tab %i", i);	    execute_action = 1;	}	/* activity detected, restarting monitoring */	else	{	    rxvt_msg (DBG_DEBUG, DBG_MACROS,		    "Macro MonitorTab: NOT detected inactivity on tab %i / %i ",		    i, PVTS(r,i)->monitor_nbytes_read);	    PVTS(r, i)->monitor_start = tp;	    PVTS(r, i)->monitor_nbytes_read = 0;	}    }    /* monitor-type "ACTIVITY" : detect activity */    else if ((PVTS(r, i)->monitor_tab == TAB_MON_ACTIVITY) &&	     (PVTS( r, i)->monitor_nbytes_read != 0))    {	rxvt_msg (DBG_INFO, DBG_MACROS,		"Macro MonitorTab: detected activity on tab %i", i);	execute_action = 1;    }    /* stop execution of this function if no activity/inactivity      * needs to be notified 

⌨️ 快捷键说明

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