about summary refs log blame commit diff stats
path: root/src/LYStyle.c
blob: dd4d12fddd1ecc1ee3bd98fc80cc860621bebbf2 (plain) (tree)











































































































































































































































































































































































































                                                                                                                      
/* character level styles for Lynx
 * (c) 1996 Rob Partington -- donated to the Lyncei (if they want it :-)
 * $Id: LYStyle.c,v 1.1 1997/05/25 00:14:19 tom Exp $
 */
#include "HTUtils.h"
#include "HTML.h"
#include "tcp.h"
#include "LYSignal.h"
#include "LYGlobalDefs.h"

#include "LYStructs.h"
#include "LYCurses.h"
#include "LYCharUtils.h"
#include "AttrList.h"
#include "SGML.h"
#include "HTMLDTD.h"

/* Hash table definitions */
#include "LYHash.h"
#include "LYStyle.h"

#include "LYexit.h"

#ifdef USE_COLOR_STYLE

PUBLIC bucket hashStyles[HASHSIZE];

/* definitions for the mono attributes we can use */
static int ncursesMono[7] = {
 A_NORMAL, A_BOLD, A_REVERSE, A_UNDERLINE, A_STANDOUT, A_BLINK, A_DIM
};

/*
 * If these strings don't match the meanings of the above attributes,
 * you'll confuse the hell out of people, so make them the same. - RP
 */
static char *Mono_Strings[7] =
{
 "normal", "bold", "reverse", "underline", "standout", "blink", "dim"
};

/* definitions for the colour attributes we can use */
static int ncursesColors[8] = {
 COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, 
 COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
};

/*
 * Ditto for these strings - RP
 */
static char *Color_Strings[16] =
{
 "black", "red", "green", "brown", "blue", "magenta", "cyan", "lightgray",
 "gray", "brightred", "brightgreen", "yellow", "brightblue", "brightmagenta",
 "brightcyan", "white"
};

/* Remember the hash codes for common elements */
PUBLIC int	s_alink=NOSTYLE, s_a=NOSTYLE, s_status=NOSTYLE,
		s_label=NOSTYLE, s_value=NOSTYLE, s_high=NOSTYLE,
		s_normal=NOSTYLE, s_alert=NOSTYLE, s_title=NOSTYLE;

/* start somewhere safe */ 
PRIVATE int colorPairs=0;

#define FREE(x) if (x) {free(x); x = NULL;}

/* icky parsing of the style options */
PRIVATE void parse_attributes ARGS5(char*,mono,char*,fg,char*,bg,int,style,char*,element)
{
 int i;
 int mA=0, fA=COLOR_WHITE, bA=COLOR_BLACK, cA=0;
	int newstyle=hash_code(element);
	if (TRACE)
	fprintf(stderr, "CSS(PA):style d=%d / h=%d, e=%s\n", style, newstyle,element);
 
 for (i=0; i<7; i++)
 {
	if (!strcasecmp(Mono_Strings[i], mono))
	{
	 mA = ncursesMono[i];
	}
 }
	if (TRACE)
	fprintf(stderr, "CSS(CP):%d\n", colorPairs);
 /*
  * `nocolor' means don't even try to do colour for this - RP
  */
 if (!strcasecmp("nocolor", fg))
 {
	fA=-1;
	bA=-1;
	cA=-1;
 }
 else
 {
	for (i=0; i<16; i++)
	{
	 if (!strcasecmp(Color_Strings[i], fg))
	 {
		fA = ncursesColors[i%8];
		/*
		 * if the string was in the upper 8, then it's
		 * a bright version, so set the BOLD attribute
		 */
		cA = (i>=8 ? A_BOLD : 0);
	 }
	}
	/* 
	 * Backgrounds are horribly broken under ncurses - RP
	 */
	for (i=0; i<16; i++)
	{
	 if (!strcasecmp(Color_Strings[i], bg))
	 {
		bA = ncursesColors[i%8];
		cA |=(i>=8 ? A_BOLD : 0);
	 }
	}
 }

 /* 
  * If we have colour, and space to create a new colour attribute,
  * and we have a valid colour description, then add this style
  */
 if (has_color && colorPairs < COLOR_PAIRS-1 && fA!=-1)
 {
	colorPairs++;
	init_pair(colorPairs, fA, bA);
	setStyle(style, COLOR_PAIR(colorPairs)|cA, cA, mA);
	setHashStyle(newstyle, COLOR_PAIR(colorPairs)|cA, cA, mA, element);
 }
 else
 {
	/* only mono is set */
	setStyle(style, -1, -1, mA);
	setHashStyle(newstyle, -1, -1, mA, element);
 }
}

/* parse a style option of the format
 * STYLE:<OBJECT>:FG:BG
 */
PRIVATE void parse_style ARGS1(char*,buffer)
{
 char *tmp = strchr(buffer, ':');
 char *element, *mono, *fg, *bg;
 
 if(!tmp)
 {
	fprintf (stderr, "\
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) {
#ifndef NOSIGHUP
	    (void) signal(SIGHUP, SIG_DFL);
#endif /* NOSIGHUP */
	    (void) signal(SIGTERM, SIG_DFL);
#ifndef VMS
	    (void) signal(SIGINT, SIG_DFL);
#endif /* !VMS */
#ifdef SIGTSTP
	    if (no_suspend)
		(void) signal(SIGTSTP,SIG_DFL);
#endif /* SIGTSTP */
	    exit(-1);
	}
	exit(1);
 }
	{
		char *i;
		for (i=buffer; *i; *i++=tolower(*i));
	}
 *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="black";
	else {*tmp='\0'; bg=tmp+1;}
 }

	if (TRACE)
	{
		int bucket = hash_code(element);
		fprintf(stderr, "CSSPARSE:%s => %d %s\n", 
			element, bucket,
			(hashStyles[bucket].name ? "used" : ""));
	}

	strtolower(element);	

 /* 
  * We use some pseudo-elements, so catch these first
  */
 if (!strncasecmp(element, "alink", 5)) /* active link */
 {
	parse_attributes(mono,fg,bg,DSTYLE_ALINK,"alink");
 }
 else if (!strcasecmp(element, "a")) /* normal link */
 {
	parse_attributes(mono,fg,bg, DSTYLE_LINK,"a");
	parse_attributes(mono,fg,bg, HTML_A,"a");
 }
 else if (!strncasecmp(element, "status", 4)) /* status bar */
 {
	parse_attributes(mono,fg,bg, DSTYLE_STATUS,"status");
 }
 else if (!strncasecmp(element, "label", 6)) /* [INLINE]'s */
 {
	parse_attributes(mono,fg,bg,DSTYLE_OPTION,"label");
 }
 else if (!strncasecmp(element, "value", 5)) /* [INLINE]'s */
 {
	parse_attributes(mono,fg,bg,DSTYLE_VALUE,"value");
 }
 else if (!strncasecmp(element, "high", 4)) /* [INLINE]'s */
 {
	parse_attributes(mono,fg,bg,DSTYLE_HIGH,"high");
 }
 /* this may vanish */
 else if (!strncasecmp(element, "candy", 5)) /* [INLINE]'s */
 {
	parse_attributes(mono,fg,bg,DSTYLE_CANDY,"candy");
 }
 /* Ok, it must be a HTML element, so look through the list until we
	* find it
	*/
 else
 {
#if !defined(USEHASH)
	int i;
	for (i=0; i<HTML_ELEMENTS; i++)
	{
	 if (!strcasecmp (HTML_dtd.tags[i].name, element))
	 {
		if (TRACE)
		 fprintf(stderr, "PARSECSS:applying style <%s,%s,%s> for HTML_%s\n",mono,fg,bg,HTML_dtd.tags[i].name);
		parse_attributes(mono,fg,bg,i+STARTAT,element);
		break;
	 }
	}
#else
	parse_attributes(mono,fg,bg,hash_code(element),element);
#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
{
}

/* Set all the buckets in the hash table to be empty */
PUBLIC void style_initialiseHashTable NOARGS
{
	int i;
	
	for (i=0; i<HASHSIZE; i++)
	{
		hashStyles[i].name=NULL;
		hashStyles[i].color=-1;
		hashStyles[i].cattr=-1;
		hashStyles[i].mono=-1;
	}
	s_high=hash_code("high");
	s_alink=hash_code("alink");
	s_value=hash_code("value");
	s_label=hash_code("label");
	s_a=hash_code("a");
	s_status=hash_code("status");
	s_alert=hash_code("alert");
	s_title=hash_code("title");
}
	
/* because curses isn't started when we parse the config file, we
 * need to remember the STYLE: lines we encounter and parse them
 * after curses has started
 */
HTList *lss_styles = NULL;

PUBLIC void parse_userstyles NOARGS
{
	char *name;
	HTList *cur = lss_styles;
	colorPairs=0;
	style_initialiseHashTable();

	/* set our styles to be the same as vanilla-curses-lynx */
	initialise_default_stylesheet();

	while ((name=HTList_nextObject(cur)) != NULL)
	{
		if (TRACE)
			fprintf(stderr, "LSS:%s\n", name ? name : "!?! empty !?!");
		if (name != NULL)
		    parse_style(name);
	}
}


/* Add a STYLE: option line to our list */
PUBLIC void HStyle_addStyle ARGS1(char*,buffer)
{
	char *name=NULL;
	StrAllocCopy(name, buffer);
	if (lss_styles==NULL)
		lss_styles=HTList_new();
	strtolower(name);
	if (TRACE)
		fprintf(stderr, "READCSS:%s\n", name ? name : "!?! empty !?!");
	HTList_addObject (lss_styles, name);
}

PUBLIC void style_deleteStyleList NOARGS
{
    char *name;
    while ((name = HTList_removeLastObject(lss_styles)) != NULL)
	FREE(name);
    HTList_delete (lss_styles);
    lss_styles=NULL;
}

char* default_stylesheet[]={
	"a:bold", "em:bold", "strong:bold", "b:bold", "i:bold",
	"alink:reverse", "status:reverse", NULL
};

PUBLIC void style_defaultStyleSheet NOARGS
{
	int i;
	for (i=0; default_stylesheet[i]; i++)
		HStyle_addStyle(default_stylesheet[i]);
}

PUBLIC int style_readFromFile ARGS1(char*, file)
{
	FILE *fh;
	char buffer[1024];
	int len;

	if (TRACE)
	    fprintf(stderr, "CSS:Reading styles from file: %s\n", file ? file : "?!? empty ?!?");
	if (file == NULL || *file == '\0')
	    return -1;
	fh=fopen(file, "r");
	if (!fh) 
	{
/* this should probably be an alert or something */
		if (TRACE)
			fprintf(stderr, "CSS:Can't open style file %s, using defaults\n", file);
		return -1;
	}
	
	style_initialiseHashTable();
	style_deleteStyleList();

	while (!feof(fh)
	 && fgets(buffer, sizeof(buffer)-1, fh) != NULL)
	{
		len = strlen(buffer);
		if (len > 0) {
		    if (buffer[len-1] == '\n' || buffer[len-1] == '\r')
			buffer[len-1]='\0'; /* hack */
		    else
			buffer[1023]='\0'; /* hack */
		}
		LYTrimTail(buffer);
		LYTrimHead(buffer);
		if (buffer[0] != '#' && (len = strlen(buffer)) > 0)
		    HStyle_addStyle(buffer);
	}
	/* the default styles are added after the user styles in order
	** that they come before them  <grin>  RP
	*/ 
/*	style_defaultStyleSheet(); */

	fclose (fh);
	if (LYCursesON)
		parse_userstyles();
	return 0;
}
#endif /* USE_COLOR_STYLE */