]> git.donarmstrong.com Git - fastq-tools.git/blob - src/fastq-grep.c
Fix inverted match option in fastq-grep.
[fastq-tools.git] / src / fastq-grep.c
1
2 /*
3  * This file is part of fastq-tools.
4  *
5  * Copyright (c) 2011 by Daniel C. Jones <dcjones@cs.washington.edu>
6  *
7  * fastq-grep :
8  * Regular expression searches of the sequences within a FASTQ file.
9  *
10  */
11
12
13 #include "common.h"
14 #include "parse.h"
15 #include <stdio.h>
16 #include <string.h>
17 #include <getopt.h>
18 #include <zlib.h>
19 #include <pcre.h>
20
21
22 #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
23 #  include <fcntl.h>
24 #  include <io.h>
25 #  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
26 #else
27 #  define SET_BINARY_MODE(file)
28 #endif
29
30
31 static const char* prog_name = "fastq-grep";
32
33
34 void print_help()
35 {
36     fprintf(stdout, 
37 "fastq-grep [OPTION]... PATTERN [FILE]...\n"
38 "Search for PATTERN in the read sequences in each FILE or standard input.\n"
39 "PATTERN, by default, is a perl compatible regular expression.\n\n"
40 "Options:\n"
41 "  -i, --id                match the read id (by default, sequence is matched)\n"
42 "  -v, --invert-match      select nonmatching entries\n"
43 "  -c, --count             output only the number of matching sequences\n"
44 "  -h, --help              print this message\n"
45 "  -V, --version           output version information and exit\n"
46     );
47 }
48
49 static int invert_flag;
50 static int count_flag;
51 static int id_flag;
52
53
54
55 void fastq_grep(FILE* fin, FILE* fout, pcre* re)
56 {
57     int rc;
58     int ovector[3];
59     size_t count = 0;
60
61     fastq_t* fqf = fastq_open(fin);
62     seq_t* seq = fastq_alloc_seq();
63
64     while (fastq_next(fqf, seq)) {
65
66         rc = pcre_exec(re,          /* pattern */
67                        NULL,        /* extra data */
68                        id_flag ? seq->id1.s : seq->seq.s,
69                        id_flag ? seq->id1.n : seq->seq.n,
70                        0,           /* subject offset */
71                        0,           /* options */
72                        ovector,     /* output vector */
73                        3         ); /* output vector length */
74
75         if ((invert_flag && rc == PCRE_ERROR_NOMATCH) || (!invert_flag && rc >= 0)) {
76             if (count_flag) count++;
77             else            fastq_print(fout, seq);
78         }
79     }
80
81     fastq_free_seq(seq);
82     fastq_close(fqf);
83
84     if (count_flag) fprintf(fout, "%zu\n", count);
85 }
86
87
88
89 int main(int argc, char* argv[])
90 {
91     SET_BINARY_MODE(stdin);
92     SET_BINARY_MODE(stdout);
93
94     const char* pat;
95     pcre* re;
96     const char* pat_error;
97     int pat_error_offset;
98
99     FILE*  fin;
100
101
102     invert_flag  = 0;
103     count_flag   = 0;
104     id_flag      = 0;
105
106     int opt;
107     int opt_idx;
108
109
110     static struct option long_options[] =
111         { 
112           {"id",           no_argument, &id_flag,     1},
113           {"invert-match", no_argument, &invert_flag, 1},
114           {"count",        no_argument, &count_flag,  1},
115           {"help",         no_argument, NULL, 'h'},
116           {"version",      no_argument, NULL, 'V'},
117           {0, 0, 0, 0}
118         };
119
120     while (1) {
121         opt = getopt_long(argc, argv, "ivchV", long_options, &opt_idx);
122
123         if( opt == -1 ) break;
124
125         switch (opt) {
126             case 0:
127                 if (long_options[opt_idx].flag != 0) break;
128                 if (optarg) {
129                 }
130                 break;
131
132             case 'i':
133                 id_flag = 1;
134                 break;
135
136             case 'v':
137                 invert_flag = 1;
138                 break;
139
140             case 'c':
141                 count_flag = 1;
142                 break;
143
144             case 'h':
145                 print_help();
146                 return 0;
147
148             case 'V':
149                 print_version(stdout, prog_name);
150                 return 0;
151
152             case '?':
153                 return 1;
154
155             default:
156                 abort();
157         }
158     }
159
160     if (optind >= argc) {
161         fprintf(stderr, "A pattern must be specified.\n");
162         return 1;
163     }
164
165     pat = argv[optind++];
166     re = pcre_compile( pat, PCRE_CASELESS, &pat_error, &pat_error_offset, NULL );
167
168
169     if (re == NULL) {
170         fprintf(stderr, "Syntax error in PCRE pattern at offset: %d: %s\n",
171                 pat_error_offset, pat_error );
172         return 1;
173     }
174
175
176     if (optind >= argc || (argc - optind == 1 && strcmp(argv[optind],"-") == 0)) {
177         fastq_grep(stdin, stdout, re);
178     }
179     else {
180         for (; optind < argc; optind++) {
181             fin = fopen(argv[optind], "rb");
182             if (fin == NULL) {
183                 fprintf(stderr, "No such file '%s'.\n", argv[optind]);
184                 continue;
185             }
186
187             fastq_grep(fin, stdout, re);
188
189             fclose(fin);
190         }
191     }
192
193     pcre_free(re);
194
195     return 0;
196 }
197
198
199