/* 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 #include #include #include #include #include #include "compat.h" #include "descrip.h" #include "stsdef.h" #ifdef VMS #include #else #ifdef _WIN32 #include #include /* PathSearchAndQualify() */ #else #include #include #ifndef USER_FROM_ENV #include #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; }