1/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 *     * Redistributions of source code must retain the above copyright
7 *       notice, this list of conditions and the following disclaimer.
8 *     * Redistributions in binary form must reproduce the above
9 *       copyright notice, this list of conditions and the following
10 *       disclaimer in the documentation and/or other materials provided
11 *       with the distribution.
12 *     * Neither the name of The Linux Foundation, nor the names of its
13 *       contributors may be used to endorse or promote products derived
14 *       from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#define LOG_NDDEBUG 0
31#define LOG_TAG "LocSvc_utils_cfg"
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <pthread.h>
36#include <string.h>
37#include <ctype.h>
38#include <unistd.h>
39#include <time.h>
40#include <loc_cfg.h>
41#include <log_util.h>
42#include <loc_misc_utils.h>
43#ifdef USE_GLIB
44#include <glib.h>
45#endif
46#include "platform_lib_includes.h"
47
48/*=============================================================================
49 *
50 *                          GLOBAL DATA DECLARATION
51 *
52 *============================================================================*/
53
54/* Parameter data */
55static uint32_t DEBUG_LEVEL = 0xff;
56static uint32_t TIMESTAMP = 0;
57
58/* Parameter spec table */
59static const loc_param_s_type loc_param_table[] =
60{
61    {"DEBUG_LEVEL",    &DEBUG_LEVEL, NULL,    'n'},
62    {"TIMESTAMP",      &TIMESTAMP,   NULL,    'n'},
63};
64static const int loc_param_num = sizeof(loc_param_table) / sizeof(loc_param_s_type);
65
66typedef struct loc_param_v_type
67{
68    char* param_name;
69    char* param_str_value;
70    int param_int_value;
71    double param_double_value;
72}loc_param_v_type;
73
74/*===========================================================================
75FUNCTION loc_set_config_entry
76
77DESCRIPTION
78   Potentially sets a given configuration table entry based on the passed in
79   configuration value. This is done by using a string comparison of the
80   parameter names and those found in the configuration file.
81
82PARAMETERS:
83   config_entry: configuration entry in the table to possibly set
84   config_value: value to store in the entry if the parameter names match
85
86DEPENDENCIES
87   N/A
88
89RETURN VALUE
90   None
91
92SIDE EFFECTS
93   N/A
94===========================================================================*/
95int loc_set_config_entry(const loc_param_s_type* config_entry, loc_param_v_type* config_value)
96{
97    int ret=-1;
98    if(NULL == config_entry || NULL == config_value)
99    {
100        LOC_LOGE("%s: INVALID config entry or parameter", __FUNCTION__);
101        return ret;
102    }
103
104    if (strcmp(config_entry->param_name, config_value->param_name) == 0 &&
105        config_entry->param_ptr)
106    {
107        switch (config_entry->param_type)
108        {
109        case 's':
110            if (strcmp(config_value->param_str_value, "NULL") == 0)
111            {
112                *((char*)config_entry->param_ptr) = '\0';
113            }
114            else {
115                strlcpy((char*) config_entry->param_ptr,
116                        config_value->param_str_value,
117                        LOC_MAX_PARAM_STRING + 1);
118            }
119            /* Log INI values */
120            LOC_LOGD("%s: PARAM %s = %s", __FUNCTION__,
121                     config_entry->param_name, (char*)config_entry->param_ptr);
122
123            if(NULL != config_entry->param_set)
124            {
125                *(config_entry->param_set) = 1;
126            }
127            ret = 0;
128            break;
129        case 'n':
130            *((int *)config_entry->param_ptr) = config_value->param_int_value;
131            /* Log INI values */
132            LOC_LOGD("%s: PARAM %s = %d", __FUNCTION__,
133                     config_entry->param_name, config_value->param_int_value);
134
135            if(NULL != config_entry->param_set)
136            {
137                *(config_entry->param_set) = 1;
138            }
139            ret = 0;
140            break;
141        case 'f':
142            *((double *)config_entry->param_ptr) = config_value->param_double_value;
143            /* Log INI values */
144            LOC_LOGD("%s: PARAM %s = %f", __FUNCTION__,
145                     config_entry->param_name, config_value->param_double_value);
146
147            if(NULL != config_entry->param_set)
148            {
149                *(config_entry->param_set) = 1;
150            }
151            ret = 0;
152            break;
153        default:
154            LOC_LOGE("%s: PARAM %s parameter type must be n, f, or s",
155                     __FUNCTION__, config_entry->param_name);
156        }
157    }
158    return ret;
159}
160
161/*===========================================================================
162FUNCTION loc_fill_conf_item
163
164DESCRIPTION
165   Takes a line of configuration item and sets defined values based on
166   the passed in configuration table. This table maps strings to values to
167   set along with the type of each of these values.
168
169PARAMETERS:
170   input_buf : buffer contanis config item
171   config_table: table definition of strings to places to store information
172   table_length: length of the configuration table
173
174DEPENDENCIES
175   N/A
176
177RETURN VALUE
178   0: Number of records in the config_table filled with input_buf
179
180SIDE EFFECTS
181   N/A
182===========================================================================*/
183int loc_fill_conf_item(char* input_buf,
184                       const loc_param_s_type* config_table, uint32_t table_length)
185{
186    int ret = 0;
187
188    if (input_buf && config_table) {
189        char *lasts;
190        loc_param_v_type config_value;
191        memset(&config_value, 0, sizeof(config_value));
192
193        /* Separate variable and value */
194        config_value.param_name = strtok_r(input_buf, "=", &lasts);
195        /* skip lines that do not contain "=" */
196        if (config_value.param_name) {
197            config_value.param_str_value = strtok_r(NULL, "=", &lasts);
198
199            /* skip lines that do not contain two operands */
200            if (config_value.param_str_value) {
201                /* Trim leading and trailing spaces */
202                loc_util_trim_space(config_value.param_name);
203                loc_util_trim_space(config_value.param_str_value);
204
205                /* Parse numerical value */
206                if ((strlen(config_value.param_str_value) >=3) &&
207                    (config_value.param_str_value[0] == '0') &&
208                    (tolower(config_value.param_str_value[1]) == 'x'))
209                {
210                    /* hex */
211                    config_value.param_int_value = (int) strtol(&config_value.param_str_value[2],
212                                                                (char**) NULL, 16);
213                }
214                else {
215                    config_value.param_double_value = (double) atof(config_value.param_str_value); /* float */
216                    config_value.param_int_value = atoi(config_value.param_str_value); /* dec */
217                }
218
219                for(uint32_t i = 0; NULL != config_table && i < table_length; i++)
220                {
221                    if(!loc_set_config_entry(&config_table[i], &config_value)) {
222                        ret += 1;
223                    }
224                }
225            }
226        }
227    }
228
229    return ret;
230}
231
232/*===========================================================================
233FUNCTION loc_read_conf_r (repetitive)
234
235DESCRIPTION
236   Reads the specified configuration file and sets defined values based on
237   the passed in configuration table. This table maps strings to values to
238   set along with the type of each of these values.
239   The difference between this and loc_read_conf is that this function returns
240   the file pointer position at the end of filling a config table. Also, it
241   reads a fixed number of parameters at a time which is equal to the length
242   of the configuration table. This functionality enables the caller to
243   repeatedly call the function to read data from the same file.
244
245PARAMETERS:
246   conf_fp : file pointer
247   config_table: table definition of strings to places to store information
248   table_length: length of the configuration table
249
250DEPENDENCIES
251   N/A
252
253RETURN VALUE
254   0: Table filled successfully
255   1: No more parameters to read
256  -1: Error filling table
257
258SIDE EFFECTS
259   N/A
260===========================================================================*/
261int loc_read_conf_r(FILE *conf_fp, const loc_param_s_type* config_table, uint32_t table_length)
262{
263    int ret=0;
264
265    unsigned int num_params=table_length;
266    if(conf_fp == NULL) {
267        LOC_LOGE("%s:%d]: ERROR: File pointer is NULL\n", __func__, __LINE__);
268        ret = -1;
269        goto err;
270    }
271
272    /* Clear all validity bits */
273    for(uint32_t i = 0; NULL != config_table && i < table_length; i++)
274    {
275        if(NULL != config_table[i].param_set)
276        {
277            *(config_table[i].param_set) = 0;
278        }
279    }
280
281    char input_buf[LOC_MAX_PARAM_LINE];  /* declare a char array */
282
283    LOC_LOGD("%s:%d]: num_params: %d\n", __func__, __LINE__, num_params);
284    while(num_params)
285    {
286        if(!fgets(input_buf, LOC_MAX_PARAM_LINE, conf_fp)) {
287            LOC_LOGD("%s:%d]: fgets returned NULL\n", __func__, __LINE__);
288            break;
289        }
290
291        num_params -= loc_fill_conf_item(input_buf, config_table, table_length);
292    }
293
294err:
295    return ret;
296}
297
298/*===========================================================================
299FUNCTION loc_udpate_conf
300
301DESCRIPTION
302   Parses the passed in buffer for configuration items, and update the table
303   that is also passed in.
304
305Reads the specified configuration file and sets defined values based on
306   the passed in configuration table. This table maps strings to values to
307   set along with the type of each of these values.
308
309PARAMETERS:
310   conf_data: configuration items in bufferas a string
311   length: strlen(conf_data)
312   config_table: table definition of strings to places to store information
313   table_length: length of the configuration table
314
315DEPENDENCIES
316   N/A
317
318RETURN VALUE
319   number of the records in the table that is updated at time of return.
320
321SIDE EFFECTS
322   N/A
323===========================================================================*/
324int loc_update_conf(const char* conf_data, int32_t length,
325                    const loc_param_s_type* config_table, uint32_t table_length)
326{
327    int ret = -1;
328
329    if (conf_data && length && config_table && table_length) {
330        // make a copy, so we do not tokenize the original data
331        char* conf_copy = (char*)malloc(length+1);
332
333        if (conf_copy != NULL)
334        {
335            memcpy(conf_copy, conf_data, length);
336            // we hard NULL the end of string to be safe
337            conf_copy[length] = 0;
338
339            // start with one record off
340            uint32_t num_params = table_length - 1;
341            char* saveptr = NULL;
342            char* input_buf = strtok_r(conf_copy, "\n", &saveptr);
343            ret = 0;
344
345            LOC_LOGD("%s:%d]: num_params: %d\n", __func__, __LINE__, num_params);
346            while(num_params && input_buf) {
347                ret++;
348                num_params -= loc_fill_conf_item(input_buf, config_table, table_length);
349                input_buf = strtok_r(NULL, "\n", &saveptr);
350            }
351            free(conf_copy);
352        }
353    }
354
355    return ret;
356}
357
358/*===========================================================================
359FUNCTION loc_read_conf
360
361DESCRIPTION
362   Reads the specified configuration file and sets defined values based on
363   the passed in configuration table. This table maps strings to values to
364   set along with the type of each of these values.
365
366PARAMETERS:
367   conf_file_name: configuration file to read
368   config_table: table definition of strings to places to store information
369   table_length: length of the configuration table
370
371DEPENDENCIES
372   N/A
373
374RETURN VALUE
375   None
376
377SIDE EFFECTS
378   N/A
379===========================================================================*/
380void loc_read_conf(const char* conf_file_name, const loc_param_s_type* config_table,
381                   uint32_t table_length)
382{
383    FILE *conf_fp = NULL;
384    char *lasts;
385    loc_param_v_type config_value;
386    uint32_t i;
387
388    if((conf_fp = fopen(conf_file_name, "r")) != NULL)
389    {
390        LOC_LOGD("%s: using %s", __FUNCTION__, conf_file_name);
391        if(table_length && config_table) {
392            loc_read_conf_r(conf_fp, config_table, table_length);
393            rewind(conf_fp);
394        }
395        loc_read_conf_r(conf_fp, loc_param_table, loc_param_num);
396        fclose(conf_fp);
397    }
398    /* Initialize logging mechanism with parsed data */
399    loc_logger_init(DEBUG_LEVEL, TIMESTAMP);
400}
401