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