remove OSF1 support
[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 libraries 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 static
43 PendingTextChunk
44 mallocChunk(int len);
45
46 #ifdef    DEBUG
47 void
48 walkPendingText
49 (
50     PendingText     list
51 )
52 {
53     PendingTextChunk chunk;
54
55     fprintf(stderr, "head: %lx\n", list->head);
56     fprintf(stderr, "tail: %lx\n", list->tail);
57
58     for (chunk = list->head; chunk != list->tail; chunk = chunk->next)
59     {
60         fprintf(stderr, "chunk: 0x%lx\n", chunk);
61         fprintf(stderr, "    buffer : %c\n", chunk->buffer[0]);
62         fprintf(stderr, "    buffLen: %d\n", chunk->buffLen);
63         fprintf(stderr, "    bufPtr : %c\n", chunk->bufPtr[0]);
64         fprintf(stderr, "    len    : %d\n", chunk->len);
65         fprintf(stderr, "    next   : 0x%lx\n", chunk->next);
66         fprintf(stderr, "    prev   : 0x%lx\n", chunk->prev);
67     }
68 }
69 #endif /* DEBUG  */
70
71 /* 
72 ** Allocate, and initialize a new PendingTextChunk.
73 */
74 static 
75 PendingTextChunk
76 mallocChunk(int len)
77 {
78     PendingTextChunk    newChunk;
79     
80     Debug('q', fprintf(stderr, ">>mallocChunk() starting\n"));
81
82     newChunk = (PendingTextChunk) XtMalloc(sizeof(PendingTextChunkRec));
83     if (!newChunk)
84     {
85         return((PendingTextChunk) NULL);
86     }
87
88     newChunk->buffLen = len;
89     newChunk->buffer  = (unsigned char *) XtMalloc(newChunk->buffLen);
90     if (!newChunk->buffer)
91     {
92         XtFree((char *) newChunk);
93         return((PendingTextChunk) NULL);
94     }
95     
96     /*
97     ** Finish initializing the new chunk.
98     */
99     newChunk->bufPtr = newChunk->buffer;
100     newChunk->len   = 0;
101     newChunk->next  = (PendingTextChunk)NULL;
102     newChunk->prev  = (PendingTextChunk)NULL;
103     return(newChunk);
104 }
105
106 /* 
107 ** Add a new pending text chunk to the end of the list.  If possible, reuse
108 ** an existing chunk, else allocate a new one.   Return true if successful,
109 ** else return false.
110 */
111 PendingTextChunk
112 _DtTermPrimPendingTextAppendChunk
113 (
114     PendingText list,
115     int         len
116 )
117 {
118     PendingTextChunk    newChunk;
119
120     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextAppendChunk() starting\n"));
121 #ifdef    DEBUG
122     walkPendingText(list);
123 #endif /* DEBUG  */
124 #ifdef    RECYCLE_CHUNKS
125     if (list->free)
126     {
127         /* 
128         ** There are chunks on the free list, this will
129         ** be easy.
130         */
131         newChunk = list->free;
132     }
133     else
134     {
135         /*
136         ** We have no free chunks.
137         */
138         newChunk = mallocChunk(len);
139         
140         if (!newChunk)
141         {
142             return(PendingTextChunk(NULL));
143         }
144     }   
145     /* 
146     ** append the new chunk to the list...
147     */
148     list->free       = list->free->next;
149     newChunk->next   = (PendingTextChunk)NULL;
150     list->tail->next = newChunk;
151     list->tail       = newChunk;
152     return(True);
153 #else  /* RECYCLE_CHUNKS */
154     /*
155     ** Create a new chunk.
156     */
157     newChunk = mallocChunk(len);
158     
159     if (!newChunk)
160     {
161         return((PendingTextChunk)NULL);
162     }
163     newChunk->next = list->tail;
164     newChunk->prev = list->tail->prev;
165     list->tail->prev->next = newChunk;
166     list->tail->prev = newChunk;
167     return(newChunk);
168 #endif /* RECYCLE_CHUNKS */
169 }
170
171 void
172 _DtTermPrimPendingTextReplace
173 (
174     PendingTextChunk chunk,
175     unsigned char *buffer,
176     int bufferLen
177 )
178 {
179
180     chunk->buffer = (unsigned char *) XtRealloc((char *) chunk->buffer,
181             bufferLen);
182     chunk->buffLen = bufferLen;
183     chunk->bufPtr = chunk->buffer;
184     chunk->len = bufferLen;
185     (void) memmove(chunk->buffer, buffer, bufferLen);
186 }
187
188 /* 
189 ** Remove a pending text chunk from the head of the list, and add it to
190 ** the free list.
191 */
192 void
193 _DtTermPrimPendingTextRemoveChunk
194 (
195     PendingText list,
196     PendingTextChunk chunk
197 )
198 {
199     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextRemoveChunk() starting\n"));
200 #ifdef    DEBUG
201     walkPendingText(list);
202 #endif /* DEBUG  */
203     /* 
204     ** add the chunk to the free list...
205     */
206     /* don't allow removal of either head or tail... */
207     if ((chunk == list->head) || (chunk == list->tail)) {
208         return;
209     }
210
211     chunk->prev->next = chunk->next;
212     chunk->next->prev = chunk->prev;
213 #ifdef    RECYCLE_CHUNKS
214     chunk->len  = 0;
215     chunk->next = list->free;
216     list->free  = chunk;
217 #else  /* RECYCLE_CHUNKS */
218     XtFree((char *) chunk->buffer);
219     XtFree((char *) chunk);    
220 #endif /* RECYCLE_CHUNKS */
221 }
222
223 /* Check to see if there is any pending text in the pending text list...
224  */
225 Boolean
226 _DtTermPrimPendingTextIsPending
227 (
228     PendingText list
229 )
230 {
231     if (list->head->next != list->tail) {
232         return(True);
233     }
234     return(False);
235 }
236
237 /* 
238 ** Get a pending text chunk from the head of the list.
239 */
240 PendingTextChunk
241 _DtTermPrimPendingTextGetChunk
242 (
243     PendingText list
244 )
245 {
246     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextGetChunk() starting\n"));
247 #ifdef    DEBUG
248     walkPendingText(list);
249 #endif /* DEBUG  */
250
251     if (list->head->next != list->tail) {
252         return(list->head->next);
253     } else {
254         return((PendingTextChunk) 0);
255     }
256 }
257
258 /* 
259 ** Flush a pending text list.  This function takes the easy way out of
260 ** calling _DtTermPrimPendingTextGetChunk() to get each chunk and
261 ** _DtTermPrimPendingTextRemoveChunk() to remove them.
262 */
263 void
264 _DtTermPrimPendingTextFlush
265 (
266     PendingText list
267 )
268 {
269     PendingTextChunk chunk;
270
271     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextFlush() starting\n"));
272 #ifdef  DEBUG
273     walkPendingText(list);
274 #endif  /* DEBUG */
275     
276     while ((chunk = _DtTermPrimPendingTextGetChunk(list))) {
277         (void) _DtTermPrimPendingTextRemoveChunk(list, chunk);
278     }
279 }
280
281 /* 
282 ** Append the supplied text to the pending text list.  Return True if
283 ** all text was appended, else return False.
284 */
285 Boolean
286 _DtTermPrimPendingTextAppend
287 (
288     PendingText     list,
289     unsigned char  *text,
290     int             len
291 )
292 {
293     PendingTextChunk    newChunk;
294     PendingTextChunk    oldTail;
295
296     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextAppend() starting\n"));
297 #ifdef    DEBUG
298     walkPendingText(list);
299 #endif /* DEBUG  */
300     /* 
301     ** remember this if we are unable to get all the text
302     ** into the list
303     */
304     oldTail = list->tail->prev;
305
306     /* 
307     ** add a new chunk to the list
308     */
309     while (len > 0)
310     {
311         newChunk = _DtTermPrimPendingTextAppendChunk(list,
312                 (len > DEFAULT_CHUNK_BUF_SIZE) ? DEFAULT_CHUNK_BUF_SIZE : len);
313         if (!newChunk)
314         {
315             /* 
316             ** the allocation failed, free up all newly created
317             ** chunks and return...
318             */
319             while (oldTail != list->tail->prev)
320             {
321                 _DtTermPrimPendingTextRemoveChunk(list, list->tail->prev);
322             }
323             return(False);
324         }
325         /* 
326         ** chunk buffers are a fixed size, copy a much as possible
327         ** from 'text' to the chunk buffer, then adjust 'len'...
328         */
329         newChunk->len = MIN(len, newChunk->buffLen);
330         (void)memcpy(newChunk->buffer, text, newChunk->len);
331         len -= newChunk->buffLen;
332     }    
333     return(True);
334 }
335
336 /* 
337 ** Write a pending text chunk from the head of the list.
338 */
339 void
340 _DtTermPrimPendingTextWrite
341 (
342     PendingText     list,
343     int             fd
344 )
345 {
346     int                 bytesWritten = 0;
347     PendingTextChunk    chunk;
348
349     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextWrite() starting\n"));
350 #ifdef    DEBUG
351     walkPendingText(list);
352 #endif /* DEBUG  */
353     chunk = list->head->next;
354     Debug('q', fprintf(stderr, ">>       len: %3.3d\n", chunk->len));
355     Debug('q', fprintf(stderr, ">>    bufPtr: <%*.*s>\n", 
356                        chunk->len, chunk->len, chunk->bufPtr));
357
358     bytesWritten = write(fd, chunk->bufPtr, chunk->len <= MAX_PTY_WRITE ?
359                          chunk->len : MAX_PTY_WRITE);
360
361     if (bytesWritten < 0) {
362
363 #ifdef DEBUG       
364         fprintf(stderr, "_DtTermPrimPendingTextWrite: write failed\n");
365 #endif
366        bytesWritten = 0;
367     }
368
369     if ((chunk->len -= bytesWritten) <= 0) {
370         /* 
371         ** All text in this chunk has been written,
372         ** remove it from the list.
373         */
374         _DtTermPrimPendingTextRemoveChunk(list, chunk);
375     }
376     else {
377         /* 
378         ** only some of the text in this chunk was written,
379         ** simply adjust the write pointer...
380         ** (list->head->len was adjusted above)
381         */
382         chunk->bufPtr += bytesWritten;
383         
384     }
385 }
386
387 PendingText
388 _DtTermPrimPendingTextCreate(
389     void
390 )
391 {
392     PendingText ptr;
393
394     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextCreate() starting\n"));
395
396     ptr = (PendingText) XtMalloc(sizeof(PendingTextRec));
397     (void) memset(ptr, '\0', sizeof(PendingTextRec));
398     ptr->head = (PendingTextChunk) XtMalloc(sizeof(PendingTextChunkRec));
399     (void) memset(ptr->head, '\0', sizeof(PendingTextChunkRec));
400     ptr->tail = (PendingTextChunk) XtMalloc(sizeof(PendingTextChunkRec));
401     (void) memset(ptr->tail, '\0', sizeof(PendingTextChunkRec));
402
403     ptr->head->next = ptr->tail;
404     ptr->tail->prev = ptr->head;
405
406 #ifdef    DEBUG
407     walkPendingText(ptr);
408 #endif /* DEBUG  */
409     return(ptr);
410 }
411
412 void
413 _DtTermPrimPendingTextDestroy(
414     PendingText ptr
415 )
416 {
417     PendingTextChunk chunk;
418
419     Debug('q', fprintf(stderr, ">>_DtTermPrimPendingTextDestroy() starting\n"));
420 #ifdef    DEBUG
421 #undef    DEBUG
422     walkPendingText(ptr);
423 #endif /* DEBUG  */
424     if (ptr) {
425         while (ptr->head) {
426             chunk = ptr->head;
427             ptr->head = ptr->head->next;
428             if (chunk->buffer) {
429                 (void) XtFree((char *) chunk->buffer);
430             }
431             (void) XtFree((char *) chunk);
432         }
433         (void) XtFree((char *) ptr);
434     }
435 }
436
437