Author: wencoo
Blog:https://wencoo.blog.csdn.net/
Date: 25/12/2023
Email: jianwen056@aliyun.com
Wechat:wencoo824
QQ:1419440391
Details:
宏定义实现如下:
#define NEXT(str,token) \
token = next_token(&str); \
if (!token) break;
解析字符串str,获取逗号前的项给token,同时str的指针进行移动,移动到下一个项起始地址。
实现:
static char *next_token(char **str)
{
char *p;
char *start;
skip_spaces(str);
if (**str == '\0') {
return 0;
}
advance_token_pos((const char**)str,
(const char**)&start,
(const char**)&p);
*p = '\0';
return start;
}
实现的功能就是在字符串str中,解析,获取,(逗号)为间隔的一个项start,进行返回,同时修改了str指针的位置。
实现:
// skip spaces in str beforehand, or trim leading spaces afterwards
// 事先跳过STR中的空格,或在之后修剪前导空格
static inline void advance_token_pos(const char **const str,
const char **const start,
const char **const end)
{
*start = *str;
*end = *start;
while (**end != '\0' && **end != ',') ++*end;
*str = *end + (**end == ',');
rskip_spaces((char**)end, (char*)*start);
}
获取字符串中,(逗号)之前的内容
实现:
static inline void rskip_spaces(char **str, char *limit)
{
char *p = *str;
while ((p > limit) && ((p[-1] == ' ') || (p[-1] == '\t')))
--p;
*str = p;
}
反向对字符串进行检查,获取空格之后的字符串。 将获取的字符串地址传给str。
/* One section started with PARSE_START and PARSE_END parses a single token
* (contained in the variable named token) for the header indicated by the
* variable tname. It does so by chaining a number of else-if statements, each
* of which checks if the tname variable indicates that this header should be
* parsed. The first parameter of the macro gives the name of the header.
*
* The string that is passed is in str. str is advanced to the next token if
* a header could be parsed. The parsed results are stored in the variable
* target, which has the type ASS_Style* or ASS_Event*.
*/
#define PARSE_START if (0) {
#define PARSE_END }
这两个宏定义定义了一个完整的if结构,看上去是这样的,给人的第一感觉就是这个样子,
if (0){
}
但是实际上,可能并不是这样的结构,中间使用了更多的宏定义,其中可能包含了很多隐藏结构,需要仔细甄别,例如
if (0){
STARREDSTRVAL(Name)
// #define STARREDSTRVAL(name) \
// } else if (ass_strcasecmp(tname, #name) == 0) { \
// while (*token == '*') ++token; \
// char *new_str = strdup(token); \
// if (new_str) { \
// free(target->name); \
// target->name = new_str; \
// }
}
可以看到if(0)没有执行,早已跳到了else逻辑,这就是PARSE_START下面逻辑可以执行的原因。
实现:
#define STARREDSTRVAL(name) \
} else if (ass_strcasecmp(tname, #name) == 0) { \
while (*token == '*') ++token; \
char *new_str = strdup(token); \
if (new_str) { \
free(target->name); \
target->name = new_str; \
}
查找字符串Name,不包含带有*
的字符串,然后将Name的数据赋值给target,也就是外部的ASS_Style *target;
实现:
int ass_strcasecmp(const char *s1, const char *s2)
{
unsigned char a, b;
do {
a = lowertab[(unsigned char)*s1++];
b = lowertab[(unsigned char)*s2++];
} while (a && a == b);
return a - b;
}
对比s1和s2,如果s1和s2相等,那么返回0。
#define strdup ass_strdup_fallback
定义了一个函数调用,其实现:
// Fallbacks
#ifndef HAVE_STRDUP
char *ass_strdup_fallback(const char *str)
{
size_t len = strlen(str) + 1;
char *new_str = malloc(len);
if (new_str)
memcpy(new_str, str, len);
return new_str;
}
#endif
给str字符串申请了空间,放在堆里面备用。
和STARREDSTRVAL功能类似,该宏定义实现的功能是查找字符串Name,然后将Name的数据赋值给target,也就是外部的ASS_Style *target;
,没有检查包含带有*
的字符串的功能
实现:
#define STRVAL(name) \
} else if (ass_strcasecmp(tname, #name) == 0) { \
char *new_str = strdup(token); \
if (new_str) { \
free(target->name); \
target->name = new_str; \
}
其余待写,其实到这里,后面的都大同小异,相同的分析思路。
由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 wencoo824。QQ:1419440391。
欢迎加微信,搜索"wencoo824",进行技术交流,备注”博客音视频技术交流“