/* character level styles for Lynx * (c) 1996 Rob Partington -- donated to the Lyncei (if they want it :-) * @Id: LYStyle.c 1.50 Sun, 06 Oct 2002 17:43:28 -0700 dickey @ */ #include #include #include #include #include #include #include #include /* defines TABLESIZE */ #include #include #include /* Hash table definitions */ #include #include #include #include #include #ifdef USE_COLOR_STYLE PRIVATE void style_initialiseHashTable NOPARAMS; /* stack of attributes during page rendering */ PUBLIC int last_styles[128]; PUBLIC int last_colorattr_ptr = 0; PUBLIC bucket hashStyles[CSHASHSIZE]; PUBLIC bucket special_bucket = { "", /* in order something to be in trace. */ 0, 0, 0, 0, NULL }; PUBLIC bucket nostyle_bucket = { "", /* in order something to be in trace. */ 0, 0, 0, 0, NULL }; PUBLIC int cached_tag_styles[HTML_ELEMENTS]; PUBLIC int current_tag_style; PUBLIC BOOL force_current_tag_style = FALSE; PUBLIC char* forced_classname; PUBLIC BOOL force_classname; /* Remember the hash codes for common elements */ PUBLIC int s_a = NOSTYLE; PUBLIC int s_aedit = NOSTYLE; PUBLIC int s_aedit_arr = NOSTYLE; PUBLIC int s_aedit_pad = NOSTYLE; PUBLIC int s_aedit_sel = NOSTYLE; PUBLIC int s_alert = NOSTYLE; PUBLIC int s_alink = NOSTYLE; PUBLIC int s_curedit = NOSTYLE; PUBLIC int s_forw_backw = NOSTYLE; PUBLIC int s_normal = NOSTYLE; PUBLIC int s_prompt_edit = NOSTYLE; PUBLIC int s_prompt_edit_arr = NOSTYLE; PUBLIC int s_prompt_edit_pad = NOSTYLE; PUBLIC int s_prompt_sel = NOSTYLE; PUBLIC int s_status = NOSTYLE; PUBLIC int s_title = NOSTYLE; PUBLIC int s_whereis = NOSTYLE; PUBLIC int s_menu_frame = NOSTYLE; PUBLIC int s_menu_bg = NOSTYLE; PUBLIC int s_menu_number = NOSTYLE; PUBLIC int s_menu_entry = NOSTYLE; PUBLIC int s_menu_active = NOSTYLE; PUBLIC int s_menu_sb = NOSTYLE; #ifdef USE_SCROLLBAR PUBLIC int s_sb_aa = NOSTYLE; PUBLIC int s_sb_bar = NOSTYLE; PUBLIC int s_sb_bg = NOSTYLE; PUBLIC int s_sb_naa = NOSTYLE; #endif /* start somewhere safe */ #define MAX_COLOR 16 PRIVATE int colorPairs = 0; #ifdef USE_BLINK # define MAX_BLINK 2 # define M_BLINK A_BLINK #else # define MAX_BLINK 1 # define M_BLINK 0 #endif PRIVATE unsigned char our_pairs[2] [MAX_BLINK] [MAX_COLOR + 1] [MAX_COLOR + 1]; /* * Parse a string containing a combination of video attributes and color. */ PRIVATE void parse_either ARGS4( char *, attrs, int, dft_color, int *, monop, int *, colorp) { int value; while (*attrs != '\0') { char *next = strchr(attrs, '+'); char save = (next != NULL) ? *next : '\0'; if (next == NULL) next = attrs + strlen(attrs); if (save != 0) /* attrs might be a constant string */ *next = '\0'; if ((value = string_to_attr(attrs)) != 0) *monop |= value; else if (colorp != 0 && (value = check_color(attrs, dft_color)) != ERR_COLOR) *colorp = value; attrs = next; if (save != '\0') *attrs++ = save; } } /* icky parsing of the style options */ PRIVATE void parse_attributes ARGS5( char *, mono, char *, fg, char *, bg, int, style, char *, element) { int mA = A_NORMAL; int fA = default_fg; int bA = default_bg; int cA = A_NORMAL; int newstyle = hash_code(element); CTRACE2(TRACE_STYLE, (tfp, "CSS(PA):style d=%d / h=%d, e=%s\n", style, newstyle, element)); parse_either(mono, ERR_COLOR, &mA, (int *)0); parse_either(bg, default_bg, &cA, &bA); parse_either(fg, default_fg, &cA, &fA); if (style == -1) { /* default */ CTRACE2(TRACE_STYLE, (tfp, "CSS(DEF):default_fg=%d, default_bg=%d\n", fA, bA)); default_fg = fA; default_bg = bA; default_color_reset = TRUE; return; } if (fA == NO_COLOR) { bA = NO_COLOR; } else if (COLORS) { #ifdef USE_BLINK if (term_blink_is_boldbg) { if (fA >= COLORS) cA = A_BOLD; if (bA >= COLORS) cA |= M_BLINK; } else #endif if (fA >= COLORS || bA >= COLORS) cA = A_BOLD; if (fA >= COLORS) fA %= COLORS; if (bA >= COLORS) bA %= COLORS; } else { cA = A_BOLD; fA = NO_COLOR; bA = NO_COLOR; } /* * If we have colour, and space to create a new colour attribute, * and we have a valid colour description, then add this style */ if (lynx_has_color && colorPairs < COLOR_PAIRS-1 && fA != NO_COLOR) { int curPair = 0; int iFg = (1 + (fA >= 0 ? fA : 0)); int iBg = (1 + (bA >= 0 ? bA : 0)); int iBold = !!(cA & A_BOLD); int iBlink = !!(cA & M_BLINK); if (fA < MAX_COLOR && bA < MAX_COLOR && (fA != default_fg || bA != default_bg) && curPair < 255) { if (our_pairs[iBold][iBlink][iFg][iBg] != 0) { curPair = our_pairs[iBold][iBlink][iFg][iBg]; } else { curPair = ++colorPairs; init_pair((short)curPair, (short)fA, (short)bA); our_pairs[iBold][iBlink][iFg][iBg] = curPair; } } CTRACE2(TRACE_STYLE, (tfp, "CSS(CURPAIR):%d\n", curPair)); if (style < DSTYLE_ELEMENTS) setStyle(style, COLOR_PAIR(curPair)|cA, cA, mA); setHashStyle(newstyle, COLOR_PAIR(curPair)|cA, cA, mA, element); } else { if (lynx_has_color && fA != NO_COLOR) { CTRACE2(TRACE_STYLE, (tfp, "CSS(NC): maximum of %d colorpairs exhausted\n", COLOR_PAIRS - 1)); } /* only mono is set */ if (style < DSTYLE_ELEMENTS) setStyle(style, -1, -1, mA); setHashStyle(newstyle, -1, -1, mA, element); } } /* parse a style option of the format * STYLE::FG:BG */ PRIVATE void parse_style ARGS1(char*, param) { static struct { char *name; int style; int *set_hash; } table[] = { { "default", -1, 0 }, /* default fg/bg */ { "alink", DSTYLE_ALINK, 0 }, /* active link */ { "a", DSTYLE_LINK, 0 }, /* normal link */ { "a", HTML_A, 0 }, /* normal link */ { "status", DSTYLE_STATUS, 0 }, /* status bar */ { "label", DSTYLE_OPTION, 0 }, /* [INLINE]'s */ { "value", DSTYLE_VALUE, 0 }, /* [INLINE]'s */ { "high", DSTYLE_HIGH, 0 }, /* [INLINE]'s */ { "normal", DSTYLE_NORMAL, 0 }, { "candy", DSTYLE_CANDY, 0 }, /* [INLINE]'s */ { "whereis", DSTYLE_WHEREIS, &s_whereis }, { "edit.active.pad", DSTYLE_ELEMENTS, &s_aedit_pad }, { "edit.active.arrow", DSTYLE_ELEMENTS, &s_aedit_arr }, { "edit.active.marked", DSTYLE_ELEMENTS, &s_aedit_sel }, { "edit.active", DSTYLE_ELEMENTS, &s_aedit }, { "edit.current", DSTYLE_ELEMENTS, &s_curedit }, { "edit.prompt.pad", DSTYLE_ELEMENTS, &s_prompt_edit_pad }, { "edit.prompt.arrow", DSTYLE_ELEMENTS, &s_prompt_edit_arr }, { "edit.prompt.marked", DSTYLE_ELEMENTS, &s_prompt_sel }, { "edit.prompt", DSTYLE_ELEMENTS, &s_prompt_edit }, { "forwbackw.arrow", DSTYLE_ELEMENTS, &s_forw_backw }, { "menu.frame", DSTYLE_ELEMENTS, &s_menu_frame }, { "menu.bg", DSTYLE_ELEMENTS, &s_menu_bg }, { "menu.n", DSTYLE_ELEMENTS, &s_menu_number }, { "menu.entry", DSTYLE_ELEMENTS, &s_menu_entry }, { "menu.active", DSTYLE_ELEMENTS, &s_menu_active }, { "menu.sb", DSTYLE_ELEMENTS, &s_menu_sb }, }; unsigned n; BOOL found = FALSE; char *buffer = 0; char *tmp = 0; char *element, *mono, *fg, *bg; if (param == 0) return; StrAllocCopy(buffer, param); if (buffer == 0) return; if ((tmp = strchr(buffer, ':')) == 0) { fprintf (stderr, gettext("\ Syntax Error parsing style in lss file:\n\ [%s]\n\ The line must be of the form:\n\ OBJECT:MONO:COLOR (ie em:bold:brightblue:white)\n\ where OBJECT is one of EM,STRONG,B,I,U,BLINK etc.\n\n"), buffer); if (!dump_output_immediately) { exit_immediately(EXIT_FAILURE); } exit(1); } strtolower(buffer); *tmp = '\0'; element = buffer; mono = tmp + 1; tmp = strchr(mono, ':'); if (!tmp) { fg = "nocolor"; bg = "nocolor"; } else { *tmp = '\0'; fg = tmp+1; tmp = strchr(fg, ':'); if (!tmp) bg = "default"; else { *tmp = '\0'; bg = tmp + 1; } } CTRACE2(TRACE_STYLE, (tfp, "CSSPARSE:%s => %d %s\n", element, hash_code(element), (hashStyles[hash_code(element)].name ? "used" : ""))); strtolower(element); /* * We use some pseudo-elements, so catch these first */ for (n = 0; n < TABLESIZE(table); n++) { if (!strcasecomp(element, table[n].name)) { parse_attributes(mono, fg, bg, table[n].style, table[n].name); if (table[n].set_hash != 0) *(table[n].set_hash) = hash_code(table[n].name); found = TRUE; break; } } if (found) { ; } else if (!strcasecomp(element, "normal")) /* added - kw */ { parse_attributes(mono,fg,bg,DSTYLE_NORMAL,"html"); s_normal = hash_code("html"); /* rather bizarre... - kw */ } /* Ok, it must be a HTML element, so look through the list until we * find it */ else { int element_number = -1; HTTag * t = SGMLFindTag(&HTML_dtd, element); if (t && t->name) { element_number = t - HTML_dtd.tags; } if (element_number >= HTML_A && element_number < HTML_ELEMENTS) parse_attributes(mono,fg,bg, element_number+STARTAT,element); else parse_attributes(mono,fg,bg, DSTYLE_ELEMENTS,element); } FREE(buffer); } #ifdef LY_FIND_LEAKS PRIVATE void free_colorstylestuff NOARGS { style_initialiseHashTable(); style_deleteStyleList(); } #endif /* * initialise the default style sheet * This should be able to be read from a file in CSS format :-) */ PRIVATE void initialise_default_stylesheet NOARGS { static CONST char *table[] = { "a:bold:green", "alert:bold:yellow:red", "alink:reverse:yellow:black", "label:normal:magenta", "status:reverse:yellow:blue", "title:normal:magenta", "whereis:reverse+underline:magenta:cyan" }; unsigned n; char temp[80]; CTRACE((tfp, "initialize_default_stylesheet\n")); for (n = 0; n < TABLESIZE(table); n++) { parse_style(strcpy(temp, table[n])); } } /* Set all the buckets in the hash table to be empty */ PRIVATE void style_initialiseHashTable NOARGS { int i; static int firsttime = 1; for (i = 0; i 0) HStyle_addStyle(buffer); } LYCloseInput (fh); if ((parent_filename == 0) && LYCursesON) parse_userstyles(); return 0; } PUBLIC int style_readFromFile ARGS1(char*, filename) { return style_readFromFileREC(filename, (char *)0); } /* Used in HTStructured methods: - kw */ PUBLIC void TrimColorClass ARGS3( CONST char *, tagname, char *, styleclassname, int *, phcode) { char *end, *start=NULL, *lookfrom; char tmp[64]; sprintf(tmp, ";%.*s", (int) sizeof(tmp) - 3, tagname); strtolower(tmp); if ((lookfrom = styleclassname) != 0) { do { end = start; start = strstr(lookfrom, tmp); if (start) lookfrom = start + 1; } while (start); /* trim the last matching element off the end ** - should match classes here as well (rp) */ if (end) *end='\0'; } *phcode = hash_code(lookfrom && *lookfrom ? lookfrom : &tmp[1]); } /* This function is designed as faster analog to TrimColorClass. It assumes that tag_name is present in stylename! -HV */ PUBLIC void FastTrimColorClass ARGS5 ( CONST char*, tag_name, int, name_len, char*, stylename, char**, pstylename_end,/*will be modified*/ int*, phcode) /*will be modified*/ { char* tag_start = *pstylename_end; BOOLEAN found = FALSE; CTRACE2(TRACE_STYLE, (tfp, "STYLE.fast-trim: [%s] from [%s]: ", tag_name, stylename)); while (tag_start >= stylename) { for (; (tag_start >= stylename) && (*tag_start != ';') ; --tag_start) ; if ( !strncasecomp(tag_start+1, tag_name, name_len) ) { found = TRUE; break; } --tag_start; } if (found) { *tag_start = '\0'; *pstylename_end = tag_start; } CTRACE2(TRACE_STYLE, (tfp, found ? "success.\n" : "failed.\n")); *phcode = hash_code(tag_start+1); } /* This is called each time lss styles are read. It will fill each elt of 'cached_tag_styles' -HV */ PUBLIC void cache_tag_styles NOARGS { char buf[200]; int i; for (i = 0; i < HTML_ELEMENTS; ++i) { LYstrncpy(buf, HTML_dtd.tags[i].name, sizeof(buf)-1); LYLowerCase(buf); cached_tag_styles[i] = hash_code(buf); } } #endif /* USE_COLOR_STYLE */