Commit fcf18f52 authored by Daniel Graziotin's avatar Daniel Graziotin

Cleanup, reformatting, better Makefile and better README

parent 90e6378a
......@@ -3,7 +3,7 @@ MAINTAINERS AND CONTRIBUTORS
Daniel Graziotin <dgraziotin AT task3 DOT cc>
Ismail Khatib <ikhatib AT gmail DOT com>
Trevor Joynson
ORIGINARY AUTHORS
-----------------
......
......@@ -54,37 +54,24 @@ all: $(OBJS)
clean:
rm -rf $(SOURCE_PATH)*.$(OBJ) $(EXE)
tests:
make install
sudo /usr/sbin/mbpfan -f -v -t
install:
make
cp $(EXE) /usr/sbin
cp -n $(CONF) /etc
@echo "-----------------------------------------------------------------------------"
@echo "An init file suitable for /lib/lsb/init-functions (Debian & Ubuntu for sure)"
@echo "is located in the main folder of the source files, called mbpfan.init.debian"
@echo "Rename it to mbpfan, give it execution permissions (chmod +x mbpfan)"
@echo "and move it to /etc/init.d"
@echo "Then, add it to the default runlevels with sudo update-rc.d mbpfan defaults"
@echo ""
@echo "Additionally, an init file suitable for /etc/rc.d/init.d/functions"
@echo "(RHEL/CentOS & Fedora) is also located at the same place, this file is called"
@echo "mbpfan.init.redhat. Also rename it to mbpfan, give it execution permissions"
@echo "and move it to /etc/init.d"
@echo "To add the script to the default runlevels, run the following as root:"
@echo "chkconfig --level 2345 mbpfan on && chkconfig --level 016 mbpfan off"
@echo "******************"
@echo "INSTALL COMPLETED"
@echo "******************"
@echo ""
@echo "A configuration file has been copied to /etc/mbpfan.conf"
@echo "See README.md file to have mbpfan automatically started at system boot."
@echo ""
@echo "Please run the tests now with the command"
@echo " sudo make tests"
@echo ""
@echo "For upstart based init systems (Ubuntu), an example upstart job has been"
@echo "provided for use in place of the LSB-style init script. To use, execute"
@echo "as root:"
@echo "cp mbpfan.upstart /etc/init/mbpfan.conf"
@echo "start mbpfan"
@echo "As a special bonus, a service file for systemd is also included. To use it,"
@echo "execute the following as root:"
@echo "cp mbpfan.service /usr/lib/systemd/system"
@echo "ln -s /usr/lib/systemd/system/mbpfan.service /etc/systemd/system/mbpfan.service"
@echo "systemctl daemon-reload"
@echo "systemctl start mbpfan.service"
@echo "To start the service automatically at boot, also execute the following:"
@echo "systemctl enable mbpfan.service"
@echo "-----------------------------------------------------------------------------"
rebuild: clean all
#rebuild is not entirely correct
......@@ -3,7 +3,6 @@ Fan-Control-Daemon
Introduction
---------------------
This is an enhanced version of [rvega's Fan-Control-Daemon](https://github.com/rvega/Fan-Control-Daemon),
which itself is an enhanced version of [Allan McRae mbpfan](http://allanmcrae.com/2010/05/simple-macbook-pro-fan-daemon/)
......@@ -15,43 +14,36 @@ This enhanced version assumes any number of processors and fans (max. 10).
* It requires root use
* It daemonizes or stays in foreground
* Verbose mode for both syslog and stdout
* Users can configure it using the file /etc/mbpfan.conf
Compile Instructions
---------------------
Compile with
make
Manually compile with
gcc -o bin/mbpfan src/mbpfan.c -lm
Run The Tests (Recommended)
---------------------------
It is recommended to run the tests before installing the program
sudo ./bin/mbpfan -t
Install Instructions
--------------------
Install with
sudo make install
It actually copies mbpfan to /usr/sbin.
It copies mbpfan to /usr/sbin and mbpfan.conf to /etc
An init file suitable for /lib/lsb/init-functions (Debian & Ubuntu fur sure)
is located in the main folder of the source files. It is called mbpfan.init.debian
Rename it to mbpfan, give it execution permissions (chmod +x mbpfan)
and move it to /etc/init.d
Then, add it to the default runlevels with sudo update-rc.d mbpfan defaults (Ubuntu example)
An init file suitable for Fedora (and probably RedHat) can be found
in the file mbpfan.init.fedora
Run The Tests (Recommended)
---------------------------
It is recommended to run the tests after installing the program
sudo ./bin/mbpfan -t
or
sudo make tests
Run Instructions
---------------------
----------------
If not installed, run with
sudo bin/mbpfan
......@@ -61,9 +53,39 @@ sudo mbpfan
If installed and using the init file, run with (Ubuntu example)
sudo service mbpfan start
Starting at boot
----------------
An init file suitable for /lib/lsb/init-functions (Debian & Ubuntu for sure)
is located in the main folder of the source files, called mbpfan.init.debian
Rename it to mbpfan, give it execution permissions (chmod +x mbpfan)
and move it to /etc/init.d
Then, add it to the default runlevels with sudo update-rc.d mbpfan defaults
Additionally, an init file suitable for /etc/rc.d/init.d/functions
(RHEL/CentOS & Fedora) is also located at the same place, this file is called
mbpfan.init.redhat. Also rename it to mbpfan, give it execution permissions
and move it to /etc/init.d
To add the script to the default runlevels, run the following as root:
chkconfig --level 2345 mbpfan on && chkconfig --level 016 mbpfan off
For upstart based init systems (Ubuntu), an example upstart job has been
provided for use in place of the LSB-style init script. To use, execute
as root:
cp mbpfan.upstart /etc/init/mbpfan.conf
start mbpfan
As a special bonus, a service file for systemd is also included. To use it,
execute the following as root:
cp mbpfan.service /usr/lib/systemd/system
ln -s /usr/lib/systemd/system/mbpfan.service /etc/systemd/system/mbpfan.service
systemctl daemon-reload
systemctl start mbpfan.service
To start the service automatically at boot, also execute the following:
systemctl enable mbpfan.service
Usage
-------
Usage: ./mbpfan OPTION(S)
-h Show the help screen
-f Run in foreground
......@@ -78,7 +100,6 @@ GNU General Public License version 3
Based On
---------------------
* http://allanmcrae.com/2010/05/simple-macbook-pro-fan-daemon/
* http://allanmcrae.com/2011/08/mbp-fan-daemon-update/
* https://launchpad.net/macfanctld
......
......@@ -32,175 +32,151 @@
int write_pid(int pid)
{
FILE *file = NULL;
file = fopen(program_pid, "w");
if(file != NULL)
{
fprintf(file, "%d", pid);
fclose(file);
return 1;
}
else
{
return 0;
FILE *file = NULL;
file = fopen(program_pid, "w");
if(file != NULL) {
fprintf(file, "%d", pid);
fclose(file);
return 1;
} else {
return 0;
}
}
int read_pid()
{
FILE *file = NULL;
int pid = -1;
file = fopen(program_pid, "r");
if(file != NULL)
{
fscanf(file, "%d", &pid);
fclose(file);
return pid;
FILE *file = NULL;
int pid = -1;
file = fopen(program_pid, "r");
if(file != NULL) {
fscanf(file, "%d", &pid);
fclose(file);
return pid;
}
return -1;
return -1;
}
int delete_pid()
{
return remove(program_pid);
return remove(program_pid);
}
void signal_handler(int signal)
{
switch(signal)
{
switch(signal) {
case SIGHUP:
//TODO: restart myself
syslog(LOG_WARNING, "Received SIGHUP signal.");
delete_pid();
exit(0);
break;
//TODO: restart myself
syslog(LOG_WARNING, "Received SIGHUP signal.");
delete_pid();
exit(0);
break;
case SIGTERM:
syslog(LOG_WARNING, "Received SIGTERM signal.");
delete_pid();
//TODO: free resources
exit(0);
break;
syslog(LOG_WARNING, "Received SIGTERM signal.");
delete_pid();
//TODO: free resources
exit(0);
break;
case SIGINT:
syslog(LOG_WARNING, "Received SIGINT signal.");
delete_pid();
//TODO: free resources
exit(0);
syslog(LOG_WARNING, "Received SIGINT signal.");
delete_pid();
//TODO: free resources
exit(0);
default:
syslog(LOG_WARNING, "Unhandled signal (%d) %s", signal, strsignal(signal));
break;
syslog(LOG_WARNING, "Unhandled signal (%d) %s", signal, strsignal(signal));
break;
}
}
void go_daemon(void (*fan_control)())
{
// Setup signal handling before we start
signal(SIGHUP, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
// Setup signal handling before we start
signal(SIGHUP, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
syslog(LOG_INFO, "%s starting up", program_name);
syslog(LOG_INFO, "%s starting up", program_name);
// Setup syslog logging - see SETLOGMASK(3)
if(verbose)
{
setlogmask(LOG_UPTO(LOG_DEBUG));
openlog(program_name, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
}
else
{
setlogmask(LOG_UPTO(LOG_INFO));
openlog(program_name, LOG_CONS, LOG_USER);
// Setup syslog logging - see SETLOGMASK(3)
if(verbose) {
setlogmask(LOG_UPTO(LOG_DEBUG));
openlog(program_name, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
} else {
setlogmask(LOG_UPTO(LOG_INFO));
openlog(program_name, LOG_CONS, LOG_USER);
}
pid_t pid_slave;
pid_t sid_slave;
pid_t pid_slave;
pid_t sid_slave;
if (daemonize)
{
if (daemonize) {
pid_slave = fork();
if (pid_slave < 0)
{
exit(EXIT_FAILURE);
pid_slave = fork();
if (pid_slave < 0) {
exit(EXIT_FAILURE);
}
if (pid_slave > 0)
{
// kill the father
exit(EXIT_SUCCESS);
if (pid_slave > 0) {
// kill the father
exit(EXIT_SUCCESS);
}
umask(0022);
umask(0022);
// new sid_slave for the child process
sid_slave = setsid();
if (sid_slave < 0)
{
exit(EXIT_FAILURE);
// new sid_slave for the child process
sid_slave = setsid();
if (sid_slave < 0) {
exit(EXIT_FAILURE);
}
if ((chdir("/")) < 0)
{
exit(EXIT_FAILURE);
if ((chdir("/")) < 0) {
exit(EXIT_FAILURE);
}
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
int current_pid = getpid();
int current_pid = getpid();
if (read_pid() == -1)
{
if (verbose)
{
printf("Writing a new .pid file with value %d at: %s\n", current_pid, program_pid);
syslog(LOG_INFO, "Writing a new .pid file with value %d at: %s", current_pid, program_pid);
if (read_pid() == -1) {
if (verbose) {
printf("Writing a new .pid file with value %d at: %s\n", current_pid, program_pid);
syslog(LOG_INFO, "Writing a new .pid file with value %d at: %s", current_pid, program_pid);
}
if (write_pid(current_pid) == 0)
{
syslog(LOG_ERR, "Can not create a .pid file at: %s. Aborting", program_pid);
if (verbose)
{
printf("ERROR: Can not create a .pid file at: %s. Aborting\n", program_pid);
if (write_pid(current_pid) == 0) {
syslog(LOG_ERR, "Can not create a .pid file at: %s. Aborting", program_pid);
if (verbose) {
printf("ERROR: Can not create a .pid file at: %s. Aborting\n", program_pid);
}
exit(EXIT_FAILURE);
}
else
{
if (verbose)
{
printf("Successfully written a new .pid file with value %d at: %s\n", current_pid, program_pid);
syslog(LOG_INFO, "Successfully written a new .pid file with value %d at: %s", current_pid, program_pid);
exit(EXIT_FAILURE);
} else {
if (verbose) {
printf("Successfully written a new .pid file with value %d at: %s\n", current_pid, program_pid);
syslog(LOG_INFO, "Successfully written a new .pid file with value %d at: %s", current_pid, program_pid);
}
}
}
else
{
syslog(LOG_ERR, "A previously created .pid file exists at: %s. Aborting", program_pid);
if (verbose)
{
printf("ERROR: a previously created .pid file exists at: %s.\n Aborting\n", program_pid);
} else {
syslog(LOG_ERR, "A previously created .pid file exists at: %s. Aborting", program_pid);
if (verbose) {
printf("ERROR: a previously created .pid file exists at: %s.\n Aborting\n", program_pid);
}
exit(EXIT_FAILURE);
exit(EXIT_FAILURE);
}
fan_control();
fan_control();
if(daemonize)
{
syslog(LOG_INFO, "%s daemon exiting", program_name);
if(daemonize) {
syslog(LOG_INFO, "%s daemon exiting", program_name);
}
return;
return;
}
......@@ -29,15 +29,14 @@ const char *program_pid = "/var/run/mbpfan.pid";
void print_usage(int argc, char *argv[])
{
if (argc >=1)
{
printf("Usage: %s OPTION(S) \n", argv[0]);
printf("Options:\n");
printf("\t-h Show this help screen\n");
printf("\t-f Run in foreground\n");
printf("\t-t Run the tests\n");
printf("\t-v Be (a lot) verbose\n");
printf("\n");
if (argc >=1) {
printf("Usage: %s OPTION(S) \n", argv[0]);
printf("Options:\n");
printf("\t-h Show this help screen\n");
printf("\t-f Run in foreground\n");
printf("\t-t Run the tests\n");
printf("\t-v Be (a lot) verbose\n");
printf("\n");
}
}
......@@ -46,34 +45,32 @@ void print_usage(int argc, char *argv[])
int main(int argc, char *argv[])
{
int c;
while( (c = getopt(argc, argv, "hftv|help")) != -1)
{
switch(c)
{
int c;
while( (c = getopt(argc, argv, "hftv|help")) != -1) {
switch(c) {
case 'h':
print_usage(argc, argv);
exit(0);
break;
print_usage(argc, argv);
exit(0);
break;
case 'f':
daemonize = 0;
break;
daemonize = 0;
break;
case 't':
tests();
exit(0);
break;
tests();
exit(0);
break;
case 'v':
verbose = 1;
break;
verbose = 1;
break;
default:
print_usage(argc, argv);
exit(0);
break;
print_usage(argc, argv);
exit(0);
break;
}
}
// pointer to mbpfan() function in mbpfan.c
void (*fan_control)() = mbpfan;
go_daemon(fan_control);
exit(0);
// pointer to mbpfan() function in mbpfan.c
void (*fan_control)() = mbpfan;
go_daemon(fan_control);
exit(0);
}
\ No newline at end of file
This diff is collapsed.
......@@ -37,6 +37,13 @@ extern int polling_interval;
struct s_sensors;
typedef struct s_sensors t_sensors;
/**
* Tries to use the settings located in
* /etc/mbpfan.conf
* If it fails, the default hardcoded settings are used
*/
void retrieve_settings();
/**
* Detect the sensors in /sys/devices/platform/coretemp.0/temp
* Return a linked list of t_sensors (first temperature detected)
......
......@@ -4,117 +4,139 @@
#include <time.h>
#include <limits.h>
#include "mbpfan.h"
#include "settings.h"
#include "minunit.h"
int tests_run = 0;
struct s_sensors
{
char* path;
char* fan_output_path;
char* fan_manual_path;
unsigned int temperature;
struct s_sensors *next;
struct s_sensors {
char* path;
char* fan_output_path;
char* fan_manual_path;
unsigned int temperature;
struct s_sensors *next;
};
typedef s_sensors t_sensors;
static char *test_sensor_paths()
{
t_sensors* sensors = retrieve_sensors();
mu_assert("No sensors found", sensors != NULL);
t_sensors* tmp = sensors;
while(tmp != NULL)
{
mu_assert("Sensor does not have a valid path", tmp->path != NULL);
if(tmp->path != NULL)
mu_assert("Sensor does not have valid temperature", tmp->temperature > 0);
tmp = tmp->next;
t_sensors* sensors = retrieve_sensors();
mu_assert("No sensors found", sensors != NULL);
t_sensors* tmp = sensors;
while(tmp != NULL) {
mu_assert("Sensor does not have a valid path", tmp->path != NULL);
if(tmp->path != NULL)
mu_assert("Sensor does not have valid temperature", tmp->temperature > 0);
tmp = tmp->next;
}
return 0;
return 0;
}
static char *test_fan_paths()
{
t_sensors* sensors = retrieve_sensors();
mu_assert("No sensors found", sensors != NULL);
t_sensors* tmp = sensors;
int found_fan_path = 0;
while(tmp != NULL)
{
if(tmp->fan_output_path != NULL)
found_fan_path++;
tmp = tmp->next;
t_sensors* sensors = retrieve_sensors();
mu_assert("No sensors found", sensors != NULL);
t_sensors* tmp = sensors;
int found_fan_path = 0;
while(tmp != NULL) {
if(tmp->fan_output_path != NULL)
found_fan_path++;
tmp = tmp->next;
}
mu_assert("No fans found", found_fan_path != 0);
return 0;
mu_assert("No fans found", found_fan_path != 0);
return 0;
}
unsigned time_seed()
{
time_t now = time ( 0 );
unsigned char *p = (unsigned char *)&now;
unsigned seed = 0;
size_t i;
for ( i = 0; i < sizeof now; i++ )
seed = seed * ( UCHAR_MAX + 2U ) + p[i];
return seed;
time_t now = time ( 0 );
unsigned char *p = (unsigned char *)&now;
unsigned seed = 0;
size_t i;
for ( i = 0; i < sizeof now; i++ )
seed = seed * ( UCHAR_MAX + 2U ) + p[i];
return seed;
}
// nothing better than a horrible piece of code to
// stress a little bit the CPU
int stress(int n)
{
int f = n;
while (f > 0)
{
while(n > 0)
{
srand ( time_seed() );
n--;
int f = n;
while (f > 0) {
while(n > 0) {
srand ( time_seed() );
n--;
}
f--;
n = f;
f--;
n = f;
}
}
static char *test_get_temp()
{
t_sensors* sensors = retrieve_sensors();
mu_assert("No sensors found", sensors != NULL);
unsigned short temp_1 = get_temp(sensors);
mu_assert("Invalid Global Temperature Found", temp_1 > 1 && temp_1 < 150);
stress(2000);
unsigned short temp_2 = get_temp(sensors);
mu_assert("Invalid Higher temp test (if fan was already spinning high, this is not worrying)", temp_1 < temp_2);
return 0;
t_sensors* sensors = retrieve_sensors();
mu_assert("No sensors found", sensors != NULL);
unsigned short temp_1 = get_temp(sensors);
mu_assert("Invalid Global Temperature Found", temp_1 > 1 && temp_1 < 150);
stress(2000);
unsigned short temp_2 = get_temp(sensors);
mu_assert("Invalid Higher temp test (if fan was already spinning high, this is not worrying)", temp_1 < temp_2);
return 0;
}
static char *test_config_file()
{
FILE *f = NULL;
Settings *settings = NULL;
f = fopen("/etc/mbpfan.conf", "r");
mu_assert("No config file found", f != NULL);
if (f == NULL)
return 0;
settings = settings_open(f);
fclose(f);
mu_assert("Could not read settings from config file", settings != NULL);
if (settings == NULL)
return 0;
mu_assert("Could not read min_fan_speed from config file",settings_get_int(settings, "general", "min_fan_speed") != 0);
mu_assert("Could not read max_fan_speed from config file",settings_get_int(settings, "general", "max_fan_speed") != 0);
mu_assert("Could not read low_temp from config file",settings_get_int(settings, "general", "low_temp") != 0);
mu_assert("Could not read high_temp from config file",settings_get_int(settings, "general", "high_temp") != 0);
mu_assert("Could not read max_temp from config file",settings_get_int(settings, "general", "max_temp") != 0);
mu_assert("Could not read polling_interval from config file",settings_get_int(settings, "general", "polling_interval") != 0);
/* Destroy the settings object */
settings_delete(settings);
return 0;
}
static char *all_tests()
{
mu_run_test(test_sensor_paths);
mu_run_test(test_fan_paths);
mu_run_test(test_get_temp);
return 0;
mu_run_test(test_sensor_paths);
mu_run_test(test_fan_paths);
mu_run_test(test_get_temp);
mu_run_test(test_config_file);
return 0;
}
int tests()
{
printf("Starting the tests..\n");
printf("It is normal for them to take a bit to finish.\n");
char *result = all_tests();
if (result != 0)
{
printf("%s \n", result);
}
else
{
printf("ALL TESTS PASSED\n");
printf("Starting the tests..\n");
printf("It is normal for them to take a bit to finish.\n");
char *result = all_tests();
if (result != 0) {
printf("%s \n", result);
} else {
printf("ALL TESTS PASSED\n");
}
printf("Tests run: %d\n", tests_run);
printf("Tests run: %d\n", tests_run);
return result != 0;
return result != 0;
}
\ No newline at end of file
......@@ -10,6 +10,7 @@ extern int tests_run;
static char *test_sensor_paths();
static char *test_fan_paths();
static char *test_get_temp();
static char *test_config_file();
static char *all_tests();
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -6,13 +6,13 @@
* Version history:
* 1.0.0 - initial release
* 2.0.0 - changed function prefix from strmap to sm to ensure
* ANSI C compatibility
* ANSI C compatibility
*
* strmap.h
*
* Copyright (c) 2009, 2011 Per Ola Kristensson.
*
* Per Ola Kristensson <pok21@cam.ac.uk>
* Per Ola Kristensson <pok21@cam.ac.uk>
* Inference Group, Department of Physics
* University of Cambridge
* Cavendish Laboratory
......@@ -44,139 +44,139 @@ extern "C"
#include <stdlib.h>
#include <string.h>
typedef struct StrMap StrMap;
/*
* This callback function is called once per key-value when enumerating
* all keys associated to values.
*
* Parameters:
*
* key: A pointer to a null-terminated C string. The string must not
* be modified by the client.
*
* value: A pointer to a null-terminated C string. The string must
* not be modified by the client.
*
* obj: A pointer to a client-specific object. This parameter may be
* null.
*
* Return value: None.
*/
typedef void(*sm_enum_func)(const char *key, const char *value, const void *obj);
/*
* Creates a string map.
*
* Parameters:
*
* capacity: The number of top-level slots this string map
* should allocate. This parameter must be > 0.
*
* Return value: A pointer to a string map object,
* or null if a new string map could not be allocated.
*/
StrMap * sm_new(unsigned int capacity);
/*
* Releases all memory held by a string map object.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
* If the supplied string map has been previously released, the
* behaviour of this function is undefined.
*
* Return value: None.
*/
void sm_delete(StrMap *map);
/*
* Returns the value associated with the supplied key.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out_buf: A pointer to an output buffer which will contain the value,
* if it exists and fits into the buffer.
*
* n_out_buf: The size of the output buffer in bytes.
*
* Return value: If out_buf is set to null and n_out_buf is set to 0 the return
* value will be the number of bytes required to store the value (if it exists)
* and its null-terminator. For all other parameter configurations the return value
* is 1 if an associated value was found and completely copied into the output buffer,
* 0 otherwise.
*/
int sm_get(const StrMap *map, const char *key, char *out_buf, unsigned int n_out_buf);
/*
* Queries the existence of a key.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: 1 if the key exists, 0 otherwise.
*/
int sm_exists(const StrMap *map, const char *key);
/*
* Associates a value with the supplied key. If the key is already
* associated with a value, the previous value is replaced.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* key: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* value: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* Return value: 1 if the association succeeded, 0 otherwise.
*/
int sm_put(StrMap *map, const char *key, const char *value);
/*
* Returns the number of associations between keys and values.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* Return value: The number of associations between keys and values.
*/
int sm_get_count(const StrMap *map);
/*
* Enumerates all associations between keys and values.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* enum_func: A pointer to a callback function that will be
* called by this procedure once for every key associated
* with a value. This parameter cannot be null.
*
* obj: A pointer to a client-specific object. This parameter will be
* passed back to the client's callback function. This parameter can
* be null.
*
* Return value: 1 if enumeration completed, 0 otherwise.
*/
int sm_enum(const StrMap *map, sm_enum_func enum_func, const void *obj);
typedef struct StrMap StrMap;
/*
* This callback function is called once per key-value when enumerating
* all keys associated to values.
*
* Parameters:
*
* key: A pointer to a null-terminated C string. The string must not
* be modified by the client.
*
* value: A pointer to a null-terminated C string. The string must
* not be modified by the client.
*
* obj: A pointer to a client-specific object. This parameter may be
* null.
*
* Return value: None.
*/
typedef void(*sm_enum_func)(const char *key, const char *value, const void *obj);
/*
* Creates a string map.
*
* Parameters:
*
* capacity: The number of top-level slots this string map
* should allocate. This parameter must be > 0.
*
* Return value: A pointer to a string map object,
* or null if a new string map could not be allocated.
*/
StrMap * sm_new(unsigned int capacity);
/*
* Releases all memory held by a string map object.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
* If the supplied string map has been previously released, the
* behaviour of this function is undefined.
*
* Return value: None.
*/
void sm_delete(StrMap *map);
/*
* Returns the value associated with the supplied key.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out_buf: A pointer to an output buffer which will contain the value,
* if it exists and fits into the buffer.
*
* n_out_buf: The size of the output buffer in bytes.
*
* Return value: If out_buf is set to null and n_out_buf is set to 0 the return
* value will be the number of bytes required to store the value (if it exists)
* and its null-terminator. For all other parameter configurations the return value
* is 1 if an associated value was found and completely copied into the output buffer,
* 0 otherwise.
*/
int sm_get(const StrMap *map, const char *key, char *out_buf, unsigned int n_out_buf);
/*
* Queries the existence of a key.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: 1 if the key exists, 0 otherwise.
*/
int sm_exists(const StrMap *map, const char *key);
/*
* Associates a value with the supplied key. If the key is already
* associated with a value, the previous value is replaced.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* key: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* value: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* Return value: 1 if the association succeeded, 0 otherwise.
*/
int sm_put(StrMap *map, const char *key, const char *value);
/*
* Returns the number of associations between keys and values.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* Return value: The number of associations between keys and values.
*/
int sm_get_count(const StrMap *map);
/*
* Enumerates all associations between keys and values.
*
* Parameters:
*
* map: A pointer to a string map. This parameter cannot be null.
*
* enum_func: A pointer to a callback function that will be
* called by this procedure once for every key associated
* with a value. This parameter cannot be null.
*
* obj: A pointer to a client-specific object. This parameter will be
* passed back to the client's callback function. This parameter can
* be null.
*
* Return value: 1 if enumeration completed, 0 otherwise.
*/
int sm_enum(const StrMap *map, sm_enum_func enum_func, const void *obj);
#ifdef __cplusplus
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment