|
|
1.1 root 1: #define UCB /* Controls output format for -F */
2: /* #define UCB_PWHASH /* If have hashed password file */
3:
4: /*
5: * ls - list file or directory
6: *
7: * Modified by Bill Joy UCB May/August 1977
8: * Modified by Dave Presotto BTL Feb/80
9: * Modified by Bill Joy and Mark Horton Summer 1980
10: *
11: * this version of ls is designed for graphic terminals and to
12: * list directories with lots of files in them compactly.
13: * It supports three variants for listings:
14: *
15: * 1) Columnar output.
16: * 2) Stream output.
17: * 3) Old one per line format.
18: *
19: * Columnar output is the default.
20: * If, however, the standard output is not a teletype, the default
21: * is one-per-line.
22: *
23: * With columnar output, the items are sorted down the columns.
24: * We use columns only for a directory we are interpreting.
25: * Thus, in particular, we do not use columns for
26: *
27: * ls /usr/bin/p*
28: *
29: * This version of ls also prints non-printing characters as '?' if
30: * the standard output is a teletype.
31: *
32: * Flags relating to these and other new features are:
33: *
34: * -m force stream output.
35: *
36: * -1 force one entry per line, e.g. to a teletype
37: *
38: * -q force non-printings to be '?'s, e.g. to a file
39: *
40: * -C force columnar output, e.g. into a file
41: *
42: * -n like -l, but user/group id's in decimal rather than
43: * looking in /etc/passwd to save time
44: *
45: * -F turns on the "flagging" of executables and directories
46: *
47: * -R causes ls to recurse through the branches of the subtree
48: * ala find
49: */
50:
51: #include <sys/param.h>
52: #include <sys/stat.h>
53: #include <sys/dir.h>
54: #include <stdio.h>
55: #include <ctype.h>
56: #include <pwd.h>
57: #include <grp.h>
58: #include <utmp.h>
59:
60: struct utmp utmp;
61: #define NMAX (sizeof utmp.ut_name)
62:
63: #define MAXFILEWIDTH 14
64: #define NFILES 1024
65: FILE *pwdf, *dirf;
66:
67: struct lbuf {
68: union {
69: char lname[15];
70: char *namep;
71: } ln;
72: char ltype;
73: ino_t lnum;
74: short lflags;
75: short lnl;
76: short luid;
77: short lgid;
78: long lsize;
79: long lmtime;
80: };
81:
82: struct dchain {
83: char *dc_name; /* the path name */
84: struct dchain *dc_next; /* the next directory on the chain */
85: };
86:
87: struct dchain *dfirst; /* the start of the directory chain */
88: struct dchain *cdfirst; /* the start of the current directory chain */
89: struct dchain *dtemp; /* temporary used when linking */
90: char *curdir; /* the current directory */
91:
92: int aflg, bflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, gflg, cflg;
93: int Aflg, nflg, qflg, Fflg, Rflg, across, Cflg;
94: int nopad;
95: int tabflg;
96: int rflg = 1;
97: long year;
98: int flags;
99: long tblocks;
100: int statreq;
101: int xtraent; /* for those switches which print out a total */
102: struct lbuf *flist[NFILES];
103: struct lbuf **lastp = flist;
104: struct lbuf **firstp = flist;
105: char *dotp = ".";
106:
107: char *makename();
108: struct lbuf *gstat();
109: char *ctime();
110: long nblock();
111: char *getname();
112:
113: #define ISARG 0100000
114: int colwidth;
115: int filewidth;
116: int fixedwidth;
117: int outcol;
118:
119: char obuf[BUFSIZ];
120:
121: main(argc, argv)
122: int argc;
123: char *argv[];
124: {
125: #include <sgtty.h>
126:
127: int i, width;
128: register struct lbuf *ep;
129: register struct lbuf **slastp;
130: struct lbuf **epp;
131: struct lbuf lb;
132: char *t;
133: char *cp;
134: int compar();
135: struct sgttyb sgbuf;
136:
137: Fflg = 0;
138: tabflg = 0;
139: Aflg = getuid() == 0;
140: setbuf(stdout, obuf);
141: lb.lmtime = time((long *) 0);
142: year = lb.lmtime - 6L*30L*24L*60L*60L; /* 6 months ago */
143: qflg = gtty(1, &sgbuf) == 0;
144:
145: /* guarantee at least on column width */
146: fixedwidth = 2;
147:
148: /*
149: * If the standard output is not a teletype,
150: * then we default to one-per-line format
151: * otherwise decide between stream and
152: * columnar based on our name.
153: */
154: if (qflg) {
155: Cflg = 1;
156: if ((sgbuf.sg_flags & XTABS) == 0)
157: tabflg++;
158: for (cp = argv[0]; cp[0] && cp[1]; cp++)
159: continue;
160: /*
161: * Certain kinds of links (l, ll, lr, lf, lx) cause some
162: * various options to be turned on.
163: */
164: switch (cp[0]) {
165: case 'l':
166: if (cp[-1] == 'l') {
167: /* ll => -l */
168: lflg = 1;
169: statreq++;
170: xtraent++;
171: } else {
172: /* l => -m */
173: nopad = 1;
174: Cflg = 0;
175: }
176: break;
177: case 'x': /* lx => -x */
178: across = 1;
179: break;
180: case 'f': /* lf => -F */
181: Fflg = 1;
182: break;
183: case 'r': /* lr => -R */
184: Rflg = 1;
185: break;
186: }
187: } else {
188: tabflg++;
189: }
190:
191: while (--argc > 0 && *argv[1] == '-') {
192: argv++;
193: while (*++*argv) switch (**argv) {
194: /*
195: * C - force columnar output
196: */
197: case 'C':
198: Cflg = 1;
199: nopad = 0;
200: continue;
201: /*
202: * m - force stream output
203: */
204: case 'm':
205: Cflg = 0;
206: nopad = 1;
207: continue;
208: /*
209: * x - force sort across
210: */
211: case 'x':
212: across = 1;
213: nopad = 0;
214: Cflg = 1;
215: continue;
216: /*
217: * q - force ?'s in output
218: */
219: case 'q':
220: qflg = 1;
221: bflg = 0;
222: continue;
223: /*
224: * b - force octal value in output
225: */
226: case 'b':
227: bflg = 1;
228: qflg = 0;
229: continue;
230: /*
231: * 1 - force 1/line in output
232: */
233: case '1':
234: Cflg = 0;
235: nopad = 0;
236: continue;
237: /* STANDARD FLAGS */
238: case 'a':
239: aflg++;
240: continue;
241:
242: case 'A':
243: Aflg = !Aflg;
244: continue;
245:
246: case 'c':
247: cflg++;
248: continue;
249:
250: case 's':
251: fixedwidth += 5;
252: sflg++;
253: statreq++;
254: xtraent++;
255: continue;
256:
257: case 'd':
258: dflg++;
259: continue;
260:
261: /*
262: * n - don't look in password file
263: */
264: case 'n':
265: nflg++;
266: case 'l':
267: lflg++;
268: statreq++;
269: xtraent++;
270: continue;
271:
272: case 'r':
273: rflg = -1;
274: continue;
275:
276: case 't':
277: tflg++;
278: statreq++;
279: continue;
280:
281: case 'u':
282: uflg++;
283: continue;
284:
285: case 'i':
286: fixedwidth += 6;
287: iflg++;
288: continue;
289:
290: case 'f':
291: fflg++;
292: continue;
293:
294: case 'g':
295: gflg++;
296: continue;
297:
298: case 'F':
299: Fflg++;
300: continue;
301:
302: case 'R':
303: Rflg++;
304: continue;
305:
306: default:
307: fprintf (stderr, "usage: ls [-1ACFRabcdfgilmnqrstux] [files]\n");
308: exit(1);
309: }
310: }
311: if (Fflg)
312: #ifdef UCB
313: fixedwidth++;
314: #else
315: fixedwidth += 2;
316: #endif
317: if (fflg) {
318: aflg++;
319: lflg = 0;
320: sflg = 0;
321: tflg = 0;
322: statreq = 0;
323: xtraent = 0;
324: }
325: if(lflg) {
326: Cflg = 0;
327: t = "/etc/passwd";
328: if (gflg)
329: t = "/etc/group";
330: nopad = 0;
331: fixedwidth = 70;
332: pwdf = fopen(t, "r");
333: }
334: if (argc==0) {
335: argc++;
336: argv = &dotp - 1;
337: }
338: for (i=0; i < argc; i++) {
339: argv++;
340: if (Cflg) {
341: width = strlen (*argv);
342: if (width > filewidth)
343: filewidth = width;
344: }
345: if ((ep = gstat(*argv, 1))==NULL)
346: continue;
347: ep->ln.namep = *argv;
348: ep->lflags |= ISARG;
349: }
350: if (!Cflg)
351: filewidth = MAXFILEWIDTH;
352: else
353: colwidth = fixedwidth + filewidth;
354: qsort(firstp, lastp - firstp, sizeof *lastp, compar);
355: slastp = lastp;
356: /* For each argument user typed */
357: for (epp=firstp; epp<slastp; epp++) {
358: ep = *epp;
359: if (ep->ltype=='d' && dflg==0 || fflg)
360: pdirectory(ep->ln.namep, (argc>1), slastp);
361: else
362: pentry(ep);
363:
364: /* -R: print subdirectories found */
365: while (dfirst || cdfirst) {
366: /* Place direct subdirs on front in right order */
367: while (cdfirst) {
368: /* reverse cdfirst onto front of dfirst */
369: dtemp = cdfirst;
370: cdfirst = cdfirst -> dc_next;
371: dtemp -> dc_next = dfirst;
372: dfirst = dtemp;
373: }
374: /* take off first dir on dfirst & print it */
375: dtemp = dfirst;
376: dfirst = dfirst->dc_next;
377: pdirectory (dtemp->dc_name, 1, firstp);
378: cfree (dtemp->dc_name);
379: cfree (dtemp);
380: }
381: }
382: if (outcol)
383: putc('\n', stdout);
384: fflush(stdout);
385: }
386:
387: /*
388: * pdirectory: print the directory name, labelling it if title is
389: * nonzero, using lp as the place to start reading in the dir.
390: */
391: pdirectory (name, title, lp)
392: char *name;
393: int title;
394: struct lbuf **lp;
395: {
396: register struct dchain *dp;
397: register struct lbuf *ap;
398: register char *pname;
399: struct lbuf **app;
400:
401: filewidth = 0;
402: curdir = name;
403: if (title)
404: printf("\n%s:\n", name);
405: lastp = lp;
406: readdir(name);
407: if (!Cflg)
408: filewidth = MAXFILEWIDTH;
409: colwidth = fixedwidth + filewidth;
410: #ifdef notdef
411: /* Taken out because it appears this is done below in pem. */
412: if (tabflg) {
413: if (colwidth <= 8)
414: colwidth = 8;
415: else
416: if (colwidth <= 16)
417: colwidth = 16;
418: }
419: #endif
420: if (fflg==0)
421: qsort(lp,lastp - lp,sizeof *lastp,compar);
422: if (Rflg) for (app=lastp-1; app>=lp; app--) {
423: ap = *app;
424: if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") &&
425: strcmp(ap->ln.lname, "..")) {
426: dp = (struct dchain *) calloc(1, sizeof(struct dchain));
427: pname = makename (curdir, ap->ln.lname);
428: dp->dc_name = (char *) calloc(1, strlen(pname)+1);
429: strcpy(dp->dc_name, pname);
430: dp -> dc_next = dfirst;
431: dfirst = dp;
432: }
433: }
434: if (lflg || sflg)
435: printf("total %D", tblocks);
436: pem(lp, lastp);
437: newline();
438: }
439:
440: /*
441: * pem: print 'em. Print a list of files (e.g. a directory) bounded
442: * by slp and lp.
443: */
444: pem(slp, lp)
445: register struct lbuf **slp, **lp;
446: {
447: int ncols, nrows, row, col;
448: register struct lbuf **ep;
449:
450: if (tabflg) {
451: if (colwidth <= 9)
452: colwidth = 8;
453: else
454: if (colwidth <= 17)
455: colwidth = 16;
456: }
457: ncols = 80 / colwidth;
458: if (ncols == 1 || Cflg == 0) {
459: for (ep = slp; ep < lp; ep++)
460: pentry(*ep);
461: return;
462: }
463: if (across) {
464: for (ep = slp; ep < lp; ep++)
465: pentry(*ep);
466: return;
467: }
468: if (xtraent)
469: slp--;
470: nrows = (lp - slp - 1) / ncols + 1;
471: for (row = 0; row < nrows; row++) {
472: col = row == 0 && xtraent;
473: for (; col < ncols; col++) {
474: ep = slp + (nrows * col) + row;
475: if (ep < lp)
476: pentry(*ep);
477: }
478: if (outcol)
479: printf("\n");
480: }
481: }
482:
483: /*
484: * pputchar: like putchar but knows how to handle control chars.
485: * CAUTION: if you make ctrl chars print in ^x notation, or any
486: * other notation which is wider than one character, the column
487: * nature of things (such as files with 14 letter names) will be
488: * messed up. Weigh this carefully!
489: */
490: pputchar(c)
491: char c;
492: {
493: char cc;
494:
495: switch (c) {
496: case '\t':
497: outcol = (outcol + 8) &~ 7;
498: break;
499: case '\n':
500: outcol = 0;
501: break;
502: default:
503: if (c < ' ' || c >= 0177) {
504: if (qflg)
505: c = '?';
506: else if (bflg) {
507: outcol += 3;
508: putc ('\\', stdout);
509: cc = '0' + (c>>6 & 07);
510: putc (cc, stdout);
511: cc = '0' + (c>>3 & 07);
512: putc (cc, stdout);
513: c = '0' + (c & 07);
514: }
515: }
516: outcol++;
517: break;
518: }
519: putc(c, stdout);
520: }
521:
522: newline()
523: {
524: if (outcol)
525: putc('\n', stdout);
526: outcol = 0;
527: }
528:
529: /*
530: * column: get to the beginning of the next column.
531: */
532: column()
533: {
534:
535: if (outcol == 0)
536: return;
537: if (nopad) {
538: putc(',', stdout);
539: outcol++;
540: if (outcol + colwidth + 2 > 80) {
541: putc('\n', stdout);
542: outcol = 0;
543: return;
544: }
545: putc(' ', stdout);
546: outcol++;
547: return;
548: }
549: if (Cflg == 0) {
550: putc('\n', stdout);
551: return;
552: }
553: if ((outcol / colwidth + 2) * colwidth > 80) {
554: putc('\n', stdout);
555: outcol = 0;
556: return;
557: }
558: if (tabflg && (colwidth <= 16)) {
559: if (colwidth > 8)
560: if ((outcol % 16) < 8) {
561: outcol += 8 - (outcol % 8);
562: putc ('\t', stdout);
563: }
564: outcol += 8 - (outcol % 8);
565: putc ('\t', stdout);
566: return;
567: }
568: do {
569: outcol++;
570: putc(' ', stdout);
571: } while (outcol % colwidth);
572: }
573:
574:
575: /*
576: * nblock: the number of 512 byte blocks a size byte file takes up.
577: * (Note: the number stays 512 no matter what BUFSIZ or the filesystem uses.)
578: */
579: long
580: nblock(size)
581: long size;
582: {
583: return((size+511)>>9);
584: }
585:
586: /*
587: * This code handles the rwx- business.
588: * You figure it out.
589: */
590: int m1[] = { 1, S_IREAD>>0, 'r', '-' };
591: int m2[] = { 1, S_IWRITE>>0, 'w', '-' };
592: int m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' };
593: int m4[] = { 1, S_IREAD>>3, 'r', '-' };
594: int m5[] = { 1, S_IWRITE>>3, 'w', '-' };
595: int m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' };
596: int m7[] = { 1, S_IREAD>>6, 'r', '-' };
597: int m8[] = { 1, S_IWRITE>>6, 'w', '-' };
598: int m9[] = { 2, S_ISVTX, 't', S_IEXEC>>6, 'x', '-' };
599:
600: int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
601:
602: pmode(aflag)
603: {
604: register int **mp;
605:
606: flags = aflag;
607: for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])];)
608: select(*mp++);
609: }
610:
611: select(pairp)
612: register int *pairp;
613: {
614: register int n;
615:
616: n = *pairp++;
617: while (--n>=0 && (flags&*pairp++)==0)
618: pairp++;
619: pputchar(*pairp);
620: }
621:
622: /*
623: * returns cat(dir, "/", file), unless dir ends in /, when it doesn't //
624: */
625: char *
626: makename(dir, file)
627: char *dir, *file;
628: {
629: static char dfile[100];
630: register char *dp, *fp;
631: register int i;
632:
633: dp = dfile;
634: fp = dir;
635: while (*fp)
636: *dp++ = *fp++;
637: if (*(dp-1) != '/')
638: *dp++ = '/';
639: fp = file;
640: for (i=0; i<DIRSIZ; i++)
641: *dp++ = *fp++;
642: *dp = 0;
643: return(dfile);
644: }
645:
646: /*
647: * readdir: read in the directory whose name is dir,
648: * starting at lastp.
649: */
650: readdir(dir)
651: char *dir;
652: {
653: static struct direct dentry;
654: register int j, width;
655: register struct lbuf *ep;
656:
657: if ((dirf = fopen(dir, "r")) == NULL) {
658: printf("%s unreadable\n", dir);
659: return;
660: }
661: tblocks = 0;
662: for(;;) {
663: if (fread(&dentry, sizeof(dentry), 1, dirf) != 1)
664: break;
665: if (dentry.d_ino==0 ||
666: aflg==0 && dentry.d_name[0]=='.' && (
667: !Aflg ||
668: dentry.d_name[1]=='\0'
669: || dentry.d_name[1]=='.' && dentry.d_name[2]=='\0'))
670: continue;
671: if (Cflg) {
672: width = strlen (dentry.d_name);
673: if (width > filewidth)
674: filewidth = width;
675: }
676: ep = gstat(makename(dir, dentry.d_name), Fflg || Rflg);
677: if (ep==NULL)
678: continue;
679: if (ep->lnum != -1)
680: ep->lnum = dentry.d_ino;
681: for (j=0; j<DIRSIZ; j++)
682: ep->ln.lname[j] = dentry.d_name[j];
683: }
684: fclose(dirf);
685: }
686:
687: /*
688: * stat the given file and return an lbuf containing it.
689: * argfl is nonzero if a stat is required because the file is
690: * an argument, rather than having been found in a directory.
691: */
692: struct lbuf *
693: gstat(file, argfl)
694: char *file;
695: {
696: struct stat statb;
697: register struct lbuf *rep;
698: static int nomocore;
699:
700: if (nomocore)
701: return(NULL);
702: rep = (struct lbuf *)malloc(sizeof(struct lbuf));
703: if (rep==NULL) {
704: fprintf(stderr, "ls: out of memory\n");
705: nomocore = 1;
706: return(NULL);
707: }
708: if (lastp >= &flist[NFILES]) {
709: static int msg;
710: lastp--;
711: if (msg==0) {
712: fprintf(stderr, "ls: too many files\n");
713: msg++;
714: }
715: }
716: *lastp++ = rep;
717: rep->lflags = 0;
718: rep->lnum = 0;
719: rep->ltype = '-';
720: if (argfl || statreq) {
721: if (stat(file, &statb)<0) {
722: printf("%s not found\n", file);
723: statb.st_ino = -1;
724: statb.st_size = 0;
725: statb.st_mode = 0;
726: if (argfl) {
727: lastp--;
728: return(0);
729: }
730: }
731: rep->lnum = statb.st_ino;
732: rep->lsize = statb.st_size;
733: switch(statb.st_mode&S_IFMT) {
734:
735: case S_IFDIR:
736: rep->ltype = 'd';
737: break;
738:
739: case S_IFBLK:
740: rep->ltype = 'b';
741: rep->lsize = statb.st_rdev;
742: break;
743:
744: case S_IFCHR:
745: rep->ltype = 'c';
746: rep->lsize = statb.st_rdev;
747: break;
748:
749: case S_IFMPB:
750: rep->ltype = 'M';
751: rep->lsize = statb.st_rdev;
752: break;
753:
754: case S_IFMPC:
755: rep->ltype = 'm';
756: rep->lsize = statb.st_rdev;
757: break;
758: }
759: rep->lflags = statb.st_mode & ~S_IFMT;
760: rep->luid = statb.st_uid;
761: rep->lgid = statb.st_gid;
762: rep->lnl = statb.st_nlink;
763: if(uflg)
764: rep->lmtime = statb.st_atime;
765: else if (cflg)
766: rep->lmtime = statb.st_ctime;
767: else
768: rep->lmtime = statb.st_mtime;
769: tblocks += nblock(statb.st_size);
770: }
771: return(rep);
772: }
773:
774: /*
775: * decide whether to print pp1 before or after pp2, based on their
776: * names, various times, and the r flag.
777: */
778: compar(pp1, pp2)
779: struct lbuf **pp1, **pp2;
780: {
781: register struct lbuf *p1, *p2;
782:
783: p1 = *pp1;
784: p2 = *pp2;
785: if (dflg==0) {
786: if (p1->lflags&ISARG && p1->ltype=='d') {
787: if (!(p2->lflags&ISARG && p2->ltype=='d'))
788: return(1);
789: } else {
790: if (p2->lflags&ISARG && p2->ltype=='d')
791: return(-1);
792: }
793: }
794: if (tflg) {
795: if(p2->lmtime == p1->lmtime)
796: return(0);
797: if(p2->lmtime > p1->lmtime)
798: return(rflg);
799: return(-rflg);
800: }
801: return(rflg * strcmp(p1->lflags&ISARG? p1->ln.namep: p1->ln.lname,
802: p2->lflags&ISARG? p2->ln.namep: p2->ln.lname));
803: }
804:
805: /*
806: * print the entry pointed at by ap
807: */
808: pentry(ap)
809: struct lbuf *ap;
810: {
811: struct { char dminor, dmajor;};
812: register struct lbuf *p;
813: register char *cp;
814: char fname[100];
815: char *pname;
816: struct passwd *getpwuid();
817: struct passwd *pwptr;
818: struct group *getgrgid();
819: struct group *grptr;
820:
821: fname[0] = 0;
822: p = ap;
823: if (p->lnum == -1)
824: return;
825: column();
826: if (iflg)
827: if (nopad && !lflg)
828: printf("%d ", p->lnum);
829: else
830: printf("%5d ", p->lnum);
831: if (sflg)
832: if (nopad && !lflg)
833: printf("%D ", nblock(p->lsize));
834: else
835: printf("%4D ", nblock(p->lsize));
836: if (lflg) {
837: pputchar(p->ltype);
838: pmode(p->lflags);
839: printf("%2d ", p->lnl);
840: if(gflg) {
841: grptr = getgrgid(p->lgid);
842: if (nflg == 0 && grptr != 0)
843: printf("%-8.8s", grptr->gr_name);
844: else
845: printf("%-8d", p->lgid);
846: } else {
847: #ifndef UCB_PWHASH
848: char *name;
849: if (nflg == 0 && (name = getname(p->luid))) {
850: printf("%-8.8s", name);
851: }
852: #else
853: pwptr = getpwuid(p->luid);
854: if (nflg == 0 && pwptr != 0)
855: printf("%-8.8s", pwptr->pw_name);
856: #endif
857: else
858: printf("%-8d", p->luid);
859: }
860: switch (p->ltype) {
861:
862: case 'b':
863: case 'c':
864: case 'm':
865: case 'M':
866: printf("%3d,%3d",
867: major((int)p->lsize), minor((int)p->lsize));
868: break;
869: default:
870: printf("%7ld", p->lsize);
871: }
872: cp = ctime(&p->lmtime);
873: if(p->lmtime < year)
874: printf(" %-7.7s %-4.4s ", cp+4, cp+20); else
875: printf(" %-12.12s ", cp+4);
876: }
877: #ifndef UCB
878: if (Fflg) {
879: if (p->ltype == 'd')
880: strcat (fname, "[");
881: else if (p->lflags & 0111)
882: strcat (fname, "*");
883: else if (!nopad)
884: strcat (fname, " ");
885: }
886: #endif
887: if (p->lflags & ISARG)
888: strncat (fname, p->ln.namep, 98);
889: else
890: strncat (fname, p->ln.lname, 14);
891: #ifndef UCB
892: if (Fflg) {
893: if (p->ltype == 'd')
894: strcat (fname, "]");
895: else if (!nopad)
896: strcat (fname, " ");
897: }
898: #else
899: if (Fflg) {
900: if (p->ltype == 'd')
901: strcat (fname, "/");
902: else if (p->lflags & 0111)
903: strcat (fname, "*");
904: else if (!nopad)
905: strcat (fname, " ");
906: }
907: #endif
908: printf ("%s", fname);
909: free(ap);
910: }
911:
912: /* char printf_id[] = "@(#) printf.c:2.2 6/5/79";*/
913:
914: #include "varargs.h"
915:
916: /*
917: * This version of printf is compatible with the Version 7 C
918: * printf. The differences are only minor except that this
919: * printf assumes it is to print through pputchar. Version 7
920: * printf is more general (and is much larger) and includes
921: * provisions for floating point.
922: */
923:
924: #define MAXOCT 11 /* Maximum octal digits in a long */
925: #define MAXINT 32767 /* largest normal length positive integer */
926: #define BIG 1000000000 /* largest power of 10 less than an unsigned long */
927: #define MAXDIGS 10 /* number of digits in BIG */
928:
929: static int width, sign, fill;
930:
931: char *b_dconv();
932:
933: printf(va_alist)
934: va_dcl
935: {
936: va_list ap;
937: register char *fmt;
938: char fcode;
939: int prec;
940: int length,mask1,nbits,n;
941: long int mask2, num;
942: register char *bptr;
943: char *ptr;
944: char buf[134];
945:
946: va_start(ap);
947: fmt = va_arg(ap,char *);
948: for (;;) {
949: /* process format string first */
950: while ((fcode = *fmt++)!='%') {
951: /* ordinary (non-%) character */
952: if (fcode=='\0')
953: return;
954: pputchar(fcode);
955: }
956: /* length modifier: -1 for h, 1 for l, 0 for none */
957: length = 0;
958: /* check for a leading - sign */
959: sign = 0;
960: if (*fmt == '-') {
961: sign++;
962: fmt++;
963: }
964: /* a '0' may follow the - sign */
965: /* this is the requested fill character */
966: fill = 1;
967: if (*fmt == '0') {
968: fill--;
969: fmt++;
970: }
971:
972: /* Now comes a digit string which may be a '*' */
973: if (*fmt == '*') {
974: width = va_arg(ap, int);
975: if (width < 0) {
976: width = -width;
977: sign = !sign;
978: }
979: fmt++;
980: }
981: else {
982: width = 0;
983: while (*fmt>='0' && *fmt<='9')
984: width = width * 10 + (*fmt++ - '0');
985: }
986:
987: /* maybe a decimal point followed by more digits (or '*') */
988: if (*fmt=='.') {
989: if (*++fmt == '*') {
990: prec = va_arg(ap, int);
991: fmt++;
992: }
993: else {
994: prec = 0;
995: while (*fmt>='0' && *fmt<='9')
996: prec = prec * 10 + (*fmt++ - '0');
997: }
998: }
999: else
1000: prec = -1;
1001:
1002: /*
1003: * At this point, "sign" is nonzero if there was
1004: * a sign, "fill" is 0 if there was a leading
1005: * zero and 1 otherwise, "width" and "prec"
1006: * contain numbers corresponding to the digit
1007: * strings before and after the decimal point,
1008: * respectively, and "fmt" addresses the next
1009: * character after the whole mess. If there was
1010: * no decimal point, "prec" will be -1.
1011: */
1012: switch (*fmt) {
1013: case 'L':
1014: case 'l':
1015: length = 2;
1016: /* no break!! */
1017: case 'h':
1018: case 'H':
1019: length--;
1020: fmt++;
1021: break;
1022: }
1023:
1024: /*
1025: * At exit from the following switch, we will
1026: * emit the characters starting at "bptr" and
1027: * ending at "ptr"-1, unless fcode is '\0'.
1028: */
1029: switch (fcode = *fmt++) {
1030: /* process characters and strings first */
1031: case 'c':
1032: buf[0] = va_arg(ap, int);
1033: ptr = bptr = &buf[0];
1034: if (buf[0] != '\0')
1035: ptr++;
1036: break;
1037: case 's':
1038: bptr = va_arg(ap,char *);
1039: if (bptr==0)
1040: bptr = "(null pointer)";
1041: if (prec < 0)
1042: prec = MAXINT;
1043: for (n=0; *bptr++ && n < prec; n++) ;
1044: ptr = --bptr;
1045: bptr -= n;
1046: break;
1047: case 'O':
1048: length = 1;
1049: fcode = 'o';
1050: /* no break */
1051: case 'o':
1052: case 'X':
1053: case 'x':
1054: if (length > 0)
1055: num = va_arg(ap,long);
1056: else
1057: num = (unsigned)va_arg(ap,int);
1058: if (fcode=='o') {
1059: mask1 = 0x7;
1060: mask2 = 0x1fffffffL;
1061: nbits = 3;
1062: }
1063: else {
1064: mask1 = 0xf;
1065: mask2 = 0x0fffffffL;
1066: nbits = 4;
1067: }
1068: n = (num!=0);
1069: bptr = buf + MAXOCT + 3;
1070: /* shift and mask for speed */
1071: do
1072: if (((int) num & mask1) < 10)
1073: *--bptr = ((int) num & mask1) + 060;
1074: else
1075: *--bptr = ((int) num & mask1) + 0127;
1076: while (num = (num >> nbits) & mask2);
1077:
1078: if (fcode=='o') {
1079: if (n)
1080: *--bptr = '0';
1081: }
1082: else
1083: if (!sign && fill <= 0) {
1084: pputchar('0');
1085: pputchar(fcode);
1086: width -= 2;
1087: }
1088: else {
1089: *--bptr = fcode;
1090: *--bptr = '0';
1091: }
1092: ptr = buf + MAXOCT + 3;
1093: break;
1094: case 'D':
1095: case 'U':
1096: case 'I':
1097: length = 1;
1098:
1099: fcode = fcode + 'a' - 'A';
1100: /* no break */
1101: case 'd':
1102: case 'i':
1103: case 'u':
1104: if (length > 0)
1105: num = va_arg(ap,long);
1106: else {
1107: n = va_arg(ap,int);
1108: if (fcode=='u')
1109: num = (unsigned) n;
1110: else
1111: num = (long) n;
1112: }
1113: if (n = (fcode != 'u' && num < 0))
1114: num = -num;
1115: /* now convert to digits */
1116: bptr = b_dconv(num, buf);
1117: if (n)
1118: *--bptr = '-';
1119: if (fill == 0)
1120: fill = -1;
1121: ptr = buf + MAXDIGS + 1;
1122: break;
1123: default:
1124: /* not a control character,
1125: * print it.
1126: */
1127: ptr = bptr = &fcode;
1128: ptr++;
1129: break;
1130: }
1131: if (fcode != '\0')
1132: b_emit(bptr,ptr);
1133: }
1134: va_end(ap);
1135: }
1136:
1137: /* b_dconv converts the unsigned long integer "value" to
1138: * printable decimal and places it in "buffer", right-justified.
1139: * The value returned is the address of the first non-zero character,
1140: * or the address of the last character if all are zero.
1141: * The result is NOT null terminated, and is MAXDIGS characters long,
1142: * starting at buffer[1] (to allow for insertion of a sign).
1143: *
1144: * This program assumes it is running on 2's complement machine
1145: * with reasonable overflow treatment.
1146: */
1147: char *
1148: b_dconv(value, buffer)
1149: long value;
1150: char *buffer;
1151: {
1152: register char *bp;
1153: register int svalue;
1154: int n;
1155: long lval;
1156:
1157: bp = buffer;
1158:
1159: /* zero is a special case */
1160: if (value == 0) {
1161: bp += MAXDIGS;
1162: *bp = '0';
1163: return(bp);
1164: }
1165:
1166: /* develop the leading digit of the value in "n" */
1167: n = 0;
1168: while (value < 0) {
1169: value -= BIG; /* will eventually underflow */
1170: n++;
1171: }
1172: while ((lval = value - BIG) >= 0) {
1173: value = lval;
1174: n++;
1175: }
1176:
1177: /* stash it in buffer[1] to allow for a sign */
1178: bp[1] = n + '0';
1179: /*
1180: * Now develop the rest of the digits. Since speed counts here,
1181: * we do it in two loops. The first gets "value" down until it
1182: * is no larger than MAXINT. The second one uses integer divides
1183: * rather than long divides to speed it up.
1184: */
1185: bp += MAXDIGS + 1;
1186: while (value > MAXINT) {
1187: *--bp = (int)(value % 10) + '0';
1188: value /= 10;
1189: }
1190:
1191: /* cannot lose precision */
1192: svalue = value;
1193: while (svalue > 0) {
1194: *--bp = (svalue % 10) + '0';
1195: svalue /= 10;
1196: }
1197:
1198: /* fill in intermediate zeroes if needed */
1199: if (buffer[1] != '0') {
1200: while (bp > buffer + 2)
1201: *--bp = '0';
1202: --bp;
1203: }
1204: return(bp);
1205: }
1206:
1207: /*
1208: * This program sends string "s" to pputchar. The character after
1209: * the end of "s" is given by "send". This allows the size of the
1210: * field to be computed; it is stored in "alen". "width" contains the
1211: * user specified length. If width<alen, the width will be taken to
1212: * be alen. "sign" is zero if the string is to be right-justified
1213: * in the field, nonzero if it is to be left-justified. "fill" is
1214: * 0 if the string is to be padded with '0', positive if it is to be
1215: * padded with ' ', and negative if an initial '-' should appear before
1216: * any padding in right-justification (to avoid printing "-3" as
1217: * "000-3" where "-0003" was intended).
1218: */
1219: b_emit(s, send)
1220: register char *s;
1221: char *send;
1222: {
1223: char cfill;
1224: register int alen;
1225: int npad;
1226:
1227: alen = send - s;
1228: if (alen > width)
1229: width = alen;
1230: cfill = fill>0? ' ': '0';
1231:
1232: /* we may want to print a leading '-' before anything */
1233: if (*s == '-' && fill < 0) {
1234: pputchar(*s++);
1235: alen--;
1236: width--;
1237: }
1238: npad = width - alen;
1239:
1240: /* emit any leading pad characters */
1241: if (!sign)
1242: while (--npad >= 0)
1243: pputchar(cfill);
1244:
1245: /* emit the string itself */
1246: while (--alen >= 0)
1247: pputchar(*s++);
1248:
1249: /* emit trailing pad characters */
1250: if (sign)
1251: while (--npad >= 0)
1252: pputchar(cfill);
1253: }
1254:
1255: #ifndef UCB_PWHASH
1256: #define NUID 2048
1257:
1258: char names[NUID][NMAX+1];
1259:
1260: char *
1261: getname(uid)
1262: {
1263: register struct passwd *pw;
1264: static init;
1265: struct passwd *getpwent();
1266:
1267: if (uid >= 0 && uid < NUID && names[uid][0])
1268: return (&names[uid][0]);
1269: if (init == 2)
1270: return (0);
1271: if (init == 0)
1272: setpwent(), init = 1;
1273: while (pw = getpwent()) {
1274: if (pw->pw_uid < 0 || pw->pw_uid >= NUID)
1275: continue;
1276: if (names[pw->pw_uid][0])
1277: continue;
1278: strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
1279: if (pw->pw_uid == uid)
1280: return (&names[uid][0]);
1281: }
1282: init = 2;
1283: endpwent();
1284: return (0);
1285: }
1286: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.