1148 lines
28 KiB
C
1148 lines
28 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <malloc.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/string.h>
|
|
#include "ini_parser.h"
|
|
|
|
#define LOG_TAG "ini_parser"
|
|
#define LOG_NDEBUG 0
|
|
|
|
static int ini_mem_alloc_size;
|
|
|
|
static void ini_memnd_alloc_recode(const char *fun_name, const char *var_name, int size, int type)
|
|
{
|
|
if (size == 0)
|
|
return;
|
|
ini_mem_alloc_size += size;
|
|
#if INI_PARSER_MEM_TRACE == 1
|
|
ALOGD("[mem]: size: %s%d, total size: %d: %s: %s%s%s\n",
|
|
size > 0 ? "+" : "", size, ini_mem_alloc_size, fun_name,
|
|
(type == INI_MEM_ALL) ? "#" : ((type == INI_MEM_SECTION) ? "[" : ""),
|
|
var_name,
|
|
(type == INI_MEM_ALL) ? "#" : ((type == INI_MEM_SECTION) ? "]" : ""));
|
|
#endif
|
|
}
|
|
|
|
static void ini_alloc_parse_mem_print(void)
|
|
{
|
|
ALOGD("ini parse mem alloc size: %d\n\n", ini_mem_alloc_size);
|
|
}
|
|
|
|
static char *pos_to_str(struct ini_s *ini_buf, unsigned int pos)
|
|
{
|
|
unsigned char *local_ini_mem = (unsigned char *)ini_buf;
|
|
|
|
if (pos == 0 || pos > ini_buf->mem_size)
|
|
return NULL;
|
|
|
|
return (char *)(local_ini_mem + ini_buf->mem_start_pos + pos);
|
|
}
|
|
|
|
static struct ini_line_s *pos_to_line(struct ini_s *ini_buf, unsigned int pos)
|
|
{
|
|
unsigned char *local_ini_mem = (unsigned char *)ini_buf;
|
|
|
|
if (pos == 0 || pos > ini_buf->mem_size)
|
|
return NULL;
|
|
|
|
return (struct ini_line_s *)(local_ini_mem + ini_buf->mem_start_pos + pos);
|
|
}
|
|
|
|
static int line_to_pos(struct ini_s *ini_buf, struct ini_line_s *pline)
|
|
{
|
|
unsigned char *p;
|
|
unsigned char *local_ini_mem = (unsigned char *)ini_buf;
|
|
|
|
if (!ini_buf || !pline)
|
|
return 0;
|
|
|
|
p = (unsigned char *)pline;
|
|
return (p - local_ini_mem - ini_buf->mem_start_pos);
|
|
}
|
|
|
|
static struct ini_section_s *pos_to_section(struct ini_s *ini_buf, unsigned int pos)
|
|
{
|
|
unsigned char *local_ini_mem = (unsigned char *)ini_buf;
|
|
|
|
if (pos == 0 || pos > ini_buf->mem_size)
|
|
return NULL;
|
|
|
|
return (struct ini_section_s *)(local_ini_mem + ini_buf->mem_start_pos + pos);
|
|
}
|
|
|
|
static int section_to_pos(struct ini_s *ini_buf, struct ini_section_s *psec)
|
|
{
|
|
unsigned char *p;
|
|
unsigned char *local_ini_mem = (unsigned char *)ini_buf;
|
|
|
|
if (!ini_buf || !psec)
|
|
return 0;
|
|
|
|
p = (unsigned char *)psec;
|
|
return (p - local_ini_mem - ini_buf->mem_start_pos);
|
|
}
|
|
|
|
/* Strip whitespace chars off end of given string, in place. Return s */
|
|
static char *rstrip(char *s)
|
|
{
|
|
char *p = s + strlen(s);
|
|
|
|
while (p > s && isspace((unsigned char)(*--p)))
|
|
*p = '\0';
|
|
return s;
|
|
}
|
|
|
|
/* Return pointer to first non-whitespace char in given string */
|
|
static char *lskip(const char *s)
|
|
{
|
|
while (*s && isspace((unsigned char)(*s)))
|
|
s++;
|
|
return (char *)s;
|
|
}
|
|
|
|
/* Return pointer to first char c or ';' comment in given string, or pointer to
|
|
*null at end of string if neither found. ';' must be prefixed by a whitespace
|
|
*character to register as a comment
|
|
*/
|
|
static char *find_char_or_comment(const char *s, char c)
|
|
{
|
|
int was_whitespace = 0;
|
|
|
|
while (*s && *s != c && !(was_whitespace && (*s == ';' || *s == '#'))) {
|
|
was_whitespace = isspace((unsigned char)(*s));
|
|
s++;
|
|
}
|
|
return (char *)s;
|
|
}
|
|
|
|
struct ini_section_s *ini_get_section(struct ini_s *ini_buf, const char *section)
|
|
{
|
|
struct ini_section_s *psec;
|
|
char *name;
|
|
|
|
if (!ini_buf || !section)
|
|
return NULL;
|
|
|
|
psec = pos_to_section(ini_buf, ini_buf->cur_section);
|
|
if (psec) {
|
|
name = pos_to_str(ini_buf, psec->name_pos);
|
|
if (name) {
|
|
if (strcmp(name, section) == 0)
|
|
return psec;
|
|
}
|
|
}
|
|
|
|
psec = pos_to_section(ini_buf, ini_buf->first_section);
|
|
while (psec) {
|
|
name = pos_to_str(ini_buf, psec->name_pos);
|
|
if (name) {
|
|
if (strcmp(name, section) == 0)
|
|
return psec;
|
|
}
|
|
psec = pos_to_section(ini_buf, psec->next);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct ini_line_s *ini_get_key_line_at_sec(struct ini_s *ini_buf,
|
|
struct ini_section_s *psec, const char *key)
|
|
{
|
|
struct ini_line_s *pline;
|
|
char *name;
|
|
|
|
if (!ini_buf || !psec || !key)
|
|
return NULL;
|
|
|
|
pline = pos_to_line(ini_buf, psec->cur_line);
|
|
if (pline) {
|
|
name = pos_to_str(ini_buf, pline->name_pos);
|
|
if (name) {
|
|
if (strcmp(name, key) == 0)
|
|
return pline;
|
|
}
|
|
}
|
|
|
|
pline = pos_to_line(ini_buf, psec->first_line);
|
|
while (pline) {
|
|
name = pos_to_str(ini_buf, pline->name_pos);
|
|
if (name) {
|
|
if (strcmp(name, key) == 0)
|
|
return pline;
|
|
}
|
|
pline = pos_to_line(ini_buf, pline->next);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int ini_set_line_exist_key_val(struct ini_s *ini_buf, struct ini_section_s *psec,
|
|
struct ini_line_s *pline, const char *new_value, unsigned int set_mode)
|
|
{
|
|
struct ini_s *tmp_inip;
|
|
struct ini_section_s *tmp_psec, *pre_psec;
|
|
struct ini_line_s *tmp_pline, *pre_pline;
|
|
char *tmp_value, *tmp_name;
|
|
unsigned char *pre_mem, *tmp_mem;
|
|
int pre_len, new_len, offset;
|
|
int tmp_size, new_pos;
|
|
int ret = 0, err_no = 0;
|
|
unsigned char *local_ini_mem = (unsigned char *)ini_buf;
|
|
|
|
if (!ini_buf || !psec || !pline || !new_value)
|
|
return -1;
|
|
|
|
tmp_mem = malloc(ini_buf->total_size);
|
|
if (!tmp_mem) {
|
|
ALOGE("%s: tmp_mem error\n", __func__);
|
|
return -1;
|
|
}
|
|
memset(tmp_mem, 0, ini_buf->total_size);
|
|
tmp_inip = (struct ini_s *)tmp_mem;
|
|
pre_mem = (void *)ini_buf;
|
|
memcpy(tmp_mem, pre_mem, sizeof(struct ini_s));
|
|
|
|
tmp_name = pos_to_str(ini_buf, pline->name_pos);
|
|
tmp_value = pos_to_str(ini_buf, pline->value_pos);
|
|
pre_len = strlen(tmp_value) + 1; //include '\0
|
|
new_len = strlen(new_value) + 1; //include '\0
|
|
|
|
offset = section_to_pos(ini_buf, psec);
|
|
tmp_psec = pos_to_section(tmp_inip, offset);
|
|
if (!tmp_psec) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
|
|
//save front sections & lines
|
|
new_pos = line_to_pos(ini_buf, pline);
|
|
if (new_pos == 0) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
memcpy(tmp_mem + tmp_inip->mem_start_pos, local_ini_mem + ini_buf->mem_start_pos, new_pos);
|
|
tmp_inip->mem_cur_pos = new_pos;
|
|
|
|
if (set_mode == INI_SET_KEY_VAL_MODE_OVERWRITE) { //overwrite new_value
|
|
tmp_size = pline->local_size - pre_len; //line size without value_str
|
|
if ((new_pos + tmp_size + new_len) > tmp_inip->mem_size) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
//save line struct & name_str
|
|
tmp_pline = pos_to_line(tmp_inip, new_pos);
|
|
if (!tmp_pline) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
memcpy(tmp_pline, pline, tmp_size);
|
|
new_pos += tmp_size;
|
|
//save new value_str
|
|
tmp_value = pos_to_str(tmp_inip, tmp_pline->value_pos);
|
|
if (!tmp_value) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
strlcpy(tmp_value, new_value, new_len);
|
|
//update line attr
|
|
tmp_pline->local_size = tmp_size + new_len;
|
|
//update cur_pos
|
|
new_pos += new_len;
|
|
tmp_inip->mem_cur_pos = new_pos;
|
|
|
|
//global offset after active_line, signed value
|
|
offset = new_len - pre_len;
|
|
ini_memnd_alloc_recode(__func__, tmp_name, offset, INI_MEM_KEY);
|
|
ALOGI("%s: %s, overwrite\n", __func__, tmp_name);
|
|
} else { //append new_value
|
|
tmp_size = pline->local_size;
|
|
if ((new_pos + tmp_size) > tmp_inip->mem_size) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
//save line struct & name_str & pre_value_str
|
|
tmp_pline = pos_to_line(tmp_inip, new_pos);
|
|
if (!tmp_pline) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
memcpy(tmp_pline, pline, pline->local_size);
|
|
//save new value_str
|
|
tmp_value = pos_to_str(tmp_inip, tmp_pline->value_pos);
|
|
if (!tmp_value) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
strlcpy((tmp_value + pre_len - 1), new_value, new_len);
|
|
//update line attr
|
|
tmp_pline->local_size = tmp_size - 1 + new_len; //remove pre_value '\0'
|
|
//update cur_pos
|
|
new_pos += tmp_size;
|
|
tmp_inip->mem_cur_pos = new_pos;
|
|
|
|
//global offset behind active_line, signed value.
|
|
offset = new_len - 1; //need remove '\0'
|
|
ini_memnd_alloc_recode(__func__, tmp_name, offset, INI_MEM_KEY);
|
|
ALOGI("%s: %s, append\n", __func__, tmp_name);
|
|
}
|
|
|
|
//save behind lines in same section
|
|
pre_pline = pos_to_line(ini_buf, pline->next);
|
|
while (pre_pline) {
|
|
tmp_pline->next = new_pos;
|
|
tmp_pline = pos_to_line(tmp_inip, new_pos);
|
|
if (!tmp_pline) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
tmp_size = pre_pline->local_size;
|
|
if ((new_pos + tmp_size) > tmp_inip->mem_size) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
memcpy((void *)tmp_pline, pre_pline, tmp_size);
|
|
tmp_pline->name_pos += offset;
|
|
tmp_pline->value_pos += offset;
|
|
|
|
new_pos += tmp_size;
|
|
tmp_inip->mem_cur_pos = new_pos;
|
|
|
|
pre_pline = pos_to_line(ini_buf, pre_pline->next);
|
|
}
|
|
|
|
//save behind sections & lines
|
|
//need trave lines to update each name_pos and value_pos
|
|
pre_psec = pos_to_section(ini_buf, psec->next);
|
|
while (pre_psec) {
|
|
tmp_psec->next = new_pos;
|
|
tmp_psec = pos_to_section(tmp_inip, new_pos);
|
|
if (!tmp_psec) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
tmp_size = pre_psec->local_size;
|
|
if ((new_pos + tmp_size) > tmp_inip->mem_size) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
memcpy((void *)tmp_psec, pre_psec, tmp_size);
|
|
tmp_psec->name_pos += offset;
|
|
|
|
new_pos += tmp_size;
|
|
tmp_inip->mem_cur_pos = new_pos;
|
|
|
|
tmp_pline = NULL;
|
|
pre_pline = pos_to_line(ini_buf, pre_psec->first_line);
|
|
while (pre_pline) {
|
|
if (!tmp_pline)
|
|
tmp_psec->first_line = new_pos;
|
|
else
|
|
tmp_pline->next = new_pos;
|
|
tmp_pline = pos_to_line(tmp_inip, new_pos);
|
|
if (!tmp_pline) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
tmp_size = pre_pline->local_size;
|
|
if ((new_pos + tmp_size) > tmp_inip->mem_size) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_key_val_end;
|
|
}
|
|
memcpy((void *)tmp_pline, pre_pline, tmp_size);
|
|
tmp_pline->name_pos += offset;
|
|
tmp_pline->value_pos += offset;
|
|
|
|
new_pos += tmp_size;
|
|
tmp_inip->mem_cur_pos = new_pos;
|
|
|
|
pre_pline = pos_to_line(ini_buf, pre_pline->next);
|
|
}
|
|
|
|
pre_psec = pos_to_section(ini_buf, pre_psec->next);
|
|
}
|
|
|
|
//restore cur_mem
|
|
memcpy(local_ini_mem + ini_buf->mem_start_pos,
|
|
tmp_mem + tmp_inip->mem_start_pos, ini_buf->mem_size);
|
|
ini_buf->mem_cur_pos = tmp_inip->mem_cur_pos;
|
|
|
|
ini_set_line_exist_key_val_end:
|
|
memset(tmp_mem, 0, ini_buf->total_size);
|
|
free(tmp_mem);
|
|
if (ret)
|
|
ALOGE("%s: %d\n", __func__, err_no);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ini_set_line_exist_keys(struct ini_s *ini_buf, struct ini_section_s *psec,
|
|
const char *new_line, const char *new_value, int line_cnt)
|
|
{
|
|
struct ini_s *tmp_inip;
|
|
struct ini_section_s *tmp_psec, *pre_psec;
|
|
struct ini_line_s *tmp_pline, *pre_pline;
|
|
char *tmp_value;
|
|
const char *pre_name, *pre_value, *token_line, *token_value;
|
|
unsigned char *tmp_mem;
|
|
int offset, tmp_size, new_pos;
|
|
int i, j, ret = 0, err_no = 0;
|
|
unsigned char *local_ini_mem = (unsigned char *)ini_buf;
|
|
|
|
if (!ini_buf || !psec || !new_line || !new_value)
|
|
return -1;
|
|
|
|
tmp_mem = malloc(ini_buf->total_size);
|
|
if (!tmp_mem) {
|
|
ALOGE("%s: tmp_mem error\n", __func__);
|
|
return -1;
|
|
}
|
|
memset(tmp_mem, 0, ini_buf->total_size);
|
|
tmp_inip = (struct ini_s *)tmp_mem;
|
|
memcpy(tmp_mem, (void *)ini_buf, sizeof(struct ini_s));
|
|
|
|
new_pos = section_to_pos(ini_buf, psec);
|
|
tmp_psec = pos_to_section(tmp_inip, new_pos);
|
|
if (!tmp_psec) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
|
|
//save front sections
|
|
memcpy(tmp_mem + tmp_inip->mem_start_pos, local_ini_mem + ini_buf->mem_start_pos, new_pos);
|
|
tmp_inip->mem_cur_pos = new_pos;
|
|
|
|
//overwrite current section with new lines value
|
|
tmp_size = psec->local_size;
|
|
if ((new_pos + tmp_size) > tmp_inip->mem_size) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
memcpy((void *)tmp_psec, psec, tmp_size);
|
|
new_pos += tmp_size;
|
|
tmp_inip->mem_cur_pos = new_pos;
|
|
|
|
offset = 0;
|
|
tmp_pline = NULL;
|
|
pre_pline = pos_to_line(ini_buf, psec->first_line);
|
|
while (pre_pline) {
|
|
if (!tmp_pline)
|
|
tmp_psec->first_line = new_pos;
|
|
else
|
|
tmp_pline->next = new_pos;
|
|
tmp_pline = pos_to_line(tmp_inip, new_pos);
|
|
if (!tmp_pline) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
pre_name = pos_to_str(ini_buf, pre_pline->name_pos);
|
|
if (!pre_name) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
token_line = new_line;
|
|
for (i = 0; i < line_cnt; i++) {
|
|
if (strcmp(pre_name, token_line) == 0) { //target line, overwrite value
|
|
pre_value = pos_to_str(ini_buf, pre_pline->value_pos);
|
|
if (!pre_value) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
tmp_size = (unsigned char *)pre_value - (unsigned char *)pre_pline;
|
|
if ((new_pos + tmp_size) > tmp_inip->mem_size) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
memcpy(tmp_pline, pre_pline, tmp_size);
|
|
tmp_pline->name_pos += offset;
|
|
tmp_pline->value_pos += offset;
|
|
new_pos += tmp_size;
|
|
|
|
tmp_value = pos_to_str(tmp_inip, tmp_pline->value_pos);
|
|
if (!tmp_value) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
token_value = new_value;
|
|
for (j = 0; j < i; j++)
|
|
token_value += strlen(token_value) + 2; //next value_str
|
|
tmp_size = strlen(token_value) + 1; //include '\0'
|
|
if ((new_pos + tmp_size) > tmp_inip->mem_size) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
strlcpy(tmp_value, token_value, tmp_size);
|
|
offset += (tmp_size - (strlen(pre_value) + 1));
|
|
new_pos += tmp_size;
|
|
|
|
ini_memnd_alloc_recode(__func__, pre_name, offset, INI_MEM_KEY);
|
|
ALOGI("%s: %s, overwrite\n", __func__, token_line);
|
|
|
|
goto ini_set_line_exist_keys_cur_psec_next_line;
|
|
}
|
|
token_line += strlen(token_line) + 2; //next value_str
|
|
}
|
|
|
|
//not target line, just copy
|
|
tmp_size = pre_pline->local_size;
|
|
if ((new_pos + tmp_size) > tmp_inip->mem_size) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
memcpy(tmp_pline, pre_pline, tmp_size);
|
|
tmp_pline->name_pos += offset;
|
|
tmp_pline->value_pos += offset;
|
|
new_pos += tmp_size;
|
|
|
|
ini_set_line_exist_keys_cur_psec_next_line:
|
|
pre_pline = pos_to_line(ini_buf, pre_pline->next);
|
|
}
|
|
|
|
//save behind sections
|
|
//need trave lines to update each name_pos and value_pos
|
|
pre_psec = pos_to_section(ini_buf, psec->next);
|
|
while (pre_psec) {
|
|
tmp_psec->next = new_pos;
|
|
tmp_psec = pos_to_section(tmp_inip, tmp_psec->next);
|
|
if (!tmp_psec) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
|
|
tmp_size = pre_psec->local_size;
|
|
if ((new_pos + tmp_size) > tmp_inip->mem_size) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
memcpy((void *)tmp_psec, pre_psec, tmp_size);
|
|
tmp_psec->name_pos += offset;
|
|
|
|
new_pos += tmp_size;
|
|
tmp_inip->mem_cur_pos = new_pos;
|
|
|
|
tmp_pline = NULL;
|
|
pre_pline = pos_to_line(ini_buf, pre_psec->first_line);
|
|
while (pre_pline) {
|
|
if (!tmp_pline)
|
|
tmp_psec->first_line = new_pos;
|
|
else
|
|
tmp_pline->next = new_pos;
|
|
tmp_pline = pos_to_line(tmp_inip, new_pos);
|
|
if (!tmp_pline) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
|
|
tmp_size = pre_pline->local_size;
|
|
if ((new_pos + tmp_size) > tmp_inip->mem_size) {
|
|
err_no = __LINE__;
|
|
ret = -1;
|
|
goto ini_set_line_exist_keys_end;
|
|
}
|
|
memcpy((void *)tmp_pline, pre_pline, tmp_size);
|
|
tmp_pline->name_pos += offset;
|
|
tmp_pline->value_pos += offset;
|
|
|
|
new_pos += tmp_size;
|
|
tmp_inip->mem_cur_pos = new_pos;
|
|
|
|
pre_pline = pos_to_line(ini_buf, pre_pline->next);
|
|
}
|
|
|
|
pre_psec = pos_to_section(ini_buf, pre_psec->next);
|
|
}
|
|
|
|
//restore cur_mem
|
|
memcpy(local_ini_mem + ini_buf->mem_start_pos,
|
|
tmp_mem + tmp_inip->mem_start_pos, ini_buf->mem_size);
|
|
ini_buf->mem_cur_pos = tmp_inip->mem_cur_pos;
|
|
|
|
ini_set_line_exist_keys_end:
|
|
memset(tmp_mem, 0, ini_buf->total_size);
|
|
free(tmp_mem);
|
|
if (ret)
|
|
ALOGE("%s: %d\n", __func__, err_no);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static struct ini_line_s *ini_new_line(struct ini_s *ini_buf, struct ini_section_s *psec,
|
|
const char *name, const char *value)
|
|
{
|
|
struct ini_line_s *pline = NULL;
|
|
unsigned int tmp_pos, start_pos, tmp_size, str_size;
|
|
char *str;
|
|
|
|
start_pos = ini_buf->mem_cur_pos;
|
|
tmp_size = sizeof(struct ini_line_s);
|
|
if (start_pos + tmp_size >= ini_buf->mem_size) {
|
|
ALOGE("%s: %s: out of mem_size %d\n",
|
|
__func__, name, ini_buf->mem_size);
|
|
return NULL;
|
|
}
|
|
pline = pos_to_line(ini_buf, start_pos);
|
|
if (!pline) {
|
|
ALOGE("%s: %s: start_pos error\n", __func__, name);
|
|
return NULL;
|
|
}
|
|
pline->next = 0;
|
|
tmp_pos = start_pos + tmp_size;
|
|
|
|
str_size = strlen(name) + 1; //include '\0'
|
|
if (tmp_pos + str_size >= ini_buf->mem_size) {
|
|
ALOGE("%s: %s: out of mem_size %d\n",
|
|
__func__, name, ini_buf->mem_size);
|
|
return NULL;
|
|
}
|
|
pline->name_pos = tmp_pos;
|
|
str = pos_to_str(ini_buf, pline->name_pos);
|
|
if (!str) {
|
|
ALOGE("%s: %s: name_pos error\n", __func__, name);
|
|
return NULL;
|
|
}
|
|
strlcpy(str, name, str_size);
|
|
tmp_pos += str_size;
|
|
|
|
str_size = strlen(value) + 1; //include '\0'
|
|
if (tmp_pos + str_size >= ini_buf->mem_size) {
|
|
ALOGE("%s: %s: out of mem_size %d\n",
|
|
__func__, name, ini_buf->mem_size);
|
|
return NULL;
|
|
}
|
|
pline->value_pos = tmp_pos;
|
|
str = pos_to_str(ini_buf, pline->value_pos);
|
|
if (!str) {
|
|
ALOGE("%s: %s: value_pos error\n", __func__, name);
|
|
return NULL;
|
|
}
|
|
strlcpy(str, value, str_size);
|
|
tmp_pos += str_size;
|
|
|
|
pline->local_size = tmp_pos - start_pos;
|
|
ini_buf->mem_cur_pos = tmp_pos;
|
|
ini_memnd_alloc_recode(__func__, name, pline->local_size, INI_MEM_KEY);
|
|
|
|
return pline;
|
|
}
|
|
|
|
static struct ini_section_s *ini_new_section(struct ini_s *ini_buf, const char *section)
|
|
{
|
|
struct ini_section_s *psec = NULL;
|
|
unsigned int tmp_pos, start_pos, tmp_size, str_size;
|
|
char *str;
|
|
|
|
start_pos = ini_buf->mem_cur_pos;
|
|
tmp_size = sizeof(struct ini_section_s);
|
|
if (start_pos + tmp_size >= ini_buf->mem_size) {
|
|
ALOGE("%s: [%s]: out of mem_size %d\n",
|
|
__func__, section, ini_buf->mem_size);
|
|
return NULL;
|
|
}
|
|
psec = pos_to_section(ini_buf, start_pos);
|
|
if (!psec) {
|
|
ALOGE("%s: [%s]: start_pos error\n", __func__, section);
|
|
return NULL;
|
|
}
|
|
psec->next = 0;
|
|
tmp_pos = start_pos + tmp_size;
|
|
|
|
str_size = strlen(section) + 1; //include '\0'
|
|
if (tmp_pos + str_size >= ini_buf->mem_size) {
|
|
ALOGE("%s: [%s]: out of mem_size %d\n",
|
|
__func__, section, ini_buf->mem_size);
|
|
return NULL;
|
|
}
|
|
psec->name_pos = tmp_pos;
|
|
str = pos_to_str(ini_buf, psec->name_pos);
|
|
if (!str) {
|
|
ALOGE("%s: [%s]: name_pos error\n", __func__, section);
|
|
return NULL;
|
|
}
|
|
strlcpy(str, section, str_size);
|
|
tmp_pos += str_size;
|
|
|
|
psec->local_size = tmp_pos - start_pos;
|
|
ini_buf->mem_cur_pos = tmp_pos;
|
|
ini_memnd_alloc_recode(__func__, section, psec->local_size, INI_MEM_SECTION);
|
|
|
|
return psec;
|
|
}
|
|
|
|
static void trim(char *str, char ch)
|
|
{
|
|
char *pstr, *ptmp;
|
|
|
|
pstr = str;
|
|
while (*pstr != '\0') {
|
|
if (*pstr == ch) {
|
|
ptmp = pstr;
|
|
while (*ptmp != '\0') {
|
|
*ptmp = *(ptmp + 1);
|
|
ptmp++;
|
|
}
|
|
} else {
|
|
pstr++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void trim_all(char *str)
|
|
{
|
|
char *pstr = NULL;
|
|
int len;
|
|
|
|
pstr = strchr(str, '\n');
|
|
if (pstr)
|
|
*pstr = 0;
|
|
|
|
len = strlen(str);
|
|
if (len > 0) {
|
|
if (str[len - 1] == '\r')
|
|
str[len - 1] = '\0';
|
|
}
|
|
|
|
pstr = strchr(str, '#');
|
|
if (pstr)
|
|
*pstr = 0;
|
|
|
|
pstr = strchr(str, ';');
|
|
if (pstr)
|
|
*pstr = 0;
|
|
|
|
trim(str, ' ');
|
|
trim(str, '{');
|
|
trim(str, '\\');
|
|
trim(str, '}');
|
|
trim(str, '\"');
|
|
}
|
|
|
|
int ini_set_key_value(struct ini_s *ini_buf,
|
|
const char *section, const char *key, const char *value, unsigned int set_mode)
|
|
{
|
|
struct ini_line_s *pline = NULL, *cur_line;
|
|
struct ini_section_s *psec = NULL, *cur_sec;
|
|
unsigned int pos;
|
|
int ret;
|
|
|
|
if (!ini_buf || !section || !key || !value)
|
|
return -1;
|
|
|
|
trim_all((char *)value);
|
|
if (value[0] == '\0')
|
|
return 0; //no value is considered not an error
|
|
|
|
if (!ini_buf->first_section) {
|
|
psec = ini_new_section(ini_buf, section);
|
|
if (!psec)
|
|
goto ini_set_key_value_end;
|
|
pline = ini_new_line(ini_buf, psec, key, value);
|
|
if (!pline)
|
|
goto ini_set_key_value_end;
|
|
|
|
pos = line_to_pos(ini_buf, pline);
|
|
psec->first_line = pos;
|
|
psec->cur_line = pos;
|
|
|
|
pos = section_to_pos(ini_buf, psec);
|
|
ini_buf->first_section = pos;
|
|
ini_buf->cur_section = pos;
|
|
} else {
|
|
psec = ini_get_section(ini_buf, section);
|
|
if (!psec) {
|
|
psec = ini_new_section(ini_buf, section);
|
|
if (!psec)
|
|
goto ini_set_key_value_end;
|
|
pline = ini_new_line(ini_buf, psec, key, value);
|
|
if (!pline)
|
|
goto ini_set_key_value_end;
|
|
cur_sec = pos_to_section(ini_buf, ini_buf->cur_section);
|
|
if (!cur_sec)
|
|
goto ini_set_key_value_end;
|
|
|
|
pos = line_to_pos(ini_buf, pline);
|
|
psec->first_line = pos;
|
|
psec->cur_line = pos;
|
|
|
|
pos = section_to_pos(ini_buf, psec);
|
|
cur_sec->next = pos;
|
|
ini_buf->cur_section = pos;
|
|
} else {
|
|
pline = ini_get_key_line_at_sec(ini_buf, psec, key);
|
|
if (!pline) {
|
|
pline = ini_new_line(ini_buf, psec, key, value);
|
|
if (!pline)
|
|
goto ini_set_key_value_end;
|
|
cur_line = pos_to_line(ini_buf, psec->cur_line);
|
|
if (!cur_line)
|
|
goto ini_set_key_value_end;
|
|
|
|
pos = line_to_pos(ini_buf, pline);
|
|
cur_line->next = pos;
|
|
psec->cur_line = pos;
|
|
} else {
|
|
ret = ini_set_line_exist_key_val(ini_buf, psec, pline,
|
|
value, set_mode);
|
|
if (ret)
|
|
goto ini_set_key_value_end;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
ini_set_key_value_end:
|
|
ALOGE("%s: [%s]: %s: error\n", __func__, section, key);
|
|
return 0;
|
|
}
|
|
|
|
static int ini_multi_line_str_store(char *buf, char *str, int max_len)
|
|
{
|
|
int len;
|
|
|
|
trim_all(str);
|
|
if (str[0] == '\0')
|
|
return 0; //no value is not considered an error
|
|
|
|
if (strlen(str) >= max_len) {
|
|
ALOGE("%s: out of max_len %d: %s\n", __func__, max_len, str);
|
|
return 0;
|
|
}
|
|
len = sprintf(buf, "%s", str);
|
|
|
|
return len;
|
|
}
|
|
|
|
static int ini_multi_line_handler(struct ini_s *ini_buf, struct ini_multi_line_s *multi_line)
|
|
{
|
|
int ret;
|
|
|
|
if (!multi_line || !multi_line->sec_name || !multi_line->key_name || !multi_line->buf)
|
|
return -1;
|
|
|
|
ALOGD("%s: [%s]: %s=%s\n",
|
|
__func__, multi_line->sec_name, multi_line->key_name, multi_line->buf);
|
|
ret = ini_set_key_value(ini_buf, multi_line->sec_name, multi_line->key_name,
|
|
multi_line->buf, INI_SET_KEY_VAL_MODE_APPEND);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int ini_key_multi_line_add(struct ini_s *ini_buf, struct ini_multi_line_s *multi_line,
|
|
char *str)
|
|
{
|
|
char *end, *p;
|
|
int n, ret = 0;
|
|
|
|
end = find_char_or_comment(str, '}');
|
|
if (*end == '}') { //multi_line end
|
|
*end = '\0';
|
|
rstrip(str);
|
|
p = multi_line->buf + multi_line->cur_pos;
|
|
n = multi_line->max_len - multi_line->cur_pos;
|
|
multi_line->cur_pos += ini_multi_line_str_store(p, str, n);
|
|
|
|
//set multi_line
|
|
ret = ini_multi_line_handler(ini_buf, multi_line);
|
|
multi_line->cur_pos = 0;
|
|
multi_line->valid = 0;
|
|
} else {
|
|
p = multi_line->buf + multi_line->cur_pos;
|
|
n = multi_line->max_len - multi_line->cur_pos;
|
|
multi_line->cur_pos += ini_multi_line_str_store(p, str, n);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int ini_key_handler(struct ini_s *ini_buf,
|
|
const char *section, const char *name, const char *value)
|
|
{
|
|
int ret;
|
|
|
|
ret = ini_set_key_value(ini_buf, section, name, value, INI_SET_KEY_VAL_MODE_OVERWRITE);
|
|
return ret;
|
|
}
|
|
|
|
int ini_parse_mem(struct ini_s *ini_buf, const char *tmp_buf)
|
|
{
|
|
const char *bufptr;
|
|
char *line;
|
|
struct ini_multi_line_s multi_line;
|
|
char section[INI_SECTION_NAME_LEN_MAX] = "";
|
|
char prev_name[INI_KEY_NAME_LEN_MAX] = "";
|
|
char *start, *end;
|
|
char *name, *value;
|
|
int char_cnt, lineno = 0, error = 0;
|
|
int ret;
|
|
|
|
if (!ini_buf || !tmp_buf)
|
|
return -1;
|
|
|
|
line = (char *)malloc(INI_LINE_LEN_MAX);
|
|
if (!line)
|
|
return -1;
|
|
memset(line, 0, INI_LINE_LEN_MAX);
|
|
|
|
multi_line.max_len = INI_MULTI_LINE_LEN_MAX;
|
|
multi_line.buf = (char *)malloc(multi_line.max_len);
|
|
if (!multi_line.buf) {
|
|
free(line);
|
|
return -1;
|
|
}
|
|
memset(multi_line.buf, 0, multi_line.max_len);
|
|
multi_line.valid = 0;
|
|
multi_line.cur_pos = 0;
|
|
multi_line.sec_name = section;
|
|
multi_line.key_name = prev_name;
|
|
|
|
bufptr = tmp_buf;
|
|
while (1) {
|
|
char_cnt = 0;
|
|
while (*bufptr != '\0') {
|
|
if (*bufptr == '\r' || *bufptr == '\n')
|
|
break;
|
|
|
|
line[char_cnt] = *bufptr++;
|
|
char_cnt++;
|
|
}
|
|
while (*bufptr == '\r' || *bufptr == '\n')
|
|
bufptr++;
|
|
line[char_cnt] = 0;
|
|
|
|
if (char_cnt == 0) //end
|
|
break;
|
|
|
|
lineno++;
|
|
//ALOGD("%s: lineno=%d\n", __func__, lineno);
|
|
if (char_cnt > INI_LINE_LEN_MAX) {
|
|
ALOGE("%s: line %d char_cnt %d out of support\n",
|
|
__func__, lineno, char_cnt);
|
|
if (!error)
|
|
error = lineno;
|
|
}
|
|
|
|
start = line;
|
|
start = lskip(rstrip(start));
|
|
|
|
if (*start == ';' || *start == '#') {
|
|
/* allow '#' comments at start of line */
|
|
} else if (*start == '[') {
|
|
/* A "[section]" line */
|
|
end = find_char_or_comment(start + 1, ']');
|
|
if (*end == ']') {
|
|
*end = '\0';
|
|
strlcpy(section, start + 1, sizeof(section));
|
|
*prev_name = '\0';
|
|
if (multi_line.valid) {
|
|
multi_line.valid = 0;
|
|
multi_line.cur_pos = 0;
|
|
if (!error)
|
|
error = lineno;
|
|
}
|
|
} else if (!error) {
|
|
/* No ']' found on section line */
|
|
error = lineno;
|
|
}
|
|
} else if (*start) {
|
|
/* Not a comment, should be a name[=:]value pair */
|
|
end = find_char_or_comment(start, '=');
|
|
if (*end != '=')
|
|
end = find_char_or_comment(start, ':');
|
|
if (*end == '=' || *end == ':') {
|
|
/* Valid name[=:]value pair found */
|
|
*end = '\0';
|
|
name = rstrip(start);
|
|
strlcpy(prev_name, name, sizeof(prev_name));
|
|
if (multi_line.valid) {
|
|
multi_line.valid = 0;
|
|
multi_line.cur_pos = 0;
|
|
if (!error)
|
|
error = lineno;
|
|
}
|
|
|
|
value = lskip(end + 1);
|
|
end = find_char_or_comment(value, '\0');
|
|
if (*end == ';' || *end == '#')
|
|
*end = '\0';
|
|
rstrip(value);
|
|
|
|
if (*value == '{') { //multi_line start
|
|
value = lskip(value + 1);
|
|
multi_line.valid = 1;
|
|
ret = ini_key_multi_line_add(ini_buf, &multi_line, value);
|
|
} else {
|
|
/* Valid name[=:]value pair found, call handler */
|
|
ret = ini_key_handler(ini_buf, section, name, value);
|
|
}
|
|
if (ret && !error)
|
|
error = lineno;
|
|
} else {
|
|
/* No '=' or ':' found, not name[=:]value line */
|
|
value = rstrip(start);
|
|
end = find_char_or_comment(value, '\0');
|
|
if (*end == ';' || *end == '#')
|
|
*end = '\0';
|
|
rstrip(value);
|
|
|
|
if (*value == '{') { //multi_line start
|
|
if (multi_line.valid == 0 && *prev_name) {
|
|
value = lskip(value + 1);
|
|
multi_line.valid = 1;
|
|
ret = ini_key_multi_line_add(ini_buf, &multi_line,
|
|
value);
|
|
if (ret && !error)
|
|
error = lineno;
|
|
} else { //'{' can't appear in the middle of multi_line
|
|
if (!error)
|
|
error = lineno;
|
|
}
|
|
} else {
|
|
if (multi_line.valid && *prev_name) {
|
|
ret = ini_key_multi_line_add(ini_buf, &multi_line,
|
|
value);
|
|
if (ret && !error)
|
|
error = lineno;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (error)
|
|
ALOGE("%s: error=%d\n", __func__, error);
|
|
|
|
memset(line, 0, INI_LINE_LEN_MAX);
|
|
free(line);
|
|
|
|
ini_alloc_parse_mem_print();
|
|
|
|
return error;
|
|
}
|
|
|
|
const char *ini_get_string(struct ini_s *ini_buf, struct ini_section_s *psec,
|
|
const char *key, const char *def_value)
|
|
{
|
|
struct ini_line_s *pline;
|
|
char *value;
|
|
|
|
if (!ini_buf || !psec)
|
|
return def_value;
|
|
|
|
pline = ini_get_key_line_at_sec(ini_buf, psec, key);
|
|
if (!pline)
|
|
return def_value;
|
|
|
|
value = pos_to_str(ini_buf, pline->value_pos);
|
|
return value;
|
|
}
|
|
|
|
void ini_list_key_value(struct ini_s *ini_buf)
|
|
{
|
|
struct ini_section_s *psec;
|
|
struct ini_line_s *pline;
|
|
char *str, *name, *value;
|
|
int value_size, i, j, n, m;
|
|
|
|
if (!ini_buf)
|
|
return;
|
|
|
|
str = (char *)malloc(512);
|
|
if (!str) {
|
|
printf("%s: malloc print memory error\n", __func__);
|
|
return;
|
|
}
|
|
|
|
psec = pos_to_section(ini_buf, ini_buf->first_section);
|
|
while (psec) {
|
|
name = pos_to_str(ini_buf, psec->name_pos);
|
|
printf("[%s]\n", name);
|
|
pline = pos_to_line(ini_buf, psec->first_line);
|
|
while (pline) {
|
|
name = pos_to_str(ini_buf, pline->name_pos);
|
|
value = pos_to_str(ini_buf, pline->value_pos);
|
|
value_size = strlen(value) + 1;
|
|
if (value_size >= 510) {
|
|
printf(" %s = ", name);
|
|
n = value_size / 510;
|
|
m = value_size % 510;
|
|
for (i = 0; i < n; i++) {
|
|
j = i * 510;
|
|
strncpy(str, value + j, 510);
|
|
str[510] = '\0';
|
|
printf("%s\n", str);
|
|
}
|
|
if (m) {
|
|
j = n * 510;
|
|
strncpy(str, value + j, m);
|
|
str[m] = '\0';
|
|
printf("%s\n", str);
|
|
}
|
|
} else {
|
|
printf(" %s = %s\n", name, value);
|
|
}
|
|
pline = pos_to_line(ini_buf, pline->next);
|
|
}
|
|
printf("\n");
|
|
psec = pos_to_section(ini_buf, psec->next);
|
|
}
|
|
|
|
memset(str, 0, 512);
|
|
free(str);
|
|
}
|
|
|
|
void ini_list_section(struct ini_s *ini_buf)
|
|
{
|
|
struct ini_section_s *psec;
|
|
char *name;
|
|
|
|
if (!ini_buf)
|
|
return;
|
|
psec = pos_to_section(ini_buf, ini_buf->first_section);
|
|
while (psec) {
|
|
name = pos_to_str(ini_buf, psec->name_pos);
|
|
printf(" %s\n", name);
|
|
psec = pos_to_section(ini_buf, psec->next);
|
|
}
|
|
}
|
|
|
|
void ini_handler_mem_free(struct ini_s *ini_buf)
|
|
{
|
|
int alloc_size;
|
|
|
|
if (!ini_buf)
|
|
return;
|
|
|
|
alloc_size = 0 - (ini_buf->mem_cur_pos - INI_MEM_DATA_OFFSET);
|
|
ini_memnd_alloc_recode(__func__, "all", alloc_size, INI_MEM_ALL);
|
|
|
|
ini_alloc_parse_mem_print();
|
|
}
|