gecko-dev/js/jsd/jsd_text.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;
}
/***************************************************************************/