first working version with minimal syntax (check test.nhtml)

This commit is contained in:
Julian Daube 2017-08-08 17:29:01 +02:00
parent 7a9a3ca64a
commit a4674d7eee
3 changed files with 214 additions and 50 deletions

View File

@ -1,8 +1,10 @@
OBJ:= main.o OBJ:= html.o main.o
OUTPUT:=nhtmlc OUTPUT:=nhtmlc
debug: CXXFLAGS = -g all: debug
debug: CFLAGS = -g
debug: CXXFLAGS = -g -DDEBUG
debug: CFLAGS = -g -DDEBUG
debug: $(OBJ) debug: $(OBJ)
gcc $(OBJ) -g -o $(OUTPUT) gcc $(OBJ) -g -o $(OUTPUT)

218
main.c
View File

@ -2,6 +2,12 @@
#include <stdlib.h> // needs: realloc, malloc, free #include <stdlib.h> // needs: realloc, malloc, free
#include <string.h> // needs: strcmp, memcpy #include <string.h> // needs: strcmp, memcpy
#include <errno.h> #include <errno.h>
#include <ctype.h> // needs: isspace
#include <getopt.h> // needs: getopt_long
#include "html.h" // needs: html_escaped
typedef struct { typedef struct {
char * c_str; char * c_str;
size_t len; size_t len;
@ -23,6 +29,7 @@ int string_append(string_t *str, char c) {
str->c_str[str->len-1] = c; str->c_str[str->len-1] = c;
str->c_str[str->len] = 0; // make sure str->c_str[str->len] = 0; // make sure
str->len++; str->len++;
return 0;
} }
void string_destroy(string_t s) { void string_destroy(string_t s) {
@ -62,6 +69,8 @@ attr_t * attr_set_find(attr_set_t *set, const char * name) {
// Append new Attribute to set // Append new Attribute to set
int attr_set_append(attr_set_t * set, attr_t *new_entry) { int attr_set_append(attr_set_t * set, attr_t *new_entry) {
if (new_entry->name.c_str== NULL) return -1; // reject empty entries
// search first // search first
attr_t * new_ptr = attr_set_find(set, new_entry->name.c_str); attr_t * new_ptr = attr_set_find(set, new_entry->name.c_str);
if (new_ptr != NULL) { if (new_ptr != NULL) {
@ -84,15 +93,90 @@ int attr_set_append(attr_set_t * set, attr_t *new_entry) {
return 0; return 0;
} }
void attr_reset(attr_t * attr) {
memset(attr, 0, sizeof(attr_t));
}
int strip(FILE * stream) {
int current = 0;
while((current = fgetc(stream)) != EOF) {
if (!isspace(current))
break;
}
return current;
}
int parse_attr(FILE * stream, attr_set_t * output) { int parse_attr(FILE * stream, attr_set_t * output) {
fprintf(stderr, "stub: parse_attr\n"); attr_t current_attr = {};
return 0; #ifdef DEBUG
printf("parse_attr\n");
#endif
int buffer = 0;
unsigned char isKey = 1;
while((buffer = fgetc(stream)) != EOF) {
// parse key=value pairs
// check for delim
//if (buffer == ' ' || buffer == '\t' || buffer == '\n'){
if (isspace(buffer)) {
attr_set_append(output, &current_attr);
#ifdef DEBUG
printf("parsed attr: %s=%s\n", current_attr.name.c_str, current_attr.value);
#endif
// reset attribute
attr_reset(&current_attr);
isKey = 1;
continue;
}
if (buffer == '=') {
isKey = 0;
continue;
} else
if (buffer == ']') {
break;
}
if (isKey) {
string_append(&current_attr.name, buffer);
} else {
string_append(&current_attr.value, buffer);
}
}
// append last attribute
attr_set_append(output, &current_attr);
//memset(output, 0, sizeof(attr_set_t));
return strip(stream);
} }
int parse_text(FILE * stream, FILE * output) { int parse_text(FILE * stream, FILE * output) {
// STUB #ifdef DEBUG
fprintf(stderr, "stub: parse_text\n"); printf("parse text\n");
return 0; #endif
int buffer = 0;
char escaped = 0;
while((buffer = fgetc(stream)) != EOF) {
if (!escaped && buffer == '\\') {
escaped = 1;
continue;
}
if (!escaped && buffer == '"') {
break;
}
escaped = 0;
if (html_escape(buffer, output)) {
continue;
}
fputc(buffer, output);
}
//fprintf(stderr, "stub: parse_text\n");
return strip(stream);
} }
typedef struct node { typedef struct node {
@ -102,7 +186,10 @@ typedef struct node {
// write out node // write out node
void print_node(node_t * node, FILE * output) { void open_node(node_t * node, FILE * output) {
// check for empty node (text mostly)
if (!node->name.c_str) return;
// start by writing tag // start by writing tag
fputc('<', output); fputc('<', output);
@ -113,43 +200,99 @@ void print_node(node_t * node, FILE * output) {
size_t i = 0; size_t i = 0;
attr_t * current = node->attributes.arr; attr_t * current = node->attributes.arr;
for (; i < node->attributes.len; i++,current++) { for (; i < node->attributes.len; i++,current++) {
fprintf(output, " %s=\"%s\"", current->name.c_str, current->value.c_str); if (current->value.c_str)
fprintf(output, " %s=\"%s\"", current->name.c_str, current->value.c_str);
else {
fputc(' ', output);
fputs(current->name.c_str, output);
}
} }
// close tag // close tag
fputc('>', output); fputc('>', output);
} }
void close_node(node_t * node, FILE * output) {
if (node->name.c_str) {
fprintf(output, "</%s>", node->name.c_str);
}
}
int print_tag(FILE * stream, FILE * output) { int readName(FILE *stream, node_t *node) {
node_t new_node; int current = strip(stream);
int buffer = 0; if (current == EOF) {
return current;
while ((buffer = fgetc(stream)) != EOF) {
switch(buffer) {
case '[': // parse attributes
if (parse_attr(stream, &new_node.attributes) != -1) {
fprintf(stderr, "could not parse attributes: %d", -1);
return -1;
}
break;
case '"':
// raw text
parse_text(stream, output);
break;
default:
if (buffer != ' ' && buffer != '\t' && buffer != '\n') {
string_append(&new_node.name, buffer);
}
}
} }
do {
return 0; if (current == '{' || current == '[') {
break;
}
if (current == ' ' || current == '\t' || current == '\n') {
current = strip(stream);
break;
}
string_append(&node->name, current);
} while((current = fgetc(stream)) != EOF);
return current;
}
enum node_type {
NODE_SELFCLOSING,
NODE_TEXT,
NODE_TAG
};
int parse_node(int current, FILE * stream, FILE * output) {
if (current == '"') {
return parse_text(stream, output);
}
// normal node
node_t current_node = {};
string_append(&current_node.name, current);
current = readName(stream, &current_node);
if (current == EOF) {
goto done;
}
#ifdef DEBUG
printf("parse_node: %s\n", current_node.name.c_str);
#endif
if (current == '[') {
current = parse_attr(stream, &current_node.attributes);
}
if (current != '{') {
// tag is selfclosing
open_node(&current_node, output);
return current;
}
current = strip(stream);
open_node(&current_node, output);
while(current != '}' && current != EOF) {
current = parse_node(current, stream, output);
}
close_node(&current_node, output);
done:
return strip(stream);
} }
int main(int argc, char ** args) { int main(int argc, char ** args) {
//getopt_long(argc, args, NULL, NULL, NULL);
char * filename= NULL; char * filename= NULL;
for(;argc != 1; --argc) { FILE * output = fopen("a.html", "w");
if (output == NULL) {
fprintf(stderr, "could not create output file\n");
return -1;
}
for(;argc > 1; --argc) {
filename = args[argc-1]; filename = args[argc-1];
printf("starting conversion of %s\n", filename); printf("starting conversion of %s\n", filename);
@ -160,16 +303,19 @@ int main(int argc, char ** args) {
continue; continue;
} }
while(!feof(handle)) { int current = strip(handle);
if (print_tag(handle, stdout) != 0) {
fprintf(stderr, "error during parsing of node\n"); while((current = parse_node(current, handle, output)) != EOF) {
break; // if () {
} // fprintf(stderr, "error during parsing of node\n");
// break;
// }
} }
fclose(handle); fclose(handle);
} }
fclose(output);
printf("done compiling\n"); printf("done compiling\n");
return 0; return 0;
} }

View File

@ -1,12 +1,28 @@
div { !DOCTYPE[html]
"hi i'm raw text" head {
"I'm raw text too :)" title { "was geht" }
"Including \"escaping\"" meta[charset=utf-8]
}
h1 {
div {
"Another, but bigger font"
"Adding a
new line adds a <br/> :)"
}
} }
body {
h1 { "Alle Meine Endchen schwimmen auf dem See" }
p {
"Alle meine Entchen schwimmen auf dem See,
schwimmen auf dem See,
Köpfchen in das Wasser, Schwänzchen in die Höh'."
}
p {
"Alle meine Täubchen gurren auf dem Dach,
gurren auf dem Dach,
eins fliegt in die Lüfte, fliegen alle nach."
}
p {
"Alle meine Hühner scharren in dem Stroh,
scharren in dem Stroh,
finden sie ein Körnchen, sind sie alle froh."
}
p {
"Alle meine Gänschen watscheln durch den Grund,
watscheln durch den Grund,
suchen in dem Tümpel, werden kugelrund."
}
}