/*- ****************************************************************************** ****************************************************************************** ** ** ARCHIVE HEADER INFORMATION ** ** @C-file{ ** FILENAME = "msdos.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" /*- **---------------------------------------------------------------------------- ** Implementation (compiler) specific include files **---------------------------------------------------------------------------- */ #if (MSDOS_TURBOC) #include #include #endif /* (MSDOS_TURBOC) */ #if (MSDOS_MSC) #include #include #include #endif /* (MSDOS_MSC) */ /*- **---------------------------------------------------------------------------- ** Implementation (compiler) specific functions and variables **---------------------------------------------------------------------------- */ #if (MSDOS_TURBOC) static int TC_utime ARGS ((char *path, TIME_T file_time)); #endif /* (MSDOS_TURBOC) */ /*- **============================================================================ ** ** 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]; SIZE_T bytes_read; SIZE_T bc; SIZE_T eol_count; int i; struct stat stat_buffer; /*- **------------------------------------------------------------------------ ** 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; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ 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; } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ bytes_read = fread (tmp_buffer, sizeof (char), EX_SAMPLE_SIZE, ex_file->file_ptr); eol_count = 0; for (bc = 0; bc < (bytes_read - 1); bc++) { if ((tmp_buffer[bc] == '\r') && (tmp_buffer[bc + 1] == '\n')) { ++eol_count; } } f_close (ex_file); ex_file->file_ptr = (FILE *) NULL; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ if (bytes_read > (80U * eol_count)) { ex_file->mode = MODE_BINARY; ex_file->format = DEF_BINARY_FMT; } else { ex_file->mode = MODE_TEXT; ex_file->format = DEF_TEXT_FMT; } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ i = stat (ex_file->file_spec, &stat_buffer); if (i != FALSE) { ERRORMSG_1 ("couldn't examine (stat) file `%s'", ex_file->file_spec); explain_error (); return; } ex_file->mod_time = stat_buffer.st_mtime; } /* 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)); } /* 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; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ 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, "rt"); 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; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ 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: file_ptr = fopen (op_file->file_spec, "wb"); break; case MODE_TEXT: file_ptr = fopen (op_file->file_spec, "wt"); break; default: ERRORMSG_1 ("invalid file mode specified (%d)", op_file->mode); return ((FILE *) NULL); } 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) */ { #if (MSDOS_TURBOC) return ((Boolean) (access (file_spec, 0) == 0)); #endif /* (MSDOS_TURBOC) */ #if (MSDOS_MSC) return ((Boolean) (access ((char *) file_spec, 0) == 0)); #endif /* (MSDOS_MSC) */ } /* 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; int status; file_handle = fileno (ex_file->file_ptr); status = isatty (file_handle); if (status == 0) { return (TRUE); } else { return (FALSE); } } /* 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 MS-DOS drive and/or path ** components in the form: ** ** D: dir1 \dir1 \dir1\dir2 \dir1\dir2\ ** D:\ D:dir1 D:\dir1 D:\dir1\dir2\ D:\dir1\dir2\ ** ** If the preamble component does not end in '\' or ':', '\' 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); } } } /* 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) */ { #if SUPPORT_VARIABLE_FMT /*- **------------------------------------------------------------------------ ** Below is debugging code for simulating record reading on MS-DOS. ** This code should be removed before official issue! **------------------------------------------------------------------------ */ Int32 bytes_read; if (ip_file->mode == MODE_TEXT) { bytes_read = read_line (max_bytes, buffer, ip_file); } else { if (feof (ip_file->file_ptr)) { return (-1L); } bytes_read = (Int32) fread (buffer, sizeof (char), (SIZE_T) max_bytes, ip_file->file_ptr); if (ferror (ip_file->file_ptr)) { return (-2L); } } return (bytes_read); #else /* NOT SUPPORT_VARIABLE_FMT */ INTERNAL_ERROR ("read_record"); return (-2L); #endif /* SUPPORT_VARIABLE_FMT */ } /* 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; /*- **------------------------------------------------------------------------ ** Loop through each of the user supplied command line arguments. **------------------------------------------------------------------------ */ tmp_qstr_ptr = NULL; for (arg_no = 1; arg_no < qargc; arg_no++) { arg = (char *) qargv[arg_no]; /*- **-------------------------------------------------------------------- ** **-------------------------------------------------------------------- */ if (qual_array[CMDQ_DEBUG].present == TRUE) { G_debugging = TRUE; } DEBUG_1 ("scan_cmd_line: command line argument: `%s'", arg); /*- **-------------------------------------------------------------------- ** If the first character of the argument is one of the allowable ** 'q_intro_str' characters then parse it as a qualifier, unless ** the argument is the 'STDIO_SYMBOL' string when it is interpreted as ** the standard input or output file. **-------------------------------------------------------------------- */ if (((STRCHR (q_intro_str, *arg) != NULL) && STRCMP (arg, STDIO_SYMBOL) != 0)) { /*- **---------------------------------------------------------------- ** Extract the component of the qualifier string after the ** 'q_intro_str' character before the 'q_sep_str' character ** if it is present. **---------------------------------------------------------------- */ if (tmp_qstr_ptr != NULL) { free (tmp_qstr_ptr); } tmp_qstr_ptr = STRDUP (arg + 1); 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 qualifier: `%s'", qual_array[q_no].q_string); } else { USAGE_1 ("ambiguous qualifier `%s'", qargv[arg_no]); } } } /*- **---------------------------------------------------------------- ** If the qualifier string is unknown, return that status. **---------------------------------------------------------------- */ if (qual_found < 0) { USAGE_1 ("unknown qualifier `%s'", qargv[arg_no]); } /*- **---------------------------------------------------------------- ** **---------------------------------------------------------------- */ if (qsep_ptr == NULL) { if (qual_array[qual_found].val_needed == VALUE_NEEDED) { USAGE_2 ("qualifier `%.1s%s' must take a value", QUAL_INTRO, qual_array[qual_found].q_string); } else { qual_array[qual_found].present = TRUE; qual_array[qual_found].value = NULL; } } else { /*- **------------------------------------------------------------ ** **------------------------------------------------------------ */ if (*qvalue_ptr == '\0') { USAGE_1 ("value missing after qualifier `%s'", qargv[arg_no]); } else if (qual_array[qual_found].val_needed == VALUE_NONE) { USAGE_2 ("qualifier `%.1s%s' does not take a value", QUAL_INTRO, qual_array[qual_found].q_string); } else { qual_array[qual_found].value = STRDUP (qvalue_ptr); qual_array[qual_found].present = TRUE; DEBUG_1 ("scan_cmd_line: qualifier value: `%s'", qual_array[qual_found].value); continue; } } } /*- **-------------------------------------------------------------------- ** **-------------------------------------------------------------------- */ else { if (qual_ipfile->present == FALSE) { qual_ipfile->present = TRUE; qual_ipfile->value = STRDUP (qargv[arg_no]); } else if (qual_opfile->present == FALSE) { qual_opfile->present = TRUE; qual_opfile->value = STRDUP (qargv[arg_no]); } else { USAGE ("too many file names specified"); } } } } /* 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 tm *tms; #if (MSDOS_MSC) struct utimbuf utb; #endif /* (MSDOS_MSC) */ /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ DEBUG_2 ("set_ftime: setting file `%s' time to %.24s", target_file->file_spec, ctime (&(target_file->mod_time))); /*- **------------------------------------------------------------------------ ** MS-DOS doesn't understand times before 1980.01.01-00:00:00 local time. ** If the time is before this time, issue a warning message and rely on ** utime() not to blow up when passed such a time. **------------------------------------------------------------------------ */ tms = localtime (&(target_file->mod_time)); if (tms->tm_year < 80) { WARNMSG_2 ("Cannot set file `%s' time to %s", target_file->file_spec, vv_timestamp (target_file->mod_time)); INFOMSG ("reason: MS-DOS does not support file times before 1980."); WARNMSG_1 ("File `%s' time set to 1980.01.01-00:00:00 GMT", target_file->file_spec); } /*- **------------------------------------------------------------------------ ** Turbo C does not have a version of utime() so we use the TC_utime() ** emulation instead. **------------------------------------------------------------------------ */ #if (MSDOS_MSC) utb.actime = target_file->mod_time; utb.modtime = target_file->mod_time; status = utime (target_file->file_spec, &utb); #endif /* (MSDOS_MSC) */ #if (MSDOS_TURBOC) status = TC_utime (target_file->file_spec, target_file->mod_time); #endif /* (MSDOS_TURBOC) */ /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ 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) */ { int file_handle; int status; file_handle = fileno (target_file->file_ptr); switch (target_file->mode) { case MODE_BINARY: status = setmode (file_handle, (int) O_BINARY); break; case MODE_TEXT: status = setmode (file_handle, (int) O_TEXT); break; default: INTERNAL_ERROR ("set_pipe_mode"); } if (status < 0) { ERRORMSG_1 ("error setting mode of file `%s'", target_file->file_spec); explain_error (); } } /* 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; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ 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; } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ 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) */ { struct tm *tm; char *tz_str; char set_tz_str[32]; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ tz_str = getenv ("TZ"); if (tz_str == NULL) { strcpy (set_tz_str, "TZ="); strcat (set_tz_str, VV_TIMEZONE); putenv (set_tz_str); } tzset (); tm = localtime (&the_time); if (tm->tm_isdst > 0) { return (timezone - (TIME_T) 3600); } else { return (timezone); } } /* 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 LOG_STATUS: case NORMAL_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) */ { #if SUPPORT_VARIABLE_FMT /*- **------------------------------------------------------------------------ ** Below is debugging code for simulating record writing on MS-DOS. ** This code should be removed before official issue! **------------------------------------------------------------------------ */ 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 / sizeof (char); } fwrite (buffer, sizeof (char), (SIZE_T) no_bytes, op_file->file_ptr); #else /* NOT SUPPORT_VARIABLE_FMT */ INTERNAL_ERROR ("write_record"); #endif /* SUPPORT_VARIABLE_FMT */ } /* write_record */ /*- **============================================================================ ** ** FUNCTION ** ** TC_utime ** ** DESCRIPTION ** ** Set the modification time of a file. This is a crude emulation of the ** Unix C utime() function for Turbo C which doesn't provide one ** (Microsoft C does). ** ** INPUT PARAMETERS ** ** file_spec - the file specification of the file ** file_time - the Unix format file modification time to be set. ** ** OUTPUT PARAMETERS ** ** None ** ** RETURN VALUE ** ** Zero if the time was set successfully, -1 otherwise. ** **============================================================================ */ #if (MSDOS_TURBOC) static int TC_utime (char *file_spec, TIME_T file_time) { int handle; int status; struct ftime fts; struct tm *tms; /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ handle = open (file_spec, O_RDWR); if (handle < 0) { ERRORMSG_1 ("error opening file `%s'", file_spec); explain_error (); return (-1); } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ tms = localtime (&file_time); fts.ft_tsec = (tms->tm_sec / 2) & 0x1f; fts.ft_min = (tms->tm_min) & 0x3f; fts.ft_hour = (tms->tm_hour) & 0x1f; fts.ft_day = (tms->tm_mday) & 0x1f; fts.ft_month = (tms->tm_mon + 1) & 0x0f; /*- **------------------------------------------------------------------------ ** If the local time is before 1980.01.01-00:00:00, reset it to that. **------------------------------------------------------------------------ */ if (tms->tm_year < 80) { fts.ft_tsec = 0; fts.ft_min = 0; fts.ft_hour = 0; fts.ft_day = 0; fts.ft_month = 0; fts.ft_year = 0; } else { fts.ft_year = (tms->tm_year - 80) & 0x7f; } status = setftime (handle, &fts); if (status != 0) { ERRORMSG_2 ("error setting file `%s' time to %.24s", file_spec, ctime (&file_time)); explain_error (); close (handle); return (-1); } /*- **------------------------------------------------------------------------ ** **------------------------------------------------------------------------ */ status = close (handle); if (status < 0) { ERRORMSG_1 ("error closing file `%s'", file_spec); return (-1); } return (0); } #endif /* (MSDOS_TURBOC) */