"
COPYRIGHT (c) 1988 by Claus Gittinger
COPYRIGHT (c) 1998-2004 by eXept Software AG
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
"{ Package: 'stx:libbasic' }"
AbstractOperatingSystem subclass:#Win32OperatingSystem
instanceVariableNames:''
classVariableNames:'HostName DomainName CurrentDirectory'
poolDictionaries:''
category:'OS-Windows'
!
Object subclass:#FileStatusInfo
instanceVariableNames:'type mode uid gid size id accessed modified created statusChanged
path fullName alternativeName'
classVariableNames:''
poolDictionaries:''
privateIn:Win32OperatingSystem
!
Object subclass:#OSProcessStatus
instanceVariableNames:'pid status code core'
classVariableNames:''
poolDictionaries:''
privateIn:Win32OperatingSystem
!
Object subclass:#RegistryEntry
instanceVariableNames:'path handle'
classVariableNames:'Lobby HKEY_CLASSES_ROOT HKEY_CURRENT_USER HKEY_LOCAL_MACHINE
HKEY_USERS HKEY_PERFORMANCE_DATA HKEY_CURRENT_CONFIG
HKEY_DYN_DATA'
poolDictionaries:''
privateIn:Win32OperatingSystem
!
OSFileHandle subclass:#Win32FILEHandle
instanceVariableNames:''
classVariableNames:''
poolDictionaries:''
privateIn:Win32OperatingSystem
!
OSFileHandle subclass:#Win32Handle
instanceVariableNames:''
classVariableNames:''
poolDictionaries:''
privateIn:Win32OperatingSystem
!
Win32OperatingSystem::Win32Handle subclass:#Win32ProcessHandle
instanceVariableNames:'pid'
classVariableNames:''
poolDictionaries:''
privateIn:Win32OperatingSystem
!
Win32OperatingSystem::Win32Handle subclass:#Win32SocketHandle
instanceVariableNames:''
classVariableNames:''
poolDictionaries:''
privateIn:Win32OperatingSystem
!
!Win32OperatingSystem primitiveDefinitions!
%{
#include "stxOSDefs.h"
/*
* ensure that ST/X runs on NT, 95 and 98
* (however, this disables some Win2K and XP features (sigh)
*/
#ifndef WINVER
# define WINVER 0x0400
#endif
#if WINVER < 0x0400
# define NO_GETADAPTERSINFO
#endif
#define USE_H_ERRNO
# ifdef i386
# ifndef _X86_
# define _X86_
# endif
# endif
/*
* notice: although many systems' include files
* already block against multiple inclusion, some
* do not. Therefore, this is done here again.
* (it does not hurt)
*/
# ifndef _SIGNAL_H_INCLUDED_
# include <signal.h>
# define _SIGNAL_H_INCLUDED_
# endif
# ifndef _SYS_TYPES_H_INCLUDED_
# include <sys/types.h>
# define _SYS_TYPES_H_INCLUDED_
# endif
# ifndef _TIME_H_INCLUDED_
# include <time.h>
# define _TIME_H_INCLUDED_
# endif
# ifndef _SYS_TIMEB_H_INCLUDED_
# include <sys/timeb.h>
# define _SYS_TIMEB_H_INCLUDED_
# endif
# ifndef _SYS_STAT_H_INCLUDED_
# include <sys/stat.h>
# define _SYS_STAT_H_INCLUDED_
# endif
# ifndef _ERRNO_H_INCLUDED_
# include <errno.h>
# define _ERRNO_H_INCLUDED_
# endif
# ifndef _STDIO_H_INCLUDED_
# include <stdio.h>
# define _STDIO_H_INCLUDED_
# endif
# ifndef _FCNTL_H_INCLUDED_
# include <fcntl.h>
# define _FCNTL_H_INCLUDED_
# endif
/* # define PROCESSDEBUGWIN32 /* */
/* # define PROCESS1DEBUGWIN32 /* */
/* # define PROCESS2DEBUGWIN32 /* */
/* # define PROCESSDEBUG_CHILDPROCESSWAIT /* */
/* # define SELECTDEBUGWIN32 /* */
/* # define SELECT1DEBUGWIN32 /* */
/* # define SELECT2DEBUGWIN32 /* */
/* # define WAITDEBUGWIN32 /* */
/* # define SIGNALDEBUGWIN32 /* */
# undef INT
# undef Array
# undef Number
# undef Method
# undef Point
# undef Rectangle
# undef Block
# undef String
# undef Message
# undef Object
# undef Context
# undef Time
# undef Date
# undef Set
# undef Signal
# undef Delay
# include <stdarg.h> /* */
# ifndef WINDOWS_H_INCLUDED
# define WINDOWS_H_INCLUDED
# include <windows.h>
# endif
# ifndef NO_GETADAPTERSINFO
# include <iphlpapi.h>
# endif
# if !defined(__BORLANDC__)
# undef stat
# define stat _stat
# undef chmod
# define chmod _chmod
# undef access
# define access _access
# define MAXFILELEN 256
# endif
# ifdef __DEF_Array
# define Array __DEF_Array
# endif
# ifdef __DEF_Number
# define Number __DEF_Number
# endif
# ifdef __DEF_Method
# define Method __DEF_Method
# endif
# ifdef __DEF_Point
# define Point __DEF_Point
# endif
# ifdef __DEF_Rectangle
# define Rectangle __DEF_Rectangle
# endif
# ifdef __DEF_Block
# define Block __DEF_Block
# endif
# ifdef __DEF_String
# define String __DEF_String
# endif
# ifdef __DEF_Message
# define Message __DEF_Message
# endif
# ifdef __DEF_Object
# define Object __DEF_Object
# endif
# ifdef __DEF_Context
# define Context __DEF_Context
# endif
# ifdef __DEF_Date
# define Date __DEF_Date
# endif
# ifdef __DEF_Time
# define Time __DEF_Time
# endif
# ifdef __DEF_Set
# define Set __DEF_Set
# endif
# ifdef __DEF_Signal
# define Signal __DEF_Signal
# endif
# ifdef __DEF_Delay
# define Delay __DEF_Delay
# endif
# define INT int
typedef int (*intf)(int);
BOOL __signalUserInterruptWIN32(DWORD sig);
# if defined (HAS_LOCALECONV)
# ifndef _LOCALE_H_INCLUDED_
# include <locale.h>
# define _LOCALE_H_INCLUDED_
# endif
# endif
# ifdef __BORLANDC__
# include <dir.h>
# define MAXPATHLEN MAXPATH
# define MAXFILELEN MAXFILE
# endif
# ifndef MAXPATHLEN
# ifndef MSDOS_LIKE
# ifndef NO_SYS_PARAM_H
# include <sys/param.h>
# endif
# endif
# ifndef MAXPATHLEN
# ifdef FILENAME_MAX /* i.e. MSDOS_LIKE */
# define MAXPATHLEN FILENAME_MAX
# else
# ifdef MAX_PATH
# define MAXPATHLEN MAX_PATH
# else
# define MAXPATHLEN 1024
# endif
# endif
# endif
# endif
/*
* sigaction dummies (you won't believe these call themself ``POSIX'' systems ...)
*/
# ifndef SA_RESTART
# define SA_RESTART 0
# endif
# ifndef SA_SIGINFO
# define SA_SIGINFO 0
# endif
# if defined(HAS_WAITPID) || defined(HAS_WAIT3)
# include <sys/wait.h>
# endif
# if defined(HAS_SYSINFO)
# include <sys/systeminfo.h>
# endif
#define SIGHANDLER_ARG int
#define _HANDLEVal(o) (HANDLE)(__externalAddressVal(o))
/*
* not all systems have time_t and off_t
* explicit add of those we know to have ...
*/
#ifndef TIME_T
# define TIME_T long
#endif
#ifndef OFF_T
# define OFF_T long
#endif
/*
* where is the timezone info ?
*/
#if defined(HAS_NO_TIMEZONE)
# if defined(HAS_NO_TM_GMTOFF)
# define TIMEZONE(tmPtr) 0
# else
# define TIMEZONE(tmPtr) ((tmPtr)->tm_gmtoff)
# endif
#else
# ifdef MSDOS_LIKE
# define TIMEZONE(tmPtr) 0
# else
# define TIMEZONE(tmPtr) timezone
# endif
#endif
%}
! !
!Win32OperatingSystem primitiveFunctions!
%{
/* isWindows-NT flag:
* 1 for NT based systemes, such as NT,XP or 2k
* 0 for w95 based systems, such as w95/w98/ME
*/
static int __isWinNT = 0;
#define __wait wait
static int
_canAccessIOWithoutBlocking (aFD, readMode)
int aFD;
int readMode;
{
struct timeval tv;
fd_set fds;
int n;
/* we use the osfhandle insteat of the fd !! WHY ?? (I do not know)
but otherwise it not works
*/
int sock = (int) _get_osfhandle (aFD);
FD_ZERO( & fds );
FD_SET ( sock, & fds );
tv.tv_sec = 0;
tv.tv_usec = 0;
if (readMode) {
n = select (sock + 1, & fds, NULL, NULL, & tv);
} else {
n = select (sock + 1, NULL, & fds, NULL, & tv);
}
if (n == 0) {
return (0);
}
if (n > 0) {
return ((FD_ISSET (sock, & fds)) ? 1 : 0);
}
switch (WSAGetLastError()) {
case WSAENOTSOCK:
if (readMode) {
DWORD w = 0;
HANDLE h = (HANDLE) _get_osfhandle (aFD);
if (PeekNamedPipe (h, 0, 0, 0, & w, 0)) {
if( !__isWinNT || w > 0 )
return (1);
return (0);
}
return (-1);
}
/* in writeMode we return allways true for none-sockets */
return (1);
case WSAEINPROGRESS:
case WSAEWOULDBLOCK: return (0);
default: return (1);
}
return (0);
}
#define _canReadWithoutBlocking(fd) _canAccessIOWithoutBlocking(fd, 1)
#define _canWriteWithoutBlocking(fd) _canAccessIOWithoutBlocking(fd, 0)
static FARPROC
__get_KERNEL32_functionAddress(functionName)
char *functionName;
{
/*
* Attention: some API calls are not available on old NT4.0/W95/W98
*/
FARPROC entry = NULL;
static HINSTANCE handle = NULL;
if (handle == NULL) {
handle = LoadLibrary("KERNEL32.DLL");
}
entry = GetProcAddress(handle, functionName);
return entry;
}
static FARPROC
__get_iphlpapi_functionAddress(functionName)
char *functionName;
{
/*
* Attention: some API calls are not available on old NT4.0/W95/W98
*/
FARPROC entry = NULL;
static HINSTANCE handle2 = NULL;
if (handle2 == NULL) {
handle2 = LoadLibrary("iphlpapi.DLL");
}
entry = GetProcAddress(handle2, functionName);
return entry;
}
%}
! !
!Win32OperatingSystem class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1988 by Claus Gittinger
COPYRIGHT (c) 1998-2004 by eXept Software AG
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
documentation
"
this class resulted from extracting WIN32 specifics of the old
OperatingSystemClass into this sub-class.
You may find some leftover unix stuff, which will go away sooner
or later.
this class realizes access to most (all ?) required operating system services;
some of it is very specific for unix, so do not depend on
things available here in your applications
- some may not be found in other OS's or be slightly different ...
(On the other hand: I do not want to hide all features
from you - in some situations it MAY be interesting to be
able to get down to a select or fork system call easily (at least on Unix systems).
You decide - portability vs. functionality)
[Class variables:]
HostName <String> remembered hostname
DomainName <String> remembered domainname
CurrentDirectory <String> remembered currentDirectories path
[author:]
Claus Gittinger (initial version & cleanup)
Manfred Dierolf (many features)
[see also:]
OSProcessStatus
Filename Date Time
ExternalStream FileStream PipeStream Socket
"
!
examples
"
various queries
[exBegin]
Transcript
showCR:'hello ' , (OperatingSystem getLoginName)
[exEnd]
[exBegin]
OperatingSystem isUNIXlike ifTrue:[
Transcript showCR:'this is some UNIX-like OS'
] ifFalse:[
Transcript showCR:'this OS is not UNIX-like'
]
[exEnd]
[exBegin]
Transcript
showCR:'this machine is called ' , OperatingSystem getHostName
[exEnd]
[exBegin]
Transcript
showCR:('this machine is in the '
, OperatingSystem getDomainName
, ' domain')
[exEnd]
[exBegin]
Transcript
showCR:('this machine''s CPU is a '
, OperatingSystem getCPUType
)
[exEnd]
[exBegin]
Transcript showCR:'executing ls command ...'.
OperatingSystem executeCommand:'ls'.
Transcript showCR:'... done.'.
[exEnd]
locking a file
(should be executed on two running smalltalks - not in two threads):
[exBegin]
|f|
f := 'testFile' asFilename readWriteStream.
10 timesRepeat:[
'about to lock ...' printCR.
[
OperatingSystem
lockFD:(f fileDescriptor)
shared:false
blocking:false
] whileFalse:[
'process ' print. OperatingSystem getProcessId print. ' is waiting' printCR.
Delay waitForSeconds:1
].
'LOCKED ...' printCR.
Delay waitForSeconds:10.
'unlock ...' printCR.
(OperatingSystem
unlockFD:(f fileDescriptor)) printCR.
Delay waitForSeconds:3.
]
[exBegin]
"
! !
!Win32OperatingSystem class methodsFor:'initialization'!
initOSType
"internal - see if running under win-NT/XP/2k
(as opposed to win-95/98/ME)"
%{ /* NOCONTEXT */
OSVERSIONINFO osvi;
memset(&osvi, 0, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
GetVersionEx (&osvi);
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
__isWinNT = 1;
} else {
__isWinNT = 0;
}
%}.
!
initialize
"initialize the class"
ObjectMemory addDependent:self.
HostName := nil.
DomainName := nil.
LastErrorNumber := nil.
PipeFailed := false.
self initOSType
"Modified: 13.9.1997 / 10:47:32 / cg"
!
update:something with:aParameter from:changedObject
"catch image restart and flush some cached data"
something == #earlyRestart ifTrue:[
"
flush cached data
"
HostName := nil.
DomainName := nil.
LastErrorNumber := nil.
PipeFailed := false.
self initOSType
]
"Modified: 22.4.1996 / 13:10:43 / cg"
"Created: 15.6.1996 / 15:22:37 / cg"
"Modified: 7.1.1997 / 19:36:11 / stefan"
! !
!Win32OperatingSystem class methodsFor:'OS signal constants'!
sigABRT
"return the signal number for SIGABRT - 0 if not supported by OS
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGABRT
RETURN ( __MKSMALLINT(SIGABRT) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigALRM
"return the signal number for SIGALRM - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGALRM
RETURN ( __MKSMALLINT(SIGALRM) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigBREAK
"return the signal number for SIGBREAK - 0 if not supported.
This is an MSDOS specific signal"
%{ /* NOCONTEXT */
#ifdef SIGBREAK
RETURN ( __MKSMALLINT(SIGBREAK) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigBUS
"return the signal number for SIGBUS - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGBUS
RETURN ( __MKSMALLINT(SIGBUS) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigCHLD
"return the signal number for SIGCHLD - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGCHLD)
RETURN ( __MKSMALLINT(SIGCHLD) );
#else
# if defined(SIGCLD)
RETURN ( __MKSMALLINT(SIGCLD) );
# else
RETURN ( __MKSMALLINT(0) );
# endif
#endif
%}
!
sigCONT
"return the signal number for SIGCONT - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGCONT)
RETURN ( __MKSMALLINT(SIGCONT) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigDANGER
"return the signal number for SIGDANGER - 0 if not supported
(seems to be an AIX special)"
%{ /* NOCONTEXT */
#if defined(SIGDANGER)
RETURN ( __MKSMALLINT(SIGDANGER) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigEMT
"return the signal number for SIGEMT - 0 if not supported by OS
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGEMT
RETURN ( __MKSMALLINT(SIGEMT) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigFP
"return the signal number for SIGFP - 0 if not supported by OS
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGFPE
RETURN ( __MKSMALLINT(SIGFPE) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigGRANT
"return the signal number for SIGGRANT - 0 if not supported
(seems to be an AIX special)"
%{ /* NOCONTEXT */
#if defined(SIGGRANT)
RETURN ( __MKSMALLINT(SIGGRANT) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigHUP
"return the signal number for SIGHUP
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGHUP
RETURN ( __MKSMALLINT(SIGHUP) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigILL
"return the signal number for SIGILL - 0 if not supported by OS
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGILL
RETURN ( __MKSMALLINT(SIGILL) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigINT
"return the signal number for SIGINT
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGINT
RETURN ( __MKSMALLINT(SIGINT) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigIO
"return the signal number for SIGIO - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGIO)
RETURN ( __MKSMALLINT(SIGIO) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigIOT
"return the signal number for SIGIOT - 0 if not supported by OS
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGIOT
RETURN ( __MKSMALLINT(SIGIOT) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigKILL
"return the signal number for SIGKILL
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGKILL
RETURN ( __MKSMALLINT(SIGKILL) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigLOST
"return the signal number for SIGLOST - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGLOST)
RETURN ( __MKSMALLINT(SIGLOST) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigMIGRATE
"return the signal number for SIGMIGRATE - 0 if not supported
(seems to be an AIX special)"
%{ /* NOCONTEXT */
#if defined(SIGMIGRATE)
RETURN ( __MKSMALLINT(SIGMIGRATE) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigMSG
"return the signal number for SIGMSG - 0 if not supported
(seems to be an AIX special)"
%{ /* NOCONTEXT */
#if defined(SIGMSG)
RETURN ( __MKSMALLINT(SIGMSG) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigPIPE
"return the signal number for SIGPIPE - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGPIPE
RETURN ( __MKSMALLINT(SIGPIPE) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigPOLL
"return the signal number for SIGPOLL - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGPOLL)
RETURN ( __MKSMALLINT(SIGPOLL) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigPRE
"return the signal number for SIGPRE - 0 if not supported
(seems to be an AIX special)"
%{ /* NOCONTEXT */
#if defined(SIGPRE)
RETURN ( __MKSMALLINT(SIGPRE) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigPROF
"return the signal number for SIGPROF - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGPROF)
RETURN ( __MKSMALLINT(SIGPROF) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigPWR
"return the signal number for SIGPWR - 0 if not supported
(not available on all systems)"
%{ /* NOCONTEXT */
#if defined(SIGPWR)
RETURN ( __MKSMALLINT(SIGPWR) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigQUIT
"return the signal number for SIGQUIT
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGQUIT
RETURN ( __MKSMALLINT(SIGQUIT) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigRETRACT
"return the signal number for SIGRETRACT - 0 if not supported
(seems to be an AIX special)"
%{ /* NOCONTEXT */
#if defined(SIGRETRACT)
RETURN ( __MKSMALLINT(SIGRETRACT) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigSAK
"return the signal number for SIGSAK - 0 if not supported
(seems to be an AIX special)"
%{ /* NOCONTEXT */
#if defined(SIGSAK)
RETURN ( __MKSMALLINT(SIGSAK) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigSEGV
"return the signal number for SIGSEGV - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGSEGV
RETURN ( __MKSMALLINT(SIGSEGV) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigSOUND
"return the signal number for SIGSOUND - 0 if not supported
(seems to be an AIX special)"
%{ /* NOCONTEXT */
#if defined(SIGSOUND)
RETURN ( __MKSMALLINT(SIGSOUND) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigSTOP
"return the signal number for SIGSTOP - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGSTOP)
RETURN ( __MKSMALLINT(SIGSTOP) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigSYS
"return the signal number for SIGSYS - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGSYS
RETURN ( __MKSMALLINT(SIGSYS) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigTERM
"return the signal number for SIGTERM - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGTERM
RETURN ( __MKSMALLINT(SIGTERM) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigTRAP
"return the signal number for SIGTRAP - 0 if not supported by OS
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#ifdef SIGTRAP
RETURN ( __MKSMALLINT(SIGTRAP) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigTSTP
"return the signal number for SIGTSTP - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGTSTP)
RETURN ( __MKSMALLINT(SIGTSTP) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigTTIN
"return the signal number for SIGTTIN - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGTTIN)
RETURN ( __MKSMALLINT(SIGTTIN) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigTTOU
"return the signal number for SIGTTOU - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGTTOU)
RETURN ( __MKSMALLINT(SIGTTOU) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigURG
"return the signal number for SIGURG - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGURG)
RETURN ( __MKSMALLINT(SIGURG) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigUSR1
"return the signal number for SIGUSR1 - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGUSR1)
RETURN ( __MKSMALLINT(SIGUSR1) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigUSR2
"return the signal number for SIGUSR2 - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGUSR2)
RETURN ( __MKSMALLINT(SIGUSR2) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigVTALRM
"return the signal number for SIGVTALRM - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGVTALRM)
RETURN ( __MKSMALLINT(SIGVTALRM) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigWINCH
"return the signal number for SIGWINCH - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGWINCH)
RETURN ( __MKSMALLINT(SIGWINCH) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigXCPU
"return the signal number for SIGXCPU - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGXCPU)
RETURN ( __MKSMALLINT(SIGXCPU) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
!
sigXFSZ
"return the signal number for SIGXFSZ - 0 if not supported
(the numeric value is not the same across unix-systems)"
%{ /* NOCONTEXT */
#if defined(SIGXFSZ)
RETURN ( __MKSMALLINT(SIGXFSZ) );
#else
RETURN ( __MKSMALLINT(0) );
#endif
%}
! !
!Win32OperatingSystem class methodsFor:'error messages'!
currentErrorNumber
"returns the OS's last error nr (i.e. the value of errno).
Notice, that the value of this flag is only valid immediately
after the error occurred - it gets updated with every other
request to the OS.
Use lastErrorNumber - currentErrorNumber is invalidated by
many, many internal calls."
%{ /* NOCONTEXT */
RETURN ( __MKSMALLINT(__threadErrno) );
%}
"
OperatingSystem currentErrorNumber
"
!
errorHolderForNumber:errNr
"return an osErrorHolder for the given error number (as returned by a system call)."
|sym typ holder|
%{
/* claus:
* I made this primitive code, since errnos are not
* standard across unixes
*/
typ = @symbol(defaultOsErrorSignal);
sym = @symbol(ERROR_OTHER);
if (__isSmallInteger(errNr)) {
int __eno = __intVal(errNr);
if (__isWIN32Error(__eno)) {
switch (__eno & 0xFFFF) {
/*
* WIN32 GetLastError returns
*/
case ERROR_INVALID_FUNCTION:
sym = @symbol(ERROR_INVALID_FUNCTION);
typ = @symbol(illegalOperationSignal);
break;
case ERROR_BAD_FORMAT:
sym = @symbol(ERROR_BAD_FORMAT);
typ = @symbol(invalidArgumentsSignal);
break;
case ERROR_FILE_NOT_FOUND:
sym = @symbol(ERROR_FILE_NOT_FOUND);
typ = @symbol(nonexistentSignal);
break;
case ERROR_PATH_NOT_FOUND:
sym = @symbol(ERROR_PATH_NOT_FOUND);
typ = @symbol(nonexistentSignal);
break;
case ERROR_TOO_MANY_OPEN_FILES:
sym = @symbol(ERROR_TOO_MANY_OPEN_FILES);
typ = @symbol(noResourcesSignal);
break;
/*
* what a nice errorCode - thats the most "useful" one I ever
* encountered ... (... those stupid micro-softies ...)
*/
case ERROR_OPEN_FAILED:
sym = @symbol(ERROR_OPEN_FAILED);
typ = @symbol(noResourcesSignal);
break;
case ERROR_ACCESS_DENIED:
sym = @symbol(ERROR_ACCESS_DENIED);
typ = @symbol(noPermissionsSignal);
break;
case ERROR_INVALID_HANDLE:
sym = @symbol(ERROR_INVALID_HANDLE);
typ = @symbol(invalidArgumentsSignal);
break;
case ERROR_NOT_ENOUGH_MEMORY:
sym = @symbol(ERROR_NOT_ENOUGH_MEMORY);
typ = @symbol(noResourcesSignal);
break;
case ERROR_INVALID_ACCESS:
sym = @symbol(ERROR_INVALID_ACCESS);
typ = @symbol(inappropriateOperationSignal);
break;
case ERROR_INVALID_DATA:
sym = @symbol(ERROR_INVALID_DATA);
typ = @symbol(invalidArgumentsSignal);
break;
case ERROR_INVALID_NAME:
sym = @symbol(ERROR_INVALID_NAME);
typ = @symbol(invalidArgumentsSignal);
break;
case ERROR_ARENA_TRASHED:
sym = @symbol(ERROR_ARENA_TRASHED);
typ = @symbol(noResourcesSignal);
break;
case ERROR_OUTOFMEMORY:
sym = @symbol(ERROR_OUTOFMEMORY);
typ = @symbol(noResourcesSignal);
break;
case ERROR_BROKEN_PIPE:
sym = @symbol(ERROR_BROKEN_PIPE);
typ = @symbol(peerFaultSignal);
break;
case ERROR_GEN_FAILURE:
sym = @symbol(ERROR_GEN_FAILURE);
break;
case ERROR_WRITE_PROTECT:
sym = @symbol(ERROR_WRITE_PROTECT);
typ = @symbol(inappropriateOperationSignal);
break;
case ERROR_WRITE_FAULT:
sym = @symbol(ERROR_WRITE_FAULT);
typ = @symbol(transferFaultSignal);
break;
case ERROR_READ_FAULT:
sym = @symbol(ERROR_READ_FAULT);
typ = @symbol(transferFaultSignal);
break;
case ERROR_HANDLE_DISK_FULL:
sym = @symbol(ERROR_HANDLE_DISK_FULL);
typ = @symbol(volumeFullSignal);
break;
case ERROR_DISK_FULL:
sym = @symbol(ERROR_DISK_FULL);
typ = @symbol(volumeFullSignal);
break;
case ERROR_SHARING_VIOLATION:
sym = @symbol(ERROR_SHARING_VIOLATION);
typ = @symbol(noPermissionsSignal);
break;
case ERROR_LOCK_VIOLATION:
sym = @symbol(ERROR_LOCK_VIOLATION);
typ = @symbol(noPermissionsSignal);
break;
case ERROR_INVALID_PARAMETER:
sym = @symbol(ERROR_INVALID_PARAMETER);
typ = @symbol(invalidArgumentsSignal);
break;
case ERROR_NET_WRITE_FAULT:
sym = @symbol(ERROR_NET_WRITE_FAULT);
typ = @symbol(transferFaultSignal);
break;
case ERROR_NOT_SUPPORTED:
sym = @symbol(ERROR_NOT_SUPPORTED);
typ = @symbol(inappropriateOperationSignal);
break;
case ERROR_REM_NOT_LIST:
sym = @symbol(ERROR_REM_NOT_LIST);
typ = @symbol(noResourcesSignal);
break;
case ERROR_NETWORK_ACCESS_DENIED:
sym = @symbol(ERROR_NETWORK_ACCESS_DENIED);
typ = @symbol(noPermissionsSignal);
break;
case ERROR_DUP_NAME:
sym = @symbol(ERROR_DUP_NAME);
typ = @symbol(noResourcesSignal);
break;
case ERROR_BAD_NETPATH:
sym = @symbol(ERROR_BAD_NETPATH);
typ = @symbol(noResourcesSignal);
break;
case ERROR_NETWORK_BUSY:
sym = @symbol(ERROR_NETWORK_BUSY);
typ = @symbol(noResourcesSignal);
break;
case ERROR_DRIVE_LOCKED:
sym = @symbol(ERROR_DRIVE_LOCKED);
typ = @symbol(inappropriateOperationSignal);
break;
case ERROR_INVALID_DRIVE:
sym = @symbol(ERROR_INVALID_DRIVE);
typ = @symbol(invalidArgumentsSignal);
break;
case ERROR_WRONG_DISK:
sym = @symbol(ERROR_WRONG_DISK);
typ = @symbol(noResourcesSignal);
break;
case ERROR_CURRENT_DIRECTORY:
sym = @symbol(ERROR_CURRENT_DIRECTORY);
typ = @symbol(invalidArgumentsSignal);
break;
/*
* what a nice errorCode - thats the most "useful" one I ever
* encountered ... (... those stupid micro-softies ...)
*/
case ERROR_CANNOT_MAKE:
sym = @symbol(ERROR_CANNOT_MAKE);
typ = @symbol(inappropriateOperationSignal);
break;
case ERROR_NO_MORE_FILES:
sym = @symbol(ERROR_NO_MORE_FILES);
typ = @symbol(noResourcesSignal);
break;
case ERROR_NOT_READY:
sym = @symbol(ERROR_NOT_READY);
typ = @symbol(noResourcesSignal);
break;
case ERROR_NOT_DOS_DISK:
sym = @symbol(ERROR_NOT_DOS_DISK);
typ = @symbol(invalidArgumentsSignal);
break;
case ERROR_OUT_OF_PAPER:
sym = @symbol(ERROR_OUT_OF_PAPER);
typ = @symbol(noResourcesSignal);
break;
case ERROR_PRINTQ_FULL:
sym = @symbol(ERROR_PRINTQ_FULL);
typ = @symbol(noResourcesSignal);
break;
default:
sym = nil;
break;
}
} else {
switch (__eno) {
/*
* POSIX errnos - these should be defined
*/
#ifdef EPERM
case EPERM:
sym = @symbol(EPERM);
typ = @symbol(noPermissionsSignal);
break;
#endif
#ifdef ENOENT
case ENOENT:
sym = @symbol(ENOENT);
typ = @symbol(nonexistentSignal);
break;
#endif
#ifdef ESRCH
case ESRCH:
sym = @symbol(ESRCH);
typ = @symbol(unavailableReferentSignal);
break;
#endif
#ifdef EINTR
case EINTR:
sym = @symbol(EINTR);
typ = @symbol(transientErrorSignal);
break;
#endif
#ifdef EIO
case EIO:
sym = @symbol(EIO);
typ = @symbol(transferFaultSignal);
break;
#endif
#ifdef ENXIO
case ENXIO:
sym = @symbol(ENXIO);
typ = @symbol(unavailableReferentSignal);
break;
#endif
#ifdef E2BIG
case E2BIG:
sym = @symbol(E2BIG);
typ = @symbol(invalidArgumentsSignal);
break;
#endif
#ifdef ENOEXEC
case ENOEXEC:
sym = @symbol(ENOEXEC);
typ = @symbol(inappropriateOperationSignal);
break;
#endif
#ifdef EBADF
case EBADF:
sym = @symbol(EBADF);
typ = @symbol(badAccessorSignal);
break;
#endif
#ifdef ECHILD
case ECHILD:
sym = @symbol(ECHILD);
typ = @symbol(informationSignal);
break;
#endif
#if !defined(EWOULDBLOCK) && defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
case EAGAIN:
sym = @symbol(EAGAIN);
typ = @symbol(notReadySignal);
break;
#endif
#ifdef ENOMEM
case ENOMEM:
sym = @symbol(ENOMEM);
typ = @symbol(noMemorySignal);
break;
#endif
#ifdef EACCES
case EACCES:
sym = @symbol(EACCES);
typ = @symbol(noPermissionsSignal);
break;
#endif
#ifdef EFAULT
case EFAULT:
sym = @symbol(EFAULT);
typ = @symbol(invalidArgumentsSignal);
break;
#endif
#ifdef EBUSY
case EBUSY:
sym = @symbol(EBUSY);
typ = @symbol(unavailableReferentSignal);
break;
#endif
#ifdef EEXIST
case EEXIST:
sym = @symbol(EEXIST);
typ = @symbol(existingReferentSignal);
break;
#endif
#ifdef EXDEV
case EXDEV:
sym = @symbol(EXDEV);
typ = @symbol(inappropriateReferentSignal);
break;
#endif
#ifdef ENODEV
case ENODEV:
sym = @symbol(ENODEV);
typ = @symbol(inaccessibleSignal);
break;
#endif
#ifdef ENOTDIR
case ENOTDIR:
sym = @symbol(ENOTDIR);
typ = @symbol(inappropriateOperationSignal);
break;
#endif
#ifdef EISDIR
case EISDIR:
sym = @symbol(EISDIR);
typ = @symbol(inappropriateOperationSignal);
break;
#endif
#ifdef EINVAL
case EINVAL:
sym = @symbol(EINVAL);
typ = @symbol(invalidArgumentsSignal);
break;
#endif
#ifdef ENFILE
case ENFILE:
sym = @symbol(ENFILE);
typ = @symbol(noResourcesSignal);
break;
#endif
#ifdef EMFILE
case EMFILE:
sym = @symbol(EMFILE);
typ = @symbol(noResourcesSignal);
break;
#endif
#ifdef ENOTTY
case ENOTTY:
sym = @symbol(ENOTTY);
typ = @symbol(inappropriateOperationSignal);
break;
#endif
#ifdef EFBIG
case EFBIG:
sym = @symbol(EFBIG);
typ = @symbol(noResourcesSignal);
break;
#endif
#ifdef ENOSPC
case ENOSPC:
sym = @symbol(ENOSPC);
typ = @symbol(noResourcesSignal);
break;
#endif
#ifdef ESPIPE
case ESPIPE:
sym = @symbol(ESPIPE);
typ = @symbol(inappropriateOperationSignal);
break;
#endif
#ifdef EROFS
case EROFS:
sym = @symbol(EROFS);
typ = @symbol(inappropriateOperationSignal);
break;
#endif
#ifdef EMLINK
case EMLINK:
sym = @symbol(EMLINK);
typ = @symbol(rangeErrorSignal);
break;
#endif
#ifdef EPIPE
case EPIPE:
sym = @symbol(EPIPE);
typ = @symbol(peerFaultSignal);
break;
#endif
#ifdef EDOM
case EDOM:
sym = @symbol(EDOM);
typ = @symbol(rangeErrorSignal);
break;
#endif
#ifdef ERANGE
case ERANGE:
sym = @symbol(ERANGE);
typ = @symbol(rangeErrorSignal);
break;
#endif
#ifdef EDEADLK
# if EDEADLK != EWOULDBLOCK
case EDEADLK:
sym = @symbol(EDEADLK);
typ = @symbol(noResourcesSignal);
break;
# endif
#endif
#ifdef ENAMETOOLONG
case ENAMETOOLONG:
sym = @symbol(ENAMETOOLONG);
typ = @symbol(rangeErrorSignal);
break;
#endif
#ifdef ENOLCK
case ENOLCK:
sym = @symbol(ENOLCK);
typ = @symbol(inappropriateOperationSignal);
break;
#endif
#ifdef ENOSYS
case ENOSYS:
sym = @symbol(ENOSYS);
typ = @symbol(inappropriateOperationSignal);
break;
#endif
#if defined(ENOTEMPTY) && (ENOTEMPTY != EEXIST)
case ENOTEMPTY:
sym = @symbol(ENOTEMPTY);
typ = @symbol(inappropriateReferentSignal);
break;
#endif
#ifdef EILSEQ
case EILSEQ:
sym = @symbol(EILSEQ);
typ = @symbol(transferFaultSignal);
break;
#endif
/*
* XPG3 errnos - defined on most systems
*/
#ifdef ENOTBLK
case ENOTBLK:
sym = @symbol(ENOTBLK);
typ = @symbol(inappropriateReferentSignal);
break;
#endif
#ifdef ETXTBSY
case ETXTBSY:
sym = @symbol(ETXTBSY);
typ = @symbol(inaccessibleSignal);
break;
#endif
/*
* some others
*/
#ifdef EWOULDBLOCK
case EWOULDBLOCK:
sym = @symbol(EWOULDBLOCK);
typ = @symbol(notReadySignal);
break;
#endif
#ifdef ENOMSG
case ENOMSG:
sym = @symbol(ENOMSG);
typ = @symbol(noDataSignal);
break;
#endif
#ifdef ELOOP
case ELOOP:
sym = @symbol(ELOOP);
typ = @symbol(rangeErrorSignal);
break;
#endif
/*
* some stream errors
*/
#ifdef ETIME
case ETIME:
sym = @symbol(ETIME);
typ = @symbol(peerFaultSignal);
break;
#endif
#ifdef ENOSR
case ENOSR:
sym = @symbol(ENOSR);
typ = @symbol(noResourcesSignal);
break;
#endif
#ifdef ENOSTR
case ENOSTR:
sym = @symbol(ENOSTR);
typ = @symbol(inappropriateReferentSignal);
break;
#endif
#ifdef ECOMM
case ECOMM:
sym = @symbol(ECOMM);
typ = @symbol(transferFaultSignal);
break;
#endif
#ifdef EPROTO
case EPROTO:
sym = @symbol(EPROTO);
typ = @symbol(inappropriateOperationSignal);
break;
#endif
/*
* nfs errors
*/
#ifdef ESTALE
case ESTALE:
sym = @symbol(ESTALE);
typ = @symbol(unavailableReferentSignal);
break;
#endif
#ifdef EREMOTE
case EREMOTE:
sym = @symbol(EREMOTE);
typ = @symbol(rangeErrorSignal);
break;
#endif
/*
* some networking errors
*/
#ifdef EINPROGRESS
case EINPROGRESS:
sym = @symbol(EINPROGRESS);
typ = @symbol(operationStartedSignal);
break;
#endif
#ifdef EALREADY
case EALREADY:
sym = @symbol(EALREADY);
typ = @symbol(operationStartedSignal);
break;
#endif
#ifdef ENOTSOCK
case ENOTSOCK:
sym = @symbol(ENOTSOCK);
typ = @symbol(inappropriateOperationSignal);
break;
#endif
#ifdef EDESTADDRREQ
case EDESTADDRREQ:
sym = @symbol(EDESTADDRREQ);
typ = @symbol(underspecifiedSignal);
break;
#endif
#ifdef EMSGSIZE
case EMSGSIZE:
sym = @symbol(EMSGSIZE);
typ = @symbol(rangeErrorSignal);
break;
#endif
#ifdef EPROTOTYPE
case EPROTOTYPE:
sym = @symbol(EPROTOTYPE);
typ = @symbol(wrongSubtypeForOperationSignal);
break;
#endif
#ifdef ENOPROTOOPT
case ENOPROTOOPT:
sym = @symbol(ENOPROTOOPT);
typ = @symbol(unsupportedOperationSignal);
break;
#endif
#ifdef EPROTONOSUPPORT
case EPROTONOSUPPORT:
sym = @symbol(EPROTONOSUPPORT);
typ = @symbol(unsupportedOperationSignal);
break;
#endif
#ifdef ESOCKTNOSUPPORT
case ESOCKTNOSUPPORT:
sym = @symbol(ESOCKTNOSUPPORT);
typ = @symbol(unsupportedOperationSignal);
break;
#endif
#ifdef EOPNOTSUPP
case EOPNOTSUPP:
sym = @symbol(EOPNOTSUPP);
typ = @symbol(inappropriateOperationSignal);
break;
#endif
#ifdef EPFNOSUPPORT
case EPFNOSUPPORT:
sym = @symbol(EPFNOSUPPORT);
typ = @symbol(unsupportedOperationSignal);
break;
#endif
#ifdef EAFNOSUPPORT
case EAFNOSUPPORT:
sym = @symbol(EAFNOSUPPORT);
typ = @symbol(unsupportedOperationSignal);
break;
#endif
#ifdef EADDRINUSE
case EADDRINUSE:
sym = @symbol(EADDRINUSE);
typ = @symbol(existingReferentSignal);
break;
#endif
#ifdef EADDRNOTAVAIL
case EADDRNOTAVAIL:
sym = @symbol(EADDRNOTAVAIL);
typ = @symbol(noPermissionsSignal);
break;
#endif
#ifdef ETIMEDOUT
case ETIMEDOUT:
sym = @symbol(ETIMEDOUT);
typ = @symbol(peerFaultSignal);
break;
#endif
#ifdef ECONNREFUSED
case ECONNREFUSED:
sym = @symbol(ECONNREFUSED);
typ = @symbol(peerFaultSignal);
break;
#endif
#ifdef ENETDOWN
case ENETDOWN:
sym = @symbol(ENETDOWN);
typ = @symbol(peerFaultSignal);
break;
#endif
#ifdef ENETUNREACH
case ENETUNREACH:
sym = @symbol(ENETUNREACH);
typ = @symbol(peerFaultSignal);
break;
#endif
#ifdef ENETRESET
case ENETRESET:
sym = @symbol(ENETRESET);
typ = @symbol(peerFaultSignal);
break;
#endif
#ifdef ECONNABORTED
case ECONNABORTED:
sym = @symbol(ECONNABORTED);
typ = @symbol(peerFaultSignal);
break;
#endif
#ifdef ECONNRESET
case ECONNRESET:
sym = @symbol(ECONNRESET);
typ = @symbol(peerFaultSignal);
break;
#endif
#ifdef EISCONN
case EISCONN:
sym = @symbol(EISCONN);
typ = @symbol(unpreparedOperationSignal);
break;
#endif
#ifdef ENOTCONN
case ENOTCONN:
sym = @symbol(ENOTCONN);
typ = @symbol(unpreparedOperationSignal);
break;
#endif
#ifdef ESHUTDOWN
case ESHUTDOWN:
sym = @symbol(ESHUTDOWN);
typ = @symbol(unpreparedOperationSignal);
break;
#endif
#ifdef EHOSTDOWN
case EHOSTDOWN:
sym = @symbol(EHOSTDOWN);
typ = @symbol(peerFaultSignal);
break;
#endif
#ifdef EHOSTUNREACH
case EHOSTUNREACH:
sym = @symbol(EHOSTUNREACH);
typ = @symbol(peerFaultSignal);
break;
#endif
#ifdef WSAEFAULT
case WSAEFAULT:
sym = @symbol(WSAEFAULT);
typ = @symbol(invalidArgumentsSignal);
break;
#endif
#ifdef WSAEINTR
case WSAEINTR:
sym = @symbol(WSAEINTR);
typ = @symbol(transientErrorSignal);
break;
#endif
#ifdef WSAEBADF
case WSAEBADF:
sym = @symbol(WSAEBADF);
typ = @symbol(badAccessorSignal);
break;
#endif
#ifdef WSAEACCESS
case WSAEACCESS:
sym = @symbol(WSAEACCESS);
typ = @symbol(badAccessorSignal);
break;
#endif
#ifdef WSAEINVAL
case WSAEINVAL:
sym = @symbol(WSAEINVAL);
typ = @symbol(invalidArgumentsSignal);
break;
#endif
#ifdef WSAEMFILE
case WSAEMFILE:
sym = @symbol(WSAEMFILE);
typ = @symbol(noResourcesSignal);
break;
#endif
#ifdef WSAEWOULDBLOCK
case WSAEWOULDBLOCK:
sym = @symbol(WSAEWOULDBLOCK);
typ = @symbol(notReadySignal);
break;
#endif
#ifdef WSAEINPROGRESS
case WSAEINPROGRESS:
sym = @symbol(WSAEINPROGRESS);
typ = @symbol(operationStartedSignal);
break;
#endif
#ifdef WSAEALREADY
case WSAEALREADY:
sym = @symbol(WSAEALREADY);
typ = @symbol(operationStartedSignal);
break;
#endif
#ifdef WSAENOTSOCK
case WSAENOTSOCK:
sym = @symbol(WSAENOTSOCK);
typ = @symbol(inappropriateOperationSignal);
break;
#endif
#ifdef WSAEPROTONOSUPPORT
case WSAEPROTONOSUPPORT:
sym = @symbol(WSAEPROTONOSUPPORT);
typ = @symbol(unsupportedOperationSignal);
break;
#endif
#ifdef WSAESOCKTNOSUPPORT
case WSAESOCKTNOSUPPORT:
sym = @symbol(WSAESOCKTNOSUPPORT);
typ = @symbol(unsupportedOperationSignal);
break;
#endif
default:
break;
}
}
}
%}.
holder := OSErrorHolder new.
holder errorSymbol:sym errorCategory:typ.
^ holder
"
OperatingSystem errorHolderForNumber:4
self errorHolderForNumber:(self errorNumberFor:#EPERM)
self errorHolderForNumber:(self errorNumberFor:#EIO)
self errorHolderForNumber:(self errorNumberFor:#ENXIO)
"
!
errorNumberFor:aSymbol
"given a symbolic error, return the numeric;
(i.e. errorNumberFor:#EBADF returns EBADF's value).
Use this, since error numbers are really not standard across unix systems."
%{ /* NOCONTEXT */
OBJ sym = aSymbol;
/*
* WIN32 GetLastError returns
*/
#ifdef ERROR_INVALID_FUNCTION
if (sym == @symbol(ERROR_INVALID_FUNCTION)) {
RETURN ( __MKSMALLINT(ERROR_INVALID_FUNCTION) );
}
#endif
#ifdef ERROR_BAD_FORMAT
if (sym == @symbol(ERROR_BAD_FORMAT)) {
RETURN ( __MKSMALLINT(ERROR_BAD_FORMAT) );
}
#endif
#ifdef ERROR_FILE_NOT_FOUND
if (sym == @symbol(ERROR_FILE_NOT_FOUND)) {
RETURN ( __MKSMALLINT(ERROR_FILE_NOT_FOUND) );
}
#endif
#ifdef ERROR_PATH_NOT_FOUND
if (sym == @symbol(ERROR_PATH_NOT_FOUND)) {
RETURN ( __MKSMALLINT(ERROR_PATH_NOT_FOUND) );
}
#endif
#ifdef ERROR_TOO_MANY_OPEN_FILES
if (sym == @symbol(ERROR_TOO_MANY_OPEN_FILES)) {
RETURN ( __MKSMALLINT(ERROR_TOO_MANY_OPEN_FILES) );
}
#endif
#ifdef ERROR_OPEN_FAILED
if (sym == @symbol(ERROR_OPEN_FAILED)) {
RETURN ( __MKSMALLINT(ERROR_OPEN_FAILED) );
}
#endif
#ifdef ERROR_ACCESS_DENIED
if (sym == @symbol(ERROR_ACCESS_DENIED)) {
RETURN ( __MKSMALLINT(ERROR_ACCESS_DENIED) );
}
#endif
#ifdef ERROR_INVALID_HANDLE
if (sym == @symbol(ERROR_INVALID_HANDLE)) {
RETURN ( __MKSMALLINT(ERROR_INVALID_HANDLE) );
}
#endif
#ifdef ERROR_NOT_ENOUGH_MEMORY
if (sym == @symbol(ERROR_NOT_ENOUGH_MEMORY)) {
RETURN ( __MKSMALLINT(ERROR_NOT_ENOUGH_MEMORY) );
}
#endif
#ifdef ERROR_INVALID_ACCESS
if (sym == @symbol(ERROR_INVALID_ACCESS)) {
RETURN ( __MKSMALLINT(ERROR_INVALID_ACCESS) );
}
#endif
#ifdef ERROR_INVALID_DATA
if (sym == @symbol(ERROR_INVALID_DATA)) {
RETURN ( __MKSMALLINT(ERROR_INVALID_DATA) );
}
#endif
#ifdef ERROR_INVALID_NAME
if (sym == @symbol(ERROR_INVALID_NAME)) {
RETURN ( __MKSMALLINT(ERROR_INVALID_NAME) );
}
#endif
#ifdef ERROR_ARENA_TRASHED
if (sym == @symbol(ERROR_ARENA_TRASHED)) {
RETURN ( __MKSMALLINT(ERROR_ARENA_TRASHED) );
}
#endif
#ifdef ERROR_OUTOFMEMORY
if (sym == @symbol(ERROR_OUTOFMEMORY)) {
RETURN ( __MKSMALLINT(ERROR_OUTOFMEMORY) );
}
#endif
#ifdef ERROR_BROKEN_PIPE
if (sym == @symbol(ERROR_BROKEN_PIPE)) {
RETURN ( __MKSMALLINT(ERROR_BROKEN_PIPE) );
}
#endif
#ifdef ERROR_GEN_FAILURE
if (sym == @symbol(ERROR_GEN_FAILURE)) {
RETURN ( __MKSMALLINT(ERROR_GEN_FAILURE) );
}
#endif
#ifdef ERROR_WRITE_PROTECT
if (sym == @symbol(ERROR_WRITE_PROTECT)) {
RETURN ( __MKSMALLINT(ERROR_WRITE_PROTECT) );
}
#endif
#ifdef ERROR_WRITE_FAULT
if (sym == @symbol(ERROR_WRITE_FAULT)) {
RETURN ( __MKSMALLINT(ERROR_WRITE_FAULT) );
}
#endif
#ifdef ERROR_READ_FAULT
if (sym == @symbol(ERROR_READ_FAULT)) {
RETURN ( __MKSMALLINT(ERROR_READ_FAULT) );
}
#endif
#ifdef ERROR_HANDLE_DISK_FULL
if (sym == @symbol(ERROR_HANDLE_DISK_FULL)) {
RETURN ( __MKSMALLINT(ERROR_HANDLE_DISK_FULL) );
}
#endif
#ifdef ERROR_DISK_FULL
if (sym == @symbol(ERROR_DISK_FULL)) {
RETURN ( __MKSMALLINT(ERROR_DISK_FULL) );
}
#endif
#ifdef ERROR_ERROR_SHARING_VIOLATION
if (sym == @symbol(ERROR_ERROR_SHARING_VIOLATION)) {
RETURN ( __MKSMALLINT(ERROR_ERROR_SHARING_VIOLATION) );
}
#endif
#ifdef ERROR_LOCK_VIOLATION
if (sym == @symbol(ERROR_LOCK_VIOLATION)) {
RETURN ( __MKSMALLINT(ERROR_LOCK_VIOLATION) );
}
#endif
#ifdef ERROR_INVALID_PARAMETER
if (sym == @symbol(ERROR_INVALID_PARAMETER)) {
RETURN ( __MKSMALLINT(ERROR_INVALID_PARAMETER) );
}
#endif
#ifdef ERROR_NET_WRITE_FAULT
if (sym == @symbol(ERROR_NET_WRITE_FAULT)) {
RETURN ( __MKSMALLINT(ERROR_NET_WRITE_FAULT) );
}
#endif
#ifdef ERROR_NOT_SUPPORTED
if (sym == @symbol(ERROR_NOT_SUPPORTED)) {
RETURN ( __MKSMALLINT(ERROR_NOT_SUPPORTED) );
}
#endif
#ifdef ERROR_REM_NOT_LIST
if (sym == @symbol(ERROR_REM_NOT_LIST)) {
RETURN ( __MKSMALLINT(ERROR_REM_NOT_LIST) );
}
#endif
#ifdef ERROR_NETWORK_ACCESS_DENIED
if (sym == @symbol(ERROR_NETWORK_ACCESS_DENIED)) {
RETURN ( __MKSMALLINT(ERROR_NETWORK_ACCESS_DENIED) );
}
#endif
#ifdef ERROR_DUP_NAME
if (sym == @symbol(ERROR_DUP_NAME)) {
RETURN ( __MKSMALLINT(ERROR_DUP_NAME) );
}
#endif
#ifdef ERROR_BAD_NETPATH
if (sym == @symbol(ERROR_BAD_NETPATH)) {
RETURN ( __MKSMALLINT(ERROR_BAD_NETPATH) );
}
#endif
#ifdef ERROR_NETWORK_BUSY
if (sym == @symbol(ERROR_NETWORK_BUSY)) {
RETURN ( __MKSMALLINT(ERROR_NETWORK_BUSY) );
}
#endif
#ifdef ERROR_DRIVE_LOCKED
if (sym == @symbol(ERROR_DRIVE_LOCKED)) {
RETURN ( __MKSMALLINT(ERROR_DRIVE_LOCKED) );
}
#endif
#ifdef ERROR_INVALID_DRIVE
if (sym == @symbol(ERROR_INVALID_DRIVE)) {
RETURN ( __MKSMALLINT(ERROR_INVALID_DRIVE) );
}
#endif
#ifdef ERROR_WRONG_DISK
if (sym == @symbol(ERROR_WRONG_DISK)) {
RETURN ( __MKSMALLINT(ERROR_WRONG_DISK) );
}
#endif
#ifdef ERROR_CURRENT_DIRECTORY
if (sym == @symbol(ERROR_CURRENT_DIRECTORY)) {
RETURN ( __MKSMALLINT(ERROR_CURRENT_DIRECTORY) );
}
#endif
#ifdef ERROR_CANNOT_MAKE
if (sym == @symbol(ERROR_CANNOT_MAKE)) {
RETURN ( __MKSMALLINT(ERROR_CANNOT_MAKE) );
}
#endif
#ifdef ERROR_NO_MORE_FILES
if (sym == @symbol(ERROR_NO_MORE_FILES)) {
RETURN ( __MKSMALLINT(ERROR_NO_MORE_FILES) );
}
#endif
#ifdef ERROR_NOT_READY
if (sym == @symbol(ERROR_NOT_READY)) {
RETURN ( __MKSMALLINT(ERROR_NOT_READY) );
}
#endif
#ifdef ERROR_NOT_DOS_DISK
if (sym == @symbol(ERROR_NOT_DOS_DISK)) {
RETURN ( __MKSMALLINT(ERROR_NOT_DOS_DISK) );
}
#endif
#ifdef ERROR_OUT_OF_PAPER
if (sym == @symbol(ERROR_OUT_OF_PAPER)) {
RETURN ( __MKSMALLINT(ERROR_OUT_OF_PAPER) );
}
#endif
#ifdef ERROR_PRINTQ_FULL
if (sym == @symbol(ERROR_PRINTQ_FULL)) {
RETURN ( __MKSMALLINT(ERROR_PRINTQ_FULL) );
}
#endif
/*
* POSIX errnos - these should be defined
*/
#ifdef EPERM
if (sym == @symbol(EPERM)) {
RETURN ( __MKSMALLINT(EPERM) );
}
#endif
#ifdef ENOENT
if (sym == @symbol(ENOENT)) {
RETURN ( __MKSMALLINT(ENOENT) );
}
#endif
#ifdef ESRCH
if (sym == @symbol(ESRCH)) {
RETURN ( __MKSMALLINT(ESRCH) );
}
#endif
#ifdef EINTR
if (sym == @symbol(EINTR)) {
RETURN ( __MKSMALLINT(EINTR) );
}
#endif
#ifdef EIO
if (sym == @symbol(EIO)) {
RETURN ( __MKSMALLINT(EIO) );
}
#endif
#ifdef ENXIO
if (sym == @symbol(ENXIO)) {
RETURN ( __MKSMALLINT(ENXIO) );
}
#endif
#ifdef E2BIG
if (sym == @symbol(E2BIG)) {
RETURN ( __MKSMALLINT(E2BIG) );
}
#endif
#ifdef ENOEXEC
if (sym == @symbol(ENOEXEC)) {
RETURN ( __MKSMALLINT(ENOEXEC) );
}
#endif
#ifdef EBADF
if (sym == @symbol(EBADF)) {
RETURN ( __MKSMALLINT(EBADF) );
}
#endif
#ifdef ECHILD
if (sym == @symbol(ECHILD)) {
RETURN ( __MKSMALLINT(ECHILD) );
}
#endif
#if defined(EAGAIN)
if (sym == @symbol(EAGAIN)) {
RETURN ( __MKSMALLINT(EAGAIN) );
}
#endif
#ifdef ENOMEM
if (sym == @symbol(ENOMEM)) {
RETURN ( __MKSMALLINT(ENOMEM) );
}
#endif
#ifdef EACCES
if (sym == @symbol(EACCES)) {
RETURN ( __MKSMALLINT(EACCES) );
}
#endif
#ifdef EFAULT
if (sym == @symbol(EFAULT)) {
RETURN ( __MKSMALLINT(EFAULT) );
}
#endif
#ifdef EBUSY
if (sym == @symbol(EBUSY)) {
RETURN ( __MKSMALLINT(EBUSY) );
}
#endif
#ifdef EXDEV
if (sym == @symbol(EXDEV)) {
RETURN ( __MKSMALLINT(EXDEV) );
}
#endif
#ifdef ENODEV
if (sym == @symbol(ENODEV)) {
RETURN ( __MKSMALLINT(ENODEV) );
}
#endif
#ifdef ENOTDIR
if (sym == @symbol(ENOTDIR)) {
RETURN ( __MKSMALLINT(ENOTDIR) );
}
#endif
#ifdef EISDIR
if (sym == @symbol(EISDIR)) {
RETURN ( __MKSMALLINT(EISDIR) );
}
#endif
#ifdef EINVAL
if (sym == @symbol(EINVAL)) {
RETURN ( __MKSMALLINT(EINVAL) );
}
#endif
#ifdef ENFILE
if (sym == @symbol(ENFILE)) {
RETURN ( __MKSMALLINT(ENFILE) );
}
#endif
#ifdef EMFILE
if (sym == @symbol(EMFILE)) {
RETURN ( __MKSMALLINT(EMFILE) );
}
#endif
#ifdef ENOTTY
if (sym == @symbol(ENOTTY)) {
RETURN ( __MKSMALLINT(ENOTTY) );
}
#endif
#ifdef EFBIG
if (sym == @symbol(EFBIG)) {
RETURN ( __MKSMALLINT(EFBIG) );
}
#endif
#ifdef ENOSPC
if (sym == @symbol(ENOSPC)) {
RETURN ( __MKSMALLINT(ENOSPC) );
}
#endif
#ifdef ESPIPE
if (sym == @symbol(ESPIPE)) {
RETURN ( __MKSMALLINT(ESPIPE) );
}
#endif
#ifdef EROFS
if (sym == @symbol(EROFS)) {
RETURN ( __MKSMALLINT(EROFS) );
}
#endif
#ifdef EMLINK
if (sym == @symbol(EMLINK)) {
RETURN ( __MKSMALLINT(EMLINK) );
}
#endif
#ifdef EPIPE
if (sym == @symbol(EPIPE)) {
RETURN ( __MKSMALLINT(EPIPE) );
}
#endif
#ifdef EDOM
if (sym == @symbol(EDOM)) {
RETURN ( __MKSMALLINT(EDOM) );
}
#endif
#ifdef ERANGE
if (sym == @symbol(ERANGE)) {
RETURN ( __MKSMALLINT(ERANGE) );
}
#endif
#ifdef EDEADLK
if (sym == @symbol(EDEADLK)) {
RETURN ( __MKSMALLINT(EDEADLK) );
}
#endif
#ifdef ENAMETOOLONG
if (sym == @symbol(ENAMETOOLONG)) {
RETURN ( __MKSMALLINT(ENAMETOOLONG) );
}
#endif
#ifdef ENOLCK
if (sym == @symbol(ENOLCK)) {
RETURN ( __MKSMALLINT(ENOLCK) );
}
#endif
#ifdef ENOSYS
if (sym == @symbol(ENOSYS)) {
RETURN ( __MKSMALLINT(ENOSYS) );
}
#endif
#ifdef ENOTEMPTY
if (sym == @symbol(ENOTEMPTY)) {
RETURN ( __MKSMALLINT(ENOTEMPTY) );
}
#endif
#ifdef EEXIST
if (sym == @symbol(EEXIST)) {
RETURN ( __MKSMALLINT(EEXIST) );
}
#endif
#ifdef EILSEQ
if (sym == @symbol(EILSEQ)) {
RETURN ( __MKSMALLINT(EILSEQ) );
}
#endif
/*
* XPG3 errnos - defined on most systems
*/
#ifdef ENOTBLK
if (sym == @symbol(ENOTBLK)) {
RETURN ( __MKSMALLINT(ENOTBLK) );
}
#endif
#ifdef ETXTBSY
if (sym == @symbol(ETXTBSY)) {
RETURN ( __MKSMALLINT(ETXTBSY) );
}
#endif
/*
* some others
*/
#ifdef EWOULDBLOCK
if (sym == @symbol(EWOULDBLOCK)) {
RETURN ( __MKSMALLINT(EWOULDBLOCK) );
}
#endif
#ifdef ENOMSG
if (sym == @symbol(ENOMSG)) {
RETURN ( __MKSMALLINT(ENOMSG) );
}
#endif
#ifdef ELOOP
if (sym == @symbol(ELOOP)) {
RETURN ( __MKSMALLINT(ELOOP) );
}
#endif
/*
* some stream errors
*/
#ifdef ETIME
if (sym == @symbol(ETIME)) {
RETURN ( __MKSMALLINT(ETIME) );
}
#endif
#ifdef ENOSR
if (sym == @symbol(ENOSR)) {
RETURN ( __MKSMALLINT(ENOSR) );
}
#endif
#ifdef ENOSTR
if (sym == @symbol(ENOSTR)) {
RETURN ( __MKSMALLINT(ENOSTR) );
}
#endif
#ifdef ECOMM
if (sym == @symbol(ECOMM)) {
RETURN ( __MKSMALLINT(ECOMM) );
}
#endif
#ifdef EPROTO
if (sym == @symbol(EPROTO)) {
RETURN ( __MKSMALLINT(EPROTO) );
}
#endif
/*
* nfs errors
*/
#ifdef ESTALE
if (sym == @symbol(ESTALE)) {
RETURN ( __MKSMALLINT(ESTALE) );
}
#endif
#ifdef EREMOTE
if (sym == @symbol(EREMOTE)) {
RETURN ( __MKSMALLINT(EREMOTE) );
}
#endif
/*
* some networking errors
*/
#ifdef EINPROGRESS
if (sym == @symbol(EINPROGRESS)) {
RETURN ( __MKSMALLINT(EINPROGRESS) );
}
#endif
#ifdef EALREADY
if (sym == @symbol(EALREADY)) {
RETURN ( __MKSMALLINT(EALREADY) );
}
#endif
#ifdef ENOTSOCK
if (sym == @symbol(ENOTSOCK)) {
RETURN ( __MKSMALLINT(ENOTSOCK) );
}
#endif
#ifdef EDESTADDRREQ
if (sym == @symbol(EDESTADDRREQ)) {
RETURN ( __MKSMALLINT(EDESTADDRREQ) );
}
#endif
#ifdef EMSGSIZE
if (sym == @symbol(EMSGSIZE)) {
RETURN ( __MKSMALLINT(EMSGSIZE) );
}
#endif
#ifdef EPROTOTYPE
if (sym == @symbol(EPROTOTYPE)) {
RETURN ( __MKSMALLINT(EPROTOTYPE) );
}
#endif
#ifdef ENOPROTOOPT
if (sym == @symbol(ENOPROTOOPT)) {
RETURN ( __MKSMALLINT(ENOPROTOOPT) );
}
#endif
#ifdef EPROTONOSUPPORT
if (sym == @symbol(EPROTONOSUPPORT)) {
RETURN ( __MKSMALLINT(EPROTONOSUPPORT) );
}
#endif
#ifdef ESOCKTNOSUPPORT
if (sym == @symbol(ESOCKTNOSUPPORT)) {
RETURN ( __MKSMALLINT(ESOCKTNOSUPPORT) );
}
#endif
#ifdef EOPNOTSUPP
if (sym == @symbol(EOPNOTSUPP)) {
RETURN ( __MKSMALLINT(EOPNOTSUPP) );
}
#endif
#ifdef EPFNOSUPPORT
if (sym == @symbol(EPFNOSUPPORT)) {
RETURN ( __MKSMALLINT(EPFNOSUPPORT) );
}
#endif
#ifdef EAFNOSUPPORT
if (sym == @symbol(EAFNOSUPPORT)) {
RETURN ( __MKSMALLINT(EAFNOSUPPORT) );
}
#endif
#ifdef EADDRINUSE
if (sym == @symbol(EADDRINUSE)) {
RETURN ( __MKSMALLINT(EADDRINUSE) );
}
#endif
#ifdef EADDRNOTAVAIL
if (sym == @symbol(EADDRNOTAVAIL)) {
RETURN ( __MKSMALLINT(EADDRNOTAVAIL) );
}
#endif
#ifdef ETIMEDOUT
if (sym == @symbol(ETIMEDOUT)) {
RETURN ( __MKSMALLINT(ETIMEDOUT) );
}
#endif
#ifdef ECONNREFUSED
if (sym == @symbol(ECONNREFUSED)) {
RETURN ( __MKSMALLINT(ECONNREFUSED) );
}
#endif
#ifdef ENETDOWN
if (sym == @symbol(ENETDOWN)) {
RETURN ( __MKSMALLINT(ENETDOWN) );
}
#endif
#ifdef ENETUNREACH
if (sym == @symbol(ENETUNREACH)) {
RETURN ( __MKSMALLINT(ENETUNREACH) );
}
#endif
#ifdef ENETRESET
if (sym == @symbol(ENETRESET)) {
RETURN ( __MKSMALLINT(ENETRESET) );
}
#endif
#ifdef ECONNABORTED
if (sym == @symbol(ECONNABORTED)) {
RETURN ( __MKSMALLINT(ECONNABORTED) );
}
#endif
#ifdef ECONNRESET
if (sym == @symbol(ECONNRESET)) {
RETURN ( __MKSMALLINT(ECONNRESET) );
}
#endif
#ifdef EISCONN
if (sym == @symbol(EISCONN)) {
RETURN ( __MKSMALLINT(EISCONN) );
}
#endif
#ifdef ENOTCONN
if (sym == @symbol(ENOTCONN)) {
RETURN ( __MKSMALLINT(ENOTCONN) );
}
#endif
#ifdef ESHUTDOWN
if (sym == @symbol(ESHUTDOWN)) {
RETURN ( __MKSMALLINT(ESHUTDOWN) );
}
#endif
#ifdef EHOSTDOWN
if (sym == @symbol(EHOSTDOWN)) {
RETURN ( __MKSMALLINT(EHOSTDOWN) );
}
#endif
#ifdef EHOSTUNREACH
if (sym == @symbol(EHOSTUNREACH)) {
RETURN ( __MKSMALLINT(EHOSTUNREACH) );
}
#endif
/*
* windows socket errors
*/
#ifdef WSAEINTR
if (sym == @symbol(WSAEINTR)) {
RETURN ( __MKSMALLINT(WSAEINTR) );
}
#endif
#ifdef WSAEBADF
if (sym == @symbol(WSAEBADF)) {
RETURN ( __MKSMALLINT(WSAEBADF) );
}
#endif
#ifdef WSAEACCESS
if (sym == @symbol(WSAEACCESS)) {
RETURN ( __MKSMALLINT(WSAEACCESS) );
}
#endif
#ifdef WSAEFAULT
if (sym == @symbol(WSAEFAULT)) {
RETURN ( __MKSMALLINT(WSAEFAULT) );
}
#endif
#ifdef WSAEINVAL
if (sym == @symbol(WSAEINVAL)) {
RETURN ( __MKSMALLINT(WSAEINVAL) );
}
#endif
#ifdef WSAEMFILE
if (sym == @symbol(WSAEMFILE)) {
RETURN ( __MKSMALLINT(WSAEMFILE) );
}
#endif
#ifdef WSAEWOULDBLOCK
if (sym == @symbol(WSAEWOULDBLOCK)) {
RETURN ( __MKSMALLINT(WSAEWOULDBLOCK) );
}
#endif
#ifdef WSAEINPROGRESS
if (sym == @symbol(WSAEINPROGRESS)) {
RETURN ( __MKSMALLINT(WSAEINPROGRESS) );
}
#endif
#ifdef WSAEALREADY
if (sym == @symbol(WSAEALREADY)) {
RETURN ( __MKSMALLINT(WSAEALREADY) );
}
#endif
#ifdef WSAENOTSOCK
if (sym == @symbol(WSAENOTSOCK)) {
RETURN ( __MKSMALLINT(WSAENOTSOCK) );
}
#endif
#ifdef WSAEPROTONOSUPPORT
if (sym == @symbol(WSAEPROTONOSUPPORT)) {
RETURN ( __MKSMALLINT(WSAEPROTONOSUPPORT) );
}
#endif
#ifdef WSAESOCKTNOSUPPORT
if (sym == @symbol(WSAESOCKTNOSUPPORT)) {
RETURN ( __MKSMALLINT(WSAESOCKTNOSUPPORT) );
}
#endif
%}.
^ -1
! !
!Win32OperatingSystem class methodsFor:'executing OS commands'!
canExecuteCommand:aCommandString
"return true, if the OS can execute aCommand."
"/ |fn|
"/
"/ fn := aCommandString asFilename.
"/ ( #('com' 'exe') includes:fn suffix) ifFalse:[^ false].
^ super canExecuteCommand:aCommandString
"
OperatingSystem canExecuteCommand:'fooBar'
OperatingSystem canExecuteCommand:'ls'
OperatingSystem canExecuteCommand:'cvs'
OperatingSystem canExecuteCommand:'diff'
OperatingSystem canExecuteCommand:'cvs.exe'
OperatingSystem canExecuteCommand:'C:\Dokumente und Einstellungen\penk\work\stx\projects\smalltalk\cvs.exe'
OperatingSystem canExecuteCommand:'C:\Windows\cvs.exe'
"
"Created: 4.11.1995 / 19:13:54 / cg"
!
commandAndArgsForOSCommand:aCommandString
"get a shell and shell arguments for command execution"
|shell args wDir path words hasRedirection|
"/
"/ 'x:\WINNT\System32\cmd /c <command>'
"/ or 'x:\WINDOWS\System32\cmd /c <command>'
"/ or 'x:\WINDOWS\System\cmd /c <command>'
"/ or whatever ...
"/
"/ to workaround a bug in win95's command.com
"/ (which always returns a 0-exit code
"/ - even if the command failed),
"/ Here, we see if the command is found along the path and
"/ call it directly if found.
"/ If not found, assume its a builtIn or batch command
"/ and pass it to command.com.
"/ Also use command.com, if any I/O redirection is
"/ involved, since that is (not yet) handled here.
"/
"/ I know: this is a kludge but should work for now...
"/ ...this will change in an upcoming version to include
"/ command.com command-line parsing here (sigh).
hasRedirection := false.
(aCommandString isNil or:[aCommandString includesAny:'<>|']) ifTrue:[
hasRedirection := true
].
self isMSWINDOWSNTlike ifTrue:[
hasRedirection ifFalse:[
|size name|
"/ test whether the commandString is an executable;
"/ then, no shell is required
name := aCommandString withoutSeparators.
(name notEmpty and:[(name startsWith:$") not]) ifTrue:[
|index file suffix|
index := name indexOfSeparatorStartingAt:1.
index ~~ 0 ifTrue:[
name := name copyFrom:1 to:(index -1).
].
file := name asFilename.
suffix := file suffix.
suffix isEmptyOrNil ifTrue:[
suffix := 'exe'.
file := file withSuffix:suffix.
].
(file exists and:[suffix = 'exe']) ifTrue:[
"/ is an executable, no shell required
^ Array with:nil with:aCommandString.
]
].
].
shell := self getEnvironment:'COMSPEC'.
shell isNil ifTrue:[
wDir := self getWindowsSystemDirectory asFilename.
shell := (wDir construct:'cmd.exe').
shell exists ifFalse:[
shell := (wDir construct:'command.com').
shell exists ifFalse:[
self error:'no command.com available'.
]
].
shell := shell pathName.
].
aCommandString isNil ifTrue:[
^ Array with:nil with:shell
].
^ Array with:nil with:(shell , ' /c ' , '"' , aCommandString , '"' )
].
"/ I/O redirection is not yet handled directly
"/ fallBack to command.com (below) to do it.
hasRedirection ifFalse:[
words := aCommandString asCollectionOfSubstringsSeparatedBy:Character space.
args := ' '.
words from:2 to:(words size) do:[:s |
args := args , (s , ' ').
].
path := self pathOfCommand:(words at:1).
path notNil ifTrue:[
"/ execute the command directly -
"/ without going through command.com
self isMSWINDOWSNTlike ifTrue:[
args := path , args.
].
^ Array with:path with:args
].
].
"/ I/O redirection or no executable was found
shell := self getEnvironment:'COMSPEC'.
shell isNil ifTrue:[
wDir := self getWindowsSystemDirectory asFilename.
shell := (wDir construct:'cmd.exe').
shell exists ifFalse:[
shell := (wDir construct:'command.com').
shell exists ifFalse:[
self error:'no command.com available'.
]
].
shell := shell pathName.
].
aCommandString isNil ifTrue:[
^ Array with:shell with:shell
].
^ Array with:shell with:(shell , ' /c ' , aCommandString)
"Modified: / 20-01-1998 / 16:57:19 / md"
"Modified: / 12-05-2004 / 12:47:06 / cg"
!
exec:aCommandPath withArguments:argString environment:environment fileDescriptors:fdArray fork:doFork newPgrp:newPgrp inDirectory:aDirectory
"Internal lowLevel entry for combined fork & exec for WIN32
If fork is false (chain a command):
execute the OS command specified by the argument, aCommandPath, with
arguments in argArray (no arguments, if nil).
If successful, this method does not return and smalltalk is gone.
If not successful, it does return.
Normal use is with forkForCommand.
If fork is true (subprocess command execution):
fork a child to do the above.
The process id of the child process is returned; nil if the fork failed.
fdArray contains the filedescriptors, to be used for the child (if fork is true).
fdArray[1] = 15 -> use fd 15 as stdin.
If an element of the array is set to nil, the corresponding filedescriptor
will be closed for the child.
fdArray[0] == StdIn for child
fdArray[1] == StdOut for child
fdArray[2] == StdErr for child
on VMS, these must be channels as returned by createMailBox.
NOTE that in WIN32 the fds are HANDLES.
If newPgrp is true, the subprocess will be established in a new process group.
The processgroup will be equal to id.
newPgrp is not used on WIN32 and VMS systems."
|dirPath cmdPath cmdLine rslt|
aDirectory notNil ifTrue:[
dirPath := aDirectory asFilename asAbsoluteFilename osNameForDirectory.
(dirPath endsWith:':') ifTrue:[
dirPath := dirPath , '\'.
].
].
self isMSWINDOWSNTlike ifTrue:[
cmdPath := aCommandPath.
cmdLine := argString
] ifFalse:[
cmdPath := 'stxspawn.exe'.
cmdLine := 'stxspawn.exe ' , aCommandPath , ' ' , argString
].
rslt := self
primExec:cmdPath
commandLine:cmdLine
fileDescriptors:fdArray
fork:doFork
newPgrp:newPgrp
inPath:dirPath
createFlags:nil.
"/ 'created ' print. cmdLine print. ' -> ' print. rslt printCR.
^ rslt
"Modified: / 31.1.1998 / 10:54:24 / md"
"Modified: / 15.5.1999 / 18:07:51 / cg"
!
getStatusOfProcess:aProcessId
"wait for a process to terminate and fetch its exit status.
This is required to avoid zombie processes."
%{
DWORD endStatus;
int status = -1;
if (__isExternalAddressLike(aProcessId)) {
HANDLE handle = _HANDLEVal(aProcessId);
if (handle) {
#ifdef DO_WRAP_CALLS
do {
__threadErrno = 0;
endStatus = STX_API_CALL2( "WaitForSingleObject", WaitForSingleObject, handle, INFINITE);
} while ((endStatus < 0) && (__threadErrno == EINTR));
#else
endStatus = WaitForSingleObject(handle , INFINITE);
#endif
if (endStatus != WAIT_FAILED) {
if (GetExitCodeProcess(handle,&endStatus)) {
status = endStatus;
#ifdef PROCESSDEBUGWIN32
fprintf(stderr, "getexitcode status = %d\n",status);
} else {
fprintf(stderr, "getexitcode failed.\n");
#endif
}
}
}
RETURN ( __MKSMALLINT(status));
}
%}.
self primitiveFailed
!
pathOfCommand:aCommand
"find where aCommand's executable file is;
return its full pathName if there is such a command, otherwise
return nil."
|path f fExt|
aCommand asFilename isAbsolute ifTrue:[
aCommand asFilename exists ifTrue:[
^ aCommand
].
^ nil
].
path := self getEnvironment:'PATH'.
path notNil ifTrue:[
(path asCollectionOfSubstringsSeparatedBy:(self pathSeparator)) do:[:path |
path isEmpty ifTrue:[
f := aCommand asFilename
] ifFalse:[
f := path asFilename construct:aCommand.
].
self executableFileExtensions do:[:ext |
ext notEmpty ifTrue:[
fExt := (f pathName , '.' , ext) asFilename.
] ifFalse:[
fExt := f.
].
fExt isExecutable ifTrue:[
^ fExt pathName
].
].
].
].
^ nil
"windows:
OperatingSystem pathOfCommand:'bcc32'
OperatingSystem pathOfCommand:'diff'
"
"Modified: / 10.9.1998 / 17:51:49 / cg"
!
primExec:commandPath commandLine:commandLine fileDescriptors:fdArray fork:doFork newPgrp:newPgrp inPath:dirName createFlags:flagsOrNil
"Internal lowLevel entry for combined fork & exec for WIN32"
|handle|
handle := Win32ProcessHandle new.
%{
/*
* if fork is false, chain to another command (not yet supported)
* otherwise, spawn a subprocess and let it execute the command.
* Currently, only the forking version is supported (who chains anyway ?)
*/
#if 0
char fullCmdPathBuffer[1024];
char fullCmdLine[1024];
char fullDirName[1024];
char *fullCmdPath = fullCmdPathBuffer;
#else
char *cmdPath = 0;
char *cmdLine = 0;
#endif
char *dir = 0;
DWORD fdwCreate = 0;
STARTUPINFO lpsiStartInfo;
PROCESS_INFORMATION lppiProcInfo;
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
if (__isString(dirName)) {
dir = __stringVal(dirName);
}
if ((__isString(commandPath) || (commandPath == nil))
&& __isString(commandLine)) {
#if 0
/*
* generate command line (cmd plus args)
*/
if (__isWinNT) {
char *d;
strcpy(fullCmdPath, __stringVal(aCommandPath));
d = strchr(fullCmdPath,' ');
if (d) {
*d++ = 0;
strcpy(fullCmdLine, d);
} else {
fullCmdLine[0] = '\0';
}
} else {
//fullCmdPath = 0;
strcpy(fullCmdPath,"stxspawn.exe");
strcpy(fullCmdLine,"stxspawn.exe ");
strcat(fullCmdLine, __stringVal(aCommandPath));
}
if (__isString(argArray)) {
if (strlen(fullCmdLine) > 0) {
strcat(fullCmdLine, " ");
}
strcat(fullCmdLine, __stringVal(argArray));
} else {
int i;
for (i=0; i<__arraySize(argArray); i++) {
OBJ arg = __ArrayInstPtr(argArray)->a_element[i];
if (__isString(arg)) {
strcat(fullCmdLine, " ");
strcat(fullCmdLine, __stringVal(arg));
} else {
/* ignore */
fprintf(stderr, "bad (non-string) arg\n");
}
}
}
#endif
if (commandPath != nil) {
cmdPath = __stringVal(commandPath);
}
cmdLine = __stringVal(commandLine);
/*
* create descriptors as req'd
*/
memset(&sa, 0, sizeof (sa));
sa.nLength = sizeof( sa );
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
if (__isWinNT) {
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, -1, 0, 0);
sa.lpSecurityDescriptor = &sd;
}
memset(&lppiProcInfo, 0, sizeof (lppiProcInfo));
memset(&lpsiStartInfo, 0, sizeof (lpsiStartInfo));
lpsiStartInfo.cb = sizeof(lpsiStartInfo);
lpsiStartInfo.lpReserved = NULL;
lpsiStartInfo.lpDesktop = NULL;
lpsiStartInfo.lpTitle = NULL;
lpsiStartInfo.dwX = 0;
lpsiStartInfo.dwY = 0;
lpsiStartInfo.dwXSize = 100;
lpsiStartInfo.dwYSize = 100;
lpsiStartInfo.dwXCountChars = 0;
lpsiStartInfo.dwYCountChars = 0;
lpsiStartInfo.dwFillAttribute = 0;
if (0 /*__isWinNT*/) {
lpsiStartInfo.dwFlags = STARTF_USESTDHANDLES;
lpsiStartInfo.wShowWindow = SW_SHOWDEFAULT;
} else {
lpsiStartInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES /*| STARTF_USEPOSITION*/;
lpsiStartInfo.wShowWindow = SW_HIDE /*SW_SHOWDEFAULT*/;
}
lpsiStartInfo.cbReserved2 = 0;
lpsiStartInfo.lpReserved2 = NULL;
lpsiStartInfo.hStdInput = NULL;
lpsiStartInfo.hStdOutput = NULL;
lpsiStartInfo.hStdError = NULL;
/*
* set create process flags
* if the flags arg is nil, use common defaults;
* if non-nil, it must be a positive integer containing the fdwCreate bits.
*/
if (flagsOrNil != nil) {
fdwCreate = __longIntVal(flagsOrNil);
} else {
if (0 /* __isWinNT */)
fdwCreate = 0; //IDLE_PRIORITY_CLASS;
else
fdwCreate = CREATE_NEW_CONSOLE; //|IDLE_PRIORITY_CLASS; // DETACHED_PROCESS; // NORMAL_PRIORITY_CLASS ;
if (newPgrp == true) {
fdwCreate |= CREATE_NEW_PROCESS_GROUP;
}
fdwCreate |= CREATE_DEFAULT_ERROR_MODE;
}
if (fdArray == nil) {
lpsiStartInfo.hStdInput = (HANDLE) _get_osfhandle (0);
lpsiStartInfo.hStdOutput = (HANDLE) _get_osfhandle (1);
lpsiStartInfo.hStdError = (HANDLE) _get_osfhandle (2);
} else if (__isArray(fdArray) && (__arraySize(fdArray) >= 3)) {
if (__ArrayInstPtr(fdArray)->a_element[0] != nil) {
if (__isExternalAddressLike(__ArrayInstPtr(fdArray)->a_element[0])) {
lpsiStartInfo.hStdInput = _HANDLEVal(__ArrayInstPtr(fdArray)->a_element[0]);
} else {
lpsiStartInfo.hStdInput = (HANDLE) _get_osfhandle (__intVal(__ArrayInstPtr(fdArray)->a_element[0]));
}
}
if (__ArrayInstPtr(fdArray)->a_element[1] != nil) {
if (__isExternalAddressLike(__ArrayInstPtr(fdArray)->a_element[1])) {
lpsiStartInfo.hStdOutput = _HANDLEVal(__ArrayInstPtr(fdArray)->a_element[1]);
} else {
lpsiStartInfo.hStdOutput = (HANDLE) _get_osfhandle (__intVal(__ArrayInstPtr(fdArray)->a_element[1]));
}
}
if (__ArrayInstPtr(fdArray)->a_element[2] != nil) {
if (__isExternalAddressLike(__ArrayInstPtr(fdArray)->a_element[2])) {
lpsiStartInfo.hStdError = _HANDLEVal(__ArrayInstPtr(fdArray)->a_element[2]);
} else {
lpsiStartInfo.hStdError = (HANDLE) _get_osfhandle (__intVal(__ArrayInstPtr(fdArray)->a_element[2]));
}
}
#ifdef PROCESSDEBUGWIN32
fprintf(stderr, "stdin %x\n", lpsiStartInfo.hStdInput);
fprintf(stderr, "stdout %x\n",lpsiStartInfo.hStdOutput);
fprintf(stderr, "stderr %x\n",lpsiStartInfo.hStdError);
#endif
} else {
fprintf(stderr, "Win32OS [warning]: bad fd arg in createProcess\n");
}
if (doFork == true) {
#ifdef PROCESSDEBUGWIN32
fprintf(stderr, "create process cmdPath:<%s> cmdLine:<%s> in <%s>\n", cmdPath, cmdLine, dir);
#endif
if (CreateProcess( cmdPath,
cmdLine,
&sa, NULL /* &sa */, /* sec-attribs */
sa.bInheritHandle, /* inherit handles */
fdwCreate,
NULL, /* env */
dir,
&lpsiStartInfo,
&lppiProcInfo ))
{
CloseHandle(lppiProcInfo.hThread);
#ifdef PROCESSDEBUGWIN32
fprintf(stderr, "created process hProcess=%x\n", lppiProcInfo.hProcess);
#endif
__externalAddressVal(handle) = lppiProcInfo.hProcess;
((struct __Win32OperatingSystem__Win32ProcessHandle_struct *)(handle))->pid = __MKSMALLINT(lppiProcInfo.dwProcessId);
RETURN (handle);
}
#ifdef PROCESSDEBUGWIN32
fprintf(stderr, "created process error %d\n", GetLastError());
#endif
RETURN (nil);
} else {
; /* should never be called that way */
}
}
%}.
"
path-argument not string
or argArray not an array/nil
or malloc failed
or not supported by OS
"
^ self primitiveFailed
!
startProcess:aCommandString inputFrom:anExternalInStream outputTo:anExternalOutStream
errorTo:anExternalErrStream auxFrom:anAuxiliaryStream
environment:anEvironmentDictionary inDirectory:dir
"start executing the OS command as specified by the argument, aCommandString
as a separate process; do not wait for the command to finish.
The commandString is passed to a shell for execution - see the description of
'sh -c' in your UNIX manual ('cmd.com' in your MSDOS manual).
The command gets stdIn, stdOut and stdErr assigned from the arguments;
each may be nil.
Return the processId if successful, nil otherwise.
Use #monitorPid:action: for synchronization and exec status return,
or #killProcess: to stop it."
|nullStream in out err shellAndArgs rslt auxFd|
aCommandString isNil ifTrue:[^ nil].
(in := anExternalInStream) isNil ifTrue:[
nullStream := Filename nullDevice readWriteStream.
in := nullStream.
].
(out := anExternalOutStream) isNil ifTrue:[
nullStream isNil ifTrue:[nullStream := Filename nullDevice writeStream].
out := nullStream.
].
(err := anExternalErrStream) isNil ifTrue:[
err := out
].
anAuxiliaryStream notNil ifTrue:[
auxFd := anAuxiliaryStream fileDescriptor
].
shellAndArgs := self commandAndArgsForOSCommand:aCommandString.
rslt := self
exec:(shellAndArgs at:1)
withArguments:(shellAndArgs at:2)
environment:anEvironmentDictionary
fileDescriptors:(Array with:in fileDescriptor
with:out fileDescriptor
with:err fileDescriptor
with:auxFd)
fork:true
newPgrp:true "/ false
inDirectory:dir.
nullStream notNil ifTrue:[
nullStream close.
].
^ rslt
"blocking at current prio (i.e. only higher prio threads execute):
OperatingSystem executeCommand:'ls -l > out'.
"
"non-blocking (lower prio threads continue):
|in out err pid sema|
in := 'out' asFilename readStream.
out := 'out2' asFilename writeStream.
err := 'err' asFilename writeStream.
sema := Semaphore new.
pid := OperatingSystem startProcess:'sleep 10; grep drw' inputFrom:in outputTo:out errorTo:err.
The following will no longer work. monitorPid has disappeared
pid notNil ifTrue:[
Processor monitorPid:pid action:[:OSstatus | sema signal ].
].
in close.
out close.
err close.
sema wait.
Transcript showCR:'finished'
"
"Modified: / 21-03-1997 / 10:04:35 / dq"
"Modified: / 15-07-1997 / 16:03:51 / stefan"
"Created: / 12-11-1998 / 14:39:20 / cg"
"Modified: / 12-05-2004 / 12:30:21 / cg"
! !
!Win32OperatingSystem class methodsFor:'file access'!
closeFd:anIntegerOrHandle
"low level close of a filedescriptor"
%{
if (__isExternalAddressLike(anIntegerOrHandle) ) {
if( !CloseHandle( anIntegerOrHandle ) ) {
fprintf( stderr, "Win32OS [warning]: Could not close handle : %x\n", anIntegerOrHandle);
}
RETURN(self);
}
if (__isSmallInteger(anIntegerOrHandle)) {
close(__intVal(anIntegerOrHandle));
RETURN(self);
}
%}.
^ self primitiveFailed.
!
createDirectory:aPathName
"create a new directory with name 'aPathName', which may be an absolute
path, or relative to the current directory.
Return true if successful (or the directory existed already), false if failed.
This is a low-level entry - use Filename protocol for compatibility."
"/ if it already exists this is ok
(self isDirectory:aPathName) ifTrue:[^ true].
%{
if (__isString(aPathName)) {
int ret;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof( sa );
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
ret = CreateDirectory(__stringVal(aPathName), &sa);
if (ret != TRUE) {
__threadErrno = __WIN32_ERR(GetLastError());
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
RETURN (false);
}
RETURN (true);
}
%}.
self primitiveFailed
"
OperatingSystem createDirectory:'foo'
"
"Modified: 20.12.1995 / 11:24:13 / stefan"
"Modified: 29.6.1996 / 14:06:54 / cg"
!
createFileForReadAppend:pathName
^ self openFile:pathName attributes:#(#'GENERIC_READ' #'GENERIC_WRITE')
!
createFileForReadWrite:pathName
^ self openFile:pathName attributes:#(#'GENERIC_READ' #'GENERIC_WRITE' #'CREATE_ALWAYS')
!
linkFile:oldPath to:newPath
"link the file 'oldPath' to 'newPath'. The link will be a hard link.
Return true if successful, false if not."
(oldPath isString not or:[newPath isString not]) ifTrue:[
"/
"/ bad argument(s) given
"/
^ self primitiveFailed
].
"/
"/ this OperatingSystem does not support links
"/
^ UnsupportedOperationSignal raise
"
OperatingSystem linkFile:'foo' to:'bar'
"
!
openFile:pathName attributes:attributeSpec
"non public internal helper.
open a file, return an os specific fileHandle.
attributes is a collection of symbols specifying how the file is
to be opened."
|fileHandle errorNumber argumentError|
fileHandle := Win32Handle new.
%{
HANDLE h;
char *name;
OBJ *ap = __ArrayInstPtr(attributeSpec)->a_element;
int numAttrib = __arraySize(attributeSpec);
int i;
DWORD access, share, create, attr;
if (! __isString(pathName)) {
fileHandle = nil;
argumentError = @symbol(badPathName);
goto badArgument;
}
if (! __isArray(attributeSpec)) {
fileHandle = nil;
argumentError = @symbol(badAttributeSpec);
goto badArgument;
}
name = __stringVal(pathName);
share = 0;
access = 0;
create = 0;
attr = 0;
for (i=0; i<numAttrib;i++) {
OBJ attrSym = ap[i];
if (attrSym == @symbol(FILE_SHARE_READ)) {
share |= FILE_SHARE_READ;
} else if (attrSym == @symbol(FILE_SHARE_WRITE)) {
share |= FILE_SHARE_WRITE;
} else if (attrSym == @symbol(GENERIC_READ)) {
access |= GENERIC_READ;
} else if (attrSym == @symbol(GENERIC_WRITE)) {
access |= GENERIC_WRITE;
} else if (attrSym == @symbol(CREATE_NEW)) {
create |= CREATE_NEW;
} else if (attrSym == @symbol(CREATE_ALWAYS)) {
create |= CREATE_ALWAYS;
} else if (attrSym == @symbol(OPEN_EXISTING)) {
create |= OPEN_EXISTING;
} else if (attrSym == @symbol(OPEN_ALWAYS)) {
create |= OPEN_ALWAYS;
} else if (attrSym == @symbol(TRUNCATE_EXISTING)) {
create |= TRUNCATE_EXISTING;
} else if (attrSym == @symbol(FILE_ATTRIBUTE_HIDDEN)) {
attr |= FILE_ATTRIBUTE_HIDDEN;
} else if (attrSym == @symbol(FILE_ATTRIBUTE_READONLY)) {
attr |= FILE_ATTRIBUTE_READONLY;
} else if (attrSym == @symbol(FILE_ATTRIBUTE_READONLY)) {
attr |= FILE_ATTRIBUTE_READONLY;
} else if (attrSym == @symbol(FILE_FLAG_WRITE_THROUGH)) {
attr |= FILE_FLAG_WRITE_THROUGH;
} else if (attrSym == @symbol(FILE_FLAG_SEQUENTIAL_SCAN)) {
attr |= FILE_FLAG_SEQUENTIAL_SCAN;
} else if (attrSym == @symbol(FILE_FLAG_DELETE_ON_CLOSE)) {
attr |= FILE_FLAG_DELETE_ON_CLOSE;
} else {
fprintf(stderr, "Win32OS [warning]: unsupported open mode\n");
}
}
if (create == 0) {
fileHandle = nil;
argumentError = @symbol(missingCreateMode);
goto badArgument;
}
#ifdef PROCESSDEBUGWIN32
fprintf(stderr, "name:<%s> access:%x share:%x create:%x attr:%x\n",
name, access, share, create, attr);
#endif
h = CreateFile(name, access, share, 0 /* sa */, create, attr, 0 /* hTempl */);
if (h != INVALID_HANDLE_VALUE) {
__externalAddressVal(fileHandle) = (void *)h;
} else {
fileHandle = nil;
errorNumber = __mkSmallInteger( __WIN32_ERR(GetLastError()) );
}
badArgument: ;
%}.
fileHandle notNil ifTrue:[
fileHandle registerForFinalization.
^ fileHandle.
].
errorNumber isNil ifTrue:[
self error:'invalid argument(s): ', argumentError.
] ifFalse:[
(self errorHolderForNumber:errorNumber) reportError
].
!
openFileForAppend:pathName
"noone sends this message yet"
^ self shouldImplement
!
openFileForRead:pathName
^ self openFile:pathName attributes:#(#'GENERIC_READ' #'OPEN_EXISTING')
!
openFileForReadAppend:pathName
"noone sends this message yet"
^ self shouldImplement
!
openFileForReadWrite:pathName
^ self openFile:pathName attributes:#(#'GENERIC_READ' #'GENERIC_WRITE')
!
openFileForWrite:pathName
^ self openFile:pathName attributes:#(#'GENERIC_WRITE' #'OPEN_EXISTING')
!
recursiveCopyDirectory:sourcePathName to:destination
"copy the directory named 'sourcePathName' and all contained files/directories to 'destination'.
Return true if successful."
^ false
"Modified: / 4.6.1998 / 04:29:49 / cg"
!
removeDirectory:fullPathName
"remove the directory named 'fullPathName'.
The directory must be empty and you must have appropriate access rights.
Return true if successful, false if directory is not empty or no permission.
This is a lowLevel entry - use Filename protocol for compatibility."
%{
int ret;
if (__isString(fullPathName)) {
#ifdef DO_WRAP_CALLS
{
char _aPathName[MAXPATHLEN];
strncpy(_aPathName, __stringVal(fullPathName), MAXPATHLEN-1); _aPathName[MAXPATHLEN-1] = '\0';
do {
__threadErrno = 0;
ret = STX_API_CALL1( "RemoveDirectory", RemoveDirectory, _aPathName);
} while ((ret < 0) && (__threadErrno == EINTR));
}
#else
ret = RemoveDirectory((char *)__stringVal(fullPathName));
__threadErrno = __WIN32_ERR(GetLastError());
#endif
if (ret != TRUE) {
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
RETURN (false);
}
RETURN (true);
}
%}.
"/
"/ either not a string argument,
"/ or not supported by OS
"/
^ self primitiveFailed
"
OperatingSystem createDirectory:'foo'
OperatingSystem removeDirectory:'foo'
"
!
removeFile:fullPathName
"remove the file named 'fullPathName'; return true if successful.
This is a lowLevel entry - use Filename protocol for compatibility."
%{
int ret;
if (__isString(fullPathName)) {
#ifdef DO_WRAP_CALLS
{
char _aPathName[MAXPATHLEN];
strncpy(_aPathName, __stringVal(fullPathName), MAXPATHLEN-1); _aPathName[MAXPATHLEN-1] = '\0';
do {
__threadErrno = 0;
ret = STX_API_CALL1( "DeleteFile", DeleteFile, _aPathName);
} while ((ret < 0) && (__threadErrno == EINTR));
}
#else
ret = DeleteFile((char *)__stringVal(fullPathName));
__threadErrno = __WIN32_ERR(GetLastError());
#endif
if (ret != TRUE) {
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
RETURN (false);
}
RETURN (true);
}
%}.
^ self primitiveFailed
!
renameFile:oldPath to:newPath
"rename the file 'oldPath' to 'newPath'.
Someone else has to care for the names to be correct and
correct for the OS used - therefore, this should not be called
directlt. Instead, use Filename protocol to rename; this cares for
any invalid names.
Returns true if successful, false if not"
%{
int ret, eno;
if (__isString(oldPath) && __isString(newPath)) {
#ifdef DO_WRAP_CALLS
char _oldPath[MAXPATHLEN], _newPath[MAXPATHLEN];
strncpy(_oldPath, __stringVal(oldPath), MAXPATHLEN-1); _oldPath[MAXPATHLEN-1] = '\0';
strncpy(_newPath, __stringVal(newPath), MAXPATHLEN-1); _newPath[MAXPATHLEN-1] = '\0';
do {
__threadErrno = 0;
ret = STX_C_CALL2( "rename", rename, _oldPath, _newPath);
} while ((ret < 0) && (__threadErrno == EINTR));
#else
__BEGIN_INTERRUPTABLE__
do {
__threadErrno = 0;
ret = rename((char *) __stringVal(oldPath), (char *) __stringVal(newPath));
} while ((ret < 0) && (__threadErrno == EINTR));
__END_INTERRUPTABLE__
if (ret < 0) {
__threadErrno = __WIN32_ERR(GetLastError());
}
#endif
if (ret < 0) {
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
RETURN (false);
}
RETURN (true);
}
%}.
^ self primitiveFailed
"
OperatingSystem renameFile:'foo' to:'bar'
"
!
truncateFile:aPathName to:newSize
"change a files size return true on success, false on failure.
This may not be supported on all architectures.
This is a low-level entry - use Filename protocol."
^ self primitiveFailed
! !
!Win32OperatingSystem class methodsFor:'file access rights'!
accessMaskFor:aSymbol
"return the access bits mask for numbers as returned by
OperatingSystem>>accessModeOf:
and expected by OperatingSystem>>changeAccessModeOf:to:.
Since these numbers are OS dependent, always use the mask
(never hardcode 8rxxx into your code)."
%{ /* NOCONTEXT */
/* posix systems should define these ... */
# ifndef S_IRUSR
# define S_IRUSR 0400
# endif
# ifndef S_IWUSR
# define S_IWUSR 0200
# endif
# ifndef S_IXUSR
# define S_IXUSR 0100
# endif
# ifndef S_IRGRP
# define S_IRGRP 0040
# endif
# ifndef S_IWGRP
# define S_IWGRP 0020
# endif
# ifndef S_IXGRP
# define S_IXGRP 0010
# endif
# ifndef S_IROTH
# define S_IROTH 0004
# endif
# ifndef S_IWOTH
# define S_IWOTH 0002
# endif
# ifndef S_IXOTH
# define S_IXOTH 0001
# endif
if (aSymbol == @symbol(readUser)) {
RETURN ( __MKSMALLINT(S_IRUSR) );
}
if (aSymbol == @symbol(writeUser)) {
RETURN ( __MKSMALLINT(S_IWUSR) );
}
if (aSymbol == @symbol(executeUser)) {
RETURN ( __MKSMALLINT(S_IXUSR) );
}
if (aSymbol == @symbol(readGroup)) {
RETURN ( __MKSMALLINT(S_IRGRP) );
}
if (aSymbol == @symbol(writeGroup)) {
RETURN ( __MKSMALLINT(S_IWGRP) );
}
if (aSymbol == @symbol(executeGroup)) {
RETURN ( __MKSMALLINT(S_IXGRP) );
}
if (aSymbol == @symbol(readOthers)) {
RETURN ( __MKSMALLINT(S_IROTH) );
}
if (aSymbol == @symbol(writeOthers)) {
RETURN ( __MKSMALLINT(S_IWOTH) );
}
if (aSymbol == @symbol(executeOthers)) {
RETURN ( __MKSMALLINT(S_IXOTH) );
}
%}.
^ self primitiveFailed
"
OperatingSystem accessMaskFor:#readUser
"
!
accessModeOf:aPathName
"return a number representing access rights rwxrwxrwx for owner,
group and others. Return nil if such a file does not exist.
Notice that the returned number is OS dependent - use the
modeMasks as returned by OperatingSystem>>accessMaskFor:"
"
this could have been implemented as:
(self infoOf:aPathName) at:#mode
but for huge directory searches the code below is faster
"
%{
struct stat buf;
int ret;
if (__isString(aPathName)) {
#ifdef DO_WRAP_CALLS
char _aPathName[MAXPATHLEN];
strncpy(_aPathName, __stringVal(aPathName), MAXPATHLEN-1); _aPathName[MAXPATHLEN-1] = '\0';
do {
__threadErrno = 0;
ret = STX_C_CALL2( "stat", stat, _aPathName, &buf);
} while ((ret < 0) && (__threadErrno == EINTR));
#else
__BEGIN_INTERRUPTABLE__
do {
__threadErrno = 0;
ret = stat( (char *)__stringVal(aPathName), &buf);
} while ((ret < 0) && (__threadErrno == EINTR));
__END_INTERRUPTABLE__
if (ret < 0) {
__threadErrno = __WIN32_ERR(GetLastError());
}
#endif
if (ret < 0) {
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
RETURN ( nil );
}
RETURN ( __MKSMALLINT(buf.st_mode & 0777) );
}
%}.
^ self primitiveFailed
"
(OperatingSystem accessModeOf:'/') printStringRadix:8
"
!
changeAccessModeOf:aPathName to:modeBits
"change the access rights of aPathName to the OS dependent modeBits.
You should construct this mask using accessMaskFor, to be OS
independent. Return true if changed,
false if such a file does not exist or change was not allowd."
%{
int ret;
if (__isString(aPathName) && __isSmallInteger(modeBits)) {
#ifdef DO_WRAP_CALLS
int chmod();
char _aPathName[MAXPATHLEN];
strncpy(_aPathName, __stringVal(aPathName), MAXPATHLEN-1); _aPathName[MAXPATHLEN-1] = '\0';
do {
__threadErrno = 0;
ret = STX_C_CALL2( "chmod", chmod, _aPathName, __intVal(modeBits));
} while ((ret < 0) && (__threadErrno == EINTR));
#else
__BEGIN_INTERRUPTABLE__
do {
__threadErrno = 0;
ret = chmod((char *)__stringVal(aPathName), __intVal(modeBits));
} while ((ret < 0) && (__threadErrno == EINTR));
__END_INTERRUPTABLE__
if (ret < 0) {
__threadErrno = __WIN32_ERR(GetLastError());
}
#endif
if (ret < 0) {
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
RETURN ( false );
}
RETURN ( true );
}
%}.
^ self primitiveFailed
! !
!Win32OperatingSystem class methodsFor:'file queries'!
caseSensitiveFilenames
"return true, if the OS has caseSensitive file naming.
On MSDOS, this will return false;
on a real OS, we return true."
^ false
!
compressPath:pathName
"return the pathName compressed - that is, remove all ..-entries
and . entries. This does not always (in case of symbolic links)
return the true pathName and is therefore used as a fallback
if realPath and popen failed."
|names n "{ Class: SmallInteger }" |
names := pathName
asCollectionOfSubstringsSeparatedBy:self fileSeparator.
names := names asOrderedCollection.
"
cut off initial double-slashes
"
[names startsWith:#('' '')] whileTrue:[
names removeFirst.
].
"
cut off double-slashes at end
"
[names endsWith:#('')] whileTrue:[
names removeLast.
].
"
cut off current-dir at beginning
"
n := names size.
[(n >= 2) and:[names startsWith:#('.')]] whileTrue:[
names removeFirst.
n := n - 1.
].
"
cut off parent-dirs at end
"
[(n > 2)
and:[(names endsWith:#('..'))
and:[((names at:(n - 1)) startsWith:'.') not ]]] whileTrue:[
names removeLast; removeLast.
n := n - 2.
].
^ names asStringWith:self fileSeparator
from:1
to:n
compressTabs:false final:nil
"
OperatingSystem compressPath:'.\..'
OperatingSystem compressPath:'\foo\bar\baz\..'
OperatingSystem compressPath:'foo\bar\baz\..'
OperatingSystem compressPath:'foo\bar\baz\..\'
OperatingSystem compressPath:'foo\bar\baz\..\\\'
OperatingSystem compressPath:'\\\foo\bar\baz\..\\\'
"
"Modified: 1.11.1996 / 20:13:48 / cg"
!
fileSeparator
"return the character used to separate names in a path.
This character differs for MSDOS and other systems,
(but those are currently not supported - so this is some
preparation for the future)"
^ $\
!
getDiskInfoOf:aVolumeName
"returns a dictionary filled with any of:
freeBytes
totalBytes
and possibly additional (OS-specific) information"
|info ok sectorsPerCluster bytesPerSector freeClusters totalClusters
type|
%{
DWORD __sectorsPerCluster, __bytesPerSector, __freeClusters, __totalClusters;
if (__isString(aVolumeName)) {
if (GetDiskFreeSpace(__stringVal(aVolumeName),
&__sectorsPerCluster,
&__bytesPerSector,
&__freeClusters,
&__totalClusters) == TRUE) {
sectorsPerCluster = __MKUINT(__sectorsPerCluster);
bytesPerSector = __MKUINT(__bytesPerSector);
freeClusters = __MKUINT(__freeClusters);
totalClusters = __MKUINT(__totalClusters);
switch (GetDriveType(__stringVal(aVolumeName))) {
case DRIVE_REMOVABLE:
type = @symbol(removable); break;
case DRIVE_FIXED:
type = @symbol(fixed); break;
case DRIVE_REMOTE:
type = @symbol(network); break;
case DRIVE_CDROM:
type = @symbol(cdrom); break;
case DRIVE_RAMDISK:
type = @symbol(ramdisk); break;
}
ok = true;
}
}
%}.
ok == true ifTrue:[
info := IdentityDictionary new.
info at:#sectorsPerCluster put:sectorsPerCluster.
info at:#bytesPerSector put:bytesPerSector.
info at:#freeClusters put:freeClusters.
info at:#totalClusters put:totalClusters.
info at:#freeBytes put:(freeClusters * sectorsPerCluster * bytesPerSector).
info at:#totalBytes put:(totalClusters * sectorsPerCluster * bytesPerSector).
type notNil ifTrue:[
info at:#type put:type
].
].
^ info
"
self getDiskInfoOf:'c:\'
self getDiskInfoOf:'d:\'
"
!
getDriveList
"return a list of volumes in the system.
On unix, no such thing like a volume exists
- there, a syntetic list with root, home & current is returned.
On MSDOS, a list of drive letters is (eventually) returned.
On VMS, a list of volumes is (eventually) returned."
|list|
list := OrderedCollection new.
%{
/*
* add drive letters as strings to list ...
*/
char buffer[1024];
char *cp;
GetLogicalDriveStrings(1023, buffer);
for (cp=buffer; *cp; ) {
__SSEND1(list, @symbol(add:), 0, __MKSTRING(cp));
cp += strlen(cp) + 1;
}
%}.
^ list
!
getFileVersionInfoOf:aPathName
"retrieves the versionData from an executable or dll.
The returned value is either a byteArray, which should be
processed further with extractVersionValue (VerQueryValue),
or nil.
This is a WIN32 specific entry, not for common usage."
%{
if (__isString(aPathName)) {
int sz;
DWORD dummy;
sz = GetFileVersionInfoSize(__stringVal(aPathName), &dummy);
if (sz > 0) {
OBJ versionData;
versionData = __BYTEARRAY_UNINITIALIZED_NEW_INT(sz);
if (versionData == nil) {
RETURN (nil);
}
if (GetFileVersionInfo(__stringVal(aPathName), 0, sz, __ByteArrayInstPtr(versionData)->ba_element) == FALSE) {
RETURN (nil);
}
RETURN (versionData);
}
}
%}.
^ nil
!
getNullDevice
"get the name of the null-device."
^ 'nul:'
!
infoOf:aPathName
"return some object filled with info for the file 'aPathName';
the info (for which corresponding access methods are understood by
the returned object) is:
type - a symbol giving the files type
mode - numeric access mode
uid - owners user id
gid - owners group id
size - files size
id - files number (i.e. inode number)
accessed - last access time (as Timestamp)
modified - last modification time (as Timestamp)
statusChanged - last status change time (as Timestamp)
alternativeName - (windows only:) the MSDOS name of the file
Some of the fields may be returned as nil on systems which do not provide
all of the information.
Return nil if such a file does not exist.
For symbolic links (if supported by the OS),
the info of the pointed-to-file (i.e. the target) is returned;
use #linkInfoOf: to get info about the link itself.
"
|info type mode uid gid size id
atime mtime ctime
aYr aMon aDay aHr aMin aSec aMS
mYr mMon mDay mHr mMin mSec mMS
cYr cMon cDay cHr cMin cSec cMS
fileName alternativeName|
%{
struct stat buf;
int ret;
char alternativeFileNameBuffer[15];
char fileNameBuffer[MAX_PATH+1];
unsigned INT ino;
if (__isString(aPathName)) {
HANDLE hFile;
FILETIME tempFileTime;
SYSTEMTIME creationTime;
SYSTEMTIME accessTime;
SYSTEMTIME modificationTime;
int modeBits = 0;
WIN32_FIND_DATA findStruct;
#ifdef DO_WRAP_CALLS
{
char _aPathName[MAXPATHLEN];
strncpy(_aPathName, __stringVal(aPathName), MAXPATHLEN-1); _aPathName[MAXPATHLEN-1] = '\0';
do {
__threadErrno = 0;
hFile = STX_API_CALL2( "FindFirstFile", FindFirstFile, _aPathName, &findStruct);
} while ((hFile < 0) && (__threadErrno == EINTR));
}
#else
hFile = FindFirstFile(__stringVal(aPathName), &findStruct);
if (hFile < 0) {
__threadErrno = __WIN32_ERR(GetLastError());
}
#endif
if (! hFile || (hFile == (HANDLE)(-1)) || (hFile == INVALID_HANDLE_VALUE)) {
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
} else {
FindClose(hFile);
id = __MKSMALLINT(0); /* could get it by opening ... */
size = __MKLARGEINT64(1, findStruct.nFileSizeLow, findStruct.nFileSizeHigh);
if (findStruct.cFileName[0] != '\0') {
bcopy(findStruct.cFileName, fileNameBuffer, MAX_PATH);
fileNameBuffer[MAX_PATH] = '\0';
fileName = __MKSTRING(fileNameBuffer); /* FULL name */
}
if (findStruct.cAlternateFileName[0] != '\0') {
bcopy(findStruct.cAlternateFileName, alternativeFileNameBuffer, 14);
alternativeFileNameBuffer[14] = '\0';
alternativeName = __MKSTRING(alternativeFileNameBuffer); /* DOS name */
}
/*
* simulate access bits
*/
if (findStruct.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
modeBits = 0444;
} else {
modeBits = 0666;
}
if (findStruct.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
type = @symbol(directory);
modeBits |= 0111; /* executable */
} else {
type = @symbol(regular);
}
mode = __MKSMALLINT(modeBits);
/*
* sigh - convert from stupid time to useful time
*/
FileTimeToLocalFileTime(&findStruct.ftCreationTime, &tempFileTime);
FileTimeToSystemTime(&tempFileTime, &creationTime);
FileTimeToLocalFileTime(&findStruct.ftLastAccessTime, &tempFileTime);
FileTimeToSystemTime(&tempFileTime, &accessTime);
FileTimeToLocalFileTime(&findStruct.ftLastWriteTime, &tempFileTime);
FileTimeToSystemTime(&tempFileTime, &modificationTime);
aYr = __MKSMALLINT(accessTime.wYear);
aMon = __MKSMALLINT(accessTime.wMonth);
aDay = __MKSMALLINT(accessTime.wDay);
aHr = __MKSMALLINT(accessTime.wHour);
aMin = __MKSMALLINT(accessTime.wMinute);
aSec = __MKSMALLINT(accessTime.wSecond);
aMS = __MKSMALLINT(accessTime.wMilliseconds);
mYr = __MKSMALLINT(modificationTime.wYear);
mMon = __MKSMALLINT(modificationTime.wMonth);
mDay = __MKSMALLINT(modificationTime.wDay);
mHr = __MKSMALLINT(modificationTime.wHour);
mMin = __MKSMALLINT(modificationTime.wMinute);
mSec = __MKSMALLINT(modificationTime.wSecond);
mMS = __MKSMALLINT(modificationTime.wMilliseconds);
cYr = __MKSMALLINT(creationTime.wYear);
cMon = __MKSMALLINT(creationTime.wMonth);
cDay = __MKSMALLINT(creationTime.wDay);
cHr = __MKSMALLINT(creationTime.wHour);
cMin = __MKSMALLINT(creationTime.wMinute);
cSec = __MKSMALLINT(creationTime.wSecond);
cMS = __MKSMALLINT(creationTime.wMilliseconds);
}
}
%}.
mode isNil ifTrue:[
(self isDirectory:aPathName) ifTrue:[
"/ the code above fails for root directories (these do not exist).
"/ simulate
mode := 8r777.
type := #directory.
uid := gid := 0.
size := 0.
id := 0.
atime := mtime := ctime := Timestamp now.
].
].
mode notNil ifTrue:[
atime isNil ifTrue:[
atime := Timestamp day:aDay month:aMon year:aYr hour:aHr minutes:aMin seconds:aSec milliseconds:aMS.
].
mtime isNil ifTrue:[
mtime := Timestamp day:mDay month:mMon year:mYr hour:mHr minutes:mMin seconds:mSec milliseconds:mMS.
].
ctime isNil ifTrue:[
ctime := Timestamp day:cDay month:cMon year:cYr hour:cHr minutes:cMin seconds:cSec milliseconds:cMS.
].
info := FileStatusInfo
type:type
mode:mode
uid:uid
gid:gid
size:size
id:id
accessed:atime
modified:mtime
created:ctime
path:nil
fullName:fileName
alternativeName:alternativeName.
^ info
].
^ nil
"
OperatingSystem infoOf:'c:\windows'
OperatingSystem infoOf:'stx.exe'
(OperatingSystem infoOf:'/') uid
(OperatingSystem infoOf:'/') accessed
"
"Modified: / 4.2.2002 / 17:15:08 / cg"
!
isDirectory:aPathName
"return true, if 'aPathName' is a valid directory path name.
(i.e. exists and is a directory).
This also returns true for symbolic links pointing to a directory;
if you need to check for this, use #linkInfo:."
%{
if (__isString(aPathName)) {
int ret;
#ifdef DO_WRAP_CALLS
char _aPathName[MAXPATHLEN];
strncpy(_aPathName, __stringVal(aPathName), MAXPATHLEN-1); _aPathName[MAXPATHLEN-1] = '\0';
do {
__threadErrno = 0;
ret = STX_API_CALL1( "GetFileAttributes", GetFileAttributes, _aPathName);
} while ((ret < 0) && (__threadErrno == EINTR));
#else
ret = GetFileAttributes((char *) __stringVal(aPathName));
if (ret < 0) {
__threadErrno = __WIN32_ERR(GetLastError());
}
#endif
if (ret < 0) {
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
RETURN ( false );
}
RETURN ( (ret & FILE_ATTRIBUTE_DIRECTORY) ? true : false);
}
%}.
^ self primitiveFailed
"an alternative implementation would be:
^ (self infoOf:aPathName) type == #directory
"
!
isExecutable:aPathName
"return true, if the given file is executable.
For symbolic links, the pointed-to-file is checked."
%{
if (__isString(aPathName)) {
int ret;
/*
* under windows, there is no executable attribute ...
* so, only check for the files existence here.
*/
#ifdef DO_WRAP_CALLS
char _aPathName[MAXPATHLEN];
strncpy(_aPathName, __stringVal(aPathName), MAXPATHLEN-1); _aPathName[MAXPATHLEN-1] = '\0';
do {
__threadErrno = 0;
ret = STX_API_CALL1( "GetFileAttributes", GetFileAttributes, _aPathName);
} while ((ret < 0) && (__threadErrno == EINTR));
#else
ret = GetFileAttributes((char *) __stringVal(aPathName));
if (ret < 0) {
__threadErrno = __WIN32_ERR(GetLastError());
}
#endif
if (ret < 0) {
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
RETURN (false);
}
RETURN (true);
}
%}.
!
isReadable:aPathName
"return true, if the file/dir 'aPathName' is readable.
For symbolic links, the pointed-to-file is checked."
%{
if (__isString(aPathName)) {
int ret;
/*
* under windows, all files are readable ...
* so, only check for the files existence here.
*/
#ifdef DO_WRAP_CALLS
char _aPathName[MAXPATHLEN];
strncpy(_aPathName, __stringVal(aPathName), MAXPATHLEN-1); _aPathName[MAXPATHLEN-1] = '\0';
do {
__threadErrno = 0;
ret = STX_API_CALL1( "GetFileAttributes", GetFileAttributes, _aPathName);
} while ((ret < 0) && (__threadErrno == EINTR));
#else
ret = GetFileAttributes((char *) __stringVal(aPathName));
if (ret < 0) {
__threadErrno = __WIN32_ERR(GetLastError());
}
#endif
if (ret < 0) {
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
RETURN (false);
}
RETURN (true);
}
%}.
^ self primitiveFailed
!
isValidPath:aPathName
"return true, if 'aPathName' is a valid path name
(i.e. the file or directory exists)"
%{
struct stat buf;
int ret;
if (__isString(aPathName) || __isSymbol(aPathName) ) {
#ifdef DO_WRAP_CALLS
char _aPathName[MAXPATHLEN];
strncpy(_aPathName, __stringVal(aPathName), MAXPATHLEN-1); _aPathName[MAXPATHLEN-1] = '\0';
do {
__threadErrno = 0;
ret = STX_API_CALL1( "GetFileAttributes", GetFileAttributes, _aPathName);
} while ((ret < 0) && (__threadErrno == EINTR));
#else
ret = GetFileAttributes((char *) __stringVal(aPathName));
if (ret < 0) {
__threadErrno = __WIN32_ERR(GetLastError());
}
#endif
if (ret < 0) {
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
RETURN ( false );
}
RETURN (true);
}
%}.
^ self primitiveFailed
!
isWritable:aPathName
"return true, if the given file is writable.
For symbolic links, the pointed-to-file is checked."
%{
int ret;
if (__isString(aPathName)) {
#ifdef DO_WRAP_CALLS
char _aPathName[MAXPATHLEN];
strncpy(_aPathName, __stringVal(aPathName), MAXPATHLEN-1); _aPathName[MAXPATHLEN-1] = '\0';
do {
__threadErrno = 0;
ret = STX_API_CALL1( "GetFileAttributes", GetFileAttributes, _aPathName);
} while ((ret < 0) && (__threadErrno == EINTR));
#else
ret = GetFileAttributes((char *) __stringVal(aPathName));
if (ret < 0) {
__threadErrno = __WIN32_ERR(GetLastError());
}
#endif
if (ret < 0) {
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
RETURN ( false );
}
RETURN ( (ret & FILE_ATTRIBUTE_READONLY) ? false : true);
}
%}.
^ self primitiveFailed
!
linkInfoOf:aPathName
"return a dictionary filled with info for the file 'aPathName',
If aPathName is invalid, nil is returned.
The contents of the dictionary gives info about the link itself,
on contrast to #infoOf:, which returns the info of the pointed to file
in case of a symbolic link.
Same as #infoOf: for windows"
^ self infoOf:aPathName
!
mimeTypeForSuffix:aFileSuffix
"given a file suffix, return a corresponding mimeType.
Here, the Registry is consulted.
Returns nil if no mimeType for the given suffix is known."
^ RegistryEntry
stringValueFor:'Content Type'
atKey:('HKEY_CLASSES_ROOT\.' , aFileSuffix)
"
self mimeTypeForSuffix:'au'
"
!
parentDirectoryName
"return the name used to refer to parent directories.
In MSDOS, Unix and other systems this is '..', but maybe different
for other systems.
(but those are currently not supported - so this is some
preparation for the future)"
^ '..'
!
pathNameOf:pathName
"return the pathName of the argument, aPathString,
- thats the full pathname of the directory, starting at '/'.
This method needs the path to be valid
(i.e. all directories must exist, be readable and executable).
Notice: if symbolic links are involved, the result may look different
from what you expect."
|p path|
"some systems have a convenient function for this ..."
path := self primPathNameOf:pathName.
path isNil ifTrue:[
(self isValidPath:pathName) ifFalse:[
p := pathName.
[(p size > 1)
and:[p endsWith:(self fileSeparator)]
] whileTrue:[
p := p copyWithoutLast:1.
].
^ p
].
"/
"/ return the original - there is nothing else can we do
"/
path := self compressPath:pathName
].
^ path.
"
OperatingSystem pathNameOf:'.'
OperatingSystem pathNameOf:'../smalltalk/../smalltalk'
OperatingSystem pathNameOf:'../../..'
OperatingSystem pathNameOf:'..'
OperatingSystem pathNameOf:'/tmp////'
OperatingSystem pathNameOf:'/foo/bar'
OperatingSystem pathNameOf:'/foo/bar/'
OperatingSystem pathNameOf:'/foo/bar//'
"
"Modified: 29.11.1996 / 18:02:12 / stefan"
"Modified: 10.1.1997 / 19:10:42 / cg"
!
primIdOf:aPathName
"the actual code to return the fileNumber (i.e. inode number) of a file."
^ nil
!
primPathNameOf:aPathName
"return the pathName of the argument, aPathString,
- thats the full pathname of the directory, starting at '/'.
This method here returns nil, if the OS does not provide a
realPath library function.
Notice: if symbolic links are involved, the result may look different
from what you expect."
%{ /* xxSTACK: 16000 */
if (__isString(aPathName)) {
char nameBuffer[MAXPATHLEN + 1 + MAXPATHLEN + 1];
char *pFinal;
int rslt;
#ifdef DO_WRAP_CALLS
char _aPathName[MAXPATHLEN];
strncpy(_aPathName, __stringVal(aPathName), MAXPATHLEN-1); _aPathName[MAXPATHLEN-1] = '\0';
do {
__threadErrno = 0;
rslt = STX_API_CALL4( "GetFullPathName", GetFullPathName, _aPathName, sizeof(nameBuffer), nameBuffer, &pFinal);
} while ((rslt < 0) && (__threadErrno == EINTR));
#else
rslt = GetFullPathName(__stringVal(aPathName), sizeof(nameBuffer), nameBuffer, &pFinal);
#endif
if (rslt > 0) {
/*
* Attention: GetLongPathName is not available on old NT4.0/W95/W98
*/
static FARPROC entry = NULL;
#ifdef NO_NT4_0_COMPATIBILITY
entry = (FARPROC) GetLongPathName;
#else
if (entry == NULL) {
entry = __get_KERNEL32_functionAddress("GetLongPathNameA");
}
#endif /* NO_NT4_0_COMPATIBILITY */
if (entry) {
#ifdef DO_WRAP_CALLS
do {
__threadErrno = 0;
rslt = STX_API_CALL3( "GetLongPathName", entry, nameBuffer, nameBuffer, sizeof(nameBuffer));
} while ((rslt < 0) && (__threadErrno == EINTR));
#else
rslt = (*entry)(nameBuffer, nameBuffer, sizeof(nameBuffer));
#endif
}
}
if (rslt > 0) {
RETURN ( __MKSTRING(nameBuffer) );
}
__threadErrno = __WIN32_ERR(GetLastError());
}
%}.
^ nil
"
self primPathNameOf:'.'
"
!
timeOfLastAccess:aPathName
"return the time, when the file was last accessed.
For nonexistent files, nil is returned."
"could be implemented as:
(self infoOf:aPathName) accessed
"
| i|
i := self infoOf:aPathName.
i notNil ifTrue:[^ i accessTime].
^ nil.
"
OperatingSystem timeOfLastAccess:'/'
"
!
timeOfLastChange:aPathName
"return the time, when the file was last changed.
For nonexistent files, nil is returned."
"could be implemented as:
(self infoOf:aPathName) modified
"
| i|
i := self infoOf:aPathName.
i notNil ifTrue:[^ i modificationTime].
^ nil.
"
OperatingSystem timeOfLastChange:'/'
"
!
typeOf:aPathName
"return the type of a file as a symbol; for nonexistent files,
nil is returned.
Notice: for symbolic links, the type of the pointed-to file is returned."
|i|
"
this could have been implemented as:
(self infoOf:aPathName) type
"
i := self infoOf:aPathName.
i notNil ifTrue:[^ i type].
^ nil.
"
OperatingSystem typeOf:'/'
OperatingSystem typeOf:'.'
OperatingSystem typeOf:'Make.proto'
OperatingSystem typeOf:'resources/motif.style'
"
!
volumeNameOf:aPathString
"return the volumeName of the argument, aPath
- thats the name of the volume where aPath is.
Not all OperatingSystem support/use volumes; on unix,
this always returns an empty string."
aPathString size < 2 ifTrue:[^ ''].
(aPathString at:2) == $: ifTrue:[
^ (aPathString at:1) asString.
].
^ ''
! !
!Win32OperatingSystem class methodsFor:'interrupts & signals'!
blockingTest
"this is a test method;
For testing double CTRL-C in blocking primitives"
%{
while(1) {
printf("blocking...");
Sleep(50);
}
%}.
"
OperatingSystem blockingTest
"
!
blockingTest2
"this is a test method;
For testing double CTRL-C in blocking primitives"
%{
while(1) {
printf("blocking...");
STX_API_CALL1("Sleep", Sleep, 50);
}
%}.
"
OperatingSystem blockingTest2
"
!
defaultSignal:signalNumber
"revert to the default action on arrival of a (Unix-)signal.
Dont confuse Unix signals with smalltalk signals.
WARNING: for some signals, it is no good idea to revert to default;
for example, the default for SIGINT (i.e. ^C) is to exit; while the
default for SIGQUIT (^ \) is to dump core.
Also, NOTICE that signal numbers are not portable between unix
systems - use OperatingSystem sigXXX to get the numeric value for
a signal."
%{ /* NOCONTEXT */
if (__isSmallInteger(signalNumber)) {
#ifdef SIG_DFL
signal(__intVal(signalNumber), SIG_DFL);
RETURN (self);
#endif
}
%}.
"
this error is triggered on non-integer argument
"
^ self primitiveFailed
"you better save a snapshot image before trying this ..."
"
'if you hit ^C now, Smalltalk will exit immediately' printNewline.
OperatingSystem defaultSignal:(OperatingSystem sigINT).
1 to:1000000 do:[:i| ].
OperatingSystem enableSignal:(OperatingSystem sigINT).
'normal ^C handling again.' printNewline
"
!
disableIOInterruptsOn:fd
"turn off IO interrupts for a filedescriptor"
"
this error is triggered on non-integer argument
or if the OS does not support IO interrupts.
"
^ self primitiveFailed
!
disableSignal:signalNumber
"disable (Unix-) signal processing for signalNumber.
Dont confuse Unix signals with smalltalk signals.
WARNING: for some signals, it is no good idea to disable
them; for example, disabling the SIGINT signal turns off ^C
handling.
Also, NOTICE that signal numbers are not portable between unix
systems - use OperatingSystem sigXXX to get the numeric value for
a signal.
Use only for fully debugged stand alone applications."
%{ /* NOCONTEXT */
if (__isSmallInteger(signalNumber)) {
int sigNo = __intVal(signalNumber);
if (sigNo == 0) {
RETURN (self);
}
#ifdef SIG_IGN
signal(sigNo, SIG_IGN);
RETURN (self);
#endif
}
%}.
"
this error is triggered on non-integer argument
"
^ self primitiveFailed
"
'now, ^C is totally ignored ...' printNewline.
OperatingSystem disableSignal:(OperatingSystem sigINT).
1 to:1000000 do:[:i| ].
OperatingSystem enableSignal:(OperatingSystem sigINT).
'^C handled again.' printNewline
"
!
disableTimer
"disable timer interrupts.
WARNING:
the system will not operate correctly with timer interrupts
disabled, because no scheduling or timeouts are possible."
%{ /* NOCONTEXT */
extern void __win32ClearTimer();
__win32ClearTimer();
%}.
^ true
!
enableChildSignalInterrupts
"enable childSignal interrupts
(SIGCHLD, if the architecture supports it).
After enabling, these signals will send the message
'childSignalInterrupt' to the ChildSignalInterruptHandler object."
self enableSignal:(self sigCHLD)
!
enableIOInterruptsOn:fd
"turn on IO interrupts for a filedescriptor"
"
this error is triggered on non-integer argument
or if the system does not support SIGIO
"
^ self primitiveFailed
!
enableSignal:signalNumber
"enable (Unix-)signal processing for signalNumber.
Dont confuse Unix signals with smalltalk signals.
The signal will be delivered to one of the standard handlers
(SIGINT, SIGQUIT, etc) or to a general handler, which
sends #signalInterrupt:.
NOTICE that signal numbers are not portable between unix
systems - use OperatingSystem sigXXX to get the numeric value for
a signal."
%{ /* NOCONTEXT */
#ifdef NSIG
# define SIG_LIMIT NSIG
#else
# ifdef SIGUSR2
# define SIG_LIMIT SIGUSR2
# else
# ifdef SIGUSR
# define SIG_LIMIT SIGUSR
# endif
# endif
#endif
#if defined(SIGPOLL) && !defined(SIGIO)
# define SIGIO SIGPOLL
#endif
#ifdef SIGCHLD
# define CHILD_SIGNAL SIGCHLD
#else
# ifdef SIGCLD
# define CHILD_SIGNAL SIGCLD
# endif
#endif
int sigNr;
#if defined(SIGINT) || defined(SIGQUIT)
# ifndef __signalUserInterrupt
extern void __signalUserInterrupt(SIGHANDLER_ARG);
# endif
#endif
#ifdef SIGFPE
# ifndef __signalFpExceptionInterrupt
extern void __signalFpExceptionInterrupt(SIGHANDLER_ARG);
# endif
#endif
#ifdef SIGIO
# ifndef __signalIoInterrupt
extern void __signalIoInterrupt(SIGHANDLER_ARG);
# endif
#endif
#ifdef CHILD_SIGNAL
# ifndef __signalChildInterrupt
extern void __signalChildInterrupt(SIGHANDLER_ARG);
# endif
#endif
#ifdef SIGPIPE
# ifndef __signalPIPEInterrupt
extern void __signalPIPEInterrupt(SIGHANDLER_ARG);
# endif
#endif
#ifdef SIGBUS
# ifndef __signalBUSInterrupt
extern void __signalBUSInterrupt(SIGHANDLER_ARG);
# endif
#endif
#ifdef SIGSEGV
# ifndef __signalSEGVInterrupt
extern void __signalSEGVInterrupt(SIGHANDLER_ARG);
# endif
#endif
#if defined(SIGILL) || defined(SIGEMT)
# ifndef __signalTrapInterrupt
extern void __signalTrapInterrupt(SIGHANDLER_ARG);
# endif
#endif
#ifdef SIGALRM
# ifndef WIN32
# ifndef __signalTimerInterrupt
extern void __signalTimerInterrupt(SIGHANDLER_ARG);
# endif
# endif
#endif
#ifndef __signalInterrupt
extern void __signalInterrupt(SIGHANDLER_ARG);
#endif
void (*handler)(SIGHANDLER_ARG);
if (__isSmallInteger(signalNumber)
&& ((sigNr = __intVal(signalNumber)) >= 0)
#ifdef SIG_LIMIT
&& (sigNr <= SIG_LIMIT)
#endif
) {
/*
* standard signals are forced into standard handlers
* - all others go into general signalInterrupt
*/
#if defined(SIGPOLL) && defined(SIGIO)
if (sigNr == SIGPOLL)
sigNr = SIGIO;
#endif
switch (sigNr) {
case 0:
/* enabling a non-supported signal */
RETURN (self);
#ifdef SIGBREAK
case SIGBREAK:
#endif
#ifdef SIGINT
case SIGINT:
#endif
#ifdef SIGQUIT
case SIGQUIT:
#endif
#ifdef SIGNALDEBUGWIN32
printf("ConsoleSignal %d\n",sigNr);
#endif
SetConsoleCtrlHandler((PHANDLER_ROUTINE)__signalUserInterruptWIN32,TRUE);
RETURN (self);
#ifdef SIGFPE
case SIGFPE:
handler = __signalFpExceptionInterrupt;
break;
#endif
#ifdef SIGPIPE
case SIGPIPE:
handler = __signalPIPEInterrupt;
break;
#endif
#ifdef SIGBUS
case SIGBUS:
handler = __signalBUSInterrupt;
break;
#endif
#ifdef SIGSEGV
case SIGSEGV:
handler = __signalSEGVInterrupt;
break;
#endif
#ifdef SIGILL
case SIGILL:
handler = __signalTrapInterrupt;
break;
#endif
#ifdef SIGEMT
case SIGEMT:
handler = __signalTrapInterrupt;
break;
#endif
#ifdef SIGIO
case SIGIO:
handler = __signalIoInterrupt;
break;
#endif
#ifdef CHILD_SIGNAL
case CHILD_SIGNAL:
handler = __signalChildInterrupt;
break;
#endif
default:
handler = __signalInterrupt;
break;
}
{
#ifdef HAS_SIGACTION
struct sigaction act;
/*
* Do not add SA_RESTART here. A signal can cause a
* thread switch, another thread can do a garbage collect
* and restarted system calls may write into old
* (collected) addresses.
*/
act.sa_flags = SA_SIGINFO; /* <- if you add more, remember dummys at the top */
sigemptyset(&act.sa_mask);
act.sa_handler = handler;
sigaction(sigNr, &act, 0);
#else
# ifdef HAS_SIGVEC
struct sigvec vec;
vec.sv_flags = SV_INTERRUPT;
sigemptyset(&vec.sv_mask);
vec.sv_handler = handler;
sigvec(sigNr, &vec, NULL);
# else
# ifdef WIN32
# ifdef SIGNALDEBUGWIN32
printf("signal %d can't change handler\n",sigNr);
# endif
# else
(void) signal(sigNr, handler);
# endif
# endif
#endif
}
/*
* maybe, we should Return the old enable-status
* as boolean here ...
*/
RETURN (self);
}
%}.
"
this error is triggered on non-integer argument, or
if the signal number is not in the valid range (1..NSIG)
"
^ self primitiveFailed
!
enableTimer:milliSeconds
"setup for a timerInterrupt, to be signalled after some (real) time."
%{ /* NOCONTEXT */
extern void __win32SetTimer();
if (__isSmallInteger(milliSeconds)) {
__win32SetTimer( __intVal(milliSeconds) );
RETURN (true);
}
%}.
^ false
!
isFatalSignal:aNumber
"return true if a signal with number aNumber is a fatal signal,
i.e. some severe internal error occured"
^ (aNumber == self sigSEGV)
or:[aNumber == self sigILL
or:[aNumber == self sigBUS]]
!
killProcess:processId
"kill a process.
The process terminates immediately and has no chance to perform any cleanup actions.
WARNING: in order to avoid zombie processes (on unix),
you have to fetch the processes exitstatus with
OperatingSystem>>getStatusOfProcess:aProcessId."
self terminateProcess:processId
!
sendSignal:signalNumber to:processId
"send a unix signal to some process (maybe myself).
Returns false if any error occurred, true otherwise.
Do not confuse UNIX signals with Smalltalk-Signals.
WARNING: in order to avoid zombie processes (on unix),
you may have to fetch the processes exitstatus with
OperatingSystem>>getStatusOfProcess:aProcessId
if the signal terminates that process."
"/
"/ either invalid argument (non-integers)
"/ or not supported by OS
"/
^ self primitiveFailed
!
terminateProcess:processHandle
"terminate a process.
The process has a chance to do some cleanup.
WIN32:
Under unix, we have terminateProcess, which does a soft
terminate (giving the process a chance to cleanup) and
killProcess, which does a hard terminate.
Under WIN32, both (currently) use the TerminateProcess
function, which unconditionally causes a process to exit.
I.e. under WIN32, the process has no chance to perform cleanup.
Use it only in extreme circumstances. The state of
global data maintained by dynamic-link libraries (DLLs)
may be compromised if TerminateProcess is used.
TODO: send it a WM_QUIT instead, to allow for proper shutdown."
self terminateProcess:processHandle exitCode:0
!
terminateProcess:processHandle exitCode:exitCode
"terminate a process.
The process should have a chance to do some cleanup.
WIN32:
Under unix, we have terminateProcess, which does a soft
terminate (giving the process a chance to cleanup) and
killProcess, which does a hard terminate.
Under WIN32, both (currently) use the TerminateProcess
function, which unconditionally causes a process to exit.
I.e. under WIN32, the process has no chance to perform cleanup.
Use it only in extreme circumstances. The state of
global data maintained by dynamic-link libraries (DLLs)
may be compromised if TerminateProcess is used.
TODO: send it a WM_QUIT instead, to allow for proper shutdown."
%{
if (__isExternalAddressLike(processHandle) ) {
HANDLE hProcess = _HANDLEVal(processHandle);
#ifdef PROCESS1DEBUGWIN32
printf("TerminateProcess handle: %x\n", hProcess);
#endif
if (hProcess != 0) {
TerminateProcess(hProcess, __intVal(exitCode));
} else {
fprintf(stderr, "Win32OS [warning]: wrong hProcess in TerminateProcess\n");
}
} else {
fprintf(stderr, "Win32OS [warning]: wrong processHandle in TerminateProcess\n");
}
%}
"Modified: / 28.12.1995 / 15:05:37 / stefan"
"Modified: / 27.1.1998 / 20:05:47 / cg"
!
terminateProcessGroup:processGroupHandle
"terminate a process group.
The processes should have a chance to do some cleanup.
WIN32:
The processGroup is terminated by sending it a CTRL-C
using GenerateConsoleCtrlEvent."
%{
if (__isExternalAddressLike(processGroupHandle) ) {
HANDLE hProcessGroup = _HANDLEVal(processGroupHandle);
DWORD processGroupId;
if (hProcessGroup != (HANDLE)0) {
processGroupId = __intVal( ((struct __Win32OperatingSystem__Win32ProcessHandle_struct *)(processGroupHandle))->pid );
#ifdef PROCESS1DEBUGWIN32
printf("TerminateProcessGroup processGroupHandle: %x (%d)\n", hProcessGroup, processGroupId);
#endif
GenerateConsoleCtrlEvent(CTRL_C_EVENT, processGroupId);
} else {
fprintf(stderr, "Win32OS [warning]: wrong hProcessGroup in TerminateProcessGroup \n");
}
} else {
fprintf(stderr, "Win32OS [warning]: wrong processGroupHandle in TerminateProcessGroup \n");
}
%}
! !
!Win32OperatingSystem class methodsFor:'ipc support'!
makePipe
"make a pipe, return array with two filedescriptors on success,
nil on failure.
This is a lowLevel entry, not for public use.
See ExternalStream>>makePipe for a more user-friendly, public interface."
|fd1 fd2|
%{
HANDLE pipeRead = (HANDLE)0;
HANDLE pipeWrite = (HANDLE)0;
SECURITY_ATTRIBUTES sa;
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
if( ! CreatePipe( &pipeRead, &pipeWrite, &sa, 0 ) ) {
@global(LastErrorNumber) = __MKSMALLINT( __WIN32_ERR(GetLastError()) );
RETURN ( nil );
}
#ifdef USE_HANDLES
fd1 = __MKEXTERNALADDRESS(pipeRead);
fd2 = __MKEXTERNALADDRESS(pipeWrite);
#else
/*
* make fileDescriptors from handles
*/
# ifdef PROCESSDEBUGWIN32
printf("piperead %x\n",pipeRead);
printf("pipewrite %x\n",pipeWrite);
# endif
fd1 = __MKSMALLINT(_open_osfhandle(pipeRead, O_BINARY));
fd2 = __MKSMALLINT(_open_osfhandle(pipeWrite, O_BINARY));
#endif
%}.
fd1 notNil ifTrue:[
^ Array with:fd1 with:fd2.
].
^ nil
! !
!Win32OperatingSystem class methodsFor:'misc'!
closePid:pid
"free pid resource"
%{
if (__isExternalAddressLike(pid) ) {
HANDLE __pid = _HANDLEVal(pid);
if (__pid != 0) {
#ifdef PROCESSDEBUGWIN32
printf("Close ProcessHandle %x\n", __pid);
#endif
CloseHandle(__pid);
_HANDLEVal(pid) = 0;
}
}
%}.
^ true.
"Created: 28.1.1998 / 14:23:04 / md"
"Modified: 28.1.1998 / 14:27:18 / md"
! !
!Win32OperatingSystem class methodsFor:'os queries'!
executableFileExtensions
"return a collection of extensions for executable program files.
Only req'd for msdos like systems ..."
^ #('com' 'exe')
"Created: 2.5.1997 / 11:42:29 / cg"
!
getDomainName
"return the domain this host is in.
Notice:
not all systems support this; on some, 'unknown' is returned."
|name idx hostName k|
DomainName notNil ifTrue:[
^ DomainName
].
name := self getEnvironment:'DOMAIN'.
name isNil ifTrue:[
name := self getEnvironment:'DOMAINNAME'.
].
name isNil ifTrue:[
"/ sometimes, we can extract the domainName from the hostName ...
hostName := self primGetHostName.
hostName notNil ifTrue:[
idx := hostName indexOf:$..
idx ~~ 0 ifTrue:[
name := hostName copyFrom:idx+1.
]
].
name isNil ifTrue:[
"/ ok, search the registry ...
"/ under NT, it is found there ...
k := RegistryEntry key:'HKEY_LOCAL_MACHINE\System'.
k notNil ifTrue:[
k subKeysDo:[:subKey |
subKey subKeysDo:[:subSubKey |
|tcp params|
(subSubKey path asLowercase endsWith:'services') ifTrue:[
tcp := subSubKey subKeyNamed:'tcpip'.
tcp notNil ifTrue:[
params := tcp subKeyNamed:'parameters'.
params notNil ifTrue:[
name := params valueNamed:'Domain'.
params close.
].
tcp close.
]
]
]
]
].
].
name isNil ifTrue:[
"/ under Win95/Win98, it is found there ...
k := RegistryEntry key:'HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP'.
k notNil ifTrue:[
name := k valueNamed:'Domain'.
k close.
]
].
name isNil ifTrue:[
'Win32OperatingSystem [warning]: cannot find out domainname' errorPrintCR.
name := 'unknown'.
]
].
DomainName := name.
^ name
"
DomainName := nil.
OperatingSystem getDomainName
OperatingSystem getHostName
"
"Modified: 26.4.1996 / 10:04:54 / stefan"
!
getEnvironment:aStringOrSymbol
"get an environment string"
%{ /* NOCONTEXT */
char *env;
if (__isString(aStringOrSymbol) || __isSymbol(aStringOrSymbol)) {
char buff[512];
env = NULL;
if (GetEnvironmentVariable(__stringVal(aStringOrSymbol),
buff,
sizeof(buff)-1)) {
env = buff;
}
if (env) {
RETURN ( __MKSTRING(env) );
}
}
%}
.
^ nil
"
OperatingSystem getEnvironment:'LANG'
OperatingSystem getEnvironment:'LOGIN'
OperatingSystem getEnvironment:'HOME'
OperatingSystem getEnvironment:'NNTPSERVER'
OperatingSystem getEnvironment:'MAIL'
OperatingSystem getEnvironment:'PATH'
"
!
getHostName
"return the hostname we are running on - if there is
a HOST environment variable, we are much faster here ...
Notice:
not all systems support this; on some, 'unknown' is returned."
|name idx|
HostName notNil ifTrue:[
^ HostName
].
name := self primGetHostName.
"/ on some systems, the hostname already contains the domain.
"/ decompose it here.
idx := name indexOf:$..
idx ~~ 0 ifTrue:[
DomainName := name copyFrom:(idx+1).
name := name copyTo:(idx-1).
].
HostName := name.
^ name
"
OperatingSystem getHostName
"
!
getLanguage
"return the domain this host is in.
Notice:
not all systems support this; on some, 'unknown' is returned."
|name|
name := self getEnvironment:'LANG'.
name isNil ifTrue:[
"/ ok, search the registry ...
"/ under XP, it is found there ...
name := RegistryEntry
stringValueFor:'sLanguage'
atKey:'HKEY_CURRENT_USER\Control Panel\International'.
name notNil ifTrue:[
name := self mapLanguage:name.
].
].
^ name
"
OperatingSystem getLanguage
"
"Modified: 26.4.1996 / 10:04:54 / stefan"
!
getLocaleInfo
"return a dictionary filled with values from the locale information;
Not all fields may be present, depending on the OS's setup and capabilities.
Possible fields are:
decimalPoint <String>
thousandsSep <String>
internationalCurrencySymbol <String>
currencySymbol <String>
monetaryDecimalPoint <String>
monetaryThousandsSeparator <String>
positiveSign <String>
negativeSign <String>
internationalFractionalDigits <Integer>
fractionalDigits <Integer>
positiveSignPrecedesCurrencySymbol <Boolean>
negativeSignPrecedesCurrencySymbol <Boolean>
positiveSignSeparatedBySpaceFromCurrencySymbol <Boolean>
negativeSignSeparatedBySpaceFromCurrencySymbol <Boolean>
positiveSignPosition <Symbol>
one of: #parenthesesAround,
#signPrecedes,
#signSuceeds,
#signPrecedesCurrencySymbol,
#signSuceedsCurrencySymbol
negativeSignPosition <like above>
it is up to the application to deal with undefined values.
Notice, that (for now), the system does not use this information;
it should be used by applications as required.
"
|info val|
LocaleInfo notNil ifTrue:[
"/ return the internal info; useful on systems which do not
"/ support this.
^ LocaleInfo
].
info := IdentityDictionary new.
%{
char *decimalPoint; /* something like "." (US) or "," (german) */
char *thousandsSep; /* something like "," (US) or "." (german) */
char *intCurrencySymbol; /* international currency symbol; something like "USD " "DM " */
char *currencySymbol; /* local currency symbol; something like "USD " "DM " */
char *monDecimalPoint; /* money: decimal point */
char *monThousandsSep; /* money: thousands sep */
char *positiveSign;
char *negativeSign;
int intFractDigits; /* money: international digits after decPoint */
int fractDigits; /* money: local digits after decPoint */
int csPosPrecedes; /* money: 1 if currency symbol precedes a positive value; 0 if it sceeds */
int csNegPrecedes; /* money: 1 if currency symbol precedes a negative value; 0 if it sceeds */
int csPosSepBySpace; /* money: 1 if currency symbol should be separated by a space from a positive value; 0 if no space */
int csNegSepBySpace; /* money: 1 if currency symbol should be separated by a space from a negative value; 0 if no space */
int csPosSignPosition; /* money: 0: ()'s around the value & currency symbol */
int csNegSignPosition; /* 1: sign precedes the value & currency symbol */
/* 2: sign succeeds the value & currency symbol */
/* 3: sign immediately precedes the currency symbol */
/* 4: sign immediately suceeds the currency symbol */
#if defined(HAS_LOCALECONV)
struct lconv *conf;
conf = localeconv();
if (conf) {
decimalPoint = conf->decimal_point;
thousandsSep = conf->thousands_sep;
intCurrencySymbol = conf->int_curr_symbol;
currencySymbol = conf->currency_symbol;
monDecimalPoint = conf->mon_decimal_point;
monThousandsSep = conf->mon_thousands_sep;
positiveSign = conf->positive_sign;
negativeSign = conf->negative_sign;
intFractDigits = conf->int_frac_digits;
fractDigits = conf->frac_digits;
csPosPrecedes = conf->p_cs_precedes;
csNegPrecedes = conf->n_cs_precedes;
csPosSepBySpace = conf->p_sep_by_space;
csNegSepBySpace = conf->n_sep_by_space;
csPosSignPosition = conf->p_sign_posn;
csNegSignPosition = conf->n_sign_posn;
}
#else
decimalPoint = (char *)0;
thousandsSep = (char *)0;
intCurrencySymbol = (char *)0;
currencySymbol = (char *)0;
monDecimalPoint = (char *)0;
monThousandsSep = (char *)0;
positiveSign = (char *)0;
negativeSign =(char *)0;
intFractDigits = -1;
fractDigits = -1;
csPosPrecedes = -1;
csNegPrecedes = -1;
csPosSepBySpace = -1;
csNegSepBySpace = -1;
csPosSignPosition = -1;
csNegSignPosition = -1;
#endif
if (decimalPoint) {
val = __MKSTRING(decimalPoint);
__AT_PUT_(info, @symbol(decimalPoint), val);
}
if (thousandsSep) {
val = __MKSTRING(thousandsSep);
__AT_PUT_(info, @symbol(thousandsSeparator), val);
}
if (intCurrencySymbol) {
val = __MKSTRING(intCurrencySymbol);
__AT_PUT_(info, @symbol(internationCurrencySymbol), val);
}
if (currencySymbol) {
val = __MKSTRING(currencySymbol);
__AT_PUT_(info, @symbol(currencySymbol), val);
}
if (monDecimalPoint) {
val = __MKSTRING(monDecimalPoint);
__AT_PUT_(info, @symbol(monetaryDecimalPoint), val);
}
if (monThousandsSep) {
val = __MKSTRING(monThousandsSep);
__AT_PUT_(info, @symbol(monetaryThousandsSeparator), val);
}
if (positiveSign) {
val = __MKSTRING(positiveSign);
__AT_PUT_(info, @symbol(positiveSign), val);
}
if (negativeSign) {
val = __MKSTRING(negativeSign);
__AT_PUT_(info, @symbol(negativeSign), val);
}
if (intFractDigits >= 0) {
__AT_PUT_(info, @symbol(internationalFractionalDigits), __MKSMALLINT(intFractDigits));
}
if (fractDigits >= 0) {
__AT_PUT_(info, @symbol(fractionalDigits), __MKSMALLINT(fractDigits));
}
if (csPosPrecedes >= 0) {
if (csPosPrecedes == 0) {
val = false;
} else {
val = true;
}
__AT_PUT_(info, @symbol(positiveSignPrecedesCurrencySymbol), val );
}
if (csNegPrecedes >= 0) {
if (csNegPrecedes == 0) {
val = false;
} else {
val = true;
}
__AT_PUT_(info, @symbol(negativeSignPrecedesCurrencySymbol), val );
}
if (csPosSepBySpace >= 0) {
if (csPosSepBySpace == 0) {
val = false;
} else {
val = true;
}
__AT_PUT_(info, @symbol(positiveSignSeparatedBySpaceFromCurrencySymbol), val);
}
if (csNegSepBySpace >= 0) {
if (csNegSepBySpace == 0) {
val = false;
} else {
val = true;
}
__AT_PUT_(info, @symbol(negativeSignSeparatedBySpaceFromCurrencySymbol), val);
}
switch (csPosSignPosition) {
case 0:
val = @symbol(parenthesesAround);
break;
case 1:
val = @symbol(signPrecedes);
break;
case 2:
val = @symbol(signSuceeds);
break;
case 3:
val = @symbol(signPrecedesCurrencySymbol);
break;
case 4:
val = @symbol(signSuceedsCurrencySymbol);
break;
default:
val = nil;
}
if (val != nil) {
__AT_PUT_(info, @symbol(positiveSignPosition), val);
}
switch (csNegSignPosition) {
case 0:
val = @symbol(parenthesesAround);
break;
case 1:
val = @symbol(signPrecedes);
break;
case 2:
val = @symbol(signSuceeds);
break;
case 3:
val = @symbol(signPrecedesCurrencySymbol);
break;
case 4:
val = @symbol(signSuceedsCurrencySymbol);
break;
default:
val = nil;
}
if (val != nil) {
__AT_PUT_(info, @symbol(negativeSignPosition), val);
}
%}.
^ info
"
OperatingSystem getLocaleInfo
"
"Created: 23.12.1995 / 14:19:20 / cg"
!
getNetworkMACAddresses
"return a dictionary filled with
key -> name of interface
value -> the MAC adress (as ByteArray)
for each interface
"
|info nAdapters rawData entry
name description macAddress ipAddress ipAddressMask|
rawData := Array new:50.
%{
#ifndef NO_GETADAPTERSINFO
/*
* temporary undef String to avoid a #define-conflict
* between ST/X's String and Windows String typedef
*/
# undef String
# undef Context
IP_ADAPTER_INFO AdapterInfo[32];
DWORD dwBufLen = sizeof(AdapterInfo);
DWORD dwStatus;
static FARPROC entry2 = NULL;
/*
* Attention: GetAdaptersInfo is not available on old NT4.0/W95/W98
*/
#ifdef NO_NT4_0_COMPATIBILITY
entry2 = (FARPROC) GetAdaptersInfo;
#else
if (entry2 == NULL) {
entry2 = __get_iphlpapi_functionAddress("GetAdaptersInfo");
}
#endif /* NO_NT4_0_COMPATIBILITY */
if (entry2) {
dwStatus = (*entry2)(
AdapterInfo, // [out] buffer to receive data
&dwBufLen); // [in] size of receive data buffer
if (dwStatus == ERROR_SUCCESS) {
PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;
unsigned char *bP;
int nA = 0;
bP = __byteArrayVal(rawData);
do {
name = __MKSTRING(pAdapterInfo->AdapterName);
description = __MKSTRING(pAdapterInfo->Description);
macAddress = __MKBYTEARRAY(pAdapterInfo->Address, 6);
ipAddress = __MKSTRING(pAdapterInfo->IpAddressList.IpAddress.String);
ipAddressMask = __MKSTRING(pAdapterInfo->IpAddressList.IpMask.String);
entry = __ARRAY_NEW_INT(5);
/*
* back to ST/X's String definition
*/
# ifdef __DEF_String
# define String __DEF_String
# endif
# ifdef __DEF_String
# define Context __DEF_Context
# endif
__ArrayInstPtr(entry)->a_element[0] = name; __STORE(entry, name);
__ArrayInstPtr(entry)->a_element[1] = description; __STORE(entry, description);
__ArrayInstPtr(entry)->a_element[2] = macAddress; __STORE(entry, macAddress);
__ArrayInstPtr(entry)->a_element[3] = ipAddress; __STORE(entry, ipAddress);
__ArrayInstPtr(entry)->a_element[4] = ipAddressMask; __STORE(entry, ipAddressMask);
__ArrayInstPtr(rawData)->a_element[nA] = entry; __STORE(rawData, entry);
nA++;
pAdapterInfo = pAdapterInfo->Next;
} while(pAdapterInfo);
nAdapters = __mkSmallInteger(nA);
}
}
#endif /* NO_GETADAPTERSINFO */
%}.
info := Dictionary new.
nAdapters notNil ifTrue:[
1 to:nAdapters do:[:i |
|entry name description macAddr ipAddr|
entry := rawData at:i.
name := entry at:1.
"/ description := entry at:2.
macAddr := entry at:3.
"/ ipAddr := entry at:4.
info at:name put:macAddr.
].
].
^ info
"
OperatingSystem getNetworkMACAddresses
"
!
getProcessId
"return the (unix-)processId"
%{ /* NOCONTEXT */
int pid = 0;
pid = GetCurrentProcessId() & 0x3FFFFFFF;
RETURN ( __MKSMALLINT(pid) );
%}
"
OperatingSystem getProcessId
"
!
getSystemID
"if supported by the OS, return the systemID;
a unique per machine identification.
WARNING:
not all systems support this; on some, 'unknown' is returned."
%{ /* NO_CONTEXT */
#if defined(HAS_GETHOSTID)
int runningId;
OBJ arr;
runningId = gethostid();
arr = __BYTEARRAY_UNINITIALIZED_NEW_INT(4);
*(int *)(__ByteArrayInstPtr(arr)->ba_element) = runningId;
RETURN (arr);
#endif
#if defined(HAS_SYSINFO) && defined(SI_HW_SERIAL)
{
char buffer[128];
buffer[0] = 0;
if (sysinfo(SI_HW_SERIAL, buffer, sizeof(buffer))) {
buffer[127] = 0;
if (strlen(buffer) > 0) {
RETURN(__MKSTRING(buffer));
}
}
}
#endif
%}.
^ 'unknown'
"
OperatingSystem getSystemID
"
!
getSystemInfo
"return info on the system weare running on.
If the system supports the uname system call, that info is returned;
otherwise, some simulated info is returned.
WARNING:
Do not depend on the amount and contents of the returned information, some
systems may return more/less than others. Also, the contents depends on the
OS, for example, linux returns 'ix86', while WIN32 returns 'x86'.
This method is mainly provided to augment error reports with some system
information.
(in case of system/version specific OS errors, conditional workarounds and patches
may be based upon this info).
Your application should NOT depend upon this in any way.
The returned info may (or may not) contain:
#system -> some operating system identification (irix, Linux, nt, win32s ...)
#version -> OS version (some os version identification)
#release -> OS release (3.5, 1.2.1 ...)
#node -> some host identification (hostname)
#domain -> domain name (hosts domain)
#machine -> type of machine (i586, mips ...)
win32:
#physicalRam -> total amount of physical memory
#freeRam -> amount of free memory
#swapSize -> size of swapSpace (page file)
#freeSwap -> free bytes in swapSpace
#virtualRam -> total amount of virtual memory
#freeVirtual -> amount of free virtual memory
#memoryLoad -> percentage of memory usage (useless)
"
|sys node rel ver mach dom info arch
physicalRam freeRam swapSize freeSwap
virtualRam freeVirtual memoryLoad numberOfCPUs|
%{ /* STACK: 4096 */
char vsnBuffer[32];
char *s;
int winVer, verMinor, verMajor;
DWORD vsn;
SYSTEM_INFO sysInfo;
MEMORYSTATUS memStatus;
int len;
vsn = GetVersion();
winVer = LOWORD(vsn);
verMinor = HIBYTE(winVer);
verMajor = LOBYTE(winVer);
if (HIWORD(vsn) & 0x8000) {
s = "win95";
} else {
if ((verMajor > 5)
|| ((verMajor == 5) && (verMinor >= 1))) {
s = "xp";
} else {
s = "nt";
}
}
sys = __MKSTRING(s);
len = snprintf(vsnBuffer, sizeof(vsnBuffer), "%d.%d", verMajor, verMinor);
rel = __MKSTRING_L(vsnBuffer, len);
GetSystemInfo(&sysInfo);
memStatus.dwLength = sizeof(memStatus);
GlobalMemoryStatus(&memStatus);
memoryLoad = __MKUINT(memStatus.dwMemoryLoad);
physicalRam = __MKUINT(memStatus.dwTotalPhys);
freeRam = __MKUINT(memStatus.dwAvailPhys);
swapSize = __MKUINT(memStatus.dwTotalPageFile);
freeSwap = __MKUINT(memStatus.dwAvailPageFile);
virtualRam = __MKUINT(memStatus.dwTotalVirtual);
freeVirtual = __MKUINT(memStatus.dwAvailVirtual);
#if defined(__BORLANDC__) && (__BORLANDC__ <= 1339)
/* BorlandC3 ... */
switch (sysInfo.u.s.wProcessorArchitecture)
#else
/* MSC, BorlandC4 ... */
switch (sysInfo.wProcessorArchitecture)
#endif
{
#ifdef PROCESSOR_ARCHITECTURE_INTEL
case PROCESSOR_ARCHITECTURE_INTEL:
s = "intel";
break;
#endif
#ifdef PROCESSOR_ARCHITECTURE_MIPS
case PROCESSOR_ARCHITECTURE_MIPS:
s = "mips";
break;
#endif
#ifdef PROCESSOR_ARCHITECTURE_ALPHA
case PROCESSOR_ARCHITECTURE_ALPHA:
s = "alpha";
break;
#endif
#ifdef PROCESSOR_ARCHITECTURE_PPC
case PROCESSOR_ARCHITECTURE_PPC:
s = "ppc";
break;
#endif
#ifdef PROCESSOR_ARCHITECTURE_ARM
case PROCESSOR_ARCHITECTURE_ARM:
s = "arm";
break;
#endif
default:
s = "unknown";
break;
}
arch = __MKSTRING(s);
switch (sysInfo.dwProcessorType) {
#ifdef PROCESSOR_INTEL_386
case PROCESSOR_INTEL_386:
s = "i386";
break;
#endif
#ifdef PROCESSOR_INTEL_486
case PROCESSOR_INTEL_486:
s = "i486";
break;
#endif
#ifdef PROCESSOR_INTEL_PENTIUM
case PROCESSOR_INTEL_PENTIUM:
s = "i586";
break;
#endif
#ifdef PROCESSOR_INTEL_860
case PROCESSOR_INTEL_860:
s = "i860";
break;
#endif
#ifdef PROCESSOR_MIPS_R2000
case PROCESSOR_MIPS_R2000:
s = "r2000";
break;
#endif
#ifdef PROCESSOR_MIPS_R3000
case PROCESSOR_MIPS_R3000:
s = "r3000";
break;
#endif
#ifdef PROCESSOR_MIPS_R4000
case PROCESSOR_MIPS_R4000:
s = "r4000";
break;
#endif
#ifdef PROCESSOR_ALPHA_21064
case PROCESSOR_ALPHA_21064:
s = "alpha21064";
break;
#endif
#ifdef PROCESSOR_ARM_7TDMI
case PROCESSOR_ARM_7TDMI:
s = "arm70001";
break;
#endif
default:
sprintf(vsnBuffer, "%d", sysInfo.dwProcessorType);
s = vsnBuffer;
break;
}
mach = __MKSTRING(s);
numberOfCPUs = __MKUINT(sysInfo.dwNumberOfProcessors);
%}.
sys isNil ifTrue:[
sys := self getSystemType.
].
node isNil ifTrue:[
node := self getHostName.
].
dom isNil ifTrue:[
dom := self getDomainName.
].
mach isNil ifTrue:[
mach := self getCPUType.
].
arch isNil ifTrue:[
arch := 'unknown'.
].
info := IdentityDictionary new.
info at:#system put:sys.
info at:#node put:node.
rel notNil ifTrue:[info at:#release put:rel].
ver notNil ifTrue:[info at:#version put:ver].
mach notNil ifTrue:[info at:#machine put:mach. info at:#cpuType put:mach].
arch notNil ifTrue:[info at:#architecture put:arch].
dom notNil ifTrue:[info at:#domain put:dom].
numberOfCPUs notNil ifTrue:[info at:#numberOfCPUs put:numberOfCPUs].
info at:#memoryLoad put:memoryLoad.
info at:#physicalRam put:physicalRam.
info at:#freeRam put:freeRam.
info at:#swapSize put:swapSize.
info at:#freeSwap put:freeSwap.
info at:#virtualRam put:virtualRam.
info at:#freeVirtual put:freeVirtual.
info at:#osType put:(self getOSType).
^ info
"
OperatingSystem getSystemInfo
"
!
getSystemType
"return a string giving the type of system we're running on.
This is almost the same as getOSType, but the returned string
is slightly different for some systems (i.e. iris vs. irix).
Dont depend on this - use getOSType. I dont really see a point
here ...
(except for slight differences between next/mach and other machs)"
^ 'win32'
"
OperatingSystem getSystemType
"
!
getWindowsDirectory
"internal interface - only for Windows based systems.
Return the windows directory
(which - depending on the system - may be \WINNT, \WINDOWS or whatever)
On non-windows systems, nil is returned."
%{
char buffer[MAXPATHLEN];
if (GetWindowsDirectory(buffer, MAXPATHLEN)) {
RETURN (__MKSTRING(buffer));
}
%}.
^ nil
"
OperatingSystem getWindowsDirectory
"
!
getWindowsSystemDirectory
"internal interface - only for Windows based systems.
Return the windows system directory
(which - depending on the system - may be \WINNT\SYSTEM32,
\WINDOWS\SYSTEM or whatever)
On non-windows systems, nil is returned."
%{
char buffer[MAXPATHLEN];
if (GetSystemDirectory(buffer, MAXPATHLEN)) {
RETURN (__MKSTRING(buffer));
}
%}.
^ nil
"
OperatingSystem getWindowsSystemDirectory
"
!
hasConsole
"return true, if there is some kind of console available
(i.e. for proper stdIn, stdOut and stdErr handling).
This only returns false when running únder windows, and
the system is running as a pure windows application.
If false, the miniDebugger is useless and not used."
%{ /* NOCONTEXT */
extern int __getNoConsoleFlag();
RETURN ( __getNoConsoleFlag() ? false : true);
%}
!
isMSDOSlike
"return true, if the OS we're running on is msdos like
(in contrast to unix-like or vms-like).
This returns true for any of msdos, win32s, win95,
winNT and os/2."
^ true
!
isMSWINDOWSNTlike
"This returns true if running in a Windows-NT system."
%{ /* NOCONTEXT */
if (__isWinNT)
RETURN(true);
%}.
^ false.
!
isMSWINDOWSlike
"return true, if running on a MS-Windows like system.
This returns true for any of win32s, win95 and winNT."
^ true
!
maxFileNameLength
"return the max number of characters in a filename.
CAVEAT:
Actually, the following is somewhat wrong - some systems
support different sizes, depending on the volume.
We return a somewhat conservative number here.
Another entry, to query for volume specific max
will be added in the future."
%{ /* NOCONTEXT */
/*
* TODO: newer systems provide a query function for this ... use it
*/
/*
* mhmh - depends on the filesystem type
*/
RETURN ( __MKSMALLINT(MAXFILELEN) );
%}
"
OperatingSystem maxFileNameLength
"
!
maxPathLength
"return the max number of characters in a pathName."
%{ /* NOCONTEXT */
RETURN ( __MKSMALLINT(MAXPATHLEN) );
%}
"
OperatingSystem maxPathLength
"
!
pathSeparator
"return the character which separates items in the PATH variable"
^ $;
"Created: 2.5.1997 / 11:36:47 / cg"
!
platformName
"return a string describing the OS platform very we're running on.
This returns #unix for all unix derivatives,
#os2, #win32, #vms or #mac for the others.
I.e. it is much less specific than getOSType or getSystemType."
^ #win32
"
OperatingSystem platformName
"
"Modified: 20.6.1997 / 17:37:26 / cg"
!
primGetDomainName
%{
#if 0 /* not needed */
HINSTANCE hNetApi32 = LoadLibrary("netapi32.dll");
DWORD (__stdcall *pfnNetApiBufferFree)(LPVOID Buffer);
DWORD (__stdcall *pfnNetWkstaGetInfo)(LPWSTR servername, DWORD level, void *bufptr);
if (hNetApi32) {
pfnNetApiBufferFree = (DWORD (__stdcall *)(void *)) GetProcAddress(hNetApi32, "NetApiBufferFree");
pfnNetWkstaGetInfo = (DWORD (__stdcall *)(LPWSTR, DWORD, void *)) GetProcAddress(hNetApi32, "NetWkstaGetInfo");
}
if (hNetApi32 && pfnNetWkstaGetInfo && pfnNetApiBufferFree) {
/* this way is more reliable, in case user has a local account. */
char dname[256];
DWORD dnamelen = sizeof(dname);
struct {
DWORD wki100_platform_id;
LPWSTR wki100_computername;
LPWSTR wki100_langroup;
DWORD wki100_ver_major;
DWORD wki100_ver_minor;
} *pwi;
/* NERR_Success *is* 0*/
if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
-1, (LPSTR)dname, dnamelen, NULL, NULL);
}
else {
WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
-1, (LPSTR)dname, dnamelen, NULL, NULL);
}
pfnNetApiBufferFree(pwi);
FreeLibrary(hNetApi32);
RETURN (__MKSTRING(dname));
}
FreeLibrary(hNetApi32);
} else {
/* Win95 doesn't have NetWksta*(), so do it the old way */
char name[256];
DWORD size = sizeof(name);
if (hNetApi32)
FreeLibrary(hNetApi32);
if (GetUserName(name,&size)) {
char sid[1024];
DWORD sidlen = sizeof(sid);
char dname[256];
DWORD dnamelen = sizeof(dname);
SID_NAME_USE snu;
if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
dname, &dnamelen, &snu)) {
RETURN (__MKSTRING(dname)); /* all that for this */
}
}
}
#endif /* not needed */
%}.
^ nil
!
primGetHostName
"return the hostname we are running on - if there is
a HOST environment variable, we are much faster here ...
Notice:
not all systems support this; on some, 'unknown' is returned."
|name|
%{ /* STACK: 2048 */
#if defined(HAS_GETHOSTNAME)
char buffer[256];
if (gethostname(buffer, sizeof(buffer)) == 0) {
name = __MKSTRING(buffer);
}
#else
char buffer[128];
int buffSize = sizeof(buffer);
if (GetComputerName(buffer, &buffSize) == TRUE) {
name = __MKSTRING(buffer);
}
#endif
%}.
name isNil ifTrue:[
name := self getEnvironment:'HOST'.
name isNil ifTrue:[
name := self getEnvironment:'HOSTNAME'.
name isNil ifTrue:[
name := self getEnvironment:'COMPUTERNAME'.
name isNil ifTrue:[
'Win32OperatingSystem [warning]: cannot find out hostname' errorPrintCR.
name := 'unknown'.
]
]
]
].
^ name
"
OperatingSystem primGetHostName
"
!
setLocaleInfo:anInfoDictionary
"set the locale information; if set, this oerrides the OS's settings.
(internal in ST/X only - the OS's settings remain unaffected)
See description of fields in #getLocaleInfo.
Notice, that (for now), the system does not use this information;
it should be used by applications as required."
LocaleInfo := anInfoDictionary
"
|d|
d := IdentityDictionary new.
d at:#decimalPoint put:'.' .
d at:#thousandsSeparator put:',' .
d at:#currencySymbol put:'USD' .
d at:#monetaryDecimalPoint put:'.' .
d at:#monetaryThousandsSeparator put:'.' .
d at:#fractionalDigits put:2 .
d at:#positiveSign put:'+' .
d at:#negativeSign put:'-' .
d at:#positiveSignPrecedesCurrencySymbol put:true .
d at:#negativeSignPrecedesCurrencySymbol put:false .
OperatingSystem setLocaleInfo:d
"
!
supportsChildInterrupts
"return true, if the OS supports childProcess termination signalling
through interrupts (i.e. SIGCHILD)"
%{ /* NOCONTEXT */
#if defined(SIGCHLD) || defined(SIGCLD)
RETURN (true);
#endif
%}.
^ false
"
OperatingSystem supportsChildInterrupts
"
!
supportsFileOwnerGroups
"return true, if the OS's file system supports file
group ownership - all OS's except windows do"
^ false
"Created: / 10.9.1998 / 17:57:03 / cg"
!
supportsFileOwners
"return true, if the OS's file system supports file
ownership - all OS's except windows do"
^ false
"Created: / 10.9.1998 / 17:55:16 / cg"
"Modified: / 10.9.1998 / 17:57:11 / cg"
!
supportsIOInterrupts
"return true, if the OS supports IO availability interrupts
(i.e. SIGPOLL/SIGIO).
Currently, this mechanism does not work on all
systems ...
"
^ false
"
OperatingSystem supportsIOInterrupts
"
!
supportsNonBlockingIO
"return true, if the OS supports nonblocking IO."
^ false
"
OperatingSystem supportsNonBlockingIO
"
!
supportsSelect
"return true, if the OS supports selecting on multiple
filedescriptors via select.
If false is returned, ProcessorScheduler will poll in 50ms
intervals for I/O becoming ready."
%{ /* NOCONTEXT */
# if defined(WIN32S)
RETURN (false);
# endif
%}.
^ true
"
OperatingSystem supportsSelect
"
!
supportsSelectOnPipes
"return true, if the OS supports selecting on pipe
filedescriptors via select.
If false is returned, ProcessorScheduler will poll in 50ms
intervals for I/O becoming ready."
^ false
"
OperatingSystem supportsSelectOnPipes
"
"Modified: / 14.12.1999 / 19:41:03 / cg"
"Created: / 14.12.1999 / 19:43:13 / cg"
!
supportsSelectOnSockets
"return true, if the OS supports selecting on socket
filedescriptors via select.
If false is returned, ProcessorScheduler will poll in 50ms
intervals for I/O becoming ready."
^ false
"
OperatingSystem supportsSelectOnSockets
"
"Modified: / 14.12.1999 / 19:41:03 / cg"
!
supportsVolumes
"return true, if the OS supports disk volumes.
False is returned for UNIX, true for MSDOS and VMS"
^ true
! !
!Win32OperatingSystem class methodsFor:'path queries'!
defaultPackagePath
|pPath pkgDirPath dirs p|
pPath := super defaultPackagePath.
pkgDirPath := self stxPackageDirPath.
pkgDirPath notNil ifTrue:[
"/ and also add the packageDirPath from the registry ...
dirs := pkgDirPath asCollectionOfSubstringsSeparatedBy:$;.
dirs do:[:aDir |
(pPath includes:aDir) ifFalse:[
pPath add:aDir.
]
]
] ifFalse:[
#(
'\smalltalk'
'\programme\smalltalk'
'\programme\eXept\smalltalk'
'\programs\smalltalk'
'\programs\eXept\smalltalk'
) do:[:d | |dd|
dd := d asFilename constructString:'packages'.
(pPath includes:dd) ifFalse:[
pPath add:dd.
].
dd := (d asFilename construct:Smalltalk versionString) constructString:'packages'.
(pPath includes:dd) ifFalse:[
pPath add:dd.
].
].
].
"/ under windows, the commandName includes the path - good.
p := Smalltalk commandName.
p notNil ifTrue:[
p := p asFilename directory constructString:'packages'.
(pPath includes:p) ifFalse:[
pPath add:p.
]
].
pPath := pPath select:[:p | p asFilename exists].
^ pPath
"
self defaultPackagePath
"
"Created: / 24.12.1999 / 00:10:41 / cg"
"Modified: / 24.12.1999 / 00:33:26 / cg"
!
defaultSystemPath
|sysPath libDirPath p|
sysPath := super defaultSystemPath.
libDirPath := self stxLibDirPath.
libDirPath notNil ifTrue:[
"/ and also add the libDirPath from the registry ...
(sysPath includes:libDirPath) ifFalse:[
sysPath add:libDirPath
].
] ifFalse:[
#(
'\smalltalk'
'\programme\smalltalk'
'\programme\eXept\smalltalk'
'\programs\smalltalk'
'\programs\eXept\smalltalk'
) do:[:d | |dd|
(d asFilename isDirectory) ifTrue:[
(sysPath includes:d) ifFalse:[
sysPath add:d.
].
dd := d , '\' , Smalltalk versionString.
(sysPath includes:dd) ifFalse:[
sysPath add:dd.
]
]
].
].
"/ under windows, the commandName includes the path - good.
p := Smalltalk commandName.
p notNil ifTrue:[
p := p asFilename directoryName.
(sysPath includes:p) ifFalse:[
sysPath add:p.
]
].
^ sysPath
"Modified: / 24.12.1999 / 00:29:18 / cg"
!
stxBinDirPath
"ask the registry for the binary directory"
|k p|
k := RegistryEntry key:'HKEY_LOCAL_MACHINE\SOFTWARE\eXept\Smalltalk/X\' , Smalltalk versionString.
k notNil ifTrue:[
p := k valueNamed:'BinDir'.
].
^ p
"
OperatingSystem stxBinDirPath
"
!
stxLibDirPath
"ask the registry for the lib directory"
|k p|
k := RegistryEntry key:'HKEY_LOCAL_MACHINE\SOFTWARE\eXept\Smalltalk/X\' , Smalltalk versionString.
k notNil ifTrue:[
p := k valueNamed:'LibDir'.
].
^ p
"
OperatingSystem stxLibDirPath
"
!
stxPackageDirPath
"ask the registry for the package directory"
|k p|
k := RegistryEntry key:'HKEY_LOCAL_MACHINE\SOFTWARE\eXept\Smalltalk/X\' , Smalltalk versionString.
k notNil ifTrue:[
p := k valueNamed:'PackageDirPath'.
].
^ p
"
OperatingSystem stxPackageDirPath
"
"Created: / 24.12.1999 / 00:11:12 / cg"
! !
!Win32OperatingSystem class methodsFor:'private'!
mapLanguage:aWindowsLanguageString
"map a windows language string to ISO languageCode_languageTerritory
format"
|windowsLanguageString|
windowsLanguageString := aWindowsLanguageString asUppercase.
#('DEU' 'de_DE'
'DES' 'de_CH'
'DEA' 'de_AT'
'DAN' 'da_DA'
'ENA' 'en_AU'
'ENC' 'en_CA'
'ENG' 'en_GB'
'ENI' 'en_IR'
'ENU' 'en_US'
'ENZ' 'en_NZ'
'FRA' 'fr_FR'
'FRB' 'fr_BE'
'FRC' 'fr_CA'
'FRS' 'fr_CH'
'ITA' 'it_IT'
'ITS' 'it_CH'
'ESM' 'es_MX'
'ESN' 'es_ES'
'ESP' 'es' "Castillian"
'NLB' 'nl_BE'
'NLD' 'nl_NL'
'CSY' 'cs_CS'
'ELL' 'el_EL'
'NON' 'no_NO'
'NOR' 'no_NO'
) pairWiseDo:[:key :mappedValue|
key = windowsLanguageString ifTrue:[
^ mappedValue
]
].
"no mapping"
^ windowsLanguageString.
"
self mapLanguage:'DEU'
"
!
osProcessStatusClass
^ OSProcessStatus
"Created: / 12.6.1998 / 16:30:43 / cg"
! !
!Win32OperatingSystem class methodsFor:'socket creation'!
socketAccessor
^ Win32SocketHandle
! !
!Win32OperatingSystem class methodsFor:'system management'!
exitWindows
"do not use - may be removed without notice"
self exitWindows:#shutdown confirm:'Do you really want to shutdown the system'
!
exitWindows:how confirm:confirmationMessageOrNil
"this method is temporary -
since my windows system menu crashes so often
(even CTRL-ALT-DEL does no longer function, but ST/X is still alive),
I added this in order to be able to shutdown w95 cleanly"
confirmationMessageOrNil notNil ifTrue:[
(Dialog confirm:confirmationMessageOrNil) ifFalse:[
^ false
].
].
%{
int flag;
if (how == @symbol(shutdown)) {
flag = EWX_SHUTDOWN;
} else if (how == @symbol(reboot)) {
flag = EWX_REBOOT;
} else if (how == @symbol(logoff)) {
flag = EWX_LOGOFF;
} else if (how == @symbol(forceShutdown)) {
flag = EWX_SHUTDOWN | EWX_FORCE;
} else if (how == @symbol(forceReboot)) {
flag = EWX_REBOOT | EWX_FORCE;
} else if (how == @symbol(forceLogoff)) {
flag = EWX_LOGOFF | EWX_FORCE;
} else {
RETURN (false);
}
RETURN ((ExitWindowsEx(flag, 0) == TRUE) ? true : false);
%}
! !
!Win32OperatingSystem class methodsFor:'time and date'!
computeDatePartsOf:osTime for:aBlock
"compute year, month and day from the OS time, osTime
and evaluate the argument, a 3-arg block with these.
Conversion is to localtime including any daylight saving adjustments."
|year month day osSeconds|
osSeconds := osTime // 1000.
%{
struct tm* tmPtr;
INT t;
TIME_T tt;
t = __longIntVal(osSeconds);
tt = (TIME_T)t;
tmPtr = localtime(&tt);
year = __MKSMALLINT(tmPtr->tm_year + 1900);
month = __MKSMALLINT(tmPtr->tm_mon + 1);
day = __MKSMALLINT(tmPtr->tm_mday);
%}.
aBlock value:year value:month value:day
"
OperatingSystem computeDatePartsOf:0 for:[:y :m :d |
y printCR. m printCR. d printCR
]
"
!
computeOSTimeFromUTCYear:y month:m day:d hour:h minute:min second:s millisecond:millis
"return the OS-dependent time for the given time and day.
The arguments are assumed to be in localtime including
any daylight saving adjustings."
|osSeconds|
%{
struct tm tm;
if (__bothSmallInteger(y, m)
&& __bothSmallInteger(d, h)
&& __bothSmallInteger(min, s)) {
TIME_T t;
int utcOffset;
tm.tm_hour = __intVal(h);
tm.tm_min = __intVal(min);
tm.tm_sec = __intVal(s);
tm.tm_year = __intVal(y) - 1900;
tm.tm_mon = __intVal(m) - 1;
tm.tm_mday = __intVal(d);
tm.tm_isdst = -1;
if (tm.tm_isdst == 0) {
utcOffset = __MKINT(TIMEZONE(tmPtr));
} else {
#ifdef HAS_ALTZONE
utcOffset = __MKINT(altzone);
#else
utcOffset = __MKINT(TIMEZONE(tmPtr) + 3600);
#endif
}
t = mktime(&tm);
osSeconds = __MKUINT((INT)t);
}
%}.
osSeconds notNil ifTrue:[
^ osSeconds * 1000 + millis
].
^ self primitiveFailed
"
OperatingSystem computeOSTimeFromUTCYear:1970 month:1 day:1 hour:0 minute:0 seconds:0 millis:0
"
!
computeOSTimeFromYear:y month:m day:d hour:h minute:min seconds:s millis:millis
"return the OS-dependent time for the given time and day.
The arguments are assumed to be in localtime including
any daylight saving adjustings."
|osSeconds|
%{
struct tm tm;
TIME_T t;
if (__bothSmallInteger(y, m)
&& __bothSmallInteger(d, h)
&& __bothSmallInteger(min, s)) {
tm.tm_hour = __intVal(h);
tm.tm_min = __intVal(min);
tm.tm_sec = __intVal(s);
tm.tm_year = __intVal(y) - 1900;
tm.tm_mon = __intVal(m) - 1;
tm.tm_mday = __intVal(d);
tm.tm_isdst = -1;
t = mktime(&tm);
osSeconds = __MKUINT((INT)t);
}
%}.
osSeconds notNil ifTrue:[
^ osSeconds * 1000 + millis
].
^ self primitiveFailed
"
OperatingSystem computeOSTimeFromYear:1970 month:1 day:1 hour:0 minute:0 seconds:0 millis:0
"
!
computeTimePartsOf:osTime for:aBlock
"compute hours, minutes, seconds and milliseconds from the osTime
and evaluate the argument, a 4-arg block with these.
Conversion is to localtime including any daylight saving adjustments."
|hours minutes seconds millis osSeconds|
osSeconds := osTime // 1000.
millis := osTime \\ 1000.
%{
struct tm *tmPtr;
INT t;
TIME_T tt;
t = __longIntVal(osSeconds);
tt = (TIME_T)t;
tmPtr = localtime(&tt);
hours = __MKSMALLINT(tmPtr->tm_hour);
minutes = __MKSMALLINT(tmPtr->tm_min);
seconds = __MKSMALLINT(tmPtr->tm_sec);
%}.
aBlock value:hours value:minutes value:seconds value:millis
"
OperatingSystem computeTimePartsOf:100 for:[:h :m :s :milli |
h printCR. m printCR. s printCR. millis printCR
]
"
!
computeUTCTimeAndDateFrom:osTime
"given an OS-dependent time in osTime, return an Array
containing year, month, day, hour, minute and seconds,
offset to UTC, daylight savings time flag, milliseconds,
dayInYear (1..) and dayInWeek (1..).
Conversion is to UTC."
|low hi year month day hours minutes seconds millis utcOffset
dst yDay wDay osSeconds ret|
millis := osTime \\ 1000.
osSeconds := osTime // 1000.
%{
struct tm *tmPtr;
struct tm *gmTmPtr;
long t;
t = __longIntVal(osSeconds);
tmPtr = gmtime(&t);
hours = __MKSMALLINT(tmPtr->tm_hour);
minutes = __MKSMALLINT(tmPtr->tm_min);
seconds = __MKSMALLINT(tmPtr->tm_sec);
year = __MKSMALLINT(tmPtr->tm_year + 1900);
month = __MKSMALLINT(tmPtr->tm_mon + 1);
day = __MKSMALLINT(tmPtr->tm_mday);
yDay = __MKSMALLINT(tmPtr->tm_yday + 1);
wDay = __MKSMALLINT(tmPtr->tm_wday == 0 ? 7 : tmPtr->tm_wday);
if (tmPtr->tm_isdst == 0) {
dst = false;
utcOffset = __MKINT(TIMEZONE(tmPtr));
} else {
dst = true;
#ifdef HAS_ALTZONE
utcOffset = __MKINT(altzone);
#else
utcOffset = __MKINT(TIMEZONE(tmPtr) + 3600);
#endif
}
%}.
"I would love to have SELF-like inline objects ..."
ret := Array new:11.
ret at:1 put:year.
ret at:2 put:month.
ret at:3 put:day.
ret at:4 put:hours.
ret at:5 put:minutes.
ret at:6 put:seconds.
ret at:7 put:utcOffset.
ret at:8 put:dst.
ret at:9 put:millis.
ret at:10 put:yDay.
ret at:11 put:wDay.
^ ret
"
OperatingSystem computeUTCTimeAndDateFrom:0
"
!
computeUTCTimePartsOf:osTime for:aBlock
"compute hours, minutes, seconds and milliseconds from the osTime
and evaluate the argument, a 4-arg block with these.
Conversion is to UTC."
|hours minutes seconds millis osSeconds|
osSeconds := osTime // 1000.
millis := osTime \\ 1000.
%{
struct tm *tmPtr;
long t;
t = __longIntVal(osSeconds);
tmPtr = gmtime(&t);
hours = __MKSMALLINT(tmPtr->tm_hour);
minutes = __MKSMALLINT(tmPtr->tm_min);
seconds = __MKSMALLINT(tmPtr->tm_sec);
%}.
aBlock value:hours value:minutes value:seconds value:millis
"
OperatingSystem computeUTCTimePartsOf:100 for:[:h :m :s :milli |
h printCR. m printCR. s printCR. milli printCR
]
"
!
getMillisecondTime
"This returns the millisecond timers value.
The range is limited to 0..1fffffff (i.e. the SmallInteger range) to avoid
LargeInteger arithmetic when doing timeouts and delays.
Since this value is wrapping around in regular intervals, this can only be used for
short relative time deltas.
Use the millisecondTimeXXX:-methods to compare and add time deltas - these know about the wrap.
BAD DESIGN:
This should be changed to return some instance of RelativeTime,
and these computations moved there.
Dont use this method in application code since it is an internal (private)
interface. For compatibility with ST-80, use Time millisecondClockValue.
"
%{ /* NOCONTEXT */
long t = 0;
#if !defined(HAS_GETTIMEOFDAY)
# if defined(HAS_FTIME)
struct timeb timebuffer;
ftime(&timebuffer);
t = (timebuffer.time * 1000) + timebuffer.millitm;
# define HAVE_TIME
# endif
# ifndef HAVE_TIME
# ifdef WIN32
t = GetTickCount();
# define HAVE_TIME
# endif
# endif
# ifndef HAVE_TIME
# ifdef MSDOS_LIKE
# ifdef __BORLANDC__
struct timeb timebuffer;
ftime(&timebuffer);
# else
struct _timeb timebuffer;
_ftime(&timebuffer);
# endif
t = (timebuffer.time * 1000) + timebuffer.millitm;
# define HAVE_TIME
# endif
# endif
#endif
#ifndef HAVE_TIME
/* assume HAS_GETTIMEOFDAY
* - will result in a linkage error
* if not fixed.
*/
/*
* bsd time
*/
struct timeval tb;
struct timezone tzb;
gettimeofday(&tb, &tzb);
t = tb.tv_sec*1000 + tb.tv_usec/1000;
#endif
#undef HAVE_TIME
RETURN ( __MKSMALLINT(t & 0x1FFFFFFF) );
%}
!
getOSTime
"This returns the OS time.
The base of the returned value is not consistent across
different OS's - some return the number of millis since jan, 1st 1970;
others since 1900. The Time classes are prepared for this, and
converts as appropriate (by using my fromOSTime: conversion methods).
Dont use this method in application code since it is an internal (private)
interface. For compatibility with ST-80, use Time>>millisecondClockValue.
or use instances of Time, Date or Timestamp to work with.
"
|seconds millis|
%{
long t;
#if !defined(HAS_GETTIMEOFDAY)
# if defined(HAS_FTIME)
struct timeb timebuffer;
ftime(&timebuffer);
seconds = __MKUINT(timebuffer.time);
millis = __MKUINT(timebuffer.millitm);
# define HAVE_TIME
# endif
# ifndef HAVE_TIME
# ifdef MSDOS_LIKE
# ifdef __BORLANDC__
struct timeb timebuffer;
ftime(&timebuffer);
# else
struct _timeb timebuffer;
_ftime(&timebuffer);
# endif
seconds = __MKUINT(timebuffer.time);
millis = __MKUINT(timebuffer.millitm);
# define HAVE_TIME
# endif
# endif
#endif
#ifndef HAVE_TIME
/* assume HAS_GETTIMEOFDAY
* - will result in a linkage error
* if not fixed.
*/
/*
* bsd time
*/
struct timeval tb;
struct timezone tzb;
gettimeofday(&tb, &tzb);
seconds = __MKUINT(tb.tv_sec);
millis = __MKUINT(tb.tv_usec / 1000);
#endif
#undef HAVE_TIME
%}.
^ (seconds * 1000) + millis
"
OperatingSystem getOSTime printCR.
Delay waitForSeconds:0.2.
OperatingSystem getOSTime printCR.
"
!
sleep:numberOfSeconds
"{ Pragma: +optSpace }"
"cease ANY action for some time. This suspends the whole smalltalk
(unix-) process for some time.
Not really useful since not even low-prio processes and interrupt
handling will run during the sleep.
Use either OperatingSystem>>millisecondDelay: (which makes all
threads sleep, but handles interrupts) or use a Delay (which makes
only the calling thread sleep)."
%{ /* NOCONTEXT */
if (__isSmallInteger(numberOfSeconds)) {
sleep(__intVal(numberOfSeconds));
RETURN ( self );
}
%}.
"
argument not integer
"
^ self primitiveFailed
"
OperatingSystem sleep:2
"
!
timeInfoFromSeconds:osSeconds milliseconds:osMilliSeconds localTime:isLocalTime
"return a timeInfo structure containing values for the given
OS-second value.
An internal helper"
|low hi year month day hours minutes seconds utcOffset
dst yDay wDay info|
%{
struct tm *tmPtr;
struct tm *gmTmPtr;
INT t;
TIME_T tt;
t = __longIntVal(osSeconds);
tt = (TIME_T)t;
tmPtr = localtime(&tt);
hours = __MKSMALLINT(tmPtr->tm_hour);
minutes = __MKSMALLINT(tmPtr->tm_min);
seconds = __MKSMALLINT(tmPtr->tm_sec);
year = __MKSMALLINT(tmPtr->tm_year + 1900);
month = __MKSMALLINT(tmPtr->tm_mon + 1);
day = __MKSMALLINT(tmPtr->tm_mday);
yDay = __MKSMALLINT(tmPtr->tm_yday+1);
wDay = __MKSMALLINT(tmPtr->tm_wday == 0 ? 7 : tmPtr->tm_wday);
if (tmPtr->tm_isdst == 0) {
dst = false;
utcOffset = __MKINT(TIMEZONE(tmPtr));
} else {
dst = true;
#ifdef HAS_ALTZONE
utcOffset = __MKINT(altzone);
#else
utcOffset = __MKINT(TIMEZONE(tmPtr) + 3600);
#endif
}
%}.
info := self timeInfoClass new.
info
year:year
month:month
day:day
hours:hours
minutes:minutes
seconds:seconds
milliseconds:osMilliSeconds
utcOffset:utcOffset
dst:dst
dayInYear:yDay
dayInWeek:wDay.
^ info
"
OperatingSystem timeInfoFromSeconds:0 localTime:false
"
! !
!Win32OperatingSystem class methodsFor:'users & groups'!
getEffectiveGroupID
"{ Pragma: +optSpace }"
"return the current users (thats you) effective numeric group id.
This is only different from getGroupID, if you have ST/X running
as a setuid program (of which you should think about twice)."
^ self getGroupID
"
OperatingSystem getEffectiveGroupID
"
!
getEffectiveUserID
"{ Pragma: +optSpace }"
"return the current users (thats you) effective numeric user id.
This is only different from getUserID, if you have ST/X running
as a setuid program (of which you should think about twice)."
^ self getUserID
"
OperatingSystem getEffectiveUserID
"
!
getFullUserNameFromID:userID
"{ Pragma: +optSpace }"
"return a string with the users full name - if available.
If not, return the login name as a fallBack."
|info gecos|
info := self userInfoOf:userID.
(info notNil
and:[info includesKey:#gecos]) ifTrue:[
gecos := info at:#gecos.
(gecos includes:$,) ifTrue:[
^ gecos copyTo:(gecos indexOf:$,) - 1
].
^ gecos
].
^ self getUserNameFromID:userID
"
OperatingSystem getFullUserNameFromID:0
OperatingSystem getFullUserNameFromID:(OperatingSystem getUserID)
OperatingSystem getUserNameFromID:(OperatingSystem getUserID)
"
"Modified: 15.7.1996 / 12:44:21 / cg"
!
getGroupID
"{ Pragma: +optSpace }"
"return the current users (thats you) numeric group id"
^ 1 "just a dummy for systems which do not have groupIDs"
"
OperatingSystem getGroupID
"
!
getGroupNameFromID:aNumber
"{ Pragma: +optSpace }"
"return the group-name-string for a given numeric group-id"
^ '???' "just a dummy for systems which do not have groupIDs"
"
OperatingSystem getGroupNameFromID:0
OperatingSystem getGroupNameFromID:10
"
!
getHomeDirectory
"{ Pragma: +optSpace }"
"return the name of the users home directory (i.e. yours).
This uses the value of the HOME environment variable,
or HOMESHARE or HOMEDRIVE:HOMEPATH as a fallBack.
If not set, return the current directory."
|dir drv path|
dir := self getEnvironment:'HOME'.
dir isNil ifTrue:[
"for NT/WIN2K/XP users:
if HOME is nil, try first HOMEHSARE and then HOMEDRIVE and HOMEPATH"
dir := self getEnvironment:'HOMESHARE'.
dir isNil ifTrue:[
((drv := self getEnvironment:'HOMEDRIVE') notNil
and:[(path := self getEnvironment:'HOMEPATH') notNil]) ifTrue:[
dir := drv , path
] ifFalse:[
dir := '.'.
].
].
].
^ dir
"
OperatingSystem getHomeDirectory
"
"Modified: / 16.2.2000 / 09:17:55 / cg"
!
getLoginName
"{ Pragma: +optSpace }"
"return a string with the users login name (thats yours)"
%{ /* NOCONTEXT */
static char cachedName[64];
static firstCall = 1;
#ifndef __BORLANDC__
extern char *getenv();
#endif
char *name = (char *)0;
if (firstCall) {
int nameSize = sizeof(cachedName);
if (GetUserName(cachedName, &nameSize) == TRUE) {
name = cachedName;
firstCall = 0;
}
} else {
name = cachedName;
}
/*
* try a few common environment variables ...
*/
if (! name || (name[0] == 0) ) {
name = getenv("LOGIN");
if (! name || (name[0] == 0) ) {
name = getenv("LOGNAME");
if (! name || (name[0] == 0) ) {
name = getenv("USER");
}
}
}
/*
* nope - I really font know who you are.
*/
if (! name || (name[0] == 0) ) {
name = "you";
}
RETURN ( __MKSTRING(name) );
%}.
"
OperatingSystem getLoginName
"
!
getUserID
"{ Pragma: +optSpace }"
"return the current users (thats you) numeric user id"
^ 1 "just a dummy for systems which do not have userIDs"
"
OperatingSystem getUserID
"
!
getUserNameFromID:aNumber
"{ Pragma: +optSpace }"
"return the user-name-string for a given numeric user-id.
This is the login name, not the fullName."
aNumber == self getUserID ifTrue:[
^ self getLoginName
].
^ '? (' , aNumber printString , ')'
"
OperatingSystem getUserNameFromID:0
OperatingSystem getUserNameFromID:100
OperatingSystem getUserNameFromID:9991
"
!
userInfoOf:aNameOrID
"{ Pragma: +optSpace }"
"return a dictionary filled with userinfo. The argument can be either
a string with the users name or its numeric id.
Notice, that DOS systems only provide a very limited set of information.
Portable applications may want to check the systemType and NOT depend
on all keys to be present in the returned dictionary."
|info name "uid gid" dir|
info := IdentityDictionary new.
name isNil ifTrue:[
aNameOrID == self getUserID ifTrue:[
name := self getLoginName
].
].
name notNil ifTrue:[
info at:#name put:name.
] ifFalse:[
info at:#name put:'unknown'
].
dir isNil ifTrue:[
aNameOrID == self getUserID ifTrue:[
dir := self getHomeDirectory
]
].
dir notNil ifTrue:[info at:#dir put:dir].
"/ uid notNil ifTrue:[info at:#uid put:uid].
"/ gid notNil ifTrue:[info at:#gid put:gid].
^ info
"
OperatingSystem userInfoOf:'root'
OperatingSystem userInfoOf:1
OperatingSystem userInfoOf:'claus'
OperatingSystem userInfoOf:'fooBar'
OperatingSystem userInfoOf:(OperatingSystem getUserID)
"
! !
!Win32OperatingSystem class methodsFor:'waiting for events'!
blockingChildProcessWait
"return true, if childProcessWait: blocks, if no children are ready.
On those systems, we must be somewhat careful when looking out for
a subprocesses status (to avoid blocking)."
^ false
!
childProcessWait:blocking pid:pidToWait
"{ Pragma: +optSpace }"
"get status changes from child processes.
Return an OSProcessStatus or nil, if no process has terminated.
If blocking is true, we wait until a process changed state,
otherwise we return immediately.
Note that win32 needs to know the HANDLE of the process on which
it waits. In case of an error, THIS ALWAYS WAITS and then times out."
|pid status code core|
%{
DWORD endStatus;
if (__isExternalAddressLike(pidToWait) ) {
HANDLE __pidToWait = _HANDLEVal(pidToWait);
int t;
#ifdef PROCESSDEBUG_CHILDPROCESSWAIT
printf("childProcessWait %x b %d\n",__pidToWait,blocking==true);
#endif
t = blocking==true ? INFINITE : 0;
#ifdef DO_WRAP_CALLS
do {
__threadErrno = 0;
endStatus = STX_API_CALL2( "WaitForSingleObject", WaitForSingleObject, __pidToWait, t);
} while ((endStatus < 0) && (__threadErrno == EINTR));
#else
endStatus = WaitForSingleObject(__pidToWait, t);
if (endStatus < 0) {
__threadErrno = __WIN32_ERR(GetLastError());
}
#endif
if ( endStatus == WAIT_TIMEOUT ) {
if (blocking==true)
status = @symbol(timeout);
else {
status = @symbol(continue);
#ifdef PROCESSDEBUG_CHILDPROCESSWAIT
printf("ret nil\n");
#endif
RETURN(nil);
}
} else {
status = @symbol(exit);
#ifdef PROCESSDEBUG_CHILDPROCESSWAIT
printf("exit\n");
#endif
if (endStatus == WAIT_OBJECT_0) {
if (GetExitCodeProcess(__pidToWait, &endStatus)) {
if (endStatus == STILL_ACTIVE) {
RETURN(nil);
}
#ifdef PROCESSDEBUG_CHILDPROCESSWAIT
printf("exit %d\n",endStatus);
#endif
code = __MKSMALLINT(endStatus);
} else {
code = __MKSMALLINT(GetLastError());
}
} else {
code = __MKSMALLINT(-1);
}
}
core = false;
pid = pidToWait;
}
%}.
(status isNil or:[pid isNil]) ifTrue:[
^ self primitiveFailed
].
"/ Transcript show:'pid: '; show:pid; show:' status: '; show:status;
"/ show:' code: '; show:code; show:' core:'; showCR:core.
^ OSProcessStatus pid:pid status:status code:code core:core
"
OperatingSystem childProcessWait:false
"
"Created: 5.1.1996 / 16:39:14 / stefan"
!
numAvailableForReadOn:fd
"return the number of bytes available for reading, without blocking."
^ (self readCheck:fd) ifTrue:[1] ifFalse:[0]
!
readCheck:fd
"return true, if data is available on a filedescriptor
(i.e. read is possible without blocking).
This depends on a working select or FIONREAD to be provided by the OS."
^ super readCheck:fd
!
selectOnAnyReadable:readFdArray writable:writeFdArray exception:exceptFdArray withTimeOut:millis
"wait for any fd in readFdArray (an Array of integers) to become ready for
reading, writeFdArray to become ready for writing, or exceptFdArray to
arrive exceptional data (i.e. out-of-band data).
Timeout after t milliseconds or, if the timeout time is 0, immediately..
Empty fd-sets will always wait. Zero time can be used to poll file-
descriptors (i.e. to check if I/O possible without blocking).
Return first ready fd if I/O ok, nil if timed-out or interrupted."
%{
#define MAXHANDLE 128
int i;
INT t;
OBJ fd, retFd;
int ret;
int numHandles = 0;
DWORD res;
HANDLE hArray[MAXHANDLE+1];
int retArray[MAXHANDLE];
int readCount;
int writeCount;
int exceptCount;
if (__isNonNilObject(readFdArray)) {
if (! __isArray(readFdArray)) goto fail;
readCount = __arraySize(readFdArray);
} else {
readCount = 0;
}
if (__isNonNilObject(writeFdArray)) {
if (! __isArray(writeFdArray)) goto fail;
writeCount = __arraySize(writeFdArray);
} else {
writeCount = 0;
}
if (__isNonNilObject(exceptFdArray)) {
if (! __isArray(exceptFdArray)) goto fail;
exceptCount = __arraySize(exceptFdArray);
} else {
exceptCount = 0;
}
for (i = 0; (i < readCount) && (numHandles < MAXHANDLE);i++) {
fd = __ArrayInstPtr(readFdArray)->a_element[i];
if (fd != nil) {
if (__isExternalAddressLike(fd)) {
hArray [numHandles] = _HANDLEVal(fd);
retArray[numHandles] = i;
++numHandles;
} else {
if (_canReadWithoutBlocking (__intVal(fd) ) ) {
RETURN (fd);
}
}
}
}
for (i = 0; (i < writeCount) && (numHandles < MAXHANDLE);i++) {
fd = __ArrayInstPtr(writeFdArray)->a_element[i];
if (fd != nil) {
if (__isExternalAddressLike(fd)) {
hArray [numHandles] = _HANDLEVal(fd);
retArray[numHandles] = i + 10000;
++numHandles;
} else {
if (_canWriteWithoutBlocking (__intVal(fd) ) ) {
RETURN (fd);
}
}
}
}
for (i = 0; (i < exceptCount) && (numHandles < MAXHANDLE);i++) {
fd = __ArrayInstPtr(exceptFdArray)->a_element[i];
if (fd != nil) {
if (__isExternalAddressLike(fd)) {
hArray [numHandles] = _HANDLEVal(fd);
retArray[numHandles] = i + 20000;
++numHandles;
}
}
}
if (__isSmallInteger(millis)) {
t = __intVal(millis);
if (t <= 0 && numHandles == 0) {
RETURN (nil);
}
} else {
t = INFINITE;
}
#ifdef SELECT3DEBUGWIN32
printf("wait Handles = %d timeout = %d\n",numHandles, t);
#endif
res = __vmWait (numHandles, hArray, MAXHANDLE, t);
if (numHandles) {
if (res == WAIT_FAILED) {
#ifdef SELECT2DEBUGWIN32
printf("- error %d; ret nil\n",GetLastError());
#endif
if (__threadErrno == EINTR) {
__threadErrno = 0;
@global(LastErrorNumber) = nil;
} else {
__threadErrno = EBADF;
if (@global(InfoPrinting) == true) {
fprintf(stderr, "Win32OS [info]: select errno = %d\n", __threadErrno);
}
@global(LastErrorNumber) = __MKSMALLINT(__threadErrno);
}
RETURN ( nil );
}
if (res == WAIT_TIMEOUT) {
#ifdef SELECT3DEBUGWIN32
printf("- timeOut; ret nil\n" );
#endif
goto polling;
}
if ((res < 0) || (res >= numHandles)) {
#ifdef SELECTDEBUGWIN32
printf("- res=%d error1 %d\n", res, GetLastError());
#endif
__threadErrno = 0;
@global(LastErrorNumber) = nil;
RETURN ( nil );
}
ret = res;
if (ret < numHandles) {
int fd = retArray[ret];
@global(LastErrorNumber) = nil;
#ifdef SELECTDEBUGWIN32
if (ret) printf("wait Handles %d %d ret\n", ret, fd);
#endif
if (fd < 10000) {
RETURN ( __ArrayInstPtr(readFdArray)->a_element[fd] );
}
if (fd < 20000) {
RETURN ( __ArrayInstPtr(writeFdArray)->a_element[fd-10000] );
}
RETURN ( __ArrayInstPtr(exceptFdArray)->a_element[fd-20000] );
}
fprintf(stderr, "Win32OS [info]: wait Handles ret = %d error2 %d\n", ret, GetLastError());
goto fail;
} else {
polling:
for (i=0; i < readCount;i++) {
fd = __ArrayInstPtr(readFdArray)->a_element[i];
if (fd != nil) {
if (! __isExternalAddressLike(fd)) {
if (_canReadWithoutBlocking (__intVal(fd)) ) {
RETURN (fd);
}
}
}
}
for (i=0; i < writeCount;i++) {
fd = __ArrayInstPtr(writeFdArray)->a_element[i];
if (fd != nil) {
if (! __isExternalAddressLike(fd)) {
if (_canWriteWithoutBlocking (__intVal(fd)) ) {
RETURN (fd);
}
}
}
}
@global(LastErrorNumber) = nil;
RETURN ( nil );
}
fail: ;
%}.
"
timeout argument not integer,
or any fd-array nonNil and not an array
or not supported by OS
"
^ self primitiveFailed
!
setBlocking:aBoolean on:fd
"{ Pragma: +optSpace }"
"set/clear the blocking attribute - if set (which is the default)
a read on the fileDescriptor will block until data is available.
If cleared, a read operation will immediately return with a value of
nil."
^ self "/ primitiveFailed
!
waitForMultipleObjects:fdOrHandleArray withTimeout:millis
"wait for an fd to become ready.
Timeout after t milliseconds or, if the timeout time is 0, immediately..
Zero time can be used to poll a file-
descriptors (i.e. to check if I/O possible without blocking).
Return the fd if I/O ok, nil if timed-out or interrupted."
%{
#ifndef MAXHANDLE
# define MAXHANDLE 128
#endif
INT t;
DWORD res;
HANDLE hArray[MAXHANDLE];
INT i, count;
if (! __isArray(fdOrHandleArray)) {
goto fail;
}
count = __arraySize(fdOrHandleArray);
for (i=0; i<count; i++) {
OBJ fdOrHandle = __ArrayInstPtr(fdOrHandleArray)->a_element[i];
HANDLE h;
if (__isExternalAddressLike(fdOrHandle)) {
h = _HANDLEVal(fdOrHandle);
} else {
if (__isSmallInteger(fdOrHandle)) {
h = (HANDLE) _get_osfhandle (__intVal(fdOrHandle));
} else {
goto fail;
}
}
hArray[i] = h;
}
if (__isSmallInteger(millis)) {
t = __intVal(millis);
} else {
t = INFINITE;
}
#ifdef DO_WRAP_CALLS
do {
__threadErrno = 0;
res = STX_API_CALL4( "WaitForMultipleObjects", WaitForMultipleObjects, count, hArray, FALSE, t);
} while ((res < 0) && (__threadErrno == EINTR));
#else
res = WaitForMultipleObjects(count, hArray, FALSE, t);
if (res < 0) {
__threadErrno = __WIN32_ERR(GetLastError());
}
#endif
if (res == WAIT_FAILED) {
RETURN (nil);
}
if (res == WAIT_TIMEOUT) {
RETURN (nil);
}
if ((res >= WAIT_OBJECT_0) && (res < (WAIT_OBJECT_0+count))) {
RETURN (__ArrayInstPtr(fdOrHandleArray)->a_element[res-WAIT_OBJECT_0]);
}
RETURN (nil);
fail: ;
%}.
"
invalid arg,
"
^ self primitiveFailed
!
waitForSingleObject:fdOrHandle withTimeout:millis
"wait for an fd to become ready.
Timeout after t milliseconds or, if the timeout time is 0, immediately..
Zero time can be used to poll a file-
descriptors (i.e. to check if I/O possible without blocking).
Return the fd if I/O ok, nil if timed-out or interrupted."
%{
INT t;
DWORD res;
HANDLE h = NULL;
if (__isExternalAddressLike(fdOrHandle)) {
h = _HANDLEVal(fdOrHandle);
} else {
if (__isSmallInteger(fdOrHandle)) {
h = (HANDLE) _get_osfhandle (__intVal(fdOrHandle));
} else {
goto fail;
}
}
if (__isSmallInteger(millis)) {
t = __intVal(millis);
} else {
t = INFINITE;
}
#ifdef DO_WRAP_CALLS
do {
__threadErrno = 0;
res = STX_API_CALL2( "WaitForSingleObject", WaitForSingleObject, h, t);
} while ((res < 0) && (__threadErrno == EINTR));
#else
res = WaitForSingleObject(h, t);
if (res < 0) {
__threadErrno = __WIN32_ERR(GetLastError());
}
#endif
if (res == WAIT_FAILED) {
RETURN (nil);
}
if (res == WAIT_TIMEOUT) {
RETURN (nil);
}
RETURN (fdOrHandle);
fail: ;
%}.
"
invalid arg,
"
^ self primitiveFailed
! !
!Win32OperatingSystem::FileStatusInfo class methodsFor:'instance creation'!
type:t mode:m uid:u gid:g size:s id:i accessed:aT modified:mT created:cT path:lP alternativeName:name2
^ self basicNew
type:t mode:m uid:u gid:g size:s
id:i accessed:aT modified:mT created:cT
path:lP alternativeName:name2
!
type:t mode:m uid:u gid:g size:s id:i accessed:aT modified:mT created:cT path:lP fullName:fullName alternativeName:name2
^ self basicNew
type:t mode:m uid:u gid:g size:s
id:i accessed:aT modified:mT created:cT
path:lP
fullName:fullName
alternativeName:name2
! !
!Win32OperatingSystem::FileStatusInfo methodsFor:'accessing'!
accessTime
"return accessed"
^ accessed
"Created: / 1.2.2002 / 11:05:49 / cg"
!
alternativeName
"return the files other name (DOS name on windows).
Nil if there is no other name"
^ alternativeName
!
creationTime
^ created
!
fileSize
"return size"
^ size
"Created: / 1.2.2002 / 11:06:15 / cg"
!
fixedHeaderSize
"return the fixedHeaderSize (VMS only; nil everywhere else)"
^ nil
!
fullName
"return the files real name (non-DOS name on windows).
Nil if there is no other name"
^ fullName
!
gid
"return gid"
^ gid
!
id
"return id"
^ id
!
mode
"return mode"
^ mode
!
modificationTime
"return modified"
^ modified
"Created: / 1.2.2002 / 11:06:33 / cg"
!
numLinks
"DOS has no hardLinks - return 1"
^ 1
"Created: / 1.2.2002 / 11:07:04 / cg"
!
path
"for symbolic links only: return the path where the symbolic link points to"
^ path
!
recordAttributes
"return the recordAttributes (VMS only; nil everywhere else)"
^ nil
!
recordFormat
"return the recordFormat (VMS only; nil everywhere else)"
^ nil
!
recordFormatNumeric
"return the recordFormat as numeric (VMS only; nil everywhere else)"
^ nil
!
recordSize
"return the recordSize (VMS only; nil everywhere else)"
^ nil
!
size
"return size"
^ size
!
statusChangeTime
"return statusChanged"
^ statusChanged ? modified
"Created: / 1.2.2002 / 11:07:27 / cg"
!
type
"return type"
^ type
!
uid
"return uid"
^ uid
! !
!Win32OperatingSystem::FileStatusInfo methodsFor:'backward compatibility'!
accessed
"return accessed"
<resource: #obsolete>
self obsoleteMethodWarning:'use #accessTime'.
^ accessed
!
at:key
"backward compatibility access: in previous releases, IdentityDictionaries
were used to hold my information. Allow access via key messages.
This method will vanish - use the proper access protocol."
^ self perform:key
!
modified
<resource: #obsolete>
self obsoleteMethodWarning:'use #modificationTime'.
^ modified
!
statusChanged
<resource: #obsolete>
self obsoleteMethodWarning:'use #statusChangeTime'.
^ statusChanged
! !
!Win32OperatingSystem::FileStatusInfo methodsFor:'private accessing'!
type:t mode:m uid:u gid:g size:s id:i accessed:aT modified:mT created:cT path:lP alternativeName:name2
type := t.
mode := m.
uid := u.
gid := g.
size := s.
id := i.
accessed := aT.
modified := mT.
created := cT.
path := lP.
alternativeName := name2.
!
type:t mode:m uid:u gid:g size:s id:i accessed:aT modified:mT created:cT path:lP fullName:name1 alternativeName:name2
type := t.
mode := m.
uid := u.
gid := g.
size := s.
id := i.
accessed := aT.
modified := mT.
created := cT.
path := lP.
fullName := name1.
alternativeName := name2.
! !
!Win32OperatingSystem::FileStatusInfo methodsFor:'queries'!
isBlockSpecial
^ type == #characterSpecial
!
isCharacterSpecial
^ type == #characterSpecial
!
isDirectory
^ type == #directory
!
isFifo
^ type == #fifo
!
isRegular
^ type == #regular
!
isSocket
^ type == #socket
!
isSymbolicLink
^ type == #symbolicLink
!
isUnknown
^ type == #unknown
! !
!Win32OperatingSystem::OSProcessStatus class methodsFor:'documentation'!
documentation
"
This is an auxillary class, that holds information about status changes of
operating system processes (these are no smalltalk processes!!).
[Instance variables:]
pid <Integer> OS-Process identifier
status <Symbol> either #exit #signal #stop #continue
code <Integer> either exitcode or signalnumber
core <Boolean> true if core has been dumped
[author:]
Stefan Vogel
[see also:]
OperatingSystem
"
! !
!Win32OperatingSystem::OSProcessStatus class methodsFor:'instance creation'!
pid:pid status:status code:code core:core
"private interface for Win32OperatingSystem"
^ self new pid:pid status:status code:code core:core
"Created: 28.12.1995 / 14:16:14 / stefan"
"Modified: 30.4.1996 / 18:25:00 / cg"
!
processCreationFailure
"private interface for Win32OperatingSystem"
^ self new pid:-1 status:#failure code:-1 core:false
"Created: 28.12.1995 / 14:35:29 / stefan"
"Modified: 30.4.1996 / 18:25:05 / cg"
! !
!Win32OperatingSystem::OSProcessStatus methodsFor:'accessing'!
code
"return the exitcode / signalNumber"
^ code
"Created: 28.12.1995 / 14:05:07 / stefan"
"Modified: 30.4.1996 / 18:26:23 / cg"
!
core
"return true if core has been dumped, false otherwise"
^ core == true
"Modified: 28.12.1995 / 14:14:38 / stefan"
!
pid
"return the pid"
^ pid
"Created: 28.12.1995 / 14:05:07 / stefan"
"Modified: 30.4.1996 / 18:26:30 / cg"
!
status
"return status as a Symbol;
one of #exit #signal #stop #continue"
^ status
"Created: 28.12.1995 / 14:05:07 / stefan"
"Modified: 30.4.1996 / 18:26:54 / cg"
! !
!Win32OperatingSystem::OSProcessStatus methodsFor:'initialization'!
pid:newPid status:newStatus code:newCode core:newCore
pid := newPid.
status := newStatus.
code := newCode.
core := newCore.
"Created: 28.12.1995 / 14:18:22 / stefan"
! !
!Win32OperatingSystem::OSProcessStatus methodsFor:'private-OS interface'!
code:something
"set the exitCode"
code := something.
"Created: 28.12.1995 / 14:05:07 / stefan"
"Modified: 30.4.1996 / 18:25:18 / cg"
!
core:something
"set core"
core := something.
"Created: 28.12.1995 / 14:05:07 / stefan"
!
pid:something
"set pid"
pid := something.
"Created: 28.12.1995 / 14:05:07 / stefan"
!
status:something
"set status"
status := something.
"Created: 28.12.1995 / 14:05:07 / stefan"
! !
!Win32OperatingSystem::OSProcessStatus methodsFor:'queries'!
couldNotExecute
"return true when a command could not be executed"
^ status == #exit and:[code = 127].
"Created: 28.12.1995 / 15:43:17 / stefan"
"Modified: 30.4.1996 / 18:27:03 / cg"
!
stillAlive
"true if process is still alive"
^ status == #stop or:[status == #continue]
"Created: 28.12.1995 / 14:27:26 / stefan"
!
success
"true if process terminated successfully"
^ status == #exit and:[code = 0]
"Created: 28.12.1995 / 14:13:05 / stefan"
"Modified: 28.12.1995 / 14:13:41 / stefan"
! !
!Win32OperatingSystem::RegistryEntry class methodsFor:'defaults'!
rootKeyNames
^ #(
'HKEY_CLASSES_ROOT'
'HKEY_CURRENT_USER'
'HKEY_LOCAL_MACHINE'
'HKEY_USERS'
'HKEY_PERFORMANCE_DATA'
'HKEY_CURRENT_CONFIG'
'HKEY_DYN_DATA'
)
!
separator
^$\
! !
!Win32OperatingSystem::RegistryEntry class methodsFor:'documentation'!
documentation
"
Interface to a WIN32 registry.
[author:]
Claus Gittinger (initial version & cleanup)
"
!
examples
"
retrieve an existing entry by key:
[exBegin]
|k|
k := Win32OperatingSystem::RegistryEntry key:'HKEY_LOCAL_MACHINE\Software\eXept\Smalltalk/X'
[exEnd]
retrieve a non-existing entry by key:
[exBegin]
|k|
k := Win32OperatingSystem::RegistryEntry key:'HKEY_LOCAL_MACHINE\Software\xxx'
[exEnd]
ask a keys value:
[exBegin]
|k|
k := Win32OperatingSystem::RegistryEntry key:'HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion'.
Transcript show:'Windows serial NR:'; showCR:(k valueNamed:'ProductId').
k := Win32OperatingSystem::RegistryEntry key:'HKEY_LOCAL_MACHINE\Software\eXept\Smalltalk/X'.
Transcript showCR:(k valueNamed:'CurrentVersion').
[exEnd]
create a sub-key (if not already present):
[exBegin]
|k subKey|
k := Win32OperatingSystem::RegistryEntry key:'HKEY_LOCAL_MACHINE\Software\eXept\Smalltalk/X'.
subKey := k createSubKeyNamed:'RegistryDemo'
[exEnd]
change a keys value:
[exBegin]
|k|
k := Win32OperatingSystem::RegistryEntry key:'HKEY_LOCAL_MACHINE\Software\eXept\Smalltalk/X\RegistryDemo'.
k valueNamed:'FooBarBaz' put:'a foo bar baz string'.
[exEnd]
delete a value:
[exBegin]
|k|
k := Win32OperatingSystem::RegistryEntry key:'HKEY_LOCAL_MACHINE\Software\eXept\Smalltalk/X\RegistryDemo'.
k deleteValueNamed:'FooBarBaz'.
[exEnd]
delete a key:
[exBegin]
|k|
k := Win32OperatingSystem::RegistryEntry key:'HKEY_LOCAL_MACHINE\Software\eXept\Smalltalk/X'.
k deleteSubKeyNamed:'RegistryDemo'.
[exEnd]
enumerate keys:
[exBegin]
|k|
k := Win32OperatingSystem::RegistryEntry key:'HKEY_LOCAL_MACHINE\Software'.
k subKeysDo:[:subKey |
Transcript showCR:subKey path
]
[exEnd]
enumerate all keys (recursive):
[exBegin]
|k|
k := Win32OperatingSystem::RegistryEntry key:'HKEY_LOCAL_MACHINE\Software'.
k allSubKeysDo:[:subKey |
Transcript showCR:subKey path
]
[exEnd]
fetch value by index:
[exBegin]
|k|
k := self key:'HKEY_LOCAL_MACHINE\SOFTWARE\eXept\Smalltalk/X'.
Transcript showCR:(k valueNameAtIndex:0)
[exEnd]
enumerate value names:
[exBegin]
|k|
k := self key:'HKEY_LOCAL_MACHINE\SOFTWARE\eXept\Smalltalk/X'.
k valueNamesDo:[:nm |
Transcript showCR:nm.
]
[exEnd]
enumerate values:
[exBegin]
|k|
k := self key:'HKEY_LOCAL_MACHINE\SOFTWARE\eXept\Smalltalk/X'.
k valueNamesAndValuesDo:[:nm :val |
Transcript showCR:(nm , ' -> ' , val storeString).
]
[exEnd]
search for a value (where does NT store the domain ?):
[exBegin]
|k|
k := self key:'HKEY_LOCAL_MACHINE\System'.
k subKeysDo:[:subKey |
subKey subKeysDo:[:subSubKey |
|tcp params|
(subSubKey path asLowercase endsWith:'services') ifTrue:[
tcp := subSubKey subKeyNamed:'tcpip'.
tcp notNil ifTrue:[
params := tcp subKeyNamed:'parameters'.
params notNil ifTrue:[
Transcript showCR:'Domain is found in ' , params path ,
' value: ' , (params valueNamed:'Domain').
params close.
].
tcp close.
]
]
]
]
[exEnd]
"
! !
!Win32OperatingSystem::RegistryEntry class methodsFor:'initialization'!
initialize
Lobby := Registry new.
ObjectMemory addDependent:self.
HKEY_CLASSES_ROOT := %{ __MKEXTERNALADDRESS(HKEY_CLASSES_ROOT) %}.
HKEY_CURRENT_USER := %{ __MKEXTERNALADDRESS(HKEY_CURRENT_USER) %}.
HKEY_LOCAL_MACHINE := %{ __MKEXTERNALADDRESS(HKEY_LOCAL_MACHINE) %}.
HKEY_USERS := %{ __MKEXTERNALADDRESS(HKEY_USERS) %}.
HKEY_PERFORMANCE_DATA := %{ __MKEXTERNALADDRESS(HKEY_PERFORMANCE_DATA) %}.
HKEY_CURRENT_CONFIG := %{ __MKEXTERNALADDRESS(HKEY_CURRENT_CONFIG) %}.
HKEY_DYN_DATA := %{ __MKEXTERNALADDRESS(HKEY_DYN_DATA) %}.
"
self initialize
"
"Created: / 19.5.1999 / 21:39:57 / cg"
"Modified: / 19.5.1999 / 22:45:31 / cg"
!
rootKeyValueFor:specialKeyStringOrSymbol
HKEY_CLASSES_ROOT isNil ifTrue:[self initialize].
specialKeyStringOrSymbol = #'HKEY_CLASSES_ROOT' ifTrue:[
^ HKEY_CLASSES_ROOT.
].
specialKeyStringOrSymbol = #'HKEY_CURRENT_USER' ifTrue:[
^ HKEY_CURRENT_USER.
].
specialKeyStringOrSymbol = #'HKEY_LOCAL_MACHINE' ifTrue:[
^ HKEY_LOCAL_MACHINE.
].
specialKeyStringOrSymbol = #'HKEY_USERS' ifTrue:[
^ HKEY_USERS.
].
specialKeyStringOrSymbol = #'HKEY_PERFORMANCE_DATA' ifTrue:[
^ HKEY_PERFORMANCE_DATA.
].
specialKeyStringOrSymbol = #'HKEY_CURRENT_CONFIG' ifTrue:[
^ HKEY_CURRENT_CONFIG.
].
specialKeyStringOrSymbol = #'HKEY_DYN_DATA' ifTrue:[
^ HKEY_DYN_DATA.
].
^ nil
"Created: / 19.5.1999 / 21:40:30 / cg"
"Modified: / 24.12.1999 / 00:02:06 / cg"
!
update:something with:aParameter from:changedObject
"handle image restarts and refetch registry handles"
(something == #returnFromSnapshot) ifTrue:[
self initialize
]
"Created: 15.6.1996 / 15:14:03 / cg"
"Modified: 24.2.1997 / 22:08:05 / cg"
! !
!Win32OperatingSystem::RegistryEntry class methodsFor:'instance creation'!
key:aKeyNamePath
"retrieve an entry by full path name (starting at a root)"
|idx first rest root|
HKEY_CLASSES_ROOT isNil ifTrue:[self initialize].
idx := aKeyNamePath indexOf:(self separator).
idx == 0 ifTrue:[
first := aKeyNamePath.
rest := nil.
] ifFalse:[
first := aKeyNamePath copyTo:idx-1.
rest := aKeyNamePath copyFrom:idx+1
].
first := first asUppercase.
"/ the first is a pseudo name
root := self rootKey:first.
root isNil ifTrue:[
^ nil
].
rest size == 0 ifTrue:[
^ root
].
^ root subKeyNamed:rest.
"
self key:'HKEY_LOCAL_MACHINE'
self key:'HKEY_LOCAL_MACHINE\Software'
self key:'HKEY_LOCAL_MACHINE\Software\Borland\'
self key:'HKEY_LOCAL_MACHINE\Software\eXept\Smalltalk/X\3.2.5\Directory'
"
"Modified: / 24.12.1999 / 00:01:52 / cg"
!
rootKey:aRootKeyStringOrSymbol
"retrieve one of the root entries by name"
|keyVal|
keyVal := self rootKeyValueFor:aRootKeyStringOrSymbol.
keyVal isNil ifTrue:[^ nil].
"/ rootKeys are not registered for RegClose ...
^ self basicNew setHandle:keyVal path:aRootKeyStringOrSymbol.
"
RegistryEntry rootKey:#'HKEY_LOCAL_MACHINE'
"
! !
!Win32OperatingSystem::RegistryEntry class methodsFor:'registry access'!
stringValueFor:valueName atKey:keyPath
"convenient accessing method;
Looks for a string value under keyPath;
returns nil if either not found, or no string value"
|k v|
k := self key:keyPath.
k isNil ifTrue:[^ nil].
v := k valueNamed:valueName.
k close.
v isString ifFalse:[^ nil].
^ v
"
self
stringValueFor:'Content Type'
atKey:'HKEY_CLASSES_ROOT\.au'
"
! !
!Win32OperatingSystem::RegistryEntry methodsFor:'accessing'!
name
"return the keys name component (subKey name within my
parent key)"
|idx|
idx := path lastIndexOf:(self class separator).
idx == 0 ifTrue:[^ path].
^ path copyFrom:idx+1
!
path
"return the keys full key path name"
^ path.
! !
!Win32OperatingSystem::RegistryEntry methodsFor:'accessing subkeys'!
createSubKeyNamed:subKeyString
"create a new key below mySelf and return a new registry entry for it.
If it already exists, return it.
Return nil if the new key cannot be created."
|newEntry subHandle|
%{
HKEY myKey, subKey = 0;
if (__isExternalAddressLike(__INST(handle))
&& (__isString(subKeyString) || __isSymbol(subKeyString))) {
myKey = (HKEY)__externalAddressVal(__INST(handle));
if (RegCreateKey(myKey, __stringVal(subKeyString), &subKey) == ERROR_SUCCESS) {
subHandle = __MKEXTERNALADDRESS(subKey);
}
}
%}.
subHandle notNil ifTrue:[
newEntry := self class basicNew
setHandle:subHandle
path:(path , self class separator asString , subKeyString).
Lobby register:newEntry.
^ newEntry.
].
^ nil
"
|top sub|
top := self key:'HKEY_LOCAL_MACHINE'.
sub := top createSubKeyNamed:'FooBarBaz'.
"
!
deleteSubKeyNamed:subKeyString
"delete a key below mySelf.
Return true on success."
%{
HKEY myKey;
if (__isExternalAddressLike(__INST(handle))
&& (__isString(subKeyString) || __isSymbol(subKeyString))) {
myKey = (HKEY)__externalAddressVal(__INST(handle));
if (RegDeleteKey(myKey, __stringVal(subKeyString)) == ERROR_SUCCESS) {
RETURN (true);
}
}
%}.
^ false
"
|top sub|
top := self key:'HKEY_LOCAL_MACHINE'.
sub := top createSubKeyNamed:'FooBarBaz'.
top deleteSubKeyNamed:'FooBarBaz'.
"
!
remoteKeyOnHost:hostName
"return the corresponding registry entry from
a remote computers registry."
|newEntry remoteHandle|
%{
HKEY myKey, remoteKey = 0;
if (__isExternalAddressLike(__INST(handle)) && __isString(hostName)) {
myKey = (HKEY)__externalAddressVal(__INST(handle));
if (RegConnectRegistry(__stringVal(hostName), myKey, &remoteKey) == ERROR_SUCCESS) {
remoteHandle = __MKEXTERNALADDRESS(remoteKey);
}
}
%}.
remoteHandle notNil ifTrue:[
newEntry := self class basicNew setHandle:remoteHandle path:path.
Lobby register:newEntry.
^ newEntry.
].
^ nil
"
|top remote|
top := self key:'HKEY_LOCAL_MACHINE'.
remote := top remoteKeyOnHost:'BETTI'
"
"
|top remote|
top := self key:'HKEY_USERS'.
remote := top remoteKeyOnHost:'BETTI'
"
"
|top remote|
top := self key:'HKEY_LOCAL_MACHINE'.
remote := top remoteKeyOnHost:'JOSHUA'
"
"
|top remote|
top := self key:'HKEY_USERS'.
remote := top remoteKeyOnHost:'JOSHUA'
"
!
subKeyAtIndex:subKeyIndex
"return a new registry entry below mySelf for the given subKey index.
Return nil if no such key exists"
|subKeyName subKeyClassName|
%{
HKEY myKey, subKey = 0;
char nameBuffer[256];
DWORD nameSize = sizeof(nameBuffer) - 1;
char classNameBuffer[256];
DWORD classNameSize = sizeof(classNameBuffer) - 1;
FILETIME modificationTime;
if (__isExternalAddressLike(__INST(handle))
&& __isSmallInteger(subKeyIndex)) {
myKey = (HKEY)__externalAddressVal(__INST(handle));
if (RegEnumKeyEx(myKey, __intVal(subKeyIndex),
nameBuffer, &nameSize,
NULL,
classNameBuffer, &classNameSize,
&modificationTime) == ERROR_SUCCESS) {
nameBuffer[nameSize] = '\0';
classNameBuffer[classNameSize] = '\0';
subKeyName = __MKSTRING(nameBuffer);
subKeyClassName = __MKSTRING(classNameBuffer);
} else {
}
}
%}.
subKeyName isNil ifTrue:[^ nil].
^ self subKeyNamed:subKeyName.
"
|top sub|
top := self key:'HKEY_LOCAL_MACHINE'.
sub := top subKeyAtIndex:0
"
!
subKeyNamed:subKeyString
"return a new registry entry below mySelf with the given subKey.
Return nil if no such key exists"
|newEntry subHandle|
%{
HKEY myKey, subKey = 0;
if (__isExternalAddressLike(__INST(handle))
&& (__isString(subKeyString) || __isSymbol(subKeyString))) {
myKey = (HKEY)__externalAddressVal(__INST(handle));
if (RegOpenKey(myKey, __stringVal(subKeyString), &subKey) == ERROR_SUCCESS) {
subHandle = __MKEXTERNALADDRESS(subKey);
}
}
%}.
subHandle notNil ifTrue:[
newEntry := self class basicNew
setHandle:subHandle
path:(path , self class separator asString , subKeyString).
Lobby register:newEntry.
^ newEntry.
].
^ nil
"
|top sub|
top := self key:'HKEY_LOCAL_MACHINE'.
sub := top subKeyNamed:'Software'
"
! !
!Win32OperatingSystem::RegistryEntry methodsFor:'accessing values'!
deleteValueNamed:aValueName
"delete a value.
Return true on success."
%{
HKEY myKey;
if (__isExternalAddressLike(__INST(handle))
&& (__isString(aValueName) || __isSymbol(aValueName))) {
myKey = (HKEY)__externalAddressVal(__INST(handle));
if (RegDeleteValue(myKey, __stringVal(aValueName)) == ERROR_SUCCESS) {
RETURN (true);
}
}
%}.
^ false
!
valueNameAtIndex:valueIndex
"return a values name for the given value index.
Return nil if no such value exists"
|valueName|
%{
HKEY myKey;
char nameBuffer[256];
DWORD nameSize = sizeof(nameBuffer) - 1;
DWORD valueType;
if (__isExternalAddressLike(__INST(handle))
&& __isSmallInteger(valueIndex)) {
myKey = (HKEY)__externalAddressVal(__INST(handle));
if (RegEnumValue(myKey, __intVal(valueIndex),
nameBuffer, &nameSize,
NULL,
&valueType,
NULL, NULL) == ERROR_SUCCESS) {
nameBuffer[nameSize] = '\0';
valueName = __MKSTRING(nameBuffer);
}
}
%}.
^ valueName
"
|top sub|
top := self key:'HKEY_LOCAL_MACHINE'.
sub := top subKeyAtIndex:0
"
!
valueNamed:aValueName
"retrieve a value; the returned object depends upon the type:
REG_BINARY -> ByteArray
REG_SZ -> String
REG_MULTI_SZ -> Array of strings
REG_DWORD -> Integer
REG_NONE -> nil
"
|data stringArray|
%{
HKEY myKey;
DWORD valueType;
union {
DWORD dWord;
unsigned char dWordBytes[4];
unsigned char smallDataBuffer[256];
} quickData;
int val;
DWORD dataSize = sizeof(quickData);
unsigned char *dataBuffer = NULL;
if (__isExternalAddressLike(__INST(handle))
&& (__isString(aValueName) || __isSymbol(aValueName))) {
int ret;
myKey = (HKEY)__externalAddressVal(__INST(handle));
/*
* try to get it with one call ...
*/
ret = RegQueryValueEx(myKey, __stringVal(aValueName),
NULL,
&valueType,
&quickData, &dataSize);
if (ret == ERROR_MORE_DATA) {
/*
* nope - need another one ...
*/
switch (valueType) {
case REG_BINARY:
case REG_MULTI_SZ:
data = __BYTEARRAY_UNINITIALIZED_NEW_INT(dataSize);
dataBuffer = __ByteArrayInstPtr(data)->ba_element;
break;
case REG_SZ:
data = __MKEMPTYSTRING(dataSize-1);
dataBuffer = __stringVal(data);
break;
}
if (dataBuffer) {
ret = RegQueryValueEx(myKey, __stringVal(aValueName),
NULL,
&valueType,
dataBuffer, &dataSize);
}
}
if (ret == ERROR_SUCCESS) {
switch (valueType) {
case REG_NONE:
/* RETURN (@symbol(none)); */
RETURN (nil);
case REG_BINARY:
/*
* did we get it with the first call ?
*/
if (! dataBuffer) {
data = __MKBYTEARRAY(quickData.smallDataBuffer, dataSize);
}
RETURN (data);
case REG_SZ:
case REG_EXPAND_SZ:
/*
* did we get it with the first call ?
*/
if (! dataBuffer) {
data = __MKSTRING_L(quickData.smallDataBuffer, dataSize-1);
}
RETURN (data);
#if 0
case REG_DWORD:
/* int in native format */
RETURN (__MKUINT(quickData.dWord));
#endif
case REG_DWORD_LITTLE_ENDIAN:
val = quickData.dWordBytes[3];
val = (val << 8) | quickData.dWordBytes[2];
val = (val << 8) | quickData.dWordBytes[1];
val = (val << 8) | quickData.dWordBytes[0];
RETURN (__MKUINT(val));
case REG_DWORD_BIG_ENDIAN:
val = quickData.dWordBytes[0];
val = (val << 8) | quickData.dWordBytes[1];
val = (val << 8) | quickData.dWordBytes[2];
val = (val << 8) | quickData.dWordBytes[3];
RETURN (__MKUINT(val));
case REG_MULTI_SZ:
{
char *cp, *cp0;
int ns = 0, i;
cp0 = dataBuffer ? dataBuffer : quickData.smallDataBuffer;
cp = cp0;
while (*cp) {
while (*cp++) ;;
ns++;
cp++;
}
stringArray = __ARRAY_NEW_INT(ns);
i = 0;
while (*cp0) {
OBJ s;
cp = cp0;
while (*cp++) ;;
s = __MKSTRING(cp0);
__ArrayInstPtr(stringArray)->a_element[i] = s;
__STORE(stringArray, s);
cp++;
cp0 = cp;
i++;
}
RETURN (stringArray);
}
}
}
}
%}.
^ nil
"
|key|
key := self key:'HKEY_LOCAL_MACHINE\SOFTWARE\eXept\Smalltalk/X'.
key valueNamed:'CurrentVersion'
"
!
valueNamed:aValueName put:datum
"store a value; the value type depends upon the stored value:
ByteArray -> REG_BINARY
String -> REG_SZ
Array of string -> REG_MULTI_SZ
Integer -> REG_DWORD
nil -> REG_NONE
"
|data stringArray|
%{
HKEY myKey;
DWORD valueType = -1;
int val;
DWORD dataSize = -1;
unsigned char *dataPointer = NULL;
int datumOk = 1, mustFreeData = 0;
if (__isExternalAddressLike(__INST(handle))
&& (__isString(aValueName) || __isSymbol(aValueName))) {
int ret;
OBJ cls;
myKey = (HKEY)__externalAddressVal(__INST(handle));
if (datum == nil) {
valueType = REG_NONE;
dataSize = 0;
} else if (__isSmallInteger(datum)) {
valueType = REG_DWORD;
val = __intVal(datum);
dataPointer = (unsigned char *)(&val);
dataSize = sizeof(val);
} else if (__isString(datum) || __isSymbol(datum)) {
valueType = REG_SZ;
dataPointer = __stringVal(datum);
dataSize = __stringSize(datum) + 1;
} else if (__Class(datum) == ByteArray) {
valueType = REG_BINARY;
dataPointer = __ByteArrayInstPtr(datum)->ba_element;
dataSize = __byteArraySize(datum);
} else if (__Class(datum) == LargeInteger) {
valueType = REG_DWORD;
val = __longIntVal(datum);
if (val) {
dataPointer = (unsigned char *)(&val);
dataSize = sizeof(val);
} else {
datumOk = 0;
}
} else if (__Class(datum) == Array) {
int i = 0, ns = 0, totalSize = 0;
valueType = REG_MULTI_SZ;
/*
* must allocate a local buffer
* find size ...
*/
for (i=0; i<__arraySize(datum); i++) {
OBJ s = __ArrayInstPtr(datum)->a_element[i];
if (__isString(datum) || __isSymbol(datum)) {
totalSize += __stringSize(datum) + 1;
} else {
datumOk = 0;
break;
}
ns++;
}
if (datumOk) {
char *cp;
/*
* allocate and fill...
*/
totalSize ++;
dataPointer = (char *)(malloc(totalSize));
mustFreeData = 1;
cp = dataPointer;
for (i=0; i<__arraySize(datum); i++) {
OBJ s = __ArrayInstPtr(datum)->a_element[i];
strcpy(cp, __stringVal(s));
cp += __stringSize(datum);
*cp++ = '\0';
}
*cp++ = '\0';
dataSize = totalSize;
}
} else {
datumOk = 0;
}
if (datumOk) {
ret = RegSetValueEx(myKey, __stringVal(aValueName),
0, valueType,
dataPointer, dataSize);
if (mustFreeData) {
free(dataPointer);
}
RETURN ((ret == ERROR_SUCCESS) ? true : false);
}
}
%}.
^ false
"
|key|
key := self key:'HKEY_LOCAL_MACHINE\SOFTWARE\eXept\Smalltalk/X'.
key valueNamed:'CurrentVersion' put:'3.5.2'
"
! !
!Win32OperatingSystem::RegistryEntry methodsFor:'enumeration'!
allSubKeysDo:aBlock
"recursively evaluate aBlock for all subKeys below the receiver"
|idx subEntry|
idx := 0.
[true] whileTrue:[
subEntry := self subKeyAtIndex:idx.
subEntry isNil ifTrue:[
^self
].
aBlock value:subEntry.
subEntry allSubKeysDo:aBlock.
subEntry close.
idx := idx + 1.
]
"
|top sub|
top := self key:'HKEY_LOCAL_MACHINE'.
top allSubKeysDo:[:subEntry |
Transcript showCR:subEntry path
]
"
!
subKeys
"return a collection of subKeys below the receiver"
|idx subEntry subKeys|
subKeys := OrderedCollection new.
self subKeysDo:[:k | subKeys add:k].
^ subKeys
"
|top sub|
top := self key:'HKEY_LOCAL_MACHINE'.
top subKeys
"
"Created: / 23.12.1999 / 22:15:22 / cg"
"Modified: / 23.12.1999 / 22:15:44 / cg"
!
subKeysDo:aBlock
"evaluate aBlock for all subKeys below the receiver"
|idx subEntry|
idx := 0.
[true] whileTrue:[
subEntry := self subKeyAtIndex:idx.
subEntry isNil ifTrue:[
^self
].
aBlock value:subEntry.
subEntry close.
idx := idx + 1.
]
"
|top sub|
top := self key:'HKEY_LOCAL_MACHINE'.
top subKeysDo:[:subEntry |
Transcript showCR:subEntry path
]
"
!
valueNamesAndValuesDo:aBlock
"evaluate aBlock for all value names"
self valueNamesDo:[:nm |
aBlock value:nm value:(self valueNamed:nm)
]
"
|key|
key := self key:'HKEY_LOCAL_MACHINE\SOFTWARE\eXept\Smalltalk/X'.
key valueNamesAndValuesDo:[:nm :val |
Transcript showCR:(nm , ' -> ' , val storeString).
]
"
!
valueNamesDo:aBlock
"evaluate aBlock for all value names"
|idx valueName|
idx := 0.
[true] whileTrue:[
valueName := self valueNameAtIndex:idx.
valueName isNil ifTrue:[
^self
].
aBlock value:valueName.
idx := idx + 1.
]
! !
!Win32OperatingSystem::RegistryEntry methodsFor:'instance release'!
close
"close mySelf"
self closeKey.
Lobby unregister:self.
"Modified: / 19.5.1999 / 22:44:44 / cg"
!
closeKey
"close mySelf"
%{
HKEY myKey;
if (__isExternalAddressLike(__INST(handle))) {
myKey = (HKEY)(__externalAddressVal(__INST(handle)));
__INST(handle) = nil;
RegCloseKey(myKey);
}
%}
!
disposed
"some entry has been collected - close it"
handle notNil ifTrue:[
self closeKey.
]
"Created: / 19.5.1999 / 22:39:52 / cg"
"Modified: / 19.5.1999 / 22:44:50 / cg"
! !
!Win32OperatingSystem::RegistryEntry methodsFor:'private'!
setHandle:aHandle path:aPathString
handle := aHandle.
path := aPathString.
"Created: / 19.5.1999 / 22:27:05 / cg"
!
setupForHandleValue:integerHandleValue
"not normally used - given an integer address,
return a registry entry. This is provided to
allow for future root keys to be added at the smalltalk level"
%{
HKEY key;
OBJ t;
key = __longIntVal(integerHandleValue);
if (! key) {
RETURN (nil);
}
__INST(handle) = t = __MKEXTERNALADDRESS(key); __STORE(self, t);
%}.
"Created: / 19.5.1999 / 21:45:05 / cg"
! !
!Win32OperatingSystem::Win32FILEHandle class methodsFor:'documentation'!
documentation
"
I represent a FILE*, as used in the stdio library.
Since most stdio libs are inherently buggy, thread-unsave
and hard to use in a multithreading environment,
these will no longer be used in future ST/X versions.
However, they may be useful when interfacing to external
libraries...
"
!
version
^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.179 2005-04-14 13:07:11 cg Exp $'
! !
!Win32OperatingSystem::Win32FILEHandle methodsFor:'release'!
closeFile
"close the file"
%{
FILE *f = (FILE *)(__externalAddressVal(self));
if (f) {
__externalAddressVal(self) = NULL;
fclose(f);
}
%}.
! !
!Win32OperatingSystem::Win32Handle class methodsFor:'documentation'!
documentation
"
I represent a generic HANDLE, which can be closed via CloseHandle.
"
!
version
^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.179 2005-04-14 13:07:11 cg Exp $'
! !
!Win32OperatingSystem::Win32Handle methodsFor:'io'!
readBytes:count into:aByteBuffer startingAt:firstIndex
"read count bytes into a byte-buffer;
Return the number of bytes read (negative on error)"
|errSym errorNumber|
%{
unsigned char *extPtr;
int bufferIsExternalBytes;
int mustFreeBuffer = 0;
int nRead = -1;
HANDLE hFile = (HANDLE)(__externalAddressVal(self));
DWORD cntWanted, offs, cntRead;
int bufferSize;
char miniBuffer[32];
BOOL ok;
if ((hFile == 0) || (hFile == INVALID_HANDLE_VALUE)) {
errSym = @symbol(errorNotOpen);
goto bad;
}
if (! __bothSmallInteger(count, firstIndex)) {
errSym = @symbol(badArgument);
goto bad;
}
cntWanted = __smallIntegerVal(count);
if (cntWanted <= 0) {
errSym = @symbol(badCount);
goto bad;
}
offs = __smallIntegerVal(firstIndex) - 1;
if (offs < 0) {
errSym = @symbol(badOffset);
goto bad;
}
bufferIsExternalBytes = __isExternalBytesLike(aByteBuffer);
if (! bufferIsExternalBytes) {
if (__isByteArray(aByteBuffer)) {
bufferSize = __byteArraySize(aByteBuffer);
} else if (__isString(aByteBuffer)) {
bufferSize = __stringSize(aByteBuffer);
} else {
errSym = @symbol(badBuffer);
goto bad;
}
if (bufferSize < (cntWanted + offs)) {
errSym = @symbol(badBufferSize);
goto bad;
}
if (cntWanted <= sizeof(miniBuffer)) {
extPtr = miniBuffer;
} else {
extPtr = malloc(cntWanted);
mustFreeBuffer = 1;
}
} else {
OBJ sz;
extPtr = (char *)(__externalBytesAddress(aByteBuffer));
sz = __externalBytesSize(aByteBuffer);
if (! __isSmallInteger(sz)) {
errSym = @symbol(badBufferSize);
goto bad;
}
bufferSize = __smallIntegerVal(sz);
if (bufferSize < (cntWanted + offs)) {
errSym = @symbol(badBufferSize);
goto bad;
}
extPtr = extPtr + offs;
}
do {
__threadErrno = 0;
ok = STX_API_CALL5( "ReadFile", ReadFile, hFile, extPtr, cntWanted, &cntRead, 0 /* lpOverlapped */);
} while(__threadErrno == EINTR);
if (ok == TRUE) {
if (! bufferIsExternalBytes) {
/* copy over */
memcpy(__byteArrayVal(aByteBuffer)+offs, extPtr, cntRead);
if (mustFreeBuffer) {
free(extPtr);
}
}
RETURN (__mkSmallInteger(cntRead));
}
errorNumber = __mkSmallInteger( __WIN32_ERR(GetLastError()) );
bad: ;
if (mustFreeBuffer) {
free(extPtr);
}
%}.
errorNumber isNil ifTrue:[
self error:'invalid argument(s): ', errSym.
] ifFalse:[
(OperatingSystem errorHolderForNumber:errorNumber) reportError
].
"
|h buff n|
h := self basicNew.
buff := ByteArray new:10.
n := h readBytes:10 into:buff startingAt:1.
Transcript show:n; space; showCR:buff.
"
!
readWaitWithTimeoutMs:millis
"return true if a timeout occurred"
|errSym errorNumber|
%{
HANDLE hFile = (HANDLE)(__externalAddressVal(self));
DWORD res;
INT t;
if ((hFile == 0) || (hFile == INVALID_HANDLE_VALUE)) {
errSym = @symbol(errorNotOpen);
goto bad;
}
#if 0
if (ioctlsocket((SOCKET)hFile, FIONREAD, &res)==0) {
/* its a socket */
if (res > 0) {
RETURN ( false );
}
}
if (PeekNamedPipe(hFile, 0, 0, 0, &res, 0)) {
/* its a namedPipe */
if (res > 0) {
RETURN ( false );
}
}
#endif
if (__isSmallInteger(millis)) {
t = __intVal(millis);
} else {
t = INFINITE;
}
do {
__threadErrno = 0;
res = WaitForSingleObject(hFile, t);
} while (__threadErrno == EINTR);
switch (res) {
case WAIT_OBJECT_0:
/* signalled */
RETURN ( false );
case WAIT_TIMEOUT:
/* signalled */
RETURN ( true );
default:
case WAIT_ABANDONED:
errorNumber = __mkSmallInteger( __WIN32_ERR(GetLastError()) );
goto bad;
}
bad: ;
%}.
"
timeout argument not integer,
or any fd-array nonNil and not an array
or not supported by OS
"
^ self primitiveFailed
!
seekTo:newPosition from:whence
"whence is one of:
#begin
#current
#end
"
|errSym errorNumber|
%{
HANDLE hFile = (HANDLE)(__externalAddressVal(self));
DWORD moveHow;
LONG posLo, posHi = 0;
__uint64__ pos64, newPos64;
if ((hFile == 0) || (hFile == INVALID_HANDLE_VALUE)) {
errSym = @symbol(errorNotOpen);
goto bad;
}
if (whence == @symbol(begin)) {
moveHow = FILE_BEGIN;
} else if (whence == @symbol(current)) {
moveHow = FILE_CURRENT;
} else if (whence == @symbol(end)) {
moveHow = FILE_END;
} else {
errSym = @symbol(badArgument2);
goto bad;
}
if (__signedLong64IntVal(newPosition, &pos64) == 0) {
errSym = @symbol(badArgument);
goto bad;
}
posLo = pos64.lo;
posHi = pos64.hi;
posLo = SetFilePointer(hFile, posLo, &posHi, moveHow);
if (posLo == 0xFFFFFFFF) {
int lastError;
/* can be either an error, or a valid low-word */
lastError = GetLastError();
if (lastError != NO_ERROR) {
errorNumber = __mkSmallInteger( __WIN32_ERR(lastError) );
goto bad;
}
}
if (posHi == 0) {
RETURN (__MKUINT( posLo ));
}
newPos64.lo = posLo;
newPos64.hi = posHi;
RETURN ( __MKUINT64(&newPos64) );
bad: ;
%}.
errorNumber isNil ifTrue:[
self error:'invalid argument(s): ', errSym.
] ifFalse:[
(OperatingSystem errorHolderForNumber:errorNumber) reportError
].
!
writeBytes:count from:aByteBuffer startingAt:firstIndex
"write count bytes from a byte-buffer;
Return the number of bytes written (negative on error)"
|errSym errorNumber|
%{
unsigned char *extPtr;
int bufferIsExternalBytes;
int mustFreeBuffer = 0;
int nWritten = -1;
HANDLE hFile = (HANDLE)(__externalAddressVal(self));
DWORD cntWanted, offs, cntWritten;
int bufferSize;
char miniBuffer[32];
BOOL ok;
if ((hFile == 0) || (hFile == INVALID_HANDLE_VALUE)) {
errSym = @symbol(errorNotOpen);
goto bad;
}
if (! __bothSmallInteger(count, firstIndex)) {
errSym = @symbol(badArgument);
goto bad;
}
cntWanted = __smallIntegerVal(count);
if (cntWanted <= 0) {
errSym = @symbol(badCount);
goto bad;
}
offs = __smallIntegerVal(firstIndex) - 1;
if (offs < 0) {
errSym = @symbol(badOffset);
goto bad;
}
bufferIsExternalBytes = __isExternalBytesLike(aByteBuffer);
if (! bufferIsExternalBytes) {
if (__isByteArray(aByteBuffer)) {
bufferSize = __byteArraySize(aByteBuffer);
} else if (__isString(aByteBuffer)) {
bufferSize = __stringSize(aByteBuffer);
} else {
errSym = @symbol(badBuffer);
goto bad;
}
if (bufferSize < (cntWanted + offs)) {
errSym = @symbol(badBufferSize);
goto bad;
}
if (cntWanted <= sizeof(miniBuffer)) {
extPtr = miniBuffer;
} else {
extPtr = malloc(cntWanted);
mustFreeBuffer = 1;
}
memcpy(extPtr, __byteArrayVal(aByteBuffer)+offs, cntWanted);
} else {
extPtr = (char *)(__externalBytesAddress(aByteBuffer));
bufferSize = __externalBytesSize(aByteBuffer);
if (! __isSmallInteger(bufferSize)) {
errSym = @symbol(badBufferSize);
goto bad;
}
bufferSize = __smallIntegerVal(bufferSize);
if (bufferSize < (cntWanted + offs)) {
errSym = @symbol(badBufferSize);
goto bad;
}
extPtr = extPtr + offs;
}
do {
__threadErrno = 0;
ok = STX_API_CALL5( "WriteFile", WriteFile, hFile, extPtr, cntWanted, &cntWritten, 0 /* lpOverlapped */);
} while(__threadErrno == EINTR);
if (ok == TRUE) {
if (mustFreeBuffer) {
free(extPtr);
}
RETURN (__mkSmallInteger(cntWritten));
}
errorNumber = __mkSmallInteger( __WIN32_ERR(GetLastError()) );
bad: ;
if (mustFreeBuffer) {
free(extPtr);
}
%}.
errorNumber isNil ifTrue:[
self error:'invalid argument(s): ', errSym.
] ifFalse:[
(OperatingSystem errorHolderForNumber:errorNumber) reportError
].
"
|h buff n|
h := self basicNew.
h setFileDescriptor:1.
buff := '12345678901234567890'.
n := h writeBytes:10 from:buff startingAt:1.
"
! !
!Win32OperatingSystem::Win32Handle methodsFor:'queries'!
isValid
^ self address ~~0
! !
!Win32OperatingSystem::Win32Handle methodsFor:'release'!
closeFile
"close the handle"
%{
HANDLE h = (HANDLE)(__externalAddressVal(self));
if (h) {
__externalAddressVal(self) = (HANDLE)0;
CloseHandle(h);
}
%}.
! !
!Win32OperatingSystem::Win32ProcessHandle methodsFor:'accessing'!
pid
^ pid
! !
!Win32OperatingSystem::Win32SocketHandle class methodsFor:'constants'!
protocolCodeOf:aNameOrNumber
"q&d hack for unix-compatibility"
aNameOrNumber isNumber ifTrue:[^ aNameOrNumber].
aNameOrNumber isNil ifTrue:[^ aNameOrNumber].
aNameOrNumber = 'tcp' ifTrue:[^ 6].
aNameOrNumber = 'udp' ifTrue:[^ 17].
aNameOrNumber = 'raw' ifTrue:[^ 255].
self error:'unsupported protocol' mayProceed:true.
^ nil.
"
self protocolCodeOf:#tcp
"
!
protocolSymbolOf:anInteger
"q&d hack for unix-compatibility"
anInteger isNil ifTrue:[^ nil].
anInteger isSymbol ifTrue:[^ anInteger].
anInteger == 6 ifTrue:[ ^ #tcp ].
anInteger == 17 ifTrue:[ ^ #udp ].
anInteger == 255 ifTrue:[ ^ #raw ].
self error:'unsupported protocol' mayProceed:true.
^ nil.
"
self protocolSymbolOf:6
"
! !
!Win32OperatingSystem::Win32SocketHandle class methodsFor:'queries'!
getAddressInfo:hostName serviceName:serviceName domain:domainArg type:typeArg protocol:protoArg flags:flags
"answer an Array of socket addresses for serviceName on hostName
Domain, type, protocol may be nil or specify a hint for the socket
addresses to be returned."
|error errorString result domain type proto|
domain := OperatingSystem domainCodeOf:domainArg.
type := OperatingSystem socketTypeCodeOf:typeArg.
proto := self protocolCodeOf:protoArg.
%{ /* STACK:32000 */
#if !defined(NO_SOCKET)
char *__hostName, *__serviceName;
int ret, cnt = 0;
if (hostName == nil) {
__hostName = 0;
} else if (__isString(hostName) || __isSymbol(hostName)) {
__hostName = __stringVal(hostName);
} else {
error = @symbol(badArgument1);
goto err;
}
if (serviceName == nil) {
__serviceName = 0;
} else if (__isString(serviceName) || __isSymbol(serviceName)) {
__serviceName = __stringVal(serviceName);
} else {
error = @symbol(badArgument2);
goto err;
}
if (__hostName == 0 && __serviceName == 0) {
error = @symbol(badArgument);
goto err;
}
{
# if defined(AI_NUMERICHOST)
/*
* Use getaddrinfo()
*/
struct addrinfo hints;
struct addrinfo *info = NULL, *infop;
memset(&hints, 0, sizeof(hints));
if (__isSmallInteger(domain))
hints.ai_family = __intVal(domain);
if (__isSmallInteger(type))
hints.ai_socktype = __intVal(type);
if (__isSmallInteger(proto))
hints.ai_protocol = __intVal(proto);
do {
/* must refetch in loop */
if (hostName == nil) {
__hostName = 0;
} else if (__isString(hostName) || __isSymbol(hostName)) {
__hostName = __stringVal(hostName);
}
if (serviceName == nil) {
__serviceName = 0;
} else if (__isString(serviceName) || __isSymbol(serviceName)) {
__serviceName = __stringVal(serviceName);
}
# ifdef DO_WRAP_CALLS
do {
__threadErrno = 0;
res = STX_WSA_CALL4( "getaddrinfo", getaddrinfo, __hostName, __serviceName, &hints, &info);
} while ((res < 0) && (__threadErrno == EINTR));
# else
__BEGIN_INTERRUPTABLE__
ret = getaddrinfo(__hostName, __serviceName, &hints, &info);
__END_INTERRUPTABLE__
# endif
} while (ret == EAI_SYSTEM && errno == EINTR);
if (ret != 0) {
switch (ret) {
case EAI_FAMILY:
error = @symbol(badProtocol);
break;
case EAI_SOCKTYPE:
error = @symbol(badSocketType);
break;
case EAI_BADFLAGS:
error = @symbol(badFlags);
break;
case EAI_NONAME:
error = @symbol(unknownHost);
break;
case EAI_SERVICE:
error = @symbol(unknownService);
break;
case EAI_ADDRFAMILY :
error = @symbol(unknownHostForProtocol);
break;
case EAI_NODATA:
error = @symbol(noAddress);
break;
case EAI_MEMORY:
error = @symbol(allocationFailure);
break;
case EAI_FAIL:
error = @symbol(permanentFailure);
break;
case EAI_AGAIN:
error = @symbol(tryAgain);
break;
case EAI_SYSTEM:
error = @symbol(systemError);
break;
default:
error = @symbol(unknownError);
}
errorString = __MKSTRING(gai_strerror(ret));
goto err;
}
for (cnt=0, infop=info; infop; infop=infop->ai_next)
cnt++;
result = __ARRAY_NEW_INT(cnt);
if (result == nil) {
error = @symbol(allocationFailure);
goto err;
}
for (infop=info, cnt=0; infop; infop=infop->ai_next, cnt++) {
OBJ o, resp;
resp = __ARRAY_NEW_INT(6);
if (resp == nil) {
error = @symbol(allocationFailure);
goto err;
}
__ArrayInstPtr(result)->a_element[cnt] = resp; __STORE(result, resp);
__ArrayInstPtr(resp)->a_element[0] = __MKSMALLINT(infop->ai_flags);
__ArrayInstPtr(resp)->a_element[1] = __MKSMALLINT(infop->ai_family);
__ArrayInstPtr(resp)->a_element[2] = __MKSMALLINT(infop->ai_socktype);
__ArrayInstPtr(resp)->a_element[3] = __MKSMALLINT(infop->ai_protocol);
__PROTECT__(resp);
o = __BYTEARRAY_NEW_INT(infop->ai_addrlen);
__UNPROTECT__(resp);
if (o == nil) {
error = @symbol(allocationFailure);
goto err;
}
memcpy(__byteArrayVal(o), infop->ai_addr, infop->ai_addrlen);
__ArrayInstPtr(resp)->a_element[4] = o; __STORE(resp, o);
if (infop->ai_canonname) {
__PROTECT__(resp);
o = __MKSTRING(infop->ai_canonname);
__UNPROTECT__(resp);
if (o == nil) {
error = @symbol(allocationFailure);
goto err;
}
__ArrayInstPtr(resp)->a_element[5] = o; __STORE(resp, o);
}
}
err:
if (info) freeaddrinfo(info);
# else /* ! AI_NUMERICHOST =============================================================*/
/*
* Use getservbyname() / gethostByName()
*/
struct hostent *hp;
char **addrpp;
int port = 0;
int i;
if (__serviceName) {
struct servent *sp;
char *__proto = 0;
if (__isString(protoArg) || __isSymbol(protoArg))
__proto = __stringVal(protoArg);
sp = getservbyname(__serviceName, __proto);
if (sp == NULL) {
errorString = @symbol(unknownService);
error = __mkSmallInteger(-3);
goto err;
}
port = sp->s_port;
}
if (__hostName) {
# ifdef USE_H_ERRNO
do {
/* must refetch in loop */
if (hostName == nil) {
__hostName = 0;
} else if (__isString(hostName) || __isSymbol(hostName)) {
__hostName = __stringVal(hostName);
}
# ifdef DO_WRAP_CALLS
hp = STX_WSA_CALL1("gethostbyname", gethostbyname, __hostName);
if ((INT)hp < 0) hp = NULL;
# else
/* __BEGIN_INTERRUPTABLE__ is dangerous, because gethostbyname
* uses a static data area
*/
__BEGIN_INTERRUPTABLE__
hp = gethostbyname(__hostName);
__END_INTERRUPTABLE__
#endif
} while ((hp == NULL)
&& (
(h_errno == TRY_AGAIN)
|| errno == EINTR
# ifdef IRIX5_3
|| (errno == ECONNREFUSED)
# endif
)
);
if (hp == 0) {
switch (h_errno) {
case HOST_NOT_FOUND:
errorString = @symbol(unknownHost);
break;
case NO_ADDRESS:
errorString = @symbol(noAddress);
break;
case NO_RECOVERY:
errorString = @symbol(permanentFailure);
break;
case TRY_AGAIN:
errorString = @symbol(tryAgain);
break;
default:
errorString = @symbol(unknownError);
break;
}
error = __mkSmallInteger(h_errno);
goto err;
}
# else /* !USE_H_ERRNO */
hp = gethostbyname(__hostName);
if (hp == 0) {
errorString = @symbol(unknownHost);
error = __mkSmallInteger(-1);
goto err;
}
# endif /* !USE_H_ERRNO*/
if (__isSmallInteger(domain) && hp->h_addrtype != __smallIntegerVal(domain)) {
errorString = @symbol(unknownHost);
error = __mkSmallInteger(-2);
goto err;
}
for (cnt = 0, addrpp = hp->h_addr_list; *addrpp; addrpp++)
cnt++;
addrpp = hp->h_addr_list;
} else {
cnt = 1;
}
result = __ARRAY_NEW_INT(cnt);
if (result == nil) {
error = @symbol(allocationFailure);
goto err;
}
for (i = 0; i < cnt; i++) {
OBJ o, resp;
struct sockaddr_in *sa;
resp = __ARRAY_NEW_INT(6);
if (resp == nil) {
error = @symbol(allocationFailure);
goto err;
}
__ArrayInstPtr(result)->a_element[i] = resp; __STORE(result, resp);
__ArrayInstPtr(resp)->a_element[0] = __mkSmallInteger(0);
__ArrayInstPtr(resp)->a_element[2] = type; __STORE(result, type);
__ArrayInstPtr(resp)->a_element[3] = proto; __STORE(result, proto);
__PROTECT__(resp);
o = __BYTEARRAY_NEW_INT(sizeof(*sa));
__UNPROTECT__(resp);
if (o == nil) {
error = @symbol(allocationFailure);
goto err;
}
__ArrayInstPtr(resp)->a_element[4] = o; __STORE(resp, o);
sa = (struct sockaddr_in *)__byteArrayVal(o);
sa->sin_port = port;
if (__hostName) {
sa->sin_family = hp->h_addrtype;
memcpy(&sa->sin_addr, *addrpp, hp->h_length);
__ArrayInstPtr(resp)->a_element[1] = __mkSmallInteger(hp->h_addrtype);
if (hp->h_name) {
__PROTECT__(resp);
o = __MKSTRING(hp->h_name);
__UNPROTECT__(resp);
if (o == nil) {
error = @symbol(allocationFailure);
goto err;
}
__ArrayInstPtr(resp)->a_element[5] = o; __STORE(resp, o);
}
addrpp++;
} else{
__ArrayInstPtr(resp)->a_element[1] = domain; __STORE(resp, domain);
}
}
err:;
# endif /* ! AI_NUMERICHOST */
}
#else /* ! HAS_SOCKET */
error = @symbol(notImplemented);
#endif
%}.
error notNil ifTrue:[
|request|
request := SocketAddressInfo new
domain:domainArg;
type:typeArg;
protocol:protoArg;
canonicalName:hostName;
serviceName:serviceName.
^ (HostNameLookupError new
parameter:error;
messageText:' - ', errorString;
request:request) raiseRequest.
].
1 to:result size do:[:i |
|entry dom info|
info := SocketAddressInfo new.
entry := result at:i.
info flags:(entry at:1).
info domain:(dom := OperatingSystem domainSymbolOf:(entry at:2)).
info type:(OperatingSystem socketTypeSymbolOf:(entry at:3)).
info protocol:(self protocolSymbolOf:(entry at:4)).
info socketAddress:((SocketAddress newDomain:dom) fromBytes:(entry at:5)).
info canonicalName:(entry at:6).
result at:i put:info
].
^ result
"
self getAddressInfo:'localhost' serviceName:nil
domain:nil type:nil protocol:nil flags:nil
self getAddressInfo:'localhost' serviceName:nil
domain:#inet type:#stream protocol:nil flags:nil
self getAddressInfo:'localhost' serviceName:nil
domain:#inet type:#stream protocol:#tcp flags:nil
self getAddressInfo:'blurb.exept.de' serviceName:nil
domain:#inet type:nil protocol:nil flags:nil
self getAddressInfo:'1.2.3.4' serviceName:'bla'
domain:#inet type:nil protocol:nil flags:nil
self getAddressInfo:'localhost' serviceName:'echo'
domain:#inet type:nil protocol:nil flags:nil
self getAddressInfo:nil serviceName:'echo'
domain:#inet type:nil protocol:nil flags:nil
self getAddressInfo:nil serviceName:nil
domain:#inet type:nil protocol:nil flags:nil
self getAddressInfo:'www.google.de' serviceName:nil
domain:nil type:nil protocol:nil flags:nil
self getAddressInfo:'smc1' serviceName:nil
domain:nil type:nil protocol:nil flags:nil
"
!
getNameInfo:socketAddress wantHostName:wantHostName wantServiceName:wantServiceName datagram:useDatagram flags:flags
"answer an Array containing the hostName and serviceName
in socketAddress.
This is the generic version of getHostByAddr, however, if supported by the OS,
this returns multiple hostnames (if appropriate)"
|error errorString hostName serviceName|
%{ /* STACK:32000 */
#if !defined(NO_SOCKET)
# ifndef NI_MAXHOST
# define NI_MAXHOST 256
# define NI_MAXSERV 64
# endif
char host[NI_MAXHOST];
char service[NI_MAXSERV];
char *hp = 0, *sp = 0;
int hsz = 0, ssz = 0;
int ret, __flags;
char *bp;
int nInstBytes, sockAddrSize;
if (wantHostName == true) {
hp = host;
hsz = sizeof(host);
}
if (wantServiceName == true) {
sp = service;
ssz = sizeof(service);
}
if (hp == 0 && sp == 0) {
error = @symbol(badArgument);
goto err;
}
if (!__isBytes(socketAddress)) {
error = @symbol(badArgument1);
goto err;
}
nInstBytes = __OBJS2BYTES__(__intVal(__ClassInstPtr(__qClass(socketAddress))->c_ninstvars));
sockAddrSize = __byteArraySize(socketAddress);
sockAddrSize -= nInstBytes;
if (!__isSmallInteger(flags)) {
error = @symbol(badArgument5);
goto err;
}
__flags = __intVal(flags);
#if defined(NI_NUMERICHOST)
if (useDatagram == true) {
__flags |= NI_DGRAM;
}
{
bp = (char *)(__byteArrayVal(socketAddress));
bp += nInstBytes;
__BEGIN_INTERRUPTABLE__
ret = getnameinfo((struct sockaddr *)bp, sockAddrSize,
hp, hsz, sp, ssz, __flags);
__END_INTERRUPTABLE__
} while (ret == EAI_SYSTEM && errno == EINTR);
if (ret != 0) {
switch (ret) {
case EAI_FAMILY:
error = @symbol(badProtocol);
break;
case EAI_SOCKTYPE:
error = @symbol(badSocketType);
break;
case EAI_BADFLAGS:
error = @symbol(badFlags);
break;
case EAI_NONAME:
error = @symbol(unknownHost);
break;
case EAI_SERVICE:
error = @symbol(unknownService);
break;
case EAI_ADDRFAMILY :
error = @symbol(unknownHostForProtocol);
break;
case EAI_NODATA:
error = @symbol(noAddress);
break;
case EAI_MEMORY:
error = @symbol(allocationFailure);
break;
case EAI_FAIL:
error = @symbol(permanentFailure);
break;
case EAI_AGAIN:
error = @symbol(tryAgain);
break;
case EAI_SYSTEM:
error = @symbol(systemError);
break;
default:
error = @symbol(unknownError);
}
errorString = __MKSTRING(gai_strerror(ret));
goto err;
}
# else /* ! NI_NUMERICHOST */
{
/*
* Do it using gethostbyaddr()
*/
struct sockaddr_in *sa;
if (sockAddrSize < sizeof(*sa)) {
error = @symbol(badArgument1);
goto err;
}
bp = (char *)(__byteArrayVal(socketAddress));
bp += nInstBytes;
sa = (struct sockaddr_in *)bp;
if (sp) {
struct servent *servp;
char *__proto = 0;
__proto = (useDatagram == true ? "udp" : "tcp");
servp = getservbyport(sa->sin_port, __proto);
if (servp) {
sp = servp->s_name;
}
}
if (hp) {
struct hostent *hostp;
# ifdef USE_H_ERRNO
do {
/* must refetch in loop */
bp = (char *)(__byteArrayVal(socketAddress));
bp += nInstBytes;
sa = (struct sockaddr_in *)bp;
/* __BEGIN_INTERRUPTABLE__ is dangerous, because gethostbyname uses a static data area
*/
hostp = gethostbyaddr((char *)&sa->sin_addr, sockAddrSize, sa->sin_family);
/* __END_INTERRUPTABLE__ */
} while ((hostp == NULL)
&& ((h_errno == TRY_AGAIN)
|| errno == EINTR
# ifdef IRIX5_3
|| (errno == ECONNREFUSED)
# endif
)
);
if (hostp == 0) {
switch (h_errno) {
case HOST_NOT_FOUND:
errorString = @symbol(unknownHost);
break;
case NO_ADDRESS:
errorString = @symbol(noAddress);
break;
case NO_RECOVERY:
errorString = @symbol(permanentFailure);
break;
case TRY_AGAIN:
errorString = @symbol(tryAgain);
break;
default:
errorString = @symbol(unknownError);
break;
}
error = __mkSmallInteger(h_errno);
goto err;
}
# else /* !USE_H_ERRNO */
hostp = gethostbyaddr((char *)&sa->sin_addr, sockAddrSize, sa->sin_family);
if (hostp == 0) {
errorString = @symbol(unknownHost);
error = __mkSmallInteger(-1);
goto err;
}
# endif /* !USE_H_ERRNO*/
hp = hostp->h_name;
}
}
# endif /* ! NI_NUMERICHOST */
if (hp)
hostName = __MKSTRING(hp);
if (sp)
serviceName = __MKSTRING(sp);
err:;
#else
error = @symbol(notImplemented);
#endif
%}.
error notNil ifTrue:[
^ (HostAddressLookupError new
parameter:error;
messageText:' - ', errorString;
request:thisContext message) raiseRequest.
].
^ Array with:hostName with:serviceName
"
self getNameInfo:
(self getAddressInfo:'localhost' serviceName:'echo'
domain:#inet type:#stream protocol:nil flags:nil) first socketAddress
wantHostName:true wantServiceName:true datagram:false flags:0
self getNameInfo:
(self getAddressInfo:'exept.exept.de' serviceName:'echo'
domain:#inet type:#stream protocol:nil flags:nil) first socketAddress
wantHostName:true wantServiceName:true datagram:false flags:0
self getNameInfo:#[1 2 3 4]
wantHostName:true wantServiceName:true datagram:false flags:0
"
! !
!Win32OperatingSystem class methodsFor:'documentation'!
version
^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.179 2005-04-14 13:07:11 cg Exp $'
! !
Win32OperatingSystem initialize!
Win32OperatingSystem::RegistryEntry initialize!