|
|
1.1 root 1: /*
2: **********************************************************************
3: * *
4: * dired [][dir][files] Stuart Cracraft (mclure@sri-unix) Sept 1980 *
5: * *
6: * Directory editor. *
7: * edit/delete files in a directory or a file list *
8: * compile with the berkeley termlib archive *
9: * and don't forget to change the 'helpfile' and *
10: * 'dirednam' strings to reflect your own setup. *
11: * *
12: * Note: if you make improvements, I'd like to get them too. *
13: * Stuart Cracraft mclure@sri-unix, *
14: * ucbvax!menlo70!sri-unix!mclure *
15: * so would I: Jay Lepreau lepreau@utah-20, *
16: * decvax!randvax!utah-cs!lepreau *
17: **********************************************************************
18: */
19:
20: /*
21: * Enhanced by J.Lepreau, Univ of Utah, 8-10/81:
22: * --bunch of stuff, including more cmds, 2 window mode,
23: * buffering output, pathname substition in !escapes,
24: * initial sort options, ^G escape from sorts, ^U escape
25: * from !escapes, empty dir check.
26: */
27:
28: #ifdef COMMENT
29:
30: Modified 12/81 by Lepreau:
31: 1. Fix up aborting of command escapes, with mildy tricky re-display.
32: 2. Make default window size be half-screen (2 window mode).
33: Added option -wf to get full screen.
34: 3. Add check for too many files to avoid core-dump.
35: 4. Fix bug in cmd escapes: must reset caught signals before invocation.
36:
37: #endif COMMENT
38:
39: /*
40: things to consider
41: - perhaps should be able to edit protection field and
42: be able to change protection instantly at the
43: touch of a key (or queue the change for later exit)
44:
45: -- Would be nice if there were cmds (e.g. 'c') which would update
46: 1) the file-info & re-display it, & 2) update whole
47: display's info.
48: */
49:
50: #ifdef vax /* this does for now */
51: # define VFORK
52: #endif
53:
54: #ifndef VFORK
55: # define vfork fork
56: #endif
57:
58: #define FALSE 0
59: #define TRUE 1
60: #define NOTDELETED 0
61: #define DELETED 1
62:
63: /* Sort Orders */
64: #define NAME 0
65: #define SIZE 1
66: #define WRITE 2
67: #define READ 3
68: char sortstr[] = "nswr"; /* must be in order by above */
69:
70: #define ESC '\033'
71: #define CURSOR 48 /* X-coord of cursor, just b4 file */
72: #define CTRL(c) ('c' & 037)
73:
74: #include <stdio.h>
75: #include <sys/types.h>
76: #include <signal.h>
77: #include <sgtty.h>
78: #include <sys/stat.h>
79: #ifdef BSD
80: #include <sys/dir.h>
81: #else
82: #include <ndir.h>
83: #define index strchr
84: #endif
85:
86: #ifdef UTAH
87: char *dirednam = "/usr/local/dired "; /* Where dired lives - need blnk */
88: char *helpfile = "/usr/help/dired.hlp"; /* Where helpfile lives */
89: #else
90: char *dirednam = "dired "; /* Where dired lives - need blnk */
91: char *helpfile = "/usr/lib/dired"; /* Where helpfile lives */
92: #endif
93:
94: char divider[132]; /* divides the windows */
95: #define DIVCHAR '-' /* makes up the divider */
96:
97: #define MOREPGM "p " /* program to page thru a file */
98:
99: #define MAXFILES 2000 /* Max number of files we can handle */
100: #define MAXN 30
101:
102: struct lbuf
103: {
104: union
105: {
106: char lname[MAXN];
107: char *namep;
108: } ln;
109: short deleted;
110: char ltype;
111: short lnum;
112: short lflags;
113: short lnl;
114: unsigned short luid;
115: unsigned short lgid;
116: long lsize;
117: long latime;
118: long lctime;
119: long lmtime;
120: };
121:
122: struct lbuf file[MAXFILES];
123:
124: struct stat statbuf;
125: struct sgttyb ioctlb;
126:
127: #define ISARG 0100000
128:
129: int gflg,
130: iflg,
131: lflg,
132: sflg; /* Random flags */
133: int splitflg; /* Split screen? */
134: int sortyp; /* Key to sort on */
135: int errcode; /* Error variable used by rm */
136: int rflg = 1; /* Reverse sort flag */
137: int totfiles = 0; /* Total files */
138: int flags; /* Gets flags */
139: int blurb; /* 1=>thing in echo area,0 otherwise */
140: int numdeleted; /* Number of files marked deleted */
141: long ttime; /* Temp time variable */
142: long year; /* Six months ago */
143: long totblocks = 0; /* Total blocks */
144: int lastuid = -1; /* Last uid/gid we handled */
145: char tempbuf[128]; /* Random temporary buffer */
146: char userbuf[35]; /* Temporary buffer for user name */
147: FILE *pwdf; /* Password/group file */
148:
149: int curfile = 0; /* Current file */
150: int topfile = 0; /* File at top of screen */
151: int curline = 0; /* Line that we're on */
152: int scrlen = 999; /* Length of screen - dired part: half size */
153: int Worklen = 0; /* Length of 'working window', the other part*/
154: int Worktop = 0; /* Top of " " */
155: int Tscrlen; /*Total length of screen,minus 1 for cmd line*/
156: int scrwid = 79; /* Width of screen */
157: char *CL,
158: *UP, /* Termcap strings we'll use */
159: *HO,
160: *CM,
161: *CD, /* clear to end of display */
162: *CE,
163: *AL; /* insert line */
164: char PC;
165: char tbuf[1024],
166: tcapbuf[128];
167: char *tgetstr (), *tgoto ();
168: char *getenv ();
169: int compar ();
170: char *ctime ();
171: char *index();
172: char *makename ();
173: char *catargs();
174: char *bldnam();
175: long nblock ();
176: int catchint();
177: int sigint;
178:
179: char bufout[BUFSIZ];
180:
181: main (argc, argv)
182: int argc;
183: char *argv[];
184: {
185: register int i,
186: cc;
187: int numarg,
188: special, /* flag says had % or # in cmd */
189: status;
190: char nambuf[128];
191: char command; /* Holds last command */
192: char **oldargv;
193: register char *t,
194: *tt;
195:
196: /* Get terminal type */
197:
198: getcap ();
199:
200: /* Process arg flags. They must be first! */
201: for (i=1; i<argc; i++) {
202: if (argv[i][0] != '-')
203: break;
204: switch (cc = argv[i][1]) {
205: case 'w': /* Window size */
206: if (argv[i][2] == 'h')
207: scrlen = 999; /* Half */
208: else if (argv[i][2] == 'f')
209: scrlen = 0; /* Full */
210: else
211: scrlen = atoi(&argv[i][2]);
212: break;
213: case 's': /* Initial sort order */
214: case 'r':
215: sortyp = index(sortstr, argv[i][2]) - sortstr;
216: rflg = (cc == 's') ? 1 : -1;
217: break;
218: default:
219: printf("Unknown option %s, ignored.\n", argv[i]);
220: break;
221: }
222: }
223: argc -= (i - 1);
224: oldargv = argv;
225: argv += (i - 1);
226:
227: if (scrlen == 0) /* full screen */
228: scrlen = Tscrlen;
229: else if (scrlen == 999) /* means split in half */
230: scrlen = (Tscrlen - 1) >> 1;
231: if (scrlen < 2)
232: scrlen = 2;
233: if (Tscrlen < scrlen)
234: scrlen = Tscrlen;
235: splitflg = (Tscrlen > scrlen+1); /* 1 extra line for separator */
236: if (splitflg) {
237: Worklen = Tscrlen - (scrlen+1); /* size of 'working' window */
238: Worktop = scrlen + 1; /* bottom half for now */
239: }
240: else
241: Worklen = 0;
242:
243: tt = divider + scrwid - 14;
244: for (t = divider; t < tt;) /* arbitrary length */
245: *t++ = DIVCHAR;
246: *t = '\0';
247:
248: signal (SIGINT, SIG_IGN);
249: signal (SIGQUIT, SIG_IGN);
250:
251: setdpy ();
252: printf ("Reading");
253:
254: time (&ttime);
255: year = ttime - 6L * 30L * 24L * 60L * 60L;/* 6 months ago */
256:
257: lflg = 1;
258: gflg = iflg = sflg = 0;
259: if (lflg)
260: {
261: t = "/etc/passwd";
262: if (gflg)
263: t = "/etc/group";
264: pwdf = fopen (t, "r");
265: }
266:
267:
268: numarg = argc;
269: if (argc == 1)
270: getdir (".");
271: else
272: if (argc == 2)
273: getdir (argv[1]);
274: else
275: {
276: while (--argc > 0)
277: {
278: if (totfiles == MAXFILES) {
279: overflow();
280: break;
281: }
282: if ((totfiles % 10) == 0)
283: putchar ('.');
284: if (gstat(*++argv) == 0) {
285: file[totfiles].ln.namep = *argv;
286: file[totfiles].lflags |= ISARG;
287: totfiles++;
288: }
289: }
290: }
291: if (totfiles == 0) {
292: printf("\n?Empty directory\n");
293: unsetdpy();
294: sleep(1); /* So user can see it - don't worry if less */
295: exit(0);
296: }
297: qsort (file, totfiles, sizeof (struct lbuf), compar);
298: blank ();
299: showscreen ();
300: curxy (0, Tscrlen);
301: ceol ();
302: curxy (CURSOR, 0);
303: startup:
304: while ((command = readchar()) != 'q')
305: {
306: if (blurb)
307: {
308: telluser ("");
309: blurb = 0;
310: }
311: switch (command)
312: {
313: case 'a': /* Abort completely */
314: blank ();
315: unsetdpy ();
316: exit (1);
317: break;
318: case 'P': /* Print a file */
319: case 'p': /* do a pr2 */
320: if (file[curfile].ltype == 'd')
321: {
322: telluser ("?Can only print files");
323: break;
324: }
325: tempbuf[0] = '\0';
326: bldnam(tempbuf, numarg, curfile, argv);
327: telluser ("Printing...");
328: while ((i = vfork ()) == -1)
329: sleep (3);
330: if (i == 0) {
331: #ifdef UTAH
332: if (command == 'p') /* little print */
333: execlp("pr2", "pr2", tempbuf, 0);
334: else /* big print */
335: #endif
336: execlp ("print", "print", tempbuf, 0);
337: telluser ("?Can't find program to list file.\n");
338: _exit(1);
339: }
340: wait (&status);
341: break;
342:
343: case '!': /* Execute a system command */
344: telluser ("");
345: curxy (0, Tscrlen);
346: unsetdpy ();
347: printf ("Command: ");
348: tempbuf[0] = 'x'; /* dummy kludge */
349: if (gets(tempbuf) != NULL && tempbuf[0] != '\0') {
350: extern char *skipto();
351: register char *op, /* old ptr */
352: *np; /* new ptr */
353: char bldbuf[70];
354:
355: bldbuf[0] = '\0';
356: op = tempbuf;
357: special = 0;
358: while (cc = *(np = skipto(op, "%#"))) {
359: special++; /* set flag */
360: *np++ = '\0'; /* zap the %/# and bump past it */
361: strcat(bldbuf, op); /* 1st part */
362: if (cc == '%') /* complete file name */
363: bldnam(bldbuf, numarg, curfile, argv);
364: else { /* Had # sign, trailing comp only */
365: if (numarg <= 2)
366: strcat (bldbuf, file[curfile].ln.lname);
367: else
368: strcat (bldbuf, file[curfile].ln.namep);
369: }
370:
371: op = np;
372: }
373: strcat(bldbuf, op);
374:
375: blank ();
376: if (special) { /* display expanded command */
377: printf( "%s\n", bldbuf);
378: } /* "system" takes long enuf for him to see it */
379: signal(SIGINT, SIG_DFL); /* temp kludge here... */
380: signal(SIGQUIT, SIG_DFL); /* should not use 'system' */
381: system (bldbuf);
382: signal (SIGINT, SIG_IGN);
383: signal (SIGQUIT, SIG_IGN);
384: printf ("\nCR to return...");
385: setdpy ();
386: readchar();
387: blank ();
388: showscreen ();
389: telluser ("");
390: }
391: else { /* CR only, or EOF, or error */
392: /*
393: * He changed his mind, skip it. Since we were in
394: * cooked mode, the CR ending the gets is echoed and
395: * we lost the first line of the display. So we
396: * re-insert it.
397: */
398: setdpy();
399: if (tempbuf[0] == 'x') /* means EOF */
400: telluser("");
401: /* null entry, normal case */
402: else if (AL == 0) { /* no insert line capability */
403: blank();
404: showscreen();
405: }
406: else { /* be a little sneakier */
407: curxy(0, Tscrlen-1); /* go back to where prompt */
408: ceol(); /* is now, and blank it */
409: home();
410: insline(); /* make some room */
411: pentry(topfile);
412: putchar('\n');
413: }
414: curxy(CURSOR, curline);
415: }
416: break;
417:
418: case 'r': /* Reverse sort */
419: curxy (0, Tscrlen);
420: printf ("reverse ");
421: rflg = -1;
422: case 's': /* Normal sort */
423: if (command == 's')
424: {
425: curxy (0, Tscrlen);
426: rflg = 1;
427: }
428: printf ("sort by [s,n,r,w]: ");
429: command = readchar();
430: while ((command == '?') || !((command == 'n') ||
431: (command == 'r') || (command == 'w') || (command == 's') ||
432: (command == CTRL(g))))
433: {
434: curxy (0, Tscrlen);
435: ceol ();
436: if (rflg == -1)
437: printf ("reverse ");
438: printf ("sort by size, name, read or write date: ");
439: command = readchar();
440: }
441:
442: if (command == CTRL(g)) { /* abort */
443: putchar(CTRL(g)); /* echo it */
444: telluser("");
445: curxy(CURSOR, curline);
446: break;
447: }
448:
449: if (command == 's')
450: sortyp = SIZE;
451: else
452: if (command == 'w')
453: sortyp = WRITE;
454: else
455: if (command == 'r')
456: sortyp = READ;
457: else
458: sortyp = 0;
459: printf ("%c", command);
460: qsort (file, totfiles, sizeof (struct lbuf), compar);
461: topfile = 0;
462: curfile = 0;
463: curline = 0;
464: blank ();
465: showscreen ();
466: curxy (CURSOR, 0);
467: break;
468:
469: case 'e': /* Edit a file or directory */
470: if (file[curfile].ltype == 'd') {
471: strcpy (tempbuf, dirednam);
472: catargs(tempbuf, oldargv);
473: }
474: else {
475: if ((t = getenv("EDITOR")) != NULL)
476: strcat(strcpy(tempbuf, t), " ");
477: else
478: strcpy (tempbuf, "ed ");
479: }
480: bldnam(tempbuf, numarg, curfile, argv);
481: blank ();
482: unsetdpy ();
483: system (tempbuf);
484: setdpy ();
485: blank ();
486: showscreen ();
487: telluser ("");
488: break;
489:
490: case 'm': /* 'more' a file */
491: if (file[curfile].ltype == 'd')
492: {
493: telluser ("?Can only page thru files");
494: break;
495: }
496: strcpy (tempbuf, MOREPGM);
497: bldnam(tempbuf, numarg, curfile, argv);
498: blank ();
499: unsetdpy ();
500: system (tempbuf);
501: /* if (!sigint) { */
502: printf ("\nCR to return...");
503: /* } */
504: setdpy ();
505: readchar();
506: blank ();
507: showscreen ();
508: telluser ("");
509: break;
510:
511: case 'T': /* don't wait at page end */
512: case 't': /* quickly type the file -- added 5/81, J.Lepreau */
513: if (file[curfile].ltype == 'd')
514: {
515: telluser ("?Can only type files");
516: break;
517: }
518: tempbuf[0] = '\0';
519: bldnam(tempbuf, numarg, curfile, argv);
520: if (type(tempbuf, command == 't')) /* little t means wait */
521: showscreen ();
522: curxy (CURSOR, curline);
523: break;
524:
525: case 'l': /* Refresh screen */
526: case CTRL(l): /* added for editor compatibility -fjl */
527: blank ();
528: showscreen ();
529: telluser ("");
530: break;
531: case 'c': /* Refresh current line */
532: curxy (0, curline);
533: pentry (curfile);
534: curxy (CURSOR, curline);
535: break;
536: case CTRL(v):
537: case 'f': /* forward window */
538: fscreen ();
539: break;
540: /* wish we could do meta-v */
541: case 'b': /* backward window */
542: bscreen ();
543: break;
544: case CTRL(n):
545: case '\r':
546: case '\n': /* next file */
547: if (curfile == totfiles - 1)
548: telluser ("?At end of files");
549: else
550: if (curline == scrlen - 1)
551: {
552: topfile = curfile;
553: curline = 0;
554: blank ();
555: showscreen ();
556: curxy (CURSOR, 0);
557: downline ();
558: }
559: else
560: downline ();
561: break;
562: case '^': /* previous file */
563: case CTRL(h): /* backspace */
564: case '-':
565: case CTRL(p):
566: if (curfile == 0)
567: telluser ("?At start of files");
568: else
569: if (curline == 0)
570: {
571: topfile = curfile - scrlen + 1;
572: curline = scrlen - 1;
573: blank ();
574: showscreen ();
575: curxy (CURSOR, curline);
576: upline ();
577: }
578: else
579: upline ();
580: break;
581: case 'h': /* Help */
582: case '?':
583: if (type(helpfile, 1)) /* wait */
584: showscreen ();
585: curxy (CURSOR, curline);
586: break;
587: case 'd': /* delete file */
588: if (file[curfile].deleted == DELETED)
589: telluser ("?Already marked deleted");
590: else
591: {
592: numdeleted++;
593: file[curfile].deleted = DELETED;
594: printf ("D%c", 010);
595: if (curline + 1 == scrlen)
596: {
597: fscreen ();
598: downline ();
599: }
600: else
601: if (curfile != totfiles - 1)
602: downline ();
603: }
604: break;
605: case 'u': /* undelete file */
606: if (file[curfile].deleted == NOTDELETED)
607: telluser ("?Not marked deleted");
608: else
609: {
610: numdeleted--;
611: file[curfile].deleted = NOTDELETED;
612: printf (" %c", 010);
613: }
614: break;
615: default:
616: telluser ("Unknown command. Type ? or h for help");
617: break;
618: }
619: }
620: if (numdeleted)
621: {
622: blank ();
623: printf ("The following %s marked for deletion:\n",
624: (numdeleted == 1) ? "is" : "are");
625: typefiles ();
626: printf ("\nShall I delete %s? ",
627: (numdeleted == 1) ? "this" : "these");
628: if ((command = readchar()) != 'y')
629: {
630: blank ();
631: showscreen ();
632: curxy (0, Tscrlen);
633: ceol ();
634: curxy (CURSOR, curline);
635: goto startup;
636: }
637: else
638: {
639: printf ("y\n");
640: for (i = 0; i < totfiles; i++)
641: if (file[i].deleted == DELETED) {
642: nambuf[0] = '\0';
643: bldnam(nambuf, numarg, i, argv);
644: if (file[i].ltype == 'd')
645: rm (nambuf, 0);
646: else
647: if (unlink (nambuf) < 0)
648: printf ("Delete of %s failed.\n", nambuf);
649: }
650: }
651: }
652: else
653: blank ();
654:
655: unsetdpy ();
656: exit(0);
657: }
658:
659: typefiles ()
660: {
661: int longsiz,
662: i,
663: j,
664: maxperln,
665: numout,
666: longthis;
667: longsiz = numout = 0;
668: for (i = 0; i < totfiles; i++)
669: if (file[i].deleted == DELETED)
670: if (file[i].lflags & ISARG)
671: {
672: if (strlen (file[i].ln.namep) > longsiz)
673: {
674: longsiz = strlen (file[i].ln.namep);
675: }
676: }
677: else
678: {
679: if (strlen (file[i].ln.lname) > longsiz)
680: {
681: longsiz = strlen (file[i].ln.lname);
682: }
683: }
684: maxperln = scrwid / (longsiz + 3);
685: for (i = 0; i < totfiles; i++)
686: if (file[i].deleted == DELETED)
687: {
688: if (file[i].lflags & ISARG)
689: {
690: printf ("%s", file[i].ln.namep);
691: longthis = strlen (file[i].ln.namep);
692: }
693: else
694: {
695: printf ("%.14s", file[i].ln.lname);
696: longthis = strlen (file[i].ln.lname);
697: }
698: numout++;
699: if ((numout % maxperln) == 0)
700: putchar ('\n');
701: else if (numout != numdeleted)
702: for (j = 0; j < (longsiz + 3 - longthis); j++)
703: putchar (' ');
704: }
705: }
706:
707: rm (arg, level)
708: char arg[];
709: {
710: struct stat buf;
711: struct direct direct;
712: char name[100];
713: int d;
714:
715: if (stat (arg, &buf))
716: {
717: return;
718: }
719: if ((buf.st_mode & S_IFMT) == S_IFDIR)
720: {
721: if (access (arg, 02) < 0)
722: {
723: printf ("%s not deleted.\n", arg);
724: return;
725: }
726: if ((d = open (arg, 0)) < 0)
727: {
728: printf ("rm: %s: cannot read\n", arg);
729: return;
730: }
731: while (read (d, (char *) & direct, sizeof (direct)) == sizeof (direct))
732: {
733: if (direct.d_ino != 0 && !dotname (direct.d_name))
734: {
735: sprintf (name, "%s/%.14s", arg, direct.d_name);
736: rm (name, level + 1);
737: }
738: }
739: close (d);
740: errcode += rmdir (arg);
741: return;
742: }
743:
744: if (unlink (arg))
745: {
746: ++errcode;
747: printf ("%s not deleted.\n", arg);
748: }
749: }
750:
751: dotname (s)
752: char *s;
753: {
754: if (s[0] == '.')
755: if (s[1] == '.')
756: if (s[2] == '\0')
757: return (1);
758: else
759: return (0);
760: else
761: if (s[1] == '\0')
762: return (1);
763: return (0);
764: }
765:
766: rmdir (f)
767: char *f;
768: {
769: int status,
770: i;
771:
772: if (dotname (f))
773: return (0);
774: while ((i = vfork ()) == -1)
775: sleep (3);
776: if (i == 0) {
777: execl ("/bin/rmdir", "rmdir", f, 0);
778: execl ("/usr/bin/rmdir", "rmdir", f, 0);
779: printf ("rm: can't find rmdir\n");
780: _exit(1);
781: }
782: wait (&status);
783: return (status);
784: }
785:
786: fscreen ()
787: {
788: if (topfile + scrlen - 1 > totfiles - 1)
789: telluser ("?No remaining windows");
790: else
791: {
792: topfile = topfile + scrlen - 1;
793: curfile = topfile;
794: curline = 0;
795: blank ();
796: showscreen ();
797: curxy (CURSOR, 0);
798: }
799: }
800:
801: bscreen ()
802: {
803: if (topfile - scrlen + 1 < 0)
804: telluser ("?No previous windows");
805: else
806: {
807: topfile = topfile - scrlen + 1;
808: curfile = topfile;
809: curline = 0;
810: blank ();
811: showscreen ();
812: curxy (CURSOR, 0);
813: }
814: }
815:
816: showscreen ()
817: {
818: int i,
819: numprint;
820: home ();
821: numprint = 0;
822: for (i = topfile; (numprint < scrlen) && (i < totfiles); i++)
823: {
824: numprint++;
825: pentry (i);
826: putchar ('\n');
827: }
828: if (splitflg)
829: printf ("%s\n", divider);
830: }
831:
832: getdir (dir) /* Reads directory dir */
833: char *dir;
834: {
835: static struct direct dentry;
836: register int j;
837: struct direct *dp;
838: DIR *dirf;
839:
840: if ((dirf = opendir (dir)) == NULL)
841: {
842: printf ("\nSorry, %s unreadable.\n", dir);
843: unsetdpy ();
844: exit(1);
845: }
846: for (;;)
847: {
848: if ((dp = readdir(dirf)) == NULL)
849: break;
850: dentry = *dp;
851: if (dentry.d_ino == 0
852: || dentry.d_name[0] == '.' && (dentry.d_name[1] == '\0'
853: || dentry.d_name[1] == '.' && dentry.d_name[2] == '\0'))
854: continue;
855:
856: if (totfiles == MAXFILES)
857: overflow(); /* abort, too may files */
858: /* Just ignore if can't find the file, dir may be changing */
859: if (gstat (makename (dir, dentry.d_name)) == 0) { /* 0 == Ok */
860: file[totfiles].lnum = dentry.d_ino;
861: strncpy(file[totfiles].ln.lname, dentry.d_name, MAXN);
862: totfiles++;
863: if (totfiles % 10 == 0)
864: putchar ('.');
865: }
866: }
867: closedir (dirf);
868: }
869:
870: gstat (name) /* Stats the file with name */
871: char *name;
872: {
873:
874: file[totfiles].lflags = 0;
875: file[totfiles].lnum = 0;
876: file[totfiles].ltype = '-';
877:
878: if (stat (name, &statbuf) < 0)
879: {
880: return(-1);
881: }
882: file[totfiles].lnum = statbuf.st_ino;
883: file[totfiles].lsize = statbuf.st_size;
884: switch (statbuf.st_mode & S_IFMT)
885: {
886: case S_IFLNK:
887: file[totfiles].ltype = 'l';
888: break;
889: case S_IFDIR:
890: file[totfiles].ltype = 'd';
891: break;
892: case S_IFBLK:
893: file[totfiles] .ltype = 'b';
894: file[totfiles].lsize = statbuf.st_rdev;
895: break;
896: case S_IFCHR:
897: file[totfiles].ltype = 'c';
898: file[totfiles].lsize = statbuf.st_rdev;
899: break;
900: }
901: file[totfiles].lflags = statbuf.st_mode & ~S_IFMT;
902: file[totfiles].luid = statbuf.st_uid;
903: file[totfiles].lgid = statbuf.st_gid;
904: file[totfiles].lnl = statbuf.st_nlink;
905: file[totfiles].latime = statbuf.st_atime;
906: file[totfiles].lctime = statbuf.st_ctime;
907: file[totfiles].lmtime = statbuf.st_mtime;
908: totblocks += nblock (statbuf.st_size);
909: return(0);
910: }
911:
912: char *
913: makename (dir, filen)
914: char *dir,
915: *filen;
916: {
917: static char dfile[100];
918: register char *dp,
919: *fp;
920: register int i;
921:
922: dp = dfile;
923: fp = dir;
924: while (*fp)
925: *dp++ = *fp++;
926: *dp++ = '/';
927: fp = filen;
928: strcpy(dp, fp);
929: return (dfile);
930: }
931:
932: long
933: nblock (size)
934: long size;
935: {
936: return ((size + 511) >> 9);
937: }
938:
939: pentry (whichone)
940: int whichone;
941: {
942: struct
943: {
944: char dminor,
945: dmajor;
946: };
947: register t;
948: register char *cp;
949:
950: if (file[whichone].lnum == -1)
951: return;
952: if (iflg)
953: printf ("%5u ", file[whichone].lnum);
954: if (sflg)
955: printf ("%4D ", nblock (file[whichone].lsize));
956: if (lflg)
957: {
958: putchar (file[whichone].ltype);
959: pmode (file[whichone].lflags);
960: printf ("%2d ", file[whichone].lnl);
961: t = file[whichone].luid;
962: if (gflg)
963: t = file[whichone].lgid;
964: if (getname (t, userbuf) == 0)
965: printf ("%-14.14s", userbuf);
966: else
967: printf ("%-14d", t);
968: if (file[whichone].ltype == 'b' || file[whichone].ltype == 'c')
969: printf ("%3d,%3d", major ((int) file[whichone].lsize),
970: minor ((int) file[whichone].lsize));
971: else
972: printf ("%7ld", file[whichone].lsize);
973: if ((sortyp == WRITE) || (sortyp == 0) || (sortyp == SIZE))
974: {
975: cp = ctime (&file[whichone].lmtime);
976: if (file[whichone].lmtime < year)
977: printf (" %-7.7s %-4.4s ", cp + 4, cp + 20);
978: else
979: printf (" %-12.12s ", cp + 4);
980: }
981: else
982: if (sortyp == READ)
983: {
984: cp = ctime (&file[whichone].latime);
985: if (file[whichone].latime < year)
986: printf (" %-7.7s %-4.4s ", cp + 4, cp + 20);
987: else
988: printf (" %-12.12s ", cp + 4);
989: }
990: }
991: printf ("%c", file[whichone].deleted ? 'D' : ' ');
992: if (file[whichone].lflags & ISARG)
993: printf (" %s", file[whichone].ln.namep);
994: else {
995: putchar(' ');
996: for (t=0; t<14; t++) {
997: register c = file[whichone].ln.lname[t] & 0377;;
998: if (c == '\0')
999: break;
1000: if (c<' ' || c>=0200) {
1001: c &= 0177;
1002: c |= 0100;
1003: putchar('^');
1004: }
1005: putchar(c);
1006: }
1007: }
1008: }
1009:
1010: getname (uid, buf)
1011: int uid;
1012: char buf[];
1013: {
1014: int j,
1015: c,
1016: n, sign,
1017: i;
1018:
1019: if (uid == lastuid)
1020: return (0);
1021: if (pwdf == NULL)
1022: return (-1);
1023: rewind (pwdf);
1024: lastuid = -1;
1025: do
1026: {
1027: i = 0;
1028: j = 0;
1029: n = 0;
1030: sign = 0;
1031: while ((c = fgetc (pwdf)) != '\n')
1032: {
1033: if (c == EOF)
1034: return (-1);
1035: if (c == ':')
1036: {
1037: j++;
1038: c = '0';
1039: }
1040: if (j == 0)
1041: buf[i++] = c;
1042: if (j == 2) {
1043: if (c=='-')
1044: sign = 1;
1045: else
1046: n = n * 10 + c - '0';
1047: }
1048: }
1049: if (sign)
1050: n = -n;
1051: n = (unsigned short)n;
1052: } while (n != uid);
1053: buf[i++] = '\0';
1054: lastuid = uid;
1055: return (0);
1056: }
1057:
1058: int m1[] =
1059: {
1060: 1, S_IREAD >> 0, 'r', '-'
1061: };
1062: int m2[] =
1063: {
1064: 1, S_IWRITE >> 0, 'w', '-'
1065: };
1066: int m3[] =
1067: {
1068: 2, S_ISUID, 's', S_IEXEC >> 0, 'x', '-'
1069: };
1070: int m4[] =
1071: {
1072: 1, S_IREAD >> 3, 'r', '-'
1073: };
1074: int m5[] =
1075: {
1076: 1, S_IWRITE >> 3, 'w', '-'
1077: };
1078: int m6[] =
1079: {
1080: 2, S_ISGID, 's', S_IEXEC >> 3, 'x', '-'
1081: };
1082: int m7[] =
1083: {
1084: 1, S_IREAD >> 6, 'r', '-'
1085: };
1086: int m8[] =
1087: {
1088: 1, S_IWRITE >> 6, 'w', '-'
1089: };
1090: int m9[] =
1091: {
1092: 2, 0/*S_ISVTX*/, 't', S_IEXEC >> 6, 'x', '-'
1093: };
1094:
1095: int *m[] =
1096: {
1097: m1, m2, m3, m4, m5, m6, m7, m8, m9
1098: };
1099:
1100: pmode (aflag)
1101: {
1102: register int **mp;
1103:
1104: flags = aflag;
1105: for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])];)
1106: select (*mp++);
1107: }
1108:
1109: select (pairp)
1110: register int *pairp;
1111: {
1112: register int n;
1113:
1114: n = *pairp++;
1115: while (--n >= 0 && (flags & *pairp++) == 0)
1116: pairp++;
1117: putchar (*pairp);
1118: }
1119:
1120: compar (pp1, pp2)
1121: struct lbuf *pp1,
1122: *pp2;
1123: {
1124: register struct lbuf *p1,
1125: *p2;
1126:
1127: p1 = pp1;
1128: p2 = pp2;
1129: if (p1 -> lflags & ISARG && p1 -> ltype == 'd')
1130: {
1131: if (!(p2 -> lflags & ISARG && p2 -> ltype == 'd'))
1132: return (1);
1133: }
1134: else
1135: {
1136: if (p2 -> lflags & ISARG && p2 -> ltype == 'd')
1137: return (-1);
1138: }
1139: if (sortyp == SIZE)
1140: {
1141: if (p2 -> lsize == p1 -> lsize)
1142: return (0);
1143: if (p2 -> lsize > p1 -> lsize)
1144: return (rflg);
1145: return (-rflg);
1146: }
1147: else
1148: if (sortyp == WRITE)
1149: {
1150: if (p2 -> lmtime == p1 -> lmtime)
1151: return (0);
1152: if (p2 -> lmtime > p1 -> lmtime)
1153: return (rflg);
1154: return (-rflg);
1155: }
1156: else
1157: if (sortyp == READ)
1158: {
1159: if (p2 -> latime == p1 -> latime)
1160: return (0);
1161: if (p2 -> latime > p1 -> latime)
1162: return (rflg);
1163: return (-rflg);
1164: }
1165: return (rflg * strcmp (p1 -> lflags & ISARG ? p1 -> ln.namep : p1 -> ln.lname,
1166: p2 -> lflags & ISARG ? p2 -> ln.namep : p2 -> ln.lname));
1167: }
1168:
1169: ceod()
1170: {
1171: putpad(CD);
1172: }
1173:
1174: ceol ()
1175: {
1176: putpad (CE);
1177: }
1178: blank ()
1179: {
1180: putpad (CL);
1181: }
1182: home ()
1183: {
1184: if (HO)
1185: putpad (HO);
1186: else
1187: curxy(0,0);
1188: }
1189: insline ()
1190: {
1191: putpad (AL);
1192: }
1193:
1194: /* Yes, folks, we use direct cursor addressing to get to next line!
1195: Before you mumble "What sort of cretin would do this?" here's
1196: the reason. We don't use \n since that obviously won't work.
1197: We don't use \012 since virgin version 7 makes that into a crlf.
1198: We don't use raw mode since we type out help files efficently,
1199: and we don't want to switch modes all the time. So enjoy. -- SMC */
1200:
1201: downline ()
1202: {
1203: curxy (CURSOR, ++curline);
1204: curfile++;
1205: }
1206: upline ()
1207: {
1208: putpad (UP);
1209: curline--;
1210: curfile--;
1211: }
1212:
1213: /*VARARGS1*/
1214: telluser (msg, args)
1215: char *msg;
1216: {
1217: curxy (0, Tscrlen);
1218: ceol ();
1219: printf (msg, args);
1220: curxy (CURSOR, curline);
1221: blurb++;
1222: }
1223: curxy (col, lin)
1224: {
1225: char *cmstr = tgoto (CM, col, lin);
1226: putpad (cmstr);
1227: }
1228:
1229: char *fgets();
1230:
1231: type (filestr, waitflg) /* Modified to type help file & others. fjl 5/81 */
1232: char *filestr; /* Kludgy now with split screen stuff! */
1233: {
1234: int helpfd = 5;
1235: FILE *fd = stdin;
1236: char *eof;
1237: register int i, n;
1238: register int cc = 0;
1239: int cur_scrl; /* current screen length */
1240: char helpbuf[512];
1241:
1242: if (!splitflg)
1243: helpfd = open(filestr, 0);
1244: else
1245: fd = fopen(filestr, "r");
1246: if (helpfd < 0 || fd == NULL) {
1247: telluser("?Unable to open %sfile",strcmp(filestr,helpfile)?"":"help ");
1248: return (FALSE);
1249: }
1250:
1251: signal(SIGINT, catchint);
1252: sigint = 0;
1253:
1254: if (!splitflg) {
1255: blank();
1256: fflush(stdout);
1257: while ((i = read (helpfd, helpbuf, 512)) > 0 && !sigint)
1258: write (1, helpbuf, i);
1259: close(helpfd);
1260: }
1261: else {
1262: cur_scrl = totfiles - topfile + 1; /* topfile starts at 0 */
1263: Worktop = ((cur_scrl < scrlen) ? cur_scrl : scrlen) + 1;
1264: do {
1265: curxy(0, Worktop);
1266: ceod();
1267: for (i = Worktop; (i < Tscrlen) && !sigint && (cc != EOF); i++) {
1268: n = 0;
1269: while ((cc = getc(fd)) != EOF) {
1270: if (cc == '\t')
1271: n |= 07;
1272: chklen: if (n++ == scrwid-1) { /* Use most of screen */
1273: if (cc != '\n') {
1274: ungetc(cc, fd);
1275: cc = '\n';
1276: }
1277: }
1278: if (cc < ' ' && cc!='\n' && cc!='\t' || cc>=0200) {
1279: putchar('^');
1280: cc &= 0177;
1281: cc |= 0100;
1282: goto chklen;
1283: }
1284: putchar(cc);
1285: if (cc == '\n')
1286: break;
1287: }
1288: }
1289: } while (!sigint && (cc != EOF) && waitchk(waitflg));
1290:
1291: if (feof(fd))
1292: printf("===== End-of-File =====\n");
1293: fflush(stdout);
1294: fclose(fd);
1295: return(FALSE); /* means needs no re-display */
1296: }
1297:
1298: if (!splitflg) { /* redundant now... */
1299: if (!sigint) {
1300: curxy(0, Tscrlen);
1301: printf ("CR to return...");
1302: readchar();
1303: }
1304: blank ();
1305: return (TRUE);
1306: }
1307: }
1308:
1309: waitchk(waitflg)
1310: {
1311: if (!waitflg)
1312: return(1);
1313: fflush(stdout);
1314: curxy(0, Tscrlen);
1315: printf ("---Continue---");
1316: ceol();
1317: curxy(0, Tscrlen);
1318: readchar();
1319: ceol();
1320: if (sigint)
1321: return(0); /* avoids clear of screen */
1322: return(1);
1323: }
1324:
1325: setdpy ()
1326: {
1327: ioctl (0, TIOCGETP, &ioctlb);
1328: ioctlb.sg_flags |= CBREAK;
1329: ioctlb.sg_flags &= ~ECHO;
1330: ioctl (0, TIOCSETP, &ioctlb);
1331: }
1332:
1333: unsetdpy ()
1334: {
1335: ioctlb.sg_flags &= ~CBREAK;
1336: ioctlb.sg_flags |= ECHO;
1337: ioctl (0, TIOCSETP, &ioctlb);
1338: }
1339:
1340: getcap ()
1341: {
1342: char *ap;
1343: char *term;
1344: char *xPC;
1345:
1346: term = getenv ("TERM");
1347: if (term == 0)
1348: {
1349: printf("No TERM in environment\n");
1350: exit(1);
1351: }
1352:
1353: switch (tgetent (tbuf, term))
1354: {
1355: case -1:
1356: printf("Cannot open termcap file\n");
1357: exit (2);
1358: case 0:
1359: printf("%s: unknown terminal", term);
1360: exit (3);
1361: }
1362:
1363: ap = tcapbuf;
1364:
1365: Tscrlen = tgetnum ("li") - 1;
1366: scrwid = tgetnum ("co") - 1;/* lose 1 so won't scroll in last line */
1367:
1368: UP = tgetstr ("up", &ap);
1369: CD = tgetstr ("cd", &ap);
1370: CE = tgetstr ("ce", &ap);
1371: HO = tgetstr ("ho", &ap);
1372: CL = tgetstr ("cl", &ap);
1373: CM = tgetstr ("cm", &ap);
1374: AL = tgetstr ("al", &ap); /* insert line, optional */
1375:
1376: xPC = tgetstr ("pc", &ap);
1377: if (xPC)
1378: PC = *xPC;
1379:
1380: if ((CM == 0) || (CL == 0) || (UP == 0))
1381: {
1382: printf("Tty must have cursor addr, clear, and 4 cursor motions.\n");
1383: exit (1);
1384: }
1385: if (Tscrlen <= 0 || scrwid <= 0)
1386: {
1387: printf("Must know the screen size\n");
1388: exit (1);
1389: }
1390: }
1391:
1392: outch (c)
1393: {
1394: putchar (c);
1395: }
1396:
1397: putpad (str)
1398: char *str;
1399: {
1400: if (str)
1401: tputs (str, 0, outch);
1402: }
1403:
1404: catchint(sig)
1405: {
1406: signal(SIGINT, SIG_IGN); /* reset it */
1407: sigint = 1;
1408: }
1409:
1410: char *
1411: bldnam(str, numarg, filidx, argv)
1412: char *str;
1413: char *argv[];
1414: {
1415:
1416: if (numarg == 1)
1417: strcat (str, file[filidx].ln.lname);
1418: else
1419: if (numarg == 2) {
1420: strcat (str, argv[1]);
1421: strcat (str, "/");
1422: strcat (str, file[filidx].ln.lname);
1423: }
1424: else
1425: strcat (str, file[filidx].ln.namep);
1426: return(str);
1427: }
1428:
1429: char *
1430: catargs(str, argv)
1431: char *str;
1432: char *argv[];
1433: {
1434: register int i;
1435:
1436: for (++argv; *argv; argv++) {
1437: if (**argv == '-') {
1438: strcat(str, *argv);
1439: strcat(str, " ");
1440: }
1441: }
1442: return(str);
1443: }
1444:
1445: overflow()
1446: {
1447: printf("\n?Too many files\007\n");
1448: fflush(stdout);
1449: sleep(1); /* So user can see it - don't worry if less */
1450: }
1451:
1452: char *skipto (string,charset)
1453: char *charset,*string;
1454: {
1455: register char *setp,*strp;
1456: register int found;
1457:
1458: found = 0; /* not found yet */
1459: strp = string; /* start at first char */
1460:
1461: while (*strp && !found) { /* until null or found */
1462: /* find first char in charset matching *strp */
1463: for (setp=charset; (*setp) && (*setp != *strp); setp++) ;
1464: if (*setp) found = 1; /* matches a char */
1465: else strp++; /* else keep looking */
1466: }
1467:
1468: return (strp);
1469: }
1470:
1471: readchar()
1472: {
1473: static neofs;
1474: register c;
1475:
1476: fflush(stdout);
1477: c = getchar();
1478: if (c == EOF)
1479: if (++neofs > 100)
1480: exit(1);
1481: return(c);
1482: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.