зеркало из https://github.com/mozilla/gecko-dev.git
472 строки
12 KiB
C
472 строки
12 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
/*
|
|
** JavaScript Debugger Navigator API - Source Text functions
|
|
*/
|
|
|
|
#include "jsd.h"
|
|
#ifdef NSPR20
|
|
#ifdef XP_MAC
|
|
#include "prpriv.h"
|
|
#else
|
|
#include "private/prpriv.h"
|
|
#endif
|
|
#endif
|
|
|
|
/**
|
|
* XXX convert this and jsd_conv so that all accumulation of text done here
|
|
* Also, use handle oriented alloc for Win16 64k limit problem
|
|
*/
|
|
|
|
PRCList jsd_source_list = PR_INIT_STATIC_CLIST(&jsd_source_list);
|
|
PRCList jsd_removed_source_list = PR_INIT_STATIC_CLIST(&jsd_removed_source_list);
|
|
|
|
/***************************************************************************/
|
|
/*
|
|
* typedef enum
|
|
* {
|
|
* JSD_SOURCE_INITED,
|
|
* JSD_SOURCE_PARTIAL,
|
|
* JSD_SOURCE_COMPLETED,
|
|
* JSD_SOURCE_ABORTED,
|
|
* JSD_SOURCE_FAILED
|
|
*
|
|
* } JSDSourceStatus;
|
|
*/
|
|
|
|
#ifdef DEBUG
|
|
void JSD_ASSERT_VALID_SOURCE_TEXT( JSDSourceText* jsdsrc )
|
|
{
|
|
PR_ASSERT( jsdsrc );
|
|
PR_ASSERT( jsdsrc->url );
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************/
|
|
|
|
/* XXX add serial number instead of dirty */
|
|
/* XXX add notification */
|
|
|
|
static PRUintn g_alterCount = 1;
|
|
|
|
|
|
static void
|
|
ClearText( JSDContext* jsdc, JSDSourceText* jsdsrc )
|
|
{
|
|
if( jsdsrc->text )
|
|
MY_XP_HUGE_FREE(jsdsrc->text);
|
|
jsdsrc->text = NULL;
|
|
jsdsrc->textLength = 0;
|
|
jsdsrc->textSpace = 0;
|
|
jsdsrc->status = JSD_SOURCE_CLEARED;
|
|
jsdsrc->dirty = JS_TRUE;
|
|
jsdsrc->alterCount = g_alterCount++ ;
|
|
}
|
|
|
|
static JSBool
|
|
AppendText( JSDContext* jsdc, JSDSourceText* jsdsrc,
|
|
const char* text, size_t length )
|
|
{
|
|
#define MEMBUF_GROW 1000
|
|
|
|
PRUintn neededSize = jsdsrc->textLength + length;
|
|
|
|
if( neededSize > jsdsrc->textSpace )
|
|
{
|
|
MY_XP_HUGE_CHAR_PTR pBuf;
|
|
PRUintn iNewSize;
|
|
|
|
/* if this is the first alloc, the req might be all that's needed*/
|
|
if( ! jsdsrc->textSpace )
|
|
iNewSize = length;
|
|
else
|
|
iNewSize = (neededSize * 5 / 4) + MEMBUF_GROW;
|
|
|
|
pBuf = (MY_XP_HUGE_CHAR_PTR) MY_XP_HUGE_ALLOC(iNewSize);
|
|
if( pBuf )
|
|
{
|
|
if( jsdsrc->text )
|
|
{
|
|
MY_XP_HUGE_MEMCPY(pBuf, jsdsrc->text, jsdsrc->textLength);
|
|
MY_XP_HUGE_FREE(jsdsrc->text);
|
|
}
|
|
jsdsrc->text = pBuf;
|
|
jsdsrc->textSpace = iNewSize;
|
|
}
|
|
else
|
|
{
|
|
/* LTNOTE: throw an out of memory exception */
|
|
ClearText( jsdc, jsdsrc );
|
|
jsdsrc->status = JSD_SOURCE_FAILED;
|
|
return JS_FALSE;
|
|
}
|
|
}
|
|
|
|
MY_XP_HUGE_MEMCPY( &jsdsrc->text[jsdsrc->textLength], text, length );
|
|
jsdsrc->textLength += length;
|
|
return JS_TRUE;
|
|
}
|
|
|
|
static JSDSourceText*
|
|
NewSource( JSDContext* jsdc, const char* url )
|
|
{
|
|
JSDSourceText* jsdsrc = PR_NEWZAP(JSDSourceText);
|
|
if( ! jsdsrc )
|
|
return NULL;
|
|
|
|
jsdsrc->url = (char*) url; /* already a copy */
|
|
jsdsrc->status = JSD_SOURCE_INITED;
|
|
jsdsrc->dirty = JS_TRUE;
|
|
jsdsrc->alterCount = g_alterCount++ ;
|
|
|
|
return jsdsrc;
|
|
}
|
|
|
|
static void
|
|
DestroySource( JSDContext* jsdc, JSDSourceText* jsdsrc )
|
|
{
|
|
PR_ASSERT( NULL == jsdsrc->text ); /* must ClearText() first */
|
|
MY_XP_FREE(jsdsrc->url);
|
|
MY_XP_FREE(jsdsrc);
|
|
}
|
|
|
|
static void
|
|
RemoveSource( JSDContext* jsdc, JSDSourceText* jsdsrc )
|
|
{
|
|
PR_REMOVE_LINK(&jsdsrc->links);
|
|
ClearText( jsdc, jsdsrc );
|
|
DestroySource( jsdc, jsdsrc );
|
|
}
|
|
|
|
static JSDSourceText*
|
|
AddSource( JSDContext* jsdc, const char* url )
|
|
{
|
|
JSDSourceText* jsdsrc = NewSource( jsdc, url );
|
|
if( ! jsdsrc )
|
|
return NULL;
|
|
PR_INSERT_LINK(&jsdsrc->links, &jsd_source_list);
|
|
return jsdsrc;
|
|
}
|
|
|
|
static void
|
|
MoveSourceToFront( JSDContext* jsdc, JSDSourceText* jsdsrc )
|
|
{
|
|
PR_REMOVE_LINK(&jsdsrc->links);
|
|
PR_INSERT_LINK(&jsdsrc->links, &jsd_source_list);
|
|
}
|
|
|
|
static void
|
|
MoveSourceToRemovedList( JSDContext* jsdc, JSDSourceText* jsdsrc )
|
|
{
|
|
ClearText(jsdc, jsdsrc);
|
|
PR_REMOVE_LINK(&jsdsrc->links);
|
|
PR_INSERT_LINK(&jsdsrc->links, &jsd_removed_source_list);
|
|
}
|
|
|
|
static void
|
|
RemoveSourceFromRemovedList( JSDContext* jsdc, JSDSourceText* jsdsrc )
|
|
{
|
|
PR_REMOVE_LINK(&jsdsrc->links);
|
|
DestroySource( jsdc, jsdsrc );
|
|
}
|
|
|
|
static JSBool
|
|
IsSourceInSourceList( JSDContext* jsdc, JSDSourceText* jsdsrcToFind )
|
|
{
|
|
JSDSourceText *jsdsrc;
|
|
|
|
for (jsdsrc = (JSDSourceText*)jsd_source_list.next;
|
|
jsdsrc != (JSDSourceText*)&jsd_source_list;
|
|
jsdsrc = (JSDSourceText*)jsdsrc->links.next )
|
|
{
|
|
if( jsdsrc == jsdsrcToFind )
|
|
return JS_TRUE;
|
|
}
|
|
return JS_FALSE;
|
|
}
|
|
|
|
/* compare strings in a case insensitive manner with a length limit
|
|
*/
|
|
|
|
static int
|
|
strncasecomp (const char* one, const char * two, int n)
|
|
{
|
|
const char *pA;
|
|
const char *pB;
|
|
|
|
for(pA=one, pB=two;; pA++, pB++)
|
|
{
|
|
int tmp;
|
|
if (pA == one+n)
|
|
return 0;
|
|
if (!(*pA && *pB))
|
|
return *pA - *pB;
|
|
tmp = MY_XP_TO_LOWER(*pA) - MY_XP_TO_LOWER(*pB);
|
|
if (tmp)
|
|
return tmp;
|
|
}
|
|
}
|
|
|
|
static char file_url_prefix[] = "file:";
|
|
#define FILE_URL_PREFIX_LEN (sizeof file_url_prefix - 1)
|
|
|
|
const char*
|
|
jsd_BuildNormalizedURL( const char* url_string )
|
|
{
|
|
char *new_url_string;
|
|
|
|
if( ! url_string )
|
|
return NULL;
|
|
|
|
if (!MY_XP_STRNCASECMP(url_string, file_url_prefix, FILE_URL_PREFIX_LEN) &&
|
|
url_string[FILE_URL_PREFIX_LEN + 0] == '/' &&
|
|
url_string[FILE_URL_PREFIX_LEN + 1] == '/') {
|
|
new_url_string = PR_smprintf("%s%s",
|
|
file_url_prefix,
|
|
url_string + FILE_URL_PREFIX_LEN + 2);
|
|
} else {
|
|
new_url_string = MY_XP_STRDUP(url_string);
|
|
}
|
|
return new_url_string;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
#ifndef JSD_SIMULATION
|
|
static PRMonitor *jsd_text_mon = NULL;
|
|
#endif /* JSD_SIMULATION */
|
|
|
|
void
|
|
jsd_LockSourceTextSubsystem(JSDContext* jsdc)
|
|
{
|
|
#ifndef JSD_SIMULATION
|
|
if (jsd_text_mon == NULL)
|
|
jsd_text_mon = PR_NewNamedMonitor("jsd-text-monitor");
|
|
|
|
PR_EnterMonitor(jsd_text_mon);
|
|
#endif /* JSD_SIMULATION */
|
|
}
|
|
|
|
void
|
|
jsd_UnlockSourceTextSubsystem(JSDContext* jsdc)
|
|
{
|
|
#ifndef JSD_SIMULATION
|
|
PR_ExitMonitor(jsd_text_mon);
|
|
#endif /* JSD_SIMULATION */
|
|
}
|
|
|
|
void
|
|
jsd_DestroyAllSources( JSDContext* jsdc )
|
|
{
|
|
JSDSourceText *jsdsrc;
|
|
JSDSourceText *next;
|
|
|
|
for (jsdsrc = (JSDSourceText*)jsd_source_list.next;
|
|
jsdsrc != (JSDSourceText*)&jsd_source_list;
|
|
jsdsrc = next)
|
|
{
|
|
next = (JSDSourceText*)jsdsrc->links.next;
|
|
RemoveSource( jsdc, jsdsrc );
|
|
}
|
|
|
|
for (jsdsrc = (JSDSourceText*)jsd_removed_source_list.next;
|
|
jsdsrc != (JSDSourceText*)&jsd_removed_source_list;
|
|
jsdsrc = next)
|
|
{
|
|
next = (JSDSourceText*)jsdsrc->links.next;
|
|
RemoveSourceFromRemovedList( jsdc, jsdsrc );
|
|
}
|
|
|
|
}
|
|
|
|
JSDSourceText*
|
|
jsd_IterateSources(JSDContext* jsdc, JSDSourceText **iterp)
|
|
{
|
|
JSDSourceText *jsdsrc = *iterp;
|
|
|
|
if (!jsdsrc)
|
|
jsdsrc = (JSDSourceText *)jsd_source_list.next;
|
|
if (jsdsrc == (JSDSourceText *)&jsd_source_list)
|
|
return NULL;
|
|
*iterp = (JSDSourceText *)jsdsrc->links.next;
|
|
return jsdsrc;
|
|
}
|
|
|
|
JSDSourceText*
|
|
jsd_FindSourceForURL(JSDContext* jsdc, const char* url)
|
|
{
|
|
JSDSourceText *jsdsrc;
|
|
|
|
for (jsdsrc = (JSDSourceText *)jsd_source_list.next;
|
|
jsdsrc != (JSDSourceText *)&jsd_source_list;
|
|
jsdsrc = (JSDSourceText *)jsdsrc->links.next) {
|
|
if (0 == strcmp(jsdsrc->url, url))
|
|
return jsdsrc;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const char*
|
|
jsd_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc)
|
|
{
|
|
return jsdsrc->url;
|
|
}
|
|
|
|
JSBool
|
|
jsd_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc,
|
|
const char** ppBuf, int* pLen )
|
|
{
|
|
*ppBuf = jsdsrc->text;
|
|
*pLen = jsdsrc->textLength;
|
|
return JS_TRUE;
|
|
}
|
|
|
|
void
|
|
jsd_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc)
|
|
{
|
|
if( JSD_SOURCE_INITED != jsdsrc->status &&
|
|
JSD_SOURCE_PARTIAL != jsdsrc->status )
|
|
{
|
|
ClearText(jsdc, jsdsrc);
|
|
}
|
|
}
|
|
|
|
JSDSourceStatus
|
|
jsd_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc)
|
|
{
|
|
return jsdsrc->status;
|
|
}
|
|
|
|
JSBool
|
|
jsd_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc)
|
|
{
|
|
return jsdsrc->dirty;
|
|
}
|
|
|
|
void
|
|
jsd_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, JSBool dirty)
|
|
{
|
|
jsdsrc->dirty = dirty;
|
|
}
|
|
|
|
PRUintn
|
|
jsd_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc)
|
|
{
|
|
return jsdsrc->alterCount;
|
|
}
|
|
|
|
PRUintn
|
|
jsd_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc)
|
|
{
|
|
return ++jsdsrc->alterCount;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
#if defined(DEBUG) && 0
|
|
void DEBUG_ITERATE_SOURCES( JSDContext* jsdc )
|
|
{
|
|
JSDSourceText* iterp = NULL;
|
|
JSDSourceText* jsdsrc = NULL;
|
|
int dummy;
|
|
|
|
while( NULL != (jsdsrc = jsd_IterateSources(jsdc, &iterp)) )
|
|
{
|
|
const char* url;
|
|
const char* text;
|
|
int len;
|
|
JSBool dirty;
|
|
JSDStreamStatus status;
|
|
JSBool gotSrc;
|
|
|
|
url = JSD_GetSourceURL(jsdc, jsdsrc);
|
|
dirty = JSD_IsSourceDirty(jsdc, jsdsrc);
|
|
status = JSD_GetSourceStatus(jsdc, jsdsrc);
|
|
gotSrc = JSD_GetSourceText(jsdc, jsdsrc, &text, &len );
|
|
|
|
dummy = 0; /* gives us a line to set breakpoint... */
|
|
}
|
|
}
|
|
#else
|
|
#define DEBUG_ITERATE_SOURCES(x) ((void)x)
|
|
#endif
|
|
|
|
/***************************************************************************/
|
|
|
|
JSDSourceText*
|
|
jsd_NewSourceText(JSDContext* jsdc, const char* url)
|
|
{
|
|
JSDSourceText* jsdsrc;
|
|
const char* new_url_string;
|
|
|
|
jsd_LockSourceTextSubsystem(jsdc);
|
|
|
|
new_url_string = jsd_BuildNormalizedURL(url);
|
|
if( ! new_url_string )
|
|
return NULL;
|
|
|
|
jsdsrc = jsd_FindSourceForURL(jsdc, new_url_string);
|
|
|
|
if( jsdsrc )
|
|
MoveSourceToRemovedList(jsdc, jsdsrc);
|
|
|
|
jsdsrc = AddSource( jsdc, new_url_string );
|
|
|
|
jsd_UnlockSourceTextSubsystem(jsdc);
|
|
|
|
return jsdsrc;
|
|
}
|
|
|
|
JSDSourceText*
|
|
jsd_AppendSourceText(JSDContext* jsdc,
|
|
JSDSourceText* jsdsrc,
|
|
const char* text, /* *not* zero terminated */
|
|
size_t length,
|
|
JSDSourceStatus status)
|
|
{
|
|
jsd_LockSourceTextSubsystem(jsdc);
|
|
|
|
if( ! IsSourceInSourceList( jsdc, jsdsrc ) )
|
|
{
|
|
RemoveSourceFromRemovedList( jsdc, jsdsrc );
|
|
jsd_UnlockSourceTextSubsystem(jsdc);
|
|
return NULL;
|
|
}
|
|
|
|
if( text && length && ! AppendText( jsdc, jsdsrc, text, length ) )
|
|
{
|
|
jsdsrc->dirty = JS_TRUE;
|
|
jsdsrc->alterCount = g_alterCount++ ;
|
|
jsdsrc->status = JSD_SOURCE_FAILED;
|
|
MoveSourceToRemovedList(jsdc, jsdsrc);
|
|
jsd_UnlockSourceTextSubsystem(jsdc);
|
|
return NULL;
|
|
}
|
|
|
|
jsdsrc->dirty = JS_TRUE;
|
|
jsdsrc->alterCount = g_alterCount++ ;
|
|
jsdsrc->status = status;
|
|
DEBUG_ITERATE_SOURCES(jsdc);
|
|
jsd_UnlockSourceTextSubsystem(jsdc);
|
|
return jsdsrc;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|