source: tags/cvs_2_svn/PROBE_DESIGN/probe_match_parser.cxx

Last change on this file was 2984, checked in by westram, 20 years ago
  • fixed reverse-complement bug (headline parsing)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.2 KB
Line 
1//  ==================================================================== //
2//                                                                       //
3//    File      : probe_match_parser.cxx                                 //
4//    Purpose   : parse the results of a probe match                     //
5//    Time-stamp: <Tue Jul/06/2004 13:41 MET Coder@ReallySoft.de>        //
6//                                                                       //
7//                                                                       //
8//  Coded by Ralf Westram (coder@reallysoft.de) in June 2004             //
9//  Copyright Department of Microbiology (Technical University Munich)   //
10//                                                                       //
11//  Visit our web site at: http://www.arb-home.de/                       //
12//                                                                       //
13//  ==================================================================== //
14
15#include <cstring>
16#include <cstdlib>
17#include <cstdio>
18#include <cctype>
19#include <map>
20
21#include <arbdb.h>
22#include <arbdbt.h>
23
24#define pm_assert(cond) arb_assert(cond)
25
26#include "probe_match_parser.hxx"
27
28using namespace std;
29
30// ---------------
31//      column
32// ---------------
33
34struct column {
35    const char *title;          // column title (pointer into ProbeMatch_impl::headline)
36    int         start_column, end_column;
37
38    column() : title(0), start_column(-1), end_column(-1) { }
39    column(const char *t, int sc, int ec) : title(t), start_column(sc), end_column(ec) { }
40};
41
42// ------------------------
43//      ProbeMatch_impl
44// ------------------------
45
46struct ltstr {
47    bool operator()(const char* s1, const char* s2) const {
48        return strcmp(s1, s2) < 0;
49    }
50};
51
52typedef map<const char*, column, ltstr> ColumnMap;
53
54class ProbeMatch_impl {
55    char      *headline;
56    ColumnMap  columns;
57    int probe_region_offset;    // left index of probe region
58
59
60public:
61    ProbeMatch_impl(const char *headline_, char **errPtr)
62        : headline(0)
63        , probe_region_offset(-1)
64    {
65        pm_assert(headline_);
66        headline = strdup(headline_);
67
68        for (char *tok_start = strtok(headline, " "); tok_start; tok_start = strtok(0, " ")) {
69            char *tok_end = strchr(tok_start, 0)-1;
70
71            int startPos = tok_start-headline;
72            int endPos   = tok_end-headline;
73
74            while (tok_end >= tok_start && tok_end[0] == '-') --tok_end;
75            while (tok_start <= tok_end && tok_start[0] == '-') ++tok_start;
76            pm_assert(tok_start <= tok_end); // otherwise column only contained '-'
77            tok_end[1] = 0;
78
79            columns[tok_start] = column(tok_start, startPos-2, endPos-2); // -2 because headline is 2 shorter than other lines
80        }
81
82        if (columns.empty()) *errPtr = strdup("No columns found");
83    }
84
85    ~ProbeMatch_impl() {
86        free(headline);
87    }
88
89    column *findColumn(const char *columntitle) {
90        ColumnMap::iterator ci = columns.find(columntitle);
91        if (ci == columns.end()) return 0;
92        return &(ci->second);
93    }
94
95    void set_probe_region_offset(int offset) { probe_region_offset = offset; }
96    int get_probe_region_offset() const { return probe_region_offset; }
97};
98
99// -------------------------
100//      ProbeMatchParser
101// -------------------------
102
103ProbeMatchParser::ProbeMatchParser(const char *probe_target, const char *headline)
104    : pimpl(0), init_error(0)
105{
106    if (!headline) {
107        init_error = strdup("No headline given");
108    }
109    else if (!probe_target) {
110        init_error = strdup("No probe target given.");
111    }
112    else {
113        pimpl = new ProbeMatch_impl(headline, &init_error);
114        if (!init_error) {
115            // modify target, so that it matches the target string in headline
116            char *probe_target_copy = GBS_global_string_copy("'%s'", probe_target); // add single quotes
117            for (int i = 0; probe_target_copy[i]; ++i) {
118                probe_target_copy[i] = toupper(probe_target_copy[i]);
119                if (probe_target_copy[i] == 'T') { // replace 'T' by 'U'
120                    probe_target_copy[i] = 'U';
121                }
122            }
123
124            // find that column and
125            column *target_found = pimpl->findColumn(probe_target_copy);
126            if (!target_found) {
127                char *probe_rev_compl = strdup(probe_target_copy);
128                GBT_reverseComplementNucSequence(probe_rev_compl, strlen(probe_rev_compl), 'U');
129                target_found          = pimpl->findColumn(probe_rev_compl);
130                free(probe_rev_compl);
131            }
132
133            if (target_found) {
134                int probe_region_offset = target_found->start_column - 9;
135                pimpl->set_probe_region_offset(probe_region_offset);
136            }
137            else {
138                init_error = GBS_global_string_copy("Probe match parser failed (Could not find target '%s' in headline)", probe_target_copy);
139            }
140            free(probe_target_copy);
141        }
142    }
143}
144
145ProbeMatchParser::~ProbeMatchParser() {
146    free(init_error);
147}
148
149bool ProbeMatchParser::getColumnRange(const char *columnName, int *startCol, int *endCol) const {
150    pm_assert(!init_error);
151    column *col = pimpl->findColumn(columnName);
152    if (!col) return false;
153
154    *startCol = col->start_column;
155    *endCol   = col->end_column;
156    return true;
157}
158
159bool ProbeMatchParser::is_gene_result() const {
160    pm_assert(!init_error);
161    return pimpl->findColumn("organism") && pimpl->findColumn("genename");
162}
163
164int ProbeMatchParser::get_probe_region_offset() const {
165    pm_assert(!init_error);
166    return pimpl->get_probe_region_offset();
167}
168
169// -------------------------
170//      ParsedProbeMatch
171// -------------------------
172
173ParsedProbeMatch::ParsedProbeMatch(const char *match_, const ProbeMatchParser& parser_)
174    : parser(parser_), match(0), error(0)
175{
176    if (match_) match = strdup(match_);
177    else error = "No match given";
178}
179
180ParsedProbeMatch::~ParsedProbeMatch() {
181    free(match);
182}
183
184inline char *strpartdup(const char *str, int c1, int c2) {
185    int len = c2-c1+1;
186
187    pm_assert(str);
188    pm_assert(c1 <= c2);
189    pm_assert((int)strlen(str) > c2);
190
191    char *buffer = (char*)malloc(len+1);
192    memcpy(buffer, str+c1, len);
193    buffer[len]  = 0;
194    return buffer;
195}
196
197int ParsedProbeMatch::get_position() const {
198    pm_assert(!error);
199    int c1, c2;
200    if (parser.getColumnRange("pos", &c1, &c2)) {
201        char *content = strpartdup(match, c1, c2);
202        int   pos     = atoi(content);
203        free(content);
204        return pos;
205    }
206    error = "no such column: 'pos'";
207    return -1;
208}
209
210const char *ParsedProbeMatch::get_probe_region() const {
211    pm_assert(!error);
212    int pro      = parser.pimpl->get_probe_region_offset();
213    int matchlen = strlen(match);
214
215    if (pro<matchlen) {
216        return match+pro;
217    }
218
219    error = GBS_global_string("can't parse match info '%s'", match);
220    return 0;
221}
222
223char *ParsedProbeMatch::get_column_content(const char *columnName, bool chop_spaces) const {
224    pm_assert(!error);
225    int sc, ec;
226    if (parser.getColumnRange(columnName, &sc, &ec)) {
227        if (chop_spaces) {
228            while (sc<ec && match[sc] == ' ') ++sc;
229            while (sc<ec && match[ec] == ' ') --ec;
230        }
231        return strpartdup(match, sc, ec);
232    }
233    return 0;
234}
Note: See TracBrowser for help on using the repository browser.