/*- ****************************************************************************** ****************************************************************************** ** ** ARCHIVE HEADER INFORMATION ** ** @C-file{ ** FILENAME = "vaxvms.c", ** VERSION = "1.00", ** DATE = "", ** TIME = "", ** ** AUTHOR = "Niel Kempson", ** ADDRESS = "25 Whitethorn Drive, Cheltenham, GL52 5LL, England", ** TELEPHONE = "+44-242 579105", ** EMAIL = "kempson@tex.ac.uk (Internet)", ** ** SUPPORTED = "yes", ** ARCHIVED = "tex.ac.uk, ftp.tex.ac.uk", ** KEYWORDS = "VVcode", ** ** CODETABLE = "ISO/ASCII", ** CHECKSUM = "51492 1481 5732 57976", ** ** DOCSTRING = { This file is part of VVcode. ** } ** } ** ** MODULE CONTENTS ** ** apply_defaults - Apply default file name and extension to a ** full file specification if either of these ** components is missing. ** confirm_yesno - Display a message to the user and wait for a ** yes/no answer. ** examine_file - Examine a file and determine its key features, ** including mode, format, record length and ** timestamp. ** explain_error - Explain the reason for an error. ** f_open_in - Open a file for input using the appropriate ** mode, format etc for the file. ** f_open_out - Open a file for output using the appropriate ** mode, format etc for the file. ** file_exists - Determine whether a file exists. ** force_file_ext - Force the file extension of a full file ** specification to a specified value. ** is_a_file - Determine whether a file stream is connected ** to a real file rather than a character ** device, pipe etc. ** legal_filespec - Takes an arbitrary string which may a file ** specification from another operating system ** and manipulates it to produce a legal file ** specification for the current operating ** system. ** make_filespec - Construct a full file specification from ** component parts. ** prompt_for_string - Present a prompt string and accept a string ** from the user. ** read_bytes - Read bytes from a currently open file. ** read_line - Read a line from a currently open (text) file. ** read_record - Read a record from a currently open file. ** scan_cmd_line - [tbs] ** set_ftime - Set the timestamp of a file to a specified ** value. ** set_pipe_mode - Set the mode of a file stream connected to a ** pipe, character device, redirected ** stdin/stdout/stderr, in fact any non-file. ** split_file_spec - Split a full file specification into its ** component parts. ** tz_offset - Determine the offset of local time from ** Greenwich Mean Time (Coordinated Universal ** Time) at a specified date and time. ** user_message - Present a message to the user. ** vv_exit - Exit the program, returning the appropriate ** status to the operating system. ** write_bytes - Write bytes to a currently open file. ** write_record - Write a record to a currently open file. ** ** COPYRIGHT ** ** Copyright (c) 1991-1993 by Niel Kempson ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License as ** published by the Free Software Foundation; either version 1, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ** In other words, you are welcome to use, share and improve this ** program. You are forbidden to forbid anyone else to use, share ** and improve what you give them. Help stamp out software-hoarding! ** ** CHANGE LOG ** ****************************************************************************** ****************************************************************************** */ static char rcsid[] = "$Id$"; /*- **---------------------------------------------------------------------------- ** Standard include files **---------------------------------------------------------------------------- */ #include /*- **---------------------------------------------------------------------------- ** Include files **---------------------------------------------------------------------------- */ #include "checkos.h" #include "machine.h" #include "local.h" #include "globals.h" #include "specific.h" #include "vvutils.h" /*- **---------------------------------------------------------------------------- ** VAX/VMS specific include files **---------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include /*- **---------------------------------------------------------------------------- ** VAX/VMS specific data types **---------------------------------------------------------------------------- */ struct utimbuf { TIME_T actime; TIME_T modtime; }; struct acb_struct { unsigned short w_size; unsigned short w_type; void *l_addr; }; typedef struct dsc$descriptor_s String_Desc; static char *month_list[] = {"???", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC", NULL}; #define DUMMY_VMS_TIMESTAMP "15-FEB-1991 16:22:12.47" #define VMS_TIMESTAMP_FORMAT "%02d-%3s-%04d %02d:%02d:%02d.%02d" /*- **---------------------------------------------------------------------------- ** VAX/VMS specific functions **---------------------------------------------------------------------------- */ Int32 CLI$PRESENT ARGS ((String_Desc * qualifier)); Int32 CLI$GET_VALUE ARGS ((String_Desc * qualifier, String_Desc * result, short *length)); static void parse_qualifier ARGS ((Qualifier_Struct *qual_struct)); static void FABFIBNAM_setup ARGS ((CONST char *file_spec, CONST char *def_file_spec, unsigned short *chan_ptr, struct FAB *fab_ptr, struct fibdef *fib_ptr, struct NAM *nam_ptr, char *esa, char *rsa)); char *vms_to_vv_timestamp ARGS ((CONST char *vms_time_str)); char *vv_to_vms_timestamp ARGS ((CONST char *vv_time_str)); static Int32 vax_utime ARGS ((CONST char *file_spec, CONST struct utimbuf * utime_struct)); Unsigned32 *unix_to_vms_time ARGS ((CONST TIME_T unix_time)); /*- **============================================================================ ** ** FUNCTION ** ** apply_defaults ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) void apply_defaults (CONST char *default_name, CONST char *default_ext, char *full_spec) #else /* NOT (ANSI_SYNTAX) */ void apply_defaults (default_name, default_ext, full_spec) CONST char *default_name; CONST char *default_ext; char *full_spec; #endif /* (ANSI_SYNTAX) */ { char name[MAX_NAME + 1]; char extension[MAX_EXT + 1]; Unsigned16 path_parts; char preamble[MAX_PREAMBLE + 1]; path_parts = split_file_spec (full_spec, preamble, name, extension, NULL); if (((path_parts & FS_NAME) == 0) && (default_name != NULL)) { strncpy (name, default_name, MAX_NAME); } if (((path_parts & FS_EXTENSION) == 0) && (default_ext != NULL)) { strncpy (extension, default_ext, MAX_EXT); } make_file_spec (preamble, name, extension, NULL, full_spec); } /* apply_defaults */ /*- **============================================================================ ** ** FUNCTION ** ** confirm_yesno ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) Boolean confirm_yesno (CONST char *confirm_str) #else /* NOT (ANSI_SYNTAX) */ Boolean confirm_yesno (confirm_str) CONST char *confirm_str; #endif /* (ANSI_SYNTAX) */ { int answer; FPRINTF (stderr, "\n%s [Y/N]: ", confirm_str); fflush (stderr); do { answer = getchar (); if (answer == EOF) { ERRORMSG ("EOF detected on standard input"); answer = 'N'; } else { answer = TOUPPER (answer); } } while (!((answer == 'N') || (answer == 'Y'))); return ((answer == 'Y') ? (Boolean) TRUE : (Boolean) FALSE); } /* confirm_yesno */ /*- **============================================================================ ** ** FUNCTION ** ** examine_file ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #define EX_SAMPLE_SIZE 512 #if (ANSI_SYNTAX) void examine_file (File_Info *ex_file) #else /* NOT (ANSI_SYNTAX) */ void examine_file (ex_file) File_Info *ex_file; #endif /* (ANSI_SYNTAX) */ { char tmp_buffer[EX_SAMPLE_SIZE]; int bytes_read; int eol_count; int i; struct stat stat_buffer; int status; /*- **------------------------------------------------------------------------ ** Initialize the File_Info structure before starting work. If the input ** file is not a real file (i.e. a device or pipe), these are the values ** that will be returned. **------------------------------------------------------------------------ */ ex_file->mode = INV_MODE; ex_file->format = INV_FORMAT; ex_file->max_rec_len = INV_RECORD_LEN; ex_file->lng_rec_len = INV_RECORD_LEN; ex_file->mod_time = INV_TIMESTAMP; /*- **---------------------------------------------------------------------------- ** VMS RECORD FORMATS ** ~~~~~~~~~~~~~~~~~~ ** RFM_UDF undefined (also stream binary) ** S RFM_FIX fixed length records ** S RFM_VAR variable length records ** RFM_VFC variable fixed control ** RFM_STM RMS-11 stream (valid only for sequential organization) ** S RFM_STMLF LF stream (valid only for sequential organization) ** RFM_STMCR CR stream (valid only for sequential organization) ** ** VMS RECORD ATTRIBUTES ** ~~~~~~~~~~~~~~~~~~~~~ ** S RAT_FTN FORTRAN or none ** S RAT_CR CR ** RAT_PRN print ** RAT_BLK block **---------------------------------------------------------------------------- */ #define RFM_UDF 0 #define RFM_FIX 1 #define RFM_VAR 2 #define RFM_VFC 3 #define RFM_STM 4 #define RFM_STMLF 5 #define RFM_STMCR 6 #define RAT_FTN 0 #define RAT_CR 1 #define RAT_PRN 2 #define RAT_BLK 3 /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ ex_file->file_ptr = fopen (ex_file->file_spec, "rb"); if (ex_file->file_ptr == (FILE *) NULL) { ERRORMSG_1 ("couldn't examine (open) file `%s'", ex_file->file_spec); explain_error (); return; } /*- **------------------------------------------------------------------------ ** Test to see if the file is 'real'. **------------------------------------------------------------------------ */ if (is_a_file (ex_file) == FALSE) { DEBUG_1 ("examine_file: `%s' is not a regular file", ex_file->file_spec); f_close (ex_file); ex_file->pipe_flag = TRUE; ex_file->file_ptr = (FILE *) NULL; return; } f_close (ex_file); /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ status = stat (ex_file->file_spec, &stat_buffer); if (status != 0) { ERRORMSG_1 ("couldn't examine (stat) file `%s'", ex_file->file_spec); explain_error (); return; } ex_file->mod_time = stat_buffer.st_ctime; /*- **------------------------------------------------------------------------ ** Use the record attributes to determine whether the file is binary or ** text. **------------------------------------------------------------------------ */ switch (stat_buffer.st_fab_rat) { case RAT_CR: case RAT_PRN: ex_file->mode = MODE_TEXT; break; case RAT_FTN: case RAT_BLK: ex_file->mode = MODE_BINARY; break; default: WARNMSG_2 ("file `%s' has an unsupported record attribute: %X", ex_file->file_spec, (int) stat_buffer.st_fab_rfm); break; } /*- **------------------------------------------------------------------------ ** Use the record format to determine the file format. We support fixed, ** variable and stream_lf files. **------------------------------------------------------------------------ */ switch (stat_buffer.st_fab_rfm) { case RFM_FIX: ex_file->format = FMT_FIXED; break; case RFM_VAR: case RFM_VFC: ex_file->format = FMT_VARIABLE; break; case RFM_STM: case RFM_STMLF: case RFM_STMCR: ex_file->format = FMT_STREAM; break; case RFM_UDF: default: WARNMSG_2 ("file `%s' has an unsupported record format: %X", ex_file->file_spec, (int) stat_buffer.st_fab_rfm); break; } /*- **------------------------------------------------------------------------ ** If the file is fixed or variable format, determine the record length. **------------------------------------------------------------------------ */ if ((ex_file->format == FMT_FIXED) || (ex_file->format == FMT_VARIABLE)) { ex_file->max_rec_len = stat_buffer.st_fab_mrs; } return; } /* examine_file */ /*- **============================================================================ ** ** FUNCTION ** ** explain_error ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) void explain_error (void) #else /* NOT (ANSI_SYNTAX) */ void explain_error () #endif /* (ANSI_SYNTAX) */ { INFOMSG_1 ("reason for error: %s", strerror (errno)); } /* _error */ /*- **============================================================================ ** ** FUNCTION ** ** f_open_in ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) FILE *f_open_in (File_Info *ip_file) #else /* NOT (ANSI_SYNTAX) */ FILE *f_open_in (ip_file) File_Info *ip_file; #endif /* (ANSI_SYNTAX) */ { FILE *file_ptr; char mrs_str[16]; /* "mrs = XXXXXX" */ char bls_str[16]; /* "bls = XXXXXX" */ /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ switch (ip_file->mode) { case MODE_BINARY: case MODE_TEXT: break; default: ERRORMSG_1 ("invalid I/P file mode specified: %X", ip_file->mode); return ((FILE *) NULL); } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ switch (ip_file->format) { /*- **-------------------------------------------------------------------- ** **-------------------------------------------------------------------- */ case FMT_FIXED: if (ip_file->max_rec_len == INV_RECORD_LEN) { ip_file->max_rec_len = DEF_FIXED_RECORD_LEN; } if ((ip_file->max_rec_len < MIN_FIXED_RECORD_LEN) || (ip_file->max_rec_len > MAX_FIXED_RECORD_LEN)) { ERRORMSG_2 ("I/P file `%s' has invalid max fixed record \ length specified: %ld", ip_file->file_spec, ip_file->max_rec_len); return ((FILE *) NULL); } SPRINTF (mrs_str, "mrs = %8ld", ip_file->max_rec_len); SPRINTF (bls_str, "bls = %8ld", ip_file->max_rec_len); switch (ip_file->mode) { case MODE_BINARY: file_ptr = fopen (ip_file->file_spec, "rb", "rfm=fix", "mbc=64", mrs_str, bls_str); break; case MODE_TEXT: file_ptr = fopen (ip_file->file_spec, "r", "rfm=fix", "mbc=64", mrs_str, bls_str); break; } break; /*- **-------------------------------------------------------------------- ** **-------------------------------------------------------------------- */ case FMT_STREAM: switch (ip_file->mode) { case MODE_BINARY: file_ptr = fopen (ip_file->file_spec, "rb", "ctx=stm", "mbc=64"); break; case MODE_TEXT: file_ptr = fopen (ip_file->file_spec, "r", "ctx=stm", "mbc=64"); break; } break; case FMT_VARIABLE: if (ip_file->max_rec_len == INV_RECORD_LEN) { ip_file->max_rec_len = DEF_VARIABLE_RECORD_LEN; } if ((ip_file->max_rec_len < MIN_VARIABLE_RECORD_LEN) || (ip_file->max_rec_len > MAX_VARIABLE_RECORD_LEN)) { ERRORMSG_2 ("I/P file `%s' has invalid max variable record \ length specified: %ld", ip_file->file_spec, ip_file->max_rec_len); return ((FILE *) NULL); } SPRINTF (mrs_str, "mrs = %8ld", ip_file->max_rec_len); switch (ip_file->mode) { case MODE_BINARY: file_ptr = fopen (ip_file->file_spec, "rb", "rfm=var", "ctx=bin", "mbc=64"); break; case MODE_TEXT: file_ptr = fopen (ip_file->file_spec, "r", "rfm=var", "rat=cr", "mbc=64"); break; } break; /*- **-------------------------------------------------------------------- ** **-------------------------------------------------------------------- */ default: ERRORMSG_1 ("invalid I/P file format specified: %X", ip_file->format); return ((FILE *) NULL); break; } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ if (file_ptr == (FILE *) NULL) { ERRORMSG_1 ("error opening file `%s' for input", ip_file->file_spec); explain_error (); return ((FILE *) NULL); } return (file_ptr); } /* f_open_in */ /*- **============================================================================ ** ** FUNCTION ** ** f_open_out ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) FILE *f_open_out (CONST Int16 overwrite_files, File_Info *op_file) #else /* NOT (ANSI_SYNTAX) */ FILE *f_open_out (overwrite_files, op_file) CONST Int16 overwrite_files; File_Info *op_file; #endif /* (ANSI_SYNTAX) */ { FILE *file_ptr; char mrs_str[16]; /* "mrs = XXXXXX" */ char bls_str[16]; /* "bls = XXXXXX" */ /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ if ((overwrite_files != OVERWRITE_YES) && (file_exists (op_file->file_spec))) { if (overwrite_files == OVERWRITE_ASK) { SPRINTF (G_tmp_msg, "File `%s' exists. Overwrite ?", op_file->file_spec); if (!confirm_yesno (G_tmp_msg)) { INFOMSG ("operation cancelled"); return ((FILE *) NULL); } } else { ERRORMSG_1 ("file `%s' exists", op_file->file_spec); return ((FILE *) NULL); } } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ switch (op_file->mode) { case MODE_BINARY: case MODE_TEXT: break; default: ERRORMSG_1 ("invalid O/P file mode specified: %X", op_file->mode); return ((FILE *) NULL); } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ switch (op_file->format) { /*- **-------------------------------------------------------------------- ** **-------------------------------------------------------------------- */ case FMT_FIXED: if (op_file->max_rec_len == INV_RECORD_LEN) { op_file->max_rec_len = DEF_FIXED_RECORD_LEN; } if ((op_file->max_rec_len < MIN_FIXED_RECORD_LEN) || (op_file->max_rec_len > MAX_FIXED_RECORD_LEN)) { ERRORMSG_2 ("O/P file `%s' has invalid max fixed record \ length specified: %ld", op_file->file_spec, op_file->max_rec_len); return ((FILE *) NULL); } SPRINTF (mrs_str, "mrs = %8ld", op_file->max_rec_len); SPRINTF (bls_str, "bls = %8ld", op_file->max_rec_len); switch (op_file->mode) { case MODE_BINARY: file_ptr = fopen (op_file->file_spec, "wb", "rfm=fix", "mbc=64", mrs_str, bls_str); break; case MODE_TEXT: file_ptr = fopen (op_file->file_spec, "w", "rfm=fix", "mbc=64", mrs_str, bls_str); break; } break; /*- **-------------------------------------------------------------------- ** **-------------------------------------------------------------------- */ case FMT_STREAM: switch (op_file->mode) { case MODE_BINARY: file_ptr = fopen (op_file->file_spec, "wb", "ctx=stm", "mbc=64"); break; case MODE_TEXT: file_ptr = fopen (op_file->file_spec, "w", "ctx=stm", "mbc=64"); break; } break; case FMT_VARIABLE: if (op_file->max_rec_len == INV_RECORD_LEN) { op_file->max_rec_len = DEF_VARIABLE_RECORD_LEN; } if ((op_file->max_rec_len < MIN_VARIABLE_RECORD_LEN) || (op_file->max_rec_len > MAX_VARIABLE_RECORD_LEN)) { ERRORMSG_2 ("O/P file `%s' has invalid max variable record \ length specified: %ld", op_file->file_spec, op_file->max_rec_len); return ((FILE *) NULL); } SPRINTF (mrs_str, "mrs = %8ld", op_file->max_rec_len); switch (op_file->mode) { case MODE_BINARY: file_ptr = fopen (op_file->file_spec, "wb", "rfm=var", mrs_str, "ctx=bin", "mbc=64"); break; case MODE_TEXT: file_ptr = fopen (op_file->file_spec, "w", "rfm=var", mrs_str, "rat=cr", "mbc=64"); break; } break; /*- **-------------------------------------------------------------------- ** **-------------------------------------------------------------------- */ default: ERRORMSG_1 ("invalid O/P file format specified: %X", op_file->format); return ((FILE *) NULL); break; } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ if (file_ptr == (FILE *) NULL) { ERRORMSG_1 ("error opening file `%s' for output", op_file->file_spec); explain_error (); return ((FILE *) NULL); } return (file_ptr); } /* f_open_out */ /*- **============================================================================ ** ** FUNCTION ** ** file_exists ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) Boolean file_exists (CONST char *file_spec) #else /* NOT (ANSI_SYNTAX) */ Boolean file_exists (file_spec) CONST char *file_spec; #endif /* (ANSI_SYNTAX) */ { return ((Boolean) (access ((char *) file_spec, 0) == 0)); } /* file_exists */ /*- **============================================================================ ** ** FUNCTION ** ** force_file_ext ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) void force_file_ext (CONST char *forced_ext, char *full_spec) #else /* NOT (ANSI_SYNTAX) */ void force_file_ext (forced_ext, full_spec) CONST char *forced_ext; char *full_spec; #endif /* (ANSI_SYNTAX) */ { char name[MAX_NAME + 1]; char preamble[MAX_PREAMBLE + 1]; if (forced_ext == NULL) { return; } (void) split_file_spec (full_spec, preamble, name, NULL, NULL); make_file_spec (preamble, name, forced_ext, NULL, full_spec); } /* force_file_ext */ /*- **============================================================================ ** ** FUNCTION ** ** is_a_file ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) Boolean is_a_file (CONST File_Info *ex_file) #else /* NOT (ANSI_SYNTAX) */ Boolean is_a_file (ex_file) CONST File_Info *ex_file; #endif /* (ANSI_SYNTAX) */ { int file_handle; file_handle = fileno (ex_file->file_ptr); if ((isatty (file_handle) == 1) || (isapipe (file_handle) == 1)) { return (FALSE); } else { return (TRUE); } } /* is_a_file */ /*- **============================================================================ ** ** FUNCTION ** ** legal_filespec ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) char *legal_filespec (CONST char *hdrf_spec) #else /* NOT (ANSI_SYNTAX) */ char *legal_filespec (hdrf_spec) CONST char *hdrf_spec; #endif /* (ANSI_SYNTAX) */ { char tmpf_name[MAX_NAME + 1]; char tmpf_ext[MAX_EXT + 1]; char *tmpf_spec; char *tmp_ptr; static char opf_spec[MAX_PATH + 1]; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ tmpf_spec = STRDUP (hdrf_spec); tmp_ptr = STRCHR (tmpf_spec, '.'); if (tmp_ptr != NULL) { strncpy (tmpf_ext, tmp_ptr, MAX_EXT); tmpf_ext[MAX_EXT] = '\0'; *tmp_ptr = '\0'; } else { strcpy (tmpf_ext, ""); } strncpy (tmpf_name, tmpf_spec, MAX_NAME); tmpf_name[MAX_NAME] = '\0'; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ for (tmp_ptr = tmpf_name; *tmp_ptr != '\0'; tmp_ptr++) { if (STRCHR (LEGAL_FILESPEC_CHARS, *tmp_ptr) == NULL) { *tmp_ptr = REPLACEMENT_FILESPEC_CHAR; } } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ for (tmp_ptr = tmpf_ext + 1; *tmp_ptr != '\0'; tmp_ptr++) { if (STRCHR (LEGAL_FILESPEC_CHARS, *tmp_ptr) == NULL) { *tmp_ptr = REPLACEMENT_FILESPEC_CHAR; } } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ strcpy (opf_spec, tmpf_name); strcat (opf_spec, tmpf_ext); if (strcmp (hdrf_spec, opf_spec) != 0) { WARNMSG_2 ("suspicious header file spec `%s' changed to `%s'", hdrf_spec, opf_spec); } return (opf_spec); } /* legal_filespec */ /*- **============================================================================ ** ** FUNCTION ** ** make_file_spec ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) void make_file_spec (CONST char *preamble, CONST char *name, CONST char *extension, CONST char *postamble, char *full_spec) #else /* NOT (ANSI_SYNTAX) */ void make_file_spec (preamble, name, extension, postamble, full_spec) CONST char *preamble; CONST char *name; CONST char *extension; CONST char *postamble; char *full_spec; #endif /* (ANSI_SYNTAX) */ { int len; char *tmp_ptr; /*- **------------------------------------------------------------------------ ** Start with an empty string and append components of the file ** specification only if they exist. **------------------------------------------------------------------------ */ strcpy (full_spec, ""); /*- **------------------------------------------------------------------------ ** The preamble component corresponds to the VAX/VMS node, device, ** directory and/or logical name components in the form: ** ** node:: ** node::device:[dir1.dir2] ** node::device: ** logical_name: ** ** If the preamble component does not end in ']', '>' or ':', we assume ** that it is a logical name and ':' is appended only if the component ** is not empty. **------------------------------------------------------------------------ */ if ((preamble != NULL) && (*preamble != '\0')) { strncat (full_spec, preamble, MAX_PREAMBLE); len = strlen (preamble); tmp_ptr = STRCHR ("]>:", preamble[len - 1]); if ((tmp_ptr == NULL) && (len < MAX_PREAMBLE)) { strcat (full_spec, ":"); } } /*- **------------------------------------------------------------------------ ** Simply append the name if it is present. **------------------------------------------------------------------------ */ if (name != NULL) { strncat (full_spec, name, MAX_NAME); } /*- **------------------------------------------------------------------------ ** If the extension component does not begin with '.', prepend '.' before ** appending the extension to the file specification. **------------------------------------------------------------------------ */ if ((extension != NULL) && (*extension != '\0')) { if (*extension != '.') { strcat (full_spec, "."); strncat (full_spec, extension, MAX_EXT - 1); } else { strncat (full_spec, extension, MAX_EXT); } } /*- **------------------------------------------------------------------------ ** The postamble component of a VAX/VMS file specification is the version ** number of the file and is introduced with ';' or unusually '.': ** ** node::device:[dir1.dir2]name.extension;version ** node::device:[dir1.dir2]name.extension.version ** ** The postamble component must be an integer in the range +/- 65535. ** ** If the postamble component does not begin with ';', prepend ';' before ** appending the postamble to the file specification. **------------------------------------------------------------------------ */ if ((postamble != NULL) && (*postamble != '\0')) { if (*postamble != ';') { strcat (full_spec, ";"); strncat (full_spec, postamble, MAX_POSTAMBLE - 1); } else { strncat (full_spec, postamble, MAX_POSTAMBLE); } } } /* make_file_spec */ /*- **============================================================================ ** ** FUNCTION ** ** prompt_for_string ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) void prompt_for_string (CONST char *confirm_str, CONST Int16 buf_size, char *return_buffer) #else /* NOT (ANSI_SYNTAX) */ void prompt_for_string (confirm_str, buf_size, return_buffer) CONST char *confirm_str; CONST Int16 buf_size; char *return_buffer; #endif /* (ANSI_SYNTAX) */ { char *status; FPRINTF (stderr, "\n%s", confirm_str); fflush (stderr); status = fgets (return_buffer, (int) buf_size, stdin); if (status == NULL) { FATALMSG ("error reading string from stdin"); explain_error (); vv_exit (); } status = STRCHR (return_buffer, '\n'); if (status != NULL) { *status = '\0'; } } /* prompt_for_string */ /*- **============================================================================ ** ** FUNCTION ** ** read_bytes ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) Int32 read_bytes (CONST Int32 max_bytes, char *buffer, File_Info *ip_file) #else /* NOT (ANSI_SYNTAX) */ Int32 read_bytes (max_bytes, buffer, ip_file) CONST Int32 max_bytes; char *buffer; File_Info *ip_file; #endif /* (ANSI_SYNTAX) */ { Int32 idx; int temp; for (idx = 0L; idx < max_bytes; idx++) { temp = fgetc (ip_file->file_ptr); if (temp == EOF) { if (ferror (ip_file->file_ptr)) { return (-2L); } if (idx == 0) { return (-1L); } break; } buffer[(SIZE_T) idx] = (char) temp; } return (idx); } /* read_bytes */ /*- **============================================================================ ** ** FUNCTION ** ** read_line ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) Int32 read_line (CONST Int32 max_bytes, char *buffer, File_Info *ip_file) #else /* NOT (ANSI_SYNTAX) */ Int32 read_line (max_bytes, buffer, ip_file) CONST Int32 max_bytes; char *buffer; File_Info *ip_file; #endif /* (ANSI_SYNTAX) */ { char *tmp_ptr; tmp_ptr = fgets (buffer, (int) max_bytes, ip_file->file_ptr); buffer[(SIZE_T) (max_bytes - 1)] = '\0'; if (tmp_ptr == NULL) { if (ferror (ip_file->file_ptr)) { return (-2L); } if (feof (ip_file->file_ptr)) { return (-1L); } } return ((Int32) strlen (buffer)); } /* read_line */ /*- **============================================================================ ** ** FUNCTION ** ** read_record ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) Int32 read_record (CONST Int32 max_bytes, char *buffer, File_Info *ip_file) #else /* NOT (ANSI_SYNTAX) */ Int32 read_record (max_bytes, buffer, ip_file) CONST Int32 max_bytes; char *buffer; File_Info *ip_file; #endif /* (ANSI_SYNTAX) */ { Int32 bytes_read; int file_handle; file_handle = fileno (ip_file->file_ptr); bytes_read = read (file_handle, buffer, max_bytes); if (ferror (ip_file->file_ptr)) { return (-2L); } if (feof (ip_file->file_ptr)) { return (-1L); } return (bytes_read); } /* read_record */ /*- **============================================================================ ** ** FUNCTION ** ** scan_cmd_line ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) void scan_cmd_line (CONST int qargc, CONST char *qargv[], CONST char *q_intro_str, CONST char *q_sep_str, Qualifier_Struct *qual_array, Qualifier_Struct *qual_ipfile, Qualifier_Struct *qual_opfile) #else /* NOT (ANSI_SYNTAX) */ void scan_cmd_line (qargc, qargv, q_intro_str, q_sep_str, qual_array, qual_ipfile, qual_opfile) CONST int qargc; CONST char *qargv[]; CONST char *q_intro_str; CONST char *q_sep_str; Qualifier_Struct *qual_array; Qualifier_Struct *qual_ipfile; Qualifier_Struct *qual_opfile; #endif /* (ANSI_SYNTAX) */ { int qual_no; char *tmp_buffer; char *tmp_ptr; /*- **------------------------------------------------------------------------ ** Loop through each of the available command qualifiers and call a ** separate function to parse that qualifier. **------------------------------------------------------------------------ */ for (qual_no = 0; qual_array[qual_no].q_string != NULL; qual_no++) { parse_qualifier (&qual_array[qual_no]); if ((qual_no == CMDQ_DEBUG) && (qual_array[qual_no].present == TRUE)) { G_debugging = TRUE; } } /*- **------------------------------------------------------------------------ ** If VVcode was invoked with the /HELP qualifier return now before ** attempting to parse the input or output file parameters. We do this ** to allow the user to issue the command VVENCODE /HELP without ** those parameters. **------------------------------------------------------------------------ */ if (qual_array[CMDQ_HELP].present == TRUE) { return; } /*- **------------------------------------------------------------------------ ** Now parse the parameters for the input and output files - it's the ** same mechanism as for qualifiers. **------------------------------------------------------------------------ */ parse_qualifier (qual_ipfile); parse_qualifier (qual_opfile); /*- **------------------------------------------------------------------------ ** Because this is a VMS implementation, it is more natural to allow the ** user to enter timestamps in the usual VMS format. If the /TIMESTAMP ** qualifier was specified the CLI routines would have converted whatever ** was entered into the VMS timestam format: "DD-MM-YYYY HH:MM:SS.CC" so ** we convert that back to VVcode internal format. **------------------------------------------------------------------------ */ if (qual_array[CMDQ_TIMESTAMP].present == TRUE) { tmp_ptr = (char *) qual_array[CMDQ_TIMESTAMP].value; tmp_buffer = STRDUP (tmp_ptr); strcpy (tmp_ptr, vms_to_vv_timestamp (tmp_buffer)); } } /* scan_cmd_line */ /*- **============================================================================ ** ** FUNCTION ** ** set_ftime ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) void set_ftime (File_Info *target_file) #else /* NOT (ANSI_SYNTAX) */ void set_ftime (target_file) File_Info *target_file; #endif /* (ANSI_SYNTAX) */ { int status; struct utimbuf utb; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ DEBUG_2 ("set_ftime: setting file `%s' time to %.24s", target_file->file_spec, ctime (&(target_file->mod_time))); utb.actime = target_file->mod_time; utb.modtime = target_file->mod_time; status = vax_utime (target_file->file_spec, &utb); /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ if (status != 0) { ERRORMSG_2 ("error setting file `%s' time to %.24s", target_file->file_spec, ctime (&(target_file->mod_time))); explain_error (); } return; } /* set_ftime */ /*- **============================================================================ ** ** FUNCTION ** ** set_pipe_mode ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) void set_pipe_mode (File_Info *target_file) #else /* NOT (ANSI_SYNTAX) */ void set_pipe_mode (target_file) File_Info *target_file; #endif /* (ANSI_SYNTAX) */ { return; } /* set_pipe_mode */ /*- **============================================================================ ** ** FUNCTION ** ** split_file_spec ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) Unsigned16 split_file_spec (CONST char *full_spec, char *preamble, char *name, char *extension, char *postamble) #else /* NOT (ANSI_SYNTAX) */ Unsigned16 split_file_spec (full_spec, preamble, name, extension, postamble) CONST char *full_spec; char *preamble; char *name; char *extension; char *postamble; #endif /* (ANSI_SYNTAX) */ { char tmp_full_spec[MAX_PATH + 1]; char *start_ptr; char *tmp_ptr; int idx; Unsigned16 path_components; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ if (preamble != NULL) { *preamble = '\0'; } if (name != NULL) { *name = '\0'; } if (extension != NULL) { *extension = '\0'; } if (postamble != NULL) { *postamble = '\0'; } path_components = FS_NOTHING; if ((full_spec == NULL) || (*full_spec == '\0')) { return (path_components); } strcpy (tmp_full_spec, full_spec); start_ptr = (char *) tmp_full_spec; /*- **------------------------------------------------------------------------ ** The preamble component corresponds to the VAX/VMS node, device, ** directory and/or logical name components in the form: ** ** node:: ** node::device:[dir1.dir2] ** node::device: ** node::logical_name: ** ** The preamble can end in "::", ":", "]" or ">" and we need to find the ** LAST occurrence of any of these items in the file specification. ** ** If the preamble component does not end in ']', '>' or ':', we assume ** that it is a logical name and ':' is appended only if the component ** is not empty. **------------------------------------------------------------------------ */ tmp_ptr = STRRSTR (start_ptr, ":]>"); if (tmp_ptr != NULL) { path_components |= FS_PREAMBLE; if (preamble != NULL) { for (idx = 0; ((idx < MAX_PREAMBLE) && (start_ptr <= tmp_ptr)); idx++) { *preamble++ = *start_ptr++; } *preamble = '\0'; } start_ptr = ++tmp_ptr; } /*- **------------------------------------------------------------------------ ** The postamble component of a VAX/VMS file specification is the version ** number of the file and is introduced with ';' or unusually '.': ** ** node::device:[dir1.dir2]name.extension;version ** node::device:[dir1.dir2]name;version ** node::device:[dir1.dir2]name.extension ** node::device:[dir1.dir2]name.extension.version ** ** We support only the ';' style of version number at the moment. **------------------------------------------------------------------------ */ tmp_ptr = STRCHR (start_ptr, ';'); if (tmp_ptr != NULL) { path_components |= FS_POSTAMBLE; if (postamble != NULL) { strncpy (postamble, tmp_ptr, MAX_POSTAMBLE); } *tmp_ptr = '\0'; } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ tmp_ptr = STRCHR (start_ptr, '.'); if (tmp_ptr != NULL) { path_components |= FS_EXTENSION; if (extension != NULL) { strncpy (extension, tmp_ptr, MAX_EXT); } *tmp_ptr = '\0'; } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ if (*start_ptr != '\0') { path_components |= FS_NAME; if (name != NULL) { strncpy (name, start_ptr, MAX_NAME); } } return (path_components); } /* split_file_spec */ /*- **============================================================================ ** ** FUNCTION ** ** tz_offset ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) TIME_T tz_offset (TIME_T the_time) #else /* NOT (ANSI_SYNTAX) */ TIME_T tz_offset (the_time) TIME_T the_time; #endif /* (ANSI_SYNTAX) */ { return (0); } /* tz_offset */ /*- **============================================================================ ** ** FUNCTION ** ** user_message ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) void user_message (CONST Int16 status, CONST char *msg_str, File_Info *log_file) #else /* NOT (ANSI_SYNTAX) */ void user_message (status, msg_str, log_file) CONST Int16 status; CONST char *msg_str; File_Info *log_file; #endif /* (ANSI_SYNTAX) */ { int to_stderr; int to_logfile; char *status_str; /*- **------------------------------------------------------------------------ ** Check the value supplied for the message status and set the output ** destinations accordingly. **------------------------------------------------------------------------ */ to_logfile = TRUE; to_stderr = FALSE; switch (status) { case NORMAL_STATUS: case LOG_STATUS: status_str = ""; break; case INFO_STATUS: status_str = "-VV-I-INFO, "; to_stderr = TRUE; break; case WARNING_STATUS: status_str = "%VV-W-WARNING, "; to_stderr = TRUE; break; case ERROR_STATUS: status_str = "%VV-E-ERROR, "; to_stderr = TRUE; break; case FATAL_STATUS: status_str = "%VV-F-FATAL, "; to_stderr = TRUE; break; default: INTERNAL_ERROR ("user_message"); vv_exit (); } /*- **------------------------------------------------------------------------ ** If the message is NULL, just update the status and/or the message ** show status. **------------------------------------------------------------------------ */ if ((msg_str == NULL) || (*msg_str == '\0')) { if (status > G_status) { G_status = status; } return; } /*- **------------------------------------------------------------------------ ** Make sure that we don't try to write to a NULL log file pointer. **------------------------------------------------------------------------ */ if (log_file->file_ptr == (FILE *) NULL) { to_logfile = FALSE; } /*- **------------------------------------------------------------------------ ** If the message is to be sent to the log file and stderr, check whether ** the log file output is also to stderr. If it is, disable the 'stderr' ** output. **------------------------------------------------------------------------ */ if (to_logfile && to_stderr) { if (log_file->file_ptr == stderr) { to_stderr = FALSE; } } /*- **------------------------------------------------------------------------ ** If the message is to be sent to stderr, output it here. **------------------------------------------------------------------------ */ if (to_stderr) { FPRINTF (stderr, "%s%s\n", status_str, msg_str); } /*- **------------------------------------------------------------------------ ** If the message is to be sent to the log file, output it here. If ** debugging is enabled, report also the name of the calling function. **------------------------------------------------------------------------ */ if (to_logfile) { FPRINTF (log_file->file_ptr, "%s%s\n", status_str, msg_str); } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ if (status > G_status) { G_status = status; } } /* user_message */ /*- **============================================================================ ** ** FUNCTION ** ** vv_exit ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) void vv_exit (void) #else /* NOT (ANSI_SYNTAX) */ void vv_exit () #endif /* (ANSI_SYNTAX) */ { switch (G_status) { case INFO_STATUS: case LOG_STATUS: case NORMAL_STATUS: exit (0x10000001L); break; case WARNING_STATUS: exit (0x10000000L); exit (1); break; case ERROR_STATUS: exit (0x10000002L); break; case FATAL_STATUS: default: exit (0x10000004L); break; } } /* vv_exit */ /*- **============================================================================ ** ** FUNCTION ** ** write_bytes ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) void write_bytes (CONST Int32 max_bytes, CONST char *buffer, File_Info *op_file) #else /* NOT (ANSI_SYNTAX) */ void write_bytes (max_bytes, buffer, op_file) CONST Int32 max_bytes; CONST char *buffer; File_Info *op_file; #endif /* (ANSI_SYNTAX) */ { Int32 idx; for (idx = 0L; idx < max_bytes; idx++) { fputc (buffer[(SIZE_T) idx], op_file->file_ptr); } } /* write_bytes */ /*- **============================================================================ ** ** FUNCTION ** ** write_record ** ** NOTE: see related file 'specific.h' for functional description. ** **============================================================================ */ #if (ANSI_SYNTAX) void write_record (CONST Int32 max_bytes, CONST char *buffer, File_Info *op_file) #else /* NOT (ANSI_SYNTAX) */ void write_record (max_bytes, buffer, op_file) CONST Int32 max_bytes; CONST char *buffer; File_Info *op_file; #endif /* (ANSI_SYNTAX) */ { Int32 no_bytes; no_bytes = max_bytes * sizeof (char); /*- **------------------------------------------------------------------------ ** Check that the buffer does not exceed the maximum allowable record ** length. If it does, truncate the record and issue a warning. **------------------------------------------------------------------------ */ if ((op_file->max_rec_len > 0) && (no_bytes > op_file->max_rec_len)) { ERRORMSG_2 ("output record too long (%ld bytes, max = %ld) - truncated", no_bytes, op_file->max_rec_len); no_bytes = op_file->max_rec_len; } fwrite (buffer, (SIZE_T) no_bytes, 1, op_file->file_ptr); } /* write_record */ /*- ****************************************************************************** ****************************************************************************** ** ** VAX/VMS specific functions private to this module. ** ****************************************************************************** ****************************************************************************** */ /*- **============================================================================ ** ** FUNCTION ** ** [tbs] ** ** DESCRIPTION ** ** [tbs] ** ** INPUT PARAMETERS ** ** [tbs] - [tbs] ** ** OUTPUT PARAMETERS ** ** [tbs] ** ** RETURN VALUE ** ** [tbs] ** **============================================================================ */ #if (ANSI_SYNTAX) static void parse_qualifier (Qualifier_Struct *qual_struct) #else /* NOT (ANSI_SYNTAX) */ static void parse_qualifier (qual_struct) Qualifier_Struct *qual_struct; #endif /* (ANSI_SYNTAX) */ { int status; String_Desc qual_desc; String_Desc result_desc; short length; char *tmp_str; char *tmp_ptr; char tmp_buffer[MAX_IP_LINE_LEN]; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ tmp_str = STRDUP (qual_struct->q_string); for (tmp_ptr = tmp_str; *tmp_ptr != '\0'; tmp_ptr++) { *tmp_ptr = TOUPPER (*tmp_ptr); } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ qual_desc.dsc$w_length = strlen (tmp_str); qual_desc.dsc$b_dtype = DSC$K_DTYPE_T; qual_desc.dsc$b_class = DSC$K_CLASS_S; qual_desc.dsc$a_pointer = tmp_str; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ result_desc.dsc$w_length = sizeof (tmp_buffer) - 1; result_desc.dsc$b_dtype = DSC$K_DTYPE_T; result_desc.dsc$b_class = DSC$K_CLASS_S; result_desc.dsc$a_pointer = tmp_buffer; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ qual_struct->value = NULL; status = CLI$PRESENT (&qual_desc); switch (status) { /*- **-------------------------------------------------------------------- ** **-------------------------------------------------------------------- */ case CLI$_COMMA: case CLI$_DEFAULTED: case CLI$_PRESENT: qual_struct->present = TRUE; status = CLI$GET_VALUE (&qual_desc, &result_desc, &length); /*- **---------------------------------------------------------------- ** **---------------------------------------------------------------- */ switch (status) { case CLI$_COMMA: case CLI$_CONCAT: case SS$_NORMAL: tmp_buffer[length] = '\0'; qual_struct->value = STRDUP (tmp_buffer); DEBUG_2 ("parse_qualifier: `/%s' present, value = `%s'", qual_struct->q_string, qual_struct->value); break; case CLI$_ABSENT: DEBUG_1 ("parse_qualifier: `/%s' present, no value given", qual_struct->q_string); break; default: FATALMSG_1 ("parse_qualifier: error parsing value of `/%s'", qual_struct->q_string); explain_error (); vv_exit (); break; } break; /*- **-------------------------------------------------------------------- ** **-------------------------------------------------------------------- */ case CLI$_LOCNEG: case CLI$_ABSENT: case CLI$_NEGATED: qual_struct->present = FALSE; DEBUG_1 ("parse_qualifier: `/%s' not present", qual_struct->q_string); break; default: FATALMSG_1 ("error checking qualifier `%s'", qual_struct->q_string); explain_error (); vv_exit (); break; } free (tmp_str); } /* parse_qualifier */ /*- **============================================================================ ** ** FUNCTION ** ** [tbs] ** ** DESCRIPTION ** ** Perform FAB & NAM initialization. ** ** INPUT PARAMETERS ** ** file_spec - file specification ** def_file_spec - default file specification ** fab_ptr - FAB to initialize ** fib_ptr - FIB to initialize ** nam_block_ptr - NAM block for FAB to use ** ** OUTPUT PARAMETERS ** ** [tbs] ** ** RETURN VALUE ** ** [tbs] ** **============================================================================ */ #if (ANSI_SYNTAX) static void FABFIBNAM_setup (CONST char *file_spec, CONST char *def_file_spec, unsigned short *chan_ptr, struct FAB *fab_ptr, struct fibdef *fib_ptr, struct NAM *nam_ptr, char *esa, char *rsa) #else /* NOT (ANSI_SYNTAX) */ static void FABFIBNAM_setup (file_spec, def_file_spec, chan_ptr, fab_ptr, fib_ptr, nam_ptr, esa, rsa) CONST char *file_spec; CONST char *def_file_spec; unsigned short *chan_ptr; struct FAB *fab_ptr; struct fibdef *fib_ptr; struct NAM *nam_ptr; char *esa; char *rsa; #endif /* (ANSI_SYNTAX) */ { int status; String_Desc dev_name; /*- **------------------------------------------------------------------------ ** Initialize FAB. **------------------------------------------------------------------------ */ memset (fab_ptr, 0, sizeof (*fab_ptr)); fab_ptr->fab$b_bln = FAB$C_BLN; fab_ptr->fab$b_bid = FAB$C_BID; fab_ptr->fab$l_nam = nam_ptr; fab_ptr->fab$b_fns = strlen (file_spec) & NAM$C_MAXRSS; fab_ptr->fab$l_fna = file_spec; fab_ptr->fab$b_dns = strlen (def_file_spec) & NAM$C_MAXRSS; fab_ptr->fab$l_dna = def_file_spec; /*- **------------------------------------------------------------------------ ** Initialize NAM. **------------------------------------------------------------------------ */ memset (nam_ptr, 0, sizeof (*nam_ptr)); nam_ptr->nam$b_bln = NAM$C_BLN; nam_ptr->nam$b_bid = NAM$C_BID; nam_ptr->nam$l_esa = esa; nam_ptr->nam$b_ess = NAM$C_MAXRSS; nam_ptr->nam$l_rsa = rsa; nam_ptr->nam$b_rss = NAM$C_MAXRSS; /*- **------------------------------------------------------------------------ ** Initialize the FIB. **------------------------------------------------------------------------ */ memset (fib_ptr, 0, sizeof (*fib_ptr)); /*- **------------------------------------------------------------------------ ** Use SYS$PARSE to determine the current device. **------------------------------------------------------------------------ */ status = sys$parse (fab_ptr, 0, 0); if ((status & 1) != 1) { FATALMSG ("FABFIBNAM_setup: couldn't parse current device"); explain_error (); LIB$SIGNAL (status); vv_exit (); } /*- **-------------------------------------------------------------------- ** Initialize the 'dev_name' descriptor **-------------------------------------------------------------------- */ dev_name.dsc$w_length = nam_ptr->nam$t_dvi[0] & NAM$C_MAXRSS; dev_name.dsc$b_dtype = DSC$K_DTYPE_T; dev_name.dsc$b_class = DSC$K_CLASS_S; dev_name.dsc$a_pointer = (char *) &(nam_ptr->nam$t_dvi[1]); /*- **-------------------------------------------------------------------- ** Assign a channel to the file's device **-------------------------------------------------------------------- */ status = sys$assign (&dev_name, chan_ptr, 0, 0); if ((status & 1) != 1) { FATALMSG_2 ("FABFIBNAM_setup: couldn't assign device `%*s'\n", dev_name.dsc$a_pointer, dev_name.dsc$w_length); explain_error (); LIB$SIGNAL (status); vv_exit (); } } /* FABFIBNAM_setup */ /*- **============================================================================ ** ** FUNCTION ** ** [tbs] ** ** DESCRIPTION ** ** [tbs] ** ** INPUT PARAMETERS ** ** [tbs] - [tbs] ** ** OUTPUT PARAMETERS ** ** [tbs] ** ** RETURN VALUE ** ** [tbs] ** **============================================================================ */ #if (ANSI_SYNTAX) char *vms_to_vv_timestamp (CONST char *vms_time_str) #else /* NOT (ANSI_SYNTAX) */ char *vms_to_vv_timestamp (vms_time_str) CONST char *vms_time_str; #endif /* (ANSI_SYNTAX) */ { static char *vv_time_str = DUMMY_VV_TIMESTAMP; char *mstring = "XXX"; int year; int month; int mday; int hours; int mins; int secs; int centi_secs; int status; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ if ((vms_time_str == NULL) || (*vms_time_str == '\0')) { strcpy (vv_time_str, ""); return (vv_time_str); } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ DEBUG_1 ("vms_to_vv_timestamp: VMS timestamp provided = `%s'", vms_time_str); status = sscanf (vms_time_str, VMS_TIMESTAMP_FORMAT, &mday, mstring, &year, &hours, &mins, &secs, ¢i_secs); month = lookup_key (month_list, mstring, NO_ABBREVIATIONS, CASE_SENSITIVE); /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ sprintf (vv_time_str, VV_TIMESTAMP_FORMAT, year, month, mday, hours, mins, secs); DEBUG_1 ("vms_to_vv_timestamp: VV timestamp returned = `%s'", vv_time_str); return (vv_time_str); } /* vms_to_vv_timestamp */ /*- **============================================================================ ** ** FUNCTION ** ** [tbs] ** ** DESCRIPTION ** ** [tbs] ** ** INPUT PARAMETERS ** ** [tbs] - [tbs] ** ** OUTPUT PARAMETERS ** ** [tbs] ** ** RETURN VALUE ** ** [tbs] ** **============================================================================ */ #if (ANSI_SYNTAX) char *vv_to_vms_timestamp (CONST char *vv_time_str) #else /* NOT (ANSI_SYNTAX) */ char *vv_to_vms_timestamp (vv_time_str) CONST char *vv_time_str; #endif /* (ANSI_SYNTAX) */ { static char *vms_time_str = DUMMY_VMS_TIMESTAMP; char *mstring = "XXX"; int year; int month; int mday; int hours; int mins; int secs; int status; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ if ((vv_time_str == NULL) || (*vv_time_str == '\0')) { strcpy (vms_time_str, ""); return (vms_time_str); } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ DEBUG_1 ("vv_to_vms_timestamp: VV timestamp provided = `%s'", vv_time_str); status = sscanf (vv_time_str, VV_TIMESTAMP_FORMAT, &year, &month, &mday, &hours, &mins, &secs); /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ sprintf (vms_time_str, VMS_TIMESTAMP_FORMAT, mday, month_list[month], year, hours, mins, secs, 0); DEBUG_1 ("vv_to_vms_timestamp: VMS timestamp returned = `%s'", vms_time_str); return (vms_time_str); } /* vv_to_vms_timestamp */ /*- **============================================================================ ** ** FUNCTION ** ** [tbs] ** ** DESCRIPTION ** ** [tbs] ** ** INPUT PARAMETERS ** ** [tbs] - [tbs] ** ** OUTPUT PARAMETERS ** ** [tbs] ** ** RETURN VALUE ** ** [tbs] ** **============================================================================ */ #if (ANSI_SYNTAX) static Int32 vax_utime (CONST char *file_spec, CONST struct utimbuf *utime_struct) #else /* NOT (ANSI_SYNTAX) */ static Int32 vax_utime (file_spec, utime_struct) CONST char *file_spec; CONST struct utimbuf *utime_struct; #endif /* (ANSI_SYNTAX) */ { int status; short iosb[4]; short rev_count; char date_str[24]; struct acb_struct acb[4]; struct fibdef fib; struct FAB fab; struct NAM nam; unsigned short io_channel; char *vv_time_str; char *vms_time_str; char esa[NAM$C_MAXRSS]; char rsa[NAM$C_MAXRSS]; unsigned long revision_time[2]; unsigned long creation_time[2]; unsigned long *quad_actime; unsigned long *quad_modtime; String_Desc time_string; String_Desc fib_desc; short revision_count; char ascdate_buffer[255]; /*- **------------------------------------------------------------------------ ** Convert the Unix format time to a VMS quadword time **------------------------------------------------------------------------ */ quad_actime = unix_to_vms_time (utime_struct->actime); quad_modtime = unix_to_vms_time (utime_struct->modtime); /*- **------------------------------------------------------------------------ ** Set up the FAB, FIB and NAM blocks for the supplied file specification. **------------------------------------------------------------------------ */ FABFIBNAM_setup (file_spec, "", &io_channel, &fab, &fib, &nam, esa, rsa); /*- **------------------------------------------------------------------------ ** Check that the file exists **------------------------------------------------------------------------ */ status = SYS$SEARCH (&fab, 0, 0); if ((status & 1) != 1) { ERRORMSG_2 ("vax_utime: error searching for file `%*s'", nam.nam$l_rsa, nam.nam$b_rsl); explain_error (); LIB$SIGNAL (status); return (-1); } /*- **------------------------------------------------------------------------ ** Copy the file ID from the NAM to FIB. **------------------------------------------------------------------------ */ fib.fib$r_fid_overlay.fib$w_fid[0] = nam.nam$w_fid[0]; fib.fib$r_fid_overlay.fib$w_fid[1] = nam.nam$w_fid[1]; fib.fib$r_fid_overlay.fib$w_fid[2] = nam.nam$w_fid[2]; /*- **------------------------------------------------------------------------ ** Construct the attribute control block item list. **------------------------------------------------------------------------ */ acb[0].w_size = ATR$S_CREDATE; acb[0].w_type = ATR$C_CREDATE; acb[0].l_addr = (void *) creation_time; acb[1].w_size = ATR$S_REVDATE; acb[1].w_type = ATR$C_REVDATE; acb[1].l_addr = (void *) revision_time; acb[2].w_size = 2; acb[2].w_type = ATR$C_ASCDATES; acb[2].l_addr = (void *) &revision_count; acb[3].w_size = 0; acb[3].w_type = 0; acb[3].l_addr = 0; /*- **------------------------------------------------------------------------ ** Build the FIB descriptor **------------------------------------------------------------------------ */ fib_desc.dsc$w_length = FIB$C_LENGTH; fib_desc.dsc$b_dtype = DSC$K_DTYPE_T; fib_desc.dsc$b_class = DSC$K_CLASS_S; fib_desc.dsc$a_pointer = (char *) &fib; /*- **------------------------------------------------------------------------ ** Set the file creation and revison dates and reset the revision count ** to one. **------------------------------------------------------------------------ */ revision_count = 1; creation_time[0] = quad_modtime[0]; creation_time[1] = quad_modtime[1]; revision_time[0] = quad_actime[0]; revision_time[1] = quad_actime[1]; /*- **------------------------------------------------------------------------ ** Modify the file. The IO$_MODIFY function is used to modify the file. ** The file's revision and expiry dates will be changed by this action ** but we don't really care since we've only just created the file. If ** it ever becomes a problem, the change could be inhibited by the ** assignment: fib.fib$r_acctl_overlay.fib$l_acctl = FIB$M_NORECORD **------------------------------------------------------------------------ */ status = SYS$QIOW (0, io_channel, IO$_MODIFY, iosb, 0, 0, &fib_desc, 0, 0, 0, acb, 0); /*- **------------------------------------------------------------------------ ** Check the return status. **------------------------------------------------------------------------ */ if ((status & 1) != 1) { ERRORMSG_2 ("vax_utime: error modifying file `%*s'", nam.nam$l_rsa, nam.nam$b_rsl); explain_error (); LIB$SIGNAL (status); return (-1); } if ((iosb[0] & 1) != 1) { ERRORMSG_2 ("vax_utime: error modifying file `%*s'", nam.nam$l_rsa, nam.nam$b_rsl); explain_error (); LIB$SIGNAL (iosb[0]); return (-1); } /*- **------------------------------------------------------------------------ ** De-access the I/O channel. **------------------------------------------------------------------------ */ status = SYS$DASSGN (io_channel); if ((status & 1) != 1) { ERRORMSG_2 ("vax_utime: error deaccessing file `%*s'", nam.nam$l_rsa, nam.nam$b_rsl); explain_error (); LIB$SIGNAL (status); return (-1); } return (0); } /* vax_utime */ /*- **============================================================================ ** ** FUNCTION ** ** [tbs] ** ** DESCRIPTION ** ** [tbs] ** ** INPUT PARAMETERS ** ** [tbs] - [tbs] ** ** OUTPUT PARAMETERS ** ** [tbs] ** ** RETURN VALUE ** ** [tbs] ** **============================================================================ */ #if (ANSI_SYNTAX) Unsigned32 *unix_to_vms_time (CONST TIME_T unix_time) #else /* NOT (ANSI_SYNTAX) */ Unsigned32 *unix_to_vms_time (unix_time) CONST TIME_T unix_time; #endif /* (ANSI_SYNTAX) */ { int status; struct tm *tms; static unsigned long vms_quad_time[2]; String_Desc vms_time_desc; static char *vms_time_str = DUMMY_VMS_TIMESTAMP; /*- **------------------------------------------------------------------------ ** Convert the Unix time to a 'tm' structure **------------------------------------------------------------------------ */ tms = localtime (&unix_time); DEBUG_2 ("unix_to_vms_time: unix time provided = %lu (%.24s)", unix_time, ctime (&unix_time)); /*- **------------------------------------------------------------------------ ** Convert the 'tm' structure into a VMS format time string **------------------------------------------------------------------------ */ sprintf (vms_time_str, VMS_TIMESTAMP_FORMAT, tms->tm_mday, month_list[tms->tm_mon + 1], tms->tm_year + 1900, tms->tm_hour, tms->tm_min, tms->tm_sec, 0); DEBUG_1 ("unix_to_vms_time: VMS time string = `%s'", vms_time_str); /*- **------------------------------------------------------------------------ ** Use SYS$BINTIM to convert the string into a VMS quadword time **------------------------------------------------------------------------ */ vms_time_desc.dsc$w_length = strlen (vms_time_str); vms_time_desc.dsc$b_dtype = DSC$K_DTYPE_T; vms_time_desc.dsc$b_class = DSC$K_CLASS_S; vms_time_desc.dsc$a_pointer = vms_time_str; status = SYS$BINTIM (&vms_time_desc, vms_quad_time); if ((status & 1) != 1) { FATALMSG_1 ("unix_to_vms_time: SYS$BINTIM error parsing `%s'", vms_time_str); explain_error (); LIB$SIGNAL (status); vv_exit (); } DEBUG_2 ("unix_to_vms_time: VMS quadword time = %08x%08x", vms_quad_time[1], vms_quad_time[0]); return (vms_quad_time); } /* vv_to_vms_timestamp */