| /* |
| * Copyright (c) 2014, The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * * Neither the name of The Linux Foundation nor |
| * the names of its contributors may be used to endorse or promote |
| * products derived from this software without specific prior written |
| * permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "ConfFileParser.h" |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <ctype.h> |
| #include <limits.h> |
| #include <math.h> |
| #include <utils/Log.h> |
| |
| //declaration of functions only specific to this file |
| static char parse_line |
| ( |
| group_table *key_file, |
| const char *line, |
| char **cur_grp |
| ); |
| |
| static char parse_load_frm_fhandler |
| ( |
| group_table *key_file, |
| FILE *fp |
| ); |
| |
| static char line_is_grp |
| ( |
| group_table *key_file, |
| const char *str, |
| char **cur_grp |
| ); |
| |
| static void free_grp_list |
| ( |
| group *a |
| ); |
| |
| static void free_key_list |
| ( |
| key_value_pair_list *a |
| ); |
| |
| static char line_is_key_value_pair |
| ( |
| group_table *key_file, |
| const char *str, |
| const char *cur_grp |
| ); |
| |
| static char line_is_comment |
| ( |
| const char *str |
| ); |
| |
| static char grp_exist |
| ( |
| const group_table *key_file, |
| const char *new_grp |
| ); |
| |
| static char add_grp |
| ( |
| group_table *key_file, |
| const char *new_grp |
| ); |
| |
| static group *alloc_group |
| ( |
| void |
| ); |
| |
| static key_value_pair_list *alloc_key_value_pair |
| ( |
| void |
| ); |
| |
| static char add_key_value_pair |
| ( |
| group_table *key_file, |
| const char *cur_grp, |
| const char *key, |
| const char *val |
| ); |
| |
| |
| //Definitions |
| void free_strs |
| ( |
| char **str_array |
| ) |
| { |
| char **str_array_cpy = str_array; |
| if(str_array != NULL) { |
| while(*str_array != NULL) { |
| free(*str_array); |
| str_array++; |
| } |
| } |
| free(str_array_cpy); |
| } |
| //ToDo: Come up with code hashing |
| //function |
| unsigned int get_hash_code |
| ( |
| const char *str |
| ) |
| { |
| |
| unsigned len = strlen(str); |
| unsigned int i; |
| unsigned int hash_code = 0; |
| |
| for(i = 0; len > 0; len--, i++) { |
| hash_code += (int)((str[i] * pow(2, len))) % INT_MAX; |
| hash_code %= INT_MAX; |
| } |
| return hash_code; |
| } |
| |
| static key_value_pair_list *alloc_key_value_pair |
| ( |
| void |
| ) |
| { |
| key_value_pair_list *key_list = NULL; |
| |
| key_list = (key_value_pair_list *)malloc( |
| sizeof(key_value_pair_list)); |
| if(key_list != NULL) { |
| key_list->key = NULL; |
| key_list->next = NULL; |
| key_list->value = NULL; |
| } |
| return key_list; |
| } |
| |
| static group * alloc_group |
| ( |
| void |
| ) |
| { |
| group *grp = NULL; |
| unsigned int i; |
| |
| grp = (group *)malloc(sizeof(group)); |
| if(grp != NULL) { |
| grp->grp_name = NULL; |
| grp->grp_next = NULL; |
| grp->num_of_keys = 0; |
| grp->keys_hash_size = MAX_UNIQ_KEYS; |
| grp->list = (key_value_pair_list **)malloc |
| (sizeof(key_value_pair_list *) * grp->keys_hash_size); |
| if(grp->list == NULL) { |
| ALOGE("Could not alloc group\n"); |
| free(grp); |
| grp = NULL; |
| }else { |
| for(i = 0; i < grp->keys_hash_size; i++) { |
| grp->list[i] = NULL; |
| } |
| } |
| } |
| return grp; |
| } |
| |
| group_table *get_key_file |
| ( |
| ) |
| { |
| group_table *t = NULL; |
| unsigned int i; |
| |
| t = (group_table *)malloc(sizeof(group_table)); |
| if (t != NULL) { |
| t->grps_hash_size = MAX_UNIQ_GRPS; |
| t->num_of_grps = 0; |
| t->grps_hash = (group **)malloc(sizeof(group *) |
| * t->grps_hash_size); |
| if (t->grps_hash == NULL) { |
| free(t); |
| return NULL; |
| } |
| for(i = 0; i < t->grps_hash_size; i++) { |
| t->grps_hash[i] = NULL; |
| } |
| } |
| return t; |
| } |
| |
| void free_key_file( |
| group_table *key_file |
| ) |
| { |
| unsigned int i; |
| |
| if(key_file != NULL) { |
| if(key_file->grps_hash != NULL) { |
| for(i = 0; i < key_file->grps_hash_size; i++) { |
| free_grp_list(key_file->grps_hash[i]); |
| } |
| } |
| free(key_file->grps_hash); |
| free(key_file); |
| } |
| } |
| |
| static void free_grp_list |
| ( |
| group *a |
| ) |
| { |
| group *next; |
| unsigned int i; |
| |
| while(a != NULL) { |
| next = a->grp_next; |
| if(a->list != NULL) { |
| for(i = 0; i < a->keys_hash_size; i++) { |
| free_key_list(a->list[i]); |
| } |
| } |
| free(a->grp_name); |
| free(a->list); |
| free(a); |
| a = next; |
| } |
| } |
| |
| static void free_key_list |
| ( |
| key_value_pair_list *a |
| ) |
| { |
| key_value_pair_list *next; |
| |
| while(a != NULL) { |
| next = a->next; |
| free(a->key); |
| free(a->value); |
| free(a); |
| a = next; |
| } |
| } |
| //return all the groups |
| //present in the file |
| char **get_grps |
| ( |
| const group_table *key_file |
| ) |
| { |
| char **grps = NULL; |
| unsigned int i = 0; |
| unsigned int j = 0; |
| unsigned int grp_len; |
| group *grp_list; |
| |
| if((key_file == NULL) |
| || (key_file->grps_hash == NULL) |
| || (key_file->grps_hash_size == 0) |
| || (key_file->num_of_grps == 0)) { |
| return grps; |
| } |
| grps = (char **)calloc((key_file->num_of_grps + 1), |
| sizeof(char *)); |
| if(grps == NULL) { |
| return grps; |
| } |
| for(i = 0; i < key_file->grps_hash_size; i++) { |
| grp_list = key_file->grps_hash[i]; |
| while(grp_list != NULL) { |
| grp_len = strlen(grp_list->grp_name); |
| grps[j] = (char *)malloc(sizeof(char) * |
| (grp_len + 1)); |
| if(grps[j] == NULL) { |
| free_strs(grps); |
| grps = NULL; |
| return grps; |
| } |
| memcpy(grps[j], grp_list->grp_name, |
| (grp_len + 1)); |
| grp_list = grp_list->grp_next; |
| j++; |
| } |
| } |
| grps[j] = NULL; |
| return grps; |
| } |
| |
| //returns the list of keys |
| //associated with group name |
| char **get_keys |
| ( |
| const group_table *key_file, |
| const char *grp_name |
| ) |
| { |
| unsigned int grp_hash_code; |
| unsigned int grp_index; |
| unsigned int i; |
| unsigned int j = 0; |
| unsigned int key_len; |
| group *grp; |
| key_value_pair_list *key_val_list; |
| char **keys = NULL; |
| |
| if((key_file == NULL) || (grp_name == NULL) |
| || (key_file->num_of_grps == 0) || |
| (key_file->grps_hash_size == 0) || |
| (key_file->grps_hash == NULL) || |
| (!strcmp(grp_name, ""))) { |
| return keys; |
| } |
| grp_hash_code = get_hash_code(grp_name); |
| grp_index = (grp_hash_code % key_file->grps_hash_size); |
| grp = key_file->grps_hash[grp_index]; |
| while(grp != NULL) { |
| if(!strcmp(grp_name, grp->grp_name)) { |
| if((grp->num_of_keys == 0) |
| || (grp->keys_hash_size == 0) |
| || (grp->list == 0)) { |
| return keys; |
| } |
| keys = (char **)calloc((grp->num_of_keys + 1), |
| sizeof(char *)); |
| if(keys == NULL) { |
| return keys; |
| } |
| for(i = 0; i < grp->keys_hash_size; i++) { |
| key_val_list = grp->list[i]; |
| while(key_val_list != NULL) { |
| key_len = strlen(key_val_list->key); |
| keys[j] = (char *)malloc(sizeof(char) * |
| (key_len + 1)); |
| if(keys[j] == NULL) { |
| free_strs(keys); |
| keys = NULL; |
| return keys; |
| } |
| memcpy(keys[j], key_val_list->key, |
| (key_len + 1)); |
| j++; |
| key_val_list = key_val_list->next; |
| } |
| } |
| keys[j] = NULL; |
| return keys; |
| } |
| grp = grp->grp_next; |
| } |
| return keys; |
| } |
| |
| char *get_value |
| ( |
| const group_table *key_file, |
| const char *grp_name, |
| const char *key |
| ) |
| { |
| unsigned int grp_hash_code; |
| unsigned int key_hash_code; |
| unsigned int grp_index; |
| unsigned int key_index; |
| unsigned val_len; |
| char *val = NULL; |
| group *grp; |
| key_value_pair_list *list; |
| |
| if((key_file == NULL) || (grp_name == NULL) |
| || (key == NULL) || (key_file->grps_hash == NULL) |
| || (key_file->grps_hash_size == 0) || !strcmp(grp_name, "") |
| ||(!strcmp(key, ""))) { |
| return NULL; |
| } |
| grp_hash_code = get_hash_code(grp_name); |
| key_hash_code = get_hash_code(key); |
| grp_index = (grp_hash_code % key_file->grps_hash_size); |
| grp = key_file->grps_hash[grp_index]; |
| while(grp != NULL) { |
| if(!strcmp(grp_name, grp->grp_name) && grp->keys_hash_size |
| && grp->list) { |
| key_index = (key_hash_code % grp->keys_hash_size); |
| list = grp->list[key_index]; |
| while((list != NULL) && (strcmp(list->key, key))) { |
| list = list->next; |
| } |
| if(list != NULL) { |
| val_len = strlen(list->value); |
| val = (char *)malloc(sizeof(char) * (val_len + 1)); |
| if(val != NULL) { |
| memcpy(val, list->value, val_len); |
| val[val_len] = '\0'; |
| } |
| } |
| return val; |
| } |
| grp = grp->grp_next; |
| } |
| return val; |
| } |
| //open the file, |
| //read, parse and load |
| //returns PARSE_SUCCESS if successfully |
| //loaded else PARSE_FAILED |
| char parse_load_file |
| ( |
| group_table *key_file, |
| const char *file |
| ) |
| { |
| FILE *fp; |
| char ret = FALSE; |
| |
| if((file == NULL) || !strcmp(file, "")) { |
| ALOGE("File name is null or empty \n"); |
| return ret; |
| } |
| |
| fp = fopen(file, "r"); |
| if(fp == NULL) { |
| ALOGE("could not open file for read\n"); |
| return ret; |
| } |
| |
| ret = parse_load_frm_fhandler(key_file, fp); |
| fclose(fp); |
| |
| return ret; |
| } |
| |
| //Read block of data from file handler |
| //extract each line, check kind of line(comment, |
| //group, key value pair) |
| static char parse_load_frm_fhandler |
| ( |
| group_table *key_file, |
| FILE *fp |
| ) |
| { |
| char buf[MAX_LINE_LEN]; |
| char ret = TRUE; |
| char *line = NULL; |
| void *new_line; |
| char *cur_grp = NULL; |
| unsigned line_len = 0; |
| unsigned line_allocated = 0; |
| unsigned int bytes_read = 0; |
| unsigned int i; |
| bool has_carriage_rtn = false; |
| |
| while((bytes_read = fread(buf, 1, MAX_LINE_LEN, fp))) { |
| for(i = 0; i < bytes_read; i++) { |
| if(line_len == line_allocated) { |
| line_allocated += 25; |
| new_line = realloc(line, line_allocated); |
| if(new_line == NULL) { |
| ret = FALSE; |
| ALOGE("memory allocation failed for line\n"); |
| break; |
| } |
| line = (char *)new_line; |
| } |
| if((buf[i] == '\n')) { |
| has_carriage_rtn = false; |
| line[line_len] = '\0'; |
| ret = parse_line(key_file, line, &cur_grp); |
| line_len = 0; |
| if(ret == FALSE) { |
| ALOGE("could not parse the line, line not proper\n"); |
| break; |
| } |
| }else if(buf[i] == '\r') { |
| ALOGE("File has carriage return\n"); |
| has_carriage_rtn = true; |
| }else if(has_carriage_rtn) { |
| ALOGE("File format is not proper, no line character\ |
| after carraige return\n"); |
| ret = FALSE; |
| break; |
| }else { |
| line[line_len] = buf[i]; |
| line_len++; |
| } |
| } |
| if (!ret) { |
| break; |
| } |
| } |
| free(line); |
| free(cur_grp); |
| |
| return ret; |
| } |
| |
| //checks whether a line is |
| //comment or grp or key pair value |
| //and accordingly adds to list |
| static char parse_line |
| ( |
| group_table *key_file, |
| const char *line, |
| char **cur_grp |
| ) |
| { |
| const char *line_begin; |
| |
| if((line == NULL) || (key_file == NULL)) { |
| ALOGE("key file or line is null\n"); |
| return FALSE; |
| } |
| |
| for(line_begin = line; isspace(*line_begin); |
| line_begin++); |
| |
| if(line_is_comment(line_begin)) { |
| ALOGE("line is comment\n"); |
| return TRUE; |
| }else if(line_is_grp(key_file, line_begin, cur_grp)) { |
| ALOGE("line is grp\n"); |
| return TRUE; |
| }else if(line_is_key_value_pair(key_file, line_begin, *cur_grp)) { |
| ALOGE("line is key value pair\n"); |
| return TRUE; |
| }else { |
| ALOGE("line is neither comment, grp nor key value pair\n"); |
| return FALSE; |
| } |
| } |
| |
| static char line_is_comment |
| ( |
| const char *str |
| ) |
| { |
| if(str == NULL) { |
| return FALSE; |
| }else if(((*str) == '#') || ((*str) == '\0') |
| || ((*str) == '\n')) { |
| return TRUE; |
| }else { |
| ALOGE("line is not comment\n"); |
| return FALSE; |
| } |
| } |
| |
| //return true if a group |
| //name already exist |
| //else false |
| static char grp_exist |
| ( |
| const group_table *key_file, |
| const char *new_grp |
| ) |
| { |
| unsigned hash_code; |
| unsigned int index; |
| group *grp; |
| |
| if((key_file == NULL) || (new_grp == NULL) |
| || (!key_file->grps_hash_size)) { |
| return FALSE; |
| }else { |
| hash_code = get_hash_code(new_grp); |
| index = hash_code % key_file->grps_hash_size; |
| grp = key_file->grps_hash[index]; |
| while(grp != NULL) { |
| if (!strcmp(grp->grp_name, new_grp)) |
| return TRUE; |
| grp = grp->grp_next; |
| } |
| return FALSE; |
| } |
| } |
| |
| //Add a group to group |
| //table if it does not exist |
| static char add_grp |
| ( |
| group_table *key_file, |
| const char *new_grp |
| ) |
| { |
| unsigned int hash_code; |
| unsigned int index; |
| unsigned int grp_name_len; |
| group *grp; |
| |
| if(!grp_exist(key_file, new_grp)) { |
| if((key_file == NULL) || (new_grp == NULL) |
| || !key_file->grps_hash_size) { |
| return FALSE; |
| } |
| hash_code = get_hash_code(new_grp); |
| ALOGE("group hash code is: %u\n", hash_code); |
| index = hash_code % key_file->grps_hash_size; |
| ALOGE("group index is: %u\n", index); |
| grp = alloc_group(); |
| if(grp == NULL) { |
| return FALSE; |
| } |
| grp_name_len = strlen(new_grp); |
| grp->grp_name = (char *)malloc( |
| sizeof(char) * (grp_name_len + 1)); |
| if(grp->grp_name == NULL) { |
| ALOGE("could not alloc memory for group name\n"); |
| ALOGE("Add group failed\n"); |
| free_grp_list(grp); |
| return FALSE; |
| }else { |
| memcpy(grp->grp_name, new_grp, (grp_name_len + 1)); |
| } |
| grp->grp_next = key_file->grps_hash[index]; |
| key_file->grps_hash[index] = grp; |
| key_file->num_of_grps++; |
| return TRUE; |
| }else { |
| return FALSE; |
| } |
| } |
| |
| //checks validity of a group |
| //a valid group is |
| //inside [] group name must be |
| //alphanumeric |
| //Example: [grpName] |
| static char line_is_grp |
| ( |
| group_table *key_file, |
| const char *str, |
| char **cur_grp |
| ) |
| { |
| const char *g_start; |
| const char *g_end; |
| char *new_grp; |
| unsigned int grp_len; |
| |
| if ((str == NULL) || (key_file == NULL)) { |
| ALOGE("str is null or key file is null\n"); |
| return FALSE; |
| } |
| //checks start mark char ']' |
| if(((*str) != '[')) { |
| ALOGE("start mark is not '['\n"); |
| return FALSE; |
| }else { |
| str++; |
| g_start = str; |
| } |
| //checks the end char '[' |
| while((*str != '\0') && ((*str) != ']')) { |
| str++; |
| } |
| //if end mark group not found |
| if ((*str) != ']') { |
| ALOGE("grp end mark is not '['\n"); |
| return FALSE; |
| }else { |
| g_end = (str - 1); |
| } |
| |
| str++; |
| //if end mark found checks the rest chars as well |
| //rest chars should be space |
| while(((*str) == ' ') || ((*str) == '\t')) { |
| str++; |
| } |
| if(*str) { |
| ALOGE("after ']' there are some character\n"); |
| return FALSE; |
| } |
| |
| str = g_start; |
| while((*g_start != '\0') && (g_start != g_end) |
| && isalnum(*g_start)) { |
| g_start++; |
| } |
| if((g_start == g_end) && isalnum(*g_start)) { |
| //look up if already exist |
| //return false else insert the grp in grp table |
| grp_len = (g_end - str + 1); |
| new_grp = (char *)malloc(sizeof(char) * (grp_len + 1)); |
| if (new_grp == NULL) { |
| ALOGE("could not alloc memory for new group\n"); |
| return FALSE; |
| } |
| memcpy(new_grp, str, grp_len); |
| new_grp[grp_len] = '\0'; |
| |
| if(add_grp(key_file, new_grp)) { |
| free(*cur_grp); |
| *cur_grp = new_grp; |
| return TRUE; |
| }else { |
| ALOGE("could not add group to group table\n"); |
| return FALSE; |
| } |
| }else { |
| return FALSE; |
| } |
| } |
| |
| //checks validity of key |
| //a valid key must start in |
| //a seperate line and key must |
| //be alphanumeric and before '=' |
| //there must not be any space |
| //Example: key=value |
| static char line_is_key_value_pair |
| ( |
| group_table *key_file, |
| const char *str, |
| const char *cur_grp |
| ) |
| { |
| const char *equal_start; |
| char *key = NULL; |
| char *val = NULL; |
| unsigned key_len; |
| unsigned val_len; |
| |
| if((str == NULL) || (cur_grp == NULL) || |
| !strcmp(cur_grp, "") || (key_file == NULL)) { |
| ALOGE("line is null or cur group or key file is null or empty\n"); |
| return FALSE; |
| } |
| equal_start = strchr(str, '='); |
| key_len = (equal_start - str); |
| if((equal_start == NULL) || (equal_start == str)) { |
| ALOGE("line does not have '=' character or no key\n"); |
| return FALSE; |
| } |
| while((str != equal_start) && isalnum(*str)) |
| str++; |
| if((str == equal_start)) { |
| key = (char *)malloc(sizeof(char) * (key_len + 1)); |
| if(key == NULL) { |
| ALOGE("could not alloc memory for new key\n"); |
| return FALSE; |
| } |
| equal_start++; |
| val_len = strlen(equal_start); |
| val = (char *)malloc(sizeof(char) * (val_len + 1)); |
| if(val == NULL) { |
| ALOGE("could not alloc memory for value\n"); |
| if(key){ |
| free(key); |
| key = NULL; |
| } |
| return FALSE; |
| } |
| memcpy(key, (str - key_len), key_len); |
| memcpy(val, equal_start, val_len); |
| key[key_len] = '\0'; |
| val[val_len] = '\0'; |
| ALOGE("Grp: %s, key: %s, value: %s\n", cur_grp, key, val); |
| return add_key_value_pair(key_file, |
| cur_grp, key, val); |
| }else { |
| ALOGE("key name doesnot have alpha numeric char\n"); |
| return FALSE; |
| } |
| } |
| |
| static char add_key_value_pair |
| ( |
| group_table *key_file, |
| const char *cur_grp, |
| const char *key, |
| const char *val |
| ) |
| { |
| unsigned int grp_hash_code; |
| unsigned int key_hash_code; |
| unsigned int grp_index; |
| unsigned int key_index; |
| unsigned key_len = 0; |
| unsigned val_len = 0; |
| group *grp = NULL; |
| key_value_pair_list *list = NULL; |
| |
| if((key_file != NULL) && (cur_grp != NULL) |
| && (key != NULL) && ((key_file->grps_hash != NULL)) |
| && (strcmp(key, ""))) { |
| grp_hash_code = get_hash_code(cur_grp); |
| ALOGE("grp hash code is %u\n", grp_hash_code); |
| grp_index = (grp_hash_code % key_file->grps_hash_size); |
| ALOGE("grp index is %u\n", grp_index); |
| grp = key_file->grps_hash[grp_index]; |
| key_hash_code = get_hash_code(key); |
| while((grp != NULL)) { |
| if(!strcmp(cur_grp, grp->grp_name)) { |
| key_index = (key_hash_code % grp->keys_hash_size); |
| if(grp->list) { |
| list = grp->list[key_index]; |
| }else { |
| ALOGE("group list is null\n"); |
| goto err; |
| } |
| while((list != NULL) && strcmp(key, list->key)) { |
| list = list->next; |
| } |
| if(list != NULL) { |
| ALOGE("group already contains the key\n"); |
| goto err; |
| }else{ |
| list = alloc_key_value_pair(); |
| if(list == NULL) { |
| ALOGE("add key value failed as could not alloc memory for key\ |
| val pair\n"); |
| goto err; |
| } |
| if(key) { |
| key_len = strlen(key); |
| } |
| list->key = (char *)malloc(sizeof(char) * |
| (key_len + 1)); |
| if(list->key == NULL) { |
| ALOGE("could not alloc memory for key\n"); |
| free(list); |
| goto err; |
| } |
| if(val) { |
| val_len = strlen(val); |
| } |
| list->value = (char *)malloc(sizeof(char) * |
| (val_len + 1)); |
| if(!list->value) { |
| free(list->key); |
| free(list); |
| goto err; |
| } |
| memcpy(list->key, key, key_len); |
| memcpy(list->value, val, val_len); |
| if (key) free((char*)key); |
| if (val) free((char*)val); |
| list->key[key_len] = '\0'; |
| list->value[val_len] = '\0'; |
| list->next = grp->list[key_index]; |
| grp->list[key_index] = list; |
| grp->num_of_keys++; |
| return TRUE; |
| } |
| } |
| grp = grp->grp_next; |
| } |
| ALOGE("group does not exist\n"); |
| goto err; |
| } |
| err: |
| if (key) free((char*)key); |
| if (val) free((char*)val); |
| return FALSE; |
| } |