Develop and Download Open Source Software

Browse CVS Repository

Contents of /netruby/netruby/Object.cs

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1.1.1 - (show annotations) (download) (vendor branch)
Mon Apr 8 13:28:28 2002 UTC (22 years ago) by arton
Branch: MAIN, vendor
CVS Tags: start, HEAD
Changes since 1.1: +0 -0 lines
initial version 0.8

1 /**********************************************************************
2
3 object.c -
4
5 $Author: matz $
6 $Date: 2001/12/18 08:40:31 $
7 created at: Thu Jul 15 12:01:24 JST 1993
8
9 Copyright (C) 1993-2000 Yukihiro Matsumoto
10 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
11 Copyright (C) 2000 Information-technology Promotion Agency, Japan
12
13 **********************************************************************/
14 /*
15 Copyright(C) 2001-2002 arton
16
17 Permission is granted for use, copying, modification, distribution,
18 and distribution of modified versions of this work as long as the
19 above copyright notice is included.
20 */
21
22 using System;
23 using System.Collections;
24 using System.Reflection;
25 using System.Security;
26
27 namespace arton.NETRuby
28 {
29 public class RBasic
30 {
31 internal RBasic(NetRuby rb)
32 {
33 }
34 internal RBasic(NetRuby rb, RMetaObject meta)
35 {
36 klass = meta;
37 ruby = rb;
38 if (rb.SafeLevel >= 3)
39 {
40 flags |= FL.TAINT;
41 }
42 GetHashCode(); // define ID
43 }
44
45 internal RBasic(RBasic o)
46 {
47 ruby = o.ruby;
48 if (o.klass is RSingletonClass)
49 {
50 RMetaObject org = o.klass;
51 RMetaObject meta = (RMetaObject)org.Clone();
52 if (meta.m_tbl == null) meta.m_tbl = new st_table();
53 else meta.m_tbl.Clear();
54 foreach (DictionaryEntry ent in org.m_tbl)
55 {
56 RNMethod m = (RNMethod)ent.Value;
57 meta.m_tbl.Add(ent.Key, new RNMethod(m));
58 }
59 klass = meta;
60 }
61 else
62 {
63 klass = o.klass;
64 }
65 flags = o.flags;
66 if (o.Test(FL.EXIVAR))
67 {
68 ruby.CloneGenericIVar(this, o);
69 }
70 GetHashCode(); // define ID
71 }
72
73 public enum FL
74 {
75 EMPTY = 0,
76 USHIFT = 11,
77 USER0 = (1<<(USHIFT+0)),
78 USER1 = (1<<(USHIFT+1)),
79 USER2 = (1<<(USHIFT+2)),
80 USER3 = (1<<(USHIFT+3)),
81 USER4 = (1<<(USHIFT+4)),
82 USER5 = (1<<(USHIFT+5)),
83 USER6 = (1<<(USHIFT+6)),
84 USER7 = (1<<(USHIFT+7)),
85 UMASK = (0xff<<USHIFT),
86 SINGLETON = USER0,
87 FINALIZE = (1<<7),
88 TAINT = (1<<8),
89 EXIVAR = (1<<9),
90 FREEZE = (1<<10),
91 }
92
93 public const int Qfalse = 0;
94 public const int Qtrue = 2;
95 public const int Qnil = 4;
96
97 protected FL flags;
98 public RMetaObject klass;
99 public NetRuby ruby;
100
101 public override string ToString()
102 {
103 string s = ruby.ClassOf(this).Name;
104 s = String.Format("#<{0}:0x{1:x8}>", s, GetHashCode());
105 return s;
106 }
107 public virtual RString ToRString()
108 {
109 RString rs = new RString(ruby, ToString(), IsTainted);
110 return rs;
111 }
112 public virtual RArray ToArray()
113 {
114 ArrayList a = new ArrayList();
115 a.Add(this);
116 return new RArray(ruby, a);
117 }
118 public virtual RInteger ToInteger()
119 {
120 return null;
121 }
122 public virtual RFloat ToFloat()
123 {
124 return null;
125 }
126 public virtual RChar ToChar()
127 {
128 return new RChar(ruby, '?');
129 }
130 public virtual RMetaObject Class
131 {
132 get { return ruby.ClassOf(this).ClassReal; }
133 }
134 public virtual bool IsNil
135 {
136 get { return false; }
137 }
138 public virtual object And(object o)
139 {
140 return null;
141 }
142 public virtual object Or(object o)
143 {
144 return null;
145 }
146 public virtual object Xor(object o)
147 {
148 return null;
149 }
150
151 public RBasic Freeze()
152 {
153 flags |= FL.FREEZE;
154 return this;
155 }
156 public bool IsFrozen
157 {
158 get { return (flags & FL.FREEZE) != 0; }
159 }
160
161 internal void FrozenClassCheck()
162 {
163 if (IsFrozen)
164 {
165 string desc = "something(?!)";
166 if (IsSingleton)
167 {
168 desc = "object";
169 }
170 else
171 {
172 if (this is RModule || this is RIncClass)
173 {
174 desc = "module";
175 }
176 else if (this is RClass)
177 {
178 desc = "class";
179 }
180 }
181 ruby.ErrorFrozen(desc);
182 }
183 }
184
185 public bool IsTainted
186 {
187 get { return (flags & FL.TAINT) != 0; }
188 }
189 public virtual bool IsSingleton
190 {
191 get { return false; }
192 }
193 public RBasic Taint()
194 {
195 ruby.Secure(4);
196 if ((flags & FL.TAINT) == 0)
197 {
198 if ((flags & FL.FREEZE) != 0)
199 {
200 ruby.ErrorFrozen("object");
201 }
202 flags |= FL.TAINT;
203 }
204 return this;
205 }
206
207 public RBasic Untaint()
208 {
209 ruby.Secure(3);
210 if ((flags & FL.TAINT) != 0)
211 {
212 if ((flags & FL.FREEZE) != 0)
213 {
214 ruby.ErrorFrozen("object");
215 }
216 flags &= ~FL.FREEZE;
217 }
218 return this;
219 }
220 internal void Set(FL f)
221 {
222 flags |= f;
223 }
224 internal void Unset(FL f)
225 {
226 flags &= ~f;
227 }
228 public bool Test(FL f)
229 {
230 return ((flags & f) == 0) ? false : true;
231 }
232 public void Infect(RBasic o)
233 {
234 if (o.IsSpecialConst == false && IsSpecialConst == false)
235 {
236 flags |= (o.flags & FL.TAINT);
237 }
238 }
239 public static bool RTest(object o)
240 {
241 if (o == null || (o is bool && (bool)o == false))
242 return false;
243 return true;
244 }
245 public static bool IsTaintedObject(object o)
246 {
247 if (o is RBasic && ((RBasic)o).IsTainted)
248 return true;
249 return false;
250 }
251 public virtual object Inspect()
252 {
253 return ruby.Funcall(this, "to_s", null);
254 }
255 public delegate object InspectMethod(RBasic r, object[] arg);
256 public virtual bool RespondTo(object[] argv)
257 {
258 object[] args = new object[2];
259 ruby.ScanArgs(argv, "11", args);
260 uint id = ruby.ToID(args[0]);
261 return RespondTo(id, !RTest(args[1]));
262 }
263 public virtual bool RespondTo(uint id, bool priv)
264 {
265 if (ruby.IsMethodBound(klass, id, !priv))
266 {
267 return true;
268 }
269 return false;
270 }
271 public virtual object Send(string name, params object[] argv)
272 {
273 RThread th = ruby.GetCurrentContext();
274 th.PushIter((th.IsBlockGiven) ? ITER.PRE : ITER.NOT);
275 object obj = ruby.Call(klass, this, name, argv, 1);
276 th.PopIter();
277 return obj;
278 }
279 public virtual object InstanceEval(params object[] argv)
280 {
281 RMetaObject klass;
282 if (IsSpecialConst)
283 klass = null;
284 else
285 klass = SingletonClass(this, ruby);
286
287 return ruby.SpecificEval(klass, this, argv);
288 }
289 protected object InspectObj(string str)
290 {
291 string s = "#" + str.Substring(1) + ">";
292 if (IsTainted)
293 {
294 return new RString(ruby, s, true);
295 }
296 return s;
297 }
298
299 // for inspect (use RString.AsString for general purpose)
300 protected string obj_to_s(object x)
301 {
302 if (x == null)
303 return "nil";
304 if (x is string)
305 return(string)x;
306 if (x is int || x is long)
307 return x.ToString();
308 object r = ruby.Funcall(x, "to_s", null);
309 if (r is RString)
310 return r.ToString();
311 return (string)r;
312 }
313
314 public virtual bool IsSpecialConst
315 {
316 get { return false; }
317 }
318 public static bool IsSpecialConstType(object o)
319 {
320 if (o is RBasic) return ((RBasic)o).IsSpecialConst;
321 if (o == null) return true; // nil
322 if (o is bool) return true; // bool
323 if (o is int || o is long || o is double) return true;
324 return false;
325 }
326 public bool IsKindOf(object c)
327 {
328 RMetaObject cl = ruby.ClassOf(this);
329 if (c is RMetaObject == false)
330 {
331 throw new eTypeError("class or module required");
332 }
333 while (cl != null)
334 {
335 if (cl == c || cl.m_tbl == ((RMetaObject)c).m_tbl)
336 return true;
337 cl = cl.super;
338 }
339 return false;
340 }
341
342 public override bool Equals(object o)
343 {
344 if (base.Equals(o)) return true;
345 return false;
346 }
347 public override int GetHashCode() // for voiding CS0659 warning.
348 {
349 return base.GetHashCode();
350 }
351 public virtual bool Eql(object o)
352 {
353 if (GetType() != o.GetType()) return false;
354 return ruby.Eql(o, this);
355 }
356
357 public bool IsIVarDefined(string name)
358 {
359 return IsIVarDefined(ruby.intern(name));
360 }
361 public virtual bool IsIVarDefined(uint id)
362 {
363 if (Test(FL.EXIVAR) || IsSpecialConst)
364 {
365 return ruby.IsGenericIVarDefined(this, id);
366 }
367 return false;
368 }
369 public object IVarGet(string name)
370 {
371 return IVarGet(ruby.intern(name));
372 }
373 public virtual object IVarGet(uint iid)
374 {
375 if (Test(FL.EXIVAR) || IsSpecialConst)
376 {
377 return ruby.GenericIVarGet(this, iid);
378 }
379 if (ruby.verbose)
380 {
381 ruby.warning(String.Format("instance variable {0} not initialized",
382 ruby.id2name(iid)));
383 }
384 return null;
385 }
386 public virtual object IVarSet(uint uid, object val)
387 {
388 IVarCheck();
389 ruby.GenericIVarSet(this, uid, val);
390 Set(FL.EXIVAR);
391 return val;
392 }
393 public virtual object IVarSet(string name, object val)
394 {
395 return IVarSet(ruby.intern(name), val);
396 }
397
398 protected void IVarCheck()
399 {
400 if (IsTainted == false && ruby.SafeLevel >= 4)
401 {
402 throw new SecurityException("Insecure: can't modify instance variable");
403 }
404 if (IsFrozen) ruby.ErrorFrozen("object");
405 }
406
407 public virtual RArray InstanceVariables
408 {
409 get {
410 ArrayList ary = new ArrayList();
411 if (ruby.generic_iv_tbl != null)
412 {
413 if (Test(FL.EXIVAR) || IsSpecialConst)
414 {
415 st_table tbl;
416 if (ruby.generic_iv_tbl.lookup(this, out tbl))
417 {
418 foreach (DictionaryEntry ent in tbl)
419 {
420 if (Parser.is_instance_id((uint)ent.Key))
421 {
422 ary.Add(ruby.id2name((uint)ent.Key));
423 }
424 }
425 }
426 }
427 }
428 return new RArray(ruby, ary);
429 }
430 }
431 public virtual object RemoveInstanceVariable(uint id)
432 {
433 object val = null;
434 if (IsTainted && ruby.SafeLevel >= 4)
435 throw new SecurityException("Insecure: can't modify instance variable");
436 if (IsFrozen) ruby.ErrorFrozen("object");
437 if (Parser.is_instance_id(id) == false)
438 {
439 throw new eNameError("`" + ruby.id2name(id) + "' is not an instance variable");
440 }
441 if (Test(FL.EXIVAR) || IsSpecialConst)
442 {
443 return ruby.GenericIVarRemove(this, id);
444 }
445 return val;
446 }
447 public virtual int id
448 {
449 get { return GetHashCode() << 1; }
450 }
451 public virtual RArray Methods
452 {
453 get { return ruby.ClassOf(this).ClassInstanceMethods(new object[1] {true}); }
454 }
455 public virtual RArray SingletonMethods
456 {
457 get { return ruby.ClassOf(this).SingletonMethods; }
458 }
459 public virtual RArray ProtectedMethods
460 {
461 get { return ruby.ClassOf(this).ClassProtectedInstanceMethods(new object[1] {true}); }
462 }
463 public virtual RArray PrivateMethods
464 {
465 get { return ruby.ClassOf(this).ClassPrivateInstanceMethods(new object[1] { true}); }
466 }
467
468 static public RClass SingletonClass(object obj, NetRuby ruby)
469 {
470 if (obj is int || obj is long || obj is double || Symbol.IsSymbol(obj))
471 {
472 throw new eTypeError("can't define singleton");
473 }
474 if (RBasic.IsSpecialConstType(obj))
475 {
476 if (obj == null)
477 {
478 if (ruby.cNilClass.IsSingleton == false)
479 {
480 ruby.cNilClass = new RSingletonClass(ruby.cNilClass);
481 return ruby.cNilClass;
482 }
483 }
484 bool b = (bool)obj;
485 RClass o = (b) ? ruby.cTrueClass : ruby.cFalseClass;
486 if (o.IsSingleton == false)
487 {
488 if (b)
489 o = ruby.cTrueClass = new RSingletonClass(o);
490 else
491 o = ruby.cFalseClass = new RSingletonClass(o);
492 }
493 return o;
494 }
495 if (obj is RBasic == false)
496 {
497 ruby.bug("Unknown object " + obj.ToString());
498 }
499 RBasic bas = (RBasic)obj;
500 RClass klass = null;
501 if (bas is RSingletonClass)
502 {
503 klass = (RClass)bas.klass;
504 }
505 else
506 {
507 klass = new RSingletonClass(bas.klass);
508 bas.klass = klass;
509 klass.AttachSingleton((RObjectBase)obj);
510 }
511 if (bas.Test(FL.TAINT))
512 {
513 klass.Set(FL.TAINT);
514 }
515 else
516 {
517 klass.Unset(FL.TAINT);
518 }
519 if (bas.Test(FL.FREEZE))
520 {
521 klass.Set(FL.FREEZE);
522 }
523
524 return klass;
525 }
526 public virtual object Missing(params object[] args)
527 {
528 return ruby.Missing(this, args);
529 }
530
531 //
532 // Internal Methods for interpreter
533 //
534 public delegate object RMethod(RBasic rcver, params object[] args);
535 protected object ruby_dummy(RBasic r, params object[] args)
536 {
537 return null;
538 }
539 static internal object ruby_missing(RBasic r, params object[] args)
540 {
541 return r.Missing(args);
542 }
543 protected object ruby_isnil(RBasic r, params object[] args)
544 {
545 return r.IsNil;
546 }
547 internal object ruby_equals(RBasic r, params object[] args)
548 {
549 return r.Equals(ruby.InstanceOf(args[0]));
550 }
551 internal object ruby_eql(RBasic r, params object[] args)
552 {
553 return r.Eql(ruby.InstanceOf(args[0]));
554 }
555 static protected object ruby_compare(RBasic r, params object[] args)
556 {
557 return ((IComparable)r).CompareTo(args[0]);
558 }
559 protected object ruby_false(RBasic r, params object[] args)
560 {
561 return false;
562 }
563 protected object ruby_true(RBasic r, params object[] args)
564 {
565 return true;
566 }
567 protected object ruby_id(RBasic r, params object[] args)
568 {
569 return r.id;
570 }
571 protected object ruby_class(RBasic r, params object[] args)
572 {
573 return r.Class;
574 }
575 protected object ruby_and(RBasic r, params object[] args)
576 {
577 return r.And(ruby.InstanceOf(args[0]));
578 }
579 protected object ruby_or(RBasic r, params object[] args)
580 {
581 return r.Or(ruby.InstanceOf(args[0]));
582 }
583 protected object ruby_xor(RBasic r, params object[] args)
584 {
585 return r.Xor(ruby.InstanceOf(args[0]));
586 }
587 protected object ruby_inspect(RBasic r, params object[] args)
588 {
589 return r.Inspect();
590 }
591 protected object ruby_respond_to(RBasic r, params object[] args)
592 {
593 return r.RespondTo(args);
594 }
595 protected object ruby_send(RBasic r, params object[] args)
596 {
597 if (args.Length < 1)
598 throw new eArgError("no method name given");
599 object[] argv = new object[args.Length - 1];
600 Array.Copy(args, 1, argv, 0, args.Length - 1);
601 return r.Send(args[0].ToString(), argv);
602 }
603 protected object instance_eval(RBasic r, params object[] args)
604 {
605 return r.InstanceEval(args);
606 }
607 protected object ruby_methods(RBasic r, params object[] args)
608 {
609 return r.Methods;
610 }
611 protected object ruby_singleton_methods(RBasic r, params object[] args)
612 {
613 return r.SingletonMethods;
614 }
615 protected object ruby_protected_methods(RBasic r, params object[] args)
616 {
617 return r.ProtectedMethods;
618 }
619 protected object ruby_private_methods(RBasic r, params object[] args)
620 {
621 return r.PrivateMethods;
622 }
623 protected object ruby_instance_variables(RBasic r, params object[] args)
624 {
625 return r.InstanceVariables;
626 }
627 protected object ruby_remove_instance_variable(RBasic r, params object[] args)
628 {
629 return r.RemoveInstanceVariable(ruby.ToID(args[0]));
630 }
631 protected object ruby_to_a(RBasic r, params object[] args)
632 {
633 return r.ToArray();
634 }
635 protected object ruby_to_s(RBasic r, params object[] args)
636 {
637 return r.ToRString();
638 }
639 protected object ruby_to_f(RBasic r, params object[] args)
640 {
641 return r.ToFloat();
642 }
643 protected object ruby_to_c(RBasic r, params object[] args)
644 {
645 return r.ToChar();
646 }
647 protected object ruby_clone(RBasic r, params object[] args)
648 {
649 try
650 {
651 return ((ICloneable)r).Clone();
652 }
653 #if _DEBUG
654 catch (Exception e)
655 {
656 System.Console.WriteLine(e.Message);
657 System.Console.WriteLine(e.StackTrace);
658 #else
659 catch
660 {
661 #endif
662 throw new eTypeError("can't clone " + ruby.ClassOf(r).Name);
663 }
664 }
665 protected object ruby_dup(RBasic r, params object[] args)
666 {
667 RBasic dup = (RBasic)ruby.Funcall(r, "clone", null);
668 if (dup.GetType() != r.GetType())
669 {
670 throw new eTypeError("duplicated object must be same type");
671 }
672 if (dup.IsSpecialConst == false)
673 {
674 dup.klass = r.klass;
675 dup.flags = r.flags;
676 dup.Infect(r);
677 }
678 return dup;
679 }
680 protected object ruby_taint(RBasic r, params object[] args)
681 {
682 return r.Taint();
683 }
684 protected object ruby_istainted(RBasic r, params object[] args)
685 {
686 return r.IsTainted;
687 }
688 protected object ruby_untaint(RBasic r, params object[] args)
689 {
690 return r.Untaint();
691 }
692 protected object ruby_freeze(RBasic r, params object[] args)
693 {
694 return r.Freeze();
695 }
696 protected object ruby_isfrozen(RBasic r, params object[] args)
697 {
698 return r.IsFrozen;
699 }
700 }
701
702 public class RData : RBasic
703 {
704 internal RData(NetRuby rb, RMetaObject meta) :
705 base(rb, meta)
706 {
707 }
708 }
709
710 public class RObjectBase : RBasic, ICloneable
711 {
712 internal RObjectBase(NetRuby rb, RMetaObject meta)
713 : base(rb, meta)
714 {
715 iv_tbl = null;
716 }
717 internal RObjectBase(RObjectBase o)
718 : base(o)
719 {
720 klass.AttachSingleton(this);
721 if (o.iv_tbl != null)
722 {
723 iv_tbl = (st_table)o.iv_tbl.Clone();
724 }
725 }
726
727 internal st_table iv_tbl;
728
729 public virtual object Run()
730 {
731 return null;
732 }
733
734 public override bool IsIVarDefined(uint iid)
735 {
736 object val = null;
737 if (iv_tbl != null && iv_tbl.lookup(iid, out val))
738 {
739 return true;
740 }
741 return false;
742 }
743 public override object IVarGet(uint iid)
744 {
745 object val = null;
746 if (iv_tbl != null && iv_tbl.lookup(iid, out val))
747 {
748 return val;
749 }
750 if (ruby.verbose)
751 {
752 ruby.warning(String.Format("instance variable {0} not initialized",
753 ruby.id2name(iid)));
754 }
755 return null;
756 }
757 public override object IVarSet(uint uid, object val)
758 {
759 IVarCheck();
760 if (iv_tbl == null) iv_tbl = new st_table();
761 iv_tbl[uid] = val;
762 return val;
763 }
764
765 public override RArray InstanceVariables
766 {
767 get {
768 ArrayList ary = new ArrayList();
769 if (iv_tbl != null)
770 {
771 foreach (DictionaryEntry ent in iv_tbl)
772 {
773 if (Parser.is_instance_id((uint)ent.Key))
774 {
775 ary.Add(ruby.id2name((uint)ent.Key));
776 }
777 }
778 }
779 return new RArray(ruby, ary);
780 }
781 }
782
783 public override object RemoveInstanceVariable(uint id)
784 {
785 object val = null;
786 if (IsTainted && ruby.SafeLevel >= 4)
787 throw new SecurityException("Insecure: can't modify instance variable");
788 if (IsFrozen) ruby.ErrorFrozen("object");
789 if (Parser.is_instance_id(id) == false)
790 {
791 throw new eNameError("`" + ruby.id2name(id) + "' is not an instance variable");
792 }
793 if (iv_tbl != null)
794 {
795 val = iv_tbl[id];
796 iv_tbl.Remove(id);
797 }
798 return val;
799 }
800
801 internal bool valGet(uint id, out object val)
802 {
803 val = null;
804 if (iv_tbl != null && iv_tbl.lookup(id, out val))
805 {
806 return true;
807 }
808 return false;
809 }
810
811 public void DefineSingletonMethod(string name, MethodInfo mi)
812 {
813 SingletonClass(this, ruby).DefineMethod(name, mi);
814 }
815 public void DefineSingletonMethod(string name, RMethod rm, int argc)
816 {
817 SingletonClass(this, ruby).DefineMethod(name, rm, argc);
818 }
819
820 public virtual void AttachSingleton(RObjectBase obj)
821 {
822 // overriden by RSingletonClass
823 }
824
825 public virtual object Clone()
826 {
827 ruby.bug("invalid clone call");
828 return null;
829 }
830
831 }
832
833 public class RObject : RObjectBase, ICloneable
834 {
835 internal RObject(NetRuby rb, RMetaObject meta)
836 : base(rb, meta)
837 {
838 }
839 internal RObject(RObject o)
840 : base(o)
841 {
842 }
843
844 public override object Inspect()
845 {
846 if (iv_tbl != null && iv_tbl.Count > 0)
847 {
848 string s = ruby.ClassOf(this).Name;
849 if (ruby.IsInspecting(this))
850 {
851 return String.Format("#<{0}:0x{1:x8} ...>", s, id);
852 }
853 return InspectObj(String.Format("-<{0}:0x{1:x8}", s, id));
854 }
855 return base.Inspect();
856 }
857
858 public override object Clone()
859 {
860 RObject o = new RObject(this);
861 return o;
862 }
863 }
864
865 public class RMainObject : RObject // for top level object only
866 {
867 public RMainObject(NetRuby rb)
868 : base(rb, rb.cObject)
869 {
870 }
871 public RMainObject(RObject o)
872 : base(o.ruby, o.ruby.cObject)
873 {
874 o.klass.AttachSingleton(this);
875 if (o.iv_tbl != null)
876 {
877 iv_tbl = (st_table)o.iv_tbl.Clone();
878 }
879 }
880 public override string ToString()
881 {
882 return "main";
883 }
884 public object Include(object[] args)
885 {
886 ruby.Secure(4);
887 return ruby.cObject.Include(args);
888 }
889 public object Public(object[] args)
890 {
891 return ruby.cObject.Public(args);
892 }
893 public object Private(object[] args)
894 {
895 return ruby.cObject.Private(args);
896 }
897 }
898 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26