[Windows] Any way to distinguish ^C Induced EOF from ^Z EOF?

Discussion in 'Java' started by Jan Burse, Mar 11, 2012.

  1. Jan Burse

    Jan Burse Guest

    Dear All,

    Just running the following test program:

    CtrlCRunner ctrl = new CtrlCRunner();
    ctrl.installCtrlC(
    new Runnable() {
    public void run() {
    /* do nothing ! */
    }
    }
    );
    FileInputStream fs = new FileInputStream(FileDescriptor.in);
    byte[] buf = new byte[256];
    for (;;) {
    System.out.print("test: ");
    int len = fs.read(buf);
    String str = new String(buf,0,Math.max(0,len));
    System.out.println("len = "+len+", buf = "+str+",
    buf[0]="+buf[0]);
    if ("exit".equals(str.trim())) break;
    }
    ctrl.deinstallCtrlC();

    Noticed that ^C and ^Z both deliver EOF.

    When pressing ^C

    test: len = -1, buf = , buf[0]=0

    When pressing ^Z and ENTER:

    test: ^Z
    len = -1, buf = , buf[0]=0

    How could I distinguish the two in Java?

    Best Regards

    BTW: It does not happen on Linux and Mac
    OS with ^C and ^D, I only see this happen
    currently on Windows 7.

    Sounds similar to the following problem:
    Inconsistent raw_input behavior after Ctrl-C
    http://www.gossamer-threads.com/lists/python/python/781893
    Jan Burse, Mar 11, 2012
    #1
    1. Advertising

  2. Jan Burse

    Jan Burse Guest

    Jan Burse schrieb:
    > I only see this happen currently on Windows 7.

    Did not yet test it for other windows versions.

    > Noticed that ^C and ^Z both deliver EOF.

    CTRL-BREAK does also deliver an EOF.
    Jan Burse, Mar 11, 2012
    #2
    1. Advertising

  3. Jan Burse

    Arne Vajhøj Guest

    On 3/11/2012 4:57 PM, Jan Burse wrote:
    > Just running the following test program:
    >
    > CtrlCRunner ctrl = new CtrlCRunner();
    > ctrl.installCtrlC(
    > new Runnable() {
    > public void run() {
    > /* do nothing ! */
    > }
    > }
    > );
    > FileInputStream fs = new FileInputStream(FileDescriptor.in);
    > byte[] buf = new byte[256];
    > for (;;) {
    > System.out.print("test: ");
    > int len = fs.read(buf);
    > String str = new String(buf,0,Math.max(0,len));
    > System.out.println("len = "+len+", buf = "+str+", buf[0]="+buf[0]);
    > if ("exit".equals(str.trim())) break;
    > }
    > ctrl.deinstallCtrlC();
    >
    > Noticed that ^C and ^Z both deliver EOF.
    >
    > When pressing ^C
    >
    > test: len = -1, buf = , buf[0]=0
    >
    > When pressing ^Z and ENTER:
    >
    > test: ^Z
    > len = -1, buf = , buf[0]=0
    >
    > How could I distinguish the two in Java?
    >
    > Best Regards
    >
    > BTW: It does not happen on Linux and Mac
    > OS with ^C and ^D, I only see this happen
    > currently on Windows 7.


    That type of stuff is very OS specific.

    I will (again) suggest using JNI to get the specific
    behavior that you desire.

    Java IO is just for the 98% of cases.

    Arne
    Arne Vajhøj, Mar 11, 2012
    #3
  4. Jan Burse

    Jan Burse Guest

    Arne Vajhøj schrieb:
    > That type of stuff is very OS specific.
    >
    > I will (again) suggest using JNI to get the specific
    > behavior that you desire.
    >
    > Java IO is just for the 98% of cases.
    >
    > Arne
    >



    When I raise the signal manually, for example
    as follows:

    new Thread() {
    public void run() {
    try {
    Thread.sleep(2000);
    } catch (InterruptedException x) {
    /* */
    }
    Signal.raise(new Signal("INT"));
    }
    }.start();

    Then the EOF does not happen. So it is not a problem
    of the Java dispatcher, more of the ReadFile operation.

    I am open to JNI, and also to JNA. Best would
    be if there is something out of the box.

    It could be fixed, if one would have access to
    GetLastError. Namely the MS docs do write:

    "Characters can be read from the console input buffer by using ReadFile
    with a handle to console input. The console mode determines the exact
    behavior of the ReadFile function. By default, the console mode is
    ENABLE_LINE_INPUT, which indicates that ReadFile should read until it
    reaches a carriage return. If you press Ctrl+C, the call succeeds, but
    GetLastError returns ERROR_OPERATION_ABORTED. For more information, see
    CreateFile."
    http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx

    Such a patch seems to be also done here:
    [Chicken-hackers] [PATCH] handle SIGINT correctly in csi on windows
    http://www.mail-archive.com//msg01846.html

    Bye
    Jan Burse, Mar 11, 2012
    #4
  5. Jan Burse

    Arne Vajhøj Guest

    On 3/11/2012 5:49 PM, Jan Burse wrote:
    > Arne Vajhøj schrieb:
    >> That type of stuff is very OS specific.
    >>
    >> I will (again) suggest using JNI to get the specific
    >> behavior that you desire.
    >>
    >> Java IO is just for the 98% of cases.
    >>
    >> Arne
    >>

    >
    >
    > When I raise the signal manually, for example
    > as follows:
    >
    > new Thread() {
    > public void run() {
    > try {
    > Thread.sleep(2000);
    > } catch (InterruptedException x) {
    > /* */
    > }
    > Signal.raise(new Signal("INT"));
    > }
    > }.start();
    >
    > Then the EOF does not happen. So it is not a problem
    > of the Java dispatcher, more of the ReadFile operation.
    >
    > I am open to JNI, and also to JNA.


    JNA is also JNI just encapsulated a bit.

    > Best would
    > be if there is something out of the box.


    Of course.

    But Java was not designed to provide that type of
    fine control over terminal IO.

    > It could be fixed, if one would have access to
    > GetLastError. Namely the MS docs do write:
    >
    > "Characters can be read from the console input buffer by using ReadFile
    > with a handle to console input. The console mode determines the exact
    > behavior of the ReadFile function. By default, the console mode is
    > ENABLE_LINE_INPUT, which indicates that ReadFile should read until it
    > reaches a carriage return. If you press Ctrl+C, the call succeeds, but
    > GetLastError returns ERROR_OPERATION_ABORTED. For more information, see
    > CreateFile."
    > http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx


    With JNI you can use it and get exactly the behavior you want.

    Arne
    Arne Vajhøj, Mar 11, 2012
    #5
  6. Jan Burse

    Jan Burse Guest

    Arne Vajhøj schrieb:
    >
    > But Java was not designed to provide that type of
    > fine control over terminal IO.


    This Java is just a *frigging cheap RI* implementation,
    that doesn't work correctly for console streams, although
    it could.

    It doesn't map the File metaphor correctly to the
    console streams. The Java developers were not reading
    the MS specs, and just doing a cheap hack.

    The native readBytes must anyway check GetLastError
    and eventually throw IOException. With some additional
    logic and a re-read everything would be fine.

    But I agree, the scope is a little bit enlarged, since
    it is a behaviour that can only be observed during
    Signals, which is also a little bit out of scope of
    standard java.

    Bye
    Jan Burse, Mar 11, 2012
    #6
  7. Jan Burse

    Arne Vajhøj Guest

    On 3/11/2012 6:23 PM, Jan Burse wrote:
    > Arne Vajhøj schrieb:
    >> But Java was not designed to provide that type of
    >> fine control over terminal IO.

    >
    > This Java is just a *frigging cheap RI* implementation,
    > that doesn't work correctly for console streams, although
    > it could.
    >
    > It doesn't map the File metaphor correctly to the
    > console streams. The Java developers were not reading
    > the MS specs, and just doing a cheap hack.
    >
    > The native readBytes must anyway check GetLastError
    > and eventually throw IOException. With some additional
    > logic and a re-read everything would be fine.
    >
    > But I agree, the scope is a little bit enlarged, since
    > it is a behaviour that can only be observed during
    > Signals, which is also a little bit out of scope of
    > standard java.


    Java was designed to write business apps that:
    * are reliable
    * are cheap to develop
    * will run on any platform that has Java

    I think they achieved that.

    But everything comes at a cost.

    Java is not a good language for OS specific code.

    That includes advanced terminal IO.

    Windows, *nix, z/OS, i, OpenVMS etc. are rather
    different when it comes to how they handle control
    keys.

    Arne
    Arne Vajhøj, Mar 11, 2012
    #7
  8. Jan Burse

    markspace Guest

    On 3/11/2012 3:23 PM, Jan Burse wrote:

    > This Java is just a *frigging cheap RI* implementation,
    > that doesn't work correctly for console streams, although



    Well we'll wait here until you right your own implementation. How long
    do you think that will take?
    markspace, Mar 11, 2012
    #8
  9. Jan Burse

    Jan Burse Guest

    markspace schrieb:
    >
    > Well we'll wait here until you right your own
    > implementation. How long do you think that will take?


    given the fact that Java appeared already in 1995
    and that tons of developers were involved with
    it, its a real schame how poor it still is.

    *fcuk*
    Jan Burse, Mar 12, 2012
    #9
  10. Jan Burse

    Lew Guest

    Jan Burse wrote:
    > given the fact that Java appeared already in 1995
    > and that tons of developers were involved with
    > it, its a real schame how poor it still is.
    >
    > *fcuk*


    The usual whinge of someone whose personal favorite feature didn't make it
    into Java, irrespective of whether such personal favorite feature is feasible,
    consistent with Java's mission, or useful to anyone else besides himself.

    On an objective basis, your statement is nonsense. On a subjective basis, poor
    you.

    --
    Lew
    Honi soit qui mal y pense.
    http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
    Lew, Mar 12, 2012
    #10
  11. On 03/12/2012 10:58 AM, Jan Burse wrote:
    > markspace schrieb:
    >>
    >> Well we'll wait here until you right your own
    > > implementation. How long do you think that will take?

    >
    > given the fact that Java appeared already in 1995
    > and that tons of developers were involved with
    > it, its a real schame how poor it still is.
    >
    > *fcuk*
    >


    Given the fact that tons of developers have consistently chosen
    differently since 1995, it is very likely that your view on this is flawed.
    Silvio Bierman, Mar 12, 2012
    #11
  12. Jan Burse

    Arne Vajhøj Guest

    On 3/12/2012 5:58 AM, Jan Burse wrote:
    > markspace schrieb:
    >>
    >> Well we'll wait here until you right your own
    >> implementation. How long do you think that will take?

    >
    > given the fact that Java appeared already in 1995
    > and that tons of developers were involved with
    > it, its a real schame how poor it still is.
    >
    > *fcuk*


    Actually Java first went GA in January 1996.

    And I think works fine or what it was intended for - and
    in fact way beyond that.

    If a developer chose Java for a task that Java was not designed
    for and has never been prioritized since, then it is the
    developers faults not Java's fault.

    Arne
    Arne Vajhøj, Mar 12, 2012
    #12
  13. Jan Burse

    Jan Burse Guest

    Arne Vajhøj schrieb:
    > If a developer chose Java for a task that Java was not designed
    > for and has never been prioritized since, then it is the
    > developers faults not Java's fault.


    Here is an example (although quite an artifical one)
    which shows how this flaw can harm the end-user. Consider
    this naive code:


    System.out.println("Do you want commit/rollback? (^D or ^Z/Enter)");
    String str=br.readLine();
    if (str=null) {
    commitTransaction();
    } else if ("".equals(str)) {
    rollbackTransaction();
    }

    Now what do you expect a program to do after the prompt:

    Do you want commit/rollback? (^D or ^Z/Enter)

    When the end-user presses ^C. Here is what happens on
    the different platforms because of this flaw:

    Mac or Linux: Upon pressing ^C the standard interrupt
    handler will be invoked, which calls System.exit(),
    neither commit nor rollback is issued, depending
    on the database most likely the System.exit() will
    do a rollback.

    Windows: A race condition is induced. Upon pressing
    ^C two things will happen: The readLine() will
    return null and in the same time the standard
    interrupt handler will be invoked. If the System.exit()
    and its shutdown handlers are slow it might be
    very well that a commit happens.

    So this is something I called fucked up. If I have time
    I will try to file a bug, if there isn't yet one. Filing
    a bug should be easy since "GetLastError returns
    ERROR_OPERATION_ABORTED" is well documented by MS.

    Best Regards

    P.S.: I did some measurements. It appears that usually
    the readLine() returns before that the INT handler gets
    invoiked. The delay is about ~1ms. One can easily
    measure it with the new System.nanoTime().

    P.S.S.: Therefore I adopetd the workaround of Gabriel
    Genellina with a timeout of around 10ms. But this
    design is also flawed, it might provoke an unrecognized
    EOF. But it is better than nothing...
    Jan Burse, Mar 12, 2012
    #13
  14. Jan Burse

    Jan Burse Guest

    Silvio Bierman schrieb:
    > Given the fact that tons of developers have consistently chosen
    > differently since 1995, it is very likely that your view on this is flawed.


    I guess your are subject to the same brainwash like
    the subjects in "The Emperor's New Clothes". I even
    don't feel pitty for you.
    Jan Burse, Mar 12, 2012
    #14
  15. Jan Burse

    Jan Burse Guest

    Lew schrieb:
    > On an objective basis, your statement is nonsense. On a subjective
    > basis, poor you.


    Personal or not. Face it, the Java library hasn't
    much evolved since 1995. I am not talking about the
    Java language, the Java language itself did a
    tremendous development, we have Generics and super
    cool good performant 64-bit JITs.

    But the platform support for Windows hasn't evolved
    since much. The NIO is kind of a joke, concerning
    interrupts, all it can give you is ClosedByInterrupt-
    Exception but not a clean InterruptedIOException.
    And ClosedByInterruptException doesn't even work
    for "CON" on Windows.

    But its no wonder, since Windows boycotted Java and
    did his own thing with CLR etc.. Why should they
    care about have a good library for Windows. In the
    end we as end-users are the victims of this commercial
    struggle. *fcuk*

    Bye
    Jan Burse, Mar 12, 2012
    #15
  16. Jan Burse

    Jan Burse Guest

    Leif Roar Moldskred schrieb:
    > Oh _come on_! If you insist on writing a console-based interactive
    > program in Java, at least have enough common sense to not choose
    > control codes for the expected user input.


    I didn't choose control codes.

    I chose end-of-file of a stream. Which is on a windows
    console ^Z and in Mac or Linux ^D. But this is only the
    most common default, it could be also other key combinations,
    and I guess it can be configured in some console utilities.

    And its very common that programs assume that everything is
    fine when a end-of-file is encountered, and that they then
    commit their work. This is the sunshine case.

    Bye
    Jan Burse, Mar 12, 2012
    #16
  17. On 3/12/2012 3:43 PM, Jan Burse wrote:
    > Lew schrieb:
    >> On an objective basis, your statement is nonsense. On a subjective
    >> basis, poor you.

    >
    > Personal or not. Face it, the Java library hasn't
    > much evolved since 1995.


    Not true.

    It has grown a lot. By more than a factor 10.

    And Java is still first GA in January 1996 not 1995.

    > I am not talking about the
    > Java language, the Java language itself did a
    > tremendous development, we have Generics and super
    > cool good performant 64-bit JITs.


    JIT's are not part of the Java language.

    > But the platform support for Windows hasn't evolved
    > since much.


    Not much.

    But that is by design.

    Java is supposed to be portable.

    Support for very OS specific features and being
    portable does not go very well together.

    If you need the fine control over stuff like
    this then pick a language that has prioritized
    low level OS integration over portability.

    > But its no wonder, since Windows boycotted Java and
    > did his own thing with CLR etc.. Why should they
    > care about have a good library for Windows. In the
    > end we as end-users are the victims of this commercial
    > struggle. *fcuk*


    ..NET does offer more low level features than Java, but
    also in .NET sometimes the answer is to go back to
    native C/C++ code.

    Arne
    Arne Vajhøj, Mar 12, 2012
    #17
  18. Jan Burse

    Arne Vajhøj Guest

    On 3/12/2012 3:16 PM, Jan Burse wrote:
    > Arne Vajhøj schrieb:
    >> If a developer chose Java for a task that Java was not designed
    >> for and has never been prioritized since, then it is the
    >> developers faults not Java's fault.

    >
    > Here is an example (although quite an artifical one)
    > which shows how this flaw can harm the end-user. Consider
    > this naive code:
    >
    >
    > System.out.println("Do you want commit/rollback? (^D or ^Z/Enter)");
    > String str=br.readLine();
    > if (str=null) {
    > commitTransaction();
    > } else if ("".equals(str)) {
    > rollbackTransaction();
    > }
    >
    > Now what do you expect a program to do after the prompt:
    >
    > Do you want commit/rollback? (^D or ^Z/Enter)
    >
    > When the end-user presses ^C. Here is what happens on
    > the different platforms because of this flaw:
    >
    > Mac or Linux: Upon pressing ^C the standard interrupt
    > handler will be invoked, which calls System.exit(),
    > neither commit nor rollback is issued, depending
    > on the database most likely the System.exit() will
    > do a rollback.
    >
    > Windows: A race condition is induced. Upon pressing
    > ^C two things will happen: The readLine() will
    > return null and in the same time the standard
    > interrupt handler will be invoked. If the System.exit()
    > and its shutdown handlers are slow it might be
    > very well that a commit happens.


    But the entire code is bad.

    CTRL/D or CTRL/Z are not portable (I am pretty sure that
    an EBCDIC based system does not have such).

    CTRL/C is not portable either.

    Considering EOF key (if such exist on the platform)
    to mean commit and return to mean rollback and all other
    to mean neither is very bad code.

    And no finally block.

    How can you expect that 2 x platform specific features +
    2 x bad coding practices could result in reliable cross
    platform code????

    Arne
    Arne Vajhøj, Mar 12, 2012
    #18
  19. On 3/12/2012 3:46 PM, Jan Burse wrote:
    > Leif Roar Moldskred schrieb:
    >> Oh _come on_! If you insist on writing a console-based interactive
    >> program in Java, at least have enough common sense to not choose
    >> control codes for the expected user input.

    >
    > I didn't choose control codes.
    >
    > I chose end-of-file of a stream. Which is on a windows
    > console ^Z and in Mac or Linux ^D.


    There are other platforms as well.

    > And its very common that programs assume that everything is
    > fine when a end-of-file is encountered, and that they then
    > commit their work.


    I don't think CTRL/Z or CTRL/D is that common to mean
    commit changes in console apps.

    Arne
    Arne Vajhøj, Mar 12, 2012
    #19
  20. Jan Burse

    Jan Burse Guest

    Arne Vajhøj schrieb:
    >
    > CTRL/D or CTRL/Z are not portable (I am pretty sure that
    > an EBCDIC based system does not have such).


    Do you see some Ctrl-D or Ctrl-Z in my code? Except
    as explanatory in a prompt?

    > CTRL/C is not portable either.


    Do you see some Ctrl-C in my code?

    But SIGINT is widely supported, even on:
    - z/OS
    - AIX

    http://www.ibm.com/developerworks/java/library/i-signalhandling/

    Whether you issue it via Ctrl-C, or some kill don't
    know what in a separate process doesn't matter.

    Here is a reminder for you: The posed problem is as follows

    IF sigint is supported THEN how sould
    FileInputStream(FileDescriptor.in) behave?

    I don't care about those platforms where there is no sigint.
    The problem is then automatically resolved. The IF THEN
    is trivially true.

    Bye
    Jan Burse, Mar 12, 2012
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jon Maz
    Replies:
    3
    Views:
    7,519
    Jon Maz
    Oct 20, 2004
  2. Shapper
    Replies:
    1
    Views:
    354
    Craig Deelsnyder
    Jun 19, 2005
  3. Simon Willison
    Replies:
    1
    Views:
    814
    poiboy
    Aug 28, 2003
  4. Kobu
    Replies:
    10
    Views:
    604
    Keith Thompson
    Mar 4, 2005
  5. SpreadTooThin

    ifstream eof not reporting eof?

    SpreadTooThin, Jun 13, 2007, in forum: C++
    Replies:
    10
    Views:
    675
    James Kanze
    Jun 15, 2007
Loading...

Share This Page