[PATCH 2/2] Generate correct json

Dirk Hohndel dirk at hohndel.org
Tue Aug 26 11:08:39 PDT 2014


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 at hohndel.org
> http://lists.hohndel.org/cgi-bin/mailman/listinfo/subsurface


More information about the subsurface mailing list