wasCSharpSQLite – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * ArrayCmd.java |
||
3 | * |
||
4 | * Copyright (c) 1997 Sun Microsystems, Inc. |
||
5 | * |
||
6 | * See the file "license.terms" for information on usage and |
||
7 | * redistribution of this file, and for a DISCLAIMER OF ALL |
||
8 | * WARRANTIES. |
||
9 | * |
||
10 | * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart |
||
11 | * |
||
12 | * RCS @(#) $Id: ArrayCmd.java,v 1.4 2003/01/10 01:57:57 mdejong Exp $ |
||
13 | * |
||
14 | */ |
||
15 | using System; |
||
16 | using System.Collections; |
||
17 | |||
18 | namespace tcl.lang |
||
19 | { |
||
20 | |||
21 | /// <summary> This class implements the built-in "array" command in Tcl.</summary> |
||
22 | |||
23 | class ArrayCmd : Command |
||
24 | { |
||
25 | internal static Type procClass = null; |
||
26 | |||
27 | private static readonly string[] validCmds = new string[] { "anymore", "donesearch", "exists", "get", "names", "nextelement", "set", "size", "startsearch", "unset" }; |
||
28 | |||
29 | internal const int OPT_ANYMORE = 0; |
||
30 | internal const int OPT_DONESEARCH = 1; |
||
31 | internal const int OPT_EXISTS = 2; |
||
32 | internal const int OPT_GET = 3; |
||
33 | internal const int OPT_NAMES = 4; |
||
34 | internal const int OPT_NEXTELEMENT = 5; |
||
35 | internal const int OPT_SET = 6; |
||
36 | internal const int OPT_SIZE = 7; |
||
37 | internal const int OPT_STARTSEARCH = 8; |
||
38 | internal const int OPT_UNSET = 9; |
||
39 | |||
40 | /// <summary> This procedure is invoked to process the "array" Tcl command. |
||
41 | /// See the user documentation for details on what it does. |
||
42 | /// </summary> |
||
43 | |||
44 | public TCL.CompletionCode cmdProc( Interp interp, TclObject[] objv ) |
||
45 | { |
||
46 | Var var = null, array = null; |
||
47 | bool notArray = false; |
||
48 | string varName, msg; |
||
49 | int index;//, result; |
||
50 | |||
51 | if ( objv.Length < 3 ) |
||
52 | { |
||
53 | throw new TclNumArgsException( interp, 1, objv, "option arrayName ?arg ...?" ); |
||
54 | } |
||
55 | |||
56 | index = TclIndex.get( interp, objv[1], validCmds, "option", 0 ); |
||
57 | |||
58 | // Locate the array variable (and it better be an array). |
||
59 | |||
60 | |||
61 | varName = objv[2].ToString(); |
||
62 | Var[] retArray = Var.lookupVar( interp, varName, null, 0, null, false, false ); |
||
63 | |||
64 | // Assign the values returned in the array |
||
65 | if ( retArray != null ) |
||
66 | { |
||
67 | var = retArray[0]; |
||
68 | array = retArray[1]; |
||
69 | } |
||
70 | |||
71 | if ( ( var == null ) || !var.isVarArray() || var.isVarUndefined() ) |
||
72 | { |
||
73 | notArray = true; |
||
74 | } |
||
75 | |||
76 | // Special array trace used to keep the env array in sync for |
||
77 | // array names, array get, etc. |
||
78 | |||
79 | if ( var != null && var.traces != null ) |
||
80 | { |
||
81 | msg = Var.callTraces( interp, array, var, varName, null, ( TCL.VarFlag.LEAVE_ERR_MSG | TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.GLOBAL_ONLY | TCL.VarFlag.TRACE_ARRAY ) ); |
||
82 | if ( (System.Object)msg != null ) |
||
83 | { |
||
84 | throw new TclVarException( interp, varName, null, "trace array", msg ); |
||
85 | } |
||
86 | } |
||
87 | |||
88 | switch ( index ) |
||
89 | { |
||
90 | |||
91 | case OPT_ANYMORE: |
||
92 | { |
||
93 | if ( objv.Length != 4 ) |
||
94 | { |
||
95 | throw new TclNumArgsException( interp, 2, objv, "arrayName searchId" ); |
||
96 | } |
||
97 | if ( notArray ) |
||
98 | { |
||
99 | |||
100 | errorNotArray( interp, objv[2].ToString() ); |
||
101 | } |
||
102 | |||
103 | if ( var.sidVec == null ) |
||
104 | { |
||
105 | |||
106 | errorIllegalSearchId( interp, objv[2].ToString(), objv[3].ToString() ); |
||
107 | } |
||
108 | |||
109 | |||
110 | SearchId e = var.getSearch( objv[3].ToString() ); |
||
111 | if ( e == null ) |
||
112 | { |
||
113 | |||
114 | errorIllegalSearchId( interp, objv[2].ToString(), objv[3].ToString() ); |
||
115 | } |
||
116 | |||
117 | if ( e.HasMore ) |
||
118 | { |
||
119 | interp.setResult( "1" ); |
||
120 | } |
||
121 | else |
||
122 | { |
||
123 | interp.setResult( "0" ); |
||
124 | } |
||
125 | break; |
||
126 | } |
||
127 | |||
128 | case OPT_DONESEARCH: |
||
129 | { |
||
130 | |||
131 | if ( objv.Length != 4 ) |
||
132 | { |
||
133 | throw new TclNumArgsException( interp, 2, objv, "arrayName searchId" ); |
||
134 | } |
||
135 | if ( notArray ) |
||
136 | { |
||
137 | |||
138 | errorNotArray( interp, objv[2].ToString() ); |
||
139 | } |
||
140 | |||
141 | bool rmOK = true; |
||
142 | if ( var.sidVec != null ) |
||
143 | { |
||
144 | |||
145 | rmOK = ( var.removeSearch( objv[3].ToString() ) ); |
||
146 | } |
||
147 | if ( ( var.sidVec == null ) || !rmOK ) |
||
148 | { |
||
149 | |||
150 | errorIllegalSearchId( interp, objv[2].ToString(), objv[3].ToString() ); |
||
151 | } |
||
152 | break; |
||
153 | } |
||
154 | |||
155 | case OPT_EXISTS: |
||
156 | { |
||
157 | |||
158 | if ( objv.Length != 3 ) |
||
159 | { |
||
160 | throw new TclNumArgsException( interp, 2, objv, "arrayName" ); |
||
161 | } |
||
162 | interp.setResult( !notArray ); |
||
163 | break; |
||
164 | } |
||
165 | |||
166 | case OPT_GET: |
||
167 | { |
||
168 | // Due to the differences in the hashtable implementation |
||
169 | // from the Tcl core and Java, the output will be rearranged. |
||
170 | // This is not a negative side effect, however, test results |
||
171 | // will differ. |
||
172 | |||
173 | if ( ( objv.Length != 3 ) && ( objv.Length != 4 ) ) |
||
174 | { |
||
175 | throw new TclNumArgsException( interp, 2, objv, "arrayName ?pattern?" ); |
||
176 | } |
||
177 | if ( notArray ) |
||
178 | { |
||
179 | return TCL.CompletionCode.RETURN; |
||
180 | } |
||
181 | |||
182 | string pattern = null; |
||
183 | if ( objv.Length == 4 ) |
||
184 | { |
||
185 | |||
186 | pattern = objv[3].ToString(); |
||
187 | } |
||
188 | |||
189 | Hashtable table = (Hashtable)var.value; |
||
190 | TclObject tobj = TclList.newInstance(); |
||
191 | |||
192 | string arrayName = objv[2].ToString(); |
||
193 | string key, strValue; |
||
194 | Var var2; |
||
195 | |||
196 | // Go through each key in the hash table. If there is a |
||
197 | // pattern, test for a match. Each valid key and its value |
||
198 | // is written into sbuf, which is returned. |
||
199 | |||
200 | // FIXME : do we need to port over the 8.1 code for this loop? |
||
201 | |||
202 | for ( IDictionaryEnumerator e = table.GetEnumerator(); e.MoveNext(); ) |
||
203 | { |
||
204 | key = ( (string)e.Key ); |
||
205 | var2 = (Var)e.Value; |
||
206 | if ( var2.isVarUndefined() ) |
||
207 | { |
||
208 | continue; |
||
209 | } |
||
210 | |||
211 | if ( (System.Object)pattern != null && !Util.stringMatch( key, pattern ) ) |
||
212 | { |
||
213 | continue; |
||
214 | } |
||
215 | |||
216 | |||
217 | strValue = interp.getVar( arrayName, key, 0 ).ToString(); |
||
218 | |||
219 | TclList.append( interp, tobj, TclString.newInstance( key ) ); |
||
220 | TclList.append( interp, tobj, TclString.newInstance( strValue ) ); |
||
221 | } |
||
222 | interp.setResult( tobj ); |
||
223 | break; |
||
224 | } |
||
225 | |||
226 | case OPT_NAMES: |
||
227 | { |
||
228 | |||
229 | if ( ( objv.Length != 3 ) && ( objv.Length != 4 ) ) |
||
230 | { |
||
231 | throw new TclNumArgsException( interp, 2, objv, "arrayName ?pattern?" ); |
||
232 | } |
||
233 | if ( notArray ) |
||
234 | { |
||
235 | return TCL.CompletionCode.RETURN; |
||
236 | } |
||
237 | |||
238 | string pattern = null; |
||
239 | if ( objv.Length == 4 ) |
||
240 | { |
||
241 | |||
242 | pattern = objv[3].ToString(); |
||
243 | } |
||
244 | |||
245 | Hashtable table = (Hashtable)var.value; |
||
246 | TclObject tobj = TclList.newInstance(); |
||
247 | string key; |
||
248 | |||
249 | // Go through each key in the hash table. If there is a |
||
250 | // pattern, test for a match. Each valid key and its value |
||
251 | // is written into sbuf, which is returned. |
||
252 | |||
253 | for ( IDictionaryEnumerator e = table.GetEnumerator(); e.MoveNext(); ) |
||
254 | { |
||
255 | key = (string)e.Key; |
||
256 | Var elem = (Var)e.Value; |
||
257 | if ( !elem.isVarUndefined() ) |
||
258 | { |
||
259 | if ( (System.Object)pattern != null ) |
||
260 | { |
||
261 | if ( !Util.stringMatch( key, pattern ) ) |
||
262 | { |
||
263 | continue; |
||
264 | } |
||
265 | } |
||
266 | TclList.append( interp, tobj, TclString.newInstance( key ) ); |
||
267 | } |
||
268 | } |
||
269 | interp.setResult( tobj ); |
||
270 | break; |
||
271 | } |
||
272 | |||
273 | case OPT_NEXTELEMENT: |
||
274 | { |
||
275 | |||
276 | if ( objv.Length != 4 ) |
||
277 | { |
||
278 | throw new TclNumArgsException( interp, 2, objv, "arrayName searchId" ); |
||
279 | } |
||
280 | if ( notArray ) |
||
281 | { |
||
282 | |||
283 | errorNotArray( interp, objv[2].ToString() ); |
||
284 | } |
||
285 | |||
286 | if ( var.sidVec == null ) |
||
287 | { |
||
288 | |||
289 | errorIllegalSearchId( interp, objv[2].ToString(), objv[3].ToString() ); |
||
290 | } |
||
291 | |||
292 | |||
293 | SearchId e = var.getSearch( objv[3].ToString() ); |
||
294 | if ( e == null ) |
||
295 | { |
||
296 | |||
297 | errorIllegalSearchId( interp, objv[2].ToString(), objv[3].ToString() ); |
||
298 | } |
||
299 | if ( e.HasMore ) |
||
300 | { |
||
301 | Hashtable table = (Hashtable)var.value; |
||
302 | DictionaryEntry entry = e.nextEntry(); |
||
303 | string key = (string)entry.Key; |
||
304 | Var elem = (Var)entry.Value; |
||
305 | if ( ( elem.flags & VarFlags.UNDEFINED ) == 0 ) |
||
306 | { |
||
307 | interp.setResult( key ); |
||
308 | } |
||
309 | else |
||
310 | { |
||
311 | interp.setResult( "" ); |
||
312 | } |
||
313 | } |
||
314 | break; |
||
315 | } |
||
316 | |||
317 | case OPT_SET: |
||
318 | { |
||
319 | |||
320 | if ( objv.Length != 4 ) |
||
321 | { |
||
322 | throw new TclNumArgsException( interp, 2, objv, "arrayName list" ); |
||
323 | } |
||
324 | int size = TclList.getLength( interp, objv[3] ); |
||
325 | if ( size % 2 != 0 ) |
||
326 | { |
||
327 | throw new TclException( interp, "list must have an even number of elements" ); |
||
328 | } |
||
329 | |||
330 | int i; |
||
331 | |||
332 | string name1 = objv[2].ToString(); |
||
333 | string name2, strValue; |
||
334 | |||
335 | // Set each of the array variable names in the interp |
||
336 | |||
337 | for ( i = 0; i < size; i++ ) |
||
338 | { |
||
339 | |||
340 | name2 = TclList.index( interp, objv[3], i++ ).ToString(); |
||
341 | |||
342 | strValue = TclList.index( interp, objv[3], i ).ToString(); |
||
343 | interp.setVar( name1, name2, TclString.newInstance( strValue ), 0 ); |
||
344 | } |
||
345 | break; |
||
346 | } |
||
347 | |||
348 | case OPT_SIZE: |
||
349 | { |
||
350 | |||
351 | if ( objv.Length != 3 ) |
||
352 | { |
||
353 | throw new TclNumArgsException( interp, 2, objv, "arrayName" ); |
||
354 | } |
||
355 | if ( notArray ) |
||
356 | { |
||
357 | interp.setResult( 0 ); |
||
358 | } |
||
359 | else |
||
360 | { |
||
361 | Hashtable table = (Hashtable)var.value; |
||
362 | int size = 0; |
||
363 | for ( IDictionaryEnumerator e = table.GetEnumerator(); e.MoveNext(); ) |
||
364 | { |
||
365 | Var elem = (Var)e.Value; |
||
366 | if ( ( elem.flags & VarFlags.UNDEFINED ) == 0 ) |
||
367 | { |
||
368 | size++; |
||
369 | } |
||
370 | } |
||
371 | interp.setResult( size ); |
||
372 | } |
||
373 | break; |
||
374 | } |
||
375 | |||
376 | case OPT_STARTSEARCH: |
||
377 | { |
||
378 | |||
379 | if ( objv.Length != 3 ) |
||
380 | { |
||
381 | throw new TclNumArgsException( interp, 2, objv, "arrayName" ); |
||
382 | } |
||
383 | if ( notArray ) |
||
384 | { |
||
385 | |||
386 | errorNotArray( interp, objv[2].ToString() ); |
||
387 | } |
||
388 | |||
389 | if ( var.sidVec == null ) |
||
390 | { |
||
391 | var.sidVec = new ArrayList( 10 ); |
||
392 | } |
||
393 | |||
394 | // Create a SearchId Object: |
||
395 | // To create a new SearchId object, a unique string |
||
396 | // identifier needs to be composed and we need to |
||
397 | // create an Enumeration of the array keys. The |
||
398 | // unique string identifier is created from three |
||
399 | // strings: |
||
400 | // |
||
401 | // "s-" is the default prefix |
||
402 | // "i" is a unique number that is 1+ the greatest |
||
403 | // SearchId index currently on the ArrayVar. |
||
404 | // "name" is the name of the array |
||
405 | // |
||
406 | // Once the SearchId string is created we construct a |
||
407 | // new SearchId object using the string and the |
||
408 | // Enumeration. From now on the string is used to |
||
409 | // uniquely identify the SearchId object. |
||
410 | |||
411 | int i = var.NextIndex; |
||
412 | |||
413 | string s = "s-" + i + "-" + objv[2].ToString(); |
||
414 | IDictionaryEnumerator e = ( (Hashtable)var.value ).GetEnumerator(); |
||
415 | var.sidVec.Add( new SearchId( e, s, i ) ); |
||
416 | interp.setResult( s ); |
||
417 | break; |
||
418 | } |
||
419 | |||
420 | case OPT_UNSET: |
||
421 | { |
||
422 | string pattern; |
||
423 | string name; |
||
424 | |||
425 | if ( ( objv.Length != 3 ) && ( objv.Length != 4 ) ) |
||
426 | { |
||
427 | throw new TclNumArgsException( interp, 2, objv, "arrayName ?pattern?" ); |
||
428 | } |
||
429 | if ( notArray ) |
||
430 | { |
||
431 | |||
432 | //Ignot this error -- errorNotArray(interp, objv[2].ToString()); |
||
433 | break; |
||
434 | } |
||
435 | if ( objv.Length == 3 ) |
||
436 | { |
||
437 | // When no pattern is given, just unset the whole array |
||
438 | |||
439 | interp.unsetVar( objv[2], 0 ); |
||
440 | } |
||
441 | else |
||
442 | { |
||
443 | |||
444 | pattern = objv[3].ToString(); |
||
445 | Hashtable table = (Hashtable)( ( (Hashtable)var.value ).Clone() ); |
||
446 | for ( IDictionaryEnumerator e = table.GetEnumerator(); e.MoveNext(); ) |
||
447 | { |
||
448 | name = (string)e.Key; |
||
449 | Var elem = (Var)e.Value; |
||
450 | if ( var.isVarUndefined() ) |
||
451 | { |
||
452 | continue; |
||
453 | } |
||
454 | if ( Util.stringMatch( name, pattern ) ) |
||
455 | { |
||
456 | interp.unsetVar( varName, name, 0 ); |
||
457 | } |
||
458 | } |
||
459 | } |
||
460 | break; |
||
461 | } |
||
462 | } |
||
463 | return TCL.CompletionCode.RETURN; |
||
464 | } |
||
465 | |||
466 | /// <summary> Error meassage thrown when an invalid identifier is used |
||
467 | /// to access an array. |
||
468 | /// |
||
469 | /// </summary> |
||
470 | /// <param name="interp">currrent interpreter. |
||
471 | /// </param> |
||
472 | /// <param name="String">var is the string representation of the |
||
473 | /// variable that was passed in. |
||
474 | /// </param> |
||
475 | |||
476 | private static void errorNotArray( Interp interp, string var ) |
||
477 | { |
||
478 | throw new TclException( interp, "\"" + var + "\" isn't an array" ); |
||
479 | } |
||
480 | |||
481 | |||
482 | /// <summary> Error message thrown when an invalid SearchId is used. The |
||
483 | /// string used to reference the SearchId is parced to determine |
||
484 | /// the reason for the failure. |
||
485 | /// |
||
486 | /// </summary> |
||
487 | /// <param name="interp">currrent interpreter. |
||
488 | /// </param> |
||
489 | /// <param name="String">sid is the string represenation of the |
||
490 | /// SearchId that was passed in. |
||
491 | /// </param> |
||
492 | |||
493 | internal static void errorIllegalSearchId( Interp interp, string varName, string sid ) |
||
494 | { |
||
495 | |||
496 | int val = validSearchId( sid.ToCharArray(), varName ); |
||
497 | |||
498 | if ( val == 1 ) |
||
499 | { |
||
500 | throw new TclException( interp, "couldn't find search \"" + sid + "\"" ); |
||
501 | } |
||
502 | else if ( val == 0 ) |
||
503 | { |
||
504 | throw new TclException( interp, "illegal search identifier \"" + sid + "\"" ); |
||
505 | } |
||
506 | else |
||
507 | { |
||
508 | throw new TclException( interp, "search identifier \"" + sid + "\" isn't for variable \"" + varName + "\"" ); |
||
509 | } |
||
510 | } |
||
511 | |||
512 | /// <summary> A valid SearchId is represented by the format s-#-arrayName. If |
||
513 | /// the SearchId string does not match this format than it is illegal, |
||
514 | /// else we cannot find it. This method is used by the |
||
515 | /// ErrorIllegalSearchId method to determine the type of error message. |
||
516 | /// |
||
517 | /// </summary> |
||
518 | /// <param name="char">pattern[] is the string use dto identify the SearchId |
||
519 | /// </param> |
||
520 | /// <returns> 1 if its a valid searchID; 0 if it is not a valid searchId, |
||
521 | /// but it is for the array, -1 if it is not a valid searchId and NOT |
||
522 | /// for the array. |
||
523 | /// </returns> |
||
524 | |||
525 | private static int validSearchId( char[] pattern, string varName ) |
||
526 | { |
||
527 | int i; |
||
528 | |||
529 | if ( ( pattern[0] != 's' ) || ( pattern[1] != '-' ) || ( pattern[2] < '0' ) || ( pattern[2] > '9' ) ) |
||
530 | { |
||
531 | return 0; |
||
532 | } |
||
533 | for ( i = 3; ( i < pattern.Length && pattern[i] != '-' ); i++ ) |
||
534 | { |
||
535 | if ( pattern[i] < '0' || pattern[i] > '9' ) |
||
536 | { |
||
537 | return 0; |
||
538 | } |
||
539 | } |
||
540 | if ( ++i >= pattern.Length ) |
||
541 | { |
||
542 | return 0; |
||
543 | } |
||
544 | if ( varName.Equals( new string( pattern, i, ( pattern.Length - i ) ) ) ) |
||
545 | { |
||
546 | return 1; |
||
547 | } |
||
548 | else |
||
549 | { |
||
550 | return -1; |
||
551 | } |
||
552 | } |
||
553 | } |
||
554 | } |