Imported Upstream version 0.1.0
[tabix.git] / bgzip.c
1 /* The MIT License
2
3    Copyright (c) 2008 Broad Institute / Massachusetts Institute of Technology
4
5    Permission is hereby granted, free of charge, to any person obtaining a copy
6    of this software and associated documentation files (the "Software"), to deal
7    in the Software without restriction, including without limitation the rights
8    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9    copies of the Software, and to permit persons to whom the Software is
10    furnished to do so, subject to the following conditions:
11
12    The above copyright notice and this permission notice shall be included in
13    all copies or substantial portions of the Software.
14
15    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21    THE SOFTWARE.
22 */
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <sys/select.h>
31 #include "bgzf.h"
32
33 static const int WINDOW_SIZE = 64 * 1024;
34
35 static int is_ready(int fd)
36 {
37         fd_set fdset;
38         struct timeval timeout;
39         FD_ZERO(&fdset);
40         FD_SET(fd, &fdset);
41         timeout.tv_sec = 0; timeout.tv_usec = 100000;
42         return select(1, &fdset, NULL, NULL, &timeout) == 1 ? 1 : 0;
43 }
44
45 static int bgzip_main_usage()
46 {
47         fprintf(stderr, "\n");
48         fprintf(stderr, "Usage:   bgzip [options] [file] ...\n\n");
49         fprintf(stderr, "Options: -c      write on standard output, keep original files unchanged\n");
50         fprintf(stderr, "         -d      decompress\n");
51         fprintf(stderr, "         -b INT  decompress at virtual file pointer INT\n");
52         fprintf(stderr, "         -s INT  decompress INT bytes in the uncompressed file\n");
53         fprintf(stderr, "         -h      give this help\n");
54         fprintf(stderr, "\n");
55         return 1;
56 }
57
58 static int write_open(const char *fn, int is_forced)
59 {
60         int fd = -1;
61         char c;
62         if (!is_forced) {
63                 if ((fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0666)) < 0 && errno == EEXIST) {
64                         fprintf(stderr, "[bgzip] %s already exists; do you wish to overwrite (y or n)? ", fn);
65                         scanf("%c", &c);
66                         if (c != 'Y' && c != 'y') {
67                                 fprintf(stderr, "[bgzip] not overwritten\n");
68                                 exit(1);
69                         }
70                 }
71         }
72         if (fd < 0) {
73                 if ((fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
74                         fprintf(stderr, "[bgzip] %s: Fail to write\n", fn);
75                         exit(1);
76                 }
77         }
78         return fd;
79 }
80
81 static void fail(BGZF* fp)
82 {
83     fprintf(stderr, "Error: %s\n", fp->error);
84     exit(1);
85 }
86
87 int main(int argc, char **argv)
88 {
89         int c, compress, pstdout, is_forced;
90         BGZF *fp;
91         void *buffer;
92         long start, end, size;
93
94         compress = 1; pstdout = 0; start = 0; size = -1; end = -1; is_forced = 0;
95         while((c  = getopt(argc, argv, "cdhfb:s:")) >= 0){
96                 switch(c){
97                 case 'h': return bgzip_main_usage();
98                 case 'd': compress = 0; break;
99                 case 'c': pstdout = 1; break;
100                 case 'b': start = atol(optarg); break;
101                 case 's': size = atol(optarg); break;
102                 case 'f': is_forced = 1; break;
103                 }
104         }
105         if (size >= 0) end = start + size;
106         if (end >= 0 && end < start) {
107                 fprintf(stderr, "[bgzip] Illegal region: [%ld, %ld]\n", start, end);
108                 return 1;
109         }
110         if (compress == 1) {
111                 int f_src, f_dst = -1;
112                 if (is_ready(fileno(stdin))) pstdout = 1;
113                 if (argc > optind && !pstdout) {
114                         if ((f_src = open(argv[optind], O_RDONLY)) < 0) {
115                                 fprintf(stderr, "[bgzip] Cannot open file: %s\n", argv[optind]);
116                                 return 1;
117                         }
118                         if (pstdout) {
119                                 f_dst = fileno(stdout);
120                         } else {
121                                 char *name = malloc(sizeof(strlen(argv[optind]) + 5));
122                                 strcpy(name, argv[optind]);
123                                 strcat(name, ".gz");
124                                 f_dst = write_open(name, is_forced);
125                                 if (f_dst < 0) return 1;
126                                 free(name);
127                         }
128                 } else if (pstdout) { 
129                         f_src = fileno(stdin);
130                         f_dst = fileno(stdout);
131                 } else return bgzip_main_usage();
132                 fp = bgzf_fdopen(f_dst, "w");
133                 buffer = malloc(WINDOW_SIZE);
134                 while ((c = read(f_src, buffer, WINDOW_SIZE)) > 0)
135                         if (bgzf_write(fp, buffer, c) < 0) fail(fp);
136                 // f_dst will be closed here
137                 if (bgzf_close(fp) < 0) fail(fp);
138                 if (argc > optind) unlink(argv[optind]);
139                 free(buffer);
140                 close(f_src);
141                 return 0;
142         } else {
143                 int f_dst, is_stdin = 0;
144                 if (argc == optind) pstdout = 1;
145                 if (is_ready(fileno(stdin))) is_stdin = 1;
146                 if (argc <= optind && !is_stdin) return bgzip_main_usage();
147                 if (argc > optind && !pstdout) {
148                         char *name;
149                         if (strstr(argv[optind], ".gz") - argv[optind] != strlen(argv[optind]) - 3) {
150                                 fprintf(stderr, "[bgzip] %s: unknown suffix -- ignored\n", argv[optind]);
151                                 return 1;
152                         }
153                         name = strdup(argv[optind]);
154                         name[strlen(name) - 3] = '\0';
155                         f_dst = write_open(name, is_forced);
156                         free(name);
157                 } else f_dst = fileno(stdout);
158                 fp = (argc == optind)? bgzf_fdopen(fileno(stdin), "r") : bgzf_open(argv[optind], "r");
159                 if (fp == NULL) {
160                         fprintf(stderr, "[bgzip] Could not open file: %s\n", argv[optind]);
161                         return 1;
162                 }
163                 buffer = malloc(WINDOW_SIZE);
164                 if (bgzf_seek(fp, start, SEEK_SET) < 0) fail(fp);
165                 while (1) {
166                         if (end < 0) c = bgzf_read(fp, buffer, WINDOW_SIZE);
167                         else c = bgzf_read(fp, buffer, (end - start > WINDOW_SIZE)? WINDOW_SIZE:(end - start));
168                         if (c == 0) break;
169                         if (c < 0) fail(fp);
170                         start += c;
171                         write(f_dst, buffer, c);
172                         if (end >= 0 && start >= end) break;
173                 }
174                 free(buffer);
175                 if (bgzf_close(fp) < 0) fail(fp);
176                 if (!pstdout) unlink(argv[optind]);
177                 return 0;
178         }
179 }