例如一個配置行的話. 就返回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;
-
}
-
}
-
}
- }