mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-11-22 14:31:20 +03:00
[project @ 2002-04-22 09:24:35 by bursa]
Initial revision svn path=/import/netsurf/; revision=2
This commit is contained in:
commit
6d48b29c2b
545
render/css.c
Normal file
545
render/css.c
Normal file
@ -0,0 +1,545 @@
|
||||
/**
|
||||
* $Id: css.c,v 1.1.1.1 2002/04/22 09:24:34 bursa Exp $
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "css.h"
|
||||
#include "utils.h"
|
||||
|
||||
/**
|
||||
* internal structures
|
||||
*/
|
||||
|
||||
struct rule {
|
||||
struct css_selector * selector;
|
||||
unsigned int selectors;
|
||||
struct css_style * style;
|
||||
struct rule * next;
|
||||
};
|
||||
|
||||
struct decl {
|
||||
unsigned long score;
|
||||
struct rule * rule;
|
||||
};
|
||||
|
||||
#define HASH_SIZE 13
|
||||
|
||||
struct css_stylesheet {
|
||||
struct rule * hash[HASH_SIZE];
|
||||
};
|
||||
|
||||
static int parse_length(struct css_length * const length, const char *s);
|
||||
static void parse_display(struct css_style * const style, const char * const value);
|
||||
static void parse_float(struct css_style * const style, const char * const value);
|
||||
static void parse_font_size(struct css_style * const style, const char * const value);
|
||||
static void parse_height(struct css_style * const style, const char * const value);
|
||||
static void parse_width(struct css_style * const style, const char * const value);
|
||||
static void parse_property_list(struct css_style * style, char * str);
|
||||
static void parse_selector(struct css_selector * sel, char * const str);
|
||||
static unsigned int hash_str(const char * str);
|
||||
static int seleq(const struct css_selector * const s1, const struct css_selector * const s2);
|
||||
static unsigned long selmatch(const struct css_selector * const s, const struct css_selector * const sr);
|
||||
static struct rule * find_rule(struct css_stylesheet * stylesheet,
|
||||
struct css_selector * selector, unsigned int selectors);
|
||||
static int cmpdecl(const struct decl * d0, const struct decl * d1);
|
||||
static void update_style(struct css_stylesheet * stylesheet, struct css_selector * selector,
|
||||
unsigned int selectors, char * str);
|
||||
static void dump_length(const struct css_length * const length);
|
||||
static void dump_selector(const struct css_selector * const sel);
|
||||
static void dump_rule(const struct rule * rule);
|
||||
static void css_dump_stylesheet(const struct css_stylesheet * stylesheet);
|
||||
|
||||
/**
|
||||
* property parsers
|
||||
*/
|
||||
|
||||
static int parse_length(struct css_length * const length, const char *s)
|
||||
{
|
||||
length->unit = css_unit_parse(s + strspn(s, "0123456789+-."));
|
||||
if (length->unit == CSS_UNIT_UNKNOWN) return 1;
|
||||
length->value = atof(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parse_display(struct css_style * const style, const char * const value)
|
||||
{
|
||||
style->display = css_display_parse(value);
|
||||
}
|
||||
|
||||
static void parse_float(struct css_style * const style, const char * const value)
|
||||
{
|
||||
style->float_ = css_float_parse(value);
|
||||
}
|
||||
|
||||
#define SIZE_FACTOR 1.2
|
||||
|
||||
static struct font_size {
|
||||
const char * keyword;
|
||||
float size;
|
||||
} const font_size[] = {
|
||||
{ "xx-small", 1.0 / (SIZE_FACTOR * SIZE_FACTOR * SIZE_FACTOR) },
|
||||
{ "x-small", 1.0 / (SIZE_FACTOR * SIZE_FACTOR) },
|
||||
{ "small", 1.0 / SIZE_FACTOR },
|
||||
{ "medium", 1.0 },
|
||||
{ "large", 1.0 * SIZE_FACTOR },
|
||||
{ "x-large", 1.0 * SIZE_FACTOR * SIZE_FACTOR },
|
||||
{ "xx-large", 1.0 * SIZE_FACTOR * SIZE_FACTOR * SIZE_FACTOR }
|
||||
};
|
||||
|
||||
static void parse_font_size(struct css_style * const style, const char * const value)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(font_size) / sizeof(struct font_size); i++) {
|
||||
if (strcmp(value, font_size[i].keyword) == 0) {
|
||||
style->font_size.size = CSS_FONT_SIZE_ABSOLUTE;
|
||||
style->font_size.value.absolute = font_size[i].size;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strcmp(value, "larger") == 0)
|
||||
style->font_size.size = CSS_FONT_SIZE_PERCENT,
|
||||
style->font_size.value.percent = SIZE_FACTOR * 100;
|
||||
else if (strcmp(value, "smaller") == 0)
|
||||
style->font_size.size = CSS_FONT_SIZE_PERCENT,
|
||||
style->font_size.value.percent = 1 / SIZE_FACTOR * 100;
|
||||
else if (strrchr(value, '%'))
|
||||
style->font_size.size = CSS_FONT_SIZE_PERCENT,
|
||||
style->font_size.value.percent = atof(value);
|
||||
else if (parse_length(&style->font_size.value.length, value) == 0)
|
||||
style->font_size.size = CSS_FONT_SIZE_LENGTH;
|
||||
}
|
||||
|
||||
static void parse_height(struct css_style * const style, const char * const value)
|
||||
{
|
||||
if (strcmp(value, "auto") == 0)
|
||||
style->height.height = CSS_HEIGHT_AUTO;
|
||||
else if (parse_length(&style->height.length, value) == 0)
|
||||
style->height.height = CSS_HEIGHT_LENGTH;
|
||||
}
|
||||
|
||||
static void parse_width(struct css_style * const style, const char * const value)
|
||||
{
|
||||
if (strcmp(value, "auto") == 0)
|
||||
style->width.width = CSS_WIDTH_AUTO;
|
||||
else if (strrchr(value, '%'))
|
||||
style->width.width = CSS_WIDTH_PERCENT,
|
||||
style->width.value.percent = atof(value);
|
||||
else if (parse_length(&style->width.value.length, value) == 0)
|
||||
style->width.width = CSS_WIDTH_LENGTH;
|
||||
}
|
||||
|
||||
static struct property {
|
||||
const char * const name;
|
||||
void (*parse) (struct css_style * const s, const char * const value);
|
||||
} const property[] = {
|
||||
{ "display", parse_display },
|
||||
{ "float", parse_float },
|
||||
{ "font-size", parse_font_size },
|
||||
{ "height", parse_height },
|
||||
{ "width", parse_width },
|
||||
};
|
||||
|
||||
/**
|
||||
* parse a property list
|
||||
*/
|
||||
|
||||
static void parse_property_list(struct css_style * style, char * str)
|
||||
{
|
||||
char * end;
|
||||
for (; str != 0; str = end) {
|
||||
char * prop;
|
||||
char * value;
|
||||
unsigned int i;
|
||||
|
||||
if ((end = strchr(str, ';')) != 0) *end = 0, end++;
|
||||
if ((value = strchr(str, ':')) == 0) continue;
|
||||
*value = 0; value++;
|
||||
prop = strip(str);
|
||||
value = strip(value);
|
||||
printf("css_parse: '%s' => '%s'\n", prop, value);
|
||||
|
||||
for (i = 0; i < sizeof(property) / sizeof(struct property); i++) {
|
||||
if (strcmp(prop, property[i].name) == 0) {
|
||||
property[i].parse(style, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* selectors
|
||||
*/
|
||||
|
||||
static void parse_selector(struct css_selector * sel, char * const str)
|
||||
{
|
||||
char * dot = strchr(str, '.');
|
||||
char * hash = strchr(str, '#');
|
||||
|
||||
if ((dot == 0) && (hash == 0)) {
|
||||
sel->element = xstrdup(str);
|
||||
sel->class = sel->id = 0;
|
||||
} else if (dot != 0) {
|
||||
*dot = 0;
|
||||
sel->element = xstrdup(str);
|
||||
sel->class = xstrdup(dot + 1);
|
||||
sel->id = 0;
|
||||
} else if (hash != 0) {
|
||||
*hash = 0;
|
||||
sel->element = xstrdup(str);
|
||||
sel->class = 0;
|
||||
sel->id = xstrdup(hash + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stylesheet structure
|
||||
*/
|
||||
|
||||
static unsigned int hash_str(const char * str)
|
||||
{
|
||||
unsigned int s = 0;
|
||||
for (; *str != 0; str++)
|
||||
s += *str;
|
||||
return s % HASH_SIZE;
|
||||
}
|
||||
|
||||
static int seleq(const struct css_selector * const s1, const struct css_selector * const s2)
|
||||
{
|
||||
return strcmp(s1->element, s2->element) == 0 &&
|
||||
((s1->class == 0 && s2->class == 0) ||
|
||||
(s1->class != 0 && s2->class != 0 && strcmp(s1->class, s2->class) == 0)) &&
|
||||
((s1->id == 0 && s2->id == 0) ||
|
||||
(s1->id != 0 && s2->id != 0 && strcmp(s1->id, s2->id) == 0));
|
||||
}
|
||||
|
||||
static unsigned long selmatch(const struct css_selector * const s, const struct css_selector * const sr)
|
||||
{
|
||||
unsigned int c;
|
||||
if (strcmp(s->element, sr->element) != 0) return 0;
|
||||
c = s->element[0] == 0 ? 0 : 1;
|
||||
if (sr->class != 0) {
|
||||
if (s->class != 0 && strcmp(s->class, sr->class) == 0) return 0x100 + c;
|
||||
return 0;
|
||||
}
|
||||
if (sr->id != 0) {
|
||||
if (s->id != 0 && strcmp(s->id, sr->id) == 0) return 0x10000 + c;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct css_stylesheet * css_new_stylesheet(void)
|
||||
{
|
||||
struct css_stylesheet * stylesheet = xcalloc(1, sizeof(struct css_stylesheet));
|
||||
return stylesheet;
|
||||
}
|
||||
|
||||
static struct rule * find_rule(struct css_stylesheet * stylesheet,
|
||||
struct css_selector * selector, unsigned int selectors)
|
||||
{
|
||||
struct rule * rule;
|
||||
for (rule = stylesheet->hash[hash_str(selector[selectors - 1].element)];
|
||||
rule != 0; rule = rule->next) {
|
||||
unsigned int i;
|
||||
if (selectors != rule->selectors)
|
||||
continue;
|
||||
/* inv: selector[0..i) == rule->selector[0..i) */
|
||||
for (i = 0; i != selectors && seleq(&selector[i], &rule->selector[i]); i++)
|
||||
;
|
||||
if (i == selectors)
|
||||
return rule;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmpdecl(const struct decl * d0, const struct decl * d1)
|
||||
{
|
||||
if (d0->score < d1->score) return -1;
|
||||
else if (d0->score == d1->score) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void css_get_style(struct css_stylesheet * stylesheet, struct css_selector * selector,
|
||||
unsigned int selectors, struct css_style * style)
|
||||
{
|
||||
struct rule * rule;
|
||||
struct decl * decl = xcalloc(0, sizeof(struct decl));
|
||||
unsigned int d, decls = 0;
|
||||
|
||||
for (rule = stylesheet->hash[hash_str(selector[selectors - 1].element)];
|
||||
rule != 0; rule = rule->next) {
|
||||
unsigned int i = selectors - 1;
|
||||
unsigned int j;
|
||||
unsigned int score, s;
|
||||
|
||||
if ((score = selmatch(&selector[i], &rule->selector[rule->selectors - 1])) == 0)
|
||||
continue;
|
||||
if (selectors < rule->selectors)
|
||||
continue;
|
||||
|
||||
for (j = rule->selectors - 1; j != 0; j--) {
|
||||
for (; i != 0 && (s = selmatch(&selector[i - 1], &rule->selector[j - 1])) == 0; i--)
|
||||
;
|
||||
if (i == 0)
|
||||
break;
|
||||
score += s;
|
||||
}
|
||||
if (j == 0) {
|
||||
decl = xrealloc(decl, (decls + 1) * sizeof(struct decl));
|
||||
decl[decls].score = score;
|
||||
decl[decls].rule = rule;
|
||||
decls++;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(decl, decls, sizeof(struct decl), (int (*) (const void *, const void *)) cmpdecl);
|
||||
|
||||
for (d = 0; d < decls; d++) {
|
||||
/* printf("%i: 0x%lx\n", d, decl[d].score); */
|
||||
/* css_dump_rule(decl[d].rule); */
|
||||
css_cascade(style, decl[d].rule->style);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_style(struct css_stylesheet * stylesheet, struct css_selector * selector,
|
||||
unsigned int selectors, char * str)
|
||||
{
|
||||
struct rule * rule = find_rule(stylesheet, selector, selectors);
|
||||
if (rule == 0) {
|
||||
unsigned int h = hash_str(selector[selectors - 1].element);
|
||||
printf("update_style: not present - adding\n");
|
||||
rule = xcalloc(1, sizeof(struct rule));
|
||||
rule->selector = selector;
|
||||
rule->selectors = selectors;
|
||||
rule->style = xcalloc(1, sizeof(struct css_style));
|
||||
parse_property_list(rule->style, str);
|
||||
rule->next = stylesheet->hash[h];
|
||||
stylesheet->hash[h] = rule;
|
||||
} else {
|
||||
printf("update_style: already present - updating\n");
|
||||
parse_property_list(rule->style, str);
|
||||
free(selector);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parse an entire css file or block
|
||||
*/
|
||||
|
||||
void css_parse_stylesheet(struct css_stylesheet * stylesheet, char * str)
|
||||
{
|
||||
/* overwrite comments with spaces */
|
||||
char * copen = strstr(str, "/*");
|
||||
while (copen != 0) {
|
||||
char * cclose = strstr(copen + 2, "*/");
|
||||
if (cclose == 0) { *copen = 0; break; }
|
||||
memset(copen, ' ', (size_t) (cclose - copen + 2));
|
||||
copen = strstr(cclose + 2, "/*");
|
||||
}
|
||||
|
||||
while (*str != 0) {
|
||||
char * open = strchr(str, '{');
|
||||
char * close = strchr(str, '}');
|
||||
char * sels_str;
|
||||
char * comma;
|
||||
|
||||
if ((open == 0) || (close == 0)) break;
|
||||
*open = 0; *close = 0;
|
||||
|
||||
sels_str = strip(str);
|
||||
do {
|
||||
char * sel_str;
|
||||
char * space;
|
||||
char * style_str;
|
||||
unsigned int selectors = 0;
|
||||
struct css_selector * selector = xcalloc(0, sizeof(struct css_selector));
|
||||
|
||||
comma = strchr(sels_str, ',');
|
||||
if (comma != 0) *comma = 0;
|
||||
|
||||
sel_str = strip(sels_str);
|
||||
printf("css_parse_stylesheet: %s\n", sel_str);
|
||||
do {
|
||||
space = strchr(sel_str, ' ');
|
||||
if (space != 0) *space = 0;
|
||||
selector = xrealloc(selector, sizeof(struct css_selector) * (selectors + 1));
|
||||
parse_selector(&selector[selectors++], sel_str);
|
||||
if (space != 0) sel_str = strip(space + 1);
|
||||
} while (space != 0);
|
||||
|
||||
style_str = xstrdup(open + 1);
|
||||
update_style(stylesheet, selector, selectors, style_str);
|
||||
free(style_str);
|
||||
|
||||
if (comma != 0) sels_str = strip(comma + 1);
|
||||
} while (comma != 0);
|
||||
|
||||
str = close + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dump a style
|
||||
*/
|
||||
|
||||
static void dump_length(const struct css_length * const length)
|
||||
{
|
||||
printf("%g%s", length->value,
|
||||
css_unit_name[length->unit]);
|
||||
}
|
||||
|
||||
void css_dump_style(const struct css_style * const style)
|
||||
{
|
||||
puts("{");
|
||||
printf("\tdisplay: %s;\n", css_display_name[style->display]);
|
||||
printf("\tfloat: %s;\n", css_float_name[style->float_]);
|
||||
printf("\tfont-size: ");
|
||||
switch (style->font_size.size) {
|
||||
case CSS_FONT_SIZE_ABSOLUTE: printf("[%g]", style->font_size.value.absolute); break;
|
||||
case CSS_FONT_SIZE_LENGTH: dump_length(&style->font_size.value.length); break;
|
||||
case CSS_FONT_SIZE_PERCENT: printf("%g%%", style->font_size.value.percent); break;
|
||||
case CSS_FONT_SIZE_INHERIT: printf("inherit"); break;
|
||||
default: printf("UNKNOWN"); break;
|
||||
}
|
||||
puts(";");
|
||||
printf("\theight: ");
|
||||
switch (style->height.height) {
|
||||
case CSS_HEIGHT_AUTO: printf("auto"); break;
|
||||
case CSS_HEIGHT_LENGTH: dump_length(&style->height.length); break;
|
||||
default: printf("UNKNOWN"); break;
|
||||
}
|
||||
puts(";");
|
||||
printf("\twidth: ");
|
||||
switch (style->width.width) {
|
||||
case CSS_WIDTH_AUTO: printf("auto"); break;
|
||||
case CSS_WIDTH_LENGTH: dump_length(&style->width.value.length); break;
|
||||
case CSS_WIDTH_PERCENT: printf("%g%%", style->width.value.percent); break;
|
||||
default: printf("UNKNOWN"); break;
|
||||
}
|
||||
puts(";");
|
||||
puts("}");
|
||||
}
|
||||
|
||||
static void dump_selector(const struct css_selector * const sel)
|
||||
{
|
||||
if (sel->class != 0)
|
||||
printf("%s.%s ", sel->element, sel->class);
|
||||
else if (sel->id != 0)
|
||||
printf("%s#%s ", sel->element, sel->id);
|
||||
else
|
||||
printf("%s ", sel->element);
|
||||
}
|
||||
|
||||
static void dump_rule(const struct rule * rule)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < rule->selectors; i++)
|
||||
dump_selector(&rule->selector[i]);
|
||||
css_dump_style(rule->style);
|
||||
}
|
||||
|
||||
static void css_dump_stylesheet(const struct css_stylesheet * stylesheet)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < HASH_SIZE; i++) {
|
||||
struct rule * rule;
|
||||
printf("hash %i:\n", i);
|
||||
for (rule = stylesheet->hash[i]; rule != 0; rule = rule->next)
|
||||
dump_rule(rule);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* cascade styles
|
||||
*/
|
||||
|
||||
void css_cascade(struct css_style * const style, const struct css_style * const apply)
|
||||
{
|
||||
float f;
|
||||
style->display = apply->display;
|
||||
style->float_ = apply->float_;
|
||||
style->height = apply->height;
|
||||
style->width = apply->width;
|
||||
|
||||
/* font-size */
|
||||
f = apply->font_size.value.percent / 100;
|
||||
switch (apply->font_size.size) {
|
||||
case CSS_FONT_SIZE_ABSOLUTE: style->font_size = apply->font_size; break;
|
||||
case CSS_FONT_SIZE_LENGTH:
|
||||
switch (apply->font_size.value.length.unit) {
|
||||
case CSS_UNIT_EM: f = apply->font_size.value.length.value; break;
|
||||
case CSS_UNIT_EX: f = apply->font_size.value.length.value * 0.6 /*?*/; break;
|
||||
default: style->font_size = apply->font_size;
|
||||
}
|
||||
if ((apply->font_size.value.length.unit != CSS_UNIT_EM) &&
|
||||
(apply->font_size.value.length.unit != CSS_UNIT_EX)) break;
|
||||
/* drop through if EM or EX */
|
||||
case CSS_FONT_SIZE_PERCENT:
|
||||
switch (style->font_size.size) {
|
||||
case CSS_FONT_SIZE_ABSOLUTE: style->font_size.value.absolute *= f; break;
|
||||
case CSS_FONT_SIZE_LENGTH: style->font_size.value.length.value *= f; break;
|
||||
default: die("attempting percentage of unknown font-size");
|
||||
}
|
||||
break;
|
||||
case CSS_FONT_SIZE_INHERIT:
|
||||
default: /* leave unchanged */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* testing
|
||||
*/
|
||||
/*
|
||||
int main(int argv, char *argc[])
|
||||
{
|
||||
int i;
|
||||
struct rule * r;
|
||||
struct css_stylesheet * s;
|
||||
struct css_selector sel = { "h1", 0, 0 };
|
||||
struct css_selector con[] = {{ "html", 0, 0 }, {"body", 0, 0}, {"h1", "foo", 0}, {"b", 0, "bar"}};
|
||||
struct css_style * style = xcalloc(1, sizeof(struct css_style));
|
||||
|
||||
s = css_new_stylesheet();
|
||||
css_parse_stylesheet(s, argc[1]);
|
||||
css_dump_stylesheet(s);
|
||||
|
||||
/* r->selectors = 1; */
|
||||
/* css_stylesheet_add_rule(s, r); */
|
||||
/* puts("********** finding h1:");
|
||||
r = find_rule(s, &sel, 1);
|
||||
if (r)
|
||||
dump_rule(r);
|
||||
else
|
||||
puts("not found");
|
||||
|
||||
puts("********** finding html body h1.foo b#bar:");
|
||||
for (i = 1; i <= sizeof(con) / sizeof(con[0]); i++) {
|
||||
css_get_style(s, con, i, style);
|
||||
css_dump_style(style);
|
||||
}
|
||||
|
||||
/* printf("%x %x\n", r, r2); */
|
||||
|
||||
/* struct css_style *s;
|
||||
struct css_selector *sel;
|
||||
|
||||
s = parse_property_list(argc[1]);
|
||||
css_dump_style(s);
|
||||
|
||||
for (i = 2; i < argv; i++) {
|
||||
css_cascade(s, parse_property_list(argc[i]));
|
||||
css_dump_style(s);
|
||||
}*/
|
||||
|
||||
/* for (i = 1; i < argv; i++) {
|
||||
sel = parse_selector(argc[i]);
|
||||
css_dump_selector(sel);
|
||||
puts("");
|
||||
}*/
|
||||
/*
|
||||
return 0;
|
||||
}
|
||||
*/
|
87
render/css.h
Normal file
87
render/css.h
Normal file
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* $Id: css.h,v 1.1.1.1 2002/04/22 09:24:34 bursa Exp $
|
||||
*/
|
||||
|
||||
#include "css_enum.h"
|
||||
|
||||
/**
|
||||
* structures and typedefs
|
||||
*/
|
||||
|
||||
typedef unsigned long colour; /* 0xrrggbb */
|
||||
#define TRANSPARENT 0x1000000
|
||||
|
||||
struct css_length {
|
||||
float value;
|
||||
css_unit unit;
|
||||
};
|
||||
|
||||
struct css_style {
|
||||
css_display display;
|
||||
css_float float_;
|
||||
|
||||
struct {
|
||||
enum { CSS_FONT_SIZE_INHERIT,
|
||||
CSS_FONT_SIZE_ABSOLUTE,
|
||||
CSS_FONT_SIZE_LENGTH,
|
||||
CSS_FONT_SIZE_PERCENT } size;
|
||||
union {
|
||||
float absolute;
|
||||
struct css_length length;
|
||||
float percent;
|
||||
} value;
|
||||
} font_size;
|
||||
|
||||
struct {
|
||||
enum { CSS_HEIGHT_AUTO,
|
||||
CSS_HEIGHT_LENGTH } height;
|
||||
struct css_length length;
|
||||
} height;
|
||||
|
||||
struct {
|
||||
enum { CSS_WIDTH_AUTO,
|
||||
CSS_WIDTH_LENGTH,
|
||||
CSS_WIDTH_PERCENT } width;
|
||||
union {
|
||||
struct css_length length;
|
||||
float percent;
|
||||
} value;
|
||||
} width;
|
||||
|
||||
|
||||
enum { BACKGROUND_SCROLL = 1, BACKGROUND_FIXED } background_attachment;
|
||||
colour background_color;
|
||||
/* char background_image[100]; */
|
||||
/* background-position */
|
||||
enum { BACKGROUND_REPEAT = 1, BACKGROUND_REPEAT_X,
|
||||
BACKGROUND_REPEAT_Y, BACKGROUND_NO_REPEAT } background_repeat;
|
||||
/* borders */
|
||||
enum { CLEAR_NONE = 1, CLEAR_BOTH, CLEAR_LEFT, CLEAR_RIGHT } clear;
|
||||
colour color;
|
||||
/* font-family */
|
||||
enum { FONT_STRAIGHT, FONT_OBLIQUE, FONT_ITALIC } font_style;
|
||||
enum { FONT_NORMAL, FONT_SMALLCAPS } font_variant;
|
||||
struct {
|
||||
enum { WEIGHT_ABSOLUTE, WEIGHT_BOLDER, WEIGHT_LIGHTER } weight;
|
||||
unsigned int value;
|
||||
} font_weight;
|
||||
};
|
||||
|
||||
struct css_stylesheet;
|
||||
|
||||
struct css_selector {
|
||||
char * element;
|
||||
char * class;
|
||||
char * id;
|
||||
};
|
||||
|
||||
/**
|
||||
* interface
|
||||
*/
|
||||
|
||||
struct css_stylesheet * css_new_stylesheet(void);
|
||||
void css_get_style(struct css_stylesheet * stylesheet, struct css_selector * selector,
|
||||
unsigned int selectors, struct css_style * style);
|
||||
void css_parse_stylesheet(struct css_stylesheet * stylesheet, char * str);
|
||||
void css_dump_style(const struct css_style * const style);
|
||||
void css_cascade(struct css_style * const style, const struct css_style * const apply);
|
22
render/css_enums
Normal file
22
render/css_enums
Normal file
@ -0,0 +1,22 @@
|
||||
css_unit em ex px in cm mm pt pc
|
||||
css_background_attachment inherit fixed scroll
|
||||
css_background_position inherit top center bottom left right length percent
|
||||
css_background_repeat inherit repeat repeat_x repeat_y no_repeat
|
||||
css_border_width inherit medium thin thick length
|
||||
css_border_style inherit none dashed dotted double groove inset outset ridge solid
|
||||
css_clear none both left right
|
||||
css_display block inline none
|
||||
css_float none left right
|
||||
css_font_style normal italic oblique
|
||||
css_font_variant normal smallcaps
|
||||
css_font_weight normal bold bolder lighter 100 200 300 400 500 600 700 800 900
|
||||
css_letter_spacing normal length
|
||||
css_line_height normal length number percent
|
||||
css_list_style_position outside inside
|
||||
css_list_style_type disc circle square decimal lower_alpha lower_roman upper_alpha upper_roman none
|
||||
css_margin auto length percent
|
||||
css_text_align left right center justify
|
||||
css_text_decoration none blink line_through overline underline
|
||||
css_text_transform none capitalize lowercase uppercase
|
||||
css_vertical_align baseline bottom middle sub super text_bottom text_top top percent
|
||||
css_white_space normal nowrap pre
|
36
render/makeenum
Normal file
36
render/makeenum
Normal file
@ -0,0 +1,36 @@
|
||||
#!/usr/bin/perl -W
|
||||
# $Id: makeenum,v 1.1.1.1 2002/04/22 09:24:34 bursa Exp $
|
||||
|
||||
$out = shift or die "usage: makeenum leafname";
|
||||
|
||||
open H, ">$out.h" or die "open 'enum.h' failed";
|
||||
open C, ">$out.c" or die "open 'enum.c' failed";
|
||||
|
||||
print C "#include \"$out.h\"\n\n";
|
||||
|
||||
while (<>) {
|
||||
chomp;
|
||||
@enum = split;
|
||||
$name = shift @enum;
|
||||
|
||||
@uc_enum = map uc, @enum;
|
||||
$uc_name = uc $name;
|
||||
|
||||
print H "extern const char * const ${name}_name[];\n";
|
||||
print H "typedef enum {\n ${uc_name}_";
|
||||
print H join ",\n ${uc_name}_", @uc_enum;
|
||||
print H ",\n ${uc_name}_UNKNOWN\n";
|
||||
print H "} $name;\n";
|
||||
print H "$name ${name}_parse(const char * const s);\n\n";
|
||||
|
||||
print C "/**\n * $name\n */\n\n";
|
||||
print C "const char * const ${name}_name[] = {\n \"";
|
||||
print C join "\",\n \"", @enum;
|
||||
print C "\"\n};\n\n";
|
||||
print C "$name ${name}_parse(const char * const s)\n{\n";
|
||||
foreach $x (@enum) {
|
||||
$ux = uc $x;
|
||||
print C " if (strcmp(s, \"$x\") == 0) return ${uc_name}_$ux;\n";
|
||||
}
|
||||
print C " return ${uc_name}_UNKNOWN;\n}\n\n";
|
||||
}
|
24
render/makefile
Normal file
24
render/makefile
Normal file
@ -0,0 +1,24 @@
|
||||
# $Id: makefile,v 1.1.1.1 2002/04/22 09:24:34 bursa Exp $
|
||||
|
||||
FLAGS = -g -Wall -W -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-qual \
|
||||
-Wcast-align -Wwrite-strings -Wconversion -Wstrict-prototypes -Wmissing-prototypes \
|
||||
-Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -std=c9x
|
||||
CC = gcc
|
||||
|
||||
render: render.o utils.o css.o css_enum.o
|
||||
$(CC) $(FLAGS) `xml2-config --libs` -o render render.o utils.o css.o css_enum.o
|
||||
|
||||
render.o: render.c css.h css_enum.h utils.h
|
||||
$(CC) $(FLAGS) `xml2-config --cflags` -c render.c
|
||||
|
||||
css.o: css.c css.h css_enum.h utils.h
|
||||
$(CC) $(FLAGS) -c css.c
|
||||
|
||||
utils.o: utils.c utils.h
|
||||
$(CC) $(FLAGS) -c utils.c
|
||||
|
||||
css_enum.o: css_enum.c css_enum.h
|
||||
$(CC) $(FLAGS) -c css_enum.c
|
||||
|
||||
css_enum.c css_enum.h: css_enums makeenum
|
||||
./makeenum css_enum < css_enums
|
484
render/render.c
Normal file
484
render/render.c
Normal file
@ -0,0 +1,484 @@
|
||||
/**
|
||||
* $Id: render.c,v 1.1.1.1 2002/04/22 09:24:35 bursa Exp $
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "parser.h" /* libxml */
|
||||
#include "css.h"
|
||||
#include "utils.h"
|
||||
|
||||
/**
|
||||
* internal structures
|
||||
*/
|
||||
|
||||
struct coord {
|
||||
unsigned long x, y;
|
||||
};
|
||||
|
||||
struct data { /* used in _private field of xmlNode */
|
||||
struct css_style * style;
|
||||
unsigned long x, y, width, height;
|
||||
};
|
||||
|
||||
struct box {
|
||||
enum { BOX_BLOCK, BOX_INLINE, BOX_FLOAT } type;
|
||||
enum { CONTENT_BLOCK, CONTENT_INLINE } content;
|
||||
xmlNode * node;
|
||||
struct css_style * style;
|
||||
unsigned long x, y, width, height;
|
||||
const char * text;
|
||||
unsigned int length;
|
||||
struct box * next;
|
||||
struct box * children;
|
||||
struct box * parent;
|
||||
};
|
||||
|
||||
void layout_element(xmlNode * e, unsigned long width);
|
||||
unsigned long layout_element_children(xmlNode * e, unsigned long width);
|
||||
|
||||
/**
|
||||
* convert a struct css_length to pixels
|
||||
*/
|
||||
|
||||
signed long len(struct css_length * length, unsigned long em)
|
||||
{
|
||||
switch (length->unit) {
|
||||
case CSS_UNIT_EM: return length->value * em;
|
||||
case CSS_UNIT_EX: return length->value * em * 0.6;
|
||||
case CSS_UNIT_PX: return length->value;
|
||||
case CSS_UNIT_IN: return length->value * 90.0;
|
||||
case CSS_UNIT_CM: return length->value * 35.0;
|
||||
case CSS_UNIT_MM: return length->value * 3.5;
|
||||
case CSS_UNIT_PT: return length->value * 90.0 / 72.0;
|
||||
case CSS_UNIT_PC: return length->value * 90.0 / 6.0;
|
||||
default: return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* layout algorithm
|
||||
*/
|
||||
|
||||
void layout_element(xmlNode * e, unsigned long width)
|
||||
{
|
||||
struct data * data = (struct data *) e->_private;
|
||||
struct css_style * style = data->style;
|
||||
switch (style->width.width) {
|
||||
case CSS_WIDTH_AUTO:
|
||||
data->width = width;
|
||||
break;
|
||||
case CSS_WIDTH_LENGTH:
|
||||
data->width = len(&style->width.value.length, 10);
|
||||
break;
|
||||
case CSS_WIDTH_PERCENT:
|
||||
data->width = width * style->width.value.percent / 100;
|
||||
break;
|
||||
}
|
||||
data->height = layout_element_children(e, data->width);
|
||||
switch (style->height.height) {
|
||||
case CSS_HEIGHT_AUTO:
|
||||
break;
|
||||
case CSS_HEIGHT_LENGTH:
|
||||
data->height = len(&style->height.length, 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long layout_element_children(xmlNode * e, unsigned long width)
|
||||
{
|
||||
struct coord pos;
|
||||
int inline_mode = 0;
|
||||
xmlNode * c = e->children;
|
||||
xmlNode * next;
|
||||
unsigned long y = 0;
|
||||
struct coord float_left = { 0, 0 }, float_right = { 0, 0 }; /* bottom corner of current float */
|
||||
xmlNode * line; /* first node in current line box */
|
||||
|
||||
printf("layout_element_children: starting %s\n", e->name);
|
||||
|
||||
while (c != 0) {
|
||||
struct data * data = (struct data *) c->_private;
|
||||
next = c->next;
|
||||
switch (c->type) {
|
||||
case XML_ELEMENT_NODE: {
|
||||
struct css_style * style = data->style;
|
||||
printf("element %s: ", c->name);
|
||||
switch (style->float_) {
|
||||
case CSS_FLOAT_NONE:
|
||||
switch (style->display) {
|
||||
case CSS_DISPLAY_BLOCK:
|
||||
printf("block");
|
||||
if (inline_mode) {
|
||||
y = pos.y;
|
||||
inline_mode = 0;
|
||||
printf(" (inline_mode = 0)");
|
||||
}
|
||||
puts("");
|
||||
layout_element(c, width);
|
||||
data->x = 0;
|
||||
data->y = y;
|
||||
y += data->height;
|
||||
break;
|
||||
case CSS_DISPLAY_INLINE:
|
||||
puts("inline");
|
||||
next = c->children;
|
||||
/* TODO: fill x, y, width, height [1] */
|
||||
/* TODO: replaced elements */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CSS_FLOAT_LEFT:
|
||||
puts("float left");
|
||||
layout_element(c, width);
|
||||
data->x = 0;
|
||||
if (inline_mode) {
|
||||
if (data->width <= width - pos.y) {
|
||||
xmlNode * n;
|
||||
for (n = line; n != c;
|
||||
n = n->next ? n->next : n->parent->next) {
|
||||
printf("moving %s\n", n->name);
|
||||
if (n->_private)
|
||||
((struct data *) n->_private)->x +=
|
||||
data->width;
|
||||
}
|
||||
data->y = y;
|
||||
} else {
|
||||
data->y = pos.y;
|
||||
}
|
||||
} else {
|
||||
data->y = y;
|
||||
}
|
||||
float_left.x = data->width;
|
||||
float_left.y = data->y + data->height;
|
||||
break;
|
||||
case CSS_FLOAT_RIGHT:
|
||||
puts("float right");
|
||||
layout_element(c, width);
|
||||
data->x = width - data->width;
|
||||
if (inline_mode) {
|
||||
if (data->width <= width - pos.y) {
|
||||
data->y = y;
|
||||
} else {
|
||||
data->y = pos.y;
|
||||
}
|
||||
} else {
|
||||
data->y = y;
|
||||
}
|
||||
float_right.x = data->x;
|
||||
float_right.y = data->y + data->height;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XML_TEXT_NODE:
|
||||
printf("text: ");
|
||||
if (whitespace(c->content)) {
|
||||
c->_private = 0;
|
||||
puts("whitespace");
|
||||
} else {
|
||||
struct data * data = xcalloc(1, sizeof(struct data));
|
||||
unsigned int x1 = y < float_right.y ? float_right.x : width;
|
||||
if (!inline_mode) {
|
||||
pos.x = y < float_left.y ? float_left.x : 0;
|
||||
pos.y = y;
|
||||
inline_mode = 1;
|
||||
line = c;
|
||||
printf("(inline_mode = 1)");
|
||||
}
|
||||
puts("");
|
||||
c->_private = data;
|
||||
data->height = 2;
|
||||
data->width = strlen(c->content) + 1;
|
||||
/* space available is pos.x to x1 */
|
||||
if (x1 - pos.x < data->width) {
|
||||
/* insufficient space: start new line */
|
||||
y = pos.y;
|
||||
pos.x = y < float_left.y ? float_left.x : 0;
|
||||
line = c;
|
||||
}
|
||||
data->x = pos.x;
|
||||
data->y = y;
|
||||
pos.x += data->width;
|
||||
pos.y = y + 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while (next == 0 && c->parent != e)
|
||||
/* TODO: fill coords of just finished inline element [1] */
|
||||
c = c->parent, next = c->next;
|
||||
c = next;
|
||||
}
|
||||
if (inline_mode) y = pos.y;
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
void render_plain_element(char *g, xmlNode *e, unsigned long x, unsigned long y)
|
||||
{
|
||||
unsigned long i;
|
||||
unsigned int l;
|
||||
xmlNode *c;
|
||||
struct data * data = e->_private;
|
||||
|
||||
for (c = e->children; c != 0; c = c->next)
|
||||
render_plain_element(g, c, x + data->x, y + data->y);
|
||||
|
||||
if (data == 0) return;
|
||||
|
||||
// printf("render_plain_element: x0 %li y0 %li x1 %li y1 %li\n", data->x0, data->y0, data->x1, data->y1);
|
||||
|
||||
for (i = (y + data->y) + 1; i < (y + data->y + data->height); i++) {
|
||||
g[80 * i + (x + data->x)] = '|';
|
||||
g[80 * i + (x + data->x + data->width)] = '|';
|
||||
}
|
||||
|
||||
// if (e->style->display != INLINE) {
|
||||
for (i = (x + data->x); i < (x + data->x + data->width); i++) {
|
||||
g[80 * (y + data->y) + i] = '-';
|
||||
g[80 * (y + data->y + data->height) + i] = '-';
|
||||
}
|
||||
g[80 * (y + data->y) + (x + data->x)] = '+';
|
||||
g[80 * (y + data->y) + (x + data->x + data->width)] = '+';
|
||||
g[80 * (y + data->y + data->height) + (x + data->x)] = '+';
|
||||
g[80 * (y + data->y + data->height) + (x + data->x + data->width)] = '+';
|
||||
// }
|
||||
|
||||
if (e->type == XML_TEXT_NODE && e->content) {
|
||||
l = strlen(e->content);
|
||||
if ((x + data->x + data->width) - (x + data->x) - 1 < l)
|
||||
l = (x + data->x + data->width) - (x + data->x) - 1;
|
||||
strncpy(g + 80 * ((y + data->y) + 1) + (x + data->x) + 1, e->content, l);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void render_plain(xmlNode *doc)
|
||||
{
|
||||
int i;
|
||||
char *g;
|
||||
|
||||
g = calloc(10000, 1);
|
||||
if (g == 0) exit(1);
|
||||
|
||||
for (i = 0; i < 10000; i++)
|
||||
g[i] = ' ';
|
||||
|
||||
render_plain_element(g, doc, 0, 0);
|
||||
|
||||
for (i = 0; i < 40; i++)
|
||||
printf("%.80s\n", g + (80 * i));
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
void walk(xmlNode *n, unsigned int depth)
|
||||
{
|
||||
xmlNode *c;
|
||||
xmlAttr *a;
|
||||
struct data * data;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < depth; i++)
|
||||
printf(" ");
|
||||
|
||||
data = n->_private;
|
||||
|
||||
switch (n->type) {
|
||||
case XML_ELEMENT_NODE:
|
||||
if (data == 0)
|
||||
printf("ELEMENT %s", n->name);
|
||||
else
|
||||
printf("ELEMENT %s [%li %li %li*%li]", n->name, data->x,
|
||||
data->y, data->width, data->height);
|
||||
/* for (a = n->properties; a != 0; a = a->next) {
|
||||
assert(a->type == XML_ATTRIBUTE_NODE);
|
||||
printf(" %s='", a->name);
|
||||
for (c = a->children; c != 0; c = c->next)
|
||||
walk(c);
|
||||
printf("'");
|
||||
}*/
|
||||
printf("\n");
|
||||
for (c = n->children; c != 0; c = c->next)
|
||||
walk(c, depth + 1);
|
||||
// printf("</%s>", n->name);
|
||||
break;
|
||||
|
||||
case XML_TEXT_NODE:
|
||||
if (data == 0)
|
||||
printf("TEXT '%s'\n", n->content);
|
||||
else
|
||||
printf("TEXT [%li %li %li*%li] '%s'\n", data->x, data->y,
|
||||
data->width, data->height, n->content);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("UNHANDLED\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* make a box tree with style data from an xml tree
|
||||
*/
|
||||
|
||||
struct box * make_box(xmlNode * n, struct css_style * style, struct css_stylesheet * stylesheet,
|
||||
struct css_selector ** selector, unsigned int depth,
|
||||
struct box * parent, struct box * prev, struct box * containing_block,
|
||||
struct box ** inline_parent)
|
||||
{
|
||||
struct box * box = xcalloc(1, sizeof(struct box));
|
||||
xmlNode * c;
|
||||
unsigned int i;
|
||||
|
||||
box->node = n;
|
||||
box->parent = parent;
|
||||
|
||||
if (n->type == XML_ELEMENT_NODE) {
|
||||
*selector = xrealloc(*selector, (depth + 1) * sizeof(struct css_selector));
|
||||
(*selector)[depth].element = n->name;
|
||||
(*selector)[depth].class = (*selector)[depth].id = 0;
|
||||
|
||||
box->style = xcalloc(1, sizeof(struct css_style));
|
||||
memcpy(box->style, style, sizeof(struct css_style));
|
||||
css_get_style(stylesheet, *selector, depth + 1, box->style);
|
||||
|
||||
switch (box->style->display) {
|
||||
case CSS_DISPLAY_BLOCK:
|
||||
box->type = BOX_BLOCK;
|
||||
break;
|
||||
case CSS_DISPLAY_INLINE:
|
||||
box->type = BOX_INLINE;
|
||||
break;
|
||||
case CSS_DISPLAY_NONE:
|
||||
default:
|
||||
free(box->style);
|
||||
free(box);
|
||||
return 0;
|
||||
}
|
||||
} else if (n->type == XML_TEXT_NODE) {
|
||||
/* anonymous inline box */
|
||||
box->type = BOX_INLINE;
|
||||
}
|
||||
|
||||
for (i = 0; i < depth; i++)
|
||||
printf(" ");
|
||||
printf("make_box: %s: %s\n", box->type == BOX_INLINE ? "inline" : "block", n->name);
|
||||
|
||||
if (*inline_parent && box->type == BOX_BLOCK) {
|
||||
/* block following inline: end inline_parent */
|
||||
printf("ending anonymous container for inlines\n");
|
||||
(*inline_parent)->next = box;
|
||||
*inline_parent = 0;
|
||||
} else if (*inline_parent && box->type == BOX_INLINE) {
|
||||
/* inline following inline */
|
||||
prev->next = box;
|
||||
} else if (!(*inline_parent) && box->type == BOX_BLOCK) {
|
||||
/* block following block */
|
||||
if (prev) prev->next = box;
|
||||
} else if (!(*inline_parent) && box->type == BOX_INLINE) {
|
||||
/* inline following block: create anonymous container block */
|
||||
printf("starting anonymous container for inlines\n");
|
||||
*inline_parent = xcalloc(1, sizeof(struct box));
|
||||
(*inline_parent)->parent = parent;
|
||||
if (prev) prev->next = *inline_parent;
|
||||
(*inline_parent)->children = box;
|
||||
}
|
||||
|
||||
|
||||
/* for (i = 0; i < depth; i++)
|
||||
printf(" ");
|
||||
printf("%s ", n->name);
|
||||
css_dump_style(data->style);*/
|
||||
|
||||
{
|
||||
struct box * prev_c;
|
||||
struct box * b;
|
||||
struct box * containing;
|
||||
struct box * inline_parent_c = 0;
|
||||
|
||||
if (box->type == BOX_BLOCK) {
|
||||
prev_c = 0;
|
||||
containing = box;
|
||||
} else {
|
||||
prev_c = box;
|
||||
containing = containing_block;
|
||||
}
|
||||
|
||||
for (c = n->children; c != 0; c = c->next) {
|
||||
b = make_box(c, box->style, stylesheet, selector, depth + 1,
|
||||
box, prev_c, containing, &inline_parent_c);
|
||||
if (!box->children) box->children = b;
|
||||
if (b) prev_c = b;
|
||||
}
|
||||
}
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
|
||||
void dump_box(struct box * box, unsigned int depth)
|
||||
{
|
||||
unsigned int i;
|
||||
struct box * c;
|
||||
|
||||
for (i = 0; i < depth; i++)
|
||||
printf(" ");
|
||||
|
||||
printf("%s: %s\n", box->type == BOX_INLINE ? "inline" : "block",
|
||||
box->node->name);
|
||||
|
||||
for (c = box->children; c != 0; c = c->next)
|
||||
dump_box(c, depth + 1);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* struct layout canvas = { 0, 0, 79, 0 }; */
|
||||
|
||||
struct css_stylesheet * stylesheet;
|
||||
struct css_style * style = xcalloc(1, sizeof(struct css_style));
|
||||
struct css_selector * selector = xcalloc(1, sizeof(struct css_selector));
|
||||
xmlNode * c;
|
||||
xmlDoc * doc;
|
||||
struct box * box;
|
||||
struct box * inline_parent = 0;
|
||||
|
||||
doc = xmlParseFile(argv[1]);
|
||||
if (doc == 0) die("xmlParseFile failed");
|
||||
|
||||
for (c = doc->children; c != 0 && c->type != XML_ELEMENT_NODE; c = c->next)
|
||||
;
|
||||
if (c == 0) die("no element in document");
|
||||
if (strcmp(c->name, "html")) die("document is not html");
|
||||
|
||||
stylesheet = css_new_stylesheet();
|
||||
css_parse_stylesheet(stylesheet, load(argv[2]));
|
||||
|
||||
box = make_box(c, style, stylesheet, &selector, 0, 0, 0, 0, &inline_parent);
|
||||
dump_box(box, 0);
|
||||
|
||||
/* walk(c, 0);
|
||||
layout_element(c, 79);
|
||||
walk(c, 0);
|
||||
printf("\n\n");
|
||||
render_plain(c);*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
75
utils/utils.c
Normal file
75
utils/utils.c
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* $Id: utils.c,v 1.1.1.1 2002/04/22 09:24:34 bursa Exp $
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "utils.h"
|
||||
|
||||
void die(const char * const error)
|
||||
{
|
||||
fprintf(stderr, "Fatal: %s\n", error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char * strip(char * const s)
|
||||
{
|
||||
size_t i;
|
||||
for (i = strlen(s); i != 0 && isspace(s[i-1]); i--)
|
||||
;
|
||||
s[i] = 0;
|
||||
return s + strspn(s, " \t\r\n");
|
||||
}
|
||||
|
||||
int whitespace(const char * str)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < strlen(str); i++)
|
||||
if (!isspace(str[i]))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void * xcalloc(const size_t n, const size_t size)
|
||||
{
|
||||
void * p = calloc(n, size);
|
||||
if (p == 0) die("Out of memory in xcalloc()");
|
||||
return p;
|
||||
}
|
||||
|
||||
void * xrealloc(void * p, const size_t size)
|
||||
{
|
||||
p = realloc(p, size);
|
||||
if (p == 0) die("Out of memory in xrealloc()");
|
||||
return p;
|
||||
}
|
||||
|
||||
char * xstrdup(const char * const s)
|
||||
{
|
||||
char * c = malloc(strlen(s) + 1);
|
||||
if (c == 0) die("Out of memory in xstrdup()");
|
||||
strcpy(c, s);
|
||||
return c;
|
||||
}
|
||||
|
||||
#define CHUNK 0x100
|
||||
|
||||
char * load(const char * const path)
|
||||
{
|
||||
FILE * fp = fopen(path, "r");
|
||||
unsigned int l = 0;
|
||||
char * buf = malloc(CHUNK);
|
||||
if (buf == 0) die("Out of memory in load()");
|
||||
while (1) {
|
||||
unsigned int i;
|
||||
for (i = 0; i != CHUNK && (buf[l] = fgetc(fp)) != EOF; i++, l++)
|
||||
;
|
||||
if (i != CHUNK) break;
|
||||
buf = xrealloc(buf, l + CHUNK);
|
||||
}
|
||||
buf[l] = 0;
|
||||
fclose(fp);
|
||||
return buf;
|
||||
}
|
11
utils/utils.h
Normal file
11
utils/utils.h
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* $Id: utils.h,v 1.1.1.1 2002/04/22 09:24:34 bursa Exp $
|
||||
*/
|
||||
|
||||
void die(const char * const error);
|
||||
char * strip(char * const s);
|
||||
int whitespace(const char * str);
|
||||
void * xcalloc(const size_t n, const size_t size);
|
||||
void * xrealloc(void * p, const size_t size);
|
||||
char * xstrdup(const char * const s);
|
||||
char * load(const char * const path);
|
Loading…
Reference in New Issue
Block a user