maslar@iccgcc.decnet.ab.com (05/07/91)
Does anyone know of a function or technique that is similar to FSEEK that will allow me to go back to the previous line? The lines of ASCII text are being read from a file by the FGETS function. The length of the lines varies. I'm writing an application-specific file reader, and need to implement a PageUp and UpArrow feature. Thanks, Mark Maslar INTERNET: maslar@icd.ab.com
henry@zoo.toronto.edu (Henry Spencer) (05/08/91)
In article <4508.28269613@iccgcc.decnet.ab.com> maslar@iccgcc.decnet.ab.com writes: >Does anyone know of a function or technique that is similar to FSEEK >that will allow me to go back to the previous line? ... There is no provision for this in the standard libraries, because it can be arbitrarily hard to implement on systems that store text files in odd ways. You can build it yourself, however, by simply using ftell() to keep track of the location of the previous line, and fseek()ing there on demand. -- And the bean-counter replied, | Henry Spencer @ U of Toronto Zoology "beans are more important". | henry@zoo.toronto.edu utzoo!henry
wirzeniu@kruuna.Helsinki.FI (Lars Wirzenius) (05/09/91)
In article <4508.28269613@iccgcc.decnet.ab.com> maslar@iccgcc.decnet.ab.com writes: >Does anyone know of a function or technique that is similar to FSEEK >that will allow me to go back to the previous line? You can do two things: 1) save all the previous text in a buffer in the memory, or 2) save the positions of the starts of the lines in memory. The former method requires plenty of memory (at least as much as the file size), so it's probably not a very good idea. The latter method requires you to call ftell at the start of each line and store the value in an array, something like: long line_starts[MAX_LINES]; /* ... */ lines_starts[line_no] = ftell(input_file); /* read the line */ /* ... */ Note that you can't assume that the value returned by ftell is in any way related to the number of characters on the line, so you can't just do fseek(f, -linelen, SEEK_CUR), well, at least not portably. You might have a problem if the input isn't coming from a file that is seekable, e.g. pipes and terminals aren't. In this case you could save the input in a temporary file, and fseek that instead. You might want to look at the source of less, which implements these kinds of things. -- Lars Wirzenius wirzenius@cc.helsinki.fi
martin@mwtech.UUCP (Martin Weitzel) (05/09/91)
In article <1991May8.154638.21318@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >In article <4508.28269613@iccgcc.decnet.ab.com> maslar@iccgcc.decnet.ab.com writes: >>Does anyone know of a function or technique that is similar to FSEEK >>that will allow me to go back to the previous line? ... > >There is no provision for this in the standard libraries, because it can >be arbitrarily hard to implement on systems that store text files in odd >ways. You can build it yourself, however, by simply using ftell() to keep >track of the location of the previous line, and fseek()ing there on demand. Which brings us to the Question: What is more portable in ANSI-C - ftell()/fseek() or fgetpos()/fsetpos(). As I understand, the former has some limitations if "really large" files must be processed. On the other hand it has the advantage that at least on binary streams you can calculate the number of bytes to skip forward or backward from a known place. Since this ability is not needed here (nor is it guaranteed for text files), I think fgetpos()/fsetpos() is the way to go (provided the compiler of the person who posted the original question is ANSI-ish enough to have these functions). -- Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83
toma@swsrv1.cirr.com (Tom Armistead) (05/11/91)
In article <4508.28269613@iccgcc.decnet.ab.com> maslar@iccgcc.decnet.ab.com writes: > >Does anyone know of a function or technique that is similar to FSEEK >that will allow me to go back to the previous line? The lines of >ASCII text are being read from a file by the FGETS function. The >length of the lines varies. I'm writing an application-specific >file reader, and need to implement a PageUp and UpArrow feature. > >Thanks, > >Mark Maslar > >INTERNET: maslar@icd.ab.com In a text file, you can generally assume that the lines will have a max length of BUFSIZ. So, you could seek backward BUFSIZ*2 bytes, read the number of bytes that were backward seeked and search from the end of that buffer, backward until you find a the \n prior to the previous line. Or you could fseek back one character at a time, read that character and look for '\n's. Either way is going to be fairly slow (the second option will be REAL slow). I did this once using the 1st method, like this: /*===========================================================================*/ #include <stdio.h> /* ** Seek back 1 line in the text file associated with the passed fp. ** Returns 0 on success, or -1 on error (probally because positioned at 1st ** line in file). */ int backup_one_line( fp ) FILE *fp; { char buf[BUFSIZ*2]; /* buffer for fread */ long posn; /* ftell() position */ int backup_ofs; /* distance arg to fseek */ int indx; /* index into buf[] */ int ret=-1; /* function return; assume error */ int lf_cnt = 0; /* line feed character counter */ posn = ftell( fp ); /* get current position in file */ /************************************************************************* ** If not far enough down in the file to read the the entire buffer size, ** then read all of the file up to the current point. **************************************************************************/ if( posn <= (long)sizeof( buf ) ) backup_ofs = posn; else /* else read entire buffer from file */ backup_ofs = sizeof( buf ); fseek( fp, (long)-backup_ofs, 1 ); /* backup size of buffer */ fread( buf, backup_ofs, 1, fp ); /* read buffer into memory */ /************************************************************************* ** Search backward from the end of the buffer to the 3rd \n character. ** 1st one is for end of current line, 2nd is for end of previous ** line and 3rd is for 1 character before previous line. **************************************************************************/ for( indx=backup_ofs-1; indx > 0; indx-- ) if( buf[indx] == '\n' && ++lf_cnt == 3 ) /* count \n's */ break; /* leave on 3rd one */ if( indx > 0 ) /* if 3rd linefeed back found */ { ret = 0; /* signify success */ posn = (backup_ofs - indx - 1); /* position to start of prev line */ fseek( fp, -posn, 1 ); /* position there */ } else if( indx == 0 && lf_cnt == 2 ) /* else, prev line is 1st in file */ { ret = 0; /* signify success */ fseek( fp, 0, 0 ); /* move to start of file */ } /************************************************************************* ** Else positioned at 1st line in file (can't go back) or was unable to ** find \n line separators. **************************************************************************/ else fseek( fp, posn, 0 ); /* position back to original pos'n */ return ret; }/*end backup_one_line*/ /*===========================================================================*/ Tom -- Tom Armistead - Software Services - 2918 Dukeswood Dr. - Garland, Tx 75040 =========================================================================== toma@swsrv1.cirr.com {egsner,letni,ozdaltx,void}!swsrv1!toma
wirzeniu@klaava.Helsinki.FI (Lars Wirzenius) (05/11/91)
In article <1991May11.063436.18318@swsrv1.cirr.com> toma@swsrv1.cirr.com (Tom Armistead) writes: >In a text file, you can generally assume that the lines will have a max length >of BUFSIZ. So, you could seek backward BUFSIZ*2 bytes, read the number of Unless I'm very much mistaken, as far as text streams are concerned, you can't portably hand fseek any other values than 0 and those earlier returned by ftell. You can't do 'fseek(f, -BUFSIZ, SEEK_CUR)', since the values returned by ftell are not guaranteed to be simple byte offsets (such offsets don't work very well for text files in all environments). -- Lars Wirzenius wirzenius@cc.helsinki.fi