Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
Fan-Control-Daemon
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
CeRiAl
Fan-Control-Daemon
Commits
fcf18f52
Commit
fcf18f52
authored
Aug 22, 2012
by
Daniel Graziotin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Cleanup, reformatting, better Makefile and better README
parent
90e6378a
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
1647 additions
and
1678 deletions
+1647
-1678
AUTHORS
AUTHORS
+1
-1
Makefile
Makefile
+14
-27
README.md
README.md
+41
-20
daemon.c
src/daemon.c
+89
-113
main.c
src/main.c
+28
-31
mbpfan.c
src/mbpfan.c
+213
-248
mbpfan.h
src/mbpfan.h
+7
-0
minunit.c
src/minunit.c
+90
-68
minunit.h
src/minunit.h
+1
-0
settings.c
src/settings.c
+492
-498
settings.h
src/settings.h
+287
-287
strmap.c
src/strmap.c
+249
-250
strmap.h
src/strmap.h
+135
-135
No files found.
AUTHORS
View file @
fcf18f52
...
...
@@ -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
-----------------
...
...
Makefile
View file @
fcf18f52
...
...
@@ -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
README.md
View file @
fcf18f52
...
...
@@ -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
...
...
src/daemon.c
View file @
fcf18f52
...
...
@@ -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
;
}
src/main.c
View file @
fcf18f52
...
...
@@ -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
src/mbpfan.c
View file @
fcf18f52
...
...
@@ -58,348 +58,313 @@ int max_temp = 86; // do not set it > 90
int
polling_interval
=
7
;
struct
s_sensors
{
char
*
path
;
char
*
fan_output_path
;
char
*
fan_manual_path
;
unsigned
int
temperature
;
struct
s_sensors
*
next
;
struct
s_sensors
{
char
*
path
;
char
*
fan_output_path
;
char
*
fan_manual_path
;
unsigned
int
temperature
;
struct
s_sensors
*
next
;
};
t_sensors
*
retrieve_sensors
()
{
t_sensors
*
sensors_head
=
NULL
;
t_sensors
*
s
=
NULL
;
char
*
path
=
NULL
;
const
char
*
path_begin
=
"/sys/devices/platform/coretemp.0/temp"
;
const
char
*
path_end
=
"_input"
;
int
path_size
=
strlen
(
path_begin
)
+
strlen
(
path_end
)
+
2
;
char
number
[
1
];
sprintf
(
number
,
"%d"
,
0
);
int
i
=
0
;
for
(
i
=
0
;
i
<
10
;
i
++
)
{
path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
path_size
);
sprintf
(
number
,
"%d"
,
i
);
path
[
0
]
=
'\0'
;
strncat
(
path
,
path_begin
,
strlen
(
path_begin
)
);
strncat
(
path
,
number
,
strlen
(
number
)
);
strncat
(
path
,
path_end
,
strlen
(
path_begin
)
);
FILE
*
file
=
fopen
(
path
,
"r"
);
if
(
file
!=
NULL
)
{
s
=
(
t_sensors
*
)
malloc
(
sizeof
(
t_sensors
)
);
s
->
path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
path_size
);
strcpy
(
s
->
path
,
path
);
fscanf
(
file
,
"%d"
,
&
s
->
temperature
);
if
(
sensors_head
==
NULL
)
{
sensors_head
=
s
;
sensors_head
->
next
=
NULL
;
}
else
{
t_sensors
*
tmp
=
sensors_head
;
while
(
tmp
->
next
!=
NULL
)
{
tmp
=
tmp
->
next
;
t_sensors
*
sensors_head
=
NULL
;
t_sensors
*
s
=
NULL
;
char
*
path
=
NULL
;
const
char
*
path_begin
=
"/sys/devices/platform/coretemp.0/temp"
;
const
char
*
path_end
=
"_input"
;
int
path_size
=
strlen
(
path_begin
)
+
strlen
(
path_end
)
+
2
;
char
number
[
1
];
sprintf
(
number
,
"%d"
,
0
);
int
i
=
0
;
for
(
i
=
0
;
i
<
10
;
i
++
)
{
path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
path_size
);
sprintf
(
number
,
"%d"
,
i
);
path
[
0
]
=
'\0'
;
strncat
(
path
,
path_begin
,
strlen
(
path_begin
)
);
strncat
(
path
,
number
,
strlen
(
number
)
);
strncat
(
path
,
path_end
,
strlen
(
path_begin
)
);
FILE
*
file
=
fopen
(
path
,
"r"
);
if
(
file
!=
NULL
)
{
s
=
(
t_sensors
*
)
malloc
(
sizeof
(
t_sensors
)
);
s
->
path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
path_size
);
strcpy
(
s
->
path
,
path
);
fscanf
(
file
,
"%d"
,
&
s
->
temperature
);
if
(
sensors_head
==
NULL
)
{
sensors_head
=
s
;
sensors_head
->
next
=
NULL
;
}
else
{
t_sensors
*
tmp
=
sensors_head
;
while
(
tmp
->
next
!=
NULL
)
{
tmp
=
tmp
->
next
;
}
tmp
->
next
=
s
;
tmp
->
next
->
next
=
NULL
;
tmp
->
next
=
s
;
tmp
->
next
->
next
=
NULL
;
}
fclose
(
file
);
fclose
(
file
);
}
free
(
path
);
path
=
NULL
;
free
(
path
);
path
=
NULL
;
}
if
(
sensors_head
!=
NULL
)
find_fans
(
sensors_head
);
return
sensors_head
;
if
(
sensors_head
!=
NULL
)
find_fans
(
sensors_head
);
return
sensors_head
;
}
void
find_fans
(
t_sensors
*
sensors
)
{
t_sensors
*
tmp
=
sensors
;
t_sensors
*
tmp
=
sensors
;
char
*
path_output
=
NULL
;
char
*
path_manual
=
NULL
;
char
*
path_output
=
NULL
;
char
*
path_manual
=
NULL
;
const
char
*
path_begin
=
"/sys/devices/platform/applesmc.768/fan"
;
const
char
*
path_output_end
=
"_output"
;
const
char
*
path_man_end
=
"_manual"
;
const
char
*
path_begin
=
"/sys/devices/platform/applesmc.768/fan"
;
const
char
*
path_output_end
=
"_output"
;
const
char
*
path_man_end
=
"_manual"
;
int
path_min_size
=
strlen
(
path_begin
)
+
strlen
(
path_output_end
)
+
2
;
int
path_man_size
=
strlen
(
path_begin
)
+
strlen
(
path_man_end
)
+
2
;
char
number
[
1
];
sprintf
(
number
,
"%d"
,
0
);
int
path_min_size
=
strlen
(
path_begin
)
+
strlen
(
path_output_end
)
+
2
;
int
path_man_size
=
strlen
(
path_begin
)
+
strlen
(
path_man_end
)
+
2
;
char
number
[
1
];
sprintf
(
number
,
"%d"
,
0
);
int
n_sensors
=
0
;
int
n_fans
=
0
;
int
n_sensors
=
0
;
int
n_fans
=
0
;
for
(
n_sensors
=
0
;
n_sensors
<
10
;
n_sensors
++
)
{
path_output
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
path_min_size
);
path_output
[
0
]
=
'\0'
;
path_manual
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
path_man_size
);
path_manual
[
0
]
=
'\0'
;
sprintf
(
number
,
"%d"
,
n_sensors
);
for
(
n_sensors
=
0
;
n_sensors
<
10
;
n_sensors
++
)
{
path_output
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
path_min_size
);
path_output
[
0
]
=
'\0'
;
path_manual
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
path_man_size
);
path_manual
[
0
]
=
'\0'
;
sprintf
(
number
,
"%d"
,
n_sensors
);
strncat
(
path_output
,
path_begin
,
strlen
(
path_begin
)
);
strncat
(
path_output
,
number
,
strlen
(
number
)
);
strncat
(
path_output
,
path_output_end
,
strlen
(
path_begin
)
);
strncat
(
path_output
,
path_begin
,
strlen
(
path_begin
)
);
strncat
(
path_output
,
number
,
strlen
(
number
)
);
strncat
(
path_output
,
path_output_end
,
strlen
(
path_begin
)
);
strncat
(
path_manual
,
path_begin
,
strlen
(
path_begin
)
);
strncat
(
path_manual
,
number
,
strlen
(
number
)
);
strncat
(
path_manual
,
path_man_end
,
strlen
(
path_begin
)
);
strncat
(
path_manual
,
path_begin
,
strlen
(
path_begin
)
);
strncat
(
path_manual
,
number
,
strlen
(
number
)
);
strncat
(
path_manual
,
path_man_end
,
strlen
(
path_begin
)
);
FILE
*
file
=
fopen
(
path_output
,
"r"
);
FILE
*
file
=
fopen
(
path_output
,
"r"
);
if
(
file
!=
NULL
)
{
if
(
tmp
->
path
!=
NULL
)
{
tmp
->
fan_output_path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
path_min_size
);
tmp
->
fan_manual_path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
path_man_size
);
if
(
file
!=
NULL
)
{
if
(
tmp
->
path
!=
NULL
)
{
tmp
->
fan_output_path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
path_min_size
);
tmp
->
fan_manual_path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
path_man_size
);
}
strcpy
(
tmp
->
fan_output_path
,
path_output
);
strcpy
(
tmp
->
fan_manual_path
,
path_manual
);
tmp
=
tmp
->
next
;
n_fans
++
;
fclose
(
file
);
strcpy
(
tmp
->
fan_output_path
,
path_output
);
strcpy
(
tmp
->
fan_manual_path
,
path_manual
);
tmp
=
tmp
->
next
;
n_fans
++
;
fclose
(
file
);
}
}
if
(
verbose
)
{
printf
(
"Found %d: sensors and %d fans
\n
"
,
n_sensors
,
n_fans
);
if
(
daemonize
)
{
syslog
(
LOG_INFO
,
"Found %d: sensors and %d fans"
,
n_sensors
,
n_fans
);
if
(
verbose
)
{
printf
(
"Found %d: sensors and %d fans
\n
"
,
n_sensors
,
n_fans
);
if
(
daemonize
)
{
syslog
(
LOG_INFO
,
"Found %d: sensors and %d fans"
,
n_sensors
,
n_fans
);
}
}
free
(
path_output
);
path_output
=
NULL
;
free
(
path_manual
);
path_manual
=
NULL
;
free
(
path_output
);
path_output
=
NULL
;
free
(
path_manual
);
path_manual
=
NULL
;
}
void
set_fans_man
(
t_sensors
*
sensors
)
{
t_sensors
*
tmp
=
sensors
;
FILE
*
file
;
while
(
tmp
!=
NULL
)
{
file
=
fopen
(
tmp
->
fan_manual_path
,
"rw+"
);
if
(
file
!=
NULL
)
{
fprintf
(
file
,
"%d"
,
1
);
fclose
(
file
);
t_sensors
*
tmp
=
sensors
;
FILE
*
file
;
while
(
tmp
!=
NULL
)
{
file
=
fopen
(
tmp
->
fan_manual_path
,
"rw+"
);
if
(
file
!=
NULL
)
{
fprintf
(
file
,
"%d"
,
1
);
fclose
(
file
);
}
tmp
=
tmp
->
next
;
tmp
=
tmp
->
next
;
}
}
t_sensors
*
refresh_sensors
(
t_sensors
*
sensors
)
{
t_sensors
*
tmp
=
sensors
;
t_sensors
*
tmp
=
sensors
;
while
(
tmp
!=
NULL
)
{
FILE
*
file
=
fopen
(
tmp
->
path
,
"r"
);
while
(
tmp
!=
NULL
)
{
FILE
*
file
=
fopen
(
tmp
->
path
,
"r"
);
if
(
file
!=
NULL
)
{
fscanf
(
file
,
"%d"
,
&
tmp
->
temperature
);
fclose
(
file
);
if
(
file
!=
NULL
)
{
fscanf
(
file
,
"%d"
,
&
tmp
->
temperature
);
fclose
(
file
);
}
tmp
=
tmp
->
next
;
tmp
=
tmp
->
next
;
}
return
sensors
;
return
sensors
;
}
/* Controls the speed of the fan */
void
set_fan_speed
(
t_sensors
*
sensors
,
int
speed
)
{
t_sensors
*
tmp
=
sensors
;
FILE
*
file
;
while
(
tmp
!=
NULL
)
{
file
=
fopen
(
tmp
->
fan_output_path
,
"rw+"
);
if
(
file
!=
NULL
)
{
fprintf
(
file
,
"%d"
,
speed
);
fclose
(
file
);
t_sensors
*
tmp
=
sensors
;
FILE
*
file
;
while
(
tmp
!=
NULL
)
{
file
=
fopen
(
tmp
->
fan_output_path
,
"rw+"
);
if
(
file
!=
NULL
)
{
fprintf
(
file
,
"%d"
,
speed
);
fclose
(
file
);
}
tmp
=
tmp
->
next
;
tmp
=
tmp
->
next
;
}
}
unsigned
short
get_temp
(
t_sensors
*
sensors
)
{
sensors
=
refresh_sensors
(
sensors
);
int
sum_temp
=
0
;
unsigned
short
temp
=
0
;
t_sensors
*
tmp
=
sensors
;
while
(
tmp
!=
NULL
)
{
sum_temp
+=
tmp
->
temperature
;
tmp
=
tmp
->
next
;
sensors
=
refresh_sensors
(
sensors
);
int
sum_temp
=
0
;
unsigned
short
temp
=
0
;
t_sensors
*
tmp
=
sensors
;
while
(
tmp
!=
NULL
)
{
sum_temp
+=
tmp
->
temperature
;
tmp
=
tmp
->
next
;
}
temp
=
(
unsigned
short
)(
ceil
(
(
float
)(
sum_temp
)
/
2000
.
)
);
return
temp
;
temp
=
(
unsigned
short
)(
ceil
(
(
float
)(
sum_temp
)
/
2000
.
)
);
return
temp
;
}
void
mbpfan
()
void
retrieve_settings
()
{
int
old_temp
,
new_temp
,
fan_speed
,
steps
;
int
temp_change
;
int
step_up
,
step_down
;
FILE
*
f
=
NULL
;
Settings
*
settings
=
NULL
;
int
result
=
0
;
t_sensors
*
sensors
=
retrieve_sensors
();
set_fans_man
(
sensors
);
new_temp
=
get_temp
(
sensors
);
fan_speed
=
2000
;
set_fan_speed
(
sensors
,
fan_speed
);
f
=
fopen
(
"/etc/mbpfan.conf"
,
"r"
);
if
(
f
==
NULL
)
{
/* Could not open configfile */
if
(
verbose
)
{
printf
(
"Couldn't open configfile, using defaults
\n
"
);
if
(
daemonize
)
{
syslog
(
LOG_INFO
,
"Couldn't open configfile, using defaults"
);
Settings
*
settings
=
NULL
;
int
result
=
0
;
FILE
*
f
=
NULL
;
f
=
fopen
(
"/etc/mbpfan.conf"
,
"r"
);
if
(
f
==
NULL
)
{
/* Could not open configfile */
if
(
verbose
)
{
printf
(
"Couldn't open configfile, using defaults
\n
"
);
if
(
daemonize
)
{
syslog
(
LOG_INFO
,
"Couldn't open configfile, using defaults"
);
}
}
}
else
{
settings
=
settings_open
(
f
);
fclose
(
f
);
if
(
settings
==
NULL
)
{
/* Could not read configfile */
if
(
verbose
)
{
printf
(
"Couldn't read configfile
\n
"
);
if
(
daemonize
)
{
syslog
(
LOG_INFO
,
"Couldn't read configfile"
);
}
else
{
settings
=
settings_open
(
f
);
fclose
(
f
);
if
(
settings
==
NULL
)
{
/* Could not read configfile */
if
(
verbose
)
{
printf
(
"Couldn't read configfile
\n
"
);
if
(
daemonize
)
{
syslog
(
LOG_INFO
,
"Couldn't read configfile"
);
}
}
}
else
{
/* Read configfile values */
result
=
settings_get_int
(
settings
,
"general"
,
"min_fan_speed"
);
if
(
result
!=
0
)
min_fan_speed
=
result
;
result
=
settings_get_int
(
settings
,
"general"
,
"max_fan_speed"
);
if
(
result
!=
0
)
max_fan_speed
=
result
;
result
=
settings_get_int
(
settings
,
"general"
,
"low_temp"
);
if
(
result
!=
0
)
low_temp
=
result
;
result
=
settings_get_int
(
settings
,
"general"
,
"high_temp"
);
if
(
result
!=
0
)
high_temp
=
result
;
result
=
settings_get_int
(
settings
,
"general"
,
"max_temp"
);
if
(
result
!=
0
)
max_temp
=
result
;
result
=
settings_get_int
(
settings
,
"general"
,
"polling_interval"
);
if
(
result
!=
0
)
polling_interval
=
result
;
/* Destroy the settings object */
settings_delete
(
settings
);
}
else
{
/* Read configfile values */
result
=
settings_get_int
(
settings
,
"general"
,
"min_fan_speed"
);
if
(
result
!=
0
)
min_fan_speed
=
result
;
result
=
settings_get_int
(
settings
,
"general"
,
"max_fan_speed"
);
if
(
result
!=
0
)
max_fan_speed
=
result
;
result
=
settings_get_int
(
settings
,
"general"
,
"low_temp"
);
if
(
result
!=
0
)
low_temp
=
result
;
result
=
settings_get_int
(
settings
,
"general"
,
"high_temp"
);
if
(
result
!=
0
)
high_temp
=
result
;
result
=
settings_get_int
(
settings
,
"general"
,
"max_temp"
);
if
(
result
!=
0
)
max_temp
=
result
;
result
=
settings_get_int
(
settings
,
"general"
,
"polling_interval"
);
if
(
result
!=
0
)
polling_interval
=
result
;
/* Destroy the settings object */
settings_delete
(
settings
);
}
}
}
void
mbpfan
()
{
int
old_temp
,
new_temp
,
fan_speed
,
steps
;
int
temp_change
;
int
step_up
,
step_down
;
retrieve_settings
();
t_sensors
*
sensors
=
retrieve_sensors
();
set_fans_man
(
sensors
);
new_temp
=
get_temp
(
sensors
);
fan_speed
=
2000
;
set_fan_speed
(
sensors
,
fan_speed
);
if
(
verbose
)
{
printf
(
"Sleeping for %d seconds
\n
"
,
polling_interval
);
if
(
daemonize
)
{
syslog
(
LOG_INFO
,
"Sleeping for %d seconds"
,
polling_interval
);
if
(
verbose
)
{
printf
(
"Sleeping for %d seconds
\n
"
,
polling_interval
);
if
(
daemonize
)
{
syslog
(
LOG_INFO
,
"Sleeping for %d seconds"
,
polling_interval
);
}
}
sleep
(
polling_interval
);
sleep
(
polling_interval
);
step_up
=
(
float
)(
max_fan_speed
-
min_fan_speed
)
/
(
float
)(
(
max_temp
-
high_temp
)
*
(
max_temp
-
high_temp
+
1
)
/
2
);
step_up
=
(
float
)(
max_fan_speed
-
min_fan_speed
)
/
(
float
)(
(
max_temp
-
high_temp
)
*
(
max_temp
-
high_temp
+
1
)
/
2
);
step_down
=
(
float
)(
max_fan_speed
-
min_fan_speed
)
/
(
float
)(
(
max_temp
-
low_temp
)
*
(
max_temp
-
low_temp
+
1
)
/
2
);
step_down
=
(
float
)(
max_fan_speed
-
min_fan_speed
)
/
(
float
)(
(
max_temp
-
low_temp
)
*
(
max_temp
-
low_temp
+
1
)
/
2
);
while
(
1
)
{
old_temp
=
new_temp
;
new_temp
=
get_temp
(
sensors
);
while
(
1
)
{
old_temp
=
new_temp
;
new_temp
=
get_temp
(
sensors
);
if
(
new_temp
>=
max_temp
&&
fan_speed
!=
max_fan_speed
)
{
fan_speed
=
max_fan_speed
;
if
(
new_temp
>=
max_temp
&&
fan_speed
!=
max_fan_speed
)
{
fan_speed
=
max_fan_speed
;
}
if
(
new_temp
<=
low_temp
&&
fan_speed
!=
min_fan_speed
)
{
fan_speed
=
min_fan_speed
;
if
(
new_temp
<=
low_temp
&&
fan_speed
!=
min_fan_speed
)
{
fan_speed
=
min_fan_speed
;
}
temp_change
=
new_temp
-
old_temp
;
temp_change
=
new_temp
-
old_temp
;
if
(
temp_change
>
0
&&
new_temp
>
high_temp
&&
new_temp
<
max_temp
)
{
steps
=
(
new_temp
-
high_temp
)
*
(
new_temp
-
high_temp
+
1
)
/
2
;
fan_speed
=
max
(
fan_speed
,
ceil
(
min_fan_speed
+
steps
*
step_up
)
);
if
(
temp_change
>
0
&&
new_temp
>
high_temp
&&
new_temp
<
max_temp
)
{
steps
=
(
new_temp
-
high_temp
)
*
(
new_temp
-
high_temp
+
1
)
/
2
;
fan_speed
=
max
(
fan_speed
,
ceil
(
min_fan_speed
+
steps
*
step_up
)
);
}
if
(
temp_change
<
0
&&
new_temp
>
low_temp
&&
new_temp
<
max_temp
)
{
steps
=
(
max_temp
-
new_temp
)
*
(
max_temp
-
new_temp
+
1
)
/
2
;
fan_speed
=
min
(
fan_speed
,
floor
(
max_fan_speed
-
steps
*
step_down
)
);
if
(
temp_change
<
0
&&
new_temp
>
low_temp
&&
new_temp
<
max_temp
)
{
steps
=
(
max_temp
-
new_temp
)
*
(
max_temp
-
new_temp
+
1
)
/
2
;
fan_speed
=
min
(
fan_speed
,
floor
(
max_fan_speed
-
steps
*
step_down
)
);
}
if
(
verbose
)
{
printf
(
"Old Temp %d: New Temp: %d, Fan Speed: %d
\n
"
,
old_temp
,
new_temp
,
fan_speed
);
if
(
daemonize
)
{
syslog
(
LOG_INFO
,
"Old Temp %d: New Temp: %d, Fan Speed: %d"
,
old_temp
,
new_temp
,
fan_speed
);
if
(
verbose
)
{
printf
(
"Old Temp %d: New Temp: %d, Fan Speed: %d
\n
"
,
old_temp
,
new_temp
,
fan_speed
);
if
(
daemonize
)
{
syslog
(
LOG_INFO
,
"Old Temp %d: New Temp: %d, Fan Speed: %d"
,
old_temp
,
new_temp
,
fan_speed
);
}
}
set_fan_speed
(
sensors
,
fan_speed
);
set_fan_speed
(
sensors
,
fan_speed
);
if
(
verbose
)
{
printf
(
"Sleeping for %d seconds
\n
"
,
polling_interval
);
if
(
daemonize
)
{
syslog
(
LOG_INFO
,
"Sleeping for %d seconds"
,
polling_interval
);
if
(
verbose
)
{
printf
(
"Sleeping for %d seconds
\n
"
,
polling_interval
);
if
(
daemonize
)
{
syslog
(
LOG_INFO
,
"Sleeping for %d seconds"
,
polling_interval
);
}
}
sleep
(
polling_interval
);
sleep
(
polling_interval
);
}
}
src/mbpfan.h
View file @
fcf18f52
...
...
@@ -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)
...
...
src/minunit.c
View file @
fcf18f52
...
...
@@ -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
src/minunit.h
View file @
fcf18f52
...
...
@@ -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
();
...
...
src/settings.c
View file @
fcf18f52
...
...
@@ -13,7 +13,7 @@
*
* Copyright (c) 2009-2011 Per Ola Kristensson.
*
* Per Ola Kristensson <pok21@cam.ac.uk>
* Per Ola Kristensson <pok21@cam.ac.uk>
* Inference Group, Department of Physics
* University of Cambridge
* Cavendish Laboratory
...
...
@@ -52,25 +52,25 @@ typedef struct Section Section;
typedef
struct
ParseState
ParseState
;
struct
Settings
{
Section
*
sections
;
unsigned
int
section_count
;
Section
*
sections
;
unsigned
int
section_count
;
};
struct
Section
{
char
*
name
;
StrMap
*
map
;
char
*
name
;
StrMap
*
map
;
};
struct
ParseState
{
char
*
current_section
;
unsigned
int
current_section_n
;
int
has_section
;
char
*
current_section
;
unsigned
int
current_section_n
;
int
has_section
;
};
enum
ConvertMode
{
CONVERT_MODE_INT
,
CONVERT_MODE_LONG
,
CONVERT_MODE_DOUBLE
,
CONVERT_MODE_INT
,
CONVERT_MODE_LONG
,
CONVERT_MODE_DOUBLE
,
};
typedef
enum
ConvertMode
ConvertMode
;
...
...
@@ -94,216 +94,216 @@ static void enum_map(const char *key, const char *value, const void *obj);
Settings
*
settings_new
()
{
Settings
*
settings
;
settings
=
(
Settings
*
)
malloc
(
sizeof
(
Settings
));
if
(
settings
==
NULL
)
{
return
NULL
;
}
settings
->
section_count
=
0
;
settings
->
sections
=
NULL
;
return
settings
;
Settings
*
settings
;
settings
=
(
Settings
*
)
malloc
(
sizeof
(
Settings
));
if
(
settings
==
NULL
)
{
return
NULL
;
}
settings
->
section_count
=
0
;
settings
->
sections
=
NULL
;
return
settings
;
}
void
settings_delete
(
Settings
*
settings
)
{
unsigned
int
i
,
n
;
Section
*
section
;
if
(
settings
==
NULL
)
{
return
;
}
section
=
settings
->
sections
;
n
=
settings
->
section_count
;
i
=
0
;
while
(
i
<
n
)
{
sm_delete
(
section
->
map
);
if
(
section
->
name
!=
NULL
)
{
free
(
section
->
name
);
}
section
++
;
i
++
;
}
free
(
settings
->
sections
);
free
(
settings
);
unsigned
int
i
,
n
;
Section
*
section
;
if
(
settings
==
NULL
)
{
return
;
}
section
=
settings
->
sections
;
n
=
settings
->
section_count
;
i
=
0
;
while
(
i
<
n
)
{
sm_delete
(
section
->
map
);
if
(
section
->
name
!=
NULL
)
{
free
(
section
->
name
);
}
section
++
;
i
++
;
}
free
(
settings
->
sections
);
free
(
settings
);
}
Settings
*
settings_open
(
FILE
*
stream
)
{
Settings
*
settings
;
char
buf
[
MAX_LINECHARS
];
char
trimmed_buf
[
MAX_LINECHARS
];
char
section_buf
[
MAX_LINECHARS
];
ParseState
parse_state
;
if
(
stream
==
NULL
)
{
return
NULL
;
}
settings
=
settings_new
();
if
(
settings
==
NULL
)
{
return
NULL
;
}
parse_state
.
current_section
=
section_buf
;
parse_state
.
current_section_n
=
sizeof
(
section_buf
);
parse_state
.
has_section
=
0
;
trim_str
(
""
,
trimmed_buf
);
while
(
fgets
(
buf
,
MAX_LINECHARS
,
stream
)
!=
NULL
)
{
trim_str
(
buf
,
trimmed_buf
);
if
(
!
parse_str
(
settings
,
trimmed_buf
,
&
parse_state
))
{
return
NULL
;
}
}
return
settings
;
Settings
*
settings
;
char
buf
[
MAX_LINECHARS
];
char
trimmed_buf
[
MAX_LINECHARS
];
char
section_buf
[
MAX_LINECHARS
];
ParseState
parse_state
;
if
(
stream
==
NULL
)
{
return
NULL
;
}
settings
=
settings_new
();
if
(
settings
==
NULL
)
{
return
NULL
;
}
parse_state
.
current_section
=
section_buf
;
parse_state
.
current_section_n
=
sizeof
(
section_buf
);
parse_state
.
has_section
=
0
;
trim_str
(
""
,
trimmed_buf
);
while
(
fgets
(
buf
,
MAX_LINECHARS
,
stream
)
!=
NULL
)
{
trim_str
(
buf
,
trimmed_buf
);
if
(
!
parse_str
(
settings
,
trimmed_buf
,
&
parse_state
))
{
return
NULL
;
}
}
return
settings
;
}
int
settings_save
(
const
Settings
*
settings
,
FILE
*
stream
)
{
unsigned
int
i
,
n
;
Section
*
section
;
char
buf
[
MAX_LINECHARS
];
if
(
settings
==
NULL
)
{
return
0
;
}
if
(
stream
==
NULL
)
{
return
0
;
}
section
=
settings
->
sections
;
n
=
settings
->
section_count
;
i
=
0
;
while
(
i
<
n
)
{
sprintf
(
buf
,
"[%s]
\n
"
,
section
->
name
);
fputs
(
buf
,
stream
);
sm_enum
(
section
->
map
,
enum_map
,
stream
);
section
++
;
i
++
;
fputs
(
"
\n
"
,
stream
);
}
return
0
;
unsigned
int
i
,
n
;
Section
*
section
;
char
buf
[
MAX_LINECHARS
];
if
(
settings
==
NULL
)
{
return
0
;
}
if
(
stream
==
NULL
)
{
return
0
;
}
section
=
settings
->
sections
;
n
=
settings
->
section_count
;
i
=
0
;
while
(
i
<
n
)
{
sprintf
(
buf
,
"[%s]
\n
"
,
section
->
name
);
fputs
(
buf
,
stream
);
sm_enum
(
section
->
map
,
enum_map
,
stream
);
section
++
;
i
++
;
fputs
(
"
\n
"
,
stream
);
}
return
0
;
}
int
settings_get
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
char
*
out_buf
,
unsigned
int
n_out_buf
)
{
Section
*
s
;
if
(
settings
==
NULL
)
{
return
0
;
}
s
=
get_section
(
settings
->
sections
,
settings
->
section_count
,
section
);
if
(
s
==
NULL
)
{
return
0
;
}
return
sm_get
(
s
->
map
,
key
,
out_buf
,
n_out_buf
);
Section
*
s
;
if
(
settings
==
NULL
)
{
return
0
;
}
s
=
get_section
(
settings
->
sections
,
settings
->
section_count
,
section
);
if
(
s
==
NULL
)
{
return
0
;
}
return
sm_get
(
s
->
map
,
key
,
out_buf
,
n_out_buf
);
}
int
settings_get_int
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
)
{
int
i
;
int
i
;
if
(
get_converted_value
(
settings
,
section
,
key
,
CONVERT_MODE_INT
,
&
i
))
{
return
i
;
}
return
0
;
if
(
get_converted_value
(
settings
,
section
,
key
,
CONVERT_MODE_INT
,
&
i
))
{
return
i
;
}
return
0
;
}
long
settings_get_long
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
)
{
long
l
;
long
l
;
if
(
get_converted_value
(
settings
,
section
,
key
,
CONVERT_MODE_LONG
,
&
l
))
{
return
l
;
}
return
0
;
if
(
get_converted_value
(
settings
,
section
,
key
,
CONVERT_MODE_LONG
,
&
l
))
{
return
l
;
}
return
0
;
}
double
settings_get_double
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
)
{
double
d
;
double
d
;
if
(
get_converted_value
(
settings
,
section
,
key
,
CONVERT_MODE_DOUBLE
,
&
d
))
{
return
d
;
}
return
0
;
if
(
get_converted_value
(
settings
,
section
,
key
,
CONVERT_MODE_DOUBLE
,
&
d
))
{
return
d
;
}
return
0
;
}
int
settings_get_int_tuple
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
int
*
out
,
unsigned
int
n_out
)
{
return
get_converted_tuple
(
settings
,
section
,
key
,
','
,
CONVERT_MODE_INT
,
out
,
n_out
);
return
get_converted_tuple
(
settings
,
section
,
key
,
','
,
CONVERT_MODE_INT
,
out
,
n_out
);
}
long
settings_get_long_tuple
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
long
*
out
,
unsigned
int
n_out
)
{
return
get_converted_tuple
(
settings
,
section
,
key
,
','
,
CONVERT_MODE_LONG
,
out
,
n_out
);
return
get_converted_tuple
(
settings
,
section
,
key
,
','
,
CONVERT_MODE_LONG
,
out
,
n_out
);
}
double
settings_get_double_tuple
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
double
*
out
,
unsigned
int
n_out
)
{
return
get_converted_tuple
(
settings
,
section
,
key
,
','
,
CONVERT_MODE_DOUBLE
,
out
,
n_out
);
return
get_converted_tuple
(
settings
,
section
,
key
,
','
,
CONVERT_MODE_DOUBLE
,
out
,
n_out
);
}
int
settings_set
(
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
const
char
*
value
)
{
Section
*
s
;
if
(
settings
==
NULL
)
{
return
0
;
}
if
(
section
==
NULL
||
key
==
NULL
||
value
==
NULL
)
{
return
0
;
}
if
(
strlen
(
section
)
==
0
)
{
return
0
;
}
/* Get a pointer to the section */
s
=
get_section
(
settings
->
sections
,
settings
->
section_count
,
section
);
if
(
s
==
NULL
)
{
/* The section is not created---create it */
s
=
(
Section
*
)
realloc
(
settings
->
sections
,
(
settings
->
section_count
+
1
)
*
sizeof
(
Section
));
if
(
s
==
NULL
)
{
return
0
;
}
settings
->
sections
=
s
;
settings
->
section_count
++
;
s
=
&
(
settings
->
sections
[
settings
->
section_count
-
1
]);
s
->
map
=
sm_new
(
DEFAULT_STRMAP_CAPACITY
);
if
(
s
->
map
==
NULL
)
{
free
(
s
);
return
0
;
}
s
->
name
=
(
char
*
)
malloc
((
strlen
(
section
)
+
1
)
*
sizeof
(
char
));
if
(
s
->
name
==
NULL
)
{
sm_delete
(
s
->
map
);
free
(
s
);
return
0
;
}
strcpy
(
s
->
name
,
section
);
}
return
sm_put
(
s
->
map
,
key
,
value
);
Section
*
s
;
if
(
settings
==
NULL
)
{
return
0
;
}
if
(
section
==
NULL
||
key
==
NULL
||
value
==
NULL
)
{
return
0
;
}
if
(
strlen
(
section
)
==
0
)
{
return
0
;
}
/* Get a pointer to the section */
s
=
get_section
(
settings
->
sections
,
settings
->
section_count
,
section
);
if
(
s
==
NULL
)
{
/* The section is not created---create it */
s
=
(
Section
*
)
realloc
(
settings
->
sections
,
(
settings
->
section_count
+
1
)
*
sizeof
(
Section
));
if
(
s
==
NULL
)
{
return
0
;
}
settings
->
sections
=
s
;
settings
->
section_count
++
;
s
=
&
(
settings
->
sections
[
settings
->
section_count
-
1
]);
s
->
map
=
sm_new
(
DEFAULT_STRMAP_CAPACITY
);
if
(
s
->
map
==
NULL
)
{
free
(
s
);
return
0
;
}
s
->
name
=
(
char
*
)
malloc
((
strlen
(
section
)
+
1
)
*
sizeof
(
char
));
if
(
s
->
name
==
NULL
)
{
sm_delete
(
s
->
map
);
free
(
s
);
return
0
;
}
strcpy
(
s
->
name
,
section
);
}
return
sm_put
(
s
->
map
,
key
,
value
);
}
int
settings_section_get_count
(
const
Settings
*
settings
,
const
char
*
section
)
{
Section
*
sect
;
if
(
settings
==
NULL
)
{
return
0
;
}
sect
=
get_section
(
settings
->
sections
,
settings
->
section_count
,
section
);
if
(
sect
==
NULL
)
{
return
0
;
}
return
sm_get_count
(
sect
->
map
);
Section
*
sect
;
if
(
settings
==
NULL
)
{
return
0
;
}
sect
=
get_section
(
settings
->
sections
,
settings
->
section_count
,
section
);
if
(
sect
==
NULL
)
{
return
0
;
}
return
sm_get_count
(
sect
->
map
);
}
int
settings_section_enum
(
const
Settings
*
settings
,
const
char
*
section
,
settings_section_enum_func
enum_func
,
const
void
*
obj
)
{
Section
*
sect
;
Section
*
sect
;
sect
=
get_section
(
settings
->
sections
,
settings
->
section_count
,
section
);
if
(
sect
==
NULL
)
{
return
0
;
}
return
sm_enum
(
sect
->
map
,
enum_func
,
obj
);
sect
=
get_section
(
settings
->
sections
,
settings
->
section_count
,
section
);
if
(
sect
==
NULL
)
{
return
0
;
}
return
sm_enum
(
sect
->
map
,
enum_func
,
obj
);
}
/* Copies a trimmed variant without leading and trailing blank characters
...
...
@@ -312,27 +312,27 @@ int settings_section_enum(const Settings *settings, const char *section, setting
*/
static
void
trim_str
(
const
char
*
str
,
char
*
out_buf
)
{
unsigned
int
len
;
const
char
*
s0
;
while
(
*
str
!=
'\0'
&&
is_blank_char
(
*
str
))
{
str
++
;
}
s0
=
str
;
len
=
0
;
while
(
*
str
!=
'\0'
)
{
len
++
;
str
++
;
}
if
(
len
>
0
)
{
str
--
;
}
while
(
is_blank_char
(
*
str
))
{
str
--
;
len
--
;
}
memcpy
(
out_buf
,
s0
,
len
);
out_buf
[
len
]
=
'\0'
;
unsigned
int
len
;
const
char
*
s0
;
while
(
*
str
!=
'\0'
&&
is_blank_char
(
*
str
))
{
str
++
;
}
s0
=
str
;
len
=
0
;
while
(
*
str
!=
'\0'
)
{
len
++
;
str
++
;
}
if
(
len
>
0
)
{
str
--
;
}
while
(
is_blank_char
(
*
str
))
{
str
--
;
len
--
;
}
memcpy
(
out_buf
,
s0
,
len
);
out_buf
[
len
]
=
'\0'
;
}
/* Parses a single input string and updates the provided settings object.
...
...
@@ -348,55 +348,49 @@ static void trim_str(const char *str, char *out_buf)
*/
static
int
parse_str
(
Settings
*
settings
,
char
*
str
,
ParseState
*
parse_state
)
{
char
buf
[
MAX_LINECHARS
];
char
buf1
[
MAX_LINECHARS
];
char
buf2
[
MAX_LINECHARS
];
int
result
;
if
(
*
str
==
'\0'
)
{
return
1
;
}
else
if
(
is_blank_str
(
str
))
{
return
1
;
}
else
if
(
is_comment_str
(
str
))
{
return
1
;
}
else
if
(
is_section_str
(
str
))
{
result
=
get_section_from_str
(
str
,
buf
,
sizeof
(
buf
));
if
(
!
result
)
{
return
0
;
}
if
(
strlen
(
buf
)
+
1
>
parse_state
->
current_section_n
)
{
return
0
;
}
strcpy
(
parse_state
->
current_section
,
buf
);
parse_state
->
has_section
=
1
;
return
1
;
}
else
if
(
is_key_value_str
(
str
))
{
result
=
get_key_value_from_str
(
str
,
buf1
,
sizeof
(
buf1
),
buf2
,
sizeof
(
buf2
));
if
(
!
result
)
{
return
0
;
}
if
(
!
parse_state
->
has_section
)
{
return
0
;
}
return
settings_set
(
settings
,
parse_state
->
current_section
,
buf1
,
buf2
);
}
else
if
(
is_key_without_value_str
(
str
))
{
result
=
get_key_without_value_from_str
(
str
,
buf
,
sizeof
(
buf
));
if
(
!
result
)
{
return
0
;
}
if
(
!
parse_state
->
has_section
)
{
return
0
;
}
return
settings_set
(
settings
,
parse_state
->
current_section
,
buf
,
""
);
}
else
{
return
0
;
}
char
buf
[
MAX_LINECHARS
];
char
buf1
[
MAX_LINECHARS
];
char
buf2
[
MAX_LINECHARS
];
int
result
;
if
(
*
str
==
'\0'
)
{
return
1
;
}
else
if
(
is_blank_str
(
str
))
{
return
1
;
}
else
if
(
is_comment_str
(
str
))
{
return
1
;
}
else
if
(
is_section_str
(
str
))
{
result
=
get_section_from_str
(
str
,
buf
,
sizeof
(
buf
));
if
(
!
result
)
{
return
0
;
}
if
(
strlen
(
buf
)
+
1
>
parse_state
->
current_section_n
)
{
return
0
;
}
strcpy
(
parse_state
->
current_section
,
buf
);
parse_state
->
has_section
=
1
;
return
1
;
}
else
if
(
is_key_value_str
(
str
))
{
result
=
get_key_value_from_str
(
str
,
buf1
,
sizeof
(
buf1
),
buf2
,
sizeof
(
buf2
));
if
(
!
result
)
{
return
0
;
}
if
(
!
parse_state
->
has_section
)
{
return
0
;
}
return
settings_set
(
settings
,
parse_state
->
current_section
,
buf1
,
buf2
);
}
else
if
(
is_key_without_value_str
(
str
))
{
result
=
get_key_without_value_from_str
(
str
,
buf
,
sizeof
(
buf
));
if
(
!
result
)
{
return
0
;
}
if
(
!
parse_state
->
has_section
)
{
return
0
;
}
return
settings_set
(
settings
,
parse_state
->
current_section
,
buf
,
""
);
}
else
{
return
0
;
}
}
/* Returns true if the input character is blank,
...
...
@@ -404,7 +398,7 @@ static int parse_str(Settings *settings, char *str, ParseState *parse_state)
*/
static
int
is_blank_char
(
char
c
)
{
return
c
==
' '
||
c
==
'\t'
||
c
==
'\r'
||
c
==
'\n'
;
return
c
==
' '
||
c
==
'\t'
||
c
==
'\r'
||
c
==
'\n'
;
}
/* Returns true if the input string is blank,
...
...
@@ -412,13 +406,13 @@ static int is_blank_char(char c)
*/
static
int
is_blank_str
(
const
char
*
str
)
{
while
(
*
str
!=
'\0'
)
{
if
(
!
is_blank_char
(
*
str
))
{
return
0
;
}
str
++
;
}
return
1
;
while
(
*
str
!=
'\0'
)
{
if
(
!
is_blank_char
(
*
str
))
{
return
0
;
}
str
++
;
}
return
1
;
}
/* Returns true if the input string denotes a comment,
...
...
@@ -426,13 +420,13 @@ static int is_blank_str(const char *str)
*/
static
int
is_comment_str
(
const
char
*
str
)
{
if
(
*
str
==
COMMENT_CHAR
)
{
/* To be a comment the first character must be the
* comment character.
*/
return
1
;
}
return
0
;
if
(
*
str
==
COMMENT_CHAR
)
{
/* To be a comment the first character must be the
* comment character.
*/
return
1
;
}
return
0
;
}
/* Returns true if the input string denotes a section name,
...
...
@@ -440,18 +434,18 @@ static int is_comment_str(const char *str)
*/
static
int
is_section_str
(
const
char
*
str
)
{
if
(
*
str
!=
SECTION_START_CHAR
)
{
/* The first character must be the section start character */
return
0
;
}
while
(
*
str
!=
'\0'
&&
*
str
!=
SECTION_END_CHAR
)
{
str
++
;
}
if
(
*
str
!=
SECTION_END_CHAR
)
{
/* The section end character must be present somewhere thereafter */
return
0
;
}
return
1
;
if
(
*
str
!=
SECTION_START_CHAR
)
{
/* The first character must be the section start character */
return
0
;
}
while
(
*
str
!=
'\0'
&&
*
str
!=
SECTION_END_CHAR
)
{
str
++
;
}
if
(
*
str
!=
SECTION_END_CHAR
)
{
/* The section end character must be present somewhere thereafter */
return
0
;
}
return
1
;
}
/* Returns true if the input string denotes a key-value pair,
...
...
@@ -459,18 +453,18 @@ static int is_section_str(const char *str)
*/
static
int
is_key_value_str
(
const
char
*
str
)
{
if
(
*
str
==
KEY_VALUE_SEPARATOR_CHAR
)
{
/* It is illegal to start with the key-value separator */
return
0
;
}
while
(
*
str
!=
'\0'
&&
*
str
!=
KEY_VALUE_SEPARATOR_CHAR
)
{
str
++
;
}
if
(
*
str
!=
KEY_VALUE_SEPARATOR_CHAR
)
{
/* The key-value separator must be present after the key part */
return
0
;
}
return
1
;
if
(
*
str
==
KEY_VALUE_SEPARATOR_CHAR
)
{
/* It is illegal to start with the key-value separator */
return
0
;
}
while
(
*
str
!=
'\0'
&&
*
str
!=
KEY_VALUE_SEPARATOR_CHAR
)
{
str
++
;
}
if
(
*
str
!=
KEY_VALUE_SEPARATOR_CHAR
)
{
/* The key-value separator must be present after the key part */
return
0
;
}
return
1
;
}
/* Returns true if the input string denotes a key without a value,
...
...
@@ -478,18 +472,18 @@ static int is_key_value_str(const char *str)
*/
static
int
is_key_without_value_str
(
const
char
*
str
)
{
if
(
*
str
==
KEY_VALUE_SEPARATOR_CHAR
)
{
/* It is illegal to start with the key-value separator */
return
0
;
}
while
(
*
str
!=
'\0'
&&
*
str
!=
KEY_VALUE_SEPARATOR_CHAR
)
{
str
++
;
}
if
(
*
str
==
KEY_VALUE_SEPARATOR_CHAR
)
{
/* The key-value separator must not be present after the key part */
return
0
;
}
return
1
;
if
(
*
str
==
KEY_VALUE_SEPARATOR_CHAR
)
{
/* It is illegal to start with the key-value separator */
return
0
;
}
while
(
*
str
!=
'\0'
&&
*
str
!=
KEY_VALUE_SEPARATOR_CHAR
)
{
str
++
;
}
if
(
*
str
==
KEY_VALUE_SEPARATOR_CHAR
)
{
/* The key-value separator must not be present after the key part */
return
0
;
}
return
1
;
}
/*
...
...
@@ -498,27 +492,27 @@ static int is_key_without_value_str(const char *str)
*/
static
int
get_section_from_str
(
const
char
*
str
,
char
*
out_buf
,
unsigned
int
out_buf_n
)
{
unsigned
int
count
;
count
=
0
;
/* Jump past the section begin character */
str
++
;
while
(
*
str
!=
'\0'
&&
*
str
!=
SECTION_END_CHAR
)
{
/* Read in the section name into the output buffer */
if
(
count
==
out_buf_n
)
{
return
0
;
}
*
out_buf
=
*
str
;
out_buf
++
;
str
++
;
count
++
;
}
/* Terminate the output buffer */
if
(
count
==
out_buf_n
)
{
return
0
;
}
*
out_buf
=
'\0'
;
return
1
;
unsigned
int
count
;
count
=
0
;
/* Jump past the section begin character */
str
++
;
while
(
*
str
!=
'\0'
&&
*
str
!=
SECTION_END_CHAR
)
{
/* Read in the section name into the output buffer */
if
(
count
==
out_buf_n
)
{
return
0
;
}
*
out_buf
=
*
str
;
out_buf
++
;
str
++
;
count
++
;
}
/* Terminate the output buffer */
if
(
count
==
out_buf_n
)
{
return
0
;
}
*
out_buf
=
'\0'
;
return
1
;
}
/*
...
...
@@ -527,67 +521,67 @@ static int get_section_from_str(const char *str, char *out_buf, unsigned int out
*/
static
int
get_key_value_from_str
(
const
char
*
str
,
char
*
out_buf1
,
unsigned
int
out_buf1_n
,
char
*
out_buf2
,
unsigned
int
out_buf2_n
)
{
unsigned
int
count1
;
unsigned
int
count2
;
count1
=
0
;
count2
=
0
;
/* Read the key value from the input string and write it sequentially
* to the first output buffer by walking the input string until we either hit
* the null-terminator or the key-value separator.
*/
while
(
*
str
!=
'\0'
&&
*
str
!=
KEY_VALUE_SEPARATOR_CHAR
)
{
/* Ensure the first output buffer is large enough. */
if
(
count1
==
out_buf1_n
)
{
return
0
;
}
/* Copy the character to the first output buffer */
*
out_buf1
=
*
str
;
out_buf1
++
;
str
++
;
count1
++
;
}
/* Terminate the first output buffer */
if
(
count1
==
out_buf1_n
)
{
return
0
;
}
*
out_buf1
=
'\0'
;
/* Now trace the first input buffer backwards until we hit a non-blank character */
while
(
is_blank_char
(
*
(
out_buf1
-
1
)))
{
out_buf1
--
;
}
*
out_buf1
=
'\0'
;
/* Try to proceed one more character, past the last read key-value
* delimiter, in the input string.
*/
if
(
*
str
!=
'\0'
)
{
str
++
;
}
/* Now find start of the value in the input string by walking the input
* string until we either hit the null-terminator or a blank character.
*/
while
(
*
str
!=
'\0'
&&
is_blank_char
(
*
str
))
{
str
++
;
}
while
(
*
str
!=
'\0'
)
{
/* Fail if there is a possibility that we are overwriting the second
* input buffer.
*/
if
(
count2
==
out_buf2_n
)
{
return
0
;
}
/* Copy the character to the second output buffer */
*
out_buf2
=
*
str
;
out_buf2
++
;
str
++
;
count2
++
;
}
/* Terminate the second output buffer */
if
(
count2
==
out_buf2_n
)
{
return
0
;
}
*
out_buf2
=
'\0'
;
return
1
;
unsigned
int
count1
;
unsigned
int
count2
;
count1
=
0
;
count2
=
0
;
/* Read the key value from the input string and write it sequentially
* to the first output buffer by walking the input string until we either hit
* the null-terminator or the key-value separator.
*/
while
(
*
str
!=
'\0'
&&
*
str
!=
KEY_VALUE_SEPARATOR_CHAR
)
{
/* Ensure the first output buffer is large enough. */
if
(
count1
==
out_buf1_n
)
{
return
0
;
}
/* Copy the character to the first output buffer */
*
out_buf1
=
*
str
;
out_buf1
++
;
str
++
;
count1
++
;
}
/* Terminate the first output buffer */
if
(
count1
==
out_buf1_n
)
{
return
0
;
}
*
out_buf1
=
'\0'
;
/* Now trace the first input buffer backwards until we hit a non-blank character */
while
(
is_blank_char
(
*
(
out_buf1
-
1
)))
{
out_buf1
--
;
}
*
out_buf1
=
'\0'
;
/* Try to proceed one more character, past the last read key-value
* delimiter, in the input string.
*/
if
(
*
str
!=
'\0'
)
{
str
++
;
}
/* Now find start of the value in the input string by walking the input
* string until we either hit the null-terminator or a blank character.
*/
while
(
*
str
!=
'\0'
&&
is_blank_char
(
*
str
))
{
str
++
;
}
while
(
*
str
!=
'\0'
)
{
/* Fail if there is a possibility that we are overwriting the second
* input buffer.
*/
if
(
count2
==
out_buf2_n
)
{
return
0
;
}
/* Copy the character to the second output buffer */
*
out_buf2
=
*
str
;
out_buf2
++
;
str
++
;
count2
++
;
}
/* Terminate the second output buffer */
if
(
count2
==
out_buf2_n
)
{
return
0
;
}
*
out_buf2
=
'\0'
;
return
1
;
}
/*
...
...
@@ -596,30 +590,30 @@ static int get_key_value_from_str(const char *str, char *out_buf1, unsigned int
*/
static
int
get_key_without_value_from_str
(
const
char
*
str
,
char
*
out_buf
,
unsigned
int
out_buf_n
)
{
unsigned
int
count
;
count
=
0
;
/* Now read the key value from the input string and write it sequentially
* to the output buffer by walking the input string until we either hit
* the null-terminator or the key-value separator.
*/
while
(
*
str
!=
'\0'
)
{
/* Ensure the output buffer is large enough. */
if
(
count
==
out_buf_n
)
{
return
0
;
}
/* Copy the character to the input buffer */
*
out_buf
=
*
str
;
out_buf
++
;
str
++
;
count
++
;
}
/* Terminate the output buffer */
if
(
count
==
out_buf_n
)
{
return
0
;
}
*
out_buf
=
'\0'
;
return
1
;
unsigned
int
count
;
count
=
0
;
/* Now read the key value from the input string and write it sequentially
* to the output buffer by walking the input string until we either hit
* the null-terminator or the key-value separator.
*/
while
(
*
str
!=
'\0'
)
{
/* Ensure the output buffer is large enough. */
if
(
count
==
out_buf_n
)
{
return
0
;
}
/* Copy the character to the input buffer */
*
out_buf
=
*
str
;
out_buf
++
;
str
++
;
count
++
;
}
/* Terminate the output buffer */
if
(
count
==
out_buf_n
)
{
return
0
;
}
*
out_buf
=
'\0'
;
return
1
;
}
/* Returns a pointer to the next token in the input string delimited
...
...
@@ -641,29 +635,29 @@ static int get_key_without_value_from_str(const char *str, char *out_buf, unsign
static
const
char
*
get_token
(
char
*
str
,
char
delim
,
char
**
last
)
{
char
*
s0
;
s0
=
str
;
/* If we hit the null-terminator the string
* is exhausted and another token does not
* exist.
*/
if
(
*
str
==
'\0'
)
{
return
NULL
;
}
/* Walk the string until we encounter a
* null-terminator or the delimiter.
*/
while
(
*
str
!=
'\0'
&&
*
str
!=
delim
)
{
str
++
;
}
/* Terminate the return token, if necessary */
if
(
*
str
!=
'\0'
)
{
*
str
=
'\0'
;
str
++
;
}
*
last
=
str
;
return
s0
;
char
*
s0
;
s0
=
str
;
/* If we hit the null-terminator the string
* is exhausted and another token does not
* exist.
*/
if
(
*
str
==
'\0'
)
{
return
NULL
;
}
/* Walk the string until we encounter a
* null-terminator or the delimiter.
*/
while
(
*
str
!=
'\0'
&&
*
str
!=
delim
)
{
str
++
;
}
/* Terminate the return token, if necessary */
if
(
*
str
!=
'\0'
)
{
*
str
=
'\0'
;
str
++
;
}
*
last
=
str
;
return
s0
;
}
/* Returns a converted value pointed to by the provided key in the given section.
...
...
@@ -674,23 +668,23 @@ static const char * get_token(char *str, char delim, char **last)
*/
static
int
get_converted_value
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
ConvertMode
mode
,
void
*
out
)
{
char
value
[
MAX_VALUECHARS
];
if
(
!
settings_get
(
settings
,
section
,
key
,
value
,
MAX_VALUECHARS
))
{
return
0
;
}
switch
(
mode
)
{
case
CONVERT_MODE_INT
:
*
((
int
*
)
out
)
=
atoi
(
value
);
return
1
;
case
CONVERT_MODE_LONG
:
*
((
long
*
)
out
)
=
atol
(
value
);
return
1
;
case
CONVERT_MODE_DOUBLE
:
*
((
double
*
)
out
)
=
atof
(
value
);
return
1
;
}
return
0
;
char
value
[
MAX_VALUECHARS
];
if
(
!
settings_get
(
settings
,
section
,
key
,
value
,
MAX_VALUECHARS
))
{
return
0
;
}
switch
(
mode
)
{
case
CONVERT_MODE_INT
:
*
((
int
*
)
out
)
=
atoi
(
value
);
return
1
;
case
CONVERT_MODE_LONG
:
*
((
long
*
)
out
)
=
atol
(
value
);
return
1
;
case
CONVERT_MODE_DOUBLE
:
*
((
double
*
)
out
)
=
atof
(
value
);
return
1
;
}
return
0
;
}
/* Returns a converted tuple pointed to by the provided key in the given section.
...
...
@@ -702,42 +696,42 @@ static int get_converted_value(const Settings *settings, const char *section, co
*/
static
int
get_converted_tuple
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
char
delim
,
ConvertMode
mode
,
void
*
out
,
unsigned
int
n_out
)
{
unsigned
int
count
;
const
char
*
token
;
static
char
value
[
MAX_VALUECHARS
];
char
*
v
;
if
(
out
==
NULL
)
{
return
0
;
}
if
(
n_out
==
0
)
{
return
0
;
}
if
(
!
settings_get
(
settings
,
section
,
key
,
value
,
MAX_VALUECHARS
))
{
return
0
;
}
v
=
value
;
count
=
0
;
/* Walk over all tokens in the value, and convert them and assign them
* to the output array as specified by the mode.
*/
while
((
token
=
get_token
(
v
,
delim
,
&
v
))
!=
NULL
&&
count
<
n_out
)
{
switch
(
mode
)
{
case
CONVERT_MODE_INT
:
((
int
*
)
out
)[
count
]
=
atoi
(
token
);
break
;
case
CONVERT_MODE_LONG
:
((
long
*
)
out
)[
count
]
=
atol
(
token
);
break
;
case
CONVERT_MODE_DOUBLE
:
((
double
*
)
out
)[
count
]
=
atof
(
token
);
break
;
default:
return
0
;
}
count
++
;
}
return
1
;
unsigned
int
count
;
const
char
*
token
;
static
char
value
[
MAX_VALUECHARS
];
char
*
v
;
if
(
out
==
NULL
)
{
return
0
;
}
if
(
n_out
==
0
)
{
return
0
;
}
if
(
!
settings_get
(
settings
,
section
,
key
,
value
,
MAX_VALUECHARS
))
{
return
0
;
}
v
=
value
;
count
=
0
;
/* Walk over all tokens in the value, and convert them and assign them
* to the output array as specified by the mode.
*/
while
((
token
=
get_token
(
v
,
delim
,
&
v
))
!=
NULL
&&
count
<
n_out
)
{
switch
(
mode
)
{
case
CONVERT_MODE_INT
:
((
int
*
)
out
)[
count
]
=
atoi
(
token
);
break
;
case
CONVERT_MODE_LONG
:
((
long
*
)
out
)[
count
]
=
atol
(
token
);
break
;
case
CONVERT_MODE_DOUBLE
:
((
double
*
)
out
)[
count
]
=
atof
(
token
);
break
;
default:
return
0
;
}
count
++
;
}
return
1
;
}
/* Returns a pointer to the section or null if the named section does not
...
...
@@ -745,22 +739,22 @@ static int get_converted_tuple(const Settings *settings, const char *section, co
*/
static
Section
*
get_section
(
Section
*
sections
,
unsigned
int
n
,
const
char
*
name
)
{
unsigned
int
i
;
Section
*
section
;
if
(
name
==
NULL
)
{
return
NULL
;
}
section
=
sections
;
i
=
0
;
while
(
i
<
n
)
{
if
(
strcmp
(
section
->
name
,
name
)
==
0
)
{
return
section
;
}
section
++
;
i
++
;
}
return
NULL
;
unsigned
int
i
;
Section
*
section
;
if
(
name
==
NULL
)
{
return
NULL
;
}
section
=
sections
;
i
=
0
;
while
(
i
<
n
)
{
if
(
strcmp
(
section
->
name
,
name
)
==
0
)
{
return
section
;
}
section
++
;
i
++
;
}
return
NULL
;
}
/* Callback function that is passed into the enumeration function in the
...
...
@@ -769,20 +763,20 @@ static Section * get_section(Section *sections, unsigned int n, const char *name
*/
static
void
enum_map
(
const
char
*
key
,
const
char
*
value
,
const
void
*
obj
)
{
FILE
*
stream
;
char
buf
[
MAX_LINECHARS
];
if
(
key
==
NULL
||
value
==
NULL
)
{
return
;
}
if
(
obj
==
NULL
)
{
return
;
}
stream
=
(
FILE
*
)
obj
;
if
(
strlen
(
key
)
<
MAX_KEYCHARS
&&
strlen
(
value
)
<
MAX_VALUECHARS
)
{
sprintf
(
buf
,
"%s%c%s
\n
"
,
key
,
KEY_VALUE_SEPARATOR_CHAR
,
value
);
fputs
(
buf
,
stream
);
}
FILE
*
stream
;
char
buf
[
MAX_LINECHARS
];
if
(
key
==
NULL
||
value
==
NULL
)
{
return
;
}
if
(
obj
==
NULL
)
{
return
;
}
stream
=
(
FILE
*
)
obj
;
if
(
strlen
(
key
)
<
MAX_KEYCHARS
&&
strlen
(
value
)
<
MAX_VALUECHARS
)
{
sprintf
(
buf
,
"%s%c%s
\n
"
,
key
,
KEY_VALUE_SEPARATOR_CHAR
,
value
);
fputs
(
buf
,
stream
);
}
}
/*
...
...
src/settings.h
View file @
fcf18f52
...
...
@@ -7,7 +7,7 @@
*
* Copyright (c) 2009 Per Ola Kristensson.
*
* Per Ola Kristensson <pok21@cam.ac.uk>
* Per Ola Kristensson <pok21@cam.ac.uk>
* Inference Group, Department of Physics
* University of Cambridge
* Cavendish Laboratory
...
...
@@ -43,292 +43,292 @@ extern "C"
{
#endif
typedef
struct
Settings
Settings
;
/*
* This callback function is called once per key-value when enumerating
* all keys inside a section.
*
* Parameters:
*
* key: A pointer to a null-terminated C string. The string must not
* be modified by the client.
*
* value: A pointer to a null-terminated C string. The string must
* not be modified by the client.
*
* obj: A pointer to a client-specific object. This parameter may be
* null.
*
* Return value: None.
*/
typedef
void
(
*
settings_section_enum_func
)(
const
char
*
key
,
const
char
*
value
,
const
void
*
obj
);
/*
* Creates a settings object.
*
* Return value: A pointer to a settings object,
* or null if a new settings object could not be allocated.
*/
Settings
*
settings_new
();
/*
* Releases all memory held by a settings object.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
* If the supplied settings object has been previously released, the
* behaviour of this function is undefined.
*
* Return value: None.
*/
void
settings_delete
(
Settings
*
settings
);
/*
* Constructs a settings object by loading settings in textual form
* from the given stream.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* stream: A pointer to a stream. This parameter cannot be null.
*
* Return value: A pointer to a settings object,
* or null if an error occurred.
*/
Settings
*
settings_open
(
FILE
*
stream
);
/*
* Saves the current settings object in textual form to the given stream.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* stream: A pointer to a stream. This parameter cannot be null.
*
* Return value: 1 if the operation succeeded, 0 otherwise.
*/
int
settings_save
(
const
Settings
*
settings
,
FILE
*
stream
);
/*
* Returns the value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out_buf: A pointer to an output buffer which will contain the value,
* if it exists and fits into the buffer.
*
* n_out_buf: The size of the output buffer in bytes.
*
* Return value: If out_buf is set to null and n_out_buf is set to 0 the return
* value will be the number of bytes required to store the value (if it exists)
* and its null-terminator. For all other parameter configurations the return value
* is 1 if an associated value was found and completely copied into the output buffer,
* 0 otherwise.
*/
int
settings_get
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
char
*
out_buf
,
unsigned
int
n_out_buf
);
/*
* Returns the integer value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The integer value associated to the provided section and
* key, or 0 if no such value exists.
*/
int
settings_get_int
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
);
/*
* Returns the long integer value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The long integer value associated to the provided section and
* key, or 0 if no such value exists.
*/
long
settings_get_long
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
);
/*
* Returns the double value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The double value associated to the provided section and
* key, or 0 if no such value exists.
*/
double
settings_get_double
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
);
/*
* Returns the integer tuple associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out: A pointer to an output buffer.
*
* n_out: The maximum number of elements the output buffer can hold.
*
* Return value: 1 if the entire tuple was copied into the output buffer,
* 0 otherwise.
*/
int
settings_get_int_tuple
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
int
*
out
,
unsigned
int
n_out
);
/*
* Returns the long tuple associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out: A pointer to an output buffer.
*
* n_out: The maximum number of elements the output buffer can hold.
*
* Return value: 1 if the entire tuple was copied into the output buffer,
* 0 otherwise.
*/
long
settings_get_long_tuple
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
long
*
out
,
unsigned
int
n_out
);
/*
* Returns the double tuple associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out: A pointer to an output buffer.
*
* n_out: The maximum number of elements the output buffer can hold.
*
* Return value: 1 if the entire tuple was copied into the output buffer,
* 0 otherwise.
*/
double
settings_get_double_tuple
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
double
*
out
,
unsigned
int
n_out
);
/*
* Associates a value with the supplied key in the provided section.
* If the key is already associated with a value, the previous value
* is replaced.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null. The string must have a string length > 0. The string will
* be copied.
*
* key: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* value: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* Return value: 1 if the association succeeded, 0 otherwise.
*/
int
settings_set
(
Settings
*
setting
,
const
char
*
section
,
const
char
*
key
,
const
char
*
value
);
/*
* Returns the number of associations between keys and values that exist
* in the provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The number of associations between keys and values in
* the provided section.
*/
int
settings_section_get_count
(
const
Settings
*
settings
,
const
char
*
section
);
/*
* Enumerates all associations between keys and values in the provided
* section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* enum_func: A pointer to a callback function that will be
* called by this procedure once for every key associated
* with a value. This parameter cannot be null.
*
* obj: A pointer to a client-specific object. This parameter will be
* passed back to the client's callback function. This parameter can
* be null.
*
* Return value: 1 if enumeration completed, 0 otherwise.
*/
int
settings_section_enum
(
const
Settings
*
settings
,
const
char
*
section
,
settings_section_enum_func
enum_func
,
const
void
*
obj
);
typedef
struct
Settings
Settings
;
/*
* This callback function is called once per key-value when enumerating
* all keys inside a section.
*
* Parameters:
*
* key: A pointer to a null-terminated C string. The string must not
* be modified by the client.
*
* value: A pointer to a null-terminated C string. The string must
* not be modified by the client.
*
* obj: A pointer to a client-specific object. This parameter may be
* null.
*
* Return value: None.
*/
typedef
void
(
*
settings_section_enum_func
)(
const
char
*
key
,
const
char
*
value
,
const
void
*
obj
);
/*
* Creates a settings object.
*
* Return value: A pointer to a settings object,
* or null if a new settings object could not be allocated.
*/
Settings
*
settings_new
();
/*
* Releases all memory held by a settings object.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
* If the supplied settings object has been previously released, the
* behaviour of this function is undefined.
*
* Return value: None.
*/
void
settings_delete
(
Settings
*
settings
);
/*
* Constructs a settings object by loading settings in textual form
* from the given stream.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* stream: A pointer to a stream. This parameter cannot be null.
*
* Return value: A pointer to a settings object,
* or null if an error occurred.
*/
Settings
*
settings_open
(
FILE
*
stream
);
/*
* Saves the current settings object in textual form to the given stream.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* stream: A pointer to a stream. This parameter cannot be null.
*
* Return value: 1 if the operation succeeded, 0 otherwise.
*/
int
settings_save
(
const
Settings
*
settings
,
FILE
*
stream
);
/*
* Returns the value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out_buf: A pointer to an output buffer which will contain the value,
* if it exists and fits into the buffer.
*
* n_out_buf: The size of the output buffer in bytes.
*
* Return value: If out_buf is set to null and n_out_buf is set to 0 the return
* value will be the number of bytes required to store the value (if it exists)
* and its null-terminator. For all other parameter configurations the return value
* is 1 if an associated value was found and completely copied into the output buffer,
* 0 otherwise.
*/
int
settings_get
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
char
*
out_buf
,
unsigned
int
n_out_buf
);
/*
* Returns the integer value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The integer value associated to the provided section and
* key, or 0 if no such value exists.
*/
int
settings_get_int
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
);
/*
* Returns the long integer value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The long integer value associated to the provided section and
* key, or 0 if no such value exists.
*/
long
settings_get_long
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
);
/*
* Returns the double value associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The double value associated to the provided section and
* key, or 0 if no such value exists.
*/
double
settings_get_double
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
);
/*
* Returns the integer tuple associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out: A pointer to an output buffer.
*
* n_out: The maximum number of elements the output buffer can hold.
*
* Return value: 1 if the entire tuple was copied into the output buffer,
* 0 otherwise.
*/
int
settings_get_int_tuple
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
int
*
out
,
unsigned
int
n_out
);
/*
* Returns the long tuple associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out: A pointer to an output buffer.
*
* n_out: The maximum number of elements the output buffer can hold.
*
* Return value: 1 if the entire tuple was copied into the output buffer,
* 0 otherwise.
*/
long
settings_get_long_tuple
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
long
*
out
,
unsigned
int
n_out
);
/*
* Returns the double tuple associated with the supplied key in the
* provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* key: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* out: A pointer to an output buffer.
*
* n_out: The maximum number of elements the output buffer can hold.
*
* Return value: 1 if the entire tuple was copied into the output buffer,
* 0 otherwise.
*/
double
settings_get_double_tuple
(
const
Settings
*
settings
,
const
char
*
section
,
const
char
*
key
,
double
*
out
,
unsigned
int
n_out
);
/*
* Associates a value with the supplied key in the provided section.
* If the key is already associated with a value, the previous value
* is replaced.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null. The string must have a string length > 0. The string will
* be copied.
*
* key: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* value: A pointer to a null-terminated C string. This parameter
* cannot be null. The string must have a string length > 0. The
* string will be copied.
*
* Return value: 1 if the association succeeded, 0 otherwise.
*/
int
settings_set
(
Settings
*
setting
,
const
char
*
section
,
const
char
*
key
,
const
char
*
value
);
/*
* Returns the number of associations between keys and values that exist
* in the provided section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* Return value: The number of associations between keys and values in
* the provided section.
*/
int
settings_section_get_count
(
const
Settings
*
settings
,
const
char
*
section
);
/*
* Enumerates all associations between keys and values in the provided
* section.
*
* Parameters:
*
* settings: A pointer to a settings object. This parameter cannot be null.
*
* section: A pointer to a null-terminated C string. This parameter cannot
* be null.
*
* enum_func: A pointer to a callback function that will be
* called by this procedure once for every key associated
* with a value. This parameter cannot be null.
*
* obj: A pointer to a client-specific object. This parameter will be
* passed back to the client's callback function. This parameter can
* be null.
*
* Return value: 1 if enumeration completed, 0 otherwise.
*/
int
settings_section_enum
(
const
Settings
*
settings
,
const
char
*
section
,
settings_section_enum_func
enum_func
,
const
void
*
obj
);
#ifdef __cplusplus
}
...
...
src/strmap.c
View file @
fcf18f52
...
...
@@ -6,13 +6,13 @@
* Version history:
* 1.0.0 - initial release
* 2.0.0 - changed function prefix from strmap to sm to ensure
* ANSI C compatibility
* ANSI C compatibility
*
* strmap.c
*
* Copyright (c) 2009, 2011 Per Ola Kristensson.
*
* Per Ola Kristensson <pok21@cam.ac.uk>
* Per Ola Kristensson <pok21@cam.ac.uk>
* Inference Group, Department of Physics
* University of Cambridge
* Cavendish Laboratory
...
...
@@ -40,18 +40,18 @@ typedef struct Pair Pair;
typedef
struct
Bucket
Bucket
;
struct
Pair
{
char
*
key
;
char
*
value
;
char
*
key
;
char
*
value
;
};
struct
Bucket
{
unsigned
int
count
;
Pair
*
pairs
;
unsigned
int
count
;
Pair
*
pairs
;
};
struct
StrMap
{
unsigned
int
count
;
Bucket
*
buckets
;
unsigned
int
count
;
Bucket
*
buckets
;
};
static
Pair
*
get_pair
(
Bucket
*
bucket
,
const
char
*
key
);
...
...
@@ -59,247 +59,246 @@ static unsigned long hash(const char *str);
StrMap
*
sm_new
(
unsigned
int
capacity
)
{
StrMap
*
map
;
map
=
(
StrMap
*
)
malloc
(
sizeof
(
StrMap
));
if
(
map
==
NULL
)
{
return
NULL
;
}
map
->
count
=
capacity
;
map
->
buckets
=
(
Bucket
*
)
malloc
(
map
->
count
*
sizeof
(
Bucket
));
if
(
map
->
buckets
==
NULL
)
{
free
(
map
);
return
NULL
;
}
memset
(
map
->
buckets
,
0
,
map
->
count
*
sizeof
(
Bucket
));
return
map
;
StrMap
*
map
;
map
=
(
StrMap
*
)
malloc
(
sizeof
(
StrMap
));
if
(
map
==
NULL
)
{
return
NULL
;
}
map
->
count
=
capacity
;
map
->
buckets
=
(
Bucket
*
)
malloc
(
map
->
count
*
sizeof
(
Bucket
));
if
(
map
->
buckets
==
NULL
)
{
free
(
map
);
return
NULL
;
}
memset
(
map
->
buckets
,
0
,
map
->
count
*
sizeof
(
Bucket
));
return
map
;
}
void
sm_delete
(
StrMap
*
map
)
{
unsigned
int
i
,
j
,
n
,
m
;
Bucket
*
bucket
;
Pair
*
pair
;
if
(
map
==
NULL
)
{
return
;
}
n
=
map
->
count
;
bucket
=
map
->
buckets
;
i
=
0
;
while
(
i
<
n
)
{
m
=
bucket
->
count
;
pair
=
bucket
->
pairs
;
j
=
0
;
while
(
j
<
m
)
{
free
(
pair
->
key
);
free
(
pair
->
value
);
pair
++
;
j
++
;
}
free
(
bucket
->
pairs
);
bucket
++
;
i
++
;
}
free
(
map
->
buckets
);
free
(
map
);
unsigned
int
i
,
j
,
n
,
m
;
Bucket
*
bucket
;
Pair
*
pair
;
if
(
map
==
NULL
)
{
return
;
}
n
=
map
->
count
;
bucket
=
map
->
buckets
;
i
=
0
;
while
(
i
<
n
)
{
m
=
bucket
->
count
;
pair
=
bucket
->
pairs
;
j
=
0
;
while
(
j
<
m
)
{
free
(
pair
->
key
);
free
(
pair
->
value
);
pair
++
;
j
++
;
}
free
(
bucket
->
pairs
);
bucket
++
;
i
++
;
}
free
(
map
->
buckets
);
free
(
map
);
}
int
sm_get
(
const
StrMap
*
map
,
const
char
*
key
,
char
*
out_buf
,
unsigned
int
n_out_buf
)
{
unsigned
int
index
;
Bucket
*
bucket
;
Pair
*
pair
;
if
(
map
==
NULL
)
{
return
0
;
}
if
(
key
==
NULL
)
{
return
0
;
}
index
=
hash
(
key
)
%
map
->
count
;
bucket
=
&
(
map
->
buckets
[
index
]);
pair
=
get_pair
(
bucket
,
key
);
if
(
pair
==
NULL
)
{
return
0
;
}
if
(
out_buf
==
NULL
&&
n_out_buf
==
0
)
{
return
strlen
(
pair
->
value
)
+
1
;
}
if
(
out_buf
==
NULL
)
{
return
0
;
}
if
(
strlen
(
pair
->
value
)
>=
n_out_buf
)
{
return
0
;
}
strcpy
(
out_buf
,
pair
->
value
);
return
1
;
unsigned
int
index
;
Bucket
*
bucket
;
Pair
*
pair
;
if
(
map
==
NULL
)
{
return
0
;
}
if
(
key
==
NULL
)
{
return
0
;
}
index
=
hash
(
key
)
%
map
->
count
;
bucket
=
&
(
map
->
buckets
[
index
]);
pair
=
get_pair
(
bucket
,
key
);
if
(
pair
==
NULL
)
{
return
0
;
}
if
(
out_buf
==
NULL
&&
n_out_buf
==
0
)
{
return
strlen
(
pair
->
value
)
+
1
;
}
if
(
out_buf
==
NULL
)
{
return
0
;
}
if
(
strlen
(
pair
->
value
)
>=
n_out_buf
)
{
return
0
;
}
strcpy
(
out_buf
,
pair
->
value
);
return
1
;
}
int
sm_exists
(
const
StrMap
*
map
,
const
char
*
key
)
{
unsigned
int
index
;
Bucket
*
bucket
;
Pair
*
pair
;
if
(
map
==
NULL
)
{
return
0
;
}
if
(
key
==
NULL
)
{
return
0
;
}
index
=
hash
(
key
)
%
map
->
count
;
bucket
=
&
(
map
->
buckets
[
index
]);
pair
=
get_pair
(
bucket
,
key
);
if
(
pair
==
NULL
)
{
return
0
;
}
return
1
;
unsigned
int
index
;
Bucket
*
bucket
;
Pair
*
pair
;
if
(
map
==
NULL
)
{
return
0
;
}
if
(
key
==
NULL
)
{
return
0
;
}
index
=
hash
(
key
)
%
map
->
count
;
bucket
=
&
(
map
->
buckets
[
index
]);
pair
=
get_pair
(
bucket
,
key
);
if
(
pair
==
NULL
)
{
return
0
;
}
return
1
;
}
int
sm_put
(
StrMap
*
map
,
const
char
*
key
,
const
char
*
value
)
{
unsigned
int
key_len
,
value_len
,
index
;
Bucket
*
bucket
;
Pair
*
tmp_pairs
,
*
pair
;
char
*
tmp_value
;
char
*
new_key
,
*
new_value
;
if
(
map
==
NULL
)
{
return
0
;
}
if
(
key
==
NULL
||
value
==
NULL
)
{
return
0
;
}
key_len
=
strlen
(
key
);
value_len
=
strlen
(
value
);
/* Get a pointer to the bucket the key string hashes to */
index
=
hash
(
key
)
%
map
->
count
;
bucket
=
&
(
map
->
buckets
[
index
]);
/* Check if we can handle insertion by simply replacing
* an existing value in a key-value pair in the bucket.
*/
if
((
pair
=
get_pair
(
bucket
,
key
))
!=
NULL
)
{
/* The bucket contains a pair that matches the provided key,
* change the value for that pair to the new value.
*/
if
(
strlen
(
pair
->
value
)
<
value_len
)
{
/* If the new value is larger than the old value, re-allocate
* space for the new larger value.
*/
tmp_value
=
(
char
*
)
realloc
(
pair
->
value
,
(
value_len
+
1
)
*
sizeof
(
char
));
if
(
tmp_value
==
NULL
)
{
return
0
;
}
pair
->
value
=
tmp_value
;
}
/* Copy the new value into the pair that matches the key */
strcpy
(
pair
->
value
,
value
);
return
1
;
}
/* Allocate space for a new key and value */
new_key
=
(
char
*
)
malloc
((
key_len
+
1
)
*
sizeof
(
char
));
if
(
new_key
==
NULL
)
{
return
0
;
}
new_value
=
(
char
*
)
malloc
((
value_len
+
1
)
*
sizeof
(
char
));
if
(
new_value
==
NULL
)
{
free
(
new_key
);
return
0
;
}
/* Create a key-value pair */
if
(
bucket
->
count
==
0
)
{
/* The bucket is empty, lazily allocate space for a single
* key-value pair.
*/
bucket
->
pairs
=
(
Pair
*
)
malloc
(
sizeof
(
Pair
));
if
(
bucket
->
pairs
==
NULL
)
{
free
(
new_key
);
free
(
new_value
);
return
0
;
}
bucket
->
count
=
1
;
}
else
{
/* The bucket wasn't empty but no pair existed that matches the provided
* key, so create a new key-value pair.
*/
tmp_pairs
=
(
Pair
*
)
realloc
(
bucket
->
pairs
,
(
bucket
->
count
+
1
)
*
sizeof
(
Pair
));
if
(
tmp_pairs
==
NULL
)
{
free
(
new_key
);
free
(
new_value
);
return
0
;
}
bucket
->
pairs
=
tmp_pairs
;
bucket
->
count
++
;
}
/* Get the last pair in the chain for the bucket */
pair
=
&
(
bucket
->
pairs
[
bucket
->
count
-
1
]);
pair
->
key
=
new_key
;
pair
->
value
=
new_value
;
/* Copy the key and its value into the key-value pair */
strcpy
(
pair
->
key
,
key
);
strcpy
(
pair
->
value
,
value
);
return
1
;
unsigned
int
key_len
,
value_len
,
index
;
Bucket
*
bucket
;
Pair
*
tmp_pairs
,
*
pair
;
char
*
tmp_value
;
char
*
new_key
,
*
new_value
;
if
(
map
==
NULL
)
{
return
0
;
}
if
(
key
==
NULL
||
value
==
NULL
)
{
return
0
;
}
key_len
=
strlen
(
key
);
value_len
=
strlen
(
value
);
/* Get a pointer to the bucket the key string hashes to */
index
=
hash
(
key
)
%
map
->
count
;
bucket
=
&
(
map
->
buckets
[
index
]);
/* Check if we can handle insertion by simply replacing
* an existing value in a key-value pair in the bucket.
*/
if
((
pair
=
get_pair
(
bucket
,
key
))
!=
NULL
)
{
/* The bucket contains a pair that matches the provided key,
* change the value for that pair to the new value.
*/
if
(
strlen
(
pair
->
value
)
<
value_len
)
{
/* If the new value is larger than the old value, re-allocate
* space for the new larger value.
*/
tmp_value
=
(
char
*
)
realloc
(
pair
->
value
,
(
value_len
+
1
)
*
sizeof
(
char
));
if
(
tmp_value
==
NULL
)
{
return
0
;
}
pair
->
value
=
tmp_value
;
}
/* Copy the new value into the pair that matches the key */
strcpy
(
pair
->
value
,
value
);
return
1
;
}
/* Allocate space for a new key and value */
new_key
=
(
char
*
)
malloc
((
key_len
+
1
)
*
sizeof
(
char
));
if
(
new_key
==
NULL
)
{
return
0
;
}
new_value
=
(
char
*
)
malloc
((
value_len
+
1
)
*
sizeof
(
char
));
if
(
new_value
==
NULL
)
{
free
(
new_key
);
return
0
;
}
/* Create a key-value pair */
if
(
bucket
->
count
==
0
)
{
/* The bucket is empty, lazily allocate space for a single
* key-value pair.
*/
bucket
->
pairs
=
(
Pair
*
)
malloc
(
sizeof
(
Pair
));
if
(
bucket
->
pairs
==
NULL
)
{
free
(
new_key
);
free
(
new_value
);
return
0
;
}
bucket
->
count
=
1
;
}
else
{
/* The bucket wasn't empty but no pair existed that matches the provided
* key, so create a new key-value pair.
*/
tmp_pairs
=
(
Pair
*
)
realloc
(
bucket
->
pairs
,
(
bucket
->
count
+
1
)
*
sizeof
(
Pair
));
if
(
tmp_pairs
==
NULL
)
{
free
(
new_key
);
free
(
new_value
);
return
0
;
}
bucket
->
pairs
=
tmp_pairs
;
bucket
->
count
++
;
}
/* Get the last pair in the chain for the bucket */
pair
=
&
(
bucket
->
pairs
[
bucket
->
count
-
1
]);
pair
->
key
=
new_key
;
pair
->
value
=
new_value
;
/* Copy the key and its value into the key-value pair */
strcpy
(
pair
->
key
,
key
);
strcpy
(
pair
->
value
,
value
);
return
1
;
}
int
sm_get_count
(
const
StrMap
*
map
)
{
unsigned
int
i
,
j
,
n
,
m
;
unsigned
int
count
;
Bucket
*
bucket
;
Pair
*
pair
;
if
(
map
==
NULL
)
{
return
0
;
}
bucket
=
map
->
buckets
;
n
=
map
->
count
;
i
=
0
;
count
=
0
;
while
(
i
<
n
)
{
pair
=
bucket
->
pairs
;
m
=
bucket
->
count
;
j
=
0
;
while
(
j
<
m
)
{
count
++
;
pair
++
;
j
++
;
}
bucket
++
;
i
++
;
}
return
count
;
unsigned
int
i
,
j
,
n
,
m
;
unsigned
int
count
;
Bucket
*
bucket
;
Pair
*
pair
;
if
(
map
==
NULL
)
{
return
0
;
}
bucket
=
map
->
buckets
;
n
=
map
->
count
;
i
=
0
;
count
=
0
;
while
(
i
<
n
)
{
pair
=
bucket
->
pairs
;
m
=
bucket
->
count
;
j
=
0
;
while
(
j
<
m
)
{
count
++
;
pair
++
;
j
++
;
}
bucket
++
;
i
++
;
}
return
count
;
}
int
sm_enum
(
const
StrMap
*
map
,
sm_enum_func
enum_func
,
const
void
*
obj
)
{
unsigned
int
i
,
j
,
n
,
m
;
Bucket
*
bucket
;
Pair
*
pair
;
if
(
map
==
NULL
)
{
return
0
;
}
if
(
enum_func
==
NULL
)
{
return
0
;
}
bucket
=
map
->
buckets
;
n
=
map
->
count
;
i
=
0
;
while
(
i
<
n
)
{
pair
=
bucket
->
pairs
;
m
=
bucket
->
count
;
j
=
0
;
while
(
j
<
m
)
{
enum_func
(
pair
->
key
,
pair
->
value
,
obj
);
pair
++
;
j
++
;
}
bucket
++
;
i
++
;
}
return
1
;
unsigned
int
i
,
j
,
n
,
m
;
Bucket
*
bucket
;
Pair
*
pair
;
if
(
map
==
NULL
)
{
return
0
;
}
if
(
enum_func
==
NULL
)
{
return
0
;
}
bucket
=
map
->
buckets
;
n
=
map
->
count
;
i
=
0
;
while
(
i
<
n
)
{
pair
=
bucket
->
pairs
;
m
=
bucket
->
count
;
j
=
0
;
while
(
j
<
m
)
{
enum_func
(
pair
->
key
,
pair
->
value
,
obj
);
pair
++
;
j
++
;
}
bucket
++
;
i
++
;
}
return
1
;
}
/*
...
...
@@ -308,25 +307,25 @@ int sm_enum(const StrMap *map, sm_enum_func enum_func, const void *obj)
*/
static
Pair
*
get_pair
(
Bucket
*
bucket
,
const
char
*
key
)
{
unsigned
int
i
,
n
;
Pair
*
pair
;
n
=
bucket
->
count
;
if
(
n
==
0
)
{
return
NULL
;
}
pair
=
bucket
->
pairs
;
i
=
0
;
while
(
i
<
n
)
{
if
(
pair
->
key
!=
NULL
&&
pair
->
value
!=
NULL
)
{
if
(
strcmp
(
pair
->
key
,
key
)
==
0
)
{
return
pair
;
}
}
pair
++
;
i
++
;
}
return
NULL
;
unsigned
int
i
,
n
;
Pair
*
pair
;
n
=
bucket
->
count
;
if
(
n
==
0
)
{
return
NULL
;
}
pair
=
bucket
->
pairs
;
i
=
0
;
while
(
i
<
n
)
{
if
(
pair
->
key
!=
NULL
&&
pair
->
value
!=
NULL
)
{
if
(
strcmp
(
pair
->
key
,
key
)
==
0
)
{
return
pair
;
}
}
pair
++
;
i
++
;
}
return
NULL
;
}
/*
...
...
@@ -334,13 +333,13 @@ static Pair * get_pair(Bucket *bucket, const char *key)
*/
static
unsigned
long
hash
(
const
char
*
str
)
{
unsigned
long
hash
=
5381
;
int
c
;
unsigned
long
hash
=
5381
;
int
c
;
while
(
c
=
*
str
++
)
{
hash
=
((
hash
<<
5
)
+
hash
)
+
c
;
}
return
hash
;
while
(
c
=
*
str
++
)
{
hash
=
((
hash
<<
5
)
+
hash
)
+
c
;
}
return
hash
;
}
/*
...
...
src/strmap.h
View file @
fcf18f52
...
...
@@ -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
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment