|
|
1.1 root 1: /*
2: * ls.c
3: * 03/17/92
4: * List structure
5: */
6:
7: #include <stdio.h>
8: #include <canon.h>
9: #include <time.h>
10: #include <sys/stat.h>
11: #include <sys/dir.h>
12: #include <pwd.h>
13: #include <grp.h>
14: #include <string.h>
15:
16: #define BSIZE BUFSIZ /* Disc blocking factor for '-s' */
17: #define NBN 128 /* Number of blocks in an indirect block */
18: #define ND 10 /* Number of direct blocks */
19: #define NI 1 /* Number of indirect blocks */
20: #define NII 1 /* Number of double indirect blocks */
21: #define NIII 1 /* Number of triple indirect blocks */
22:
23: #define MTIME 0 /* Use modify time */
24: #define ATIME 1 /* Use access time */
25: #define CTIME 2 /* Use create time */
26:
27: #define GAP 1 /* Space between Multi-column entries */
28: #define MAXLEN 78 /* Maximum line length */
29: #define MAXARG 4096 /* Maximum # of args stored for -C sort */
30: #define MAXDIR 128 /* Maximum # of subdirectories for -R */
31: #define MAXWID 12 /* Default max width for columns */
32: #define MAXNBUF 80 /* Maximum namebuf length */
33:
34: #define OLD (60L*60*24*365) /* old form of dates (seconds) */
35:
36: /*
37: * The following flags are mutually exclusive.
38: * The rightmost one on the command line wins.
39: */
40: #define EXCLUDE_Clmnox Cflag = lflag = mflag = nflag = oflag = xflag = 0
41:
42: int aflag; /* List all entries (including "." & "..") */
43: int bflag; /* Print non-raphic chars in octal */
44: int Cflag; /* Multicolumn, sorted down the columns */
45: int dflag; /* Treat directories like files */
46: int fflag; /* Force something to look like a directory */
47: int Fflag; /* Print / after dirs, * after executables */
48: int gflag; /* Print gid vs. uid */
49: int iflag; /* Give i-number */
50: int lflag; /* Longer format */
51: int mflag; /* Stream format output */
52: int nflag; /* Same as -l except GID and UID are #s */
53: int oflag; /* Same as -l except group is not printed */
54: int pflag; /* Print a / after directories */
55: int qflag; /* Force non-graphic chars into ? mode */
56: int Rflag; /* List directories recursively */
57: int rflag; /* Reverse order of sort */
58: int sflag; /* Print size in bytes */
59: int tflag = MTIME; /* Which time to display and sort on */
60: int xflag; /* Multicolumn, sort across the columns */
61: int sortflg; /* On for sort by time, 0 for by name */
62: int myuid; /* User id for selecting .* suppression */
63:
64: int linesiz = 0; /* Keep track of how much printed for -m */
65: int first = 1; /* First in stream format? */
66: int maxwidth = MAXWID; /* Longest string in multi-column format */
67: int ncols = 1; /* Number of columns */
68: int nrows = 1; /* Number of rows */
69: int offset = 0; /* How far to move pointer to print next entry*/
70: int nlast = 0; /* Number of cols in last row */
71: int ccol = 0; /* Current Column */
72: time_t curtime;
73:
74: char obuf[BUFSIZ];
75:
76: char *deflist[] = {
77: ".",
78: NULL
79: };
80:
81: char *namelist[MAXARG]; /* store file names for column output */
82:
83: typedef struct dlist{
84: char *name;
85: fsize_t size;
86: } DLIST;
87:
88: typedef struct ls {
89: char ls_dname[DIRSIZ+1];
90: char *ls_name;
91: char *ck_name;
92: ino_t ls_ino;
93: short ls_mode;
94: short ls_uid;
95: short ls_gid;
96: short ls_nlink;
97: fsize_t ls_size;
98: dev_t ls_rdev; /* Real device */
99: time_t ls_time; /* One of atime, mtime, ctime */
100: } LS;
101:
102: int (*qcomp)();
103: int qtcomp();
104: int qncomp();
105: int qdncomp();
106:
107: char *alloc();
108: void fatal();
109: char *getuname();
110: char *getgname();
111: char *getname();
112: char *getflag();
113:
114: main(argc, argv)
115: char *argv[];
116: {
117: register char *ap;
118: register int es;
119:
120: setbuf(stdout, obuf);
121:
122: /*
123: * recognize variations on the name "ls" as implying which
124: * flags to set by default.
125: * basename flags
126: * l -l
127: * lc -C recognized, but conflicts with COHERENT /bin/lc
128: * lf -CF
129: * lr -CR
130: * lx -x
131: */
132: if ((ap = strrchr(argv[0], '/')) == NULL)
133: ap = argv[0];
134: else
135: ++ap;
136: if (streq(ap, "l"))
137: lflag = 1;
138: else if (streq(ap, "lc"))
139: Cflag = 1;
140: else if (streq(ap, "lf"))
141: Cflag = Fflag = 1;
142: else if (streq(ap, "lr"))
143: Cflag = Rflag = 1;
144: else if (streq(ap, "lx"))
145: xflag = 1;
146:
147: while (argc>1 && *argv[1]=='-') {
148: for (ap=&argv[1][1]; *ap; ap++)
149: switch (*ap) {
150: case 'a':
151: aflag = 1;
152: break;
153:
154: case 'b':
155: bflag = 1;
156: break;
157:
158: case 'c':
159: tflag = CTIME;
160: break;
161:
162: case 'C':
163: EXCLUDE_Clmnox;
164: Cflag = 1;
165: break;
166:
167: case 'd':
168: dflag = 1;
169: break;
170:
171: case 'F':
172: Fflag = 1;
173: break;
174:
175: case 'f':
176: aflag = fflag = 1;
177: break;
178:
179: case 'g':
180: gflag = 1;
181: break;
182:
183: case 'i':
184: iflag = 1;
185: break;
186:
187: case 'l':
188: EXCLUDE_Clmnox;
189: lflag = 1;
190: break;
191:
192: case 'm':
193: EXCLUDE_Clmnox;
194: mflag = 1;
195: break;
196:
197: case 'n':
198: EXCLUDE_Clmnox;
199: nflag = 1;
200: break;
201:
202: case 'o':
203: EXCLUDE_Clmnox;
204: oflag = 1;
205: break;
206:
207: case 'p':
208: pflag = 1;
209: break;
210:
211: case 'q':
212: qflag = 1;
213: break;
214:
215: case 'r':
216: rflag = 1;
217: break;
218:
219: case 'R':
220: Rflag = 1;
221: break;
222:
223: case 's':
224: sflag = 1;
225: break;
226:
227: case 't':
228: sortflg = 1;
229: break;
230:
231: case 'u':
232: tflag = ATIME;
233: break;
234:
235: case 'x':
236: EXCLUDE_Clmnox;
237: xflag = 1;
238: break;
239:
240: default:
241: usage();
242: }
243: argc--;
244: argv++;
245: }
246: if (fflag)
247: lflag = sflag = 0;
248: time(&curtime);
249: myuid = getuid();
250: qcomp = (sortflg) ? qtcomp : qncomp;
251: es = (argc > 1) ? ls(argv+1, argc-1) : ls(deflist, 1);
252: exit(es);
253: }
254:
255: /*
256: * Do 'ls' on one file or directory.
257: * 'narg' is the number of names in 'flist'
258: * to determine special output format.
259: */
260: ls(flist, narg)
261: register char **flist;
262: int narg;
263: {
264: register int estat = 0;
265: register LS *lsp;
266: register LS *arena;
267: LS *asavep;
268: int Cargs = 0;
269: struct stat sb;
270:
271: arena = (LS *)alloc(narg*sizeof(LS),"arena");
272: asavep = arena;
273: for ( ; *flist!=NULL; flist++) {
274: if (stat(*flist, &sb) < 0) {
275: perror(*flist);
276: estat = 1;
277: continue;
278: }
279: astore(*flist, &sb, asavep++);
280: }
281: qsort(arena, asavep-arena, sizeof(LS), qcomp);
282: if (qcomp == qncomp)
283: qcomp = qdncomp;
284: if (xflag || Cflag)
285: ncols = MAXLEN/(maxwidth+GAP);
286:
287: for (lsp = arena; lsp < asavep; lsp++) {
288: if (fflag)
289: continue;
290: if ((lsp->ls_mode & S_IFMT) == S_IFDIR && !dflag)
291: continue;
292: if (Cflag)
293: svname(lsp->ck_name,Cargs++);
294: else if (xflag)
295: prcolh(lsp->ck_name);
296: else
297: prstuff(lsp->ls_name, lsp);
298: }
299: if (Cflag && Cargs)
300: prnames(Cargs);
301: maxwidth = MAXWID;
302: linesiz = 0;
303: for (lsp = arena; lsp < asavep; lsp++) {
304: if (dflag || (lsp->ls_mode&S_IFMT)!=S_IFDIR)
305: continue;
306: if (narg > 1)
307: printf("\n%s:\n", lsp->ls_name);
308: lsdir(lsp->ls_name,lsp->ls_size);
309: freename(lsp);
310: }
311: free(arena);
312: if ((mflag && linesiz) || ((Cflag || xflag) && ccol)){
313: putchar('\n');
314: ccol = 0;
315: linesiz = 0;
316: }
317: return estat;
318: }
319:
320: /*
321: * Print for all options except -C and -x
322: */
323: prstuff(file, lsp)
324: char *file;
325: register LS *lsp;
326: {
327: register char *cp;
328: register spcl = 0;
329:
330: if (iflag)
331: printf("%5u ", lsp->ls_ino);
332: if (sflag) {
333: prsize(lsp);
334: putchar(' ');
335: }
336: if (lflag || oflag || nflag) {
337: switch (lsp->ls_mode & S_IFMT) {
338: case S_IFREG:
339: putchar('-');
340: break;
341:
342: case S_IFDIR:
343: putchar('d');
344: break;
345:
346: case S_IFCHR:
347: putchar('c');
348: spcl++;
349: break;
350:
351: case S_IFBLK:
352: putchar('b');
353: spcl++;
354: break;
355:
356: case S_IFPIP:
357: putchar('p');
358: break;
359:
360: case S_IFMPB:
361: case S_IFMPC:
362: putchar('m');
363: spcl++;
364: break;
365:
366: default:
367: putchar('x');
368: }
369: prmode((lsp->ls_mode>>6)&07, lsp->ls_mode&S_ISUID);
370: prmode((lsp->ls_mode>>3)&07, lsp->ls_mode&S_ISGID);
371: prmode(lsp->ls_mode&07, 0);
372: if (lsp->ls_mode & S_ISVTX)
373: putchar('t');
374: else
375: putchar(' ');
376: printf("%2d ", lsp->ls_nlink);
377: if (!gflag){
378: if (!nflag){
379: cp = getuname(lsp->ls_uid);
380: if (cp == NULL)
381: printf("%-10d ", lsp->ls_uid);
382: else
383: printf("%-10s ", cp);
384: } else
385: printf("%-10d ", lsp->ls_uid);
386: }
387: if (!oflag){
388: if (!nflag){
389: cp = getgname(lsp->ls_gid);
390: if (cp == NULL)
391: printf("%-10d ", lsp->ls_gid);
392: else
393: printf("%-10s ", cp);
394: } else
395: printf("%-10d ", lsp->ls_gid);
396: }
397: if (!spcl)
398: printf("%7ld", lsp->ls_size);
399: else
400: printf("%3d %3d", major(lsp->ls_rdev),
401: minor(lsp->ls_rdev));
402: prtime(&lsp->ls_time);
403: }
404: if (!mflag ){
405: prname(file);
406: prflag(lsp->ls_mode);
407: putchar('\n');
408: }
409: else
410: prstream(file,lsp->ls_mode);
411: }
412:
413: /*
414: * Print out a filesize from a ls store buffer.
415: * This size (in BSIZE units or blocks) takes
416: * into account indirect blocks.
417: * However this should be done in a more general manner.
418: */
419: prsize(lsp)
420: register LS *lsp;
421: {
422: long blocks, size;
423: register ftype;
424:
425: size = 0;
426: ftype = lsp->ls_mode & S_IFMT;
427: if (ftype==S_IFREG || ftype==S_IFDIR || ftype==S_IFPIP) {
428: size = blocks = (lsp->ls_size+BSIZE-1)/BSIZE;
429: if (blocks > ND) {
430: size++;
431: blocks -= ND;
432: if (blocks > NBN*NI) {
433: blocks -= NBN*NI;
434: size += 2 + blocks/NBN;
435: }
436: }
437: }
438: printf("%4ld", size);
439: return size;
440: }
441:
442: /*
443: * Print a time (if it is older than
444: * one year) print the year instead
445: * of the mm:ss part.
446: */
447: prtime(tp)
448: register time_t *tp;
449: {
450: register struct tm *tmp;
451: register struct tm *now;
452: register int thisyear;
453: register char *cp;
454:
455: now = localtime(&curtime);
456: thisyear = now->tm_year;
457: cp = asctime(tmp = localtime(tp));
458: if (thisyear > tmp->tm_year) {
459: cp[10] = '\0';
460: printf(" %s %d ", cp, tmp->tm_year+1900);
461: } else {
462: cp[16] = '\0';
463: printf(" %s ", cp);
464: }
465: }
466:
467: /*
468: * Print 'rwx' type modes out.
469: */
470: prmode(m, suid)
471: int m;
472: int suid;
473: {
474: m <<= 6;
475: putchar(m&S_IREAD ? 'r' : '-');
476: putchar(m&S_IWRITE ? 'w' : '-');
477: if (suid)
478: putchar('s');
479: else
480: putchar(m&S_IEXEC ? 'x' : '-');
481: }
482:
483: /*
484: * Get a user name. Either look
485: * in password or group file depending
486: * on 'gflag'.
487: */
488: char *
489: getuname(uid)
490: short uid;
491: {
492: register struct passwd *pwp;
493: static id = -1;
494: static char *name;
495:
496: if (uid == id)
497: return name;
498: id = uid;
499: name = NULL;
500: if ((pwp=getpwuid( uid)) != NULL)
501: name = pwp->pw_name;
502: return name;
503: }
504:
505: /*
506: * Get group name.
507: * Look in group file .
508: */
509: char *
510: getgname(uid)
511: short uid;
512: {
513: register struct group *grp;
514: static id = -1;
515: static char *name;
516:
517: if (uid == id)
518: return name;
519: id = uid;
520: name = NULL;
521: if ((grp=getgrgid( uid)) != NULL)
522: name = grp->gr_name;
523: return name;
524: }
525:
526: /*
527: * List out the files in a directory
528: * If 'fflag' is set, it may not be
529: * but consider it one anyway.
530: */
531: lsdir(dir,dirsize)
532: char *dir;
533: fsize_t dirsize;
534: {
535: int fd, Cargs = 0, Rargs = 0;
536: struct stat sb;
537: LS *lsp;
538: register char *np1, *np2;
539: register int n;
540: register struct direct *dp;
541: register int nb;
542: unsigned size;
543: char *curname;
544: char *namebuf; /* Buffer for constructing names */
545: char *dirbuf; /* Buffer for reading directories */
546: DLIST **dirlist;
547: LS *dsaved;
548: LS *dsavep;
549:
550: if ((fd = open(dir, 0)) < 0) {
551: fprintf(stderr, "%s: cannot read\n", dir);
552: return;
553: }
554: if (!fflag) {
555: size = dirsize/sizeof (struct direct) * sizeof (LS);
556: dsaved = alloc(size,"dsaved");
557: dsavep = dsaved;
558: }
559: if (Rflag)
560: dirlist = (char **)alloc(MAXDIR * sizeof(char *), "dirlist");
561: dirbuf = alloc(BSIZE,"dirbuf");
562: namebuf = alloc(MAXNBUF,"namebuf");
563: curname = alloc(DIRSIZ+1,"curname");
564: lsp = alloc(sizeof(LS),"lsp");
565: if (mflag)
566: first = 1; /* For stream option */
567: while ((nb = read(fd, dirbuf, BSIZE )) > 0)
568: for (dp=dirbuf; dp<(dirbuf+nb); dp++) {
569: if (dp->d_ino == 0)
570: continue;
571: np1 = dp->d_name;
572: if (aflag == 0 && *np1++ == '.') {
573: if (myuid != 0)
574: continue;
575: if (*np1=='\0' || (*np1++=='.' && *np1=='\0'))
576: continue;
577: }
578: if (iflag) {
579: sb.st_ino = dp->d_ino;
580: canino(sb.st_ino);
581: }
582: np2 = curname;
583: np1 = dp->d_name;
584: n = DIRSIZ;
585: do {
586: *np2++ = *np1++;
587: } while (--n);
588: *np2 = '\0';
589: if (lflag || xflag || Cflag || sflag || tflag || Rflag ||
590: sortflg || pflag || Fflag || oflag || nflag) {
591: np2 = namebuf;
592: np1 = dir;
593: while (*np2++ = *np1++)
594: ;
595: np2-=2;
596: if (*np2++ != '/')
597: *np2++ = '/';
598: np1 = curname;
599: while (*np2++ = *np1++)
600: ;
601: if (stat(namebuf, &sb) < 0) {
602: fprintf(stderr, "%s: cannot stat\n", curname);
603: continue;
604: }
605: }
606: convert(&sb, lsp);
607: if (Rflag
608: && ((lsp->ls_mode & S_IFMT) == S_IFDIR)
609: && strcmp(curname, ".") != 0
610: && strcmp(curname, "..") != 0 ) {
611: if (Rargs >= MAXDIR)
612: fatal("too many subdirectories");
613: dirlist[Rargs] = alloc(sizeof(DLIST),"dirlist");
614: dirlist[Rargs]->name = alloc(strlen(namebuf) + 1,"name");
615: strcpy(dirlist[Rargs]->name,namebuf);
616: dirlist[Rargs++]->size = lsp->ls_size;
617: } else if (fflag) {
618: ncols = MAXLEN/(maxwidth+GAP);
619: if (Cflag)
620: svname(curname, Cargs++);
621: else if (xflag)
622: prcolh(curname);
623: else
624: prstuff(curname, lsp);
625: } else {
626: store(curname, &sb,dsavep++);
627: }
628: }
629: free(lsp);
630: free(curname);
631: free(namebuf);
632: free(dirbuf);
633: if (!fflag) {
634: ncols = MAXLEN/(maxwidth+GAP);
635: output(dsaved,dsavep);
636: } else if (Cflag && Cargs)
637: prnames(Cargs);
638: if (!fflag)
639: for (lsp = dsaved; lsp < dsavep; lsp++)
640: freename(lsp);
641: if ((mflag && linesiz) || ((Cflag || xflag) && ccol)){
642: putchar('\n');
643: ccol = 0;
644: linesiz = 0;
645: }
646: if (!fflag)
647: free(dsaved);
648: close(fd);
649: maxwidth = MAXWID;
650: if (Rflag && Rargs){
651: for(n=0;n<Rargs;n++){
652: putchar('\n');
653: printf("%s:\n",dirlist[n]->name);
654: lsdir(dirlist[n]->name,dirlist[n]->size);
655: free(dirlist[n]->name);
656: }
657: for(n=0;n<Rargs;n++)
658: free(dirlist[n]);
659: }
660: if (Rflag)
661: free(dirlist);
662: }
663:
664: /*
665: * Store data away for intra-directory
666: * sorting.
667: */
668: store(name, sbp,lsp)
669: char *name;
670: register struct stat *sbp;
671: register LS *lsp;
672: {
673: convert(sbp, lsp);
674: if (xflag || Cflag)
675: cstore(lsp,name);
676: strncpy(lsp->ls_dname, name, DIRSIZ+1);
677: }
678:
679: /*
680: * Store each argument away for inter-directory sorting.
681: * Sets lsp->ls_name to allocated name.
682: */
683: astore(name, sbp,lsp)
684: char *name;
685: register struct stat *sbp;
686: register LS *lsp;
687: {
688: convert(sbp, lsp);
689: if (xflag || Cflag)
690: cstore(lsp,name);
691: lsp->ls_name = alloc(strlen(name)+1,"ls->name");
692: strcpy(lsp->ls_name, name);
693: }
694:
695: /*
696: * Free allocated name fields.
697: */
698: freename(lsp) register LS *lsp;
699: {
700: if (lsp->ls_name != NULL)
701: free(lsp->ls_name);
702: if (lsp->ck_name != NULL)
703: free(lsp->ck_name);
704: }
705:
706: /*
707: * Convert a stat buffer into an ls store
708: * buffer.
709: */
710: convert(sbp, lsp)
711: register struct stat *sbp;
712: register LS *lsp;
713: {
714: lsp->ls_ino = sbp->st_ino;
715: lsp->ls_mode = sbp->st_mode;
716: lsp->ls_nlink = sbp->st_nlink;
717: lsp->ls_uid = sbp->st_uid;
718: lsp->ls_gid = sbp->st_gid;
719: lsp->ls_size = sbp->st_size;
720: lsp->ls_rdev = sbp->st_rdev;
721: if (tflag == CTIME)
722: lsp->ls_time = sbp->st_ctime;
723: else if (tflag == MTIME)
724: lsp->ls_time = sbp->st_mtime;
725: else if (tflag == ATIME)
726: lsp->ls_time = sbp->st_atime;
727: }
728:
729: /*
730: * Sort, output and free up space from
731: * the current directory being considered.
732: */
733: output(start,stop)
734: LS *start;
735: LS *stop;
736: {
737: register LS *lsp, *lse;
738: register unsigned nel;
739: int Cargs = 0;
740: nel = stop - start;
741: qsort(start, nel, sizeof (LS), qcomp);
742: for (lsp=start, lse=stop; lsp < lse; lsp++){
743: if (Cflag)
744: svname(lsp->ck_name,Cargs++);
745: else if (xflag)
746: prcolh(lsp->ck_name);
747: else
748: prstuff(lsp->ls_dname, lsp);
749: }
750: if (Cflag && Cargs)
751: prnames(Cargs);
752: }
753:
754: /*
755: * The following are the three qsort comparison routines:
756: * sort by time, sort by directory name, sort by full pathname.
757: * They can be used both in the argument sort and in each directory sort.
758: */
759:
760: /*
761: * Sort by time (either access, modify, or create setup elsewhere)
762: * (forward or backward).
763: */
764: qtcomp(lsp1, lsp2)
765: register LS *lsp1, *lsp2;
766: {
767: register int rval = 0;
768:
769: if (lsp1->ls_time < lsp2->ls_time)
770: rval++;
771: else if (lsp1->ls_time > lsp2->ls_time)
772: rval--;
773: return (rflag) ? -rval : rval;
774: }
775:
776: /*
777: * Sort by directory name.
778: * (forward or reverse).
779: */
780: qdncomp(lsp1, lsp2)
781: LS *lsp1, *lsp2;
782: {
783: register int rval;
784:
785: rval = strncmp(lsp1->ls_dname, lsp2->ls_dname, DIRSIZ);
786: return (rflag) ? -rval : rval;
787: }
788:
789: /*
790: * Sort by full pathname.
791: * (forward or reverse).
792: */
793: qncomp(lsp1, lsp2)
794: LS *lsp1, *lsp2;
795: {
796: register int rval;
797:
798: rval = strcmp(lsp1->ls_name, lsp2->ls_name);
799: return (rflag) ? -rval : rval;
800: }
801:
802: usage()
803: {
804: fprintf(stderr, "Usage: ls [-abcCdfFgilmnopqrRstux] [files ...]\n");
805: exit(1);
806: }
807:
808: is_x(m)
809: int m;
810: {
811: m <<= 6;
812: return m&S_IEXEC;
813: }
814:
815: /*
816: * Print non-graphic chars in octal or '?' format
817: * or as they are depending on which flag is set.
818: */
819: prname(s)
820: char *s;
821: {
822: if (bflag) {
823: while ( *s != '\0')
824: if ( *s >= ' ' && *s <= '~')
825: putchar(*s++);
826: else
827: printf("\\0%o",*s++);
828: } else if (qflag) {
829: while ( *s != '\0')
830: if ( *s >= ' ' && *s <= '~')
831: putchar(*s++);
832: else {
833: putchar('?');
834: *s++;
835: }
836: } else
837: printf(s);
838: }
839:
840: /*
841: * Print in stream format for -m option
842: */
843: prstream(s,m)
844: char *s;
845: short m;
846: {
847: register int sl;
848:
849: sl = strlen(s);
850: if ( (linesiz + sl) > MAXLEN ){
851: putchar(',');
852: putchar('\n');
853: prname(s);
854: linesiz = sl + prflag(m) + 1;
855: }
856: else if (!first) {
857: printf(", ");
858: prname(s);
859: linesiz += sl + prflag(m) + 2;
860: } else {
861: first = 0;
862: prname(s);
863: linesiz = sl + prflag(m);
864: }
865: }
866:
867: /*
868: * Prints flag if executable or directory and -F or -p flsg is set.
869: */
870: prflag(m)
871: short m;
872: {
873: if (pflag)
874: if((m & S_IFMT) == S_IFDIR){
875: putchar('/');
876: return 1;
877: }
878: if (Fflag) {
879: if((m & S_IFMT) == S_IFDIR) {
880: putchar('/');
881: return 1;
882: } else if (is_x(m>>6 & 07) ) {
883: putchar('*');
884: return 1;
885: } else if( is_x(m>>3 & 07) ) {
886: putchar('*');
887: return 1;
888: } else if( is_x(m & 07) ){
889: putchar('*');
890: return 1;
891: }
892: }
893: return 0;
894: }
895:
896: /*
897: * Returns flag if executable or directory and -F or -p flsg is set.
898: */
899: char *
900: getflag(m)
901: short m;
902: {
903: if (pflag) {
904: if((m & S_IFMT) == S_IFDIR)
905: return "/";
906: }
907: if (Fflag) {
908: if((m & S_IFMT) == S_IFDIR)
909: return "/";
910: else if( is_x(m>>6 & 07) )
911: return "*";
912: else if( is_x(m>>3 & 07) )
913: return "*";
914: else if( is_x(m & 07) )
915: return "*";
916: }
917: return "";
918: }
919:
920: /*
921: * Returns file name with non-graphic chars in octal or '?' format
922: * or as they are depending on which flag is set.
923: */
924: char *
925: getname(s)
926: char *s;
927: {
928: char tmp[80];
929: char *t;
930: int i = 0;
931: char buf[5];
932:
933: t = tmp;
934: if (bflag){
935: while (*s) {
936: if (*s >= ' ' && *s <= '~') {
937: *t++ = *s++;
938: } else {
939: sprintf(buf,"\\0%o",*s++);
940: while(buf[i] != '\0'){
941: *t++ = buf[i];
942: buf[i++] = '\0';
943: }
944: i=0;
945: }
946: }
947: *t = '\0';
948: } else if (qflag){
949: while ( *s != '\0')
950: if ( *s >= ' ' && *s <= '~')
951: *t++ = *s++;
952: else{
953: *t++ = '?';
954: *s++;
955: }
956: *t = '\0';
957: } else
958: strcpy(tmp,s);
959: return tmp;
960: }
961:
962: /*
963: * Prints name in multi-column format across the screen (-x option).
964: */
965: prcolh(name)
966: char *name;
967: {
968: if ( ccol < ncols)
969: printf(name);
970: if ( ++ccol < ncols)
971: printf("%*s",maxwidth - strlen(name) + GAP,"");
972: else {
973: ccol = 0;
974: putchar('\n');
975: }
976: }
977:
978: /*
979: * Sets chars in buffer to NULs.
980: */
981: clear(s)
982: char *s;
983: {
984: while (*s != '\0')
985: *s++ = '\0';
986: }
987:
988: /*
989: * Adds whatever information to file name as indicated by flags
990: * (i.e. iflag, sflag, bflag) and stores it in ck_name so its
991: * entire length can be recorded. Used for -x and -C.
992: * Sets lsp->ls_name to allocated name.
993: */
994: cstore(lsp, name)
995: LS *lsp;
996: char *name;
997: {
998: register int sl;
999: char buf[80],tmp[80],tmp2[80];
1000:
1001: clear(buf); clear(tmp); clear(tmp2);
1002: if ( sflag)
1003: sprintf(buf,"%3d",getsize(lsp));
1004: if (iflag){
1005: sprintf(tmp,"%5u ", lsp->ls_ino);
1006: strcat(buf,tmp);
1007: }
1008: strcpy(tmp2,getname(name));
1009: strcat(buf,tmp2);
1010: if ( Fflag || pflag)
1011: strcat(buf,getflag(lsp->ls_mode));
1012: sl = strlen(buf);
1013: if (maxwidth < sl)
1014: maxwidth = sl;
1015: lsp->ck_name = alloc(sl+1, "ck_name");
1016: strcpy(lsp->ck_name,buf);
1017: }
1018:
1019: /*
1020: * Returns size of file. see prsize.
1021: */
1022: getsize(lsp)
1023: register LS *lsp;
1024: {
1025: long blocks, size;
1026: register ftype;
1027:
1028: size = 0;
1029: ftype = lsp->ls_mode & S_IFMT;
1030: if (ftype==S_IFREG || ftype==S_IFDIR || ftype==S_IFPIP) {
1031: size = blocks = (lsp->ls_size+BSIZE-1)/BSIZE;
1032: if (blocks > ND) {
1033: size++;
1034: blocks -= ND;
1035: if (blocks > NBN*NI) {
1036: blocks -= NBN*NI;
1037: size += 2 + blocks/NBN;
1038: }
1039: }
1040: }
1041: return size;
1042: }
1043:
1044: /*
1045: * Save file name for -C option.
1046: * This allocates namelist[i], prnames() eventually frees it.
1047: */
1048: svname(name,i)
1049: char *name;
1050: int i;
1051: {
1052: if (i >= MAXARG)
1053: fatal("more than %d files with -C option", MAXARG);
1054: namelist[i] = alloc(strlen(name)+1,"svname");
1055: strcpy(namelist[i],name);
1056: }
1057:
1058: /*
1059: * Print names in multi-column format going down the screen (-C option).
1060: * Free the namelist members allocated by svname.
1061: */
1062: prnames(Cargs)
1063: int Cargs;
1064: {
1065: register int nc, i, j, nl;
1066:
1067: ncols = MAXLEN/(maxwidth+GAP);
1068: nc = ncols;
1069: nlast = Cargs % ncols;
1070: nrows = Cargs/ncols + (nlast ? 1 : 0);
1071: offset = nrows -1;
1072:
1073: if (nlast == 0)
1074: nlast = ncols;
1075: nl = nlast;
1076: for(i=0; i < offset; i++){
1077: for(j = i; j < Cargs;j+=offset+ (nl-- >0) )
1078: prcolh(namelist[j]);
1079: nl = nlast;
1080: }
1081: while (nlast--){
1082: prcolh(namelist[i]);
1083: i += nrows;
1084: }
1085: if (ccol){
1086: putchar('\n');
1087: ccol = 0;
1088: }
1089: for (i = 0; i < Cargs; i++)
1090: free(namelist[i]);
1091: }
1092:
1093: /*
1094: * Put message and die.
1095: */
1096: /* VARARGS */
1097: void
1098: fatal(s) char *s;
1099: {
1100: fprintf(stderr, "\nls: fatal: %r\n", &s);
1101: exit(1);
1102: }
1103:
1104: /*
1105: * Get space or die.
1106: */
1107: char *
1108: alloc(n, msg) register int n; char *msg;
1109: {
1110: extern char *calloc();
1111: register char *cp;
1112:
1113: if ((cp = calloc(n, 1)) == NULL)
1114: fatal("out of space: %s", msg);
1115: return cp;
1116: }
1117:
1118: /* end of ls.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.