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

📄 sequence.cpp

📁 支持Unicode及Uniscribe的多语言输入的文本编辑器源码。
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
	sequence.cpp

	data-sequence class

	Copyright J Brown 1999-2006
	www.catch22.net

	Freeware
*/
#include <windows.h>
#include <stdarg.h>
#include <stdio.h>
#include "sequence.h"

#ifdef DEBUG_SEQUENCE

char debugfile[_MAX_PATH];
void odebug(const char *fmt, ...)
{
	va_list varg;
	va_start(varg, fmt);
	char buf[512];

	vsprintf(buf, fmt, varg);
	OutputDebugString(buf);

	va_end(varg);
}

void debug(const char *fmt, ...)
{
	FILE *fp;
	va_list varg;
	va_start(varg, fmt);

	if((fp = fopen(debugfile, "a")) != 0)
	{
		vfprintf(fp, fmt, varg);
		fclose(fp);
	}

	va_end(varg);
}

#else
#define debug
#define odebug
#endif


sequence::sequence ()
{
	record_action(action_invalid, 0);
	
	head = tail		= 0;
	sequence_length = 0;
	group_id		= 0;
	group_refcount	= 0;

	head			= new span(0, 0, 0);
	tail			= new span(0, 0, 0);
	head->next		= tail;
	tail->prev		= head;

#ifdef DEBUG_SEQUENCE
	SYSTEMTIME st;
	GetLocalTime(&st);
	sprintf(debugfile, "seqlog-%04d%02d%02d-%02d%02d%0d.txt", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
#endif
}

sequence::~sequence ()
{
	clear();

	delete head;
	delete tail;
}

bool sequence::init ()
{
	sequence_length = 0;

	if(!alloc_modifybuffer(0x10000))
		return false;

	record_action(action_invalid, 0);
	group_id		= 0;
	group_refcount	= 0;
	undoredo_index	= 0;
	undoredo_length = 0;

	return true;
}

bool sequence::init (const seqchar *buffer, size_t length)
{
	clear();

	if(!init())
		return false;

	buffer_control *bc = alloc_modifybuffer(length);
	memcpy(bc->buffer, buffer, length * sizeof(seqchar));
	bc->length = length;

	span *sptr = new span(0, length, bc->id, tail, head);
	head->next = sptr;
	tail->prev = sptr;

	sequence_length = length;
	return true;
}

//
//	Initialize from an on-disk file
//
bool sequence::open(TCHAR *filename, bool readonly)
{
	return false;
}

//
//	Initialize from an on-disk file
//
//bool sequence::save(TCHAR *filename)
//{
//	return false;
//}

template <class type>
void sequence::clear_vector (type &vectorobject)
{
	for(size_t i = 0; i < vectorobject.size(); i++)
	{
		delete vectorobject[i];
	}
}

void sequence::clearstack (eventstack &dest)
{
	for(size_t i = 0; i < dest.size(); i++)
	{
		dest[i]->free();
		delete dest[i];
	}

	dest.clear();
}

void sequence::debug1 ()
{
	span *sptr;

	for(sptr = head; sptr; sptr = sptr->next)
	{
		char *buffer = (char *)buffer_list[sptr->buffer]->buffer;
		printf("%.*s", sptr->length, buffer + sptr->offset);
	}

	printf("\n");
}

void sequence::debug2 ()
{
	span *sptr;

	printf("**********************\n");
	for(sptr = head; sptr; sptr = sptr->next)
	{
		char *buffer = (char *)buffer_list[sptr->buffer]->buffer;
		
		printf("[%d] [%4d %4d] %.*s\n", sptr->id, 
			sptr->offset, sptr->length,
			sptr->length, buffer + sptr->offset);
	}

	printf("-------------------------\n");

	for(sptr = tail; sptr; sptr = sptr->prev)
	{
		char *buffer = (char *)buffer_list[sptr->buffer]->buffer;
		
		printf("[%d] [%4d %4d] %.*s\n", sptr->id, 
			sptr->offset, sptr->length,
			sptr->length, buffer + sptr->offset);
	}

	printf("**********************\n");

	for(sptr = head; sptr; sptr = sptr->next)
	{
		char *buffer = (char *)buffer_list[sptr->buffer]->buffer;
		printf("%.*s", sptr->length, buffer + sptr->offset);
	}

	printf("\nsequence length = %d chars\n", sequence_length);
	printf("\n\n");
}

//
//	Allocate a buffer and add it to our 'buffer control' list
//
sequence::buffer_control* sequence::alloc_buffer (size_t maxsize)
{
	buffer_control *bc;

	if((bc = new buffer_control) == 0)
		return 0;

	// allocate a new buffer of byte/wchar/long/whatever
	if((bc->buffer  = new seqchar[maxsize]) == 0)
	{
		delete bc;
		return 0;
	}

	bc->length  = 0;
	bc->maxsize = maxsize;
	bc->id		= buffer_list.size();		// assign the id

	buffer_list.push_back(bc);

	return bc;
}

sequence::buffer_control* sequence::alloc_modifybuffer (size_t maxsize)
{
	buffer_control *bc;
	
	if((bc = alloc_buffer(maxsize)) == 0)
		return 0;

	modifybuffer_id  = bc->id;
	modifybuffer_pos = 0;

	return bc;
}

//
//	Import the specified range of data into the sequence so we have our own private copy
//
bool sequence::import_buffer (const seqchar *buf, size_t len, size_t *buffer_offset)
{
	buffer_control *bc;
	
	// get the current modify-buffer
	bc = buffer_list[modifybuffer_id];

	// if there isn't room then allocate a new modify-buffer
	if(bc->length + len >= bc->maxsize)
	{
		bc = alloc_modifybuffer(len + 0x10000);
		
		// make sure that no old spans use this buffer
		record_action(action_invalid, 0);
	}

	if(bc == 0)
		return false;

	// import the data
	memcpy(bc->buffer + bc->length, buf, len * sizeof(seqchar));
	
	*buffer_offset = bc->length;
	bc->length += len;

	return true;
}


//
//	sequence::spanfromindex
//
//	search the spanlist for the span which encompasses the specified index position
//
//	index		- character-position index
//	*spanindex  - index of span within sequence
//
sequence::span* sequence::spanfromindex (size_w index, size_w *spanindex = 0) const
{
	span * sptr;
	size_w curidx = 0;
	
	// scan the list looking for the span which holds the specified index
	for(sptr = head->next; sptr->next; sptr = sptr->next)
	{
		if(index >= curidx && index < curidx + sptr->length)
		{
			if(spanindex) 
				*spanindex = curidx;

			return sptr;
		}

		curidx += sptr->length;
	}

	// insert at tail
	if(sptr && index == curidx)
	{
		*spanindex = curidx;
		return sptr;
	}

	return 0;
}

void sequence::swap_spanrange(span_range *src, span_range *dest)
{
	if(src->boundary)
	{
		if(!dest->boundary)
		{
			src->first->next = dest->first;
			src->last->prev  = dest->last;
			dest->first->prev = src->first;
			dest->last->next  = src->last;
		}
	}
	else
	{
		if(dest->boundary)
		{
			src->first->prev->next = src->last->next;
			src->last->next->prev  = src->first->prev;
		}
		else
		{
			src->first->prev->next = dest->first;
			src->last->next->prev  = dest->last;
			dest->first->prev = src->first->prev;
			dest->last->next = src->last->next;
		}	
	}
}

void sequence::restore_spanrange (span_range *range, bool undo_or_redo)
{
	if(range->boundary)
	{
		span *first = range->first->next;
		span *last  = range->last->prev;

		// unlink spans from main list
		range->first->next = range->last;
		range->last->prev  = range->first;

		// store the span range we just removed
		range->first = first;
		range->last  = last;
		range->boundary = false;
	}
	else
	{
		span *first = range->first->prev;
		span *last  = range->last->next;

		// are we moving spans into an "empty" region?
		// (i.e. inbetween two adjacent spans)
		if(first->next == last)
		{
			// move the old spans back into the empty region
			first->next = range->first;
			last->prev  = range->last;

			// store the span range we just removed
			range->first  = first;
			range->last   = last;
			range->boundary  = true;
		}
		// we are replacing a range of spans in the list,
		// so swap the spans in the list with the one's in our "undo" event
		else
		{
			// find the span range that is currently in the list
			first = first->next;
			last  = last->prev;

			// unlink the the spans from the main list
			first->prev->next = range->first;
			last->next->prev  = range->last;

			// store the span range we just removed
			range->first = first;
			range->last  = last;
			range->boundary = false;
		}
	}

	// update the 'sequence length' and 'quicksave' states
	std::swap(range->sequence_length,    sequence_length);
	std::swap(range->quicksave,			 can_quicksave);

	undoredo_index	= range->index;

	if(range->act == action_erase && undo_or_redo == true || 
		range->act != action_erase && undo_or_redo == false)
	{
		undoredo_length = range->length;
	}
	else
	{
		undoredo_length = 0;
	}
}

//
//	sequence::undoredo
//
//	private routine used to undo/redo spanrange events to/from 
//	the sequence - handles 'grouped' events
//
bool sequence::undoredo (eventstack &source, eventstack &dest)
{
	span_range *range = 0;
	size_t group_id;

	if(source.empty())
		return false;

	// make sure that no "optimized" actions can occur
	record_action(action_invalid, 0);

	group_id = source.back()->group_id;

	do
	{
		// remove the next event from the source stack
		range = source.back();
		source.pop_back();

		// add event onto the destination stack
		dest.push_back(range);

		// do the actual work
		restore_spanrange(range, source == undostack ? true : false);
	}
	while(!source.empty() && (source.back()->group_id == group_id && group_id != 0));

	return true;
}

// 
//	UNDO the last action
//
bool sequence::undo ()
{
	debug("Undo\n");
	return undoredo(undostack, redostack);
}

//
//	REDO the last UNDO
//
bool sequence::redo ()
{
	debug("Redo\n");
	return undoredo(redostack, undostack);
}

//
//	Will calling sequence::undo change the sequence?
//
bool sequence::canundo () const
{
	return undostack.size() != 0;
}

//
//	Will calling sequence::redo change the sequence?
//
bool sequence::canredo () const
{
	return redostack.size() != 0;
}

//
//	Group repeated actions on the sequence (insert/erase etc)
//	into a single 'undoable' action
//
void sequence::group()
{
	if(group_refcount == 0)
	{
		if(++group_id == 0)
			++group_id;

		group_refcount++;
	}
}

//
//	Close the grouping
//
void sequence::ungroup()
{
	if(group_refcount > 0)
		group_refcount--;
}

//
//	Return logical length of the sequence
//
size_w sequence::size () const
{
	return sequence_length;
}

//
//	sequence::initundo
//
//	create a new (empty) span range and save the current sequence state
//
sequence::span_range* sequence::initundo (size_w index, size_w length, action act)
{
	span_range *event = new span_range (
								sequence_length, 
								index,
								length,
								act,
								can_quicksave, 
								group_refcount ? group_id : 0
								);

	undostack.push_back(event);
	
	return event;
}

sequence::span_range* sequence::stackback(eventstack &source, size_t idx)
{
	size_t length = source.size();
	
	if(length > 0 && idx < length)
	{
		return source[length - idx - 1];
	}
	else
	{
		return 0;
	}
}

void sequence::record_action (action act, size_w index)
{
	lastaction_index = index;
	lastaction       = act;
}

bool sequence::can_optimize (action act, size_w index)
{
	return (lastaction == act && lastaction_index == index);
}

//
//	sequence::insert_worker
//
bool sequence::insert_worker (size_w index, const seqchar *buf, size_w length, action act)

⌨️ 快捷键说明

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