Add header.
[kai/samba.git] / source4 / lib / appweb / ejs-2.0 / ejs / ejsClass.c
1 /*
2  *      @file   ejsClass.c
3  *      @brief  EJS class support
4  */
5 /********************************* Copyright **********************************/
6 /*
7  *      @copy   default
8  *      
9  *      Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
10  *      Copyright (c) Michael O'Brien, 1994-1995. All Rights Reserved.
11  *      
12  *      This software is distributed under commercial and open source licenses.
13  *      You may use the GPL open source license described below or you may acquire 
14  *      a commercial license from Mbedthis Software. You agree to be fully bound 
15  *      by the terms of either license. Consult the LICENSE.TXT distributed with 
16  *      this software for full details.
17  *      
18  *      This software is open source; you can redistribute it and/or modify it 
19  *      under the terms of the GNU General Public License as published by the 
20  *      Free Software Foundation; either version 2 of the License, or (at your 
21  *      option) any later version. See the GNU General Public License for more 
22  *      details at: http://www.mbedthis.com/downloads/gplLicense.html
23  *      
24  *      This program is distributed WITHOUT ANY WARRANTY; without even the 
25  *      implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
26  *      
27  *      This GPL license does NOT permit incorporating this software into 
28  *      proprietary programs. If you are unable to comply with the GPL, you must
29  *      acquire a commercial license to use this software. Commercial licenses 
30  *      for this software and support services are available from Mbedthis 
31  *      Software at http://www.mbedthis.com 
32  *      
33  *      @end
34  */
35 /********************************* Includes ***********************************/
36
37 #include        "ejs.h"
38
39 #if BLD_FEATURE_EJS
40
41 /************************************ Code ************************************/
42 /*
43  *      Internal API
44  *
45  *      Routine to create a simple class object. This routine will create a
46  *      stand-alone class object. Callers must insert this into the relevant
47  *      "global" object for name resolution. From these class objects, instance
48  *      objects may be created via the javascript "new" command.
49  *
50  *      Users should use ejsDefineClass
51  */
52
53 EjsVar *ejsCreateSimpleClass(Ejs *ep, EjsVar *baseClass, const char *className)
54 {
55         EjsProperty     *pp;
56         EjsVar          *classObj;
57
58         /*
59          *      Create an instance of an Object to act as the static class object
60          */
61         classObj = ejsCreateSimpleObjUsingClass(ep, baseClass);
62         if (classObj == 0) {
63                 mprAssert(classObj);
64                 return 0;
65         }
66         ejsSetClassName(ep, classObj, className);
67
68         /*
69          *      Set the propotype property to point to this class.
70          *      Note: this is a self reference so the alive bit will not be turned on.
71          */
72         pp = ejsSetProperty(ep, classObj, "prototype", classObj);
73         ejsMakePropertyEnumerable(pp, 0);
74
75         return classObj;
76 }
77
78 /******************************************************************************/
79 /*
80  *      Define a class in the given interpreter. If parentClass is specified, the
81  *      class is defined in the parent. Otherwise, the class will be defined
82  *      locally/globally. ClassName and extends are full variable specs 
83  *      (may contain ".")
84  */
85
86 EjsVar *ejsDefineClass(Ejs *ep, const char *className, const char *extends, 
87         EjsCMethod constructor)
88 {
89         EjsVar          *parentClass, *classObj, *baseClass, *vp;
90         char            *name;
91         char            *cp;
92
93         /*
94          *      If the className is a qualified name (with "."), then get the 
95          *      parent class name.
96          */
97         name = mprStrdup(ep, className);
98         cp = strrchr(name, '.');
99         if (cp != 0) {
100                 *cp++ = '\0';
101                 className = cp;
102                 parentClass = ejsFindProperty(ep, 0, 0, ep->global, ep->local, name, 0);
103                 if (parentClass == 0 || parentClass->type != EJS_TYPE_OBJECT) {
104                         mprError(ep, MPR_LOC, "Can't find class's parent class %s", name);
105                         mprFree(name);
106                         return 0;
107                 }
108
109         } else {
110                 /*
111                  *      Simple class name without a "." so create the class locally 
112                  *      if a local scope exists, otherwise globally.
113                  */
114                 parentClass = (ep->local) ? ep->local : ep->global;
115         }
116
117         if (parentClass == 0) {
118                 mprError(ep, MPR_LOC, "Can't find parent class");
119                 mprFree(name);
120                 return 0;
121         }
122
123         /* OPT should use function that doesn't parse [] . */
124         baseClass = ejsGetClass(ep, 0, extends);
125         if (baseClass == 0) {
126                 mprAssert(baseClass);
127                 mprFree(name);
128                 return 0;
129         }
130
131         classObj = ejsCreateSimpleClass(ep, baseClass, className);
132         if (classObj == 0) {
133                 mprAssert(classObj);
134                 mprFree(name);
135                 return 0;
136         }
137
138         if (constructor) {
139                 ejsDefineCMethod(ep, classObj, className, constructor, 0);
140         }
141
142         ejsSetPropertyAndFree(ep, parentClass, className, classObj);
143
144         vp = ejsGetPropertyAsVar(ep, parentClass, className);
145         mprFree(name);
146
147         return vp;
148 }
149
150 /******************************************************************************/
151 /*
152  *      Find a class and return the property defining the class. ClassName may 
153  *      contain "." and is interpreted relative to obj. Obj is typically some
154  *      parent object, ep->local or ep->global. If obj is null, then the global 
155  *      space is used.
156  */
157
158 EjsVar *ejsGetClass(Ejs *ep, EjsVar *obj, const char *className)
159 {
160         EjsVar          *vp;
161
162         mprAssert(ep);
163
164         /*
165          *      Search first for a constructor of the name of class
166          *      global may not be defined yet.
167          */
168         if (obj) {
169                 vp = ejsFindProperty(ep, 0, 0, obj, 0, className, 0);
170
171         } else {
172                 mprAssert(ep->global);
173                 vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, className, 0);
174         }
175         if (vp == 0 || vp->type != EJS_TYPE_OBJECT) {
176                 return 0;
177         }
178
179         /*
180          *      Return a reference to the prototype (self) reference. This
181          *      ensures that even if "obj" is deleted, this reference will remain
182          *      usable.
183          */
184         return ejsGetPropertyAsVar(ep, vp, "prototype");
185 }
186
187 /******************************************************************************/
188 /*
189  *      Return the class name of a class or object
190  */
191
192 const char *ejsGetClassName(EjsVar *vp)
193 {
194         EjsObj  *obj;
195
196         mprAssert(vp);
197         mprAssert(vp->type == EJS_TYPE_OBJECT);
198         mprAssert(vp->objectState->baseClass);
199
200         if (vp == 0 || !ejsVarIsObject(vp)) {
201                 return 0;
202         }
203         obj = vp->objectState;
204
205         return obj->className;
206 }
207
208 /******************************************************************************/
209 /*
210  *      Return the class name of an objects underlying class
211  *      If called on an object, it returns the base class. 
212  *      If called on a class, it returns the base class for the class. 
213  */
214
215 const char *ejsGetBaseClassName(EjsVar *vp)
216 {
217         EjsObj  *obj;
218
219         mprAssert(vp);
220         mprAssert(vp->type == EJS_TYPE_OBJECT);
221         mprAssert(vp->objectState->baseClass);
222
223         if (vp == 0 || !ejsVarIsObject(vp)) {
224                 return 0;
225         }
226         obj = vp->objectState;
227         if (obj->baseClass == 0) {
228                 return 0;
229         }
230         mprAssert(obj->baseClass->objectState);
231
232         return obj->baseClass->objectState->className;
233 }
234
235 /******************************************************************************/
236
237 EjsVar *ejsGetBaseClass(EjsVar *vp)
238 {
239         if (vp == 0 || !ejsVarIsObject(vp) || vp->objectState == 0) {
240                 mprAssert(0);
241                 return 0;
242         }
243         return vp->objectState->baseClass;
244 }
245
246 /******************************************************************************/
247
248 void ejsSetBaseClass(EjsVar *vp, EjsVar *baseClass)
249 {
250         if (vp == 0 || !ejsVarIsObject(vp) || vp->objectState == 0) {
251                 mprAssert(0);
252                 return;
253         }
254         vp->objectState->baseClass = baseClass;
255 }
256
257 /******************************************************************************/
258
259 #else
260 void ejsProcsDummy() {}
261
262 /******************************************************************************/
263 #endif /* BLD_FEATURE_EJS */
264
265 /*
266  * Local variables:
267  * tab-width: 4
268  * c-basic-offset: 4
269  * End:
270  * vim:tw=78
271  * vim600: sw=4 ts=4 fdm=marker
272  * vim<600: sw=4 ts=4
273  */