/* * ls * * version 2.0 * * Rewritten for speed, memory usage, and reliability * * now checks TERM var and displays MouseText folder only if set to gnocon * does not apply name quicksort if files are on an HFS volume */ #include #include #include #include #include #include #include #include #pragma stacksize 1024 #pragma optimize -1 /*#pragma optimize 8*/ #define CALCULATE -1 #define ONLYONE -2 unsigned fl_all,fl_reverse; unsigned fl_gnocon; unsigned fl_sortname,fl_sortcreate,fl_sortmod; unsigned firstflag; struct directory { ResultBuf32Ptr dir_name; struct directory *parent; unsigned fake; word num_entries; longword num_bytes; word no_sort; unsigned width; DirEntryRecPtrGS *entry_ptrs; DirEntryRecPtrGS entries; }; DirEntryRecGS dirinfo; ResultBuf32 nameb; lsexit(int x_code) { SYSTEMQUITFLAGS(0x4000); SYSTEMQUITPATH(NULL); exit(x_code); } /*#define lsexit(x) exit(x)*/ #define qsort(a,b,c,d) nqsort(a,b,c,d) extern void SortList(void *a, int c, int b, void *d); void nqsort(void *,unsigned, unsigned,int (*cmp)(void *,void *)); void printGS(GSString255Ptr g) { fwrite(g->text,g->length,1,stdout); } typedef struct listStruct *list; const char month[12][4] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; typedef struct FileTypeConv { word type; char rep[10]; } FileTypeConv; FileTypeConv FTTable[] = { 0x0f, "DIR ", /* directory */ 0xB0, "src ", /* apw source file */ 0xb1, "obj ", /* apw object file */ 0x04, "txt ", /* ascii text file */ 0xb3, "s16 ", /* gs/os program file */ 0xb5, "exe ", /* gs/os shell program file */ 0xb8, "nda ", 0xb9, "cda ", 0xba, "tol ", 0x00, "non ", /* typeless file */ 0x01, "bad ", /* bad block file */ 0x06, "bin ", /* general binary file */ 0x08, "fot ", /* graphics screen file */ 0x19, "adb ", /* appleworks data base file */ 0x1a, "awp ", /* appleworks word processor file */ 0x1b, "asp ", /* appleworks spreadsheet */ 0xb2, "lib ", /* apw library file */ 0xb4, "rtl ", /* apw runtime library */ 0xef, "pas ", /* pascal partition */ 0xf0, "cmd ", 0xfa, "int ", /* integer basic program */ 0xfb, "var ", /* int basic var file */ 0xfc, "bas ", /* applesloth basic file */ 0xfd, "var ", /* applesloth variable file */ 0xfe, "rel ", /* EDASM relocatable code */ 0xff, "sys ", /* prodos 8 system program file */ -1, ""}; char conv[10]; char *getFileType(int type) { int i; i = 0; while (FTTable[i].type != -1) { if (FTTable[i].type == type) { return FTTable[i].rep; } else i++; } sprintf(conv,"$%2X ",type); return conv; } word curYear; void *sortRoutine; int columns; int openDirectory, fl_longOutput, inK; int dirOnly, idType, fl_recursive, fl_nosort; int more,less; unsigned whichTime; void printDirName(struct directory *d, unsigned level) { if (d == NULL) return; else { printDirName(d->parent,level+1); if (d->dir_name != NULL) { printGS((GSString255Ptr)&d->dir_name->bufString); if (level) putchar('/'); } } if (!level) putchar(':'); } void long_out(DirEntryRecGS *entry) { TimeRec *time; if (whichTime) time = &entry->createDateTime; else time = &entry->modDateTime; printf("%c%c%c%c%c%c%c %04lX %4s %8ld", (entry->fileType == 0x0f) ? 'd' : ((entry->flags & 0x8000) ? 'e' : '-'), (entry->access & 0x01) ? 'r' : '-', (entry->access & 0x02) ? 'w' : '-', ((entry->fileType == 0xff) || (entry->fileType == 0xb5) || (entry->fileType == 0xb3) || ((entry->fileType == 0xb0) && (entry->auxType == 6l))) ? 'x' : '-', (entry->access & 0x20) ? 'b' : '-', (entry->access & 0x40) ? 'r' : '-', (entry->access & 0x80) ? 'd' : '-', entry->auxType, getFileType(entry->fileType), entry->eof+entry->resourceEOF); if (time->year+1900 == curYear) printf(" %3s %2d %02d:%02d ", month[time->month],time->day+1,time->hour,time->minute); else printf(" %3s %2d %4d ",month[time->month],time->day+1, time->year+1900); /*puts(entry->name->bufString.text);*/ } /* fake a directory read for command-line arguments */ struct directory *fakeDirect(int argc, char **argv,struct directory *par) { struct directory *new; unsigned i,file_count = 0,maxWidth = 0; unsigned err; DirEntryRecPtrGS newents,nptr; FileInfoRecGS fi; ResultBuf255Ptr newn; extern GSString255Ptr __C2GSMALLOC(char *); new = malloc(sizeof(struct directory)); new->num_entries = argc; new->num_bytes = 0l; new->parent = par; new->dir_name = NULL; new->no_sort = 0; new->fake = 1; if ((argc * sizeof(DirEntryRecGS)) > 60000) printf("exceeded ORCA pointer math bug range\n"); newents = new->entries = malloc(argc * sizeof(DirEntryRecGS)); new->entry_ptrs = malloc(argc * sizeof(DirEntryRecGS *)); fi.pCount = 12; fi.optionList = 0l; nptr = newents; for (i = 0; i < argc; i++) { new->entry_ptrs[file_count] = nptr; nptr->pCount = 17; nptr->optionList = NULL; fi.pathname = __C2GSMALLOC(argv[i]); GetFileInfoGS(&fi); if (err=_toolErr) { fprintf(stderr,"ls: %s: %s\n",strerror(_mapErr(err)),argv[i]); lsexit(1); } nptr->name = malloc(fi.pathname->length+5); nptr->name->bufSize = fi.pathname->length+5; memcpy(&nptr->name->bufString,fi.pathname, fi.pathname->length+2); nptr->name->bufString.text[fi.pathname->length] = 0; free(fi.pathname); if (fi.storageType == 0x05) /* extended file? */ nptr->flags = 0x8000; else nptr->flags = 0; nptr->fileType = fi.fileType; /* this is used by the qsort routine to maintain command-line ordering for directories */ if (fi.fileType == 0x0F) nptr->entryNum = i; nptr->auxType = fi.auxType; nptr->eof = fi.eof; nptr->blockCount = fi.blocksUsed; nptr->createDateTime = fi.createDateTime; nptr->modDateTime = fi.modDateTime; nptr->access = fi.access; nptr->resourceEOF = fi.resourceEOF; nptr->resourceBlocks = fi.resourceBlocks; file_count++; new->num_bytes += (nptr->eof + nptr->resourceEOF); if (nptr->name->bufString.length > maxWidth) maxWidth = nptr->name->bufString.length; /* NOTHING AFTER THIS LINE, PLEASE */ nptr = (DirEntryRecPtrGS) ((unsigned long) nptr + sizeof(DirEntryRecGS)); } new->width = maxWidth; new->num_entries = file_count; return new; } struct directory *readDirect(int fd,struct directory *par, ResultBuf32Ptr n) { struct directory *new; unsigned i,file_count = 0,maxWidth = 0; DirEntryRecPtrGS newents,nptr; ResultBuf255Ptr newn; nameb.bufSize = 36; dirinfo.pCount = 14; dirinfo.refNum = fd; dirinfo.base = dirinfo.displacement = 0; dirinfo.name = (ResultBuf255Ptr) &nameb; GetDirEntry(&dirinfo); new = malloc(sizeof(struct directory)); new->num_entries = dirinfo.entryNum; new->num_bytes = 0l; new->parent = par; new->dir_name = n; new->fake = 0; if (dirinfo.fileSysID == hfsFSID) new->no_sort = 1; else new->no_sort = 0; if ((dirinfo.entryNum * sizeof(DirEntryRecGS)) > 60000) printf("exceeded ORCA pointer math bug range\n"); newents = new->entries = malloc(dirinfo.entryNum * sizeof(DirEntryRecGS)); new->entry_ptrs = malloc(dirinfo.entryNum * sizeof(DirEntryRecGS *)); nptr = newents; for (i = 0; i < new->num_entries; i++) { new->entry_ptrs[file_count] = nptr; nptr->pCount = 17; nptr->refNum = fd; nptr->base = nptr->displacement = 1; nptr->name = (ResultBuf255Ptr) &nameb; nptr->optionList = NULL; GetDirEntry(nptr); if ((fl_all) || (!(nptr->access & fileInvisible))) { file_count++; newn = malloc(37); nameb.bufString.text[nameb.bufString.length] = 0; memcpy(newn,&nameb,36); nptr->name = newn; new->num_bytes += (nptr->eof + nptr->resourceEOF); if (nptr->name->bufString.length > maxWidth) maxWidth = nptr->name->bufString.length; /* NOTHING AFTER THIS LINE, PLEASE */ nptr = (DirEntryRecPtrGS) ((unsigned long) nptr + sizeof(DirEntryRecGS)); } } new->width = maxWidth; new->num_entries = file_count; return new; } int sortByType(DirEntryRecGS **a,DirEntryRecGS **b) { unsigned ea,eb; if ((*a)->fileType == 0x0F) { if ((*b)->fileType == 0x0F) { /* if both are dirs, maintain command-line ordering */ ea = (*a)->entryNum; eb = (*b)->entryNum; if (ea > eb) return 1; else if (ea == eb) return 0; else return -1; } else return 1; } else { if ((*b)->fileType == 0x0F) return -1; } } int sortByName(DirEntryRecGS **a,DirEntryRecGS **b) { return strcmp((*a)->name->bufString.text,(*b)->name->bufString.text) * more; } int sortByCreate(DirEntryRecGS **a,DirEntryRecGS **b) { TimeRec *time1, *time2; time1 = &((*a)->createDateTime); time2 = &((*b)->createDateTime); if (time1->year > time2->year) return less; if (time1->year < time2->year) return more; if (time1->month > time2->month) return less; if (time1->month < time2->month) return more; if (time1->day > time2->day) return less; if (time1->day < time2->day) return more; if (time1->hour > time2->hour) return less; if (time1->hour < time2->hour) return more; if (time1->minute > time2->minute) return less; if (time1->minute < time2->minute) return more; if (time1->second > time2->second) return less; if (time1->second < time2->second) return more; return 0; } int sortByMod(DirEntryRecGS **a,DirEntryRecGS **b) { TimeRec *time1, *time2; time1 = &((*a)->modDateTime); time2 = &((*b)->modDateTime); if (time1->year > time2->year) return less; if (time1->year < time2->year) return more; if (time1->month > time2->month) return less; if (time1->month < time2->month) return more; if (time1->day > time2->day) return less; if (time1->day < time2->day) return more; if (time1->hour > time2->hour) return less; if (time1->hour < time2->hour) return more; if (time1->minute > time2->minute) return less; if (time1->minute < time2->minute) return more; if (time1->second > time2->second) return less; if (time1->second < time2->second) return more; return 0; } void listDir(struct directory *d) { unsigned i; unsigned dirflag; struct directory *dd; int fd; int Col,Row,Height; int j, afile = FALSE, numColumns = 1; unsigned rWidth,width; unsigned fakeind; unsigned num_entries; char *cwd; DirEntryRecGS *entry; num_entries = d->num_entries; if ((fl_longOutput) && (!d->fake)) printf("total %ldk\n",(d->num_bytes / 1024l)); if (!num_entries) return; if (d->fake && openDirectory) { /* sort by type first */ qsort(d->entry_ptrs, num_entries, sizeof(DirEntryRecGS *), sortByType); num_entries = 0; while ((num_entries < d->num_entries) && (d->entry_ptrs[num_entries]->fileType != 0x0F)) num_entries++; /* finally, sort the non-directory files the way they wanted */ if (num_entries) qsort(d->entry_ptrs, num_entries, sizeof(DirEntryRecGS *), sortRoutine); } else if ((!fl_nosort) && (!(d->no_sort && fl_sortname))) qsort(d->entry_ptrs, num_entries, sizeof(DirEntryRecGS *),sortRoutine); if (!fl_longOutput && columns == CALCULATE) { rWidth = d->width; width = rWidth; if (inK) width+=5; if (idType) width++; if (width < 15) { rWidth = 15 - (width - rWidth); width = 15; } /* for jawaid :-) */ numColumns = 80 / (++width); } Height = (num_entries / numColumns); if (num_entries % numColumns) Height++; for (Row=0; Row < Height; Row ++) { for (Col = 0; Col < numColumns; Col ++) { i = Col * Height + Row; if (i >= num_entries) continue; entry = d->entry_ptrs[i]; if (entry->fileType == 0x0F) dirflag = TRUE; /*if (mult && entry->fileType == 0x0f) continue;*/ afile = TRUE; if (inK) printf("%4ld ",((entry->eof+entry->resourceEOF)/1024)+1); /* time = 0 means do mod date, = 1 means do create date */ /*time = (sortRoutine == CompareCreate) ? 1 : 0;*/ if (fl_longOutput) long_out(d->entry_ptrs[i]); printGS(&entry->name->bufString); if (idType) { if (entry->fileType == 0x0f) putchar('/'); else if ((entry->fileType == 0xff) || (entry->fileType == 0xb5) || (entry->fileType == 0xb3) || ((entry->fileType == 0xb0) && (entry->auxType == 6l))) putchar('*'); else putchar(' '); } if (Col+1 < numColumns) { for (j=0;j<(rWidth-(int)(entry->name->bufString.length));j++) putchar(' '); putchar(' '); } } putchar('\n'); } if ((dirflag && fl_recursive) || (d->fake && openDirectory)) { unsigned start_ent = (d->fake ? num_entries : 0); /* if there were regular files in a command-line list, put a blank line in there but don't count as first */ if (d->fake && (num_entries != 0)) { putchar('\n'); } for (i = start_ent; i < d->num_entries; i++) { if (d->entry_ptrs[i]->fileType == 0x0F) { ResultBuf32Ptr p; p = (ResultBuf32Ptr) d->entry_ptrs[i]->name; /* let the danged kernel do some of the work! */ if (fl_recursive) { cwd = malloc(1024l); getwd(cwd); chdir(p->bufString.text); fd = open(".",O_RDONLY); } else fd = open(p->bufString.text,O_RDONLY); if (fd <= 0) { perror("could not open"); exit(1); } dd = readDirect(fd,d,p); close(fd); /* print the directory name for recursive listings */ if (!firstflag) firstflag = 1; else putchar('\n'); printDirName(dd,0); putchar('\n'); listDir(dd); if (fl_recursive) { chdir(cwd); free(cwd); } /* DISPOSE of 'dd' at this point */ } } } } int main(int argc, char **argv) { int fd; struct directory *dd; TimeRec curtime; int ch; extern int getopt_restart(void); getopt_restart(); curtime = ReadTimeHex(); curYear = curtime.year + 1900; if (isatty(STDOUT_FILENO) && (!strncmp(ttyname(STDOUT_FILENO),".ttyco",6))) strcpy(FTTable[0].rep,"\x1B\xFXY\xE\x18 "); else strcpy(FTTable[0].rep,"DIR "); /* we restart, remember? */ /* initialize our restartable global variables */ fl_nosort = 0; fl_reverse = 0; more = 1; less = -1; sortRoutine = sortByName; columns = CALCULATE; openDirectory = TRUE; fl_all = FALSE; fl_longOutput = FALSE; inK = FALSE; dirOnly = FALSE; idType = FALSE; fl_recursive = FALSE; whichTime = 0; firstflag = 0; while ((ch = getopt(argc, argv, "acdflnqrst1CFR")) != EOF) { switch(ch) { case 'n' : fl_nosort = TRUE; break; case 'r' : more = -1; less = 1; break; case 't' : sortRoutine = sortByMod; whichTime = 0; break; case 'c' : sortRoutine = sortByCreate; whichTime = 1; break; case '1' : columns = ONLYONE; break; case 'C' : columns = CALCULATE; break; case 'a' : fl_all = TRUE;; break; case 'l' : fl_longOutput = TRUE; break; case 's' : inK = TRUE; break; case 'f' : dirOnly = TRUE; fl_longOutput = FALSE; inK = FALSE; fl_all = TRUE; break; case 'q' : break; case 'F' : idType = TRUE; break; case 'R' : fl_recursive = TRUE; break; case 'd' : openDirectory = FALSE; fl_recursive = FALSE; break; default: (void)fprintf(stderr, "usage: ls [-acdfilnqrstu1ACLFR] [name ...]\n"); lsexit(1); } } argv += optind; argc -= optind; if (!argc) { fd = open(".",O_RDONLY); if (fd <= 0) { perror("ls:"); exit(1); } dd = readDirect(fd,NULL,NULL); close(fd); listDir(dd); } else { /* files as arguments */ /* add the args to a special list one by one with GetFileInfo */ dd = fakeDirect(argc, argv, NULL); if (dd->num_entries) listDir(dd); } lsexit(0); }