зеркало из https://github.com/microsoft/git.git
Merge branch 'tb/ban-strtok'
Mark strtok() and strtok_r() to be banned. * tb/ban-strtok: banned.h: mark `strtok()` and `strtok_r()` as banned t/helper/test-json-writer.c: avoid using `strtok()` t/helper/test-oidmap.c: avoid using `strtok()` t/helper/test-hashmap.c: avoid using `strtok()` string-list: introduce `string_list_setlen()` string-list: multi-delimiter `string_list_split_in_place()`
This commit is contained in:
Коммит
d699e27bd4
4
banned.h
4
banned.h
|
@ -18,6 +18,10 @@
|
|||
#define strncpy(x,y,n) BANNED(strncpy)
|
||||
#undef strncat
|
||||
#define strncat(x,y,n) BANNED(strncat)
|
||||
#undef strtok
|
||||
#define strtok(x,y) BANNED(strtok)
|
||||
#undef strtok_r
|
||||
#define strtok_r(x,y,z) BANNED(strtok_r)
|
||||
|
||||
#undef sprintf
|
||||
#undef vsprintf
|
||||
|
|
|
@ -1685,11 +1685,11 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
|
|||
if (is_available)
|
||||
*is_available = 0;
|
||||
|
||||
string_list_split_in_place(&list, testing, ',', -1);
|
||||
string_list_split_in_place(&list, testing, ",", -1);
|
||||
for_each_string_list_item(item, &list) {
|
||||
struct string_list pair = STRING_LIST_INIT_NODUP;
|
||||
|
||||
if (string_list_split_in_place(&pair, item->string, ':', 2) != 2)
|
||||
if (string_list_split_in_place(&pair, item->string, ":", 2) != 2)
|
||||
continue;
|
||||
|
||||
if (!strcmp(*cmd, pair.items[0].string)) {
|
||||
|
|
2
diff.c
2
diff.c
|
@ -139,7 +139,7 @@ static int parse_dirstat_params(struct diff_options *options, const char *params
|
|||
int i;
|
||||
|
||||
if (*params_copy)
|
||||
string_list_split_in_place(¶ms, params_copy, ',', -1);
|
||||
string_list_split_in_place(¶ms, params_copy, ",", -1);
|
||||
for (i = 0; i < params.nr; i++) {
|
||||
const char *p = params.items[i].string;
|
||||
if (!strcmp(p, "changes")) {
|
||||
|
|
2
notes.c
2
notes.c
|
@ -964,7 +964,7 @@ void string_list_add_refs_from_colon_sep(struct string_list *list,
|
|||
char *globs_copy = xstrdup(globs);
|
||||
int i;
|
||||
|
||||
string_list_split_in_place(&split, globs_copy, ':', -1);
|
||||
string_list_split_in_place(&split, globs_copy, ":", -1);
|
||||
string_list_remove_empty_items(&split, 0);
|
||||
|
||||
for (i = 0; i < split.nr; i++)
|
||||
|
|
|
@ -651,7 +651,7 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs)
|
|||
snapshot->buf,
|
||||
snapshot->eof - snapshot->buf);
|
||||
|
||||
string_list_split_in_place(&traits, p, ' ', -1);
|
||||
string_list_split_in_place(&traits, p, " ", -1);
|
||||
|
||||
if (unsorted_string_list_has_string(&traits, "fully-peeled"))
|
||||
snapshot->peeled = PEELED_FULLY;
|
||||
|
|
|
@ -203,6 +203,15 @@ void string_list_clear_func(struct string_list *list, string_list_clear_func_t c
|
|||
list->nr = list->alloc = 0;
|
||||
}
|
||||
|
||||
void string_list_setlen(struct string_list *list, size_t nr)
|
||||
{
|
||||
if (list->strdup_strings)
|
||||
BUG("cannot setlen a string_list which owns its entries");
|
||||
if (nr > list->nr)
|
||||
BUG("cannot grow a string_list with setlen");
|
||||
list->nr = nr;
|
||||
}
|
||||
|
||||
struct string_list_item *string_list_append_nodup(struct string_list *list,
|
||||
char *string)
|
||||
{
|
||||
|
@ -301,7 +310,7 @@ int string_list_split(struct string_list *list, const char *string,
|
|||
}
|
||||
|
||||
int string_list_split_in_place(struct string_list *list, char *string,
|
||||
int delim, int maxsplit)
|
||||
const char *delim, int maxsplit)
|
||||
{
|
||||
int count = 0;
|
||||
char *p = string, *end;
|
||||
|
@ -315,7 +324,7 @@ int string_list_split_in_place(struct string_list *list, char *string,
|
|||
string_list_append(list, p);
|
||||
return count;
|
||||
}
|
||||
end = strchr(p, delim);
|
||||
end = strpbrk(p, delim);
|
||||
if (end) {
|
||||
*end = '\0';
|
||||
string_list_append(list, p);
|
||||
|
|
|
@ -134,6 +134,16 @@ typedef void (*string_list_clear_func_t)(void *p, const char *str);
|
|||
/** Call a custom clear function on each util pointer */
|
||||
void string_list_clear_func(struct string_list *list, string_list_clear_func_t clearfunc);
|
||||
|
||||
/*
|
||||
* Set the length of a string_list to `nr`, provided that (a) `list`
|
||||
* does not own its own storage, and (b) that `nr` is no larger than
|
||||
* `list->nr`.
|
||||
*
|
||||
* Useful when "shrinking" `list` to write over existing entries that
|
||||
* are no longer used without reallocating.
|
||||
*/
|
||||
void string_list_setlen(struct string_list *list, size_t nr);
|
||||
|
||||
/**
|
||||
* Apply `func` to each item. If `func` returns nonzero, the
|
||||
* iteration aborts and the return value is propagated.
|
||||
|
@ -270,5 +280,5 @@ int string_list_split(struct string_list *list, const char *string,
|
|||
* list->strdup_strings must *not* be set.
|
||||
*/
|
||||
int string_list_split_in_place(struct string_list *list, char *string,
|
||||
int delim, int maxsplit);
|
||||
const char *delim, int maxsplit);
|
||||
#endif /* STRING_LIST_H */
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "git-compat-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "strbuf.h"
|
||||
#include "string-list.h"
|
||||
|
||||
struct test_entry
|
||||
{
|
||||
|
@ -150,6 +151,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
|
|||
*/
|
||||
int cmd__hashmap(int argc, const char **argv)
|
||||
{
|
||||
struct string_list parts = STRING_LIST_INIT_NODUP;
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
int icase;
|
||||
struct hashmap map = HASHMAP_INIT(test_entry_cmp, &icase);
|
||||
|
@ -159,21 +161,26 @@ int cmd__hashmap(int argc, const char **argv)
|
|||
|
||||
/* process commands from stdin */
|
||||
while (strbuf_getline(&line, stdin) != EOF) {
|
||||
char *cmd, *p1 = NULL, *p2 = NULL;
|
||||
char *cmd, *p1, *p2;
|
||||
unsigned int hash = 0;
|
||||
struct test_entry *entry;
|
||||
|
||||
/* break line into command and up to two parameters */
|
||||
cmd = strtok(line.buf, DELIM);
|
||||
string_list_setlen(&parts, 0);
|
||||
string_list_split_in_place(&parts, line.buf, DELIM, 2);
|
||||
string_list_remove_empty_items(&parts, 0);
|
||||
|
||||
/* ignore empty lines */
|
||||
if (!cmd || *cmd == '#')
|
||||
if (!parts.nr)
|
||||
continue;
|
||||
if (!*parts.items[0].string || *parts.items[0].string == '#')
|
||||
continue;
|
||||
|
||||
p1 = strtok(NULL, DELIM);
|
||||
if (p1) {
|
||||
cmd = parts.items[0].string;
|
||||
p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
|
||||
p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
|
||||
if (p1)
|
||||
hash = icase ? strihash(p1) : strhash(p1);
|
||||
p2 = strtok(NULL, DELIM);
|
||||
}
|
||||
|
||||
if (!strcmp("add", cmd) && p1 && p2) {
|
||||
|
||||
|
@ -260,6 +267,7 @@ int cmd__hashmap(int argc, const char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
string_list_clear(&parts, 0);
|
||||
strbuf_release(&line);
|
||||
hashmap_clear_and_free(&map, struct test_entry, ent);
|
||||
return 0;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "test-tool.h"
|
||||
#include "json-writer.h"
|
||||
#include "string-list.h"
|
||||
|
||||
static const char *expect_obj1 = "{\"a\":\"abc\",\"b\":42,\"c\":true}";
|
||||
static const char *expect_obj2 = "{\"a\":-1,\"b\":2147483647,\"c\":0}";
|
||||
|
@ -394,35 +395,41 @@ static int unit_tests(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void get_s(int line_nr, char **s_in)
|
||||
struct line {
|
||||
struct string_list *parts;
|
||||
size_t consumed_nr;
|
||||
int nr;
|
||||
};
|
||||
|
||||
static void get_s(struct line *line, char **s_in)
|
||||
{
|
||||
*s_in = strtok(NULL, " ");
|
||||
if (!*s_in)
|
||||
die("line[%d]: expected: <s>", line_nr);
|
||||
if (line->consumed_nr > line->parts->nr)
|
||||
die("line[%d]: expected: <s>", line->nr);
|
||||
*s_in = line->parts->items[line->consumed_nr++].string;
|
||||
}
|
||||
|
||||
static void get_i(int line_nr, intmax_t *s_in)
|
||||
static void get_i(struct line *line, intmax_t *s_in)
|
||||
{
|
||||
char *s;
|
||||
char *endptr;
|
||||
|
||||
get_s(line_nr, &s);
|
||||
get_s(line, &s);
|
||||
|
||||
*s_in = strtol(s, &endptr, 10);
|
||||
if (*endptr || errno == ERANGE)
|
||||
die("line[%d]: invalid integer value", line_nr);
|
||||
die("line[%d]: invalid integer value", line->nr);
|
||||
}
|
||||
|
||||
static void get_d(int line_nr, double *s_in)
|
||||
static void get_d(struct line *line, double *s_in)
|
||||
{
|
||||
char *s;
|
||||
char *endptr;
|
||||
|
||||
get_s(line_nr, &s);
|
||||
get_s(line, &s);
|
||||
|
||||
*s_in = strtod(s, &endptr);
|
||||
if (*endptr || errno == ERANGE)
|
||||
die("line[%d]: invalid float value", line_nr);
|
||||
die("line[%d]: invalid float value", line->nr);
|
||||
}
|
||||
|
||||
static int pretty;
|
||||
|
@ -453,6 +460,7 @@ static char *get_trimmed_line(char *buf, int buf_size)
|
|||
|
||||
static int scripted(void)
|
||||
{
|
||||
struct string_list parts = STRING_LIST_INIT_NODUP;
|
||||
struct json_writer jw = JSON_WRITER_INIT;
|
||||
char buf[MAX_LINE_LENGTH];
|
||||
char *line;
|
||||
|
@ -470,66 +478,77 @@ static int scripted(void)
|
|||
die("expected first line to be 'object' or 'array'");
|
||||
|
||||
while ((line = get_trimmed_line(buf, MAX_LINE_LENGTH)) != NULL) {
|
||||
struct line state = { 0 };
|
||||
char *verb;
|
||||
char *key;
|
||||
char *s_value;
|
||||
intmax_t i_value;
|
||||
double d_value;
|
||||
|
||||
line_nr++;
|
||||
state.parts = &parts;
|
||||
state.nr = ++line_nr;
|
||||
|
||||
verb = strtok(line, " ");
|
||||
/* break line into command and zero or more tokens */
|
||||
string_list_setlen(&parts, 0);
|
||||
string_list_split_in_place(&parts, line, " ", -1);
|
||||
string_list_remove_empty_items(&parts, 0);
|
||||
|
||||
/* ignore empty lines */
|
||||
if (!parts.nr || !*parts.items[0].string)
|
||||
continue;
|
||||
|
||||
verb = parts.items[state.consumed_nr++].string;
|
||||
|
||||
if (!strcmp(verb, "end")) {
|
||||
jw_end(&jw);
|
||||
}
|
||||
else if (!strcmp(verb, "object-string")) {
|
||||
get_s(line_nr, &key);
|
||||
get_s(line_nr, &s_value);
|
||||
get_s(&state, &key);
|
||||
get_s(&state, &s_value);
|
||||
jw_object_string(&jw, key, s_value);
|
||||
}
|
||||
else if (!strcmp(verb, "object-int")) {
|
||||
get_s(line_nr, &key);
|
||||
get_i(line_nr, &i_value);
|
||||
get_s(&state, &key);
|
||||
get_i(&state, &i_value);
|
||||
jw_object_intmax(&jw, key, i_value);
|
||||
}
|
||||
else if (!strcmp(verb, "object-double")) {
|
||||
get_s(line_nr, &key);
|
||||
get_i(line_nr, &i_value);
|
||||
get_d(line_nr, &d_value);
|
||||
get_s(&state, &key);
|
||||
get_i(&state, &i_value);
|
||||
get_d(&state, &d_value);
|
||||
jw_object_double(&jw, key, i_value, d_value);
|
||||
}
|
||||
else if (!strcmp(verb, "object-true")) {
|
||||
get_s(line_nr, &key);
|
||||
get_s(&state, &key);
|
||||
jw_object_true(&jw, key);
|
||||
}
|
||||
else if (!strcmp(verb, "object-false")) {
|
||||
get_s(line_nr, &key);
|
||||
get_s(&state, &key);
|
||||
jw_object_false(&jw, key);
|
||||
}
|
||||
else if (!strcmp(verb, "object-null")) {
|
||||
get_s(line_nr, &key);
|
||||
get_s(&state, &key);
|
||||
jw_object_null(&jw, key);
|
||||
}
|
||||
else if (!strcmp(verb, "object-object")) {
|
||||
get_s(line_nr, &key);
|
||||
get_s(&state, &key);
|
||||
jw_object_inline_begin_object(&jw, key);
|
||||
}
|
||||
else if (!strcmp(verb, "object-array")) {
|
||||
get_s(line_nr, &key);
|
||||
get_s(&state, &key);
|
||||
jw_object_inline_begin_array(&jw, key);
|
||||
}
|
||||
else if (!strcmp(verb, "array-string")) {
|
||||
get_s(line_nr, &s_value);
|
||||
get_s(&state, &s_value);
|
||||
jw_array_string(&jw, s_value);
|
||||
}
|
||||
else if (!strcmp(verb, "array-int")) {
|
||||
get_i(line_nr, &i_value);
|
||||
get_i(&state, &i_value);
|
||||
jw_array_intmax(&jw, i_value);
|
||||
}
|
||||
else if (!strcmp(verb, "array-double")) {
|
||||
get_i(line_nr, &i_value);
|
||||
get_d(line_nr, &d_value);
|
||||
get_i(&state, &i_value);
|
||||
get_d(&state, &d_value);
|
||||
jw_array_double(&jw, i_value, d_value);
|
||||
}
|
||||
else if (!strcmp(verb, "array-true"))
|
||||
|
@ -552,6 +571,7 @@ static int scripted(void)
|
|||
printf("%s\n", jw.json.buf);
|
||||
|
||||
jw_release(&jw);
|
||||
string_list_clear(&parts, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "oidmap.h"
|
||||
#include "setup.h"
|
||||
#include "strbuf.h"
|
||||
#include "string-list.h"
|
||||
|
||||
/* key is an oid and value is a name (could be a refname for example) */
|
||||
struct test_entry {
|
||||
|
@ -25,6 +26,7 @@ struct test_entry {
|
|||
*/
|
||||
int cmd__oidmap(int argc UNUSED, const char **argv UNUSED)
|
||||
{
|
||||
struct string_list parts = STRING_LIST_INIT_NODUP;
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
struct oidmap map = OIDMAP_INIT;
|
||||
|
||||
|
@ -35,19 +37,24 @@ int cmd__oidmap(int argc UNUSED, const char **argv UNUSED)
|
|||
|
||||
/* process commands from stdin */
|
||||
while (strbuf_getline(&line, stdin) != EOF) {
|
||||
char *cmd, *p1 = NULL, *p2 = NULL;
|
||||
char *cmd, *p1, *p2;
|
||||
struct test_entry *entry;
|
||||
struct object_id oid;
|
||||
|
||||
/* break line into command and up to two parameters */
|
||||
cmd = strtok(line.buf, DELIM);
|
||||
string_list_setlen(&parts, 0);
|
||||
string_list_split_in_place(&parts, line.buf, DELIM, 2);
|
||||
string_list_remove_empty_items(&parts, 0);
|
||||
|
||||
/* ignore empty lines */
|
||||
if (!cmd || *cmd == '#')
|
||||
if (!parts.nr)
|
||||
continue;
|
||||
if (!*parts.items[0].string || *parts.items[0].string == '#')
|
||||
continue;
|
||||
|
||||
p1 = strtok(NULL, DELIM);
|
||||
if (p1)
|
||||
p2 = strtok(NULL, DELIM);
|
||||
cmd = parts.items[0].string;
|
||||
p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
|
||||
p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
|
||||
|
||||
if (!strcmp("put", cmd) && p1 && p2) {
|
||||
|
||||
|
@ -108,6 +115,7 @@ int cmd__oidmap(int argc UNUSED, const char **argv UNUSED)
|
|||
}
|
||||
}
|
||||
|
||||
string_list_clear(&parts, 0);
|
||||
strbuf_release(&line);
|
||||
oidmap_free(&map, 1);
|
||||
return 0;
|
||||
|
|
|
@ -62,7 +62,7 @@ int cmd__string_list(int argc, const char **argv)
|
|||
struct string_list list = STRING_LIST_INIT_NODUP;
|
||||
int i;
|
||||
char *s = xstrdup(argv[2]);
|
||||
int delim = *argv[3];
|
||||
const char *delim = argv[3];
|
||||
int maxsplit = atoi(argv[4]);
|
||||
|
||||
i = string_list_split_in_place(&list, s, delim, maxsplit);
|
||||
|
@ -111,7 +111,7 @@ int cmd__string_list(int argc, const char **argv)
|
|||
*/
|
||||
if (sb.len && sb.buf[sb.len - 1] == '\n')
|
||||
strbuf_setlen(&sb, sb.len - 1);
|
||||
string_list_split_in_place(&list, sb.buf, '\n', -1);
|
||||
string_list_split_in_place(&list, sb.buf, "\n", -1);
|
||||
|
||||
string_list_sort(&list);
|
||||
|
||||
|
|
|
@ -18,6 +18,14 @@ test_split () {
|
|||
"
|
||||
}
|
||||
|
||||
test_split_in_place() {
|
||||
cat >expected &&
|
||||
test_expect_success "split (in place) $1 at $2, max $3" "
|
||||
test-tool string-list split_in_place '$1' '$2' '$3' >actual &&
|
||||
test_cmp expected actual
|
||||
"
|
||||
}
|
||||
|
||||
test_split "foo:bar:baz" ":" "-1" <<EOF
|
||||
3
|
||||
[0]: "foo"
|
||||
|
@ -61,6 +69,49 @@ test_split ":" ":" "-1" <<EOF
|
|||
[1]: ""
|
||||
EOF
|
||||
|
||||
test_split_in_place "foo:;:bar:;:baz:;:" ":;" "-1" <<EOF
|
||||
10
|
||||
[0]: "foo"
|
||||
[1]: ""
|
||||
[2]: ""
|
||||
[3]: "bar"
|
||||
[4]: ""
|
||||
[5]: ""
|
||||
[6]: "baz"
|
||||
[7]: ""
|
||||
[8]: ""
|
||||
[9]: ""
|
||||
EOF
|
||||
|
||||
test_split_in_place "foo:;:bar:;:baz" ":;" "0" <<EOF
|
||||
1
|
||||
[0]: "foo:;:bar:;:baz"
|
||||
EOF
|
||||
|
||||
test_split_in_place "foo:;:bar:;:baz" ":;" "1" <<EOF
|
||||
2
|
||||
[0]: "foo"
|
||||
[1]: ";:bar:;:baz"
|
||||
EOF
|
||||
|
||||
test_split_in_place "foo:;:bar:;:baz" ":;" "2" <<EOF
|
||||
3
|
||||
[0]: "foo"
|
||||
[1]: ""
|
||||
[2]: ":bar:;:baz"
|
||||
EOF
|
||||
|
||||
test_split_in_place "foo:;:bar:;:" ":;" "-1" <<EOF
|
||||
7
|
||||
[0]: "foo"
|
||||
[1]: ""
|
||||
[2]: ""
|
||||
[3]: "bar"
|
||||
[4]: ""
|
||||
[5]: ""
|
||||
[6]: ""
|
||||
EOF
|
||||
|
||||
test_expect_success "test filter_string_list" '
|
||||
test "x-" = "x$(test-tool string-list filter - y)" &&
|
||||
test "x-" = "x$(test-tool string-list filter no y)" &&
|
||||
|
|
Загрузка…
Ссылка в новой задаче