From 4dbcd267a0214439b7b257448d45a28e91dbb1a1 Mon Sep 17 00:00:00 2001 From: Bobbi Webber-Manners Date: Sun, 31 May 2020 15:12:15 -0400 Subject: [PATCH] Made fileent into a union and populate it for each subsort. Saves main memory. --- sortdir.c | 91 ++++++++++++++++++++++++++++++++--------------------- sortdir.po | Bin 143360 -> 143360 bytes 2 files changed, 55 insertions(+), 36 deletions(-) diff --git a/sortdir.c b/sortdir.c index 183409a..451e4fb 100644 --- a/sortdir.c +++ b/sortdir.c @@ -3,6 +3,11 @@ * * Bobbi January-March 2020 * + * TODO: IDEA you only need one sorteddata block at a time. Do not allocate + * until writeout time and use one block buffer. Iterate through + * filelist[] collecting all entries for block 1, 2, 3 in turn. + * Huge aux memory savings!! + * TODO: filent can be a couple bytes smaller. * TODO: Obsolete MAXFILES is hardcoded - need a better way to do this * TODO: Check for no memory when allocating aux memory * TODO: Enable free list functionality on ProDOS-8 @@ -20,6 +25,7 @@ * v0.57 Fixed bugs in aux memory allocation, memory zeroing bug * v0.58 Fixed more bugs. Now working properly using aux memory * v0.59 Moved creation of filelist[] into buildsorttable(). More bugfix. + * v0.60 Modified fileent to be a union. Build it for each subsort. Saves RAM. */ //#pragma debug 9 @@ -130,14 +136,17 @@ struct block { * Entry for array of filenames used by qsort() */ struct fileent { - char name[NMLEN+1]; /* Name converted to upper/lower case */ - char datetime[20]; /* Date/time as a yyyy-mm-dd hh:mm string */ - uchar type; /* ProDOS file type */ - uint blocks; /* Size in blocks */ - ulong eof; /* EOF position in bytes */ - uint order; /* Hack to make qsort() stable */ - uchar blockidx; /* Index of dir block (1,2,3 ...) */ - uchar entrynum; /* Entry within the block */ + uchar blockidx; /* Index of dir block (1,2,3 ...) */ + uchar entrynum; /* Entry within the block */ + uint order; /* Hack to make qsort() stable */ +// TODO: Can make this a couple bytes smaller + union { + char name[NMLEN+1]; /* Name converted to upper/lower case */ + char datetime[20]; /* Date/time as a yyyy-mm-dd hh:mm string */ + uchar type; /* ProDOS file type */ + uint blocks; /* Size in blocks */ + ulong eof; /* EOF position in bytes */ + }; }; /* @@ -236,7 +245,7 @@ int subdirblocks(uchar device, uint keyblk, struct pd_dirent *ent, uint blocknum, uint blkentries, uint *blkcnt); void enqueuesubdir(uint blocknum, uint subdiridx); int readdir(uint device, uint blocknum); -void buildsorttable(void); +void buildsorttable(char s); int cmp_name_asc(const void *a, const void *b); int cmp_name_desc(const void *a, const void *b); int cmp_name_asc_ci(const void *a, const void *b); @@ -1363,9 +1372,9 @@ int readdir(uint device, uint blocknum) { /* * Build filelist[], the table used by the sorting algorithm. */ -void buildsorttable() { +void buildsorttable(char s) { static char namebuf[NMLEN+1]; - uint off, blks, eof; + uint off; uchar entry, i; struct datetime dt; struct pd_dirent *ent; @@ -1385,26 +1394,37 @@ void buildsorttable() { ent = (struct pd_dirent*)(dirblkbuf + off); if (ent->typ_len != 0) { - blks = ent->blksused[0] + 256U * ent->blksused[1]; - eof = ent->eof[0] + 256L * ent->eof[1] + 65536L * ent->eof[2]; - fixcase(ent->name, namebuf, - ent->vers, ent->minvers, ent->typ_len & 0x0f); - - bzero(filelist[idx].name, NMLEN + 1); - for (i = 0; i < (ent->typ_len & 0x0f); ++i) - filelist[idx].name[i] = namebuf[i]; - filelist[idx].type = ent->type; filelist[idx].blockidx = blkidx; filelist[idx].entrynum = entry; - filelist[idx].blocks = blks; - filelist[idx].eof = eof; - - readdatetime(do_ctime ? ent->ctime : ent->mtime, &dt); - sprintf(filelist[idx].datetime, - "%04d-%02d-%02d %02d:%02d %s", - dt.year, dt.month, dt.day, dt.hour, dt.minute, - (dt.ispd25format ? "*" : " ")); + switch (tolower(s)) { + case 'n': + case 'i': + fixcase(ent->name, namebuf, + ent->vers, ent->minvers, ent->typ_len & 0x0f); + bzero(filelist[idx].name, NMLEN + 1); + for (i = 0; i < (ent->typ_len & 0x0f); ++i) + filelist[idx].name[i] = namebuf[i]; + break; + case 't': + filelist[idx].type = ent->type; + break; + case 'b': + filelist[idx].blocks = + ent->blksused[0] + 256U * ent->blksused[1]; + break; + case 'e': + filelist[idx].eof = + ent->eof[0] + 256L * ent->eof[1] + 65536L * ent->eof[2]; + break; + case 'd': + readdatetime(do_ctime ? ent->ctime : ent->mtime, &dt); + sprintf(filelist[idx].datetime, + "%04d-%02d-%02d %02d:%02d %s", + dt.year, dt.month, dt.day, dt.hour, dt.minute, + (dt.ispd25format ? "*" : " ")); + break; + } ++idx; } } @@ -1658,6 +1678,7 @@ void sortlist(char s) { /* * Print the file info stored in filelist[] */ +#if 0 void printlist(void) { uint i, j; hline(); @@ -1679,6 +1700,7 @@ void printlist(void) { } hline(); } +#endif /* * Convert block index to block number @@ -1809,7 +1831,7 @@ void interactive(void) { doverbose = 1; - puts("S O R T D I R v0.59 alpha Use ^ to return to previous question"); + puts("S O R T D I R v0.60 alpha Use ^ to return to previous question"); q1: fputs("\nEnter path (e.g.: /H1) of starting directory> ", stdout); @@ -1928,10 +1950,6 @@ void processdir(uint device, uint blocknum) { uchar i, errs; flushall(); errs = readdir(device, blocknum); - buildsorttable(); -// if (doverbose) { -// printlist(); -// } if ((strlen(fixopts) == 0) && errs) { err(NONFATAL, "Error scanning directory, will not sort\n"); goto done; @@ -1942,6 +1960,7 @@ void processdir(uint device, uint blocknum) { for (i = 0; i < strlen(sortopts); ++i) { if (doverbose) printf("[%c] ", sortopts[i]); + buildsorttable(sortopts[i]); sortlist(sortopts[i]); } if (doverbose) @@ -1949,9 +1968,9 @@ void processdir(uint device, uint blocknum) { #ifdef SORT sortblocks(device); #endif - if (doverbose) { - printlist(); - } + //if (doverbose) { + // printlist(); + //} if (dowrite) { puts("Writing dir ..."); errs = writedir(device); diff --git a/sortdir.po b/sortdir.po index dbe3cc014e262adb05cc7960e9e65d2ee2e7e824..c756b2de96e0801cf3517849a3ae0d46bdc98e16 100644 GIT binary patch delta 23408 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%0A)#ep>C(_;U9uMD~#N7z$= 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 I7wx0|2W;Yh+W-In delta 24050 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