Skip to content

Commit

Permalink
Merge branch 'scalar-with-gvfs'
Browse files Browse the repository at this point in the history
Prepare `scalar` to use the GVFS protocol instead of partial clone
(required to support Azure Repos).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
  • Loading branch information
dscho committed Jun 2, 2021
2 parents 2722325 + bc4437a commit c2fd2c1
Show file tree
Hide file tree
Showing 10 changed files with 888 additions and 24 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2475,7 +2475,7 @@ endif
.PHONY: objects
objects: $(OBJECTS)

SCALAR_SOURCES := contrib/scalar/scalar.c
SCALAR_SOURCES := contrib/scalar/scalar.c contrib/scalar/json-parser.c
SCALAR_OBJECTS := $(SCALAR_SOURCES:c=o)
OBJECTS += $(SCALAR_OBJECTS)

Expand Down
4 changes: 2 additions & 2 deletions contrib/scalar/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ include ../../config.mak.uname
-include ../../config.mak.autogen
-include ../../config.mak

TARGETS = scalar$(X) scalar.o
TARGETS = scalar$(X) scalar.o json-parser.o
GITLIBS = ../../common-main.o ../../libgit.a ../../xdiff/lib.a

all: scalar$X ../../bin-wrappers/scalar

$(GITLIBS):
$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) $(subst ../../,,$@)

$(TARGETS): $(GITLIBS) scalar.c
$(TARGETS): $(GITLIBS) scalar.c json-parser.c json-parser.h
$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) $(patsubst %,contrib/scalar/%,$@)

clean:
Expand Down
182 changes: 182 additions & 0 deletions contrib/scalar/json-parser.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
#include "cache.h"
#include "json-parser.h"

static int reset_iterator(struct json_iterator *it)
{
it->p = it->begin = it->json;
strbuf_release(&it->key);
strbuf_release(&it->string_value);
it->type = JSON_NULL;
return -1;
}

static int parse_json_string(struct json_iterator *it, struct strbuf *out)
{
const char *begin = it->p;

if (*(it->p)++ != '"')
return error("expected double quote: '%.*s'", 5, begin),
reset_iterator(it);

strbuf_reset(&it->string_value);
#define APPEND(c) strbuf_addch(out, c)
while (*it->p != '"') {
switch (*it->p) {
case '\0':
return error("incomplete string: '%s'", begin),
reset_iterator(it);
case '\\':
it->p++;
if (*it->p == '\\' || *it->p == '"')
APPEND(*it->p);
else if (*it->p == 'b')
APPEND(8);
else if (*it->p == 't')
APPEND(9);
else if (*it->p == 'n')
APPEND(10);
else if (*it->p == 'f')
APPEND(12);
else if (*it->p == 'r')
APPEND(13);
else if (*it->p == 'u') {
unsigned char binary[2];
int i;

if (hex_to_bytes(binary, it->p + 1, 2) < 0)
return error("invalid: '%.*s'",
6, it->p - 1),
reset_iterator(it);
it->p += 4;

i = (binary[0] << 8) | binary[1];
if (i < 0x80)
APPEND(i);
else if (i < 0x0800) {
APPEND(0xc0 | ((i >> 6) & 0x1f));
APPEND(0x80 | (i & 0x3f));
} else if (i < 0x10000) {
APPEND(0xe0 | ((i >> 12) & 0x0f));
APPEND(0x80 | ((i >> 6) & 0x3f));
APPEND(0x80 | (i & 0x3f));
} else {
APPEND(0xf0 | ((i >> 18) & 0x07));
APPEND(0x80 | ((i >> 12) & 0x3f));
APPEND(0x80 | ((i >> 6) & 0x3f));
APPEND(0x80 | (i & 0x3f));
}
}
break;
default:
APPEND(*it->p);
}
it->p++;
}

it->end = it->p++;
return 0;
}

static void skip_whitespace(struct json_iterator *it)
{
while (isspace(*it->p))
it->p++;
}

int iterate_json(struct json_iterator *it)
{
skip_whitespace(it);
it->begin = it->p;

switch (*it->p) {
case '\0':
return reset_iterator(it), 0;
case 'n':
if (!starts_with(it->p, "null"))
return error("unexpected value: %.*s", 4, it->p),
reset_iterator(it);
it->type = JSON_NULL;
it->end = it->p = it->begin + 4;
break;
case 't':
if (!starts_with(it->p, "true"))
return error("unexpected value: %.*s", 4, it->p),
reset_iterator(it);
it->type = JSON_TRUE;
it->end = it->p = it->begin + 4;
break;
case 'f':
if (!starts_with(it->p, "false"))
return error("unexpected value: %.*s", 5, it->p),
reset_iterator(it);
it->type = JSON_FALSE;
it->end = it->p = it->begin + 5;
break;
case '-': case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
it->type = JSON_NUMBER;
it->end = it->p = it->begin + strspn(it->p, "-.0123456789");
break;
case '"':
it->type = JSON_STRING;
if (parse_json_string(it, &it->string_value) < 0)
return -1;
break;
case '[': {
const char *save = it->begin;
size_t key_offset = it->key.len;
int i = 0, res;

for (it->p++, skip_whitespace(it); *it->p != ']'; i++) {
strbuf_addf(&it->key, "[%d]", i);

if ((res = iterate_json(it)))
return reset_iterator(it), res;
strbuf_setlen(&it->key, key_offset);

skip_whitespace(it);
if (*it->p == ',')
it->p++;
}

it->type = JSON_ARRAY;
it->begin = save;
it->end = it->p;
it->p++;
break;
}
case '{': {
const char *save = it->begin;
size_t key_offset = it->key.len;
int res;

strbuf_addch(&it->key, '.');
for (it->p++, skip_whitespace(it); *it->p != '}'; ) {
strbuf_setlen(&it->key, key_offset + 1);
if (parse_json_string(it, &it->key) < 0)
return -1;
skip_whitespace(it);
if (*(it->p)++ != ':')
return error("expected colon: %.*s", 5, it->p),
reset_iterator(it);

if ((res = iterate_json(it)))
return res;

skip_whitespace(it);
if (*it->p == ',')
it->p++;
}
strbuf_setlen(&it->key, key_offset);

it->type = JSON_OBJECT;
it->begin = save;
it->end = it->p;
it->p++;
break;
}
}

return it->fn(it);
}
29 changes: 29 additions & 0 deletions contrib/scalar/json-parser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef JSON_PARSER_H
#define JSON_PARSER_H

#include "strbuf.h"

struct json_iterator {
const char *json, *p, *begin, *end;
struct strbuf key, string_value;
enum {
JSON_NULL = 0,
JSON_FALSE,
JSON_TRUE,
JSON_NUMBER,
JSON_STRING,
JSON_ARRAY,
JSON_OBJECT
} type;
int (*fn)(struct json_iterator *it);
void *fn_data;
};
#define JSON_ITERATOR_INIT(json_, fn_, fn_data_) { \
.json = json_, .p = json_, \
.key = STRBUF_INIT, .string_value = STRBUF_INIT, \
.fn = fn_, .fn_data = fn_data_ \
}

int iterate_json(struct json_iterator *it);

#endif
Loading

0 comments on commit c2fd2c1

Please sign in to comment.