csv_create:
   58|    309|{
   59|    309|	memset(csv, 0, sizeof(struct csv));
   60|    309|	csv->delimiter= ',';
   61|    309|	csv->quote_char = '\"';
   62|    309|	csv->realloc = realloc;
   63|    309|	csv->emit_field = csv_emit_field_empty;
   64|    309|	csv->emit_row = csv_emit_row_empty;
   65|    309|}
csv_destroy:
   69|    309|{
   70|    309|	if (csv->buf) {
  ------------------
  |  Branch (70:6): [True: 56, False: 253]
  ------------------
   71|     56|		csv->realloc(csv->buf, 0);
   72|     56|		csv->buf = NULL;
   73|     56|	}
   74|    309|}
csv_isvalid:
   78|    309|{
   79|    309|	if (csv->error_status == CSV_ER_OK && csv->state == CSV_IN_QUOTES)
  ------------------
  |  Branch (79:6): [True: 309, False: 0]
  |  Branch (79:40): [True: 56, False: 253]
  ------------------
   80|     56|		csv->error_status = CSV_ER_INVALID;
   81|    309|	return !csv->error_status;
   82|    309|}
csv_parse_impl:
  127|    309|{
  128|    309|	if (end - s == 0)
  ------------------
  |  Branch (128:6): [True: 0, False: 309]
  ------------------
  129|      0|		return NULL;
  130|    309|	assert(end - s > 0);
  131|    309|	assert(csv->emit_field);
  132|    309|	assert(csv->emit_row);
  133|  8.20M|	for (const char *p = s; p != end; p++) {
  ------------------
  |  Branch (133:26): [True: 8.20M, False: 309]
  ------------------
  134|  8.20M|		bool is_line_end = (*p == '\n' || *p == '\r');
  ------------------
  |  Branch (134:23): [True: 60.8k, False: 8.14M]
  |  Branch (134:37): [True: 1.67k, False: 8.14M]
  ------------------
  135|       |		/* realloc buffer */
  136|  8.20M|		if (csv->buf == NULL ||
  ------------------
  |  Branch (136:7): [True: 309, False: 8.20M]
  ------------------
  137|  8.20M|		   (csv->bufp && csv->buf_len < (size_t)(csv->bufp - csv->buf + 1))) {
  ------------------
  |  Branch (137:7): [True: 8.14M, False: 61.4k]
  |  Branch (137:20): [True: 237, False: 8.14M]
  ------------------
  138|    546|			size_t new_size = csv->buf_len * 2;
  139|    546|			if (csv->buf_len == 0 || csv->buf == NULL)
  ------------------
  |  Branch (139:8): [True: 309, False: 237]
  |  Branch (139:29): [True: 0, False: 237]
  ------------------
  140|    309|				new_size = 256;
  141|    546|			char *new_buf = (char *)csv->realloc(csv->buf, new_size);
  142|    546|			if (new_buf == NULL) {
  ------------------
  |  Branch (142:8): [True: 0, False: 546]
  ------------------
  143|      0|				csv->error_status = CSV_ER_MEMORY_ERROR;
  144|      0|				return NULL;
  145|      0|			}
  146|    546|			csv->buf_len = new_size;
  147|    546|			csv->bufp = csv->bufp - csv->buf + new_buf;
  148|    546|			csv->buf = new_buf;
  149|    546|		}
  150|       |		/* \r\n (or \n\r) linebreak, not in quotes */
  151|  8.20M|		if (is_line_end && csv->state != CSV_IN_QUOTES &&
  ------------------
  |  Branch (151:7): [True: 62.5k, False: 8.14M]
  |  Branch (151:22): [True: 61.5k, False: 1.00k]
  ------------------
  152|  8.20M|		   *p != csv->prev_symbol &&
  ------------------
  |  Branch (152:6): [True: 60.9k, False: 575]
  ------------------
  153|  8.20M|		   (csv->prev_symbol  == '\n' || csv->prev_symbol == '\r')) {
  ------------------
  |  Branch (153:7): [True: 381, False: 60.5k]
  |  Branch (153:36): [True: 322, False: 60.2k]
  ------------------
  154|    703|			csv->prev_symbol = '\0';
  155|    703|			continue;
  156|    703|		}
  157|  8.20M|		csv->prev_symbol = *p;
  158|       |		/* 2 switches to avoid code dublicates */
  159|  8.20M|		switch (csv->state) {
  ------------------
  |  Branch (159:11): [True: 8.13M, False: 64.5k]
  ------------------
  160|  61.9k|		case CSV_LEADING_SPACES:
  ------------------
  |  Branch (160:3): [True: 61.9k, False: 8.14M]
  ------------------
  161|  61.9k|			csv->bufp = csv->buf;
  162|  61.9k|			if (*p == ' ') /* skip spaces */
  ------------------
  |  Branch (162:8): [True: 263, False: 61.6k]
  ------------------
  163|    263|				continue;
  164|  61.6k|			csv->state = CSV_OUT_OF_QUOTES;
  165|       |			/* symbol not handled, continue to the next switch */
  166|  61.6k|			break;
  167|  1.36k|		case CSV_QUOTE_OPENING:
  ------------------
  |  Branch (167:3): [True: 1.36k, False: 8.20M]
  ------------------
  168|  1.36k|			if (*p == csv->quote_char && csv->bufp) {
  ------------------
  |  Branch (168:8): [True: 398, False: 962]
  |  Branch (168:33): [True: 398, False: 0]
  ------------------
  169|       |				/* double-quote "" */
  170|    398|				*csv->bufp++ = csv->quote_char;
  171|    398|				csv->state = CSV_OUT_OF_QUOTES;
  172|    398|				continue;
  173|    398|			}
  174|    962|			csv->state = CSV_IN_QUOTES;
  175|       |			/* symbol not handled, continue to the next switch */
  176|    962|			break;
  177|  1.28k|		case CSV_QUOTE_CLOSING:
  ------------------
  |  Branch (177:3): [True: 1.28k, False: 8.20M]
  ------------------
  178|  1.28k|			if (*p == csv->quote_char) {
  ------------------
  |  Branch (178:8): [True: 384, False: 898]
  ------------------
  179|       |				/* double-quote "" */
  180|    384|				*csv->bufp++ = csv->quote_char;
  181|    384|				csv->state = CSV_IN_QUOTES;
  182|    384|				continue;
  183|    384|			}
  184|    898|			csv->state = CSV_OUT_OF_QUOTES;
  185|       |			/* symbol not handled, continue to the next switch */
  186|    898|			break;
  187|  8.20M|		}
  188|       |
  189|  8.20M|		switch (csv->state) {
  ------------------
  |  Branch (189:11): [True: 0, False: 8.20M]
  ------------------
  190|  7.12M|		case CSV_OUT_OF_QUOTES:
  ------------------
  |  Branch (190:3): [True: 7.12M, False: 1.07M]
  ------------------
  191|  7.12M|			if (is_line_end || *p == csv->delimiter) {
  ------------------
  |  Branch (191:8): [True: 60.8k, False: 7.06M]
  |  Branch (191:23): [True: 616, False: 7.06M]
  ------------------
  192|       |				/* end of field */
  193|  61.4k|				csv->state = CSV_LEADING_SPACES;
  194|  61.4k|				csv->bufp -= csv->ending_spaces;
  195|  61.4k|				csv->ending_spaces = 0;
  196|  61.4k|				if (firstonly) {
  ------------------
  |  Branch (196:9): [True: 0, False: 61.4k]
  ------------------
  197|      0|					csv->state = CSV_NEWFIELD;
  198|      0|					return p;
  199|  61.4k|				} else {
  200|  61.4k|					csv->emit_field(csv->emit_ctx,
  201|  61.4k|							csv->buf, csv->bufp);
  202|  61.4k|				}
  203|       |
  204|  61.4k|				csv->bufp = csv->buf;
  205|       |
  206|  7.06M|			} else if (*p == csv->quote_char) {
  ------------------
  |  Branch (206:15): [True: 1.36k, False: 7.06M]
  ------------------
  207|  1.36k|				csv->state = CSV_QUOTE_OPENING;
  208|  7.06M|			} else {
  209|  7.06M|				*csv->bufp++ = *p;
  210|  7.06M|			}
  211|       |
  212|  7.12M|			if (*p == ' ') {
  ------------------
  |  Branch (212:8): [True: 3.08k, False: 7.12M]
  ------------------
  213|  3.08k|				csv->ending_spaces++;
  214|  7.12M|			} else {
  215|  7.12M|				csv->ending_spaces = 0;
  216|  7.12M|			}
  217|  7.12M|			if (is_line_end) {
  ------------------
  |  Branch (217:8): [True: 60.8k, False: 7.06M]
  ------------------
  218|       |				/*
  219|       |				 * bufp == buf means an empty field,
  220|       |				 * but bufp == 0 means no field at the moment,
  221|       |				 * it may be an end of the line or file
  222|       |				 */
  223|  60.8k|				csv->bufp = 0;
  224|  60.8k|				csv->emit_row(csv->emit_ctx);
  225|  60.8k|			}
  226|  7.12M|			break;
  227|  1.07M|		case CSV_IN_QUOTES:
  ------------------
  |  Branch (227:3): [True: 1.07M, False: 7.12M]
  ------------------
  228|       |			/*
  229|       |			 * Bufp can became NULL in two cases:
  230|       |			 * CSV_NEWFIELD and CSV_OUT_OF_QUOTES.
  231|       |			 *
  232|       |			 * In a case of 'newfield' the csv after
  233|       |			 * nullifying bufp and returning to the
  234|       |			 * iteration starts from
  235|       |			 * CSV_LEADING_SPACES. Here bufp is set
  236|       |			 * to not NULL (see 'leading_spaces').
  237|       |			 *
  238|       |			 * In a case of 'out_of_quotes' it can be
  239|       |			 * set to NULL only if
  240|       |			 * is_line_end == true. So at the
  241|       |			 * beginning of 'out_of_quotes'
  242|       |			 * is_line_end was true also
  243|       |			 * (see "if (is_line_end || ..." above).
  244|       |			 * In this 'if' the state of the csv is
  245|       |			 * set to CSV_LEADING_SPACES, so on a
  246|       |			 * next iteration the bufp are set to not
  247|       |			 * NULL.
  248|       |			 */
  249|  1.07M|			assert(csv->bufp != NULL);
  250|  1.07M|			if (*p == csv->quote_char) {
  ------------------
  |  Branch (250:8): [True: 1.29k, False: 1.07M]
  ------------------
  251|  1.29k|				csv->state = CSV_QUOTE_CLOSING;
  252|  1.07M|			} else {
  253|  1.07M|				*csv->bufp++ = *p;
  254|  1.07M|			}
  255|  1.07M|			break;
  256|      0|		case CSV_NEWFIELD:
  ------------------
  |  Branch (256:3): [True: 0, False: 8.20M]
  ------------------
  257|      0|			csv->bufp = csv->buf;
  258|      0|			csv->state = CSV_LEADING_SPACES;
  259|      0|			if (is_line_end) {
  ------------------
  |  Branch (259:8): [True: 0, False: 0]
  ------------------
  260|      0|				csv->bufp = 0;
  261|      0|				if (p + 1 == end)
  ------------------
  |  Branch (261:9): [True: 0, False: 0]
  ------------------
  262|      0|					return NULL;
  263|      0|				else
  264|      0|					return p + 1;
  265|       |
  266|      0|			}
  267|      0|			break;
  268|  8.20M|		}
  269|  8.20M|	}
  270|    309|	return end;
  271|    309|}
csv_parse_chunk:
  275|    309|csv_parse_chunk(struct csv *csv, const char *s, const char *end) {
  276|    309|	csv_parse_impl(csv, s, end, false);
  277|    309|}
csv_finish_parsing:
  281|    309|{
  282|    309|	if (csv_isvalid(csv)){
  ------------------
  |  Branch (282:6): [True: 253, False: 56]
  ------------------
  283|    253|		if (csv->bufp) {
  ------------------
  |  Branch (283:7): [True: 179, False: 74]
  ------------------
  284|    179|				csv->bufp -= csv->ending_spaces;
  285|    179|				csv->emit_field(csv->emit_ctx,
  286|    179|						csv->buf, csv->bufp);
  287|    179|				csv->emit_row(csv->emit_ctx);
  288|    179|		}
  289|    253|		if (csv->buf)
  ------------------
  |  Branch (289:7): [True: 253, False: 0]
  ------------------
  290|    253|			csv->realloc(csv->buf, 0);
  291|    253|		csv->bufp = NULL;
  292|    253|		csv->buf = NULL;
  293|    253|		csv->buf_len = 0;
  294|    253|	}
  295|    309|}
csv.c:csv_emit_field_empty:
   50|  61.6k|{
   51|  61.6k|	(void) ctx;
   52|  61.6k|	(void) field;
   53|  61.6k|	(void) end;
   54|  61.6k|}
csv.c:csv_emit_row_empty:
   44|  61.0k|{
   45|  61.0k|	(void) ctx;
   46|  61.0k|}

LLVMFuzzerTestOneInput:
    8|    309|{
    9|    309|	struct csv csv;
   10|    309|	csv_create(&csv);
   11|    309|	char *buf = calloc(size + 1, sizeof(char));
   12|    309|	if (buf == NULL)
  ------------------
  |  Branch (12:6): [True: 0, False: 309]
  ------------------
   13|      0|		return 0;
   14|    309|	memcpy(buf, data, size);
   15|    309|	buf[size] = '\0';
   16|    309|	char *end = buf + size;
   17|    309|	csv_parse_chunk(&csv, buf, end);
   18|    309|	csv_finish_parsing(&csv);
   19|    309|	csv_destroy(&csv);
   20|    309|	free(buf);
   21|       |
   22|    309|	return 0;
   23|    309|}

