Setting position indicators in Streams

This is a discussion on Setting position indicators in Streams within the C Programming forums, part of the General Programming Boards category; Hello all, I need to be able to seek through a stream. This is a non-file stream, created by a ...

  1. #1
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591

    Setting position indicators in Streams

    Hello all, I need to be able to seek through a stream. This is a non-file stream, created by a pipe between my program and a subprogram, more specifically, created by the "popen()" function. Seeking position markers in a file stream is pretty easy, but it does not seem to be as straightforward with this kind of stream.
    So far, I have tried the rewind() and fseek() functions, but these do not work (the first character scanned after a call to rewind() should be the first character in the stream again, but instead results in a EOF (and I know the stream was not empty)).
    Is there something else I need to be doing, or are these types of streams (ones created by popen()) un-seekable?
    Thanks for any help.

    Here is a sample of the code I am using:
    Code:
    int
    main(void)
    {
    	int num_lines;
    	FILE *streamp;
    
    	streamp = popen(COMMAND, "r");
    
           //pass stream onto function
    	num_lines = get_num_lines(streamp);
    
           //prints "10" in the specific case I am using, so I know stream is not empty.
           printf("%d", num_lines);
    
           //RESET marker to beginning of stream (I had hoped)
           rewind(streamp);
    
           //instead this indicated that the marker was still at the end of the stream
    	if( fgetc(streamp) == EOF)
                 printf("END");
    }
    
    int
    get_num_lines(FILE *streamp)
    {
    	int num_lines = 0;
    	char ch, prev = NEWLINE;
    
    	while((ch = fgetc(streamp)) != EOF)
    	{
    		if(ch == NEWLINE)
    		{
    			++num_lines;
    		}
    
    		prev = ch;
    	}
    
    	if(prev != NEWLINE)
    	{
    		++num_lines;
    	}
    
    	return(num_lines);
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,849
    You can't seek on a pipe (at all, in either direction).

    Check the value of errno
    Code:
    RETURN VALUE
           The rewind function returns no value.  Upon successful completion, fgetpos, fseek, fsetpos
           return  0, and ftell returns the current offset.  Otherwise, -1 is returned and the global
           variable errno is set to indicate the error.
    
    ERRORS
           EBADF  The stream specified is not a seekable stream.
    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.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  3. #3
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    Okay, so the return value for this call to fseek(streamp, 0L, SEEK_SET) is 0, and the return value for ftell(streamp) is 0.... which is odd ...
    According to the return values, the fseek function completed successfully and the new position should be back at the start (0)... however when I start reading from this position, the first char is EOF (and not the first char I read initally before coming to the end of the stream).
    Also, excuse my newbieness, but how do I check the "global variable errno" for the EBADF error number??

  4. #4
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,175
    Just #include <errno.h> and then after attemping fseek() check if(errno == EBADF)

    But it doesn't really matter because errno is only set when fseek() fails.

    Example:
    Code:
    {
      if(fseek(fp, 0L, SEEK_SET) == -1)
        if(errno == EBADF)
          // blah
    }
    If you understand what you're doing, you're not learning anything.

  5. #5
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    There seems to be a contradiction here:
    If pipe streams are not seekable, and a non-seekable stream passed to fseek will return a -1 (error), then why am I getting a return value of 0 (which implies the stream is seekable).
    And if pipe streams are seekable, and I set the position marker to the begining of the text, then why does a subsequent call to fgetc not return the first character on the stream, instead returning an EOF (indicating the marker is unchanged and still at the end of the stream).
    Something is amiss somewhere...

  6. #6
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,175
    I'm not seeing where you're checking the return value of fseek() in your code.
    If you understand what you're doing, you're not learning anything.

  7. #7
    Registered User
    Join Date
    Jan 2005
    Posts
    204
    Code:
    int
    get_num_lines(FILE *streamp)
    {
    	int num_lines = 0;
    	char ch, prev = NEWLINE;
    
    	while((ch = fgetc(streamp)) != EOF)
    	{
    		if(ch == NEWLINE)
    		{
    			++num_lines;
    		}
    
    		prev = ch;
    	}
    
    	if(prev != NEWLINE)
    	{
    		++num_lines;
    	}
    
    	return(num_lines);
    }
    Also, ch should be declared as int.

  8. #8
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    Quote Originally Posted by itsme86
    I'm not seeing where you're checking the return value of fseek() in your code.
    yea, sorry about that, I put that check in after the original post, just a simple printf check:
    printf("%d", fseek(streamp, 0L, SEEK_SET));
    Which printed "0", indicating it returned without error and the new position should be 0 (implies stream is seekable...)
    Then I used:
    printf("%d", ftell(streamp));
    which printed "0", to indicate that the new position is back at the beginning of the stream (once again, implying the stream was successfully sought through).
    However, the "fgetc == EOF" check passed, indicating the first character of the stream (position 0) was an EOF, which cannot at all be possible since the stream was definately not empty on the first pass through it.
    The return values seem to be directly conflicting with what actually happens: on one hand, fseek elludes that it IS seekable, on the other, the first char after a seek still being an EOF elludes that it is NOT seekable (or has not been sought through correctly, though I only know of one way to seek through a stream correctly, and I believe I have used it, no?)

    Note: To be more specific, the stream I am referring to is created by a popen() call using the "dir /b" command, so the stream is pretty standard and is of the form:
    "file1.ext\nfile2.ext\nfile3.ext..."

    I've tailored the code so you can copy/paste/compile and try it directly:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define COMMAND "dir /b" /* unix users: ls -l */
    #define NEWLINE '\n'
    
    int
    get_num_lines(FILE *streamp);
    
    int
    main(void)
    {
    	int num_lines;
    	FILE *streamp;
    
    	/* creates stream via pipe from subprocess output */
    	streamp = popen(COMMAND, "r");
    
    	num_lines = get_num_lines(streamp);
    	
    	/* prints number of lines in stream */
    	printf("%d", num_lines);
    
    	/* return stream position marker to beginning of stream */
    	/* a printing of 0 ensures that this has been done successfully */
    	printf("\n%d", fseek(streamp, 0L, SEEK_SET));
    
    	/* display the current postion, should be 0 if 0 was printed in the previous printf */
    	printf("\n%d", ftell(streamp));
    
    	/* if EOF is displayed, position is at EOF */
    	/* indicating fseek and ftell have FALSIFIED return values */
    	if(fgetc(streamp) == EOF) printf("\nEOF");
    
    	getch();
    	pclose(streamp);
    }
    
    int
    get_num_lines(FILE *streamp)
    {
    	int num_lines = 0;
    	char ch, prev = NEWLINE;
    
    	while((ch = fgetc(streamp)) != EOF)
    	{
    		if(ch == NEWLINE)
    		{
    			++num_lines;
    		}
    
    		prev = ch;
    	}
    
    	if(prev != NEWLINE)
    	{
    		++num_lines;
    	}
    
    	return(num_lines);
    }
    Also, caduardo21, is there any specific reason for using an int over a char variable? is it because of the comparison with the int EOF?

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    204
    The reason is that EOF does not fit in a char variable. How would we distinguish a real character from end-of-file if it did?

  10. #10
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    nm, I stand corrected
    Last edited by @nthony; 07-02-2006 at 11:19 PM.

  11. #11
    Devil's Advocate SlyMaelstrom's Avatar
    Join Date
    May 2004
    Location
    Out of scope
    Posts
    4,077
    Quote Originally Posted by @nthony
    huh?
    EOF is an integer, integers "fit" in char variables and vice versa. You distinguish a real character from EOF because real characters are positive integers (with the exception of some non-alphanumeric characters), EOF tends to be negative. Infact, so long as you don't use character-specific representions such as "%c" in a printf statement, a character is almost undistinguishable from an integer.
    But, alas, this is what I've *learned*, so correct me if I'm wrong of course....
    You're wrong. Characters may fit in integers but that doesn't mean integers fit in characters. That's like saying, people fit in a car there for cars fit in people. One is significantly larger than the other in memory. A char is a single byte. That's 256 possible values. All of which have predefined ascii values, none of which are EOF. The FAQ gives a good explaination on EOF.

    http://faq.cprogramming.com/cgi-bin/...&id=1043284351
    Sent from my iPadŽ

  12. #12
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    and now i finally know exactly what an EOF is, thanks!

    Any solutions to the initial problem...
    if all three calls to the fseek, ftell, and printf functions are correct, then that means there is a discrepency in the fseek and ftell functions in the stdio library, which probably should be reported to.... uh... whoever you report standard C library bugs to...

  13. #13
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
    #include<stdio.h>
    
    int main( void )
    {
        int t, s;
        t = ftell( stdin );
        s = fseek( stdin, 0L, SEEK_SET );
        
        printf("t is %d, s is %d\n", t, s );
        
        return 0;
    }
    
    /*
    t is -1, s is -1
    */
    You're on crack.


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

  14. #14
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    ... except I'm not using a stdin stream, try my example above or this simplier test below, and then let me know what values you get:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int
    main(void)
    {
            int ch;
            /* change as apporpiate to system */
    	FILE *streamp = popen("dir /b", "r");
    
    	/* print characters in stream */
    	/* shows that stream is not empty */
    	while((ch=fgetc(streamp)) != EOF)
    		printf("%c", ch);
    	
    	/* check status of stream */	
    	printf("\nEOF?: %d", feof(streamp));
    	
    	/* reset position marker */
    	printf("\nfseek succeed?: %d", fseek(streamp, 0, SEEK_SET));
    	printf("\nPosition?: %d", ftell(streamp));
    	printf("\nError?: %d", ferror(streamp));
    	printf("\nEOF?: %d\n", feof(streamp));
    
    	getch();
    	
    	/* if zero's above, this should fail */	
    	if((ch=fgetc(streamp)) == EOF)
    		printf("STILL @ EOF", ch);
    }

  15. #15
    Devil's Advocate SlyMaelstrom's Avatar
    Join Date
    May 2004
    Location
    Out of scope
    Posts
    4,077
    All input is to stdin unless it's from a text file in which case, Quzah's example is still correct. You should really look up stdin if you don't know what it is.
    Last edited by SlyMaelstrom; 07-04-2006 at 04:24 AM.
    Sent from my iPadŽ

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. setting cursor position
    By scrasnu in forum C Programming
    Replies: 1
    Last Post: 10-04-2008, 11:28 AM
  2. Button handler
    By Nephiroth in forum Windows Programming
    Replies: 8
    Last Post: 03-12-2006, 06:23 AM
  3. Problem with linked list ADT and incomplete structure
    By prawntoast in forum C Programming
    Replies: 1
    Last Post: 04-30-2005, 02:29 AM
  4. Setting text cursor position inside edit
    By Rutabega in forum Windows Programming
    Replies: 2
    Last Post: 07-15-2004, 09:39 AM
  5. setting Cursor Position in C???
    By librab103 in forum C Programming
    Replies: 2
    Last Post: 07-26-2003, 03:54 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21