我们继续看meta_expand余下的代码。251~255行处理“"/'”这样的元符号,其实就是字符串引用符号。257~260行则是处理普通字符及仅有“=”的情况。函数split_line也在同一文件中。
Insmod——split_line函数
47 /*
48 * Split into words delimited by whitespace,
49 * handle remaining quotes though...
50 * If strip_quotes != 0 then strip one level of quotes from the line.
51 */
52 static void split_line(GLOB_LIST *g, char *line, int strip_quotes)
53 {
54 int len;
55 char *d;
56 char *e;
57 char *p;
58 char tmpline[PATH_MAX];
59
60 for (p = line; *p; p = e) {
61 /* Skip leading whitespace */
62 while (*p && isspace(*p))
63 ++p;
64
65 /* find end of word */
66 d = tmpline;
67 for (e = p; *e && !(isspace(*e)); ++e) {
68 char match;
69
70 /* Quote handling */
71 switch (*e) {
72 case '//':
73 if (!strip_quotes)
74 *d++ = *e;
75 break;
76
77 case '"':
78 case '/'':
79 match = *e;
80 if (!strip_quotes)
81 *d++ = *e;
82 for (++e; *e && *e != match; ++e) {
83 *d++ = *e;
84 if (*e == '//' && *(e + 1) == match)
85 *d++ = *++e;
86 }
87 if (!strip_quotes)
88 *d++ = *e;
89 break;
90
91 default:
92 *d++ = *e;
93 break;
94 }
95 }
96
97 if ((len = (int)(d - tmpline)) > 0) {
98 char *str = xmalloc(len + 1);
99 strncpy(str, tmpline, len);
100 str[len] = '/0';
101 g->pathv = (char **)xrealloc(g->pathv,
102 (g->pathc + 2) * sizeof(char *));
103 g->pathv[g->pathc++] = str;
104 }
105 }
106
107 if (g->pathc)
108 g->pathv[g->pathc] = NULL;
109 }
在“=”的情况下,没有特别的处理,只是将字符拷入缓存,注意84、85行处理了转义字符。267~275行是对Shell的元符号的处理,他们是:[]~?*,如果允许使用Shell变量,还包括$。如果处理不了,继续往下走,277~281行又是对“=”进行处理。。如果不止是“=”,而且glob也无法处理。那么就只好请echo帮忙了。297~310行构建echo命令行。311~313行则通过管道执行echo命令。320~328行则是从管道获取输出。在330~335行对这些输出用split_line分割参数。
回到do_read函数,1303~1311行,将解析好的路径信息存到modpath中。到此Example.module.conf的第6 行处理完毕。然后,进入1325的for循环,不过因为one_err=0。所以,实际上没有执行。函数gen_file_conf也在config.c中。
Insmod——gen_file_conf函数
423 /* Read a config option for a generated filename */
424 static int gen_file_conf(struct gen_files *gf, int assgn, const char *parm, const char *arg)
425 {
426
427 int l = strlen(gf->base);
428 if (assgn &&
429 strncmp(parm, gf->base, l) == 0 &&
430 strcmp(parm+l, "file") == 0 &&
431 !gf->name) {
432 gf->name = xstrdup(arg);
433 return(0);
434 }
435 return(1);
436 }
显然,这是察看形如x=xxx这样的式子是否定义了gen_file的路径。one_err在assign为1,parm不等于insmod_opt,path,persistdir时,为1。将进入gen_file_conf函数。
接着看第8行。insmod调用do_read时,all设为1。因此,进入1142行的else if块。decode_list在同一文件中。arg此时为” scsi_hostadapter”。
Insmod——decode_list函数
323 static void decode_list(int *n, OPT_LIST **list, char *arg, int adding,
324 char *version, int opts)
325 {
326 GLOB_LIST *pg;
327 GLOB_LIST *prevlist = NULL;
328 int i, autoclean = 1;
329 int where = *n;
330 char *arg2 = next_word(arg);
331
332 if (opts && !strcmp (arg, "-k")) {
333 if (!*arg2)
334 error("Missing module argument after -k/n");
335 arg = arg2;
336 arg2 = next_word(arg);
337 autoclean = 0;
338 }
339
340 for (i = 0; i < *n; ++i) {
341 if (strcmp((*list)[i].name, arg) == 0) {
342 if (adding)
343 prevlist = (*list)[i].opts;
344 else
345 free((*list)[i].opts);
346 (*list)[i].opts = NULL;
347 where = i;
348 break;
349 }
350 }
351 if (where == *n) {
352 (*list) = (OPT_LIST *)xrealloc((*list),
353 (*n + 2) * sizeof(OPT_LIST));
354 (*list)[*n].name = xstrdup(arg);
355 (*list)[*n].autoclean = autoclean;
356 *n += 1;
357 memset(&(*list)[*n], 0, sizeof(OPT_LIST));
358 } else if (!autoclean)
359 (*list)[where].autoclean = 0;
360 pg = (GLOB_LIST *)xmalloc(sizeof(GLOB_LIST));
361 meta_expand(arg2, pg, NULL, version, ME_ALL);
362 (*list)[where].opts = addlist(prevlist, pg);
363 }
有了上面代码的基础,这段代码相当简单。首先处理-k选项,然后根据是否设定了adding,添加或覆盖对应的项。至此,Example.module.conf的第8行也已处理完。第9、10、11、13行的处理也是类似的,此处就略过了。第22行中`kernelversion`的处理我们也已经看过了。因此,直接跳到第28行。经过类似的处理后,parm = if,arg = -f。进入do_read第950行的if块中,这时level=0。Arg=-f是要测试文件的存在,因此,在973行获取文件路径后,在974行通过meta_expand对可能存在的元符号进行处理,这个我们已经看过了。然后通过access函数测试文件的存在与否。这里假定文件存在。注意此时level=1,这个if块下面的代码处理比较操作符及取反操作符,比较简单,不赘述了。
接下来处理第29行,if块里的语句。注意在1063行,因为此时state[level]=1(我们假设文件存在),因此跳过了这个if块。同时注意在646行,函数第一次运行时将state[0]设为0。直到1082行,同样首先使用meta_expand对include文件的路径进行元字符处理。注意,如果路径中不包含元字符,也没有分行,meta_expand,将不做任何处理,g.pathc将为0。然后这个路径将作为conf_file传给do_read做递归调用,然后经过同样漫长的过程,最终返回来。
处理endif的语句在897~906行,非常简单。好了,我们顺便看看910~945行,else和elseif的处理。else的处理很简单,将state[level]取反即可,state[level]自会照顾else块里代码的解析。elseif就要花点心思,首先如果elseif之前的if条件为真,那么为了实现3个以上的分支,将state[level]设为2,这样可以通过927行和1063行的if检测。相反,如果elseif之前的条件测试均没通过,那么就将parm置为if,用处理if的语句来处理。这个实现,可说相当的巧妙。
Example.module.conf的最后一行,看似不同,但实际上还是通过decode_list来处理。所以,就不看了。