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