Skip to content

Commit ae795fd

Browse files
dschoderrickstolee
authored andcommitted
Merge branch 'scalar-with-gvfs'
Prepare `scalar` to use the GVFS protocol instead of partial clone (required to support Azure Repos). Signed-off-by: Johannes Schindelin <[email protected]>
2 parents bc3a765 + 5c5eccd commit ae795fd

File tree

10 files changed

+891
-24
lines changed

10 files changed

+891
-24
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2503,7 +2503,7 @@ endif
25032503
.PHONY: objects
25042504
objects: $(OBJECTS)
25052505

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

contrib/scalar/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ include ../../config.mak.uname
3333
-include ../../config.mak.autogen
3434
-include ../../config.mak
3535

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

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

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

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

4747
clean:

contrib/scalar/json-parser.c

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
#include "cache.h"
2+
#include "json-parser.h"
3+
4+
static int reset_iterator(struct json_iterator *it)
5+
{
6+
it->p = it->begin = it->json;
7+
strbuf_release(&it->key);
8+
strbuf_release(&it->string_value);
9+
it->type = JSON_NULL;
10+
return -1;
11+
}
12+
13+
static int parse_json_string(struct json_iterator *it, struct strbuf *out)
14+
{
15+
const char *begin = it->p;
16+
17+
if (*(it->p)++ != '"')
18+
return error("expected double quote: '%.*s'", 5, begin),
19+
reset_iterator(it);
20+
21+
strbuf_reset(&it->string_value);
22+
#define APPEND(c) strbuf_addch(out, c)
23+
while (*it->p != '"') {
24+
switch (*it->p) {
25+
case '\0':
26+
return error("incomplete string: '%s'", begin),
27+
reset_iterator(it);
28+
case '\\':
29+
it->p++;
30+
if (*it->p == '\\' || *it->p == '"')
31+
APPEND(*it->p);
32+
else if (*it->p == 'b')
33+
APPEND(8);
34+
else if (*it->p == 't')
35+
APPEND(9);
36+
else if (*it->p == 'n')
37+
APPEND(10);
38+
else if (*it->p == 'f')
39+
APPEND(12);
40+
else if (*it->p == 'r')
41+
APPEND(13);
42+
else if (*it->p == 'u') {
43+
unsigned char binary[2];
44+
int i;
45+
46+
if (hex_to_bytes(binary, it->p + 1, 2) < 0)
47+
return error("invalid: '%.*s'",
48+
6, it->p - 1),
49+
reset_iterator(it);
50+
it->p += 4;
51+
52+
i = (binary[0] << 8) | binary[1];
53+
if (i < 0x80)
54+
APPEND(i);
55+
else if (i < 0x0800) {
56+
APPEND(0xc0 | ((i >> 6) & 0x1f));
57+
APPEND(0x80 | (i & 0x3f));
58+
} else if (i < 0x10000) {
59+
APPEND(0xe0 | ((i >> 12) & 0x0f));
60+
APPEND(0x80 | ((i >> 6) & 0x3f));
61+
APPEND(0x80 | (i & 0x3f));
62+
} else {
63+
APPEND(0xf0 | ((i >> 18) & 0x07));
64+
APPEND(0x80 | ((i >> 12) & 0x3f));
65+
APPEND(0x80 | ((i >> 6) & 0x3f));
66+
APPEND(0x80 | (i & 0x3f));
67+
}
68+
}
69+
break;
70+
default:
71+
APPEND(*it->p);
72+
}
73+
it->p++;
74+
}
75+
76+
it->end = it->p++;
77+
return 0;
78+
}
79+
80+
static void skip_whitespace(struct json_iterator *it)
81+
{
82+
while (isspace(*it->p))
83+
it->p++;
84+
}
85+
86+
int iterate_json(struct json_iterator *it)
87+
{
88+
skip_whitespace(it);
89+
it->begin = it->p;
90+
91+
switch (*it->p) {
92+
case '\0':
93+
return reset_iterator(it), 0;
94+
case 'n':
95+
if (!starts_with(it->p, "null"))
96+
return error("unexpected value: %.*s", 4, it->p),
97+
reset_iterator(it);
98+
it->type = JSON_NULL;
99+
it->end = it->p = it->begin + 4;
100+
break;
101+
case 't':
102+
if (!starts_with(it->p, "true"))
103+
return error("unexpected value: %.*s", 4, it->p),
104+
reset_iterator(it);
105+
it->type = JSON_TRUE;
106+
it->end = it->p = it->begin + 4;
107+
break;
108+
case 'f':
109+
if (!starts_with(it->p, "false"))
110+
return error("unexpected value: %.*s", 5, it->p),
111+
reset_iterator(it);
112+
it->type = JSON_FALSE;
113+
it->end = it->p = it->begin + 5;
114+
break;
115+
case '-': case '.':
116+
case '0': case '1': case '2': case '3': case '4':
117+
case '5': case '6': case '7': case '8': case '9':
118+
it->type = JSON_NUMBER;
119+
it->end = it->p = it->begin + strspn(it->p, "-.0123456789");
120+
break;
121+
case '"':
122+
it->type = JSON_STRING;
123+
if (parse_json_string(it, &it->string_value) < 0)
124+
return -1;
125+
break;
126+
case '[': {
127+
const char *save = it->begin;
128+
size_t key_offset = it->key.len;
129+
int i = 0, res;
130+
131+
for (it->p++, skip_whitespace(it); *it->p != ']'; i++) {
132+
strbuf_addf(&it->key, "[%d]", i);
133+
134+
if ((res = iterate_json(it)))
135+
return reset_iterator(it), res;
136+
strbuf_setlen(&it->key, key_offset);
137+
138+
skip_whitespace(it);
139+
if (*it->p == ',')
140+
it->p++;
141+
}
142+
143+
it->type = JSON_ARRAY;
144+
it->begin = save;
145+
it->end = it->p;
146+
it->p++;
147+
break;
148+
}
149+
case '{': {
150+
const char *save = it->begin;
151+
size_t key_offset = it->key.len;
152+
int res;
153+
154+
strbuf_addch(&it->key, '.');
155+
for (it->p++, skip_whitespace(it); *it->p != '}'; ) {
156+
strbuf_setlen(&it->key, key_offset + 1);
157+
if (parse_json_string(it, &it->key) < 0)
158+
return -1;
159+
skip_whitespace(it);
160+
if (*(it->p)++ != ':')
161+
return error("expected colon: %.*s", 5, it->p),
162+
reset_iterator(it);
163+
164+
if ((res = iterate_json(it)))
165+
return res;
166+
167+
skip_whitespace(it);
168+
if (*it->p == ',')
169+
it->p++;
170+
}
171+
strbuf_setlen(&it->key, key_offset);
172+
173+
it->type = JSON_OBJECT;
174+
it->begin = save;
175+
it->end = it->p;
176+
it->p++;
177+
break;
178+
}
179+
}
180+
181+
return it->fn(it);
182+
}

contrib/scalar/json-parser.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef JSON_PARSER_H
2+
#define JSON_PARSER_H
3+
4+
#include "strbuf.h"
5+
6+
struct json_iterator {
7+
const char *json, *p, *begin, *end;
8+
struct strbuf key, string_value;
9+
enum {
10+
JSON_NULL = 0,
11+
JSON_FALSE,
12+
JSON_TRUE,
13+
JSON_NUMBER,
14+
JSON_STRING,
15+
JSON_ARRAY,
16+
JSON_OBJECT
17+
} type;
18+
int (*fn)(struct json_iterator *it);
19+
void *fn_data;
20+
};
21+
#define JSON_ITERATOR_INIT(json_, fn_, fn_data_) { \
22+
.json = json_, .p = json_, \
23+
.key = STRBUF_INIT, .string_value = STRBUF_INIT, \
24+
.fn = fn_, .fn_data = fn_data_ \
25+
}
26+
27+
int iterate_json(struct json_iterator *it);
28+
29+
#endif

0 commit comments

Comments
 (0)