source: buchla-68k/orig/GEMDOS/LS.C@ 4b63bf3

Last change on this file since 4b63bf3 was 3ae31e9, checked in by Thomas Lopatic <thomas@…>, 7 years ago

Imported original source code.

  • Property mode set to 100755
File size: 15.9 KB
Line 
1/*
2 =============================================================================
3 ls.c - a Unix-like directory listing program for GEMDOS
4 Version 1 -- 1988-05-18
5 =============================================================================
6*/
7
8#include "stdio.h"
9#include "stddefs.h"
10#include "malloc.h"
11#include "osbind.h"
12
13#undef ANSI /* if ansi display */
14#define GLASS /* if glass tty */
15
16#define QS '\\' /* filename separator (character) */
17#define DQS "\\" /* filename separator (string) */
18
19#define ID TRUE /* always identify directory if TRUE */
20#define ALL TRUE /* show hidden files by default if TRUE */
21#define LONG TRUE /* long listing by default if TRUE */
22#define COLM FALSE /* 1-column listing by default if TRUE */
23#define RSORT FALSE /* reverse sort by default if TRUE */
24#define TSORT FALSE /* time sort by default if TRUE */
25#define DU FALSE /* include disk use by default if TRUE */
26
27#define NAMESIZ 13 /* 12 character name + NULL */
28#define ONECS 512 /* cluster size on one-sided floppy */
29#define TWOCS 1024 /* cluster size on two-sided floppy */
30#define HARDCS 4096 /* cluster size on hard disk */
31#define SCRSIZ 22 /* scrolling size of display screen */
32
33/*
34
35*/
36
37struct dta { /* DOS Disk Transfer Address table */
38
39 char reserved[21]; /* used in "find next" operation */
40 char attr; /* file attribute byte */
41 int ftime; /* time of last modification */
42 int fdate; /* date of last modification */
43 long fsize; /* file size in bytes */
44 char fname[NAMESIZ]; /* filename and extension */
45};
46
47struct outbuf { /* output buffer -- array of file structs */
48
49 unsigned oattr;
50 unsigned odate;
51 unsigned otime;
52 long osize;
53 char oname[NAMESIZ+1];
54
55} *obuf;
56
57/*
58
59*/
60
61char spath[80]; /* holds current pathname string */
62
63int allf = ALL; /* include hidden & system files */
64int ll = LONG; /* long listing */
65int colm = COLM; /* 1-column format */
66int rev = RSORT; /* reverse sort */
67int tsrt = TSORT; /* timesort the listing */
68int usage = DU; /* print disk usage */
69int recd; /* recursive descent requested */
70int sizonly; /* only print sizes */
71int np; /* number of groups printed */
72int nargs; /* number of non-option arguments */
73int clsize = 0; /* size of a cluster, in bytes */
74int clmask; /* clsize-1 for rounding & chopping */
75int drive; /* code number for drive requested */
76int tsc; /* 1 if output is to console screen */
77
78long left; /* unused space left on disk */
79long total; /* total of sizes encountered */
80
81/*
82
83*/
84
85main(argc, argv)
86int argc;
87char *argv[];
88{
89 char *s;
90 int c;
91 int nt;
92
93 nt = 0;
94 c = 0;
95
96 /* process input options */
97
98 while (--argc > 0 AND (*++argv)[0] EQ '-') {
99
100 for (s = argv[0] + 1; *s NE '\0'; s++) {
101
102 switch (0x007F & *s) {
103
104 case 'a': /* -a: list all files */
105
106 allf = NOT allf;
107 break;
108
109 case 'c': /* -c: 1-column listing requested */
110
111 colm = NOT colm;
112 break;
113
114 case 'l': /* -l: long listing requested */
115
116 ll = NOT ll;
117 break;
118
119 case 'r': /* -r: reverse sort direction */
120
121 rev = NOT rev;
122 break;
123
124 case 's': /* -s: print sizes only */
125
126 sizonly = TRUE;
127
128 if (*(s+1) EQ '1') {
129
130 clsize = ONECS; /* diskuse for 1-sided floppy */
131 s++;
132 nt++;
133
134 } else if (*(s+1) EQ '2') {
135
136 clsize = TWOCS; /* or 2-sided */
137 s++;
138 nt++;
139 }
140
141 break;
142
143 case 't': /* -t: time sort requested */
144
145 tsrt = NOT tsrt;
146 break;
147
148 case 'u': /* -u: print disk usage */
149
150 usage = NOT usage;
151 break;
152
153 case 'R': /* -R: recursively list subdirs */
154
155 recd = 1;
156 break;
157
158 default:
159
160 fprintf(stderr, "unknown arg %c\n", *s);
161 exit(1);
162 }
163 }
164 }
165
166/*
167
168*/
169
170 nargs = argc;
171 tsc = toscreen(); /* find out if output is to console screen */
172 obuf = (struct outbuf *)malloc(sizeof(*obuf)); /* point to free memory */
173
174 if (argc EQ 0) {
175
176 argc++;
177 curdrv(spath); /* default to current drive */
178
179 } else
180 strcpy(spath, *argv);
181
182 FOREVER { /* cycle through args present */
183
184 if (spath[1] EQ ':' AND spath[2] EQ '\0') /* if drive only */
185 getpath(spath); /* get path */
186
187 if (usage OR sizonly OR ll)
188 c = getsize(spath); /* get use data only if needed */
189
190 if (c EQ 0)
191 search(spath); /* go do the hard work */
192
193 if (--argc > 0) {
194
195 strcpy(spath, *++argv);
196
197 } else {
198
199 if (usage OR sizonly) {
200
201 if (np > 1) {
202
203 fprintf(stdout, "-------\n%7ld bytes total", total);
204
205 if (!nt)
206 fputs("; ", stdout);
207 }
208
209 if (!nt)
210 fprintf(stdout, "%7ld bytes left on drive %c\n",
211 left, drive+'a');
212 }
213
214 return;
215 }
216 }
217}
218
219/*
220
221*/
222
223int
224getsize(path) /* get file cluster size */
225char *path;
226{
227 if (clsize EQ 0) { /* if size not already set */
228
229 if ((clsize = getcl(path)) EQ 0) { /* get cluster size for drive */
230
231 fprintf(stderr, "Invalid drive: %c\n", *path);
232 return(1);
233 }
234 }
235
236 clmask = clsize-1;
237 return(0);
238}
239
240/*
241
242*/
243
244/* toscreen - find out if output is to console screen */
245
246int
247toscreen()
248{
249 struct {
250
251 unsigned int ax,
252 bx,
253 cx,
254 dx,
255 si,
256 di,
257 ds,
258 es;
259 } r;
260
261 r.ax = 0x4400;
262 r.bx = 1;
263 sysint(0x21, &r, &r);
264 return(r.dx & 1);
265}
266
267/*
268
269*/
270
271/* search - search 'path' for filename or directory */
272
273search(path)
274char *path;
275{
276 struct dta dta; /* DOS file data table */
277 extern struct outbuf; /* array of file structs */
278 extern int nargs; /* number of files or directories */
279 int path_len; /* length of initial path */
280 int z; /* char counter */
281 int k = 0; /* counts number of entries found */
282 char work[80]; /* working path string */
283 int comp(); /* string, time comparison routine */
284 int mask = 0x0010; /* attribute mask */
285 long bytes = 0; /* count of disk usage this directory */
286
287 if (allf)
288 mask = 0x001F;
289
290 strcpy(work,path);
291 path_len = strlen(work); /* save original path length */
292
293 if (!find_first(work, &dta, 0) OR work[path_len-1] EQ QS) {
294
295 if (work[path_len-1] NE QS) {
296
297 strcat(work, DQS); /* if path is to a directory */
298 path_len++;
299 }
300
301 strcat(work,"*.*"); /* list everything in it */
302 }
303
304/*
305
306*/
307
308 if (find_first(work, &dta, mask)) {
309
310 do {
311
312 if (dta.attr & 0x08) /* ignore volume label */
313 continue;
314
315 if (dta.fname[0] EQ '.' AND !allf) /* unless -a option */
316 continue; /* ignore "." and ".." */
317
318 obuf[k].oattr = dta.attr; /* stash this entry */
319 obuf[k].otime = dta.ftime;
320 obuf[k].odate = dta.fdate;
321 obuf[k].osize = dta.fsize;
322 strcpy(obuf[k].oname, dta.fname);
323
324 if (usage OR sizonly) {
325
326 if ((dta.attr & 0x10) AND dta.fname[0] NE '.') {
327
328 bytes += clsize; /* sum up disk usage */
329
330 } else if (dta.fsize) {
331
332 obuf[k].osize = ((dta.fsize + clmask) & (long)(~clmask));
333 bytes += obuf[k].osize;
334 }
335 }
336
337 k++;
338
339 } while (find_next(&dta));
340
341 } else {
342
343 work[path_len-1] = NULL;
344 fprintf(stderr, "Can't find a file or directory named \"%s\"\n", work);
345 return;
346 }
347
348/*
349
350*/
351 work[path_len] = NULL; /* restore directory pathname */
352
353 if (np++ AND !sizonly)
354 fputc(endlin(),stdout); /* separate listing blocks */
355
356 if (usage OR sizonly) {
357
358 total += bytes; /* total bytes to date */
359 fprintf(stdout, "%7ld ", bytes);
360 }
361
362 if (recd OR nargs > 1 OR usage OR sizonly OR ID) {
363
364 fprintf(stdout, "%s", work); /* identify the block */
365 fputc(endlin(),stdout);
366 }
367
368 if (!sizonly) {
369
370 qsort(obuf,k,sizeof(obuf[0]),comp); /* sort the entries */
371
372 if (ll)
373 longlist(k); /* and print them */
374 else
375 shortlist(k);
376 }
377
378 if (!recd)
379 return; /* quit if not -R */
380
381 strcat(work, "*.*");
382
383 if (find_first(work, &dta, mask)) /* else find all sub-dirs */
384 do {
385
386 if (dta.attr & 0x10 AND dta.fname[0] NE '.') {
387
388 work[path_len] = 0; /* discard old name */
389
390 for (z=0; dta.fname[z] NE NULL; z++)
391 dta.fname[z] = tolower(dta.fname[z]);
392
393 strcat(work, dta.fname); /* install a new one */
394 strcat(work, DQS);
395 search(work); /* and recurse */
396 }
397
398 } while (find_next(&dta));
399
400 return;
401}
402
403/*
404
405*/
406
407/* find_first - find first file in chosen directory */
408
409find_first(path, dta, mask)
410char *path;
411struct dta *dta;
412int mask;
413{
414 struct {
415
416 int ax, bx, cx;
417 char *dx;
418 int si, di, ds, es;
419 } r;
420 extern int _showds();
421
422 r.ax = 0x1A00; /* DOS interrupt 1A */
423 r.dx = (char *)dta;
424 r.ds = _showds();
425 sysint(0x21, &r, &r); /* sets data transfer address */
426
427 r.ax = 0x4E00; /* DOS interrupt 4E */
428 r.cx = mask;
429 r.dx = path;
430 r.ds = _showds();
431 return(!(sysint(0x21, &r, &r) & 1)); /* fills the structure */
432}
433
434/*
435
436*/
437
438/* find_next - find the next file in the same directory */
439
440find_next(dta)
441struct dta *dta;
442{
443 struct {
444
445 int ax, bx, cx;
446 char *dx;
447 int si, di, ds, es;
448 } r;
449 extern int _showds();
450
451 r.ax = 0x1A00;
452 r.dx = (char *)dta;
453 r.ds = _showds();
454 sysint(0x21, &r, &r); /* set dta */
455
456 r.ax = 0x4F00;
457 return(!(sysint(0x21, &r, &r) & 1)); /* fill the table */
458}
459
460/*
461
462*/
463
464/* curdrv - get current default drive */
465
466curdrv(sp)
467char *sp;
468{
469 struct {
470
471 int ax, bx, cx;
472 char *dx, *si, *di, *ds, *es;
473 } r;
474
475 r.ax = 0x1900; /* DOS interrupt 19 */
476 sysint(0x21, &r, &r); /* gets current drive number */
477 *sp++ = r.ax + 'a'; /* convert to symbolic drive name */
478 *sp++ = ':';
479 return;
480}
481
482/*
483
484*/
485
486/* getpath - get path to directory on indicated drive */
487
488getpath(sp)
489char *sp;
490{
491 struct {
492
493 int ax, bx, cx, dx;
494 char *si;
495 int di, ds, es;
496 } r;
497 extern int _showds();
498
499 strcat(sp, DQS); /* append root file symbol to drive name */
500
501 r.ax = 0x4700; /* DOS interrupt 47 gets path string */
502 r.dx = *sp - '`'; /* convert drive name to index */
503 r.ds = _showds();
504 r.si = sp + 3; /* paste string after root symbol */
505 sysint(0x21, &r, &r);
506 return;
507}
508
509/*
510
511*/
512
513/* getcl - get cluster size & space left on requested drive */
514
515int
516getcl(pp)
517char *pp;
518{
519 struct {
520
521 int ax, bx, cx, dx, si, di, ds, es;
522 } r;
523 int cs;
524 extern long left;
525 extern int drive;
526
527 if (*(pp+1) EQ ':') /* use specified drive if any */
528 r.ax = *pp - 'a';
529 else {
530
531 r.ax = 0x1900; /* else get code for default drive */
532 sysint(0x21, &r, &r);
533 }
534
535 drive = r.ax & 0x7F;
536
537 if (!usage AND !sizonly AND drive EQ 2)
538 return(HARDCS);
539 else {
540
541 r.dx = drive + 1; /* 0 = default, 1 = a, etc */
542 r.ax = 0x3600;
543 sysint(0x21, &r, &r); /* DOS interrupt hex 36 */
544
545 if (r.ax EQ 0xFFFF) /* gets free disk space */
546 return(0); /* and other goodies */
547 else {
548 cs = r.ax * r.cx; /* r.ax = sectors/cluster */
549 left = (long)cs * r.bx; /* r.bx = # unused clusters */
550 return(cs); /* r.cx = bytes/sector */
551 } /* r.dx = drive capacity (clusters) */
552 }
553}
554
555/*
556
557*/
558
559/* comp - compare size of two entries */
560
561int
562comp(a,b)
563struct outbuf *a, *b;
564{
565 int y;
566
567 if (tsrt) {
568
569 if (a->odate NE b->odate) /* if dates differ */
570 y = (a->odate < b->odate) ? -1 : 1; /* that settles it */
571 else
572 y = (a->otime < b->otime) ? -1 : 1; /* else compare times */
573
574 return((rev) ? y : -y);
575
576 } else {
577
578 y = strcmp(a->oname, b->oname); /* name comparison */
579 return((rev) ? -y : y);
580 }
581}
582
583/*
584
585*/
586
587/* shortlist - print a list of names in 5 columns */
588
589shortlist(k)
590int k; /* total number to print */
591{
592 int i, m, n;
593
594 if (colm)
595 n = k; /* set for 1-column listing */
596 else
597 n = (k + 4)/5; /* or 5-column */
598
599 for (i=0; i < n; i++){
600
601 for (m = 0; (i+m) < k; m += n) {
602
603 if (obuf[i+m].oattr & 0x10)
604 strcat(obuf[i+m].oname, DQS); /* mark directories */
605
606 putname(i+m); /* print the name */
607 fputs(" ", stdout);
608 }
609
610 fputc(endlin(),stdout);
611 }
612
613 return;
614}
615
616/*
617
618*/
619
620/* putname - convert name to lower case and print */
621
622putname(i)
623int i;
624{
625 int c, j = 0;
626
627 while ((c = tolower(obuf[i].oname[j])) NE 0) {
628
629 fputc(c, stdout);
630 j++;
631 }
632
633 while (j++ < NAMESIZ - 1) /* pad to columnarize */
634 fputc(' ', stdout);
635}
636
637/*
638
639*/
640
641/* endlin - end a line and watch for screen overflow */
642
643static int lc = 0; /* line counter */
644
645endlin(fp)
646FILE *fp;
647{
648 extern int tsc; /* true if output is to screen */
649 int c;
650
651 if (tsc AND ++lc GE SCRSIZ) { /* pause if output is to console screen */
652 /* and we've shown a screenful */
653
654#ifdef ANSI
655 fputs("\n\033[30;43m--More--", fp);
656 c = ci();
657 fputs("\033[32;40m\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b", fp);
658#endif
659
660#ifdef GLASS
661 fputs("\n--More--", fp);
662 c = ci();
663 fputs("\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b", fp);
664#endif
665
666 switch (c) {
667
668 case '\r': /* <RETURN> - show 1 more line */
669
670 lc = SCRSIZ - 1;
671 break;
672
673 case 'q': /* quit with "q" or "ctrl-C" */
674 case '\003':
675
676 exit(0);
677
678 default:
679
680 lc = 0; /* else show another screenful */
681 break;
682 }
683
684 return('\b');
685
686 } else
687 return('\n');
688}
689
690/*
691
692*/
693
694/* longlist - list everything about files in two columns */
695
696struct llst { /* structure to hold file information */
697
698 char *fattr; /* file attribute pointer */
699 long size; /* file size */
700 int day; /* the day of creation */
701 int mnum; /* month number */
702 int yr;
703 int hh; /* creation times */
704 int mm;
705 int ap; /* am or pm */
706} l;
707
708/*
709
710*/
711
712longlist(k)
713int k; /* total number to list */
714{
715
716 int i, m, n, cdate;
717 char *mon, *mname();
718
719 cdate = gcdate(); /* get current date (in months) */
720
721 if (colm)
722 n = k; /* set for 1 column listing */
723 else
724 n = (k + 1)/2; /* or for 2 column listing */
725
726 for (i=0; i < n; i++){
727
728 for (m = 0; (m+i) < k; m += n) {
729
730 fill(i+m, &l); /* fill llst structure */
731 mon = mname(l.mnum); /* conv month # to name */
732
733 fprintf(stdout, "%s%7ld %2d %s ",
734 l.fattr, l.size, l.day, mon);
735
736 if (cdate GE (l.yr * 12 +l.mnum) + 12)
737 fprintf(stdout, " %4d ", l.yr); /* print year if too old */
738 else {
739 fprintf(stdout, "%2d:%02d%c ",
740 l.hh, l.mm, l.ap); /* else print time */
741 }
742
743 putname(i+m);
744
745 if (m+n < k)
746 fputs("\272 ", stdout); /* double bar separator */
747 }
748
749 fputc(endlin(),stdout);
750 }
751
752 return;
753}
754
755/*
756
757*/
758
759/* fill - fill long list structure with file information */
760
761fill(i, ll)
762int i;
763struct llst *ll;
764{
765 int j, k;
766 static char fbuf[16][4] = {
767
768 "--w",
769 "---",
770 "-hw",
771 "-h-",
772 "s-w",
773 "s--",
774 "shw",
775 "sh-",
776 "d-w",
777 "d--",
778 "dhw",
779 "dh-",
780 "d-w",
781 "d--",
782 "dhw",
783 "dh-"
784 };
785
786/*
787
788*/
789
790 if ((obuf[i].oattr & 0x10) AND obuf[i].oname[0] NE '.') {
791
792 ll->size = clsize;
793 j = 8; /* if directory, use block size */
794
795 } else { /* and set dir attr offset */
796
797 ll->size = obuf[i].osize; /* else use file size */
798 j = 0; /* and file attr offset */
799 }
800
801 ll->fattr = fbuf[(obuf[i].oattr & 0x07) + j]; /* point to symbolic attr */
802 ll->day = obuf[i].odate & 0x1F;
803 ll->mnum = (obuf[i].odate >> 5) & 0x0F;
804 ll->yr = (obuf[i].odate >> 9) + 1980;
805 k = obuf[i].otime >> 5; /* this is a mess */
806 ll->mm = k & 0x3f;
807 ll->ap = ((ll->hh = k >> 6) GE 12) ? 'p' : 'a';
808
809 if (ll->hh > 12)
810 ll->hh -= 12;
811
812 if (ll->hh EQ 0)
813 ll->hh = 12;
814
815 return;
816}
817
818
819/*
820
821*/
822
823/* gcdate - get current date (in months) for comparison */
824
825int
826gcdate()
827{
828 struct {
829 unsigned int ax, bx, cx, dx, si, di, ds, es;
830 } r;
831
832 r.ax = 0x2A00;
833 sysint(0x21, &r, &r);
834 return(r.cx * 12 + (r.dx >> 8)); /* yr * 12 + month */
835}
836
837/*
838
839*/
840
841/* mname - convert month number to month name */
842
843char *
844mname(n)
845int n;
846{
847 static char *name[] = {
848
849 "???",
850 "Jan",
851 "Feb",
852 "Mar",
853 "Apr",
854 "May",
855 "Jun",
856 "Jul",
857 "Aug",
858 "Sep",
859 "Oct",
860 "Nov",
861 "Dec"
862 };
863
864 return((n < 1 OR n > 12) ? name[0] : name[n]);
865}
866
867/*
868
869*/
870
871int
872_showds()
873{
874 struct{
875 int cs, ss, ds, es;
876 } r;
877
878 segread(&r);
879 return(r.ds);
880}
881
882int
883ci()
884{
885 return(bdos(7) & 0xFF);
886}
Note: See TracBrowser for help on using the repository browser.