本次解析src/option_list.h 与 src/option_list.c 两个。

    option_list.h 中包含的代码如下:

    #ifndef OPTION_LIST_H
    #define OPTION_LIST_H
    #include "list.h"
    
    typedef struct{
        char *key;
        char *val;
        int used;
    } kvp;
    
    
    int read_option(char *s, list *options);
    void option_insert(list *l, char *key, char *val);
    char *option_find(list *l, char *key);
    float option_find_float(list *l, char *key, float def);
    float option_find_float_quiet(list *l, char *key, float def);
    void option_unused(list *l);
    
    #endif

    首先,我们分析option.h 中的源码,可以发现了包含list.h 头文件,同时定义结构体kvp,结构体kvp中包含2个char类型指针,1个整形变量。以及定义了6个函数,下面我们分别对这6个函数进行解析,我们将注解写入option_list.c 中,如下:

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include "option_list.h"
    #include "utils.h"
    
    //函数主要功能:
    //    解析[.data,.cfg]每一行信息,主要是为数据配置文件或者神经网络结构数据文件,都是根据这个函数进行读取的;
    list *read_data_cfg(char *filename)
    {
        FILE *file = fopen(filename, "r");
        if(file == 0) file_error(filename);
        char *line;
        int nu = 0;
        list *options = make_list(); // 初始化链表
        while((line=fgetl(file)) != 0){ //fgetl() 读取文件中一行数据,
            ++ nu;
            strip(line); //过滤掉字符数组中的' ' 和 '\t' 以及 '\n' 三种字符
            switch(line[0]){
                case '\0':
                case '#':
                case ';':
                    free(line);
                    break;
                default:
                    // 若该行数组进行插入操作;
                    if(!read_option(line, options)){
                        fprintf(stderr, "Config file error line %d, could parse: %s\n", nu, line);
                        free(line);
                    }
                    break;
            }
        }
        fclose(file);
        return options;
    }
    
    // emmmm,先搁置在这
    metadata get_metadata(char *file)
    {
        metadata m = {0};
        list *options = read_data_cfg(file);
    
        char *name_list = option_find_str(options, "names", 0);
        if(!name_list) name_list = option_find_str(options, "labels", 0);
        if(!name_list) {
            fprintf(stderr, "No names or labels found\n");
        } else {
            m.names = get_labels(name_list);
        }
        m.classes = option_find_int(options, "classes", 2);
        free_list(options);
        return m;
    }
    
    // 读取某一字符数组,若满足条件,插入到链表options中
    int read_option(char *s, list *options)
    {
        size_t i;
        size_t len = strlen(s);
        char *val = 0;
        // 找到字符'='
        for(i = 0; i < len; ++i){
            if(s[i] == '='){
                s[i] = '\0';
                val = s+i+1;
                break;
            }
        }
        // 如果没有找到
        if(i == len-1) return 0;
        char *key = s;
        // 插入操作
        option_insert(options, key, val);
        return 1;
    }
    
    // 插入操作,根据传入key和val 构建新kvp结构体,插入链表l中
    void option_insert(list *l, char *key, char *val)
    {
        kvp *p = malloc(sizeof(kvp));
        p->key = key;
        p->val = val;
        p->used = 0;
        // 链表中保存的数据为 kvp结构体
        list_insert(l, p);
    }
    
    // 链表遍历操作,打印kvp结构体标志位used 为0的数据,
    void option_unused(list *l)
    {
        node *n = l->front;
        while(n){
            kvp *p = (kvp *)n->val;
            if(!p->used){
                fprintf(stderr, "Unused field: '%s = %s'\n", p->key, p->val);
            }
            n = n->next;
        }
    }
    
    // 查找操作,获取指定key的val,没找到返回null.
    char *option_find(list *l, char *key)
    {
        node *n = l->front;
        while(n){
            kvp *p = (kvp *)n->val; // 需要注意结构体node的定义,val是 void类型指针,需要强制转换
            if(strcmp(p->key, key) == 0){
                p->used = 1;
                return p->val;
            }
            n = n->next;
        }
        return 0;
    }
    
    // 查找操作,key为字符数组
    char *option_find_str(list *l, char *key, char *def)
    {
        char *v = option_find(l, key);
        if(v) return v;
        if(def) fprintf(stderr, "%s: Using default '%s'\n", key, def);
        return def;
    }
    
    // 查找操作,key为可显示转换int类型字符数组
    int option_find_int(list *l, char *key, int def)
    {
        char *v = option_find(l, key);
        if(v) return atoi(v);
        fprintf(stderr, "%s: Using default '%d'\n", key, def);
        return def;
    }
    
    // 查找操作
    int option_find_int_quiet(list *l, char *key, int def)
    {
        char *v = option_find(l, key);
        if(v) return atoi(v);
        return def;
    }
    
    // 查找操作
    float option_find_float_quiet(list *l, char *key, float def)
    {
        char *v = option_find(l, key);
        if(v) return atof(v);
        return def;
    }
    
    // 查找操作,key为可显示转换float类型字符数组
    float option_find_float(list *l, char *key, float def)
    {
        char *v = option_find(l, key);
        if(v) return atof(v);
        fprintf(stderr, "%s: Using default '%lf'\n", key, def);
        return def;
    }