nginx ngx_conf_read_token详细分析

/*
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元素新的开始
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值