1 /*
2 * $LynxId: LYStyle.c,v 1.73 2013/06/02 19:17:06 tom Exp $
3 *
4 * character level styles for Lynx
5 * (c) 1996 Rob Partington -- donated to the Lyncei (if they want it :-)
6 */
7 #include <HTUtils.h>
8 #include <HTML.h>
9 #include <LYGlobalDefs.h>
10
11 #include <LYStructs.h>
12 #include <LYReadCFG.h>
13 #include <LYCurses.h>
14 #include <LYCharUtils.h>
15 #include <LYUtils.h> /* defines TABLESIZE */
16 #include <AttrList.h>
17 #include <SGML.h>
18 #include <HTMLDTD.h>
19
20 /* Hash table definitions */
21 #include <LYHash.h>
22 #include <LYStyle.h>
23
24 #include <LYexit.h>
25 #include <LYLeaks.h>
26 #include <LYStrings.h>
27 #include <LYHash.h>
28
29 #define CTRACE1(p) CTRACE2(TRACE_CFG || TRACE_STYLE, p)
30
31 #ifdef USE_COLOR_STYLE
32
33 static void style_initialiseHashTable(void);
34
35 /* because curses isn't started when we parse the config file, we
36 * need to remember the STYLE: lines we encounter and parse them
37 * after curses has started
38 */
39 static HTList *lss_styles = NULL;
40
41 #define CACHEW 128
42 #define CACHEH 64
43
44 static unsigned *cached_styles_ptr = NULL;
45 static int cached_styles_rows = 0;
46 static int cached_styles_cols = 0;
47
48 /* stack of attributes during page rendering */
49 int last_styles[MAX_LAST_STYLES + 1] =
50 {0};
51 int last_colorattr_ptr = 0;
52
53 bucket hashStyles[CSHASHSIZE];
54
55 int cached_tag_styles[HTML_ELEMENTS];
56 int current_tag_style;
57 BOOL force_current_tag_style = FALSE;
58 char *forced_classname;
59 BOOL force_classname;
60
61 /* Remember the hash codes for common elements */
62 int s_a = NOSTYLE;
63 int s_aedit = NOSTYLE;
64 int s_aedit_arr = NOSTYLE;
65 int s_aedit_pad = NOSTYLE;
66 int s_aedit_sel = NOSTYLE;
67 int s_alert = NOSTYLE;
68 int s_alink = NOSTYLE;
69 int s_curedit = NOSTYLE;
70 int s_forw_backw = NOSTYLE;
71 int s_hot_paste = NOSTYLE;
72 int s_menu_active = NOSTYLE;
73 int s_menu_bg = NOSTYLE;
74 int s_menu_entry = NOSTYLE;
75 int s_menu_frame = NOSTYLE;
76 int s_menu_number = NOSTYLE;
77 int s_menu_sb = NOSTYLE;
78 int s_normal = NOSTYLE;
79 int s_prompt_edit = NOSTYLE;
80 int s_prompt_edit_arr = NOSTYLE;
81 int s_prompt_edit_pad = NOSTYLE;
82 int s_prompt_sel = NOSTYLE;
83 int s_status = NOSTYLE;
84 int s_title = NOSTYLE;
85 int s_whereis = NOSTYLE;
86
87 #ifdef USE_SCROLLBAR
88 int s_sb_aa = NOSTYLE;
89 int s_sb_bar = NOSTYLE;
90 int s_sb_bg = NOSTYLE;
91 int s_sb_naa = NOSTYLE;
92 #endif
93
94 /* start somewhere safe */
95 #define MAX_COLOR 16
96 static int colorPairs = 0;
97
98 #ifdef USE_BLINK
99 # define MAX_BLINK 2
100 # define M_BLINK A_BLINK
101 #else
102 # define MAX_BLINK 1
103 # define M_BLINK 0
104 #endif
105
106 #define MAX_PAIR 255 /* because our_pairs[] type is unsigned-char */
107 static unsigned char our_pairs[2]
108 [MAX_BLINK]
109 [MAX_COLOR + 1]
110 [MAX_COLOR + 1];
111
new_bucket(const char * name)112 static bucket *new_bucket(const char *name)
113 {
114 bucket *result = typecalloc(bucket);
115
116 if (!result)
117 outofmem(__FILE__, "new_bucket");
118 StrAllocCopy(result->name, name);
119 return result;
120 }
121
122 #if OMIT_SCN_KEEPING
special_bucket(void)123 bucket *special_bucket(void)
124 {
125 return new_bucket("<special>");
126 }
127 #endif
128
nostyle_bucket(void)129 bucket *nostyle_bucket(void)
130 {
131 return new_bucket("<NOSTYLE>");
132 }
133
TrimLowercase(char * buffer)134 static char *TrimLowercase(char *buffer)
135 {
136 LYRemoveBlanks(buffer);
137 strtolower(buffer);
138 return buffer;
139 }
140
141 /*
142 * Parse a string containing a combination of video attributes and color.
143 */
parse_either(const char * attrs,int dft_color,int * monop,int * colorp)144 static void parse_either(const char *attrs,
145 int dft_color,
146 int *monop,
147 int *colorp)
148 {
149 int value;
150 char *temp_attrs = NULL;
151
152 if (StrAllocCopy(temp_attrs, attrs) != NULL) {
153 char *to_free = temp_attrs;
154
155 while (*temp_attrs != '\0') {
156 char *next = strchr(temp_attrs, '+');
157 char save = (char) ((next != NULL) ? *next : '\0');
158
159 if (next == NULL)
160 next = temp_attrs + strlen(temp_attrs);
161
162 if (save != 0)
163 *next = '\0';
164 if ((value = string_to_attr(temp_attrs)) != 0)
165 *monop |= value;
166 else if (colorp != 0
167 && (value = check_color(temp_attrs, dft_color)) != ERR_COLOR)
168 *colorp = value;
169
170 temp_attrs = next;
171 if (save != '\0')
172 *temp_attrs++ = save;
173 }
174 FREE(to_free);
175 }
176 }
177
178 /* icky parsing of the style options */
parse_attributes(const char * mono,const char * fg,const char * bg,int style,const char * element)179 static void parse_attributes(const char *mono,
180 const char *fg,
181 const char *bg,
182 int style,
183 const char *element)
184 {
185 int mA = A_NORMAL;
186 int fA = default_fg;
187 int bA = default_bg;
188 int cA = A_NORMAL;
189 int newstyle = hash_code(element);
190
191 CTRACE2(TRACE_STYLE, (tfp, "CSS(PA):style d=%d / h=%d, e=%s\n",
192 style, newstyle, element));
193
194 parse_either(mono, ERR_COLOR, &mA, (int *) 0);
195 parse_either(bg, default_bg, &cA, &bA);
196 parse_either(fg, default_fg, &cA, &fA);
197
198 if (style == -1) { /* default */
199 CTRACE2(TRACE_STYLE, (tfp, "CSS(DEF):default_fg=%d, default_bg=%d\n",
200 fA, bA));
201 default_fg = fA;
202 default_bg = bA;
203 default_color_reset = TRUE;
204 return;
205 }
206 if (fA == NO_COLOR) {
207 bA = NO_COLOR;
208 } else if (COLORS) {
209 #ifdef USE_BLINK
210 if (term_blink_is_boldbg) {
211 if (fA >= COLORS)
212 cA = A_BOLD;
213 if (bA >= COLORS)
214 cA |= M_BLINK;
215 } else
216 #endif
217 if (fA >= COLORS || bA >= COLORS)
218 cA = A_BOLD;
219 if (fA >= COLORS)
220 fA %= COLORS;
221 if (bA >= COLORS)
222 bA %= COLORS;
223 } else {
224 cA = A_BOLD;
225 fA = NO_COLOR;
226 bA = NO_COLOR;
227 }
228
229 /*
230 * If we have colour, and space to create a new colour attribute,
231 * and we have a valid colour description, then add this style
232 */
233 if (lynx_has_color && colorPairs < COLOR_PAIRS - 1 && fA != NO_COLOR) {
234 int curPair = 0;
235 int iFg = (1 + (fA >= 0 ? fA : 0));
236 int iBg = (1 + (bA >= 0 ? bA : 0));
237 int iBold = !!((unsigned) cA & A_BOLD);
238 int iBlink = !!((unsigned) cA & M_BLINK);
239
240 CTRACE2(TRACE_STYLE, (tfp, "parse_attributes %d/%d %d/%d %#x\n",
241 fA, default_fg, bA, default_bg, cA));
242 if (fA < MAX_COLOR
243 && bA < MAX_COLOR
244 #ifdef USE_CURSES_PAIR_0
245 && (cA != A_NORMAL || fA != default_fg || bA != default_bg)
246 #endif
247 && curPair < MAX_PAIR) {
248 if (our_pairs[iBold][iBlink][iFg][iBg] != 0) {
249 curPair = our_pairs[iBold][iBlink][iFg][iBg];
250 } else {
251 curPair = ++colorPairs;
252 init_pair((short) curPair, (short) fA, (short) bA);
253 our_pairs[iBold][iBlink][iFg][iBg] = UCH(curPair);
254 }
255 }
256 CTRACE2(TRACE_STYLE, (tfp, "CSS(CURPAIR):%d\n", curPair));
257 if (style < DSTYLE_ELEMENTS)
258 setStyle(style, COLOR_PAIR(curPair) | cA, cA, mA);
259 setHashStyle(newstyle, COLOR_PAIR(curPair) | cA, cA, mA, element);
260 } else {
261 if (lynx_has_color && fA != NO_COLOR) {
262 CTRACE2(TRACE_STYLE,
263 (tfp, "CSS(NC): maximum of %d colorpairs exhausted\n",
264 COLOR_PAIRS - 1));
265 }
266 /* only mono is set */
267 if (style < DSTYLE_ELEMENTS)
268 setStyle(style, -1, -1, mA);
269 setHashStyle(newstyle, -1, -1, mA, element);
270 }
271 }
272
273 /* parse a style option of the format
274 * STYLE:<OBJECT>:FG:BG
275 */
parse_style(char * param)276 static void parse_style(char *param)
277 {
278 /* *INDENT-OFF* */
279 static struct {
280 const char *name;
281 int style;
282 int *set_hash;
283 } table[] = {
284 { "default", -1, 0 }, /* default fg/bg */
285 { "alink", DSTYLE_ALINK, 0 }, /* active link */
286 { "a", DSTYLE_LINK, 0 }, /* normal link */
287 { "a", HTML_A, 0 }, /* normal link */
288 { "status", DSTYLE_STATUS, 0 }, /* status bar */
289 { "label", DSTYLE_OPTION, 0 }, /* [INLINE]s */
290 { "value", DSTYLE_VALUE, 0 }, /* [INLINE]s */
291 { "normal", DSTYLE_NORMAL, 0 },
292 { "candy", DSTYLE_CANDY, 0 }, /* [INLINE]s */
293 { "whereis", DSTYLE_WHEREIS, &s_whereis },
294 { "edit.active.pad", DSTYLE_ELEMENTS, &s_aedit_pad },
295 { "edit.active.arrow", DSTYLE_ELEMENTS, &s_aedit_arr },
296 { "edit.active.marked", DSTYLE_ELEMENTS, &s_aedit_sel },
297 { "edit.active", DSTYLE_ELEMENTS, &s_aedit },
298 { "edit.current", DSTYLE_ELEMENTS, &s_curedit },
299 { "edit.prompt.pad", DSTYLE_ELEMENTS, &s_prompt_edit_pad },
300 { "edit.prompt.arrow", DSTYLE_ELEMENTS, &s_prompt_edit_arr },
301 { "edit.prompt.marked", DSTYLE_ELEMENTS, &s_prompt_sel },
302 { "edit.prompt", DSTYLE_ELEMENTS, &s_prompt_edit },
303 { "forwbackw.arrow", DSTYLE_ELEMENTS, &s_forw_backw },
304 { "hot.paste", DSTYLE_ELEMENTS, &s_hot_paste },
305 { "menu.frame", DSTYLE_ELEMENTS, &s_menu_frame },
306 { "menu.bg", DSTYLE_ELEMENTS, &s_menu_bg },
307 { "menu.n", DSTYLE_ELEMENTS, &s_menu_number },
308 { "menu.entry", DSTYLE_ELEMENTS, &s_menu_entry },
309 { "menu.active", DSTYLE_ELEMENTS, &s_menu_active },
310 { "menu.sb", DSTYLE_ELEMENTS, &s_menu_sb },
311 };
312 /* *INDENT-ON* */
313
314 unsigned n;
315 BOOL found = FALSE;
316
317 char *buffer = 0;
318 char *tmp = 0;
319 char *element, *mono;
320 const char *fg, *bg;
321
322 if (param == 0)
323 return;
324 CTRACE2(TRACE_STYLE, (tfp, "parse_style(%s)\n", param));
325 StrAllocCopy(buffer, param);
326 if (buffer == 0)
327 return;
328
329 TrimLowercase(buffer);
330 if ((tmp = strchr(buffer, ':')) == 0) {
331 fprintf(stderr, gettext("\
332 Syntax Error parsing style in lss file:\n\
333 [%s]\n\
334 The line must be of the form:\n\
335 OBJECT:MONO:COLOR (ie em:bold:brightblue:white)\n\
336 where OBJECT is one of EM,STRONG,B,I,U,BLINK etc.\n\n"), buffer);
337 exit_immediately(EXIT_FAILURE);
338 }
339 *tmp = '\0';
340 element = buffer;
341
342 mono = tmp + 1;
343 tmp = strchr(mono, ':');
344
345 if (!tmp) {
346 fg = "nocolor";
347 bg = "nocolor";
348 } else {
349 *tmp = '\0';
350 fg = tmp + 1;
351 tmp = strchr(fg, ':');
352 if (!tmp)
353 bg = "default";
354 else {
355 *tmp = '\0';
356 bg = tmp + 1;
357 }
358 }
359
360 CTRACE2(TRACE_STYLE, (tfp, "CSSPARSE:%s => %d %s\n",
361 element, hash_code(element),
362 (hashStyles[hash_code(element)].name ? "used" : "")));
363
364 /*
365 * We use some pseudo-elements, so catch these first
366 */
367 for (n = 0; n < TABLESIZE(table); n++) {
368 if (!strcasecomp(element, table[n].name)) {
369 parse_attributes(mono, fg, bg, table[n].style, table[n].name);
370 if (table[n].set_hash != 0)
371 *(table[n].set_hash) = hash_code(table[n].name);
372 found = TRUE;
373 break;
374 }
375 }
376
377 if (found) {
378 if (!strcasecomp(element, "normal")) {
379 /* added - kw */
380 parse_attributes(mono, fg, bg, DSTYLE_NORMAL, "html");
381 s_normal = hash_code("html"); /* rather bizarre... - kw */
382
383 LYnormalColor();
384 }
385 } else {
386 /* It must be a HTML element, so look through the list until we find it. */
387 int element_number = -1;
388 HTTag *t = SGMLFindTag(&HTML_dtd, element);
389
390 if (t && t->name) {
391 element_number = (int) (t - HTML_dtd.tags);
392 }
393 if (element_number >= HTML_A &&
394 element_number < HTML_ELEMENTS) {
395 parse_attributes(mono, fg, bg, element_number + STARTAT, element);
396 } else {
397 parse_attributes(mono, fg, bg, DSTYLE_ELEMENTS, element);
398 }
399 }
400 FREE(buffer);
401 }
402
style_deleteStyleList(void)403 static void style_deleteStyleList(void)
404 {
405 LYFreeStringList(lss_styles);
406 lss_styles = NULL;
407 }
408
free_colorstylestuff(void)409 static void free_colorstylestuff(void)
410 {
411 style_initialiseHashTable();
412 style_deleteStyleList();
413 memset(our_pairs, 0, sizeof(our_pairs));
414 FreeCachedStyles();
415 }
416
417 /*
418 * Initialise the default style sheet to match the vanilla-curses lynx.
419 */
initialise_default_stylesheet(void)420 static void initialise_default_stylesheet(void)
421 {
422 /* Use the data setup in USE_COLOR_TABLE */
423 /* *INDENT-OFF* */
424 static const struct {
425 int color; /* index into lynx_color_pairs[] */
426 const char *type;
427 } table2[] = {
428 /*
429 * non-color-style colors encode bold/reverse/underline as a 0-7
430 * index like this:
431 * b,r,u 0
432 * b,r,U 1
433 * b,R,u 2
434 * b,R,U 3
435 * B,r,u 4
436 * B,r,U 5
437 * B,R,u 6
438 * B,R,U 7
439 */
440 { 0, "normal" },
441 { 1, "a" },
442 { 2, "status" },
443 { 4, "b" },
444 { 4, "blink" },
445 { 4, "cite" },
446 { 4, "del" },
447 { 4, "em" },
448 { 4, "i" },
449 { 4, "ins" },
450 { 4, "strike" },
451 { 4, "strong" },
452 { 4, "u" },
453 #if 0
454 { 5, "a.b" },
455 { 5, "b.a" },
456 { 5, "var.a" },
457 #endif
458 { 6, "alink" },
459 { 7, "whereis" },
460 #if 0
461 { 0, "h2.link" },
462 { 0, "link.h2" },
463 #endif
464 #ifdef USE_PRETTYSRC
465 /* FIXME: HTL_tagspecs_defaults[] has similar info */
466 { 4, "span.htmlsrc_comment" },
467 { 4, "span.htmlsrc_tag" },
468 { 4, "span.htmlsrc_attrib" },
469 { 4, "span.htmlsrc_attrval" },
470 { 4, "span.htmlsrc_abracket" },
471 { 4, "span.htmlsrc_entity" },
472 { 4, "span.htmlsrc_href" },
473 { 4, "span.htmlsrc_entire" },
474 { 4, "span.htmlsrc_badseq" },
475 { 4, "span.htmlsrc_badtag" },
476 { 4, "span.htmlsrc_badattr" },
477 { 4, "span.htmlsrc_sgmlspecial" },
478 #endif
479 };
480 /* *INDENT-ON* */
481
482 unsigned n;
483 char *normal = LYgetTableString(0);
484 char *strong = LYgetTableString(4);
485
486 CTRACE1((tfp, "initialise_default_stylesheet\n"));
487
488 /*
489 * For debugging this function, create hash codes for all of the tags.
490 * That makes it simpler to find the cases that are overlooked in the
491 * table.
492 */
493 for (n = 0; n < (unsigned) HTML_dtd.number_of_tags; ++n) {
494 char *name = 0;
495
496 HTSprintf0(&name, "%s:%s", HTML_dtd.tags[n].name, normal);
497 parse_style(name);
498 FREE(name);
499 }
500
501 for (n = 0; n < TABLESIZE(table2); ++n) {
502 int code = table2[n].color;
503 char *name = 0;
504 char *value = 0;
505
506 switch (code) {
507 case 0:
508 value = normal;
509 break;
510 case 4:
511 value = strong;
512 break;
513 default:
514 value = LYgetTableString(code);
515 break;
516 }
517 HTSprintf0(&name, "%s:%s", table2[n].type, value);
518 parse_style(name);
519 FREE(name);
520 if (value != normal && value != strong && value != 0)
521 free(value);
522 }
523 FREE(normal);
524 FREE(strong);
525 }
526
527 /* Set all the buckets in the hash table to be empty */
style_initialiseHashTable(void)528 static void style_initialiseHashTable(void)
529 {
530 int i;
531 static int firsttime = 1;
532
533 for (i = 0; i < CSHASHSIZE; i++) {
534 if (firsttime)
535 hashStyles[i].name = NULL;
536 else
537 FREE(hashStyles[i].name);
538 hashStyles[i].color = 0;
539 hashStyles[i].cattr = 0;
540 hashStyles[i].mono = 0;
541 }
542 if (firsttime) {
543 firsttime = 0;
544 #ifdef LY_FIND_LEAKS
545 atexit(free_colorstylestuff);
546 #endif
547 }
548 s_alink = hash_code("alink");
549 s_a = hash_code("a");
550 s_status = hash_code("status");
551 s_alert = hash_code("alert");
552 s_title = hash_code("title");
553 #ifdef USE_SCROLLBAR
554 s_sb_bar = hash_code("scroll.bar");
555 s_sb_bg = hash_code("scroll.back");
556 s_sb_aa = hash_code("scroll.arrow");
557 s_sb_naa = hash_code("scroll.noarrow");
558 #endif
559 }
560
parse_userstyles(void)561 void parse_userstyles(void)
562 {
563 char *name;
564 HTList *cur = LYuse_color_style ? lss_styles : 0;
565
566 colorPairs = 0;
567 style_initialiseHashTable();
568
569 if (HTList_isEmpty(cur)) {
570 initialise_default_stylesheet();
571 } else {
572 while ((name = (char *) HTList_nextObject(cur)) != NULL) {
573 CTRACE2(TRACE_STYLE, (tfp, "LSS:%s\n",
574 (name
575 ? name
576 : "!?! empty !?!")));
577 if (name != NULL)
578 parse_style(name);
579 }
580 }
581
582 #define dft_style(a,b) if (a == NOSTYLE) a = b
583 /* *INDENT-OFF* */
584 dft_style(s_prompt_edit, s_normal);
585 dft_style(s_prompt_edit_arr, s_prompt_edit);
586 dft_style(s_prompt_edit_pad, s_prompt_edit);
587 dft_style(s_prompt_sel, s_prompt_edit);
588 dft_style(s_aedit, s_alink);
589 dft_style(s_aedit_arr, s_aedit);
590 dft_style(s_aedit_pad, s_aedit);
591 dft_style(s_curedit, s_aedit);
592 dft_style(s_aedit_sel, s_aedit);
593 dft_style(s_menu_bg, s_normal);
594 dft_style(s_menu_entry, s_menu_bg);
595 dft_style(s_menu_frame, s_menu_bg);
596 dft_style(s_menu_number, s_menu_bg);
597 dft_style(s_menu_active, s_alink);
598 /* *INDENT-ON* */
599
600 }
601
602 /* Add a STYLE: option line to our list. Process "default:" early
603 * for it to have the same semantic as other lines: works at any place
604 * of the style file, the first line overrides the later ones.
605 */
HStyle_addStyle(char * buffer)606 static void HStyle_addStyle(char *buffer)
607 {
608 char *name = NULL;
609
610 CTRACE1((tfp, "HStyle_addStyle(%s)\n", buffer));
611
612 StrAllocCopy(name, buffer);
613 TrimLowercase(name);
614
615 if (lss_styles == NULL)
616 lss_styles = HTList_new();
617
618 if (!strncasecomp(name, "default:", 8)) {
619 /* default fg/bg */
620 CTRACE2(TRACE_STYLE, (tfp, "READCSS.default%s:%s\n",
621 (default_color_reset ? ".ignore" : ""),
622 name ? name : "!?! empty !?!"));
623 if (!default_color_reset)
624 parse_style(name);
625 FREE(name);
626 return; /* do not need to process it again */
627 }
628 CTRACE2(TRACE_STYLE, (tfp, "READCSS:%s\n", name ? name : "!?! empty !?!"));
629 HTList_addObject(lss_styles, name);
630 }
631
style_readFromFileREC(char * lss_filename,char * parent_filename)632 static int style_readFromFileREC(char *lss_filename,
633 char *parent_filename)
634 {
635 FILE *fh;
636 char *buffer = NULL;
637
638 CTRACE2(TRACE_STYLE, (tfp, "CSS:Reading styles from file: %s\n",
639 lss_filename ? lss_filename : "?!? empty ?!?"));
640 if (isEmpty(lss_filename))
641 return -1;
642 if ((fh = LYOpenCFG(lss_filename, parent_filename, LYNX_LSS_FILE)) == 0) {
643 /* this should probably be an alert or something */
644 CTRACE2(TRACE_STYLE, (tfp,
645 "CSS:Can't open style file '%s', using defaults\n", lss_filename));
646 return -1;
647 }
648
649 if (parent_filename == 0) {
650 free_colorstylestuff();
651 }
652
653 while (LYSafeGets(&buffer, fh) != NULL) {
654 LYTrimTrailing(buffer);
655 LYTrimTail(buffer);
656 LYTrimHead(buffer);
657 if (!strncasecomp(buffer, "include:", 8))
658 style_readFromFileREC(LYSkipBlanks(buffer + 8), lss_filename);
659 else if (buffer[0] != '#' && strlen(buffer) != 0)
660 HStyle_addStyle(buffer);
661 }
662
663 LYCloseInput(fh);
664 if ((parent_filename == 0) && LYCursesON)
665 parse_userstyles();
666 return 0;
667 }
668
style_readFromFile(char * filename)669 int style_readFromFile(char *filename)
670 {
671 return style_readFromFileREC(filename, (char *) 0);
672 }
673
674 /* Used in HTStructured methods: - kw */
675
TrimColorClass(const char * tagname,char * styleclassname,int * phcode)676 void TrimColorClass(const char *tagname,
677 char *styleclassname,
678 int *phcode)
679 {
680 char *end, *start = NULL, *lookfrom;
681 char tmp[64];
682
683 sprintf(tmp, ";%.*s", (int) sizeof(tmp) - 3, tagname);
684 TrimLowercase(tmp);
685
686 if ((lookfrom = styleclassname) != 0) {
687 do {
688 end = start;
689 start = strstr(lookfrom, tmp);
690 if (start)
691 lookfrom = start + 1;
692 }
693 while (start);
694 /* trim the last matching element off the end
695 * - should match classes here as well (rp)
696 */
697 if (end)
698 *end = '\0';
699 }
700 *phcode = hash_code(lookfrom && *lookfrom ? lookfrom : &tmp[1]);
701 }
702
703 /* This function is designed as faster analog to TrimColorClass.
704 * It assumes that tag_name is present in stylename! -HV
705 */
FastTrimColorClass(const char * tag_name,unsigned name_len,char * stylename,char ** pstylename_end,int * phcode)706 void FastTrimColorClass(const char *tag_name,
707 unsigned name_len,
708 char *stylename,
709 char **pstylename_end, /*will be modified */
710 int *phcode) /*will be modified */
711 {
712 char *tag_start = *pstylename_end;
713 BOOLEAN found = FALSE;
714
715 CTRACE2(TRACE_STYLE,
716 (tfp, "STYLE.fast-trim: [%s] from [%s]: ",
717 tag_name, stylename));
718 while (tag_start >= stylename) {
719 for (; (tag_start >= stylename) && (*tag_start != ';'); --tag_start) ;
720 if (!strncasecomp(tag_start + 1, tag_name, (int) name_len)) {
721 found = TRUE;
722 break;
723 }
724 --tag_start;
725 }
726 if (found) {
727 *tag_start = '\0';
728 *pstylename_end = tag_start;
729 }
730 CTRACE2(TRACE_STYLE, (tfp, found ? "success.\n" : "failed.\n"));
731 *phcode = hash_code(tag_start + 1);
732 }
733
734 /* This is called each time lss styles are read. It will fill
735 * each element of 'cached_tag_styles' -HV
736 */
cache_tag_styles(void)737 void cache_tag_styles(void)
738 {
739 char buf[200];
740 int i;
741
742 for (i = 0; i < HTML_ELEMENTS; ++i) {
743 LYStrNCpy(buf, HTML_dtd.tags[i].name, sizeof(buf) - 1);
744 LYLowerCase(buf);
745 cached_tag_styles[i] = hash_code(buf);
746 }
747 }
748
749 #define SIZEOF_CACHED_STYLES (unsigned) (cached_styles_rows * cached_styles_cols)
750
RefCachedStyle(int y,int x)751 static unsigned *RefCachedStyle(int y, int x)
752 {
753 unsigned *result = 0;
754
755 if (cached_styles_ptr == 0) {
756 cached_styles_rows = display_lines;
757 cached_styles_cols = LYcols;
758 cached_styles_ptr = typecallocn(unsigned, SIZEOF_CACHED_STYLES);
759 }
760 if (y >= 0 &&
761 x >= 0 &&
762 y < cached_styles_rows &&
763 x < cached_styles_cols) {
764 result = cached_styles_ptr + (y * cached_styles_cols) + x;
765 }
766 return result;
767 }
768
ValidCachedStyle(int y,int x)769 BOOL ValidCachedStyle(int y, int x)
770 {
771 return (BOOL) (RefCachedStyle(y, x) != 0);
772 }
773
GetCachedStyle(int y,int x)774 unsigned GetCachedStyle(int y, int x)
775 {
776 unsigned value = 0;
777 unsigned *cache = RefCachedStyle(y, x);
778
779 if (cache != 0) {
780 value = *cache;
781 }
782 return value;
783 }
784
SetCachedStyle(int y,int x,unsigned value)785 void SetCachedStyle(int y, int x, unsigned value)
786 {
787 unsigned *cache = RefCachedStyle(y, x);
788
789 if (cache != 0) {
790 *cache = value;
791 }
792 }
793
ResetCachedStyles(void)794 void ResetCachedStyles(void)
795 {
796 if (cached_styles_ptr != NULL) {
797 memset(cached_styles_ptr, 0, sizeof(unsigned) * SIZEOF_CACHED_STYLES);
798 }
799 }
800
FreeCachedStyles(void)801 void FreeCachedStyles(void)
802 {
803 if (cached_styles_ptr != NULL) {
804 FREE(cached_styles_ptr);
805 cached_styles_rows = 0;
806 cached_styles_cols = 0;
807 }
808 }
809
810 /*
811 * Recompute the pairs associated with the color style.
812 */
update_color_style(void)813 void update_color_style(void)
814 {
815 CTRACE((tfp, "update_color_style %p\n", lss_styles));
816 memset(our_pairs, 0, sizeof(our_pairs));
817 parse_userstyles();
818 }
819
820 #endif /* USE_COLOR_STYLE */
821