1 /* The MIT License
2
3 Copyright (c) 2008 Genome Research Ltd (GRL).
4
5 Permission is hereby granted, free of charge, to any person obtaining
6 a copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sublicense, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
12
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 */
25
26 /* Contact: Heng Li <lh3@sanger.ac.uk> */
27 #define FSYNC_ON_FLUSH
28
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <zlib.h>
34 #include <errno.h>
35 #ifdef FSYNC_ON_FLUSH
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
39 #endif
40 #include <sys/resource.h>
41 #include <sys/time.h>
42 #include "utils.h"
43
44 #include "ksort.h"
45 #define pair64_lt(a, b) ((a).x < (b).x || ((a).x == (b).x && (a).y < (b).y))
46 KSORT_INIT(128, pair64_t, pair64_lt)
47 KSORT_INIT(64, uint64_t, ks_lt_generic)
48
49 #include "kseq.h"
50 KSEQ_INIT2(, gzFile, err_gzread)
51
52 /********************
53 * System utilities *
54 ********************/
55
err_xopen_core(const char * func,const char * fn,const char * mode)56 FILE *err_xopen_core(const char *func, const char *fn, const char *mode)
57 {
58 FILE *fp = 0;
59 if (strcmp(fn, "-") == 0)
60 return (strstr(mode, "r"))? stdin : stdout;
61 if ((fp = fopen(fn, mode)) == 0) {
62 err_fatal(func, "fail to open file '%s' : %s", fn, strerror(errno));
63 }
64 return fp;
65 }
66
err_xreopen_core(const char * func,const char * fn,const char * mode,FILE * fp)67 FILE *err_xreopen_core(const char *func, const char *fn, const char *mode, FILE *fp)
68 {
69 if (freopen(fn, mode, fp) == 0) {
70 err_fatal(func, "fail to open file '%s' : %s", fn, strerror(errno));
71 }
72 return fp;
73 }
74
err_xzopen_core(const char * func,const char * fn,const char * mode)75 gzFile err_xzopen_core(const char *func, const char *fn, const char *mode)
76 {
77 gzFile fp;
78 if (strcmp(fn, "-") == 0) {
79 fp = gzdopen(fileno((strstr(mode, "r"))? stdin : stdout), mode);
80 /* According to zlib.h, this is the only reason gzdopen can fail */
81 if (!fp) err_fatal(func, "Out of memory");
82 return fp;
83 }
84 if ((fp = gzopen(fn, mode)) == 0) {
85 err_fatal(func, "fail to open file '%s' : %s", fn, errno ? strerror(errno) : "Out of memory");
86 }
87 return fp;
88 }
89
err_fatal(const char * header,const char * fmt,...)90 void err_fatal(const char *header, const char *fmt, ...)
91 {
92 va_list args;
93 va_start(args, fmt);
94 fprintf(stderr, "[%s] ", header);
95 vfprintf(stderr, fmt, args);
96 fprintf(stderr, "\n");
97 va_end(args);
98 exit(EXIT_FAILURE);
99 }
100
err_fatal_core(const char * header,const char * fmt,...)101 void err_fatal_core(const char *header, const char *fmt, ...)
102 {
103 va_list args;
104 va_start(args, fmt);
105 fprintf(stderr, "[%s] ", header);
106 vfprintf(stderr, fmt, args);
107 fprintf(stderr, " Abort!\n");
108 va_end(args);
109 abort();
110 }
111
_err_fatal_simple(const char * func,const char * msg)112 void _err_fatal_simple(const char *func, const char *msg)
113 {
114 fprintf(stderr, "[%s] %s\n", func, msg);
115 exit(EXIT_FAILURE);
116 }
117
_err_fatal_simple_core(const char * func,const char * msg)118 void _err_fatal_simple_core(const char *func, const char *msg)
119 {
120 fprintf(stderr, "[%s] %s Abort!\n", func, msg);
121 abort();
122 }
123
err_fwrite(const void * ptr,size_t size,size_t nmemb,FILE * stream)124 size_t err_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
125 {
126 size_t ret = fwrite(ptr, size, nmemb, stream);
127 if (ret != nmemb)
128 _err_fatal_simple("fwrite", strerror(errno));
129 return ret;
130 }
131
err_fread_noeof(void * ptr,size_t size,size_t nmemb,FILE * stream)132 size_t err_fread_noeof(void *ptr, size_t size, size_t nmemb, FILE *stream)
133 {
134 size_t ret = fread(ptr, size, nmemb, stream);
135 if (ret != nmemb)
136 {
137 _err_fatal_simple("fread", ferror(stream) ? strerror(errno) : "Unexpected end of file");
138 }
139 return ret;
140 }
141
err_gzread(gzFile file,void * ptr,unsigned int len)142 int err_gzread(gzFile file, void *ptr, unsigned int len)
143 {
144 int ret = gzread(file, ptr, len);
145
146 if (ret < 0)
147 {
148 int errnum = 0;
149 const char *msg = gzerror(file, &errnum);
150 _err_fatal_simple("gzread", Z_ERRNO == errnum ? strerror(errno) : msg);
151 }
152
153 return ret;
154 }
155
err_fseek(FILE * stream,long offset,int whence)156 int err_fseek(FILE *stream, long offset, int whence)
157 {
158 int ret = fseek(stream, offset, whence);
159 if (0 != ret)
160 {
161 _err_fatal_simple("fseek", strerror(errno));
162 }
163 return ret;
164 }
165
err_ftell(FILE * stream)166 long err_ftell(FILE *stream)
167 {
168 long ret = ftell(stream);
169 if (-1 == ret)
170 {
171 _err_fatal_simple("ftell", strerror(errno));
172 }
173 return ret;
174 }
175
err_printf(const char * format,...)176 int err_printf(const char *format, ...)
177 {
178 va_list arg;
179 int done;
180 va_start(arg, format);
181 done = vfprintf(stdout, format, arg);
182 int saveErrno = errno;
183 va_end(arg);
184 if (done < 0) _err_fatal_simple("vfprintf(stdout)", strerror(saveErrno));
185 return done;
186 }
187
err_fprintf(FILE * stream,const char * format,...)188 int err_fprintf(FILE *stream, const char *format, ...)
189 {
190 va_list arg;
191 int done;
192 va_start(arg, format);
193 done = vfprintf(stream, format, arg);
194 int saveErrno = errno;
195 va_end(arg);
196 if (done < 0) _err_fatal_simple("vfprintf", strerror(saveErrno));
197 return done;
198 }
199
err_fputc(int c,FILE * stream)200 int err_fputc(int c, FILE *stream)
201 {
202 int ret = putc(c, stream);
203 if (EOF == ret)
204 {
205 _err_fatal_simple("fputc", strerror(errno));
206 }
207
208 return ret;
209 }
210
err_fputs(const char * s,FILE * stream)211 int err_fputs(const char *s, FILE *stream)
212 {
213 int ret = fputs(s, stream);
214 if (EOF == ret)
215 {
216 _err_fatal_simple("fputs", strerror(errno));
217 }
218
219 return ret;
220 }
221
err_puts(const char * s)222 int err_puts(const char *s)
223 {
224 int ret = puts(s);
225 if (EOF == ret)
226 {
227 _err_fatal_simple("puts", strerror(errno));
228 }
229
230 return ret;
231 }
232
err_fflush(FILE * stream)233 int err_fflush(FILE *stream)
234 {
235 int ret = fflush(stream);
236 if (ret != 0) _err_fatal_simple("fflush", strerror(errno));
237
238 #ifdef FSYNC_ON_FLUSH
239 /* Calling fflush() ensures that all the data has made it to the
240 kernel buffers, but this may not be sufficient for remote filesystems
241 (e.g. NFS, lustre) as an error may still occur while the kernel
242 is copying the buffered data to the file server. To be sure of
243 catching these errors, we need to call fsync() on the file
244 descriptor, but only if it is a regular file. */
245 {
246 struct stat sbuf;
247 if (0 != fstat(fileno(stream), &sbuf))
248 _err_fatal_simple("fstat", strerror(errno));
249
250 if (S_ISREG(sbuf.st_mode))
251 {
252 if (0 != fsync(fileno(stream)))
253 _err_fatal_simple("fsync", strerror(errno));
254 }
255 }
256 #endif
257 return ret;
258 }
259
err_fclose(FILE * stream)260 int err_fclose(FILE *stream)
261 {
262 int ret = fclose(stream);
263 if (ret != 0) _err_fatal_simple("fclose", strerror(errno));
264 return ret;
265 }
266
err_gzclose(gzFile file)267 int err_gzclose(gzFile file)
268 {
269 int ret = gzclose(file);
270 if (Z_OK != ret)
271 {
272 _err_fatal_simple("gzclose", Z_ERRNO == ret ? strerror(errno) : zError(ret));
273 }
274
275 return ret;
276 }
277
278 /*********
279 * Timer *
280 *********/
281
cputime()282 double cputime()
283 {
284 struct rusage r;
285 getrusage(RUSAGE_SELF, &r);
286 return r.ru_utime.tv_sec + r.ru_stime.tv_sec + 1e-6 * (r.ru_utime.tv_usec + r.ru_stime.tv_usec);
287 }
288
realtime()289 double realtime()
290 {
291 struct timeval tp;
292 struct timezone tzp;
293 gettimeofday(&tp, &tzp);
294 return tp.tv_sec + tp.tv_usec * 1e-6;
295 }
296