Code

moving trunk for module inkscape
[inkscape.git] / src / dom / js / jscntxt.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * ***** BEGIN LICENSE BLOCK *****
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is Mozilla Communicator client code, released
17  * March 31, 1998.
18  *
19  * The Initial Developer of the Original Code is
20  * Netscape Communications Corporation.
21  * Portions created by the Initial Developer are Copyright (C) 1998
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either of the GNU General Public License Version 2 or later (the "GPL"),
28  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
40 /*
41  * JS execution context.
42  */
43 #include "jsstddef.h"
44 #include <stdarg.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include "jstypes.h"
48 #include "jsarena.h" /* Added by JSIFY */
49 #include "jsutil.h" /* Added by JSIFY */
50 #include "jsclist.h"
51 #include "jsprf.h"
52 #include "jsatom.h"
53 #include "jscntxt.h"
54 #include "jsconfig.h"
55 #include "jsdbgapi.h"
56 #include "jsexn.h"
57 #include "jsgc.h"
58 #include "jslock.h"
59 #include "jsnum.h"
60 #include "jsobj.h"
61 #include "jsopcode.h"
62 #include "jsscan.h"
63 #include "jsscript.h"
64 #include "jsstr.h"
66 JSContext *
67 js_NewContext(JSRuntime *rt, size_t stackChunkSize)
68 {
69     JSContext *cx;
70     JSBool ok, first;
72     cx = (JSContext *) malloc(sizeof *cx);
73     if (!cx)
74         return NULL;
75     memset(cx, 0, sizeof *cx);
77     cx->runtime = rt;
78 #if JS_STACK_GROWTH_DIRECTION > 0
79     cx->stackLimit = (jsuword)-1;
80 #endif
81 #ifdef JS_THREADSAFE
82     js_InitContextForLocking(cx);
83 #endif
85     JS_LOCK_GC(rt);
86     for (;;) {
87         first = (rt->contextList.next == &rt->contextList);
88         if (rt->state == JSRTS_UP) {
89             JS_ASSERT(!first);
90             break;
91         }
92         if (rt->state == JSRTS_DOWN) {
93             JS_ASSERT(first);
94             rt->state = JSRTS_LAUNCHING;
95             break;
96         }
97         JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT);
98     }
99     JS_APPEND_LINK(&cx->links, &rt->contextList);
100     JS_UNLOCK_GC(rt);
102     /*
103      * First we do the infallible, every-time per-context initializations.
104      * Should a later, fallible initialization (js_InitRegExpStatics, e.g.,
105      * or the stuff under 'if (first)' below) fail, at least the version
106      * and arena-pools will be valid and safe to use (say, from the last GC
107      * done by js_DestroyContext).
108      */
109     cx->version = JSVERSION_DEFAULT;
110     cx->jsop_eq = JSOP_EQ;
111     cx->jsop_ne = JSOP_NE;
112     JS_InitArenaPool(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval));
113     JS_InitArenaPool(&cx->tempPool, "temp", 1024, sizeof(jsdouble));
115 #if JS_HAS_REGEXPS
116     if (!js_InitRegExpStatics(cx, &cx->regExpStatics)) {
117         js_DestroyContext(cx, JS_NO_GC);
118         return NULL;
119     }
120 #endif
121 #if JS_HAS_EXCEPTIONS
122     cx->throwing = JS_FALSE;
123 #endif
125     /*
126      * If cx is the first context on this runtime, initialize well-known atoms,
127      * keywords, numbers, and strings.  If one of these steps should fail, the
128      * runtime will be left in a partially initialized state, with zeroes and
129      * nulls stored in the default-initialized remainder of the struct.  We'll
130      * clean the runtime up under js_DestroyContext, because cx will be "last"
131      * as well as "first".
132      */
133     if (first) {
134         ok = (rt->atomState.liveAtoms == 0)
135              ? js_InitAtomState(cx, &rt->atomState)
136              : js_InitPinnedAtoms(cx, &rt->atomState);
137         if (ok)
138             ok = js_InitScanner(cx);
139         if (ok)
140             ok = js_InitRuntimeNumberState(cx);
141         if (ok)
142             ok = js_InitRuntimeStringState(cx);
143         if (!ok) {
144             js_DestroyContext(cx, JS_NO_GC);
145             return NULL;
146         }
148         JS_LOCK_GC(rt);
149         rt->state = JSRTS_UP;
150         JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
151         JS_UNLOCK_GC(rt);
152     }
154     return cx;
157 void
158 js_DestroyContext(JSContext *cx, JSGCMode gcmode)
160     JSRuntime *rt;
161     JSBool last;
162     JSArgumentFormatMap *map;
164     rt = cx->runtime;
166     /* Remove cx from context list first. */
167     JS_LOCK_GC(rt);
168     JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING);
169     JS_REMOVE_LINK(&cx->links);
170     last = (rt->contextList.next == &rt->contextList);
171     if (last)
172         rt->state = JSRTS_LANDING;
173     JS_UNLOCK_GC(rt);
175     if (last) {
176 #ifdef JS_THREADSAFE
177         /*
178          * If cx is not in a request already, begin one now so that we wait
179          * for any racing GC started on a not-last context to finish, before
180          * we plow ahead and unpin atoms.  Note that even though we begin a
181          * request here if necessary, we end all requests on cx below before
182          * forcing a final GC.  This lets any not-last context destruction
183          * racing in another thread try to force or maybe run the GC, but by
184          * that point, rt->state will not be JSRTS_UP, and that GC attempt
185          * will return early.
186          */
187         if (cx->requestDepth == 0)
188             JS_BeginRequest(cx);
189 #endif
191         /* Unpin all pinned atoms before final GC. */
192         js_UnpinPinnedAtoms(&rt->atomState);
194         /* Unlock and clear GC things held by runtime pointers. */
195         js_FinishRuntimeNumberState(cx);
196         js_FinishRuntimeStringState(cx);
198         /* Clear debugging state to remove GC roots. */
199         JS_ClearAllTraps(cx);
200         JS_ClearAllWatchPoints(cx);
201     }
203 #if JS_HAS_REGEXPS
204     /*
205      * Remove more GC roots in regExpStatics, then collect garbage.
206      * XXX anti-modularity alert: we rely on the call to js_RemoveRoot within
207      * XXX this function call to wait for any racing GC to complete, in the
208      * XXX case where JS_DestroyContext is called outside of a request on cx
209      */
210     js_FreeRegExpStatics(cx, &cx->regExpStatics);
211 #endif
213 #ifdef JS_THREADSAFE
214     /*
215      * Destroying a context implicitly calls JS_EndRequest().  Also, we must
216      * end our request here in case we are "last" -- in that event, another
217      * js_DestroyContext that was not last might be waiting in the GC for our
218      * request to end.  We'll let it run below, just before we do the truly
219      * final GC and then free atom state.
220      *
221      * At this point, cx must be inaccessible to other threads.  It's off the
222      * rt->contextList, and it should not be reachable via any object private
223      * data structure.
224      */
225     while (cx->requestDepth != 0)
226         JS_EndRequest(cx);
227 #endif
229     if (last) {
230         /* Always force, so we wait for any racing GC to finish. */
231         js_ForceGC(cx, GC_LAST_CONTEXT);
233         /* Iterate until no finalizer removes a GC root or lock. */
234         while (rt->gcPoke)
235             js_GC(cx, GC_LAST_CONTEXT);
237         /* Try to free atom state, now that no unrooted scripts survive. */
238         if (rt->atomState.liveAtoms == 0)
239             js_FreeAtomState(cx, &rt->atomState);
241         /* Take the runtime down, now that it has no contexts or atoms. */
242         JS_LOCK_GC(rt);
243         rt->state = JSRTS_DOWN;
244         JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
245         JS_UNLOCK_GC(rt);
246     } else {
247         if (gcmode == JS_FORCE_GC)
248             js_ForceGC(cx, 0);
249         else if (gcmode == JS_MAYBE_GC)
250             JS_MaybeGC(cx);
251     }
253     /* Free the stuff hanging off of cx. */
254     JS_FinishArenaPool(&cx->stackPool);
255     JS_FinishArenaPool(&cx->tempPool);
256     if (cx->lastMessage)
257         free(cx->lastMessage);
259     /* Remove any argument formatters. */
260     map = cx->argumentFormatMap;
261     while (map) {
262         JSArgumentFormatMap *temp = map;
263         map = map->next;
264         JS_free(cx, temp);
265     }
267     /* Destroy the resolve recursion damper. */
268     if (cx->resolvingTable) {
269         JS_DHashTableDestroy(cx->resolvingTable);
270         cx->resolvingTable = NULL;
271     }
273     /* Finally, free cx itself. */
274     free(cx);
277 JSBool
278 js_ValidContextPointer(JSRuntime *rt, JSContext *cx)
280     JSCList *cl;
282     for (cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next) {
283         if (cl == &cx->links)
284             return JS_TRUE;
285     }
286     JS_RUNTIME_METER(rt, deadContexts);
287     return JS_FALSE;
290 JSContext *
291 js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp)
293     JSContext *cx = *iterp;
295     if (unlocked)
296         JS_LOCK_GC(rt);
297     if (!cx)
298         cx = (JSContext *)&rt->contextList;
299     cx = (JSContext *)cx->links.next;
300     if (&cx->links == &rt->contextList)
301         cx = NULL;
302     *iterp = cx;
303     if (unlocked)
304         JS_UNLOCK_GC(rt);
305     return cx;
308 static void
309 ReportError(JSContext *cx, const char *message, JSErrorReport *reportp)
311     /*
312      * Check the error report, and set a JavaScript-catchable exception
313      * if the error is defined to have an associated exception.  If an
314      * exception is thrown, then the JSREPORT_EXCEPTION flag will be set
315      * on the error report, and exception-aware hosts should ignore it.
316      */
317     if (reportp && reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
318         reportp->flags |= JSREPORT_EXCEPTION;
320 #if JS_HAS_ERROR_EXCEPTIONS
321     /*
322      * Call the error reporter only if an exception wasn't raised.
323      *
324      * If an exception was raised, then we call the debugErrorHook
325      * (if present) to give it a chance to see the error before it
326      * propagates out of scope.  This is needed for compatability
327      * with the old scheme.
328      */
329     if (!js_ErrorToException(cx, message, reportp)) {
330         js_ReportErrorAgain(cx, message, reportp);
331     } else if (cx->runtime->debugErrorHook && cx->errorReporter) {
332         JSDebugErrorHook hook = cx->runtime->debugErrorHook;
333         /* test local in case debugErrorHook changed on another thread */
334         if (hook)
335             hook(cx, message, reportp, cx->runtime->debugErrorHookData);
336     }
337 #else
338     js_ReportErrorAgain(cx, message, reportp);
339 #endif
342 /*
343  * We don't post an exception in this case, since doing so runs into
344  * complications of pre-allocating an exception object which required
345  * running the Exception class initializer early etc.
346  * Instead we just invoke the errorReporter with an "Out Of Memory"
347  * type message, and then hope the process ends swiftly.
348  */
349 void
350 js_ReportOutOfMemory(JSContext *cx, JSErrorCallback callback)
352     JSStackFrame *fp;
353     JSErrorReport report;
354     JSErrorReporter onError = cx->errorReporter;
356     /* Get the message for this error, but we won't expand any arguments. */
357     const JSErrorFormatString *efs = callback(NULL, NULL, JSMSG_OUT_OF_MEMORY);
358     const char *msg = efs ? efs->format : "Out of memory";
360     /* Fill out the report, but don't do anything that requires allocation. */
361     memset(&report, 0, sizeof (struct JSErrorReport));
362     report.flags = JSREPORT_ERROR;
363     report.errorNumber = JSMSG_OUT_OF_MEMORY;
365     /*
366      * Walk stack until we find a frame that is associated with some script
367      * rather than a native frame.
368      */
369     for (fp = cx->fp; fp; fp = fp->down) {
370         if (fp->script && fp->pc) {
371             report.filename = fp->script->filename;
372             report.lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
373             break;
374         }
375     }
377     /*
378      * If debugErrorHook is present then we give it a chance to veto
379      * sending the error on to the regular ErrorReporter.
380      */
381     if (onError) {
382         JSDebugErrorHook hook = cx->runtime->debugErrorHook;
383         if (hook &&
384             !hook(cx, msg, &report, cx->runtime->debugErrorHookData)) {
385             onError = NULL;
386         }
387     }
389     if (onError)
390         onError(cx, msg, &report);
393 JSBool
394 js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap)
396     char *last;
397     JSStackFrame *fp;
398     JSErrorReport report;
399     JSBool warning;
401     if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx))
402         return JS_TRUE;
404     last = JS_vsmprintf(format, ap);
405     if (!last)
406         return JS_FALSE;
408     memset(&report, 0, sizeof (struct JSErrorReport));
409     report.flags = flags;
411     /* Find the top-most active script frame, for best line number blame. */
412     for (fp = cx->fp; fp; fp = fp->down) {
413         if (fp->script && fp->pc) {
414             report.filename = fp->script->filename;
415             report.lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
416             break;
417         }
418     }
420     warning = JSREPORT_IS_WARNING(report.flags);
421     if (warning && JS_HAS_WERROR_OPTION(cx)) {
422         report.flags &= ~JSREPORT_WARNING;
423         warning = JS_FALSE;
424     }
426     ReportError(cx, last, &report);
427     free(last);
428     return warning;
431 /*
432  * The arguments from ap need to be packaged up into an array and stored
433  * into the report struct.
434  *
435  * The format string addressed by the error number may contain operands
436  * identified by the format {N}, where N is a decimal digit. Each of these
437  * is to be replaced by the Nth argument from the va_list. The complete
438  * message is placed into reportp->ucmessage converted to a JSString.
439  *
440  * Returns true if the expansion succeeds (can fail if out of memory).
441  */
442 JSBool
443 js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
444                         void *userRef, const uintN errorNumber,
445                         char **messagep, JSErrorReport *reportp,
446                         JSBool *warningp, JSBool charArgs, va_list ap)
448     const JSErrorFormatString *efs;
449     int i;
450     int argCount;
452     *warningp = JSREPORT_IS_WARNING(reportp->flags);
453     if (*warningp && JS_HAS_WERROR_OPTION(cx)) {
454         reportp->flags &= ~JSREPORT_WARNING;
455         *warningp = JS_FALSE;
456     }
458     *messagep = NULL;
459     if (callback) {
460         efs = callback(userRef, NULL, errorNumber);
461         if (efs) {
462             size_t totalArgsLength = 0;
463             size_t argLengths[10]; /* only {0} thru {9} supported */
464             argCount = efs->argCount;
465             JS_ASSERT(argCount <= 10);
466             if (argCount > 0) {
467                 /*
468                  * Gather the arguments into an array, and accumulate
469                  * their sizes. We allocate 1 more than necessary and
470                  * null it out to act as the caboose when we free the
471                  * pointers later.
472                  */
473                 reportp->messageArgs = (const jschar **)
474                     JS_malloc(cx, sizeof(jschar *) * (argCount + 1));
475                 if (!reportp->messageArgs)
476                     return JS_FALSE;
477                 reportp->messageArgs[argCount] = NULL;
478                 for (i = 0; i < argCount; i++) {
479                     if (charArgs) {
480                         char *charArg = va_arg(ap, char *);
481                         reportp->messageArgs[i]
482                             = js_InflateString(cx, charArg, strlen(charArg));
483                         if (!reportp->messageArgs[i])
484                             goto error;
485                     }
486                     else
487                         reportp->messageArgs[i] = va_arg(ap, jschar *);
488                     argLengths[i] = js_strlen(reportp->messageArgs[i]);
489                     totalArgsLength += argLengths[i];
490                 }
491                 /* NULL-terminate for easy copying. */
492                 reportp->messageArgs[i] = NULL;
493             }
494             /*
495              * Parse the error format, substituting the argument X
496              * for {X} in the format.
497              */
498             if (argCount > 0) {
499                 if (efs->format) {
500                     const char *fmt;
501                     const jschar *arg;
502                     jschar *out;
503                     int expandedArgs = 0;
504                     size_t expandedLength
505                         = strlen(efs->format)
506                             - (3 * argCount) /* exclude the {n} */
507                             + totalArgsLength;
508                     /*
509                      * Note - the above calculation assumes that each argument
510                      * is used once and only once in the expansion !!!
511                      */
512                     reportp->ucmessage = out = (jschar *)
513                         JS_malloc(cx, (expandedLength + 1) * sizeof(jschar));
514                     if (!out)
515                         goto error;
516                     fmt = efs->format;
517                     while (*fmt) {
518                         if (*fmt == '{') {
519                             if (isdigit(fmt[1])) {
520                                 int d = JS7_UNDEC(fmt[1]);
521                                 JS_ASSERT(expandedArgs < argCount);
522                                 arg = reportp->messageArgs[d];
523                                 js_strncpy(out, arg, argLengths[d]);
524                                 out += argLengths[d];
525                                 fmt += 3;
526                                 expandedArgs++;
527                                 continue;
528                             }
529                         }
530                         /*
531                          * is this kosher?
532                          */
533                         *out++ = (unsigned char)(*fmt++);
534                     }
535                     JS_ASSERT(expandedArgs == argCount);
536                     *out = 0;
537                     *messagep =
538                         js_DeflateString(cx, reportp->ucmessage,
539                                          (size_t)(out - reportp->ucmessage));
540                     if (!*messagep)
541                         goto error;
542                 }
543             } else {
544                 /*
545                  * Zero arguments: the format string (if it exists) is the
546                  * entire message.
547                  */
548                 if (efs->format) {
549                     *messagep = JS_strdup(cx, efs->format);
550                     if (!*messagep)
551                         goto error;
552                     reportp->ucmessage
553                         = js_InflateString(cx, *messagep, strlen(*messagep));
554                     if (!reportp->ucmessage)
555                         goto error;
556                 }
557             }
558         }
559     }
560     if (*messagep == NULL) {
561         /* where's the right place for this ??? */
562         const char *defaultErrorMessage
563             = "No error message available for error number %d";
564         size_t nbytes = strlen(defaultErrorMessage) + 16;
565         *messagep = (char *)JS_malloc(cx, nbytes);
566         if (!*messagep)
567             goto error;
568         JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber);
569     }
570     return JS_TRUE;
572 error:
573     if (reportp->messageArgs) {
574         i = 0;
575         while (reportp->messageArgs[i])
576             JS_free(cx, (void *)reportp->messageArgs[i++]);
577         JS_free(cx, (void *)reportp->messageArgs);
578         reportp->messageArgs = NULL;
579     }
580     if (reportp->ucmessage) {
581         JS_free(cx, (void *)reportp->ucmessage);
582         reportp->ucmessage = NULL;
583     }
584     if (*messagep) {
585         JS_free(cx, (void *)*messagep);
586         *messagep = NULL;
587     }
588     return JS_FALSE;
591 JSBool
592 js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
593                        void *userRef, const uintN errorNumber,
594                        JSBool charArgs, va_list ap)
596     JSStackFrame *fp;
597     JSErrorReport report;
598     char *message;
599     JSBool warning;
601     if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx))
602         return JS_TRUE;
604     memset(&report, 0, sizeof (struct JSErrorReport));
605     report.flags = flags;
606     report.errorNumber = errorNumber;
608     /*
609      * If we can't find out where the error was based on the current frame,
610      * see if the next frame has a script/pc combo we can use.
611      */
612     for (fp = cx->fp; fp; fp = fp->down) {
613         if (fp->script && fp->pc) {
614             report.filename = fp->script->filename;
615             report.lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
616             break;
617         }
618     }
620     if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
621                                  &message, &report, &warning, charArgs, ap)) {
622         return JS_FALSE;
623     }
625     ReportError(cx, message, &report);
627     if (message)
628         JS_free(cx, message);
629     if (report.messageArgs) {
630         int i = 0;
631         while (report.messageArgs[i])
632             JS_free(cx, (void *)report.messageArgs[i++]);
633         JS_free(cx, (void *)report.messageArgs);
634     }
635     if (report.ucmessage)
636         JS_free(cx, (void *)report.ucmessage);
638     return warning;
641 JS_FRIEND_API(void)
642 js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *reportp)
644     JSErrorReporter onError;
646     if (!message)
647         return;
649     if (cx->lastMessage)
650         free(cx->lastMessage);
651     cx->lastMessage = JS_strdup(cx, message);
652     if (!cx->lastMessage)
653         return;
654     onError = cx->errorReporter;
656     /*
657      * If debugErrorHook is present then we give it a chance to veto
658      * sending the error on to the regular ErrorReporter.
659      */
660     if (onError) {
661         JSDebugErrorHook hook = cx->runtime->debugErrorHook;
662         if (hook &&
663             !hook(cx, cx->lastMessage, reportp,
664                   cx->runtime->debugErrorHookData)) {
665             onError = NULL;
666         }
667     }
668     if (onError)
669         onError(cx, cx->lastMessage, reportp);
672 void
673 js_ReportIsNotDefined(JSContext *cx, const char *name)
675     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_DEFINED, name);
678 #if defined DEBUG && defined XP_UNIX
679 /* For gdb usage. */
680 void js_traceon(JSContext *cx)  { cx->tracefp = stderr; }
681 void js_traceoff(JSContext *cx) { cx->tracefp = NULL; }
682 #endif
684 JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
685 #if JS_HAS_DFLT_MSG_STRINGS
686 #define MSG_DEF(name, number, count, exception, format) \
687     { format, count } ,
688 #else
689 #define MSG_DEF(name, number, count, exception, format) \
690     { NULL, count } ,
691 #endif
692 #include "js.msg"
693 #undef MSG_DEF
694 };
696 const JSErrorFormatString *
697 js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber)
699     if ((errorNumber > 0) && (errorNumber < JSErr_Limit))
700         return &js_ErrorFormatString[errorNumber];
701     return NULL;