Commit 1f8131bd authored by Daniel Graziotin's avatar Daniel Graziotin

Fixes #18. Seems ready for v1.4.0

parent 03ac2050
...@@ -3,8 +3,7 @@ Fan-Control-Daemon ...@@ -3,8 +3,7 @@ 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 [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/)
Fan-Control-Daemon is a daemon that uses input from coretemp module and sets the fan speed using the applesmc module. Fan-Control-Daemon is a daemon that uses input from coretemp module and sets the fan speed using the applesmc module.
This enhanced version assumes any number of processors and fans (max. 10). This enhanced version assumes any number of processors and fans (max. 10).
...@@ -50,10 +49,6 @@ Compile with ...@@ -50,10 +49,6 @@ Compile with
make make
Manually compile with
gcc -o bin/mbpfan src/mbpfan.c -lm
Install Instructions Install Instructions
-------------------- --------------------
......
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
#!/bin/bash #!/bin/bash
# Archlinux rc script
# not maintained in this proejct # not maintained in this project
# please, fix it and contribute back to the project
daemon_name=mbpfan daemon_name=mbpfan
......
...@@ -34,10 +34,12 @@ int write_pid(int pid) ...@@ -34,10 +34,12 @@ 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 { } else {
return 0; return 0;
} }
...@@ -48,11 +50,13 @@ int read_pid() ...@@ -48,11 +50,13 @@ 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;
} }
...@@ -103,6 +107,7 @@ void go_daemon(void (*fan_control)()) ...@@ -103,6 +107,7 @@ void go_daemon(void (*fan_control)())
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 { } else {
setlogmask(LOG_UPTO(LOG_INFO)); setlogmask(LOG_UPTO(LOG_INFO));
openlog(program_name, LOG_CONS, LOG_USER); openlog(program_name, LOG_CONS, LOG_USER);
...@@ -115,9 +120,11 @@ void go_daemon(void (*fan_control)()) ...@@ -115,9 +120,11 @@ void go_daemon(void (*fan_control)())
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);
...@@ -127,6 +134,7 @@ void go_daemon(void (*fan_control)()) ...@@ -127,6 +134,7 @@ void go_daemon(void (*fan_control)())
// 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);
} }
...@@ -151,23 +159,30 @@ void go_daemon(void (*fan_control)()) ...@@ -151,23 +159,30 @@ void go_daemon(void (*fan_control)())
printf("Writing a new .pid file with value %d at: %s\n", 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); 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) { if (verbose) {
printf("Successfully written a new .pid file with value %d at: %s\n", 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); 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); syslog(LOG_ERR, "A previously created .pid file exists at: %s. Aborting", program_pid);
if (verbose) { if (verbose) {
printf("ERROR: a previously created .pid file exists at: %s.\n Aborting\n", program_pid); printf("ERROR: a previously created .pid file exists at: %s.\n Aborting\n", program_pid);
} }
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
* *
*/ */
#ifndef _DAEMON_H_
#define _DAEMON_H_
/** /**
* Write the PID of the forked daemon to the * Write the PID of the forked daemon to the
...@@ -48,3 +50,5 @@ void signal_handler(int signal); ...@@ -48,3 +50,5 @@ void signal_handler(int signal);
* Daemonizes * Daemonizes
*/ */
int go_daemon(void (*function)()); int go_daemon(void (*function)());
#endif
\ No newline at end of file
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
extern int daemonize; extern int daemonize;
extern int verbose; extern int verbose;
extern const char* program_name; extern const char* program_name;
extern const char* program_pid; extern const char* program_pid;
struct s_sensors {
char* path;
char* fan_output_path;
char* fan_manual_path;
unsigned int temperature;
struct s_sensors *next;
};
typedef s_sensors t_sensors;
#endif
\ No newline at end of file
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
* *
*/ */
/**
* Code formatted with astyle -A3 -s --break-blocks=all --add-brackets *.c *.h
*/
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
...@@ -46,6 +50,7 @@ int main(int argc, char *argv[]) ...@@ -46,6 +50,7 @@ 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':
......
...@@ -57,7 +57,7 @@ int max_temp = 86; // do not set it > 90 ...@@ -57,7 +57,7 @@ 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;
...@@ -65,6 +65,9 @@ struct s_sensors { ...@@ -65,6 +65,9 @@ struct s_sensors {
unsigned int temperature; unsigned int temperature;
struct s_sensors *next; struct s_sensors *next;
}; };
*/
typedef struct s_sensors t_sensors;
t_sensors *retrieve_sensors() t_sensors *retrieve_sensors()
...@@ -82,6 +85,7 @@ t_sensors *retrieve_sensors() ...@@ -82,6 +85,7 @@ t_sensors *retrieve_sensors()
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);
...@@ -98,24 +102,33 @@ t_sensors *retrieve_sensors() ...@@ -98,24 +102,33 @@ t_sensors *retrieve_sensors()
s->path = (char *) malloc(sizeof( char ) * path_size); s->path = (char *) malloc(sizeof( char ) * path_size);
strcpy(s->path, path); strcpy(s->path, path);
fscanf(file, "%d", &s->temperature); fscanf(file, "%d", &s->temperature);
if (sensors_head == NULL) { if (sensors_head == NULL) {
sensors_head = s; sensors_head = s;
sensors_head->next = NULL; sensors_head->next = NULL;
} else { } else {
t_sensors *tmp = sensors_head; t_sensors *tmp = sensors_head;
while (tmp->next != NULL) { while (tmp->next != NULL) {
tmp = tmp->next; 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;
} }
...@@ -162,6 +175,7 @@ void find_fans(t_sensors* sensors) ...@@ -162,6 +175,7 @@ void find_fans(t_sensors* sensors)
tmp->fan_output_path = (char *) malloc(sizeof( char ) * path_min_size); tmp->fan_output_path = (char *) malloc(sizeof( char ) * path_min_size);
tmp->fan_manual_path = (char *) malloc(sizeof( char ) * path_man_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;
...@@ -173,6 +187,7 @@ void find_fans(t_sensors* sensors) ...@@ -173,6 +187,7 @@ void find_fans(t_sensors* sensors)
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);
} }
...@@ -189,12 +204,15 @@ void set_fans_man(t_sensors *sensors) ...@@ -189,12 +204,15 @@ 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); fprintf(file, "%d", 1);
fclose(file); fclose(file);
} }
tmp = tmp->next; tmp = tmp->next;
} }
} }
...@@ -214,6 +232,7 @@ t_sensors *refresh_sensors(t_sensors *sensors) ...@@ -214,6 +232,7 @@ t_sensors *refresh_sensors(t_sensors *sensors)
tmp = tmp->next; tmp = tmp->next;
} }
return sensors; return sensors;
} }
...@@ -223,8 +242,10 @@ void set_fan_speed(t_sensors* sensors, int speed) ...@@ -223,8 +242,10 @@ 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); fprintf(file, "%d", speed);
fclose(file); fclose(file);
...@@ -243,10 +264,12 @@ unsigned short get_temp(t_sensors* sensors) ...@@ -243,10 +264,12 @@ unsigned short get_temp(t_sensors* sensors)
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;
} }
...@@ -262,35 +285,63 @@ void retrieve_settings() ...@@ -262,35 +285,63 @@ void retrieve_settings()
/* Could not open configfile */ /* Could not open configfile */
if(verbose) { if(verbose) {
printf("Couldn't open configfile, using defaults\n"); printf("Couldn't open configfile, using defaults\n");
if(daemonize) { if(daemonize) {
syslog(LOG_INFO, "Couldn't open configfile, using defaults"); syslog(LOG_INFO, "Couldn't open configfile, using defaults");
} }
} }
} else { } else {
settings = settings_open(f); settings = settings_open(f);
fclose(f); fclose(f);
if (settings == NULL) { if (settings == NULL) {
/* Could not read configfile */ /* Could not read configfile */
if(verbose) { if(verbose) {
printf("Couldn't read configfile\n"); printf("Couldn't read configfile\n");
if(daemonize) { if(daemonize) {
syslog(LOG_INFO, "Couldn't read configfile"); syslog(LOG_INFO, "Couldn't read configfile");
} }
} }
} else { } else {
/* Read configfile values */ /* Read configfile values */
result = settings_get_int(settings, "general", "min_fan_speed"); result = settings_get_int(settings, "general", "min_fan_speed");
if (result != 0) min_fan_speed = result;
if (result != 0) {
min_fan_speed = result;
}
result = settings_get_int(settings, "general", "max_fan_speed"); result = settings_get_int(settings, "general", "max_fan_speed");
if (result != 0) max_fan_speed = result;
if (result != 0) {
max_fan_speed = result;
}
result = settings_get_int(settings, "general", "low_temp"); result = settings_get_int(settings, "general", "low_temp");
if (result != 0) low_temp = result;
if (result != 0) {
low_temp = result;
}
result = settings_get_int(settings, "general", "high_temp"); result = settings_get_int(settings, "general", "high_temp");
if (result != 0) high_temp = result;
if (result != 0) {
high_temp = result;
}
result = settings_get_int(settings, "general", "max_temp"); result = settings_get_int(settings, "general", "max_temp");
if (result != 0) max_temp = result;
if (result != 0) {
max_temp = result;
}
result = settings_get_int(settings, "general", "polling_interval"); result = settings_get_int(settings, "general", "polling_interval");
if (result != 0) polling_interval = result;
if (result != 0) {
polling_interval = result;
}
/* Destroy the settings object */ /* Destroy the settings object */
settings_delete(settings); settings_delete(settings);
...@@ -316,10 +367,12 @@ void mbpfan() ...@@ -316,10 +367,12 @@ void mbpfan()
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 ) /
...@@ -354,6 +407,7 @@ void mbpfan() ...@@ -354,6 +407,7 @@ void mbpfan()
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);
} }
...@@ -363,10 +417,12 @@ void mbpfan() ...@@ -363,10 +417,12 @@ void mbpfan()
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);
} }
} }
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
* *
*/ */
#ifndef _MBPFAN_H_
#define _MBPFAN_H_
/** Basic fan speed parameters /** Basic fan speed parameters
*/ */
extern int min_fan_speed; extern int min_fan_speed;
...@@ -83,3 +86,5 @@ unsigned short get_temp(t_sensors* sensors); ...@@ -83,3 +86,5 @@ unsigned short get_temp(t_sensors* sensors);
* Main Program * Main Program
*/ */
void mbpfan(); void mbpfan();
#endif
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include <limits.h> #include <limits.h>
#include "global.h"
#include "mbpfan.h" #include "mbpfan.h"
#include "settings.h" #include "settings.h"
#include "minunit.h" #include "minunit.h"
...@@ -10,32 +11,41 @@ ...@@ -10,32 +11,41 @@
int tests_run = 0; int tests_run = 0;
static char *test_sensor_paths() static const 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 const 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;
} }
...@@ -46,8 +56,11 @@ unsigned time_seed() ...@@ -46,8 +56,11 @@ unsigned time_seed()
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;
} }
...@@ -56,17 +69,19 @@ unsigned time_seed() ...@@ -56,17 +69,19 @@ unsigned time_seed()
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() ); srand ( time_seed() );
n--; n--;
} }
f--; f--;
n = f; n = f;
} }
} }
static char *test_get_temp() static const 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);
...@@ -78,21 +93,24 @@ static char *test_get_temp() ...@@ -78,21 +93,24 @@ static char *test_get_temp()
return 0; return 0;
} }
static char *test_config_file() static const char *test_config_file()
{ {
FILE *f = NULL; FILE *f = NULL;
Settings *settings = NULL; Settings *settings = NULL;
f = fopen("/etc/mbpfan.conf", "r"); f = fopen("/etc/mbpfan.conf", "r");
mu_assert("No config file found", f != NULL); mu_assert("No config file found", f != NULL);
if (f == NULL) if (f == NULL) {
return 0; return 0;
}
settings = settings_open(f); settings = settings_open(f);
fclose(f); fclose(f);
mu_assert("Could not read settings from config file", settings != NULL); mu_assert("Could not read settings from config file", settings != NULL);
if (settings == NULL)
if (settings == NULL) {
return 0; 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 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 max_fan_speed from config file",settings_get_int(settings, "general", "max_fan_speed") != 0);
...@@ -107,7 +125,7 @@ static char *test_config_file() ...@@ -107,7 +125,7 @@ static char *test_config_file()
} }
static char *all_tests() static const 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);
...@@ -120,12 +138,15 @@ int tests() ...@@ -120,12 +138,15 @@ 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(); const char *result = all_tests();
if (result != 0) { if (result != 0) {
printf("%s \n", result); printf("%s \n", result);
} else { } else {
printf("ALL TESTS PASSED\n"); 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;
......
/** /**
* This is the MinUnit testing framework - http://www.jera.com/techinfo/jtns/jtn002.html * This is the MinUnit testing framework - http://www.jera.com/techinfo/jtns/jtn002.html
*/ */
#define mu_assert(message, test) do { if (!(test)) return message; } while (0)
#define mu_run_test(test) do { char *message = test(); tests_run++; \
if (message) return message; } while (0)
struct s_sensors { #ifndef _MINUNIT_H_
char* path; #define _MINUNIT_H_
char* fan_output_path;
char* fan_manual_path;
unsigned int temperature;
struct s_sensors *next;
};
typedef s_sensors t_sensors;
#define mu_assert(message, test) do { if (!(test)) return message; } while (0)
#define mu_run_test(test) do { const char *message = test(); tests_run++; \
if (message) return message; } while (0)
extern int tests_run; extern int tests_run;
static char *test_sensor_paths(); static const char *test_sensor_paths();
static char *test_fan_paths(); static const char *test_fan_paths();
static char *test_get_temp(); static const char *test_get_temp();
static char *test_config_file(); static const char *test_config_file();
static char *all_tests(); static const char *all_tests();
int tests(); int tests();
#endif
\ No newline at end of file
...@@ -97,9 +97,11 @@ Settings * settings_new() ...@@ -97,9 +97,11 @@ 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;
...@@ -113,17 +115,22 @@ void settings_delete(Settings *settings) ...@@ -113,17 +115,22 @@ void settings_delete(Settings *settings)
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);
} }
...@@ -139,20 +146,26 @@ Settings * settings_open(FILE *stream) ...@@ -139,20 +146,26 @@ Settings * settings_open(FILE *stream)
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;
} }
...@@ -165,12 +178,15 @@ int settings_save(const Settings *settings, FILE *stream) ...@@ -165,12 +178,15 @@ int settings_save(const Settings *settings, FILE *stream)
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);
...@@ -179,6 +195,7 @@ int settings_save(const Settings *settings, FILE *stream) ...@@ -179,6 +195,7 @@ int settings_save(const Settings *settings, FILE *stream)
i++; i++;
fputs("\n", stream); fputs("\n", stream);
} }
return 0; return 0;
} }
...@@ -189,10 +206,13 @@ int settings_get(const Settings *settings, const char *section, const char *key, ...@@ -189,10 +206,13 @@ int settings_get(const Settings *settings, const char *section, const char *key,
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);
} }
...@@ -203,6 +223,7 @@ int settings_get_int(const Settings *settings, const char *section, const char * ...@@ -203,6 +223,7 @@ int settings_get_int(const Settings *settings, const char *section, const char *
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;
} }
...@@ -213,6 +234,7 @@ long settings_get_long(const Settings *settings, const char *section, const char ...@@ -213,6 +234,7 @@ long settings_get_long(const Settings *settings, const char *section, const char
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;
} }
...@@ -223,6 +245,7 @@ double settings_get_double(const Settings *settings, const char *section, const ...@@ -223,6 +245,7 @@ double settings_get_double(const Settings *settings, const char *section, const
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;
} }
...@@ -248,36 +271,47 @@ int settings_set(Settings *settings, const char *section, const char *key, const ...@@ -248,36 +271,47 @@ int settings_set(Settings *settings, const char *section, const char *key, const
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);
} }
...@@ -288,10 +322,13 @@ int settings_section_get_count(const Settings *settings, const char *section) ...@@ -288,10 +322,13 @@ int settings_section_get_count(const Settings *settings, const char *section)
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);
} }
...@@ -300,9 +337,11 @@ int settings_section_enum(const Settings *settings, const char *section, setting ...@@ -300,9 +337,11 @@ int settings_section_enum(const Settings *settings, const char *section, setting
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);
} }
...@@ -318,19 +357,24 @@ static void trim_str(const char *str, char *out_buf) ...@@ -318,19 +357,24 @@ static void trim_str(const char *str, char *out_buf)
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';
} }
...@@ -355,39 +399,54 @@ static int parse_str(Settings *settings, char *str, ParseState *parse_state) ...@@ -355,39 +399,54 @@ static int parse_str(Settings *settings, char *str, ParseState *parse_state)
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)) { } else if (is_comment_str(str)) {
return 1; return 1;
} else if (is_section_str(str)) { } else if (is_section_str(str)) {
result = get_section_from_str(str, buf, sizeof(buf)); result = get_section_from_str(str, buf, sizeof(buf));
if (!result) { if (!result) {
return 0; return 0;
} }
if (strlen(buf) + 1 > parse_state->current_section_n) { if (strlen(buf) + 1 > parse_state->current_section_n) {
return 0; return 0;
} }
strcpy(parse_state->current_section, buf); strcpy(parse_state->current_section, buf);
parse_state->has_section = 1; parse_state->has_section = 1;
return 1; return 1;
} else if (is_key_value_str(str)) { } else if (is_key_value_str(str)) {
result = get_key_value_from_str(str, buf1, sizeof(buf1), buf2, sizeof(buf2)); result = get_key_value_from_str(str, buf1, sizeof(buf1), buf2, sizeof(buf2));
if (!result) { if (!result) {
return 0; return 0;
} }
if (!parse_state->has_section) { if (!parse_state->has_section) {
return 0; return 0;
} }
return settings_set(settings, parse_state->current_section, buf1, buf2); return settings_set(settings, parse_state->current_section, buf1, buf2);
} else if (is_key_without_value_str(str)) { } else if (is_key_without_value_str(str)) {
result = get_key_without_value_from_str(str, buf, sizeof(buf)); result = get_key_without_value_from_str(str, buf, sizeof(buf));
if (!result) { if (!result) {
return 0; return 0;
} }
if (!parse_state->has_section) { if (!parse_state->has_section) {
return 0; return 0;
} }
return settings_set(settings, parse_state->current_section, buf, ""); return settings_set(settings, parse_state->current_section, buf, "");
} else { } else {
return 0; return 0;
} }
...@@ -410,8 +469,10 @@ static int is_blank_str(const char *str) ...@@ -410,8 +469,10 @@ static int is_blank_str(const char *str)
if (!is_blank_char(*str)) { if (!is_blank_char(*str)) {
return 0; return 0;
} }
str++; str++;
} }
return 1; return 1;
} }
...@@ -426,6 +487,7 @@ static int is_comment_str(const char *str) ...@@ -426,6 +487,7 @@ static int is_comment_str(const char *str)
*/ */
return 1; return 1;
} }
return 0; return 0;
} }
...@@ -438,13 +500,16 @@ static int is_section_str(const char *str) ...@@ -438,13 +500,16 @@ static int is_section_str(const char *str)
/* 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;
} }
...@@ -457,13 +522,16 @@ static int is_key_value_str(const char *str) ...@@ -457,13 +522,16 @@ static int is_key_value_str(const char *str)
/* 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;
} }
...@@ -476,13 +544,16 @@ static int is_key_without_value_str(const char *str) ...@@ -476,13 +544,16 @@ static int is_key_without_value_str(const char *str)
/* 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;
} }
...@@ -497,20 +568,24 @@ static int get_section_from_str(const char *str, char *out_buf, unsigned int out ...@@ -497,20 +568,24 @@ static int get_section_from_str(const char *str, char *out_buf, unsigned int out
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;
} }
...@@ -526,6 +601,7 @@ static int get_key_value_from_str(const char *str, char *out_buf1, unsigned int ...@@ -526,6 +601,7 @@ static int get_key_value_from_str(const char *str, char *out_buf1, unsigned int
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.
...@@ -535,34 +611,42 @@ static int get_key_value_from_str(const char *str, char *out_buf1, unsigned int ...@@ -535,34 +611,42 @@ static int get_key_value_from_str(const char *str, char *out_buf1, unsigned int
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.
...@@ -570,16 +654,19 @@ static int get_key_value_from_str(const char *str, char *out_buf1, unsigned int ...@@ -570,16 +654,19 @@ static int get_key_value_from_str(const char *str, char *out_buf1, unsigned int
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;
} }
...@@ -593,6 +680,7 @@ static int get_key_without_value_from_str(const char *str, char *out_buf, unsign ...@@ -593,6 +680,7 @@ static int get_key_without_value_from_str(const char *str, char *out_buf, unsign
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.
...@@ -602,16 +690,19 @@ static int get_key_without_value_from_str(const char *str, char *out_buf, unsign ...@@ -602,16 +690,19 @@ static int get_key_without_value_from_str(const char *str, char *out_buf, unsign
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;
} }
...@@ -638,6 +729,7 @@ static const char * get_token(char *str, char delim, char **last) ...@@ -638,6 +729,7 @@ 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.
...@@ -645,17 +737,20 @@ static const char * get_token(char *str, char delim, char **last) ...@@ -645,17 +737,20 @@ static const char * get_token(char *str, char delim, char **last)
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;
} }
...@@ -673,6 +768,7 @@ static int get_converted_value(const Settings *settings, const char *section, co ...@@ -673,6 +768,7 @@ static int get_converted_value(const Settings *settings, const char *section, co
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);
...@@ -684,6 +780,7 @@ static int get_converted_value(const Settings *settings, const char *section, co ...@@ -684,6 +780,7 @@ static int get_converted_value(const Settings *settings, const char *section, co
*((double *)out) = atof(value); *((double *)out) = atof(value);
return 1; return 1;
} }
return 0; return 0;
} }
...@@ -704,14 +801,18 @@ static int get_converted_tuple(const Settings *settings, const char *section, co ...@@ -704,14 +801,18 @@ static int get_converted_tuple(const Settings *settings, const char *section, co
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.
*/ */
...@@ -729,8 +830,10 @@ static int get_converted_tuple(const Settings *settings, const char *section, co ...@@ -729,8 +830,10 @@ static int get_converted_tuple(const Settings *settings, const char *section, co
default: default:
return 0; return 0;
} }
count++; count++;
} }
return 1; return 1;
} }
...@@ -745,15 +848,19 @@ static Section * get_section(Section *sections, unsigned int n, const char *name ...@@ -745,15 +848,19 @@ static Section * get_section(Section *sections, unsigned int n, const char *name
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;
} }
...@@ -769,10 +876,13 @@ static void enum_map(const char *key, const char *value, const void *obj) ...@@ -769,10 +876,13 @@ static void enum_map(const char *key, const char *value, const void *obj)
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);
......
...@@ -62,15 +62,19 @@ StrMap * sm_new(unsigned int capacity) ...@@ -62,15 +62,19 @@ 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;
} }
...@@ -84,23 +88,28 @@ void sm_delete(StrMap *map) ...@@ -84,23 +88,28 @@ void sm_delete(StrMap *map)
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);
} }
...@@ -114,24 +123,31 @@ int sm_get(const StrMap *map, const char *key, char *out_buf, unsigned int n_out ...@@ -114,24 +123,31 @@ int sm_get(const StrMap *map, const char *key, char *out_buf, unsigned int n_out
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;
} }
...@@ -145,15 +161,19 @@ int sm_exists(const StrMap *map, const char *key) ...@@ -145,15 +161,19 @@ int sm_exists(const StrMap *map, const char *key)
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;
} }
...@@ -168,14 +188,17 @@ int sm_put(StrMap *map, const char *key, const char *value) ...@@ -168,14 +188,17 @@ int sm_put(StrMap *map, const char *key, const char *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.
*/ */
...@@ -188,50 +211,64 @@ int sm_put(StrMap *map, const char *key, const char *value) ...@@ -188,50 +211,64 @@ int sm_put(StrMap *map, const char *key, const char *value)
* 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;
...@@ -252,22 +289,27 @@ int sm_get_count(const StrMap *map) ...@@ -252,22 +289,27 @@ int sm_get_count(const StrMap *map)
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;
} }
...@@ -280,24 +322,30 @@ int sm_enum(const StrMap *map, sm_enum_func enum_func, const void *obj) ...@@ -280,24 +322,30 @@ int sm_enum(const StrMap *map, sm_enum_func enum_func, const void *obj)
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;
} }
...@@ -311,20 +359,25 @@ static Pair * get_pair(Bucket *bucket, const char *key) ...@@ -311,20 +359,25 @@ static Pair * get_pair(Bucket *bucket, const char *key)
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;
} }
...@@ -339,6 +392,7 @@ static unsigned long hash(const char *str) ...@@ -339,6 +392,7 @@ static unsigned long hash(const char *str)
while (c = *str++) { while (c = *str++) {
hash = ((hash << 5) + hash) + c; hash = ((hash << 5) + hash) + c;
} }
return hash; return hash;
} }
......
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