Imported Upstream version 2.10
[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             tmp=localtime(&statbuf.ctime);
120             printf("  %02d-%s-%04d %02d:%02d",tmp->tm_mday,month[tmp->tm_mon],tmp->tm_year+1900,tmp->tm_hour,tmp->tm_min);
121           }
122           putchar('\n');
123           ++l;
124         }
125       }
126       if (announce==2) announce=1;
127     }
128     printf("%5.1d Files occupying %6.1ldK",l,(buf.f_bused*buf.f_bsize)/1024);
129     printf(", %7.1ldK Free.\n",(buf.f_bfree*buf.f_bsize)/1024);
130   }
131   else printf("No files found\n");
132 }
133 /*}}}*/
134 /* old3dir -- old CP/M Plus style long output */ /*{{{*/
135 static void old3dir(char **dirent, int entries, struct cpmInode *ino)
136 {
137   struct cpmStatFS buf;
138   struct cpmStat statbuf;
139   struct cpmInode file;
140
141   if (entries)
142   {
143     int i,j,k,l,announce,user, attrib;
144     int totalBytes=0,totalRecs=0;
145
146     qsort(dirent,entries,sizeof(char*),namecmp);
147     cpmStatFS(ino,&buf);
148     announce=1;
149     for (l=0,user=0; user<32; ++user)
150     {
151       for (i=0; i<entries; ++i)
152       {
153         struct tm *tmp;
154
155         if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
156         {
157           cpmNamei(ino,dirent[i],&file);
158           cpmStat(&file,&statbuf);
159           cpmAttrGet(&file, &attrib);
160           if (announce==1)
161           {
162             if (user) putchar('\n');
163             printf("Directory For Drive A:  User %2.1d\n\n",user);
164             printf("    Name     Bytes   Recs   Attributes   Prot      Update          Create\n");
165             printf("------------ ------ ------ ------------ ------ --------------  --------------\n\n");
166           }
167           announce=2;
168           for (j=2; dirent[i][j] && dirent[i][j]!='.'; ++j) putchar(toupper(dirent[i][j]));
169           k=j; while (k<10) { putchar(' '); ++k; }
170           putchar(' ');
171           if (dirent[i][j]=='.') ++j;
172           for (k=0; dirent[i][j]; ++j,++k) putchar(toupper(dirent[i][j]));
173           for (; k<3; ++k) putchar(' ');
174
175           totalBytes+=statbuf.size;
176           totalRecs+=(statbuf.size+127)/128;
177           printf(" %5.1ldk",(long) (statbuf.size+buf.f_bsize-1) /
178                         buf.f_bsize*(buf.f_bsize/1024));
179           printf(" %6.1ld ",(long)(statbuf.size/128));
180           putchar((attrib & CPM_ATTR_F1)   ? '1' : ' ');
181           putchar((attrib & CPM_ATTR_F2)   ? '2' : ' ');
182           putchar((attrib & CPM_ATTR_F3)   ? '3' : ' ');          
183           putchar((attrib & CPM_ATTR_F4)   ? '4' : ' ');
184           putchar((statbuf.mode&(S_IWUSR|S_IWGRP|S_IWOTH)) ? ' ' : 'R');
185           putchar((attrib & CPM_ATTR_SYS)  ? 'S' : ' ');
186           putchar((attrib & CPM_ATTR_ARCV) ? 'A' : ' ');
187           printf("      ");
188           if      (attrib & CPM_ATTR_PWREAD)  printf("Read   ");
189           else if (attrib & CPM_ATTR_PWWRITE) printf("Write  ");
190           else if (attrib & CPM_ATTR_PWDEL)   printf("Delete "); 
191           else printf("None   ");
192           tmp=localtime(&statbuf.mtime);
193           printf("%02d/%02d/%02d %02d:%02d  ",tmp->tm_mon+1,tmp->tm_mday,tmp->tm_year%100,tmp->tm_hour,tmp->tm_min);
194           tmp=localtime(&statbuf.ctime);
195           printf("%02d/%02d/%02d %02d:%02d",tmp->tm_mon+1,tmp->tm_mday,tmp->tm_year%100,tmp->tm_hour,tmp->tm_min);
196           putchar('\n');
197           ++l;
198         }
199       }
200       if (announce==2) announce=1;
201     }
202     printf("\nTotal Bytes     = %6.1dk  ",(totalBytes+1023)/1024);
203     printf("Total Records = %7.1d  ",totalRecs);
204     printf("Files Found = %4.1d\n",l);
205     printf("Total 1k Blocks = %6.1ld   ",(buf.f_bused*buf.f_bsize)/1024);
206     printf("Used/Max Dir Entries For Drive A: %4.1ld/%4.1ld\n",buf.f_files-buf.f_ffree,buf.f_files);
207   }
208   else printf("No files found\n");
209 }
210 /*}}}*/
211 /* ls      -- UNIX style output */ /*{{{*/
212 static void ls(char **dirent, int entries, struct cpmInode *ino, int l, int c, int iflag)
213 {
214   int i,user,announce,any;
215   time_t now;
216   struct cpmStat statbuf;
217   struct cpmInode file;
218
219   time(&now);
220   qsort(dirent,entries,sizeof(char*),namecmp);
221   announce=0;
222   any=0;
223   for (user=0; user<32; ++user)
224   {
225     announce=0;
226     for (i=0; i<entries; ++i) if (dirent[i][0]!='.')
227     {
228       if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
229       {
230         if (announce==0)
231         {
232           if (any) putchar('\n');
233           printf("%d:\n",user);
234           announce=1;
235         }
236         any=1;
237         if (iflag || l)
238         {
239           cpmNamei(ino,dirent[i],&file);
240           cpmStat(&file,&statbuf);
241         }
242         if (iflag) printf("%4ld ",(long) statbuf.ino);
243         if (l)
244         {
245           struct tm *tmp;
246
247           putchar(S_ISDIR(statbuf.mode) ? 'd' : '-');
248           putchar(statbuf.mode&0400 ? 'r' : '-');
249           putchar(statbuf.mode&0200 ? 'w' : '-');
250           putchar(statbuf.mode&0100 ? 'x' : '-');
251           putchar(statbuf.mode&0040 ? 'r' : '-');
252           putchar(statbuf.mode&0020 ? 'w' : '-');
253           putchar(statbuf.mode&0010 ? 'x' : '-');
254           putchar(statbuf.mode&0004 ? 'r' : '-');
255           putchar(statbuf.mode&0002 ? 'w' : '-');
256           putchar(statbuf.mode&0001 ? 'x' : '-');
257 #if 0
258           putchar(statbuf.flags&FLAG_PUBLIC ? 'p' : '-');
259           putchar(dir[i].flags&FLAG_SYSTEM ? 's' : '-');
260           printf(" %-2d ",dir[i].user);
261 #endif
262           printf("%8.1ld ",(long)statbuf.size);
263           tmp=localtime(c ? &statbuf.ctime : &statbuf.mtime);
264           printf("%s %02d ",month[tmp->tm_mon],tmp->tm_mday);
265           if ((c ? statbuf.ctime : statbuf.mtime)<(now-182*24*3600)) printf("%04d  ",tmp->tm_year+1900);
266           else printf("%02d:%02d ",tmp->tm_hour,tmp->tm_min);
267         }
268         printf("%s\n",dirent[i]+2);
269       }
270     }
271   }
272 }
273 /*}}}*/
274 /* lsattr  -- output something like e2fs lsattr */ /*{{{*/
275 static void lsattr(char **dirent, int entries, struct cpmInode *ino)
276 {
277   int i,user,announce,any;
278   struct cpmStat statbuf;
279   struct cpmInode file;
280   cpm_attr_t attrib;
281
282   qsort(dirent,entries,sizeof(char*),namecmp);
283   announce=0;
284   any=0;
285   for (user=0; user<32; ++user)
286   {
287     announce=0;
288     for (i=0; i<entries; ++i) if (dirent[i][0]!='.')
289     {
290       if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
291       {
292         if (announce==0)
293         {
294           if (any) putchar('\n');
295           printf("%d:\n",user);
296           announce=1;
297         }
298         any=1;
299
300         cpmNamei(ino,dirent[i],&file);
301         cpmStat(&file,&statbuf);
302         cpmAttrGet(&file, &attrib); 
303
304         putchar ((attrib & CPM_ATTR_F1)      ? '1' : '-');
305         putchar ((attrib & CPM_ATTR_F2)      ? '2' : '-');
306         putchar ((attrib & CPM_ATTR_F3)      ? '3' : '-');
307         putchar ((attrib & CPM_ATTR_F4)      ? '4' : '-');
308         putchar ((attrib & CPM_ATTR_SYS)     ? 's' : '-');
309         putchar ((attrib & CPM_ATTR_ARCV)    ? 'a' : '-');
310         putchar ((attrib & CPM_ATTR_PWREAD)  ? 'r' : '-');
311         putchar ((attrib & CPM_ATTR_PWWRITE) ? 'w' : '-');
312         putchar ((attrib & CPM_ATTR_PWDEL)   ? 'e' : '-');
313
314         printf(" %s\n",dirent[i]+2);
315       }
316     }
317   }
318 }
319 /*}}}*/
320
321 const char cmd[]="cpmls";
322
323 int main(int argc, char *argv[])
324 {
325   /* variables */ /*{{{*/
326   const char *err;
327   const char *image;
328   const char *format=FORMAT;
329   const char *devopts=NULL;
330   int c,usage=0;
331   struct cpmSuperBlock drive;
332   struct cpmInode root;
333   int style=0;
334   int changetime=0;
335   int inode=0;
336   char **gargv;
337   int gargc;
338   static char starlit[2]="*";
339   static char * const star[]={starlit};
340   /*}}}*/
341
342   /* parse options */ /*{{{*/
343   while ((c=getopt(argc,argv,"cT:f:ih?dDFlA"))!=EOF) switch(c)
344   {
345     case 'f': format=optarg; break;
346     case 'T': devopts=optarg; break;
347     case 'h':
348     case '?': usage=1; break;
349     case 'd': style=1; break;
350     case 'D': style=2; break;
351     case 'F': style=3; break;
352     case 'l': style=4; break;
353     case 'A': style=5; break;
354     case 'c': changetime=1; break;
355     case 'i': inode=1; break;
356   }
357
358   if (optind==argc) usage=1;
359   else image=argv[optind++];
360
361   if (usage)
362   {
363     fprintf(stderr,"Usage: %s [-f format] [-T libdsk-type] [-d|-D|-F|-A|[-l][-c][-i]] image [file ...]\n",cmd);
364     exit(1);
365   }
366   /*}}}*/
367   /* open image */ /*{{{*/
368   if ((err=Device_open(&drive.dev,image,O_RDONLY,devopts))) 
369   {
370     fprintf(stderr,"%s: can not open %s (%s)\n",cmd,image,err);
371     exit(1);
372   }
373   cpmReadSuper(&drive,&root,format);
374   /*}}}*/
375   if (optind<argc) cpmglob(optind,argc,argv,&root,&gargc,&gargv);
376   else cpmglob(0,1,star,&root,&gargc,&gargv);
377   if (style==1) olddir(gargv,gargc);
378   else if (style==2) oldddir(gargv,gargc,&root);
379   else if (style==3) old3dir(gargv,gargc,&root);
380   else if (style==5) lsattr(gargv, gargc, &root); 
381   else ls(gargv,gargc,&root,style==4,changetime,inode);
382   exit(0);
383 }