/*- ****************************************************************************** ****************************************************************************** ** ** ARCHIVE HEADER INFORMATION ** ** @C-file{ ** FILENAME = "vmcms.c", ** VERSION = "1.00", ** DATE = "", ** TIME = "", ** ** AUTHOR = "Niel Kempson and Rainer Schoepf", ** ADDRESS = "25 Whitethorn Drive, Cheltenham, GL52 5LL, England", ** TELEPHONE = "+44-242 579105", ** EMAIL = "kempson@tex.ac.uk (Internet), ** schoepf@sc.ZIB-Berlin.de (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 ** and Rainer Schoepf ** ** 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 #define MAX_CMD 128 /*- **---------------------------------------------------------------------------- ** Include files **---------------------------------------------------------------------------- */ #include "checkos.h" #include "machine.h" #include "local.h" #include "globals.h" #include "specific.h" #include "vvutils.h" /*- **============================================================================ ** ** 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]; Int16 path_parts; char postamble[MAX_POSTAMBLE + 1]; path_parts = split_file_spec (full_spec, NULL, name, extension, postamble); 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); } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ if ((path_parts & FS_POSTAMBLE) == 0) { strcpy (postamble, ".A"); } make_file_spec (NULL, name, extension, postamble, 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]:\n", confirm_str); 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' ? TRUE : 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]; FILE *file_ptr; int bytes_read; int i, j; char cmd_string[MAX_CMD]; char dummy[9]; char c; int status; struct tm tms; /*- **------------------------------------------------------------------------ ** 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; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ sprintf (cmd_string, "LISTFILE %s (NOHEADER DATE LIFO", ex_file->file_spec); for (i = 0; cmd_string[i] != '\0'; i++) { if (cmd_string[i] == '.') { cmd_string[i] = ' '; } else if (islower (cmd_string[i])) { cmd_string[i] = toupper (cmd_string[i]); } } DEBUG_1 ("examine_file: passing command `%s' to VM", cmd_string); status = system (cmd_string); if (status != 0) { ERRORMSG_1 ("error reading info for file `%s'", ex_file->file_spec); explain_error (); return; } for (i = 1; i <=3; i++) { status = scanf ("%s", dummy); DEBUG_1 ("examine_file: item skipped: `%s'", dummy); if (status != 1) { ERRORMSG_1 ("error parsing info for file `%s'", ex_file->file_spec); explain_error (); return; } } status = scanf (" %c %d %d %d", &c, &(ex_file->lng_rec_len), &i, &j); DEBUG_2 ("examine_file: record format: %c, record_length: %d", c, ex_file->lng_rec_len); DEBUG_2 ("examine_file: number of records: %d, number of blocks: %d", i, j); if (status != 4) { ERRORMSG_2 ("error parsing record info for file `%s', only %d items parsed", ex_file->file_spec, status); explain_error (); return; } ex_file->max_rec_len = ex_file->lng_rec_len; switch (c) { case 'V': ex_file->format = FMT_VARIABLE; break; case 'F': ex_file->format = FMT_FIXED; break; default: ERRORMSG_2 ("file `%s' has an unsupported record format (%c)", ex_file->file_spec, c); explain_error (); return; } status = scanf ("%d/%d/%d %d:%d:%d", &tms.tm_mon, &tms.tm_mday, &tms.tm_year, &tms.tm_hour, &tms.tm_min, &tms.tm_sec); DEBUG_3 ("examine_file: date as parsed: %02d/%02d/%02d", tms.tm_mon, tms.tm_mday, tms.tm_year); DEBUG_3 ("examine_file: time as parsed: %02d:%02d:%02d", tms.tm_hour, tms.tm_min, tms.tm_sec); if (status == 5) { tms.tm_sec = 0; } else if (status != 6) { ERRORMSG_1 ("error parsing time info for file `%s'", ex_file->file_spec); explain_error (); return; } tms.tm_mon--; ex_file->mod_time = make_time (&tms); /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ ex_file->file_ptr = fopen (ex_file->file_spec, "rb"); if (file_ptr == (FILE *) NULL) { ERRORMSG_1 ("couldn't examine (open) file `%s'", ex_file->file_spec); explain_error (); return; } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ bytes_read = fread (tmp_buffer, sizeof (char), EX_SAMPLE_SIZE, ex_file->file_ptr); ex_file->mode = MODE_TEXT; /* default */ for (i = 0; i < bytes_read - 1; i++) { if (!isprint(tmp_buffer[i])) { ex_file->mode = MODE_BINARY; break; } } f_close (ex_file); ex_file->file_ptr = (FILE *) NULL; } /* 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 ("Error number: %ld", (long) errno); } /* explain_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; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ /* if ((ip_file->rec_length < MIN_RECORD_LEN) || (ip_file->rec_length > MAX_RECORD_LEN)) { FATALMSG_1 ("invalid record length specified `%d'", ip_file->rec_length); vv_exit (G_status); }*/ /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ switch (ip_file->mode) { case MODE_BINARY: file_ptr = fopen (ip_file->file_spec, "rb"); break; case MODE_TEXT: file_ptr = fopen (ip_file->file_spec, "r"); break; default: ERRORMSG_1 ("invalid file mode specified (%d)", ip_file->mode); return ((FILE *) NULL); } 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 tmp_buffer[512]; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ 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)) { ERRORMSG ("operation cancelled"); return ((FILE *) NULL); } } else { ERRORMSG_1 ("file `%s' exists", op_file->file_spec); return ((FILE *) NULL); } } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ if (op_file->format == FMT_VARIABLE ) { if (op_file->max_rec_len == INV_RECORD_LEN) { op_file->max_rec_len = op_file->lng_rec_len = DEF_VARIABLE_RECORD_LEN; } else if ((op_file->max_rec_len < MIN_VARIABLE_RECORD_LEN) || (op_file->max_rec_len > MAX_VARIABLE_RECORD_LEN)) { WARNMSG_1 ("invalid record length specified `%d'", op_file->max_rec_len); WARNMSG_1 ("using default (%d) instead", DEF_VARIABLE_RECORD_LEN); op_file->max_rec_len = op_file->lng_rec_len = DEF_VARIABLE_RECORD_LEN; } sprintf (tmp_buffer, "%s, RECFM=V", op_file->mode == MODE_BINARY ? "wb" : "w"); } else if (op_file->format == FMT_FIXED ) { if (op_file->max_rec_len == INV_RECORD_LEN) { op_file->max_rec_len = op_file->lng_rec_len = DEF_FIXED_RECORD_LEN; } else if ((op_file->max_rec_len < MIN_FIXED_RECORD_LEN) || (op_file->max_rec_len > MAX_FIXED_RECORD_LEN)) { WARNMSG_1 ("invalid record length specified `%d'", op_file->max_rec_len); WARNMSG_1 ("using default (%d) instead", DEF_FIXED_RECORD_LEN); op_file->max_rec_len = op_file->lng_rec_len = DEF_FIXED_RECORD_LEN; } sprintf (tmp_buffer, "%s, RECFM=F, LRECL=%d", op_file->mode == MODE_BINARY ? "wb" : "w", op_file->lng_rec_len); } DEBUG_2 ("f_open_out: going to open file `%s' with specification `%s'", op_file->file_spec, tmp_buffer); file_ptr = fopen (op_file->file_spec, tmp_buffer); 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) */ { FILE *fp; int result; fp = fopen (file_spec, "r"); DEBUG_2 ("file_exists: trial open of file `%s' in \"r\" mode returns file pointer `%lx'", file_spec, (long) fp); result = (fp != (FILE *) NULL); DEBUG_1 ("file_exists: result = %d", result); fclose (fp); return (result); } /* 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 postamble[MAX_POSTAMBLE + 1]; if (forced_ext == NULL) { return; } (void) split_file_spec (full_spec, NULL, name, NULL, postamble); make_file_spec (NULL, name, forced_ext, postamble, 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) */ { 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, ""); /*- **------------------------------------------------------------------------ ** VM/CMS has no preamble component. **------------------------------------------------------------------------ */ /*- **------------------------------------------------------------------------ ** 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); } } /*- **------------------------------------------------------------------------ ** If the postamble component does not begin with '.', prepend '.' before ** appending the extension 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); 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) { return (idx); } 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) { return (-1); } else { 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) */ { int i; int c; char *s; DEBUG_1 ("read_record: want to read record of with maximum size %d", max_bytes); if (ip_file->mode == MODE_TEXT) { s = fgets (buffer, max_bytes, ip_file->file_ptr); if (s == (char *) NULL) { return (-1L); } i = strlen (s); } else { if (feof (ip_file->file_ptr)) { return (-1); } for (i = 0; i < max_bytes; i++) { c = getc (ip_file->file_ptr); if (c == EOF) { break; } else { buffer[i] = c; } } } DEBUG_1 ("read_record: record with %d bytes read", i); return (i); } /* 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) */ { char *arg; int arg_no; int len; int qual_found; int q_no; char *qsep_ptr; char *qvalue_ptr; char *tmp_qstr_ptr; int paren_seen = 0; char *file_specs[6]; int i; char tmp_buffer[512]; /*- **------------------------------------------------------------------------ ** Initialize file spec array **------------------------------------------------------------------------ */ for (i = 0; i < 6; i++) { file_specs[i] = NULL; } /*- **------------------------------------------------------------------------ ** Loop through each of the user supplied command line arguments. **------------------------------------------------------------------------ */ for (arg_no = 1; arg_no < qargc; arg_no++) { arg = (char *) qargv[arg_no]; if (arg[0] == '(') { paren_seen = 1; break; } else if (arg_no > 6) { USAGE ("too many arguments"); } else { file_specs[arg_no - 1] = STRDUP (arg); } } if (arg_no == 1) { USAGE ("too few arguments"); } /* arg_no is now the first option argument */ strcpy (tmp_buffer, file_specs[0]); if (arg_no > 2) { strcat (tmp_buffer, "."); strcat (tmp_buffer, file_specs[1]); if (arg_no > 3) { strcat (tmp_buffer, "."); strcat (tmp_buffer, file_specs[2]); } } for (i = 0; tmp_buffer[i] != '\0'; i++) { if (islower (tmp_buffer[i])) { tmp_buffer[i] = toupper (tmp_buffer[i]); } } qual_ipfile->present = TRUE; qual_ipfile->value = STRDUP (tmp_buffer); if (arg_no > 4) { if (strcmp (file_specs[3], "=") == 0) { file_specs[3] = file_specs[0]; } strcpy (tmp_buffer, file_specs[3]); if (arg_no > 5) { if (strcmp (file_specs[4], "=") == 0) { file_specs[4] = file_specs[1]; } strcat (tmp_buffer, "."); strcat (tmp_buffer, file_specs[4]); if (arg_no > 6) { if (strcmp (file_specs[5], "=") == 0) { file_specs[5] = file_specs[2]; } strcat (tmp_buffer, "."); strcat (tmp_buffer, file_specs[5]); } } for (i = 0; tmp_buffer[i] != '\0'; i++) { if (islower (tmp_buffer[i])) { tmp_buffer[i] = toupper (tmp_buffer[i]); } } qual_opfile->present = TRUE; qual_opfile->value = STRDUP (tmp_buffer); } for (; arg_no < qargc; arg_no++) { arg = (char *) qargv[arg_no]; /*- **-------------------------------------------------------------------- ** **-------------------------------------------------------------------- */ DEBUG_1 ("scan_cmd_line: command line argument: `%s'", arg); if (*arg == '(') { if (arg[1] == '\0') { continue; } ++arg; } /*- **---------------------------------------------------------------- ** Extract the component of the qualifier string before the ** 'q_sep_str' character if it is present. **---------------------------------------------------------------- */ tmp_qstr_ptr = STRDUP (arg); qsep_ptr = STRSTR (tmp_qstr_ptr, q_sep_str); qvalue_ptr = NULL; if (qsep_ptr != NULL) { *qsep_ptr = '\0'; qvalue_ptr = qsep_ptr + 1; } /*- **---------------------------------------------------------------- ** Search the command qualifier structure array for this ** qualifier string. **---------------------------------------------------------------- */ len = strlen (tmp_qstr_ptr); qual_found = -1; for (q_no = 0; qual_array[q_no].q_string != NULL; q_no++) { if (STRNCMPI (qual_array[q_no].q_string, tmp_qstr_ptr, len) == 0) { /*- **-------------------------------------------------------- ** **-------------------------------------------------------- */ if (qual_found < 0) { qual_found = q_no; DEBUG_1 ("scan_cmd_line: matches option: `%s'", qual_array[q_no].q_string); } else { USAGE_1 ("ambiguous option `%s'", qargv[arg_no]); } } } /*- **---------------------------------------------------------------- ** If the option string is unknown, return that status. **---------------------------------------------------------------- */ if (qual_found < 0) { USAGE_1 ("unknown option `%s'", qargv[arg_no]); } /*- **---------------------------------------------------------------- ** **---------------------------------------------------------------- */ if (qsep_ptr == NULL) { if (qual_array[qual_found].val_needed == VALUE_NONE) { qual_array[qual_found].present = TRUE; qual_array[qual_found].value = NULL; if (qual_found == CMDQ_DEBUG) { G_debugging = TRUE; } continue; } else { /*- **-------------------------------------------------------- ** **-------------------------------------------------------- */ if (((arg_no + 1) < qargc) && (STRCHR (QUAL_INTRO, *qargv[arg_no + 1]) == NULL)) { /*- **---------------------------------------------------- ** **---------------------------------------------------- */ qual_array[qual_found].present = TRUE; qual_array[qual_found].value = STRDUP (qargv[++arg_no]); DEBUG_1 ("scan_cmd_line: option value: `%s'", qargv[arg_no]); } else { /*- **---------------------------------------------------- ** **---------------------------------------------------- */ if (qual_array[qual_found].val_needed == VALUE_NEEDED) { USAGE_2 ("option `%.1s%s' needs a value", QUAL_INTRO, qual_array[qual_found].q_string); } else { qual_array[qual_found].present = TRUE; qual_array[qual_found].value = NULL; } } continue; } } else { /*- **------------------------------------------------------------ ** **------------------------------------------------------------ */ if (*qvalue_ptr == '\0') { USAGE_1 ("value missing for option `%.1s%s'", qargv[arg_no]); } else if (qual_array[qual_found].val_needed == VALUE_NONE) { USAGE_2 ("option `%.1s%s' does not take a value", QUAL_INTRO, qual_array[qual_found].q_string); } else { qual_array[qual_found].present = TRUE; qual_array[qual_found].value = STRDUP (qvalue_ptr); DEBUG_1 ("scan_cmd_line: option value: `%s'", qual_array[qual_found].value); continue; } } } } /* 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; int i; struct tm *tms; char cmd_string[MAX_CMD]; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ DEBUG_2 ("set_ftime: setting file `%s' time to %s", target_file->file_spec, ctime (&(target_file->mod_time))); /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ tms = localtime (&(target_file->mod_time)); sprintf (cmd_string, "EXEC TOUCH %s (%02d/%02d/%02d %02d:%02d:%02d)", target_file->file_spec, tms->tm_mon + 1, tms->tm_mday, tms->tm_year, tms->tm_hour, tms->tm_min, tms->tm_sec); for (i = 0; cmd_string[i] != '\0'; i++) { if (cmd_string[i] == '.') { cmd_string[i] = ' '; } else if (islower (cmd_string[i])) { cmd_string[i] = toupper (cmd_string[i]); } } DEBUG_1 ("set_ftime: passing command `%s' to VM", cmd_string); status = system (cmd_string); if (status != 0) { ERRORMSG_2 ("error setting file `%s' time to %s", 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; char *tmp_ptr2; int idx; Int16 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; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ tmp_ptr = STRCHR (start_ptr, '.'); if (tmp_ptr != NULL) { path_components |= FS_EXTENSION; tmp_ptr2 = tmp_ptr; tmp_ptr2++; while (*tmp_ptr2 != '\0') { if (*tmp_ptr2 == '.') { *tmp_ptr2 = '\0'; tmp_ptr2++; if ((tmp_ptr2 != '\0') && isalpha (*tmp_ptr2)) { path_components |= FS_POSTAMBLE; if (postamble != NULL) { postamble[0] = '.'; postamble[1] = *tmp_ptr2; tmp_ptr2++; if (isdigit (*tmp_ptr2)) { postamble[2] = *tmp_ptr2; postamble[3] = '\0'; } else { postamble[2] = '\0'; } } } break; } tmp_ptr2++; } 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) */ { /* struct tm *tm; TIME_T timezone; tm = localtime (&the_time); if (tm->tm_isdst > 0) { return (timezone - (TIME_T) 3600); } else { return (timezone); } */ return ((TIME_T) 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 = " -- "; to_stderr = TRUE; break; case WARNING_STATUS: status_str = "\nWARNING: "; to_stderr = TRUE; break; case ERROR_STATUS: status_str = "\nERROR: "; to_stderr = TRUE; break; case FATAL_STATUS: status_str = "\nFATAL: "; 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 LOG_STATUS: case NORMAL_STATUS: exit (0); break; case WARNING_STATUS: exit (1); break; case ERROR_STATUS: exit (2); break; case FATAL_STATUS: default: exit (3); 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); fwrite (buffer, (Int16) no_bytes, 1, op_file->file_ptr); } /* write_record */