]> git.cworth.org Git - apitrace/blob - common/trace_callset.cpp
93d145fa3a2b0f881794786d3aa23e7db047fbb9
[apitrace] / common / trace_callset.cpp
1 /**************************************************************************
2  *
3  * Copyright 2012 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 #include <assert.h>
28 #include <stdlib.h>
29
30 #include <limits>
31 #include <fstream>
32 #include <iostream>
33 #include <string>
34
35 #include <trace_callset.hpp>
36
37
38 using namespace trace;
39
40
41 // Parser class for call sets
42 class CallSetParser
43 {
44     CallSet &set;
45
46 protected:
47     char lookahead;
48
49     CallSetParser(CallSet &_set) :
50         set(_set),
51         lookahead(0)
52     {}
53
54 public:
55     void parse() {
56         skipWhiteSpace();
57         while (lookahead) {
58             assert(!isSpace());
59             parseRange();
60             // skip any comma
61             isOperator(',');
62         }
63     }
64
65 private:
66     void parseRange() {
67         CallNo start = std::numeric_limits<CallNo>::min();
68         CallNo stop = std::numeric_limits<CallNo>::max();
69         CallNo step = 1;
70         CallFlags freq = FREQUENCY_ALL;
71         if (isAlpha()) {
72             freq = parseFrequency();
73         } else {
74             if (isOperator('*')) {
75                 // no-change
76             } else {
77                 start = parseCallNo();
78                 if (isOperator('-')) {
79                     if (isDigit()) {
80                         stop = parseCallNo();
81                     } else {
82                         // no-change
83                     }
84                 } else {
85                     stop = start;
86                 }
87             }
88             if (isOperator('/')) {
89                 if (isDigit()) {
90                     step = parseCallNo();
91                 } else {
92                     freq = parseFrequency();
93                 }
94             }
95         }
96         set.addRange(CallRange(start, stop, step, freq));
97     }
98
99     // match and consume an operator
100     bool isOperator(char c) {
101         if (lookahead == c) {
102             consume();
103             skipWhiteSpace();
104             return true;
105         } else {
106             return false;
107         }
108     }
109
110     CallNo parseCallNo() {
111         CallNo number = 0;
112         if (isDigit()) {
113             do {
114                 CallNo digit = consume() - '0';
115                 number = number * 10 + digit;
116             } while (isDigit());
117         } else {
118             std::cerr << "error: expected digit, found '" << lookahead << "'\n";
119             exit(0);
120         }
121         skipWhiteSpace();
122         return number;
123     }
124
125     CallFlags parseFrequency() {
126         std::string freq;
127         if (isAlpha()) {
128             do {
129                 freq.push_back(consume());
130             } while (isAlpha());
131         } else {
132             std::cerr << "error: expected frequency, found '" << lookahead << "'\n";
133             exit(0);
134         }
135         skipWhiteSpace();
136         if (freq == "frame") {
137             return FREQUENCY_FRAME;
138         } else if (freq == "rendertarget" || freq == "fbo") {
139             return FREQUENCY_RENDERTARGET;
140         } else if (freq == "render" || freq == "draw") {
141             return FREQUENCY_RENDER;
142         } else {
143             std::cerr << "error: expected frequency, found '" << freq << "'\n";
144             exit(0);
145             return FREQUENCY_NONE;
146         }
147     }
148
149     // match lookahead with a digit (does not consume)
150     bool isDigit() const {
151         return lookahead >= '0' && lookahead <= '9';
152     }
153
154     bool isAlpha() const {
155         return lookahead >= 'a' && lookahead <= 'z';
156     }
157
158     void skipWhiteSpace() {
159         while (isSpace()) {
160             consume();
161         }
162     }
163
164     bool isSpace() const {
165         return lookahead == ' ' ||
166                lookahead == '\t' ||
167                lookahead == '\r' ||
168                lookahead == '\n';
169     }
170
171     virtual char consume() = 0;
172 };
173
174
175 class StringCallSetParser : public CallSetParser
176 {
177     const char *buf;
178
179 public:
180     StringCallSetParser(CallSet &_set, const char *_buf) :
181         CallSetParser(_set),
182         buf(_buf)
183     {
184         lookahead = *buf;
185     }
186
187     char consume() {
188         char c = lookahead;
189         if (lookahead) {
190             ++buf;
191             lookahead = *buf;
192         }
193         return c;
194     }
195 };
196
197
198 class FileCallSetParser : public CallSetParser
199 {
200     std::ifstream stream;
201
202 public:
203     FileCallSetParser(CallSet &_set, const char *filename) :
204         CallSetParser(_set)
205     {
206         stream.open(filename);
207         if (!stream.is_open()) {
208             std::cerr << "error: failed to open \"" << filename << "\"\n";
209             exit(1);
210         }
211
212         stream.get(lookahead);
213     }
214
215     char consume() {
216         char c = lookahead;
217         if (stream.eof()) {
218             lookahead = 0;
219         } else {
220             stream.get(lookahead);
221         }
222         return c;
223     }
224 };
225
226
227 CallSet::CallSet(const char *string): limits(std::numeric_limits<CallNo>::min(), std::numeric_limits<CallNo>::max())
228 {
229     if (*string == '@') {
230         FileCallSetParser parser(*this, &string[1]);
231         parser.parse();
232     } else {
233         StringCallSetParser parser(*this, string);
234         parser.parse();
235     }
236 }
237
238
239 CallSet::CallSet(CallFlags freq): limits(std::numeric_limits<CallNo>::min(), std::numeric_limits<CallNo>::max()) {
240     if (freq != FREQUENCY_NONE) {
241         CallNo start = std::numeric_limits<CallNo>::min();
242         CallNo stop = std::numeric_limits<CallNo>::max();
243         CallNo step = 1;
244         addRange(CallRange(start, stop, step, freq));
245         assert(!empty());
246     }
247 }