牢骚&经验
- 代码是由《LinuxC编程实战》课后题修改而来的,所以可能就是有那种打补丁的感觉,我觉得课后题里面的样例写的真的很乱,比如命令什么的,一会path,一会儿pathname,而且有些代码就是感觉有点…画蛇添足,比如strncpy之后还补个\0在后面…
- 还有就是写这个的时候加参数什么感觉特别痛苦…后面就直接用全局变量了,确实很方便
- 模块化的思想真的很重要,还要注意调用完会不会对下次产生影响,比如那个g_leave_len,display完目录后要记得把它重新设置为初始值
- 还有一个就是调试吧,我觉得gdb真的是用不来,或者说难用…所以我在很多地方打印我想看的东西
- man和网络资源要利用起来
- 在家上课真的…作业比在学校多了好多
克服的困难
- 参数的解析:
用按位或,我觉得真的很妙 - 输出对齐:
弄两个全局变量,一个表示一行剩余长度,一个表示该目录最长长度,如果一行放不下就给剩余长度赋初始值,并打印换行符 - -R参数:
我是用递归做的,具体下面有 - 权限不够:
在opendir和lstat里面多加一行判断,判断errno是否为13(因为出现Permisson deny的时候errno为13),或者可以考虑用sudo来执行 - R参数递归时一直有一个莫名其妙的 .:
因为我的逻辑是:读dirent,如果是目录就接着递归,但是…目录下都有一个.和…,他们也是目录,多加一条判断过滤他们即可 - 对于目录的解析:
目录后如果没有/一定要加上去,因为比如我有一个run目录,下面有data,如果我传的是/run,下面的函数会处理成/rundata而不是/run/data - 打印相关信息:
到dirent、stat、passwd、group这几个结构体去打印
上代码环节
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <limits.h>
#include <dirent.h>
#include <grp.h>
#include <pwd.h>
#include <errno.h>
#include "debug.h"
#include <signal.h>
#include <errno.h>
#define PARAM_NONE 0
#define PARAM_A 1
#define PARAM_L 2
#define PARAM_R 4
#define PARAM_r 8
#define PARAM_n 16
#define PARAM_h 32
#define PARAM_i 64
#define MAXROWLEN 80
#define WHITE 0
#define BLUE 1
#define GREEN 2
#define RED 3
#define LBLUE 4
#define YELLOW 5
#define KB 1024
#define MB 1024*1024
#define GB 1024*1024*1024
#define TB 1024*1024*1024*1024
#define YES 1
#define NO 0
void display_dir_R(int, const char*);
void display_single(const char*, int);
void display_attribute(struct stat, const char*);
void display(int, const char*);
void display_dir(int, const char*);
void print_name(const char*, int);
int get_color(struct stat);
void print_volume(long int, int);
void print_info(struct stat);
static void mask_ctrl_c();
int isPARAM_h = NO;
int isPARAM_n = NO;
int isPARAM_i = NO;
int g_leave_len = MAXROWLEN;
int g_maxlen;
int main(int argc, char *argv[])
{
mask_ctrl_c();
char path[PATH_MAX+1];
int num;
char param[32] = {0};
int flag_param = PARAM_NONE;
struct stat statbuf;
for (int i = 1, j = 0; i < argc; i++)
{
if (argv[i][0] == '-')
{
for (int k= 1; k < strlen(argv[i]); k++, j++)
{
param[j] = argv[i][k];
}
num++;
}
}
int i = 0;
while (param[i] != 0)
{
if (param[i] == 'a')
{
flag_param |= PARAM_A;
i++;
continue;
}
else if (param[i] == 'l')
{
flag_param |= PARAM_L;
i++;
continue;
}
else if (param[i] == 'R')
{
flag_param |= PARAM_R;
i++;
continue;
}
else if (param[i] == 'r')
{
flag_param |= PARAM_r;
i++;
continue;
}
else if (param[i] == 'h')
{
isPARAM_h = YES;
i++;
continue;
}
else if (param[i] == 'n')
{
isPARAM_n = YES;
i++;
continue;
}
else if (param[i] == 'i')
{
isPARAM_i = YES;
i++;
continue;
}
else
{
fprintf(stderr, "my_ls: 不适用的选项 -- %c\n", param[i]);
exit(1);
}
}
if (num+1 == argc)
{
display_dir(flag_param, "./");
return 0;
}
for (int i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
continue;
}
strcpy(path, argv[i]);
if (stat(path, &statbuf) == -1)
{
my_err("stat", __LINE__);
}
if (S_ISDIR(statbuf.st_mode))
{
if (path[strlen(argv[i])-1] != '/')
{
path[strlen(argv[i])] = '/';
path[strlen(argv[i])+1] = '\0';
}
if (flag_param & PARAM_R)
{
display_dir_R(flag_param, path);
}
else
display_dir(flag_param, path);
}
else
{
display(flag_param, path);
if (num+2 == argc)
{
putchar('\n');
}
}
}
return 0;
}
void display_single(const char *name, int color)
{
int len;
if (g_leave_len < g_maxlen)
{
putchar('\n');
g_leave_len = MAXROWLEN;
}
len = g_maxlen-strlen(name);
print_name(name, color);
for (int i = 0; i < len+2; i++)
{
putchar(' ');
}
g_leave_len -= g_maxlen+2;
}
void display(int flag, const char *path)
{
int i, j, path_len = strlen(path), color;
char basename[NAME_MAX+1];
struct stat statbuf;
for (i = 0, j = 0; i < path_len; i++)
{
if (path[i] == '/')
{
j = 0;
continue;
}
basename[j++] = path[i];
}
basename[j] = '\0';
if (lstat(path, &statbuf) == -1)
{
if (errno != 13)
my_err("opendir", __LINE__);
else
return;
}
if (isPARAM_i == YES)
{
if (flag & PARAM_A)
{
if (g_leave_len < g_maxlen)
{
putchar('\n');
g_leave_len = MAXROWLEN;
}
printf("%-8d ", (int)statbuf.st_ino);
}
else if (basename[0] != '.')
{
if (g_leave_len < g_maxlen)
{
putchar('\n');
g_leave_len = MAXROWLEN;
}
printf("%-8d ", (int)statbuf.st_ino);
}
}
flag = flag & (~PARAM_r);
color = get_color(statbuf);
switch (flag)
{
case PARAM_NONE:
if (basename[0] != '.')
{
display_single(basename, color);
}
break;
case PARAM_R:
if (basename[0] != '.')
{
display_single(basename, color);
}
break;
case PARAM_A:
display_single(basename, color);
break;
case PARAM_A + PARAM_R:
display_single(basename, color);
break;
case PARAM_L:
if (basename[0] != '.')
{
display_attribute(statbuf, basename);
}
break;
case PARAM_L + PARAM_R:
if (basename[0] != '.')
{
display_attribute(statbuf, basename);
}
break;
case PARAM_A + PARAM_L:
display_attribute(statbuf, basename);
break;
case PARAM_A + PARAM_L + PARAM_R:
display_attribute(statbuf, basename);
break;
}
}
void display_dir(int flag_param, const char *path)
{
g_leave_len = 80;
DIR *dir;
struct dirent *ptr;
int count = 0;
char filenames[256][PATH_MAX+1], temp[PATH_MAX+1];
if ((dir = opendir(path)) == NULL)
{
if (errno != 13)
my_err("opendir", __LINE__);
else
return;
}
while ((ptr = readdir(dir)) != NULL)
{
if (g_maxlen < strlen(ptr->d_name))
{
g_maxlen = strlen(ptr->d_name);
}
count++;
}
if (count >= 256)
{
fprintf(stderr, "too many files under this dir\n");
exit(0);
}
closedir(dir);
if ((dir = opendir(path)) == NULL)
{
my_err("opendir", __LINE__);
}
int len = strlen(path);
for (int i = 0; i < count; i++)
{
if ((ptr = readdir(dir)) == NULL)
{
my_err("readdir", __LINE__);
}
strncpy(filenames[i], path, len);
filenames[i][len] = '\0';
strcat(filenames[i], ptr->d_name);
filenames[i][len+strlen(ptr->d_name)] = '\0';
}
for (int i = 0; i < count-1; i++)
{
for (int j = 0; j < count-1-i; j++)
{
if (strcmp(filenames[j], filenames[j+1]) > 0)
{
strcpy(temp, filenames[j+1]);
strcpy(filenames[j+1], filenames[j]);
strcpy(filenames[j], temp);
}
}
}
if (flag_param & PARAM_r)
{
for (int i = count-1; i >= 0; i--)
{
display(flag_param, filenames[i]);
}
}
else
{
for (int i = 0; i < count; i++)
{
display(flag_param, filenames[i]);
}
}
closedir(dir);
if ((flag_param & PARAM_L) == 0)
putchar('\n');
}
void display_attribute(struct stat buf, const char *name)
{
char buf_time[32];
int color = WHITE;
if(S_ISLNK(buf.st_mode))
{
printf("l");
color = LBLUE;
}
else if(S_ISREG(buf.st_mode))
{
printf("-");
}
else if(S_ISDIR(buf.st_mode))
{
printf("d");
color = BLUE;
}
else if(S_ISCHR(buf.st_mode))
{
printf("c");
color = YELLOW;
}
else if(S_ISBLK(buf.st_mode))
{
printf("b");
color = YELLOW;
}
else if(S_ISFIFO(buf.st_mode))
{
printf("f");
}
else if(S_ISSOCK(buf.st_mode))
{
printf("s");
}
if(buf.st_mode&S_IRUSR)
{
printf("r");
}
else
{
printf("-");
}
if(buf.st_mode&S_IWUSR)
{
printf("w");
}
else
{
printf("-");
}
if(buf.st_mode&S_IXUSR)
{
printf("x");
color = GREEN;
}
else
{
printf("-");
}
if(buf.st_mode&S_IRGRP)
{
printf("r");
}
else
{
printf("-");
}
if(buf.st_mode&S_IWGRP)
{
printf("w");
}
else
{
printf("-");
}
if(buf.st_mode&S_IXGRP)
{
printf("x");
}
else
{
printf("-");
}
if(buf.st_mode&S_IROTH)
{
printf("r");
}
else
{
printf("-");
}
if(buf.st_mode&S_IWOTH)
{
printf("w");
}
else
{
printf("-");
}
if(buf.st_mode&S_IXOTH)
{
printf("x");
}
else
{
printf("-");
}
putchar(' ');
if (S_ISDIR(buf.st_mode))
{
color = BLUE;
}
printf("%d ",(int)buf.st_nlink);
print_info(buf);
print_volume(buf.st_size, isPARAM_h);
strcpy(buf_time,ctime(&buf.st_mtime));
buf_time[strlen(buf_time)-1]='\0';
printf("%s ",buf_time);
print_name(name, color);
putchar('\n');
}
void print_name(const char *name, int color)
{
if (color == GREEN)
{
printf("\033[1m\033[32m%-s\033[0m",name);
}
else if (color == BLUE)
{
printf("\033[1m\033[34m%-s\033[0m",name);
}
else if (color == WHITE)
{
printf("%-s",name);
}
else if (color == LBLUE)
{
printf("\033[1m\033[36m%-s\033[0m",name);
}
else if (color == YELLOW)
{
printf("\033[1m\033[33m%-s\033[0m",name);
}
}
int get_color(struct stat buf)
{
int color = WHITE;
if (S_ISLNK(buf.st_mode))
{
color = LBLUE;
}
else if(S_ISDIR(buf.st_mode))
{
color = BLUE;
}
else if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode))
{
color = YELLOW;
}
else if (buf.st_mode&S_IXUSR)
{
color = GREEN;
}
return color;
}
void print_volume(long int volume, int isPARAM_h)
{
if (isPARAM_h == YES)
{
if (volume < KB)
{
printf("%5ld ", volume);
}
else if (volume < MB)
{
printf("%4.1lfK ", volume*1.0/KB);
}
else if (volume < GB)
{
printf("%4.1lfM ", volume*1.0/MB);
}
else
{
printf("%4.1lfG ", volume*1.0/GB);
}
}
else
{
printf("%5ld ", volume);
}
}
void print_info(struct stat buf)
{
if (isPARAM_n == NO)
{
struct passwd *pwd;
struct group *grp;
pwd=getpwuid(buf.st_uid);
grp=getgrgid(buf.st_gid);
printf("%s ",pwd->pw_name);
printf("%s ",grp->gr_name);
}
else
{
printf("%4d ", buf.st_uid);
printf("%4d ", buf.st_gid);
}
}
static void mask_ctrl_c()
{
sigset_t intmask;
sigemptyset(&intmask);
sigaddset(&intmask,SIGINT);
sigprocmask(SIG_BLOCK,&intmask,NULL);
}
void display_dir_R(int flag_param, const char *path)
{
DIR *dir;
struct dirent *ptr;
char temp_name[PATH_MAX+1];
printf("%s:\n", path);
display_dir(flag_param, path);
putchar('\n');
if ((dir = opendir(path)) == NULL)
{
if (errno != 13)
my_err("opendir", __LINE__);
else
return;
}
int len = strlen(path);
while ((ptr = readdir(dir)) != NULL)
{
if (ptr->d_type == DT_DIR && (ptr->d_name[0] != '.'))
{
strncpy(temp_name, path, len);
temp_name[len] = '\0';
strcat(temp_name, ptr->d_name);
temp_name[len+strlen(ptr->d_name)] = '/';
temp_name[len+strlen(ptr->d_name)+1] = '\0';
display_dir_R(flag_param, temp_name);
}
}
closedir(dir);
return;
}