/* * Copyright (c) 2020 YuQing <384681@qq.com> * * This program is free software: you can use, redistribute, and/or modify * it under the terms of the Lesser GNU General Public License, version 3 * or later ("LGPL"), as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the Lesser GNU General Public License * along with this program. If not, see . */ #ifndef SHARED_FUNC_H #define SHARED_FUNC_H #include #include #include #include #include #include #include #include "common_define.h" #include "ini_file_reader.h" #ifdef __cplusplus extern "C" { #endif /** lowercase the string * parameters: * src: input string, will be changed * return: lowercased string */ char *toLowercase(char *src); /** uppercase the string * parameters: * src: input string, will be changed * return: uppercased string */ char *toUppercase(char *src); /** date format to string * parameters: * nTime: unix timestamp * szDateFormat: date format, more detail man strftime * buff: store the formated result, can be NULL * buff_size: buffer size, max bytes can contain * return: formated date string */ char *formatDatetime(const time_t nTime, \ const char *szDateFormat, \ char *buff, const int buff_size); /** get character count, only support GB charset * parameters: * s: the string * return: character count */ int getCharLen(const char *s); /** replace \r and \n to space * parameters: * s: the string * return: replaced string */ char *replaceCRLF2Space(char *s); /** get the filename absolute path * parameters: * fileame: the filename * szAbsPath: store the absolute path * pathSize: max bytes to contain * return: absolute path, NULL for fail */ char *getAbsolutePath(const char *fileame, char *szAbsPath, \ const int pathSize); /** get the executable file absolute filename * parameters: * exeFilename: the executable filename * szAbsFilename: store the absolute filename * maxSize: max bytes to contain * return: absolute filename, NULL for fail */ char *getExeAbsoluteFilename(const char *exeFilename, char *szAbsFilename, \ const int maxSize); #ifndef WIN32 /** get running process count by program name such as fdfs_trackerd * parameters: * progName: the program name * bAllOwners: false for only get my proccess count * return: proccess count, >= 0 success, < 0 fail */ int getProccessCount(const char *progName, const bool bAllOwners); /** get running process ids by program name such as fdfs_trackerd * parameters: * progName: the program name * bAllOwners: false for only get my proccess count * pids: store the pids * arrSize: max pids * return: proccess count, >= 0 success, < 0 fail */ int getUserProcIds(const char *progName, const bool bAllOwners, \ int pids[], const int arrSize); /** execute program, get it's output * parameters: * command: the program * output: store ouput result * buff_size: output max size (bytes) * return: error no, 0 success, != 0 fail */ int getExecResult(const char *command, char *output, const int buff_size); #endif /** daemon init * parameters: * bCloseFiles: if close the stdin, stdout and stderr * return: none */ void daemon_init(bool bCloseFiles); /** convert buffer content to hex string such as 0B82A1 * parameters: * s: the buffer * len: the buffer length * szHexBuff: store the hex string (must have enough space) * return: hex string (szHexBuff) */ char *bin2hex(const char *s, const int len, char *szHexBuff); /** parse hex string to binary content * parameters: * s: the hex string such as 8B04CD * szBinBuff: store the converted binary content(must have enough space) * nDestLen: store the converted content length * return: converted binary content (szBinBuff) */ char *hex2bin(const char *s, char *szBinBuff, int *nDestLen); /** print binary buffer as hex string * parameters: * s: the buffer * len: the buffer length * return: none */ void printBuffHex(const char *s, const int len); /** 16 bits int convert to buffer (big-endian) * parameters: * n: 16 bits int value * buff: the buffer, at least 2 bytes space, no tail \0 * return: none */ void short2buff(const short n, char *buff); /** buffer convert to 16 bits int * parameters: * buff: big-endian 2 bytes buffer * return: 16 bits int value */ short buff2short(const char *buff); /** 32 bits int convert to buffer (big-endian) * parameters: * n: 32 bits int value * buff: the buffer, at least 4 bytes space, no tail \0 * return: none */ void int2buff(const int n, char *buff); /** buffer convert to 32 bits int * parameters: * buff: big-endian 4 bytes buffer * return: 32 bits int value */ int buff2int(const char *buff); /** long (64 bits) convert to buffer (big-endian) * parameters: * n: 64 bits int value * buff: the buffer, at least 8 bytes space, no tail \0 * return: none */ void long2buff(int64_t n, char *buff); /** buffer convert to 64 bits int * parameters: * buff: big-endian 8 bytes buffer * return: 64 bits int value */ int64_t buff2long(const char *buff); /** 32 bits float convert to buffer (big-endian) * parameters: * n: 32 bits float value * buff: the buffer, at least 4 bytes space, no tail \0 * return: none */ static inline void float2buff(float f, char *buff) { int *p; p = (int *)&f; int2buff(*p, buff); } /** buffer convert to 32 bits float * parameters: * buff: big-endian 8 bytes buffer * return: 32 bits float value */ static inline float buff2float(const char *buff) { int n; float *p; n = buff2int(buff); p = (float *)&n; return *p; } /** double (64 bits) convert to buffer (big-endian) * parameters: * n: 64 bits double value * buff: the buffer, at least 8 bytes space, no tail \0 * return: none */ static inline void double2buff(double d, char *buff) { int64_t *p; p = (int64_t *)&d; long2buff(*p, buff); } /** buffer convert to 64 bits double * parameters: * buff: big-endian 8 bytes buffer * return: 64 bits double value */ static inline double buff2double(const char *buff) { int64_t n; double *p; n = buff2long(buff); p = (double *)&n; return *p; } /** trim leading spaces ( \t\r\n) * parameters: * pStr: the string to trim * return: trimed string porinter as pStr */ char *trim_left(char *pStr); /** trim tail spaces ( \t\r\n) * parameters: * pStr: the string to trim * return: trimed string porinter as pStr */ char *trim_right(char *pStr); /** trim leading and tail spaces ( \t\r\n) * parameters: * pStr: the string to trim * return: trimed string porinter as pStr */ char *trim(char *pStr); /** trim leading and tail spaces ( \t\r\n) * parameters: * pStr: the string to trim * return: trimed string porinter as pStr */ static inline char *fc_trim(char *pStr) { trim_right(pStr); trim_left(pStr); return pStr; } /** trim leading spaces ( \t\r\n) * parameters: * s: the string to trim * return: none */ void string_ltrim(string_t *s); /** trim tail spaces ( \t\r\n) * parameters: * s: the string to trim * return: none */ void string_rtrim(string_t *s); #define FC_STRING_TRIM(s) \ do { \ string_ltrim(s); \ string_rtrim(s); \ } while (0) static inline void string_trim(string_t *s) { FC_STRING_TRIM(s); } /** copy string to BufferInfo * parameters: * pBuff: the dest buffer * str: source string * return: error no, 0 success, != 0 fail */ int buffer_strcpy(BufferInfo *pBuff, const char *str); /** copy binary buffer to BufferInfo * parameters: * pBuff: the dest buffer * buff: source buffer * len: source buffer length * return: error no, 0 success, != 0 fail */ int buffer_memcpy(BufferInfo *pBuff, const char *buff, const int len); /** url encode * parameters: * src: the source string to encode * src_len: source string length * dest: store dest string * dest_len: store the dest string length * return: error no, 0 success, != 0 fail */ char *urlencode(const char *src, const int src_len, char *dest, int *dest_len); /** url decode, terminated with \0 * parameters: * src: the source string to decode * src_len: source string length * dest: store dest string * dest_len: store the dest string length * return: error no, 0 success, != 0 fail */ char *urldecode(const char *src, const int src_len, char *dest, int *dest_len); /** url decode, no terminate with \0 * parameters: * src: the source string to decode * src_len: source string length * dest: store dest string * dest_len: store the dest string length * return: error no, 0 success, != 0 fail */ char *urldecode_ex(const char *src, const int src_len, char *dest, int *dest_len); /** get char occurs count * parameters: * src: the source string * seperator: find this char occurs times * return: char occurs count */ int getOccurCount(const char *src, const char seperator); /** get the file line count * parameters: * filename: the filename * until_offset: util the file offset, -1 for file end * line_count: store the line count * return: error no, 0 success, != 0 fail */ int fc_get_file_line_count_ex(const char *filename, const int64_t until_offset, int64_t *line_count); static inline int fc_get_file_line_count(const char *filename, int64_t *line_count) { const int64_t until_offset = -1; return fc_get_file_line_count_ex(filename, until_offset, line_count); } /** split string * parameters: * src: the source string, will be modified by this function * seperator: seperator char * nMaxCols: max columns (max split count) * nColCount: store the columns (array elements) count * return: string array, should call freeSplit to free, return NULL when fail */ char **split(char *src, const char seperator, const int nMaxCols, \ int *nColCount); /** free split results * parameters: * p: return by function split * return: none */ void freeSplit(char **p); /** split string * parameters: * src: the source string, will be modified by this function * seperator: seperator char * pCols: store split strings * nMaxCols: max columns (max split count) * return: string array / column count */ int splitEx(char *src, const char seperator, char **pCols, const int nMaxCols); /** split string * parameters: * src: the source string * seperator: seperator char * dest: store split strings * max_count: max split count * ignore_empty: if ignore empty string * return: string array count */ int split_string_ex(const string_t *src, const char seperator, string_t *dest, const int max_count, const bool ignore_empty); /** split string by delimiter characters * parameters: * src: the source string, will be modified by this function * delim: the delimiter characters * pCols: store split strings * nMaxCols: max columns (max split count) * return: string array / column count */ int fc_split_string(char *src, const char *delim, char **pCols, const int nMaxCols); /** if the input string contains all delimiter characters * parameters: * str: the input string * delim: the delimiter characters * return: true for contains all delimiter characters, otherwise false */ bool fc_match_delim(const char *str, const char *delim); /** split string * parameters: * src: the source string, will be modified by this function * seperator: seperator char * pCols: store split strings * nMaxCols: max columns (max split count) * return: string array / column count */ int my_strtok(char *src, const char *delim, char **pCols, const int nMaxCols); /** check file exist * parameters: * filename: the filename * return: true if file exists, otherwise false */ bool fileExists(const char *filename); /** check if a directory * parameters: * filename: the filename * return: true for directory */ bool isDir(const char *filename); /** check if a regular file * parameters: * filename: the filename * return: true for regular file */ bool isFile(const char *filename); /** check if filename securty, /../ ocur in filename not allowed * parameters: * filename: the filename * len: filename length * return: true for regular file */ bool is_filename_secure(const char *filename, const int len); /** load log_level from config context * parameters: * pIniContext: the config context * return: none */ void load_log_level(IniContext *pIniContext); /** load log_level from config file * parameters: * conf_filename: the config filename * return: none */ int load_log_level_ex(const char *conf_filename); /** set global log level * parameters: * pLogLevel: log level string value * return: none */ void set_log_level(char *pLogLevel); /** load allow hosts from config context * parameters: * pIniContext: the config context * allow_ip_addrs: store allow ip addresses * allow_ip_count: store allow ip address count * return: error no , 0 success, != 0 fail */ int load_allow_hosts(IniContext *pIniContext, \ in_addr_t **allow_ip_addrs, int *allow_ip_count); /** get time item from config context * parameters: * ini_ctx: the full ini context * item_name: item name in config file, time format as hour:minute, such as 15:25 * pTimeInfo: store time info * default_hour: default hour value * default_minute: default minute value * bRetryGlobal: if fetch from global section when the item not exist * return: error no , 0 success, != 0 fail */ int get_time_item_from_conf_ex(IniFullContext *ini_ctx, const char *item_name, TimeInfo *pTimeInfo, const byte default_hour, const byte default_minute, const bool bRetryGlobal); /** get time item from config context * parameters: * pIniContext: the config context * item_name: item name in config file, time format as hour:minute, such as 15:25 * pTimeInfo: store time info * default_hour: default hour value * default_minute: default minute value * return: error no , 0 success, != 0 fail */ int get_time_item_from_conf(IniContext *pIniContext, \ const char *item_name, TimeInfo *pTimeInfo, \ const byte default_hour, const byte default_minute); /** get time item from string * parameters: * pValue: the time string, format as hour:minute, such as 15:25 * item_name: item name in config file * pTimeInfo: store time info * default_hour: default hour value * default_minute: default minute value * return: error no , 0 success, != 0 fail */ int get_time_item_from_str(const char *pValue, const char *item_name, TimeInfo *pTimeInfo, const byte default_hour, const byte default_minute); /** trim path tail char / * parameters: * filePath: the file path to chop * return: none */ void chopPath(char *filePath); /** get file content * parameters: * filename: the filename * buff: return the buff, must be freed * file_size: store the file size * return: error no , 0 success, != 0 fail */ int getFileContent(const char *filename, char **buff, int64_t *file_size); /** get file content * parameters: * filename: the filename * buff: the buff to store file content * offset: the start offset * size: specify the size to fetch and return the fetched size * return: error no , 0 success, != 0 fail */ int getFileContentEx(const char *filename, char *buff, \ int64_t offset, int64_t *size); /** get file size * parameters: * filename: the filename * file_size: store the file size * return: error no , 0 success, != 0 fail */ int getFileSize(const char *filename, int64_t *file_size); /** write to file * parameters: * filename: the filename to write * buff: the buffer to write * file_size: the file size * return: error no , 0 success, != 0 fail */ int writeToFile(const char *filename, const char *buff, const int file_size); /** safe write to file, first write to tmp file, then rename to true filename * parameters: * filename: the filename to write * buff: the buffer to write * file_size: the file size * return: error no , 0 success, != 0 fail */ int safeWriteToFile(const char *filename, const char *buff, \ const int file_size); /** get a line from file * parameters: * fd: the fd to read * buff: the buffer to store the line * size: the buffer max size * once_bytes: the bytes per read * return: error no , 0 success, != 0 fail */ int fd_gets(int fd, char *buff, const int size, int once_bytes); /** set unix rlimit * parameters: * resource: resource id, please see sys/resource.h * value: the value to set * return: error no , 0 success, != 0 fail */ int set_rlimit(int resource, const rlim_t value); /** fcntl add flags such as O_NONBLOCK or FD_CLOEXEC * parameters: * fd: the fd to set * get_cmd: the get command * set_cmd: the set command * adding_flags: the flags to add * return: error no , 0 success, != 0 fail */ int fcntl_add_flags(int fd, int get_cmd, int set_cmd, int adding_flags); /** set fd flags such as O_NONBLOCK * parameters: * fd: the fd to set * adding_flags: the flags to add * return: error no , 0 success, != 0 fail */ int fd_add_flags(int fd, int adding_flags); /** set non block mode * parameters: * fd: the fd to set * return: error no , 0 success, != 0 fail */ #define set_nonblock(fd) fd_add_flags(fd, O_NONBLOCK) /** set fd FD_CLOEXEC flags * parameters: * fd: the fd to set * return: error no , 0 success, != 0 fail */ int fd_set_cloexec(int fd); /** set run by group and user * parameters: * group_name: the group name, can be NULL or empty * username: the username, can be NULL or empty * return: error no , 0 success, != 0 fail */ int set_run_by(const char *group_name, const char *username); /** compare ip address, type is (in_addr_t *) * parameters: * p1: the first ip address * p2: the second ip address * return: > 0 when p1 > p2, 0 when p1 == p2, < 0 when p1 < p2 */ int cmp_by_ip_addr_t(const void *p1, const void *p2); /** parse bytes * parameters: * pStr: the string to parse * default_unit_bytes: default unit if not specified the unit like MB etc. * bytes: store the parsed bytes * return: error no , 0 success, != 0 fail */ int parse_bytes(const char *pStr, const int default_unit_bytes, int64_t *bytes); /** set rand seed * return: error no , 0 success, != 0 fail */ int set_rand_seed(); /** set timer wrapper * parameters: * first_remain_seconds: remain time for first time, in seconds * interval: the interval * sighandler: handler function * return: error no , 0 success, != 0 fail */ int set_timer(const int first_remain_seconds, const int interval, \ void (*sighandler)(int)); /** set file access and modified times * parameters: * filename: the file to modify times * new_time: the time to set * return: error no , 0 success, != 0 fail */ int set_file_utimes(const char *filename, const time_t new_time); /** ignore singal pipe (SIGPIPE) * return: error no , 0 success, != 0 fail */ int ignore_signal_pipe(); double get_line_distance_km(const double lat1, const double lon1, const double lat2, const double lon2); /** is private ip address for IPv4 * return: true for private ip, otherwise false */ bool is_private_ip(const char* ip); /** get current time in ns * return: current time */ int64_t get_current_time_ns(); /** get current time in us * return: current time */ int64_t get_current_time_us(); #define get_current_time_ms() (get_current_time_us() / 1000) /** is the number power 2 * parameters: * n: the number to test * return: true for power 2, otherwise false */ bool is_power2(const int64_t n); /** set file read lock * parameters: * fd: the file descriptor to lock * return: error no, 0 for success, != 0 fail */ int file_read_lock(int fd); /** set file write lock * parameters: * fd: the file descriptor to lock * return: error no, 0 for success, != 0 fail */ int file_write_lock(int fd); /** file unlock * parameters: * fd: the file descriptor to unlock * return: error no, 0 for success, != 0 fail */ int file_unlock(int fd); /** try file read lock * parameters: * fd: the file descriptor to lock * return: error no, 0 for success, != 0 fail */ int file_try_read_lock(int fd); /** try file write lock * parameters: * fd: the file descriptor to lock * return: error no, 0 for success, != 0 fail */ int file_try_write_lock(int fd); /** try file unlock * parameters: * fd: the file descriptor to unlock * return: error no, 0 for success, != 0 fail */ int file_try_unlock(int fd); /** is a leading spaces line * parameters: * content: the whole string content * current: the current line * return: error no, 0 for success, != 0 fail */ bool isLeadingSpacesLine(const char *content, const char *current); /** is a trailing spaces line * parameters: * tail: the current line tail * end: the string end ptr * return: error no, 0 for success, != 0 fail */ bool isTrailingSpacesLine(const char *tail, const char *end); /** write to file * parameters: * fd: the fd to write * buf: the buffer * nbyte: the buffer length * return: written bytes for success, -1 when fail */ ssize_t fc_safe_write(int fd, const char *buf, const size_t nbyte); /** lock and write to file * parameters: * fd: the fd to write * buf: the buffer * nbyte: the buffer length * return: written bytes for success, -1 when fail */ ssize_t fc_lock_write(int fd, const char *buf, const size_t nbyte); /** read from file * parameters: * fd: the fd to read * buf: the buffer * count: expect read bytes * return: read bytes for success, -1 when fail */ ssize_t fc_safe_read(int fd, char *buf, const size_t count); /** ftok with hash code * parameters: * path: the file path * proj_id: the project id * return: read bytes for success, -1 when fail */ key_t fc_ftok(const char *path, const int proj_id); /** convert int to string * parameters: * n: the 32 bits integer * buff: output buffer * thousands_separator: if add thousands separator * return: string buffer */ const char *int2str(const int n, char *buff, const bool thousands_separator); static inline const char *int_to_comma_str(const int n, char *buff) { return int2str(n, buff, true); } /** convert long to string * parameters: * n: the 64 bits integer * buff: output buffer * thousands_separator: if add thousands separator * return: string buffer */ const char *long2str(const int64_t n, char *buff, const bool thousands_separator); static inline const char *long_to_comma_str(const int64_t n, char *buff) { return long2str(n, buff, true); } /** if the string starts with the needle string * parameters: * str: the string to detect * needle: the needle string * return: true for starts with the needle string, otherwise false */ bool starts_with(const char *str, const char *needle); /** if the string ends with the needle string * parameters: * str: the string to detect * needle: the needle string * return: true for ends with the needle string, otherwise false */ bool ends_with(const char *str, const char *needle); /** strdup extension * parameters: * str: the string to duplicate * len: the length of string * return: the duplicated string, NULL for fail */ char *fc_strdup1(const char *str, const int len); /** memmem * parameters: * str: the string to match * needle: the needle string * return: the matched string, NULL for fail */ const char *fc_memmem(const string_t *str, const string_t *needle); /** memmem * parameters: * str: the string to match * needle: the needle string * return: the matched string, NULL for fail */ const char *fc_memrchr(const char *str, const int ch, const int len); /** format HTTP Date as: Sat, 11 Mar 2017 21:49:51 GMT * parameters: * t: the time to format * buffer: the buffer * return: formatted GMT date string */ char *format_http_date(time_t t, BufferInfo *buffer); /** return full path for the filename (the second parameter) * parameters: * from: the input full path filename to get base path * filename: the filename to resolve path * full_filename: store the resolved full path filename * size: the max size of full_filename * return: the resolved full path filename */ char *resolve_path(const char *from, const char *filename, char *full_filename, const int size); /** get gzip command full filename * return: the gzip command full filename */ const char *get_gzip_command_filename(); /** delete file * parameters: * filename: the filename to delete * caption: the caption of this filename * return: error no, 0 success, != 0 fail */ int fc_delete_file_ex(const char *filename, const char *caption); static inline int fc_delete_file(const char *filename) { return fc_delete_file_ex(filename, ""); } /** if prime number * parameters: * n: the number to detect * return: true for prime number, otherwise false */ bool fc_is_prime(const int64_t n); /** find the largest prime number not greater than n * parameters: * n: the number to detect * return: the largest prime number near n */ int64_t fc_floor_prime(const int64_t n); /** find the smallest prime number not less than n * parameters: * n: the number to detect * return: the smallest prime number near n */ int64_t fc_ceil_prime(const int64_t n); /** init buffer * parameters: * buffer: the buffer to init * buffer_size: the buffer size * return: error no, 0 success, != 0 fail */ int fc_init_buffer(BufferInfo *buffer, const int buffer_size); /** free buffer * parameters: * buffer: the buffer to free * return: none */ void fc_free_buffer(BufferInfo *buffer); static inline int fc_get_umask() { mode_t mode; mode = umask(0); //fetch umask(mode); //restore return mode; } int fc_check_mkdir_ex(const char *path, const mode_t mode, bool *create); static inline int fc_check_mkdir(const char *path, const mode_t mode) { bool create; return fc_check_mkdir_ex(path, mode, &create); } int fc_get_first_line(const char *filename, char *buff, const int buff_size, string_t *line); int fc_get_last_line(const char *filename, char *buff, const int buff_size, int64_t *file_size, string_t *line); int fc_get_last_lines(const char *filename, char *buff, const int buff_size, string_t *lines, int *count); /** if the input path contains the needle path * parameters: * path: the absolute path to match * needle: the needle path, must be absolute * result: store the errno * return: true for contain, otherwise false */ bool fc_path_contains(const string_t *path, const string_t *needle, int *result); /** sleep in milliseconds * parameters: * milliseconds: milliseconds to sleep * return: 0 for success, != 0 for fail */ static inline int fc_sleep_ms(const int milliseconds) { struct timespec ts; ts.tv_sec = milliseconds / 1000; ts.tv_nsec = (milliseconds % 1000) * (1000 * 1000); if (nanosleep(&ts, NULL) == 0) { return 0; } else { return errno != 0 ? errno : EINVAL; } } #ifdef __cplusplus } #endif #endif