1 /* 2 * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "qdf_file.h" 20 #include "qdf_module.h" 21 #include "qdf_parse.h" 22 #include "qdf_status.h" 23 #include "qdf_str.h" 24 #include "qdf_trace.h" 25 #include "qdf_types.h" 26 27 QDF_STATUS qdf_ini_parse(const char *ini_path, void *context, 28 qdf_ini_item_cb item_cb, qdf_ini_section_cb section_cb) 29 { 30 QDF_STATUS status; 31 char *fbuf; 32 char *cursor; 33 int ini_read_count = 0; 34 35 status = qdf_file_read(ini_path, &fbuf); 36 if (QDF_IS_STATUS_ERROR(status)) { 37 qdf_err("Failed to read *.ini file @ %s", ini_path); 38 return status; 39 } 40 41 /* foreach line */ 42 cursor = fbuf; 43 while (*cursor != '\0') { 44 char *key = cursor; 45 char *value = NULL; 46 bool comment = false; 47 bool eol = false; 48 49 /* 50 * Look for the end of the line, while noting any 51 * value ('=') or comment ('#') indicators 52 */ 53 while (!eol) { 54 switch (*cursor) { 55 case '\r': 56 case '\n': 57 *cursor = '\0'; 58 cursor++; 59 /* fall through */ 60 case '\0': 61 eol = true; 62 break; 63 64 case '=': 65 /* 66 * The first '=' is the value indicator. 67 * Subsequent '=' are valid value characters. 68 */ 69 if (!value && !comment) { 70 value = cursor + 1; 71 *cursor = '\0'; 72 } 73 74 cursor++; 75 break; 76 77 case '#': 78 /* 79 * We don't process comments, so we can null- 80 * terminate unconditionally here (unlike '='). 81 */ 82 comment = true; 83 *cursor = '\0'; 84 /* fall through */ 85 default: 86 cursor++; 87 break; 88 } 89 } 90 91 key = qdf_str_trim(key); 92 93 /* 94 * Ignoring comments, a valid ini line contains one of: 95 * 1) some 'key=value' config item 96 * 2) section header 97 * 3) a line containing whitespace 98 */ 99 if (value) { 100 status = item_cb(context, key, value); 101 if (QDF_IS_STATUS_ERROR(status)) 102 goto free_fbuf; 103 else 104 ini_read_count++; 105 } else if (key[0] == '[') { 106 qdf_size_t len = qdf_str_len(key); 107 108 if (key[len - 1] != ']') { 109 qdf_err("Invalid *.ini syntax '%s'", key); 110 } else { 111 key[len - 1] = '\0'; 112 status = section_cb(context, key + 1); 113 if (QDF_IS_STATUS_ERROR(status)) 114 goto free_fbuf; 115 } 116 } else if (key[0] != '\0') { 117 qdf_err("Invalid *.ini syntax '%s'", key); 118 } 119 120 /* skip remaining EoL characters */ 121 while (*cursor == '\n' || *cursor == '\r') 122 cursor++; 123 } 124 125 qdf_debug("INI values read: %d", ini_read_count); 126 if (ini_read_count != 0) 127 status = QDF_STATUS_SUCCESS; 128 else 129 status = QDF_STATUS_E_FAILURE; 130 131 free_fbuf: 132 qdf_file_buf_free(fbuf); 133 134 return status; 135 } 136 qdf_export_symbol(qdf_ini_parse); 137 138