nginx 配置文件解析函数------------ngx_conf_read_token

来源:互联网 发布:游戏狗软件 编辑:程序博客网 时间:2024/06/11 22:51

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_tngx_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;            }        }    }}



0 0
原创粉丝点击