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

📄 elog.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <cursor.h>#include <mouse.h>#include <keyboard.h>#include <frame.h>#include <fcall.h>#include <plumb.h>#include "dat.h"#include "fns.h"#include "edit.h"static char Wsequence[] = "warning: changes out of sequence\n";static int	warned = FALSE;/* * Log of changes made by editing commands.  Three reasons for this: * 1) We want addresses in commands to apply to old file, not file-in-change. * 2) It's difficult to track changes correctly as things move, e.g. ,x m$ * 3) This gives an opportunity to optimize by merging adjacent changes. * It's a little bit like the Undo/Redo log in Files, but Point 3) argues for a * separate implementation.  To do this well, we use Replace as well as * Insert and Delete */typedef struct Buflog Buflog;struct Buflog{	short	type;		/* Replace, Filename */	uint		q0;		/* location of change (unused in f) */	uint		nd;		/* # runes to delete */	uint		nr;		/* # runes in string or file name */};enum{	Buflogsize = sizeof(Buflog)/sizeof(Rune),};/* * Minstring shouldn't be very big or we will do lots of I/O for small changes. * Maxstring is RBUFSIZE so we can fbufalloc() once and not realloc elog.r. */enum{	Minstring = 16,		/* distance beneath which we merge changes */	Maxstring = RBUFSIZE,	/* maximum length of change we will merge into one */};voideloginit(File *f){	if(f->elog.type != Empty)		return;	f->elog.type = Null;	if(f->elogbuf == nil)		f->elogbuf = emalloc(sizeof(Buffer));	if(f->elog.r == nil)		f->elog.r = fbufalloc();	bufreset(f->elogbuf);}voidelogclose(File *f){	if(f->elogbuf){		bufclose(f->elogbuf);		free(f->elogbuf);		f->elogbuf = nil;	}}voidelogreset(File *f){	f->elog.type = Null;	f->elog.nd = 0;	f->elog.nr = 0;}voidelogterm(File *f){	elogreset(f);	if(f->elogbuf)		bufreset(f->elogbuf);	f->elog.type = Empty;	fbuffree(f->elog.r);	f->elog.r = nil;	warned = FALSE;}voidelogflush(File *f){	Buflog b;	b.type = f->elog.type;	b.q0 = f->elog.q0;	b.nd = f->elog.nd;	b.nr = f->elog.nr;	switch(f->elog.type){	default:		warning(nil, "unknown elog type 0x%ux\n", f->elog.type);		break;	case Null:		break;	case Insert:	case Replace:		if(f->elog.nr > 0)			bufinsert(f->elogbuf, f->elogbuf->nc, f->elog.r, f->elog.nr);		/* fall through */	case Delete:		bufinsert(f->elogbuf, f->elogbuf->nc, (Rune*)&b, Buflogsize);		break;	}	elogreset(f);}voidelogreplace(File *f, int q0, int q1, Rune *r, int nr){	uint gap;	if(q0==q1 && nr==0)		return;	eloginit(f);	if(f->elog.type!=Null && q0<f->elog.q0){		if(warned++ == 0)			warning(nil, Wsequence);		elogflush(f);	}	/* try to merge with previous */	gap = q0 - (f->elog.q0+f->elog.nd);	/* gap between previous and this */	if(f->elog.type==Replace && f->elog.nr+gap+nr<Maxstring){		if(gap < Minstring){			if(gap > 0){				bufread(f, f->elog.q0+f->elog.nd, f->elog.r+f->elog.nr, gap);				f->elog.nr += gap;			}			f->elog.nd += gap + q1-q0;			runemove(f->elog.r+f->elog.nr, r, nr);			f->elog.nr += nr;			return;		}	}	elogflush(f);	f->elog.type = Replace;	f->elog.q0 = q0;	f->elog.nd = q1-q0;	f->elog.nr = nr;	if(nr > RBUFSIZE)		editerror("internal error: replacement string too large(%d)", nr);	runemove(f->elog.r, r, nr);}voideloginsert(File *f, int q0, Rune *r, int nr){	int n;	if(nr == 0)		return;	eloginit(f);	if(f->elog.type!=Null && q0<f->elog.q0){		if(warned++ == 0)			warning(nil, Wsequence);		elogflush(f);	}	/* try to merge with previous */	if(f->elog.type==Insert && q0==f->elog.q0 && f->elog.nr+nr<Maxstring){		runemove(f->elog.r+f->elog.nr, r, nr);		f->elog.nr += nr;		return;	}	while(nr > 0){		elogflush(f);		f->elog.type = Insert;		f->elog.q0 = q0;		n = nr;		if(n > RBUFSIZE)			n = RBUFSIZE;		f->elog.nr = n;		runemove(f->elog.r, r, n);		r += n;		nr -= n;	}}voidelogdelete(File *f, int q0, int q1){	if(q0 == q1)		return;	eloginit(f);	if(f->elog.type!=Null && q0<f->elog.q0+f->elog.nd){		if(warned++ == 0)			warning(nil, Wsequence);		elogflush(f);	}	/* try to merge with previous */	if(f->elog.type==Delete && f->elog.q0+f->elog.nd==q0){		f->elog.nd += q1-q0;		return;	}	elogflush(f);	f->elog.type = Delete;	f->elog.q0 = q0;	f->elog.nd = q1-q0;}#define tracelog 0voidelogapply(File *f){	Buflog b;	Rune *buf;	uint i, n, up, mod;	uint tq0, tq1;	Buffer *log;	Text *t;	elogflush(f);	log = f->elogbuf;	t = f->curtext;	buf = fbufalloc();	mod = FALSE;	/*	 * The edit commands have already updated the selection in t->q0, t->q1,	 * but using coordinates relative to the unmodified buffer.  As we apply the log,	 * we have to update the coordinates to be relative to the modified buffer.	 * Textinsert and textdelete will do this for us; our only work is to apply the	 * convention that an insertion at t->q0==t->q1 is intended to select the 	 * inserted text.	 */	/*	 * We constrain the addresses in here (with textconstrain()) because	 * overlapping changes will generate bogus addresses.   We will warn	 * about changes out of sequence but proceed anyway; here we must	 * keep things in range.	 */	while(log->nc > 0){		up = log->nc-Buflogsize;		bufread(log, up, (Rune*)&b, Buflogsize);		switch(b.type){		default:			fprint(2, "elogapply: 0x%ux\n", b.type);			abort();			break;		case Replace:			if(tracelog)				warning(nil, "elog replace %d %d (%d %d)\n",					b.q0, b.q0+b.nd, t->q0, t->q1);			if(!mod){				mod = TRUE;				filemark(f);			}			textconstrain(t, b.q0, b.q0+b.nd, &tq0, &tq1);			textdelete(t, tq0, tq1, TRUE);			up -= b.nr;			for(i=0; i<b.nr; i+=n){				n = b.nr - i;				if(n > RBUFSIZE)					n = RBUFSIZE;				bufread(log, up+i, buf, n);				textinsert(t, tq0+i, buf, n, TRUE);			}			if(t->q0 == b.q0 && t->q1 == b.q0)				t->q1 += b.nr;			break;		case Delete:			if(tracelog)				warning(nil, "elog delete %d %d (%d %d)\n",					b.q0, b.q0+b.nd, t->q0, t->q1);			if(!mod){				mod = TRUE;				filemark(f);			}			textconstrain(t, b.q0, b.q0+b.nd, &tq0, &tq1);			textdelete(t, tq0, tq1, TRUE);			break;		case Insert:			if(tracelog)				warning(nil, "elog insert %d %d (%d %d)\n",					b.q0, b.q0+b.nr, t->q0, t->q1);			if(!mod){				mod = TRUE;				filemark(f);			}			textconstrain(t, b.q0, b.q0, &tq0, &tq1);			up -= b.nr;			for(i=0; i<b.nr; i+=n){				n = b.nr - i;				if(n > RBUFSIZE)					n = RBUFSIZE;				bufread(log, up+i, buf, n);				textinsert(t, tq0+i, buf, n, TRUE);			}			if(t->q0 == b.q0 && t->q1 == b.q0)				t->q1 += b.nr;			break;/*		case Filename:			f->seq = u.seq;			fileunsetname(f, epsilon);			f->mod = u.mod;			up -= u.n;			free(f->name);			if(u.n == 0)				f->name = nil;			else				f->name = runemalloc(u.n);			bufread(delta, up, f->name, u.n);			f->nname = u.n;			break;*/		}		bufdelete(log, up, log->nc);	}	fbuffree(buf);	elogterm(f);	/*	 * Bad addresses will cause bufload to crash, so double check.	 * If changes were out of order, we expect problems so don't complain further.	 */	if(t->q0 > f->nc || t->q1 > f->nc || t->q0 > t->q1){		if(!warned)			warning(nil, "elogapply: can't happen %d %d %d\n", t->q0, t->q1, f->nc);		t->q1 = min(t->q1, f->nc);		t->q0 = min(t->q0, t->q1);	}}

⌨️ 快捷键说明

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