blob: c1fb3d12231b97f3a52e6bdf034360c94e671706 [file] [log] [blame]
// Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <assert.h>
#if defined(_WIN32) || defined(_WIN64)
#pragma warning(disable : 4996)
#define LINE_FEED_STR "\r\n"
#define BINARY_MODE "b"
#else
#define LINE_FEED_STR "\n"
#define BINARY_MODE
#endif
#define LSECT_DELIMITER '['
#define RSECT_DELIMITER ']'
#define KEY_DELIMITER '='
#define IS_LINEFEED(c) ((c) == '\r' || (c) == '\n')
#define IS_TAB_SPACE(c) ((c) == ' ' || (c) == '\t')
#define IS_COMMENT(c) ((c) == '#' || (c) == ';')
#define BASE_BUF_SIZE 1024
#if 0
#define chrcmp(c1,c2) ((c1)==(c2)
#else
#define chrcmp(c1,c2) (toupper(c1)==toupper(c2))
#endif
static int cp_key_value(char *buf, const char *line, int n)
{
char *d = buf;
while (n--) {
if (IS_TAB_SPACE(*line)) {
line++;
continue;
}
if (IS_LINEFEED(*line)) {
if (n)
*d++ = 0;
break;
}
if (!(*d = *line))
break;
d++;
line++;
}
return d - buf;
}
static int cp_value(char *buf, const char *value, int n)
{
char *d = buf;
while (n--) {
if (IS_TAB_SPACE(*value)) {
value++;
continue;
}
if (IS_LINEFEED(*value)) {
if (n)
*d = 0;
break;
}
if (!(*d = *value))
break;
d++;
value++;
}
return d - buf;
}
static int get_section(const char *line, char *section)
{
char *pos = section;
if (*line++ != LSECT_DELIMITER)
return 0;
while (*line && !IS_LINEFEED(*line) && *line != RSECT_DELIMITER)
*pos++ = *line++;
if (*line == RSECT_DELIMITER) {
*pos++ = 0;
return pos-section;
}
else
return 0;
}
static const char * find_section(const char *line, const char *section)
{
if (*line++ != LSECT_DELIMITER)
return NULL;
while (chrcmp(*line, *section)) {
line++;
section++;
}
if (!*section && *line == RSECT_DELIMITER)
return section;
else
return NULL;
}
static const char * find_key(const char *line, const char *key)
{
while (chrcmp(*line, *key)) {
line++;
key++;
}
if (!*key) {
if (*line != KEY_DELIMITER && !IS_TAB_SPACE(*line))
return NULL;
while (*line && *line != KEY_DELIMITER)
line++;
if (*line == KEY_DELIMITER) {
return ++line;
}
}
return NULL;
}
int get_profile_section(const char *section, char *buf, int buf_size, const char *file)
{
FILE *fp;
char line[BASE_BUF_SIZE];
const char *val = NULL;
char *pos = buf;
int available = buf_size;
int len;
if (!buf || !buf_size || !file) {
errno = EINVAL;
return 0;
}
if ((fp = fopen(file, "r"BINARY_MODE)) == NULL)
return 0;
while (fgets(line, sizeof(line), fp)) {
if ((val = find_section(line, section)))
break;
}
if (val) {
val = NULL;
while (available > 0 && fgets(line, sizeof(line), fp)) {
if (*line == LSECT_DELIMITER)
break;
if (IS_COMMENT(*line) || IS_TAB_SPACE(*line))
continue;
len = cp_key_value(pos, line, available);
available -= len;
pos += len;
}
if (available > 0)
*pos++ = 0;
}
fclose(fp);
return pos - buf;
}
int get_profile_section_names(char *buf, int buf_size, const char *file)
{
FILE *fp;
char line[BASE_BUF_SIZE];
char *pos = buf;
if (!buf || !buf_size || !file) {
errno = EINVAL;
return -1;
}
if ((fp = fopen(file, "r"BINARY_MODE)) == NULL)
return -1;
while (fgets(line, sizeof(line), fp))
pos += get_section(line, pos);
*pos++ = 0;
fclose(fp);
return pos - buf;
}
int get_profile_string(const char *section, const char *key, const char *default_str,
char *buf, int buf_size, const char *file)
{
FILE *fp;
char line[BASE_BUF_SIZE];
const char *val = NULL;
int len;
if (!section || !*section || !key || !*key || !buf || !buf_size || !file) {
errno = EINVAL;
return 0;
}
if ((fp = fopen(file, "r"BINARY_MODE)) == NULL)
goto default_value;
while (fgets(line, sizeof(line), fp)) {
if ((val = find_section(line, section)))
break;
}
if (val) {
val = NULL;
while (fgets(line, sizeof(line), fp)) {
if (*line == LSECT_DELIMITER)
break;
if (IS_COMMENT(*line))
continue;
if ((val = find_key(line, key)))
break;
}
}
fclose(fp);
default_value:
if (!val) {
if (!default_str) {
errno = EINVAL;
return 0;
}
val = default_str;
}
len = cp_value(buf, val, buf_size);
return len;
}
int write_profile_string(const char *section, const char *key, const char *str,
const char *file)
{
FILE *fp;
char line[BASE_BUF_SIZE];
const char *find = NULL;
char *rest_data = NULL;
int rpos = 0, wpos = 0, eof, len, ret = 0;
if (!section || !*section || !key || !*key || !str || !file) {
errno = EINVAL;
return -1;
}
if (!(fp = fopen(file, "r+"BINARY_MODE))) {
if (!(fp = fopen(file, "w"BINARY_MODE)))
return -1;
goto append_section;
}
while (fgets(line, sizeof(line), fp)) {
if ((find = find_section(line, section)))
break;
}
if (find) {
find = NULL;
while (fgets(line, sizeof(line), fp)) {
if (*line == LSECT_DELIMITER) {
find = line;
if (!wpos)
wpos = rpos = ftell(fp) - strlen(line);
break;
}
if (IS_COMMENT(*line))
continue;
if (IS_LINEFEED(*line)) {
if (!wpos)
wpos = rpos = ftell(fp) - strlen(line);
continue;
}
if ((find = find_key(line, key))) {
rpos = ftell(fp);
wpos = rpos - strlen(line);
break;
}
}
if (find == NULL) {
len = strlen(line);
if (!IS_LINEFEED(line[len-1]) && !IS_LINEFEED(line[len-2]))
fputs(LINE_FEED_STR, fp);
goto append_key; /*end of file*/
}
}
if (find) {
fseek(fp, 0, SEEK_END);
eof = ftell(fp);
fseek(fp, rpos, SEEK_SET);
len = eof - rpos;
rest_data = malloc(len);
assert(rest_data);
if (len != fread(rest_data, 1, len, fp)) {
ret = -1;
goto close;
}
/*Overwrite*/
fseek(fp, wpos, SEEK_SET);
sprintf(line, "%s=%s%s", key, str, LINE_FEED_STR);
fputs(line, fp);
if (len != fwrite(rest_data, 1, len, fp)) {
ret = -1;
goto close;
}
}
else {
len = strlen(line);
if (!IS_LINEFEED(line[len-1]) && !IS_LINEFEED(line[len-2]))
fputs(LINE_FEED_STR, fp);
append_section:
sprintf(line, "[%s]%s", section, LINE_FEED_STR);
fputs(line, fp);
append_key:
sprintf(line, "%s=%s%s", key, str, LINE_FEED_STR);
fputs(line, fp);
}
close:
fclose(fp);
if (rest_data)
free(rest_data);
return ret;
}