使用C对TOML文件的解析

@TOC
TOML是前GitHub CEO, Tom Preston-Werner,于2013年创建的语言,其目标是成为一个小规模的易于使用的语义化配置文件格式。TOML被设计为可以无二义性的转换为一个哈希表(Hash table)。

toml书写语法

参考这里

解析toml文件

这里使用tomlc99

#下载库
git clone https://github.com/cktan/tomlc99.git
cd tomlc99
#创建test.c文件
vi test.c

将以下代码复制到test.c文件中

#ifdef NDEBUG
#undef NDEBUG
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdint.h>
#include <assert.h>
#include "toml.h"

typedef struct node_t node_t;
struct node_t {
    const char*   key;
    toml_table_t* tab;
};

node_t stack[20];
int stacktop = 0;

/*设置输出颜色*/
#define red_color "\E[1;31m"
#define color_suffix "\E[0m"

static void print_array_of_tables(toml_array_t* arr, const char* key);
static void print_array(toml_array_t* arr);

/**
 * @brief 打印表名
 * 
 * @param arrname 数组名或者是表名
 */
static void print_table_title(const char* arrname)
{
    int i;
    printf("%s", arrname ? "[[" : "[");
    /*打印上级*/
    printf(red_color"开始打印上级:"color_suffix);
    for (i = 1; i < stacktop; i++) {
    printf("%s", stack[i].key);
    if (i + 1 < stacktop)
        printf(".");
    }
    /*打印尾部*/
    printf(red_color"打印尾部:"color_suffix);
    if (arrname)
    printf(".%s]]\n", arrname);
    else
    printf("]\n");
}

/**
 * @brief 打印表
 * 
 * @param curtab 
 */
static void print_table(toml_table_t* curtab)
{
    int i;
    const char* key;
    const char* raw;
    toml_array_t* arr;
    toml_table_t* tab;

    /*轮询KEY*/
    for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) {
        /*如果是KV则打印*/
    if (0 != (raw = toml_raw_in(curtab, key))) {
        printf(red_color"如果是KV则打印\n"color_suffix);
        printf("%s = %s\n", key, raw);
        /*如果是表中数组或者KV型数组*/
    } else if (0 != (arr = toml_array_in(curtab, key))) {
        /*[[key]]数组或者KV型数组*/
        if (toml_array_kind(arr) == 't') {
            printf(red_color"如果是[[key]]数组\n"color_suffix);
        print_array_of_tables(arr, key);
        }
        else {
            /*KV型数组*/
            printf(red_color"如果是KV型数组\n"color_suffix);
        printf("%s = [\n", key);/*xx = [ss,sss]*/
        print_array(arr);
        printf("    ]\n");
        }
    } else if (0 != (tab = toml_table_in(curtab, key))) {
        /*如果是[tab.tab]嵌套则分解*/
        printf(red_color"如果是[tab.tab]嵌套则分解打印\n"color_suffix);
        stack[stacktop].key = key;
        stack[stacktop].tab = tab;
        stacktop++;
        print_table_title(0);
        print_table(tab);
        stacktop--;
    } else {
        abort();
    }
    }
}

/**
 * @brief 打印标表中数组
 * 
 * @param arr 数组指针
 * @param key 数组名
 */
static void print_array_of_tables(toml_array_t* arr, const char* key)
{
    int i;
    toml_table_t* tab;
    printf("\n");
    /*轮询表中数组*/
    printf(red_color"轮询表中数组\n"color_suffix);
    for (i = 0; 0 != (tab = toml_table_at(arr, i)); i++) {
    print_table_title(key);//[[key]]
    print_table(tab);
    printf("\n");
    }
}

/**
 * @brief 打印数组
 * 
 * @param curarr 
 */
static void print_array(toml_array_t* curarr)
{
    toml_array_t* arr;
    const char* raw;
    toml_table_t* tab;
    int i;

    switch (toml_array_kind(curarr)) {
/*
[
    0: yyy,
    1: xxx,
    2: xxx,
]
*/
    case 'v': 
    for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) {
        printf("  %d: %s,\n", i, raw);
    }
    break;
/*
[
    0:
        0:
            0:xxx
            1:xxx
        1:
            0:xxx
            1:xxx
    1:
        0:
            0:xxx
            1:xxx
        1:
            0:xxx
            1:xxx   
]
*/
    case 'a': 
    for (i = 0; 0 != (arr = toml_array_at(curarr, i)); i++) {
        printf("  %d: \n", i);
        print_array(arr);
    }
    break;
        
    case 't': 
    for (i = 0; 0 != (tab = toml_table_at(curarr, i)); i++) {
        print_table(tab);
    }
    printf("\n");
    break;
    
    case '\0':
    break;

    default:
    abort();
    }
}

/**
 * @brief 解析打印toml文件
 * 
 * @param fp 
 */
static void cat(FILE* fp)
{
    char  errbuf[200];
    
    toml_table_t* tab = toml_parse_file(fp, errbuf, sizeof(errbuf));
    if (!tab) {
    fprintf(stderr, "ERROR: %s\n", errbuf);
    return;
    }

    stack[stacktop].tab = tab;
    stack[stacktop].key = "";
    stacktop++;
    print_table(tab);
    stacktop--;

    toml_free(tab);
}

int main(int argc, const char* argv[])
{
    int i;
    if (argc == 1) {
    cat(stdin);
    } else {
    for (i = 1; i < argc; i++) {
        
        FILE* fp = fopen(argv[i], "r");
        if (!fp) {
        fprintf(stderr, "ERROR: cannot open %s: %s\n",
            argv[i], strerror(errno));
        exit(1);
        }
        cat(fp);
        fclose(fp);
    }
    }
    return 0;
}

准备测试的toml文件,写入到同级目录的sample.toml文件中

[Service]
  Port = 50000
  Timeout = 5000
  ConnectRetries = 10
  Labels = [ 'MQTT_Protocol' ,'MODBUS_Protocol' ]
  StartupMsg = 'mqtt modbus device service started'
  CheckInterval = '10s'

[Clients]
  [Clients.Data]
    Host = 'localhost'
    Port = 48080

  [Clients.Metadata]
    Host = 'localhost'
    Port = 48081

[Device]
  DataTransform = false
  Discovery = false
  MaxCmdOps = 128
  MaxCmdResultLen = 256

[Logging]
  LogLevel = 'DEBUG'

[[DeviceList]]
  Name = 'modbus-01_hangzhou-temperature_device-1'
  Profile = 'modbus_temperature_device_profile_common'
  Description = 'An temperature device'
  [DeviceList.Protocols]
    [DeviceList.Protocols.modbus-rtu]
      Address = '/tmp/slave'
      BaudRate = 9600
      DataBits = 8
      StopBits = 1
      Parity = 'N'
      UnitID = 1
  [[DeviceList.AutoEvents]]
    Resource = 'temperature'
    OnChange = false
    Frequency = '10s'
  [[DeviceList.AutoEvents]]
    Resource = 'humidity'
    OnChange = true
    Frequency = '15000ms'

[[DeviceList]]
  Name = 'modbus-01_hangzhou-temperature_device-2'
  Profile = 'modbus_temperature_device_profile_common'
  Description = 'An temperature device'
  [DeviceList.Protocols]
    [DeviceList.Protocols.modbus-rtu]
      Address = '/tmp/slave'
      BaudRate = 9600
      DataBits = 8
      StopBits = 1
      Parity = 'N'
      UnitID = 2
  [[DeviceList.AutoEvents]]
    Resource = 'temperature'
    OnChange = false
    Frequency = '10s'
  [[DeviceList.AutoEvents]]
    Resource = 'humidity'
    OnChange = true
    Frequency = '15000ms'
gcc toml.c test.c -o test
#增加执行权限
sudo chmod +x test
#运行解析
./test sample.toml

测试输出内容如下

在这里插入图片描述
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容