1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/jsd/jsd_text.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,525 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * JavaScript Debugging support - Source Text functions 1.12 + */ 1.13 + 1.14 +#include <ctype.h> 1.15 +#include "jsd.h" 1.16 +#include "jsprf.h" 1.17 + 1.18 +#ifdef DEBUG 1.19 +void JSD_ASSERT_VALID_SOURCE_TEXT(JSDSourceText* jsdsrc) 1.20 +{ 1.21 + MOZ_ASSERT(jsdsrc); 1.22 + MOZ_ASSERT(jsdsrc->url); 1.23 +} 1.24 +#endif 1.25 + 1.26 +/***************************************************************************/ 1.27 +/* XXX add notification */ 1.28 + 1.29 +static void 1.30 +_clearText(JSDContext* jsdc, JSDSourceText* jsdsrc) 1.31 +{ 1.32 + if( jsdsrc->text ) 1.33 + free(jsdsrc->text); 1.34 + jsdsrc->text = nullptr; 1.35 + jsdsrc->textLength = 0; 1.36 + jsdsrc->textSpace = 0; 1.37 + jsdsrc->status = JSD_SOURCE_CLEARED; 1.38 + jsdsrc->dirty = true; 1.39 + jsdsrc->alterCount = jsdc->sourceAlterCount++ ; 1.40 + jsdsrc->doingEval = false; 1.41 +} 1.42 + 1.43 +static bool 1.44 +_appendText(JSDContext* jsdc, JSDSourceText* jsdsrc, 1.45 + const char* text, size_t length) 1.46 +{ 1.47 +#define MEMBUF_GROW 1000 1.48 + 1.49 + unsigned neededSize = jsdsrc->textLength + length; 1.50 + 1.51 + if( neededSize > jsdsrc->textSpace ) 1.52 + { 1.53 + char* newBuf; 1.54 + unsigned iNewSize; 1.55 + 1.56 + /* if this is the first alloc, the req might be all that's needed*/ 1.57 + if( ! jsdsrc->textSpace ) 1.58 + iNewSize = length; 1.59 + else 1.60 + iNewSize = (neededSize * 5 / 4) + MEMBUF_GROW; 1.61 + 1.62 + newBuf = (char*) realloc(jsdsrc->text, iNewSize); 1.63 + if( ! newBuf ) 1.64 + { 1.65 + /* try again with the minimal size really asked for */ 1.66 + iNewSize = neededSize; 1.67 + newBuf = (char*) realloc(jsdsrc->text, iNewSize); 1.68 + if( ! newBuf ) 1.69 + { 1.70 + /* out of memory */ 1.71 + _clearText( jsdc, jsdsrc ); 1.72 + jsdsrc->status = JSD_SOURCE_FAILED; 1.73 + return false; 1.74 + } 1.75 + } 1.76 + 1.77 + jsdsrc->text = newBuf; 1.78 + jsdsrc->textSpace = iNewSize; 1.79 + } 1.80 + 1.81 + memcpy(jsdsrc->text + jsdsrc->textLength, text, length); 1.82 + jsdsrc->textLength += length; 1.83 + return true; 1.84 +} 1.85 + 1.86 +static JSDSourceText* 1.87 +_newSource(JSDContext* jsdc, char* url) 1.88 +{ 1.89 + JSDSourceText* jsdsrc = (JSDSourceText*)calloc(1,sizeof(JSDSourceText)); 1.90 + if( ! jsdsrc ) 1.91 + return nullptr; 1.92 + 1.93 + jsdsrc->url = url; 1.94 + jsdsrc->status = JSD_SOURCE_INITED; 1.95 + jsdsrc->dirty = true; 1.96 + jsdsrc->alterCount = jsdc->sourceAlterCount++ ; 1.97 + 1.98 + return jsdsrc; 1.99 +} 1.100 + 1.101 +static void 1.102 +_destroySource(JSDContext* jsdc, JSDSourceText* jsdsrc) 1.103 +{ 1.104 + MOZ_ASSERT(nullptr == jsdsrc->text); /* must _clearText() first */ 1.105 + free(jsdsrc->url); 1.106 + free(jsdsrc); 1.107 +} 1.108 + 1.109 +static void 1.110 +_removeSource(JSDContext* jsdc, JSDSourceText* jsdsrc) 1.111 +{ 1.112 + JS_REMOVE_LINK(&jsdsrc->links); 1.113 + _clearText(jsdc, jsdsrc); 1.114 + _destroySource(jsdc, jsdsrc); 1.115 +} 1.116 + 1.117 +static JSDSourceText* 1.118 +_addSource(JSDContext* jsdc, char* url) 1.119 +{ 1.120 + JSDSourceText* jsdsrc = _newSource(jsdc, url); 1.121 + if( ! jsdsrc ) 1.122 + return nullptr; 1.123 + JS_INSERT_LINK(&jsdsrc->links, &jsdc->sources); 1.124 + return jsdsrc; 1.125 +} 1.126 + 1.127 +static void 1.128 +_moveSourceToRemovedList(JSDContext* jsdc, JSDSourceText* jsdsrc) 1.129 +{ 1.130 + _clearText(jsdc, jsdsrc); 1.131 + JS_REMOVE_LINK(&jsdsrc->links); 1.132 + JS_INSERT_LINK(&jsdsrc->links, &jsdc->removedSources); 1.133 +} 1.134 + 1.135 +static void 1.136 +_removeSourceFromRemovedList( JSDContext* jsdc, JSDSourceText* jsdsrc ) 1.137 +{ 1.138 + JS_REMOVE_LINK(&jsdsrc->links); 1.139 + _destroySource( jsdc, jsdsrc ); 1.140 +} 1.141 + 1.142 +static bool 1.143 +_isSourceInSourceList(JSDContext* jsdc, JSDSourceText* jsdsrcToFind) 1.144 +{ 1.145 + JSDSourceText *jsdsrc; 1.146 + 1.147 + for( jsdsrc = (JSDSourceText*)jsdc->sources.next; 1.148 + jsdsrc != (JSDSourceText*)&jsdc->sources; 1.149 + jsdsrc = (JSDSourceText*)jsdsrc->links.next ) 1.150 + { 1.151 + if( jsdsrc == jsdsrcToFind ) 1.152 + return true; 1.153 + } 1.154 + return false; 1.155 +} 1.156 + 1.157 +/* compare strings in a case insensitive manner with a length limit 1.158 +*/ 1.159 + 1.160 +static int 1.161 +strncasecomp (const char* one, const char * two, int n) 1.162 +{ 1.163 + const char *pA; 1.164 + const char *pB; 1.165 + 1.166 + for(pA=one, pB=two;; pA++, pB++) 1.167 + { 1.168 + int tmp; 1.169 + if (pA == one+n) 1.170 + return 0; 1.171 + if (!(*pA && *pB)) 1.172 + return *pA - *pB; 1.173 + tmp = tolower(*pA) - tolower(*pB); 1.174 + if (tmp) 1.175 + return tmp; 1.176 + } 1.177 +} 1.178 + 1.179 +static const char file_url_prefix[] = "file:"; 1.180 +#define FILE_URL_PREFIX_LEN (sizeof file_url_prefix - 1) 1.181 + 1.182 +char* 1.183 +jsd_BuildNormalizedURL( const char* url_string ) 1.184 +{ 1.185 + char *new_url_string; 1.186 + 1.187 + if( ! url_string ) 1.188 + return nullptr; 1.189 + 1.190 + if (!strncasecomp(url_string, file_url_prefix, FILE_URL_PREFIX_LEN) && 1.191 + url_string[FILE_URL_PREFIX_LEN + 0] == '/' && 1.192 + url_string[FILE_URL_PREFIX_LEN + 1] == '/') { 1.193 + new_url_string = JS_smprintf("%s%s", 1.194 + file_url_prefix, 1.195 + url_string + FILE_URL_PREFIX_LEN + 2); 1.196 + } else { 1.197 + new_url_string = strdup(url_string); 1.198 + } 1.199 + return new_url_string; 1.200 +} 1.201 + 1.202 +/***************************************************************************/ 1.203 + 1.204 +void 1.205 +jsd_DestroyAllSources( JSDContext* jsdc ) 1.206 +{ 1.207 + JSDSourceText *jsdsrc; 1.208 + JSDSourceText *next; 1.209 + 1.210 + for( jsdsrc = (JSDSourceText*)jsdc->sources.next; 1.211 + jsdsrc != (JSDSourceText*)&jsdc->sources; 1.212 + jsdsrc = next ) 1.213 + { 1.214 + next = (JSDSourceText*)jsdsrc->links.next; 1.215 + _removeSource( jsdc, jsdsrc ); 1.216 + } 1.217 + 1.218 + for( jsdsrc = (JSDSourceText*)jsdc->removedSources.next; 1.219 + jsdsrc != (JSDSourceText*)&jsdc->removedSources; 1.220 + jsdsrc = next ) 1.221 + { 1.222 + next = (JSDSourceText*)jsdsrc->links.next; 1.223 + _removeSourceFromRemovedList( jsdc, jsdsrc ); 1.224 + } 1.225 + 1.226 +} 1.227 + 1.228 +JSDSourceText* 1.229 +jsd_IterateSources(JSDContext* jsdc, JSDSourceText **iterp) 1.230 +{ 1.231 + JSDSourceText *jsdsrc = *iterp; 1.232 + 1.233 + if( !jsdsrc ) 1.234 + jsdsrc = (JSDSourceText *)jsdc->sources.next; 1.235 + if( jsdsrc == (JSDSourceText *)&jsdc->sources ) 1.236 + return nullptr; 1.237 + *iterp = (JSDSourceText *)jsdsrc->links.next; 1.238 + return jsdsrc; 1.239 +} 1.240 + 1.241 +JSDSourceText* 1.242 +jsd_FindSourceForURL(JSDContext* jsdc, const char* url) 1.243 +{ 1.244 + JSDSourceText *jsdsrc; 1.245 + 1.246 + for( jsdsrc = (JSDSourceText *)jsdc->sources.next; 1.247 + jsdsrc != (JSDSourceText *)&jsdc->sources; 1.248 + jsdsrc = (JSDSourceText *)jsdsrc->links.next ) 1.249 + { 1.250 + if( 0 == strcmp(jsdsrc->url, url) ) 1.251 + return jsdsrc; 1.252 + } 1.253 + return nullptr; 1.254 +} 1.255 + 1.256 +const char* 1.257 +jsd_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc) 1.258 +{ 1.259 + return jsdsrc->url; 1.260 +} 1.261 + 1.262 +bool 1.263 +jsd_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc, 1.264 + const char** ppBuf, int* pLen ) 1.265 +{ 1.266 + *ppBuf = jsdsrc->text; 1.267 + *pLen = jsdsrc->textLength; 1.268 + return true; 1.269 +} 1.270 + 1.271 +void 1.272 +jsd_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc) 1.273 +{ 1.274 + if( JSD_SOURCE_INITED != jsdsrc->status && 1.275 + JSD_SOURCE_PARTIAL != jsdsrc->status ) 1.276 + { 1.277 + _clearText(jsdc, jsdsrc); 1.278 + } 1.279 +} 1.280 + 1.281 +JSDSourceStatus 1.282 +jsd_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc) 1.283 +{ 1.284 + return jsdsrc->status; 1.285 +} 1.286 + 1.287 +bool 1.288 +jsd_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc) 1.289 +{ 1.290 + return jsdsrc->dirty; 1.291 +} 1.292 + 1.293 +void 1.294 +jsd_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, bool dirty) 1.295 +{ 1.296 + jsdsrc->dirty = dirty; 1.297 +} 1.298 + 1.299 +unsigned 1.300 +jsd_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc) 1.301 +{ 1.302 + return jsdsrc->alterCount; 1.303 +} 1.304 + 1.305 +unsigned 1.306 +jsd_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc) 1.307 +{ 1.308 + return jsdsrc->alterCount = jsdc->sourceAlterCount++; 1.309 +} 1.310 + 1.311 +/***************************************************************************/ 1.312 + 1.313 +#if defined(DEBUG) && 0 1.314 +void DEBUG_ITERATE_SOURCES( JSDContext* jsdc ) 1.315 +{ 1.316 + JSDSourceText* iterp = nullptr; 1.317 + JSDSourceText* jsdsrc = nullptr; 1.318 + int dummy; 1.319 + 1.320 + while( nullptr != (jsdsrc = jsd_IterateSources(jsdc, &iterp)) ) 1.321 + { 1.322 + const char* url; 1.323 + const char* text; 1.324 + int len; 1.325 + bool dirty; 1.326 + JSDStreamStatus status; 1.327 + bool gotSrc; 1.328 + 1.329 + url = JSD_GetSourceURL(jsdc, jsdsrc); 1.330 + dirty = JSD_IsSourceDirty(jsdc, jsdsrc); 1.331 + status = JSD_GetSourceStatus(jsdc, jsdsrc); 1.332 + gotSrc = JSD_GetSourceText(jsdc, jsdsrc, &text, &len ); 1.333 + 1.334 + dummy = 0; /* gives us a line to set breakpoint... */ 1.335 + } 1.336 +} 1.337 +#else 1.338 +#define DEBUG_ITERATE_SOURCES(x) ((void)x) 1.339 +#endif 1.340 + 1.341 +/***************************************************************************/ 1.342 + 1.343 +JSDSourceText* 1.344 +jsd_NewSourceText(JSDContext* jsdc, const char* url) 1.345 +{ 1.346 + JSDSourceText* jsdsrc; 1.347 + char* new_url_string; 1.348 + 1.349 + JSD_LOCK_SOURCE_TEXT(jsdc); 1.350 + 1.351 + new_url_string = jsd_BuildNormalizedURL(url); 1.352 + 1.353 + if( ! new_url_string ) 1.354 + return nullptr; 1.355 + 1.356 + jsdsrc = jsd_FindSourceForURL(jsdc, new_url_string); 1.357 + 1.358 + if( jsdsrc ) 1.359 + { 1.360 + if( jsdsrc->doingEval ) 1.361 + { 1.362 + free(new_url_string); 1.363 + JSD_UNLOCK_SOURCE_TEXT(jsdc); 1.364 + return nullptr; 1.365 + } 1.366 + else 1.367 + _moveSourceToRemovedList(jsdc, jsdsrc); 1.368 + } 1.369 + 1.370 + jsdsrc = _addSource( jsdc, new_url_string ); 1.371 + 1.372 + JSD_UNLOCK_SOURCE_TEXT(jsdc); 1.373 + 1.374 + return jsdsrc; 1.375 +} 1.376 + 1.377 +JSDSourceText* 1.378 +jsd_AppendSourceText(JSDContext* jsdc, 1.379 + JSDSourceText* jsdsrc, 1.380 + const char* text, /* *not* zero terminated */ 1.381 + size_t length, 1.382 + JSDSourceStatus status) 1.383 +{ 1.384 + JSD_LOCK_SOURCE_TEXT(jsdc); 1.385 + 1.386 + if( jsdsrc->doingEval ) 1.387 + { 1.388 + JSD_UNLOCK_SOURCE_TEXT(jsdc); 1.389 + return nullptr; 1.390 + } 1.391 + 1.392 + if( ! _isSourceInSourceList( jsdc, jsdsrc ) ) 1.393 + { 1.394 + _removeSourceFromRemovedList( jsdc, jsdsrc ); 1.395 + JSD_UNLOCK_SOURCE_TEXT(jsdc); 1.396 + return nullptr; 1.397 + } 1.398 + 1.399 + if( text && length && ! _appendText( jsdc, jsdsrc, text, length ) ) 1.400 + { 1.401 + jsdsrc->dirty = true; 1.402 + jsdsrc->alterCount = jsdc->sourceAlterCount++ ; 1.403 + jsdsrc->status = JSD_SOURCE_FAILED; 1.404 + _moveSourceToRemovedList(jsdc, jsdsrc); 1.405 + JSD_UNLOCK_SOURCE_TEXT(jsdc); 1.406 + return nullptr; 1.407 + } 1.408 + 1.409 + jsdsrc->dirty = true; 1.410 + jsdsrc->alterCount = jsdc->sourceAlterCount++ ; 1.411 + jsdsrc->status = status; 1.412 + DEBUG_ITERATE_SOURCES(jsdc); 1.413 + JSD_UNLOCK_SOURCE_TEXT(jsdc); 1.414 + return jsdsrc; 1.415 +} 1.416 + 1.417 +JSDSourceText* 1.418 +jsd_AppendUCSourceText(JSDContext* jsdc, 1.419 + JSDSourceText* jsdsrc, 1.420 + const jschar* text, /* *not* zero terminated */ 1.421 + size_t length, 1.422 + JSDSourceStatus status) 1.423 +{ 1.424 +#define UNICODE_TRUNCATE_BUF_SIZE 1024 1.425 + static char* buf = nullptr; 1.426 + int remaining = length; 1.427 + 1.428 + if(!text || !length) 1.429 + return jsd_AppendSourceText(jsdc, jsdsrc, nullptr, 0, status); 1.430 + 1.431 + JSD_LOCK_SOURCE_TEXT(jsdc); 1.432 + if(!buf) 1.433 + { 1.434 + buf = js_pod_malloc<char>(UNICODE_TRUNCATE_BUF_SIZE); 1.435 + if(!buf) 1.436 + { 1.437 + JSD_UNLOCK_SOURCE_TEXT(jsdc); 1.438 + return nullptr; 1.439 + } 1.440 + } 1.441 + while(remaining && jsdsrc) { 1.442 + int bytes = (remaining < UNICODE_TRUNCATE_BUF_SIZE) ? remaining : UNICODE_TRUNCATE_BUF_SIZE; 1.443 + int i; 1.444 + for(i = 0; i < bytes; i++) 1.445 + buf[i] = (const char) *(text++); 1.446 + jsdsrc = jsd_AppendSourceText(jsdc,jsdsrc, 1.447 + buf, bytes, 1.448 + JSD_SOURCE_PARTIAL); 1.449 + remaining -= bytes; 1.450 + } 1.451 + if(jsdsrc && status != JSD_SOURCE_PARTIAL) 1.452 + jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc, nullptr, 0, status); 1.453 + 1.454 + JSD_UNLOCK_SOURCE_TEXT(jsdc); 1.455 + return jsdsrc; 1.456 +} 1.457 + 1.458 +/* convienence function for adding complete source of url in one call */ 1.459 +bool 1.460 +jsd_AddFullSourceText(JSDContext* jsdc, 1.461 + const char* text, /* *not* zero terminated */ 1.462 + size_t length, 1.463 + const char* url) 1.464 +{ 1.465 + JSDSourceText* jsdsrc; 1.466 + 1.467 + JSD_LOCK_SOURCE_TEXT(jsdc); 1.468 + 1.469 + jsdsrc = jsd_NewSourceText(jsdc, url); 1.470 + if( jsdsrc ) 1.471 + jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc, 1.472 + text, length, JSD_SOURCE_PARTIAL ); 1.473 + if( jsdsrc ) 1.474 + jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc, 1.475 + nullptr, 0, JSD_SOURCE_COMPLETED ); 1.476 + 1.477 + JSD_UNLOCK_SOURCE_TEXT(jsdc); 1.478 + 1.479 + return jsdsrc ? true : false; 1.480 +} 1.481 + 1.482 +/***************************************************************************/ 1.483 + 1.484 +void 1.485 +jsd_StartingEvalUsingFilename(JSDContext* jsdc, const char* url) 1.486 +{ 1.487 + JSDSourceText* jsdsrc; 1.488 + 1.489 + /* NOTE: We leave it locked! */ 1.490 + JSD_LOCK_SOURCE_TEXT(jsdc); 1.491 + 1.492 + jsdsrc = jsd_FindSourceForURL(jsdc, url); 1.493 + if(jsdsrc) 1.494 + { 1.495 +#if 0 1.496 +#ifndef JSD_LOWLEVEL_SOURCE 1.497 + MOZ_ASSERT(! jsdsrc->doingEval); 1.498 +#endif 1.499 +#endif 1.500 + jsdsrc->doingEval = true; 1.501 + } 1.502 +} 1.503 + 1.504 +void 1.505 +jsd_FinishedEvalUsingFilename(JSDContext* jsdc, const char* url) 1.506 +{ 1.507 + JSDSourceText* jsdsrc; 1.508 + 1.509 + /* NOTE: We ASSUME it is locked! */ 1.510 + 1.511 + jsdsrc = jsd_FindSourceForURL(jsdc, url); 1.512 + if(jsdsrc) 1.513 + { 1.514 +#if 0 1.515 +#ifndef JSD_LOWLEVEL_SOURCE 1.516 + /* 1.517 + * when using this low level source addition, this jsdsrc might 1.518 + * not have existed before the eval, but does exist now (without 1.519 + * this flag set!) 1.520 + */ 1.521 + MOZ_ASSERT(jsdsrc->doingEval); 1.522 +#endif 1.523 +#endif 1.524 + jsdsrc->doingEval = false; 1.525 + } 1.526 + 1.527 + JSD_UNLOCK_SOURCE_TEXT(jsdc); 1.528 +}