1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : * JavaScript Debugging support - Source Text functions
40 : */
41 :
42 : #include <ctype.h>
43 : #include "jsd.h"
44 :
45 : #ifdef DEBUG
46 0 : void JSD_ASSERT_VALID_SOURCE_TEXT(JSDSourceText* jsdsrc)
47 : {
48 0 : JS_ASSERT(jsdsrc);
49 0 : JS_ASSERT(jsdsrc->url);
50 0 : }
51 : #endif
52 :
53 : /***************************************************************************/
54 : /* XXX add notification */
55 :
56 : static void
57 0 : _clearText(JSDContext* jsdc, JSDSourceText* jsdsrc)
58 : {
59 0 : if( jsdsrc->text )
60 0 : free(jsdsrc->text);
61 0 : jsdsrc->text = NULL;
62 0 : jsdsrc->textLength = 0;
63 0 : jsdsrc->textSpace = 0;
64 0 : jsdsrc->status = JSD_SOURCE_CLEARED;
65 0 : jsdsrc->dirty = JS_TRUE;
66 0 : jsdsrc->alterCount = jsdc->sourceAlterCount++ ;
67 0 : jsdsrc->doingEval = JS_FALSE;
68 0 : }
69 :
70 : static JSBool
71 0 : _appendText(JSDContext* jsdc, JSDSourceText* jsdsrc,
72 : const char* text, size_t length)
73 : {
74 : #define MEMBUF_GROW 1000
75 :
76 0 : unsigned neededSize = jsdsrc->textLength + length;
77 :
78 0 : if( neededSize > jsdsrc->textSpace )
79 : {
80 : char* newBuf;
81 : unsigned iNewSize;
82 :
83 : /* if this is the first alloc, the req might be all that's needed*/
84 0 : if( ! jsdsrc->textSpace )
85 0 : iNewSize = length;
86 : else
87 0 : iNewSize = (neededSize * 5 / 4) + MEMBUF_GROW;
88 :
89 0 : newBuf = (char*) realloc(jsdsrc->text, iNewSize);
90 0 : if( ! newBuf )
91 : {
92 : /* try again with the minimal size really asked for */
93 0 : iNewSize = neededSize;
94 0 : newBuf = (char*) realloc(jsdsrc->text, iNewSize);
95 0 : if( ! newBuf )
96 : {
97 : /* out of memory */
98 0 : _clearText( jsdc, jsdsrc );
99 0 : jsdsrc->status = JSD_SOURCE_FAILED;
100 0 : return JS_FALSE;
101 : }
102 : }
103 :
104 0 : jsdsrc->text = newBuf;
105 0 : jsdsrc->textSpace = iNewSize;
106 : }
107 :
108 0 : memcpy(jsdsrc->text + jsdsrc->textLength, text, length);
109 0 : jsdsrc->textLength += length;
110 0 : return JS_TRUE;
111 : }
112 :
113 : static JSDSourceText*
114 0 : _newSource(JSDContext* jsdc, char* url)
115 : {
116 0 : JSDSourceText* jsdsrc = (JSDSourceText*)calloc(1,sizeof(JSDSourceText));
117 0 : if( ! jsdsrc )
118 0 : return NULL;
119 :
120 0 : jsdsrc->url = url;
121 0 : jsdsrc->status = JSD_SOURCE_INITED;
122 0 : jsdsrc->dirty = JS_TRUE;
123 0 : jsdsrc->alterCount = jsdc->sourceAlterCount++ ;
124 :
125 0 : return jsdsrc;
126 : }
127 :
128 : static void
129 0 : _destroySource(JSDContext* jsdc, JSDSourceText* jsdsrc)
130 : {
131 0 : JS_ASSERT(NULL == jsdsrc->text); /* must _clearText() first */
132 0 : free(jsdsrc->url);
133 0 : free(jsdsrc);
134 0 : }
135 :
136 : static void
137 0 : _removeSource(JSDContext* jsdc, JSDSourceText* jsdsrc)
138 : {
139 0 : JS_REMOVE_LINK(&jsdsrc->links);
140 0 : _clearText(jsdc, jsdsrc);
141 0 : _destroySource(jsdc, jsdsrc);
142 0 : }
143 :
144 : static JSDSourceText*
145 0 : _addSource(JSDContext* jsdc, char* url)
146 : {
147 0 : JSDSourceText* jsdsrc = _newSource(jsdc, url);
148 0 : if( ! jsdsrc )
149 0 : return NULL;
150 0 : JS_INSERT_LINK(&jsdsrc->links, &jsdc->sources);
151 0 : return jsdsrc;
152 : }
153 :
154 : static void
155 0 : _moveSourceToFront(JSDContext* jsdc, JSDSourceText* jsdsrc)
156 : {
157 0 : JS_REMOVE_LINK(&jsdsrc->links);
158 0 : JS_INSERT_LINK(&jsdsrc->links, &jsdc->sources);
159 0 : }
160 :
161 : static void
162 0 : _moveSourceToRemovedList(JSDContext* jsdc, JSDSourceText* jsdsrc)
163 : {
164 0 : _clearText(jsdc, jsdsrc);
165 0 : JS_REMOVE_LINK(&jsdsrc->links);
166 0 : JS_INSERT_LINK(&jsdsrc->links, &jsdc->removedSources);
167 0 : }
168 :
169 : static void
170 0 : _removeSourceFromRemovedList( JSDContext* jsdc, JSDSourceText* jsdsrc )
171 : {
172 0 : JS_REMOVE_LINK(&jsdsrc->links);
173 0 : _destroySource( jsdc, jsdsrc );
174 0 : }
175 :
176 : static JSBool
177 0 : _isSourceInSourceList(JSDContext* jsdc, JSDSourceText* jsdsrcToFind)
178 : {
179 : JSDSourceText *jsdsrc;
180 :
181 0 : for( jsdsrc = (JSDSourceText*)jsdc->sources.next;
182 0 : jsdsrc != (JSDSourceText*)&jsdc->sources;
183 0 : jsdsrc = (JSDSourceText*)jsdsrc->links.next )
184 : {
185 0 : if( jsdsrc == jsdsrcToFind )
186 0 : return JS_TRUE;
187 : }
188 0 : return JS_FALSE;
189 : }
190 :
191 : /* compare strings in a case insensitive manner with a length limit
192 : */
193 :
194 : static int
195 206573 : strncasecomp (const char* one, const char * two, int n)
196 : {
197 : const char *pA;
198 : const char *pB;
199 :
200 293368 : for(pA=one, pB=two;; pA++, pB++)
201 : {
202 : int tmp;
203 293368 : if (pA == one+n)
204 17359 : return 0;
205 276009 : if (!(*pA && *pB))
206 0 : return *pA - *pB;
207 276009 : tmp = tolower(*pA) - tolower(*pB);
208 276009 : if (tmp)
209 189214 : return tmp;
210 86795 : }
211 : }
212 :
213 : static char file_url_prefix[] = "file:";
214 : #define FILE_URL_PREFIX_LEN (sizeof file_url_prefix - 1)
215 :
216 : char*
217 206573 : jsd_BuildNormalizedURL( const char* url_string )
218 : {
219 : char *new_url_string;
220 :
221 206573 : if( ! url_string )
222 0 : return NULL;
223 :
224 223932 : if (!strncasecomp(url_string, file_url_prefix, FILE_URL_PREFIX_LEN) &&
225 34718 : url_string[FILE_URL_PREFIX_LEN + 0] == '/' &&
226 17359 : url_string[FILE_URL_PREFIX_LEN + 1] == '/') {
227 17359 : new_url_string = JS_smprintf("%s%s",
228 : file_url_prefix,
229 : url_string + FILE_URL_PREFIX_LEN + 2);
230 : } else {
231 189214 : new_url_string = strdup(url_string);
232 : }
233 206573 : return new_url_string;
234 : }
235 :
236 : /***************************************************************************/
237 :
238 : void
239 280 : jsd_DestroyAllSources( JSDContext* jsdc )
240 : {
241 : JSDSourceText *jsdsrc;
242 : JSDSourceText *next;
243 :
244 560 : for( jsdsrc = (JSDSourceText*)jsdc->sources.next;
245 280 : jsdsrc != (JSDSourceText*)&jsdc->sources;
246 0 : jsdsrc = next )
247 : {
248 0 : next = (JSDSourceText*)jsdsrc->links.next;
249 0 : _removeSource( jsdc, jsdsrc );
250 : }
251 :
252 560 : for( jsdsrc = (JSDSourceText*)jsdc->removedSources.next;
253 280 : jsdsrc != (JSDSourceText*)&jsdc->removedSources;
254 0 : jsdsrc = next )
255 : {
256 0 : next = (JSDSourceText*)jsdsrc->links.next;
257 0 : _removeSourceFromRemovedList( jsdc, jsdsrc );
258 : }
259 :
260 280 : }
261 :
262 : JSDSourceText*
263 0 : jsd_IterateSources(JSDContext* jsdc, JSDSourceText **iterp)
264 : {
265 0 : JSDSourceText *jsdsrc = *iterp;
266 :
267 0 : if( !jsdsrc )
268 0 : jsdsrc = (JSDSourceText *)jsdc->sources.next;
269 0 : if( jsdsrc == (JSDSourceText *)&jsdc->sources )
270 0 : return NULL;
271 0 : *iterp = (JSDSourceText *)jsdsrc->links.next;
272 0 : return jsdsrc;
273 : }
274 :
275 : JSDSourceText*
276 0 : jsd_FindSourceForURL(JSDContext* jsdc, const char* url)
277 : {
278 : JSDSourceText *jsdsrc;
279 :
280 0 : for( jsdsrc = (JSDSourceText *)jsdc->sources.next;
281 0 : jsdsrc != (JSDSourceText *)&jsdc->sources;
282 0 : jsdsrc = (JSDSourceText *)jsdsrc->links.next )
283 : {
284 0 : if( 0 == strcmp(jsdsrc->url, url) )
285 0 : return jsdsrc;
286 : }
287 0 : return NULL;
288 : }
289 :
290 : const char*
291 0 : jsd_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc)
292 : {
293 0 : return jsdsrc->url;
294 : }
295 :
296 : JSBool
297 0 : jsd_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc,
298 : const char** ppBuf, int* pLen )
299 : {
300 0 : *ppBuf = jsdsrc->text;
301 0 : *pLen = jsdsrc->textLength;
302 0 : return JS_TRUE;
303 : }
304 :
305 : void
306 0 : jsd_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc)
307 : {
308 0 : if( JSD_SOURCE_INITED != jsdsrc->status &&
309 0 : JSD_SOURCE_PARTIAL != jsdsrc->status )
310 : {
311 0 : _clearText(jsdc, jsdsrc);
312 : }
313 0 : }
314 :
315 : JSDSourceStatus
316 0 : jsd_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc)
317 : {
318 0 : return jsdsrc->status;
319 : }
320 :
321 : JSBool
322 0 : jsd_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc)
323 : {
324 0 : return jsdsrc->dirty;
325 : }
326 :
327 : void
328 0 : jsd_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, JSBool dirty)
329 : {
330 0 : jsdsrc->dirty = dirty;
331 0 : }
332 :
333 : unsigned
334 0 : jsd_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc)
335 : {
336 0 : return jsdsrc->alterCount;
337 : }
338 :
339 : unsigned
340 0 : jsd_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc)
341 : {
342 0 : return jsdsrc->alterCount = jsdc->sourceAlterCount++;
343 : }
344 :
345 : /***************************************************************************/
346 :
347 : #if defined(DEBUG) && 0
348 : void DEBUG_ITERATE_SOURCES( JSDContext* jsdc )
349 : {
350 : JSDSourceText* iterp = NULL;
351 : JSDSourceText* jsdsrc = NULL;
352 : int dummy;
353 :
354 : while( NULL != (jsdsrc = jsd_IterateSources(jsdc, &iterp)) )
355 : {
356 : const char* url;
357 : const char* text;
358 : int len;
359 : JSBool dirty;
360 : JSDStreamStatus status;
361 : JSBool gotSrc;
362 :
363 : url = JSD_GetSourceURL(jsdc, jsdsrc);
364 : dirty = JSD_IsSourceDirty(jsdc, jsdsrc);
365 : status = JSD_GetSourceStatus(jsdc, jsdsrc);
366 : gotSrc = JSD_GetSourceText(jsdc, jsdsrc, &text, &len );
367 :
368 : dummy = 0; /* gives us a line to set breakpoint... */
369 : }
370 : }
371 : #else
372 : #define DEBUG_ITERATE_SOURCES(x) ((void)x)
373 : #endif
374 :
375 : /***************************************************************************/
376 :
377 : JSDSourceText*
378 0 : jsd_NewSourceText(JSDContext* jsdc, const char* url)
379 : {
380 : JSDSourceText* jsdsrc;
381 : char* new_url_string;
382 :
383 0 : JSD_LOCK_SOURCE_TEXT(jsdc);
384 :
385 : #ifdef LIVEWIRE
386 : new_url_string = url; /* we take ownership of alloc'd string */
387 : #else
388 0 : new_url_string = jsd_BuildNormalizedURL(url);
389 : #endif
390 0 : if( ! new_url_string )
391 0 : return NULL;
392 :
393 0 : jsdsrc = jsd_FindSourceForURL(jsdc, new_url_string);
394 :
395 0 : if( jsdsrc )
396 : {
397 0 : if( jsdsrc->doingEval )
398 : {
399 0 : free(new_url_string);
400 0 : JSD_UNLOCK_SOURCE_TEXT(jsdc);
401 0 : return NULL;
402 : }
403 : else
404 0 : _moveSourceToRemovedList(jsdc, jsdsrc);
405 : }
406 :
407 0 : jsdsrc = _addSource( jsdc, new_url_string );
408 :
409 0 : JSD_UNLOCK_SOURCE_TEXT(jsdc);
410 :
411 0 : return jsdsrc;
412 : }
413 :
414 : JSDSourceText*
415 0 : jsd_AppendSourceText(JSDContext* jsdc,
416 : JSDSourceText* jsdsrc,
417 : const char* text, /* *not* zero terminated */
418 : size_t length,
419 : JSDSourceStatus status)
420 : {
421 0 : JSD_LOCK_SOURCE_TEXT(jsdc);
422 :
423 0 : if( jsdsrc->doingEval )
424 : {
425 0 : JSD_UNLOCK_SOURCE_TEXT(jsdc);
426 0 : return NULL;
427 : }
428 :
429 0 : if( ! _isSourceInSourceList( jsdc, jsdsrc ) )
430 : {
431 0 : _removeSourceFromRemovedList( jsdc, jsdsrc );
432 0 : JSD_UNLOCK_SOURCE_TEXT(jsdc);
433 0 : return NULL;
434 : }
435 :
436 0 : if( text && length && ! _appendText( jsdc, jsdsrc, text, length ) )
437 : {
438 0 : jsdsrc->dirty = JS_TRUE;
439 0 : jsdsrc->alterCount = jsdc->sourceAlterCount++ ;
440 0 : jsdsrc->status = JSD_SOURCE_FAILED;
441 0 : _moveSourceToRemovedList(jsdc, jsdsrc);
442 0 : JSD_UNLOCK_SOURCE_TEXT(jsdc);
443 0 : return NULL;
444 : }
445 :
446 0 : jsdsrc->dirty = JS_TRUE;
447 0 : jsdsrc->alterCount = jsdc->sourceAlterCount++ ;
448 0 : jsdsrc->status = status;
449 : DEBUG_ITERATE_SOURCES(jsdc);
450 0 : JSD_UNLOCK_SOURCE_TEXT(jsdc);
451 0 : return jsdsrc;
452 : }
453 :
454 : JSDSourceText*
455 0 : jsd_AppendUCSourceText(JSDContext* jsdc,
456 : JSDSourceText* jsdsrc,
457 : const jschar* text, /* *not* zero terminated */
458 : size_t length,
459 : JSDSourceStatus status)
460 : {
461 : #define UNICODE_TRUNCATE_BUF_SIZE 1024
462 : static char* buf = NULL;
463 0 : int remaining = length;
464 :
465 0 : if(!text || !length)
466 0 : return jsd_AppendSourceText(jsdc, jsdsrc, NULL, 0, status);
467 :
468 0 : JSD_LOCK_SOURCE_TEXT(jsdc);
469 0 : if(!buf)
470 : {
471 0 : buf = malloc(UNICODE_TRUNCATE_BUF_SIZE);
472 0 : if(!buf)
473 : {
474 0 : JSD_UNLOCK_SOURCE_TEXT(jsdc);
475 0 : return NULL;
476 : }
477 : }
478 0 : while(remaining && jsdsrc) {
479 0 : int bytes = JS_MIN(remaining, UNICODE_TRUNCATE_BUF_SIZE);
480 : int i;
481 0 : for(i = 0; i < bytes; i++)
482 0 : buf[i] = (const char) *(text++);
483 0 : jsdsrc = jsd_AppendSourceText(jsdc,jsdsrc,
484 : buf, bytes,
485 : JSD_SOURCE_PARTIAL);
486 0 : remaining -= bytes;
487 : }
488 0 : if(jsdsrc && status != JSD_SOURCE_PARTIAL)
489 0 : jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc, NULL, 0, status);
490 :
491 0 : JSD_UNLOCK_SOURCE_TEXT(jsdc);
492 0 : return jsdsrc;
493 : }
494 :
495 : /* convienence function for adding complete source of url in one call */
496 : JSBool
497 0 : jsd_AddFullSourceText(JSDContext* jsdc,
498 : const char* text, /* *not* zero terminated */
499 : size_t length,
500 : const char* url)
501 : {
502 : JSDSourceText* jsdsrc;
503 :
504 0 : JSD_LOCK_SOURCE_TEXT(jsdc);
505 :
506 0 : jsdsrc = jsd_NewSourceText(jsdc, url);
507 0 : if( jsdsrc )
508 0 : jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc,
509 : text, length, JSD_SOURCE_PARTIAL );
510 0 : if( jsdsrc )
511 0 : jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc,
512 : NULL, 0, JSD_SOURCE_COMPLETED );
513 :
514 0 : JSD_UNLOCK_SOURCE_TEXT(jsdc);
515 :
516 0 : return jsdsrc ? JS_TRUE : JS_FALSE;
517 : }
518 :
519 : /***************************************************************************/
520 :
521 : void
522 0 : jsd_StartingEvalUsingFilename(JSDContext* jsdc, const char* url)
523 : {
524 : JSDSourceText* jsdsrc;
525 :
526 : /* NOTE: We leave it locked! */
527 0 : JSD_LOCK_SOURCE_TEXT(jsdc);
528 :
529 0 : jsdsrc = jsd_FindSourceForURL(jsdc, url);
530 0 : if(jsdsrc)
531 : {
532 : #if 0
533 : #ifndef JSD_LOWLEVEL_SOURCE
534 : JS_ASSERT(! jsdsrc->doingEval);
535 : #endif
536 : #endif
537 0 : jsdsrc->doingEval = JS_TRUE;
538 : }
539 0 : }
540 :
541 : void
542 0 : jsd_FinishedEvalUsingFilename(JSDContext* jsdc, const char* url)
543 : {
544 : JSDSourceText* jsdsrc;
545 :
546 : /* NOTE: We ASSUME it is locked! */
547 :
548 0 : jsdsrc = jsd_FindSourceForURL(jsdc, url);
549 0 : if(jsdsrc)
550 : {
551 : #if 0
552 : #ifndef JSD_LOWLEVEL_SOURCE
553 : /*
554 : * when using this low level source addition, this jsdsrc might
555 : * not have existed before the eval, but does exist now (without
556 : * this flag set!)
557 : */
558 : JS_ASSERT(jsdsrc->doingEval);
559 : #endif
560 : #endif
561 0 : jsdsrc->doingEval = JS_FALSE;
562 : }
563 :
564 0 : JSD_UNLOCK_SOURCE_TEXT(jsdc);
565 0 : }
|