ini_parse_stream:
   97|    553|{
   98|       |    /* Uses a fair bit of stack (use heap instead if you need to) */
   99|    553|#if INI_USE_STACK
  100|    553|    char line[INI_MAX_LINE];
  101|    553|    size_t max_line = INI_MAX_LINE;
  ------------------
  |  |  141|    553|#define INI_MAX_LINE 200
  ------------------
  102|       |#else
  103|       |    char* line;
  104|       |    size_t max_line = INI_INITIAL_ALLOC;
  105|       |#endif
  106|       |#if INI_ALLOW_REALLOC && !INI_USE_STACK
  107|       |    char* new_line;
  108|       |#endif
  109|    553|    char section[INI_MAX_SECTION] = "";
  110|    553|#if INI_ALLOW_MULTILINE
  111|    553|    char prev_name[INI_MAX_NAME] = "";
  112|    553|#endif
  113|       |
  114|    553|    size_t offset;
  115|    553|    char* start;
  116|    553|    char* end;
  117|    553|    char* name;
  118|    553|    char* value;
  119|    553|    int lineno = 0;
  120|    553|    int error = 0;
  121|    553|    char abyss[16];  /* Used to consume input when a line is too long. */
  122|    553|    size_t abyss_len;
  123|       |
  124|    553|    assert(reader != NULL);
  ------------------
  |  Branch (124:5): [True: 0, False: 553]
  |  Branch (124:5): [True: 553, False: 0]
  ------------------
  125|    553|    assert(stream != NULL);
  ------------------
  |  Branch (125:5): [True: 0, False: 553]
  |  Branch (125:5): [True: 553, False: 0]
  ------------------
  126|    553|    assert(handler != NULL);
  ------------------
  |  Branch (126:5): [True: 0, False: 553]
  |  Branch (126:5): [True: 553, False: 0]
  ------------------
  127|       |
  128|       |#if !INI_USE_STACK
  129|       |    line = (char*)ini_malloc(INI_INITIAL_ALLOC);
  130|       |    if (!line) {
  131|       |        return -2;
  132|       |    }
  133|       |#endif
  134|       |
  135|       |#if INI_HANDLER_LINENO
  136|       |#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno)
  137|       |#else
  138|    553|#define HANDLER(u, s, n, v) handler(u, s, n, v)
  139|    553|#endif
  140|       |
  141|       |    /* Scan through stream line by line */
  142|  7.51k|    while (reader(line, (int)max_line, stream) != NULL) {
  ------------------
  |  Branch (142:12): [True: 6.95k, False: 553]
  ------------------
  143|  6.95k|        offset = strlen(line);
  144|       |
  145|       |#if INI_ALLOW_REALLOC && !INI_USE_STACK
  146|       |        while (max_line < INI_MAX_LINE &&
  147|       |               offset == max_line - 1 && line[offset - 1] != '\n') {
  148|       |            max_line *= 2;
  149|       |            if (max_line > INI_MAX_LINE)
  150|       |                max_line = INI_MAX_LINE;
  151|       |            new_line = ini_realloc(line, max_line);
  152|       |            if (!new_line) {
  153|       |                ini_free(line);
  154|       |                return -2;
  155|       |            }
  156|       |            line = new_line;
  157|       |            if (reader(line + offset, (int)(max_line - offset), stream) == NULL)
  158|       |                break;
  159|       |            offset += strlen(line + offset);
  160|       |        }
  161|       |#endif
  162|       |
  163|  6.95k|        lineno++;
  164|       |
  165|       |        /* If line exceeded INI_MAX_LINE bytes, discard till end of line. */
  166|  6.95k|        if (offset == max_line - 1 && line[offset - 1] != '\n') {
  ------------------
  |  Branch (166:13): [True: 58, False: 6.90k]
  |  Branch (166:39): [True: 55, False: 3]
  ------------------
  167|    241|            while (reader(abyss, sizeof(abyss), stream) != NULL) {
  ------------------
  |  Branch (167:20): [True: 189, False: 52]
  ------------------
  168|    189|                if (!error)
  ------------------
  |  Branch (168:21): [True: 31, False: 158]
  ------------------
  169|     31|                    error = lineno;
  170|    189|                abyss_len = strlen(abyss);
  171|    189|                if (abyss_len > 0 && abyss[abyss_len - 1] == '\n')
  ------------------
  |  Branch (171:21): [True: 189, False: 0]
  |  Branch (171:38): [True: 3, False: 186]
  ------------------
  172|      3|                    break;
  173|    189|            }
  174|     55|        }
  175|       |
  176|  6.95k|        start = line;
  177|  6.95k|#if INI_ALLOW_BOM
  178|  6.95k|        if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
  ------------------
  |  Branch (178:13): [True: 552, False: 6.40k]
  |  Branch (178:28): [True: 31, False: 521]
  ------------------
  179|     31|                           (unsigned char)start[1] == 0xBB &&
  ------------------
  |  Branch (179:28): [True: 18, False: 13]
  ------------------
  180|     18|                           (unsigned char)start[2] == 0xBF) {
  ------------------
  |  Branch (180:28): [True: 2, False: 16]
  ------------------
  181|      2|            start += 3;
  182|      2|        }
  183|  6.95k|#endif
  184|  6.95k|        start = ini_rstrip(ini_lskip(start), line + offset);
  185|       |
  186|  6.95k|        if (strchr(INI_START_COMMENT_PREFIXES, *start)) {
  ------------------
  |  |  120|  6.95k|#define INI_START_COMMENT_PREFIXES ";#"
  ------------------
  |  Branch (186:13): [True: 3.39k, False: 3.56k]
  ------------------
  187|       |            /* Start-of-line comment */
  188|  3.39k|        }
  189|  3.56k|#if INI_ALLOW_MULTILINE
  190|  3.56k|        else if (*prev_name && *start && start > line) {
  ------------------
  |  Branch (190:18): [True: 462, False: 3.10k]
  |  Branch (190:32): [True: 462, False: 0]
  |  Branch (190:42): [True: 235, False: 227]
  ------------------
  191|    235|#if INI_ALLOW_INLINE_COMMENTS
  192|    235|            end = ini_find_chars_or_comment(start, NULL);
  193|    235|            *end = '\0';
  194|    235|            ini_rstrip(start, end);
  195|    235|#endif
  196|       |            /* Non-blank line with leading whitespace, treat as continuation
  197|       |               of previous name's value (as per Python configparser). */
  198|    235|            if (!HANDLER(user, section, prev_name, start) && !error)
  ------------------
  |  |  138|    470|#define HANDLER(u, s, n, v) handler(u, s, n, v)
  ------------------
  |  Branch (198:17): [True: 0, False: 235]
  |  Branch (198:62): [True: 0, False: 0]
  ------------------
  199|      0|                error = lineno;
  200|    235|        }
  201|  3.33k|#endif
  202|  3.33k|        else if (*start == '[') {
  ------------------
  |  Branch (202:18): [True: 1.13k, False: 2.20k]
  ------------------
  203|       |            /* A "[section]" line */
  204|  1.13k|            end = ini_find_chars_or_comment(start + 1, "]");
  205|  1.13k|            if (*end == ']') {
  ------------------
  |  Branch (205:17): [True: 615, False: 517]
  ------------------
  206|    615|                *end = '\0';
  207|    615|                ini_strncpy0(section, start + 1, sizeof(section));
  208|    615|#if INI_ALLOW_MULTILINE
  209|    615|                *prev_name = '\0';
  210|    615|#endif
  211|       |#if INI_CALL_HANDLER_ON_NEW_SECTION
  212|       |                if (!HANDLER(user, section, NULL, NULL) && !error)
  213|       |                    error = lineno;
  214|       |#endif
  215|    615|            }
  216|    517|            else if (!error) {
  ------------------
  |  Branch (216:22): [True: 35, False: 482]
  ------------------
  217|       |                /* No ']' found on section line */
  218|     35|                error = lineno;
  219|     35|            }
  220|  1.13k|        }
  221|  2.20k|        else if (*start) {
  ------------------
  |  Branch (221:18): [True: 2.20k, False: 0]
  ------------------
  222|       |            /* Not a comment, must be a name[=:]value pair */
  223|  2.20k|            end = ini_find_chars_or_comment(start, "=:");
  224|  2.20k|            if (*end == '=' || *end == ':') {
  ------------------
  |  Branch (224:17): [True: 559, False: 1.64k]
  |  Branch (224:32): [True: 850, False: 791]
  ------------------
  225|  1.40k|                *end = '\0';
  226|  1.40k|                name = ini_rstrip(start, end);
  227|  1.40k|                value = end + 1;
  228|  1.40k|#if INI_ALLOW_INLINE_COMMENTS
  229|  1.40k|                end = ini_find_chars_or_comment(value, NULL);
  230|  1.40k|                *end = '\0';
  231|  1.40k|#endif
  232|  1.40k|                value = ini_lskip(value);
  233|  1.40k|                ini_rstrip(value, end);
  234|       |
  235|  1.40k|#if INI_ALLOW_MULTILINE
  236|  1.40k|                ini_strncpy0(prev_name, name, sizeof(prev_name));
  237|  1.40k|#endif
  238|       |                /* Valid name[=:]value pair found, call handler */
  239|  1.40k|                if (!HANDLER(user, section, name, value) && !error)
  ------------------
  |  |  138|  2.81k|#define HANDLER(u, s, n, v) handler(u, s, n, v)
  ------------------
  |  Branch (239:21): [True: 0, False: 1.40k]
  |  Branch (239:61): [True: 0, False: 0]
  ------------------
  240|      0|                    error = lineno;
  241|  1.40k|            }
  242|    791|            else {
  243|       |                /* No '=' or ':' found on name[=:]value line */
  244|       |#if INI_ALLOW_NO_VALUE
  245|       |                *end = '\0';
  246|       |                name = ini_rstrip(start, end);
  247|       |                if (!HANDLER(user, section, name, NULL) && !error)
  248|       |                    error = lineno;
  249|       |#else
  250|    791|                if (!error)
  ------------------
  |  Branch (250:21): [True: 134, False: 657]
  ------------------
  251|    134|                    error = lineno;
  252|    791|#endif
  253|    791|            }
  254|  2.20k|        }
  255|       |
  256|       |#if INI_STOP_ON_FIRST_ERROR
  257|       |        if (error)
  258|       |            break;
  259|       |#endif
  260|  6.95k|    }
  261|       |
  262|       |#if !INI_USE_STACK
  263|       |    ini_free(line);
  264|       |#endif
  265|       |
  266|    553|    return error;
  267|    553|}
ini_parse_string:
  317|    553|int ini_parse_string(const char* string, ini_handler handler, void* user) {
  318|    553|    return ini_parse_string_length(string, strlen(string), handler, user);
  319|    553|}
ini_parse_string_length:
  323|    553|                            ini_handler handler, void* user) {
  324|    553|    ini_parse_string_ctx ctx;
  325|       |
  326|    553|    ctx.ptr = string;
  327|    553|    ctx.num_left = length;
  328|    553|    return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler,
  329|    553|                            user);
  330|    553|}
ini.c:ini_rstrip:
   48|  10.0k|{
   49|  14.6k|    while (end > s && isspace((unsigned char)(*--end)))
  ------------------
  |  Branch (49:12): [True: 8.79k, False: 5.82k]
  |  Branch (49:23): [True: 4.60k, False: 4.18k]
  ------------------
   50|  4.60k|        *end = '\0';
   51|  10.0k|    return s;
   52|  10.0k|}
ini.c:ini_lskip:
   56|  8.36k|{
   57|  12.7k|    while (*s && isspace((unsigned char)(*s)))
  ------------------
  |  Branch (57:12): [True: 8.17k, False: 4.56k]
  |  Branch (57:18): [True: 4.36k, False: 3.80k]
  ------------------
   58|  4.36k|        s++;
   59|  8.36k|    return (char*)s;
   60|  8.36k|}
ini.c:ini_find_chars_or_comment:
   66|  4.97k|{
   67|  4.97k|#if INI_ALLOW_INLINE_COMMENTS
   68|  4.97k|    int was_space = 0;
   69|  27.8k|    while (*s && (!chars || !strchr(chars, *s)) &&
  ------------------
  |  Branch (69:12): [True: 25.0k, False: 2.84k]
  |  Branch (69:19): [True: 6.19k, False: 18.8k]
  |  Branch (69:29): [True: 16.8k, False: 2.02k]
  ------------------
   70|  23.0k|           !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
  ------------------
  |  |  130|  5.41k|#define INI_INLINE_COMMENT_PREFIXES ";"
  ------------------
  |  Branch (70:14): [True: 5.41k, False: 17.5k]
  |  Branch (70:27): [True: 105, False: 5.30k]
  ------------------
   71|  22.9k|        was_space = isspace((unsigned char)(*s));
   72|  22.9k|        s++;
   73|  22.9k|    }
   74|       |#else
   75|       |    while (*s && (!chars || !strchr(chars, *s))) {
   76|       |        s++;
   77|       |    }
   78|       |#endif
   79|  4.97k|    return (char*)s;
   80|  4.97k|}
ini.c:ini_strncpy0:
   85|  2.02k|{
   86|       |    /* Could use strncpy internally, but it causes gcc warnings (see issue #91) */
   87|  2.02k|    size_t i;
   88|  8.89k|    for (i = 0; i < size - 1 && src[i]; i++)
  ------------------
  |  Branch (88:17): [True: 8.83k, False: 59]
  |  Branch (88:33): [True: 6.86k, False: 1.96k]
  ------------------
   89|  6.86k|        dest[i] = src[i];
   90|  2.02k|    dest[i] = '\0';
   91|  2.02k|    return dest;
   92|  2.02k|}
ini.c:ini_reader_string:
  291|  7.75k|static char* ini_reader_string(char* str, int num, void* stream) {
  292|  7.75k|    ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream;
  293|  7.75k|    const char* ctx_ptr = ctx->ptr;
  294|  7.75k|    size_t ctx_num_left = ctx->num_left;
  295|  7.75k|    char* strp = str;
  296|  7.75k|    char c;
  297|       |
  298|  7.75k|    if (ctx_num_left == 0 || num < 2)
  ------------------
  |  Branch (298:9): [True: 605, False: 7.14k]
  |  Branch (298:30): [True: 0, False: 7.14k]
  ------------------
  299|    605|        return NULL;
  300|       |
  301|  37.4k|    while (num > 1 && ctx_num_left != 0) {
  ------------------
  |  Branch (301:12): [True: 37.2k, False: 204]
  |  Branch (301:23): [True: 36.7k, False: 518]
  ------------------
  302|  36.7k|        c = *ctx_ptr++;
  303|  36.7k|        ctx_num_left--;
  304|  36.7k|        *strp++ = c;
  305|  36.7k|        if (c == '\n')
  ------------------
  |  Branch (305:13): [True: 6.42k, False: 30.3k]
  ------------------
  306|  6.42k|            break;
  307|  30.3k|        num--;
  308|  30.3k|    }
  309|       |
  310|  7.14k|    *strp = '\0';
  311|  7.14k|    ctx->ptr = ctx_ptr;
  312|  7.14k|    ctx->num_left = ctx_num_left;
  313|  7.14k|    return str;
  314|  7.75k|}

dumper:
   30|  1.64k|{
   31|  1.64k|    User = *((int*)user);
   32|  1.64k|    if (strcmp(section, Prev_section)) {
  ------------------
  |  Branch (32:9): [True: 368, False: 1.27k]
  ------------------
   33|    368|        strncpy(Prev_section, section, sizeof(Prev_section));
   34|    368|        Prev_section[sizeof(Prev_section) - 1] = '\0';
   35|    368|    }
   36|  1.64k|    return 1;
   37|  1.64k|}
LLVMFuzzerTestOneInput:
   41|    582|{
   42|    582|    char *data_in;
   43|    582|    static int u = 100;
   44|       |
   45|    582|    if (size < kMinInputLength || size > kMaxInputLength) {
  ------------------
  |  |   22|  1.16k|#define kMinInputLength 8
  ------------------
                  if (size < kMinInputLength || size > kMaxInputLength) {
  ------------------
  |  |   23|    578|#define kMaxInputLength 512
  ------------------
  |  Branch (45:9): [True: 4, False: 578]
  |  Branch (45:35): [True: 25, False: 553]
  ------------------
   46|     29|        return 0;
   47|     29|    }
   48|       |
   49|    553|    Prev_section[0] = '\0';
   50|       |
   51|    553|    data_in = calloc((size + 1), sizeof(char));
   52|    553|    if (!data_in) return 0;
  ------------------
  |  Branch (52:9): [True: 0, False: 553]
  ------------------
   53|       |
   54|    553|    memcpy(data_in, data, size);
   55|       |
   56|    553|    ini_parse_string(data_in, dumper, &u);
   57|       |
   58|    553|    free(data_in);
   59|       |
   60|    553|    return 0;
   61|    553|}

