static int _call_cb(const char *arg, const opts *opt, opt_error *error) { int nb_arg_used = 1; switch (opt->has_arg) { case NO_ARG: if (!opt->cb(opt->long_opt, NULL, opt->user_data)) return set_parse_error(error, -1, 0, CALLBACK_ERROR, -1); break; case OPTIONAL_ARG: if (!opt->cb(opt->long_opt, arg, opt->user_data)) return set_parse_error(error, -1, 0, CALLBACK_ERROR, -1); nb_arg_used += arg != NULL ? 1 : 0; break; case REQUIRED_ARG: if (arg == NULL) return set_parse_error(error, -1, 0, ARG_NOT_PROVIDE, -1); if (!opt->cb(opt->long_opt, arg, opt->user_data)) return set_parse_error(error, -1, 0, CALLBACK_ERROR, -1); ++nb_arg_used; break; } return nb_arg_used; }
static int parse_name( char **name, const char **value, git_config_parser *reader, const char *line) { const char *name_end = line, *value_start; *name = NULL; *value = NULL; while (*name_end && is_namechar(*name_end)) name_end++; if (line == name_end) { set_parse_error(reader, 0, "Invalid configuration key"); return -1; } value_start = name_end; while (*value_start && git__isspace(*value_start)) value_start++; if (*value_start == '=') { *value = value_start + 1; } else if (*value_start) { set_parse_error(reader, 0, "Invalid configuration key"); return -1; } if ((*name = git__strndup(line, name_end - line)) == NULL) return -1; return 0; }
int parse_long_opt(const char *long_opt, const char *next_opt[], const opts options[], opt_error *error) { const char *real_opt; const char *real_arg; int nb_arg_parsed; nb_arg_parsed = _split_opt_and_arg(long_opt, next_opt, &real_opt, &real_arg); if (nb_arg_parsed == -1) return -1; int idx = _get_opts_idx_for_opt(real_opt, options); if (idx == -1) nb_arg_parsed = set_parse_error(error, -1, 0, UNKNOWN_OPT, -1); else if (_call_cb(real_arg, &options[idx], error) != -1) { if (options[idx].has_arg == NO_ARG && nb_arg_parsed > 1) --nb_arg_parsed; } else nb_arg_parsed = -1; free((void*)real_opt); return nb_arg_parsed; }
static void advance_pos (TextgenTemplate *tpl, const gchar *text, gint length, gint *pos, gint *line, gint *column, GError **error) { const gchar *next_char = g_utf8_find_next_char (text + *pos, text + length + 1); if (!next_char) { emit_message (tpl, TEXTGEN_MESSAGE_ERROR, *line, *column, _("Invalid UTF-8 character")); set_parse_error (error); return; } if (text[*pos] == '\n') { (*line)++; *column = 1; } else (*column)++; *pos = next_char - text; }
static Node * parse_list (TextgenTemplate *tpl, GList *tokens, CheckEndFunc check_end, GList **end, GError **error) { gboolean success = TRUE; GList *list = NULL; GList *l; l = tokens; while (l && !(check_end && check_end (l))) { Token *token = l->data; if (token->type == TOKEN_TEXT) { Node *node; node = g_slice_new (Node); node->type = NODE_TEXT; node->value.text.text = token->content; node->value.text.length = token->content_length; token->owns_content = FALSE; list = g_list_prepend (list, node); l = l->next; } else if (token->type == TOKEN_VARIABLE) { Node *node; node = g_slice_new (Node); node->type = NODE_VARIABLE; node->value.variable.name = token->content; node->value.variable.line = token->line; node->value.variable.column = token->column; token->owns_content = FALSE; list = g_list_prepend (list, node); l = l->next; } else if (token->type == TOKEN_EXPRESSION || token->type == TOKEN_SCRIPT) { Node *node; node = g_slice_new (Node); node->type = token->type == TOKEN_EXPRESSION ? NODE_EXPRESSION : NODE_SCRIPT; node->value.script.code = token->content; node->value.script.length = token->content_length; node->value.script.code_line = token->line; node->value.script.code_column = token->content_column; token->owns_content = FALSE; list = g_list_prepend (list, node); l = l->next; } else if (token->type == TOKEN_COMMAND) { if (g_ascii_strcasecmp (token->command, "IF") == 0) { Node *node; GList *end; GError *tmp_error = NULL; node = parse_condition (tpl, l, &end, &tmp_error); if (tmp_error) { g_propagate_error (error, tmp_error); success = FALSE; goto finish; } list = g_list_prepend (list, node); l = end->next; } else if (g_ascii_strcasecmp (token->command, "INCLUDE") == 0) { Node *node; node = g_slice_new (Node); node->type = NODE_INCLUDE; node->value.script.code = token->content; node->value.script.length = token->content_length; node->value.script.code_line = token->line; node->value.script.code_column = token->content_column; token->owns_content = FALSE; list = g_list_prepend (list, node); l = l->next; } else { emit_message (tpl, TEXTGEN_MESSAGE_ERROR, token->line, token->column, _("Unknown command %s"), token->command); set_parse_error (error); success = FALSE; goto finish; } } } if (end) *end = l; finish: if (success) { Node *node = g_slice_new (Node); node->type = NODE_LIST; node->value.list = g_list_reverse (list); return node; } else { g_list_free_full (list, free_node); return NULL; } }
static Node * parse_condition (TextgenTemplate *tpl, GList *tokens, GList **end, GError **error) { Token *start_token = tokens->data; Token *end_token; gboolean success = TRUE; Node *if_true = NULL; Node *if_false = NULL; GList *tmp_end = NULL; GError *tmp_error = NULL; if_true = parse_list (tpl, tokens->next, check_condition_if_true_end, &tmp_end, &tmp_error); if (tmp_error != NULL) { success = FALSE; g_propagate_error (error, tmp_error); goto finish; } if (tmp_end == NULL) { emit_message (tpl, TEXTGEN_MESSAGE_ERROR, start_token->line, start_token->column, _("Could not find ENDIF of the condition")); set_parse_error (error); success = FALSE; goto finish; } end_token = tmp_end->data; if (g_ascii_strcasecmp (end_token->command, "ELSEIF") == 0) { if_false = parse_condition (tpl, tmp_end, &tmp_end, &tmp_error); if (tmp_error) { g_propagate_error (error, tmp_error); success = FALSE; goto finish; } } else if (g_ascii_strcasecmp (end_token->command, "ELSE") == 0) { if_false = parse_list (tpl, tmp_end->next, check_condition_if_false_end, &tmp_end, &tmp_error); if (tmp_error) { g_propagate_error (error, tmp_error); success = FALSE; goto finish; } if (tmp_end == NULL) { emit_message (tpl, TEXTGEN_MESSAGE_ERROR, start_token->line, start_token->column, _("Could not find ENDIF of the condition")); set_parse_error (error); success = FALSE; goto finish; } } finish: if (success) { Node *node; node = g_slice_new (Node); node->type = NODE_CONDITION; node->value.cond.code = start_token->content; node->value.cond.length = start_token->content_length; node->value.cond.if_true = if_true; node->value.cond.if_false = if_false; node->value.cond.code_line = start_token->line; node->value.cond.code_column = start_token->column; start_token->owns_content = FALSE; *end = tmp_end; return node; } else { if (if_true) free_node (if_true); if (if_false) free_node (if_false); return FALSE; } }
static Token * maybe_parse_instruction (TextgenTemplate *tpl, const gchar *text, gint length, gint start, gint start_line, gint start_column, gboolean *ignore_empty_line, gint *after_end, gint *after_end_line, gint *after_end_column, GError **error) { gboolean success = TRUE; gboolean found_end = FALSE; gchar instr; gint content_offset; gchar *command = NULL; gchar *content = NULL; gint content_length; gint pos = start; gint cur_line = start_line; gint cur_column = start_column; GError *tmp_error = NULL; if (start < length - 1 && text[start] == '[') { if (text[start + 1] == '!') { *ignore_empty_line = TRUE; instr = text[start + 2]; content_offset = 3; } else { *ignore_empty_line = FALSE; instr = text[start + 1]; content_offset = 2; } if (!IS_VALID_INSTRUCTION_CHAR (instr)) return NULL; } else return NULL; pos += content_offset; cur_column += content_offset; while (pos < length) { if (pos < length - 1 && text[pos] == instr && text[pos + 1] == ']') { gint content_start = start + content_offset; content_length = pos - content_start; content = g_strndup (text + content_start, content_length); *after_end = pos + 2; cur_column += 2; found_end = TRUE; break; } advance_pos (tpl, text, length, &pos, &cur_line, &cur_column, &tmp_error); if (tmp_error) { g_propagate_error (error, tmp_error); success = FALSE; goto finish; } } if (!found_end) { emit_message (tpl, TEXTGEN_MESSAGE_ERROR, start_line, start_column, _("Could not find the end of the instruction"), instr); set_parse_error (error); success = FALSE; goto finish; } if (instr == TOKEN_COMMAND) { static GRegex *regex = NULL; GMatchInfo *match_info; gchar *old_content = content; gint start_pos; gint end_pos; if (!regex) regex = g_regex_new ("^\\s*([A-Za-z]+)\\s+(.*)$", G_REGEX_MULTILINE | G_REGEX_OPTIMIZE, 0, NULL); if (!g_regex_match (regex, old_content, 0, &match_info)) { emit_message (tpl, TEXTGEN_MESSAGE_ERROR, start_line, start_column, _("A command must look like this: [# COMMAND content #]")); set_parse_error (error); success = FALSE; goto finish; } command = g_match_info_fetch (match_info, 1); content = g_match_info_fetch (match_info, 2); g_match_info_fetch_pos (match_info, 2, &start_pos, &end_pos); content_length = end_pos - start_pos; g_match_info_free (match_info); g_free (old_content); } *after_end_line = cur_line; *after_end_column = cur_column; finish: if (success) { Token *token = g_slice_new (Token); token->type = instr; token->command = command; token->content = content; token->content_length = content_length; token->line = start_line; token->column = start_column; token->content_column = start_column + content_offset; token->owns_content = TRUE; token->owns_command = TRUE; return token; } else { g_free (command); g_free (content); return NULL; } }
static int parse_section_header_ext(git_config_parser *reader, const char *line, const char *base_name, char **section_name) { int c, rpos; char *first_quote, *last_quote; git_buf buf = GIT_BUF_INIT; size_t quoted_len, alloc_len, base_name_len = strlen(base_name); /* * base_name is what came before the space. We should be at the * first quotation mark, except for now, line isn't being kept in * sync so we only really use it to calculate the length. */ first_quote = strchr(line, '"'); if (first_quote == NULL) { set_parse_error(reader, 0, "Missing quotation marks in section header"); goto end_error; } last_quote = strrchr(line, '"'); quoted_len = last_quote - first_quote; if (quoted_len == 0) { set_parse_error(reader, 0, "Missing closing quotation mark in section header"); goto end_error; } GITERR_CHECK_ALLOC_ADD(&alloc_len, base_name_len, quoted_len); GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2); if (git_buf_grow(&buf, alloc_len) < 0 || git_buf_printf(&buf, "%s.", base_name) < 0) goto end_error; rpos = 0; line = first_quote; c = line[++rpos]; /* * At the end of each iteration, whatever is stored in c will be * added to the string. In case of error, jump to out */ do { switch (c) { case 0: set_parse_error(reader, 0, "Unexpected end-of-line in section header"); goto end_error; case '"': goto end_parse; case '\\': c = line[++rpos]; if (c == 0) { set_parse_error(reader, rpos, "Unexpected end-of-line in section header"); goto end_error; } default: break; } git_buf_putc(&buf, (char)c); c = line[++rpos]; } while (line + rpos < last_quote); end_parse: if (git_buf_oom(&buf)) goto end_error; if (line[rpos] != '"' || line[rpos + 1] != ']') { set_parse_error(reader, rpos, "Unexpected text after closing quotes"); git_buf_free(&buf); return -1; } *section_name = git_buf_detach(&buf); return 0; end_error: git_buf_free(&buf); return -1; }
static int parse_section_header(git_config_parser *reader, char **section_out) { char *name, *name_end; int name_length, c, pos; int result; char *line; size_t line_len; git_parse_advance_ws(&reader->ctx); line = git__strndup(reader->ctx.line, reader->ctx.line_len); if (line == NULL) return -1; /* find the end of the variable's name */ name_end = strrchr(line, ']'); if (name_end == NULL) { git__free(line); set_parse_error(reader, 0, "Missing ']' in section header"); return -1; } GITERR_CHECK_ALLOC_ADD(&line_len, (size_t)(name_end - line), 1); name = git__malloc(line_len); GITERR_CHECK_ALLOC(name); name_length = 0; pos = 0; /* Make sure we were given a section header */ c = line[pos++]; assert(c == '['); c = line[pos++]; do { if (git__isspace(c)){ name[name_length] = '\0'; result = parse_section_header_ext(reader, line, name, section_out); git__free(line); git__free(name); return result; } if (!config_keychar(c) && c != '.') { set_parse_error(reader, pos, "Unexpected character in header"); goto fail_parse; } name[name_length++] = (char)git__tolower(c); } while ((c = line[pos++]) != ']'); if (line[pos - 1] != ']') { set_parse_error(reader, pos, "Unexpected end of file"); goto fail_parse; } git__free(line); name[name_length] = 0; *section_out = name; return 0; fail_parse: git__free(line); git__free(name); return -1; }