1 /* #includes */ /*{{{C}}}*//*{{{*/
15 /* variables */ /*{{{*/
16 static const char * const month[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" };
19 /* namecmp -- compare two entries */ /*{{{*/
20 static int namecmp(const void *a, const void *b)
22 if (**((const char * const *)a)=='[') return -1;
23 return strcmp(*((const char * const *)a),*((const char * const *)b));
26 /* onlyuser0 -- do all entries belong to user 0? */ /*{{{*/
27 static int onlyuser0(char ** const dirent, int entries)
31 for (i=0; i<entries; ++i)
33 if (dirent[i][0]!='.' && (dirent[i][0]!='0' || dirent[i][1]!='0')) return 0;
39 /* olddir -- old style output */ /*{{{*/
40 static void olddir(char **dirent, int entries)
42 int i,j,k,l,user,announce,showuser,files;
44 showuser=!onlyuser0(dirent,entries);
46 for (user=0; user<32; ++user)
49 for (i=l=0; i<entries; ++i)
51 /* This selects real regular files implicitly, because only those have
52 * the user in their name. ".", ".." and the password file do not.
54 if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
57 if (announce && showuser)
59 printf("User %d\n",user);
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(' ');
82 if (files==0) printf("No file\n");
85 /* oldddir -- old style long output */ /*{{{*/
86 static void oldddir(char **dirent, int entries, struct cpmInode *ino)
89 struct cpmStat statbuf;
94 int i,j,k,l,announce,user;
96 qsort(dirent,entries,sizeof(char*),namecmp);
98 printf(" Name Bytes Recs Attr update create\n");
99 printf("------------ ------ ------ ---- ----------------- -----------------\n");
101 for (l=user=0; user<32; ++user)
103 for (i=0; i<entries; ++i)
107 if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
111 printf("\nUser %d:\n\n",user);
112 printf(" Name Bytes Recs Attr update create\n");
113 printf("------------ ------ ------ ---- ----------------- -----------------\n");
116 for (j=2; dirent[i][j] && dirent[i][j]!='.'; ++j) putchar(toupper(dirent[i][j]));
117 k=j; while (k<10) { putchar(' '); ++k; }
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(' ');
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));
128 printf(" %6.1ld ",(long)(statbuf.size/128));
129 putchar(statbuf.mode&0200 ? ' ' : 'R');
130 putchar(statbuf.mode&01000 ? 'S' : ' ');
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);
137 else if (statbuf.ctime) printf(" ");
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);
147 if (announce==2) announce=1;
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);
152 else printf("No files found\n");
155 /* old3dir -- old CP/M Plus style long output */ /*{{{*/
156 static void old3dir(char **dirent, int entries, struct cpmInode *ino)
158 struct cpmStatFS buf;
159 struct cpmStat statbuf;
160 struct cpmInode file;
164 int i,j,k,l,announce,user, attrib;
165 int totalBytes=0,totalRecs=0;
167 qsort(dirent,entries,sizeof(char*),namecmp);
170 for (l=0,user=0; user<32; ++user)
172 for (i=0; i<entries; ++i)
176 if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
178 cpmNamei(ino,dirent[i],&file);
179 cpmStat(&file,&statbuf);
180 cpmAttrGet(&file, &attrib);
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");
190 for (j=2; dirent[i][j] && dirent[i][j]!='.'; ++j) putchar(toupper(dirent[i][j]));
191 k=j; while (k<10) { putchar(' '); ++k; }
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(' ');
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' : ' ');
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 ");
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);
220 if (ino->sb->cnotatime && statbuf.ctime)
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);
225 else if (!ino->sb->cnotatime && statbuf.atime)
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);
234 if (announce==2) announce=1;
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);
242 else printf("No files found\n");
245 /* ls -- UNIX style output */ /*{{{*/
246 static void ls(char **dirent, int entries, struct cpmInode *ino, int l, int c, int iflag)
248 int i,user,announce,any;
250 struct cpmStat statbuf;
251 struct cpmInode file;
254 qsort(dirent,entries,sizeof(char*),namecmp);
257 for (user=0; user<32; ++user)
260 for (i=0; i<entries; ++i) if (dirent[i][0]!='.')
262 if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
266 if (any) putchar('\n');
267 printf("%d:\n",user);
273 cpmNamei(ino,dirent[i],&file);
274 cpmStat(&file,&statbuf);
276 if (iflag) printf("%4ld ",(long) statbuf.ino);
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' : '-');
292 putchar(statbuf.flags&FLAG_PUBLIC ? 'p' : '-');
293 putchar(dir[i].flags&FLAG_SYSTEM ? 's' : '-');
294 printf(" %-2d ",dir[i].user);
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);
302 printf("%s\n",dirent[i]+2);
308 /* lsattr -- output something like e2fs lsattr */ /*{{{*/
309 static void lsattr(char **dirent, int entries, struct cpmInode *ino)
311 int i,user,announce,any;
312 struct cpmStat statbuf;
313 struct cpmInode file;
316 qsort(dirent,entries,sizeof(char*),namecmp);
319 for (user=0; user<32; ++user)
322 for (i=0; i<entries; ++i) if (dirent[i][0]!='.')
324 if (dirent[i][0]=='0'+user/10 && dirent[i][1]=='0'+user%10)
328 if (any) putchar('\n');
329 printf("%d:\n",user);
334 cpmNamei(ino,dirent[i],&file);
335 cpmStat(&file,&statbuf);
336 cpmAttrGet(&file, &attrib);
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' : '-');
348 printf(" %s\n",dirent[i]+2);
355 const char cmd[]="cpmls";
357 int main(int argc, char *argv[])
359 /* variables */ /*{{{*/
363 const char *devopts=NULL;
365 struct cpmSuperBlock super;
366 struct cpmInode root;
373 static char starlit[2]="*";
374 static char * const star[]={ starlit };
377 /* parse options */ /*{{{*/
378 if (!(format=getenv("CPMTOOLSFMT"))) format=FORMAT;
379 while ((c=getopt(argc,argv,"cT:f:ih?dDFlAu"))!=EOF) switch(c)
381 case 'f': format=optarg; break;
382 case 'T': devopts=optarg; break;
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;
395 if (optind==argc) usage=1;
396 else image=argv[optind++];
401 fprintf(stderr,"Usage: %s [-f format] [-T libdsk-type] [-d|-D|-F|-A|[-l][-c][-i]] [-u] image [file ...]\n",cmd);
403 fprintf(stderr,"Usage: %s [-f format] [-d|-D|-F|-A|[-l][-c][-i]] [-u] image [file ...]\n",cmd);
408 /* open image */ /*{{{*/
409 if ((err=Device_open(&super.dev,image,O_RDONLY,devopts)))
411 fprintf(stderr,"%s: cannot open %s (%s)\n",cmd,image,err);
414 if (cpmReadSuper(&super,&root,format,uppercase)==-1)
416 fprintf(stderr,"%s: cannot read superblock (%s)\n",cmd,boo);
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);