hmmer-3.3/easel/esl_fileparser.c
/* Function:  esl_fileparser_NextLinePeeked()
 * Synopsis:  Read the next line, prepending a peek.
 * Incept:    SRE, Wed Oct 15 10:08:37 2008 [Janelia]
 *
 * Purpose:   Sometimes we need to peek at the start of an input stream
 *            to see whether it is in a binary format, before we start
 *            parsing it as ASCII lines. When this happens, the caller
 *            will typically have used <fread()> to read a fixed
 *            number of bytes from the input stream, checked to see if
 *            they are a magic number representing a binary format,
 *            and found that they are not. The caller then wants to
 *            switch to reading in ASCII format with the <fileparser>
 *            API, but with those bytes included on the first
 *            line. Because the file might start with comments or
 *            blank lines that need to be skipped, we want to deal
 *            with the peeked data in the context of the
 *            <ESL_FILEPARSER>. The caller cannot simply close and
 *            reopen the stream, because the stream may be a pipe
 *            (<stdin> or <gzip -dc> for example).
 *            
 *            The caller passes the bytes it peeked at with <fread()>
 *            in <prefix>, and the number of bytes it peeked at in
 *            <plen>.
 *            
 *            The parser is advanced to the next non-blank,
 *            non-comment data line that contains at least one token,
 *            taking the prepended <prefix> into account.
 *
 *            There is a significant flaw in this mechanism, and as a
 *            result the caller must be able to guarantee the
 *            following limitation. The first data-containing line
 *            must be longer than <prefix>. It is sufficient for the
 *            first data token to be longer than <prefix>.
 *            (Equivalently, if <prefix> contains any data token, it
 *            must not contain any newline \verb+\n+ after that data.)  The
 *            reason is that we need to avoid a situation where the
 *            concatenated prefix+nextline contains more than one data
 *            line, because other routines in the module assume that
 *            <efp->buf> is a single \verb+\n+-terminated line of input.  For
 *            example: HMMER save files either start with a 4-byte
 *            binary magic number, or with "HMMER", and "HMMER" is
 *            longer than 4 bytes.
 *
 * Args:      efp      - open fileparser
 *            prefix   - bytes that caller obtained by peeking with fread()
 *            plen     - number of bytes in prefix
 *
 * Returns:   <eslOK> on success.
 *            <eslEOF> if no more tokens remain in the file.  
 *
 * Throws:    <eslEMEM> on allocation error.
 *
 * Xref:      For an example, see HMMER's HMM save file input.
 */
esl_fileparser_NextLinePeeked()
Synopsis:  Read the next line, prepending a peek.

Sometimes we need to peek at the start of an input stream
to see whether it is in a binary format, before we start
parsing it as ASCII lines. When this happens, the caller
will typically have used  to read a fixed
number of bytes from the input stream, checked to see if
they are a magic number representing a binary format,
and found that they are not. The caller then wants to
switch to reading in ASCII format with the 
API, but with those bytes included on the first
line. Because the file might start with comments or
blank lines that need to be skipped, we want to deal
with the peeked data in the context of the
. The caller cannot simply close and
reopen the stream, because the stream may be a pipe
( or  for example).

The caller passes the bytes it peeked at with 
in , and the number of bytes it peeked at in
.

The parser is advanced to the next non-blank,
non-comment data line that contains at least one token,
taking the prepended  into account.

There is a significant flaw in this mechanism, and as a
result the caller must be able to guarantee the
following limitation. The first data-containing line
must be longer than . It is sufficient for the
first data token to be longer than .

efp      - open fileparser
prefix   - bytes that caller obtained by peeking with fread()
plen     - number of bytes in prefix

 on success.
 if no more tokens remain in the file.

 on allocation error.

For an example, see HMMER's HMM save file input.
esl_fileparser_NextLinePeeked () Synopsis : Read the next line prepending a peek . Sometimes we need to peek at the start of an input stream to see whether it is in a binary format before we start parsing it as ASCII lines . When this happens the caller will typically have used to read a fixed number of bytes from the input stream checked to see if they are a magic number representing a binary format and found that they are not . The caller then wants to switch to reading in ASCII format with the API but with those bytes included on the first line . Because the file might start with comments or blank lines that need to be skipped we want to deal with the peeked data in the context of the . The caller cannot simply close and reopen the stream because the stream may be a pipe ( or for example ) . The caller passes the bytes it peeked at with in and the number of bytes it peeked at in . The parser is advanced to the next non - blank non - comment data line that contains at least one token taking the prepended into account . There is a significant flaw in this mechanism and as a result the caller must be able to guarantee the following limitation . The first data - containing line must be longer than . It is sufficient for the first data token to be longer than . efp - open fileparser prefix - bytes that caller obtained by peeking with fread () plen - number of bytes in prefix on success . if no more tokens remain in the file . on allocation error . For an example see HMMER ' s HMM save file input .
int
esl_fileparser_NextLinePeeked(ESL_FILEPARSER *efp, char *prefix, int plen)
{
  int   blen;
  int   status;
  if ((status = nextline(efp)) != eslOK)  goto ERROR; 
  blen = strlen(efp->buf);
  if (blen + plen + 1 > efp->buflen) {
    ESL_REALLOC(efp->buf, sizeof(char) * (blen + plen + 1));
    efp->buflen = blen + plen + 1;
  }
  memmove(efp->buf+plen, efp->buf, blen+1);
  memcpy(efp->buf, prefix, plen);
  efp->s = efp->buf;
  while (*(efp->s) != '\0' && isspace(*(efp->s))) efp->s++;
  if    (*(efp->s) != '\0' && *efp->s != efp->commentchar) return eslOK;
  else                                                     return esl_fileparser_NextLine(efp);
 ERROR:
  return status;
}
int esl_fileparser_NextLinePeeked ( ESL_FILEPARSER * efp , char * prefix , int plen ) { int blen ; int status ; if ( ( status = nextline ( efp ) ) != eslOK ) goto ERROR ; blen = strlen ( efp -> buf ) ; if ( blen + plen + 1 > efp -> buflen ) { ESL_REALLOC ( efp -> buf , sizeof ( char ) * ( blen + plen + 1 ) ) ; efp -> buflen = blen + plen + 1 ; } memmove ( efp -> buf + plen , efp -> buf , blen + 1 ) ; memcpy ( efp -> buf , prefix , plen ) ; efp -> s = efp -> buf ; while ( * ( efp -> s ) != ' \0 ' && isspace ( * ( efp -> s ) ) ) efp -> s ++ ; if ( * ( efp -> s ) != ' \0 ' && * efp -> s != efp -> commentchar ) return eslOK ; else return esl_fileparser_NextLine ( efp ) ; ERROR : return status ; }
Function:  esl_fileparser_NextLinePeeked()
 Synopsis:  Read the next line, prepending a peek.
Function : esl_fileparser_NextLinePeeked () Synopsis : Read the next line prepending a peek .
/* First, make buf = the first line again, by prepending <prefix>. */ /* EOF, EMEM */