Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtTerm / Term / TermBuffer.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 #ifndef lint
24 #ifdef  VERBOSE_REV_INFO
25 static char rcs_id[] = "$TOG: TermBuffer.c /main/2 1997/04/17 18:04:41 samborn $";
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 <Xm/Xm.h>
42 #include "TermHeader.h"       /* for MIN/MAX */
43 #include "TermBufferP.h"
44 #include "TermEnhance.h"
45
46 /*
47 ** clear "count" enhancements starting at startCol
48 */
49 static
50 clearEnhancements
51 (
52     TermBuffer tb,
53     short      row,
54     short      startCol,
55     short      count
56 );
57
58 static void
59 insertEnhancements
60 (
61     TermBuffer tb,
62     short      row,
63     short      col,
64     short      insertCount
65 );
66
67 static void
68 deleteEnhancement
69 (
70     TermBuffer tb, 
71     short      row,
72     short      col
73 );
74
75 static void
76 _DtTermClearEnhancements
77 (
78     TermBuffer tb,
79     short      row,
80     short      col,
81     short      count
82 );
83
84 static int
85 _DtTermSetEnhancement
86 (
87     TermBuffer      tb,
88     short           row,
89     short           col,
90     unsigned char   id,
91     enhValue        value
92 );
93
94 static Boolean
95 _DtTermGetEnhancement
96 (
97     const TermBuffer      tb,
98     const short           row,
99     const short           col,
100     enhValue            **enhancements,
101     short                *count,
102     const countSpec       countWhich
103 );
104
105 static termChar *
106 _DtTermGetCharacterPointer
107 (
108     TermBuffer  tb,
109     short       row,
110     short       col
111 );
112
113 static void
114 _DtTermInsertEnhancements
115 (
116     const TermBuffer  tb, 
117     const short       row,
118     const short       col,
119     short             insertCount,
120     const Boolean     insertFlag
121 );
122
123 static Boolean
124 _DtTermBufferCreateEnhancement
125 (
126     TermBuffer  tb,
127     short       row,
128     short       col
129 );
130
131 static void
132 _DtTermBufferResize
133 (
134     TermBuffer  newTb,
135     short      *newRows,
136     short      *newCols
137 );
138
139 static void
140 _DtTermDeleteEnhancement
141 (
142     TermBuffer  tb, 
143     short       row,
144     short       col,
145     short       width
146 );
147
148 static short
149 _DtTermInsert
150 (
151     TermBuffer  tb,
152     short       row,
153     short       col,
154     termChar   *newChars,
155     short       numChars,
156     Boolean     insertFlag,   /* if TRUE, insert, else overwrite        */
157     termChar  **returnChars,  /* pointer to overflow buffer             */
158     short      *returnCount   /* count of characters in overflow buffer */
159 );
160
161 static Boolean
162 _DtTermSetLineLength
163 (
164     TermBuffer      tb,
165     short           row,
166     short           newLength
167 );
168
169 static short
170 _DtTermGetLineLength
171 (
172     TermBuffer      tb,
173     short           row
174 );
175
176 static Boolean
177 _DtTermClearLine
178 (
179     TermBuffer  tb,
180     short       row,
181     short       newLength
182 );
183
184 #if (defined(TEST) || defined(__CODECENTER__) || defined(VALIDATE_ENH))
185 static void
186 validateEnhancements
187 (
188     TermBuffer  tb,
189     short       row
190 );    
191 #    define VALIDATE_ENHANCEMENTS(tb, row) validateEnhancements((tb), (row))
192 #else    
193 #    define VALIDATE_ENHANCEMENTS(tb, row)
194 #endif /* TEST || __CODECENTER__ || VALIDATE_ENH */
195
196 /*
197 ** A blank enhancement structure, it will come in handy.
198 */
199 static DtTermEnhPart blankEnh = {0, 0, 0, 0, 0};
200
201 /* 
202 ** Create and initialize the Dt-specific parts of the term buffer.
203 */
204 TermBuffer
205 _DtTermBufferCreateBuffer
206 (
207     const Widget  w,
208     const short   rows,
209     const short   cols,
210     const short   sizeOfBuffer,
211     const short   sizeOfLine,
212     const short   sizeOfEnh
213 )
214 {
215     int             i;
216     TermBuffer      newTB;
217     DtLine    *lines;
218
219     newTB = _DtTermPrimBufferCreateBuffer(w, rows, cols, 
220                                     sizeOfBuffer, sizeOfLine, sizeOfEnh);
221     
222     
223     if (newTB)
224     {
225         VALUE_LIST(newTB) = (enhValues) malloc(NUM_ENHANCEMENT_FIELDS *
226                                                sizeof(enhValue));
227
228         if (!VALUE_LIST(newTB))
229         {
230             _DtTermPrimBufferFreeBuffer(newTB);
231             return((TermBuffer) NULL);
232         }
233
234         NUM_ENH_FIELDS(newTB) = NUM_ENHANCEMENT_FIELDS;
235         for (lines = DT_LINES(newTB);
236              lines < DT_LINES(newTB) + ROWS(newTB);
237              lines++)
238         {
239             DT_ENH(*lines) = (DtEnh) NULL;
240         }        
241         DT_ENH_STATE(newTB)    = blankEnh;
242         DT_ENH_DIRTY(newTB)    = 0;
243         ENH_PROC(newTB)        = _DtTermEnhProc;
244         BUFFER_CREATE(newTB)   = _DtTermBufferCreateBuffer;
245         BUFFER_FREE(newTB)     = _DtTermBufferFreeBuffer;
246         BUFFER_RESIZE(newTB)   = _DtTermBufferResize;
247         CLEAR_ENH(newTB)       = _DtTermClearEnhancements;
248         INSERT_ENH(newTB)      = _DtTermInsertEnhancements;
249         DELETE_ENH(newTB)      = _DtTermDeleteEnhancement;
250         SET_ENH(newTB)         = _DtTermSetEnhancement;
251         GET_ENH(newTB)         = _DtTermGetEnhancement;
252         SET_LINE_LENGTH(newTB) = _DtTermSetLineLength;
253         CLEAR_LINE(newTB)      = _DtTermClearLine;
254     }
255     return(newTB);
256 }                    
257
258 /* 
259 ** Resize buffer, this is a helper function, if malloc fails, then the
260 ** appropriate dimensions are forced to the current maximums
261 */
262 static void
263 _DtTermBufferResize
264 (
265     TermBuffer  tb,
266     short      *newRows,
267     short      *newCols
268 )
269 {
270     short   i;
271     DtEnh   enh;
272     DtLine *lines;
273     
274     /*
275     ** make any necessary width adjustments first...
276     **
277     ** NOTE:
278     **    We do not take any action if the new column width is less
279     **    than the current column width.  It is the responsibility of
280     **    the rendering code to make sure that two column characters
281     **    are handled properly if the second column falls past the last
282     **    column in the window.
283     */
284     if (*newCols > MAX_COLS(tb)) 
285     {
286         termChar *newLineBuffer;
287
288         /*
289         ** now extend the line buffers and enhancements for all lines,
290         ** (even lines that are not being used at the moment
291         ** (ROWS < MAX_ROWS))...
292         */
293         lines = DT_LINES(tb);
294         for (i = 0; i < MAX_ROWS(tb); i++)
295         {
296             /*
297             ** only copy the enhancement information when it exists
298             */
299             if (DT_ENH(lines[i]))
300             {
301                 enh = (DtEnh) malloc(*newCols * sizeof(DtTermEnhPart));
302
303                 if (enh)
304                 {
305                     /*
306                     ** copy the enhancment info for all characters on
307                     ** the line, zero out the rest
308                     */
309                     (void) memcpy(enh, DT_ENH(lines[i]),
310                                   WIDTH(lines[i]) * sizeof(DtTermEnhPart));
311                     (void) memset(&enh[WIDTH(lines[i])], 0,
312                                   (*newCols - WIDTH(lines[i])) *
313                                   sizeof(DtTermEnhPart));
314                     free(DT_ENH(lines[i]));
315                     DT_ENH(lines[i]) = enh;
316                 }
317                 else
318                 {
319                     /*
320                     ** the malloc failed, revert back to MAX_COLS
321                     */
322                     *newCols = MAX_COLS(tb);
323                     *newRows = MIN(*newRows, MAX_ROWS(tb));
324                     break;
325                 }
326             }
327             newLineBuffer = (termChar *) malloc((unsigned) 
328                                         *newCols * BYTES_PER_CHAR(tb));
329             
330             if (newLineBuffer == NULL)
331             {
332                 /*
333                 ** line buffer malloc failed, we can only increase the
334                 ** width to the current maximum...
335                 */
336                 *newCols = MAX_COLS(tb);
337                 *newRows = MIN(*newRows, MAX_ROWS(tb));
338                 break;
339             }
340             memcpy(newLineBuffer, BUFFER(lines[i]), LENGTH(lines[i]) *
341                    BYTES_PER_CHAR(tb));
342             free(BUFFER(lines[i]));
343             BUFFER(lines[i])  = newLineBuffer;
344             WRAPPED(lines[i]) = False;
345         }
346         MAX_COLS(tb) = *newCols;
347     }
348     COLS(tb) = *newCols;
349
350     /*
351     ** now adjust the length of the buffer as necessary...
352     */
353     if (*newRows > MAX_ROWS(tb)) 
354     {
355         /*
356         ** the number of rows is increasing
357         */
358         lines = (DtLine *) malloc((unsigned) *newRows * sizeof(DtLine));
359         if (lines != NULL)
360         {
361             /*
362             ** the malloc succeeded, copy the old information, and then
363             ** free it...
364             */
365             memcpy(lines, DT_LINES(tb), sizeof(DtLine) * MAX_ROWS(tb));
366             free(DT_LINES(tb));
367             LINES(tb) = (TermLine *)lines;
368             
369             /*
370             ** now initialize the new lines...
371             **
372             ** NOTE:
373             **     If we are unable to malloc any part of a line, adjust
374             **     "newRows" and break.
375             */
376             for (i = MAX_ROWS(tb); i < *newRows; i++)
377             {
378                 lines[i] = (DtLine) malloc(SIZE_OF_LINE(tb));
379                 if (lines[i])
380                 {
381                     DT_ENH(lines[i])    = NULL;
382                     BUFFER(lines[i]) = (termChar *) malloc((unsigned) COLS(tb) *
383                                                            BYTES_PER_CHAR(tb));
384                     if (BUFFER(lines[i]))
385                     {
386                         LENGTH(lines[i])  = 0;
387                         WIDTH(lines[i])   = 0;
388                         WRAPPED(lines[i]) = False;
389                     }
390                     else 
391                     {
392                         /*
393                         ** the line buffer malloc failed...
394                         */
395                         *newRows = i;
396                         break;
397                     }
398                 }
399                 else
400                 {
401                     /*
402                     ** we couldn't malloc this line...
403                     */
404                     *newRows = i;
405                     break;
406                 }
407             }
408             MAX_ROWS(tb) = *newRows;
409         }
410         else
411         {
412             /*
413             ** the malloc for the row buffer failed, revert back to MAX_ROWS
414             */
415             *newRows = MAX_ROWS(tb);
416         }
417     }
418     ROWS(tb) = *newRows;
419 }    
420
421 /*
422 ** Free the buffer.
423 **
424 ** NOTE: This is a helper function, and should only be called by
425 **       TermPrimBufferFreeBuffer.
426 */
427 void
428 _DtTermBufferFreeBuffer
429 (
430     const TermBuffer tb
431 )
432 {
433     DtLine     *lines;
434
435     /*
436     ** Free the Dt-specific buffer info...
437     */
438     for (lines = DT_LINES(tb); lines < DT_LINES(tb) + ROWS(tb); lines++)
439     {
440         if (DT_ENH(*lines))
441         {
442             (void) free(DT_ENH(*lines));
443         }
444     }
445     if (VALUE_LIST(tb))
446     {
447         (void) free(VALUE_LIST(tb));
448     }
449 }
450
451 /*
452 ** clear all the enhancements from startCol through stopCol
453 */
454 static
455 clearEnhancements
456 (
457     TermBuffer tb,
458     short      row,
459     short      col,
460     short      count
461 )
462 {
463     DtEnh  enh;
464     int    i;
465     
466
467     enh  = DT_ENH(DT_LINE_OF_TBUF(tb, row));
468     
469     if (enh)
470     {
471         enh += col;
472         for(i = 0; i < count; i++)
473         {
474             /*
475             ** Clear all of the enhancement information.
476             */
477             *enh = blankEnh;
478             enh++;
479         }
480     }
481 }
482
483 /*
484 ** Clear "count" enhancement blocks, starting at the specified row and column.
485 */
486 static void
487 _DtTermClearEnhancements
488 (
489     TermBuffer  tb,
490     short       row,
491     short       col,
492     short       count
493 )
494 {
495     clearEnhancements(tb, row, col, count);
496 }
497
498 /* 
499 ** Insert the desired number of enhancements at the specified
500 ** position...
501 **
502 ** NOTE:
503 **   We depend on the calling function to insure that insertCount
504 **   has been properly clipped to insure that we don't go out of
505 **   bounds.
506 **   Results are undefined if this function is called when the specified
507 **   column is at the end of the line.
508 */
509 static void
510 _DtTermInsertEnhancements
511 (
512     const TermBuffer  tb, 
513     const short       row,
514     const short       col,
515     short             insertCount,
516     const Boolean     insertFlag
517 )
518 {
519
520     DtTermEnhPart   fillEnh;
521     DtEnh           enh;
522     DtLine          line;
523     int             i;    
524     int             copyCount;
525     
526     line = DT_LINE_OF_TBUF(tb, row);
527     enh  = DT_ENH(line);
528
529     /* 
530     ** There's nothing to do if we're past the end of the line or
531     ** the dirty bit is clear and there are no ehancements on
532     ** this line...
533     */
534     if ((col < WIDTH(line)) && ((DT_ENH_DIRTY(tb)) || (enh != NULL)))
535     {
536         if ((enh == NULL))
537         {
538             /* 
539             ** there are currently no enhancements on this line, 
540             ** allocate an enhancement buffer, and reset 'enh'...
541             */
542             _DtTermBufferCreateEnhancement(tb, row, col);
543             enh = DT_ENH(line);
544         }
545
546         /* 
547         ** get a copy of the current enhancement (we'll insert 'copyCount'
548         ** copies of it into the enhancement buffer)
549         */
550         fillEnh = DT_ENH_STATE(tb);
551
552         if (insertFlag)
553         {
554             /* 
555             ** we're in insert mode, move any existing enhancements...
556             */
557             copyCount = MIN((WIDTH(line) - col),
558                     (COLS(tb) - col - insertCount));
559             copyCount = MAX(0, copyCount);
560             memmove(enh + col + insertCount, enh + col, 
561                     copyCount * sizeof(DtTermEnhPart));
562         }
563
564 #ifdef    NOCODE
565         /* 
566         ** insert insertCount copies of fillEnh into the enhancement buffer
567         ** starting at line->enh[col + 1]...
568         */
569         enh += col + 1;
570         for (i = 0; i < insertCount; i++)
571         {
572             *enh = fillEnh;
573             enh++;
574         }
575 #else  /* NOCODE */
576         /* 
577         ** insert insertCount copies of fillEnh into the enhancement buffer
578         ** starting at line->enh[col + 1]...
579         */
580         enh += col;
581         for (i = 0; i < insertCount; i++)
582         {
583             *enh = fillEnh;
584             enh++;
585         }
586 #endif /* NOCODE */
587
588     }
589 }
590
591 void
592 _DtTermBufferDelete
593 (
594     TermBuffer  tb,
595     short      *row,
596     short      *col,
597     short      *count        /* number of columns to delete     */
598 )
599 {
600     _DtTermPrimBufferDelete(tb, row, col, count, NULL, NULL);
601 }
602
603 /* 
604 ** delete the desired enhancements starting the specified position...
605 */
606 static void
607 _DtTermDeleteEnhancement
608 (
609     TermBuffer  tb, 
610     short       row,
611     short       col,
612     short       width
613 )
614 {
615     DtEnh           enh;
616     DtTermEnhPart   fillEnh;
617     DtLine          line;
618     int             copyCount;
619     
620     line = DT_LINE_OF_TBUF(tb, row);
621     enh  = DT_ENH(line);
622
623     if ((enh == NULL) || (WIDTH(line) <= col))
624     {
625         /* 
626         ** no enhancements, or at (or past) the end of the line, return
627         */
628         return;
629     }
630
631     /* 
632     ** get a copy of the current enhancement
633     */
634     fillEnh = enh[col];
635
636     /* 
637     ** move all of the enhancement blocks between col + width and and the
638     ** end of the line to col
639     */
640     copyCount = WIDTH(line) - (col + width);
641     memcpy(enh + col , enh + col + width,
642            copyCount * sizeof(DtTermEnhPart));
643
644 }
645
646
647 /*
648 ** Create an enhancement block at the specified row and column.
649 **
650 ** NOTE:  For the time being, we simply allocate an entire row's worth
651 **        of enhancement blocks if it doesn't exist already.  We may
652 **        get smarter later on.
653 */
654 /*ARGSUSED*/
655 static Boolean
656 _DtTermBufferCreateEnhancement
657 (
658     TermBuffer  tb,
659     short       row,
660     short       col
661 )
662 {
663     DtLine  line;
664     DtEnh  *enh;
665     
666     if (!VALID_ROW(tb, row) || !VALID_COL(tb, col))
667     {
668         return(False);
669     }
670                         
671     line = DT_LINE_OF_TBUF(tb, row);
672     enh  = &(DT_ENH(line));
673
674     /*
675     ** If this row already has enhancement blocks allocated, return.
676     */
677     if (*enh == NULL)
678     {
679         /*
680         ** Otherwise, allocate and initialize a row of enhancement blocks.
681         */
682         *enh = (DtEnh) malloc(MAX_COLS(tb) * sizeof(DtTermEnhPart));
683         if (*enh == NULL)
684         {
685             return(False);
686         }
687
688         /*
689         ** Clear all the enhancements...
690         */
691         (void) memset(*enh, 0, MAX_COLS(tb) * sizeof(DtTermEnhPart));
692     }
693     return(True);
694 }
695
696 /*
697 ** Free the enhancement block at the specified row and column.
698 **
699 ** NOTE: We may get smarter later on.
700 */
701 Boolean
702 _DtTermBufferFreeEnhancement
703 (
704     TermBuffer  tb,
705     short       row,
706     short       col
707 )
708 {
709     return(True);
710 }
711
712 /*
713 ** Set the desired enhancement.
714 **
715 **  This function does the right thing (as far as I can tell regarding
716 **  propagating enhancements).
717 **
718 ** Return:
719 **     -1   : the enhancement was not set
720 **     >= 0 : the number of characters (as opposed to character positions)
721 **            that the enhancement affects
722 */
723 static int
724 _DtTermSetEnhancement
725 (
726     TermBuffer      tb,
727     short           row,
728     short           col,
729     unsigned char   id,
730     enhValue        value
731 )
732 {
733     int     i;
734     DtEnh   enhState;
735     
736     enhState = (DtEnh) &(DT_ENH_STATE(tb));
737     
738     /*
739     ** Set the value.
740     */
741     switch (id)
742     {
743       case enhVideo:
744         enhState->video   = (value &= VIDEO_MASK);
745         break;
746       case enhField:
747         enhState->field   = (value &= FIELD_MASK);
748         break;
749       case enhFgColor:
750         enhState->fgColor = (value &= COLOR_MASK);
751         break;
752       case enhBgColor:
753         enhState->bgColor = (value &= COLOR_MASK);
754         break;
755       case enhFont:
756         enhState->font    = (value &= FONT_MASK);
757         break;
758       default:
759         return(-1);
760     }
761     
762     /* 
763     ** We've set the value, now decide if this anything but the blank
764     ** enhancement.
765     */
766     DT_ENH_DIRTY(tb) = ((enhState->video   != blankEnh.video  ) ||
767                         (enhState->field   != blankEnh.field  ) ||
768                         (enhState->fgColor != blankEnh.fgColor) ||
769                         (enhState->bgColor != blankEnh.bgColor) ||
770                         (enhState->font    != blankEnh.font   ));
771     /* 
772     ** return the correct count (which in this case will always be 0)
773     */
774     return(0);
775 }
776
777 /*
778 ** Get the enhancements for the desired row and column.
779 **
780 **  enhValues:
781 **      a pointer to an array of the current enhancement values
782 **
783 **  count:
784 **      the number of columns for which the enhancements are
785 **      valid, or the number of columns until the enhancements
786 **      were modified by an escape sequence (see 'countWhich' below)
787 **
788 **  countWhich:
789 **      if 'countWhich' is countAll then count until any enhancement value
790 **      changes
791 **      if 'countAll' is countNew then count until a new enhancement value
792 **      starts (regardless of whether it is the same or not).
793 **
794 ** Return:
795 **     True if row and col are valid
796 */
797 static Boolean
798 _DtTermGetEnhancement
799 (
800     const TermBuffer      tb,
801     const short           row,
802     const short           col,
803           enhValue      **values,
804           short          *count,
805     const countSpec       countWhich
806 )
807 {
808     /*
809     ** store the current enhancement values here
810     */
811     int    i;
812     DtLine line;
813     DtEnh  enh;
814
815     /*
816     ** First we do some simple bounds checking
817     */
818     VALIDATE_ENHANCEMENTS(tb, row);
819     if (!VALID_ROW(tb, row) || !VALID_COL(tb, col))
820     {
821         return(False);
822     }
823     line = DT_LINE_OF_TBUF(tb, row);
824
825     /*
826     ** point to the correct enhancement chunk.
827     */
828     if (DT_ENH(line) == NULL || (WIDTH(line) <= col))
829     {
830         /*
831         ** There are either no enhancements allocated for this line, 
832         ** or we're past the end of the line, in either case return
833         ** a blank enhancement.
834         */
835         enh = &blankEnh;
836     }
837     else
838     {
839         /*
840         ** We're in the line get the current enhancement values
841         */
842         enh = &(DT_ENH(line)[col]);
843     }
844
845     /*
846     ** Shove the enhancement values into their correct locations...
847     */
848     *values                    = (VALUE_LIST(tb));
849     (*values)[(int)enhVideo  ] = (enh->video   & VIDEO_MASK);
850     (*values)[(int)enhField  ] = (enh->field   & FIELD_MASK);
851     (*values)[(int)enhFgColor] = (enh->fgColor & COLOR_MASK);
852     (*values)[(int)enhBgColor] = (enh->bgColor & COLOR_MASK);
853     (*values)[(int)enhFont   ] = (enh->font    & FONT_MASK );
854
855     /*
856     ** Now count how many characters are affected by the enhancements.
857     */
858     if (DT_ENH(line) == NULL)
859     {
860         /*
861         ** There no enhancements allocated for this line, the default
862         ** enhancement is active for the remainder of the line.
863         ** NOTE: Make sure count >= 0.
864         */
865         *count = MAX(0, WIDTH(line) - col);
866     }
867     else if (WIDTH(line) <= col)
868     {
869         /*
870         ** We're past the end of the line, count will always == 0;
871         */
872         *count = 0;
873     }
874     else
875     {
876         /*
877         ** We're in the line, determine the number of characters that
878         ** these enhancements apply to.
879         */
880         switch (countWhich)
881         {
882           case countNew:
883             /*
884             **  For Vt220 emulation, countNew is the same as countAll...
885             **  JRM 08/30/93
886             */
887           case countAll:
888             /*
889             ** count until an enhancement value changes
890             */
891             for (i = 0; i < (WIDTH(line) - col); i++)
892             {
893                 if (((*values)[(int)enhVideo  ] != (enh->video   & VIDEO_MASK))||
894                     ((*values)[(int)enhField  ] != (enh->field   & FIELD_MASK))||
895                     ((*values)[(int)enhFgColor] != (enh->fgColor & COLOR_MASK))||
896                     ((*values)[(int)enhBgColor] != (enh->bgColor & COLOR_MASK))||
897                     ((*values)[(int)enhFont   ] != (enh->font    & FONT_MASK ))  )
898                 {
899                     /*
900                     ** the enhancements differ; break out
901                     */
902                     break;
903                 }
904                 enh++;
905             }
906             break;
907           default:
908             VALIDATE_ENHANCEMENTS(tb, row);
909             return(False);
910         }
911         *count = i;
912     }
913     VALIDATE_ENHANCEMENTS(tb, row);
914     return(True);
915 }
916
917 /*
918 ** This is a vt-specific helper function for setting the line length.
919 ** By the time the function is called, termBufferSetLineLength()
920 ** as already validated the newLength, the row, and insured that the
921 ** new length is > the current length
922 **
923 ** This function propagates the correct enhancement to the new end of line.
924 */
925 static Boolean
926 _DtTermSetLineLength
927 (
928     TermBuffer      tb,
929     short           row,
930     short           newLength
931 )
932 {
933     return(True);
934 }
935
936 /*
937 ** _DtTermPrimBufferClearLine will reset the line width, this is
938 ** our chance to clear any enhancements that may exist on this line...
939 */
940 static Boolean
941 _DtTermClearLine
942 (
943     TermBuffer  tb,
944     short       row,
945     short       newWidth
946 )
947 {
948     DtLine  line;
949     DtEnh   enh;
950     
951     line = DT_LINE_OF_TBUF(tb, row);
952     enh  = DT_ENH(line);
953     
954     if (enh != NULL)
955     {
956         /*
957         ** We have enhancements, clear all those between the current
958         ** and the new length...
959         */
960         
961         (void) memset(&enh[newWidth], 0,
962                       (WIDTH(line) - newWidth) * sizeof(DtTermEnhPart));
963     }
964     return(True);
965 }
966
967 /*
968 ** Erase characters on the specified row (and clear the enhancements) with
969 ** the appropriate semantics.  For VT class emulators, there are several
970 ** ways to erase characters:
971 **      - from the active position to the end of line
972 **      - erase the specified number of characters starting at the current
973 **        cursor position
974 **      - from the start of the line to the active position
975 **      - erase the entire line
976 **      - from the active position to the end of the buffer
977 **      - erase the specified number of lines starting at the current
978 **        cursor position
979 **      - from the start of the buffer to the active position
980 **      - erase the entire buffer
981 */
982 void
983 _DtTermBufferErase
984 (
985     TermBuffer  tb,
986     short       row,
987     short       col,
988     short       count,
989     DtEraseMode eraseSwitch
990 )
991 {
992     short  startCol;
993     short  lastCol;
994     
995     switch(eraseSwitch)
996     {
997       case eraseFromCol0:
998         /*
999         ** erase from col 0 to the current cursor position
1000         */
1001         startCol = 0;
1002         lastCol  = MIN(col, WIDTH(DT_LINE_OF_TBUF(tb, row)) - 1);
1003         break;
1004         
1005       case eraseCharCount:
1006         /*
1007         ** erase "count" characters from the current cursor position
1008         */
1009         startCol = col;
1010         lastCol  = MIN(col + count - 1, WIDTH(DT_LINE_OF_TBUF(tb, row)) - 1);
1011         break;
1012
1013       case eraseLineCount:
1014       case eraseToEOL:
1015       case eraseLine:
1016       case eraseBuffer:
1017       case eraseFromRow0Col0:
1018       case eraseToEOB:
1019         /*
1020         ** These cases should have been handled by _DtTermFuncErase()
1021         */
1022         return;
1023     }
1024
1025     _DtTermPrimBufferErase(tb, row, startCol, lastCol);
1026     /*
1027     ** now clear the corresponding enhancements...
1028     */
1029     clearEnhancements(tb, row, startCol, lastCol - startCol + 1);
1030 }
1031
1032 #if (defined(TEST) || defined(__CODECENTER__) || defined(VALIDATE_ENH))
1033 static void
1034 _DtTermValidateEnhancements
1035 (
1036     TermBuffer  tb,
1037     short       row
1038 )
1039 {
1040     DtTermEnhPart  refEnh;
1041     DtEnh        thisEnh;
1042     DtLine    thisLine;
1043     short          col;
1044     Boolean validatePassed;
1045
1046     validatePassed = True;
1047
1048     thisLine = DT_LINE_OF_TBUF(tb, row);
1049     if (DT_ENH(thisLine))
1050     {
1051         /* 
1052         ** Initialize the reference enhancement
1053         */
1054         refEnh = blankEnh;
1055         refEnh.videoStart = 0;
1056         refEnh.fieldStart = 0;
1057         refEnh.colorStart = 0;
1058         refEnh.fontStart  = 0;
1059
1060         for(col = 0, thisEnh = DT_ENH(thisLine); 
1061             col < WIDTH(thisLine) + 
1062                   (DANGLE(thisLine) >= 0 ? 1 : 0);
1063             col++, thisEnh++)
1064         {
1065             if (thisEnh->videoStart)
1066             {
1067                 refEnh.video = thisEnh->video;
1068             }
1069             else if (refEnh.video != thisEnh->video)
1070             {
1071                 fprintf(stderr, "Video enhancements don't match:");
1072                 fprintf(stderr, "    row : %3.3d, col : %3.3d\n", row, col);
1073                 fprintf(stderr, "    refEnh.video : %d\n", (int)(refEnh.video  & VIDEO_MASK));
1074                 fprintf(stderr, "    thisEnh->video: %d\n", (int)(thisEnh->video & VIDEO_MASK));
1075                 validatePassed = False;
1076             }    
1077
1078             if (thisEnh->fieldStart)
1079             {
1080                 refEnh.field = thisEnh->field;
1081             }
1082             else if (refEnh.field != thisEnh->field)
1083             {
1084                 fprintf(stderr, "Field enhancements don't match:");
1085                 fprintf(stderr, "    row : %3.3d, col : %3.3d\n", row, col);
1086                 fprintf(stderr, "    refEnh.field : %d\n", (int)(refEnh.field  & FIELD_MASK));
1087                 fprintf(stderr, "    thisEnh->field: %d\n", (int)(thisEnh->field & FIELD_MASK));
1088                 validatePassed = False;
1089             }    
1090             if (thisEnh->colorStart)
1091             {
1092                 refEnh.color = thisEnh->color;
1093             }
1094             else if (refEnh.color != thisEnh->color)
1095             {
1096                 fprintf(stderr, "Color enhancements don't match:");
1097                 fprintf(stderr, "    row : %3.3d, col : %3.3d\n", row, col);
1098                 fprintf(stderr, "    refEnh.color : %d\n", (int)(refEnh.color  & COLOR_MASK));
1099                 fprintf(stderr, "    thisEnh->color: %d\n", (int)(thisEnh->color & COLOR_MASK));
1100                 validatePassed = False;
1101             }    
1102             if (thisEnh->font <= 2)
1103             {
1104                 if (thisEnh->fontStart)
1105                 {
1106                     refEnh.font = thisEnh->font;
1107                 }
1108                 else if (refEnh.font != thisEnh->font)
1109                 {
1110                     fprintf(stderr, "Font enhancements don't match:");
1111                     fprintf(stderr, "    row : %3.3d, col : %3.3d\n", row, col);
1112                     fprintf(stderr, "    refEnh.font : %d\n", (int)(refEnh.font  & FONT_MASK));
1113                     fprintf(stderr, "    thisEnh->font: %d\n", (int)(thisEnh->font & FONT_MASK));
1114                     validatePassed = False;
1115                 }    
1116             }
1117             else
1118             {
1119                 fprintf(stderr, "Font enhancement out of range:");
1120                 fprintf(stderr, "    row : %3.3d, col : %3.3d\n", row, col);
1121                 fprintf(stderr, "    thisEnh->font: %d\n", (int)(thisEnh->font & FONT_MASK));
1122                 validatePassed = False;
1123             }
1124         }
1125     }
1126     if (validatePassed == False)
1127     {
1128         fprintf(stderr, "validateEnhancement failed\n");
1129     }
1130 }
1131 #endif /* TEST || __CODECENTER__ || DEBUG || VALIDATE_ENH */
1132
1133 #if (defined(TEST) || defined(__CODECENTER__) || defined(DEBUG))
1134 #ifdef NOCODE
1135 static void
1136 _printLine
1137 (
1138     TermBuffer tb,
1139     short row
1140 )
1141 {
1142     DtLine line;
1143     termChar   *pChar;
1144     short       j;
1145
1146     printf("Line: %d\n", row);
1147
1148     line = tb->lines[row];
1149     printf("    length: %3d\n", line->length);
1150     if (line->length > 0)
1151     {
1152         printf("    buffer: <");
1153         pChar = line->buffer;
1154         for (j = 0; j < line->length; j++)
1155         {
1156             printf("%X", *pChar++);
1157         }
1158         printf(">\n");
1159     }
1160 }
1161
1162 static int
1163 _DtTermPrintEnhancement
1164 (
1165     TermBuffer tb,
1166     short row,
1167     short col
1168 )
1169 {
1170     enhValue        enhancements[NUM_ENHANCEMENT_FIELDS];
1171     short           enhCount;
1172
1173
1174     _DtTermPrimBufferGetEnhancement(tb, row, col, enhancements, &enhCount, countNew);
1175     printf("    col  : %d\n", col);
1176     printf("    Count: %d\n", enhCount);
1177     printf("        Video: '_");
1178     printf("%s", IS_BOLD(enhancements[enhVideo])        != 0 ? "B":"b");
1179     printf("_");
1180     printf("%s", IS_SECURE(enhancements[enhVideo])      != 0 ? "S":"s");
1181     printf("_");
1182     printf("%s", IS_HALF_BRIGHT(enhancements[enhVideo]) != 0 ? "H":"h");
1183     printf("_");
1184     printf("%s", IS_UNDERLINE(enhancements[enhVideo])   != 0 ? "U":"u");
1185     printf("_");
1186     printf("%s", IS_INVERSE(enhancements[enhVideo])     != 0 ? "I":"i");
1187     printf("_");
1188     printf("%s", IS_BLINK(enhancements[enhVideo])       != 0 ? "B":"b");
1189     printf("_'\n");
1190
1191     /*
1192     ** Field type
1193     */
1194     printf("        Field: ");
1195     switch (enhancements[enhField])
1196     {
1197       case FIELD_PROTECT:
1198         printf("PROTECT");
1199         break;
1200       case FIELD_UNPROTECT:
1201         printf("UNPROTECT");
1202         break;
1203       case FIELD_TRANSMIT:
1204         printf("TRANSMIT");
1205         break;
1206       case FIELD_END:
1207         printf("END");
1208         break;
1209     }
1210     printf("\n");
1211
1212     /*
1213     ** Color id
1214     */
1215     printf("        Color: %1d\n", enhancements[enhFont]);
1216
1217     /*
1218     ** Font id
1219     */
1220     printf("        Font : ");
1221     switch (enhancements[enhFont])
1222     {
1223       case FONT_NORMAL:
1224         printf("NORMAL");
1225         break;
1226       case FONT_LINEDRAW:
1227         printf("LINEDRAW");
1228         break;
1229     }
1230     printf("\n");
1231     return(enhCount);
1232 }
1233 #endif /* NOCODE */
1234
1235 static void
1236 printEnh
1237 (
1238     DtEnh enh
1239 )
1240 {
1241     printf(" video  : %d\n", enh->video);
1242     printf(" field  : %d\n", enh->field);
1243     printf(" fgColor: %d\n", enh->fgColor);
1244     printf(" bgColor: %d\n", enh->bgColor);
1245     printf(" font   : %d\n", enh->font);
1246 }
1247
1248 /*
1249 ** Print the contents of the TermBuffer.
1250 */
1251 static void
1252 _DtTermPrintBuffer
1253 (
1254     DtTermBuffer tb
1255 )
1256 {
1257     short i;
1258     short j;
1259     short k;
1260
1261     if (tb == NULL) {
1262         printf("TermBuffer has been freed.\n");
1263         return;
1264     }
1265
1266     printf("TermBuffer dimensions:\n");
1267     printf("    rows: %d\n", ROWS(tb));
1268     printf("    cols: %d\n", COLS(tb));
1269     printf("    enhDirty: %d\n", DT_ENH_DIRTY(tb));
1270     printf("    enhState:\n");
1271     printEnh(&(DT_ENH_STATE(tb)));
1272 #ifdef NOCODE
1273     for (i = 0; i < ROWS(tb); i++)
1274     {
1275         _printLine(tb, i);
1276         j = 0;
1277         do
1278         {
1279             k = _termBufferPrintEnhancement(tb, i, j);
1280             if (k == 0)
1281             {
1282                 break;
1283             }
1284             j += k;
1285         } while (j < COLS(tb));
1286     }
1287 #endif /* NOCODE */
1288 }
1289 #endif /* (defined(TEST) || defined(__CODECENTER__)) */
1290
1291 #ifdef TEST
1292 /*
1293 ** Some simple tests of the termBuffer.
1294 */
1295 /* the following is to allow for a single main function in the code... */
1296 #define       termBufMain     main
1297 termBufMain()
1298 {
1299     TermBuffer  myTB;
1300
1301     printf("Sizeof DtTermEnhPart : %d\n", sizeof(struct _DtTermEnhPart));
1302     printf("Sizeof termBufferRec : %d\n", sizeof(struct _TermBufferRec));
1303
1304     myTB = _DtTermPrimBufferCreateBuffer(12, 80);
1305     _termBufferPrintBuffer(myTB);
1306
1307     printf("[0,0] %d\n", _DtTermPrimBufferSetEnhancement(myTB, 0, 0, enhVideo, BLINK));
1308     _termBufferPrintEnhancement(myTB, 0, 0);
1309     printf("[0,1] %d\n", _DtTermPrimBufferSetEnhancement(myTB, 0, 1, enhVideo, INVERSE));
1310     _termBufferPrintEnhancement(myTB, 0, 0);
1311     _termBufferPrintEnhancement(myTB, 0, 1);
1312     printf("[0,9] %d\n", _DtTermPrimBufferSetEnhancement(myTB, 0, 9, enhVideo, UNDERLINE));
1313     _termBufferPrintEnhancement(myTB, 0, 0);
1314     _termBufferPrintEnhancement(myTB, 0, 1);
1315     _termBufferPrintEnhancement(myTB, 0, 9);
1316     printf("[0,6] %d\n", _DtTermPrimBufferSetEnhancement(myTB, 0, 6, enhVideo, HALF_BRIGHT));
1317     _termBufferPrintEnhancement(myTB, 0, 0);
1318     _termBufferPrintEnhancement(myTB, 0, 1);
1319     _termBufferPrintEnhancement(myTB, 0, 6);
1320     _termBufferPrintEnhancement(myTB, 0, 9);
1321     _termBufferPrintBuffer(myTB);
1322
1323     _DtTermPrimBufferSetEnhancement(myTB, 10, 10, enhVideo, BLINK);
1324     _DtTermPrimBufferSetEnhancement(myTB, 10, 20, enhColor, 3);
1325     _termBufferPrintBuffer(myTB);
1326
1327     _DtTermPrimBufferResizeBuffer(&myTB,  6, 40);
1328     _termBufferPrintBuffer(myTB);
1329
1330     _DtTermPrimBufferSetEnhancement(myTB, 10, 10, enhVideo, BLINK);
1331     _DtTermPrimBufferResizeBuffer(&myTB, 12, 80);
1332     _termBufferPrintBuffer(myTB);
1333
1334     _DtTermPrimBufferFreeBuffer(myTB);
1335 }
1336 #endif /* TEST */
1337
1338
1339
1340
1341
1342
1343
1344
1345