gff.c
/***************************************************************************
 *  Library:
 *      #include <biolibc/gff.h>
 *      -lbiolibc -lxtend
 *
 *  Description:
 *      Read next feature (line) from a GFF file.
 *
 *      feature must be initialized using BL_GFF_INIT or bl_gff_init()
 *      before being passed to this function.
 *
 *      bl_gff_read() will allocate memory for string fields as needed.
 *      The object should be passed to bl_gff_free() as soon as possible
 *      after the data are no longer needed.
 *
 *      If passed an object that is not in an initialized state,
 *      bl_gff_read() will free and initialize it before repopulating it
 *      with a new feature.
 *
 *      If field_mask is not BL_GFF_FIELD_ALL, fields not indicated by a 1
 *      in the bit mask are discarded rather than stored in feature.
 *      That field in the structure is then populated with an appropriate
 *      marker, such as '.'.  Possible mask values are:
 *
 *      BL_GFF_FIELD_ALL
 *      BL_GFF_FIELD_SEQID
 *      BL_GFF_FIELD_SOURCE
 *      BL_GFF_FIELD_TYPE
 *      BL_GFF_FIELD_START
 *      BL_GFF_FIELD_END
 *      BL_GFF_FIELD_SCORE
 *      BL_GFF_FIELD_STRAND
 *      BL_GFF_FIELD_PHASE
 *      BL_GFF_FIELD_ATTRIBUTES
 *
 *  Arguments:
 *      feature         Pointer to a bl_gff_t structure
 *      gff_stream      A FILE stream from which to read the line
 *      field_mask      Bit mask indicating which fields to store in feature
 *
 *  Returns:
 *      BL_READ_OK on successful read
 *      BL_READ_EOF if EOF is encountered after a complete feature
 *      BL_READ_TRUNCATED if EOF or bad data is encountered elsewhere
 *
 *  Examples:
 *      bl_gff_skip_header(stdin);
 *      bl_gff_init(&feature);
 *
 *      bl_gff_read(&feature, stdin, BL_GFF_FIELD_ALL);
 *      bl_gff_read(&feature, gff_stream,
 *          BL_GFF_FIELD_SEQID|BL_GFF_FIELD_START|BL_GFF_FIELD_END);
 *
 *  See also:
 *      bl_gff_write(3)
 *
 *  History: 
 *  Date        Name        Modification
 *  2021-04-05  Jason Bacon Begin
 ***************************************************************************/
#include 
-lbiolibc -lxtend

Read next feature (line) from a GFF file.

feature must be initialized using BL_GFF_INIT or bl_gff_init()
before being passed to this function.

bl_gff_read() will allocate memory for string fields as needed.
The object should be passed to bl_gff_free() as soon as possible
after the data are no longer needed.

If passed an object that is not in an initialized state,
bl_gff_read() will free and initialize it before repopulating it
with a new feature.

If field_mask is not BL_GFF_FIELD_ALL, fields not indicated by a 1
in the bit mask are discarded rather than stored in feature.
That field in the structure is then populated with an appropriate
marker, such as '.'.  Possible mask values are.



feature         Pointer to a bl_gff_t structure
gff_stream      A FILE stream from which to read the line
field_mask      Bit mask indicating which fields to store in feature

BL_READ_OK on successful read
BL_READ_EOF if EOF is encountered after a complete feature
BL_READ_TRUNCATED if EOF or bad data is encountered elsewhere







Date        Name        Modification
2021-04-05  Jason Bacon Begin
#include - lbiolibc - lxtend Read next feature ( line ) from a GFF file . feature must be initialized using BL_GFF_INIT or bl_gff_init () before being passed to this function . bl_gff_read () will allocate memory for string fields as needed . The object should be passed to bl_gff_free () as soon as possible after the data are no longer needed . If passed an object that is not in an initialized state bl_gff_read () will free and initialize it before repopulating it with a new feature . If field_mask is not BL_GFF_FIELD_ALL fields not indicated by a 1 in the bit mask are discarded rather than stored in feature . That field in the structure is then populated with an appropriate marker such as ' . ' . Possible mask values are . feature Pointer to a bl_gff_t structure gff_stream A FILE stream from which to read the line field_mask Bit mask indicating which fields to store in feature BL_READ_OK on successful read BL_READ_EOF if EOF is encountered after a complete feature BL_READ_TRUNCATED if EOF or bad data is encountered elsewhere Date Name Modification 2021 - 04 - 05 Jason Bacon Begin
int     bl_gff_read(bl_gff_t *feature, FILE *gff_stream,
	    gff_field_mask_t field_mask)
{
    char    *end,
	    line[BL_GFF_LINE_MAX_CHARS + 1],
	    strand_str[BL_GFF_STRAND_MAX_CHARS + 1],
	    phase_str[BL_GFF_PHASE_MAX_DIGITS + 1],
	    start_str[BL_POSITION_MAX_DIGITS + 1],
	    end_str[BL_POSITION_MAX_DIGITS + 1],
	    score_str[BL_GFF_SCORE_MAX_DIGITS + 1];
    size_t  len;
    int     delim,
	    ch;
    if ( feature->attributes != NULL )
	bl_gff_free(feature);
    if ( (ch = getc(gff_stream)) == '#' )
    {
	fgets(line, BL_GFF_LINE_MAX_CHARS, gff_stream);
	if ( strcmp(line, "##\n") == 0 )
	{
	    strlcpy(feature->type, "###", BL_GFF_TYPE_MAX_CHARS);
	    return BL_READ_OK;
	}
    }
    else if ( ch != EOF )
	ungetc(ch, gff_stream);
    feature->file_pos = ftell(gff_stream);
    if ( tsv_read_field(gff_stream, feature->seqid,
			BL_CHROM_MAX_CHARS, &len) == EOF )
    {
	return BL_READ_EOF;
    }
    if ( tsv_read_field(gff_stream, feature->source,
			BL_GFF_SOURCE_MAX_CHARS, &len) == EOF )
    {
	fprintf(stderr, "bl_gff_read(): Got EOF reading SOURCE: %s.\n",
		feature->source);
	return BL_READ_TRUNCATED;
    }
    if ( tsv_read_field(gff_stream, feature->type,
			BL_GFF_TYPE_MAX_CHARS, &len) == EOF )
    {
	fprintf(stderr, "bl_gff_read(): Got EOF reading feature: %s.\n",
		feature->type);
	return BL_READ_TRUNCATED;
    }
    if ( tsv_read_field(gff_stream, start_str,
			BL_POSITION_MAX_DIGITS, &len) == EOF )
    {
	fprintf(stderr, "bl_gff_read(): Got EOF reading start POS: %s.\n",
		start_str);
	return BL_READ_TRUNCATED;
    }
    else
    {
	feature->start = strtoul(start_str, &end, 10);
	if ( *end != '\0' )
	{
	    fprintf(stderr,
		    "bl_gff_read(): Invalid feature position: %s\n",
		    start_str);
	    return BL_READ_TRUNCATED;
	}
    }
    if ( tsv_read_field(gff_stream, end_str,
			BL_POSITION_MAX_DIGITS, &len) == EOF )
    {
	fprintf(stderr, "bl_gff_read(): Got EOF reading end POS: %s.\n",
		end_str);
	return BL_READ_TRUNCATED;
    }
    else
    {
	feature->end = strtoul(end_str, &end, 10);
	if ( *end != '\0' )
	{
	    fprintf(stderr,
		    "bl_gff_read(): Invalid feature position: %s\n",
		    end_str);
	    return BL_READ_TRUNCATED;
	}
    }
    if ( tsv_read_field(gff_stream, score_str,
			BL_GFF_SCORE_MAX_DIGITS, &len) == EOF )
    {
	fprintf(stderr, "bl_gff_read(): Got EOF reading SCORE: %s.\n",
		score_str);
	return BL_READ_TRUNCATED;
    }
    else
    {
	feature->score = strtod(score_str, &end);
	if ( *end != '\0' )
	    feature->score = BL_GFF_SCORE_UNAVAILABLE;
    }
    if ( tsv_read_field(gff_stream, strand_str,
			BL_GFF_STRAND_MAX_CHARS, &len) == EOF )
    {
	fprintf(stderr, "bl_gff_read(): Got EOF reading STRAND: %s.\n",
		strand_str);
	return BL_READ_TRUNCATED;
    }
    else
	feature->strand = *strand_str;
    if ( tsv_read_field(gff_stream, phase_str,
			BL_GFF_PHASE_MAX_DIGITS, &len) == EOF )
    {
	fprintf(stderr, "bl_gff_read(): Got EOF reading PHASE: %s.\n",
		phase_str);
	return BL_READ_TRUNCATED;
    }
    else
	feature->phase = *phase_str;
    if ( (delim = tsv_read_field_malloc(gff_stream, &feature->attributes,
			&feature->attributes_array_size,
			&feature->attributes_len)) == EOF )
    {
	fprintf(stderr, "bl_gff_read(): Got EOF reading ATTRIBUTES: %s.\n",
		feature->attributes);
	return BL_READ_TRUNCATED;
    }
    if ( delim != '\n' )
	dsv_skip_rest_of_line(gff_stream);
    feature->feature_id = bl_gff_extract_attribute(feature, "ID");
    feature->feature_name = bl_gff_extract_attribute(feature, "Name");
    if ( feature->feature_name == NULL )
    {
	if ( (feature->feature_name = strdup("unnamed")) == NULL )
	    fprintf(stderr, "bl_gff_read(): Could not strdup() feature_name.\n");
    }
    feature->feature_parent = bl_gff_extract_attribute(feature, "Parent");
    if ( feature->feature_parent == NULL )
    {
	if ( (feature->feature_parent = strdup("noparent")) == NULL )
	    fprintf(stderr, "bl_gff_read(): Could not strdup() feature_parent.\n");
    }
    return BL_READ_OK;
}
int bl_gff_read ( bl_gff_t * feature , FILE * gff_stream , gff_field_mask_t field_mask ) { char * end , line [ BL_GFF_LINE_MAX_CHARS + 1 ] , strand_str [ BL_GFF_STRAND_MAX_CHARS + 1 ] , phase_str [ BL_GFF_PHASE_MAX_DIGITS + 1 ] , start_str [ BL_POSITION_MAX_DIGITS + 1 ] , end_str [ BL_POSITION_MAX_DIGITS + 1 ] , score_str [ BL_GFF_SCORE_MAX_DIGITS + 1 ] ; size_t len ; int delim , ch ; if ( feature -> attributes != NULL ) bl_gff_free ( feature ) ; if ( ( ch = getc ( gff_stream ) ) == ' ' ) { fgets ( line , BL_GFF_LINE_MAX_CHARS , gff_stream ) ; if ( strcmp ( line , " \n " ) == 0 ) { strlcpy ( feature -> type , " " , BL_GFF_TYPE_MAX_CHARS ) ; return BL_READ_OK ; } } else if ( ch != EOF ) ungetc ( ch , gff_stream ) ; feature -> file_pos = ftell ( gff_stream ) ; if ( tsv_read_field ( gff_stream , feature -> seqid , BL_CHROM_MAX_CHARS , & len ) == EOF ) { return BL_READ_EOF ; } if ( tsv_read_field ( gff_stream , feature -> source , BL_GFF_SOURCE_MAX_CHARS , & len ) == EOF ) { fprintf ( stderr , " \n " , feature -> source ) ; return BL_READ_TRUNCATED ; } if ( tsv_read_field ( gff_stream , feature -> type , BL_GFF_TYPE_MAX_CHARS , & len ) == EOF ) { fprintf ( stderr , " \n " , feature -> type ) ; return BL_READ_TRUNCATED ; } if ( tsv_read_field ( gff_stream , start_str , BL_POSITION_MAX_DIGITS , & len ) == EOF ) { fprintf ( stderr , " \n " , start_str ) ; return BL_READ_TRUNCATED ; } else { feature -> start = strtoul ( start_str , & end , 10 ) ; if ( * end != ' \0 ' ) { fprintf ( stderr , " \n " , start_str ) ; return BL_READ_TRUNCATED ; } } if ( tsv_read_field ( gff_stream , end_str , BL_POSITION_MAX_DIGITS , & len ) == EOF ) { fprintf ( stderr , " \n " , end_str ) ; return BL_READ_TRUNCATED ; } else { feature -> end = strtoul ( end_str , & end , 10 ) ; if ( * end != ' \0 ' ) { fprintf ( stderr , " \n " , end_str ) ; return BL_READ_TRUNCATED ; } } if ( tsv_read_field ( gff_stream , score_str , BL_GFF_SCORE_MAX_DIGITS , & len ) == EOF ) { fprintf ( stderr , " \n " , score_str ) ; return BL_READ_TRUNCATED ; } else { feature -> score = strtod ( score_str , & end ) ; if ( * end != ' \0 ' ) feature -> score = BL_GFF_SCORE_UNAVAILABLE ; } if ( tsv_read_field ( gff_stream , strand_str , BL_GFF_STRAND_MAX_CHARS , & len ) == EOF ) { fprintf ( stderr , " \n " , strand_str ) ; return BL_READ_TRUNCATED ; } else feature -> strand = * strand_str ; if ( tsv_read_field ( gff_stream , phase_str , BL_GFF_PHASE_MAX_DIGITS , & len ) == EOF ) { fprintf ( stderr , " \n " , phase_str ) ; return BL_READ_TRUNCATED ; } else feature -> phase = * phase_str ; if ( ( delim = tsv_read_field_malloc ( gff_stream , & feature -> attributes , & feature -> attributes_array_size , & feature -> attributes_len ) ) == EOF ) { fprintf ( stderr , " \n " , feature -> attributes ) ; return BL_READ_TRUNCATED ; } if ( delim != ' \n ' ) dsv_skip_rest_of_line ( gff_stream ) ; feature -> feature_id = bl_gff_extract_attribute ( feature , " " ) ; feature -> feature_name = bl_gff_extract_attribute ( feature , " " ) ; if ( feature -> feature_name == NULL ) { if ( ( feature -> feature_name = strdup ( " " ) ) == NULL ) fprintf ( stderr , " \n " ) ; } feature -> feature_parent = bl_gff_extract_attribute ( feature , " " ) ; if ( feature -> feature_parent == NULL ) { if ( ( feature -> feature_parent = strdup ( " " ) ) == NULL ) fprintf ( stderr , " \n " ) ; } return BL_READ_OK ; }
Library:
      #include <biolibc/gff.h>
      -lbiolibc -lxtend
Library : #include <biolibc / gff . h > - lbiolibc - lxtend
// Use this as a model for other _read() functions? // Makes reusing a structure easy without risk of memory leaks // Check for group terminators (Line with just ###) // FIXME: Rely on parent ID instead of ###? // FIXME: Respect field_mask // 1 Chromosome // 2 Source // 3 Feature // 4 Feature start position // 5 Feature end position // 6 Score // 7 Strand // 8 Phase (bases to start of next codon: 0, 1, or 2. "." if unavailable) // 9 Attributes //fprintf(stderr, "%s %zu\n", feature->attributes, //        strlen(feature->attributes)); // printf("delim = %u\n", delim); // Extract feature ID from attributes // Extract feature name from attributes // Extract feature parent from attributes