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