diff options
Diffstat (limited to 'src/storycode.c')
-rw-r--r-- | src/storycode.c | 341 |
1 files changed, 297 insertions, 44 deletions
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; } |