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