/* * 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 libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* * * (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... */ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 600 #endif #include #include #include #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 accommodate 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: * * * 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: * * * 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: * * * 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); } } /************************************************************************** * 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: * * * 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 */