📄 arjtypes.c
字号:
/* * $Id: arjtypes.c,v 1.5 2004/01/25 10:39:30 andrew_belov Exp $ * --------------------------------------------------------------------------- * This module provides some multiplatform property types which cover both DOS * (as internally involved in ARJ) and UNIX requirements. * */#include <time.h>#include "arj.h"DEBUGHDR(__FILE__) /* Debug information block *//* Timestamp macros */#define get_tx(m,d,h,n) (((unsigned long)m<<21)+((unsigned long)d<<16)+((unsigned long)h<<11)+(n<<5))#define get_tstamp(y,m,d,h,n,s) ((((unsigned long)(y-1980))<<25)+get_tx(m,d,h,n)+(s/2))#define ts_year(ts) ((unsigned int)((ts>>25)&0x7f)+1980)#define ts_month(ts) ((unsigned int)(ts>>21)&0x0f) /* 1..12 means Jan..Dec */#define ts_day(ts) ((unsigned int)(ts>>16)&0x1f) /* 1..31 means 1st..31st */#define ts_hour(ts) ((unsigned int)(ts>>11)&0x1f)#define ts_min(ts) ((unsigned int)(ts>>5)&0x3f)#define ts_sec(ts) ((unsigned int)((ts&0x1f)*2))static char monthdays[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};/* Q&D helper macro */#define is_unix(host_os) (host_os==OS_UNIX||host_os==OS_NEXT)/* Timestamp storage structures */#if SFX_LEVEL>=ARJSFX static char time_list_format[]="%04u-%02u-%02u %02u:%02u:%02u";#endif/* * File mode routines *//* Parses a file mode specifier from the archive. The idea is to allow creation of DOS attributes under UNIX, but no features exist for DOS->UNIX conversion. */void fm_store(struct file_mode *dest, int host_os, int mode){ if(host_os==OS_SPECIAL) dest->dos=dest->native=mode; if(is_unix(OS)) { dest->native=mode; dest->dos=FATTR_ARCH; if(is_unix(OS)&&!(mode&FATTR_IWUSR)) dest->dos|=FATTR_RDONLY; } else /* Assume a DOS-style system */ dest->dos=dest->native=mode;}/* Retrieves a native file mode corresponding to the host OS */unsigned int fm_native(struct file_mode *fm, int host_os){ return(is_unix(host_os)?fm->native:fm->dos);}/* * Timestamp routines *//* Returns 1 if there's a leap year */static int isleapyear(int year){ if(year%400==0) return(1); if(year%100==0) return(0); if(year%4==0) return(1); return(0);}/* A "home-brew" implemenation of localtime(). This is for cases when we have a TZ_VAR of our own. */#ifdef TZ_VARstatic struct tm *ununixtime(unsigned long *pt)#define localtime(t) ununixtime((unsigned long *)(t)){ unsigned long unixtime, timepart; int year, month, mdays; static struct tm stm; unixtime=*pt-TZ_VAR; if(_daylight) unixtime+=3600; timepart=unixtime%86400L; unixtime/=86400L; for(year=1970; 365+isleapyear(year)<=unixtime; year++) unixtime-=365+isleapyear(year); stm.tm_year=year-1900; month=0; while(1) { if(month==1) mdays=isleapyear(year)?29:28; else mdays=monthdays[month]; if(mdays>unixtime||month==11) break; unixtime-=mdays; month++; } stm.tm_mon=month; stm.tm_mday=unixtime+1; stm.tm_hour=timepart/3600; stm.tm_min=timepart/60%60; stm.tm_sec=timepart%60; return(&stm);}#endif/* Converts a UNIX timestamp to the DOS style */static unsigned long ts_unix2dos(unsigned long ts){ struct tm *stm; stm=localtime((time_t*)&ts); return(get_tstamp(stm->tm_year+1900, stm->tm_mon+1, stm->tm_mday, stm->tm_hour, stm->tm_min, stm->tm_sec));}/* Creates a Unix timestamp from the given date and time */static unsigned long mk_unixtime(int y, int m, int d, int hh, int mm, int ss){ unsigned long u=0; int i; /* Clash with NetBSD/x86-64 patch: leaving rc as unsigned long still permits to escape the year 2038 problem in favor of year 2106 problem, while a dedicated time_t structure can be expected as a 64-bit value on relevant platforms -- ASR fix 25/01/2004 */ unsigned long rc; time_t tt; long tzshift; #ifndef TZ_VAR long shiftd1, shiftd2; #endif struct tm *stm; if(y>=2001) { i=y-2001; u=11323; /* The following piece of code is rather paranoid in 16/32-bit world, where the timestamps are limited to year 2108. */ #if defined(__32BIT__)||defined(TILED) if(i>=400) { u+=1022679L*(i/400); i%=400; } #endif if(i>=100) { u+=36524L*(i/100); i%=100; } u+=1461L*(i/4); u+=365L*(i%4); } else if(y>=1973) u=1096+(y-1973)/4*1461L+((y-1973)%4)*365L; else u=(y-1970)*365L; for(i=1; i<m; i++) { u+=(int)monthdays[i-1]; if(i==2) u+=isleapyear(y); } rc=86400*(unsigned long)(u+d-1)+(unsigned long)hh*3600+(unsigned long)mm*60+(unsigned long)ss; /* If we have to use the timezone variable, do it now */ #ifdef TZ_VAR tzshift=-TZ_VAR; if(_daylight) tzshift+=3600; #else tt=(time_t)rc; stm=localtime(&tt); debug_assert(stm!=NULL); /* LIBCS.DLL returns NULL for unixtime beyond 0x7FFFFFFF */ tzshift=(long)stm->tm_hour*3600+(long)stm->tm_min*60; shiftd1=stm->tm_mday; stm=gmtime(&tt); debug_assert(stm!=NULL); shiftd2=stm->tm_mday; /* Local time overruns GMT, add 24 hours for safety */ if(shiftd1<shiftd2&&shiftd1==1&&shiftd2>=28) tzshift+=86400; else if(shiftd1>shiftd2&&shiftd1>=28&&shiftd2==1) tzshift-=86400; else if(shiftd1>shiftd2) tzshift+=86400; else if(shiftd1<shiftd2) tzshift-=86400; tzshift-=(long)stm->tm_hour*3600+(long)stm->tm_min*60; tzshift%=86400; #endif /* Fix the timezone if it does not roll over the zero */ return((tzshift>0&&rc<tzshift)?rc:rc-tzshift);}/* Converts a DOS timestamp to the UNIX representation */static unsigned long ts_dos2unix(unsigned long ts){ unsigned int y, m, d, hh, mm, ss; unsigned long rc; if(ts==0) return(0); y=ts_year(ts); m=ts_month(ts); d=ts_day(ts); hh=ts_hour(ts); mm=ts_min(ts); ss=ts_sec(ts); /* TODO: These assertions must be replaced by run-time check for incorrect timestamps like 31/15/2063 or 00/00/1980, since month array is 1...12 only. */ #ifdef DEBUG debug_assert(m>=1&&m<=12); debug_assert(d>=1&&d<=31); #endif return(mk_unixtime(y, m, d, hh, mm, ss));}/* Stores a timestamp */void ts_store(struct timestamp *dest, int host_os, unsigned long value){ if(host_os==OS_SPECIAL) dest->dos=dest->unixtime=value; else if(is_unix(host_os)) { dest->unixtime=value; dest->dos=ts_unix2dos(value); } else { dest->dos=value; dest->unixtime=ts_dos2unix(value); }}/* Retrieves a native timestamp corresponding to the host OS */unsigned long ts_native(struct timestamp *ts, int host_os){ return(is_unix(host_os)?ts->unixtime:ts->dos);}/* Compares two timestamps */int ts_cmp(struct timestamp *ts1, struct timestamp *ts2){ unsigned long tsn1, tsn2; tsn1=ts_native(ts1, OS); tsn2=ts_native(ts2, OS); if(tsn1<tsn2) return(-1); else if(tsn1==tsn2) return(0); else return(1);}#if SFX_LEVEL>=ARJ||defined(REARJ)/* Produces an ARJ timestamp from the given date */void make_timestamp(struct timestamp *dest, int y, int m, int d, int hh, int mm, int ss){ dest->unixtime=mk_unixtime(y, m, d, hh, mm, ss); dest->dos=ts_unix2dos(dest->unixtime);}#endif#if SFX_LEVEL>=ARJSFX/* Restores the given timestamp to character form */void timestamp_to_str(char *str, struct timestamp *ts){ struct tm *stm; stm=localtime((time_t *)&ts->unixtime); /* Workaround for a MS C v 7.0 CRT bug */ #if TARGET==DOS&&COMPILER==MSC&&_MSC_VER==700 if(stm->tm_year<70) /* 31 -> 101 */ stm->tm_year+=70; #endif sprintf(str, time_list_format, stm->tm_year+1900, stm->tm_mon+1, stm->tm_mday, stm->tm_hour, stm->tm_min, stm->tm_sec);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -