📄 ls.c
字号:
if (field & F_ATIME) { CMP= atimecmp; } else { CMP= mtimecmp; } if (present('r')) { rCMP= CMP; CMP= revcmp; } mergesort(al); } /* Separate by file type if so desired. */ if (field & F_TYPE) { CMP= typecmp; mergesort(al); } }}struct file *newfile(char *name)/* Create file structure for given name. */{ struct file *new; new= (struct file *) allocate(sizeof(*new)); new->name= strcpy((char *) allocate(strlen(name)+1), name); return new;}void pushfile(struct file **flist, struct file *new)/* Add file to the head of a list. */{ new->next= *flist; *flist= new;}void delfile(struct file *old)/* Release old file structure. */{ free((void *) old->name); free((void *) old);}struct file *popfile(struct file **flist)/* Pop file off top of file list. */{ struct file *f; f= *flist; *flist= f->next; return f;}int dotflag(char *name)/* Return flag that would make ls list this name: -a or -A. */{ if (*name++ != '.') return 0; switch (*name++) { case 0: return 'a'; /* "." */ case '.': if (*name == 0) return 'a'; /* ".." */ default: return 'A'; /* ".*" */ }}int adddir(struct file **aflist, char *name)/* Add directory entries of directory name to a file list. */{ DIR *d; struct dirent *e; if (access(name, 0) < 0) { report(name); return 0; } if ((d= opendir(name)) == nil) { report(name); return 0; } while ((e= readdir(d)) != nil) { if (e->d_ino != 0 && present(dotflag(e->d_name))) { pushfile(aflist, newfile(e->d_name)); aflist= &(*aflist)->next; } } closedir(d); return 1;}off_t countblocks(struct file *flist)/* Compute total block count for a list of files. */{ off_t cb = 0; while (flist != nil) { switch (flist->mode & S_IFMT) { case S_IFDIR: case S_IFREG:#ifdef S_IFLNK case S_IFLNK:#endif cb += nblocks(flist); } flist= flist->next; } return cb;}void printname(char *name)/* Print a name with control characters as '?' (unless -q). The terminal is * assumed to be eight bit clean. */{ int c, q= present('q'); while ((c= (unsigned char) *name++) != 0) { if (q && (c <= ' ' || c == 0177)) c= '?'; putchar(c); }}int mark(struct file *f, int doit){ int c; if (!(field & F_MARK)) return 0; switch (f->mode & S_IFMT) { case S_IFDIR: c= '/'; break;#ifdef S_IFIFO case S_IFIFO: c= '|'; break;#endif#ifdef S_IFLNK case S_IFLNK: c= '@'; break;#endif#ifdef S_IFSOCK case S_IFSOCK: c= '='; break;#endif case S_IFREG: if (f->mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { c= '*'; break; } default: c= 0; } if (doit && c != 0) putchar(c); return c;}int colwidth[MAXCOLS]; /* Need colwidth[i] spaces to print column i. */int sizwidth[MAXCOLS]; /* Spaces for the size field in a -X print. */int namwidth[MAXCOLS]; /* Name field. */int maxise(int *aw, int w)/* Set *aw to the larger of it and w. Then return it. */{ if (w > *aw) *aw= w; return *aw;}static int nsp= 0; /* This many spaces have not been printed yet. */#define spaces(n) (nsp= (n))#define terpri() (nsp= 0, putchar('\n')) /* No trailing spaces */void print1(struct file *f, int col, int doit)/* Either compute the number of spaces needed to print file f (doit == 0) or * really print it (doit == 1). */{ int width= 0, n; char *p; while (nsp>0) { putchar(' '); nsp--; }/* Fill gap between two columns */ if (field & F_INODE) { if (doit) printf("%5d ", f->ino); else width+= 6; } if (field & F_BLOCKS) { if (doit) printf("%4ld ", nblk2k(nblocks(f))); else width+= 5; } if (field & F_MODE) { if (doit) { printf("%s ", permissions(f)); } else { width+= (field & F_EXTRA) ? 5 : 11; } } if (field & F_EXTRA) { p= cxsize(f); n= strlen(p)+1; if (doit) { n= sizwidth[col] - n; while (n > 0) { putchar(' '); --n; } printf("%s ", p); } else { width+= maxise(&sizwidth[col], n); } } if (field & F_LONG) { if (doit) { printf("%2u ", (unsigned) f->nlink); if (!(field & F_GROUP)) { printf("%-8s ", uidname(f->uid)); } printf("%-8s ", gidname(f->gid)); switch (f->mode & S_IFMT) { case S_IFBLK: case S_IFCHR:#ifdef S_IFMPB case S_IFMPB:#endif#ifdef S_IFMPC case S_IFMPC:#endif printf("%3d, %3d ", major(f->rdev), minor(f->rdev)); break; default: printf("%8ld ", (long) f->size); } printf("%s ", timestamp(f)); } else { width += (field & F_GROUP) ? 34 : 43; } } n= strlen(f->name); if (doit) { printname(f->name); if (mark(f, 1) != 0) n++;#ifdef S_IFLNK if ((field & F_LONG) && (f->mode & S_IFMT) == S_IFLNK) { char *buf; int r, didx; buf= (char *) allocate(((size_t) f->size + 1) * sizeof(buf[0])); addpath(&didx, f->name); r= readlink(path, buf, (int) f->size); delpath(didx); if (r > 0) buf[r] = 0; else r=1, strcpy(buf, "?"); printf(" -> "); printname(buf); free((void *) buf); n+= 4 + r; }#endif spaces(namwidth[col] - n); } else { if (mark(f, 0) != 0) n++;#ifdef S_IFLNK if ((field & F_LONG) && (f->mode & S_IFMT) == S_IFLNK) { n+= 4 + (int) f->size; }#endif width+= maxise(&namwidth[col], n + NSEP); maxise(&colwidth[col], width); }}int countfiles(struct file *flist)/* Return number of files in the list. */{ int n= 0; while (flist != nil) { n++; flist= flist->next; } return n;}struct file *filecol[MAXCOLS]; /* filecol[i] is list of files for column i. */int nfiles, nlines; /* # files to print, # of lines needed. */int columnise(struct file *flist, int nplin)/* Chop list of files up in columns. Note that 3 columns are used for 5 files * even though nplin may be 4, filecol[3] will simply be nil. */{ int i, j; nlines= (nfiles + nplin - 1) / nplin; /* nlines needed for nfiles */ filecol[0]= flist; for (i=1; i<nplin; i++) { /* Give nlines files to each column. */ for (j=0; j<nlines && flist != nil; j++) flist= flist->next; filecol[i]= flist; }}int print(struct file *flist, int nplin, int doit)/* Try (doit == 0), or really print the list of files over nplin columns. * Return true if it can be done in nplin columns or if nplin == 1. */{ register struct file *f; register int i, totlen; columnise(flist, nplin); if (!doit) { if (nplin==1 && !(field & F_EXTRA)) return 1; /* No need to try 1 column. */ for (i=0; i<nplin; i++) { colwidth[i]= sizwidth[i]= namwidth[i]= 0; } } while (--nlines >= 0) { totlen=0; for (i=0; i<nplin; i++) { if ((f= filecol[i]) != nil) { filecol[i]= f->next; print1(f, i, doit); } if (!doit && nplin>1) { /* See if this line is not too long. */ totlen+= colwidth[i]; if (totlen > ncols+NSEP) return 0; } } if (doit) terpri(); } return 1;}enum depth { SURFACE, SURFACE1, SUBMERGED };enum state { BOTTOM, SINKING, FLOATING };void listfiles(struct file *flist, enum depth depth, enum state state)/* Main workhorse of ls, it sorts and prints the list of files. Flags: * depth: working with the command line / just one file / listing dir. * state: How "recursive" do we have to be. */{ struct file *dlist= nil, **afl= &flist, **adl= &dlist; int nplin; static int white = 1; /* Nothing printed yet. */ /* Flush everything previously printed, so new error output will * not intermix with files listed earlier. */ fflush(stdout); if (field != 0 || state != BOTTOM) { /* Need stat(2) info. */ while (*afl != nil) { static struct stat st; int r, didx; addpath(&didx, (*afl)->name); if ((r= status(path, &st)) < 0#ifdef S_IFLNK && (status == lstat || lstat(path, &st) < 0)#endif ) { if (depth != SUBMERGED || errno != ENOENT) report((*afl)->name); delfile(popfile(afl)); } else { setstat(*afl, &st); afl= &(*afl)->next; } delpath(didx); } } sort(&flist); if (depth == SUBMERGED && (field & (F_BLOCKS | F_LONG))) { printf("total %ld\n", nblk2k(countblocks(flist))); } if (state == SINKING || depth == SURFACE1) { /* Don't list directories themselves, list their contents later. */ afl= &flist; while (*afl != nil) { if (((*afl)->mode & S_IFMT) == S_IFDIR) { pushfile(adl, popfile(afl)); adl= &(*adl)->next; } else { afl= &(*afl)->next; } } } if ((nfiles= countfiles(flist)) > 0) { /* Print files in how many columns? */ nplin= !present('C') ? 1 : nfiles < MAXCOLS ? nfiles : MAXCOLS; while (!print(flist, nplin, 0)) nplin--; /* Try first */ print(flist, nplin, 1); /* Then do it! */ white = 0; } while (flist != nil) { /* Destroy file list */ if (state == FLOATING && (flist->mode & S_IFMT) == S_IFDIR) { /* But keep these directories for ls -R. */ pushfile(adl, popfile(&flist)); adl= &(*adl)->next; } else { delfile(popfile(&flist)); } } while (dlist != nil) { /* List directories */ if (dotflag(dlist->name) != 'a' || depth != SUBMERGED) { int didx; addpath(&didx, dlist->name); flist= nil; if (adddir(&flist, path)) { if (depth != SURFACE1) { if (!white) putchar('\n'); printf("%s:\n", path); white = 0; } listfiles(flist, SUBMERGED, state == FLOATING ? FLOATING : BOTTOM); } delpath(didx); } delfile(popfile(&dlist)); }}int main(int argc, char **argv){ struct file *flist= nil, **aflist= &flist; enum depth depth; char *lsflags; struct winsize ws; uid= geteuid(); gid= getegid(); if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++; argv++; if (strcmp(arg0, "ls") != 0) { char *p= arg0+1; while (*p != 0) { if (strchr(arg0flag, *p) != nil) *p += 'A' - 'a'; p++; } setflags(arg0+1); } while (*argv != nil && (*argv)[0] == '-') { if ((*argv)[1] == '-' && (*argv)[2] == 0) { argv++; break; } setflags(*argv++ + 1); } istty= isatty(1); if (istty && (lsflags= getenv("LSOPTS")) != nil) { if (*lsflags == '-') lsflags++; setflags(lsflags); } if (!present('1') && !present('C') && !present('l') && (istty || present('M') || present('X') || present('F')) ) setflags("C"); if (istty) setflags("q"); if (SUPER_ID == 0 || present('a')) setflags("A"); if (present('i')) field|= F_INODE; if (present('s')) field|= F_BLOCKS; if (present('M')) field|= F_MODE; if (present('X')) field|= F_EXTRA|F_MODE; if (present('t')) field|= F_BYTIME; if (present('u')) field|= F_ATIME; if (present('c')) field|= F_CTIME; if (present('l')) field= (field | F_MODE | F_LONG) & ~F_EXTRA; if (present('g')) field= (field | F_MODE | F_LONG | F_GROUP) & ~F_EXTRA; if (present('F')) field|= F_MARK; if (present('T')) field|= F_TYPE; if (present('d')) field|= F_DIR;#ifdef S_IFLNK status= present('L') ? stat : lstat;#endif if (present('C')) { int t= istty ? 1 : open("/dev/tty", O_WRONLY); if (t >= 0 && ioctl(t, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0) ncols= ws.ws_col - 1; if (t != 1 && t != -1) close(t); } depth= SURFACE; if (*argv == nil) { if (!(field & F_DIR)) depth= SURFACE1; pushfile(aflist, newfile(".")); } else { if (argv[1] == nil && !(field & F_DIR)) depth= SURFACE1; do { pushfile(aflist, newfile(*argv++)); aflist= &(*aflist)->next; } while (*argv!=nil); } listfiles(flist, depth, (field & F_DIR) ? BOTTOM : present('R') ? FLOATING : SINKING); exit(ex);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -