mirror of
https://github.com/open-simh/simtools.git
synced 2026-01-25 11:46:44 +00:00
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.
1122 lines
35 KiB
C
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);
|
|
}
|