C++實(shí)現(xiàn)簡單的ls命令及其原理
思維導(dǎo)圖

準(zhǔn)備工作
對控制參數(shù)的處理
一共有 7 個(gè)可選參數(shù),分別是-a、-l、-R、-t、-r、-i、-s,這些參數(shù)可以相互自由組合,因此可以設(shè)計(jì)一種機(jī)制,就是直接把它們?nèi)坑醚h(huán)一次性做或運(yùn)算,得到一個(gè)參數(shù)標(biāo)記Vec。
// 標(biāo)記: -a、-l、-R、-t、-r、-i、-s 參數(shù)(向量分量) #define a 0b1000000 #define l 0b0100000 #define R 0b0010000 #define t 0b0001000 #define r 0b0000100 #define I 0b0000010 #define s 0b0000001 // 向量 int Vec = 0;
而 Vec 可以使用全局變量,這樣可以避免寫函數(shù)時(shí)不斷地給函數(shù)參數(shù)加入地址參數(shù),使得更加代碼整潔,更直觀。
對dir參數(shù)的處理
同理,依然可以設(shè)計(jì)一個(gè)全局容器,不斷地把 dirname 扔進(jìn)去:
char* dirname[4096 * 128]; int dirlen = 0;
而對于 filename 也是一樣的,但在每次遍歷一個(gè)dir 之前,就得filename 容器做重置處理:
char* filenames[4096 * 128]; int file_cnt = 0;
函數(shù)實(shí)現(xiàn)
void tags_cal(int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
if (argv[i][0] !=
'-') { // 只接受以'-'開頭的參數(shù),其它參數(shù)要么錯(cuò)誤,要么是文件夾名稱或文件名
char* tempdirname = (char*)malloc(sizeof(char) * 4096);
strcpy(tempdirname, argv[i]);
dirname[dirlen++] = tempdirname;
} else {
int len = strlen(argv[i]);
for (int j = 1; j < len; j++) {
switch (argv[i][j]) {
case 'a':
Vec |= a;
break;
case 'l':
Vec |= l;
break;
case 'R':
Vec |= R;
break;
case 't':
Vec |= t;
break;
case 'r':
Vec |= r;
break;
case 'i':
Vec |= I;
break;
case 's':
Vec |= s;
break;
default:
fprintf(stderr, "%c參數(shù)錯(cuò)誤!\n", argv[i][j]);
break;
}
}
}
}
if (dirlen == 0) {
dirlen = 1;
char* tempdirname = (char*)malloc(sizeof(char) * 2048);
strcpy(tempdirname, ".");
dirname[0] = tempdirname;
}
}這里需要注意的是,如果dirlen == 0,說明我們的命令并沒有加參數(shù),默認(rèn)是對當(dāng)前文件夾進(jìn)行操作,因此需要重新對 dirlen賦值為 1,然后把 dirname[0]置為"."。
實(shí)現(xiàn)
我們上一步成功得到了,dirnname、dirlen,這樣就可以逐個(gè)dirname[i]進(jìn)行處理了!
void do_myls() {
for (int i = 0; i < dirlen; i++) {
if (do_name(dirname[i]) == -1) {
continue;
}
// 且自動(dòng)字典排序
if ((Vec & t) == t) { // 時(shí)間排序
do_t(filenames);
}
if ((Vec & r) == r) { // 逆序
do_r(filenames, file_cnt);
}
printf("當(dāng)前路徑:\"%s\"\n", dirname[i]);
int tag = 0; // 換行
for (int j = 0; j < file_cnt; j++) {
// 拼湊文件名
char path[4096] = {0};
strcpy(path, dirname[i]);
int len = strlen(dirname[i]);
strcpy(&path[len], "/");
strcpy(&path[len + 1], filenames[j]);
tag++;
if ((Vec & a) == 0) {
if ((strcmp(filenames[j], ".") == 0 ||
strcmp(filenames[j], "..") == 0) ||
filenames[j][0] == '.') {
continue;
}
}
struct stat info;
stat(path, &info); // 拉進(jìn) info
if (S_ISDIR(info.st_mode) && ((Vec & R) == R)) {
// 如果是目錄,那就直接拉進(jìn) dirnames:"dirname/filename"
char* tempdirname = (char*)malloc(sizeof(char) * 4096);
strcpy(tempdirname, dirname[i]);
int len = strlen(tempdirname);
strcpy(&tempdirname[len], "/");
strcpy(&tempdirname[len + 1], filenames[j]);
dirname[dirlen++] = tempdirname;
}
if ((Vec & I) == I) {
do_i(path);
}
if ((Vec & s) == s) {
do_s(path);
}
if ((Vec & l) == 0) {
if (S_ISDIR(info.st_mode)) // 判斷是否為目錄
{
printf(GREEN "%s\t" NONE, filenames[j]);
} else {
printf(BLUE "%s\t" NONE, filenames[j]);
}
}
if ((Vec & l) == l) {
void mode_to_letters();
char modestr[11];
mode_to_letters(info.st_mode, modestr);
printf("%s ", modestr);
printf("%4d ", (int)info.st_nlink);
printf("%-8s ", uid_to_name(info.st_uid));
printf("%-8s ", gid_to_name(info.st_gid));
printf("%8ld ", (long)info.st_size);
printf("%.12s ", ctime(&info.st_mtime));
if (S_ISDIR(info.st_mode)) // 判斷是否為目錄
{
printf(GREEN "%s\t" NONE, filenames[j]);
} else {
printf(BLUE "%s\t" NONE, filenames[j]);
}
printf("\n");
}
if ((tag % 5 == 0) && ((Vec & l) == 0)) {
printf("\n");
}
}
// 清空容器
for (int k = 0; k < file_cnt; k++) {
memset(filenames[k], 4096, '\0');
}
file_cnt = 0;
}
}這里最關(guān)鍵的就是對-R參數(shù)的處理,因?yàn)槲覀兊恼w框架并不適合做函數(shù)的遞歸,因此我們可以在判斷某個(gè) filename是一個(gè) dir 之后,就可以把它加入到 dirname 中,并且把 dirlen++,這樣就在邏輯上實(shí)現(xiàn)了遍歷,這里也充分利用了全局變量的優(yōu)勢:牽一發(fā)而動(dòng)全身。
struct stat info;
stat(path, &info); // 拉進(jìn) info
if (S_ISDIR(info.st_mode) && ((Vec & R) == R)) {
// 如果是目錄,那就直接拉進(jìn) dirnames:"dirname/filename"
char* tempdirname = (char*)malloc(sizeof(char) * 4096);
strcpy(tempdirname, dirname[i]);
int len = strlen(tempdirname);
strcpy(&tempdirname[len], "/");
strcpy(&tempdirname[len + 1], filenames[j]);
dirname[dirlen++] = tempdirname;
}而其它的功能性函數(shù)實(shí)現(xiàn)起來就很簡單了,就不累贅了。
完整代碼
#include <dirent.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
// 標(biāo)記: -a、-l、-R、-t、-r、-i、-s 參數(shù)(向量分量)
#define a 0b1000000
#define l 0b0100000
#define R 0b0010000
#define t 0b0001000
#define r 0b0000100
#define I 0b0000010
#define s 0b0000001
// 顏色宏
#define NONE "\033[m"
#define GREEN "\033[0;32;32m"
#define BLUE "\033[0;32;34m"
// 函數(shù)聲明
void tags_cal(int argc, char* argv[]);
void restored_ls(struct dirent* cur_item);
void sort(char** filenames, int start, int end);
void do_r(char** filenames, int file_cnt);
int partition(char** filenames, int start, int end);
void swap(char** s1, char** s2);
int compare(char* s1, char* s2);
char* uid_to_name(uid_t);
char* gid_to_name(gid_t);
void mode_to_letters(int, char[]);
char* uid_to_name(uid_t);
// ********函數(shù)聲明********
void do_i(char filename[]);
void do_s(char filename[]);
int do_name(char dirname[]);
void do_myls();
void do_t(char** filenames);
int Vec = 0;
char* dirname[4096 * 128];
int dirlen = 0;
char* filenames[4096 * 128];
int file_cnt = 0;
int main(int argc, char* argv[]) {
tags_cal(argc, argv);
do_myls();
return 0;
}
void do_myls() {
for (int i = 0; i < dirlen; i++) {
if (do_name(dirname[i]) == -1) {
continue;
}
// 且自動(dòng)字典排序
if ((Vec & t) == t) { // 時(shí)間排序
do_t(filenames);
}
if ((Vec & r) == r) { // 逆序
do_r(filenames, file_cnt);
}
printf("當(dāng)前路徑:\"%s\"\n", dirname[i]);
int tag = 0; // 換行
for (int j = 0; j < file_cnt; j++) {
// 拼湊文件名
char path[4096] = {0};
strcpy(path, dirname[i]);
int len = strlen(dirname[i]);
strcpy(&path[len], "/");
strcpy(&path[len + 1], filenames[j]);
tag++;
if ((Vec & a) == 0) {
if ((strcmp(filenames[j], ".") == 0 ||
strcmp(filenames[j], "..") == 0) ||
filenames[j][0] == '.') {
continue;
}
}
struct stat info;
stat(path, &info); // 拉進(jìn) info
if (S_ISDIR(info.st_mode) && ((Vec & R) == R)) {
// 如果是目錄,那就直接拉進(jìn) dirnames:"dirname/filename"
char* tempdirname = (char*)malloc(sizeof(char) * 4096);
strcpy(tempdirname, dirname[i]);
int len = strlen(tempdirname);
strcpy(&tempdirname[len], "/");
strcpy(&tempdirname[len + 1], filenames[j]);
dirname[dirlen++] = tempdirname;
}
if ((Vec & I) == I) {
do_i(path);
}
if ((Vec & s) == s) {
do_s(path);
}
if ((Vec & l) == 0) {
if (S_ISDIR(info.st_mode)) // 判斷是否為目錄
{
printf(GREEN "%s\t" NONE, filenames[j]);
} else {
printf(BLUE "%s\t" NONE, filenames[j]);
}
}
if ((Vec & l) == l) {
void mode_to_letters();
char modestr[11];
mode_to_letters(info.st_mode, modestr);
printf("%s ", modestr);
printf("%4d ", (int)info.st_nlink);
printf("%-8s ", uid_to_name(info.st_uid));
printf("%-8s ", gid_to_name(info.st_gid));
printf("%8ld ", (long)info.st_size);
printf("%.12s ", ctime(&info.st_mtime));
if (S_ISDIR(info.st_mode)) // 判斷是否為目錄
{
printf(GREEN "%s\t" NONE, filenames[j]);
} else {
printf(BLUE "%s\t" NONE, filenames[j]);
}
printf("\n");
}
if ((tag % 5 == 0) && ((Vec & l) == 0)) {
printf("\n");
}
}
// 清空容器
for (int k = 0; k < file_cnt; k++) {
memset(filenames[k], 4096, '\0');
}
file_cnt = 0;
}
}
void tags_cal(int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
if (argv[i][0] !=
'-') { // 只接受以'-'開頭的參數(shù),其它參數(shù)要么錯(cuò)誤,要么是文件夾名稱或文件名
char* tempdirname = (char*)malloc(sizeof(char) * 4096);
strcpy(tempdirname, argv[i]);
dirname[dirlen++] = tempdirname;
} else {
int len = strlen(argv[i]);
for (int j = 1; j < len; j++) {
switch (argv[i][j]) {
case 'a':
Vec |= a;
break;
case 'l':
Vec |= l;
break;
case 'R':
Vec |= R;
break;
case 't':
Vec |= t;
break;
case 'r':
Vec |= r;
break;
case 'i':
Vec |= I;
break;
case 's':
Vec |= s;
break;
default:
fprintf(stderr, "%c參數(shù)錯(cuò)誤!\n", argv[i][j]);
break;
}
}
}
}
if (dirlen == 0) {
dirlen = 1;
char* tempdirname = (char*)malloc(sizeof(char) * 2048);
strcpy(tempdirname, ".");
dirname[0] = tempdirname;
}
}
void do_i(char filename[]) {
struct stat info;
if (stat(filename, &info) == -1)
perror(filename);
printf("%llu\t", info.st_ino);
}
void do_s(char filename[]) {
struct stat info;
if (stat(filename, &info) == -1)
perror(filename);
printf("%4llu\t", info.st_size / 4096 * 4 + (info.st_size % 4096 ? 4 : 0));
}
int do_name(char dirname[]) {
int i = 0;
int len = 0;
DIR* dir_ptr;
struct dirent* direntp;
if ((dir_ptr = opendir(dirname)) == NULL) {
fprintf(stderr, "權(quán)限不夠,cannot open: %s\n", dirname);
return -1;
} else {
while ((direntp = readdir(dir_ptr))) {
restored_ls(direntp);
}
sort(filenames, 0, file_cnt - 1);
}
printf("\n");
closedir(dir_ptr);
return 1;
}
void sort(char** filenames, int start, int end) {
if (start < end) {
int position = partition(filenames, start, end);
sort(filenames, start, position - 1);
sort(filenames, position + 1, end);
}
}
int partition(char** filenames, int start, int end) {
if (!filenames)
return -1;
char* privot = filenames[start];
while (start < end) {
while (start < end && compare(privot, filenames[end]) < 0)
--end;
swap(&filenames[start], &filenames[end]);
while (start < end && compare(privot, filenames[start]) >= 0)
++start;
swap(&filenames[start], &filenames[end]);
}
return start;
}
void swap(char** s1, char** s2) {
char* tmp = *s1;
*s1 = *s2;
*s2 = tmp;
}
int compare(char* s1, char* s2) {
if (*s1 == '.')
s1++;
if (*s2 == '.')
s2++;
while (*s1 && *s2 && *s1 == *s2) {
++s1;
++s2;
if (*s1 == '.')
s1++;
if (*s2 == '.')
s2++;
}
return *s1 - *s2;
}
void restored_ls(struct dirent* cur_item) {
char* result = (char*)malloc(sizeof(char) * 4096);
strcpy(result, cur_item->d_name);
filenames[file_cnt++] = result;
}
void mode_to_letters(int mode, char str[]) {
strcpy(str, "----------");
if (S_ISDIR(mode))
str[0] = 'd';
if (S_ISCHR(mode))
str[0] = 'c';
if (S_ISBLK(mode))
str[0] = 'b';
if (mode & S_IRUSR)
str[1] = 'r';
if (mode & S_IWUSR)
str[2] = 'w';
if (mode & S_IXUSR)
str[3] = 'x';
if (mode & S_IRGRP)
str[4] = 'r';
if (mode & S_IWGRP)
str[5] = 'w';
if (mode & S_IXGRP)
str[6] = 'x';
if (mode & S_IROTH)
str[7] = 'r';
if (mode & S_IWOTH)
str[8] = 'w';
if (mode & S_IXOTH)
str[9] = 'x';
}
char* gid_to_name(gid_t gid) {
struct group *getgrgid(), *grp_ptr;
static char numstr[10];
if ((grp_ptr = getgrgid(gid)) == NULL) {
sprintf(numstr, "%d", gid);
return numstr;
} else {
return grp_ptr->gr_name;
}
}
char* uid_to_name(gid_t uid) {
struct passwd* getpwuid();
struct passwd* pw_ptr;
static char numstr[10];
if ((pw_ptr = getpwuid(uid)) == NULL) {
sprintf(numstr, "%d", uid);
return numstr;
} else {
return pw_ptr->pw_name;
}
}
void do_t(char** filenames) {
char temp[2048] = {0};
struct stat info1;
struct stat info2;
for (int i = 0; i < file_cnt - 1; i++) {
for (int j = i + 1; j < file_cnt; j++) {
stat(filenames[i], &info1);
stat(filenames[j], &info2);
if (info1.st_mtime < info2.st_mtime) {
strcpy(temp, filenames[i]);
strcpy(filenames[i], filenames[j]);
strcpy(filenames[j], temp);
}
}
}
}
void do_r(char** arr, int file_cnt) {
// 只需要修改指針
char left = 0;
char right = file_cnt - 1;
char temp;
while (left < right) {
char* temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}總結(jié)
這個(gè) myls的難點(diǎn)在于整個(gè)系統(tǒng)的設(shè)計(jì),比如參數(shù)怎么處理,怎么根據(jù)參數(shù)輸出相應(yīng)的信息。而函數(shù)的實(shí)現(xiàn)就比較簡單。
到此這篇關(guān)于C++實(shí)現(xiàn)簡單的ls命令及其原理的文章就介紹到這了,更多相關(guān)C++ ls命令內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言入門篇--sizeof與strlen基礎(chǔ)理論
本篇文章是c語言基礎(chǔ)篇,主要為大家介紹了C語言的sizeof與strlen的基本理論知識(shí),希望可以幫助大家快速入門c語言的世界,更好的理解c語言2021-08-08
簡單分析C語言中指針數(shù)組與數(shù)組指針的區(qū)別
這篇文章主要介紹了C語言中指針數(shù)組與數(shù)組指針的區(qū)別,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-11-11

