该函数获取配置文件nginx.conf中的配置行或者配置块起始处的token.将这些token放在cf->args动态数组中, 并返回这些token所在配置文件中的位置.
例如一个配置行的话. 就返回NGX_OK. 配置行以分号结尾. 如果是一个配置块的起始处, 即以'{'结尾, 则返回NGX_CONF_BLOCK_START.
对于token的定义为: 连续非空白字符. 单双引号包围的字符. 单双引号内允许转义序列如\t, \r, \n.
'#'之后为注释. 其后行内的所有字符全部忽略.
理解该函数的要点只需理解几个标识的具体含义即可.
found: 为1表明发现一个token. 然后将该token压入cf->args数组中.
need_space: token被单双引号包围时, 最后一个分号后面必须是空白字符、分号、坐花括号或者右括号( 左括号匹配在代码中没看见? ). 否则出错.
last_space: 为1表明前面扫描的字符均为空白字符. 即还未发现token起始位置. 为0表明已找到token的起始位置.
sharp_comment: 扫描到'#'字符后置1, 其后所有字符都会忽略直至一行结束.
quoted: 转义序列, '\'之后的字符被跳过.然后quoted置0.
s_quoted, d_quoted: token以单或双引号起始, 必须以单或双引号结束.
例如:
worker_processes 1;
解析后cf->args数组里有两个ngx_str_t结构. 两个字符串分别是"worker_processes"和"1", 返回值为NGX_OK。
event {
worker_connections 1024;
}
解析时cf_args数组里有一个ngx_str_t结构.字符串为"event". 返回值为NGX_CONF_BLOCK_START.
例如一个配置行的话. 就返回NGX_OK. 配置行以分号结尾. 如果是一个配置块的起始处, 即以'{'结尾, 则返回NGX_CONF_BLOCK_START.
对于token的定义为: 连续非空白字符. 单双引号包围的字符. 单双引号内允许转义序列如\t, \r, \n.
'#'之后为注释. 其后行内的所有字符全部忽略.
理解该函数的要点只需理解几个标识的具体含义即可.
found: 为1表明发现一个token. 然后将该token压入cf->args数组中.
need_space: token被单双引号包围时, 最后一个分号后面必须是空白字符、分号、坐花括号或者右括号( 左括号匹配在代码中没看见? ). 否则出错.
last_space: 为1表明前面扫描的字符均为空白字符. 即还未发现token起始位置. 为0表明已找到token的起始位置.
sharp_comment: 扫描到'#'字符后置1, 其后所有字符都会忽略直至一行结束.
quoted: 转义序列, '\'之后的字符被跳过.然后quoted置0.
s_quoted, d_quoted: token以单或双引号起始, 必须以单或双引号结束.
例如:
worker_processes 1;
解析后cf->args数组里有两个ngx_str_t结构. 两个字符串分别是"worker_processes"和"1", 返回值为NGX_OK。
event {
worker_connections 1024;
}
解析时cf_args数组里有一个ngx_str_t结构.字符串为"event". 返回值为NGX_CONF_BLOCK_START.
点击(此处)折叠或打开
- 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;
- b = cf->conf_file->buffer;
- start = b->pos;
- start_line = cf->conf_file->line;
-
- file_size = ngx_file_size(&cf->conf_file->file.info);
-
- for ( ;; ) {
- //已处理完缓冲区中的字符.
- if (b->pos >= b->last) {
-
- if (cf->conf_file->file.offset >= file_size) {
- //文件已处理完. 但是已解析出的token数大于0或者已发现一个token的
- //起始位置. 配置行不完整. 配置语法出错。
- 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;
- }
- //处理完配置文件.
- return NGX_CONF_FILE_DONE;
- }
- //未处理的缓冲区字符长度.
- len = b->pos - start;
- //若长度等于缓冲区长度. 则配置出错.
- //token长度不能大于NGX_CONF_BUFFER.
- 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;
- }
- //将未处理完的字符拷贝到缓冲区开始出. 这些字符是一个token的一部分
- if (len) {
- ngx_memmove(b->start, start, len);
- }
- // 配置文件未处理的长度.
- size = (ssize_t) (file_size - cf->conf_file->file.offset);
- //若超过可用缓冲区长度则一次读取可用缓冲区长度的字符.
- if (size > b->end - (b->start + len)) {
- size = b->end - (b->start + len);
- }
- //从上次读取结束的地方开始读取size个字符继续处理.
- 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;
- }
- //[b->pos, b->last) 之间是需要处理的字符.
- b->pos = b->start + len;
- b->last = b->pos + n;
- start = b->start;
- }
-
- ch = *b->pos++;
- //当前字符是换行符. 行计数器增1, 若之前扫描到该行首是注释符, 则注释标识清
- //0。
- if (ch == LF) {
- cf->conf_file->line++;
-
- if (sharp_comment) {
- sharp_comment = 0;
- }
- }
- //当前行是注释行, 吃掉该行后续所有字符.
- if (sharp_comment) {
- continue;
- }
- //跳过\后面的字符. 即转义序列.
- if (quoted) {
- quoted = 0;
- continue;
- }
- //当token被单或双引号包围是need_space会被置1.
- if (need_space) {
-
- if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
- last_space = 1;
- need_space = 0;
- continue;
- }
-
-
- //配置行以分号结尾.
- if (ch == ';') {
- return NGX_OK;
- }
- //配置块以{开始
- 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表明未发现token起始位置, 吃掉所有空白字符.
- if (last_space) {
- if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
- continue;
- }
- //非空白字符是一个token的起始位置.
- start = b->pos - 1;
- start_line = cf->conf_file->line;
-
- switch (ch) {
-
- case ';':
- case '{':
- //在分号和左括号之前必定会出现至少一个token. 否则是配置语法错误
- 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 = 1;
- continue;
- //转义序列.其后面的一个字符将被跳过.
- case '\\':
- quoted = 1;
- last_space = 0;
- continue;
- //引号开头的token.
- case '"':
- start++;
- d_quoted = 1;
- last_space = 0;
- continue;
-
- case '\'':
- start++;
- s_quoted = 1;
- last_space = 0;
- continue;
-
- default:
- last_space = 0;
- }
- //到这里开始处理token字符.
- } else {
- if (ch == '{' && variable) {
- continue;
- }
-
- variable = 0;
- //转义序列.其后面的一个字符将被跳过
- if (ch == '\\') {
- quoted = 1;
- continue;
- }
- //??????这里是什么???
- if (ch == '$') {
- variable = 1;
- continue;
- }
- //单双引号包围的字符是一个token.
- 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;
- }
- //字符是空格、制表符、换行符、分号或是左花括号表示一个token的结束.
- //也即发现一个token
- } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF
- || ch == ';' || ch == '{')
- {
- last_space = 1;
- found = 1;
- }
-
- if (found) {
- //将该token放入cf->args动态数组中.
- word = ngx_array_push(cf->args);
- if (word == NULL) {
- return NGX_ERROR;
- }
-
- word->data = ngx_pnalloc(cf->pool, b->pos - start + 1);
- if (word->data == NULL) {
- return NGX_ERROR;
- }
- //将token中的转义序列转义后复制给word->data, 其他的按原样复制.
- 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;
- //若token以分号结束则处理完一个配置行.
- if (ch == ';') {
- return NGX_OK;
- }
- //若token以左花括号结束则发现配置块起始位置.
- if (ch == '{') {
- return NGX_CONF_BLOCK_START;
- }
- //发现token标识清0
- found = 0;
- }
- }
- }
- }