/* C-Kermit C RTL replacement functions for VMS systems.*//*---------------------------------------------------------------------- * * utime() * * VMS C RTL before V7.3 lacks utime(). In V7.3, utime() sets only * the modified (revised) date, not the created date of a file. * * UNIX "ls -l" reports the modified time. VMS "DIRECTORY /DATE" * reports the creation time. Reconciling these in FTP DIR reports * is non-trivial. * * UNIX utime() sets revision and access times. VMS does not always * maintain access times, so this utime() replacement sets the * creation and revision times to the specified revision (or * creation?) time. Any access time is ignored. * *---------------------------------------------------------------------- */#if __CRTL_VER >= 70300000/* Avoid "%CC-W-EMPTYFILE, Source file does not contain any declarations." */int dummy_function(void);#else /* __CRTL_VER < 70300000 */#include #include #include #include #include #include #include #include #include #include #include #include #include "ckvrtl.h"/* Use if available. Otherwise declare IOSB here. */#if !defined( __VAX) && (__CRTL_VER >= 70000000)#include #else /* __CRTL_VER >= 70000000 */typedef struct _iosb { unsigned short int iosb$w_status; /* Final I/O status */ unsigned short int iosb$w_bcnt; /* 16-bit byte count */ unsigned int iosb$l_dev_depend; /* 32-bit dev dependent */ } IOSB;#endif /* !defined( __VAX) && (__CRTL_VER >= 70000000) *//* Ugly work-around for bad type in VAX . */#ifdef __VAX#define UWA (unsigned int)#else /* def __VAX */#define UWA#endif /* def __VAX *//* Private utime() code. *//* Use long name (NAML) structure only where available. (This should be non-VAX with __CRTL_VER >= 70200000.)*/#ifdef NAML$C_BID/* Use long name (NAML) structure. */#define FAB$L_NAMX fab$l_naml#define NAMX NAML#define NAMX$C_MAXRSS NAML$C_MAXRSS#define NAMX$B_DEV naml$l_long_dev_size#define NAMX$L_DEV naml$l_long_dev#define NAMX$L_ESA naml$l_long_expand#define NAMX$B_ESL naml$l_long_expand_size#define NAMX$B_ESS naml$l_long_expand_alloc#define NAMX$W_FID naml$w_fid#define NAMX$L_RSA naml$l_long_result#define NAMX$B_RSL naml$l_long_result_size#define NAMX$B_RSS naml$l_long_result_alloc#define CC$RMS_NAMX cc$rms_naml#else /* def NAML$C_BID *//* Use short name (NAM) structure. */#define FAB$L_NAMX fab$l_nam#define NAMX NAM#define NAMX$C_MAXRSS NAM$C_MAXRSS#define NAMX$B_DEV nam$b_dev#define NAMX$L_DEV nam$l_dev#define NAMX$L_ESA nam$l_esa#define NAMX$B_ESL nam$b_esl#define NAMX$B_ESS nam$b_ess#define NAMX$W_FID nam$w_fid#define NAMX$L_RSA nam$l_rsa#define NAMX$B_RSL nam$b_rsl#define NAMX$B_RSS nam$b_rss#define CC$RMS_NAMX cc$rms_nam#endif /* def NAML$C_BID *//*--------------------------------------------------------------------*//* Private utime() code. *//* Action routine for decc$to_vms(), in utime(). */char vms_path[ NAMX$C_MAXRSS+ 1];int set_vms_name( char *name, int type){ strncpy( vms_path, name, NAMX$C_MAXRSS); vms_path[ NAMX$C_MAXRSS] = '\0'; return 1;}/*--------------------------------------------------------------------*//* utime() replacement. */int vms_utime( const char *path, const struct utimbuf *times){time_t utc_unsigned;int chan, i;int sts, sts2;unsigned short int vms_num_vec_time[ 7];unsigned int vms_abs_time[ 2];struct tm *tms;struct _iosb iosb_q;/* QIOW item list used to set creation and revision dates. */struct atrdef ut_atr[ 3] = { {sizeof( vms_abs_time), ATR$C_CREDATE, UWA vms_abs_time}, {sizeof( vms_abs_time), ATR$C_REVDATE, UWA vms_abs_time}, {0,0,0}};/* Various RMS structures used for file access. */struct FAB ut_fab = cc$rms_fab;struct RAB ut_rab = cc$rms_rab;struct NAMX ut_namx = CC$RMS_NAMX;static struct fibdef ut_fib;/* Device and file name buffers and their descriptors. */static char dev_namx[ NAMX$C_MAXRSS+ 1];char esa_namx[ NAMX$C_MAXRSS+ 1];char rsa_namx[ NAMX$C_MAXRSS+ 1];struct dsc$descriptor dev_dsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, dev_namx};struct dsc$descriptor fib_dsc = {sizeof( ut_fib), DSC$K_DTYPE_T, DSC$K_CLASS_S, (char *) &ut_fib};/* We will accept either a UNIX-like path name or a VMS-like path name. If a slash is found in the name, assume that it's UNIX-like, and convert it to VMS form. Otherwise, use it as-is.*/if (strchr( path, '/') != NULL) { sts = decc$to_vms( path, set_vms_name, 0, 0); path = vms_path; }/* Install the VMS file specification into the FAB. */ut_fab.fab$l_fna = (char *) path;ut_fab.fab$b_fns = (unsigned char) strlen( path);ut_fab.fab$l_dna = "";ut_fab.fab$b_dns = 0;/* Point the FAB to the NAMX. */ut_fab.FAB$L_NAMX = &ut_namx;/* Install the name buffers into the NAM. */ut_namx.NAMX$L_ESA = esa_namx;ut_namx.NAMX$B_ESL = 0;ut_namx.NAMX$B_ESS = sizeof( esa_namx)- 1;ut_namx.NAMX$L_RSA = rsa_namx;ut_namx.NAMX$B_RSL = 0;ut_namx.NAMX$B_RSS = sizeof( rsa_namx)- 1;/* Convert the modification time (UTC time_t) to local "tm" time. */tms = localtime( &(times-> modtime));/* Move (translate) "tm" structure local time to VMS vector time. */if (tms != NULL) { vms_num_vec_time[ 0] = tms-> tm_year+ 1900; vms_num_vec_time[ 1] = tms-> tm_mon+ 1; vms_num_vec_time[ 2] = tms-> tm_mday; vms_num_vec_time[ 3] = tms-> tm_hour; vms_num_vec_time[ 4] = tms-> tm_min; vms_num_vec_time[ 5] = tms-> tm_sec; vms_num_vec_time[ 6] = 0; /* centiseconds *//* Convert VMS vector time to VMS absolute time (quadword). */ sts = lib$cvt_vectim( vms_num_vec_time, vms_abs_time); if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) {/* Parse the file specification. */ sts = sys$parse( &ut_fab, 0, 0); if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) {/* Locate the file. (Gets the FID.) */ sts = sys$search( &ut_fab, 0, 0); if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) {/* Form the device name descriptor. */ dev_dsc.dsc$w_length = ut_namx.NAMX$B_DEV; dev_dsc.dsc$a_pointer = (char *) ut_namx.NAMX$L_DEV;/* Assign a channel to the disk device. */ sts = sys$assign( &dev_dsc, &chan, 0, 0); if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) {/* Move the FID (and not the DID) into the FIB. */ memset( (void *) &ut_fib, 0, sizeof( ut_fib)); for (i = 0; i < 3; i++) { ut_fib.fib$w_fid[ i] = ut_namx.NAMX$W_FID[ i]; ut_fib.fib$w_did[ i] = 0; }/* Prevent this QIOW from setting the revision time to now. */ ut_fib.fib$l_acctl = FIB$M_NORECORD;/* Set the file dates. */ sts = sys$qiow( 0, chan, IO$_MODIFY, &iosb_q, 0, 0, &fib_dsc, 0, 0, 0, ut_atr, 0); if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) { sts = iosb_q.iosb$w_status; } sts2 = sys$dassgn( chan); if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) { sts = sts2; } } } } } }/* Convert successful VMS status to zero = success status. If failure, set errno and vaxc$errno, and return -1 = failure status.*/if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS) { sts = 0; }else { errno = EVMSERR; vaxc$errno = sts; sts = -1; }return sts;}#endif /* __CRTL_VER >= 70300000 [else] *//**********************************************************************/#if !defined( __VAX) && (__CRTL_VER >= 70301000)#include #include /* Flag to sense if vms_init() was called. (Handy for debug.) */int vms_init_done = -1;/* vms_init() Uses LIB$INITIALIZE to set a collection of C RTL features without requiring the user to define the corresponding logical names.*//* Structure to hold a DECC$* feature name and its desired value. */typedef struct { char *name; int value; } decc_feat_t;/* Array of DECC$* feature names and their desired values. */decc_feat_t decc_feat_array[] = { /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */ { "DECC$ARGV_PARSE_STYLE", 1 }, /* Preserve case for file names on ODS5 disks. */ { "DECC$EFS_CASE_PRESERVE", 1 }, /* Enable multiple dots (and most characters) in ODS5 file names, while preserving VMS-ness of ";version". */ { "DECC$EFS_CHARSET", 1 }, /* List terminator. */ { (char *)NULL, 0 } };/* LIB$INITIALIZE initialization function. */static void vms_init( void){int feat_index;int feat_value;int feat_value_max;int feat_value_min;int i;int sts;/* Set the global flag to indicate that LIB$INITIALIZE worked. */vms_init_done = 1;/* Loop through all items in the decc_feat_array[]. */for (i = 0; decc_feat_array[ i].name != NULL; i++) { /* Get the feature index. */ feat_index = decc$feature_get_index( decc_feat_array[ i].name); if (feat_index >= 0) { /* Valid item. Collect its properties. */ feat_value = decc$feature_get_value( feat_index, 1); feat_value_min = decc$feature_get_value( feat_index, 2); feat_value_max = decc$feature_get_value( feat_index, 3); if ((decc_feat_array[ i].value >= feat_value_min) && (decc_feat_array[ i].value <= feat_value_max)) { /* Valid value. Set it if necessary. */ if (feat_value != decc_feat_array[ i].value) { sts = decc$feature_set_value( feat_index, 1, decc_feat_array[ i].value); } } else { /* Invalid DECC feature value. */ printf( " INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n", feat_value, feat_value_min, decc_feat_array[ i].name, feat_value_max); } } else { /* Invalid DECC feature name. */ printf( " UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[ i].name); } }}/* Get "vms_init()" into a valid, loaded LIB$INITIALIZE PSECT. */#pragma nostandard/* Establish the LIB$INITIALIZE PSECTs, with proper alignment and other attributes. Note that "nopic" is significant only on VAX.*/#pragma extern_model save#pragma extern_model strict_refdef "LIB$INITIALIZE" 2, nopic, nowrtvoid (*const x_vms_init)() = vms_init;#pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrtconst int spare[ 8] = { 0 };#pragma extern_model restore/* Fake reference to ensure loading the LIB$INITIALIZE PSECT. */#pragma extern_model saveint LIB$INITIALIZE(void);#pragma extern_model strict_refdefint dmy_lib$initialize = (int) LIB$INITIALIZE;#pragma extern_model restore#pragma standard#endif /* !defined( __VAX) && (__CRTL_VER >= 70301000) */