Initial revision
[TestXSLT.git] / libsablot / src / engine / key.cpp
1 /* 
2  * The contents of this file are subject to the Mozilla Public
3  * License Version 1.1 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of
5  * the License at http://www.mozilla.org/MPL/
6  * 
7  * Software distributed under the License is distributed on an "AS
8  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9  * implied. See the License for the specific language governing
10  * rights and limitations under the License.
11  * 
12  * The Original Code is the Sablotron XSLT Processor.
13  * 
14  * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15  * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16  * Ginger Alliance Ltd. All Rights Reserved.
17  * 
18  * Contributor(s):
19  * 
20  * Alternatively, the contents of this file may be used under the
21  * terms of the GNU General Public License Version 2 or later (the
22  * "GPL"), in which case the provisions of the GPL are applicable 
23  * instead of those above.  If you wish to allow use of your 
24  * version of this file only under the terms of the GPL and not to
25  * allow others to use your version of this file under the MPL,
26  * indicate your decision by deleting the provisions above and
27  * replace them with the notice and other provisions required by
28  * the GPL.  If you do not delete the provisions above, a recipient
29  * may use your version of this file under either the MPL or the
30  * GPL.
31  */
32
33 #include "key.h"
34 #include "tree.h"
35 #include "guard.h"
36 #include "domprovider.h"
37
38 //
39 //  KList
40 //
41
42 KList::KList()
43     : doc(NULL)
44 {
45 }
46
47 KList::~KList()
48 {
49 }
50
51 int KList::findNdx(const Str& keyValue) const
52 {
53     int bottom = 0,
54         top = number() - 1,
55             middle = 0;
56         Bool found = FALSE;
57         while (top >= bottom && !found)
58         {
59             middle = (top + bottom)/2;
60             //switch(values[middle] -> compare(keyValue))
61             switch(keyValue.compare(values[middle]))
62             {
63             case 1:
64               bottom = middle + 1; break;
65             case -1:
66               top = middle - 1; break;
67             case 0:
68               found = TRUE; 
69             }
70         }
71         if (!found) return -1;
72         // return first match
73         while (middle > 0 && keyValue == values[middle-1])
74             middle--;
75         return middle;
76 }
77
78 eFlag KList::getNodes(Sit S, const Str& keyValue, Context& result) const
79 {
80     int ndx = findNdx(keyValue);
81     if (ndx != -1)
82     {
83         do
84             {
85             result.append((*this)[ndx]);
86             }
87             while (++ndx < number() && keyValue == values[ndx]);
88     }    
89     return OK;
90 }
91
92 eFlag KList::makeValues(Sit S, Expression& use)
93 {
94     Context c(NULL);  //_cn_ no current in top level keys
95     Expression result(use.getOwnerElement());
96     NodeHandle thisVertex;
97     DStr strg;
98     for (int i = 0; i < number(); i++)
99     {
100       thisVertex = (*this)[i];
101       c.set(thisVertex);
102       E( use.eval(S, result, &c) );
103       c.deppend();
104       //values.append(new Str);
105       switch(result.type)
106         {    
107         case EX_NODESET:
108           {
109             const Context& set = result.tonodesetRef();
110             if (set.isVoid()) 
111               { //add an empty key
112                 char *foo = new char[1]; *foo = '\0';
113                 values.append(foo);
114                 break;
115               }
116             S.dom().constructStringValue(set[0], strg);
117             //*(values.last()) = strg;
118             values.append(strg.cloneData());
119             strg.empty();
120             for (int j = 1; j < set.getSize(); j++)
121               {
122                 insertBefore(thisVertex, ++i);
123                 //values.append(new Str);
124                 S.dom().constructStringValue(set[j], strg);
125                 //*(values.last()) = strg;
126                 values.append(strg.cloneData());
127                 strg.empty();
128               }
129           }; break;
130         default:
131           {
132             //E( result.tostring(S, *(values.last())) );
133             strg.empty();
134             E( result.tostring(S, strg) );
135             values.append(strg.cloneData());
136           }
137         }
138     }
139     return OK;
140 }
141
142 int KList::compare(int i, int j, void *data)
143 {
144   //int cmp = strcmp((char*)*(values[i]), (char*)*(values[j]));
145   //always non wcsxfrm'ed ????
146   int cmp = strcmp(values[i], values[j]);
147   if (!cmp) return 0;
148   return (cmp > 0) ? 1 : -1;
149 }
150
151 void KList::swap(int i, int j)
152 {
153     SList<NodeHandle>::swap(i, j);
154     values.swap(i, j);
155 }
156
157 void KList::sort(Sit S)
158 {
159     SList<NodeHandle>::sort(0, number() - 1, &(S.dom()));
160 }
161
162
163 //
164 //  Key
165 //
166
167 Key::Key(const EQName& ename_, Expression& match_, Expression& use_)
168     : ename(ename_), match(match_), use(use_)
169 {
170 }
171
172 eFlag Key::create(Sit S, SXP_Document doc)
173 {
174     GP( Context ) c = new Context(NULL, /* isForKey = */ TRUE);
175     if (find(doc))
176         // subkey exists, return
177         return OK;
178     // create a context for 'match'
179     //E( toTree(doc) -> getMatchingList(S, match, *c) );
180     S.dom().getMatchingList(S, doc, match, *c);
181     // only keep the array of nodes
182     KList *array = (*c).getKeyArray();
183     array -> incRefCount();
184     array -> setSourceDoc(doc);
185     subkeys.append(array);
186     // create values
187     E( array -> makeValues(S, use) );
188     array -> sort(S);
189     Str fullname;
190     ename.getname(fullname);
191     Log2(S, L2_KEY_ADDED, Str(array -> number()), fullname);
192     // #tom#
193     // list();
194     //
195     // c dies
196     return OK;
197 }
198
199 const EQName& Key::getName()
200 {
201     return ename;
202 }
203
204 eFlag Key::getNodes(Sit S, const Str& keyValue, Context& result, SXP_Document doc) const
205 {
206     KList *array = find(doc);
207     E( NZ(array) -> getNodes(S, keyValue, result) );
208     return OK;
209 }
210
211 Key::~Key()
212 {
213     subkeys.freeall(FALSE);
214 }
215
216 void Key::report(Sit S, MsgType type, MsgCode code, 
217     const Str &arg1, const Str &arg2) const
218 {
219     S.message(type, code, arg1, arg2);
220 }
221
222 void Key::list()
223 {
224     Str full;
225     ename.getname(full);
226     printf("// KEY %s\n", (char*)full);
227     for (int i = 0; i < subkeys.number(); i++)
228     {
229         printf("//   \"doc %p\"\n",subkeys[i] -> getSourceDoc());
230         for (int j = 0; j < subkeys[i] -> number(); j++)
231             printf("//     (%p) '%s'\n", subkeys[i] -> operator[](j), 
232                    //(char*)*(subkeys[i] -> values[j]));
233                    subkeys[i] -> values[j]);
234         putchar('\n');
235     }
236 }
237
238 KList* Key::find(SXP_Document doc) const
239 {
240     int i;
241     for (i = 0; i < subkeys.number(); i++)
242         if (subkeys[i] -> getSourceDoc() == doc)
243             return subkeys[i];
244     return NULL;
245 }
246
247 //
248 //  KeySet
249 //
250
251 #define KeyErr1(situa, code, ename) {\
252     Str fullname; ename.getname(fullname); Err1(S, code, fullname); }
253
254 KeySet::KeySet()
255 : PList<Key*>(LIST_SIZE_SMALL)
256 {
257 }
258
259 eFlag KeySet::addKey(Sit S, const EQName& ename, SXP_Document doc,
260     Expression& match, Expression& use)
261 {
262     if (findKey(ename))
263         KeyErr1(S, E1_DUPLICIT_KEY, ename);
264     Key *newKey;
265     append(newKey = new Key(ename, match, use));
266     E( newKey -> create(S, doc) );
267     return OK;
268 }
269
270 eFlag KeySet::makeKeysForDoc(Sit S, SXP_Document doc)
271 {
272     for (int i = 0; i < number(); i++)
273     {
274         Key* k = (*this)[i];
275         if (k -> find(doc)) break;
276         E( k -> create(S, doc) );
277     }
278     return OK;
279 }
280
281 eFlag KeySet::getNodes(Sit S, const EQName& ename, SXP_Document doc,
282     const Str& value, Context& result)
283 {    
284     Key* theKey = findKey(ename);
285     if (!theKey)
286         KeyErr1(S, E1_KEY_NOT_FOUND, ename);
287     E( theKey -> getNodes(S, value, result, doc) );
288     return OK;
289 }
290
291 KeySet::~KeySet()
292 {
293     freeall(FALSE);
294 }
295
296 Key* KeySet::findKey(const EQName& ename)
297 {
298     for (int i = 0; i < number(); i++)
299     {
300         if (ename == (*this)[i] -> getName())
301             return (*this)[i];
302     }
303     return NULL;
304 }
305
306 void KeySet::report(Sit S, MsgType type, MsgCode code, 
307     const Str &arg1, const Str &arg2) const
308 {
309     S.message(type, code, arg1, arg2);
310 }
311