]> git.donarmstrong.com Git - fastq-tools.git/blob - src/fastq-grep.c
a new and improved parser
[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 "fastq-common.h"
14 #include "fastq-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 void print_help()
32 {
33     fprintf( stderr, 
34 "fastq-grep [OPTION]... PATTERN [FILE]...\n"
35 "Search for PATTERN in the read sequences in each FILE or standard input.\n"
36 "PATTERN, by default, is a perl compatible regular expression.\n\n"
37 "Options:\n"
38 "  -h, --help              print this message\n"
39 "  -v, --invert-match      select nonmatching entries\n"
40 "  -c, --count             output only the number of matching sequences\n"
41     );
42 }
43
44 static int invert_flag;
45 static int help_flag;
46 static int count_flag;
47
48
49
50 void print_fastq_entry(FILE* fout, seq_t* seq)
51 {
52     fprintf(fout, "@%s\n%s\n+%s\n%s\n",
53                   seq->id1.s,
54                   seq->seq.s,
55                   seq->id2.s,
56                   seq->qual.s );
57 }
58
59
60 void fastq_grep(FILE* fin, FILE* fout, pcre* re)
61 {
62     int rc;
63     int ovector[3];
64     size_t count = 0;
65
66     fastq_t* fqf = fastq_open(fin);
67     seq_t* seq = fastq_alloc_seq();
68
69     while (fastq_next(fqf, seq)) {
70         rc = pcre_exec(re,          /* pattern */
71                        NULL,        /* extre data */
72                        seq->seq.s,  /* subject */
73                        seq->seq.n,  /* subject length */
74                        0,           /* subject offset */
75                        0,           /* options */
76                        ovector,     /* output vector */
77                        3         ); /* output vector length */
78
79         if ((invert_flag && rc == PCRE_ERROR_NOMATCH) || rc >= 0) {
80             if (count_flag) count++;
81             else            print_fastq_entry(fout, seq);
82         }
83     }
84
85     fastq_free_seq(seq);
86     fastq_close(fqf);
87
88     if (count_flag) fprintf(fout, "%zu\n", count);
89 }
90
91
92
93 int main(int argc, char* argv[])
94 {
95     SET_BINARY_MODE(stdin);
96     SET_BINARY_MODE(stdout);
97
98     const char* pat;
99     pcre* re;
100     const char* pat_error;
101     int pat_error_offset;
102
103     FILE*  fin;
104
105
106     invert_flag  = 0;
107     help_flag    = 0;
108     count_flag   = 0;
109
110     int opt;
111     int opt_idx;
112
113
114     static struct option long_options[] =
115         { 
116           {"help", no_argument, &help_flag, 1},
117           {"invert-match", no_argument, &invert_flag, 1},
118           {"count", no_argument, &count_flag, 1},
119           {0, 0, 0, 0}
120         };
121
122     while (1) {
123         opt = getopt_long(argc, argv, "hvc", long_options, &opt_idx);
124
125         if( opt == -1 ) break;
126
127         switch (opt) {
128             case 0:
129                 if (long_options[opt_idx].flag != 0) break;
130                 if (optarg) {
131                 }
132                 break;
133
134             case 'h':
135                 help_flag = 1;
136                 break;
137
138             case 'v':
139                 invert_flag = 1;
140                 break;
141
142             case 'c':
143                 count_flag = 1;
144                 break;
145
146             case '?':
147                 return 1;
148
149             default:
150                 abort();
151         }
152     }
153
154     if (help_flag) {
155         print_help();
156         return 0;
157     }
158
159     if (optind >= argc) {
160         fprintf(stderr, "A pattern must be specified.\n");
161         return 1;
162     }
163
164     pat = argv[optind++];
165     re = pcre_compile( pat, PCRE_CASELESS, &pat_error, &pat_error_offset, NULL );
166
167
168     if (re == NULL) {
169         fprintf(stderr, "Syntax error in PCRE pattern at offset: %d: %s\n",
170                 pat_error_offset, pat_error );
171         return 1;
172     }
173
174
175     if (optind >= argc || (argc - optind == 1 && strcmp(argv[optind],"-") == 0)) {
176         fastq_grep(stdin, stdout, re);
177     }
178     else {
179         for (; optind < argc; optind++) {
180             fin = fopen(argv[optind], "rb");
181             if (fin == NULL) {
182                 fprintf(stderr, "No such file '%s'.\n", argv[optind]);
183                 continue;
184             }
185
186             fastq_grep(fin, stdout, re);
187
188             fclose(fin);
189         }
190     }
191
192     pcre_free(re);
193
194     return 0;
195 }
196
197
198