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

📄 insdelchar.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	Copyright (c) 1984 AT&T	*//*	  All Rights Reserved  	*//*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*//*	The copyright notice above does not evidence any   	*//*	actual or intended publication of such source code.	*/#ifndef lintstatic	char sccsid[] = "@(#)insdelchar.c 1.1 92/07/30 SMI"; /* from S5R3 1.4.1.1 */#endif/* * Modify current screen line 'old' to match desired line 'new'. * 'ln' is the line number on the screen. * x x:set tabstop=4 shiftwidth=4: */#include "curses.ext"#define min(a,b) ((a)<(b) ? (a) : (b))#define max(a,b) ((a)>(b) ? (a) : (b))/* Macros for costs to insert and delete nchars on this terminal */#define costic(nchars) (_cost(icfixed) + ((nchars)*_cost(icvar)) )#define costdc(nchars) (_cost(dcfixed) + _cost(dcvar)*nchars)#define CHECKSTEP 10	/* Check every # chars for match */#define MINDIFF    8	/* Don't use I/D if < # chars different */static char chardiff[256];static int shift[50], low[50], high[50], matchcount;static chtype *nb, *ob;static char *cp;static int maxlen, olen, nlen;static int movecost = 0, firstnonblank, firstdiff;static chtype nullline[] = {0, 0};#ifdef DEBUGstatic int call_time = 0;#endif /* DEBUG */_id_char (old, new, ln)register struct line   *old, *new;int ln;{	register int ur;	matchcount = 0;	/* Quick checks for empty lines. */	if (old) {		olen = old->length; ob = old->body;	} else {		olen = 0; ob = nullline;	}	if (new) {		nlen = new->length; nb = new->body;	} else {		nlen = 0; nb = nullline;	}	if (nlen <= 0) {		if (olen > 0)			_clrline(ln,ob,olen);		return;	}	maxlen = max(olen, nlen);#ifdef DEBUG	if (outf) {		fprintf(outf, "time %d\n", ++call_time);		_dump_idc(old, new, ln);	}#endif	if (movecost == 0) {		register int i, j;		i = _cost(Cursor_address);		j = _cost(Parm_right_cursor);		movecost = _cost(Column_address);		if (i < movecost) movecost = i;		if (j < movecost) movecost = j;	}	/*	 * If any of these functions returns non-zero, punt and be quick	 * about it. This handles many common cases with little overhead.	 */	if ((ur = _idc_flag_uneq()) || _idc_findmatch() || _idc_costs()) {		if (ur >= 0)			_idc_repchar(old, ln);		return;	}	/* Do the fancy ins/del char stuff */#ifdef DEBUG	_idc_delchar(old, new, ln);	_idc_inschar(old, new, ln);#else	_idc_delchar(old, ln);	_idc_inschar(old, ln);#endif /* DEBUG */	_chk_typeahead();}/* * Find chars that line up exactly in new and old lines. * Return 1 iff insert/delete should be avoided.  Return * -1 if the lines are identical, for immediate return. * * The variables set below are: * * given line old:|    abcdefghijklm *   and line new:|          ghijktuvwxyz * we get: *                |                ^ minlen = 13 = minimum length *                |                     ^ maxlen = 18 = maximum length *                |    ^ firstdiff = 0 = 1st char diff between 2 lines *                |          ^ firstnonblank = 6 = 1st non-blank in new line *                |    ^^^^^^     ^^^ seen = 8 = count diffs btw. 2 lines *                |               ^^^ nbseen = 3 = count diffs after firstnonblank *                |0000111111000001111111 <- chardiff * * chardiff[] is used by _idc_findmatch(), _idc_costs(), _idc_delchar() and * _idc_inschar(). firstdiff and firstnonblank are used by _idc_repchar(). * */static_idc_flag_uneq(){	register int j, seen = 0, nbseen = 0;	register chtype *p = ob, *q = nb;	register int minlen = olen + nlen - maxlen;	/* nothing on old line? */	if (olen <= 0) {		for (firstdiff = 0;		     (*q++ == ' ') && (firstdiff < minlen);		     firstdiff++)			;		firstnonblank = firstdiff;		return 1;	}	/* find first non-blank; fill in chardiff[] & seen */	cp = chardiff;	for (j = minlen; (j > 0) && (*q == ' '); j--)		if (*cp++ = (*p++ != *q++))			seen++;	firstnonblank = minlen - j;	/* continue with chardiff[] & seen & nbseen */	for ( ; j>0; j--)		if (*cp++ = (*p++ != *q++))			seen++, nbseen++;	/* are the lines the same? */	if (seen == 0 && olen == nlen)		return -1;	/* Lines are identical */	/* find the first difference */	if (seen == 0)		firstdiff = minlen;	else for (j = 0; j < minlen; j++)		if (chardiff[j]) {			firstdiff = j;			break;		}	/* continue with chardiff[] */	for (j=maxlen-minlen; j>0; j--)		*cp++ = 1;	if (olen != nlen)		seen++, nbseen++;#ifdef DEBUG	if (outf) {		fprintf(outf, "chardiff:           ");	/* line up with _dump_idc */		for (j = 0; j < maxlen; j++)			fprintf(outf, chardiff[j] ? "^" : ".");		fprintf(outf, "\n");		fprintf(outf, "maxlen = %d\n", maxlen);	}#endif /* DEBUG */	/* are lines similar enough? */	if (seen < MINDIFF || nbseen < MINDIFF) {#ifdef DEBUG		if(outf) fprintf(outf, "noid because diffs seen (%d) < MINDIFF %d, or diffs seen after first nonblank (%d after %d) < MINDIFF\n", seen, MINDIFF, nbseen, firstnonblank);#endif		return 1;	}	return 0;}/* * Find matching parts in the new and old lines. * Return 1 iff insert/delete should be avoided. * * As an example, consider the following case of old and new lines. The * booleans set in chardiff[] denoting differing characters are indicated * with a '^'. * * old:   79 SEND: Send all messages to recipients and of the messageABC23456789| PUSH ENTER * new:   79 SEND: Send the message to all recipients the message center23456789| PUSH ENTER *           0    +    1    +    2    +    3    +    4    +    5    +    6    +    7    + * chardiff: ...........^^^........^^^^^^^^^^^^^^^^^^^^^^.^^^^^^^^^^^^^^.................... * * The output from this routine is the set of arrays low, high and shift. * The low and high arrays indicate groups of characters in the new line * which match groups of characters in the old line. If it takes an * insertion or deletion to make the groups match, the distance away is * indicated by the shift value. The corresponding low and high columns from * the old line are gotten from subtracting the shift value for that group. * Characters between the groups will be overstruck. The values of low, * high and shift for this example is given here. The corresponding low * and high columns from the old line are indicated by the olow and ohigh * columns. * *    i   low   high    shift   olow    ohigh *    0   -1    -1      0       -1      -1 *    1   0     10      0       0       10 *    2   29    40      3       26      37 *    3   41    51      -4      45      55 *    4   59    78      0       59      78 *    5   79    79      0       79      79 * * Group 1, columns 0-10 from old "SEND: Send " match columns 0-10 from new. * Group 1-2, columns 11-25 from old "all messages to" will be overstruck *    with "the message to ". * Group 2, columns 26-37 from old " recipients " match new columns 29-40 *    " recipients ". The old must be shifted right 3 columns by deleting *    "and" from the end of old and inserting "all" at the beginning. * Group 2-3, there is nothing to overstrike between. * Group 3, columns 45-55 from old "the message" match new columns 41-51 *    "the message". The old must be shifted left 4 columns by deleting *    "the ". * Group 3-4, columns 52-58. After making the above deletions, the old *    "ABC" will be above the new " cen", which must be overstruck *    followed by an insertion of "ter". * Group 4, at this point columns 59-78 of old "23456789| PUSH ENTER" will *    match columns 59-78 of new "23456789| PUSH ENTER" and the line is *    done. * Groups 0 and 5 act as sentinels during the algorithms. */static_idc_findmatch(){	register int k, h, l;	register int nhub, ohub, nb_nhub;	register chtype *chp;	int ostart, highwat;	/* Search for matches */	shift[0] = 0; low[0] = high[0] = -1; matchcount = 1; highwat = 0;	/* Look for ohub code matching nhub, stepping nhub through by CHECKSTEP. */	for (nhub=0; nhub<nlen; nhub += CHECKSTEP) {		/* ohub value for where to start looking */		ostart = chardiff[nhub] ? highwat : nhub;		/*		 * This loop is likely to burn most of the CPU time, hence		 * extra effort is taken to make it run quickly.		 */		nb_nhub = nb[nhub];	/* constant within loop */		for (chp=ob+ostart,ohub=ostart; ohub<olen; ohub++) {			if (nb_nhub == *chp++ /*ob[ohub]*/) {				/*				 * Found a possible match.  See how far in				 * both directions it goes.  The double loops				 * are a speed trick.  This is really ugly,				 * but has to be very fast.				 */				/* to the left .. */				if (nhub <= ohub) {					for (l=nhub,k=ohub; l>=0 && nb[l]==ob[k]; l--,k--)						;				} else {					for (l=nhub,k=ohub; k>=0 && nb[l]==ob[k]; l--,k--)						;				}				l++;				if (l < 0)					l = 0;				/* .. and the right */				if (nhub >= ohub) {					for (h=nhub,k=ohub; h<maxlen && nb[h]==ob[k]; h++,k++)						;				} else {					for (h=nhub,k=ohub; k<maxlen && nb[h]==ob[k]; h++,k++)						;				}				h--;				if (h >= maxlen)					h = maxlen - 1;				if (h-l > MINDIFF) {	/* Count if at least MINDIFF long */					int s = nhub-ohub;		/* amount shifted */					int oh;				/* old high value */					/* Maybe this match includes the previous match */					if (l <= low[matchcount-1])						matchcount--;					/* If we overlap, do not count that part */					if (l <= high[matchcount-1])						l = high[matchcount-1] + 1;					/* Cannot overlap in the old part, either */					oh = high[matchcount-1] - shift[matchcount-1];					if (l - s <= oh)						l = oh + s + 1;					/* Record high, low, nhub, ohub in list of matches */					high[matchcount] = h;					low[matchcount] = l;					shift[matchcount++] = s;					highwat = h - s + 2;					nhub = highwat;					break;				}			}		}	}	shift[matchcount] = 0; low[matchcount] = high[matchcount] = maxlen;#ifdef DEBUG	if (outf) {		fprintf(outf, "matchcount = %d\n", matchcount);		_dump_shift((struct line *)0, (struct line *)0, 0, 0, "", 0);	}#endif	return matchcount <= 1;}/* * Calculate the approximate costs with and without insert/delete char. * Return 1 iff insert/delete should be avoided. * * The cost NOT using insert/delete is derived from the chardiff[] * array. Groups of characters that are different would have to be * overstruck. Groups of characters that are the same would be skipped * over using cursor_address, parm_right_cursor or column_address. * * Similarly, the cost using insert/delete also includes the cost to * insert or delete characters from the ends of the groups. */static_idc_costs(){	register int i, j, k;	register int cid, cnoid;	cid = 0;	if (low[1] > 0)		cid += movecost + low[1];	for (i=1; i<matchcount; i++) {		j = shift[i] - shift[i-1];		k = (j==0) ? 0 : (j<0) ? costdc(-j) : costic(j);		if (j || (low[i+1] > high[i] + 1)) {			cid += movecost +	/* to get cursor there */				k +				/* i/d char cost */				(low[i+1]-high[i] - 1);		/* cost to redraw next diff */#ifdef DEBUG			if (outf) fprintf(outf, "i %d, add %d + %d + %d for %d\n", i,				movecost , k, (low[i+1]-high[i] - 1) , cid);#endif		}	}	cnoid = 0;	for (i=0; i<nlen; i++)		if (chardiff[i]) {			cnoid++;			if (!chardiff[i-1])				cnoid += movecost;		}	if (nlen < maxlen)		cnoid += _cost(Clr_eol);#ifdef DEBUG	if (outf)		fprintf(outf, "costid %d, costnoid %d, noid %d\n", cid, cnoid, cnoid <= cid);#endif	return cnoid <= cid;}/* * Simple replacement strategy, not using insert/delete char. * _clrbol() gets rid of any leading blanks and * showstring does all the replacement work. */static_idc_repchar(old, ln)register struct line *old;{#ifdef DEBUG	if (outf)		fprintf(outf, "doing simple replace char, starting at col %d with blanks to col %d\n", firstdiff, firstnonblank);#endif	firstdiff = _clrbol(firstnonblank, firstdiff, ln, ob);	/* no need to blank out blanks */	if (firstdiff == olen && nb[firstdiff] == ' ')		while (nb[++firstdiff] == ' ')			;	/* Avoid extra cursor motion to left margin or to same text *//* - untested	while ((chardiff[firstdiff] == 0) && (firstdiff < minlen))		firstdiff++;*/	_pos(ln, firstdiff);	_showstring(ln, firstdiff, nb+firstdiff, nb+nlen-1, old);	if (nlen < maxlen) {		_pos(ln, nlen);		_clreol();	}	_chk_typeahead();}/* * Ins/del char update strategy.  Do all deletions first to avoid * losing text from right edge of screen. */#ifdef DEBUGstatic_idc_delchar(old, new, ln)register struct line *old, *new;#elsestatic_idc_delchar(old, ln)register struct line *old;#endif /* DEBUG */{	register int i, l, oh_im1_p1, k;	register chtype *p, *q, *r;	int hi_im1, shif_im1, j;#ifdef DEBUG	if (outf) fprintf(outf, "doing delete chars\n");#endif	/* Do the deletions */	for (i=1; i<matchcount; i++) {#ifdef DEBUG		if (outf) fprintf(outf, "comparing shift[i=%d] = %d to shift[i-1=%d] = %d.\n", i, shift[i], i-1, shift[i-1]);#endif /* DEBUG */		if (shift[i] < shift[i-1]) {		/* If it is a deletion */			/*			 * Overall strategy: there are two possibilities:			 * the previous area is about to be shifted off			 * the right end, so that we need to delete something			 * from the end of that area, or we are in a region			 * that needs to have text removed from the			 * beginning. Both may occur together.			 *			 * In the first case, in which shift[i-1] > 0,			 * we move to the end of the previous area and			 * delete the extra characters.			 *			 *    QfghijkAB			 *    QdefghiAB			 *			 * In the above example, the "jk" needs to be			 * deleted so that the "de" may be inserted later			 * in the insert routine.			 *			 * In the second case, there are two parts:			 * first overstrike things that do not need to			 * be deleted, then delete the rest.			 *			 *    Q d e f g h i A B		new			 *    Q w x y z A B		old			 *			 * In the above example, we overstrike the "wxyz"			 * over the old "defg", then delete the old "hi".			 *			 * If both cases occur together, we move to the			 * end of the previous area and do the overstrikes			 * there. Then both sets of character deletions			 * get done together.			 *			 * In both cases, shift[i-1]-shift[i] will be the			 * number of characters to be deleted, and			 * low[i] - high[i-1] + 1 will be the number of			 * characters to be overstruck.			 */			hi_im1 = high[i-1];			shif_im1 = shift[i-1];			oh_im1_p1 = hi_im1 - shif_im1 + 1;/* old start col (ohigh[i-1]+1)*/			/* output overstrike part */			p = nb + hi_im1 + 1;			q = nb + low[i] - 1;			/* number overstruck = low[i] - high[i-1] + 1 */			if (p <= q) {#ifdef DEBUG				if (outf) fprintf(outf, "del-overstriking %d chars at column %d\n", q - p + 1, oh_im1_p1);#endif /* DEBUG */				_pos(ln, oh_im1_p1);				_showstring(ln, oh_im1_p1, p, q, old);				/* update internal copy of screen */				r = ob + oh_im1_p1;				oh_im1_p1 += q - p + 1;				while (p <= q)	/* update old buffer */					*r++ = *p++;#ifdef DEBUG				_dump_shift(old, new, ln, 1, "del-replacement", i);#endif /* DEBUG */			}			if (shif_im1 > 0)	/* position to delete */				l = oh_im1_p1;			else				l = low[i];

⌨️ 快捷键说明

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