Bug 12909 fixed: Completion on (mt)list led to a crash
[scilab.git] / scilab / modules / completion / src / cpp / FieldsManager.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2011 - DIGITEO - Calixte DENIZET
4  * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
5  *
6  * This file must be used under the terms of the CeCILL.
7  * This source file is licensed as described in the file COPYING, which
8  * you should have received as part of this distribution.  The terms
9  * are also available at
10  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
11  *
12  */
13
14 #include <cstdio>
15 #include <string>
16 #include <cstdlib>
17 #include <vector>
18 #include <cstring>
19
20 #include "FieldsManager.hxx"
21 #include "UnknownMlistFieldsGetter.hxx"
22 #include "HandleFieldsGetter.hxx"
23
24 extern "C" {
25 #include "api_scilab.h"
26 #include "Scierror.h"
27 #include "code2str.h"
28 }
29
30 #include <iostream>
31
32 namespace org_modules_completion
33 {
34
35 std::map<const std::string, FieldsGetter *> FieldsManager::typeToFieldsGetter = std::map<const std::string, FieldsGetter *>();
36
37 void FieldsManager::addFieldsGetter(const std::string & typeName, FieldsGetter * getter)
38 {
39     typeToFieldsGetter[typeName] = getter;
40 }
41
42 const char ** FieldsManager::getFieldsForType(const std::string & typeName, int * mlist, char ** fieldPath, const int fieldPathLen, int * fieldsSize)
43 {
44     std::map<const std::string, FieldsGetter *>::const_iterator it = typeToFieldsGetter.find(typeName);
45     *fieldsSize = 0;
46     if (it == typeToFieldsGetter.end())
47     {
48         UnknownMlistFieldsGetter getter;
49         return getter.getFieldsName(typeName, mlist, fieldPath, fieldPathLen, fieldsSize);
50     }
51     return it->second->getFieldsName(typeName, mlist, fieldPath, fieldPathLen, fieldsSize);
52 }
53
54 const char ** FieldsManager::getFields(int * addr, char ** fieldPath, const int fieldPathLen, int * fieldsSize)
55 {
56     int type;
57     const char ** fields = 0;
58     SciErr sciErr = getVarType(pvApiCtx, addr, &type);
59     if (sciErr.iErr)
60     {
61         return 0;
62     }
63
64     if (type == sci_mlist || type == sci_tlist)
65     {
66         int * strs = 0;
67         const int nbItem = addr[1];
68         sciErr = getListItemAddress(pvApiCtx, addr, 1, &strs);
69         if (sciErr.iErr)
70         {
71             return 0;
72         }
73
74         const int r = strs[1];
75         const int c = strs[2];
76         int typeLen = strs[5] - 1;
77         char * str = new char[typeLen + 1];
78         code2str(&str, strs + 5 + r * c, typeLen);
79         str[typeLen] = 0;
80         fields = getFieldsForType(str, addr, fieldPath, fieldPathLen, fieldsSize);
81         delete[] str;
82     }
83     else if (type == sci_handles)
84     {
85         HandleFieldsGetter getter;
86         fields = getter.getFieldsName("", addr, fieldPath, fieldPathLen, fieldsSize);
87     }
88
89     return fields;
90 }
91
92 char ** FieldsManager::getFieldPath(const char * _str, int * len)
93 {
94     std::vector<std::string> v;
95     std::string str(_str);
96     int pos = (int)str.length();
97     const char symbs[27] = "+-*/\\([ ^,;={&|])}:\"\'><~@\t";
98     char ** ret = 0;
99
100     if (str.at(pos - 1) == '.')
101     {
102         pos--;
103     }
104
105     for (int i = pos - 1; i >= 0; i--)
106     {
107         const char c = str.at(i);
108         if (c == '.')
109         {
110             v.push_back(str.substr(i + 1, pos - i - 1));
111             pos = i;
112         }
113         else
114         {
115             for (int j = 0; j < 27; j++)
116             {
117                 if (c == symbs[j])
118                 {
119                     v.push_back(str.substr(i + 1, pos - i - 1));
120                     goto finish;
121                 }
122             }
123         }
124     }
125
126     v.push_back(str.substr(0, pos));
127
128 finish :
129
130     *len = (int)v.size();
131     if (*len != 0)
132     {
133         ret = (char **) malloc(sizeof(char *) **len);
134         for (int i = 0; i < *len; i++)
135         {
136             ret[i] = strdup(v.at(*len - i - 1).c_str());
137         }
138     }
139
140     return ret;
141 }
142 }