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

📄 lines.c

📁 dtelent是开源的开发项目
💻 C
字号:
/* lines.c
 * Copyright (c) 1997 David Cole
 *
 * Manage line array for terminal with history.  At the moment, only a
 * fixed size history is supported.
 */
#include <windows.h>
#include <string.h>

#include "utils.h"
#include "term.h"
#include "termwin.h"
#include "lines.h"
#include "emul.h"
#include "log.h"

/* Return the specified line
 */
Line* linesGetLine(int num)
{
    if (num < 0 || num >= term.numLinesUsed)
	return NULL;
    ASSERT(term.lineList != NULL);
    ASSERT(term.lineList[num] != NULL);
    return term.lineList[num];
}

/* Allocate a Line.
 *
 * Return a pointer to the new line, initialised to 0 length.
 */
static Line* linesAlloc(void)
{
    Line* line;

    if (term.numLinesUsed == term.maxLines) {
	/* We have filled our history.  We have to remove the oldest
	 * line to make room for the new line.
	 */
	ASSERT(term.lineList != NULL);
	line = term.lineList[0];
	ASSERT(line != NULL);
	ASSERT(term.maxLines > 1);
	memmove(&term.lineList[0], &term.lineList[1],
		(term.maxLines - 1) * sizeof(*term.lineList));
	term.numLinesUsed--;
	/* Tell the terminal window that the top history line was
	 * removed.  This might cause a scroll.
	 */
	winTopLineRemoved();
    } else
	/* Allocate a new line
	 */
	line = (Line *)xmalloc(sizeof(*line));

    /* Initialise the line with zero length, no wrap, and current
     * color attributes.
     */
    ASSERT(line != NULL);
    line->len = 0;
    line->wrapped = 0;
    line->attr[0] = getCurrAttr();

    return line;
}

/* Add a new line to the bottom of the line array
 */
void linesNewLine()
{
    Line* line = linesAlloc();
    term.lineList[term.numLinesUsed++] = line;
}

/* Make sure that lines exist up to the specified line array index
 */
void linesCreateTo(int idx)
{
    if (idx >= term.maxLines)
	idx = term.maxLines - 1;

    while (term.lineList[idx] == NULL)
	term.lineList[term.numLinesUsed++] = linesAlloc();
}

/* Return the line array index of the specified terminal line.
 *
 * Args:
 * posy - offset from the top line of the terminal.
 */
int linesTerminalToLine(int posy)
{
    return winTerminalTopLine() + posy;
}

/* Fill a part of a line with an ASCII character + attribute. */
static void linesFill (Line *line, int x, int n, unsigned char c, unsigned char attr)
{
    int i;

    if (n<=0) return;
    line->text[x].cType = DTCHAR_ASCII;
    line->text[x].cCode = c;
    for (i=1; i<n; ++i) {
	line->text[x+i] = line->text[x];
    }
    memset (&line->attr[x], attr, n);
}

/* Insert a number of lines at the specified terminal line.
 *
 * Args:
 * posy -     the terminal line to insert lines before
 * bottom -   the bottom terminal line (handles scroll regions)
 * numLines - the number of lines to insert
 */
void linesInsert(int posy, int bottom, int numLines)
{
    /* Convert terminal lines to line array index
     */
    int posyIdx = linesTerminalToLine(posy);
    int bottomIdx = linesTerminalToLine(bottom);

    ASSERT(posy >= 0);
    ASSERT(bottom >= 1);
    ASSERT(posy < bottom);
    ASSERT(bottom <= term.winSize.cy);
    ASSERT(numLines > 0);
    ASSERT(posyIdx <= term.maxLines);
    ASSERT(bottomIdx <= term.maxLines);

    /* Make sure that we do not try to insert more lines than will fit
     * in the region.
     */
    if (posy + numLines > bottom)
	numLines = bottom - posy;

    /* Make that lines exist to the specified y position
     */
    linesCreateTo(posyIdx);

    /* Insert the blank lines
     */
    while (numLines-- > 0) {
	Line* line;

	if (term.numLinesUsed >= bottomIdx) {
	    /* Take the line off the bottom and insert it
	     * at the current position.
	     */
	    line = term.lineList[bottomIdx - 1];
	    ASSERT(line != NULL);
	    line->len = 0;
	    line->wrapped = 0;
	    line->attr[0] = getCurrAttr();
	} else
	    /* We need to create a new line to insert it
	     */
	    line = linesAlloc();

	/* If there are any lines at or after the insertion position,
	 * we need to move them down.
	 */
	if (posyIdx < bottomIdx - 1)
	    memmove(&term.lineList[posyIdx + 1], &term.lineList[posyIdx],
		    (bottomIdx - posyIdx - 1) * sizeof(*term.lineList));
	term.lineList[posyIdx] = line;
    }
}

/* Insert a number of blank characters in the specified terminal line.
 *
 * Args:
 * posy -     the terminal line to insert characters into
 * posx -     the column at which characters will be inserted
 * numChars - the number of characters to be inserted
 */
void linesCharsInsert(int posy, int posx, int numChars)
{
    /* Convert the terminal line to line array index
     */
    int posyIdx = linesTerminalToLine(posy);
    Line* line;			/* line being modified */

    ASSERT(posy >= 0);
    ASSERT(posy < term.winSize.cy);
    ASSERT(posx >= 0);
    ASSERT(numChars > 0);
    ASSERT(posyIdx < term.maxLines);

    linesCreateTo(posyIdx);
    line = term.lineList[posyIdx];
    ASSERT(line != NULL);

    /* Do not insert any characters if at end of line
     */
    if (line == NULL || posx >= line->len)
	return;

    /* Make sure that we do not insert past the right edge of the
     * window
     */
    if (numChars + posx > term.winSize.cx)
	numChars = term.winSize.cx - posx;
    if (numChars + line->len > term.winSize.cx)
	line->len = term.winSize.cx - numChars;

    /* Now insert the blank characters
     */
    memmove(line->text + posx + numChars,
	    line->text + posx,
	    sizeof(line->text[0])*(line->len - posx));
    memmove(line->attr + posx + numChars,
	    line->attr + posx,
	    line->len - posx + 1);
    linesFill (line, posx, numChars, ' ', getCurrAttr());

    line->len += numChars;
}

/* Delete a number of lines at the specified terminal line.
 *
 * Args:
 * posy -     the terminal line to delete lines at
 * bottom -   the bottom terminal line (handle scroll regions)
 * numLines - the number of lines to delete
 */
void linesDelete(int posy, int bottom, int numLines)
{
    /* Convert terminal lines to line array index
     */
    int posyIdx = linesTerminalToLine(posy);
    int bottomIdx = linesTerminalToLine(bottom);

    ASSERT(posy >= 0);
    ASSERT(bottom >= 1);
    ASSERT(posy < bottom);
    ASSERT(bottom <= term.winSize.cy);
    ASSERT(numLines > 0);
    ASSERT(posyIdx <= term.maxLines);
    ASSERT(bottomIdx <= term.maxLines);

    /* Limit bottom line to the number of lines that have actually
     * been used.
     */
    if (bottomIdx > term.numLinesUsed)
	bottomIdx = term.numLinesUsed;

    /* Make sure that we do not try to delete more lines than are in
     * the region.
     */
    if (posy + numLines > bottom)
	numLines = bottom - posy;

    /* Make that lines exist to the specified y position
     */
    linesCreateTo(posyIdx);

    while (numLines--) {
	/* Take the top line, clear it, and rotate it to the bottom of
	 * the delete region.
	 */
	Line* line = term.lineList[posyIdx];
	ASSERT(line != NULL);
	line->len = 0;
	line->wrapped = 0;
	line->attr[0] = getCurrAttr();

	/* If there are any lines used after the current point -
	 * shuffle them up.
	 */
	if (posyIdx < bottomIdx - 1)
	    memmove(&term.lineList[posyIdx], &term.lineList[posyIdx + 1],
		    (bottomIdx - 1 - posyIdx) * sizeof(*term.lineList));
	term.lineList[bottomIdx - 1] = line;
    }
}

/* Delete a number of characters in the specified terminal line.
 *
 * Args:
 * posy -     the terminal line to delete characters from
 * posx -     the column at which characters will be deleted
 * numChars - the number of characters to be deleted
 */
void linesCharsDelete(int posy, int posx, int numChars)
{
    /* Convert terminal line to line array index
     */
    int posyIdx = linesTerminalToLine(posy);
    Line* line;			/* the line being modified */

    ASSERT(posy >= 0);
    ASSERT(posy < term.winSize.cy);
    ASSERT(posx >= 0);
    ASSERT(numChars > 0);
    ASSERT(posyIdx < term.maxLines);

    /* Make sure lines exist up to the one being modified
     */
    linesCreateTo(posyIdx);
    line = term.lineList[posyIdx];

    /* Make sure that the line length does not extend past the right
     * edge of the window
     */
    if (line->len > term.winSize.cx)
	line->len = term.winSize.cx;

    /* Do not delete any characters if past end of line
     */
    if (posx >= line->len)
	return;
    /* Only delete characters up to the end of the line
     */
    if (numChars > line->len - posx)
	numChars = line->len - posx;

    memmove(line->text + posx,
	    line->text + posx + numChars,
	    line->len - posx - numChars);
    memmove(line->attr + posx,
	    line->attr + posx + numChars,
	    line->len - posx - numChars + 1);

    line->len -= numChars;
}

/* Clear all of the text in the terminal between two locations.
 *
 * Args:
 * y1/x1 - terminal line/column to clear from
 * y2/x2 - terminal line/column to clear to
 *
 * The from location is assumed to precede the to location.
 */
void linesClearRange(int y1, int x1, int y2, int x2)
{
    int lineIdx;		/* iterate over lines to be cleared */
    Line* line;			/* line currently being cleared */

    /* If start of clear operation is off bottom of terminal, we have
     * no work to do.
     */
    if (y1 >= term.winSize.cy)
	return;

    /* If end of clear operation is off bottom of terminal, set it to
     * the end of the last line on the terminal.
     */
    if (y2 >= term.winSize.cy) {
	y2 = term.winSize.cy - 1;
	x2 = term.winSize.cx;
    }

    ASSERT(x1 >= 0);
    ASSERT(x2 >= 0);
    ASSERT(y2 >= y1);

    /* Convert the starting line to line array index and make sure
     * lines exist to that point.
     */
    lineIdx = linesTerminalToLine(y1);
    linesCreateTo(linesTerminalToLine(y2));
    line = term.lineList[lineIdx];
    ASSERT(line != NULL);

    if (y1 == y2) {
	/* Clearing text on single line
	 */
	ASSERT(x1 <= x2);
	if (x1 <= line->len) {
	    if (x2 >= line->len) {
		/* Cleared to end of line - redefine line length
		 */
		line->len = x1;
		line->wrapped = 0;
		line->attr[line->len] = getCurrAttr();
	    } else {
		/* Cleared part of line
		 */
		linesFill (line, x1, x2-x1, ' ', getCurrAttr());
	    }
	}
	return;
    }

    /* Clearing more than one line - first line is from x1 to end of line
     */
    if (x1 < line->len) {
	line->len = x1;
	line->wrapped = 0;
	line->attr[x1] = getCurrAttr();
    }
    ++lineIdx;
    ++y1;
    /* Totally clear all lines until y2
     */
    while (y1 < y2) {
	ASSERT(term.lineList[lineIdx] != NULL);
	term.lineList[lineIdx]->len = 0;
	term.lineList[lineIdx]->wrapped = 0;
	term.lineList[lineIdx]->attr[0] = getCurrAttr();
	++lineIdx;
	++y1;
    }
    /* Clearing last line - clear from start of line to x2
     */
    if (y1 == term.winSize.cy)
	return;
    line = term.lineList[lineIdx];
    ASSERT(line != NULL);
    if (x2 >= line->len) {
	line->len = 0;
	line->wrapped = 0;
	line->attr[0] = getCurrAttr();
    } else {
	ASSERT(x2 > 0);
	linesFill (line, 0, x2, ' ', getCurrAttr());
    }
}

/* Fill the screen with 'E' for alignment test
 */
void linesAlignTest()
{
    int y;			/* iterate over lines to be cleared */

    for (y = 0; y < term.winSize.cy; y++) {
	int lineIdx = linesTerminalToLine(y);
	Line* line;
	linesCreateTo(lineIdx);
	line = term.lineList[lineIdx];
	ASSERT(line != NULL);
	line->len = term.winSize.cx;
	line->wrapped = 0;
	linesFill (line, 0, term.winSize.cx, 'E', getCurrAttr());
	line->attr [term.winSize.cx] = getCurrAttr();
    }
}

/* Switch to/from inverse video
 */
void linesInvertAll()
{
    int y;			/* iterate over lines to be inverted */

    for (y = 0; y < term.winSize.cy; y++) {
	int lineIdx = linesTerminalToLine(y);
	Line* line;
	int x;
	linesCreateTo(lineIdx);
	line = term.lineList[lineIdx];
	ASSERT(line != NULL);
	for (x = 0; x <= line->len; x++)
	    line->attr[x] = (unsigned char)REVERSE(line->attr[x]);
    }
}

/* Set the character at the current cursor position.
 *
 * Args:
 * c - the character to set at the cursor position.
 */
void linesSetChar(const DtChar *dCh)
{
    int lineIdx;		/* cursor terminal line as line array index */
    Line* line;			/* line being modified */
    int posy = term.cursor.y;
    int posx = term.cursor.x;
    int i;

    /* If cursor off bottom of terminal, we have nothing to do
     */
    if (posy >= term.winSize.cy)
	return;

    /* Make sure lines up to the cursor location exist
     */
    lineIdx = linesTerminalToLine(posy);
    ASSERT(lineIdx < term.maxLines);
    linesCreateTo(lineIdx);
    line = term.lineList[lineIdx];
    ASSERT(line != NULL);

    ASSERT(posx < sizeof(line->text));
    if (posx >= line->len) {
	/* Append to the end of the line, retain the end of line
	 * attribute.
	 */
	line->attr[posx + 1] = line->attr[line->len];

	if (posx > line->len) {
	    for (i=line->len; i<posx; ++i) {
		line->text[i].cType = DTCHAR_ASCII;
		line->text[i].cCode = ' ';
		line->attr[i] = line->attr[line->len];
	    }
	}
	line->len = posx + 1;
    }

    /* Set the character
     */
    line->text[posx] = *dCh;
    line->attr[posx] = getCurrAttr();

    /* Make sure that the line length does not extend past the right
     * edge of the window
     */
    if (line->len > term.winSize.cx)
	line->len = term.winSize.cx;
}

⌨️ 快捷键说明

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