aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.org.uk>2012-09-03 09:02:31 +0200
committerThomas White <taw@bitwiz.org.uk>2012-09-03 09:02:31 +0200
commite855e14baa0c00bb0da4da1aef4d120f10c7a65e (patch)
tree2e46daa98cf0cea9abbaa01250cbd6df4070504c
parent29978f93c0dba6a6a2b164168650620589667fa3 (diff)
"Finished" parser
-rw-r--r--Makefile.am7
-rw-r--r--src/presentation.h1
-rw-r--r--src/storycode.c341
-rw-r--r--src/storycode.h2
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/render_test_sc1.c95
-rw-r--r--tests/storycode_test.c28
7 files changed, 427 insertions, 48 deletions
diff --git a/Makefile.am b/Makefile.am
index 30d789a..a6003a8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,10 +25,13 @@ icons_DATA = data/colloquium-select.svg data/colloquium-text.svg \
EXTRA_DIST += $(colloquium_DATA)
-noinst_PROGRAMS = tests/storycode_test tests/render_test
-TESTS = tests/storycode_test tests/render_test
+noinst_PROGRAMS = tests/storycode_test tests/render_test tests/render_test_sc1
+TESTS = tests/storycode_test tests/render_test tests/render_test_sc1
tests_storycode_test_SOURCES = tests/storycode_test.c src/storycode.c
tests_render_test_SOURCES = tests/render_test.c src/storycode.c src/render.c \
src/layout.c
+
+tests_render_test_sc1_SOURCES = tests/render_test_sc1.c src/storycode.c \
+ src/render.c src/layout.c
diff --git a/src/presentation.h b/src/presentation.h
index 64e6d79..73eb5b3 100644
--- a/src/presentation.h
+++ b/src/presentation.h
@@ -57,6 +57,7 @@ struct frame
struct frame **rendering_order;
int num_ro;
+ int max_ro;
char *sc; /* Storycode */
diff --git a/src/storycode.c b/src/storycode.c
index b9dfb20..d843128 100644
--- a/src/storycode.c
+++ b/src/storycode.c
@@ -28,6 +28,7 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include "storycode.h"
#include "presentation.h"
@@ -136,91 +137,343 @@ static int sc_block_list_add(SCBlockList *bl,
bl->blocks[bl->n_blocks].options = options;
bl->blocks[bl->n_blocks].contents = contents;
bl->n_blocks++;
+
return 0;
}
-SCBlockList *sc_find_blocks(const char *sc, const char *blockname)
+static int get_subexpr(const char *sc, char *bk, char **pcontents, int *err)
{
- SCBlockList *bl;
- const char *pos;
- char label[1024];
+ size_t ml;
+ int i;
+ int bct = 1;
+ int found = 0;
+ char *contents;
- bl = sc_block_list_new();
- if ( bl == NULL ) return NULL;
+ *err = 0;
- if ( strlen(blockname) > 1021 ) {
- fprintf(stderr, "Block name '%s' too long.\n", blockname);
- return NULL;
+ ml = strlen(sc);
+ contents = malloc(ml+1);
+ if ( contents == NULL ) {
+ *err = -1;
+ return 0;
}
+ *pcontents = contents;
+
+ for ( i=0; i<ml; i++ ) {
+ if ( sc[i] == bk[0] ) {
+ bct++;
+ } else if ( sc[i] == bk[1] ) {
+ bct--;
+ }
+ if ( bct == 0 ) {
+ found = 1;
+ break;
+ }
+ contents[i] = sc[i];
+ }
+
+ if ( (!found) || (bct != 0) ) {
+ *err = 1;
+ return 0;
+ }
+
+ contents[i] = '\0';
+ return i+1;
+}
+
- strcpy(label, "\\");
- strcat(label, blockname);
- strcat(label, "{");
+static size_t read_block(const char *sc, char **pname, char **options,
+ char **contents, int *err)
+{
+ size_t l, i, j;
+ char *name;
+ int done;
+
+ *err = 0;
+
+ l = strlen(sc);
+ i = 0; j = 0;
+ name = malloc(l+1);
+ if ( name == NULL ) {
+ *err = 1;
+ return 0;
+ }
- pos = sc;
+ done = 0;
do {
- pos = strstr(pos, label);
+ char c = sc[i];
- if ( pos != NULL ) {
+ if ( isalnum(c) ) {
+ name[j++] = c;
+ i++;
+ } else {
+ /* Found the end of the name */
+ done = 1;
+ }
- int i;
- int bct = 1;
- int found = 0;
- int ml = strlen(pos);
+ } while ( !done && (i<l) );
- pos += strlen(label);
+ name[j] = '\0';
- for ( i=0; i<ml; i++ ) {
- if ( pos[i] == '{' ) {
- bct++;
- } else if ( pos[i] == '}' ) {
- bct--;
- }
- if ( bct == 0 ) {
- found = 1;
- break;
+ if ( !done ) {
+ *err = 1;
+ printf("Couldn't find end of block beginning '%s'\n", sc);
+ return 0;
+ }
+ *pname = name;
+
+ if ( sc[i] == '[' ) {
+
+ i += get_subexpr(sc+i+1, "[]", options, err) + 1;
+ if ( *err ) {
+ printf("Couldn't find end of options '%s'\n", sc+i);
+ return 0;
+ }
+
+ } else {
+ *options = NULL;
+ }
+
+ if ( sc[i] == '{' ) {
+
+ i += get_subexpr(sc+i+1, "{}", contents, err) + 1;
+ if ( *err ) {
+ printf("Couldn't find end of content '%s'\n", sc+i);
+ return 0;
+ }
+
+ } else {
+ *contents = NULL;
+ }
+
+ return i+1;
+}
+
+
+SCBlockList *sc_find_blocks(const char *sc, const char *blockname)
+{
+ SCBlockList *bl;
+ char *tbuf;
+ size_t len, i, j;
+
+ bl = sc_block_list_new();
+ if ( bl == NULL ) return NULL;
+
+ len = strlen(sc);
+ tbuf = malloc(len+1);
+ if ( tbuf == NULL ) {
+ sc_block_list_free(bl);
+ return NULL;
+ }
+
+ i = 0; j = 0;
+ do {
+
+ if ( sc[i] == '\\' ) {
+
+ int err;
+ char *name = NULL;
+ char *options = NULL;
+ char *contents = NULL;
+
+ if ( (blockname == NULL) && (j != 0) ) {
+ tbuf[j] = '\0';
+ if ( sc_block_list_add(bl, NULL, NULL,
+ strdup(tbuf)) )
+ {
+ fprintf(stderr,
+ "Failed to add block.\n");
+ sc_block_list_free(bl);
+ free(tbuf);
+ return NULL;
}
+ j = 0;
}
- if ( (!found) || (bct != 0) ) {
- fprintf(stderr, "Parse error while looking for"
- " block '%s'\n", blockname);
+ i += read_block(sc+i+1, &name, &options, &contents,
+ &err);
+ if ( err ) {
+ printf("Parse error\n");
sc_block_list_free(bl);
+ free(tbuf);
return NULL;
}
- /* FIXME: Find options */
-
- if ( sc_block_list_add(bl, strdup(blockname), NULL,
- strndup(pos, i)) )
+ if ( (blockname == NULL)
+ || ((blockname != NULL) && !strcmp(blockname, name)) )
{
- fprintf(stderr, "Failed to add block.\n");
- sc_block_list_free(bl);
- return NULL;
+ if ( sc_block_list_add(bl, name, options,
+ contents) )
+ {
+ fprintf(stderr,
+ "Failed to add block.\n");
+ sc_block_list_free(bl);
+ free(tbuf);
+ return NULL;
+ }
}
- pos += i+1;
- printf("Remaining text '%s'\n", pos);
+ } else {
+ tbuf[j++] = sc[i++];
}
- } while ( pos != NULL );
+ } while ( i<len );
+
+ if ( (blockname == NULL) && (j != 0) ) {
+ tbuf[j] = '\0';
+ if ( sc_block_list_add(bl, NULL, NULL, tbuf) )
+ {
+ fprintf(stderr,
+ "Failed to add block.\n");
+ sc_block_list_free(bl);
+ free(tbuf);
+ return NULL;
+ }
+ j = 0;
+ }
return bl;
}
+static char *remove_blocks(const char *in, const char *blockname)
+{
+ SCBlockList *bl;
+ SCBlockListIterator *iter;
+ char *out;
+ struct scblock *b;
+
+ bl = sc_find_blocks(in, NULL);
+ if ( bl == NULL ) {
+ printf("Failed to find blocks.\n");
+ return NULL;
+ }
+
+ out = malloc(strlen(in)+1);
+ if ( out == NULL ) return NULL;
+ out[0] = '\0';
+
+ for ( b = sc_block_list_first(bl, &iter);
+ b != NULL;
+ b = sc_block_list_next(bl, iter) )
+ {
+ if ( b->name == NULL ) {
+ strcat(out, b->contents);
+ } else {
+
+ if ( strcmp(blockname, b->name) != 0 ) {
+ strcat(out, "\\");
+ strcat(out, b->name);
+ if ( b->options != NULL ) {
+ strcat(out, "[");
+ strcat(out, b->options);
+ strcat(out, "]");
+ }
+ if ( b->contents != NULL ) {
+ strcat(out, "{");
+ strcat(out, b->contents);
+ strcat(out, "}");
+ }
+
+ if ( (b->options == NULL)
+ && (b->contents == NULL) ) {
+ strcat(out, " ");
+ }
+
+ }
+
+ }
+ }
+ sc_block_list_free(bl);
+
+ return out;
+}
+
+
+static int alloc_ro(struct frame *fr)
+{
+ struct frame **new_ro;
+
+ new_ro = realloc(fr->rendering_order,
+ fr->max_ro*sizeof(struct frame *));
+ if ( new_ro == NULL ) return 1;
+
+ fr->rendering_order = new_ro;
+
+ return 0;
+}
+
+
+static struct frame *frame_new()
+{
+ struct frame *n;
+
+ n = calloc(1, sizeof(struct frame));
+ if ( n == NULL ) return NULL;
+
+ n->rendering_order = NULL;
+ n->max_ro = 32;
+ alloc_ro(n);
+
+ n->num_ro = 1;
+ n->rendering_order[0] = n;
+
+ return n;
+}
+
+
+static struct frame *add_subframe(struct frame *fr, char *sc)
+{
+ struct frame *n;
+
+ n = frame_new();
+ if ( n == NULL ) return NULL;
+
+ if ( fr->num_ro == fr->max_ro ) {
+ fr->max_ro += 32;
+ if ( alloc_ro(fr) ) return NULL;
+ }
+
+ fr->rendering_order[fr->num_ro++] = fr;
+
+ return fr;
+}
+
+
+static void recursive_unpack(struct frame *fr, const char *sc)
+{
+ SCBlockList *bl;
+ SCBlockListIterator *iter;
+ struct scblock *b;
+
+ bl = sc_find_blocks(sc, "f");
+
+ for ( b = sc_block_list_first(bl, &iter);
+ b != NULL;
+ b = sc_block_list_next(bl, iter) )
+ {
+ struct frame *sfr;
+ sfr = add_subframe(fr, remove_blocks(sc, "f"));
+ recursive_unpack(sfr, b->contents);
+ }
+ sc_block_list_free(bl);
+}
+
+
/* Unpack level 2 StoryCode (content + subframes) into frames */
struct frame *sc_unpack(const char *sc)
{
struct frame *fr;
- fr = calloc(1, sizeof(struct frame));
+ fr = frame_new();
if ( fr == NULL ) return NULL;
-
+ fr->sc = remove_blocks(sc, "f");
+ printf("Top frame: '%s'\n", fr->sc);
+ recursive_unpack(fr, sc);
return fr;
}
diff --git a/src/storycode.h b/src/storycode.h
index 6ba5e45..97d22f8 100644
--- a/src/storycode.h
+++ b/src/storycode.h
@@ -44,4 +44,6 @@ struct scblock *sc_block_list_next(SCBlockList *bl, SCBlockListIterator *iter);
extern SCBlockList *sc_find_blocks(const char *sc, const char *blockname);
extern void sc_block_list_free(SCBlockList *bl);
+extern struct frame *sc_unpack(const char *sc);
+
#endif /* STORYCODE_H */
diff --git a/tests/.gitignore b/tests/.gitignore
index 5549a63..b352eb3 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -3,3 +3,4 @@
.dirstamp
storycode_test
render_test
+render_test_sc1
diff --git a/tests/render_test_sc1.c b/tests/render_test_sc1.c
new file mode 100644
index 0000000..9cbf042
--- /dev/null
+++ b/tests/render_test_sc1.c
@@ -0,0 +1,95 @@
+/*
+ * render_test_sc1.c
+ *
+ * Colloquium - A tiny presentation program
+ *
+ * Copyright (c) 2012 Thomas White <taw@bitwiz.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+#include "../src/storycode.h"
+#include "../src/render.h"
+#include "../src/layout.h"
+#include "../src/stylesheet.h"
+
+
+static gint mw_destroy(GtkWidget *w, void *p)
+{
+ exit(0);
+}
+
+static gboolean draw_sig(GtkWidget *da, cairo_t *cr, struct frame *fr)
+{
+ PangoContext *pc;
+ GtkAllocation allocation;
+ gint w, h;
+
+ w = gtk_widget_get_allocated_width(da);
+ h = gtk_widget_get_allocated_height(da);
+
+ /* Overall background */
+ cairo_rectangle(cr, 0.0, 0.0, w, h);
+ cairo_set_source_rgb(cr, 0.9, 0.9, 0.9);
+ cairo_fill(cr);
+
+ pc = gtk_widget_get_pango_context(da);
+
+ gtk_widget_get_allocation(da, &allocation);
+
+ layout_frame(fr, allocation.width, allocation.height);
+ render_frame(fr, cr, pc);
+
+ return FALSE;
+}
+
+
+int main(int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *drawingarea;
+ struct frame *fr;
+
+ gtk_init(&argc, &argv);
+
+ fr = sc_unpack("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur.\\f{Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.} Wibble Wobble.");
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ drawingarea = gtk_drawing_area_new();
+ gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(drawingarea));
+ gtk_widget_set_size_request(GTK_WIDGET(drawingarea), 320, 200);
+
+ g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(mw_destroy),
+ NULL);
+
+ g_signal_connect(G_OBJECT(drawingarea), "draw",
+ G_CALLBACK(draw_sig), fr);
+
+ gtk_widget_show_all(window);
+ gtk_main();
+
+ return 0;
+}
diff --git a/tests/storycode_test.c b/tests/storycode_test.c
index a39fa72..e9987ef 100644
--- a/tests/storycode_test.c
+++ b/tests/storycode_test.c
@@ -35,14 +35,38 @@ int main(int argc, char *argv[])
SCBlockList *bl;
SCBlockListIterator *iter;
struct scblock *b;
+ const char *tt = "\\bg[a=b]{wibble \\f{wobble}}\\bg{rwawr}Wobble"
+ "\\f{wibble \\bg[muhu]{wobble}}";
- bl = sc_find_blocks("\\bg{wibble \\f{wobble}}\\bg{rwawr}Wobble", "bg");
+ printf("'%s' ->\n", tt);
+ bl = sc_find_blocks(tt, "bg");
+
+ if ( bl == NULL ) {
+ printf("Failed to find blocks.\n");
+ return 1;
+ }
+
+ for ( b = sc_block_list_first(bl, &iter);
+ b != NULL;
+ b = sc_block_list_next(bl, iter) )
+ {
+ printf(" \\%s [%s] {%s}\n", b->name, b->options, b->contents);
+ }
+ sc_block_list_free(bl);
+
+ printf("->\n");
+ bl = sc_find_blocks(tt, NULL);
+
+ if ( bl == NULL ) {
+ printf("Failed to find blocks.\n");
+ return 1;
+ }
for ( b = sc_block_list_first(bl, &iter);
b != NULL;
b = sc_block_list_next(bl, iter) )
{
- printf("'%s'\n", b->contents);
+ printf(" \\%s [%s] {%s}\n", b->name, b->options, b->contents);
}
sc_block_list_free(bl);