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