Commit fcf18f52 authored by Daniel Graziotin's avatar Daniel Graziotin

Cleanup, reformatting, better Makefile and better README

parent 90e6378a
......@@ -3,7 +3,7 @@ MAINTAINERS AND CONTRIBUTORS
Daniel Graziotin <dgraziotin AT task3 DOT cc>
Ismail Khatib <ikhatib AT gmail DOT com>
Trevor Joynson
ORIGINARY AUTHORS
-----------------
......
......@@ -54,37 +54,24 @@ all: $(OBJS)
clean:
rm -rf $(SOURCE_PATH)*.$(OBJ) $(EXE)
tests:
make install
sudo /usr/sbin/mbpfan -f -v -t
install:
make
cp $(EXE) /usr/sbin
cp -n $(CONF) /etc
@echo "-----------------------------------------------------------------------------"
@echo "An init file suitable for /lib/lsb/init-functions (Debian & Ubuntu for sure)"
@echo "is located in the main folder of the source files, called mbpfan.init.debian"
@echo "Rename it to mbpfan, give it execution permissions (chmod +x mbpfan)"
@echo "and move it to /etc/init.d"
@echo "Then, add it to the default runlevels with sudo update-rc.d mbpfan defaults"
@echo ""
@echo "Additionally, an init file suitable for /etc/rc.d/init.d/functions"
@echo "(RHEL/CentOS & Fedora) is also located at the same place, this file is called"
@echo "mbpfan.init.redhat. Also rename it to mbpfan, give it execution permissions"
@echo "and move it to /etc/init.d"
@echo "To add the script to the default runlevels, run the following as root:"
@echo "chkconfig --level 2345 mbpfan on && chkconfig --level 016 mbpfan off"
@echo "******************"
@echo "INSTALL COMPLETED"
@echo "******************"
@echo ""
@echo "A configuration file has been copied to /etc/mbpfan.conf"
@echo "See README.md file to have mbpfan automatically started at system boot."
@echo ""
@echo "Please run the tests now with the command"
@echo " sudo make tests"
@echo ""
@echo "For upstart based init systems (Ubuntu), an example upstart job has been"
@echo "provided for use in place of the LSB-style init script. To use, execute"
@echo "as root:"
@echo "cp mbpfan.upstart /etc/init/mbpfan.conf"
@echo "start mbpfan"
@echo "As a special bonus, a service file for systemd is also included. To use it,"
@echo "execute the following as root:"
@echo "cp mbpfan.service /usr/lib/systemd/system"
@echo "ln -s /usr/lib/systemd/system/mbpfan.service /etc/systemd/system/mbpfan.service"
@echo "systemctl daemon-reload"
@echo "systemctl start mbpfan.service"
@echo "To start the service automatically at boot, also execute the following:"
@echo "systemctl enable mbpfan.service"
@echo "-----------------------------------------------------------------------------"
rebuild: clean all
#rebuild is not entirely correct
......@@ -3,7 +3,6 @@ Fan-Control-Daemon
Introduction
---------------------
This is an enhanced version of [rvega's Fan-Control-Daemon](https://github.com/rvega/Fan-Control-Daemon),
which itself is an enhanced version of [Allan McRae mbpfan](http://allanmcrae.com/2010/05/simple-macbook-pro-fan-daemon/)
......@@ -15,43 +14,36 @@ This enhanced version assumes any number of processors and fans (max. 10).
* It requires root use
* It daemonizes or stays in foreground
* Verbose mode for both syslog and stdout
* Users can configure it using the file /etc/mbpfan.conf
Compile Instructions
---------------------
Compile with
make
Manually compile with
gcc -o bin/mbpfan src/mbpfan.c -lm
Run The Tests (Recommended)
---------------------------
It is recommended to run the tests before installing the program
sudo ./bin/mbpfan -t
Install Instructions
--------------------
Install with
sudo make install
It actually copies mbpfan to /usr/sbin.
It copies mbpfan to /usr/sbin and mbpfan.conf to /etc
An init file suitable for /lib/lsb/init-functions (Debian & Ubuntu fur sure)
is located in the main folder of the source files. It is called mbpfan.init.debian
Rename it to mbpfan, give it execution permissions (chmod +x mbpfan)
and move it to /etc/init.d
Then, add it to the default runlevels with sudo update-rc.d mbpfan defaults (Ubuntu example)
An init file suitable for Fedora (and probably RedHat) can be found
in the file mbpfan.init.fedora
Run The Tests (Recommended)
---------------------------
It is recommended to run the tests after installing the program
sudo ./bin/mbpfan -t
or
sudo make tests
Run Instructions
---------------------
----------------
If not installed, run with
sudo bin/mbpfan
......@@ -61,9 +53,39 @@ sudo mbpfan
If installed and using the init file, run with (Ubuntu example)
sudo service mbpfan start
Starting at boot
----------------
An init file suitable for /lib/lsb/init-functions (Debian & Ubuntu for sure)
is located in the main folder of the source files, called mbpfan.init.debian
Rename it to mbpfan, give it execution permissions (chmod +x mbpfan)
and move it to /etc/init.d
Then, add it to the default runlevels with sudo update-rc.d mbpfan defaults
Additionally, an init file suitable for /etc/rc.d/init.d/functions
(RHEL/CentOS & Fedora) is also located at the same place, this file is called
mbpfan.init.redhat. Also rename it to mbpfan, give it execution permissions
and move it to /etc/init.d
To add the script to the default runlevels, run the following as root:
chkconfig --level 2345 mbpfan on && chkconfig --level 016 mbpfan off
For upstart based init systems (Ubuntu), an example upstart job has been
provided for use in place of the LSB-style init script. To use, execute
as root:
cp mbpfan.upstart /etc/init/mbpfan.conf
start mbpfan
As a special bonus, a service file for systemd is also included. To use it,
execute the following as root:
cp mbpfan.service /usr/lib/systemd/system
ln -s /usr/lib/systemd/system/mbpfan.service /etc/systemd/system/mbpfan.service
systemctl daemon-reload
systemctl start mbpfan.service
To start the service automatically at boot, also execute the following:
systemctl enable mbpfan.service
Usage
-------
Usage: ./mbpfan OPTION(S)
-h Show the help screen
-f Run in foreground
......@@ -78,7 +100,6 @@ GNU General Public License version 3
Based On
---------------------
* http://allanmcrae.com/2010/05/simple-macbook-pro-fan-daemon/
* http://allanmcrae.com/2011/08/mbp-fan-daemon-update/
* https://launchpad.net/macfanctld
......
......@@ -32,175 +32,151 @@
int write_pid(int pid)
{
FILE *file = NULL;
file = fopen(program_pid, "w");
if(file != NULL)
{
fprintf(file, "%d", pid);
fclose(file);
return 1;
}
else
{
return 0;
FILE *file = NULL;
file = fopen(program_pid, "w");
if(file != NULL) {
fprintf(file, "%d", pid);
fclose(file);
return 1;
} else {
return 0;
}
}
int read_pid()
{
FILE *file = NULL;
int pid = -1;
file = fopen(program_pid, "r");
if(file != NULL)
{
fscanf(file, "%d", &pid);
fclose(file);
return pid;
FILE *file = NULL;
int pid = -1;
file = fopen(program_pid, "r");
if(file != NULL) {
fscanf(file, "%d", &pid);
fclose(file);
return pid;
}
return -1;
return -1;
}
int delete_pid()
{
return remove(program_pid);
return remove(program_pid);
}
void signal_handler(int signal)
{
switch(signal)
{
switch(signal) {
case SIGHUP:
//TODO: restart myself
syslog(LOG_WARNING, "Received SIGHUP signal.");
delete_pid();
exit(0);
break;
//TODO: restart myself
syslog(LOG_WARNING, "Received SIGHUP signal.");
delete_pid();
exit(0);
break;
case SIGTERM:
syslog(LOG_WARNING, "Received SIGTERM signal.");
delete_pid();
//TODO: free resources
exit(0);
break;
syslog(LOG_WARNING, "Received SIGTERM signal.");
delete_pid();
//TODO: free resources
exit(0);
break;
case SIGINT:
syslog(LOG_WARNING, "Received SIGINT signal.");
delete_pid();
//TODO: free resources
exit(0);
syslog(LOG_WARNING, "Received SIGINT signal.");
delete_pid();
//TODO: free resources
exit(0);
default:
syslog(LOG_WARNING, "Unhandled signal (%d) %s", signal, strsignal(signal));
break;
syslog(LOG_WARNING, "Unhandled signal (%d) %s", signal, strsignal(signal));
break;
}
}
void go_daemon(void (*fan_control)())
{
// Setup signal handling before we start
signal(SIGHUP, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
// Setup signal handling before we start
signal(SIGHUP, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
syslog(LOG_INFO, "%s starting up", program_name);
syslog(LOG_INFO, "%s starting up", program_name);
// Setup syslog logging - see SETLOGMASK(3)
if(verbose)
{
setlogmask(LOG_UPTO(LOG_DEBUG));
openlog(program_name, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
}
else
{
setlogmask(LOG_UPTO(LOG_INFO));
openlog(program_name, LOG_CONS, LOG_USER);
// Setup syslog logging - see SETLOGMASK(3)
if(verbose) {
setlogmask(LOG_UPTO(LOG_DEBUG));
openlog(program_name, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
} else {
setlogmask(LOG_UPTO(LOG_INFO));
openlog(program_name, LOG_CONS, LOG_USER);
}
pid_t pid_slave;
pid_t sid_slave;
pid_t pid_slave;
pid_t sid_slave;
if (daemonize)
{
if (daemonize) {
pid_slave = fork();
if (pid_slave < 0)
{
exit(EXIT_FAILURE);
pid_slave = fork();
if (pid_slave < 0) {
exit(EXIT_FAILURE);
}
if (pid_slave > 0)
{
// kill the father
exit(EXIT_SUCCESS);
if (pid_slave > 0) {
// kill the father
exit(EXIT_SUCCESS);
}
umask(0022);
umask(0022);
// new sid_slave for the child process
sid_slave = setsid();
if (sid_slave < 0)
{
exit(EXIT_FAILURE);
// new sid_slave for the child process
sid_slave = setsid();
if (sid_slave < 0) {
exit(EXIT_FAILURE);
}
if ((chdir("/")) < 0)
{
exit(EXIT_FAILURE);
if ((chdir("/")) < 0) {
exit(EXIT_FAILURE);
}
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
int current_pid = getpid();
int current_pid = getpid();
if (read_pid() == -1)
{
if (verbose)
{
printf("Writing a new .pid file with value %d at: %s\n", current_pid, program_pid);
syslog(LOG_INFO, "Writing a new .pid file with value %d at: %s", current_pid, program_pid);
if (read_pid() == -1) {
if (verbose) {
printf("Writing a new .pid file with value %d at: %s\n", current_pid, program_pid);
syslog(LOG_INFO, "Writing a new .pid file with value %d at: %s", current_pid, program_pid);
}
if (write_pid(current_pid) == 0)
{
syslog(LOG_ERR, "Can not create a .pid file at: %s. Aborting", program_pid);
if (verbose)
{
printf("ERROR: Can not create a .pid file at: %s. Aborting\n", program_pid);
if (write_pid(current_pid) == 0) {
syslog(LOG_ERR, "Can not create a .pid file at: %s. Aborting", program_pid);
if (verbose) {
printf("ERROR: Can not create a .pid file at: %s. Aborting\n", program_pid);
}
exit(EXIT_FAILURE);
}
else
{
if (verbose)
{
printf("Successfully written a new .pid file with value %d at: %s\n", current_pid, program_pid);
syslog(LOG_INFO, "Successfully written a new .pid file with value %d at: %s", current_pid, program_pid);
exit(EXIT_FAILURE);
} else {
if (verbose) {
printf("Successfully written a new .pid file with value %d at: %s\n", current_pid, program_pid);
syslog(LOG_INFO, "Successfully written a new .pid file with value %d at: %s", current_pid, program_pid);
}
}
}
else
{
syslog(LOG_ERR, "A previously created .pid file exists at: %s. Aborting", program_pid);
if (verbose)
{
printf("ERROR: a previously created .pid file exists at: %s.\n Aborting\n", program_pid);
} else {
syslog(LOG_ERR, "A previously created .pid file exists at: %s. Aborting", program_pid);
if (verbose) {
printf("ERROR: a previously created .pid file exists at: %s.\n Aborting\n", program_pid);
}
exit(EXIT_FAILURE);
exit(EXIT_FAILURE);
}
fan_control();
fan_control();
if(daemonize)
{
syslog(LOG_INFO, "%s daemon exiting", program_name);
if(daemonize) {
syslog(LOG_INFO, "%s daemon exiting", program_name);
}
return;
return;
}
......@@ -29,15 +29,14 @@ const char *program_pid = "/var/run/mbpfan.pid";
void print_usage(int argc, char *argv[])
{
if (argc >=1)
{
printf("Usage: %s OPTION(S) \n", argv[0]);
printf("Options:\n");
printf("\t-h Show this help screen\n");
printf("\t-f Run in foreground\n");
printf("\t-t Run the tests\n");
printf("\t-v Be (a lot) verbose\n");
printf("\n");
if (argc >=1) {
printf("Usage: %s OPTION(S) \n", argv[0]);
printf("Options:\n");
printf("\t-h Show this help screen\n");
printf("\t-f Run in foreground\n");
printf("\t-t Run the tests\n");
printf("\t-v Be (a lot) verbose\n");
printf("\n");
}
}
......@@ -46,34 +45,32 @@ void print_usage(int argc, char *argv[])
int main(int argc, char *argv[])
{
int c;
while( (c = getopt(argc, argv, "hftv|help")) != -1)
{
switch(c)
{
int c;
while( (c = getopt(argc, argv, "hftv|help")) != -1) {
switch(c) {
case 'h':
print_usage(argc, argv);
exit(0);
break;
print_usage(argc, argv);
exit(0);
break;
case 'f':
daemonize = 0;
break;
daemonize = 0;
break;
case 't':
tests();
exit(0);
break;
tests();
exit(0);
break;
case 'v':
verbose = 1;
break;
verbose = 1;
break;
default:
print_usage(argc, argv);
exit(0);
break;
print_usage(argc, argv);
exit(0);
break;
}
}
// pointer to mbpfan() function in mbpfan.c
void (*fan_control)() = mbpfan;
go_daemon(fan_control);
exit(0);
// pointer to mbpfan() function in mbpfan.c
void (*fan_control)() = mbpfan;
go_daemon(fan_control);
exit(0);
}
\ No newline at end of file
......@@ -58,348 +58,313 @@ int max_temp = 86; // do not set it > 90
int polling_interval = 7;
struct s_sensors
{
char* path;
char* fan_output_path;
char* fan_manual_path;
unsigned int temperature;
struct s_sensors *next;
struct s_sensors {
char* path;
char* fan_output_path;
char* fan_manual_path;
unsigned int temperature;
struct s_sensors *next;
};
t_sensors *retrieve_sensors()
{
t_sensors *sensors_head = NULL;
t_sensors *s = NULL;
char *path = NULL;
const char *path_begin = "/sys/devices/platform/coretemp.0/temp";
const char *path_end = "_input";
int path_size = strlen(path_begin) + strlen(path_end) + 2;
char number[1];
sprintf(number,"%d",0);
int i = 0;
for(i = 0; i<10; i++)
{
path = (char*) malloc(sizeof( char ) * path_size);
sprintf(number,"%d",i);
path[0] = '\0';
strncat( path, path_begin, strlen(path_begin) );
strncat( path, number, strlen(number) );
strncat( path, path_end, strlen(path_begin) );
FILE *file = fopen(path, "r");
if(file != NULL)
{
s = (t_sensors *) malloc( sizeof( t_sensors ) );
s->path = (char *) malloc(sizeof( char ) * path_size);
strcpy(s->path, path);
fscanf(file, "%d", &s->temperature);
if (sensors_head == NULL)
{
sensors_head = s;
sensors_head->next = NULL;
}
else
{
t_sensors *tmp = sensors_head;
while (tmp->next != NULL)
{
tmp = tmp->next;
t_sensors *sensors_head = NULL;
t_sensors *s = NULL;
char *path = NULL;
const char *path_begin = "/sys/devices/platform/coretemp.0/temp";
const char *path_end = "_input";
int path_size = strlen(path_begin) + strlen(path_end) + 2;
char number[1];
sprintf(number,"%d",0);
int i = 0;
for(i = 0; i<10; i++) {
path = (char*) malloc(sizeof( char ) * path_size);
sprintf(number,"%d",i);
path[0] = '\0';
strncat( path, path_begin, strlen(path_begin) );
strncat( path, number, strlen(number) );
strncat( path, path_end, strlen(path_begin) );
FILE *file = fopen(path, "r");
if(file != NULL) {
s = (t_sensors *) malloc( sizeof( t_sensors ) );
s->path = (char *) malloc(sizeof( char ) * path_size);
strcpy(s->path, path);
fscanf(file, "%d", &s->temperature);
if (sensors_head == NULL) {
sensors_head = s;
sensors_head->next = NULL;
} else {
t_sensors *tmp = sensors_head;
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = s;
tmp->next->next = NULL;
tmp->next = s;
tmp->next->next = NULL;
}
fclose(file);
fclose(file);
}
free(path);
path = NULL;
free(path);
path = NULL;
}
if(sensors_head != NULL)
find_fans(sensors_head);
return sensors_head;
if(sensors_head != NULL)
find_fans(sensors_head);
return sensors_head;
}
void find_fans(t_sensors* sensors)
{
t_sensors *tmp = sensors;
t_sensors *tmp = sensors;
char *path_output = NULL;
char *path_manual = NULL;
char *path_output = NULL;
char *path_manual = NULL;
const char *path_begin = "/sys/devices/platform/applesmc.768/fan";
const char *path_output_end = "_output";
const char *path_man_end = "_manual";
const char *path_begin = "/sys/devices/platform/applesmc.768/fan";
const char *path_output_end = "_output";
const char *path_man_end = "_manual";
int path_min_size = strlen(path_begin) + strlen(path_output_end) + 2;
int path_man_size = strlen(path_begin) + strlen(path_man_end) + 2;
char number[1];
sprintf(number,"%d",0);
int path_min_size = strlen(path_begin) + strlen(path_output_end) + 2;
int path_man_size = strlen(path_begin) + strlen(path_man_end) + 2;
char number[1];
sprintf(number,"%d",0);
int n_sensors = 0;
int n_fans = 0;
int n_sensors = 0;
int n_fans = 0;
for(n_sensors = 0; n_sensors<10; n_sensors++)
{
path_output = (char*) malloc(sizeof( char ) * path_min_size);
path_output[0] = '\0';
path_manual = (char*) malloc(sizeof( char ) * path_man_size);
path_manual[0] = '\0';
sprintf(number,"%d",n_sensors);
for(n_sensors = 0; n_sensors<10; n_sensors++) {
path_output = (char*) malloc(sizeof( char ) * path_min_size);
path_output[0] = '\0';
path_manual = (char*) malloc(sizeof( char ) * path_man_size);
path_manual[0] = '\0';
sprintf(number,"%d",n_sensors);
strncat( path_output, path_begin, strlen(path_begin) );
strncat( path_output, number, strlen(number) );
strncat( path_output, path_output_end, strlen(path_begin) );
strncat( path_output, path_begin, strlen(path_begin) );
strncat( path_output, number, strlen(number) );
strncat( path_output, path_output_end, strlen(path_begin) );
strncat( path_manual, path_begin, strlen(path_begin) );
strncat( path_manual, number, strlen(number) );
strncat( path_manual, path_man_end, strlen(path_begin) );
strncat( path_manual, path_begin, strlen(path_begin) );
strncat( path_manual, number, strlen(number) );
strncat( path_manual, path_man_end, strlen(path_begin) );
FILE *file = fopen(path_output, "r");
FILE *file = fopen(path_output, "r");
if(file != NULL)
{
if (tmp->path != NULL)
{
tmp->fan_output_path = (char *) malloc(sizeof( char ) * path_min_size);
tmp->fan_manual_path = (char *) malloc(sizeof( char ) * path_man_size);
if(file != NULL) {
if (tmp->path != NULL) {
tmp->fan_output_path = (char *) malloc(sizeof( char ) * path_min_size);
tmp->fan_manual_path = (char *) malloc(sizeof( char ) * path_man_size);
}
strcpy(tmp->fan_output_path, path_output);
strcpy(tmp->fan_manual_path, path_manual);
tmp = tmp->next;
n_fans++;
fclose(file);
strcpy(tmp->fan_output_path, path_output);
strcpy(tmp->fan_manual_path, path_manual);
tmp = tmp->next;
n_fans++;
fclose(file);
}
}
if(verbose)
{
printf("Found %d: sensors and %d fans\n", n_sensors, n_fans);
if(daemonize)
{
syslog(LOG_INFO, "Found %d: sensors and %d fans", n_sensors, n_fans);
if(verbose) {
printf("Found %d: sensors and %d fans\n", n_sensors, n_fans);
if(daemonize) {
syslog(LOG_INFO, "Found %d: sensors and %d fans", n_sensors, n_fans);
}
}
free(path_output);
path_output = NULL;
free(path_manual);
path_manual = NULL;
free(path_output);
path_output = NULL;
free(path_manual);
path_manual = NULL;
}
void set_fans_man(t_sensors *sensors)
{
t_sensors *tmp = sensors;
FILE *file;
while(tmp != NULL)
{
file = fopen(tmp->fan_manual_path, "rw+");
if(file != NULL)
{
fprintf(file, "%d", 1);
fclose(file);
t_sensors *tmp = sensors;
FILE *file;
while(tmp != NULL) {
file = fopen(tmp->fan_manual_path, "rw+");
if(file != NULL) {
fprintf(file, "%d", 1);
fclose(file);
}
tmp = tmp->next;
tmp = tmp->next;
}
}
t_sensors *refresh_sensors(t_sensors *sensors)
{
t_sensors *tmp = sensors;
t_sensors *tmp = sensors;
while(tmp != NULL)
{
FILE *file = fopen(tmp->path, "r");
while(tmp != NULL) {
FILE *file = fopen(tmp->path, "r");
if(file != NULL)
{
fscanf(file, "%d", &tmp->temperature);
fclose(file);
if(file != NULL) {
fscanf(file, "%d", &tmp->temperature);
fclose(file);
}
tmp = tmp->next;
tmp = tmp->next;
}
return sensors;
return sensors;
}
/* Controls the speed of the fan */
void set_fan_speed(t_sensors* sensors, int speed)
{
t_sensors *tmp = sensors;
FILE *file;
while(tmp != NULL)
{
file = fopen(tmp->fan_output_path, "rw+");
if(file != NULL)
{
fprintf(file, "%d", speed);
fclose(file);
t_sensors *tmp = sensors;
FILE *file;
while(tmp != NULL) {
file = fopen(tmp->fan_output_path, "rw+");
if(file != NULL) {
fprintf(file, "%d", speed);
fclose(file);
}
tmp = tmp->next;
tmp = tmp->next;
}
}
unsigned short get_temp(t_sensors* sensors)
{
sensors = refresh_sensors(sensors);
int sum_temp = 0;
unsigned short temp = 0;
t_sensors* tmp = sensors;
while(tmp != NULL)
{
sum_temp += tmp->temperature;
tmp = tmp->next;
sensors = refresh_sensors(sensors);
int sum_temp = 0;
unsigned short temp = 0;
t_sensors* tmp = sensors;
while(tmp != NULL) {
sum_temp += tmp->temperature;
tmp = tmp->next;
}
temp = (unsigned short)( ceil( (float)( sum_temp ) / 2000. ) );
return temp;
temp = (unsigned short)( ceil( (float)( sum_temp ) / 2000. ) );
return temp;
}
void mbpfan()
void retrieve_settings()
{
int old_temp, new_temp, fan_speed, steps;
int temp_change;
int step_up, step_down;
FILE *f = NULL;
Settings *settings = NULL;
int result = 0;
t_sensors* sensors = retrieve_sensors();
set_fans_man(sensors);
new_temp = get_temp(sensors);
fan_speed = 2000;
set_fan_speed(sensors, fan_speed);
f = fopen("/etc/mbpfan.conf", "r");
if (f == NULL)
{
/* Could not open configfile */
if(verbose)
{
printf("Couldn't open configfile, using defaults\n");
if(daemonize)
{
syslog(LOG_INFO, "Couldn't open configfile, using defaults");
Settings *settings = NULL;
int result = 0;
FILE *f = NULL;
f = fopen("/etc/mbpfan.conf", "r");
if (f == NULL) {
/* Could not open configfile */
if(verbose) {
printf("Couldn't open configfile, using defaults\n");
if(daemonize) {
syslog(LOG_INFO, "Couldn't open configfile, using defaults");
}
}
}
else
{
settings = settings_open(f);
fclose(f);
if (settings == NULL)
{
/* Could not read configfile */
if(verbose)
{
printf("Couldn't read configfile\n");
if(daemonize)
{
syslog(LOG_INFO, "Couldn't read configfile");
} else {
settings = settings_open(f);
fclose(f);
if (settings == NULL) {
/* Could not read configfile */
if(verbose) {
printf("Couldn't read configfile\n");
if(daemonize) {
syslog(LOG_INFO, "Couldn't read configfile");
}
}
}
else
{
/* Read configfile values */
result = settings_get_int(settings, "general", "min_fan_speed");
if (result != 0) min_fan_speed = result;
result = settings_get_int(settings, "general", "max_fan_speed");
if (result != 0) max_fan_speed = result;
result = settings_get_int(settings, "general", "low_temp");
if (result != 0) low_temp = result;
result = settings_get_int(settings, "general", "high_temp");
if (result != 0) high_temp = result;
result = settings_get_int(settings, "general", "max_temp");
if (result != 0) max_temp = result;
result = settings_get_int(settings, "general", "polling_interval");
if (result != 0) polling_interval = result;
/* Destroy the settings object */
settings_delete(settings);
} else {
/* Read configfile values */
result = settings_get_int(settings, "general", "min_fan_speed");
if (result != 0) min_fan_speed = result;
result = settings_get_int(settings, "general", "max_fan_speed");
if (result != 0) max_fan_speed = result;
result = settings_get_int(settings, "general", "low_temp");
if (result != 0) low_temp = result;
result = settings_get_int(settings, "general", "high_temp");
if (result != 0) high_temp = result;
result = settings_get_int(settings, "general", "max_temp");
if (result != 0) max_temp = result;
result = settings_get_int(settings, "general", "polling_interval");
if (result != 0) polling_interval = result;
/* Destroy the settings object */
settings_delete(settings);
}
}
}
void mbpfan()
{
int old_temp, new_temp, fan_speed, steps;
int temp_change;
int step_up, step_down;
retrieve_settings();
t_sensors* sensors = retrieve_sensors();
set_fans_man(sensors);
new_temp = get_temp(sensors);
fan_speed = 2000;
set_fan_speed(sensors, fan_speed);
if(verbose)
{
printf("Sleeping for %d seconds\n", polling_interval);
if(daemonize)
{
syslog(LOG_INFO, "Sleeping for %d seconds", polling_interval);
if(verbose) {
printf("Sleeping for %d seconds\n", polling_interval);
if(daemonize) {
syslog(LOG_INFO, "Sleeping for %d seconds", polling_interval);
}
}
sleep(polling_interval);
sleep(polling_interval);
step_up = (float)( max_fan_speed - min_fan_speed ) /
(float)( ( max_temp - high_temp ) * ( max_temp - high_temp + 1 ) / 2 );
step_up = (float)( max_fan_speed - min_fan_speed ) /
(float)( ( max_temp - high_temp ) * ( max_temp - high_temp + 1 ) / 2 );
step_down = (float)( max_fan_speed - min_fan_speed ) /
(float)( ( max_temp - low_temp ) * ( max_temp - low_temp + 1 ) / 2 );
step_down = (float)( max_fan_speed - min_fan_speed ) /
(float)( ( max_temp - low_temp ) * ( max_temp - low_temp + 1 ) / 2 );
while(1)
{
old_temp = new_temp;
new_temp = get_temp(sensors);
while(1) {
old_temp = new_temp;
new_temp = get_temp(sensors);
if(new_temp >= max_temp && fan_speed != max_fan_speed)
{
fan_speed = max_fan_speed;
if(new_temp >= max_temp && fan_speed != max_fan_speed) {
fan_speed = max_fan_speed;
}
if(new_temp <= low_temp && fan_speed != min_fan_speed)
{
fan_speed = min_fan_speed;
if(new_temp <= low_temp && fan_speed != min_fan_speed) {
fan_speed = min_fan_speed;
}
temp_change = new_temp - old_temp;
temp_change = new_temp - old_temp;
if(temp_change > 0 && new_temp > high_temp && new_temp < max_temp)
{
steps = ( new_temp - high_temp ) * ( new_temp - high_temp + 1 ) / 2;
fan_speed = max( fan_speed, ceil(min_fan_speed + steps * step_up) );
if(temp_change > 0 && new_temp > high_temp && new_temp < max_temp) {
steps = ( new_temp - high_temp ) * ( new_temp - high_temp + 1 ) / 2;
fan_speed = max( fan_speed, ceil(min_fan_speed + steps * step_up) );
}
if(temp_change < 0 && new_temp > low_temp && new_temp < max_temp)
{
steps = ( max_temp - new_temp ) * ( max_temp - new_temp + 1 ) / 2;
fan_speed = min( fan_speed, floor(max_fan_speed - steps * step_down) );
if(temp_change < 0 && new_temp > low_temp && new_temp < max_temp) {
steps = ( max_temp - new_temp ) * ( max_temp - new_temp + 1 ) / 2;
fan_speed = min( fan_speed, floor(max_fan_speed - steps * step_down) );
}
if(verbose)
{
printf("Old Temp %d: New Temp: %d, Fan Speed: %d\n", old_temp, new_temp, fan_speed);
if(daemonize)
{
syslog(LOG_INFO, "Old Temp %d: New Temp: %d, Fan Speed: %d", old_temp, new_temp, fan_speed);
if(verbose) {
printf("Old Temp %d: New Temp: %d, Fan Speed: %d\n", old_temp, new_temp, fan_speed);
if(daemonize) {
syslog(LOG_INFO, "Old Temp %d: New Temp: %d, Fan Speed: %d", old_temp, new_temp, fan_speed);
}
}
set_fan_speed(sensors, fan_speed);
set_fan_speed(sensors, fan_speed);
if(verbose)
{
printf("Sleeping for %d seconds\n", polling_interval);
if(daemonize)
{
syslog(LOG_INFO, "Sleeping for %d seconds", polling_interval);
if(verbose) {
printf("Sleeping for %d seconds\n", polling_interval);
if(daemonize) {
syslog(LOG_INFO, "Sleeping for %d seconds", polling_interval);
}
}
sleep(polling_interval);
sleep(polling_interval);
}
}
......@@ -37,6 +37,13 @@ extern int polling_interval;
struct s_sensors;
typedef struct s_sensors t_sensors;
/**
* Tries to use the settings located in
* /etc/mbpfan.conf
* If it fails, the default hardcoded settings are used
*/
void retrieve_settings();
/**
* Detect the sensors in /sys/devices/platform/coretemp.0/temp
* Return a linked list of t_sensors (first temperature detected)
......
......@@ -4,117 +4,139 @@
#include <time.h>
#include <limits.h>
#include "mbpfan.h"
#include "settings.h"
#include "minunit.h"
int tests_run = 0;
struct s_sensors
{
char* path;
char* fan_output_path;
char* fan_manual_path;
unsigned int temperature;
struct s_sensors *next;
struct s_sensors {
char* path;
char* fan_output_path;
char* fan_manual_path;
unsigned int temperature;
struct s_sensors *next;
};
typedef s_sensors t_sensors;
static char *test_sensor_paths()
{
t_sensors* sensors = retrieve_sensors();
mu_assert("No sensors found", sensors != NULL);
t_sensors* tmp = sensors;
while(tmp != NULL)
{
mu_assert("Sensor does not have a valid path", tmp->path != NULL);
if(tmp->path != NULL)
mu_assert("Sensor does not have valid temperature", tmp->temperature > 0);
tmp = tmp->next;
t_sensors* sensors = retrieve_sensors();
mu_assert("No sensors found", sensors != NULL);
t_sensors* tmp = sensors;
while(tmp != NULL) {
mu_assert("Sensor does not have a valid path", tmp->path != NULL);
if(tmp->path != NULL)
mu_assert("Sensor does not have valid temperature", tmp->temperature > 0);
tmp = tmp->next;
}
return 0;
return 0;
}
static char *test_fan_paths()
{
t_sensors* sensors = retrieve_sensors();
mu_assert("No sensors found", sensors != NULL);
t_sensors* tmp = sensors;
int found_fan_path = 0;
while(tmp != NULL)
{
if(tmp->fan_output_path != NULL)
found_fan_path++;
tmp = tmp->next;
t_sensors* sensors = retrieve_sensors();
mu_assert("No sensors found", sensors != NULL);
t_sensors* tmp = sensors;
int found_fan_path = 0;
while(tmp != NULL) {
if(tmp->fan_output_path != NULL)
found_fan_path++;
tmp = tmp->next;
}
mu_assert("No fans found", found_fan_path != 0);
return 0;
mu_assert("No fans found", found_fan_path != 0);
return 0;
}
unsigned time_seed()
{
time_t now = time ( 0 );
unsigned char *p = (unsigned char *)&now;
unsigned seed = 0;
size_t i;
for ( i = 0; i < sizeof now; i++ )
seed = seed * ( UCHAR_MAX + 2U ) + p[i];
return seed;
time_t now = time ( 0 );
unsigned char *p = (unsigned char *)&now;
unsigned seed = 0;
size_t i;
for ( i = 0; i < sizeof now; i++ )
seed = seed * ( UCHAR_MAX + 2U ) + p[i];
return seed;
}
// nothing better than a horrible piece of code to
// stress a little bit the CPU
int stress(int n)
{
int f = n;
while (f > 0)
{
while(n > 0)
{
srand ( time_seed() );
n--;
int f = n;
while (f > 0) {
while(n > 0) {
srand ( time_seed() );
n--;
}
f--;
n = f;
f--;
n = f;
}
}
static char *test_get_temp()
{
t_sensors* sensors = retrieve_sensors();
mu_assert("No sensors found", sensors != NULL);
unsigned short temp_1 = get_temp(sensors);
mu_assert("Invalid Global Temperature Found", temp_1 > 1 && temp_1 < 150);
stress(2000);
unsigned short temp_2 = get_temp(sensors);
mu_assert("Invalid Higher temp test (if fan was already spinning high, this is not worrying)", temp_1 < temp_2);
return 0;
t_sensors* sensors = retrieve_sensors();
mu_assert("No sensors found", sensors != NULL);
unsigned short temp_1 = get_temp(sensors);
mu_assert("Invalid Global Temperature Found", temp_1 > 1 && temp_1 < 150);
stress(2000);
unsigned short temp_2 = get_temp(sensors);
mu_assert("Invalid Higher temp test (if fan was already spinning high, this is not worrying)", temp_1 < temp_2);
return 0;
}
static char *test_config_file()
{
FILE *f = NULL;
Settings *settings = NULL;
f = fopen("/etc/mbpfan.conf", "r");
mu_assert("No config file found", f != NULL);
if (f == NULL)
return 0;
settings = settings_open(f);
fclose(f);
mu_assert("Could not read settings from config file", settings != NULL);
if (settings == NULL)
return 0;
mu_assert("Could not read min_fan_speed from config file",settings_get_int(settings, "general", "min_fan_speed") != 0);
mu_assert("Could not read max_fan_speed from config file",settings_get_int(settings, "general", "max_fan_speed") != 0);
mu_assert("Could not read low_temp from config file",settings_get_int(settings, "general", "low_temp") != 0);
mu_assert("Could not read high_temp from config file",settings_get_int(settings, "general", "high_temp") != 0);
mu_assert("Could not read max_temp from config file",settings_get_int(settings, "general", "max_temp") != 0);
mu_assert("Could not read polling_interval from config file",settings_get_int(settings, "general", "polling_interval") != 0);
/* Destroy the settings object */
settings_delete(settings);
return 0;
}
static char *all_tests()
{
mu_run_test(test_sensor_paths);
mu_run_test(test_fan_paths);
mu_run_test(test_get_temp);
return 0;
mu_run_test(test_sensor_paths);
mu_run_test(test_fan_paths);
mu_run_test(test_get_temp);
mu_run_test(test_config_file);
return 0;
}
int tests()
{
printf("Starting the tests..\n");
printf("It is normal for them to take a bit to finish.\n");
char *result = all_tests();
if (result != 0)
{
printf("%s \n", result);
}
else
{
printf("ALL TESTS PASSED\n");
printf("Starting the tests..\n");
printf("It is normal for them to take a bit to finish.\n");
char *result = all_tests();
if (result != 0) {
printf("%s \n", result);
} else {
printf("ALL TESTS PASSED\n");
}
printf("Tests run: %d\n", tests_run);
printf("Tests run: %d\n", tests_run);
return result != 0;
return result != 0;
}
\ No newline at end of file
......@@ -10,6 +10,7 @@ extern int tests_run;
static char *test_sensor_paths();
static char *test_fan_paths();
static char *test_get_temp();
static char *test_config_file();
static char *all_tests();
......
......@@ -13,7 +13,7 @@
*
* Copyright (c) 2009-2011 Per Ola Kristensson.
*
* Per Ola Kristensson <pok21@cam.ac.uk>
* Per Ola Kristensson <pok21@cam.ac.uk>
* Inference Group, Department of Physics
* University of Cambridge
* Cavendish Laboratory
......@@ -52,25 +52,25 @@ typedef struct Section Section;
typedef struct ParseState ParseState;
struct Settings {
Section *sections;
unsigned int section_count;
Section *sections;
unsigned int section_count;
};
struct Section {
char *name;
StrMap *map;
char *name;
StrMap *map;
};
struct ParseState {
char *current_section;
unsigned int current_section_n;
int has_section;
char *current_section;
unsigned int current_section_n;
int has_section;
};
enum ConvertMode {
CONVERT_MODE_INT,
CONVERT_MODE_LONG,
CONVERT_MODE_DOUBLE,
CONVERT_MODE_INT,
CONVERT_MODE_LONG,
CONVERT_MODE_DOUBLE,
};
typedef enum ConvertMode ConvertMode;
......@@ -94,216 +94,216 @@ static void enum_map(const char *key, const char *value, const void *obj);
Settings * settings_new()
{
Settings *settings;
settings = (Settings*)malloc(sizeof(Settings));
if (settings == NULL) {
return NULL;
}
settings->section_count = 0;
settings->sections = NULL;
return settings;
Settings *settings;
settings = (Settings*)malloc(sizeof(Settings));
if (settings == NULL) {
return NULL;
}
settings->section_count = 0;
settings->sections = NULL;
return settings;
}
void settings_delete(Settings *settings)
{
unsigned int i, n;
Section *section;
if (settings == NULL) {
return;
}
section = settings->sections;
n = settings->section_count;
i = 0;
while (i < n) {
sm_delete(section->map);
if (section->name != NULL) {
free(section->name);
}
section++;
i++;
}
free(settings->sections);
free(settings);
unsigned int i, n;
Section *section;
if (settings == NULL) {
return;
}
section = settings->sections;
n = settings->section_count;
i = 0;
while (i < n) {
sm_delete(section->map);
if (section->name != NULL) {
free(section->name);
}
section++;
i++;
}
free(settings->sections);
free(settings);
}
Settings * settings_open(FILE *stream)
{
Settings *settings;
char buf[MAX_LINECHARS];
char trimmed_buf[MAX_LINECHARS];
char section_buf[MAX_LINECHARS];
ParseState parse_state;
if (stream == NULL) {
return NULL;
}
settings = settings_new();
if (settings == NULL) {
return NULL;
}
parse_state.current_section = section_buf;
parse_state.current_section_n = sizeof(section_buf);
parse_state.has_section = 0;
trim_str("", trimmed_buf);
while (fgets(buf, MAX_LINECHARS, stream) != NULL) {
trim_str(buf, trimmed_buf);
if (!parse_str(settings, trimmed_buf, &parse_state)) {
return NULL;
}
}
return settings;
Settings *settings;
char buf[MAX_LINECHARS];
char trimmed_buf[MAX_LINECHARS];
char section_buf[MAX_LINECHARS];
ParseState parse_state;
if (stream == NULL) {
return NULL;
}
settings = settings_new();
if (settings == NULL) {
return NULL;
}
parse_state.current_section = section_buf;
parse_state.current_section_n = sizeof(section_buf);
parse_state.has_section = 0;
trim_str("", trimmed_buf);
while (fgets(buf, MAX_LINECHARS, stream) != NULL) {
trim_str(buf, trimmed_buf);
if (!parse_str(settings, trimmed_buf, &parse_state)) {
return NULL;
}
}
return settings;
}
int settings_save(const Settings *settings, FILE *stream)
{
unsigned int i, n;
Section *section;
char buf[MAX_LINECHARS];
if (settings == NULL) {
return 0;
}
if (stream == NULL) {
return 0;
}
section = settings->sections;
n = settings->section_count;
i = 0;
while (i < n) {
sprintf(buf, "[%s]\n", section->name);
fputs(buf, stream);
sm_enum(section->map, enum_map, stream);
section++;
i++;
fputs("\n", stream);
}
return 0;
unsigned int i, n;
Section *section;
char buf[MAX_LINECHARS];
if (settings == NULL) {
return 0;
}
if (stream == NULL) {
return 0;
}
section = settings->sections;
n = settings->section_count;
i = 0;
while (i < n) {
sprintf(buf, "[%s]\n", section->name);
fputs(buf, stream);
sm_enum(section->map, enum_map, stream);
section++;
i++;
fputs("\n", stream);
}
return 0;
}
int settings_get(const Settings *settings, const char *section, const char *key, char *out_buf, unsigned int n_out_buf)
{
Section *s;
if (settings == NULL) {
return 0;
}
s = get_section(settings->sections, settings->section_count, section);
if (s == NULL) {
return 0;
}
return sm_get(s->map, key, out_buf, n_out_buf);
Section *s;
if (settings == NULL) {
return 0;
}
s = get_section(settings->sections, settings->section_count, section);
if (s == NULL) {
return 0;
}
return sm_get(s->map, key, out_buf, n_out_buf);
}
int settings_get_int(const Settings *settings, const char *section, const char *key)
{
int i;
int i;
if (get_converted_value(settings, section, key, CONVERT_MODE_INT, &i)) {
return i;
}
return 0;
if (get_converted_value(settings, section, key, CONVERT_MODE_INT, &i)) {
return i;
}
return 0;
}
long settings_get_long(const Settings *settings, const char *section, const char *key)
{
long l;
long l;
if (get_converted_value(settings, section, key, CONVERT_MODE_LONG, &l)) {
return l;
}
return 0;
if (get_converted_value(settings, section, key, CONVERT_MODE_LONG, &l)) {
return l;
}
return 0;
}
double settings_get_double(const Settings *settings, const char *section, const char *key)
{
double d;
double d;
if (get_converted_value(settings, section, key, CONVERT_MODE_DOUBLE, &d)) {
return d;
}
return 0;
if (get_converted_value(settings, section, key, CONVERT_MODE_DOUBLE, &d)) {
return d;
}
return 0;
}
int settings_get_int_tuple(const Settings *settings, const char *section, const char *key, int *out, unsigned int n_out)
{
return get_converted_tuple(settings, section, key, ',', CONVERT_MODE_INT, out, n_out);
return get_converted_tuple(settings, section, key, ',', CONVERT_MODE_INT, out, n_out);
}
long settings_get_long_tuple(const Settings *settings, const char *section, const char *key, long *out, unsigned int n_out)
{
return get_converted_tuple(settings, section, key, ',', CONVERT_MODE_LONG, out, n_out);
return get_converted_tuple(settings, section, key, ',', CONVERT_MODE_LONG, out, n_out);
}
double settings_get_double_tuple(const Settings *settings, const char *section, const char *key, double *out, unsigned int n_out)
{
return get_converted_tuple(settings, section, key, ',', CONVERT_MODE_DOUBLE, out, n_out);
return get_converted_tuple(settings, section, key, ',', CONVERT_MODE_DOUBLE, out, n_out);
}
int settings_set(Settings *settings, const char *section, const char *key, const char *value)
{
Section *s;
if (settings == NULL) {
return 0;
}
if (section == NULL || key == NULL || value == NULL) {
return 0;
}
if (strlen(section) == 0) {
return 0;
}
/* Get a pointer to the section */
s = get_section(settings->sections, settings->section_count, section);
if (s == NULL) {
/* The section is not created---create it */
s = (Section*)realloc(settings->sections, (settings->section_count + 1) * sizeof(Section));
if (s == NULL) {
return 0;
}
settings->sections = s;
settings->section_count++;
s = &(settings->sections[settings->section_count - 1]);
s->map = sm_new(DEFAULT_STRMAP_CAPACITY);
if (s->map == NULL) {
free(s);
return 0;
}
s->name = (char*)malloc((strlen(section) + 1) * sizeof(char));
if (s->name == NULL) {
sm_delete(s->map);
free(s);
return 0;
}
strcpy(s->name, section);
}
return sm_put(s->map, key, value);
Section *s;
if (settings == NULL) {
return 0;
}
if (section == NULL || key == NULL || value == NULL) {
return 0;
}
if (strlen(section) == 0) {
return 0;
}
/* Get a pointer to the section */
s = get_section(settings->sections, settings->section_count, section);
if (s == NULL) {
/* The section is not created---create it */
s = (Section*)realloc(settings->sections, (settings->section_count + 1) * sizeof(Section));
if (s == NULL) {
return 0;
}
settings->sections = s;
settings->section_count++;
s = &(settings->sections[settings->section_count - 1]);
s->map = sm_new(DEFAULT_STRMAP_CAPACITY);
if (s->map == NULL) {
free(s);
return 0;
}
s->name = (char*)malloc((strlen(section) + 1) * sizeof(char));
if (s->name == NULL) {
sm_delete(s->map);
free(s);
return 0;
}
strcpy(s->name, section);
}
return sm_put(s->map, key, value);
}
int settings_section_get_count(const Settings *settings, const char *section)
{
Section *sect;
if (settings == NULL) {
return 0;
}
sect = get_section(settings->sections, settings->section_count, section);
if (sect == NULL) {
return 0;
}
return sm_get_count(sect->map);
Section *sect;
if (settings == NULL) {
return 0;
}
sect = get_section(settings->sections, settings->section_count, section);
if (sect == NULL) {
return 0;
}
return sm_get_count(sect->map);
}
int settings_section_enum(const Settings *settings, const char *section, settings_section_enum_func enum_func, const void *obj)
{
Section *sect;
Section *sect;
sect = get_section(settings->sections, settings->section_count, section);
if (sect == NULL) {
return 0;
}
return sm_enum(sect->map, enum_func, obj);
sect = get_section(settings->sections, settings->section_count, section);
if (sect == NULL) {
return 0;
}
return sm_enum(sect->map, enum_func, obj);
}
/* Copies a trimmed variant without leading and trailing blank characters
......@@ -312,27 +312,27 @@ int settings_section_enum(const Settings *settings, const char *section, setting
*/
static void trim_str(const char *str, char *out_buf)
{
unsigned int len;
const char *s0;
while (*str != '\0' && is_blank_char(*str)) {
str++;
}
s0 = str;
len = 0;
while (*str != '\0') {
len++;
str++;
}
if (len > 0) {
str--;
}
while (is_blank_char(*str)) {
str--;
len--;
}
memcpy(out_buf, s0, len);
out_buf[len] = '\0';
unsigned int len;
const char *s0;
while (*str != '\0' && is_blank_char(*str)) {
str++;
}
s0 = str;
len = 0;
while (*str != '\0') {
len++;
str++;
}
if (len > 0) {
str--;
}
while (is_blank_char(*str)) {
str--;
len--;
}
memcpy(out_buf, s0, len);
out_buf[len] = '\0';
}
/* Parses a single input string and updates the provided settings object.
......@@ -348,55 +348,49 @@ static void trim_str(const char *str, char *out_buf)
*/
static int parse_str(Settings *settings, char *str, ParseState *parse_state)
{
char buf[MAX_LINECHARS];
char buf1[MAX_LINECHARS];
char buf2[MAX_LINECHARS];
int result;
if (*str == '\0') {
return 1;
}
else if (is_blank_str(str)) {
return 1;
}
else if (is_comment_str(str)) {
return 1;
}
else if (is_section_str(str)) {
result = get_section_from_str(str, buf, sizeof(buf));
if (!result) {
return 0;
}
if (strlen(buf) + 1 > parse_state->current_section_n) {
return 0;
}
strcpy(parse_state->current_section, buf);
parse_state->has_section = 1;
return 1;
}
else if (is_key_value_str(str)) {
result = get_key_value_from_str(str, buf1, sizeof(buf1), buf2, sizeof(buf2));
if (!result) {
return 0;
}
if (!parse_state->has_section) {
return 0;
}
return settings_set(settings, parse_state->current_section, buf1, buf2);
}
else if (is_key_without_value_str(str)) {
result = get_key_without_value_from_str(str, buf, sizeof(buf));
if (!result) {
return 0;
}
if (!parse_state->has_section) {
return 0;
}
return settings_set(settings, parse_state->current_section, buf, "");
}
else {
return 0;
}
char buf[MAX_LINECHARS];
char buf1[MAX_LINECHARS];
char buf2[MAX_LINECHARS];
int result;
if (*str == '\0') {
return 1;
} else if (is_blank_str(str)) {
return 1;
} else if (is_comment_str(str)) {
return 1;
} else if (is_section_str(str)) {
result = get_section_from_str(str, buf, sizeof(buf));
if (!result) {
return 0;
}
if (strlen(buf) + 1 > parse_state->current_section_n) {
return 0;
}
strcpy(parse_state->current_section, buf);
parse_state->has_section = 1;
return 1;
} else if (is_key_value_str(str)) {
result = get_key_value_from_str(str, buf1, sizeof(buf1), buf2, sizeof(buf2));
if (!result) {
return 0;
}
if (!parse_state->has_section) {
return 0;
}
return settings_set(settings, parse_state->current_section, buf1, buf2);
} else if (is_key_without_value_str(str)) {
result = get_key_without_value_from_str(str, buf, sizeof(buf));
if (!result) {
return 0;
}
if (!parse_state->has_section) {
return 0;
}
return settings_set(settings, parse_state->current_section, buf, "");
} else {
return 0;
}
}
/* Returns true if the input character is blank,
......@@ -404,7 +398,7 @@ static int parse_str(Settings *settings, char *str, ParseState *parse_state)
*/
static int is_blank_char(char c)
{
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}
/* Returns true if the input string is blank,
......@@ -412,13 +406,13 @@ static int is_blank_char(char c)
*/
static int is_blank_str(const char *str)
{
while (*str != '\0') {
if (!is_blank_char(*str)) {
return 0;
}
str++;
}
return 1;
while (*str != '\0') {
if (!is_blank_char(*str)) {
return 0;
}
str++;
}
return 1;
}
/* Returns true if the input string denotes a comment,
......@@ -426,13 +420,13 @@ static int is_blank_str(const char *str)
*/
static int is_comment_str(const char *str)
{
if (*str == COMMENT_CHAR) {
/* To be a comment the first character must be the
* comment character.
*/
return 1;
}
return 0;
if (*str == COMMENT_CHAR) {
/* To be a comment the first character must be the
* comment character.
*/
return 1;
}
return 0;
}
/* Returns true if the input string denotes a section name,
......@@ -440,18 +434,18 @@ static int is_comment_str(const char *str)
*/
static int is_section_str(const char *str)
{
if (*str != SECTION_START_CHAR) {
/* The first character must be the section start character */
return 0;
}
while (*str != '\0' && *str != SECTION_END_CHAR) {
str++;
}
if (*str != SECTION_END_CHAR) {
/* The section end character must be present somewhere thereafter */
return 0;
}
return 1;
if (*str != SECTION_START_CHAR) {
/* The first character must be the section start character */
return 0;
}
while (*str != '\0' && *str != SECTION_END_CHAR) {
str++;
}
if (*str != SECTION_END_CHAR) {
/* The section end character must be present somewhere thereafter */
return 0;
}
return 1;
}
/* Returns true if the input string denotes a key-value pair,
......@@ -459,18 +453,18 @@ static int is_section_str(const char *str)
*/
static int is_key_value_str(const char *str)
{
if (*str == KEY_VALUE_SEPARATOR_CHAR) {
/* It is illegal to start with the key-value separator */
return 0;
}
while (*str != '\0' && *str != KEY_VALUE_SEPARATOR_CHAR) {
str++;
}
if (*str != KEY_VALUE_SEPARATOR_CHAR) {
/* The key-value separator must be present after the key part */
return 0;
}
return 1;
if (*str == KEY_VALUE_SEPARATOR_CHAR) {
/* It is illegal to start with the key-value separator */
return 0;
}
while (*str != '\0' && *str != KEY_VALUE_SEPARATOR_CHAR) {
str++;
}
if (*str != KEY_VALUE_SEPARATOR_CHAR) {
/* The key-value separator must be present after the key part */
return 0;
}
return 1;
}
/* Returns true if the input string denotes a key without a value,
......@@ -478,18 +472,18 @@ static int is_key_value_str(const char *str)
*/
static int is_key_without_value_str(const char *str)
{
if (*str == KEY_VALUE_SEPARATOR_CHAR) {
/* It is illegal to start with the key-value separator */
return 0;
}
while (*str != '\0' && *str != KEY_VALUE_SEPARATOR_CHAR) {
str++;
}
if (*str == KEY_VALUE_SEPARATOR_CHAR) {
/* The key-value separator must not be present after the key part */
return 0;
}
return 1;
if (*str == KEY_VALUE_SEPARATOR_CHAR) {
/* It is illegal to start with the key-value separator */
return 0;
}
while (*str != '\0' && *str != KEY_VALUE_SEPARATOR_CHAR) {
str++;
}
if (*str == KEY_VALUE_SEPARATOR_CHAR) {
/* The key-value separator must not be present after the key part */
return 0;
}
return 1;
}
/*
......@@ -498,27 +492,27 @@ static int is_key_without_value_str(const char *str)
*/
static int get_section_from_str(const char *str, char *out_buf, unsigned int out_buf_n)
{
unsigned int count;
count = 0;
/* Jump past the section begin character */
str++;
while (*str != '\0' && *str != SECTION_END_CHAR) {
/* Read in the section name into the output buffer */
if (count == out_buf_n) {
return 0;
}
*out_buf = *str;
out_buf++;
str++;
count++;
}
/* Terminate the output buffer */
if (count == out_buf_n) {
return 0;
}
*out_buf = '\0';
return 1;
unsigned int count;
count = 0;
/* Jump past the section begin character */
str++;
while (*str != '\0' && *str != SECTION_END_CHAR) {
/* Read in the section name into the output buffer */
if (count == out_buf_n) {
return 0;
}
*out_buf = *str;
out_buf++;
str++;
count++;
}
/* Terminate the output buffer */
if (count == out_buf_n) {
return 0;
}
*out_buf = '\0';
return 1;
}
/*
......@@ -527,67 +521,67 @@ static int get_section_from_str(const char *str, char *out_buf, unsigned int out
*/
static int get_key_value_from_str(const char *str, char *out_buf1, unsigned int out_buf1_n, char *out_buf2, unsigned int out_buf2_n)
{
unsigned int count1;
unsigned int count2;
count1 = 0;
count2 = 0;
/* Read the key value from the input string and write it sequentially
* to the first output buffer by walking the input string until we either hit
* the null-terminator or the key-value separator.
*/
while (*str != '\0' && *str != KEY_VALUE_SEPARATOR_CHAR) {
/* Ensure the first output buffer is large enough. */
if (count1 == out_buf1_n) {
return 0;
}
/* Copy the character to the first output buffer */
*out_buf1 = *str;
out_buf1++;
str++;
count1++;
}
/* Terminate the first output buffer */
if (count1 == out_buf1_n) {
return 0;
}
*out_buf1 = '\0';
/* Now trace the first input buffer backwards until we hit a non-blank character */
while (is_blank_char(*(out_buf1 - 1))) {
out_buf1--;
}
*out_buf1 = '\0';
/* Try to proceed one more character, past the last read key-value
* delimiter, in the input string.
*/
if (*str != '\0') {
str++;
}
/* Now find start of the value in the input string by walking the input
* string until we either hit the null-terminator or a blank character.
*/
while (*str != '\0' && is_blank_char(*str)) {
str++;
}
while (*str != '\0') {
/* Fail if there is a possibility that we are overwriting the second
* input buffer.
*/
if (count2 == out_buf2_n) {
return 0;
}
/* Copy the character to the second output buffer */
*out_buf2 = *str;
out_buf2++;
str++;
count2++;
}
/* Terminate the second output buffer */
if (count2 == out_buf2_n) {
return 0;
}
*out_buf2 = '\0';
return 1;
unsigned int count1;
unsigned int count2;
count1 = 0;
count2 = 0;
/* Read the key value from the input string and write it sequentially
* to the first output buffer by walking the input string until we either hit
* the null-terminator or the key-value separator.
*/
while (*str != '\0' && *str != KEY_VALUE_SEPARATOR_CHAR) {
/* Ensure the first output buffer is large enough. */
if (count1 == out_buf1_n) {
return 0;
}
/* Copy the character to the first output buffer */
*out_buf1 = *str;
out_buf1++;
str++;
count1++;
}
/* Terminate the first output buffer */
if (count1 == out_buf1_n) {
return 0;
}
*out_buf1 = '\0';
/* Now trace the first input buffer backwards until we hit a non-blank character */
while (is_blank_char(*(out_buf1 - 1))) {
out_buf1--;
}
*out_buf1 = '\0';
/* Try to proceed one more character, past the last read key-value
* delimiter, in the input string.
*/
if (*str != '\0') {
str++;
}
/* Now find start of the value in the input string by walking the input
* string until we either hit the null-terminator or a blank character.
*/
while (*str != '\0' && is_blank_char(*str)) {
str++;
}
while (*str != '\0') {
/* Fail if there is a possibility that we are overwriting the second
* input buffer.
*/
if (count2 == out_buf2_n) {
return 0;
}
/* Copy the character to the second output buffer */
*out_buf2 = *str;
out_buf2++;
str++;
count2++;
}
/* Terminate the second output buffer */
if (count2 == out_buf2_n) {
return 0;
}
*out_buf2 = '\0';
return 1;
}
/*
......@@ -596,30 +590,30 @@ static int get_key_value_from_str(const char *str, char *out_buf1, unsigned int
*/
static int get_key_without_value_from_str(const char *str, char *out_buf, unsigned int out_buf_n)
{
unsigned int count;
count = 0;
/* Now read the key value from the input string and write it sequentially
* to the output buffer by walking the input string until we either hit
* the null-terminator or the key-value separator.
*/
while (*str != '\0') {
/* Ensure the output buffer is large enough. */
if (count == out_buf_n) {
return 0;
}
/* Copy the character to the input buffer */
*out_buf = *str;
out_buf++;
str++;
count++;
}
/* Terminate the output buffer */
if (count == out_buf_n) {
return 0;
}
*out_buf = '\0';
return 1;
unsigned int count;
count = 0;
/* Now read the key value from the input string and write it sequentially
* to the output buffer by walking the input string until we either hit
* the null-terminator or the key-value separator.
*/
while (*str != '\0') {
/* Ensure the output buffer is large enough. */
if (count == out_buf_n) {
return 0;
}
/* Copy the character to the input buffer */
*out_buf = *str;
out_buf++;
str++;
count++;
}
/* Terminate the output buffer */
if (count == out_buf_n) {
return 0;
}
*out_buf = '\0';
return 1;
}
/* Returns a pointer to the next token in the input string delimited
......@@ -641,29 +635,29 @@ static int get_key_without_value_from_str(const char *str, char *out_buf, unsign
static const char * get_token(char *str, char delim, char **last)
{
char *s0;
s0 = str;
/* If we hit the null-terminator the string
* is exhausted and another token does not
* exist.
*/
if (*str == '\0') {
return NULL;
}
/* Walk the string until we encounter a
* null-terminator or the delimiter.
*/
while (*str != '\0' && *str != delim) {
str++;
}
/* Terminate the return token, if necessary */
if (*str != '\0') {
*str = '\0';
str++;
}
*last = str;
return s0;
char *s0;
s0 = str;
/* If we hit the null-terminator the string
* is exhausted and another token does not
* exist.
*/
if (*str == '\0') {
return NULL;
}
/* Walk the string until we encounter a
* null-terminator or the delimiter.
*/
while (*str != '\0' && *str != delim) {
str++;
}
/* Terminate the return token, if necessary */
if (*str != '\0') {
*str = '\0';
str++;
}
*last = str;
return s0;
}
/* Returns a converted value pointed to by the provided key in the given section.
......@@ -674,23 +668,23 @@ static const char * get_token(char *str, char delim, char **last)
*/
static int get_converted_value(const Settings *settings, const char *section, const char *key, ConvertMode mode, void *out)
{
char value[MAX_VALUECHARS];
if (!settings_get(settings, section, key, value, MAX_VALUECHARS)) {
return 0;
}
switch (mode) {
case CONVERT_MODE_INT:
*((int *)out) = atoi(value);
return 1;
case CONVERT_MODE_LONG:
*((long *)out) = atol(value);
return 1;
case CONVERT_MODE_DOUBLE:
*((double *)out) = atof(value);
return 1;
}
return 0;
char value[MAX_VALUECHARS];
if (!settings_get(settings, section, key, value, MAX_VALUECHARS)) {
return 0;
}
switch (mode) {
case CONVERT_MODE_INT:
*((int *)out) = atoi(value);
return 1;
case CONVERT_MODE_LONG:
*((long *)out) = atol(value);
return 1;
case CONVERT_MODE_DOUBLE:
*((double *)out) = atof(value);
return 1;
}
return 0;
}
/* Returns a converted tuple pointed to by the provided key in the given section.
......@@ -702,42 +696,42 @@ static int get_converted_value(const Settings *settings, const char *section, co
*/
static int get_converted_tuple(const Settings *settings, const char *section, const char *key, char delim, ConvertMode mode, void *out, unsigned int n_out)
{
unsigned int count;
const char *token;
static char value[MAX_VALUECHARS];
char *v;
if (out == NULL) {
return 0;
}
if (n_out == 0) {
return 0;
}
if (!settings_get(settings, section, key, value, MAX_VALUECHARS)) {
return 0;
}
v = value;
count = 0;
/* Walk over all tokens in the value, and convert them and assign them
* to the output array as specified by the mode.
*/
while ((token = get_token(v, delim, &v)) != NULL && count < n_out) {
switch (mode) {
case CONVERT_MODE_INT:
((int *)out)[count] = atoi(token);
break;
case CONVERT_MODE_LONG:
((long *)out)[count] = atol(token);
break;
case CONVERT_MODE_DOUBLE:
((double *)out)[count] = atof(token);
break;
default:
return 0;
}
count++;
}
return 1;
unsigned int count;
const char *token;
static char value[MAX_VALUECHARS];
char *v;
if (out == NULL) {
return 0;
}
if (n_out == 0) {
return 0;
}
if (!settings_get(settings, section, key, value, MAX_VALUECHARS)) {
return 0;
}
v = value;
count = 0;
/* Walk over all tokens in the value, and convert them and assign them
* to the output array as specified by the mode.
*/
while ((token = get_token(v, delim, &v)) != NULL && count < n_out) {
switch (mode) {
case CONVERT_MODE_INT:
((int *)out)[count] = atoi(token);
break;
case CONVERT_MODE_LONG:
((long *)out)[count] = atol(token);
break;
case CONVERT_MODE_DOUBLE:
((double *)out)[count] = atof(token);
break;
default:
return 0;
}
count++;
}
return 1;
}
/* Returns a pointer to the section or null if the named section does not
......@@ -745,22 +739,22 @@ static int get_converted_tuple(const Settings *settings, const char *section, co
*/
static Section * get_section(Section *sections, unsigned int n, const char *name)
{
unsigned int i;
Section *section;
if (name == NULL) {
return NULL;
}
section = sections;
i = 0;
while (i < n) {
if (strcmp(section->name, name) == 0) {
return section;
}
section++;
i++;
}
return NULL;
unsigned int i;
Section *section;
if (name == NULL) {
return NULL;
}
section = sections;
i = 0;
while (i < n) {
if (strcmp(section->name, name) == 0) {
return section;
}
section++;
i++;
}
return NULL;
}
/* Callback function that is passed into the enumeration function in the
......@@ -769,20 +763,20 @@ static Section * get_section(Section *sections, unsigned int n, const char *name
*/
static void enum_map(const char *key, const char *value, const void *obj)
{
FILE *stream;
char buf[MAX_LINECHARS];
if (key == NULL || value == NULL) {
return;
}
if (obj == NULL) {
return;
}
stream = (FILE *)obj;
if (strlen(key) < MAX_KEYCHARS && strlen(value) < MAX_VALUECHARS) {
sprintf(buf, "%s%c%s\n", key, KEY_VALUE_SEPARATOR_CHAR, value);
fputs(buf, stream);
}
FILE *stream;
char buf[MAX_LINECHARS];
if (key == NULL || value == NULL) {
return;
}
if (obj == NULL) {
return;
}
stream = (FILE *)obj;
if (strlen(key) < MAX_KEYCHARS && strlen(value) < MAX_VALUECHARS) {
sprintf(buf, "%s%c%s\n", key, KEY_VALUE_SEPARATOR_CHAR, value);
fputs(buf, stream);
}
}
/*
......
......@@ -7,7 +7,7 @@
*
* Copyright (c) 2009 Per Ola Kristensson.
*
* Per Ola Kristensson <pok21@cam.ac.uk>
* Per Ola Kristensson <pok21@cam.ac.uk>
* Inference Group, Department of Physics
* University of Cambridge
* Cavendish Laboratory
......@@ -43,292 +43,292 @@ extern "C"
{
#endif
typedef struct Settings Settings;
/*
* This callback function is called once per key-value when enumerating
* all keys inside a section.
*
* Parameters:
*
* key: A pointer to a null-terminated C string. The string must not
* be modified by the client.
*
* value: A pointer to a null-terminated C string. The string must
* not be modified by the client.
*
* obj: A pointer to a client-specific object. This parameter may be
* null.
*
* Return value: None.
*/
typedef void(*settings_section_enum_func)(const char *key, const char *value, const void *obj);
/*
* Creates a settings object.
*
* Return value: A pointer to a settings object,
* or null if a new settings object could not be allocated.
*/
Settings * settings_new();
/*
* Releases all memory held by a settings object.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
* If the supplied settings object has been previously released, the
* behaviour of this function is undefined.
*
* Return value: None.
*/
void settings_delete(Settings *settings);
/*
* Constructs a settings object by loading settings in textual form
* from the given stream.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* stream: A pointer to a stream. This parameter cannot be null.
*
* Return value: A pointer to a settings object,
* or null if an error occurred.
*/
Settings * settings_open(FILE *stream);
/*
* Saves the current settings object in textual form to the given stream.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* stream: A pointer to a stream. This parameter cannot be null.
*
* Return value: 1 if the operation succeeded, 0 otherwise.
*/
int settings_save(const Settings *settings, FILE *stream);
/*
* Returns the value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out_buf: A pointer to an output buffer which will contain the value,
* if it exists and fits into the buffer.
*
* n_out_buf: The size of the output buffer in bytes.
*
* Return value: If out_buf is set to null and n_out_buf is set to 0 the return
* value will be the number of bytes required to store the value (if it exists)
* and its null-terminator. For all other parameter configurations the return value
* is 1 if an associated value was found and completely copied into the output buffer,
* 0 otherwise.
*/
int settings_get(const Settings *settings, const char *section, const char *key, char *out_buf, unsigned int n_out_buf);
/*
* Returns the integer value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The integer value associated to the provided section and
* key, or 0 if no such value exists.
*/
int settings_get_int(const Settings *settings, const char *section, const char *key);
/*
* Returns the long integer value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The long integer value associated to the provided section and
* key, or 0 if no such value exists.
*/
long settings_get_long(const Settings *settings, const char *section, const char *key);
/*
* Returns the double value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The double value associated to the provided section and
* key, or 0 if no such value exists.
*/
double settings_get_double(const Settings *settings, const char *section, const char *key);
/*
* Returns the integer tuple associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out: A pointer to an output buffer.
*
* n_out: The maximum number of elements the output buffer can hold.
*
* Return value: 1 if the entire tuple was copied into the output buffer,
* 0 otherwise.
*/
int settings_get_int_tuple(const Settings *settings, const char *section, const char *key, int *out, unsigned int n_out);
/*
* Returns the long tuple associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out: A pointer to an output buffer.
*
* n_out: The maximum number of elements the output buffer can hold.
*
* Return value: 1 if the entire tuple was copied into the output buffer,
* 0 otherwise.
*/
long settings_get_long_tuple(const Settings *settings, const char *section, const char *key, long *out, unsigned int n_out);
/*
* Returns the double tuple associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out: A pointer to an output buffer.
*
* n_out: The maximum number of elements the output buffer can hold.
*
* Return value: 1 if the entire tuple was copied into the output buffer,
* 0 otherwise.
*/
double settings_get_double_tuple(const Settings *settings, const char *section, const char *key, double *out, unsigned int n_out);
/*
* Associates a value with the supplied key in the provided section.
* If the key is already associated with a value, the previous value
* is replaced.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null. The string must have a string length > 0. The string will
* be copied.
*
* key: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* value: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* Return value: 1 if the association succeeded, 0 otherwise.
*/
int settings_set(Settings *setting, const char *section, const char *key, const char *value);
/*
* Returns the number of associations between keys and values that exist
* in the provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The number of associations between keys and values in
* the provided section.
*/
int settings_section_get_count(const Settings *settings, const char *section);
/*
* Enumerates all associations between keys and values in the provided
* section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* enum_func: A pointer to a callback function that will be
* called by this procedure once for every key associated
* with a value. This parameter cannot be null.
*
* obj: A pointer to a client-specific object. This parameter will be
* passed back to the client's callback function. This parameter can
* be null.
*
* Return value: 1 if enumeration completed, 0 otherwise.
*/
int settings_section_enum(const Settings *settings, const char *section, settings_section_enum_func enum_func, const void *obj);
typedef struct Settings Settings;
/*
* This callback function is called once per key-value when enumerating
* all keys inside a section.
*
* Parameters:
*
* key: A pointer to a null-terminated C string. The string must not
* be modified by the client.
*
* value: A pointer to a null-terminated C string. The string must
* not be modified by the client.
*
* obj: A pointer to a client-specific object. This parameter may be
* null.
*
* Return value: None.
*/
typedef void(*settings_section_enum_func)(const char *key, const char *value, const void *obj);
/*
* Creates a settings object.
*
* Return value: A pointer to a settings object,
* or null if a new settings object could not be allocated.
*/
Settings * settings_new();
/*
* Releases all memory held by a settings object.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
* If the supplied settings object has been previously released, the
* behaviour of this function is undefined.
*
* Return value: None.
*/
void settings_delete(Settings *settings);
/*
* Constructs a settings object by loading settings in textual form
* from the given stream.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* stream: A pointer to a stream. This parameter cannot be null.
*
* Return value: A pointer to a settings object,
* or null if an error occurred.
*/
Settings * settings_open(FILE *stream);
/*
* Saves the current settings object in textual form to the given stream.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* stream: A pointer to a stream. This parameter cannot be null.
*
* Return value: 1 if the operation succeeded, 0 otherwise.
*/
int settings_save(const Settings *settings, FILE *stream);
/*
* Returns the value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out_buf: A pointer to an output buffer which will contain the value,
* if it exists and fits into the buffer.
*
* n_out_buf: The size of the output buffer in bytes.
*
* Return value: If out_buf is set to null and n_out_buf is set to 0 the return
* value will be the number of bytes required to store the value (if it exists)
* and its null-terminator. For all other parameter configurations the return value
* is 1 if an associated value was found and completely copied into the output buffer,
* 0 otherwise.
*/
int settings_get(const Settings *settings, const char *section, const char *key, char *out_buf, unsigned int n_out_buf);
/*
* Returns the integer value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The integer value associated to the provided section and
* key, or 0 if no such value exists.
*/
int settings_get_int(const Settings *settings, const char *section, const char *key);
/*
* Returns the long integer value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The long integer value associated to the provided section and
* key, or 0 if no such value exists.
*/
long settings_get_long(const Settings *settings, const char *section, const char *key);
/*
* Returns the double value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The double value associated to the provided section and
* key, or 0 if no such value exists.
*/
double settings_get_double(const Settings *settings, const char *section, const char *key);
/*
* Returns the integer tuple associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out: A pointer to an output buffer.
*
* n_out: The maximum number of elements the output buffer can hold.
*
* Return value: 1 if the entire tuple was copied into the output buffer,
* 0 otherwise.
*/
int settings_get_int_tuple(const Settings *settings, const char *section, const char *key, int *out, unsigned int n_out);
/*
* Returns the long tuple associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out: A pointer to an output buffer.
*
* n_out: The maximum number of elements the output buffer can hold.
*
* Return value: 1 if the entire tuple was copied into the output buffer,
* 0 otherwise.
*/
long settings_get_long_tuple(const Settings *settings, const char *section, const char *key, long *out, unsigned int n_out);
/*
* Returns the double tuple associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out: A pointer to an output buffer.
*
* n_out: The maximum number of elements the output buffer can hold.
*
* Return value: 1 if the entire tuple was copied into the output buffer,
* 0 otherwise.
*/
double settings_get_double_tuple(const Settings *settings, const char *section, const char *key, double *out, unsigned int n_out);
/*
* Associates a value with the supplied key in the provided section.
* If the key is already associated with a value, the previous value
* is replaced.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null. The string must have a string length > 0. The string will
* be copied.
*
* key: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* value: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* Return value: 1 if the association succeeded, 0 otherwise.
*/
int settings_set(Settings *setting, const char *section, const char *key, const char *value);
/*
* Returns the number of associations between keys and values that exist
* in the provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The number of associations between keys and values in
* the provided section.
*/
int settings_section_get_count(const Settings *settings, const char *section);
/*
* Enumerates all associations between keys and values in the provided
* section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* enum_func: A pointer to a callback function that will be
* called by this procedure once for every key associated
* with a value. This parameter cannot be null.
*
* obj: A pointer to a client-specific object. This parameter will be
* passed back to the client's callback function. This parameter can
* be null.
*
* Return value: 1 if enumeration completed, 0 otherwise.
*/
int settings_section_enum(const Settings *settings, const char *section, settings_section_enum_func enum_func, const void *obj);
#ifdef __cplusplus
}
......
......@@ -6,13 +6,13 @@
* Version history:
* 1.0.0 - initial release
* 2.0.0 - changed function prefix from strmap to sm to ensure
* ANSI C compatibility
* ANSI C compatibility
*
* strmap.c
*
* Copyright (c) 2009, 2011 Per Ola Kristensson.
*
* Per Ola Kristensson <pok21@cam.ac.uk>
* Per Ola Kristensson <pok21@cam.ac.uk>
* Inference Group, Department of Physics
* University of Cambridge
* Cavendish Laboratory
......@@ -40,18 +40,18 @@ typedef struct Pair Pair;
typedef struct Bucket Bucket;
struct Pair {
char *key;
char *value;
char *key;
char *value;
};
struct Bucket {
unsigned int count;
Pair *pairs;
unsigned int count;
Pair *pairs;
};
struct StrMap {
unsigned int count;
Bucket *buckets;
unsigned int count;
Bucket *buckets;
};
static Pair * get_pair(Bucket *bucket, const char *key);
......@@ -59,247 +59,246 @@ static unsigned long hash(const char *str);
StrMap * sm_new(unsigned int capacity)
{
StrMap *map;
map = (StrMap*)malloc(sizeof(StrMap));
if (map == NULL) {
return NULL;
}
map->count = capacity;
map->buckets = (Bucket*)malloc(map->count * sizeof(Bucket));
if (map->buckets == NULL) {
free(map);
return NULL;
}
memset(map->buckets, 0, map->count * sizeof(Bucket));
return map;
StrMap *map;
map = (StrMap*)malloc(sizeof(StrMap));
if (map == NULL) {
return NULL;
}
map->count = capacity;
map->buckets = (Bucket*)malloc(map->count * sizeof(Bucket));
if (map->buckets == NULL) {
free(map);
return NULL;
}
memset(map->buckets, 0, map->count * sizeof(Bucket));
return map;
}
void sm_delete(StrMap *map)
{
unsigned int i, j, n, m;
Bucket *bucket;
Pair *pair;
if (map == NULL) {
return;
}
n = map->count;
bucket = map->buckets;
i = 0;
while (i < n) {
m = bucket->count;
pair = bucket->pairs;
j = 0;
while(j < m) {
free(pair->key);
free(pair->value);
pair++;
j++;
}
free(bucket->pairs);
bucket++;
i++;
}
free(map->buckets);
free(map);
unsigned int i, j, n, m;
Bucket *bucket;
Pair *pair;
if (map == NULL) {
return;
}
n = map->count;
bucket = map->buckets;
i = 0;
while (i < n) {
m = bucket->count;
pair = bucket->pairs;
j = 0;
while(j < m) {
free(pair->key);
free(pair->value);
pair++;
j++;
}
free(bucket->pairs);
bucket++;
i++;
}
free(map->buckets);
free(map);
}
int sm_get(const StrMap *map, const char *key, char *out_buf, unsigned int n_out_buf)
{
unsigned int index;
Bucket *bucket;
Pair *pair;
if (map == NULL) {
return 0;
}
if (key == NULL) {
return 0;
}
index = hash(key) % map->count;
bucket = &(map->buckets[index]);
pair = get_pair(bucket, key);
if (pair == NULL) {
return 0;
}
if (out_buf == NULL && n_out_buf == 0) {
return strlen(pair->value) + 1;
}
if (out_buf == NULL) {
return 0;
}
if (strlen(pair->value) >= n_out_buf) {
return 0;
}
strcpy(out_buf, pair->value);
return 1;
unsigned int index;
Bucket *bucket;
Pair *pair;
if (map == NULL) {
return 0;
}
if (key == NULL) {
return 0;
}
index = hash(key) % map->count;
bucket = &(map->buckets[index]);
pair = get_pair(bucket, key);
if (pair == NULL) {
return 0;
}
if (out_buf == NULL && n_out_buf == 0) {
return strlen(pair->value) + 1;
}
if (out_buf == NULL) {
return 0;
}
if (strlen(pair->value) >= n_out_buf) {
return 0;
}
strcpy(out_buf, pair->value);
return 1;
}
int sm_exists(const StrMap *map, const char *key)
{
unsigned int index;
Bucket *bucket;
Pair *pair;
if (map == NULL) {
return 0;
}
if (key == NULL) {
return 0;
}
index = hash(key) % map->count;
bucket = &(map->buckets[index]);
pair = get_pair(bucket, key);
if (pair == NULL) {
return 0;
}
return 1;
unsigned int index;
Bucket *bucket;
Pair *pair;
if (map == NULL) {
return 0;
}
if (key == NULL) {
return 0;
}
index = hash(key) % map->count;
bucket = &(map->buckets[index]);
pair = get_pair(bucket, key);
if (pair == NULL) {
return 0;
}
return 1;
}
int sm_put(StrMap *map, const char *key, const char *value)
{
unsigned int key_len, value_len, index;
Bucket *bucket;
Pair *tmp_pairs, *pair;
char *tmp_value;
char *new_key, *new_value;
if (map == NULL) {
return 0;
}
if (key == NULL || value == NULL) {
return 0;
}
key_len = strlen(key);
value_len = strlen(value);
/* Get a pointer to the bucket the key string hashes to */
index = hash(key) % map->count;
bucket = &(map->buckets[index]);
/* Check if we can handle insertion by simply replacing
* an existing value in a key-value pair in the bucket.
*/
if ((pair = get_pair(bucket, key)) != NULL) {
/* The bucket contains a pair that matches the provided key,
* change the value for that pair to the new value.
*/
if (strlen(pair->value) < value_len) {
/* If the new value is larger than the old value, re-allocate
* space for the new larger value.
*/
tmp_value = (char*)realloc(pair->value, (value_len + 1) * sizeof(char));
if (tmp_value == NULL) {
return 0;
}
pair->value = tmp_value;
}
/* Copy the new value into the pair that matches the key */
strcpy(pair->value, value);
return 1;
}
/* Allocate space for a new key and value */
new_key = (char*)malloc((key_len + 1) * sizeof(char));
if (new_key == NULL) {
return 0;
}
new_value = (char*)malloc((value_len + 1) * sizeof(char));
if (new_value == NULL) {
free(new_key);
return 0;
}
/* Create a key-value pair */
if (bucket->count == 0) {
/* The bucket is empty, lazily allocate space for a single
* key-value pair.
*/
bucket->pairs = (Pair*)malloc(sizeof(Pair));
if (bucket->pairs == NULL) {
free(new_key);
free(new_value);
return 0;
}
bucket->count = 1;
}
else {
/* The bucket wasn't empty but no pair existed that matches the provided
* key, so create a new key-value pair.
*/
tmp_pairs = (Pair*)realloc(bucket->pairs, (bucket->count + 1) * sizeof(Pair));
if (tmp_pairs == NULL) {
free(new_key);
free(new_value);
return 0;
}
bucket->pairs = tmp_pairs;
bucket->count++;
}
/* Get the last pair in the chain for the bucket */
pair = &(bucket->pairs[bucket->count - 1]);
pair->key = new_key;
pair->value = new_value;
/* Copy the key and its value into the key-value pair */
strcpy(pair->key, key);
strcpy(pair->value, value);
return 1;
unsigned int key_len, value_len, index;
Bucket *bucket;
Pair *tmp_pairs, *pair;
char *tmp_value;
char *new_key, *new_value;
if (map == NULL) {
return 0;
}
if (key == NULL || value == NULL) {
return 0;
}
key_len = strlen(key);
value_len = strlen(value);
/* Get a pointer to the bucket the key string hashes to */
index = hash(key) % map->count;
bucket = &(map->buckets[index]);
/* Check if we can handle insertion by simply replacing
* an existing value in a key-value pair in the bucket.
*/
if ((pair = get_pair(bucket, key)) != NULL) {
/* The bucket contains a pair that matches the provided key,
* change the value for that pair to the new value.
*/
if (strlen(pair->value) < value_len) {
/* If the new value is larger than the old value, re-allocate
* space for the new larger value.
*/
tmp_value = (char*)realloc(pair->value, (value_len + 1) * sizeof(char));
if (tmp_value == NULL) {
return 0;
}
pair->value = tmp_value;
}
/* Copy the new value into the pair that matches the key */
strcpy(pair->value, value);
return 1;
}
/* Allocate space for a new key and value */
new_key = (char*)malloc((key_len + 1) * sizeof(char));
if (new_key == NULL) {
return 0;
}
new_value = (char*)malloc((value_len + 1) * sizeof(char));
if (new_value == NULL) {
free(new_key);
return 0;
}
/* Create a key-value pair */
if (bucket->count == 0) {
/* The bucket is empty, lazily allocate space for a single
* key-value pair.
*/
bucket->pairs = (Pair*)malloc(sizeof(Pair));
if (bucket->pairs == NULL) {
free(new_key);
free(new_value);
return 0;
}
bucket->count = 1;
} else {
/* The bucket wasn't empty but no pair existed that matches the provided
* key, so create a new key-value pair.
*/
tmp_pairs = (Pair*)realloc(bucket->pairs, (bucket->count + 1) * sizeof(Pair));
if (tmp_pairs == NULL) {
free(new_key);
free(new_value);
return 0;
}
bucket->pairs = tmp_pairs;
bucket->count++;
}
/* Get the last pair in the chain for the bucket */
pair = &(bucket->pairs[bucket->count - 1]);
pair->key = new_key;
pair->value = new_value;
/* Copy the key and its value into the key-value pair */
strcpy(pair->key, key);
strcpy(pair->value, value);
return 1;
}
int sm_get_count(const StrMap *map)
{
unsigned int i, j, n, m;
unsigned int count;
Bucket *bucket;
Pair *pair;
if (map == NULL) {
return 0;
}
bucket = map->buckets;
n = map->count;
i = 0;
count = 0;
while (i < n) {
pair = bucket->pairs;
m = bucket->count;
j = 0;
while (j < m) {
count++;
pair++;
j++;
}
bucket++;
i++;
}
return count;
unsigned int i, j, n, m;
unsigned int count;
Bucket *bucket;
Pair *pair;
if (map == NULL) {
return 0;
}
bucket = map->buckets;
n = map->count;
i = 0;
count = 0;
while (i < n) {
pair = bucket->pairs;
m = bucket->count;
j = 0;
while (j < m) {
count++;
pair++;
j++;
}
bucket++;
i++;
}
return count;
}
int sm_enum(const StrMap *map, sm_enum_func enum_func, const void *obj)
{
unsigned int i, j, n, m;
Bucket *bucket;
Pair *pair;
if (map == NULL) {
return 0;
}
if (enum_func == NULL) {
return 0;
}
bucket = map->buckets;
n = map->count;
i = 0;
while (i < n) {
pair = bucket->pairs;
m = bucket->count;
j = 0;
while (j < m) {
enum_func(pair->key, pair->value, obj);
pair++;
j++;
}
bucket++;
i++;
}
return 1;
unsigned int i, j, n, m;
Bucket *bucket;
Pair *pair;
if (map == NULL) {
return 0;
}
if (enum_func == NULL) {
return 0;
}
bucket = map->buckets;
n = map->count;
i = 0;
while (i < n) {
pair = bucket->pairs;
m = bucket->count;
j = 0;
while (j < m) {
enum_func(pair->key, pair->value, obj);
pair++;
j++;
}
bucket++;
i++;
}
return 1;
}
/*
......@@ -308,25 +307,25 @@ int sm_enum(const StrMap *map, sm_enum_func enum_func, const void *obj)
*/
static Pair * get_pair(Bucket *bucket, const char *key)
{
unsigned int i, n;
Pair *pair;
n = bucket->count;
if (n == 0) {
return NULL;
}
pair = bucket->pairs;
i = 0;
while (i < n) {
if (pair->key != NULL && pair->value != NULL) {
if (strcmp(pair->key, key) == 0) {
return pair;
}
}
pair++;
i++;
}
return NULL;
unsigned int i, n;
Pair *pair;
n = bucket->count;
if (n == 0) {
return NULL;
}
pair = bucket->pairs;
i = 0;
while (i < n) {
if (pair->key != NULL && pair->value != NULL) {
if (strcmp(pair->key, key) == 0) {
return pair;
}
}
pair++;
i++;
}
return NULL;
}
/*
......@@ -334,13 +333,13 @@ static Pair * get_pair(Bucket *bucket, const char *key)
*/
static unsigned long hash(const char *str)
{
unsigned long hash = 5381;
int c;
unsigned long hash = 5381;
int c;
while (c = *str++) {
hash = ((hash << 5) + hash) + c;
}
return hash;
while (c = *str++) {
hash = ((hash << 5) + hash) + c;
}
return hash;
}
/*
......
......@@ -6,13 +6,13 @@
* Version history:
* 1.0.0 - initial release
* 2.0.0 - changed function prefix from strmap to sm to ensure
* ANSI C compatibility
* ANSI C compatibility
*
* strmap.h
*
* Copyright (c) 2009, 2011 Per Ola Kristensson.
*
* Per Ola Kristensson <pok21@cam.ac.uk>
* Per Ola Kristensson <pok21@cam.ac.uk>
* Inference Group, Department of Physics
* University of Cambridge
* Cavendish Laboratory
......@@ -44,139 +44,139 @@ extern "C"
#include <stdlib.h>
#include <string.h>
typedef struct StrMap StrMap;
/*
* This callback function is called once per key-value when enumerating
* all keys associated to values.
*
* Parameters:
*
* key: A pointer to a null-terminated C string. The string must not
* be modified by the client.
*
* value: A pointer to a null-terminated C string. The string must
* not be modified by the client.
*
* obj: A pointer to a client-specific object. This parameter may be
* null.
*
* Return value: None.
*/
typedef void(*sm_enum_func)(const char *key, const char *value, const void *obj);
/*
* Creates a string map.
*
* Parameters:
*
* capacity: The number of top-level slots this string map
* should allocate. This parameter must be > 0.
*
* Return value: A pointer to a string map object,
* or null if a new string map could not be allocated.
*/
StrMap * sm_new(unsigned int capacity);
/*
* Releases all memory held by a string map object.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
* If the supplied string map has been previously released, the
* behaviour of this function is undefined.
*
* Return value: None.
*/
void sm_delete(StrMap *map);
/*
* Returns the value associated with the supplied key.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out_buf: A pointer to an output buffer which will contain the value,
* if it exists and fits into the buffer.
*
* n_out_buf: The size of the output buffer in bytes.
*
* Return value: If out_buf is set to null and n_out_buf is set to 0 the return
* value will be the number of bytes required to store the value (if it exists)
* and its null-terminator. For all other parameter configurations the return value
* is 1 if an associated value was found and completely copied into the output buffer,
* 0 otherwise.
*/
int sm_get(const StrMap *map, const char *key, char *out_buf, unsigned int n_out_buf);
/*
* Queries the existence of a key.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: 1 if the key exists, 0 otherwise.
*/
int sm_exists(const StrMap *map, const char *key);
/*
* Associates a value with the supplied key. If the key is already
* associated with a value, the previous value is replaced.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* key: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* value: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* Return value: 1 if the association succeeded, 0 otherwise.
*/
int sm_put(StrMap *map, const char *key, const char *value);
/*
* Returns the number of associations between keys and values.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* Return value: The number of associations between keys and values.
*/
int sm_get_count(const StrMap *map);
/*
* Enumerates all associations between keys and values.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* enum_func: A pointer to a callback function that will be
* called by this procedure once for every key associated
* with a value. This parameter cannot be null.
*
* obj: A pointer to a client-specific object. This parameter will be
* passed back to the client's callback function. This parameter can
* be null.
*
* Return value: 1 if enumeration completed, 0 otherwise.
*/
int sm_enum(const StrMap *map, sm_enum_func enum_func, const void *obj);
typedef struct StrMap StrMap;
/*
* This callback function is called once per key-value when enumerating
* all keys associated to values.
*
* Parameters:
*
* key: A pointer to a null-terminated C string. The string must not
* be modified by the client.
*
* value: A pointer to a null-terminated C string. The string must
* not be modified by the client.
*
* obj: A pointer to a client-specific object. This parameter may be
* null.
*
* Return value: None.
*/
typedef void(*sm_enum_func)(const char *key, const char *value, const void *obj);
/*
* Creates a string map.
*
* Parameters:
*
* capacity: The number of top-level slots this string map
* should allocate. This parameter must be > 0.
*
* Return value: A pointer to a string map object,
* or null if a new string map could not be allocated.
*/
StrMap * sm_new(unsigned int capacity);
/*
* Releases all memory held by a string map object.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
* If the supplied string map has been previously released, the
* behaviour of this function is undefined.
*
* Return value: None.
*/
void sm_delete(StrMap *map);
/*
* Returns the value associated with the supplied key.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out_buf: A pointer to an output buffer which will contain the value,
* if it exists and fits into the buffer.
*
* n_out_buf: The size of the output buffer in bytes.
*
* Return value: If out_buf is set to null and n_out_buf is set to 0 the return
* value will be the number of bytes required to store the value (if it exists)
* and its null-terminator. For all other parameter configurations the return value
* is 1 if an associated value was found and completely copied into the output buffer,
* 0 otherwise.
*/
int sm_get(const StrMap *map, const char *key, char *out_buf, unsigned int n_out_buf);
/*
* Queries the existence of a key.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: 1 if the key exists, 0 otherwise.
*/
int sm_exists(const StrMap *map, const char *key);
/*
* Associates a value with the supplied key. If the key is already
* associated with a value, the previous value is replaced.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* key: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* value: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* Return value: 1 if the association succeeded, 0 otherwise.
*/
int sm_put(StrMap *map, const char *key, const char *value);
/*
* Returns the number of associations between keys and values.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* Return value: The number of associations between keys and values.
*/
int sm_get_count(const StrMap *map);
/*
* Enumerates all associations between keys and values.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* enum_func: A pointer to a callback function that will be
* called by this procedure once for every key associated
* with a value. This parameter cannot be null.
*
* obj: A pointer to a client-specific object. This parameter will be
* passed back to the client's callback function. This parameter can
* be null.
*
* Return value: 1 if enumeration completed, 0 otherwise.
*/
int sm_enum(const StrMap *map, sm_enum_func enum_func, const void *obj);
#ifdef __cplusplus
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment