1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/cde/lib/DtTerm/TermPrim/TermPrimBuffer.c

2417 lines
58 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
#ifndef lint
#ifdef VERBOSE_REV_INFO
static char rcs_id[] = "$XConsortium: TermPrimBuffer.c /main/1 1996/04/21 19:16:49 drk $";
#endif /* VERBOSE_REV_INFO */
#endif /* lint */
/* *
* (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company *
* (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
* (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc. *
* (c) Copyright 1993, 1994, 1996 Novell, Inc. *
* (c) Copyright 1996 Digital Equipment Corporation. *
* (c) Copyright 1996 FUJITSU LIMITED. *
* (c) Copyright 1996 Hitachi. *
*/
#define USE_MEMCPY /* use memcpy for line movement... */
#include <stdlib.h>
#include <wchar.h>
#include <Xm/Xm.h>
#include "TermHeader.h" /* for MIN/MAX */
#include "TermPrim.h"
#include "TermPrimBuffer.h"
#include "TermPrimBufferP.h"
#include "TermPrimSelect.h"
#include "TermPrimDebug.h"
/*
** Allocate and initialize a new terminal buffer.
*/
TermBuffer
_DtTermPrimBufferCreateBuffer
(
const Widget w,
const short rows,
const short cols,
const short sizeOfBuffer,
const short sizeOfLine,
const short sizeOfEnh
)
{
int i;
TermLine *newTL;
TermBuffer newTB;
Boolean *tabs;
int sizeOfChar;
/*
** malloc new a TermBuffer and an array of TermLine pointers
*/
newTB = (TermBuffer) malloc(sizeOfBuffer);
/* the following MIN ensures that on systems where malloc of 0 returns
* NULL, we won't confuse a 0 size buffer with a malloc failure and an
* invalid buffer...
*/
newTL = (TermLine *) malloc((unsigned) MAX(rows, 1) * sizeof(TermLine));
if (!newTB || !newTL)
{
/*
** clean up and leave if either of the previous malloc's failed.
*/
if (newTB)
{
free(newTB);
}
if (newTL)
{
free(newTL);
}
return((TermBuffer)NULL);
}
/*
** malloc a tabs array...
*/
tabs = (Boolean *) malloc((unsigned) cols * sizeof(Boolean));
if (!tabs)
{
free(newTB);
free(newTL);
/*
** clean up and leave if either of the previous malloc's failed.
*/
return((TermBuffer)NULL);
}
/*
** initialize the tabs...
*/
for (i = 0; i < cols; i++) {
tabs[i] = 0 == i % 8;
}
/*
** decide how many bytes to allocate per character...
*/
BYTES_PER_CHAR(newTB) = MB_CUR_MAX == 1 ? 1 : sizeof(wchar_t);
/*
** setting debug flag m:1 forces us into wide char mode...
*/
DebugF('m', 1, BYTES_PER_CHAR(newTB) = sizeof(wchar_t));
/*
** now malloc the individual lines...
*/
for (i = 0; i < rows; i++)
{
newTL[i] = (TermLine) malloc(sizeOfLine);
if (newTL[i])
{
BUFFER(newTL[i]) = (termChar *)
malloc((unsigned)
cols * BYTES_PER_CHAR(newTB));
if (BUFFER(newTL[i]) == NULL)
{
/*
** we couldn't malloc a line buffer
*/
break;
}
LENGTH(newTL[i]) = 0;
WIDTH(newTL[i]) = 0;
WRAPPED(newTL[i]) = False;
START_SELECTION(newTL[i]) = NON_SELECTION_COL;
END_SELECTION(newTL[i]) = NON_SELECTION_COL;
}
else
{
/*
** we couldn't malloc a line
*/
break;
}
}
/*
** If we were unable to malloc a full set of lines (i != rows),
** then cleanup and leave.
*/
if (i != rows)
{
int j;
for (j = 0; j < i; j++)
{
free(BUFFER(newTL[j]));
free(newTL[j]);
}
free(newTL);
free(newTB);
free(tabs);
return((TermBuffer)NULL);
}
/*
** Initialize the new TermBuffer.
*/
LINES(newTB) = newTL;
TABS(newTB) = tabs;
ROWS(newTB) = rows;
COLS(newTB) = cols;
MAX_ROWS(newTB) = rows;
MAX_COLS(newTB) = cols;
SIZE_OF_BUFFER(newTB) = sizeOfBuffer;
SIZE_OF_LINE(newTB) = sizeOfLine;
SIZE_OF_ENH(newTB) = sizeOfEnh;
BUFFER_CREATE(newTB) = _DtTermPrimBufferCreateBuffer;
BUFFER_FREE(newTB) = NULL;
BUFFER_RESIZE(newTB) = NULL;
ENH_PROC(newTB) = NULL;
CLEAR_ENH(newTB) = NULL;
INSERT_ENH(newTB) = NULL;
DELETE_ENH(newTB) = NULL;
SET_ENH(newTB) = NULL;
GET_ENH(newTB) = NULL;
SET_LINE_WIDTH(newTB) = NULL;
CLEAR_LINE(newTB) = NULL;
NEXT_BUFFER(newTB) = NULL;
PREV_BUFFER(newTB) = NULL;
BUFFER_SELECT_INFO(newTB) = NULL;
WIDGET(newTB) = w;
return (newTB);
}
void
_DtTermPrimBufferFreeBuffer
(
const TermBuffer tb
)
{
int i;
/* check for null buffer... */
if (!tb) {
return;
}
/*
** Free any buffer-specific info first...
*/
if (BUFFER_FREE(tb))
{
(*BUFFER_FREE(tb))(tb);
}
/*
** free the old buffer...
*/
for (i = 0; i < MAX_ROWS(tb); i++)
{
(void) free(BUFFER(LINES(tb)[i]));
(void) free(LINES(tb)[i]);
}
(void) free(TABS(tb));
(void) free(LINES(tb));
(void) free(tb);
}
/*
** Resize the terminal buffer, and try to be smart about it. If the buffer
** shrinks, then simply adjust the size, no reallocs necessary (that way if
** the user returns to the previous size, no data is lost).
**
** NOTE:
** Given this implementation, the memory allocated to the buffer will
** never decrease it simply increases to accomodate the largest size
** that has ever been requested.
*/
void
_DtTermPrimBufferResizeBuffer
(
TermBuffer *oldTB,
short *newRows,
short *newCols
)
{
int i;
short thisTabWidth;
short tabWidth;
TermLine *newTL;
Boolean *tabs;
/*
** enforce some minimum size constraints...
*/
*newRows = MAX(*newRows, 1);
*newCols = MAX(*newCols, 1);
/*
** the number of cols is increasing, start small and adjust the tab
** stops first...
*/
if (*newCols > MAX_COLS(*oldTB))
{
tabs = (Boolean *) malloc((unsigned) *newCols * sizeof(Boolean));
if (tabs)
{
/* copy over the tab stops... */
(void) memcpy(tabs, TABS(*oldTB), COLS(*oldTB) * sizeof(Boolean));
free(TABS(*oldTB));
TABS(*oldTB) = tabs;
/*
** we need to extend the tab stops...
**
** when tabWidth == 0, it has not been initialized. When
** it is < 0, we have encountered unequal tab stops...
*/
tabWidth = 0;
for (i = 0, thisTabWidth = 0; i < COLS(*oldTB); i++, thisTabWidth++)
{
if (TABS(*oldTB)[i])
{
if (tabWidth == 0)
{
/* first tab stop, set tabWidth... */
tabWidth = thisTabWidth;
}
else if (tabWidth != thisTabWidth)
{
/* tab stops differ, set tabWidth to -1... */
tabWidth = -1;
}
/* reset for next tab stop... */
thisTabWidth = 0;
}
}
if (tabWidth > 0)
{
/*
** we have consistent tab stops. Extend the buffer...
*/
for (i = COLS(*oldTB); i < *newCols; i++)
{
TABS(*oldTB)[i] = (0 == (i % tabWidth));
}
}
else
{
/*
** we don't have consistent tab stops, so clear the rest...
*/
(void) memset(&(TABS(*oldTB)[COLS(*oldTB)]), '\0',
(*newCols - COLS(*oldTB)) * sizeof(Boolean));
}
}
else
{
/*
** the malloc failed, adjust newCols and newRows and leave...
*/
*newCols = MAX_COLS(*oldTB);
*newRows = MIN(*newRows, MAX_ROWS(*oldTB));
COLS(*oldTB) = *newCols;
ROWS(*oldTB) = *newRows;
return;
}
}
else
{
/*
** take care of any shrinkage...
*/
COLS(*oldTB) = *newCols;
}
/*
** Now give the resize helper a shot at resizing the buffer
*/
if (BUFFER_RESIZE(*oldTB))
{
/*
** Call the resize helper function if it exists...
*/
(*BUFFER_RESIZE(*oldTB))(*oldTB, newRows, newCols);
}
else
{
/*
** There is no helper function, do it ourselves...
** NOTE:
** This might cause some duplication of code, but due
** to time constraints, it is the most expeditious route.
*/
/*
** make any necessary width adjustments first...
**
** NOTE:
** We do not take any action if the new column width is less
** than the current column width. It is the responsibility of
** the rendering code to make sure that two column characters
** are handled properly if the second column falls past the last
** column in the window.
*/
if (*newCols > MAX_COLS(*oldTB))
{
termChar *newLineBuffer;
/*
** now extend the line buffers for all lines, (even lines that
** are not being used at the moment (ROWS < MAX_ROWS))...
*/
newTL = LINES(*oldTB);
for (i = 0; i < MAX_ROWS(*oldTB); i++)
{
newLineBuffer = (termChar *) malloc((unsigned)
*newCols * BYTES_PER_CHAR(*oldTB));
if (newLineBuffer == NULL)
{
/*
** line buffer malloc failed, we can only increase the
** width to the current maximum...
*/
*newCols = MAX_COLS(*oldTB);
*newRows = MIN(*newRows, MAX_ROWS(*oldTB));
break;
}
memcpy(newLineBuffer, BUFFER(newTL[i]), LENGTH(newTL[i]));
free(BUFFER(newTL[i]));
BUFFER(newTL[i]) = newLineBuffer;
WRAPPED(newTL[i]) = False;
}
MAX_COLS(*oldTB) = *newCols;
}
COLS(*oldTB) = *newCols;
/*
** now adjust the length of the buffer as necessary...
*/
if (*newRows > MAX_ROWS(*oldTB))
{
/*
** the number of rows is increasing
*/
newTL = (TermLine *) malloc((unsigned) *newRows *
sizeof(TermLine));
if (newTL != NULL)
{
/*
** the malloc succeeded, copy the old information, and
** then free it...
*/
memcpy(newTL, LINES(*oldTB), sizeof(TermLine) *
ROWS(*oldTB));
free(LINES(*oldTB));
LINES(*oldTB) = newTL;
/*
** now initialize the new lines...
*/
for (i = ROWS(*oldTB); i < *newRows; i++)
{
newTL[i] = (TermLine) malloc(SIZE_OF_LINE(*oldTB));
if (newTL[i])
{
BUFFER(newTL[i]) = (termChar *)
malloc((unsigned) COLS(*oldTB) *
BYTES_PER_CHAR(*oldTB));
if (BUFFER(newTL[i]) == NULL)
{
/*
** line buffer malloc failed...
*/
*newRows = i;
break;
}
LENGTH(newTL[i]) = 0;
WIDTH(newTL[i]) = 0;
WRAPPED(newTL[i]) = False;
START_SELECTION(newTL[i]) = NON_SELECTION_COL;
END_SELECTION(newTL[i]) = NON_SELECTION_COL;
}
else
{
/*
** line malloc failed, lets limit the
** number of rows
*/
*newRows = i;
break;
}
}
/*
** its conceivable that MAX_ROWS could actually decrease if
** we are low on memory...
*/
MAX_ROWS(*oldTB) = MIN(MAX_ROWS(*oldTB), *newRows);
}
else
{
/*
** the row buffer malloc failed, revert back to MAX_ROWS
*/
*newRows = MAX_ROWS(*oldTB);
}
}
ROWS(*oldTB) = *newRows;
}
}
#ifdef NOCODE
/*
** Create an enhancement block at the specified row and column.
**
** NOTE: For the time being, we simply allocate an entire row's worth
** of enhancement blocks if it doesn't exist already. We may
** get smarter later on.
*/
/*ARGSUSED*/
Boolean
_DtTermPrimBufferCreateEnhancement
(
const TermBuffer tb,
const short row,
const short col
)
{
return(True);
}
/*
** Clear the enhancement block at the specified row and column.
*/
static
void
clearEnhancement
(
const TermBuffer tb,
const short row,
const short col
)
{
}
#endif /* NOCODE */
/*
** Call the emulations specific function to insert the desired number of
** enhancements at the specified position...
**
** Assumptions:
** - insertCount has been properly clipped to insure that we don't go
** out of bounds
**
** Notes:
** - results are undefined if this function is called when the specified
** column is at the end of the line.
*/
static void
insertEnhancements
(
const TermBuffer tb,
const short row,
const short col,
const short insertCount,
const Boolean insertFlag
)
{
/*
** call the insert function only when it exists and we're in
** insert mode...
*/
if (INSERT_ENH(tb))
{
(*INSERT_ENH(tb))(tb, row, col, insertCount, insertFlag);
}
}
/*
** Free the enhancement block at the specified row and column.
**
** NOTE: We may get smarter later on.
*/
Boolean
_DtTermPrimBufferFreeEnhancement
(
const TermBuffer tb,
const short row,
const short col
)
{
return(True);
}
#ifdef BBA
#pragma BBA_IGNORE
#endif /*BBA*/
static void
RememberTermBuffer
(
const TermBuffer tb,
TermLine **referenceLines,
int *referenceLineCount
)
{
int i1;
int i2;
*referenceLineCount = ROWS(tb);
*referenceLines = (TermLine *) XtMalloc(ROWS(tb) * sizeof(TermLine));
/* copy over the lines...
*/
for (i1 = 0; i1 < ROWS(tb); i1++) {
(*referenceLines)[i1] = LINE_OF_TBUF(tb, i1);
}
/* verify that they are all unique...
*/
/* do a brute force check... */
for (i1 = 0; i1 < ROWS(tb) - 1; i1++) {
for (i2 = i1 + 1; i2 < ROWS(tb); i2++) {
if ((*referenceLines)[i1] == (*referenceLines)[i2]) {
(void) fprintf(stderr,
">>RememberTermBuffer: dup ptrs lines %d and %d\n",
i1, i2);
}
}
}
}
#ifdef BBA
#pragma BBA_IGNORE
#endif /*BBA*/
static void
CheckTermBuffer
(
const TermBuffer tb,
TermLine *referenceLines,
int referenceLineCount
)
{
int i1;
int i2;
int matchedLine;
if (referenceLineCount != ROWS(tb)) {
for (i1 = 0; i1 < ROWS(tb); i1++) {
matchedLine = -1;
for (i2 = 0; i2 < ROWS(tb); i2++) {
if (referenceLines[i1] == LINE_OF_TBUF(tb, i2)) {
if (matchedLine == -1) {
matchedLine = i2;
} else {
/* duplicate pointer... */
fprintf(stderr,
">>CheckTermBuffer: duplicate pointer src=%d, dest=%d and %d\n",
i1, matchedLine, i2);
}
}
}
if (matchedLine == -1) {
fprintf(stderr,
">>CheckTermBuffer: dropped pointer src=%d\n", i1);
}
}
}
if (referenceLines) {
XtFree((char *) referenceLines);
}
}
short
_DtTermPrimBufferGetText
(
const TermBuffer tb,
const short row,
const short col,
const short width,
char *buffer,
const Boolean needWideChar
)
{
short retLen;
short colWidth;
short mbLen;
char *pChar;
wchar_t *pwc;
TermCharInfoRec charInfoFirst;
TermCharInfoRec charInfoLast;
if (!VALID_ROW(tb, row) || !VALID_COL(tb, col))
{
return(0);
}
colWidth = MIN(width, WIDTH(LINE_OF_TBUF(tb, row)) - col);
if (colWidth > 0)
{
_DtTermPrimGetCharacterInfo(tb, row, col, &charInfoFirst);
_DtTermPrimGetCharacterInfo(tb, row, col + colWidth - 1, &charInfoLast);
if ((BYTES_PER_CHAR(tb) > 1) && !needWideChar)
{
/*
** our caller wants multi-byte characters...
*/
retLen = 0;
pChar = buffer;
for (pwc = charInfoFirst.u.pwc; pwc <= charInfoLast.u.pwc; pwc++)
{
mbLen = wctomb(pChar, *pwc);
if (mbLen > 0)
{
pChar += mbLen;
retLen += mbLen;
}
else
{
fprintf(stderr, "_DtTermPrimBufferGetText: invalid wide char.\n");
}
}
}
else
{
retLen = charInfoLast.idx - charInfoFirst.idx + 1;
memcpy(buffer, charInfoFirst.u.pc, retLen);
}
}
else
{
/*
** colWidth == 0, there is nothing to return
*/
retLen = 0;
}
return(retLen);
}
short
_DtTermPrimBufferGetRows
(
const TermBuffer tb
)
{
return(ROWS(tb));
}
short
_DtTermPrimBufferGetCols
(
const TermBuffer tb
)
{
return(COLS(tb));
}
void
_DtTermPrimBufferSetLinks
(
const TermBuffer tb,
const TermBuffer prev,
const TermBuffer next
)
{
PREV_BUFFER(tb) = prev;
NEXT_BUFFER(tb) = next;
}
void
_DtTermPrimBufferSetSelectInfo
(
const TermBuffer tb,
const TermSelectInfo si
)
{
BUFFER_SELECT_INFO(tb) = si;
}
/*
** Set the desired enhancement; simply call the emulator specific
** function.
*/
int
_DtTermPrimBufferSetEnhancement
(
const TermBuffer tb,
const short row,
const short col,
const unsigned char id,
const enhValue value
)
{
if (SET_ENH(tb))
{
return((*SET_ENH(tb))(tb, row, col, id, value));
}
else
{
return(0);
}
}
/*
** Get the enhancements for the desired row and column by calling the
** emulator specific routine.
*/
Boolean
_DtTermPrimBufferGetEnhancement
(
const TermBuffer tb,
const short row,
const short col,
enhValue **values,
short *count,
const countSpec countWhich
)
{
if (GET_ENH(tb))
{
return((*GET_ENH(tb))(tb, row, col, values, count, countWhich));
}
else
{
*count = WIDTH(LINE_OF_TBUF(tb, row));
return(True);
}
}
/*
** Return a pointer to the character at the specified row,col.
*/
termChar *
_DtTermPrimBufferGetCharacterPointer
(
const TermBuffer tb,
const short row,
const short col
)
{
TermCharInfoRec charInfo;
if (VALID_ROW(tb, row) && VALID_COL(tb, col))
{
_DtTermPrimGetCharacterInfo(tb, row, col, &charInfo);
return((termChar *)charInfo.u.pc);
}
else
{
return(NULL);
}
}
/*
** Get the character info for the specified character. If the
** specified column exceeds the width of the line, then make up
** some reasonable information, allowing the calling routine to
** continue in a reasonable fashion.
**
** XXX: this doesn't get the emulator specific information yet (like
** enhancements
*/
Boolean
_DtTermPrimGetCharacterInfo
(
TermBuffer tb,
short row,
short col,
TermCharInfo charInfo
)
{
wchar_t *pwc;
short charWidth;
TermLine line;
short totalWidth;
if (!VALID_ROW(tb, row))
{
return(False);
}
line = LINE_OF_TBUF(tb, row);
/*
** handle the easy cases first...
*/
if (col >= WIDTH(line))
{
/*
** make up some reasonable values when col equals or
** exceeds the width of the line
*/
charInfo->u.ptc = NULL;
charInfo->idx = LENGTH(line);
charInfo->len = BYTES_PER_CHAR(tb);
charInfo->startCol = col;
charInfo->width = 1;
charInfo->enh = 0;
charInfo->enhLen = 0;
}
else if (BYTES_PER_CHAR(tb) == 1)
{
/*
** this is easy in a 1 byte locale...
*/
charInfo->u.ptc = BUFFER(line) + col;
charInfo->idx = col;
charInfo->len = BYTES_PER_CHAR(tb);
charInfo->startCol = col;
charInfo->width = 1;
charInfo->enh = 0;
charInfo->enhLen = 0;
}
else if (col == 0)
{
charInfo->u.pwc = (wchar_t *)BUFFER(line);
charInfo->idx = 0;
charInfo->len = BYTES_PER_CHAR(tb);
charInfo->startCol = 0;
charInfo->width = MAX(1, wcwidth(*((wchar_t *)BUFFER(line))));
charInfo->enh = 0;
charInfo->enhLen = 0;
}
else
{
/*
** not so easy when we're dealing with wchars...
*/
if (col <= WIDTH(line) / 2)
{
/*
** work from left to right
*/
totalWidth = 0;
for (pwc = (wchar_t *)BUFFER(line);
pwc < (wchar_t *)BUFFER(line) + LENGTH(line);
pwc++)
{
charWidth = MAX(1, wcwidth(*pwc));
totalWidth += charWidth;
if (col < totalWidth)
{
/*
** we've found the character, now fill in the info...
*/
charInfo->u.pwc = pwc;
charInfo->idx = pwc - (wchar_t *)BUFFER(line);
charInfo->startCol = totalWidth - charWidth;
charInfo->width = charWidth;
break;
}
}
}
else
{
/*
** work from right to left
*/
totalWidth = WIDTH(line);
for (pwc = (wchar_t *)BUFFER(line) + (LENGTH(line) - 1);
pwc >= (wchar_t *)BUFFER(line);
pwc--)
{
charWidth = MAX(1, wcwidth(*pwc));
totalWidth -= charWidth;
if (totalWidth <= col)
{
/*
** we've found the character, now fill in the info...
*/
charInfo->u.pwc = pwc;
charInfo->idx = pwc - (wchar_t *)BUFFER(line);
if (totalWidth == col)
{
charInfo->startCol = col;
}
else
{
charInfo->startCol = col - 1;
}
charInfo->width = charWidth;
break;
}
}
}
charInfo->len = BYTES_PER_CHAR(tb);
charInfo->enh = 0;
charInfo->enhLen = 0;
}
return(True);
}
/*
** Insert as many characters as possible at the specified row,col
** return a count of the number of characters bumped off the end of the line
** in 'returnCount' and a pointer to a buffer containing those characters
** 'returnChars'.
**
** The the new width of the line is returned as the value of the function.
*/
short
_DtTermPrimBufferInsert
(
const TermBuffer tb,
const short row,
const short col,
const termChar *newChars,
short numChars,
Boolean insertFlag, /* if TRUE, insert, else overwrite */
termChar **returnChars, /* pointer to overflow buffer */
short *returnCount /* count of characters in overflow buffer */
)
{
short insertCount;
short newWidth;
short insertOverflow; /* # of newChars that would overflow */
TermLine line;
termChar *start;
short copyCount; /* number of bytes to copy */
if (!VALID_ROW(tb, row) || !VALID_COL(tb, col))
{
*returnCount = 0;
return(0);
}
line = LINE_OF_TBUF(tb, row);
#ifdef OLD_CODE
/* before we modify the buffer, disown the selection... */
(void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
#endif /* OLD_CODE */
/* if this line is part of the selection, disown the selection... */
if (IS_IN_SELECTION(line, col, MAX_SELECTION_COL)) {
(void) _DtTermPrimSelectDisown(WIDGET(tb));
}
if (BYTES_PER_CHAR(tb) > 1)
{
/*
** we do not handle multibyte characters here...
*/
_DtTermPrimBufferInsertWc(tb, row, col, (wchar_t *)newChars,
numChars, insertFlag,
returnChars, returnCount);
return 0;
}
if (WIDTH(line) < col)
{
/*
** We're adding characters past the current end of line,
** pad it out.
*/
_DtTermPrimBufferPadLine(tb, row, col);
}
insertCount = MIN(numChars, COLS(tb) - col);
copyCount = insertCount * BYTES_PER_CHAR(tb);
start = BUFFER(line) + col;
/*
** It doesn't matter if we're overwriting, or inserting at the end
** of the line, the result is the same...
*/
if (col == WIDTH(line))
{
insertFlag = False;
}
if (insertFlag == False)
{
/*
** We're overwriting:
** - determine the new line width
** - put any extra new characters into the overflow buffer
**
** The following will be done later:
** - copy the newChars into the line buffer
** - adjust line width (_DtTermPrimBufferSetLineWidth won't
** let the line get shorter)...
*/
newWidth = MAX(WIDTH(line), col + insertCount);
*returnCount = numChars - insertCount;
if (*returnCount > 0)
{
memcpy(*returnChars, newChars + insertCount,
*returnCount * BYTES_PER_CHAR(tb));
}
}
else
{
/*
** we're inserting text in the middle of the line...
*/
*returnCount = MAX(0, (WIDTH(line) + numChars) - COLS(tb));
if (*returnCount > 0)
{
/*
** we'll have some overflow, figure out how many (if any)
** of the new characters will overflow and put them into
** the overflow buffer...
*/
insertOverflow = numChars - insertCount;
memcpy(*returnChars, newChars + insertCount,
insertOverflow * BYTES_PER_CHAR(tb));
/*
** copy the displaced characters from the line to the
** overflow buffer as well...
*/
memcpy(*returnChars + insertOverflow, BUFFER(line) +
(WIDTH(line) - MAX(0, *returnCount - insertOverflow)),
MAX(0, *returnCount - insertOverflow)
* BYTES_PER_CHAR(tb));
}
/*
** Any overflow has been taken care of, now it's time to make
** room for the new characters...
*/
memmove(start + insertCount, start,
MAX(0, WIDTH(line) - col - *returnCount));
/*
** Compute the new line width...
*/
newWidth = WIDTH(line) + insertCount;
}
/*
** Everything's ready:
** - put the characters into the line
** - adjust the line width (_DtTermPrimBufferSetLineWidth won't
** let the line get shorter)...
** - update the enhancements
*/
memcpy(start, newChars, copyCount);
_DtTermPrimBufferSetLineWidth(tb, row, newWidth);
insertEnhancements(tb, row, col, insertCount, insertFlag);
return(WIDTH(line));
}
/*
** Delete enough characters from the buffer to exceed width.
**
** If returnChars != NULL then the deleted characters are returned
** in a buffer pointed to by returnChars. It is the responsibility
** of the calling function to XtFree the buffer containing returned
** characters when they are no longer needed.
*/
void
_DtTermPrimBufferDelete
(
TermBuffer tb,
short *row,
short *col,
short *width,
termChar **returnChars, /* pointer to delete buffer */
short *returnCount /* count of bytes in delete buffer */
)
{
int copyCount;
TermLine line;
short localRow;
short localCol;
TermCharInfoRec charInfo;
if (!VALID_ROW(tb, *row) || !VALID_COL(tb, *col))
{
if (returnChars)
{
*returnChars = NULL;
*returnCount = 0;
}
return;
}
line = LINE_OF_TBUF(tb, *row);
#ifdef OLD_CODE
/* before we modify the buffer, disown the selection... */
(void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
#endif /* OLD_CODE */
/* if this line is part of the selection, disown the selection... */
if (IS_IN_SELECTION(line, *col, MAX_SELECTION_COL)) {
(void) _DtTermPrimSelectDisown(WIDGET(tb));
}
if (BYTES_PER_CHAR(tb) > 1)
{
/*
** we do not handle multibyte characters here...
*/
_DtTermPrimBufferDeleteWc(tb, row, col, width, returnChars,
returnCount);
return;
}
localRow = *row;
localCol = *col;
*width = MAX(0, MIN(WIDTH(line) - localCol, *width));
/*
** there are 4 cases of deleting a character from a line:
** Case 1:
** the cursor is past the end of the line (col >= WIDTH(line))
**
** Case 2:
** the cursor is in the middle of the line (copyCount > 0)
** - move the remaining characters to the left
** - deleteEnhancement
**
** Case 3:
** the cursor is at the end of the line (copyCount == 0 and
** col == WIDTH(line) - 1)
** - deleteEnhancement
** - adjust WIDTH and LENGTH
*/
if (localCol >= WIDTH(line) || *width == 0)
{
/*
** Handle Case 1...
*/
if (returnChars)
{
*returnChars = NULL;
*returnCount = 0;
}
return;
}
_DtTermPrimGetCharacterInfo(tb, localRow, localCol, &charInfo);
/*
** Save the current characters before we overwrite them...
*/
if (returnChars != NULL)
{
*returnCount = (*width * BYTES_PER_CHAR(tb));
*returnChars = (termChar *)XtMalloc(*returnCount);
memcpy(*returnChars, charInfo.u.pc, *returnCount);
}
/*
** Cases 2 and 3 require that we delete the enhancement...
*/
if (DELETE_ENH(tb))
{
(*DELETE_ENH(tb))(tb, localRow, localCol, *width);
}
copyCount = MAX(0, WIDTH(line) - *width - localCol);
if (copyCount > 0)
{
/*
** handle case 2
*/
memmove(charInfo.u.pc, charInfo.u.pc + *width,
copyCount * BYTES_PER_CHAR(tb));
}
/*
** Case 2 and 3 require that we adjust the line width
*/
WIDTH(line) -= *width;
LENGTH(line) -= *width;
}
/*
** replace all characters between startCol, and stopCol with spaces,
** if startCol > stopCol, then simply return
*/
void
_DtTermPrimBufferErase
(
TermBuffer tb,
short row,
short startCol,
short stopCol
)
{
TermCharInfoRec charInfo;
char *pchar;
/*
** Make sure we have a valid row, and if we have a valid
** row, make sure that startCol is <= stopCol
*/
if (!(VALID_ROW(tb, row)) || (startCol > stopCol))
{
return;
}
#ifdef OLD_CODE
/* before we modify the buffer, disown the selection... */
(void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
#endif /* OLD_CODE */
/* if this line is part of the selection, disown the selection... */
if (IS_IN_SELECTION(LINE_OF_TBUF(tb, row), startCol, stopCol)) {
(void) _DtTermPrimSelectDisown(WIDGET(tb));
}
if (BYTES_PER_CHAR(tb) > 1)
{
_DtTermPrimBufferEraseWc(tb, row, startCol, stopCol);
}
else
{
_DtTermPrimGetCharacterInfo(tb, row, startCol, &charInfo);
pchar = charInfo.u.pc;
_DtTermPrimGetCharacterInfo(tb, row, stopCol, &charInfo);
/*
** replace the characters with spaces...
*/
while(pchar <= charInfo.u.pc)
{
*pchar = ' ';
pchar++;
}
}
}
/*
** Adjust the line width, (the line can never be shortened)
*/
Boolean
_DtTermPrimBufferSetLineWidth
(
const TermBuffer tb,
const short row,
short newWidth
)
{
TermLine line;
/*
** Make sure we have a valid row.
*/
if (!VALID_ROW(tb, row))
{
return(False);
}
line = LINE_OF_TBUF(tb, row);
#ifdef OLD_CODE
/* before we modify the buffer, disown the selection... */
(void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
#endif /* OLD_CODE */
/* if this line is part of the selection, disown the selection... */
if (IS_IN_SELECTION(line, newWidth, MAX_SELECTION_COL)) {
(void) _DtTermPrimSelectDisown(WIDGET(tb));
}
/*
** Clip the new width to the buffer width.
*/
newWidth = MIN(newWidth, COLS(tb));
/*
** Make sure we actually have something to do.
*/
if (WIDTH(line) >= newWidth)
{
return(True);
}
WIDTH(line) = newWidth;
if (BYTES_PER_CHAR(tb) == 1)
{
/*
** in single byte locales, we go ahead and set the line length too,
** it is the responsibility of wide-character routines to set the
** line length themselves...
*/
LENGTH(line) = newWidth; /* works in single byte locales */
}
return(True);
}
/*
** the line length is the lesser of the actual length, or the length
** necessary to get to the buffer width
** (in the case that the buffer shrank after the line was full)
*/
short
_DtTermPrimBufferGetLineLength
(
const TermBuffer tb,
const short row
)
{
short retLen;
short width;
TermCharInfoRec charInfo;
if (VALID_ROW(tb, row))
{
width = MIN(WIDTH(LINE_OF_TBUF(tb, row)), COLS(tb));
if (width > 0)
{
(void)_DtTermPrimGetCharacterInfo(tb, row, width - 1, &charInfo);
/*
** a line can not end on column 1 of 2. Note that we must
** add 1 to the column index to make it the line length...
*/
if ((charInfo.width == 2) && (charInfo.startCol != width - 2)) {
/* only half of charInfo.idx fits in the line, so drop
* it...
*/
retLen = charInfo.idx;
} else {
/* single column character or double column character that
* fits on the line...
*/
retLen = charInfo.idx + 1;
}
}
else
{
retLen = 0;
}
}
else
{
retLen = 0;
}
return(retLen);
}
/*
** the line width is the lesser of the actual width, or the buffer width
** (in the case that the buffer shrank after the line was full)
*/
short
_DtTermPrimBufferGetLineWidth
(
const TermBuffer tb,
const short row
)
{
short width = 0;
TermCharInfoRec charInfo;
if (VALID_ROW(tb, row))
{
width = MIN(WIDTH(LINE_OF_TBUF(tb, row)), COLS(tb));
if (width > 0)
{
(void)_DtTermPrimGetCharacterInfo(tb, row, width - 1, &charInfo);
/*
** a line can not end on column 1 of 2...
*/
if ((charInfo.width == 2) && (charInfo.startCol != width - 2)) {
/* only half of charInfo.idx fits in the line, so drop
* it...
*/
(void) width--;
} else {
/* single column character or double column character that
* fits on the line...
*/
}
}
}
return(width);
}
/**************************************************************************
* Function:
* _DtTermPrimBufferMoveLockArea():
* move locked screen memory up or down in the screen buffer.
*
* Parameters:
* TermBuffer tb: term buffer to use
* short dest: point to move the locked region to
* short src: point to move the locked region from
* short length: size of the locked region
*
* Returns:
* <nothing>
*
* Notes:
*/
void
_DtTermPrimBufferMoveLockArea
(
const TermBuffer tb,
const short dest,
const short src,
const short length
)
{
TermLine lineCache[10];
TermLine *holdLines = lineCache;
TermLine *destPtr;
TermLine *srcPtr;
short cacheSize;
short distance;
int i;
int refLineCount;
TermLine *refLines;
DebugF('B', 1, RememberTermBuffer(tb,&refLines,&refLineCount));
/* don't bother if there is we are being asked to do nothing...
*/
if ((length <= 0) || (dest == src))
return;
#ifdef OLD_CODE
/* before we modify the buffer, disown the selection... */
(void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
#endif /* OLD_CODE */
/* before we modify the buffer, check and see if the leading or
* trailing edge of the buffer crosses the selection and if the
* destination line crosses the selection. If it does, we need
* to disown it...
*/
/* leading edge of src... */
if ((src > 0) &&
IS_IN_SELECTION(LINE_OF_TBUF(tb, src - 1), MIN_SELECTION_COL,
MAX_SELECTION_COL) &&
IS_IN_SELECTION(LINE_OF_TBUF(tb, src), MIN_SELECTION_COL,
MAX_SELECTION_COL)) {
(void) _DtTermPrimSelectDisown(WIDGET(tb));
}
/* trailing edge of src... */
if (((src + length) < ROWS(tb)) &&
IS_IN_SELECTION(LINE_OF_TBUF(tb, src + length - 1),
MIN_SELECTION_COL, MAX_SELECTION_COL) &&
IS_IN_SELECTION(LINE_OF_TBUF(tb, src + length), MIN_SELECTION_COL,
MAX_SELECTION_COL)) {
(void) _DtTermPrimSelectDisown(WIDGET(tb));
}
/* destination... */
if ((dest > 0) && IS_IN_SELECTION(LINE_OF_TBUF(tb, dest - 1),
MIN_SELECTION_COL, MAX_SELECTION_COL) &&
IS_IN_SELECTION(LINE_OF_TBUF(tb, dest),
MIN_SELECTION_COL, MAX_SELECTION_COL)) {
(void) _DtTermPrimSelectDisown(WIDGET(tb));
}
/* we need to save the line positions of the smaller of the length
* of the chunk to move, or the distance to move the chunk.
*/
distance = (dest > src) ? (dest - src) : (src - dest);
cacheSize = MIN(length, distance);
/* if we are moving more lines than will fit in the lineCache, we need
* to malloc (and free) storage for the termLineRecs...
*/
if (cacheSize > (sizeof(lineCache) / sizeof(lineCache[0]))) {
holdLines = (TermLine *) XtMalloc(cacheSize * sizeof(TermLine));
}
/*
** clear the wrap flag for the line preceding the block to be
** moved, and the last line of the block to be moved
*/
_DtTermPrimBufferSetLineWrapFlag(tb, src - 1, FALSE);
_DtTermPrimBufferSetLineWrapFlag(tb, src + length, FALSE);
/* cache them away... */
if (distance > length) {
/* save away the locked area... */
destPtr = holdLines;
srcPtr = &(LINE_OF_TBUF(tb, src));
for (i = 0; i < length; i++) {
*destPtr++ = *srcPtr++;
}
/* move the area above/below the locked area... */
if (dest > src) {
/* we are moving the locked area down, so we must move
* the scroll area up...
*/
destPtr = &(LINE_OF_TBUF(tb, src));
srcPtr = &(LINE_OF_TBUF(tb, src + length));
for (i = 0; i < distance; i++) {
*destPtr++ = *srcPtr++;
}
} else {
/* we are moving the locked area up, so we must move
* the scroll area down...
*/
destPtr = &(LINE_OF_TBUF(tb, src + length - 1));
srcPtr = &(LINE_OF_TBUF(tb, src - 1));
for (i = 0; i < distance; i++) {
*destPtr-- = *srcPtr--;
}
}
/* restore the cached lock area... */
destPtr = &(LINE_OF_TBUF(tb, dest));
srcPtr = holdLines;
for (i = 0; i < length; i++) {
*destPtr++ = *srcPtr++;
}
} else {
/* save away the area we will move the lock area over...
*/
if (dest > src) {
/* moving it down. Save the area under the lock area...
*/
destPtr = holdLines;
srcPtr = &(LINE_OF_TBUF(tb, src + length));
for (i = 0; i < distance; i++) {
*destPtr++ = *srcPtr++;
}
/* move the lock area down... */
destPtr = &(LINE_OF_TBUF(tb, dest + length - 1));
srcPtr = &(LINE_OF_TBUF(tb, src + length - 1));
for (i = 0; i < length; i++) {
*destPtr-- = *srcPtr--;
}
/* restore the area under (that is now over) the lock area... */
destPtr = &(LINE_OF_TBUF(tb, src));
srcPtr = holdLines;
for (i = 0; i < distance; i++) {
*destPtr++ = *srcPtr++;
}
} else {
/* moving it up. Save the area over the lock area...
*/
destPtr = holdLines;
srcPtr = &(LINE_OF_TBUF(tb, dest));
for (i = 0; i < distance; i++) {
*destPtr++ = *srcPtr++;
}
/* move the lock area up... */
destPtr = &(LINE_OF_TBUF(tb, dest));
srcPtr = &(LINE_OF_TBUF(tb, src));
for (i = 0; i < length; i++) {
*destPtr++ = *srcPtr++;
}
/* restore the area over (that is now under) the lock area... */
destPtr = &(LINE_OF_TBUF(tb, dest + length));
srcPtr = holdLines;
for (i = 0; i < distance; i++) {
*destPtr++ = *srcPtr++;
}
}
}
/* free up the holdLines (if we malloc'ed it)... */
if (holdLines != lineCache) {
(void) XtFree((char *) holdLines);
}
DebugF('B', 1, CheckTermBuffer(tb,refLines,refLineCount));
}
/**************************************************************************
* Function:
* _DtTermPrimBufferInsertLine(): insert one or more lines of text from
* the end of the buffer below the insertion point, or from
* the beginning of the buffer above the insertion point.
*
* Parameters:
* TermBuffer tb: term buffer to insert end/begining into
* short dest: point to insert below/above
* short length: number of lines to insert
* short src: source point of insertion
*
* Returns:
* <nothing>
*
* Notes:
*/
void
_DtTermPrimBufferInsertLine
(
const TermBuffer tb,
const short dest,
const short length,
const short src
)
{
TermLine lineCache[10];
TermLine *holdLines = lineCache;
TermLine *destPtr;
TermLine *srcPtr;
short distance;
int i;
int refLineCount;
TermLine *refLines;
DebugF('B', 1, RememberTermBuffer(tb,&refLines,&refLineCount));
/* don't bother if there is we are being asked to do nothing...
*/
if (length <= 0)
return;
#ifdef OLD_CODE
/* before we modify the buffer, disown the selection... */
(void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
#endif /* OLD_CODE */
/* before we modify the buffer, check and see if the
* destination line crosses the selection. If it does, we need
* to disown it...
*/
/* destination... */
if (dest > src) {
if (((dest + length) < ROWS(tb)) &&
IS_IN_SELECTION(LINE_OF_TBUF(tb, dest + length),
MIN_SELECTION_COL, MAX_SELECTION_COL) &&
IS_IN_SELECTION(LINE_OF_TBUF(tb, dest + length + 1),
MIN_SELECTION_COL, MAX_SELECTION_COL)) {
(void) _DtTermPrimSelectDisown(WIDGET(tb));
}
} else {
if (dest > 1) {
if (IS_IN_SELECTION(LINE_OF_TBUF(tb, dest),
MIN_SELECTION_COL, MAX_SELECTION_COL) &&
IS_IN_SELECTION(LINE_OF_TBUF(tb, dest - 1),
MIN_SELECTION_COL, MAX_SELECTION_COL)) {
(void) _DtTermPrimSelectDisown(WIDGET(tb));
}
}
}
/* if we are being asked to move all (or more) the lines in the
* buffer, then we can just clear them all out and return...
*/
if (length >= ROWS(tb)) {
for (i = 0; i < ROWS(tb); i++) {
_DtTermPrimBufferClearLine(tb, i, 0);
}
return;
}
/* if dest and src match, we can just clear them out and return...
*/
if (src == dest) {
for (i = 0; (i < length) && ((i + dest) < ROWS(tb)); i++) {
_DtTermPrimBufferClearLine(tb, src + i, 0);
}
return;
}
/* if we are moving more lines than will fit in the lineCache, we need
* to malloc (and free) storage for the termLineRecs...
*/
if (length > (sizeof(lineCache) / sizeof(lineCache[0]))) {
holdLines = (TermLine *) XtMalloc(length * sizeof(TermLine));
}
if (dest > src) {
/* our src is above the destination. Copy the lines to insert,
* move the lines above the insertion pointer up, and insert
* the saved lines...
*/
/* save away the top length lines... */
destPtr = holdLines;
srcPtr = &(LINE_OF_TBUF(tb, src));
for (i = 0; i < length; i++) {
/* these lines will be cleared, so we don't need to track
* movement of them...
*/
*destPtr++ = *srcPtr++;
}
/* copy the lines above the insertion point up... */
destPtr = &(LINE_OF_TBUF(tb, src));
srcPtr = &(LINE_OF_TBUF(tb, src + length));
for (i = src; i < dest - length + 1; i++) {
*destPtr++ = *srcPtr++;
}
/* restore the saved lines above the insertion point... */
destPtr = &(LINE_OF_TBUF(tb, dest - length + 1));
srcPtr = holdLines;
for (i = 0; i < length; i++) {
*destPtr = *srcPtr;
/* clear the line... */
_DtTermPrimBufferClearLine(tb, dest - length + 1 + i, 0);
*destPtr++;
*srcPtr++;
}
#ifdef DONT_DO_THIS_ANY_MORE
/* Adjust or disown selection */
_DtTermPrimSelectDeleteLine(tb,length) ;
#endif /* DONT_DO_THIS_ANY_MORE */
} else {
/* our src is below the destination. Copy the lines to insert,
* move the lines below the insertion pointer down, and insert
* the saved lines...
*/
/* save away the bottom length lines... */
destPtr = holdLines;
srcPtr = &(LINE_OF_TBUF(tb, src));
for (i = 0; i < length; i++) {
*destPtr++ = *srcPtr++;
}
/* copy the lines below the insertion point down... */
destPtr = &(LINE_OF_TBUF(tb, src + length - 1));
srcPtr = &(LINE_OF_TBUF(tb, src - 1));
for (i = 0; i < src - dest; i++) {
*destPtr-- = *srcPtr--;
}
/* restore the saved lines below the insertion point... */
destPtr = &(LINE_OF_TBUF(tb, dest));
srcPtr = holdLines;
for (i = 0; i < length; i++) {
*destPtr = *srcPtr;
/* clear the line... */
_DtTermPrimBufferClearLine(tb, dest + i, 0);
*destPtr++;
*srcPtr++;
}
}
/* free up the holdLines (if we malloc'ed it)... */
if (holdLines != lineCache) {
(void) XtFree((char *) holdLines);
}
DebugF('B', 1, CheckTermBuffer(tb,refLines,refLineCount));
}
/**************************************************************************
* Function:
* _DtTermPrimBufferInsertLineFromTB(): insert one or more lines
* of text from the end of the buffer below the insertion
* point, or from the beginning of the buffer above the
* insertion point.
*
* Parameters:
* TermBuffer tb: term buffer to insert end/begining into
* short dest: point to insert below/above
* short length: number of lines to insert
* InsertSource: source of insertion (end or beginning)
*
* Returns:
* <nothing>
*
* Notes:
*/
void
_DtTermPrimBufferInsertLineFromTB
(
const TermBuffer tb,
const short dest,
const short length,
const InsertSource insertSource
)
{
if (insertSource == insertFromTop) {
(void) _DtTermPrimBufferInsertLine(tb, dest, length, 0);
} else {
(void) _DtTermPrimBufferInsertLine(tb, dest, length,
ROWS(tb) - length);
}
}
#ifdef NOTDONE
/**************************************************************************
* Function:
* _DtTermPrimBufferScrollToHistory(): scroll one or more lines
* of text from the beginning of the active buffer into
* the history buffer.
*
* Parameters:
* TermBuffer tb: term buffer to scroll out of
* short length: number of lines to scroll
*
* Returns:
* the number of lines scrolled (removed from active buffer)
*
* Notes:
*/
int
_DtTermPrimBufferScrollToHistory()
(
const TermBuffer tb,
const short length,
)
{
if (PREV_BUFFER(tb)) {
}
#endif /* NOTDONE */
/**************************************************************************
* Function:
* _DtTermPrimBufferDeleteLine(): deletes one or more lines of text from
* the deletion poing and sticks them at the end of the
* line buffer. It does not clear the line. That is
* normally done when the line is inserted.
*
* Parameters:
* TermBuffer tb: term buffer to insert end/begining into
* short source: point to insert below/above
* short length: number of lines to insert
* short lastUsedLine: number of last line in the buffer we need
* to keep
*
* Returns:
* <nothing>
*
* Notes:
*/
void
_DtTermPrimBufferDeleteLine
(
const TermBuffer tb,
const short source,
const short length,
const short lastUsedRow
)
{
TermLine lineCache[10];
TermLine *holdLines = lineCache;
TermLine *destPtr;
TermLine *srcPtr;
short copyLength;
int i;
int refLineCount;
TermLine *refLines;
DebugF('B', 1, RememberTermBuffer(tb,&refLines,&refLineCount));
/* don't bother if there is we are being asked to do nothing...
*/
if (length <= 0)
return;
/* if we are being asked to move the last usedLines, we don't have
* to do anything either...
*/
if (source + length >= lastUsedRow)
return;
#ifdef OLD_CODE
/* before we modify the buffer, disown the selection... */
(void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
#endif /* OLD_CODE */
/* if we are moving more lines than will fit in the lineCache, we need
* to malloc (and free) storage for the termLineRecs...
*/
if (length > (sizeof(lineCache) / sizeof(lineCache[0]))) {
holdLines = (TermLine *) XtMalloc(length * sizeof(TermLine));
}
/* clear the deleted lines... */
for (i = 0; i < length; i++) {
(void) _DtTermPrimBufferClearLine(tb, source + i, 0);
}
#ifdef USE_MEMCPY
(void) memcpy(holdLines, &(LINE_OF_TBUF(tb, source)), length *
sizeof(TermLine));
#else /* USE_MEMCPY */
destPtr = holdLines;
srcPtr = &(LINE_OF_TBUF(tb, source));
for (i = 0; i < length; i++) {
*destPtr++ = *srcPtr++;
}
#endif /* USE_MEMCPY */
/* ripple up the lines... */
copyLength = MAX(0, MIN(ROWS(tb), lastUsedRow) - source - length);
if (copyLength > 0) {
#ifdef USE_MEMCPY
(void) memmove(&(LINE_OF_TBUF(tb, source)),
&(LINE_OF_TBUF(tb, source + length)),
copyLength * sizeof(TermLine));
#else /* USE_MEMCPY */
destPtr = &(LINE_OF_TBUF(tb, source));
srcPtr = &(LINE_OF_TBUF(tb, source + length));
for (i = 0; i < copyLength; i++) {
*destPtr++ = *srcPtr++;
}
#endif /* USE_MEMCPY */
}
/* copy back the deleted (cached) lines... */
#ifdef USE_MEMCPY
(void) memcpy(&(LINE_OF_TBUF(tb, source + copyLength)), holdLines,
length * sizeof(TermLine));
#else /* USE_MEMCPY */
destPtr = &(LINE_OF_TBUF(tb, source + copyLength));
srcPtr = holdLines;
for (i = 0; i < length; i++) {
*destPtr++ = *srcPtr++;
}
#endif /* USE_MEMCPY */
/* free up the holdLines (if we malloc'ed it)... */
if (holdLines != lineCache) {
(void) XtFree((char *) holdLines);
}
DebugF('B', 1, CheckTermBuffer(tb,refLines,refLineCount));
}
/*
** Pad the requested row from the current width to 'newWidth' with spaces...
*/
void
_DtTermPrimBufferPadLine
(
const TermBuffer tb,
const short row,
const short newWidth
)
{
TermLine line;
#ifdef OLD_CODE
/* before we modify the buffer, disown the selection... */
(void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
#endif /* OLD_CODE */
line = LINE_OF_TBUF(tb, row);
/* if this line is part of the selection, disown the selection... */
if (IS_IN_SELECTION(line, MIN(newWidth, WIDTH(line)),
MAX(newWidth, WIDTH(line)))) {
(void) _DtTermPrimSelectDisown(WIDGET(tb));
}
(void)memset(BUFFER(line) + WIDTH(line),
0x20, (newWidth - WIDTH(line)) * BYTES_PER_CHAR(tb));
if (CLEAR_ENH(tb))
{
(*CLEAR_ENH(tb))(tb, row, WIDTH(line), newWidth - WIDTH(line));
}
_DtTermPrimBufferSetLineWidth(tb, row, newWidth);
}
/*
** Clear the line to the new width (just reset the line width).
** NOTES:
** We also clear the wrapped flag as well.
*/
Boolean
_DtTermPrimBufferClearLine
(
const TermBuffer tb,
const short row,
short newWidth
)
{
TermLine line;
#ifdef OLD_CODE
/* before we modify the buffer, disown the selection... */
(void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
#endif /* OLD_CODE */
/*
** handle multi-byte locales...
*/
if (BYTES_PER_CHAR(tb) > 1)
{
return(_DtTermPrimBufferClearLineWc(tb, row, newWidth));
}
/*
** Some simple bounds checking.
*/
if (!VALID_ROW(tb, row))
{
return(False);
}
line = LINE_OF_TBUF(tb, row);
/* if this line is part of the selection, disown the selection... */
if (IS_IN_SELECTION(line, MIN(newWidth, WIDTH(line)),
MAX(newWidth, WIDTH(line)))) {
(void) _DtTermPrimSelectDisown(WIDGET(tb));
}
/*
** Clip the new width to the buffer width.
*/
newWidth = MIN(newWidth, COLS(tb));
/*
** force width to the desired value
**
** (We take the direct approach because _DtTermPrimBufferSetLineWidth
** doesn't allow the line width to decrease.)
*/
if (newWidth < WIDTH(line))
{
/*
** Call the helper function if it exists
*/
if (CLEAR_LINE(tb))
{
(*CLEAR_LINE(tb))(tb, row, newWidth);
}
WRAPPED(line) = False;
WIDTH(line) = newWidth;
LENGTH(line) = newWidth; /* this works in single-byte locales */
}
return(True);
}
short
_DtTermPrimBufferGetNextTab
(
const TermBuffer tb,
short col
)
{
if (!VALID_COL(tb, col))
{
return(0);
}
/* find the next set tab stop... */
for (col++; (col < COLS(tb)) && (!TABS(tb)[col]); col++)
;
/* did we go to the end of the line w/out hitting one?... */
if (col >= COLS(tb)) {
return(0);
} else {
return(col);
}
}
short
_DtTermPrimBufferGetPreviousTab
(
const TermBuffer tb,
short col
)
{
if (!VALID_COL(tb, col - 1))
{
return(0);
}
/* find the next set tab stop... */
for (col--; (col > 0) && (!TABS(tb)[col]); col--)
;
/* we can just return col. If ther was not another tab stop, it will
* be -1...
*/
return(col);
}
Boolean
_DtTermPrimBufferSetTab
(
const TermBuffer tb,
const short col
)
{
if (VALID_COL(tb, col))
{
TABS(tb)[col] = True;
return(True);
}
return(False);
}
Boolean
_DtTermPrimBufferClearTab
(
const TermBuffer tb,
const short col
)
{
if (VALID_COL(tb, col))
{
TABS(tb)[col] = False;
return(True);
}
return(False);
}
Boolean
_DtTermPrimBufferClearAllTabs
(
const TermBuffer tb
)
{
(void) memset(TABS(tb), '\0', COLS(tb) * sizeof(Boolean));
return(True);
}
/*
** Set the line wrap flag to the desired state.
*/
void
_DtTermPrimBufferSetLineWrapFlag
(
TermBuffer tb,
short row,
Boolean state
)
{
if (VALID_ROW(tb, row))
{
WRAPPED(LINE_OF_TBUF(tb, row)) = state;
}
return;
}
/*
** Return the state of the line wrap flag.
*/
Boolean
_DtTermPrimBufferTestLineWrapFlag
(
TermBuffer tb,
short row
)
{
if (VALID_ROW(tb, row))
{
return(WRAPPED(LINE_OF_TBUF(tb, row)));
}
else
{
return(FALSE);
}
}
/*
** Set the in selection flag to the desired state.
*/
void
_DtTermPrimBufferSetInSelectionFlag
(
TermBuffer tb,
short row,
TermLineSelection state
)
{
if (VALID_ROW(tb, row))
{
if (state) {
START_SELECTION(LINE_OF_TBUF(tb, row)) = state->selectionStart;
END_SELECTION(LINE_OF_TBUF(tb, row)) = state->selectionEnd;
} else {
START_SELECTION(LINE_OF_TBUF(tb, row)) = NON_SELECTION_COL;
END_SELECTION(LINE_OF_TBUF(tb, row)) = NON_SELECTION_COL;
}
}
return;
}
/*
** Return the state of the in selection flag.
*/
TermLineSelection
_DtTermPrimBufferGetInSelectionFlag
(
TermBuffer tb,
short row
)
{
if (VALID_ROW(tb, row))
{
if ((START_SELECTION(LINE_OF_TBUF(tb, row)) != NON_SELECTION_COL) &&
(END_SELECTION(LINE_OF_TBUF(tb, row)) != NON_SELECTION_COL)) {
return(&IN_SELECTION(LINE_OF_TBUF(tb, row)));
}
}
return((TermLineSelection) 0);
}
void
_DtTermPrimBufferSetSelectLines
(
TermBuffer tb,
short beginRow,
short beginCol,
short endRow,
short endCol
)
{
int i1;
for (i1 = 0; i1 < ROWS(tb); i1++) {
if ((i1 >= beginRow) && (i1 <= endRow)) {
if (i1 == beginRow) {
START_SELECTION(LINE_OF_TBUF(tb, i1)) = beginCol;
} else {
START_SELECTION(LINE_OF_TBUF(tb, i1)) = MIN_SELECTION_COL;
}
if (i1 == endRow) {
END_SELECTION(LINE_OF_TBUF(tb, i1)) = endCol;
} else {
END_SELECTION(LINE_OF_TBUF(tb, i1)) = MAX_SELECTION_COL;
}
} else {
START_SELECTION(LINE_OF_TBUF(tb, i1)) = NON_SELECTION_COL;
END_SELECTION(LINE_OF_TBUF(tb, i1)) = NON_SELECTION_COL;
}
}
}
#if (defined(TEST) || defined(__CODECENTER__) || defined(DEBUG))
static void
_termBufferPrintLine
(
const TermBuffer tb,
const short row
)
{
TermLine line;
termChar *pChar;
short j;
printf("Line: %d\n", row);
line = LINE_OF_TBUF(tb, row];
printf(" width: %3d\n", WIDTH(line));
printf(" length: %3d\n", LENGTH(line));
if (LENGTH(line) > 0)
{
printf(" buffer: <");
pChar = BUFFER(line);
for (j = 0; j < LENGTH(line); j++)
{
printf("%X", *pChar++);
}
printf(">\n");
}
}
/*
** Print the contents of the TermBuffer.
*/
static void
_termBufferPrintBuffer
(
const TermBuffer tb
)
{
short i;
short j;
short k;
if (tb == NULL) {
printf("TermBuffer has been freed.\n");
return;
}
printf("TermBuffer dimensions:\n");
printf(" rows: %d\n", ROWS(tb));
printf(" cols: %d\n", COLS(tb));
for (i = 0; i < ROWS(tb); i++)
{
_termBufferPrintLine(tb, i);
}
}
#endif /* (defined(TEST) || defined(__CODECENTER__)) */
#ifdef TEST
/*
** Some simple tests of the termBuffer.
*/
/* the following is to allow for a single main function in the code... */
#define termBufMain main
termBufMain()
{
const TermBuffer myTB;
printf("Sizeof termEnhRec : %d\n", sizeof(struct _termEnhRec));
printf("Sizeof termBufferRec : %d\n", sizeof(struct _TermBufferRec));
myTB = _DtTermPrimBufferCreateBuffer(12, 80);
_termBufferPrintBuffer(myTB);
printf("[0,0] %d\n", _DtTermPrimBufferSetEnhancement(myTB, 0, 0, enhVideo, BLINK));
_termBufferPrintEnhancement(myTB, 0, 0);
printf("[0,1] %d\n", _DtTermPrimBufferSetEnhancement(myTB, 0, 1, enhVideo, INVERSE));
_termBufferPrintEnhancement(myTB, 0, 0);
_termBufferPrintEnhancement(myTB, 0, 1);
printf("[0,9] %d\n", _DtTermPrimBufferSetEnhancement(myTB, 0, 9, enhVideo, UNDERLINE));
_termBufferPrintEnhancement(myTB, 0, 0);
_termBufferPrintEnhancement(myTB, 0, 1);
_termBufferPrintEnhancement(myTB, 0, 9);
printf("[0,6] %d\n", _DtTermPrimBufferSetEnhancement(myTB, 0, 6, enhVideo, HALF_BRIGHT));
_termBufferPrintEnhancement(myTB, 0, 0);
_termBufferPrintEnhancement(myTB, 0, 1);
_termBufferPrintEnhancement(myTB, 0, 6);
_termBufferPrintEnhancement(myTB, 0, 9);
_termBufferPrintBuffer(myTB);
_DtTermPrimBufferSetEnhancement(myTB, 10, 10, enhVideo, BLINK);
_DtTermPrimBufferSetEnhancement(myTB, 10, 20, enhColor, 3);
_termBufferPrintBuffer(myTB);
_DtTermPrimBufferResizeBuffer(&myTB, 6, 40);
_termBufferPrintBuffer(myTB);
_DtTermPrimBufferSetEnhancement(myTB, 10, 10, enhVideo, BLINK);
_DtTermPrimBufferResizeBuffer(&myTB, 12, 80);
_termBufferPrintBuffer(myTB);
_DtTermPrimBufferFreeBuffer(myTB);
}
#endif /* TEST */