读取nginx的conf文件_nginx 配置文件解析函数————ngx_conf_read_token

  • Post author:
  • Post category:其他


1. 首先在函数ngx_conf_parse 根据文件名申请buff

2.根据文件大小读取文件内容

3. 逐个读取字符

解析文件中的字符步骤:

一)last_space 为1的情况,表示刚开始解析或者是前面已经解析到一个关键字(一般以空格,分号, 左大括号等为边界).

1. pos指针一个字符一个字符往右移动 ch = *pos++

2. 遇到空格,制表符(\t),回车,换行,直接跳过

3.更新局部变量start为pos指针-1

4.遇到分号,左大括号和右大括号直接return返回

5.遇到# 设置comment标记,continue

6.遇到\,’,”,设置对应标记,并将last_space 设置为0

7.其它情况设置last_space 为0

二)Last_sapce  不为0,解析关键字过程中

1. 遇到${,continue

2.遇到\, $等设置标记位,continue

3.遇到第二个双引号或者单引号,清空引号标记位,设置找到关键字标记found=1,并且设置后面跟着的字符必须有空格Need_space=1

4.遇到空格,\t,回车,换行,{,分号,设置找到关键字标记found=1,并设置last_space为1,重新开始寻找新的关键字.

5.找到关键字found=1,从存放关键字的数组cf->args找到一个空位置,将关键字存放到该字符串数组的空位中。如果是因为第4步骤的分号或者{设置的,这return OK或BLOKC_START。更新found为0

static ngx_int_t

ngx_conf_read_token(ngx_conf_t *cf)

{

u_char *start, ch, *src, *dst;

off_t file_size;

size_t len;

ssize_t n, size;

ngx_uint_t found, need_space, last_space, sharp_comment, variable;

ngx_uint_t quoted, s_quoted, d_quoted, start_line;

ngx_str_t *word;

ngx_buf_t *b;

found = 0;

need_space = 0;

last_space = 1;

sharp_comment = 0;

variable = 0;

quoted = 0;

s_quoted = 0;

d_quoted = 0;

cf->args->nelts = 0;/*设置保存参数的数组个数为0,即清空保存配置的数组*/

/*获取配置文件的buffer*/

b = cf->conf_file->buffer;

/*上一次读取结束的文件buf位置,第一次读取时为文件的起始位置*/

start = b->pos;

/*上一次读取的结束行数*/

start_line = cf->conf_file->line;

/*配置文件大小(字节)*/

file_size = ngx_file_size(&cf->conf_file->file.info);

ngx_conf_log_error(NGX_LOG_DEBUG,cf,0,”file_size=%lu,start_line=%uz”,file_size,start_line);

for ( ;; ) {

/*第一次,b->pos = b->last,后续b->last指向读取buffer的结尾,

* 从第2次循环开始,如果为真,表示前一次读取的buffer已经全部解析完毕,需要进入判断一下是否文件已经读完,或者没有读完的话,继续读取

* 第2次以后if为真的情况是,文件的大小大于buffer的长度(4096),此时需要多次读取*/

if (b->pos >= b->last) {

/*如果偏移量大于文件大小,说明文件已读取完毕,返回NGX_CONF_FILE_DONE*/

if (cf->conf_file->file.offset >= file_size) {

if (cf->args->nelts > 0 || !last_space) {

if (cf->conf_file->file.fd == NGX_INVALID_FILE) {

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

“unexpected end of parameter, ”

“expecting \”;\””);

return NGX_ERROR;

}

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

“unexpected end of file, ”

“expecting \”;\” or \”}\””);

return NGX_ERROR;

}

ngx_conf_log_error(NGX_LOG_DEBUG,cf,0,”start =%d,pos=%d”,start,b->pos);

return NGX_CONF_FILE_DONE;

}

/*这个两个值在重新执行for循环的情况下应该相等,因为前面刚刚把b->pos赋值给了start*/

len = b->pos – start; /*len表示还有多少已扫描但是没有被解析*/

/*如果这个长度超过了最大文件buffer,NGX_CONF_BUFFER(4096),出错返回*/

if (len == NGX_CONF_BUFFER) {

cf->conf_file->line = start_line;

if (d_quoted) {

ch = ‘”‘;

} else if (s_quoted) {

ch = ‘\”;

} else {

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

“too long parameter \”%*s…\” started”,

10, start);

return NGX_ERROR;

}

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

“too long parameter, probably ”

“missing terminating \”%c\” character”, ch);

return NGX_ERROR;

}

/**/

if (len) {

ngx_memmove(b->start, start, len);

}

size = (ssize_t) (file_size – cf->conf_file->file.offset);

/*即文件大小大于分配的buffer长度,size取为buffer长度*/

if (size > b->end – (b->start + len)) {

size = b->end – (b->start + len);

}

/*读取size大小的文件数据到buf中,起始地址为b->start + len,修改文件偏移量*/

n = ngx_read_file(&cf->conf_file->file, b->start + len, size,

cf->conf_file->file.offset);

if (n == NGX_ERROR) {

return NGX_ERROR;

}

if (n != size) {

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

ngx_read_file_n ” returned ”

“only %z bytes instead of %z”,

n, size);

return NGX_ERROR;

}

/*修改当前buf的位置b->pos*/

b->pos = b->start + len;

/*指向数据的结尾*/

b->last = b->pos + n;

start = b->start;

}

/*一个字节一个字节地循环处理文件buff内容*/

ch = *b->pos++;

/*如果是换行符*/

if (ch == LF) {

cf->conf_file->line++;//处理的行数+1

if (sharp_comment) {//修改注释行标记位

sharp_comment = 0;

}

}

/*如果前面是#开头的注释,直接跳过#后面的所有字符,直到上面的遇到换行符后,

* 将该注释标记去除,表示注释结束,新的行开始0*/

if (sharp_comment) {

continue;

}

/*前面有反斜杠转义字符\,说明这个字符是一个转义字符,忽略\后面的字符*/

if (quoted) {

quoted = 0;

continue;

}

/*need_space默认为0,单引号或者双引号结束后,需要有以下分隔符:

* 空格,制表符,回车,换行,分号,左大括号,右小括号

* 遇到其它都是错误的,返回error*/

if (need_space) {

/*如果遇到空格,制表符,回车,换行,则将need_space清空,last_space置1*/

if (ch == ‘ ‘ || ch == ‘\t’ || ch == CR || ch == LF) {

last_space = 1;

need_space = 0;

continue;

}

/*如果遇到分号;则该行读取结束*/

if (ch == ‘;’) {

return NGX_OK;

}

/*遇到'{‘表示新的block的开始*/

if (ch == ‘{‘) {

return NGX_CONF_BLOCK_START;

}

if (ch == ‘)’) {

last_space = 1;

need_space = 0;

} else {

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

“unexpected \”%c\””, ch);

return NGX_ERROR;

}

}

/*last_space初始化为1,last_space表示上一个字符为字符串分隔符,需要重新计算start,以表示新的token的起始地址*/

if (last_space) {

/*遇到空格,制表符,回车,换行等字符,则无需处理*/

if (ch == ‘ ‘ || ch == ‘\t’ || ch == CR || ch == LF) {

continue;

}

start = b->pos – 1;/*更新start值,作为新的token(关键字)的起始地址*/

start_line = cf->conf_file->line;

switch (ch) {

/*遇到;或者{,直接返回*/

case ‘;’:

case ‘{‘:

if (cf->args->nelts == 0) {

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

“unexpected \”%c\””, ch);

return NGX_ERROR;

}

if (ch == ‘{‘) {

return NGX_CONF_BLOCK_START;

}

return NGX_OK;

case ‘}’: //遇到}也返回

if (cf->args->nelts != 0) {

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

“unexpected \”}\””);

return NGX_ERROR;

}

return NGX_CONF_BLOCK_DONE;

case ‘#’:/*遇到#,设置sharp_comment标记*/

sharp_comment = 1;

continue;

case ‘\\’:/*遇到\,设置quoted=1,last_space=0*/

quoted = 1;

last_space = 0;

continue;

case ‘”‘://遇到第一个“,设置d_quoted为1

start++;

d_quoted = 1;

last_space = 0;

continue;

case ‘\”://遇到第一个单引号’,设置s_quoted为1

start++;

s_quoted = 1;

last_space = 0;

continue;

default:

last_space = 0;

}

} else {

if (ch == ‘{‘ && variable) {

continue;

}

variable = 0;

if (ch == ‘\\’) {

quoted = 1;

continue;

}

/*遇到$符,设置variable为1*/

if (ch == ‘$’) {

variable = 1;

continue;

}

if (d_quoted) {

if (ch == ‘”‘) {//遇到第二个双引号”,设置d_quoted=0,need_space=1,found=1

d_quoted = 0;

need_space = 1;

found = 1;

}

} else if (s_quoted) {//遇到第二个单引号’,设置s_quoted=0,need_space=1,found=1

if (ch == ‘\”) {

s_quoted = 0;

need_space = 1;

found = 1;

}

} else if (ch == ‘ ‘ || ch == ‘\t’ || ch == CR || ch == LF

|| ch == ‘;’ || ch == ‘{‘)//遇到空格,制表符,回车,换行符,分号,{,设置last_space=1,found=1

{

last_space = 1;

found = 1;

}

//正常情况下,遇到空格或分号结束时,设置了last_space=1,found=1

if (found) {

/*args是初始化为10个ngx_str_t大小的动态数组,在ngx_init_cycle中初始化

* 存放配置文件中的一行中的关键字,如:

* worker_processes 1;

* args的第一个数组元素就是 worker_process

* 第二个数组元素就是1*/

word = ngx_array_push(cf->args);//找到数组可用的位置

if (word == NULL) {

return NGX_ERROR;

}

/*文件数据的起始位置为start,当前的位置为b->pos*/

word->data = ngx_pnalloc(cf->pool, b->pos – start + 1);

if (word->data == NULL) {

return NGX_ERROR;

}

/*将start开始的数据拷贝到word->data中,并记录拷贝的大小len*/

for (dst = word->data, src = start, len = 0;

src < b->pos – 1;

len++)

{

if (*src == ‘\\’) {

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 (ch == ‘;’) {

return NGX_OK;

}

/*如果是一个block,如event,则返回NGX_CONF_BLOCK_START*/

if (ch == ‘{‘) {

return NGX_CONF_BLOCK_START;

}

/*等于其它的符号,如空格,则继续循环*/

found = 0;

}

}

}

}



版权声明:本文为weixin_33509203原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。