漂亮的LinuxC注释转换器--(2.2)目录级联转换最终实现

一.序
前面两篇文章对注释转换以及目录级联转换的算法思想以及实现思路进行了阐述,接下来进行正式实现
二.实现思路图解
这里写图片描述
三.具体实现
1.convert.cpp
根据用户选项,调用正确的函数

//convert.cpp
#include"ConvertComment.h"
#include"BrowseDir.h"

int main(int argc, char *argv[])
{
    //操作选择
    int opt = -1;
    while((opt = getopt(argc, argv, "s::S::r::R::h::H::")) != -1)       //::代表后面可跟字母或者也可不跟
    {
        switch(opt)
        {
            case 'S':
            case 's':
                SeeArgc(argc);
                OneFileCovert(argv[3], argv[2]);
                break;
            case 'R':
            case 'r':
                SeeArgc(argc);
                DirConvert(argv[3], argv[2]);
                break;
            case 'H':
            case 'h':
                help();
                break;
            default:
                cout<<"Usage: ./convert [-Option] src dest"<<endl;
                cout<<"[Option]: S/R/H"<<endl;
                break;
        }
    }
    SeeArgc(argc);
    return 0;
}

2.BrowseDir.h
DirConvert,OneFileConvert,及需要的对目录操作函数的实现

//BrowseDir.h
#ifndef _BROWSEDIR_H
#define _BROWSEDIR_H

#include"utili.h"
#include"ConvertComment.h"

void FileCp(char *des, char *src);              //复制文件
BOOL IsCFile(char *file);                       //判断是否是.c文件
BOOL IsCppFile(char *file);                     //判断是否是.cpp文件
char* GetFileName(char *NamePath);              //只获取文件名or目录名
void PathCat(char *desPath, char *srcPath);     //目录后追加文件名或者路径
int PathCmp(char *dir1, char *dir2);            //(注释转换没用到)比较两个目录是否同级(深度相同)1 0 -1
int PathDep(char *dir);                         //(注释转换没用到)统计目录的深度
void help();                                    //帮助文档
void SeeArgc(const int count);                  //判断参数数量是否正确
void OneFileCovert(char *des, char *src);       //单个文件的注释转换
void DirConvert(char *des, char *src);          //目录的递归转换
void BeginConvert(char *des, char *src);        //进行目录递归转换
size_t GetFileSize(FILE *NamePath);             //获取一个文件的大小

size_t GetFileSize(FILE *NamePath)
{
    size_t size = 0;
    fseek(NamePath, 0, SEEK_END);
    size = ftell(NamePath);
    cout<<"大小为:"<<size<<endl;
    return size;
}
void FileCp(char *des, char *src)
{
    FILE *inputfile = fopen(src, "rb");
    if(NULL == inputfile)
    {
        cout<<"Open src file Fail!"<<endl;
        exit(EXIT_FAILURE);
    }
    size_t SIZE = GetFileSize(inputfile);
    fseek(inputfile, 0, SEEK_SET);          //使文件流指针回到文件开始
    char buf[SIZE+1];

    FILE *outputfile = fopen(des, "wb");
    if(NULL == outputfile)
    {
        cout<<"Open des file Fail!"<<endl;
        exit(EXIT_FAILURE);
    }
    while(!feof(inputfile))
    {
        fread(buf, sizeof(char), SIZE, inputfile);
        fwrite(buf, sizeof(char), SIZE, outputfile);
    }
    fclose(inputfile);
    fclose(outputfile);
}
BOOL IsCFile(char *file)
{
    int len = strlen(file);
    if(file[len-1] == 'c' && file[len-2] == '.')
        return TRUE;
    else
        return FALSE;
}
BOOL IsCppFile(char *file)
{
    int len = strlen(file);
    if(file[len-1] == 'p' && file[len-2] == 'p'
        && file[len-3] == 'c' && file[len-4] == '.')
        return TRUE;
    else
        return FALSE;
}
char* GetFileName(char *NamePath)
{
    if(NULL == NamePath)
    {
        cout<<"NamePath is NULL!"<<endl;
        exit(EXIT_FAILURE);
    }
    int len = strlen(NamePath);
    char *Current = NULL;
    while(len > 0 && NamePath[len] != '/')
    {
         len--;
    }
    if(NamePath[len] == '/')
        Current = &NamePath[len] + 1;
    else
        Current = &NamePath[len];
    return Current;
}
void PathCat(char *desPath, char *srcPath)
{
    char          *ptrdes;
    char *srcPathname = GetFileName(srcPath);
    if(lstat(desPath, &statbuf) < 0)
    {
        cout<<"lstat error!"<<endl;
        exit(EXIT_FAILURE);
    }
    if(desPath[strlen(desPath)] != '/' && S_ISDIR(statbuf.st_mode) != 0)
    {
         ptrdes = desPath + strlen(desPath);
         *ptrdes++ = '/';
         *ptrdes = 0;
    }
    strcat(desPath, srcPathname);
}
int PathDep(char *dir)
{
    int len = strlen(dir);
    int count = 0;
    while(len-- > 0)
    {
         if(dir[len] == '/')
             ++count;
    }
    return count;
}
int PathCmp(char *dir1, char *dir2)
{
    if(PathDep(dir1) > PathDep(dir2))
        return 1;
    else if(PathDep(dir1) == PathDep(dir2))
        return 0;
    else
        return -1;
}

void OneFileCovert(char *des, char *src)
{
    FILE *inputfile = fopen(src, "r");
    if(NULL == inputfile)
    {
        cout<<"Open src file Fail!"<<endl;
        exit(EXIT_FAILURE);
    }
    FILE *outputfile = fopen(des, "w");
    if(NULL == outputfile)
    {
        cout<<"Open des file Fail!"<<endl;
        exit(EXIT_FAILURE);
    }

    ConvertComment(inputfile, outputfile);

    fclose(inputfile);
    fclose(outputfile);
}
void DirConvert(char *des, char *src)
{
    char src_path[_POSIX_PATH_MAX];
    memset(src_path, 0, _POSIX_PATH_MAX);

    struct dirent *dirp;
    DIR           *dpsrc;               //源目录
    DIR           *dpdes;               //目的目录
    if(NULL == des || NULL == src)      //参数检测
    {
        cout<<"des/src is NULL!"<<endl;
        exit(EXIT_FAILURE);
    }
    if(NULL == (dpdes = opendir(des)))  //如果目的目录不存在,则创建
    {
        mkdir(des, 0755);
    }
    if(NULL == (dpsrc = opendir(src)))  //如果源目录不存在,退出程序
    {
         perror("opendir src");
         exit(EXIT_FAILURE);
    }
    if(NULL == realpath(src,src_path))  //src给src_path
    {
        perror("realpath src");
        exit(EXIT_FAILURE);
    }
    //readdir读取src的顺序为:t1,t2,t3,input.c
    while((dirp = readdir(dpsrc)) != NULL)
    {
        if(strcmp(dirp->d_name, ".") == 0 ||
           strcmp(dirp->d_name, "..") == 0)
            continue;                   //忽略"."和".."
        PathCat(src_path,dirp->d_name);
        cout<<src_path<<endl;
        BeginConvert(des,src_path);   //des=./t1 src_path=./tttttt/t1
        if(NULL == realpath(src,src_path))//将src_path恢复成src
        {
            perror("realpath src");
            exit(EXIT_FAILURE);
        }
    }
    closedir(dpsrc);
    closedir(dpdes);
}
void BeginConvert(char *des, char *src) //des=./t1  src=./tttttt/t1
{
    //(1)将src,des的路径转化成绝对路径分别存于src_path,des_path中
    //(2)获取src的属性。
    //(3)分情况讨论
    //a.如果src是文件,判断是否是.c/.cpp文件,des_path追加这一文件,然后直接调动OneFileConvert()进行转换
    //b.如果src是目录,des_path追加这一目录,然后DirpConvert(des_path,src_path)

    //(1)
    char *srcfilename = GetFileName(src);
    char src_path[_POSIX_PATH_MAX];
    memset(src_path, 0, _POSIX_PATH_MAX);
    char des_path[_POSIX_PATH_MAX];
    memset(des_path, 0, _POSIX_PATH_MAX);
    if(NULL == realpath(src, src_path))
    {
        perror("realpath src");
        exit(EXIT_FAILURE);
    }
    if(NULL == realpath(des, des_path))
    {
        perror("realpath des");
        exit(EXIT_FAILURE);
    }
    //(2)
    if(lstat(src_path, &statbuf) < 0)
    {
         perror("lstat src");
         exit(EXIT_FAILURE);
    }
    //(3)
    //a.文件
    if(S_ISDIR(statbuf.st_mode) == 0)
    {
        if(IsCFile(src_path) || IsCppFile(src_path))
        {
            PathCat(des_path, srcfilename);
            OneFileCovert(des_path, src_path);
        }
        else    //只是单纯的写拷贝文件
        {
            PathCat(des_path, srcfilename);
            FileCp(des_path, src_path);
        }
    }
    //b.目录
    else
    {
        PathCat(des_path, srcfilename);
        DirConvert(des_path, src_path);
    }
}
void help()
{
     FILE *README = fopen("README.md", "r");
     if(NULL == README)
     {
          cout<<"Open README.md fail!"<<endl;
          exit(EXIT_FAILURE);
     }
     char buf[READMESIZE];
     while(!feof(README))
     {
          fgets(buf, READMESIZE, README);
          cout<<buf<<endl;
     }
}
void SeeArgc(const int count)
{
    if(count != 4)
    {
        cout<<"Argument is error!"<<endl;
        exit(EXIT_FAILURE);
    }
}

#endif

四.收获
1.学会了gdb的带参调试
2.会使用目录操作函数及文件操作函数实现自己的小想法,这次目录级联转换的小项目主要使用到了这些函数:
lstat获取文件属性,opendir–>readdir–>closedir的目录操作流程,realpath将相对路径转化成绝对路径。
3.注意到的问题:

dirp = readdir(dirname);
如果将dirp->d_name转化成绝对路径,只是给dirp->d_name字符串前面添加了源程序(即代码执行路径),而不是真正的绝对路径,这样会导致,下一次递归打开dirp->d_name时,程序报错,文件不存在!所以我的程序中加入了将dirp->d_name与其所在目录绝对路径的字符串拼接函数PathCat,当然这给与其无关的某些操作也提供了方便。 

源码请戳
https://github.com/zhangzhuo233/little_project/tree/master/ConvertComment/day2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值