On Tue, Aug 26, 2014 at 07:56:20PM +0200, Salvo 'LtWorf' Tomaselli wrote: > Not quite the solution I'd want, but the json generation would need > to be re-done from scratch to generate valid json code.
... and that is considered not worth it? > Instead, I wrote this, to find and remove the guilty commas. It tries to > move as little bytes around as possible, and writing it felt like > interviewing for a position at Facebook. I don't know about Facebook's interview process... but I don't think this is the way I would have done this. Why not just do the memmove on the fly while you scan the string? This seems rather fragile to me. /D > --- > save-html.c | 100 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 100 insertions(+) > > diff --git a/save-html.c b/save-html.c > index c3d5073..987bc59 100644 > --- a/save-html.c > +++ b/save-html.c > @@ -1,7 +1,106 @@ > +#include <string.h> > + > #include "save-html.h" > #include "gettext.h" > #include "stdio.h" > > +/** > + * Marks invalid commas inside a json for deletion. > + * > + * buf: json string > + * buf_len: strlen(buf) > + * marked: pointer to int array, where the positions of the > + * commas to delete are marked > + * marked_size: initially contains the size of the array. > + * When returning will contain the amount of marked commas > + * > + * Returns false if there was not enough space inside the array > + **/ > +static bool mark_invalid_commas(char *buf, size_t buf_len, int *marked, > size_t *marked_size) { > + size_t size = *marked_size; > + size_t used = 0; > + int i; > + bool string = false; > + bool escape = false; > + > + for (i = 0; i < buf_len; i++) { > + char c = buf[i]; > + > + if (c == ',' && (!string)) { > + /* > + * If the next non-whitespace symbol is a } or ] > + * mark for deletion > + **/ > + int inc = 1; > + > + //Skip whitespace > + while (buf[i + inc] == ' ' || buf[i + inc] == '\n') > + inc++; > + > + switch (buf[i + inc]) { > + case ']': > + case '}': > + if (size>used) { > + marked[used++] = i; > + } else { > + return false; > + } > + } > + } > + > + else if (c == '"' && (!escape) ) { > + string = !string; > + } > + > + if (c == '\\') > + escape = true; > + else > + escape = false; //Reset escape state > + } > + > + *marked_size = used; > + return true; > +} > + > +/** > + * Deletes the chars at the given positions inside a string, > + * operates in-place > + * > + * buf: the string > + * buf_len: strlen(buf) > + * marked: array with the positions of the chars to delete > + * marked_size: size of the array > + * > + * Returns the new size of the string. > + **/ > +static size_t delete_at_position(char *buf, size_t buf_len, int *marked, > size_t marked_size) { > + int i; > + int distance; > + > + for (i = 0; i < marked_size; i++) { > + if (i + 1< marked_size) > + distance = marked[i + 1] - marked[i]; > + else > + distance = buf_len - marked[i] + 1; > + memmove(buf + marked[i] - i, buf + marked[i] + 1, distance - 1); > + } > + return buf_len - i; > +} > + > +/** > + * Removes the wrong commas from a json > + * > + * [[1,2,3,],] will become [[1,2,3]] > + * as it should be. > + **/ > +static void clean_json(struct membuffer *b) { > + size_t items = b->len / 10; > + int *marked = calloc(items , sizeof(int)); > + mark_invalid_commas(b->buffer, b->len, marked, &items); > + b->len = delete_at_position(b->buffer, b->len, marked, items); > + free(marked); > +} > + > void write_attribute(struct membuffer *b, const char *att_name, const char > *value) > { > if (!value) > @@ -335,6 +434,7 @@ void export_HTML(const char *file_name, const char > *photos_dir, const bool selec > > struct membuffer buf = { 0 }; > export_list(&buf, photos_dir, selected_only, list_only); > + clean_json(&buf); > > f = subsurface_fopen(file_name, "w+"); > if (!f) > -- > 2.1.0 > > _______________________________________________ > subsurface mailing list > subsurface@hohndel.org > http://lists.hohndel.org/cgi-bin/mailman/listinfo/subsurface _______________________________________________ subsurface mailing list subsurface@hohndel.org http://lists.hohndel.org/cgi-bin/mailman/listinfo/subsurface