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