BOA代码笔记 2

boa.c 续

书接上回。
main函数的调用到了 fixup_server_root()
static void fixup_server_root()
{
    char *dirbuf;

    if (!server_root) {
#ifdef SERVER_ROOT
        server_root = strdup(SERVER_ROOT);
        if (!server_root) {
            perror("strdup (SERVER_ROOT)");
            exit(1);
        }
#else
        fputs("boa: don't know where server root is.  Please #define "
              "SERVER_ROOT in boa.h\n"
              "and recompile, or use the -c command line option to "
              "specify it.\n", stderr);
        exit(1);
#endif
    }

    if (chdir(server_root) == -1) {
        fprintf(stderr, "Could not chdir to \"%s\": aborting\n",
                server_root);
        exit(1);
    }

    dirbuf = normalize_path(server_root);
    free(server_root);
    server_root = dirbuf;
}
该函数的功能主要是由程序运行时的选项和defines.h里的宏定义确定server_root。
如果参数没有指定server_root,那么就由宏指定,如果宏没指定,就报错。

该函数最后调用的normalize_path(),定义在util.c里。功能是,如果给出的是绝对路径,不转化。如果是相对路径转化为绝对路径。
该函数不贴了,用到了getcwd()
       #include <unistd.h>
       char *getcwd(char *buf, size_t size);
       char *getwd(char *buf);
getcwd函数返回当前程序的工作目录。因此,如果相对路径不是"."的话,还需要将两个字符串连接起来。细节上的处理大家有兴趣的话可以看一下。

 fixup_server_root()调用完毕,程序运行到这儿,应该已经有了规范的工作目录了。


main函数继续执行到read_config_files();
程序的注释说,Description: Reads config files via yyparse, then makes sure that  all required variables were set properly.
这个函数解析配置文件,保证所有的全局变量正确初始化。
void read_config_files(void)
{
    char *temp;
    current_uid = getuid();
    yyin = fopen("boa.conf", "r");

    if (!yyin) {
        fputs("Could not open boa.conf for reading.\n", stderr);
        exit(1);
    }
    if (yyparse()) {
        fputs("Error parsing config files, exiting\n", stderr);
        exit(1);
    }

    if (!server_name) {
        struct hostent *he;
        char temp_name[100];

        if (gethostname(temp_name, 100) == -1) {
            perror("gethostname:");
            exit(1);
        }

        he = gethostbyname(temp_name);
        if (he == NULL) {
            perror("gethostbyname:");
            exit(1);
        }

        server_name = strdup(he->h_name);
        if (server_name == NULL) {
            perror("strdup:");
            exit(1);
        }
    }
    tempdir = getenv("TMP");
    if (tempdir == NULL)
        tempdir = "/tmp";

    if (single_post_limit < 0) {
        fprintf(stderr, "Invalid value for single_post_limit: %d\n",
                single_post_limit);
        exit(1);
    }

    if (document_root) {
        temp = normalize_path(document_root);
        free(document_root);
        document_root = temp;
    }

    if (error_log_name) {
        temp = normalize_path(error_log_name);
        free(error_log_name);
        error_log_name = temp;
    }

    if (access_log_name) {
        temp = normalize_path(access_log_name);
        free(access_log_name);
        access_log_name = temp;
    }

    if (cgi_log_name) {
        temp = normalize_path(cgi_log_name);
        free(cgi_log_name);
        cgi_log_name = temp;
    }

    if (dirmaker) {
        temp = normalize_path(dirmaker);
        free(dirmaker);
        dirmaker = temp;
    }

#if 0
    if (mime_types) {
        temp = normalize_path(mime_types);
        free(mime_types);
        mime_types = temp;
    }
#endif
}
首先打开boa.conf文件,yyin被赋值。然后就可以调用yyparse()进行解析了。
关于flex和bison学习,推荐oreilly的flex&bison。

现在把bison和flex部分研究一下吧

boa_grammar.y

%{
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/* #include "boa.h" */
#include "parse.h"
# yyerror的实现在boa_lexer.l里
int yyerror(char * msg);

/* yydebug = 1; */

#ifdef DEBUG
#define DBG(x) x
#else
#define DBG(x)
#endif
# 之后可以看到arg1hold用于临时保存TOKEN的参数内容,mime_type也是临时用于存储mime的名。
char *arg1hold;
char mime_type[256];            /* global to inherit */

%}

%union {
    char *	sval;
    int		ival;
    struct ccommand * cval;
};

/* boa.conf tokens */
%token <cval> STMT_NO_ARGS STMT_ONE_ARG STMT_TWO_ARGS

/* mime.type tokens */
%token <sval> MIMETYPE
%token <sval> STRING
%token <ival> INTEGER

%start ConfigFiles

%%

ConfigFiles:		BoaConfigStmts MimeTypeStmts
	;

BoaConfigStmts:		BoaConfigStmts BoaConfigStmt
	|		/* empty */
	;

BoaConfigStmt:		
			StmtNoArgs
	|		StmtOneArg
	|		StmtTwoArgs
	;

StmtNoArgs:		STMT_NO_ARGS
		{ if ($1->action) {
			DBG(printf("StmtNoArgs: %s\n",$1->name);)
			$1->action(NULL,NULL,$1->object);
		 }
		}
	;

StmtOneArg:		STMT_ONE_ARG STRING
		{ if ($1->action) {
			DBG(printf("StmtOneArg: %s %s\n",$1->name,$2);)
			$1->action($2,NULL,$1->object);
		 }
		}
	;

StmtTwoArgs:		STMT_TWO_ARGS STRING
		{ arg1hold = strdup($2); }
			 STRING
		{ if ($1->action) {
			DBG(printf("StmtTwoArgs: '%s' '%s' '%s'\n",
			            $1->name,arg1hold,$4);)
			$1->action($4,arg1hold,$1->object);
		  }
		  free(arg1hold);
		}
	;


/******************* mime.types **********************/

MimeTypeStmts:		MimeTypeStmts MimeTypeStmt
	|		/* empty */
	;

MimeTypeStmt:		MIMETYPE 
		{ strcpy(mime_type, $1); }
			ExtensionList
	;

ExtensionList:		ExtensionList Extension
	|		/* empty */
	;

Extension:		STRING
		{ add_mime_type($1, mime_type); }
	;

%%

先说说这个宏,DBG(x)
#ifdef DEBUG
#define DBG(x) x
#else
#define DBG(x)
#endif
学了一招!
up主之前用#define DEBUG,然后每一处需要调试时调用的函数前后加上#ifdef DEBUG ......  #endif的方法来达到同样效果,太累。
这里只要在需要调试的函数前后加上DBG()就行了。

将boa.conf文件和mime.types文件的语法规则写在一起,简单的先后关系:ConfigFiles: BoaConfigStmts MimeTypeStmts;

BoaConfigStmts
boa config stmt分三种,无参的,一个参数的,两个参数的。
实际的配置如下:
AccessLog   /var/log/boa/access_log
Alias   /doc   /usr/doc

词法分析得到一条stmt后,调用action函数进行操作。
每一个stmt是struct ccommand *类型,声明如下
struct ccommand{
    char *name;
    int type;
    void (*action) (char *, char *, void *);
    void *object;
};
所有的struct ccommand以数组方式存储
struct ccommand clist[] = {
    {"Port", S1A, c_set_int, &server_port},  
    ......
    {"CGIPath", S1A, c_set_string, &cgi_path},
    {"MaxConnections", S1A, c_set_int, &max_connections},
};
词法分析yylex每次找到一个stmt就根据名字从这个数组中查找对应项返回给yyparse,再从yyparse中调用action,完成各自的初始化。

MimeTypeStmts
mimetype的形式类似于 MIMETYPE STRING STRING STRING...
每次解析到一个MIMETYPE,先暂时存储于mime_type字符数组。解析STRING时,就调用add_mime_type($1, mime_type);
这个函数的作用就是将type-extension添加到一个哈系表中,type为key,可以有很多extension,索引方式存储。

语法分析规则boa_grammar.y就到这儿,词法分析规则boa_lexer.l就不说了。
大体功能和yywrap()、yyerror()在前一篇已经提到,具体的词法规则就太细节了。


好了,回到我们的read_config_files(),大家不会忘了这个函数还没完呢吧?^ ^
其实也没什么了,把一些路径转化为绝对路径,host_name什么的验证一下,也就完了。
最后有个#if 0  ......   #endif
我是第一次到见这个用法,查了一下就是相当于多行注释。有的文章推荐这样用。


好了,up主累了,看会儿动画去,下次更新依然不定期。。。 ^ ^
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值