Chinaunix首页 | 论坛 | 博客
  • 博客访问: 368642
  • 博文数量: 56
  • 博客积分: 1449
  • 博客等级: 中尉
  • 技术积分: 822
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-08 10:24
文章分类

全部博文(56)

文章存档

2014年(7)

2012年(13)

2011年(10)

2010年(26)

分类: 服务器与存储

2014-07-23 16:44:04

该函数获取配置文件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.

点击(此处)折叠或打开

  1. static ngx_int_t
  2. ngx_conf_read_token(ngx_conf_t *cf)
  3. {
  4.     u_char *start, ch, *src, *dst;
  5.     off_t file_size;
  6.     size_t len;
  7.     ssize_t n, size;
  8.     ngx_uint_t found, need_space, last_space, sharp_comment, variable;
  9.     ngx_uint_t quoted, s_quoted, d_quoted, start_line;
  10.     ngx_str_t *word;
  11.     ngx_buf_t *b;

  12.     found = 0;
  13.     need_space = 0;
  14.     last_space = 1;
  15.     sharp_comment = 0;
  16.     variable = 0;
  17.     quoted = 0;
  18.     s_quoted = 0;
  19.     d_quoted = 0;

  20.     cf->args->nelts = 0;
  21.     b = cf->conf_file->buffer;
  22.     start = b->pos;
  23.     start_line = cf->conf_file->line;

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

  25.     for ( ;; ) {
  26. //已处理完缓冲区中的字符.
  27.         if (b->pos >= b->last) {

  28.             if (cf->conf_file->file.offset >= file_size) {
  29. //文件已处理完. 但是已解析出的token数大于0或者已发现一个token的
  30. //起始位置. 配置行不完整. 配置语法出错。
  31.                 if (cf->args->nelts > 0 || !last_space) {

  32.                     if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
  33.                         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  34.                                            "unexpected end of parameter, "
  35.                                            "expecting \";\"");
  36.                         return NGX_ERROR;
  37.                     }

  38.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  39.                                   "unexpected end of file, "
  40.                                   "expecting \";\" or \"}\"");
  41.                     return NGX_ERROR;
  42.                 }
  43. //处理完配置文件.
  44.                 return NGX_CONF_FILE_DONE;
  45.             }
  46. //未处理的缓冲区字符长度.
  47.             len = b->pos - start;
  48. //若长度等于缓冲区长度. 则配置出错.
  49. //token长度不能大于NGX_CONF_BUFFER.
  50.             if (len == NGX_CONF_BUFFER) {
  51.                 cf->conf_file->line = start_line;

  52.                 if (d_quoted) {
  53.                     ch = '"';

  54.                 } else if (s_quoted) {
  55.                     ch = '\'';

  56.                 } else {
  57.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  58.                                        "too long parameter \"%*s...\" started",
  59.                                        10, start);
  60.                     return NGX_ERROR;
  61.                 }

  62.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  63.                                    "too long parameter, probably "
  64.                                    "missing terminating \"%c\" character", ch);
  65.                 return NGX_ERROR;
  66.             }
  67. //将未处理完的字符拷贝到缓冲区开始出. 这些字符是一个token的一部分
  68.             if (len) {
  69.                 ngx_memmove(b->start, start, len);
  70.             }
  71. // 配置文件未处理的长度.
  72.             size = (ssize_t) (file_size - cf->conf_file->file.offset);
  73. //若超过可用缓冲区长度则一次读取可用缓冲区长度的字符.
  74.             if (size > b->end - (b->start + len)) {
  75.                 size = b->end - (b->start + len);
  76.             }
  77. //从上次读取结束的地方开始读取size个字符继续处理.
  78.             n = ngx_read_file(&cf->conf_file->file, b->start + len, size,
  79.                               cf->conf_file->file.offset);

  80.             if (n == NGX_ERROR) {
  81.                 return NGX_ERROR;
  82.             }

  83.             if (n != size) {
  84.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  85.                                    ngx_read_file_n " returned "
  86.                                    "only %z bytes instead of %z",
  87.                                    n, size);
  88.                 return NGX_ERROR;
  89.             }
  90. //[b->pos, b->last) 之间是需要处理的字符.
  91.             b->pos = b->start + len;
  92.             b->last = b->pos + n;
  93.             start = b->start;
  94.         }

  95.         ch = *b->pos++;
  96. //当前字符是换行符. 行计数器增1, 若之前扫描到该行首是注释符, 则注释标识清
  97. //0。
  98.         if (ch == LF) {
  99.             cf->conf_file->line++;

  100.             if (sharp_comment) {
  101.                 sharp_comment = 0;
  102.             }
  103.         }
  104. //当前行是注释行, 吃掉该行后续所有字符.
  105.         if (sharp_comment) {
  106.             continue;
  107.         }
  108. //跳过\后面的字符. 即转义序列.
  109.         if (quoted) {
  110.             quoted = 0;
  111.             continue;
  112.         }
  113. //当token被单或双引号包围是need_space会被置1.
  114.         if (need_space) {

  115.             if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
  116.                 last_space = 1;
  117.                 need_space = 0;
  118.                 continue;
  119.             }


  120. //配置行以分号结尾.
  121.             if (ch == ';') {
  122.                 return NGX_OK;
  123.             }
  124. //配置块以{开始
  125.             if (ch == '{') {
  126.                 return NGX_CONF_BLOCK_START;
  127.             }

  128.             if (ch == ')') {
  129.                 last_space = 1;
  130.                 need_space = 0;

  131.             } else {
  132.                  ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  133.                                     "unexpected \"%c\"", ch);
  134.                  return NGX_ERROR;
  135.             }
  136.         }
  137. //last_space为1表明未发现token起始位置, 吃掉所有空白字符.
  138.         if (last_space) {
  139.             if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
  140.                 continue;
  141.             }
  142. //非空白字符是一个token的起始位置.
  143.             start = b->pos - 1;
  144.             start_line = cf->conf_file->line;

  145.             switch (ch) {

  146.             case ';':
  147.             case '{':
  148. //在分号和左括号之前必定会出现至少一个token. 否则是配置语法错误
  149.                 if (cf->args->nelts == 0) {
  150.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  151.                                        "unexpected \"%c\"", ch);
  152.                     return NGX_ERROR;
  153.                 }
  154. //配置块起始位置.
  155.                 if (ch == '{') {
  156.                     return NGX_CONF_BLOCK_START;
  157.                 }
  158. //配置行结束.
  159.                 return NGX_OK;
  160. //配置块结束标识右括号独占一行.
  161.             case '}':
  162.                 if (cf->args->nelts != 0) {
  163.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  164.                                        "unexpected \"}\"");
  165.                     return NGX_ERROR;
  166.                 }

  167.                 return NGX_CONF_BLOCK_DONE;
  168. //注释符.
  169.             case '#':
  170.                 sharp_comment = 1;
  171.                 continue;
  172. //转义序列.其后面的一个字符将被跳过.
  173.             case '\\':
  174.                 quoted = 1;
  175.                 last_space = 0;
  176.                 continue;
  177. //引号开头的token.
  178.             case '"':
  179.                 start++;
  180.                 d_quoted = 1;
  181.                 last_space = 0;
  182.                 continue;

  183.             case '\'':
  184.                 start++;
  185.                 s_quoted = 1;
  186.                 last_space = 0;
  187.                 continue;

  188.             default:
  189.                 last_space = 0;
  190.             }
  191. //到这里开始处理token字符.
  192.         } else {
  193.             if (ch == '{' && variable) {
  194.                 continue;
  195.             }

  196.             variable = 0;
  197. //转义序列.其后面的一个字符将被跳过
  198.             if (ch == '\\') {
  199.                 quoted = 1;
  200.                 continue;
  201.             }
  202. //??????这里是什么???
  203.             if (ch == '$') {
  204.                 variable = 1;
  205.                 continue;
  206.             }
  207. //单双引号包围的字符是一个token.
  208.             if (d_quoted) {
  209.                 if (ch == '"') {
  210.                     d_quoted = 0;
  211.                     need_space = 1;
  212.                     found = 1;
  213.                 }

  214.             } else if (s_quoted) {
  215.                 if (ch == '\'') {
  216.                     s_quoted = 0;
  217.                     need_space = 1;
  218.                     found = 1;
  219.                 }
  220. //字符是空格、制表符、换行符、分号或是左花括号表示一个token的结束.
  221. //也即发现一个token
  222.             } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF
  223.                        || ch == ';' || ch == '{')
  224.             {
  225.                 last_space = 1;
  226.                 found = 1;
  227.             }

  228.             if (found) {
  229. //将该token放入cf->args动态数组中.
  230.                 word = ngx_array_push(cf->args);
  231.                 if (word == NULL) {
  232.                     return NGX_ERROR;
  233.                 }

  234.                 word->data = ngx_pnalloc(cf->pool, b->pos - start + 1);
  235.                 if (word->data == NULL) {
  236.                     return NGX_ERROR;
  237.                 }
  238. //将token中的转义序列转义后复制给word->data, 其他的按原样复制.
  239.                 for (dst = word->data, src = start, len = 0;
  240.                      src < b->pos - 1;
  241.                      len++)
  242.                 {
  243.                     if (*src == '\\') {
  244.                         switch (src[1]) {
  245.                         case '"':
  246.                         case '\'':
  247.                         case '\\':
  248.                             src++;
  249.                             break;

  250.                         case 't':
  251.                             *dst++ = '\t';
  252.                             src += 2;
  253.                             continue;

  254.                         case 'r':
  255.                             *dst++ = '\r';
  256.                             src += 2;
  257.                             continue;

  258.                         case 'n':
  259.                             *dst++ = '\n';
  260.                             src += 2;
  261.                             continue;
  262.                         }

  263.                     }
  264.                     *dst++ = *src++;
  265.                 }
  266.                 *dst = '\0';
  267.                 word->len = len;
  268. //若token以分号结束则处理完一个配置行.
  269.                 if (ch == ';') {
  270.                     return NGX_OK;
  271.                 }
  272. //若token以左花括号结束则发现配置块起始位置.
  273.                 if (ch == '{') {
  274.                     return NGX_CONF_BLOCK_START;
  275.                 }
  276. //发现token标识清0
  277.                 found = 0;
  278.             }
  279.         }
  280.     }
  281. }


阅读(4233) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~