/* This is part of ODS2 written by Paul Nankervis, * email address: Paulnank@au1.ibm.com * * ODS2 is distributed freely for all members of the * VMS community to use. However all derived works * must maintain comments in their source to acknowledge * the contributions of the original author and * subsequent contributors. This is free software; no * warranty is offered, and while we believe it to be useful, * you use it at your own risk. */ /* * Vmstime.c * Author: Paul Nankervis * 1.4 Changed declarations NOT to define DOLLAR identifiers * unless DOLLAR is defined (some compilers can't handle $'s!) * 1.4A Changed default DOLLAR handling to include DOLLAR * identifers unless NO_DOLLAR is defined * (ie #ifdef DOLLAR to #ifndef NO_DOLLAR) * 1.5 Added 64 bit support and cvt_internal routines * 1.6 Change addx, subx and compare to use larger integers * 1.6A Fixed endian problems in addx/subx * Please send bug reports or requests for enhancement * or improvement via email to: PaulNank@au1.ibm.com * This module contains versions of the VMS time routines * sys$numtim(), sys$asctim() and friends... They are * intended to be compatible with the routines of the same * name on a VMS system (so descriptors feature regularly!) * This code relies on being able to manipluate day numbers * and times using 32 bit arithmetic to crack a VMS quadword * byte by byte. If your C compiler doesn't have 32 bit unsigned * integer types then give up now! On a 64 bit systems VMSTIME_64BIT * can be defined to do 64 bit operations directly.... * One advantage of doing arithmetic byte by byte is that * the code does not depend on what 'endian' the target * machine is - it will always treat bytes in the same order! * (Hopefully VMS time bytes will always be in the same order!) * Note: VMS time quadwords are simply an eight byte integer * (quadword) representing the number of 100 nanasecond * units since 17-Nov-1858. Delta times (time differences) * are represented by a negative quadword value. It is * interesting that Windows UTC times are in the same units * but are based on the year 1601. * A couple of stupid questions to go on with:- * o OK, I give up! What is the difference between a zero * date and a zero delta time? * o Anyone notice that the use of 16 bit words in * sys$numtim restricts delta times to 65535 days? * Paul Nankervis * paulnank@au1.ibm.com * Note: The routine are defined here with an underscore instead * of a dollar symbol (ie sys_asctim instead of sys$asctim). * This avoids problems on systems which don't handle * the '$' well, and it avoids conflicts under VMS. */ #if !defined( DEBUG ) && defined( DEBUG_VMSTIME ) #define DEBUG DEBUG_VMSTIME #else #ifndef DEBUG #define DEBUG 0 #endif #endif #include #include #include #include #ifdef _WIN32 #include /* Use windows routines to get currrent time */ #else #ifndef NO_LOCALTIME #if defined(VMS) #include /* For VAXC and GCC include libraries on VMS */ #else #ifdef USE_FTIME #include /* For ftime() */ #else #include /* gettimeofday() */ #endif #endif #endif #endif #include "vmstime.h" /* Our header file! */ #include "ods2.h" #define TIMEBASE 100000 /* 10 millisecond units in quadword */ #define TIMESIZE 8640000 /* Factor between dates & times */ #define QUAD_CENTURY_DAYS 146097 /* (400*365) + (400/4) - (400/100) + (400/400) */ #define CENTURY_DAYS 36524 /* (100*365) + (100/4) - (100/100) */ #define QUAD_YEAR_DAYS 1461 /* (4*365) + (4/4) */ #define YEAR_DAYS 365 /* 365 */ #define OFFSET_DAYS 94187 /* ((1858-1601)*365) + ((1858-1601)/4) - ((1858-1601)/100) + ((1858-1601)/400) + 320 OFFSET FROM 1/1/1601 TO 17/11/1858 */ #define BASE_YEAR 1601 /* lib$addx & lib$subx perform arithmetic using a small integer at a time. Compare can be done using a full size integer (if the endian is correct.Note that on a big endian machine the maximum unit of work is always one character!!! */ #ifdef VMSTIME_64BIT #define LARGE_INT unsigned VMSTIME_64BIT #define SMALL_INT unsigned int #define WORK_INT unsigned VMSTIME_64BIT #else #define WORK_INT unsigned int #if defined(VMS) || defined(_WIN32) #define LARGE_INT unsigned int #define SMALL_INT unsigned short #else #define SMALL_INT unsigned char #endif #endif /***************************************************************** lib_addx() */ unsigned lib_addx(void *addant,void *addee,void *result,int *lenadd) { register int count; if (lenadd == NULL) { count = 8; } else { count = *lenadd * 4; } #ifdef LARGE_INT if (count == sizeof(LARGE_INT)) { *(LARGE_INT *) result = *(LARGE_INT *) addant + *(LARGE_INT *) addee; } else { #else { #endif register SMALL_INT *ant = (SMALL_INT *) addant; register SMALL_INT *ee = (SMALL_INT *) addee; register SMALL_INT *res = (SMALL_INT *) result; register WORK_INT carry = 0; count /= sizeof(SMALL_INT); do { carry = *ant++ + (carry + *ee++); *res++ = carry; carry = carry >> (sizeof(SMALL_INT) * 8); } while (--count > 0); } return LIB__NORMAL; } /***************************************************************** lib_subx() */ unsigned lib_subx(void *subant,void *subee,void *result,int *lenadd) { register int count; if (lenadd == NULL) { count = 8; } else { count = *lenadd * 4; } #ifdef LARGE_INT if (count == sizeof(LARGE_INT)) { *(LARGE_INT *) result = *(LARGE_INT *) subant + *(LARGE_INT *) subee; } else { #else { #endif register SMALL_INT *ant = (SMALL_INT *) subant; register SMALL_INT *ee = (SMALL_INT *) subee; register SMALL_INT *res = (SMALL_INT *) result; register WORK_INT carry = 0; count /= sizeof(SMALL_INT); do { carry = *ant++ - (carry + *ee++); *res++ = carry; carry = (carry >> (sizeof(SMALL_INT) * 8)) & 1; } while (--count > 0); } return LIB__NORMAL; } /********************************************************** vmstime_compare() */ /* vmstime_compare() is used to compare times. returns -1 if time2 is bigger 0 if times are equal 1 if time1 is bigger */ int vmstime_compare(pVMSTIME time1,pVMSTIME time2) { #ifdef VMSTIME_64BIT if (*time1 > *time2) return 1; if (*time1 < *time2) return -1; #else #ifdef LARGE_INT register int count = 8 / sizeof(LARGE_INT); register LARGE_INT *t1 = (LARGE_INT *) time1 + 8 / sizeof(LARGE_INT) - 1; register LARGE_INT *t2 = (LARGE_INT *) time2 + 8 / sizeof(LARGE_INT) - 1; #else register int count = 8 / sizeof(SMALL_INT); register SMALL_INT *t1 = (SMALL_INT *) time1 + 8 / sizeof(SMALL_INT) - 1; register SMALL_INT *t2 = (SMALL_INT *) time2 + 8 / sizeof(SMALL_INT) - 1; #endif do { if (*t1 > *t2) return 1; if (*t1 < *t2) return -1; t1--; t2--; } while (--count > 0); #endif return 0; } /******************************************************** vmstime_date_time() */ /* vmstime_date_time() is an internal routine assemble the date (day number) and time in a time quadword - basically the opposite of lib_day() */ unsigned vmstime_date_time(int days,pVMSTIME timadr,int day_time) { /* Put date/time into VMS quadword timbuf... */ #ifdef VMSTIME_64BIT if (day_time <= -TIMESIZE || day_time >= TIMESIZE) return SS__IVTIME; *timadr = ((days * (VMSTIME_64BIT) TIMESIZE) + day_time) * TIMEBASE; #else register unsigned time = day_time; register unsigned char *dstptr = timadr; register int count = 8,carry = 0,date = days; if (day_time <= -TIMESIZE || day_time >= TIMESIZE) return SS__IVTIME; if (date == 0 && day_time < 0) { do { carry += (time & 0xFF) * TIMEBASE; time = (time >> 8) | 0xFF000000; *dstptr++ = carry; carry = (carry >> 8); } while (--count > 0); } else{ do { time += (date & 0xFF) * TIMESIZE; date = (date >> 8); carry += (time & 0xFF) * TIMEBASE; time = (time >> 8); *dstptr++ = carry; carry = (carry >> 8); } while (--count > 0); } #endif return SS__NORMAL; } /*********************************************************** lib_cvt_vectim() */ /* lib_cvt_vectim() takes individual date/time fields from a seven word buffer and munges them into a time quadword... */ int vmstime_mthend[] = {0,31,60,91,121,152,182,213,244,274,305,335,366}; unsigned lib_cvt_vectim(unsigned short timvec[7],pVMSTIME timadr) { register vmscond_t sts; register int year,month,days; /* lib_cvt_vectim packs the seven date/time components into a quadword... */ if (timvec[3] > 23 || timvec[4] > 59 || timvec[5] > 59 || timvec[6] > 99) return SS__IVTIME; year = timvec[0]; month = timvec[1]; days = timvec[2]; if (year == 0 && month == 0) { /* Pass back delta result */ sts = vmstime_date_time(-days,timadr,timvec[3] * -360000 - timvec[4] * 6000 - timvec[5] * 100 - timvec[6]); } else { /* Generate days since base date.. */ int nonleap_adjust = 0; if (year < 1858 || year > 9999 || month < 1 || month > 12 || days < 1) return SS__IVTIME; days += vmstime_mthend[month - 1]; if (month > 1) { if (year % 4) { nonleap_adjust = 1; } else { if ((year % 100) == 0 && year % 400) nonleap_adjust = 1; } } if (days > vmstime_mthend[month] || (month == 2 && days > vmstime_mthend[month] - nonleap_adjust)) return SS__IVTIME; if (month > 2) days -= nonleap_adjust; year -= BASE_YEAR; days += year * YEAR_DAYS + year / 4 - year / 100 + year / 400 - OFFSET_DAYS - 1; sts = vmstime_date_time(days,timadr,timvec[3] * 360000 + timvec[4] * 6000 + timvec[5] * 100 + timvec[6]); } return sts; } /*************************************************************** sys_gettim() */ /* sys_gettim() implemented here by getting C library time in seconds since 1-Jan-1970 and munging into a time quadword... Can use time() to just get seconds or ftime() to find seconds with milli-seconds. localtime() is used to find non-offset time. Note that some libraries don't do any of this particularly well! Under windows we can use a munged version of the internal UTC time */ unsigned sys_gettim(pVMSTIME timadr) { #ifdef _WIN32 /* Get windows time adjust for timezone and convert to VMS... */ GetSystemTimeAsFileTime((struct _FILETIME *)timadr); FileTimeToLocalFileTime((struct _FILETIME *)timadr, (struct _FILETIME *)timadr); return vmstime_from_nt(timadr,timadr); #else #ifdef NO_LOCALTIME /* Use time straight from time() */ time_t curtim = time(NULL); return vmstime_date_time(40587 + curtim / 86400,timadr, (curtim % 86400) * 100); #else /* Get time from ftime() and localtime() */ struct tm *lclptr; unsigned short timvec[7]; #ifdef USE_FTIME struct timeb timval; timval.millitm = 0; /* for broken versions of ftime() */ ftime(&timval); lclptr = localtime(&timval.time); timvec[6] = timval.millitm / 10; #else struct timeval timval; if( gettimeofday( &timval, NULL ) ) { return SS$_BADPARAM; } lclptr = localtime(&timval.tv_sec); timvec[6] = (timval.tv_usec + 500) / 10000; #endif timvec[0] = lclptr->tm_year + 1900; timvec[1] = lclptr->tm_mon + 1; timvec[2] = lclptr->tm_mday; timvec[3] = lclptr->tm_hour; timvec[4] = lclptr->tm_min; timvec[5] = lclptr->tm_sec; return lib_cvt_vectim(timvec,timadr); #endif #endif } /************************************************************** vmstime_day() */ /* vmstime_day() is a routine to crack time quadwords into a day number and time. It is different to lib_day() in that delta times are returned as negative values to distinguish small delta values from dates */ unsigned vmstime_day(int *days,pVMSTIME timadr,int *day_time) { VMSTIME wrktim; #ifdef VMSTIME_64BIT register VMSTIME_64BIT timval; #else register int delta = 0; register unsigned char *srcptr; #endif /* If no time specified get current using gettim() */ if (timadr == NULL) { register vmscond_t sts; sts = sys_gettim(wrktim); if (!(sts & STS_M_SUCCESS)) return sts; #ifdef VMSTIME_64BIT timval = *wrktim; } else { timval = *timadr; } timval /= TIMEBASE; *days = (timval / TIMESIZE); if (day_time != NULL) *day_time = (timval % TIMESIZE); #else srcptr = wrktim + 7; } else { /* Check specified time for delta... */ if ((delta = ISDELTA(timadr))) { /* We have to 2's complement delta times - sigh!! */ register int count = 8,carry = 1; register unsigned char *dstptr = wrktim; srcptr = timadr; do { carry += (~*srcptr++) & 0xFF; *dstptr++ = carry; carry = carry >> 8; } while (--count > 0); srcptr = wrktim + 7; } else { srcptr = timadr + 7; } } /* Extract the date and time from the quadword... */ { register int count = 5,date = 0; register unsigned time = 0, carry; carry = *srcptr--; carry = (carry << 8) | *srcptr--; carry = (carry << 8) | *srcptr--; do { carry = (carry << 8) | *srcptr--; time = (time << 8) | (carry / TIMEBASE); date = (date << 8) | (time / TIMESIZE); carry %= TIMEBASE; time %= TIMESIZE; } while (--count > 0); /* Return results... */ if (delta) { *days = -(int) date; if (day_time != NULL) *day_time = -(int) time; } else { *days = date; if (day_time != NULL) *day_time = time; } } #endif return LIB__NORMAL; } /****************************************************************** lib_day() */ /* lib_day() is a routine to crack time quadwords into a day number and time. */ unsigned lib_day(int *days,pVMSTIME timadr,int *day_time) { register vmscond_t sts; sts = vmstime_day(days,timadr,day_time); if (*day_time < 0) *day_time = -*day_time; return sts; } /*********************************************************** vmstime_numtim() */ /* vmstime_numtim() takes a time quadword and breaks it into a seven word time vector (year,month,day,hour...) */ unsigned vmstime_numtim(unsigned short timvec[7],pVMSTIME timadr, int *days,int *day_time,int *day_of_year) { register int date,time; /* Use vmstime_day to crack time into days/time... */ { register vmscond_t sts; sts = vmstime_day(days,timadr,day_time); if (!(sts & STS_M_SUCCESS)) return sts; date = *days; time = *day_time; } /* Delta time or date? */ if (date < 0 || time < 0) { timvec[0] = 0; /* Year */ timvec[1] = 0; /* Month */ timvec[2] = -date; /* Days */ time = -time; } else { /* Date - calculate years to quad century... */ register int year; date += OFFSET_DAYS; year = BASE_YEAR + (date / QUAD_CENTURY_DAYS) * 400; date %= QUAD_CENTURY_DAYS; /* Add years to century - last century in quad is longer!! */ { register int century = date / CENTURY_DAYS; if (century == 4) century = 3; if (century) { year += century * 100; date -= century * CENTURY_DAYS; } } /* Add years to quad year... */ year += (date / QUAD_YEAR_DAYS) * 4; date %= QUAD_YEAR_DAYS; /* Finally to current year - last year in quad is longer!! */ { register int yearno = date / YEAR_DAYS; if (yearno == 4) yearno = 3; if (yearno) { year += yearno; date -= yearno * YEAR_DAYS; } } if (day_of_year != NULL) *day_of_year = date; /* Non-leap adjustment for years which have no Feb 29th */ if (date++ > 58) { if (year % 4) { date++; } else { if ((year % 100) == 0 && year % 400) date++; } } /* Figure out month and return results... */ { register int month = 1; while (date > vmstime_mthend[month]) month++; timvec[0] = year; /* Year */ timvec[1] = month; /* Month */ timvec[2] = date - vmstime_mthend[month - 1]; /* Days */ } } /* Return time information... */ timvec[6] = time % 100; /* Hundredths */ time /= 100; timvec[5] = time % 60; /* Seconds */ time /= 60; timvec[4] = time % 60; /* Minutes */ timvec[3] = time / 60; /* Hours */ return SS__NORMAL; } /*************************************************************** sys_numtim() */ /* sys_numtim() takes a time quadword and breaks it into a seven word time vector (year,month,day,hour...) */ unsigned sys_numtim(unsigned short timvec[7],pVMSTIME timadr) { int days,day_time; return vmstime_numtim(timvec,timadr,&days,&day_time,NULL); } /*********************************************************** vmstime_getnum() */ /* Define internal tables... */ static const char vmstime_punct[] = "::."; static const char vmstime_digits[] = "0123456789"; static const char vmstime_months[] = "-JAN-FEB-MAR-APR-MAY-JUN-JUL-AUG-SEP-OCT-NOV-DEC-"; /* vmstime_getnum() internal routine to convert a printable number to binary */ char *vmstime_getnum(char *ptr,char *end,unsigned short *result,int *scale) { register int numval = 0; register int scaleval = 1; register char *chrptr = ptr; do { register int binval = 0; register char digit = *chrptr++; do { if (digit == vmstime_digits[binval]) break; } while (++binval < 10); numval = numval * 10 + binval; scaleval *= 10; } while (chrptr < end && isdigit(*chrptr)); *result = numval; *scale = scaleval; return chrptr; } /*************************************************************** sys_bintim() */ #define NOVALUE 0xFFFF /* sys_bintim() takes a printable time and converts it to a time quadword */ unsigned sys_bintim(struct dsc_descriptor *timbuf,pVMSTIME timadr) { int scale; unsigned short wrktim[7]; register int field_count = 0; register char *chrptr = timbuf->dsc_a_pointer; register char *endptr = chrptr + timbuf->dsc_w_length; memset( wrktim, 0, sizeof(wrktim) ); /* Skip any spaces... */ while (chrptr < endptr && *chrptr == ' ') chrptr++; /* Get the day number or delta days... */ if (chrptr < endptr && isdigit(*chrptr)) { chrptr = vmstime_getnum(chrptr,endptr,&wrktim[2],&scale); field_count++; } else { wrktim[2] = NOVALUE; } /* Check for month separator "-" - if found then we have a date! */ if (chrptr < endptr && *chrptr == '-') { chrptr++; wrktim[0] = wrktim[1] = NOVALUE; wrktim[3] = wrktim[4] = wrktim[5] = wrktim[6] = NOVALUE; /* See if there is a month... */ if (chrptr + 2 < endptr && *chrptr != '-') { register int month = 1; register char upmth0 = toupper(chrptr[0]); register char upmth1 = toupper(chrptr[1]); register char upmth2 = toupper(chrptr[2]); register const char *mthptr = vmstime_months + 1; do { if (upmth0 == mthptr[0] && upmth1 == mthptr[1] && upmth2 == mthptr[2]) break; mthptr += 4; } while (++month <= 12); chrptr += 3; wrktim[1] = month; field_count++; } /* Now look for year... */ if (chrptr < endptr && *chrptr == '-') { chrptr++; if (chrptr < endptr && isdigit(*chrptr)) { chrptr = vmstime_getnum(chrptr,endptr,&wrktim[0],&scale); field_count++; } } } else { /* Set default values for delta time... */ wrktim[0] = wrktim[1] = 0; wrktim[3] = wrktim[4] = wrktim[5] = wrktim[6] = 0; if (wrktim[2] == NOVALUE) wrktim[2] = 0; /* If no space then just a time value? */ if (chrptr < endptr && *chrptr != ' ') { wrktim[3] = wrktim[2]; wrktim[2] = 0; } field_count = 7; /* Don't use current time! */ } /* Skip any spaces... */ while (chrptr < endptr && *chrptr == ' ') chrptr++; /* Extract time fields... Note: we don't round hundredths into seconds */ { register int time_field; for (time_field = 0; time_field < 4 && chrptr < endptr; time_field++) { if (chrptr < endptr && isdigit(*chrptr)) { chrptr = vmstime_getnum(chrptr,endptr,&wrktim[time_field + 3], &scale); field_count++; if (time_field == 3) { register unsigned hundredth = wrktim[6] * 1000 / scale; if (hundredth < 995) hundredth += 5; wrktim[6] = hundredth / 10; break; } } if (chrptr < endptr && time_field < 3 && *chrptr == vmstime_punct[time_field]) chrptr++; } } /* Skip any spaces... */ while (chrptr < endptr && *chrptr == ' ') chrptr++; /* If anything left then we have a problem... */ if (chrptr < endptr) return SS__IVTIME; /* If some fields not specified use current time...*/ if (field_count < 7) { register int field; unsigned short curtim[7]; register vmscond_t sts = sys_numtim(curtim,NULL); if (!(sts & STS_M_SUCCESS)) return sts; for (field = 0; field < 7; field++) { if (wrktim[field] == NOVALUE) wrktim[field] = curtim[field]; } } return lib_cvt_vectim(wrktim,timadr); } /*************************************************************** sys_asctim() */ /* sys_asctim() converts a time quadword into printable form... */ unsigned sys_asctim(unsigned short *timlen,struct dsc_descriptor *timbuf, pVMSTIME timadr,unsigned cvtflg) { unsigned short timvec[7]; register int count,timval; register char *chrptr = timbuf->dsc_a_pointer; register char *endptr = chrptr + timbuf->dsc_w_length; /* First use sys_numtim to get the date/time fields... */ { register vmscond_t sts; sts = sys_numtim(timvec,timadr); if (!(sts & STS_M_SUCCESS)) return sts; } /* See if we want delta days or date... */ if (cvtflg == 0) { /* Check if date or delta time... */ if (timvec[0]) { /* Generate two digit day... */ if( chrptr < endptr ) { if( (timval = timvec[2]) / 10 == 0 ) { *chrptr++ = ' '; } else { *chrptr++ = vmstime_digits[timval / 10]; } if( chrptr < endptr ) { *chrptr++ = vmstime_digits[timval % 10]; } } /* Add month name with hyphen separators... */ if ((count = (int)(endptr - chrptr)) > 5) count = 5; memcpy(chrptr,vmstime_months + (((size_t)timvec[1] - 1) * 4),count); chrptr += count; /* Get year... */ timval = timvec[0]; } else { /* Get delta days... */ timval = timvec[2]; } /* Common code for year number and delta days! Spaces first... */ count = 1000; if (timval < count && chrptr < endptr) { do { *chrptr++ = ' '; count /= 10; } while (timval < count && count > 1 && chrptr < endptr); } else { if (timval >= 10000) count = 10000; } /* Then digits... */ if (chrptr < endptr) { do { *chrptr++ = vmstime_digits[timval / count]; timval = timval % count; count /= 10; } while (count > 0 && chrptr < endptr); } /* Put a space between date and time... */ if (chrptr < endptr) *chrptr++ = ' '; } /* Move onto time fields... hh:mm:ss.hh */ if (chrptr < endptr) { count = 0; do { timval = timvec[count + 3]; *chrptr++ = vmstime_digits[timval / 10]; if (chrptr >= endptr) break; *chrptr++ = vmstime_digits[timval % 10]; if (count >= 3 || chrptr >= endptr) break; *chrptr++ = vmstime_punct[count++]; } while (chrptr < endptr); } /* We've done it - return length... */ if (timlen != NULL) *timlen = (int)((chrptr - (char *) timbuf->dsc_a_pointer)); return SS__NORMAL; } /********************************************************** lib_day_of_week() */ /* lib_day_of_week() computes day of week from time quadword... */ unsigned lib_day_of_week(pVMSTIME timadr,unsigned *weekday) { int days; register vmscond_t sts; /* Use lib_day to crack quadword... */ sts = lib_day(&days,timadr,NULL); if (sts & STS_M_SUCCESS) { *weekday = ((days + 2) % 7) + 1; } return sts; } /****************************************************** lib_mult_delta_time() */ /* lib_mult_delta_time multiplies a delta time by a scalar integer... */ unsigned lib_mult_delta_time(int *multiple,pVMSTIME timadr) { register int factor = *multiple; /* Check for delta time... */ if (!ISDELTA(timadr)) return SS__IVTIME; /* Use absolute factor... */ if (factor < 0) factor = -factor; #ifdef VMSTIME_64BIT *timadr *= factor; #else { register int count = 8; register unsigned carry = 0; register unsigned char *ptr = timadr; do { carry += *ptr * factor; *ptr++ = carry; carry = (carry >> 8); } while (--count > 0); } #endif return LIB__NORMAL; } /************************************************************ lib_add_times() */ /* lib_add_times() adds two quadword time values */ unsigned lib_add_times(pVMSTIME time1,pVMSTIME time2,pVMSTIME result) { if (ISDELTA(time1)) { if (ISDELTA(time2)) { #ifdef VMSTIME_64BIT *result = *time1 + *time2; } else { *result = *time2 - *time1; #else lib_addx(time1,time2,result,NULL); } else { lib_subx(time2,time1,result,NULL); #endif } } else { if (ISDELTA(time2)) { #ifdef VMSTIME_64BIT *result = *time1 - *time2; #else lib_subx(time1,time2,result,NULL); #endif } else { return LIB__ONEDELTIM; } } return LIB__NORMAL; } /************************************************************ lib_sub_times() */ /* lib_sub_times() subtracts two quadword time values */ unsigned lib_sub_times(pVMSTIME time1,pVMSTIME time2,pVMSTIME result) { #ifdef VMSTIME_64BIT if (ISDELTA(time1) != ISDELTA(time2)) { *result = *time1 + *time2; } else { if (*time1 < *time2) { *result = *time1 - *time2; } else { *result = *time2 - *time1; } } #else if (ISDELTA(time1) != ISDELTA(time2)) { lib_addx(time1,time2,result,NULL); } else { if (vmstime_compare(time1,time2) < 0) { lib_subx(time1,time2,result,NULL); } else { lib_subx(time2,time1,result,NULL); } } #endif return LIB__NORMAL; } /*********************************************** lib_cvt_from_internal_time() */ /* lib_cvt_from_internal_time() extracts a time field from a time value */ unsigned lib_cvt_from_internal_time(unsigned *operation, unsigned *result,pVMSTIME input_time) { register unsigned resval; unsigned short timvec[7]; int days,day_time,day_of_year; if (*operation >= LIB$K_MAX_OPERATION) return LIB__INVOPER; { register vmscond_t sts; sts = vmstime_numtim(timvec,input_time,&days,&day_time,&day_of_year); if (!(sts & STS_M_SUCCESS)) return sts; } if (timvec[0] != 0) { switch (*operation) { case LIB$K_MONTH_OF_YEAR: resval = timvec[1]; break; case LIB$K_DAY_OF_YEAR: resval = day_of_year + 1; break; case LIB$K_HOUR_OF_YEAR: resval = day_of_year * 24 + timvec[3]; break; case LIB$K_MINUTE_OF_YEAR: resval = (day_of_year * 24 + timvec[3]) * 60 + timvec[4]; break; case LIB$K_SECOND_OF_YEAR: resval = ((day_of_year * 24 + timvec[3]) * 60 + timvec[4]) * 60 + timvec[5]; break; case LIB$K_DAY_OF_MONTH: resval = timvec[2]; break; case LIB$K_HOUR_OF_MONTH: resval = (timvec[2] - 1) * 24 + timvec[3]; break; case LIB$K_MINUTE_OF_MONTH: resval = ((timvec[2] - 1) * 24 + timvec[3]) * 60 + timvec[4]; break; case LIB$K_SECOND_OF_MONTH: resval = (((timvec[2] - 1) * 24 + timvec[3]) * 60 + timvec[4]) * 60 + timvec[5]; break; case LIB$K_DAY_OF_WEEK: resval = ((days + 2) % 7) + 1; break; case LIB$K_HOUR_OF_WEEK: resval = ((days + 2) % 7) * 24 + timvec[3]; break; case LIB$K_MINUTE_OF_WEEK: resval = (((days + 2) % 7) * 24 + timvec[3]) * 60 + timvec[4]; break; case LIB$K_SECOND_OF_WEEK: resval = ((((days + 2) % 7) * 24 + timvec[3]) * 60 + timvec[4]) * 60 + timvec[5]; break; case LIB$K_HOUR_OF_DAY: resval = timvec[3]; break; case LIB$K_MINUTE_OF_DAY: resval = timvec[3] * 60 + timvec[4]; break; case LIB$K_SECOND_OF_DAY: resval = (timvec[3] * 60 + timvec[4]) * 60 + timvec[5]; break; case LIB$K_MINUTE_OF_HOUR: resval = timvec[4]; break; case LIB$K_SECOND_OF_HOUR: resval = timvec[4] * 60 + timvec[5]; break; case LIB$K_SECOND_OF_MINUTE: resval = timvec[5]; break; case LIB$K_JULIAN_DATE: resval = days; break; default: return LIB__DELTIMREQ; } } else { switch (*operation) { case LIB$K_DELTA_WEEKS: resval = timvec[2] / 7; break; case LIB$K_DELTA_DAYS: resval = timvec[2]; break; case LIB$K_DELTA_HOURS: resval = timvec[2] * 24 + timvec[3]; break; case LIB$K_DELTA_MINUTES: resval = (timvec[2] * 24 + timvec[3]) * 60 + timvec[4]; break; case LIB$K_DELTA_SECONDS: resval = ((timvec[2] * 24 + timvec[3]) * 60 + timvec[4]) * 60 + timvec[5]; break; case 0: case LIB$K_DELTA_WEEKS_F: case LIB$K_DELTA_DAYS_F: case LIB$K_DELTA_HOURS_F: case LIB$K_DELTA_MINUTES_F: case LIB$K_DELTA_SECONDS_F: return LIB__INVOPER; default: return LIB__ABSTIMREQ; } } *result = resval; return LIB__NORMAL; } /************************************************* lib_cvt_to_internal_time() */ static const unsigned char vmstime_oneweek[] = {0x00,0xc0,0x1b,0xd7,0x7f,0xfa,0xff,0xff}; static const unsigned char vmstime_oneday[] = {0x00,0x40,0x96,0xd5,0x36,0xff,0xff,0xff}; static const unsigned char vmstime_onehour[] = {0x00,0x98,0x3b,0x9e,0xf7,0xff,0xff,0xff}; static const unsigned char vmstime_oneminute[] = {0x00,0xba,0x3c,0xdc,0xff,0xff,0xff,0xff}; static const unsigned char vmstime_onesecond[] = {0x80,0x69,0x67,0xff,0xff,0xff,0xff,0xff}; /* lib_cvt_to_internal_time() converts a time field to a time value */ unsigned lib_cvt_to_internal_time(unsigned *operation,int *input, pVMSTIME result) { unsigned const char *ptr; if (*input < 1) return LIB__IVTIME; switch (*operation) { case LIB$K_DELTA_WEEKS: ptr = vmstime_oneweek; break; case LIB$K_DELTA_DAYS: ptr = vmstime_oneday; break; case LIB$K_DELTA_HOURS: ptr = vmstime_onehour; break; case LIB$K_DELTA_MINUTES: ptr = vmstime_oneminute; break; case LIB$K_DELTA_SECONDS: ptr = vmstime_onesecond; break; default: return LIB__INVOPER; } memcpy(result,ptr,sizeof(VMSTIME)); return lib_mult_delta_time(input,result); } /********************************************************** vmstime_from_nt() */ /* Difference between VMS and NT is 94187 days.... */ static const unsigned char vmstime_nt_offset[] = {0x00,0xc0,0xac,0x76,0x88,0xe3,0xde,0xfe}; /* vmstime_from_nt() convert Windows NT time to vmstime */ unsigned vmstime_from_nt(pVMSTIME nt_time,pVMSTIME vms_time) { if (ISDELTA(nt_time)) return LIB__IVTIME; return lib_sub_times(nt_time,(pVMSTIME) vmstime_nt_offset,vms_time); } /************************************************************ vmstime_to_nt() */ /* vmstime_to_nt() convert vmstime to Windows NT time */ unsigned vmstime_to_nt(pVMSTIME vms_time,pVMSTIME nt_time) { if (ISDELTA(vms_time)) return LIB__IVTIME; return lib_add_times(vms_time,(pVMSTIME) vmstime_nt_offset,nt_time); }