Timothe Litt 886c1fae06 Preliminary merge with Baker + other changes
Many style/formatting edits.

Bug fixes.

Reverted some previous changes temporarily while reviewing new code.

Merged Baker's "virtual device" in a simpler form.  ODS2 will assign a sensible
drive name when mounting /image (== /virtual).  If a specific drive name
is desired, mount /image drivename=filespec.

Files can be quoted, or use set qualifier_style unix if slashes are a problem.
Note that mount on the command line allows tab completion.

Moved "statistics" command into show.

Coded support for import/binary (fixed records, 512 bytes).

Converted fgets to fgetline

Added show devices for Unix (limited by standard APIs)

Got rid of separate ODS2-Image build.
2016-03-05 01:27:56 -05:00

1122 lines
35 KiB
C

/*
Vmstime.c V2.1
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 arihmetic 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.
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h> /* Use windows routines to get currrent time */
#else
#ifndef NO_LOCALTIME
#if defined(VMS)
#include <timeb.h> /* For VAXC and GCC include libraries on VMS */
#else
#include <sys/timeb.h> /* For ftime() */
#endif
#endif
#endif
#include "vmstime.h" /* Our header file! */
#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 unsigned 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 timeb timval;
struct tm *lclptr;
unsigned short timvec[7];
timval.millitm = 0; /* for broken versions of ftime() */
ftime(&timval);
lclptr = localtime(&timval.time);
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;
timvec[6] = timval.millitm / 10;
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 unsigned 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 unsigned 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 unsigned 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;
/* 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 unsigned 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 unsigned 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 = (endptr - chrptr)) > 5) count = 5;
memcpy(chrptr,vmstime_months + ((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 = (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 unsigned 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 unsigned 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);
}