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