426 lines
10 KiB
C
426 lines
10 KiB
C
/****************************************************************************
|
|
* apps/system/settings/storage_text.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include "system/settings.h"
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <ctype.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <nuttx/config.h>
|
|
#include <sys/types.h>
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#define BUFFER_SIZE 256 /* Note alignment for Flash writes! */
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: getsetting
|
|
*
|
|
* Description:
|
|
* Gets the setting information from a given key.
|
|
*
|
|
* Input Parameters:
|
|
* key - key of the required setting
|
|
*
|
|
* Returned Value:
|
|
* The setting
|
|
*
|
|
****************************************************************************/
|
|
|
|
FAR static setting_t *getsetting(char *key);
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Public Data
|
|
****************************************************************************/
|
|
|
|
extern setting_t map[CONFIG_SYSTEM_SETTINGS_MAP_SIZE];
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: getsetting
|
|
*
|
|
* Description:
|
|
* Gets the setting information from a given key.
|
|
*
|
|
* Input Parameters:
|
|
* key - key of the required setting
|
|
*
|
|
* Returned Value:
|
|
* The setting
|
|
*
|
|
****************************************************************************/
|
|
|
|
FAR setting_t *getsetting(char *key)
|
|
{
|
|
int i;
|
|
FAR setting_t *setting;
|
|
|
|
if (strlen(key) >= CONFIG_SYSTEM_SETTINGS_KEY_SIZE)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < CONFIG_SYSTEM_SETTINGS_MAP_SIZE; i++)
|
|
{
|
|
setting = &map[i];
|
|
|
|
if (strcmp(key, setting->key) == 0)
|
|
{
|
|
return setting;
|
|
}
|
|
|
|
if (setting->type == SETTING_EMPTY)
|
|
{
|
|
strncpy(setting->key, key, CONFIG_SYSTEM_SETTINGS_KEY_SIZE);
|
|
setting->key[CONFIG_SYSTEM_SETTINGS_KEY_SIZE - 1] = '\0';
|
|
return setting;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: load_text
|
|
*
|
|
* Description:
|
|
* Loads text from a storage file.
|
|
*
|
|
* Input Parameters:
|
|
* file - the filename of the storage to use
|
|
*
|
|
* Returned Value:
|
|
* Success or negated failure code
|
|
*
|
|
****************************************************************************/
|
|
|
|
int load_text(FAR char *file)
|
|
{
|
|
int ret = OK;
|
|
FAR FILE *f;
|
|
FAR char *eq;
|
|
FAR char *key;
|
|
FAR char *val;
|
|
FAR char *backup_file;
|
|
FAR char *buffer;
|
|
FAR setting_t *setting;
|
|
|
|
/* Check that the file exists */
|
|
|
|
if (access(file, F_OK) != 0)
|
|
{
|
|
/* If not, try the backup file */
|
|
|
|
backup_file = malloc(strlen(file) + 2);
|
|
if (backup_file == NULL)
|
|
{
|
|
return -ENODEV;
|
|
}
|
|
|
|
strcpy(backup_file, file);
|
|
strcat(backup_file, "~");
|
|
|
|
if (access(backup_file, F_OK) == 0)
|
|
{
|
|
/* There is a backup file
|
|
* Restore this as the new settings file
|
|
*/
|
|
|
|
rename(backup_file, file);
|
|
}
|
|
|
|
free(backup_file);
|
|
}
|
|
|
|
f = fopen(file, "r");
|
|
if (f == NULL)
|
|
{
|
|
return -ENOENT;
|
|
}
|
|
|
|
buffer = malloc(BUFFER_SIZE);
|
|
if (buffer == NULL)
|
|
{
|
|
ret = -ENOMEM;
|
|
goto abort;
|
|
}
|
|
|
|
while (fgets(buffer, BUFFER_SIZE, f))
|
|
{
|
|
int i;
|
|
|
|
/* Remove any line terminators */
|
|
|
|
for (i = ((int)strlen(buffer) - 1); i > 0; i--)
|
|
{
|
|
if (buffer[i] == ';' || buffer[i] == '\n' || buffer[i] == '\r')
|
|
{
|
|
buffer[i] = '\0';
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Separate the key / value pair */
|
|
|
|
eq = strchr(buffer, '=');
|
|
if (eq == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
key = buffer;
|
|
val = eq + 1;
|
|
*eq = '\0';
|
|
|
|
/* Check if the key is valid */
|
|
|
|
if (!isalpha(key[0]))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* Get the setting slot */
|
|
|
|
setting = getsetting(key);
|
|
if (setting == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* Parse the value */
|
|
|
|
if (isalpha(val[0]))
|
|
{
|
|
if (strcasecmp(val, "true") == 0)
|
|
{
|
|
/* It's a boolean */
|
|
|
|
setting->type = SETTING_BOOL;
|
|
setting->val.i = 1;
|
|
}
|
|
else if (strcasecmp(val, "false") == 0)
|
|
{
|
|
/* It's a boolean */
|
|
|
|
setting->type = SETTING_BOOL;
|
|
setting->val.i = 0;
|
|
}
|
|
else
|
|
{
|
|
/* It's a string */
|
|
|
|
if (strlen(val) >= CONFIG_SYSTEM_SETTINGS_VALUE_SIZE)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
setting->type = SETTING_STRING;
|
|
strncpy(setting->val.s, val,
|
|
CONFIG_SYSTEM_SETTINGS_VALUE_SIZE);
|
|
setting->val.s[CONFIG_SYSTEM_SETTINGS_VALUE_SIZE - 1] = '\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strchr(val, '.') != NULL)
|
|
{
|
|
FAR char *s = val;
|
|
i = 0;
|
|
while (s[i]) s[i] == '.' ? i++ : *s++;
|
|
if (i == 1)
|
|
{
|
|
/* It's a float */
|
|
|
|
double d = 0;
|
|
if (sscanf(val, "%lf", &d) == 1)
|
|
{
|
|
setting->type = SETTING_FLOAT;
|
|
setting->val.f = d;
|
|
}
|
|
}
|
|
else if (i == 3)
|
|
{
|
|
/* It's an IP address */
|
|
|
|
setting->type = SETTING_IP_ADDR;
|
|
inet_pton(AF_INET, val, &setting->val.ip);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* It's an integer */
|
|
|
|
i = 0;
|
|
if (sscanf(val, "%d", &i) == 1)
|
|
{
|
|
setting->type = SETTING_INT;
|
|
setting->val.i = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Handle parse errors */
|
|
|
|
if (setting->type == SETTING_EMPTY)
|
|
{
|
|
memset(setting->key, 0, CONFIG_SYSTEM_SETTINGS_KEY_SIZE);
|
|
}
|
|
}
|
|
|
|
free(buffer);
|
|
|
|
abort:
|
|
fclose(f);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: save_text
|
|
*
|
|
* Description:
|
|
* Saves text to a storage file.
|
|
*
|
|
* Input Parameters:
|
|
* file - the filename of the storage to use
|
|
*
|
|
* Returned Value:
|
|
* Success or negated failure code
|
|
*
|
|
****************************************************************************/
|
|
|
|
int save_text(FAR char *file)
|
|
{
|
|
int ret = OK;
|
|
FAR char *backup_file = malloc(strlen(file) + 2);
|
|
FAR FILE *f;
|
|
int i;
|
|
|
|
if (backup_file == NULL)
|
|
{
|
|
return -ENODEV;
|
|
}
|
|
|
|
strcpy(backup_file, file);
|
|
strcat(backup_file, "~");
|
|
|
|
f = fopen(backup_file, "w");
|
|
if (f == NULL)
|
|
{
|
|
ret = -ENODEV;
|
|
goto abort;
|
|
}
|
|
|
|
for (i = 0; i < CONFIG_SYSTEM_SETTINGS_MAP_SIZE; i++)
|
|
{
|
|
if (map[i].type == SETTING_EMPTY)
|
|
{
|
|
break;
|
|
}
|
|
|
|
switch (map[i].type)
|
|
{
|
|
case SETTING_STRING:
|
|
{
|
|
fprintf(f, "%s=%s\n", map[i].key,
|
|
map[i].val.s);
|
|
}
|
|
break;
|
|
|
|
case SETTING_INT:
|
|
{
|
|
fprintf(f, "%s=%d\n", map[i].key,
|
|
map[i].val.i);
|
|
}
|
|
break;
|
|
case SETTING_BOOL:
|
|
{
|
|
fprintf(f, "%s=%s\n", map[i].key,
|
|
map[i].val.i ?
|
|
"true" : "false");
|
|
}
|
|
break;
|
|
|
|
case SETTING_FLOAT:
|
|
{
|
|
fprintf(f, "%s=%.06f\n", map[i].key,
|
|
map[i].val.f);
|
|
}
|
|
break;
|
|
|
|
case SETTING_IP_ADDR:
|
|
{
|
|
char buffer[20];
|
|
inet_ntop(AF_INET, &map[i].val.ip, buffer, 20);
|
|
fprintf(f, "%s=%s\n", map[i].key, buffer);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
remove(file);
|
|
rename(backup_file, file);
|
|
|
|
abort:
|
|
free(backup_file);
|
|
|
|
return ret;
|
|
}
|