为Linux 操作系统建立兼容的 Windows命令接口

2021-01-17 03:11

阅读:675

标签:details   表达   baidu   错误   nec   temp   tchar   enter   attr   

简单实现的dos命令

CLS, DATE,TIME,FIND,FINDSTR,COMP,FC,EXIT,HELP,MORE

说明

  • 由于自己能力和时间有限,程序依旧存在不少bug,并且不是原模原样的实现dos命令,有的简单实现,有的命令参数众多,只实现了几个
  • 这个程序写的并不优雅,违反了很多大忌,只是简单能跑
  • 写完后我再也不想见到“段错误”这三个字,心酸,这个可能在出现段错误时为你提供点解决思路https://www.cnblogs.com/zl-graduate/p/5735288.html
  • 使用的环境
    • gcc 9.2.1 20190909
    • GNU gdb (Debian 8.3-1) 8.3
    • Kali-Linux-2018.2-vm-amd64
  • 参考的Linux api文档
    • Linux c api 参考手册https://legacy.gitbook.com/book/wizardforcel/linux-c-api-ref/details
    • https://github.com/guodongxiaren/LinuxAPI/wiki

结构

为了演示,所用到的两个文档1.txt 2.txt

技术图片技术图片

CLS

功能

cls命令的功能是清屏

设计流程

技术图片 其实就是简单地 fputs("\x1b[2J\x1b[H", stdout);其中的不明所以的字符串是VT100的控制码,部分定义如下 "\x1b[2J"清除整个屏幕,行属性变成单宽单高,光标位置不变 "\x1b[H"光标移动 \033[0m 关闭所有属性 \033[1m 设置为高亮 \033[4m 下划线 \033[5m 闪烁 \033[7m 反显 \033[8m 消隐 \033[nA 光标上移 n 行 \033[nB 光标下移 n 行 \033[nC 光标右移 n 行 \033[nD 光标左移 n 行 \033[y;xH 设置光标位置 \033[2J 清屏 \033[K 清除从光标到行尾的内容 \033[s 保存光标位置 \033[u 恢复光标位置 \033[?25l 隐藏光标 \033[?25h 显示光标 \033[30m – \033[37m 设置前景色

效果

技术图片技术图片

DATE

功能

date 命令用来查看和修改当前日期 详细操作查看https://jingyan.baidu.com/article/1974b2893e7d62f4b1f774ff.html

设计流程

技术图片 判断是否有输入参数t,?,进行相关处理。 如果没有则打印当前日期,并提示输入更改日期,判断日期是否合法再进行修改 判断年月日是否合法直接用了这位博主的代码 https://blog.csdn.net/freeape/article/details/48682411

效果

技术图片技术图片

TIME

功能

time 用来查看和修改计算机时间 详细操作查看https://jingyan.baidu.com/article/aa6a2c14ab5ac90d4c19c492.html

设计流程

技术图片 判断是否有输入参数t,?,进行相关处理。 如果没有则打印当前时间,并提示输入更改时间,判断时间是否合法再进行修改

效果

技术图片

FIND

在之后涉及比较的命令的程序都参考了https://zhidao.baidu.com/question/237942227.html下一骑当后的回答

功能

find 命令用于查找文档中的特定字符和数字及行号 详细操作查看https://jingyan.baidu.com/article/86f4a73ecfe08637d65269ef.html

设计流程

技术图片 采用指针遍历文件的匹配算法来寻找字符串,并通过输入参数/C/N/V等控制输出打印的形式

效果

技术图片

FINDSTR

这个命令自己实现的并不完全

功能

findstr是find的升级版 详细操作查看https://jingyan.baidu.com/article/a65957f418641e24e67f9b99.html

设计流程

技术图片技术图片 命令所需参数有文件路径,文件类型和所搜寻的字符串 该模块包含两个函数 findstr函数如上图1,主要负责遍历目录与文件,挑选符合参数决定的文件类型 find1函数如上图2,主要负责采用指针遍历文件,与参数决定的字符串进行对比,找到所匹配的字符串。每次读取一行采用指针遍历方法与字符串进行对比 对于文件的遍历和文件类型的识别参考了 https://zhidao.baidu.com/question/683010229831852652.html https://www.cnblogs.com/xudong-bupt/p/3504442.html 以下是我的程序

while ((ptr = readdir(dir)) != NULL)
    {
        if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) //是当前目录和父目录
            continue;
        else if (ptr->d_type == 4) //是dir
        {
            char *cpath = (char *)malloc(strlen(path) + strlen(ptr->d_name) + strlen("/") + 1);
            strcpy(cpath, path);
            strcat(cpath, "/");
            strcat(cpath, ptr->d_name);
            //findstr(cpath, type, str);
        }
        else//是文件
        {
            p = strrchr(ptr->d_name, ‘.‘);//取得文件最后一个.后的字符,即文件的类型
            sprintf(ftype, "%s", p);
            if (strcmp(ftype, type) == 0)
            {
                char *fpath = (char *)malloc(strlen(path) + strlen(ptr->d_name) + strlen("/") + 1);
                strcpy(fpath, path);
                strcat(fpath, "/");
                strcat(fpath, ptr->d_name);
                find1(fpath, str);
            }
        }
    }

使用readdir()返回一个结构

struct dirent
{
ino_t d_ino;
ff_t d_off;
signed short int d_reclen;
unsigned char d_type;
har d_name[256];
};

d_ino 此目录进入点的inode d_off 目录文件开头至此目录进入点的位移 d_reclen _name的长度,不包含NULL字符 d_type 所指的文件类型 d_name 文件名

效果

技术图片

COMP

该命令要求两个文件的大小相同,获取文件大小的方法参考了https://www.cnblogs.com/xudong-bupt/p/3506772.html

功能

comp逐字节比较两个文件或文件集的内容 详细操作查看https://jingyan.baidu.com/article/90808022da9bbbfd91c80f1b.html](https://jingyan.baidu.com/article/90808022da9bbbfd91c80f1b.html)

设计流程

技术图片技术图片技术图片 主要包含三个函数comp,command_comp,file_comp分别对应上图1,2,3 comp主要通过控制流程控制程序走向 command_comp主要对输入的参数进行分析,并返回一个和(包含参数信息,/L对应1,/A对应2,/D对应4,无对应0) file_comp主要通过匹配算法进行字符串的查找,并根据对参数指令的分析返回的值进行打印输出

效果

技术图片

FC

功能

FC是DOS及Windows下的一个比较文件的命令行工具,使用该命令能够将两个类似文件的不同之处进行详细对比。 详细操作查看https://baike.baidu.com/item/FC/10362340?fr=aladdin

设计流程

技术图片 比较两个文件的不同之处,循环读取文件1的一行,与文件2的每一行进行对比,输出不相等的行。再循环读取文件2的一行,与文件1的每一行进行对比,输出不相等的行。

效果

技术图片

EXIT

功能

退出当前命令窗口 详细操作查看https://baike.baidu.com/item/FC/10362340?fr=aladdin

设计流程

技术图片 这里实在不会实现,只好假装实现,因为通过命令窗口调用该程序,所以得到该程序的父进程的id,然后将其kill假装实现了exit

效果

技术图片

HELP

功能

help列出命令的帮助信息 详细操作查看https://jingyan.baidu.com/article/ea24bc39d29264da63b33163.html

设计流程

技术图片 直接输入help命令显示所有help信息,通过help+命令,输出对应命令的信息

效果

技术图片

MORE

功能

more 命令将文本文档逐行进行显示, 也可显示多个文档, 跳行和显示下几行 详细操作查看https://jingyan.baidu.com/article/bad08e1e327c3709c85121fa.html 其实这个程序大部分用了github上的代码,可惜后面找不到出处了

设计流程

技术图片 主要包含more see_more do_more几个函数,这里全部展示在上图。 more允许打印多个文件,当打印满时,可以通过命令q退出命令,命令m打印更多,命令\n打印下一个文件。

效果

技术图片 两个文件时 技术图片 M继续显示,\n显示下一个文件 技术图片技术图片

主函数

设计流程

技术图片

效果

为了模仿windows前面的提示符,通过getcwd()获取当前目录,并显示 技术图片

其它说明

对于格式化显示输出的问题

保留小数https://blog.csdn.net/qq_36667170/article/details/79265224 前面补0https://zhidao.baidu.com/question/2272528818662923828.html

动态开辟多个指针

参考自https://zhidao.baidu.com/question/1430108991238952819.html

pArrStr=(char**)malloc(sizeof(char*)*strLen);//动态开辟N个char*指针,然后给pArrStr保存 for(i=0;i

对时间相关模块说明

其实开始说明中的linux api文档中解释的就可以,并且有相关示例,这个也比较详细https://blog.csdn.net/lhl_blog/article/details/86238140

相关调用函数清单

struct tm
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
int tm_sec 代表目前秒数,正常范围为0-59,但允许至61秒 int tm_min 代表目前分数,范围0-59 int tm_hour 从午夜算起的时数,范围为0-23 int tm_mday 目前月份的日数,范围01-31int tm_mon 代表目前月份,从一月算起,范围从0-11 int tm_year 从1900 年算起至今的年数int tm_wday 一星期的日数,从星期一算起,范围为0-6 int tm_yday 从今年1月1日算起至今的天数,范围为0-365 int tm_isdst 日光节约时间的旗标 此函数返回的时间日期未经时区转换,而是UTC时间。
struct timeval{
long tv_sec; /*秒*/
long tv_usec; /*微秒*/
};
struct timezone{
int tz_minuteswest; /*和Greenwich 时间差了多少分钟*/
int tz_dsttime; /*日光节约时间的状态*/
};
time_t time(time_t *t); 返回从公元1970年1月1日的UTC时间从0时0分0秒算起到现在所经过的秒数。
struct tm *localtime(const time_t *timep); 将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构tm返回。
time_t mktime(strcut tm *timeptr); mktime()用来将参数timeptr所指的tm结构数据转换成从公元1970年1月1日0时0分0 秒算起至今的UTC时间所经过的秒数。
int stime(long *tp)设置时间。
int settimeofday(const struct timeval *tv, const struct timezone *tz);设置当前时间。

程序涉及到了很多字符串的操作

字符串和数字的转化

https://blog.csdn.net/smile_zhangw/article/details/82051014

字符串的拼接

https://www.cnblogs.com/metaphors/p/9409153.html

相关调用函数清单

int strcmp(const char *s1, const char *s2);比较两个字符串。
char *strtok(char *s, const char *delim); strtok()用来将字符串分割成一个个片段。参数s指向欲分割的字符串,参数delim则为分割字符串,当strtok()在参数s的字符串中发现到参数delim的分割字符时则会将该字符改为\0 字符。在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回下一个分割后的字符串指针。
在main()中的使用
//对命令按空格进行分割,命令存入*argv[]中,命令数存入argc中
        if (strlen(input) != 0)
        {
            char *delim = " ";
            char *p;
            p = strtok(input, delim);
            argv[0] = p;
            while ((p = strtok(NULL, delim)))
            {
                argv[argc] = p;
                argc++;
            }
        }
char *gets(char *s); 由标准输入设备内读进一字符串。
char *strcpy(char *dest, const char *src); strcpy()会将参数src字符串拷贝至参数dest所指的地址。
char *strcat(char *dest, const char *src);连接两个字符串。
char *strchr(const char *s, int c); 查找字符串中第一个出现的指定字符。
size_t strlen(const char *s);返回字符串长度

对涉及文件相关操作模块说明

清空缓存

因为c读取字符时,可能读到缓冲区的字符,产生影响,所以需要清除 参考https://jingyan.baidu.com/article/9f7e7ec0b5e4a86f28155415.html https://zhuanlan.zhihu.com/p/54990226

相关调用函数清单

FILE *fopen(const char *path, const char *mode); 参数path字符串包含欲打开的文件路径及文件名,参数mode字符串则代表着流形态。
char *fgets(char *s, int size, FILE *stream);从文件中读取一字符串。
long ftell(FILE *stream);取得文件流的读取位置。
struct dirent *readdir(DIR *dir);读取目录。
int fseek(FILE *stream, long offset, int whence);移动文件流的读写位置。
int fputs(const char *s, FILE *stream);将一指定字符写入文件内。
int fgetc(FILE * stream);文件中读取一个字符。
int getchar(void); getchar()用来从标准输入设备中读取一个字符。然后将该字符从unsigned char转换成int后返回。

程序

gcc -o shell shell.c ./shell 技术图片

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//findstr命令
void find1(char *argv, char *str)
{
    FILE *fp;
    int stringsize = strlen(str) * sizeof(char);
    char *line = (char *)calloc(512, sizeof(char));
    fp = fopen(argv, "r");
    int i = 0;
    while (fgets(line, 512, fp))
    {
        int j = 0;
        char *start;
        i = 0;
        start = line;
        while (i d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) //是当前目录和父目录
            continue;
        else if (ptr->d_type == 4) //是dir
        {
            char *cpath = (char *)malloc(strlen(path) + strlen(ptr->d_name) + strlen("/") + 1);
            strcpy(cpath, path);
            strcat(cpath, "/");
            strcat(cpath, ptr->d_name);
            //findstr(cpath, type, str);
        }
        else//是文件
        {
            p = strrchr(ptr->d_name, ‘.‘);//取得文件最后一个.后的字符,即文件的类型
            sprintf(ftype, "%s", p);
            if (strcmp(ftype, type) == 0)
            {
                char *fpath = (char *)malloc(strlen(path) + strlen(ptr->d_name) + strlen("/") + 1);
                strcpy(fpath, path);
                strcat(fpath, "/");
                strcat(fpath, ptr->d_name);
                find1(fpath, str);
            }
        }
    }
}
//find命令
int command_comp1(char **str)
{
    int i = 3;
    if (strcmp(str[i], "/V") == 0)//包含字符串的所在行,不显示
    {
        return 1;
    }
    else if (strcmp(str[i], "/C") == 0)//只显示包含字符串的行
    {
        return 2;
    }
    else if (strcmp(str[i], "/N") == 0)//显示找到的包含字符串的行数
    {
        return 3;
    }
    else
    {
        printf("命令行参数有误");
        exit(0);
    }
}
void find(int argc, char **argv)
{
    FILE *fp;
    char *string = argv[2];
    int stringsize = strlen(string) * sizeof(char);
    char *line = (char *)calloc(512, sizeof(char));
    fp = fopen(argv[1], "r");
    int i = 0, flag = 0, linec = 1, linen = 0;
    int pa;
    pa = command_comp1(argv);
    while (fgets(line, 512, fp))//读取一行
    {
        int j = 0;
        char *start;
        i = 0;
        start = line;
        while (i     字位置: 字的结束\n\n有关 FINDSTR 常见表达法的详细情况,请见联机命令参考。\n");
            n = 1;
        }
        if (strcmp(argv[1], "help") == 0)
        {
            printf("提供 Windows 命令的帮助信息。\nHELP [command]\n\n command - 显示该命令的帮助信息。\n");
            n = 1;
        }
        if (strcmp(argv[1], "more") == 0)
        {
            printf("逐屏显示输出。\n\nMORE [/E [/C] [/P] [/S] [/Tn] [+n]]  显示下一页\n 显示下一行\n");
            n = 1;
        }
        if (strcmp(argv[1], "time") == 0)
        {
            printf("显示或设置系统时间。\n\nTIME [/T | time]\n\n显示当前时间设置和输入新时间的提示,请键入\n不带参数的 TIME。要保留现有时间,请按 Enter。\n\n如果命令扩展被启用,TIME 命令会支持 /T 命令行开关;该命令行开关告诉\n命令只输出当前时间,但不提示输入新时间。\n");
            n = 1;
        }
        if (n == 0)
        {
            printf("帮助工具不支持此命令。请尝试\" %s /?\"。\n", argv[1]);
        }
    }
}
//time命令
bool IsLegal(int hour, int minute, int second)//判断时间是否合法的函数
{
    if (hour >= 0 && hour = 0 && minute = 0 && second tm_hour, p->tm_min, p->tm_sec);
        while (1)
        {
            printf("输入新时间:");
            scanf("%d:%d:%d", &hour, &minute, &second);
            //转化为tm结构
            p->tm_hour = hour;
            p->tm_min = minute;
            p->tm_sec = second;
            //转化为time_t结构
            tt = mktime(p);
            char ch;
            while ((ch = getchar()) != ‘\n‘ && ch != EOF)
                ;
            if (IsLegal(hour, minute, second))//判断时间是否合法
            {
                if (stime(&tt) tm_hour, p->tm_min, p->tm_sec);
        }
        else if (strcmp(argv[1], "?") == 0)
        {
            printf("显示或设置系统时间。\n");
            printf("\nTIME [/T| time] \n");
            printf("\n显示当前时间设置和输入新时间的提示,请键入不带参数的 TIME。要保留现有时间,请按 Enter。\n");
            printf("如果命令扩展被启用,TIME 命令会支持 /T 命令行开关;该命令行开关告诉命令只输出当前时间,但不提示输入新时间。\n");
        }
        else
        {
            printf("%s", argv[1]);
            time(&timep);
            p = localtime(&timep);
            //通过‘:‘将输入字符分割
            if (token = strtok(argv[1], s))
            {
                hour = atoi(token);
                if (token = strtok(NULL, s))
                {
                    minute = atoi(token);
                    if (token = strtok(NULL, s))
                    {
                        second = atoi(token);
                        p->tm_hour = hour;
                        p->tm_min = minute;
                        p->tm_sec = second;
                        tt = mktime(p);
                    }
                    else
                    {
                    }
                }
                else
                {
                }
            }
            else
            {
            }
            while (1)
            {
                if (IsLegal(hour, minute, second))
                {
                    if (stime(&tt) tm_hour = hour;
                p->tm_min = minute;
                p->tm_sec = second;
                tt = mktime(p);
                char ch;
                while ((ch = getchar()) != ‘\n‘ && ch != EOF)
                    ;
            }
        }
    }
    else
    {
        printf("系统无法接受输入的时间");
    }
}
//date命令
bool IsLeapYear(int year)//判断日期是否合法的函数
{
    if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
        return true;
    return false;
}
bool DIsLegal(int year, int mon, int day)
{
    if (year  12 || day  31)
        return false;
    if (1 == mon || 3 == mon || 5 == mon || 7 == mon || 8 == mon || 10 == mon || 12 == mon)
    {
        return true;
    }
    if (IsLeapYear(year))
    {
        if (2 == mon && (28 == day || 30 == day || 31 == day))
            return false;
        return true;
    }
    else
    {
        if (2 == mon && (29 == day || 30 == day || 31 == day))
            return false;
        return true;
    }
}
void date(int argc, char **argv)
{
    char *wday[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
    time_t timep;
    struct tm *p;
    int innum = argc;
    int year;
    int mon;
    int day;
    struct tm settime;
    struct timeval tv;
    const char s[2] = "-";
    char *token;
    //getopt(argc, argv, "ab");
    if (innum == 1)
    {
        time(&timep);
        p = localtime(&timep); //取得当地时间
        printf("% d/% d/ % d % s\n", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, wday[p->tm_wday]);
        while (1)
        {
            printf("输入新日期:");
            scanf("%d-%d-%d", &year, &mon, &day);
            //将日期转化为tm结构
            settime.tm_mday = day;
            settime.tm_mon = mon - 1;
            settime.tm_year = year - 1900;
            //通过tm结构转化我timeval结构
            tv.tv_sec = mktime(&settime);
            tv.tv_usec = 0;
            char ch;
            while ((ch = getchar()) != ‘\n‘ && ch != EOF)//清空内存中的字符
                ;
            if (DIsLegal(year, mon, day))//判断是否合法
            {
                if (settimeofday(&tv, (struct timezone *)0) tm_year), (1 + p->tm_mon), p->tm_mday, wday[p->tm_wday]);
        }
        else if (strcmp(argv[1], "?") == 0)
        {
            printf("显示或设置日期。\n");
            printf("\nDATE [/T| date] \n");
            printf("\n显示当前日期设置和输入新日期的提示,请键入不带参数的DATE。要保留现有日期,请按Enter。\n");
            printf("如果命令扩展被启用,DATE命令会支持/T开关:该开关指示命令只输出当前日期,但不提示输出新日期。\n");
        }
        //将输入的字符通过‘-‘分割
        else
        {
            if (token = strtok(argv[1], s))
            {
                year = atoi(token);
                if (token = strtok(NULL, s))
                {
                    mon = atoi(token);
                    if (token = strtok(NULL, s))
                    {
                        day = atoi(token);
                        settime.tm_mday = day;
                        settime.tm_mon = mon - 1;
                        settime.tm_year = year - 1900;
                        tv.tv_sec = mktime(&settime);
                        tv.tv_usec = 0;
                    }
                    else
                    {
                    }
                }
                else
                {
                }
            }
            else
            {
            }
            while (1)
            {
                if (IsLegal(year, mon, day))
                {
                    if (settimeofday(&tv, (struct timezone *)0) ");
                scanf("%d-%d-%d", &year, &mon, &day);
                settime.tm_mday = day;
                settime.tm_mon = mon - 1;
                settime.tm_year = year - 1900;
                tv.tv_sec = mktime(&settime);
                tv.tv_usec = 0;
                char ch;
                while ((ch = getchar()) != ‘\n‘ && ch != EOF)
                    ;
            }
        }
    }
    else
    {
        printf("系统无法接受输入的日期");
    }
}
//cls命令
void cls(int argc, char **argv)
{
    if (argc == 1)
    {
        fputs("\x1b[2J\x1b[H", stdout);//屏幕控制指令,清除屏幕
    }
    else
    {
        if (strcmp(argv[1], "?") == 0)
        {
            printf("清除屏幕\n");
            printf("\nCLS\n");
            printf("\n");
        }
        else
        {
            fputs("\x1b[2J\x1b[H", stdout);
        }
    }
}
//exit命令
void Exit()
{
    char *f = "kill -9 ";
    char str[10];
    int d = getppid();//获取当前进程的父进程
    sprintf(str, "%d", d);//将d转化为字符串
    //字符串的拼接
    char *command = (char *)malloc(strlen(f) + strlen(str));
    strcpy(command, f);
    strcat(command, str);
    system(command);//执行系统命令
}
//主函数
int main()
{
    char *input = (char *)malloc(2024);
    int argc;
    int i;
    fputs("\x1b[2J\x1b[H", stdout);//清除屏幕
    char buf[80];
    getcwd(buf, sizeof(buf));//获取当前路径
    printf("Microsoft Windows [版本 10.0.18363.535]\n(c) 2019 Microsoft Corporation。保留所有权利。\n");
    printf("\n");
    printf("%s>", buf);
    while (gets(input))
    {
        char **argv = (char **)malloc(2024);
        char *temp = (char *)malloc(2024);
        argc = 1;
        i = 0;
        //对命令按空格进行分割,命令存入*argv[]中,命令数存入argc中
        if (strlen(input) != 0)
        {
            char *delim = " ";
            char *p;
            p = strtok(input, delim);
            argv[0] = p;
            while ((p = strtok(NULL, delim)))
            {
                argv[argc] = p;
                argc++;
            }
        }
        //判断命令
        if (0 == strcmp(argv[0], "find"))
            find(argc, argv);
        else if (0 == strcmp(argv[0], "findstr"))
            findstr(argv[1], argv[2], argv[3]);
        else if (0 == strcmp(argv[0], "comp"))
            comp(argc, argv);
        else if (0 == strcmp(argv[0], "fc"))
            fc(argv);
        else if (0 == strcmp(argv[0], "date"))
            date(argc, argv);
        else if (0 == strcmp(argv[0], "time"))
            Time(argc, argv);
        else if (0 == strcmp(argv[0], "more"))
            more(argc, argv);
        else if (0 == strcmp(argv[0], "cls"))
            cls(argc, argv);
        else if (0 == strcmp(argv[0], "help"))
            help(argc, argv);
        else if (0 == strcmp(argv[0], "exit"))
            Exit();
        else
        {
            printf("命令行有误");
        }
        //释放内存
        free(argv);
        free(temp);
        printf("%s>", buf);
    }
}

为Linux 操作系统建立兼容的 Windows命令接口

标签:details   表达   baidu   错误   nec   temp   tchar   enter   attr   

原文地址:https://www.cnblogs.com/Qi-Lin/p/12207186.html


评论


亲,登录后才可以留言!