Fixes #18. Seems ready for v1.4.0
This commit is contained in:
parent
03ac20500b
commit
1f8131bd9d
15 changed files with 323 additions and 47 deletions
|
@ -3,8 +3,7 @@ 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/)
|
||||
This is an enhanced version of [Allan McRae mbpfan](http://allanmcrae.com/2010/05/simple-macbook-pro-fan-daemon/)
|
||||
|
||||
Fan-Control-Daemon is a daemon that uses input from coretemp module and sets the fan speed using the applesmc module.
|
||||
This enhanced version assumes any number of processors and fans (max. 10).
|
||||
|
@ -50,10 +49,6 @@ Compile with
|
|||
|
||||
make
|
||||
|
||||
Manually compile with
|
||||
|
||||
gcc -o bin/mbpfan src/mbpfan.c -lm
|
||||
|
||||
|
||||
Install Instructions
|
||||
--------------------
|
||||
|
|
0
mbpfan.init.debian
Executable file → Normal file
0
mbpfan.init.debian
Executable file → Normal file
0
mbpfan.init.gentoo
Executable file → Normal file
0
mbpfan.init.gentoo
Executable file → Normal file
0
mbpfan.init.redhat
Executable file → Normal file
0
mbpfan.init.redhat
Executable file → Normal file
|
@ -1,6 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
# not maintained in this proejct
|
||||
# Archlinux rc script
|
||||
# not maintained in this project
|
||||
# please, fix it and contribute back to the project
|
||||
|
||||
daemon_name=mbpfan
|
||||
|
15
src/daemon.c
15
src/daemon.c
|
@ -34,10 +34,12 @@ 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;
|
||||
}
|
||||
|
@ -48,11 +50,13 @@ 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;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -103,6 +107,7 @@ void go_daemon(void (*fan_control)())
|
|||
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);
|
||||
|
@ -115,9 +120,11 @@ void go_daemon(void (*fan_control)())
|
|||
if (daemonize) {
|
||||
|
||||
pid_slave = fork();
|
||||
|
||||
if (pid_slave < 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (pid_slave > 0) {
|
||||
// kill the father
|
||||
exit(EXIT_SUCCESS);
|
||||
|
@ -127,6 +134,7 @@ void go_daemon(void (*fan_control)())
|
|||
|
||||
// new sid_slave for the child process
|
||||
sid_slave = setsid();
|
||||
|
||||
if (sid_slave < 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -151,23 +159,30 @@ void go_daemon(void (*fan_control)())
|
|||
printf("Writing a new .pid file with value %d at: %s\n", current_pid, program_pid);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef _DAEMON_H_
|
||||
#define _DAEMON_H_
|
||||
|
||||
/**
|
||||
* Write the PID of the forked daemon to the
|
||||
|
@ -47,4 +49,6 @@ void signal_handler(int signal);
|
|||
/**
|
||||
* Daemonizes
|
||||
*/
|
||||
int go_daemon(void (*function)());
|
||||
int go_daemon(void (*function)());
|
||||
|
||||
#endif
|
16
src/global.h
16
src/global.h
|
@ -1,5 +1,19 @@
|
|||
#ifndef _GLOBAL_H_
|
||||
#define _GLOBAL_H_
|
||||
|
||||
extern int daemonize;
|
||||
extern int verbose;
|
||||
|
||||
extern const char* program_name;
|
||||
extern const char* program_pid;
|
||||
extern const char* program_pid;
|
||||
|
||||
struct s_sensors {
|
||||
char* path;
|
||||
char* fan_output_path;
|
||||
char* fan_manual_path;
|
||||
unsigned int temperature;
|
||||
struct s_sensors *next;
|
||||
};
|
||||
|
||||
typedef s_sensors t_sensors;
|
||||
#endif
|
|
@ -13,6 +13,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Code formatted with astyle -A3 -s --break-blocks=all --add-brackets *.c *.h
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
@ -46,6 +50,7 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
|
||||
int c;
|
||||
|
||||
while( (c = getopt(argc, argv, "hftv|help")) != -1) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
|
|
72
src/mbpfan.c
72
src/mbpfan.c
|
@ -57,7 +57,7 @@ int max_temp = 86; // do not set it > 90
|
|||
|
||||
int polling_interval = 7;
|
||||
|
||||
|
||||
/*
|
||||
struct s_sensors {
|
||||
char* path;
|
||||
char* fan_output_path;
|
||||
|
@ -65,6 +65,9 @@ struct s_sensors {
|
|||
unsigned int temperature;
|
||||
struct s_sensors *next;
|
||||
};
|
||||
*/
|
||||
|
||||
typedef struct s_sensors t_sensors;
|
||||
|
||||
|
||||
t_sensors *retrieve_sensors()
|
||||
|
@ -82,6 +85,7 @@ t_sensors *retrieve_sensors()
|
|||
sprintf(number,"%d",0);
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(i = 0; i<10; i++) {
|
||||
path = (char*) malloc(sizeof( char ) * path_size);
|
||||
|
||||
|
@ -98,24 +102,33 @@ t_sensors *retrieve_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;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
free(path);
|
||||
path = NULL;
|
||||
}
|
||||
if(sensors_head != NULL)
|
||||
|
||||
if(sensors_head != NULL) {
|
||||
find_fans(sensors_head);
|
||||
}
|
||||
|
||||
return sensors_head;
|
||||
}
|
||||
|
||||
|
@ -162,6 +175,7 @@ void find_fans(t_sensors* sensors)
|
|||
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;
|
||||
|
@ -173,6 +187,7 @@ void find_fans(t_sensors* sensors)
|
|||
|
||||
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);
|
||||
}
|
||||
|
@ -189,12 +204,15 @@ 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);
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
@ -214,6 +232,7 @@ t_sensors *refresh_sensors(t_sensors *sensors)
|
|||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
return sensors;
|
||||
}
|
||||
|
||||
|
@ -223,8 +242,10 @@ 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);
|
||||
|
@ -243,10 +264,12 @@ unsigned short get_temp(t_sensors* sensors)
|
|||
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;
|
||||
}
|
||||
|
@ -262,35 +285,63 @@ void retrieve_settings()
|
|||
/* 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 {
|
||||
/* Read configfile values */
|
||||
result = settings_get_int(settings, "general", "min_fan_speed");
|
||||
if (result != 0) min_fan_speed = result;
|
||||
|
||||
if (result != 0) {
|
||||
min_fan_speed = result;
|
||||
}
|
||||
|
||||
result = settings_get_int(settings, "general", "max_fan_speed");
|
||||
if (result != 0) max_fan_speed = result;
|
||||
|
||||
if (result != 0) {
|
||||
max_fan_speed = result;
|
||||
}
|
||||
|
||||
result = settings_get_int(settings, "general", "low_temp");
|
||||
if (result != 0) low_temp = result;
|
||||
|
||||
if (result != 0) {
|
||||
low_temp = result;
|
||||
}
|
||||
|
||||
result = settings_get_int(settings, "general", "high_temp");
|
||||
if (result != 0) high_temp = result;
|
||||
|
||||
if (result != 0) {
|
||||
high_temp = result;
|
||||
}
|
||||
|
||||
result = settings_get_int(settings, "general", "max_temp");
|
||||
if (result != 0) max_temp = result;
|
||||
|
||||
if (result != 0) {
|
||||
max_temp = result;
|
||||
}
|
||||
|
||||
result = settings_get_int(settings, "general", "polling_interval");
|
||||
if (result != 0) polling_interval = result;
|
||||
|
||||
if (result != 0) {
|
||||
polling_interval = result;
|
||||
}
|
||||
|
||||
/* Destroy the settings object */
|
||||
settings_delete(settings);
|
||||
|
@ -316,10 +367,12 @@ void mbpfan()
|
|||
|
||||
if(verbose) {
|
||||
printf("Sleeping for %d seconds\n", polling_interval);
|
||||
|
||||
if(daemonize) {
|
||||
syslog(LOG_INFO, "Sleeping for %d seconds", polling_interval);
|
||||
}
|
||||
}
|
||||
|
||||
sleep(polling_interval);
|
||||
|
||||
step_up = (float)( max_fan_speed - min_fan_speed ) /
|
||||
|
@ -354,6 +407,7 @@ void mbpfan()
|
|||
|
||||
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);
|
||||
}
|
||||
|
@ -363,10 +417,12 @@ void mbpfan()
|
|||
|
||||
if(verbose) {
|
||||
printf("Sleeping for %d seconds\n", polling_interval);
|
||||
|
||||
if(daemonize) {
|
||||
syslog(LOG_INFO, "Sleeping for %d seconds", polling_interval);
|
||||
}
|
||||
}
|
||||
|
||||
sleep(polling_interval);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef _MBPFAN_H_
|
||||
#define _MBPFAN_H_
|
||||
|
||||
/** Basic fan speed parameters
|
||||
*/
|
||||
extern int min_fan_speed;
|
||||
|
@ -82,4 +85,6 @@ unsigned short get_temp(t_sensors* sensors);
|
|||
/**
|
||||
* Main Program
|
||||
*/
|
||||
void mbpfan();
|
||||
void mbpfan();
|
||||
|
||||
#endif
|
|
@ -3,6 +3,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include "global.h"
|
||||
#include "mbpfan.h"
|
||||
#include "settings.h"
|
||||
#include "minunit.h"
|
||||
|
@ -10,32 +11,41 @@
|
|||
int tests_run = 0;
|
||||
|
||||
|
||||
static char *test_sensor_paths()
|
||||
static const 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)
|
||||
|
||||
if(tmp->path != NULL) {
|
||||
mu_assert("Sensor does not have valid temperature", tmp->temperature > 0);
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static char *test_fan_paths()
|
||||
static const 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)
|
||||
if(tmp->fan_output_path != NULL) {
|
||||
found_fan_path++;
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
mu_assert("No fans found", found_fan_path != 0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -46,8 +56,11 @@ unsigned time_seed()
|
|||
unsigned char *p = (unsigned char *)&now;
|
||||
unsigned seed = 0;
|
||||
size_t i;
|
||||
for ( i = 0; i < sizeof now; i++ )
|
||||
|
||||
for ( i = 0; i < sizeof now; i++ ) {
|
||||
seed = seed * ( UCHAR_MAX + 2U ) + p[i];
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
|
@ -56,17 +69,19 @@ unsigned time_seed()
|
|||
int stress(int n)
|
||||
{
|
||||
int f = n;
|
||||
|
||||
while (f > 0) {
|
||||
while(n > 0) {
|
||||
srand ( time_seed() );
|
||||
n--;
|
||||
}
|
||||
|
||||
f--;
|
||||
n = f;
|
||||
}
|
||||
}
|
||||
|
||||
static char *test_get_temp()
|
||||
static const char *test_get_temp()
|
||||
{
|
||||
t_sensors* sensors = retrieve_sensors();
|
||||
mu_assert("No sensors found", sensors != NULL);
|
||||
|
@ -78,21 +93,24 @@ static char *test_get_temp()
|
|||
return 0;
|
||||
}
|
||||
|
||||
static char *test_config_file()
|
||||
static const 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)
|
||||
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)
|
||||
|
||||
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);
|
||||
|
@ -107,7 +125,7 @@ static char *test_config_file()
|
|||
}
|
||||
|
||||
|
||||
static char *all_tests()
|
||||
static const char *all_tests()
|
||||
{
|
||||
mu_run_test(test_sensor_paths);
|
||||
mu_run_test(test_fan_paths);
|
||||
|
@ -120,12 +138,15 @@ int tests()
|
|||
{
|
||||
printf("Starting the tests..\n");
|
||||
printf("It is normal for them to take a bit to finish.\n");
|
||||
char *result = all_tests();
|
||||
const char *result = all_tests();
|
||||
|
||||
if (result != 0) {
|
||||
printf("%s \n", result);
|
||||
|
||||
} else {
|
||||
printf("ALL TESTS PASSED\n");
|
||||
}
|
||||
|
||||
printf("Tests run: %d\n", tests_run);
|
||||
|
||||
return result != 0;
|
||||
|
|
|
@ -1,27 +1,23 @@
|
|||
/**
|
||||
* This is the MinUnit testing framework - http://www.jera.com/techinfo/jtns/jtn002.html
|
||||
*/
|
||||
|
||||
#ifndef _MINUNIT_H_
|
||||
#define _MINUNIT_H_
|
||||
|
||||
#define mu_assert(message, test) do { if (!(test)) return message; } while (0)
|
||||
#define mu_run_test(test) do { char *message = test(); tests_run++; \
|
||||
#define mu_run_test(test) do { const char *message = test(); tests_run++; \
|
||||
if (message) return message; } while (0)
|
||||
|
||||
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;
|
||||
|
||||
|
||||
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 const char *test_sensor_paths();
|
||||
static const char *test_fan_paths();
|
||||
static const char *test_get_temp();
|
||||
static const char *test_config_file();
|
||||
|
||||
static char *all_tests();
|
||||
static const char *all_tests();
|
||||
|
||||
int tests();
|
||||
int tests();
|
||||
|
||||
#endif
|
110
src/settings.c
110
src/settings.c
|
@ -97,9 +97,11 @@ Settings * settings_new()
|
|||
Settings *settings;
|
||||
|
||||
settings = (Settings*)malloc(sizeof(Settings));
|
||||
|
||||
if (settings == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
settings->section_count = 0;
|
||||
settings->sections = NULL;
|
||||
return settings;
|
||||
|
@ -113,17 +115,22 @@ void settings_delete(Settings *settings)
|
|||
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);
|
||||
}
|
||||
|
@ -139,20 +146,26 @@ Settings * settings_open(FILE *stream)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -165,12 +178,15 @@ int settings_save(const Settings *settings, FILE *stream)
|
|||
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);
|
||||
|
@ -179,6 +195,7 @@ int settings_save(const Settings *settings, FILE *stream)
|
|||
i++;
|
||||
fputs("\n", stream);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -189,10 +206,13 @@ int settings_get(const Settings *settings, const char *section, const char *key,
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -203,6 +223,7 @@ int settings_get_int(const Settings *settings, const char *section, const char *
|
|||
if (get_converted_value(settings, section, key, CONVERT_MODE_INT, &i)) {
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -213,6 +234,7 @@ long settings_get_long(const Settings *settings, const char *section, const char
|
|||
if (get_converted_value(settings, section, key, CONVERT_MODE_LONG, &l)) {
|
||||
return l;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -223,6 +245,7 @@ double settings_get_double(const Settings *settings, const char *section, const
|
|||
if (get_converted_value(settings, section, key, CONVERT_MODE_DOUBLE, &d)) {
|
||||
return d;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -248,36 +271,47 @@ int settings_set(Settings *settings, const char *section, const char *key, const
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -288,10 +322,13 @@ int settings_section_get_count(const Settings *settings, const char *section)
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -300,9 +337,11 @@ int settings_section_enum(const Settings *settings, const char *section, setting
|
|||
Section *sect;
|
||||
|
||||
sect = get_section(settings->sections, settings->section_count, section);
|
||||
|
||||
if (sect == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sm_enum(sect->map, enum_func, obj);
|
||||
}
|
||||
|
||||
|
@ -318,19 +357,24 @@ static void trim_str(const char *str, char *out_buf)
|
|||
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';
|
||||
}
|
||||
|
@ -355,39 +399,54 @@ static int parse_str(Settings *settings, char *str, ParseState *parse_state)
|
|||
|
||||
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;
|
||||
}
|
||||
|
@ -410,8 +469,10 @@ static int is_blank_str(const char *str)
|
|||
if (!is_blank_char(*str)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
str++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -426,6 +487,7 @@ static int is_comment_str(const char *str)
|
|||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -438,13 +500,16 @@ static int is_section_str(const char *str)
|
|||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -457,13 +522,16 @@ static int is_key_value_str(const char *str)
|
|||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -476,13 +544,16 @@ static int is_key_without_value_str(const char *str)
|
|||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -497,20 +568,24 @@ static int get_section_from_str(const char *str, char *out_buf, unsigned int out
|
|||
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;
|
||||
}
|
||||
|
@ -526,6 +601,7 @@ static int get_key_value_from_str(const char *str, char *out_buf1, unsigned int
|
|||
|
||||
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.
|
||||
|
@ -535,34 +611,42 @@ static int get_key_value_from_str(const char *str, char *out_buf1, unsigned int
|
|||
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.
|
||||
|
@ -570,16 +654,19 @@ static int get_key_value_from_str(const char *str, char *out_buf1, unsigned int
|
|||
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;
|
||||
}
|
||||
|
@ -593,6 +680,7 @@ static int get_key_without_value_from_str(const char *str, char *out_buf, unsign
|
|||
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.
|
||||
|
@ -602,16 +690,19 @@ static int get_key_without_value_from_str(const char *str, char *out_buf, unsign
|
|||
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;
|
||||
}
|
||||
|
@ -638,6 +729,7 @@ 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.
|
||||
|
@ -645,17 +737,20 @@ static const char * get_token(char *str, char delim, char **last)
|
|||
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;
|
||||
}
|
||||
|
@ -673,6 +768,7 @@ static int get_converted_value(const Settings *settings, const char *section, co
|
|||
if (!settings_get(settings, section, key, value, MAX_VALUECHARS)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case CONVERT_MODE_INT:
|
||||
*((int *)out) = atoi(value);
|
||||
|
@ -684,6 +780,7 @@ static int get_converted_value(const Settings *settings, const char *section, co
|
|||
*((double *)out) = atof(value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -704,14 +801,18 @@ static int get_converted_tuple(const Settings *settings, const char *section, co
|
|||
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.
|
||||
*/
|
||||
|
@ -729,8 +830,10 @@ static int get_converted_tuple(const Settings *settings, const char *section, co
|
|||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -745,15 +848,19 @@ static Section * get_section(Section *sections, unsigned int n, const char *name
|
|||
if (name == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
section = sections;
|
||||
i = 0;
|
||||
|
||||
while (i < n) {
|
||||
if (strcmp(section->name, name) == 0) {
|
||||
return section;
|
||||
}
|
||||
|
||||
section++;
|
||||
i++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -769,10 +876,13 @@ static void enum_map(const char *key, const char *value, const void *obj)
|
|||
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);
|
||||
|
|
54
src/strmap.c
54
src/strmap.c
|
@ -62,15 +62,19 @@ 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;
|
||||
}
|
||||
|
@ -84,23 +88,28 @@ void sm_delete(StrMap *map)
|
|||
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);
|
||||
}
|
||||
|
@ -114,24 +123,31 @@ int sm_get(const StrMap *map, const char *key, char *out_buf, unsigned int n_out
|
|||
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;
|
||||
}
|
||||
|
@ -145,15 +161,19 @@ int sm_exists(const StrMap *map, const char *key)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -168,14 +188,17 @@ int sm_put(StrMap *map, const char *key, const char *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.
|
||||
*/
|
||||
|
@ -188,50 +211,64 @@ int sm_put(StrMap *map, const char *key, const char *value)
|
|||
* 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;
|
||||
|
@ -252,22 +289,27 @@ int sm_get_count(const StrMap *map)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -280,24 +322,30 @@ int sm_enum(const StrMap *map, sm_enum_func enum_func, const void *obj)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -311,20 +359,25 @@ static Pair * get_pair(Bucket *bucket, const char *key)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -339,6 +392,7 @@ static unsigned long hash(const char *str)
|
|||
while (c = *str++) {
|
||||
hash = ((hash << 5) + hash) + c;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue