зеркало из https://github.com/mozilla/gecko-dev.git
Added rickg's tool for finding dereference errors
This commit is contained in:
Родитель
274a93def5
Коммит
c20dbf23de
|
@ -0,0 +1,88 @@
|
|||
/*================================================================*
|
||||
Copyright © 1998 Rick Gessner. All Rights Reserved.
|
||||
*================================================================*/
|
||||
|
||||
#include "CCPPTokenizer.h"
|
||||
#include "CScanner.h"
|
||||
#include "CToken.h"
|
||||
#include "tokens.h"
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
CCPPTokenizer::CCPPTokenizer() : mTokens(0) {
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* Process: Destroy the tokenizer
|
||||
* Usage:
|
||||
* Calls:
|
||||
* Notes:
|
||||
*********************************************************/
|
||||
CCPPTokenizer::~CCPPTokenizer() {
|
||||
CToken* theToken=0;
|
||||
while(theToken=(CToken*)mTokens.Pop()){
|
||||
delete theToken;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int consumeToken(CScanner& aScanner,CToken** aToken){
|
||||
static nsCAutoString gOperatorChars("/?.<>[]{}~^+=-!%&*(),|:");
|
||||
|
||||
PRUnichar theChar=0;
|
||||
int result=aScanner.getChar(theChar);
|
||||
if(kNoError==result){
|
||||
if((isspace(theChar)) || (theChar>=kSpace)) {
|
||||
if('#'==theChar)
|
||||
*aToken=(CToken*)new CCompilerDirectiveToken();
|
||||
else if((theChar=='_') || (isalpha(theChar)))
|
||||
*aToken=(CToken*)new CIdentifierToken();
|
||||
else if(isdigit(theChar))
|
||||
*aToken=(CToken*)new CNumberToken();
|
||||
else if((kLF==theChar) || (kCR==theChar))
|
||||
*aToken=(CToken*)new CNewlineToken();
|
||||
else if(isspace(theChar))
|
||||
*aToken=(CToken*)new CWhitespaceToken();
|
||||
else if(-1<gOperatorChars.Find(theChar)) {
|
||||
PRUnichar nextChar;
|
||||
aScanner.peek(nextChar);
|
||||
if((kForwardSlash==theChar) && ((kForwardSlash==nextChar) || (kAsterisk==nextChar))){
|
||||
*aToken=(CToken*)new CCommentToken(nextChar);
|
||||
}
|
||||
else *aToken=(CToken*)new COperatorToken();
|
||||
}
|
||||
else if((kQuote==theChar) || (kApostrophe==theChar))
|
||||
*aToken=(CToken*)new CQuotedStringToken();
|
||||
else if(kSemicolon==theChar) {
|
||||
*aToken=(CToken*)new CSemicolonToken();
|
||||
}
|
||||
if(*aToken){
|
||||
result=(*aToken)->consume(theChar,aScanner);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int CCPPTokenizer::tokenize(CScanner& aScanner){
|
||||
int result=0;
|
||||
while(kNoError==result){
|
||||
CToken* theToken=0;
|
||||
result=consumeToken(aScanner,&theToken);
|
||||
if(theToken) {
|
||||
//theToken->debugDumpSource(cout);
|
||||
mTokens.Push(theToken);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
CToken* CCPPTokenizer::getTokenAt(int anIndex){
|
||||
if((anIndex>=0) && (anIndex<mTokens.GetSize())){
|
||||
return (CToken*)mTokens.ObjectAt(anIndex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef _CTOKENIZER
|
||||
#define _CTOKENIZER
|
||||
|
||||
#include "sharedtypes.h"
|
||||
#include <typeinfo.h>
|
||||
#include "CScanner.h"
|
||||
#include "nsDeque.h"
|
||||
|
||||
class CToken;
|
||||
|
||||
class CCPPTokenizer {
|
||||
public:
|
||||
CCPPTokenizer();
|
||||
~CCPPTokenizer();
|
||||
|
||||
virtual int32 tokenize(CScanner& aScanner);
|
||||
|
||||
CToken* getTokenAt(int anIndex);
|
||||
int32 getCount() {return mTokens.GetSize();}
|
||||
protected:
|
||||
nsDeque mTokens;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
|
||||
|
||||
#include "IDirectory.h"
|
||||
#include "nsDeque.h"
|
||||
#include "nsString.h"
|
||||
#include "direct.h"
|
||||
#include "io.h"
|
||||
|
||||
/***************************************************************************************
|
||||
|
||||
***************************************************************************************/
|
||||
class CDirEntry : public IDirEntry {
|
||||
public:
|
||||
|
||||
CDirEntry(const nsCString& aName,IDirectory* aParent,int aAttrs,int aSize) : IDirEntry(), mName(aName){
|
||||
mAttributes=aAttrs;
|
||||
mParent=aParent;
|
||||
mSize=aSize;
|
||||
}
|
||||
|
||||
virtual CDirEntry::~CDirEntry() {
|
||||
}
|
||||
|
||||
virtual nsCString& getName(void){
|
||||
return mName;
|
||||
}
|
||||
|
||||
virtual IDirEntry* getParent(void){
|
||||
return mParent;
|
||||
}
|
||||
|
||||
virtual int getAttributes(void){
|
||||
return mAttributes;
|
||||
}
|
||||
|
||||
virtual int getSize(void){
|
||||
return mSize;
|
||||
}
|
||||
|
||||
virtual void getPath(nsCString& aString){
|
||||
if(mParent){
|
||||
mParent->getPath(aString);
|
||||
aString+='/';
|
||||
}
|
||||
aString+=mName;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCString mName;
|
||||
int mAttributes;
|
||||
int mSize;
|
||||
IDirectory* mParent;
|
||||
};
|
||||
|
||||
/***************************************************************************************
|
||||
|
||||
***************************************************************************************/
|
||||
class CDirectory : public IDirectory {
|
||||
public:
|
||||
|
||||
CDirectory(const nsCString& aName,const char* aFileSpec,IDirectory* aParent) :
|
||||
IDirectory(),
|
||||
mChildren(0),
|
||||
mName(aName),
|
||||
mFileSpec(aFileSpec)
|
||||
{
|
||||
mState=eUninitialized;
|
||||
mParent=aParent;
|
||||
}
|
||||
|
||||
virtual CDirectory::~CDirectory() {
|
||||
IDirEntry* theEntry=0;
|
||||
while(theEntry=(IDirEntry*)mChildren.Pop()) {
|
||||
delete theEntry;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @update gess 6/1/99
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
virtual nsCString& getName(void){
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @update gess 6/1/99
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
virtual IDirEntry* getParent(void){
|
||||
return mParent;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @update gess 6/1/99
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
virtual int getAttributes(void){
|
||||
return mAttributes;
|
||||
}
|
||||
|
||||
virtual int getSize(void){
|
||||
if(eUninitialized==mState){
|
||||
rescan();
|
||||
}
|
||||
return mChildren.GetSize();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @update gess 6/1/99
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
virtual void getPath(nsCString& aString){
|
||||
if(mParent){
|
||||
mParent->getPath(aString);
|
||||
aString+='/';
|
||||
}
|
||||
aString+=mName;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @update gess 6/1/99
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
virtual IDirEntry* getEntryAt(int anIndex){
|
||||
IDirEntry* result=0;
|
||||
|
||||
if(eUninitialized==mState){
|
||||
rescan();
|
||||
}
|
||||
|
||||
if(anIndex<mChildren.GetSize()){
|
||||
result=(IDirEntry*)mChildren.ObjectAt(anIndex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @update gess 6/1/99
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
virtual void rescan(void){
|
||||
mChildren.Erase();
|
||||
nsCAutoString thePath("");
|
||||
getPath(thePath);
|
||||
if(thePath.Length()){
|
||||
int result=_chdir(thePath.GetBuffer());
|
||||
if(!result){
|
||||
struct _finddata_t theFile;
|
||||
long hFile;
|
||||
if(-1!=(hFile=_findfirst(mFileSpec.GetBuffer(),&theFile))) {
|
||||
do {
|
||||
if('.'!=theFile.name[0]){
|
||||
nsCAutoString theName(theFile.name);
|
||||
IDirEntry* theEntry=0;
|
||||
if(theFile.attrib & _A_SUBDIR){
|
||||
theEntry=new CDirectory(theName,mFileSpec.GetBuffer(),this);
|
||||
}
|
||||
else {
|
||||
theEntry=new CDirEntry(theName,this,0,theFile.size);
|
||||
}
|
||||
mChildren.Push(theEntry);
|
||||
}
|
||||
} while(0==_findnext(hFile,&theFile));
|
||||
_findclose(hFile);
|
||||
}
|
||||
mState=eOk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
enum eDirState {eUninitialized,eOk,eNotADir};
|
||||
nsDeque mChildren;
|
||||
eDirState mState;
|
||||
IDirectory* mParent;
|
||||
int mSize;
|
||||
int mAttributes;
|
||||
nsCAutoString mName;
|
||||
nsCAutoString mFileSpec;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Ask the system to open a given directory, with given path
|
||||
* @update gess 6/1/99
|
||||
* @param aPath contains the path to directory you want opened
|
||||
* @return ptr to directory (if legal) or 0 if invalid path
|
||||
*/
|
||||
IDirectory* IDirectory::openDirectory(const nsCString& aPath,const char* aFileSpec){
|
||||
IDirectory* result=0;
|
||||
|
||||
nsCAutoString theCopy(aPath);
|
||||
theCopy.ReplaceChar('\\','/'); //replace all forward slashes with backslashes
|
||||
|
||||
if(0<theCopy.Length()){
|
||||
//by now, you have nothing but the actual directory name...
|
||||
//so let's go ask the OS to open the directory...
|
||||
int rv=_chdir(theCopy);
|
||||
if(!rv) {
|
||||
//if you're here, we successfully opened the directory...
|
||||
result=new CDirectory(theCopy,aFileSpec,0);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void IDirectory::closeDirectory(IDirectory* aDirectory){
|
||||
if(aDirectory) {
|
||||
CDirectory* theDir=(CDirectory*)aDirectory;
|
||||
delete theDir;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* Copyright (C) 1998 Rick Gessner. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include "CScanner.h"
|
||||
|
||||
const int kBufsize=1024;
|
||||
|
||||
|
||||
/**
|
||||
* Use this constructor if you want i/o to be stream based.
|
||||
*
|
||||
* @update gess 5/12/98
|
||||
* @param aStream --
|
||||
* @param assumeOwnership --
|
||||
* @param aFilename --
|
||||
* @return
|
||||
*/
|
||||
CScanner::CScanner(istream& aStream) : mBuffer(""), mFileStream(aStream) {
|
||||
mIncremental=true;
|
||||
mOffset=0;
|
||||
mTotalRead=0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* default destructor
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
CScanner::~CScanner() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab data from underlying stream.
|
||||
*
|
||||
* @update gess4/3/98
|
||||
* @return error code
|
||||
*/
|
||||
int CScanner::fillBuffer(void) {
|
||||
int anError=kNoError;
|
||||
|
||||
mBuffer="";
|
||||
if(!mFileStream) {
|
||||
//This is DEBUG code!!!!!! XXX DEBUG XXX
|
||||
//If you're here, it means someone tried to load a
|
||||
//non-existent document. So as a favor, we emit a
|
||||
//little bit of HTML explaining the error.
|
||||
anError=(mIncremental) ? kInterrupted : kEOF;
|
||||
}
|
||||
else {
|
||||
int numread=0;
|
||||
char buf[kBufsize+1];
|
||||
buf[kBufsize]=0;
|
||||
|
||||
if(mFileStream) {
|
||||
mFileStream.read(buf,kBufsize);
|
||||
numread=mFileStream.gcount();
|
||||
buf[numread]=0;
|
||||
}
|
||||
mOffset=0;
|
||||
if((0<numread) && (0==anError))
|
||||
mBuffer=buf;
|
||||
mTotalRead+=mBuffer.Length();
|
||||
}
|
||||
|
||||
return anError;
|
||||
}
|
||||
|
||||
/**
|
||||
* determine if the scanner has reached EOF
|
||||
*
|
||||
* @update gess 5/12/98
|
||||
* @param
|
||||
* @return 0=!eof 1=eof kInterrupted=interrupted
|
||||
*/
|
||||
int CScanner::endOfFile() {
|
||||
int theError=kNoError;
|
||||
|
||||
if(mOffset>=mBuffer.Length()) {
|
||||
theError=fillBuffer();
|
||||
}
|
||||
|
||||
if(kNoError==theError) {
|
||||
if (0==mBuffer.Length()) {
|
||||
return kEOF;
|
||||
}
|
||||
}
|
||||
|
||||
return theError;
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve next char from scanners internal input stream
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param
|
||||
* @return error code reflecting read status
|
||||
*/
|
||||
int CScanner::getChar(PRUnichar& aChar) {
|
||||
int result=kNoError;
|
||||
|
||||
if(mOffset>=mBuffer.Length())
|
||||
result=endOfFile();
|
||||
|
||||
if(kNoError == result) {
|
||||
aChar=mBuffer.CharAt(mOffset++);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* peek ahead to consume next char from scanner's internal
|
||||
* input buffer
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
int CScanner::peek(PRUnichar& aChar) {
|
||||
int result=kNoError;
|
||||
|
||||
if(mOffset>=mBuffer.Length())
|
||||
result=endOfFile();
|
||||
|
||||
if(kNoError == result) {
|
||||
aChar=mBuffer.CharAt(mOffset);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the given char back onto the scanner
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param
|
||||
* @return error code
|
||||
*/
|
||||
int CScanner::push(PRUnichar aChar) {
|
||||
if(mOffset>0)
|
||||
mOffset--;
|
||||
else {
|
||||
mBuffer.Insert(aChar,0);
|
||||
}
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Consume chars as long as they are <i>in</i> the
|
||||
* given validSet of input chars.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param
|
||||
* @return error code
|
||||
*/
|
||||
int CScanner::readWhile(nsCString& aString,nsCString& aValidSet,bool addTerminal){
|
||||
PRUnichar theChar=0;
|
||||
int result=kNoError;
|
||||
|
||||
while(kNoError==result) {
|
||||
result=getChar(theChar);
|
||||
if(kNoError==result) {
|
||||
int pos=aValidSet.Find(theChar);
|
||||
if(kNotFound==pos) {
|
||||
if(addTerminal)
|
||||
aString+=theChar;
|
||||
else push(theChar);
|
||||
break;
|
||||
}
|
||||
else aString+=theChar;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Consume characters until you find one contained in given
|
||||
* input set.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param
|
||||
* @return error code
|
||||
*/
|
||||
int CScanner::readUntil(nsCString& aString,nsCString& aTerminalSet,bool addTerminal){
|
||||
PRUnichar theChar=0;
|
||||
int result=kNoError;
|
||||
|
||||
while(kNoError == result) {
|
||||
result=getChar(theChar);
|
||||
if(kNoError==result) {
|
||||
int pos=aTerminalSet.Find(theChar);
|
||||
if(kNotFound!=pos) {
|
||||
if(addTerminal)
|
||||
aString+=theChar;
|
||||
else push(theChar);
|
||||
break;
|
||||
}
|
||||
else aString+=theChar;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Consumes chars until you see the given terminalChar
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param
|
||||
* @return error code
|
||||
*/
|
||||
int CScanner::readUntil(nsCString& aString, PRUnichar aTerminalChar, bool addTerminal) {
|
||||
PRUnichar ch=0;
|
||||
int result=kNoError;
|
||||
|
||||
while(kNoError==result) {
|
||||
result=getChar(ch);
|
||||
if(ch==aTerminalChar) {
|
||||
if(addTerminal)
|
||||
aString+=ch;
|
||||
else push(ch);
|
||||
break;
|
||||
}
|
||||
else aString+=ch;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (C) 1998 Rick Gessner. All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* MODULE NOTES:
|
||||
* @update gess 4/1/98
|
||||
*
|
||||
* The scanner is a low-level service class that knows
|
||||
* how to consume characters out of an (internal) stream.
|
||||
* This class also offers a series of utility methods
|
||||
* that most tokenizers want, such as readUntil(),
|
||||
* readWhile() and SkipWhitespace().
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CSCANNER_
|
||||
#define CSCANNER_
|
||||
|
||||
|
||||
#include "SharedTypes.h"
|
||||
#include "nsString.h"
|
||||
#include <fstream.h>
|
||||
|
||||
|
||||
class CScanner {
|
||||
public:
|
||||
|
||||
|
||||
/**
|
||||
* Use this constructor if you want i/o to be stream based.
|
||||
*
|
||||
* @update gess 5/12/98
|
||||
* @param aMode represents the parser mode (nav, other)
|
||||
* @return
|
||||
*/
|
||||
CScanner(istream& aStream);
|
||||
|
||||
|
||||
~CScanner();
|
||||
|
||||
/**
|
||||
* retrieve next char from internal input stream
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param ch is the char to accept new value
|
||||
* @return error code reflecting read status
|
||||
*/
|
||||
int getChar(PRUnichar& ch);
|
||||
|
||||
/**
|
||||
* peek ahead to consume next char from scanner's internal
|
||||
* input buffer
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param ch is the char to accept new value
|
||||
* @return error code reflecting read status
|
||||
*/
|
||||
int peek(PRUnichar& ch);
|
||||
|
||||
/**
|
||||
* Push the given char back onto the scanner
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param character to be pushed
|
||||
* @return error code
|
||||
*/
|
||||
int push(PRUnichar ch);
|
||||
|
||||
/**
|
||||
* Determine if the scanner has reached EOF.
|
||||
* This method can also cause the buffer to be filled
|
||||
* if it happens to be empty
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @return true upon eof condition
|
||||
*/
|
||||
int endOfFile(void);
|
||||
|
||||
/**
|
||||
* Consume characters until you find the terminal char
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aString receives new data from stream
|
||||
* @param aTerminal contains terminating char
|
||||
* @param addTerminal tells us whether to append terminal to aString
|
||||
* @return error code
|
||||
*/
|
||||
int readUntil(nsCString& aString,PRUnichar aTerminal,bool addTerminal);
|
||||
|
||||
/**
|
||||
* Consume characters until you find one contained in given
|
||||
* terminal set.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aString receives new data from stream
|
||||
* @param aTermSet contains set of terminating chars
|
||||
* @param addTerminal tells us whether to append terminal to aString
|
||||
* @return error code
|
||||
*/
|
||||
int readUntil(nsCString& aString,nsCString& aTermSet,bool addTerminal);
|
||||
|
||||
/**
|
||||
* Consume characters while they're members of anInputSet
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aString receives new data from stream
|
||||
* @param anInputSet contains valid chars
|
||||
* @param addTerminal tells us whether to append terminal to aString
|
||||
* @return error code
|
||||
*/
|
||||
int readWhile(nsCString& aString,nsCString& anInputSet,bool addTerminal);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Internal method used to cause the internal buffer to
|
||||
* be filled with data.
|
||||
*
|
||||
* @update gess4/3/98
|
||||
*/
|
||||
int fillBuffer(void);
|
||||
|
||||
|
||||
istream& mFileStream;
|
||||
nsCString mBuffer;
|
||||
int mOffset;
|
||||
int mTotalRead;
|
||||
bool mIncremental;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
/*================================================================*
|
||||
Copyright © 1998 Rick Gessner. All Rights Reserved.
|
||||
*================================================================*/
|
||||
|
||||
|
||||
#include "CToken.h"
|
||||
#include "CScanner.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
static int TokenCount=0;
|
||||
|
||||
|
||||
/**************************************************************
|
||||
And now for the CToken...
|
||||
**************************************************************/
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @update gess 7/21/98
|
||||
*/
|
||||
CToken::CToken(int aTag) : mTextValue() {
|
||||
mTypeID=aTag;
|
||||
mAttrCount=0;
|
||||
TokenCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with string for tagname assignment
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param nsCString--name of token
|
||||
*/
|
||||
CToken::CToken(const nsCString& aName) : mTextValue(aName) {
|
||||
mTypeID=0;
|
||||
mAttrCount=0;
|
||||
TokenCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor from char*
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aName--char* containing name of token
|
||||
*/
|
||||
CToken::CToken(const char* aName) : mTextValue(aName) {
|
||||
mTypeID=0;
|
||||
mAttrCount=0;
|
||||
TokenCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decstructor
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
*/
|
||||
CToken::~CToken() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method gets called when a token is about to be reused
|
||||
* for some other purpose. The token should initialize itself
|
||||
* to some reasonable default values.
|
||||
* @update gess7/25/98
|
||||
* @param aTag
|
||||
* @param aString
|
||||
*/
|
||||
void CToken::reinitialize(int aTag, const nsCString& aString){
|
||||
if(0==aString.Length())
|
||||
mTextValue.Truncate(0);
|
||||
else mTextValue.SetString(aString);
|
||||
mAttrCount=0;
|
||||
mTypeID=aTag;
|
||||
mAttrCount=0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual method used to tell this toke to consume his
|
||||
* valid chars.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aChar -- first char in sequence
|
||||
* @param aScanner -- object to retrieve data from
|
||||
* @return int error code
|
||||
*/
|
||||
int CToken::consume(PRUnichar aChar,CScanner& aScanner) {
|
||||
int result=kNoError;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This debug method causes the token to dump its content
|
||||
* to the given stream (formated for debugging).
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param ostream -- output stream to accept output data
|
||||
*/
|
||||
void CToken::debugDumpToken(ostream& anOutputStream) {
|
||||
anOutputStream << "[" << getClassName() << "] ";
|
||||
int i=0;
|
||||
for(i=0;i<mTextValue.Length();i++){
|
||||
anOutputStream << char(mTextValue.CharAt(i));
|
||||
}
|
||||
anOutputStream << ": " << mTypeID << endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* This debug method causes the token to dump its content
|
||||
* to the given stream, formated as text.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param ostream -- output stream to accept output data
|
||||
*/
|
||||
void CToken::debugDumpSource(ostream& anOutputStream) {
|
||||
char buf[256];
|
||||
mTextValue.ToCString(buf,sizeof(buf)-1);
|
||||
anOutputStream << buf << endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter method that changes the string value of this token
|
||||
* @update gess5/11/98
|
||||
* @param name is a char* value containing new string value
|
||||
*/
|
||||
void CToken::setStringValue(const char* name){
|
||||
mTextValue=name;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method retrieves the value of this internal string.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @return nsCString reference to internal string value
|
||||
*/
|
||||
nsCString& CToken::getStringValue(void) {
|
||||
return mTextValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve string value of the token
|
||||
* @update gess5/11/98
|
||||
* @return current int value for this token
|
||||
*/
|
||||
int CToken::getIntValue(int& anErrorCode){
|
||||
return mTextValue.ToInteger(&anErrorCode,10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve string value of the token
|
||||
* @update gess5/11/98
|
||||
* @return reference to string containing string value
|
||||
*/
|
||||
float CToken::getFloatValue(int& anErrorCode){
|
||||
return mTextValue.ToFloat(&anErrorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method retrieves the value of this internal string
|
||||
* as a nsCString.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @return char* rep of internal string value
|
||||
*/
|
||||
char* CToken::getStringValue(char* aBuffer, int aMaxLen) {
|
||||
strcpy(aBuffer,"string");
|
||||
return aBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the internal ordinal value for this token.
|
||||
* This method is deprecated, and will soon be going away.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param value -- new ordinal value for this token
|
||||
*/
|
||||
void CToken::setTypeID(int aTypeID) {
|
||||
mTypeID=aTypeID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves copy of internal ordinal value.
|
||||
* This method is deprecated, and will soon be going away.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @return int containing ordinal value
|
||||
*/
|
||||
int CToken::getTypeID(void) {
|
||||
return mTypeID;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the attribute count for this token
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param value -- new attr count
|
||||
*/
|
||||
void CToken::setAttributeCount(int value) {
|
||||
mAttrCount=value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves copy of attr count for this token
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @return int containing attribute count
|
||||
*/
|
||||
int CToken::getAttributeCount(void) {
|
||||
return mAttrCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve type of token. This class returns -1, but
|
||||
* subclasses return something more meaningful.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @return int value containing token type.
|
||||
*/
|
||||
int CToken::getTokenType(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve this tokens classname.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @return char* containing name of class
|
||||
*/
|
||||
const char* CToken::getClassName(void) {
|
||||
return "token";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
*/
|
||||
void CToken::selfTest(void) {
|
||||
#ifdef _debug
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
/*================================================================*
|
||||
Copyright © 1998 Rick Gessner. All Rights Reserved.
|
||||
*================================================================*/
|
||||
|
||||
|
||||
/**
|
||||
* MODULE NOTES:
|
||||
* @update gess 4/1/98
|
||||
*
|
||||
* This class is defines the basic notion of a token
|
||||
* within our system. All other tokens are derived from
|
||||
* this one. It offers a few basic interfaces, but the
|
||||
* most important is consume(). The consume() method gets
|
||||
* called during the tokenization process when an instance
|
||||
* of that particular token type gets detected in the
|
||||
* input stream.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CTOKEN__
|
||||
#define CTOKEN__
|
||||
|
||||
|
||||
#include "SharedTypes.h"
|
||||
#include "nsString.h"
|
||||
#include <iostream.h>
|
||||
#include "cscanner.h"
|
||||
|
||||
|
||||
/**
|
||||
* Token objects represent sequences of characters as they
|
||||
* are consumed from the input stream (URL). While they're
|
||||
* pretty general in nature, we use subclasses (found in
|
||||
* nsHTMLTokens.h) to define <start>, </end>, <text>,
|
||||
* <comment>, <&entity>, <newline>, and <whitespace> tokens.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
*/
|
||||
class CToken {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
* @update gess7/21/98
|
||||
*/
|
||||
CToken(int aTag=0);
|
||||
|
||||
/**
|
||||
* Constructor with string assignment for tag
|
||||
* @update gess5/11/98
|
||||
* @param aName is the given name of the token
|
||||
*/
|
||||
CToken(const nsCString& aName);
|
||||
|
||||
/**
|
||||
* constructor from char*
|
||||
* @update gess5/11/98
|
||||
* @param aName is the given name of the token
|
||||
*/
|
||||
CToken(const char* aName);
|
||||
|
||||
/**
|
||||
* destructor
|
||||
* @update gess5/11/98
|
||||
*/
|
||||
virtual ~CToken();
|
||||
|
||||
/**
|
||||
* This method gets called when a token is about to be reused
|
||||
* for some other purpose. The token should reinit itself to
|
||||
* some reasonable default values.
|
||||
* @update gess7/25/98
|
||||
* @param aTag
|
||||
* @param aString
|
||||
*/
|
||||
virtual void reinitialize(int aTag, const nsCString& aString);
|
||||
|
||||
/**
|
||||
* Retrieve string value of the token
|
||||
* @update gess5/11/98
|
||||
* @return reference to string containing string value
|
||||
*/
|
||||
virtual nsCString& getStringValue(void);
|
||||
|
||||
/**
|
||||
* Retrieve string value of the token
|
||||
* @update gess5/11/98
|
||||
* @return current int value for this token
|
||||
*/
|
||||
virtual int getIntValue(int& anErrorCode);
|
||||
|
||||
/**
|
||||
* Retrieve string value of the token
|
||||
* @update gess5/11/98
|
||||
* @return reference to string containing string value
|
||||
*/
|
||||
virtual float getFloatValue(int& anErrorCode);
|
||||
|
||||
/**
|
||||
* setter method that changes the string value of this token
|
||||
* @update gess5/11/98
|
||||
* @param name is a char* value containing new string value
|
||||
*/
|
||||
virtual void setStringValue(const char* name);
|
||||
|
||||
/**
|
||||
* Retrieve string value of the token as a c-string
|
||||
* @update gess5/11/98
|
||||
* @return reference to string containing string value
|
||||
*/
|
||||
virtual char* getStringValue(char* aBuffer, int aMaxLen);
|
||||
|
||||
/**
|
||||
* sets the ordinal value of this token (not currently used)
|
||||
* @update gess5/11/98
|
||||
* @param value is the new ord value for this token
|
||||
*/
|
||||
virtual void setTypeID(int aValue);
|
||||
|
||||
/**
|
||||
* getter which retrieves the current ordinal value for this token
|
||||
* @update gess5/11/98
|
||||
* @return current ordinal value
|
||||
*/
|
||||
virtual int getTypeID(void);
|
||||
|
||||
/**
|
||||
* sets the # of attributes found for this token.
|
||||
* @update gess5/11/98
|
||||
* @param value is the attr count
|
||||
*/
|
||||
virtual void setAttributeCount(int aValue);
|
||||
|
||||
/**
|
||||
* getter which retrieves the current attribute count for this token
|
||||
* @update gess5/11/98
|
||||
* @return current attribute count
|
||||
*/
|
||||
virtual int getAttributeCount(void);
|
||||
|
||||
/**
|
||||
* Causes token to consume data from given scanner.
|
||||
* Note that behavior varies wildly between CToken subclasses.
|
||||
* @update gess5/11/98
|
||||
* @param aChar -- most recent char consumed
|
||||
* @param aScanner -- input source where token should get data
|
||||
* @return error code (0 means ok)
|
||||
*/
|
||||
virtual int consume(PRUnichar aChar,CScanner& aScanner);
|
||||
|
||||
/**
|
||||
* Causes token to dump itself in debug form to given output stream
|
||||
* @update gess5/11/98
|
||||
* @param out is the output stream where token should write itself
|
||||
*/
|
||||
virtual void debugDumpToken(ostream& out);
|
||||
|
||||
/**
|
||||
* Causes token to dump itself in source form to given output stream
|
||||
* @update gess5/11/98
|
||||
* @param out is the output stream where token should write itself
|
||||
*/
|
||||
virtual void debugDumpSource(ostream& out);
|
||||
|
||||
/**
|
||||
* getter which retrieves type of token
|
||||
* @update gess5/11/98
|
||||
* @return int containing token type
|
||||
*/
|
||||
virtual int getTokenType(void);
|
||||
|
||||
/**
|
||||
* getter which retrieves the class name for this token
|
||||
* This method is only used for debug purposes.
|
||||
* @update gess5/11/98
|
||||
* @return const char* containing class name
|
||||
*/
|
||||
virtual const char* getClassName(void);
|
||||
|
||||
/**
|
||||
* perform self test.
|
||||
* @update gess5/11/98
|
||||
*/
|
||||
virtual void selfTest(void);
|
||||
|
||||
protected:
|
||||
int mTypeID;
|
||||
int mAttrCount;
|
||||
nsCAutoString mTextValue;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef _IDIRECTORY
|
||||
#define _IDIRECTORY
|
||||
|
||||
#include "sharedtypes.h"
|
||||
#include <typeinfo.h>
|
||||
|
||||
class nsCString;
|
||||
|
||||
class IDirEntry {
|
||||
public:
|
||||
virtual nsCString& getName(void)=0;
|
||||
virtual IDirEntry* getParent(void)=0;
|
||||
virtual int getAttributes(void)=0;
|
||||
virtual int getSize(void)=0;
|
||||
virtual void getPath(nsCString& aString)=0;
|
||||
};
|
||||
|
||||
class IDirectory : public IDirEntry {
|
||||
public:
|
||||
virtual IDirEntry* getEntryAt(int anIndex)=0;
|
||||
virtual void rescan(void)=0;
|
||||
|
||||
static IDirectory* openDirectory(const nsCString& aPath,const char* aFileSpec);
|
||||
static void closeDirectory(IDirectory* aDirectory);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*================================================================*
|
||||
Copyright © 1998 Rick Gessner. All Rights Reserved.
|
||||
*================================================================*/
|
||||
|
||||
#ifndef SHARED_TYPES__
|
||||
#define SHARED_TYPES__
|
||||
|
||||
|
||||
|
||||
const int kInterrupted = 10;
|
||||
const int kNoError = 0;
|
||||
|
||||
|
||||
const unsigned int kNewLine = '\n';
|
||||
const unsigned int kCR = '\r';
|
||||
const unsigned int kLF = '\n';
|
||||
const unsigned int kTab = '\t';
|
||||
const unsigned int kSpace = ' ';
|
||||
const unsigned int kQuote = '"';
|
||||
const unsigned int kApostrophe = '\'';
|
||||
const unsigned int kLessThan = '<';
|
||||
const unsigned int kGreaterThan = '>';
|
||||
const unsigned int kAmpersand = '&';
|
||||
const unsigned int kForwardSlash = '/';
|
||||
const unsigned int kBackSlash = '\\';
|
||||
const unsigned int kEqual = '=';
|
||||
const unsigned int kMinus = '-';
|
||||
const unsigned int kPlus = '+';
|
||||
const unsigned int kExclamation = '!';
|
||||
const unsigned int kSemicolon = ';';
|
||||
const unsigned int kPoundsign = '#';
|
||||
const unsigned int kAsterisk = '*';
|
||||
const unsigned int kUnderbar = '_';
|
||||
const unsigned int kComma = ',';
|
||||
const unsigned int kLeftParen = '(';
|
||||
const unsigned int kRightParen = ')';
|
||||
const unsigned int kLeftBrace = '{';
|
||||
const unsigned int kRightBrace = '}';
|
||||
const unsigned int kLeftBracket = '[';
|
||||
const unsigned int kRightBracket = ']';
|
||||
const unsigned int kColon = ':';
|
||||
const unsigned int kDot = '.';
|
||||
const unsigned int kVerticalBar = '|';
|
||||
const unsigned int kPercentage = '%';
|
||||
const unsigned int kTilde = '~';
|
||||
const unsigned int kQuestionMark = '?';
|
||||
const unsigned int kCaret = '^';
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,726 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
|
||||
/******************************************************************************************
|
||||
MODULE NOTES:
|
||||
|
||||
This file contains the workhorse copy and shift functions used in nsStrStruct.
|
||||
Ultimately, I plan to make the function pointers in this system available for
|
||||
use by external modules. They'll be able to install their own "handlers".
|
||||
Not so, today though.
|
||||
|
||||
*******************************************************************************************/
|
||||
|
||||
#ifndef _BUFFERROUTINES_H
|
||||
#define _BUFFERROUTINES_H
|
||||
|
||||
#include "nsCRT.h"
|
||||
|
||||
#ifndef TESTBED
|
||||
#include "nsUnicharUtilCIID.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsICaseConversion.h"
|
||||
#endif
|
||||
|
||||
#define KSHIFTLEFT (0)
|
||||
#define KSHIFTRIGHT (1)
|
||||
|
||||
|
||||
inline PRUnichar GetUnicharAt(const char* aString,PRUint32 anIndex) {
|
||||
return ((PRUnichar*)aString)[anIndex];
|
||||
}
|
||||
|
||||
inline PRUnichar GetCharAt(const char* aString,PRUint32 anIndex) {
|
||||
return (PRUnichar)aString[anIndex];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
//
|
||||
// This set of methods is used to shift the contents of a char buffer.
|
||||
// The functions are differentiated by shift direction and the underlying charsize.
|
||||
//
|
||||
|
||||
/**
|
||||
* This method shifts single byte characters left by a given amount from an given offset.
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is a ptr to a cstring where left-shift is to be performed
|
||||
* @param aLength is the known length of aDest
|
||||
* @param anOffset is the index into aDest where shifting shall begin
|
||||
* @param aCount is the number of chars to be "cut"
|
||||
*/
|
||||
void ShiftCharsLeft(char* aDest,PRUint32 aLength,PRUint32 anOffset,PRUint32 aCount) {
|
||||
//PRUint32 theMax=aLength-anOffset;
|
||||
//PRUint32 theLength=(theMax<aCount) ? theMax : aCount;
|
||||
|
||||
char* first= aDest+anOffset+aCount;
|
||||
char* last = aDest+aLength;
|
||||
char* to = aDest+anOffset;
|
||||
|
||||
//now loop over characters, shifting them left...
|
||||
while(first<=last) {
|
||||
*to=*first;
|
||||
to++;
|
||||
first++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method shifts single byte characters right by a given amount from an given offset.
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is a ptr to a cstring where the shift is to be performed
|
||||
* @param aLength is the known length of aDest
|
||||
* @param anOffset is the index into aDest where shifting shall begin
|
||||
* @param aCount is the number of chars to be "inserted"
|
||||
*/
|
||||
void ShiftCharsRight(char* aDest,PRUint32 aLength,PRUint32 anOffset,PRUint32 aCount) {
|
||||
char* last = aDest+aLength;
|
||||
char* first= aDest+anOffset-1;
|
||||
char* to = aDest+aLength+aCount;
|
||||
|
||||
//Copy rightmost chars, up to offset+theDelta...
|
||||
while(first<last) {
|
||||
*to=*last;
|
||||
to--;
|
||||
last--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method shifts unicode characters by a given amount from an given offset.
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is a ptr to a cstring where the shift is to be performed
|
||||
* @param aLength is the known length of aDest
|
||||
* @param anOffset is the index into aDest where shifting shall begin
|
||||
* @param aCount is the number of chars to be "cut"
|
||||
*/
|
||||
void ShiftDoubleCharsLeft(char* aDest,PRUint32 aLength,PRUint32 anOffset,PRUint32 aCount) {
|
||||
//PRUint32 theMax=aLength-anOffset;
|
||||
//PRUint32 theLength=(theMax<aCount) ? theMax : aCount;
|
||||
|
||||
PRUnichar* theBuf=(PRUnichar*)aDest;
|
||||
PRUnichar* first= theBuf+anOffset+aCount;
|
||||
PRUnichar* last = theBuf+aLength;
|
||||
PRUnichar* to = theBuf+anOffset;
|
||||
|
||||
//now loop over characters, shifting them left...
|
||||
while(first<=last) {
|
||||
*to=*first;
|
||||
to++;
|
||||
first++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method shifts unicode characters by a given amount from an given offset.
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is a ptr to a cstring where the shift is to be performed
|
||||
* @param aLength is the known length of aDest
|
||||
* @param anOffset is the index into aDest where shifting shall begin
|
||||
* @param aCount is the number of chars to be "inserted"
|
||||
*/
|
||||
void ShiftDoubleCharsRight(char* aDest,PRUint32 aLength,PRUint32 anOffset,PRUint32 aCount) {
|
||||
PRUnichar* theBuf=(PRUnichar*)aDest;
|
||||
PRUnichar* last = theBuf+aLength;
|
||||
PRUnichar* first= theBuf+anOffset-1;
|
||||
PRUnichar* to = theBuf+aLength+aCount;
|
||||
|
||||
//Copy rightmost chars, up to offset+theDelta...
|
||||
while(first<last) {
|
||||
*to=*last;
|
||||
to--;
|
||||
last--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef void (*ShiftChars)(char* aDest,PRUint32 aLength,PRUint32 anOffset,PRUint32 aCount);
|
||||
ShiftChars gShiftChars[2][2]= {
|
||||
{&ShiftCharsLeft,&ShiftCharsRight},
|
||||
{&ShiftDoubleCharsLeft,&ShiftDoubleCharsRight}
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
//
|
||||
// This set of methods is used to copy one buffer onto another.
|
||||
// The functions are differentiated by the size of source and dest character sizes.
|
||||
// WARNING: Your destination buffer MUST be big enough to hold all the source bytes.
|
||||
// We don't validate these ranges here (this should be done in higher level routines).
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* Going 1 to 1 is easy, since we assume ascii. No conversions are necessary.
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the destination buffer
|
||||
* @param aDestOffset is the pos to start copy to in the dest buffer
|
||||
* @param aSource is the source buffer
|
||||
* @param anOffset is the offset to start copying from in the source buffer
|
||||
* @param aCount is the (max) number of chars to copy
|
||||
*/
|
||||
void CopyChars1To1(char* aDest,PRInt32 anDestOffset,const char* aSource,PRUint32 anOffset,PRUint32 aCount) {
|
||||
|
||||
char* to = aDest+anDestOffset;
|
||||
const char* first= aSource+anOffset;
|
||||
const char* last = first+aCount;
|
||||
|
||||
//now loop over characters, shifting them left...
|
||||
while(first<last) {
|
||||
*to=*first;
|
||||
to++;
|
||||
first++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Going 1 to 2 requires a conversion from ascii to unicode. This can be expensive.
|
||||
* @param aDest is the destination buffer
|
||||
* @param aDestOffset is the pos to start copy to in the dest buffer
|
||||
* @param aSource is the source buffer
|
||||
* @param anOffset is the offset to start copying from in the source buffer
|
||||
* @param aCount is the (max) number of chars to copy
|
||||
*/
|
||||
void CopyChars1To2(char* aDest,PRInt32 anDestOffset,const char* aSource,PRUint32 anOffset,PRUint32 aCount) {
|
||||
|
||||
PRUnichar* theDest=(PRUnichar*)aDest;
|
||||
PRUnichar* to = theDest+anDestOffset;
|
||||
const unsigned char* first= (const unsigned char*)aSource+anOffset;
|
||||
const unsigned char* last = first+aCount;
|
||||
|
||||
//now loop over characters, shifting them left...
|
||||
while(first<last) {
|
||||
*to=(PRUnichar)(*first);
|
||||
to++;
|
||||
first++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Going 2 to 1 requires a conversion from unicode down to ascii. This can be lossy.
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the destination buffer
|
||||
* @param aDestOffset is the pos to start copy to in the dest buffer
|
||||
* @param aSource is the source buffer
|
||||
* @param anOffset is the offset to start copying from in the source buffer
|
||||
* @param aCount is the (max) number of chars to copy
|
||||
*/
|
||||
void CopyChars2To1(char* aDest,PRInt32 anDestOffset,const char* aSource,PRUint32 anOffset,PRUint32 aCount) {
|
||||
char* to = aDest+anDestOffset;
|
||||
PRUnichar* theSource=(PRUnichar*)aSource;
|
||||
const PRUnichar* first= theSource+anOffset;
|
||||
const PRUnichar* last = first+aCount;
|
||||
|
||||
//now loop over characters, shifting them left...
|
||||
while(first<last) {
|
||||
if(*first<256)
|
||||
*to=(char)*first;
|
||||
else *to='.';
|
||||
to++;
|
||||
first++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Going 2 to 2 is fast and efficient.
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the destination buffer
|
||||
* @param aDestOffset is the pos to start copy to in the dest buffer
|
||||
* @param aSource is the source buffer
|
||||
* @param anOffset is the offset to start copying from in the source buffer
|
||||
* @param aCount is the (max) number of chars to copy
|
||||
*/
|
||||
void CopyChars2To2(char* aDest,PRInt32 anDestOffset,const char* aSource,PRUint32 anOffset,PRUint32 aCount) {
|
||||
PRUnichar* theDest=(PRUnichar*)aDest;
|
||||
PRUnichar* to = theDest+anDestOffset;
|
||||
PRUnichar* theSource=(PRUnichar*)aSource;
|
||||
PRUnichar* from= theSource+anOffset;
|
||||
|
||||
memcpy((void*)to,(void*)from,aCount*2);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
typedef void (*CopyChars)(char* aDest,PRInt32 anDestOffset,const char* aSource,PRUint32 anOffset,PRUint32 aCount);
|
||||
|
||||
CopyChars gCopyChars[2][2]={
|
||||
{&CopyChars1To1,&CopyChars1To2},
|
||||
{&CopyChars2To1,&CopyChars2To2}
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
//
|
||||
// This set of methods is used to search a buffer looking for a char.
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* This methods cans the given buffer for the given char
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aDest is the buffer to be searched
|
||||
* @param aLength is the size (in char-units, not bytes) of the buffer
|
||||
* @param anOffset is the start pos to begin searching
|
||||
* @param aChar is the target character we're looking for
|
||||
* @param aIgnorecase tells us whether to use a case sensitive search
|
||||
* @return index of pos if found, else -1 (kNotFound)
|
||||
*/
|
||||
inline PRInt32 FindChar1(const char* aDest,PRUint32 aLength,PRUint32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase) {
|
||||
PRInt32 theIndex=0;
|
||||
PRInt32 theLength=(PRInt32)aLength;
|
||||
|
||||
if(aIgnoreCase) {
|
||||
PRUnichar theChar=nsCRT::ToUpper(aChar);
|
||||
for(theIndex=(PRInt32)anOffset;theIndex<theLength;theIndex++){
|
||||
if(nsCRT::ToUpper(aDest[theIndex])==theChar)
|
||||
return theIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(theIndex=(PRInt32)anOffset;theIndex<theLength;theIndex++){
|
||||
if(aDest[theIndex]==aChar)
|
||||
return theIndex;
|
||||
}
|
||||
}
|
||||
return kNotFound;
|
||||
}
|
||||
|
||||
/**
|
||||
* This methods cans the given buffer for the given char
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aDest is the buffer to be searched
|
||||
* @param aLength is the size (in char-units, not bytes) of the buffer
|
||||
* @param anOffset is the start pos to begin searching
|
||||
* @param aChar is the target character we're looking for
|
||||
* @param aIgnorecase tells us whether to use a case sensitive search
|
||||
* @return index of pos if found, else -1 (kNotFound)
|
||||
*/
|
||||
inline PRInt32 FindChar2(const char* aDest,PRUint32 aLength,PRUint32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase) {
|
||||
PRInt32 theIndex=0;
|
||||
PRInt32 theLength=(PRInt32)aLength;
|
||||
PRUnichar* theBuf=(PRUnichar*)aDest;
|
||||
|
||||
if(aIgnoreCase) {
|
||||
PRUnichar theChar=nsCRT::ToUpper(aChar);
|
||||
for(theIndex=(PRInt32)anOffset;theIndex<theLength;theIndex++){
|
||||
if(nsCRT::ToUpper(theBuf[theIndex])==theChar)
|
||||
return theIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(theIndex=(PRInt32)anOffset;theIndex<theLength;theIndex++){
|
||||
if(theBuf[theIndex]==aChar)
|
||||
return theIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return kNotFound;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This methods cans the given buffer (in reverse) for the given char
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aDest is the buffer to be searched
|
||||
* @param aLength is the size (in char-units, not bytes) of the buffer
|
||||
* @param anOffset is the start pos to begin searching
|
||||
* @param aChar is the target character we're looking for
|
||||
* @param aIgnorecase tells us whether to use a case sensitive search
|
||||
* @return index of pos if found, else -1 (kNotFound)
|
||||
*/
|
||||
inline PRInt32 RFindChar1(const char* aDest,PRUint32 aDestLength,PRUint32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase) {
|
||||
PRInt32 theIndex=0;
|
||||
|
||||
if(aIgnoreCase) {
|
||||
PRUnichar theChar=nsCRT::ToUpper(aChar);
|
||||
for(theIndex=(PRInt32)anOffset;theIndex>=0;theIndex--){
|
||||
if(nsCRT::ToUpper(aDest[theIndex])==theChar)
|
||||
return theIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(theIndex=(PRInt32)anOffset;theIndex>=0;theIndex--){
|
||||
if(aDest[theIndex]==aChar)
|
||||
return theIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return kNotFound;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This methods cans the given buffer for the given char
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aDest is the buffer to be searched
|
||||
* @param aLength is the size (in char-units, not bytes) of the buffer
|
||||
* @param anOffset is the start pos to begin searching
|
||||
* @param aChar is the target character we're looking for
|
||||
* @param aIgnorecase tells us whether to use a case sensitive search
|
||||
* @return index of pos if found, else -1 (kNotFound)
|
||||
*/
|
||||
inline PRInt32 RFindChar2(const char* aDest,PRUint32 aDestLength,PRUint32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase) {
|
||||
|
||||
PRInt32 theIndex=0;
|
||||
PRUnichar* theBuf=(PRUnichar*)aDest;
|
||||
|
||||
if(aIgnoreCase) {
|
||||
PRUnichar theChar=nsCRT::ToUpper(aChar);
|
||||
for(theIndex=(PRInt32)anOffset;theIndex>=0;theIndex--){
|
||||
if(nsCRT::ToUpper(theBuf[theIndex])==theChar)
|
||||
return theIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(theIndex=(PRInt32)anOffset;theIndex>=0;theIndex--){
|
||||
if(theBuf[theIndex]==aChar)
|
||||
return theIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return kNotFound;
|
||||
}
|
||||
|
||||
typedef PRInt32 (*FindChars)(const char* aDest,PRUint32 aDestLength,PRUint32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase);
|
||||
FindChars gFindChars[]={&FindChar1,&FindChar2};
|
||||
FindChars gRFindChars[]={&RFindChar1,&RFindChar2};
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
//
|
||||
// This set of methods is used to compare one buffer onto another.
|
||||
// The functions are differentiated by the size of source and dest character sizes.
|
||||
// WARNING: Your destination buffer MUST be big enough to hold all the source bytes.
|
||||
// We don't validate these ranges here (this should be done in higher level routines).
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* This method compares the data in one buffer with another
|
||||
* @update gess 01/04/99
|
||||
* @param aStr1 is the first buffer to be compared
|
||||
* @param aStr2 is the 2nd buffer to be compared
|
||||
* @param aCount is the number of chars to compare
|
||||
* @param aIgnorecase tells us whether to use a case-sensitive comparison
|
||||
* @return -1,0,1 depending on <,==,>
|
||||
*/
|
||||
PRInt32 Compare1To1(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
|
||||
PRInt32 result=0;
|
||||
if(aIgnoreCase)
|
||||
result=nsCRT::strncasecmp(aStr1,aStr2,aCount);
|
||||
else result=strncmp(aStr1,aStr2,aCount);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method compares the data in one buffer with another
|
||||
* @update gess 01/04/99
|
||||
* @param aStr1 is the first buffer to be compared
|
||||
* @param aStr2 is the 2nd buffer to be compared
|
||||
* @param aCount is the number of chars to compare
|
||||
* @param aIgnorecase tells us whether to use a case-sensitive comparison
|
||||
* @return -1,0,1 depending on <,==,>
|
||||
*/
|
||||
PRInt32 Compare2To2(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
|
||||
PRInt32 result=0;
|
||||
if(aIgnoreCase)
|
||||
result=nsCRT::strncasecmp((PRUnichar*)aStr1,(PRUnichar*)aStr2,aCount);
|
||||
else result=nsCRT::strncmp((PRUnichar*)aStr1,(PRUnichar*)aStr2,aCount);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method compares the data in one buffer with another
|
||||
* @update gess 01/04/99
|
||||
* @param aStr1 is the first buffer to be compared
|
||||
* @param aStr2 is the 2nd buffer to be compared
|
||||
* @param aCount is the number of chars to compare
|
||||
* @param aIgnorecase tells us whether to use a case-sensitive comparison
|
||||
* @return -1,0,1 depending on <,==,>
|
||||
*/
|
||||
PRInt32 Compare2To1(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
|
||||
PRInt32 result;
|
||||
if(aIgnoreCase)
|
||||
result=nsCRT::strncasecmp((PRUnichar*)aStr1,aStr2,aCount);
|
||||
else result=nsCRT::strncmp((PRUnichar*)aStr1,aStr2,aCount);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method compares the data in one buffer with another
|
||||
* @update gess 01/04/99
|
||||
* @param aStr1 is the first buffer to be compared
|
||||
* @param aStr2 is the 2nd buffer to be compared
|
||||
* @param aCount is the number of chars to compare
|
||||
* @param aIgnorecase tells us whether to use a case-sensitive comparison
|
||||
* @return -1,0,1 depending on <,==,>
|
||||
*/
|
||||
PRInt32 Compare1To2(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
|
||||
PRInt32 result;
|
||||
if(aIgnoreCase)
|
||||
result=nsCRT::strncasecmp((PRUnichar*)aStr2,aStr1,aCount)*-1;
|
||||
else result=nsCRT::strncmp((PRUnichar*)aStr2,aStr1,aCount)*-1;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
typedef PRInt32 (*CompareChars)(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase);
|
||||
CompareChars gCompare[2][2]={
|
||||
{&Compare1To1,&Compare1To2},
|
||||
{&Compare2To1,&Compare2To2},
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
//
|
||||
// This set of methods is used to convert the case of strings...
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* This method performs a case conversion the data in the given buffer
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aString is the buffer to be case shifted
|
||||
* @param aCount is the number of chars to compare
|
||||
* @param aToUpper tells us whether to convert to upper or lower
|
||||
* @return 0
|
||||
*/
|
||||
PRInt32 ConvertCase1(char* aString,PRUint32 aCount,PRBool aToUpper){
|
||||
PRInt32 result=0;
|
||||
|
||||
typedef char chartype;
|
||||
chartype* cp = (chartype*)aString;
|
||||
chartype* end = cp + aCount-1;
|
||||
while (cp <= end) {
|
||||
chartype ch = *cp;
|
||||
if(aToUpper) {
|
||||
if ((ch >= 'a') && (ch <= 'z')) {
|
||||
*cp = 'A' + (ch - 'a');
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((ch >= 'A') && (ch <= 'Z')) {
|
||||
*cp = 'a' + (ch - 'A');
|
||||
}
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
#ifndef TESTBED
|
||||
class HandleCaseConversionShutdown3 : public nsIShutdownListener {
|
||||
public :
|
||||
NS_IMETHOD OnShutdown(const nsCID& cid, nsISupports* service);
|
||||
HandleCaseConversionShutdown3(void) { NS_INIT_REFCNT(); }
|
||||
virtual ~HandleCaseConversionShutdown3(void) {}
|
||||
NS_DECL_ISUPPORTS
|
||||
};
|
||||
|
||||
static NS_DEFINE_CID(kUnicharUtilCID, NS_UNICHARUTIL_CID);
|
||||
static NS_DEFINE_IID(kICaseConversionIID, NS_ICASECONVERSION_IID);
|
||||
static NS_DEFINE_IID(kIShutdownListenerIID, NS_ISHUTDOWNLISTENER_IID);
|
||||
static nsICaseConversion * gCaseConv = 0;
|
||||
|
||||
NS_IMPL_ISUPPORTS(HandleCaseConversionShutdown3, kIShutdownListenerIID);
|
||||
|
||||
nsresult HandleCaseConversionShutdown3::OnShutdown(const nsCID& cid, nsISupports* service) {
|
||||
if (cid.Equals(kUnicharUtilCID)) {
|
||||
NS_ASSERTION(service == gCaseConv, "wrong service!");
|
||||
if(gCaseConv){
|
||||
gCaseConv->Release();
|
||||
gCaseConv = 0;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
class CCaseConversionServiceInitializer {
|
||||
public:
|
||||
CCaseConversionServiceInitializer(){
|
||||
mListener = new HandleCaseConversionShutdown3();
|
||||
if(mListener){
|
||||
mListener->AddRef();
|
||||
nsServiceManager::GetService(kUnicharUtilCID, kICaseConversionIID,(nsISupports**) &gCaseConv, mListener);
|
||||
}
|
||||
}
|
||||
protected:
|
||||
HandleCaseConversionShutdown3* mListener;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This method performs a case conversion the data in the given buffer
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aString is the buffer to be case shifted
|
||||
* @param aCount is the number of chars to compare
|
||||
* @param aToUpper tells us whether to convert to upper or lower
|
||||
* @return 0
|
||||
*/
|
||||
PRInt32 ConvertCase2(char* aString,PRUint32 aCount,PRBool aToUpper){
|
||||
PRUnichar* cp = (PRUnichar*)aString;
|
||||
PRUnichar* end = cp + aCount-1;
|
||||
PRInt32 result=0;
|
||||
|
||||
#ifndef TESTBED
|
||||
static CCaseConversionServiceInitializer gCaseConversionServiceInitializer;
|
||||
|
||||
// I18N code begin
|
||||
if(gCaseConv) {
|
||||
nsresult err=(aToUpper) ? gCaseConv->ToUpper(cp, cp, aCount) : gCaseConv->ToLower(cp, cp, aCount);
|
||||
if(NS_SUCCEEDED(err))
|
||||
return 0;
|
||||
}
|
||||
// I18N code end
|
||||
#endif
|
||||
|
||||
|
||||
while (cp <= end) {
|
||||
PRUnichar ch = *cp;
|
||||
if(aToUpper) {
|
||||
if ((ch >= 'a') && (ch <= 'z')) {
|
||||
*cp = 'A' + (ch - 'a');
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((ch >= 'A') && (ch <= 'Z')) {
|
||||
*cp = 'a' + (ch - 'A');
|
||||
}
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef PRInt32 (*CaseConverters)(char*,PRUint32,PRBool);
|
||||
CaseConverters gCaseConverters[]={&ConvertCase1,&ConvertCase2};
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
//
|
||||
// This set of methods is used compress char sequences in a buffer...
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* This method compresses duplicate runs of a given char from the given buffer
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aString is the buffer to be manipulated
|
||||
* @param aLength is the length of the buffer
|
||||
* @param aSet tells us which chars to compress from given buffer
|
||||
* @param aEliminateLeading tells us whether to strip chars from the start of the buffer
|
||||
* @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
|
||||
* @return the new length of the given buffer
|
||||
*/
|
||||
PRInt32 CompressChars1(char* aString,PRUint32 aLength,const char* aSet){
|
||||
|
||||
typedef char chartype;
|
||||
chartype* from = aString;
|
||||
chartype* end = aString + aLength-1;
|
||||
chartype* to = from;
|
||||
|
||||
//this code converts /n, /t, /r into normal space ' ';
|
||||
//it also compresses runs of whitespace down to a single char...
|
||||
if(aSet){
|
||||
PRUint32 aSetLen=strlen(aSet);
|
||||
while (from <= end) {
|
||||
chartype theChar = *from++;
|
||||
if(kNotFound!=FindChar1(aSet,aSetLen,0,theChar,PR_FALSE)){
|
||||
*to++=theChar;
|
||||
while (from <= end) {
|
||||
theChar = *from++;
|
||||
if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,PR_FALSE)){
|
||||
*to++ = theChar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*to++ = theChar;
|
||||
}
|
||||
}
|
||||
*to = 0;
|
||||
}
|
||||
return to - (chartype*)aString;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method compresses duplicate runs of a given char from the given buffer
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aString is the buffer to be manipulated
|
||||
* @param aLength is the length of the buffer
|
||||
* @param aSet tells us which chars to compress from given buffer
|
||||
* @param aEliminateLeading tells us whether to strip chars from the start of the buffer
|
||||
* @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
|
||||
* @return the new length of the given buffer
|
||||
*/
|
||||
PRInt32 CompressChars2(char* aString,PRUint32 aLength,const char* aSet){
|
||||
|
||||
typedef PRUnichar chartype;
|
||||
chartype* from = (chartype*)aString;
|
||||
chartype* end = from + aLength-1;
|
||||
chartype* to = from;
|
||||
|
||||
//this code converts /n, /t, /r into normal space ' ';
|
||||
//it also compresses runs of whitespace down to a single char...
|
||||
if(aSet){
|
||||
PRUint32 aSetLen=strlen(aSet);
|
||||
while (from <= end) {
|
||||
chartype theChar = *from++;
|
||||
if(kNotFound!=FindChar1(aSet,aSetLen,0,theChar,PR_FALSE)){
|
||||
*to++=theChar;
|
||||
while (from <= end) {
|
||||
theChar = *from++;
|
||||
if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,PR_FALSE)){
|
||||
*to++ = theChar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*to++ = theChar;
|
||||
}
|
||||
}
|
||||
*to = 0;
|
||||
}
|
||||
return to - (chartype*)aString;
|
||||
}
|
||||
|
||||
typedef PRInt32 (*CompressChars)(char* aString,PRUint32 aCount,const char* aSet);
|
||||
CompressChars gCompressChars[]={&CompressChars1,&CompressChars2};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,628 @@
|
|||
#include <iostream.h>
|
||||
#include <fstream.h>
|
||||
#include "nsString.h"
|
||||
#include "IDirectory.h"
|
||||
#include "CScanner.h"
|
||||
#include "CCPPTokenizer.h"
|
||||
#include "tokens.h"
|
||||
#include "CToken.h"
|
||||
#include <direct.h>
|
||||
|
||||
//*******************************************************************************
|
||||
// Global variables...
|
||||
//*******************************************************************************
|
||||
bool gVerbose=false;
|
||||
bool gShowIncludeErrors=false;
|
||||
bool gEmitHTML=false;
|
||||
char gRootDir[1024];
|
||||
|
||||
|
||||
class IPattern {
|
||||
public:
|
||||
virtual CToken* scan(CCPPTokenizer& aTokenizer,int anIndex,ostream& anOutput)=0;
|
||||
};
|
||||
|
||||
|
||||
class CPattern {
|
||||
public:
|
||||
CPattern(const nsCString& aFilename) : mNames(0), mFilename(aFilename), mSafeNames(0) {
|
||||
mIndex=0;
|
||||
mLineNumber=1;
|
||||
mErrCount=0;
|
||||
}
|
||||
|
||||
CToken* matchID(nsDeque& aDeque,nsCString& aName){
|
||||
int theMax=aDeque.GetSize();
|
||||
for(int theIndex=0;theIndex<theMax;theIndex++){
|
||||
CToken* theToken=(CToken*)aDeque.ObjectAt(theIndex);
|
||||
if(theToken){
|
||||
nsCString& theName=theToken->getStringValue();
|
||||
if(theName==aName) {
|
||||
return theToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
This gets called when we know we've seen an if statement (at anIndex).
|
||||
Look into the parm list (...) for an ID. If you find one, then you know
|
||||
it's a conditioned identifier which can be safely ignored during other
|
||||
error tests.
|
||||
***************************************************************************/
|
||||
CToken* findSafeIDInIfStatement(CCPPTokenizer& aTokenizer,nsDeque& aNameDeque) {
|
||||
CToken* result=0;
|
||||
|
||||
enum eState {eSkipLparen,eFindID};
|
||||
eState theState=eSkipLparen;
|
||||
CToken* theToken=0;
|
||||
while(theToken=aTokenizer.getTokenAt(++mIndex)) {
|
||||
int theType=theToken->getTokenType();
|
||||
nsCString& theString=theToken->getStringValue();
|
||||
PRUnichar theChar=theString[0];
|
||||
|
||||
switch(theState) {
|
||||
case eSkipLparen:
|
||||
//first scan for the lparen...
|
||||
switch(theType) {
|
||||
case eToken_comment:
|
||||
case eToken_whitespace:
|
||||
case eToken_newline:
|
||||
mLineNumber+=theString.CountChar('\n'); break;
|
||||
|
||||
case eToken_operator:
|
||||
switch(theChar) {
|
||||
case '(': theState=eFindID; break;
|
||||
case ')': return 0; break;
|
||||
default:
|
||||
break;
|
||||
} //switch
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
} //switch
|
||||
break;
|
||||
|
||||
//now scan for the identifier...
|
||||
case eFindID:
|
||||
switch(theType) {
|
||||
case eToken_comment:
|
||||
case eToken_whitespace:
|
||||
case eToken_newline:
|
||||
mLineNumber+=theString.CountChar('\n'); break;
|
||||
|
||||
case eToken_identifier:
|
||||
if(matchID(mNames,theString)) {
|
||||
return theToken;
|
||||
}
|
||||
break;
|
||||
case eToken_operator:
|
||||
switch(theChar) {
|
||||
case ')':
|
||||
case ';':
|
||||
case '{':
|
||||
case '(':
|
||||
return result;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
} //switch
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
} //switch
|
||||
break;
|
||||
|
||||
default:
|
||||
switch(theType) {
|
||||
case eToken_comment:
|
||||
case eToken_whitespace:
|
||||
case eToken_newline:
|
||||
mLineNumber+=theString.CountChar('\n');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}//switch
|
||||
break;
|
||||
} //switch
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
We're looking for the pattern foo-> without the preceeding (conditional) if():
|
||||
Assume that the given id (aName) exists in the tokenizer at anIndex.
|
||||
|
||||
if(foo)
|
||||
foo->
|
||||
***************************************************************************/
|
||||
CToken* findPtrDecl(CCPPTokenizer& aTokenizer,int anIndex,PRUnichar& anOpChar,bool allocRequired) {
|
||||
|
||||
enum eState {eFindNew,eFindType,eFindPunct,eFindStar};
|
||||
CToken* theToken=0;
|
||||
CToken* theID=0;
|
||||
eState theState=eFindStar;
|
||||
|
||||
while(theToken=aTokenizer.getTokenAt(++anIndex)){
|
||||
if(theToken) {
|
||||
nsCString& theString=theToken->getStringValue();
|
||||
int theType=theToken->getTokenType();
|
||||
|
||||
anOpChar=theString[0];
|
||||
switch(theType){
|
||||
|
||||
case eToken_semicolon:
|
||||
case eToken_operator:
|
||||
switch(theState) {
|
||||
case eFindStar:
|
||||
if('*'==anOpChar)
|
||||
theState=eFindType;
|
||||
else return 0;
|
||||
break;
|
||||
case eFindPunct:
|
||||
switch(anOpChar) {
|
||||
case '=':
|
||||
if(!allocRequired)
|
||||
return theID;
|
||||
else theState=eFindNew;
|
||||
break;
|
||||
case ';':
|
||||
return (allocRequired) ? 0 : theID;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case eToken_identifier:
|
||||
switch(theState){
|
||||
case eFindType:
|
||||
theID=theToken;
|
||||
theState=eFindPunct;
|
||||
break;
|
||||
case eFindNew:
|
||||
if(theString.Equals("new") || theString.Equals("PR_Malloc"))
|
||||
return theID;
|
||||
else return 0;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}//if
|
||||
}//while
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
We're looking for the pattern *foo.
|
||||
***************************************************************************/
|
||||
bool hasSimpleDeref(nsCString& aName,CCPPTokenizer& aTokenizer,int anIndex) {
|
||||
bool result=false;
|
||||
|
||||
int theMin=anIndex-3;
|
||||
for(int theIndex=anIndex-1;theIndex>theMin;theIndex--){
|
||||
CToken* theToken=aTokenizer.getTokenAt(theIndex);
|
||||
if(theToken) {
|
||||
nsCString& theString=theToken->getStringValue();
|
||||
int theType=theToken->getTokenType();
|
||||
PRUnichar theChar=theString[0];
|
||||
if(eToken_operator==theType) {
|
||||
if('*'==theChar){
|
||||
result=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(result) {
|
||||
int theMax=anIndex+3;
|
||||
for(int theIndex=anIndex;theIndex<theMax;theIndex++){
|
||||
CToken* theToken=aTokenizer.getTokenAt(theIndex);
|
||||
if(theToken) {
|
||||
nsCString& theString=theToken->getStringValue();
|
||||
int theType=theToken->getTokenType();
|
||||
PRUnichar theChar=theString[0];
|
||||
if(eToken_operator==theType) {
|
||||
if((','==theChar) || (')'==theChar)){
|
||||
result=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
We're looking for the pattern foo-> without the preceeding (conditional) if():
|
||||
Assume that the given id (aName) exists in the tokenizer at anIndex.
|
||||
|
||||
if(foo)
|
||||
foo->
|
||||
***************************************************************************/
|
||||
bool hasUnconditionedDeref(nsCString& aName,CCPPTokenizer& aTokenizer,int anIndex) {
|
||||
bool result=false;
|
||||
|
||||
enum eState {eFailure,eFindIf,eFindDeref};
|
||||
CToken* theToken=0;
|
||||
eState theState=eFindDeref;
|
||||
int theIndex=anIndex+1;
|
||||
|
||||
while(eFailure!=theState){
|
||||
CToken* theToken=aTokenizer.getTokenAt(theIndex);
|
||||
if(theToken) {
|
||||
nsCString& theString=theToken->getStringValue();
|
||||
int theType=theToken->getTokenType();
|
||||
PRUnichar theChar=theString[0];
|
||||
switch(theState){
|
||||
case eFindDeref:
|
||||
switch(theType) {
|
||||
case eToken_whitespace:
|
||||
case eToken_comment:
|
||||
case eToken_newline:
|
||||
theIndex++;
|
||||
break;
|
||||
default:
|
||||
if(0==theString.Compare("->",true,2)) {
|
||||
theIndex=anIndex-1; //now start looking backwards...
|
||||
theState=eFindIf;
|
||||
}
|
||||
else theState=eFailure;
|
||||
}//switch
|
||||
break;
|
||||
|
||||
case eFindIf:
|
||||
switch(theType) {
|
||||
case eToken_whitespace:
|
||||
case eToken_comment:
|
||||
case eToken_newline:
|
||||
theIndex--;
|
||||
break;
|
||||
case eToken_semicolon:
|
||||
return true;
|
||||
break;
|
||||
|
||||
case eToken_operator:
|
||||
switch(theChar){
|
||||
case '{':
|
||||
case '+':
|
||||
case '-':
|
||||
case '=':
|
||||
case '*':
|
||||
case '%':
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
theIndex-=1;
|
||||
break;
|
||||
case eToken_identifier:
|
||||
if(0==theString.Compare("if",true,2)){
|
||||
return false;
|
||||
}
|
||||
else if(0==theString.Compare(aName)){
|
||||
return false;
|
||||
}
|
||||
else if(0==theString.Compare("while",true,5)){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
theIndex--;
|
||||
} //switch
|
||||
break;
|
||||
}//switch
|
||||
}//if
|
||||
else theState=eFailure;
|
||||
}//while
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void skipSemi(CCPPTokenizer& aTokenizer) {
|
||||
CToken* theToken=0;
|
||||
while(theToken=aTokenizer.getTokenAt(++mIndex)){
|
||||
int theType=theToken->getTokenType();
|
||||
nsCString& theString=theToken->getStringValue();
|
||||
PRUnichar theChar=theString[0];
|
||||
|
||||
switch(theType){
|
||||
case eToken_semicolon:
|
||||
return;
|
||||
case eToken_operator:
|
||||
if(('}'==theChar) || (';'==theChar))
|
||||
return;
|
||||
break;
|
||||
case eToken_newline:
|
||||
case eToken_comment:
|
||||
case eToken_whitespace:
|
||||
mLineNumber+=theString.CountChar('\n');
|
||||
default:
|
||||
break;
|
||||
} //switch
|
||||
}//while
|
||||
}
|
||||
|
||||
void OutputMozillaFilename(ostream& anOutput) {
|
||||
|
||||
PRInt32 pos=mFilename.Find("mozilla");
|
||||
const char* buf=mFilename.GetBuffer();
|
||||
if(-1<pos) {
|
||||
buf+=pos+8;
|
||||
|
||||
if(gEmitHTML) {
|
||||
anOutput << "<br><a href=\"" ;
|
||||
|
||||
anOutput << "http://lxr.mozilla.org/mozilla/source/";
|
||||
anOutput << buf << "#" << mLineNumber;
|
||||
|
||||
cout << "\">";
|
||||
}
|
||||
|
||||
cout << buf << ":" << mLineNumber;
|
||||
|
||||
if(gEmitHTML) {
|
||||
cout << "</a>";
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
anOutput << buf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
This method iterates the tokens (in tokenizer) looking for statements.
|
||||
The statements are then decoded to find pointer variables. If they get a
|
||||
new call, then they're recorded in mNames. If they're in an IF(), then
|
||||
they're recording in mSafeNames. We also look for simple dereferences.
|
||||
When we find one, we look it up in mSafeNames. If it's not there, we have
|
||||
a potential deref error.
|
||||
***************************************************************************/
|
||||
void scan(CCPPTokenizer& aTokenizer,ostream& anOutput){
|
||||
int theMax=aTokenizer.getCount();
|
||||
int theIDCount=mNames.GetSize();
|
||||
int theSafeIDCount=mSafeNames.GetSize();
|
||||
CToken* theMatch=0;
|
||||
|
||||
while(mIndex<theMax){
|
||||
CToken* theToken=aTokenizer.getTokenAt(mIndex);
|
||||
int theType=theToken->getTokenType();
|
||||
nsCString& theString=theToken->getStringValue();
|
||||
int theNLCount=theString.CountChar('\n');
|
||||
|
||||
switch(theType){
|
||||
case eToken_operator:
|
||||
{
|
||||
PRUnichar theChar=theString[0];
|
||||
switch(theChar){
|
||||
case '{':
|
||||
mIndex++;
|
||||
scan(aTokenizer,anOutput);
|
||||
break;
|
||||
case '}':
|
||||
//before returning, let's remove the new identifiers...
|
||||
while(mNames.GetSize()>theIDCount){
|
||||
CToken* theToken2=(CToken*)mNames.Pop();
|
||||
}
|
||||
while(mSafeNames.GetSize()>theSafeIDCount){
|
||||
CToken* theToken2=(CToken*)mSafeNames.Pop();
|
||||
}
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case eToken_comment:
|
||||
case eToken_newline:
|
||||
case eToken_whitespace:
|
||||
mLineNumber+=theString.CountChar('\n');
|
||||
break;
|
||||
|
||||
//If it's an ID, then we're looking for 3 patterns:
|
||||
// 1. ID* ID...;
|
||||
// 2. *ID=ID;
|
||||
// 3. ID->XXX;
|
||||
case eToken_identifier:
|
||||
{
|
||||
PRUnichar theOpChar=0;
|
||||
if(theToken=findPtrDecl(aTokenizer,mIndex,theOpChar,true)) {
|
||||
//we found ID* ID; (or) ID* ID=...;
|
||||
mNames.Push(theToken);
|
||||
mIndex+=2;
|
||||
skipSemi(aTokenizer);
|
||||
}
|
||||
|
||||
else if(0==theString.Compare("if",true,2)) {
|
||||
CToken* theSafeID=findSafeIDInIfStatement(aTokenizer,mNames);
|
||||
if(theSafeID) {
|
||||
mSafeNames.Push(theSafeID);
|
||||
theSafeIDCount++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
CToken* theMatch=matchID(mNames,theString);
|
||||
if(theMatch){
|
||||
if((hasUnconditionedDeref(theString,aTokenizer,mIndex)) ||
|
||||
(hasSimpleDeref(theString,aTokenizer,mIndex))){
|
||||
CToken* theSafeID=matchID(mSafeNames,theString);
|
||||
if(theSafeID) {
|
||||
nsCString& s1=theSafeID->getStringValue();
|
||||
if(s1.Equals(theString))
|
||||
break;
|
||||
}
|
||||
//dump the name out in LXR format
|
||||
|
||||
OutputMozillaFilename(anOutput);
|
||||
nsCAutoString theCStr(theString);
|
||||
|
||||
|
||||
anOutput << " Deref-error: \"" << (const char*)theCStr << "\"" << endl;
|
||||
mErrCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
nsDeque mNames;
|
||||
nsDeque mSafeNames;
|
||||
int mIndex;
|
||||
int mLineNumber;
|
||||
int mErrCount;
|
||||
nsCString mFilename;
|
||||
};
|
||||
|
||||
void ScanFile(nsCString& aFilename,ostream& anOutput,int& aLineCount,int& anErrCount) {
|
||||
nsCAutoString theCStr(aFilename);
|
||||
|
||||
fstream input((const char*)theCStr,ios::in);
|
||||
CScanner theScanner(input);
|
||||
CCPPTokenizer theTokenizer;
|
||||
theTokenizer.tokenize(theScanner);
|
||||
|
||||
CPattern thePattern(aFilename);
|
||||
thePattern.scan(theTokenizer,anOutput);
|
||||
aLineCount+=thePattern.mLineNumber;
|
||||
anErrCount+=thePattern.mErrCount;
|
||||
}
|
||||
|
||||
|
||||
void IterateFiles(IDirectory& aDirectory,ostream& anOutput,int& aFilecount,int& aLineCount,int& anErrCount) {
|
||||
|
||||
nsCAutoString thePath("");
|
||||
aDirectory.getPath(thePath);
|
||||
|
||||
int theCount=aDirectory.getSize();
|
||||
int theIndex=0;
|
||||
for(theIndex=0;theIndex<theCount;theIndex++){
|
||||
IDirEntry* theEntry=aDirectory.getEntryAt(theIndex);
|
||||
nsCString& theName=theEntry->getName();
|
||||
if(!dynamic_cast<IDirectory*>(theEntry)){
|
||||
nsCAutoString theCopy;
|
||||
theName.Right(theCopy,4);
|
||||
if(0==theCopy.Compare(".cpp",true,3)) {
|
||||
nsCAutoString path(thePath);
|
||||
path.Append('/');
|
||||
path.Append(theName);
|
||||
aFilecount++;
|
||||
ScanFile(path,anOutput,aLineCount,anErrCount);
|
||||
}
|
||||
} else {
|
||||
//we've got a directory on our hands...
|
||||
//let's go walk it...
|
||||
nsCAutoString path(thePath);
|
||||
path.Append("/");
|
||||
path.Append(theName);
|
||||
if(!theName.EqualsIgnoreCase("cvs")) {
|
||||
IDirectory* theDirectory=IDirectory::openDirectory(path.GetBuffer(),"*.*");
|
||||
if(theDirectory) {
|
||||
IterateFiles(*theDirectory,anOutput,aFilecount,aLineCount,anErrCount);
|
||||
IDirectory::closeDirectory(theDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ConsumeArguments(int argc, char* argv[]) {
|
||||
if(argc<2) {
|
||||
cout << "Usage: dreftool -h -d sourcepath" << endl;
|
||||
cout << "-D path to root of source tree" << endl;
|
||||
cout << "-H emit as HTML" << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(int index=1;index<argc;index++){
|
||||
switch(argv[index][0]) {
|
||||
case '-':
|
||||
case '/':
|
||||
switch(toupper(argv[index][1])){
|
||||
case 'D': //to specify starting directory
|
||||
if(('-'!=argv[index+1][0]) && ('/'!=argv[index+1][0])) {
|
||||
strcpy(gRootDir,argv[index+1]);
|
||||
index++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'H': //user chose to show redundant include errors
|
||||
gEmitHTML=true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]){
|
||||
|
||||
getcwd(gRootDir,sizeof(gRootDir)-1);
|
||||
ConsumeArguments(argc,argv);
|
||||
|
||||
int fileCount=0;
|
||||
int lineCount=0;
|
||||
int errCount=0;
|
||||
|
||||
#if 0
|
||||
nsCAutoString temp("test3.cpp");
|
||||
ScanFile(temp,cout,lineCount,errCount);
|
||||
fileCount++;
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
|
||||
if(gEmitHTML) {
|
||||
cout << "<html><body>" << endl;
|
||||
}
|
||||
|
||||
cout << "Scanning " << gRootDir << "..." << endl;
|
||||
IDirectory* theDirectory=IDirectory::openDirectory(gRootDir,"*.*");
|
||||
if(theDirectory)
|
||||
IterateFiles(*theDirectory,cout,fileCount,lineCount,errCount);
|
||||
#endif
|
||||
|
||||
if(gEmitHTML) {
|
||||
cout << "<PRE>" <<endl;
|
||||
}
|
||||
|
||||
cout << endl << endl << "Summary: " << endl;
|
||||
cout << "===============================" << endl;
|
||||
cout<< "Files: " << fileCount << endl;
|
||||
cout<< "Lines: " << lineCount<< endl;
|
||||
cout<< "Errors: " << errCount<< endl;
|
||||
|
||||
if(gEmitHTML) {
|
||||
cout << "</PRE>" <<endl;
|
||||
cout << "</body></html>" << endl;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#!nmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
#!nmake
|
||||
#
|
||||
# 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.
|
||||
|
||||
memerror::
|
||||
cl /DTESTBED /c CCPPTokenizer.cpp
|
||||
cl /DTESTBED /c CDirectory.cpp
|
||||
cl /DTESTBED /c CScanner.cpp
|
||||
cl /DTESTBED /c CToken.cpp
|
||||
cl /DTESTBED /c main.cpp
|
||||
cl /DTESTBED /c nsCRT.cpp
|
||||
cl /DTESTBED /c nsDeque.cpp
|
||||
cl /DTESTBED /c nsStr.cpp
|
||||
cl /DTESTBED /c nsString.cpp
|
||||
cl /DTESTBED /c tokens.cpp
|
||||
link /OUT:dreftool.exe CCPPTokenizer.obj CDirectory.obj CScanner.obj CToken.obj main.obj nsCRT.obj nsDeque.obj nsStr.obj nsString.obj tokens.obj
|
||||
|
||||
all:: memerror
|
||||
|
||||
clean::
|
||||
del *.obj dreftool.exe
|
||||
|
||||
clobber:: clean
|
||||
|
||||
|
|
@ -0,0 +1,432 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* MODULE NOTES:
|
||||
* @update gess7/30/98
|
||||
*
|
||||
* Much as I hate to do it, we were using string compares wrong.
|
||||
* Often, programmers call functions like strcmp(s1,s2), and pass
|
||||
* one or more null strings. Rather than blow up on these, I've
|
||||
* added quick checks to ensure that cases like this don't cause
|
||||
* us to fail.
|
||||
*
|
||||
* In general, if you pass a null into any of these string compare
|
||||
* routines, we simply return 0.
|
||||
*/
|
||||
|
||||
|
||||
#include "nsCRT.h"
|
||||
|
||||
|
||||
// XXX Bug: These tables don't lowercase the upper 128 characters properly
|
||||
|
||||
// This table maps uppercase characters to lower case characters;
|
||||
// characters that are neither upper nor lower case are unaffected.
|
||||
static const unsigned char kUpper2Lower[256] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64,
|
||||
|
||||
// upper band mapped to lower [A-Z] => [a-z]
|
||||
97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
|
||||
112,113,114,115,116,117,118,119,120,121,122,
|
||||
|
||||
91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
|
||||
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
|
||||
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
|
||||
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
|
||||
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
|
||||
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
|
||||
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
|
||||
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
|
||||
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
|
||||
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
|
||||
};
|
||||
|
||||
static const unsigned char kLower2Upper[256] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
|
||||
96,
|
||||
|
||||
// lower band mapped to upper [a-z] => [A-Z]
|
||||
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
|
||||
|
||||
123,124,125,126,127,
|
||||
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
|
||||
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
|
||||
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
|
||||
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
|
||||
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
|
||||
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
|
||||
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
|
||||
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
|
||||
};
|
||||
|
||||
// XXX bug: this doesn't map 0x80 to 0x9f properly
|
||||
const PRUnichar kIsoLatin1ToUCS2[256] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
|
||||
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
|
||||
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
|
||||
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
|
||||
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
|
||||
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
|
||||
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
|
||||
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
|
||||
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
|
||||
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define TOLOWER(_ucs2) \
|
||||
(((_ucs2) < 256) ? PRUnichar(kUpper2Lower[_ucs2]) : _ToLower(_ucs2))
|
||||
|
||||
#define TOUPPER(_ucs2) \
|
||||
(((_ucs2) < 256) ? PRUnichar(kLower2Upper[_ucs2]) : _ToUpper(_ucs2))
|
||||
|
||||
static PRUnichar _ToLower(PRUnichar aChar)
|
||||
{
|
||||
// XXX need i18n code here
|
||||
return aChar;
|
||||
}
|
||||
|
||||
static PRUnichar _ToUpper(PRUnichar aChar)
|
||||
{
|
||||
// XXX need i18n code here
|
||||
return aChar;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
PRUnichar nsCRT::ToUpper(PRUnichar aChar) {
|
||||
return TOUPPER(aChar);
|
||||
}
|
||||
|
||||
PRUnichar nsCRT::ToLower(PRUnichar aChar) {
|
||||
return TOLOWER(aChar);
|
||||
}
|
||||
|
||||
char nsCRT::ToUpper(char aChar) {
|
||||
if((aChar>='a') && (aChar<='z'))
|
||||
aChar-=32;
|
||||
return aChar;
|
||||
}
|
||||
|
||||
char nsCRT::ToLower(char aChar) {
|
||||
if((aChar>='A') && (aChar<='Z'))
|
||||
aChar+=32;
|
||||
return aChar;
|
||||
}
|
||||
|
||||
PRInt32 nsCRT::strlen(const PRUnichar* s) {
|
||||
PRInt32 len = 0;
|
||||
if(s) {
|
||||
while (*s++ != 0) {
|
||||
len++;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @update gess10/29/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
void nsCRT::strncpy(PRUnichar* aDest, const char* aSource,PRInt32 aLength) {
|
||||
if(aDest && aSource) {
|
||||
int theIndex;
|
||||
for(theIndex=0;theIndex<aLength;theIndex++) {
|
||||
aDest[theIndex] = kIsoLatin1ToUCS2[aSource[theIndex]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare unichar string ptrs, stopping at the 1st null
|
||||
* NOTE: If both are null, we return 0.
|
||||
* @update gess7/30/98
|
||||
* @param s1 and s2 both point to unichar strings
|
||||
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
|
||||
*/
|
||||
PRInt32 nsCRT::strcmp(const PRUnichar* s1, const PRUnichar* s2)
|
||||
{
|
||||
if(s1 && s2) {
|
||||
for (;;) {
|
||||
PRUnichar c1 = *s1++;
|
||||
PRUnichar c2 = *s2++;
|
||||
if (c1 != c2) {
|
||||
if (c1 < c2) return -1;
|
||||
return 1;
|
||||
}
|
||||
if ((0==c1) || (0==c2)) break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare unichar string ptrs, stopping at the 1st null or nth char.
|
||||
* NOTE: If either is null, we return 0.
|
||||
* @update gess7/30/98
|
||||
* @param s1 and s2 both point to unichar strings
|
||||
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
|
||||
*/
|
||||
PRInt32 nsCRT::strncmp(const PRUnichar* s1, const PRUnichar* s2, PRInt32 n)
|
||||
{
|
||||
if(s1 && s2) {
|
||||
if(0<n) {
|
||||
while (--n >= 0) {
|
||||
PRUnichar c1 = *s1++;
|
||||
PRUnichar c2 = *s2++;
|
||||
if (c1 != c2) {
|
||||
if (c1 < c2) return -1;
|
||||
return 1;
|
||||
}
|
||||
if ((0==c1) || (0==c2)) break;
|
||||
}
|
||||
}
|
||||
else return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare unichar string ptrs without regard to case
|
||||
* NOTE: If both are null, we return 0.
|
||||
* @update gess7/30/98
|
||||
* @param s1 and s2 both point to unichar strings
|
||||
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
|
||||
*/
|
||||
PRInt32 nsCRT::strcasecmp(const PRUnichar* s1, const PRUnichar* s2)
|
||||
{
|
||||
if(s1 && s2) {
|
||||
for (;;) {
|
||||
PRUnichar c1 = *s1++;
|
||||
PRUnichar c2 = *s2++;
|
||||
if (c1 != c2) {
|
||||
c1 = TOLOWER(c1);
|
||||
c2 = TOLOWER(c2);
|
||||
if (c1 != c2) {
|
||||
if (c1 < c2) return -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if ((0==c1) || (0==c2)) break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare unichar string ptrs, stopping at the 1st null or nth char;
|
||||
* also ignoring the case of characters.
|
||||
* NOTE: If both are null, we return 0.
|
||||
* @update gess7/30/98
|
||||
* @param s1 and s2 both point to unichar strings
|
||||
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
|
||||
*/
|
||||
PRInt32 nsCRT::strncasecmp(const PRUnichar* s1, const PRUnichar* s2, PRInt32 n)
|
||||
{
|
||||
if(s1 && s2) {
|
||||
if(0<n){
|
||||
while (--n >= 0) {
|
||||
PRUnichar c1 = *s1++;
|
||||
PRUnichar c2 = *s2++;
|
||||
if (c1 != c2) {
|
||||
c1 = TOLOWER(c1);
|
||||
c2 = TOLOWER(c2);
|
||||
if (c1 != c2) {
|
||||
if (c1 < c2) return -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if ((0==c1) || (0==c2)) break;
|
||||
}
|
||||
} else return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare a unichar string ptr to cstring.
|
||||
* NOTE: If both are null, we return 0.
|
||||
* @update gess7/30/98
|
||||
* @param s1 points to unichar string
|
||||
* @param s2 points to cstring
|
||||
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
|
||||
*/
|
||||
PRInt32 nsCRT::strcmp(const PRUnichar* s1, const char* s2)
|
||||
{
|
||||
if(s1 && s2) {
|
||||
for (;;) {
|
||||
PRUnichar c1 = *s1++;
|
||||
PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++];
|
||||
if (c1 != c2) {
|
||||
if (c1 < c2) return -1;
|
||||
return 1;
|
||||
}
|
||||
if ((0==c1) || (0==c2)) break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare a unichar string ptr to cstring, up to N chars.
|
||||
* NOTE: If both are null, we return 0.
|
||||
* @update gess7/30/98
|
||||
* @param s1 points to unichar string
|
||||
* @param s2 points to cstring
|
||||
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
|
||||
*/
|
||||
PRInt32 nsCRT::strncmp(const PRUnichar* s1, const char* s2, PRInt32 n)
|
||||
{
|
||||
if(s1 && s2) {
|
||||
if(0<n){
|
||||
while (--n >= 0) {
|
||||
PRUnichar c1 = *s1++;
|
||||
PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++];
|
||||
if (c1 != c2) {
|
||||
if (c1 < c2) return -1;
|
||||
return 1;
|
||||
}
|
||||
if ((0==c1) || (0==c2)) break;
|
||||
}
|
||||
} else return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare a unichar string ptr to cstring without regard to case
|
||||
* NOTE: If both are null, we return 0.
|
||||
* @update gess7/30/98
|
||||
* @param s1 points to unichar string
|
||||
* @param s2 points to cstring
|
||||
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
|
||||
*/
|
||||
PRInt32 nsCRT::strcasecmp(const PRUnichar* s1, const char* s2)
|
||||
{
|
||||
if(s1 && s2) {
|
||||
for (;;) {
|
||||
PRUnichar c1 = *s1++;
|
||||
PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++];
|
||||
if (c1 != c2) {
|
||||
c1 = TOLOWER(c1);
|
||||
c2 = TOLOWER(c2);
|
||||
if (c1 != c2) {
|
||||
if (c1 < c2) return -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if ((0==c1) || (0==c2)) break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caseless compare up to N chars between unichar string ptr to cstring.
|
||||
* NOTE: If both are null, we return 0.
|
||||
* @update gess7/30/98
|
||||
* @param s1 points to unichar string
|
||||
* @param s2 points to cstring
|
||||
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
|
||||
*/
|
||||
PRInt32 nsCRT::strncasecmp(const PRUnichar* s1, const char* s2, PRInt32 n)
|
||||
{
|
||||
if(s1 && s2){
|
||||
if(0<n){
|
||||
while (--n >= 0) {
|
||||
PRUnichar c1 = *s1++;
|
||||
PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++];
|
||||
if (c1 != c2) {
|
||||
c1 = TOLOWER(c1);
|
||||
c2 = TOLOWER(c2);
|
||||
if (c1 != c2) {
|
||||
if (c1 < c2) return -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (c1 == 0) break;
|
||||
}
|
||||
} else return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRUint32 nsCRT::HashValue(const PRUnichar* us)
|
||||
{
|
||||
PRUint32 rv = 0;
|
||||
if(us) {
|
||||
PRUnichar ch;
|
||||
while ((ch = *us++) != 0) {
|
||||
// FYI: rv = rv*37 + ch
|
||||
rv = ((rv << 5) + (rv << 2) + rv) + ch;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
PRUint32 nsCRT::HashValue(const PRUnichar* us, PRInt32* uslenp)
|
||||
{
|
||||
PRUint32 rv = 0;
|
||||
PRInt32 len = 0;
|
||||
PRUnichar ch;
|
||||
while ((ch = *us++) != 0) {
|
||||
// FYI: rv = rv*37 + ch
|
||||
rv = ((rv << 5) + (rv << 2) + rv) + ch;
|
||||
len++;
|
||||
}
|
||||
*uslenp = len;
|
||||
return rv;
|
||||
}
|
||||
|
||||
PRInt32 nsCRT::atoi( const PRUnichar *string )
|
||||
{
|
||||
return atoi(string);
|
||||
}
|
||||
|
||||
float PR_strtod(char* cp, char** cpp) {
|
||||
float f=1.1f;
|
||||
**cpp=0;
|
||||
return f;
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
#ifndef nsCRT_h___
|
||||
#define nsCRT_h___
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
//#include "plstr.h"
|
||||
#include "nscore.h"
|
||||
|
||||
/// This is a wrapper class around all the C runtime functions.
|
||||
|
||||
//const PRInt32 kNotFound = -1;
|
||||
|
||||
extern const PRUnichar kIsoLatin1ToUCS2[256];
|
||||
|
||||
float PR_strtod(char* cp, char** cpp);
|
||||
|
||||
class nsCRT {
|
||||
public:
|
||||
/** Copy bytes from aSrc to aDest.
|
||||
@param aDest the destination address
|
||||
@param aSrc the source address
|
||||
@param aCount the number of bytes to copy
|
||||
*/
|
||||
static void memcpy(void* aDest, const void* aSrc, PRInt32 aCount) {
|
||||
::memcpy(aDest, aSrc, (size_t)aCount);
|
||||
}
|
||||
|
||||
static void memmove(void* aDest, const void* aSrc, PRInt32 aCount) {
|
||||
::memmove(aDest, aSrc, (size_t)aCount);
|
||||
}
|
||||
|
||||
static void memset(void* aDest, PRUint8 aByte, PRInt32 aCount) {
|
||||
::memset(aDest, aByte, aCount);
|
||||
}
|
||||
|
||||
static void zero(void* aDest, PRInt32 aCount) {
|
||||
::memset(aDest, 0, (size_t)aCount);
|
||||
}
|
||||
|
||||
static void strncpy(PRUnichar* aDest, const char* aSource,PRInt32 aLength);
|
||||
|
||||
|
||||
/** Compute the string length of s
|
||||
@param s the string in question
|
||||
@return the length of s
|
||||
*/
|
||||
static PRInt32 strlen(const char* s) {
|
||||
return PRInt32(::strlen(s));
|
||||
}
|
||||
|
||||
/// Compare s1 and s2.
|
||||
static PRInt32 strcmp(const char* s1, const char* s2) {
|
||||
return ::strcmp(s1,s2);
|
||||
}
|
||||
|
||||
/// Case-insensitive string comparison.
|
||||
static PRInt32 strcasecmp(const char* s1, const char* s2) {
|
||||
return ::strcmpi(s1,s2);
|
||||
}
|
||||
|
||||
/// Case-insensitive string comparison with length
|
||||
static PRInt32 strncasecmp(const char* s1, const char* s2, PRInt32 aMaxLen) {
|
||||
return ::strnicmp(s1, s2, aMaxLen);
|
||||
}
|
||||
|
||||
/// Like strlen except for ucs2 strings
|
||||
static PRInt32 strlen(const PRUnichar* s);
|
||||
|
||||
/// Like strcmp except for ucs2 strings
|
||||
static PRInt32 strcmp(const PRUnichar* s1, const PRUnichar* s2);
|
||||
/// Like strcmp except for ucs2 strings
|
||||
static PRInt32 strncmp(const PRUnichar* s1, const PRUnichar* s2,
|
||||
PRInt32 aMaxLen);
|
||||
|
||||
/// Like strcasecmp except for ucs2 strings
|
||||
static PRInt32 strcasecmp(const PRUnichar* s1, const PRUnichar* s2);
|
||||
/// Like strncasecmp except for ucs2 strings
|
||||
static PRInt32 strncasecmp(const PRUnichar* s1, const PRUnichar* s2,
|
||||
PRInt32 aMaxLen);
|
||||
|
||||
/// Like strcmp with a char* and a ucs2 string
|
||||
static PRInt32 strcmp(const PRUnichar* s1, const char* s2);
|
||||
/// Like strncmp with a char* and a ucs2 string
|
||||
static PRInt32 strncmp(const PRUnichar* s1, const char* s2,
|
||||
PRInt32 aMaxLen);
|
||||
|
||||
/// Like strcasecmp with a char* and a ucs2 string
|
||||
static PRInt32 strcasecmp(const PRUnichar* s1, const char* s2);
|
||||
/// Like strncasecmp with a char* and a ucs2 string
|
||||
static PRInt32 strncasecmp(const PRUnichar* s1, const char* s2,
|
||||
PRInt32 aMaxLen);
|
||||
|
||||
/// Compute a hashcode for a ucs2 string
|
||||
static PRUint32 HashValue(const PRUnichar* s1);
|
||||
|
||||
/// Same as above except that we return the length in s1len
|
||||
static PRUint32 HashValue(const PRUnichar* s1, PRInt32* s1len);
|
||||
|
||||
/// String to integer.
|
||||
static PRInt32 atoi( const PRUnichar *string );
|
||||
|
||||
static PRUnichar ToUpper(PRUnichar aChar);
|
||||
static char ToUpper(char aChar);
|
||||
|
||||
static PRUnichar ToLower(PRUnichar aChar);
|
||||
static char ToLower(char aChar);
|
||||
};
|
||||
|
||||
#endif /* nsCRT_h___ */
|
|
@ -0,0 +1,596 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "nsDeque.h"
|
||||
#include "nsCRT.h"
|
||||
#include <stdio.h>
|
||||
|
||||
//#define _SELFTEST_DEQUE 1
|
||||
#undef _SELFTEST_DEQUE
|
||||
|
||||
/**
|
||||
* Standard constructor
|
||||
* @update gess4/18/98
|
||||
* @return new deque
|
||||
*/
|
||||
nsDeque::nsDeque(nsDequeFunctor* aDeallocator) {
|
||||
mDeallocator=aDeallocator;
|
||||
mOrigin=mSize=0;
|
||||
mData=mBuffer; // don't allocate space until you must
|
||||
mCapacity=sizeof(mBuffer)/sizeof(mBuffer[0]);
|
||||
nsCRT::zero(mData,mCapacity*sizeof(mBuffer[0]));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
* @update gess4/18/98
|
||||
*/
|
||||
nsDeque::~nsDeque() {
|
||||
// char buffer[30];
|
||||
// printf("Capacity: %i\n",mCapacity);
|
||||
|
||||
static int mCaps[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
switch(mCapacity) {
|
||||
case 4: mCaps[0]++; break;
|
||||
case 8: mCaps[1]++; break;
|
||||
case 16: mCaps[2]++; break;
|
||||
case 32: mCaps[3]++; break;
|
||||
case 64: mCaps[4]++; break;
|
||||
case 128: mCaps[5]++; break;
|
||||
case 256: mCaps[6]++; break;
|
||||
case 512: mCaps[7]++; break;
|
||||
case 1024: mCaps[8]++; break;
|
||||
case 2048: mCaps[9]++; break;
|
||||
case 4096: mCaps[10]++; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Erase();
|
||||
if(mData && (mData!=mBuffer))
|
||||
delete [] mData;
|
||||
mData=0;
|
||||
if(mDeallocator) {
|
||||
delete mDeallocator;
|
||||
}
|
||||
mDeallocator=0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of elements currently stored in
|
||||
* this deque.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param
|
||||
* @return int contains element count
|
||||
*/
|
||||
PRInt32 nsDeque::GetSize(void) const {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){
|
||||
if(mDeallocator) {
|
||||
delete mDeallocator;
|
||||
}
|
||||
mDeallocator=aDeallocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from container without destroying them.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
nsDeque& nsDeque::Empty() {
|
||||
if((0<mCapacity) && (mData)) {
|
||||
nsCRT::zero(mData,mCapacity*sizeof(mData));
|
||||
}
|
||||
mSize=0;
|
||||
mOrigin=0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and delete all items from container
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @return this
|
||||
*/
|
||||
nsDeque& nsDeque::Erase() {
|
||||
if(mDeallocator && mSize) {
|
||||
ForEach(*mDeallocator);
|
||||
}
|
||||
return Empty();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method adds an item to the end of the deque.
|
||||
* This operation has the potential to cause the
|
||||
* underlying buffer to resize.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param anItem: new item to be added to deque
|
||||
* @return nada
|
||||
*/
|
||||
nsDeque& nsDeque::GrowCapacity(void) {
|
||||
|
||||
PRInt32 theNewSize = mCapacity<<2;
|
||||
void** temp=new void*[theNewSize];
|
||||
|
||||
//Here's the interesting part: You can't just move the elements
|
||||
//directy (in situ) from the old buffer to the new one.
|
||||
//Since capacity has changed, the old origin doesn't make
|
||||
//sense anymore. It's better to resequence the elements now.
|
||||
|
||||
if(mData) {
|
||||
int tempi=0;
|
||||
int i=0;
|
||||
int j=0;
|
||||
for(i=mOrigin;i<mCapacity;i++) temp[tempi++]=mData[i]; //copy the leading elements...
|
||||
for(j=0;j<mOrigin;j++) temp[tempi++]=mData[j]; //copy the trailing elements...
|
||||
if(mData!=mBuffer)
|
||||
delete [] mData;
|
||||
}
|
||||
mCapacity=theNewSize;
|
||||
mOrigin=0; //now realign the origin...
|
||||
mData=temp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds an item to the end of the deque.
|
||||
* This operation has the potential to cause the
|
||||
* underlying buffer to resize.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param anItem: new item to be added to deque
|
||||
* @return nada
|
||||
*/
|
||||
nsDeque& nsDeque::Push(void* anItem) {
|
||||
if(mSize==mCapacity) {
|
||||
GrowCapacity();
|
||||
}
|
||||
int offset=mOrigin+mSize;
|
||||
if(offset<mCapacity)
|
||||
mData[offset]=anItem;
|
||||
else mData[offset-mCapacity]=anItem;
|
||||
mSize++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds an item to the front of the deque.
|
||||
* This operation has the potential to cause the
|
||||
* underlying buffer to resize.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param anItem: new item to be added to deque
|
||||
* @return nada
|
||||
*/
|
||||
nsDeque& nsDeque::PushFront(void* anItem) {
|
||||
if(mSize==mCapacity) {
|
||||
GrowCapacity();
|
||||
}
|
||||
if(0==mOrigin){ //case1: [xxx..]
|
||||
//mOrigin=mCapacity-1-mSize++;
|
||||
mOrigin=mCapacity-1;
|
||||
mData[mOrigin]=anItem;
|
||||
}
|
||||
else {// if(mCapacity==(mOrigin+mSize-1)){ //case2: [..xxx] and case3: [.xxx.]
|
||||
mData[--mOrigin]=anItem;
|
||||
}
|
||||
mSize++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and return the last item in the container.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param none
|
||||
* @return ptr to last item in container
|
||||
*/
|
||||
void* nsDeque::Pop(void) {
|
||||
void* result=0;
|
||||
if(mSize>0) {
|
||||
int offset=mOrigin+mSize-1;
|
||||
if(offset>=mCapacity)
|
||||
offset-=mCapacity;
|
||||
result=mData[offset];
|
||||
mData[offset]=0;
|
||||
mSize--;
|
||||
if(0==mSize)
|
||||
mOrigin=0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets called you want to remove and return
|
||||
* the first member in the container.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param nada
|
||||
* @return last item in container
|
||||
*/
|
||||
void* nsDeque::PopFront() {
|
||||
void* result=0;
|
||||
if(mSize>0) {
|
||||
result=mData[mOrigin];
|
||||
mData[mOrigin++]=0; //zero it out for debugging purposes.
|
||||
mSize--;
|
||||
if(mCapacity==mOrigin) //you popped off the end, so cycle back around...
|
||||
mOrigin=0;
|
||||
if(0==mSize)
|
||||
mOrigin=0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets called you want to peek at the topmost
|
||||
* member without removing it.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param nada
|
||||
* @return last item in container
|
||||
*/
|
||||
void* nsDeque::Peek() {
|
||||
void* result=0;
|
||||
if(mSize>0) {
|
||||
result=mData[mOrigin];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to retrieve the ith element from this container.
|
||||
* Keep in mind that accessing the underlying elements is
|
||||
* done in a relative fashion. Object 0 is not necessarily
|
||||
* the first element (the first element is at mOrigin).
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param anIndex : 0 relative offset of item you want
|
||||
* @return void* or null
|
||||
*/
|
||||
void* nsDeque::ObjectAt(PRInt32 anIndex) const {
|
||||
void* result=0;
|
||||
|
||||
if((anIndex>=0) && (anIndex<mSize))
|
||||
{
|
||||
if(anIndex<(mCapacity-mOrigin)) {
|
||||
result=mData[mOrigin+anIndex];
|
||||
}
|
||||
else {
|
||||
result=mData[anIndex-(mCapacity-mOrigin)];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return an iterator pointing to
|
||||
* the beginning of the queue. Note that this
|
||||
* takes the circular buffer semantics into account.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @return new deque iterator, init'ed to 1st item
|
||||
*/
|
||||
nsDequeIterator nsDeque::Begin(void) const{
|
||||
return nsDequeIterator(*this,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return an iterator pointing to
|
||||
* the last of the queue. Note that this
|
||||
* takes the circular buffer semantics into account.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @return new deque iterator, init'ed to last item
|
||||
*/
|
||||
nsDequeIterator nsDeque::End(void) const{
|
||||
return nsDequeIterator(*this,mSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method when you wanto to iterate all the
|
||||
* members of the container, passing a functor along
|
||||
* to call your code.
|
||||
*
|
||||
* @update gess4/20/98
|
||||
* @param aFunctor object to call for each member
|
||||
* @return *this
|
||||
*/
|
||||
void nsDeque::ForEach(nsDequeFunctor& aFunctor) const{
|
||||
int i=0;
|
||||
for(i=0;i<mSize;i++){
|
||||
void* obj=ObjectAt(i);
|
||||
obj=aFunctor(obj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method when you wanto to iterate all the
|
||||
* members of the container, passing a functor along
|
||||
* to call your code. Iteration continues until your
|
||||
* functor returns a non-null.
|
||||
*
|
||||
* @update gess4/20/98
|
||||
* @param aFunctor object to call for each member
|
||||
* @return *this
|
||||
*/
|
||||
const void* nsDeque::FirstThat(nsDequeFunctor& aFunctor) const{
|
||||
int i=0;
|
||||
for(i=0;i<mSize;i++){
|
||||
void* obj=ObjectAt(i);
|
||||
obj=aFunctor(obj);
|
||||
if(obj)
|
||||
return obj;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* Here comes the nsDequeIterator class...
|
||||
******************************************************/
|
||||
|
||||
/**
|
||||
* DequeIterator is an object that knows how to iterate (forward and backward)
|
||||
* a Deque. Normally, you don't need to do this, but there are some special
|
||||
* cases where it is pretty handy, so here you go.
|
||||
*
|
||||
* This is a standard dequeiterator constructor
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param aQueue is the deque object to be iterated
|
||||
* @param anIndex is the starting position for your iteration
|
||||
*/
|
||||
nsDequeIterator::nsDequeIterator(const nsDeque& aQueue,int anIndex): mIndex(anIndex), mDeque(aQueue) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy construct a new iterator beginning with given
|
||||
*
|
||||
* @update gess4/20/98
|
||||
* @param aCopy is another iterator to copy from
|
||||
* @return
|
||||
*/
|
||||
nsDequeIterator::nsDequeIterator(const nsDequeIterator& aCopy) : mIndex(aCopy.mIndex), mDeque(aCopy.mDeque) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves iterator to first element in deque
|
||||
* @update gess4/18/98
|
||||
* @return this
|
||||
*/
|
||||
nsDequeIterator& nsDequeIterator::First(void){
|
||||
mIndex=0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard assignment operator for dequeiterator
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param aCopy is an iterator to be copied from
|
||||
* @return *this
|
||||
*/
|
||||
nsDequeIterator& nsDequeIterator::operator=(const nsDequeIterator& aCopy) {
|
||||
//queue's are already equal.
|
||||
mIndex=aCopy.mIndex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* preform ! operation against to iterators to test for equivalence
|
||||
* (or lack thereof)!
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param anIter is the object to be compared to
|
||||
* @return TRUE if NOT equal.
|
||||
*/
|
||||
PRBool nsDequeIterator::operator!=(nsDequeIterator& anIter) {
|
||||
return PRBool(!this->operator==(anIter));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare 2 iterators for equivalence.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param anIter is the other iterator to be compared to
|
||||
* @return TRUE if EQUAL
|
||||
*/
|
||||
PRBool nsDequeIterator::operator<(nsDequeIterator& anIter) {
|
||||
return PRBool(((mIndex<anIter.mIndex) && (&mDeque==&anIter.mDeque)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare 2 iterators for equivalence.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param anIter is the other iterator to be compared to
|
||||
* @return TRUE if EQUAL
|
||||
*/
|
||||
PRBool nsDequeIterator::operator==(nsDequeIterator& anIter) {
|
||||
return PRBool(((mIndex==anIter.mIndex) && (&mDeque==&anIter.mDeque)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare 2 iterators for equivalence.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param anIter is the other iterator to be compared to
|
||||
* @return TRUE if EQUAL
|
||||
*/
|
||||
PRBool nsDequeIterator::operator>=(nsDequeIterator& anIter) {
|
||||
return PRBool(((mIndex>=anIter.mIndex) && (&mDeque==&anIter.mDeque)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-increment operator
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @return object at preincremented index
|
||||
*/
|
||||
void* nsDequeIterator::operator++() {
|
||||
return mDeque.ObjectAt(++mIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-increment operator
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param param is ignored
|
||||
* @return object at post-incremented index
|
||||
*/
|
||||
void* nsDequeIterator::operator++(int) {
|
||||
return mDeque.ObjectAt(mIndex++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-decrement operator
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @return object at pre-decremented index
|
||||
*/
|
||||
void* nsDequeIterator::operator--() {
|
||||
return mDeque.ObjectAt(--mIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-decrement operator
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param param is ignored
|
||||
* @return object at post-decremented index
|
||||
*/
|
||||
void* nsDequeIterator::operator--(int) {
|
||||
return mDeque.ObjectAt(mIndex--);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dereference operator
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @return object at ith index
|
||||
*/
|
||||
void* nsDequeIterator::GetCurrent(void) {
|
||||
return mDeque.ObjectAt(mIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method when you wanto to iterate all the
|
||||
* members of the container, passing a functor along
|
||||
* to call your code.
|
||||
*
|
||||
* @update gess4/20/98
|
||||
* @param aFunctor object to call for each member
|
||||
* @return *this
|
||||
*/
|
||||
void nsDequeIterator::ForEach(nsDequeFunctor& aFunctor) const{
|
||||
mDeque.ForEach(aFunctor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method when you wanto to iterate all the
|
||||
* members of the container, passing a functor along
|
||||
* to call your code.
|
||||
*
|
||||
* @update gess4/20/98
|
||||
* @param aFunctor object to call for each member
|
||||
* @return *this
|
||||
*/
|
||||
const void* nsDequeIterator::FirstThat(nsDequeFunctor& aFunctor) const{
|
||||
return mDeque.FirstThat(aFunctor);
|
||||
}
|
||||
|
||||
#ifdef _SELFTEST_DEQUE
|
||||
/**************************************************************
|
||||
Now define the token deallocator class...
|
||||
**************************************************************/
|
||||
class _SelfTestDeallocator: public nsDequeFunctor{
|
||||
public:
|
||||
_SelfTestDeallocator::_SelfTestDeallocator() {
|
||||
nsDeque::SelfTest();
|
||||
}
|
||||
virtual void* operator()(void* anObject) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
static _SelfTestDeallocator gDeallocator;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* conduct automated self test for this class
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
void nsDeque::SelfTest(void) {
|
||||
#ifdef _SELFTEST_DEQUE
|
||||
|
||||
{
|
||||
nsDeque theDeque(gDeallocator); //construct a simple one...
|
||||
|
||||
int ints[200];
|
||||
int count=sizeof(ints)/sizeof(int);
|
||||
int i=0;
|
||||
|
||||
for(i=0;i<count;i++){ //initialize'em
|
||||
ints[i]=10*(1+i);
|
||||
}
|
||||
|
||||
for(i=0;i<70;i++){
|
||||
theDeque.Push(&ints[i]);
|
||||
}
|
||||
|
||||
for(i=0;i<56;i++){
|
||||
int* temp=(int*)theDeque.Pop();
|
||||
}
|
||||
|
||||
for(i=0;i<55;i++){
|
||||
theDeque.Push(&ints[i]);
|
||||
}
|
||||
|
||||
for(i=0;i<35;i++){
|
||||
int* temp=(int*)theDeque.Pop();
|
||||
}
|
||||
|
||||
for(i=0;i<35;i++){
|
||||
theDeque.Push(&ints[i]);
|
||||
}
|
||||
|
||||
for(i=0;i<38;i++){
|
||||
int* temp=(int*)theDeque.Pop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int x;
|
||||
x=10;
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,411 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* MODULE NOTES:
|
||||
* @update gess 4/15/98 (tax day)
|
||||
*
|
||||
* The Deque is a very small, very efficient container object
|
||||
* than can hold elements of type void*, offering the following features:
|
||||
* It's interface supports pushing and poping of children.
|
||||
* It can iterate (via an interator class) it's children.
|
||||
* When full, it can efficently resize dynamically.
|
||||
*
|
||||
*
|
||||
* NOTE: The only bit of trickery here is that this deque is
|
||||
* built upon a ring-buffer. Like all ring buffers, the first
|
||||
* element may not be at index[0]. The mOrigin member determines
|
||||
* where the first child is. This point is quietly hidden from
|
||||
* customers of this class.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NSDEQUE
|
||||
#define _NSDEQUE
|
||||
|
||||
#include "nscore.h"
|
||||
|
||||
/**
|
||||
* The nsDequefunctor class is used when you want to create
|
||||
* callbacks between the deque and your generic code.
|
||||
* Use these objects in a call to ForEach();
|
||||
*
|
||||
* @update gess4/20/98
|
||||
*/
|
||||
class NS_COM nsDequeFunctor{
|
||||
public:
|
||||
virtual void* operator()(void* anObject)=0;
|
||||
};
|
||||
|
||||
|
||||
/******************************************************
|
||||
* Here comes the nsDeque class itself...
|
||||
******************************************************/
|
||||
|
||||
/**
|
||||
* The deque (double-ended queue) class is a common container type,
|
||||
* whose behavior mimics a line in your favorite checkout stand.
|
||||
* Classic CS describes the common behavior of a queue as FIFO.
|
||||
* A Deque allows items to be added and removed from either end of
|
||||
* the queue.
|
||||
*
|
||||
* @update gess4/20/98
|
||||
*/
|
||||
|
||||
class NS_COM nsDeque {
|
||||
friend class nsDequeIterator;
|
||||
public:
|
||||
nsDeque(nsDequeFunctor* aDeallocator);
|
||||
~nsDeque();
|
||||
|
||||
/**
|
||||
* Returns the number of elements currently stored in
|
||||
* this deque.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param
|
||||
* @return int contains element count
|
||||
*/
|
||||
PRInt32 GetSize() const;
|
||||
|
||||
|
||||
/**
|
||||
* Pushes new member onto the end of the deque
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param ptr to object to store
|
||||
* @return *this
|
||||
*/
|
||||
nsDeque& Push(void* anItem);
|
||||
|
||||
/**
|
||||
* Pushes new member onto the front of the deque
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param ptr to object to store
|
||||
* @return *this
|
||||
*/
|
||||
nsDeque& PushFront(void* anItem);
|
||||
|
||||
/**
|
||||
* Remove and return the first item in the container.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param none
|
||||
* @return ptr to first item in container
|
||||
*/
|
||||
void* Pop(void);
|
||||
|
||||
/**
|
||||
* Remove and return the first item in the container.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param none
|
||||
* @return ptr to first item in container
|
||||
*/
|
||||
void* PopFront(void);
|
||||
|
||||
|
||||
/**
|
||||
* Return topmost item without removing it.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param none
|
||||
* @return ptr to first item in container
|
||||
*/
|
||||
void* Peek(void);
|
||||
|
||||
/**
|
||||
* method used to retrieve ptr to
|
||||
* ith member in container. DOesn't remove
|
||||
* that item.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param index of desired item
|
||||
* @return ptr to ith element in list
|
||||
*/
|
||||
void* ObjectAt(int anIndex) const;
|
||||
|
||||
/**
|
||||
* Remove all items from container without destroying them
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
nsDeque& Empty();
|
||||
|
||||
/**
|
||||
* Remove and delete all items from container
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
nsDeque& Erase();
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new iterator, init'ed to start of container
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @return new dequeIterator
|
||||
*/
|
||||
nsDequeIterator Begin() const;
|
||||
|
||||
/**
|
||||
* Creates a new iterator, init'ed to end of container
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @return new dequeIterator
|
||||
*/
|
||||
nsDequeIterator End() const;
|
||||
|
||||
|
||||
/**
|
||||
* Call this method when you wanto to iterate all the
|
||||
* members of the container, passing a functor along
|
||||
* to call your code.
|
||||
*
|
||||
* @update gess4/20/98
|
||||
* @param aFunctor object to call for each member
|
||||
* @return *this
|
||||
*/
|
||||
void ForEach(nsDequeFunctor& aFunctor) const;
|
||||
|
||||
/**
|
||||
* Call this method when you wanto to iterate all the
|
||||
* members of the container, passing a functor along
|
||||
* to call your code. This process will interupt if
|
||||
* your function returns a null to this iterator.
|
||||
*
|
||||
* @update gess4/20/98
|
||||
* @param aFunctor object to call for each member
|
||||
* @return *this
|
||||
*/
|
||||
const void* FirstThat(nsDequeFunctor& aFunctor) const;
|
||||
|
||||
void SetDeallocator(nsDequeFunctor* aDeallocator);
|
||||
|
||||
/**
|
||||
* Perform automated selftest on the deque
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
static void SelfTest();
|
||||
|
||||
protected:
|
||||
|
||||
PRInt32 mSize;
|
||||
PRInt32 mCapacity;
|
||||
PRInt32 mOrigin;
|
||||
nsDequeFunctor* mDeallocator;
|
||||
void* mBuffer[8];
|
||||
void** mData;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
/**
|
||||
* Simple default constructor (PRIVATE)
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
nsDeque();
|
||||
|
||||
/**
|
||||
* Copy constructor (PRIVATE)
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
nsDeque(const nsDeque& other);
|
||||
|
||||
/**
|
||||
* Deque assignment operator (PRIVATE)
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param another deque
|
||||
* @return *this
|
||||
*/
|
||||
nsDeque& operator=(const nsDeque& anOther);
|
||||
|
||||
nsDeque& GrowCapacity(void);
|
||||
|
||||
};
|
||||
|
||||
/******************************************************
|
||||
* Here comes the nsDequeIterator class...
|
||||
******************************************************/
|
||||
|
||||
class NS_COM nsDequeIterator {
|
||||
public:
|
||||
|
||||
/**
|
||||
* DequeIterator is an object that knows how to iterate (forward and backward)
|
||||
* a Deque. Normally, you don't need to do this, but there are some special
|
||||
* cases where it is pretty handy, so here you go.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param aQueue is the deque object to be iterated
|
||||
* @param anIndex is the starting position for your iteration
|
||||
*/
|
||||
nsDequeIterator(const nsDeque& aQueue,int anIndex=0);
|
||||
|
||||
/**
|
||||
* DequeIterator is an object that knows how to iterate (forward and backward)
|
||||
* a Deque. Normally, you don't need to do this, but there are some special
|
||||
* cases where it is pretty handy, so here you go.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param aQueue is the deque object to be iterated
|
||||
* @param anIndex is the starting position for your iteration
|
||||
*/
|
||||
nsDequeIterator(const nsDequeIterator& aCopy);
|
||||
|
||||
/**
|
||||
* Moves iterator to first element in deque
|
||||
* @update gess4/18/98
|
||||
* @return this
|
||||
*/
|
||||
nsDequeIterator& First(void);
|
||||
|
||||
/**
|
||||
* Standard assignment operator for deque
|
||||
* @update gess4/18/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
nsDequeIterator& operator=(const nsDequeIterator& aCopy);
|
||||
|
||||
/**
|
||||
* preform ! operation against to iterators to test for equivalence
|
||||
* (or lack thereof)!
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param anIter is the object to be compared to
|
||||
* @return TRUE if NOT equal.
|
||||
*/
|
||||
PRBool operator!=(nsDequeIterator& anIter);
|
||||
|
||||
/**
|
||||
* Compare 2 iterators for equivalence.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param anIter is the other iterator to be compared to
|
||||
* @return TRUE if EQUAL
|
||||
*/
|
||||
PRBool operator<(nsDequeIterator& anIter);
|
||||
|
||||
/**
|
||||
* Compare 2 iterators for equivalence.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param anIter is the other iterator to be compared to
|
||||
* @return TRUE if EQUAL
|
||||
*/
|
||||
PRBool operator==(nsDequeIterator& anIter);
|
||||
|
||||
/**
|
||||
* Compare 2 iterators for equivalence.
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param anIter is the other iterator to be compared to
|
||||
* @return TRUE if EQUAL
|
||||
*/
|
||||
PRBool operator>=(nsDequeIterator& anIter);
|
||||
|
||||
/**
|
||||
* Pre-increment operator
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @return object at preincremented index
|
||||
*/
|
||||
void* operator++();
|
||||
|
||||
/**
|
||||
* Post-increment operator
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param param is ignored
|
||||
* @return object at post-incremented index
|
||||
*/
|
||||
void* operator++(int);
|
||||
|
||||
/**
|
||||
* Pre-decrement operator
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @return object at pre-decremented index
|
||||
*/
|
||||
void* operator--();
|
||||
|
||||
/**
|
||||
* Post-decrement operator
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @param param is ignored
|
||||
* @return object at post-decremented index
|
||||
*/
|
||||
void* operator--(int);
|
||||
|
||||
/**
|
||||
* Retrieve the ptr to the iterators notion of current node
|
||||
*
|
||||
* @update gess4/18/98
|
||||
* @return object at ith index
|
||||
*/
|
||||
void* GetCurrent(void);
|
||||
|
||||
/**
|
||||
* Call this method when you wanto to iterate all the
|
||||
* members of the container, passing a functor along
|
||||
* to call your code.
|
||||
*
|
||||
* @update gess4/20/98
|
||||
* @param aFunctor object to call for each member
|
||||
* @return *this
|
||||
*/
|
||||
void ForEach(nsDequeFunctor& aFunctor) const;
|
||||
|
||||
/**
|
||||
* Call this method when you wanto to iterate all the
|
||||
* members of the container, passing a functor along
|
||||
* to call your code.
|
||||
*
|
||||
* @update gess4/20/98
|
||||
* @param aFunctor object to call for each member
|
||||
* @return *this
|
||||
*/
|
||||
const void* FirstThat(nsDequeFunctor& aFunctor) const;
|
||||
|
||||
protected:
|
||||
|
||||
PRInt32 mIndex;
|
||||
const nsDeque& mDeque;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,706 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
|
||||
/******************************************************************************************
|
||||
MODULE NOTES:
|
||||
|
||||
This file contains the nsStr data structure.
|
||||
This general purpose buffer management class is used as the basis for our strings.
|
||||
It's benefits include:
|
||||
1. An efficient set of library style functions for manipulating nsStrs
|
||||
2. Support for 1 and 2 byte character strings (which can easily be increased to n)
|
||||
3. Unicode awareness and interoperability.
|
||||
|
||||
*******************************************************************************************/
|
||||
|
||||
#include "nsStr.h"
|
||||
#include "bufferRoutines.h"
|
||||
#include "stdio.h" //only used for printf
|
||||
#include "nsCRT.h"
|
||||
#include "nsDeque.h"
|
||||
|
||||
|
||||
static const char* kFoolMsg = "Error: Some fool overwrote the shared buffer.";
|
||||
//static const char* kCallFindChar = "For better performance, call FindChar() for targets whose length==1.";
|
||||
//static const char* kCallRFindChar = "For better performance, call RFindChar() for targets whose length==1.";
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// The following is a memory agent who knows how to recycled (pool) freed memory...
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
/**************************************************************
|
||||
Define the char* (pooled) deallocator class...
|
||||
**************************************************************/
|
||||
|
||||
/*
|
||||
class nsBufferDeallocator: public nsDequeFunctor{
|
||||
public:
|
||||
virtual void* operator()(void* anObject) {
|
||||
char* aCString= (char*)anObject;
|
||||
delete [] aCString;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class nsPoolingMemoryAgent : public nsMemoryAgent{
|
||||
public:
|
||||
nsPoolingMemoryAgent() {
|
||||
memset(mPools,0,sizeof(mPools));
|
||||
}
|
||||
|
||||
virtual ~nsPoolingMemoryAgent() {
|
||||
nsBufferDeallocator theDeallocator;
|
||||
int i=0;
|
||||
for(i=0;i<10;i++){
|
||||
if(mPools[i]){
|
||||
mPools[i]->ForEach(theDeallocator); //now delete the buffers
|
||||
}
|
||||
delete mPools[i];
|
||||
mPools[i]=0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual PRBool Alloc(nsStr& aDest,PRUint32 aCount) {
|
||||
|
||||
//we're given the acount value in charunits; we have to scale up by the charsize.
|
||||
int theShift=4;
|
||||
PRUint32 theNewCapacity=eDefaultSize;
|
||||
while(theNewCapacity<aCount){
|
||||
theNewCapacity<<=1;
|
||||
theShift++;
|
||||
}
|
||||
|
||||
aDest.mCapacity=theNewCapacity++;
|
||||
theShift=(theShift<<aDest.mCharSize)-4;
|
||||
if((theShift<12) && (mPools[theShift])){
|
||||
aDest.mStr=(char*)mPools[theShift]->Pop();
|
||||
}
|
||||
if(!aDest.mStr) {
|
||||
//we're given the acount value in charunits; we have to scale up by the charsize.
|
||||
size_t theSize=(theNewCapacity<<aDest.mCharSize);
|
||||
aDest.mStr=new char[theSize];
|
||||
}
|
||||
aDest.mOwnsBuffer=1;
|
||||
return PRBool(aDest.mStr!=0);
|
||||
|
||||
}
|
||||
|
||||
virtual PRBool Free(nsStr& aDest){
|
||||
if(aDest.mStr){
|
||||
if(aDest.mOwnsBuffer){
|
||||
int theShift=1;
|
||||
unsigned int theValue=1;
|
||||
while((theValue<<=1)<aDest.mCapacity){
|
||||
theShift++;
|
||||
}
|
||||
theShift-=4;
|
||||
if(theShift<12){
|
||||
if(!mPools[theShift]){
|
||||
mPools[theShift]=new nsDeque(0);
|
||||
}
|
||||
mPools[theShift]->Push(aDest.mStr);
|
||||
}
|
||||
else delete [] aDest.mStr; //it's too big. Just delete it.
|
||||
}
|
||||
aDest.mStr=0;
|
||||
aDest.mOwnsBuffer=0;
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
nsDeque* mPools[16];
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
static char* gCommonEmptyBuffer=0;
|
||||
/**
|
||||
*
|
||||
* @update gess10/30/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
char* GetSharedEmptyBuffer() {
|
||||
if(!gCommonEmptyBuffer) {
|
||||
const size_t theDfltSize=5;
|
||||
gCommonEmptyBuffer=new char[theDfltSize];
|
||||
if(gCommonEmptyBuffer){
|
||||
nsCRT::zero(gCommonEmptyBuffer,theDfltSize);
|
||||
gCommonEmptyBuffer[0]=0;
|
||||
}
|
||||
else {
|
||||
printf("%s\n","Memory allocation error!");
|
||||
}
|
||||
}
|
||||
return gCommonEmptyBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method initializes all the members of the nsStr structure
|
||||
*
|
||||
* @update gess10/30/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
void nsStr::Initialize(nsStr& aDest,eCharSize aCharSize) {
|
||||
aDest.mStr=GetSharedEmptyBuffer();
|
||||
aDest.mLength=0;
|
||||
aDest.mCapacity=0;
|
||||
aDest.mCharSize=aCharSize;
|
||||
aDest.mOwnsBuffer=0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method initializes all the members of the nsStr structure
|
||||
* @update gess10/30/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
void nsStr::Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer){
|
||||
aDest.mStr=(aCString) ? aCString : GetSharedEmptyBuffer();
|
||||
aDest.mLength=aLength;
|
||||
aDest.mCapacity=aCapacity;
|
||||
aDest.mCharSize=aCharSize;
|
||||
aDest.mOwnsBuffer=aOwnsBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @update gess10/30/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
nsIMemoryAgent* GetDefaultAgent(void){
|
||||
// static nsPoolingMemoryAgent gDefaultAgent;
|
||||
static nsMemoryAgent gDefaultAgent;
|
||||
return (nsIMemoryAgent*)&gDefaultAgent;
|
||||
}
|
||||
|
||||
/**
|
||||
* This member destroys the memory buffer owned by an nsStr object (if it actually owns it)
|
||||
* @update gess10/30/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
void nsStr::Destroy(nsStr& aDest,nsIMemoryAgent* anAgent) {
|
||||
if((aDest.mStr) && (aDest.mStr!=GetSharedEmptyBuffer())) {
|
||||
if(!anAgent)
|
||||
anAgent=GetDefaultAgent();
|
||||
|
||||
if(anAgent) {
|
||||
anAgent->Free(aDest);
|
||||
}
|
||||
else{
|
||||
printf("%s\n","Leak occured in nsStr.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method gets called when the internal buffer needs
|
||||
* to grow to a given size. The original contents are not preserved.
|
||||
* @update gess 3/30/98
|
||||
* @param aNewLength -- new capacity of string in charSize units
|
||||
* @return void
|
||||
*/
|
||||
void nsStr::EnsureCapacity(nsStr& aString,PRUint32 aNewLength,nsIMemoryAgent* anAgent) {
|
||||
if(aNewLength>aString.mCapacity) {
|
||||
nsIMemoryAgent* theAgent=(anAgent) ? anAgent : GetDefaultAgent();
|
||||
theAgent->Realloc(aString,aNewLength);
|
||||
AddNullTerminator(aString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets called when the internal buffer needs
|
||||
* to grow to a given size. The original contents ARE preserved.
|
||||
* @update gess 3/30/98
|
||||
* @param aNewLength -- new capacity of string in charSize units
|
||||
* @return void
|
||||
*/
|
||||
void nsStr::GrowCapacity(nsStr& aDest,PRUint32 aNewLength,nsIMemoryAgent* anAgent) {
|
||||
if(aNewLength>aDest.mCapacity) {
|
||||
nsStr theTempStr;
|
||||
nsStr::Initialize(theTempStr,aDest.mCharSize);
|
||||
|
||||
nsIMemoryAgent* theAgent=(anAgent) ? anAgent : GetDefaultAgent();
|
||||
EnsureCapacity(theTempStr,aNewLength,theAgent);
|
||||
|
||||
if(aDest.mLength) {
|
||||
Append(theTempStr,aDest,0,aDest.mLength,theAgent);
|
||||
}
|
||||
theAgent->Free(aDest);
|
||||
aDest.mStr = theTempStr.mStr;
|
||||
theTempStr.mStr=0; //make sure to null this out so that you don't lose the buffer you just stole...
|
||||
aDest.mLength=theTempStr.mLength;
|
||||
aDest.mCapacity=theTempStr.mCapacity;
|
||||
aDest.mOwnsBuffer=theTempStr.mOwnsBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the contents of aDest with aSource, up to aCount of chars.
|
||||
* @update gess10/30/98
|
||||
* @param aDest is the nsStr that gets changed.
|
||||
* @param aSource is where chars are copied from
|
||||
* @param aCount is the number of chars copied from aSource
|
||||
*/
|
||||
void nsStr::Assign(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){
|
||||
if(&aDest!=&aSource){
|
||||
Truncate(aDest,0,anAgent);
|
||||
Append(aDest,aSource,anOffset,aCount,anAgent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method appends the given nsStr to this one. Note that we have to
|
||||
* pay attention to the underlying char-size of both structs.
|
||||
* @update gess10/30/98
|
||||
* @param aDest is the nsStr to be manipulated
|
||||
* @param aSource is where char are copied from
|
||||
* @aCount is the number of bytes to be copied
|
||||
*/
|
||||
void nsStr::Append(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){
|
||||
if(anOffset<aSource.mLength){
|
||||
PRUint32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
|
||||
PRUint32 theLength=(anOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-anOffset);
|
||||
if(0<theLength){
|
||||
if(aDest.mLength+theLength > aDest.mCapacity) {
|
||||
GrowCapacity(aDest,aDest.mLength+theLength,anAgent);
|
||||
}
|
||||
|
||||
//now append new chars, starting at offset
|
||||
(*gCopyChars[aSource.mCharSize][aDest.mCharSize])(aDest.mStr,aDest.mLength,aSource.mStr,anOffset,theLength);
|
||||
|
||||
aDest.mLength+=theLength;
|
||||
}
|
||||
}
|
||||
AddNullTerminator(aDest);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method inserts up to "aCount" chars from a source nsStr into a dest nsStr.
|
||||
* @update gess10/30/98
|
||||
* @param aDest is the nsStr that gets changed
|
||||
* @param aDestOffset is where in aDest the insertion is to occur
|
||||
* @param aSource is where chars are copied from
|
||||
* @param aSrcOffset is where in aSource chars are copied from
|
||||
* @param aCount is the number of chars from aSource to be inserted into aDest
|
||||
*/
|
||||
void nsStr::Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUint32 aSrcOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){
|
||||
//there are a few cases for insert:
|
||||
// 1. You're inserting chars into an empty string (assign)
|
||||
// 2. You're inserting onto the end of a string (append)
|
||||
// 3. You're inserting onto the 1..n-1 pos of a string (the hard case).
|
||||
if(0<aSource.mLength){
|
||||
if(aDest.mLength){
|
||||
if(aDestOffset<aDest.mLength){
|
||||
PRInt32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
|
||||
PRInt32 theLength=(aSrcOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-aSrcOffset);
|
||||
|
||||
if(aSrcOffset<aSource.mLength) {
|
||||
//here's the only new case we have to handle.
|
||||
//chars are really being inserted into our buffer...
|
||||
GrowCapacity(aDest,aDest.mLength+theLength,anAgent);
|
||||
|
||||
//shift the chars right by theDelta...
|
||||
(*gShiftChars[aDest.mCharSize][KSHIFTRIGHT])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
|
||||
|
||||
//now insert new chars, starting at offset
|
||||
(*gCopyChars[aSource.mCharSize][aDest.mCharSize])(aDest.mStr,aDestOffset,aSource.mStr,aSrcOffset,theLength);
|
||||
|
||||
//finally, make sure to update the string length...
|
||||
aDest.mLength+=theLength;
|
||||
AddNullTerminator(aDest);
|
||||
|
||||
}//if
|
||||
//else nothing to do!
|
||||
}
|
||||
else Append(aDest,aSource,0,aCount,anAgent);
|
||||
}
|
||||
else Append(aDest,aSource,0,aCount,anAgent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method deletes up to aCount chars from aDest
|
||||
* @update gess10/30/98
|
||||
* @param aDest is the nsStr to be manipulated
|
||||
* @param aDestOffset is where in aDest deletion is to occur
|
||||
* @param aCount is the number of chars to be deleted in aDest
|
||||
*/
|
||||
void nsStr::Delete(nsStr& aDest,PRUint32 aDestOffset,PRUint32 aCount,nsIMemoryAgent* anAgent){
|
||||
if(aDestOffset<aDest.mLength){
|
||||
|
||||
PRUint32 theDelta=aDest.mLength-aDestOffset;
|
||||
PRUint32 theLength=(theDelta<aCount) ? theDelta : aCount;
|
||||
|
||||
if(aDestOffset+theLength<aDest.mLength) {
|
||||
|
||||
//if you're here, it means we're cutting chars out of the middle of the string...
|
||||
//so shift the chars left by theLength...
|
||||
(*gShiftChars[aDest.mCharSize][KSHIFTLEFT])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
|
||||
aDest.mLength-=theLength;
|
||||
}
|
||||
else Truncate(aDest,aDestOffset,anAgent);
|
||||
}//if
|
||||
}
|
||||
|
||||
/**
|
||||
* This method truncates the given nsStr at given offset
|
||||
* @update gess10/30/98
|
||||
* @param aDest is the nsStr to be truncated
|
||||
* @param aDestOffset is where in aDest truncation is to occur
|
||||
*/
|
||||
void nsStr::Truncate(nsStr& aDest,PRUint32 aDestOffset,nsIMemoryAgent* anAgent){
|
||||
if(aDestOffset<aDest.mLength){
|
||||
aDest.mLength=aDestOffset;
|
||||
AddNullTerminator(aDest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method forces the given string to upper or lowercase
|
||||
* @update gess1/7/99
|
||||
* @param aDest is the string you're going to change
|
||||
* @param aToUpper: if TRUE, then we go uppercase, otherwise we go lowercase
|
||||
* @return
|
||||
*/
|
||||
void nsStr::ChangeCase(nsStr& aDest,PRBool aToUpper) {
|
||||
// somehow UnicharUtil return failed, fallback to the old ascii only code
|
||||
gCaseConverters[aDest.mCharSize](aDest.mStr,aDest.mLength,aToUpper);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @update gess1/7/99
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
void nsStr::Trim(nsStr& aDest,const char* aSet,PRBool aEliminateLeading,PRBool aEliminateTrailing){
|
||||
|
||||
if((aDest.mLength>0) && aSet){
|
||||
PRInt32 theIndex=-1;
|
||||
PRInt32 theMax=aDest.mLength;
|
||||
PRInt32 theSetLen=nsCRT::strlen(aSet);
|
||||
|
||||
if(aEliminateLeading) {
|
||||
while(++theIndex<=theMax) {
|
||||
PRUnichar theChar=GetCharAt(aDest,theIndex);
|
||||
PRInt32 thePos=gFindChars[eOneByte](aSet,theSetLen,0,theChar,PR_FALSE);
|
||||
if(kNotFound==thePos)
|
||||
break;
|
||||
}
|
||||
if(0<theIndex) {
|
||||
if(theIndex<theMax) {
|
||||
Delete(aDest,0,theIndex,0);
|
||||
}
|
||||
else Truncate(aDest,0);
|
||||
}
|
||||
}
|
||||
|
||||
if(aEliminateTrailing) {
|
||||
theIndex=aDest.mLength;
|
||||
PRInt32 theNewLen=theIndex;
|
||||
while(--theIndex>0) {
|
||||
PRUnichar theChar=GetCharAt(aDest,theIndex); //read at end now...
|
||||
PRInt32 thePos=gFindChars[eOneByte](aSet,theSetLen,0,theChar,PR_FALSE);
|
||||
if(kNotFound<thePos)
|
||||
theNewLen=theIndex;
|
||||
else break;
|
||||
}
|
||||
if(theNewLen<theMax) {
|
||||
Truncate(aDest,theNewLen);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @update gess1/7/99
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
void nsStr::CompressSet(nsStr& aDest,const char* aSet,PRBool aEliminateLeading,PRBool aEliminateTrailing){
|
||||
Trim(aDest,aSet,aEliminateLeading,aEliminateTrailing);
|
||||
PRUint32 aNewLen=gCompressChars[aDest.mCharSize](aDest.mStr,aDest.mLength,aSet);
|
||||
aDest.mLength=aNewLen;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
Searching methods...
|
||||
**************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* This searches aDest for a given substring
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aDest string to search
|
||||
* @param aTarget is the substring you're trying to find.
|
||||
* @param aIgnorecase indicates case sensitivity of search
|
||||
* @param anOffset tells us where to start the search
|
||||
* @return index in aDest where member of aSet occurs, or -1 if not found
|
||||
*/
|
||||
PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool aIgnoreCase,PRInt32 anOffset) {
|
||||
|
||||
PRInt32 result=kNotFound;
|
||||
|
||||
if((0<aDest.mLength) && (anOffset<(PRInt32)aDest.mLength)) {
|
||||
PRInt32 theMax=aDest.mLength-aTarget.mLength;
|
||||
PRInt32 index=(0<=anOffset) ? anOffset : 0;
|
||||
|
||||
if((aDest.mLength>=aTarget.mLength) && (aTarget.mLength>0) && (index>=0)){
|
||||
PRInt32 theTargetMax=aTarget.mLength;
|
||||
while(index<=theMax) {
|
||||
PRInt32 theSubIndex=-1;
|
||||
PRBool matches=PR_TRUE;
|
||||
while((++theSubIndex<theTargetMax) && (matches)){
|
||||
PRUnichar theChar=(aIgnoreCase) ? nsCRT::ToLower(GetCharAt(aDest,index+theSubIndex)) : GetCharAt(aDest,index+theSubIndex);
|
||||
PRUnichar theTargetChar=(aIgnoreCase) ? nsCRT::ToLower(GetCharAt(aTarget,theSubIndex)) : GetCharAt(aTarget,theSubIndex);
|
||||
matches=PRBool(theChar==theTargetChar);
|
||||
}
|
||||
if(matches) {
|
||||
result=index;
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
} //while
|
||||
}//if
|
||||
}//if
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This searches aDest for a given character
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aDest string to search
|
||||
* @param char is the character you're trying to find.
|
||||
* @param aIgnorecase indicates case sensitivity of search
|
||||
* @param anOffset tells us where to start the search
|
||||
* @return index in aDest where member of aSet occurs, or -1 if not found
|
||||
*/
|
||||
PRInt32 nsStr::FindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRInt32 anOffset) {
|
||||
PRInt32 result=kNotFound;
|
||||
if((0<aDest.mLength) && (anOffset<(PRInt32)aDest.mLength)) {
|
||||
PRUint32 index=(0<=anOffset) ? (PRUint32)anOffset : 0;
|
||||
result=gFindChars[aDest.mCharSize](aDest.mStr,aDest.mLength,index,aChar,aIgnoreCase);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This searches aDest for a character found in aSet.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aDest string to search
|
||||
* @param aSet contains a list of chars to be searched for
|
||||
* @param aIgnorecase indicates case sensitivity of search
|
||||
* @param anOffset tells us where to start the search
|
||||
* @return index in aDest where member of aSet occurs, or -1 if not found
|
||||
*/
|
||||
PRInt32 nsStr::FindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRInt32 anOffset) {
|
||||
|
||||
PRInt32 index=(0<=anOffset) ? anOffset-1 : -1;
|
||||
PRInt32 thePos;
|
||||
|
||||
//Note that the search is inverted here. We're scanning aDest, one char at a time
|
||||
//but doing the search against the given set. That's why we use 0 as the offset below.
|
||||
if((0<aDest.mLength) && (0<aSet.mLength)){
|
||||
while(++index<(PRInt32)aDest.mLength) {
|
||||
PRUnichar theChar=GetCharAt(aDest,index);
|
||||
thePos=gFindChars[aSet.mCharSize](aSet.mStr,aSet.mLength,0,theChar,aIgnoreCase);
|
||||
if(kNotFound!=thePos)
|
||||
return index;
|
||||
} //while
|
||||
}
|
||||
return kNotFound;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
Reverse Searching methods...
|
||||
**************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* This searches aDest (in reverse) for a given substring
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aDest string to search
|
||||
* @param aTarget is the substring you're trying to find.
|
||||
* @param aIgnorecase indicates case sensitivity of search
|
||||
* @param anOffset tells us where to start the search (counting from left)
|
||||
* @return index in aDest where member of aSet occurs, or -1 if not found
|
||||
*/
|
||||
PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool aIgnoreCase,PRInt32 anOffset) {
|
||||
|
||||
PRInt32 result=kNotFound;
|
||||
|
||||
if((0<aDest.mLength) && (anOffset<(PRInt32)aDest.mLength)) {
|
||||
PRInt32 index=(0<=anOffset) ? anOffset : aDest.mLength-1;
|
||||
|
||||
if((aDest.mLength>=aTarget.mLength) && (aTarget.mLength>0) && (index>=0)){
|
||||
|
||||
nsStr theCopy;
|
||||
nsStr::Initialize(theCopy,eOneByte);
|
||||
nsStr::Assign(theCopy,aTarget,0,aTarget.mLength,0);
|
||||
if(aIgnoreCase){
|
||||
nsStr::ChangeCase(theCopy,PR_FALSE); //force to lowercase
|
||||
}
|
||||
|
||||
PRInt32 theTargetMax=theCopy.mLength;
|
||||
while(index>=0) {
|
||||
PRInt32 theSubIndex=-1;
|
||||
PRBool matches=PR_FALSE;
|
||||
if(index+theCopy.mLength<=aDest.mLength) {
|
||||
matches=PR_TRUE;
|
||||
while((++theSubIndex<theTargetMax) && (matches)){
|
||||
PRUnichar theDestChar=(aIgnoreCase) ? nsCRT::ToLower(GetCharAt(aDest,index+theSubIndex)) : GetCharAt(aDest,index+theSubIndex);
|
||||
PRUnichar theTargetChar=GetCharAt(theCopy,theSubIndex);
|
||||
matches=PRBool(theDestChar==theTargetChar);
|
||||
} //while
|
||||
} //if
|
||||
if(matches) {
|
||||
result=index;
|
||||
break;
|
||||
}
|
||||
index--;
|
||||
} //while
|
||||
nsStr::Destroy(theCopy,0);
|
||||
}//if
|
||||
}//if
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This searches aDest (in reverse) for a given character
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aDest string to search
|
||||
* @param char is the character you're trying to find.
|
||||
* @param aIgnorecase indicates case sensitivity of search
|
||||
* @param anOffset tells us where to start the search
|
||||
* @return index in aDest where member of aSet occurs, or -1 if not found
|
||||
*/
|
||||
PRInt32 nsStr::RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRInt32 anOffset) {
|
||||
PRInt32 result=kNotFound;
|
||||
if((0<aDest.mLength) && (anOffset<(PRInt32)aDest.mLength)) {
|
||||
PRUint32 index=(0<=anOffset) ? anOffset : aDest.mLength-1;
|
||||
result=gRFindChars[aDest.mCharSize](aDest.mStr,aDest.mLength,index,aChar,aIgnoreCase);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This searches aDest (in reverese) for a character found in aSet.
|
||||
*
|
||||
* @update gess 3/25/98
|
||||
* @param aDest string to search
|
||||
* @param aSet contains a list of chars to be searched for
|
||||
* @param aIgnorecase indicates case sensitivity of search
|
||||
* @param anOffset tells us where to start the search
|
||||
* @return index in aDest where member of aSet occurs, or -1 if not found
|
||||
*/
|
||||
PRInt32 nsStr::RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRInt32 anOffset) {
|
||||
|
||||
PRInt32 index=(0<=anOffset) ? anOffset : aDest.mLength;
|
||||
PRInt32 thePos;
|
||||
|
||||
//note that the search is inverted here. We're scanning aDest, one char at a time
|
||||
//but doing the search against the given set. That's why we use 0 as the offset below.
|
||||
if(0<aDest.mLength) {
|
||||
while(--index>=0) {
|
||||
PRUnichar theChar=GetCharAt(aDest,index);
|
||||
thePos=gFindChars[aSet.mCharSize](aSet.mStr,aSet.mLength,0,theChar,aIgnoreCase);
|
||||
if(kNotFound!=thePos)
|
||||
return index;
|
||||
} //while
|
||||
}
|
||||
return kNotFound;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare source and dest strings, up to an (optional max) number of chars
|
||||
* @param aDest is the first str to compare
|
||||
* @param aSource is the second str to compare
|
||||
* @param aCount -- if (-1), then we use length of longer string; if (0<aCount) then it gives the max # of chars to compare
|
||||
* @param aIgnorecase tells us whether to search with case sensitivity
|
||||
* @return aDest<aSource=-1;aDest==aSource==0;aDest>aSource=1
|
||||
*/
|
||||
PRInt32 nsStr::Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 aCount,PRBool aIgnoreCase) {
|
||||
PRInt32 result=0;
|
||||
|
||||
if(aCount) {
|
||||
PRInt32 minlen=(aSource.mLength<aDest.mLength) ? aSource.mLength : aDest.mLength;
|
||||
|
||||
if(0==minlen) {
|
||||
if ((aDest.mLength == 0) && (aSource.mLength == 0))
|
||||
return 0;
|
||||
if (aDest.mLength == 0)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
PRInt32 maxlen=(aSource.mLength<aDest.mLength) ? aDest.mLength : aSource.mLength;
|
||||
aCount = (aCount<0) ? maxlen : MinInt(aCount,maxlen);
|
||||
result=(*gCompare[aDest.mCharSize][aSource.mCharSize])(aDest.mStr,aSource.mStr,aCount,aIgnoreCase);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
CBufDescriptor::CBufDescriptor(char* aString,PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength) {
|
||||
mBuffer=aString;
|
||||
mCharSize=eOneByte;
|
||||
mStackBased=aStackBased;
|
||||
mLength=mCapacity=0;
|
||||
if(aString && aCapacity>1) {
|
||||
mCapacity=aCapacity-1;
|
||||
mLength=(-1==aLength) ? strlen(aString) : aLength;
|
||||
if(mLength>PRInt32(mCapacity))
|
||||
mLength=mCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
CBufDescriptor::CBufDescriptor(PRUnichar* aString,PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength) {
|
||||
mBuffer=(char*)aString;
|
||||
mCharSize=eTwoByte;
|
||||
mStackBased=aStackBased;
|
||||
mLength=mCapacity=0;
|
||||
if(aString && aCapacity>1) {
|
||||
mCapacity=aCapacity-1;
|
||||
mLength=(-1==aLength) ? nsCRT::strlen(aString) : aLength;
|
||||
if(mLength>PRInt32(mCapacity))
|
||||
mLength=mCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
|
@ -0,0 +1,343 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
MODULE NOTES:
|
||||
|
||||
1. There are two philosophies to building string classes:
|
||||
A. Hide the underlying buffer & offer API's allow indirect iteration
|
||||
B. Reveal underlying buffer, risk corruption, but gain performance
|
||||
|
||||
We chose the option B for performance reasons.
|
||||
|
||||
2 Our internal buffer always holds capacity+1 bytes.
|
||||
|
||||
The nsStr struct is a simple structure (no methods) that contains
|
||||
the necessary info to be described as a string. This simple struct
|
||||
is manipulated by the static methods provided in this class.
|
||||
(Which effectively makes this a library that works on structs).
|
||||
|
||||
There are also object-based versions called nsString and nsAutoString
|
||||
which use nsStr but makes it look at feel like an object.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
#ifndef _nsStr
|
||||
#define _nsStr
|
||||
|
||||
#include "nscore.h"
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
enum eCharSize {eOneByte=0,eTwoByte=1};
|
||||
#define kDefaultCharSize eTwoByte
|
||||
#define kRadix10 (10)
|
||||
#define kRadix16 (16)
|
||||
#define kAutoDetect (100)
|
||||
#define kRadixUnknown (kAutoDetect+1)
|
||||
const PRInt32 kNotFound = -1;
|
||||
|
||||
|
||||
class nsIMemoryAgent;
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
class NS_COM CBufDescriptor {
|
||||
public:
|
||||
CBufDescriptor(char* aString,PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength=-1);
|
||||
CBufDescriptor(PRUnichar* aString,PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength=-1);
|
||||
|
||||
char* mBuffer;
|
||||
eCharSize mCharSize;
|
||||
PRUint32 mCapacity;
|
||||
PRInt32 mLength;
|
||||
PRBool mStackBased;
|
||||
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
struct NS_COM nsStr {
|
||||
|
||||
/**
|
||||
* This method initializes an nsStr for use
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aString is the nsStr to be initialized
|
||||
* @param aCharSize tells us the requested char size (1 or 2 bytes)
|
||||
*/
|
||||
static void Initialize(nsStr& aDest,eCharSize aCharSize);
|
||||
|
||||
/**
|
||||
* This method initializes an nsStr for use
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aString is the nsStr to be initialized
|
||||
* @param aCharSize tells us the requested char size (1 or 2 bytes)
|
||||
*/
|
||||
static void Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer);
|
||||
|
||||
/**
|
||||
* This method destroys the given nsStr, and *MAY*
|
||||
* deallocate it's memory depending on the setting
|
||||
* of the internal mOwnsBUffer flag.
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aString is the nsStr to be manipulated
|
||||
* @param anAgent is the allocator to be used to the nsStr
|
||||
*/
|
||||
static void Destroy(nsStr& aDest,nsIMemoryAgent* anAgent=0);
|
||||
|
||||
/**
|
||||
* These methods are where memory allocation/reallocation occur.
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aString is the nsStr to be manipulated
|
||||
* @param anAgent is the allocator to be used on the nsStr
|
||||
* @return
|
||||
*/
|
||||
static void EnsureCapacity(nsStr& aString,PRUint32 aNewLength,nsIMemoryAgent* anAgent=0);
|
||||
static void GrowCapacity(nsStr& aString,PRUint32 aNewLength,nsIMemoryAgent* anAgent=0);
|
||||
|
||||
/**
|
||||
* These methods are used to append content to the given nsStr
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the nsStr to be appended to
|
||||
* @param aSource is the buffer to be copied from
|
||||
* @param anOffset tells us where in source to start copying
|
||||
* @param aCount tells us the (max) # of chars to copy
|
||||
* @param anAgent is the allocator to be used for alloc/free operations
|
||||
*/
|
||||
static void Append(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount,nsIMemoryAgent* anAgent=0);
|
||||
|
||||
/**
|
||||
* These methods are used to assign contents of a source string to dest string
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the nsStr to be appended to
|
||||
* @param aSource is the buffer to be copied from
|
||||
* @param anOffset tells us where in source to start copying
|
||||
* @param aCount tells us the (max) # of chars to copy
|
||||
* @param anAgent is the allocator to be used for alloc/free operations
|
||||
*/
|
||||
static void Assign(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount,nsIMemoryAgent* anAgent=0);
|
||||
|
||||
/**
|
||||
* These methods are used to insert content from source string to the dest nsStr
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the nsStr to be appended to
|
||||
* @param aDestOffset tells us where in dest to start insertion
|
||||
* @param aSource is the buffer to be copied from
|
||||
* @param aSrcOffset tells us where in source to start copying
|
||||
* @param aCount tells us the (max) # of chars to insert
|
||||
* @param anAgent is the allocator to be used for alloc/free operations
|
||||
*/
|
||||
static void Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUint32 aSrcOffset,PRInt32 aCount,nsIMemoryAgent* anAgent=0);
|
||||
|
||||
/**
|
||||
* This method deletes chars from the given str.
|
||||
* The given allocator may choose to resize the str as well.
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the nsStr to be deleted from
|
||||
* @param aDestOffset tells us where in dest to start deleting
|
||||
* @param aCount tells us the (max) # of chars to delete
|
||||
* @param anAgent is the allocator to be used for alloc/free operations
|
||||
*/
|
||||
static void Delete(nsStr& aDest,PRUint32 aDestOffset,PRUint32 aCount,nsIMemoryAgent* anAgent=0);
|
||||
|
||||
/**
|
||||
* This method is used to truncate the given string.
|
||||
* The given allocator may choose to resize the str as well (but it's not likely).
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the nsStr to be appended to
|
||||
* @param aDestOffset tells us where in dest to start insertion
|
||||
* @param aSource is the buffer to be copied from
|
||||
* @param aSrcOffset tells us where in source to start copying
|
||||
* @param anAgent is the allocator to be used for alloc/free operations
|
||||
*/
|
||||
static void Truncate(nsStr& aDest,PRUint32 aDestOffset,nsIMemoryAgent* anAgent=0);
|
||||
|
||||
/**
|
||||
* This method is used to perform a case conversion on the given string
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the nsStr to be case shifted
|
||||
* @param toUpper tells us to go upper vs. lower
|
||||
*/
|
||||
static void ChangeCase(nsStr& aDest,PRBool aToUpper);
|
||||
|
||||
|
||||
/**
|
||||
* This method trims chars (given in aSet) from the edges of given buffer
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the buffer to be manipulated
|
||||
* @param aSet tells us which chars to remove from given buffer
|
||||
* @param aEliminateLeading tells us whether to strip chars from the start of the buffer
|
||||
* @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
|
||||
*/
|
||||
static void Trim(nsStr& aDest,const char* aSet,PRBool aEliminateLeading,PRBool aEliminateTrailing);
|
||||
|
||||
/**
|
||||
* This method compresses duplicate runs of a given char from the given buffer
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the buffer to be manipulated
|
||||
* @param aSet tells us which chars to compress from given buffer
|
||||
* @param aChar is the replacement char
|
||||
* @param aEliminateLeading tells us whether to strip chars from the start of the buffer
|
||||
* @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
|
||||
*/
|
||||
static void CompressSet(nsStr& aDest,const char* aSet,PRBool aEliminateLeading,PRBool aEliminateTrailing);
|
||||
|
||||
/**
|
||||
* This method compares the data bewteen two nsStr's
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aStr1 is the first buffer to be compared
|
||||
* @param aStr2 is the 2nd buffer to be compared
|
||||
* @param aCount is the number of chars to compare
|
||||
* @param aIgnorecase tells us whether to use a case-sensitive comparison
|
||||
* @return -1,0,1 depending on <,==,>
|
||||
*/
|
||||
static PRInt32 Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 aCount,PRBool aIgnoreCase);
|
||||
|
||||
/**
|
||||
* These methods scan the given string for 1 or more chars in a given direction
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the nsStr to be searched to
|
||||
* @param aSource (or aChar) is the substr we're looking to find
|
||||
* @param aIgnoreCase tells us whether to search in a case-sensitive manner
|
||||
* @param anOffset tells us where in the dest string to start searching
|
||||
* @return the index of the source (substr) in dest, or -1 (kNotFound) if not found.
|
||||
*/
|
||||
static PRInt32 FindSubstr(const nsStr& aDest,const nsStr& aSource, PRBool aIgnoreCase,PRInt32 anOffset);
|
||||
static PRInt32 FindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRInt32 anOffset);
|
||||
static PRInt32 FindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRInt32 anOffset);
|
||||
|
||||
static PRInt32 RFindSubstr(const nsStr& aDest,const nsStr& aSource, PRBool aIgnoreCase,PRInt32 anOffset);
|
||||
static PRInt32 RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRInt32 anOffset);
|
||||
static PRInt32 RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRInt32 anOffset);
|
||||
|
||||
|
||||
PRUint32 mLength;
|
||||
PRUint32 mCapacity;
|
||||
eCharSize mCharSize;
|
||||
PRBool mOwnsBuffer;
|
||||
|
||||
union {
|
||||
char* mStr;
|
||||
PRUnichar* mUStr;
|
||||
};
|
||||
};
|
||||
|
||||
/**************************************************************
|
||||
A couple of tiny helper methods used in the string classes.
|
||||
**************************************************************/
|
||||
|
||||
inline PRInt32 MinInt(PRInt32 anInt1,PRInt32 anInt2){
|
||||
return (anInt1<anInt2) ? anInt1 : anInt2;
|
||||
}
|
||||
|
||||
inline PRInt32 MaxInt(PRInt32 anInt1,PRInt32 anInt2){
|
||||
return (anInt1<anInt2) ? anInt2 : anInt1;
|
||||
}
|
||||
|
||||
inline void AddNullTerminator(nsStr& aDest) {
|
||||
if(eTwoByte==aDest.mCharSize)
|
||||
aDest.mUStr[aDest.mLength]=0;
|
||||
else aDest.mStr[aDest.mLength]=0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to access a given char in the given string
|
||||
*
|
||||
* @update gess 01/04/99
|
||||
* @param aDest is the nsStr to be appended to
|
||||
* @param anIndex tells us where in dest to get the char from
|
||||
* @return the given char, or 0 if anIndex is out of range
|
||||
*/
|
||||
inline PRUnichar GetCharAt(const nsStr& aDest,PRUint32 anIndex){
|
||||
if(anIndex<aDest.mLength) {
|
||||
return (eTwoByte==aDest.mCharSize) ? aDest.mUStr[anIndex] : aDest.mStr[anIndex];
|
||||
}//if
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
class nsIMemoryAgent {
|
||||
public:
|
||||
virtual PRBool Alloc(nsStr& aString,PRUint32 aCount)=0;
|
||||
virtual PRBool Realloc(nsStr& aString,PRUint32 aCount)=0;
|
||||
virtual PRBool Free(nsStr& aString)=0;
|
||||
};
|
||||
|
||||
class nsMemoryAgent : public nsIMemoryAgent {
|
||||
protected:
|
||||
enum eDelta{eDefaultSize=16};
|
||||
public:
|
||||
|
||||
virtual PRBool Alloc(nsStr& aDest,PRUint32 aCount) {
|
||||
|
||||
//we're given the acount value in charunits; now scale up to next multiple.
|
||||
PRUint32 theNewCapacity=eDefaultSize;
|
||||
while(theNewCapacity<aCount){
|
||||
theNewCapacity<<=1;
|
||||
}
|
||||
|
||||
aDest.mCapacity=theNewCapacity++;
|
||||
PRUint32 theSize=(theNewCapacity<<aDest.mCharSize);
|
||||
aDest.mStr = new char[theSize];
|
||||
|
||||
aDest.mOwnsBuffer=1;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
virtual PRBool Free(nsStr& aDest){
|
||||
if(aDest.mStr){
|
||||
if(aDest.mOwnsBuffer){
|
||||
delete [] aDest.mStr;
|
||||
}
|
||||
aDest.mStr=0;
|
||||
aDest.mOwnsBuffer=0;
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
virtual PRBool Realloc(nsStr& aDest,PRUint32 aCount){
|
||||
Free(aDest);
|
||||
return Alloc(aDest,aCount);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
char* GetSharedEmptyBuffer();
|
||||
nsIMemoryAgent* GetDefaultAgent(void);
|
||||
|
||||
#endif
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,744 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
GENERAL STRING ISSUES:
|
||||
|
||||
1. nsStrings and nsAutoString are always null terminated.
|
||||
2. If you try to set a null char (via SetChar()) a new length is set
|
||||
3. nsCStrings can be upsampled into nsString without data loss
|
||||
4. Char searching is faster than string searching. Use char interfaces
|
||||
if your needs will allow it.
|
||||
5. It's easy to use the stack for nsAutostring buffer storage (fast too!).
|
||||
See the CBufDescriptor class in nsStr.h
|
||||
6. It's ONLY ok to provide non-null-terminated buffers to Append() and Insert()
|
||||
provided you specify a 0<n value for the optional count argument.
|
||||
7. Downsampling from nsString to nsCString is lossy -- don't do it!
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
MODULE NOTES:
|
||||
|
||||
This version of the nsString class offers many improvements over the
|
||||
original version:
|
||||
1. Wide and narrow chars
|
||||
2. Allocators
|
||||
3. Much smarter autostrings
|
||||
4. Subsumable strings
|
||||
5. Memory pools and recycling
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
#ifndef _nsCString_
|
||||
#define _nsCString_
|
||||
|
||||
#include "nscore.h"
|
||||
#include <stdio.h>
|
||||
#include "nsCRT.h"
|
||||
#include "nsStr.h"
|
||||
|
||||
|
||||
class NS_COM nsSubsumeCStr;
|
||||
|
||||
class NS_COM nsCString : public nsStr {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default constructor. Note that we actually allocate a small buffer
|
||||
* to begin with. This is because the "philosophy" of the string class
|
||||
* was to allow developers direct access to the underlying buffer for
|
||||
* performance reasons.
|
||||
*/
|
||||
nsCString(nsIMemoryAgent* anAgent=0);
|
||||
|
||||
|
||||
/**
|
||||
* This constructor accepts an isolatin string
|
||||
* @param aCString is a ptr to a 1-byte cstr
|
||||
*/
|
||||
nsCString(const char* aCString,PRInt32 aLength=-1,nsIMemoryAgent* anAgent=0);
|
||||
|
||||
/**
|
||||
* This constructor accepts a unichar string
|
||||
* @param aCString is a ptr to a 2-byte cstr
|
||||
*/
|
||||
nsCString(const PRUnichar* aString,PRInt32 aLength=-1,nsIMemoryAgent* anAgent=0);
|
||||
|
||||
/**
|
||||
* This is a copy constructor that accepts an nsStr
|
||||
* @param reference to another nsCString
|
||||
*/
|
||||
nsCString(const nsStr&,nsIMemoryAgent* anAgent=0);
|
||||
|
||||
/**
|
||||
* This is our copy constructor
|
||||
* @param reference to another nsCString
|
||||
*/
|
||||
nsCString(const nsCString& aString);
|
||||
|
||||
/**
|
||||
* This constructor takes a subsumestr
|
||||
* @param reference to subsumestr
|
||||
*/
|
||||
nsCString(nsSubsumeCStr& aSubsumeStr);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
*/
|
||||
virtual ~nsCString();
|
||||
|
||||
/**
|
||||
* Retrieve the length of this string
|
||||
* @return string length
|
||||
*/
|
||||
inline PRInt32 Length() const { return (PRInt32)mLength; }
|
||||
|
||||
|
||||
/**
|
||||
* Call this method if you want to force a different string capacity
|
||||
* @update gess7/30/98
|
||||
* @param aLength -- contains new length for mStr
|
||||
* @return
|
||||
*/
|
||||
void SetLength(PRUint32 aLength) {
|
||||
Truncate(aLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the new length of the string.
|
||||
* @param aLength is new string length.
|
||||
* @return nada
|
||||
*/
|
||||
void SetCapacity(PRUint32 aLength);
|
||||
/**
|
||||
* This method truncates this string to given length.
|
||||
*
|
||||
* @param anIndex -- new length of string
|
||||
* @return nada
|
||||
*/
|
||||
void Truncate(PRInt32 anIndex=0);
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether or not the characters in this
|
||||
* string are in sorted order.
|
||||
*
|
||||
* @return TRUE if ordered.
|
||||
*/
|
||||
PRBool IsOrdered(void) const;
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether or not this string has a length of 0
|
||||
*
|
||||
* @return TRUE if empty.
|
||||
*/
|
||||
PRBool IsEmpty(void) const {
|
||||
return PRBool(0==mLength);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Accessor methods...
|
||||
*********************************************************************/
|
||||
|
||||
const char* GetBuffer(void) const;
|
||||
|
||||
|
||||
/**
|
||||
* Get nth character.
|
||||
*/
|
||||
//PRUnichar operator[](PRUint32 anIndex) const;
|
||||
PRUnichar CharAt(PRUint32 anIndex) const;
|
||||
PRUnichar First(void) const;
|
||||
PRUnichar Last(void) const;
|
||||
|
||||
PRBool SetCharAt(PRUnichar aChar,PRUint32 anIndex);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
String creation methods...
|
||||
*********************************************************************/
|
||||
|
||||
/**
|
||||
* Create a new string by appending given string to this
|
||||
* @param aString -- 2nd string to be appended
|
||||
* @return new string
|
||||
*/
|
||||
nsSubsumeCStr operator+(const nsCString& aString);
|
||||
|
||||
/**
|
||||
* create a new string by adding this to the given buffer.
|
||||
* @param aCString is a ptr to cstring to be added to this
|
||||
* @return newly created string
|
||||
*/
|
||||
nsSubsumeCStr operator+(const char* aCString);
|
||||
|
||||
|
||||
/**
|
||||
* create a new string by adding this to the given char.
|
||||
* @param aChar is a char to be added to this
|
||||
* @return newly created string
|
||||
*/
|
||||
nsSubsumeCStr operator+(PRUnichar aChar);
|
||||
nsSubsumeCStr operator+(char aChar);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
Lexomorphic transforms...
|
||||
*********************************************************************/
|
||||
|
||||
/**
|
||||
* Converts chars in this to lowercase
|
||||
* @update gess 7/27/98
|
||||
*/
|
||||
void ToLowerCase();
|
||||
|
||||
|
||||
/**
|
||||
* Converts chars in this to lowercase, and
|
||||
* stores them in aOut
|
||||
* @update gess 7/27/98
|
||||
* @param aOut is a string to contain result
|
||||
*/
|
||||
void ToLowerCase(nsCString& aString) const;
|
||||
|
||||
/**
|
||||
* Converts chars in this to uppercase
|
||||
* @update gess 7/27/98
|
||||
*/
|
||||
void ToUpperCase();
|
||||
|
||||
/**
|
||||
* Converts chars in this to lowercase, and
|
||||
* stores them in a given output string
|
||||
* @update gess 7/27/98
|
||||
* @param aOut is a string to contain result
|
||||
*/
|
||||
void ToUpperCase(nsCString& aString) const;
|
||||
|
||||
|
||||
/**
|
||||
* This method is used to remove all occurances of the
|
||||
* characters found in aSet from this string.
|
||||
*
|
||||
* @param aSet -- characters to be cut from this
|
||||
* @return *this
|
||||
*/
|
||||
nsCString& StripChars(const char* aSet);
|
||||
nsCString& StripChar(PRUnichar aChar);
|
||||
|
||||
/**
|
||||
* This method strips whitespace throughout the string
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
nsCString& StripWhitespace();
|
||||
|
||||
/**
|
||||
* swaps occurence of 1 string for another
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
nsCString& ReplaceChar(PRUnichar aOldChar,PRUnichar aNewChar);
|
||||
nsCString& ReplaceChar(const char* aSet,PRUnichar aNewChar);
|
||||
|
||||
PRInt32 CountChar(PRUnichar aChar);
|
||||
|
||||
/**
|
||||
* This method trims characters found in aTrimSet from
|
||||
* either end of the underlying string.
|
||||
*
|
||||
* @param aTrimSet -- contains chars to be trimmed from
|
||||
* both ends
|
||||
* @return this
|
||||
*/
|
||||
nsCString& Trim(const char* aSet,PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE);
|
||||
|
||||
/**
|
||||
* This method strips whitespace from string.
|
||||
* You can control whether whitespace is yanked from
|
||||
* start and end of string as well.
|
||||
*
|
||||
* @param aEliminateLeading controls stripping of leading ws
|
||||
* @param aEliminateTrailing controls stripping of trailing ws
|
||||
* @return this
|
||||
*/
|
||||
nsCString& CompressSet(const char* aSet, PRUnichar aChar,PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE);
|
||||
|
||||
/**
|
||||
* This method strips whitespace from string.
|
||||
* You can control whether whitespace is yanked from
|
||||
* start and end of string as well.
|
||||
*
|
||||
* @param aEliminateLeading controls stripping of leading ws
|
||||
* @param aEliminateTrailing controls stripping of trailing ws
|
||||
* @return this
|
||||
*/
|
||||
nsCString& CompressWhitespace( PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE);
|
||||
|
||||
/**********************************************************************
|
||||
string conversion methods...
|
||||
*********************************************************************/
|
||||
|
||||
operator char*() {return mStr;}
|
||||
operator const char*() const {return (const char*)mStr;}
|
||||
|
||||
/**
|
||||
* This method constructs a new nsCString on the stack that is a copy
|
||||
* of this string.
|
||||
*
|
||||
*/
|
||||
nsCString* ToNewString() const;
|
||||
|
||||
/**
|
||||
* Creates an ISOLatin1 clone of this string
|
||||
* @return ptr to new isolatin1 string
|
||||
*/
|
||||
char* ToNewCString() const;
|
||||
|
||||
/**
|
||||
* Creates a unicode clone of this string
|
||||
* @return ptr to new unicode string
|
||||
*/
|
||||
PRUnichar* ToNewUnicode() const;
|
||||
|
||||
/**
|
||||
* Copies data from internal buffer onto given char* buffer
|
||||
* @param aBuf is the buffer where data is stored
|
||||
* @param aBuflength is the max # of chars to move to buffer
|
||||
* @return ptr to given buffer
|
||||
*/
|
||||
char* ToCString(char* aBuf,PRUint32 aBufLength,PRUint32 anOffset=0) const;
|
||||
|
||||
/**
|
||||
* Perform string to float conversion.
|
||||
* @param aErrorCode will contain error if one occurs
|
||||
* @return float rep of string value
|
||||
*/
|
||||
float ToFloat(PRInt32* aErrorCode) const;
|
||||
|
||||
/**
|
||||
* Try to derive the radix from the value contained in this string
|
||||
* @return kRadix10, kRadix16 or kAutoDetect (meaning unknown)
|
||||
*/
|
||||
PRUint32 DetermineRadix(void);
|
||||
|
||||
/**
|
||||
* Perform string to int conversion.
|
||||
* @param aErrorCode will contain error if one occurs
|
||||
* @return int rep of string value
|
||||
*/
|
||||
PRInt32 ToInteger(PRInt32* aErrorCode,PRUint32 aRadix=kRadix10) const;
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
String manipulation methods...
|
||||
*********************************************************************/
|
||||
|
||||
/**
|
||||
* Functionally equivalent to assign or operator=
|
||||
*
|
||||
*/
|
||||
nsCString& SetString(const char* aString,PRInt32 aLength=-1) {return Assign(aString,aLength);}
|
||||
nsCString& SetString(const nsStr& aString,PRInt32 aLength=-1) {return Assign(aString,aLength);}
|
||||
|
||||
/**
|
||||
* assign given string to this string
|
||||
* @param aStr: buffer to be assigned to this
|
||||
* @param alength is the length of the given str (or -1)
|
||||
if you want me to determine its length
|
||||
* @return this
|
||||
*/
|
||||
nsCString& Assign(const nsCString& aString,PRInt32 aCount=-1);
|
||||
nsCString& Assign(const char* aString,PRInt32 aCount=-1);
|
||||
nsCString& Assign(PRUnichar aChar);
|
||||
nsCString& Assign(char aChar);
|
||||
|
||||
/**
|
||||
* here come a bunch of assignment operators...
|
||||
* @param aString: string to be added to this
|
||||
* @return this
|
||||
*/
|
||||
nsCString& operator=(const nsCString& aString) {return Assign(aString);}
|
||||
nsCString& operator=(PRUnichar aChar) {return Assign(aChar);}
|
||||
nsCString& operator=(char aChar) {return Assign(aChar);}
|
||||
nsCString& operator=(const char* aCString) {return Assign(aCString);}
|
||||
#ifdef AIX
|
||||
nsCString& operator=(const nsSubsumeCStr& aSubsumeString); // AIX requires a const here
|
||||
#else
|
||||
nsCString& operator=(nsSubsumeCStr& aSubsumeString);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Here's a bunch of append mehtods for varying types...
|
||||
* @param aString : string to be appended to this
|
||||
* @return this
|
||||
*/
|
||||
nsCString& operator+=(const nsCString& aString){return Append(aString,aString.mLength);}
|
||||
nsCString& operator+=(const char* aCString) {return Append(aCString);}
|
||||
nsCString& operator+=(PRUnichar aChar){return Append(aChar);}
|
||||
nsCString& operator+=(char aChar){return Append(aChar);}
|
||||
|
||||
/*
|
||||
* Appends n characters from given string to this,
|
||||
* This version computes the length of your given string
|
||||
*
|
||||
* @param aString is the source to be appended to this
|
||||
* @return number of chars copied
|
||||
*/
|
||||
nsCString& Append(const nsCString& aString) {return Append(aString,aString.mLength);}
|
||||
|
||||
|
||||
/*
|
||||
* Appends n characters from given string to this,
|
||||
*
|
||||
* @param aString is the source to be appended to this
|
||||
* @param aCount -- number of chars to copy; -1 tells us to compute the strlen for you
|
||||
* @return number of chars copied
|
||||
*/
|
||||
nsCString& Append(const nsCString& aString,PRInt32 aCount);
|
||||
nsCString& Append(const char* aString,PRInt32 aCount=-1);
|
||||
nsCString& Append(PRUnichar aChar);
|
||||
nsCString& Append(char aChar);
|
||||
nsCString& Append(PRInt32 aInteger,PRInt32 aRadix=10); //radix=8,10 or 16
|
||||
nsCString& Append(float aFloat);
|
||||
|
||||
/*
|
||||
* Copies n characters from this string to given string,
|
||||
* starting at the leftmost offset.
|
||||
*
|
||||
*
|
||||
* @param aCopy -- Receiving string
|
||||
* @param aCount -- number of chars to copy
|
||||
* @return number of chars copied
|
||||
*/
|
||||
PRUint32 Left(nsCString& aCopy,PRInt32 aCount) const;
|
||||
|
||||
/*
|
||||
* Copies n characters from this string to given string,
|
||||
* starting at the given offset.
|
||||
*
|
||||
*
|
||||
* @param aCopy -- Receiving string
|
||||
* @param aCount -- number of chars to copy
|
||||
* @param anOffset -- position where copying begins
|
||||
* @return number of chars copied
|
||||
*/
|
||||
PRUint32 Mid(nsCString& aCopy,PRUint32 anOffset,PRInt32 aCount) const;
|
||||
|
||||
/*
|
||||
* Copies n characters from this string to given string,
|
||||
* starting at rightmost char.
|
||||
*
|
||||
*
|
||||
* @param aCopy -- Receiving string
|
||||
* @param aCount -- number of chars to copy
|
||||
* @return number of chars copied
|
||||
*/
|
||||
PRUint32 Right(nsCString& aCopy,PRInt32 aCount) const;
|
||||
|
||||
/*
|
||||
* This method inserts n chars from given string into this
|
||||
* string at str[anOffset].
|
||||
*
|
||||
* @param aCopy -- String to be inserted into this
|
||||
* @param anOffset -- insertion position within this str
|
||||
* @param aCount -- number of chars to be copied from aCopy
|
||||
* @return number of chars inserted into this.
|
||||
*/
|
||||
nsCString& Insert(const nsCString& aCopy,PRUint32 anOffset,PRInt32 aCount=-1);
|
||||
|
||||
/**
|
||||
* Insert a given string into this string at
|
||||
* a specified offset.
|
||||
*
|
||||
* @param aString* to be inserted into this string
|
||||
* @param anOffset is insert pos in str
|
||||
* @return the number of chars inserted into this string
|
||||
*/
|
||||
nsCString& Insert(const char* aChar,PRUint32 anOffset,PRInt32 aCount=-1);
|
||||
|
||||
/**
|
||||
* Insert a single char into this string at
|
||||
* a specified offset.
|
||||
*
|
||||
* @param character to be inserted into this string
|
||||
* @param anOffset is insert pos in str
|
||||
* @return the number of chars inserted into this string
|
||||
*/
|
||||
nsCString& Insert(PRUnichar aChar,PRUint32 anOffset);
|
||||
nsCString& Insert(char aChar,PRUint32 anOffset);
|
||||
|
||||
/*
|
||||
* This method is used to cut characters in this string
|
||||
* starting at anOffset, continuing for aCount chars.
|
||||
*
|
||||
* @param anOffset -- start pos for cut operation
|
||||
* @param aCount -- number of chars to be cut
|
||||
* @return *this
|
||||
*/
|
||||
nsCString& Cut(PRUint32 anOffset,PRInt32 aCount);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
Searching methods...
|
||||
*********************************************************************/
|
||||
|
||||
/**
|
||||
* Search for given character within this string.
|
||||
* This method does so by using a binary search,
|
||||
* so your string HAD BETTER BE ORDERED!
|
||||
*
|
||||
* @param aChar is the unicode char to be found
|
||||
* @return offset in string, or -1 (kNotFound)
|
||||
*/
|
||||
PRInt32 BinarySearch(PRUnichar aChar) const;
|
||||
|
||||
/**
|
||||
* Search for given substring within this string
|
||||
*
|
||||
* @param aString is substring to be sought in this
|
||||
* @param anOffset tells us where in this strig to start searching
|
||||
* @return offset in string, or -1 (kNotFound)
|
||||
*/
|
||||
PRInt32 Find(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
|
||||
PRInt32 Find(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
|
||||
PRInt32 Find(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
|
||||
|
||||
/**
|
||||
* Search for given char within this string
|
||||
*
|
||||
* @param aString is substring to be sought in this
|
||||
* @param anOffset tells us where in this strig to start searching
|
||||
* @param aIgnoreCase selects case sensitivity
|
||||
* @return find pos in string, or -1 (kNotFound)
|
||||
*/
|
||||
PRInt32 Find(PRUnichar aChar,PRInt32 offset=-1,PRBool aIgnoreCase=PR_FALSE) const;
|
||||
PRInt32 FindChar(PRUnichar aChar,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
|
||||
|
||||
/**
|
||||
* This method searches this string for the first character
|
||||
* found in the given string
|
||||
* @param aString contains set of chars to be found
|
||||
* @param anOffset tells us where to start searching in this
|
||||
* @return -1 if not found, else the offset in this
|
||||
*/
|
||||
PRInt32 FindCharInSet(const char* aString,PRInt32 anOffset=-1) const;
|
||||
PRInt32 FindCharInSet(const PRUnichar* aString,PRInt32 anOffset=-1) const;
|
||||
PRInt32 FindCharInSet(const nsStr& aString,PRInt32 anOffset=-1) const;
|
||||
|
||||
|
||||
/**
|
||||
* This methods scans the string backwards, looking for the given string
|
||||
* @param aString is substring to be sought in this
|
||||
* @param aIgnoreCase tells us whether or not to do caseless compare
|
||||
* @return offset in string, or -1 (kNotFound)
|
||||
*/
|
||||
PRInt32 RFind(const char* aCString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
|
||||
PRInt32 RFind(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
|
||||
PRInt32 RFind(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
|
||||
|
||||
|
||||
/**
|
||||
* Search for given char within this string
|
||||
*
|
||||
* @param aString is substring to be sought in this
|
||||
* @param anOffset tells us where in this strig to start searching
|
||||
* @param aIgnoreCase selects case sensitivity
|
||||
* @return find pos in string, or -1 (kNotFound)
|
||||
*/
|
||||
PRInt32 RFind(PRUnichar aChar,PRInt32 offset=-1,PRBool aIgnoreCase=PR_FALSE) const;
|
||||
PRInt32 RFindChar(PRUnichar aChar,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
|
||||
|
||||
/**
|
||||
* This method searches this string for the last character
|
||||
* found in the given string
|
||||
* @param aString contains set of chars to be found
|
||||
* @param anOffset tells us where to start searching in this
|
||||
* @return -1 if not found, else the offset in this
|
||||
*/
|
||||
PRInt32 RFindCharInSet(const char* aString,PRInt32 anOffset=-1) const;
|
||||
PRInt32 RFindCharInSet(const PRUnichar* aString,PRInt32 anOffset=-1) const;
|
||||
PRInt32 RFindCharInSet(const nsStr& aString,PRInt32 anOffset=-1) const;
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
Comparison methods...
|
||||
*********************************************************************/
|
||||
|
||||
/**
|
||||
* Compares a given string type to this string.
|
||||
* @update gess 7/27/98
|
||||
* @param S is the string to be compared
|
||||
* @param aIgnoreCase tells us how to treat case
|
||||
* @param aCount tells us how many chars to compare
|
||||
* @return -1,0,1
|
||||
*/
|
||||
virtual PRInt32 Compare(const nsStr &aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
virtual PRInt32 Compare(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
virtual PRInt32 Compare(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
|
||||
/**
|
||||
* These methods compare a given string type to this one
|
||||
* @param aString is the string to be compared to this
|
||||
* @return TRUE or FALSE
|
||||
*/
|
||||
PRBool operator==(const nsStr &aString) const;
|
||||
PRBool operator==(const char* aString) const;
|
||||
PRBool operator==(const PRUnichar* aString) const;
|
||||
|
||||
/**
|
||||
* These methods perform a !compare of a given string type to this
|
||||
* @param aString is the string to be compared to this
|
||||
* @return TRUE
|
||||
*/
|
||||
PRBool operator!=(const nsStr &aString) const;
|
||||
PRBool operator!=(const char* aString) const;
|
||||
PRBool operator!=(const PRUnichar* aString) const;
|
||||
|
||||
/**
|
||||
* These methods test if a given string is < than this
|
||||
* @param aString is the string to be compared to this
|
||||
* @return TRUE or FALSE
|
||||
*/
|
||||
PRBool operator<(const nsStr &aString) const;
|
||||
PRBool operator<(const char* aString) const;
|
||||
PRBool operator<(const PRUnichar* aString) const;
|
||||
|
||||
/**
|
||||
* These methods test if a given string is > than this
|
||||
* @param aString is the string to be compared to this
|
||||
* @return TRUE or FALSE
|
||||
*/
|
||||
PRBool operator>(const nsStr &S) const;
|
||||
PRBool operator>(const char* aString) const;
|
||||
PRBool operator>(const PRUnichar* aString) const;
|
||||
|
||||
/**
|
||||
* These methods test if a given string is <= than this
|
||||
* @param aString is the string to be compared to this
|
||||
* @return TRUE or FALSE
|
||||
*/
|
||||
PRBool operator<=(const nsStr &S) const;
|
||||
PRBool operator<=(const char* aString) const;
|
||||
PRBool operator<=(const PRUnichar* aString) const;
|
||||
|
||||
/**
|
||||
* These methods test if a given string is >= than this
|
||||
* @param aString is the string to be compared to this
|
||||
* @return TRUE or FALSE
|
||||
*/
|
||||
PRBool operator>=(const nsStr &S) const;
|
||||
PRBool operator>=(const char* aString) const;
|
||||
PRBool operator>=(const PRUnichar* aString) const;
|
||||
|
||||
/**
|
||||
* Compare this to given string; note that we compare full strings here.
|
||||
* The optional length argument just lets us know how long the given string is.
|
||||
* If you provide a length, it is compared to length of this string as an
|
||||
* optimization.
|
||||
*
|
||||
* @param aString -- the string to compare to this
|
||||
* @param aCount -- number of chars in given string you want to compare
|
||||
* @return TRUE if equal
|
||||
*/
|
||||
PRBool Equals(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
PRBool Equals(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
PRBool Equals(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
|
||||
PRBool EqualsIgnoreCase(const nsStr& aString) const;
|
||||
PRBool EqualsIgnoreCase(const char* aString,PRInt32 aCount=-1) const;
|
||||
PRBool EqualsIgnoreCase(const PRUnichar* aString,PRInt32 aCount=-1) const;
|
||||
|
||||
|
||||
static void Recycle(nsCString* aString);
|
||||
static nsCString* CreateString(void);
|
||||
|
||||
|
||||
nsIMemoryAgent* mAgent;
|
||||
|
||||
};
|
||||
|
||||
//ostream& operator<<(ostream& aStream,const nsCString& aString);
|
||||
//virtual void DebugDump(ostream& aStream) const;
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Here comes the AutoString class which uses internal memory
|
||||
(typically found on the stack) for its default buffer.
|
||||
If the buffer needs to grow, it gets reallocated on the heap.
|
||||
**************************************************************/
|
||||
|
||||
class NS_COM nsCAutoString : public nsCString {
|
||||
public:
|
||||
|
||||
nsCAutoString();
|
||||
nsCAutoString(const char* aString,PRInt32 aLength=-1);
|
||||
nsCAutoString(CBufDescriptor& aBuffer);
|
||||
nsCAutoString(const PRUnichar* aString,PRInt32 aLength=-1);
|
||||
nsCAutoString(const nsStr& aString);
|
||||
nsCAutoString(const nsCAutoString& aString);
|
||||
|
||||
#ifdef AIX
|
||||
nsCAutoString(const nsSubsumeCStr& aSubsumeStr); // AIX requires a const
|
||||
#else
|
||||
nsCAutoString(nsSubsumeCStr& aSubsumeStr);
|
||||
#endif // AIX
|
||||
nsCAutoString(PRUnichar aChar);
|
||||
virtual ~nsCAutoString();
|
||||
|
||||
nsCAutoString& operator=(const nsCString& aString) {nsCString::Assign(aString); return *this;}
|
||||
nsCAutoString& operator=(const char* aCString) {nsCString::Assign(aCString); return *this;}
|
||||
nsCAutoString& operator=(PRUnichar aChar) {nsCString::Assign(aChar); return *this;}
|
||||
nsCAutoString& operator=(char aChar) {nsCString::Assign(aChar); return *this;}
|
||||
|
||||
|
||||
char mBuffer[32];
|
||||
};
|
||||
|
||||
/***************************************************************
|
||||
The subsumestr class is very unusual.
|
||||
It differs from a normal string in that it doesn't use normal
|
||||
copy semantics when another string is assign to this.
|
||||
Instead, it "steals" the contents of the source string.
|
||||
|
||||
This is very handy for returning nsString classes as part of
|
||||
an operator+(...) for example, in that it cuts down the number
|
||||
of copy operations that must occur.
|
||||
|
||||
You should probably not use this class unless you really know
|
||||
what you're doing.
|
||||
***************************************************************/
|
||||
class NS_COM nsSubsumeCStr : public nsCString {
|
||||
public:
|
||||
nsSubsumeCStr(nsStr& aString);
|
||||
nsSubsumeCStr(PRUnichar* aString,PRBool assumeOwnership,PRInt32 aLength=-1);
|
||||
nsSubsumeCStr(char* aString,PRBool assumeOwnership,PRInt32 aLength=-1);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
#ifndef nscore_h___
|
||||
#define nscore_h___
|
||||
|
||||
#ifdef _WIN32
|
||||
#define NS_WIN32 1
|
||||
#endif
|
||||
|
||||
#if defined(__unix)
|
||||
#define NS_UNIX 1
|
||||
#endif
|
||||
|
||||
#define NS_BASE
|
||||
#define PR_TRUE 1
|
||||
#define PR_FALSE 0
|
||||
#define NS_ERROR_ILLEGAL_VALUE -1
|
||||
#define NS_OK 0
|
||||
#define NS_COM
|
||||
|
||||
#define kEOF 11111
|
||||
#define int32 int
|
||||
|
||||
|
||||
/** ucs2 datatype for 2 byte unicode characters */
|
||||
typedef unsigned short int PRUint16;
|
||||
|
||||
/** ucs4 datatype for 4 byte unicode characters */
|
||||
typedef unsigned int PRUint32;
|
||||
|
||||
typedef char PRUint8;
|
||||
typedef int PRInt32;
|
||||
typedef short int PRInt16;
|
||||
typedef short int PRUnichar;
|
||||
typedef char PRBool;
|
||||
#define PR_TRUE 1
|
||||
#define PR_FALSE 0
|
||||
|
||||
|
||||
#ifdef NS_UCS4
|
||||
typedef int PRUnichar;
|
||||
#else
|
||||
typedef short int PRUnichar;
|
||||
#endif
|
||||
|
||||
/// The preferred symbol for null.
|
||||
#define nsnull 0
|
||||
|
||||
/* Define brackets for protecting C code from C++ */
|
||||
#ifdef __cplusplus
|
||||
#define NS_BEGIN_EXTERN_C extern "C" {
|
||||
#define NS_END_EXTERN_C }
|
||||
#else
|
||||
#define NS_BEGIN_EXTERN_C
|
||||
#define NS_END_EXTERN_C
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Import/export defines */
|
||||
|
||||
#ifdef NS_WIN32
|
||||
#define NS_IMPORT _declspec(dllimport)
|
||||
#define NS_IMPORT_(type) type _declspec(dllimport) __stdcall
|
||||
#define NS_EXPORT _declspec(dllexport)
|
||||
// XXX NS_EXPORT_ defined in nsCOm.h (xpcom) differs in where the __declspec
|
||||
// is placed. It needs to be done this way to make the 4.x compiler happy...
|
||||
#undef NS_EXPORT_
|
||||
#define NS_EXPORT_(type) type _declspec(dllexport) __stdcall
|
||||
#elif defined(XP_MAC)
|
||||
|
||||
#define NS_IMPORT
|
||||
#define NS_IMPORT_(type) type
|
||||
|
||||
// XXX NS_EXPORT_ defined in nsCom.h actually does an export. Here it's just sugar.
|
||||
#undef NS_EXPORT
|
||||
#undef NS_EXPORT_
|
||||
|
||||
#define NS_EXPORT
|
||||
#define NS_EXPORT_(type) type
|
||||
|
||||
#else
|
||||
/* XXX do something useful? */
|
||||
#define NS_IMPORT
|
||||
#define NS_IMPORT_(type) type
|
||||
#define NS_EXPORT
|
||||
#define NS_EXPORT_(type) type
|
||||
#endif
|
||||
|
||||
#ifdef _IMPL_NS_NET
|
||||
#define NS_NET NS_EXPORT
|
||||
#else
|
||||
#define NS_NET NS_IMPORT
|
||||
#endif
|
||||
|
||||
#ifdef _IMPL_NS_DOM
|
||||
#define NS_DOM NS_EXPORT
|
||||
#else
|
||||
#define NS_DOM NS_IMPORT
|
||||
#endif
|
||||
|
||||
#ifdef _IMPL_NS_WIDGET
|
||||
#define NS_WIDGET NS_EXPORT
|
||||
#else
|
||||
#define NS_WIDGET NS_IMPORT
|
||||
#endif
|
||||
|
||||
#ifdef _IMPL_NS_VIEW
|
||||
#define NS_VIEW NS_EXPORT
|
||||
#else
|
||||
#define NS_VIEW NS_IMPORT
|
||||
#endif
|
||||
|
||||
#ifdef _IMPL_NS_GFXNONXP
|
||||
#define NS_GFXNONXP NS_EXPORT
|
||||
#define NS_GFXNONXP_(type) NS_EXPORT_(type)
|
||||
#else
|
||||
#define NS_GFXNONXP NS_IMPORT
|
||||
#define NS_GFXNONXP_(type) NS_IMPORT_(type)
|
||||
#endif
|
||||
|
||||
#ifdef _IMPL_NS_GFX
|
||||
#define NS_GFX NS_EXPORT
|
||||
#define NS_GFX_(type) NS_EXPORT_(type)
|
||||
#else
|
||||
#define NS_GFX NS_IMPORT
|
||||
#define NS_GFX_(type) NS_IMPORT_(type)
|
||||
#endif
|
||||
|
||||
#ifdef _IMPL_NS_PLUGIN
|
||||
#define NS_PLUGIN NS_EXPORT
|
||||
#else
|
||||
#define NS_PLUGIN NS_IMPORT
|
||||
#endif
|
||||
|
||||
#endif /* nscore_h___ */
|
|
@ -0,0 +1,134 @@
|
|||
|
||||
#include "tokens.h"
|
||||
#include "CScanner.h"
|
||||
#include "nsString.h"
|
||||
|
||||
static nsCAutoString gIdentChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_");
|
||||
static nsCAutoString gDigits("0123456789");
|
||||
static nsCAutoString gWhitespace(" \n\r\t\b");
|
||||
static nsCAutoString gNewlines("\r\n");
|
||||
|
||||
|
||||
int CIdentifierToken::consume(PRUnichar aChar, CScanner& aScanner) {
|
||||
mTextValue=aChar;
|
||||
int result=aScanner.readWhile(mTextValue,gIdentChars,false);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
int CNumberToken::consume(PRUnichar aChar, CScanner& aScanner) {
|
||||
mTextValue=aChar;
|
||||
int result=aScanner.readWhile(mTextValue,gDigits,false);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
int CWhitespaceToken::consume(PRUnichar aChar, CScanner& aScanner) {
|
||||
mTextValue=aChar;
|
||||
int result=aScanner.readWhile(mTextValue,gWhitespace,false);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
bool validOperator(nsCString& aString) {
|
||||
bool result=false;
|
||||
int len=aString.Length();
|
||||
|
||||
switch(len) {
|
||||
case 1: return true;
|
||||
case 3:
|
||||
result=((0==aString.Compare("<<=")) ||(0==aString.Compare(">>=")));
|
||||
break;
|
||||
default:
|
||||
switch(aString[0]) {
|
||||
case '+': case '=':
|
||||
case '&': case '|':
|
||||
case '<': case '>':
|
||||
if((aString[1]==aString[0]) || (aString[1]=='='))
|
||||
result=true;
|
||||
break;
|
||||
case '-':
|
||||
if((aString[1]==aString[0]) || (aString[1]=='>'))
|
||||
result=true;
|
||||
break;
|
||||
case ':':
|
||||
if((len==2) && (aString[1]==aString[0]))
|
||||
result=true;
|
||||
break;
|
||||
case '*': case '/':
|
||||
case '^': case '!':
|
||||
case '~': case '%':
|
||||
if((aString[1]=='='))
|
||||
result=true;
|
||||
break;
|
||||
case '(':
|
||||
result=aString[1]==')'; break;
|
||||
case '[':
|
||||
result=aString[1]==']'; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int COperatorToken::consume(PRUnichar aChar, CScanner& aScanner) {
|
||||
int result=0;
|
||||
mTextValue=aChar;
|
||||
while((validOperator(mTextValue)) && (kNoError==result)){
|
||||
result=aScanner.getChar(aChar);
|
||||
mTextValue+=aChar;
|
||||
}
|
||||
if(kNoError==result) {
|
||||
mTextValue.Truncate(mTextValue.mLength-1);
|
||||
aScanner.push(aChar);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
int CCommentToken::consume(PRUnichar aChar, CScanner& aScanner) {
|
||||
int result=0;
|
||||
if('/'==mTextValue[1]) {
|
||||
result=aScanner.readUntil(mTextValue,gNewlines,false);
|
||||
}
|
||||
else {
|
||||
bool done=false;
|
||||
nsCAutoString temp("/");
|
||||
while((0==result) && (false==done)){
|
||||
aScanner.readUntil(mTextValue,temp,true);
|
||||
PRUnichar theChar=mTextValue[mTextValue.Length()-2];
|
||||
done=('*'==theChar);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
int CCompilerDirectiveToken::consume(PRUnichar aChar, CScanner& aScanner) {
|
||||
mTextValue=aChar;
|
||||
int result=aScanner.readUntil(mTextValue,gNewlines,false);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
int CSemicolonToken::consume(PRUnichar aChar, CScanner& aScanner) {
|
||||
int result=0;
|
||||
mTextValue=aChar;
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
int CNewlineToken::consume(PRUnichar aChar, CScanner& aScanner) {
|
||||
mTextValue=aChar;
|
||||
int result=aScanner.readWhile(mTextValue,gNewlines,false);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
int CQuotedStringToken::consume(PRUnichar aChar, CScanner& aScanner) {
|
||||
mTextValue=aChar;
|
||||
int result=aScanner.readUntil(mTextValue,aChar,true);
|
||||
return result;
|
||||
};
|
|
@ -0,0 +1,90 @@
|
|||
|
||||
#ifndef _CPPTOKENS
|
||||
#define _CPPTOKENS
|
||||
|
||||
#include "CToken.h"
|
||||
|
||||
enum eCPPTokens
|
||||
{
|
||||
eToken_unknown=2000,
|
||||
|
||||
eToken_whitespace,
|
||||
eToken_comment,
|
||||
eToken_identifier,
|
||||
eToken_number,
|
||||
eToken_operator,
|
||||
eToken_semicolon,
|
||||
eToken_newline,
|
||||
eToken_compilerdirective,
|
||||
eToken_quotedstring,
|
||||
eToken_last
|
||||
};
|
||||
|
||||
class CIdentifierToken : public CToken {
|
||||
public:
|
||||
CIdentifierToken() : CToken() { }
|
||||
virtual int consume(PRUnichar aChar,CScanner& aScanner);
|
||||
virtual int getTokenType(void) {return eToken_identifier;}
|
||||
};
|
||||
|
||||
class CNumberToken: public CToken {
|
||||
public:
|
||||
CNumberToken() : CToken() { }
|
||||
virtual int consume(PRUnichar aChar,CScanner& aScanner);
|
||||
virtual int getTokenType(void) {return eToken_number;}
|
||||
};
|
||||
|
||||
class CWhitespaceToken: public CToken {
|
||||
public:
|
||||
CWhitespaceToken() : CToken() { }
|
||||
virtual int consume(PRUnichar aChar,CScanner& aScanner);
|
||||
virtual int getTokenType(void) {return eToken_whitespace;}
|
||||
};
|
||||
|
||||
class COperatorToken: public CToken {
|
||||
public:
|
||||
COperatorToken() : CToken() { }
|
||||
virtual int consume(PRUnichar aChar,CScanner& aScanner);
|
||||
virtual int getTokenType(void) {return eToken_operator;}
|
||||
};
|
||||
|
||||
class CCommentToken: public CToken {
|
||||
public:
|
||||
CCommentToken(PRUnichar the2ndChar) : CToken() {
|
||||
PRUnichar theBuf[3]={'/',0,0};
|
||||
theBuf[1]=the2ndChar;
|
||||
mTextValue.Assign(theBuf);
|
||||
}
|
||||
virtual int consume(PRUnichar aChar,CScanner& aScanner);
|
||||
virtual int getTokenType(void) {return eToken_comment;}
|
||||
};
|
||||
|
||||
class CCompilerDirectiveToken: public CToken {
|
||||
public:
|
||||
CCompilerDirectiveToken() : CToken() { }
|
||||
virtual int consume(PRUnichar aChar,CScanner& aScanner);
|
||||
virtual int getTokenType(void) {return eToken_compilerdirective;}
|
||||
};
|
||||
|
||||
class CSemicolonToken: public CToken {
|
||||
public:
|
||||
CSemicolonToken() : CToken() { }
|
||||
virtual int consume(PRUnichar aChar,CScanner& aScanner);
|
||||
virtual int getTokenType(void) {return eToken_semicolon;}
|
||||
};
|
||||
|
||||
class CNewlineToken: public CToken {
|
||||
public:
|
||||
CNewlineToken() : CToken() { }
|
||||
virtual int consume(PRUnichar aChar,CScanner& aScanner);
|
||||
virtual int getTokenType(void) {return eToken_newline;}
|
||||
};
|
||||
|
||||
class CQuotedStringToken: public CToken {
|
||||
public:
|
||||
CQuotedStringToken() : CToken() { }
|
||||
virtual int consume(PRUnichar aChar,CScanner& aScanner);
|
||||
virtual int getTokenType(void) {return eToken_quotedstring;}
|
||||
};
|
||||
|
||||
#endif
|
Загрузка…
Ссылка в новой задаче