1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: color.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2007 University of Washington
8 * Copyright 2013-2017 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
23 #include "../headers.h"
27 #include "../../pith/osdep/color.h"
28 #include "../../pith/osdep/collate.h"
32 struct color_name_list
{
35 struct color_name_list
*next
;
39 struct color_name_list
*names
;
46 /* useful definitions */
47 #define ANSI8_COLOR() (color_options & COLOR_ANSI8_OPT)
48 #define ANSI16_COLOR() (color_options & COLOR_ANSI16_OPT)
49 #define ANSI256_COLOR() (color_options & COLOR_ANSI256_OPT)
50 #define ANSI_COLOR() (color_options & (COLOR_ANSI8_OPT | COLOR_ANSI16_OPT | COLOR_ANSI256_OPT))
51 /* transparent (default) color is possible */
52 #define COL_TRANS() ((color_options & COLOR_TRANS_OPT) ? 1 : 0) /* transparent */
53 #define END_PSEUDO_REVERSE "EndInverse"
58 static unsigned color_options
;
59 static COLOR_PAIR
*the_rev_color
, *the_normal_color
;
60 static COLOR_PAIR
*color_blasted_by_attrs
;
61 static int pinvstate
; /* physical state of inverse (standout) attribute */
62 static int pboldstate
; /* physical state of bold attribute */
63 static int pulstate
; /* physical state of underline attribute */
64 static int rev_color_state
;
66 static int boldstate
; /* should-be state of bold attribute */
67 static int ulstate
; /* should-be state of underline attribute */
68 static int invstate
; /* should-be state of Inverse, which could be a color
69 change or an actual setinverse */
70 static int _color_inited
, _using_color
;
71 static char *_nfcolor
, *_nbcolor
, *_rfcolor
, *_rbcolor
;
72 static char *_last_fg_color
, *_last_bg_color
;
73 static int _force_fg_color_change
;
74 static int _force_bg_color_change
;
76 static struct color_table
*color_tbl
;
78 /* external references */
79 extern char *_op
, *_oc
, *_setaf
, *_setab
, *_setf
, *_setb
, *_scp
;
80 extern int _bce
, _colors
;
83 /* internal prototypes */
84 void flip_rev_color(int);
87 void reset_attr_state(void);
88 void add_to_color_name_list(struct color_table
*t
, char *name
);
89 void free_color_name_list(struct color_name_list
**nl
);
93 extern char *tparm(char *, ...);
96 void tinitcolor(void);
99 struct color_table
*init_color_table(void);
100 void free_color_table(struct color_table
**);
101 int color_to_val(char *);
106 * Start or end bold mode
108 * Result: escape sequence to go into or out of reverse color is output
110 * (This is only called when there is a reverse color.)
112 * Arg state = ON set bold
116 flip_rev_color(int state
)
118 if((rev_color_state
= state
) == TRUE
)
119 (void)pico_set_colorp(the_rev_color
, PSC_NONE
);
121 pico_set_normal_color();
126 * Start or end bold mode
128 * Result: escape sequence to go into or out of bold is output
130 * Arg state = ON set bold
136 extern char *_setbold
, *_clearallattr
;
138 if((pboldstate
= state
) == TRUE
){
143 if(_clearallattr
!= NULL
){
144 if(!color_blasted_by_attrs
)
145 color_blasted_by_attrs
= pico_get_cur_color();
147 _force_fg_color_change
= _force_bg_color_change
= 1;
148 putpad(_clearallattr
);
151 rev_color_state
= state
;
158 * Start or end inverse mode
160 * Result: escape sequence to go into or out of inverse is output
162 * Arg state = ON set inverse
168 extern char *_setinverse
, *_clearinverse
;
170 if((pinvstate
= state
) == TRUE
){
171 if(_setinverse
!= NULL
)
176 * Unfortunately, some termcap entries configure end standout to
177 * be clear all attributes.
179 if(_clearinverse
!= NULL
){
180 if(!color_blasted_by_attrs
)
181 color_blasted_by_attrs
= pico_get_cur_color();
183 _force_fg_color_change
= _force_bg_color_change
= 1;
184 putpad(_clearinverse
);
185 pboldstate
= (pboldstate
== FALSE
) ? pboldstate
: A_UNKNOWN
;
186 pulstate
= (pulstate
== FALSE
) ? pulstate
: A_UNKNOWN
;
187 rev_color_state
= A_UNKNOWN
;
194 * Start or end underline mode
196 * Result: escape sequence to go into or out of underline is output
198 * Arg state = ON set underline
204 extern char *_setunderline
, *_clearunderline
;
206 if((pulstate
= state
) == TRUE
){
207 if(_setunderline
!= NULL
)
208 putpad(_setunderline
);
212 * Unfortunately, some termcap entries configure end underline to
213 * be clear all attributes.
215 if(_clearunderline
!= NULL
){
216 if(!color_blasted_by_attrs
)
217 color_blasted_by_attrs
= pico_get_cur_color();
219 _force_fg_color_change
= _force_bg_color_change
= 1;
220 putpad(_clearunderline
);
221 pboldstate
= (pboldstate
== FALSE
) ? pboldstate
: A_UNKNOWN
;
222 pinvstate
= (pinvstate
== FALSE
) ? pinvstate
: A_UNKNOWN
;
223 rev_color_state
= A_UNKNOWN
;
255 extern char *_setbold
;
259 return(_setbold
!= NULL
);
288 reset_attr_state(void)
291 * If we have to turn some attributes off, do that first since that
292 * may turn off other attributes as a side effect.
294 if(boldstate
== FALSE
&& pboldstate
!= boldstate
)
295 flip_bold(boldstate
);
297 if(ulstate
== FALSE
&& pulstate
!= ulstate
)
300 if(invstate
== FALSE
){
301 if(pico_get_rev_color()){
302 if(rev_color_state
!= invstate
)
303 flip_rev_color(invstate
);
306 if(pinvstate
!= invstate
)
312 * Now turn everything on that needs turning on.
314 if(boldstate
== TRUE
&& pboldstate
!= boldstate
)
315 flip_bold(boldstate
);
317 if(ulstate
== TRUE
&& pulstate
!= ulstate
)
320 if(invstate
== TRUE
){
321 if(pico_get_rev_color()){
322 if(rev_color_state
!= invstate
)
323 flip_rev_color(invstate
);
326 if(pinvstate
!= invstate
)
331 if(color_blasted_by_attrs
){
332 (void)pico_set_colorp(color_blasted_by_attrs
, PSC_NONE
);
333 free_color_pair(&color_blasted_by_attrs
);
342 if(_color_inited
|| panicking())
345 if(ANSI_COLOR() || (_colors
> 0 && ((_setaf
&& _setab
) || (_setf
&& _setb
)
346 /**** not sure how to do this yet
351 color_tbl
= init_color_table();
354 putpad("\033[39;49m");
367 * Treading on thin ice here. Tgoto wasn't designed for this. It takes
368 * arguments column and row. We only use one of them, so we put it in
369 * the row argument. The 0 is just a placeholder.
371 #define tparm(s, c) tgoto(s, 0, c)
383 if((ANSI8_COLOR() && (color
< 0 || color
>= 8+COL_TRANS())) ||
384 (ANSI16_COLOR() && (color
< 0 || color
>= 16+COL_TRANS())) ||
385 (ANSI256_COLOR() && (color
< 0 || color
>= 256+COL_TRANS())) ||
386 (!ANSI_COLOR() && (color
< 0 || color
>= _colors
+COL_TRANS())))
392 if(COL_TRANS() && color
== pico_count_in_color_table()-1)
393 snprintf(buf
, sizeof(buf
), "\033[39m");
394 else if(ANSI256_COLOR())
395 snprintf(buf
, sizeof(buf
), "\033[38;5;%dm", color
);
398 snprintf(buf
, sizeof(buf
), "\033[3%cm", color
+ '0');
400 snprintf(buf
, sizeof(buf
), "\033[9%cm", (color
-8) + '0');
405 else if(COL_TRANS() && color
== pico_count_in_color_table()-1 && _op
){
406 char bg_color_was
[MAXCOLORLEN
+1];
408 bg_color_was
[0] = '\0';
411 * Setting transparent (default) foreground color.
412 * We don't know how to set only the default foreground color,
413 * _op sets both foreground and background. So we need to
415 * get current background color
417 * if (current background was not default) reset it
419 if(_last_bg_color
&& strncmp(_last_bg_color
, MATCH_TRAN_COLOR
, RGBLEN
)){
420 strncpy(bg_color_was
, _last_bg_color
, sizeof(bg_color_was
));
421 bg_color_was
[sizeof(bg_color_was
)-1] = '\0';
426 _force_bg_color_change
= 1;
427 pico_set_bg_color(bg_color_was
);
431 putpad(tparm(_setaf
, color
));
433 putpad(tparm(_setf
, color
));
435 /* set color pair method */
451 if((ANSI8_COLOR() && (color
< 0 || color
>= 8+COL_TRANS())) ||
452 (ANSI16_COLOR() && (color
< 0 || color
>= 16+COL_TRANS())) ||
453 (ANSI256_COLOR() && (color
< 0 || color
>= 256+COL_TRANS())) ||
454 (!ANSI_COLOR() && (color
< 0 || color
>= _colors
+COL_TRANS())))
460 if(COL_TRANS() && color
== pico_count_in_color_table()-1)
461 snprintf(buf
, sizeof(buf
), "\033[49m");
462 else if(ANSI256_COLOR())
463 snprintf(buf
, sizeof(buf
), "\033[48;5;%dm", color
);
466 snprintf(buf
, sizeof(buf
), "\033[4%cm", color
+ '0');
468 snprintf(buf
, sizeof(buf
), "\033[10%cm", (color
-8) + '0');
473 else if(COL_TRANS() && color
== pico_count_in_color_table()-1 && _op
){
474 char fg_color_was
[MAXCOLORLEN
+1];
476 fg_color_was
[0] = '\0';
479 * Setting transparent (default) background color.
480 * We don't know how to set only the default background color,
481 * _op sets both foreground and background. So we need to
483 * get current foreground color
485 * if (current foreground was not default) reset it
487 if(_last_fg_color
&& strncmp(_last_fg_color
, MATCH_TRAN_COLOR
, RGBLEN
)){
488 strncpy(fg_color_was
, _last_fg_color
, sizeof(fg_color_was
));
489 fg_color_was
[sizeof(fg_color_was
)-1] = '\0';
494 _force_fg_color_change
= 1;
495 pico_set_fg_color(fg_color_was
);
499 putpad(tparm(_setab
, color
));
501 putpad(tparm(_setb
, color
));
503 /* set color pair method */
512 * We're not actually using the RGB value other than as a string which
513 * maps into the color.
514 * In fact, on some systems color 1 and color 4 are swapped, and color 3
515 * and color 6 are swapped. So don't believe the RGB values.
516 * Still, it feels right to have them be the canonical values, so we do that.
518 * Actually we are using them more now. In color_to_val we map to the closest
519 * color if we don't get an exact match. We ignore values over 255.
521 * More than one "name" can map to the same "rgb".
522 * More than one "name" can map to the same "val".
523 * The "val" for a "name" and for its "rgb" are the same.
526 init_color_table(void)
528 struct color_table
*ct
= NULL
, *t
;
532 count
= pico_count_in_color_table();
534 if(count
> 0 && count
<= 256+COL_TRANS()){
538 int red
, green
, blue
;
541 ct
= (struct color_table
*) fs_get((count
+1) * sizeof(struct color_table
));
543 memset(ct
, 0, (count
+1) * sizeof(struct color_table
));
546 * We boldly assume that 256 colors means xterm 256-color
547 * color cube and grayscale.
549 if(ANSI_COLOR() && (count
== 256+COL_TRANS())){
552 for(r
= 0; r
< 6; r
++)
553 for(g
= 0; g
< 6; g
++)
554 for(b
= 0; b
< 6; b
++){
555 ind
= 16 + 36*r
+ 6*g
+ b
;
556 cube
[ind
].red
= r
? (40*r
+ 55) : 0;
557 cube
[ind
].green
= g
? (40*g
+ 55) : 0;
558 cube
[ind
].blue
= b
? (40*b
+ 55) : 0;
559 snprintf(cube
[ind
].rgb
, sizeof(cube
[ind
].rgb
), "%3.3d,%3.3d,%3.3d",
560 cube
[ind
].red
, cube
[ind
].green
, cube
[ind
].blue
);
563 for(gray
= 0; gray
< 24; gray
++){
565 graylevel
= 10*gray
+ 8;
566 cube
[ind
].red
= graylevel
;
567 cube
[ind
].green
= graylevel
;
568 cube
[ind
].blue
= graylevel
;
569 snprintf(cube
[ind
].rgb
, sizeof(cube
[ind
].rgb
), "%3.3d,%3.3d,%3.3d",
570 graylevel
, graylevel
, graylevel
);
574 for(i
= 0, t
= ct
; t
&& i
< count
; i
++, t
++){
579 strncpy(colorname
, "black", sizeof(colorname
));
580 colorname
[sizeof(colorname
)-1] = '\0';
583 strncpy(colorname
, "red", sizeof(colorname
));
584 colorname
[sizeof(colorname
)-1] = '\0';
587 strncpy(colorname
, "green", sizeof(colorname
));
588 colorname
[sizeof(colorname
)-1] = '\0';
591 strncpy(colorname
, "yellow", sizeof(colorname
));
592 colorname
[sizeof(colorname
)-1] = '\0';
595 strncpy(colorname
, "blue", sizeof(colorname
));
596 colorname
[sizeof(colorname
)-1] = '\0';
599 strncpy(colorname
, "magenta", sizeof(colorname
));
600 colorname
[sizeof(colorname
)-1] = '\0';
603 strncpy(colorname
, "cyan", sizeof(colorname
));
604 colorname
[sizeof(colorname
)-1] = '\0';
607 strncpy(colorname
, "white", sizeof(colorname
));
608 colorname
[sizeof(colorname
)-1] = '\0';
611 snprintf(colorname
, sizeof(colorname
), "color%3.3d", i
);
615 if(COL_TRANS() && i
== count
-1){
616 strncpy(colorname
, MATCH_TRAN_COLOR
, sizeof(colorname
));
617 colorname
[sizeof(colorname
)-1] = '\0';
620 add_to_color_name_list(t
, colorname
);
622 if(count
== 8+COL_TRANS()){
623 if(COL_TRANS() && i
== count
-1){
624 t
->red
= t
->green
= t
->blue
= -1;
629 t
->red
= t
->green
= t
->blue
= 0;
630 add_to_color_name_list(t
, "color008");
631 add_to_color_name_list(t
, "colordgr");
632 add_to_color_name_list(t
, "colormgr");
636 t
->green
= t
->blue
= 0;
637 add_to_color_name_list(t
, "color009");
641 t
->red
= t
->blue
= 0;
642 add_to_color_name_list(t
, "color010");
645 t
->red
= t
->green
= 255;
647 add_to_color_name_list(t
, "color011");
650 t
->red
= t
->green
= 0;
652 add_to_color_name_list(t
, "color012");
655 t
->red
= t
->blue
= 255;
657 add_to_color_name_list(t
, "color013");
661 t
->green
= t
->blue
= 255;
662 add_to_color_name_list(t
, "color014");
665 t
->red
= t
->green
= t
->blue
= 255;
666 add_to_color_name_list(t
, "color015");
667 add_to_color_name_list(t
, "colorlgr");
671 else if(count
== 16+COL_TRANS() || count
== 256+COL_TRANS()){
672 if(COL_TRANS() && i
== count
-1){
673 t
->red
= t
->green
= t
->blue
= -1;
677 * This set of RGB values seems to come close to describing
678 * what a 16-color xterm gives you.
682 t
->red
= t
->green
= t
->blue
= 0;
684 case COL_RED
: /* actually dark red */
686 t
->green
= t
->blue
= 0;
688 case COL_GREEN
: /* actually dark green */
690 t
->red
= t
->blue
= 0;
692 case COL_YELLOW
: /* actually dark yellow */
694 t
->red
= t
->green
= 174;
696 case COL_BLUE
: /* actually dark blue */
698 t
->red
= t
->green
= 0;
700 case COL_MAGENTA
: /* actually dark magenta */
702 t
->red
= t
->blue
= 174;
704 case COL_CYAN
: /* actually dark cyan */
706 t
->green
= t
->blue
= 174;
708 case COL_WHITE
: /* actually light gray */
709 t
->red
= t
->green
= t
->blue
= 174;
711 add_to_color_name_list(t
, "colorlgr");
714 case 8: /* dark gray */
715 t
->red
= t
->green
= t
->blue
= 64;
717 add_to_color_name_list(t
, "colordgr");
718 add_to_color_name_list(t
, "colormgr");
724 t
->green
= t
->blue
= 0;
728 t
->red
= t
->blue
= 0;
730 case 11: /* yellow */
732 t
->red
= t
->green
= 255;
736 t
->red
= t
->green
= 0;
738 case 13: /* magenta */
740 t
->red
= t
->blue
= 255;
744 t
->green
= t
->blue
= 255;
747 t
->red
= t
->green
= t
->blue
= 255;
750 t
->red
= cube
[i
].red
;
751 t
->green
= cube
[i
].green
;
752 t
->blue
= cube
[i
].blue
;
755 add_to_color_name_list(t
, "colordgr");
759 add_to_color_name_list(t
, "colormgr");
763 add_to_color_name_list(t
, "colorlgr");
771 if(COL_TRANS() && i
== count
-1){
772 t
->red
= t
->green
= t
->blue
= -1;
777 t
->red
= t
->green
= t
->blue
= 0;
779 case COL_RED
: /* actually dark red */
781 t
->green
= t
->blue
= 0;
783 case COL_GREEN
: /* actually dark green */
785 t
->red
= t
->blue
= 0;
787 case COL_YELLOW
: /* actually dark yellow */
789 t
->red
= t
->green
= 255;
791 case COL_BLUE
: /* actually dark blue */
793 t
->red
= t
->green
= 0;
795 case COL_MAGENTA
: /* actually dark magenta */
797 t
->red
= t
->blue
= 255;
799 case COL_CYAN
: /* actually dark cyan */
801 t
->green
= t
->blue
= 255;
803 case COL_WHITE
: /* actually light gray */
804 t
->red
= t
->green
= t
->blue
= 255;
807 /* this will just be a string match */
808 t
->red
= t
->green
= t
->blue
= 256+i
;
814 for(i
= 0, t
= ct
; t
&& i
< count
; i
++, t
++){
815 t
->rgb
= (char *)fs_get((RGBLEN
+1) * sizeof(char));
816 if(COL_TRANS() && i
== count
-1)
817 snprintf(t
->rgb
, RGBLEN
+1, MATCH_TRAN_COLOR
);
819 snprintf(t
->rgb
, RGBLEN
+1, "%3.3d,%3.3d,%3.3d", t
->red
, t
->green
, t
->blue
);
828 add_to_color_name_list(struct color_table
*t
, char *name
)
830 if(t
&& name
&& *name
){
831 struct color_name_list
*new_name
;
833 new_name
= (struct color_name_list
*) fs_get(sizeof(struct color_name_list
));
835 memset(new_name
, 0, sizeof(*new_name
));
836 new_name
->namelen
= strlen(name
);
838 new_name
->name
= (char *) fs_get((new_name
->namelen
+1) * sizeof(char));
840 strncpy(new_name
->name
, name
, new_name
->namelen
+1);
841 new_name
->name
[new_name
->namelen
] = '\0';
844 struct color_name_list
*nl
;
845 for(nl
= t
->names
; nl
->next
; nl
= nl
->next
)
859 free_color_name_list(struct color_name_list
**nl
)
863 free_color_name_list(&(*nl
)->next
);
866 fs_give((void **) &(*nl
)->name
);
868 fs_give((void **) nl
);
874 * Map from integer color value to canonical color name.
879 struct color_table
*ct
;
880 static char cbuf
[12];
882 /* before we get set up, we still need to use this a bit */
902 snprintf(cbuf
, sizeof(cbuf
), "color%3.3d", color
);
907 for(ct
= color_tbl
; ct
->names
; ct
++)
911 /* rgb _is_ the canonical name */
915 /* not supposed to get here */
916 snprintf(cbuf
, sizeof(cbuf
), "color%3.3d", color
);
922 * Argument is a color name which could be an RGB string, a name like "blue",
923 * or a name like "color011".
925 * Returns a pointer to the canonical name of the color.
928 color_to_canonical_name(char *s
)
930 struct color_table
*ct
;
931 struct color_name_list
*nl
;
937 if(*s
== ' ' || isdigit(*s
)){
938 /* check for rgb string instead of name */
939 for(ct
= color_tbl
; ct
->rgb
; ct
++)
940 if(!strncmp(ct
->rgb
, s
, RGBLEN
))
944 for(done
=0, ct
= color_tbl
; !done
&& ct
->names
; ct
++){
945 for(nl
= ct
->names
; !done
&& nl
; nl
= nl
->next
)
946 if(nl
->name
&& !struncmp(nl
->name
, s
, nl
->namelen
))
954 /* rgb is the canonical name */
957 else if(!struncmp(s
, MATCH_NORM_COLOR
, RGBLEN
) || !struncmp(s
, MATCH_NONE_COLOR
, RGBLEN
))
965 * Argument is the name of a color or an RGB value that we recognize.
966 * The table should be set up so that the val returned is the same whether
967 * or not we choose the canonical name.
969 * Returns the integer value for the color.
972 color_to_val(char *s
)
974 struct color_table
*ct
;
975 struct color_name_list
*nl
;
981 if(*s
== ' ' || isdigit(*s
)){
982 /* check for rgb string instead of name */
983 for(ct
= color_tbl
; ct
->rgb
; ct
++)
984 if(!strncmp(ct
->rgb
, s
, RGBLEN
))
988 * Didn't match any. Find "closest" to match.
991 int r
= -1, g
= -1, b
= -1;
992 char *p
, *comma
, scopy
[RGBLEN
+1];
994 strncpy(scopy
, s
, sizeof(scopy
));
995 scopy
[sizeof(scopy
)-1] = '\0';
998 comma
= strchr(p
, ',');
1003 if(r
>= 0 && r
<= 255 && *p
){
1004 comma
= strchr(p
, ',');
1009 if(g
>= 0 && g
<= 255 && *p
){
1016 if(r
>= 0 && r
<= 255 && g
>= 0 && g
<= 255 && b
>= 0 && b
<= 255){
1017 struct color_table
*closest
= NULL
;
1018 int closest_value
= 1000000;
1021 for(ct
= color_tbl
; ct
->rgb
; ct
++){
1023 if(ct
->red
>= 0 && ct
->red
<= 255
1024 && ct
->green
>= 0 && ct
->green
<= 255
1025 && ct
->blue
>= 0 && ct
->blue
<= 255){
1026 cv
= (ct
->red
- r
) * (ct
->red
- r
) +
1027 (ct
->green
- g
) * (ct
->green
- g
) +
1028 (ct
->blue
- b
) * (ct
->blue
- b
);
1029 if(cv
< closest_value
){
1042 for(done
=0, ct
= color_tbl
; !done
&& ct
->names
; ct
++){
1043 for(nl
= ct
->names
; !done
&& nl
; nl
= nl
->next
)
1044 if(nl
->name
&& !struncmp(nl
->name
, s
, nl
->namelen
))
1060 free_color_table(struct color_table
**ctbl
)
1062 struct color_table
*t
;
1065 for(t
= *ctbl
; t
->names
; t
++){
1066 free_color_name_list(&t
->names
);
1069 fs_give((void **) &t
->rgb
);
1072 fs_give((void **) ctbl
);
1078 pico_count_in_color_table(void)
1082 ? (ANSI8_COLOR() ? 8 : ANSI16_COLOR() ? 16 : 256)
1089 pico_nfcolor(char *s
)
1092 fs_give((void **) &_nfcolor
);
1098 _nfcolor
= (char *) fs_get((len
+1) * sizeof(char));
1100 strncpy(_nfcolor
, s
, len
+1);
1101 _nfcolor
[len
] = '\0';
1104 if(the_normal_color
){
1105 strncpy(the_normal_color
->fg
, _nfcolor
, MAXCOLORLEN
+1);
1106 the_normal_color
->fg
[MAXCOLORLEN
] = '\0';
1109 else if(the_normal_color
)
1110 free_color_pair(&the_normal_color
);
1115 pico_nbcolor(char *s
)
1118 fs_give((void **) &_nbcolor
);
1124 _nbcolor
= (char *) fs_get((len
+1) * sizeof(char));
1126 strncpy(_nbcolor
, s
, len
+1);
1127 _nbcolor
[len
] = '\0';
1130 if(the_normal_color
){
1131 strncpy(the_normal_color
->bg
, _nbcolor
, MAXCOLORLEN
+1);
1132 the_normal_color
->bg
[MAXCOLORLEN
] = '\0';
1135 else if(the_normal_color
)
1136 free_color_pair(&the_normal_color
);
1140 pico_rfcolor(char *s
)
1143 fs_give((void **) &_rfcolor
);
1149 _rfcolor
= (char *) fs_get((len
+1) * sizeof(char));
1151 strncpy(_rfcolor
, s
, len
+1);
1152 _rfcolor
[len
] = '\0';
1156 strncpy(the_rev_color
->fg
, _rfcolor
, MAXCOLORLEN
+1);
1157 the_rev_color
->fg
[MAXCOLORLEN
] = '\0';
1160 else if(the_rev_color
)
1161 free_color_pair(&the_rev_color
);
1165 pico_rbcolor(char *s
)
1168 fs_give((void **) &_rbcolor
);
1174 _rbcolor
= (char *) fs_get((len
+1) * sizeof(char));
1176 strncpy(_rbcolor
, s
, len
+1);
1177 _rbcolor
[len
] = '\0';
1181 strncpy(the_rev_color
->bg
, _rbcolor
, MAXCOLORLEN
+1);
1182 the_rev_color
->bg
[MAXCOLORLEN
] = '\0';
1185 else if(the_rev_color
)
1186 free_color_pair(&the_rev_color
);
1196 return(_color_inited
);
1201 pico_usingcolor(void)
1203 return(_using_color
&& pico_hascolor());
1208 * This should only be called when we're using the
1209 * unix termdef color, as opposed to the ANSI defined
1210 * color stuff or the Windows stuff.
1213 pico_trans_color(void)
1215 return(_bce
&& _op
);
1220 pico_toggle_color(int on
)
1231 free_color_table(&color_tbl
);
1234 putpad("\033[39;49m");
1247 pico_get_color_options(void)
1249 return(color_options
);
1254 pico_trans_is_on(void)
1256 return(COL_TRANS());
1261 * Absolute set of options. Caller has to OR things together and so forth.
1264 pico_set_color_options(unsigned flags
)
1266 color_options
= flags
;
1272 pico_toggle_color(0);
1277 fs_give((void **) &_nfcolor
);
1280 fs_give((void **) &_nbcolor
);
1283 fs_give((void **) &_rfcolor
);
1286 fs_give((void **) &_rbcolor
);
1289 fs_give((void **) &_last_fg_color
);
1292 fs_give((void **) &_last_bg_color
);
1295 free_color_pair(&the_rev_color
);
1297 if(the_normal_color
)
1298 free_color_pair(&the_normal_color
);
1303 pico_set_nfg_color(void)
1306 (void)pico_set_fg_color(_nfcolor
);
1311 pico_set_nbg_color(void)
1314 (void)pico_set_bg_color(_nbcolor
);
1319 pico_set_normal_color(void)
1321 if(!_nfcolor
|| !_nbcolor
||
1322 !pico_set_fg_color(_nfcolor
) || !pico_set_bg_color(_nbcolor
)){
1323 (void)pico_set_fg_color(DEFAULT_NORM_FORE_RGB
);
1324 (void)pico_set_bg_color(DEFAULT_NORM_BACK_RGB
);
1330 * If inverse is a color, returns a pointer to that color.
1331 * If not, returns NULL.
1333 * NOTE: Don't free this!
1336 pico_get_rev_color(void)
1338 if(pico_usingcolor() && _rfcolor
&& _rbcolor
&&
1339 pico_is_good_color(_rfcolor
) && pico_is_good_color(_rbcolor
)){
1341 the_rev_color
= new_color_pair(_rfcolor
, _rbcolor
);
1343 return(the_rev_color
);
1351 * Returns a pointer to the normal color.
1353 * NOTE: Don't free this!
1356 pico_get_normal_color(void)
1358 if(pico_usingcolor() && _nfcolor
&& _nbcolor
&&
1359 pico_is_good_color(_nfcolor
) && pico_is_good_color(_nbcolor
)){
1360 if(!the_normal_color
)
1361 the_normal_color
= new_color_pair(_nfcolor
, _nbcolor
);
1363 return(the_normal_color
);
1371 * Sets color to (fg,bg).
1372 * Flags == PSC_NONE No alternate default if fg,bg fails.
1373 * == PSC_NORM Set it to Normal color on failure.
1374 * == PSC_REV Set it to Reverse color on failure.
1376 * If flag PSC_RET is set, returns an allocated copy of the previous
1377 * color pair, otherwise returns NULL.
1380 pico_set_colors(char *fg
, char *bg
, int flags
)
1383 COLOR_PAIR
*cp
= NULL
, *rev
= NULL
;
1386 cp
= pico_get_cur_color();
1388 if(fg
&& !strcmp(fg
, END_PSEUDO_REVERSE
)){
1391 free_color_pair(&cp
);
1393 else if(!((uc
=pico_usingcolor()) && fg
&& bg
&&
1394 pico_set_fg_color(fg
) && pico_set_bg_color(bg
))){
1396 if(uc
&& flags
& PSC_NORM
)
1397 pico_set_normal_color();
1398 else if(flags
& PSC_REV
){
1399 if((rev
= pico_get_rev_color()) != NULL
){
1400 pico_set_fg_color(rev
->fg
); /* these will succeed */
1401 pico_set_bg_color(rev
->bg
);
1406 strncpy(cp
->fg
, END_PSEUDO_REVERSE
, MAXCOLORLEN
+1);
1407 cp
->fg
[MAXCOLORLEN
] = '\0';
1408 strncpy(cp
->bg
, END_PSEUDO_REVERSE
, MAXCOLORLEN
+1);
1409 cp
->bg
[MAXCOLORLEN
] = '\0';
1420 pico_is_good_color(char *s
)
1422 struct color_table
*ct
;
1423 struct color_name_list
*nl
;
1426 if(!s
|| !color_tbl
)
1429 if(!strcmp(s
, END_PSEUDO_REVERSE
))
1431 else if(!struncmp(s
, MATCH_NORM_COLOR
, RGBLEN
) || !struncmp(s
, MATCH_NONE_COLOR
, RGBLEN
))
1433 else if(*s
== ' ' || isdigit(*s
)){
1434 /* check for rgb string instead of name */
1435 for(ct
= color_tbl
; ct
->rgb
; ct
++)
1436 if(!strncmp(ct
->rgb
, s
, RGBLEN
))
1439 /* if no match it's still ok if rgb */
1441 int r
= -1, g
= -1, b
= -1;
1442 char *p
, *comma
, scopy
[RGBLEN
+1];
1444 strncpy(scopy
, s
, sizeof(scopy
));
1445 scopy
[sizeof(scopy
)-1] = '\0';
1448 comma
= strchr(p
, ',');
1453 if(r
>= 0 && r
<= 255 && *p
){
1454 comma
= strchr(p
, ',');
1459 if(g
>= 0 && g
<= 255 && *p
){
1466 if(r
>= 0 && r
<= 255 && g
>= 0 && g
<= 255 && b
>= 0 && b
<= 255)
1467 ct
= color_tbl
; /* to force TRUE */
1471 for(done
=0, ct
= color_tbl
; !done
&& ct
->names
; ct
++){
1472 for(nl
= ct
->names
; !done
&& nl
; nl
= nl
->next
)
1473 if(nl
->name
&& !struncmp(nl
->name
, s
, nl
->namelen
))
1481 return(ct
->names
? TRUE
: FALSE
);
1486 * Return TRUE on success.
1489 pico_set_fg_color(char *s
)
1493 if(!s
|| !color_tbl
)
1496 if(!strcmp(s
, END_PSEUDO_REVERSE
)){
1501 if(!struncmp(s
, MATCH_NORM_COLOR
, RGBLEN
))
1503 else if(!struncmp(s
, MATCH_NONE_COLOR
, RGBLEN
))
1506 if((val
= color_to_val(s
)) >= 0){
1510 changed
= !_last_fg_color
|| strcmp(_last_fg_color
,colorx(val
));
1512 /* already set correctly */
1513 if(!_force_fg_color_change
&& !changed
)
1516 _force_fg_color_change
= 0;
1520 fs_give((void **) &_last_fg_color
);
1522 len
= strlen(colorx(val
));
1523 if((_last_fg_color
= (char *) fs_get((len
+1) * sizeof(char))) != NULL
){
1524 strncpy(_last_fg_color
, colorx(val
), len
+1);
1525 _last_fg_color
[len
] = '\0';
1538 pico_set_bg_color(char *s
)
1542 if(!s
|| !color_tbl
)
1545 if(!strcmp(s
, END_PSEUDO_REVERSE
)){
1550 if(!struncmp(s
, MATCH_NORM_COLOR
, RGBLEN
))
1552 else if(!struncmp(s
, MATCH_NONE_COLOR
, RGBLEN
))
1555 if((val
= color_to_val(s
)) >= 0){
1559 changed
= !_last_bg_color
|| strcmp(_last_bg_color
,colorx(val
));
1561 /* already set correctly */
1562 if(!_force_bg_color_change
&& !changed
)
1565 _force_bg_color_change
= 0;
1569 fs_give((void **) &_last_bg_color
);
1571 len
= strlen(colorx(val
));
1572 if((_last_bg_color
= (char *) fs_get((len
+1) * sizeof(char))) != NULL
){
1573 strncpy(_last_bg_color
, colorx(val
), len
+1);
1574 _last_bg_color
[len
] = '\0';
1587 * Return a pointer to an rgb string for the input color. The output is 11
1588 * characters long and looks like rrr,ggg,bbb.
1590 * Args colorName -- The color to convert to ascii rgb.
1592 * Returns Pointer to a static buffer containing the rgb string. Can use up
1593 * to three returned values at once before the first is overwritten.
1596 color_to_asciirgb(char *colorName
)
1598 static char c_to_a_buf
[3][RGBLEN
+1];
1599 static int whichbuf
= 0;
1600 struct color_table
*ct
;
1601 struct color_name_list
*nl
;
1604 whichbuf
= (whichbuf
+ 1) % 3;
1606 c_to_a_buf
[whichbuf
][0] = '\0';
1608 for(done
=0, ct
= color_tbl
; !done
&& ct
->names
; ct
++){
1609 for(nl
= ct
->names
; !done
&& nl
; nl
= nl
->next
)
1610 if(nl
->name
&& !struncmp(nl
->name
, colorName
, nl
->namelen
))
1617 if(ct
&& ct
->names
){
1618 strncpy(c_to_a_buf
[whichbuf
], ct
->rgb
, sizeof(c_to_a_buf
[0]));
1619 c_to_a_buf
[whichbuf
][sizeof(c_to_a_buf
[0])-1] = '\0';
1621 else if(*colorName
== ' ' || isdigit(*colorName
)){
1622 /* check for rgb string instead of name */
1623 for(ct
= color_tbl
; ct
->rgb
; ct
++)
1624 if(!strncmp(ct
->rgb
, colorName
, RGBLEN
))
1627 /* if no match it's still ok if rgb */
1629 int r
= -1, g
= -1, b
= -1;
1630 char *p
, *comma
, scopy
[RGBLEN
+1];
1632 strncpy(scopy
, colorName
, sizeof(scopy
));
1633 scopy
[sizeof(scopy
)-1] = '\0';
1636 comma
= strchr(p
, ',');
1641 if(r
>= 0 && r
<= 255 && *p
){
1642 comma
= strchr(p
, ',');
1647 if(g
>= 0 && g
<= 255 && *p
){
1654 if(r
>= 0 && r
<= 255 && g
>= 0 && g
<= 255 && b
>= 0 && b
<= 255){
1655 /* it was already RGB */
1656 snprintf(c_to_a_buf
[whichbuf
], sizeof(c_to_a_buf
[0]), "%3.3d,%3.3d,%3.3d", r
, g
, b
);
1660 strncpy(c_to_a_buf
[whichbuf
], ct
->rgb
, sizeof(c_to_a_buf
[0]));
1661 c_to_a_buf
[whichbuf
][sizeof(c_to_a_buf
[0])-1] = '\0';
1665 if(!c_to_a_buf
[whichbuf
][0]){
1669 * If we didn't find the color it could be that it is the
1670 * normal color (MATCH_NORM_COLOR) or the none color
1671 * (MATCH_NONE_COLOR). If that is the case, this strncpy thing
1672 * will work out correctly because those two strings are
1673 * RGBLEN long. Otherwise we're in a bit of trouble. This
1674 * most likely means that the user is using the same pinerc on
1675 * two terminals, one with more colors than the other. We didn't
1676 * find a match because this color isn't present on this terminal.
1677 * Since the return value of this function is assumed to be
1678 * RGBLEN long, we'd better make it that long.
1679 * It still won't work correctly because colors will be screwed up,
1680 * but at least the embedded colors in filter.c will get properly
1681 * sucked up when they're encountered.
1683 strncpy(c_to_a_buf
[whichbuf
], "xxxxxxxxxxx", RGBLEN
); /* RGBLEN is 11 */
1684 l
= strlen(colorName
);
1685 strncpy(c_to_a_buf
[whichbuf
], colorName
, (l
< RGBLEN
) ? l
: RGBLEN
);
1686 c_to_a_buf
[whichbuf
][RGBLEN
] = '\0';
1689 return(c_to_a_buf
[whichbuf
]);
1694 pico_get_last_fg_color(void)
1701 len
= strlen(_last_fg_color
);
1702 if((ret
= (char *) fs_get((len
+1) * sizeof(char))) != NULL
){
1703 strncpy(ret
, _last_fg_color
, len
+1);
1713 pico_get_last_bg_color(void)
1720 len
= strlen(_last_bg_color
);
1721 if((ret
= (char *) fs_get((len
+1) * sizeof(char))) != NULL
){
1722 strncpy(ret
, _last_bg_color
, len
+1);
1732 pico_get_cur_color(void)
1734 return(new_color_pair(_last_fg_color
, _last_bg_color
));
1737 #else /* _WINDOWS */
1738 static short _in_inverse
, _in_bold
, _in_uline
;
1741 pico_trans_is_on(void)
1750 mswin_rev(_in_inverse
= 1);
1757 mswin_rev(_in_inverse
= 0);
1763 return(_in_inverse
);
1770 mswin_uline(_in_uline
= 1);
1777 mswin_uline(_in_uline
= 0);
1784 mswin_bold(_in_bold
= 1);
1793 mswin_bold(_in_bold
= 0);
1797 #endif /* _WINDOWS */