1 module htslib.hfile; 2 3 import std.bitmanip; 4 5 // @file htslib/hfile.h 6 // Buffered low-level input/output streams. 7 /* 8 Copyright (C) 2013-2019 Genome Research Ltd. 9 10 Author: John Marshall <jm18@sanger.ac.uk> 11 12 Permission is hereby granted, free of charge, to any person obtaining a copy 13 of this software and associated documentation files (the "Software"), to deal 14 in the Software without restriction, including without limitation the rights 15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 copies of the Software, and to permit persons to whom the Software is 17 furnished to do so, subject to the following conditions: 18 19 The above copyright notice and this permission notice shall be included in 20 all copies or substantial portions of the Software. 21 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 25 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28 DEALINGS IN THE SOFTWARE. */ 29 30 import core.stdc..string : memcpy, strlen; 31 32 //#include <sys/types.h> 33 alias off_t = size_t; 34 alias ssize_t = size_t; 35 36 //#include "hts_defs.h" 37 38 extern(C): 39 40 /// internal 41 struct hFILE_backend; // @suppress(dscanner.style.phobos_naming_convention) 42 struct kstring_t; 43 44 /// Low-level input/output stream handle 45 /** The fields of this structure are declared here solely for the benefit 46 of the hFILE-related inline functions. They may change in future releases. 47 User code should not use them directly; you should imagine that hFILE is an 48 opaque incomplete type. 49 */ 50 struct hFILE { // @suppress(dscanner.style.phobos_naming_convention) 51 // @cond internal 52 char *buffer; /// ? 53 char *begin; /// ? 54 char *end; /// ? 55 char *limit; /// ? 56 const(hFILE_backend) *backend; /// internal 57 off_t offset; /// file offset 58 //unsigned at_eof:1, mobile:1, readonly:1; 59 pragma(msg, "hFile: bitfield order assumed starting with LSB"); 60 mixin(bitfields!( 61 ubyte, "at_eof", 1, 62 ubyte, "mobile", 1, 63 ubyte, "readonly", 1, 64 ubyte, "padding", 5)); 65 int has_errno; /// zero or actual errno 66 // @endcond 67 } 68 69 /// Open the named file or URL as a stream 70 /** @return An hFILE pointer, or `NULL` (with _errno_ set) if an error occurred. 71 72 The usual `fopen(3)` _mode_ letters are supported: one of 73 `r` (read), `w` (write), `a` (append), optionally followed by any of 74 `+` (update), `e` (close on `exec(2)`), `x` (create exclusively), 75 `:` (indicates scheme-specific variable arguments follow). 76 */ 77 hFILE *hopen(const(char) *filename, const(char) *mode, ...); 78 79 /// Associate a stream with an existing open file descriptor 80 /** @return An hFILE pointer, or `NULL` (with _errno_ set) if an error occurred. 81 82 Note that the file must be opened in binary mode, or else 83 there will be problems on platforms that make a difference 84 between text and binary mode. 85 86 For socket descriptors (on Windows), _mode_ should contain `s`. 87 */ 88 hFILE *hdopen(int fd, const(char) *mode); 89 90 /// Report whether the file name or URL denotes remote storage 91 /** @return 0 if local, 1 if remote. 92 93 "Remote" means involving e.g. explicit network access, with the implication 94 that callers may wish to cache such files' contents locally. 95 */ 96 int hisremote(const(char) *filename); 97 98 /// Append an extension or replace an existing extension 99 /** @param buffer The kstring to be used to store the modified filename 100 @param filename The filename to be (copied and) adjusted 101 @param replace If non-zero, one extension (if any) is removed first 102 @param extension The extension to be added (e.g. ".csi") 103 @return The modified filename (i.e., `buffer->s`), or NULL on error. 104 @since 1.10 105 106 If _filename_ is an URL, alters extensions at the end of the `hier-part`, 107 leaving any trailing `?query` or `#fragment` unchanged. 108 */ 109 char *haddextension(kstring_t *buffer, const(char) *filename, 110 int replace, const(char) *extension); 111 112 /// Flush (for output streams) and close the stream 113 /** @return 0 if successful, or `EOF` (with _errno_ set) if an error occurred. 114 */ 115 int hclose(hFILE *fp); 116 117 /// Close the stream, without flushing or propagating errors 118 /** For use while cleaning up after an error only. Preserves _errno_. 119 */ 120 void hclose_abruptly(hFILE *fp); 121 122 /// Return the stream's error indicator 123 /** @return Non-zero (in fact, an _errno_ value) if an error has occurred. 124 125 This would be called `herror()` and return true/false to parallel `ferror(3)`, 126 but a networking-related `herror(3)` function already exists. 127 */ 128 pragma(inline, true) 129 int herrno(hFILE *fp) 130 { 131 return fp.has_errno; 132 } 133 134 /// Clear the stream's error indicator 135 pragma(inline, true) 136 void hclearerr(hFILE *fp) 137 { 138 fp.has_errno = 0; 139 } 140 141 /// Reposition the read/write stream offset 142 /** @return The resulting offset within the stream (as per `lseek(2)`), 143 or negative if an error occurred. 144 */ 145 off_t hseek(hFILE *fp, off_t offset, int whence); 146 147 /// Report the current stream offset 148 /** @return The offset within the stream, starting from zero. 149 */ 150 pragma(inline, true) 151 off_t htell(hFILE *fp) 152 { 153 return fp.offset + (fp.begin - fp.buffer); 154 } 155 156 /// Read one character from the stream 157 /** @return The character read, or `EOF` on end-of-file or error. 158 */ 159 pragma(inline, true) 160 int hgetc(hFILE *fp) 161 { 162 return (fp.end > fp.begin)? *(fp.begin++) : hgetc2(fp); 163 } 164 /// ditto 165 int hgetc2(hFILE *); 166 167 /// Read from the stream until the delimiter, up to a maximum length 168 /** @param buffer The buffer into which bytes will be written 169 @param size The size of the buffer 170 @param delim The delimiter (interpreted as an `unsigned char`) 171 @param fp The file stream 172 @return The number of bytes read, or negative on error. 173 @since 1.4 174 175 Bytes will be read into the buffer up to and including a delimiter, until 176 EOF is reached, or _size-1_ bytes have been written, whichever comes first. 177 The string will then be terminated with a NUL byte (`\0`). 178 */ 179 ssize_t hgetdelim(char *buffer, size_t size, int delim, hFILE *fp); 180 181 /// Read a line from the stream, up to a maximum length 182 /** @param buffer The buffer into which bytes will be written 183 @param size The size of the buffer 184 @param fp The file stream 185 @return The number of bytes read, or negative on error. 186 @since 1.4 187 188 Specialization of hgetdelim() for a `\n` delimiter. 189 */ 190 pragma(inline, true) 191 ssize_t hgetln(char *buffer, size_t size, hFILE *fp) 192 { 193 return hgetdelim(buffer, size, '\n', fp); 194 } 195 196 /// Read a line from the stream, up to a maximum length 197 /** @param buffer The buffer into which bytes will be written 198 @param size The size of the buffer (must be > 1 to be useful) 199 @param fp The file stream 200 @return _buffer_ on success, or `NULL` if an error occurred. 201 @since 1.4 202 203 This function can be used as a replacement for `fgets(3)`, or together with 204 kstring's `kgetline()` to read arbitrarily-long lines into a _kstring_t_. 205 */ 206 char *hgets(char *buffer, int size, hFILE *fp); 207 208 /// Peek at characters to be read without removing them from buffers 209 /** @param fp The file stream 210 @param buffer The buffer to which the peeked bytes will be written 211 @param nbytes The number of bytes to peek at; limited by the size of the 212 internal buffer, which could be as small as 4K. 213 @return The number of bytes peeked, which may be less than _nbytes_ 214 if EOF is encountered; or negative, if there was an I/O error. 215 216 The characters peeked at remain in the stream's internal buffer, and will be 217 returned by later hread() etc calls. 218 */ 219 ssize_t hpeek(hFILE *fp, void *buffer, size_t nbytes); 220 221 /// Read a block of characters from the file 222 /** @return The number of bytes read, or negative if an error occurred. 223 224 The full _nbytes_ requested will be returned, except as limited by EOF 225 or I/O errors. 226 */ 227 pragma(inline, true) 228 ssize_t hread(hFILE *fp, void *buffer, size_t nbytes) 229 { 230 size_t n = fp.end - fp.begin; 231 if (n > nbytes) n = nbytes; 232 memcpy(buffer, fp.begin, n); 233 fp.begin += n; 234 return (n == nbytes || !fp.mobile)? cast(ssize_t) n : hread2(fp, buffer, nbytes, n); 235 } 236 /// ditto 237 ssize_t hread2(hFILE *, void *, size_t, size_t); 238 239 240 /// Write a character to the stream 241 /** @return The character written, or `EOF` if an error occurred. 242 */ 243 pragma(inline, true) 244 int hputc(int c, hFILE *fp) 245 { 246 if (fp.begin < fp.limit) *(fp.begin++) = cast(char) c; 247 else c = hputc2(c, fp); 248 return c; 249 } 250 /// ditto 251 int hputc2(int, hFILE *); 252 253 /// Write a string to the stream 254 /** @return 0 if successful, or `EOF` if an error occurred. 255 */ 256 pragma(inline, true) 257 int hputs(const(char) *text, hFILE *fp) 258 { 259 260 size_t nbytes = strlen(text), n = fp.limit - fp.begin; 261 if (n > nbytes) n = nbytes; 262 memcpy(fp.begin, text, n); 263 fp.begin += n; 264 return (n == nbytes)? 0 : hputs2(text, nbytes, n, fp); 265 } 266 /// ditto 267 int hputs2(const(char) *, size_t, size_t, hFILE *); 268 269 /// Write a block of characters to the file 270 /** @return Either _nbytes_, or negative if an error occurred. 271 272 In the absence of I/O errors, the full _nbytes_ will be written. 273 */ 274 pragma(inline, true) 275 ssize_t hwrite(hFILE *fp, const(void) *buffer, size_t nbytes) 276 { 277 if(!fp.mobile){ 278 if (fp.limit - fp.begin < nbytes){ 279 hfile_set_blksize(fp, fp.limit - fp.buffer + nbytes); 280 fp.end = fp.limit; 281 } 282 } 283 284 size_t n = fp.limit - fp.begin; 285 if (nbytes >= n && fp.begin == fp.buffer) { 286 // Go straight to hwrite2 if the buffer is empty and the request 287 // won't fit. 288 return hwrite2(fp, buffer, nbytes, 0); 289 } 290 291 if (n > nbytes) n = nbytes; 292 memcpy(fp.begin, buffer, n); 293 fp.begin += n; 294 return (n==nbytes)? cast(ssize_t) n : hwrite2(fp, buffer, nbytes, n); 295 } 296 /// ditto 297 ssize_t hwrite2(hFILE *, const(void) *, size_t, size_t); 298 /// set hfile blocksize 299 int hfile_set_blksize(hFILE *fp, size_t bufsiz); 300 301 /// For writing streams, flush buffered output to the underlying stream 302 /** @return 0 if successful, or `EOF` if an error occurred. 303 304 This includes low-level flushing such as via `fdatasync(2)`. 305 */ 306 int hflush(hFILE *fp); 307 308 /// For hfile_mem: get the internal buffer and it's size from a hfile 309 /** @return buffer if successful, or NULL if an error occurred 310 311 The buffer returned should not be freed as this will happen when the 312 hFILE is closed. 313 */ 314 char *hfile_mem_get_buffer(hFILE *file, size_t *length); 315 316 /// For hfile_mem: get the internal buffer and it's size from a hfile. 317 /** @return buffer if successful, or NULL if an error occurred 318 319 This is similar to hfile_mem_get_buffer except that ownership of the 320 buffer is granted to the caller, who now has responsibility for freeing 321 it. From this point onwards, the hFILE should not be used for any 322 purpose other than closing. 323 */ 324 char *hfile_mem_steal_buffer(hFILE *file, size_t *length);