js/jsd/jsd_text.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     7 /*
     8  * JavaScript Debugging support - Source Text functions
     9  */
    11 #include <ctype.h>
    12 #include "jsd.h"
    13 #include "jsprf.h"
    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
    23 /***************************************************************************/
    24 /* XXX add notification */
    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 }    
    40 static bool
    41 _appendText(JSDContext* jsdc, JSDSourceText* jsdsrc, 
    42             const char* text, size_t length)
    43 {
    44 #define MEMBUF_GROW 1000
    46     unsigned neededSize = jsdsrc->textLength + length;
    48     if( neededSize > jsdsrc->textSpace )
    49     {
    50         char* newBuf;
    51         unsigned iNewSize;
    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;
    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         }
    74         jsdsrc->text = newBuf;
    75         jsdsrc->textSpace = iNewSize;
    76     }
    78     memcpy(jsdsrc->text + jsdsrc->textLength, text, length);
    79     jsdsrc->textLength += length;
    80     return true;
    81 }
    83 static JSDSourceText*
    84 _newSource(JSDContext* jsdc, char* url)
    85 {
    86     JSDSourceText* jsdsrc = (JSDSourceText*)calloc(1,sizeof(JSDSourceText));
    87     if( ! jsdsrc )
    88         return nullptr;
    90     jsdsrc->url        = url;
    91     jsdsrc->status     = JSD_SOURCE_INITED;
    92     jsdsrc->dirty      = true;
    93     jsdsrc->alterCount = jsdc->sourceAlterCount++ ;
    95     return jsdsrc;
    96 }
    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 }
   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 }
   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 }
   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 }
   132 static void
   133 _removeSourceFromRemovedList( JSDContext* jsdc, JSDSourceText* jsdsrc )
   134 {
   135     JS_REMOVE_LINK(&jsdsrc->links);
   136     _destroySource( jsdc, jsdsrc );
   137 }
   139 static bool
   140 _isSourceInSourceList(JSDContext* jsdc, JSDSourceText* jsdsrcToFind)
   141 {
   142     JSDSourceText *jsdsrc;
   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 }
   154 /*  compare strings in a case insensitive manner with a length limit
   155 */
   157 static int 
   158 strncasecomp (const char* one, const char * two, int n)
   159 {
   160     const char *pA;
   161     const char *pB;
   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 }
   176 static const char file_url_prefix[] = "file:";
   177 #define FILE_URL_PREFIX_LEN     (sizeof file_url_prefix - 1)
   179 char*
   180 jsd_BuildNormalizedURL( const char* url_string )
   181 {
   182     char *new_url_string;
   184     if( ! url_string )
   185         return nullptr;
   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 }
   199 /***************************************************************************/
   201 void
   202 jsd_DestroyAllSources( JSDContext* jsdc )
   203 {
   204     JSDSourceText *jsdsrc;
   205     JSDSourceText *next;
   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     }
   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     }
   223 }
   225 JSDSourceText*
   226 jsd_IterateSources(JSDContext* jsdc, JSDSourceText **iterp)
   227 {
   228     JSDSourceText *jsdsrc = *iterp;
   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 }
   238 JSDSourceText*
   239 jsd_FindSourceForURL(JSDContext* jsdc, const char* url)
   240 {
   241     JSDSourceText *jsdsrc;
   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 }
   253 const char*
   254 jsd_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc)
   255 {
   256     return jsdsrc->url;
   257 }
   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 }
   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 }
   278 JSDSourceStatus
   279 jsd_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc)
   280 {
   281     return jsdsrc->status;
   282 }
   284 bool
   285 jsd_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc)
   286 {
   287     return jsdsrc->dirty;
   288 }
   290 void
   291 jsd_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, bool dirty)
   292 {
   293     jsdsrc->dirty = dirty;
   294 }
   296 unsigned
   297 jsd_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc)
   298 {
   299     return jsdsrc->alterCount;
   300 }
   302 unsigned
   303 jsd_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc)
   304 {
   305     return jsdsrc->alterCount = jsdc->sourceAlterCount++;
   306 }
   308 /***************************************************************************/
   310 #if defined(DEBUG) && 0
   311 void DEBUG_ITERATE_SOURCES( JSDContext* jsdc )
   312 {
   313     JSDSourceText* iterp = nullptr;
   314     JSDSourceText* jsdsrc = nullptr;
   315     int dummy;
   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;
   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 );
   331         dummy = 0;  /* gives us a line to set breakpoint... */
   332     }
   333 }
   334 #else
   335 #define DEBUG_ITERATE_SOURCES(x) ((void)x)
   336 #endif
   338 /***************************************************************************/
   340 JSDSourceText*
   341 jsd_NewSourceText(JSDContext* jsdc, const char* url)
   342 {
   343     JSDSourceText* jsdsrc;
   344     char* new_url_string;
   346     JSD_LOCK_SOURCE_TEXT(jsdc);
   348     new_url_string = jsd_BuildNormalizedURL(url);
   350     if( ! new_url_string )
   351         return nullptr;
   353     jsdsrc = jsd_FindSourceForURL(jsdc, new_url_string);
   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     }
   367     jsdsrc = _addSource( jsdc, new_url_string );
   369     JSD_UNLOCK_SOURCE_TEXT(jsdc);
   371     return jsdsrc;
   372 }
   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);
   383     if( jsdsrc->doingEval )
   384     {
   385         JSD_UNLOCK_SOURCE_TEXT(jsdc);
   386         return nullptr;
   387     }
   389     if( ! _isSourceInSourceList( jsdc, jsdsrc ) )
   390     {
   391         _removeSourceFromRemovedList( jsdc, jsdsrc );
   392         JSD_UNLOCK_SOURCE_TEXT(jsdc);
   393         return nullptr;
   394     }
   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     }
   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 }
   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;
   425     if(!text || !length)
   426         return jsd_AppendSourceText(jsdc, jsdsrc, nullptr, 0, status);
   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);
   451     JSD_UNLOCK_SOURCE_TEXT(jsdc);
   452     return jsdsrc;
   453 }
   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;
   464     JSD_LOCK_SOURCE_TEXT(jsdc);
   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 );
   474     JSD_UNLOCK_SOURCE_TEXT(jsdc);
   476     return jsdsrc ? true : false;
   477 }
   479 /***************************************************************************/
   481 void
   482 jsd_StartingEvalUsingFilename(JSDContext* jsdc, const char* url)
   483 {
   484     JSDSourceText* jsdsrc;
   486     /* NOTE: We leave it locked! */
   487     JSD_LOCK_SOURCE_TEXT(jsdc); 
   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 }    
   501 void
   502 jsd_FinishedEvalUsingFilename(JSDContext* jsdc, const char* url)
   503 {
   504     JSDSourceText* jsdsrc;
   506     /* NOTE: We ASSUME it is locked! */
   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     }
   524     JSD_UNLOCK_SOURCE_TEXT(jsdc);
   525 }    

mercurial