Imported Upstream version 2.17
[debian/cpmtools] / cpmls.c
1 /* #includes */ /*{{{C}}}*//*{{{*/
2 #include "config.h"
3
4 #include <ctype.h>
5 #include <errno.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include "getopt_.h"
11 #include "cpmfs.h"
12
13 #ifdef USE_DMALLOC
14 #include <dmalloc.h>
15 #endif
16 /*}}}*/
17
18 /* variables */ /*{{{*/
19 static const char * const month[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" };
20 /*}}}*/
21
22 /* namecmp -- compare two entries */ /*{{{*/
23 static int namecmp(const void *a, const void *b)
24 {
25   if (**((const char * const *)a)=='[') return -1;
26   return strcmp(*((const char * const *)a),*((const char * const *)b));
27 }
28 /*}}}*/
29 /* olddir  -- old style output */ /*{{{*/
30 static void olddir(char **dirent, int entries)
31 {
32   int i,j,k,l,user,announce;
33
34   announce=0;
35   for (user=0; user<32; ++user)
36   {
37     for (i=l=0; i<entries; ++i)
38     {
39       if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
40       {
41         if (announce==1)
42         {
43           printf("User %d\n",user);
44         }
45         announce=2;
46         if (l%4) printf(" : ");
47         for (j=2; dirent[i][j] && dirent[i][j]!='.'; ++j) putchar(toupper(dirent[i][j]));
48         k=j; while (k<11) { putchar(' '); ++k; }
49         if (dirent[i][j]=='.') ++j;
50         for (k=0; dirent[i][j]; ++j,++k) putchar(toupper(dirent[i][j]));
51         for (; k<3; ++k) putchar(' ');
52         ++l;
53       }
54       if (l && (l%4)==0) {
55         l = 0;
56         putchar('\n');
57       } 
58     }
59     if (l%4) {
60         putchar('\n');
61     }
62
63     if (announce==2) announce=1;
64   }
65   if (entries==0) printf("No files\n");
66 }
67 /*}}}*/
68 /* oldddir -- old style long output */ /*{{{*/
69 static void oldddir(char **dirent, int entries, struct cpmInode *ino)
70 {
71   struct cpmStatFS buf;
72   struct cpmStat statbuf;
73   struct cpmInode file;
74
75   if (entries)
76   {
77     int i,j,k,l,announce,user;
78
79     qsort(dirent,entries,sizeof(char*),namecmp);
80     cpmStatFS(ino,&buf);
81     printf("     Name    Bytes   Recs  Attr     update             create\n");
82     printf("------------ ------ ------ ---- -----------------  -----------------\n");
83     announce=0;
84     for (l=user=0; user<32; ++user)
85     {
86       for (i=0; i<entries; ++i)
87       {
88         struct tm *tmp;
89
90         if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
91         {
92           if (announce==1)
93           {
94             printf("\nUser %d:\n\n",user);
95             printf("     Name    Bytes   Recs  Attr     update             create\n");
96             printf("------------ ------ ------ ---- -----------------  -----------------\n");
97           }
98           announce=2;
99           for (j=2; dirent[i][j] && dirent[i][j]!='.'; ++j) putchar(toupper(dirent[i][j]));
100           k=j; while (k<10) { putchar(' '); ++k; }
101           putchar('.');
102           if (dirent[i][j]=='.') ++j;
103           for (k=0; dirent[i][j]; ++j,++k) putchar(toupper(dirent[i][j]));
104           for (; k<3; ++k) putchar(' ');
105
106           cpmNamei(ino,dirent[i],&file);
107           cpmStat(&file,&statbuf);
108           printf(" %5.1ldK",(long) (statbuf.size+buf.f_bsize-1) /
109                         buf.f_bsize*(buf.f_bsize/1024));
110
111           printf(" %6.1ld ",(long)(statbuf.size/128));
112           putchar(statbuf.mode&0200 ? ' ' : 'R');
113           putchar(statbuf.mode&01000 ? 'S' : ' ');
114           putchar(' ');
115           if (statbuf.mtime)
116           {
117             tmp=localtime(&statbuf.mtime);
118             printf("  %02d-%s-%04d %02d:%02d",tmp->tm_mday,month[tmp->tm_mon],tmp->tm_year+1900,tmp->tm_hour,tmp->tm_min);
119           }
120           else if (statbuf.ctime) printf("                   ");
121           if (statbuf.ctime)
122           {
123             tmp=localtime(&statbuf.ctime);
124             printf("  %02d-%s-%04d %02d:%02d",tmp->tm_mday,month[tmp->tm_mon],tmp->tm_year+1900,tmp->tm_hour,tmp->tm_min);
125           }
126           putchar('\n');
127           ++l;
128         }
129       }
130       if (announce==2) announce=1;
131     }
132     printf("%5.1d Files occupying %6.1ldK",l,(buf.f_bused*buf.f_bsize)/1024);
133     printf(", %7.1ldK Free.\n",(buf.f_bfree*buf.f_bsize)/1024);
134   }
135   else printf("No files found\n");
136 }
137 /*}}}*/
138 /* old3dir -- old CP/M Plus style long output */ /*{{{*/
139 static void old3dir(char **dirent, int entries, struct cpmInode *ino)
140 {
141   struct cpmStatFS buf;
142   struct cpmStat statbuf;
143   struct cpmInode file;
144
145   if (entries)
146   {
147     int i,j,k,l,announce,user, attrib;
148     int totalBytes=0,totalRecs=0;
149
150     qsort(dirent,entries,sizeof(char*),namecmp);
151     cpmStatFS(ino,&buf);
152     announce=1;
153     for (l=0,user=0; user<32; ++user)
154     {
155       for (i=0; i<entries; ++i)
156       {
157         struct tm *tmp;
158
159         if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
160         {
161           cpmNamei(ino,dirent[i],&file);
162           cpmStat(&file,&statbuf);
163           cpmAttrGet(&file, &attrib);
164           if (announce==1)
165           {
166             if (user) putchar('\n');
167             printf("Directory For Drive A:  User %2.1d\n\n",user);
168             printf("    Name     Bytes   Recs   Attributes   Prot      Update          Create\n");
169             printf("------------ ------ ------ ------------ ------ --------------  --------------\n\n");
170           }
171           announce=2;
172           for (j=2; dirent[i][j] && dirent[i][j]!='.'; ++j) putchar(toupper(dirent[i][j]));
173           k=j; while (k<10) { putchar(' '); ++k; }
174           putchar(' ');
175           if (dirent[i][j]=='.') ++j;
176           for (k=0; dirent[i][j]; ++j,++k) putchar(toupper(dirent[i][j]));
177           for (; k<3; ++k) putchar(' ');
178
179           totalBytes+=statbuf.size;
180           totalRecs+=(statbuf.size+127)/128;
181           printf(" %5.1ldk",(long) (statbuf.size+buf.f_bsize-1) /
182                         buf.f_bsize*(buf.f_bsize/1024));
183           printf(" %6.1ld ",(long)(statbuf.size/128));
184           putchar((attrib & CPM_ATTR_F1)   ? '1' : ' ');
185           putchar((attrib & CPM_ATTR_F2)   ? '2' : ' ');
186           putchar((attrib & CPM_ATTR_F3)   ? '3' : ' ');          
187           putchar((attrib & CPM_ATTR_F4)   ? '4' : ' ');
188           putchar((statbuf.mode&(S_IWUSR|S_IWGRP|S_IWOTH)) ? ' ' : 'R');
189           putchar((attrib & CPM_ATTR_SYS)  ? 'S' : ' ');
190           putchar((attrib & CPM_ATTR_ARCV) ? 'A' : ' ');
191           printf("      ");
192           if      (attrib & CPM_ATTR_PWREAD)  printf("Read   ");
193           else if (attrib & CPM_ATTR_PWWRITE) printf("Write  ");
194           else if (attrib & CPM_ATTR_PWDEL)   printf("Delete "); 
195           else printf("None   ");
196           if (statbuf.mtime)
197           {
198             tmp=localtime(&statbuf.mtime);
199             printf("%02d/%02d/%02d %02d:%02d  ",tmp->tm_mon+1,tmp->tm_mday,tmp->tm_year%100,tmp->tm_hour,tmp->tm_min);
200           }
201           else if (statbuf.ctime) printf("                ");
202           if (statbuf.ctime)
203           {
204             tmp=localtime(&statbuf.ctime);
205             printf("%02d/%02d/%02d %02d:%02d",tmp->tm_mon+1,tmp->tm_mday,tmp->tm_year%100,tmp->tm_hour,tmp->tm_min);
206           }
207           putchar('\n');
208           ++l;
209         }
210       }
211       if (announce==2) announce=1;
212     }
213     printf("\nTotal Bytes     = %6.1dk  ",(totalBytes+1023)/1024);
214     printf("Total Records = %7.1d  ",totalRecs);
215     printf("Files Found = %4.1d\n",l);
216     printf("Total 1k Blocks = %6.1ld   ",(buf.f_bused*buf.f_bsize)/1024);
217     printf("Used/Max Dir Entries For Drive A: %4.1ld/%4.1ld\n",buf.f_files-buf.f_ffree,buf.f_files);
218   }
219   else printf("No files found\n");
220 }
221 /*}}}*/
222 /* ls      -- UNIX style output */ /*{{{*/
223 static void ls(char **dirent, int entries, struct cpmInode *ino, int l, int c, int iflag)
224 {
225   int i,user,announce,any;
226   time_t now;
227   struct cpmStat statbuf;
228   struct cpmInode file;
229
230   time(&now);
231   qsort(dirent,entries,sizeof(char*),namecmp);
232   announce=0;
233   any=0;
234   for (user=0; user<32; ++user)
235   {
236     announce=0;
237     for (i=0; i<entries; ++i) if (dirent[i][0]!='.')
238     {
239       if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
240       {
241         if (announce==0)
242         {
243           if (any) putchar('\n');
244           printf("%d:\n",user);
245           announce=1;
246         }
247         any=1;
248         if (iflag || l)
249         {
250           cpmNamei(ino,dirent[i],&file);
251           cpmStat(&file,&statbuf);
252         }
253         if (iflag) printf("%4ld ",(long) statbuf.ino);
254         if (l)
255         {
256           struct tm *tmp;
257
258           putchar(S_ISDIR(statbuf.mode) ? 'd' : '-');
259           putchar(statbuf.mode&0400 ? 'r' : '-');
260           putchar(statbuf.mode&0200 ? 'w' : '-');
261           putchar(statbuf.mode&0100 ? 'x' : '-');
262           putchar(statbuf.mode&0040 ? 'r' : '-');
263           putchar(statbuf.mode&0020 ? 'w' : '-');
264           putchar(statbuf.mode&0010 ? 'x' : '-');
265           putchar(statbuf.mode&0004 ? 'r' : '-');
266           putchar(statbuf.mode&0002 ? 'w' : '-');
267           putchar(statbuf.mode&0001 ? 'x' : '-');
268 #if 0
269           putchar(statbuf.flags&FLAG_PUBLIC ? 'p' : '-');
270           putchar(dir[i].flags&FLAG_SYSTEM ? 's' : '-');
271           printf(" %-2d ",dir[i].user);
272 #endif
273           printf("%8.1ld ",(long)statbuf.size);
274           tmp=localtime(c ? &statbuf.ctime : &statbuf.mtime);
275           printf("%s %02d ",month[tmp->tm_mon],tmp->tm_mday);
276           if ((c ? statbuf.ctime : statbuf.mtime)<(now-182*24*3600)) printf("%04d  ",tmp->tm_year+1900);
277           else printf("%02d:%02d ",tmp->tm_hour,tmp->tm_min);
278         }
279         printf("%s\n",dirent[i]+2);
280       }
281     }
282   }
283 }
284 /*}}}*/
285 /* lsattr  -- output something like e2fs lsattr */ /*{{{*/
286 static void lsattr(char **dirent, int entries, struct cpmInode *ino)
287 {
288   int i,user,announce,any;
289   struct cpmStat statbuf;
290   struct cpmInode file;
291   cpm_attr_t attrib;
292
293   qsort(dirent,entries,sizeof(char*),namecmp);
294   announce=0;
295   any=0;
296   for (user=0; user<32; ++user)
297   {
298     announce=0;
299     for (i=0; i<entries; ++i) if (dirent[i][0]!='.')
300     {
301       if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
302       {
303         if (announce==0)
304         {
305           if (any) putchar('\n');
306           printf("%d:\n",user);
307           announce=1;
308         }
309         any=1;
310
311         cpmNamei(ino,dirent[i],&file);
312         cpmStat(&file,&statbuf);
313         cpmAttrGet(&file, &attrib); 
314
315         putchar ((attrib & CPM_ATTR_F1)      ? '1' : '-');
316         putchar ((attrib & CPM_ATTR_F2)      ? '2' : '-');
317         putchar ((attrib & CPM_ATTR_F3)      ? '3' : '-');
318         putchar ((attrib & CPM_ATTR_F4)      ? '4' : '-');
319         putchar ((attrib & CPM_ATTR_SYS)     ? 's' : '-');
320         putchar ((attrib & CPM_ATTR_ARCV)    ? 'a' : '-');
321         putchar ((attrib & CPM_ATTR_PWREAD)  ? 'r' : '-');
322         putchar ((attrib & CPM_ATTR_PWWRITE) ? 'w' : '-');
323         putchar ((attrib & CPM_ATTR_PWDEL)   ? 'e' : '-');
324
325         printf(" %s\n",dirent[i]+2);
326       }
327     }
328   }
329 }
330 /*}}}*/
331
332 const char cmd[]="cpmls";
333
334 int main(int argc, char *argv[])
335 {
336   /* variables */ /*{{{*/
337   const char *err;
338   const char *image;
339   const char *format;
340   const char *devopts=NULL;
341   int c,usage=0;
342   struct cpmSuperBlock drive;
343   struct cpmInode root;
344   int style=0;
345   int changetime=0;
346   int inode=0;
347   char **gargv;
348   int gargc;
349   static char starlit[2]="*";
350   static char * const star[]={starlit};
351   /*}}}*/
352
353   /* parse options */ /*{{{*/
354   if (!(format=getenv("CPMTOOLSFMT"))) format=FORMAT;
355   while ((c=getopt(argc,argv,"cT:f:ih?dDFlA"))!=EOF) switch(c)
356   {
357     case 'f': format=optarg; break;
358     case 'T': devopts=optarg; break;
359     case 'h':
360     case '?': usage=1; break;
361     case 'd': style=1; break;
362     case 'D': style=2; break;
363     case 'F': style=3; break;
364     case 'l': style=4; break;
365     case 'A': style=5; break;
366     case 'c': changetime=1; break;
367     case 'i': inode=1; break;
368   }
369
370   if (optind==argc) usage=1;
371   else image=argv[optind++];
372
373   if (usage)
374   {
375     fprintf(stderr,"Usage: %s [-f format] [-T libdsk-type] [-d|-D|-F|-A|[-l][-c][-i]] image [file ...]\n",cmd);
376     exit(1);
377   }
378   /*}}}*/
379   /* open image */ /*{{{*/
380   if ((err=Device_open(&drive.dev,image,O_RDONLY,devopts))) 
381   {
382     fprintf(stderr,"%s: can not open %s (%s)\n",cmd,image,err);
383     exit(1);
384   }
385   cpmReadSuper(&drive,&root,format);
386   /*}}}*/
387   if (optind<argc) cpmglob(optind,argc,argv,&root,&gargc,&gargv);
388   else cpmglob(0,1,star,&root,&gargc,&gargv);
389   if (style==1) olddir(gargv,gargc);
390   else if (style==2) oldddir(gargv,gargc,&root);
391   else if (style==3) old3dir(gargv,gargc,&root);
392   else if (style==5) lsattr(gargv, gargc, &root); 
393   else ls(gargv,gargc,&root,style==4,changetime,inode);
394   exit(0);
395 }