How to FSEEK previous line of text?

Tom Armistead toma at swsrv1.cirr.com
Sat May 11 16:34:36 AEST 1991


In article <4508.28269613 at iccgcc.decnet.ab.com> maslar at 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 at 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 at swsrv1.cirr.com                {egsner,letni,ozdaltx,void}!swsrv1!toma



More information about the Comp.lang.c mailing list