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