command-linestdinopenedgeprogress-4gl

How to determine if a procedure was passed a file to standard input when run via the command line


By running the procedure through the command line, pointing it to the input file like this

_progres -b -p test.p < test.txt

I can read the contents of test.txt into test.p with a simple

def var cline as c no-undo.
_tt:
do while true on endkey undo _tt,leave _tt:
import unformatted cline.
end.

However, if i don't pass a file to test.p, then without an explicitly open input, the error will be ** Attempt to read with no current source of input. (513). How to determine that a procedure was passed a file as input.


Solution

  • This should do what you want:

    /* isatty.i
     */
     
    function isatty returns logical () in super.
    

    and:

    /* isatty.p
     * 
     * to use this:
     *
     *    run isatty.p persistent
     *
     *    {isatty.i}
     *    message isatty().
     *
     */
    
    &IF "{&PROCESS-ARCHITECTURE}" = "64" &THEN
      &global-define XINT           int64
      &global-define LONGINT        int64
      &global-define PUTLONGINT     PUT-INT64
      &global-define GETLONGINT     GET-INT64
     &ELSE
      &global-define XINT           integer
      &global-define LONGINT        long
      &global-define PUTLONGINT     PUT-LONG
      &global-define GETLONGINT     GET-LONG
    &ENDIF
    
    define stream inStrm.
    
    session:add-super-procedure( this-procedure ).
    
    return.
    
    
    procedure GetFileType external "kernel32.dll":
      define input  parameter fileHandle as {&LONGINT}.
      define return parameter result     as {&LONGINT}.
    end.
    
    procedure GetStdHandle external "kernel32.dll":
      define input  parameter fileHandle as {&LONGINT}.
      define return parameter result     as {&LONGINT}.
    end.
    
    
    /* determine if we are running with user input or redirected input
     *
     */
    
    function isatty returns logical ():
    
      define variable result     as logical   no-undo.
      define variable tty        as character no-undo.
      define variable fileHandle as int64     no-undo.
      define variable fileType   as int64     no-undo.
    
      result = false.
    
      if opsys = "unix" then
        do:
    
          input stream inStrm through value( "tty" ).
          import stream inStrm unformatted tty.
          input stream inStrm close.
          if tty begins "/dev/" then
            result = true.
    
        end.
       else
        do:
    
          /* Windows stdin = -10    */
    
          run getStdHandle( -10, output fileHandle ).
    
          run getFileType( fileHandle, output fileType ).
    
          /* 0x0000 = unknown
           * 0x0001 = disk
           * 0x0002 = character (CON or LPT etc)
           * 0x0003 = pipe
           * 0x8000 = remote (unused?)
           */
    
          if fileType = 2 then
            result = true.
    
        end.
    
      return result.
    
    end.
    

    test it with:

    /* testtty.p
     */
    
    run isatty.p persistent.
       
    {isatty.i}
    message isatty().
     
    quit.
    

    Like so:

    $ pro -p testtty.p
    yes
    

    and:

    $ cat /dev/null | pro -b -p testtty.p > tty.out
    $ cat tty.out
    no
    

    This is legal (but somewhat confusing):

    $ pro -b -p testtty.p > tty.out
    $ cat tty.out
    yes
    

    If you are doing that intentionally be aware that in such a case LASTKEY will be -1.