1 module dhtslib.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-2016 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 /// Low-level input/output stream handle
43 /** The fields of this structure are declared here solely for the benefit
44 of the hFILE-related inline functions.  They may change in future releases.
45 User code should not use them directly; you should imagine that hFILE is an
46 opaque incomplete type.
47 */
48 struct hFILE { // @suppress(dscanner.style.phobos_naming_convention)
49     // @cond internal
50     char *buffer;   /// ?
51     char *begin;    /// ?
52     char *end;      /// ?
53     char *limit;    /// ?
54     const(hFILE_backend) *backend;      /// internal
55     off_t offset;   /// file offset
56     //unsigned at_eof:1, mobile:1, readonly:1;
57     pragma(msg, "hFile: bitfield order assumed starting with LSB");
58     mixin(bitfields!(
59     ubyte, "at_eof", 1,
60     ubyte, "mobile", 1,
61     ubyte, "readonly", 1,
62     ubyte, "padding", 5));
63     int has_errno;  /// zero or actual errno
64     // @endcond
65 }
66 
67 /// Open the named file or URL as a stream
68 /** @return An hFILE pointer, or `NULL` (with _errno_ set) if an error occurred.
69 
70 The usual `fopen(3)` _mode_ letters are supported: one of
71 `r` (read), `w` (write), `a` (append), optionally followed by any of
72 `+` (update), `e` (close on `exec(2)`), `x` (create exclusively),
73 `:` (indicates scheme-specific variable arguments follow).
74 */
75 hFILE *hopen(const(char) *filename, const(char) *mode, ...);
76 
77 /// Associate a stream with an existing open file descriptor
78 /** @return An hFILE pointer, or `NULL` (with _errno_ set) if an error occurred.
79 
80 Note that the file must be opened in binary mode, or else
81 there will be problems on platforms that make a difference
82 between text and binary mode.
83 
84 For socket descriptors (on Windows), _mode_ should contain `s`.
85 */
86 hFILE *hdopen(int fd, const(char) *mode);
87 
88 /// Report whether the file name or URL denotes remote storage
89 /** @return  0 if local, 1 if remote.
90 
91 "Remote" means involving e.g. explicit network access, with the implication
92 that callers may wish to cache such files' contents locally.
93 */
94 int hisremote(const(char) *filename);
95 
96 /// Flush (for output streams) and close the stream
97 /** @return  0 if successful, or `EOF` (with _errno_ set) if an error occurred.
98 */
99 int hclose(hFILE *fp);
100 
101 /// Close the stream, without flushing or propagating errors
102 /** For use while cleaning up after an error only.  Preserves _errno_.
103 */
104 void hclose_abruptly(hFILE *fp);
105 
106 /// Return the stream's error indicator
107 /** @return  Non-zero (in fact, an _errno_ value) if an error has occurred.
108 
109 This would be called `herror()` and return true/false to parallel `ferror(3)`,
110 but a networking-related `herror(3)` function already exists.
111 */
112 pragma(inline, true)
113 int herrno(hFILE *fp)
114 {
115     return fp.has_errno;
116 }
117 
118 /// Clear the stream's error indicator
119 pragma(inline, true)
120 void hclearerr(hFILE *fp)
121 {
122     fp.has_errno = 0;
123 }
124 
125 /// Reposition the read/write stream offset
126 /** @return  The resulting offset within the stream (as per `lseek(2)`),
127     or negative if an error occurred.
128 */
129 off_t hseek(hFILE *fp, off_t offset, int whence);
130 
131 /// Report the current stream offset
132 /** @return  The offset within the stream, starting from zero.
133 */
134 pragma(inline, true)
135 off_t htell(hFILE *fp)
136 {
137     return fp.offset + (fp.begin - fp.buffer);
138 }
139 
140 /// Read one character from the stream
141 /** @return  The character read, or `EOF` on end-of-file or error.
142 */
143 pragma(inline, true)
144 int hgetc(hFILE *fp)
145 {
146     return (fp.end > fp.begin)? *(fp.begin++) : hgetc2(fp);
147 }
148 /// ditto
149 int hgetc2(hFILE *);
150 
151 /// Read from the stream until the delimiter, up to a maximum length
152 /** @param buffer  The buffer into which bytes will be written
153     @param size    The size of the buffer
154     @param delim   The delimiter (interpreted as an `unsigned char`)
155     @param fp      The file stream
156     @return  The number of bytes read, or negative on error.
157     @since   1.4
158 
159 Bytes will be read into the buffer up to and including a delimiter, until
160 EOF is reached, or _size-1_ bytes have been written, whichever comes first.
161 The string will then be terminated with a NUL byte (`\0`).
162 */
163 ssize_t hgetdelim(char *buffer, size_t size, int delim, hFILE *fp);
164 
165 /// Read a line from the stream, up to a maximum length
166 /** @param buffer  The buffer into which bytes will be written
167     @param size    The size of the buffer
168     @param fp      The file stream
169     @return  The number of bytes read, or negative on error.
170     @since   1.4
171 
172 Specialization of hgetdelim() for a `\n` delimiter.
173 */
174 pragma(inline, true)
175 ssize_t hgetln(char *buffer, size_t size, hFILE *fp)
176 {
177     return hgetdelim(buffer, size, '\n', fp);
178 }
179 
180 /// Read a line from the stream, up to a maximum length
181 /** @param buffer  The buffer into which bytes will be written
182     @param size    The size of the buffer (must be > 1 to be useful)
183     @param fp      The file stream
184     @return  _buffer_ on success, or `NULL` if an error occurred.
185     @since   1.4
186 
187 This function can be used as a replacement for `fgets(3)`, or together with
188 kstring's `kgetline()` to read arbitrarily-long lines into a _kstring_t_.
189 */
190 char *hgets(char *buffer, int size, hFILE *fp);
191 
192 /// Peek at characters to be read without removing them from buffers
193 /** @param fp      The file stream
194     @param buffer  The buffer to which the peeked bytes will be written
195     @param nbytes  The number of bytes to peek at; limited by the size of the
196                    internal buffer, which could be as small as 4K.
197     @return  The number of bytes peeked, which may be less than _nbytes_
198              if EOF is encountered; or negative, if there was an I/O error.
199 
200 The characters peeked at remain in the stream's internal buffer, and will be
201 returned by later hread() etc calls.
202 */
203 ssize_t hpeek(hFILE *fp, void *buffer, size_t nbytes);
204 
205 /// Read a block of characters from the file
206 /** @return  The number of bytes read, or negative if an error occurred.
207 
208 The full _nbytes_ requested will be returned, except as limited by EOF
209 or I/O errors.
210 */
211 pragma(inline, true)
212 ssize_t hread(hFILE *fp, void *buffer, size_t nbytes)
213 {
214     size_t n = fp.end - fp.begin;
215     if (n > nbytes) n = nbytes;
216     memcpy(buffer, fp.begin, n);
217     fp.begin += n;
218     return (n == nbytes || !fp.mobile)? cast(ssize_t) n : hread2(fp, buffer, nbytes, n);
219 }
220 /// ditto
221 ssize_t hread2(hFILE *, void *, size_t, size_t);
222 
223 
224 /// Write a character to the stream
225 /** @return  The character written, or `EOF` if an error occurred.
226 */
227 pragma(inline, true)
228 int hputc(int c, hFILE *fp)
229 {
230     if (fp.begin < fp.limit) *(fp.begin++) = cast(char) c;
231     else c = hputc2(c, fp);
232     return c;
233 }
234 /// ditto
235 int hputc2(int, hFILE *);
236 
237 /// Write a string to the stream
238 /** @return  0 if successful, or `EOF` if an error occurred.
239 */
240 pragma(inline, true)
241 int hputs(const(char) *text, hFILE *fp)
242 {
243 
244     size_t nbytes = strlen(text), n = fp.limit - fp.begin;
245     if (n > nbytes) n = nbytes;
246     memcpy(fp.begin, text, n);
247     fp.begin += n;
248     return (n == nbytes)? 0 : hputs2(text, nbytes, n, fp);
249 }
250 /// ditto
251 int hputs2(const(char) *, size_t, size_t, hFILE *);
252 
253 /// Write a block of characters to the file
254 /** @return  Either _nbytes_, or negative if an error occurred.
255 
256 In the absence of I/O errors, the full _nbytes_ will be written.
257 */
258 pragma(inline, true)
259 ssize_t hwrite(hFILE *fp, const(void) *buffer, size_t nbytes)
260 {
261     if(!fp.mobile){
262         if (fp.limit - fp.begin < nbytes){
263             hfile_set_blksize(fp, fp.limit - fp.buffer + nbytes);
264             fp.end = fp.limit;
265         }
266     }
267 
268     size_t n = fp.limit - fp.begin;
269     if (nbytes >= n && fp.begin == fp.buffer) {
270         // Go straight to hwrite2 if the buffer is empty and the request
271         // won't fit.
272         return hwrite2(fp, buffer, nbytes, 0);
273     }
274 
275     if (n > nbytes) n = nbytes;
276     memcpy(fp.begin, buffer, n);
277     fp.begin += n;
278     return (n==nbytes)? cast(ssize_t) n : hwrite2(fp, buffer, nbytes, n);
279 }
280 /// ditto
281 ssize_t hwrite2(hFILE *, const(void) *, size_t, size_t);
282 /// set hfile blocksize
283 int hfile_set_blksize(hFILE *fp, size_t bufsiz);
284 
285 /// For writing streams, flush buffered output to the underlying stream
286 /** @return  0 if successful, or `EOF` if an error occurred.
287 
288 This includes low-level flushing such as via `fdatasync(2)`.
289 */
290 int hflush(hFILE *fp);
291 
292 /// For hfile_mem: get the internal buffer and it's size from a hfile
293 /** @return  buffer if successful, or NULL if an error occurred
294 
295 The buffer returned should not be freed as this will happen when the
296 hFILE is closed.
297 */
298 char *hfile_mem_get_buffer(hFILE *file, size_t *length);
299 
300 /// For hfile_mem: get the internal buffer and it's size from a hfile.
301 /** @return  buffer if successful, or NULL if an error occurred
302 
303 This is similar to hfile_mem_get_buffer except that ownership of the
304 buffer is granted to the caller, who now has responsibility for freeing
305 it.  From this point onwards, the hFILE should not be used for any
306 purpose other than closing.
307 */
308 char *hfile_mem_steal_buffer(hFILE *file, size_t *length);