1/*
2* Copyright (C) 2011 The Android Open Source Project
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16#include <stdio.h>
17#include "EntryPoint.h"
18#include <string>
19#include "TypeFactory.h"
20#include "strUtils.h"
21#include <sstream>
22
23
24EntryPoint::EntryPoint()
25{
26    reset();
27}
28
29EntryPoint::~EntryPoint()
30{
31}
32
33void EntryPoint::reset()
34{
35    m_unsupported = false;
36    m_customDecoder = false;
37    m_notApi = false;
38    m_vars.empty();
39}
40
41bool parseTypeField(const std::string & f, std::string *vartype, std::string *varname)
42{
43    size_t pos = 0, last;
44    bool done = false;
45
46
47    *vartype = "";
48    if (varname != NULL) *varname = "";
49
50    enum { ST_TYPE, ST_NAME, ST_END } state = ST_TYPE;
51
52    while(!done) {
53
54        std::string str = getNextToken(f, pos, &last, WHITESPACE);
55        if (str.size() == 0) break;
56
57        switch(state) {
58        case ST_TYPE:
59            if (str == "const") {
60                pos = last;
61                *vartype = "const ";
62            } else {
63                // must be a type name;
64                *vartype += str;
65                state = ST_NAME;
66                pos = last;
67            }
68            break;
69        case ST_NAME:
70            if (str.size() == 0) {
71                done = true;
72            } else if (str == "*") {
73                (*vartype) += "*";
74                pos = last;
75            } else if (varname == NULL) {
76                done = true;
77            } else {
78                while (str[0] == '*') {
79                    (*vartype) += "*";
80                    str[0] = ' ';
81                    str = trim(str);
82                }
83                *varname = str;
84                done = true;
85            }
86            break;
87        case ST_END:
88            break;
89        }
90    }
91    return true;
92}
93
94// return true for valid line (need to get into the entry points list)
95bool EntryPoint::parse(unsigned int lc, const std::string & str)
96{
97    size_t pos, last;
98    std::string field;
99
100    reset();
101    std::string linestr = trim(str);
102
103    if (linestr.size() == 0) return false;
104    if (linestr.at(0) == '#') return false;
105
106    // skip PREFIX
107    field = getNextToken(linestr, 0, &last, "(");
108    pos = last + 1;
109    // return type
110    field = getNextToken(linestr, pos, &last, ",)");
111    std::string retTypeName;
112    if (!parseTypeField(field, &retTypeName, NULL)) {
113        fprintf(stderr, "line: %d: Parsing error in field <%s>\n", lc, field.c_str());
114        return false;
115    }
116    pos = last + 1;
117    const VarType *theType = TypeFactory::instance()->getVarTypeByName(retTypeName);
118    if (theType->name() == "UNKNOWN") {
119        fprintf(stderr, "UNKNOWN retval: %s\n", linestr.c_str());
120    }
121
122    m_retval.init(std::string(""), theType, std::string(""), Var::POINTER_OUT, std::string(""), std::string(""));
123
124    // function name
125    m_name = getNextToken(linestr, pos, &last, ",)");
126    pos = last + 1;
127
128    // parameters;
129    int nvars = 0;
130    while (pos < linestr.size() - 1) {
131        field = getNextToken(linestr, pos, &last, ",)");
132        std::string vartype, varname;
133        if (!parseTypeField(field, &vartype, &varname)) {
134            fprintf(stderr, "line: %d: Parsing error in field <%s>\n", lc, field.c_str());
135            return false;
136        }
137        nvars++;
138        const VarType *v = TypeFactory::instance()->getVarTypeByName(vartype);
139        if (v->id() == 0) {
140            fprintf(stderr, "%d: Unknown type: %s\n", lc, vartype.c_str());
141        } else {
142            if (varname == "" &&
143                !(v->name() == "void" && !v->isPointer())) {
144                std::ostringstream oss;
145                oss << "var" << nvars;
146                varname = oss.str();
147            }
148
149            m_vars.push_back(Var(varname, v, std::string(""), Var::POINTER_IN, "", ""));
150        }
151        pos = last + 1;
152    }
153    return true;
154}
155
156void EntryPoint::print(FILE *fp, bool newline,
157                       const std::string & name_suffix,
158                       const std::string & name_prefix,
159                       const std::string & ctx_param ) const
160{
161    fprintf(fp, "%s %s%s%s(",
162            m_retval.type()->name().c_str(),
163            name_prefix.c_str(),
164            m_name.c_str(),
165            name_suffix.c_str());
166
167    if (ctx_param != "") fprintf(fp, "%s ", ctx_param.c_str());
168
169    for (size_t i = 0; i < m_vars.size(); i++) {
170        if (m_vars[i].isVoid()) continue;
171        if (i != 0 || ctx_param != "") fprintf(fp, ", ");
172        fprintf(fp, "%s %s", m_vars[i].type()->name().c_str(),
173                m_vars[i].name().c_str());
174    }
175    fprintf(fp, ")%s", newline? "\n" : "");
176}
177
178Var * EntryPoint::var(const std::string & name)
179{
180    Var *v = NULL;
181    for (size_t i = 0; i < m_vars.size(); i++) {
182        if (m_vars[i].name() == name) {
183            v = &m_vars[i];
184            break;
185        }
186    }
187    return v;
188}
189
190bool EntryPoint::hasPointers()
191{
192    bool pointers = false;
193    if (m_retval.isPointer()) pointers = true;
194    if (!pointers) {
195        for (size_t i = 0; i < m_vars.size(); i++) {
196            if (m_vars[i].isPointer()) {
197                pointers = true;
198                break;
199            }
200        }
201    }
202    return pointers;
203}
204
205int EntryPoint::setAttribute(const std::string &line, size_t lc)
206{
207    size_t pos = 0;
208    size_t last;
209    std::string token = getNextToken(line, 0, &last, WHITESPACE);
210
211    if (token == "len") {
212        pos = last;
213        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
214
215        if (varname.size() == 0) {
216            fprintf(stderr, "ERROR: %u: Missing variable name in 'len' attribute\n", (unsigned int)lc);
217            return -1;
218        }
219        Var * v = var(varname);
220        if (v == NULL) {
221            fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
222                    (unsigned int)lc, varname.c_str(), name().c_str());
223            return -2;
224        }
225        // set the size expression into var
226        pos = last;
227        v->setLenExpression(line.substr(pos));
228    } else if (token == "param_check") {
229        pos = last;
230        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
231
232        if (varname.size() == 0) {
233            fprintf(stderr, "ERROR: %u: Missing variable name in 'param_check' attribute\n", (unsigned int)lc);
234            return -1;
235        }
236        Var * v = var(varname);
237        if (v == NULL) {
238            fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
239                    (unsigned int)lc, varname.c_str(), name().c_str());
240            return -2;
241        }
242        // set the size expression into var
243        pos = last;
244        v->setParamCheckExpression(line.substr(pos));
245
246    } else if (token == "dir") {
247        pos = last;
248        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
249        if (varname.size() == 0) {
250            fprintf(stderr, "ERROR: %u: Missing variable name in 'dir' attribute\n", (unsigned int)lc);
251            return -1;
252        }
253        Var * v = var(varname);
254        if (v == NULL) {
255            fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
256                    (unsigned int)lc, varname.c_str(), name().c_str());
257            return -2;
258        }
259
260        pos = last;
261        std::string pointerDirStr = getNextToken(line, pos, &last, WHITESPACE);
262        if (pointerDirStr.size() == 0) {
263            fprintf(stderr, "ERROR: %u: missing pointer directions\n", (unsigned int)lc);
264            return -3;
265        }
266
267        if (pointerDirStr == "out") {
268            v->setPointerDir(Var::POINTER_OUT);
269        } else if (pointerDirStr == "inout") {
270            v->setPointerDir(Var::POINTER_INOUT);
271        } else if (pointerDirStr == "in") {
272            v->setPointerDir(Var::POINTER_IN);
273        } else {
274            fprintf(stderr, "ERROR: %u: unknow pointer direction %s\n", (unsigned int)lc, pointerDirStr.c_str());
275        }
276    } else if (token == "var_flag") {
277        pos = last;
278        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
279        if (varname.size() == 0) {
280            fprintf(stderr, "ERROR: %u: Missing variable name in 'var_flag' attribute\n", (unsigned int)lc);
281            return -1;
282        }
283        Var * v = var(varname);
284        if (v == NULL) {
285            fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
286                    (unsigned int)lc, varname.c_str(), name().c_str());
287            return -2;
288        }
289        int count = 0;
290        for (;;) {
291            pos = last;
292            std::string flag = getNextToken(line, pos, &last, WHITESPACE);
293            if (flag.size() == 0) {
294                if (count == 0) {
295                    fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
296                    return -3;
297                }
298                break;
299            }
300            count++;
301
302            if (flag == "nullAllowed") {
303                if (v->isPointer()) {
304                    v->setNullAllowed(true);
305                } else {
306                    fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n",
307                            (unsigned int) lc, v->name().c_str());
308                }
309            } else if (flag == "isLarge") {
310                if (v->isPointer()) {
311                    v->setIsLarge(true);
312                } else {
313                    fprintf(stderr, "WARNING: %u: setting isLarge flag for a non-pointer variable %s\n",
314                            (unsigned int) lc, v->name().c_str());
315                }
316            } else {
317                fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str());
318            }
319        }
320    } else if (token == "custom_pack") {
321        pos = last;
322        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
323
324        if (varname.size() == 0) {
325            fprintf(stderr, "ERROR: %u: Missing variable name in 'custom_pack' attribute\n", (unsigned int)lc);
326            return -1;
327        }
328        Var * v = var(varname);
329        if (v == NULL) {
330            fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
331                    (unsigned int)lc, varname.c_str(), name().c_str());
332            return -2;
333        }
334        // set the size expression into var
335        pos = last;
336        v->setPackExpression(line.substr(pos));
337    } else if (token == "custom_write") {
338        pos = last;
339        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
340
341        if (varname.size() == 0) {
342            fprintf(stderr, "ERROR: %u: Missing variable name in 'custom_write' attribute\n", (unsigned int)lc);
343            return -1;
344        }
345        Var * v = var(varname);
346        if (v == NULL) {
347            fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
348                    (unsigned int)lc, varname.c_str(), name().c_str());
349            return -2;
350        }
351        // set the size expression into var
352        pos = last;
353        v->setWriteExpression(line.substr(pos));
354    } else if (token == "flag") {
355        pos = last;
356        std::string flag = getNextToken(line, pos, &last, WHITESPACE);
357        if (flag.size() == 0) {
358            fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
359            return -4;
360        }
361
362        if (flag == "unsupported") {
363            setUnsupported(true);
364        } else if (flag == "custom_decoder") {
365            setCustomDecoder(true);
366        } else if (flag == "not_api") {
367            setNotApi(true);
368        } else {
369            fprintf(stderr, "WARNING: %u: unknown flag %s\n", (unsigned int)lc, flag.c_str());
370        }
371    } else {
372        fprintf(stderr, "WARNING: %u: unknown attribute %s\n", (unsigned int)lc, token.c_str());
373    }
374
375    return 0;
376}
377