+/* time conversions */
+/* cpm2unix_time -- convert CP/M time to UTC */ /*{{{*/
+static time_t cpm2unix_time(int days, int hour, int min)
+{
+ /* CP/M stores timestamps in local time. We don't know which */
+ /* timezone was used and if DST was in effect. Assuming it was */
+ /* the current offset from UTC is most sensible, but not perfect. */
+
+ int year,days_per_year;
+ static int days_per_month[]={31,0,31,30,31,30,31,31,30,31,30,31};
+ char **old_environ;
+ static char gmt0[]="TZ=GMT0";
+ static char *gmt_env[]={ gmt0, (char*)0 };
+ struct tm tms;
+ time_t lt,t;
+
+ time(<);
+ t=lt;
+ tms=*localtime(<);
+ old_environ=environ;
+ environ=gmt_env;
+ lt=mktime(&tms);
+ lt-=t;
+ tms.tm_sec=0;
+ tms.tm_min=((min>>4)&0xf)*10+(min&0xf);
+ tms.tm_hour=((hour>>4)&0xf)*10+(hour&0xf);
+ tms.tm_mday=1;
+ tms.tm_mon=0;
+ tms.tm_year=78;
+ tms.tm_isdst=-1;
+ for (;;)
+ {
+ year=tms.tm_year+1900;
+ days_per_year=((year%4)==0 && ((year%100) || (year%400)==0)) ? 366 : 365;
+ if (days>days_per_year)
+ {
+ days-=days_per_year;
+ ++tms.tm_year;
+ }
+ else break;
+ }
+ for (;;)
+ {
+ days_per_month[1]=(days_per_year==366) ? 29 : 28;
+ if (days>days_per_month[tms.tm_mon])
+ {
+ days-=days_per_month[tms.tm_mon];
+ ++tms.tm_mon;
+ }
+ else break;
+ }
+ t=mktime(&tms)+(days-1)*24*3600;
+ environ=old_environ;
+ t-=lt;
+ return t;
+}
+/*}}}*/
+/* unix2cpm_time -- convert UTC to CP/M time */ /*{{{*/
+static void unix2cpm_time(time_t now, int *days, int *hour, int *min)
+{
+ struct tm *tms;
+ int i;
+
+ tms=localtime(&now);
+ *min=((tms->tm_min/10)<<4)|(tms->tm_min%10);
+ *hour=((tms->tm_hour/10)<<4)|(tms->tm_hour%10);
+ for (i=1978,*days=0; i<1900+tms->tm_year; ++i)
+ {
+ *days+=365;
+ if (i%4==0 && (i%100!=0 || i%400==0)) ++*days;
+ }
+ *days += tms->tm_yday+1;
+}
+/*}}}*/
+