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

📄 svi_smap.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1993, 1994 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)svi_smap.c	8.39 (Berkeley) 4/13/94";#endif /* not lint */#include <sys/types.h>#include <sys/queue.h>#include <sys/time.h>#include <bitstring.h>#include <limits.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <termios.h>#include "compat.h"#include <curses.h>#include <db.h>#include <regex.h>#include "vi.h"#include "vcmd.h"#include "svi_screen.h"static int	svi_deleteln __P((SCR *, int));static int	svi_insertln __P((SCR *, int));static int	svi_sm_delete __P((SCR *, EXF *, recno_t));static int	svi_sm_insert __P((SCR *, EXF *, recno_t));static int	svi_sm_reset __P((SCR *, EXF *, recno_t));/* * svi_change -- *	Make a change to the screen. */intsvi_change(sp, ep, lno, op)	SCR *sp;	EXF *ep;	recno_t lno;	enum operation op;{	SMAP *p;	size_t oldy, oldx;	/* Appending is the same as inserting, if the line is incremented. */	if (op == LINE_APPEND) {		++lno;		op = LINE_INSERT;	}	/* Ignore the change if the line is after the map. */	if (lno > TMAP->lno)		return (0);	/*	 * If the line is before the map, and it's a decrement, decrement	 * the map.  If it's an increment, increment the map.  Otherwise,	 * ignore it.	 */	if (lno < HMAP->lno) {		switch (op) {		case LINE_APPEND:			abort();			/* NOTREACHED */		case LINE_DELETE:			for (p = HMAP; p <= TMAP; ++p)				--p->lno;			if (sp->lno >= lno)				--sp->lno;			F_SET(sp, S_RENUMBER);			break;		case LINE_INSERT:			for (p = HMAP; p <= TMAP; ++p)				++p->lno;			if (sp->lno >= lno)				++sp->lno;			F_SET(sp, S_RENUMBER);			break;		case LINE_RESET:			break;		}		return (0);	}	F_SET(SVP(sp), SVI_SCREENDIRTY);	/* Invalidate the cursor, if it's on this line. */	if (sp->lno == lno)		F_SET(SVP(sp), SVI_CUR_INVALID);	/* Invalidate the line size cache. */	SVI_SCR_CFLUSH(SVP(sp));	getyx(stdscr, oldy, oldx);	switch (op) {	case LINE_DELETE:		if (svi_sm_delete(sp, ep, lno))			return (1);		F_SET(sp, S_RENUMBER);		break;	case LINE_INSERT:		if (svi_sm_insert(sp, ep, lno))			return (1);		F_SET(sp, S_RENUMBER);		break;	case LINE_RESET:		if (svi_sm_reset(sp, ep, lno))			return (1);		break;	default:		abort();	}	MOVEA(sp, oldy, oldx);	return (0);}/* * svi_sm_fill -- *	Fill in the screen map, placing the specified line at the *	right position.  There isn't any way to tell if an SMAP *	entry has been filled in, so this routine had better be *	called with P_FILL set before anything else is done. * * !!! * Unexported interface: if lno is OOBLNO, P_TOP means that the HMAP * slot is already filled in, P_BOTTOM means that the TMAP slot is * already filled in, and we just finish up the job. */intsvi_sm_fill(sp, ep, lno, pos)	SCR *sp;	EXF *ep;	recno_t lno;	enum position pos;{	SMAP *p, tmp;	/* Flush all cached information from the SMAP. */	for (p = HMAP; p <= TMAP; ++p)		SMAP_FLUSH(p);	switch (pos) {	case P_FILL:		tmp.lno = 1;		tmp.off = 1;		/* See if less than half a screen from the top. */		if (svi_sm_nlines(sp, ep,		    &tmp, lno, HALFTEXT(sp)) <= HALFTEXT(sp)) {			lno = 1;			goto top;		}		/* See if less than half a screen from the bottom. */		if (file_lline(sp, ep, &tmp.lno))			return (1);		if (!O_ISSET(sp, O_LEFTRIGHT))			tmp.off = svi_opt_screens(sp, ep, tmp.lno, NULL);		if (svi_sm_nlines(sp, ep,		    &tmp, lno, HALFTEXT(sp)) <= HALFTEXT(sp)) {			TMAP->lno = tmp.lno;			if (!O_ISSET(sp, O_LEFTRIGHT))				TMAP->off = tmp.off;			goto bottom;		}		goto middle;	case P_TOP:		if (lno != OOBLNO) {top:			HMAP->lno = lno;			HMAP->off = 1;		}		/* If we fail, just punt. */		for (p = HMAP; p < TMAP; ++p)			if (svi_sm_next(sp, ep, p, p + 1))				goto err;		break;	case P_MIDDLE:		/* If we fail, guess that the file is too small. */middle:		p = HMAP + (TMAP - HMAP) / 2;		for (p->lno = lno, p->off = 1; p > HMAP; --p)			if (svi_sm_prev(sp, ep, p, p - 1)) {				lno = 1;				goto top;			}		/* If we fail, just punt. */		p = HMAP + (TMAP - HMAP) / 2;		for (; p < TMAP; ++p)			if (svi_sm_next(sp, ep, p, p + 1))				goto err;		break;	case P_BOTTOM:		if (lno != OOBLNO) {			TMAP->lno = lno;			if (!O_ISSET(sp, O_LEFTRIGHT))				TMAP->off = svi_opt_screens(sp, ep, lno, NULL);		}		/* If we fail, guess that the file is too small. */bottom:		for (p = TMAP; p > HMAP; --p)			if (svi_sm_prev(sp, ep, p, p - 1)) {				lno = 1;				goto top;			}		break;	}	return (0);	/*	 * Try and put *something* on the screen.  If this fails,	 * we have a serious hard error.	 */err:	HMAP->lno = 1;	HMAP->off = 1;	for (p = HMAP; p < TMAP; ++p)		if (svi_sm_next(sp, ep, p, p + 1))			return (1);	return (0);}/* * For the routines svi_sm_reset, svi_sm_delete and svi_sm_insert: if the * screen only contains one line, or, if the line is the entire screen, this * gets fairly exciting.  Skip the fun and simply return if there's only one * line in the screen, or just call fill.  Fill may not be entirely accurate, * i.e. we may be painting the screen with something not even close to the * cursor, but it's not like we're into serious performance issues here, and * the refresh routine will fix it for us. */#define	TOO_WEIRD {							\	if (cnt_orig >= sp->t_rows) {					\		if (cnt_orig == 1)					\			return (0);					\		if (file_gline(sp, ep, lno, NULL) == NULL)		\			if (file_lline(sp, ep, &lno))			\				return (1);				\		F_SET(sp, S_REDRAW);					\		return (svi_sm_fill(sp, ep, lno, P_TOP));		\	}								\}/* * svi_sm_delete -- *	Delete a line out of the SMAP. */static intsvi_sm_delete(sp, ep, lno)	SCR *sp;	EXF *ep;	recno_t lno;{	SMAP *p, *t;	size_t cnt_orig;	/*	 * Find the line in the map, and count the number of screen lines	 * which display any part of the deleted line.	 */	for (p = HMAP; p->lno != lno; ++p);	if (O_ISSET(sp, O_LEFTRIGHT))		cnt_orig = 1;	else		for (cnt_orig = 1, t = p + 1;		    t <= TMAP && t->lno == lno; ++cnt_orig, ++t);	TOO_WEIRD;	/* Delete that many lines from the screen. */	MOVE(sp, p - HMAP, 0);	if (svi_deleteln(sp, cnt_orig))		return (1);	/* Shift the screen map up. */	memmove(p, p + cnt_orig, (((TMAP - p) - cnt_orig) + 1) * sizeof(SMAP));	/* Decrement the line numbers for the rest of the map. */	for (t = TMAP - cnt_orig; p <= t; ++p)		--p->lno;	/* Display the new lines. */	for (p = TMAP - cnt_orig;;) {		if (p < TMAP && svi_sm_next(sp, ep, p, p + 1))			return (1);		/* svi_sm_next() flushed the cache. */		if (svi_line(sp, ep, ++p, NULL, NULL))			return (1);		if (p == TMAP)			break;	}	return (0);}/* * svi_sm_insert -- *	Insert a line into the SMAP. */static intsvi_sm_insert(sp, ep, lno)	SCR *sp;	EXF *ep;	recno_t lno;{	SMAP *p, *t;	size_t cnt_orig, cnt;	/*	 * Find the line in the map, find out how many screen lines	 * needed to display the line.	 */	for (p = HMAP; p->lno != lno; ++p);	if (O_ISSET(sp, O_LEFTRIGHT))		cnt_orig = 1;	else		cnt_orig = svi_opt_screens(sp, ep, lno, NULL);	TOO_WEIRD;	/*	 * The lines left in the screen override the number of screen	 * lines in the inserted line.	 */	cnt = (TMAP - p) + 1;	if (cnt_orig > cnt)		cnt_orig = cnt;	/* Push down that many lines. */	MOVE(sp, p - HMAP, 0);	if (svi_insertln(sp, cnt_orig))		return (1);	/* Shift the screen map down. */	memmove(p + cnt_orig, p, (((TMAP - p) - cnt_orig) + 1) * sizeof(SMAP));	/* Increment the line numbers for the rest of the map. */	for (t = p + cnt_orig; t <= TMAP; ++t)		++t->lno;	/* Fill in the SMAP for the new lines, and display. */	for (cnt = 1, t = p; cnt <= cnt_orig; ++t, ++cnt) {		t->lno = lno;		t->off = cnt;		SMAP_FLUSH(t);		if (svi_line(sp, ep, t, NULL, NULL))			return (1);	}	return (0);}/* * svi_sm_reset -- *	Reset a line in the SMAP. */static intsvi_sm_reset(sp, ep, lno)	SCR *sp;	EXF *ep;	recno_t lno;{	SMAP *p, *t;	size_t cnt_orig, cnt_new, cnt, diff;	/*	 * See if the number of on-screen rows taken up by the old display	 * for the line is the same as the number needed for the new one.	 * If so, repaint, otherwise do it the hard way.	 */	for (p = HMAP; p->lno != lno; ++p);	if (O_ISSET(sp, O_LEFTRIGHT)) {		t = p;		cnt_orig = cnt_new = 1;	} else {		for (cnt_orig = 0,		    t = p; t <= TMAP && t->lno == lno; ++cnt_orig, ++t);		cnt_new = svi_opt_screens(sp, ep, lno, NULL);	}	TOO_WEIRD;	if (cnt_orig == cnt_new) {		do {			SMAP_FLUSH(p);			if (svi_line(sp, ep, p, NULL, NULL))				return (1);		} while (++p < t);		return (0);	}	if (cnt_orig < cnt_new) {		/* Get the difference. */		diff = cnt_new - cnt_orig;		/*		 * The lines left in the screen override the number of screen		 * lines in the inserted line.		 */		cnt = (TMAP - p) + 1;		if (diff > cnt)			diff = cnt;		/* Push down the extra lines. */		MOVE(sp, p - HMAP, 0);		if (svi_insertln(sp, diff))			return (1);		/* Shift the screen map down. */		memmove(p + diff, p, (((TMAP - p) - diff) + 1) * sizeof(SMAP));		/* Fill in the SMAP for the replaced line, and display. */		for (cnt = 1, t = p; cnt_new-- && t <= TMAP; ++t, ++cnt) {			t->lno = lno;			t->off = cnt;			SMAP_FLUSH(t);			if (svi_line(sp, ep, t, NULL, NULL))				return (1);		}	} else {		/* Get the difference. */		diff = cnt_orig - cnt_new;		/* Delete that many lines from the screen. */		MOVE(sp, p - HMAP, 0);		if (svi_deleteln(sp, diff))			return (1);		/* Shift the screen map up. */		memmove(p, p + diff, (((TMAP - p) - diff) + 1) * sizeof(SMAP));		/* Fill in the SMAP for the replaced line, and display. */		for (cnt = 1, t = p; cnt_new--; ++t, ++cnt) {			t->lno = lno;			t->off = cnt;			SMAP_FLUSH(t);			if (svi_line(sp, ep, t, NULL, NULL))				return (1);		}		/* Display the new lines at the bottom of the screen. */		for (t = TMAP - diff;;) {			if (t < TMAP && svi_sm_next(sp, ep, t, t + 1))				return (1);			/* svi_sm_next() flushed the cache. */			if (svi_line(sp, ep, ++t, NULL, NULL))				return (1);			if (t == TMAP)				break;		}	}	return (0);}/* * svi_sm_up -- *	Scroll the SMAP up count logical lines. */intsvi_sm_up(sp, ep, rp, count, cursor_move)	SCR *sp;	EXF *ep;	MARK *rp;	recno_t count;	int cursor_move;{	SMAP *p, svmap, tmp;	int ignore_cursor;	/* Set the default return position. */	rp->lno = sp->lno;	rp->cno = sp->cno;	/*	 * Invalidate the cursor.  The line is probably going to change,	 * but if cursor_move isn't set it may not.  In any case, this	 * routine moves the cursor to draw things.	 */	F_SET(SVP(sp), SVI_CUR_INVALID);	/*	 * There are two forms of this command, one where the cursor tries to	 * follow the line, and one where it doesn't.  In the latter, we try	 * and keep the cursor at the same position on the screen, but, if the	 * screen is small enough and the line length large enough, the cursor	 * can end up in very strange places.  Probably not worth fixing.	 *	 * Find the line in the SMAP -- ignore the cursor if it wasn't on the	 * screen.	 */	if (svi_sm_cursor(sp, ep, &p))		return (1);	if (p == NULL)		ignore_cursor = 1;	else {		svmap = *p;		ignore_cursor = 0;	}	/*	 * Check to see if movement is possible.  Lots of checks...	 *	 * Find out if it's possible to move past the end of the map.  If	 * that's okay because we think that we can move the cursor down	 * in the map, check to make sure that the map isn't mostly empty.	 */	if (svi_sm_next(sp, ep, TMAP, &tmp))		return (1);	if (tmp.lno > TMAP->lno &&	    !file_gline(sp, ep, tmp.lno, NULL) ||	    !O_ISSET(sp, O_LEFTRIGHT) &&	    tmp.off > svi_opt_screens(sp, ep, tmp.lno, NULL)) {		if (!cursor_move || ignore_cursor || p == TMAP) {			v_eof(sp, ep, NULL);			return (1);		}		if (svi_sm_next(sp, ep, p, &tmp))			return (1);		if (!file_gline(sp, ep, tmp.lno, NULL) ||

⌨️ 快捷键说明

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