Files
open-simh.simtools/extracters/ods2/compat.c
Timothe Litt 66e00b9900 Backlog of work since 2016
Too much to list all, but includes (in no particular order):
 - Cleanup for 64-bit builds, MSVC warnings.
 - Structured help
 - Help file compiler.
 - Supports volsets, writes/create work.
 - Support for I18n in messages, help.
 - Makefiles.
 - Initialize volume/volset
 - Command line editing/history

Builds and works on Linux and Windows (VS).
Not recently built or tested on other platforms, but
not intentinonally broken.
2022-10-10 11:00:20 -04:00

451 lines
12 KiB
C

/* Timothe Litt March 2016
* Copyright (C) 2016 Timothe litt
* litt at acm dot org
*
* Free for use with the ODS2 package. All other rights reserved.
*/
/*
* This is distributed as part of ODS2, originally written by
* Paul Nankervis, email address: Paulnank@au1.ibm.com
*
* ODS2 is distributed freely for all members of the
* VMS community to use. However all derived works
* must maintain comments in their source to acknowledge
* the contributions of the original author and
* subsequent contributors. This is free software; no
* warranty is offered, and while we believe it to be useful,
* you use it at your own risk.
*/
/* This module contains compatibility code, currently just
* to support Microsoft Windows.
*
* Microsoft deprecates sprintf, but doesn't supply standard
* replacement until very recent IDEs.
* Microsoft doesn't like fopen, or strerror, or getcwd, or getenv.
* One needs to use a M$ call to translate system errors.
*
* Finding out about drive letter assignments is unique to windows.
*/
#if !defined( DEBUG ) && defined( DEBUG_COMPAT )
#define DEBUG DEBUG_COMPAT
#else
#ifndef DEBUG
#define DEBUG 0
#endif
#endif
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "compat.h"
#include "descrip.h"
#include "stsdef.h"
#ifdef VMS
#include <jpidef.h>
#else
#ifdef _WIN32
#include <windows.h>
#include <shlwapi.h> /* PathSearchAndQualify() */
#else
#include <unistd.h>
#include <sys/types.h>
#ifndef USER_FROM_ENV
#include <pwd.h>
#endif
#endif
#endif
#if defined(_MSC_VER) && _MSC_VER < 1900
/******************************************************************* c99_vsnprintf() */
int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) {
int count = -1;
if (size != 0)
count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
if (count == -1)
count = _vscprintf(format, ap);
return count;
}
/******************************************************************* c99_snprintf() */
int c99_snprintf(char *outBuf, size_t size, const char *format, ...) {
int count;
va_list ap;
va_start(ap, format);
count = c99_vsnprintf(outBuf, size, format, ap);
va_end(ap);
return count;
}
#endif
#ifdef _MSC_VER
/******************************************************************* openf() */
FILE *openf( const char *filename, const char *mode ) {
errno_t err;
FILE *fd = NULL;
err = fopen_s( &fd, filename, mode );
if( err == 0 ) {
return fd;
}
return NULL;
}
#endif
#ifdef _WIN32
/******************************************************************* ods2_strerror() */
const char *ods2_strerror( int errn ) {
static char buf[256];
if( strerror_s( buf, sizeof( buf ), errn ) != 0 )
(void) snprintf( buf, sizeof( buf ), "Untranslatable error %u", errn );
return buf;
}
/******************************************************************* w32_errstr() */
TCHAR *w32_errstr( DWORD eno, ... ) {
va_list ap;
TCHAR *msg = NULL;
if( eno == NO_ERROR )
eno = GetLastError();
va_start(ap, eno);
if( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL, eno, 0,
(LPSTR)&msg, 1, &ap ) == 0 ) {
msg = (TCHAR *)malloc( 64 );
if( msg == NULL ) {
printf( "Out of memory reporting Windows error(%u\n", eno );
} else
(void) snprintf( msg, 64, "(%u)", eno );
}
va_end(ap);
return msg;
}
/******************************************************************* driveFromLetter() */
char *driveFromLetter( const char *letter ) {
DWORD rv = ERROR_INSUFFICIENT_BUFFER;
DWORD cs = 16;
TCHAR *bufp = NULL;
do {
if( rv == ERROR_INSUFFICIENT_BUFFER ) {
TCHAR *newp;
cs *= 2;
newp = (TCHAR *) realloc( bufp, cs );
if( newp == NULL )
break;
bufp = newp;
}
rv = QueryDosDevice( letter, bufp, cs );
if( rv == 0 ) {
rv = GetLastError();
continue;
}
return bufp;
} while( rv == ERROR_INSUFFICIENT_BUFFER );
free( bufp );
return NULL;
}
#endif
/******************************************************************* get_env() */
char *get_env( const char *name ) {
size_t i;
char *r;
#ifdef _WIN32
(void) getenv_s( &i, NULL, 0, name );
if( i == 0 )
return NULL;
if ((r = malloc( i )) == NULL )
return NULL;
(void)getenv_s( &i, r, i, name );
return r;
#else
char *t;
t = getenv( name );
if( t == NULL )
return NULL;
i = strlen( t );
r = malloc( i + 1 );
if( r == NULL )
return NULL;
memcpy( r, t, i+1 );
return r;
#endif
}
/******************************************************************* get_username() */
char *get_username( void ) {
char *username;
char *r;
size_t i;
#ifdef VMS
char uame[12 + 1] = "UNKNOWN ";
struct dsc$descriptor_s userdsc = { sizeof( uname ) - 1,
DSC$K_DTYPE_T,
DSC$K_CLASS_S, uname };
r = "UNKNOWN";
if( $SUCCESSFUL(lib$getjpi( &JPI$_USERNAME, 0, 0, 0, &userdsc, 0 )) ) {
for( i = sizeof( uname ) - 1; i >= 0; i-- ) {
if( uname[i] == ' ' )
uname[i] = '\0';
else
break;
}
if( uname[0] )
r = uname;
}
#else
#ifdef _WIN32
(void) getenv_s( &i, NULL, 0, "USERNAME" );
if( i == 0 )
r = "UNKNOWN";
else {
if ((r = malloc( i )) == NULL )
return NULL;
(void)getenv_s( &i, r, i, "USERNAME" );
return r;
}
#else
#ifdef USER_FROM_ENV
if( (r = getenv( "USER" )) == NULL )
r = getenv( "LOGNAME" );
if( r == NULL )
r = "UNKNOWN";
#else
struct passwd *pw;
pw = getpwuid(geteuid());
r = pw->pw_name;
#endif
#endif
#endif
i = strlen( r );
if( (username = malloc( i + 1 )) == NULL )
return NULL;
memcpy( username, r, i + 1 );
return username;
}
/******************************************************************* homefile () */
char *homefile( int dotfile, const char *filename, const char *ext ) {
char * prefix, *delim, *name;
size_t pfxlen, dellen, namlen, extlen;
#ifdef _WIN32
char *drive;
prefix = drive = get_env( "HOMEDRIVE" );
if( drive != NULL ) {
prefix = get_env( "HOMEPATH" );
if( prefix != NULL ) {
dellen = strlen( drive );
pfxlen = strlen( prefix );
if( (name = malloc( dellen + pfxlen + 1 )) == NULL ) {
free( prefix );
free( drive );
return NULL;
}
memcpy( name, drive, dellen );
memcpy( name+dellen, prefix, pfxlen +1 );
free( prefix );
prefix = name;
}
free( drive );
}
delim = dotfile? "\\.": "\\";
#elif defined( VMS )
prefix = get_env( "SYS$LOGIN" );
delim = dotfile? "_": "";
#else
prefix = get_env( "HOME" );
delim = dotfile? "/." : "/";
#endif
pfxlen = prefix? strlen( prefix ) : 0;
dellen = strlen( delim );
namlen = strlen( filename );
extlen = ext? strlen( ext ) : 0;
if( (name = malloc( pfxlen+dellen+namlen+extlen+1)) == NULL )
return NULL;
/* N.B. There is no buffer overrun here */
if( pfxlen )
memcpy( name, prefix, pfxlen );
memcpy( name+pfxlen, delim, dellen );
memcpy( name+pfxlen+dellen, filename, namlen+1 );
if( ext )
memcpy( name+pfxlen+dellen+namlen, ext, extlen+1 );
free( prefix );
return name;
}
/************************************************************* get_realpath() */
char *get_realpath( const char *filnam ) {
#ifdef _WIN32
size_t n;
char *path, resultant_path[MAX_PATH];
if ( filnam == NULL || strpbrk( filnam, "*?" ) != NULL ||
!PathSearchAndQualify( filnam, /* pcszPath */
resultant_path, /* pszFullyQualifiedPath */
/* cchFullyQualifiedPath */
sizeof( resultant_path )
) ) {
return NULL;
}
n = strlen( resultant_path );
path = (char *) malloc( n + 1 );
if ( path != NULL ) {
memcpy( path, resultant_path, n + 1 );
}
return path;
#elif defined VMS
#define MAXPATH 255
size_t n;
unsigned short resultant_path[1 + ( ( MAXPATH + 1 ) / 2)];
char *path;
unsigned long context, sts, flags;
struct dsc$descriptor filespec = {
0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL
};
struct dsc$descriptor resultant_filespec = {
MAXPATH, DSC$K_DTYPE_T, DSC$K_CLASS_VS, (char *) resultant_path
};
path = NULL;
if ( filnam != NULL ) {
filespec.dsc$w_length = strlen( filnam );
filespec.dsc$a_pointer = (char *) filnam;
*resultant_path = 0;
context = 0;
flags = LIB$M_FIL_NOWILD;
sts = lib$find_file( &filespec, &resultant_filespec, &context,
NULL, NULL, &sts, &flags );
lib$find_file_end( &context );
if( $SUCCESSFUL(sts) ) {
n = *resultant_path;
path = (char *) malloc( n + 1 );
if ( path != NULL ) {
memcpy( path, resultant_path + 1, n );
path[n] = '\0';
}
}
}
return path;
#elif defined unix || 1
size_t n;
char *path, resolved_path[PATH_MAX+1];
if ( filnam == NULL || realpath( filnam, resolved_path ) == NULL ) {
return NULL;
}
n = strlen( resolved_path );
path = (char *) malloc( n + 1 );
if ( path != NULL ) {
memcpy( path, resolved_path, n + 1 );
}
return path;
#endif
}
/******************************************************************** Ctime() */
char *Ctime( time_t *tval ) {
char *buf;
#ifdef _WIN32
if( (buf = malloc( 26 )) == NULL ) return NULL;
if( ctime_s( buf, 26, tval ) != 0 ) {
free( buf );
return NULL;
}
#else
char *cbuf;
if( (buf = malloc( 25 )) == NULL ) return NULL;
if( (cbuf = ctime( tval )) == NULL ) {
free( buf );
return NULL;
}
memcpy( buf, cbuf, 24 );
#endif
buf[24] = '\0';
return buf;
}
/******************************************************************* fgetline() */
/* Read a line of input - unlimited length
* Removes \n, returns NULL at EOF
* If *buf is NULL, one is allocated of size *bufsize.
* Thereafter, it is reused. Expanded if necessary.
* Caller responsible for free()
*/
char *fgetline( FILE *stream, int keepnl, char **buf, size_t *bufsize ) {
int c;
size_t idx = 0;
if( *buf == NULL && (*buf = malloc( *bufsize )) == NULL ) {
perror( "malloc" );
exit(EXIT_FAILURE);
}
while( (c = getc( stream )) != EOF && c != '\n' ) {
if( idx + (keepnl != 0) +2 > *bufsize ) { /* Now + char + (? \n) + \0 */
char *nbuf;
*bufsize += 32;
nbuf = (char *) realloc( *buf, *bufsize );
if( nbuf == NULL ) {
perror( "realloc" );
exit(EXIT_FAILURE);
}
*buf = nbuf;
}
buf[0][idx++] = c;
}
if( c == '\n' ) {
if( keepnl )
buf[0][idx++] = '\n';
} else {
if( c == EOF && idx == 0 ) {
buf[0][0] = '\0';
return NULL;
}
}
buf[0][idx] = '\0';
return *buf;
}