//以目录枚举为例子,说明enumerator,从源码剥离可运行
#include <stdio.h>
#include <stdbool.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <sys/time.h>
#include <stdarg.h>
/**
* This macro allows counting the number of arguments passed to a macro.
* Combined with the VA_ARGS_DISPATCH() macro this can be used to implement
* macro overloading based on the number of arguments.
* 0 to 10 arguments are currently supported.
*/
#define VA_ARGS_NUM(...) _VA_ARGS_NUM(0,##__VA_ARGS__,10,9,8,7,6,5,4,3,2,1,0)
#define _VA_ARGS_NUM(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,NUM,...) NUM
/**
* This macro can be used to dispatch a macro call based on the number of given
* arguments, for instance:
*
* @code
* #define MY_MACRO(...) VA_ARGS_DISPATCH(MY_MACRO, __VA_ARGS__)(__VA_ARGS__)
* #define MY_MACRO1(arg) one_arg(arg)
* #define MY_MACRO2(arg1,arg2) two_args(arg1,arg2)
* @endcode
*
* MY_MACRO() can now be called with either one or two arguments, which will
* resolve to one_arg(arg) or two_args(arg1,arg2), respectively.
*/
#define VA_ARGS_DISPATCH(func, ...) _VA_ARGS_DISPATCH(func, VA_ARGS_NUM(__VA_ARGS__))
#define _VA_ARGS_DISPATCH(func, num) __VA_ARGS_DISPATCH(func, num)
#define __VA_ARGS_DISPATCH(func, num) func ## num
/**
* Assign variadic arguments to the given variables.
*
* @note The order and types of the variables are significant and must match the
* variadic arguments passed to the function that calls this macro exactly.
*
* @param last the last argument before ... in the function that calls this
* @param ... variable names
*/
#define VA_ARGS_GET(last, ...) ({ \
va_list _va_args_get_ap; \
va_start(_va_args_get_ap, last); \
_VA_ARGS_GET_ASGN(__VA_ARGS__) \
va_end(_va_args_get_ap); \
})
/**
* Assign variadic arguments from a va_list to the given variables.
*
* @note The order and types of the variables are significant and must match the
* variadic arguments passed to the function that calls this macro exactly.
*
* @param list the va_list variable in the function that calls this
* @param ... variable names
*/
#define VA_ARGS_VGET(list, ...) ({ \
va_list _va_args_get_ap; \
va_copy(_va_args_get_ap, list); \
_VA_ARGS_GET_ASGN(__VA_ARGS__) \
va_end(_va_args_get_ap); \
})
#define _VA_ARGS_GET_ASGN(...) VA_ARGS_DISPATCH(_VA_ARGS_GET_ASGN, __VA_ARGS__)(__VA_ARGS__)
#define _VA_ARGS_GET_ASGN1(v1) __VA_ARGS_GET_ASGN(v1)
#define _VA_ARGS_GET_ASGN2(v1,v2) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2)
#define _VA_ARGS_GET_ASGN3(v1,v2,v3) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
__VA_ARGS_GET_ASGN(v3)
#define _VA_ARGS_GET_ASGN4(v1,v2,v3,v4) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
__VA_ARGS_GET_ASGN(v3) __VA_ARGS_GET_ASGN(v4)
#define _VA_ARGS_GET_ASGN5(v1,v2,v3,v4,v5) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
__VA_ARGS_GET_ASGN(v3) __VA_ARGS_GET_ASGN(v4) __VA_ARGS_GET_ASGN(v5)
#define __VA_ARGS_GET_ASGN(v) v = va_arg(_va_args_get_ap, typeof(v));
#ifndef FALSE
# define FALSE false
#endif /* FALSE */
#ifndef TRUE
# define TRUE true
#endif /* TRUE */
typedef struct enumerator_t enumerator_t;
struct enumerator_t {
/**
* 枚举集合。
*
* enumerate() 方法接受可变数量的指针参数(枚举到的值被写入这些参数)
*
*通常只需分配调用枚举器的 venumerate() 方法的通用 enumerator_enumerate_default() 函数就足够了。 ...
*
* @param ... 枚举项的变量列表,取决于实现
* @return TRUE if pointers returned
*/
bool (*enumerate)(enumerator_t *this, ...);
/**
* 枚举集合。
*
* venumerate() 方法采用一个变量参数列表,其中包含将枚举值写入的指针。
*
* @param args 枚举项的变量列表,取决于实现
* @return TRUE if pointers returned
*/
bool (*venumerate)(enumerator_t *this, va_list args);
/**
* Destroy an enumerator_t instance.
*/
void (*destroy)(enumerator_t *this);
};
/**
* Enumerator implementation for directory enumerator
*/
typedef struct {
/** implements enumerator_t */
enumerator_t public;
/** directory handle */
DIR *dir;
/** absolute path of current file */
char full[PATH_MAX];
/** where directory part of full ends and relative file gets written */
//完整路径中的目录部分结束以及相对文件将被写入的位置
char *full_end;
} dir_enum_t;
/**
* Helper function that compares two strings for equality
*/
static inline bool streq(const char *x, const char *y)
{
return (x == y) || (x && y && strcmp(x, y) == 0);
}
bool enumerate_dir_enum(dir_enum_t *this, va_list args){
//读取目录中的条目,依靠此函数特性实现枚举
struct dirent *entry = readdir(this->dir);
struct stat *st = NULL;
size_t remaining;
char **relative = NULL, **absolute = NULL;;
int len;
//对应enumerate输入的变参... &relative, &file, NULL 下面写入这些值相当于写入那些值
VA_ARGS_VGET(args, relative, absolute, st);
if (!entry)
{
return FALSE;
}
if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
{
return this->public.enumerate(&this->public, relative, absolute, st);
}
if (relative)
{
//条目名称
*relative = entry->d_name;
}
if (absolute || st)
{
//full是路径,relative
remaining = sizeof(this->full) - (this->full_end - this->full);
len = snprintf(this->full_end, remaining, "%s", entry->d_name);
if (len < 0 || len >= remaining)
{
return FALSE;
}
if (absolute)
{
*absolute = this->full;
}
if (st && stat(this->full, st))
{
/* try lstat() e.g. if a symlink is not valid anymore */
if ((errno != ENOENT && errno != ENOTDIR) || lstat(this->full, st))
{
return FALSE;
}
}
}
return TRUE;
}
# define DIRECTORY_SEPARATOR "/"
static inline bool path_is_separator(char c)
{
return c == DIRECTORY_SEPARATOR[0];
}
/**
* Object allocation/initialization macro, using designated initializer.
*/
#define INIT(this, ...) ({ (this) = malloc(sizeof(*(this))); \
*(this) = (typeof(*(this))){ __VA_ARGS__ }; (this); })
bool enumerator_enumerate_default(enumerator_t *enumerator, ...)
{
va_list args;
bool result;
if (!enumerator->venumerate)
{
return FALSE;
}
//va_start用于获取函数参数列表...中可变参数的首指针
//输出参数args保存函数参数列表中可变参数的首指针(即,可变参数列表)
//输入参数enumerator为函数参数列表中最后一个固定参数(...之前)
va_start(args, enumerator);
result = enumerator->venumerate(enumerator, args);
va_end(args);
return result;
}
void destroy_dir_enum(dir_enum_t *this){
closedir(this->dir);
free(this);
}
enumerator_t* enumerator_create_directory(const char *path)
{
dir_enum_t *this;
int len;
//实例化
INIT(this,
.public = {
.enumerate = enumerator_enumerate_default,
.venumerate = enumerate_dir_enum,
.destroy = destroy_dir_enum,
},
);
if (*path == '\0')
{
path = "./";
}
len = snprintf(this->full, sizeof(this->full)-1, "%s", path);
if (len < 0 || len >= sizeof(this->full)-1)
{
free(this);
return NULL;
}
/* append a '/' if not already done */
if (!path_is_separator(this->full[len-1]))
{
this->full[len++] = DIRECTORY_SEPARATOR[0];
this->full[len] = '\0';
}
this->full_end = &this->full[len];
//打开目录
this->dir = opendir(path);
if (!this->dir)
{
free(this);
return NULL;
}
return &this->public;
}
int main()
{
char *file;
char *relative;
char *st;
char *path = "/root/open/strongswan-6.0.0";
enumerator_t *enumerator;
enumerator = enumerator_create_directory(path);
if (enumerator){
while (enumerator->enumerate(enumerator, &relative, &file, NULL))
{
printf("file: %s | relative: %s | size:%s\n", file, relative, NULL);
}
enumerator->destroy(enumerator);
}
return 0;
}