您的位置:首页 > 编程语言 > C语言/C++

用C语言实现解析简单配置文件的小工具

2012-12-18 14:47 1076 查看
本文介绍作者写的一个小工具,简单的代码中包含了C语言对字符串的处理技巧,对文本文件的简单解析,二进制文件的数据复制的方法,以及格式化输出文本文件的示例。

工具的输入是如下内容的配置文件:

;资源管理器配置脚本

;以行为单位,每行不能超过255个字符
;空行和以;开头的注释行会被忽略掉
;每行都关联一个资源文件,资源序号从0开始,依次递增

.\img\img128x128.bin
.\snd\start.wav
.\img\sheis1.bin
.\snd\balloon.wav
.\img\sheis2.bin

工具的源代码贴在这里:

#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

/* 定义相关文件名 */
#define CONFIG_FILE_NAME        ("config.txt")
#define RESPAK_FILE_NAME        ("resmm.bin")
#define ADDRS_C_FILE_NAME       ("resmm_addrs.c")

/* 定义配置行最大的字符数 */
#define LINE_CHARS      (255)
/* 定义复制文件数据时的缓冲区大小 */
#define BUF_SIZE        (8 * 1024)

/* 从配置行提取文件名 */
static char* extract_file_name(const char* line, char* file_name)
{
    /* 过滤配置行左边的空格符 */
    while(isspace(*line++)){};
    line--;
    /* 忽略空行和注释行 */
    if((*line == '\0') || (*line == ';'))
        return NULL;

    /* 提取文件名,并去掉右边的空格符 */
    strcpy(file_name, line);
    {
        char* p = file_name + strlen(file_name) - 1;
        while(isspace(*p--)){};
        p++;
        p++;
        *p = '\0';
    }

    return file_name;
}

/* 扫描有效文件数 */
static int scan_file_count(FILE* cf)
{
    char line[LINE_CHARS + 1];
    char file_name[LINE_CHARS + 1];
    int count = 0;

    while(!feof(cf))
    {
        fgets(line, LINE_CHARS, cf);
        if(extract_file_name(line, file_name) != NULL)
            count++;
    }

    return count;
}

/* 复制文件数据 */
static size_t copy_file_datas(FILE* pf, FILE* rf)
{
    unsigned char buf[BUF_SIZE];
    size_t total = 0;
    size_t len;

    do{
        len = fread(buf, sizeof(unsigned char), BUF_SIZE, rf);
        fwrite(buf, sizeof(unsigned char), len, pf);
        total += len;
    }while(len == BUF_SIZE);

    return total;
}

/* 主函数 */
int main(int argc, char* argv[])
{
    FILE* cf;
    FILE* pf;
    FILE* rf;
    int count;
    size_t* lens;
    size_t len;
    unsigned int addr;
    char line[LINE_CHARS + 1];
    char file_name[LINE_CHARS + 1];
    int i;

    /* 打开配置文件,并扫描有效文件数 */
    if((cf = fopen(CONFIG_FILE_NAME, "rt")) == NULL)
    {
        printf("Can\'t open %s!\n", CONFIG_FILE_NAME);
        return -1;
    }
    count = scan_file_count(cf);
    fseek(cf, 0L, SEEK_SET);

    /* 打开资源包文件 */
    if((pf = fopen(RESPAK_FILE_NAME, "wb")) == NULL)
    {
        printf("Can\'t create %s!\n", RESPAK_FILE_NAME);
        fclose(cf);
        return -1;
    }

    /* 复制打包资源文件,并统计其大小 */
    if((lens = (size_t*)malloc(sizeof(size_t) * count)) == NULL)
    {
        printf("No enough memory!\n");
        fclose(pf);
        fclose(cf);
        return -1;
    }
    i = 0;
    while(!feof(cf))
    {
        fgets(line, LINE_CHARS, cf);
        if(extract_file_name(line, file_name) != NULL)
        {
            if((rf = fopen(file_name, "rb")) == NULL)
            {
                printf("Can\'t open %s!\n", file_name);
                fclose(pf);
                fclose(cf);
                return -1;
            }
            if((len = copy_file_datas(pf, rf)) == 0)
            {
                printf("File %s is empty!\n", file_name);
                fclose(pf);
                fclose(cf);
                return -1;
            }
            lens[i++] = len;
            fclose(rf);
        }
    }
    fclose(pf);
    fclose(cf);

    /* 打开地址描述的C语言源文件 */
    if((cf = fopen(ADDRS_C_FILE_NAME, "wt")) == NULL)
    {
        printf("Can\'t open %s!\n", ADDRS_C_FILE_NAME);
        return -1;
    }

    /* 把各个资源的地址和长度信息写入C语言数组 */
    fprintf(cf, "#define RES_COUNT\t(%d)\n\n", count);
    fprintf(cf, "static const INT32U addrs[RES_COUNT] = \n{\n");
    addr = 0;
    for(i = 0; i < count; i++)
    {
        fprintf(cf, "\t\t0x%08x,\n", addr);
        addr += lens[i];
    }
    fprintf(cf, "};\n\n");
    fprintf(cf, "static const INT32U lens[RES_COUNT] = \n{\n");
    for(i = 0; i < count; i++)
        fprintf(cf, "\t\t0x%08x,\n", lens[i]);
    fprintf(cf, "};");

    fclose(cf);
    free(lens);
    return 0;
}
格式化输出的文本文件是这样的:

#define RES_COUNT	(5)

static const INT32U addrs[RES_COUNT] = 
{
		0x00000000,
		0x00008000,
		0x0000889a,
		0x0001089a,
		0x0001219a,
};

static const INT32U lens[RES_COUNT] = 
{
		0x00008000,
		0x0000089a,
		0x00008000,
		0x00001900,
		0x00008000,
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: