Compare commits

..

No commits in common. "master" and "V1.0.86" have entirely different histories.

14 changed files with 56 additions and 238 deletions

View File

@ -1,12 +1,4 @@
Version 1.88 2026-09-04
* local_host_ip_addrs_to_string: fix buffer overflow
* shared_func.[hc]: add function parse_timestamp
* ini_file_reader.[hc]: add function iniGetTimestampValueEx
Version 1.87 2026-07-10
* ini_file_readers can refer env variable such as %{env::FASTDFS_IPADDR}
Version 1.86 2026-06-26 Version 1.86 2026-06-26
* add function fc_parse_version * add function fc_parse_version
* change return type of format_ip_address and format_ip_port * change return type of format_ip_address and format_ip_port

View File

@ -21,5 +21,5 @@ Debian, Ubuntu etc.:
# the command lines as: # the command lines as:
git clone https://github.com/happyfish100/libfastcommon.git git clone https://github.com/happyfish100/libfastcommon.git
cd libfastcommon; git checkout V1.0.88 cd libfastcommon; git checkout V1.0.86
./make.sh clean && ./make.sh && sudo ./make.sh install ./make.sh clean && ./make.sh && sudo ./make.sh install

View File

@ -1,3 +1,11 @@
Copyright (C) 2010 Happy Fish / YuQing
libfastcommon may be copied only under the terms of the Less GNU General
Public License(LGPL).
Please visit the libfastcommon Home Page for more detail.
English language: https://github.com/happyfish100/libfastcommon
Chinese language: http://www.fastken.com/
c common functions library extracted from my open source projects FastDFS and c common functions library extracted from my open source projects FastDFS and
FastDHT. this library is very simple and stable. FastDHT. this library is very simple and stable.
@ -6,29 +14,20 @@ some functions are wrappered into php extension, such as fastcommon_gethostaddrs
fastcommon_id_generator_xxx, fastcommon_get_ifconfigs, fastcommon_get_sysinfo etc. fastcommon_id_generator_xxx, fastcommon_get_ifconfigs, fastcommon_get_sysinfo etc.
C function including: C function including:
logger: [logger.h] asynchronously sync to disk for high performance, thread safe, logger: [logger.h] asynchronously sync to disk for high performance, thread safe,
log rotate, auto delete old log files, compress log file etc. log rotate, auto delete old log files, compress log file etc.
ini file reader: [ini_file_reader.h] support sections marked by [SectionName], ini file reader: [ini_file_reader.h] support sections marked by [SectionName]
support a config item ocurs multiple times for multiple values, such as: support a config item ocurs multiple times for multiple values, such as:
```
tracker_server = ip1 tracker_server = ip1
tracker_server = ip2 tracker_server = ip2
```
```
#include directive to include other ini file #include directive to include other ini file
#@function directive for annotation #@function directive for annotation
#@set directive to set variables for condition of #@if directive #@set directive to set variables for condition of #@if directive
support control statements for special purpose as: support control statements for special purpose as:
#@if, #@else, #@endif, #@for, #@endfor #@if, #@else, #@endif, #@for, #@endfor
```
for more detail, please see [ini file reader guide](doc/ini_file_reader-Chinese.md) id generator: [id_generator.h] generate unique 64 bits integer ID for multi processes
id generator: [id_generator.h] generate unique 64 bits integer ID for multi processes.
for more detail, please see [id generator description](doc/id_generator-Chinese.md)
string operation: [shared_func.h] uppercase, lowercase, trim etc. string operation: [shared_func.h] uppercase, lowercase, trim etc.
@ -73,5 +72,5 @@ C function including:
char convert: [char_converter.h] and [char_convert_loader.h] for fast char convert char convert: [char_converter.h] and [char_convert_loader.h] for fast char convert
more detail info please see the c header files. detail info please see the c header files.

View File

@ -10,42 +10,38 @@ libfastcommon是在github开源的⼀个C函数库。它提供了ini⽂件解析
## ini_file_reader的主要特点 ## ini_file_reader的主要特点
### 1、⽀持section ### 1、⽀持section
例如:
``` ```
[workers] 例如: [workers]
threads = 4
# 其他配置项
``` ```
### 2、⼀个配置项可以出现多次 ### 2、⼀个配置项可以出现多次
通过iniGetValues或者iniGetValuesEx获取。例如
``` ```
tracker_server = 172.16.168.10 通过iniGetValues或者iniGetValuesEx获取。例如
tracker_server = 172.16.168.11 tracker_server = ip1
tracker_server = ip2
``` ```
### 3、 #include指令包含其他配置⽂件 ### 3、 #include指令包含其他配置⽂件
可以包含本地配置⽂件也可以包含URL目前仅⽀持HTTP。例如
``` ```
#include http.conf 可以包含本地⽂件也可以包含URL目前仅⽀持HTTP。例如
#include http.conf
``` ```
### 4、 #@function指令⽀持标注 ### 4、 #@function指令⽀持标注
配置项的取值为扩展(外部)动态库的返回值。
⽀持三个内置标注:
``` ```
配置项的取值为扩展(外部)动态库的返回值
V1.39⽀持三个内置标注:
I. LOCAL_IP_GET [inner | private | outer | public] 获取本机IP地址 I. LOCAL_IP_GET [inner | private | outer | public] 获取本机IP地址
inner或private表示获取内网IPouter或public表示获取外网IP inner或private表示获取内网IPouter或public表示获取外网IP
[index]表示获取指定序号的本机IP0表示获取第一个IP-1表示获取最后一个IP [index]表示获取指定序号的本机IP0表示获取第一个IP-1表示获取最后一个IP
例如:[0]、inner[-1], outer[1]等等 例如:[0]、inner[-1], outer[1]等等
II. SHELL_EXEC 获取命令⾏输出执行的command为配置项 II. SHELL_EXEC 获取命令⾏输出执行的command为配置项
III. REPLACE_VARS 替换配置项中%{VARIABLE}格式的变量,普通变量由#@set指令设置。 III. REPLACE_VARS 替换配置项中%{VARIABLE}格式的变量,变量由#@set指令设置
可以引用环境变量,格式为 %{env::VARIABLE},例如 %{env::FASTDFS_IPADDR}
``` ```
配置⽰例:
``` ```
配置⽰例:
#@function SHELL_EXEC #@function SHELL_EXEC
host = hostname host = hostname
@ -61,14 +57,12 @@ tracker_server = 172.16.168.11
### 5、 #@add_annotation 扩展#@function标签 ### 5、 #@add_annotation 扩展#@function标签
```
格式: 格式:
```
#@add_annotation <function> <动态库文件名> [参数1, 参数2, ...] #@add_annotation <function> <动态库文件名> [参数1, 参数2, ...]
```
参数个数0到3个。 参数个数0到3个。
使用libshmcache扩展标签CONFIG_GET示例 使用libshmcache扩展标签CONFIG_GET示例
```
#@add_annotation CONFIG_GET /usr/lib/libshmcache.so /etc/libshmcache.conf #@add_annotation CONFIG_GET /usr/lib/libshmcache.so /etc/libshmcache.conf
#@function CONFIG_GET #@function CONFIG_GET

View File

@ -3,7 +3,7 @@
%define CommitVersion %(echo $COMMIT_VERSION) %define CommitVersion %(echo $COMMIT_VERSION)
Name: libfastcommon Name: libfastcommon
Version: 1.0.88 Version: 1.0.86
Release: 1%{?dist} Release: 1%{?dist}
Summary: c common functions library extracted from my open source projects FastDFS Summary: c common functions library extracted from my open source projects FastDFS
License: LGPL License: LGPL

View File

@ -180,7 +180,6 @@ int fast_buffer_append_binary(FastBuffer *buffer,
int fast_buffer_append_file(FastBuffer *buffer, const char *filename) int fast_buffer_append_file(FastBuffer *buffer, const char *filename)
{ {
const int64_t offset = 0;
struct stat st; struct stat st;
int result; int result;
int64_t file_size; int64_t file_size;
@ -214,7 +213,7 @@ int fast_buffer_append_file(FastBuffer *buffer, const char *filename)
} }
if ((result=getFileContentEx(filename, buffer->data + buffer->length, if ((result=getFileContentEx(filename, buffer->data + buffer->length,
offset, &file_size)) != 0) 0, &file_size)) != 0)
{ {
return result; return result;
} }

View File

@ -22,7 +22,7 @@
#define FC_MAJOR_VERSION 1 #define FC_MAJOR_VERSION 1
#define FC_MINOR_VERSION 0 #define FC_MINOR_VERSION 0
#define FC_PATCH_VERSION 88 #define FC_PATCH_VERSION 86
#define FC_VERSION_INT FC_VERSION_TO_INT(FC_MAJOR_VERSION, \ #define FC_VERSION_INT FC_VERSION_TO_INT(FC_MAJOR_VERSION, \
FC_MINOR_VERSION, FC_PATCH_VERSION) FC_MINOR_VERSION, FC_PATCH_VERSION)

View File

@ -299,11 +299,6 @@ static char *doReplaceVars(IniContext *pContext, const char *param,
{ {
#define VARIABLE_TAG_MIN_LENGTH 4 //%{v} #define VARIABLE_TAG_MIN_LENGTH 4 //%{v}
#define ENV_VAR_NAME_STARTWITH_STR "env::"
#define ENV_VAR_NAME_STARTWITH_LEN (sizeof(ENV_VAR_NAME_STARTWITH_STR) - 1)
#define ENV_VARIABLE_MARK_STR "%{"ENV_VAR_NAME_STARTWITH_STR
SetDirectiveVars *set; SetDirectiveVars *set;
const char *p; const char *p;
const char *e; const char *e;
@ -324,14 +319,12 @@ static char *doReplaceVars(IniContext *pContext, const char *param,
set = iniGetVars(pContext); set = iniGetVars(pContext);
if (set == NULL || set->vars == NULL) { if (set == NULL || set->vars == NULL) {
if (strstr(param, ENV_VARIABLE_MARK_STR) == NULL) {
logWarning("file: "__FILE__", line: %d, " logWarning("file: "__FILE__", line: %d, "
"NO set directives before, set value to %s", "NO set directives before, set value to %s",
__LINE__, param); __LINE__, param);
fc_strlcpy(output, param, FAST_INI_ITEM_VALUE_SIZE); fc_strlcpy(output, param, FAST_INI_ITEM_VALUE_SIZE);
return output; return output;
} }
}
pEnd = param + strlen(param); pEnd = param + strlen(param);
pLoopEnd = pEnd - (VARIABLE_TAG_MIN_LENGTH - 1); pLoopEnd = pEnd - (VARIABLE_TAG_MIN_LENGTH - 1);
@ -361,33 +354,25 @@ static char *doReplaceVars(IniContext *pContext, const char *param,
*(name + name_len) = '\0'; *(name + name_len) = '\0';
fc_trim(name); fc_trim(name);
name_len = strlen(name); name_len = strlen(name);
if (name_len > ENV_VAR_NAME_STARTWITH_LEN && if (name_len > 0) {
memcmp(name, ENV_VAR_NAME_STARTWITH_STR,
ENV_VAR_NAME_STARTWITH_LEN) == 0)
{
value = getenv(name + ENV_VAR_NAME_STARTWITH_LEN);
} else if (name_len > 0) {
if (set != NULL && set->vars != NULL) {
value = (char *)fc_hash_find(set->vars, name, name_len); value = (char *)fc_hash_find(set->vars, name, name_len);
} else { } else {
value = NULL; value = NULL;
} }
} else {
value = NULL;
}
if (value != NULL) { if (value != NULL) {
len = strlen(value); len = strlen(value);
} else { }
else {
logWarning("file: "__FILE__", line: %d, " logWarning("file: "__FILE__", line: %d, "
"variable \"%s\" NOT found, keep the origin", "name: %s NOT found, keep the origin",
__LINE__, name); __LINE__, name);
value = start - 2; value = start - 2;
len = p - value; len = p - value;
} }
pDest += iniCopyBuffer(pDest, FAST_INI_ITEM_VALUE_SIZE - pDest += iniCopyBuffer(pDest, FAST_INI_ITEM_VALUE_SIZE -
(pDest - output), value, len); (pDest - output), value, len);
} else { }
else {
if (pDest - output < FAST_INI_ITEM_VALUE_LEN) { if (pDest - output < FAST_INI_ITEM_VALUE_LEN) {
*pDest++ = *p++; *pDest++ = *p++;
} }
@ -3531,26 +3516,3 @@ int iniGetPercentValueEx(IniFullContext *ini_ctx,
return 0; return 0;
} }
int64_t iniGetTimestampValueEx(const char *szSectionName,
const char *szItemName, IniContext *pContext,
const int64_t nDefaultValue, const int nDefaultUnitTS,
const bool bRetryGlobal)
{
char *pValue;
int64_t nValue;
pValue = iniGetStrValueEx(szSectionName,
szItemName, pContext, bRetryGlobal);
if (pValue == NULL)
{
return nDefaultValue;
}
if (parse_timestamp(pValue, nDefaultUnitTS, &nValue) != 0)
{
return nDefaultValue;
}
return nValue;
}

View File

@ -140,10 +140,6 @@ extern "C" {
#define iniGetPercentValue(ini_ctx, item_name, item_value, default_value) \ #define iniGetPercentValue(ini_ctx, item_name, item_value, default_value) \
iniGetPercentValueEx(ini_ctx, item_name, item_value, default_value, false) iniGetPercentValueEx(ini_ctx, item_name, item_value, default_value, false)
#define iniGetTimestampValue(szSectionName, szItemName, pContext, nDefaultValue) \
iniGetTimestampValueEx(szSectionName, szItemName, \
pContext, nDefaultValue, 1, false)
#define iniGetByteValue(szSectionName, szItemName, pContext, nDefaultValue) \ #define iniGetByteValue(szSectionName, szItemName, pContext, nDefaultValue) \
iniGetByteValueEx(szSectionName, szItemName, \ iniGetByteValueEx(szSectionName, szItemName, \
pContext, nDefaultValue, 1, false) pContext, nDefaultValue, 1, false)
@ -428,22 +424,6 @@ int64_t iniGetByteCorrectValueEx(IniFullContext *pIniContext,
const int nDefaultUnitBytes, const int64_t nMinValue, const int nDefaultUnitBytes, const int64_t nMinValue,
const int64_t nMaxValue, const bool bRetryGlobal); const int64_t nMaxValue, const bool bRetryGlobal);
/** get item timestamp value (64 bits integer)
* parameters:
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
* nDefaultValue: the default value
* nDefaultUnitBytes: the default timestamp unit, such as 1 for second, 86400 for day
* bRetryGlobal: if fetch from global section when the item not exist
* return: int64 value, return nDefaultValue when the item not exist
*/
int64_t iniGetTimestampValueEx(const char *szSectionName,
const char *szItemName, IniContext *pContext,
const int64_t nDefaultValue, const int nDefaultUnitTS,
const bool bRetryGlobal);
/** get item boolean value /** get item boolean value
* parameters: * parameters:
* szSectionName: the section name, NULL or empty string for * szSectionName: the section name, NULL or empty string for

View File

@ -70,20 +70,11 @@ const char *local_host_ip_addrs_to_string(char *buff, const int size)
len = snprintf(buff, size, "local_host_ip_count: %d,", len = snprintf(buff, size, "local_host_ip_count: %d,",
g_local_host_ip_count); g_local_host_ip_count);
if (len >= size)
{
return buff;
}
pEnd = g_local_host_ip_addrs + pEnd = g_local_host_ip_addrs +
IP_ADDRESS_SIZE * g_local_host_ip_count; IP_ADDRESS_SIZE * g_local_host_ip_count;
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE) for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
{ {
len += snprintf(buff + len, size - len, " %s", p); len += snprintf(buff + len, size - len, " %s", p);
if (len >= size)
{
break;
}
} }
return buff; return buff;

View File

@ -24,7 +24,6 @@
int get_pid_from_file(const char *pidFilename, pid_t *pid) int get_pid_from_file(const char *pidFilename, pid_t *pid)
{ {
const int64_t offset = 0;
char buff[32]; char buff[32];
int64_t file_size; int64_t file_size;
int result; int result;
@ -34,7 +33,7 @@ int get_pid_from_file(const char *pidFilename, pid_t *pid)
} }
file_size = sizeof(buff); file_size = sizeof(buff);
if ((result=getFileContentEx(pidFilename, buff, offset, &file_size)) != 0) { if ((result=getFileContentEx(pidFilename, buff, 0, &file_size)) != 0) {
return result; return result;
} }
@ -184,13 +183,12 @@ static const char *process_get_exename(const char* program)
static const char *get_exename_by_pid(const pid_t pid, char *buff, static const char *get_exename_by_pid(const pid_t pid, char *buff,
const int buff_size, int *result) const int buff_size, int *result)
{ {
const int64_t offset = 0;
char cmdfile[MAX_PATH_SIZE]; char cmdfile[MAX_PATH_SIZE];
int64_t cmdsz; int64_t cmdsz;
cmdsz = buff_size; cmdsz = buff_size;
sprintf(cmdfile, "/proc/%d/cmdline", pid); sprintf(cmdfile, "/proc/%d/cmdline", pid);
if ((*result=getFileContentEx(cmdfile, buff, offset, &cmdsz)) != 0) { if ((*result=getFileContentEx(cmdfile, buff, 0, &cmdsz)) != 0) {
fprintf(stderr, "read file %s fail, errno: %d, error info: %s\n", fprintf(stderr, "read file %s fail, errno: %d, error info: %s\n",
cmdfile, *result, strerror(*result)); cmdfile, *result, strerror(*result));
return NULL; return NULL;

View File

@ -2484,88 +2484,6 @@ int parse_bytes(const char *pStr, const int default_unit_bytes, int64_t *bytes)
return result; return result;
} }
int parse_timestamp(const char *str, const int default_unit_secs, int64_t *seconds)
{
char *pReservedEnd;
int result;
pReservedEnd = NULL;
*seconds = strtoll(str, &pReservedEnd, 10);
if (*seconds < 0)
{
logError("file: "__FILE__", line: %d, "
"timestamp: %"PRId64" < 0, input string: %s",
__LINE__, *seconds, str);
return EINVAL;
}
if (pReservedEnd == NULL || *pReservedEnd == '\0')
{
*seconds *= default_unit_secs;
return 0;
}
if (*pReservedEnd == ' ' || *pReservedEnd == '\t')
{
do {
++pReservedEnd;
} while (*pReservedEnd == ' ' || *pReservedEnd == '\t');
if (*pReservedEnd == '\0')
{
*seconds *= default_unit_secs;
return 0;
}
}
if (*(pReservedEnd + 1) != '\0')
{
logError("file: "__FILE__", line: %d, "
"unkown timestamp unit: \"%s\", input string: \"%s\"",
__LINE__, pReservedEnd, str);
return EINVAL;
}
switch (*pReservedEnd)
{
case 's':
result = 0;
break;
case 'm':
*seconds *= 60;
result = 0;
break;
case 'h':
*seconds *= 3600;
result = 0;
break;
case 'd':
*seconds *= 86400;
result = 0;
break;
case 'W':
*seconds *= 7 * 86400;
result = 0;
break;
case 'M':
*seconds *= 30 * 86400;
result = 0;
break;
case 'Y':
*seconds *= 365 * 86400;
result = 0;
break;
default:
result = EINVAL;
logError("file: "__FILE__", line: %d, "
"unkown timestamp unit: \"%s\", input string: \"%s\"",
__LINE__, pReservedEnd, str);
break;
}
return result;
}
int set_rand_seed() int set_rand_seed()
{ {
time_t ts; time_t ts;
@ -3365,7 +3283,6 @@ static int format_bytes_string(const int64_t input_bytes,
} }
p = buff + fc_itoa(n, buff); p = buff + fc_itoa(n, buff);
} }
return p - buff; return p - buff;
} }
@ -4173,13 +4090,12 @@ int fc_check_rename_ex(const char *oldpath, const char *newpath,
int fc_get_first_line(const char *filename, char *buff, int fc_get_first_line(const char *filename, char *buff,
const int buff_size, string_t *line) const int buff_size, string_t *line)
{ {
const int64_t offset = 0;
int result; int result;
int64_t read_bytes; int64_t read_bytes;
char *line_end; char *line_end;
read_bytes = buff_size - 1; read_bytes = buff_size - 1;
if ((result=getFileContentEx(filename, buff, offset, &read_bytes)) != 0) { if ((result=getFileContentEx(filename, buff, 0, &read_bytes)) != 0) {
FC_SET_STRING_EMPTY(*line, buff); FC_SET_STRING_EMPTY(*line, buff);
return result; return result;
} }
@ -4205,7 +4121,6 @@ int fc_get_first_line(const char *filename, char *buff,
int fc_get_first_lines(const char *filename, char *buff, int fc_get_first_lines(const char *filename, char *buff,
const int buff_size, string_t *lines, int *count) const int buff_size, string_t *lines, int *count)
{ {
const int64_t offset = 0;
int result; int result;
int target_count; int target_count;
int64_t read_bytes; int64_t read_bytes;
@ -4219,7 +4134,7 @@ int fc_get_first_lines(const char *filename, char *buff,
} }
read_bytes = buff_size - 1; read_bytes = buff_size - 1;
if ((result=getFileContentEx(filename, buff, offset, &read_bytes)) != 0) { if ((result=getFileContentEx(filename, buff, 0, &read_bytes)) != 0) {
*count = 0; *count = 0;
FC_SET_STRING_EMPTY(*lines, buff); FC_SET_STRING_EMPTY(*lines, buff);
return result; return result;

View File

@ -878,7 +878,7 @@ int getFileContentEx1(int fd, const char *filename, char *buff,
* size: specify the size to fetch and return the fetched size * size: specify the size to fetch and return the fetched size
* return: error no , 0 success, != 0 fail * return: error no , 0 success, != 0 fail
*/ */
int getFileContentEx(const char *filename, char *buff, int getFileContentEx(const char *filename, char *buff, \
int64_t offset, int64_t *size); int64_t offset, int64_t *size);
/** get file size /** get file size
@ -979,22 +979,12 @@ int fc_compare_int64_ptr(const int64_t *n1, const int64_t *n2);
/** parse bytes /** parse bytes
* parameters: * parameters:
* pStr: the string to parse * pStr: the string to parse
* default_unit_bytes: default unit if not specified, the unit like MB etc. * default_unit_bytes: default unit if not specified the unit like MB etc.
* bytes: store the parsed bytes * bytes: store the parsed bytes
* return: error no , 0 success, != 0 fail * return: error no , 0 success, != 0 fail
*/ */
int parse_bytes(const char *pStr, const int default_unit_bytes, int64_t *bytes); int parse_bytes(const char *pStr, const int default_unit_bytes, int64_t *bytes);
/** parse timestamp
* parameters:
* str: the string to parse
* default_unit_secs: default unit if not specified
* seconds: store the parsed seconds
* return: error no , 0 success, != 0 fail
*/
int parse_timestamp(const char *str, const int default_unit_secs, int64_t *seconds);
/** set rand seed /** set rand seed
* return: error no , 0 success, != 0 fail * return: error no , 0 success, != 0 fail
*/ */

View File

@ -118,13 +118,12 @@ int get_sys_cpu_count()
int get_boot_time(struct timeval *boot_time) int get_boot_time(struct timeval *boot_time)
{ {
#ifdef OS_LINUX #ifdef OS_LINUX
const int64_t offset = 0;
char buff[256]; char buff[256];
int64_t bytes; int64_t bytes;
struct sysinfo si; struct sysinfo si;
bytes = sizeof(buff); bytes = sizeof(buff);
if (getFileContentEx("/proc/uptime", buff, offset, &bytes) == 0) if (getFileContentEx("/proc/uptime", buff, 0, &bytes) == 0)
{ {
double uptime; double uptime;
double btime; double btime;
@ -622,7 +621,6 @@ static void parse_proc_stat(char *buff, const int len,
int get_processes(struct fast_process_info **processes, int *count) int get_processes(struct fast_process_info **processes, int *count)
{ {
const int64_t offset = 0;
const char *dirname = "/proc"; const char *dirname = "/proc";
char filename[128]; char filename[128];
char buff[4096]; char buff[4096];
@ -681,7 +679,7 @@ int get_processes(struct fast_process_info **processes, int *count)
sprintf(filename, "%s/%s/stat", dirname, ent->d_name); sprintf(filename, "%s/%s/stat", dirname, ent->d_name);
bytes = sizeof(buff); bytes = sizeof(buff);
if (getFileContentEx(filename, buff, offset, &bytes) != 0) if (getFileContentEx(filename, buff, 0, &bytes) != 0)
{ {
continue; continue;
} }