annotate ezBAMQC/src/htslib/cram/mFILE.c @ 0:dfa3745e5fd8

Uploaded
author youngkim
date Thu, 24 Mar 2016 17:12:52 -0400
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
1 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
2 Copyright (c) 2005-2006, 2008-2009, 2013 Genome Research Ltd.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
3 Author: James Bonfield <jkb@sanger.ac.uk>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
4
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
5 Redistribution and use in source and binary forms, with or without
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
6 modification, are permitted provided that the following conditions are met:
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
7
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
8 1. Redistributions of source code must retain the above copyright notice,
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
9 this list of conditions and the following disclaimer.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
10
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
11 2. Redistributions in binary form must reproduce the above copyright notice,
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
12 this list of conditions and the following disclaimer in the documentation
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
13 and/or other materials provided with the distribution.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
14
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
15 3. Neither the names Genome Research Ltd and Wellcome Trust Sanger
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
16 Institute nor the names of its contributors may be used to endorse or promote
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
17 products derived from this software without specific prior written permission.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
18
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
19 THIS SOFTWARE IS PROVIDED BY GENOME RESEARCH LTD AND CONTRIBUTORS "AS IS" AND
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
22 DISCLAIMED. IN NO EVENT SHALL GENOME RESEARCH LTD OR CONTRIBUTORS BE LIABLE
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
25 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
26 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
27 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
29 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
30
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
31
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
32 #ifdef HAVE_CONFIG_H
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
33 #include "io_lib_config.h"
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
34 #endif
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
35
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
36 #include <stdio.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
37 #include <stdlib.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
38 #include <errno.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
39 #include <string.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
40 #include <sys/types.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
41 #include <sys/stat.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
42 #include <fcntl.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
43 #include <unistd.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
44 #include <stdarg.h>
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
45
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
46 #include "cram/os.h"
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
47 #include "cram/mFILE.h"
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
48 #include "cram/vlen.h"
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
49
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
50 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
51 * This file contains memory-based versions of the most commonly used
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
52 * (by io_lib) stdio functions.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
53 *
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
54 * Actual file IO takes place either on opening or closing an mFILE.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
55 *
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
56 * Coupled to this are a bunch of rather scary macros which can be obtained
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
57 * by including stdio_hack.h. It is recommended though that you use mFILE.h
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
58 * instead and replace fopen with mfopen (etc). This is more or less
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
59 * mandatory if you wish to use both FILE and mFILE structs in a single file.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
60 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
61
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
62 static mFILE *m_channel[3]; /* stdin, stdout and stderr fakes */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
63
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
64 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
65 * Reads the entirety of fp into memory. If 'fn' exists it is the filename
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
66 * associated with fp. This will be used for more optimal reading (via a
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
67 * stat to identify the size and a single read). Otherwise we use successive
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
68 * reads until EOF.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
69 *
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
70 * Returns a malloced buffer on success of length *size
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
71 * NULL on failure
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
72 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
73 static char *mfload(FILE *fp, const char *fn, size_t *size, int binary) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
74 struct stat sb;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
75 char *data = NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
76 size_t allocated = 0, used = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
77 int bufsize = 8192;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
78
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
79 #ifdef _WIN32
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
80 if (binary)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
81 _setmode(_fileno(fp), _O_BINARY);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
82 else
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
83 _setmode(_fileno(fp), _O_TEXT);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
84 #endif
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
85
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
86 if (fn && -1 != stat(fn, &sb)) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
87 data = malloc(allocated = sb.st_size);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
88 bufsize = sb.st_size;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
89 } else {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
90 fn = NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
91 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
92
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
93 do {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
94 size_t len;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
95 if (used + bufsize > allocated) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
96 allocated += bufsize;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
97 data = realloc(data, allocated);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
98 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
99 len = fread(data + used, 1, allocated - used, fp);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
100 if (len > 0)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
101 used += len;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
102 } while (!feof(fp) && (fn == NULL || used < sb.st_size));
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
103
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
104 *size = used;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
105
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
106 return data;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
107 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
108
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
109 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
110 * Creates and returns m_channel[0].
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
111 * We initialise this on the first attempted read, which then slurps in
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
112 * all of stdin until EOF is met.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
113 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
114 mFILE *mstdin(void) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
115 if (m_channel[0])
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
116 return m_channel[0];
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
117
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
118 m_channel[0] = mfcreate(NULL, 0);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
119 if (NULL == m_channel[0]) return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
120 m_channel[0]->fp = stdin;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
121 return m_channel[0];
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
122 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
123
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
124 static void init_mstdin(void) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
125 static int done_stdin = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
126 if (done_stdin)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
127 return;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
128
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
129 m_channel[0]->data = mfload(stdin, NULL, &m_channel[0]->size, 1);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
130 m_channel[0]->mode = MF_READ;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
131 done_stdin = 1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
132 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
133
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
134 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
135 * Creates and returns m_channel[1]. This is the fake for stdout. It starts as
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
136 * an empty buffer which is physically written out only when mfflush or
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
137 * mfclose are called.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
138 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
139 mFILE *mstdout(void) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
140 if (m_channel[1])
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
141 return m_channel[1];
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
142
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
143 m_channel[1] = mfcreate(NULL, 0);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
144 if (NULL == m_channel[1]) return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
145 m_channel[1]->fp = stdout;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
146 m_channel[1]->mode = MF_WRITE;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
147 return m_channel[1];
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
148 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
149
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
150 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
151 * Stderr as an mFILE.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
152 * The code handles stderr by returning m_channel[2], but also checking
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
153 * for stderr in fprintf (the common usage of it) to auto-flush.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
154 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
155 mFILE *mstderr(void) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
156 if (m_channel[2])
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
157 return m_channel[2];
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
158
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
159 m_channel[2] = mfcreate(NULL, 0);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
160 if (NULL == m_channel[2]) return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
161 m_channel[2]->fp = stderr;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
162 m_channel[2]->mode = MF_WRITE;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
163 return m_channel[2];
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
164 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
165
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
166
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
167 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
168 * For creating existing mFILE pointers directly from memory buffers.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
169 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
170 mFILE *mfcreate(char *data, int size) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
171 mFILE *mf = (mFILE *)malloc(sizeof(*mf));
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
172 if (NULL == mf) return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
173 mf->fp = NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
174 mf->data = data;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
175 mf->alloced = size;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
176 mf->size = size;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
177 mf->eof = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
178 mf->offset = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
179 mf->flush_pos = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
180 mf->mode = MF_READ | MF_WRITE;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
181 return mf;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
182 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
183
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
184 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
185 * Recreate an existing mFILE to house new data/size.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
186 * It also rewinds the file.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
187 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
188 void mfrecreate(mFILE *mf, char *data, int size) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
189 if (mf->data)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
190 free(mf->data);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
191 mf->data = data;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
192 mf->size = size;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
193 mf->alloced = size;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
194 mf->eof = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
195 mf->offset = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
196 mf->flush_pos = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
197 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
198
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
199
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
200 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
201 * Creates a new mFILE to contain the contents of the FILE pointer.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
202 * This mFILE is purely for in-memory operations and has no links to the
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
203 * original FILE* it came from. It also doesn't close the FILE pointer.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
204 * Consider using mfreopen() is you need different behaviour.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
205 *
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
206 * Returns mFILE * on success
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
207 * NULL on failure.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
208 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
209 mFILE *mfcreate_from(const char *path, const char *mode_str, FILE *fp) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
210 mFILE *mf;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
211
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
212 /* Open using mfreopen() */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
213 if (NULL == (mf = mfreopen(path, mode_str, fp)))
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
214 return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
215
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
216 /* Disassociate from the input stream */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
217 mf->fp = NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
218
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
219 return mf;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
220 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
221
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
222 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
223 * Converts a FILE * to an mFILE *.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
224 * Use this for wrapper functions to turn external prototypes requring
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
225 * FILE * as an argument into internal code using mFILE *.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
226 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
227 mFILE *mfreopen(const char *path, const char *mode_str, FILE *fp) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
228 mFILE *mf;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
229 int r = 0, w = 0, a = 0, b = 0, x = 0, mode = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
230
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
231 /* Parse mode:
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
232 * r = read file contents (if truncated => don't read)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
233 * w = write on close
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
234 * a = position at end of buffer
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
235 * x = position at same location as the original fp, don't seek on flush
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
236 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
237 if (strchr(mode_str, 'r'))
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
238 r = 1, mode |= MF_READ;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
239 if (strchr(mode_str, 'w'))
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
240 w = 1, mode |= MF_WRITE | MF_TRUNC;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
241 if (strchr(mode_str, 'a'))
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
242 w = a = 1, mode |= MF_WRITE | MF_APPEND;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
243 if (strchr(mode_str, 'b'))
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
244 b = 1, mode |= MF_BINARY;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
245 if (strchr(mode_str, 'x'))
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
246 x = 1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
247 if (strchr(mode_str, '+')) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
248 w = 1, mode |= MF_READ | MF_WRITE;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
249 if (a)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
250 r = 1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
251 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
252
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
253 if (r) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
254 mf = mfcreate(NULL, 0);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
255 if (NULL == mf) return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
256 if (!(mode & MF_TRUNC)) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
257 mf->data = mfload(fp, path, &mf->size, b);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
258 mf->alloced = mf->size;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
259 if (!a)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
260 fseek(fp, 0, SEEK_SET);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
261 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
262 } else if (w) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
263 /* Write - initialise the data structures */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
264 mf = mfcreate(NULL, 0);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
265 if (NULL == mf) return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
266 } else {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
267 fprintf(stderr, "Must specify either r, w or a for mode\n");
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
268 return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
269 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
270 mf->fp = fp;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
271 mf->mode = mode;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
272
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
273 if (x) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
274 mf->mode |= MF_MODEX;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
275 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
276
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
277 if (a) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
278 mf->flush_pos = mf->size;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
279 fseek(fp, 0, SEEK_END);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
280 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
281
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
282 return mf;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
283 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
284
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
285 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
286 * Opens a file. If we have read access (r or a+) then it loads the entire
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
287 * file into memory. If We have write access then the pathname is stored.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
288 * We do not actually write until an mfclose, which then checks this pathname.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
289 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
290 mFILE *mfopen(const char *path, const char *mode) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
291 FILE *fp;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
292
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
293 if (NULL == (fp = fopen(path, mode)))
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
294 return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
295 return mfreopen(path, mode, fp);
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 * Closes an mFILE. If the filename is known (implying write access) then this
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
300 * also writes the data to disk.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
301 *
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
302 * Stdout is handled by calling mfflush which writes to stdout if appropriate.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
303 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
304 int mfclose(mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
305 if (!mf)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
306 return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
307
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
308 mfflush(mf);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
309
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
310 if (mf->fp)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
311 fclose(mf->fp);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
312
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
313 mfdestroy(mf);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
314
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
315 return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
316 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
317
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
318 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
319 * Closes the file pointer contained within the mFILE without destroying
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
320 * the in-memory data.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
321 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
322 int mfdetach(mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
323 if (!mf)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
324 return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
325
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
326 mfflush(mf);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
327
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
328 if (mf->fp) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
329 fclose(mf->fp);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
330 mf->fp = NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
331 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
332
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
333 return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
334 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
335
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
336 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
337 * Destroys an mFILE structure but does not flush or close it
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
338 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
339 int mfdestroy(mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
340 if (!mf)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
341 return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
342
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
343 if (mf->data)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
344 free(mf->data);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
345 free(mf);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
346
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
347 return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
348 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
349
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
350 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
351 * Steals that data out of an mFILE. The mFILE itself will be closed.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
352 * It is up to the caller to free the stolen buffer. If size_out is
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
353 * not NULL, mf->size will be stored in it.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
354 * This is more-or-less the opposite of mfcreate().
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
355 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
356
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
357 void *mfsteal(mFILE *mf, size_t *size_out) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
358 void *data;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
359
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
360 if (!mf) return NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
361
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
362 data = mf->data;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
363
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
364 if (NULL != size_out) *size_out = mf->size;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
365
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
366 mfdetach(mf);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
367 mf->data = NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
368 mfdestroy(mf);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
369
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
370 return data;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
371 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
372
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
373 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
374 * Seek/tell functions. Nothing more than updating and reporting an
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
375 * in-memory index. NB we can seek on stdin or stdout even provided we
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
376 * haven't been flushing.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
377 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
378 int mfseek(mFILE *mf, long offset, int whence) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
379 switch (whence) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
380 case SEEK_SET:
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
381 mf->offset = offset;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
382 break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
383 case SEEK_CUR:
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
384 mf->offset += offset;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
385 break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
386 case SEEK_END:
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
387 mf->offset = mf->size + offset;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
388 break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
389 default:
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
390 errno = EINVAL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
391 return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
392 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
393
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
394 mf->eof = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
395 return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
396 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
397
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
398 long mftell(mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
399 return mf->offset;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
400 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
401
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
402 void mrewind(mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
403 mf->offset = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
404 mf->eof = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
405 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
406
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
407 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
408 * mftruncate is not directly a translation of ftruncate as the latter
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
409 * takes a file descriptor instead of a FILE *. It performs the analogous
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
410 * role though.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
411 *
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
412 * If offset is -1 then the file is truncated to be the current file
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
413 * offset.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
414 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
415 void mftruncate(mFILE *mf, long offset) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
416 mf->size = offset != -1 ? offset : mf->offset;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
417 if (mf->offset > mf->size)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
418 mf->offset = mf->size;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
419 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
420
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
421 int mfeof(mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
422 return mf->eof;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
423 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
424
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
425 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
426 * mFILE read/write functions. Basically these turn fread/fwrite syntax
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
427 * into memcpy statements, with appropriate memory handling for writing.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
428 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
429 size_t mfread(void *ptr, size_t size, size_t nmemb, mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
430 size_t len;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
431 char *cptr = (char *)ptr;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
432
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
433 if (mf == m_channel[0]) init_mstdin();
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
434
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
435 if (mf->size <= mf->offset)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
436 return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
437
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
438 len = size * nmemb <= mf->size - mf->offset
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
439 ? size * nmemb
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
440 : mf->size - mf->offset;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
441 if (!size)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
442 return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
443
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
444 memcpy(cptr, &mf->data[mf->offset], len);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
445 mf->offset += len;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
446
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
447 if (len != size * nmemb) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
448 mf->eof = 1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
449 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
450
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
451 return len / size;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
452 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
453
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
454 size_t mfwrite(void *ptr, size_t size, size_t nmemb, mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
455 if (!(mf->mode & MF_WRITE))
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
456 return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
457
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
458 /* Append mode => forced all writes to end of file */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
459 if (mf->mode & MF_APPEND)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
460 mf->offset = mf->size;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
461
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
462 /* Make sure we have enough room */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
463 while (size * nmemb + mf->offset > mf->alloced) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
464 size_t new_alloced = mf->alloced ? mf->alloced * 2 : 1024;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
465 void * new_data = realloc(mf->data, new_alloced);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
466 if (NULL == new_data) return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
467 mf->alloced = new_alloced;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
468 mf->data = new_data;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
469 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
470
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
471 /* Record where we need to reflush from */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
472 if (mf->offset < mf->flush_pos)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
473 mf->flush_pos = mf->offset;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
474
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
475 /* Copy the data over */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
476 memcpy(&mf->data[mf->offset], ptr, size * nmemb);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
477 mf->offset += size * nmemb;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
478 if (mf->size < mf->offset)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
479 mf->size = mf->offset;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
480
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
481 return nmemb;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
482 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
483
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
484 int mfgetc(mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
485 if (mf == m_channel[0]) init_mstdin();
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
486 if (mf->offset < mf->size) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
487 return (unsigned char)mf->data[mf->offset++];
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
488 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
489
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
490 mf->eof = 1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
491 return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
492 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
493
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
494 int mungetc(int c, mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
495 if (mf->offset > 0) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
496 mf->data[--mf->offset] = c;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
497 return c;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
498 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
499
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
500 mf->eof = 1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
501 return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
502 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
503
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
504 char *mfgets(char *s, int size, mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
505 int i;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
506
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
507 if (mf == m_channel[0]) init_mstdin();
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
508 *s = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
509 for (i = 0; i < size-1;) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
510 if (mf->offset < mf->size) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
511 s[i] = mf->data[mf->offset++];
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
512 if (s[i++] == '\n')
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
513 break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
514 } else {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
515 mf->eof = 1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
516 break;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
517 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
518 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
519
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
520 s[i] = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
521 return i ? s : NULL;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
522 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
523
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
524 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
525 * Flushes an mFILE. If this is a real open of a file in write mode then
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
526 * mFILE->fp will be set. We then write out any new data in mFILE since the
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
527 * last flush. We cannot tell what may have been modified as we don't keep
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
528 * track of that, so we typically rewrite out the entire file contents between
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
529 * the last flush_pos and the end of file.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
530 *
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
531 * For stderr/stdout we also reset the offsets so we cannot modify things
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
532 * we've already output.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
533 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
534 int mfflush(mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
535 if (!mf->fp)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
536 return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
537
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
538 /* FIXME: only do this when opened in write mode */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
539 if (mf == m_channel[1] || mf == m_channel[2]) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
540 if (mf->flush_pos < mf->size) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
541 size_t bytes = mf->size - mf->flush_pos;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
542 if (fwrite(mf->data + mf->flush_pos, 1, bytes, mf->fp) < bytes)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
543 return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
544 if (0 != fflush(mf->fp))
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
545 return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
546 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
547
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
548 /* Stdout & stderr are non-seekable streams so throw away the data */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
549 mf->offset = mf->size = mf->flush_pos = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
550 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
551
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
552 /* only flush when opened in write mode */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
553 if (mf->mode & MF_WRITE) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
554 if (mf->flush_pos < mf->size) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
555 size_t bytes = mf->size - mf->flush_pos;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
556 if (!(mf->mode & MF_MODEX)) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
557 fseek(mf->fp, mf->flush_pos, SEEK_SET);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
558 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
559 if (fwrite(mf->data + mf->flush_pos, 1, bytes, mf->fp) < bytes)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
560 return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
561 if (0 != fflush(mf->fp))
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
562 return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
563 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
564 if (ftell(mf->fp) != -1 &&
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
565 ftruncate(fileno(mf->fp), ftell(mf->fp)) == -1)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
566 return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
567 mf->flush_pos = mf->size;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
568 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
569
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
570 return 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
571 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
572
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
573 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
574 * A wrapper around vsprintf() to write to an mFILE. This also uses vflen() to
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
575 * estimate how many additional bytes of storage will be required for the
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
576 * vsprintf to work.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
577 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
578 int mfprintf(mFILE *mf, char *fmt, ...) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
579 int ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
580 size_t est_length;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
581 va_list args;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
582
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
583 va_start(args, fmt);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
584 est_length = vflen(fmt, args);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
585 va_end(args);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
586 while (est_length + mf->offset > mf->alloced) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
587 size_t new_alloced = mf->alloced ? mf->alloced * 2 : 1024;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
588 void * new_data = realloc(mf->data, new_alloced);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
589 if (NULL == new_data) return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
590 mf->alloced = new_alloced;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
591 mf->data = new_data;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
592 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
593
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
594 va_start(args, fmt);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
595 ret = vsprintf(&mf->data[mf->offset], fmt, args);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
596 va_end(args);
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
597
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
598 if (ret > 0) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
599 mf->offset += ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
600 if (mf->size < mf->offset)
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
601 mf->size = mf->offset;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
602 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
603
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
604 if (mf->fp == stderr) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
605 /* Auto-flush for stderr */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
606 if (0 != mfflush(mf)) return -1;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
607 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
608
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
609 return ret;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
610 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
611
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
612 /*
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
613 * Converts an mFILE from binary to ascii mode by replacing all
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
614 * cr-nl with nl.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
615 *
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
616 * Primarily used on windows when we've uncompressed a binary file which
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
617 * happens to be a text file (eg Experiment File). Previously we would have
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
618 * seeked back to the start and used _setmode(fileno(fp), _O_TEXT).
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
619 *
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
620 * Side effect: resets offset and flush_pos back to the start.
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
621 */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
622 void mfascii(mFILE *mf) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
623 size_t p1, p2;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
624
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
625 for (p1 = p2 = 1; p1 < mf->size; p1++, p2++) {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
626 if (mf->data[p1] == '\n' && mf->data[p1-1] == '\r') {
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
627 p2--; /* delete the \r */
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
628 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
629 mf->data[p2] = mf->data[p1];
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
630 }
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
631 mf->size = p2;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
632
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
633 mf->offset = mf->flush_pos = 0;
dfa3745e5fd8 Uploaded
youngkim
parents:
diff changeset
634 }