1 /* 2 * Copyright (c) 2018-2021 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 if (qdf_str_eq(QDF_WIFI_MODULE_PARAMS_FILE, ini_path)) 36 status = qdf_module_param_file_read(ini_path, &fbuf); 37 else 38 status = qdf_file_read(ini_path, &fbuf); 39 if (QDF_IS_STATUS_ERROR(status)) { 40 qdf_err("Failed to read *.ini file @ %s", ini_path); 41 return status; 42 } 43 44 /* foreach line */ 45 cursor = fbuf; 46 while (*cursor != '\0') { 47 char *key = cursor; 48 char *value = NULL; 49 bool comment = false; 50 bool eol = false; 51 52 /* 53 * Look for the end of the line, while noting any 54 * value ('=') or comment ('#') indicators 55 */ 56 while (!eol) { 57 switch (*cursor) { 58 case '\r': 59 case '\n': 60 *cursor = '\0'; 61 cursor++; 62 /* fall through */ 63 case '\0': 64 eol = true; 65 break; 66 67 case '=': 68 /* 69 * The first '=' is the value indicator. 70 * Subsequent '=' are valid value characters. 71 */ 72 if (!value && !comment) { 73 value = cursor + 1; 74 *cursor = '\0'; 75 } 76 77 cursor++; 78 break; 79 80 case '#': 81 case '[': 82 /* 83 * We don't process comments, so we can null- 84 * terminate unconditionally here (unlike '='). 85 */ 86 comment = true; 87 *cursor = '\0'; 88 /* fall through */ 89 default: 90 cursor++; 91 break; 92 } 93 } 94 95 key = qdf_str_trim(key); 96 97 /* 98 * Ignoring comments, a valid ini line contains one of: 99 * 1) some 'key=value' config item 100 * 2) section header 101 * 3) a line containing whitespace 102 */ 103 if (value) { 104 status = item_cb(context, key, value); 105 if (QDF_IS_STATUS_ERROR(status)) 106 goto free_fbuf; 107 else 108 ini_read_count++; 109 } else if (key[0] == '[') { 110 qdf_size_t len = qdf_str_len(key); 111 112 if (key[len - 1] != ']') { 113 qdf_err("Invalid *.ini syntax '%s'", key); 114 } else { 115 key[len - 1] = '\0'; 116 if (section_cb) 117 status = section_cb(context, key + 1); 118 else 119 status = QDF_STATUS_E_NULL_VALUE; 120 121 if (QDF_IS_STATUS_ERROR(status)) 122 goto free_fbuf; 123 } 124 } else if (key[0] != '\0') { 125 qdf_err("Invalid *.ini syntax '%s'", key); 126 } 127 128 /* skip remaining EoL characters */ 129 while (*cursor == '\n' || *cursor == '\r') 130 cursor++; 131 } 132 133 qdf_info("INI values read: %d", ini_read_count); 134 if (ini_read_count != 0) { 135 qdf_info("INI file parse successful"); 136 status = QDF_STATUS_SUCCESS; 137 } else { 138 qdf_info("INI file parse fail: invalid file format"); 139 status = QDF_STATUS_E_INVAL; 140 } 141 142 free_fbuf: 143 if (qdf_str_eq(QDF_WIFI_MODULE_PARAMS_FILE, ini_path)) 144 qdf_module_param_file_free(fbuf); 145 else 146 qdf_file_buf_free(fbuf); 147 148 return status; 149 } 150 qdf_export_symbol(qdf_ini_parse); 151 152