动态的去掉源代码中的条件编译宏

源代码中有很多的条件宏代码块,在代码发布到客户时,需要根据客户的配置动态去掉未定义的宏代码块,保留已经定义的宏代码块。


源代码中如果有“宏配置文件” 中没有出现过的条件编译宏,则必需保留!


以下代码使用栈结构完成,遇到#ifdef 或者 #ifndef就入栈,遇到#endif 就出栈。


/**********************************************************************
 * strip_macro.c
 *
 * Wang Dongquan <wdq347@163.com>
 * Time-stamp: <>
 * Description:
 *
 * strip undefined macro parts according to config_macro file
 *
 * gcc - O2 - W - Wall strip_macro.c - o strip_macro
 *
 * 1. config_macro file format is line by line which likes 'variable = value',
 * value must be 'y' or 'n', and 'y' means defined, 'n' means undefined
 *
 * 2. src_file contrains macro parts
 *
 * 3. dst_file is generated by stripping undefined macro parts of src_file
 ***********************************************************************/


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

#define MAX_STACK_LAYER 128
#define MAX_LINE_BUFFER 2048
#define MAX_MACRO_NUMBER 256
#define MAX_MACRO_CHAR 128

/* macro conf */
struct macro_def {
    char macro[MAX_MACRO_CHAR];
    unsigned char len;
    unsigned char defined;
    unsigned short value;
};

enum {
    MACRO_PUSH = 0,
    MACRO_POP,
    MACRO_ELSE,
    MACRO_SIMPLE, 
};

enum {
    MACRO_UNDEFINED = 0,
    MACRO_DEFINED,
    MACRO_IGNORED, 
};

static inline char *pass_space(char *line, int len)
{
    int i = 0;
    for (i = 0;i < len;i++) {
        if (line[i] != ' '
            && line[i] != '\t'
            && line[i] != '\n'
            && line[i] != '\r'
            && line[i] != '\0')
            break;
    }
    return line + i;
}

static inline char *pass_word(char *line, int len)
{
    int i = 0;

    for (i = 0;i < len;i++) {
        if (line[i] == ' '
            || line[i] == '\t'
            || line[i] == '\n'
            || line[i] == '\r'
            || line[i] == '\0')
            break;
    }
    return line + i;
}

static int line_word(char *line, int len, char **word, int *word_len)
{
    char *p = line;

    *word_len = 0;
    p = pass_space(line, len);
    if (p > line + len)
        return -1;

    *word = p;
    p = pass_word(p, line + len - p);
    if (p > line + len)
        return -1;
    *word_len = p - *word;
    return 0;
}

static void usage()
{
    printf("strip_macro config_file src_file dst_file\n");
    printf("config_file: file format is line by line which likes 'variable = value'\n");
    printf("src_file   : source file including variable macros defined or undefined in config_file\n");
    printf("dst_file   : output file stripped according to config_file\n");
}

static int config_macro(FILE *conf, struct macro_def **macro)
{
    char *p = NULL;
    char line[MAX_LINE_BUFFER];
    int i = 0, len = 0;

    char *v = NULL, *vv = NULL;
    int v_len = 0, vv_len = 0;

    while (fgets(line, MAX_LINE_BUFFER, conf)) {
        len = strlen(line);
        p = pass_space(line, len);
        if (p >= line + len)
            continue;
        if (*p == '#')
            continue;
        p = strchr(line, '=');
        if (p == NULL)
            continue;
        *p = '\0';
        line_word(line, len, &v, &v_len);
        line_word(p + 1, line + len - p - 1, &vv, &vv_len);
        if (v_len > 0 && vv_len > 0 && v && vv) {
            macro[i] = (struct macro_def *)calloc(1, sizeof(struct macro_def));
            if (macro[i] == NULL)
                return -1;
            strncpy(macro[i]->macro, v, v_len);
            macro[i]->len = v_len;
            if (*vv == 'y')
                macro[i]->defined = MACRO_DEFINED;
            else
                macro[i]->defined = MACRO_UNDEFINED;
            if (++i > MAX_MACRO_NUMBER)
                return -1;
        }
    }
    return 0;
}

static int judge_macro_var(char *var, int var_len, struct macro_def **macro)
{
    int defined = MACRO_IGNORED, i = 0;

    for (i = 0;macro[i] != NULL;i++) {
        if (var_len == macro[i]->len && memcmp(var, macro[i]->macro, var_len) == 0) {
            defined = macro[i]->defined;
            break;
        }
    }

    return defined;
}

static int judge_macro(char *def, int def_len, char *var, int var_len, struct macro_def **macro, int *defined)
{
    int ret = MACRO_SIMPLE;

    if ((def_len == sizeof("#ifdef") - 1)
        && memcmp(def, "#ifdef", sizeof("#ifdef") - 1) == 0) {
        *defined = judge_macro_var(var, var_len, macro);
        ret = MACRO_PUSH;
    }
    else if ((def_len == sizeof("#ifndef") - 1)
        && memcmp(def, "#ifndef", sizeof("#ifndef") - 1) == 0) {
        *defined = judge_macro_var(var, var_len, macro);
        if (*defined != MACRO_IGNORED)
            *defined = ((*defined == MACRO_DEFINED) ? MACRO_UNDEFINED : MACRO_DEFINED);
        ret = MACRO_PUSH;
    }
    else if ((def_len == sizeof("#endif") - 1)
        && memcmp(def, "#endif", sizeof("#endif") - 1) == 0) {
        ret = MACRO_POP;
    }
    else if ((def_len == sizeof("#else") - 1)
        && memcmp(def, "#else", sizeof("#else") - 1) == 0) {
        ret = MACRO_ELSE;
    }

    return ret;
}


static void judge_printf_line(FILE *dst, char *line, char *stack, int curr_stack, int simple_string)
{
    int i = 0;

    if (simple_string == 1
        || stack[curr_stack] == MACRO_IGNORED) {
        for (i = 1;i <= curr_stack;i++) {
            if (stack[i] == MACRO_UNDEFINED)
                break;
        }
        if (i > curr_stack)
            fprintf(dst, "%s", line);
    }
}


static int strip_macro(struct macro_def **macro, FILE *src, FILE *dst)
{
    int ret = 0, defined = MACRO_IGNORED;

    char line[MAX_LINE_BUFFER];
    int len = 0;

    char *def = NULL, *var = NULL;
    int def_len = 0, var_len = 0;

    char stack[MAX_STACK_LAYER];
    int curr_stack = 0;

    while (fgets(line, MAX_LINE_BUFFER, src)) {
        len = strlen(line);
        if (line_word(line, len, &def, &def_len))
            return -1;
        if (line_word(def + def_len, line + len - def - def_len, &var, &var_len))
            return -1;

        ret = judge_macro(def, def_len, var, var_len, macro, &defined);
        switch (ret) {
        case MACRO_PUSH:
            if (curr_stack >= MAX_STACK_LAYER - 1)
                return -1;
            stack[++curr_stack] = defined;
            judge_printf_line(dst, line, stack, curr_stack, 0);
            break;

        case MACRO_POP:
            judge_printf_line(dst, line, stack, curr_stack, 0);
            curr_stack--;
            break;

        case MACRO_ELSE:
            judge_printf_line(dst, line, stack, curr_stack, 0);
            if (stack[curr_stack] != MACRO_IGNORED)
                stack[curr_stack] =
                    ((stack[curr_stack] == MACRO_DEFINED) ? MACRO_UNDEFINED : MACRO_DEFINED);
            break;

        default:
            judge_printf_line(dst, line, stack, curr_stack, 1);
            break;
        }
    }

    return 0;
}


int main(int argc, char *argv[])
{
    int ret = -1;
    struct macro_def **macro = NULL;
    FILE *conf = NULL, *src = NULL, *dst = NULL;

    if (argc != 4) {
        usage();
        return -1;
    }

    conf = fopen(argv[1], "r");
    if (conf == NULL)
        goto end;

    src = fopen(argv[2], "r");
    if (src == NULL)
        goto end;

    dst = fopen(argv[3], "w+");
    if (dst == NULL)
        goto end;

    macro = (struct macro_def **)calloc(MAX_MACRO_NUMBER, sizeof(struct macro_def *));
    if (macro == NULL)
        goto end;

    /* get all config macros */
    ret = config_macro(conf, macro);
    if (ret != 0) {
        ret = -1;
        goto end;
    }

    ret = strip_macro(macro, src, dst);
    
end:
    if (conf)
        fclose(conf);
    if (src)
        fclose(src);
    if (dst)
        fclose(dst);

    if (macro) {
        int i = 0;
        for (i = 0;i < MAX_MACRO_NUMBER;i++) {
            if (macro[i])
                free(macro[i]);
            else
                break;
        }
        free(macro);
    }
    return ret;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值