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