ini_parse_stream:
  100|    546|{
  101|       |    /* Uses a fair bit of stack (use heap instead if you need to) */
  102|    546|#if INI_USE_STACK
  103|    546|    char line[INI_MAX_LINE];
  104|    546|    size_t max_line = INI_MAX_LINE;
  ------------------
  |  |  141|    546|#define INI_MAX_LINE 200
  ------------------
  105|       |#else
  106|       |    char* line;
  107|       |    size_t max_line = INI_INITIAL_ALLOC;
  108|       |#endif
  109|       |#if INI_ALLOW_REALLOC && !INI_USE_STACK
  110|       |    char* new_line;
  111|       |#endif
  112|    546|    char section[MAX_SECTION] = "";
  113|    546|#if INI_ALLOW_MULTILINE
  114|    546|    char prev_name[MAX_NAME] = "";
  115|    546|#endif
  116|       |
  117|    546|    size_t offset;
  118|    546|    char* start;
  119|    546|    char* end;
  120|    546|    char* name;
  121|    546|    char* value;
  122|    546|    int lineno = 0;
  123|    546|    int error = 0;
  124|    546|    char abyss[16];  /* Used to consume input when a line is too long. */
  125|    546|    size_t abyss_len;
  126|       |
  127|    546|    assert(reader != NULL);
  ------------------
  |  Branch (127:5): [True: 0, False: 546]
  |  Branch (127:5): [True: 546, False: 0]
  ------------------
  128|    546|    assert(stream != NULL);
  ------------------
  |  Branch (128:5): [True: 0, False: 546]
  |  Branch (128:5): [True: 546, False: 0]
  ------------------
  129|    546|    assert(handler != NULL);
  ------------------
  |  Branch (129:5): [True: 0, False: 546]
  |  Branch (129:5): [True: 546, False: 0]
  ------------------
  130|       |
  131|       |#if !INI_USE_STACK
  132|       |    line = (char*)ini_malloc(INI_INITIAL_ALLOC);
  133|       |    if (!line) {
  134|       |        return -2;
  135|       |    }
  136|       |#endif
  137|       |
  138|       |#if INI_HANDLER_LINENO
  139|       |#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno)
  140|       |#else
  141|    546|#define HANDLER(u, s, n, v) handler(u, s, n, v)
  142|    546|#endif
  143|       |
  144|       |    /* Scan through stream line by line */
  145|  7.56k|    while (reader(line, (int)max_line, stream) != NULL) {
  ------------------
  |  Branch (145:12): [True: 7.02k, False: 546]
  ------------------
  146|  7.02k|        offset = strlen(line);
  147|       |
  148|       |#if INI_ALLOW_REALLOC && !INI_USE_STACK
  149|       |        while (max_line < INI_MAX_LINE &&
  150|       |               offset == max_line - 1 && line[offset - 1] != '\n') {
  151|       |            max_line *= 2;
  152|       |            if (max_line > INI_MAX_LINE)
  153|       |                max_line = INI_MAX_LINE;
  154|       |            new_line = ini_realloc(line, max_line);
  155|       |            if (!new_line) {
  156|       |                ini_free(line);
  157|       |                return -2;
  158|       |            }
  159|       |            line = new_line;
  160|       |            if (reader(line + offset, (int)(max_line - offset), stream) == NULL)
  161|       |                break;
  162|       |            offset += strlen(line + offset);
  163|       |        }
  164|       |#endif
  165|       |
  166|  7.02k|        lineno++;
  167|       |
  168|       |        /* If line exceeded INI_MAX_LINE bytes, discard till end of line. */
  169|  7.02k|        if (offset == max_line - 1 && line[offset - 1] != '\n') {
  ------------------
  |  Branch (169:13): [True: 56, False: 6.96k]
  |  Branch (169:39): [True: 53, False: 3]
  ------------------
  170|    256|            while (reader(abyss, sizeof(abyss), stream) != NULL) {
  ------------------
  |  Branch (170:20): [True: 210, False: 46]
  ------------------
  171|    210|                if (!error)
  ------------------
  |  Branch (171:21): [True: 29, False: 181]
  ------------------
  172|     29|                    error = lineno;
  173|    210|                abyss_len = strlen(abyss);
  174|    210|                if (abyss_len > 0 && abyss[abyss_len - 1] == '\n')
  ------------------
  |  Branch (174:21): [True: 210, False: 0]
  |  Branch (174:38): [True: 7, False: 203]
  ------------------
  175|      7|                    break;
  176|    210|            }
  177|     53|        }
  178|       |
  179|  7.02k|        start = line;
  180|  7.02k|#if INI_ALLOW_BOM
  181|  7.02k|        if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
  ------------------
  |  Branch (181:13): [True: 545, False: 6.47k]
  |  Branch (181:28): [True: 31, False: 514]
  ------------------
  182|     31|                           (unsigned char)start[1] == 0xBB &&
  ------------------
  |  Branch (182:28): [True: 18, False: 13]
  ------------------
  183|     18|                           (unsigned char)start[2] == 0xBF) {
  ------------------
  |  Branch (183:28): [True: 1, False: 17]
  ------------------
  184|      1|            start += 3;
  185|      1|        }
  186|  7.02k|#endif
  187|  7.02k|        start = ini_rstrip(ini_lskip(start), line + offset);
  188|       |
  189|  7.02k|        if (strchr(INI_START_COMMENT_PREFIXES, *start)) {
  ------------------
  |  |  120|  7.02k|#define INI_START_COMMENT_PREFIXES ";#"
  ------------------
  |  Branch (189:13): [True: 3.35k, False: 3.66k]
  ------------------
  190|       |            /* Start-of-line comment */
  191|  3.35k|        }
  192|  3.66k|#if INI_ALLOW_MULTILINE
  193|  3.66k|        else if (*prev_name && *start && start > line) {
  ------------------
  |  Branch (193:18): [True: 542, False: 3.12k]
  |  Branch (193:32): [True: 542, False: 0]
  |  Branch (193:42): [True: 282, False: 260]
  ------------------
  194|    282|#if INI_ALLOW_INLINE_COMMENTS
  195|    282|            end = ini_find_chars_or_comment(start, NULL);
  196|    282|            *end = '\0';
  197|    282|            ini_rstrip(start, end);
  198|    282|#endif
  199|       |            /* Non-blank line with leading whitespace, treat as continuation
  200|       |               of previous name's value (as per Python configparser). */
  201|    282|            if (!HANDLER(user, section, prev_name, start) && !error)
  ------------------
  |  |  141|    564|#define HANDLER(u, s, n, v) handler(u, s, n, v)
  ------------------
  |  Branch (201:17): [True: 0, False: 282]
  |  Branch (201:62): [True: 0, False: 0]
  ------------------
  202|      0|                error = lineno;
  203|    282|        }
  204|  3.38k|#endif
  205|  3.38k|        else if (*start == '[') {
  ------------------
  |  Branch (205:18): [True: 1.06k, False: 2.31k]
  ------------------
  206|       |            /* A "[section]" line */
  207|  1.06k|            end = ini_find_chars_or_comment(start + 1, "]");
  208|  1.06k|            if (*end == ']') {
  ------------------
  |  Branch (208:17): [True: 608, False: 459]
  ------------------
  209|    608|                *end = '\0';
  210|    608|                ini_strncpy0(section, start + 1, sizeof(section));
  211|    608|#if INI_ALLOW_MULTILINE
  212|    608|                *prev_name = '\0';
  213|    608|#endif
  214|       |#if INI_CALL_HANDLER_ON_NEW_SECTION
  215|       |                if (!HANDLER(user, section, NULL, NULL) && !error)
  216|       |                    error = lineno;
  217|       |#endif
  218|    608|            }
  219|    459|            else if (!error) {
  ------------------
  |  Branch (219:22): [True: 42, False: 417]
  ------------------
  220|       |                /* No ']' found on section line */
  221|     42|                error = lineno;
  222|     42|            }
  223|  1.06k|        }
  224|  2.31k|        else if (*start) {
  ------------------
  |  Branch (224:18): [True: 2.31k, False: 0]
  ------------------
  225|       |            /* Not a comment, must be a name[=:]value pair */
  226|  2.31k|            end = ini_find_chars_or_comment(start, "=:");
  227|  2.31k|            if (*end == '=' || *end == ':') {
  ------------------
  |  Branch (227:17): [True: 929, False: 1.38k]
  |  Branch (227:32): [True: 539, False: 849]
  ------------------
  228|  1.46k|                *end = '\0';
  229|  1.46k|                name = ini_rstrip(start, end);
  230|  1.46k|                value = end + 1;
  231|  1.46k|#if INI_ALLOW_INLINE_COMMENTS
  232|  1.46k|                end = ini_find_chars_or_comment(value, NULL);
  233|  1.46k|                *end = '\0';
  234|  1.46k|#endif
  235|  1.46k|                value = ini_lskip(value);
  236|  1.46k|                ini_rstrip(value, end);
  237|       |
  238|  1.46k|#if INI_ALLOW_MULTILINE
  239|  1.46k|                ini_strncpy0(prev_name, name, sizeof(prev_name));
  240|  1.46k|#endif
  241|       |                /* Valid name[=:]value pair found, call handler */
  242|  1.46k|                if (!HANDLER(user, section, name, value) && !error)
  ------------------
  |  |  141|  2.93k|#define HANDLER(u, s, n, v) handler(u, s, n, v)
  ------------------
  |  Branch (242:21): [True: 0, False: 1.46k]
  |  Branch (242:61): [True: 0, False: 0]
  ------------------
  243|      0|                    error = lineno;
  244|  1.46k|            }
  245|    849|            else {
  246|       |                /* No '=' or ':' found on name[=:]value line */
  247|       |#if INI_ALLOW_NO_VALUE
  248|       |                *end = '\0';
  249|       |                name = ini_rstrip(start, end);
  250|       |                if (!HANDLER(user, section, name, NULL) && !error)
  251|       |                    error = lineno;
  252|       |#else
  253|    849|                if (!error)
  ------------------
  |  Branch (253:21): [True: 122, False: 727]
  ------------------
  254|    122|                    error = lineno;
  255|    849|#endif
  256|    849|            }
  257|  2.31k|        }
  258|       |
  259|       |#if INI_STOP_ON_FIRST_ERROR
  260|       |        if (error)
  261|       |            break;
  262|       |#endif
  263|  7.02k|    }
  264|       |
  265|       |#if !INI_USE_STACK
  266|       |    ini_free(line);
  267|       |#endif
  268|       |
  269|    546|    return error;
  270|    546|}
ini_parse_string:
  320|    546|int ini_parse_string(const char* string, ini_handler handler, void* user) {
  321|    546|    return ini_parse_string_length(string, strlen(string), handler, user);
  322|    546|}
ini_parse_string_length:
  326|    546|                            ini_handler handler, void* user) {
  327|    546|    ini_parse_string_ctx ctx;
  328|       |
  329|    546|    ctx.ptr = string;
  330|    546|    ctx.num_left = length;
  331|    546|    return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler,
  332|    546|                            user);
  333|    546|}
ini.c:ini_rstrip:
   51|  10.2k|{
   52|  15.2k|    while (end > s && isspace((unsigned char)(*--end)))
  ------------------
  |  Branch (52:12): [True: 9.30k, False: 5.89k]
  |  Branch (52:23): [True: 4.96k, False: 4.34k]
  ------------------
   53|  4.96k|        *end = '\0';
   54|  10.2k|    return s;
   55|  10.2k|}
ini.c:ini_lskip:
   59|  8.48k|{
   60|  12.8k|    while (*s && isspace((unsigned char)(*s)))
  ------------------
  |  Branch (60:12): [True: 8.20k, False: 4.60k]
  |  Branch (60:18): [True: 4.31k, False: 3.88k]
  ------------------
   61|  4.31k|        s++;
   62|  8.48k|    return (char*)s;
   63|  8.48k|}
ini.c:ini_find_chars_or_comment:
   69|  5.13k|{
   70|  5.13k|#if INI_ALLOW_INLINE_COMMENTS
   71|  5.13k|    int was_space = 0;
   72|  28.2k|    while (*s && (!chars || !strchr(chars, *s)) &&
  ------------------
  |  Branch (72:12): [True: 25.3k, False: 2.89k]
  |  Branch (72:19): [True: 6.33k, False: 19.0k]
  |  Branch (72:29): [True: 16.9k, False: 2.07k]
  ------------------
   73|  23.2k|           !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
  ------------------
  |  |  130|  6.31k|#define INI_INLINE_COMMENT_PREFIXES ";"
  ------------------
  |  Branch (73:14): [True: 6.31k, False: 16.9k]
  |  Branch (73:27): [True: 162, False: 6.14k]
  ------------------
   74|  23.1k|        was_space = isspace((unsigned char)(*s));
   75|  23.1k|        s++;
   76|  23.1k|    }
   77|       |#else
   78|       |    while (*s && (!chars || !strchr(chars, *s))) {
   79|       |        s++;
   80|       |    }
   81|       |#endif
   82|  5.13k|    return (char*)s;
   83|  5.13k|}
ini.c:ini_strncpy0:
   88|  2.07k|{
   89|       |    /* Could use strncpy internally, but it causes gcc warnings (see issue #91) */
   90|  2.07k|    size_t i;
   91|  9.06k|    for (i = 0; i < size - 1 && src[i]; i++)
  ------------------
  |  Branch (91:17): [True: 9.00k, False: 61]
  |  Branch (91:33): [True: 6.99k, False: 2.01k]
  ------------------
   92|  6.99k|        dest[i] = src[i];
   93|  2.07k|    dest[i] = '\0';
   94|  2.07k|    return dest;
   95|  2.07k|}
ini.c:ini_reader_string:
  294|  7.82k|static char* ini_reader_string(char* str, int num, void* stream) {
  295|  7.82k|    ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream;
  296|  7.82k|    const char* ctx_ptr = ctx->ptr;
  297|  7.82k|    size_t ctx_num_left = ctx->num_left;
  298|  7.82k|    char* strp = str;
  299|  7.82k|    char c;
  300|       |
  301|  7.82k|    if (ctx_num_left == 0 || num < 2)
  ------------------
  |  Branch (301:9): [True: 592, False: 7.23k]
  |  Branch (301:30): [True: 0, False: 7.23k]
  ------------------
  302|    592|        return NULL;
  303|       |
  304|  37.8k|    while (num > 1 && ctx_num_left != 0) {
  ------------------
  |  Branch (304:12): [True: 37.6k, False: 224]
  |  Branch (304:23): [True: 37.1k, False: 507]
  ------------------
  305|  37.1k|        c = *ctx_ptr++;
  306|  37.1k|        ctx_num_left--;
  307|  37.1k|        *strp++ = c;
  308|  37.1k|        if (c == '\n')
  ------------------
  |  Branch (308:13): [True: 6.49k, False: 30.6k]
  ------------------
  309|  6.49k|            break;
  310|  30.6k|        num--;
  311|  30.6k|    }
  312|       |
  313|  7.23k|    *strp = '\0';
  314|  7.23k|    ctx->ptr = ctx_ptr;
  315|  7.23k|    ctx->num_left = ctx_num_left;
  316|  7.23k|    return str;
  317|  7.82k|}

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

