-d option to convert old (<=ProDOS 2.4.2) <-> new (ProDOS 2.5+) date format

This commit is contained in:
Bobbi Webber-Manners 2020-03-01 17:00:09 -05:00
parent bc50613dda
commit 4a6ee27fff
1 changed files with 73 additions and 12 deletions

View File

@ -2,7 +2,6 @@
* Bobbi January-February 2020
*
* TODO: Tool for 'extending' volume dir to more than 4 blocks
* TODO: Legacy/extended date format conversion
* TODO: Trimming unused directory blocks
* TODO: Make a version that doesn't need GNO - eliminate call to stat()
*/
@ -156,6 +155,7 @@ static uchar do_ctime = 0; /* -k ctime option */
static char sortopts[5] = ""; /* -s:abc list of sort options */
static char caseopts[2] = ""; /* -c:x case conversion option */
static char fixopts[2] = ""; /* -f:x fix mode option */
static char dateopts[2] = ""; /* -d:x date conversion option */
/* Prototypes */
void hline(void);
@ -167,7 +167,8 @@ void fixcase(char *in, char *out, uchar minvers, uchar vers, uchar len);
void lowercase(char *p, uchar len, uchar *minvers, uchar *vers);
void uppercase(char *p, uchar len, uchar *minvers, uchar *vers);
void initialcase(uchar mode, char *p, uchar len, uchar *minvers, uchar *vers);
void convertdatetime(uchar time[4], struct datetime *dt);
void readdatetime(uchar time[4], struct datetime *dt);
void writedatetime(uchar pd25, struct datetime *dt, uchar time[4]);
uint askfix(void);
int readfreelist(uchar device);
int isfree(uint blk);
@ -478,7 +479,7 @@ ret:
* Supports the legacy ProDOS date/time format as used by ProDOS 1.0->2.4.0
* and also the new format introduced with ProDOS 2.5.
*/
void convertdatetime(uchar time[4], struct datetime *dt) {
void readdatetime(uchar time[4], struct datetime *dt) {
uint d = time[0] + 256U * time[1];
uint t = time[2] + 256U * time[3];
if (!(t & 0xe000)) {
@ -504,6 +505,38 @@ void convertdatetime(uchar time[4], struct datetime *dt) {
}
}
/*
* Write the date and time stored in struct datetime in ProDOS on disk format,
* storing the bytes in array time[]. If pd25 is 0 then use legacy format
* (ProDOS 1.0-2.4.2) otherwise use the new date and time format introduced
* with ProDOS 2.5
*/
void writedatetime(uchar pd25, struct datetime *dt, uchar time[4]) {
uint d, t;
if (pd25 == 0) {
/* ProDOS 1.0 to 2.4.2 date format */
uint year = dt->year;
if (year > 2039) /* 2039 is last year */
year = 2039;
if (year < 1940) /* 1940 is first year */
year = 1940;
if (year >= 2000)
year -= 2000;
if (year >= 1900)
year -= 1900;
d = (year << 9) | (dt->month << 5) | dt->day;
t = (dt->hour << 8) | dt->minute;
} else {
/* ProDOS 2.5.0+ */
t = ((dt->month + 1) << 12) | dt->year;
d = (dt->day << 11) | (dt->hour << 6) | dt->minute;
}
time[0] = d & 0xff;
time[1] = (d >> 8) & 0xff;
time[2] = t & 0xff;
time[3] = (t >> 8) & 0xff;
}
/*
* Determine whether or not to perform a fix
* Return 0 not to perform fix, 1 to perform fix
@ -931,9 +964,30 @@ int readdir(uint device, uint blocknum) {
&(ent->vers),
&(ent->minvers));
break;
default:
err(FATALBADARG, "Invalid case option");
}
}
if (strlen(dateopts) > 0) {
struct datetime ctime, mtime;
readdatetime(ent->ctime, &ctime);
readdatetime(ent->mtime, &mtime);
uchar pd25;
switch (dateopts[0]) {
case 'n':
pd25 = 1;
break;
case 'o':
pd25 = 0;
break;
default:
err(FATALBADARG, "Invalid date option");
}
writedatetime(pd25, &ctime, ent->ctime);
writedatetime(pd25, &mtime, ent->mtime);
}
static char namebuf[NMLEN+1];
fixcase(ent->name, namebuf,
@ -978,8 +1032,7 @@ int readdir(uint device, uint blocknum) {
filelist[numfiles].eof = eof;
struct datetime dt;
convertdatetime(do_ctime ? ent->ctime : ent->mtime,
&dt);
readdatetime(do_ctime ? ent->ctime : ent->mtime, &dt);
sprintf(filelist[numfiles].datetime,
"%04d-%02d-%02d %02d:%02d %s",
dt.year, dt.month, dt.day, dt.hour, dt.minute,
@ -1467,6 +1520,7 @@ void usage(void) {
printf("usage: sortdir [-s xxx] [-n x] [-rDwcvVh] path\n\n");
printf(" Options: -s xxx Directory sort options\n");
printf(" -n x Filename upper/lower case options\n");
printf(" -d x Date format conversion options\n");
printf(" -f x Fix mode\n");
printf(" -r Recursive descent\n");
printf(" -D Whole-disk mode (implies -r)\n");
@ -1476,14 +1530,18 @@ void usage(void) {
printf(" -V Verbose debugging output\n");
printf(" -h This help\n");
printf("\n");
printf("Upper/lower case option x:\n");
printf("-nx: Upper/lower case filenames, where x is:\n");
printf(" l convert filenames to lower case eg: read.me\n");
printf(" u convert filenames to upper case eg: READ.ME\n");
printf(" i convert filenames to initial upper case eg: Read.me\n");
printf(" c convert filenames to camel case eg: Read.Me\n");
printf("\n");
printf("Directory sort options xxx, is a list of fields on which\n");
printf("to sort. The sort options are processed left-to-right.\n");
printf("-dx: Date/time on-disk format conversion, where x is:\n");
printf(" n convert to new (ProDOS 2.5+) format\n");
printf(" o convert to old (ProDOS 1.0-2.4.2, GSOS) format\n");
printf("\n");
printf("-sxxx: Dir sort, where xxx is a list of fields to sort\n");
printf("on. The sort options are processed left-to-right.\n");
printf(" n sort by filename ascending\n");
printf(" N sort by filename descending\n");
printf(" i sort by filename ascending - case insensitive\n");
@ -1499,7 +1557,7 @@ void usage(void) {
printf(" e sort by EOF position ascending\n");
printf(" E sort by EOF position descending\n");
printf("\n");
printf("Fix mode options x:\n");
printf("-fx: Fix mode, where x is:\n");
printf(" ? prompt for each fix\n");
printf(" n never fix\n");
printf(" y always fix (be careful!)\n");
@ -1592,7 +1650,7 @@ int main(int argc, char *argv[]) {
exit(1);
}
int opt;
while ((opt = getopt(argc, argv, "cDrwvVs:n:f:h")) != -1) {
while ((opt = getopt(argc, argv, "cDrwvVs:n:f:d:h")) != -1) {
switch (opt) {
case 'c':
do_ctime = 1;
@ -1622,6 +1680,9 @@ int main(int argc, char *argv[]) {
case 'f':
strncpy(fixopts, optarg, 1);
break;
case 'd':
strncpy(dateopts, optarg, 1);
break;
case 'h':
default:
usage();
@ -1631,8 +1692,8 @@ int main(int argc, char *argv[]) {
if (optind != argc - 1)
usage();
if (((strlen(caseopts) > 0) || (strlen(fixopts) > 0)) &&
(strlen(sortopts) == 0))
if (((strlen(caseopts) > 0) || (strlen(fixopts) > 0) ||
(strlen(dateopts) > 0)) && (strlen(sortopts) == 0))
strncpy(sortopts, ".", 1);
uchar dev;