/*
ngx 版本0.1.0
这个函数会被循环调用多次
把每次分析的值放到cf->args这个数组里面
碰到{ ; 返回
ngx数组的用法要知道
此函数读取如下的格式
格式1
user nobody;
http {
include conf/mime.types;
#gzip on;
server {
listen 80;
location / {root html; }
}
}
user nobody cf->args 数组长度2
http cf->args 数组长度1
include conf/mime.types cf->args 数组长度2
还可以读取以下格式 可以用双(单)引号包括 可以多个相连
格式2
'error_log' "logs/error.log"; cf->args数组长度2
"error_log" "logs/err
or.log"; 用引号包括可以有换行 数组长度1
error_log "l\"ogs/error.log"; 中间有双引号要用\转义 数组长度2
error_log "logs/error.log" "dfadsfa";相邻的双引号中间要有\r\n\t或空格 数组长度3
上面单引号一样
*/
//用到的几个结构体如下
struct ngx_buf_s {
u_char *pos;
u_char *last;//内容的实际末尾位置
off_t file_pos;
off_t file_last;
int type;
u_char *start; //分配内存开始指针 /* start of buffer */
u_char *end; //分配内存结束指针 /* end of buffer */
ngx_buf_tag_t tag;
ngx_file_t *file;
ngx_buf_t *shadow;
/* the buf's content could be changed */
unsigned temporary:1;
/*
* the buf's content is in a memory cache or in a read only memory
* and must not be changed
*/
unsigned memory:1;
/* the buf's content is mmap()ed and must not be changed */
unsigned mmap:1;
unsigned recycled:1;
unsigned in_file:1;
unsigned flush:1;
unsigned last_buf:1;
unsigned last_shadow:1;
unsigned temp_file:1;
unsigned zerocopy_busy:1;
/* STUB */ int num;
};
typedef struct {
ngx_file_t file;//里面存有个文件的信息 前面赋过值
ngx_buf_t *buffer;//一次读取的内容放到这个里面
ngx_uint_t line; //记录配置文件的行数
} ngx_conf_file_t;
struct ngx_conf_t {
char *name;
ngx_array_t *args;
ngx_cycle_t *cycle;
ngx_pool_t *pool;
ngx_conf_file_t *conf_file;
ngx_log_t *log;
void *ctx;
ngx_uint_t module_type;
ngx_uint_t cmd_type;
ngx_conf_handler_pt handler;
char *handler_conf;
};
static int ngx_conf_read_token(ngx_conf_t *cf)
{
u_char *start, ch, *src, *dst;
int len;
int found, need_space, last_space, sharp_comment;
int quoted, s_quoted, d_quoted;
ssize_t n;
ngx_str_t *word;
ngx_buf_t *b;
found = 0;
need_space = 0;
last_space = 1;
sharp_comment = 0;
quoted = s_quoted = d_quoted = 0;
cf->args->nelts = 0;
b = cf->conf_file->buffer;
start = b->pos;
#if 0
ngx_log_debug(cf->log, "TOKEN START");
#endif
for ( ;; ) {
//每次读取配置文件1024个字节的内容
if (b->pos >= b->last) {//读取的内容分析完了 重读取
if (cf->conf_file->file.offset
>= ngx_file_size(&cf->conf_file->file.info)) {
return NGX_CONF_FILE_DONE;//整个文件分析完成
}
//start cf->args数组里面每个元素的开始指针
//b->pos 每向后分析一个字符加一 当前位置
//b->last 内存中实际内容尾部指针
//b->start 分配内存的头 b->end 分配内存的尾 这两个值不变
//下面的自己算了
if (b->pos - start) {//分析上次的末尾
ngx_memcpy(b->start, start, b->pos - start);
}
n = ngx_read_file(&cf->conf_file->file,
b->start + (b->pos - start),
b->end - (b->start + (b->pos - start)),
cf->conf_file->file.offset);
if (n == NGX_ERROR) {
return NGX_ERROR;
}
b->pos = b->start + (b->pos - start);
start = b->start;
b->last = b->pos + n;
}
ch = *b->pos++;//pos位置加加
#if 0
ngx_log_debug(cf->log, "%d:%d:%d:%d:%d '%c'" _
last_space _ need_space _
quoted _ s_quoted _ d_quoted _ ch);
#endif
if (ch == LF) {//碰到\n
cf->conf_file->line++;
if (sharp_comment) {//注释不支持换行
sharp_comment = 0;
}
}
if (sharp_comment) {
continue;
}
if (quoted) {//碰到\ "sflj\"dlf" 这种情况
quoted = 0;
continue;
}
if (need_space) {//有单引号双引号开始的 处理上面格式2
if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
last_space = 1;
need_space = 0;
continue;
}
if (ch == ';' || ch == '{') {
return NGX_OK;
}
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"unexpected '%c' in %s:%d",
ch, cf->conf_file->file.name.data,
cf->conf_file->line);
return NGX_ERROR;
}
if (last_space) {//last_space 判断cf->args这个数组里面每个元素的开始位置
if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
continue;
}
start = b->pos - 1;
switch (ch) {
case ';':
case '{':
if (cf->args->nelts == 0) {//以{开始 但是cf->args元素为0 {前面必须有值
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"unexpected '%c' in %s:%d",
ch, cf->conf_file->file.name.data,
cf->conf_file->line);
return NGX_ERROR;
}
return NGX_OK;
case '}'://一个块分析完成
if (cf->args->nelts > 0) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"unexpected '}' in %s:%d",
cf->conf_file->file.name.data,
cf->conf_file->line);
return NGX_ERROR;
}
return NGX_CONF_BLOCK_DONE;
case '#'://注释
sharp_comment = 1;
continue;
case '\\':
quoted = 1;
last_space = 0;
continue;
case '"':
start++;//以双引号开始 开始元素位置加一
d_quoted = 1;
last_space = 0;
continue;
case '\'':
start++;
s_quoted = 1;
last_space = 0;
continue;
default:
last_space = 0;
}
} else {//处理开始后的情况
if (ch == '\\') {
quoted = 1;
continue;
}
if (d_quoted) {//双引号
if (ch == '"') {
d_quoted = 0;
need_space = 1;
found = 1;
}
} else if (s_quoted) {
if (ch == '\'') {
s_quoted = 0;
need_space = 1;
found = 1;
}
} else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF
|| ch == ';' || ch == '{') {
//碰到这些值 cf->args数组一个元素的的结束 \r\n上面的if elseif先处理过了
last_space = 1;
found = 1;
}
if (found) {//要把值放到cf->args中
if (!(word = ngx_push_array(cf->args))) {
/*
这句获取一个元素的地址
cf->args被分配内存 conf.args = ngx_create_array(pool, 10, sizeof(ngx_str_t)); ngx_cycle.c:148行
*/
return NGX_ERROR;
}
if (!(word->data = ngx_palloc(cf->pool, b->pos - start + 1))) {
//ngx_str_t->data分配内存
return NGX_ERROR;
}
//复制值到cf->args中
for (dst = word->data, src = start, len = 0;
src < b->pos - 1;
len++)
{
if (*src == '\\') {//\t \r \n添加到cf->args数组元素中
switch (src[1]) {
case '"':
case '\'':
case '\\':
src++;
break;
case 't':
*dst++ = '\t';
src += 2;
continue;
case 'r':
*dst++ = '\r';
src += 2;
continue;
case 'n':
*dst++ = '\n';
src += 2;
continue;
}
}
*dst++ = *src++;
}
*dst = '\0';
word->len = len;
#if 0
ngx_log_debug(cf->log, "FOUND %d:'%s'" _ word->len _ word->data);
#endif
if (ch == ';' || ch == '{') {
return NGX_OK;
}
found = 0;//cf->args元素新的开始
}
}
}
}
nginx ngx_conf_read_token详细分析
最新推荐文章于 2022-08-02 14:56:59 发布