See documentation in header file. */
| 71 | |
| 72 | /* See documentation in header file. */ |
| 73 | int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, |
| 74 | void* user) |
| 75 | { |
| 76 | /* Uses a fair bit of stack (use heap instead if you need to) */ |
| 77 | #if INI_USE_STACK |
| 78 | char line[INI_MAX_LINE]; |
| 79 | #else |
| 80 | char* line; |
| 81 | #endif |
| 82 | char section[MAX_SECTION] = ""; |
| 83 | char prev_name[MAX_NAME] = ""; |
| 84 | |
| 85 | char* start; |
| 86 | char* end; |
| 87 | char* name; |
| 88 | char* value; |
| 89 | int lineno = 0; |
| 90 | int error = 0; |
| 91 | |
| 92 | #if !INI_USE_STACK |
| 93 | line = (char*)malloc(INI_MAX_LINE); |
| 94 | if (!line) { |
| 95 | return -2; |
| 96 | } |
| 97 | #endif |
| 98 | |
| 99 | /* Scan through stream line by line */ |
| 100 | while (reader(line, INI_MAX_LINE, stream) != NULL) { |
| 101 | lineno++; |
| 102 | |
| 103 | start = line; |
| 104 | #if INI_ALLOW_BOM |
| 105 | if (lineno == 1 && (unsigned char)start[0] == 0xEF && |
| 106 | (unsigned char)start[1] == 0xBB && |
| 107 | (unsigned char)start[2] == 0xBF) { |
| 108 | start += 3; |
| 109 | } |
| 110 | #endif |
| 111 | start = lskip(rstrip(start)); |
| 112 | |
| 113 | if (*start == ';' || *start == '#') { |
| 114 | /* Per Python configparser, allow both ; and # comments at the |
| 115 | start of a line */ |
| 116 | } |
| 117 | #if INI_ALLOW_MULTILINE |
| 118 | else if (*prev_name && *start && start > line) { |
| 119 | /* Non-blank line with leading whitespace, treat as continuation |
| 120 | of previous name's value (as per Python configparser). */ |
| 121 | if (!handler(user, section, prev_name, start) && !error) |
| 122 | error = lineno; |
| 123 | } |
| 124 | #endif |
| 125 | else if (*start == '[') { |
| 126 | /* A "[section]" line */ |
| 127 | end = find_chars_or_comment(start + 1, "]"); |
| 128 | if (*end == ']') { |
| 129 | *end = '\0'; |
| 130 | strncpy0(section, start + 1, sizeof(section)); |
no test coverage detected