js/jsd/jsd_text.cpp

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

mercurial