From 24c20239779d0ec616adde651c594c7bf08d58c7 Mon Sep 17 00:00:00 2001 From: Thomas White Date: Tue, 19 Feb 2019 18:17:56 +0100 Subject: WIP --- src/sc_parse.c | 856 --------------------------------------------------------- 1 file changed, 856 deletions(-) delete mode 100644 src/sc_parse.c (limited to 'src/sc_parse.c') diff --git a/src/sc_parse.c b/src/sc_parse.c deleted file mode 100644 index 78f5799..0000000 --- a/src/sc_parse.c +++ /dev/null @@ -1,856 +0,0 @@ -/* - * sc_parse.c - * - * Copyright © 2013-2018 Thomas White - * - * This file is part of Colloquium. - * - * Colloquium 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 . - * - */ - - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "sc_parse.h" -#include "utils.h" - -struct _scblock -{ - char *name; - char *options; - char *contents; - - SCBlock *next; - SCBlock *child; -}; - - -SCBlock *sc_block_new() -{ - SCBlock *bl; - - bl = calloc(1, sizeof(SCBlock)); - if ( bl == NULL ) return NULL; - - return bl; -} - - -SCBlock *sc_block_next(const SCBlock *bl) -{ - assert(bl != NULL); - return bl->next; -} - - -SCBlock *sc_block_child(const SCBlock *bl) -{ - return bl->child; -} - - -const char *sc_block_name(const SCBlock *bl) -{ - return bl->name; -} - - -const char *sc_block_options(const SCBlock *bl) -{ - return bl->options; -} - - -const char *sc_block_contents(const SCBlock *bl) -{ - return bl->contents; -} - - -static SCBlock *sc_find_previous(SCBlock *top, SCBlock *find) -{ - if ( top->next == find ) return top; - - if ( top->child != NULL ) { - SCBlock *t = sc_find_previous(top->child, find); - if ( t != NULL ) return t; - } - if ( top->next != NULL ) { - SCBlock *t = sc_find_previous(top->next, find); - if ( t != NULL ) return t; - } - return NULL; -} - - -/* Add a new block before "bl" */ -SCBlock *sc_block_prepend(SCBlock *bl, SCBlock *top) -{ - SCBlock *bln; - SCBlock *prev; - - prev = sc_find_previous(top, bl); - if ( prev == NULL ) { - fprintf(stderr, "Couldn't find previous\n"); - return NULL; - } - - bln = sc_block_new(); - if ( bln == NULL ) return NULL; - - prev->next = bln; - bln->next = bl; - return bln; -} - - -/* Append "bln" after "bl" */ -void sc_block_append_p(SCBlock *bl, SCBlock *bln) -{ - if ( bl != NULL ) { - bln->next = bl->next; - bl->next = bln; - } -} - - -/* Insert a new block after "bl". "name", "options" and "contents" - * will not be copied. Returns the block just created, or NULL on error. - * If *blfp points to NULL, it will updated to point at the new block. */ -SCBlock *sc_block_append(SCBlock *bl, char *name, char *opt, char *contents, - SCBlock **blfp) -{ - SCBlock *bln = sc_block_new(); - - if ( bln == NULL ) return NULL; - - bln->name = name; - bln->options = opt; - bln->contents = contents; - bln->child = NULL; - bln->next = NULL; - - sc_block_append_p(bl, bln); - - if ( (blfp != NULL) && (*blfp == NULL) ) { - *blfp = bln; - } - - return bln; -} - - -/* Insert a new block at the end of the chain starting 'bl'. - * "name", "options" and "contents" will not be copied. Returns the block just - * created, or NULL on error. */ -SCBlock *sc_block_append_end(SCBlock *bl, char *name, char *opt, char *contents) -{ - SCBlock *bln = sc_block_new(); - - if ( bln == NULL ) return NULL; - - while ( bl->next != NULL ) { - bln->next = bl->next; - bl = bl->next; - }; - - return sc_block_append(bl, name, opt, contents, NULL); -} - - -void sc_block_append_block(SCBlock *bl, SCBlock *bln) -{ - - if ( bl == NULL ) return; - - while ( bl->next != NULL ) bl = bl->next; - - bl->next = bln; - bln->next = NULL; -} - - -/* Append a new block to the chain inside "parent". - * "name", "options" and "contents" will not be copied. Returns the block just - * created, or NULL on error. */ -SCBlock *sc_block_append_inside(SCBlock *parent, - char *name, char *opt, char *contents) -{ - SCBlock *bln; - SCBlock *bl; - SCBlock **ptr; - - bl = parent->child; - if ( bl != NULL ) { - while ( bl->next != NULL ) bl = bl->next; - ptr = &bl->next; - } else { - ptr = &parent->child; - } - - bln = sc_block_new(); - if ( bln == NULL ) return NULL; - - bln->name = name; - bln->options = opt; - bln->contents = contents; - bln->child = NULL; - bln->next = NULL; - - *ptr = bln; - - return bln; -} - - -/* Insert a new block to the chain, just after "afterme". - * "name", "options" and "contents" will not be copied. Returns the block just - * created, or NULL on error. */ -SCBlock *sc_block_insert_after(SCBlock *afterme, - char *name, char *opt, char *contents) -{ - SCBlock *bl; - - bl = sc_block_new(); - if ( bl == NULL ) return NULL; - - bl->name = name; - bl->options = opt; - bl->contents = contents; - bl->child = NULL; - bl->next = afterme->next; - afterme->next = bl; - - return bl; -} - - -static SCBlock *sc_find_parent(SCBlock *top, SCBlock *find) -{ - if ( top->child == find ) return top; - if ( top->next == find ) return top; - - if ( top->child != NULL ) { - SCBlock *t = sc_find_parent(top->child, find); - if ( t != NULL ) return t; - } - if ( top->next != NULL ) { - SCBlock *t = sc_find_parent(top->next, find); - if ( t != NULL ) return t; - } - return NULL; -} - - -/* Unlink "deleteme", which is somewhere under "top" */ -static int sc_block_unlink(SCBlock **top, SCBlock *deleteme) -{ - SCBlock *parent = sc_find_parent(*top, deleteme); - if ( parent == NULL ) { - /* Maybe it's the first block? */ - if ( *top == deleteme ) { - fprintf(stderr, "Unlinking at top\n"); - *top = (*top)->next; - return 0; - } else { - fprintf(stderr, "Couldn't find block parent!\n"); - return 1; - } - } - - if ( parent->next == deleteme ) { - parent->next = deleteme->next; - } - - if ( parent->child == deleteme ) { - parent->child = deleteme->next; - } - return 0; -} - - -/* Delete "deleteme", which is somewhere under "top" */ -int sc_block_delete(SCBlock **top, SCBlock *deleteme) -{ - int r; - r = sc_block_unlink(top, deleteme); - if ( !r ) { - sc_block_free(deleteme); - } - return r; -} - - -/* Frees "bl" and all its children (but not the blocks following it) */ -void sc_block_free(SCBlock *bl) -{ - if ( bl == NULL ) return; - - if ( bl->child != NULL ) { - SCBlock *ch = bl->child; - while ( ch != NULL ) { - SCBlock *next = ch->next; - sc_block_free(ch); - ch = next; - } - } - - free(bl); -} - - -/* Serialise one block (including children) */ -char *serialise_sc_block(const SCBlock *bl) -{ - char *a; - SCBlock *ch; - size_t len = 3; - - if ( bl == NULL ) return strdup(""); - - if ( bl->name != NULL ) len += 1+strlen(bl->name); - if ( bl->options != NULL ) len += 2+strlen(bl->options); - if ( bl->contents != NULL ) len += 2+strlen(bl->contents); - a = malloc(len); - if ( a == NULL ) return NULL; - a[0] = '\0'; - - if ( bl->name == NULL ) { - strcat(a, bl->contents); - } else if ( strcmp(bl->name, "newpara") == 0 ) { - strcat(a, "\n"); - - } else { - - strcat(a, "\\"); - strcat(a, bl->name); - if ( bl->options != NULL ) { - strcat(a, "["); - strcat(a, bl->options); - strcat(a, "]"); - } - if ( (bl->contents != NULL) || (bl->child != NULL) ) { - strcat(a, "{"); - } - if ( bl->contents != NULL ) { - strcat(a, bl->contents); - } - - /* Special case to prevent "\somethingSome text" */ - if ( (bl->name != NULL) && (bl->options == NULL) - && (bl->contents == NULL) && (bl->next != NULL) - && (bl->next->name == NULL) && (bl->child == NULL) ) - { - strcat(a, "{}"); - } - - } - - /* Add ALL child blocks of this one */ - ch = bl->child; - while ( ch != NULL ) { - - char *anew; - char *c = serialise_sc_block(ch); - if ( c == NULL ) { - free(a); - return NULL; - } - - len += strlen(c); - - anew = realloc(a, len); - if ( anew == NULL ) { - return NULL; - } else { - a = anew; - } - - strcat(a, c); - free(c); - - ch = ch->next; - - } - - if ( (bl->name != NULL) && - ((bl->contents != NULL) || (bl->child != NULL)) ) { - strcat(a, "}"); - } - - return a; -} - - -int save_sc_block(GOutputStream *fh, const SCBlock *bl) -{ - while ( bl != NULL ) { - GError *error = NULL; - char *a = serialise_sc_block(bl); - gssize r; - if ( a == NULL ) { - fprintf(stderr, "Failed to serialise block\n"); - return 1; - } - r = g_output_stream_write(fh, a, strlen(a), NULL, &error); - if ( r == -1 ) { - fprintf(stderr, "Write failed: %s\n", error->message); - return 1; - } - free(a); - bl = bl->next; - } - return 0; -} - - -static void recursive_show_sc_blocks(const char *prefix, const SCBlock *bl) -{ - while ( bl != NULL ) { - show_sc_block(bl, prefix); - bl = bl->next; - } -} - - -void show_sc_block(const SCBlock *bl, const char *prefix) -{ - printf("%s (%p) ", prefix, bl); - if ( bl == NULL ) return; - if ( bl->name != NULL ) printf("\\%s ", bl->name); - if ( bl->options != NULL ) printf("[%s] ", bl->options); - if ( bl->contents != NULL ) printf("{%s} ", bl->contents); - printf("\n"); - - if ( bl->child != NULL ) { - char new_prefix[strlen(prefix)+3]; - strcpy(new_prefix, " "); - strcat(new_prefix, prefix); - recursive_show_sc_blocks(new_prefix, bl->child); - } -} - - -void show_sc_blocks(const SCBlock *bl) -{ - recursive_show_sc_blocks("", bl); -} - - -static int get_subexpr(const char *sc, char *bk, char **pcontents, int *err) -{ - size_t ml; - int i; - int bct = 1; - int found = 0; - char *contents; - - *err = 0; - - ml = strlen(sc); - contents = malloc(ml+1); - if ( contents == NULL ) { - *err = -1; - return 0; - } - *pcontents = contents; - - for ( i=0; iname = strdup("newpara"); - bl->contents = NULL; - nb = bl; - } else { - sc_block_append(bl, strdup("newpara"), - NULL, NULL, &nb); - } - - /* Add any text after the \n */ - if ( strlen(npos+1) > 0 ) { - sc_block_append(nb, NULL, NULL, - strdup(npos+1), &nb); - } - npos[0] = '\0'; - } - } - - if ( sc_block_child(bl) != NULL ) { - separate_newlines(sc_block_child(bl)); - } - - bl = sc_block_next(bl); - - } -} - - -SCBlock *sc_parse(const char *sc) -{ - SCBlock *bl; - SCBlock *blf = NULL; - char *tbuf; - size_t len, i, j; - - if ( sc == NULL ) return NULL; - - if ( strlen(sc) == 0 ) { - SCBlock *bl = sc_block_new(); - sc_block_set_contents(bl, g_strdup("")); - return bl; - } - - bl = NULL; - - len = strlen(sc); - tbuf = malloc(len+1); - if ( tbuf == NULL ) { - sc_block_free(bl); - return NULL; - } - - i = 0; j = 0; - do { - - if ( sc[i] == '\\' ) { - - int err; - char *name = NULL; - char *opt = NULL; - char *contents = NULL; - - /* Is this an escaped backslash? */ - if ( sc[i+1] == '\\' ) { - tbuf[j++] = '\\'; - i += 2; /* Skip both backslashes */ - continue; - } - - /* No, it's a real block. Dispatch the previous block */ - if ( j != 0 ) { - tbuf[j] = '\0'; - bl = sc_block_append(bl, NULL, NULL, - strdup(tbuf), &blf); - if ( bl == NULL ) { - fprintf(stderr, "Block add failed.\n"); - sc_block_free(blf); - free(tbuf); - return NULL; - } - j = 0; - } - - i += read_block(sc+i+1, &name, &opt, &contents, &err); - if ( err ) { - printf(_("Parse error\n")); - sc_block_free(blf); - free(tbuf); - return NULL; - } - - bl = sc_block_append(bl, name, opt, contents, &blf); - if ( bl == NULL ) { - fprintf(stderr, "Block add failed.\n"); - sc_block_free(blf); - free(tbuf); - return NULL; - } - bl->child = sc_parse(contents); - free(bl->contents); - bl->contents = NULL; - - } else { - - tbuf[j++] = sc[i++]; - } - - } while ( i 0 ) { - - /* Leftover buffer is empty? */ - if ( (j==1) && (tbuf[0]=='\0') ) return bl; - - tbuf[j] = '\0'; - bl = sc_block_append(bl, NULL, NULL, tbuf, &blf); - if ( bl == NULL ) { - fprintf(stderr, "Block add failed.\n"); - sc_block_free(blf); - free(tbuf); - return NULL; - } - j = 0; - } - - separate_newlines(blf); - - return blf; -} - - -void sc_block_set_name(SCBlock *bl, char *nam) -{ - if ( bl == NULL ) { - fprintf(stderr, "sc_block_set_name: NULL block\n"); - return; - } - free(bl->name); - bl->name = nam; -} - - -void sc_block_set_options(SCBlock *bl, char *opt) -{ - free(bl->options); - bl->options = opt; -} - - -void sc_block_set_contents(SCBlock *bl, char *con) -{ - g_free(bl->contents); - bl->contents = con; -} - - -void sc_insert_text(SCBlock *b1, size_t o1, const char *t) -{ - size_t len; - char *cnew; - char *tmp; - char *p1; - - if ( b1->contents == NULL ) { - b1->contents = strdup(t); - return; - } - len = strlen(b1->contents)+1+strlen(t); - - cnew = realloc(b1->contents, len); - if ( cnew == NULL ) return; - - tmp = malloc(len); - if ( tmp == NULL ) { - free(cnew); - return; - } - - p1 = cnew + o1; - strcpy(tmp, p1); - strcpy(p1, t); - strcpy(p1+strlen(t), tmp); - free(tmp); - b1->contents = cnew; -} - - -void sc_insert_block(SCBlock *b1, int o1, SCBlock *ins) -{ - SCBlock *second; - char *p1 = g_utf8_offset_to_pointer(b1->contents, o1); - - /* Create a new block containing the second half of b1 */ - second = sc_block_new(); - sc_block_set_contents(second, g_strdup(p1)); - - /* Chop off b1 at the insertion point */ - sc_block_set_contents(b1, g_utf8_substring(b1->contents, 0, o1)); - - /* Link the new block into the chain */ - SCBlock *old_next = b1->next; - b1->next = ins; - ins->next = second; - second->next = old_next; -} - - -/* Delete text from SCBlock contents. o2=-1 means "to the end". - * Returns the number of bytes deleted. */ -size_t scblock_delete_text(SCBlock *b, ssize_t o1, ssize_t o2) -{ - size_t len; - - if ( b->contents == NULL ) { - fprintf(stderr, "Deleting text from block \\%s\n", b->name); - return 0; - } - - if ( (o2 != -1) && (o1 > o2) ) { - ssize_t t = o2; - o2 = o1; - o1 = t; - } - - len = strlen(b->contents); - if ( o2 < 0 ) o2 = len; - if ( (o1 >= o2) || (o1 > len) || (o2 > len) ) { - fprintf(stderr, "Invalid delete: %i %i %i\n", - (int)o1, (int)o2, (int)len); - return 0; - } - memmove(b->contents+o1, b->contents+o2, len-o2+1); - - return o2-o1; -} - - -static char *s_strdup(const char *a) -{ - if ( a == NULL ) return NULL; - return strdup(a); -} - - -SCBlock *sc_block_split(SCBlock *bl, size_t pos) -{ - SCBlock *n = sc_block_new(); - - if ( bl->child != NULL ) { - fprintf(stderr, "Splitting a block with a child!\n"); - return NULL; - } - - /* Second block */ - n->name = s_strdup(bl->name); - n->options = s_strdup(bl->options); - if ( bl->contents != NULL ) { - n->contents = strdup(bl->contents+pos); - /* Truncate the first block */ - bl->contents[pos] = '\0'; - } else { - n->contents = NULL; - } - - n->next = bl->next; - bl->next = n; - - return n; -} - - -/* Return a new block which is the parent for "bl" */ -SCBlock *sc_block_new_parent(SCBlock *bl, const char *name) -{ - SCBlock *n = sc_block_new(); - if ( n == NULL ) return NULL; - n->name = s_strdup(name); - n->child = bl; - return n; -} -- cgit v1.2.3