UnixOperatingSystem.st
branchjv
changeset 21024 8734987eb5c7
parent 20727 fb8c5591428b
parent 20963 68a1d022d6f4
child 21088 6f4535127ce6
--- a/UnixOperatingSystem.st	Wed Oct 26 23:35:39 2016 +0100
+++ b/UnixOperatingSystem.st	Fri Nov 18 20:48:04 2016 +0000
@@ -989,35 +989,51 @@
 
 documentation
 "
-    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)
-
+    This class realizes access to most (all?) required operating system services.
+    At startup, the global 'OperatingSystem' will be bound to either me, or one of
+    my sibling classes, Win32OperatingSystem, VMSOperatinSystem or OSXOperatingSystem.
+
+    Never access UnixOperatingSystem directly. Always only refer to OperatingSystem,
+    if at all. Most functionality is actually used indirectly, via the Filename, PipeStream
+    or Socket classes.
+    
+    Some of the functions are specific for unix, some may not be found in other OS's 
+    or behave slightly different, returning different data.
+    
+    For portable programs, only rely on protocol which is found in my abstract
+    superclass, and will therefore also be found in my correspnding sibling os-classes
+    (i.e. Win32OperatingSystem).
+    If you need os-specific functionality, surround it by a condition, such as
+    OperatingSystem isUNIXlike or OperatingSystem isMSWINDOWSlike.
+    
+    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.
+
+    Notice, that on Unix systems, the Win32OperatingSystem class is not even loaded,
+    and vice versa. So you may have to open a changes browser on the other class, to check
+    how the corresponding function operates in the other os.
+    
     [Class variables:]
 
-	HostName        <String>        remembered hostname
-
-	DomainName      <String>        remembered domainname
-
-	SlowFork        <Boolean>       if set, fork and popen are avoided;
-					(more or less obsolete now)
-
-
-	CurrentDirectory <String>       remembered currentDirectories path
+        HostName        <String>        remembered hostname
+
+        DomainName      <String>        remembered domainname
+
+        SlowFork        <Boolean>       if set, fork and popen are avoided;
+                                        (more or less obsolete now)
+
+
+        CurrentDirectory <String>       remembered currentDirectories path
 
     [author:]
-	Claus Gittinger
+        Claus Gittinger
 
     [see also:]
-	OSProcessStatus
-	Filename Date Time
-	ExternalStream FileStream PipeStream Socket
+        OSProcessStatus
+        Filename Date Time
+        ExternalStream FileStream PipeStream Socket
 "
 !
 
@@ -3525,13 +3541,14 @@
 fork
     "fork a new (HEAVY-weight) unix process.
      Not supported with MSDOS & VMS systems.
-     Dont confuse this with Block>>fork, which creates
-     lightweight smalltalk processes. This method will return
-     0 to the child process, and a non-zero number (which is the childs
-     unix-process-id) to the parent (original) process.
-
-     In normal situations, you dont need to use this low level entry; see
-     #startProcess: and #executCommand: for higher level interfaces."
+     Don't confuse this with Block>>fork, which creates
+     lightweight smalltalk processes. 
+     This method will return 0 to the child process, 
+     and a non-zero number (which is the childs unix-process-id) 
+     to the parent (original) process.
+
+     In normal situations, you don't need to use this low level entry; 
+     see #startProcess: and #executeCommand: for higher level interfaces."
 
 %{  /* NOCONTEXT */
     int pid;
@@ -3545,13 +3562,16 @@
     ^ UnsupportedOperationSignal raise
 
     "
-     |id|
-
+     |id t1 t2 t3|
+
+     t1 := Timestamp now.
      id := OperatingSystem fork.
      id == 0 ifTrue:[
-	'I am the child process' printCR.
-	OperatingSystem exit
-     ]
+         'Child t=' print. (Timestamp now - t1) printCR. 
+         'I am the child process' printCR.
+         OperatingSystem exit
+     ].
+     'Parent t=' print. (Timestamp now - t1) printCR. 
     "
 !
 
@@ -3632,6 +3652,127 @@
 
 startProcess:aCommandString inputFrom:anExternalInStream outputTo:anExternalOutStream
     errorTo:anExternalErrStream auxFrom:anAuxiliaryStream
+    environment:anEvironmentDictionary inDirectory:dir newPgrp:newPgrp showWindow:ignoredHere
+
+    "start executing the OS command as specified by the argument, aCommandString
+     as a separate process; do not wait for the command to finish.
+     If aCommandString is a String, 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).
+     If aCommandString is an Array, the first element is the command to be executed,
+     and the other elements are the arguments to the command. No shell is invoked in this case.
+     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:newPgrp
+        inDirectory:dir.
+
+    nullStream notNil ifTrue:[
+        nullStream close.
+    ].
+
+    ^ rslt
+
+    "blocking at current prio (i.e. only higher prio threads execute):
+
+     OperatingSystem executeCommand:'ls -l > out'.
+     OperatingSystem executeCommand:#('/bin/ls' '-l') outputTo:Transcript.
+    "
+
+    "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'
+    "
+
+    "
+     |pid sema|
+
+     sema := Semaphore new.
+
+     Processor
+            monitor:[
+                pid := OperatingSystem startProcess:'(sleep 2; ls -l) > out 2>err'
+            ]
+            action:[:osStatus | sema signal ].
+
+     sema wait.
+     Transcript showCR:'finished'
+    "
+
+    "
+     |pid sema|
+
+     sema := Semaphore new.
+
+     Processor
+            monitor:[
+                pid := OperatingSystem startProcess:'(sleep 1; echo 1; sleep 9; ls -l) > out 2>err'
+            ]
+            action:[:osStatus | sema signal ].
+
+     Delay waitForSeconds:2.
+     OperatingSystem terminateProcess:pid.
+     Transcript showCR:'terminated'
+    "
+
+    "Modified: / 21.3.1997 / 10:04:35 / dq"
+    "Modified: / 15.7.1997 / 16:03:51 / stefan"
+    "Modified: / 5.6.1998 / 19:03:51 / cg"
+    "Created: / 12.11.1998 / 14:39:20 / cg"
+!
+
+startProcess:aCommandString inputFrom:anExternalInStream outputTo:anExternalOutStream
+    errorTo:anExternalErrStream auxFrom:anAuxiliaryStream
     environment:anEvironmentDictionary inDirectory:dir showWindow:ignoredHere
 
     "start executing the OS command as specified by the argument, aCommandString
@@ -3646,109 +3787,10 @@
      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'.
-     OperatingSystem executeCommand:#('/bin/ls' '-l') outputTo:Transcript.
-    "
-
-    "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'
-    "
-
-    "
-     |pid sema|
-
-     sema := Semaphore new.
-
-     Processor
-            monitor:[
-                pid := OperatingSystem startProcess:'(sleep 2; ls -l) > out 2>err'
-            ]
-            action:[:osStatus | sema signal ].
-
-     sema wait.
-     Transcript showCR:'finished'
-    "
-
-    "
-     |pid sema|
-
-     sema := Semaphore new.
-
-     Processor
-            monitor:[
-                pid := OperatingSystem startProcess:'(sleep 1; echo 1; sleep 9; ls -l) > out 2>err'
-            ]
-            action:[:osStatus | sema signal ].
-
-     Delay waitForSeconds:2.
-     OperatingSystem terminateProcess:pid.
-     Transcript showCR:'terminated'
-    "
-
-    "Modified: / 21.3.1997 / 10:04:35 / dq"
-    "Modified: / 15.7.1997 / 16:03:51 / stefan"
-    "Modified: / 5.6.1998 / 19:03:51 / cg"
-    "Created: / 12.11.1998 / 14:39:20 / cg"
+    ^ self
+        startProcess:aCommandString inputFrom:anExternalInStream outputTo:anExternalOutStream
+        errorTo:anExternalErrStream auxFrom:anAuxiliaryStream
+        environment:anEvironmentDictionary inDirectory:dir newPgrp:true showWindow:ignoredHere
 ! !
 
 !UnixOperatingSystem class methodsFor:'executing OS commands-queries'!
@@ -3829,7 +3871,7 @@
     ].
 
     "/ command is a single word, not relative and not absolute.
-    "/ search along PATH environment variable to see what a shoell would do.
+    "/ search along PATH environment variable to see what a shell would do.
     path := self getEnvironment:'PATH'.
     path notEmptyOrNil ifTrue:[
         (path asCollectionOfSubstringsSeparatedBy:self pathSeparator) do:[:eachPathComponent |
@@ -6106,7 +6148,7 @@
 
 defaultSignal:signalNumber
     "revert to the default action on arrival of a (Unix-)signal.
-     Dont confuse Unix signals with smalltalk signals.
+     Don't 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.
@@ -6118,8 +6160,8 @@
 
     if (__isSmallInteger(signalNumber)) {
 #ifdef SIG_DFL
-	signal(__intVal(signalNumber), SIG_DFL);
-	RETURN (self);
+        signal(__intVal(signalNumber), SIG_DFL);
+        RETURN (self);
 #endif
     }
 %}.
@@ -6175,7 +6217,7 @@
 
 disableSignal:signalNumber
     "disable (Unix-) signal processing for signalNumber.
-     Dont confuse Unix signals with smalltalk signals.
+     Don't 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.
@@ -6187,23 +6229,23 @@
 %{  /* NOCONTEXT */
 #ifdef __SCHTEAM__
     if (signalNumber.isSmallInteger()) {
-	int sigNo = signalNumber.intValue();
-
-	if (sigNo != 0) {
-	    java.lang.System.err.println("ignored disable-signal: "+sigNo);
-	}
-	return context._RETURN(self);
+        int sigNo = signalNumber.intValue();
+
+        if (sigNo != 0) {
+            java.lang.System.err.println("ignored disable-signal: "+sigNo);
+        }
+        return context._RETURN(self);
     }
 #else
     if (__isSmallInteger(signalNumber)) {
-	int sigNo = __intVal(signalNumber);
-
-	if (sigNo == 0) {
-	    RETURN (self);
-	}
+        int sigNo = __intVal(signalNumber);
+
+        if (sigNo == 0) {
+            RETURN (self);
+        }
 # ifdef SIG_IGN
-	signal(sigNo, SIG_IGN);
-	RETURN (self);
+        signal(sigNo, SIG_IGN);
+        RETURN (self);
 # endif
     }
 #endif
@@ -9054,7 +9096,7 @@
     "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).
-     Don't depend on this - use getOSType. I dont really see a point
+     Don't depend on this - use getOSType. I don't really see a point
      here ...
      (except for slight differences between next/mach and other machs)"
 
@@ -9076,7 +9118,7 @@
 
 %}.
     sys isNil ifTrue:[
-	^ self getOSType
+        ^ self getOSType
     ].
     ^ sys
 
@@ -10726,7 +10768,7 @@
     }
 
     /*
-     * nope - I really dont know who you are.
+     * nope - I really don't know who you are.
      */
     if (! name || (name[0] == 0) ) {
         name = "you";
@@ -13241,94 +13283,88 @@
     type := OperatingSystem socketTypeCodeOf:typeArg.
     proto := self protocolCodeOf:protoArg.
     serviceNameArg notNil ifTrue:[
-	serviceName := serviceNameArg printString.      "convert integer port numbers"
+        serviceName := serviceNameArg printString.      "convert integer port numbers"
     ].
 
     hostName isNil ifTrue:[
-	encodedHostName := nil.
+        encodedHostName := nil.
     ] ifFalse:[
-	encodedHostName := hostName utf8Encoded.
+        encodedHostName := hostName utf8Encoded.
     ].
     (encodedHostName ~~ hostName and:[OperatingSystem getCodeset ~~ #utf8]) ifTrue:[
-	"hostName is not plain ASCII - so this is an IDN domain name. Have to ensure, that the locale is UTF-8.
-	 Block interrupt to not affect other ST/X processes while the locale is changed."
-	|interruptsBlocked oldLocale|
-
-	interruptsBlocked := OperatingSystem blockInterrupts.
-	oldLocale := OperatingSystem setLocale:#'LC_CTYPE' to:nil.
-	OperatingSystem setLocale:#'LC_CTYPE' to:'en_US.UTF-8'.
-	result := self primGetAddressInfo:encodedHostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags.
-	OperatingSystem setLocale:#'LC_CTYPE' to:oldLocale.
-	interruptsBlocked ifFalse:[
-	    OperatingSystem unblockInterrupts.
-	].
+        "hostName is not plain ASCII - so this is an IDN domain name. Have to ensure, that the locale is UTF-8.
+         Block interrupt to not affect other ST/X processes while the locale is changed."
+        |interruptsBlocked oldLocale|
+
+        interruptsBlocked := OperatingSystem blockInterrupts.
+        oldLocale := OperatingSystem setLocale:#'LC_CTYPE' to:nil.
+        OperatingSystem setLocale:#'LC_CTYPE' to:'en_US.UTF-8'.
+        result := self primGetAddressInfo:encodedHostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags.
+        OperatingSystem setLocale:#'LC_CTYPE' to:oldLocale.
+        interruptsBlocked ifFalse:[
+            OperatingSystem unblockInterrupts.
+        ].
     ] ifFalse:[
-	result := self primGetAddressInfo:encodedHostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags.
+        result := self primGetAddressInfo:encodedHostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags.
     ].
     result isArray ifFalse:[
-	|request|
-	request := SocketAddressInfo new
-	    domain:domainArg;
-	    type:typeArg;
-	    protocol:protoArg;
-	    canonicalName:hostName;
-	    serviceName:serviceName.
-	^ (HostNameLookupError new
-		parameter:result;
-		messageText:' - ', (result printString);
-		request:request) raiseRequest.
+        |request|
+        request := SocketAddressInfo new
+            domain:domainArg;
+            type:typeArg;
+            protocol:protoArg;
+            canonicalName:hostName;
+            serviceName:serviceName.
+        ^ (HostNameLookupError new
+                parameter:result;
+                messageText:' - ', (result printString);
+                request:request) raiseRequest.
     ].
     1 to:result size do:[:i |
-	|entry dom info|
-
-	entry := result at:i.
-
-	info := SocketAddressInfo new.
-	info
-	    flags:(entry at:1);
-	    domain:(dom := OperatingSystem domainSymbolOf:(entry at:2));
-	    type:(OperatingSystem socketTypeSymbolOf:(entry at:3));
-	    protocol:(self protocolSymbolOf:(entry at:4));
-	    socketAddress:((SocketAddress newDomain:dom) fromBytes:(entry at:5));
-	    canonicalName:(entry at:6).
-
-	result at:i put:info.
+        |entry dom info|
+
+        entry := result at:i.
+
+        info := SocketAddressInfo new.
+        info
+            flags:(entry at:1);
+            domain:(dom := OperatingSystem domainSymbolOf:(entry at:2));
+            type:(OperatingSystem socketTypeSymbolOf:(entry at:3));
+            protocol:(self protocolSymbolOf:(entry at:4));
+            socketAddress:((SocketAddress newDomain:dom) fromBytes:(entry at:5));
+            canonicalName:(entry at:6).
+
+        result at:i put:info.
     ].
     ^ result
 
     "
      self getAddressInfo:'localhost' serviceName:nil
-	    domain:nil type:nil protocol:nil flags:nil
+            domain:nil type:nil protocol:nil flags:nil
      self getAddressInfo:'localhost' serviceName:nil
-	    domain:#inet type:#stream protocol:nil flags:nil
+            domain:#inet type:#stream protocol:nil flags:nil
      self getAddressInfo:'localhost' serviceName:nil
-	    domain:#inet type:#stream protocol:#tcp flags:nil
+            domain:#inet type:#stream protocol:#tcp flags:nil
      self getAddressInfo:'blurb.exept.de' serviceName:nil
-	    domain:#inet type:nil protocol:nil flags: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
+            domain:#inet type:nil protocol:nil flags:nil
      self getAddressInfo:'localhost' serviceName:'echo'
-	    domain:#inet type:nil protocol:nil flags:nil
+            domain:#inet type:nil protocol:nil flags:nil
      self getAddressInfo:nil serviceName:'echo'
-	    domain:#inet type:nil protocol:nil flags:nil
+            domain:#inet type:nil protocol:nil flags:nil
      self getAddressInfo:nil serviceName:nil
-	    domain:#inet type:nil protocol:nil flags: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:'www.exept.de' serviceName:nil
-	    domain:nil type:nil protocol:nil flags:nil
+            domain:nil type:nil protocol:nil flags:nil
      self getAddressInfo:'www.exept.de' serviceName:nil
-	    domain:#'AF_INET' type:nil protocol:nil flags:nil
+            domain:nil type:nil protocol:nil flags:nil
      self getAddressInfo:'www.exept.de' serviceName:nil
-<<<<<<< UnixOperatingSystem.st
+            domain:#'AF_INET' type:nil protocol:nil flags:nil
+     self getAddressInfo:'www.exept.de' serviceName:nil
             domain:#'AF_INET6' type:nil protocol:nil flags:nil
-     self getAddressInfo:'www.baden-württemberg.de' serviceName:nil
+     self getAddressInfo:'www.baden-wrttemberg.de' serviceName:nil
             domain:#'AF_INET' type:#stream protocol:nil flags:nil
-=======
-	    domain:#'AF_INET6' type:nil protocol:nil flags:nil
-     self getAddressInfo:'www.baden-wrttemberg.de' serviceName:nil
-	    domain:#'AF_INET' type:#stream protocol:nil flags:nil
->>>>>>> 1.489
     "
 !