Menu

#875 Add a .nulldevice object to .environment

5.3.0
unread
nobody
None
none
1
2026-07-12
2026-06-15
No

Allow an ooRexx pendant for the null device (/dev/null in Unix, null in Windows), which needs to be a stream object.

Attached a suggested implementation with test scripts (just run testNullDevice.rex).

3 Attachments

Discussion

  • m-stgt

    m-stgt - 2026-06-16

    null in Windows

    Reserved names in Windows (like CON, PRN, AUX, etc.) are no 4-letter words. Choosing NUL.TXT as output file name might make it hard to find.

     
  • jfaucher

    jfaucher - 2026-06-16

    "dir | testFilter.rex"
    better to use
    "dir | rexx testFilter.rex"
    because the test opened 3 times my editor :-)

    I tested on macOS, after defining a "dir" script.
    All good, except the test 4b.
    Press ENTER, stay blocked.
    Even Ctrl-D does not unblock.
    Must Ctrl-C.
    (did not investigate)

    The redirection with the error keyword catches the stderr of the executed command,
    but does not catch the error message when the command can't be executed.

    On macOS, where dir is not a command:

    *** 3. cmd=[dir | rexx testFilter.rex] about to 'address system cmd with error using (.nullDevice)':
        29 *-* address system cmd with error  using (.nullDevice)
           >>>   "dir | testFilter.rex"
           +++   "RC(127)"
    

    It would be good to show in the documentation how to catch this error message with NullDevice:

    .error~destination(.NullDevice)
    address system (command) with error stem error.
    .error~destination -- restore
    
     
    • jfaucher

      jfaucher - 2026-06-16

      About the macOS problem, is it only me?

      I can't debug the child rexx process, so I don't know why/where the child rexx process is blocked.

      My notes:

      Same problem if I replace parse pull by linein.
      Testing with parse pull.

      With ::options trace i in rgfNullDevice.cls

      debug in xcode, edit scheme to select console = terminal.

      *** 4b. cmd=[rexx -e ".output~charout('enter text, press <enter>: ');parse pull data;if data<>'' then say '(stdout):' data;else say"] about to 'address system cmd with input using (.nullDevice)':
             >I> Method "LINEIN" with scope "NullDevice.Implementation" in package "/Users/jlfaucher/Downloads/rexx/NullDevice/rgfNullDevice.cls".
          26 *-* raise notReady -- return ("")
             <I< Method "LINEIN" with scope "NullDevice.Implementation" in package "/Users/jlfaucher/Downloads/rexx/NullDevice/rgfNullDevice.cls".
      enter text, press <enter>:
      
      ENTER    does nothing
      ^D       does nothing
      

      pause in xcode

      #0  0x0000000187b0d204 in __wait4 ()
      #1  0x0000000100841e90 in ioCommandHandler at /Users/Shared/local/rexx/oorexx/official/main/trunk/interpreter/platform/unix/SystemCommands.cpp:1035
      #2  0x00000001007de610 in RedirectingCommandHandlerDispatcher::run at /Users/Shared/local/rexx/oorexx/official/main/trunk/interpreter/concurrency/CommandHandler.cpp:294
      #3  0x00000001007aa278 in NativeActivation::run at /Users/Shared/local/rexx/oorexx/official/main/trunk/interpreter/execution/NativeActivation.cpp:1692
      #4  0x00000001007e5684 in Activity::run at /Users/Shared/local/rexx/oorexx/official/main/trunk/interpreter/concurrency/Activity.cpp:3449
      #5  0x00000001007ddfe4 in CommandHandler::call at /Users/Shared/local/rexx/oorexx/official/main/trunk/interpreter/concurrency/CommandHandler.cpp:143
      #6  0x00000001007a0018 in RexxActivation::command at /Users/Shared/local/rexx/oorexx/official/main/trunk/interpreter/execution/RexxActivation.cpp:4368
      #7  0x00000001007f9840 in RexxInstructionAddress::execute at /Users/Shared/local/rexx/oorexx/official/main/trunk/interpreter/instructions/AddressInstruction.cpp:163
      
      RexxObjectPtr RexxEntry ioCommandHandler(RexxExitContext *context, RexxStringObject address, RexxStringObject command, RexxIORedirectorContext *ioContext)
      {
      ...
          waitpid(pid, &status, 0);                                <-- waiting here (A)
          int rc;
          if (WIFEXITED(status)) // child process ended normal     breakpoint here
          {
              rc = WEXITSTATUS(status); // set return code
          }
          else
          {   // child process died
              rc = -(WTERMSIG(status));                            rc == -8
              if (rc == 1) // process was stopped
              {
                  rc = -1;
              }
          }
      
          // unknown command code?
          // a FAILURE will be raised for any command returning 127
          if (rc == UNKNOWN_COMMAND)
          {
              return ErrorFailure(context, commandString);
          }
          else if (rc != 0)
          {
              // for any non-zero return code we raise an ERROR condition
              context->RaiseCondition("ERROR", context->String(commandString),     <-- reach here (B)
                NULL, context->WholeNumberToObject(rc));
              return NULLOBJECT;
          }
          return context->False(); // zero return code
      }
      

      continue execution in xcode

      No longer blocked, but the console is still unresponsive.

      The breakpoint (A) is triggered.
      Step by step, I reach (B)

      continue execution in xcode.

      The program terminates, the frozen console is killed by xcode.

      Relaunch, attach xcode to the child rexx.
      The child process is terminated immediatly.

       
      • jfaucher

        jfaucher - 2026-06-16

        I tested with a simpler test case:

        -- testNullInput.rex
        .input~destination(.NullDevice)
        .output~charout('enter text, press <enter>: ')
        parse pull data
        .input~destination -- restore
        say data
        ::requires"rgfNullDevice.cls"
        

        This program crashes on macOS, does not crash on Windows.
        When debugging, I see the same situation on both platforms.
        raise notReady returns an OREF_NULL value.

        The crash is here:

        RexxInstructionParse::execute(RexxActivation *context, ExpressionStack *stack )
            switch (stringSource)
            {
                // PULL or PARSE PULL instruction
                case SUBKEY_PULL:
                    // pull a line from the queue and push on the stack for safekeeping
                    value = context->pullInput();                                            OREF_NULL
                    stack->push(value);
                    context->traceKeywordResult(GlobalNames::PULL, value);
                    break;
        ...
            // create the parse target
            target.init(value, argList, argCount, parseFlags, multiple, context, stack);    crash because value is OREF_NULL
        

        It's the same situation on Windows,
        When debugging, I get Exception thrown at 0x00007FFC6C26C524 (rexx.dll) in rexx.exe: 0xC0000005: Access violation reading location 0x0000000000000018.
        The fact that oorexx doesn't crash outside the debugger is a mistery.

        The solution is probably given by

        void StreamInfo::notreadyError(int error_code, RexxObjectPtr result)
        {
        ...
        context->RaiseCondition("NOTREADY", context->String(stream_name), self, result);
        

        A result must be specified in rgfNullDevice.cls when raising the exception.

        -- InputStream: raise notReady condition
        ::method charIn         unguarded   -- implement abstract method
           raise notReady description (self~objectName) array (self) return ("")
        ::method chars          unguarded   -- implement abstract method
           raise notReady description (self~objectName) array (self) return (0)
        ::method lineIn         unguarded   -- implement abstract method
           raise notReady description (self~objectName) array (self) return ("")
        ::method lines          unguarded   -- implement abstract method
           raise notReady description (self~objectName) array (self) return (0)
        

        With these changes, no more crash on macOS.
        That doesn't fix the blocking problem for 4b.
        Perhaps this test case is a bit convoluted.

         
        • Rony G. Flatscher

          Bonjour Jean Louis, many, many thanks for looking and debugging this, highly appreciated! Being on the road until the end of next week, I will only be able to return to this thereafter. Best regards, ---rony

           
        • jfaucher

          jfaucher - 2026-06-18

          Blocking problem due to Bug #2066

           
        • Anonymous

          Anonymous - 2026-07-12

          Just a little remark (not had the time to place it earlier). It should never be the case that plain ooRexx code crashes the interpreter. So the question would be whether the native code should be changed to raise a condition (and the documentation would need to point out that a description and a result must be supplied raising the notReady condition?

           

Anonymous
Anonymous

Add attachments
Cancel





MongoDB Logo MongoDB