Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtTerm / TermPrim / TermPrimPendingText.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 #ifndef lint
24 #ifdef  VERBOSE_REV_INFO
25 static char rcs_id[] = "$TOG: TermPrimPendingText.c /main/3 1997/07/03 15:40:05 samborn $";
26 #endif  /* VERBOSE_REV_INFO */
27 #endif  /* lint */
28
29 /*                                                                      *
30  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
31  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
32  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
33  * (c) Copyright 1993, 1994 Novell, Inc.                                *
34  */
35
36 #include <stdio.h>
37 #include <X11/Intrinsic.h>
38 #include "TermHeader.h"
39 #include "TermPrimDebug.h"
40 #include "TermPrimPendingTextP.h"
41
42 #ifdef __osf__
43 #include <termios.h>
44 #include <poll.h>
45 #endif /* __osf__ */
46
47 static
48 PendingTextChunk
49 mallocChunk(int len);
50
51 #ifdef    DEBUG
52 void
53 walkPendingText
54 (
55     PendingText     list
56 )
57 {
58     PendingTextChunk chunk;
59
60     fprintf(stderr, "head: %lx\n", list->head);
61     fprintf(stderr, "tail: %lx\n", list->tail);
62
63     for (chunk = list->head; chunk != list->tail; chunk = chunk->next)
64     {
65         fprintf(stderr, "chunk: 0x%lx\n", chunk);
66         fprintf(stderr, "    buffer : %c\n", chunk->buffer[0]);
67         fprintf(stderr, "    buffLen: %d\n", chunk->buffLen);
68         fprintf(stderr, "    bufPtr : %c\n", chunk->bufPtr[0]);
69         fprintf(stderr, "    len    : %d\n", chunk->len);
70         fprintf(stderr, "    next   : 0x%lx\n", chunk->next);
71         fprintf(stderr, "    prev   : 0x%lx\n", chunk->prev);
72     }
73 }
74 #endif /* DEBUG  */
75
76 /* 
77 ** Allocate, and initialize a new PendingTextChunk.
78 */
79 static 
80 PendingTextChunk
81 mallocChunk(int len)
82 {
83     PendingTextChunk    newChunk;
84     
85     Debug('q', fprintf(stderr, ">>mallocChunk() starting\n"));
86
87     newChunk = (PendingTextChunk) XtMalloc(sizeof(PendingTextChunkRec));
88     if (!newChunk)
89     {
90         return((PendingTextChunk) NULL);
91     }
92
93     newChunk->buffLen = len;
94     newChunk->buffer  = (unsigned char *) XtMalloc(newChunk->buffLen);
95     if (!newChunk->buffer)
96     {
97         XtFree((char *) newChunk);
98         return((PendingTextChunk) NULL);
99     }
100     
101     /*
102     ** Finish initializing the new chunk.
103     */
104     newChunk->bufPtr = newChunk->buffer;
105     newChunk->len   = 0;
106     newChunk->next  = (PendingTextChunk)NULL;
107     newChunk->prev  = (PendingTextChunk)NULL;
108     return(newChunk);
109 }
110
111 /* 
112 ** Add a new pending text chunk to the end of the list.  If possible, reuse
113 ** an existing chunk, else allocate a new one.   Return true if successful,
114 ** else return false.
115 */
116 PendingTextChunk
117 _DtTermPrimPendingTextAppendChunk
118 (
119     PendingText list,
120     int         len
121 )
122 {
123     PendingTextChunk    newChunk;
124
125     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextAppendChunk() starting\n"));
126 #ifdef    DEBUG
127     walkPendingText(list);
128 #endif /* DEBUG  */
129 #ifdef    RECYCLE_CHUNKS
130     if (list->free)
131     {
132         /* 
133         ** There are chunks on the free list, this will
134         ** be easy.
135         */
136         newChunk = list->free;
137     }
138     else
139     {
140         /*
141         ** We have no free chunks.
142         */
143         newChunk = mallocChunk(len);
144         
145         if (!newChunk)
146         {
147             return(PendingTextChunk(NULL));
148         }
149     }   
150     /* 
151     ** append the new chunk to the list...
152     */
153     list->free       = list->free->next;
154     newChunk->next   = (PendingTextChunk)NULL;
155     list->tail->next = newChunk;
156     list->tail       = newChunk;
157     return(True);
158 #else  /* RECYCLE_CHUNKS */
159     /*
160     ** Create a new chunk.
161     */
162     newChunk = mallocChunk(len);
163     
164     if (!newChunk)
165     {
166         return((PendingTextChunk)NULL);
167     }
168     newChunk->next = list->tail;
169     newChunk->prev = list->tail->prev;
170     list->tail->prev->next = newChunk;
171     list->tail->prev = newChunk;
172     return(newChunk);
173 #endif /* RECYCLE_CHUNKS */
174 }
175
176 void
177 _DtTermPrimPendingTextReplace
178 (
179     PendingTextChunk chunk,
180     unsigned char *buffer,
181     int bufferLen
182 )
183 {
184
185     chunk->buffer = (unsigned char *) XtRealloc((char *) chunk->buffer,
186             bufferLen);
187     chunk->buffLen = bufferLen;
188     chunk->bufPtr = chunk->buffer;
189     chunk->len = bufferLen;
190     (void) memmove(chunk->buffer, buffer, bufferLen);
191 }
192
193 /* 
194 ** Remove a pending text chunk from the head of the list, and add it to
195 ** the free list.
196 */
197 void
198 _DtTermPrimPendingTextRemoveChunk
199 (
200     PendingText list,
201     PendingTextChunk chunk
202 )
203 {
204     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextRemoveChunk() starting\n"));
205 #ifdef    DEBUG
206     walkPendingText(list);
207 #endif /* DEBUG  */
208     /* 
209     ** add the chunk to the free list...
210     */
211     /* don't allow removal of either head or tail... */
212     if ((chunk == list->head) || (chunk == list->tail)) {
213         return;
214     }
215
216     chunk->prev->next = chunk->next;
217     chunk->next->prev = chunk->prev;
218 #ifdef    RECYCLE_CHUNKS
219     chunk->len  = 0;
220     chunk->next = list->free;
221     list->free  = chunk;
222 #else  /* RECYCLE_CHUNKS */
223     XtFree((char *) chunk->buffer);
224     XtFree((char *) chunk);    
225 #endif /* RECYCLE_CHUNKS */
226 }
227
228 /* Check to see if there is any pending text in the pending text list...
229  */
230 Boolean
231 _DtTermPrimPendingTextIsPending
232 (
233     PendingText list
234 )
235 {
236     if (list->head->next != list->tail) {
237         return(True);
238     }
239     return(False);
240 }
241
242 /* 
243 ** Get a pending text chunk from the head of the list.
244 */
245 PendingTextChunk
246 _DtTermPrimPendingTextGetChunk
247 (
248     PendingText list
249 )
250 {
251     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextGetChunk() starting\n"));
252 #ifdef    DEBUG
253     walkPendingText(list);
254 #endif /* DEBUG  */
255
256     if (list->head->next != list->tail) {
257         return(list->head->next);
258     } else {
259         return((PendingTextChunk) 0);
260     }
261 }
262
263 /* 
264 ** Flush a pending text list.  This function takes the easy way out of
265 ** calling _DtTermPrimPendingTextGetChunk() to get each chunk and
266 ** _DtTermPrimPendingTextRemoveChunk() to remove them.
267 */
268 void
269 _DtTermPrimPendingTextFlush
270 (
271     PendingText list
272 )
273 {
274     PendingTextChunk chunk;
275
276     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextFlush() starting\n"));
277 #ifdef  DEBUG
278     walkPendingText(list);
279 #endif  /* DEBUG */
280     
281     while (chunk = _DtTermPrimPendingTextGetChunk(list)) {
282         (void) _DtTermPrimPendingTextRemoveChunk(list, chunk);
283     }
284 }
285
286 /* 
287 ** Append the supplied text to the pending text list.  Return True if
288 ** all text was appended, else return False.
289 */
290 Boolean
291 _DtTermPrimPendingTextAppend
292 (
293     PendingText     list,
294     unsigned char  *text,
295     int             len
296 )
297 {
298     PendingTextChunk    newChunk;
299     PendingTextChunk    oldTail;
300
301     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextAppend() starting\n"));
302 #ifdef    DEBUG
303     walkPendingText(list);
304 #endif /* DEBUG  */
305     /* 
306     ** remember this if we are unable to get all the text
307     ** into the list
308     */
309     oldTail = list->tail->prev;
310
311     /* 
312     ** add a new chunk to the list
313     */
314     while (len > 0)
315     {
316         newChunk = _DtTermPrimPendingTextAppendChunk(list,
317                 (len > DEFAULT_CHUNK_BUF_SIZE) ? DEFAULT_CHUNK_BUF_SIZE : len);
318         if (!newChunk)
319         {
320             /* 
321             ** the allocation failed, free up all newly created
322             ** chunks and return...
323             */
324             while (oldTail != list->tail->prev)
325             {
326                 _DtTermPrimPendingTextRemoveChunk(list, list->tail->prev);
327             }
328             return(False);
329         }
330         /* 
331         ** chunk buffers are a fixed size, copy a much as possible
332         ** from 'text' to the chunk buffer, then adjust 'len'...
333         */
334         newChunk->len = MIN(len, newChunk->buffLen);
335         (void)memcpy(newChunk->buffer, text, newChunk->len);
336         len -= newChunk->buffLen;
337     }    
338     return(True);
339 }
340
341 /* 
342 ** Write a pending text chunk from the head of the list.
343 */
344 void
345 _DtTermPrimPendingTextWrite
346 (
347     PendingText     list,
348     int             fd
349 )
350 {
351     int                 bytesWritten = 0;
352     PendingTextChunk    chunk;
353
354     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextWrite() starting\n"));
355 #ifdef    DEBUG
356     walkPendingText(list);
357 #endif /* DEBUG  */
358     chunk = list->head->next;
359     Debug('q', fprintf(stderr, ">>       len: %3.3d\n", chunk->len));
360     Debug('q', fprintf(stderr, ">>    bufPtr: <%*.*s>\n", 
361                        chunk->len, chunk->len, chunk->bufPtr));
362
363     bytesWritten = write(fd, chunk->bufPtr, chunk->len <= MAX_PTY_WRITE ?
364                          chunk->len : MAX_PTY_WRITE);
365
366     if (bytesWritten < 0) {
367
368 #ifdef DEBUG       
369         fprintf(stderr, "_DtTermPrimPendingTextWrite: write failed\n");
370 #endif
371        bytesWritten = 0;
372     }
373
374     if ((chunk->len -= bytesWritten) <= 0) {
375         /* 
376         ** All text in this chunk has been written,
377         ** remove it from the list.
378         */
379         _DtTermPrimPendingTextRemoveChunk(list, chunk);
380     }
381     else {
382         /* 
383         ** only some of the text in this chunk was written,
384         ** simply adjust the write pointer...
385         ** (list->head->len was adjusted above)
386         */
387         chunk->bufPtr += bytesWritten;
388         
389     }
390 }
391
392 PendingText
393 _DtTermPrimPendingTextCreate(
394     void
395 )
396 {
397     PendingText ptr;
398
399     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextCreate() starting\n"));
400
401     ptr = (PendingText) XtMalloc(sizeof(PendingTextRec));
402     (void) memset(ptr, '\0', sizeof(PendingTextRec));
403     ptr->head = (PendingTextChunk) XtMalloc(sizeof(PendingTextChunkRec));
404     (void) memset(ptr->head, '\0', sizeof(PendingTextChunkRec));
405     ptr->tail = (PendingTextChunk) XtMalloc(sizeof(PendingTextChunkRec));
406     (void) memset(ptr->tail, '\0', sizeof(PendingTextChunkRec));
407
408     ptr->head->next = ptr->tail;
409     ptr->tail->prev = ptr->head;
410
411 #ifdef    DEBUG
412     walkPendingText(ptr);
413 #endif /* DEBUG  */
414     return(ptr);
415 }
416
417 void
418 _DtTermPrimPendingTextDestroy(
419     PendingText ptr
420 )
421 {
422     PendingTextChunk chunk;
423
424     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextDestroy() starting\n"));
425 #ifdef    DEBUG
426 #undef    DEBUG
427     walkPendingText(ptr);
428 #endif /* DEBUG  */
429     if (ptr) {
430         while (ptr->head) {
431             chunk = ptr->head;
432             ptr->head = ptr->head->next;
433             if (chunk->buffer) {
434                 (void) XtFree((char *) chunk->buffer);
435             }
436             (void) XtFree((char *) chunk);
437         }
438         (void) XtFree((char *) ptr);
439     }
440 }
441
442