2 * ========================================================================
3 * Copyright 2006-2007 University of Washington
4 * Copyright 2013-2022 Eduardo Chappa
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
19 #include "../headers.h"
23 #include "../../pith/osdep/color.h"
24 #include "../../pith/osdep/collate.h"
28 struct color_name_list
{
31 struct color_name_list
*next
;
35 struct color_name_list
*names
;
42 /* useful definitions */
43 #define ANSI8_COLOR() (color_options & COLOR_ANSI8_OPT)
44 #define ANSI16_COLOR() (color_options & COLOR_ANSI16_OPT)
45 #define ANSI256_COLOR() (color_options & COLOR_ANSI256_OPT)
46 #define ANSI_COLOR() (color_options & (COLOR_ANSI8_OPT | COLOR_ANSI16_OPT | COLOR_ANSI256_OPT))
47 /* transparent (default) color is possible */
48 #define COL_TRANS() ((color_options & COLOR_TRANS_OPT) ? 1 : 0) /* transparent */
49 #define END_PSEUDO_REVERSE "EndInverse"
54 static unsigned color_options
;
55 static COLOR_PAIR
*the_rev_color
, *the_normal_color
;
56 static COLOR_PAIR
*color_blasted_by_attrs
;
57 static int pinvstate
; /* physical state of inverse (standout) attribute */
58 static int pboldstate
; /* physical state of bold attribute */
59 static int pulstate
; /* physical state of underline attribute */
60 static int rev_color_state
;
62 static int boldstate
; /* should-be state of bold attribute */
63 static int ulstate
; /* should-be state of underline attribute */
64 static int invstate
; /* should-be state of Inverse, which could be a color
65 change or an actual setinverse */
66 static int _color_inited
, _using_color
;
67 static char *_nfcolor
, *_nbcolor
, *_rfcolor
, *_rbcolor
;
68 static char *_last_fg_color
, *_last_bg_color
;
69 static int _force_fg_color_change
;
70 static int _force_bg_color_change
;
72 static struct color_table
*color_tbl
;
74 /* external references */
75 extern char *_op
, *_oc
, *_setaf
, *_setab
, *_setf
, *_setb
, *_scp
;
76 extern int _bce
, _colors
;
79 /* internal prototypes */
80 void flip_rev_color(int);
83 void reset_attr_state(void);
84 void add_to_color_name_list(struct color_table
*t
, char *name
);
85 void free_color_name_list(struct color_name_list
**nl
);
89 extern char *tparm(char *, ...);
91 extern char *tgoto(char *, int, int);
92 void tinitcolor(void);
95 struct color_table
*init_color_table(void);
96 void free_color_table(struct color_table
**);
97 int color_to_val(char *);
102 * Start or end bold mode
104 * Result: escape sequence to go into or out of reverse color is output
106 * (This is only called when there is a reverse color.)
108 * Arg state = ON set bold
112 flip_rev_color(int state
)
114 if((rev_color_state
= state
) == TRUE
)
115 (void)pico_set_colorp(the_rev_color
, PSC_NONE
);
117 pico_set_normal_color();
122 * Start or end bold mode
124 * Result: escape sequence to go into or out of bold is output
126 * Arg state = ON set bold
132 extern char *_setbold
, *_clearallattr
;
134 if((pboldstate
= state
) == TRUE
){
139 if(_clearallattr
!= NULL
){
140 if(!color_blasted_by_attrs
)
141 color_blasted_by_attrs
= pico_get_cur_color();
143 _force_fg_color_change
= _force_bg_color_change
= 1;
144 putpad(_clearallattr
);
147 rev_color_state
= state
;
154 * Start or end inverse mode
156 * Result: escape sequence to go into or out of inverse is output
158 * Arg state = ON set inverse
164 extern char *_setinverse
, *_clearinverse
;
166 if((pinvstate
= state
) == TRUE
){
167 if(_setinverse
!= NULL
)
172 * Unfortunately, some termcap entries configure end standout to
173 * be clear all attributes.
175 if(_clearinverse
!= NULL
){
176 if(!color_blasted_by_attrs
)
177 color_blasted_by_attrs
= pico_get_cur_color();
179 _force_fg_color_change
= _force_bg_color_change
= 1;
180 putpad(_clearinverse
);
181 pboldstate
= (pboldstate
== FALSE
) ? pboldstate
: A_UNKNOWN
;
182 pulstate
= (pulstate
== FALSE
) ? pulstate
: A_UNKNOWN
;
183 rev_color_state
= A_UNKNOWN
;
190 * Start or end underline mode
192 * Result: escape sequence to go into or out of underline is output
194 * Arg state = ON set underline
200 extern char *_setunderline
, *_clearunderline
;
202 if((pulstate
= state
) == TRUE
){
203 if(_setunderline
!= NULL
)
204 putpad(_setunderline
);
208 * Unfortunately, some termcap entries configure end underline to
209 * be clear all attributes.
211 if(_clearunderline
!= NULL
){
212 if(!color_blasted_by_attrs
)
213 color_blasted_by_attrs
= pico_get_cur_color();
215 _force_fg_color_change
= _force_bg_color_change
= 1;
216 putpad(_clearunderline
);
217 pboldstate
= (pboldstate
== FALSE
) ? pboldstate
: A_UNKNOWN
;
218 pinvstate
= (pinvstate
== FALSE
) ? pinvstate
: A_UNKNOWN
;
219 rev_color_state
= A_UNKNOWN
;
251 extern char *_setbold
;
255 return(_setbold
!= NULL
);
284 reset_attr_state(void)
287 * If we have to turn some attributes off, do that first since that
288 * may turn off other attributes as a side effect.
290 if(boldstate
== FALSE
&& pboldstate
!= boldstate
)
291 flip_bold(boldstate
);
293 if(ulstate
== FALSE
&& pulstate
!= ulstate
)
296 if(invstate
== FALSE
){
297 if(pico_get_rev_color()){
298 if(rev_color_state
!= invstate
)
299 flip_rev_color(invstate
);
302 if(pinvstate
!= invstate
)
308 * Now turn everything on that needs turning on.
310 if(boldstate
== TRUE
&& pboldstate
!= boldstate
)
311 flip_bold(boldstate
);
313 if(ulstate
== TRUE
&& pulstate
!= ulstate
)
316 if(invstate
== TRUE
){
317 if(pico_get_rev_color()){
318 if(rev_color_state
!= invstate
)
319 flip_rev_color(invstate
);
322 if(pinvstate
!= invstate
)
327 if(color_blasted_by_attrs
){
328 (void)pico_set_colorp(color_blasted_by_attrs
, PSC_NONE
);
329 free_color_pair(&color_blasted_by_attrs
);
338 if(_color_inited
|| panicking())
341 if(ANSI_COLOR() || (_colors
> 0 && ((_setaf
&& _setab
) || (_setf
&& _setb
)
342 /**** not sure how to do this yet
347 color_tbl
= init_color_table();
350 putpad("\033[39;49m");
363 * Treading on thin ice here. Tgoto wasn't designed for this. It takes
364 * arguments column and row. We only use one of them, so we put it in
365 * the row argument. The 0 is just a placeholder.
367 #define tparm(s, c) tgoto(s, 0, c)
379 if((ANSI8_COLOR() && (color
< 0 || color
>= 8+COL_TRANS())) ||
380 (ANSI16_COLOR() && (color
< 0 || color
>= 16+COL_TRANS())) ||
381 (ANSI256_COLOR() && (color
< 0 || color
>= 256+COL_TRANS())) ||
382 (!ANSI_COLOR() && (color
< 0 || color
>= _colors
+COL_TRANS())))
388 if(COL_TRANS() && color
== pico_count_in_color_table()-1)
389 snprintf(buf
, sizeof(buf
), "\033[39m");
390 else if(ANSI256_COLOR())
391 snprintf(buf
, sizeof(buf
), "\033[38;5;%dm", color
);
394 snprintf(buf
, sizeof(buf
), "\033[3%cm", color
+ '0');
396 snprintf(buf
, sizeof(buf
), "\033[9%cm", (color
-8) + '0');
401 else if(COL_TRANS() && color
== pico_count_in_color_table()-1 && _op
){
402 char bg_color_was
[MAXCOLORLEN
+1];
404 bg_color_was
[0] = '\0';
407 * Setting transparent (default) foreground color.
408 * We don't know how to set only the default foreground color,
409 * _op sets both foreground and background. So we need to
411 * get current background color
413 * if (current background was not default) reset it
415 if(_last_bg_color
&& strncmp(_last_bg_color
, MATCH_TRAN_COLOR
, RGBLEN
)){
416 strncpy(bg_color_was
, _last_bg_color
, sizeof(bg_color_was
));
417 bg_color_was
[sizeof(bg_color_was
)-1] = '\0';
422 _force_bg_color_change
= 1;
423 pico_set_bg_color(bg_color_was
);
427 putpad(tparm(_setaf
, color
));
429 putpad(tparm(_setf
, color
));
431 /* set color pair method */
447 if((ANSI8_COLOR() && (color
< 0 || color
>= 8+COL_TRANS())) ||
448 (ANSI16_COLOR() && (color
< 0 || color
>= 16+COL_TRANS())) ||
449 (ANSI256_COLOR() && (color
< 0 || color
>= 256+COL_TRANS())) ||
450 (!ANSI_COLOR() && (color
< 0 || color
>= _colors
+COL_TRANS())))
456 if(COL_TRANS() && color
== pico_count_in_color_table()-1)
457 snprintf(buf
, sizeof(buf
), "\033[49m");
458 else if(ANSI256_COLOR())
459 snprintf(buf
, sizeof(buf
), "\033[48;5;%dm", color
);
462 snprintf(buf
, sizeof(buf
), "\033[4%cm", color
+ '0');
464 snprintf(buf
, sizeof(buf
), "\033[10%cm", (color
-8) + '0');
469 else if(COL_TRANS() && color
== pico_count_in_color_table()-1 && _op
){
470 char fg_color_was
[MAXCOLORLEN
+1];
472 fg_color_was
[0] = '\0';
475 * Setting transparent (default) background color.
476 * We don't know how to set only the default background color,
477 * _op sets both foreground and background. So we need to
479 * get current foreground color
481 * if (current foreground was not default) reset it
483 if(_last_fg_color
&& strncmp(_last_fg_color
, MATCH_TRAN_COLOR
, RGBLEN
)){
484 strncpy(fg_color_was
, _last_fg_color
, sizeof(fg_color_was
));
485 fg_color_was
[sizeof(fg_color_was
)-1] = '\0';
490 _force_fg_color_change
= 1;
491 pico_set_fg_color(fg_color_was
);
495 putpad(tparm(_setab
, color
));
497 putpad(tparm(_setb
, color
));
499 /* set color pair method */
508 * We're not actually using the RGB value other than as a string which
509 * maps into the color.
510 * In fact, on some systems color 1 and color 4 are swapped, and color 3
511 * and color 6 are swapped. So don't believe the RGB values.
512 * Still, it feels right to have them be the canonical values, so we do that.
514 * Actually we are using them more now. In color_to_val we map to the closest
515 * color if we don't get an exact match. We ignore values over 255.
517 * More than one "name" can map to the same "rgb".
518 * More than one "name" can map to the same "val".
519 * The "val" for a "name" and for its "rgb" are the same.
522 init_color_table(void)
524 struct color_table
*ct
= NULL
, *t
;
528 count
= pico_count_in_color_table();
530 if(count
> 0 && count
<= 256+COL_TRANS()){
534 int red
, green
, blue
;
537 ct
= (struct color_table
*) fs_get((count
+1) * sizeof(struct color_table
));
539 memset(ct
, 0, (count
+1) * sizeof(struct color_table
));
542 * We boldly assume that 256 colors means xterm 256-color
543 * color cube and grayscale.
545 if(ANSI_COLOR() && (count
== 256+COL_TRANS())){
548 for(r
= 0; r
< 6; r
++)
549 for(g
= 0; g
< 6; g
++)
550 for(b
= 0; b
< 6; b
++){
551 ind
= 16 + 36*r
+ 6*g
+ b
;
552 cube
[ind
].red
= r
? (40*r
+ 55) : 0;
553 cube
[ind
].green
= g
? (40*g
+ 55) : 0;
554 cube
[ind
].blue
= b
? (40*b
+ 55) : 0;
555 snprintf(cube
[ind
].rgb
, sizeof(cube
[ind
].rgb
), "%3.3d,%3.3d,%3.3d",
556 cube
[ind
].red
, cube
[ind
].green
, cube
[ind
].blue
);
559 for(gray
= 0; gray
< 24; gray
++){
561 graylevel
= 10*gray
+ 8;
562 cube
[ind
].red
= graylevel
;
563 cube
[ind
].green
= graylevel
;
564 cube
[ind
].blue
= graylevel
;
565 snprintf(cube
[ind
].rgb
, sizeof(cube
[ind
].rgb
), "%3.3d,%3.3d,%3.3d",
566 graylevel
, graylevel
, graylevel
);
570 for(i
= 0, t
= ct
; t
&& i
< count
; i
++, t
++){
575 strncpy(colorname
, "black", sizeof(colorname
));
576 colorname
[sizeof(colorname
)-1] = '\0';
579 strncpy(colorname
, "red", sizeof(colorname
));
580 colorname
[sizeof(colorname
)-1] = '\0';
583 strncpy(colorname
, "green", sizeof(colorname
));
584 colorname
[sizeof(colorname
)-1] = '\0';
587 strncpy(colorname
, "yellow", sizeof(colorname
));
588 colorname
[sizeof(colorname
)-1] = '\0';
591 strncpy(colorname
, "blue", sizeof(colorname
));
592 colorname
[sizeof(colorname
)-1] = '\0';
595 strncpy(colorname
, "magenta", sizeof(colorname
));
596 colorname
[sizeof(colorname
)-1] = '\0';
599 strncpy(colorname
, "cyan", sizeof(colorname
));
600 colorname
[sizeof(colorname
)-1] = '\0';
603 strncpy(colorname
, "white", sizeof(colorname
));
604 colorname
[sizeof(colorname
)-1] = '\0';
607 snprintf(colorname
, sizeof(colorname
), "color%3.3d", i
);
611 if(COL_TRANS() && i
== count
-1){
612 strncpy(colorname
, MATCH_TRAN_COLOR
, sizeof(colorname
));
613 colorname
[sizeof(colorname
)-1] = '\0';
616 add_to_color_name_list(t
, colorname
);
618 if(count
== 8+COL_TRANS()){
619 if(COL_TRANS() && i
== count
-1){
620 t
->red
= t
->green
= t
->blue
= -1;
625 t
->red
= t
->green
= t
->blue
= 0;
626 add_to_color_name_list(t
, "color008");
627 add_to_color_name_list(t
, "colordgr");
628 add_to_color_name_list(t
, "colormgr");
632 t
->green
= t
->blue
= 0;
633 add_to_color_name_list(t
, "color009");
637 t
->red
= t
->blue
= 0;
638 add_to_color_name_list(t
, "color010");
641 t
->red
= t
->green
= 255;
643 add_to_color_name_list(t
, "color011");
646 t
->red
= t
->green
= 0;
648 add_to_color_name_list(t
, "color012");
651 t
->red
= t
->blue
= 255;
653 add_to_color_name_list(t
, "color013");
657 t
->green
= t
->blue
= 255;
658 add_to_color_name_list(t
, "color014");
661 t
->red
= t
->green
= t
->blue
= 255;
662 add_to_color_name_list(t
, "color015");
663 add_to_color_name_list(t
, "colorlgr");
667 else if(count
== 16+COL_TRANS() || count
== 256+COL_TRANS()){
668 if(COL_TRANS() && i
== count
-1){
669 t
->red
= t
->green
= t
->blue
= -1;
673 * This set of RGB values seems to come close to describing
674 * what a 16-color xterm gives you.
678 t
->red
= t
->green
= t
->blue
= 0;
680 case COL_RED
: /* actually dark red */
682 t
->green
= t
->blue
= 0;
684 case COL_GREEN
: /* actually dark green */
686 t
->red
= t
->blue
= 0;
688 case COL_YELLOW
: /* actually dark yellow */
690 t
->red
= t
->green
= 174;
692 case COL_BLUE
: /* actually dark blue */
694 t
->red
= t
->green
= 0;
696 case COL_MAGENTA
: /* actually dark magenta */
698 t
->red
= t
->blue
= 174;
700 case COL_CYAN
: /* actually dark cyan */
702 t
->green
= t
->blue
= 174;
704 case COL_WHITE
: /* actually light gray */
705 t
->red
= t
->green
= t
->blue
= 174;
707 add_to_color_name_list(t
, "colorlgr");
710 case 8: /* dark gray */
711 t
->red
= t
->green
= t
->blue
= 64;
713 add_to_color_name_list(t
, "colordgr");
714 add_to_color_name_list(t
, "colormgr");
720 t
->green
= t
->blue
= 0;
724 t
->red
= t
->blue
= 0;
726 case 11: /* yellow */
728 t
->red
= t
->green
= 255;
732 t
->red
= t
->green
= 0;
734 case 13: /* magenta */
736 t
->red
= t
->blue
= 255;
740 t
->green
= t
->blue
= 255;
743 t
->red
= t
->green
= t
->blue
= 255;
746 t
->red
= cube
[i
].red
;
747 t
->green
= cube
[i
].green
;
748 t
->blue
= cube
[i
].blue
;
751 add_to_color_name_list(t
, "colordgr");
755 add_to_color_name_list(t
, "colormgr");
759 add_to_color_name_list(t
, "colorlgr");
767 if(COL_TRANS() && i
== count
-1){
768 t
->red
= t
->green
= t
->blue
= -1;
773 t
->red
= t
->green
= t
->blue
= 0;
775 case COL_RED
: /* actually dark red */
777 t
->green
= t
->blue
= 0;
779 case COL_GREEN
: /* actually dark green */
781 t
->red
= t
->blue
= 0;
783 case COL_YELLOW
: /* actually dark yellow */
785 t
->red
= t
->green
= 255;
787 case COL_BLUE
: /* actually dark blue */
789 t
->red
= t
->green
= 0;
791 case COL_MAGENTA
: /* actually dark magenta */
793 t
->red
= t
->blue
= 255;
795 case COL_CYAN
: /* actually dark cyan */
797 t
->green
= t
->blue
= 255;
799 case COL_WHITE
: /* actually light gray */
800 t
->red
= t
->green
= t
->blue
= 255;
803 /* this will just be a string match */
804 t
->red
= t
->green
= t
->blue
= 256+i
;
810 for(i
= 0, t
= ct
; t
&& i
< count
; i
++, t
++){
811 t
->rgb
= (char *)fs_get((RGBLEN
+1) * sizeof(char));
812 if(COL_TRANS() && i
== count
-1)
813 snprintf(t
->rgb
, RGBLEN
+1, MATCH_TRAN_COLOR
);
815 snprintf(t
->rgb
, RGBLEN
+1, "%3.3d,%3.3d,%3.3d", t
->red
, t
->green
, t
->blue
);
824 add_to_color_name_list(struct color_table
*t
, char *name
)
826 if(t
&& name
&& *name
){
827 struct color_name_list
*new_name
;
829 new_name
= (struct color_name_list
*) fs_get(sizeof(struct color_name_list
));
831 memset(new_name
, 0, sizeof(*new_name
));
832 new_name
->namelen
= strlen(name
);
834 new_name
->name
= (char *) fs_get((new_name
->namelen
+1) * sizeof(char));
836 strncpy(new_name
->name
, name
, new_name
->namelen
+1);
837 new_name
->name
[new_name
->namelen
] = '\0';
840 struct color_name_list
*nl
;
841 for(nl
= t
->names
; nl
->next
; nl
= nl
->next
)
855 free_color_name_list(struct color_name_list
**nl
)
859 free_color_name_list(&(*nl
)->next
);
862 fs_give((void **) &(*nl
)->name
);
864 fs_give((void **) nl
);
870 * Map from integer color value to canonical color name.
875 struct color_table
*ct
;
876 static char cbuf
[12];
878 /* before we get set up, we still need to use this a bit */
898 snprintf(cbuf
, sizeof(cbuf
), "color%3.3d", color
);
903 for(ct
= color_tbl
; ct
->names
; ct
++)
907 /* rgb _is_ the canonical name */
911 /* not supposed to get here */
912 snprintf(cbuf
, sizeof(cbuf
), "color%3.3d", color
);
918 * Argument is a color name which could be an RGB string, a name like "blue",
919 * or a name like "color011".
921 * Returns a pointer to the canonical name of the color.
924 color_to_canonical_name(char *s
)
926 struct color_table
*ct
;
927 struct color_name_list
*nl
;
933 if(*s
== ' ' || isdigit(*s
)){
934 /* check for rgb string instead of name */
935 for(ct
= color_tbl
; ct
->rgb
; ct
++)
936 if(!strncmp(ct
->rgb
, s
, RGBLEN
))
940 for(done
=0, ct
= color_tbl
; !done
&& ct
->names
; ct
++){
941 for(nl
= ct
->names
; !done
&& nl
; nl
= nl
->next
)
942 if(nl
->name
&& !struncmp(nl
->name
, s
, nl
->namelen
))
950 /* rgb is the canonical name */
953 else if(!struncmp(s
, MATCH_NORM_COLOR
, RGBLEN
) || !struncmp(s
, MATCH_NONE_COLOR
, RGBLEN
))
961 * Argument is the name of a color or an RGB value that we recognize.
962 * The table should be set up so that the val returned is the same whether
963 * or not we choose the canonical name.
965 * Returns the integer value for the color.
968 color_to_val(char *s
)
970 struct color_table
*ct
;
971 struct color_name_list
*nl
;
977 if(*s
== ' ' || isdigit(*s
)){
978 /* check for rgb string instead of name */
979 for(ct
= color_tbl
; ct
->rgb
; ct
++)
980 if(!strncmp(ct
->rgb
, s
, RGBLEN
))
984 * Didn't match any. Find "closest" to match.
987 int r
= -1, g
= -1, b
= -1;
988 char *p
, *comma
, scopy
[RGBLEN
+1];
990 strncpy(scopy
, s
, sizeof(scopy
));
991 scopy
[sizeof(scopy
)-1] = '\0';
994 comma
= strchr(p
, ',');
999 if(r
>= 0 && r
<= 255 && *p
){
1000 comma
= strchr(p
, ',');
1005 if(g
>= 0 && g
<= 255 && *p
){
1012 if(r
>= 0 && r
<= 255 && g
>= 0 && g
<= 255 && b
>= 0 && b
<= 255){
1013 struct color_table
*closest
= NULL
;
1014 int closest_value
= 1000000;
1017 for(ct
= color_tbl
; ct
->rgb
; ct
++){
1019 if(ct
->red
>= 0 && ct
->red
<= 255
1020 && ct
->green
>= 0 && ct
->green
<= 255
1021 && ct
->blue
>= 0 && ct
->blue
<= 255){
1022 cv
= (ct
->red
- r
) * (ct
->red
- r
) +
1023 (ct
->green
- g
) * (ct
->green
- g
) +
1024 (ct
->blue
- b
) * (ct
->blue
- b
);
1025 if(cv
< closest_value
){
1038 for(done
=0, ct
= color_tbl
; !done
&& ct
->names
; ct
++){
1039 for(nl
= ct
->names
; !done
&& nl
; nl
= nl
->next
)
1040 if(nl
->name
&& !struncmp(nl
->name
, s
, nl
->namelen
))
1056 free_color_table(struct color_table
**ctbl
)
1058 struct color_table
*t
;
1061 for(t
= *ctbl
; t
->names
; t
++){
1062 free_color_name_list(&t
->names
);
1065 fs_give((void **) &t
->rgb
);
1068 fs_give((void **) ctbl
);
1074 pico_count_in_color_table(void)
1078 ? (ANSI8_COLOR() ? 8 : ANSI16_COLOR() ? 16 : 256)
1085 pico_nfcolor(char *s
)
1088 fs_give((void **) &_nfcolor
);
1094 _nfcolor
= (char *) fs_get((len
+1) * sizeof(char));
1096 strncpy(_nfcolor
, s
, len
+1);
1097 _nfcolor
[len
] = '\0';
1100 if(the_normal_color
){
1101 strncpy(the_normal_color
->fg
, _nfcolor
, MAXCOLORLEN
+1);
1102 the_normal_color
->fg
[MAXCOLORLEN
] = '\0';
1105 else if(the_normal_color
)
1106 free_color_pair(&the_normal_color
);
1111 pico_nbcolor(char *s
)
1114 fs_give((void **) &_nbcolor
);
1120 _nbcolor
= (char *) fs_get((len
+1) * sizeof(char));
1122 strncpy(_nbcolor
, s
, len
+1);
1123 _nbcolor
[len
] = '\0';
1126 if(the_normal_color
){
1127 strncpy(the_normal_color
->bg
, _nbcolor
, MAXCOLORLEN
+1);
1128 the_normal_color
->bg
[MAXCOLORLEN
] = '\0';
1131 else if(the_normal_color
)
1132 free_color_pair(&the_normal_color
);
1136 pico_rfcolor(char *s
)
1139 fs_give((void **) &_rfcolor
);
1145 _rfcolor
= (char *) fs_get((len
+1) * sizeof(char));
1147 strncpy(_rfcolor
, s
, len
+1);
1148 _rfcolor
[len
] = '\0';
1152 strncpy(the_rev_color
->fg
, _rfcolor
, MAXCOLORLEN
+1);
1153 the_rev_color
->fg
[MAXCOLORLEN
] = '\0';
1156 else if(the_rev_color
)
1157 free_color_pair(&the_rev_color
);
1161 pico_rbcolor(char *s
)
1164 fs_give((void **) &_rbcolor
);
1170 _rbcolor
= (char *) fs_get((len
+1) * sizeof(char));
1172 strncpy(_rbcolor
, s
, len
+1);
1173 _rbcolor
[len
] = '\0';
1177 strncpy(the_rev_color
->bg
, _rbcolor
, MAXCOLORLEN
+1);
1178 the_rev_color
->bg
[MAXCOLORLEN
] = '\0';
1181 else if(the_rev_color
)
1182 free_color_pair(&the_rev_color
);
1192 return(_color_inited
);
1197 pico_usingcolor(void)
1199 return(_using_color
&& pico_hascolor());
1204 * This should only be called when we're using the
1205 * unix termdef color, as opposed to the ANSI defined
1206 * color stuff or the Windows stuff.
1209 pico_trans_color(void)
1211 return(_bce
&& _op
);
1216 pico_toggle_color(int on
)
1227 free_color_table(&color_tbl
);
1230 putpad("\033[39;49m");
1243 pico_get_color_options(void)
1245 return(color_options
);
1250 pico_trans_is_on(void)
1252 return(COL_TRANS());
1257 * Absolute set of options. Caller has to OR things together and so forth.
1260 pico_set_color_options(unsigned flags
)
1262 color_options
= flags
;
1268 pico_toggle_color(0);
1273 fs_give((void **) &_nfcolor
);
1276 fs_give((void **) &_nbcolor
);
1279 fs_give((void **) &_rfcolor
);
1282 fs_give((void **) &_rbcolor
);
1285 fs_give((void **) &_last_fg_color
);
1288 fs_give((void **) &_last_bg_color
);
1291 free_color_pair(&the_rev_color
);
1293 if(the_normal_color
)
1294 free_color_pair(&the_normal_color
);
1299 pico_set_nfg_color(void)
1302 (void)pico_set_fg_color(_nfcolor
);
1307 pico_set_nbg_color(void)
1310 (void)pico_set_bg_color(_nbcolor
);
1315 pico_set_normal_color(void)
1317 if(!_nfcolor
|| !_nbcolor
||
1318 !pico_set_fg_color(_nfcolor
) || !pico_set_bg_color(_nbcolor
)){
1319 (void)pico_set_fg_color(DEFAULT_NORM_FORE_RGB
);
1320 (void)pico_set_bg_color(DEFAULT_NORM_BACK_RGB
);
1326 * If inverse is a color, returns a pointer to that color.
1327 * If not, returns NULL.
1329 * NOTE: Don't free this!
1332 pico_get_rev_color(void)
1334 if(pico_usingcolor() && _rfcolor
&& _rbcolor
&&
1335 pico_is_good_color(_rfcolor
) && pico_is_good_color(_rbcolor
)){
1337 the_rev_color
= new_color_pair(_rfcolor
, _rbcolor
);
1339 return(the_rev_color
);
1347 * Returns a pointer to the normal color.
1349 * NOTE: Don't free this!
1352 pico_get_normal_color(void)
1354 if(pico_usingcolor() && _nfcolor
&& _nbcolor
&&
1355 pico_is_good_color(_nfcolor
) && pico_is_good_color(_nbcolor
)){
1356 if(!the_normal_color
)
1357 the_normal_color
= new_color_pair(_nfcolor
, _nbcolor
);
1359 return(the_normal_color
);
1367 * Sets color to (fg,bg).
1368 * Flags == PSC_NONE No alternate default if fg,bg fails.
1369 * == PSC_NORM Set it to Normal color on failure.
1370 * == PSC_REV Set it to Reverse color on failure.
1372 * If flag PSC_RET is set, returns an allocated copy of the previous
1373 * color pair, otherwise returns NULL.
1376 pico_set_colors(char *fg
, char *bg
, int flags
)
1379 COLOR_PAIR
*cp
= NULL
, *rev
= NULL
;
1382 cp
= pico_get_cur_color();
1384 if(fg
&& !strcmp(fg
, END_PSEUDO_REVERSE
)){
1387 free_color_pair(&cp
);
1389 else if(!((uc
=pico_usingcolor()) && fg
&& bg
&&
1390 pico_set_fg_color(fg
) && pico_set_bg_color(bg
))){
1392 if(uc
&& flags
& PSC_NORM
)
1393 pico_set_normal_color();
1394 else if(flags
& PSC_REV
){
1395 if((rev
= pico_get_rev_color()) != NULL
){
1396 pico_set_fg_color(rev
->fg
); /* these will succeed */
1397 pico_set_bg_color(rev
->bg
);
1402 strncpy(cp
->fg
, END_PSEUDO_REVERSE
, MAXCOLORLEN
+1);
1403 cp
->fg
[MAXCOLORLEN
] = '\0';
1404 strncpy(cp
->bg
, END_PSEUDO_REVERSE
, MAXCOLORLEN
+1);
1405 cp
->bg
[MAXCOLORLEN
] = '\0';
1416 pico_is_good_color(char *s
)
1418 struct color_table
*ct
;
1419 struct color_name_list
*nl
;
1422 if(!s
|| !color_tbl
)
1425 if(!strcmp(s
, END_PSEUDO_REVERSE
))
1427 else if(!struncmp(s
, MATCH_NORM_COLOR
, RGBLEN
) || !struncmp(s
, MATCH_NONE_COLOR
, RGBLEN
))
1429 else if(*s
== ' ' || isdigit(*s
)){
1430 /* check for rgb string instead of name */
1431 for(ct
= color_tbl
; ct
->rgb
; ct
++)
1432 if(!strncmp(ct
->rgb
, s
, RGBLEN
))
1435 /* if no match it's still ok if rgb */
1437 int r
= -1, g
= -1, b
= -1;
1438 char *p
, *comma
, scopy
[RGBLEN
+1];
1440 strncpy(scopy
, s
, sizeof(scopy
));
1441 scopy
[sizeof(scopy
)-1] = '\0';
1444 comma
= strchr(p
, ',');
1449 if(r
>= 0 && r
<= 255 && *p
){
1450 comma
= strchr(p
, ',');
1455 if(g
>= 0 && g
<= 255 && *p
){
1462 if(r
>= 0 && r
<= 255 && g
>= 0 && g
<= 255 && b
>= 0 && b
<= 255)
1463 ct
= color_tbl
; /* to force TRUE */
1467 for(done
=0, ct
= color_tbl
; !done
&& ct
->names
; ct
++){
1468 for(nl
= ct
->names
; !done
&& nl
; nl
= nl
->next
)
1469 if(nl
->name
&& !struncmp(nl
->name
, s
, nl
->namelen
))
1477 return(ct
->names
? TRUE
: FALSE
);
1482 * Return TRUE on success.
1485 pico_set_fg_color(char *s
)
1489 if(!s
|| !color_tbl
)
1492 if(!strcmp(s
, END_PSEUDO_REVERSE
)){
1497 if(!struncmp(s
, MATCH_NORM_COLOR
, RGBLEN
))
1499 else if(!struncmp(s
, MATCH_NONE_COLOR
, RGBLEN
))
1502 if((val
= color_to_val(s
)) >= 0){
1506 changed
= !_last_fg_color
|| strcmp(_last_fg_color
,colorx(val
));
1508 /* already set correctly */
1509 if(!_force_fg_color_change
&& !changed
)
1512 _force_fg_color_change
= 0;
1516 fs_give((void **) &_last_fg_color
);
1518 len
= strlen(colorx(val
));
1519 if((_last_fg_color
= (char *) fs_get((len
+1) * sizeof(char))) != NULL
){
1520 strncpy(_last_fg_color
, colorx(val
), len
+1);
1521 _last_fg_color
[len
] = '\0';
1534 pico_set_bg_color(char *s
)
1538 if(!s
|| !color_tbl
)
1541 if(!strcmp(s
, END_PSEUDO_REVERSE
)){
1546 if(!struncmp(s
, MATCH_NORM_COLOR
, RGBLEN
))
1548 else if(!struncmp(s
, MATCH_NONE_COLOR
, RGBLEN
))
1551 if((val
= color_to_val(s
)) >= 0){
1555 changed
= !_last_bg_color
|| strcmp(_last_bg_color
,colorx(val
));
1557 /* already set correctly */
1558 if(!_force_bg_color_change
&& !changed
)
1561 _force_bg_color_change
= 0;
1565 fs_give((void **) &_last_bg_color
);
1567 len
= strlen(colorx(val
));
1568 if((_last_bg_color
= (char *) fs_get((len
+1) * sizeof(char))) != NULL
){
1569 strncpy(_last_bg_color
, colorx(val
), len
+1);
1570 _last_bg_color
[len
] = '\0';
1583 * Return a pointer to an rgb string for the input color. The output is 11
1584 * characters long and looks like rrr,ggg,bbb.
1586 * Args colorName -- The color to convert to ascii rgb.
1588 * Returns Pointer to a static buffer containing the rgb string. Can use up
1589 * to three returned values at once before the first is overwritten.
1592 color_to_asciirgb(char *colorName
)
1594 static char c_to_a_buf
[3][RGBLEN
+1];
1595 static int whichbuf
= 0;
1596 struct color_table
*ct
;
1597 struct color_name_list
*nl
;
1600 whichbuf
= (whichbuf
+ 1) % 3;
1602 c_to_a_buf
[whichbuf
][0] = '\0';
1604 for(done
=0, ct
= color_tbl
; !done
&& ct
->names
; ct
++){
1605 for(nl
= ct
->names
; !done
&& nl
; nl
= nl
->next
)
1606 if(nl
->name
&& !struncmp(nl
->name
, colorName
, nl
->namelen
))
1613 if(ct
&& ct
->names
){
1614 strncpy(c_to_a_buf
[whichbuf
], ct
->rgb
, sizeof(c_to_a_buf
[0]));
1615 c_to_a_buf
[whichbuf
][sizeof(c_to_a_buf
[0])-1] = '\0';
1617 else if(*colorName
== ' ' || isdigit(*colorName
)){
1618 /* check for rgb string instead of name */
1619 for(ct
= color_tbl
; ct
->rgb
; ct
++)
1620 if(!strncmp(ct
->rgb
, colorName
, RGBLEN
))
1623 /* if no match it's still ok if rgb */
1625 int r
= -1, g
= -1, b
= -1;
1626 char *p
, *comma
, scopy
[RGBLEN
+1];
1628 strncpy(scopy
, colorName
, sizeof(scopy
));
1629 scopy
[sizeof(scopy
)-1] = '\0';
1632 comma
= strchr(p
, ',');
1637 if(r
>= 0 && r
<= 255 && *p
){
1638 comma
= strchr(p
, ',');
1643 if(g
>= 0 && g
<= 255 && *p
){
1650 if(r
>= 0 && r
<= 255 && g
>= 0 && g
<= 255 && b
>= 0 && b
<= 255){
1651 /* it was already RGB */
1652 snprintf(c_to_a_buf
[whichbuf
], sizeof(c_to_a_buf
[0]), "%3.3d,%3.3d,%3.3d", r
, g
, b
);
1656 strncpy(c_to_a_buf
[whichbuf
], ct
->rgb
, sizeof(c_to_a_buf
[0]));
1657 c_to_a_buf
[whichbuf
][sizeof(c_to_a_buf
[0])-1] = '\0';
1661 if(!c_to_a_buf
[whichbuf
][0]){
1665 * If we didn't find the color it could be that it is the
1666 * normal color (MATCH_NORM_COLOR) or the none color
1667 * (MATCH_NONE_COLOR). If that is the case, this strncpy thing
1668 * will work out correctly because those two strings are
1669 * RGBLEN long. Otherwise we're in a bit of trouble. This
1670 * most likely means that the user is using the same pinerc on
1671 * two terminals, one with more colors than the other. We didn't
1672 * find a match because this color isn't present on this terminal.
1673 * Since the return value of this function is assumed to be
1674 * RGBLEN long, we'd better make it that long.
1675 * It still won't work correctly because colors will be screwed up,
1676 * but at least the embedded colors in filter.c will get properly
1677 * sucked up when they're encountered.
1679 strcpy(c_to_a_buf
[whichbuf
], "xxxxxxxxxxx");
1680 l
= strlen(colorName
);
1681 strncpy(c_to_a_buf
[whichbuf
], colorName
, (l
< RGBLEN
) ? l
: RGBLEN
);
1682 c_to_a_buf
[whichbuf
][RGBLEN
] = '\0';
1685 return(c_to_a_buf
[whichbuf
]);
1690 pico_get_last_fg_color(void)
1697 len
= strlen(_last_fg_color
);
1698 if((ret
= (char *) fs_get((len
+1) * sizeof(char))) != NULL
){
1699 strncpy(ret
, _last_fg_color
, len
+1);
1709 pico_get_last_bg_color(void)
1716 len
= strlen(_last_bg_color
);
1717 if((ret
= (char *) fs_get((len
+1) * sizeof(char))) != NULL
){
1718 strncpy(ret
, _last_bg_color
, len
+1);
1728 pico_get_cur_color(void)
1730 return(new_color_pair(_last_fg_color
, _last_bg_color
));
1733 #else /* _WINDOWS */
1734 static short _in_inverse
, _in_bold
, _in_uline
;
1737 pico_trans_is_on(void)
1746 mswin_rev(_in_inverse
= 1);
1753 mswin_rev(_in_inverse
= 0);
1759 return(_in_inverse
);
1766 mswin_uline(_in_uline
= 1);
1773 mswin_uline(_in_uline
= 0);
1780 mswin_bold(_in_bold
= 1);
1789 mswin_bold(_in_bold
= 0);
1793 #endif /* _WINDOWS */