| 74 | } |
| 75 | |
| 76 | csv_record *__parse_csv_record(const str *_in, enum csv_flags parse_flags, |
| 77 | unsigned char sep) |
| 78 | { |
| 79 | str_list *record = NULL, **last = &record; |
| 80 | str in = *_in, field; |
| 81 | char *ch, *p, *c, finished, *lim, *field_start; |
| 82 | |
| 83 | if (parse_flags & CSV_SHM) { |
| 84 | malloc_f = osips_shm_malloc; |
| 85 | free_f = osips_shm_free; |
| 86 | } else { |
| 87 | malloc_f = osips_pkg_malloc; |
| 88 | free_f = osips_pkg_free; |
| 89 | } |
| 90 | |
| 91 | if (parse_flags & CSV_RFC_4180) |
| 92 | goto rfc_4180_parsing; |
| 93 | |
| 94 | trim(&in); |
| 95 | |
| 96 | for (finished = 0; !finished; ) { |
| 97 | ch = memchr(in.s, sep, in.len); |
| 98 | if (!ch) { |
| 99 | ch = in.s + in.len; |
| 100 | finished = 1; |
| 101 | } |
| 102 | |
| 103 | field.s = in.s; |
| 104 | field.len = ch - in.s; |
| 105 | in.s += field.len + 1; |
| 106 | in.len -= field.len + 1; |
| 107 | trim(&field); |
| 108 | |
| 109 | if (!push_csv_field(&field, last, parse_flags)) |
| 110 | goto oom; |
| 111 | |
| 112 | last = &(*last)->next; |
| 113 | } |
| 114 | |
| 115 | return record; |
| 116 | |
| 117 | rfc_4180_parsing: |
| 118 | parse_flags |= CSV_DUP_FIELDS; |
| 119 | |
| 120 | if (in.len >= 2 && in.s[in.len - 2] == '\r' && in.s[in.len - 1] == '\n') |
| 121 | in.len -= 2; |
| 122 | |
| 123 | field_start = NULL; |
| 124 | for (ch = in.s, lim = in.s + in.len; ch < lim; ch++) { |
| 125 | if (*ch < 0x20 || *ch > 0x7E) |
| 126 | goto bad_csv_str; |
| 127 | |
| 128 | switch (*ch) { |
| 129 | case ',': |
| 130 | if (field_start) |
| 131 | field.s = field_start; |
| 132 | else |
| 133 | field.s = in.s; |
no test coverage detected