Back to index

lightning-sunbird  0.9+nobinonly
jsd_text.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * JavaScript Debugging support - Source Text functions
00040  */
00041 
00042 #include <ctype.h>
00043 #include "jsd.h"
00044 
00045 #ifdef DEBUG
00046 void JSD_ASSERT_VALID_SOURCE_TEXT(JSDSourceText* jsdsrc)
00047 {
00048     JS_ASSERT(jsdsrc);
00049     JS_ASSERT(jsdsrc->url);
00050 }
00051 #endif
00052 
00053 /***************************************************************************/
00054 /* XXX add notification */
00055 
00056 static void
00057 _clearText(JSDContext* jsdc, JSDSourceText* jsdsrc)
00058 {
00059     if( jsdsrc->text )
00060         free(jsdsrc->text);
00061     jsdsrc->text        = NULL;
00062     jsdsrc->textLength  = 0;
00063     jsdsrc->textSpace   = 0;
00064     jsdsrc->status      = JSD_SOURCE_CLEARED;
00065     jsdsrc->dirty       = JS_TRUE;
00066     jsdsrc->alterCount  = jsdc->sourceAlterCount++ ;
00067     jsdsrc->doingEval   = JS_FALSE;
00068 }    
00069 
00070 static JSBool
00071 _appendText(JSDContext* jsdc, JSDSourceText* jsdsrc, 
00072             const char* text, size_t length)
00073 {
00074 #define MEMBUF_GROW 1000
00075 
00076     uintN neededSize = jsdsrc->textLength + length;
00077 
00078     if( neededSize > jsdsrc->textSpace )
00079     {
00080         char* newBuf;
00081         uintN iNewSize;
00082 
00083         /* if this is the first alloc, the req might be all that's needed*/
00084         if( ! jsdsrc->textSpace )
00085             iNewSize = length;
00086         else
00087             iNewSize = (neededSize * 5 / 4) + MEMBUF_GROW;
00088 
00089         newBuf = (char*) realloc(jsdsrc->text, iNewSize);
00090         if( ! newBuf )
00091         {
00092             /* try again with the minimal size really asked for */
00093             iNewSize = neededSize;
00094             newBuf = (char*) realloc(jsdsrc->text, iNewSize);
00095             if( ! newBuf )
00096             {
00097                 /* out of memory */
00098                 _clearText( jsdc, jsdsrc );
00099                 jsdsrc->status = JSD_SOURCE_FAILED;
00100                 return JS_FALSE;
00101             }
00102         }
00103 
00104         jsdsrc->text = newBuf;
00105         jsdsrc->textSpace = iNewSize;
00106     }
00107 
00108     memcpy(jsdsrc->text + jsdsrc->textLength, text, length);
00109     jsdsrc->textLength += length;
00110     return JS_TRUE;
00111 }
00112 
00113 static JSDSourceText*
00114 _newSource(JSDContext* jsdc, const char* url)
00115 {
00116     JSDSourceText* jsdsrc = (JSDSourceText*)calloc(1,sizeof(JSDSourceText));
00117     if( ! jsdsrc )
00118         return NULL;
00119     
00120     jsdsrc->url        = (char*) url; /* already a copy */
00121     jsdsrc->status     = JSD_SOURCE_INITED;
00122     jsdsrc->dirty      = JS_TRUE;
00123     jsdsrc->alterCount = jsdc->sourceAlterCount++ ;
00124             
00125     return jsdsrc;
00126 }
00127 
00128 static void
00129 _destroySource(JSDContext* jsdc, JSDSourceText* jsdsrc)
00130 {
00131     JS_ASSERT(NULL == jsdsrc->text);  /* must _clearText() first */
00132     free(jsdsrc->url);
00133     free(jsdsrc);
00134 }
00135 
00136 static void
00137 _removeSource(JSDContext* jsdc, JSDSourceText* jsdsrc)
00138 {
00139     JS_REMOVE_LINK(&jsdsrc->links);
00140     _clearText(jsdc, jsdsrc);
00141     _destroySource(jsdc, jsdsrc);
00142 }
00143 
00144 static JSDSourceText*
00145 _addSource(JSDContext* jsdc, const char* url)
00146 {
00147     JSDSourceText* jsdsrc = _newSource(jsdc, url);
00148     if( ! jsdsrc )
00149         return NULL;
00150     JS_INSERT_LINK(&jsdsrc->links, &jsdc->sources);
00151     return jsdsrc;
00152 }
00153 
00154 static void
00155 _moveSourceToFront(JSDContext* jsdc, JSDSourceText* jsdsrc)
00156 {
00157     JS_REMOVE_LINK(&jsdsrc->links);
00158     JS_INSERT_LINK(&jsdsrc->links, &jsdc->sources);
00159 }
00160 
00161 static void
00162 _moveSourceToRemovedList(JSDContext* jsdc, JSDSourceText* jsdsrc)
00163 {
00164     _clearText(jsdc, jsdsrc);
00165     JS_REMOVE_LINK(&jsdsrc->links);
00166     JS_INSERT_LINK(&jsdsrc->links, &jsdc->removedSources);
00167 }
00168 
00169 static void
00170 _removeSourceFromRemovedList( JSDContext* jsdc, JSDSourceText* jsdsrc )
00171 {
00172     JS_REMOVE_LINK(&jsdsrc->links);
00173     _destroySource( jsdc, jsdsrc );
00174 }
00175 
00176 static JSBool
00177 _isSourceInSourceList(JSDContext* jsdc, JSDSourceText* jsdsrcToFind)
00178 {
00179     JSDSourceText *jsdsrc;
00180 
00181     for( jsdsrc = (JSDSourceText*)jsdc->sources.next;
00182          jsdsrc != (JSDSourceText*)&jsdc->sources;
00183          jsdsrc = (JSDSourceText*)jsdsrc->links.next ) 
00184     {
00185         if( jsdsrc == jsdsrcToFind )
00186             return JS_TRUE;
00187     }
00188     return JS_FALSE;
00189 }
00190 
00191 /*  compare strings in a case insensitive manner with a length limit
00192 */
00193 
00194 static int 
00195 strncasecomp (const char* one, const char * two, int n)
00196 {
00197     const char *pA;
00198     const char *pB;
00199     
00200     for(pA=one, pB=two;; pA++, pB++) 
00201     {
00202         int tmp;
00203         if (pA == one+n) 
00204             return 0;   
00205         if (!(*pA && *pB)) 
00206             return *pA - *pB;
00207         tmp = tolower(*pA) - tolower(*pB);
00208         if (tmp) 
00209             return tmp;
00210     }
00211 }
00212 
00213 static char file_url_prefix[]    = "file:";
00214 #define FILE_URL_PREFIX_LEN     (sizeof file_url_prefix - 1)
00215 
00216 const char*
00217 jsd_BuildNormalizedURL( const char* url_string )
00218 {
00219     char *new_url_string;
00220 
00221     if( ! url_string )
00222         return NULL;
00223 
00224     if (!strncasecomp(url_string, file_url_prefix, FILE_URL_PREFIX_LEN) &&
00225         url_string[FILE_URL_PREFIX_LEN + 0] == '/' &&
00226         url_string[FILE_URL_PREFIX_LEN + 1] == '/') {
00227         new_url_string = JS_smprintf("%s%s",
00228                                      file_url_prefix,
00229                                      url_string + FILE_URL_PREFIX_LEN + 2);
00230     } else {
00231         new_url_string = strdup(url_string);
00232     }
00233     return new_url_string;
00234 }
00235 
00236 /***************************************************************************/
00237 
00238 void
00239 jsd_DestroyAllSources( JSDContext* jsdc )
00240 {
00241     JSDSourceText *jsdsrc;
00242     JSDSourceText *next;
00243 
00244     for( jsdsrc = (JSDSourceText*)jsdc->sources.next;
00245          jsdsrc != (JSDSourceText*)&jsdc->sources;
00246          jsdsrc = next ) 
00247     {
00248         next = (JSDSourceText*)jsdsrc->links.next;
00249         _removeSource( jsdc, jsdsrc );
00250     }
00251 
00252     for( jsdsrc = (JSDSourceText*)jsdc->removedSources.next;
00253          jsdsrc != (JSDSourceText*)&jsdc->removedSources;
00254          jsdsrc = next ) 
00255     {
00256         next = (JSDSourceText*)jsdsrc->links.next;
00257         _removeSourceFromRemovedList( jsdc, jsdsrc );
00258     }
00259 
00260 }
00261 
00262 JSDSourceText*
00263 jsd_IterateSources(JSDContext* jsdc, JSDSourceText **iterp)
00264 {
00265     JSDSourceText *jsdsrc = *iterp;
00266     
00267     if( !jsdsrc )
00268         jsdsrc = (JSDSourceText *)jsdc->sources.next;
00269     if( jsdsrc == (JSDSourceText *)&jsdc->sources )
00270         return NULL;
00271     *iterp = (JSDSourceText *)jsdsrc->links.next;
00272     return jsdsrc;
00273 }
00274 
00275 JSDSourceText*
00276 jsd_FindSourceForURL(JSDContext* jsdc, const char* url)
00277 {
00278     JSDSourceText *jsdsrc;
00279 
00280     for( jsdsrc = (JSDSourceText *)jsdc->sources.next;
00281          jsdsrc != (JSDSourceText *)&jsdc->sources;
00282          jsdsrc = (JSDSourceText *)jsdsrc->links.next )
00283     {
00284         if( 0 == strcmp(jsdsrc->url, url) )
00285             return jsdsrc;
00286     }
00287     return NULL;
00288 }
00289 
00290 const char*
00291 jsd_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc)
00292 {
00293     return jsdsrc->url;
00294 }
00295 
00296 JSBool
00297 jsd_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc,
00298                   const char** ppBuf, intN* pLen )
00299 {
00300     *ppBuf = jsdsrc->text;
00301     *pLen  = jsdsrc->textLength;
00302     return JS_TRUE;
00303 }
00304 
00305 void
00306 jsd_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc)
00307 {
00308     if( JSD_SOURCE_INITED  != jsdsrc->status &&
00309         JSD_SOURCE_PARTIAL != jsdsrc->status )
00310     {
00311         _clearText(jsdc, jsdsrc);
00312     }
00313 }
00314 
00315 JSDSourceStatus
00316 jsd_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc)
00317 {
00318     return jsdsrc->status;
00319 }
00320 
00321 JSBool
00322 jsd_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc)
00323 {
00324     return jsdsrc->dirty;
00325 }
00326 
00327 void
00328 jsd_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, JSBool dirty)
00329 {
00330     jsdsrc->dirty = dirty;
00331 }
00332 
00333 uintN
00334 jsd_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc)
00335 {
00336     return jsdsrc->alterCount;
00337 }
00338 
00339 uintN
00340 jsd_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc)
00341 {
00342     return jsdsrc->alterCount = jsdc->sourceAlterCount++;
00343 }
00344 
00345 /***************************************************************************/
00346 
00347 #if defined(DEBUG) && 0
00348 void DEBUG_ITERATE_SOURCES( JSDContext* jsdc )
00349 {
00350     JSDSourceText* iterp = NULL;
00351     JSDSourceText* jsdsrc = NULL;
00352     int dummy;
00353     
00354     while( NULL != (jsdsrc = jsd_IterateSources(jsdc, &iterp)) )
00355     {
00356         const char*     url;
00357         const char*     text;
00358         int             len;
00359         JSBool          dirty;
00360         JSDStreamStatus status;
00361         JSBool          gotSrc;
00362 
00363         url     = JSD_GetSourceURL(jsdc, jsdsrc);
00364         dirty   = JSD_IsSourceDirty(jsdc, jsdsrc);
00365         status  = JSD_GetSourceStatus(jsdc, jsdsrc);
00366         gotSrc  = JSD_GetSourceText(jsdc, jsdsrc, &text, &len );
00367         
00368         dummy = 0;  /* gives us a line to set breakpoint... */
00369     }
00370 }
00371 #else
00372 #define DEBUG_ITERATE_SOURCES(x) ((void)x)
00373 #endif
00374 
00375 /***************************************************************************/
00376 
00377 JSDSourceText*
00378 jsd_NewSourceText(JSDContext* jsdc, const char* url)
00379 {
00380     JSDSourceText* jsdsrc;
00381     const char* new_url_string;
00382 
00383     JSD_LOCK_SOURCE_TEXT(jsdc);
00384 
00385 #ifdef LIVEWIRE
00386     new_url_string = url; /* we take ownership of alloc'd string */
00387 #else
00388     new_url_string = jsd_BuildNormalizedURL(url);
00389 #endif
00390     if( ! new_url_string )
00391         return NULL;
00392 
00393     jsdsrc = jsd_FindSourceForURL(jsdc, new_url_string);
00394 
00395     if( jsdsrc )
00396     {
00397         if( jsdsrc->doingEval )
00398         {
00399 #ifdef LIVEWIRE
00400             free((char*)new_url_string);
00401 #endif
00402             JSD_UNLOCK_SOURCE_TEXT(jsdc);
00403             return NULL;
00404         }
00405         else    
00406             _moveSourceToRemovedList(jsdc, jsdsrc);
00407     }
00408 
00409     jsdsrc = _addSource( jsdc, new_url_string );
00410 
00411     JSD_UNLOCK_SOURCE_TEXT(jsdc);
00412 
00413     return jsdsrc;
00414 }
00415 
00416 JSDSourceText*
00417 jsd_AppendSourceText(JSDContext* jsdc, 
00418                      JSDSourceText* jsdsrc,
00419                      const char* text,       /* *not* zero terminated */
00420                      size_t length,
00421                      JSDSourceStatus status)
00422 {
00423     JSD_LOCK_SOURCE_TEXT(jsdc);
00424 
00425     if( jsdsrc->doingEval )
00426     {
00427         JSD_UNLOCK_SOURCE_TEXT(jsdc);
00428         return NULL;
00429     }
00430 
00431     if( ! _isSourceInSourceList( jsdc, jsdsrc ) )
00432     {
00433         _removeSourceFromRemovedList( jsdc, jsdsrc );
00434         JSD_UNLOCK_SOURCE_TEXT(jsdc);
00435         return NULL;
00436     }
00437 
00438     if( text && length && ! _appendText( jsdc, jsdsrc, text, length ) )
00439     {
00440         jsdsrc->dirty  = JS_TRUE;
00441         jsdsrc->alterCount  = jsdc->sourceAlterCount++ ;
00442         jsdsrc->status = JSD_SOURCE_FAILED;
00443         _moveSourceToRemovedList(jsdc, jsdsrc);
00444         JSD_UNLOCK_SOURCE_TEXT(jsdc);
00445         return NULL;    
00446     }
00447 
00448     jsdsrc->dirty  = JS_TRUE;
00449     jsdsrc->alterCount  = jsdc->sourceAlterCount++ ;
00450     jsdsrc->status = status;
00451     DEBUG_ITERATE_SOURCES(jsdc);
00452     JSD_UNLOCK_SOURCE_TEXT(jsdc);
00453     return jsdsrc;
00454 }
00455 
00456 JSDSourceText*
00457 jsd_AppendUCSourceText(JSDContext* jsdc,
00458                        JSDSourceText* jsdsrc,
00459                        const jschar* text,       /* *not* zero terminated */
00460                        size_t length,
00461                        JSDSourceStatus status)
00462 {
00463 #define UNICODE_TRUNCATE_BUF_SIZE 1024
00464     static char* buf = NULL;
00465     int remaining = length;
00466 
00467     if(!text || !length)
00468         return jsd_AppendSourceText(jsdc, jsdsrc, NULL, 0, status);
00469 
00470     JSD_LOCK_SOURCE_TEXT(jsdc);
00471     if(!buf)
00472     {
00473         buf = malloc(UNICODE_TRUNCATE_BUF_SIZE);
00474         if(!buf)
00475         {
00476             JSD_UNLOCK_SOURCE_TEXT(jsdc);
00477             return NULL;
00478         }
00479     }
00480     while(remaining && jsdsrc) {
00481         int bytes = JS_MIN(remaining, UNICODE_TRUNCATE_BUF_SIZE);
00482         int i;
00483         for(i = 0; i < bytes; i++)
00484             buf[i] = (const char) *(text++);
00485         jsdsrc = jsd_AppendSourceText(jsdc,jsdsrc,
00486                                       buf, bytes,
00487                                       JSD_SOURCE_PARTIAL);
00488         remaining -= bytes;
00489     }
00490     if(jsdsrc && status != JSD_SOURCE_PARTIAL)
00491         jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc, NULL, 0, status);
00492 
00493     JSD_UNLOCK_SOURCE_TEXT(jsdc);
00494     return jsdsrc;
00495 }
00496 
00497 /* convienence function for adding complete source of url in one call */
00498 JSBool
00499 jsd_AddFullSourceText(JSDContext* jsdc, 
00500                       const char* text,       /* *not* zero terminated */
00501                       size_t      length,
00502                       const char* url)
00503 {
00504     JSDSourceText* jsdsrc;
00505 
00506     JSD_LOCK_SOURCE_TEXT(jsdc);
00507 
00508     jsdsrc = jsd_NewSourceText(jsdc, url);
00509     if( jsdsrc )
00510         jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc,
00511                                       text, length, JSD_SOURCE_PARTIAL );
00512     if( jsdsrc )
00513         jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc,
00514                                       NULL, 0, JSD_SOURCE_COMPLETED );
00515 
00516     JSD_UNLOCK_SOURCE_TEXT(jsdc);
00517 
00518     return jsdsrc ? JS_TRUE : JS_FALSE;
00519 }
00520 
00521 /***************************************************************************/
00522 
00523 void
00524 jsd_StartingEvalUsingFilename(JSDContext* jsdc, const char* url)
00525 {
00526     JSDSourceText* jsdsrc;
00527 
00528     /* NOTE: We leave it locked! */
00529     JSD_LOCK_SOURCE_TEXT(jsdc); 
00530 
00531     jsdsrc = jsd_FindSourceForURL(jsdc, url);
00532     if(jsdsrc)
00533     {
00534 #if 0
00535 #ifndef JSD_LOWLEVEL_SOURCE
00536         JS_ASSERT(! jsdsrc->doingEval);
00537 #endif
00538 #endif
00539         jsdsrc->doingEval = JS_TRUE;
00540     }
00541 }    
00542 
00543 void
00544 jsd_FinishedEvalUsingFilename(JSDContext* jsdc, const char* url)
00545 {
00546     JSDSourceText* jsdsrc;
00547 
00548     /* NOTE: We ASSUME it is locked! */
00549 
00550     jsdsrc = jsd_FindSourceForURL(jsdc, url);
00551     if(jsdsrc)
00552     {
00553 #if 0
00554 #ifndef JSD_LOWLEVEL_SOURCE
00555         /*
00556         * when using this low level source addition, this jsdsrc might 
00557         * not have existed before the eval, but does exist now (without
00558         * this flag set!)
00559         */
00560         JS_ASSERT(jsdsrc->doingEval);
00561 #endif
00562 #endif
00563         jsdsrc->doingEval = JS_FALSE;
00564     }
00565 
00566     JSD_UNLOCK_SOURCE_TEXT(jsdc);
00567 }