summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libcss/errors.h1
-rw-r--r--include/libcss/stylesheet.h17
-rw-r--r--src/parse/language.c39
-rw-r--r--src/stylesheet.c154
-rw-r--r--src/stylesheet.h11
-rw-r--r--src/utils/errors.c3
-rw-r--r--test/css21.c37
-rw-r--r--test/dump.h7
-rw-r--r--test/parse-auto.c44
-rw-r--r--test/parse2-auto.c2
-rw-r--r--test/select-auto.c3
11 files changed, 233 insertions, 85 deletions
diff --git a/include/libcss/errors.h b/include/libcss/errors.h
index 8e321ce..2a36492 100644
--- a/include/libcss/errors.h
+++ b/include/libcss/errors.h
@@ -20,6 +20,7 @@ typedef enum css_error {
CSS_NEEDDATA = 5,
CSS_BADCHARSET = 6,
CSS_EOF = 7,
+ CSS_IMPORTS_PENDING = 8
} css_error;
/* Convert a libcss error value to a string */
diff --git a/include/libcss/stylesheet.h b/include/libcss/stylesheet.h
index 6a89372..eb14ad3 100644
--- a/include/libcss/stylesheet.h
+++ b/include/libcss/stylesheet.h
@@ -11,23 +11,24 @@
#include <libcss/errors.h>
#include <libcss/types.h>
-/**
- * Type of stylesheet import handler
- */
-typedef css_error (*css_import_handler)(void *pw, const char *url,
- css_stylesheet *sheet);
-
css_error css_stylesheet_create(css_language_level level,
const char *charset, const char *url, const char *title,
css_origin origin, uint64_t media,
- css_import_handler import_callback, void *import_pw,
- css_allocator_fn alloc, void *alloc_pw, css_stylesheet **stylesheet);
+ css_allocator_fn alloc, void *alloc_pw,
+ css_stylesheet **stylesheet);
css_error css_stylesheet_destroy(css_stylesheet *sheet);
css_error css_stylesheet_append_data(css_stylesheet *sheet,
const uint8_t *data, size_t len);
css_error css_stylesheet_data_done(css_stylesheet *sheet);
+css_error css_stylesheet_next_pending_import(css_stylesheet *parent,
+ css_string *url, uint64_t *media);
+css_error css_stylesheet_register_import(css_stylesheet *parent,
+ css_stylesheet *child);
+
+css_error css_stylesheet_get_language_level(css_stylesheet *sheet,
+ css_language_level *level);
css_error css_stylesheet_get_url(css_stylesheet *sheet, const char **url);
css_error css_stylesheet_get_title(css_stylesheet *sheet, const char **title);
css_error css_stylesheet_get_origin(css_stylesheet *sheet, css_origin *origin);
diff --git a/src/parse/language.c b/src/parse/language.c
index a187379..11fe972 100644
--- a/src/parse/language.c
+++ b/src/parse/language.c
@@ -408,7 +408,6 @@ css_error handleStartAtRule(css_language *c, const parserutils_vector *vector)
} else if (atkeyword->ilower == c->strings[IMPORT]) {
if (c->state != HAD_RULE) {
css_rule *rule;
- css_stylesheet *import;
css_media_type media = 0;
css_error error;
@@ -477,49 +476,15 @@ css_error handleStartAtRule(css_language *c, const parserutils_vector *vector)
if (error != CSS_OK)
return error;
- /** \todo resolve URI */
- char url[uri->idata->len + 1];
- memcpy(url, uri->idata->data, uri->idata->len);
- url[uri->idata->len] = '\0';
-
- /* Create imported sheet */
- error = css_stylesheet_create(c->sheet->level, NULL,
- url, NULL, c->sheet->origin, media,
- c->sheet->import, c->sheet->import_pw,
- c->alloc, c->pw, &import);
+ error = css_stylesheet_rule_set_nascent_import(c->sheet,
+ rule, uri->idata, media);
if (error != CSS_OK) {
css_stylesheet_rule_destroy(c->sheet, rule);
return error;
}
- /* Trigger fetch of imported sheet */
- if (c->sheet->import != NULL) {
- error = c->sheet->import(c->sheet->import_pw,
- url, import);
- if (error != CSS_OK) {
- css_stylesheet_destroy(import);
- css_stylesheet_rule_destroy(c->sheet,
- rule);
- return error;
- }
- }
-
- error = css_stylesheet_rule_set_import(c->sheet, rule,
- import);
- if (error != CSS_OK) {
- /** \todo we need to tell the client to stop
- * doing stuff with the imported sheet */
- css_stylesheet_destroy(import);
- css_stylesheet_rule_destroy(c->sheet, rule);
- return error;
- }
-
- /* Imported sheet is now owned by the rule */
-
error = css_stylesheet_add_rule(c->sheet, rule);
if (error != CSS_OK) {
- /** \todo we need to tell the client to stop
- * doing stuff with the imported sheet */
css_stylesheet_rule_destroy(c->sheet, rule);
return error;
}
diff --git a/src/stylesheet.c b/src/stylesheet.c
index 4174859..7072bfc 100644
--- a/src/stylesheet.c
+++ b/src/stylesheet.c
@@ -26,8 +26,6 @@ static css_error _remove_selectors(css_stylesheet *sheet, css_rule *rule);
* \param title Title of stylesheet
* \param origin Origin of stylesheet
* \param media Media stylesheet applies to
- * \param import_callback Handler for imported stylesheets, or NULL
- * \param import_pw Client private data for import_callback
* \param alloc Memory (de)allocation function
* \param alloc_pw Client private data for alloc
* \param stylesheet Pointer to location to receive stylesheet
@@ -38,8 +36,8 @@ static css_error _remove_selectors(css_stylesheet *sheet, css_rule *rule);
css_error css_stylesheet_create(css_language_level level,
const char *charset, const char *url, const char *title,
css_origin origin, uint64_t media,
- css_import_handler import_callback, void *import_pw,
- css_allocator_fn alloc, void *alloc_pw, css_stylesheet **stylesheet)
+ css_allocator_fn alloc, void *alloc_pw,
+ css_stylesheet **stylesheet)
{
parserutils_error perror;
css_error error;
@@ -120,9 +118,6 @@ css_error css_stylesheet_create(css_language_level level,
sheet->origin = origin;
sheet->media = media;
- sheet->import = import_callback;
- sheet->import_pw = import_pw;
-
sheet->alloc = alloc;
sheet->pw = alloc_pw;
@@ -200,10 +195,13 @@ css_error css_stylesheet_append_data(css_stylesheet *sheet,
* Flag that the last of a stylesheet's data has been seen
*
* \param sheet The stylesheet in question
- * \return CSS_OK on success, appropriate error otherwise
+ * \return CSS_OK on success,
+ * CSS_IMPORTS_PENDING if there are imports pending,
+ * appropriate error otherwise
*/
css_error css_stylesheet_data_done(css_stylesheet *sheet)
{
+ const css_rule *r;
css_error error;
if (sheet == NULL)
@@ -223,6 +221,127 @@ css_error css_stylesheet_data_done(css_stylesheet *sheet)
sheet->parser_frontend = NULL;
sheet->parser = NULL;
+ /* Determine if there are any pending imports */
+ for (r = sheet->rule_list; r != NULL; r = r->next) {
+ const css_rule_import *i = (const css_rule_import *) r;
+
+ if (r->type != CSS_RULE_UNKNOWN &&
+ r->type != CSS_RULE_CHARSET &&
+ r->type != CSS_RULE_IMPORT)
+ break;
+
+ if (r->type == CSS_RULE_IMPORT && i->sheet == NULL)
+ return CSS_IMPORTS_PENDING;
+ }
+
+ return CSS_OK;
+}
+
+/**
+ * Retrieve the next pending import for the parent stylesheet
+ *
+ * \param parent Parent stylesheet
+ * \param url Pointer to object to be populated with details of URL of
+ * imported stylesheet (potentially relative)
+ * \param media Pointer to location to receive applicable media types for
+ * imported sheet,
+ * \return CSS_OK on success,
+ * CSS_INVALID if there are no pending imports remaining
+ *
+ * The client must resolve the absolute URL of the imported stylesheet,
+ * using the parent's URL as the base. It must then fetch the imported
+ * stylesheet, and parse it to completion, including fetching any stylesheets
+ * it may import. The resultant sheet must then be registered with the
+ * parent using css_stylesheet_register_import().
+ *
+ * The client must then call this function again, to determine if there
+ * are any further imports for the parent stylesheet, and, if so,
+ * process them as described above.
+ *
+ * If the client is unable to fetch an imported stylesheet, it must
+ * register an empty stylesheet with the parent in its place.
+ */
+css_error css_stylesheet_next_pending_import(css_stylesheet *parent,
+ css_string *url, uint64_t *media)
+{
+ const css_rule *r;
+
+ if (parent == NULL || url == NULL || media == NULL)
+ return CSS_BADPARM;
+
+ for (r = parent->rule_list; r != NULL; r = r->next) {
+ const css_rule_import *i = (const css_rule_import *) r;
+
+ if (r->type != CSS_RULE_UNKNOWN &&
+ r->type != CSS_RULE_CHARSET &&
+ r->type != CSS_RULE_IMPORT)
+ break;
+
+ if (r->type == CSS_RULE_IMPORT && i->sheet == NULL) {
+ url->len = i->url->len;
+ url->data = (uint8_t *) i->url->data;
+
+ *media = i->media;
+
+ return CSS_OK;
+ }
+ }
+
+ return CSS_INVALID;
+}
+
+/**
+ * Register an imported stylesheet with its parent
+ *
+ * \param parent Parent stylesheet
+ * \param import Imported sheet
+ * \return CSS_OK on success,
+ * CSS_INVALID if there are no outstanding imports,
+ * appropriate error otherwise.
+ *
+ * Ownership of the imported stylesheet is transferred to the parent.
+ */
+css_error css_stylesheet_register_import(css_stylesheet *parent,
+ css_stylesheet *import)
+{
+ css_rule *r;
+
+ if (parent == NULL || import == NULL)
+ return CSS_BADPARM;
+
+ for (r = parent->rule_list; r != NULL; r = r->next) {
+ css_rule_import *i = (css_rule_import *) r;
+
+ if (r->type != CSS_RULE_UNKNOWN &&
+ r->type != CSS_RULE_CHARSET &&
+ r->type != CSS_RULE_IMPORT)
+ break;
+
+ if (r->type == CSS_RULE_IMPORT && i->sheet == NULL) {
+ i->sheet = import;
+
+ return CSS_OK;
+ }
+ }
+
+ return CSS_INVALID;
+}
+
+/**
+ * Retrieve the language level of a stylesheet
+ *
+ * \param sheet The stylesheet to retrieve the language level of
+ * \param level Pointer to location to receive language level
+ * \return CSS_OK on success, appropriate error otherwise
+ */
+css_error css_stylesheet_get_language_level(css_stylesheet *sheet,
+ css_language_level *level)
+{
+ if (sheet == NULL || level == NULL)
+ return CSS_BADPARM;
+
+ *level = sheet->level;
+
return CSS_OK;
}
@@ -689,7 +808,8 @@ css_error css_stylesheet_rule_destroy(css_stylesheet *sheet, css_rule *rule)
{
css_rule_import *import = (css_rule_import *) rule;
- css_stylesheet_destroy(import->sheet);
+ if (import->sheet != NULL)
+ css_stylesheet_destroy(import->sheet);
}
break;
case CSS_RULE_MEDIA:
@@ -864,27 +984,31 @@ css_error css_stylesheet_rule_set_charset(css_stylesheet *sheet,
return CSS_OK;
}
+
/**
- * Set the imported stylesheet associated with a rule
+ * Set the necessary data to import a stylesheet associated with a rule
*
* \param sheet The stylesheet context
* \param rule The rule to add to (must be of type CSS_RULE_IMPORT)
- * \param import The imported sheet
+ * \param url The URL of the imported stylesheet
+ * \param media The applicable media types for the imported stylesheet
* \return CSS_OK on success, appropriate error otherwise
*/
-css_error css_stylesheet_rule_set_import(css_stylesheet *sheet,
- css_rule *rule, css_stylesheet *import)
+css_error css_stylesheet_rule_set_nascent_import(css_stylesheet *sheet,
+ css_rule *rule, const parserutils_hash_entry *url,
+ uint64_t media)
{
css_rule_import *r = (css_rule_import *) rule;
- if (sheet == NULL || rule == NULL || import == NULL)
+ if (sheet == NULL || rule == NULL || url == NULL)
return CSS_BADPARM;
/* Ensure rule is a CSS_RULE_IMPORT */
assert(rule->type == CSS_RULE_IMPORT);
/* Set the rule's sheet field */
- r->sheet = import;
+ r->url = url;
+ r->media = media;
return CSS_OK;
}
diff --git a/src/stylesheet.h b/src/stylesheet.h
index 2b5860f..d2316d1 100644
--- a/src/stylesheet.h
+++ b/src/stylesheet.h
@@ -133,6 +133,9 @@ typedef struct css_rule_page {
typedef struct css_rule_import {
css_rule base;
+ const parserutils_hash_entry *url;
+ uint64_t media;
+
css_stylesheet *sheet;
} css_rule_import;
@@ -161,9 +164,6 @@ struct css_stylesheet {
void *ownerNode; /**< Owning node in document */
css_rule *ownerRule; /**< Owning rule in parent */
- css_import_handler import; /**< Import callback */
- void *import_pw; /**< Import handler data */
-
css_language_level level; /**< Language level of sheet */
css_parser *parser; /**< Core parser for sheet */
void *parser_frontend; /**< Frontend parser */
@@ -207,8 +207,9 @@ css_error css_stylesheet_rule_append_style(css_stylesheet *sheet,
css_error css_stylesheet_rule_set_charset(css_stylesheet *sheet,
css_rule *rule, const parserutils_hash_entry *charset);
-css_error css_stylesheet_rule_set_import(css_stylesheet *sheet,
- css_rule *rule, css_stylesheet *import);
+css_error css_stylesheet_rule_set_nascent_import(css_stylesheet *sheet,
+ css_rule *rule, const parserutils_hash_entry *url,
+ uint64_t media);
/** \todo registering other rule-type data with css_rules */
diff --git a/src/utils/errors.c b/src/utils/errors.c
index b5b4792..c53a442 100644
--- a/src/utils/errors.c
+++ b/src/utils/errors.c
@@ -44,6 +44,9 @@ const char *css_error_to_string(css_error error)
case CSS_EOF:
result = "EOF encountered";
break;
+ case CSS_IMPORTS_PENDING:
+ result = "Imports pending";
+ break;
}
return result;
diff --git a/test/css21.c b/test/css21.c
index 3da2bfb..47558bc 100644
--- a/test/css21.c
+++ b/test/css21.c
@@ -40,8 +40,8 @@ int main(int argc, char **argv)
for (int count = 0; count < ITERATIONS; count++) {
assert(css_stylesheet_create(CSS_LEVEL_21, "UTF-8", argv[2],
- NULL, CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL, NULL,
- NULL, myrealloc, NULL, &sheet) == CSS_OK);
+ NULL, CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL,
+ myrealloc, NULL, &sheet) == CSS_OK);
fp = fopen(argv[2], "rb");
if (fp == NULL) {
@@ -74,7 +74,38 @@ int main(int argc, char **argv)
fclose(fp);
- assert(css_stylesheet_data_done(sheet) == CSS_OK);
+ error = css_stylesheet_data_done(sheet);
+ assert(error == CSS_OK || error == CSS_IMPORTS_PENDING);
+
+ while (error == CSS_IMPORTS_PENDING) {
+ css_string url;
+ uint64_t media;
+
+ error = css_stylesheet_next_pending_import(sheet,
+ &url, &media);
+ assert(error == CSS_OK || error == CSS_INVALID);
+
+ if (error == CSS_OK) {
+ css_stylesheet *import;
+ char buf[url.len + 1];
+
+ memcpy(buf, url.data, url.len);
+ buf[url.len] = '\0';
+
+ assert(css_stylesheet_create(CSS_LEVEL_21,
+ "UTF-8", buf, NULL, CSS_ORIGIN_AUTHOR,
+ media, myrealloc, NULL, &import) ==
+ CSS_OK);
+
+ assert(css_stylesheet_data_done(import) ==
+ CSS_OK);
+
+ assert(css_stylesheet_register_import(sheet,
+ import) == CSS_OK);
+
+ error = CSS_IMPORTS_PENDING;
+ }
+ }
#if DUMP_HASH
parserutils_hash_dump(sheet->dictionary);
diff --git a/test/dump.h b/test/dump.h
index 98ec1bb..4626894 100644
--- a/test/dump.h
+++ b/test/dump.h
@@ -87,11 +87,8 @@ void dump_rule_import(css_rule_import *s, char **buf, size_t *buflen)
{
char *ptr = *buf;
- if (s->sheet == NULL) {
- assert(0 && "No imported sheet");
- }
-
- ptr += sprintf(ptr, "| @import url(\"%s\")", s->sheet->url);
+ ptr += sprintf(ptr, "| @import url(\"%.*s\")",
+ (int) s->url->len, (const char *) s->url->data);
/** \todo media list */
diff --git a/test/parse-auto.c b/test/parse-auto.c
index bef54cd..4c42359 100644
--- a/test/parse-auto.c
+++ b/test/parse-auto.c
@@ -308,7 +308,7 @@ void run_test(const uint8_t *data, size_t len, exp_entry *exp, size_t explen)
static int testnum;
assert(css_stylesheet_create(CSS_LEVEL_21, "UTF-8", "foo", NULL,
- CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL, NULL, NULL,
+ CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL,
myrealloc, NULL, &sheet) == CSS_OK);
error = css_stylesheet_append_data(sheet, data, len);
@@ -317,7 +317,35 @@ void run_test(const uint8_t *data, size_t len, exp_entry *exp, size_t explen)
assert(0);
}
- assert(css_stylesheet_data_done(sheet) == CSS_OK);
+ error = css_stylesheet_data_done(sheet);
+ assert(error == CSS_OK || error == CSS_IMPORTS_PENDING);
+
+ while (error == CSS_IMPORTS_PENDING) {
+ css_string url;
+ uint64_t media;
+
+ error = css_stylesheet_next_pending_import(sheet,
+ &url, &media);
+ assert(error == CSS_OK || error == CSS_INVALID);
+
+ if (error == CSS_OK) {
+ css_stylesheet *import;
+ char buf[url.len + 1];
+
+ memcpy(buf, url.data, url.len);
+ buf[url.len] = '\0';
+
+ assert(css_stylesheet_create(CSS_LEVEL_21,
+ "UTF-8", buf, NULL, CSS_ORIGIN_AUTHOR,
+ media, myrealloc, NULL, &import) ==
+ CSS_OK);
+
+ assert(css_stylesheet_register_import(sheet,
+ import) == CSS_OK);
+
+ error = CSS_IMPORTS_PENDING;
+ }
+ }
e = 0;
testnum++;
@@ -460,13 +488,11 @@ void validate_rule_charset(css_rule_charset *s, exp_entry *e, int testnum)
void validate_rule_import(css_rule_import *s, exp_entry *e, int testnum)
{
- if (s->sheet == NULL) {
- assert(0 && "No imported sheet");
- }
-
- if (strcmp(s->sheet->url, e->name) != 0) {
- printf("%d: Got URL '%s'. Expected '%s'\n",
- testnum, s->sheet->url, e->name);
+ if (strncmp((const char *) s->url->data, e->name,
+ (int) s->url->len) != 0) {
+ printf("%d: Got URL '%.*s'. Expected '%s'\n",
+ testnum, (int) s->url->len, (const char *) s->url->data,
+ e->name);
assert(0 && "Mismatched URLs");
}
}
diff --git a/test/parse2-auto.c b/test/parse2-auto.c
index 59ae220..80fcd24 100644
--- a/test/parse2-auto.c
+++ b/test/parse2-auto.c
@@ -172,7 +172,7 @@ void run_test(const uint8_t *data, size_t len, const char *exp, size_t explen)
buflen = 2 * explen;
assert(css_stylesheet_create(CSS_LEVEL_21, "UTF-8", "foo", NULL,
- CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL, NULL, NULL,
+ CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL,
myrealloc, NULL, &sheet) == CSS_OK);
error = css_stylesheet_append_data(sheet, data, len);
diff --git a/test/select-auto.c b/test/select-auto.c
index 3f859a0..bd34a99 100644
--- a/test/select-auto.c
+++ b/test/select-auto.c
@@ -439,8 +439,7 @@ void parse_sheet(line_ctx *ctx, const char *data, size_t len)
/** \todo How are we going to handle @import? */
assert(css_stylesheet_create(CSS_LEVEL_21, "UTF-8", "foo", "foo",
- origin, media, NULL, NULL, myrealloc, NULL, &sheet) ==
- CSS_OK);
+ origin, media, myrealloc, NULL, &sheet) == CSS_OK);
/* Extend array of sheets and append new sheet to it */
temp = realloc(ctx->sheets,