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=CreateFileHandlehFile=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/0AllFiles(*.*)/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;
CStringstrFilename(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;
CStringstrFilename(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;
CStringstrFilename(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);
}
stringtarget("001"),globalTag;globalTag.append("<");globalTag.appendoot);globalTag.append(">");
stringpropTag1;propTag1.append("<");propTag1.append(name);propTag1.append(">");
string endTag1;endTag1.append("</");endTag1.append(name);endTag1.append(">");
stringpropTag2;propTag2.append("<");propTag2.append(name2);propTag2.append(">");
stringendTag2;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);
intoffset=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);
CFilefile(_T("Produces.xml"),CFile::modeWrite);
file.Write(tmp.c_str(),tmp.size());
file.Flush();
file.Close();
}
else
{
CFilefile(_T(%%1),CFile::modeWrite|CFile::modeCreate);
temp.Format("<?xmlversion=/"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 toread"); // process error
return;
}
HANDLE hMapFile, hMapFileToWrite;
//创建一个文件映射
hMapFile = CreateFileMapping(hFile, // Currentfile 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 filemapping 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 offile");
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 towrite"); // 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 filemapping object for write");
return;
}
lpMapAddressToWrite =MapViewOfFile(hMapFileToWrite, //Handle to mapping object.FILE_MAP_WRITE, //Read/write permission0, // 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 toread"); // process error
return;
}
HANDLE hMapFile, hMapFileToWrite;
//创建一个文件映射
hMapFile = CreateFileMapping(hFile, // Currentfile 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 filemapping 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 offile");
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, // createdemo.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 towrite"); //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 filemapping 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 bestrlen
(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 bestrlen
(COMPRESS_FILE_TAG_HEAD) =strlen(COMPRESS_FILE_TAG_TAIL)
#endif
*/
/**//**//**//* Compress from file source tofile dest until EOF on source.
def() returns Z_OK on success, Z_MEM_ERROR ifemory could not be allocated for processing, Z_STREAM_ERROR if an invalidcompression
level is supplied, Z_VERSION_ERROR if theversion of zlib. And the version of the library linked do not matc, or Z_ERRNOif there isan error reading or writing the files. */
static it def(FILE *source, FILE *dest, intlevel)
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 untiloutput
buffernot 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 fileprocessed
*/
} 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 tofile dest until stream ends or EOF. inf() returns Z_OK on success, Z_MEM_ERRORif memory could not be allocated for processing, Z_DATA_ERROR if the deflatedata is invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and theversion of the library linked do not match, or Z_ERRNO
if there is an error reading or writing thefiles. */
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 streamends 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 untiloutput
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'sdone */
} 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 dirheader to zfile: write error. ");
return 1;
}
if (fwrite(file, 1, len, zfile) != len||ferror(zfile))
{
fprintf(stderr,"When writing file or dirheader 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 dirheader to
zfile: write error. ");
return1;
}
return 0;
}
/**//* compress or decompress from stdin tostdout */
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 andlowercase '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: Noprivilege 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 andlowercase 'L'
{
fprintf(stderr,"File or dir %s notfound.",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 receivenotifications
// 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 Schemaconstraints. We refer to these as "common features" in followingexamples.
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 "commonhandlers" in subsequent examples.
// You will use a default handler provided byXerces-C++ (no op action).
// Users should write their own handlers andinstall them.
DefaultHandler handler;
parser->setContentHandler(&handler);
// The object parser calls when it detectsviolations of the schema.
parser->setErrorHandler(&handler);
// The object parser calls to find the schemaand
// resolve schema imports/includes.
parser->setEntityResolver(&handler);
// Parse the XML document.
// Document content sent to registeredContentHandler 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(intpos=0;AfxExtractSubString(line,content,pos,seperator);++pos)
{
if(line.Trim()!="")
{
string str(line);
match_results::backref_typebr=pat.match(str,results);
if(br.matched){
//br
}
}
}
/*
//+---------------------------------------------------------------------------
//
// Copyright ( C ) Microsoft, 1994 - 2002.
//
// File: restack.h
//
// Functions: a quick-'n'-dirty, type-unsafestack used by the iterative
// regular expression algorithm
//
// Notes: Care must be taken when using thisstack. You must pop off
// the correct type of object, otherwise youget garbage. Also,
// if you push anything that has a non-trivialdestructor, then
// be sure to explicitely pop everything offthe stack and don't
// use the unsafe_long_jump method.
//
// Author: Eric Niebler ( ericne@microsoft.com)
//
// 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<> structstatic_assert<true> { static_assert() {} };
// Work-around for a template-templateparameter 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 isconstant
// warning C4189: local variable is initializedbut not referenced
// warning C4244: conversion from 'T' to 'int',possible loss of data
// warning C4510: default constructor could notbe generated
// warning C4610: struct can never beinstantiated - user defined constructor required
// warning C4800: forcing value to bool 'true'or 'false' (performance warning)
#pragma warning( push )
#pragma warning( disable : 4127 4189 4244 45104610 4800 )
// Make sure nobody has tampered with thepacking 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 typenameselect_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 orfunction 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<> structdestroyer_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 consttype_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 dynamicmemory
// 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 weperform run-time type checking?
bool AssumePodT = false, // assume non-throwingcopy/assign/destroy for better perf
size_t DynamicBlockSizeT = 4096, // blocksallocated from heap are this size
size_t StaticBlockSizeT = 1024 // initial blockon stack is this size
>
class hetero_stack
{
typedef unsigned char byte_t;
typedef detail::type_vtable const* vtable_ptr;
public:
typedefhetero_stack<AlignmentT,RuntimeTypeCheckT,AssumePodT,DynamicBlockSizeT,StaticBlockSizeT>stack_type;
template< typename T >
struct aligned_sizeof
{
enum
{
// round up sizeof(T) to the nearest multipleof 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. allocfrom here
byte_t * m_end; // ptr to last+1 byte_t inm_mem
};
union
{
header m_head;
byte_t m_align[ aligned_sizeof<header>::no_rtti];
};
// This is the buffer into which values will bepushed and popped.
// It is guaranteed to meet the AlignmentTrequirements 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 thenode.
// OK to do this even if later statementsthrow.
m_current_node->m_head.m_current =m_current;
// Do we have a node with available memoryalready?
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 thelist
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 thisbuffer
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 thenew 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 makethe
// previous node the current node
if( m_current == m_begin )
{
// write the cached value of m_current intom_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_unwinderconst & );
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 themlater.
hetero_stack( hetero_stack const & );
hetero_stack & operator=( hetero_stackconst & );
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 inhetero_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 onthe 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 isnot 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'tneed to use an unwinder object.
typedef typename detail::select< AssumePodT|| detail::has_trivial_copy<T>::value,
dummy_unwinder, real_unwinder >::typeunwinder;
// 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 updatem_current until after
// the copy c'tor to avoid the need for anunwinder 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 apointer to the type_info
// for this type T. It will be checked inpop().
if( RuntimeTypeCheckT )
{
detail::to_type<vtable_ptr>( pb +aligned_sizeof<T>::no_rtti ) = &detail::type_info_ex<T,AlignmentT>::vtable;
}
// ok, everything succeeded -- dismiss theguard
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 inpush() 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 opcould 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<Tconst>( pT );
regex::detail::destroy( &ref );
unwind( pT );
}
// Call this version of pop when you don't needthe 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 inpush() 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<Tconst>( pv );
regex::detail::destroy( &ref );
}
// Call this version of pop when you don't needthe 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 inpush() 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 sobail.
}
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 topof the stack is a
// pointer to a type_info struct. Assert thatwe 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 thetop 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 calldestructors.
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 ifRuntimeTypeCheckT 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 atype_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 automaticallypushing/popping
// things to and from the stack. This isespecially useful
// if you want to push a bunch of things"atomically". For
// instance:
//
// typedef hetero_stack<>::scoped_popscoped_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 thecase when an
// exception gets thrown, then theyautomatically 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_tconst & ); // 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 thedestructor
// 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 ( ericne@microsoft.com)
//
// History: 3-29-00ericne 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>::templatecharacter<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_tagiterator_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_tagiterator_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_tagiterator_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_tagiterator_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 : publicstd::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 thestring
MULTILINE = 0x0004, // ^ and $ can matchinternal line breaks
SINGLELINE = 0x0008, // . can match newlinecharacter
RIGHTMOST = 0x0010, // start matching at theright of the string
NOBACKREFS = 0x0020, // only meaningful whenused with GLOBAL and substitute
FIRSTBACKREFS = 0x0040, // only meaningful whenused with GLOBAL
ALLBACKREFS = 0x0080, // only meaningful whenused with GLOBAL
NORMALIZE = 0x0100, // Preprocess patterns:"//n" => "/n", etc.
EXTENDED = 0x0200, // ignore whitespace inpattern
};
// For backwards compatibility
REGEX_FLAGS const noflags = NOFLAGS;
// helper functions to make it easier tocombine
// 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_FLAGSf1, 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 beemitted 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 > structliteral;
template<> struct literal<char>
{
static char const * string( char const * sz,wchar_t const * ) { return sz; }
template< char ch, wchar_t > structcharacter { 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 > structcharacter { enum { value = ch }; };
};
struct posix_charset_type
{
char const * m_szcharset;
size_t cchars;
};
extern posix_charset_type constg_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 theinformation
// about the set of characters that can bematched 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, Tconst & rhs )
{
return ( lhs > rhs ) ? lhs : rhs;
}
template< typename T >
T const & regex_min( T const & lhs, Tconst & rhs )
{
return ( lhs < rhs ) ? lhs : rhs;
}
} // namespace detail
//
// The perl_syntax class encapsulates the Perl5 regular expression syntax. It is
// used as a template parameter tobasic_rpattern. To customize regex syntax, create
// your own syntax class and use it as atemplate 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 thePerl 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 typenamestd::basic_string<CharT>::iterator iterator;
typedef typenamestd::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 &®EX_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-definedintrinsic 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( CharTch, std::basic_string<CharT> const & str ) //throw( bad_regexpr,std::bad_alloc )
{
perl_syntax sy( NOFLAGS );
if( invalid_charset( ch ) )
throw bad_regexpr( "invalid characterspecified to register_intrinsic_charset" );
std::basic_string<CharT> pat = str;
typenamestd::basic_string<CharT>::iterator ibegin = pat.begin();
if( BEGIN_CHARSET != sy.reg_token( ibegin,pat.end() ) )
throw bad_regexpr( "expecting beginning ofcharset" );
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 POSIXregular 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 typenamestd::basic_string<CharT>::iterator iterator;
typedef typenamestd::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 &®EX_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 intrinsiccharacter 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( CharTch, std::basic_string<CharT> const & str ) //throw( bad_regexpr,std::bad_alloc )
{
posix_syntax sy( NOFLAGS );
if( invalid_charset( ch ) )
throw bad_regexpr( "invalid characterspecified to register_intrinsic_charset" );
std::basic_string<CharT> pat = str;
typenamestd::basic_string<CharT>::iterator ibegin = pat.begin();
if( BEGIN_CHARSET != sy.reg_token( ibegin,pat.end() ) )
throw bad_regexpr( "expecting beginning ofcharset" );
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 andsubstituting regular expressions
//
// Notes: implementation details that reallybelong in a cpp file,
// but can't because of template weirdness
//
// Author: Eric Niebler ( ericne@microsoft.com)
//
// 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/lowercaseconversions:
inline char regex_toupper( char ch ) { usingnamespace std; return ( char )toupper( ch ); }
inline char regex_tolower( char ch ) { usingnamespace 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 typenamestd::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 typenamestd::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_CDECLinstantiator_helper( ... )
{
return instantiator();
}
//--------------------------------------------------------------------------
//
// Class: match_param
//
// Description: Struct that contains the stateof the matching operation.
// Passed by reference to allrecursive_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 frequentlyused fields
// are placed at offsets which are a power of 2(assuming
// a 32-bit architecture, and iterators whichare 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 forspeeding up pattern compilation.
// Every basic_rpattern object has an arena asa member.
// sub_expr objects can only be allocated fromthis arena.
// Memory is alloc'ed in chunks using theunderlying allocator.
// Chunks are freed en-masse when clear() orfinalize() is called.
//
// History: 8/17/2001 - ericne - Created
//
// Notes: This is NOT a std-compliant allocatorand CANNOT be used with
// STL containers. arena_allocator objectsmaintain state, and
// STL containers are allowed to assume theirallocators do
// not maintain state. In regexpr2.cpp, Idefine slist<>, a simple
// arena-friendly singly-linked list for usewith 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
{
returnconst_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>::typechar_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 callfinalize().
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 isfinalized 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 toalign 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 suitablyaligned
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 traversingthis graph.
//
// Methods: ~sub_expr_base - virt dtor socleanup happens correctly
// recursive_match_all - match thissub-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 freeingmemory. That will
// happen automatically when the arena objectgets destroyed.
static void operator delete( void * )
{
}
// For choosing an appropriate virtual functionbased 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 onthe 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 >
inlinesub_expr_base<IterT>::~sub_expr_base()
{
}
//--------------------------------------------------------------------------
//
// Class: subst_node
//
// Description: Substitution strings are parsedinto an array of these
// structures in order to speed up substoperations.
//
// 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 arereferenced
// get_first_subexpression - return ptr tofirst sub_expr struct
// get_width - get min/max nbr chars thispattern can match
// loops - if false, we only need to try tomatch at 1st position
// cgroups - number of visible groups
// _cgroups_total - total number of groups,including hidden ( ?: ) groups
// get_pat - get string representing thepattern
// get_subst - get string representing thesubstitution string
// get_subst_list - get the list of subst nodes
// _normalize_string - perform characterescaping
//
// Members: m_fuses_backrefs - true if subststring refers to backrefs
// m_floop - false if pat only needs to bematched 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 tomatch
//
// 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 typenamestd::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 destructorsbecause all allocated
// memory associated with the parsed patternresides in the arena.
// The memory will be freed when the arena getsdestroyed.
//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 thesubstitution uses backrefs
bool m_floop; // false ifm_pfirst->recursive_match_all only needs to be called once
bool m_fok_to_recurse; // false if the patternwould recurse too deeply
size_t m_cgroups; // number of groups ( alwaysat least one )
size_t m_cgroups_visible; // number of visiblegroups
REGEX_FLAGS m_flags; // flags used to customizesearch/replace
REGEX_MODE m_mode; // Used to pick the fast orsafe 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 speedup 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<typenamestring_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_typesize_type;
typedef typename rpattern_type::char_typechar_type;
typedef typename rpattern_type::traits_typetraits_type;
typedef typename rpattern_type::backref_typebackref_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 typenamestd::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 theguard 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 typenamebasic_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 globalfind
{
// The NOBACKREFS flag is ignored in the matchmethod.
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 ifwe'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 becauseCharT const * is not
// convertible to type IterT. Check thedeclaration 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 beginningand 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 emptyand 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;
typenamestd::basic_string<char_type>::const_iterator itsubpos2; // iter intosubst string
typenamestd::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 nextcharacter?
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 calledstr.replace, and the substitution
// string is empty. Erase the part of thestring 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 iffsave_backrefs
size_type pos_offset = 0; // keep track of howmuch 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 wedon't
// need to do any special backref maintenancehere
}
// prevent a pattern that matches 0 charactersfrom 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 thebackref 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
(
®ex_access::_do_match_iterative_helper_s,
®ex_access::_do_match_iterative_helper_c,
®ex_access::_do_match_recursive_s,
®ex_access::_do_match_recursive_c,
®ex_access::_do_match_with_stack,
®ex_access::_do_match_impl
);
}
};
//
// Some helper functions needed byprocess_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 &®EX_CHAR(CharT,'f') >= ch )
|| ( REGEX_CHAR(CharT,'A') <= ch &®EX_CHAR(CharT,'F') >= ch );
}
template< typename CharT >
inline int regex_xdigit2int( CharT ch )
{
if( REGEX_CHAR(CharT,'a') <= ch &®EX_CHAR(CharT,'f') >= ch )
return ch - REGEX_CHAR(CharT,'a') + 10;
if( REGEX_CHAR(CharT,'A') <= ch &®EX_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 beprocessed as a regex
//
// Notes: When fPattern is true, the perlescape sequences are not
// processed. If there is an octal or hexexcape sequence, we
// don't want to turn it into a regexmetacharacter here. We
// leave it unescaped so the regex parsercorrectly 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() &®EX_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'): caseREGEX_CHAR(CharT,'1'): case REGEX_CHAR(CharT,'2'): case REGEX_CHAR(CharT,'3'):
case REGEX_CHAR(CharT,'4'): caseREGEX_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 &®EX_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 syntaxmodules
//
// Classes:
//
// Functions:
//
// Coupling:
//
// Notes:
//
// Author: Eric Niebler ( ericne@microsoft.com)
//
// History: 3-29-00ericne Created
//
//----------------------------------------------------------------------------
#include "syntax2.h"
namespace regex
{
REGEX_SELECTANY TOKEN constperl_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 constperl_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 constg_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 constg_cposix_charsets = ARRAYSIZE( g_rgposix_charsets );
} // namespace detail
} // namespace regex
/***
*resetstk - Recover from Stack overflow.
*
* Copyright (c) Microsoft Corporation. Allrights 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 consts_osplatform_getter;
return s_osplatform_getter.m_osplatform;
};
/***
* void _resetstkoflw(void) - Recovers fromStack Overflow
*
* Purpose:
* Sets the guard page to its position beforethe 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 stackpointer
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 stackpointer 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 tothe start of the stack
// region, abandon the reset effort for lack ofspace. 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 stackregion below the new guard
// page. This can't be done for Win9x becauseof 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 expressionpattern 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 ( ericne@microsoft.com)
//
//----------------------------------------------------------------------------
#ifndef REGEXPR_H
#define REGEXPR_H
#ifdef _MSC_VER
// warning C4189: local variable is initializedbut not referenced
// warning C4290: C++ exception specificationignored 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 47104786 )
# 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 unsafeheterogeneous stack.
// If you are getting a compiler error in oneof 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 typechecking
typedefhetero_stack<REGEX_STACK_ALIGNMENT,true,false,32,0> unsafe_stack;
#else
// Assume that all types pushed on stack havetrivial destructors.
typedefhetero_stack<REGEX_STACK_ALIGNMENT,false,true,4096,1024> unsafe_stack;
#endif
// Used to initialize variables with the samevalue 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 conststatic_init<T>::value = T();
//
// Forward declarations
//
template< typename IterT > classsub_expr;
template< typename IterT > classmatch_group_base;
template< typename IterT > classbasic_rpattern_base_impl;
template< typename IterT > structmatch_param;
template< typename IterT > structsub_expr_base;
template< typename IterT > structregex_access;
// an iterator that keeps track of whether itis singular or not.
template< typename IterT > structsmart_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 conversionOK!
: 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 > structiter_select
{
typedef typename select
<
REGEX_DEBUG_ITERATORS &&!is_scalar<IterT>::value,
smart_iter<IterT>,
IterT
>::type type;
};
template< int SizeT > structtype_with_size { char buffer[ SizeT ]; };
// make up for the fact that the VC6std::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_CDECLconvert_allocator( FromT const & from, ... )
{
return from;
}
template< int > struct rebind_helper;
// unknown allocator
template< typename T >
type_with_size<1> REGEX_CDECLallocator_picker( T const &, ... );
template<> struct rebind_helper<1>
{
template< typename AllocT, typename ElemT>
struct inner
{
REGEX_NVC6( typedef typename AllocT::templaterebind<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 typenamerebind_helper<alloc_type>::template inner<AllocT,ElemT>::type type;
};
}
//--------------------------------------------------------------------------
//
// Class: width_type
//
// Description: represents the width of asub-expression
//
// Members: m_min - smallest number ofcharacters a sub-expr can span
// m_max - largest number of characters asub-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 escapesequences
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 aback-reference. It is a template
// on the iterator type.
//
// Methods: backref_tag - c'tor
// operator bool - so that if( br ) is true ifthis br matched
// operator! - inverse of operator bool()
//
// Members: reserved - move along, nothing tosee 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_typetraits_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, typenameOStreamT::char_type const *, int ) const
{
sout.write( first,static_cast<std::streamsize>( std::distance( first, second ) ) );
}
public:
typedef IterT iterator_type;
typedef typenamestd::iterator_traits<IterT>::value_type char_type;
typedef std::basic_string<char_type>string_type;
typedef typenamedetail::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. Thisallows implicit conversion to bool,
// but not to int. It also disallows conversionto 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 internalbook-keeping
size_t reserved2; // used for internalbook-keeping
bool reserved3; // used for internalbook-keeping
smart_iter_type reserved4; // used for internalbook-keeping
smart_iter_type reserved5; // used for internalbook-keeping
};
//namespace detail
//{
// indexing into the backref vector is fasterif the backref_tag struct
// has a size that is a power of 2.
//staticstatic_assert<32==sizeof(backref_tag<char*>)> constcheck_backref_size;
//}
// --------------------------------------------------------------------------
//
// Class: basic_match_results
//
// Description: Use this structure forreturning 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. Useiterator_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_typeconst & 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 : publicbasic_match_results<CharT const *, AllocT>
{
typedef basic_match_results<CharT const *,AllocT> base;
REGEX_DEPRECATED typedef typenamebase::const_iterator const_iterator;
typedef typename base::iterator_typeiterator_type;
typedef typename base::backref_typebackref_type;
typedef typename base::allocator_typeallocator_type;
typedef typename base::backref_vectorbackref_vector;
explicit basic_match_results_c( allocator_typeconst & 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_iteratoriterator_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 : publicsubst_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_iteratoriterator_type;
typedef basic_match_results<iterator_type,AllocT> base;
typedef typename base::backref_typebackref_type;
typedef typename base::allocator_typeallocator_type;
typedef typename base::backref_vectorbackref_vector;
friend structdetail::regex_access<iterator_type>;
explicit basic_subst_results( allocator_typeconst & 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;
typedefstd::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 : privatesplit_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_typeconst & alloc = allocator_type() )
: base( alloc )
{
}
#if !defined(_MSC_VER) | 1200 < _MSC_VER
typedef typename allocator_type::pointerpointer;
typedef typename allocator_type::const_pointerconst_pointer;
#else
typedef string_type * pointer;
typedef string_type const * const_pointer;
#endif
// shortcuts to the most basic read-onlycontainer operations
typedef typename base::size_type size_type;
typedef typename base::difference_typedifference_type;
typedef typename base::value_type value_type;
typedef typename base::reference reference;
typedef typename base::const_referenceconst_reference;
typedef typename base::iterator iterator;
typedef typename base::const_iteratorconst_iterator;
typedef typename base::reverse_iteratorreverse_iterator;
typedef typename base::const_reverse_iteratorconst_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 howmatching occurs.
//
enum REGEX_MODE
{
MODE_FAST, // Uses the fast, recursivealgorithm. Could overflow stack.
MODE_SAFE, // Uses the slow, iterativealgorithm. Can't overflow stack.
MODE_MIXED, // Uses a heuristic toautomatically 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 lesssevere. 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 intrinsiccharacter sets.
// This should be called after changing thelocale with setlocale()
//
template< typename CharT >
void reset_intrinsic_charsets( CharT ch =CharT( 0 ) );
// This is for implementation details thatreally belong in the
// cpp file, but can't go there because oftemplate 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 substitutionstring
// _find_next_group - parse the next group ofthe pattern
// _find_next - parse the next sub_expr of thepattern
// _find_atom - parse the next atom of thepattern
// _quantify - quantify the sub_expr
// _common_init - perform some commoninitialization tasks
// _parse_subst - parse the substitution string
// _add.m_subst_backref - add a backref node tothe subst list
//
// Members: m_invisible_groups - list of hiddengroups
//
// 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:
typedefdetail::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_typebackref_type;
typedef typename impl::backref_vectorbackref_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(). Ifthat.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_typeconst &, REGEX_FLAGS, REGEX_MODE )>( &this_type::init ),
static_cast<void (this_type::*)( string_typeconst &, 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 enditer
// count - count matches in a null-terminatedstring
// count - count matches in a std::string
// substitute - do substitutions in astd::string
// _do_match - internal implementation
// _do_count - internal implementation
//
// History: 8/13/2001 - ericne - Created
//
//--------------------------------------------------------------------------
template
<
typename IterT,
typename SyntaxT =perl_syntax<REGEX_DEPENDENT_TYPENAMEstd::iterator_traits<IterT>::value_type>
>
class basic_rpattern : public basic_rpattern_base<IterT,SyntaxT>
{
typedefdetail::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 becauseOtherT is not
// convertible to type IterT. Check thedeclaration of your rpattern object.
detail::static_assert<detail::is_convertible<OtherT,IterT>::value > constiterator_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
{
returndetail::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 becauseCharT* is not
// convertible to type IterT. Check thedeclaration 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
{
returndetail::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 becauseiter_type is not
// convertible to type IterT. Check thedeclaration 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 becauseOtherT is not
// convertible to type IterT. Check thedeclaration of your rpattern object.
detail::static_assert<detail::is_convertible<OtherT,IterT>::value > constiterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
returndetail::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 becauseCharT* is not
// convertible to type IterT. Check thedeclaration of your rpattern object.
detail::static_assert<detail::is_convertible<CharT*,IterT>::value > constiterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
returndetail::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 becauseiter_type is not
// convertible to type IterT. Check thedeclaration 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 > constiterator_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 becauseOtherT is not
// convertible to type IterT. Check thedeclaration of your rpattern object.
detail::static_assert<detail::is_convertible<OtherT,IterT>::value > constiterator_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 becauseIter2 is not
// convertible to type IterT. Check thedeclaration of your rpattern object.
detail::static_assert<detail::is_convertible<Char1T*,IterT>::value > constiterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
// If your compile breaks here, it's becausethe string you passed in doesn't have
// the same character type as yoursplit_results struct
same_char_types( Char1T(), Char2T() );
// If your compile breaks here, it is becauseCharT const * is not
// convertible to type IterT. Check thedeclaration of your rpattern object.
returndetail::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 becauseiter_type is not
// convertible to type IterT. Check thedeclaration 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 > constiterator_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 becauseiter_type is not
// convertible to type IterT. Check thedeclaration 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 > constiterator_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 formatching C-style, NULL-
// terminated strings. It treats thenull-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-terminatedstring
// _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<CharTconst *, SyntaxT>
{
typedefdetail::basic_rpattern_base_impl<CharT const *> impl;
public:
typedef typename basic_rpattern_base<CharTconst *, SyntaxT>::syntax_type syntax_type;
typedef typename basic_rpattern_base<CharTconst *, SyntaxT>::char_type char_type;
typedef typename basic_rpattern_base<CharTconst *, SyntaxT>::traits_type traits_type;
typedef typename basic_rpattern_base<CharTconst *, SyntaxT>::string_type string_type;
typedef typename basic_rpattern_base<CharTconst *, SyntaxT>::size_type size_type;
typedef typename basic_rpattern_base<CharTconst *, SyntaxT>::backref_type backref_type;
typedef typename basic_rpattern_base<CharTconst *, 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<CharTconst*>::_do_match_c( *this, results, szbegin ) )
{
return results.backref(0);
}
else
{
returndetail::static_init<backref_type>::value;
}
}
size_t count( CharT const * szbegin ) const
{
return detail::regex_access<CharTconst*>::_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. Asa result, the regex code
// gets instantiated twice, once for barepointers (rpattern_c) and once for
// the wrapped pointers (rpattern). But ifthere is a conversion from the
// bare ptr to the wrapped ptr, then we onlyneed to instantiate the template
// for the wrapped ptr, and the code will workfor the bare ptrs, too.
// This can be a significant space savings. TheREGEX_FOLD_INSTANTIONS
// macro controls this optimization. Thedefault 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
typedefbasic_rpattern<restring::const_iterator, perl_syntax<rechar_t> >perl_rpattern;
typedefbasic_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_resultsand subst_results
typedefbasic_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 awayin 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 forback-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 rpatternmethods, definitions for all the
// subexpression types used to perform thematching, the
// charset class definition .
//
// Classes: too many to list here
//
// Functions:
//
// Author: Eric Niebler ( ericne@microsoft.com)
//
// History: 12-11-1998ericne Created
// 01-05-2001 ericneRemoved dependency on VC's choice
// of STL iterator types.
// 08-15-2001 ericneRemoved regexpr class, moved match
// state to match_results container.
// 09-17-2001nathann Add DEBUG_HEAP_SUPPORT
// 11-16-2001 ericneAdd 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 isconstant
// warning C4355: 'this' : used in base memberinitializer 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 47104786 )
#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 includedin the header, then we
// need to mark some functions as inline toprevent them from being multiply
// defined. But if the implementation file isnot included in the header,
// we can't mark them as inline, otherwise thelinker 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( charconst * 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_tlhs, 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_twc, 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_twc, 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 theallocator object
// no longer sub allocates memory. This enablesheap checking tools like
// AppVerifier & PageHeap to find errorslike buffer overruns
#if !defined( REGEX_DEBUG_HEAP ) ®EX_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 typenamestd::iterator_traits<IEndT>::value_type char_type;
size_t retval = 0;
while( iend != ibegin &®EX_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 searchalgorithm
//
// Members: m_begin - iter to first char inpattern sequence
// m_last - iter to last char in patternsequence
// m_len - length of the pattern sequence
// m_off - array of offsets, indexed by ASCIIchar values
//
// History: 6/8/2003 - ericne - Created
//
//--------------------------------------------------------------------------
template< typename IterT >
class boyer_moore
{
typedef typenamestd::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 charch ) { 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 typenamestd::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, OtherTend ) const
{
typedef typenamestd::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 datastructure, using the
// search sub-sequence to prime the pump.
boyer_moore( IterT begin, IterT end, char_typeconst* lower = 0 )
: m_begin( begin )
, m_last( begin )
, m_low_last( lower )
{
typedef typename std::iterator_traits<IterT>::difference_typediff_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 setmatching 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 operationsare 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 ofelement 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 thenanother.
// 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 ifthe allocator
// has per-instance state.
template< typename T, typenameAllocT=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>::typechar_allocator;
#if !defined(_MSC_VER) | 1200 < _MCS_VER
// Use the empty base optimization to avoidreserving
// 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 : publicstd::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'mentwork....
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 COMMAbool2type<CaseT>() ); )
REGEX_NVC6( return pcs->templatein<CaseT>( m_ch ); )
}
};
template< typename AllocT >
struct basic_charset
{
typedefbasic_charset<std::allocator<char> > other_type;
typedefslist<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_typeconst & 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 virtuald'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_typeconst & that )
{
if( that.m_fcompliment )
{
// If no posix-style character sets are used,then we can merge this
// nested character set directly into theenclosing 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 tothis->m_ranges
wchar_t chlow = UCHAR_MAX;
typedef typenameother_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 nestedcharacter
// set into the enclosing character set, so wemust save
// a pointer to the nested character set in alist.
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<unsignedchar>( regex_tolower( ch ) ) );
m_ascii_bitvector.set( static_cast<unsignedchar>( regex_toupper( ch ) ) );
}
else
{
m_ascii_bitvector.set( static_cast<unsignedchar>( 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 twoparameters
void set_bit_range( char ch1, char ch2, bool constfnocase )
{
if( static_cast<unsigned char>( ch1 )> static_cast<unsigned char>( ch2 ) )
throw bad_regexpr( "invalid rangespecified in character set" );
if( fnocase )
{
// i is unsigned int to prevent overflow if ch2is UCHAR_MAX
for( unsigned int i = static_cast<unsignedchar>( ch1 );
i <= static_cast<unsigned char>( ch2); ++i )
{
m_ascii_bitvector.set( static_cast<unsignedchar>( regex_toupper( (char) i ) ) );
m_ascii_bitvector.set( static_cast<unsignedchar>( regex_tolower( (char) i ) ) );
}
}
else
{
// i is unsigned int to prevent overflow if ch2is UCHAR_MAX
for( unsigned int i = static_cast<unsignedchar>( ch1 );
i <= static_cast<unsigned char>( ch2); ++i )
{
m_ascii_bitvector.set( static_cast<unsignedchar>( i ) );
}
}
}
// Note overloading based on first twoparameters
void set_bit_range( wchar_t ch1, wchar_t ch2,bool const fnocase )
{
if( ch1 > ch2 )
throw bad_regexpr( "invalid rangespecified 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 ( usesoperator<() for pair templates )
m_ranges.sort();
// merge ranges that overlap
typename ranges_type::iteratoricur=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 them_posixcharson info
// into the ascii_bitvector
if( wct_zero != m_posixcharson )
{
// BUGBUG this is kind of expensive. Think of abetter way.
for( unsigned int i=0; i<=UCHAR_MAX; ++i )
if( regex_isctype( i, m_posixcharson ) )
m_ascii_bitvector.set( static_cast<unsignedchar>( i ) );
}
// m_fskip_extended_check is a cache whichtells us whether we
// need to check the m_posixcharsoff andm_nestedcharsets vectors,
// which would only be used in nesteduser-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 theascii bitvector,
// so we don't need to ever call regex_isctypeever again.
m_posixcharson = wct_zero;
}
template< bool CaseT, typename CharT >
bool extended_check( CharT ch REGEX_VC6(COMMAbool2type<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_iteratoriter_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_iteratoriter_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(COMMAbool2type<CaseT>) ) const
{
// Whoops, forgot to call optimize() on thischarset
REGEX_ASSERT( wct_zero == m_posixcharson );
return m_fcompliment !=
(
( m_ascii_bitvector[ static_cast<unsignedchar>( 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(COMMAbool2type<CaseT>) ) const
{
// use range_match_type to see if this characteris within one of the
// ranges stored in m_rgranges.
return m_fcompliment !=
(
( ( UCHAR_MAX >= ch ) ?
( m_ascii_bitvector[ static_cast<unsignedchar>( ch ) ] ) :
( ( in_ranges( ch, bool2type<CaseT>() ) )
|| ( wct_zero != m_posixcharson &®ex_iswctype( ch, m_posixcharson ) ) ) )
|| ( extended_check REGEX_NVC6(<CaseT>) (ch REGEX_VC6(COMMA bool2type<CaseT>()) ) )
);
}
private:
basic_charset & operator=( basic_charsetconst & that );
basic_charset( basic_charset const & that);
};
// Intrinsic character sets are allocated onthe heap with the standard allocator.
// They are either the built-in character sets,or the user-defined ones.
struct charset : publicbasic_charset<std::allocator<char> >
{
charset()
{
}
private:
charset( charset const & );
charset & operator=( charset const & );
};
// charset is no longer an incomplete type sowe now
// know how to destroy one. free_charset() isused in syntax2.h
REGEXPR_H_INLINE void free_charset( charsetconst * pcharset )
{
delete pcharset;
}
// Custom character sets are the ones thatappear in patterns between
// square brackets. They are allocated in aregex_arena to speed up
// pattern compilation and to make rpatternclean-up faster.
struct custom_charset : publicbasic_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_charsetconst & );
};
template< typename CharT >
class intrinsic_charsets
{
struct intrinsic_charset : public charset
{
intrinsic_charset( bool fcompliment, regex_ctype_tdesc, char const * sz )
{
reset( fcompliment, desc, sz );
}
void reset( bool fcompliment, regex_ctype_tdesc, char const * sz )
{
clear();
m_fcompliment = fcompliment;
m_posixcharson = desc;
for( ; *sz; ++sz )
m_ascii_bitvector.set( static_cast<unsignedchar>( *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, eitherbeginning 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 typenamestd::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 forstring'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_typechar_type;
typedef std::char_traits<char_type>traits_type;
return traits_type::eq( *iter, char_type() );
}
};
// Evaluates end-of-line conditions, either theend 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 typenamestd::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 typenamestd::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 typenamestd::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 typenamestd::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, registerCharT 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, registerCharT 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_iteratorconst_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 mustappear 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 bytraversing this graph.
//
// Methods: sub_expr - construct a sub_expr
// recursive_match_this - does this sub_exprmatch at the given location
// width_this - what is the width of thissub_expr
// ~sub_expr - recursively delete the sub_exprgraph
// 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 thegraph
// recursive_match_all - recursive_match_thisand recursive_match_next
// is_assertion - true if this sub_expr is azero-width assertion
// get_width - find the width of the graph atthis sub_expr
//
// Members: m_pnext - pointer to the next nodein the graph
//
// History: 8/14/2000 - ericne - Created
//
//--------------------------------------------------------------------------
template< typename IterT >
class sub_expr : publicsub_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 typenamestd::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 cannotbe quantified" );
}
// Match this object and all subsequent objects
// If recursive_match_all returns false, itmust 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 tomark the
// end of the pattern. (Duh!) It is responsiblefor ending
// the recursion, or for letting the searchcontinue if
// the match is zero-width and we are trying tofind a
// non-zero-width match
template< typename IterT >
class end_of_pattern : publicsub_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 arezero-width
// ( i.e., assertions eat no characters duringmatching )
// 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 : publicsub_expr<IterT>
{
match_wrapper & operator=( match_wrapperconst & );
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 : publicmatch_wrapper<IterT, SubExprT>
{
match_quantifier & operator=( match_quantifierconst & );
public:
match_quantifier( SubExprT * psub, size_tlbound, 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 : publicmatch_quantifier<IterT, SubExprT>
{
atom_quantifier & operator=(atom_quantifier const & );
public:
atom_quantifier( SubExprT * psub, size_tlbound, size_t ubound )
: match_quantifier<IterT, SubExprT>(psub, lbound, ubound )
{
}
protected:
void _push_frame( unsafe_stack * pstack, IterTcurr, size_t count ) const
{
std::pair<IterT, size_t> p( curr, count);
pstack->push( p );
}
void _pop_frame( match_param<IterT> ¶m ) 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_tlbound, 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 cannotget 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 a25% speed up to use a macro
// here instead of a template.
#defineDECLARE_RECURSIVE_MATCH_ALL(CSTRINGS,EXT) /
virtual bool recursive_match_all ## EXT(match_param<IterT> & param, IterT icur ) const /
{ /
typedef typenamestd::iterator_traits<IterT>::difference_type diff_type; /
/* In an ideal world, ibegin and cdiff would bemembers of a union */ /
/* to conserve stack, but I don't know if IterTis a POD type or not. */ /
IterT ibegin = icur; /
diff_type cdiff = 0; /* must be a signedintegral 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, andback 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->templatetop<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 : publicatom_quantifier<IterT, SubExprT>
{
min_atom_quantifier & operator=(min_atom_quantifier const & );
public:
min_atom_quantifier( SubExprT * psub, size_tlbound, 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 cannotget 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 a25% speed up to use a macro
// here instead of a template.
#defineDECLARE_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->templatetop<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_typechar_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 : publicmatch_char<IterT>
{
match_char_t & operator=( match_char_tconst & );
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_thisREGEX_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_thisREGEX_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_thisREGEX_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_thisREGEX_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
(
typenamestd::iterator_traits<IterT>::value_type ch,
REGEX_FLAGS flags,
regex_arena & arena
)
{
typedef typenamestd::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 : publicsub_expr<IterT>
{
match_literal & operator=( match_literalconst & );
public:
typedef typenamesub_expr<IterT>::char_type char_type;
typedef std::basic_string<char_type>string_type;
typedef typename string_type::iteratoriterator;
typedef typename string_type::const_iteratorconst_iterator;
typedef typename std::iterator_traits<IterT>::difference_typediff_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 signedintegral 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 : publicmatch_literal<IterT>
{
match_literal_t & operator=(match_literal_t const & );
public:
typedef typenamematch_literal<IterT>::char_type char_type;
typedef typenamematch_literal<IterT>::string_type string_type;
typedef typename match_literal<IterT>::iteratoriterator;
typedef typenamematch_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_thisREGEX_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_thisREGEX_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_thisREGEX_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_thisREGEX_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 : publicmatch_literal<IterT>
{
match_literal_nocase_t & operator=(match_literal_nocase_t const & );
public:
typedef typename match_literal<IterT>::char_typechar_type;
typedef typenamematch_literal<IterT>::string_type string_type;
typedef typenamematch_literal<IterT>::iterator iterator;
typedef typenamematch_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 literalin [ m_ibegin, m_iend ).
regex_toupper( ibegin, iend );
// Store the lowercase version of the literalin 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_thisREGEX_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_thisREGEX_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_thisREGEX_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 memorywill 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 charwide.
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 : publicmatch_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 : publicsub_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, typenameCharSetPtrT, bool CaseT >
class match_charset_t : publicmatch_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) inREGEX_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_thisREGEX_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_thisREGEX_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_thisREGEX_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_thisREGEX_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_charsetconst> 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, boolfthisword )
{
return ! fprevword && fthisword;
}
};
struct word_stop
{
static bool eval( bool fprevword, boolfthisword )
{
return fprevword && ! fthisword;
}
};
template< typename IterT, typename CondT>
class word_assertion_t : publicassertion<IterT>
{
word_assertion_t & operator=(word_assertion_t const & );
public:
typedef typenameassertion<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_thisREGEX_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_thisREGEX_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_thisREGEX_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_thisREGEX_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 COMMAtrue_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 rangeof 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 > classmax_group_quantifier;
template< typename IterT > classmin_group_quantifier;
template< typename IterT >
class match_group_base : publicsub_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> ¶m ) const
{
typedef typename alt_list_type::const_iteratoriter_type;
unsafe_stack * ps = param.m_pstack;
REGEX_VC6( ps->pop(type2type<iter_type>() COMMA 0 ); )
REGEX_NVC6( ps->templatepop<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_iteratoriter_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 -1if 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_iteratoriter_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 typenamesub_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_groupobject 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_allREGEX_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_allREGEX_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_thisREGEX_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 charactersfor 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_iteratoriter_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_iteratoriter_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 usedwhen adding elements
char_type * m_peek_chars_begin;
};
char_type * m_peek_chars_end;
};
template< typename IterT >
inlinematch_group_base<IterT>::~match_group_base()
{
}
// A indestructable_sub_expr is an object thatbrings itself back
// to life after explicitly being deleted. Itis used
// to ease clean-up of the sub_expr graph,where most
// nodes are dynamically allocated, but somenodes are
// members of other nodes and are notdynamically allocated.
// The recursive delete of the sub_expr graphcauses
// delete to be ( incorrectly ) called on thesemembers.
// By inheriting these members fromindestructable_sub_expr,
// explicit attempts to delete the object willhave no
// effect. ( Actually, the object will bedestructed and
// then immediately reconstructed. ) This isaccomplished
// by calling placement new in operator delete.
template< typename IterT, typename T >
class indestructable_sub_expr : publicsub_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 typenamematch_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 inan 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 : publicindestructable_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> ¶m ) 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(COMMAfalse_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 : publicsub_expr<IterT>
{
match_group_base<IterT> const *const m_pgroup;
group_wrapper & operator=( group_wrapperconst & );
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
{
returnm_pgroup->match_group_base<IterT>::iterative_match_this_c( param );
}
virtual bool iterative_rematch_this_s(match_param<IterT> & param ) const
{
returnm_pgroup->match_group_base<IterT>::iterative_rematch_this_s( param );
}
virtual bool iterative_rematch_this_c(match_param<IterT> & param ) const
{
returnm_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 ifm_cgroup is -1, or like
// an independent group otherwise.
template< typename IterT >
class independent_group_base : publicmatch_group_base<IterT>
{
independent_group_base( independent_group_baseconst & );
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 backrefvector 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 thenreturn
// 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 azero-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 returnedtrue, 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-widthassertion.
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_allREGEX_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_allREGEX_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_thisREGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c( match_param<IterT>& param ) const
{
return _do_iterative_match_thisREGEX_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 typenamematch_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> ¶m ) const
{
unsafe_stack * pstack = param.m_pstack;
typedef typename match_param<IterT>::backref_typebackref_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 : publicindependent_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 *constm_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 assertioncannot 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 : publicindependent_group_base<IterT>
{
lookbehind_assertion( lookbehind_assertionconst & );
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 typenamestd::iterator_traits<IterT>::difference_type diff_type;
// This is the room in the string from thestart to the current position
diff_type room = std::distance(param.m_ibufferbegin, icur );
// If we don't have enough room to match thelookbehind, the match fails.
// If we wanted the match to fail, try to matchthe 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 backrefvector 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 asparam.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 thenreturn
// Note that we're callingrecursive_match_all_s regardless of the CStringsT switch.
// This is because for the lookbehindassertion, 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 wereexpecting, 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 returnedtrue, 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 negativelookbehind, 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 satisfiedin a way that permited
// the rest of the pattern to matchsuccessfully, 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 typenamestd::iterator_traits<IterT>::difference_type diff_type;
// Save the backrefs
this->_push_frame( param );
// This is the room in the string from thestart to the current position
diff_type room = std::distance(param.m_ibufferbegin, param.m_icur );
// If we don't have enough room to match thelookbehind, the match fails.
// If we wanted the match to fail, try to matchthe 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 asparam.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 thenreturn
// Note that we're calling_do_match_iterative_helper_s regardless of the CStringsT switch.
// This is because for the lookbehindassertion, 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 wereexpecting, 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 returnedtrue, the backrefs must be restored
if( fmatched )
{
// Restore the backrefs
this->_pop_frame( param );
// Match succeeded. If this is a negativelookbehind, 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 satisfiedin a way that permited
// the rest of the pattern to matchsuccessfully, 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_allREGEX_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_allREGEX_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_thisREGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c(match_param<IterT> & param ) const
{
return _do_iterative_match_thisREGEX_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 : publicindestructable_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 : publicmatch_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 theend_quant
// object must declare a destructor, and itmust 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 typenamebackref_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 typenamebackref_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 grouphas matched
br.reserved3 = true; // toggle used forbacktracking
br.reserved4 =static_init<smart_iter_type>::value;
br.reserved5 =static_init<smart_iter_type>::value;
}
void _pop_frame( match_param<IterT> ¶m ) 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;
}
typenamebackref_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 >
inlinegroup_quantifier<IterT>::~group_quantifier()
{
}
template< typename IterT >
class max_group_quantifier : publicgroup_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 typenamebackref_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 theend_quant object
// gets destroyed.
this->_cleanup();
}
virtual bool recursive_match_all_s(match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_allREGEX_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_allREGEX_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 : publicindestructable_sub_expr<IterT, end_quantifier>
{
max_group_quantifier<IterT> const *constm_pquant;
end_quantifier & operator=( end_quantifierconst & );
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> ¶m ) 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_typesmart_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(COMMACStringsT()) ) )
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, moveon 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_typesmart_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_allREGEX_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_allREGEX_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 : publicgroup_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 typenamebackref_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 theend_quant object
// gets destroyed.
this->_cleanup();
}
virtual bool recursive_match_all_s(match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_allREGEX_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_allREGEX_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 : publicindestructable_sub_expr<IterT, end_quantifier>
{
min_group_quantifier<IterT> const *constm_pquant;
end_quantifier & operator=( end_quantifierconst & );
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> ¶m ) 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 typenamebackref_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 typenamebackref_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_allREGEX_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_allREGEX_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 : publicsub_expr<IterT>
{
bool _do_iterative_rematch_this(match_param<IterT> & param ) const
{
typedef typenamestd::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 groupto which this backref refers
virtual width_type width_this(width_param<IterT> & param )
{
// fix up the backref to take into account thenumber of invisible groups
fixup_backref( m_nbackref, param.m_invisible_groups);
if( m_nbackref >= param.m_rggroups.size() )
throw bad_regexpr( "reference tononexistent group" );
// If the entry in the backref vector has beennulled 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 thisgroup 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 : publicmatch_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_thisREGEX_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_thisREGEX_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_thisREGEX_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 ifthe following is false:
REGEX_ASSERT( this->m_nbackref <param.m_cbackrefs );
// Don't match a backref that hasn't matchanything
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 typenamestd::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 : publicsub_expr<IterT>
{
match_recurse & operator=( match_recurseconst & );
void _push_frame( match_param<IterT>& param ) const
{
typedef typenamematch_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> ¶m ) const
{
typedef typenamematch_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 therest of the pattern
// using the end of the recursive match as thestart 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( "recursionsub-expression cannot be quantified" );
}
virtual bool recursive_match_all_s(match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_allREGEX_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_allREGEX_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_thisREGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c(match_param<IterT> & param ) const
{
return _do_iterative_match_thisREGEX_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> ¶m )
{
// fix up the backref to take into account thenumber 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> ¶m )
{
( void ) m_passert->width_this( param );
}
};
template< typename IterT, typename CondT>
class match_conditional : publicmatch_group<IterT>
{
protected:
typedef typenamematch_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_iteratoriter_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_iteratoriter_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_allREGEX_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_allREGEX_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_thisREGEX_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_thisREGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_rematch_this_c(match_param<IterT> & param ) const
{
return _do_iterative_rematch_thisREGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );
}
virtual width_type width_this(width_param<IterT> & param )
{
typedef typename alt_list_type::const_iteratoriter_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 boolbasic_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 voidbasic_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 deallocatingthe 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<>
structis_random_access_helper<std::random_access_iterator_tag>
{
enum { value = true };
};
template< typename IterT >
struct is_random_access
{
typedef typenamestd::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 voidbasic_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 voidbasic_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 voidbasic_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 arenamemory
// 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 theend_of_pattern marker
*pgroup->pnext() = new( this->m_arena )detail::end_of_pattern<IterT>;
// The parse was successful. Dismiss the parsesentry
guard.dismiss();
}
REGEX_ASSERT( 0 == m_pfirst );
m_pfirst = pgroup;
// Calculate the width of the pattern and allgroups
this->m_nwidth = pgroup->group_width(rggroups, m_invisible_groups );
//
// determine if we can get away with onlycalling m_pfirst->recursive_match_all only once
//
this->m_floop = true;
// Optimization: if first character of patternstring is '^'
// and we are not doing a multiline match, thenwe 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 ofpattern string are ".*" or ".+",
// then we only need to try recursive_match_allonce
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 voidbasic_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 regularexpression" );
// 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 thatfact here so that
// we can opt to use a stack-conservativealgorithm 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 wecan 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 extensionsequence" );
}
}
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 ofcomment" );
}
break;
default:
throw bad_regexpr( "bad extensionsequence" );
}
}
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 theremust be at
// most 2 alternates.
if( fconditional && 2 <pgroup->calternates() )
throw bad_regexpr( "Too many alternates inconditional subexpression" );
// if this is the top-level group and itreturned a "must have"
// string, then use that to initialize aboyer-moore search structure
if(detail::is_random_access<IterT>::value && must.m_has && 0== pgroup->group_number() )
{
typedef typename string_type::const_iteratoriter_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 arecontained within it
pgroup->set_extent( detail::extent_type(extent_start, this->m_cgroups - extent_start ) );
// If this is not a pattern modifier, restorethe
// flags to their previous settings. Thiscauses
// 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 beforefinding the end of the
// character set, then this is an ill-formedregex
template< typename IterT >
inline void check_iter( IterT icur, IterT iend)
{
if( iend == icur )
throw bad_regexpr( "expecting end ofcharacter set" );
}
template< typename IBeginT, typename IEndT>
inline typenamestd::iterator_traits<IEndT>::value_type get_escaped_char( IBeginT &icur, IEndT iend, bool normalize )
{
typedef typenamestd::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'): caseREGEX_CHAR(char_type,'1'): case REGEX_CHAR(char_type,'2'): caseREGEX_CHAR(char_type,'3'):
case REGEX_CHAR(char_type,'4'): caseREGEX_CHAR(char_type,'5'): case REGEX_CHAR(char_type,'6'): caseREGEX_CHAR(char_type,'7'):
ch = char_type( *icur++ -REGEX_CHAR(char_type,'0') );
for( i=0; i<2 &®EX_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 representthemselves
default: default_:
ch = *icur;
++icur;
break;
}
return ch;
}
template< typename CharT, typename CharSetT,typename SyntaxT >
inline void parse_charset(
std::auto_ptr<CharSetT> & pnew,
typenamestd::basic_string<CharT>::iterator & icur,
typenamestd::basic_string<CharT>::const_iterator iend,
SyntaxT & sy )
{
typedef CharT char_type;
typedef std::basic_string<CharT>string_type;
typedef typename string_type::const_iteratoriter_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 thenext 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 fallthrough
case NO_TOKEN:
pnew->set_bit_range( ch_prev, *icur++,fnocase );
continue;
case CHARSET_ESCAPE: // BUGBUG user-definedcharset?
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 arecase-sensitive,
// so no special handling must be done when theNOCASE
// 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 intrinsiccharset
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();
typenameregex::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 possibleinfinite 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 thesepointers now.
pnew.release();
pold.release();
}
}
return pcharset;
}
} // namespace detail
//
// Read ahead through the pattern and treatsequential atoms
// as a single atom, making sure to handlequantification
// 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::iteratoriter_type;
typedef typenamestd::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 toskip?
{
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 toquantify something.
throw bad_regexpr( "quantifier notexpected" );
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( "mismatchedparenthesis" );
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( "mismatchedparenthesis" );
return false;
}
_find_atom( ipat, pgroup, sy );
return true;
case END_GROUP:
if( 0 == pgroup->group_number() )
throw bad_regexpr( "mismatchedparenthesis" );
return false;
case ALTERNATION:
pgroup->end_alternate();
pgroup->add_alternate();
return true;
case BEGIN_GROUP:
// Find next group. could return NULL if thegroup 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 morethat 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 bea 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 acharacter 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 escapesequence //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 characterset?
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 quotemetaoff 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 tokentype" );
break;
}
// If pnew is null, then the currentsubexpression 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 thelargest 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 asatom
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 asatom
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 asatom
}
break;
default:
return; // not a valid quantifier - treat asatom
}
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 thispattern could recurse
// deeply. Note that fact here so that we canopt 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 backreferencein 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 escapesequence 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 theiterative match routine.
// It is responsible for calling match on thecurrent 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(); // thebottom 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'redone
return true;
s.push( expr );
expr = param.m_pnext;
}
while( expr->iterative_match_this( param,CStringsT() ) );
do
{
if( jump_ptr == s.set_jump() ) // No moreposibilities to try
return false;
s.pop( expr );
}
while( ! expr->iterative_rematch_this(param, CStringsT() ) );
}
}
template< typename IterT >
REGEXPR_H_INLINE boolregex_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 boolregex_access<IterT>::_do_match_recursive_s( sub_expr_base<IterT>const * expr, match_param<IterT> & param, IterT icur )
{
returnstatic_cast<match_group_base<IterT>const*>(expr)->match_group_base<IterT>::recursive_match_all_s(param, icur );
}
template< typename IterT >
REGEXPR_H_INLINE boolregex_access<IterT>::_do_match_recursive_c( sub_expr_base<IterT>const * expr, match_param<IterT> & param, IterT icur )
{
returnstatic_cast<match_group_base<IterT>const*>(expr)->match_group_base<IterT>::recursive_match_all_c(param, icur );
}
template< typename IterT >
REGEX_NOINLINE boolregex_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 boolregex_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, IterTicur );
bool floop = pat._loops();
unsigned flags = pat.flags();
width_type nwidth = pat.get_width();
// Create some aliases for convenience andeffeciency.
REGEX_ASSERT( 0 != param.m_prgbackrefs );
// If the pstack parameter is not NULL, weshould do a safe, iterative match.
// Otherwise, we should do a fast, recursivematch.
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 exceedsthe width of the
// string, a succesful match is impossible
typedef typenamestd::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 lastcharacter.
// 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 rightmostmatches
if( icur == param.m_imatchbegin )
break;
}
}
else
{
// begin trying to match before the firstcharacter.
// 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 firstcharacter.
// 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 toallow the REGEX_TO_INSTANTIATE
// list to recursively generate theinstantiations 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, typenameT11=empty_typelist, typename T12=empty_typelist
>
struct typelist : publiccons<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 instantiatingbasic_rpattern
// with the template parameters we are interestedin. It also
// instntiates any helper routines thisbasic_rpattern relies
// on.
template< typename IterT, typename SyntaxT>
struct rpattern_instantiator : protectedregex::basic_rpattern<IterT,SyntaxT>
{
static instantiator instantiate()
{
typedef typenamestd::iterator_traits<IterT>::value_type char_type;
void (*pfn)( char_type ) =&reset_intrinsic_charsets;
returnregex::basic_rpattern<IterT,SyntaxT>::instantiate() +
regex_access<IterT>::instantiate() +
instantiator_helper( pfn );
}
};
// The regex_instantiate uses typelists and therpattern_instantiator
// to generate instantiations for all the typesin 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 typenamestd::iterator_traits<HeadT>::value_type char_type;
typedef typename SyntaxT::templaterebind<char_type>::other syntax_type;
returnrpattern_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_INSTANTIATEstd::string::const_iterator, /
std::wstring::const_iterator, /
lpcstr_t, /
lpcwstr_t
# else
# define REGEX_TO_INSTANTIATErestring::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::regexreg("(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(LPCSTRDirPath));
funMakeSure *MakeSureDirectoryPathExists;
HMODULEhMod=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;
CStringStrTempFileName=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[] = "EXCELFiles(*.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;
COleVariantcovOptional((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(
CStringstrSourceName,//数据源名
CStringstrSourceDb,//数据库存放路径
CStringstrDescription//数据源描述字符串
)
{
HKEY hKey;
DWORD lDisp;
CStringss;//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[] = "EXCELFiles(*.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;
COleVariantcovOptional((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, DWORDValue)
{
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, constchar* 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, DWORDValue)
{
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, LPCTSTRValue)
{
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, constCString 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);
CStringsrcFileName,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 /uwmpshell.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://ProgramFiles//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//InternetExplorer//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//WindowsNT//CurrentVersion");
Reg.WriteString("设定字体替换","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//WindowsNT//CurrentVersion//FontSubstitutes");
Reg.WriteString("设置光驱自动运行功能(AutoRun)","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Services//Cdrom");
Reg.WriteString("改变鼠标设置","我的电脑//HKEY_CURRENT_USER//ControlPanel//Mouse");
Reg.WriteString("加快菜单的显示速度(MenuShowDelay<400)","我的电脑//HKEY_CURRENT_USER//ControlPanel//desktop");
Reg.WriteString("修改系统的注册单位(RegisteredOrganization)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//WindowsNT//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//ControlPanel//desktop");
Reg.WriteString("设置启动信息提示(LegalNoticeCaption/Text)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//WindowsNT//CurrentVersion//Winlogon");
Reg.WriteString("更改登陆时的背景图案(Wallpaper)","我的电脑//HKEY_USERS//.DEFAULT//ControlPanel//Desktop");
Reg.WriteString("限制远程修改本机注册表(//winreg//AllowedPaths//Machine)","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Control//SecurePipeServers");
Reg.WriteString("修改环境变量","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Control//SessionManager//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//OpenFind//Places//UserDefinedPlaces");
Reg.WriteString("OfficeXP用户指定文件夹","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Office//10.0//Common//OpenFind//Places//UserDefinedPlaces");
Reg.WriteString("查看VB6临时文件","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//VisualBasic//6.0//RecentFiles");
Reg.WriteString("设置默认HTML编辑器","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//InternetExplorer//Default HTML Editor");
Reg.WriteString("更改重要URL","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//InternetExplorer//Main");
Reg.WriteString("控制面板注册位置","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//ControlPanel//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("CopyTo");
ContextMenuHandlers.CreateKey("MoveTo");
ContextMenuHandlers.CreateKey("SendTo");
}
CRegEdit CopyTo;
if(CopyTo.OpenKey("SOFTWARE//Classes//AllFilesystemObjects//shellex//ContextMenuHandlers//CopyTo"))
{
CopyTo.WriteString("","{C2FBB630-2971-11D1-A18C-00C04FD75D13}");
}
CRegEdit MoveTo;
if(MoveTo.OpenKey("SOFTWARE//Classes//AllFilesystemObjects//shellex//ContextMenuHandlers//MoveTo"))
{
MoveTo.WriteString("","{C2FBB631-2971-11D1-A18C-00C04FD75D13}");
}
CRegEdit SendTo;
if(SendTo.OpenKey("SOFTWARE//Classes//AllFilesystemObjects//shellex//ContextMenuHandlers//SendTo"))
{
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("","FolderOptions");
}
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//JavaDevelopment Kit//1.6");
RegJavaHome.ReadString("JavaHome",StrPath);
CRegEdit SysJavaHome;CString StrJavaHome;
SysJavaHome.m_RootKey=HKEY_LOCAL_MACHINE;
SysJavaHome.OpenKey("SYSTEM//CurrentControlSet//Control//SessionManager//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//SessionManager//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//SessionManager//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);
}
elseif(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 emptydir:/"%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 emptydir:/"%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 addthe description.
psl->SetPath(lpszPathObj);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFileinterface 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 fromMultiByteWideChar 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
POINTCurPoint;
//HTREEITEM CurItem;
GetCursorPos(&CurPoint);
//m_wndGameTree.ScreenToClient(&CurPoint);
//CurItem=m_wndGameTree.HitTest(CurPoint);
//if(CurItem){
//m_wndGameTree.SelectItem(CurItem);
CMenuGTMenu;
POINTpoint;
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[]数组开始时存放的是所有盘符。
当我用这样的代码测试结果是正确的,光驱盘符会被去掉:
CStringroot; //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, LPCTSTRlpszSavePath);
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, longtimeout = DEFAULT_RECVTIMEOUT);
int SelectSend(char *pData, int len, longtimeout = 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(constchar* 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, (unsignedlong*)&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, intlen, 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, intlen, 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 = newCInternetSession(strAppName,
INTERNET_OPEN_TYPE_PRECONFIG);
// if Not good, show message + return
// should never failed anyway
if(!pInternetSession)
{
AfxMessageBox("Can't start internetsession");
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,
CStringuserPass)
{
// 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 boxhave been showed
}
return 1;
}
bool CFtpGet::GetFile(CString remoteFile,
CStringlocalFile)
{
// 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,
intnumber_file)
{
// init some var
BOOL goodfile;
int x=0;
int nb_lost_file =0;
// while loop to transfer every file in thearray
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 numberof
// 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 canreconnect 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/orcall 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 filebutton
{
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, theother 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 beentransfered
for(inttest=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 handlercode 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 handlercode here
int selection=0;
selection = m_file.GetCurSel();
// now i get the good one
if(selection <0)
{
AfxMessageBox("You have to select a valuein the file list");
return;
}
m_file.DeleteString(selection);
// no more in the dialog
}
void CHttpDlg::OnAnon() // anonymous checkbutton
{
// TODO: Add your control notification handlercode 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("your@email.com");
m_pass_email.SetWindowText("Youremail");
// 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 onfailure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL,::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFCinitialization 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 onfailure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL,::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFCinitialization 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();
CStringpathname="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 (intifile=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: MFCinitialization 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())
{
CStringlcs_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";
CFilemFile(_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: MFCinitialization 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;
CFileDialogm_FileDlg(FALSE,"pdf","",OFN_OVERWRITEPROMPT,"AdobeAcrobat 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 ByDigitaltitan");
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;
HANDLEhRead_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) (LHANDLElhSession,
ULONG ulUIParam, lpMapiMessage lpMessage,
FLAGS flFlags, ULONG ulReserved);
ULONG (PASCAL *lpfnMAPIResolveName) (LHANDLElhSession,
ULONG ulUIParam, LPTSTR lpszName,
FLAGS ulFlags, ULONG ulReserved,
lpMapiRecipDesc FAR *lppRecip);
ULONG (FAR PASCAL *lpfnMAPILogon)(ULONGulUIParam,
LPSTR lpszProfileName, LPSTR lpszPassword,
FLAGS flFlags, ULONG ulReserved,
LPLHANDLE lplhSession);
ULONG (FAR PASCAL *lpfnMAPILogoff)(LHANDLElhSession,
ULONG ulUIParam, FLAGS flFlags,
ULONG ulReserved);
ULONG (FAR PASCAL *lpfnMAPIFreeBuffer)(LPVOIDlpBuffer);
ULONG (FAR PASCAL *lpfnMAPIAddress)(LHANDLElhSession,
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)(LHANDLElhSession,
ULONG ulUIParam, LPSTR lpszMessageType,
LPSTR lpszSeedMessageID, FLAGS flFlags,
ULONG ulReserved, LPSTR lpszMessageID);
ULONG (FAR PASCAL *lpfnMAPIReadMail)(LHANDLElhSession,
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(LHANDLElhSession,
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(LHANDLElhSession,
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(LHANDLElhSession,
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 (LHANDLElhSession,
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 andControls...弹出组件、控件选择对话框,进入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 Reportfiles(*.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_NORMALFILE_
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);
}