diff --git a/hts.c b/hts.c index 67c27218f..fde37a5eb 100644 --- a/hts.c +++ b/hts.c @@ -1231,6 +1231,7 @@ int hts_close(htsFile *fp) hts_idx_destroy(fp->idx); free(fp->fn); free(fp->fn_aux); + free((void *)fp->fnidx); free(fp->line.s); free(fp); errno = save; @@ -1242,6 +1243,11 @@ const htsFormat *hts_get_format(htsFile *fp) return fp? &fp->format : NULL; } +const char *hts_get_fn(htsFile *fp) +{ + return fp? fp->fn : NULL; +} + const char *hts_format_file_extension(const htsFormat *format) { if (!format) return "?"; diff --git a/htslib/hts.h b/htslib/hts.h index 1b8541048..6fea2daaa 100644 --- a/htslib/hts.h +++ b/htslib/hts.h @@ -508,6 +508,14 @@ int hts_close(htsFile *fp); HTSLIB_EXPORT const htsFormat *hts_get_format(htsFile *fp); +/*! + @abstract Returns the file's name + @param fp The file handle + @return Read-only pointer to the file's fn field. +*/ +HTSLIB_EXPORT +const char *hts_get_fn(htsFile *fp); + /*! @ abstract Returns a string containing the file format extension. @ param format Format structure containing the file type. diff --git a/htslib/sam.h b/htslib/sam.h index 7d6b983f9..f0257a5f3 100644 --- a/htslib/sam.h +++ b/htslib/sam.h @@ -1089,8 +1089,7 @@ int bam_set_qname(bam1_t *b, const char *qname); /** @param fp File handle for the data file being written. @param h Bam header structured (needed for BAI and CSI). @param min_shift 0 for BAI, or larger for CSI (CSI defaults to 14). - @param fnidx Filename to write index to. This pointer must remain valid - until after sam_idx_save is called. + @param fnidx Filename to write index to. @return 0 on success, <0 on failure. @note This must be called after the header has been written, but before @@ -1325,6 +1324,20 @@ const char *sam_parse_region(sam_hdr_t *h, const char *s, int *tid, const char *mode, const char *format); +/// sam_open_write - Open a file for writing only +/** The method opens a new alignment file for writing, writes header hdr to it + * and attaches the header struct to the returned htsFile struct. + * If successful, ownership of hdr is given to the htsFile struct and hdr + * should not be freed separately. + * @param fn Name of the file + * @param h Pointer to the header previously read or created + * @param mode Pointer to the mode string (must contain "w") + * @param fmt Pointer to the format + * @return Pointer to the htsFile (with hdr) on success, NULL on failure + */ + HTSLIB_EXPORT + htsFile *sam_open_write(const char *fn, sam_hdr_t *hdr, const char *mode, const htsFormat *fmt); + HTSLIB_EXPORT int sam_hdr_change_HD(sam_hdr_t *h, const char *key, const char *val); @@ -1343,7 +1356,8 @@ const char *sam_parse_region(sam_hdr_t *h, const char *s, int *tid, int sam_read1(samFile *fp, sam_hdr_t *h, bam1_t *b) HTS_RESULT_USED; /// sam_write1 - Write a record to a file /** @param fp Pointer to the destination file - * @param h Pointer to the header structure previously read + * @param h Pointer to the header structure previously read. Can be NULL, + * if fp has a non-NULL pointer to a valid header struct. * @param b Pointer to the record to be written * @return >= 0 on successfully writing the record, -1 on error */ diff --git a/sam.c b/sam.c index 12742b5ec..878fcc270 100644 --- a/sam.c +++ b/sam.c @@ -894,7 +894,9 @@ int bam_index_build(const char *fn, int min_shift) // Initialise fp->idx for the current format type. // This must be called after the header has been written but no other data. int sam_idx_init(htsFile *fp, sam_hdr_t *h, int min_shift, const char *fnidx) { - fp->fnidx = fnidx; + fp->fnidx = strdup(fnidx); + if (!fp->fnidx) return -1; + if (fp->format.format == bam || fp->format.format == bcf || (fp->format.format == sam && fp->format.compression == bgzf)) { int n_lvls, fmt = HTS_FMT_CSI; @@ -1671,6 +1673,30 @@ int sam_hdr_write(htsFile *fp, const sam_hdr_t *h) return 0; } +htsFile *sam_open_write(const char *fn, sam_hdr_t *hdr, const char *mode, const htsFormat *fmt) { + htsFile *sf = NULL; + if (fn && mode) { + if (strchr(mode, 'w')) { + sf = hts_open_format(fn, mode, fmt); + if (sf) { + if (sam_hdr_write(sf, hdr) < 0) { + hts_log_error("Writing header to file \"%s\" failed", fn); + sam_close(sf); + sf = NULL; + } else { + if (sf->bam_header) + sam_hdr_destroy(sf->bam_header); + sf->bam_header = hdr; + } + } + } else { + hts_log_error("Only write mode allowed"); + } + } + + return sf; +} + static int old_sam_hdr_change_HD(sam_hdr_t *h, const char *key, const char *val) { char *p, *q, *beg = NULL, *end = NULL, *newtext; @@ -3192,8 +3218,10 @@ int sam_format1(const bam_hdr_t *h, const bam1_t *b, kstring_t *str) // Sadly we need to be able to modify the bam_hdr here so we can // reference count the structure. -int sam_write1(htsFile *fp, const sam_hdr_t *h, const bam1_t *b) +int sam_write1(htsFile *fp, const sam_hdr_t *hdr, const bam1_t *b) { + const sam_hdr_t *h = hdr; + if (!h) h = fp->bam_header; switch (fp->format.format) { case binary_format: fp->format.category = sequence_data; diff --git a/vcf.c b/vcf.c index dd21d5332..8416c5e80 100644 --- a/vcf.c +++ b/vcf.c @@ -3295,7 +3295,8 @@ static int vcf_idx_init(htsFile *fp, bcf_hdr_t *h, int min_shift, const char *fn fp->idx = NULL; return -1; } - fp->fnidx = fnidx; + fp->fnidx = strdup(fnidx); + if (!fp->fnidx) return -1; return 0; } @@ -3315,7 +3316,8 @@ int bcf_idx_init(htsFile *fp, bcf_hdr_t *h, int min_shift, const char *fnidx) { fp->idx = hts_idx_init(nids, HTS_FMT_CSI, bgzf_tell(fp->fp.bgzf), min_shift, n_lvls); if (!fp->idx) return -1; - fp->fnidx = fnidx; + fp->fnidx = strdup(fnidx); + if (!fp->fnidx) return -1; return 0; }