显示字符流的16进制值,C语言实现,跨平台

        跨平台显示字符流的16进制值,C语言实现,

        以下代码编译后,将程序路径加入环境变量即可使用 。兼容windows、linux、macos平台。

/***********************************************************************************************************************************************************************
** @file:       hex.c
** @author:     huixuan.li
** @date:       2024-05-27 14:23:49
** @brief:      展示将字节流的16进制值
***********************************************************************************************************************************************************************/
#if defined(_WIN32) || defined(_WIN64)
#include <fcntl.h>
#include <io.h>
#elif defined(__linux__)
#elif defined(__APPLE__)
#else
# error Your operating system is not supported!
#endif
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define BUFFER_SIZE 1024

/* 返回码定义 */
static enum{ SUCCESS, ARGS_ERROR, HANDLE_ERROR } EXITCODE;

/* 错误信息与帮助信息 */
static char ARG_ERROR_INFO[] =
"ERROR! Couldn't recognize argument %s, please use option \"--help\" for instructions\n";
static char HELP_INFO[] =
"The program can read a file or input stream and output its hexadecimal value to other file or standrad output, \"-b\" option set the read mode to binary, as follows: \n"
"\t<command> | bytes [-b] [-o <outputfile>]\n"
"\t<inputfile> > bytes [-b] [-o <outputfile>]\n"
"\tbytes <inputfile> [-b] [-o <outputfile>]\n"
"Alternatively, use the bytes command to perform interactive input and output, as shown below:\n"
"\tbytes [-b] [-o <outputfile>]\n";

/* 缓冲区 */
static char OUTPUT_FILE_BUFFER[BUFFER_SIZE];

/* 全局参数 */
static struct mode{
    bool if_binary;
    bool if_stdin_redirect;
    bool if_stdout_redirect;
} mode = { false,false };

static char *input_file_path = NULL;
static char *output_file_path = NULL;
static FILE *input_file_stream;
static FILE *output_file_stream;

/* 读取参数并根据参数修改全局参数 */
static void analyze_arguments(int argc, char **argv);

/* 根据全局参数设置输入流 */
static void set_input_stream(void);

/* 根据全局参数设置输出流 */
static void set_output_stream(void);

/* 进行转化输出 */
static void transform(void);

/* 主函数 */
int main(int argc, char *argv[]){
    analyze_arguments(argc, argv);
    set_input_stream();
    set_output_stream();
    transform();
    exit(EXITCODE = SUCCESS);
}


/* 读取参数并根据参数修改全局参数 */
static void analyze_arguments(int argc, char **argv){
    // 对参数遍历处理
    for (int i = 1;i < argc;i++){
        char *p = argv[i];
        // 若以-开头,则判定为选项
        if (*p == '-'){
            // -b选项
            if (strcmp(p, "-b") == 0){
                mode.if_binary = true;
            }
            // --help选项
            else if (strcmp(p, "--help") == 0){
                fputs(HELP_INFO, stdout);
                exit(EXITCODE = SUCCESS);
            }
            // -o选项
            else if (strcmp(p, "-o") == 0){
                // 若outputfile已存在
                if (output_file_path != NULL){
                    fprintf(stderr, "Error! An outputfile %s is already given!\n", output_file_path);
                    exit(EXITCODE = ARGS_ERROR);
                }
                // 若为参数末尾
                if (i == argc - 1){
                    fputs("Error! Couldn't find outputfile in arguments!\n", stderr);
                    exit(EXITCODE = ARGS_ERROR);
                }
                output_file_path = argv[++i];
            }
            // 未知选项
            else{
                fprintf(stderr, ARG_ERROR_INFO, p);
                exit(EXITCODE = ARGS_ERROR);
            }
        }
        // 若参数不以-开头,则判定为输入文件名
        else{
            // 若存在多个文件名则报错
            if (input_file_path != NULL){
                fprintf(stderr, "Error! Multiple input_file set: %s and %s\n", input_file_path, p);
                exit(EXITCODE = ARGS_ERROR);
            }
            input_file_path = p;
        }
    }

    // 检测标准输入输出是否被重定向
    struct stat stat_info;
    // 获取文件描述符的状态信息
    if (fstat(fileno(stdin), &stat_info) == -1){
        fputs("Error! Couldn't get stdin statement!\n", stderr);
        exit(EXITCODE = ARGS_ERROR);
    }
    mode.if_stdin_redirect = !S_ISCHR(stat_info.st_mode);
    // 获取文件描述符的状态信息
    if (fstat(fileno(stdout), &stat_info) == -1){
        fputs("Error! Couldn't get stdin statement!\n", stderr);
        exit(EXITCODE = ARGS_ERROR);
    }
    mode.if_stdout_redirect = !S_ISCHR(stat_info.st_mode);
}

/* 根据全局参数设置输入流 */
static void set_input_stream(void){
    // 二进制模式下
    if (mode.if_binary){
        // 指定输入文件时
        if (input_file_path != NULL){
            input_file_stream = fopen(input_file_path, "rb");
            if (input_file_stream == NULL){
                fprintf(stderr, "Error occur in open input_file %s!\n", input_file_path);
                exit(EXITCODE = HANDLE_ERROR);
            }
        }
        // 不指定输入文件时
        else{
            // 以二进制打开输入流
        #if defined(_WIN32) || defined(_WIN64)
            _setmode(_fileno(stdin), _O_BINARY);
        #else
            freopen(NULL, "rb", stdin);
        #endif
            input_file_stream = stdin;
        }
    }
    //非二进制模式下
    else{
        // 指定输入文件时
        if (input_file_path != NULL){
            input_file_stream = fopen(input_file_path, "r");
            if (input_file_stream == NULL){
                fprintf(stderr, "Error occur in open input_file %s!\n", input_file_path);
                exit(EXITCODE = HANDLE_ERROR);
            }
        }
        // 不指定输入文件时
        else{
            input_file_stream = stdin;
        }
    }
}

/* 根据全局参数设置输出流 */
static void set_output_stream(void){
    // 指定输出文件时
    if (output_file_path != NULL){
        output_file_stream = fopen(output_file_path, "w");
        if (output_file_stream == NULL){
            fprintf(stderr, "Error occur in open output_file %s, please check whether the path exists!\n", output_file_path);
            exit(EXITCODE = HANDLE_ERROR);
        }
    }
    // 不指定输出文件时
    else{
        output_file_stream = stdout;
    }

    // 重定向标准输入或指定输入文件时设置缓冲区(非交互模式时设置缓冲区)
    if (mode.if_stdin_redirect || input_file_path != NULL){
        if (setvbuf(output_file_stream, OUTPUT_FILE_BUFFER, _IOFBF, BUFFER_SIZE)){
            fputs("ERROR! Couldn't set buffer for output stream!\n", stderr);
            fclose(output_file_stream);
            exit(EXITCODE = HANDLE_ERROR);
        }
    }
}

/* 进行转化输出 */
static void transform(void){
    // 二进制模式
    if (mode.if_binary){
        bool line_begin = true;
        char c;
        // 交互模式
        if (input_file_path == NULL && !mode.if_stdin_redirect){
            while (true){
                c = fgetc(input_file_stream);

                // 若出现错误
                if (ferror(input_file_stream)){
                    fclose(input_file_stream);
                    fclose(output_file_stream);
                    fputs("Unknown error occur in reading!\n", stderr);
                    exit(EXITCODE = HANDLE_ERROR);
                }
                // 若超出末尾
                if (feof(input_file_stream)){
                    fclose(input_file_stream);
                    fclose(output_file_stream);
                    return;
                }

            #if defined(_WIN32)|| defined(_WIN64)||defined(__linux__)
                if (line_begin){
                    if (c == '\n'){
                        fprintf(output_file_stream, "0x%02hhX\n", c);
                        line_begin = true;
                    } else{
                        fprintf(output_file_stream, "0x%02hhX", c);
                        line_begin = false;
                    }
                } else{
                    if (c == '\n'){
                        fprintf(output_file_stream, "\t0x%02hhX\n", c);
                        line_begin = true;
                    } else{
                        fprintf(output_file_stream, "\t0x%02hhX", c);
                    }
                }
            #elif defined(__APPLE__)
                if (line_begin){
                    if (c == '\n' || c == '\r'){
                        fprintf(output_file_stream, "0x%02hhX\n", c);
                        line_begin = true;
                    } else{
                        fprintf(output_file_stream, "0x%02hhX", c);
                        line_begin = false;
                    }
                } else{
                    if (c == '\n' || c == '\r'){
                        fprintf(output_file_stream, "\t0x%02hhX\n", c);
                        line_begin = true;
                    } else{
                        fprintf(output_file_stream, "\t0x%02hhX", c);
                    }
                }
            # endif
            }
        }
        // 非交互模式
        else{
            while (true){
                c = fgetc(input_file_stream);

                // 若出现错误
                if (ferror(input_file_stream)){
                    fclose(input_file_stream);
                    fclose(output_file_stream);
                    fputs("Unknown error occur in reading!\n", stderr);
                    exit(EXITCODE = HANDLE_ERROR);
                }
                // 若超出末尾
                if (feof(input_file_stream)){
                #if defined(__linux__)
                    // linux下若在控制台打印额外打印换行符
                    if (output_file_path == NULL && !mode.if_stdout_redirect){
                        fputs("\n", stderr);
                    }
                #endif
                    fclose(input_file_stream);
                    fclose(output_file_stream);
                    return;
                }

                if (line_begin){
                    fprintf(output_file_stream, "0x%02hhX", c);
                    line_begin = false;
                } else{
                    fprintf(output_file_stream, "\t0x%02hhX", c);
                }
            }
        }

    }
    // 非二进制模式
    else{
        char c;
        bool line_begin = true;

        while (true){
            c = fgetc(input_file_stream);
            // 若出现异常
            if (ferror(input_file_stream)){
                fputs("Unknown error occur in reading!\n", stderr);
                fclose(input_file_stream);
                fclose(output_file_stream);
                exit(EXITCODE = HANDLE_ERROR);
            }

            // 若超出末尾
            if (feof(input_file_stream)){
            #if defined(__linux__)
                // 若在控制台展示,linux额外打印换行符
                if (output_file_path == NULL && !mode.if_stdout_redirect){
                    fputs("\n", stderr);
                }
            #endif
                fclose(input_file_stream);
                fclose(output_file_stream);
                return;
            }

            if (line_begin){
                if (c == '\n'){
                    fprintf(output_file_stream, "0x%02hhX\n", c);
                    line_begin = true;
                } else{
                    fprintf(output_file_stream, "0x%02hhX", c);
                    line_begin = false;
                }
            } else{
                if (c == '\n'){
                    fprintf(output_file_stream, "\t0x%02hhX\n", c);
                    line_begin = true;
                } else{
                    fprintf(output_file_stream, "\t0x%02hhX", c);
                }
            }
        }
    }
}

使用方式示例:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值