cdesktopenv/cde/lib/DtTerm/TermPrim/TermPrimPendingText.c

432 lines
10 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 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 Hewlett-Packard Company *
* (c) Copyright 1993, 1994 International Business Machines Corp. *
* (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
* (c) Copyright 1993, 1994 Novell, Inc. *
*/
#include <stdio.h>
#include <X11/Intrinsic.h>
#include "TermHeader.h"
#include "TermPrimDebug.h"
#include "TermPrimPendingTextP.h"
static
PendingTextChunk
mallocChunk(int len);
#ifdef DEBUG
void
walkPendingText
(
PendingText list
)
{
PendingTextChunk chunk;
fprintf(stderr, "head: %lx\n", list->head);
fprintf(stderr, "tail: %lx\n", list->tail);
for (chunk = list->head; chunk != list->tail; chunk = chunk->next)
{
fprintf(stderr, "chunk: 0x%lx\n", chunk);
fprintf(stderr, " buffer : %c\n", chunk->buffer[0]);
fprintf(stderr, " buffLen: %d\n", chunk->buffLen);
fprintf(stderr, " bufPtr : %c\n", chunk->bufPtr[0]);
fprintf(stderr, " len : %d\n", chunk->len);
fprintf(stderr, " next : 0x%lx\n", chunk->next);
fprintf(stderr, " prev : 0x%lx\n", chunk->prev);
}
}
#endif /* DEBUG */
/*
** Allocate, and initialize a new PendingTextChunk.
*/
static
PendingTextChunk
mallocChunk(int len)
{
PendingTextChunk newChunk;
Debug('q', fprintf(stderr, ">>mallocChunk() starting\n"));
newChunk = (PendingTextChunk) XtMalloc(sizeof(PendingTextChunkRec));
if (!newChunk)
{
return((PendingTextChunk) NULL);
}
newChunk->buffLen = len;
newChunk->buffer = (unsigned char *) XtMalloc(newChunk->buffLen);
if (!newChunk->buffer)
{
XtFree((char *) newChunk);
return((PendingTextChunk) NULL);
}
/*
** Finish initializing the new chunk.
*/
newChunk->bufPtr = newChunk->buffer;
newChunk->len = 0;
newChunk->next = (PendingTextChunk)NULL;
newChunk->prev = (PendingTextChunk)NULL;
return(newChunk);
}
/*
** Add a new pending text chunk to the end of the list. If possible, reuse
** an existing chunk, else allocate a new one. Return true if successful,
** else return false.
*/
PendingTextChunk
_DtTermPrimPendingTextAppendChunk
(
PendingText list,
int len
)
{
PendingTextChunk newChunk;
Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextAppendChunk() starting\n"));
#ifdef DEBUG
walkPendingText(list);
#endif /* DEBUG */
#ifdef RECYCLE_CHUNKS
if (list->free)
{
/*
** There are chunks on the free list, this will
** be easy.
*/
newChunk = list->free;
}
else
{
/*
** We have no free chunks.
*/
newChunk = mallocChunk(len);
if (!newChunk)
{
return(PendingTextChunk(NULL));
}
}
/*
** append the new chunk to the list...
*/
list->free = list->free->next;
newChunk->next = (PendingTextChunk)NULL;
list->tail->next = newChunk;
list->tail = newChunk;
return(True);
#else /* RECYCLE_CHUNKS */
/*
** Create a new chunk.
*/
newChunk = mallocChunk(len);
if (!newChunk)
{
return((PendingTextChunk)NULL);
}
newChunk->next = list->tail;
newChunk->prev = list->tail->prev;
list->tail->prev->next = newChunk;
list->tail->prev = newChunk;
return(newChunk);
#endif /* RECYCLE_CHUNKS */
}
void
_DtTermPrimPendingTextReplace
(
PendingTextChunk chunk,
unsigned char *buffer,
int bufferLen
)
{
chunk->buffer = (unsigned char *) XtRealloc((char *) chunk->buffer,
bufferLen);
chunk->buffLen = bufferLen;
chunk->bufPtr = chunk->buffer;
chunk->len = bufferLen;
(void) memmove(chunk->buffer, buffer, bufferLen);
}
/*
** Remove a pending text chunk from the head of the list, and add it to
** the free list.
*/
void
_DtTermPrimPendingTextRemoveChunk
(
PendingText list,
PendingTextChunk chunk
)
{
Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextRemoveChunk() starting\n"));
#ifdef DEBUG
walkPendingText(list);
#endif /* DEBUG */
/*
** add the chunk to the free list...
*/
/* don't allow removal of either head or tail... */
if ((chunk == list->head) || (chunk == list->tail)) {
return;
}
chunk->prev->next = chunk->next;
chunk->next->prev = chunk->prev;
#ifdef RECYCLE_CHUNKS
chunk->len = 0;
chunk->next = list->free;
list->free = chunk;
#else /* RECYCLE_CHUNKS */
XtFree((char *) chunk->buffer);
XtFree((char *) chunk);
#endif /* RECYCLE_CHUNKS */
}
/* Check to see if there is any pending text in the pending text list...
*/
Boolean
_DtTermPrimPendingTextIsPending
(
PendingText list
)
{
if (list->head->next != list->tail) {
return(True);
}
return(False);
}
/*
** Get a pending text chunk from the head of the list.
*/
PendingTextChunk
_DtTermPrimPendingTextGetChunk
(
PendingText list
)
{
Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextGetChunk() starting\n"));
#ifdef DEBUG
walkPendingText(list);
#endif /* DEBUG */
if (list->head->next != list->tail) {
return(list->head->next);
} else {
return((PendingTextChunk) 0);
}
}
/*
** Flush a pending text list. This function takes the easy way out of
** calling _DtTermPrimPendingTextGetChunk() to get each chunk and
** _DtTermPrimPendingTextRemoveChunk() to remove them.
*/
void
_DtTermPrimPendingTextFlush
(
PendingText list
)
{
PendingTextChunk chunk;
Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextFlush() starting\n"));
#ifdef DEBUG
walkPendingText(list);
#endif /* DEBUG */
while ((chunk = _DtTermPrimPendingTextGetChunk(list))) {
(void) _DtTermPrimPendingTextRemoveChunk(list, chunk);
}
}
/*
** Append the supplied text to the pending text list. Return True if
** all text was appended, else return False.
*/
Boolean
_DtTermPrimPendingTextAppend
(
PendingText list,
unsigned char *text,
int len
)
{
PendingTextChunk newChunk;
PendingTextChunk oldTail;
Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextAppend() starting\n"));
#ifdef DEBUG
walkPendingText(list);
#endif /* DEBUG */
/*
** remember this if we are unable to get all the text
** into the list
*/
oldTail = list->tail->prev;
/*
** add a new chunk to the list
*/
while (len > 0)
{
newChunk = _DtTermPrimPendingTextAppendChunk(list,
(len > DEFAULT_CHUNK_BUF_SIZE) ? DEFAULT_CHUNK_BUF_SIZE : len);
if (!newChunk)
{
/*
** the allocation failed, free up all newly created
** chunks and return...
*/
while (oldTail != list->tail->prev)
{
_DtTermPrimPendingTextRemoveChunk(list, list->tail->prev);
}
return(False);
}
/*
** chunk buffers are a fixed size, copy a much as possible
** from 'text' to the chunk buffer, then adjust 'len'...
*/
newChunk->len = MIN(len, newChunk->buffLen);
(void)memcpy(newChunk->buffer, text, newChunk->len);
len -= newChunk->buffLen;
}
return(True);
}
/*
** Write a pending text chunk from the head of the list.
*/
void
_DtTermPrimPendingTextWrite
(
PendingText list,
int fd
)
{
int bytesWritten = 0;
PendingTextChunk chunk;
Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextWrite() starting\n"));
#ifdef DEBUG
walkPendingText(list);
#endif /* DEBUG */
chunk = list->head->next;
Debug('q', fprintf(stderr, ">> len: %3.3d\n", chunk->len));
Debug('q', fprintf(stderr, ">> bufPtr: <%*.*s>\n",
chunk->len, chunk->len, chunk->bufPtr));
bytesWritten = write(fd, chunk->bufPtr, chunk->len <= MAX_PTY_WRITE ?
chunk->len : MAX_PTY_WRITE);
if (bytesWritten < 0) {
#ifdef DEBUG
fprintf(stderr, "_DtTermPrimPendingTextWrite: write failed\n");
#endif
bytesWritten = 0;
}
if ((chunk->len -= bytesWritten) <= 0) {
/*
** All text in this chunk has been written,
** remove it from the list.
*/
_DtTermPrimPendingTextRemoveChunk(list, chunk);
}
else {
/*
** only some of the text in this chunk was written,
** simply adjust the write pointer...
** (list->head->len was adjusted above)
*/
chunk->bufPtr += bytesWritten;
}
}
PendingText
_DtTermPrimPendingTextCreate(
void
)
{
PendingText ptr;
Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextCreate() starting\n"));
ptr = (PendingText) XtMalloc(sizeof(PendingTextRec));
(void) memset(ptr, '\0', sizeof(PendingTextRec));
ptr->head = (PendingTextChunk) XtMalloc(sizeof(PendingTextChunkRec));
(void) memset(ptr->head, '\0', sizeof(PendingTextChunkRec));
ptr->tail = (PendingTextChunk) XtMalloc(sizeof(PendingTextChunkRec));
(void) memset(ptr->tail, '\0', sizeof(PendingTextChunkRec));
ptr->head->next = ptr->tail;
ptr->tail->prev = ptr->head;
#ifdef DEBUG
walkPendingText(ptr);
#endif /* DEBUG */
return(ptr);
}
void
_DtTermPrimPendingTextDestroy(
PendingText ptr
)
{
PendingTextChunk chunk;
Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextDestroy() starting\n"));
#ifdef DEBUG
#undef DEBUG
walkPendingText(ptr);
#endif /* DEBUG */
if (ptr) {
while (ptr->head) {
chunk = ptr->head;
ptr->head = ptr->head->next;
if (chunk->buffer) {
(void) XtFree((char *) chunk->buffer);
}
(void) XtFree((char *) chunk);
}
(void) XtFree((char *) ptr);
}
}