FreeBSD 10 clang port
[oweals/cde.git] / cde / lib / DtTerm / TermPrim / TermPrimBuffer.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[] = "$XConsortium: TermPrimBuffer.c /main/1 1996/04/21 19:16:49 drk $";
26 #endif  /* VERBOSE_REV_INFO */
27 #endif  /* lint */
28
29 /*                                                                      *
30  * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company               *
31  * (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
32  * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.                *
33  * (c) Copyright 1993, 1994, 1996 Novell, Inc.                          *
34  * (c) Copyright 1996 Digital Equipment Corporation.                    *
35  * (c) Copyright 1996 FUJITSU LIMITED.                                  *
36  * (c) Copyright 1996 Hitachi.                                          *
37  */
38
39 #define USE_MEMCPY      /* use memcpy for line movement... */
40
41 #include <wchar.h>
42 #include <Xm/Xm.h>
43 #include "TermHeader.h"       /* for MIN/MAX */
44 #include "TermPrim.h"
45 #include "TermPrimBuffer.h"
46 #include "TermPrimBufferP.h"
47 #include "TermPrimSelect.h"
48 #include "TermPrimDebug.h"
49
50 /*
51 ** Allocate and initialize a new terminal buffer.
52 */
53 TermBuffer
54 _DtTermPrimBufferCreateBuffer
55 (
56     const Widget  w,
57     const short   rows,
58     const short   cols,
59     const short   sizeOfBuffer,
60     const short   sizeOfLine,
61     const short   sizeOfEnh
62 )
63 {
64     int             i;
65     TermLine       *newTL;
66     TermBuffer      newTB;
67     Boolean        *tabs;
68     int             sizeOfChar;
69     
70     /*
71     ** malloc new a TermBuffer and an array of TermLine pointers
72     */
73     newTB = (TermBuffer) malloc(sizeOfBuffer);
74     /* the following MIN ensures that on systems where malloc of 0 returns
75      * NULL, we won't confuse a 0 size buffer with a malloc failure and an
76      * invalid buffer...
77      */
78     newTL  = (TermLine *) malloc((unsigned) MAX(rows, 1) * sizeof(TermLine));
79
80     if (!newTB || !newTL)
81     {
82         /*
83         ** clean up and leave if either of the previous malloc's failed.
84         */
85         if (newTB)
86         {
87             free(newTB);
88         }
89         if (newTL)
90         {
91             free(newTL);
92         }
93         return((TermBuffer)NULL);
94     }
95
96     /*
97     ** malloc a tabs array...
98     */
99     tabs = (Boolean *) malloc((unsigned) cols * sizeof(Boolean));
100     if (!tabs)
101     {
102         free(newTB);
103         free(newTL);
104         /*
105         ** clean up and leave if either of the previous malloc's failed.
106         */
107         return((TermBuffer)NULL);
108     }
109     /*
110     ** initialize the tabs...
111     */
112     for (i = 0; i < cols; i++) {
113         tabs[i] = 0 == i % 8;
114     }
115
116     /* 
117     ** decide how many bytes to allocate per character...
118     */
119     BYTES_PER_CHAR(newTB) = MB_CUR_MAX == 1 ? 1 : sizeof(wchar_t);
120
121     /* 
122     ** setting debug flag m:1 forces us into wide char mode...
123     */
124     DebugF('m', 1, BYTES_PER_CHAR(newTB) = sizeof(wchar_t));
125
126     /*
127     ** now malloc the individual lines...
128     */
129     for (i = 0; i < rows; i++)
130     {
131         newTL[i] = (TermLine) malloc(sizeOfLine);
132         if (newTL[i])
133         {
134             BUFFER(newTL[i]) = (termChar *) 
135                                       malloc((unsigned) 
136                                              cols * BYTES_PER_CHAR(newTB));
137
138             if (BUFFER(newTL[i]) == NULL)
139             {
140                 /*
141                 ** we couldn't malloc a line buffer
142                 */
143                 break;
144             }
145             LENGTH(newTL[i])  = 0;
146             WIDTH(newTL[i])   = 0;
147             WRAPPED(newTL[i]) = False;
148             START_SELECTION(newTL[i]) = NON_SELECTION_COL;
149             END_SELECTION(newTL[i]) = NON_SELECTION_COL;
150         }
151         else
152         {
153             /*
154             ** we couldn't malloc a line
155             */
156             break;
157         }
158     }
159
160     /*
161     ** If we were unable to malloc a full set of lines (i != rows),
162     ** then cleanup and leave.
163     */
164     if (i != rows)
165     {
166         int j;
167
168         for (j = 0; j < i; j++)
169         {
170             free(BUFFER(newTL[j]));
171             free(newTL[j]);
172         }
173         free(newTL);
174         free(newTB);
175         free(tabs);
176         return((TermBuffer)NULL);
177     }
178
179     /*
180     ** Initialize the new TermBuffer.
181     */
182     LINES(newTB)                = newTL;
183     TABS(newTB)                 = tabs;
184     ROWS(newTB)                 = rows;
185     COLS(newTB)                 = cols;
186     MAX_ROWS(newTB)             = rows;
187     MAX_COLS(newTB)             = cols;
188     SIZE_OF_BUFFER(newTB)       = sizeOfBuffer;
189     SIZE_OF_LINE(newTB)         = sizeOfLine;
190     SIZE_OF_ENH(newTB)          = sizeOfEnh;
191     BUFFER_CREATE(newTB)        = _DtTermPrimBufferCreateBuffer;
192     BUFFER_FREE(newTB)          = NULL;
193     BUFFER_RESIZE(newTB)        = NULL;
194     ENH_PROC(newTB)             = NULL;
195     CLEAR_ENH(newTB)            = NULL;
196     INSERT_ENH(newTB)           = NULL;
197     DELETE_ENH(newTB)           = NULL;
198     SET_ENH(newTB)              = NULL;
199     GET_ENH(newTB)              = NULL;
200     SET_LINE_WIDTH(newTB)       = NULL;
201     CLEAR_LINE(newTB)           = NULL;
202     NEXT_BUFFER(newTB)          = NULL;
203     PREV_BUFFER(newTB)          = NULL;
204     BUFFER_SELECT_INFO(newTB)   = NULL;
205     WIDGET(newTB)               = w;
206     return (newTB);
207 }
208
209 void
210 _DtTermPrimBufferFreeBuffer
211 (
212     const TermBuffer tb
213 )
214 {
215     int i;
216
217     /* check for null buffer... */
218     if (!tb) {
219         return;
220     }
221
222     /*
223     ** Free any buffer-specific info first...
224     */
225     if (BUFFER_FREE(tb))
226     {
227         (*BUFFER_FREE(tb))(tb);
228     }
229         
230     /*
231     ** free the old buffer...
232     */
233     for (i = 0; i < MAX_ROWS(tb); i++)
234     {
235         (void) free(BUFFER(LINES(tb)[i]));
236         (void) free(LINES(tb)[i]);
237     }
238     (void) free(TABS(tb));
239     (void) free(LINES(tb));
240     (void) free(tb);
241 }
242
243 /*
244 ** Resize the terminal buffer, and try to be smart about it.  If the buffer
245 ** shrinks, then simply adjust the size, no reallocs necessary (that way if
246 ** the user returns to the previous size, no data is lost).
247 **
248 ** NOTE:
249 **    Given this implementation, the memory allocated to the buffer will 
250 **    never decrease it simply increases to accomodate the largest size
251 **    that has ever been requested.
252 */
253 void
254 _DtTermPrimBufferResizeBuffer
255 (
256     TermBuffer *oldTB,
257     short      *newRows,
258     short      *newCols
259 )
260 {
261     int         i;
262     short       thisTabWidth;
263     short       tabWidth;
264     TermLine   *newTL;
265     Boolean    *tabs;
266     
267     /*
268     ** enforce some minimum size constraints...
269     */
270     *newRows = MAX(*newRows, 1);
271     *newCols = MAX(*newCols, 1);
272
273     /*
274     ** the number of cols is increasing, start small and adjust the tab
275     ** stops first...
276     */
277     if (*newCols > MAX_COLS(*oldTB)) 
278     {
279         tabs = (Boolean *) malloc((unsigned) *newCols * sizeof(Boolean));
280         if (tabs)
281         {
282             /* copy over the tab stops... */
283             (void) memcpy(tabs, TABS(*oldTB), COLS(*oldTB) * sizeof(Boolean));
284             free(TABS(*oldTB));
285             TABS(*oldTB) = tabs;
286             
287             /*
288             ** we need to extend the tab stops...
289             **
290             ** when tabWidth == 0, it has not been initialized.  When
291             ** it is < 0, we have encountered unequal tab stops...
292             */
293             tabWidth = 0;
294             for (i = 0, thisTabWidth = 0; i < COLS(*oldTB); i++, thisTabWidth++)
295             {
296                 if (TABS(*oldTB)[i])
297                 {
298                     if (tabWidth == 0)
299                     {
300                         /* first tab stop, set tabWidth... */
301                         tabWidth = thisTabWidth;
302                     } 
303                     else if (tabWidth != thisTabWidth)
304                     {
305                         /* tab stops differ, set tabWidth to -1... */
306                         tabWidth = -1;
307                     }
308                     /* reset for next tab stop... */
309                     thisTabWidth = 0;
310                 }
311             }
312             
313             if (tabWidth > 0)
314             {
315                 /*
316                 ** we have consistent tab stops.  Extend the buffer...
317                 */
318                 for (i = COLS(*oldTB); i < *newCols; i++)
319                 {
320                     TABS(*oldTB)[i] = (0 == (i % tabWidth));
321                 }
322             }
323             else
324             {
325                 /*
326                 ** we don't have consistent tab stops, so clear the rest...
327                 */
328                 (void) memset(&(TABS(*oldTB)[COLS(*oldTB)]), '\0',
329                               (*newCols - COLS(*oldTB)) * sizeof(Boolean));
330             }
331         }
332         else 
333         {
334             /*
335             ** the malloc failed, adjust newCols and newRows and leave...
336             */
337             *newCols     = MAX_COLS(*oldTB);
338             *newRows     = MIN(*newRows, MAX_ROWS(*oldTB));
339             COLS(*oldTB) = *newCols;
340             ROWS(*oldTB) = *newRows;
341             return;
342         }
343     }
344     else
345     {
346         /*
347         ** take care of any shrinkage...
348         */
349         COLS(*oldTB) = *newCols;
350     }
351
352     /*
353     ** Now give the resize helper a shot at resizing the buffer
354     */
355     if (BUFFER_RESIZE(*oldTB))
356     {
357         /* 
358         ** Call the resize helper function if it exists...
359         */
360         (*BUFFER_RESIZE(*oldTB))(*oldTB, newRows, newCols);
361     }
362     else
363     {
364         /*
365         ** There is no helper function, do it ourselves...
366         ** NOTE:
367         **     This might cause some duplication of code, but due
368         **     to time constraints, it is the most expeditious route.
369         */
370         /*
371         ** make any necessary width adjustments first...
372         **
373         ** NOTE:
374         **    We do not take any action if the new column width is less
375         **    than the current column width.  It is the responsibility of
376         **    the rendering code to make sure that two column characters
377         **    are handled properly if the second column falls past the last
378         **    column in the window.
379         */
380         if (*newCols > MAX_COLS(*oldTB)) 
381         {
382             termChar *newLineBuffer;
383             
384             /*
385             ** now extend the line buffers for all lines, (even lines that
386             ** are not being used at the moment (ROWS < MAX_ROWS))...
387             */
388             newTL = LINES(*oldTB);
389             for (i = 0; i < MAX_ROWS(*oldTB); i++)
390             {
391                 newLineBuffer = (termChar *) malloc((unsigned) 
392                                                     *newCols * BYTES_PER_CHAR(*oldTB));
393                 
394                 if (newLineBuffer == NULL)
395                 {
396                     /*
397                     ** line buffer malloc failed, we can only increase the
398                     ** width to the current maximum...
399                     */
400                     *newCols = MAX_COLS(*oldTB);
401                     *newRows = MIN(*newRows, MAX_ROWS(*oldTB));
402                     break;
403                 }
404                 memcpy(newLineBuffer, BUFFER(newTL[i]), LENGTH(newTL[i]));
405                 free(BUFFER(newTL[i]));
406                 BUFFER(newTL[i])  = newLineBuffer;
407                 WRAPPED(newTL[i]) = False;
408             }
409             MAX_COLS(*oldTB) = *newCols;
410         }
411         COLS(*oldTB) = *newCols;
412         
413         /*
414         ** now adjust the length of the buffer as necessary...
415         */
416         if (*newRows > MAX_ROWS(*oldTB)) 
417         {
418             /*
419             ** the number of rows is increasing
420             */
421             newTL = (TermLine *) malloc((unsigned) *newRows * 
422                                         sizeof(TermLine));
423             if (newTL != NULL)
424             {
425                 /*
426                 ** the malloc succeeded, copy the old information, and
427                 ** then free it...
428                 */
429                 memcpy(newTL, LINES(*oldTB), sizeof(TermLine) * 
430                        ROWS(*oldTB));
431                 free(LINES(*oldTB));
432                 LINES(*oldTB) = newTL;
433                 
434                 /*
435                 ** now initialize the new lines...
436                 */
437                 for (i = ROWS(*oldTB); i < *newRows; i++)
438                 {
439                     newTL[i] = (TermLine) malloc(SIZE_OF_LINE(*oldTB));
440                     if (newTL[i])
441                     {
442                         BUFFER(newTL[i]) = (termChar *) 
443                             malloc((unsigned) COLS(*oldTB) * 
444                                    BYTES_PER_CHAR(*oldTB));
445                         if (BUFFER(newTL[i]) == NULL)
446                         {
447                             /*
448                             ** line buffer malloc failed...
449                             */
450                             *newRows = i;
451                             break;
452                         }
453                         LENGTH(newTL[i])  = 0;
454                         WIDTH(newTL[i])   = 0;
455                         WRAPPED(newTL[i]) = False;
456                         START_SELECTION(newTL[i]) = NON_SELECTION_COL;
457                         END_SELECTION(newTL[i]) = NON_SELECTION_COL;
458                     }
459                     else
460                     {
461                         /*
462                         ** line malloc failed, lets limit the
463                         ** number of rows
464                         */
465                         *newRows = i;
466                         break;
467                     }
468                 }
469                 /*
470                 ** its conceivable that MAX_ROWS could actually decrease if
471                 ** we are low on memory...
472                 */
473                 MAX_ROWS(*oldTB) = MIN(MAX_ROWS(*oldTB), *newRows);
474             }
475             else
476             {
477                 /*
478                 ** the row buffer malloc failed, revert back to MAX_ROWS
479                 */
480                 *newRows = MAX_ROWS(*oldTB);
481             }
482         }
483         ROWS(*oldTB) = *newRows;
484     }
485 }
486
487 #ifdef NOCODE
488
489 /*
490 ** Create an enhancement block at the specified row and column.
491 **
492 ** NOTE:  For the time being, we simply allocate an entire row's worth
493 **        of enhancement blocks if it doesn't exist already.  We may
494 **        get smarter later on.
495 */
496 /*ARGSUSED*/
497 Boolean
498 _DtTermPrimBufferCreateEnhancement
499 (
500     const TermBuffer  tb,
501     const short       row,
502     const short       col
503 )
504 {
505     return(True);
506 }
507
508 /*
509 ** Clear the enhancement block at the specified row and column.
510 */
511 static
512 void
513 clearEnhancement
514 (
515     const TermBuffer  tb,
516     const short       row,
517     const short       col
518 )
519 {
520
521 }
522 #endif /* NOCODE */
523
524 /* 
525 ** Call the emulations specific function to insert the desired number of
526 ** enhancements at the specified position...
527 **
528 ** Assumptions:
529 **   - insertCount has been properly clipped to insure that we don't go
530 **     out of bounds
531 **
532 ** Notes:
533 **   - results are undefined if this function is called when the specified
534 **     column is at the end of the line.
535 */
536 static void
537 insertEnhancements
538 (
539     const TermBuffer  tb, 
540     const short       row,
541     const short       col,
542     const short       insertCount,
543     const Boolean     insertFlag
544 )
545 {
546     /* 
547     ** call the insert function only when it exists and we're in 
548     ** insert mode...
549     */
550     if (INSERT_ENH(tb))
551     {
552         (*INSERT_ENH(tb))(tb, row, col, insertCount, insertFlag);
553     }
554 }
555
556 /*
557 ** Free the enhancement block at the specified row and column.
558 **
559 ** NOTE: We may get smarter later on.
560 */
561 Boolean
562 _DtTermPrimBufferFreeEnhancement
563 (
564     const TermBuffer  tb,
565     const short       row,
566     const short       col
567 )
568 {
569     return(True);
570 }
571
572 #ifdef  BBA
573 #pragma BBA_IGNORE
574 #endif  /*BBA*/
575 static void
576 RememberTermBuffer
577 (
578     const TermBuffer  tb,
579     TermLine **referenceLines,
580     int *referenceLineCount
581 )
582 {
583     int i1;
584     int i2;
585
586     *referenceLineCount = ROWS(tb);
587     *referenceLines = (TermLine *) XtMalloc(ROWS(tb) * sizeof(TermLine));
588
589     /* copy over the lines...
590      */
591     for (i1 = 0; i1 < ROWS(tb); i1++) {
592         (*referenceLines)[i1] = LINE_OF_TBUF(tb, i1);
593     }
594
595     /* verify that they are all unique...
596      */
597
598     /* do a brute force check... */
599     for (i1 = 0; i1 < ROWS(tb) - 1; i1++) {
600         for (i2 = i1 + 1; i2 < ROWS(tb); i2++) {
601             if ((*referenceLines)[i1] == (*referenceLines)[i2]) {
602                 (void) fprintf(stderr,
603                         ">>RememberTermBuffer: dup ptrs lines %d and %d\n",
604                         i1, i2);
605             }
606         }
607     }
608 }
609
610 #ifdef  BBA
611 #pragma BBA_IGNORE
612 #endif  /*BBA*/
613 static void
614 CheckTermBuffer
615 (
616     const TermBuffer  tb, 
617     TermLine *referenceLines,
618     int referenceLineCount
619 )
620 {
621     int i1;
622     int i2;
623     int matchedLine;
624
625     if (referenceLineCount != ROWS(tb)) {
626         for (i1 = 0; i1 < ROWS(tb); i1++) {
627             matchedLine = -1;
628             for (i2 = 0; i2 < ROWS(tb); i2++) {
629                 if (referenceLines[i1] == LINE_OF_TBUF(tb, i2)) {
630                     if (matchedLine == -1) {
631                         matchedLine = i2;
632                     } else {
633                         /* duplicate pointer... */
634                         fprintf(stderr,
635                                 ">>CheckTermBuffer: duplicate pointer src=%d, dest=%d and %d\n",
636                                 i1, matchedLine, i2);
637                     }
638                 }
639             }
640             if (matchedLine == -1) {
641                 fprintf(stderr,
642                         ">>CheckTermBuffer: dropped pointer src=%d\n", i1);
643             }
644         }
645     }
646     
647     if (referenceLines) {
648       XtFree((char *) referenceLines);
649     }
650 }
651
652 short
653 _DtTermPrimBufferGetText
654 (
655     const TermBuffer      tb,
656     const short           row,
657     const short           col,
658     const short           width,
659           char           *buffer,
660     const Boolean         needWideChar
661 )
662 {
663     short           retLen;
664     short           colWidth;
665     short           mbLen;
666     char           *pChar;
667     wchar_t        *pwc;
668     TermCharInfoRec charInfoFirst;
669     TermCharInfoRec charInfoLast;
670     
671     if (!VALID_ROW(tb, row) || !VALID_COL(tb, col))
672     {
673         return(0);
674     }
675     
676     colWidth = MIN(width, WIDTH(LINE_OF_TBUF(tb, row)) - col);
677     if (colWidth > 0)
678     {
679         _DtTermPrimGetCharacterInfo(tb, row, col, &charInfoFirst);
680         _DtTermPrimGetCharacterInfo(tb, row, col + colWidth - 1, &charInfoLast);
681         
682         if ((BYTES_PER_CHAR(tb) > 1) && !needWideChar)
683         {
684             /*
685             ** our caller wants multi-byte characters...
686             */
687             retLen = 0;
688             pChar  = buffer;
689             
690             for (pwc = charInfoFirst.u.pwc; pwc <= charInfoLast.u.pwc; pwc++)
691             {
692                 mbLen = wctomb(pChar, *pwc);
693                 if (mbLen > 0)
694                 {
695                     pChar  += mbLen;
696                     retLen += mbLen;
697                 }
698                 else
699                 {
700                     fprintf(stderr, "_DtTermPrimBufferGetText: invalid wide char.\n");
701                 }
702             }
703         }
704         else
705         {
706             retLen = charInfoLast.idx - charInfoFirst.idx + 1;
707             memcpy(buffer, charInfoFirst.u.pc, retLen);
708         }
709     }
710     else
711     {
712         /*
713         ** colWidth == 0, there is nothing to return
714         */
715         retLen = 0;
716     }
717     
718     return(retLen);
719 }
720
721 short
722 _DtTermPrimBufferGetRows
723 (
724     const TermBuffer  tb
725 )
726 {
727     return(ROWS(tb));
728 }
729
730 short
731 _DtTermPrimBufferGetCols
732 (
733     const TermBuffer  tb
734 )
735 {
736     return(COLS(tb));
737 }
738
739 void
740 _DtTermPrimBufferSetLinks
741 (
742     const TermBuffer  tb,
743     const TermBuffer  prev,
744     const TermBuffer  next
745 )
746 {
747     PREV_BUFFER(tb) = prev;
748     NEXT_BUFFER(tb) = next;
749 }    
750
751 void
752 _DtTermPrimBufferSetSelectInfo
753 (
754     const TermBuffer        tb,
755     const TermSelectInfo    si
756 )
757 {
758     BUFFER_SELECT_INFO(tb) = si;
759 }
760
761 /*
762 ** Set the desired enhancement; simply call the emulator specific
763 ** function.
764 */
765 int
766 _DtTermPrimBufferSetEnhancement
767 (
768     const TermBuffer      tb,
769     const short           row,
770     const short           col,
771     const unsigned char   id,
772     const enhValue        value
773 )
774 {
775     if (SET_ENH(tb))
776     {
777         return((*SET_ENH(tb))(tb, row, col, id, value));
778     }
779     else
780     {
781         return(0);
782     }
783 }
784
785 /*
786 ** Get the enhancements for the desired row and column by calling the
787 ** emulator specific routine.
788 */
789 Boolean
790 _DtTermPrimBufferGetEnhancement
791 (
792     const TermBuffer      tb,
793     const short           row,
794     const short           col,
795           enhValue      **values,
796           short          *count,
797     const countSpec       countWhich
798 )
799 {
800     if (GET_ENH(tb))
801     {
802         return((*GET_ENH(tb))(tb, row, col, values, count, countWhich));
803     }
804     else
805     {
806         *count = WIDTH(LINE_OF_TBUF(tb, row));
807         return(True);
808     }
809 }
810
811 /*
812 ** Return a pointer to the character at the specified row,col.
813 */
814 termChar *
815 _DtTermPrimBufferGetCharacterPointer
816 (
817     const TermBuffer  tb,
818     const short       row,
819     const short       col
820 )
821 {
822     TermCharInfoRec    charInfo;
823     
824     if (VALID_ROW(tb, row) && VALID_COL(tb, col))
825     {
826         _DtTermPrimGetCharacterInfo(tb, row, col, &charInfo);
827         return((termChar *)charInfo.u.pc);
828     }
829     else
830     {
831         return(NULL);
832     }
833 }
834
835 /* 
836 ** Get the character info for the specified character.  If the
837 ** specified column exceeds the width of the line, then make up
838 ** some reasonable information, allowing the calling routine to
839 ** continue in a reasonable fashion.
840 **
841 ** XXX: this doesn't get the emulator specific information yet (like
842 **      enhancements
843 */
844 Boolean
845 _DtTermPrimGetCharacterInfo
846 (
847     TermBuffer      tb,
848     short           row,
849     short           col,
850     TermCharInfo    charInfo
851 )
852 {
853     wchar_t    *pwc;
854     short       charWidth;  
855     TermLine    line;
856     short       totalWidth;
857
858     if (!VALID_ROW(tb, row))
859     {
860         return(False);
861     }    
862
863     line = LINE_OF_TBUF(tb, row);
864
865     /*
866     ** handle the easy cases first...
867     */
868     if (col >= WIDTH(line))
869     {
870         /* 
871         ** make up some reasonable values when col equals or 
872         ** exceeds the width of the line
873         */
874         charInfo->u.ptc    = NULL;
875         charInfo->idx      = LENGTH(line);
876         charInfo->len      = BYTES_PER_CHAR(tb);
877         charInfo->startCol = col;
878         charInfo->width    = 1;
879         charInfo->enh      = 0;
880         charInfo->enhLen   = 0;
881     }
882     else if (BYTES_PER_CHAR(tb) == 1)
883     {
884         /* 
885         ** this is easy in a 1 byte locale...
886         */
887         charInfo->u.ptc    = BUFFER(line) + col;
888         charInfo->idx      = col;
889         charInfo->len      = BYTES_PER_CHAR(tb);
890         charInfo->startCol = col;
891         charInfo->width    = 1;
892         charInfo->enh      = 0;
893         charInfo->enhLen   = 0;
894     }
895     else if (col == 0)
896     {
897         charInfo->u.pwc    = (wchar_t *)BUFFER(line);
898         charInfo->idx      = 0;
899         charInfo->len      = BYTES_PER_CHAR(tb);
900         charInfo->startCol = 0;
901         charInfo->width    = MAX(1, wcwidth(*((wchar_t *)BUFFER(line))));
902         charInfo->enh      = 0;
903         charInfo->enhLen   = 0;
904     }
905     else
906     {
907         /* 
908         ** not so easy when we're dealing with wchars...
909         */
910         if (col <= WIDTH(line) / 2)
911         {
912             /*
913             ** work from left to right
914             */
915             totalWidth = 0;
916             for (pwc = (wchar_t *)BUFFER(line);
917                  pwc < (wchar_t *)BUFFER(line) + LENGTH(line);
918                  pwc++)
919             {
920                 charWidth = MAX(1, wcwidth(*pwc));
921                 totalWidth += charWidth;
922                 if (col < totalWidth)
923                 {
924                     /* 
925                     ** we've found the character, now fill in the info...
926                     */
927                     charInfo->u.pwc    = pwc;
928                     charInfo->idx      = pwc - (wchar_t *)BUFFER(line);
929                     charInfo->startCol = totalWidth - charWidth;
930                     charInfo->width    = charWidth;
931                     break;
932                 }
933             }
934         }
935         else
936         {
937             /*
938             ** work from right to left
939             */
940             totalWidth = WIDTH(line);
941             for (pwc = (wchar_t *)BUFFER(line) + (LENGTH(line) - 1);
942                  pwc >= (wchar_t *)BUFFER(line);
943                  pwc--)
944             {
945                 charWidth = MAX(1, wcwidth(*pwc));
946                 totalWidth -= charWidth;
947                 if (totalWidth <= col)
948                 {
949                     /* 
950                     ** we've found the character, now fill in the info...
951                     */
952                     charInfo->u.pwc = pwc;
953                     charInfo->idx   = pwc - (wchar_t *)BUFFER(line);
954                     if (totalWidth == col)
955                     {
956                         charInfo->startCol = col;
957                     }
958                     else
959                     {
960                         charInfo->startCol = col - 1;
961                     }
962                     charInfo->width = charWidth;
963                     break;
964                 }
965             }
966         }
967         charInfo->len    = BYTES_PER_CHAR(tb);
968         charInfo->enh    = 0;
969         charInfo->enhLen = 0;
970     }
971     return(True);
972 }
973
974 /*
975 ** Insert as many characters as possible at the specified row,col
976 ** return a count of the number of characters bumped off the end of the line
977 ** in 'returnCount' and a pointer to a buffer containing those characters
978 ** 'returnChars'.
979 ** 
980 ** The the new width of the line is returned as the value of the function.
981 */
982 short
983 _DtTermPrimBufferInsert
984 (
985     const TermBuffer  tb,
986     const short       row,
987     const short       col,
988     const termChar   *newChars,
989           short       numChars,
990           Boolean     insertFlag,   /* if TRUE, insert, else overwrite        */
991           termChar  **returnChars,  /* pointer to overflow buffer             */
992           short      *returnCount   /* count of characters in overflow buffer */
993 )   
994 {
995            short        insertCount;
996            short        newWidth;
997            short        insertOverflow; /* # of newChars that would overflow */
998            TermLine     line;
999            termChar    *start;
1000            short        copyCount;   /* number of bytes to copy */
1001     
1002     if (!VALID_ROW(tb, row) || !VALID_COL(tb, col))
1003     {
1004         *returnCount = 0;
1005         return(0);
1006     }
1007     
1008     line = LINE_OF_TBUF(tb, row);
1009
1010 #ifdef  OLD_CODE
1011     /* before we modify the buffer, disown the selection... */
1012     (void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
1013 #endif  /* OLD_CODE */
1014
1015     /* if this line is part of the selection, disown the selection... */
1016     if (IS_IN_SELECTION(line, col, MAX_SELECTION_COL)) {
1017         (void) _DtTermPrimSelectDisown(WIDGET(tb));
1018     }
1019
1020     if (BYTES_PER_CHAR(tb) > 1)
1021     {
1022         /*
1023         ** we do not handle multibyte characters here...
1024         */
1025         _DtTermPrimBufferInsertWc(tb, row, col, (wchar_t *)newChars,
1026                                   numChars, insertFlag,
1027                                   returnChars, returnCount);
1028         return 0;
1029     }
1030
1031     if (WIDTH(line) < col)
1032     {
1033         /*
1034         ** We're adding characters past the current end of line,
1035         ** pad it out.
1036         */
1037         _DtTermPrimBufferPadLine(tb, row, col);
1038     }
1039     
1040     insertCount  = MIN(numChars, COLS(tb) - col);
1041     copyCount    = insertCount * BYTES_PER_CHAR(tb);
1042     start        = BUFFER(line) + col;
1043     
1044     /*
1045     ** It doesn't matter if we're overwriting, or inserting at the end 
1046     ** of the line, the result is the same...
1047     */
1048     if (col == WIDTH(line))
1049     {
1050         insertFlag = False;
1051     }
1052
1053     if (insertFlag == False)
1054     {
1055         /* 
1056         ** We're overwriting:
1057         **      - determine the new line width
1058         **      - put any extra new characters into the overflow buffer
1059         ** 
1060         ** The following will be done later:
1061         **      - copy the newChars into the line buffer 
1062         **      - adjust line width (_DtTermPrimBufferSetLineWidth won't
1063         **        let the line get shorter)...
1064         */
1065         newWidth     = MAX(WIDTH(line), col + insertCount);
1066         *returnCount = numChars - insertCount;
1067         if (*returnCount > 0)
1068         {
1069             memcpy(*returnChars, newChars + insertCount,
1070                    *returnCount * BYTES_PER_CHAR(tb));
1071         }
1072     }
1073     else
1074     {
1075         /* 
1076         ** we're inserting text in the middle of the line...
1077         */
1078         *returnCount = MAX(0, (WIDTH(line) + numChars) - COLS(tb));
1079         if (*returnCount > 0)
1080         {
1081             /* 
1082             ** we'll have some overflow, figure out how many (if any)
1083             ** of the new characters will overflow and put them into
1084             ** the overflow buffer...
1085             */
1086             insertOverflow = numChars - insertCount;
1087             memcpy(*returnChars, newChars + insertCount,
1088                    insertOverflow * BYTES_PER_CHAR(tb));
1089
1090             /* 
1091             ** copy the displaced characters from the line to the 
1092             ** overflow buffer as well...
1093             */
1094             memcpy(*returnChars + insertOverflow, BUFFER(line) + 
1095                    (WIDTH(line) - MAX(0, *returnCount - insertOverflow)),
1096                    MAX(0, *returnCount - insertOverflow) 
1097                    * BYTES_PER_CHAR(tb));
1098         }
1099         /* 
1100         ** Any overflow has been taken care of, now it's time to make
1101         ** room for the new characters...
1102         */
1103         memmove(start + insertCount, start,
1104                 MAX(0, WIDTH(line) - col - *returnCount));
1105
1106         /* 
1107         ** Compute the new line width...
1108         */
1109         newWidth = WIDTH(line) + insertCount;
1110     }
1111
1112     /* 
1113     ** Everything's ready:
1114     **     - put the characters into the line
1115     **     - adjust the line width (_DtTermPrimBufferSetLineWidth won't
1116     **       let the line get shorter)...
1117     **     - update the enhancements
1118     */
1119     memcpy(start, newChars, copyCount);
1120     _DtTermPrimBufferSetLineWidth(tb, row, newWidth);
1121     insertEnhancements(tb, row, col, insertCount, insertFlag);
1122     return(WIDTH(line));
1123 }
1124
1125 /* 
1126 ** Delete enough characters from the buffer to exceed width.
1127 **
1128 ** If returnChars != NULL then the deleted characters are returned
1129 ** in a buffer pointed to by returnChars.  It is the responsibility
1130 ** of the calling function to XtFree the buffer containing returned
1131 ** characters when they are no longer needed.
1132 */
1133 void
1134 _DtTermPrimBufferDelete
1135 (
1136     TermBuffer  tb,
1137     short      *row,
1138     short      *col,
1139     short      *width,
1140     termChar  **returnChars,  /* pointer to delete buffer        */
1141     short      *returnCount   /* count of bytes in delete buffer */
1142 )
1143 {
1144     int      copyCount;
1145     TermLine line;
1146     short    localRow;
1147     short    localCol;    
1148     TermCharInfoRec charInfo;
1149     
1150
1151     if (!VALID_ROW(tb, *row) || !VALID_COL(tb, *col))
1152     {
1153         if (returnChars)
1154         {
1155             *returnChars = NULL;
1156             *returnCount = 0;
1157         }
1158         return; 
1159     }
1160
1161     line     = LINE_OF_TBUF(tb, *row);
1162
1163 #ifdef  OLD_CODE
1164     /* before we modify the buffer, disown the selection... */
1165     (void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
1166 #endif  /* OLD_CODE */
1167
1168     /* if this line is part of the selection, disown the selection... */
1169     if (IS_IN_SELECTION(line, *col, MAX_SELECTION_COL)) {
1170         (void) _DtTermPrimSelectDisown(WIDGET(tb));
1171     }
1172
1173     if (BYTES_PER_CHAR(tb) > 1)
1174     {
1175         /*
1176         ** we do not handle multibyte characters here...
1177         */
1178         _DtTermPrimBufferDeleteWc(tb, row, col, width, returnChars,
1179                                   returnCount);
1180         return;
1181     }
1182     localRow = *row;
1183     localCol = *col;
1184     *width   = MAX(0, MIN(WIDTH(line) - localCol, *width));
1185
1186     /* 
1187     ** there are 4 cases of deleting a character from a line:
1188     **     Case 1:
1189     **       the cursor is past the end of the line (col >= WIDTH(line))
1190     **
1191     **     Case 2:
1192     **       the cursor is in the middle of the line (copyCount > 0)
1193     **          - move the remaining characters to the left
1194     **          - deleteEnhancement
1195     **
1196     **     Case 3:
1197     **       the cursor is at the end of the line (copyCount == 0 and
1198     **       col == WIDTH(line) - 1)
1199     **          - deleteEnhancement
1200     **          - adjust WIDTH and LENGTH
1201     */
1202     if (localCol >= WIDTH(line) || *width == 0)
1203     {
1204         /* 
1205         ** Handle Case 1...
1206         */
1207         if (returnChars)
1208         {
1209             *returnChars = NULL;
1210             *returnCount = 0;
1211         }
1212         return;
1213     }
1214
1215     _DtTermPrimGetCharacterInfo(tb, localRow, localCol, &charInfo);
1216     
1217     /* 
1218     ** Save the current characters before we overwrite them...
1219     */
1220     if (returnChars != NULL)
1221     {
1222         *returnCount = (*width * BYTES_PER_CHAR(tb));
1223         *returnChars = (termChar *)XtMalloc(*returnCount);
1224         memcpy(*returnChars, charInfo.u.pc, *returnCount);
1225     }
1226
1227     /* 
1228     ** Cases 2 and 3 require that we delete the enhancement...
1229     */
1230     if (DELETE_ENH(tb))
1231     {
1232         (*DELETE_ENH(tb))(tb, localRow, localCol, *width);
1233     }
1234
1235     copyCount = MAX(0, WIDTH(line) - *width - localCol);
1236     if (copyCount > 0)
1237     {
1238         /* 
1239         ** handle case 2
1240         */
1241         memmove(charInfo.u.pc, charInfo.u.pc + *width,
1242                 copyCount * BYTES_PER_CHAR(tb));
1243     }
1244
1245     /* 
1246     ** Case 2 and 3 require that we adjust the line width
1247     */
1248     WIDTH(line)  -= *width;
1249     LENGTH(line) -= *width;
1250 }
1251
1252 /*
1253 ** replace all characters between startCol, and stopCol with spaces,
1254 ** if startCol > stopCol, then simply return
1255 */
1256 void
1257 _DtTermPrimBufferErase
1258 (
1259     TermBuffer tb,
1260     short      row,
1261     short      startCol,
1262     short      stopCol
1263 )
1264 {
1265     TermCharInfoRec       charInfo;
1266     char                 *pchar;
1267
1268     /*
1269     ** Make sure we have a valid row, and if we have a valid
1270     ** row, make sure that startCol is <= stopCol
1271     */
1272     if (!(VALID_ROW(tb, row)) || (startCol > stopCol))
1273     {
1274         return;
1275     }
1276
1277 #ifdef  OLD_CODE
1278     /* before we modify the buffer, disown the selection... */
1279     (void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
1280 #endif  /* OLD_CODE */
1281
1282     /* if this line is part of the selection, disown the selection... */
1283     if (IS_IN_SELECTION(LINE_OF_TBUF(tb, row), startCol, stopCol)) {
1284         (void) _DtTermPrimSelectDisown(WIDGET(tb));
1285     }
1286
1287     if (BYTES_PER_CHAR(tb) > 1)
1288     {
1289         _DtTermPrimBufferEraseWc(tb, row, startCol, stopCol);
1290     }
1291     else
1292     {
1293         _DtTermPrimGetCharacterInfo(tb, row, startCol, &charInfo);
1294         pchar = charInfo.u.pc;
1295         
1296         _DtTermPrimGetCharacterInfo(tb, row, stopCol, &charInfo);
1297         
1298         /*
1299         ** replace the characters with spaces...
1300         */
1301         while(pchar <= charInfo.u.pc)
1302         {
1303             *pchar = ' ';
1304             pchar++;
1305         }
1306     }
1307 }
1308
1309
1310 /*
1311 ** Adjust the line width, (the line can never be shortened)
1312 */
1313 Boolean
1314 _DtTermPrimBufferSetLineWidth
1315 (
1316     const TermBuffer    tb,
1317     const short         row,
1318           short         newWidth
1319 )
1320 {
1321     TermLine    line;
1322     
1323     /*
1324     ** Make sure we have a valid row.
1325     */
1326     if (!VALID_ROW(tb, row))
1327     {
1328         return(False);
1329     }
1330
1331     line = LINE_OF_TBUF(tb, row);
1332
1333 #ifdef  OLD_CODE
1334     /* before we modify the buffer, disown the selection... */
1335     (void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
1336 #endif  /* OLD_CODE */
1337
1338     /* if this line is part of the selection, disown the selection... */
1339     if (IS_IN_SELECTION(line, newWidth, MAX_SELECTION_COL)) {
1340         (void) _DtTermPrimSelectDisown(WIDGET(tb));
1341     }
1342
1343     /*
1344     ** Clip the new width to the buffer width.
1345     */
1346     newWidth = MIN(newWidth, COLS(tb));
1347
1348     /*
1349     ** Make sure we actually have something to do.
1350     */
1351     if (WIDTH(line) >= newWidth)
1352     {
1353         return(True);
1354     }
1355
1356     WIDTH(line) = newWidth;
1357     if (BYTES_PER_CHAR(tb) == 1)
1358     {
1359         /*
1360         ** in single byte locales, we go ahead and set the line length too,
1361         ** it is the responsibility of wide-character routines to set the
1362         ** line length themselves...
1363         */ 
1364         LENGTH(line) = newWidth; /* works in single byte locales */
1365     }
1366     
1367     return(True);
1368 }
1369
1370 /*
1371 ** the line length is the lesser of the actual length, or the length
1372 ** necessary to get to the buffer width
1373 ** (in the case that the buffer shrank after the line was full)
1374 */
1375 short
1376 _DtTermPrimBufferGetLineLength
1377 (
1378     const TermBuffer    tb,
1379     const short         row
1380 )
1381 {
1382     short           retLen;
1383     short           width;
1384     TermCharInfoRec charInfo;
1385     
1386     if (VALID_ROW(tb, row)) 
1387     {
1388         width = MIN(WIDTH(LINE_OF_TBUF(tb, row)), COLS(tb));
1389         if (width > 0)
1390         {
1391             
1392             (void)_DtTermPrimGetCharacterInfo(tb, row, width - 1, &charInfo);
1393     
1394             /*
1395             ** a line can not end on column 1 of 2.  Note that we must
1396             ** add 1 to the column index to make it the line length...
1397             */
1398             if ((charInfo.width == 2) && (charInfo.startCol != width - 2)) {
1399                 /* only half of charInfo.idx fits in the line, so drop
1400                  * it...
1401                  */
1402                 retLen = charInfo.idx;
1403             } else {
1404                 /* single column character or double column character that
1405                  * fits on the line...
1406                  */
1407                 retLen = charInfo.idx + 1;
1408             }
1409         }
1410         else
1411         {
1412             retLen = 0;
1413         }
1414     }
1415     else
1416     {
1417         retLen = 0;
1418     }
1419     
1420     return(retLen);
1421
1422 }
1423
1424 /*
1425 ** the line width is the lesser of the actual width, or the buffer width
1426 ** (in the case that the buffer shrank after the line was full)
1427 */
1428 short
1429 _DtTermPrimBufferGetLineWidth
1430 (
1431     const TermBuffer    tb,
1432     const short         row
1433 )
1434 {
1435     short           width = 0;
1436     TermCharInfoRec charInfo;
1437     
1438     if (VALID_ROW(tb, row)) 
1439     {
1440         width = MIN(WIDTH(LINE_OF_TBUF(tb, row)), COLS(tb));
1441         if (width > 0)
1442         {
1443             
1444             (void)_DtTermPrimGetCharacterInfo(tb, row, width - 1, &charInfo);
1445     
1446             /*
1447             ** a line can not end on column 1 of 2...
1448             */
1449             if ((charInfo.width == 2) && (charInfo.startCol != width - 2)) {
1450                 /* only half of charInfo.idx fits in the line, so drop
1451                  * it...
1452                  */
1453                 (void) width--;
1454             } else {
1455                 /* single column character or double column character that
1456                  * fits on the line...
1457                  */
1458             }
1459         }
1460     }
1461     
1462     return(width);
1463 }
1464
1465
1466 /**************************************************************************
1467  *  Function:
1468  *      _DtTermPrimBufferMoveLockArea():
1469  *              move locked screen memory up or down in the screen buffer.
1470  *
1471  *  Parameters:
1472  *      TermBuffer tb: term buffer to use
1473  *      short dest: point to move the locked region to
1474  *      short src: point to move the locked region from
1475  *      short length: size of the locked region
1476  *
1477  *  Returns:
1478  *      <nothing>
1479  *
1480  *  Notes:
1481  */
1482 void
1483 _DtTermPrimBufferMoveLockArea
1484 (
1485     const TermBuffer tb, 
1486     const short dest,
1487     const short src,
1488     const short length
1489 )
1490 {
1491     TermLine lineCache[10];
1492     TermLine *holdLines = lineCache;
1493     TermLine *destPtr;
1494     TermLine *srcPtr;
1495     short cacheSize;
1496     short distance;
1497     int i;
1498     int refLineCount;
1499     TermLine *refLines;
1500
1501     DebugF('B', 1, RememberTermBuffer(tb,&refLines,&refLineCount));
1502
1503     /* don't bother if there is we are being asked to do nothing...
1504      */
1505     if ((length <= 0) || (dest == src))
1506         return;
1507
1508 #ifdef  OLD_CODE
1509     /* before we modify the buffer, disown the selection... */
1510     (void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
1511 #endif  /* OLD_CODE */
1512
1513     /* before we modify the buffer, check and see if the leading or
1514      * trailing edge of the buffer crosses the selection and if the
1515      * destination line crosses the selection.  If it does, we need
1516      * to disown it...
1517      */
1518     /* leading edge of src... */
1519     if ((src > 0) &&
1520             IS_IN_SELECTION(LINE_OF_TBUF(tb, src - 1), MIN_SELECTION_COL,
1521             MAX_SELECTION_COL) &&
1522             IS_IN_SELECTION(LINE_OF_TBUF(tb, src), MIN_SELECTION_COL,
1523             MAX_SELECTION_COL)) {
1524         (void) _DtTermPrimSelectDisown(WIDGET(tb));
1525     }
1526
1527     /* trailing edge of src... */
1528     if (((src + length) < ROWS(tb)) &&
1529             IS_IN_SELECTION(LINE_OF_TBUF(tb, src + length - 1),
1530             MIN_SELECTION_COL, MAX_SELECTION_COL) &&
1531             IS_IN_SELECTION(LINE_OF_TBUF(tb, src + length), MIN_SELECTION_COL,
1532             MAX_SELECTION_COL)) {
1533         (void) _DtTermPrimSelectDisown(WIDGET(tb));
1534     }
1535
1536     /* destination... */
1537     if ((dest > 0) && IS_IN_SELECTION(LINE_OF_TBUF(tb, dest - 1),
1538             MIN_SELECTION_COL, MAX_SELECTION_COL) &&
1539             IS_IN_SELECTION(LINE_OF_TBUF(tb, dest),
1540             MIN_SELECTION_COL, MAX_SELECTION_COL)) {
1541         (void) _DtTermPrimSelectDisown(WIDGET(tb));
1542     }
1543         
1544     /* we need to save the line positions of the smaller of the length
1545      * of the chunk to move, or the distance to move the chunk.
1546      */
1547     distance = (dest > src) ? (dest - src) : (src - dest);
1548     cacheSize = MIN(length, distance);
1549
1550     /* if we are moving more lines than will fit in the lineCache, we need
1551      * to malloc (and free) storage for the termLineRecs...
1552      */
1553     if (cacheSize > (sizeof(lineCache) / sizeof(lineCache[0]))) {
1554         holdLines = (TermLine *) XtMalloc(cacheSize * sizeof(TermLine));
1555     }
1556
1557      /*
1558      ** clear the wrap flag for the line preceding the block to be
1559      ** moved, and the last line of the block to be moved
1560      */
1561      _DtTermPrimBufferSetLineWrapFlag(tb, src - 1, FALSE);
1562      _DtTermPrimBufferSetLineWrapFlag(tb, src + length, FALSE);
1563
1564     /* cache them away... */
1565     if (distance > length) {
1566         /* save away the locked area... */
1567         destPtr = holdLines;
1568         srcPtr = &(LINE_OF_TBUF(tb, src));
1569
1570         for (i = 0; i < length; i++) {
1571             *destPtr++ = *srcPtr++;
1572         }
1573         /* move the area above/below the locked area... */
1574         if (dest > src) {
1575             /* we are moving the locked area down, so we must move
1576              * the scroll area up...
1577              */
1578             destPtr = &(LINE_OF_TBUF(tb, src));
1579             srcPtr = &(LINE_OF_TBUF(tb, src + length));
1580             for (i = 0; i < distance; i++) {
1581                 *destPtr++ = *srcPtr++;
1582             }
1583         } else {
1584             /* we are moving the locked area up, so we must move
1585              * the scroll area down...
1586              */
1587             destPtr = &(LINE_OF_TBUF(tb, src + length - 1));
1588             srcPtr = &(LINE_OF_TBUF(tb, src - 1));
1589             for (i = 0; i < distance; i++) {
1590                 *destPtr-- = *srcPtr--;
1591             }
1592         }
1593         /* restore the cached lock area... */
1594         destPtr = &(LINE_OF_TBUF(tb, dest));
1595         srcPtr = holdLines;
1596         for (i = 0; i < length; i++) {
1597             *destPtr++ = *srcPtr++;
1598         }
1599     } else {
1600         /* save away the area we will move the lock area over...
1601          */
1602         if (dest > src) {
1603             /* moving it down.  Save the area under the lock area...
1604              */
1605             destPtr = holdLines;
1606             srcPtr = &(LINE_OF_TBUF(tb, src + length));
1607             for (i = 0; i < distance; i++) {
1608                 *destPtr++ = *srcPtr++;
1609             }
1610             /* move the lock area down... */
1611             destPtr = &(LINE_OF_TBUF(tb, dest + length - 1));
1612             srcPtr = &(LINE_OF_TBUF(tb, src + length - 1));
1613             for (i = 0; i < length; i++) {
1614                 *destPtr-- = *srcPtr--;
1615             }
1616             /* restore the area under (that is now over) the lock area... */
1617             destPtr = &(LINE_OF_TBUF(tb, src));
1618             srcPtr = holdLines;
1619             for (i = 0; i < distance; i++) {
1620                 *destPtr++ = *srcPtr++;
1621             }
1622         } else {
1623             /* moving it up.  Save the area over the lock area...
1624              */
1625             destPtr = holdLines;
1626             srcPtr = &(LINE_OF_TBUF(tb, dest));
1627             for (i = 0; i < distance; i++) {
1628                 *destPtr++ = *srcPtr++;
1629             }
1630             /* move the lock area up... */
1631             destPtr = &(LINE_OF_TBUF(tb, dest));
1632             srcPtr = &(LINE_OF_TBUF(tb, src));
1633             for (i = 0; i < length; i++) {
1634                 *destPtr++ = *srcPtr++;
1635             }
1636             /* restore the area over (that is now under) the lock area... */
1637             destPtr = &(LINE_OF_TBUF(tb, dest + length));
1638             srcPtr = holdLines;
1639             for (i = 0; i < distance; i++) {
1640                 *destPtr++ = *srcPtr++;
1641             }
1642         }
1643     }
1644
1645     /* free up the holdLines (if we malloc'ed it)... */
1646     if (holdLines != lineCache) {
1647         (void) XtFree((char *) holdLines);
1648     }
1649
1650     DebugF('B', 1, CheckTermBuffer(tb,refLines,refLineCount));
1651 }
1652
1653
1654 /**************************************************************************
1655  *  Function:
1656  *      _DtTermPrimBufferInsertLine():  insert one or more lines of text from
1657  *              the end of the buffer below the insertion point, or from
1658  *              the beginning of the buffer above the insertion point.
1659  *
1660  *  Parameters:
1661  *      TermBuffer tb: term buffer to insert end/begining into
1662  *      short dest: point to insert below/above
1663  *      short length: number of lines to insert
1664  *      short src: source point of insertion
1665  *
1666  *  Returns:
1667  *      <nothing>
1668  *
1669  *  Notes:
1670  */
1671 void
1672 _DtTermPrimBufferInsertLine
1673 (
1674     const TermBuffer tb,
1675     const short dest,
1676     const short length,
1677     const short src
1678 )
1679 {
1680     TermLine lineCache[10];
1681     TermLine *holdLines = lineCache;
1682     TermLine *destPtr;
1683     TermLine *srcPtr;
1684     short distance;
1685     int i;
1686     int refLineCount;
1687     TermLine *refLines;
1688
1689     DebugF('B', 1, RememberTermBuffer(tb,&refLines,&refLineCount));
1690
1691     /* don't bother if there is we are being asked to do nothing...
1692      */
1693     if (length <= 0)
1694         return;
1695
1696 #ifdef  OLD_CODE
1697     /* before we modify the buffer, disown the selection... */
1698     (void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
1699 #endif  /* OLD_CODE */
1700
1701     /* before we modify the buffer, check and see if the
1702      * destination line crosses the selection.  If it does, we need
1703      * to disown it...
1704      */
1705     /* destination... */
1706     if (dest > src) {
1707         if (((dest + length) < ROWS(tb)) &&
1708                 IS_IN_SELECTION(LINE_OF_TBUF(tb, dest + length),
1709                 MIN_SELECTION_COL, MAX_SELECTION_COL) &&
1710                 IS_IN_SELECTION(LINE_OF_TBUF(tb, dest + length + 1),
1711                 MIN_SELECTION_COL, MAX_SELECTION_COL)) {
1712             (void) _DtTermPrimSelectDisown(WIDGET(tb));
1713         }
1714     } else {
1715         if (dest > 1) {
1716             if (IS_IN_SELECTION(LINE_OF_TBUF(tb, dest),
1717                     MIN_SELECTION_COL, MAX_SELECTION_COL) &&
1718                     IS_IN_SELECTION(LINE_OF_TBUF(tb, dest - 1),
1719                     MIN_SELECTION_COL, MAX_SELECTION_COL)) {
1720                 (void) _DtTermPrimSelectDisown(WIDGET(tb));
1721             }
1722         }
1723     }
1724
1725     /* if we are being asked to move all (or more) the lines in the
1726      * buffer, then we can just clear them all out and return...
1727      */
1728     if (length >= ROWS(tb)) {
1729         for (i = 0; i < ROWS(tb); i++) {
1730             _DtTermPrimBufferClearLine(tb, i, 0);
1731         }
1732         return;
1733     }
1734
1735     /* if dest and src match, we can just clear them out and return...
1736      */
1737     if (src == dest) {
1738         for (i = 0; (i < length) && ((i + dest) < ROWS(tb)); i++) {
1739             _DtTermPrimBufferClearLine(tb, src + i, 0);
1740         }
1741         return;
1742     }
1743
1744     /* if we are moving more lines than will fit in the lineCache, we need
1745      * to malloc (and free) storage for the termLineRecs...
1746      */
1747     if (length > (sizeof(lineCache) / sizeof(lineCache[0]))) {
1748         holdLines = (TermLine *) XtMalloc(length * sizeof(TermLine));
1749     }
1750
1751     if (dest > src) {
1752         /* our src is above the destination.  Copy the lines to insert,
1753          * move the lines above the insertion pointer up, and insert
1754          * the saved lines...
1755          */
1756
1757         /* save away the top length lines... */
1758         destPtr = holdLines;
1759         srcPtr = &(LINE_OF_TBUF(tb, src));
1760         for (i = 0; i < length; i++) {
1761             /* these lines will be cleared, so we don't need to track
1762              * movement of them...
1763              */
1764             *destPtr++ = *srcPtr++;
1765         }
1766         /* copy the lines above the insertion point up... */
1767         destPtr = &(LINE_OF_TBUF(tb, src));
1768         srcPtr = &(LINE_OF_TBUF(tb, src + length));
1769         for (i = src; i < dest - length + 1; i++) {
1770             *destPtr++ = *srcPtr++;
1771         }
1772         /* restore the saved lines above the insertion point... */
1773         destPtr = &(LINE_OF_TBUF(tb, dest - length + 1));
1774         srcPtr = holdLines;
1775         for (i = 0; i < length; i++) {
1776             *destPtr = *srcPtr;
1777             /* clear the line... */
1778             _DtTermPrimBufferClearLine(tb, dest - length + 1 + i, 0);
1779             *destPtr++;
1780             *srcPtr++;
1781         }
1782
1783 #ifdef  DONT_DO_THIS_ANY_MORE
1784         /* Adjust or disown selection */
1785         _DtTermPrimSelectDeleteLine(tb,length) ;
1786 #endif  /* DONT_DO_THIS_ANY_MORE */
1787     } else {
1788         /* our src is below the destination.  Copy the lines to insert,
1789          * move the lines below the insertion pointer down, and insert
1790          * the saved lines...
1791          */
1792         /* save away the bottom length lines... */
1793         destPtr = holdLines;
1794         srcPtr = &(LINE_OF_TBUF(tb, src));
1795         for (i = 0; i < length; i++) {
1796             *destPtr++ = *srcPtr++;
1797         }
1798         /* copy the lines below the insertion point down... */
1799         destPtr = &(LINE_OF_TBUF(tb, src + length - 1));
1800         srcPtr = &(LINE_OF_TBUF(tb, src - 1));
1801         for (i = 0; i < src - dest; i++) {
1802             *destPtr-- = *srcPtr--;
1803         }
1804         /* restore the saved lines below the insertion point... */
1805         destPtr = &(LINE_OF_TBUF(tb, dest));
1806         srcPtr = holdLines;
1807         for (i = 0; i < length; i++) {
1808             *destPtr = *srcPtr;
1809             /* clear the line... */
1810             _DtTermPrimBufferClearLine(tb, dest + i, 0);
1811             *destPtr++;
1812             *srcPtr++;
1813         }
1814     }
1815
1816     /* free up the holdLines (if we malloc'ed it)... */
1817     if (holdLines != lineCache) {
1818         (void) XtFree((char *) holdLines);
1819     }
1820
1821     DebugF('B', 1, CheckTermBuffer(tb,refLines,refLineCount));
1822 }
1823
1824
1825 /**************************************************************************
1826  *  Function:
1827  *      _DtTermPrimBufferInsertLineFromTB():  insert one or more lines
1828  *              of text from the end of the buffer below the insertion
1829  *              point, or from the beginning of the buffer above the
1830  *              insertion point.
1831  *
1832  *  Parameters:
1833  *      TermBuffer tb: term buffer to insert end/begining into
1834  *      short dest: point to insert below/above
1835  *      short length: number of lines to insert
1836  *      InsertSource: source of insertion (end or beginning)
1837  *
1838  *  Returns:
1839  *      <nothing>
1840  *
1841  *  Notes:
1842  */
1843 void
1844 _DtTermPrimBufferInsertLineFromTB
1845 (
1846     const TermBuffer tb,
1847     const short dest,
1848     const short length,
1849     const InsertSource insertSource
1850 )
1851 {
1852     if (insertSource == insertFromTop) {
1853         (void) _DtTermPrimBufferInsertLine(tb, dest, length, 0);
1854     } else {
1855         (void) _DtTermPrimBufferInsertLine(tb, dest, length,
1856                 ROWS(tb) - length);
1857     }
1858 }
1859
1860
1861 #ifdef  NOTDONE
1862 /**************************************************************************
1863  *  Function:
1864  *      _DtTermPrimBufferScrollToHistory():  scroll one or more lines
1865  *              of text from the beginning of the active buffer into
1866  *              the history buffer.
1867  *
1868  *  Parameters:
1869  *      TermBuffer tb: term buffer to scroll out of
1870  *      short length: number of lines to scroll
1871  *
1872  *  Returns:
1873  *      the number of lines scrolled (removed from active buffer)
1874  *
1875  *  Notes:
1876  */
1877 int
1878 _DtTermPrimBufferScrollToHistory()
1879 (
1880     const TermBuffer tb,
1881     const short length,
1882 )
1883 {
1884     if (PREV_BUFFER(tb)) {
1885     
1886 }
1887 #endif  /* NOTDONE */
1888
1889
1890 /**************************************************************************
1891  *  Function:
1892  *      _DtTermPrimBufferDeleteLine():  deletes one or more lines of text from
1893  *              the deletion poing and sticks them at the end of the
1894  *              line buffer.  It does not clear the line.  That is
1895  *              normally done when the line is inserted.
1896  *
1897  *  Parameters:
1898  *      TermBuffer tb: term buffer to insert end/begining into
1899  *      short source: point to insert below/above
1900  *      short length: number of lines to insert
1901  *      short lastUsedLine: number of last line in the buffer we need
1902  *              to keep
1903  *
1904  *  Returns:
1905  *      <nothing>
1906  *
1907  *  Notes:
1908  */
1909 void
1910 _DtTermPrimBufferDeleteLine
1911 (   
1912     const TermBuffer tb, 
1913     const short source,
1914     const short length,
1915     const short lastUsedRow
1916 )
1917 {
1918     TermLine lineCache[10];
1919     TermLine *holdLines = lineCache;
1920     TermLine *destPtr;
1921     TermLine *srcPtr;
1922     short copyLength;
1923     int i;
1924     int refLineCount;
1925     TermLine *refLines;
1926
1927     DebugF('B', 1, RememberTermBuffer(tb,&refLines,&refLineCount));
1928
1929     /* don't bother if there is we are being asked to do nothing...
1930      */
1931     if (length <= 0)
1932         return;
1933     /* if we are being asked to move the last usedLines, we don't have
1934      * to do anything either...
1935      */
1936     if (source + length >= lastUsedRow)
1937         return;
1938
1939 #ifdef  OLD_CODE
1940     /* before we modify the buffer, disown the selection... */
1941     (void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
1942 #endif  /* OLD_CODE */
1943
1944     /* if we are moving more lines than will fit in the lineCache, we need
1945      * to malloc (and free) storage for the termLineRecs...
1946      */
1947     if (length > (sizeof(lineCache) / sizeof(lineCache[0]))) {
1948         holdLines = (TermLine *) XtMalloc(length * sizeof(TermLine));
1949     }
1950
1951     /* clear the deleted lines... */
1952     for (i = 0; i < length; i++) {
1953         (void) _DtTermPrimBufferClearLine(tb, source + i, 0);
1954     }
1955
1956 #ifdef  USE_MEMCPY
1957     (void) memcpy(holdLines, &(LINE_OF_TBUF(tb, source)), length * 
1958                   sizeof(TermLine));
1959 #else   /* USE_MEMCPY */
1960     destPtr = holdLines;
1961     srcPtr = &(LINE_OF_TBUF(tb, source));
1962     for (i = 0; i < length; i++) {
1963         *destPtr++ = *srcPtr++;
1964     }
1965 #endif  /* USE_MEMCPY */
1966
1967     /* ripple up the lines... */
1968     copyLength = MAX(0, MIN(ROWS(tb), lastUsedRow) - source - length);
1969     if (copyLength > 0) {
1970 #ifdef  USE_MEMCPY
1971         (void) memcpy(&(LINE_OF_TBUF(tb, source)),
1972                       &(LINE_OF_TBUF(tb, source + length)),
1973                       copyLength * sizeof(TermLine));
1974 #else   /* USE_MEMCPY */
1975         destPtr = &(LINE_OF_TBUF(tb, source));
1976         srcPtr = &(LINE_OF_TBUF(tb, source + length));
1977         for (i = 0; i < copyLength; i++) {
1978             *destPtr++ = *srcPtr++;
1979         }
1980 #endif  /* USE_MEMCPY */
1981     }
1982
1983     /* copy back the deleted (cached) lines... */
1984 #ifdef  USE_MEMCPY
1985     (void) memcpy(&(LINE_OF_TBUF(tb, source + copyLength)), holdLines,
1986             length * sizeof(TermLine));
1987 #else   /* USE_MEMCPY */
1988     destPtr = &(LINE_OF_TBUF(tb, source + copyLength));
1989     srcPtr = holdLines;
1990     for (i = 0; i < length; i++) {
1991         *destPtr++ = *srcPtr++;
1992     }
1993 #endif  /* USE_MEMCPY */
1994
1995     /* free up the holdLines (if we malloc'ed it)... */
1996     if (holdLines != lineCache) {
1997         (void) XtFree((char *) holdLines);
1998     }
1999
2000     DebugF('B', 1, CheckTermBuffer(tb,refLines,refLineCount));
2001 }
2002
2003 /*
2004 ** Pad the requested row from the current width to 'newWidth' with spaces...
2005 */
2006 void
2007 _DtTermPrimBufferPadLine
2008 (
2009     const TermBuffer  tb,
2010     const short       row,
2011     const short       newWidth
2012 )
2013 {
2014     TermLine    line;
2015     
2016 #ifdef  OLD_CODE
2017     /* before we modify the buffer, disown the selection... */
2018     (void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
2019 #endif  /* OLD_CODE */
2020
2021     line = LINE_OF_TBUF(tb, row);
2022
2023     /* if this line is part of the selection, disown the selection... */
2024     if (IS_IN_SELECTION(line, MIN(newWidth, WIDTH(line)),
2025             MAX(newWidth, WIDTH(line)))) {
2026         (void) _DtTermPrimSelectDisown(WIDGET(tb));
2027     }
2028
2029     (void)memset(BUFFER(line) + WIDTH(line),
2030                  0x20, (newWidth - WIDTH(line)) * BYTES_PER_CHAR(tb));
2031     if (CLEAR_ENH(tb))
2032     {
2033         (*CLEAR_ENH(tb))(tb, row, WIDTH(line), newWidth - WIDTH(line));
2034     }
2035     _DtTermPrimBufferSetLineWidth(tb, row, newWidth);
2036 }
2037
2038 /*
2039 ** Clear the line to the new width (just reset the line width).
2040 ** NOTES:
2041 **     We also clear the wrapped flag as well.
2042 */
2043 Boolean
2044 _DtTermPrimBufferClearLine
2045 (
2046     const TermBuffer  tb,
2047     const short       row,
2048           short       newWidth
2049 )
2050 {
2051     TermLine    line;
2052
2053 #ifdef  OLD_CODE
2054     /* before we modify the buffer, disown the selection... */
2055     (void) _DtTermPrimSelectDisownIfNecessary(WIDGET(tb));
2056 #endif  /* OLD_CODE */
2057
2058     /*
2059     ** handle multi-byte locales...
2060     */
2061     if (BYTES_PER_CHAR(tb) > 1)
2062     {
2063         return(_DtTermPrimBufferClearLineWc(tb, row, newWidth));
2064     }
2065         
2066     /*
2067     ** Some simple bounds checking.
2068     */
2069     if (!VALID_ROW(tb, row))
2070     {
2071         return(False);
2072     }
2073
2074     line = LINE_OF_TBUF(tb, row);
2075
2076     /* if this line is part of the selection, disown the selection... */
2077     if (IS_IN_SELECTION(line, MIN(newWidth, WIDTH(line)),
2078             MAX(newWidth, WIDTH(line)))) {
2079         (void) _DtTermPrimSelectDisown(WIDGET(tb));
2080     }
2081
2082     /*
2083     ** Clip the new width to the buffer width.
2084     */
2085     newWidth = MIN(newWidth, COLS(tb));
2086
2087     /*
2088     ** force width to the desired value
2089     **
2090     ** (We take the direct approach because _DtTermPrimBufferSetLineWidth
2091     **  doesn't allow the line width to decrease.)
2092     */
2093     if (newWidth < WIDTH(line))
2094     {
2095         /* 
2096         ** Call the helper function if it exists
2097         */
2098         if (CLEAR_LINE(tb))
2099         {
2100             (*CLEAR_LINE(tb))(tb, row, newWidth);
2101         }
2102         WRAPPED(line) = False;
2103         WIDTH(line)   = newWidth;
2104         LENGTH(line)  = newWidth; /* this works in single-byte locales */
2105     }
2106     return(True);
2107 }
2108
2109 short
2110 _DtTermPrimBufferGetNextTab
2111 (
2112     const TermBuffer    tb,
2113           short         col
2114 )
2115 {
2116     if (!VALID_COL(tb, col))
2117     {
2118         return(0);
2119     }
2120
2121     /* find the next set tab stop... */
2122     for (col++; (col < COLS(tb)) && (!TABS(tb)[col]); col++)
2123         ;
2124
2125     /* did we go to the end of the line w/out hitting one?... */
2126     if (col >= COLS(tb)) {
2127         return(0);
2128     } else {
2129         return(col);
2130     }
2131 }
2132
2133
2134 short
2135 _DtTermPrimBufferGetPreviousTab
2136 (
2137     const TermBuffer    tb,
2138           short         col
2139 )
2140 {
2141     if (!VALID_COL(tb, col - 1))
2142     {
2143         return(0);
2144     }
2145
2146     /* find the next set tab stop... */
2147     for (col--; (col > 0) && (!TABS(tb)[col]); col--)
2148         ;
2149
2150     /* we can just return col.  If ther was not another tab stop, it will
2151      * be -1...
2152      */
2153     return(col);
2154 }
2155
2156
2157 Boolean
2158 _DtTermPrimBufferSetTab
2159 (
2160     const TermBuffer    tb,
2161     const short         col
2162 )
2163 {
2164     if (VALID_COL(tb, col))
2165     {
2166         TABS(tb)[col] = True;
2167         return(True);
2168     }
2169     return(False);
2170 }
2171
2172
2173 Boolean
2174 _DtTermPrimBufferClearTab
2175 (
2176     const TermBuffer    tb,
2177     const short         col
2178 )
2179 {
2180     if (VALID_COL(tb, col))
2181     {
2182         TABS(tb)[col] = False;
2183         return(True);
2184     }
2185     return(False);
2186 }
2187
2188
2189 Boolean
2190 _DtTermPrimBufferClearAllTabs
2191 (
2192     const TermBuffer      tb
2193 )
2194 {
2195     (void) memset(TABS(tb), '\0', COLS(tb) * sizeof(Boolean));
2196     return(True);
2197 }
2198
2199 /*
2200 ** Set the line wrap flag to the desired state.
2201 */
2202 void
2203 _DtTermPrimBufferSetLineWrapFlag
2204 (
2205     TermBuffer  tb,
2206     short       row,
2207     Boolean     state
2208 )
2209 {
2210     if (VALID_ROW(tb, row))
2211     {
2212         WRAPPED(LINE_OF_TBUF(tb, row)) = state;
2213     }
2214     return;
2215 }
2216
2217 /*
2218 ** Return the state of the line wrap flag.
2219 */
2220 Boolean
2221 _DtTermPrimBufferTestLineWrapFlag
2222 (
2223     TermBuffer  tb,
2224     short       row
2225 )
2226 {
2227     if (VALID_ROW(tb, row))
2228     {
2229         return(WRAPPED(LINE_OF_TBUF(tb, row)));
2230     }
2231     else 
2232     {
2233         return(FALSE);
2234     }
2235 }
2236
2237 /*
2238 ** Set the in selection flag to the desired state.
2239 */
2240 void
2241 _DtTermPrimBufferSetInSelectionFlag
2242 (
2243     TermBuffer  tb,
2244     short       row,
2245     TermLineSelection     state
2246 )
2247 {
2248     if (VALID_ROW(tb, row))
2249     {
2250         if (state) {
2251             START_SELECTION(LINE_OF_TBUF(tb, row)) = state->selectionStart;
2252             END_SELECTION(LINE_OF_TBUF(tb, row)) = state->selectionEnd;
2253         } else {
2254             START_SELECTION(LINE_OF_TBUF(tb, row)) = NON_SELECTION_COL;
2255             END_SELECTION(LINE_OF_TBUF(tb, row)) = NON_SELECTION_COL;
2256         }
2257     }
2258     return;
2259 }
2260
2261 /*
2262 ** Return the state of the in selection flag.
2263 */
2264 TermLineSelection
2265 _DtTermPrimBufferGetInSelectionFlag
2266 (
2267     TermBuffer  tb,
2268     short       row
2269 )
2270 {
2271     if (VALID_ROW(tb, row))
2272     {
2273         if ((START_SELECTION(LINE_OF_TBUF(tb, row)) != NON_SELECTION_COL) &&
2274                 (END_SELECTION(LINE_OF_TBUF(tb, row)) != NON_SELECTION_COL)) {
2275             return(&IN_SELECTION(LINE_OF_TBUF(tb, row)));
2276         }
2277     }
2278     return((TermLineSelection) 0);
2279 }
2280
2281 void
2282 _DtTermPrimBufferSetSelectLines
2283 (
2284     TermBuffer tb,
2285     short beginRow,
2286     short beginCol,
2287     short endRow,
2288     short endCol
2289 )
2290 {
2291     int                   i1;
2292
2293     for (i1 = 0; i1 < ROWS(tb); i1++) {
2294         if ((i1 >= beginRow) && (i1 <= endRow)) {
2295             if (i1 == beginRow) {
2296                 START_SELECTION(LINE_OF_TBUF(tb, i1)) = beginCol;
2297             } else {
2298                 START_SELECTION(LINE_OF_TBUF(tb, i1)) = MIN_SELECTION_COL;
2299             }
2300             if (i1 == endRow) {
2301                 END_SELECTION(LINE_OF_TBUF(tb, i1)) = endCol;
2302             } else {
2303                 END_SELECTION(LINE_OF_TBUF(tb, i1)) = MAX_SELECTION_COL;
2304             }
2305         } else {
2306             START_SELECTION(LINE_OF_TBUF(tb, i1)) = NON_SELECTION_COL;
2307             END_SELECTION(LINE_OF_TBUF(tb, i1)) = NON_SELECTION_COL;
2308         }
2309     }
2310 }
2311
2312 #if (defined(TEST) || defined(__CODECENTER__) || defined(DEBUG))
2313 static void
2314 _termBufferPrintLine
2315 (
2316     const TermBuffer tb,
2317     const short row
2318 )
2319 {
2320     TermLine    line;
2321     termChar   *pChar;
2322     short       j;
2323
2324     printf("Line: %d\n", row);
2325
2326     line = LINE_OF_TBUF(tb, row];
2327     printf("    width: %3d\n", WIDTH(line));
2328     printf("    length: %3d\n", LENGTH(line));
2329     if (LENGTH(line) > 0)
2330     {
2331         printf("    buffer: <");
2332         pChar = BUFFER(line);
2333         for (j = 0; j < LENGTH(line); j++)
2334         {
2335             printf("%X", *pChar++);
2336         }
2337         printf(">\n");
2338     }
2339 }
2340
2341 /*
2342 ** Print the contents of the TermBuffer.
2343 */
2344 static void
2345 _termBufferPrintBuffer
2346 (
2347     const TermBuffer tb
2348 )
2349 {
2350     short i;
2351     short j;
2352     short k;
2353
2354     if (tb == NULL) {
2355         printf("TermBuffer has been freed.\n");
2356         return;
2357     }
2358
2359     printf("TermBuffer dimensions:\n");
2360     printf("    rows: %d\n", ROWS(tb));
2361     printf("    cols: %d\n", COLS(tb));
2362
2363     for (i = 0; i < ROWS(tb); i++)
2364     {
2365         _termBufferPrintLine(tb, i);
2366     }
2367 }
2368 #endif /* (defined(TEST) || defined(__CODECENTER__)) */
2369
2370 #ifdef TEST
2371 /*
2372 ** Some simple tests of the termBuffer.
2373 */
2374 /* the following is to allow for a single main function in the code... */
2375 #define       termBufMain     main
2376 termBufMain()
2377 {
2378     const TermBuffer  myTB;
2379
2380     printf("Sizeof termEnhRec    : %d\n", sizeof(struct _termEnhRec));
2381     printf("Sizeof termBufferRec : %d\n", sizeof(struct _TermBufferRec));
2382
2383     myTB = _DtTermPrimBufferCreateBuffer(12, 80);
2384     _termBufferPrintBuffer(myTB);
2385
2386     printf("[0,0] %d\n", _DtTermPrimBufferSetEnhancement(myTB, 0, 0, enhVideo, BLINK));
2387     _termBufferPrintEnhancement(myTB, 0, 0);
2388     printf("[0,1] %d\n", _DtTermPrimBufferSetEnhancement(myTB, 0, 1, enhVideo, INVERSE));
2389     _termBufferPrintEnhancement(myTB, 0, 0);
2390     _termBufferPrintEnhancement(myTB, 0, 1);
2391     printf("[0,9] %d\n", _DtTermPrimBufferSetEnhancement(myTB, 0, 9, enhVideo, UNDERLINE));
2392     _termBufferPrintEnhancement(myTB, 0, 0);
2393     _termBufferPrintEnhancement(myTB, 0, 1);
2394     _termBufferPrintEnhancement(myTB, 0, 9);
2395     printf("[0,6] %d\n", _DtTermPrimBufferSetEnhancement(myTB, 0, 6, enhVideo, HALF_BRIGHT));
2396     _termBufferPrintEnhancement(myTB, 0, 0);
2397     _termBufferPrintEnhancement(myTB, 0, 1);
2398     _termBufferPrintEnhancement(myTB, 0, 6);
2399     _termBufferPrintEnhancement(myTB, 0, 9);
2400     _termBufferPrintBuffer(myTB);
2401
2402     _DtTermPrimBufferSetEnhancement(myTB, 10, 10, enhVideo, BLINK);
2403     _DtTermPrimBufferSetEnhancement(myTB, 10, 20, enhColor, 3);
2404     _termBufferPrintBuffer(myTB);
2405
2406     _DtTermPrimBufferResizeBuffer(&myTB,  6, 40);
2407     _termBufferPrintBuffer(myTB);
2408
2409     _DtTermPrimBufferSetEnhancement(myTB, 10, 10, enhVideo, BLINK);
2410     _DtTermPrimBufferResizeBuffer(&myTB, 12, 80);
2411     _termBufferPrintBuffer(myTB);
2412
2413     _DtTermPrimBufferFreeBuffer(myTB);
2414 }
2415 #endif /* TEST */
2416