Thread: ctrl+z

  1. #1
    Registered User Noir's Avatar
    Join Date
    Mar 2007
    Posts
    218

    ctrl+z

    I have a little getline function that works okay unless there's a ctrl+z in the stream. Here's some code:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    
    /* return true:
         the string is empty due to hitting a delimiter right away
         the string is not empty
       return false:
         the string is empty due to eof or a stream error */
    int getline( char *string, int size, char delimiter ) {
      int i = 0;
      int c;
    
      if ( size > 0 ) {
        // stop reading at size, eof, or a delimiter
        while ( --size > 0
          && ( c = getchar() ) != EOF
          && ( string[i++] = c ) != delimiter );
    
        // trim the delimiter if it's there and end the string
        string[i - ( i && string[i - 1] == delimiter )] = '\0';
    
        // clear the stream  up to the next delimiter
        while ( stdin->_cnt > 0
          && !ferror( stdin )
          && ( c = getchar() ) != EOF
          && c != delimiter );
      }
    
      return i != 0;
    }
    
    
    int main( void ) {
      char array[5];
    
      while ( 1 ) {
        int rc = getline( array, 5, '\n' );
        printf( "%d: %s\n", rc, array );
      }
    
      return 0;
    }
    If I type "abcd^Z" it works. If I type "abc^Z", it doesn't see the eof and puts ascii 26 as the last character. I can check for ascii 26, but that's kludgy. Can somebody suggest something better?

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > stdin->_cnt > 0
    Why do you have this - it isn't portable.

    The recognition of ctrl-z as signalling EOF only happens at the start of the line.
    At other points, I see a multitude of interesting effects.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User Noir's Avatar
    Join Date
    Mar 2007
    Posts
    218
    > stdin->_cnt > 0
    Why do you have this - it isn't portable.
    What I'm trying to do isn't portable either.
    The recognition of ctrl-z as signalling EOF only happens at the start of the line.
    At other points, I see a multitude of interesting effects.
    The only way around it I can think of is conditional compiling if eof comes from ctrl+z...
    Code:
        // stop reading at size, eof, or a delimiter
        while ( --size > 0
          && ( c = getchar() ) != EOF
    #ifdef EOF_CTRLZ
          && c != 26
    #endif
          && ( string[i++] = c ) != delimiter );
    But I don't like it. There has to be a better way that I'm not smart enough to see.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Well I've tried it with cygwin and vc6, and neither of those seem to be returning the literal value of ctrl-z in the input buffer.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    I'd be surprised if any of them do. Ctrl+Z or ctrl+D is just what the shell / console uses as EOF, not your actual program. As far as I'm aware, all it just passes EOF to them, not the ctrl+value.

    Quzah.
    Hope is the first step on the road to disappointment.

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    EOF has to be represented by something, quzah. Under several flavours of unix, a CTRL-D (ASCII value 4) encountered in a file stream is taken to be an indicator of end of file; when C standard I/O functions such as fgetc() encounter a CTRL-D character in a stream they return EOF. Similarly, under windows, a CTRL-Z (ASCII value 26) is treated as an EOF marker. If you look at the workings of some file systems, a CTRL-D or CTRL-Z character (or a set of two or more such characters) is actually written to disk to mark the end of the file on disk.

  7. #7
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by grumpy
    EOF has to be represented by something, quzah.
    Naturally. It's represented as EOF.
    Quote Originally Posted by grumpy
    Under several flavours of unix, a CTRL-D (ASCII value 4) encountered in a file stream is taken to be an indicator of end of file; when C standard I/O functions such as fgetc() encounter a CTRL-D character in a stream they return EOF.
    Which clearly is wrong when compared to what EOF is by definition: negative.
    Quote Originally Posted by grumpy
    Similarly, under windows, a CTRL-Z (ASCII value 26) is treated as an EOF marker. If you look at the workings of some file systems, a CTRL-D or CTRL-Z character (or a set of two or more such characters) is actually written to disk to mark the end of the file on disk.
    And again. EOF cannot be represented in a char. Therefore, it should never ever be represented as a positive value, because that is 180 degrees of what the standard says it is. It's negative. Always.


    Quzah.
    Hope is the first step on the road to disappointment.

  8. #8
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    You missed the point, quzah. When CTRL-D and CTRL-Z characters (or other ones, depending on OS) occur in a file or stream they are taken as markers indicating end of that file (or a stream). When functions like fgetc() (or OS-specific functions that might be called to implement fgetc()) encounter those markers, fgetc() will return EOF. In other words, the implementation of functions like fgetc() will include logic that yields behaviour functionally equivalent to;
    Code:
        if (character_read_from_stream == 4)    /*  unix behaviour: detect CTRL-D in stream */
            return EOF;
    That is not wrong according to the standard: the C standard does not mandate how files are laid out on a disk or other hardware. It only requires that an end-of-file be detected, and that EOF be returned by C I/O functions when it is.

    There is also no actual requirement in the C standard that EOF be a negative value. The actual requirement is that EOF be an integral value that cannot be stored in an unsigned char. A negative value is one possibility. A large positive value (which exceeds the maximum value that can be stored in an unsigned char) is another.

  9. #9
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    No, it is a part of the standard that it must be negative:
    Quote Originally Posted by The Standard, 7.19.1
    EOF
    which expands to an integer constant expression, with type int and a negative value, that
    is returned by several functions to indicate end-of-file, that is, no more input from a
    stream;
    Anyway, the control characters are usually read as two keys, not one. But it seems to me that it's entirely up to your shell what key you hit to be EOF. So, it should be that it just sends EOF directly to the program, not the control key sequence. Maybe not, but that's how it seems like it should work to me.


    Quzah.
    Last edited by quzah; 03-25-2007 at 03:32 AM.
    Hope is the first step on the road to disappointment.

  10. #10
    Its hard... But im here swgh's Avatar
    Join Date
    Apr 2005
    Location
    England
    Posts
    1,688
    It is strange that some texts I have read state that using EOF is considered poor practice, and others say it can be used in exceptional circumstances. Personally, I rarely use it, only really had to once when creating a grade book class for an assignment. Didn't work properly anyway. But I suppose everybody has a use for a function where others will always differ, All parts of the language where designed to do somthing.

    Just my two cents.
    Double Helix STL

  11. #11
    Registered User Noir's Avatar
    Join Date
    Mar 2007
    Posts
    218
    I fixed that with a macro. It's not pretty, but it works for me. I can't test it on places that don't use ctrl+z for eof though. A friend also told me that it didn't work on his compiler because of the 'stdin->_cnt' part. He uses a borland compiler, so I guess whoever told me that _cnt is used everywhere was wrong. I fixed that too, but I'm not sure it's a good fix but it's portable now. You guys were kind enough to help me out before, can you give me a code review?
    Code:
    #include <stdio.h>
    #include <string.h>
    
    
    // remove this behavior with EOF instead of 26
    #define EOF_CTRLZ 26
    
    
    /* return true:
         the string is empty due to hitting a delimiter right away
         the string is not empty
       return false:
         the string is empty due to eof or a stream error */
    int getline( char *string, int size, char delimiter ) {
      int rc = 0;
    
      if ( size > 0 ) {
        int c = delimiter;
        int i = 0;
    
        // stop reading at size - 1, eof, or a delimiter
        while ( --size > 0
          && ( c = getchar() ) != EOF
          && c != EOF_CTRLZ
          && c != delimiter ) {
    
          string[i++] = c;
        }
    
        string[i] = '\0';
        rc = i > 0 || c == delimiter;
    
        if ( size ) {
          // force some input so clearing doesn't block
          ungetc( delimiter, stdin );
        }
    
        // clear up to eof or the next delimiter
        while ( !ferror( stdin )
          && ( c = getchar() ) != EOF
          && c != EOF_CTRLZ
          && c != delimiter );
      }
    
      return rc;
    }
    
    
    int main( void ) {
      char array[5];
    
      while ( 1 ) {
        int rc = getline( array, 5, '\n' );
        printf( "%d: %s\n", rc, array );
      }
    
      return 0;
    }

  12. #12
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Correct, Borland uses a really weird File struct. Instead of _cnt it's level.... Weird.

  13. #13
    Registered User Noir's Avatar
    Join Date
    Mar 2007
    Posts
    218
    Yeah, weird. I wonder how many other compilers are weird.

  14. #14
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Well FILE is supposed to be an opaque type, all you ever need worry about is storing a FILE* and passing it to routines which need it. Every single implementation is free to define members of that struct (assuming it is even a struct) as it sees fit. It's only because some things like getc() can be a macro that you can see inside it at all.

    Taking sneak peeks at the innards is just asking for trouble.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  15. #15
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396

    Don't use text mode

    Holy cow people, why not just switch the file to binary mode? It's stdin, right?

    Code:
    freopen(NULL, "rb", stdin);
    Now the Ctrl-Z will come through always, and you can process it how you want.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 0
    Last Post: 07-02-2007, 12:32 AM
  2. how to capture CTRL, SHIFT and ALT ?
    By goldenrock in forum C Programming
    Replies: 3
    Last Post: 11-06-2003, 01:20 AM
  3. Trapping Ctrl Alt Delete
    By emus21 in forum A Brief History of Cprogramming.com
    Replies: 14
    Last Post: 09-17-2003, 12:10 PM
  4. Recognizing ALT or Ctrl + letter
    By MethodMan in forum C Programming
    Replies: 2
    Last Post: 02-22-2003, 07:16 PM
  5. Ctrl + Alt +Delete
    By golfinguy4 in forum Windows Programming
    Replies: 4
    Last Post: 10-27-2002, 07:46 PM