annotate ezBAMQC/src/htslib/hfile.c @ 3:ddfb71ec32ed

Uploaded
author cshl-bsr
date Tue, 29 Mar 2016 15:31:11 -0400
parents dfa3745e5fd8
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
1 /* hfile.c -- buffered low-level input/output streams.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
2
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
3 Copyright (C) 2013-2015 Genome Research Ltd.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
4
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
5 Author: John Marshall <jm18@sanger.ac.uk>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
6
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
7 Permission is hereby granted, free of charge, to any person obtaining a copy
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
8 of this software and associated documentation files (the "Software"), to deal
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
9 in the Software without restriction, including without limitation the rights
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
11 copies of the Software, and to permit persons to whom the Software is
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
12 furnished to do so, subject to the following conditions:
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
13
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
14 The above copyright notice and this permission notice shall be included in
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
15 all copies or substantial portions of the Software.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
16
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
23 DEALINGS IN THE SOFTWARE. */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
24
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
25 #include <stdio.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
26 #include <stdlib.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
27 #include <string.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
28 #include <errno.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
29
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
30 #include "htslib/hfile.h"
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
31 #include "hfile_internal.h"
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
32
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
33 /* hFILE fields are used as follows:
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
34
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
35 char *buffer; // Pointer to the start of the I/O buffer
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
36 char *begin; // First not-yet-read character / unused position
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
37 char *end; // First unfilled/unfillable position
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
38 char *limit; // Pointer to the first position past the buffer
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
39
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
40 const hFILE_backend *backend; // Methods to refill/flush I/O buffer
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
41
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
42 off_t offset; // Offset within the stream of buffer position 0
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
43 int at_eof:1; // For reading, whether EOF has been seen
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
44 int has_errno; // Error number from the last failure on this stream
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
45
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
46 For reading, begin is the first unread character in the buffer and end is the
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
47 first unfilled position:
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
48
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
49 -----------ABCDEFGHIJKLMNO---------------
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
50 ^buffer ^begin ^end ^limit
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
51
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
52 For writing, begin is the first unused position and end is unused so remains
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
53 equal to buffer:
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
54
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
55 ABCDEFGHIJKLMNOPQRSTUVWXYZ---------------
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
56 ^buffer ^begin ^limit
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
57 ^end
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
58
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
59 Thus if begin > end then there is a non-empty write buffer, if begin < end
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
60 then there is a non-empty read buffer, and if begin == end then both buffers
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
61 are empty. In all cases, the stream's file position indicator corresponds
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
62 to the position pointed to by begin. */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
63
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
64 hFILE *hfile_init(size_t struct_size, const char *mode, size_t capacity)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
65 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
66 hFILE *fp = (hFILE *) malloc(struct_size);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
67 if (fp == NULL) goto error;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
68
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
69 if (capacity == 0) capacity = 32768;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
70 // FIXME For now, clamp input buffer sizes so mpileup doesn't eat memory
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
71 if (strchr(mode, 'r') && capacity > 32768) capacity = 32768;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
72
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
73 fp->buffer = (char *) malloc(capacity);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
74 if (fp->buffer == NULL) goto error;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
75
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
76 fp->begin = fp->end = fp->buffer;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
77 fp->limit = &fp->buffer[capacity];
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
78
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
79 fp->offset = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
80 fp->at_eof = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
81 fp->has_errno = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
82 return fp;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
83
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
84 error:
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
85 hfile_destroy(fp);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
86 return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
87 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
88
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
89 void hfile_destroy(hFILE *fp)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
90 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
91 int save = errno;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
92 if (fp) free(fp->buffer);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
93 free(fp);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
94 errno = save;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
95 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
96
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
97 static inline int writebuffer_is_nonempty(hFILE *fp)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
98 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
99 return fp->begin > fp->end;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
100 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
101
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
102 /* Refills the read buffer from the backend (once, so may only partially
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
103 fill the buffer), returning the number of additional characters read
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
104 (which might be 0), or negative when an error occurred. */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
105 static ssize_t refill_buffer(hFILE *fp)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
106 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
107 ssize_t n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
108
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
109 // Move any unread characters to the start of the buffer
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
110 if (fp->begin > fp->buffer) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
111 fp->offset += fp->begin - fp->buffer;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
112 memmove(fp->buffer, fp->begin, fp->end - fp->begin);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
113 fp->end = &fp->buffer[fp->end - fp->begin];
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
114 fp->begin = fp->buffer;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
115 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
116
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
117 // Read into the available buffer space at fp->[end,limit)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
118 if (fp->at_eof || fp->end == fp->limit) n = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
119 else {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
120 n = fp->backend->read(fp, fp->end, fp->limit - fp->end);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
121 if (n < 0) { fp->has_errno = errno; return n; }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
122 else if (n == 0) fp->at_eof = 1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
123 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
124
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
125 fp->end += n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
126 return n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
127 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
128
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
129 /* Called only from hgetc(), when our buffer is empty. */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
130 int hgetc2(hFILE *fp)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
131 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
132 return (refill_buffer(fp) > 0)? (unsigned char) *(fp->begin++) : EOF;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
133 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
134
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
135 ssize_t hpeek(hFILE *fp, void *buffer, size_t nbytes)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
136 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
137 size_t n = fp->end - fp->begin;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
138 while (n < nbytes) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
139 ssize_t ret = refill_buffer(fp);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
140 if (ret < 0) return ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
141 else if (ret == 0) break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
142 else n += ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
143 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
144
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
145 if (n > nbytes) n = nbytes;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
146 memcpy(buffer, fp->begin, n);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
147 return n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
148 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
149
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
150 /* Called only from hread(); when called, our buffer is empty and nread bytes
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
151 have already been placed in the destination buffer. */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
152 ssize_t hread2(hFILE *fp, void *destv, size_t nbytes, size_t nread)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
153 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
154 const size_t capacity = fp->limit - fp->buffer;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
155 char *dest = (char *) destv;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
156 dest += nread, nbytes -= nread;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
157
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
158 // Read large requests directly into the destination buffer
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
159 while (nbytes * 2 >= capacity && !fp->at_eof) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
160 ssize_t n = fp->backend->read(fp, dest, nbytes);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
161 if (n < 0) { fp->has_errno = errno; return n; }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
162 else if (n == 0) fp->at_eof = 1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
163 fp->offset += n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
164 dest += n, nbytes -= n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
165 nread += n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
166 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
167
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
168 while (nbytes > 0 && !fp->at_eof) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
169 size_t n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
170 ssize_t ret = refill_buffer(fp);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
171 if (ret < 0) return ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
172
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
173 n = fp->end - fp->begin;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
174 if (n > nbytes) n = nbytes;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
175 memcpy(dest, fp->begin, n);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
176 fp->begin += n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
177 dest += n, nbytes -= n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
178 nread += n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
179 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
180
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
181 return nread;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
182 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
183
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
184 /* Flushes the write buffer, fp->[buffer,begin), out through the backend
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
185 returning 0 on success or negative if an error occurred. */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
186 static ssize_t flush_buffer(hFILE *fp)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
187 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
188 const char *buffer = fp->buffer;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
189 while (buffer < fp->begin) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
190 ssize_t n = fp->backend->write(fp, buffer, fp->begin - buffer);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
191 if (n < 0) { fp->has_errno = errno; return n; }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
192 buffer += n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
193 fp->offset += n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
194 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
195
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
196 fp->begin = fp->buffer; // Leave the buffer empty
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
197 return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
198 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
199
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
200 int hflush(hFILE *fp)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
201 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
202 if (flush_buffer(fp) < 0) return EOF;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
203 if (fp->backend->flush(fp) < 0) { fp->has_errno = errno; return EOF; }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
204 return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
205 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
206
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
207 /* Called only from hputc(), when our buffer is already full. */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
208 int hputc2(int c, hFILE *fp)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
209 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
210 if (flush_buffer(fp) < 0) return EOF;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
211 *(fp->begin++) = c;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
212 return c;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
213 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
214
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
215 /* Called only from hwrite() and hputs2(); when called, our buffer is full and
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
216 ncopied bytes from the source have already been copied to our buffer. */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
217 ssize_t hwrite2(hFILE *fp, const void *srcv, size_t totalbytes, size_t ncopied)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
218 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
219 const char *src = (const char *) srcv;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
220 ssize_t ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
221 const size_t capacity = fp->limit - fp->buffer;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
222 size_t remaining = totalbytes - ncopied;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
223 src += ncopied;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
224
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
225 ret = flush_buffer(fp);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
226 if (ret < 0) return ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
227
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
228 // Write large blocks out directly from the source buffer
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
229 while (remaining * 2 >= capacity) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
230 ssize_t n = fp->backend->write(fp, src, remaining);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
231 if (n < 0) { fp->has_errno = errno; return n; }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
232 fp->offset += n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
233 src += n, remaining -= n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
234 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
235
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
236 // Just buffer any remaining characters
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
237 memcpy(fp->begin, src, remaining);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
238 fp->begin += remaining;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
239
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
240 return totalbytes;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
241 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
242
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
243 /* Called only from hputs(), when our buffer is already full. */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
244 int hputs2(const char *text, size_t totalbytes, size_t ncopied, hFILE *fp)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
245 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
246 return (hwrite2(fp, text, totalbytes, ncopied) >= 0)? 0 : EOF;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
247 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
248
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
249 off_t hseek(hFILE *fp, off_t offset, int whence)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
250 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
251 off_t pos;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
252
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
253 if (writebuffer_is_nonempty(fp)) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
254 int ret = flush_buffer(fp);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
255 if (ret < 0) return ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
256 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
257 else {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
258 // Convert relative offsets from being relative to the hFILE's stream
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
259 // position (at begin) to being relative to the backend's physical
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
260 // stream position (at end, due to the buffering read-ahead).
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
261 if (whence == SEEK_CUR) offset -= fp->end - fp->begin;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
262 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
263
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
264 pos = fp->backend->seek(fp, offset, whence);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
265 if (pos < 0) { fp->has_errno = errno; return pos; }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
266
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
267 // Seeking succeeded, so discard any non-empty read buffer
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
268 fp->begin = fp->end = fp->buffer;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
269 fp->at_eof = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
270
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
271 fp->offset = pos;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
272 return pos;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
273 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
274
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
275 int hclose(hFILE *fp)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
276 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
277 int err = fp->has_errno;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
278
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
279 if (writebuffer_is_nonempty(fp) && hflush(fp) < 0) err = fp->has_errno;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
280 if (fp->backend->close(fp) < 0) err = errno;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
281 hfile_destroy(fp);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
282
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
283 if (err) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
284 errno = err;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
285 return EOF;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
286 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
287 else return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
288 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
289
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
290 void hclose_abruptly(hFILE *fp)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
291 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
292 int save = errno;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
293 if (fp->backend->close(fp) < 0) { /* Ignore subsequent errors */ }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
294 hfile_destroy(fp);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
295 errno = save;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
296 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
297
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
298
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
299 /***************************
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
300 * File descriptor backend *
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
301 ***************************/
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
302
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
303 #include <sys/socket.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
304 #include <sys/stat.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
305 #include <fcntl.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
306 #include <unistd.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
307
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
308 #ifdef _WIN32
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
309 #define HAVE_CLOSESOCKET
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
310 #endif
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
311
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
312 /* For Unix, it doesn't matter whether a file descriptor is a socket.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
313 However Windows insists on send()/recv() and its own closesocket()
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
314 being used when fd happens to be a socket. */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
315
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
316 typedef struct {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
317 hFILE base;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
318 int fd;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
319 int is_socket:1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
320 } hFILE_fd;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
321
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
322 static ssize_t fd_read(hFILE *fpv, void *buffer, size_t nbytes)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
323 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
324 hFILE_fd *fp = (hFILE_fd *) fpv;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
325 ssize_t n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
326 do {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
327 n = fp->is_socket? recv(fp->fd, buffer, nbytes, 0)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
328 : read(fp->fd, buffer, nbytes);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
329 } while (n < 0 && errno == EINTR);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
330 return n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
331 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
332
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
333 static ssize_t fd_write(hFILE *fpv, const void *buffer, size_t nbytes)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
334 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
335 hFILE_fd *fp = (hFILE_fd *) fpv;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
336 ssize_t n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
337 do {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
338 n = fp->is_socket? send(fp->fd, buffer, nbytes, 0)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
339 : write(fp->fd, buffer, nbytes);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
340 } while (n < 0 && errno == EINTR);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
341 return n;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
342 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
343
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
344 static off_t fd_seek(hFILE *fpv, off_t offset, int whence)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
345 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
346 hFILE_fd *fp = (hFILE_fd *) fpv;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
347 return lseek(fp->fd, offset, whence);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
348 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
349
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
350 static int fd_flush(hFILE *fpv)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
351 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
352 hFILE_fd *fp = (hFILE_fd *) fpv;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
353 int ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
354 do {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
355 #ifdef HAVE_FDATASYNC
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
356 ret = fdatasync(fp->fd);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
357 #else
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
358 ret = fsync(fp->fd);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
359 #endif
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
360 // Ignore invalid-for-fsync(2) errors due to being, e.g., a pipe,
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
361 // and operation-not-supported errors (Mac OS X)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
362 if (ret < 0 && (errno == EINVAL || errno == ENOTSUP)) ret = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
363 } while (ret < 0 && errno == EINTR);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
364 return ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
365 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
366
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
367 static int fd_close(hFILE *fpv)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
368 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
369 hFILE_fd *fp = (hFILE_fd *) fpv;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
370 int ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
371 do {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
372 #ifdef HAVE_CLOSESOCKET
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
373 ret = fp->is_socket? closesocket(fp->fd) : close(fp->fd);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
374 #else
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
375 ret = close(fp->fd);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
376 #endif
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
377 } while (ret < 0 && errno == EINTR);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
378 return ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
379 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
380
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
381 static const struct hFILE_backend fd_backend =
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
382 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
383 fd_read, fd_write, fd_seek, fd_flush, fd_close
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
384 };
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
385
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
386 static size_t blksize(int fd)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
387 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
388 struct stat sbuf;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
389 if (fstat(fd, &sbuf) != 0) return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
390 return sbuf.st_blksize;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
391 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
392
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
393 static hFILE *hopen_fd(const char *filename, const char *mode)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
394 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
395 hFILE_fd *fp = NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
396 int fd = open(filename, hfile_oflags(mode), 0666);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
397 if (fd < 0) goto error;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
398
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
399 fp = (hFILE_fd *) hfile_init(sizeof (hFILE_fd), mode, blksize(fd));
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
400 if (fp == NULL) goto error;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
401
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
402 fp->fd = fd;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
403 fp->is_socket = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
404 fp->base.backend = &fd_backend;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
405 return &fp->base;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
406
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
407 error:
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
408 if (fd >= 0) { int save = errno; (void) close(fd); errno = save; }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
409 hfile_destroy((hFILE *) fp);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
410 return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
411 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
412
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
413 hFILE *hdopen(int fd, const char *mode)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
414 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
415 hFILE_fd *fp = (hFILE_fd*) hfile_init(sizeof (hFILE_fd), mode, blksize(fd));
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
416 if (fp == NULL) return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
417
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
418 fp->fd = fd;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
419 fp->is_socket = (strchr(mode, 's') != NULL);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
420 fp->base.backend = &fd_backend;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
421 return &fp->base;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
422 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
423
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
424 static hFILE *hopen_fd_stdinout(const char *mode)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
425 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
426 int fd = (strchr(mode, 'r') != NULL)? STDIN_FILENO : STDOUT_FILENO;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
427 // TODO Set binary mode (for Windows)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
428 return hdopen(fd, mode);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
429 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
430
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
431 int hfile_oflags(const char *mode)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
432 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
433 int rdwr = 0, flags = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
434 const char *s;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
435 for (s = mode; *s; s++)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
436 switch (*s) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
437 case 'r': rdwr = O_RDONLY; break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
438 case 'w': rdwr = O_WRONLY; flags |= O_CREAT | O_TRUNC; break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
439 case 'a': rdwr = O_WRONLY; flags |= O_CREAT | O_APPEND; break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
440 case '+': rdwr = O_RDWR; break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
441 default: break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
442 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
443
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
444 #ifdef O_BINARY
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
445 flags |= O_BINARY;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
446 #endif
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
447
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
448 return rdwr | flags;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
449 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
450
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
451
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
452 /*********************
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
453 * In-memory backend *
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
454 *********************/
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
455
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
456 typedef struct {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
457 hFILE base;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
458 const char *buffer;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
459 size_t length, pos;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
460 } hFILE_mem;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
461
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
462 static ssize_t mem_read(hFILE *fpv, void *buffer, size_t nbytes)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
463 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
464 hFILE_mem *fp = (hFILE_mem *) fpv;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
465 size_t avail = fp->length - fp->pos;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
466 if (nbytes > avail) nbytes = avail;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
467 memcpy(buffer, fp->buffer + fp->pos, nbytes);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
468 fp->pos += nbytes;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
469 return nbytes;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
470 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
471
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
472 static off_t mem_seek(hFILE *fpv, off_t offset, int whence)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
473 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
474 hFILE_mem *fp = (hFILE_mem *) fpv;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
475 size_t absoffset = (offset >= 0)? offset : -offset;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
476 size_t origin;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
477
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
478 switch (whence) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
479 case SEEK_SET: origin = 0; break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
480 case SEEK_CUR: origin = fp->pos; break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
481 case SEEK_END: origin = fp->length; break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
482 default: errno = EINVAL; return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
483 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
484
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
485 if ((offset < 0 && absoffset > origin) ||
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
486 (offset >= 0 && absoffset > fp->length - origin)) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
487 errno = EINVAL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
488 return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
489 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
490
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
491 fp->pos = origin + offset;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
492 return fp->pos;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
493 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
494
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
495 static int mem_close(hFILE *fpv)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
496 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
497 return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
498 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
499
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
500 static const struct hFILE_backend mem_backend =
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
501 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
502 mem_read, NULL, mem_seek, NULL, mem_close
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
503 };
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
504
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
505 static hFILE *hopen_mem(const char *data, const char *mode)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
506 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
507 // TODO Implement write modes, which will require memory allocation
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
508 if (strchr(mode, 'r') == NULL) { errno = EINVAL; return NULL; }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
509
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
510 hFILE_mem *fp = (hFILE_mem *) hfile_init(sizeof (hFILE_mem), mode, 0);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
511 if (fp == NULL) return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
512
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
513 fp->buffer = data;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
514 fp->length = strlen(data);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
515 fp->pos = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
516 fp->base.backend = &mem_backend;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
517 return &fp->base;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
518 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
519
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
520
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
521 /******************************
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
522 * hopen() backend dispatcher *
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
523 ******************************/
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
524
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
525 hFILE *hopen(const char *fname, const char *mode)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
526 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
527 if (strncmp(fname, "http://", 7) == 0 ||
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
528 strncmp(fname, "ftp://", 6) == 0) return hopen_net(fname, mode);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
529 #ifdef HAVE_IRODS
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
530 else if (strncmp(fname, "irods:", 6) == 0) return hopen_irods(fname, mode);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
531 #endif
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
532 else if (strncmp(fname, "data:", 5) == 0) return hopen_mem(fname + 5, mode);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
533 else if (strcmp(fname, "-") == 0) return hopen_fd_stdinout(mode);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
534 else return hopen_fd(fname, mode);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
535 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
536
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
537 int hisremote(const char *fname)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
538 {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
539 // FIXME Make a new backend entry to return this
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
540 if (strncmp(fname, "http://", 7) == 0 ||
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
541 strncmp(fname, "https://", 8) == 0 ||
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
542 strncmp(fname, "ftp://", 6) == 0) return 1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
543 #ifdef HAVE_IRODS
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
544 else if (strncmp(fname, "irods:", 6) == 0) return 1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
545 #endif
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
546 else return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
547 }