ini_parse_stream:
  100|    542|{
  101|       |    /* Uses a fair bit of stack (use heap instead if you need to) */
  102|    542|#if INI_USE_STACK
  103|    542|    char line[INI_MAX_LINE];
  104|    542|    size_t max_line = INI_MAX_LINE;
  ------------------
  |  |  141|    542|#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|    542|    char section[MAX_SECTION] = "";
  113|    542|#if INI_ALLOW_MULTILINE
  114|    542|    char prev_name[MAX_NAME] = "";
  115|    542|#endif
  116|       |
  117|    542|    size_t offset;
  118|    542|    char* start;
  119|    542|    char* end;
  120|    542|    char* name;
  121|    542|    char* value;
  122|    542|    int lineno = 0;
  123|    542|    int error = 0;
  124|    542|    char abyss[16];  /* Used to consume input when a line is too long. */
  125|    542|    size_t abyss_len;
  126|       |
  127|    542|    assert(reader != NULL);
  ------------------
  |  Branch (127:5): [True: 0, False: 542]
  |  Branch (127:5): [True: 542, False: 0]
  ------------------
  128|    542|    assert(stream != NULL);
  ------------------
  |  Branch (128:5): [True: 0, False: 542]
  |  Branch (128:5): [True: 542, False: 0]
  ------------------
  129|    542|    assert(handler != NULL);
  ------------------
  |  Branch (129:5): [True: 0, False: 542]
  |  Branch (129:5): [True: 542, 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|    542|#define HANDLER(u, s, n, v) handler(u, s, n, v)
  142|    542|#endif
  143|       |
  144|       |    /* Scan through stream line by line */
  145|  7.87k|    while (reader(line, (int)max_line, stream) != NULL) {
  ------------------
  |  Branch (145:12): [True: 7.33k, False: 542]
  ------------------
  146|  7.33k|        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.33k|        lineno++;
  167|       |
  168|       |        /* If line exceeded INI_MAX_LINE bytes, discard till end of line. */
  169|  7.33k|        if (offset == max_line - 1 && line[offset - 1] != '\n') {
  ------------------
  |  Branch (169:13): [True: 54, False: 7.27k]
  |  Branch (169:39): [True: 51, False: 3]
  ------------------
  170|    217|            while (reader(abyss, sizeof(abyss), stream) != NULL) {
  ------------------
  |  Branch (170:20): [True: 172, False: 45]
  ------------------
  171|    172|                if (!error)
  ------------------
  |  Branch (171:21): [True: 28, False: 144]
  ------------------
  172|     28|                    error = lineno;
  173|    172|                abyss_len = strlen(abyss);
  174|    172|                if (abyss_len > 0 && abyss[abyss_len - 1] == '\n')
  ------------------
  |  Branch (174:21): [True: 172, False: 0]
  |  Branch (174:38): [True: 6, False: 166]
  ------------------
  175|      6|                    break;
  176|    172|            }
  177|     51|        }
  178|       |
  179|  7.33k|        start = line;
  180|  7.33k|#if INI_ALLOW_BOM
  181|  7.33k|        if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
  ------------------
  |  Branch (181:13): [True: 541, False: 6.78k]
  |  Branch (181:28): [True: 29, False: 512]
  ------------------
  182|     29|                           (unsigned char)start[1] == 0xBB &&
  ------------------
  |  Branch (182:28): [True: 15, False: 14]
  ------------------
  183|     15|                           (unsigned char)start[2] == 0xBF) {
  ------------------
  |  Branch (183:28): [True: 1, False: 14]
  ------------------
  184|      1|            start += 3;
  185|      1|        }
  186|  7.33k|#endif
  187|  7.33k|        start = ini_rstrip(ini_lskip(start), line + offset);
  188|       |
  189|  7.33k|        if (strchr(INI_START_COMMENT_PREFIXES, *start)) {
  ------------------
  |  |  120|  7.33k|#define INI_START_COMMENT_PREFIXES ";#"
  ------------------
  |  Branch (189:13): [True: 3.70k, False: 3.62k]
  ------------------
  190|       |            /* Start-of-line comment */
  191|  3.70k|        }
  192|  3.62k|#if INI_ALLOW_MULTILINE
  193|  3.62k|        else if (*prev_name && *start && start > line) {
  ------------------
  |  Branch (193:18): [True: 517, False: 3.11k]
  |  Branch (193:32): [True: 517, False: 0]
  |  Branch (193:42): [True: 232, False: 285]
  ------------------
  194|    232|#if INI_ALLOW_INLINE_COMMENTS
  195|    232|            end = ini_find_chars_or_comment(start, NULL);
  196|    232|            *end = '\0';
  197|    232|            ini_rstrip(start, end);
  198|    232|#endif
  199|       |            /* Non-blank line with leading whitespace, treat as continuation
  200|       |               of previous name's value (as per Python configparser). */
  201|    232|            if (!HANDLER(user, section, prev_name, start) && !error)
  ------------------
  |  |  141|    464|#define HANDLER(u, s, n, v) handler(u, s, n, v)
  ------------------
  |  Branch (201:17): [True: 0, False: 232]
  |  Branch (201:62): [True: 0, False: 0]
  ------------------
  202|      0|                error = lineno;
  203|    232|        }
  204|  3.39k|#endif
  205|  3.39k|        else if (*start == '[') {
  ------------------
  |  Branch (205:18): [True: 1.26k, False: 2.13k]
  ------------------
  206|       |            /* A "[section]" line */
  207|  1.26k|            end = ini_find_chars_or_comment(start + 1, "]");
  208|  1.26k|            if (*end == ']') {
  ------------------
  |  Branch (208:17): [True: 693, False: 573]
  ------------------
  209|    693|                *end = '\0';
  210|    693|                ini_strncpy0(section, start + 1, sizeof(section));
  211|    693|#if INI_ALLOW_MULTILINE
  212|    693|                *prev_name = '\0';
  213|    693|#endif
  214|       |#if INI_CALL_HANDLER_ON_NEW_SECTION
  215|       |                if (!HANDLER(user, section, NULL, NULL) && !error)
  216|       |                    error = lineno;
  217|       |#endif
  218|    693|            }
  219|    573|            else if (!error) {
  ------------------
  |  Branch (219:22): [True: 45, False: 528]
  ------------------
  220|       |                /* No ']' found on section line */
  221|     45|                error = lineno;
  222|     45|            }
  223|  1.26k|        }
  224|  2.13k|        else if (*start) {
  ------------------
  |  Branch (224:18): [True: 2.13k, False: 0]
  ------------------
  225|       |            /* Not a comment, must be a name[=:]value pair */
  226|  2.13k|            end = ini_find_chars_or_comment(start, "=:");
  227|  2.13k|            if (*end == '=' || *end == ':') {
  ------------------
  |  Branch (227:17): [True: 520, False: 1.61k]
  |  Branch (227:32): [True: 887, False: 724]
  ------------------
  228|  1.40k|                *end = '\0';
  229|  1.40k|                name = ini_rstrip(start, end);
  230|  1.40k|                value = end + 1;
  231|  1.40k|#if INI_ALLOW_INLINE_COMMENTS
  232|  1.40k|                end = ini_find_chars_or_comment(value, NULL);
  233|  1.40k|                *end = '\0';
  234|  1.40k|#endif
  235|  1.40k|                value = ini_lskip(value);
  236|  1.40k|                ini_rstrip(value, end);
  237|       |
  238|  1.40k|#if INI_ALLOW_MULTILINE
  239|  1.40k|                ini_strncpy0(prev_name, name, sizeof(prev_name));
  240|  1.40k|#endif
  241|       |                /* Valid name[=:]value pair found, call handler */
  242|  1.40k|                if (!HANDLER(user, section, name, value) && !error)
  ------------------
  |  |  141|  2.81k|#define HANDLER(u, s, n, v) handler(u, s, n, v)
  ------------------
  |  Branch (242:21): [True: 0, False: 1.40k]
  |  Branch (242:61): [True: 0, False: 0]
  ------------------
  243|      0|                    error = lineno;
  244|  1.40k|            }
  245|    724|            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|    724|                if (!error)
  ------------------
  |  Branch (253:21): [True: 123, False: 601]
  ------------------
  254|    123|                    error = lineno;
  255|    724|#endif
  256|    724|            }
  257|  2.13k|        }
  258|       |
  259|       |#if INI_STOP_ON_FIRST_ERROR
  260|       |        if (error)
  261|       |            break;
  262|       |#endif
  263|  7.33k|    }
  264|       |
  265|       |#if !INI_USE_STACK
  266|       |    ini_free(line);
  267|       |#endif
  268|       |
  269|    542|    return error;
  270|    542|}
ini_parse_string:
  320|    542|int ini_parse_string(const char* string, ini_handler handler, void* user) {
  321|    542|    return ini_parse_string_length(string, strlen(string), handler, user);
  322|    542|}
ini_parse_string_length:
  326|    542|                            ini_handler handler, void* user) {
  327|    542|    ini_parse_string_ctx ctx;
  328|       |
  329|    542|    ctx.ptr = string;
  330|    542|    ctx.num_left = length;
  331|    542|    return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler,
  332|    542|                            user);
  333|    542|}
ini.c:ini_rstrip:
   51|  10.3k|{
   52|  15.1k|    while (end > s && isspace((unsigned char)(*--end)))
  ------------------
  |  Branch (52:12): [True: 9.02k, False: 6.10k]
  |  Branch (52:23): [True: 4.75k, False: 4.27k]
  ------------------
   53|  4.75k|        *end = '\0';
   54|  10.3k|    return s;
   55|  10.3k|}
ini.c:ini_lskip:
   59|  8.73k|{
   60|  13.3k|    while (*s && isspace((unsigned char)(*s)))
  ------------------
  |  Branch (60:12): [True: 8.44k, False: 4.88k]
  |  Branch (60:18): [True: 4.59k, False: 3.85k]
  ------------------
   61|  4.59k|        s++;
   62|  8.73k|    return (char*)s;
   63|  8.73k|}
ini.c:ini_find_chars_or_comment:
   69|  5.03k|{
   70|  5.03k|#if INI_ALLOW_INLINE_COMMENTS
   71|  5.03k|    int was_space = 0;
   72|  26.9k|    while (*s && (!chars || !strchr(chars, *s)) &&
  ------------------
  |  Branch (72:12): [True: 24.0k, False: 2.89k]
  |  Branch (72:19): [True: 5.78k, False: 18.2k]
  |  Branch (72:29): [True: 16.1k, False: 2.10k]
  ------------------
   73|  21.9k|           !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
  ------------------
  |  |  130|  4.70k|#define INI_INLINE_COMMENT_PREFIXES ";"
  ------------------
  |  Branch (73:14): [True: 4.70k, False: 17.2k]
  |  Branch (73:27): [True: 37, False: 4.66k]
  ------------------
   74|  21.8k|        was_space = isspace((unsigned char)(*s));
   75|  21.8k|        s++;
   76|  21.8k|    }
   77|       |#else
   78|       |    while (*s && (!chars || !strchr(chars, *s))) {
   79|       |        s++;
   80|       |    }
   81|       |#endif
   82|  5.03k|    return (char*)s;
   83|  5.03k|}
ini.c:ini_strncpy0:
   88|  2.10k|{
   89|       |    /* Could use strncpy internally, but it causes gcc warnings (see issue #91) */
   90|  2.10k|    size_t i;
   91|  9.38k|    for (i = 0; i < size - 1 && src[i]; i++)
  ------------------
  |  Branch (91:17): [True: 9.32k, False: 61]
  |  Branch (91:33): [True: 7.28k, False: 2.03k]
  ------------------
   92|  7.28k|        dest[i] = src[i];
   93|  2.10k|    dest[i] = '\0';
   94|  2.10k|    return dest;
   95|  2.10k|}
ini.c:ini_reader_string:
  294|  8.08k|static char* ini_reader_string(char* str, int num, void* stream) {
  295|  8.08k|    ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream;
  296|  8.08k|    const char* ctx_ptr = ctx->ptr;
  297|  8.08k|    size_t ctx_num_left = ctx->num_left;
  298|  8.08k|    char* strp = str;
  299|  8.08k|    char c;
  300|       |
  301|  8.08k|    if (ctx_num_left == 0 || num < 2)
  ------------------
  |  Branch (301:9): [True: 587, False: 7.50k]
  |  Branch (301:30): [True: 0, False: 7.50k]
  ------------------
  302|    587|        return NULL;
  303|       |
  304|  36.5k|    while (num > 1 && ctx_num_left != 0) {
  ------------------
  |  Branch (304:12): [True: 36.3k, False: 185]
  |  Branch (304:23): [True: 35.8k, False: 500]
  ------------------
  305|  35.8k|        c = *ctx_ptr++;
  306|  35.8k|        ctx_num_left--;
  307|  35.8k|        *strp++ = c;
  308|  35.8k|        if (c == '\n')
  ------------------
  |  Branch (308:13): [True: 6.81k, False: 29.0k]
  ------------------
  309|  6.81k|            break;
  310|  29.0k|        num--;
  311|  29.0k|    }
  312|       |
  313|  7.50k|    *strp = '\0';
  314|  7.50k|    ctx->ptr = ctx_ptr;
  315|  7.50k|    ctx->num_left = ctx_num_left;
  316|  7.50k|    return str;
  317|  8.08k|}

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

