gecko-dev/lib/libstyle/csstojs.c

987 lines
26 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/* CSStoJS tranlation code */
#include "xp.h"
#include "css.h"
#include "cssI.h"
/* ALLOW_IMPORT
* Switch allows or stops the translation of @import rules.
*/
#define ALLOW_IMPORT 0
/* ALLOW_FONTDEF
* Switch allows or stops the translation of @fontdef rules.
*/
#define ALLOW_FONTDEF 1
/* ALLOW_PRIORITY
* Switch allows or stops the translation of "!important" in the value.
*/
#define ALLOW_PRIORITY 0
/* ALLOW_PSEUDO_ELEMENTS
* Switch allows or prevents the translation of rules with pseudo-elements
* :first-line and :first-letter in the selector.
*/
#define ALLOW_PSEUDO_ELEMENTS 0
/* ALLOW_ACTIVE_PSEUDO_CLASS
* Switch allows or prevents the translation of rules with pseudo-class
* :active in the selector.
*/
#define ALLOW_ACTIVE_PSEUDO_CLASS 0
#define STYLE_INITIAL_BUFSIZ 1024
#define STYLE_INCR_BUFSIZ 1024
/* property type values */
#define CSS_PROPERTY_TYPE_ASSIGNMENT (1)
#define CSS_PROPERTY_TYPE_CALL (2)
/* pseudo class type values */
#define CSS_PSEUDO_CLASS_NONE (0)
#define CSS_PSEUDO_CLASS_LINK (1)
#define CSS_PSEUDO_CLASS_ACTIVE (2)
#define CSS_PSEUDO_CLASS_VISITED (3)
typedef struct {
char * buffer;
int32 buffer_size; /* size of buffer in bytes */
int32 buffer_count; /* bytes used */
int32 prior_count; /* buffer_count at beginning of rule */
int32 pseudo_class_state; /* holds temporary state during translation */
XP_Bool ignore_rule; /* during translation, may decide to ignore a rule */
} *StyleBuffer, StyleBufferRec;
XP_BEGIN_PROTOS
static XP_Bool ConvertStyleSheet(css_node stylesheet, StyleBuffer sb);
static void ConvertRule(css_node rule, StyleBuffer sb);
static void ConvertSelector(css_node selector, css_node pseudo_element,
StyleBuffer sb);
static void ConvertContextualSelector(css_node selector, css_node pseudo_element,
StyleBuffer sb);
static void ConvertSingleSelector(css_node simple, css_node pseudo_element,
StyleBuffer sb);
static void ConvertDeclaration(css_node declaration_list, StyleBuffer sb);
static void ConvertProperty(const char * css1_property, StyleBuffer sb,
int * property_type_return);
static void ConvertValue(css_node value, StyleBuffer sb, int property_type);
static void ConvertURLValue(char * url_value, StyleBuffer sb);
static void StripURLValue(char ** url_return, int * url_length_return);
static void ConvertStringValue(char * string_value, StyleBuffer sb);
static void StyleBufferWrite(char * str, int len, StyleBuffer sb);
static void AnteRule(StyleBuffer sb);
static void IgnoreRule(StyleBuffer sb);
static void PostRule(StyleBuffer sb);
static void SaltPseudoClass(const char * pseudo_class, StyleBuffer sb);
static int32 GetPseudoClass(StyleBuffer sb);
#if (ALLOW_IMPORT || ALLOW_FONTDEF)
static void ConvertToLink(css_node ruleset, int rel_type, StyleBuffer sb);
static void EchoCSS(char * src, int32 src_count, StyleBuffer sb);
#endif
XP_END_PROTOS
static char * input_buffer;
static int32 input_buffer_count; /* bytes used, not including NULL */
static int32 input_buffer_index;
/* result and max_to_read are created and passed as int, not int32, on Win16. */
void css_GetBuf(char * buf, int *result, int max_to_read)
{
int i = 0;
if (input_buffer) {
while ((i < max_to_read) && (input_buffer_count > input_buffer_index))
buf[i++] = input_buffer[input_buffer_index++];
if (0 == i) {
input_buffer = NULL;
input_buffer_count = input_buffer_index = 0;
}
}
*result = i;
return;
}
/* Java and JavaScript */
static const char * reserved_words[] = {
"abstract",
"boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
"const",
"continue",
"default",
"delete",
"do",
"double",
"else",
"extends",
"false",
"final",
"finally",
"float",
"for",
"function",
"goto",
"if",
"implements",
"import",
"in",
"instanceof",
"int",
"interface",
"long",
"native",
"new",
"null",
"package",
"private",
"protected",
"public",
"return",
"short",
"static",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
"transient",
"true",
"try",
"typeof",
"var",
"void",
"volatile",
"while",
"with"
};
static XP_Bool IsReservedWord(const char * css_name)
{
int lower = 0;
int upper = (sizeof(reserved_words) / sizeof(char *)) - 1;
int x;
int32 result;
while (upper >= lower) {
x = (lower + upper) / 2;
result = XP_STRCMP(css_name, reserved_words[x]);
if (result < 0)
upper = x - 1;
else if (result > 0)
lower = x + 1;
else
return 1;
}
return 0;
}
/* CSS_ConvertToJSCompatibleName
* converts characters which are illegal in JavaScript names.
*
* Anne-Marie ==> Anne_Marie "-" (dash) always converts to "_"
* 5NewportRd ==> _5NewportRd 1st character a digit prepend "_"
* Convert lower to upper case when second parameter is true.
* When second parameter is false, prepend "_" to reserved words.
* Returns NULL on error.
*/
PUBLIC char *
CSS_ConvertToJSCompatibleName(char *css_name, XP_Bool uppercase_it)
{
int32 len;
char *new_name;
char *cp;
XP_Bool reserved = 0;
XP_ASSERT(css_name);
if (!css_name)
return NULL;
len = XP_STRLEN(css_name);
if (! uppercase_it)
reserved = IsReservedWord(css_name);
if (reserved || XP_IS_DIGIT(*css_name))
len++;
cp = new_name = XP_ALLOC((len+1) * sizeof(char));
if (!new_name)
return NULL;
if (reserved || XP_IS_DIGIT(*css_name)) {
*cp = '_';
cp++;
}
for(; *css_name; css_name++, cp++)
if (*css_name == '-')
*cp = '_';
else
*cp = uppercase_it ? (XP_TO_UPPER(*css_name)) : *css_name;
*cp = '\0';
return new_name;
}
PUBLIC
void CSS_ConvertToJS(char * src, int32 src_count, char ** dst, int32 * dst_count)
{
StyleBuffer sb;
XP_Bool translated;
*dst = NULL;
*dst_count = 0;
if (NULL == src || 0 == src_count)
return;
input_buffer = src;
input_buffer_count = src_count;
input_buffer_index = 0;
css_tree_root = NULL;
if (css_parse() != 0)
return;
sb = XP_NEW_ZAP(StyleBufferRec);
if (sb == NULL)
return;
translated = ConvertStyleSheet(css_tree_root, sb);
css_FreeNode(css_tree_root);
#if ALLOW_IMPORT
if (! translated)
EchoCSS(src, src_count, sb);
#endif
/* The caller should free *dst. */
*dst = sb->buffer;
*dst_count = sb->buffer_count;
XP_DELETE(sb);
}
/* Release all subtree and the node */
void css_FreeNode(css_node vp)
{
if (vp) {
css_FreeNode(vp->left);
css_FreeNode(vp->right);
if (vp->string)
XP_FREE(vp->string);
XP_DELETE(vp);
}
}
static XP_Bool ConvertStyleSheet(css_node stylesheet, StyleBuffer sb)
{
#if (ALLOW_IMPORT || ALLOW_FONTDEF)
XP_Bool translate_rules = 1;
/* CSS1 requires @import productions occurring after
* ruleset productions to be ignored. This is implemented
* here. The restriction is not enforced by the parser.
*/
for (; stylesheet && (stylesheet->node_id != NODE_RULESET_LIST);
stylesheet = stylesheet->left) {
#if ALLOW_IMPORT
if (NODE_IMPORT_LIST == stylesheet->node_id) {
ConvertToLink(stylesheet->right, stylesheet->node_id, sb);
translate_rules = 0;
}
#endif
#if ALLOW_FONTDEF
if (NODE_FONTDEF_LIST == stylesheet->node_id) {
ConvertToLink(stylesheet->right, stylesheet->node_id, sb);
}
#endif
}
#if (ALLOW_IMPORT)
if (! translate_rules)
return 0;
#endif
#endif
for (; stylesheet; stylesheet = stylesheet->left) {
if (stylesheet->node_id == NODE_RULESET_LIST)
ConvertRule(stylesheet->right, sb);
}
return 1;
}
/* Generate the JavaScript corresponding to one CSS1 rule. */
static void ConvertRule(css_node rule, StyleBuffer sb)
{
css_node selector_list, selector;
css_node declaration_list;
if (! rule || rule->node_id != NODE_RULESET)
return;
for (selector_list = rule->left; selector_list;
selector_list = selector_list->left) {
selector = selector_list->right;
if (! selector)
continue;
for (declaration_list = rule->right; declaration_list;
declaration_list = declaration_list->left) {
if (declaration_list->right) {
AnteRule(sb);
ConvertSelector(selector->left, selector->right, sb);
ConvertDeclaration(declaration_list->right, sb);
PostRule(sb);
}
}
}
}
static void AnteRule(StyleBuffer sb)
{
sb->prior_count = sb->buffer_count;
sb->pseudo_class_state = CSS_PSEUDO_CLASS_NONE;
}
static void PostRule(StyleBuffer sb)
{
if (sb->ignore_rule) {
sb->buffer_count = sb->prior_count;
sb->ignore_rule = 0;
if (0 == sb->buffer_count)
sb->buffer_count = 1;
sb->buffer[sb->buffer_count-1] = '\0';
}
}
static void StyleBufferWrite(char * str, int len, StyleBuffer sb)
{
if (str == NULL)
return;
if (len <= 0) {
len = strlen(str);
if (len <= 0)
return;
}
if (sb->buffer == NULL) {
sb->buffer = (char *) XP_ALLOC(STYLE_INITIAL_BUFSIZ);
if (sb->buffer) {
sb->buffer_size = STYLE_INITIAL_BUFSIZ;
*sb->buffer = '\0';
sb->buffer_count = 1;
}
}
if (sb->buffer_count + len > sb->buffer_size) {
sb->buffer = (char *)
XP_REALLOC(sb->buffer, sb->buffer_size + STYLE_INCR_BUFSIZ);
if (sb->buffer) {
sb->buffer_size += STYLE_INCR_BUFSIZ;
} else {
sb->buffer_size = sb->buffer_count = 0;
}
}
if (sb->buffer_count + len <= sb->buffer_size) {
(void) strncpy(sb->buffer + sb->buffer_count - 1, str, len);
sb->buffer_count += len;
sb->buffer[sb->buffer_count-1] = '\0';
}
}
static void ConvertSelector(css_node selector, css_node pseudo_element,
StyleBuffer sb)
{
if (selector->node_id == NODE_SELECTOR_CONTEXTUAL) {
StyleBufferWrite("contextual(", 11, sb);
ConvertContextualSelector(selector, pseudo_element, sb);
StyleBufferWrite(")", 1, sb);
} else {
ConvertSingleSelector(selector, pseudo_element, sb);
}
}
static void ConvertContextualSelector(css_node selector,
css_node pseudo_element, StyleBuffer sb)
{
if (selector->left) {
/* pseudo_elements may be present only on the final context object */
ConvertContextualSelector(selector->left, NULL, sb);
StyleBufferWrite(", ", 2, sb);
}
ConvertSingleSelector(selector->right, pseudo_element, sb);
}
static void ConvertSingleSelector(css_node selector, css_node pseudo_element,
StyleBuffer sb)
{
char * str1;
char * str2;
if (! selector)
return;
if (selector->node_id == NODE_WILD) {
/* CSS1 Section 7.1 states: "A ruleset that [has] a selector
* string that is not valid CSS1 is skipped." (sic)
*/
IgnoreRule(sb);
}
if (! selector->left)
return;
str1 = selector->left->string;
str2 = selector->right ? selector->right->string : NULL;
switch (selector->node_id) {
case NODE_SIMPLE_SELECTOR_NAME_ONLY:
/* "document.tags.<TAG>" */
StyleBufferWrite("document.tags.", 14, sb);
str1 = CSS_ConvertToJSCompatibleName(str1, TRUE);
StyleBufferWrite(str1, 0, sb);
XP_FREE(str1);
break;
case NODE_SIMPLE_SELECTOR_DOT_AND_CLASS:
/* "document.classes.<class>.all" */
StyleBufferWrite("document.classes.", 17, sb);
str1 = CSS_ConvertToJSCompatibleName(str1, FALSE);
StyleBufferWrite(str1, 0, sb);
XP_FREE(str1);
StyleBufferWrite(".all", 4, sb);
break;
case NODE_SIMPLE_SELECTOR_ID_SELECTOR:
/* "document.ids.<id>" */
StyleBufferWrite("document.ids.", 13, sb);
str1 = CSS_ConvertToJSCompatibleName(str1, FALSE);
StyleBufferWrite(str1, 0, sb);
XP_FREE(str1);
break;
case NODE_SIMPLE_SELECTOR_NAME_AND_CLASS:
/* "document.classes.<class>.<TAG>" */
StyleBufferWrite("document.classes.", 17, sb);
str2 = CSS_ConvertToJSCompatibleName(str2, FALSE);
StyleBufferWrite(str2, 0, sb);
XP_FREE(str2);
StyleBufferWrite(".", 1, sb);
str1 = CSS_ConvertToJSCompatibleName(str1, TRUE);
StyleBufferWrite(str1, 0, sb);
XP_FREE(str1);
break;
case NODE_SIMPLE_SELECTOR_NAME_PSEUDO_CLASS:
/* "document.tags.<TAG> */
#ifdef DOM
/*
* By design, leave the pseudoclass in place by generating
* ``document.tags["A:visited"]'' or whatever. Never ignore
* the pseudoclass name because, well, duh.
*/
StyleBufferWrite("document.tags[\"", 15, sb);
str1 = CSS_ConvertToJSCompatibleName(str1, TRUE);
StyleBufferWrite(str1, 0, sb);
XP_FREE(str1);
StyleBufferWrite(":", 1, sb);
StyleBufferWrite(str2, 0, sb);
StyleBufferWrite("\"].", 3, sb);
break;
#else
/* By design, prepend the pseudoclass name to the property
* name when the property is 'color'; otherwise, ignore the
* pseudoclass name.
*/
StyleBufferWrite("document.tags.", 14, sb);
str1 = CSS_ConvertToJSCompatibleName(str1, TRUE);
StyleBufferWrite(str1, 0, sb);
XP_FREE(str1);
SaltPseudoClass(str2, sb);
break;
#endif
case NODE_SIMPLE_SELECTOR_NAME_CLASS_PSEUDO_CLASS:
/* "document.classes.<class>.<TAG>" */
/* By design, prepend the pseudoclass name to the property
* name when the property is 'color'; otherwise, ignore the
* pseudoclass name.
*/
StyleBufferWrite("document.classes.", 17, sb);
str1 = CSS_ConvertToJSCompatibleName(str1, FALSE);
StyleBufferWrite(str1, 0, sb);
XP_FREE(str1);
StyleBufferWrite(".", 1, sb);
str1 = CSS_ConvertToJSCompatibleName(selector->string, TRUE);
StyleBufferWrite(str1, 0, sb);
XP_FREE(str1);
SaltPseudoClass(str2, sb);
break;
default:
break;
}
if (pseudo_element) {
#if ! ALLOW_PSEUDO_ELEMENTS
IgnoreRule(sb);
#endif
StyleBufferWrite(".", 1, sb);
ConvertProperty(pseudo_element->string, sb, NULL);
}
}
static void IgnoreRule(StyleBuffer sb)
{
sb->ignore_rule = 1;
}
static void SaltPseudoClass(const char * pseudo_class, StyleBuffer sb)
{
if (! pseudo_class)
return;
/* The parser always gives these strings in lower case. */
if (0 == XP_STRCMP(pseudo_class, "link"))
sb->pseudo_class_state = CSS_PSEUDO_CLASS_LINK;
else if (0 == XP_STRCMP(pseudo_class, "visited"))
sb->pseudo_class_state = CSS_PSEUDO_CLASS_VISITED;
else if (0 == XP_STRCMP(pseudo_class, "active")) {
#if (! ALLOW_ACTIVE_PSEUDO_CLASS)
IgnoreRule(sb);
#endif
sb->pseudo_class_state = CSS_PSEUDO_CLASS_ACTIVE;
}
}
static int32 GetPseudoClass(StyleBuffer sb)
{
return sb->pseudo_class_state;
}
/* Pseudo-elements as well as property names are converted by this. */
static void ConvertProperty(const char * css1_property, StyleBuffer sb,
int * property_type_return)
{
XP_Bool upper;
char ch[2];
int32 pseudo_class;
ch[1] = '\0';
if (property_type_return)
*property_type_return = CSS_PROPERTY_TYPE_ASSIGNMENT;
/* The CSS1 float property is translated to align because float is
* a reserved word in JavaScript.
*/
if (0 == XP_STRCASECMP(css1_property, "float"))
StyleBufferWrite("align", 5, sb);
else {
if (property_type_return) {
if ( (0 == XP_STRCASECMP(css1_property, "margin"))
|| (0 == XP_STRCASECMP(css1_property, "padding"))
|| (0 == XP_STRCASECMP(css1_property, "border-width")))
*property_type_return = CSS_PROPERTY_TYPE_CALL;
}
pseudo_class = GetPseudoClass(sb);
if (0 == XP_STRCASECMP(css1_property, "margin"))
StyleBufferWrite("margins", 7, sb);
else if (0 == XP_STRCASECMP(css1_property, "padding"))
StyleBufferWrite("paddings", 8, sb);
else if (0 == XP_STRCASECMP(css1_property, "border-width"))
StyleBufferWrite("borderWidths", 12, sb);
else if ((CSS_PSEUDO_CLASS_NONE != pseudo_class)
&& (0 == XP_STRCASECMP(css1_property, "color"))) {
switch (pseudo_class) {
case CSS_PSEUDO_CLASS_LINK:
default:
StyleBufferWrite("linkColor", 9, sb);
break;
case CSS_PSEUDO_CLASS_ACTIVE:
StyleBufferWrite("activeColor", 11, sb);
break;
case CSS_PSEUDO_CLASS_VISITED:
StyleBufferWrite("visitedColor", 12, sb);
break;
}
}
else {
for (upper=0; *css1_property; css1_property++) {
if (*css1_property == '-') {
upper = 1;
continue;
}
ch[0] = (upper ? toupper(*css1_property)
: tolower(*css1_property));
upper = 0;
StyleBufferWrite(ch, 1, sb);
}
}
}
}
static void ConvertDeclaration(css_node declaration, StyleBuffer sb)
{
int property_type;
if (declaration &&
(declaration->node_id == NODE_DECLARATION_PROPERTY_EXPR ||
declaration->node_id == NODE_DECLARATION_PROPERTY_EXPR_PRIO)) {
StyleBufferWrite(".", 1, sb);
ConvertProperty(declaration->left->string, sb, &property_type);
ConvertValue(declaration->right, sb, property_type);
#if ALLOW_PRIORITY
if (declaration->node_id == NODE_DECLARATION_PROPERTY_EXPR_PRIO)
StyleBufferWrite(" !important", 11, sb);
#endif
StyleBufferWrite("\n", 1, sb);
}
}
static void ConvertValue(css_node value, StyleBuffer sb, int property_type)
{
css_node term;
XP_Bool comma;
if (CSS_PROPERTY_TYPE_ASSIGNMENT == property_type)
StyleBufferWrite(" = \"", 4, sb);
else
StyleBufferWrite("(", 1, sb);
for (comma=FALSE; value; value=value->left, comma = TRUE) {
if (CSS_PROPERTY_TYPE_CALL == property_type && comma)
StyleBufferWrite(",", 1, sb);
if (value->node_id == NODE_EMPTY_OP)
StyleBufferWrite(" ", 1, sb);
if (CSS_PROPERTY_TYPE_CALL == property_type)
StyleBufferWrite("\"", 1, sb);
if (value->node_id == NODE_EXPR_OP)
StyleBufferWrite(value->string, 0, sb);
term = value->right;
if (term) {
if (term->node_id == NODE_STRING)
ConvertStringValue(term->string, sb);
else if (NODE_URL == term->node_id)
ConvertURLValue(term->string, sb);
else {
StyleBufferWrite(term->string, 0, sb);
if (term->node_id == NODE_UNARY_OP)
StyleBufferWrite(term->left->string, 0, sb);
}
}
if (CSS_PROPERTY_TYPE_CALL == property_type)
StyleBufferWrite("\"", 1, sb);
}
if (CSS_PROPERTY_TYPE_ASSIGNMENT == property_type)
StyleBufferWrite("\"", 1, sb);
else
StyleBufferWrite(")", 1, sb);
}
static void ConvertStringValue(char * string_value, StyleBuffer sb)
{
for (; *string_value; string_value++) {
if (*string_value == '"')
StyleBufferWrite("\\", 1, sb);
StyleBufferWrite(string_value, 1, sb);
}
}
static void StripURLValue(char ** url_return, int * url_length_return)
{
char * ptr;
int len;
if (! url_return || ! *url_return ||
! url_length_return || ! *url_length_return)
return;
ptr = *url_return;
len = *url_length_return;
/* Skip leading whitespace */
while (len > 0 && isspace(*ptr)) {
ptr++;
len--;
}
/* Skip trailing whitespace */
while (len > 0 && isspace(*(ptr + len - 1)))
len--;
/* Skip enclosing quotation marks */
if (('"' == *ptr || '\'' == *ptr ) &&
(len > 1) &&
(*ptr == *(ptr + len - 1))) {
ptr++;
len -= 2;
}
*url_return = ptr;
*url_length_return = len;
}
static void ConvertURLValue(char * url_value, StyleBuffer sb)
{
char * ptr = url_value;
int len;
len = strlen(ptr);
if (len < 6)
return;
/* Don't count the 5 characters for 'url()' */
len -= 5;
StyleBufferWrite("url(", 4, sb);
ptr += 4;
StripURLValue(&ptr, &len);
if (len > 0)
StyleBufferWrite(ptr, len, sb);
StyleBufferWrite(")", 1, sb);
}
#if (ALLOW_IMPORT || ALLOW_FONTDEF)
static char * open_call = "document.write('";
static char * close_call = "');\n";
static void ConvertToLink(css_node rule, int rel_type, StyleBuffer sb)
{
int len;
char * ptr;
char ch;
char hexbuf[4];
if (rule && rule->string) {
if ((NODE_IMPORT_URL == rule->node_id) ||
(NODE_IMPORT_STRING == rule->node_id)) {
StyleBufferWrite(open_call, 0, sb);
if (NODE_IMPORT_LIST == rel_type)
StyleBufferWrite("<LINK REL=stylesheet ", 21, sb);
else
StyleBufferWrite("<LINK REL=fontdef ", 18, sb);
/* Copy the url */
len = XP_STRLEN(rule->string);
ptr = NULL;
if ((NODE_IMPORT_URL == rule->node_id) && (len > 5)) {
/* Copy the characters inside the parens */
ptr = rule->string + 4;
len -= 5;
StripURLValue(&ptr, &len);
if (len <= 0)
ptr = NULL;
} else {
/* Copy the characters inside the quotes */
ptr = rule->string + 1;
len -= 2;
}
if (NULL != ptr) {
if (NODE_IMPORT_LIST == rel_type)
StyleBufferWrite("HREF=", 5, sb);
else
StyleBufferWrite("SRC=", 4, sb);
StyleBufferWrite(ptr, len, sb);
}
StyleBufferWrite(">');\n", 5, sb);
}
}
}
static char * open_style = "<style type=text/css>\\n";
static char * close_style = "</style>";
static char * disable_at_rules = "HI { donna : lou }\\n";
static void EchoCSS(char * src, int32 src_count, StyleBuffer sb)
{
char ch;
char * start;
char * end;
int len;
if (! src || src_count <= 0) return;
StyleBufferWrite(open_call, 0, sb);
StyleBufferWrite(open_style, 0, sb);
StyleBufferWrite(close_call, 0, sb);
/* Don't recurse on the @-rules!
* Write a harmless rule at the beginning of the style sheet.
* The lexer, parser, and finally the translator will see it.
* The translator will skip @ rules which occur after any
* ordinary rule. CSS requires that behavior for @import;
* @fontdef voluntarily observes the same restriction; there
* are no other recognized @ rules.
*/
StyleBufferWrite(open_call, 0, sb);
StyleBufferWrite(disable_at_rules, 0, sb);
StyleBufferWrite(close_call, 0, sb);
/* Echo the entire CSS buffer, escaping some characters. */
StyleBufferWrite(open_call, 0, sb);
start = src;
for (end = start; --src_count >=0; end++) {
ch = *end;
if (('\n' == ch) || ('\'' == ch) || ('\f' == ch) ||
('\v' == ch) || ('\r' == ch)) {
len = end - start;
if (len) {
StyleBufferWrite(start, len, sb);
start = end;
}
switch (ch) {
case '\n': StyleBufferWrite("\\n", 2, sb); break;
case '\'': StyleBufferWrite("\\'", 2, sb); break;
case '\f': StyleBufferWrite("\\f", 2, sb); break;
case '\v': StyleBufferWrite("\\v", 2, sb); break;
case '\r': StyleBufferWrite("\\r", 2, sb); break;
default : break;
}
start = end + 1;
}
}
len = end - start;
if (len) {
StyleBufferWrite(start, len, sb);
}
StyleBufferWrite(close_call, 0, sb);
StyleBufferWrite(open_call, 0, sb);
StyleBufferWrite(close_style, 0, sb);
StyleBufferWrite(close_call, 0, sb);
}
#endif
#ifdef TEST_CSS_TRANSLATION
#define TEST_CSS_INITIAL_BUFSIZ 4096
#define TEST_CSS_INCR_BUFSIZ 4096
void main()
{
int ch;
char *b;
int32 src_count;
char *dst;
int32 dst_count;
char * src;
int src_size;
int done;
done = ch = 0;
src_size = src_count = 0;
src = (char *) XP_ALLOC(TEST_CSS_INITIAL_BUFSIZ);
if (src) src_size = TEST_CSS_INITIAL_BUFSIZ;
while (!done) {
for (b = src + src_count; src_count < src_size; src_count++, b++) {
*b = ch = getc(stdin);
/* Either the null character or EOF will serve to terminate. */
if (ch == EOF || ch == '\0') {
done = 1;
/* We don't need to add this character to the src_count */
break;
}
}
if (!done) {
src_size += TEST_CSS_INCR_BUFSIZ;
src = (char *) XP_REALLOC(src, src_size);
if (!src) {
src_size = src_count = 0;
printf("css test: memory allocation failure\n");
done = 1;
}
}
}
/* The src_count need not include the terminating NULL or EOF */
CSS_ConvertToJS(src, src_count, &dst, &dst_count);
printf("%s", dst);
XP_FREE(dst);
}
#endif