MFC文件操作大全

1.创建文件夹

CreateDirectory(%%1,NULL);

 

2.创建文件

CFile file;

file.Open(%%1,CFile::modeCreate|CFile::modeWrite);

 

3.删除文件

DeleteFile(%%1);

 

4.删除文件夹

RemoveDirectory(%%1);

 

5.删除一个目录下所有的文件夹

CFileFind finder;

CString path;

path.Format("%s//*.*",%%1);

BOOL bWorking = finder.FindFile(path); 

while (bWorking)

{

bWorking = finder.FindNextFile();

if (finder.IsDirectory() && !finder.IsDots())

{

RemoveDirectory(finder.GetFilePath());

}

 

6.清空文件夹

RemoveDirectory(%%1);

CreateDirectory(%%1,NULL);

 

7.读取文件

char sRead[5120];

CFile mFile(_T(%%1),CFile::modeRead);

while (sRead!=NULL)

{

mFile.Read(sRead,5120);

CString %%2(sRead);

%%3

}

mFile.Close();

 

8.写入文件

CFile mFile(_T(%%1), CFile::modeWrite|CFile::modeCreate);

mFile.Write(%%2,sizeof(%%2));

mFile.Flush();

mFile.Close(); 

 

9.写入随机文件

char szTempPath[_MAX_PATH],szTempfile[_MAX_PATH];

GetTempPath(_MAX_PATH, szTempPath);

GetTempFileName(szTempPath,_T ("my_"),0,szTempfile);

CFile m_tempFile(szTempfile,CFile:: modeCreate|CFile:: modeWrite);

char m_char='a';

m_tempFile.Write(&m_char,2);

m_tempFile.Close();

//循环写入多个值

strTempA;

int i;

int nCount=6;

//共有6个文件名需要保存

for (i=0;i{strTemp.Format("%d",i);

strTempA=文件名;

//文件名可以从数组,列表框等处取得.

::WritePrivateProfileString("UseFileName","FileName"+strTemp,strTempA,

c://usefile//usefile.ini);

}

strTemp.Format("%d",nCount);

::WritePrivateProfileString("FileCount","Count",strTemp,"c://usefile//usefile.ini");

//将文件总数写入,以便读出.

//读出

nCount=::GetPrivateProfileInt("FileCount","Count",0,"c://usefile//usefile.ini");

for(i=0;i{strTemp.Format("%d",i);

strTemp="FileName"+strTemp;

::GetPrivateProfileString("CurrentIni",strTemp,"default.fil", strTempA.GetBuffer(MAX_PATH),MAX_PATH,"c://usefile//usefile.ini");

//使用strTempA中的内容.

}

1.Seek 

Seek(100L,CFile::begin);//移动到文件开始后100字节处 

Seek(100L,CFile::end); 

Seek(100L,CFile::current); 

2.GetPosition 

得到文件当前位置,返回32位文件指针 

DWORD pos=file.GetPostition(); 

file.Seek(pos,CFile::begin); 

3.GetLength()

 

10.读取文件属性

DWORD dwAttrs = GetFileAttributes(%%1); 

if(dwAttrs & FILE_ATTRIBUTE_READONLY)     {   

  %%2

}     

if(dwAttrs & FILE_ATTRIBUTE_NORMAL){   

  %%3

}   

 

11.写入属性

SetFileAttributes(%%1,dwAttrs | FILE_ATTRIBUTE_READONLY);   

 

12.枚举一个目录下所有文件夹

CFileFind finder; 

CString path;

path.Format("%s//*.*",%%1);

BOOL bWorking = finder.FindFile(path); 

while (bWorking) { 

bWorking = finder.FindNextFile();

if(finder.IsDirectory() && !finder.IsDots()){

CString %%1=finder.GetFilePath();

%%2

}

 

13.复制文件夹

/*

#include <deque>

using namespace std;

*/

deque<CString>ctr;

WIN32_FIND_DATA FileData; 

HANDLE hSearch; 

DWORD dwAttrs; 

char szDirPath[] = %%2; 

char szNewPath[MAX_PATH];

BOOL fFinished = FALSE; 

if (!CreateDirectory(szDirPath, NULL)) {

//不能创建新的目录 

  return;

}

CString path;

path.Format("%s//*.*",%%1);

hSearch = FindFirstFile(path, &FileData); 

if (hSearch == INVALID_HANDLE_VALUE) { 

  return; 

while (ctr.size>0) {

if(!fFinished)

  lstrcpy(szNewPath, szDirPath); 

  lstrcat(szNewPath, FileData.cFileName); 

  if (CopyFile(FileData.cFileName, szNewPath, FALSE)) { 

  dwAttrs = GetFileAttributes(FileData.cFileName); 

  if (!(dwAttrs & FILE_ATTRIBUTE_READONLY)) { 

  SetFileAttributes(szNewPath, 

  dwAttrs | FILE_ATTRIBUTE_READONLY); 

  } 

  } 

  else { 

  //不能复制文件

  return; 

  } 

  if (!FindNextFile(hSearch, &FileData)) { 

  if (GetLastError() == ERROR_NO_MORE_FILES) { 

  //遍历文件夹完成 

  fFinished = TRUE; 

  } 

  else { 

  //找不到下一个文件

  return; 

  } 

  }

}

FindClose(hSearch); 

 

14.复制一个目录下所有的文件夹到另一个文件夹下

/*

#include <deque>

using namespace std;

*/

deque<CString>ctr;

WIN32_FIND_DATA FileData; 

HANDLE hSearch; 

DWORD dwAttrs; 

char szDirPath[] = %%2; 

char szNewPath[MAX_PATH];

BOOL fFinished = FALSE; 

if (!CreateDirectory(szDirPath,NULL)) 

{

//不能创建新的目录 

return;

}

CString path;

CFileFind finder;

path.Format("%s//*.*",%%1);

BOOL bWorking = finder.FindFile(path); 

while (bWorking) 

bWorking = finder.FindNextFile();

if(finder.IsDirectory() && !finder.IsDots()){

hSearch = FindFirstFile(finder.GetFilePath()+"//*.*", &FileData); 

if (hSearch == INVALID_HANDLE_VALUE) 

return; 

while (!fFinished) 

lstrcpy(szNewPath, szDirPath); 

lstrcat(szNewPath, FileData.cFileName); 

if (CopyFile(FileData.cFileName, szNewPath, FALSE)) 

dwAttrs = GetFileAttributes(FileData.cFileName); 

if (!(dwAttrs & FILE_ATTRIBUTE_READONLY)) 

SetFileAttributes(szNewPath, 

dwAttrs | FILE_ATTRIBUTE_READONLY); 

else 

//不能复制文件

return; 

if (!FindNextFile(hSearch, &FileData)) 

if (GetLastError() == ERROR_NO_MORE_FILES) 

//遍历文件夹完成 

fFinished = TRUE; 

else 

//找不到下一个文件

return; 

FindClose(hSearch);

}

 

15.移动文件夹

/*

#include <deque>

using namespace std;

*/

deque<CString>ctr;

WIN32_FIND_DATA FileData; 

HANDLE hSearch; 

DWORD dwAttrs; 

char szDirPath[] = %%2; 

char szNewPath[MAX_PATH];

BOOL fFinished = FALSE; 

if (!CreateDirectory(szDirPath, NULL)) 

{

//不能创建新的目录 

return;

}

CString path;

path.Format("%s//*.*",%%1);

hSearch = FindFirstFile(path, &FileData); 

if (hSearch == INVALID_HANDLE_VALUE) 

return; 

while (!fFinished) 

lstrcpy(szNewPath, szDirPath); 

lstrcat(szNewPath, FileData.cFileName); 

if (CopyFile(FileData.cFileName, szNewPath, FALSE)) 

dwAttrs = GetFileAttributes(FileData.cFileName); 

if (!(dwAttrs & FILE_ATTRIBUTE_READONLY)) 

SetFileAttributes(szNewPath, 

dwAttrs | FILE_ATTRIBUTE_READONLY); 

else 

//不能复制文件

return; 

if (!FindNextFile(hSearch, &FileData)) 

if (GetLastError() == ERROR_NO_MORE_FILES) 

//遍历文件夹完成 

fFinished = TRUE; 

else 

//找不到下一个文件

return; 

FindClose(hSearch); 

RemoveDirectory(%%1); 

 

16.移动一个文件夹下所有的文件夹到另一个目录下

/*

#include <deque>

using namespace std;

*/

deque<CString>ctr;

WIN32_FIND_DATA FileData; 

HANDLE hSearch; 

DWORD dwAttrs; 

char szDirPath[] = %%2; 

char szNewPath[MAX_PATH];

BOOL fFinished = FALSE; 

if (!CreateDirectory(szDirPath,NULL)) 

{

//不能创建新的目录 

return;

}

CString path;

path.Format("%s//*.*",%%1);

BOOL bWorking = finder.FindFile(path); 

while (bWorking) 

bWorking = finder.FindNextFile();

if(finder.IsDirectory() && !finder.IsDots()){

hSearch = FindFirstFile(finder.GetFilePath()+"//*.*", &FileData); 

if (hSearch == INVALID_HANDLE_VALUE) 

return; 

while (!fFinished) 

lstrcpy(szNewPath, szDirPath); 

lstrcat(szNewPath, FileData.cFileName); 

if (CopyFile(FileData.cFileName, szNewPath, FALSE)) 

dwAttrs = GetFileAttributes(FileData.cFileName); 

if (!(dwAttrs & FILE_ATTRIBUTE_READONLY)) 

SetFileAttributes(szNewPath, 

dwAttrs | FILE_ATTRIBUTE_READONLY); 

else 

//不能复制文件

return; 

if (!FindNextFile(hSearch, &FileData)) 

if (GetLastError() == ERROR_NO_MORE_FILES) 

//遍历文件夹完成 

fFinished = TRUE; 

else 

//找不到下一个文件

return; 

FindClose(hSearch);

RemoveDirectory(finder.GetFilePath().GetBuffer(0));

}

 

17.以一个文件夹的框架在另一个目录创建文件夹和空文件

/*

#include <deque>

using namespace std;

*/

deque<CString>ctr;

WIN32_FIND_DATA FileData; 

HANDLE hSearch; 

DWORD dwAttrs; 

char szDirPath[] = %%2; 

char szNewPath[MAX_PATH];

BOOL fFinished = FALSE; 

if (!CreateDirectory(szDirPath, NULL)) 

{

//不能创建新的目录 

return;

}

CString path;

path.Format("%s//*.*",%%1);

hSearch = FindFirstFile(path, &FileData); 

if (hSearch == INVALID_HANDLE_VALUE) 

return; 

while (!fFinished) 

lstrcpy(szNewPath, szDirPath); 

lstrcat(szNewPath, FileData.cFileName); 

HANDLE hFile=CreateFileHandle hFile=CreateFile(szNewPath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL);

if(!hFile)

{

//不能创建文件

return;

if (!FindNextFile(hSearch, &FileData))

if (GetLastError() == ERROR_NO_MORE_FILES) 

//遍历文件夹完成 

fFinished = TRUE; 

else 

//找不到下一个文件

return;

FindClose(hSearch); 

 

18.复制文件

CopyFile(%%1,%%2,true);

 

19.复制一个文件夹下所有的文件到另一个目录

/*

#include <string>

using std::string;

*/

char sep='/';

#ifdef _WIN32

sep='//';

#endif

CFileFind finder; 

CString path;

path.Format("%s//*.*",%%1);

BOOL bWorking = finder.FindFile(path); 

while (bWorking) 

bWorking = finder.FindNextFile();

if(!finder.IsDirectory() || finder.IsDots()){

string s(finder.GetFileName());

if(s.rfind(sep,s.length())!=string::npos)

{

char *file=substr(i+1,s.length()-i).c_str();

CString sourcefile;

sourcefile.Format("%s%c%s",%%1,sep,file);

CString targetfile;

targetfile.Format("%s%c%s",%%2,file);

CopyFile(sourcefile,targetfile,true);

}

}

 

20.提取扩展名

CString path(%%1);

CString %%2=path.Mid(path.ReverseFind('.'));

 

21.提取文件名

CString path(%%1);

CString %%2=path.Mid(path.ReverseFind('//')+1);

 

22.提取文件路径

char appName[MAX_PATH];

GetModualFileName(NULL,appName,MAX_PATH);

CString %%1(appName);

 

23.替换扩展名

/*

#include <string>

using std::string;

*/

string s(%%1);

string newExt(%%2);

string::size_type i=s.rfind('.',s.length());

if(i!=string::npos)

s.replace(i+1,newExt.length(),newExt);

CString %%3(s); 

 

24.追加路径

/*

#include <string>

#include <cstdlib>

#include <boost/filesystem/operations.hpp>

#include <boost/filesystem/fstream.hpp>

using namespace std;

using namespace boost::filesystem;

*/

try {

path p1=complete(path(%%2,native),

path(%%1,native));

path p2=system_complete(path(%%2,native));

CString %%3(p3);

%%4

}

catch(exception& e){

//e.what();

 

25.移动文件

MoveFile(%%1,%%2); 

 

26.移动一个文件夹下所有文件到另一个目录

/*

#include <string>

using std::string;

*/

char sep='/';

#ifdef _WIN32

sep='//';

#endif

CFileFind finder; 

CString path;

path.Format("%s//*.*",%%1);

BOOL bWorking = finder.FindFile(path); 

while (bWorking) 

bWorking = finder.FindNextFile();

if(!finder.IsDirectory() || finder.IsDots()){

string s(finder.GetFileName());

CString sourcefile(%%1);

if(s.rfind(sep,s.length())!=string::npos)

{

sourcefile=sourcefile+"//"+s.substr(i+1,s.length()-i);

CString targetfile(s.substr(i+1,s.length()-i));

targetfile=%%2+"//"+targetfile/;

MoveFile(sourcefile.GetBuffer(0),targetfile.GetBuffer(0),true);

}

}

 

27.指定目录下搜索文件

CString strFileTitle;

CFileFind finder;

BOOL bWorking = finder.FindFile(%%1); //"C://windows//sysbkup//*.cab"

while(bWorking)

{

bWorking=finder.FindNextFile();

strFileTitle=finder.GetFileTitle();

 

28.打开对话框

CString %%1;

CFileDialog dlg(TRUE);///TRUE为OPEN对话框,FALSE为SAVE AS对话框

//dlg.m_ofn.lpstrInitialDir=_T("d://"); //这里就设置了对话框的默认目录d盘

dlg.m_ofn.lpstrFilter="Document/0*.doc/0All Files(*.*)/0*.*/0/0";

if(dlg.DoModal()==IDOK)

%%1=dlg.GetPathName();

 

29.文件分割

CFile m_File;

CString m_Filename,m_FileTitle,m_FilePath;

m_FileName=%%1;

char pBuf[4096];

if(m_File.Open(m_FileName,CFile::modeRead | CFile::shareDenyWrite))

{

m_FileName=m_File.GetPathName();

m_FileTitle=m_File.GetFileTitle();

DWORD FileLength=m_File.GetLength();

DWORD PartLength=FileLength/2+FileLength%2;

int nCount=1;

CString strName;

CFile wrFile;

DWORD ReadBytes;

while(true)

{

ReadBytes=m_File.Read(pBuf,PartLength);

strName.Format("%s%d",m_FIleTitle,nCount);

wrFile.Open(strName,CFile::modeWrite | CFile::modeCreate);

wrFile.Write(pBuf,ReadBytes);

wrFile.Close();

if(ReadBytes<PartLength)

break;

nCount++;

}

m_File.Close();

}

else

AfxMessageBox("不能打开文件"); 

 

30.文件合并

//#include <string>

using std::string;

string s(%%1);

char sep='/';

#ifdef _WIN32

sep='//';

#endif

size_t sz=s.rfind(sep,s.length());

if(sz!=string::npos)

{

CFile Out;

CString strFilename(s.substr(i+1,s.length()-i));

if(Out.Open(%%2+"//"+strfilename,cfile::modewrite%7ccfile::modecreate)){

for(int i=1;i<=2;i++)

{

CString Filename;

Filename.Format("%s//%s%d",%%2,strfilename,atoi(i));

CFile In;

if(In.Open(Filename,CFile::modeRead)){

char cbBuffer[4096];

int nFilesize=In.GetLength();

while(nFilesize>0){

int nSize=sizeof(cbBuffer);

if(nSize>nFilesize)

nSize=nFilesize;

try{

In.Read(cbBuffer,nSize);

}

catch(CFileException *e){

char *lpMsgBuf;

if(FormatMessage(

FORMAT_MESSAGE_ALLOCATE_BUFFER |

FORMAT_MESSAGE_FROM_SYSTEM,

NULL,e->m_lOsError,

MAKELANGID(LANG_NEUTRAL,

SUBLANG_DEFAULT),

(LPSTR)&lpMsgBuf,0,NULL)>0){

AfxMessageBox(lpMsgBuf);

LocalFree(lpMsgBuf);

}

e->Delete();

return;

}

try{

Out.Write(cbBuffer,nSize);

}

catch(CFileException *e){

char *lpMsgBuf;

if(FormatMessage(

FORMAT_MESSAGE_ALLOCATE_BUFFER |

FORMAT_MESSAGE_FROM_SYSTEM,

NULL,e->m_lOsError,

MAKELANGID(LANG_NEUTRAL,

SUBLANG_DEFAULT),

(LPSTR)&lpMsgBuf,0,NULL)>0){

AfxMessageBox(lpMsgBuf);

LocalFree(lpMsgBuf);

}

e->Delete();

return;

}

nFilesize=nSize;

}

}

else

AfxMessageBox("不能打开"+Filename);

}

}

}

else

AfxMessageBox("不能创建输出文件");

 

31.文件简单加密

//#include <string>

using std::string;

string s(%%1);

char sep='/';

#ifdef _WIN32

sep='//';

#endif

size_t sz=s.rfind(sep,s.length());

CString outfile;

if(sz!=string::npos)

{

CFile Out,In;

int nFIlesize;

char *lpMsgBuf;

CString strFilename(s.substr(i+1,s.length()-i));

if(!in.Open(%%1,CFile::modeRead)){

//不能打开输入文件

return;

}

outfile.Format("//enc_",%%2,strfilename);

if(!Out.Open(outfile,CFile::modewrite|CFile::modeCreate)){

//不能打开输出文件

return;

}

}

nFilesize=In.GetLength();

lpBuffer=new char[nFilesize];

if(lpBuffer==NULL){

//不能分配复制缓存

return;

}

CFileStatus rStatus;

In.GetStatus(%%1,rStatus);

try{

In.Read(cbBuffer,nFilesize);

}

catch(CFileException *e){

char *lpMsgBuf;

if(FormatMessage(

FORMAT_MESSAGE_ALLOCATE_BUFFER |

FORMAT_MESSAGE_FROM_SYSTEM,

NULL,e->m_lOsError,

MAKELANGID(LANG_NEUTRAL,

SUBLANG_DEFAULT),

(LPSTR)&lpMsgBuf,0,NULL)>0){

AfxMessageBox(lpMsgBuf);

LocalFree(lpMsgBuf);

}

e->Delete();

return;

}

for(int i=0;i<nFilesize;i++)

{

int ibt=lpBuffer[i];

ibt+=100;

ibt%=256;

bpBuffer[i]=(char)ibt;

}

try{

Out.Write(cbBuffer,nFilesize);

}

catch(CFileException *e){

char *lpMsgBuf;

if(FormatMessage(

FORMAT_MESSAGE_ALLOCATE_BUFFER |

FORMAT_MESSAGE_FROM_SYSTEM,

NULL,e->m_lOsError,

MAKELANGID(LANG_NEUTRAL,

SUBLANG_DEFAULT),

(LPSTR)&lpMsgBuf,0,NULL)>0){

AfxMessageBox(lpMsgBuf);

LocalFree(lpMsgBuf);

}

e->Delete();

return;

}

Out.Close();

//In.Close();

CFile::SetStatus(outfile,rstatus);

delete[] lpBuffer;

 

32.文件简单解密

//#include <string>

using std::string;

string s(%%1);

char sep='/';

#ifdef _WIN32

sep='//';

#endif

size_t sz=s.rfind(sep,s.length());

CString infile;

if(sz!=string::npos)

{

CFile Out,In;

int nFIlesize;

char *lpMsgBuf;

CString strFilename(s.substr(i+1,s.length()-i));

infile.Format("%s//enc_%s",%%2,strfilename)

if(!in.Open(infile,CFile::moderead)){

//不能打开输入文件

return;

}

if(!Out.Open(%%1,CFile::modeWrite|CFile::modeCreate)){

//不能打开输出文件

return;

}

nFilesize=In.GetLength();

lpBuffer=new char[nFilesize];

if(lpBuffer==NULL){

//不能分配复制缓存

return;

}

CFileStatus rStatus;

In.GetStatus(infile,rstatus);

try{

In.Read(cbBuffer,nFilesize);

}

catch(CFileException *e){

char *lpMsgBuf;

if(FormatMessage(

FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,

NULL,e->m_lOsError,

MAKELANGID(LANG_NEUTRAL,

SUBLANG_DEFAULT),

(LPSTR)&lpMsgBuf,0,NULL)>0){

AfxMessageBox(lpMsgBuf);

LocalFree(lpMsgBuf);

}

e->Delete();

return;

}

for(int i=0;i<nFilesize;i++)

{

int ibt=lpBuffer[i];

ibt-=100;ibt+=256;

ibt%=256;

bpBuffer[i]=(char)ibt;

}

try{

Out.Write(cbBuffer,nFilesize);

}

catch(CFileException *e){

char *lpMsgBuf;

if(FormatMessage(

FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,

NULL,e->m_lOsError,

MAKELANGID(LANG_NEUTRAL,

SUBLANG_DEFAULT),

(LPSTR)&lpMsgBuf,0,NULL)>0){

AfxMessageBox(lpMsgBuf);

LocalFree(lpMsgBuf);

}

e->Delete();

return;

}

Out.Close();

//In.Close();

CFile::SetStatus(%%1,rStatus);

delete[] lpBuffer;

 

33.读取ini文件属性

CStdioFile inifile(%%1,CFile::modeRead);

CString path = inifile.GetFilePath();

inifile.Close();

char key[1024];

DWORD bytes = GetPrivateProfileString(%%2,%%3,%%4,key,1024,path);

if(bytes < 1024)

key[bytes] = '/0';

CString %%5(key); 

 

34.合并一个目录下所有的文件

CString Directory;

Directory.Format("%s//*.*",%%1);

CFileFind FFile;

CFile Out;

if(Out.Open(%%2,CFile::modeWrite|CFile::modeCreate)){

BOOL bFound=FFile.FindFile(Directory);

while(bFound)

{

bFound=FFile.FileNextFile();

if(!FFile.IsDirectory() && !FFile.IsDots())

{

CString Filename=FFile.GetFileName();

CFile In;

if(In.Open(Filename,CFile::modeRead)){

char cbBuffer[4096];

int nFIlesize=In.GetLength();

while(nFIlesize>0){

{

int nSize=sizeof(cbBuffer);

if(nSize>nFilesize)

nSize=nFilesize;

try {

In.Read(cbBuffer,nSize);

}

catch(CFileException *e){

char *lpMsgBuf;

if(FormatMessage(

FORMAT_MESSAGE_ALLOCATE_BUFFER |

FORMAT_MESSAGE_FROM_SYSTEM,

NULL,e->m_lOsError,

MAKELANGID(LANG_NEUTRAL,

SUBLANG_DEFAULT),

(LPSTR)&lpMsgBuf,0,NULL)>0){

AfxMessageBox(lpMsgBuf);

LocalFree(lpMsgBuf);

}

e->Delete();

return;

}

try {

Out.Write(cbBuffer,nSize);

}

catch(CFileException *e){

char *lpMsgBuf;

if(FormatMessage(

FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,

NULL,e->m_lOsError,

MAKELANGID(LANG_NEUTRAL,

SUBLANG_DEFAULT),

(LPSTR)&lpMsgBuf,0,NULL)>0){

AfxMessageBox(lpMsgBuf);

LocalFree(lpMsgBuf);

}

e->Delete();

return;

}

nFilesize=nSize;

}

}

else

AfxMessageBox("不能打开"+Filename);

}

}

}

}

else

AfxMessageBox("不能创建输出文件"); 

 

35.写入ini文件属性

/*

CStdioFile inifile(%%1,CFile::modeRead);

CString path = inifile.GetFilePath();

inifile.Close();

int bytes = GetPrivateProfileInt(%%2,%%3,%%4,path); 

*/

WritePrivateProfileString(%%2,%%3,%%4,path);

 

36.获得当前路径

TCHAR szDir[MAX_PATH];

GetCurrentDirectory(MAX_PATH,szDir);

CString %%1;

%%1.Format("%s",szDir); 

37.读取XML数据库

/*

#include <string>

using namespace std;

*/

char sRead[5192];

const char* name="Name";

const char* name2="author";

const char* root="ProductData";

const char* subNodeTag="Product";

const char* ID="pid";

//%%2="ProductData" //%%4="pid" //%%6="author"

//%%3="Product" //%%5="Name"

char sRead[5192];

CFile mFile(_T(%%1),CFile::modeRead);

mFile.Read(sRead,5192);

if(sRead!=NULL)

{

string tmp;

while(sRead!=NULL)

{

tmp.append(sRead);

mFile.Read(sRead,5192);

}

string target("001"),globalTag;globalTag.append("<");globalTag.appendoot);globalTag.append(">");

string propTag1;propTag1.append("<");propTag1.append(name);propTag1.append(">");

string endTag1;endTag1.append("</");endTag1.append(name);endTag1.append(">");

string propTag2;propTag2.append("<");propTag2.append(name2);propTag2.append(">");

string endTag2;endTag2.append("</");endTag2.append(name2);endTag2.append(">");

int offset=tmp.find_first_of(globalTag);

while(offset)

{

offset=tmp.find_first_of(globalTag);

string description;

tmp.copy(description.begin(),tmp.find_first_of("/"",offset+1)-offset);

if(target.compare(description)==0)

{

string prop,prop2;

offset=tmp.find_first_of(propTag1,offset)+strlen(name)+2;

tmp.copy(prop.begin(),tmp.find_first_of(endTag1,offset)- offset,offset);

offset=tmp.find_first_of(propTag2,offset)+strlen(name2)+2;

tmp.copy(prop2.begin(),tmp.find_first_of(endTag2,offset)-offset,offset);

//CString %%8(prop),%%9(prop2);

//%%10

return 0;

}

}

}

else

return -1; 

38.写入XML数据库

/*

#include <string>

using namespace std;

*/

char sRead[5192];

int no;

const char* name="Name";

const char* name2="author";

const char* root="ProductData";

const char* subNodeTag="Product";

const char* ID="pid";

//%%2="ProductData" //%%4="pid" //%%6="port"

//%%3="Product" //%%5="Name" //%%7="author"

CString temp;

char sRead[5192];

string description;

CFile mFile(_T(%%1),CFile::modeRead);

mFile.Read(sRead,5192);

if(sRead!=NULL)

{

string tmp;

while(sRead!=NULL)

{

tmp.append(sRead);

memset(sRead,0,5192);

mFile.Read(sRead,5192);

}

temp.Format("<%s %s",subNodeTag,ID);

int offset=tmp.find_last_of(temp)+strlen(subNodeTag) +strlen(ID)+4;

temp.Format("/"><%s",name);

tmp.copy(description.begin(),tmp.find_last_of(temp)- offset,offset);

no=atoi(description.c_str())+1;

mFile.Close();

temp.Format("</%s>",root);

CString temp2;

temp2.Format("<%s %s=/"%d/"><%s>%s</%s><%s>%s</%s",subNodeTag,ID,no,name,"bbbbbbbbbbbbbbbb",name,name2,"cccccccccccccc",name2);

tmp.insert(tmp.find_last_of(temp),temp2);

CFile file(_T("Produces.xml"),CFile::modeWrite);

file.Write(tmp.c_str(),tmp.size());

file.Flush();

file.Close();

}

else

{

CFile file(_T(%%1),CFile::modeWrite|CFile::modeCreate);

temp.Format("<?xml version=/"1.0/" encoding=/"gb2312/"?><%s><%s %s=/"0/"><%s>%s</%s><%s>%s</%s></%s></%s>",root,subNodeTag,ID,name,"bbbbbbbbbbbbbbbb",name,name2,"cccccccccccccc",name2,subNodeTag,root);

file.Write(temp.GetBuffer(0),temp.GetLength());

file.Flush();

file.Close();

39.ZIP压缩文件

//www.zlib.net

/*

#ifdef _DEBUG

#pragma comment(lib,"zlibd.lib")

#else

#pragma comment(lib,"zlib.lib")

#endif

#include "zlib.h"

#include "zconf.h"

*/

HANDLE hFile, hFileToWrite;

CString strFilePath;

m_ctrEdit.GetWindowText(strFilePath); 

//打开要进行压缩的文件

hFile = CreateFile(strFilePath, // file name

GENERIC_READ, // open for reading

FILE_SHARE_READ, // share for reading

NULL, // no security

OPEN_EXISTING, // existing file only

FILE_ATTRIBUTE_NORMAL, // normal file

NULL

); // no attr. template 

if (hFile == INVALID_HANDLE_VALUE)

{

AfxMessageBox("Could not open file to read"); // process error

return;

HANDLE hMapFile, hMapFileToWrite; 

//创建一个文件映射

hMapFile = CreateFileMapping(hFile, // Current file handle.

NULL, // Default security.

PAGE_READONLY, // Read/write permission.

0, // Max. object size.

0, // Size of hFile.

"ZipTestMappingObjectForRead"

); // Name of mapping object. 

if (hMapFile == NULL)

{

AfxMessageBox("Could not create file mapping object");

return;

LPVOID lpMapAddress, lpMapAddressToWrite; 

 

//创建一个文件映射的视图用来作为source

lpMapAddress = MapViewOfFile(hMapFile, // Handle to mapping object.

FILE_MAP_READ, // Read/write permission

0, // Max. object size.

0, // Size of hFile.

0); // Map entire file. 

 

if (lpMapAddress == NULL)

{

AfxMessageBox("Could not map view of file");

return;

}

DWORD dwFileLength,dwFileLengthToWrite;

dwFileLength = GetFileSize(hFile, NULL);

m_dwSourceFileLength = dwFileLength;

//因为压缩函数的输出缓冲必须比输入大0.1% + 12 然后一个DWORD用来保存压缩前的大小,

// 解压缩的时候用,当然还可以保存更多的信息,这里用不到

dwFileLengthToWrite = (double)dwFileLength*1.001 + 12 +sizeof(DWORD);

//以下是创建一个文件,用来保存压缩后的文件

hFileToWrite = CreateFile("demoFile.rar", // demoFile.rar

GENERIC_WRITE|GENERIC_READ, // open for writing

0, // do not share

NULL, // no security

CREATE_ALWAYS, // overwrite existing

FILE_ATTRIBUTE_NORMAL , // normal file

NULL); // no attr. template 

 

if (hFileToWrite == INVALID_HANDLE_VALUE)

{

AfxMessageBox("Could not open file to write"); // process error

return;

}

hMapFileToWrite = CreateFileMapping(hFileToWrite, // Current file handle.

NULL, // Default security.

PAGE_READWRITE, // Read/write permission.

0, // Max. object size.

dwFileLengthToWrite, // Size of hFile.

"ZipTestMappingObjectForWrite"); // Name of mapping object.

if (hMapFileToWrite == NULL)

{

AfxMessageBox("Could not create file mapping object for write");

return;

}

lpMapAddressToWrite = MapViewOfFile(hMapFileToWrite, //Handle to mapping object.FILE_MAP_WRITE, // Read/write permission 0, // Max. object size.

0, // Size of hFile.

0

); // Map entire file.

if (lpMapAddressToWrite == NULL)

{

AfxMessageBox("Could not map view of file");

return;

}

//这里是将压缩前的大小保存在文件的第一个DWORD里面

LPVOID pBuf = lpMapAddressToWrite;

(*(DWORD*)pBuf) = dwFileLength;

pBuf = (DWORD*)pBuf + 1;

//这里就是最重要的,zlib里面提供的一个方法,将源缓存的数据压缩至目的缓存

//原形如下:

//int compress (Bytef *dest, uLongf *destLen, const Bytef*source, uLong sourceLen);

//参数destLen返回实际压缩后的文件大小。

compress((Bytef*)pBuf,&dwFileLengthToWrite, (Bytef*)lpMapAddress, dwFileLength);

UnmapViewOfFile(lpMapAddress);

CloseHandle(hMapFile);

CloseHandle(hFile);

UnmapViewOfFile(lpMapAddressToWrite);

CloseHandle(hMapFileToWrite);

//这里将文件大小重新设置一下

SetFilePointer(hFileToWrite,dwFileLengthToWrite + sizeof(DWORD) ,NULL,FILE_BEGIN);

SetEndOfFile(hFileToWrite);

CloseHandle(hFileToWrite); 

40.ZIP解压缩

//www.zlib.net

/*

#ifdef _DEBUG

#pragma comment(lib,"zlibd.lib")

#else

#pragma comment(lib,"zlib.lib")

#endif

#include "zlib.h"

#include "zconf.h"

*/

HANDLE hFile, hFileToWrite;

CString strFilePath=%%1;

//打开要进行解压缩的文件

hFile = CreateFile(strFilePath, // file name

GENERIC_READ, // open for reading

FILE_SHARE_READ, // share for reading

NULL, // no security

OPEN_EXISTING, // existing file only

FILE_ATTRIBUTE_NORMAL, // normal file

NULL

); // no attr. template

if (hFile == INVALID_HANDLE_VALUE)

{

AfxMessageBox("Could not open file to read"); // process error

return;

}

HANDLE hMapFile, hMapFileToWrite;

//创建一个文件映射

hMapFile = CreateFileMapping(hFile, // Current file handle.

NULL, // Default security.

PAGE_READONLY, // Read/write permission.

0, // Max. object size.

0, // Size of hFile.

"ZipTestMappingObjectForRead"); // Name of mapping object.

if (hMapFile == NULL)

{

AfxMessageBox("Could not create file mapping object");

return;

}

LPVOID lpMapAddress, lpMapAddressToWrite;

//创建一个文件映射的视图用来作为source

lpMapAddress = MapViewOfFile(hMapFile, // Handle to mapping

object.FILE_MAP_READ, // Read/write permission

0, // Max. object size.

0, // Size of hFile.

0); // Map entire file.

if (lpMapAddress == NULL)

{

AfxMessageBox("Could not map view of file");

return;

}

DWORD dwFileLength,dwFileLengthToWrite;

dwFileLength = GetFileSize(hFile, NULL) - sizeof(DWORD);

//因为压缩函数的输出缓冲必须比输入大0.1% + 12 然后一个DWORD用来保存压缩前的大小,

// 解压缩的时候用,当然还可以保存更多的信息,这里用不到

// dwFileLengthToWrite = (double)dwFileLength*1.001 + 12 +sizeof(DWORD);

dwFileLengthToWrite = (*(DWORD*)lpMapAddress);

LPVOID pSourceBuf = lpMapAddress;

pSourceBuf = (DWORD*)pSourceBuf + 1;

//以下是创建一个文件,用来保存压缩后的文件

hFileToWrite = CreateFile(%%2, // create demo.gz

GENERIC_WRITE|GENERIC_READ, // open for writing

0, // do not share

NULL, // no security

CREATE_ALWAYS, // overwrite existing

FILE_ATTRIBUTE_NORMAL , // normal file

NULL

); // no attr. template

if (hFileToWrite == INVALID_HANDLE_VALUE)

{

AfxMessageBox("Could not open file to write"); //process error

return;

}

hMapFileToWrite = CreateFileMapping(hFileToWrite, // Currentfile handle.

NULL, // Default security.

PAGE_READWRITE, // Read/write permission.

0, // Max. object size.

dwFileLengthToWrite, // Size of hFile.

"ZipTestMappingObjectForWrite"); // Name of mapping object.

if (hMapFileToWrite == NULL)

{

AfxMessageBox("Could not create file mapping object for write");

return;

}

lpMapAddressToWrite = MapViewOfFile(hMapFileToWrite, //Handle to mapping object.

FILE_MAP_WRITE, // Read/write permission

0, // Max. object size.

0, // Size of hFile.

0

); // Map entire file.

if (lpMapAddressToWrite == NULL)

{

AfxMessageBox("Could not map view of file");

return;

}

//这里是将压缩前的大小保存在文件的第一个DWORD里面

LPVOID pBuf = lpMapAddressToWrite;

//这里就是最重要的,zlib里面提供的一个方法,将源缓存的数据压缩至目的缓存

//原形如下:

//int compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);

//参数destLen返回实际压缩后的文件大小。

uncompress((Bytef*)pBuf,&dwFileLengthToWrite, (Bytef*)pSourceBuf, dwFileLength);

UnmapViewOfFile(lpMapAddress);

CloseHandle(hMapFile);

CloseHandle(hFile);

UnmapViewOfFile(lpMapAddressToWrite);

CloseHandle(hMapFileToWrite);

//这里将文件大小重新设置一下

SetFilePointer(hFileToWrite,dwFileLengthToWrite,NULL,FILE_BEGIN);

SetEndOfFile(hFileToWrite);

CloseHandle(hFileToWrite); 

 

41.获得应用程序完整路径

char appName[MAX_PATH];

GetModuleFileName(NULL,appName,MAX_PATH);

CString %%1(appName);

42.递归删除目录中的文件

CString Directory(%%1);

CStringArray csa;

int count=0;

if(Directory.Right(1)!="//")

Directory+="//";

Directory+="*.*";

CFileFInd FFile;

csa.add(Directory);

while(count<csa.GetSize())

{

if(FFile.FindFile(csa.GetAt(i)))

{

bFound=FFile.FindNextFile();

if(!FFile.IsDirectory() && !FFile.IsDots())

{

DeleteFile(FFile.GetFilePath());

}

else if(FFile.IsDirectory())

{

csa.Add(FilePath+"//*.*");

}

}

else

count++;

}

 

43.ZIP压缩文件夹

//www.zlib.net

/*

#include <stdio.h>

#include <string.h>

#include <assert.h>

#include <dos.h>

#include <direct.h>

#include <zlib.h> 

#if defined(MSDOS) || defined(OS2) || defined(WIN32) || 

defined(__CYGWIN__)

# include <fcntl.h>

# include <io.h>

# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)

#else

# define SET_BINARY_MODE(file)

#endif 

#define CHUNK 16384 

//#define USE_TAG

#ifdef USE_TAG

#define COMPRESS_FILE_TAG_HEAD "<<<"

#define COMPRESS_FILE_TAG_TAIL ">>>"

#define COMPRESS_FILE_TAG_END_LEN 3    // must be strlen 

(COMPRESS_FILE_TAG_HEAD) = strlen(COMPRESS_FILE_TAG_TAIL)

#else

#define COMPRESS_FILE_TAG_HEAD ""

#define COMPRESS_FILE_TAG_TAIL ""

#define COMPRESS_FILE_TAG_END_LEN 0    // must be strlen 

(COMPRESS_FILE_TAG_HEAD) = strlen(COMPRESS_FILE_TAG_TAIL)

 #endif

*/

/**//**//**//* Compress from file source to file dest until EOF on source.

def() returns Z_OK on success, Z_MEM_ERROR if emory could not be allocated for processing, Z_STREAM_ERROR if an invalid compression

level is supplied, Z_VERSION_ERROR if the version of zlib. And the version of the library linked do not matc, or Z_ERRNO if there isan error reading or writing the files. */

static it def(FILE *source, FILE *dest, int level)

int ret, flush;

unsigned have;

z_stream strm;

unsigned char in[CHUNK];

unsigned char out[CHUNK]; 

/**//**//**//* allocate deflate state */

strm.zalloc = Z_NULL;

strm.zfree = Z_NULL;

strm.opaque = Z_NULL;

ret = deflateInit(&strm, level);

if (ret != Z_OK)

return ret; 

/**//**//**//* compress until end of file */

do {

strm.avail_in = fread(in, 1, CHUNK, source);

if (ferror(source)) {

(void)deflateEnd(&strm);

return Z_ERRNO;

}

flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;

strm.next_in = in; 

/**//**//**//* run deflate() on input until output 

 buffer not full, finish

compression if all of source has been read in */

do {

strm.avail_out = CHUNK;

strm.next_out = out;

ret = deflate(&strm, flush);    /**//**//**//* no 

bad return value */

assert(ret != Z_STREAM_ERROR); /**//**//**//* 

  

state not clobbered */

have = CHUNK - strm.avail_out;

if (fwrite(out, 1, have, dest) != have || ferror 

(dest)) {

(void)deflateEnd(&strm);

return Z_ERRNO;

}

} while (strm.avail_out == 0);

assert(strm.avail_in == 0);     /**//**//**//* all 

input will be used */ 

/**//**//**//* done when last data in file processed 

*/

} while (flush != Z_FINISH);

assert(ret == Z_STREAM_END);        /**//**//**//* stream 

will be complete */ 

/**//**//**//* clean up and return */

(void)deflateEnd(&strm);

return Z_OK;

/**//**//**//* Decompress from file source to file dest until stream ends or EOF. inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be allocated for processing, Z_DATA_ERROR if the deflate data is invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and the version of the library linked do not match, or Z_ERRNO 

 if there is an error reading or writing the files. */

static int inf(FILE *source, FILE *dest)

{

int ret;

unsigned have;

z_stream strm;

unsigned char in[CHUNK];

unsigned char out[CHUNK]; 

/**//**//**//* allocate inflate state */

strm.zalloc = Z_NULL;

strm.zfree = Z_NULL;

strm.opaque = Z_NULL;

strm.avail_in = 0;

strm.next_in = Z_NULL;

ret = inflateInit(&strm);

if (ret != Z_OK)

return ret; 

/**//**//**//* decompress until deflate stream ends or end 

of file */

do {

strm.avail_in = fread(in, 1, CHUNK, source);

if (ferror(source)) {

(void)inflateEnd(&strm);

return Z_ERRNO;

}

if (strm.avail_in == 0)

break;

strm.next_in = in; 

/**//**//**//* run inflate() on input until output 

buffer not full */

do {

strm.avail_out = CHUNK;

strm.next_out = out;

ret = inflate(&strm, Z_NO_FLUSH);

assert(ret != Z_STREAM_ERROR); /**//**//**//* 

  

state not clobbered */

switch (ret) {

case Z_NEED_DICT:

ret = Z_DATA_ERROR;     /**//**//**//* and 

fall through */

case Z_DATA_ERROR:

case Z_MEM_ERROR:

(void)inflateEnd(&strm);

return ret;

}

have = CHUNK - strm.avail_out;

if (fwrite(out, 1, have, dest) != have || ferror 

(dest)) {

(void)inflateEnd(&strm);

return Z_ERRNO;

}

} while (strm.avail_out == 0); 

/**//**//**//* done when inflate() says it's done */

} while (ret != Z_STREAM_END); 

/**//**//**//* clean up and return */

(void)inflateEnd(&strm);

return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;

}

/**//**//**//* report a zlib or i/o error */

static void zerr(int ret)

{

fputs("zpipe: ", stderr);

switch (ret) {

case Z_ERRNO:

if (ferror(stdin))

fputs("error reading stdin ", stderr);

if (ferror(stdout))

fputs("error writing stdout ", stderr);

break;

case Z_STREAM_ERROR:

fputs("invalid compression level ", stderr);

break;

case Z_DATA_ERROR:

fputs("invalid or incomplete deflate data ", stderr);

break;

case Z_MEM_ERROR:

fputs("out of memory ", stderr);

break;

case Z_VERSION_ERROR:

fputs("zlib version mismatch! ", stderr);

}

}

// 以上就是zpipe.c的几个主要函数:def()、inf()和zerr(),def()是压缩函数,主要使用了zlib的deflate()接口;inf()是压缩函数,主要使用了zlib的inflate()接口;zerr()是错误打印函数。

static int write_zfile_file_header(const char *file,FILE *zfile)

{

int len;

len = strlen(file);

if (fwrite(COMPRESS_FILE_TAG_HEAD, 1,COMPRESS_FILE_TAG_END_LEN, zfile) != COMPRESS_FILE_TAG_END_LEN || ferror(zfile)) 

{

fprintf(stderr,"When writing file or dir header to zfile: write error. ");

return 1;

}

if (fwrite(file, 1, len, zfile) != len|| ferror(zfile)) 

{

fprintf(stderr,"When writing file or dir header to zfile: write error. ");

return 1;

}

if (fwrite(COMPRESS_FILE_TAG_TAIL, 1,COMPRESS_FILE_TAG_END_LEN, zfile) != COMPRESS_FILE_TAG_END_LEN || ferror(zfile)) 

{

fprintf(stderr,"When writing file or dir header to 

zfile: write error. ");

  return 1;

}

return 0;

}

/**//* compress or decompress from stdin to stdout */

static int compress_dir(char *file_in,FILE *fd_out)

{

FILE *fd_in;

struct _finddata_t find_data;

char file[128];

long lf;

int ret;

write_zfile_file_header(file_in,fd_out);

sprintf(file,"%s%s",file_in,"/*");

if((lf = _findfirst(file,&find_data))==-1l)    // LOOKOUT:not eleven, but one and lowercase 'L'

{

fprintf(stdout,"file not found. ");

}

else

{

do 

{

if(!strcmp(find_data.name,".") || !strcmp(find_data.name,".."))

continue;

fprintf(stdout,"%s",find_data.name);

sprintf(file,"%s%s%s",file_in,"/",find_data.name);

if(find_data.attrib & _A_SUBDIR)

{

fprintf(stdout," ---directory--- ");

ret = compress_dir(file,fd_out);

}

else

{

write_zfile_file_header(file,fd_out);

if(access(file, 2) != 0)    //W_OK=2

{

int attrib;

attrib = _chmod(file,0);

_chmod(file,1,attrib & ~_A_RDONLY);

fprintf(stderr,"When writing file: No privilege to write file %s. ",file);

return -1;

}

fd_in = fopen(file,"rb+");

SET_BINARY_MODE(fd_in);

ret = def(fd_in, fd_out,Z_DEFAULT_COMPRESSION);

if (ret != Z_OK)

zerr(ret);

else

fprintf(stdout," zip over ");

fclose(fd_in);

}

}while( _findnext(lf, &find_data ) == 0 );

}

return 0;

}

 

//int argc, char **argv

struct _finddata_t find_data;

FILE *fd_in;

FILE *fd_out;

const char *file_dir;

char file_out[100];

int ret;

if (argc == 2) 

{

file_dir = argv[1];

if(_findfirst(file_dir,&find_data)==-1l)    //LOOKOUT: not eleven, but one and lowercase 'L'

{

fprintf(stderr,"File or dir %s not found.",file_dir);

return 1;

}

if(find_data.attrib & _A_SUBDIR)

{

sprintf(file_out,"%s%s",file_dir,".z");

fd_out = fopen(file_out,"wb+");

SET_BINARY_MODE(fd_out);

fprintf(stdout,"Dir %s being Compressed ...",file_dir);

ret = compress_dir(file_dir,fd_out);

fclose(fd_out);

}

else

{

fprintf(stdout,"File %s being Compressed ...",file_dir);

sprintf(file_out,"%s%s",file_dir,".z");

fd_in = fopen(file_dir,"rb+");

fd_out = fopen(file_out,"wb+");

SET_BINARY_MODE(fd_in);

SET_BINARY_MODE(fd_out);

ret = def(fd_in, fd_out, Z_DEFAULT_COMPRESSION);

fclose(fd_in);

fclose(fd_out);

}

if (ret != 0)

{

fprintf(stderr,"Compress Error !!!!!!!!!!!!!! ");

zerr(ret);

}

else

fprintf(stdout,"Compress OK--------------- ");

}

else {

fprintf(stdout,"zod usage: zod [file]/[directory] ");

}

getch();

44.验证DTD

/*

#include <stdexcept> // runtime_error

#include <xercesc/sax2/DefaultHandler.hpp>

*/

using namespace std;

using namespace xercesc;

try {

    // Initialize Xerces and obtain a SAX2 parser

    XercesInitializer init;

    auto_ptr<SAX2XMLReader> 

parser(XMLReaderFactory::createXMLReader());

    // Enable validation

    parser->setFeature(XMLUni::fgSAX2CoreValidation, true);

    // Register error handler to receive notifications

    // of DTD violations

    CircusErrorHandler error;

    parser->setErrorHandler(&error);

    parser->parse("animals.xml");

} catch (const SAXException& e) {

cout << "xml error: " << toNative(e.getMessage()) << "/n";

    return EXIT_FAILURE;

} catch (const XMLException& e) {

    cout << "xml error: " << toNative(e.getMessage()) << "/n";

    return EXIT_FAILURE;

} catch (const exception& e) {

cout << e.what() << "/n";

return EXIT_FAILURE;

}

 

45.Schema 验证

/*

#include <xercesc/sax2/XMLReaderFactory.hpp>

#include <xercesc/sax2/SAX2XMLReader.hpp>

#include <xercesc/sax2/DefaultHandler.hpp>

 Handy definitions of constants.

#include <xercesc/util/XMLUni.hpp>

 Create a SAX2 parser object.

*/

SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();

// Set the appropriate features on the parser. Enable namespaces, schema validation, and the checking of all Schema constraints. We refer to these as "common features" in following examples.

parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);

parser->setFeature(XMLUni::fgSAX2CoreValidation, true);

parser->setFeature(XMLUni::fgXercesDynamic, false);

parser->setFeature(XMLUni::fgXercesSchema, true);

parser->setFeature(XMLUni::fgXercesSchemaFullChecking, true);

// Set appropriate ContentHandler, ErrorHandler, and EntityResolver.

// These will be referred to as "common handlers" in subsequent examples.

// You will use a default handler provided by Xerces-C++ (no op action).

// Users should write their own handlers and install them.

DefaultHandler handler;

parser->setContentHandler(&handler);

// The object parser calls when it detects violations of the schema.

parser->setErrorHandler(&handler);

// The object parser calls to find the schema and 

// resolve schema imports/includes.

parser->setEntityResolver(&handler);

// Parse the XML document.

// Document content sent to registered ContentHandler instance.

parser->parse(xmlFile);

// Delete the parser instance.

delete parser;

 

46.Grep

/*

#include<string>

#include "regexpr2.h"

using namespace std;

using namespace regex;

*/

match_results results;

rpattern pat(%%2);

char sRead[5120];

CFile mFile(_T(%%1),CFile::modeRead);

CString content;

while(sRead!=NULL)

{

mFile.Read(sRead,5120);

content+=CString(sRead);

}

mFile.Close();

CString line;

CString sub;

char seperator='/n';

for(int pos=0;AfxExtractSubString(line,content,pos,seperator);++pos)

{

if(line.Trim()!="")

{

string str(line);

match_results::backref_type br=pat.match(str,results);

if(br.matched){

//br

}

}

}

 

/*

//+---------------------------------------------------------------------------

//

//  Copyright ( C ) Microsoft, 1994 - 2002.

//

//  File:       restack.h

//

//  Functions:  a quick-'n'-dirty, type-unsafe stack used by the iterative

//              regular expression algorithm

//

//  Notes:      Care must be taken when using this stack. You must pop off

//              the correct type of object, otherwise you get garbage. Also,

//              if you push anything that has a non-trivial destructor, then

//              be sure to explicitely pop everything off the stack and don't

//              use the unsafe_long_jump method.

//

//  Author:     Eric Niebler ( [email protected] )

//

//  History:    11/15/2001   ericne   Created

//

//----------------------------------------------------------------------------

 

#ifndef HETERO_STACK_H

#define HETERO_STACK_H

 

#include <string>

#include <utility>

#include <typeinfo>

#include <stdexcept>

#include <functional>

 

#ifndef REGEX_CDECL

#ifdef _MSC_VER

#define REGEX_CDECL __cdecl

#else

#define REGEX_CDECL

#endif

#endif

 

#define COMMA ,

#if !defined(_MSC_VER) | 1200 < _MSC_VER

# define REGEX_VC6(x)

# define REGEX_NVC6(x) x

#else

# define REGEX_VC6(x) x

# define REGEX_NVC6(x)

#endif

 

namespace regex

{

 

namespace detail

{

 

// For compile-time assertions that generate

// no run-time overhead.

template< bool f > struct static_assert;

template<>         struct static_assert<true> { static_assert() {} };

 

// Work-around for a template-template parameter problem on VC7.0

template< typename T > struct type2type { typedef T type; };

 

template< bool F > struct bool2type { enum { value = F }; };

 

typedef bool2type<true>  true_t;

typedef bool2type<false> false_t;

 

#ifdef _MSC_VER

// warning C4127: conditional expression is constant

// warning C4189: local variable is initialized but not referenced

// warning C4244: conversion from 'T' to 'int', possible loss of data

// warning C4510: default constructor could not be generated

// warning C4610: struct can never be instantiated - user defined constructor required

// warning C4800: forcing value to bool 'true' or 'false' (performance warning)

#pragma warning( push )

#pragma warning( disable : 4127 4189 4244 4510 4610 4800 )

 

// Make sure nobody has tampered with the packing before defining the

// alignof structure

#pragma pack( push )

#pragma pack() // use the default packing

#endif

 

template< typename T >

class alignof

{

    struct helper

    {

        helper();

        char    m_c;

        T       m_t;

    };

public:

    enum { value = sizeof(helper)-sizeof(T) < sizeof(T) ? sizeof(helper)-sizeof(T) : sizeof(T) };

};

 

#ifdef _MSC_VER

#pragma pack( pop )

#endif

 

//

// Type traits

//

 

typedef char (&yes_type)[1];

typedef char (&no_type)[2];

 

template< bool >

struct select_helper

{

    template< typename T, typename U >

    struct nested

    {

        typedef T type;

    };

};

 

template<>

struct select_helper<false>

{

    template< typename T, typename U >

    struct nested

    {

        typedef U type;

    };

};

 

// For use in conditional typedefs

template< bool F, typename T, typename U >

struct select

{

    typedef typename select_helper<F>::template nested<T,U>::type type;

};

 

template< typename U >

struct convertible_helper

{

    static yes_type             check( U );

    static no_type  REGEX_CDECL check(...);

};

 

template< typename T >

struct factory

{

    static T& make();

};

 

template< typename T, typename U >

struct is_convertible

{

    enum { value = (sizeof(convertible_helper<U>::check(factory<T>::make()))==sizeof(yes_type)) };

};

 

template< size_t N >

struct is_power_of_two

{

    enum { value = 1==N || 0==(N%2) && is_power_of_two<N/2>::value };

};

 

template<>

struct is_power_of_two<0>

{

    enum { value = false };

};

 

// Very primative implementation of is_scalar. This doesn't work

// for void, reference types, array types or function types, but

// we don't use those types from hetero_stack.

struct bool_convertible { bool_convertible(bool); };

 

template< typename T >

struct is_scalar

{

    enum { value = is_convertible<T,bool_convertible>::value };

};

 

template< typename T >

struct has_trivial_copy

{

    enum { value = is_scalar<T>::value };

};

 

template< typename T >

struct has_trivial_assignment

{

    enum { value = is_scalar<T>::value };

};

 

template< typename T >

struct has_trivial_destructor

{

    enum { value = is_scalar<T>::value };

};

 

template< bool > struct destroyer_helper

{

    template< typename T >

    static void destroy( T const * pT )

    {

        pT, pT->~T();

    }

};

template<> struct destroyer_helper<true>

{

    template< typename T >

    static void destroy( T const * )

    {

    }

};

template< typename T >

void destroy( T const * pT )

{

    destroyer_helper<has_trivial_destructor<T>::value>::destroy( pT );

}

 

struct type_vtable

{

    std::type_info const *  typeinfo_ptr;

    size_t             size;

    size_t             aligned_size;

    void (*destroy)( void * );

    void (*copy)( void *, void const * );

};

 

template< typename T, size_t AlignmentT >

class type_info_ex

{

    static void destroy( void * pv )

    {

        T const * pT = static_cast<T const*>( pv );

        regex::detail::destroy( pT );

        (void)pv;

        (void)pT;

    }

    static void copy( void * dst, void const * src )

    {

        new ( dst ) T( *static_cast<T const *>( src ) );

    }

public:

    static type_vtable const vtable;

 

    static bool equals( type_vtable const * ptm )

    {

        return ptm == & vtable || *ptm->typeinfo_ptr == typeid(T);

    }

};

 

template< typename T,size_t AlignmentT >

type_vtable const type_info_ex<T,AlignmentT>::vtable =

{

    &typeid(T),

    sizeof(T),

    ( sizeof(T) + AlignmentT - 1 ) & ~( AlignmentT - 1 ),

    has_trivial_destructor<T>::value ? 0 : &type_info_ex<T,AlignmentT>::destroy,

    &type_info_ex<T,AlignmentT>::copy

};

 

template< typename T >

inline T & to_type( void * pv )

{

    return *static_cast<T*>( pv );

}

 

} // namespace detail

 

// --------------------------------------------------------------------------

//

// Class:       hetero_stack

//

// Description: Fast, heterogeneous stack.

//

// Methods:     allocate        - reserve space on stack

//              unwind          - unwind the stack

//              hetero_stack    - c'tor

//              ~hetero_stack   - d'tor, release all dynamic memory

//              push            - push an object on the stack

//              pop             - pop an object from the stack

//

// Members:     m_first_node    -

//              m_current_node  -

//

// Typedefs:    byte_t            -

//

// History:     10/19/2001 - ericne - Created

//

// --------------------------------------------------------------------------

template

<

    size_t  AlignmentT         = sizeof(void*),

    bool    RuntimeTypeCheckT  = true,  // should we perform run-time type checking?

    bool    AssumePodT         = false, // assume non-throwing copy/assign/destroy for better perf

    size_t  DynamicBlockSizeT  = 4096,  // blocks allocated from heap are this size

    size_t  StaticBlockSizeT   = 1024   // initial block on stack is this size

>

class hetero_stack

{

    typedef unsigned char byte_t;

    typedef detail::type_vtable const* vtable_ptr;

 

public:

 

    typedef hetero_stack<AlignmentT,RuntimeTypeCheckT,AssumePodT,DynamicBlockSizeT,StaticBlockSizeT> stack_type;

 

    template< typename T >

    struct aligned_sizeof

    {

        enum

        {

            // round up sizeof(T) to the nearest multiple of AlignmentT

            no_rtti   = ( sizeof( T ) + AlignmentT - 1 ) & ~( AlignmentT - 1 ),

            with_rtti = RuntimeTypeCheckT ?

                no_rtti + aligned_sizeof<vtable_ptr>::no_rtti :

                no_rtti

        };

    };

 

private:

 

    struct stack_node

    {

        struct header

        {

            stack_node * m_back;

            stack_node * m_next;

            byte_t     * m_current; // ptr into m_mem. alloc from here

            byte_t     * m_end;     // ptr to last+1 byte_t in m_mem

        };

 

        union

        {

            header  m_head;

            byte_t  m_align[ aligned_sizeof<header>::no_rtti ];

        };

 

        // This is the buffer into which values will be pushed and popped.

        // It is guaranteed to meet the AlignmentT requirements because of

        // the union above.

        byte_t  m_mem[1];

 

        size_t size() const // throw()

        {

            return static_cast<size_t>( m_head.m_end - m_mem );

        }

    };

 

    enum

    {

        DYNAMIC_BLOCK_SIZE =

            DynamicBlockSizeT > sizeof( stack_node ) ?

            DynamicBlockSizeT : sizeof( stack_node )

    };

 

    union

    {

        stack_node  m_node;

        byte_t      m_buf[ aligned_sizeof<stack_node::header>::no_rtti + StaticBlockSizeT ];

    } m_first_node;

 

    stack_node * m_current_node;

 

    // Cache these for faster access

    byte_t * m_begin;

    byte_t * m_current;

    byte_t * m_end;

 

    byte_t * grow( size_t size ) // throw(std::bad_alloc)

    {

        // write the cached value of current into the node.

        // OK to do this even if later statements throw.

        m_current_node->m_head.m_current = m_current;

 

        // Do we have a node with available memory already?

        if( m_current_node->m_head.m_next )

        {

            // Does this node have enough room?

            if( size <= m_current_node->m_head.m_next->size() )

            {

                m_current_node  = m_current_node->m_head.m_next;

                m_current       = m_current_node->m_head.m_current = m_current_node->m_mem + size;

                m_end           = m_current_node->m_head.m_end;

                return m_begin  = m_current_node->m_mem;

            }

 

            // Create a new node and insert it into the list

            stack_node * new_node = static_cast<stack_node*>(

                ::operator new( size + offsetof( stack_node, m_mem ) ) );

 

            new_node->m_head.m_back = m_current_node;

            new_node->m_head.m_next = m_current_node->m_head.m_next;

 

            m_current = m_end = new_node->m_head.m_current =

                new_node->m_head.m_end = new_node->m_mem + size;

 

            m_current_node->m_head.m_next->m_head.m_back = new_node;

            m_current_node->m_head.m_next = new_node;

            m_current_node = new_node;

 

            return m_begin = m_current_node->m_mem;

        }

 

        // We need to create a new node from scratch

        size_t new_size = detail::regex_max( size,

            static_cast<size_t>(DYNAMIC_BLOCK_SIZE) - offsetof( stack_node, m_mem ) );

 

        stack_node * new_node = static_cast<stack_node*>(

            ::operator new( new_size + offsetof( stack_node, m_mem ) ) );

 

        new_node->m_head.m_back = m_current_node;

        new_node->m_head.m_next = 0;

 

        m_current = new_node->m_head.m_current = new_node->m_mem + size;

        m_end     = new_node->m_head.m_end     = new_node->m_mem + new_size;

 

        m_current_node->m_head.m_next = new_node;

        m_current_node = new_node;

 

        return m_begin = m_current_node->m_mem;

    }

 

    byte_t * allocate( size_t size ) // throw(std::bad_alloc)

    {

        // This is the ptr to return

        byte_t * mem = m_current;

 

        // Advance the high-water mark

        m_current += size;

 

        // Check to see if we have overflowed this buffer

        if( std::less<void*>()( m_end, m_current ) ) // if( m_end < m_current )

        {

            // oops, back this out.

            m_current = mem;

 

            // allocate a new block and return a ptr to the new memory

            return grow( size );

        }

 

        return mem;

    }

 

    byte_t * unwind( byte_t * pb ) // throw()

    {

        // roll back the stack

        m_current = pb;

 

        // If we've unwound this whole block, then make the

        // previous node the current node

        if( m_current == m_begin )

        {

            // write the cached value of m_current into m_current_node

            m_current_node->m_head.m_current = m_current;

            m_current_node = m_current_node->m_head.m_back;

 

            // update the cache

            m_begin   = m_current_node->m_mem;

            m_current = m_current_node->m_head.m_current;

            m_end     = m_current_node->m_head.m_end;

        }

 

        return pb;

    }

 

    byte_t * unwind( size_t size ) // throw()

    {

        return unwind( m_current - size );

    }

 

    void long_jump_impl( void * jump_ptr, detail::bool2type<true> ) // throw()

    {

        safe_long_jump( jump_ptr );

    }

 

    void long_jump_impl( void * jump_ptr, detail::bool2type<false> ) // throw()

    {

        unsafe_long_jump( jump_ptr );

    }

 

    struct real_unwinder;

    friend struct real_unwinder;

    struct real_unwinder

    {

        real_unwinder( stack_type * pstack, size_t size ) // throw()

            : m_pstack(pstack), m_size(size) {}

 

        ~real_unwinder() // throw()

        {

            if( m_pstack )

                m_pstack->unwind( m_size );

        }

 

        void dismiss() // throw()

        {

            m_pstack = 0;

        }

 

    private:

        real_unwinder( real_unwinder const & );

        real_unwinder & operator=( real_unwinder const & );

 

        stack_type * m_pstack;

        size_t       m_size;

    };

 

    struct dummy_unwinder

    {

        dummy_unwinder( stack_type *, size_t ) {} // throw()

        void dismiss() {} // throw()

    };

 

    // Disallow these for now. Might implement them later.

    hetero_stack( hetero_stack const & );

    hetero_stack & operator=( hetero_stack const & );

 

public:

 

    class type_error : public std::logic_error

    {

        std::type_info const * m_prequested_type;

        std::type_info const * m_pactual_type;

    public:

        type_error

        (

            std::type_info const & requested_type,

            std::type_info const & actual_type,

            std::string const & s = "type error in hetero_stack"

        ) // throw()

            : std::logic_error( s + " (requested type: " + requested_type.name()

                + ", actual type: " + actual_type.name() + ")" )

            , m_prequested_type( &requested_type )

            , m_pactual_type( &actual_type )

        {

        }

        std::type_info const & requested_type() const // throw()

        {

            return *m_prequested_type;

        }

        std::type_info const & actual_type() const // throw()

        {

            return *m_pactual_type;

        }

    };

 

    hetero_stack() // throw()

        : m_current_node( &m_first_node.m_node )

    {

        m_first_node.m_node.m_head.m_back    = & m_first_node.m_node;

        m_first_node.m_node.m_head.m_next    = 0;

        m_begin = m_current = m_first_node.m_node.m_head.m_current = m_first_node.m_node.m_mem;

        m_end = m_first_node.m_node.m_head.m_end = m_first_node.m_buf + sizeof( m_first_node );

    }

 

    ~hetero_stack() // throw()

    {

        // AlignmentT must be a power of two

        detail::static_assert< detail::is_power_of_two<AlignmentT>::value > const align_test;

 

        // Call any destructors for objects still on the stack

        if( RuntimeTypeCheckT && ! AssumePodT )

        {

            long_jump( m_first_node.m_node.m_mem );

        }

 

        // delete all the memory blocks

        m_current_node = m_first_node.m_node.m_head.m_next;

        for( stack_node * next_node; m_current_node; m_current_node = next_node )

        {

            next_node = m_current_node->m_head.m_next;

            ::operator delete( static_cast<void*>( m_current_node ) );

        }

    }

 

    template< typename T >

    inline void push( T const & t ) // throw(std::bad_alloc,...)

    {

        // Make sure that the alignment for type T is not worse

        // than our declared alignment.

        detail::static_assert<( AlignmentT >= detail::alignof<T>::value )> const align_test;

        static_cast<void>(align_test);

 

        // If T won't throw in copy c'tor then we don't need to use an unwinder object.

        typedef typename detail::select< AssumePodT || detail::has_trivial_copy<T>::value,

            dummy_unwinder, real_unwinder >::type unwinder;

 

        // If this throws, it doesn't change state,

        // so there is nothing to roll back.

        byte_t * pb = allocate( aligned_sizeof<T>::with_rtti );

 

        // Rolls back the allocate if later steps throw

        // BUGBUG we can do the alloc, but not update m_current until after

        // the copy c'tor to avoid the need for an unwinder object

        unwinder guard( this, aligned_sizeof<T>::with_rtti );

 

        new ( pb ) T( t ); // Could throw if ! has_trivial_copy<T>::value

 

        // If we are debugging the stack, then push a pointer to the type_info

        // for this type T. It will be checked in pop().

        if( RuntimeTypeCheckT )

        {

            detail::to_type<vtable_ptr>( pb + aligned_sizeof<T>::no_rtti ) = & detail::type_info_ex<T,AlignmentT>::vtable;

        }

 

        // ok, everything succeeded -- dismiss the guard

        guard.dismiss();

    }

 

    template< typename T >

    inline void pop( T & t ) // throw(...)

    {

        detail::static_assert<( AlignmentT >= detail::alignof<T>::value )> const align_test;

        static_cast<void>(align_test);

 

        // If we are debugging the stack, then in push() we pushed a pointer

        // to the type_info struct for this type T.  Check it now.

        if( RuntimeTypeCheckT )

        {

            byte_t * pti = m_current - aligned_sizeof<vtable_ptr>::no_rtti;

            if( ! detail::type_info_ex<T,AlignmentT>::equals( detail::to_type<vtable_ptr>( pti ) ) )

                throw type_error( typeid( T ), *detail::to_type<vtable_ptr>( pti )->typeinfo_ptr );

        }

 

        // Don't change state yet because assignment op could throw!

        byte_t * pT = m_current - aligned_sizeof<T>::with_rtti;

        t = detail::to_type<T const>( pT ); // could throw

        T const & ref = detail::to_type<T const>( pT );

        regex::detail::destroy( &ref );

        unwind( pT );

    }

 

    // Call this version of pop when you don't need the popped value

    template< typename T >

    inline void pop( REGEX_VC6(detail::type2type<T> COMMA int) ) // throw(type_error,...)

    {

        detail::static_assert<( AlignmentT >= detail::alignof<T>::value )> const align_test;

        static_cast<void>(align_test);

 

        // If we are debugging the stack, then in push() we pushed a pointer

        // to the type_info struct for this type T.  Check it now.

        if( RuntimeTypeCheckT )

        {

            byte_t * pti = m_current - aligned_sizeof<vtable_ptr>::no_rtti;

            if( ! detail::type_info_ex<T,AlignmentT>::equals( detail::to_type<vtable_ptr>( pti ) ) )

                throw type_error( typeid( T ), *detail::to_type<vtable_ptr>( pti )->typeinfo_ptr );

        }

 

        byte_t * pv = unwind( aligned_sizeof<T>::with_rtti );

        T const & ref = detail::to_type<T const>( pv );

        regex::detail::destroy( &ref );

    }

 

    // Call this version of pop when you don't need the popped value and

    // throwing an exception isn't an option

    template< typename T >

    inline bool pop( std::nothrow_t const & ) // throw()

    {

        detail::static_assert<( AlignmentT >= detail::alignof<T>::value )> const align_test;

        static_cast<void>(align_test);

 

        // If we are debugging the stack, then in push() we pushed a pointer

        // to the type_info struct for this type T.  Check it now.

        if( RuntimeTypeCheckT )

        {

            byte_t * pti = m_current - aligned_sizeof<vtable_ptr>::no_rtti;

            if( ! detail::type_info_ex<T,AlignmentT>::equals( detail::to_type<vtable_ptr>( pti ) ) )

                return false; // type error, can't throw so bail.

        }

 

        byte_t * pv = unwind( aligned_sizeof<T>::with_rtti );

        T const & ref = detail::to_type<T const>( pv );

        regex::detail::destroy( &ref );

        return true;

    }

 

    template< typename T >

    inline T & top( REGEX_VC6(detail::type2type<T>) ) const // throw(type_error,...)

    {

        detail::static_assert<( AlignmentT >= detail::alignof<T>::value )> const align_test;

        static_cast<void>(align_test);

 

        if( RuntimeTypeCheckT )

        {

            // If we are debugging the stack, then the top of the stack is a

            // pointer to a type_info struct. Assert that we have the correct type.

            byte_t * pti = m_current - aligned_sizeof<vtable_ptr>::no_rtti;

            if( ! detail::type_info_ex<T,AlignmentT>::equals( detail::to_type<vtable_ptr>( pti ) ) )

                throw type_error( typeid( T ), *detail::to_type<vtable_ptr>( pti )->typeinfo_ptr );

        }

 

        byte_t * pT = m_current - aligned_sizeof<T>::with_rtti;

        return detail::to_type<T>( pT );

    }

 

    // Fetch the type_info for the element at the top of the stack

    std::type_info const & top_type() const // throw()

    {

        detail::static_assert< RuntimeTypeCheckT > const type_check;

        static_cast<void>(type_check);

 

        byte_t * pti = m_current - aligned_sizeof<vtable_ptr>::no_rtti;

        return *detail::to_type<vtable_ptr>( pti )->typeinfo_ptr;

    }

 

    // Get a pointer to the top of the stack

    void * set_jump() const // throw()

    {

        return m_current;

    }

 

    // Quick and dirty stack unwind. Does not call destructors.

    void unsafe_long_jump( void *const jump_ptr ) // throw()

    {

        for( ;; )

        {

            if( std::less<void*>()( jump_ptr, m_current_node->m_mem ) ||

                std::less<void*>()( m_current_node->m_head.m_end, jump_ptr ) )

            {

                m_current_node->m_head.m_current = m_current_node->m_mem;

                m_current_node = m_current_node->m_head.m_back;

            }

            else

            {

                m_begin   = m_current_node->m_mem;

                m_current = m_current_node->m_head.m_current = static_cast<byte_t*>( jump_ptr );

                m_end     = m_current_node->m_head.m_end;

                return;

            }

        }

    }

 

    // Safe long jump; does call destructors if RuntimeTypeCheckT is true.

    void safe_long_jump( void *const jump_ptr ) // throw()

    {

        detail::static_assert< RuntimeTypeCheckT > const type_check;

        static_cast<void>(type_check);

 

        while( m_current != jump_ptr )

        {

            // The top of the stack is a pointer to a type_vtable struct.

            m_current -= aligned_sizeof<vtable_ptr>::no_rtti;

            vtable_ptr pvtable = detail::to_type<vtable_ptr>( m_current );

 

            // find the start of the object

            m_current -= pvtable->aligned_size;

 

            // call the destructor for T

            if( pvtable->destroy )

            {

                pvtable->destroy( m_current );

            }

 

            // move to the previous buffer if necessary

            if( m_current == m_begin && m_current != jump_ptr )

            {

                m_current_node->m_head.m_current = m_current;

                m_current_node = m_current_node->m_head.m_back;

                m_begin   = m_current_node->m_mem;

                m_current = m_current_node->m_head.m_current;

                m_end     = m_current_node->m_head.m_end;

            }

        }

    }

 

    // Stack unwind. If RuntimeTypeCheckT && !AssumePodT, then destructors

    // are called.  Otherwise they are not.

    void long_jump( void * jump_ptr ) // throw()

    {

        long_jump_impl( jump_ptr, detail::bool2type<RuntimeTypeCheckT && !AssumePodT>() );

    }

 

    struct stack_guard

    {

        stack_type * m_ps;

        void       * m_jump_ptr;

 

        explicit stack_guard( stack_type * ps )

            : m_ps( ps )

            , m_jump_ptr( ps->set_jump() )

        {

        }

        ~stack_guard()

        {

            m_ps->long_jump( m_jump_ptr );

        }

    };

 

    bool empty() const // throw()

    {

        return m_current == m_first_node.m_node.m_mem;

    }

 

    // Use scoped_push for automatically pushing/popping

    // things to and from the stack. This is especially useful

    // if you want to push a bunch of things "atomically".  For

    // instance:

    //

    // typedef hetero_stack<>::scoped_pop scoped_pop;

    // scoped_pop p1 = stack.scoped_push( int(1) ); // could throw

    // scoped_pop p2 = stack.scoped_push( std::string("foo") ); // could throw

    // stack.push( float(3.14159) ); // could throw

    // p2.dismiss(); // ok, nothing threw, so ...

    // p1.dismiss(); //  ... dismiss the scoped_pops

    //

    // If p2 and p1 are not dismissed, as in the case when an

    // exception gets thrown, then they automatically pop their

    // arguments from the stack.

 

    class scoped_pop_base

    {

        scoped_pop_base & operator=( scoped_pop_base const & ); // disallow assignment

    protected:

        mutable stack_type * m_pstack;

 

        explicit scoped_pop_base( stack_type * pstack ) // throw(std::bad_alloc,...)

          : m_pstack( pstack )

        {

        }

        scoped_pop_base( scoped_pop_base const & right ) // throw() // destructive copy

          : m_pstack( right.m_pstack )

        {

            right.dismiss();

        }

    public:

        void dismiss() const // throw()

        {

            m_pstack = 0;

        }

    };

 

    template< typename T >

    class scoped_pop_t : public scoped_pop_base

    {

        scoped_pop_t & operator=( scoped_pop_t const & ); // disallow assignment

    public:

        scoped_pop_t( stack_type * pstack, T const & t ) // throw(std::bad_alloc,...)

          : scoped_pop_base( pstack )

        {

            // Note that if this throws an exception the destructor

            // will not get called, which is what we want.

            m_pstack->push( t );

        }

        ~scoped_pop_t() // throw()

        {

            // If we own this stack space, pop it.

            if( m_pstack )

                m_pstack->template pop<T>( std::nothrow );

        }

    };

 

    template< typename T >

    scoped_pop_t<T> scoped_push( T const & t ) // throw(...)

    {

        return scoped_pop_t<T>( this, t );

    }

 

    typedef scoped_pop_base const & scoped_pop;

};

 

#ifdef _MSC_VER

#pragma warning( pop )

#endif

 

} // namespace regex

 

#endif

//+---------------------------------------------------------------------------

//

//  Copyright ( C ) Microsoft, 1994 - 2002.

//

//  File:       syntax2.h

//

//  Contents:   syntax modules for regexpr

//

//  Classes:    perl_syntax, posix_syntax

//

//  Author:     Eric Niebler ( [email protected] )

//

//  History:    3-29-00   ericne   Created

//

//----------------------------------------------------------------------------

 

#ifndef SYNTAX_H

#define SYNTAX_H

 

#ifdef _MSC_VER

#pragma warning( push )

// warning C4786: identifier was truncated to '255' characters in the debug information

#pragma warning( disable : 4786 )

#endif

 

#include <map>

#include <iosfwd>

#include <string>

#include <cctype>

#include <cwctype>

#include <cassert>

#include <iterator>

#include <stdexcept>

 

#ifndef ARRAYSIZE

# define ARRAYSIZE( a ) (sizeof(a)/sizeof((a)[0]))

#endif

 

#ifndef UCHAR_MAX

# define UCHAR_MAX 0xff

#endif

 

#ifndef WCHAR_MAX

# define WCHAR_MAX ((wchar_t)-1)

#endif

 

#ifdef _MSC_VER

# include <crtdbg.h>

# define REGEX_ASSERT(x)        _ASSERTE(x)

# define REGEX_FORCEINLINE      __forceinline

# define REGEX_SELECTANY        __declspec(selectany)

# define REGEX_CDECL            __cdecl

# define REGEX_SEH_TRY          __try

# define REGEX_SEH_EXCEPT(x)    __except( x )

# define REGEX_RESET_STK_OFLW() _resetstkoflw()

# if 1200 < _MSC_VER

# define REGEX_NOINLINE         __declspec(noinline)

# define REGEX_DEPRECATED       __declspec(deprecated)

# define REGEX_DEPENDENT_TYPENAME typename

# else

# define REGEX_NOINLINE

# define REGEX_DEPRECATED

# define REGEX_DEPENDENT_TYPENAME

# endif

#else

# include <cassert>

# define REGEX_ASSERT(x)        assert(x)

# define REGEX_NOINLINE

# define REGEX_FORCEINLINE      inline

# define REGEX_SELECTANY

# define REGEX_CDECL

# define REGEX_SEH_TRY

# define REGEX_SEH_EXCEPT(x)    if( false )

# define REGEX_RESET_STK_OFLW() ((void)0)

# define REGEX_DEPRECATED

# define REGEX_DEPENDENT_TYPENAME typename

#endif

 

#define REGEX_STRING(CharT,sz) (::regex::detail::literal<CharT>::string( sz, L##sz ))

#define REGEX_CHAR(CharT,ch) (static_cast<CharT>(::regex::detail::literal<CharT>::template character<ch,L##ch>::value))

 

#if defined(_MSC_VER) & _CPPLIB_VER <= 310

namespace std

{

template<>

struct iterator_traits< char * >

{    // get traits from iterator _Iter

    typedef random_access_iterator_tag iterator_category;

    typedef char value_type;

    typedef ptrdiff_t difference_type;

    typedef difference_type distance_type;    // retained

    typedef char * pointer;

    typedef char & reference;

};

template<>

struct iterator_traits< char const * >

{    // get traits from iterator _Iter

    typedef random_access_iterator_tag iterator_category;

    typedef char value_type;

    typedef ptrdiff_t difference_type;

    typedef difference_type distance_type;    // retained

    typedef char * pointer;

    typedef char & reference;

};

 

template<>

struct iterator_traits< wchar_t * >

{    // get traits from iterator _Iter

    typedef random_access_iterator_tag iterator_category;

    typedef wchar_t value_type;

    typedef ptrdiff_t difference_type;

    typedef difference_type distance_type;    // retained

    typedef wchar_t * pointer;

    typedef wchar_t & reference;

};

template<>

struct iterator_traits< wchar_t const * >

{    // get traits from iterator _Iter

    typedef random_access_iterator_tag iterator_category;

    typedef wchar_t value_type;

    typedef ptrdiff_t difference_type;

    typedef difference_type distance_type;    // retained

    typedef wchar_t * pointer;

    typedef wchar_t & reference;

};

}

#endif

 

namespace regex

{

 

class bad_regexpr : public std::invalid_argument

{

public:

    explicit bad_regexpr( std::string const & s )

        : std::invalid_argument( s ) {}

    virtual ~bad_regexpr() throw() {}

};

 

//

// Flags to control how matching occurs

//

enum REGEX_FLAGS

{

    NOFLAGS       = 0x0000,

    NOCASE        = 0x0001, // ignore case

    GLOBAL        = 0x0002, // match everywhere in the string

    MULTILINE     = 0x0004, // ^ and $ can match internal line breaks

    SINGLELINE    = 0x0008, // . can match newline character

    RIGHTMOST     = 0x0010, // start matching at the right of the string

    NOBACKREFS    = 0x0020, // only meaningful when used with GLOBAL and substitute

    FIRSTBACKREFS = 0x0040, // only meaningful when used with GLOBAL

    ALLBACKREFS   = 0x0080, // only meaningful when used with GLOBAL

    NORMALIZE     = 0x0100, // Preprocess patterns: "//n" => "/n", etc.

    EXTENDED      = 0x0200, // ignore whitespace in pattern

};

 

// For backwards compatibility

REGEX_FLAGS const noflags = NOFLAGS;

 

// helper functions to make it easier to combine

// the regex flags.

inline REGEX_FLAGS operator|( REGEX_FLAGS f1, REGEX_FLAGS f2 )

{

    return ( REGEX_FLAGS ) ( ( unsigned )f1 | ( unsigned )f2 );

}

inline REGEX_FLAGS & operator|=( REGEX_FLAGS & f1, REGEX_FLAGS f2 )

{

    return f1 = ( f1 | f2 );

}

inline REGEX_FLAGS operator&( REGEX_FLAGS f1, REGEX_FLAGS f2 )

{

    return ( REGEX_FLAGS ) ( ( unsigned )f1 & ( unsigned )f2 );

}

inline REGEX_FLAGS & operator&=( REGEX_FLAGS & f1, REGEX_FLAGS f2 )

{

    return f1 = ( f1 & f2 );

}

#if !defined(_MSC_VER) | 1200 < _MSC_VER

inline REGEX_FLAGS operator~( REGEX_FLAGS f )

{

    return ( REGEX_FLAGS ) ~( unsigned )f;

}

#endif

 

//

// The following are the tokens that can be emitted by the syntax module.

// Don't reorder this list!!!

//

enum TOKEN

{

    NO_TOKEN = 0,

 

    // REGULAR TOKENS

    BEGIN_GROUP,

    END_GROUP,

    ALTERNATION,

    BEGIN_LINE,

    END_LINE,

    BEGIN_CHARSET,

    MATCH_ANY,

    ESCAPE,

 

    // QUANTIFICATION TOKENS

    ONE_OR_MORE,

    ZERO_OR_MORE,

    ZERO_OR_ONE,

    ONE_OR_MORE_MIN,

    ZERO_OR_MORE_MIN,

    ZERO_OR_ONE_MIN,

    BEGIN_RANGE,

    RANGE_SEPARATOR,

    END_RANGE,

    END_RANGE_MIN,

 

    // ESCAPE SEQUENCES

    ESC_DIGIT,

    ESC_NOT_DIGIT,

    ESC_SPACE,

    ESC_NOT_SPACE,

    ESC_WORD,

    ESC_NOT_WORD,

    ESC_BEGIN_STRING,

    ESC_END_STRING,

    ESC_END_STRING_z,

    ESC_WORD_BOUNDARY,

    ESC_NOT_WORD_BOUNDARY,

    ESC_WORD_START,

    ESC_WORD_STOP,

    ESC_QUOTE_META_ON,

    ESC_QUOTE_META_OFF,

 

    // SUBSTITUTION TOKENS

    SUBST_BACKREF,

    SUBST_PREMATCH,

    SUBST_POSTMATCH,

    SUBST_MATCH,

    SUBST_ESCAPE,

    SUBST_QUOTE_META_ON,

    SUBST_UPPER_ON,

    SUBST_UPPER_NEXT,

    SUBST_LOWER_ON,

    SUBST_LOWER_NEXT,

    SUBST_ALL_OFF,

 

    // CHARSET TOKENS

    CHARSET_NEGATE,

    CHARSET_ESCAPE,

    CHARSET_RANGE,

    CHARSET_BACKSPACE,

    CHARSET_END,

    CHARSET_ALNUM,

    CHARSET_NOT_ALNUM,

    CHARSET_ALPHA,

    CHARSET_NOT_ALPHA,

    CHARSET_BLANK,

    CHARSET_NOT_BLANK,

    CHARSET_CNTRL,

    CHARSET_NOT_CNTRL,

    CHARSET_DIGIT,

    CHARSET_NOT_DIGIT,

    CHARSET_GRAPH,

    CHARSET_NOT_GRAPH,

    CHARSET_LOWER,

    CHARSET_NOT_LOWER,

    CHARSET_PRINT,

    CHARSET_NOT_PRINT,

    CHARSET_PUNCT,

    CHARSET_NOT_PUNCT,

    CHARSET_SPACE,

    CHARSET_NOT_SPACE,

    CHARSET_UPPER,

    CHARSET_NOT_UPPER,

    CHARSET_XDIGIT,

    CHARSET_NOT_XDIGIT,

 

    // EXTENSION TOKENS

    EXT_NOBACKREF,

    EXT_POS_LOOKAHEAD,

    EXT_NEG_LOOKAHEAD,

    EXT_POS_LOOKBEHIND,

    EXT_NEG_LOOKBEHIND,

    EXT_INDEPENDENT,

    EXT_COMMENT,

    EXT_CONDITION,

    EXT_RECURSE,

    EXT_UNKNOWN

};

 

namespace detail

{

 

template< typename CharT > struct literal;

 

template<> struct literal<char>

{

    static char const * string( char const * sz, wchar_t const * ) { return sz; }

    template< char ch, wchar_t > struct character { enum { value = ch }; };

};

 

template<> struct literal<wchar_t>

{

    static wchar_t const * string( char const *, wchar_t const * sz ) { return sz; }

    template< char, wchar_t ch > struct character { enum { value = ch }; };

};

 

struct posix_charset_type

{

    char const * m_szcharset;

    size_t       cchars;

};

 

extern posix_charset_type const g_rgposix_charsets[];

extern size_t const g_cposix_charsets;

 

template< typename IterT >

bool is_posix_charset( IterT icur, IterT iend, char const * szcharset )

{

    for( ; iend != icur && char() != *szcharset; ++icur, ++szcharset )

    {

        if( *icur != *szcharset )

            return false;

    }

    return char() == *szcharset;

}

 

// Forward-declare the class that holds all the information

// about the set of characters that can be matched by a charset

struct charset;

void free_charset( charset const * );

 

template< typename CharT >

struct charset_map_node

{

    std::basic_string<CharT> m_str;

    charset const * m_rgcharsets[2]; // 0==case, 1==nocase

 

    charset_map_node()

    {

        m_rgcharsets[0] = m_rgcharsets[1] = 0;

    }

 

    charset_map_node( charset_map_node const & node )

    {

        *this = node;

    }

 

    charset_map_node & operator=( charset_map_node const & node )

    {

        m_str = node.m_str;

        m_rgcharsets[0] = node.m_rgcharsets[0];

        m_rgcharsets[1] = node.m_rgcharsets[1];

        return *this;

    }

 

    void set( std::basic_string<CharT> const & str )

    {

        clear();

        m_str = str;

    }

 

    void clear()

    {

        std::basic_string<CharT>().swap( m_str );

        free_charset( m_rgcharsets[0] );

        free_charset( m_rgcharsets[1] );

        m_rgcharsets[0] = m_rgcharsets[1] = 0;

    }

};

 

template< typename CharT >

class charset_map

{

    std::map<CharT, charset_map_node<CharT> > m_map;

public:

    typedef typename std::map<CharT, charset_map_node<CharT> >::iterator iterator;

    ~charset_map()

    {

        for( iterator iter = m_map.begin(); m_map.end() != iter; ++iter )

            iter->second.clear();

    }

    charset_map_node<CharT> & operator[]( CharT ch ) { return m_map[ ch ]; }

    iterator begin() { return m_map.begin(); }

    iterator end() { return m_map.end(); }

    iterator find( CharT ch ) { return m_map.find( ch ); }

    void erase( iterator iter ) { m_map.erase( iter ); }

};

 

 

inline detail::charset_map<char> & get_perl_charset_map( char )

{

    static detail::charset_map<char> s_charset_map;

    return s_charset_map;

}

 

inline detail::charset_map<wchar_t> & get_perl_charset_map( wchar_t )

{

    static detail::charset_map<wchar_t> s_charset_map;

    return s_charset_map;

}

 

inline detail::charset_map<char> & get_posix_charset_map( char )

{

    static detail::charset_map<char> s_charset_map;

    return s_charset_map;

}

 

inline detail::charset_map<wchar_t> & get_posix_charset_map( wchar_t )

{

    static detail::charset_map<wchar_t> s_charset_map;

    return s_charset_map;

}

 

inline bool regex_isspace( char ch )

{

    using namespace std;

    return 0 != isspace( ch );

}

 

inline bool regex_isspace( wchar_t wch )

{

    using namespace std;

    return 0 != iswspace( wch );

}

 

template< typename T >

T const & regex_max( T const & lhs, T const & rhs )

{

    return ( lhs > rhs ) ? lhs : rhs;

}

 

template< typename T >

T const & regex_min( T const & lhs, T const & rhs )

{

    return ( lhs < rhs ) ? lhs : rhs;

}

 

} // namespace detail

 

//

// The perl_syntax class encapsulates the Perl 5 regular expression syntax. It is

// used as a template parameter to basic_rpattern.  To customize regex syntax, create

// your own syntax class and use it as a template parameter instead.

//

 

class perl_syntax_base

{

protected:

    perl_syntax_base()

    {

    }

 

    static TOKEN const s_rgreg[ UCHAR_MAX + 1 ];

    static TOKEN const s_rgescape[ UCHAR_MAX + 1 ];

 

    static TOKEN look_up( char ch, TOKEN const rg[] )

    {

        return rg[ static_cast<unsigned char>( ch ) ];

    }

    static TOKEN look_up( wchar_t ch, TOKEN const rg[] )

    {

        return UCHAR_MAX < ch ? NO_TOKEN : rg[ static_cast<unsigned char>( ch ) ];

    }

};

 

// --------------------------------------------------------------------------

//

// Class:       perl_syntax

//

// Description: Module that encapsulates the Perl syntax

//

// Methods:     eat_whitespace             -

//              min_quant                  -

//              perl_syntax                -

//              perl_syntax                -

//              set_flags                  -

//              get_flags                  -

//              reg_token                  -

//              quant_token                -

//              charset_token              -

//              subst_token                -

//              ext_token                  -

//              get_charset_map            -

//              invalid_charset            -

//              register_intrinsic_charset -

//              _invalid_charset           -

//              _invalid_charset           -

//

// Members:     m_flags                    -

//              s_charset_map              -

//

// Typedefs:    iterator                   -

//              const_iterator             -

//              char_type                  -

//

// History:     11/16/2001 - ericne - Created

//

// --------------------------------------------------------------------------

template< typename CharT >

class perl_syntax : protected perl_syntax_base

{

public:

    typedef typename std::basic_string<CharT>::iterator iterator;

    typedef typename std::basic_string<CharT>::const_iterator const_iterator;

    typedef CharT char_type;

    template< typename OtherT > struct rebind { typedef perl_syntax<OtherT> other; };

 

private:

    REGEX_FLAGS m_flags;

 

    const_iterator eat_whitespace( iterator & icur, const_iterator iend )

    {

        if( m_flags & EXTENDED )

        {

            while( iend != icur && ( REGEX_CHAR(CharT,'#') == *icur || detail::regex_isspace( *icur ) ) )

            {

                if( REGEX_CHAR(CharT,'#') == *icur++ )

                {

                    while( iend != icur && REGEX_CHAR(CharT,'/n') != *icur++ ) {}

                }

                else

                {

                    for( ; iend != icur && detail::regex_isspace( *icur ); ++icur ) {}

                }

            }

        }

        return icur;

    }

 

    bool min_quant( iterator & icur, const_iterator iend )

    {

        return ( iend != eat_whitespace( ++icur, iend ) && REGEX_CHAR(CharT,'?') == *icur ? ( ++icur, true ) : false );

    }

 

public:

 

    perl_syntax( REGEX_FLAGS flags )

        : m_flags( flags )

    {

    }

 

    perl_syntax( perl_syntax<CharT> const & sy )

        : m_flags( sy.m_flags )

    {

    }

 

    void set_flags( REGEX_FLAGS flags )

    {

        m_flags = flags;

    }

 

    REGEX_FLAGS get_flags() const

    {

        return m_flags;

    }

 

    TOKEN reg_token( iterator & icur, const_iterator iend )

    {

        REGEX_ASSERT( iend != icur );

        if( iend == eat_whitespace( icur, iend ) )

            return NO_TOKEN;

        TOKEN tok = look_up( *icur, s_rgreg );

        if( tok )

            ++icur;

        if( ESCAPE == tok && iend != icur )

        {

            tok = look_up( *icur, s_rgescape );

            if( tok )

                ++icur;

            else

                tok = ESCAPE;

        }

        return tok;

    }

    TOKEN quant_token( iterator & icur, const_iterator iend )

    {

        REGEX_ASSERT( iend != icur );

        if( iend == eat_whitespace( icur, iend ) )

            return NO_TOKEN;

        TOKEN tok = NO_TOKEN;

        switch( *icur )

        {

        case REGEX_CHAR(CharT,'*'):

            tok = min_quant( icur, iend ) ? ZERO_OR_MORE_MIN : ZERO_OR_MORE;

            break;

        case REGEX_CHAR(CharT,'+'):

            tok = min_quant( icur, iend ) ? ONE_OR_MORE_MIN : ONE_OR_MORE;

            break;

        case REGEX_CHAR(CharT,'?'):

            tok = min_quant( icur, iend ) ? ZERO_OR_ONE_MIN : ZERO_OR_ONE;

            break;

        case REGEX_CHAR(CharT,'}'):

            tok = min_quant( icur, iend ) ? END_RANGE_MIN : END_RANGE;

            break;

        case REGEX_CHAR(CharT,'{'):

            tok = BEGIN_RANGE;

            ++icur;

            break;

        case REGEX_CHAR(CharT,','):

            tok = RANGE_SEPARATOR;

            ++icur;

            break;

        }

        return tok;

    }

    TOKEN charset_token( iterator & icur, const_iterator iend )

    {

        REGEX_ASSERT( iend != icur );

        TOKEN tok = NO_TOKEN;

        switch( *icur )

        {

        case REGEX_CHAR(CharT,'-'):

            tok = CHARSET_RANGE;

            ++icur;

            break;

        case REGEX_CHAR(CharT,'^'):

            tok = CHARSET_NEGATE;

            ++icur;

            break;

        case REGEX_CHAR(CharT,']'):

            tok = CHARSET_END;

            ++icur;

            break;

        case REGEX_CHAR(CharT,'//'):

            tok = CHARSET_ESCAPE;

            if( iend == ++icur )

                break;

            switch( *icur )

            {

            case REGEX_CHAR(CharT,'b'):

                tok = CHARSET_BACKSPACE;

                ++icur;

                break;

            case REGEX_CHAR(CharT,'d'):

                tok = ESC_DIGIT;

                ++icur;

                break;

            case REGEX_CHAR(CharT,'D'):

                tok = ESC_NOT_DIGIT;

                ++icur;

                break;

            case REGEX_CHAR(CharT,'s'):

                tok = ESC_SPACE;

                ++icur;

                break;

            case REGEX_CHAR(CharT,'S'):

                tok = ESC_NOT_SPACE;

                ++icur;

                break;

            case REGEX_CHAR(CharT,'w'):

                tok = ESC_WORD;

                ++icur;

                break;

            case REGEX_CHAR(CharT,'W'):

                tok = ESC_NOT_WORD;

                ++icur;

                break;

            }

            break;

        case REGEX_CHAR(CharT,'['):

            if( REGEX_CHAR(CharT,':') == *( ++icur )-- )

            {

                for( size_t i=0; !tok && i < detail::g_cposix_charsets; ++i )

                {

                    if( detail::is_posix_charset<const_iterator>( icur, iend, detail::g_rgposix_charsets[i].m_szcharset ) )

                    {

                        tok = TOKEN( CHARSET_ALNUM + i );

                        std::advance( icur, detail::g_rgposix_charsets[i].cchars );

                    }

                }

            }

            break;

        }

        return tok;

    }

    TOKEN subst_token( iterator & icur, const_iterator iend )

    {

        REGEX_ASSERT( iend != icur );

        TOKEN tok = NO_TOKEN;

        switch( *icur )

        {

        case REGEX_CHAR(CharT,'//'):

            tok = SUBST_ESCAPE;

            if( iend != ++icur )

                switch( *icur )

                {

                case REGEX_CHAR(CharT,'Q'):

                    tok = SUBST_QUOTE_META_ON;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'U'):

                    tok = SUBST_UPPER_ON;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'u'):

                    tok = SUBST_UPPER_NEXT;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'L'):

                    tok = SUBST_LOWER_ON;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'l'):

                    tok = SUBST_LOWER_NEXT;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'E'):

                    tok = SUBST_ALL_OFF;

                    ++icur;

                    break;

                }

            break;

        case REGEX_CHAR(CharT,'$'):

            tok = SUBST_BACKREF;

            if( iend != ++icur )

                switch( *icur )

                {

                case REGEX_CHAR(CharT,'&'):

                    tok = SUBST_MATCH;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'`'):

                    tok = SUBST_PREMATCH;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'/''):

                    tok = SUBST_POSTMATCH;

                    ++icur;

                    break;

                }

            break;

        }

        return tok;

    }

    TOKEN ext_token( iterator & icur, const_iterator iend )

    {

        REGEX_ASSERT( iend != icur );

        if( iend == eat_whitespace( icur, iend ) )

            return NO_TOKEN;

        bool finclude;

        TOKEN tok = NO_TOKEN;

        if( REGEX_CHAR(CharT,'?') == *icur )

        {

            tok = EXT_UNKNOWN;

            ++icur;

            if( m_flags & EXTENDED )

                for( ; iend != icur && detail::regex_isspace( *icur ); ++icur ) {}

            if( iend != icur )

            {

                switch( *icur )

                {

                case REGEX_CHAR(CharT,':'):

                    tok = EXT_NOBACKREF;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'='):

                    tok = EXT_POS_LOOKAHEAD;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'!'):

                    tok = EXT_NEG_LOOKAHEAD;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'#'):

                    tok = EXT_COMMENT;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'('):

                    tok = EXT_CONDITION;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'R'):

                    tok = EXT_RECURSE;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'<'):

                    if( iend == eat_whitespace( ++icur, iend ) )

                        break;

                    switch( *icur )

                    {

                    case REGEX_CHAR(CharT,'='):

                        tok = EXT_POS_LOOKBEHIND;

                        ++icur;

                        break;

                    case REGEX_CHAR(CharT,'!'):

                        tok = EXT_NEG_LOOKBEHIND;

                        ++icur;

                        break;

                    }

                    break;

                case REGEX_CHAR(CharT,'>'):

                    tok = EXT_INDEPENDENT;

                    ++icur;

                    break;

                default:

                    finclude = true;

                    do

                    {

                        if( REGEX_CHAR(CharT,':') == *icur )

                        {

                            tok = EXT_NOBACKREF;

                            ++icur;

                            break;

                        }

                        if( REGEX_CHAR(CharT,')') == *icur )

                        {

                            tok = EXT_NOBACKREF;

                            break;

                        }

                        if( REGEX_CHAR(CharT,'-') == *icur && finclude )

                            finclude = false;

                        else if( REGEX_CHAR(CharT,'i') == *icur )

                            m_flags = ( REGEX_FLAGS ) ( finclude ? ( m_flags | NOCASE )     : ( m_flags & ~NOCASE ) );

                        else if( REGEX_CHAR(CharT,'m') == *icur )

                            m_flags = ( REGEX_FLAGS ) ( finclude ? ( m_flags | MULTILINE )  : ( m_flags & ~MULTILINE ) );

                        else if( REGEX_CHAR(CharT,'s') == *icur )

                            m_flags = ( REGEX_FLAGS ) ( finclude ? ( m_flags | SINGLELINE ) : ( m_flags & ~SINGLELINE ) );

                        else if( REGEX_CHAR(CharT,'x') == *icur )

                            m_flags = ( REGEX_FLAGS ) ( finclude ? ( m_flags | EXTENDED )   : ( m_flags & ~EXTENDED ) );

                        else

                            break;

                    } while( iend != eat_whitespace( ++icur, iend ) );

                    break;

                }

            }

        }

        return tok;

    }

 

    // Functions used for making user-defined intrinsic character sets

    static detail::charset_map<CharT> & get_charset_map()

    {

        return detail::get_perl_charset_map( CharT() );

    }

    static bool invalid_charset( CharT ch )

    {

        return _invalid_charset( ch );

    }

    static void register_intrinsic_charset( CharT ch, std::basic_string<CharT> const & str ) //throw( bad_regexpr, std::bad_alloc )

    {

        perl_syntax sy( NOFLAGS );

        if( invalid_charset( ch ) )

            throw bad_regexpr( "invalid character specified to register_intrinsic_charset" );

        std::basic_string<CharT> pat = str;

        typename std::basic_string<CharT>::iterator ibegin = pat.begin();

        if( BEGIN_CHARSET != sy.reg_token( ibegin, pat.end() ) )

            throw bad_regexpr( "expecting beginning of charset" );

        regex::detail::charset_map<CharT> & charset_map = get_charset_map();

        regex::detail::charset_map_node<CharT> & map_node = charset_map[ ch ];

        map_node.set( std::basic_string<CharT>( ibegin, pat.end() ) );

    }

 private:

    static bool _invalid_charset( char ch )

    {

        using namespace std;

        return NO_TOKEN != s_rgescape[ static_cast<unsigned char>( ch ) ]

            || isdigit( ch ) || 'e' == ch || 'x' == ch || 'c' == ch;

    }

    static bool _invalid_charset( wchar_t ch )

    {

        return UCHAR_MAX >= ch && _invalid_charset( static_cast<char>( ch ) );

    }

};

 

// --------------------------------------------------------------------------

//

// Class:       posix_syntax

//

// Description: Implements the basic POSIX regular expression syntax

//

// Methods:     posix_syntax               -

//              posix_syntax               -

//              get_flags                  -

//              set_flags                  -

//              reg_token                  -

//              quant_token                -

//              charset_token              -

//              subst_token                -

//              ext_token                  -

//              get_charset_map            -

//              invalid_charset            -

//              register_intrinsic_charset -

//

// Members:     m_flags                    -

//              s_charset_map              -

//

// Typedefs:    iterator                   -

//              const_iterator             -

//              char_type                  -

//

// History:     11/16/2001 - ericne - Created

//

// --------------------------------------------------------------------------

template< typename CharT >

class posix_syntax

{

    REGEX_FLAGS m_flags;

 

public:

    typedef typename std::basic_string<CharT>::iterator iterator;

    typedef typename std::basic_string<CharT>::const_iterator const_iterator;

    typedef CharT char_type;

    template< typename OtherT > struct rebind { typedef posix_syntax<OtherT> other; };

 

    posix_syntax( REGEX_FLAGS flags )

        : m_flags( flags )

    {

    }

 

    posix_syntax( posix_syntax<CharT> const & sy )

        : m_flags( sy.m_flags )

    {

    }

 

    REGEX_FLAGS get_flags() const

    {

        return m_flags;

    }

 

    void set_flags( REGEX_FLAGS flags )

    {

        m_flags = flags;

    }

 

    TOKEN reg_token( iterator & icur, const_iterator iend )

    {

        TOKEN tok = NO_TOKEN;

        switch( *icur )

        {

        case REGEX_CHAR(CharT,'.'):

            tok = MATCH_ANY;

            ++icur;

            break;

        case REGEX_CHAR(CharT,'^'):

            tok = BEGIN_LINE;

            ++icur;

            break;

        case REGEX_CHAR(CharT,'$'):

            tok = END_LINE;

            ++icur;

            break;

        case REGEX_CHAR(CharT,'['):

            tok = BEGIN_CHARSET;

            ++icur;

            break;

        case REGEX_CHAR(CharT,'//'):

            tok = ESCAPE;

            ++icur;

            if( iend != icur )

            {

                switch( *icur )

                {

                case REGEX_CHAR(CharT,'('):

                    tok = BEGIN_GROUP;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,')'):

                    tok = END_GROUP;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'|'):

                    tok = ALTERNATION;

                    ++icur;

                    break;

                }

            }

            break;

        }

        return tok;

    }

    TOKEN quant_token( iterator & icur, const_iterator iend )

    {

        TOKEN tok = NO_TOKEN;

        switch( *icur )

        {

        case REGEX_CHAR(CharT,'*'):

            tok = ZERO_OR_MORE;

            ++icur;

            break;

        case REGEX_CHAR(CharT,','):

            tok = RANGE_SEPARATOR;

            ++icur;

            break;

        case REGEX_CHAR(CharT,'//'):

            ++icur;

            if( iend != icur )

            {

                switch( *icur )

                {

                case REGEX_CHAR(CharT,'?'):

                    tok = ZERO_OR_ONE;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'+'):

                    tok = ONE_OR_MORE;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'{'):

                    tok = BEGIN_RANGE;

                    ++icur;

                    break;

                case REGEX_CHAR(CharT,'}'):

                    tok = END_RANGE;

                    ++icur;

                    break;

                default:

                    --icur;

                    break;

                }

            }

            else

            {

                --icur;

            }

        }

        return tok;

    }

    TOKEN charset_token( iterator & icur, const_iterator iend )

    {

        TOKEN tok = NO_TOKEN;

        switch( *icur )

        {

        case REGEX_CHAR(CharT,'^'):

            tok = CHARSET_NEGATE;

            ++icur;

            break;

        case REGEX_CHAR(CharT,'-'):

            tok = CHARSET_RANGE;

            ++icur;

            break;

        case REGEX_CHAR(CharT,']'):

            tok = CHARSET_END;

            ++icur;

            break;

        case REGEX_CHAR(CharT,'['):

            if( REGEX_CHAR(CharT,':') == *( ++icur )-- )

            {

                for( size_t i=0; !tok && i < detail::g_cposix_charsets; ++i )

                {

                    if( detail::is_posix_charset<const_iterator>( icur, iend, detail::g_rgposix_charsets[i].m_szcharset ) )

                    {

                        tok = TOKEN( CHARSET_ALNUM + i );

                        std::advance( icur, detail::g_rgposix_charsets[i].cchars );

                    }

                }

            }

            break;

        }

        return tok;

    }

    TOKEN subst_token( iterator & icur, const_iterator iend )

    {

        TOKEN tok = NO_TOKEN;

        if( REGEX_CHAR(CharT,'//') == *icur )

        {

            tok = SUBST_ESCAPE;

            ++icur;

            if( iend != icur && REGEX_CHAR(CharT,'0') <= *icur && REGEX_CHAR(CharT,'9') >= *icur )

            {

                tok = SUBST_BACKREF;

            }

        }

        return tok;

    }

    TOKEN ext_token( iterator &, const_iterator )

    {

        return NO_TOKEN;

    }

 

    // Functions for making user-defined intrinsic character sets

    static detail::charset_map<CharT> & get_charset_map()

    {

        return detail::get_posix_charset_map( CharT() );

    }

    static bool invalid_charset( CharT ch )

    {

        return _invalid_charset( ch );

    }

    static void register_intrinsic_charset( CharT ch, std::basic_string<CharT> const & str ) //throw( bad_regexpr, std::bad_alloc )

    {

        posix_syntax sy( NOFLAGS );

        if( invalid_charset( ch ) )

            throw bad_regexpr( "invalid character specified to register_intrinsic_charset" );

        std::basic_string<CharT> pat = str;

        typename std::basic_string<CharT>::iterator ibegin = pat.begin();

        if( BEGIN_CHARSET != sy.reg_token( ibegin, pat.end() ) )

            throw bad_regexpr( "expecting beginning of charset" );

        regex::detail::charset_map<CharT> & charset_map = get_charset_map();

        regex::detail::charset_map_node<CharT> & map_node = charset_map[ ch ];

        map_node.set( std::basic_string<CharT>( ibegin, pat.end() ) );

    }

 private:

    static bool _invalid_charset( char ch )

    {

        static char const s_invalid[] = "0123456789()|?+{}//exc";

        return 0 != std::char_traits<CharT>::find( s_invalid, ARRAYSIZE( s_invalid ) - 1, ch );

    }

    static bool _invalid_charset( wchar_t ch )

    {

        return UCHAR_MAX >= ch && _invalid_charset( static_cast<char>( ch ) );

    }

};

 

} // namespace regex

 

#ifdef _MSC_VER

#pragma warning( pop )

#endif

 

#endif

 

//+---------------------------------------------------------------------------

//

//  Copyright ( C ) Microsoft, 1994 - 2002.

//

//  File:       reimpl2.h

//

//  Functions:  helpers for matching and substituting regular expressions

//

//  Notes:      implementation details that really belong in a cpp file,

//              but can't because of template weirdness

//

//  Author:     Eric Niebler ( [email protected] )

//

//  History:    8/15/2001   ericne   Created

//

//----------------------------------------------------------------------------

 

#ifndef REIMPL_H

#define REIMPL_H

 

//

// Helper functions for match and substitute

//

 

namespace detail

{

 

// For use while doing uppercase/lowercase conversions:

inline  char   regex_toupper(  char   ch ) { using namespace std; return (  char   )toupper( ch ); }

inline  char   regex_tolower(  char   ch ) { using namespace std; return (  char   )tolower( ch ); }

inline wchar_t regex_toupper( wchar_t ch ) { using namespace std; return ( wchar_t )towupper( ch ); }

inline wchar_t regex_tolower( wchar_t ch ) { using namespace std; return ( wchar_t )towlower( ch ); }

 

template< typename IBeginT, typename IEndT >

inline void regex_toupper( IBeginT ibegin, IEndT iend )

{

    typedef typename std::iterator_traits<IEndT>::value_type char_type;

    typedef std::char_traits<char_type> traits_type;

 

    for( ; iend != ibegin; ++ibegin )

        traits_type::assign( *ibegin, regex_toupper( *ibegin ) );

}

 

template< typename IBeginT, typename IEndT >

inline void regex_tolower( IBeginT ibegin, IEndT iend )

{

    typedef typename std::iterator_traits<IEndT>::value_type char_type;

    typedef std::char_traits<char_type> traits_type;

 

    for( ; iend != ibegin; ++ibegin )

        traits_type::assign( *ibegin, regex_tolower( *ibegin ) );

}

 

//

// Helper fn for swapping two auto_ptr's

//

template< typename T >

inline void swap_auto_ptr( std::auto_ptr<T> & left, std::auto_ptr<T> & right )

{

    std::auto_ptr<T> temp( left );

    left  = right;

    right = temp;

}

 

template< typename T >

inline void reset_auto_ptr( std::auto_ptr<T> & left )

{

    std::auto_ptr<T> temp( 0 );

    left = temp;

}

 

template< typename T, typename U >

inline void reset_auto_ptr( std::auto_ptr<T> & left, U * right )

{

    std::auto_ptr<T> temp( right );

    left = temp;

}

 

typedef int instantiator;

 

inline instantiator REGEX_CDECL instantiator_helper( ... )

{

    return instantiator();

}

 

// --------------------------------------------------------------------------

//

// Class:       match_param

//

// Description: Struct that contains the state of the matching operation.

//              Passed by reference to all recursive_match_all and recursive_match_this routines.

//

// Methods:     match_param - ctor

//

// Members:     ibufferbegin - start of the buffer

//              ibegin       - start of this iteration

//              iend        - end of the string

//              prgbackrefs  - pointer to backref array

//

// History:     8/14/2000 - ericne - Created

//

// --------------------------------------------------------------------------

template< typename IterT >

struct match_param

{

    typedef backref_tag<IterT>              backref_type;

    typedef sub_expr_base<IterT> const *    sub_expr_ptr;

 

    // for performance reasons, the most frequently used fields 

    // are placed at offsets which are a power of 2 (assuming

    // a 32-bit architecture, and iterators which are 32 bits).

 

    backref_type *      m_prgbackrefs;      // offsetof == 0

    IterT               m_iend;             // offsetof == 4

    IterT               m_icur;             // offsetof == 8

    size_t              m_cbackrefs;

    sub_expr_ptr        m_pnext;            // offsetof == 16

    IterT               m_ibufferbegin;

    IterT               m_imatchbegin;

    sub_expr_ptr        m_pfirst;

    unsafe_stack *      m_pstack;           // offsetof == 32

    bool                m_no0len;

    bool                m_reserved;

 

    match_param

    (

        IterT           ibufferbegin,

        IterT           imatchbegin,

        IterT           iend,

        backref_type *  prgbackrefs,

        size_t          cbackrefs

    )

        : m_prgbackrefs( prgbackrefs )

        , m_iend( iend )

        , m_icur( imatchbegin )

        , m_cbackrefs( cbackrefs )

        , m_pnext( 0 )

        , m_ibufferbegin( ibufferbegin )

        , m_imatchbegin( imatchbegin )

        , m_pfirst( 0 )

        , m_pstack( 0 )

        , m_no0len( false )

        , m_reserved( false )

    {

    }

};

 

// --------------------------------------------------------------------------

//

// Class:       arena_allocator

//

// Description: A small, fast allocator for speeding up pattern compilation.

//              Every basic_rpattern object has an arena as a member.

//              sub_expr objects can only be allocated from this arena.

//              Memory is alloc'ed in chunks using the underlying allocator.

//              Chunks are freed en-masse when clear() or finalize() is called.

//

// History:     8/17/2001 - ericne - Created

//

// Notes:       This is NOT a std-compliant allocator and CANNOT be used with

//              STL containers. arena_allocator objects maintain state, and

//              STL containers are allowed to assume their allocators do

//              not maintain state. In regexpr2.cpp, I define slist<>, a simple

//              arena-friendly singly-linked list for use with the arena

//              allocator.

//

// --------------------------------------------------------------------------

template< typename AllocT = std::allocator<char> >

struct pool_impl

{

    typedef typename rebind<AllocT, char>::type char_allocator_type;

 

    struct mem_block

    {

        size_t  m_offset;

        size_t  m_blocksize;

        mem_block * m_pnext;

        unsigned char m_data[ 1 ];

    };

#if !defined(_MSC_VER) | 1200 < _MSC_VER

    struct pool_data : char_allocator_type

    {

        pool_data( size_t default_size, char_allocator_type const & alloc )

            : char_allocator_type( alloc )

            , m_pfirst( 0 )

            , m_default_size( default_size )

        {

        }

        mem_block * m_pfirst;

        size_t      m_default_size;

        char_allocator_type & get_allocator()

        {

            return *this;

        }

    } m_data;

#else

    struct pool_data

    {

        pool_data( size_t default_size, char_allocator_type const & alloc )

            : m_alloc( alloc )

            , m_pfirst( 0 )

            , m_default_size( default_size )

        {

        }

        char_allocator_type m_alloc;

        mem_block * m_pfirst;

        size_t      m_default_size;

        char_allocator_type & get_allocator()

        {

            return m_alloc;

        }

    } m_data;

#endif

    void new_block( size_t size );

    void clear();

    void * allocate( size_t size );

    explicit pool_impl( size_t default_size, char_allocator_type const & alloc = char_allocator_type() );

    ~pool_impl();

    char_allocator_type get_allocator() const

    {

        return const_cast<pool_impl*>(this)->m_data.get_allocator();

    }

};

 

template< typename T, typename AllocT = std::allocator<char> >

class arena_allocator

{

public:

    typedef size_t size_type;

    typedef ptrdiff_t difference_type;

    typedef T *pointer;

    typedef T const *const_pointer;

    typedef T & reference;

    typedef T const & const_reference;

    typedef T value_type;

 

    typedef typename rebind<AllocT, char>::type char_alloc_type;

    typedef pool_impl<AllocT> pool_impl_t;

    typedef typename rebind<AllocT, pool_impl_t>::type pool_alloc_type;

 

    explicit arena_allocator( size_t default_size, char_alloc_type const & alloc = char_alloc_type() )

        : m_pool( 0 )

    {

        char_alloc_type char_alloc( alloc );

        pool_alloc_type pool_alloc( convert_allocator<pool_impl_t>( char_alloc, 0 ) );

        m_pool = pool_alloc.allocate( 1, 0 );

        pool_alloc.construct( m_pool, pool_impl_t( default_size, char_alloc ) ); // can't throw

    }

#if !defined(_MSC_VER) | 1200 < _MSC_VER

    arena_allocator( arena_allocator const & that )

        : m_pool( that.m_pool )

    {

    }

#endif

    template< typename U >

    arena_allocator( arena_allocator<U> const & that )

        : m_pool( that.m_pool )

    {

    }

    ~arena_allocator()

    { // Many arena_allocators may point to m_pool, so don't delete it.

    } // Rather, wait for someone to call finalize().

    pointer allocate( size_type size, void const * =0 )

    {

        return static_cast<T*>( m_pool->allocate( size * sizeof(T) ) );

    }

    void deallocate( void *, size_type )

    { // no-op. deallocation happens when pool is finalized or cleared.

    }

    void construct( pointer p, T const & t )

    {

        new( static_cast<void*>(p) ) T( t );

    }

    void destroy( pointer p )

    {

        regex::detail::destroy( p );

    }

#if !defined(_MSC_VER) | 1200 < _MSC_VER

    template< typename U > struct rebind

    {

        typedef arena_allocator<U> other;

    };

#endif

    void clear()

    {

        m_pool->clear();

    }

    void finalize()

    {

        char_alloc_type char_alloc( m_pool->get_allocator() );

        pool_alloc_type pool_alloc( convert_allocator<pool_impl_t>( char_alloc, 0 ) );

        pool_alloc.destroy( m_pool );

        pool_alloc.deallocate( m_pool, 1 );

        m_pool = 0;

    }

    void swap( arena_allocator & that )

    {

        using std::swap;

        swap( m_pool, that.m_pool );

    }

 

    // the pool lives here

    pool_impl_t * m_pool;

};

 

// Dummy struct used by the pool allocator to align returned pointers

struct not_pod

{

    virtual ~not_pod() {}

};

 

template< typename AllocT >

inline pool_impl<AllocT>::pool_impl( size_t default_size, char_allocator_type const & alloc )

    : m_data( default_size, alloc )

{

}

 

template< typename AllocT >

inline pool_impl<AllocT>::~pool_impl()

{

    clear();

}

 

template< typename AllocT >

inline void pool_impl<AllocT>::clear()

{

    for( mem_block * pnext; m_data.m_pfirst; m_data.m_pfirst = pnext )

    {

        pnext = m_data.m_pfirst->m_pnext;

        m_data.get_allocator().deallocate( reinterpret_cast<char*>( m_data.m_pfirst ), m_data.m_pfirst->m_blocksize );

    }

}

 

template< typename AllocT >

inline void pool_impl<AllocT>::new_block( size_t size )

{

    size_t blocksize = regex_max( m_data.m_default_size, size ) + offsetof( mem_block, m_data );

    mem_block * pnew = reinterpret_cast<mem_block*>( m_data.get_allocator().allocate( blocksize, 0 ) );

    if( 0 == pnew )

    {

        throw std::bad_alloc();

    }

    pnew->m_offset      = 0;

    pnew->m_blocksize   = blocksize;

    pnew->m_pnext       = m_data.m_pfirst;

    m_data.m_pfirst     = pnew;

}

 

template< typename AllocT >

inline void * pool_impl<AllocT>::allocate( size_t size )

{

    if( 0 == size )

        size = 1;

 

    if( 0 == m_data.m_pfirst || m_data.m_pfirst->m_offset + size > m_data.m_default_size )

        new_block( size );

 

    void * pnew = m_data.m_pfirst->m_data + m_data.m_pfirst->m_offset;

 

    // ensure returned pointers are always suitably aligned

    m_data.m_pfirst->m_offset += ( ( size + alignof<not_pod>::value - 1 )

                                 & ~( alignof<not_pod>::value - 1 ) );

 

    return pnew;

}

 

// The regex_arena is a basic, vanilla arena_allocator.

typedef arena_allocator<char> regex_arena;

 

template< typename T >

type_with_size<3> allocator_picker( arena_allocator<T> const &, int );

 

template<> struct rebind_helper<3>

{

template< typename, typename ElemT>

struct inner

{

typedef arena_allocator<ElemT> type;

};

};

 

// --------------------------------------------------------------------------

//

// Class:       sub_expr_base

//

// Description: patterns are "compiled" into a directed graph of sub_expr_base

//              structs.  Matching is accomplished by traversing this graph.

//

// Methods:     ~sub_expr_base - virt dtor so cleanup happens correctly

//              recursive_match_all      - match this sub-expression and all following

//                               sub-expression

//

// History:     8/14/2000 - ericne - Created

//

// --------------------------------------------------------------------------

template< typename IterT >

struct sub_expr_base

{

    virtual bool recursive_match_all_s( match_param<IterT> &, IterT ) const = 0; //throw() (offset 0)

    virtual bool recursive_match_all_c( match_param<IterT> &, IterT ) const = 0; //throw() (offset 4)

    virtual bool iterative_match_this_s( match_param<IterT> & ) const = 0; //throw()       (offset 8)

    virtual bool iterative_match_this_c( match_param<IterT> & ) const = 0; //throw()       (offset 12)

    virtual bool iterative_rematch_this_s( match_param<IterT> & ) const = 0; //throw()     (offset 16)

    virtual bool iterative_rematch_this_c( match_param<IterT> & ) const = 0; //throw()     (offset 20)

 

    virtual ~sub_expr_base() = 0;                                                       // (offset 24)

 

    // Use the regex_arena for memory management

    static void * operator new( size_t size, regex_arena & arena )

    {

        return arena.allocate( size );

    }

    static void operator delete( void *, regex_arena & )

    {

    }

 

    // Invoke the d'tor, but don't bother freeing memory. That will

    // happen automatically when the arena object gets destroyed.

    static void operator delete( void * )

    {

    }

 

    // For choosing an appropriate virtual function based on a compile time constant

    bool recursive_match_all( match_param<IterT> & param, IterT icur, false_t ) const //throw()

    {

        return recursive_match_all_s( param, icur );

    }

    bool recursive_match_all( match_param<IterT> & param, IterT icur, true_t ) const //throw()

    {

        return recursive_match_all_c( param, icur );

    }

    bool iterative_match_this( match_param<IterT> & param, false_t ) const //throw()

    {

        return iterative_match_this_s( param );

    }

    bool iterative_match_this( match_param<IterT> & param, true_t ) const //throw()

    {

        return iterative_match_this_c( param );

    }

    bool iterative_rematch_this( match_param<IterT> & param, false_t ) const //throw()

    {

        return iterative_rematch_this_s( param );

    }

    bool iterative_rematch_this( match_param<IterT> & param, true_t ) const //throw()

    {

        return iterative_rematch_this_c( param );

    }

private:

    // don't allocate sub-expressions directly on the heap; they should

    // be allocated from an arena

    static void * operator new( size_t size ) throw( std::bad_alloc );

    // disable all the vector new's and delete's.

    static void * operator new[]( size_t size, regex_arena & arena ) throw( std::bad_alloc );

    static void operator delete[]( void *, regex_arena & );

    static void * operator new[]( size_t size ) throw( std::bad_alloc );

    static void operator delete[]( void * );

};

 

template< typename IterT >

inline sub_expr_base<IterT>::~sub_expr_base()

{

}

 

// --------------------------------------------------------------------------

//

// Class:       subst_node

//

// Description: Substitution strings are parsed into an array of these

//              structures in order to speed up subst operations.

//

// Members:     stype         - type of this struct

//              .m_subst_string  - do a string substitution

//             .m_subst_backref - do a bacref substitution

//              op            - execute an operation

//

// History:     8/14/2000 - ericne - Created

//

// --------------------------------------------------------------------------

struct subst_node

{

    enum

    {

        PREMATCH  = -1,

        POSTMATCH = -2

    };

 

    enum subst_type

    {

        SUBST_STRING,

        SUBST_BACKREF,

        SUBST_OP

    };

 

    enum op_type

    {

        UPPER_ON   = SUBST_UPPER_ON,

        UPPER_NEXT = SUBST_UPPER_NEXT,

        LOWER_ON   = SUBST_LOWER_ON,

        LOWER_NEXT = SUBST_LOWER_NEXT,

        ALL_OFF    = SUBST_ALL_OFF

    };

 

    struct string_offsets

    {

        ptrdiff_t       m_rstart;

        ptrdiff_t       m_rlength;

    };

 

    subst_type          m_stype;

 

    union

    {

        string_offsets  m_subst_string;

        size_t          m_subst_backref;

        op_type         m_op;

    };

};

 

typedef std::list<subst_node> subst_list_type;

size_t DEFAULT_BLOCK_SIZE();

 

template< typename IterT >

class boyer_moore;

 

// --------------------------------------------------------------------------

//

// Class:       basic_rpattern_base_impl

//

// Description:

//

// Methods:     basic_rpattern_base_impl - ctor

//              flags                   - get the state of the flags

//              uses_backrefs           - true if the backrefs are referenced

//              get_first_subexpression - return ptr to first sub_expr struct

//              get_width               - get min/max nbr chars this pattern can match

//              loops                   - if false, we only need to try to match at 1st position

//              cgroups                 - number of visible groups

//              _cgroups_total          - total number of groups, including hidden ( ?: ) groups

//              get_pat                 - get string representing the pattern

//              get_subst               - get string representing the substitution string

//              get_subst_list          - get the list of subst nodes

//              _normalize_string       - perform character escaping

//

// Members:     m_fuses_backrefs        - true if subst string refers to backrefs

//              m_floop                 - false if pat only needs to be matched in one place

//              m_cgroups               - total count of groups

//              m_cgroups_visible       - count of visible groups

//              m_flags                 - the flags

//              m_nwidth                - width of this pattern

//              m_pat                   - pattern string

//              m_subst                 - substitution string

//              m_subst_list            - list of substitution nodes

//              m_pfirst                - ptr to first subexpression to match

//

// Typedefs:    char_type               -

//              string_type             -

//              size_type               -

//

// History:     8/14/2000 - ericne - Created

//

// --------------------------------------------------------------------------

template< typename IterT >

class basic_rpattern_base_impl

{

    basic_rpattern_base_impl( basic_rpattern_base_impl<IterT> const & );

    basic_rpattern_base_impl & operator=( basic_rpattern_base_impl<IterT> const & );

protected:

    typedef typename std::iterator_traits<IterT>::value_type char_type;

    typedef std::char_traits<char_type>                   traits_type;

 

    typedef std::basic_string<char_type>                  string_type;

    typedef size_t                                        size_type;

 

    typedef backref_tag<IterT>                             backref_type;

    typedef std::vector<backref_type>                     backref_vector;

 

    friend struct regex_access<IterT>;

 

    explicit basic_rpattern_base_impl

    (

        REGEX_FLAGS         flags = NOFLAGS,

        REGEX_MODE          mode  = MODE_DEFAULT,

        string_type const & pat   = string_type(),

        string_type const & subst = string_type()

    )                                               //throw()

        : m_arena( DEFAULT_BLOCK_SIZE() )

        , m_fuses_backrefs( false )

        , m_floop( true )

        , m_fok_to_recurse( true )

        , m_cgroups( 0 )

        , m_cgroups_visible( 0 )

        , m_flags( flags )

        , m_mode( mode )

        , m_nwidth( uninit_width() )

        , m_pat( new string_type( pat ) )

        , m_subst( new string_type( subst ) )

        , m_subst_list()

        , m_pfirst( 0 )

        , m_invisible_groups()

        , m_search( 0 )

    {

    }

 

    virtual ~basic_rpattern_base_impl()

    {

        // We're not going to be calling destructors because all allocated

        // memory associated with the parsed pattern resides in the arena.

        // The memory will be freed when the arena gets destroyed.

        //delete m_pfirst;

        reset_auto_ptr( m_pat );

        reset_auto_ptr( m_subst );

        m_arena.finalize();

    }

 

    regex_arena m_arena;           // The sub_expr arena

 

    bool        m_fuses_backrefs;  // true if the substitution uses backrefs

    bool        m_floop;           // false if m_pfirst->recursive_match_all only needs to be called once

    bool        m_fok_to_recurse;  // false if the pattern would recurse too deeply

    size_t      m_cgroups;         // number of groups ( always at least one )

    size_t      m_cgroups_visible; // number of visible groups

    REGEX_FLAGS m_flags;           // flags used to customize search/replace

    REGEX_MODE  m_mode;            // Used to pick the fast or safe algorithm

    width_type  m_nwidth;          // width of the pattern

 

    std::auto_ptr<string_type>   m_pat;   // contains the unparsed pattern

    std::auto_ptr<string_type>   m_subst; // contains the unparsed substitution

 

    subst_list_type              m_subst_list; // used to speed up substitution

    sub_expr_base<IterT> const * m_pfirst;     // first subexpression in pattern

 

    std::list<size_t>           m_invisible_groups; // groups w/o backrefs

 

    boyer_moore<typename string_type::const_iterator>  * m_search;

 

    size_t _cgroups_total() const //throw()

    {

        return m_cgroups;

    }

 

    bool _loops() const //throw()

    {

        return m_floop;

    }

 

    size_t _get_next_group_nbr()

    {

        return m_cgroups++;

    }

 

    void _normalize_string( string_type & str ) const //throw()

    {

        if( NORMALIZE & flags() )

            process_escapes( str, true );

    }

 

    bool _save_backrefs() const //throw()

    {

        return m_fuses_backrefs || ! ( flags() & NOBACKREFS );

    }

 

    sub_expr_base<IterT> const * _get_first_subexpression() const //throw()

    {

        return m_pfirst;

    }

 

    REGEX_FLAGS flags() const //throw()

    {

        return m_flags;

    }

 

    REGEX_MODE mode() const // throw()

    {

        return m_mode;

    }

 

    width_type get_width() const //throw()

    {

        return m_nwidth;

    }

 

    size_t cgroups() const //throw()

    {

        return m_cgroups_visible;

    }

 

    string_type const & get_pat() const //throw()

    {

        return *m_pat;

    }

 

    string_type const & get_subst() const //throw()

    {

        return *m_subst;

    }

 

    bool _ok_to_recurse() const; //throw();

 

    void swap( basic_rpattern_base_impl<IterT> & that ); // throw();

 

    enum { npos = static_cast<size_type>( -1 ) };

 

    static instantiator instantiate()

    {

        typedef basic_rpattern_base_impl this_type;

 

        return instantiator_helper

        (

            &this_type::_ok_to_recurse,

            &this_type::swap

        );

    }

};

 

template< typename IterT >

struct regex_access

{

    typedef basic_rpattern_base_impl< IterT >    rpattern_type;

    typedef typename rpattern_type::size_type    size_type;

    typedef typename rpattern_type::char_type    char_type;

    typedef typename rpattern_type::traits_type  traits_type;

    typedef typename rpattern_type::backref_type backref_type;

 

    static bool _do_match_iterative_helper_s

    (

        sub_expr_base<IterT> const * expr,

        match_param<IterT> & param,

        IterT icur

    );

 

    static bool _do_match_iterative_helper_c

    (

        sub_expr_base<IterT> const * expr,

        match_param<IterT> & param,

        IterT icur

    );

 

    static bool _do_match_recursive_s

    (

        sub_expr_base<IterT> const * expr,

        match_param<IterT> & param,

        IterT icur

    );

 

    static bool _do_match_recursive_c

    (

        sub_expr_base<IterT> const * expr,

        match_param<IterT> & param,

        IterT icur

    );

 

    static bool _do_match_impl

    (

        rpattern_type const & pat,

        match_param<IterT> & param,

        bool const use_null

    );

 

    static bool _do_match_with_stack

    (

        rpattern_type const & pat,

        match_param<IterT> & param,

        bool const use_null

    );

 

    template< typename Alloc1T, typename Alloc2T >

    static void _fixup_backrefs

    (

        std::vector<backref_type,Alloc1T> & rgbackrefs,

        std::list<size_t,Alloc2T> const & invisible

    )

    {

        typedef typename std::list<size_t,Alloc2T>::const_iterator iter_type;

 

        // Remove information about the "invisible" groups

        if( rgbackrefs[0].matched )

        {

            size_t dropped = 0;

            iter_type const end = invisible.end();

            iter_type curr = invisible.begin(), next = invisible.begin();

 

            for( ; end != curr; curr = next, ++dropped )

            {

                if( end == ++next )

                {

                    std::copy(

                        rgbackrefs.begin() + *curr + 1,

                        rgbackrefs.end(),

                        rgbackrefs.begin() + *curr - dropped );

                }

                else

                {

                    std::copy(

                        rgbackrefs.begin() + *curr + 1,

                        rgbackrefs.begin() + *next,

                        rgbackrefs.begin() + *curr - dropped );

                }

            }

 

            rgbackrefs.resize( rgbackrefs.size() - dropped );

        }

        else

        {

            rgbackrefs.resize( rgbackrefs.size() - invisible.size() );

        }

    }

 

    template< typename AllocT >

    static bool _do_try_match

    (

        rpattern_type const & pat,

        match_param<IterT> & param,

        std::vector<backref_type,AllocT> & rgbackrefs,

        bool const use_null

    )

    {

        bool success;

        rgbackrefs.resize( pat._cgroups_total() );

        param.m_prgbackrefs = & rgbackrefs[0];

        param.m_cbackrefs = rgbackrefs.size();

 

        REGEX_SEH_TRY

        {

            if( pat._ok_to_recurse() )

            {

                success = _do_match_impl( pat, param, use_null );

            }

            else

            {

                success = _do_match_with_stack( pat, param, use_null );

            }

        }

        REGEX_SEH_EXCEPT( REGEX_SEH_STACK_OVERFLOW == _exception_code() )

        {

            // we have overflowed the stack. reset the guard page.

            REGEX_RESET_STK_OFLW();

 

            // This match fails silently.

            for( size_t i=0; i < param.m_cbackrefs; ++i )

            {

                param.m_prgbackrefs[i] = static_init<backref_type>::value;

            }

 

            success = false;

        }

 

        _fixup_backrefs( rgbackrefs, pat.m_invisible_groups );

        return success;

    }

 

    template< typename AllocT >

    static bool _do_match

    (

        rpattern_type const & pat,

        basic_match_results<IterT,AllocT> & results,

        IterT ibegin,

        IterT iend,

        bool use_null

    )

    {

        typedef typename basic_match_results<IterT,AllocT>::backref_vector backref_vector;

 

        results.m_ibegin = ibegin;

        match_param<IterT> param( ibegin, ibegin, iend, 0, 0 );

 

        if( GLOBAL & pat.flags() ) // do a global find

        {

            // The NOBACKREFS flag is ignored in the match method.

            bool const fAll   = ( ALLBACKREFS   == ( ALLBACKREFS   & pat.flags() ) );

            bool const fFirst = ( FIRSTBACKREFS == ( FIRSTBACKREFS & pat.flags() ) );

 

            backref_vector rgtempbackrefs( results.m_rgbackrefs.get_allocator() );

 

            while( _do_try_match( pat, param, results.m_rgbackrefs, use_null ) )

            {

                backref_type const & br = param.m_prgbackrefs[0];

 

                // Handle specially the backref flags

                if( fFirst )

                {

                    rgtempbackrefs.push_back( br );

                }

                else if( fAll )

                {

                    rgtempbackrefs.insert(

                        rgtempbackrefs.end(),

                        results.m_rgbackrefs.begin(),

                        results.m_rgbackrefs.end() );

                }

                else

                {

                    rgtempbackrefs.swap( results.m_rgbackrefs );

                }

 

                param.m_imatchbegin = br.second;

                param.m_no0len = ( br.first == br.second );

            }

 

            // restore the backref vectors

            results.m_rgbackrefs.swap( rgtempbackrefs );

            return ! results.m_rgbackrefs.empty();

        }

        else

        {

            return _do_try_match( pat, param, results.m_rgbackrefs, use_null );

        }

    }

 

    template< typename AllocT >

    static bool _do_match_c

    (

        rpattern_type const & pat,

        basic_match_results<IterT,AllocT> & results,

        char_type const * szbegin

    )

    {

        if( RIGHTMOST & pat.flags() )

        {

            // We need to know the end of the string if we're doing a

            // RIGHTMOST match.

            char_type const * szend = szbegin;

            std::advance( szend, traits_type::length( szbegin ) );

            return _do_match( pat, results, szbegin, szend, false );

        }

        else

        {

            return _do_match( pat, results, szbegin, 0, true );

        }

    }

 

    static size_t _do_count

    (

        rpattern_type const & pat,

        IterT ibegin,

        IterT iend,

        bool use_null

    )

    {

        size_t cmatches = 0;

        std::vector<backref_type> rgbackrefs;

 

        // If your compile breaks here, it is because CharT const * is not

        // convertible to type IterT. Check the declaration of your rpattern object.

        match_param<IterT> param( ibegin, ibegin, iend, 0, 0 );

 

        while( _do_try_match( pat, param, rgbackrefs, use_null ) )

        {

            backref_type const & br = param.m_prgbackrefs[0];

            ++cmatches;

            param.m_imatchbegin = br.second;

 

            param.m_no0len = ( br.first == br.second );

        }

 

        return cmatches;

    }

 

    template< typename CharT, typename TraitsT, typename AllocT >

    static size_t _do_split

    (

        rpattern_type const & pat,

        basic_split_results<CharT, TraitsT, AllocT> & results,

        IterT ibegin,

        IterT iend,

        int limit,

        bool use_null

    )

    {

        typedef typename basic_split_results<CharT, TraitsT, AllocT>::string_type   string_type;

        typedef typename rebind<AllocT, backref_type>::type                         backref_allocator;

 

        std::vector<backref_type,backref_allocator> rgbackrefs( 

            convert_allocator<backref_type>( results.strings().get_allocator(), 0 ) );

 

        typedef typename rebind<AllocT, CharT>::type                                char_allocator_type;

        char_allocator_type char_allocator = 

            convert_allocator<CharT>( results.strings().get_allocator(), 0 );

 

        // reserve some initial space

        results.strings().clear();

        results.strings().reserve( 10 );

 

        match_param<IterT> param( ibegin, ibegin, iend, 0, 0 );

 

        while( 1 != limit && _do_try_match( pat, param, rgbackrefs, use_null ) )

        {

            backref_type const & br = param.m_prgbackrefs[0];

            param.m_no0len = ( br.first == br.second );

 

            // discard zero-width matches at the beginning and end of the buffer

            if( param.m_no0len )

            {

                // if we're at the beginning, skip

                if( br.first == param.m_ibufferbegin )

                    continue;

 

                // if we're at the end, break

                if( use_null ? 0 == *param.m_imatchbegin : param.m_imatchbegin == param.m_iend )

                    break;

            }

 

            string_type tmp( param.m_imatchbegin, br.first, char_allocator );

            results.strings().push_back( tmp );

            param.m_imatchbegin = br.second;

 

            // add any groups

            for( size_t i = 1; i < rgbackrefs.size(); ++i )

            {

                backref_type const & br = rgbackrefs[i];

                string_type tmp( br.first, br.second, char_allocator );

                results.strings().push_back( tmp );

            }

 

            if( limit > 0 )

                --limit;

        }

 

        // append the last string, unless it's empty and limit is 0

        if( use_null )

        {

            if( *param.m_imatchbegin || 0 != limit )

                results.strings().push_back( string_type( &*param.m_imatchbegin, char_allocator ) );

        }

        else

        {

            if( param.m_imatchbegin != param.m_iend || 0 != limit )

                results.strings().push_back( string_type( param.m_imatchbegin, param.m_iend, char_allocator ) );

        }

 

        // remove trailing empty fields

        if( 0 == limit )

        {

            while( results.size() && results.back().empty() )

            {

                results.strings().pop_back();

            }

        }

 

        return results.size();

    }

 

    template< typename CharT, typename TraitsT, typename AllocT >

    static size_t _do_subst_internal

    (

        std::basic_string<CharT, TraitsT, AllocT> & str,

        basic_subst_results<CharT, TraitsT, AllocT> const & results,

        rpattern_type const & pat,

        size_type strpos,

        size_type strlen

    )

    {

        typedef subst_list_type::const_iterator iter_type;

        enum { UPPER = -1, NIL, LOWER } next = NIL, rest = NIL;

        bool first = true;

        size_t old_strpos = strpos;

        typename std::basic_string<CharT, TraitsT, AllocT>::iterator itstrlen = str.begin();

        std::advance( itstrlen, strpos + strlen );

        std::basic_string<char_type> const & subst = pat.get_subst();

 

        for( iter_type isubst = pat.m_subst_list.begin(); pat.m_subst_list.end() != isubst; ++isubst )

        {

            size_t sublen = 0;

            typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator itsubpos1; // iter into str

            typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator itsublen1;

            typename std::basic_string<char_type>::const_iterator              itsubpos2; // iter into subst string

            typename std::basic_string<char_type>::const_iterator              itsublen2;

            typename std::basic_string<CharT, TraitsT, AllocT>::iterator       itstrpos = str.begin();

            std::advance( itstrpos, strpos );

 

            switch( isubst->m_stype )

            {

            case subst_node::SUBST_STRING:

                itsubpos2 = subst.begin();

                std::advance( itsubpos2, isubst->m_subst_string.m_rstart );

                itsublen2 = itsubpos2;

                std::advance( itsublen2, isubst->m_subst_string.m_rlength );

 

                if( first )

                    str.replace( itstrpos, itstrlen, itsubpos2, itsublen2 );

                else

                    str.insert( itstrpos, itsubpos2, itsublen2 );

                sublen = std::distance( itsubpos2, itsublen2 );

                break;

 

            case subst_node::SUBST_BACKREF:

                switch( isubst->m_subst_backref )

                {

                case subst_node::PREMATCH:

                    itsubpos1 = results.backref_str().begin();

                    itsublen1 = itsubpos1;

                    std::advance( itsublen1, sublen = results.rstart() );

                    break;

                case subst_node::POSTMATCH:

                    itsubpos1 = results.backref_str().begin();

                    std::advance( itsubpos1, results.rstart() + results.rlength() );

                    itsublen1 = results.backref_str().end();

                    break;

                default:

                    itsubpos1 = results.backref_str().begin();

                    std::advance( itsubpos1, results.rstart( isubst->m_subst_backref ) );

                    itsublen1 = itsubpos1;

                    std::advance( itsublen1, results.rlength( isubst->m_subst_backref ) );

                    break;

                }

 

                if( first )

                    str.replace( itstrpos, itstrlen, itsubpos1, itsublen1 );

                else

                    str.insert( itstrpos, itsubpos1, itsublen1 );

                sublen = std::distance( itsubpos1, itsublen1 );

                break;

 

            case subst_node::SUBST_OP:

                switch( isubst->m_op )

                {

                case subst_node::UPPER_ON:

                    rest = UPPER;

                    break;

                case subst_node::UPPER_NEXT:

                    next = UPPER;

                    break;

                case subst_node::LOWER_ON:

                    rest = LOWER;

                    break;

                case subst_node::LOWER_NEXT:

                    next = LOWER;

                    break;

                case subst_node::ALL_OFF:

                    rest = NIL;

                    break;

                default:

                    REGEX_ASSERT(false);

                    break;

                }

                continue; // jump to the next item in the list

 

            default:

                REGEX_ASSERT(false);

                break;

            }

 

            first = false;

 

            // Are we upper- or lower-casing this string?

            if( rest )

            {

                typename std::basic_string<CharT, TraitsT, AllocT>::iterator ibegin = str.begin();

                std::advance( ibegin, strpos );

                typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator iend = ibegin;

                std::advance( iend, sublen );

                switch( rest )

                {

                case UPPER:

                    regex_toupper( ibegin, iend );

                    break;

                case LOWER:

                    regex_tolower( ibegin, iend );

                    break;

                default:

                    REGEX_ASSERT(false);

                    break;

                }

            }

 

            // Are we upper- or lower-casing the next character?

            if( next )

            {

                switch( next )

                {

                case UPPER:

                    traits_type::assign( str[strpos], regex_toupper( str[strpos] ) );

                    break;

                case LOWER:

                    traits_type::assign( str[strpos], regex_tolower( str[strpos] ) );

                    break;

                default:

                    REGEX_ASSERT(false);

                    break;

                }

                next = NIL;

            }

 

            strpos += sublen;

        }

 

        // If *first* is still true, then we never called str.replace, and the substitution

        // string is empty. Erase the part of the string that the pattern matched.

        if( first )

            str.erase( strpos, strlen );

 

        // return length of the substitution

        return strpos - old_strpos;

    }

 

    template< typename CharT, typename TraitsT, typename AllocT >

    static size_t _do_subst

    (

        rpattern_type const & pat,

        std::basic_string<CharT, TraitsT, AllocT> & str,

        basic_subst_results<CharT, TraitsT, AllocT> & results,

        size_type pos,

        size_type len

    )

    {

        typedef std::basic_string<CharT, TraitsT, AllocT> string_type;

        typedef typename basic_subst_results<CharT, TraitsT, AllocT>::backref_vector backref_vector;

 

        results.m_pbackref_str = pat._save_backrefs() ? &( results.m_backref_str = str ) : &str;

        results.m_ibegin = results.m_pbackref_str->begin();

 

        size_t csubst = 0;

        size_type stop_offset = results.m_pbackref_str->size();

        if( len != rpattern_type::npos )

            stop_offset = regex_min( size_t( pos + len ), stop_offset );

 

        match_param<IterT> param( results.m_ibegin, results.m_ibegin, results.m_ibegin, 0, 0 );

 

        std::advance( param.m_imatchbegin, pos );

        std::advance( param.m_iend, stop_offset );

        param.m_ibufferbegin = param.m_imatchbegin;

 

        if( GLOBAL & pat.flags() )

        {

            bool const fAll   = ( ALLBACKREFS   == ( ALLBACKREFS   & pat.flags() ) );

            bool const fFirst = ( FIRSTBACKREFS == ( FIRSTBACKREFS & pat.flags() ) );

            backref_vector rgtempbackrefs( results.m_rgbackrefs.get_allocator() ); // temporary vector used if fsave_backrefs

 

            size_type pos_offset = 0; // keep track of how much the backref_str and

                                      // the current string are out of sync

 

            while( _do_try_match( pat, param, results.m_rgbackrefs, false ) )

            {

                backref_type const & br = param.m_prgbackrefs[0];

                ++csubst;

                size_type match_length = std::distance( br.first, br.second );

                pos = std::distance( results.m_ibegin, br.first );

                size_type subst_length = _do_subst_internal( str, results, pat, pos + pos_offset, match_length );

 

                if( pat._save_backrefs() )

                {

                    pos += match_length;

                    pos_offset += ( subst_length - match_length );

 

                    // Handle specially the backref flags

                    if( fFirst )

                    {

                        rgtempbackrefs.push_back( br );

                    }

                    else if( fAll )

                    {

                        rgtempbackrefs.insert(

                            rgtempbackrefs.end(),

                            results.m_rgbackrefs.begin(),

                            results.m_rgbackrefs.end() );

                    }

                    else

                    {

                        rgtempbackrefs.swap( results.m_rgbackrefs );

                    }

                }

                else

                {

                    pos += subst_length;

                    stop_offset += ( subst_length - match_length );

                    results.m_ibegin = results.m_pbackref_str->begin();

 

                    // we're not saving backref information, so we don't

                    // need to do any special backref maintenance here

                }

 

                // prevent a pattern that matches 0 characters from matching

                // again at the same point in the string

                param.m_no0len = ( 0 == match_length );

 

                param.m_imatchbegin = results.m_ibegin;

                std::advance( param.m_imatchbegin, pos ); // ineffecient for bidirectional iterators.

 

                param.m_iend = results.m_ibegin;

                std::advance( param.m_iend, stop_offset ); // ineffecient for bidirectional iterators.

            }

 

            // If we did special backref handling, swap the backref vectors

            if( pat._save_backrefs() )

            {

                results.m_rgbackrefs.swap( rgtempbackrefs );

            }

            else if( ! results.m_rgbackrefs[0].matched )

            {

                results.m_rgbackrefs.clear();

            }

        }

        else if( _do_try_match( pat, param, results.m_rgbackrefs, false ) )

        {

            backref_type const & br = param.m_prgbackrefs[0];

            ++csubst;

            _do_subst_internal(

                str, results, pat,

                std::distance( results.m_ibegin, br.first ),

                std::distance( br.first, br.second ) );

            results.m_ibegin = results.m_pbackref_str->begin();

        }

 

        if( NOBACKREFS == ( pat.flags() & NOBACKREFS ) )

        {

            results.m_rgbackrefs.clear();

        }

 

        return csubst;

    }

 

    static instantiator instantiate()

    {

        return instantiator_helper

        (

            &regex_access::_do_match_iterative_helper_s,

            &regex_access::_do_match_iterative_helper_c,

            &regex_access::_do_match_recursive_s,

            &regex_access::_do_match_recursive_c,

            &regex_access::_do_match_with_stack,

            &regex_access::_do_match_impl

        );

    }

};

 

 

//

// Some helper functions needed by process_escapes

//

template< typename CharT >

inline bool regex_isxdigit( CharT ch )

{

    return ( REGEX_CHAR(CharT,'0') <= ch && REGEX_CHAR(CharT,'9') >= ch )

        || ( REGEX_CHAR(CharT,'a') <= ch && REGEX_CHAR(CharT,'f') >= ch )

        || ( REGEX_CHAR(CharT,'A') <= ch && REGEX_CHAR(CharT,'F') >= ch );

}

 

template< typename CharT >

inline int regex_xdigit2int( CharT ch )

{

    if( REGEX_CHAR(CharT,'a') <= ch && REGEX_CHAR(CharT,'f') >= ch )

        return ch - REGEX_CHAR(CharT,'a') + 10;

    if( REGEX_CHAR(CharT,'A') <= ch && REGEX_CHAR(CharT,'F') >= ch )

        return ch - REGEX_CHAR(CharT,'A') + 10;

    return ch - REGEX_CHAR(CharT,'0');

}

 

} // namespace detail

 

// --------------------------------------------------------------------------

//

// Function:    process_escapes

//

// Description: Turn the escape sequnces /f /n /r /t /v // into their

//              ASCII character equivalents. Also, optionally process

//              perl escape sequences.

//

// Returns:     void

//

// Arguments:   str      - the string to process

//              fPattern - true if the string is to be processed as a regex

//

// Notes:       When fPattern is true, the perl escape sequences are not

//              processed.  If there is an octal or hex excape sequence, we

//              don't want to turn it into a regex metacharacter here.  We

//              leave it unescaped so the regex parser correctly interprests

//              it as a character literal.

//

// History:     8/1/2001 - ericne - Created

//

// --------------------------------------------------------------------------

template< typename CharT, typename TraitsT, typename AllocT >

inline void process_escapes( std::basic_string<CharT, TraitsT, AllocT> & str, bool fPattern ) //throw()

{

    typedef typename std::basic_string<CharT, TraitsT, AllocT>::size_type size_type;

 

    size_type i = 0;

    size_type const npos = std::basic_string<CharT, TraitsT, AllocT>::npos;

 

    if( str.empty() )

        return;

 

    while( npos != ( i = str.find( REGEX_CHAR(CharT,'//'), i ) ) )

    {

        if( str.size() - 1 == i )

            return;

 

        switch( str[i+1] )

        {

        case REGEX_CHAR(CharT,'a'):

            str.replace( i, 2, 1, REGEX_CHAR(CharT,'/a') );

            break;

        case REGEX_CHAR(CharT,'b'):

            if( ! fPattern )

                str.replace( i, 2, 1, REGEX_CHAR(CharT,'/b') );

            else

                ++i;

            break;

        case REGEX_CHAR(CharT,'e'):

            str.replace( i, 2, 1, CharT( 27 ) );

            break;

        case REGEX_CHAR(CharT,'f'):

            str.replace( i, 2, 1, REGEX_CHAR(CharT,'/f') );

            break;

        case REGEX_CHAR(CharT,'n'):

            str.replace( i, 2, 1, REGEX_CHAR(CharT,'/n') );

            break;

        case REGEX_CHAR(CharT,'r'):

            str.replace( i, 2, 1, REGEX_CHAR(CharT,'/r') );

            break;

        case REGEX_CHAR(CharT,'t'):

            str.replace( i, 2, 1, REGEX_CHAR(CharT,'/t') );

            break;

        case REGEX_CHAR(CharT,'v'):

            str.replace( i, 2, 1, REGEX_CHAR(CharT,'/v') );

            break;

        case REGEX_CHAR(CharT,'//'):

            if( fPattern )

            {

                if( i+3 < str.size() && REGEX_CHAR(CharT,'//') == str[i+2] && REGEX_CHAR(CharT,'//') == str[i+3] )

                    str.erase( i, 2 );

                ++i;

            }

            else

                str.erase( i, 1 );

            break;

        case REGEX_CHAR(CharT,'0'): case REGEX_CHAR(CharT,'1'): case REGEX_CHAR(CharT,'2'): case REGEX_CHAR(CharT,'3'):

        case REGEX_CHAR(CharT,'4'): case REGEX_CHAR(CharT,'5'): case REGEX_CHAR(CharT,'6'): case REGEX_CHAR(CharT,'7'):

            if( ! fPattern )

            {

                size_t j=i+2;

                CharT ch = CharT( str[i+1] - REGEX_CHAR(CharT,'0') );

                for( ; j-i < 4 && j < str.size() && REGEX_CHAR(CharT,'0') <= str[j] && REGEX_CHAR(CharT,'7') >= str[j]; ++j )

                    ch = CharT( ch * 8 + ( str[j] - REGEX_CHAR(CharT,'0') ) );

                str.replace( i, j-i, 1, ch );

            }

            break;

        case REGEX_CHAR(CharT,'x'):

            if( ! fPattern )

            {

                CharT ch = 0;

                size_t j=i+2;

                for( ; j-i < 4 && j < str.size() && detail::regex_isxdigit( str[j] ); ++j )

                    ch = CharT( ch * 16 + detail::regex_xdigit2int( str[j] ) );

                str.replace( i, j-i, 1, ch );

            }

            break;

        case REGEX_CHAR(CharT,'c'):

            if( ! fPattern && i+2 < str.size() )

            {

                CharT ch = str[i+2];

                if( REGEX_CHAR(CharT,'a') <= ch && REGEX_CHAR(CharT,'z') >= ch )

                    ch = detail::regex_toupper( ch );

                str.replace( i, 3, 1, CharT( ch ^ 0x40 ) );

            }

            break;

        default:

            if( fPattern )

                ++i;

            else

                str.erase( i, 1 );

            break;

        }

        ++i;

        if( str.size() <= i )

            return;

    }

}

 

#endif

//+---------------------------------------------------------------------------

//

//  Copyright ( C ) Microsoft, 1994 - 2002.

//

//  File:       syntax2.cpp

//

//  Contents:   data definitions for the syntax modules

//

//  Classes:

//

//  Functions:

//

//  Coupling:

//

//  Notes:

//

//  Author:     Eric Niebler ( [email protected] )

//

//  History:    3-29-00   ericne   Created

//

//----------------------------------------------------------------------------

 

#include "syntax2.h"

 

namespace regex

{

 

REGEX_SELECTANY TOKEN const perl_syntax_base::s_rgreg[ UCHAR_MAX + 1 ] =

{

/*  0*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/*  8*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/* 16*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/* 24*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/* 32*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    END_LINE,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/* 40*/ BEGIN_GROUP, END_GROUP, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,  MATCH_ANY, NO_TOKEN,

/* 48*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/* 56*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/* 64*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/* 72*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/* 80*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/* 88*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN, BEGIN_CHARSET,      ESCAPE,  NO_TOKEN, BEGIN_LINE, NO_TOKEN,

/* 96*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/*104*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/*112*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN,    NO_TOKEN,  NO_TOKEN,   NO_TOKEN, NO_TOKEN,

/*120*/    NO_TOKEN,  NO_TOKEN, NO_TOKEN,      NO_TOKEN, ALTERNATION,  NO_TOKEN,   NO_TOKEN, NO_TOKEN

// and the rest are 0...

};

 

REGEX_SELECTANY TOKEN const perl_syntax_base::s_rgescape[ UCHAR_MAX + 1 ] =

{

/*  0*/    NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

/*  8*/    NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

/* 16*/    NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

/* 24*/    NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

/* 32*/    NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

/* 40*/    NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

/* 48*/    NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

/* 56*/    NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

/* 64*/    NO_TOKEN,   ESC_BEGIN_STRING, ESC_NOT_WORD_BOUNDARY,       NO_TOKEN,

      ESC_NOT_DIGIT, ESC_QUOTE_META_OFF,              NO_TOKEN,       NO_TOKEN,

/* 72*/    NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

/* 80*/    NO_TOKEN,  ESC_QUOTE_META_ON,              NO_TOKEN,  ESC_NOT_SPACE,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,   ESC_NOT_WORD,

/* 88*/    NO_TOKEN,           NO_TOKEN,        ESC_END_STRING,       NO_TOKEN,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

/* 96*/    NO_TOKEN,           NO_TOKEN,     ESC_WORD_BOUNDARY,       NO_TOKEN,

          ESC_DIGIT,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

/*104*/    NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN,

/*112*/    NO_TOKEN,           NO_TOKEN,              NO_TOKEN,      ESC_SPACE,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       ESC_WORD,

/*120*/    NO_TOKEN,           NO_TOKEN,      ESC_END_STRING_z,       NO_TOKEN,

           NO_TOKEN,           NO_TOKEN,              NO_TOKEN,       NO_TOKEN

// and the rest are 0...

};

 

namespace detail

{

 

REGEX_SELECTANY extern posix_charset_type const g_rgposix_charsets[] =

{

    { "[:alnum:]",    9 },

    { "[:^alnum:]",  10 },

    { "[:alpha:]",    9 },

    { "[:^alpha:]",  10 },

    { "[:blank:]",    9 },

    { "[:^blank:]",  10 },

    { "[:cntrl:]",    9 },

    { "[:^cntrl:]",  10 },

    { "[:digit:]",    9 },

    { "[:^digit:]",  10 },

    { "[:graph:]",    9 },

    { "[:^graph:]",  10 },

    { "[:lower:]",    9 },

    { "[:^lower:]",  10 },

    { "[:print:]",    9 },

    { "[:^print:]",  10 },

    { "[:punct:]",    9 },

    { "[:^punct:]",  10 },

    { "[:space:]",    9 },

    { "[:^space:]",  10 },

    { "[:upper:]",    9 },

    { "[:^upper:]",  10 },

    { "[:xdigit:]",  10 },

    { "[:^xdigit:]", 11 }

};

 

REGEX_SELECTANY extern size_t const g_cposix_charsets = ARRAYSIZE( g_rgposix_charsets );

 

} // namespace detail

 

} // namespace regex

 

 

 

 

 

 

/***

*resetstk - Recover from Stack overflow.

*

*       Copyright (c) Microsoft Corporation. All rights reserved.

*

*Purpose:

*       Defines the _resetstkoflw() function.

*

*******************************************************************************/

 

#if defined(_MSC_VER) & _MSC_VER < 1300

#include <stdlib.h>

#include <malloc.h>

#include <windows.h>

 

#define MIN_STACK_REQ_WIN9X 0x11000

#define MIN_STACK_REQ_WINNT 0x2000

 

#ifdef _WIN64

typedef unsigned __int64 REGEX_DWORD_PTR;

#else

typedef unsigned __int32 REGEX_DWORD_PTR;

#endif

 

struct osplatform_getter

{

    int m_osplatform;

 

    osplatform_getter() : m_osplatform( 0 )

    {

        OSVERSIONINFOA osvi;

        osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);

        if( GetVersionExA( & osvi ) )

            m_osplatform = osvi.dwPlatformId;

    }

};

 

inline int get_osplatform()

{

    static osplatform_getter const s_osplatform_getter;

    return s_osplatform_getter.m_osplatform;

};

 

/***

* void _resetstkoflw(void) - Recovers from Stack Overflow

*

* Purpose:

*       Sets the guard page to its position before the stack overflow.

*

* Exit:

*       Returns nonzero on success, zero on failure

*

*******************************************************************************/

 

extern "C" int __cdecl _resetstkoflw(void)

{

    LPBYTE pStack, pGuard, pStackBase, pMinGuard;

    MEMORY_BASIC_INFORMATION mbi;

    SYSTEM_INFO si;

    DWORD PageSize;

    DWORD flNewProtect;

    DWORD flOldProtect;

 

    // Use _alloca() to get the current stack pointer

 

    pStack = static_cast<LPBYTE>( _alloca(1) );

 

    // Find the base of the stack.

 

    if (VirtualQuery(pStack, &mbi, sizeof mbi) == 0)

        return 0;

    pStackBase = static_cast<LPBYTE>( mbi.AllocationBase );

 

    // Find the page just below where the stack pointer currently points.

    // This is the new guard page.

 

    GetSystemInfo(&si);

    PageSize = si.dwPageSize;

 

    pGuard = (LPBYTE) (((REGEX_DWORD_PTR)pStack & ~(REGEX_DWORD_PTR)(PageSize - 1))

                       - PageSize);

 

    // If the potential guard page is too close to the start of the stack

    // region, abandon the reset effort for lack of space.  Win9x has a

    // larger reserved stack requirement.

 

    pMinGuard = pStackBase + ((get_osplatform() == VER_PLATFORM_WIN32_WINDOWS)

                              ? MIN_STACK_REQ_WIN9X

                              : MIN_STACK_REQ_WINNT);

 

    if (pGuard < pMinGuard)

        return 0;

 

    // On a non-Win9x system, release the stack region below the new guard

    // page.  This can't be done for Win9x because of OS limitations.

 

    if (get_osplatform() != VER_PLATFORM_WIN32_WINDOWS) {

        if (pGuard > pStackBase)

            VirtualFree(pStackBase, pGuard - pStackBase, MEM_DECOMMIT);

 

        VirtualAlloc(pGuard, PageSize, MEM_COMMIT, PAGE_READWRITE);

    }

 

    // Enable the new guard page.

 

    flNewProtect = get_osplatform() == VER_PLATFORM_WIN32_WINDOWS

                   ? PAGE_NOACCESS

                   : PAGE_READWRITE | PAGE_GUARD;

 

    return VirtualProtect(pGuard, PageSize, flNewProtect, &flOldProtect);

}

 

#endif

//+---------------------------------------------------------------------------

//

//  Copyright ( C ) Microsoft, 1994 - 2002.

//

//  File:       regexpr2.h

//

//  Contents:   classes for regular expression pattern matching a-la perl

//

//  Classes:    basic_rpattern_base

//

//  Functions:  rpattern::match

//              rpattern::substitute

//              match_results::cbackrefs

//              match_results::backref

//              match_results::all_backrefs

//              match_results::backref_str

//

//  Author:     Eric Niebler ( [email protected] )

//

//----------------------------------------------------------------------------

 

#ifndef REGEXPR_H

#define REGEXPR_H

 

#ifdef _MSC_VER

  // warning C4189: local variable is initialized but not referenced

  // warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)

  // warning C4702: unreachable code

  // warning C4710: function 'blah' not inlined

  // warning C4786: identifier was truncated to '255' characters in the debug information

# pragma warning( push )

# pragma warning( disable : 4189 4290 4702 4710 4786 )

# define REGEX_SEH_STACK_OVERFLOW 0xC00000FDL

# if 1200 < _MSC_VER

# include <malloc.h> // for _resetstkoflw

# else

  extern "C" int __cdecl _resetstkoflw(void);

# endif

  extern "C" unsigned long __cdecl _exception_code(void);

#endif

 

#include <list>

#include <iosfwd>

#include <string>

#include <vector>

#include <memory>

#include <cwctype>

#include "syntax2.h"

#include "restack.h"

 

namespace regex

{

 

// This is the default alignment for the unsafe heterogeneous stack.

// If you are getting a compiler error in one of the unsafe_stack

// methods, then compile with -DREGEX_STACK_ALIGNMENT=16 or 32

#ifndef REGEX_STACK_ALIGNMENT

# define REGEX_STACK_ALIGNMENT sizeof( void* )

#endif

 

#if !defined( REGEX_DEBUG ) & ( defined( DEBUG ) | defined( _DEBUG ) | defined( DBG ) )

# define REGEX_DEBUG 1

#else

# define REGEX_DEBUG 0

#endif

 

#if !defined( REGEX_DEBUG_ITERATORS ) & defined( _HAS_ITERATOR_DEBUGGING )

# define REGEX_DEBUG_ITERATORS 1

#else

# define REGEX_DEBUG_ITERATORS 0

#endif

 

namespace detail

{

#if REGEX_DEBUG | REGEX_DEBUG_ITERATORS

    // Turn on hetero_stack's run-time type checking

    typedef hetero_stack<REGEX_STACK_ALIGNMENT,true,false,32,0>       unsafe_stack;

#else

    // Assume that all types pushed on stack have trivial destructors.

    typedef hetero_stack<REGEX_STACK_ALIGNMENT,false,true,4096,1024>  unsafe_stack;

#endif

 

    // Used to initialize variables with the same value they would have

    // if they were initialized as a static global. ( Ptrs get NULL,

    // integer types get 0, etc, etc )

    template< typename T > struct static_init { static T const value; };

    template< typename T > T const static_init<T>::value = T();

 

    //

    // Forward declarations

    //

    template< typename IterT > class  sub_expr;

    template< typename IterT > class  match_group_base;

    template< typename IterT > class  basic_rpattern_base_impl;

    template< typename IterT > struct match_param;

    template< typename IterT > struct sub_expr_base;

    template< typename IterT > struct regex_access;

 

    // an iterator that keeps track of whether it is singular or not.

    template< typename IterT > struct smart_iter

    {

        IterT m_iter;

        bool m_valid;

 

        smart_iter()

            : m_iter( static_init<IterT>::value )

            , m_valid( false )

        {

        }

        smart_iter( smart_iter const & rhs )

            : m_iter( rhs.m_iter )

            , m_valid( rhs.m_valid )

        {

        }

        smart_iter( IterT iter ) // implicit conversion OK!

            : m_iter( iter )

            , m_valid( true )

        {

        }

        smart_iter & operator=( smart_iter const & rhs )

        {

            m_iter  = rhs.m_iter;

            m_valid = rhs.m_valid;

            return *this;

        }

        friend bool operator==( smart_iter const & lhs, smart_iter const & rhs )

        {

            if( !lhs.m_valid || !rhs.m_valid )

                return lhs.m_valid == rhs.m_valid;

            else

                return lhs.m_iter == rhs.m_iter;

        }

        friend bool operator!=( smart_iter const & lhs, smart_iter const & rhs )

        {

            return ! operator==( lhs, rhs );

        }

    };

 

    template< typename IterT > struct iter_select

    {

        typedef typename select

        <

            REGEX_DEBUG_ITERATORS && !is_scalar<IterT>::value,

            smart_iter<IterT>,

            IterT

        >::type     type;

    };

 

    template< int SizeT > struct type_with_size { char buffer[ SizeT ]; };

 

    // make up for the fact that the VC6 std::allocator does

    // not have template constructors

    template< typename ToT, typename FromT >

    std::allocator<ToT> convert_allocator( std::allocator<FromT>, int )

    {

        return std::allocator<ToT>();

    }

 

    template< typename ToT, typename FromT >

    FromT const & REGEX_CDECL convert_allocator( FromT const & from, ... )

    {

        return from;

    }

 

    template< int > struct rebind_helper;

 

    // unknown allocator

    template< typename T >

    type_with_size<1> REGEX_CDECL allocator_picker( T const &, ... );

 

    template<> struct rebind_helper<1>

    {

        template< typename AllocT, typename ElemT >

        struct inner

        {

            REGEX_NVC6( typedef typename AllocT::template rebind<ElemT>::other type; )

        };

    };

 

    // std::allocator

    template< typename T >

    type_with_size<2> allocator_picker( std::allocator<T> const &, int );

 

    template<> struct rebind_helper<2>

    {

        template< typename, typename ElemT >

        struct inner

        {

            typedef std::allocator<ElemT> type;

        };

    };

 

    template< typename AllocT, typename ElemT >

    struct rebind

    {

        enum { alloc_type = sizeof(allocator_picker(factory<AllocT>::make(),0)) };

 

        typedef typename rebind_helper<alloc_type>::template inner<AllocT,ElemT>::type type;

    };

}

 

// --------------------------------------------------------------------------

//

// Class:       width_type

//

// Description: represents the width of a sub-expression

//

// Members:     m_min      - smallest number of characters a sub-expr can span

//              m_max      - largest number of characters a sub-expr can span

//

// History:     8/14/2000 - ericne - Created

//

// --------------------------------------------------------------------------

struct width_type

{

    size_t m_min;

    size_t m_max;

};

 

inline width_type const uninit_width()

{

    width_type const width = { size_t( -1 ), size_t( -1 ) };

    return width;

}

 

// Helper function for processing escape sequences

template< typename CharT, typename TraitsT, typename AllocT >

void process_escapes( std::basic_string<CharT, TraitsT, AllocT> & str, bool fPattern = false ); //throw()

 

// --------------------------------------------------------------------------

//

// Class:       backref_tag

//

// Description: Struct which contains a back-reference.  It is a template

//              on the iterator type.

//

// Methods:     backref_tag   - c'tor

//              operator bool - so that if( br ) is true if this br matched

//              operator!     - inverse of operator bool()

//

// Members:     reserved      - move along, nothing to see here

//

// History:     8/9/2001 - ericne - Created

//

// --------------------------------------------------------------------------

template< typename IterT >

class backref_tag : public std::pair<IterT, IterT>

{

    struct detail_t { detail_t * d; };

 

    template< typename OStreamT, typename OtherT >

    void REGEX_CDECL _do_print( OStreamT & sout, OtherT, ... ) const

    {

        typedef typename OStreamT::char_type char_type;

        typedef typename OStreamT::traits_type traits_type;

        std::ostreambuf_iterator<char_type, traits_type> iout( sout );

        for( IterT iter = first; iter != second; ++iter, ++iout )

            *iout = *iter;

    }

 

    // overload that is optimized for bare char*

    template< typename OStreamT >

    void _do_print( OStreamT & sout, typename OStreamT::char_type const *, int ) const

    {

        sout.write( first, static_cast<std::streamsize>( std::distance( first, second ) ) );

    }

 

public:

    typedef IterT iterator_type;

    typedef typename std::iterator_traits<IterT>::value_type char_type;

    typedef std::basic_string<char_type> string_type;

 

    typedef typename detail::iter_select<IterT>::type smart_iter_type;

 

    explicit backref_tag

    (

        IterT i1 = detail::static_init<IterT>::value,

        IterT i2 = detail::static_init<IterT>::value

    )

        : std::pair<IterT, IterT>( i1, i2 )

        , matched( false )

        , reserved1( i1 )

        , reserved2( 0 )

        , reserved3( false )

        , reserved4( detail::static_init<smart_iter_type>::value )

        , reserved5( detail::static_init<smart_iter_type>::value )

    {

    }

 

    IterT begin() const

    {

        return first;

    }

 

    IterT end() const

    {

        return second;

    }

 

    string_type const str() const

    {

        return matched ? string_type( first, second ) : string_type();

    }

 

    // Use the "safe bool" idiom. This allows implicit conversion to bool,

    // but not to int. It also disallows conversion to void*.

    typedef detail_t * detail_t::* bool_type;

 

    operator bool_type() const //throw()

    {

        return matched ? &detail_t::d : 0;

    }

 

    bool operator!() const //throw()

    {

        return ! matched;

    }

 

    template< typename CharT, typename TraitsT >

    std::basic_ostream<CharT, TraitsT> & print( std::basic_ostream<CharT, TraitsT> & sout ) const

    {

        _do_print( sout, IterT(), 0 );

        return sout;

    }

 

    bool   matched;

 

//private:

    IterT           reserved1; // used for internal book-keeping

    size_t          reserved2; // used for internal book-keeping

    bool            reserved3; // used for internal book-keeping

    smart_iter_type reserved4; // used for internal book-keeping

    smart_iter_type reserved5; // used for internal book-keeping

};

 

//namespace detail

//{

    // indexing into the backref vector is faster if the backref_tag struct

    // has a size that is a power of 2.

    //static static_assert<32==sizeof(backref_tag<char*>)> const check_backref_size;

//}

 

// --------------------------------------------------------------------------

//

// Class:       basic_match_results

//

// Description: Use this structure for returning match/substitute results

//              out from the match()/substitute() methods.

//

// Methods:     cbackrefs      -

//              backref        -

//              all_backrefs   -

//              rlength        -

//

// Members:     m_rgbackrefs   -

//

// Typedefs:    const_iterator -

//              backref_type   -

//              backref_vector -

//

// History:     8/8/2001 - ericne - Created

//

// --------------------------------------------------------------------------

template

<

    typename IterT,

    typename AllocT = std::allocator< REGEX_DEPENDENT_TYPENAME std::iterator_traits<IterT>::value_type >

>

struct basic_match_results

{

    // const_iterator is deprecated. Use iterator_type instead.

    REGEX_DEPRECATED typedef IterT                                const_iterator;

    typedef IterT                                                 iterator_type;

    typedef backref_tag<IterT>                                    backref_type;

    typedef typename detail::rebind<AllocT, backref_type>::type   allocator_type;

    typedef std::vector<backref_type, allocator_type>             backref_vector;

    friend struct detail::regex_access<IterT>;

 

    explicit basic_match_results( allocator_type const & alloc = allocator_type() )

        : m_rgbackrefs( alloc )

    {

    }

 

    virtual ~basic_match_results()

    {

    }

 

    size_t cbackrefs() const //throw()

    {

        return m_rgbackrefs.size();

    }

 

    backref_type const & backref( size_t cbackref ) const //throw( std::out_of_range )

    {

        return m_rgbackrefs.at( cbackref );

    }

 

    backref_vector const & all_backrefs() const //throw()

    {

        return m_rgbackrefs;

    }

 

    size_t rstart( size_t cbackref = 0 ) const //throw( std::out_of_range )

    {

        return std::distance( m_ibegin, m_rgbackrefs.at( cbackref ).first );

    }

 

    size_t rlength( size_t cbackref = 0 ) const //throw( std::out_of_range )

    {

        return std::distance( m_rgbackrefs.at( cbackref ).first, m_rgbackrefs.at( cbackref ).second );

    }

 

private:

    backref_vector m_rgbackrefs;

    IterT           m_ibegin;

};

 

// Unnecessary and deprecated

template< typename CharT, typename AllocT = std::allocator<CharT> >

struct basic_match_results_c : public basic_match_results<CharT const *, AllocT>

{

    typedef basic_match_results<CharT const *, AllocT> base;

    REGEX_DEPRECATED typedef typename base::const_iterator const_iterator;

    typedef typename base::iterator_type  iterator_type;

    typedef typename base::backref_type   backref_type;

    typedef typename base::allocator_type allocator_type;

    typedef typename base::backref_vector backref_vector;

 

    explicit basic_match_results_c( allocator_type const & alloc = allocator_type() )

        : basic_match_results<CharT const *, AllocT>( alloc )

    {

    }

};

 

template< typename CharT, typename TraitsT, typename AllocT >

struct subst_results_base

{

    typedef typename detail::rebind<AllocT, CharT>::type              char_allocator_type;

    typedef std::basic_string<CharT, TraitsT, char_allocator_type>    string_type;

    typedef typename string_type::const_iterator                    iterator_type;

    typedef basic_match_results<iterator_type,AllocT>                type;

};

 

//

// For storing the results of a substitute() operation

//

template

<

    typename CharT,

    typename TraitsT = std::char_traits<CharT>,

    typename AllocT  = std::allocator<CharT>

>

struct basic_subst_results : public subst_results_base<CharT, TraitsT, AllocT>::type

{

    typedef typename detail::rebind<AllocT, CharT>::type              char_allocator_type;

    typedef std::basic_string<CharT, TraitsT, char_allocator_type>    string_type;

    typedef typename string_type::const_iterator                    iterator_type;

    typedef basic_match_results<iterator_type, AllocT>               base;

    typedef typename base::backref_type                             backref_type;

    typedef typename base::allocator_type                           allocator_type;

    typedef typename base::backref_vector                           backref_vector;

    friend struct detail::regex_access<iterator_type>;

 

    explicit basic_subst_results( allocator_type const & alloc = allocator_type() )

        : basic_match_results< iterator_type, AllocT >( alloc )

        , m_backref_str( detail::convert_allocator<CharT>( alloc, 0 ) )

        , m_pbackref_str( &m_backref_str )

    {

    }

 

    string_type const & backref_str() const //throw()

    {

        return *m_pbackref_str;

    }

 

private:

    string_type         m_backref_str;

    string_type const * m_pbackref_str;

};

 

 

template< typename CharT, typename TraitsT, typename AllocT >

struct split_results_base

{

    typedef typename detail::rebind<AllocT, CharT>::type            char_allocator_type;

    typedef std::basic_string<CharT, TraitsT, char_allocator_type>  string_type;

    typedef typename detail::rebind<AllocT, string_type>::type      allocator_type;

    typedef std::vector<string_type,allocator_type>                 type;

};

 

//

// For storing the results of a split() operation

//

template

<

    typename CharT,

    typename TraitsT = std::char_traits<CharT>,

    typename AllocT  = std::allocator<CharT>

>

struct basic_split_results : private split_results_base<CharT, TraitsT, AllocT>::type

{

    typedef CharT                                                   char_type;

    typedef typename detail::rebind<AllocT, CharT>::type            char_allocator_type;

    typedef std::basic_string<CharT, TraitsT, char_allocator_type>  string_type;

    typedef typename detail::rebind<AllocT, string_type>::type      allocator_type;

    typedef std::vector<string_type,allocator_type>                 string_vector;

    typedef string_vector                                           base;

 

    explicit basic_split_results( allocator_type const & alloc = allocator_type() )

        : base( alloc )

    {

    }

 

#if !defined(_MSC_VER) | 1200 < _MSC_VER

    typedef typename allocator_type::pointer        pointer;

    typedef typename allocator_type::const_pointer  const_pointer;

#else

    typedef string_type *                           pointer;

    typedef string_type const *                     const_pointer;

#endif

 

    // shortcuts to the most basic read-only container operations

    typedef typename base::size_type                size_type;

    typedef typename base::difference_type          difference_type;

    typedef typename base::value_type               value_type;

    typedef typename base::reference                reference;

    typedef typename base::const_reference          const_reference;

    typedef typename base::iterator                 iterator;

    typedef typename base::const_iterator           const_iterator;

    typedef typename base::reverse_iterator         reverse_iterator;

    typedef typename base::const_reverse_iterator   const_reverse_iterator;

    using base::begin;

    using base::end;

    using base::rbegin;

    using base::rend;

    using base::operator[];

    using base::at;

    using base::size;

    using base::front;

    using base::back;

 

    string_vector & strings()

    {

        return *this;

    }

 

    string_vector const & strings() const

    {

        return *this;

    }

};

 

//

// The REGEX_MODE is a way of controlling how matching occurs.

//

enum REGEX_MODE

{

    MODE_FAST,  // Uses the fast, recursive algorithm. Could overflow stack.

    MODE_SAFE,  // Uses the slow, iterative algorithm. Can't overflow stack.

    MODE_MIXED, // Uses a heuristic to automatically determine which algorithm

                // is the most appropriate for this pattern.

 

    // MS VC++ has structured exception handling, which makes the

    // consequences of a stack overflow much less severe. Because of this,

    // it is possible to use the "fast" algorithm always on MS platforms,

#ifdef _MSC_VER

    MODE_DEFAULT = MODE_FAST

#else

    MODE_DEFAULT = MODE_MIXED

#endif

};

 

//

// helper function for resetting the intrinsic character sets.

// This should be called after changing the locale with setlocale()

//

template< typename CharT >

void reset_intrinsic_charsets( CharT ch = CharT( 0 ) );

 

// This is for implementation details that really belong in the

// cpp file, but can't go there because of template strangeness.

#include "reimpl2.h"

 

// --------------------------------------------------------------------------

//

// Class:       basic_rpattern_base

//

// Description:

//

// Methods:     basic_rpattern_base - c'tor

//              basic_rpattern_base -

//              basic_rpattern_base -

//              init                - ( re )initialize the pattern

//              init                -

//              set_substitution    - set the substitution string

//              _find_next_group    - parse the next group of the pattern

//              _find_next          - parse the next sub_expr of the pattern

//              _find_atom          - parse the next atom of the pattern

//              _quantify           - quantify the sub_expr

//              _common_init        - perform some common initialization tasks

//              _parse_subst        - parse the substitution string

//              _add.m_subst_backref  - add a backref node to the subst list

//

// Members:     m_invisible_groups  - list of hidden groups

//

// Typedefs:    syntax_type         -

//              backref_type        -

//              backref_vector      -

//              string_type         -

//              size_type           -

//

// History:     8/14/2000 - ericne - Created

//              8/5/2001 - ericne - complete overhaul

//

// --------------------------------------------------------------------------

template< typename IterT, typename SyntaxT >

class basic_rpattern_base : protected detail::basic_rpattern_base_impl<IterT>

{

protected:

    typedef detail::basic_rpattern_base_impl<IterT>   impl;

public:

    typedef SyntaxT syntax_type;

    typedef typename impl::char_type       char_type;

    typedef typename impl::traits_type     traits_type;

 

    typedef typename impl::string_type     string_type;

    typedef typename impl::size_type       size_type;

 

    typedef typename impl::backref_type    backref_type;

    typedef typename impl::backref_vector  backref_vector;

 

    void init

    (

        string_type const & pat,

        REGEX_FLAGS flags = NOFLAGS,

        REGEX_MODE mode = MODE_DEFAULT

    );                                                      //throw( bad_regexpr, std::bad_alloc );

 

    void init

    (

        string_type const & pat,

        string_type const & subst,

        REGEX_FLAGS flags = NOFLAGS,

        REGEX_MODE mode = MODE_DEFAULT

    );                                                      //throw( bad_regexpr, std::bad_alloc );

 

    void set_substitution

    (

        string_type const & subst

    );                                                      //throw( bad_regexpr, std::bad_alloc );

 

    using impl::flags;

    using impl::mode;

    using impl::get_width;

    using impl::cgroups;

    using impl::get_pat;

    using impl::get_subst;

    using impl::swap;

    using impl::npos;

 

protected:

    basic_rpattern_base() //throw()

        : detail::basic_rpattern_base_impl<IterT>()

    {

    }

 

    basic_rpattern_base( basic_rpattern_base<IterT, SyntaxT> const & that )                                                   //throw()

        : detail::basic_rpattern_base_impl<IterT>( that.flags(), that.mode(), that.get_pat(), that.get_subst() )

    {

        // Don't call _normalize_string(). If that.flags()&NORMALIZE,

        // then subst has already been normalized.

        _common_init( this->m_flags );

        _parse_subst( *this->m_subst, this->m_fuses_backrefs, this->m_subst_list ); // must come after _common_init

    }

 

    explicit basic_rpattern_base

    (

        string_type const & pat,

        REGEX_FLAGS flags = NOFLAGS,

        REGEX_MODE mode = MODE_DEFAULT

    )                                                   //throw( bad_regexpr, std::bad_alloc )

        : detail::basic_rpattern_base_impl<IterT>( flags, mode, pat )

    {

        _common_init( this->m_flags );

    }

 

    basic_rpattern_base

    (

        string_type const & pat,

        string_type const & subst,

        REGEX_FLAGS flags = NOFLAGS,

        REGEX_MODE mode = MODE_DEFAULT

    )                                                   //throw( bad_regexpr, std::bad_alloc )

        : detail::basic_rpattern_base_impl<IterT>( flags, mode, pat, subst )

    {

        _common_init( this->m_flags );

        _normalize_string( *this->m_subst );

        _parse_subst( *this->m_subst, this->m_fuses_backrefs, this->m_subst_list ); // must come after _common_init

    }

 

    basic_rpattern_base & operator=

    (

        basic_rpattern_base<IterT, SyntaxT> const & that

    )                                                   //throw( bad_regexpr, std::bad_alloc )

    {

        basic_rpattern_base<IterT, SyntaxT> temp( that );

        swap( temp );

        return *this;

    }

 

    detail::match_group_base<IterT> * _find_next_group

    (

        typename string_type::iterator & ipat,

        detail::match_group_base<IterT> * pgroup, syntax_type & sy,

        std::vector<detail::match_group_base<IterT>*> & rggroups

    );

 

    bool _find_next

    (

        typename string_type::iterator & ipat,

        detail::match_group_base<IterT> * pgroup, syntax_type & sy,

        std::vector<detail::match_group_base<IterT>*> & rggroups

    );

 

    void _find_atom

    (

        typename string_type::iterator & ipat,

        detail::match_group_base<IterT> * pgroup,

        syntax_type & sy

    );

 

    void _quantify

    (

        std::auto_ptr<detail::sub_expr<IterT> > & pnew,

        typename string_type::iterator & ipat,

        bool is_group,

        syntax_type & sy

    );

 

    void _add_subst_backref

    (

        detail::subst_node & snode,

        size_t nbackref,

        ptrdiff_t rstart,

        bool & uses_backrefs,

        detail::subst_list_type & subst_list

    ) const;

 

    void _parse_subst

    (

        string_type & subst,

        bool & uses_backrefs,

        detail::subst_list_type & subst_list

    ) const;

 

    void _common_init( REGEX_FLAGS flags );

 

    static detail::instantiator instantiate()

    {

        typedef basic_rpattern_base this_type;

 

        return detail::instantiator_helper

        (

            &detail::basic_rpattern_base_impl<IterT>::instantiate,

            static_cast<void (this_type::*)( string_type const &, REGEX_FLAGS, REGEX_MODE )>( &this_type::init ),

            static_cast<void (this_type::*)( string_type const &, string_type const &, REGEX_FLAGS, REGEX_MODE )>( &this_type::init ),

            &this_type::set_substitution,

            &this_type::_find_next_group,

            &this_type::_find_next,

            &this_type::_find_atom,

            &this_type::_add_subst_backref,

            &this_type::_parse_subst,

            &this_type::_common_init

        );

    }

};

 

// --------------------------------------------------------------------------

//

// Class:       basic_rpattern

//

// Description: generic regex pattern object

//

// Methods:     basic_rpattern - c'tor

//              basic_rpattern -

//              basic_rpattern -

//              match          - match from begin iter to end iter

//              match          - match a null-terminated string

//              match          - match a std::string

//              count          - count matches from begin iter to end iter

//              count          - count matches in a null-terminated string

//              count          - count matches in a std::string

//              substitute     - do substitutions in a std::string

//              _do_match      - internal implementation

//              _do_count      - internal implementation

//

// History:     8/13/2001 - ericne - Created

//

// --------------------------------------------------------------------------

template

<

    typename IterT,

    typename SyntaxT = perl_syntax<REGEX_DEPENDENT_TYPENAME std::iterator_traits<IterT>::value_type>

>

class basic_rpattern : public basic_rpattern_base<IterT, SyntaxT>

{

    typedef detail::basic_rpattern_base_impl<IterT> impl;

 

    template< typename CharT >

    static void same_char_types( CharT, CharT ) {}

 

public:

    typedef typename basic_rpattern_base<IterT, SyntaxT>::syntax_type     syntax_type;

    typedef typename basic_rpattern_base<IterT, SyntaxT>::char_type       char_type;

    typedef typename basic_rpattern_base<IterT, SyntaxT>::traits_type     traits_type;

 

    typedef typename basic_rpattern_base<IterT, SyntaxT>::string_type     string_type;

    typedef typename basic_rpattern_base<IterT, SyntaxT>::size_type       size_type;

 

    typedef typename basic_rpattern_base<IterT, SyntaxT>::backref_type    backref_type;

    typedef typename basic_rpattern_base<IterT, SyntaxT>::backref_vector  backref_vector;

 

    basic_rpattern() //throw()

        : basic_rpattern_base<IterT, SyntaxT>()

    {

    }

 

    basic_rpattern( basic_rpattern const & that )

        : basic_rpattern_base<IterT, SyntaxT>( that )

    {

    }

 

    explicit basic_rpattern

    (

        string_type const & pat,

        REGEX_FLAGS flags = NOFLAGS,

        REGEX_MODE mode = MODE_DEFAULT

    )                                                   //throw( bad_regexpr, std::bad_alloc )

        : basic_rpattern_base<IterT, SyntaxT>( pat, flags, mode )

    {

    }

 

    basic_rpattern

    (

        string_type const & pat,

        string_type const & subst,

        REGEX_FLAGS flags = NOFLAGS,

        REGEX_MODE mode = MODE_DEFAULT

    )                                                   //throw( bad_regexpr, std::bad_alloc )

        : basic_rpattern_base<IterT, SyntaxT>( pat, subst, flags, mode )

    {

    }

 

    basic_rpattern & operator=( basic_rpattern<IterT, SyntaxT> const & that ) //throw( bad_regexpr, std::bad_alloc )

    {

        basic_rpattern_base<IterT, SyntaxT>::operator=( that );

        return *this;

    }

 

    // Iter2 must be convertible to type IterT

    template< typename OtherT, typename AllocT >

    backref_type const & match

    (

        OtherT ibegin,

        OtherT iend,

        basic_match_results<IterT, AllocT> & results

    ) const

    {

        // If your compile breaks here, it is because OtherT is not

        // convertible to type IterT. Check the declaration of your rpattern object.

        detail::static_assert< detail::is_convertible<OtherT,IterT>::value > const iterator_types_are_not_convertible;

        ( void ) iterator_types_are_not_convertible;

 

        if( detail::regex_access<IterT>::_do_match( *this, results, ibegin, iend, false ) )

        {

            return results.backref(0);

        }

        else

        {

            return detail::static_init<backref_type>::value;

        }

    }

 

    template< typename CharT, typename AllocT >

    backref_type const & match

    (

        CharT * szbegin,

        basic_match_results<IterT, AllocT> & results

    ) const

    {

        // If your compile breaks here, it is because CharT* is not

        // convertible to type IterT. Check the declaration of your rpattern object.

        detail::static_assert< detail::is_convertible<CharT*,IterT>::value > const iterator_types_are_not_convertible;

        ( void ) iterator_types_are_not_convertible;

 

        if( detail::regex_access<IterT>::_do_match_c( *this, results, szbegin ) )

        {

            return results.backref(0);

        }

        else

        {

            return detail::static_init<backref_type>::value;

        }

    }

 

    template< typename CharT, typename TraitsT, typename AllocT >

    backref_type const & match

    (

        std::basic_string<CharT, TraitsT, AllocT> const & str,

        basic_match_results<IterT, AllocT> & results,

        size_type pos = 0,

        size_type len = static_cast<size_type>(-1)

    ) const

    {

        // If your compile breaks here, it is because iter_type is not

        // convertible to type IterT. Check the declaration of your rpattern object.

        typedef typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator iter_type;

        detail::static_assert< detail::is_convertible<iter_type,IterT>::value > const iterator_types_are_not_convertible;

        ( void ) iterator_types_are_not_convertible;

 

        IterT ibegin = str.begin(), iend = str.begin();

 

        if( len == npos || pos + len >= str.size() )

            iend = IterT(str.end());

        else

            std::advance( iend, pos + len );

 

        std::advance( ibegin, pos );

        return match( ibegin, iend, results );

    }

 

    template< typename OtherT >

    size_t count( OtherT ibegin, OtherT iend ) const

    {

        // If your compile breaks here, it is because OtherT is not

        // convertible to type IterT. Check the declaration of your rpattern object.

        detail::static_assert< detail::is_convertible<OtherT,IterT>::value > const iterator_types_are_not_convertible;

        ( void ) iterator_types_are_not_convertible;

 

        return detail::regex_access<IterT>::_do_count( *this, ibegin, iend, false );

    }

 

    template< typename CharT >

    size_t count( CharT * szbegin ) const

    {

        // If your compile breaks here, it is because CharT* is not

        // convertible to type IterT. Check the declaration of your rpattern object.

        detail::static_assert< detail::is_convertible<CharT*,IterT>::value > const iterator_types_are_not_convertible;

        ( void ) iterator_types_are_not_convertible;

 

        return detail::regex_access<IterT>::_do_count( *this, szbegin, (CharT*)0, true );

    }

 

    template< typename CharT, typename TraitsT, typename AllocT >

    size_t count

    (

        std::basic_string<CharT, TraitsT, AllocT> const & str,

        size_type pos = 0,

        size_type len = static_cast<size_type>(-1)

    ) const

    {

        // If your compile breaks here, it is because iter_type is not

        // convertible to type IterT. Check the declaration of your rpattern object.

        typedef typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator iter_type;

        detail::static_assert< detail::is_convertible<iter_type,IterT>::value > const iterator_types_are_not_convertible;

        ( void ) iterator_types_are_not_convertible;

 

        IterT ibegin = str.begin(), iend = str.begin();

 

        if( len == npos || pos + len >= str.size() )

            iend = IterT(str.end());

        else

            std::advance( iend, pos + len );

 

        std::advance( ibegin, pos );

        return count( ibegin, iend );

    }

 

    template< typename OtherT, typename CharT, typename TraitsT, typename AllocT >

    size_t split

    (

        OtherT ibegin,

        OtherT iend,

        basic_split_results<CharT, TraitsT, AllocT> & results,

        int limit = 0

    ) const

    {

        // If your compile breaks here, it is because OtherT is not

        // convertible to type IterT. Check the declaration of your rpattern object.

        detail::static_assert< detail::is_convertible<OtherT,IterT>::value > const iterator_types_are_not_convertible;

        ( void ) iterator_types_are_not_convertible;

 

        return detail::regex_access<IterT>::_do_split( *this, results, ibegin, iend, limit, false );

    }

 

    template< typename Char1T, typename Char2T, typename TraitsT, typename AllocT >

    size_t split

    (

        Char1T * szbegin,

        basic_split_results<Char2T, TraitsT, AllocT> & results,

        int limit = 0

    ) const

    {

        // If your compile breaks here, it is because Iter2 is not

        // convertible to type IterT. Check the declaration of your rpattern object.

        detail::static_assert< detail::is_convertible<Char1T*,IterT>::value > const iterator_types_are_not_convertible;

        ( void ) iterator_types_are_not_convertible;

 

        // If your compile breaks here, it's because the string you passed in doesn't have

        // the same character type as your split_results struct

        same_char_types( Char1T(), Char2T() );

 

        // If your compile breaks here, it is because CharT const * is not

        // convertible to type IterT. Check the declaration of your rpattern object.

        return detail::regex_access<IterT>::_do_split( *this, results, szbegin, (Char1T*)0, limit, true );

    }

 

    template< typename CharT, typename TraitsT, typename AllocT >

    size_t split

    (

        std::basic_string<CharT, TraitsT, AllocT> const & str,

        basic_split_results<CharT, TraitsT, AllocT> & results,

        int limit = 0,

        size_type pos = 0,

        size_type len = static_cast<size_type>(-1)

    ) const

    {

        // If your compile breaks here, it is because iter_type is not

        // convertible to type IterT. Check the declaration of your rpattern object.

        typedef typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator iter_type;

        detail::static_assert< detail::is_convertible<iter_type,IterT>::value > const iterator_types_are_not_convertible;

        ( void ) iterator_types_are_not_convertible;

 

        IterT ibegin = str.begin(), iend = str.begin();

 

        if( len == npos || pos + len >= str.size() )

            iend = IterT(str.end());

        else

            std::advance( iend, pos + len );

 

        std::advance( ibegin, pos );

        return split( ibegin, iend, results, limit );

    }

 

    template< typename CharT, typename TraitsT, typename AllocT >

    size_t substitute

    (

        std::basic_string<CharT, TraitsT, AllocT> & str,

        basic_subst_results<CharT, TraitsT, AllocT> & results,

        size_type pos = 0,

        size_type len = static_cast<size_type>(-1)

    ) const

    {

        // If your compile breaks here, it is because iter_type is not

        // convertible to type IterT. Check the declaration of your rpattern object.

        typedef typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator iter_type;

        detail::static_assert< detail::is_convertible<iter_type,IterT>::value > const iterator_types_are_not_convertible;

        ( void ) iterator_types_are_not_convertible;

 

        return detail::regex_access<IterT>::_do_subst( *this, str, results, pos, len );

    }

};

 

// --------------------------------------------------------------------------

//

// Class:       basic_rpattern_c

//

// Description: a pattern object optimized for matching C-style, NULL-

//              terminated strings. It treats the null-terminator as

//              the end-of-string condition.

//

// Methods:     basic_rpattern_c - c'tor

//              basic_rpattern_c -

//              basic_rpattern_c -

//              match            - match a null-terminated string

//              count            - count matches in a null-terminated string

//              _do_match_c      - internal implementation

//

// History:     8/13/2001 - ericne - Created

//

// --------------------------------------------------------------------------

template< typename CharT, typename SyntaxT = perl_syntax<CharT> >

class basic_rpattern_c : public basic_rpattern_base<CharT const *, SyntaxT>

{

    typedef detail::basic_rpattern_base_impl<CharT const *> impl;

public:

    typedef typename basic_rpattern_base<CharT const *, SyntaxT>::syntax_type     syntax_type;

    typedef typename basic_rpattern_base<CharT const *, SyntaxT>::char_type       char_type;

    typedef typename basic_rpattern_base<CharT const *, SyntaxT>::traits_type     traits_type;

 

    typedef typename basic_rpattern_base<CharT const *, SyntaxT>::string_type     string_type;

    typedef typename basic_rpattern_base<CharT const *, SyntaxT>::size_type       size_type;

 

    typedef typename basic_rpattern_base<CharT const *, SyntaxT>::backref_type    backref_type;

    typedef typename basic_rpattern_base<CharT const *, SyntaxT>::backref_vector  backref_vector;

 

    basic_rpattern_c() //throw()

        : basic_rpattern_base<CharT const *, SyntaxT>()

    {

    }

 

    basic_rpattern_c( basic_rpattern_c const & that )

        : basic_rpattern_base<CharT const *, SyntaxT>( that )

    {

    }

 

    explicit basic_rpattern_c

    (

        string_type const & pat,

        REGEX_FLAGS flags = NOFLAGS,

        REGEX_MODE mode = MODE_DEFAULT

    )                                                           //throw( bad_regexpr, std::bad_alloc )

        : basic_rpattern_base<CharT const *, SyntaxT>( pat, flags, mode )

    {

    }

 

    basic_rpattern_c & operator=( basic_rpattern_c<CharT, SyntaxT> const & that )

    {

        basic_rpattern_base<CharT const *, SyntaxT>::operator=( that );

        return *this;

    }

 

    template< typename AllocT >

    backref_type const & match

    (

        CharT const * szbegin,

        basic_match_results_c<CharT, AllocT> & results

    ) const

    {

        if( detail::regex_access<CharT const*>::_do_match_c( *this, results, szbegin ) )

        {

            return results.backref(0);

        }

        else

        {

            return detail::static_init<backref_type>::value;

        }

    }

 

    size_t count( CharT const * szbegin ) const

    {

        return detail::regex_access<CharT const*>::_do_count( *this, szbegin, (CharT const*)0, true );

    }

};

 

 

 

#if defined(UNICODE) | defined(_UNICODE)

typedef wchar_t rechar_t;

#else

typedef char    rechar_t;

#endif

 

typedef std::basic_string<rechar_t> restring;

 

// On many implementations of the STL, string::iterator is not a typedef

// for char*. Rather, it is a wrapper class. As a result, the regex code

// gets instantiated twice, once for bare pointers (rpattern_c) and once for

// the wrapped pointers (rpattern). But if there is a conversion from the

// bare ptr to the wrapped ptr, then we only need to instantiate the template

// for the wrapped ptr, and the code will work for the bare ptrs, too.

// This can be a significant space savings.  The REGEX_FOLD_INSTANTIONS

// macro controls this optimization. The default is "off" for backwards

// compatibility. To turn the optimization on, compile with:

// -DREGEX_FOLD_INSTANTIATIONS=1

#ifndef REGEX_FOLD_INSTANTIATIONS

#define REGEX_FOLD_INSTANTIATIONS 0

#endif

 

typedef ::regex::detail::select

<

    REGEX_FOLD_INSTANTIATIONS &&

        detail::is_convertible<rechar_t const *,restring::const_iterator>::value,

    restring::const_iterator,

    rechar_t const *

>::type lpctstr_t;

 

// For matching against null-terminated strings

typedef basic_rpattern<lpctstr_t, perl_syntax<rechar_t> >  perl_rpattern_c;

typedef basic_rpattern<lpctstr_t, posix_syntax<rechar_t> > posix_rpattern_c;

 

// For matching against std::strings

typedef basic_rpattern<restring::const_iterator, perl_syntax<rechar_t> >  perl_rpattern;

typedef basic_rpattern<restring::const_iterator, posix_syntax<rechar_t> > posix_rpattern;

 

// Default to perl syntax

typedef perl_rpattern    rpattern;

typedef perl_rpattern_c  rpattern_c;

 

// typedefs for the commonly used match_results and subst_results

typedef basic_match_results<restring::const_iterator> match_results;

typedef basic_match_results<lpctstr_t>                match_results_c;

typedef basic_subst_results<rechar_t>                 subst_results;

typedef basic_split_results<rechar_t>                 split_results;

 

#if defined(_MSC_VER) & 1200 < _MSC_VER

// These are no longer useful, and will go away in a future release

// You should be using the version without the _c

# pragma deprecated( basic_rpattern_c )

# pragma deprecated( basic_match_results_c )

#endif

 

#define STATIC_RPATTERN_EX( type, var, params ) /

    static type const var params;

 

#define STATIC_RPATTERN( var, params ) /

    STATIC_RPATTERN_EX( regex::rpattern, var, params )

 

#define STATIC_RPATTERN_C( var, params ) /

    STATIC_RPATTERN_EX( regex::rpattern_c, var, params )

 

#if defined(_MSC_VER) & 1200 < _MSC_VER

#pragma deprecated(STATIC_RPATTERN_EX)

#endif

 

//

// ostream inserter operator for back-references

//

template< typename CharT, typename TraitsT, typename IterT >

inline std::basic_ostream<CharT, TraitsT> & operator<<

(

    std::basic_ostream<CharT, TraitsT> & sout,

    backref_tag<IterT> const & br

)

{

    return br.print( sout );

}

 

} // namespace regex

 

 

//

// specializations for std::swap

//

namespace std

{

    template<>

    inline void swap( regex::detail::regex_arena & left, regex::detail::regex_arena & right )

    {

        left.swap( right );

    }

 

    template< typename IterT, typename SyntaxT >

    inline void swap( regex::basic_rpattern_base<IterT, SyntaxT> & left, regex::basic_rpattern_base<IterT, SyntaxT> & right )

    {

        left.swap( right );

    }

}

 

#ifdef _MSC_VER

#pragma warning( pop )

#endif

 

#endif

//+---------------------------------------------------------------------------

//

//  Copyright ( C ) Microsoft, 1994 - 2002.

//

//  File:       regexpr2.cpp

//

//  Contents:   implementation for rpattern methods, definitions for all the

//              subexpression types used to perform the matching, the

//              charset class definition .

//

//  Classes:    too many to list here

//

//  Functions:

//

//  Author:     Eric Niebler ( [email protected] )

//

//  History:    12-11-1998   ericne   Created

//              01-05-2001   ericne   Removed dependency on VC's choice

//                                    of STL iterator types.

//              08-15-2001   ericne   Removed regexpr class, moved match

//                                    state to match_results container.

//              09-17-2001   nathann  Add DEBUG_HEAP_SUPPORT

//              11-16-2001   ericne   Add stack-conservative algorithm

//

//----------------------------------------------------------------------------

 

#ifdef _MSC_VER

// unlimited inline expansion ( compile with /Ob1 or /Ob2 )

# pragma inline_recursion( on )

# pragma inline_depth( 255 )

// warning C4127: conditional expression is constant

// warning C4355: 'this' : used in base member initializer list

// warning C4702: unreachable code

// warning C4710: function 'blah' not inlined

// warning C4786: identifier was truncated to '255' characters in the debug information

# pragma warning( push )

# pragma warning( disable : 4127 4355 4702 4710 4786 )

#endif

 

#include <limits>

#include <cctype>

#include <cwchar>

#include <memory>

#include <cwctype>

#include <malloc.h>

#include <algorithm>

 

#ifdef __MWERKS__

# include <alloca.h>

#endif

 

// If the implementation file has been included in the header, then we

// need to mark some functions as inline to prevent them from being multiply

// defined.  But if the implementation file is not included in the header,

// we can't mark them as inline, otherwise the linker won't find them.

#ifdef REGEXPR_H

# define REGEXPR_H_INLINE inline

#else

# define REGEXPR_H_INLINE

# include "regexpr2.h"

#endif

 

#ifdef REGEX_TO_INCLUDE

# include REGEX_TO_INCLUDE

#endif

 

// $PORT$

// _alloca is not standard

#ifndef alloca

# define alloca _alloca

#endif

 

namespace regex

{

 

namespace detail

{

 

inline wctype_t REGEX_CDECL regex_wctype( char const * sz )

{

    using namespace std;

    return wctype( sz );

}

 

namespace

{

 

#ifdef __GLIBC__

struct regex_ctype_t

{

    int      m_ctype;

    wctype_t m_wctype;

};

 

#define REGEX_DECL_CTYPE(desc)                                                  /

    inline regex_ctype_t const & wct_ ## desc()                                 /

    {                                                                           /

        static regex_ctype_t const s_wct = { _IS ## desc, regex_wctype(#desc) };/

        return s_wct;                                                           /

    }

 

REGEX_DECL_CTYPE(alnum)

REGEX_DECL_CTYPE(alpha)

REGEX_DECL_CTYPE(blank)

REGEX_DECL_CTYPE(cntrl)

REGEX_DECL_CTYPE(digit)

REGEX_DECL_CTYPE(graph)

REGEX_DECL_CTYPE(lower)

REGEX_DECL_CTYPE(print)

REGEX_DECL_CTYPE(punct)

REGEX_DECL_CTYPE(space)

REGEX_DECL_CTYPE(upper)

REGEX_DECL_CTYPE(xdigit)

regex_ctype_t const wct_zero = { 0,  0 };

 

inline regex_ctype_t & operator |= ( regex_ctype_t & lhs, regex_ctype_t const & rhs )

{

    lhs.m_ctype  |= rhs.m_ctype;

    lhs.m_wctype |= rhs.m_wctype;

    return lhs;

}

inline regex_ctype_t operator | ( regex_ctype_t lhs, regex_ctype_t const & rhs )

{

    return lhs |= rhs;

}

inline int REGEX_CDECL regex_isctype( int ch, regex_ctype_t const & desc )

{

    return __isctype( ch, desc.m_ctype );

}

inline int REGEX_CDECL regex_iswctype( wint_t wc, regex_ctype_t desc )

{

    using namespace std;

    return iswctype( wc, desc.m_wctype );

}

inline bool operator == ( regex_ctype_t const & lhs, regex_ctype_t const & rhs )

{

    return lhs.m_ctype == rhs.m_ctype && lhs.m_wctype == rhs.m_wctype;

}

inline bool operator != ( regex_ctype_t const & lhs, regex_ctype_t const & rhs )

{

    return lhs.m_ctype != rhs.m_ctype || lhs.m_wctype != rhs.m_wctype;

}

#else

typedef wctype_t regex_ctype_t;

 

#define REGEX_DECL_CTYPE(desc)                                                   /

    inline regex_ctype_t const wct_ ## desc()                                    /

    {                                                                            /

        static regex_ctype_t const s_wct = regex_wctype(#desc);                  /

        return s_wct;                                                            /

    }

 

REGEX_DECL_CTYPE(alnum)

REGEX_DECL_CTYPE(alpha)

REGEX_DECL_CTYPE(cntrl)

REGEX_DECL_CTYPE(digit)

REGEX_DECL_CTYPE(graph)

REGEX_DECL_CTYPE(lower)

REGEX_DECL_CTYPE(print)

REGEX_DECL_CTYPE(punct)

REGEX_DECL_CTYPE(space)

REGEX_DECL_CTYPE(upper)

REGEX_DECL_CTYPE(xdigit)

regex_ctype_t const wct_zero    = 0;

 

#if defined(_MSC_VER) & ( _MSC_VER==1200 | defined(_CPPLIB_VER) )

inline regex_ctype_t const wct_blank() { return _BLANK; } // work around for bug in VC++

inline int REGEX_CDECL regex_isctype( int ch, regex_ctype_t desc )

{

    return _isctype( ch, static_cast<int>( desc ) );

}

#else

REGEX_DECL_CTYPE(blank)

inline int REGEX_CDECL regex_isctype( int ch, regex_ctype_t desc )

{

    using namespace std;

    return iswctype( btowc( ch ), desc );

}

#endif

inline int REGEX_CDECL regex_iswctype( wint_t wc, regex_ctype_t desc )

{

    using namespace std;

    return iswctype( wc, desc );

}

#endif

} // unnamed namespace

 

template< typename CStringsT, typename IterT >

bool _do_match_iterative( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur, CStringsT );

 

// NathanN:

// By defining the symbol REGEX_DEBUG_HEAP the allocator object

// no longer sub allocates memory.  This enables heap checking tools like

// AppVerifier & PageHeap to find errors like buffer overruns

#if !defined( REGEX_DEBUG_HEAP ) & REGEX_DEBUG

# define REGEX_DEBUG_HEAP 1

#else

# define REGEX_DEBUG_HEAP 0

#endif

 

REGEXPR_H_INLINE size_t DEFAULT_BLOCK_SIZE()

{

#if REGEX_DEBUG_HEAP

    // put each allocation in its own mem_block

    return 1;

#else

    // put multiple allocation in each mem_block

    return 352;

#endif

}

 

template< typename IBeginT, typename IEndT >

inline size_t parse_int( IBeginT & ibegin, IEndT iend, size_t const max_ = size_t( -1 ) )

{

    typedef typename std::iterator_traits<IEndT>::value_type char_type;

    size_t retval = 0;

    while( iend != ibegin && REGEX_CHAR(char_type,'0') <= *ibegin && REGEX_CHAR(char_type,'9') >= *ibegin && max_ > retval )

    {

        retval *= 10;

        retval += static_cast<size_t>( *ibegin - REGEX_CHAR(char_type,'0') );

        ++ibegin;

    }

    if( max_ < retval )

    {

        retval /= 10;

        --ibegin;

    }

    return retval;

}

 

// --------------------------------------------------------------------------

//

// Class:       boyer_moore

//

// Description: fast sub-string search algorithm

//

// Members:     m_begin - iter to first char in pattern sequence

//              m_last  - iter to last char in pattern sequence

//              m_len   - length of the pattern sequence

//              m_off   - array of offsets, indexed by ASCII char values

//

// History:     6/8/2003 - ericne - Created

//

// --------------------------------------------------------------------------

template< typename IterT >

class boyer_moore

{

    typedef typename std::iterator_traits<IterT>::value_type    char_type;

    typedef typename std::char_traits<char_type>                traits_type;

 

    enum { OFFSET_SIZE = UCHAR_MAX + 1 };

 

    IterT               m_begin;

    IterT               m_last;

    char_type const*    m_low_last;

    unsigned char       m_len;

    unsigned char       m_off[ OFFSET_SIZE ];

 

    static unsigned char hash_char( char ch )           { return static_cast<unsigned char>( ch ); }

    static unsigned char hash_char( signed char ch )    { return static_cast<unsigned char>( ch ); }

    static unsigned char hash_char( unsigned char ch )  { return ch; }

    static unsigned char hash_char( wchar_t ch )        { return static_cast<unsigned char>( ch % OFFSET_SIZE ); }

    template< typename  CharT >

    static unsigned char REGEX_VC6(REGEX_CDECL) hash_char( CharT ch REGEX_VC6(...) )

    {

        return static_cast<unsigned char>( std::char_traits<CharT>::to_int_type( ch ) % OFFSET_SIZE );

    }

 

    // case-sensitive Boyer-Moore search

    template< typename OtherT >

    OtherT find_with_case( OtherT begin, OtherT end ) const

    {

        typedef typename std::iterator_traits<OtherT>::difference_type diff_type;

        diff_type const endpos = std::distance( begin, end );

        diff_type offset = m_len;

 

        for( diff_type curpos = offset; curpos < endpos; curpos += offset )

        {

            std::advance( begin, offset );

 

            IterT  pat_tmp = m_last;

            OtherT str_tmp = begin;

 

            for( ; traits_type::eq( *str_tmp, *pat_tmp );

                --pat_tmp, --str_tmp )

            {

                if( pat_tmp == m_begin )

                {

                    return str_tmp;

                }

            }

 

            offset = m_off[ hash_char( *begin ) ];

        }

 

        return end;

    }

 

    // case-insensitive Boyer-Moore search

    template< typename OtherT >

    OtherT find_without_case( OtherT begin, OtherT end ) const

    {

        typedef typename std::iterator_traits<OtherT>::difference_type diff_type;

        diff_type const endpos = std::distance( begin, end );

        diff_type offset = m_len;

 

        for( diff_type curpos = offset; curpos < endpos; curpos += offset )

        {

            std::advance( begin, offset );

 

            IterT               pat_tmp  = m_last;

            char_type const*    low_tmp  = m_low_last;

            OtherT              str_tmp  = begin;

 

            for( ; traits_type::eq( *str_tmp, *pat_tmp ) || traits_type::eq( *str_tmp, *low_tmp );

                --pat_tmp, --str_tmp, --low_tmp )

            {

                if( pat_tmp == m_begin )

                {

                    return str_tmp;

                }

            }

 

            offset = m_off[ hash_char( *begin ) ];

        }

 

        return end;

    }

 

public:

    // initialize the Boyer-Moore search data structure, using the

    // search sub-sequence to prime the pump.

    boyer_moore( IterT begin, IterT end, char_type const* lower = 0 )

        : m_begin( begin )

        , m_last( begin )

        , m_low_last( lower )

    {

        typedef typename std::iterator_traits<IterT>::difference_type diff_type;

        diff_type diff = std::distance( begin, end );

        m_len  = static_cast<unsigned char>( regex_min<diff_type>( diff, UCHAR_MAX ) );

        std::fill_n( m_off, ARRAYSIZE( m_off ), m_len );

        --m_len;

 

        for( unsigned char offset = m_len; offset; --offset, ++m_last )

        {

            m_off[ hash_char( *m_last ) ] = offset;

        }

 

        if( m_low_last )

        {

            for( unsigned char offset = m_len; offset; --offset, ++m_low_last )

            {

                unsigned char hash = hash_char( *m_low_last );

                m_off[ hash ] = regex_min( m_off[ hash ], offset );

            }

        }

    }

 

    template< typename OtherT >

    OtherT find( OtherT begin, OtherT end ) const

    {

        if( m_low_last )

        {

            return find_without_case( begin, end );

        }

        else

        {

            return find_with_case( begin, end );

        }

    }

 

    static void * operator new( size_t size, regex_arena & arena )

    {

        return arena.allocate( size );

    }

    static void operator delete( void *, regex_arena & )

    {

    }

};

 

// This class is used to speed up character set matching by providing

// a bitset that spans the ASCII range. std::bitset is not used because

// the range-checking slows it down.

// Note: The division and modulus operations are optimized by the compiler

// into bit-shift operations.

class ascii_bitvector

{

    typedef unsigned int elem_type;

 

    enum

    {

        CBELEM = CHAR_BIT * sizeof( elem_type ), // count of bits per element

        CELEMS = ( UCHAR_MAX+1 ) / CBELEM        // number of element in array

    };

 

    elem_type m_rg[ CELEMS ];

 

    // Used to inline operations like: bv1 |= ~bv2; without creating temp bit vectors.

    struct not_ascii_bitvector

    {

        ascii_bitvector const & m_ref;

        not_ascii_bitvector( ascii_bitvector const & ref )

            : m_ref( ref ) {}

    private:

        not_ascii_bitvector & operator=( not_ascii_bitvector const & );

    };

 

    ascii_bitvector( ascii_bitvector const & );

    ascii_bitvector & operator=( ascii_bitvector const & );

public:

    ascii_bitvector()

    {

        zero();

    }

    void zero()

    {

        std::fill_n( m_rg, ARRAYSIZE( m_rg ), 0 );

    }

    void set( unsigned char ch )

    {

        m_rg[ ( ch / CBELEM ) ] |= ( ( elem_type )1U << ( ch % CBELEM ) );

    }

    bool operator[]( unsigned char ch ) const

    {

        return 0 != ( m_rg[ ( ch / CBELEM ) ] & ( ( elem_type )1U << ( ch % CBELEM ) ) );

    }

    not_ascii_bitvector const operator~() const

    {

        return not_ascii_bitvector( *this );

    }

    ascii_bitvector & operator|=( ascii_bitvector const & that )

    {

        for( int i=0; i<CELEMS; ++i )

            m_rg[ i ] |= that.m_rg[ i ];

        return *this;

    }

    ascii_bitvector & operator|=( not_ascii_bitvector const & that )

    {

        for( int i=0; i<CELEMS; ++i )

            m_rg[ i ] |= ~that.m_ref.m_rg[ i ];

        return *this;

    }

};

 

typedef std::pair<wchar_t, wchar_t> range_type;

 

// determines if one range is less then another.

// used in binary search of range vector

struct range_less

{

    bool operator()( range_type const & rg1, range_type const & rg2 ) const

    {

        return rg1.second < rg2.first;

    }

};

 

// A singly-linked list, which works even if the allocator

// has per-instance state.

template< typename T, typename AllocT=std::allocator<T> >

class slist

{

    struct cons

    {

        T      car;

        cons * cdr;

 

        cons( T const & t, cons * nxt )

            : car( t )

            , cdr( nxt )

        {

        }

    };

 

    typedef typename rebind<AllocT, cons>::type cons_allocator;

    typedef typename rebind<AllocT, char>::type char_allocator;

 

#if !defined(_MSC_VER) | 1200 < _MCS_VER

    // Use the empty base optimization to avoid reserving

    // space for the allocator if it is empty.

    struct slist_impl : cons_allocator

    {

        cons * m_lst;

 

        slist_impl( cons_allocator const & alloc, cons *lst )

            : cons_allocator( alloc )

            , m_lst( lst )

        {

        }

        cons_allocator & allocator()

        {

            return *this;

        }

    };

#else

    struct slist_impl

    {

cons_allocator m_alloc;

        cons   *m_lst;

 

        slist_impl( cons_allocator const & alloc, cons *lst )

            : m_alloc( alloc )

            , m_lst( lst )

        {

        }

        cons_allocator & allocator()

        {

            return m_alloc;

        }

    };

#endif

 

    slist_impl m_impl;

 

    // find the previous node in the list (*prev(lst)==lst)

    cons ** prev( cons *lst, cons *hint = 0 )

    {

        if( m_impl.m_lst == lst )

            return &m_impl.m_lst;

        if( !hint || hint->cdr != lst )

            for( hint=m_impl.m_lst; hint->cdr != lst; hint=hint->cdr )

                {}

        return &hint->cdr;

    }

public:

    typedef T           value_type;

    typedef T*          pointer;

    typedef T&          reference;

    typedef T const*    const_pointer;

    typedef T const&    const_reference;

    typedef size_t      size_type;

 

    struct iterator : public std::iterator<std::forward_iterator_tag, T>

    {

        friend class slist<T,AllocT>;

        explicit iterator( cons * pcons = 0 )

            : m_pcons( pcons )

        {

        }

        T & operator*() const

        {

            return m_pcons->car;

        }

        T * operator->() const

        {

            return &m_pcons->car;

        }

        iterator & operator++()

        {

            m_pcons = m_pcons->cdr;

            return *this;

        }

        iterator operator++( int )

        {

            iterator i( *this );

            ++*this;

            return i;

        }

        bool operator==( iterator it )

        {

            return m_pcons == it.m_pcons;

        }

        bool operator!=( iterator it )

        {

            return m_pcons != it.m_pcons;

        }

    private:

        cons * m_pcons;

    };

 

    // not ideal, but good enough for gov'ment work....

    typedef iterator const_iterator;

 

    explicit slist( char_allocator const & al = char_allocator() )

        : m_impl( convert_allocator<cons>( al, 0 ), 0 )

    {

    }

    ~slist()

    {

        clear();

    }

    void clear()

    {

        for( cons *nxt; m_impl.m_lst; m_impl.m_lst=nxt )

        {

            nxt = m_impl.m_lst->cdr;

            m_impl.allocator().destroy( m_impl.m_lst );

            m_impl.allocator().deallocate( m_impl.m_lst, 1 );

        }

    }

    void push_front( T const & t )

    {

        cons * lst = m_impl.allocator().allocate( 1, 0 );

        try

        {

            m_impl.allocator().construct( lst, cons( t, m_impl.m_lst ) );

        }

        catch(...)

        {

            m_impl.allocator().deallocate( lst, 1 );

            throw;

        }

        m_impl.m_lst = lst;

    }

    template< typename PredT >

    void sort( PredT pred )

    {

        // simple insertion sort

        cons *rst=m_impl.m_lst;

        m_impl.m_lst = 0;

        while( rst )

        {

            cons *cur=m_impl.m_lst, *prv=0;

            while( cur && ! pred( rst->car, cur->car ) )

                prv=cur, cur=cur->cdr;

            if( prv )

                prv->cdr=rst, rst=rst->cdr, prv->cdr->cdr=cur;

            else

                m_impl.m_lst=rst, rst=rst->cdr, m_impl.m_lst->cdr=cur;

        }

    }

    void sort()

    {

        this->sort( std::less<T>() );

    }

    iterator begin() const

    {

        return iterator( m_impl.m_lst );

    }

    iterator end() const

    {

        return iterator();

    }

    bool empty() const

    {

        return 0 == m_impl.m_lst;

    }

    size_t size() const

    {

        size_t len=0;

        for( cons *lst=m_impl.m_lst; lst; lst=lst->cdr, ++len )

            {}

        return len;

    }

    iterator erase( iterator it, iterator hint = iterator() )

    {

        cons **prv = prev( it.m_pcons, hint.m_pcons ); // *prv==it.p

        *prv = it.m_pcons->cdr;

        m_impl.allocator().destroy( it.m_pcons );

        m_impl.allocator().deallocate( it.m_pcons, 1 );

        return iterator( *prv );

    }

    void reverse()

    {

        cons *prv=0, *nxt;

        while( m_impl.m_lst )

            nxt = m_impl.m_lst->cdr, m_impl.m_lst->cdr = prv, prv = m_impl.m_lst, m_impl.m_lst = nxt;

        m_impl.m_lst = prv;

    }

};

 

template< typename AllocT >

struct basic_charset;

 

template< typename CharT >

struct posixcharsoff_pred

{

    CharT m_ch;

    posixcharsoff_pred( CharT ch )

        : m_ch( ch )

    {

    }

    bool operator()( regex_ctype_t desc ) const

    {

        return ! local_isctype( m_ch, desc );

    }

    static int local_isctype( char ch, regex_ctype_t desc )

    {

        return regex_isctype( ch, desc );

    }

    static int local_isctype( wchar_t ch, regex_ctype_t desc )

    {

        return regex_iswctype( ch, desc );

    }

};

 

template< typename CharT, bool CaseT >

struct in_charset_pred

{

    CharT m_ch;

    in_charset_pred( CharT ch )

        : m_ch( ch )

    {

    }

    template< typename AllocT >

    bool operator()( basic_charset<AllocT> const * pcs ) const

    {

        REGEX_VC6( return pcs->in( m_ch COMMA bool2type<CaseT>() ); )

        REGEX_NVC6( return pcs->template in<CaseT>( m_ch ); )

    }

};

 

template< typename AllocT >

struct basic_charset

{

    typedef basic_charset<std::allocator<char> >    other_type;

    typedef slist<range_type,std::allocator<char> > other_ranges_type;

 

    typedef slist<range_type,AllocT>                ranges_type;

    typedef slist<regex_ctype_t,AllocT>             posixcharsoff_type;

    typedef slist<other_type const*,AllocT>         nestedcharsets_type;

 

    typedef typename rebind<AllocT, char>::type     char_allocator_type;

 

    bool                m_fcompliment;

    bool                m_fskip_extended_check;

    ascii_bitvector     m_ascii_bitvector;

    regex_ctype_t       m_posixcharson;

    ranges_type         m_ranges;

    posixcharsoff_type  m_posixcharsoff;

    nestedcharsets_type m_nestedcharsets;

 

    explicit basic_charset( char_allocator_type const & al = char_allocator_type() )

        : m_fcompliment( false )

        , m_fskip_extended_check( false )

        , m_ascii_bitvector()

        , m_posixcharson( wct_zero )

        , m_ranges( al )

        , m_posixcharsoff( al )

        , m_nestedcharsets( al )

    {

    }

 

    // We'll be inheriting from this, so a virtual d'tor is regretably necessary.

    virtual ~basic_charset()

    {

    }

 

    void clear()

    {

        m_fcompliment = false;

        m_fskip_extended_check = false;

        m_ascii_bitvector.zero();

        m_posixcharson = wct_zero;

        m_ranges.clear();

        m_posixcharsoff.clear();

        m_nestedcharsets.clear();

    }

 

    // merge one charset into another

    basic_charset & operator|=( other_type const & that )

    {

        if( that.m_fcompliment )

        {

            // If no posix-style character sets are used, then we can merge this

            // nested character set directly into the enclosing character set.

            if( wct_zero == that.m_posixcharson &&

                that.m_posixcharsoff.empty() &&

                that.m_nestedcharsets.empty() )

            {

                m_ascii_bitvector |= ~ that.m_ascii_bitvector;

 

                // append the inverse of that.m_ranges to this->m_ranges

                wchar_t chlow = UCHAR_MAX;

                typedef typename other_ranges_type::const_iterator iter_type;

                for( iter_type prg = that.m_ranges.begin(); that.m_ranges.end() != prg; ++prg )

                {

                    if( UCHAR_MAX + 1 != prg->first )

                        m_ranges.push_front( range_type( wchar_t( chlow+1 ), wchar_t( prg->first-1 ) ) );

                    chlow = prg->second;

                }

                if( WCHAR_MAX != chlow )

                    m_ranges.push_front( range_type( wchar_t( chlow+1 ), WCHAR_MAX ) );

            }

            else

            {

                // There is no simple way to merge this nested character

                // set into the enclosing character set, so we must save

                // a pointer to the nested character set in a list.

                m_nestedcharsets.push_front( &that );

            }

        }

        else

        {

            m_ascii_bitvector |= that.m_ascii_bitvector;

            std::copy( that.m_ranges.begin(),

                       that.m_ranges.end(),

                       std::front_inserter( m_ranges ) );

 

            m_posixcharson |= that.m_posixcharson;

            std::copy( that.m_posixcharsoff.begin(),

                       that.m_posixcharsoff.end(),

                       std::front_inserter( m_posixcharsoff ) );

 

            std::copy( that.m_nestedcharsets.begin(),

                       that.m_nestedcharsets.end(),

                       std::front_inserter( m_nestedcharsets ) );

        }

        return *this;

    }

 

    // Note overloading based on first parameter

    void set_bit( char ch, bool const fnocase )

    {

        if( fnocase )

        {

            m_ascii_bitvector.set( static_cast<unsigned char>( regex_tolower( ch ) ) );

            m_ascii_bitvector.set( static_cast<unsigned char>( regex_toupper( ch ) ) );

        }

        else

        {

            m_ascii_bitvector.set( static_cast<unsigned char>( ch ) );

        }

    }

 

    // Note overloading based on first parameter

    void set_bit( wchar_t ch, bool const fnocase )

    {

        if( UCHAR_MAX >= ch )

            set_bit( static_cast<char>( ch ), fnocase );

        else

            m_ranges.push_front( range_type( ch, ch ) );

    }

 

    // Note overloading based on first two parameters

    void set_bit_range( char ch1, char ch2, bool const fnocase )

    {

        if( static_cast<unsigned char>( ch1 ) > static_cast<unsigned char>( ch2 ) )

            throw bad_regexpr( "invalid range specified in character set" );

 

        if( fnocase )

        {

            // i is unsigned int to prevent overflow if ch2 is UCHAR_MAX

            for( unsigned int i = static_cast<unsigned char>( ch1 );

                 i <= static_cast<unsigned char>( ch2 ); ++i )

            {

                m_ascii_bitvector.set( static_cast<unsigned char>( regex_toupper( (char) i ) ) );

                m_ascii_bitvector.set( static_cast<unsigned char>( regex_tolower( (char) i ) ) );

            }

        }

        else

        {

            // i is unsigned int to prevent overflow if ch2 is UCHAR_MAX

            for( unsigned int i = static_cast<unsigned char>( ch1 );

                 i <= static_cast<unsigned char>( ch2 ); ++i )

            {

                m_ascii_bitvector.set( static_cast<unsigned char>( i ) );

            }

        }

    }

 

    // Note overloading based on first two parameters

    void set_bit_range( wchar_t ch1, wchar_t ch2, bool const fnocase )

    {

        if( ch1 > ch2 )

            throw bad_regexpr( "invalid range specified in character set" );

 

        if( UCHAR_MAX >= ch1 )

            set_bit_range( static_cast<char>( ch1 ), static_cast<char>( regex_min<wchar_t>( UCHAR_MAX, ch2 ) ), fnocase );

 

        if( UCHAR_MAX < ch2 )

            m_ranges.push_front( range_type( regex_max( static_cast<wchar_t>( UCHAR_MAX + 1 ), ch1 ), ch2 ) );

    }

 

    void optimize( type2type<wchar_t> )

    {

        if( m_ranges.begin() != m_ranges.end() )

        {

            // this sorts on range_type.m_pfirst ( uses operator<() for pair templates )

            m_ranges.sort();

 

            // merge ranges that overlap

            typename ranges_type::iterator icur=m_ranges.begin(), iprev=icur++;

            while( icur != m_ranges.end() )

            {

                if( icur->first <= iprev->second + 1 )

                {

                    iprev->second = regex_max( iprev->second, icur->second );

                    icur = m_ranges.erase( icur, iprev );

                }

                else

                {

                    iprev=icur++;

                }

            }

        }

 

        // For the ASCII range, merge the m_posixcharson info

        // into the ascii_bitvector

        if( wct_zero != m_posixcharson )

        {

            // BUGBUG this is kind of expensive. Think of a better way.

            for( unsigned int i=0; i<=UCHAR_MAX; ++i )

                if( regex_isctype( i, m_posixcharson ) )

                    m_ascii_bitvector.set( static_cast<unsigned char>( i ) );

        }

 

        // m_fskip_extended_check is a cache which tells us whether we

        // need to check the m_posixcharsoff and m_nestedcharsets vectors,

        // which would only be used in nested user-defined character sets

        m_fskip_extended_check = m_posixcharsoff.empty() && m_nestedcharsets.empty();

    }

 

    void optimize( type2type<char> )

    {

        optimize( type2type<wchar_t>() );

 

        // the posixcharson info was merged into the ascii bitvector,

        // so we don't need to ever call regex_isctype ever again.

        m_posixcharson = wct_zero;

    }

 

    template< bool CaseT, typename CharT >

    bool extended_check( CharT ch REGEX_VC6(COMMA bool2type<CaseT>) ) const

    {

        REGEX_ASSERT( m_fskip_extended_check == ( m_posixcharsoff.empty() && m_nestedcharsets.empty() ) );

 

        if( m_fskip_extended_check )

        {

            return false;

        }

 

        return ( m_posixcharsoff.end() !=

                 std::find_if( m_posixcharsoff.begin(), m_posixcharsoff.end(),

                               posixcharsoff_pred<CharT>( ch ) ) )

            || ( m_nestedcharsets.end() !=

                 std::find_if( m_nestedcharsets.begin(), m_nestedcharsets.end(),

                               in_charset_pred<CharT, CaseT>( ch ) ) );

    }

 

    inline bool in_ranges( wchar_t ch, true_t ) const

    {

        typedef typename ranges_type::const_iterator iter_type;

        iter_type ibegin = m_ranges.begin(), iend = m_ranges.end();

 

        return ibegin != iend &&

            std::binary_search( ibegin, iend, range_type( ch, ch ), range_less() );

    }

 

    inline bool in_ranges( wchar_t ch, false_t ) const

    {

        typedef typename ranges_type::const_iterator iter_type;

        iter_type ibegin = m_ranges.begin(), iend = m_ranges.end();

 

        if( ibegin == iend )

            return false;

 

        wchar_t const chup = regex_toupper( ch );

        if( std::binary_search( ibegin, iend, range_type( chup, chup ), range_less() ) )

            return true;

 

        wchar_t const chlo = regex_tolower( ch );

        if( chup == chlo )

            return false;

 

        return std::binary_search( ibegin, iend, range_type( chlo, chlo ), range_less() );

    }

 

    // Note overloading based on parameter

    template< bool CaseT >

    bool in( char ch REGEX_VC6(COMMA bool2type<CaseT>) ) const

    {

        // Whoops, forgot to call optimize() on this charset

        REGEX_ASSERT( wct_zero == m_posixcharson );

 

        return m_fcompliment !=

               (

                    ( m_ascii_bitvector[ static_cast<unsigned char>( ch ) ] )

                 || ( extended_check REGEX_NVC6(<CaseT>) ( ch REGEX_VC6(COMMA bool2type<CaseT>()) ) )

               );

    }

 

    // Note overloading based on parameter

    template< bool CaseT >

    bool in( wchar_t ch REGEX_VC6(COMMA bool2type<CaseT>) ) const

    {

        // use range_match_type to see if this character is within one of the

        // ranges stored in m_rgranges.

        return m_fcompliment !=

               (

                    ( ( UCHAR_MAX >= ch ) ?

                      ( m_ascii_bitvector[ static_cast<unsigned char>( ch ) ] ) :

                      (    ( in_ranges( ch, bool2type<CaseT>() ) )

                        || ( wct_zero != m_posixcharson && regex_iswctype( ch, m_posixcharson ) ) ) )

                 || ( extended_check REGEX_NVC6(<CaseT>) ( ch REGEX_VC6(COMMA bool2type<CaseT>()) ) )

               );

    }

 

private:

    basic_charset & operator=( basic_charset const & that );

    basic_charset( basic_charset const & that );

};

 

// Intrinsic character sets are allocated on the heap with the standard allocator.

// They are either the built-in character sets, or the user-defined ones.

struct charset : public basic_charset<std::allocator<char> >

{

    charset()

    {

    }

private:

    charset( charset const & );

    charset & operator=( charset const & );

};

 

// charset is no longer an incomplete type so we now

// know how to destroy one. free_charset() is used in syntax2.h

REGEXPR_H_INLINE void free_charset( charset const * pcharset )

{

    delete pcharset;

}

 

// Custom character sets are the ones that appear in patterns between

// square brackets.  They are allocated in a regex_arena to speed up

// pattern compilation and to make rpattern clean-up faster.

struct custom_charset : public basic_charset<regex_arena>

{

    static void * operator new( size_t size, regex_arena & arena )

    {

        return arena.allocate( size );

    }

    static void operator delete( void *, regex_arena & ) {}

    static void operator delete( void * ) {}

 

    custom_charset( regex_arena & arena )

        : basic_charset<regex_arena>( arena )

    {

    }

private:

    custom_charset( custom_charset const & );

    custom_charset & operator=( custom_charset const & );

};

 

template< typename CharT >

class intrinsic_charsets

{

    struct intrinsic_charset : public charset

    {

        intrinsic_charset( bool fcompliment, regex_ctype_t desc, char const * sz )

        {

            reset( fcompliment, desc, sz );

        }

        void reset( bool fcompliment, regex_ctype_t desc, char const * sz )

        {

            clear();

            m_fcompliment  = fcompliment;

            m_posixcharson = desc;

            for( ; *sz; ++sz )

                m_ascii_bitvector.set( static_cast<unsigned char>( *sz ) );

            optimize( type2type<CharT>() );

        }

    private:

        intrinsic_charset( intrinsic_charset const & );

        intrinsic_charset & operator=( intrinsic_charset const & );

    };

 

    static intrinsic_charset & _get_word_charset()

    {

        static intrinsic_charset s_word_charset( false, wct_alpha()|wct_digit(), "_" );

        return s_word_charset;

    }

    static intrinsic_charset & _get_digit_charset()

    {

        static intrinsic_charset s_digit_charset( false, wct_digit(), "" );

        return s_digit_charset;

    }

    static intrinsic_charset & _get_space_charset()

    {

        static intrinsic_charset s_space_charset( false, wct_space(), "" );

        return s_space_charset;

    }

    static intrinsic_charset & _get_not_word_charset()

    {

        static intrinsic_charset s_not_word_charset( true, wct_alpha()|wct_digit(), "_" );

        return s_not_word_charset;

    }

    static intrinsic_charset & _get_not_digit_charset()

    {

        static intrinsic_charset s_not_digit_charset( true, wct_digit(), "" );

        return s_not_digit_charset;

    }

    static intrinsic_charset & _get_not_space_charset()

    {

        static intrinsic_charset s_not_space_charset( true, wct_space(), "" );

        return s_not_space_charset;

    }

public:

    static charset const & get_word_charset()

    {

        return _get_word_charset();

    }

    static charset const & get_digit_charset()

    {

        return _get_digit_charset();

    }

    static charset const & get_space_charset()

    {

        return _get_space_charset();

    }

    static charset const & get_not_word_charset()

    {

        return _get_not_word_charset();

    }

    static charset const & get_not_digit_charset()

    {

        return _get_not_digit_charset();

    }

    static charset const & get_not_space_charset()

    {

        return _get_not_space_charset();

    }

    static void reset()

    {

        _get_word_charset().reset( false, wct_alpha()|wct_digit(), "_" );

        _get_digit_charset().reset( false, wct_digit(), "" );

        _get_space_charset().reset( false, wct_space(), "" );

        _get_not_word_charset().reset( true, wct_alpha()|wct_digit(), "_" );

        _get_not_digit_charset().reset( true, wct_digit(), "" );

        _get_not_space_charset().reset( true, wct_space(), "" );

    }

};

 

//

// Operator implementations

//

 

// Evaluates the beginning-of-string condition

template< typename CStringsT >

struct bos_t

{

    template< typename IterT >

    static bool eval( match_param<IterT> const & param, IterT iter )

    {

        return param.m_ibufferbegin == iter;

    }

};

 

// Find the beginning of a line, either beginning of a string, or the character

// immediately following a newline

template< typename CStringsT >

struct bol_t

{

    template< typename IterT >

    static bool eval( match_param<IterT> const & param, IterT iter )

    {

        typedef typename std::iterator_traits<IterT>::value_type char_type;

        typedef std::char_traits<char_type> traits_type;

 

        return param.m_ibufferbegin == iter || traits_type::eq( REGEX_CHAR(char_type,'/n'), *--iter );

    }

};

 

// Evaluates end-of-string condition for string's

template< typename CStringsT >

struct eos_t

{

    template< typename IterT >

    static bool eval( match_param<IterT> const & param, IterT iter )

    {

        return param.m_iend == iter;

    }

};

template<>

struct eos_t<true_t>

{

    template< typename IterT >

    static bool eval( match_param<IterT> const &, IterT iter )

    {

        typedef typename std::iterator_traits<IterT>::value_type char_type;

        typedef std::char_traits<char_type> traits_type;

 

        return traits_type::eq( *iter, char_type() );

    }

};

 

// Evaluates end-of-line conditions, either the end of the string, or a

// newline character.

template< typename CStringsT >

struct eol_t

{

    template< typename IterT >

    static bool eval( match_param<IterT> const & param, IterT iter )

    {

        typedef typename std::iterator_traits<IterT>::value_type char_type;

        typedef std::char_traits<char_type> traits_type;

 

        return param.m_iend == iter

            || traits_type::eq( REGEX_CHAR(char_type,'/n'), *iter );

    }

};

template<>

struct eol_t<true_t>

{

    template< typename IterT >

    static bool eval( match_param<IterT> const &, IterT iter )

    {

        typedef typename std::iterator_traits<IterT>::value_type char_type;

        typedef std::char_traits<char_type> traits_type;

 

        return traits_type::eq( *iter, char_type() )

            || traits_type::eq( *iter, REGEX_CHAR(char_type,'/n') );

    }

};

 

// Evaluates perl's end-of-string conditions, either the end of the string, or a

// newline character followed by end of string. ( Only used by $ and /Z assertions )

template< typename CStringsT >

struct peos_t

{

    template< typename IterT >

    static bool eval( match_param<IterT> const & param, IterT iter )

    {

        typedef typename std::iterator_traits<IterT>::value_type char_type;

        typedef std::char_traits<char_type> traits_type;

 

        return param.m_iend == iter

            || ( traits_type::eq( REGEX_CHAR(char_type,'/n'), *iter ) && param.m_iend == ++iter );

    }

};

template<>

struct peos_t<true_t>

{

    template< typename IterT >

    static bool eval( match_param<IterT> const &, IterT iter )

    {

        typedef typename std::iterator_traits<IterT>::value_type char_type;

        typedef std::char_traits<char_type> traits_type;

 

        return traits_type::eq( *iter, char_type() )

            || ( traits_type::eq( *iter, REGEX_CHAR(char_type,'/n') )

                && traits_type::eq( *++iter, char_type() ) );

    }

};

 

// compare two characters, case-sensitive

template< typename CharT >

struct ch_neq_t

{

    typedef CharT char_type;

    typedef std::char_traits<char_type> traits_type;

 

    static bool eval( register CharT ch1, register CharT ch2 )

    {

        return ! traits_type::eq( ch1, ch2 );

    }

};

 

// Compare two characters, disregarding case

template< typename CharT >

struct ch_neq_nocase_t

{

    typedef CharT char_type;

    typedef std::char_traits<char_type> traits_type;

 

    static bool eval( register CharT ch1, register CharT ch2 )

    {

        return ! traits_type::eq( regex_toupper( ch1 ), regex_toupper( ch2 ) );

    }

};

 

//

// helper functions for dealing with widths.

//

inline size_t width_add( size_t a, size_t b )

{

    return ( size_t( -1 ) == a || size_t( -1 ) == b ? size_t( -1 ) : a + b );

}

 

inline size_t width_mult( size_t a, size_t b )

{

    if( 0 == a || 0 == b )

        return 0;

 

    if( size_t( -1 ) == a || size_t( -1 ) == b )

        return size_t( -1 );

 

    return a * b;

}

 

inline bool operator==( width_type const & rhs, width_type const & lhs )

{

    return ( rhs.m_min == lhs.m_min && rhs.m_max == lhs.m_max );

}

 

inline bool operator!=( width_type const & rhs, width_type const & lhs )

{

    return ( rhs.m_min != lhs.m_min || rhs.m_max != lhs.m_max );

}

 

inline width_type operator+( width_type const & rhs, width_type const & lhs )

{

    width_type width = { width_add( rhs.m_min, lhs.m_min ), width_add( rhs.m_max, lhs.m_max ) };

    return width;

}

 

inline width_type operator*( width_type const & rhs, width_type const & lhs )

{

    width_type width = { width_mult( rhs.m_min, lhs.m_min ), width_mult( rhs.m_max, lhs.m_max ) };

    return width;

}

 

inline width_type & operator+=( width_type & rhs, width_type const & lhs )

{

    rhs.m_min = width_add( rhs.m_min, lhs.m_min );

    rhs.m_max = width_add( rhs.m_max, lhs.m_max );

    return rhs;

}

 

inline width_type & operator*=( width_type & rhs, width_type const & lhs )

{

    rhs.m_min = width_mult( rhs.m_min, lhs.m_min );

    rhs.m_max = width_mult( rhs.m_max, lhs.m_max );

    return rhs;

}

 

namespace

{

    width_type const zero_width = { 0, 0 };

    width_type const worst_width = { 0, size_t( -1 ) };

}

 

template< typename IterT >

struct width_param

{

    std::vector<match_group_base<IterT>*> & m_rggroups;

    std::list<size_t> const &               m_invisible_groups;

    width_type                              m_width;

 

    width_param

    (

        std::vector<match_group_base<IterT>*> & rggroups,

        std::list<size_t> const & invisible_groups

    )

        : m_rggroups( rggroups )

        , m_invisible_groups( invisible_groups )

        , m_width( zero_width )

    {

    }

private:

    width_param & operator=( width_param const & );

};

 

template< typename CharT >

struct must_have

{

    typedef std::basic_string<CharT>                string_type;

    typedef typename string_type::const_iterator    const_iterator;

 

    bool            m_has;

    const_iterator  m_begin;

    const_iterator  m_end;

    CharT const *   m_lower;

};

 

template< typename CharT >

struct peek_param

{

    // "chars" is a list of characters. If every alternate in a group

    // begins with a character or string literal, the "chars" list can

    // be used to speed up the matching of a group.

    size_t              m_cchars;

 

    union

    {

        CharT           m_rgchars[2];

        CharT const *   m_pchars;

    };

 

    // "must" is a string that must appear in the match. It is used

    // to speed up the search.

    must_have<CharT>    m_must_have;

};

 

// --------------------------------------------------------------------------

//

// Class:       sub_expr

//

// Description: patterns are "compiled" into a directed graph of sub_expr

//              structs.  Matching is accomplished by traversing this graph.

//

// Methods:     sub_expr             - construct a sub_expr

//              recursive_match_this - does this sub_expr match at the given location

//              width_this           - what is the width of this sub_expr

//              ~sub_expr            - recursively delete the sub_expr graph

//              next                 - pointer to the next node in the graph

//              next                 - pointer to the next node in the graph

//              recursive_match_next - match the rest of the graph

//              recursive_match_all  - recursive_match_this and recursive_match_next

//              is_assertion         - true if this sub_expr is a zero-width assertion

//              get_width            - find the width of the graph at this sub_expr

//

// Members:     m_pnext      - pointer to the next node in the graph

//

// History:     8/14/2000 - ericne - Created

//

// --------------------------------------------------------------------------

template< typename IterT >

class sub_expr : public sub_expr_base<IterT>

{

    sub_expr * m_pnext;

 

protected:

    // Only derived classes can instantiate sub_expr's

    sub_expr()

        : m_pnext( 0 )

    {

    }

 

public:

    typedef IterT                                               iterator_type;

    typedef typename std::iterator_traits<IterT>::value_type    char_type;

    typedef std::char_traits<char_type>                         traits_type;

 

    virtual ~sub_expr()

    {

        delete m_pnext;

    }

 

    sub_expr ** pnext()

    {

        return & m_pnext;

    }

 

    sub_expr const * next() const

    {

        return m_pnext;

    }

 

    virtual sub_expr * quantify( size_t, size_t, bool, regex_arena & )

    {

        throw bad_regexpr( "sub-expression cannot be quantified" );

    }

 

    // Match this object and all subsequent objects

    // If recursive_match_all returns false, it must not change any of param's state

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return ( recursive_match_this_s( param, icur ) && recursive_match_next( param, icur, false_t() ) );

    }

 

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const // for C-style strings

    {

        return ( recursive_match_this_c( param, icur ) && recursive_match_next( param, icur, true_t() ) );

    }

 

    // match this object only

    virtual bool recursive_match_this_s( match_param<IterT> &, IterT & ) const

    {

        return true;

    }

 

    virtual bool recursive_match_this_c( match_param<IterT> &, IterT & ) const // for C-style strings

    {

        return true;

    }

 

    // Match all subsequent objects

    template< typename CStringsT >

    bool recursive_match_next( match_param<IterT> & param, IterT icur, CStringsT ) const

    {

        return m_pnext->recursive_match_all( param, icur, CStringsT() );

    }

 

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        param.m_pnext = next();

        return true;

    }

 

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const // for C-style strings

    {

        param.m_pnext = next();

        return true;

    }

 

    virtual bool iterative_rematch_this_s( match_param<IterT> & ) const

    {

        return false;

    }

 

    virtual bool iterative_rematch_this_c( match_param<IterT> & ) const // for C-style strings

    {

        return false;

    }

 

    virtual bool is_assertion() const

    {

        return false;

    }

 

    width_type get_width( width_param<IterT> & param )

    {

        width_type temp_width = width_this( param );

        if( m_pnext )

            temp_width += m_pnext->get_width( param );

        return temp_width;

    }

 

    virtual width_type width_this( width_param<IterT> & ) = 0;

 

    virtual bool peek_this( peek_param<char_type> & ) const

    {

        return false;

    }

};

 

// An object of type end_of_pattern is used to mark the

// end of the pattern.  (Duh!)  It is responsible for ending

// the recursion, or for letting the search continue if

// the match is zero-width and we are trying to find a

// non-zero-width match

template< typename IterT >

class end_of_pattern : public sub_expr<IterT>

{

    bool _do_match_this( match_param<IterT> & param, IterT icur ) const

    {

        return ! param.m_no0len || param.m_imatchbegin != icur;

    }

public:

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return _do_match_this( param, icur );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const // for C-style strings

    {

        return _do_match_this( param, icur );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        param.m_pnext = 0;

        return _do_match_this( param, param.m_icur );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const // for C-style strings

    {

        param.m_pnext = 0;

        return _do_match_this( param, param.m_icur );

    }

    virtual width_type width_this( width_param<IterT> & )

    {

        return zero_width;

    }

};

 

// Base class for sub-expressions which are zero-width

// ( i.e., assertions eat no characters during matching )

// Assertions cannot be quantified.

template< typename IterT >

class assertion : public sub_expr<IterT>

{

public:

    virtual bool is_assertion() const

    {

        return true;

    }

    virtual width_type width_this( width_param<IterT> & )

    {

        return zero_width;

    }

    virtual bool peek_this( peek_param<char_type> & peek ) const

    {

        return this->next()->peek_this( peek );

    }

};

 

template< typename OpT, typename OpCT >

struct opwrap

{

    typedef OpT  op_type;

    typedef OpCT opc_type;

};

 

#define REGEX_OP(x) opwrap< x<false_t>, x<true_t> >

 

template< typename IterT, typename OpWrapT >

class assert_op : public assertion<IterT>

{

public:

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return ( assert_op::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return ( assert_op::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );

    }

    virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const

    {

        return OpWrapT::op_type::eval( param, icur );

    }

    virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const

    {

        return OpWrapT::opc_type::eval( param, icur );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return OpWrapT::op_type::eval( param, param.m_icur );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return OpWrapT::opc_type::eval( param, param.m_icur );

    }

};

 

template< typename IterT >

inline assertion<IterT> * create_bos( REGEX_FLAGS, regex_arena & arena )

{

    return new( arena ) assert_op<IterT, REGEX_OP(bos_t) >();

}

 

template< typename IterT >

inline assertion<IterT> * create_eos( REGEX_FLAGS, regex_arena & arena )

{

    return new( arena ) assert_op<IterT, REGEX_OP(peos_t) >();

}

 

template< typename IterT >

inline assertion<IterT> * create_eoz( REGEX_FLAGS, regex_arena & arena )

{

    return new( arena ) assert_op<IterT, REGEX_OP(eos_t) >();

}

 

template< typename IterT >

inline assertion<IterT> * create_bol( REGEX_FLAGS flags, regex_arena & arena )

{

    switch( MULTILINE & flags )

    {

    case 0:

        return new( arena ) assert_op<IterT, REGEX_OP(bos_t) >();

    case MULTILINE:

        return new( arena ) assert_op<IterT, REGEX_OP(bol_t) >();

    default:

        REGEX_ASSERT(false);

        return 0;

    }

}

 

template< typename IterT >

inline assertion<IterT> * create_eol( REGEX_FLAGS flags, regex_arena & arena )

{

    switch( MULTILINE & flags )

    {

    case 0:

        return new( arena ) assert_op<IterT, REGEX_OP(peos_t) >();

    case MULTILINE:

        return new( arena ) assert_op<IterT, REGEX_OP(eol_t) >();

    default:

        REGEX_ASSERT(false);

        return 0;

    }

}

 

template< typename IterT, typename SubExprT = sub_expr<IterT> >

class match_wrapper : public sub_expr<IterT>

{

    match_wrapper & operator=( match_wrapper const & );

public:

    match_wrapper( SubExprT * psub )

        : m_psub( psub )

    {

    }

    virtual ~match_wrapper()

    {

        _cleanup();

    }

    virtual width_type width_this( width_param<IterT> & param )

    {

        return m_psub->width_this( param );

    }

    virtual bool peek_this( peek_param<char_type> & peek ) const

    {

        return m_psub->peek_this( peek );

    }

protected:

    void _cleanup()

    {

        delete m_psub;

        m_psub = 0;

    }

 

    SubExprT * m_psub;

};

 

template< typename IterT, typename SubExprT = sub_expr<IterT> >

class match_quantifier : public match_wrapper<IterT, SubExprT>

{

    match_quantifier & operator=( match_quantifier const & );

public:

    match_quantifier( SubExprT * psub, size_t lbound, size_t ubound )

        : match_wrapper<IterT, SubExprT>( psub )

        , m_lbound( lbound )

        , m_ubound( ubound )

    {

    }

    virtual width_type width_this( width_param<IterT> & param )

    {

        width_type this_width = match_wrapper<IterT, SubExprT>::width_this( param );

        width_type quant_width = { m_lbound, m_ubound };

        return this_width * quant_width;

    }

    virtual bool peek_this( peek_param<char_type> & peek ) const

    {

        return 0 != m_lbound && this->m_psub->peek_this( peek );

    }

protected:

    size_t const m_lbound;

    size_t const m_ubound;

};

 

template< typename IterT, typename SubExprT >

class atom_quantifier : public match_quantifier<IterT, SubExprT>

{

    atom_quantifier & operator=( atom_quantifier const & );

public:

    atom_quantifier( SubExprT * psub, size_t lbound, size_t ubound )

        : match_quantifier<IterT, SubExprT>( psub, lbound, ubound )

    {

    }

protected:

    void _push_frame( unsafe_stack * pstack, IterT curr, size_t count ) const

    {

        std::pair<IterT, size_t> p( curr, count );

        pstack->push( p );

    }

 

    void _pop_frame( match_param<IterT> & param ) const

    {

        std::pair<IterT, size_t> p;

        param.m_pstack->pop( p );

        param.m_icur = p.first;

    }

};

 

template< typename IterT, typename SubExprT >

class max_atom_quantifier : public atom_quantifier<IterT, SubExprT>

{

    max_atom_quantifier & operator=( max_atom_quantifier const & );

 

public:

    max_atom_quantifier( SubExprT * psub, size_t lbound, size_t ubound )

        : atom_quantifier<IterT, SubExprT>( psub, lbound, ubound )

    {

    }

 

    // Why a macro instead of a template, you ask?  Performance.  Due to a known

    // bug in the VC7 inline heuristic, I cannot get VC7 to inline the calls to

    // m_psub methods unless I use these macros.  And the performance win is

    // nothing to sneeze at. It's on the order of a 25% speed up to use a macro

    // here instead of a template.

#define DECLARE_RECURSIVE_MATCH_ALL(CSTRINGS,EXT)                                                           /

    virtual bool recursive_match_all ## EXT( match_param<IterT> & param, IterT icur ) const                 /

    {                                                                                                       /

        typedef typename std::iterator_traits<IterT>::difference_type diff_type;                            /

        /* In an ideal world, ibegin and cdiff would be members of a union    */                            /

        /* to conserve stack, but I don't know if IterT is a POD type or not. */                            /

        IterT     ibegin   = icur;                                                                          /

        diff_type cdiff    = 0; /* must be a signed integral type */                                        /

        size_t    cmatches = 0;                                                                             /

        /* greedily match as much as we can*/                                                               /

        if( this->m_ubound && this->m_psub->SubExprT::recursive_match_this ## EXT( param, icur ) )          /

        {                                                                                                   /

            if( 0 == ( cdiff = -std::distance( ibegin, icur ) ) )                                           /

                return this->recursive_match_next( param, icur, CSTRINGS() );                               /

            while( ++cmatches < this->m_ubound && this->m_psub->SubExprT::recursive_match_this ## EXT( param, icur ) )/

                {}                                                                                          /

        }                                                                                                   /

        if( this->m_lbound > cmatches )                                                                     /

            return false;                                                                                   /

        /* try matching the rest of the pattern, and back off if necessary */                               /

        for( ; ; --cmatches, std::advance( icur, cdiff ) )                                                  /

        {                                                                                                   /

            if( this->recursive_match_next( param, icur, CSTRINGS() ) )                                     /

                return true;                                                                                /

            if( this->m_lbound == cmatches )                                                                /

                return false;                                                                               /

        }                                                                                                   /

    }

 

#define DECLARE_ITERATIVE_MATCH_THIS(EXT)                                                                   /

    virtual bool iterative_match_this ## EXT( match_param<IterT> & param ) const                            /

    {                                                                                                       /

        IterT ibegin = param.m_icur;                                                                        /

        size_t cmatches = 0;                                                                                /

        if( this->m_ubound && this->m_psub->SubExprT::iterative_match_this ## EXT( param ) )                /

        {                                                                                                   /

            if( 0 == std::distance( ibegin, param.m_icur ) )                                                /

            {                                                                                               /

                cmatches = this->m_lbound;                                                                  /

            }                                                                                               /

            else                                                                                            /

            {                                                                                               /

                while( ++cmatches < this->m_ubound && this->m_psub->SubExprT::iterative_match_this ## EXT( param ) )/

                    {}                                                                                      /

            }                                                                                               /

        }                                                                                                   /

        if( cmatches >= this->m_lbound )                                                                    /

        {                                                                                                   /

            this->_push_frame( param.m_pstack, ibegin, cmatches );                                          /

            param.m_pnext = this->next();                                                                   /

            return true;                                                                                    /

        }                                                                                                   /

        param.m_icur = ibegin;                                                                              /

        return false;                                                                                       /

    }

 

#define DECLARE_ITERATIVE_REMATCH_THIS(EXT)                                                                 /

    virtual bool iterative_rematch_this ## EXT( match_param<IterT> & param ) const                          /

    {                                                                                                       /

        typedef std::pair<IterT, size_t> top_type;                                                          /

        size_t & cmatches = REGEX_VC6( param.m_pstack->top( type2type<top_type>() ).second )                /

                            REGEX_NVC6( param.m_pstack->template top<top_type>().second );                  /

        if( this->m_lbound != cmatches )                                                                    /

        {                                                                                                   /

            --cmatches;                                                                                     /

            this->m_psub->SubExprT::iterative_rematch_this ## EXT( param );                                 /

            param.m_pnext = this->next();                                                                   /

            return true;                                                                                    /

        }                                                                                                   /

        this->_pop_frame( param );                                                                          /

        return false;                                                                                       /

    }

 

    DECLARE_RECURSIVE_MATCH_ALL(false_t,_s)

    DECLARE_RECURSIVE_MATCH_ALL(true_t,_c)

    DECLARE_ITERATIVE_MATCH_THIS(_s)

    DECLARE_ITERATIVE_MATCH_THIS(_c)

    DECLARE_ITERATIVE_REMATCH_THIS(_s)

    DECLARE_ITERATIVE_REMATCH_THIS(_c)

 

#undef DECLARE_RECURSIVE_MATCH_ALL

#undef DECLARE_ITERATIVE_MATCH_THIS

#undef DECLARE_ITERATIVE_REMATCH_THIS

};

 

template< typename IterT, typename SubExprT >

class min_atom_quantifier : public atom_quantifier<IterT, SubExprT>

{

    min_atom_quantifier & operator=( min_atom_quantifier const & );

 

public:

    min_atom_quantifier( SubExprT * psub, size_t lbound, size_t ubound )

        : atom_quantifier<IterT, SubExprT>( psub, lbound, ubound )

    {

    }

 

    // Why a macro instead of a template, you ask?  Performance.  Due to a known

    // bug in the VC7 inline heuristic, I cannot get VC7 to inline the calls to

    // m_psub methods unless I use these macros.  And the performance win is

    // nothing to sneeze at. It's on the order of a 25% speed up to use a macro

    // here instead of a template.

#define DECLARE_RECURSIVE_MATCH_ALL(CSTRINGS,EXT)                                                           /

    virtual bool recursive_match_all ## EXT( match_param<IterT> & param, IterT icur ) const                 /

    {                                                                                                       /

        IterT  icur_tmp = icur;                                                                             /

        size_t cmatches = 0;                                                                                /

        if( this->m_psub->SubExprT::recursive_match_this ## EXT( param, icur_tmp ) )                        /

        {                                                                                                   /

            if( icur_tmp == icur )                                                                          /

                return this->recursive_match_next( param, icur, CSTRINGS() );                               /

            if( this->m_lbound )                                                                            /

            {                                                                                               /

                icur = icur_tmp;                                                                            /

                ++cmatches;                                                                                 /

            }                                                                                               /

            for( ; cmatches < this->m_lbound; ++cmatches )                                                  /

            {                                                                                               /

                if( ! this->m_psub->SubExprT::recursive_match_this ## EXT( param, icur ) )                  /

                    return false;                                                                           /

            }                                                                                               /

        }                                                                                                   /

        else if( this->m_lbound )                                                                           /

        {                                                                                                   /

            return false;                                                                                   /

        }                                                                                                   /

        do                                                                                                  /

        {                                                                                                   /

            if( this->recursive_match_next( param, icur, CSTRINGS() ) )                                     /

                return true;                                                                                /

        }                                                                                                   /

        while( cmatches < this->m_ubound &&                                                                 /

             ( ++cmatches, this->m_psub->SubExprT::recursive_match_this ## EXT( param, icur ) ) );          /

        return false;                                                                                       /

    }

 

#define DECLARE_ITERATIVE_MATCH_THIS(EXT)                                                                   /

    virtual bool iterative_match_this ## EXT( match_param<IterT> & param ) const                            /

    {                                                                                                       /

        IterT ibegin = param.m_icur;                                                                        /

        size_t cmatches = 0;                                                                                /

        if( this->m_psub->SubExprT::iterative_match_this ## EXT( param ) )                                  /

        {                                                                                                   /

            if( 0 == std::distance( ibegin, param.m_icur ) )                                                /

            {                                                                                               /

                cmatches = this->m_ubound;                                                                  /

            }                                                                                               /

            else if( this->m_lbound )                                                                       /

            {                                                                                               /

                for( ++cmatches; cmatches < this->m_lbound; ++cmatches )                                    /

                {                                                                                           /

                    if( ! this->m_psub->SubExprT::iterative_match_this ## EXT( param ) )                    /

                    {                                                                                       /

                        param.m_icur = ibegin;                                                              /

                        return false;                                                                       /

                    }                                                                                       /

                }                                                                                           /

            }                                                                                               /

            else                                                                                            /

            {                                                                                               /

                param.m_icur = ibegin;                                                                      /

            }                                                                                               /

        }                                                                                                   /

        else if( this->m_lbound )                                                                           /

        {                                                                                                   /

            return false;                                                                                   /

        }                                                                                                   /

        this->_push_frame( param.m_pstack, ibegin, cmatches );                                              /

        param.m_pnext = this->next();                                                                       /

        return true;                                                                                        /

    }

 

#define DECLARE_ITERATIVE_REMATCH_THIS(EXT)                                                                 /

    virtual bool iterative_rematch_this ## EXT( match_param<IterT> & param ) const                          /

    {                                                                                                       /

        typedef std::pair<IterT, size_t> top_type;                                                          /

        size_t & cmatches = REGEX_VC6( param.m_pstack->top( type2type<top_type>() ).second )                /

                            REGEX_NVC6( param.m_pstack->template top<top_type>().second );                  /

        if( cmatches == this->m_ubound || ! this->m_psub->SubExprT::iterative_match_this ## EXT( param ) )  /

        {                                                                                                   /

            this->_pop_frame( param );                                                                      /

            return false;                                                                                   /

        }                                                                                                   /

        ++cmatches;                                                                                         /

        param.m_pnext = this->next();                                                                       /

        return true;                                                                                        /

    }

 

    DECLARE_RECURSIVE_MATCH_ALL(false_t,_s)

    DECLARE_RECURSIVE_MATCH_ALL(true_t,_c)

    DECLARE_ITERATIVE_MATCH_THIS(_s)

    DECLARE_ITERATIVE_MATCH_THIS(_c)

    DECLARE_ITERATIVE_REMATCH_THIS(_s)

    DECLARE_ITERATIVE_REMATCH_THIS(_c)

 

#undef DECLARE_RECURSIVE_MATCH_ALL

#undef DECLARE_ITERATIVE_MATCH_THIS

#undef DECLARE_ITERATIVE_REMATCH_THIS

};

 

template< typename CharT >

struct char_nocase

{

    CharT m_chlo;

    CharT m_chhi;

};

 

template< typename IterT >

class match_char : public sub_expr<IterT>

{

    match_char & operator=( match_char const & );

public:

    typedef typename sub_expr<IterT>::char_type char_type;

 

    virtual width_type width_this( width_param<IterT> & )

    {

        width_type width = { 1, 1 };

        return width;

    }

    virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

    {

        --param.m_icur;

        return false;

    }

    virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

    {

        --param.m_icur;

        return false;

    }

};

 

template< typename IterT, typename CharT >

class match_char_t : public match_char<IterT>

{

    match_char_t & operator=( match_char_t const & );

 

public:

    match_char_t( CharT const & ch )

        : m_ch( ch )

    {

    }

 

    virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )

    {

        if( greedy )

            return new( arena ) max_atom_quantifier<IterT, match_char_t<IterT, CharT> >( this, lbound, ubound );

        else

            return new( arena ) min_atom_quantifier<IterT, match_char_t<IterT, CharT> >( this, lbound, ubound );

    }

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return ( match_char_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return ( match_char_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );

    }

    virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this REGEX_NVC6(<false_t>) ( param, param.m_icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this REGEX_NVC6(<true_t>) ( param, param.m_icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool peek_this( peek_param<char_type> & peek ) const

    {

        _do_peek_this( peek, m_ch );

        return true;

    }

private:

    static bool eq( char_type left, char_type right )

    {

        return traits_type::eq( left, right );

    }

    static bool eq( char_type left, char_nocase<char_type> right )

    {

        return traits_type::eq( left, right.m_chlo ) ||

               traits_type::eq( left, right.m_chhi );

    }

    static void _do_peek_this( peek_param<char_type> & peek, char_type ch )

    {

        peek.m_cchars           = 1;

        peek.m_rgchars[0]       = ch;

        peek.m_must_have.m_has  = false;

    }

    static void _do_peek_this( peek_param<char_type> & peek, char_nocase<char_type> ch )

    {

        peek.m_cchars           = 2;

        peek.m_rgchars[0]       = ch.m_chlo;

        peek.m_rgchars[1]       = ch.m_chhi;

        peek.m_must_have.m_has  = false;

    }

    template< typename CStringsT >

    bool _do_match_this( match_param<IterT> & param, IterT & icur REGEX_VC6(COMMA CStringsT) ) const

    {

        if( eos_t<CStringsT>::eval( param, icur ) || ! eq( *icur, m_ch ) )

            return false;

        ++icur;

        return true;

    }

    CharT const m_ch;

};

 

template< typename IterT >

inline match_char<IterT> * create_char

(

     typename std::iterator_traits<IterT>::value_type ch,

     REGEX_FLAGS flags,

     regex_arena & arena

)

{

    typedef typename std::iterator_traits<IterT>::value_type char_type;

    typedef std::char_traits<char_type> traits_type;

 

    switch( NOCASE & flags )

    {

    case 0:

        return new( arena ) match_char_t<IterT, char_type>( ch );

 

    case NOCASE:

        {

            char_nocase<char_type> nocase = { regex_tolower( ch ), regex_toupper( ch ) };

 

            if( traits_type::eq( nocase.m_chlo, nocase.m_chhi ) )

                return new( arena ) match_char_t<IterT, char_type>( ch );

            else

                return new( arena ) match_char_t<IterT, char_nocase<char_type> >( nocase );

        }

    default:

        REGEX_ASSERT(false);

        return 0;

    }

}

 

template< typename IterT >

class match_literal : public sub_expr<IterT>

{

    match_literal & operator=( match_literal const & );

public:

    typedef typename sub_expr<IterT>::char_type                     char_type;

    typedef std::basic_string<char_type>                            string_type;

    typedef typename string_type::iterator                          iterator;

    typedef typename string_type::const_iterator                    const_iterator;

    typedef typename std::iterator_traits<IterT>::difference_type   diff_type;

 

    match_literal( const_iterator ibegin, const_iterator iend )

        : m_ibegin( ibegin )

        , m_iend( iend )

        , m_dist( std::distance( m_ibegin, m_iend ) )

    {

    }

 

    const_iterator const m_ibegin;

    const_iterator const m_iend;

    diff_type      const m_dist; // must be signed integral type

 

    virtual width_type width_this( width_param<IterT> & )

    {

        width_type width = { static_cast<size_t>( m_dist ), static_cast<size_t>( m_dist ) };

        return width;

    }

    virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

    {

        std::advance( param.m_icur, -m_dist );

        return false;

    }

    virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

    {

        std::advance( param.m_icur, -m_dist );

        return false;

    }

};

 

template< typename IterT >

class match_literal_t : public match_literal<IterT>

{

    match_literal_t & operator=( match_literal_t const & );

public:

    typedef typename match_literal<IterT>::char_type       char_type;

    typedef typename match_literal<IterT>::string_type     string_type;

    typedef typename match_literal<IterT>::iterator        iterator;

    typedef typename match_literal<IterT>::const_iterator  const_iterator;

 

    match_literal_t( const_iterator ibegin, const_iterator iend )

        : match_literal<IterT>( ibegin, iend )

    {

    }

 

    virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )

    {

        if( greedy )

            return new( arena ) max_atom_quantifier<IterT, match_literal_t<IterT> >( this, lbound, ubound );

        else

            return new( arena ) min_atom_quantifier<IterT, match_literal_t<IterT> >( this, lbound, ubound );

    }

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return ( match_literal_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return ( match_literal_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );

    }

    virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this REGEX_NVC6(<false_t>) ( param, param.m_icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this REGEX_NVC6(<true_t>) ( param, param.m_icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool peek_this( peek_param<char_type> & peek ) const

    {

        peek.m_cchars             = 1;

        peek.m_rgchars[0]         = *this->m_ibegin;

        peek.m_must_have.m_has    = true;

        peek.m_must_have.m_begin  = this->m_ibegin;

        peek.m_must_have.m_end    = this->m_iend;

        peek.m_must_have.m_lower  = 0;

        return true;

    }

private:

    template< typename CStringsT >

    bool _do_match_this( match_param<IterT> & param, IterT & icur REGEX_VC6(COMMA CStringsT) ) const

    {

        IterT icur_tmp = icur;

        const_iterator ithis = this->m_ibegin;

        for( ; this->m_iend != ithis; ++icur_tmp, ++ithis )

        {

            if( eos_t<CStringsT>::eval( param, icur_tmp ) || ! traits_type::eq( *ithis, *icur_tmp ) )

                return false;

        }

        icur = icur_tmp;

        return true;

    }

};

 

template< typename IterT >

class match_literal_nocase_t : public match_literal<IterT>

{

    match_literal_nocase_t & operator=( match_literal_nocase_t const & );

 

public:

    typedef typename match_literal<IterT>::char_type       char_type;

    typedef typename match_literal<IterT>::string_type     string_type;

    typedef typename match_literal<IterT>::iterator        iterator;

    typedef typename match_literal<IterT>::const_iterator  const_iterator;

 

    match_literal_nocase_t( iterator ibegin, const_iterator iend, regex_arena & arena )

        : match_literal<IterT>( ibegin, iend )

        , m_szlower( arena_allocator<char_type>( arena ).allocate( m_dist ) )

    {

        // Copy from ibegin to m_szlower

        std::copy( this->m_ibegin, this->m_iend, m_szlower );

        // Store the uppercase version of the literal in [ m_ibegin, m_iend ).

        regex_toupper( ibegin, iend );

        // Store the lowercase version of the literal in m_strlower.

        regex_tolower( m_szlower, m_szlower + this->m_dist );

    }

 

    virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )

    {

        if( greedy )

            return new( arena ) max_atom_quantifier<IterT, match_literal_nocase_t<IterT> >( this, lbound, ubound );

        else

            return new( arena ) min_atom_quantifier<IterT, match_literal_nocase_t<IterT> >( this, lbound, ubound );

    }

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return ( match_literal_nocase_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return ( match_literal_nocase_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );

    }

    virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this REGEX_NVC6(<false_t>) ( param, param.m_icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this REGEX_NVC6(<true_t>) ( param, param.m_icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool peek_this( peek_param<char_type> & peek ) const

    {

        peek.m_cchars             = 2;

        peek.m_rgchars[0]         = *this->m_ibegin;

        peek.m_rgchars[1]         = *m_szlower;

        peek.m_must_have.m_has    = true;

        peek.m_must_have.m_begin  = this->m_ibegin;

        peek.m_must_have.m_end    = this->m_iend;

        peek.m_must_have.m_lower  = m_szlower;

        return true;

    }

private:

    // Allocated from a regex arena. The memory will be cleaned up

    // when the arena is deallocated.

    char_type *const m_szlower;

 

    template< typename CStringsT >

    bool _do_match_this( match_param<IterT> & param, IterT & icur REGEX_VC6(COMMA CStringsT) ) const

    {

        IterT icur_tmp = icur;

        const_iterator ithisu    = this->m_ibegin;  // uppercase

        char_type const * ithisl = m_szlower;       // lowercase

        for( ; this->m_iend != ithisu; ++icur_tmp, ++ithisu, ++ithisl )

        {

            if( eos_t<CStringsT>::eval( param, icur_tmp ) ||

                ( ! traits_type::eq( *ithisu, *icur_tmp ) &&

                  ! traits_type::eq( *ithisl, *icur_tmp ) ) )

                return false;

        }

        icur = icur_tmp;

        return true;

    }

};

 

template< typename IterT, typename IBeginT, typename IEndT >

inline sub_expr<IterT> * create_literal

(

    IBeginT         ibegin,

    IEndT           iend,

    REGEX_FLAGS     flags,

    regex_arena &   arena

)

{

    // A match_char is faster than a match_literal, so prefer it

    // when the literal to match is only 1 char wide.

    if( 1 == std::distance<IEndT>( ibegin, iend ) )

    {

        return create_char<IterT>( *ibegin, flags, arena );

    }

 

    switch( NOCASE & flags )

    {

    case 0:

        return new( arena ) match_literal_t<IterT>( ibegin, iend );

    case NOCASE:

        return new( arena ) match_literal_nocase_t<IterT>( ibegin, iend, arena );

    default:

        REGEX_ASSERT(false);

        return 0;

    }

}

 

template< typename IterT >

class match_any : public sub_expr<IterT>

{

public:

    virtual width_type width_this( width_param<IterT> & )

    {

        width_type width = { 1, 1 };

        return width;

    }

    virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

    {

        --param.m_icur;

        return false;

    }

    virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

    {

        --param.m_icur;

        return false;

    }

};

 

template< typename IterT, typename EosWrapT >

class match_any_t : public match_any<IterT>

{

    bool _do_match_this_s( match_param<IterT> & param, IterT & icur ) const

    {

        if( EosWrapT::op_type::eval( param, icur ) )

            return false;

        ++icur;

        return true;

    }

    bool _do_match_this_c( match_param<IterT> & param, IterT & icur ) const

    {

        if( EosWrapT::opc_type::eval( param, icur ) )

            return false;

        ++icur;

        return true;

    }

public:

    virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )

    {

        if( greedy )

            return new( arena ) max_atom_quantifier<IterT, match_any_t<IterT, EosWrapT> >( this, lbound, ubound );

        else

            return new( arena ) min_atom_quantifier<IterT, match_any_t<IterT, EosWrapT> >( this, lbound, ubound );

    }

 

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return ( match_any_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return ( match_any_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );

    }

    virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this_s( param, icur );

    }

    virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this_c( param, icur );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this_s( param, param.m_icur );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this_c( param, param.m_icur );

    }

};

 

template< typename IterT >

inline match_any<IterT> * create_any( REGEX_FLAGS flags, regex_arena & arena )

{

    switch( SINGLELINE & flags )

    {

    case 0:

        return new( arena ) match_any_t<IterT, REGEX_OP(eol_t) >();

    case SINGLELINE:

        return new( arena ) match_any_t<IterT, REGEX_OP(eos_t) >();

    default:

        REGEX_ASSERT(false);

        return 0;

    }

}

 

template< typename IterT >

class match_charset : public sub_expr<IterT>

{

public:

    virtual width_type width_this( width_param<IterT> & )

    {

        width_type width = { 1, 1 };

        return width;

    }

    virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

    {

        --param.m_icur;

        return false;

    }

    virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

    {

        --param.m_icur;

        return false;

    }

};

 

template< typename IterT, typename CharSetPtrT, bool CaseT >

class match_charset_t : public match_charset<IterT>

{

    CharSetPtrT const m_pcs;

 

    match_charset_t & operator=( match_charset_t const & );

 

    template< typename CStringsT >

    bool _do_match_this( match_param<IterT> & param, IterT & icur REGEX_VC6(COMMA CStringsT) ) const

    {

        if( eos_t<CStringsT>::eval( param, icur ) || 

            ! m_pcs->REGEX_NVC6(template) in REGEX_NVC6(<CaseT>)( *icur REGEX_VC6(COMMA bool2type<CaseT>()) ) )

            return false;

        ++icur;

        return true;

    }

public:

    match_charset_t( CharSetPtrT pcs )

         : m_pcs( pcs )

    {

    }

 

    virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )

    {

        if( greedy )

            return new( arena ) max_atom_quantifier<IterT, match_charset_t<IterT, CharSetPtrT, CaseT> >( this, lbound, ubound );

        else

            return new( arena ) min_atom_quantifier<IterT, match_charset_t<IterT, CharSetPtrT, CaseT> >( this, lbound, ubound );

    }

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return ( match_charset_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return ( match_charset_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );

    }

    virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this REGEX_NVC6(<false_t>) ( param, param.m_icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this REGEX_NVC6(<true_t>) ( param, param.m_icur REGEX_VC6(COMMA true_t()) );

    }

};

 

template< typename IterT >

inline match_charset<IterT> * create_charset

(

    charset const &    cs,

    REGEX_FLAGS        flags,

    regex_arena &      arena

)

{

    switch( NOCASE & flags )

    {

    case 0:

        return new( arena ) match_charset_t<IterT, charset const*, true>( &cs );

    case NOCASE:

        return new( arena ) match_charset_t<IterT, charset const*, false>( &cs );

    default:

        REGEX_ASSERT(false);

        return 0;

    }

}

 

template< typename IterT >

inline match_charset<IterT> * create_custom_charset

(

    custom_charset const *  pcs,

    REGEX_FLAGS             flags,

    regex_arena &           arena

)

{

    typedef std::auto_ptr<custom_charset const> auto_charset;

    auto_charset acs( pcs );

 

    switch( NOCASE & flags )

    {

    case 0:

        return new( arena ) match_charset_t<IterT, auto_charset, true>( acs );

    case NOCASE:

        return new( arena ) match_charset_t<IterT, auto_charset, false>( acs );

    default:

        REGEX_ASSERT(false);

        return 0;

    }

}

 

template< bool IsBoundaryT >

struct word_boundary

{

    static bool eval( bool fprevword, bool fthisword )

    {

        return IsBoundaryT == ( fprevword != fthisword );

    }

};

 

struct word_start

{

    static bool eval( bool fprevword, bool fthisword )

    {

        return ! fprevword && fthisword;

    }

};

 

struct word_stop

{

    static bool eval( bool fprevword, bool fthisword )

    {

        return fprevword && ! fthisword;

    }

};

 

template< typename IterT, typename CondT >

class word_assertion_t : public assertion<IterT>

{

    word_assertion_t & operator=( word_assertion_t const & );

public:

    typedef typename assertion<IterT>::char_type char_type;

 

    word_assertion_t()

        : m_isword( intrinsic_charsets<char_type>::get_word_charset() )

    {

    }

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return ( word_assertion_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return ( word_assertion_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );

    }

    virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this REGEX_NVC6(<false_t>) ( param, param.m_icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this REGEX_NVC6(<true_t>) ( param, param.m_icur REGEX_VC6(COMMA true_t()) );

    }

private:

    bool _is_word( char_type ch ) const

    {

        return REGEX_VC6( m_isword.in( ch COMMA true_t() ) )

               REGEX_NVC6( m_isword.template in<true>( ch ) );

    }

    template< typename CStringsT >

    bool _do_match_this( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

    {

        bool const fthisword = ! eos_t<CStringsT>::eval( param, icur ) && _is_word( *icur );

        bool const fprevword = ! bos_t<CStringsT>::eval( param, icur ) && _is_word( *--icur );

 

        return CondT::eval( fprevword, fthisword );

    }

    charset const & m_isword;

};

 

template< typename IterT >

inline assertion<IterT> * create_word_boundary

(

    bool            fisboundary,

    REGEX_FLAGS,    // flags

    regex_arena &   arena

)

{

    if( fisboundary )

        return new( arena ) word_assertion_t<IterT, word_boundary<true> >();

    else

        return new( arena ) word_assertion_t<IterT, word_boundary<false> >();

}

 

template< typename IterT >

inline assertion<IterT> * create_word_start( REGEX_FLAGS, regex_arena & arena )

{

    return new( arena ) word_assertion_t<IterT, word_start>();

}

 

template< typename IterT >

inline assertion<IterT> * create_word_stop( REGEX_FLAGS, regex_arena & arena )

{

    return new( arena ) word_assertion_t<IterT, word_stop>();

}

 

// an "extent" represents the range of backrefs that can be modified as the

// result of a look-ahead or look-behind

typedef std::pair<size_t, size_t> extent_type;

 

template< typename IterT > class max_group_quantifier;

template< typename IterT > class min_group_quantifier;

 

template< typename IterT >

class match_group_base : public sub_expr<IterT>

{

protected:

    typedef slist<sub_expr<IterT>*,regex_arena> alt_list_type;

 

private:

    match_group_base & operator=( match_group_base const & );

 

    void _push_frame( match_param<IterT> & param ) const

    {

        unsafe_stack * ps = param.m_pstack;

 

        if( size_t( -1 ) != m_cgroup )

        {

            IterT & reserved1 = param.m_prgbackrefs[ m_cgroup ].reserved1;

            ps->push( reserved1 );

            reserved1 = param.m_icur;

        }

 

        ps->push( m_rgalternates.begin() );

    }

 

    void _pop_frame( match_param<IterT> & param ) const

    {

        typedef typename alt_list_type::const_iterator iter_type;

        unsafe_stack * ps = param.m_pstack;

 

        REGEX_VC6( ps->pop( type2type<iter_type>() COMMA 0 ); )

        REGEX_NVC6( ps->template pop<iter_type>(); )

 

        if( size_t( -1 ) != m_cgroup )

            ps->pop( param.m_prgbackrefs[ m_cgroup ].reserved1 );

    }

 

    template< typename CStringsT >

    bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

    {

        typedef typename alt_list_type::const_iterator iter_type;

 

        if( 0 != m_peek_chars_begin && 

            ( eos_t<CStringsT>::eval( param, icur ) ||

              m_peek_chars_end == std::find( m_peek_chars_begin, m_peek_chars_end, *icur ) ) )

        {

            return false;

        }

 

        if( size_t( -1 ) != m_cgroup ) // could be -1 if this is a lookahead_assertion

        {

            IterT & reserved1 = param.m_prgbackrefs[ m_cgroup ].reserved1;

            IterT old_ibegin = reserved1;

            reserved1 = icur;

 

            for( iter_type ialt = m_rgalternates.begin(); m_rgalternates.end() != ialt; ++ialt )

            {

                if( (*ialt)->recursive_match_all( param, icur, CStringsT() ) )

                    return true;

            }

 

            reserved1 = old_ibegin;

        }

        else

        {

            for( iter_type ialt = m_rgalternates.begin(); m_rgalternates.end() != ialt; ++ialt )

            {

                if( (*ialt)->recursive_match_all( param, icur, CStringsT() ) )

                    return true;

            }

        }

 

        return false;

    }

    template< typename CStringsT >

    bool _do_iterative_match_this( match_param<IterT> & param REGEX_VC6(COMMA CStringsT) ) const

    {

        if( 0 != m_peek_chars_begin && 

            ( eos_t<CStringsT>::eval( param, param.m_icur ) ||

              m_peek_chars_end == std::find( m_peek_chars_begin, m_peek_chars_end, *param.m_icur ) ) )

        {

            return false;

        }

 

        _push_frame( param );

        param.m_pnext = *m_rgalternates.begin();

        return true;

    }

    bool _do_iterative_rematch_this( match_param<IterT> & param ) const

    {

        typedef typename alt_list_type::const_iterator iter_type;

        iter_type next_iter = ++param.m_pstack->REGEX_NVC6(template) top REGEX_NVC6(<iter_type>) ( REGEX_VC6(type2type<iter_type>()) );

        if( m_rgalternates.end() != next_iter )

        {

            param.m_pnext = *next_iter;

            return true;

        }

        _pop_frame( param );

        return false;

    }

public:

    typedef typename sub_expr<IterT>::char_type char_type;

 

    match_group_base( size_t cgroup, regex_arena & arena )

        : m_rgalternates( arena_allocator<sub_expr<IterT>*>( arena ) )

        , m_cgroup( cgroup )

        , m_nwidth( uninit_width() )

        , m_pptail( 0 )

        , m_peek_chars_end( 0 )

    {

    }

 

    // Derived classes that own the end_group object must have a

    // destructor, and that destructor must call _cleanup().

    virtual ~match_group_base() = 0;

 

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_match_this REGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_match_this REGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this( param );

    }

    virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this( param );

    }

    size_t group_number() const

    {

        return m_cgroup;

    }

    void add_item( sub_expr<IterT> * pitem )

    {

        *m_pptail = pitem;

        m_pptail = pitem->pnext();

    }

    void add_alternate()

    {

        m_rgalternates.push_front( 0 );

        m_pptail = &*m_rgalternates.begin();

    }

    void end_alternate()

    {

        *m_pptail = _get_end_group();

    }

    void open_group()

    {

        add_alternate();

    }

    must_have<char_type> close_group( regex_arena & arena )

    {

        end_alternate();

        m_rgalternates.reverse();

        return get_peek_chars( arena );

    }

    must_have<char_type> get_peek_chars( regex_arena & arena )

    {

        m_peek_chars_begin = 0;

 

        // optimization: find the lookahead characters for each alternate

        size_t total_chars = 0;

        peek_param<char_type> peek;

        typename alt_list_type::const_iterator ialt;

        for( ialt = m_rgalternates.begin(); m_rgalternates.end() != ialt; ++ialt )

        {

            if( ! (*ialt)->peek_this( peek ) )

            {

                peek.m_must_have.m_has = false;

                return peek.m_must_have;

            }

            total_chars += peek.m_cchars;

        }

 

        arena_allocator<char_type> alloc( arena );

        m_peek_chars_begin = alloc.allocate( total_chars, 0 );

        m_peek_chars_end   = m_peek_chars_begin;

 

        for( ialt = m_rgalternates.begin(); m_rgalternates.end() != ialt; ++ialt )

        {

            (*ialt)->peek_this( peek );

            char_type const * in = ( peek.m_cchars > 2 ) ? peek.m_pchars : peek.m_rgchars;

            m_peek_chars_end = std::copy( in, in + peek.m_cchars, m_peek_chars_end );

        }

 

        std::sort( m_peek_chars_begin, m_peek_chars_end );

        m_peek_chars_end = std::unique( m_peek_chars_begin, m_peek_chars_end );

 

        if( 1 < m_rgalternates.size() )

            peek.m_must_have.m_has = false;

 

        return peek.m_must_have;

    }

    size_t calternates() const

    {

        return m_rgalternates.size();

    }

    virtual void set_extent( extent_type const & )

    {

    }

    width_type group_width

    (

        std::vector<match_group_base<IterT>*> & rggroups,

        std::list<size_t> const &               invisible_groups

    )

    {

        // This should only be called on the top node

        REGEX_ASSERT( 0 == m_cgroup );

        if( uninit_width() == m_nwidth )

        {

            width_param<IterT> param( rggroups, invisible_groups );

            match_group_base<IterT>::width_this( param );

        }

        return m_nwidth;

    }

    virtual width_type width_this( width_param<IterT> & param )

    {

        typedef typename alt_list_type::const_iterator iter_type;

        width_type width = { size_t( -1 ), 0 };

        for( iter_type ialt = m_rgalternates.begin(); worst_width != width && m_rgalternates.end() != ialt; ++ialt )

        {

            // prevent possible infinite recursion

            if( m_cgroup < param.m_rggroups.size() )

                param.m_rggroups[ m_cgroup ] = 0;

 

            width_type temp_width = ( *ialt )->get_width( param );

 

            if( m_cgroup < param.m_rggroups.size() )

                param.m_rggroups[ m_cgroup ] = this;

 

            width.m_min = regex_min( width.m_min, temp_width.m_min );

            width.m_max = regex_max( width.m_max, temp_width.m_max );

        }

        return m_nwidth = width;

    }

    virtual bool peek_this( peek_param<char_type> & peek ) const

    {

        if( 0 == m_peek_chars_begin )

            return false;

 

        peek.m_cchars = std::distance( m_peek_chars_begin, m_peek_chars_end );

        if( 2 < peek.m_cchars )

            peek.m_pchars = m_peek_chars_begin;

        else

            std::copy( m_peek_chars_begin, m_peek_chars_end, peek.m_rgchars );

 

        peek.m_must_have.m_has = false;

        if( 1 == m_rgalternates.size() )

        {

            peek_param<char_type> local_peek;

            (*m_rgalternates.begin())->peek_this( local_peek );

            peek.m_must_have = local_peek.m_must_have;

        }

 

        return true;

    }

 

protected:

    void _cleanup()

    {

        typedef typename alt_list_type::const_iterator iter_type;

        for( iter_type ialt = m_rgalternates.begin(); m_rgalternates.end() != ialt; ++ialt )

            delete *ialt;

        m_rgalternates.clear();

    }

 

    virtual sub_expr<IterT> * _get_end_group() = 0;

 

    alt_list_type           m_rgalternates;

    size_t const            m_cgroup;

    width_type              m_nwidth;

 

    union

    {

        sub_expr<IterT>  ** m_pptail; // only used when adding elements

        char_type         * m_peek_chars_begin;

    };

 

    char_type             * m_peek_chars_end;

};

 

template< typename IterT >

inline match_group_base<IterT>::~match_group_base()

{

}

 

// A indestructable_sub_expr is an object that brings itself back

// to life after explicitly being deleted.  It is used

// to ease clean-up of the sub_expr graph, where most

// nodes are dynamically allocated, but some nodes are

// members of other nodes and are not dynamically allocated.

// The recursive delete of the sub_expr graph causes

// delete to be ( incorrectly ) called on these members.

// By inheriting these members from indestructable_sub_expr,

// explicit attempts to delete the object will have no

// effect. ( Actually, the object will be destructed and

// then immediately reconstructed. ) This is accomplished

// by calling placement new in operator delete.

template< typename IterT, typename T >

class indestructable_sub_expr : public sub_expr<IterT>

{

    static void * operator new( size_t, regex_arena & );

    static void operator delete( void *, regex_arena & );

protected:

    static void * operator new( size_t, void * pv ) { return pv; }

    static void operator delete( void *, void * ) {}

public:

    virtual ~indestructable_sub_expr() {}

    static void operator delete( void * pv ) { ::new( pv ) T; }

};

 

template< typename IterT >

class match_group : public match_group_base<IterT>

{

    match_group( match_group const & );

    match_group & operator=( match_group const & );

public:

    match_group( size_t cgroup, regex_arena & arena )

        : match_group_base<IterT>( cgroup, arena )

        , m_end_group( this )

    {

    }

 

    virtual ~match_group()

    {

        this->_cleanup();

    }

 

    virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )

    {

        if( greedy )

            return new( arena ) max_group_quantifier<IterT>( this, lbound, ubound );

        else

            return new( arena ) min_group_quantifier<IterT>( this, lbound, ubound );

    }

 

protected:

    typedef typename match_group_base<IterT>::alt_list_type alt_list_type;

 

    struct old_backref

    {

        IterT m_ibegin;

        IterT m_iend;

        bool  m_matched;

 

        old_backref() {}

        old_backref( backref_tag<IterT> const & br )

            : m_ibegin( br.first )

            , m_iend( br.second )

            , m_matched( br.matched )

        {

        }

    };

 

    static void restore_backref( backref_tag<IterT> & br, old_backref const & old_br )

    {

        br.first   = old_br.m_ibegin;

        br.second  = old_br.m_iend;

        br.matched = old_br.m_matched;

    }

 

    template< typename CStringsT >

    bool _do_call_back( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

    {

        if( size_t( -1 ) != this->m_cgroup )

        {

            backref_tag<IterT> & br = param.m_prgbackrefs[ this->m_cgroup ];

 

            // Save the relevant portions of the backref in an old_backref struct

            old_backref old_br( br );

 

            br.first   = br.reserved1;

            br.second  = icur;

            br.matched = true;

 

            if( this->recursive_match_next( param, icur, CStringsT() ) )

                return true;

 

            // Restore the backref to its saved state

            restore_backref( br, old_br );

        }

        else

        {

            if( this->recursive_match_next( param, icur, CStringsT() ) )

                return true;

        }

 

        return false;

    }

 

    class end_group : public indestructable_sub_expr<IterT, end_group>

    {

        match_group<IterT> const *const m_pgroup;

 

        end_group & operator=( end_group const & );

 

        void _push_frame( match_param<IterT> & param ) const

        {

            size_t cgroup = m_pgroup->group_number();

 

            if( size_t( -1 ) != cgroup )

            {

                backref_tag<IterT> & br = param.m_prgbackrefs[ cgroup ];

                old_backref old_br( br );

                param.m_pstack->push( old_br );

 

                br.first   = br.reserved1;

                br.second  = param.m_icur;

                br.matched = true;

            }

        }

        void _pop_frame( match_param<IterT> & param ) const

        {

            size_t cgroup = m_pgroup->group_number();

 

            if( size_t( -1 ) != cgroup )

            {

                old_backref old_br;

                param.m_pstack->pop( old_br );

                match_group<IterT>::restore_backref( param.m_prgbackrefs[ cgroup ], old_br );

            }

        }

        bool _do_iterative_match_this( match_param<IterT> & param ) const

        {

            _push_frame( param );

            param.m_pnext = m_pgroup->next();

            return true;

        }

        bool _do_iterative_rematch_this( match_param<IterT> & param ) const

        {

            _pop_frame( param );

            return false;

        }

    public:

        end_group( match_group<IterT> const * pgroup = 0 )

            : m_pgroup( pgroup )

        {

        }

        virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

        {

            return m_pgroup->REGEX_NVC6(template) _do_call_back REGEX_NVC6(<false_t>)( param, icur REGEX_VC6(COMMA false_t()) );

        }

        virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

        {

            return m_pgroup->REGEX_NVC6(template) _do_call_back REGEX_NVC6(<true_t>)( param, icur REGEX_VC6(COMMA true_t()) );

        }

        virtual bool iterative_match_this_s( match_param<IterT> & param ) const

        {

            return _do_iterative_match_this( param );

        }

        virtual bool iterative_match_this_c( match_param<IterT> & param ) const

        {

            return _do_iterative_match_this( param );

        }

        virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

        {

            return _do_iterative_rematch_this( param );

        }

        virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

        {

            return _do_iterative_rematch_this( param );

        }

        virtual width_type width_this( width_param<IterT> & )

        {

            return zero_width;

        }

    } m_end_group;

 

    friend class end_group;

 

    virtual sub_expr<IterT> * _get_end_group()

    {

        return & m_end_group;

    }

};

 

template< typename IterT >

inline void save_backrefs( backref_tag<IterT> const * ibegin, backref_tag<IterT> const * iend, IterT * prgci )

{

    for( ; ibegin != iend; ++ibegin, ++prgci )

    {

        new( prgci ) IterT( ibegin->reserved1 );

    }

}

 

template< typename IterT >

inline void restore_backrefs( backref_tag<IterT> * ibegin, backref_tag<IterT> * iend, IterT const * prgci )

{

    for( ; ibegin != iend; ++ibegin, ++prgci )

    {

        ibegin->reserved1 = *prgci;

        prgci->~IterT();

    }

}

 

template< typename IterT >

class group_wrapper : public sub_expr<IterT>

{

    match_group_base<IterT> const *const m_pgroup;

 

    group_wrapper & operator=( group_wrapper const & );

public:

    group_wrapper( match_group_base<IterT> const * pgroup )

        : m_pgroup( pgroup )

    {

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        return m_pgroup->match_group_base<IterT>::iterative_match_this_s( param );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        return m_pgroup->match_group_base<IterT>::iterative_match_this_c( param );

    }

    virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

    {

        return m_pgroup->match_group_base<IterT>::iterative_rematch_this_s( param );

    }

    virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

    {

        return m_pgroup->match_group_base<IterT>::iterative_rematch_this_c( param );

    }

    virtual width_type width_this( width_param<IterT> & )

    {

        return zero_width;

    }

};

 

struct deleter

{

    template< typename T >

    void operator()( T const & t )

    {

        t.T::~T();

    }

};

 

// Behaves like a lookahead assertion if m_cgroup is -1, or like

// an independent group otherwise.

template< typename IterT >

class independent_group_base : public match_group_base<IterT>

{

    independent_group_base( independent_group_base const & );

    independent_group_base & operator=( independent_group_base const & );

 

    template< typename CStringsT >

    bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

    {

        backref_tag<IterT> * prgbr = 0;

 

        // Copy onto the stack the part of the backref vector that could

        // be modified by the lookahead.

        if( m_extent.second )

        {

            prgbr = static_cast<backref_tag<IterT>*>( alloca( m_extent.second * sizeof( backref_tag<IterT> ) ) );

            std::uninitialized_copy(

                param.m_prgbackrefs + m_extent.first,

                param.m_prgbackrefs + m_extent.first + m_extent.second,

                prgbr );

        }

 

        // Match until the end of this group and then return

        // BUGBUG can the compiler optimize this?

        bool const fdomatch = CStringsT::value ?

            match_group_base<IterT>::recursive_match_all_c( param, icur ) :

            match_group_base<IterT>::recursive_match_all_s( param, icur );

 

        if( m_fexpected == fdomatch )

        {

            // If m_cgroup != 1, then this is not a zero-width assertion.

            if( fdomatch && size_t( -1 ) != this->m_cgroup )

                icur = param.m_prgbackrefs[ this->m_cgroup ].second;

 

            if( this->recursive_match_next( param, icur, CStringsT() ) )

            {

                std::for_each( prgbr, prgbr + m_extent.second, deleter() );

                return true;

            }

        }

 

        // if match_group::recursive_match_all returned true, the backrefs must be restored

        if( m_extent.second && fdomatch )

            std::copy( prgbr, prgbr + m_extent.second, param.m_prgbackrefs + m_extent.first );

 

        std::for_each( prgbr, prgbr + m_extent.second, deleter() );

        return false;

    }

    template< typename CStringsT >

    bool _do_iterative_match_this( match_param<IterT> & param REGEX_VC6(COMMA CStringsT) ) const

    {

        group_wrapper<IterT> expr( this );

 

        _push_frame( param );

        IterT ibegin = param.m_icur;

 

        bool const fdomatch = _do_match_iterative( &expr, param, param.m_icur, CStringsT() );

 

        if( m_fexpected == fdomatch )

        {

            // If m_cgroup == -1, then this is a zero-width assertion.

            if( fdomatch && size_t( -1 ) == this->m_cgroup )

                param.m_icur = ibegin;

 

            param.m_pnext = this->next();

            return true;

        }

 

        _pop_frame( param );

        return false;

    }

    bool _do_iterative_rematch_this( match_param<IterT> & param ) const

    {

        _pop_frame( param );

        return false;

    }

public:

    independent_group_base( size_t cgroup, regex_arena & arena )

        : match_group_base<IterT>( cgroup, arena )

        , m_fexpected( true )

        , m_extent( 0, 0 )

    {

    }

    virtual void set_extent( extent_type const & ex )

    {

        m_extent = ex;

    }

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_match_this REGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_match_this REGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this( param );

    }

    virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this( param );

    }

    virtual bool peek_this( peek_param<char_type> & peek ) const

    {

        if( size_t( -1 ) == this->m_cgroup )

            return false;

        return match_group_base<IterT>::peek_this( peek );

    }

protected:

 

    void _push_frame( match_param<IterT> & param ) const

    {

        unsafe_stack * pstack = param.m_pstack;

        typedef typename match_param<IterT>::backref_type backref_type;

        backref_type * ibegin = param.m_prgbackrefs + m_extent.first;

        backref_type * iend   = ibegin + m_extent.second;

 

        for( ; iend != ibegin; ++ibegin )

        {

            pstack->push( *ibegin );

        }

        pstack->push( param.m_icur );

    }

 

    void _pop_frame( match_param<IterT> & param ) const

    {

        unsafe_stack * pstack = param.m_pstack;

        typedef typename match_param<IterT>::backref_type backref_type;

 

        backref_type * ibegin = param.m_prgbackrefs + m_extent.first;

        backref_type * iend   = ibegin + m_extent.second;

 

        pstack->pop( param.m_icur );

        while( iend != ibegin )

        {

            pstack->pop( *--iend );

        }

    }

 

    independent_group_base( bool const fexpected, regex_arena & arena )

        : match_group_base<IterT>( size_t( -1 ), arena )

        , m_fexpected( fexpected )

    {

    }

 

    bool const  m_fexpected;

    extent_type m_extent;

};

 

template< typename IterT >

class independent_group : public independent_group_base<IterT>

{

    independent_group( independent_group const & );

    independent_group & operator=( independent_group const & );

public:

    independent_group( size_t cgroup, regex_arena & arena )

        : independent_group_base<IterT>( cgroup, arena )

        , m_end_group( this )

    {

    }

 

    virtual ~independent_group()

    {

        this->_cleanup();

    }

 

    virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )

    {

        if( greedy )

            return new( arena ) max_group_quantifier<IterT>( this, lbound, ubound );

        else

            return new( arena ) min_group_quantifier<IterT>( this, lbound, ubound );

    }

 

protected:

    independent_group( bool const fexpected, regex_arena & arena )

        : independent_group_base<IterT>( fexpected, arena )

        , m_end_group( this )

    {

    }

 

    bool _do_call_back( match_param<IterT> & param, IterT icur ) const

    {

        if( size_t( -1 ) != this->m_cgroup )

        {

            backref_tag<IterT> & br = param.m_prgbackrefs[ this->m_cgroup ];

            br.first   = br.reserved1;

            br.second  = icur;

            br.matched = true;

        }

        return true;

    }

 

    class end_group : public indestructable_sub_expr<IterT, end_group>

    {

        independent_group<IterT> const *const m_pgroup;

 

        end_group & operator=( end_group const & );

        bool _do_iterative_match_this( match_param<IterT> & param ) const

        {

            size_t cgroup = m_pgroup->group_number();

            if( size_t( -1 ) != cgroup )

            {

                backref_tag<IterT> & br = param.m_prgbackrefs[ cgroup ];

                br.first   = br.reserved1;

                br.second  = param.m_icur;

                br.matched = true;

            }

            param.m_pnext = 0;

            return true;

        }

    public:

        end_group( independent_group<IterT> const * pgroup = 0 )

            : m_pgroup( pgroup )

        {

        }

        virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

        {

            return m_pgroup->_do_call_back( param, icur );

        }

        virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

        {

            return m_pgroup->_do_call_back( param, icur );

        }

        virtual bool iterative_match_this_s( match_param<IterT> & param ) const

        {

            return _do_iterative_match_this( param );

        }

        virtual bool iterative_match_this_c( match_param<IterT> & param ) const

        {

            return _do_iterative_match_this( param );

        }

        virtual width_type width_this( width_param<IterT> & )

        {

            return zero_width;

        }

    } m_end_group;

 

    friend class end_group;

 

    virtual sub_expr<IterT> * _get_end_group()

    {

        return & m_end_group;

    }

};

 

template< typename IterT >

class lookahead_assertion : public independent_group<IterT>

{

    lookahead_assertion( lookahead_assertion const & );

    lookahead_assertion & operator=( lookahead_assertion const & );

public:

    lookahead_assertion( bool const fexpected, regex_arena & arena )

        : independent_group<IterT>( fexpected, arena )

    {

    }

    virtual sub_expr<IterT> * quantify( size_t, size_t, bool, regex_arena & )

    {

        throw bad_regexpr( "look-ahead assertion cannot be quantified" );

    }

    virtual bool is_assertion() const

    {

        return true;

    }

    virtual width_type width_this( width_param<IterT> & param )

    {

        // calculate the group's width and store it, but return zero_width

        match_group_base<IterT>::width_this( param );

        return zero_width;

    }

    virtual bool peek_this( peek_param<char_type> & peek ) const

    {

        return this->next()->peek_this( peek );

    }

};

 

template< typename IterT >

class lookbehind_assertion : public independent_group_base<IterT>

{

    lookbehind_assertion( lookbehind_assertion const & );

    lookbehind_assertion & operator=( lookbehind_assertion const & );

 

    template< typename CStringsT >

    bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

    {

        typedef typename std::iterator_traits<IterT>::difference_type diff_type;

 

        // This is the room in the string from the start to the current position

        diff_type room = std::distance( param.m_ibufferbegin, icur );

 

        // If we don't have enough room to match the lookbehind, the match fails.

        // If we wanted the match to fail, try to match the rest of the pattern.

        if( this->m_nwidth.m_min > static_cast<size_t>( room ) )

            return this->m_fexpected ? false : this->recursive_match_next( param, icur, CStringsT() );

 

        backref_tag<IterT> * prgbr = 0;

 

        // Copy onto the stack the part of the backref vector that could

        // be modified by the lookbehind.

        if( this->m_extent.second )

        {

            prgbr = static_cast<backref_tag<IterT>*>( alloca( this->m_extent.second * sizeof( backref_tag<IterT> ) ) );

            std::uninitialized_copy(

                param.m_prgbackrefs + this->m_extent.first,

                param.m_prgbackrefs + this->m_extent.first + this->m_extent.second,

                prgbr );

        }

 

        IterT local_ibegin  = icur;

        std::advance( local_ibegin, -static_cast<diff_type>( regex_min<size_t>( this->m_nwidth.m_max, room ) ) );

 

        IterT local_iend = icur;

        std::advance( local_iend, -static_cast<diff_type>( this->m_nwidth.m_min ) );

 

        // Create a local param struct that has icur as param.m_iend

        match_param<IterT> local_param( param.m_ibufferbegin, param.m_imatchbegin, icur, param.m_prgbackrefs, param.m_cbackrefs );

 

        // Find the rightmost match that ends at icur.

        for( IterT local_icur = local_ibegin; ; ++local_icur )

        {

            // Match until the end of this group and then return

            // Note that we're calling recursive_match_all_s regardless of the CStringsT switch.

            // This is because for the lookbehind assertion, the termination condition is when

            // icur == param.m_iend, not when *icur == '/0'

            bool const fmatched = match_group_base<IterT>::recursive_match_all_s( local_param, local_icur );

 

            // If the match results were what we were expecting, try to match the

            // rest of the pattern. If that succeeds, return true.

            if( this->m_fexpected == fmatched && this->recursive_match_next( param, icur, CStringsT() ) )

            {

                std::for_each( prgbr, prgbr + this->m_extent.second, deleter() );

                return true;

            }

 

            // if match_group::recursive_match_all returned true, the backrefs must be restored

            if( fmatched )

            {

                if( this->m_extent.second )

                    std::copy( prgbr, prgbr + this->m_extent.second, param.m_prgbackrefs + this->m_extent.first );

 

                // Match succeeded. If this is a negative lookbehind, we didn't want it

                // to succeed, so return false.

                if( ! this->m_fexpected )

                {

                    std::for_each( prgbr, prgbr + this->m_extent.second, deleter() );

                    return false;

                }

            }

 

            if( local_icur == local_iend )

                break;

        }

 

        // No variation of the lookbehind was satisfied in a way that permited

        // the rest of the pattern to match successfully, so return false.

        std::for_each( prgbr, prgbr + this->m_extent.second, deleter() );

        return false;

    }

 

    template< typename CStringsT >

    bool _do_iterative_match_this( match_param<IterT> & param REGEX_VC6(COMMA CStringsT) ) const

    {

        typedef typename std::iterator_traits<IterT>::difference_type diff_type;

 

        // Save the backrefs

        this->_push_frame( param );

 

        // This is the room in the string from the start to the current position

        diff_type room = std::distance( param.m_ibufferbegin, param.m_icur );

 

        // If we don't have enough room to match the lookbehind, the match fails.

        // If we wanted the match to fail, try to match the rest of the pattern.

        if( this->m_nwidth.m_min > static_cast<size_t>( room ) )

        {

            if( this->m_fexpected )

            {

                this->_pop_frame( param );

                return false;

            }

            param.m_pnext = this->next();

            return true;

        }

 

        IterT local_ibegin  = param.m_icur;

        std::advance( local_ibegin, -static_cast<diff_type>( regex_min<size_t>( this->m_nwidth.m_max, room ) ) );

 

        IterT local_iend = param.m_icur;

        std::advance( local_iend, -static_cast<diff_type>( this->m_nwidth.m_min ) );

 

        // Create a local param struct that has icur as param.m_iend

        match_param<IterT> local_param( param.m_ibufferbegin, param.m_imatchbegin, param.m_icur, param.m_prgbackrefs, param.m_cbackrefs );

        local_param.m_pstack = param.m_pstack;

 

        group_wrapper<IterT> expr( this );

 

        // Find the rightmost match that ends at icur.

        for( IterT local_icur = local_ibegin; ; ++local_icur )

        {

            // Match until the end of this group and then return

            // Note that we're calling _do_match_iterative_helper_s regardless of the CStringsT switch.

            // This is because for the lookbehind assertion, the termination condition is when

            // icur == param.m_iend, not when *icur == '/0'

            bool const fmatched = regex_access<IterT>::_do_match_iterative_helper_s( &expr, local_param, local_icur );

 

            // If the match results were what we were expecting, try to match the

            // rest of the pattern. If that succeeds, return true.

            if( this->m_fexpected == fmatched )

            {

                param.m_pnext = this->next();

                return true;

            }

 

            // if match_group::recursive_match_all returned true, the backrefs must be restored

            if( fmatched )

            {

                // Restore the backrefs

                this->_pop_frame( param );

 

                // Match succeeded. If this is a negative lookbehind, we didn't want it

                // to succeed, so return false.

                if( ! this->m_fexpected )

                    return false;

 

                // Save the backrefs again.

                this->_push_frame( param );

            }

 

            if( local_icur == local_iend )

                break;

        }

 

        // No variation of the lookbehind was satisfied in a way that permited

        // the rest of the pattern to match successfully, so return false.

        this->_pop_frame( param );

        return false;

    }

    bool _do_iterative_rematch_this( match_param<IterT> & param ) const

    {

        this->_pop_frame( param );

        return false;

    }

public:

    lookbehind_assertion( bool const fexpected, regex_arena & arena )

        : independent_group_base<IterT>( fexpected, arena )

    {

    }

 

    virtual ~lookbehind_assertion()

    {

        this->_cleanup();

    }

 

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_match_this REGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_match_this REGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this( param );

    }

    virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this( param );

    }

 

    virtual bool is_assertion() const

    {

        return true;

    }

    virtual width_type width_this( width_param<IterT> & param )

    {

        // calculate the group's width and store it, but return zero_width

        match_group_base<IterT>::width_this( param );

        return zero_width;

    }

    virtual bool peek_this( peek_param<char_type> & peek ) const

    {

        return this->next()->peek_this( peek );

    }

 

protected:

    struct end_group : public indestructable_sub_expr<IterT, end_group>

    {

        virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

        {

            return param.m_iend == icur;

        }

        virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

        {

            return param.m_iend == icur;

        }

        virtual bool iterative_match_this_s( match_param<IterT> & param ) const

        {

            param.m_pnext = 0;

            return param.m_iend == param.m_icur;

        }

        virtual bool iterative_match_this_c( match_param<IterT> & param ) const

        {

            param.m_pnext = 0;

            return param.m_iend == param.m_icur;

        }

        virtual width_type width_this( width_param<IterT> & )

        {

            return zero_width;

        }

    } m_end_group;

 

    virtual sub_expr<IterT> * _get_end_group()

    {

        return & m_end_group;

    }

};

 

template< typename IterT >

class group_quantifier : public match_quantifier<IterT>

{

    group_quantifier & operator=( group_quantifier const & );

 

    bool _do_iterative_match_this( match_param<IterT> & param ) const

    {

        _push_frame( param );

        param.m_pnext = this->m_psub->next(); // ptr to end_quant

        return true;

    }

    bool _do_iterative_rematch_this( match_param<IterT> & param ) const

    {

        _pop_frame( param );

        return false;

    }

public:

    group_quantifier

    (

        match_group_base<IterT> * psub,

        size_t lbound,

        size_t ubound,

        sub_expr<IterT> * pend_quant

    )

        : match_quantifier<IterT>( psub, lbound, ubound )

        , m_group( *psub )

    {

        *psub->pnext() = pend_quant;

    }

 

    // sub-classes of group_quantifer that own the end_quant

    // object must declare a destructor, and it must call _cleanup

    virtual ~group_quantifier() = 0;

 

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_match_this( param );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_match_this( param );

    }

    virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this( param );

    }

    virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this( param );

    }

 

protected:

    struct old_quant

    {

        typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;

 

        size_t          reserved2;

        bool            reserved3;

        smart_iter_type reserved4;

        smart_iter_type reserved5;

 

        old_quant()

        {

        }

        old_quant( backref_tag<IterT> const & br )

            : reserved2( br.reserved2 )

            , reserved3( br.reserved3 )

            , reserved4( br.reserved4 )

            , reserved5( br.reserved5 )

        {

        }

    };

 

    void _push_frame( match_param<IterT> & param ) const

    {

        typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;

 

        backref_tag<IterT> & br = param.m_prgbackrefs[ group_number() ];

        old_quant old_qt( br );

        param.m_pstack->push( old_qt );

 

        br.reserved2 = 0;    // nbr of times this group has matched

        br.reserved3 = true; // toggle used for backtracking

        br.reserved4 = static_init<smart_iter_type>::value;

        br.reserved5 = static_init<smart_iter_type>::value;

    }

 

    void _pop_frame( match_param<IterT> & param ) const

    {

        backref_tag<IterT> & br = param.m_prgbackrefs[ group_number() ];

        old_quant old_qt;

        param.m_pstack->pop( old_qt );

 

        br.reserved2 = old_qt.reserved2;

        br.reserved3 = old_qt.reserved3;

        br.reserved4 = old_qt.reserved4;

        br.reserved5 = old_qt.reserved5;

    }

 

    size_t group_number() const

    {

        return m_group.group_number();

    }

 

    size_t & cmatches( match_param<IterT> & param ) const

    {

        return param.m_prgbackrefs[ group_number() ].reserved2;

    }

 

    typename backref_tag<IterT>::smart_iter_type & highwater1( match_param<IterT> & param ) const

    {

        return param.m_prgbackrefs[ group_number() ].reserved4;

    }

 

    typename backref_tag<IterT>::smart_iter_type & highwater2( match_param<IterT> & param ) const

    {

        return param.m_prgbackrefs[ group_number() ].reserved5;

    }

 

    match_group_base<IterT> const & m_group;

};

 

template< typename IterT >

inline group_quantifier<IterT>::~group_quantifier()

{

}

 

template< typename IterT >

class max_group_quantifier : public group_quantifier<IterT>

{

    max_group_quantifier & operator=( max_group_quantifier const & );

 

    template< typename CStringsT >

    bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

    {

        typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;

 

        smart_iter_type old_highwater1 = this->highwater1( param );

        smart_iter_type old_highwater2 = this->highwater2( param );

        size_t          old_cmatches   = this->cmatches( param );

 

        this->highwater1( param ) = static_init<smart_iter_type>::value;

        this->highwater2( param ) = icur;

        this->cmatches( param )   = 0;

 

        if( _do_recurse REGEX_NVC6(<CStringsT>) ( param, icur REGEX_VC6(COMMA CStringsT()) ) )

            return true;

 

        this->cmatches( param )   = old_cmatches;

        this->highwater2( param ) = old_highwater2;

        this->highwater1( param ) = old_highwater1;

 

        return false;

    }

public:

    max_group_quantifier( match_group_base<IterT> * psub, size_t lbound, size_t ubound )

        : group_quantifier<IterT>( psub, lbound, ubound, & m_end_quant )

        , m_end_quant( this )

    {

    }

 

    virtual ~max_group_quantifier()

    {

        // Must call _cleanup() here before the end_quant object

        // gets destroyed.

        this->_cleanup();

    }

 

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

 

protected:

    template< typename CStringsT >

    bool _do_recurse( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

    {

        if( this->m_ubound == this->cmatches( param ) )

            return this->recursive_match_next( param, icur, CStringsT() );

 

        ++this->cmatches( param );

        if( this->m_psub->recursive_match_all( param, icur, CStringsT() ) )

            return true;

 

        if( --this->cmatches( param ) < this->m_lbound )

            return false;

 

        return this->recursive_match_next( param, icur, CStringsT() );

    }

 

    class end_quantifier : public indestructable_sub_expr<IterT, end_quantifier>

    {

        max_group_quantifier<IterT> const *const m_pquant;

 

        end_quantifier & operator=( end_quantifier const & );

 

        void _push_frame( match_param<IterT> & param ) const

        {

            backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];

            param.m_pstack->push( br.reserved4 );

            br.reserved4 = br.reserved5;

            br.reserved5 = param.m_icur;

        }

 

        void _pop_frame( match_param<IterT> & param ) const

        {

            backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];

            br.reserved5 = br.reserved4;

            param.m_pstack->pop( br.reserved4 );

        }

 

        template< typename CStringsT >

        bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

        {

            typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;

            smart_iter_type old_highwater1 = m_pquant->highwater1( param );

 

            if( icur == old_highwater1 )

                return m_pquant->recursive_match_next( param, icur, CStringsT() );

 

            m_pquant->highwater1( param ) = m_pquant->highwater2( param );

            m_pquant->highwater2( param ) = icur;

 

            if( m_pquant->REGEX_NVC6(template) _do_recurse REGEX_NVC6(<CStringsT>) ( param, icur REGEX_VC6(COMMA CStringsT()) ) )

                return true;

 

            m_pquant->highwater2( param ) = m_pquant->highwater1( param );

            m_pquant->highwater1( param ) = old_highwater1;

 

            return false;

        }

        bool _do_iterative_match_this( match_param<IterT> & param ) const

        {

            backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];

 

            // forcibly break the infinite loop

            if( param.m_icur == br.reserved4 )

            {

                _push_frame( param );

                param.m_pnext = m_pquant->next();

                return true;

            }

 

            _push_frame( param );

 

            // If we've matched the max nbr of times, move on to the next

            // sub-expr.

            if( m_pquant->m_ubound == br.reserved2 )

            {

                param.m_pnext = m_pquant->next();

                br.reserved3 = false;

                return true;

            }

 

            // Rematch the group.

            br.reserved3 = true;

            param.m_pnext = m_pquant->m_psub;

            ++br.reserved2;

            return true;

        }

        bool _do_iterative_rematch_this( match_param<IterT> & param ) const

        {

            typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;

 

            backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];

 

            // infinite loop forcibly broken

            if( param.m_icur == param.m_pstack->REGEX_NVC6(template) top REGEX_NVC6(<smart_iter_type>) ( REGEX_VC6(type2type<smart_iter_type>()) ) )

            {

                _pop_frame( param );

                return false;

            }

 

            if( br.reserved3 )

            {

                --br.reserved2;

                param.m_pnext = m_pquant->next();

                if( m_pquant->m_lbound <= br.reserved2 )

                {

                    br.reserved3 = false;

                    return true;

                }

                _pop_frame( param );

                return false;

            }

            br.reserved3 = true;

            _pop_frame( param );

            return false;

        }

    public:

        end_quantifier( max_group_quantifier<IterT> const * pquant = 0 )

            : m_pquant( pquant )

        {

        }

        virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

        {

            return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

        }

        virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

        {

            return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

        }

        virtual bool iterative_match_this_s( match_param<IterT> & param ) const

        {

            return _do_iterative_match_this( param );

        }

        virtual bool iterative_match_this_c( match_param<IterT> & param ) const

        {

            return _do_iterative_match_this( param );

        }

        virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

        {

            return _do_iterative_rematch_this( param );

        }

        virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

        {

            return _do_iterative_rematch_this( param );

        }

        virtual width_type width_this( width_param<IterT> & )

        {

            return zero_width;

        }

    } m_end_quant;

 

    friend class end_quantifier;

};

 

template< typename IterT >

class min_group_quantifier : public group_quantifier<IterT>

{

    min_group_quantifier & operator=( min_group_quantifier const & );

 

    template< typename CStringsT >

    bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

    {

        typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;

 

        smart_iter_type old_highwater1 = this->highwater1( param );

        smart_iter_type old_highwater2 = this->highwater2( param );

        size_t          old_cmatches   = this->cmatches( param );

 

        this->highwater1( param ) = static_init<smart_iter_type>::value;

        this->highwater2( param ) = icur;

        this->cmatches( param )   = 0;

 

        if( _do_recurse REGEX_NVC6(<CStringsT>) ( param, icur REGEX_VC6(COMMA CStringsT()) ) )

            return true;

 

        this->cmatches( param )   = old_cmatches;

        this->highwater2( param ) = old_highwater2;

        this->highwater1( param ) = old_highwater1;

 

        return false;

    }

public:

    min_group_quantifier( match_group_base<IterT> * psub, size_t lbound, size_t ubound )

        : group_quantifier<IterT>( psub, lbound, ubound, & m_end_quant )

        , m_end_quant( this )

    {

    }

 

    virtual ~min_group_quantifier()

    {

        // Must call _cleanup() here before the end_quant object

        // gets destroyed.

        this->_cleanup();

    }

 

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

 

protected:

 

    template< typename CStringsT >

    bool _do_recurse( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

    {

        if( this->m_lbound <= this->cmatches( param ) )

        {

            if( this->recursive_match_next( param, icur, CStringsT() ) )

                return true;

        }

 

        if( this->m_ubound > this->cmatches( param ) )

        {

            ++this->cmatches( param );

            if( this->m_psub->recursive_match_all( param, icur, CStringsT() ) )

                return true;

            --this->cmatches( param );

        }

 

        return false;

    }

 

    class end_quantifier : public indestructable_sub_expr<IterT, end_quantifier>

    {

        min_group_quantifier<IterT> const *const m_pquant;

 

        end_quantifier & operator=( end_quantifier const & );

 

        void _push_frame( match_param<IterT> & param ) const

        {

            backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];

            param.m_pstack->push( br.reserved4 );

            br.reserved4 = br.reserved5;

            br.reserved5 = param.m_icur;

        }

 

        void _pop_frame( match_param<IterT> & param ) const

        {

            backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];

            br.reserved5 = br.reserved4;

            param.m_pstack->pop( br.reserved4 );

        }

 

        template< typename CStringsT >

        bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

        {

            typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;

 

            smart_iter_type old_highwater1 = m_pquant->highwater1( param );

 

            if( icur == old_highwater1 )

                return m_pquant->recursive_match_next( param, icur, CStringsT() );

 

            m_pquant->highwater1( param ) = m_pquant->highwater2( param );

            m_pquant->highwater2( param ) = icur;

 

            if( m_pquant->REGEX_NVC6(template) _do_recurse REGEX_NVC6(<CStringsT>) ( param, icur REGEX_VC6(COMMA CStringsT()) ) )

                return true;

 

            m_pquant->highwater2( param ) = m_pquant->highwater1( param );

            m_pquant->highwater1( param ) = old_highwater1;

 

            return false;

        }

 

        bool _do_iterative_match_this( match_param<IterT> & param ) const

        {

            backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];

 

            // forcibly break the infinite loop

            if( param.m_icur == br.reserved4 )

            {

                _push_frame( param );

                param.m_pnext = m_pquant->next();

                return true;

            }

 

            _push_frame( param );

 

            if( m_pquant->m_lbound <= br.reserved2 )

            {

                br.reserved3 = false;

                param.m_pnext = m_pquant->next();

                return true;

            }

 

            ++br.reserved2;

            param.m_pnext = m_pquant->m_psub;

 

            return true;

        }

 

        bool _do_iterative_rematch_this( match_param<IterT> & param ) const

        {

            typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;

 

            backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];

 

            // infinite loop forcibly broken

            if( param.m_icur == param.m_pstack->REGEX_NVC6(template) top REGEX_NVC6(<smart_iter_type>) ( REGEX_VC6(type2type<smart_iter_type>()) ) )

            {

                _pop_frame( param );

                return false;

            }

 

            if( br.reserved3 )

            {

                --br.reserved2;

 

                _pop_frame( param );

                return false;

            }

 

            br.reserved3 = true;

 

            if( m_pquant->m_ubound > br.reserved2 )

            {

                ++br.reserved2;

                param.m_pnext = m_pquant->m_psub;

                return true;

            }

 

            _pop_frame( param );

            return false;

        }

    public:

        end_quantifier( min_group_quantifier<IterT> const * pquant = 0 )

            : m_pquant( pquant )

        {

        }

 

        virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

        {

            return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

        }

        virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

        {

            return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

        }

        virtual bool iterative_match_this_s( match_param<IterT> & param ) const

        {

            return _do_iterative_match_this( param );

        }

        virtual bool iterative_match_this_c( match_param<IterT> & param ) const

        {

            return _do_iterative_match_this( param );

        }

        virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

        {

            return _do_iterative_rematch_this( param );

        }

        virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

        {

            return _do_iterative_rematch_this( param );

        }

        virtual width_type width_this( width_param<IterT> & )

        {

            return zero_width;

        }

    } m_end_quant;

 

    friend class end_quantifier;

};

 

inline void fixup_backref( size_t & cbackref, std::list<size_t> const & invisible_groups )

{

    std::list<size_t>::const_iterator iter = invisible_groups.begin();

    for( ; invisible_groups.end() != iter && cbackref >= *iter; ++iter )

    {

        ++cbackref;

    }

}

 

template< typename IterT >

class match_backref : public sub_expr<IterT>

{

    bool _do_iterative_rematch_this( match_param<IterT> & param ) const

    {

        typedef typename std::iterator_traits<IterT>::difference_type diff_type;

        backref_tag<IterT> const & br = param.m_prgbackrefs[ m_nbackref ];

        diff_type dist = std::distance( br.first, br.second );

        std::advance( param.m_icur, -dist );

        return false;

    }

public:

    match_backref( size_t nbackref )

        : m_nbackref( nbackref )

    {

    }

 

    // Return the width specifications of the group to which this backref refers

    virtual width_type width_this( width_param<IterT> & param )

    {

        // fix up the backref to take into account the number of invisible groups

        fixup_backref( m_nbackref, param.m_invisible_groups );

 

        if( m_nbackref >= param.m_rggroups.size() )

            throw bad_regexpr( "reference to nonexistent group" );

 

        // If the entry in the backref vector has been nulled out, then we are

        // calculating the width for this group.

        if( 0 == param.m_rggroups[ m_nbackref ] )

            return worst_width; // can't tell how wide this group will be.  :-(

 

        return param.m_rggroups[ m_nbackref ]->width_this( param );

    }

    virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this( param );

    }

    virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this( param );

    }

protected:

    size_t m_nbackref;

};

 

template< typename CmpT, typename IterT >

class match_backref_t : public match_backref<IterT>

{

public:

    match_backref_t( size_t nbackref )

        : match_backref<IterT>( nbackref )

    {

    }

    virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )

    {

        if( greedy )

            return new( arena ) max_atom_quantifier<IterT, match_backref_t<CmpT, IterT> >( this, lbound, ubound );

        else

            return new( arena ) min_atom_quantifier<IterT, match_backref_t<CmpT, IterT> >( this, lbound, ubound );

    }

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return ( match_backref_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return ( match_backref_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );

    }

    virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const

    {

        return _do_match_this REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this REGEX_NVC6(<false_t>) ( param, param.m_icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        param.m_pnext = this->next();

        return _do_match_this REGEX_NVC6(<true_t>) ( param, param.m_icur REGEX_VC6(COMMA true_t()) );

    }

protected:

    template< typename CStringsT >

    bool _do_match_this( match_param<IterT> & param, IterT & icur REGEX_VC6(COMMA CStringsT) ) const

    {

        // Pattern compilation should have failed if the following is false:

        REGEX_ASSERT( this->m_nbackref < param.m_cbackrefs );

 

        // Don't match a backref that hasn't match anything

        if( ! param.m_prgbackrefs[ this->m_nbackref ].matched )

            return false;

 

        IterT ithis       = param.m_prgbackrefs[ this->m_nbackref ].first;

        IterT const iend  = param.m_prgbackrefs[ this->m_nbackref ].second;

        IterT icur_tmp    = icur;

 

        for( ; iend != ithis; ++icur_tmp, ++ithis )

        {

            if( eos_t<CStringsT>::eval( param, icur_tmp ) || CmpT::eval( *icur_tmp, *ithis ) )

                return false;

        }

        icur = icur_tmp;

        return true;

    }

};

 

template< typename IterT >

inline match_backref<IterT> * create_backref(

    size_t cbackref,

    REGEX_FLAGS flags, regex_arena & arena )

{

    typedef typename std::iterator_traits<IterT>::value_type char_type;

 

    switch( NOCASE & flags )

    {

    case 0:

        return new( arena ) match_backref_t<ch_neq_t<char_type>, IterT>( cbackref );

    case NOCASE:

        return new( arena ) match_backref_t<ch_neq_nocase_t<char_type>, IterT>( cbackref );

    default:

        REGEX_ASSERT(false);

        return 0;

    }

}

 

template< typename IterT >

class match_recurse : public sub_expr<IterT>

{

    match_recurse & operator=( match_recurse const & );

 

    void _push_frame( match_param<IterT> & param ) const

    {

        typedef typename match_param<IterT>::backref_type backref_type;

        unsafe_stack * pstack = param.m_pstack;

        backref_type * ibegin = param.m_prgbackrefs;

        backref_type * iend   = ibegin + param.m_cbackrefs;

        for( ; iend != ibegin; ++ibegin )

        {

            pstack->push( ibegin->reserved1 );

        }

    }

 

    void _pop_frame( match_param<IterT> & param ) const

    {

        typedef typename match_param<IterT>::backref_type backref_type;

        unsafe_stack * pstack = param.m_pstack;

        backref_type * ibegin = param.m_prgbackrefs;

        backref_type * iend   = ibegin + param.m_cbackrefs;

        while( iend != ibegin )

        {

            --iend;

            pstack->pop( iend->reserved1 );

        }

    }

 

    template< typename CStringsT >

    bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

    {

        // Prevent infinite recursion. If icur == param.m_prgbackrefs[ 0 ].reserved1,

        // then the pattern has eaten 0 chars to date, and we would recurse forever.

        if( icur == param.m_prgbackrefs[ 0 ].reserved1 )

            return this->recursive_match_next( param, icur, CStringsT() );

 

        // copy the backref vector onto the stack

        IterT * prgci = static_cast<IterT*>( alloca( param.m_cbackrefs * sizeof( IterT ) ) );

        save_backrefs<IterT>( param.m_prgbackrefs, param.m_prgbackrefs + param.m_cbackrefs, prgci );

 

        // Recurse.

        if( param.m_pfirst->recursive_match_all( param, icur, CStringsT() ) )

        {

            // Restore the backref vector

            restore_backrefs<IterT>( param.m_prgbackrefs, param.m_prgbackrefs + param.m_cbackrefs, prgci );

 

            // Recursive match succeeded. Try to match the rest of the pattern

            // using the end of the recursive match as the start of the next

            return this->recursive_match_next( param, param.m_prgbackrefs[ 0 ].second, CStringsT() );

        }

 

        // Recursion failed

        std::for_each( prgci, prgci + param.m_cbackrefs, deleter() );

        return false;

    }

    template< typename CStringsT >

    bool _do_iterative_match_this( match_param<IterT> & param REGEX_VC6(COMMA CStringsT) ) const

    {

        param.m_pstack->push( param.m_icur );

 

        // Prevent infine recursion

        if( param.m_icur == param.m_prgbackrefs[ 0 ].reserved1 )

        {

            param.m_pnext = this->next();

            return true;

        }

 

        _push_frame( param );

 

        if( _do_match_iterative( param.m_pfirst, param, param.m_icur, CStringsT() ) )

        {

            _pop_frame( param );

            param.m_pnext = this->next();

            return true;

        }

 

        _pop_frame( param );

        param.m_pstack->pop( param.m_icur );

        return false;

    }

    bool _do_iterative_rematch_this( match_param<IterT> & param ) const

    {

        param.m_pstack->pop( param.m_icur );

        return false;

    }

public:

    match_recurse()

    {

    }

 

    virtual sub_expr<IterT> * quantify( size_t, size_t, bool, regex_arena & )

    {

        throw bad_regexpr( "recursion sub-expression cannot be quantified" );

    }

 

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_match_this REGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_match_this REGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this( param );

    }

    virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this( param );

    }

    virtual width_type width_this( width_param<IterT> & )

    {

        return worst_width;

    }

};

 

template< typename IterT >

inline match_recurse<IterT> * create_recurse( regex_arena & arena )

{

    return new( arena ) match_recurse<IterT>();

}

 

template< typename IterT >

struct backref_condition

{

    size_t m_cbackref;

 

    backref_condition( size_t cbackref )

        : m_cbackref( cbackref )

    {

    }

 

    template< typename CStringsT >

    bool recursive_match_this( match_param<IterT> & param, IterT, CStringsT ) const

    {

        return m_cbackref < param.m_cbackrefs && param.m_prgbackrefs[ m_cbackref ].matched;

    }

    template< typename CStringsT >

    bool iterative_match_this( match_param<IterT> & param, CStringsT ) const

    {

        return m_cbackref < param.m_cbackrefs && param.m_prgbackrefs[ m_cbackref ].matched;

    }

    template< typename CStringsT >

    bool iterative_rematch_this( match_param<IterT> &, CStringsT ) const

    {

        return false;

    }

    void width_this( width_param<IterT> & param )

    {

        // fix up the backref to take into account the number of invisible groups

        fixup_backref( m_cbackref, param.m_invisible_groups );

    }

};

 

template< typename IterT >

struct assertion_condition

{

    std::auto_ptr<match_group_base<IterT> > m_passert;

 

    assertion_condition( match_group_base<IterT> * passert , regex_arena & arena )

        : m_passert( passert )

    {

        *passert->pnext() = new( arena ) end_of_pattern<IterT>;

    }

 

    bool recursive_match_this( match_param<IterT> & param, IterT icur, false_t ) const

    {

        return m_passert->recursive_match_all_s( param, icur );

    }

    bool recursive_match_this( match_param<IterT> & param, IterT icur, true_t ) const

    {

        return m_passert->recursive_match_all_c( param, icur );

    }

    bool iterative_match_this( match_param<IterT> & param, false_t ) const

    {

        return m_passert->iterative_match_this_s( param );

    }

    bool iterative_match_this( match_param<IterT> & param, true_t ) const

    {

        return m_passert->iterative_match_this_c( param );

    }

    bool iterative_rematch_this( match_param<IterT> & param, false_t ) const

    {

        return m_passert->iterative_rematch_this_s( param );

    }

    bool iterative_rematch_this( match_param<IterT> & param, true_t ) const

    {

        return m_passert->iterative_rematch_this_c( param );

    }

    void width_this( width_param<IterT> & param )

    {

        ( void ) m_passert->width_this( param );

    }

};

 

template< typename IterT, typename CondT >

class match_conditional : public match_group<IterT>

{

protected:

    typedef typename match_group<IterT>::alt_list_type alt_list_type;

 

private:

    match_conditional & operator=( match_conditional const & );

 

    template< typename CStringsT >

    bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const

    {

        typedef typename alt_list_type::const_iterator iter_type;

        iter_type ialt = this->m_rgalternates.begin();

 

        if( m_condition.recursive_match_this( param, icur, CStringsT() ) || this->m_rgalternates.end() != ++ialt )

        {

            return (*ialt)->recursive_match_all( param, icur, CStringsT() );

        }

        return this->recursive_match_next( param, icur, CStringsT() );

    }

    template< typename CStringsT >

    bool _do_iterative_match_this( match_param<IterT> & param REGEX_VC6(COMMA CStringsT) ) const

    {

        typedef typename alt_list_type::const_iterator iter_type;

        iter_type ialt = this->m_rgalternates.begin();

 

        if( m_condition.iterative_match_this( param, CStringsT() ) )

        {

            param.m_pstack->push( true );

            param.m_pnext = *ialt;

            return true;

        }

        param.m_pstack->push( false );

        param.m_pnext = ( this->m_rgalternates.end() != ++ialt ) ? *ialt : this->next();

        return true;

    }

    template< typename CStringsT >

    bool _do_iterative_rematch_this( match_param<IterT> & param REGEX_VC6(COMMA CStringsT) ) const

    {

        bool condition;

        param.m_pstack->pop( condition );

        if( condition )

            m_condition.iterative_rematch_this( param, CStringsT() );

        return false;

    }

public:

    typedef CondT condition_type;

 

    match_conditional( size_t cgroup, condition_type condition, regex_arena & arena )

        : match_group<IterT>( cgroup, arena )

        , m_condition( condition )

    {

    }

 

    virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );

    }

    virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const

    {

        return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_match_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_match_this REGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );

    }

    virtual bool iterative_match_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_match_this REGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );

    }

    virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this REGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );

    }

    virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const

    {

        return _do_iterative_rematch_this REGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );

    }

    virtual width_type width_this( width_param<IterT> & param )

    {

        typedef typename alt_list_type::const_iterator iter_type;

        iter_type ialt = this->m_rgalternates.begin();

 

        width_type width = ( *ialt )->get_width( param );

 

        if( this->m_rgalternates.end() != ++ialt )

        {

            width_type temp_width = ( *ialt )->get_width( param );

            width.m_min = regex_min( width.m_min, temp_width.m_min );

            width.m_max = regex_max( width.m_max, temp_width.m_max );

        }

        else

        {

            width.m_min = 0;

        }

 

        // Have the condition calculate its width, too. This is important

        // if the condition is a lookbehind assertion.

        m_condition.width_this( param );

 

        return this->m_nwidth = width;

    }

 

protected:

    condition_type m_condition;

};

 

template< typename IterT >

inline match_conditional<IterT, backref_condition<IterT> > * create_backref_conditional(

    size_t cgroup,

    size_t cbackref,

    regex_arena & arena )

{

    backref_condition<IterT> cond( cbackref );

    return new( arena ) match_conditional<IterT, backref_condition<IterT> >(

        cgroup, cond, arena );

}

 

template< typename IterT >

inline match_conditional<IterT, assertion_condition<IterT> > * create_assertion_conditional(

    size_t cgroup,

    match_group_base<IterT> * passert,

    regex_arena & arena )

{

    assertion_condition<IterT> cond( passert, arena );

    return new( arena ) match_conditional<IterT, assertion_condition<IterT> >(

        cgroup, cond, arena );

}

 

//

// From basic_rpattern_base_impl

//

 

template< typename IterT >

REGEXPR_H_INLINE bool basic_rpattern_base_impl<IterT>::_ok_to_recurse() const //throw()

{

    switch( m_mode )

    {

    case MODE_FAST:

        return true;

    case MODE_SAFE:

        return false;

    case MODE_MIXED:

        return m_fok_to_recurse;

    default:

        return false;

    }

}

 

template< typename IterT >

REGEXPR_H_INLINE void basic_rpattern_base_impl<IterT>::swap( basic_rpattern_base_impl<IterT> & that ) // throw()

{

    using std::swap;

    swap( m_fuses_backrefs, that.m_fuses_backrefs );

    swap( m_floop, that.m_floop );

    swap( m_fok_to_recurse, that.m_fok_to_recurse );

    swap( m_cgroups, that.m_cgroups );

    swap( m_cgroups_visible, that.m_cgroups_visible );

    swap( m_flags, that.m_flags );

    swap( m_mode, that.m_mode );

    swap( m_nwidth, that.m_nwidth );

    swap( m_pfirst, that.m_pfirst );

    swap( m_search, that.m_search );

 

    swap_auto_ptr( m_pat, that.m_pat );

    swap_auto_ptr( m_subst, that.m_subst );

 

    m_subst_list.swap( that.m_subst_list );

    m_invisible_groups.swap( that.m_invisible_groups );

    m_arena.swap( that.m_arena );

}

 

// A helper class for automatically deallocating the arena when

// parsing the pattern results in an exception

class arena_guard

{

    arena_guard( arena_guard const & );

    arena_guard & operator=( arena_guard const & );

    regex_arena * m_parena;

public:

    explicit arena_guard( regex_arena & arena )

        : m_parena( &arena )

    {

    }

    ~arena_guard()

    {

        if( m_parena )

            m_parena->clear();

    }

    void dismiss()

    {

        m_parena = 0;

    }

};

 

template< typename CatT > 

struct is_random_access_helper

{

    enum { value = false };

};

template<> 

struct is_random_access_helper<std::random_access_iterator_tag>

{

    enum { value = true };

};

template< typename IterT > 

struct is_random_access

{

    typedef typename std::iterator_traits<IterT>::iterator_category cat_type;

    enum { value = is_random_access_helper<cat_type>::value };

};

 

} // namespace detail

 

//

// Implementation of basic_rpattern_base:

//

 

template< typename IterT, typename SyntaxT >

REGEXPR_H_INLINE void basic_rpattern_base<IterT, SyntaxT>::init( string_type const & pat, REGEX_FLAGS flags, REGEX_MODE mode )

{

    basic_rpattern_base<IterT, SyntaxT> temp( pat, flags, mode );

    swap( temp );

}

 

template< typename IterT, typename SyntaxT >

REGEXPR_H_INLINE void basic_rpattern_base<IterT, SyntaxT>::init( string_type const & pat, string_type const & subst, REGEX_FLAGS flags, REGEX_MODE mode )

{

    basic_rpattern_base<IterT, SyntaxT> temp( pat, subst, flags, mode );

    swap( temp );

}

 

template< typename IterT, typename SyntaxT >

REGEXPR_H_INLINE void basic_rpattern_base<IterT, SyntaxT>::_common_init( REGEX_FLAGS flags )

{

    this->m_cgroups = 0;

    std::vector<detail::match_group_base<IterT>*> rggroups;

    typename string_type::iterator ipat = this->m_pat->begin();

    syntax_type sy( flags );

    detail::match_group_base<IterT> * pgroup;

 

    // Set up a sentry that will free the arena memory

    // automatically on parse failure.

    {

        detail::arena_guard guard( this->m_arena );

 

        // This will throw on failure

        pgroup = _find_next_group( ipat, 0, sy, rggroups );

 

        // terminate the pattern with the end_of_pattern marker

        *pgroup->pnext() = new( this->m_arena ) detail::end_of_pattern<IterT>;

 

        // The parse was successful. Dismiss the parse sentry

        guard.dismiss();

    }

 

    REGEX_ASSERT( 0 == m_pfirst );

    m_pfirst = pgroup;

 

    // Calculate the width of the pattern and all groups

    this->m_nwidth = pgroup->group_width( rggroups, m_invisible_groups );

 

    //

    // determine if we can get away with only calling m_pfirst->recursive_match_all only once

    //

 

    this->m_floop = true;

 

    // Optimization: if first character of pattern string is '^'

    // and we are not doing a multiline match, then we only

    // need to try recursive_match_all once

    typename string_type::iterator icur = this->m_pat->begin();

    if( MULTILINE != ( MULTILINE & this->m_flags ) &&

        1 == pgroup->calternates() &&

        this->m_pat->end() != icur &&

        BEGIN_LINE == sy.reg_token( icur, this->m_pat->end() ) )

    {

        this->m_flags = ( REGEX_FLAGS ) ( m_flags & ~RIGHTMOST );

        this->m_floop = false;

    }

 

    // Optimization: if first 2 characters of pattern string are ".*" or ".+",

    // then we only need to try recursive_match_all once

    icur = this->m_pat->begin();

    if( RIGHTMOST != ( RIGHTMOST & this->m_flags ) &&

        SINGLELINE == ( SINGLELINE & this->m_flags ) &&

        1 == pgroup->calternates() &&

        this->m_pat->end() != icur &&

        MATCH_ANY == sy.reg_token( icur, this->m_pat->end() ) &&

        this->m_pat->end() != icur )

    {

        switch( sy.quant_token( icur, this->m_pat->end() ) )

        {

        case ONE_OR_MORE:

        case ZERO_OR_MORE:

        case ONE_OR_MORE_MIN:

        case ZERO_OR_MORE_MIN:

            this->m_floop = false;

            break;

        default:

            break;

        }

    }

}

 

template< typename IterT, typename SyntaxT >

REGEXPR_H_INLINE void basic_rpattern_base<IterT, SyntaxT>::set_substitution( string_type const & subst )

{

    using std::swap;

    std::auto_ptr<string_type> temp_subst( new string_type( subst ) );

    detail::subst_list_type temp_subst_list;

    bool uses_backrefs = false;

 

    _normalize_string( *temp_subst );

    basic_rpattern_base<IterT, SyntaxT>::_parse_subst( *temp_subst, uses_backrefs, temp_subst_list );

 

    detail::swap_auto_ptr( temp_subst, this->m_subst );

    swap( uses_backrefs, this->m_fuses_backrefs );

    temp_subst_list.swap( this->m_subst_list );

}

 

template< typename IterT, typename SyntaxT >

inline detail::match_group_base<IterT> * basic_rpattern_base<IterT, SyntaxT>::_find_next_group(

    typename string_type::iterator & ipat,

    detail::match_group_base<IterT> * pgroup_enclosing, syntax_type & sy,

    std::vector<detail::match_group_base<IterT>*> & rggroups )

{

    std::auto_ptr<detail::match_group_base<IterT> > pgroup;

    typename string_type::iterator itemp = ipat;

    REGEX_FLAGS old_flags = sy.get_flags();

    TOKEN tok = NO_TOKEN;

    size_t extent_start = this->m_cgroups;

    bool fconditional = false;

 

    // Look for group extensions.

    if( this->m_pat->end() != ipat && NO_TOKEN != ( tok = sy.ext_token( ipat, this->m_pat->end() ) ) )

    {

        if( this->m_pat->begin() == itemp || this->m_pat->end() == ipat )

            throw bad_regexpr( "ill-formed regular expression" );

 

        // Is this a recursion element?

        if( EXT_RECURSE == tok )

        {

            pgroup_enclosing->add_item( detail::create_recurse<IterT>( this->m_arena ) );

 

            // This pattern could recurse deeply. Note that fact here so that

            // we can opt to use a stack-conservative algorithm at match time.

            this->m_fok_to_recurse = false;

        }

 

        // Don't process empty groups like (?:) or (?i) or (?R)

        if( END_GROUP != sy.reg_token( itemp = ipat, this->m_pat->end() ) )

        {

            switch( tok )

            {

            case EXT_NOBACKREF:

                // note that this group is not visible, so we can fix

                // up offsets into the backref vector later

                m_invisible_groups.push_back( this->m_cgroups );

                detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::match_group<IterT>( _get_next_group_nbr(), this->m_arena ) );

                break;

 

            case EXT_INDEPENDENT:

                m_invisible_groups.push_back( this->m_cgroups );

                detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::independent_group<IterT>( _get_next_group_nbr(), this->m_arena ) );

                break;

 

            case EXT_POS_LOOKAHEAD:

                detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::lookahead_assertion<IterT>( true, this->m_arena ) );

                break;

 

            case EXT_NEG_LOOKAHEAD:

                detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::lookahead_assertion<IterT>( false, this->m_arena ) );

                break;

 

            case EXT_POS_LOOKBEHIND:

                detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::lookbehind_assertion<IterT>( true, this->m_arena ) );

                break;

 

            case EXT_NEG_LOOKBEHIND:

                detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::lookbehind_assertion<IterT>( false, this->m_arena ) );

                break;

 

            case EXT_CONDITION:

                fconditional = true;

                m_invisible_groups.push_back( this->m_cgroups );

 

                if( size_t cbackref = detail::parse_int( ipat, this->m_pat->end() ) &&

                    END_GROUP == sy.reg_token( ipat, this->m_pat->end() ) )

                {

                    detail::reset_auto_ptr(

                        pgroup, detail::create_backref_conditional<IterT>(

                            _get_next_group_nbr(), cbackref, this->m_arena ) );

                }

                else

                {

                    switch( sy.ext_token( itemp = ipat, this->m_pat->end() ) )

                    {

                    case EXT_POS_LOOKAHEAD:

                    case EXT_NEG_LOOKAHEAD:

                    case EXT_POS_LOOKBEHIND:

                    case EXT_NEG_LOOKBEHIND:

                        {

                            std::auto_ptr<detail::match_group_base<IterT> > pgroup_tmp(

                                _find_next_group( ipat, 0, sy, rggroups ) );

                            detail::reset_auto_ptr(

                                pgroup, detail::create_assertion_conditional<IterT>(

                                    _get_next_group_nbr(), pgroup_tmp.get(), this->m_arena ) );

                            pgroup_tmp.release();

                        }

                        break;

                    default:

                        throw bad_regexpr( "bad extension sequence" );

                    }

                }

                break;

 

            case EXT_COMMENT:

                while( END_GROUP != ( tok = sy.reg_token( ipat, this->m_pat->end() ) ) )

                {

                    if( NO_TOKEN == tok && this->m_pat->end() != ipat )

                        ++ipat;

                    if( this->m_pat->end() == ipat )

                        throw bad_regexpr( "Expecting end of comment" );

                }

                break;

 

            default:

                throw bad_regexpr( "bad extension sequence" );

            }

        }

        else

        {

            // Skip over the END_GROUP token

            ipat = itemp;

        }

    }

    else

    {

        detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::match_group<IterT>( _get_next_group_nbr(), this->m_arena ) );

        ++this->m_cgroups_visible;

    }

 

    if( 0 != pgroup.get() )

    {

        detail::must_have<char_type> must;

 

        pgroup->open_group();

        while( _find_next( ipat, pgroup.get(), sy, rggroups ) ) {}

        must = pgroup->close_group( this->m_arena );

 

        // if this is a conditional group, then there must be at

        // most 2 alternates.

        if( fconditional && 2 < pgroup->calternates() )

            throw bad_regexpr( "Too many alternates in conditional subexpression" );

 

        // if this is the top-level group and it returned a "must have"

        // string, then use that to initialize a boyer-moore search structure

        if( detail::is_random_access<IterT>::value && must.m_has && 0 == pgroup->group_number() )

        {

            typedef typename string_type::const_iterator iter_type;

            m_search = new( this->m_arena ) detail::boyer_moore<iter_type>

                ( must.m_begin, must.m_end, must.m_lower );

        }

 

        // Add this group to the rggroups array

        if( size_t( -1 ) != pgroup->group_number() )

        {

            if( pgroup->group_number() >= rggroups.size() )

                rggroups.resize( pgroup->group_number() + 1, 0 );

            rggroups[ pgroup->group_number() ] = pgroup.get();

        }

 

        // tell this group how many groups are contained within it

        pgroup->set_extent( detail::extent_type( extent_start, this->m_cgroups - extent_start ) );

 

        // If this is not a pattern modifier, restore the

        // flags to their previous settings.  This causes

        // pattern modifiers to have the scope of their

        // enclosing group.

        sy.set_flags( old_flags );

    }

 

    return pgroup.release();

}

 

namespace detail

{

 

// If we reached the end of the string before finding the end of the

// character set, then this is an ill-formed regex

template< typename IterT >

inline void check_iter( IterT icur, IterT iend )

{

    if( iend == icur )

        throw bad_regexpr( "expecting end of character set" );

}

 

template< typename IBeginT, typename IEndT >

inline typename std::iterator_traits<IEndT>::value_type get_escaped_char( IBeginT & icur, IEndT iend, bool normalize )

{

    typedef typename std::iterator_traits<IEndT>::value_type char_type;

    char_type ch = 0, i;

    check_iter<IEndT>( icur, iend );

 

    switch( *icur )

    {

    // octal escape sequence

    case REGEX_CHAR(char_type,'0'): case REGEX_CHAR(char_type,'1'): case REGEX_CHAR(char_type,'2'): case REGEX_CHAR(char_type,'3'):

    case REGEX_CHAR(char_type,'4'): case REGEX_CHAR(char_type,'5'): case REGEX_CHAR(char_type,'6'): case REGEX_CHAR(char_type,'7'):

        ch = char_type( *icur++ - REGEX_CHAR(char_type,'0') );

        for( i=0; i<2 && REGEX_CHAR(char_type,'0') <= *icur && REGEX_CHAR(char_type,'7') >= *icur; check_iter<IEndT>( ++icur, iend ) )

            ch = char_type( ch * 8 + ( *icur - REGEX_CHAR(char_type,'0') ) );

        break;

    // bell character

    case REGEX_CHAR(char_type,'a'):

        if( ! normalize )

            goto default_;

        ch = REGEX_CHAR(char_type,'/a');

        ++icur;

        break;

    // control character

    case REGEX_CHAR(char_type,'c'):

        check_iter<IEndT>( ++icur, iend );

        ch = *icur++;

        if( REGEX_CHAR(char_type,'a') <= ch && REGEX_CHAR(char_type,'z') >= ch )

            ch = detail::regex_toupper( ch );

        ch ^= 0x40;

        break;

    // escape character

    case REGEX_CHAR(char_type,'e'):

        ch = 27;

        ++icur;

        break;

    // formfeed character

    case REGEX_CHAR(char_type,'f'):

        if( ! normalize )

            goto default_;

        ch = REGEX_CHAR(char_type,'/f');

        ++icur;

        break;

    // newline

    case REGEX_CHAR(char_type,'n'):

        if( ! normalize )

            goto default_;

        ch = REGEX_CHAR(char_type,'/n');

        ++icur;

        break;

    // return

    case REGEX_CHAR(char_type,'r'):

        if( ! normalize )

            goto default_;

        ch = REGEX_CHAR(char_type,'/r');

        ++icur;

        break;

    // horizontal tab

    case REGEX_CHAR(char_type,'t'):

        if( ! normalize )

            goto default_;

        ch = REGEX_CHAR(char_type,'/t');

        ++icur;

        break;

    // vertical tab

    case REGEX_CHAR(char_type,'v'):

        if( ! normalize )

            goto default_;

        ch = REGEX_CHAR(char_type,'/v');

        ++icur;

        break;

    // hex escape sequence

    case REGEX_CHAR(char_type,'x'):

        for( ++icur, ch=i=0; i<2 && detail::regex_isxdigit( *icur ); check_iter<IEndT>( ++icur, iend ) )

            ch = char_type( ch * 16 + detail::regex_xdigit2int( *icur ) );

        break;

    // backslash

    case REGEX_CHAR(char_type,'//'):

        if( ! normalize )

            goto default_;

        ch = REGEX_CHAR(char_type,'//');

        ++icur;

        break;

    // all other escaped characters represent themselves

    default: default_:

        ch = *icur;

        ++icur;

        break;

    }

 

    return ch;

}

 

template< typename CharT, typename CharSetT, typename SyntaxT >

inline void parse_charset(

    std::auto_ptr<CharSetT> & pnew,

    typename std::basic_string<CharT>::iterator & icur,

    typename std::basic_string<CharT>::const_iterator iend,

    SyntaxT & sy )

{

    typedef CharT char_type;

    typedef std::basic_string<CharT> string_type;

    typedef typename string_type::const_iterator iter_type;

    typename string_type::iterator itemp = icur;

    bool const normalize = ( NORMALIZE == ( NORMALIZE & sy.get_flags() ) );

 

    if( iend != itemp && CHARSET_NEGATE == sy.charset_token( itemp, iend ) )

    {

        pnew->m_fcompliment = true;

        icur = itemp;

    }

 

    TOKEN tok;

    char_type ch_prev = 0;

    bool fhave_prev = false;

    charset const * pcharset = 0;

    typename string_type::iterator iprev = icur;

    bool const fnocase = ( NOCASE == ( NOCASE & sy.get_flags() ) );

 

    check_iter<iter_type>( icur, iend );

 

    // remember the current position and grab the next token

    tok = sy.charset_token( icur, iend );

    do

    {

        check_iter<iter_type>( icur, iend );

 

        if( CHARSET_RANGE == tok && fhave_prev )

        {

            // remember the current position

            typename string_type::iterator iprev2 = icur;

            fhave_prev = false;

 

            // ch_prev is lower bound of a range

            switch( sy.charset_token( icur, iend ) )

            {

            case CHARSET_RANGE:

            case CHARSET_NEGATE:

                icur = iprev2; // un-get these tokens and fall through

            case NO_TOKEN:

                pnew->set_bit_range( ch_prev, *icur++, fnocase );

                continue;

            case CHARSET_ESCAPE: // BUGBUG user-defined charset?

                pnew->set_bit_range( ch_prev, get_escaped_char( icur, iend, normalize ), fnocase );

                continue;

            case CHARSET_BACKSPACE:

                pnew->set_bit_range( ch_prev, char_type( 8 ), fnocase ); // backspace

                continue;

            case CHARSET_END: // fall through

            default:          // not a range.

                icur = iprev; // backup to range token

                pnew->set_bit( ch_prev, fnocase );

                pnew->set_bit( *icur++, fnocase );

                continue;

            }

        }

 

        if( fhave_prev )

            pnew->set_bit( ch_prev, fnocase );

        fhave_prev = false;

 

        switch( tok )

        {

            // None of the intrinsic charsets are case-sensitive,

            // so no special handling must be done when the NOCASE

            // flag is set.

        case CHARSET_RANGE:

        case CHARSET_NEGATE:

        case CHARSET_END:

            icur = iprev; // un-get these tokens

            ch_prev = *icur++;

            fhave_prev = true;

            continue;

        case CHARSET_BACKSPACE:

            ch_prev = char_type( 8 ); // backspace

            fhave_prev = true;

            continue;

        case ESC_DIGIT:

            *pnew |= intrinsic_charsets<char_type>::get_digit_charset();

            continue;

        case ESC_NOT_DIGIT:

            *pnew |= intrinsic_charsets<char_type>::get_not_digit_charset();

            continue;

        case ESC_SPACE:

            *pnew |= intrinsic_charsets<char_type>::get_space_charset();

            continue;

        case ESC_NOT_SPACE:

            *pnew |= intrinsic_charsets<char_type>::get_not_space_charset();

            continue;

        case ESC_WORD:

            *pnew |= intrinsic_charsets<char_type>::get_word_charset();

            continue;

        case ESC_NOT_WORD:

            *pnew |= intrinsic_charsets<char_type>::get_not_word_charset();

            continue;

        case CHARSET_ALNUM:

            pnew->m_posixcharson |= ( wct_alnum() );

            continue;

        case CHARSET_NOT_ALNUM:

            pnew->m_posixcharsoff.push_front( wct_alnum() );

            continue;

        case CHARSET_ALPHA:

            pnew->m_posixcharson |= ( wct_alpha() );

            continue;

        case CHARSET_NOT_ALPHA:

            pnew->m_posixcharsoff.push_front( wct_alpha() );

            continue;

        case CHARSET_BLANK:

            pnew->m_posixcharson |= ( wct_blank() );

            continue;

        case CHARSET_NOT_BLANK:

            pnew->m_posixcharsoff.push_front( wct_blank() );

            continue;

        case CHARSET_CNTRL:

            pnew->m_posixcharson |= ( wct_cntrl() );

            continue;

        case CHARSET_NOT_CNTRL:

            pnew->m_posixcharsoff.push_front( wct_cntrl() );

            continue;

        case CHARSET_DIGIT:

            pnew->m_posixcharson |= ( wct_digit() );

            continue;

        case CHARSET_NOT_DIGIT:

            pnew->m_posixcharsoff.push_front( wct_digit() );

            continue;

        case CHARSET_GRAPH:

            pnew->m_posixcharson |= ( wct_graph() );

            continue;

        case CHARSET_NOT_GRAPH:

            pnew->m_posixcharsoff.push_front( wct_graph() );

            continue;

        case CHARSET_LOWER:

            if( NOCASE == ( NOCASE & sy.get_flags() ) )

                pnew->m_posixcharson |= ( wct_lower()|wct_upper() );

            else

                pnew->m_posixcharson |= ( wct_lower() );

            continue;

        case CHARSET_NOT_LOWER:

            if( NOCASE == ( NOCASE & sy.get_flags() ) )

                pnew->m_posixcharsoff.push_front( wct_lower()|wct_upper() );

            else

                pnew->m_posixcharsoff.push_front( wct_lower() );

            continue;

        case CHARSET_PRINT:

            pnew->m_posixcharson |= ( wct_print() );

            continue;

        case CHARSET_NOT_PRINT:

            pnew->m_posixcharsoff.push_front( wct_print() );

            continue;

        case CHARSET_PUNCT:

            pnew->m_posixcharson |= ( wct_punct() );

            continue;

        case CHARSET_NOT_PUNCT:

            pnew->m_posixcharsoff.push_front( wct_punct() );

            continue;

        case CHARSET_SPACE:

            pnew->m_posixcharson |= ( wct_space() );

            continue;

        case CHARSET_NOT_SPACE:

            pnew->m_posixcharsoff.push_front( wct_space() );

            continue;

        case CHARSET_UPPER:

            if( NOCASE == ( NOCASE & sy.get_flags() ) )

                pnew->m_posixcharson |= ( wct_upper()|wct_lower() );

            else

                pnew->m_posixcharson |= ( wct_upper() );

            continue;

        case CHARSET_NOT_UPPER:

            if( NOCASE == ( NOCASE & sy.get_flags() ) )

                pnew->m_posixcharsoff.push_front( wct_upper()|wct_lower() );

            else

                pnew->m_posixcharsoff.push_front( wct_upper() );

            continue;

        case CHARSET_XDIGIT:

            pnew->m_posixcharson |= ( wct_xdigit() );

            continue;

        case CHARSET_NOT_XDIGIT:

            pnew->m_posixcharsoff.push_front( wct_xdigit() );

            continue;

        case CHARSET_ESCAPE:

            // Maybe this is a user-defined intrinsic charset

            pcharset = get_altern_charset( *icur, sy );

            if( 0 != pcharset )

            {

                 *pnew |= *pcharset;

                 ++icur;

                 continue;

            }

            else

            {

                ch_prev = get_escaped_char( icur, iend, normalize );

                fhave_prev = true;

            }

            continue;

        default:

            ch_prev = *icur++;

            fhave_prev = true;

            continue;

        }

    }

    while( check_iter<iter_type>( iprev = icur, iend ),

           CHARSET_END != ( tok = sy.charset_token( icur, iend ) ) );

 

    if( fhave_prev )

        pnew->set_bit( ch_prev, fnocase );

 

    pnew->optimize( type2type<char_type>() );

}

 

template< typename CharT, typename SyntaxT >

inline charset const * get_altern_charset( CharT ch, SyntaxT & sy )

{

    typedef std::basic_string<CharT> string_type;

    charset const * pcharset = 0;

    regex::detail::charset_map<CharT> & charset_map = sy.get_charset_map();

    typename regex::detail::charset_map<CharT>::iterator iter = charset_map.find( ch );

    if( charset_map.end() != iter )

    {

        bool const fnocase = ( NOCASE == ( sy.get_flags() & NOCASE ) );

        pcharset = iter->second.m_rgcharsets[ fnocase ];

        if( 0 == pcharset )

        {

            // tmp takes ownership of any ptrs.

            charset_map_node<CharT> tmp = iter->second;

            charset_map.erase( iter ); // prevent possible infinite recursion

            typename string_type::iterator ibegin = tmp.m_str.begin();

            std::auto_ptr<charset> pnew( new charset );

            std::auto_ptr<charset const> pold( tmp.m_rgcharsets[ !fnocase ] );

            parse_charset<CharT, charset>( pnew, ibegin, tmp.m_str.end(), sy );

            tmp.m_rgcharsets[ fnocase ] = pcharset = pnew.get();

            charset_map[ ch ] = tmp; // could throw

            // charset_map has taken ownership of these pointers now.

            pnew.release();

            pold.release();

        }

    }

    return pcharset;

}

 

} // namespace detail

 

//

// Read ahead through the pattern and treat sequential atoms

// as a single atom, making sure to handle quantification

// correctly. Warning: dense code ahead.

//

template< typename IterT, typename SyntaxT >

inline void basic_rpattern_base<IterT, SyntaxT>::_find_atom(

    typename string_type::iterator & ipat,

    detail::match_group_base<IterT> * pgroup,

    syntax_type & sy )

{

    typedef typename string_type::iterator iter_type;

    typedef typename std::iterator_traits<iter_type>::difference_type diff_type;

    iter_type itemp = ipat, ibegin;

    diff_type const nstart = std::distance( this->m_pat->begin(), ipat );

 

    do

    {

        if( itemp != ipat ) // Is there whitespace to skip?

        {

            diff_type dist = std::distance( this->m_pat->begin(), ipat );

            this->m_pat->erase( ipat, itemp ); // erase the whitespace from the patttern

            std::advance( ipat = this->m_pat->begin(), dist );

            if( this->m_pat->end() == ( itemp = ipat ) ) // are we at the end of the pattern?

                break;

        }

        switch( sy.quant_token( itemp, this->m_pat->end() ) )

        {

            // if {, } can't be interpreted as quantifiers, treat them as regular chars

        case BEGIN_RANGE:

            std::advance( ibegin = this->m_pat->begin(), nstart );

            if( ibegin != ipat ) // treat as a quantifier

                goto quantify;

        case NO_TOKEN:

        case END_RANGE:

        case END_RANGE_MIN:

        case RANGE_SEPARATOR:

            break;

 

        default:

            std::advance( ibegin = this->m_pat->begin(), nstart );

            if( ibegin == ipat ) // must be able to quantify something.

                throw bad_regexpr( "quantifier not expected" );

 

quantify:   if( ibegin != --ipat )

                pgroup->add_item( detail::create_literal<IterT>( ibegin, ipat, sy.get_flags(), this->m_arena ) );

            std::auto_ptr<detail::sub_expr<IterT> > pnew( detail::create_char<IterT>( *ipat++, sy.get_flags(), this->m_arena ) );

            _quantify( pnew, ipat, false, sy );

            pgroup->add_item( pnew.release() );

            return;

        }

    } while( this->m_pat->end() != ++ipat && ! sy.reg_token( itemp = ipat, this->m_pat->end() ) );

 

    std::advance( ibegin = this->m_pat->begin(), nstart );

    REGEX_ASSERT( ipat != ibegin );

    pgroup->add_item( detail::create_literal<IterT>( ibegin, ipat, sy.get_flags(), this->m_arena ) );

}

 

template< typename IterT, typename SyntaxT >

inline bool basic_rpattern_base<IterT, SyntaxT>::_find_next(

    typename string_type::iterator & ipat,

    detail::match_group_base<IterT> * pgroup,

    syntax_type & sy,

    std::vector<detail::match_group_base<IterT>*> & rggroups )

{

    std::auto_ptr<detail::sub_expr<IterT> > pnew;

    std::auto_ptr<detail::custom_charset> pcs;

    typename string_type::iterator ibegin, itemp;

    bool fdone, is_group = false;

    bool const normalize = ( NORMALIZE == ( NORMALIZE & sy.get_flags() ) );

 

    if( this->m_pat->end() == ipat )

    {

        if( 0 != pgroup->group_number() )

            throw bad_regexpr( "mismatched parenthesis" );

        return false;

    }

 

    switch( sy.reg_token( ipat, this->m_pat->end() ) )

    {

    case NO_TOKEN: // not a token. Must be an atom

        if( this->m_pat->end() == ipat )

        {

            if( 0 != pgroup->group_number() )

                throw bad_regexpr( "mismatched parenthesis" );

            return false;

        }

        _find_atom( ipat, pgroup, sy );

        return true;

 

    case END_GROUP:

        if( 0 == pgroup->group_number() )

            throw bad_regexpr( "mismatched parenthesis" );

        return false;

 

    case ALTERNATION:

        pgroup->end_alternate();

        pgroup->add_alternate();

        return true;

 

    case BEGIN_GROUP:

        // Find next group. could return NULL if the group is really

        // a pattern modifier, like: ( ?s-i )

        detail::reset_auto_ptr( pnew, _find_next_group( ipat, pgroup, sy, rggroups ) );

        is_group = true;

        break;

 

    case BEGIN_LINE:

        detail::reset_auto_ptr( pnew, detail::create_bol<IterT>( sy.get_flags(), this->m_arena ) );

        break;

 

    case END_LINE:

        detail::reset_auto_ptr( pnew, detail::create_eol<IterT>( sy.get_flags(), this->m_arena ) );

        break;

 

    case BEGIN_CHARSET:

        detail::reset_auto_ptr( pcs, new( this->m_arena ) detail::custom_charset( this->m_arena ) );

        detail::parse_charset<char_type, detail::custom_charset>(

            pcs, ipat, this->m_pat->end(), sy );

        detail::reset_auto_ptr( pnew,

            detail::create_custom_charset<IterT>( pcs.get(), sy.get_flags(), this->m_arena ) );

        pcs.release();

        break;

 

    case MATCH_ANY:

        detail::reset_auto_ptr( pnew, detail::create_any<IterT>( sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_WORD_BOUNDARY:

        detail::reset_auto_ptr( pnew, detail::create_word_boundary<IterT>( true, sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_NOT_WORD_BOUNDARY:

        detail::reset_auto_ptr( pnew, detail::create_word_boundary<IterT>( false, sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_WORD_START:

        detail::reset_auto_ptr( pnew, detail::create_word_start<IterT>( sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_WORD_STOP:

        detail::reset_auto_ptr( pnew, detail::create_word_stop<IterT>( sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_DIGIT:

        detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( detail::intrinsic_charsets<char_type>::get_digit_charset(), sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_NOT_DIGIT:

        detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( detail::intrinsic_charsets<char_type>::get_not_digit_charset(), sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_WORD:

        detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( detail::intrinsic_charsets<char_type>::get_word_charset(), sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_NOT_WORD:

        detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( detail::intrinsic_charsets<char_type>::get_not_word_charset(), sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_SPACE:

        detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( detail::intrinsic_charsets<char_type>::get_space_charset(), sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_NOT_SPACE:

        detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( detail::intrinsic_charsets<char_type>::get_not_space_charset(), sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_BEGIN_STRING:

        detail::reset_auto_ptr( pnew, detail::create_bos<IterT>( sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_END_STRING:

        detail::reset_auto_ptr( pnew, detail::create_eos<IterT>( sy.get_flags(), this->m_arena ) );

        break;

 

    case ESC_END_STRING_z:

        detail::reset_auto_ptr( pnew, detail::create_eoz<IterT>( sy.get_flags(), this->m_arena ) );

        break;

 

    case ESCAPE:

        if( this->m_pat->end() == ipat )

        {

            // BUGBUG what if the escape sequence is more that 1 character?

            detail::reset_auto_ptr( pnew, detail::create_char<IterT>( *--ipat, sy.get_flags(), this->m_arena ) );

            ++ipat;

        }

        else if( REGEX_CHAR(char_type,'0') <= *ipat && REGEX_CHAR(char_type,'9') >= *ipat )

        {

            // Parse at most 3 decimal digits.

            size_t nbackref = detail::parse_int( itemp = ipat, this->m_pat->end(), 999 );

            // If the resulting number could conceivably be a backref, then it is.

            if( REGEX_CHAR(char_type,'0') != *ipat && ( 10 > nbackref || nbackref < _cgroups_total() ) )

            {

                detail::reset_auto_ptr( pnew, detail::create_backref<IterT>( nbackref, sy.get_flags(), this->m_arena ) );

                ipat = itemp;

            }

            else

            {

                // It's an octal character escape sequence. If *ipat is 8 or 9, insert

                // a NULL character, and leave the 8 or 9 as a character literal.

                char_type ch = 0, i = 0;

                for( ; i < 3 && this->m_pat->end() != ipat && REGEX_CHAR(char_type,'0') <= *ipat && REGEX_CHAR(char_type,'7') >= *ipat; ++i, ++ipat )

                    ch = char_type( ch * 8 + ( *ipat - REGEX_CHAR(char_type,'0') ) );

                detail::reset_auto_ptr( pnew, detail::create_char<IterT>( ch, sy.get_flags(), this->m_arena ) );

            }

        }

        else if( REGEX_CHAR(char_type,'e') == *ipat )

        {

            ++ipat;

            detail::reset_auto_ptr( pnew, detail::create_char<IterT>( char_type( 27 ), sy.get_flags(), this->m_arena ) );

        }

        else if( REGEX_CHAR(char_type,'x') == *ipat )

        {

            char_type ch = 0, i = 0;

            for( ++ipat; i < 2 && this->m_pat->end() != ipat && detail::regex_isxdigit( *ipat ); ++i, ++ipat )

                ch = char_type( ch * 16 + detail::regex_xdigit2int( *ipat ) );

            detail::reset_auto_ptr( pnew, detail::create_char<IterT>( ch, sy.get_flags(), this->m_arena ) );

        }

        else if( REGEX_CHAR(char_type,'c') == *ipat )

        {

            if( this->m_pat->end() == ++ipat )

                throw bad_regexpr( "incomplete escape sequence //c" );

            char_type ch = *ipat++;

            if( REGEX_CHAR(char_type,'a') <= ch && REGEX_CHAR(char_type,'z') >= ch )

                ch = detail::regex_toupper( ch );

            detail::reset_auto_ptr( pnew, detail::create_char<IterT>( char_type( ch ^ 0x40 ), sy.get_flags(), this->m_arena ) );

        }

        else if( REGEX_CHAR(char_type,'a') == *ipat && normalize )

        {

            ++ipat;

            detail::reset_auto_ptr( pnew, detail::create_char<IterT>( REGEX_CHAR(char_type,'/a'), sy.get_flags(), this->m_arena ) );

        }

        else if( REGEX_CHAR(char_type,'f') == *ipat && normalize )

        {

            ++ipat;

            detail::reset_auto_ptr( pnew, detail::create_char<IterT>( REGEX_CHAR(char_type,'/f'), sy.get_flags(), this->m_arena ) );

        }

        else if( REGEX_CHAR(char_type,'n') == *ipat && normalize )

        {

            ++ipat;

            detail::reset_auto_ptr( pnew, detail::create_char<IterT>( REGEX_CHAR(char_type,'/n'), sy.get_flags(), this->m_arena ) );

        }

        else if( REGEX_CHAR(char_type,'r') == *ipat && normalize )

        {

            ++ipat;

            detail::reset_auto_ptr( pnew, detail::create_char<IterT>( REGEX_CHAR(char_type,'/r'), sy.get_flags(), this->m_arena ) );

        }

        else if( REGEX_CHAR(char_type,'t') == *ipat && normalize )

        {

            ++ipat;

            detail::reset_auto_ptr( pnew, detail::create_char<IterT>( REGEX_CHAR(char_type,'/t'), sy.get_flags(), this->m_arena ) );

        }

        else if( REGEX_CHAR(char_type,'//') == *ipat && normalize )

        {

            ++ipat;

            detail::reset_auto_ptr( pnew, detail::create_char<IterT>( REGEX_CHAR(char_type,'//'), sy.get_flags(), this->m_arena ) );

        }

        else

        {

            // Is this a user-defined intrinsic character set?

            detail::charset const * pcharset = detail::get_altern_charset( *ipat, sy );

            if( 0 != pcharset )

                detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( *pcharset, sy.get_flags(), this->m_arena ) );

            else

                detail::reset_auto_ptr( pnew, detail::create_char<IterT>( *ipat, sy.get_flags(), this->m_arena ) );

            ++ipat;

        }

        break;

 

        // If quotemeta, loop until we find quotemeta off or end of string

    case ESC_QUOTE_META_ON:

        for( ibegin = itemp = ipat, fdone = false; !fdone && this->m_pat->end() != ipat; )

        {

            switch( sy.reg_token( ipat, this->m_pat->end() ) )

            {

            case ESC_QUOTE_META_OFF:

                fdone = true;

                break;

            case NO_TOKEN:

                if( this->m_pat->end() != ipat )

                    ++ipat; // fallthrough

            default:

                itemp = ipat;

                break;

            }

        }

        if( itemp != ibegin )

            pgroup->add_item( detail::create_literal<IterT>( ibegin, itemp, sy.get_flags(), this->m_arena ) );

 

        // skip the quantification code below

        return true;

 

    // Should never get here for valid patterns

    case ESC_QUOTE_META_OFF:

        throw bad_regexpr( "quotemeta turned off, but was never turned on" );

 

    default:

        REGEX_ASSERT( ! "Unhandled token type" );

        break;

    }

 

    // If pnew is null, then the current subexpression is a no-op.

    if( pnew.get() )

    {

        // Look for quantifiers

        _quantify( pnew, ipat, is_group, sy );

 

        // Add the item to the group

        pgroup->add_item( pnew.release() );

    }

    return true;

}

 

template< typename IterT, typename SyntaxT >

inline void basic_rpattern_base<IterT, SyntaxT>::_quantify(

    std::auto_ptr<detail::sub_expr<IterT> > & pnew,

    typename string_type::iterator & ipat,

    bool is_group,

    syntax_type & sy )

{

    if( this->m_pat->end() != ipat && ! pnew->is_assertion() )

    {

        typename string_type::iterator itemp = ipat, itemp2;

        bool fmin = false;

 

        // Since size_t is unsigned, -1 is really the largest size_t

        size_t lbound = ( size_t )-1;

        size_t ubound = ( size_t )-1;

        size_t ubound_tmp;

 

        switch( sy.quant_token( itemp, this->m_pat->end() ) )

        {

        case ZERO_OR_MORE_MIN:

            fmin = true;

        case ZERO_OR_MORE:

            lbound = 0;

            break;

 

        case ONE_OR_MORE_MIN:

            fmin = true;

        case ONE_OR_MORE:

            lbound = 1;

            break;

 

        case ZERO_OR_ONE_MIN:

            fmin = true;

        case ZERO_OR_ONE:

            lbound = 0;

            ubound = 1;

            break;

 

        case BEGIN_RANGE:

            lbound = detail::parse_int( itemp, this->m_pat->end() );

            if( this->m_pat->end() == itemp )

                return; // not a valid quantifier - treat as atom

 

            switch( sy.quant_token( itemp, this->m_pat->end() ) )

            {

            case END_RANGE_MIN:

                fmin = true;

            case END_RANGE:

                ubound = lbound;

                break;

 

            case RANGE_SEPARATOR:

                itemp2 = itemp;

                ubound_tmp = detail::parse_int( itemp, this->m_pat->end() );

                if( itemp != itemp2 )

                    ubound = ubound_tmp;

                if( itemp == this->m_pat->end() )

                    return; // not a valid quantifier - treat as atom

                switch( sy.quant_token( itemp, this->m_pat->end() ) )

                {

                case END_RANGE_MIN:

                    fmin = true;

                case END_RANGE:

                    break;

                default:

                    return; // not a valid quantifier - treat as atom

                }

                break;

 

            default:

                return; // not a valid quantifier - treat as atom

            }

 

            if( ubound < lbound  )

                throw bad_regexpr( "Can't do {n, m} with n > m" );

 

            break;

 

        default:

            break;

        }

 

        if( ( size_t )-1 != lbound )

        {

            // If we are quantifying a group, then this pattern could recurse

            // deeply. Note that fact here so that we can opt to use a stack-

            // conservative algorithm at match time.

            if( is_group && ubound > 16 )

                this->m_fok_to_recurse = false;

 

            std::auto_ptr<detail::sub_expr<IterT> > pquant( pnew->quantify( lbound, ubound, ! fmin, this->m_arena ) );

            pnew.release();

            detail::reset_auto_ptr( pnew, pquant.release() );

            ipat = itemp;

        }

    }

}

 

template< typename IterT, typename SyntaxT >

inline void basic_rpattern_base<IterT, SyntaxT>::_add_subst_backref(

    detail::subst_node & snode,

    size_t nbackref,

    ptrdiff_t rstart,

    bool & uses_backrefs,

    detail::subst_list_type & subst_list ) const

{

    uses_backrefs = true;

    REGEX_ASSERT( detail::subst_node::SUBST_STRING == snode.m_stype );

    if( snode.m_subst_string.m_rlength )

        subst_list.push_back( snode );

 

    snode.m_stype = detail::subst_node::SUBST_BACKREF;

    snode.m_subst_backref = nbackref;

    subst_list.push_back( snode );

 

    // re-initialize the subst_node

    snode.m_stype = detail::subst_node::SUBST_STRING;

    snode.m_subst_string.m_rstart = rstart;

    snode.m_subst_string.m_rlength = 0;

}

 

template< typename IterT, typename SyntaxT >

inline void basic_rpattern_base<IterT, SyntaxT>::_parse_subst(

    string_type & subst,

    bool & uses_backrefs,

    detail::subst_list_type & subst_list ) const

{

    TOKEN tok;

    detail::subst_node snode;

    typename string_type::iterator icur = subst.begin();

    size_t nbackref;

    typename string_type::iterator itemp;

    bool fdone;

    syntax_type sy( this->m_flags );

 

    uses_backrefs = false;

 

    // Initialize the subst_node

    snode.m_stype = detail::subst_node::SUBST_STRING;

    snode.m_subst_string.m_rstart = 0;

    snode.m_subst_string.m_rlength = 0;

 

    while( subst.end() != icur )

    {

        switch( tok = sy.subst_token( icur, subst.end() ) )

        {

        case SUBST_MATCH:

            _add_subst_backref( snode, 0, std::distance( subst.begin(), icur ), uses_backrefs, subst_list );

            break;

 

        case SUBST_PREMATCH:

            _add_subst_backref( snode, ( size_t )detail::subst_node::PREMATCH, std::distance( subst.begin(), icur ), uses_backrefs, subst_list );

            break;

 

        case SUBST_POSTMATCH:

            _add_subst_backref( snode, ( size_t )detail::subst_node::POSTMATCH, std::distance( subst.begin(), icur ), uses_backrefs, subst_list );

            break;

 

        case SUBST_BACKREF:

            nbackref = detail::parse_int( icur, subst.end(), cgroups() - 1 ); // always at least 1 group

            if( 0 == nbackref )

                throw bad_regexpr( "invalid backreference in substitution" );

 

            _add_subst_backref( snode, nbackref, std::distance( subst.begin(), icur ), uses_backrefs, subst_list );

            break;

 

        case SUBST_QUOTE_META_ON:

            REGEX_ASSERT( detail::subst_node::SUBST_STRING == snode.m_stype );

            if( snode.m_subst_string.m_rlength )

                subst_list.push_back( snode );

 

            snode.m_subst_string.m_rstart = std::distance( subst.begin(), icur );

            for( itemp = icur, fdone = false; !fdone && subst.end() != icur; )

            {

                switch( tok = sy.subst_token( icur, subst.end() ) )

                {

                case SUBST_ALL_OFF:

                    fdone = true;

                    break;

                case NO_TOKEN:

                    ++icur; // fall-through

                default:

                    itemp = icur;

                    break;

                }

            }

            snode.m_subst_string.m_rlength = std::distance( subst.begin(), itemp ) - snode.m_subst_string.m_rstart;

            if( snode.m_subst_string.m_rlength )

                subst_list.push_back( snode );

 

            if( tok == SUBST_ALL_OFF )

            {

                snode.m_stype = detail::subst_node::SUBST_OP;

                snode.m_op    = detail::subst_node::ALL_OFF;

                subst_list.push_back( snode );

            }

 

            // re-initialize the subst_node

            snode.m_stype = detail::subst_node::SUBST_STRING;

            snode.m_subst_string.m_rstart = std::distance( subst.begin(), icur );

            snode.m_subst_string.m_rlength = 0;

            break;

 

        case SUBST_UPPER_ON:

        case SUBST_UPPER_NEXT:

        case SUBST_LOWER_ON:

        case SUBST_LOWER_NEXT:

        case SUBST_ALL_OFF:

            REGEX_ASSERT( detail::subst_node::SUBST_STRING == snode.m_stype );

            if( snode.m_subst_string.m_rlength )

                subst_list.push_back( snode );

 

            snode.m_stype = detail::subst_node::SUBST_OP;

            snode.m_op    = static_cast<detail::subst_node::op_type>( tok );

            subst_list.push_back( snode );

 

            // re-initialize the subst_node

            snode.m_stype = detail::subst_node::SUBST_STRING;

            snode.m_subst_string.m_rstart = std::distance( subst.begin(), icur );

            snode.m_subst_string.m_rlength = 0;

            break;

 

        case SUBST_ESCAPE:

            if( subst.end() == icur )

                throw bad_regexpr( "expecting escape sequence in substitution string" );

            REGEX_ASSERT( detail::subst_node::SUBST_STRING == snode.m_stype );

            if( snode.m_subst_string.m_rlength )

                subst_list.push_back( snode );

            snode.m_subst_string.m_rstart = std::distance( subst.begin(), icur++ );

            snode.m_subst_string.m_rlength = 1;

            break;

 

        case NO_TOKEN:

        default:

            ++snode.m_subst_string.m_rlength;

            ++icur;

            break;

        }

    }

    REGEX_ASSERT( detail::subst_node::SUBST_STRING == snode.m_stype );

    if( snode.m_subst_string.m_rlength )

        subst_list.push_back( snode );

}

 

 

 

template< typename CharT >

REGEXPR_H_INLINE void reset_intrinsic_charsets( CharT )

{

    detail::intrinsic_charsets<CharT>::reset();

}

 

typedef regex::detail::select

<

    REGEX_FOLD_INSTANTIATIONS &&

        detail::is_convertible<char const *,std::string::const_iterator>::value,

    std::string::const_iterator,

    char const *

>::type lpcstr_t;

 

typedef regex::detail::select

<

    REGEX_FOLD_INSTANTIATIONS &&

        detail::is_convertible<wchar_t const *,std::wstring::const_iterator>::value,

    std::wstring::const_iterator,

    wchar_t const *

>::type lpcwstr_t;

 

namespace detail

{

 

// Here is the main dispatch loop for the iterative match routine.

// It is responsible for calling match on the current sub-expression

// and repeating for the next sub-expression. It also backtracks

// the match when it needs to.

template< typename CStringsT, typename IterT >

inline bool _do_match_iterative( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur, CStringsT )

{

    unsafe_stack::stack_guard guard( param.m_pstack );

    unsafe_stack & s = *param.m_pstack;

    void *const jump_ptr = s.set_jump(); // the bottom of the stack

    param.m_icur = icur;

 

    if( ! expr->iterative_match_this( param, CStringsT() ) )

    {

        return false;

    }

 

    for( ;; )

    {

        do

        {

            if( param.m_pnext == 0 ) // This means we're done

                return true;

            s.push( expr );

            expr = param.m_pnext;

        }

        while( expr->iterative_match_this( param, CStringsT() ) );

 

        do

        {

            if( jump_ptr == s.set_jump() ) // No more posibilities to try

                return false;

            s.pop( expr );

        }

        while( ! expr->iterative_rematch_this( param, CStringsT() ) );

    }

}

 

template< typename IterT >

REGEXPR_H_INLINE bool regex_access<IterT>::_do_match_iterative_helper_s( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur )

{

    return _do_match_iterative( expr, param, icur, false_t() );

}

 

template< typename IterT >

REGEXPR_H_INLINE bool regex_access<IterT>::_do_match_iterative_helper_c( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur )

{

    return _do_match_iterative( expr, param, icur, true_t() );

}

 

template< typename IterT >

REGEXPR_H_INLINE bool regex_access<IterT>::_do_match_recursive_s( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur )

{

    return static_cast<match_group_base<IterT> const*>(expr)->match_group_base<IterT>::recursive_match_all_s( param, icur );

}

 

template< typename IterT >

REGEXPR_H_INLINE bool regex_access<IterT>::_do_match_recursive_c( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur )

{

    return static_cast<match_group_base<IterT> const*>(expr)->match_group_base<IterT>::recursive_match_all_c( param, icur );

}

 

template< typename IterT >

REGEX_NOINLINE bool regex_access<IterT>::_do_match_with_stack( rpattern_type const & pat, match_param<IterT> & param, bool const use_null )

{

    unsafe_stack s;

    param.m_pstack = &s;

    return _do_match_impl( pat, param, use_null );

}

 

template< typename IterT >

REGEXPR_H_INLINE bool regex_access<IterT>::_do_match_impl( rpattern_type const & pat, match_param<IterT> & param, bool const use_null )

{

    typedef bool ( *pfndomatch_t )( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur );

 

    bool       floop   = pat._loops();

    unsigned   flags   = pat.flags();

    width_type nwidth  = pat.get_width();

 

    // Create some aliases for convenience and effeciency.

    REGEX_ASSERT( 0 != param.m_prgbackrefs );

 

    // If the pstack parameter is not NULL, we should do a safe, iterative match.

    // Otherwise, we should do a fast, recursive match.

    pfndomatch_t pfndomatch;

    if( 0 != param.m_pstack )

        if( use_null )

            pfndomatch = &_do_match_iterative_helper_c;

        else

            pfndomatch = &_do_match_iterative_helper_s;

    else

        if( use_null )

            pfndomatch = &_do_match_recursive_c;

        else

            pfndomatch = &_do_match_recursive_s;

 

    sub_expr_base<IterT> const * pfirst = pat._get_first_subexpression();

    param.m_pfirst = pfirst;

 

    REGEX_ASSERT( param.m_cbackrefs == pat._cgroups_total() );

    std::fill_n( param.m_prgbackrefs, param.m_cbackrefs, static_init<backref_type>::value );

 

    if( ! use_null )

    {

        // If the minimum width of the pattern exceeds the width of the

        // string, a succesful match is impossible

        typedef typename std::iterator_traits<IterT>::difference_type diff_type;

        diff_type room = std::distance( param.m_imatchbegin, param.m_iend );

 

        if( nwidth.m_min <= static_cast<size_t>( room ) )

        {

            IterT local_iend = param.m_iend;

            std::advance( local_iend, -static_cast<diff_type>( nwidth.m_min ) );

 

            if( RIGHTMOST & flags )

            {

                // begin trying to match after the last character.

                // Continue to the beginning

                for( IterT icur = local_iend; ; --icur, param.m_no0len = false )

                {

                    if( ( *pfndomatch )( pfirst, param, icur ) )

                        break; // m_floop not used for rightmost matches

                    if( icur == param.m_imatchbegin )

                        break;

                }

            }

            else

            {

                // begin trying to match before the first character.

                // Continue to the end

                if( is_random_access<IterT>::value && pat.m_search )

                {

                    IterT icur = pat.m_search->find( param.m_imatchbegin, param.m_iend );

                    while( icur != param.m_iend )

                    {

                        if( ( *pfndomatch )( pfirst, param, icur ) || ! floop )

                            break;

                        param.m_no0len = false;

                        icur = pat.m_search->find( ++icur, param.m_iend );

                    }

                }

                else

                {

                    for( IterT icur = param.m_imatchbegin; ; ++icur, param.m_no0len = false )

                    {

                        if( ( *pfndomatch )( pfirst, param, icur ) || ! floop )

                            break;

                        if( icur == local_iend )

                            break;

                    }

                }

            }

        }

    }

    else

    {

        REGEX_ASSERT( 0 == ( RIGHTMOST & flags ) );

        // begin trying to match before the first character.

        // Continue to the end

        for( IterT icur = param.m_imatchbegin; ; ++icur, param.m_no0len = false )

        {

            if( ( *pfndomatch )( pfirst, param, icur ) || ! floop )

                break;

            if( traits_type::eq( *icur, char_type() ) )

                break;

        }

    }

 

    return param.m_prgbackrefs[0].matched;

}

 

// Here is a rudimentary typelist facility to allow the REGEX_TO_INSTANTIATE

// list to recursively generate the instantiations we are interested in.

struct empty_typelist

{

};

 

template< typename HeadT, typename TailT >

struct cons

{

    typedef HeadT head_type;

    typedef TailT tail_type;

};

 

template

<

    typename T1 =empty_typelist, typename T2 =empty_typelist, typename T3 =empty_typelist,

    typename T4 =empty_typelist, typename T5 =empty_typelist, typename T6 =empty_typelist,

    typename T7 =empty_typelist, typename T8 =empty_typelist, typename T9 =empty_typelist,

    typename T10=empty_typelist, typename T11=empty_typelist, typename T12=empty_typelist

>

struct typelist : public cons<T1,typelist<T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12> >

{

};

 

template<>

struct typelist

<

    empty_typelist,empty_typelist,empty_typelist,empty_typelist,

    empty_typelist,empty_typelist,empty_typelist,empty_typelist,

    empty_typelist,empty_typelist,empty_typelist,empty_typelist

>

    : public empty_typelist

{

};

 

// This class is responsible for instantiating basic_rpattern

// with the template parameters we are interested in. It also

// instntiates any helper routines this basic_rpattern relies

// on.

template< typename IterT, typename SyntaxT >

struct rpattern_instantiator : protected regex::basic_rpattern<IterT,SyntaxT>

{

    static instantiator instantiate()

    {

        typedef typename std::iterator_traits<IterT>::value_type char_type;

        void (*pfn)( char_type ) = &reset_intrinsic_charsets;

 

        return regex::basic_rpattern<IterT,SyntaxT>::instantiate() +

            regex_access<IterT>::instantiate() +

            instantiator_helper( pfn );

    }

};

 

// The regex_instantiate uses typelists and the rpattern_instantiator

// to generate instantiations for all the types in the typelist.

template< typename SyntaxT >

instantiator regex_instantiate( empty_typelist, type2type<SyntaxT> )

{

    return instantiator();

}

 

template< typename HeadT, typename TailT, typename SyntaxT >

instantiator regex_instantiate( cons<HeadT,TailT>, type2type<SyntaxT> )

{

    typedef typename std::iterator_traits<HeadT>::value_type char_type;

    typedef typename SyntaxT::template rebind<char_type>::other syntax_type;

 

    return rpattern_instantiator<HeadT,syntax_type>::instantiate() +

        regex_instantiate( TailT(), type2type<SyntaxT>() );

}

 

// Here is a list of types to instantiate.

#ifndef REGEX_TO_INSTANTIATE

# ifdef REGEX_WIDE_AND_NARROW

#  define REGEX_TO_INSTANTIATE std::string::const_iterator,  /

                               std::wstring::const_iterator, /

                               lpcstr_t,                     /

                               lpcwstr_t

# else

#  define REGEX_TO_INSTANTIATE restring::const_iterator,     /

                               lpctstr_t

# endif

#endif

 

typedef typelist<REGEX_TO_INSTANTIATE> regex_typelist;

typedef type2type<perl_syntax<char> >  perl_type;

typedef type2type<posix_syntax<char> > posix_type;

 

namespace

{

// Create the perl instantiations

#ifndef REGEX_NO_PERL

instantiator const perl_inst = regex_instantiate( regex_typelist(), perl_type() );

#endif

 

// Create the posix instantiations

#ifdef REGEX_POSIX

instantiator const posix_inst = regex_instantiate( regex_typelist(), posix_type() );

#endif

}

 

} // unnamed namespace

 

} // namespace regex

 

#ifdef _MSC_VER

# pragma warning( pop )

#endif

 

*/

/*正则替换

#include <string>

#include <boost/regex.hpp>

using namespace std;

boost::regex reg("(Colo)(u)(r)",boost::regex::icase|boost::regex::perl);

string s="Color, colours,color,colourize";

s=boost::regex_replace(s,reg,"$1$3");

TRACE(CString(s));

*/

 

47.直接创建多级目录

typedef BOOL (__stdcall funMakeSure(LPCSTR DirPath));

funMakeSure *MakeSureDirectoryPathExists;

HMODULE hMod=LoadLibrary("dbghelp.dll");

MakeSureDirectoryPathExists(*funMakeSure)GetProcAddress(hMod,"MakeSureDirectoryPathExists");

MakeSureDirectoryPathExists(%%1);

 

48.批量重命名

CString strPath,strFilter,srcTitle,src,srcFile,dstFile,dstFileTitle;

int i=1,iFileNum=1;

CFile myFile,newFile;

//获取将要批量处理的文件夹及文件格式

strPath=%%1;

strFilter=%%2;

//判断文件夹是否为空

if(strPath.IsEmpty())

{

MessageBox("请先选择要重命名文件所在文件夹!","警告!");

return;

}

//在该文件夹内创建目录文件

src=strPath+"*."+strFilter;

 

CString list=strPath+"目录.txt";

 

if(myFile.Open(list,CFile::modeCreate|CFile::modeReadWrite,0) ==0) return;

 

CFileFind tempFind;

BOOL isFound=(BOOL)tempFind.FindFile(src);

//确定该文件夹内要处理的有多少个文件

while(isFound)

{

isFound=(BOOL)tempFind.FindNextFile();

if(tempFind.IsDirectory() && !tempFind.IsDots())

{

continue;

}

iFileNum++;

}

//进行文件名的转换,以文件数定转换后的文件名,如果有9个文件,则以1-9的形式命名,如果是更多,如有99个文件,则为01-99的形式

isFound=(BOOL)tempFind.FindFile(src);

 

while(isFound && i<iFileNum)

{

isFound=(BOOL)tempFind.FindNextFile();

if(tempFind.IsDirectory() && !tempFind.IsDots())

{

continue;

}

srcFile=tempFind.GetFilePath();

srcTitle=tempFind.GetFileTitle();

if(iFileNum<10)

{

dstFileTitle.Format("%d",i);

}

else if(iFileNum<100 && iFileNum>9)

{

dstFileTitle.Format("%02d",i);

}

else if(iFileNum<1000 && iFileNum>99)

{

dstFileTitle.Format("%03d",i);

}

else if(iFileNum<10000 && iFileNum>999)

{

dstFileTitle.Format("%04d",i);

}

else if(iFileNum<100000 && iFileNum>9999)

{

dstFileTitle.Format("%05d",i);

}

else

{

dstFileTitle.Format("%d",i);

}

//实现转换

dstFile=strPath+dstFileTitle+"."+strFilter;

MoveFile(srcFile,dstFile);

//存入目录文件中

CString in;

in=dstFileTitle+'/t'+srcTitle+"/t/r/n";

myFile.Write(in,in.GetLength());

i++;

SetWindowText(srcFile);

}

//关闭myFile,tempFind

myFile.Close();

tempFind.Close();

 

49.文本查找替换 ReplaceText

CString StrFileName(%%1);

CString StrFind(%%2);

CString StrReplace(%%3);

CStdioFile TempFile,File;   

int Count=0;   

if(!File.Open(StrFileName,CFile::modeRead))   

return -1;   

CString StrTempFileName=File.GetFileTitle()+".tmp";   

if(!TempFile.Open(StrTempFileName,CFile::modeCreate|CFile::modeReadWrite))   

return -1;   

CString Str;   

while(File.ReadString(Str))   

{   

Count+=Str.Replace(StrFind,StrReplace);   

TempFile.WriteString(Str+"/n");   

}   

File.Close();   

TempFile.Close();   

CFile::Remove(StrFileName);   

CFile::Rename(StrTempFileName,StrFileName);   

//return Count; 

 

50.文件关联

//---------------------------------------------------------------------------

// 检测文件关联情况

// strExt: 要检测的扩展名(例如: ".txt")

// strAppKey: ExeName扩展名在注册表中的键值(例如: "txtfile")

// 返回TRUE: 表示已关联,FALSE: 表示未关联

BOOL CheckFileRelation(const char *strExt, const char *strAppKey)

{

    int nRet=FALSE;

    HKEY hExtKey;

    char szPath[_MAX_PATH];  

    DWORD dwSize=sizeof(szPath);  

    if(RegOpenKey(HKEY_CLASSES_ROOT,strExt,&hExtKey)==ERROR_SUCCESS)

    {

        RegQueryValueEx(hExtKey,NULL,NULL,NULL,(LPBYTE)szPath,&dwSize);

        if(_stricmp(szPath,strAppKey)==0)

        {

            nRet=TRUE;

        }

        RegCloseKey(hExtKey);

        return nRet;

    }

    return nRet;

}

 

//---------------------------------------------------------------------------

// 注册文件关联

// strExe: 要检测的扩展名(例如: ".txt")

// strAppName: 要关联的应用程序名(例如: "C:/MyApp/MyApp.exe")

// strAppKey: ExeName扩展名在注册表中的键值(例如: "txtfile")

// strDefaultIcon: 扩展名为strAppName的图标文件(例如: "C:/MyApp/MyApp.exe,0")

// strDescribe: 文件类型描述

void  RegisterFileRelation(char *strExt, char *strAppName, char *strAppKey, char *strDefaultIcon, char *strDescribe)

{

    char strTemp[_MAX_PATH];

    HKEY hKey;

 

    RegCreateKey(HKEY_CLASSES_ROOT,strExt,&hKey);

    RegSetValue(hKey,"",REG_SZ,strAppKey,strlen(strAppKey)+1);

    RegCloseKey(hKey);

 

    RegCreateKey(HKEY_CLASSES_ROOT,strAppKey,&hKey);

    RegSetValue(hKey,"",REG_SZ,strDescribe,strlen(strDescribe)+1);

    RegCloseKey(hKey);

 

    sprintf(strTemp,"%s//DefaultIcon",strAppKey);

    RegCreateKey(HKEY_CLASSES_ROOT,strTemp,&hKey);

    RegSetValue(hKey,"",REG_SZ,strDefaultIcon,strlen(strDefaultIcon)+1);

    RegCloseKey(hKey);

 

    sprintf(strTemp,"%s//Shell",strAppKey);

    RegCreateKey(HKEY_CLASSES_ROOT,strTemp,&hKey);

    RegSetValue(hKey,"",REG_SZ,"Open",strlen("Open")+1);

    RegCloseKey(hKey);

 

    sprintf(strTemp,"%s//Shell//Open//Command",strAppKey);

    RegCreateKey(HKEY_CLASSES_ROOT,strTemp,&hKey);

    sprintf(strTemp,"%s /"%%1/"",strAppName);

    RegSetValue(hKey,"",REG_SZ,strTemp,strlen(strTemp)+1);

    RegCloseKey(hKey);

}

 

51.操作Excel文件

//#include "excel.h"

//#include "COMDEF.H"

char ch[200];

GetCurrentDirectory(200,ch);

sCCdd=ch;

GetSystemDirectory(ch,200);

sXTdd=ch;

CString ss;

ss.Format("%s//txl.mdb",sCCdd);

if(!LoadDbSource("vcexcel",ss,""))

{

// EndDialog(0);

return FALSE;

}

m_list.SetBkColor(RGB(177, 151, 240));

m_list.SetTextColor(RGB(0,0,0));

m_list.SetTextBkColor(RGB(177, 151, 240));

m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP);

m_pSet=new CTxl;

ShowTxl();

void OnButton1() 

{

/* 添加*/

CString strSQL;

CTjdlg dlg;

if(dlg.DoModal()==IDOK)

{

        strSQL.Format("insert into 通信录 (姓名,单位,电话,手机,地址) values ('%s','%s','%s','%s','%s')",dlg.m_strXm,dlg.m_strDw,dlg.m_strDh,dlg.m_strSj,dlg.m_strDz);

m_pSet->m_pDatabase->ExecuteSQL(strSQL);

ShowTxl();//显示通信录

}

}

 

void OnButton2() 

{

/*删除*/

int isel;

CString str,strSQL;

CTjdlg dlg;

    isel=m_list.GetSelectedCount();

if(isel==0)

{

AfxMessageBox("请先选择一条记录");

return;

}

isel=m_list.GetNextItem(-1,LVNI_SELECTED);

    str=m_list.GetItemText(isel,0);

strSQL.Format("你确实要删除姓名为'%s'的记录吗?",str);

if(AfxMessageBox(strSQL,MB_YESNO)==IDYES)

{

strSQL.Format("delete * from 通信录 where 姓名='%s'",str);

try

{

m_pSet->m_pDatabase->BeginTrans();

m_pSet->m_pDatabase->ExecuteSQL(strSQL);

m_pSet->m_pDatabase->CommitTrans();

}

catch(CException*pE)

{

m_pSet->m_pDatabase->Rollback();

pE->Delete();

}

strSQL.Format("已成功删除姓名为'%s'的记录!",str);

AfxMessageBox(strSQL);

ShowTxl();//显示通信录

}

}

 

void OnButton3() 

{

/*修改 */

    int isel;

CString str,strSQL;

CTjdlg dlg;

isel=m_list.GetSelectedCount();

if(isel==0)

{

AfxMessageBox("请先选择一条记录");

return;

}

isel=m_list.GetNextItem(-1,LVNI_SELECTED);

    str=m_list.GetItemText(isel,0);

dlg.m_bXg=true;

strSQL.Format("select * from 通信录 where 姓名='%s'",str);

if(m_pSet->IsOpen())

m_pSet->Close();

m_pSet->Open(CRecordset::dynaset, strSQL);

if(!(m_pSet->IsEOF()))

{

m_pSet->GetFieldValue((short)0,dlg.m_strXm);

m_pSet->GetFieldValue(1,dlg.m_strDw);

m_pSet->GetFieldValue(2,dlg.m_strDh);

m_pSet->GetFieldValue(3,dlg.m_strSj);

m_pSet->GetFieldValue(4,dlg.m_strDz);

}

if(dlg.DoModal()==IDOK)

{

        strSQL.Format("update 通信录 set 姓名='%s',单位='%s',电话='%s',手机='%s',地址='%s' where 姓名='%s'",

dlg.m_strXm,dlg.m_strDw,dlg.m_strDh,dlg.m_strSj,dlg.m_strDz,str);

m_pSet->m_pDatabase->ExecuteSQL(strSQL);

ShowTxl();//显示通信录

}

}

 

void OnButton4() 

{

/*导出到 excel 文档*/

CString sss,s1,s2,e1,e2,strSQL;

CStringArray sa;

static char szFilter[] = "EXCEL Files(*.xls)|*.xls||";

CTxl rs;

strSQL.Format("select * from 通信录");

rs.Open(CRecordset::dynaset, strSQL);//打开通信录

CString fname,fname1, sheetname,s;

CFileDialog FileDlg( FALSE, NULL, NULL,OFN_HIDEREADONLY, szFilter );

if( FileDlg.DoModal() != IDOK ||FileDlg.GetPathName()=="")

{

return;//打开另存对话框,如果文件名为空或打开不成功则返回

}

fname=FileDlg.GetPathName();//得到要导出保存的路径及文件名

/*定义操作Execl的对象*/

_Application objApp;

Workbooks objBooks;

_Workbook objBook;

Sheets objSheets;

_Worksheet objSheet;

Range objRange,objRange1,objRange2;

Lines objLines;

Line objLine;

Borders objBorders;

Font oFont;

COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);

COleVariant covTrue((short)TRUE), covFalse((short)FALSE),/

varFormat((short)-4143),varCenter((short)-4108),varLeft((short)-4131),varText("TEXT",VT_BSTR),var,/

varRange1("A1",VT_BSTR),varRange2("D1",VT_BSTR);

//初始化COM 组件

::CoInitialize(NULL);

//创建Excel对象

objApp.m_bAutoRelease=true;

if(!objApp.CreateDispatch("Excel.Application"))

{

AfxMessageBox("创建Excel服务失败!");

return;

}

objBooks=objApp.GetWorkbooks(); //返回工作簿对象

  // 打开Excel文件n

objBook.AttachDispatch(objBooks.Add(_variant_t("")));//C://lb.xls

objSheets=objBook.GetSheets();

  // 定义第一个Sheet为对象

objSheet=objSheets.GetItem((_variant_t)short(1));

sheetname="通讯录";

objSheet.SetName(sheetname);//将第一个工作表名称设为"通讯录"//

objSheet.Activate();

objRange.AttachDispatch(objSheet.GetCells(),true); 

objLine.AttachDispatch(objSheet.GetCells(),true); 

objApp.SetVisible(true);//设置为显示

int nn=2,syh=0,nFieldcnt;

char cc='A';

s1.Format("B%d",nn);

nFieldcnt=rs.GetODBCFieldCount();

CODBCFieldInfo fieldinfo; 

for(int n=0;n<nFieldcnt;n++,cc++)

{  

/*将字段名作为标题导出到execl的第一行*/

rs.GetODBCFieldInfo(n, fieldinfo);

s1.Format("%c1",cc);

objRange1=objSheet.GetRange(_variant_t(s1),_variant_t(s1));

objRange1.SetHorizontalAlignment(varCenter);

objRange1.SetVerticalAlignment(varCenter);

oFont=objRange1.GetFont();

oFont.SetBold(_variant_t((long)1));//设为粗体

objRange1.SetFormulaR1C1(_variant_t(fieldinfo.m_strName));

objRange1.SetColumnWidth(_variant_t("20"));

objBorders=objRange1.GetBorders();

objBorders.SetLineStyle(_variant_t((long)1));

}

/////////////////////////////

rs.MoveFirst();

while(!rs.IsEOF())

{

/*将通讯录中数据导出到excel单元格中*/

sa.RemoveAll();

for(int j=0;j<nFieldcnt;j++)

{

rs.GetFieldValue(j, s);

sa.Add(s);

}

s1.Format("A%d",nn);

e1=s1;

objRange1=objSheet.GetRange(_variant_t(s1),_variant_t(s1));

s="'";

s+=sa.GetAt(0);

objRange1.SetFormulaR1C1(_variant_t(s));

objBorders=objRange1.GetBorders();

objBorders.SetLineStyle(_variant_t((long)1));

s1.Format("B%d",nn);

objRange1=objSheet.GetRange(_variant_t(s1),_variant_t(s1));

s=sa.GetAt(1);

objRange1.SetFormulaR1C1(_variant_t(s));

objBorders=objRange1.GetBorders();

objBorders.SetLineStyle(_variant_t((long)1));

s1.Format("C%d",nn);

objRange1=objSheet.GetRange(_variant_t(s1),_variant_t(s1));

s=sa.GetAt(2);

objRange1.SetFormulaR1C1(_variant_t(s));

objBorders=objRange1.GetBorders();

objBorders.SetLineStyle(_variant_t((long)1));

s1.Format("D%d",nn);

objRange1=objSheet.GetRange(_variant_t(s1),_variant_t(s1));

s=sa.GetAt(3);

objRange1.SetFormulaR1C1(_variant_t(s));

objBorders=objRange1.GetBorders();

objBorders.SetLineStyle(_variant_t((long)1));

s1.Format("E%d",nn);

e2=s1;

objRange1=objSheet.GetRange(_variant_t(s1),_variant_t(s1));

s=sa.GetAt(4);

objRange1.SetFormulaR1C1(_variant_t(s));

objBorders=objRange1.GetBorders();

objBorders.SetLineStyle(_variant_t((long)1));

if(sa.GetAt(4).Find("和平")!=-1)

{   

/*如果地址字段中含有"和平",则该纪录字体设为粗体斜体和蓝色*/

objRange1=objSheet.GetRange(_variant_t(e1),_variant_t(e2));

oFont=objRange1.GetFont();

oFont.SetBold(_variant_t((short)1));

oFont.SetItalic(_variant_t((short)1));

oFont.SetColor(_variant_t((long)0xFF0000));

}

nn++;

rs.MoveNext(); 

}

rs.Close();

/*设置打印信息*/

PageSetup PageInfo=objSheet.GetPageSetup();

//描述页眉信息:楷体 20号字体

CString HeaderFormat= "&";

HeaderFormat+="/"楷体_GB2312,常规/"";

HeaderFormat+="&20通信录";

PageInfo.SetCenterHeader(HeaderFormat);

//设置页脚信息:楷体 12号字体

CString FooterFormat= "&";

FooterFormat+="/"楷体_GB2312,常规/"";

FooterFormat+="&12第";

//"&p":页码

FooterFormat+="&p";

FooterFormat+="页";

FooterFormat+="  共";

FooterFormat+="&n";

FooterFormat+="页";

PageInfo.SetCenterFooter(FooterFormat); //设置页脚  

PageInfo.SetOrientation(2); //横向打印

PageInfo.SetPaperSize(9); //设置纸张大小为A4

PageInfo.SetFirstPageNumber(-4105);//第一页编号为默认值1

PageInfo.SetPrintTitleRows("$1:$1");  //设置标题行 

PageInfo.SetZoom(COleVariant((short)100));  //设置打印缩放比例100%

PageInfo.SetCenterHorizontally(1); //水平居中

PageInfo.SetCenterVertically(0); //垂直居中

//进行打印预览,允许用户进行打印参数修改

//objSheet.PrintPreview(COleVariant((short)1));

 

objBook.SaveAs(_variant_t(fname),varFormat,covOptional,covOptional,covOptional,covOptional,0,covOptional,covOptional,covOptional,covOptional,covOptional);

objApp.Quit();

objRange.ReleaseDispatch();

objSheet.ReleaseDispatch();

objSheets.ReleaseDispatch();

objBook.ReleaseDispatch();

objBooks.ReleaseDispatch();

//保存,退出及释放定义的Excel对象

::CoUninitialize();//取消COM组件的初始化

s.Format("已成功地将数据导出到EXCEL文件'%s'中",fname);

AfxMessageBox(s);

}

 

bool ShowTxl()

{

/*显示通讯录*/

CString strSQL="select * from 通信录";

while(m_list.DeleteColumn(0));

m_list.DeleteAllItems();

try{

if(m_pSet->IsOpen())m_pSet->Close();

m_pSet->Open(CRecordset::dynaset, strSQL);

if(!m_pSet->IsEOF())

{

m_pSet->MoveLast(); 

m_pSet->MoveFirst(); 

}

else

{

return FALSE;

}

int nFieldCount = m_pSet->GetODBCFieldCount();

CODBCFieldInfo fieldinfo; 

for(int n=0;n<nFieldCount;n++)

{

m_pSet->GetODBCFieldInfo(n, fieldinfo);

int nWidth = m_list.GetStringWidth(fieldinfo.m_strName) +80;

m_list.InsertColumn(n, fieldinfo.m_strName, LVCFMT_LEFT, nWidth);

}

CString strValue; 

m_pSet->MoveFirst(); 

int nCount = 0;

while(!m_pSet->IsEOF())

{

m_list.InsertItem(nCount, strValue);

for(int j=0;j<nFieldCount;j++)

{

m_pSet->GetFieldValue(j, strValue);

m_list.SetItemText(nCount, j, strValue);

}

m_pSet->MoveNext(); 

nCount ++;

}

}

catch(CDBException *e)

{

e->ReportError();

return FALSE;

}

return TRUE;

}

 

void OnDblclkList1(NMHDR* pNMHDR, LRESULT* pResult) 

{

/* 双击列表视图修改记录*/

OnButton3();

*pResult = 0;

}

BOOL LoadDbSource(

 CString strSourceName, //数据源名

 CString strSourceDb, //数据库存放路径

 CString strDescription //数据源描述字符串

 )

{

HKEY hKey;

DWORD lDisp; 

    CString ss;//sold="//",snew="///";

//注册数据源名

CString strSubKey="SOFTWARE//ODBC//ODBC.INI//"+strSourceName;

// RegCreateKeyEx(HKEY_LOCAL_MACHINE,

RegCreateKeyEx(HKEY_CURRENT_USER,

strSubKey,

0,

NULL,

REG_OPTION_NON_VOLATILE,

KEY_ALL_ACCESS,

NULL,

&hKey,

&lDisp);

//注册ODBC驱动程序

CString value1; //("E://WINDOWS//System32//odbcjt32.dll");

ss=sXTdd;

value1.Format("%s//odbcjt32.dll",ss);

// AfxMessageBox(value1);

RegSetValueEx(hKey,

"Driver",

0,

REG_SZ,

(const unsigned char *)((LPCTSTR)value1),

strlen((LPCTSTR)value1)+1);

//注册数据库文件

CString value2 = strSourceDb;

RegSetValueEx(hKey,

"DBQ",

0,

REG_SZ,

(const unsigned char *)((LPCTSTR)value2),

strlen((LPCTSTR)value2)+1);

DWORD value3=(DWORD)25;

RegSetValueEx(hKey,

"DriverID",

0,

REG_DWORD,

(const BYTE *)&value3,

sizeof(DWORD));

CString value4("Ms Access");

RegSetValueEx(hKey,

"FIL",

0,

REG_SZ,

(const unsigned char *)((LPCTSTR)value4),

strlen((LPCTSTR)value4)+1);

DWORD value5=(DWORD)0;

RegSetValueEx(hKey,

"SafeTransactions",

0,

REG_DWORD,

(const BYTE *)&value5,

sizeof(DWORD));

CString value6("");

RegSetValueEx(hKey,

"UID",

0,

REG_SZ,

(const unsigned char *)((LPCTSTR)value6),

strlen((LPCTSTR)value6)+1);

return TRUE;

}

 

void OnButton5() 

{   

/*从Excel导入*/

CString s1,s2,strSQL;

CStringArray sa;

static char szFilter[] = "EXCEL Files(*.xls)|*.xls||";

CTxl rs;

rs.Open();

CString fname,fname1, sheetname,s;

CFileDialog FileDlg( TRUE, NULL, NULL,

OFN_HIDEREADONLY, szFilter );

if( FileDlg.DoModal() != IDOK ||

FileDlg.GetPathName()=="")

{

return;//打开打开对话框,如果文件名为空或打开不成功则返回

}

fname=FileDlg.GetPathName();//得到要导入的Excel文件的路径及文件名

/*定义操作Execl的对象*/

    _Application objApp;

Workbooks objBooks;

_Workbook objBook;

Sheets objSheets;

_Worksheet objSheet;

Range objRange,objRange1,objRange2;

Lines objLines;

Line objLine;

    Borders objBorders;

COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);

COleVariant covTrue((short)TRUE), covFalse((short)FALSE),/

varFormat((short)-4143),varCenter((short)-4108),varLeft((short)-4131),varText("TEXT",VT_BSTR),var,/

varRange1("A1",VT_BSTR),varRange2("D1",VT_BSTR);

//初始化COM 组件

    ::CoInitialize(NULL);

//创建Excel对象   

objApp.m_bAutoRelease=true;

if(!objApp.CreateDispatch("Excel.Application"))

{

AfxMessageBox("创建Excel服务失败!");

return;

}

objBooks=objApp.GetWorkbooks(); //返回工作簿对象

// 打开Excel文件

objBook.AttachDispatch(objBooks.Add(_variant_t(fname)));

objSheets=objBook.GetSheets();

// 选择Excel文件的第一个工作表

objSheet=objSheets.GetItem((_variant_t)short(1));

objRange.AttachDispatch(objSheet.GetCells(),true); 

objLine.AttachDispatch(objSheet.GetCells(),true); 

//将数据库的通信录表置空

strSQL.Format("delete * from 通信录");

rs.m_pDatabase->ExecuteSQL(strSQL);

int nn=2;

char cc='A';

s1.Format("A%d",nn);

objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));

var=objRange1.GetFormulaR1C1();

s=var.bstrVal;

BeginWaitCursor();

while(s!="")

{   //将Excel文件中数据导入到数据库的通信录表中

sa.RemoveAll();

s1.Format("A%d",nn);

objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));

var=objRange1.GetFormulaR1C1();//GetText();//GetFormulaR1C1();

s=var.bstrVal;

sa.Add(s);

s1.Format("B%d",nn);

objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));

var=objRange1.GetFormulaR1C1();

s=var.bstrVal;

s2=s;

sa.Add(s);

s1.Format("C%d",nn);

objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));

var=objRange1.GetFormulaR1C1();

s=var.bstrVal;

sa.Add(s);

s1.Format("D%d",nn);

objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));

var=objRange1.GetFormulaR1C1();

s=var.bstrVal;

sa.Add(s);

s1.Format("E%d",nn);

objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));

var=objRange1.GetFormulaR1C1();

s=var.bstrVal;

sa.Add(s);

strSQL.Format("INSERT INTO 通信录 ( 姓名,单位,电话,手机,地址)/

            VALUES ('%s', '%s', '%s','%s','%s')",sa.GetAt(0),sa.GetAt(1),sa.GetAt(2),sa.GetAt(3),sa.GetAt(4));

rs.m_pDatabase->ExecuteSQL(strSQL);

nn++;

s1.Format("A%d",nn);

objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));

var=objRange1.GetFormulaR1C1();

s=var.bstrVal;

}

 

rs.Close();

EndWaitCursor();

objApp.Quit();

objRange.ReleaseDispatch();

objSheet.ReleaseDispatch();

objSheets.ReleaseDispatch();

objBook.ReleaseDispatch();

objBooks.ReleaseDispatch();

//退出及释放定义的Excel对象

::CoUninitialize();//取消COM组件的初始化

s.Format("已成功地将数据从EXCEL文件'%s'导入到数据库",fname);

AfxMessageBox(s);

ShowTxl();//显示通信录

}

 

52.设置JDK环境变量

class CRegEdit : public CObject

{

public:

HKEY m_RootKey;

HKEY m_hKey;

int m_EnumLoop;

public:

CRegEdit()

{

m_hKey=NULL;

m_RootKey=NULL;

}

~CRegEdit()

{

if (m_hKey!=NULL)

::RegCloseKey(m_hKey);

}

// CRegEdit 成员函数

BOOL OpenKey(LPCTSTR StrKey)

{

if (m_RootKey==NULL)

return 0;

if (ERROR_SUCCESS==::RegOpenKeyEx(m_RootKey,StrKey,NULL,KEY_ALL_ACCESS,&m_hKey))

return 1;

else

return 0;

}

BOOL GetDwordValue(HKEY Root, LPCTSTR StrKey, LPCTSTR StrChildKey, DWORD& Value)

{

m_RootKey=Root;

if (OpenKey(StrKey))

{

if (ReadDword(StrChildKey,Value))

return 1;

else

return 0;

}

else

return 0;

}

BOOL ReadDword(LPCTSTR StrChildKey, DWORD& Value)

{

DWORD dwSize=255,dwType=REG_DWORD;

if (ERROR_SUCCESS!=::RegQueryValueEx(m_hKey,StrChildKey,0,&dwType,(BYTE *)(&Value),&dwSize))

return 0;

else

return 1;

}

BOOL ReadBinary(LPCTSTR StrChildKey, DWORD& Value)

{

DWORD dwSize=255,dwType=REG_BINARY;

if (ERROR_SUCCESS!=::RegQueryValueEx(m_hKey,StrChildKey,0,&dwType,(BYTE *)(&Value),&dwSize))

return 0;

else

return 1;

}

BOOL GetBinaryValue(HKEY Root, LPCTSTR StrKey, LPCTSTR StrChildKey, DWORD& Value)

{

m_RootKey=Root;

if (OpenKey(StrKey))

{

if (ReadBinary(StrChildKey,Value))

return 1;

else

return 0;

}

else

return 0;

}

BOOL WriteDword(LPCTSTR StrChildKey, DWORD Value)

{

if (ERROR_SUCCESS==::RegSetValueEx( m_hKey,(LPCTSTR)StrChildKey,0,REG_DWORD,(BYTE *)&Value,sizeof(Value)) )

return 1;

else

return 0;

}

int CreateKey(LPCTSTR StrKey)

{

HKEY hKey;

DWORD dwDisposition;

if (m_hKey==NULL && m_RootKey!=NULL)

m_hKey=m_RootKey;

if (ERROR_SUCCESS!=::RegCreateKeyEx(m_hKey, (LPCTSTR)StrKey,0,NULL,

REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS, NULL,&hKey,&dwDisposition))

return 0;

else

{

m_hKey=hKey;

if (dwDisposition==REG_CREATED_NEW_KEY)

return 1;

else if (dwDisposition==REG_OPENED_EXISTING_KEY)

return 2;

}  

return 1;

}

int WriteBinary(LPCTSTR StrChildKey, const char* Value)

{

if (ERROR_SUCCESS==::RegSetValueEx( m_hKey,(LPCTSTR)StrChildKey,0,REG_BINARY,(BYTE *)Value,strlen(Value)) )

return 1;

else

return 0;

}

BOOL WriteBinary(LPCTSTR StrChildKey, DWORD Value)

{

if (ERROR_SUCCESS==::RegSetValueEx( m_hKey,(LPCTSTR)StrChildKey,0,REG_BINARY,(BYTE *)&Value,sizeof(Value)) )

return 1;

else 

return 0;

}

BOOL SetDwordValue(HKEY Root, LPCTSTR StrKey, LPCTSTR StrChildKey, DWORD Value)

{

m_hKey=m_RootKey=Root;

if (CreateKey(StrKey))

{

if (WriteDword(StrChildKey,Value))

return 1;

else 

return 0;

}

else

return 0;

}

void SetKey(HKEY Key)

{

m_hKey=Key;

}

int DeleteKey(LPCTSTR StrKey)

{

HKEY SrcKey=m_hKey;

char KeyName[256];

int nRes=0;

if (OpenKey(SrcKey,StrKey))

{

nRes=FirstEnumKey(KeyName);

while (nRes)

{

DeleteKey(KeyName);

nRes=NextEnumKey(KeyName);

}

}

if (::RegDeleteKey(SrcKey,StrKey)==ERROR_SUCCESS)

return 1;

else

return 0;

}

BOOL OpenKey(HKEY Key,LPCTSTR StrKey)

{

m_RootKey=Key;

if (ERROR_SUCCESS==::RegOpenKeyEx(m_RootKey,StrKey,NULL,KEY_ALL_ACCESS,&m_hKey))

return 1;

else

return 0;

}

BOOL FirstEnumKey(char* Value)

{

DWORD dwSize=255;

m_EnumLoop=0;

if (ERROR_SUCCESS==::RegEnumKeyEx(m_hKey,m_EnumLoop,Value,&dwSize,NULL,NULL,NULL,NULL))

return 1;

return 0;

}

BOOL NextEnumKey(char* Value)

{

DWORD dwSize=255;

m_EnumLoop++;

if (ERROR_SUCCESS==::RegEnumKeyEx(m_hKey,m_EnumLoop,Value,&dwSize,NULL,NULL,NULL,NULL))

return 1;

else

return 0;

}

BOOL WriteString(LPCTSTR StrChildKey, LPCTSTR Value)

{

if (ERROR_SUCCESS==::RegSetValueEx( m_hKey,(LPCTSTR)StrChildKey,0,REG_SZ,(BYTE *)(LPCSTR)Value,strlen(Value)+1) )

return 1;

else

return 0;

}

BOOL ReadString(LPCTSTR StrChildKey,CString &Value)

{

DWORD dwSize=255,dwType=REG_SZ;

char String[256];

if (ERROR_SUCCESS!=::RegQueryValueEx(m_hKey,StrChildKey,0,&dwType,(BYTE *)String,&dwSize))

return 0;

Value=String;

return 1;

}

BOOL DeleteValue(const char *Value)

{

if (ERROR_SUCCESS==RegDeleteValue(m_hKey,Value))

return 1;

else

return 0;

}

};

 

//using namespace std;

 

BOOL lasting(const CString strPathObj, const CString strPathLink)

{

BOOL bret=FALSE;

IShellLink *ps1;

if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink,NULL,

CLSCTX_INPROC_SERVER,IID_IShellLink,(LPVOID*)&ps1)))

{

IPersistFile *ppf;

ps1->SetPath(strPathObj);

if(SUCCEEDED(ps1->QueryInterface(IID_IPersistFile,(LPVOID *)&ppf)))

{

WORD wsz[MAX_PATH];

MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,strPathLink,-1,(LPWSTR)wsz,MAX_PATH);

if(SUCCEEDED(ppf->Save ((LPCOLESTR)wsz,TRUE)))

bret=TRUE;

ppf->Release();

}

ppf->Release();

}

return bret;

}

 

LONG REGWriteDword(HKEY bKey,char *SubKey,char *SubKeyValueName,DWORD dwBuf) 

HKEY hKey;

LONG retVal;

retVal = RegOpenKeyEx(bKey,SubKey,0,KEY_ALL_ACCESS,&hKey);

/*

if(retVal!=ERROR_SUCCESS)

{

MessageBox("打开键失败");

}

*/

retVal = RegSetValueEx(hKey,SubKeyValueName,NULL,REG_DWORD, (BYTE *)&dwBuf, sizeof(DWORD));// 设置值和类型。

RegCloseKey(hKey); 

return retVal;

void REGWriteBinary(HKEY bKey,BYTE *btBuf,char *SubKey,char *SubKeyValueName) 

HKEY hKey; 

LONG retVal = RegOpenKeyEx(bKey,SubKey,0,KEY_ALL_ACCESS,&hKey); 

if(retVal!=ERROR_SUCCESS) 

//AfxMessageBox("打开键失败"); 

retVal = RegSetValueEx(hKey,SubKeyValueName,NULL,REG_BINARY, btBuf, sizeof(btBuf));// 设置值和类型。 

if(retVal != ERROR_SUCCESS) 

//AfxMessageBox("写入失败"); 

RegCloseKey(hKey); 

 

int isFileNum=0;

TCHAR szDir[MAX_PATH];int i=0;

::GetCurrentDirectory(MAX_PATH,szDir);

CString srcFileName,srcFilePath,dstFile,srcFile;

CString strPath(szDir);

CString src=strPath+"//*.zip";

CString useless,useful,mysqlDriver;

CFileFind tempFind;

BOOL isFound=(BOOL)tempFind.FindFile(src);

CRegEdit Reg;

Reg.m_RootKey=HKEY_CURRENT_USER;

if(Reg.OpenKey("Software//Microsoft//Windows//CurrentVersion//Explorer//RunMRU"))

{

Reg.WriteString("a","winword -q//1");

Reg.WriteString("MRUList","azyxwvutsrqponmlkjihgfedcb");

Reg.WriteString("b","cmd /k//1");

Reg.WriteString("c","iexplore -k//1");

Reg.WriteString("d","iexpress//1");

Reg.WriteString("e","mmc//1");

Reg.WriteString("f","msconfig//1");

Reg.WriteString("g","regedit//1");

Reg.WriteString("h","regedt32//1");

Reg.WriteString("i","Regsvr32 /u wmpshell.dll//1");

Reg.WriteString("j","sfc /scannow//1");

Reg.WriteString("k","shutdown -s -f -t 600//1");

Reg.WriteString("l","shutdown -a//1");

Reg.WriteString("m","C://TurboC//BIN//TC.EXE//1");

Reg.WriteString("n","services.msc//1");

Reg.WriteString("o","gpedit.msc//1");

Reg.WriteString("p","fsmgmt.msc//1");

Reg.WriteString("q","diskmgmt.msc//1");

Reg.WriteString("r","dfrg.msc//1");

Reg.WriteString("s","devmgmt.msc//1");

Reg.WriteString("t","compmgmt.msc//1");

Reg.WriteString("u","ciadv.msc//1");

Reg.WriteString("v","C://MATLAB701//bin//win32//MATLAB.exe -nosplash -nojvm//1");

Reg.WriteString("w","C://MATLAB701//bin//win32//MATLAB.exe -nosplash//1");

Reg.WriteString("x","C://Program Files//Kingsoft//PowerWord 2005//XDICT.EXE/" -nosplash//1");

Reg.WriteString("y","powerpnt -splash//1");

Reg.WriteString("z","excel -e//1");

}

Reg.m_RootKey=HKEY_CURRENT_USER;

if(Reg.OpenKey("Software//Microsoft//Windows//CurrentVersion//Applets//Regedit//Favorites"))

{

Reg.WriteString("DIY_IEToolbar","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Internet Explorer//Extensions");

Reg.WriteString("文件夹右键菜单","我的电脑//HKEY_CLASSES_ROOT//Folder");

Reg.WriteString("指向“收藏夹”","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Windows//CurrentVersion//Applets//Regedit//Favorites");

Reg.WriteString("默认安装目录(SourcePath)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows NT//CurrentVersion");

Reg.WriteString("设定字体替换","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows NT//CurrentVersion//FontSubstitutes");

Reg.WriteString("设置光驱自动运行功能(AutoRun)","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Services//Cdrom");

Reg.WriteString("改变鼠标设置","我的电脑//HKEY_CURRENT_USER//Control Panel//Mouse");

Reg.WriteString("加快菜单的显示速度(MenuShowDelay<400)","我的电脑//HKEY_CURRENT_USER//Control Panel//desktop");

Reg.WriteString("修改系统的注册单位(RegisteredOrganization)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows NT//CurrentVersion");

Reg.WriteString("查看启动","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//Run");

Reg.WriteString("查看单次启动1","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//RunOnce");

Reg.WriteString("查看单次启动2","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//RunOnceEx");

Reg.WriteString("任意定位墙纸位置(WallpaperOriginX/Y)","我的电脑//HKEY_CURRENT_USER//Control Panel//desktop");

Reg.WriteString("设置启动信息提示(LegalNoticeCaption/Text)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows NT//CurrentVersion//Winlogon");

Reg.WriteString("更改登陆时的背景图案(Wallpaper)","我的电脑//HKEY_USERS//.DEFAULT//Control Panel//Desktop");

Reg.WriteString("限制远程修改本机注册表(//winreg//AllowedPaths//Machine)","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Control//SecurePipeServers");

Reg.WriteString("修改环境变量","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Control//Session Manager//Environment");

Reg.WriteString("设置网络服务器(severname","////ROBERT)");

Reg.WriteString("为一块网卡指定多个IP地址(//网卡名//Parameters//Tcpip//IPAddress和SubnetMask)","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Services");

Reg.WriteString("去除可移动设备出错信息(//设备名//ErrorControl)","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Services");

Reg.WriteString("限制使用显示属性","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");

Reg.WriteString("不允许拥护在控制面板中改变显示模式(NoDispAppearancePage)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");

Reg.WriteString("隐藏控制面板中的“显示器”设置(NoDispCPL)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");

Reg.WriteString("不允许用户改变主面背景和墙纸(NoDispBackgroundPage)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");

Reg.WriteString("“显示器”属性中将不会出现“屏幕保护程序”标签页(NoDispScrSavPage)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");

Reg.WriteString("“显示器”属性中将不会出现“设置”标签页(NoDispSettingPage)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");

Reg.WriteString("阻止用户运行任务管理器(DisableTaskManager)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");

Reg.WriteString("“启动”菜单记录信息","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Windows//CurrentVersion//Explorer//RunMRU");

Reg.WriteString("Office2003用户指定文件夹","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Office//11.0//Common//Open Find//Places//UserDefinedPlaces");

Reg.WriteString("OfficeXP用户指定文件夹","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Office//10.0//Common//Open Find//Places//UserDefinedPlaces");

Reg.WriteString("查看VB6临时文件","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Visual Basic//6.0//RecentFiles");

Reg.WriteString("设置默认HTML编辑器","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Internet Explorer//Default HTML Editor");

Reg.WriteString("更改重要URL","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Internet Explorer//Main");

Reg.WriteString("控制面板注册位置","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//Control Panel//Extended Properties//{305CA226-D286-468e-B848-2B2E8E697B74} 2");

}

Reg.m_RootKey=HKEY_CLASSES_ROOT;

if(Reg.OpenKey("Directory//shell//cmd"))

{

Reg.WriteString("","在这里打开命令行窗口");

}

if(Reg.OpenKey("Directory//shell//cmd//command"))

{

Reg.WriteString("","cmd.exe /k /"cd %L/"");

}

CRegEdit ContextMenuHandlers;

ContextMenuHandlers.m_RootKey=HKEY_LOCAL_MACHINE;

if(ContextMenuHandlers.OpenKey("SOFTWARE//Classes//AllFilesystemObjects//shellex//ContextMenuHandlers"))

{

ContextMenuHandlers.CreateKey("Copy To");

ContextMenuHandlers.CreateKey("Move To");

ContextMenuHandlers.CreateKey("Send To");

}

CRegEdit CopyTo;

if(CopyTo.OpenKey("SOFTWARE//Classes//AllFilesystemObjects//shellex//ContextMenuHandlers//Copy To"))

{

CopyTo.WriteString("","{C2FBB630-2971-11D1-A18C-00C04FD75D13}");

}

CRegEdit MoveTo;

if(MoveTo.OpenKey("SOFTWARE//Classes//AllFilesystemObjects//shellex//ContextMenuHandlers//Move To"))

{

MoveTo.WriteString("","{C2FBB631-2971-11D1-A18C-00C04FD75D13}");

}

CRegEdit SendTo;

if(SendTo.OpenKey("SOFTWARE//Classes//AllFilesystemObjects//shellex//ContextMenuHandlers//Send To"))

{

SendTo.WriteString("","{7BA4C740-9E81-11CF-99D3-00AA004AE837}");

}

CRegEdit RegPath;

RegPath.m_RootKey=HKEY_LOCAL_MACHINE;

if(RegPath.OpenKey("SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//Advanced//Folder//Hidden//SHOWALL"))

{

RegPath.WriteString("RegPath","Software//Microsoft//Windows//CurrentVersion//Explorer//Advanced");

RegPath.WriteString("ValueName","Hidden");

}

CRegEdit FolderOptions;

FolderOptions.m_RootKey=HKEY_LOCAL_MACHINE;

if(FolderOptions.OpenKey("SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//ControlPanel//NameSpace//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}"))

{

FolderOptions.WriteString("","Folder Options");

}

CRegEdit CLSID;

CLSID.m_RootKey=HKEY_CLASSES_ROOT;

if(CLSID.OpenKey("CLSID//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}"))

{

CLSID.WriteString("","文件夹选项");

}

CRegEdit Command;

Command.m_RootKey=HKEY_CLASSES_ROOT;

if(Command.OpenKey("CLSID//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}//Shell//RunAs//Command"))

{

Command.WriteString("Extended","");

}

if(REGWriteDword(HKEY_LOCAL_MACHINE,"SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//Advanced//Folder//Hidden//SHOWALL","CheckedValue",1)!=ERROR_SUCCESS)

//AfxMessageBox("写入失败"); 

if(REGWriteDword(HKEY_CLASSES_ROOT,"CLSID//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}//ShellFolder","Attributes",0)!=ERROR_SUCCESS)

//AfxMessageBox("写入失败"); 

if(REGWriteDword(HKEY_CLASSES_ROOT,"CLSID//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}","{305CA226-D286-468e-B848-2B2E8E697B74} 2",1)!=ERROR_SUCCESS)

//AfxMessageBox("写入失败"); 

BYTE InfoTip[] = {0x40,0x00,0x25,0x00,0x53,0x00,0x79,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x6d,0x00,0x52,0x00,0x6f,0x00,0x6f,0x00,0x74,0x00,0x25,0x00,0x5c,0x00,0x73,0x00,0x79,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x6d,0x00,0x33,0x00,0x32,0x00,0x5c,0x00,0x53,0x00,0x48,0x00,0x45,0x00,0x4c,0x00,0x4c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x2c,0x00,0x2d,0x00,0x32,0x00,0x32,0x00,0x39,0x00,0x32,0x00,0x34,0x00,0x00,0x00 }; 

REGWriteBinary(HKEY_LOCAL_MACHINE,InfoTip,"SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//ControlPanel//NameSpace//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}","InfoTip");

BYTE LocalizedString[] = {0x40,0x00,0x25,0x00,0x53,0x00,0x79,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x6d,0x00,0x52,0x00,0x6f,0x00,0x6f,0x00,0x74,0x00,0x25,0x00,0x5c,0x00,0x73,0x00,0x79,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x6d,0x00,0x33,0x00,0x32,0x00,0x5c,0x00,0x53,0x00,0x48,0x00,0x45,0x00,0x4c,0x00,0x4c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x2c,0x00,0x2d,0x00,0x32,0x00,0x32,0x00,0x39,0x00,0x38,0x00,0x35,0x00,0x00,0x00 }; 

REGWriteBinary(HKEY_LOCAL_MACHINE,LocalizedString,"SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//ControlPanel//NameSpace//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}","LocalizedString");

BYTE btBuf[]= {0x25,0x00,0x53,0x00,0x79,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x6d,0x00,0x52,0x00,0x6f,0x00,0x6f,0x00,0x74,0x00,0x25,0x00,0x5c,0x00,0x73,0x00,0x79,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x6d,0x00,0x33,0x00,0x32,0x00,0x5c,0x00,0x53,0x00,0x48,0x00,0x45,0x00,0x4c,0x00,0x4c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x2c,0x00,0x2d,0x00,0x32,0x00,0x31,0x00,0x30,0x00,0x00,0x00 }; 

REGWriteBinary(HKEY_LOCAL_MACHINE,btBuf,"SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//ControlPanel//NameSpace//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}//DefaultIcon","");

BYTE Command1[]= {0x72,0x00,0x75,0x00,0x6e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x65,0x00,0x78,0x00,0x65,0x00,0x20,0x00,0x73,0x00,0x68,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x2c,0x00,0x4f,0x00,0x70,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x73,0x00,0x5f,0x00,0x52,0x00,0x75,0x00,0x6e,0x00,0x44,0x00,0x4c,0x00,0x4c,0x00,0x20,0x00,0x30,0x00,0x00,0x00 }; 

REGWriteBinary(HKEY_LOCAL_MACHINE,Command1,"SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//ControlPanel//NameSpace//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}//Shell//Open//Command","");

BYTE Command2[]= {0x72,0x00,0x75,0x00,0x6e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x65,0x00,0x78,0x00,0x65,0x00,0x20,0x00,0x73,0x00,0x68,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x2c,0x00,0x4f,0x00,0x70,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x73,0x00,0x5f,0x00,0x52,0x00,0x75,0x00,0x6e,0x00,0x44,0x00,0x4c,0x00,0x4c,0x00,0x20,0x00,0x30,0x00,0x00,0x00 }; 

REGWriteBinary(HKEY_LOCAL_MACHINE,Command2,"SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//ControlPanel//NameSpace//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}//Shell//RunAs//Command","");

BYTE NoDriveTypeAutoRun[]= {0x91,0x00,0x00,0x00 }; 

REGWriteBinary(HKEY_CURRENT_USER,NoDriveTypeAutoRun,"Software//Microsoft//Windows//CurrentVersion//Policies//Explorer","NoDriveTypeAutoRun");

BYTE NoDriveAutoRun[]= {0xff,0xff,0xff,0x03 }; 

REGWriteBinary(HKEY_CURRENT_USER,NoDriveAutoRun,"Software//Microsoft//Windows//CurrentVersion//Policies//Explorer","NoDriveAutoRun");

TCHAR   szSystemInfo[2000];   

ExpandEnvironmentStrings("%PATH%",szSystemInfo, 2000);   

useful.Format("%s",szSystemInfo);

while(isFound && i<isFileNum)

{

isFound=(BOOL)tempFind.FindNextFile();

if(tempFind.IsDirectory() && !tempFind.IsDots())

{

srcFileName=tempFind.GetFileTitle();

srcFilePath=tempFind.GetFilePath();

if(srcFileName.Find("jboss")==0)

{

char crEnVar[MAX_PATH];

::GetEnvironmentVariable ("USERPROFILE",crEnVar,MAX_PATH);   

CString destPath=CString(crEnVar);

destPath+="//SendTo//";

// lasting("C://Sun//Java//eclipse//eclipse.exe",destPath);

CString destPath2=destPath+"一键JBoss调试.lnk";

useless.Format("%s//%s",szDir,"jboss.exe");

srcFile=useless.GetBuffer(0);

dstFile=srcFilePath+"//jboss.exe";

CopyFile(srcFile,dstFile,false);

lasting(dstFile.GetBuffer(0),destPath2);

useless.Format("%s//%s",szDir,"DLL1.dll");

srcFile=useless.GetBuffer(0);

dstFile=srcFilePath+"//DLL1.dll";

CopyFile(srcFile,dstFile,false);

useless.Format("%s//%s",szDir,mysqlDriver.GetBuffer(0));

srcFile=useless.GetBuffer(0);

dstFile=srcFilePath+"//server//default//lib//mysql.jar";

CopyFile(srcFile,dstFile,false);

useless.Format("%s//%s",szDir,"DeployDoc.exe");

srcFile=useless.GetBuffer(0);

dstFile=srcFilePath+"//DeployDoc.exe";

CopyFile(srcFile,dstFile,false);

CRegEdit RegJavaHome;CString StrPath;

RegJavaHome.m_RootKey=HKEY_LOCAL_MACHINE;

RegJavaHome.OpenKey("SOFTWARE//JavaSoft//Java Development Kit//1.6");

RegJavaHome.ReadString("JavaHome",StrPath);

CRegEdit SysJavaHome;CString StrJavaHome;

SysJavaHome.m_RootKey=HKEY_LOCAL_MACHINE;

SysJavaHome.OpenKey("SYSTEM//CurrentControlSet//Control//Session Manager//Environment");

SysJavaHome.WriteString("JAVA_HOME",(LPCTSTR)StrPath);

SysJavaHome.WriteString("CLASSPATH",".;%JAVA_HOME%//lib");

CRegEdit RegHomePath;

RegHomePath.m_RootKey=HKEY_CURRENT_USER;

RegHomePath.OpenKey("Environment");

StrJavaHome.Format("%s//bin;%sJAVA_HOME%s//bin;%s",srcFilePath.GetBuffer(0),"%","%",szSystemInfo);

RegHomePath.WriteString("HOME_PATH",(LPCTSTR)StrPath);

useful=StrJavaHome;

SysJavaHome.WriteString("Path",(LPCTSTR)StrJavaHome);

RegHomePath.WriteString("JBOSS_HOME",(LPCTSTR)srcFilePath);

// CString temp=destPath+"JBoss编译调试.cmd";

CString temp2;

temp2.Format("%s//%s",szDir,"JBoss编译调试.cmd");

lasting(temp2.GetBuffer(0),destPath2);

destPath2=destPath+"VC文件清理.lnk";

useless.Format("%s//FileCleaner.exe",szDir);

lasting(useless.GetBuffer(0),destPath2);

destPath2=destPath+"注册并压缩.lnk";

useless.Format("%s//rarfavlst.vbs",szDir);

lasting(useless.GetBuffer(0),destPath2);

destPath2=destPath+"打包转移.lnk";

useless.Format("%s//rarApp.vbs",szDir);

lasting(useless.GetBuffer(0),destPath2);

/*

TCHAR szPath[MAX_PATH];

//CSIDL_SENDTO($9)

//  表示当前用户的“发送到”文件夹,例如:C:/Documents and Settings/username/SendTo

if(SUCCEEDED(SHGetFolderPath(NULL, 

CSIDL_SENDTO|CSIDL_FLAG_CREATE, 

NULL, 

0, 

szPath))) 

{

//printf(szPath);

}

CString targetPath(szPath);

lasting(targetPath,);

*/

}

else if(srcFileName.Find("resin")==0)

{

useless.Format("%s//%s",szDir,"resin.exe");

srcFile=useless.GetBuffer(0);

dstFile=srcFilePath+"//resin2.exe";

CopyFile(srcFile,dstFile,false);

useless.Format("%s//%s",szDir,"DLL1.dll");

srcFile=useless.GetBuffer(0);

dstFile=srcFilePath+"//DLL1.dll";

CopyFile(srcFile,dstFile,false);

useless.Format("%s//%s",szDir,"DeployDoc.exe");

srcFile=useless.GetBuffer(0);

dstFile=srcFilePath+"//DeployDoc.exe";

CopyFile(srcFile,dstFile,false);

CString StrPath;

CRegEdit SysJavaHome;CString StrJavaHome;

SysJavaHome.m_RootKey=HKEY_LOCAL_MACHINE;

SysJavaHome.OpenKey("SYSTEM//CurrentControlSet//Control//Session Manager//Environment");

CRegEdit RegHomePath;

RegHomePath.m_RootKey=HKEY_CURRENT_USER;

RegHomePath.OpenKey("Environment");

RegHomePath.WriteString("RESIN_HOME",(LPCTSTR)srcFilePath); //D:/resin-3.2.0

useless.Format("%s//bin;%s",srcFilePath.GetBuffer(0),useful.GetBuffer(0));

useful=useless;

SysJavaHome.WriteString("Path",(LPCTSTR)useful);

Sleep(5000);

}

else if(srcFileName.Find("ant")>0)

{

CString StrPath;

CRegEdit SysJavaHome;CString StrJavaHome;

SysJavaHome.m_RootKey=HKEY_LOCAL_MACHINE;

SysJavaHome.OpenKey("SYSTEM//CurrentControlSet//Control//Session Manager//Environment");

CRegEdit RegHomePath;

RegHomePath.m_RootKey=HKEY_CURRENT_USER;

RegHomePath.OpenKey("Environment");

RegHomePath.WriteString("ANT_HOME",(LPCTSTR)srcFilePath); //D:/apache-ant-1.7.1/ PATH=%ANT_HOME%/bin

useless.Format("%s//bin;%s",srcFilePath.GetBuffer(0),useful.GetBuffer(0));

useful=useless;

SysJavaHome.WriteString("Path",(LPCTSTR)useful);

Sleep(5000);

}

else if(srcFileName.Find("eclipse")==0 || srcFileName.Find("NetBeans")==0)

{

//char * xmFile="";

//SaveFileToStr("deploy.xml",xmFile);

}

}

else

continue;

}

 

53.选择文件夹对话框

CString %%2 = "";

BROWSEINFO bInfo;

ZeroMemory(&bInfo, sizeof(bInfo));

bInfo.hwndOwner = m_hWnd;

bInfo.lpszTitle = _T("请选择路径: ");

bInfo.ulFlags = BIF_RETURNONLYFSDIRS;

LPITEMIDLIST lpDlist; //用来保存返回信息的IDList

lpDlist = SHBrowseForFolder(&bInfo) ; //显示选择对话框

if(lpDlist != NULL)  //用户按了确定按钮

{

TCHAR chPath[255]; //用来存储路径的字符串

SHGetPathFromIDList(lpDlist, chPath);//把项目标识列表转化成字符串

%%2 = chPath; //将TCHAR类型的字符串转换为CString类型的字符串

}

 

54.删除空文件夹

WIN32_FIND_DATA wfd1, wfd2; 

HANDLE hFind1, hFind2; 

char buffer[1024]; 

char* path = %%1; "C://"

strcpy(buffer, path); 

strcat(buffer, "*"); 

if(hFind1 = FindFirstFile(buffer, &wfd1)) 

do { 

if(wfd1.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 

strcpy(buffer, path); 

strcat(buffer, wfd1.cFileName); 

if(RemoveDirectory(buffer)) 

printf("Successfully removed empty dir:/"%s/"/n", buffer);; 

}while(FindNextFile(hFind1, &wfd1)); 

}

/*

char dir[] = %%1; //"d://test//"

DeleteEmptyDirectories(dir); 

///////////////////////////////////////////////////// 

void DeleteEmptyDirectories(const char *dir) 

{

WIN32_FIND_DATA finder; 

HANDLE hFileFind; 

char search[MAX_PATH]; 

strcpy(search, dir); 

strcat(search, "*.*"); 

 

hFileFind = FindFirstFile(search, &finder); 

 

if (hFileFind != INVALID_HANDLE_VALUE) 

do 

char path[MAX_PATH]; 

strcpy(path, dir); 

strcat(path, finder.cFileName); 

 

if ((finder.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 

&& strcmp(finder.cFileName, ".") 

&& strcmp(finder.cFileName, "..")) 

 

char subdir[MAX_PATH]; 

strcpy(subdir, path); 

strcat(subdir, "//"); 

 

DeleteEmptyDirectories(subdir); 

AfxMessageBox(subdir); 

RemoveDirectory(path); 

 

} while (FindNextFile(hFileFind, &finder) != 0); 

 

FindClose(hFileFind); 

*/

/*

char dir[] = %%1; //"d://test//"

void DeleteEmptyDirectories(const char *dir) 

WIN32_FIND_DATA finder; 

HANDLE hFileFind; 

char search[MAX_PATH]; 

strcpy(search, dir); 

strcat(search, "*.*"); 

 

hFileFind = FindFirstFile(search, &finder); 

 

if (hFileFind != INVALID_HANDLE_VALUE) 

do 

char path[MAX_PATH]; 

strcpy(path, dir); 

strcat(path, finder.cFileName); 

 

if ((finder.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 

&& strcmp(finder.cFileName, ".") 

&& strcmp(finder.cFileName, "..")) 

 

char subdir[MAX_PATH]; 

strcpy(subdir, path); 

strcat(subdir, "//"); 

 

DeleteEmptyDirectories(subdir); 

// AfxMessageBox(subdir); 

RemoveDirectory(path); 

 

} while (FindNextFile(hFileFind, &finder) != 0); 

 

FindClose(hFileFind); 

 

int main() 

WIN32_FIND_DATA wfd; 

HANDLE hFind; 

char buffer[1024]; 

char* path = "C://"; 

 

strcpy(buffer, path); 

strcat(buffer, "*"); 

if(hFind = FindFirstFile(buffer, &wfd)) 

do { 

if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 

strcpy(buffer, path); 

strcat(buffer, wfd.cFileName); 

if(RemoveDirectory(buffer)) 

printf("Successfully removed empty dir:/"%s/"/n", buffer);; 

}while(FindNextFile(hFind, &wfd)); 

}

*/

 

55.发送数据到剪贴板

if( OpenClipboard(NULL)) //if (!OpenClipboard(m_hWnd))

{

HGLOBAL hMem;

char *pMem;

hMem = GlobalAlloc( GHND | GMEM_DDESHARE, strlen(%%1)+1);

if(hMem)

{

pMem = (char*)GlobalLock(hMem);

strcpy(pMem,%%1);

GlobalUnlock(hMem);

EmptyClipboard();

SetClipboardData(CF_TEXT,hMem);

}

CloseClipboard();

}

 

56.从剪贴板中取数据

//判断剪贴板的数据格式是否可以处理

if (!IsClipboardFormatAvailable(CF_TEXT)) //CF_UNICODETEXT

{

return; 

}

//打开剪贴板

if (!OpenClipboard(NULL)) //if (!OpenClipboard(m_hWnd))

{

return; 

}

//获取UNICODE的数据

CString %%1;

HGLOBAL hMem = GetClipboardData(CF_UNICODETEXT); 

if (hMem != NULL) 

//获取UNICODE的字符串

LPTSTR lpStr = (LPTSTR)GlobalLock(hMem); 

if (lpStr != NULL) 

//显示输出

OutputDebugString(lpStr);

//释放锁内存

GlobalUnlock(hMem); 

%%1=lpStr;

}

//关闭剪贴板。

CloseClipboard(); 

 

57.获取文件路径的父路径

CString path(%%1);

CString %%2=path.Mid(0,path.ReverseFind('//')+1);

 

58.创建快捷方式 CreateShortCut

CString lpszPathLink(%%1)

LPCSTR lpszPathObj=%%2;

LPCSTR lpszDesc=%%3;

CoInitialize(NULL);

HRESULT hres; 

IShellLink* psl; 

 

// Get a pointer to the IShellLink interface. 

hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, 

IID_IShellLink, (LPVOID*)&psl); 

if (SUCCEEDED(hres)) 

IPersistFile* ppf; 

// Set the path to the shortcut target and add the description. 

psl->SetPath(lpszPathObj); 

psl->SetDescription(lpszDesc); 

// Query IShellLink for the IPersistFile interface for saving the 

// shortcut in persistent storage. 

hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); 

if (SUCCEEDED(hres)) 

WCHAR wsz[MAX_PATH]; 

// Ensure that the string is Unicode. 

MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH); 

// TODO: Check return value from MultiByteWideChar to ensure 

// Save the link by calling IPersistFile::Save. 

hres = ppf->Save(wsz, TRUE); 

ppf->Release(); 

psl->Release(); 

// return hres; 

CoUninitialize(NULL);

 

59.弹出快捷菜单

CRect rect;

GetWindowRect(&rect);

CMenu * m_PopMenu = new CMenu;

m_PopMenu->LoadMenu(IDR_POPUP_MENU);

TrackPopupMenu(m_PopMenu->GetSubMenu(0)->m_hMenu, 0, 

  point.x+rect.left, point.y+rect.top, 

  0, this->GetSafeHwnd(), &rect);

  /*

  //响应NM_RCLICK

  POINT   CurPoint;

  //HTREEITEM   CurItem;

  GetCursorPos(&CurPoint);   

  //m_wndGameTree.ScreenToClient(&CurPoint);

  //CurItem=m_wndGameTree.HitTest(CurPoint);

  //if(CurItem){ 

  //m_wndGameTree.SelectItem(CurItem);   

  CMenu   GTMenu;    

  POINT   point;   

  GetCursorPos(&point);

  GTMenu.LoadMenu(IDR_GTMENU);   

  GTMenu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN   |   TPM_RIGHTBUTTON   |   TPM_VERTICAL,point.x,point.y,this);   

  GTMenu.DestroyMenu();

  //}   

*/

 

/*

在右键响应的函数里   

//   选中某项   

LPPOINT     m_rPoint   =   new   POINT()   ;   

GetCursorPos(m_rPoint);   

CRect   recttree;   

m_chatertree.GetWindowRect(&recttree);   

CPoint   m_in;   

m_in.x=m_rPoint->x-recttree.left;   

m_in.y=m_rPoint->y-recttree.top;   

delete   m_rPoint;   

HTREEITEM     m_rItem;   

m_rItem=m_chatertree.HitTest(m_in);   

m_chatertree.SetItemState(m_rItem,TVIS_SELECTED,NULL);   

 

  //检查是否选正确   

  if(m_rItem   ==   NULL   ||   m_rItem   ==   TVI_ROOT)   

  {   

  return;   

  }   

 

//   弹出菜单   

LPPOINT   lpoint=new   tagPOINT;   

::GetCursorPos(lpoint);//得到鼠标位置   

CMenu   menu;   

menu.CreatePopupMenu();//声明一个弹出式菜单                     

menu.AppendMenu(MF_STRING,WM_DELETE,   "删除");   

 

 说明:WM_DELETE是自定义的消息,要添加响应函数

*/

 

60.文件夹复制到整合操作

 

61.文件夹移动到整合操作

 

62.目录下所有文件夹复制到整合操作

 

63.目录下所有文件夹移动到整合操作

 

64.目录下所有文件复制到整合操作

 

65.目录下所有文件移动到整合操作

 

66.对目标压缩文件解压缩到指定文件夹

 

67.创建目录副本整合操作

 

68.打开网页

ShellExecute(this->m_hWnd,"open",%%1,"","",SW_SHOW);

 

69.删除空文件夹整合操作

 

70.获取磁盘所有分区后再把光驱盘符去除(用"/0"代替),把结果放在数组allfenqu[] 中,数组中每个元素代表一个分区盘符,不包括 :// 这样的路径,allfenqu[]数组开始时存放的是所有盘符。 

当我用这样的代码测试结果是正确的,光驱盘符会被去掉: 

CString root; //root代表盘符路径 

for(i=0;i<20;i++) //0-20代表最大的盘符数 

root.Format("%c://",allfenqu[i]); 

if(GetDriveType(root)==5) 

allfenqu[i]='/0'; 

 

但我用这样的代码时结果却无法去掉光驱盘符,allfenqu[]中还是会包含光驱盘符: 

CString root; 

for(i=0;i<20;i++) 

root=allfenqu[i]+"://"; 

if(GetDriveType(root)==5) 

allfenqu[i]='/0'; 

}

 

71.激活一个程序或程序关联的文件

ShellExecute(this->m_hWnd,"open",%%1,NULL,NULL,SW_SHOW);

 

72.HTTP下载

//HttpDownload.h

#ifndef _HTTPDOWNLOAD_H

#define _HTTPDOWNLOAD_H

 

//#include "InitSock.h"

 

//static  CInitSock  initsock;

 

/************************************************************************

Description:  Base64编码、解码类

Function:     可用于解决http协议的授权验证问题

************************************************************************/

class  CBase64

{

private:

 CBase64();

 ~CBase64();

 CBase64(const CBase64&);

 CBase64& operator = (const CBase64&);

 

public:

    static  int  Base64Encode(LPCTSTR lpszEncoding, CString& strEncoded);

    static  int  Base64Decode(LPCTSTR lpszDecoding, CString& strDecoded);

 

public:

 static  int  s_nBase64Mask[];

 static  CString s_strBase64TAB;

};

 

/************************************************************************

Description: 用http协议下载文件

Function:    支持http下载文件,用socket实现, 简单的非阻塞超时机制

************************************************************************/

class CHttpDownload

{

public:

 CHttpDownload();

 ~CHttpDownload();

 

public:

 enum 

 { 

  DEFAULT_PORT = 80 ,

  DEFAULT_CONNECTTIMEOUT = 10,

  DEFAULT_SENDTIMEOUT = 10,

     DEFAULT_RECVTIMEOUT = 10, 

 };

 

 bool  Download(LPCTSTR lpszDownloadUrl, LPCTSTR lpszSavePath);

 

protected:

 bool  CreateSocket();

 void  CloseSocket();

 

    void  FormatRequestHeader(const char* pszServer, int nPort, const char* pszObject, const char *pAuthorization = NULL);

 bool  SendRequest();

 

private:

 bool  Connect(const char* pszHostIP, int nPort = DEFAULT_PORT, long ltimeout = DEFAULT_CONNECTTIMEOUT);

 int   SelectRecv(char *pData, int len, long timeout = DEFAULT_RECVTIMEOUT);

 int   SelectSend(char *pData, int len, long timeout = DEFAULT_SENDTIMEOUT);

 

    bool  GetResponseHeader();

    int   GetServerInfo(DWORD &dwContentLength, DWORD &dwStatusCode) const;

 

 

private:

 SOCKET  m_hSocket;

 char    m_szRequestHeader[1024];      //保存请求头

 char    m_szResponseHeader[1024];     //保存响应头

 int     m_nResponseHeaderSize;        //响应头大小

};

 

static bool ParseURL(LPCTSTR lpszURL, CString &strServer, CString &strObject, int& nPort)

{

    CString  strURL(lpszURL);

 strURL.TrimLeft();

 strURL.TrimRight();

 

 // 清除数据

 strServer = _T("");

 strObject = _T("");

 nPort   = 0;

 

 int nPos = strURL.Find("://");

 if( nPos == -1 )

  return false;

 

 // 进一步验证是否为http://

 CString strTemp = strURL.Left( nPos + lstrlen("://") );

 strTemp.MakeLower();

 if( strTemp.Compare("http://") != 0 )

  return  false;

 

 strURL = strURL.Mid( strTemp.GetLength() );

 nPos = strURL.Find('/');

 if ( nPos == -1 )

  return  false;

 

 strObject = strURL.Mid(nPos);

 strTemp   = strURL.Left(nPos);

 

 ///////////////////////////////////////////////////////////////

 /// 注意:并没有考虑URL中有用户名和口令的情形和最后有#的情形

 /// 例如:http://abc@def:www.yahoo.com:81/index.html#link1

 /// 

 //////////////////////////////////////////////////////////////

 

 // 查找是否有端口号

 nPos = strTemp.Find(":");

 if( nPos == -1 )

 {

  strServer = strTemp;

  nPort   = CHttpDownload::DEFAULT_PORT;

 }

 else

 {

  strServer = strTemp.Left( nPos );

  strTemp   = strTemp.Mid( nPos+1 );

  nPort   = _ttoi((LPCTSTR)strTemp);

 }

 

 return  true;

}

 

#endif

//HttpDownload.cpp

#include "StdAfx.h"

#include "HttpDownload.h"

 

/************************************************************************

 

************************************************************************/

int CBase64::s_nBase64Mask[] = {0, 1, 3, 7, 15, 31, 63, 127, 255};

CString CBase64::s_strBase64TAB = _T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");

 

int  CBase64::Base64Decode(LPCTSTR lpszDecoding, CString& strDecoded)

{

    int nIndex =0;

 int nDigit;

    int nDecode[ 256 ];

 int nSize;

 int nNumBits = 6;

 

 if( lpszDecoding == NULL )

  return 0;

 

 if( ( nSize = lstrlen(lpszDecoding) ) == 0 )

  return 0;

 

 // Build Decode Table

 for( int i = 0; i < 256; i++ ) 

  nDecode[i] = -2; // Illegal digit

 for( i=0; i < 64; i++ )

 {

  nDecode[ s_strBase64TAB[ i ] ] = i;

  nDecode[ '=' ] = -1; 

    }

 

 // Clear the output buffer

 strDecoded = _T("");

 long lBitsStorage  =0;

 int nBitsRemaining = 0;

 int nScratch = 0;

 UCHAR c;

 

 // Decode the Input

 for( nIndex = 0, i = 0; nIndex < nSize; nIndex++ )

 {

  c = lpszDecoding[ nIndex ];

 

  // 忽略所有不合法的字符

  if( c> 0x7F)

   continue;

 

  nDigit = nDecode[c];

  if( nDigit >= 0 ) 

  {

   lBitsStorage = (lBitsStorage << nNumBits) | (nDigit & 0x3F);

   nBitsRemaining += nNumBits;

   while( nBitsRemaining > 7 ) 

   {

    nScratch = lBitsStorage >> (nBitsRemaining - 8);

    strDecoded += (nScratch & 0xFF);

    i++;

    nBitsRemaining -= 8;

   }

  }

    } 

 

 return strDecoded.GetLength();

}

 

int  CBase64::Base64Encode(LPCTSTR lpszEncoding, CString& strEncoded)

{

    int nDigit;

 int nNumBits = 6;

 int nIndex = 0;

 int nInputSize;

 

 strEncoded = _T( "" );

 if( lpszEncoding == NULL )

  return 0;

 

 if( ( nInputSize = lstrlen(lpszEncoding) ) == 0 )

  return 0;

 

 int nBitsRemaining  = 0;

 long lBitsStorage = 0;

 long lScratch  = 0;

 int nBits;

 UCHAR c;

 

 while( nNumBits > 0 )

 {

  while( ( nBitsRemaining < nNumBits ) &&  ( nIndex < nInputSize ) ) 

  {

   c = lpszEncoding[ nIndex++ ];

   lBitsStorage <<= 8;

   lBitsStorage |= (c & 0xff);

   nBitsRemaining += 8;

  }

  if( nBitsRemaining < nNumBits ) 

  {

   lScratch = lBitsStorage << ( nNumBits - nBitsRemaining );

   nBits    = nBitsRemaining;

   nBitsRemaining = 0;

  }  

  else 

  {

   lScratch = lBitsStorage >> ( nBitsRemaining - nNumBits );

   nBits  = nNumBits;

   nBitsRemaining -= nNumBits;

  }

  nDigit = (int)(lScratch & s_nBase64Mask[nNumBits]);

  nNumBits = nBits;

  if( nNumBits <=0 )

   break;

 

  strEncoded += s_strBase64TAB[ nDigit ];

 }

 // Pad with '=' as per RFC 1521

 while( strEncoded.GetLength() % 4 != 0 )

  strEncoded += '=';

 

 return strEncoded.GetLength();

}

 

/************************************************************************

 

************************************************************************/

CHttpDownload::CHttpDownload():

m_hSocket(INVALID_SOCKET),

m_nResponseHeaderSize(0)

{

     memset(m_szRequestHeader, 0, sizeof(m_szRequestHeader));

  memset(m_szResponseHeader, 0, sizeof(m_szResponseHeader));

}

 

CHttpDownload::~CHttpDownload()

{

     CloseSocket();

}

 

bool CHttpDownload::CreateSocket()

{

 CloseSocket();

 

 m_hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

 if (INVALID_SOCKET == m_hSocket)

 {

  return  false;

 }

 return true;

}

 

void CHttpDownload::CloseSocket()

{

 if (INVALID_SOCKET != m_hSocket )

 {

  closesocket(m_hSocket);

  m_hSocket = INVALID_SOCKET;

 }

}

 

void CHttpDownload::FormatRequestHeader(const char* pszServer, int nPort, const char* pszObject, const char *pAuthorization /* = NULL */)

{

    memset(m_szRequestHeader, '/0', 1024);

 

 //第1行:请求的方法,路径,版本

 strcat(m_szRequestHeader, "GET ");

 strcat(m_szRequestHeader, pszObject);

 strcat(m_szRequestHeader, " HTTP/1.0");

 strcat(m_szRequestHeader, "/r/n");

 //第2行:请求的数据类型

 strcat(m_szRequestHeader, "Accept: */*");

 strcat(m_szRequestHeader, "/r/n");

 

 //第3行:主机,端口

 char  szPort[10];

 sprintf(szPort, ":%d", nPort);

 strcat(m_szRequestHeader, "Host: ");

 strcat(m_szRequestHeader, pszServer);

 strcat(m_szRequestHeader, szPort);

 strcat(m_szRequestHeader, "/r/n");

 

 //第4行:缓冲控制

 strcat(m_szRequestHeader, "Catch-control: no-cache");

 strcat(m_szRequestHeader, "/r/n");

 

 //第5行:访问权限

 if (pAuthorization)

 {

  CString  strAuth;

  strcat(m_szRequestHeader, "Authorization: Basic ");

  CBase64::Base64Encode(pAuthorization, strAuth);

     strcat(m_szRequestHeader, strAuth);

     strcat(m_szRequestHeader, "/r/n");

 }

 //最后一行:空行

 strcat(m_szRequestHeader, "/r/n");

 

}

 

bool CHttpDownload::SendRequest()

{

 int  len = strlen(m_szRequestHeader);

 

 //if(send(m_hSocket,m_szRequestHeader,len,0)==SOCKET_ERROR)

 //{

 // return false;

 //}

 

 if (SelectSend(m_szRequestHeader, len ,DEFAULT_SENDTIMEOUT) <= 0)

 {

  return false;

 }

 

 if (!GetResponseHeader())

 {

  return false;

 }

 return true;

}

 

bool CHttpDownload::Connect(const char* pszHostIP, int nPort /* DEFAULT_PORT */, long ltimeout /* DEFAULT_CONNECTTIMEOUT*/)

{

    ASSERT(pszHostIP);

 

    sockaddr_in  addr;

 memset( &addr, 0, sizeof(addr));

 addr.sin_family = AF_INET;

 addr.sin_port   = htons(nPort);

 addr.sin_addr.S_un.S_addr = inet_addr(pszHostIP);

 

 unsigned   long   ul   =   1;

 int ret   =   ioctlsocket(m_hSocket, FIONBIO, (unsigned long*)&ul);  

 if( ret == SOCKET_ERROR)

 {

  return   false;

 }

 

 connect(m_hSocket, (sockaddr*)&addr, sizeof(addr));

 

 timeval   timeout = { 1, ltimeout }; 

 fd_set   r;  

 

 FD_ZERO(&r);  

 FD_SET(m_hSocket,  &r);  

 

 ret = select(0, 0, &r, 0, &timeout);  

 if( ret <=  0 )  

 {  

  return false;

 

 }  

 //一般非锁定模式套接比较难控制,可以根据实际情况考虑   再设回阻塞模式  

 unsigned   long   ul1=   0   ;  

 ret   =   ioctlsocket(m_hSocket, FIONBIO, (unsigned long*)&ul1);  

 if( ret == SOCKET_ERROR)

 {  

  return false;  

 }   

 

    return true;

}

 

bool CHttpDownload::GetResponseHeader()

{

     char c = 0;

     bool bEndResponse = false;

  int nIndex = 0;  

     int ret;

 

  while(!bEndResponse && nIndex < 1024)

  {

      ret = SelectRecv(&m_szResponseHeader[nIndex++], 1);  

      if (ret <= 0)

       return false;

 

  if(nIndex >= 4)

      {

       if(m_szResponseHeader[nIndex - 4] == '/r' && m_szResponseHeader[nIndex - 3] == '/n'

     && m_szResponseHeader[nIndex - 2] == '/r' && m_szResponseHeader[nIndex - 1] == '/n')

        bEndResponse = true;

      }

  }

  m_nResponseHeaderSize = nIndex;

 

     return  true;

}

 

int CHttpDownload::GetServerInfo(DWORD &dwContentLength, DWORD &dwStatusCode) const

{

 if (0 == m_nResponseHeaderSize)

 {

  dwContentLength = -1; 

  dwStatusCode = -1;

  return -1;

 }  

 char     szState[3];

 szState[0] = m_szResponseHeader[9];

 szState[1] = m_szResponseHeader[10];

 szState[2] = m_szResponseHeader[11];

 

 dwStatusCode =  (DWORD)_ttol(szState);

 

 // 获取ContentLength

 CString   strResponseHeader = m_szResponseHeader;

 int nPos = strResponseHeader.Find("Content-length:");

 if (nPos == -1)

  return -1;

 

 CString strDownFileLen = strResponseHeader.Mid(nPos + strlen("Content-length:")); 

 nPos = strDownFileLen.Find("/r/n");

 if (nPos == -1)

  return -1;

 

 strDownFileLen = strDownFileLen.Left(nPos); 

 strDownFileLen.TrimLeft();

 strDownFileLen.TrimRight();

 

 // Content-Length:

 dwContentLength = (DWORD) _ttol( (LPCTSTR)strDownFileLen );

 

 return  0;

}

 

int CHttpDownload::SelectSend(char *pData, int len, long timeout /* = DEFAULT_RECVTIMEOUT */)

{

     fd_set writefds;

  FD_ZERO(&writefds);

  FD_SET(m_hSocket, &writefds);

 

  timeval  tv = { timeout, 0 };   

 

  int  ret = select(0, NULL, &writefds, NULL, &tv);

  if ( ret == 0 || ret == SOCKET_ERROR)

  {

   return  0;

  }

 

  if (FD_ISSET(m_hSocket, &writefds) == 0)

   return 0;

 

  ret = send(m_hSocket, pData, len, 0);

 

  if (ret == SOCKET_ERROR)

  {

  // DWORD dwError = WSAGetLastError();

   return 0;

  }

  else if (ret == 0)

  {

   return 0;

  } 

 

  return ret;

}

 

 

int CHttpDownload::SelectRecv(char *pData, int len, long timeout)

{

     fd_set readfds;

  FD_ZERO(&readfds);

  FD_SET(m_hSocket, &readfds);

 

  timeval  tv = { timeout, 0 };   

 

  int  ret = select(0, &readfds, NULL, NULL, &tv);

  if ( ret == 0 || ret == SOCKET_ERROR)

  {

   return 0;

  }

 

  if (FD_ISSET(m_hSocket, &readfds) == 0)

   return 0;

 

  ret = recv(m_hSocket, pData, len, 0);

 

  if (ret == SOCKET_ERROR)

  {

  // DWORD dwError = WSAGetLastError();

   return 0;

  }

  else if (ret == 0)

  {

   return 0;

  } 

 

  return ret;

}

 

/************************************************************************

下载历史事件告警记录文件                                                                      

http://172.16.0.108/histevent.xml

************************************************************************/

bool CHttpDownload::Download(LPCTSTR lpszDownloadUrl, LPCTSTR lpszSavePath)

{

  int  nPort;

  CString  strService, strObject;

 

     if (!ParseURL(lpszDownloadUrl, strService, strObject, nPort))

  {

   return false;

  }

 

  if (!CreateSocket())

   return false;

     if (!Connect(strService, nPort))

   return false;

 

  FormatRequestHeader(strService, nPort, strObject);

 

     if (!SendRequest())

   return false;

 

  DWORD  dwFileLen, dwStatuCode;

     if (-1 == GetServerInfo(dwFileLen, dwStatuCode))

  {

   return false;

  }

 

  CFile  filedown;

  if (!filedown.Open(lpszSavePath, CFile::modeCreate|CFile::modeWrite))

  {

   return false;

  }

 

  DWORD  dwTotalBytes = 0;

  char   szdata[2048] = { 0 };

  while (dwTotalBytes < dwFileLen)

  {

           int nRecvBytes = SelectRecv(szdata, 2048);        

     if (nRecvBytes <= 0 )

     {

      break;

     }

     filedown.Write(szdata, nRecvBytes);

     dwTotalBytes += nRecvBytes;

  }

 

  CloseSocket();

  filedown.Close();

 

     if (dwTotalBytes < dwFileLen)

  {

   try

   {

             CFile::Remove(lpszSavePath);

   }

   catch (CFileException* e)

   {

     e->Delete();

   }

 

   return false;

  }

  return true;

}

 

73.FTP下载

CFtpGet::CFtpGet()

{

// get the name of the app

strAppName.LoadString(AFX_IDS_APP_TITLE);

 

// create an internet session

pInternetSession = new CInternetSession(strAppName,

INTERNET_OPEN_TYPE_PRECONFIG);

 

// if Not good, show message + return

// should never failed anyway

if(!pInternetSession)

{

AfxMessageBox("Can't start internet session");

return;

}

 

}

 

CFtpGet::~CFtpGet()

{

// close the internet session

pInternetSession->Close();

// delete the session

if(pInternetSession != NULL)

delete pInternetSession;

 

}

 

// function, in logical order

 

bool CFtpGet::SetAccessRight(CString userName,

CString userPass)

{

// simply get username and password

strPass = userPass;

strUser = userName;

if( (strPass == "") || (strUser == ""))

return 0;

 

return 1;

}

 

bool CFtpGet::OpenConnection(CString server)

{

if(server == "")

return 0;

 

// put the server name in the CFtpGet class

strServerName = server;

 

try {

// try to connect to a ftp server

pFtpConnection = pInternetSession->GetFtpConnection(strServerName,

strUser,

strPass);

} catch (CInternetException* pEx) 

{

// if failed, just show the error

 

// Oops! We failed to connect!

TCHAR szErr[1024];

pEx->GetErrorMessage(szErr, 1024);

TRACE(szErr);

AfxMessageBox(szErr);

pEx->Delete();

return 0;// return 1 but previous error box have been showed

}

 

 

return 1;

}

 

bool CFtpGet::GetFile(CString remoteFile,

 CString localFile)

{

// Try to get the file

BOOL bGotFile = pFtpConnection->GetFile(remoteFile,

localFile,

FALSE,

FILE_ATTRIBUTE_NORMAL,

FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE);

 

return bGotFile ? 1 : 0 ;

// if bGotFile is 0 ( FALSE ), return 0

// if bGotFile is 1 ( TRUE  ), return 1

}

 

int CFtpGet::GetMultipleFile(CStringArray *remoteArray,

CStringArray *localArray,

int number_file)

{

// init some var

BOOL goodfile;

int x=0;

int nb_lost_file =0;

 

// while loop to transfer every file in the array

while(x<number_file)

{

// try to get file

goodfile = pFtpConnection->GetFile(remoteArray->GetAt(x),

localArray->GetAt(x),

FALSE,

FILE_ATTRIBUTE_NORMAL,

FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE);

 

missed[x] = goodfile ? 0 : 1;

// if failed, missed[x] become 1

// if good, missed become 0

if(missed[x])

nb_lost_file++;

// if the file was missed, increase the number of 

// missing file.

// increase to the next file

x++;

}

//return the number of missing file, if any.

return nb_lost_file;

}

 

bool CFtpGet::CloseConnection()

{

// close the connection to server, you can reconnect latter

if(pFtpConnection == NULL)

return 0;

try{

pFtpConnection->Close();

}catch(...)

{

return 0;

}

if(pFtpConnection != NULL)

delete pFtpConnection;

 

return 1;

}

 

 

int CAddFile::DoModal() 

{

// TODO: Add your specialized code here and/or call the base class

return CDialog::DoModal();

}

 

void CAddFile::OnCancel() 

{

// TODO: Add extra cleanup here

strNewFile = "";

CDialog::OnCancel();

}

 

void CAddFile::OnOK() 

{

// TODO: Add extra validation here

m_new_file.GetWindowText(strNewFile);

CDialog::OnOK();

}

 

void CAddFile::OnBnClickedOk()

{

// TODO: 在此添加控件通知处理程序代码

OnOK();

}

 

m_folder.SetWindowText("c://download//");

 

void CHttpDlg::OnNewVer() //Get These file button

{

CString folder;

CString user;

CString pass;

CString server;

// CString program_name;

CString tempRemote;

CString tempLocal;

// error

CString Error;

 

// get folder

m_folder.GetWindowText(folder);

// Get username, password, server

m_user.GetWindowText(user);

m_pass.GetWindowText(pass);

m_server.GetWindowText(server);

 

// get every file name in the box

// make 2 CStringArray, one for remote, the other for local

CStringArray remote;

CStringArray local;

 

for(int x=0;x<m_file.GetCount();x++)

{

m_file.GetText(x,tempRemote);

remote.Add(tempRemote);

tempLocal = folder + tempRemote;

local.Add(tempLocal);

}

 

// open CFtpGet class

CFtpGet ftpget;

// SetRight

ftpget.SetAccessRight(user,pass);

// open server

bool conectOK;

conectOK = ftpget.OpenConnection(server);

// transfer multiple file

if(conectOK)

{

ftpget.GetMultipleFile(&remote,&local,m_file.GetCount());

}

else

memset(ftpget.missed,0,sizeof(bool[100]));

// verify which file, if any, have not been transfered

for(int test=0;test<m_file.GetCount();test++)

{

if(ftpget.missed[test])

{

m_file.GetText(test,Error);

Error = "The file " + Error;

Error += " is missing!";

AfxMessageBox(Error);

}

}

// close connection

ftpget.CloseConnection();

// quit this function

}

 

void CHttpDlg::OnAdd() // Add button

{

// TODO: Add your control notification handler code here

CAddFile add;

int ret = add.DoModal();

int lng = 0;

CString newfile;

 

if(ret == IDOK)

{

// get m_new_file lenght

lng = add.strNewFile.GetLength();

// if OK put in list

if(lng == 0 )// no input

return;

 

m_file.AddString(add.strNewFile);

}

}

 

void CHttpDlg::OnDel() // delete button

{

// TODO: Add your control notification handler code here

int selection=0;

 

selection = m_file.GetCurSel();

// now i get the good one

if(selection <0)

{

AfxMessageBox("You have to select a value in the file list");

return;

}

 

m_file.DeleteString(selection);

// no more in the dialog

}

 

void CHttpDlg::OnAnon() // anonymous check button

{

// TODO: Add your control notification handler code here

int check = m_anon.GetCheck();

 

if(check == 1)

{

// store some info in mem

m_user.GetWindowText(cOldUser,99);

m_pass.GetWindowText(cOldPass,99);

 

// set new value

m_user.SetWindowText("anonymous");

m_pass.SetWindowText("[email protected]");

m_pass_email.SetWindowText("Your email");

 

// you can't edit anonymous

m_user.SetReadOnly(TRUE);

}else

{

// set the old value ( if any )

m_user.SetWindowText(cOldUser);

m_pass.SetWindowText(cOldPass);

m_pass_email.SetWindowText("Password");

 

// you have to edit the user name.

m_user.SetReadOnly(FALSE);

}

}

 

 

74.写图像到剪切板 setClipboardImage

CBitmap   *pOldBitmap,NewBitmap;   

  CDC*   pt;   

  pt=CDC::FromHandle(::GetDC(NULL));   

          NewBitmap.CreateCompatibleBitmap(pt,m_RectCopyCut.Width(),m_RectCopyCut.Height());   

  CDC   dc;   

  dc.CreateCompatibleDC(NULL);   

          pOldBitmap=dc.SelectObject(&NewBitmap);   

  dc.FillRect(m_RectCopyCut,   CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));     dc.BitBlt(0,0,m_RectCopyCut.Width(),m_RectCopyCut.Height(),   

  &m_dcMemory,m_RectCopyCut.left+m_nHPos,m_RectCopyCut.top   +m_nVPos,SRCCOPY);     HANDLE   handle=DDBToDIB(NewBitmap,BI_RGB,NULL);     if(!OpenClipboard())   

  return;   

  EmptyClipboard();   

  SetClipboardData(CF_DIB,handle);   

  CloseClipboard();   

  ReleaseDC(pt);   

  dc.SelectObject(pOldBitmap);

 

75.从剪贴板复制图像到窗体

 

76.删除文件夹下的所有文件且不删除文件夹下的文件夹

///////////////////////////////////////////////////// 

// char dir[] = "d://test//"; 

// DeleteAnyFiles(dir); 

///////////////////////////////////////////////////// 

void DeleteAnyFiles(const char *dir) 

 

WIN32_FIND_DATA finder; 

HANDLE hFileFind; 

char search[MAX_PATH]; 

strcpy(search, dir); 

strcat(search, "*.*"); 

 

hFileFind = FindFirstFile(search, &finder); 

 

if (hFileFind != INVALID_HANDLE_VALUE) 

do 

char path[MAX_PATH]; 

strcpy(path, dir); 

strcat(path, finder.cFileName); 

 

if (!(finder.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 

DeleteFile(path); 

 

} while (FindNextFile(hFileFind, &finder) != 0); 

 

FindClose(hFileFind); 

 

int nRetCode = 0; 

 

// initialize MFC and print and error on failure 

if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) 

// TODO: change error code to suit your needs 

cerr << _T("Fatal Error: MFC initialization failed") << endl; 

nRetCode = 1; 

else 

{

CString strHello; 

strHello.LoadString(IDS_HELLO); 

cout << (LPCTSTR)strHello << endl; 

 

/* 测试目录为d://test//,可以随意改变,但目录分割符必须是// */ 

char dir[] = "d://test//"; 

DeleteAnyFiles(dir); 

return nRetCode;

 

77.XML遍历结点属性值

 

78.拷贝文件名复制文件

#include "stdafx.h"

#include "fdg.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

 

CWinApp theApp;

 

using namespace std;

 

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

int nRetCode = 0;

// initialize MFC and print and error on failure

if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))

{

// TODO: change error code to suit your needs

cerr << _T("Fatal Error: MFC initialization failed") << endl;

nRetCode = 1;

}

else

{

//判断剪贴板的数据格式是否可以处理

if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) 

{

return -1; 

}

//打开剪贴板

if (!OpenClipboard(NULL)) 

{

return -1; 

}

//获取UNICODE的数据

CString str;

CString path;

HGLOBAL hMem = GetClipboardData(CF_TEXT); //CF_UNICODETEXT

if (hMem != NULL) 

//获取UNICODE的字符串

LPTSTR lpStr = (LPTSTR)GlobalLock(hMem); 

if (lpStr != NULL) 

//显示输出

OutputDebugString(lpStr);

//释放锁内存

GlobalUnlock(hMem); 

str=lpStr;

path=lpStr;

}

//关闭剪贴板。

CloseClipboard(); 

CString pathname="C://"+path.Mid(path.ReverseFind('//')+1);

CopyFile(str,pathname,true);

}

return nRetCode;

}

 

79.开源程序库Xercesc-C++代码工程中内联

#include "stdafx.h" 

#include "InlineXercesc.h"

#include <list>

#include <queue>

#include <string>

#include <boost/regex.hpp>

#include <shlwapi.h>

#pragma comment( lib, "shlwapi.lib")

#ifdef _DEBUG 

#define new DEBUG_NEW 

#undef THIS_FILE 

static char THIS_FILE[] = __FILE__; 

#endif 

CWinApp theApp; 

using namespace std;

typedef list<CString, allocator<string> > tagSTRING;

typedef queue<CString, tagSTRING> STRING;

STRING fal,fal2;

CStringArray all;

CString filter = ".cpp";

void doSearch(CString path)

{

if(PathFileExists(path))

{

CFileFind ff;

CString szDir = path;

if(szDir.Right(1) != "//")

szDir += "//";

szDir += "*.*";

BOOL res = ff.FindFile(szDir);

while(res)

{

res = ff.FindNextFile();

if(ff.IsDirectory() && !ff.IsDots())//目录是文件夹

{

//如果是一个子目录,用递归继续往深一层找

doSearch(ff.GetFilePath());//递归调用

}

else if(!ff.IsDots()) 

{

//显示当前访问的文件

CString strPath = ff.GetFileName();

if (strPath.Find(filter) > 0) {

for (int ifile=0;ifile<all.GetSize();ifile++) {

CString file=all.GetAt(ifile);

if (file.Mid(file.ReverseFind('//') + 1)==strPath) {

fal2.push(ff.GetFilePath());

}

}

}

}

}

ff.Close();//关闭

}

}

 

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) 

int nRetCode = 0; 

if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) 

cerr << _T("Fatal Error: MFC initialization failed") << endl; 

nRetCode = 1; 

else 

CString lib="xercesc";

CString regex;

regex.Format("include.*?%s.*?>",lib);

boost::regex reg(regex.GetBuffer(0));

boost::smatch m;

CString SourceLib="C://xercesc";

TCHAR szDir[MAX_PATH];

CString szDirPath;

GetCurrentDirectory(MAX_PATH,szDir);

szDirPath.Format("%s//*.*",szDir);

CString CurDir(szDir);

CFileFind finder;

BOOL bWorking = finder.FindFile(szDirPath); 

while (bWorking) 

bWorking = finder.FindNextFile();

if(finder.IsDirectory() && !finder.IsDots()){

CString enumDir = CurDir + "//" + finder.GetFileName() + "//";

//枚举一个文件夹中的所有文件夹

CFileFind finder2; 

CString szDirPath2;

szDirPath2.Format("%s//*.*",finder.GetFileName());

BOOL bWorking2 = finder2.FindFile(szDirPath2); 

while (bWorking) { 

bWorking2 = finder2.FindNextFile();

if(!finder2.IsDirectory() && !finder2.IsDots())

{

CStdioFile   f_sfile;

CString  lcs_FileName=finder2.GetFilePath();

if(f_sfile.Open(lcs_FileName,CFile::modeRead))   

{   

//逐行读取

CString sb;

CString  lcs_FileContent;

int    li_line = 0;

long ll_LineCount = 0;

while(f_sfile.ReadString(lcs_FileContent))

{

li_line++;

//读取第li_line行数据: lcs_FileContent

string s(lcs_FileContent.GetBuffer(0));

string::const_iterator it=s.begin();

string::const_iterator end=s.end();

if(boost::regex_serach(it,end,m,reg) && m[1].matched)

{

//it=m[0].second;

int pos=s.find_last_of("/")+1;

s=s.substr(pos,s.find_first_of(">"));

fal.push(CString(s.c_str()));

sb+="#include /"";

sb+=s.c_str();

sb+="/"";

}

else

sb+=lcs_FileContent;

sb+="/r/n";

}

f_sfile.Close();

CFile mFile(_T(lcs_FileName), CFile::modeWrite);

mFile.Write(sb.GetBuffer(0),sizeof(sb.GetBuffer(0)));

mFile.Flush();

mFile.Close(); 

f_sfile.Close(); 

}

}

finder2.Close();

while(fal.size()>0)

{

CString file(fal.front());

fal.pop();

CString targetPath= enumDir

+ file.Mid(file.ReverseFind('//') + 1);

if(!PathFileExists(targetPath))

{

CStdioFile   f_sfile;

CString  lcs_FileName=finder2.GetFilePath();

if(f_sfile.Open(lcs_FileName,CFile::modeRead))   

CFile mFile(_T(targetPath), CFile::modeCreate|CFile::modeWrite);

CString  lcs_FileContent;

int    li_line = 0;

long ll_LineCount = 0;

while(f_sfile.ReadString(lcs_FileContent))

{

li_line++;

//读取第li_line行数据: lcs_FileContent

string s(lcs_FileContent.GetBuffer(0));

string::const_iterator it=s.begin();

string::const_iterator end=s.end();

if(boost::regex_serach(it,end,m,reg) && m[1].matched)

{

//it=m[0].second;

int pos=s.find_last_of("/")+1;

s=s.substr(pos,s.find_first_of(">"));

fal.push(CString(s.c_str()));

mFile.Write("#include /"",sizeof("#include /""));

mFile.Write(s.c_str(),sizeof(s.c_str()));

mFile.Write("/"",sizeof("/""));

}

else

mFile.Write(lcs_FileContent,sizeof(lcs_FileContent));

mFile.Write("/r/n",sizeof("/r/n"));

}

mFile.Flush();

mFile.Close();

}

}

}

CFileFind finder3; 

bWorking2 = finder3.FindFile(szDirPath2); 

while (bWorking) { 

bWorking2 = finder3.FindNextFile();

if(!finder3.IsDirectory() && !finder3.IsDots()){

CString path=finder3.GetFilePath();

if(path.Mid(path.ReverseFind('.'))==".hpp")

{

path.Replace(".hpp",".cpp");

all.Add(path);

}

}

}

finder3.Close();

int count = 1;

while (count > 0) {

doSearch(SourceLib);

all.RemoveAll();

while(fal2.size()>0)

{

CString file1 = fal2.front();

CString targetPath = enumDir+ file1.Mid(file1.ReverseFind('//') + 1);

if(!PathFileExists(targetPath))

{

CString  lcs_FileName=finder2.GetFilePath()+"//ReadMe.txt";

CStdioFile   f_sfile;

if(f_sfile.Open(lcs_FileName,CFile::modeRead))   

{   

CFile mFile(_T(targetPath), CFile::modeCreate|CFile::modeWrite);

//逐行读取

CString  lcs_FileContent;

int    li_line = 0;

long ll_LineCount = 0;

while(f_sfile.ReadString(lcs_FileContent))

{

li_line++;

//读取第li_line行数据: lcs_FileContent

string s(lcs_FileContent.GetBuffer(0));

string::const_iterator it=s.begin();

string::const_iterator end=s.end();

if(boost::regex_serach(it,end,m,reg) && m[1].matched)

{

//it=m[0].second;

int pos=s.find_last_of("/")+1;

s=s.substr(pos,s.find_first_of(">"));

fal2.push(CString(s.c_str()));

all(fal2.back().Replace(".hpp",".cpp"));

mFile.Write("#include /"",sizeof("#include /""));

mFile.Write(s.c_str(),sizeof(s.c_str()));

mFile.Write("/"",sizeof("/""));

}

else

mFile.Write(lcs_FileContent,sizeof(lcs_FileContent));

mFile.Write("/r/n",sizeof("/r/n"));

mFile.Flush();

mFile.Close();

}

}

}

}

}

finder.Close();

}

return nRetCode; 

}

 

80.提取包含头文件列表

#include <boost/regex.hpp>

CString regex;

regex.Format("include.*?%s.*?>",lib);

boost::regex reg(regex.GetBuffer(0));

boost::smatch m;

TCHAR szDir[MAX_PATH];

GetCurrentDirectory(MAX_PATH,szDir);

CString CurDir;

CurDir.Format("%s//*.*",szDir);

CFileFind finder;

BOOL bWorking = finder.FindFile(CurDir); 

while(bWorking)

{

bWorking = finder.FindNextFile();

if (finder.IsDirectory() && !finder.IsDots())

{

CString  lcs_FileName=finder.GetFilePath()+"//StdAfx.cpp";

CStdioFile   f_sfile;

//逐行读取

CString  lcs_FileContent;

int    li_line = 0;

long ll_LineCount = 0;

while(f_sfile.ReadString(lcs_FileContent))

{

li_line++;

//读取第li_line行数据: string s(lcs_FileContent.GetBuffer(0));

string::const_iterator it=s.begin();

string::const_iterator end=s.end();

if(boost::regex_serach(it,end,m,reg) && m[1].matched)

{

//it=m[0].second;

int pos=s.find_last_of("/")+1;

s=s.substr(pos,s.find_first_of(">"));

fal2.push(CString(s.c_str()));

}

}

CString targetPath = finder.GetFilePath()+"//ReadMe.txt";

CFile mFile(_T(targetPath),CFile::modeCreate|CFile::modeWrite);

mFile.Write("#include /"",sizeof("#include /""));

mFile.Write(s.c_str(),sizeof(s.c_str()));

mFile.Write("/"",sizeof("/""));

mFile.Write("/r/n",sizeof("/r/n"));

mFile.Flush();

mFile.Close();

}

 

81.剪贴扳转换成打印字符

#include "stdafx.h" 

#include "%%0.h" 

#ifdef _DEBUG 

#define new DEBUG_NEW 

#undef THIS_FILE 

static char THIS_FILE[] = __FILE__; 

#endif 

CWinApp theApp; 

using namespace std; 

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) 

int nRetCode = 0; 

if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) 

cerr << _T("Fatal Error: MFC initialization failed") << endl; 

nRetCode = 1; 

else 

//判断剪贴板的数据格式是否可以处理

if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) 

{

return 0; 

}

//打开剪贴板

if (!OpenClipboard(NULL)) 

{

return 0; 

}

//获取UNICODE的数据

CString s;

HGLOBAL hMem = GetClipboardData(CF_TEXT); 

if (hMem != NULL) 

//获取UNICODE的字符串

LPTSTR lpStr = (LPTSTR)GlobalLock(hMem); 

if (lpStr != NULL) 

//显示输出

OutputDebugString(lpStr);

//释放锁内存

GlobalUnlock(hMem); 

s=lpStr;

CString sub;

CString sb;

int pos;

char seperator = '/n';

for (pos = 0; AfxExtractSubString(sub, s, pos, seperator); ++pos)

{

if(sub.Trim()!="")

{

sub.Replace("^", "^^");

sub.Replace("&", "^&");

sub.Replace(":", "^:");

sub.Replace(">", "^>");

sub.Replace("<", "^<");

sub.Replace("|", "^|");

sub.Replace("/"", "^/"");

sub.Replace("//", "////");

sub.Replace("/"", "///"");

sb+=("w.WriteLine(/"ECHO " +sub + "/");/r/n");

}

char *pMem;

hMem = GlobalAlloc( GHND | GMEM_DDESHARE, strlen(sb)+1);

if(hMem)

{

pMem = (char*)GlobalLock(hMem);

strcpy(pMem,sb);

GlobalUnlock(hMem);

EmptyClipboard();

SetClipboardData(CF_TEXT,hMem);

}

CloseClipboard();

}

return nRetCode; 

 

82.把JButton或JTree组件写到一个流中

 

83.注册全局热键

/*

BOOL RegisterHotKey( 

HWND hWnd . //指定接收WM_HOTKEY消息的窗体句柄 

int id. //热键标识.同一调用线程内的不同热键标识不能相同.应用程序中的标识值在0x0000和0xbfff之间.DLL中的在0xc000和0xffff之间 

UINT fsModifiers.//下列值的组合:MOD_ALT.MOD_CONTROL.MOD_SHIFT.MOD_WIN.MOD_KEYUP 

UINT vk //按键的虚拟码 

), 

*/

//在初始化的时候注册: 

RegisterHotKey(m_hWnd.1688.MOD_SHIFT|MOD_CONTROL

 

84.菜单勾选/取消完成后关闭计算机

//使此进程获取:关机权限

HANDLE hToken;

LUID luid;

TOKEN_PRIVILEGES tp;

//获取此进程的令牌    

::OpenProcessToken(::GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken);    

 

//查询权限值:获取权限的唯一标识值    

::LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&luid);    

 

tp.PrivilegeCount = 1;    

 

tp.Privileges[0].Luid = luid;    

tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;    

 

//调整令牌权限    

::AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL);    

::ExitWindowsEx(EWX_SHUTDOWN,0);

 

85.菜单勾选/取消完成后重新启动计算机

//使此进程获取:关机权限    

HANDLE hToken;

LUID luid;

TOKEN_PRIVILEGES tp;

//获取此进程的令牌    

::OpenProcessToken(::GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken);    

 

//查询权限值:获取权限的唯一标识值    

::LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&luid);    

 

tp.PrivilegeCount = 1;    

 

tp.Privileges[0].Luid = luid;    

tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;    

 

//调整令牌权限    

::AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL);    

::ExitWindowsEx(EWX_REBOOT,0);

 

86.菜单勾选/取消完成后注销计算机

//使此进程获取:关机权限

HANDLE hToken;

LUID luid;

TOKEN_PRIVILEGES tp;

//获取此进程的令牌    

::OpenProcessToken(::GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken);    

 

//查询权限值:获取权限的唯一标识值    

::LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&luid);    

 

tp.PrivilegeCount = 1;    

 

tp.Privileges[0].Luid = luid;    

tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;    

 

//调整令牌权限    

::AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL);    

::ExitWindowsEx(EWX_LOGOFF,0);

 

87.菜单勾选/取消开机自启动程序

::OnSetMusic() 

// TODO: Add your command handler code here 

 

/*CMenu  *menu1,*menu2;  

    menu2=menu1.GetSubMenu(1);  

    menu2.GetMenuItemID(3);  */ 

if(GetCheck()==FALSE) 

SetCheck(); 

sndPlaySound("D://oscillograph//res//天路(钢琴伴奏)裁.wav",SND_LOOP); 

else 

sndPlaySound("D://oscillograph//res//天路(钢琴伴奏)裁.wav",NULL); 

}

}

/////////////////////////////////////////////////////////////////////

 

TCHAR m_fileName[100];

GetModuleFileName(NULL,m_fileName,100);

 HKEY hKey;

 CString str = _T("Software//Microsoft//Windows//CurrentVersion//Run");

 if (ERROR_SUCCESS != RegCreateKey(HKEY_LOCAL_MACHINE, str, &hKey))

 {

  AfxMessageBox("打开注册表项失败");

  RegCloseKey(hKey);

  return;

 }

 int length = 0;

 while(m_fileName[length]!=_T('/0'))

  length++;

 if (ERROR_SUCCESS != RegSetValueEx(hKey, _T(%%1), 0, REG_SZ, (const BYTE *)m_fileName, sizeof(TCHAR)*length))

 {

  AfxMessageBox("写注册表失败");

 }

 RegCloseKey(hKey);

 

88.菜单勾选/取消自动登录系统

 

89.模拟键盘输入字符串

CString   str=%%1;

  DWORD   sc,shift;   

  unsigned   char   vkey;   

  char   a;   

    for   (int   i=0;i<str.GetLength();i++)   

  {   

  a=str.GetAt(i);   

  sc=OemKeyScan(a);   

  shift=sc>>16;   

    vkey=MapVirtualKey(sc&0xffff,1);   

    if   (shift)   

  keybd_event(VK_SHIFT,0,0,0);   

    keybd_event(vkey,0,0,0);   

  keybd_event(vkey,0,KEYEVENTF_KEYUP,0);   

  if   (shift)   

  keybd_event(VK_SHIFT,0,KEYEVENTF_KEYUP,0);   

  }

 

90.提取PDF文件中的文本

try   

  {   

  int   iFont;   

  PDFlib   pPDF;   

  CFileDialog   m_FileDlg(FALSE,"pdf","",OFN_OVERWRITEPROMPT,"Adobe   Acrobat   PDF   文件(*.pdf)|*.pdf|所有文件(*.*)|*.*||",this);   

  char   pFileName[255];   

 

  CEdit*   pPDFText=(CEdit*)GetDlgItem(IDC_EDITPDF);   

  CString   strPDFText;   

  pPDFText->GetWindowText(strPDFText);   

  char   pPDFInfo[1024];   

  sprintf(pPDFInfo,"%s",strPDFText);   

 

  char   pAttachFileName[255];   

  sprintf(pAttachFileName,"%s",m_AttachFileName);   

  if(m_FileDlg.DoModal()==IDOK)   

  {   

  m_PDFFileName=m_FileDlg.GetFileName();   

  sprintf(pFileName,m_PDFFileName);   

  if(pPDF.open_file(pFileName)==-1)   

  {   

  //   

  }   

  pPDF.set_parameter("hypertextencoding","host");   

  pPDF.set_info("Creator","DigitalSky");   

  pPDF.set_info("Author","DigitalTitan");   

  pPDF.set_info("Title","Title");   

  pPDF.begin_page((float)a4_width,(float)a4_height);   

  iFont=pPDF.load_font("Helvetica-Bold","host","");   

  pPDF.setfont(iFont,12);   

  pPDF.set_text_pos(50,a4_height-50);   

  pPDF.setcolor("fill","rgb",0,0,1,0);   

  pPDF.show("Version   1.0   (C)   CopyRight   By   Digitaltitan");   

  iFont=pPDF.findfont("STSong-Light","GB-EUC-H",0);   

  pPDF.setcolor("fill","rgb",0,0,0,0);   

  pPDF.setfont(iFont,24);   

  pPDF.continue_text("转换文档生成为");   

 

  pPDF.setcolor("stroke","rgb",0.24f,0.51f,0.047f,0);   

  pPDF.moveto(50,a4_height-80);   

  pPDF.lineto(a4_width-50,a4_height-80);   

  pPDF.moveto(50,a4_height-78);   

  pPDF.lineto(a4_width-50,a4_height-78);   

  pPDF.stroke();   

  pPDF.attach_file(a4_width-50,0,0,a4_height-90,pAttachFileName,"DigitalSky","DigitalTitan","doc","paperclip");   

 

  pPDF.set_text_pos(50,a4_height-100);   

  iFont=pPDF.findfont("STSong-Light","GB-EUC-H",0);   

  pPDF.setcolor("fill","rgb",0,0,0,0);   

  pPDF.setfont(iFont,12);   

  pPDF.continue_text(pPDFInfo);   

 

  //Word文件如何导入?   

 

  pPDF.end_page();   

  pPDF.close();   

  }   

  }   

          catch(PDFlib::Exception   &ex)   

  {   

  //   

          }   

下载免费开发包http://partners.adobe.com/asn/acrobat/sdk/fdftk/FDFToolkitForWindows.zip

PDF   SDK有一个例子--AddImage,该例子生产一个dll,放在Acrobat的安装目录下,然后启动Acrobat,就看到多了一个菜单项“AddImage”,就可以调用AddImage了。我的问题是:如何不生成dll给Acrobat调用,而是直接运行AddImage的功能?

 

91.操作内存映射文件

91.1发送内存映射数据

HANDLE hFileMapping;

LPSTR pData;

hFileMapping=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,0x100,%%1); //"MyShare"

if(hFileMapping==NULL)

{

//文件映射至内存失败!

return -1;

}

pData=(LPSTR)MapViewOfFile(hFileMapping,FILE_MAP_ALL_ACCESS,0,0,0);

if(pData==NULL)

{

//文件试镜像到进程地址空间失败!

return -1;

}

sprintf(pData,%%2);

UnmapViewOfFile(pData);

 

91.2接收内存映射数据

HANDLE hFileMapping;

LPSTR pData;

hFileMapping=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,0x100,%%1); //"MyShare"

if(hFileMapping==NULL)

{

//文件映射至内存失败!

return -1;

}

pData=(LPSTR)MapViewOfFile(hFileMapping,FILE_MAP_ALL_ACCESS,0,0,0);

if(pData==NULL)

{

//文件试镜像到进程地址空间失败!

return -1;

}

CString %%2;

%%2.Format("%s",pData);

UnmapViewOfFile(pData);

 

92.重定向windows控制台程序的输出信息

STARTUPINFO si;

PROCESS_INFOMATION pi;

SECURITY_ATTRIBUTES sa;

HANDLE hRead_OutPipe,hWrite_OutPipe,hRead_InPipe,hWrite_InPipe;

sa.mLength=sizeof(SECURITY_ATTRIBUTES);

sa.lpSecurityDescriptor=NULL;

sa.bInheritHandle=TRUE;

ZeroMemory(&pi,sizeof(pi));

ZeroMemory(&si,sizeof(si));

GetStartipInfo(&si);

si.cb=sizeof(si);

si.dwFlags=STARTF_USESTDHANDLES|STARTF_USERSHOWWINDOW;

si.hStdOutput=hWrite_OutPipe;

si.hStdError=hWrite_OutPipe;

si.hStdInput=hWrite_InPipe;

si.wShowWindow=SW_HIDE;

if(!CreateProcess(NULL,%%1,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi)) {

//创建进程失败

return -1;

}

if(!CreateProcess(&hRead_OutPipe,&hWrite_OutPipe,&sa,0)) {

//创建进程失败

return -1;

}

if(!CreateProcess(&hRead_InPipe,&hWrite_InPipe,&sa,0)) {

//创建进程失败

return -1;

}

si.hStdOutput=hWrite_OutPipe;

si.hStdError=hWrite_OutPipe;

si.hStdInput=hWrite_InPipe;

char buf[4096];

DWORD readlen=0;

CString %%2;

%%2+="/r/n";

DWORD dwWritten=0;

WriteFile(hWrite_InPipe,%%2,%%2.GetLength(),&dwWritten,0);

CString %%3;

BOOL read_ret=TRUE;

while(read_ret=TRUE)

{

memset(buf,'/0',sizeof(buf));

read_ret=ReadFile(hRead_OutPipe,buf,sizeof(buf),&readlen,NULL);

CString buffer(buf);

%%3+=buffer;

}

 

93.接受邮件

用Visual C++编写电子邮件程序

94.发送邮件

一、概述 

---- 本文主要讲述如何使用Visual C++用MAPI编写E-mail程序。MAPI是包含在

Windows之中的,因此不需要安装其他额外的部件。MAPI有以下三种形式: 

 

SMAPI,Simple MAPI,简单的MAPI 

 

CMC,Common Messaging Calls,一般通讯调用 

 

完整的MAPI 

---- SMAPI和CMC都包含在完整的MAPI中,当用户想执行一些高级操作,比如

编写自己的E-mail服务器的时候,必须使用完整的MAPI。本文主要阐述如何编

写能够收发电子邮件的程序,因此使用SMAPI就足够了。 

 

二、编写电子邮件程序 

3-1 初始化MAPI 

 

---- 要使用MAPI,必须首先对它进行初始化。初始化包括以下三个步骤: 

 

装载MAPI32.DLL动态链接库 

 

找到想要调用的MAPI函数地址 

 

登录到电子邮件对象 

3-1-1 装载MAPI32.DLL 

 

---- 要装载MAPI,用户必须程序运行时动态的装载一个动态链接库。LoadLibrary

函数提供了此功能,它定位一个动态链接库,并返回HINSTANCE局柄(需要保存该句柄)。 

 

LoadLibrary的语法如下:

LoadLibrary ( lpLibFileName );

其中lpLibFileName为LPCTSTR结构变量,

是所要调用的库的路径和名称。

 

程序示例:

// 调用MAPI32.DLL并计算函数地址

HINSTANCE hInstMail;

hInstMail = ::LoadLibrary ( “MAPI32.DLL” );

if ( hInstMail == NULL )

{

// 错误处理

// 受篇幅限制,下面的错误处理部分省略

}

3-1-2 确定函数地址 

 

---- 由于MAPI32.DLL是被动态装载的,因此不知道所要调用的函数地址,

也就不能一开始就调用它们,而要通过函数名获得函数的地址,并在动态链

接库中查找每一个函数并核实。因此首先必须为这些函数声明指针 

 

程序示例:

// 为MAPI32.DLL中的函数声明函数指针

ULONG (PASCAL *lpfnMAPISendMail) (LHANDLE lhSession, 

ULONG ulUIParam, lpMapiMessage lpMessage, 

FLAGS flFlags, ULONG ulReserved);

ULONG (PASCAL *lpfnMAPIResolveName) (LHANDLE lhSession, 

ULONG ulUIParam, LPTSTR lpszName, 

FLAGS ulFlags, ULONG ulReserved,

lpMapiRecipDesc FAR *lppRecip);

ULONG (FAR PASCAL *lpfnMAPILogon)(ULONG ulUIParam, 

LPSTR lpszProfileName, LPSTR lpszPassword, 

FLAGS flFlags, ULONG ulReserved, 

LPLHANDLE lplhSession);

ULONG (FAR PASCAL *lpfnMAPILogoff)(LHANDLE lhSession, 

ULONG ulUIParam, FLAGS flFlags,

ULONG ulReserved);

ULONG (FAR PASCAL *lpfnMAPIFreeBuffer)(LPVOID lpBuffer);

ULONG (FAR PASCAL *lpfnMAPIAddress)(LHANDLE lhSession,

ULONG ulUIParam, LPSTR lpszCaption,

ULONG nEditFields, LPSTR lpszLabels,

ULONG nRecips, lpMapiRecipDesc lpRecips,

FLAGS flFlags, ULONG ulReserved, 

LPULONG lpnNewRecips, 

lpMapiRecipDesc FAR *lppNewRecips);

ULONG (FAR PASCAL *lpfnMAPIFindNext)(LHANDLE lhSession,

ULONG ulUIParam, LPSTR lpszMessageType, 

LPSTR lpszSeedMessageID, FLAGS flFlags,

ULONG ulReserved, LPSTR lpszMessageID);

ULONG (FAR PASCAL *lpfnMAPIReadMail)(LHANDLE lhSession, 

ULONG ulUIParam, LPSTR lpszMessageID,

FLAGS flFlags, ULONG ulReserved, 

lpMapiMessage FAR *lppMessage);

---- 为了决定每一个函数的地址,必须为每一个函数调用GetProcAddress。 

 

GetProcAddress的语法为:

GetProcAddress (hModule, lpProcName);

其中,hModule为HMODULE结构,是所调用DLL模块的句柄;

lpProcName为LPCSTR结构,是函数名称。

 

程序示例:

// 找到MAPI32.DLL函数的地址,并将它们保存在函数指针变量里

(FARPROC&) lpfnMAPISendMail = GetProcAddress(hInstMail,

“MAPISendMail”);

(FARPROC&) lpfnMAPIResolveName = GetProcAddress(

hInstMail, “MAPIResolveName”);

(FARPROC&) lpfnMAPILogon = GetProcAddress(hInstMail,

“MAPILogon”);

(FARPROC&) lpfnMAPILogoff = GetProcAddress(hInstMail,

“MAPILogoff”);

(FARPROC&) lpfnMAPIFreeBuffer = GetProcAddress(

hInstMail, “MAPIFreeBuffer”);

(FARPROC&) lpfnMAPIAddress = GetProcAddress(hInstMail,

“MAPIAddress”);

(FARPROC&) lpfnMAPIFindNext = GetProcAddress(hInstMail,

“MAPIFindNext”);

(FARPROC&) lpfnMAPIReadMail = GetProcAddress(hInstMail,

“MAPIReadMail”);

 

3-1-3 登录到电子邮件对象 

 

---- 用户必须在电子邮件系统中登录,才能实现MAPI的各种功能。MAPI提供了登录的三种选择: 

 

登录到一个已经存在的对象。 

 

登录到一个新对象,用编程的方法确定解释新信息。 

 

使用对话框提示用户登录。 

---- 我们通常选择登录到一个已经存在的电子邮件对象,因为网络合作用户通

常会保持自己的电子邮件程序处于激活状态。登录通常使用MAPI提供的函数

lpfnMAPILogon。 

 

lpfnMAPILogon的语法为:

lpfnMAPILogon (lpszProfileName, lpszPassword, flFlags, 

ulReserved, lplhSession );

---- 其中,lpszProfileName指向一个256字符以内的登录名称,lpszPassword

指向密码,它们均为LPTSTR结构。flFlags为FLAGS结构,其值详见表1。ulReserved

必须为0。lplhSession为输出SMAPI的句柄。 

 

表1:lpfnMAPILogon函数中flFlags的值

值 意义

MAPI_FORCE_DOWNLOAD 

在函数调用返回之前下载用户的所有邮件。

如果MAPI_FORCE_DOWNLOAD没有被设置,

那么信件能够在函数调用返回后在后台被下载。

MAPI_NEW_SESSION 建立一个新会话,

而不是获得环境的共享会话。如果MAPI_NEW_SESSION没有被设置,

MAPILogon使用现有的共享会话。

MAPI_LOGON_UI 显示一个登录对话框来提示用户输入登录信息。

例如Outlook检查用户电子邮件时便是如此。

MAPI_PASSWORD_UI MAPILogon只允许用户输入电子邮件的密码,

而不许改动账号。

 

程序示例:

LHANDLE lhSession;

ULONG lResult = lpfnMAPILogon(0, NULL, NULL, 0, 0, 

&lhSession);

if (lResult != SUCCESS_SUCCESS)

//SUCCESS_SUCCESS在MAPI.H中被定义

{

// 错误处理

}

 

3-2 阅读电子邮件 

 

---- MAPIFindNext和MAPIReadMail使用与阅读E-mail的两个基本函数。

MAPIFindNext用于定位第一封或下一封电子邮件并返回标识号,MAPIReadMail返回

以该标识号为基础的电子邮件的内容。另外,一个常用的函数是MAPIFreeBuffer,

用于释放内存。 

 

3-2-1 定位到第一封信 

 

---- 要找到第一封信,需要使用MAPIFindNext函数,其函数声明如下: 

 

ULONG FAR PASCAL MAPIFindNext(LHANDLE lhSession, 

ULONG ulUIParam, LPTSTR lpszMessageType, 

LPTSTR lpszSeedMessageID, FLAGS flFlags, 

ULONG ulReserved, LPTSTR lpszMessageID )

---- 其中,lhSession为提交SMAPI的会话句柄 ;ulUIParam为父窗体的句柄;

lpszMessageType指向一个字符串,用来鉴别邮件类型,并加以查找;

lpszSeedMessageID为指向起始信息ID的指针,其值为0时,

MAPIFindNext获得第一封电子邮件;flFlags的值见表2;ulReserved必须为0;

lpszMessageID为输出值,它是指向信息ID地址的指针。 

 

---- 表2:MAPIFindNext函数中flFlags的值 

 

值 意义

MAPI_GUARANTEE_FIFO 按邮件发送的时间顺序接受电子邮件。

MAPI_LONG_MSGID 返回信件标识符可达512字符。

MAPI_UNREAD_ONLY 只列举没有阅读过的电子邮件。

 

程序示例:

// 找到第一条没有阅读的电子邮件

char pMessageID [513];

ULONG lResult = lpfnMAPIFindNext(lhSession, NULL, NULL,

NULL, MAPI_LONG_MSGID | MAPI_UNREAD_ONLY,

0, pMessageID);

3-2-2 阅读信息

当信件ID被获取后,就可以调用MAPIReadMail

阅读实际的E-mail信息了。MAPIReadMail的函数声明如下:

ULONG FAR PASCAL MAPIReadMail(LHANDLE lhSession, 

ULONG ulUIParam, LPTSTR lpszMessageID, 

FLAGS flFlags, ULONG ulReserved,

lpMapiMessage FAR * lppMessage);

其中,lppMessage为指向MapiMessage的指针;

除flFlags外的其他参数与lpfnFindNext函数的同名参数意义相同,

flFlags参数的值见表3:

 

表3:MAPIReadMail函数中flFlags的值:

值 意义

MAPI_BODY_AS_FILE 将邮件信息写到一个临时文件中,

并且将它作为第一个附件添加到附件列表中。

MAPI_ENVELOPE_ONLY 只读取邮件标题。

MAPI_PEEK 读完邮件之后不把它标记为“已读”。

MAPI_SUPPRESS_ATTACH MAPIReadMail函数不拷贝附件,

但是将邮件文本写入MapiMessage结构中。

 

程序示例:

// 读取电子邮件

long nFlags = MAPI_SUPPRESS_ATTACH;

if (!bMarkAsRead)

nFlags = nFlags | MAPI_PEEK;

lResult = lpfnMAPIReadMail(lhSession, NULL, pMessageID,

nFlags, 0, &pMessage);

if (lResult != SUCCESS_SUCCESS);

return false;

 

如果调用成功,就可以访问MapiMessage结构了(使用pMessage):

pMessage- >ulReserved:0

pMessage- >lpszSubject:邮件标题

pMessage- >lpszNoteText:邮件信息

pMessage- >lpszMessageType:邮件类型

pMessage- >DateReceived:接收时间

pMessage- >lpszConversationID:邮件所属的会话线程ID

pMessage- >flFlags:其值见表4

 

表4:MapiMessage结构中的flFlags

值 意义

MAPI_RECEIPT_REQUESTED 接收通知被申请。

客户端应用程序在发送消息时设置该项。

MAPI_SENT 邮件已被发送。

MAPI_UNREAD 邮件是“未读”状态。

 

pMessage- >lpOriginator:指向MapiRecipDesc结构,包含发件人信息。

pMessage- >nRecipCount:信件者数目。

pMessage- >lpRecips:指向MapiRecipDesc结构数组,包含接收者信息。

pMessage- >nFileCount:附件数量。

pMessage- >lpFiles:指向MapiFileDesc结构数组,

每一个结构包含一个文件附件。

 

3-2-3 释放内存 

 

---- 在访问另一条信件以前应当释放内存,否则会出现内存泄漏。 

 

程序示例:

 

// 释放内存

lpfnMAPIFreeBuffer(pMessage);

3-2-4 定位到下一条信件

定位到下一条信件依然使用MAPIFindNext函数,

该函数声明及参数意义详见3-2-1节。下面示范如何定位到下一条信件。

 

程序示例:

// 定位到下一条没有阅读的信件

ULONG lResult = lpfnMAPIFindNext(lhSession, NULL, NULL, 

pMessageID, MAPI_LONG_MSGID|MAPI_UNREAD_ONLY, 

0, pMessageID);

 

3-3 发送电子邮件 

 

---- 发送电子邮件的一般步骤: 

 

---- 1. 建立MapiMessage结构对象 

 

---- 2. 调用MAPIResolveName使发送者名称合法 

 

---- 3. 添加附件 

 

---- 4. 调用MAPISendMail发送电子邮件 

 

---- 5. 调用MAPIFreeBuffer释放内存 

 

---- 下面详细分别详细阐述。 

 

3-3-1 建立MapiMessage结构对象 

 

---- 对于MapiMessage结构,3-2-2节已经做过介绍,下面一步步介绍如何设置其中的值: 

 

---- 1. 为MapiMessage对象分配内存: 

 

MapiMessage message;

Memset(&message, 0, sizeof(message));

---- 2. 将ulReserved设置为0: 

 

message.ulReserved = 0;

---- 3. 设置信息类型指针lpszMessageType,可以为NULL: 

 

message.lpszMessageType = NULL;

---- 4. 设置信件标题(lpszSubject): 

 

char subject[512];

strcpy(subject, sSubject);

message.lpszSubject = subject;

---- 5. 设置信件内容: 

 

char text[5000];

strcpy(text, sMessage);

message.lpszNoteText = text;

---- 6. 设置flFlags标识,详见3-2-2节中表4: 

 

message.flFlags = MAPI_SENT;

---- 7. 用一个指向MapiRecipDesc结构的指针设置发送者信息(lpOriginator),

或将其设置为NULL: 

 

message.lpOriginator = NULL;

---- 8. 设置接收者数目(nRecipCount),可以是1或更多: 

 

message.nRecipCount = 1;

---- 9. 设置接收者信息(lpRecips),详见3-3-2节 

 

---- 10. 设置附件数量(nFileCount) 

 

---- 11. 设置附件信息,详见3-3-3节 

 

b3-3-2 正确设置接收者信息 

 

---- 设置接收者信息时,应当使用MAPIResolveName函数来为MapiRecipDesc结构

对象分配内存,并返回一个指针,该指针将被保存在MapiMessage结构的lpRecips中。

MAPIResolveName的函数声明如下: 

 

ULONG FAR PASCAL MAPIResolveName(LHANDLE lhSession, 

ULONG ulUIParam, LPTSTR lpszName, 

FLAGS flFlags, ULONG ulReserved, 

lpMapiRecipDesc FAR * lppRecip )

---- 其中lppRecip即为前面提到的返回的指针。除flFlags外其余参数与前几个

函数意义相同。flFlags的值详见表5。 

 

表5:MAPIResolveName中flFlags的值

值 意义

MAPI_AB_NOMODIFY 对话框为只读。如果MAPI_DIALOG被设置,

那么该项将被忽略。

MAPI_DIALOG 显示一个名称解决方案的对话框

MAPI_LOGON_UI 如果需要的话,将会显示仪个对话框让用户登录

MAPI_NEW_SESSION 新建一个会话

 

程序示例:

char recipient[512];

strcpy(recipient, sTo);

lResult = lpfnMAPIResolveName(lhSession, 0, recipient,

0, 0, &message.lpRecips);

 

3-3-3 添加附件 

 

---- 下面的程序示例将演示如何在电子邮件中包含附件。只有一点需要说明:

MapiFileDesc结构中flFlags的值,详见表6。 

 

表6:MapiFileDesc结构中flFlags的值

值 意义

MAPI_OLE 附件是OLE对象。

MAPI_OLE_STATIC 附件是静态OLE对象。

0 附件将被视为数据文件

 

程序示例:

// 设置附件信息

CString sPath, sFileName;

MapiFileDesc FileInfo;

char path[512];

char filename[512];

if (sAttachment == “”)

message.nFileCount = 0;

else

{

int nPos = sAttachment.ReverseFind(‘//’);

if (nPos == -1)

{

sPath = sAttachment;

}

else

{

sPath = sAttachment;

sFilename = sAttachment.Mid(nPos +1);

}

strcpy(path, sPath);

strcpy(filename, sFilename);

 

message.nFileCount = 1;

FileInfo.ulReserved = 0;

 

FileInfo.flFlags = 0;

 

FileInfo.nPosition = sMessage.GetLength() –1;

FileInfo.lpszPathName = path;

FileInfo.lpszFileName = filename;

FileInfo.lpFileType = NULL;

message.lpFiles = & m_FileInfo;

}

 

3-3-4 发送电子邮件 

 

---- 使用MAPISendMail发送电子邮件,其声明如下: 

 

ULONG FAR PASCAL MAPISendMail (LHANDLE lhSession, 

ULONG ulUIParam, lpMapiMessage lpMessage, 

FLAGS flFlags, ULONG ulReserved )

---- 其中,flFlags的允许值为MAPI_DIALOG、MAPI_LOGON_UI和MAPI_NEW_SESSION,

其意义与前几个函数中同名标识意义相同。 

 

程序示例:

 

lResult = lpfnMAPISendMail(0, 0, &m_message, 0, 0);

 

3-3-5 释放内存 

 

程序示例:

lpfnMAPIFreeBuffer(m_message.lpRecips);

四、小结 

---- 本文比较具体的介绍并演示了编写一个电子邮件程序的核心部分,如果读者

要编写电子邮件程序,还需要进行的处理: 

 

---- 1. 加上错误处理代码。受篇幅限制,本文的程序示例中只有两处为错误

处理留空,比较它们的异同。电子邮件程序是非常容易出错的,因此除这两处外要

在主要函数调用完成后都加上错误处理,或使用try throw catch块处理例外。 

 

---- 2. 加上UI处理。 

 

---- 另外,本文所阐述的方法比较简单易行,事实上,有关电子邮件的程序远比

这复杂得多,因此读者若需要编写一个功能强大的电子邮件程序,需要精通MAPI和

SMTP/POP3等协议;如果读者要编写一个电子邮件服务器,那么不妨在精通MAPI和

SMTP/POP3之后,阅读一些有关Exchange Server的资料。 

 

95.报表相关

 一、准备工作

 

  (1)安装Crystal Report软件

Crystal Report 4.6是一个免费的报表工具,可以在VB5或WINDOWS NT 4.0 BackOffice等光盘上找到,Crystal report4.6中包含了报表设计工具与报表打印控件。程序的发行只需要安装打印控件相关部分即可。

 

  (2)设计报表

 

  我们生成一个名为sample.rpt的报表,这一过程可以参考 Crystal report自带的帮助文档,本文不作详细介绍。

 

  二、创建VC工程添加报表控件

 

  在VC集成环境中用AppWizard新建一个MFC单文档工程,其余选项都为默认。菜单中选择Project->Add To Project->Components and Controls...弹出组件、控件选择对话框,进入Registered ActiveX Controls,选中Crystal Report Control 4.6 ,单击Insert按钮,确认后进入类配置对话框,按默认即可。关闭控件选择对话框完成控件的添加。

 

  三、实现报表的显示与打印

 

  下面我们将在对话框中演示控件的静态创建过程,在主视图中演示控件的动态创建过程。

 

  3.1在对话框中打印出报表

 

  在资源编辑器中打开ID为IDD_ABOUTBOX的对话框模板,在Controls工具条中我们可以找到刚加入到工程中的Crystal Report Control 4.6控件按钮,把它插入到对话框合适的位置处。

 

  右键单击对话框中的控件,选择属性,此时可以设置控件的许多属性。我们在Control选项页ReportFileName中输入报表文件名sample.rpt(可以加上完整路径),在Print Window选项页中设置控件的合适位置,回到对话框模板中按住Ctrl键,双击鼠标左键,弹出Add Member Variable对话框,我们将成员变量命名为m_CrystalReport,打开ClassWizard,为CAboutDlg对话框添加WM_INITDIALOG消息的处理函数:BOOL OnInitDialog(),并在函数中做如下处理

 

BOOL CAboutDlg::OnInitDialog() 

{

CDialog::OnInitDialog();

/////此行设置控件的父窗口,你也可以去掉该行看看运行效果/////////

m_CrystalReport.SetWindowParentHandle((long)(this->m_hWnd));

/////打印报表到窗口中/////

m_CrystalReport.PrintReport(); 

return TRUE; 

  至此,程序的第一部分编写完成,编译运行,打开About对话框看看效果吧!

  假如您并没有显示出报表,有如下可能原因:

 

  (1)控件没有放置在合适的位置或尺寸不对。

 

  (2)报表文件本身存在诸如数据源不可用等错误。

 

  控件窗口中的工具条提供了缩放、打印等功能,您也可以试试在打印机上打印出来的效果。

 

  3.2 在程序主视窗中显示报表

 

  打开ClassWizard增加对ID_FILE_OPEN和ID_FILE_PRINT的处理函数,代码如下

 

void CMyReportView::OnFileOpen()

{

char Filter[] = "Crystal Report files(*.rpt)|*.rpt|All files(*.*)|*.*||";

CRect rect;

CFileDialog OpenDlg(TRUE,0,0,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,(LPCTSTR)Filter,NULL);

if(OpenDlg.DoModal()!=IDOK) ///显示文件对话框

return;

CString m_fName=OpenDlg.GetPathName(); ///取得文件名

if(m_CrystalReport)

m_CrystalReport.DestroyWindow();

GetClientRect(rect);

///////////////////创建控件///////////////

if (!m_CrystalReport.Create(AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)),WS_CHILD|

_ WS_VISIBLE,rect,this,IDC_CRYSTALREPORT1))

{

AfxMessageBox("控件创建失败!");

return ;

}

m_CrystalReport.SetWindowParentHandle((long)(this->m_hWnd));///设置父窗口

m_CrystalReport.SetWindowBorderStyle(0); ///设置为没有边框

m_CrystalReport.SetWindowLeft(0); ///左空间

m_CrystalReport.SetWindowTop(0); ///顶部空间

m_CrystalReport.SetWindowControls(FALSE); ///不显示工具条

m_CrystalReport.SetReportFileName(m_fName); ///设置报表文件

m_CrystalReport.SetWindowWidth(rect.Width()); ///设置窗口宽度

m_CrystalReport.SetWindowHeight(rect.Height()); ///设置窗口高度

m_CrystalReport.SetFormulas(0, "Company=/"VC知识库/""); 

///将报表中的Company变量的值设置为VC知识库

m_CrystalReport.SetDestination(0); ///设置输出对象是屏幕

m_CrystalReport.PrintReport(); ///显示报表

void CMyReportView::OnFilePrint() 

{

if(m_CrystalReport && m_CrystalReport.GetReportFileName() != "")

{

m_CrystalReport.SetDestination(1); ///设置输出对象是打印机 

m_CrystalReport.PrintReport(); ///打印

}

}

  后记:我们利用Crystal Report 4.6在VC++环境下实现了报表处理,但Crystal Report 4.6报表控件的功能及可控性能可能无法满足您的要求,Seagate公司此款软件的最新版本是Crystal Report 8.0,各方面表现都非常出色,但此款软件的免费版本并不包括报表设计器,可喜的是8.0中的报表显示控件兼容以前版本的报表格式,所以笔者建议用4.6版本来设计报表,依靠8.0中的报表显示控件来显示、打印。 

 

96.全屏幕截取

CBitmap* m_pBackBitmap;

/*******************************

* 拷贝屏幕固定区域

* 参数:

* xStartPt  - 拷贝屏幕的起始点X坐标

* yStartPt  - 拷贝屏幕的起始点Y坐标

* width      - 拷贝宽度

* height     - 拷贝高度

* xToCopy  - 拷贝目的地的起始点X坐标

* yToCopy  - 拷贝目的地的起始点Y坐标

*******************************/

void CopyScreenToBitmap(xStartPt, yStartPt, width, height, xToCopy, yToCopy)

{

        //NEW资源(调用一次重新拷贝一次)

        if (m_pBackBitmap != NULL)

        {

                delete m_pBackBitmap;

                m_pBackBitmap = NULL;

        }

 

        m_pBackBitmap = new CBitmap();

 

        CDC ScrDC,MemDC;

 

        ScrDC.CreateDC("DISPLAY", NULL, NULL, NULL);

        MemDC.CreateCompatibleDC(&ScrDC);

 

        m_pBackBitmap->CreateCompatibleBitmap(&ScrDC,width,height);

        MemDC.SelectObject(m_pBackBitmap);

 

        //开始拷贝

        MemDC.BitBlt(xStartPt, yStartPt, width, height,&ScrDC,xToCopy,yToCopy,SRCCOPY);

 

        ScrDC.DeleteDC();

        MemDC.DeleteDC();

}

 

//取的屏幕分辨率

int width = ::GetSystemMetrics(SM_CXSCREEN);

int height = ::GetSystemMetrics(SM_CYSCREEN);

 

this->CopyScreenToBitmap(0,0,width,height,0,0);

 

//这时m_pBackBitmap指向的CBitmap对象就存着全屏的图象了

 

97.区域截幕

HBITMAP CopyScreenToBitmap(LPRECT lpRect) 

//lpRect 代表选定区域 

HDC hScrDC, hMemDC; 

// 屏幕和内存设备描述表 

HBITMAP hBitmap, hOldBitmap; 

// 位图句柄 

int nX, nY, nX2, nY2; 

// 选定区域坐标 

int nWidth, nHeight; 

// 位图宽度和高度 

int xScrn, yScrn; 

// 屏幕分辨率

 

// 确保选定区域不为空矩形 

if (IsRectEmpty(lpRect)) 

return NULL; 

//为屏幕创建设备描述表 

hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL); 

//为屏幕设备描述表创建兼容的内存设备描述表 

hMemDC = CreateCompatibleDC(hScrDC); 

// 获得选定区域坐标 

nX = lpRect- >left; 

nY = lpRect- >top; 

nX2 = lpRect- >right; 

nY2 = lpRect- >bottom; 

// 获得屏幕分辨率 

xScrn = GetDeviceCaps(hScrDC, HORZRES); 

yScrn = GetDeviceCaps(hScrDC, VERTRES); 

//确保选定区域是可见的 

if (nX 〈0) 

nX = 0; 

if (nY 〈 0) 

nY = 0; 

if (nX2 > xScrn) 

nX2 = xScrn; 

if (nY2 > yScrn) 

nY2 = yScrn; 

nWidth = nX2 - nX; 

nHeight = nY2 - nY; 

// 创建一个与屏幕设备描述表兼容的位图 

hBitmap = CreateCompatibleBitmap 

(hScrDC, nWidth, nHeight); 

// 把新位图选到内存设备描述表中 

hOldBitmap = SelectObject(hMemDC, hBitmap); 

// 把屏幕设备描述表拷贝到内存设备描述表中 

BitBlt(hMemDC, 0, 0, nWidth, nHeight, 

hScrDC, nX, nY, SRCCOPY); 

//得到屏幕位图的句柄 

hBitmap = SelectObject(hMemDC, hOldBitmap); 

//清除 

DeleteDC(hScrDC); 

DeleteDC(hMemDC); 

// 返回位图句柄 

return hBitmap; 

}

 

得到屏幕位图句柄以后,我们 

可以把屏幕内容粘贴到剪贴板上. 

if (OpenClipboard(hWnd)) 

//hWnd为程序窗口句柄 

//清空剪贴板 

EmptyClipboard(); 

//把屏幕内容粘贴到剪贴板上, 

hBitmap 为刚才的屏幕位图句柄 

SetClipboardData(CF_BITMAP, hBitmap); 

//关闭剪贴板 

CloseClipb 

oard(); 

}

 

int SaveBitmapToFile(HBITMAP hBitmap , 

LPSTR lpFileName) //hBitmap 为刚才的屏幕位图句柄 

{ //lpFileName 为位图文件名 

HDC hDC; 

//设备描述表 

int iBits; 

//当前显示分辨率下每个像素所占字节数 

WORD wBitCount; 

//位图中每个像素所占字节数 

//定义调色板大小, 位图中像素字节大小 , 

位图文件大小 , 写入文件字节数 

DWORD dwPaletteSize=0, 

dwBmBitsSize, 

dwDIBSize, dwWritten; 

BITMAP Bitmap; 

//位图属性结构 

BITMAPFILEHEADER bmfHdr; 

//位图文件头结构 

BITMAPINFOHEADER bi; 

//位图信息头结构 

LPBITMAPINFOHEADER lpbi; 

//指向位图信息头结构 

HANDLE fh, hDib, hPal,hOldPal=NULL; 

//定义文件,分配内存句柄,调色板句柄

 

//计算位图文件每个像素所占字节数 

hDC = CreateDC("DISPLAY",NULL,NULL,NULL); 

iBits = GetDeviceCaps(hDC, BITSPIXEL) * 

GetDeviceCaps(hDC, PLANES); 

DeleteDC(hDC); 

if (iBits 〈 = 1) 

wBitCount = 1; 

else if (iBits 〈 = 4) 

wBitCount = 4; 

else if (iBits 〈 = 8) 

wBitCount = 8; 

else if (iBits 〈 = 24) 

wBitCount = 24; 

//计算调色板大小 

if (wBitCount 〈 = 8) 

dwPaletteSize = (1 〈 〈 wBitCount) * 

sizeof(RGBQUAD);

 

//设置位图信息头结构 

GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap); 

bi.biSize = sizeof(BITMAPINFOHEADER); 

bi.biWidth = Bitmap.bmWidth; 

bi.biHeight = Bitmap.bmHeight; 

bi.biPlanes = 1; 

bi.biBitCount = wBitCount; 

bi.biCompression = BI_RGB; 

bi.biSi 

zeImage = 0; 

bi.biXPelsPerMeter = 0; 

bi.biYPelsPerMeter = 0; 

bi.biClrUsed = 0; 

bi.biClrImportant = 0;

 

dwBmBitsSize = ((Bitmap.bmWidth * 

wBitCount+31)/32)* 4 

*Bitmap.bmHeight ; 

//为位图内容分配内存 

hDib = GlobalAlloc(GHND,dwBmBitsSize+ 

dwPaletteSize+sizeof(BITMAPINFOHEADER)); 

lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib); 

*lpbi = bi; 

// 处理调色板 

hPal = GetStockObject(DEFAULT_PALETTE); 

if (hPal) 

hDC = GetDC(NULL); 

hOldPal = SelectPalette(hDC, hPal, FALSE); 

RealizePalette(hDC); 

// 获取该调色板下新的像素值 

GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, 

(LPSTR)lpbi + sizeof(BITMAPINFOHEADER) 

+dwPaletteSize, 

(BITMAPINFOHEADER *) 

lpbi, DIB_RGB_COLORS); 

//恢复调色板 

if (hOldPal) 

SelectPalette(hDC, hOldPal, TRUE); 

RealizePalette(hDC); 

ReleaseDC(NULL, hDC); 

//创建位图文件 

fh = CreateFile(lpFileName, GENERIC_WRITE, 

0, NULL, CREATE_ALWAYS, 

FILE_ATTRIBUTE_NORMAL   FILE_ 

FLAG_SEQUENTIAL_SCAN, NULL); 

if (fh == INVALID_HANDLE_VALUE) 

return FALSE; 

// 设置位图文件头 

bmfHdr.bfType = 0x4D42; // "BM" 

dwDIBSize = sizeof(BITMAPFILEHEADER) 

+ sizeof(BITMAPINFOHEADER) 

+ dwPaletteSize + dwBmBitsSize; 

bmfHdr.bfSize = dwDIBSize; 

bmfHdr.bfReserved1 = 0; 

bmfHdr.bfReserved2 = 0; 

bmfHdr.bfOffBits = (DWORD)sizeof 

(BITMAPFILEHEADER) 

+ (DWORD)sizeof(BITMAPINFOHEADER) 

+ dwPaletteSize; 

// 写入位图文件头 

WriteFile(fh, (LPSTR)&bmfHdr, sizeof 

(BITMAPFILEHEADER), &dwWritten, NULL); 

// 写入位图文件其余内容 

WriteFile(fh, (LPSTR)lpbi, dwDIBSize, 

&dwWritten, NULL); 

//清除 

GlobalUnlock(hDib); 

GlobalFree(hDib); 

CloseHandle(fh); 

}

你可能感兴趣的:(String,basic,iterator,regex,mfc,token)