1.创建文件夹
CreateDirectory(%%1,NULL);
2.创建文件
CFile file;
file.Open(%%1,CFile::modeCreate|CFile::modeWrite);
3.删除文件
DeleteFile(%%1);
4.删除文件夹
RemoveDirectory(%%1);
5.删除一个目录下所有的文件夹
CFileFind finder;
CString path;
path.Format("%s//*.*",%%1);
BOOL bWorking = finder.FindFile(path);
while (bWorking)
{
bWorking = finder.FindNextFile();
if (finder.IsDirectory() && !finder.IsDots())
{
RemoveDirectory(finder.GetFilePath());
}
}
6.清空文件夹
RemoveDirectory(%%1);
CreateDirectory(%%1,NULL);
7.读取文件
char sRead[5120];
CFile mFile(_T(%%1),CFile::modeRead);
while (sRead!=NULL)
{
mFile.Read(sRead,5120);
CString %%2(sRead);
%%3
}
mFile.Close();
8.写入文件
CFile mFile(_T(%%1), CFile::modeWrite|CFile::modeCreate);
mFile.Write(%%2,sizeof(%%2));
mFile.Flush();
mFile.Close();
9.写入随机文件
char szTempPath[_MAX_PATH],szTempfile[_MAX_PATH];
GetTempPath(_MAX_PATH, szTempPath);
GetTempFileName(szTempPath,_T ("my_"),0,szTempfile);
CFile m_tempFile(szTempfile,CFile:: modeCreate|CFile:: modeWrite);
char m_char='a';
m_tempFile.Write(&m_char,2);
m_tempFile.Close();
//循环写入多个值
strTempA;
int i;
int nCount=6;
//共有6个文件名需要保存
for (i=0;i{strTemp.Format("%d",i);
strTempA=文件名;
//文件名可以从数组,列表框等处取得.
::WritePrivateProfileString("UseFileName","FileName"+strTemp,strTempA,
c://usefile//usefile.ini);
}
strTemp.Format("%d",nCount);
::WritePrivateProfileString("FileCount","Count",strTemp,"c://usefile//usefile.ini");
//将文件总数写入,以便读出.
//读出
nCount=::GetPrivateProfileInt("FileCount","Count",0,"c://usefile//usefile.ini");
for(i=0;i{strTemp.Format("%d",i);
strTemp="FileName"+strTemp;
::GetPrivateProfileString("CurrentIni",strTemp,"default.fil", strTempA.GetBuffer(MAX_PATH),MAX_PATH,"c://usefile//usefile.ini");
//使用strTempA中的内容.
}
1.Seek
Seek(100L,CFile::begin);//移动到文件开始后100字节处
Seek(100L,CFile::end);
Seek(100L,CFile::current);
2.GetPosition
得到文件当前位置,返回32位文件指针
DWORD pos=file.GetPostition();
file.Seek(pos,CFile::begin);
3.GetLength()
10.读取文件属性
DWORD dwAttrs = GetFileAttributes(%%1);
if(dwAttrs & FILE_ATTRIBUTE_READONLY) {
%%2
}
if(dwAttrs & FILE_ATTRIBUTE_NORMAL){
%%3
}
11.写入属性
SetFileAttributes(%%1,dwAttrs | FILE_ATTRIBUTE_READONLY);
12.枚举一个目录下所有文件夹
CFileFind finder;
CString path;
path.Format("%s//*.*",%%1);
BOOL bWorking = finder.FindFile(path);
while (bWorking) {
bWorking = finder.FindNextFile();
if(finder.IsDirectory() && !finder.IsDots()){
CString %%1=finder.GetFilePath();
%%2
}
}
13.复制文件夹
/*
#include <deque>
using namespace std;
*/
deque<CString>ctr;
WIN32_FIND_DATA FileData;
HANDLE hSearch;
DWORD dwAttrs;
char szDirPath[] = %%2;
char szNewPath[MAX_PATH];
BOOL fFinished = FALSE;
if (!CreateDirectory(szDirPath, NULL)) {
//不能创建新的目录
return;
}
CString path;
path.Format("%s//*.*",%%1);
hSearch = FindFirstFile(path, &FileData);
if (hSearch == INVALID_HANDLE_VALUE) {
return;
}
while (ctr.size>0) {
if(!fFinished)
lstrcpy(szNewPath, szDirPath);
lstrcat(szNewPath, FileData.cFileName);
if (CopyFile(FileData.cFileName, szNewPath, FALSE)) {
dwAttrs = GetFileAttributes(FileData.cFileName);
if (!(dwAttrs & FILE_ATTRIBUTE_READONLY)) {
SetFileAttributes(szNewPath,
dwAttrs | FILE_ATTRIBUTE_READONLY);
}
}
else {
//不能复制文件
return;
}
if (!FindNextFile(hSearch, &FileData)) {
if (GetLastError() == ERROR_NO_MORE_FILES) {
//遍历文件夹完成
fFinished = TRUE;
}
else {
//找不到下一个文件
return;
}
}
}
}
FindClose(hSearch);
14.复制一个目录下所有的文件夹到另一个文件夹下
/*
#include <deque>
using namespace std;
*/
deque<CString>ctr;
WIN32_FIND_DATA FileData;
HANDLE hSearch;
DWORD dwAttrs;
char szDirPath[] = %%2;
char szNewPath[MAX_PATH];
BOOL fFinished = FALSE;
if (!CreateDirectory(szDirPath,NULL))
{
//不能创建新的目录
return;
}
CString path;
CFileFind finder;
path.Format("%s//*.*",%%1);
BOOL bWorking = finder.FindFile(path);
while (bWorking)
{
bWorking = finder.FindNextFile();
if(finder.IsDirectory() && !finder.IsDots()){
hSearch = FindFirstFile(finder.GetFilePath()+"//*.*", &FileData);
if (hSearch == INVALID_HANDLE_VALUE)
{
return;
}
while (!fFinished)
{
lstrcpy(szNewPath, szDirPath);
lstrcat(szNewPath, FileData.cFileName);
if (CopyFile(FileData.cFileName, szNewPath, FALSE))
{
dwAttrs = GetFileAttributes(FileData.cFileName);
if (!(dwAttrs & FILE_ATTRIBUTE_READONLY))
{
SetFileAttributes(szNewPath,
dwAttrs | FILE_ATTRIBUTE_READONLY);
}
}
else
{
//不能复制文件
return;
}
if (!FindNextFile(hSearch, &FileData))
{
if (GetLastError() == ERROR_NO_MORE_FILES)
{
//遍历文件夹完成
fFinished = TRUE;
}
else
{
//找不到下一个文件
return;
}
}
}
FindClose(hSearch);
}
}
15.移动文件夹
/*
#include <deque>
using namespace std;
*/
deque<CString>ctr;
WIN32_FIND_DATA FileData;
HANDLE hSearch;
DWORD dwAttrs;
char szDirPath[] = %%2;
char szNewPath[MAX_PATH];
BOOL fFinished = FALSE;
if (!CreateDirectory(szDirPath, NULL))
{
//不能创建新的目录
return;
}
CString path;
path.Format("%s//*.*",%%1);
hSearch = FindFirstFile(path, &FileData);
if (hSearch == INVALID_HANDLE_VALUE)
{
return;
}
while (!fFinished)
{
lstrcpy(szNewPath, szDirPath);
lstrcat(szNewPath, FileData.cFileName);
if (CopyFile(FileData.cFileName, szNewPath, FALSE))
{
dwAttrs = GetFileAttributes(FileData.cFileName);
if (!(dwAttrs & FILE_ATTRIBUTE_READONLY))
{
SetFileAttributes(szNewPath,
dwAttrs | FILE_ATTRIBUTE_READONLY);
}
}
else
{
//不能复制文件
return;
}
if (!FindNextFile(hSearch, &FileData))
{
if (GetLastError() == ERROR_NO_MORE_FILES)
{
//遍历文件夹完成
fFinished = TRUE;
}
else
{
//找不到下一个文件
return;
}
}
}
FindClose(hSearch);
RemoveDirectory(%%1);
16.移动一个文件夹下所有的文件夹到另一个目录下
/*
#include <deque>
using namespace std;
*/
deque<CString>ctr;
WIN32_FIND_DATA FileData;
HANDLE hSearch;
DWORD dwAttrs;
char szDirPath[] = %%2;
char szNewPath[MAX_PATH];
BOOL fFinished = FALSE;
if (!CreateDirectory(szDirPath,NULL))
{
//不能创建新的目录
return;
}
CString path;
path.Format("%s//*.*",%%1);
BOOL bWorking = finder.FindFile(path);
while (bWorking)
{
bWorking = finder.FindNextFile();
if(finder.IsDirectory() && !finder.IsDots()){
hSearch = FindFirstFile(finder.GetFilePath()+"//*.*", &FileData);
if (hSearch == INVALID_HANDLE_VALUE)
{
return;
}
while (!fFinished)
{
lstrcpy(szNewPath, szDirPath);
lstrcat(szNewPath, FileData.cFileName);
if (CopyFile(FileData.cFileName, szNewPath, FALSE))
{
dwAttrs = GetFileAttributes(FileData.cFileName);
if (!(dwAttrs & FILE_ATTRIBUTE_READONLY))
{
SetFileAttributes(szNewPath,
dwAttrs | FILE_ATTRIBUTE_READONLY);
}
}
else
{
//不能复制文件
return;
}
if (!FindNextFile(hSearch, &FileData))
{
if (GetLastError() == ERROR_NO_MORE_FILES)
{
//遍历文件夹完成
fFinished = TRUE;
}
else
{
//找不到下一个文件
return;
}
}
}
FindClose(hSearch);
RemoveDirectory(finder.GetFilePath().GetBuffer(0));
}
}
17.以一个文件夹的框架在另一个目录创建文件夹和空文件
/*
#include <deque>
using namespace std;
*/
deque<CString>ctr;
WIN32_FIND_DATA FileData;
HANDLE hSearch;
DWORD dwAttrs;
char szDirPath[] = %%2;
char szNewPath[MAX_PATH];
BOOL fFinished = FALSE;
if (!CreateDirectory(szDirPath, NULL))
{
//不能创建新的目录
return;
}
CString path;
path.Format("%s//*.*",%%1);
hSearch = FindFirstFile(path, &FileData);
if (hSearch == INVALID_HANDLE_VALUE)
{
return;
}
while (!fFinished)
{
lstrcpy(szNewPath, szDirPath);
lstrcat(szNewPath, FileData.cFileName);
HANDLE hFile=CreateFileHandle hFile=CreateFile(szNewPath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if(!hFile)
{
//不能创建文件
return;
}
if (!FindNextFile(hSearch, &FileData))
{
if (GetLastError() == ERROR_NO_MORE_FILES)
{
//遍历文件夹完成
fFinished = TRUE;
}
else
{
//找不到下一个文件
return;
}
}
}
FindClose(hSearch);
18.复制文件
CopyFile(%%1,%%2,true);
19.复制一个文件夹下所有的文件到另一个目录
/*
#include <string>
using std::string;
*/
char sep='/';
#ifdef _WIN32
sep='//';
#endif
CFileFind finder;
CString path;
path.Format("%s//*.*",%%1);
BOOL bWorking = finder.FindFile(path);
while (bWorking)
{
bWorking = finder.FindNextFile();
if(!finder.IsDirectory() || finder.IsDots()){
string s(finder.GetFileName());
if(s.rfind(sep,s.length())!=string::npos)
{
char *file=substr(i+1,s.length()-i).c_str();
CString sourcefile;
sourcefile.Format("%s%c%s",%%1,sep,file);
CString targetfile;
targetfile.Format("%s%c%s",%%2,file);
CopyFile(sourcefile,targetfile,true);
}
}
}
20.提取扩展名
CString path(%%1);
CString %%2=path.Mid(path.ReverseFind('.'));
21.提取文件名
CString path(%%1);
CString %%2=path.Mid(path.ReverseFind('//')+1);
22.提取文件路径
char appName[MAX_PATH];
GetModualFileName(NULL,appName,MAX_PATH);
CString %%1(appName);
23.替换扩展名
/*
#include <string>
using std::string;
*/
string s(%%1);
string newExt(%%2);
string::size_type i=s.rfind('.',s.length());
if(i!=string::npos)
s.replace(i+1,newExt.length(),newExt);
CString %%3(s);
24.追加路径
/*
#include <string>
#include <cstdlib>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
using namespace std;
using namespace boost::filesystem;
*/
try {
path p1=complete(path(%%2,native),
path(%%1,native));
path p2=system_complete(path(%%2,native));
CString %%3(p3);
%%4
}
catch(exception& e){
//e.what();
}
25.移动文件
MoveFile(%%1,%%2);
26.移动一个文件夹下所有文件到另一个目录
/*
#include <string>
using std::string;
*/
char sep='/';
#ifdef _WIN32
sep='//';
#endif
CFileFind finder;
CString path;
path.Format("%s//*.*",%%1);
BOOL bWorking = finder.FindFile(path);
while (bWorking)
{
bWorking = finder.FindNextFile();
if(!finder.IsDirectory() || finder.IsDots()){
string s(finder.GetFileName());
CString sourcefile(%%1);
if(s.rfind(sep,s.length())!=string::npos)
{
sourcefile=sourcefile+"//"+s.substr(i+1,s.length()-i);
CString targetfile(s.substr(i+1,s.length()-i));
targetfile=%%2+"//"+targetfile/;
MoveFile(sourcefile.GetBuffer(0),targetfile.GetBuffer(0),true);
}
}
}
27.指定目录下搜索文件
CString strFileTitle;
CFileFind finder;
BOOL bWorking = finder.FindFile(%%1); //"C://windows//sysbkup//*.cab"
while(bWorking)
{
bWorking=finder.FindNextFile();
strFileTitle=finder.GetFileTitle();
}
28.打开对话框
CString %%1;
CFileDialog dlg(TRUE);///TRUE为OPEN对话框,FALSE为SAVE AS对话框
//dlg.m_ofn.lpstrInitialDir=_T("d://"); //这里就设置了对话框的默认目录d盘
dlg.m_ofn.lpstrFilter="Document/0*.doc/0All Files(*.*)/0*.*/0/0";
if(dlg.DoModal()==IDOK)
%%1=dlg.GetPathName();
29.文件分割
CFile m_File;
CString m_Filename,m_FileTitle,m_FilePath;
m_FileName=%%1;
char pBuf[4096];
if(m_File.Open(m_FileName,CFile::modeRead | CFile::shareDenyWrite))
{
m_FileName=m_File.GetPathName();
m_FileTitle=m_File.GetFileTitle();
DWORD FileLength=m_File.GetLength();
DWORD PartLength=FileLength/2+FileLength%2;
int nCount=1;
CString strName;
CFile wrFile;
DWORD ReadBytes;
while(true)
{
ReadBytes=m_File.Read(pBuf,PartLength);
strName.Format("%s%d",m_FIleTitle,nCount);
wrFile.Open(strName,CFile::modeWrite | CFile::modeCreate);
wrFile.Write(pBuf,ReadBytes);
wrFile.Close();
if(ReadBytes<PartLength)
break;
nCount++;
}
m_File.Close();
}
else
AfxMessageBox("不能打开文件");
30.文件合并
//#include <string>
using std::string;
string s(%%1);
char sep='/';
#ifdef _WIN32
sep='//';
#endif
size_t sz=s.rfind(sep,s.length());
if(sz!=string::npos)
{
CFile Out;
CString strFilename(s.substr(i+1,s.length()-i));
if(Out.Open(%%2+"//"+strfilename,cfile::modewrite%7ccfile::modecreate)){
for(int i=1;i<=2;i++)
{
CString Filename;
Filename.Format("%s//%s%d",%%2,strfilename,atoi(i));
CFile In;
if(In.Open(Filename,CFile::modeRead)){
char cbBuffer[4096];
int nFilesize=In.GetLength();
while(nFilesize>0){
int nSize=sizeof(cbBuffer);
if(nSize>nFilesize)
nSize=nFilesize;
try{
In.Read(cbBuffer,nSize);
}
catch(CFileException *e){
char *lpMsgBuf;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,e->m_lOsError,
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
(LPSTR)&lpMsgBuf,0,NULL)>0){
AfxMessageBox(lpMsgBuf);
LocalFree(lpMsgBuf);
}
e->Delete();
return;
}
try{
Out.Write(cbBuffer,nSize);
}
catch(CFileException *e){
char *lpMsgBuf;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,e->m_lOsError,
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
(LPSTR)&lpMsgBuf,0,NULL)>0){
AfxMessageBox(lpMsgBuf);
LocalFree(lpMsgBuf);
}
e->Delete();
return;
}
nFilesize=nSize;
}
}
else
AfxMessageBox("不能打开"+Filename);
}
}
}
else
AfxMessageBox("不能创建输出文件");
31.文件简单加密
//#include <string>
using std::string;
string s(%%1);
char sep='/';
#ifdef _WIN32
sep='//';
#endif
size_t sz=s.rfind(sep,s.length());
CString outfile;
if(sz!=string::npos)
{
CFile Out,In;
int nFIlesize;
char *lpMsgBuf;
CString strFilename(s.substr(i+1,s.length()-i));
if(!in.Open(%%1,CFile::modeRead)){
//不能打开输入文件
return;
}
outfile.Format("//enc_",%%2,strfilename);
if(!Out.Open(outfile,CFile::modewrite|CFile::modeCreate)){
//不能打开输出文件
return;
}
}
nFilesize=In.GetLength();
lpBuffer=new char[nFilesize];
if(lpBuffer==NULL){
//不能分配复制缓存
return;
}
CFileStatus rStatus;
In.GetStatus(%%1,rStatus);
try{
In.Read(cbBuffer,nFilesize);
}
catch(CFileException *e){
char *lpMsgBuf;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,e->m_lOsError,
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
(LPSTR)&lpMsgBuf,0,NULL)>0){
AfxMessageBox(lpMsgBuf);
LocalFree(lpMsgBuf);
}
e->Delete();
return;
}
for(int i=0;i<nFilesize;i++)
{
int ibt=lpBuffer[i];
ibt+=100;
ibt%=256;
bpBuffer[i]=(char)ibt;
}
try{
Out.Write(cbBuffer,nFilesize);
}
catch(CFileException *e){
char *lpMsgBuf;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,e->m_lOsError,
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
(LPSTR)&lpMsgBuf,0,NULL)>0){
AfxMessageBox(lpMsgBuf);
LocalFree(lpMsgBuf);
}
e->Delete();
return;
}
Out.Close();
//In.Close();
CFile::SetStatus(outfile,rstatus);
delete[] lpBuffer;
}
32.文件简单解密
//#include <string>
using std::string;
string s(%%1);
char sep='/';
#ifdef _WIN32
sep='//';
#endif
size_t sz=s.rfind(sep,s.length());
CString infile;
if(sz!=string::npos)
{
CFile Out,In;
int nFIlesize;
char *lpMsgBuf;
CString strFilename(s.substr(i+1,s.length()-i));
infile.Format("%s//enc_%s",%%2,strfilename)
if(!in.Open(infile,CFile::moderead)){
//不能打开输入文件
return;
}
if(!Out.Open(%%1,CFile::modeWrite|CFile::modeCreate)){
//不能打开输出文件
return;
}
nFilesize=In.GetLength();
lpBuffer=new char[nFilesize];
if(lpBuffer==NULL){
//不能分配复制缓存
return;
}
CFileStatus rStatus;
In.GetStatus(infile,rstatus);
try{
In.Read(cbBuffer,nFilesize);
}
catch(CFileException *e){
char *lpMsgBuf;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,e->m_lOsError,
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
(LPSTR)&lpMsgBuf,0,NULL)>0){
AfxMessageBox(lpMsgBuf);
LocalFree(lpMsgBuf);
}
e->Delete();
return;
}
for(int i=0;i<nFilesize;i++)
{
int ibt=lpBuffer[i];
ibt-=100;ibt+=256;
ibt%=256;
bpBuffer[i]=(char)ibt;
}
try{
Out.Write(cbBuffer,nFilesize);
}
catch(CFileException *e){
char *lpMsgBuf;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,e->m_lOsError,
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
(LPSTR)&lpMsgBuf,0,NULL)>0){
AfxMessageBox(lpMsgBuf);
LocalFree(lpMsgBuf);
}
e->Delete();
return;
}
Out.Close();
//In.Close();
CFile::SetStatus(%%1,rStatus);
delete[] lpBuffer;
}
33.读取ini文件属性
CStdioFile inifile(%%1,CFile::modeRead);
CString path = inifile.GetFilePath();
inifile.Close();
char key[1024];
DWORD bytes = GetPrivateProfileString(%%2,%%3,%%4,key,1024,path);
if(bytes < 1024)
key[bytes] = '/0';
CString %%5(key);
34.合并一个目录下所有的文件
CString Directory;
Directory.Format("%s//*.*",%%1);
CFileFind FFile;
CFile Out;
if(Out.Open(%%2,CFile::modeWrite|CFile::modeCreate)){
BOOL bFound=FFile.FindFile(Directory);
while(bFound)
{
bFound=FFile.FileNextFile();
if(!FFile.IsDirectory() && !FFile.IsDots())
{
CString Filename=FFile.GetFileName();
CFile In;
if(In.Open(Filename,CFile::modeRead)){
char cbBuffer[4096];
int nFIlesize=In.GetLength();
while(nFIlesize>0){
{
int nSize=sizeof(cbBuffer);
if(nSize>nFilesize)
nSize=nFilesize;
try {
In.Read(cbBuffer,nSize);
}
catch(CFileException *e){
char *lpMsgBuf;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,e->m_lOsError,
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
(LPSTR)&lpMsgBuf,0,NULL)>0){
AfxMessageBox(lpMsgBuf);
LocalFree(lpMsgBuf);
}
e->Delete();
return;
}
try {
Out.Write(cbBuffer,nSize);
}
catch(CFileException *e){
char *lpMsgBuf;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,e->m_lOsError,
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
(LPSTR)&lpMsgBuf,0,NULL)>0){
AfxMessageBox(lpMsgBuf);
LocalFree(lpMsgBuf);
}
e->Delete();
return;
}
nFilesize=nSize;
}
}
else
AfxMessageBox("不能打开"+Filename);
}
}
}
}
else
AfxMessageBox("不能创建输出文件");
35.写入ini文件属性
/*
CStdioFile inifile(%%1,CFile::modeRead);
CString path = inifile.GetFilePath();
inifile.Close();
int bytes = GetPrivateProfileInt(%%2,%%3,%%4,path);
*/
WritePrivateProfileString(%%2,%%3,%%4,path);
36.获得当前路径
TCHAR szDir[MAX_PATH];
GetCurrentDirectory(MAX_PATH,szDir);
CString %%1;
%%1.Format("%s",szDir);
37.读取XML数据库
/*
#include <string>
using namespace std;
*/
char sRead[5192];
const char* name="Name";
const char* name2="author";
const char* root="ProductData";
const char* subNodeTag="Product";
const char* ID="pid";
//%%2="ProductData" //%%4="pid" //%%6="author"
//%%3="Product" //%%5="Name"
char sRead[5192];
CFile mFile(_T(%%1),CFile::modeRead);
mFile.Read(sRead,5192);
if(sRead!=NULL)
{
string tmp;
while(sRead!=NULL)
{
tmp.append(sRead);
mFile.Read(sRead,5192);
}
string target("001"),globalTag;globalTag.append("<");globalTag.appendoot);globalTag.append(">");
string propTag1;propTag1.append("<");propTag1.append(name);propTag1.append(">");
string endTag1;endTag1.append("</");endTag1.append(name);endTag1.append(">");
string propTag2;propTag2.append("<");propTag2.append(name2);propTag2.append(">");
string endTag2;endTag2.append("</");endTag2.append(name2);endTag2.append(">");
int offset=tmp.find_first_of(globalTag);
while(offset)
{
offset=tmp.find_first_of(globalTag);
string description;
tmp.copy(description.begin(),tmp.find_first_of("/"",offset+1)-offset);
if(target.compare(description)==0)
{
string prop,prop2;
offset=tmp.find_first_of(propTag1,offset)+strlen(name)+2;
tmp.copy(prop.begin(),tmp.find_first_of(endTag1,offset)- offset,offset);
offset=tmp.find_first_of(propTag2,offset)+strlen(name2)+2;
tmp.copy(prop2.begin(),tmp.find_first_of(endTag2,offset)-offset,offset);
//CString %%8(prop),%%9(prop2);
//%%10
return 0;
}
}
}
else
return -1;
38.写入XML数据库
/*
#include <string>
using namespace std;
*/
char sRead[5192];
int no;
const char* name="Name";
const char* name2="author";
const char* root="ProductData";
const char* subNodeTag="Product";
const char* ID="pid";
//%%2="ProductData" //%%4="pid" //%%6="port"
//%%3="Product" //%%5="Name" //%%7="author"
CString temp;
char sRead[5192];
string description;
CFile mFile(_T(%%1),CFile::modeRead);
mFile.Read(sRead,5192);
if(sRead!=NULL)
{
string tmp;
while(sRead!=NULL)
{
tmp.append(sRead);
memset(sRead,0,5192);
mFile.Read(sRead,5192);
}
temp.Format("<%s %s",subNodeTag,ID);
int offset=tmp.find_last_of(temp)+strlen(subNodeTag) +strlen(ID)+4;
temp.Format("/"><%s",name);
tmp.copy(description.begin(),tmp.find_last_of(temp)- offset,offset);
no=atoi(description.c_str())+1;
mFile.Close();
temp.Format("</%s>",root);
CString temp2;
temp2.Format("<%s %s=/"%d/"><%s>%s</%s><%s>%s</%s",subNodeTag,ID,no,name,"bbbbbbbbbbbbbbbb",name,name2,"cccccccccccccc",name2);
tmp.insert(tmp.find_last_of(temp),temp2);
CFile file(_T("Produces.xml"),CFile::modeWrite);
file.Write(tmp.c_str(),tmp.size());
file.Flush();
file.Close();
}
else
{
CFile file(_T(%%1),CFile::modeWrite|CFile::modeCreate);
temp.Format("<?xml version=/"1.0/" encoding=/"gb2312/"?><%s><%s %s=/"0/"><%s>%s</%s><%s>%s</%s></%s></%s>",root,subNodeTag,ID,name,"bbbbbbbbbbbbbbbb",name,name2,"cccccccccccccc",name2,subNodeTag,root);
file.Write(temp.GetBuffer(0),temp.GetLength());
file.Flush();
file.Close();
}
39.ZIP压缩文件
//www.zlib.net
/*
#ifdef _DEBUG
#pragma comment(lib,"zlibd.lib")
#else
#pragma comment(lib,"zlib.lib")
#endif
#include "zlib.h"
#include "zconf.h"
*/
HANDLE hFile, hFileToWrite;
CString strFilePath;
m_ctrEdit.GetWindowText(strFilePath);
//打开要进行压缩的文件
hFile = CreateFile(strFilePath, // file name
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // no security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL
); // no attr. template
if (hFile == INVALID_HANDLE_VALUE)
{
AfxMessageBox("Could not open file to read"); // process error
return;
}
HANDLE hMapFile, hMapFileToWrite;
//创建一个文件映射
hMapFile = CreateFileMapping(hFile, // Current file handle.
NULL, // Default security.
PAGE_READONLY, // Read/write permission.
0, // Max. object size.
0, // Size of hFile.
"ZipTestMappingObjectForRead"
); // Name of mapping object.
if (hMapFile == NULL)
{
AfxMessageBox("Could not create file mapping object");
return;
}
LPVOID lpMapAddress, lpMapAddressToWrite;
//创建一个文件映射的视图用来作为source
lpMapAddress = MapViewOfFile(hMapFile, // Handle to mapping object.
FILE_MAP_READ, // Read/write permission
0, // Max. object size.
0, // Size of hFile.
0); // Map entire file.
if (lpMapAddress == NULL)
{
AfxMessageBox("Could not map view of file");
return;
}
DWORD dwFileLength,dwFileLengthToWrite;
dwFileLength = GetFileSize(hFile, NULL);
m_dwSourceFileLength = dwFileLength;
//因为压缩函数的输出缓冲必须比输入大0.1% + 12 然后一个DWORD用来保存压缩前的大小,
// 解压缩的时候用,当然还可以保存更多的信息,这里用不到
dwFileLengthToWrite = (double)dwFileLength*1.001 + 12 +sizeof(DWORD);
//以下是创建一个文件,用来保存压缩后的文件
hFileToWrite = CreateFile("demoFile.rar", // demoFile.rar
GENERIC_WRITE|GENERIC_READ, // open for writing
0, // do not share
NULL, // no security
CREATE_ALWAYS, // overwrite existing
FILE_ATTRIBUTE_NORMAL , // normal file
NULL); // no attr. template
if (hFileToWrite == INVALID_HANDLE_VALUE)
{
AfxMessageBox("Could not open file to write"); // process error
return;
}
hMapFileToWrite = CreateFileMapping(hFileToWrite, // Current file handle.
NULL, // Default security.
PAGE_READWRITE, // Read/write permission.
0, // Max. object size.
dwFileLengthToWrite, // Size of hFile.
"ZipTestMappingObjectForWrite"); // Name of mapping object.
if (hMapFileToWrite == NULL)
{
AfxMessageBox("Could not create file mapping object for write");
return;
}
lpMapAddressToWrite = MapViewOfFile(hMapFileToWrite, //Handle to mapping object.FILE_MAP_WRITE, // Read/write permission 0, // Max. object size.
0, // Size of hFile.
0
); // Map entire file.
if (lpMapAddressToWrite == NULL)
{
AfxMessageBox("Could not map view of file");
return;
}
//这里是将压缩前的大小保存在文件的第一个DWORD里面
LPVOID pBuf = lpMapAddressToWrite;
(*(DWORD*)pBuf) = dwFileLength;
pBuf = (DWORD*)pBuf + 1;
//这里就是最重要的,zlib里面提供的一个方法,将源缓存的数据压缩至目的缓存
//原形如下:
//int compress (Bytef *dest, uLongf *destLen, const Bytef*source, uLong sourceLen);
//参数destLen返回实际压缩后的文件大小。
compress((Bytef*)pBuf,&dwFileLengthToWrite, (Bytef*)lpMapAddress, dwFileLength);
UnmapViewOfFile(lpMapAddress);
CloseHandle(hMapFile);
CloseHandle(hFile);
UnmapViewOfFile(lpMapAddressToWrite);
CloseHandle(hMapFileToWrite);
//这里将文件大小重新设置一下
SetFilePointer(hFileToWrite,dwFileLengthToWrite + sizeof(DWORD) ,NULL,FILE_BEGIN);
SetEndOfFile(hFileToWrite);
CloseHandle(hFileToWrite);
40.ZIP解压缩
//www.zlib.net
/*
#ifdef _DEBUG
#pragma comment(lib,"zlibd.lib")
#else
#pragma comment(lib,"zlib.lib")
#endif
#include "zlib.h"
#include "zconf.h"
*/
HANDLE hFile, hFileToWrite;
CString strFilePath=%%1;
//打开要进行解压缩的文件
hFile = CreateFile(strFilePath, // file name
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // no security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL
); // no attr. template
if (hFile == INVALID_HANDLE_VALUE)
{
AfxMessageBox("Could not open file to read"); // process error
return;
}
HANDLE hMapFile, hMapFileToWrite;
//创建一个文件映射
hMapFile = CreateFileMapping(hFile, // Current file handle.
NULL, // Default security.
PAGE_READONLY, // Read/write permission.
0, // Max. object size.
0, // Size of hFile.
"ZipTestMappingObjectForRead"); // Name of mapping object.
if (hMapFile == NULL)
{
AfxMessageBox("Could not create file mapping object");
return;
}
LPVOID lpMapAddress, lpMapAddressToWrite;
//创建一个文件映射的视图用来作为source
lpMapAddress = MapViewOfFile(hMapFile, // Handle to mapping
object.FILE_MAP_READ, // Read/write permission
0, // Max. object size.
0, // Size of hFile.
0); // Map entire file.
if (lpMapAddress == NULL)
{
AfxMessageBox("Could not map view of file");
return;
}
DWORD dwFileLength,dwFileLengthToWrite;
dwFileLength = GetFileSize(hFile, NULL) - sizeof(DWORD);
//因为压缩函数的输出缓冲必须比输入大0.1% + 12 然后一个DWORD用来保存压缩前的大小,
// 解压缩的时候用,当然还可以保存更多的信息,这里用不到
// dwFileLengthToWrite = (double)dwFileLength*1.001 + 12 +sizeof(DWORD);
dwFileLengthToWrite = (*(DWORD*)lpMapAddress);
LPVOID pSourceBuf = lpMapAddress;
pSourceBuf = (DWORD*)pSourceBuf + 1;
//以下是创建一个文件,用来保存压缩后的文件
hFileToWrite = CreateFile(%%2, // create demo.gz
GENERIC_WRITE|GENERIC_READ, // open for writing
0, // do not share
NULL, // no security
CREATE_ALWAYS, // overwrite existing
FILE_ATTRIBUTE_NORMAL , // normal file
NULL
); // no attr. template
if (hFileToWrite == INVALID_HANDLE_VALUE)
{
AfxMessageBox("Could not open file to write"); //process error
return;
}
hMapFileToWrite = CreateFileMapping(hFileToWrite, // Currentfile handle.
NULL, // Default security.
PAGE_READWRITE, // Read/write permission.
0, // Max. object size.
dwFileLengthToWrite, // Size of hFile.
"ZipTestMappingObjectForWrite"); // Name of mapping object.
if (hMapFileToWrite == NULL)
{
AfxMessageBox("Could not create file mapping object for write");
return;
}
lpMapAddressToWrite = MapViewOfFile(hMapFileToWrite, //Handle to mapping object.
FILE_MAP_WRITE, // Read/write permission
0, // Max. object size.
0, // Size of hFile.
0
); // Map entire file.
if (lpMapAddressToWrite == NULL)
{
AfxMessageBox("Could not map view of file");
return;
}
//这里是将压缩前的大小保存在文件的第一个DWORD里面
LPVOID pBuf = lpMapAddressToWrite;
//这里就是最重要的,zlib里面提供的一个方法,将源缓存的数据压缩至目的缓存
//原形如下:
//int compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
//参数destLen返回实际压缩后的文件大小。
uncompress((Bytef*)pBuf,&dwFileLengthToWrite, (Bytef*)pSourceBuf, dwFileLength);
UnmapViewOfFile(lpMapAddress);
CloseHandle(hMapFile);
CloseHandle(hFile);
UnmapViewOfFile(lpMapAddressToWrite);
CloseHandle(hMapFileToWrite);
//这里将文件大小重新设置一下
SetFilePointer(hFileToWrite,dwFileLengthToWrite,NULL,FILE_BEGIN);
SetEndOfFile(hFileToWrite);
CloseHandle(hFileToWrite);
41.获得应用程序完整路径
char appName[MAX_PATH];
GetModuleFileName(NULL,appName,MAX_PATH);
CString %%1(appName);
42.递归删除目录中的文件
CString Directory(%%1);
CStringArray csa;
int count=0;
if(Directory.Right(1)!="//")
Directory+="//";
Directory+="*.*";
CFileFInd FFile;
csa.add(Directory);
while(count<csa.GetSize())
{
if(FFile.FindFile(csa.GetAt(i)))
{
bFound=FFile.FindNextFile();
if(!FFile.IsDirectory() && !FFile.IsDots())
{
DeleteFile(FFile.GetFilePath());
}
else if(FFile.IsDirectory())
{
csa.Add(FilePath+"//*.*");
}
}
else
count++;
}
43.ZIP压缩文件夹
//www.zlib.net
/*
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <dos.h>
#include <direct.h>
#include <zlib.h>
#if defined(MSDOS) || defined(OS2) || defined(WIN32) ||
defined(__CYGWIN__)
# include <fcntl.h>
# include <io.h>
# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
#else
# define SET_BINARY_MODE(file)
#endif
#define CHUNK 16384
//#define USE_TAG
#ifdef USE_TAG
#define COMPRESS_FILE_TAG_HEAD "<<<"
#define COMPRESS_FILE_TAG_TAIL ">>>"
#define COMPRESS_FILE_TAG_END_LEN 3 // must be strlen
(COMPRESS_FILE_TAG_HEAD) = strlen(COMPRESS_FILE_TAG_TAIL)
#else
#define COMPRESS_FILE_TAG_HEAD ""
#define COMPRESS_FILE_TAG_TAIL ""
#define COMPRESS_FILE_TAG_END_LEN 0 // must be strlen
(COMPRESS_FILE_TAG_HEAD) = strlen(COMPRESS_FILE_TAG_TAIL)
#endif
*/
/**//**//**//* Compress from file source to file dest until EOF on source.
def() returns Z_OK on success, Z_MEM_ERROR if emory could not be allocated for processing, Z_STREAM_ERROR if an invalid compression
level is supplied, Z_VERSION_ERROR if the version of zlib. And the version of the library linked do not matc, or Z_ERRNO if there isan error reading or writing the files. */
static it def(FILE *source, FILE *dest, int level)
int ret, flush;
unsigned have;
z_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
/**//**//**//* allocate deflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit(&strm, level);
if (ret != Z_OK)
return ret;
/**//**//**//* compress until end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source);
if (ferror(source)) {
(void)deflateEnd(&strm);
return Z_ERRNO;
}
flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
strm.next_in = in;
/**//**//**//* run deflate() on input until output
buffer not full, finish
compression if all of source has been read in */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = deflate(&strm, flush); /**//**//**//* no
bad return value */
assert(ret != Z_STREAM_ERROR); /**//**//**//*
state not clobbered */
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror
(dest)) {
(void)deflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0);
assert(strm.avail_in == 0); /**//**//**//* all
input will be used */
/**//**//**//* done when last data in file processed
*/
} while (flush != Z_FINISH);
assert(ret == Z_STREAM_END); /**//**//**//* stream
will be complete */
/**//**//**//* clean up and return */
(void)deflateEnd(&strm);
return Z_OK;
}
/**//**//**//* Decompress from file source to file dest until stream ends or EOF. inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be allocated for processing, Z_DATA_ERROR if the deflate data is invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and the version of the library linked do not match, or Z_ERRNO
if there is an error reading or writing the files. */
static int inf(FILE *source, FILE *dest)
{
int ret;
unsigned have;
z_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
/**//**//**//* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if (ret != Z_OK)
return ret;
/**//**//**//* decompress until deflate stream ends or end
of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source);
if (ferror(source)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
if (strm.avail_in == 0)
break;
strm.next_in = in;
/**//**//**//* run inflate() on input until output
buffer not full */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR); /**//**//**//*
state not clobbered */
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /**//**//**//* and
fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror
(dest)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0);
/**//**//**//* done when inflate() says it's done */
} while (ret != Z_STREAM_END);
/**//**//**//* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
/**//**//**//* report a zlib or i/o error */
static void zerr(int ret)
{
fputs("zpipe: ", stderr);
switch (ret) {
case Z_ERRNO:
if (ferror(stdin))
fputs("error reading stdin ", stderr);
if (ferror(stdout))
fputs("error writing stdout ", stderr);
break;
case Z_STREAM_ERROR:
fputs("invalid compression level ", stderr);
break;
case Z_DATA_ERROR:
fputs("invalid or incomplete deflate data ", stderr);
break;
case Z_MEM_ERROR:
fputs("out of memory ", stderr);
break;
case Z_VERSION_ERROR:
fputs("zlib version mismatch! ", stderr);
}
}
// 以上就是zpipe.c的几个主要函数:def()、inf()和zerr(),def()是压缩函数,主要使用了zlib的deflate()接口;inf()是压缩函数,主要使用了zlib的inflate()接口;zerr()是错误打印函数。
static int write_zfile_file_header(const char *file,FILE *zfile)
{
int len;
len = strlen(file);
if (fwrite(COMPRESS_FILE_TAG_HEAD, 1,COMPRESS_FILE_TAG_END_LEN, zfile) != COMPRESS_FILE_TAG_END_LEN || ferror(zfile))
{
fprintf(stderr,"When writing file or dir header to zfile: write error. ");
return 1;
}
if (fwrite(file, 1, len, zfile) != len|| ferror(zfile))
{
fprintf(stderr,"When writing file or dir header to zfile: write error. ");
return 1;
}
if (fwrite(COMPRESS_FILE_TAG_TAIL, 1,COMPRESS_FILE_TAG_END_LEN, zfile) != COMPRESS_FILE_TAG_END_LEN || ferror(zfile))
{
fprintf(stderr,"When writing file or dir header to
zfile: write error. ");
return 1;
}
return 0;
}
/**//* compress or decompress from stdin to stdout */
static int compress_dir(char *file_in,FILE *fd_out)
{
FILE *fd_in;
struct _finddata_t find_data;
char file[128];
long lf;
int ret;
write_zfile_file_header(file_in,fd_out);
sprintf(file,"%s%s",file_in,"/*");
if((lf = _findfirst(file,&find_data))==-1l) // LOOKOUT:not eleven, but one and lowercase 'L'
{
fprintf(stdout,"file not found. ");
}
else
{
do
{
if(!strcmp(find_data.name,".") || !strcmp(find_data.name,".."))
continue;
fprintf(stdout,"%s",find_data.name);
sprintf(file,"%s%s%s",file_in,"/",find_data.name);
if(find_data.attrib & _A_SUBDIR)
{
fprintf(stdout," ---directory--- ");
ret = compress_dir(file,fd_out);
}
else
{
write_zfile_file_header(file,fd_out);
if(access(file, 2) != 0) //W_OK=2
{
int attrib;
attrib = _chmod(file,0);
_chmod(file,1,attrib & ~_A_RDONLY);
fprintf(stderr,"When writing file: No privilege to write file %s. ",file);
return -1;
}
fd_in = fopen(file,"rb+");
SET_BINARY_MODE(fd_in);
ret = def(fd_in, fd_out,Z_DEFAULT_COMPRESSION);
if (ret != Z_OK)
zerr(ret);
else
fprintf(stdout," zip over ");
fclose(fd_in);
}
}while( _findnext(lf, &find_data ) == 0 );
}
return 0;
}
//int argc, char **argv
struct _finddata_t find_data;
FILE *fd_in;
FILE *fd_out;
const char *file_dir;
char file_out[100];
int ret;
if (argc == 2)
{
file_dir = argv[1];
if(_findfirst(file_dir,&find_data)==-1l) //LOOKOUT: not eleven, but one and lowercase 'L'
{
fprintf(stderr,"File or dir %s not found.",file_dir);
return 1;
}
if(find_data.attrib & _A_SUBDIR)
{
sprintf(file_out,"%s%s",file_dir,".z");
fd_out = fopen(file_out,"wb+");
SET_BINARY_MODE(fd_out);
fprintf(stdout,"Dir %s being Compressed ...",file_dir);
ret = compress_dir(file_dir,fd_out);
fclose(fd_out);
}
else
{
fprintf(stdout,"File %s being Compressed ...",file_dir);
sprintf(file_out,"%s%s",file_dir,".z");
fd_in = fopen(file_dir,"rb+");
fd_out = fopen(file_out,"wb+");
SET_BINARY_MODE(fd_in);
SET_BINARY_MODE(fd_out);
ret = def(fd_in, fd_out, Z_DEFAULT_COMPRESSION);
fclose(fd_in);
fclose(fd_out);
}
if (ret != 0)
{
fprintf(stderr,"Compress Error !!!!!!!!!!!!!! ");
zerr(ret);
}
else
fprintf(stdout,"Compress OK--------------- ");
}
else {
fprintf(stdout,"zod usage: zod [file]/[directory] ");
}
getch();
44.验证DTD
/*
#include <stdexcept> // runtime_error
#include <xercesc/sax2/DefaultHandler.hpp>
*/
using namespace std;
using namespace xercesc;
try {
// Initialize Xerces and obtain a SAX2 parser
XercesInitializer init;
auto_ptr<SAX2XMLReader>
parser(XMLReaderFactory::createXMLReader());
// Enable validation
parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
// Register error handler to receive notifications
// of DTD violations
CircusErrorHandler error;
parser->setErrorHandler(&error);
parser->parse("animals.xml");
} catch (const SAXException& e) {
cout << "xml error: " << toNative(e.getMessage()) << "/n";
return EXIT_FAILURE;
} catch (const XMLException& e) {
cout << "xml error: " << toNative(e.getMessage()) << "/n";
return EXIT_FAILURE;
} catch (const exception& e) {
cout << e.what() << "/n";
return EXIT_FAILURE;
}
45.Schema 验证
/*
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/sax2/DefaultHandler.hpp>
Handy definitions of constants.
#include <xercesc/util/XMLUni.hpp>
Create a SAX2 parser object.
*/
SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();
// Set the appropriate features on the parser. Enable namespaces, schema validation, and the checking of all Schema constraints. We refer to these as "common features" in following examples.
parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
parser->setFeature(XMLUni::fgXercesDynamic, false);
parser->setFeature(XMLUni::fgXercesSchema, true);
parser->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
// Set appropriate ContentHandler, ErrorHandler, and EntityResolver.
// These will be referred to as "common handlers" in subsequent examples.
// You will use a default handler provided by Xerces-C++ (no op action).
// Users should write their own handlers and install them.
DefaultHandler handler;
parser->setContentHandler(&handler);
// The object parser calls when it detects violations of the schema.
parser->setErrorHandler(&handler);
// The object parser calls to find the schema and
// resolve schema imports/includes.
parser->setEntityResolver(&handler);
// Parse the XML document.
// Document content sent to registered ContentHandler instance.
parser->parse(xmlFile);
// Delete the parser instance.
delete parser;
46.Grep
/*
#include<string>
#include "regexpr2.h"
using namespace std;
using namespace regex;
*/
match_results results;
rpattern pat(%%2);
char sRead[5120];
CFile mFile(_T(%%1),CFile::modeRead);
CString content;
while(sRead!=NULL)
{
mFile.Read(sRead,5120);
content+=CString(sRead);
}
mFile.Close();
CString line;
CString sub;
char seperator='/n';
for(int pos=0;AfxExtractSubString(line,content,pos,seperator);++pos)
{
if(line.Trim()!="")
{
string str(line);
match_results::backref_type br=pat.match(str,results);
if(br.matched){
//br
}
}
}
/*
//+---------------------------------------------------------------------------
//
// Copyright ( C ) Microsoft, 1994 - 2002.
//
// File: restack.h
//
// Functions: a quick-'n'-dirty, type-unsafe stack used by the iterative
// regular expression algorithm
//
// Notes: Care must be taken when using this stack. You must pop off
// the correct type of object, otherwise you get garbage. Also,
// if you push anything that has a non-trivial destructor, then
// be sure to explicitely pop everything off the stack and don't
// use the unsafe_long_jump method.
//
// Author: Eric Niebler ( [email protected] )
//
// History: 11/15/2001 ericne Created
//
//----------------------------------------------------------------------------
#ifndef HETERO_STACK_H
#define HETERO_STACK_H
#include <string>
#include <utility>
#include <typeinfo>
#include <stdexcept>
#include <functional>
#ifndef REGEX_CDECL
#ifdef _MSC_VER
#define REGEX_CDECL __cdecl
#else
#define REGEX_CDECL
#endif
#endif
#define COMMA ,
#if !defined(_MSC_VER) | 1200 < _MSC_VER
# define REGEX_VC6(x)
# define REGEX_NVC6(x) x
#else
# define REGEX_VC6(x) x
# define REGEX_NVC6(x)
#endif
namespace regex
{
namespace detail
{
// For compile-time assertions that generate
// no run-time overhead.
template< bool f > struct static_assert;
template<> struct static_assert<true> { static_assert() {} };
// Work-around for a template-template parameter problem on VC7.0
template< typename T > struct type2type { typedef T type; };
template< bool F > struct bool2type { enum { value = F }; };
typedef bool2type<true> true_t;
typedef bool2type<false> false_t;
#ifdef _MSC_VER
// warning C4127: conditional expression is constant
// warning C4189: local variable is initialized but not referenced
// warning C4244: conversion from 'T' to 'int', possible loss of data
// warning C4510: default constructor could not be generated
// warning C4610: struct can never be instantiated - user defined constructor required
// warning C4800: forcing value to bool 'true' or 'false' (performance warning)
#pragma warning( push )
#pragma warning( disable : 4127 4189 4244 4510 4610 4800 )
// Make sure nobody has tampered with the packing before defining the
// alignof structure
#pragma pack( push )
#pragma pack() // use the default packing
#endif
template< typename T >
class alignof
{
struct helper
{
helper();
char m_c;
T m_t;
};
public:
enum { value = sizeof(helper)-sizeof(T) < sizeof(T) ? sizeof(helper)-sizeof(T) : sizeof(T) };
};
#ifdef _MSC_VER
#pragma pack( pop )
#endif
//
// Type traits
//
typedef char (&yes_type)[1];
typedef char (&no_type)[2];
template< bool >
struct select_helper
{
template< typename T, typename U >
struct nested
{
typedef T type;
};
};
template<>
struct select_helper<false>
{
template< typename T, typename U >
struct nested
{
typedef U type;
};
};
// For use in conditional typedefs
template< bool F, typename T, typename U >
struct select
{
typedef typename select_helper<F>::template nested<T,U>::type type;
};
template< typename U >
struct convertible_helper
{
static yes_type check( U );
static no_type REGEX_CDECL check(...);
};
template< typename T >
struct factory
{
static T& make();
};
template< typename T, typename U >
struct is_convertible
{
enum { value = (sizeof(convertible_helper<U>::check(factory<T>::make()))==sizeof(yes_type)) };
};
template< size_t N >
struct is_power_of_two
{
enum { value = 1==N || 0==(N%2) && is_power_of_two<N/2>::value };
};
template<>
struct is_power_of_two<0>
{
enum { value = false };
};
// Very primative implementation of is_scalar. This doesn't work
// for void, reference types, array types or function types, but
// we don't use those types from hetero_stack.
struct bool_convertible { bool_convertible(bool); };
template< typename T >
struct is_scalar
{
enum { value = is_convertible<T,bool_convertible>::value };
};
template< typename T >
struct has_trivial_copy
{
enum { value = is_scalar<T>::value };
};
template< typename T >
struct has_trivial_assignment
{
enum { value = is_scalar<T>::value };
};
template< typename T >
struct has_trivial_destructor
{
enum { value = is_scalar<T>::value };
};
template< bool > struct destroyer_helper
{
template< typename T >
static void destroy( T const * pT )
{
pT, pT->~T();
}
};
template<> struct destroyer_helper<true>
{
template< typename T >
static void destroy( T const * )
{
}
};
template< typename T >
void destroy( T const * pT )
{
destroyer_helper<has_trivial_destructor<T>::value>::destroy( pT );
}
struct type_vtable
{
std::type_info const * typeinfo_ptr;
size_t size;
size_t aligned_size;
void (*destroy)( void * );
void (*copy)( void *, void const * );
};
template< typename T, size_t AlignmentT >
class type_info_ex
{
static void destroy( void * pv )
{
T const * pT = static_cast<T const*>( pv );
regex::detail::destroy( pT );
(void)pv;
(void)pT;
}
static void copy( void * dst, void const * src )
{
new ( dst ) T( *static_cast<T const *>( src ) );
}
public:
static type_vtable const vtable;
static bool equals( type_vtable const * ptm )
{
return ptm == & vtable || *ptm->typeinfo_ptr == typeid(T);
}
};
template< typename T,size_t AlignmentT >
type_vtable const type_info_ex<T,AlignmentT>::vtable =
{
&typeid(T),
sizeof(T),
( sizeof(T) + AlignmentT - 1 ) & ~( AlignmentT - 1 ),
has_trivial_destructor<T>::value ? 0 : &type_info_ex<T,AlignmentT>::destroy,
&type_info_ex<T,AlignmentT>::copy
};
template< typename T >
inline T & to_type( void * pv )
{
return *static_cast<T*>( pv );
}
} // namespace detail
// --------------------------------------------------------------------------
//
// Class: hetero_stack
//
// Description: Fast, heterogeneous stack.
//
// Methods: allocate - reserve space on stack
// unwind - unwind the stack
// hetero_stack - c'tor
// ~hetero_stack - d'tor, release all dynamic memory
// push - push an object on the stack
// pop - pop an object from the stack
//
// Members: m_first_node -
// m_current_node -
//
// Typedefs: byte_t -
//
// History: 10/19/2001 - ericne - Created
//
// --------------------------------------------------------------------------
template
<
size_t AlignmentT = sizeof(void*),
bool RuntimeTypeCheckT = true, // should we perform run-time type checking?
bool AssumePodT = false, // assume non-throwing copy/assign/destroy for better perf
size_t DynamicBlockSizeT = 4096, // blocks allocated from heap are this size
size_t StaticBlockSizeT = 1024 // initial block on stack is this size
>
class hetero_stack
{
typedef unsigned char byte_t;
typedef detail::type_vtable const* vtable_ptr;
public:
typedef hetero_stack<AlignmentT,RuntimeTypeCheckT,AssumePodT,DynamicBlockSizeT,StaticBlockSizeT> stack_type;
template< typename T >
struct aligned_sizeof
{
enum
{
// round up sizeof(T) to the nearest multiple of AlignmentT
no_rtti = ( sizeof( T ) + AlignmentT - 1 ) & ~( AlignmentT - 1 ),
with_rtti = RuntimeTypeCheckT ?
no_rtti + aligned_sizeof<vtable_ptr>::no_rtti :
no_rtti
};
};
private:
struct stack_node
{
struct header
{
stack_node * m_back;
stack_node * m_next;
byte_t * m_current; // ptr into m_mem. alloc from here
byte_t * m_end; // ptr to last+1 byte_t in m_mem
};
union
{
header m_head;
byte_t m_align[ aligned_sizeof<header>::no_rtti ];
};
// This is the buffer into which values will be pushed and popped.
// It is guaranteed to meet the AlignmentT requirements because of
// the union above.
byte_t m_mem[1];
size_t size() const // throw()
{
return static_cast<size_t>( m_head.m_end - m_mem );
}
};
enum
{
DYNAMIC_BLOCK_SIZE =
DynamicBlockSizeT > sizeof( stack_node ) ?
DynamicBlockSizeT : sizeof( stack_node )
};
union
{
stack_node m_node;
byte_t m_buf[ aligned_sizeof<stack_node::header>::no_rtti + StaticBlockSizeT ];
} m_first_node;
stack_node * m_current_node;
// Cache these for faster access
byte_t * m_begin;
byte_t * m_current;
byte_t * m_end;
byte_t * grow( size_t size ) // throw(std::bad_alloc)
{
// write the cached value of current into the node.
// OK to do this even if later statements throw.
m_current_node->m_head.m_current = m_current;
// Do we have a node with available memory already?
if( m_current_node->m_head.m_next )
{
// Does this node have enough room?
if( size <= m_current_node->m_head.m_next->size() )
{
m_current_node = m_current_node->m_head.m_next;
m_current = m_current_node->m_head.m_current = m_current_node->m_mem + size;
m_end = m_current_node->m_head.m_end;
return m_begin = m_current_node->m_mem;
}
// Create a new node and insert it into the list
stack_node * new_node = static_cast<stack_node*>(
::operator new( size + offsetof( stack_node, m_mem ) ) );
new_node->m_head.m_back = m_current_node;
new_node->m_head.m_next = m_current_node->m_head.m_next;
m_current = m_end = new_node->m_head.m_current =
new_node->m_head.m_end = new_node->m_mem + size;
m_current_node->m_head.m_next->m_head.m_back = new_node;
m_current_node->m_head.m_next = new_node;
m_current_node = new_node;
return m_begin = m_current_node->m_mem;
}
// We need to create a new node from scratch
size_t new_size = detail::regex_max( size,
static_cast<size_t>(DYNAMIC_BLOCK_SIZE) - offsetof( stack_node, m_mem ) );
stack_node * new_node = static_cast<stack_node*>(
::operator new( new_size + offsetof( stack_node, m_mem ) ) );
new_node->m_head.m_back = m_current_node;
new_node->m_head.m_next = 0;
m_current = new_node->m_head.m_current = new_node->m_mem + size;
m_end = new_node->m_head.m_end = new_node->m_mem + new_size;
m_current_node->m_head.m_next = new_node;
m_current_node = new_node;
return m_begin = m_current_node->m_mem;
}
byte_t * allocate( size_t size ) // throw(std::bad_alloc)
{
// This is the ptr to return
byte_t * mem = m_current;
// Advance the high-water mark
m_current += size;
// Check to see if we have overflowed this buffer
if( std::less<void*>()( m_end, m_current ) ) // if( m_end < m_current )
{
// oops, back this out.
m_current = mem;
// allocate a new block and return a ptr to the new memory
return grow( size );
}
return mem;
}
byte_t * unwind( byte_t * pb ) // throw()
{
// roll back the stack
m_current = pb;
// If we've unwound this whole block, then make the
// previous node the current node
if( m_current == m_begin )
{
// write the cached value of m_current into m_current_node
m_current_node->m_head.m_current = m_current;
m_current_node = m_current_node->m_head.m_back;
// update the cache
m_begin = m_current_node->m_mem;
m_current = m_current_node->m_head.m_current;
m_end = m_current_node->m_head.m_end;
}
return pb;
}
byte_t * unwind( size_t size ) // throw()
{
return unwind( m_current - size );
}
void long_jump_impl( void * jump_ptr, detail::bool2type<true> ) // throw()
{
safe_long_jump( jump_ptr );
}
void long_jump_impl( void * jump_ptr, detail::bool2type<false> ) // throw()
{
unsafe_long_jump( jump_ptr );
}
struct real_unwinder;
friend struct real_unwinder;
struct real_unwinder
{
real_unwinder( stack_type * pstack, size_t size ) // throw()
: m_pstack(pstack), m_size(size) {}
~real_unwinder() // throw()
{
if( m_pstack )
m_pstack->unwind( m_size );
}
void dismiss() // throw()
{
m_pstack = 0;
}
private:
real_unwinder( real_unwinder const & );
real_unwinder & operator=( real_unwinder const & );
stack_type * m_pstack;
size_t m_size;
};
struct dummy_unwinder
{
dummy_unwinder( stack_type *, size_t ) {} // throw()
void dismiss() {} // throw()
};
// Disallow these for now. Might implement them later.
hetero_stack( hetero_stack const & );
hetero_stack & operator=( hetero_stack const & );
public:
class type_error : public std::logic_error
{
std::type_info const * m_prequested_type;
std::type_info const * m_pactual_type;
public:
type_error
(
std::type_info const & requested_type,
std::type_info const & actual_type,
std::string const & s = "type error in hetero_stack"
) // throw()
: std::logic_error( s + " (requested type: " + requested_type.name()
+ ", actual type: " + actual_type.name() + ")" )
, m_prequested_type( &requested_type )
, m_pactual_type( &actual_type )
{
}
std::type_info const & requested_type() const // throw()
{
return *m_prequested_type;
}
std::type_info const & actual_type() const // throw()
{
return *m_pactual_type;
}
};
hetero_stack() // throw()
: m_current_node( &m_first_node.m_node )
{
m_first_node.m_node.m_head.m_back = & m_first_node.m_node;
m_first_node.m_node.m_head.m_next = 0;
m_begin = m_current = m_first_node.m_node.m_head.m_current = m_first_node.m_node.m_mem;
m_end = m_first_node.m_node.m_head.m_end = m_first_node.m_buf + sizeof( m_first_node );
}
~hetero_stack() // throw()
{
// AlignmentT must be a power of two
detail::static_assert< detail::is_power_of_two<AlignmentT>::value > const align_test;
// Call any destructors for objects still on the stack
if( RuntimeTypeCheckT && ! AssumePodT )
{
long_jump( m_first_node.m_node.m_mem );
}
// delete all the memory blocks
m_current_node = m_first_node.m_node.m_head.m_next;
for( stack_node * next_node; m_current_node; m_current_node = next_node )
{
next_node = m_current_node->m_head.m_next;
::operator delete( static_cast<void*>( m_current_node ) );
}
}
template< typename T >
inline void push( T const & t ) // throw(std::bad_alloc,...)
{
// Make sure that the alignment for type T is not worse
// than our declared alignment.
detail::static_assert<( AlignmentT >= detail::alignof<T>::value )> const align_test;
static_cast<void>(align_test);
// If T won't throw in copy c'tor then we don't need to use an unwinder object.
typedef typename detail::select< AssumePodT || detail::has_trivial_copy<T>::value,
dummy_unwinder, real_unwinder >::type unwinder;
// If this throws, it doesn't change state,
// so there is nothing to roll back.
byte_t * pb = allocate( aligned_sizeof<T>::with_rtti );
// Rolls back the allocate if later steps throw
// BUGBUG we can do the alloc, but not update m_current until after
// the copy c'tor to avoid the need for an unwinder object
unwinder guard( this, aligned_sizeof<T>::with_rtti );
new ( pb ) T( t ); // Could throw if ! has_trivial_copy<T>::value
// If we are debugging the stack, then push a pointer to the type_info
// for this type T. It will be checked in pop().
if( RuntimeTypeCheckT )
{
detail::to_type<vtable_ptr>( pb + aligned_sizeof<T>::no_rtti ) = & detail::type_info_ex<T,AlignmentT>::vtable;
}
// ok, everything succeeded -- dismiss the guard
guard.dismiss();
}
template< typename T >
inline void pop( T & t ) // throw(...)
{
detail::static_assert<( AlignmentT >= detail::alignof<T>::value )> const align_test;
static_cast<void>(align_test);
// If we are debugging the stack, then in push() we pushed a pointer
// to the type_info struct for this type T. Check it now.
if( RuntimeTypeCheckT )
{
byte_t * pti = m_current - aligned_sizeof<vtable_ptr>::no_rtti;
if( ! detail::type_info_ex<T,AlignmentT>::equals( detail::to_type<vtable_ptr>( pti ) ) )
throw type_error( typeid( T ), *detail::to_type<vtable_ptr>( pti )->typeinfo_ptr );
}
// Don't change state yet because assignment op could throw!
byte_t * pT = m_current - aligned_sizeof<T>::with_rtti;
t = detail::to_type<T const>( pT ); // could throw
T const & ref = detail::to_type<T const>( pT );
regex::detail::destroy( &ref );
unwind( pT );
}
// Call this version of pop when you don't need the popped value
template< typename T >
inline void pop( REGEX_VC6(detail::type2type<T> COMMA int) ) // throw(type_error,...)
{
detail::static_assert<( AlignmentT >= detail::alignof<T>::value )> const align_test;
static_cast<void>(align_test);
// If we are debugging the stack, then in push() we pushed a pointer
// to the type_info struct for this type T. Check it now.
if( RuntimeTypeCheckT )
{
byte_t * pti = m_current - aligned_sizeof<vtable_ptr>::no_rtti;
if( ! detail::type_info_ex<T,AlignmentT>::equals( detail::to_type<vtable_ptr>( pti ) ) )
throw type_error( typeid( T ), *detail::to_type<vtable_ptr>( pti )->typeinfo_ptr );
}
byte_t * pv = unwind( aligned_sizeof<T>::with_rtti );
T const & ref = detail::to_type<T const>( pv );
regex::detail::destroy( &ref );
}
// Call this version of pop when you don't need the popped value and
// throwing an exception isn't an option
template< typename T >
inline bool pop( std::nothrow_t const & ) // throw()
{
detail::static_assert<( AlignmentT >= detail::alignof<T>::value )> const align_test;
static_cast<void>(align_test);
// If we are debugging the stack, then in push() we pushed a pointer
// to the type_info struct for this type T. Check it now.
if( RuntimeTypeCheckT )
{
byte_t * pti = m_current - aligned_sizeof<vtable_ptr>::no_rtti;
if( ! detail::type_info_ex<T,AlignmentT>::equals( detail::to_type<vtable_ptr>( pti ) ) )
return false; // type error, can't throw so bail.
}
byte_t * pv = unwind( aligned_sizeof<T>::with_rtti );
T const & ref = detail::to_type<T const>( pv );
regex::detail::destroy( &ref );
return true;
}
template< typename T >
inline T & top( REGEX_VC6(detail::type2type<T>) ) const // throw(type_error,...)
{
detail::static_assert<( AlignmentT >= detail::alignof<T>::value )> const align_test;
static_cast<void>(align_test);
if( RuntimeTypeCheckT )
{
// If we are debugging the stack, then the top of the stack is a
// pointer to a type_info struct. Assert that we have the correct type.
byte_t * pti = m_current - aligned_sizeof<vtable_ptr>::no_rtti;
if( ! detail::type_info_ex<T,AlignmentT>::equals( detail::to_type<vtable_ptr>( pti ) ) )
throw type_error( typeid( T ), *detail::to_type<vtable_ptr>( pti )->typeinfo_ptr );
}
byte_t * pT = m_current - aligned_sizeof<T>::with_rtti;
return detail::to_type<T>( pT );
}
// Fetch the type_info for the element at the top of the stack
std::type_info const & top_type() const // throw()
{
detail::static_assert< RuntimeTypeCheckT > const type_check;
static_cast<void>(type_check);
byte_t * pti = m_current - aligned_sizeof<vtable_ptr>::no_rtti;
return *detail::to_type<vtable_ptr>( pti )->typeinfo_ptr;
}
// Get a pointer to the top of the stack
void * set_jump() const // throw()
{
return m_current;
}
// Quick and dirty stack unwind. Does not call destructors.
void unsafe_long_jump( void *const jump_ptr ) // throw()
{
for( ;; )
{
if( std::less<void*>()( jump_ptr, m_current_node->m_mem ) ||
std::less<void*>()( m_current_node->m_head.m_end, jump_ptr ) )
{
m_current_node->m_head.m_current = m_current_node->m_mem;
m_current_node = m_current_node->m_head.m_back;
}
else
{
m_begin = m_current_node->m_mem;
m_current = m_current_node->m_head.m_current = static_cast<byte_t*>( jump_ptr );
m_end = m_current_node->m_head.m_end;
return;
}
}
}
// Safe long jump; does call destructors if RuntimeTypeCheckT is true.
void safe_long_jump( void *const jump_ptr ) // throw()
{
detail::static_assert< RuntimeTypeCheckT > const type_check;
static_cast<void>(type_check);
while( m_current != jump_ptr )
{
// The top of the stack is a pointer to a type_vtable struct.
m_current -= aligned_sizeof<vtable_ptr>::no_rtti;
vtable_ptr pvtable = detail::to_type<vtable_ptr>( m_current );
// find the start of the object
m_current -= pvtable->aligned_size;
// call the destructor for T
if( pvtable->destroy )
{
pvtable->destroy( m_current );
}
// move to the previous buffer if necessary
if( m_current == m_begin && m_current != jump_ptr )
{
m_current_node->m_head.m_current = m_current;
m_current_node = m_current_node->m_head.m_back;
m_begin = m_current_node->m_mem;
m_current = m_current_node->m_head.m_current;
m_end = m_current_node->m_head.m_end;
}
}
}
// Stack unwind. If RuntimeTypeCheckT && !AssumePodT, then destructors
// are called. Otherwise they are not.
void long_jump( void * jump_ptr ) // throw()
{
long_jump_impl( jump_ptr, detail::bool2type<RuntimeTypeCheckT && !AssumePodT>() );
}
struct stack_guard
{
stack_type * m_ps;
void * m_jump_ptr;
explicit stack_guard( stack_type * ps )
: m_ps( ps )
, m_jump_ptr( ps->set_jump() )
{
}
~stack_guard()
{
m_ps->long_jump( m_jump_ptr );
}
};
bool empty() const // throw()
{
return m_current == m_first_node.m_node.m_mem;
}
// Use scoped_push for automatically pushing/popping
// things to and from the stack. This is especially useful
// if you want to push a bunch of things "atomically". For
// instance:
//
// typedef hetero_stack<>::scoped_pop scoped_pop;
// scoped_pop p1 = stack.scoped_push( int(1) ); // could throw
// scoped_pop p2 = stack.scoped_push( std::string("foo") ); // could throw
// stack.push( float(3.14159) ); // could throw
// p2.dismiss(); // ok, nothing threw, so ...
// p1.dismiss(); // ... dismiss the scoped_pops
//
// If p2 and p1 are not dismissed, as in the case when an
// exception gets thrown, then they automatically pop their
// arguments from the stack.
class scoped_pop_base
{
scoped_pop_base & operator=( scoped_pop_base const & ); // disallow assignment
protected:
mutable stack_type * m_pstack;
explicit scoped_pop_base( stack_type * pstack ) // throw(std::bad_alloc,...)
: m_pstack( pstack )
{
}
scoped_pop_base( scoped_pop_base const & right ) // throw() // destructive copy
: m_pstack( right.m_pstack )
{
right.dismiss();
}
public:
void dismiss() const // throw()
{
m_pstack = 0;
}
};
template< typename T >
class scoped_pop_t : public scoped_pop_base
{
scoped_pop_t & operator=( scoped_pop_t const & ); // disallow assignment
public:
scoped_pop_t( stack_type * pstack, T const & t ) // throw(std::bad_alloc,...)
: scoped_pop_base( pstack )
{
// Note that if this throws an exception the destructor
// will not get called, which is what we want.
m_pstack->push( t );
}
~scoped_pop_t() // throw()
{
// If we own this stack space, pop it.
if( m_pstack )
m_pstack->template pop<T>( std::nothrow );
}
};
template< typename T >
scoped_pop_t<T> scoped_push( T const & t ) // throw(...)
{
return scoped_pop_t<T>( this, t );
}
typedef scoped_pop_base const & scoped_pop;
};
#ifdef _MSC_VER
#pragma warning( pop )
#endif
} // namespace regex
#endif
//+---------------------------------------------------------------------------
//
// Copyright ( C ) Microsoft, 1994 - 2002.
//
// File: syntax2.h
//
// Contents: syntax modules for regexpr
//
// Classes: perl_syntax, posix_syntax
//
// Author: Eric Niebler ( [email protected] )
//
// History: 3-29-00 ericne Created
//
//----------------------------------------------------------------------------
#ifndef SYNTAX_H
#define SYNTAX_H
#ifdef _MSC_VER
#pragma warning( push )
// warning C4786: identifier was truncated to '255' characters in the debug information
#pragma warning( disable : 4786 )
#endif
#include <map>
#include <iosfwd>
#include <string>
#include <cctype>
#include <cwctype>
#include <cassert>
#include <iterator>
#include <stdexcept>
#ifndef ARRAYSIZE
# define ARRAYSIZE( a ) (sizeof(a)/sizeof((a)[0]))
#endif
#ifndef UCHAR_MAX
# define UCHAR_MAX 0xff
#endif
#ifndef WCHAR_MAX
# define WCHAR_MAX ((wchar_t)-1)
#endif
#ifdef _MSC_VER
# include <crtdbg.h>
# define REGEX_ASSERT(x) _ASSERTE(x)
# define REGEX_FORCEINLINE __forceinline
# define REGEX_SELECTANY __declspec(selectany)
# define REGEX_CDECL __cdecl
# define REGEX_SEH_TRY __try
# define REGEX_SEH_EXCEPT(x) __except( x )
# define REGEX_RESET_STK_OFLW() _resetstkoflw()
# if 1200 < _MSC_VER
# define REGEX_NOINLINE __declspec(noinline)
# define REGEX_DEPRECATED __declspec(deprecated)
# define REGEX_DEPENDENT_TYPENAME typename
# else
# define REGEX_NOINLINE
# define REGEX_DEPRECATED
# define REGEX_DEPENDENT_TYPENAME
# endif
#else
# include <cassert>
# define REGEX_ASSERT(x) assert(x)
# define REGEX_NOINLINE
# define REGEX_FORCEINLINE inline
# define REGEX_SELECTANY
# define REGEX_CDECL
# define REGEX_SEH_TRY
# define REGEX_SEH_EXCEPT(x) if( false )
# define REGEX_RESET_STK_OFLW() ((void)0)
# define REGEX_DEPRECATED
# define REGEX_DEPENDENT_TYPENAME typename
#endif
#define REGEX_STRING(CharT,sz) (::regex::detail::literal<CharT>::string( sz, L##sz ))
#define REGEX_CHAR(CharT,ch) (static_cast<CharT>(::regex::detail::literal<CharT>::template character<ch,L##ch>::value))
#if defined(_MSC_VER) & _CPPLIB_VER <= 310
namespace std
{
template<>
struct iterator_traits< char * >
{ // get traits from iterator _Iter
typedef random_access_iterator_tag iterator_category;
typedef char value_type;
typedef ptrdiff_t difference_type;
typedef difference_type distance_type; // retained
typedef char * pointer;
typedef char & reference;
};
template<>
struct iterator_traits< char const * >
{ // get traits from iterator _Iter
typedef random_access_iterator_tag iterator_category;
typedef char value_type;
typedef ptrdiff_t difference_type;
typedef difference_type distance_type; // retained
typedef char * pointer;
typedef char & reference;
};
template<>
struct iterator_traits< wchar_t * >
{ // get traits from iterator _Iter
typedef random_access_iterator_tag iterator_category;
typedef wchar_t value_type;
typedef ptrdiff_t difference_type;
typedef difference_type distance_type; // retained
typedef wchar_t * pointer;
typedef wchar_t & reference;
};
template<>
struct iterator_traits< wchar_t const * >
{ // get traits from iterator _Iter
typedef random_access_iterator_tag iterator_category;
typedef wchar_t value_type;
typedef ptrdiff_t difference_type;
typedef difference_type distance_type; // retained
typedef wchar_t * pointer;
typedef wchar_t & reference;
};
}
#endif
namespace regex
{
class bad_regexpr : public std::invalid_argument
{
public:
explicit bad_regexpr( std::string const & s )
: std::invalid_argument( s ) {}
virtual ~bad_regexpr() throw() {}
};
//
// Flags to control how matching occurs
//
enum REGEX_FLAGS
{
NOFLAGS = 0x0000,
NOCASE = 0x0001, // ignore case
GLOBAL = 0x0002, // match everywhere in the string
MULTILINE = 0x0004, // ^ and $ can match internal line breaks
SINGLELINE = 0x0008, // . can match newline character
RIGHTMOST = 0x0010, // start matching at the right of the string
NOBACKREFS = 0x0020, // only meaningful when used with GLOBAL and substitute
FIRSTBACKREFS = 0x0040, // only meaningful when used with GLOBAL
ALLBACKREFS = 0x0080, // only meaningful when used with GLOBAL
NORMALIZE = 0x0100, // Preprocess patterns: "//n" => "/n", etc.
EXTENDED = 0x0200, // ignore whitespace in pattern
};
// For backwards compatibility
REGEX_FLAGS const noflags = NOFLAGS;
// helper functions to make it easier to combine
// the regex flags.
inline REGEX_FLAGS operator|( REGEX_FLAGS f1, REGEX_FLAGS f2 )
{
return ( REGEX_FLAGS ) ( ( unsigned )f1 | ( unsigned )f2 );
}
inline REGEX_FLAGS & operator|=( REGEX_FLAGS & f1, REGEX_FLAGS f2 )
{
return f1 = ( f1 | f2 );
}
inline REGEX_FLAGS operator&( REGEX_FLAGS f1, REGEX_FLAGS f2 )
{
return ( REGEX_FLAGS ) ( ( unsigned )f1 & ( unsigned )f2 );
}
inline REGEX_FLAGS & operator&=( REGEX_FLAGS & f1, REGEX_FLAGS f2 )
{
return f1 = ( f1 & f2 );
}
#if !defined(_MSC_VER) | 1200 < _MSC_VER
inline REGEX_FLAGS operator~( REGEX_FLAGS f )
{
return ( REGEX_FLAGS ) ~( unsigned )f;
}
#endif
//
// The following are the tokens that can be emitted by the syntax module.
// Don't reorder this list!!!
//
enum TOKEN
{
NO_TOKEN = 0,
// REGULAR TOKENS
BEGIN_GROUP,
END_GROUP,
ALTERNATION,
BEGIN_LINE,
END_LINE,
BEGIN_CHARSET,
MATCH_ANY,
ESCAPE,
// QUANTIFICATION TOKENS
ONE_OR_MORE,
ZERO_OR_MORE,
ZERO_OR_ONE,
ONE_OR_MORE_MIN,
ZERO_OR_MORE_MIN,
ZERO_OR_ONE_MIN,
BEGIN_RANGE,
RANGE_SEPARATOR,
END_RANGE,
END_RANGE_MIN,
// ESCAPE SEQUENCES
ESC_DIGIT,
ESC_NOT_DIGIT,
ESC_SPACE,
ESC_NOT_SPACE,
ESC_WORD,
ESC_NOT_WORD,
ESC_BEGIN_STRING,
ESC_END_STRING,
ESC_END_STRING_z,
ESC_WORD_BOUNDARY,
ESC_NOT_WORD_BOUNDARY,
ESC_WORD_START,
ESC_WORD_STOP,
ESC_QUOTE_META_ON,
ESC_QUOTE_META_OFF,
// SUBSTITUTION TOKENS
SUBST_BACKREF,
SUBST_PREMATCH,
SUBST_POSTMATCH,
SUBST_MATCH,
SUBST_ESCAPE,
SUBST_QUOTE_META_ON,
SUBST_UPPER_ON,
SUBST_UPPER_NEXT,
SUBST_LOWER_ON,
SUBST_LOWER_NEXT,
SUBST_ALL_OFF,
// CHARSET TOKENS
CHARSET_NEGATE,
CHARSET_ESCAPE,
CHARSET_RANGE,
CHARSET_BACKSPACE,
CHARSET_END,
CHARSET_ALNUM,
CHARSET_NOT_ALNUM,
CHARSET_ALPHA,
CHARSET_NOT_ALPHA,
CHARSET_BLANK,
CHARSET_NOT_BLANK,
CHARSET_CNTRL,
CHARSET_NOT_CNTRL,
CHARSET_DIGIT,
CHARSET_NOT_DIGIT,
CHARSET_GRAPH,
CHARSET_NOT_GRAPH,
CHARSET_LOWER,
CHARSET_NOT_LOWER,
CHARSET_PRINT,
CHARSET_NOT_PRINT,
CHARSET_PUNCT,
CHARSET_NOT_PUNCT,
CHARSET_SPACE,
CHARSET_NOT_SPACE,
CHARSET_UPPER,
CHARSET_NOT_UPPER,
CHARSET_XDIGIT,
CHARSET_NOT_XDIGIT,
// EXTENSION TOKENS
EXT_NOBACKREF,
EXT_POS_LOOKAHEAD,
EXT_NEG_LOOKAHEAD,
EXT_POS_LOOKBEHIND,
EXT_NEG_LOOKBEHIND,
EXT_INDEPENDENT,
EXT_COMMENT,
EXT_CONDITION,
EXT_RECURSE,
EXT_UNKNOWN
};
namespace detail
{
template< typename CharT > struct literal;
template<> struct literal<char>
{
static char const * string( char const * sz, wchar_t const * ) { return sz; }
template< char ch, wchar_t > struct character { enum { value = ch }; };
};
template<> struct literal<wchar_t>
{
static wchar_t const * string( char const *, wchar_t const * sz ) { return sz; }
template< char, wchar_t ch > struct character { enum { value = ch }; };
};
struct posix_charset_type
{
char const * m_szcharset;
size_t cchars;
};
extern posix_charset_type const g_rgposix_charsets[];
extern size_t const g_cposix_charsets;
template< typename IterT >
bool is_posix_charset( IterT icur, IterT iend, char const * szcharset )
{
for( ; iend != icur && char() != *szcharset; ++icur, ++szcharset )
{
if( *icur != *szcharset )
return false;
}
return char() == *szcharset;
}
// Forward-declare the class that holds all the information
// about the set of characters that can be matched by a charset
struct charset;
void free_charset( charset const * );
template< typename CharT >
struct charset_map_node
{
std::basic_string<CharT> m_str;
charset const * m_rgcharsets[2]; // 0==case, 1==nocase
charset_map_node()
{
m_rgcharsets[0] = m_rgcharsets[1] = 0;
}
charset_map_node( charset_map_node const & node )
{
*this = node;
}
charset_map_node & operator=( charset_map_node const & node )
{
m_str = node.m_str;
m_rgcharsets[0] = node.m_rgcharsets[0];
m_rgcharsets[1] = node.m_rgcharsets[1];
return *this;
}
void set( std::basic_string<CharT> const & str )
{
clear();
m_str = str;
}
void clear()
{
std::basic_string<CharT>().swap( m_str );
free_charset( m_rgcharsets[0] );
free_charset( m_rgcharsets[1] );
m_rgcharsets[0] = m_rgcharsets[1] = 0;
}
};
template< typename CharT >
class charset_map
{
std::map<CharT, charset_map_node<CharT> > m_map;
public:
typedef typename std::map<CharT, charset_map_node<CharT> >::iterator iterator;
~charset_map()
{
for( iterator iter = m_map.begin(); m_map.end() != iter; ++iter )
iter->second.clear();
}
charset_map_node<CharT> & operator[]( CharT ch ) { return m_map[ ch ]; }
iterator begin() { return m_map.begin(); }
iterator end() { return m_map.end(); }
iterator find( CharT ch ) { return m_map.find( ch ); }
void erase( iterator iter ) { m_map.erase( iter ); }
};
inline detail::charset_map<char> & get_perl_charset_map( char )
{
static detail::charset_map<char> s_charset_map;
return s_charset_map;
}
inline detail::charset_map<wchar_t> & get_perl_charset_map( wchar_t )
{
static detail::charset_map<wchar_t> s_charset_map;
return s_charset_map;
}
inline detail::charset_map<char> & get_posix_charset_map( char )
{
static detail::charset_map<char> s_charset_map;
return s_charset_map;
}
inline detail::charset_map<wchar_t> & get_posix_charset_map( wchar_t )
{
static detail::charset_map<wchar_t> s_charset_map;
return s_charset_map;
}
inline bool regex_isspace( char ch )
{
using namespace std;
return 0 != isspace( ch );
}
inline bool regex_isspace( wchar_t wch )
{
using namespace std;
return 0 != iswspace( wch );
}
template< typename T >
T const & regex_max( T const & lhs, T const & rhs )
{
return ( lhs > rhs ) ? lhs : rhs;
}
template< typename T >
T const & regex_min( T const & lhs, T const & rhs )
{
return ( lhs < rhs ) ? lhs : rhs;
}
} // namespace detail
//
// The perl_syntax class encapsulates the Perl 5 regular expression syntax. It is
// used as a template parameter to basic_rpattern. To customize regex syntax, create
// your own syntax class and use it as a template parameter instead.
//
class perl_syntax_base
{
protected:
perl_syntax_base()
{
}
static TOKEN const s_rgreg[ UCHAR_MAX + 1 ];
static TOKEN const s_rgescape[ UCHAR_MAX + 1 ];
static TOKEN look_up( char ch, TOKEN const rg[] )
{
return rg[ static_cast<unsigned char>( ch ) ];
}
static TOKEN look_up( wchar_t ch, TOKEN const rg[] )
{
return UCHAR_MAX < ch ? NO_TOKEN : rg[ static_cast<unsigned char>( ch ) ];
}
};
// --------------------------------------------------------------------------
//
// Class: perl_syntax
//
// Description: Module that encapsulates the Perl syntax
//
// Methods: eat_whitespace -
// min_quant -
// perl_syntax -
// perl_syntax -
// set_flags -
// get_flags -
// reg_token -
// quant_token -
// charset_token -
// subst_token -
// ext_token -
// get_charset_map -
// invalid_charset -
// register_intrinsic_charset -
// _invalid_charset -
// _invalid_charset -
//
// Members: m_flags -
// s_charset_map -
//
// Typedefs: iterator -
// const_iterator -
// char_type -
//
// History: 11/16/2001 - ericne - Created
//
// --------------------------------------------------------------------------
template< typename CharT >
class perl_syntax : protected perl_syntax_base
{
public:
typedef typename std::basic_string<CharT>::iterator iterator;
typedef typename std::basic_string<CharT>::const_iterator const_iterator;
typedef CharT char_type;
template< typename OtherT > struct rebind { typedef perl_syntax<OtherT> other; };
private:
REGEX_FLAGS m_flags;
const_iterator eat_whitespace( iterator & icur, const_iterator iend )
{
if( m_flags & EXTENDED )
{
while( iend != icur && ( REGEX_CHAR(CharT,'#') == *icur || detail::regex_isspace( *icur ) ) )
{
if( REGEX_CHAR(CharT,'#') == *icur++ )
{
while( iend != icur && REGEX_CHAR(CharT,'/n') != *icur++ ) {}
}
else
{
for( ; iend != icur && detail::regex_isspace( *icur ); ++icur ) {}
}
}
}
return icur;
}
bool min_quant( iterator & icur, const_iterator iend )
{
return ( iend != eat_whitespace( ++icur, iend ) && REGEX_CHAR(CharT,'?') == *icur ? ( ++icur, true ) : false );
}
public:
perl_syntax( REGEX_FLAGS flags )
: m_flags( flags )
{
}
perl_syntax( perl_syntax<CharT> const & sy )
: m_flags( sy.m_flags )
{
}
void set_flags( REGEX_FLAGS flags )
{
m_flags = flags;
}
REGEX_FLAGS get_flags() const
{
return m_flags;
}
TOKEN reg_token( iterator & icur, const_iterator iend )
{
REGEX_ASSERT( iend != icur );
if( iend == eat_whitespace( icur, iend ) )
return NO_TOKEN;
TOKEN tok = look_up( *icur, s_rgreg );
if( tok )
++icur;
if( ESCAPE == tok && iend != icur )
{
tok = look_up( *icur, s_rgescape );
if( tok )
++icur;
else
tok = ESCAPE;
}
return tok;
}
TOKEN quant_token( iterator & icur, const_iterator iend )
{
REGEX_ASSERT( iend != icur );
if( iend == eat_whitespace( icur, iend ) )
return NO_TOKEN;
TOKEN tok = NO_TOKEN;
switch( *icur )
{
case REGEX_CHAR(CharT,'*'):
tok = min_quant( icur, iend ) ? ZERO_OR_MORE_MIN : ZERO_OR_MORE;
break;
case REGEX_CHAR(CharT,'+'):
tok = min_quant( icur, iend ) ? ONE_OR_MORE_MIN : ONE_OR_MORE;
break;
case REGEX_CHAR(CharT,'?'):
tok = min_quant( icur, iend ) ? ZERO_OR_ONE_MIN : ZERO_OR_ONE;
break;
case REGEX_CHAR(CharT,'}'):
tok = min_quant( icur, iend ) ? END_RANGE_MIN : END_RANGE;
break;
case REGEX_CHAR(CharT,'{'):
tok = BEGIN_RANGE;
++icur;
break;
case REGEX_CHAR(CharT,','):
tok = RANGE_SEPARATOR;
++icur;
break;
}
return tok;
}
TOKEN charset_token( iterator & icur, const_iterator iend )
{
REGEX_ASSERT( iend != icur );
TOKEN tok = NO_TOKEN;
switch( *icur )
{
case REGEX_CHAR(CharT,'-'):
tok = CHARSET_RANGE;
++icur;
break;
case REGEX_CHAR(CharT,'^'):
tok = CHARSET_NEGATE;
++icur;
break;
case REGEX_CHAR(CharT,']'):
tok = CHARSET_END;
++icur;
break;
case REGEX_CHAR(CharT,'//'):
tok = CHARSET_ESCAPE;
if( iend == ++icur )
break;
switch( *icur )
{
case REGEX_CHAR(CharT,'b'):
tok = CHARSET_BACKSPACE;
++icur;
break;
case REGEX_CHAR(CharT,'d'):
tok = ESC_DIGIT;
++icur;
break;
case REGEX_CHAR(CharT,'D'):
tok = ESC_NOT_DIGIT;
++icur;
break;
case REGEX_CHAR(CharT,'s'):
tok = ESC_SPACE;
++icur;
break;
case REGEX_CHAR(CharT,'S'):
tok = ESC_NOT_SPACE;
++icur;
break;
case REGEX_CHAR(CharT,'w'):
tok = ESC_WORD;
++icur;
break;
case REGEX_CHAR(CharT,'W'):
tok = ESC_NOT_WORD;
++icur;
break;
}
break;
case REGEX_CHAR(CharT,'['):
if( REGEX_CHAR(CharT,':') == *( ++icur )-- )
{
for( size_t i=0; !tok && i < detail::g_cposix_charsets; ++i )
{
if( detail::is_posix_charset<const_iterator>( icur, iend, detail::g_rgposix_charsets[i].m_szcharset ) )
{
tok = TOKEN( CHARSET_ALNUM + i );
std::advance( icur, detail::g_rgposix_charsets[i].cchars );
}
}
}
break;
}
return tok;
}
TOKEN subst_token( iterator & icur, const_iterator iend )
{
REGEX_ASSERT( iend != icur );
TOKEN tok = NO_TOKEN;
switch( *icur )
{
case REGEX_CHAR(CharT,'//'):
tok = SUBST_ESCAPE;
if( iend != ++icur )
switch( *icur )
{
case REGEX_CHAR(CharT,'Q'):
tok = SUBST_QUOTE_META_ON;
++icur;
break;
case REGEX_CHAR(CharT,'U'):
tok = SUBST_UPPER_ON;
++icur;
break;
case REGEX_CHAR(CharT,'u'):
tok = SUBST_UPPER_NEXT;
++icur;
break;
case REGEX_CHAR(CharT,'L'):
tok = SUBST_LOWER_ON;
++icur;
break;
case REGEX_CHAR(CharT,'l'):
tok = SUBST_LOWER_NEXT;
++icur;
break;
case REGEX_CHAR(CharT,'E'):
tok = SUBST_ALL_OFF;
++icur;
break;
}
break;
case REGEX_CHAR(CharT,'$'):
tok = SUBST_BACKREF;
if( iend != ++icur )
switch( *icur )
{
case REGEX_CHAR(CharT,'&'):
tok = SUBST_MATCH;
++icur;
break;
case REGEX_CHAR(CharT,'`'):
tok = SUBST_PREMATCH;
++icur;
break;
case REGEX_CHAR(CharT,'/''):
tok = SUBST_POSTMATCH;
++icur;
break;
}
break;
}
return tok;
}
TOKEN ext_token( iterator & icur, const_iterator iend )
{
REGEX_ASSERT( iend != icur );
if( iend == eat_whitespace( icur, iend ) )
return NO_TOKEN;
bool finclude;
TOKEN tok = NO_TOKEN;
if( REGEX_CHAR(CharT,'?') == *icur )
{
tok = EXT_UNKNOWN;
++icur;
if( m_flags & EXTENDED )
for( ; iend != icur && detail::regex_isspace( *icur ); ++icur ) {}
if( iend != icur )
{
switch( *icur )
{
case REGEX_CHAR(CharT,':'):
tok = EXT_NOBACKREF;
++icur;
break;
case REGEX_CHAR(CharT,'='):
tok = EXT_POS_LOOKAHEAD;
++icur;
break;
case REGEX_CHAR(CharT,'!'):
tok = EXT_NEG_LOOKAHEAD;
++icur;
break;
case REGEX_CHAR(CharT,'#'):
tok = EXT_COMMENT;
++icur;
break;
case REGEX_CHAR(CharT,'('):
tok = EXT_CONDITION;
++icur;
break;
case REGEX_CHAR(CharT,'R'):
tok = EXT_RECURSE;
++icur;
break;
case REGEX_CHAR(CharT,'<'):
if( iend == eat_whitespace( ++icur, iend ) )
break;
switch( *icur )
{
case REGEX_CHAR(CharT,'='):
tok = EXT_POS_LOOKBEHIND;
++icur;
break;
case REGEX_CHAR(CharT,'!'):
tok = EXT_NEG_LOOKBEHIND;
++icur;
break;
}
break;
case REGEX_CHAR(CharT,'>'):
tok = EXT_INDEPENDENT;
++icur;
break;
default:
finclude = true;
do
{
if( REGEX_CHAR(CharT,':') == *icur )
{
tok = EXT_NOBACKREF;
++icur;
break;
}
if( REGEX_CHAR(CharT,')') == *icur )
{
tok = EXT_NOBACKREF;
break;
}
if( REGEX_CHAR(CharT,'-') == *icur && finclude )
finclude = false;
else if( REGEX_CHAR(CharT,'i') == *icur )
m_flags = ( REGEX_FLAGS ) ( finclude ? ( m_flags | NOCASE ) : ( m_flags & ~NOCASE ) );
else if( REGEX_CHAR(CharT,'m') == *icur )
m_flags = ( REGEX_FLAGS ) ( finclude ? ( m_flags | MULTILINE ) : ( m_flags & ~MULTILINE ) );
else if( REGEX_CHAR(CharT,'s') == *icur )
m_flags = ( REGEX_FLAGS ) ( finclude ? ( m_flags | SINGLELINE ) : ( m_flags & ~SINGLELINE ) );
else if( REGEX_CHAR(CharT,'x') == *icur )
m_flags = ( REGEX_FLAGS ) ( finclude ? ( m_flags | EXTENDED ) : ( m_flags & ~EXTENDED ) );
else
break;
} while( iend != eat_whitespace( ++icur, iend ) );
break;
}
}
}
return tok;
}
// Functions used for making user-defined intrinsic character sets
static detail::charset_map<CharT> & get_charset_map()
{
return detail::get_perl_charset_map( CharT() );
}
static bool invalid_charset( CharT ch )
{
return _invalid_charset( ch );
}
static void register_intrinsic_charset( CharT ch, std::basic_string<CharT> const & str ) //throw( bad_regexpr, std::bad_alloc )
{
perl_syntax sy( NOFLAGS );
if( invalid_charset( ch ) )
throw bad_regexpr( "invalid character specified to register_intrinsic_charset" );
std::basic_string<CharT> pat = str;
typename std::basic_string<CharT>::iterator ibegin = pat.begin();
if( BEGIN_CHARSET != sy.reg_token( ibegin, pat.end() ) )
throw bad_regexpr( "expecting beginning of charset" );
regex::detail::charset_map<CharT> & charset_map = get_charset_map();
regex::detail::charset_map_node<CharT> & map_node = charset_map[ ch ];
map_node.set( std::basic_string<CharT>( ibegin, pat.end() ) );
}
private:
static bool _invalid_charset( char ch )
{
using namespace std;
return NO_TOKEN != s_rgescape[ static_cast<unsigned char>( ch ) ]
|| isdigit( ch ) || 'e' == ch || 'x' == ch || 'c' == ch;
}
static bool _invalid_charset( wchar_t ch )
{
return UCHAR_MAX >= ch && _invalid_charset( static_cast<char>( ch ) );
}
};
// --------------------------------------------------------------------------
//
// Class: posix_syntax
//
// Description: Implements the basic POSIX regular expression syntax
//
// Methods: posix_syntax -
// posix_syntax -
// get_flags -
// set_flags -
// reg_token -
// quant_token -
// charset_token -
// subst_token -
// ext_token -
// get_charset_map -
// invalid_charset -
// register_intrinsic_charset -
//
// Members: m_flags -
// s_charset_map -
//
// Typedefs: iterator -
// const_iterator -
// char_type -
//
// History: 11/16/2001 - ericne - Created
//
// --------------------------------------------------------------------------
template< typename CharT >
class posix_syntax
{
REGEX_FLAGS m_flags;
public:
typedef typename std::basic_string<CharT>::iterator iterator;
typedef typename std::basic_string<CharT>::const_iterator const_iterator;
typedef CharT char_type;
template< typename OtherT > struct rebind { typedef posix_syntax<OtherT> other; };
posix_syntax( REGEX_FLAGS flags )
: m_flags( flags )
{
}
posix_syntax( posix_syntax<CharT> const & sy )
: m_flags( sy.m_flags )
{
}
REGEX_FLAGS get_flags() const
{
return m_flags;
}
void set_flags( REGEX_FLAGS flags )
{
m_flags = flags;
}
TOKEN reg_token( iterator & icur, const_iterator iend )
{
TOKEN tok = NO_TOKEN;
switch( *icur )
{
case REGEX_CHAR(CharT,'.'):
tok = MATCH_ANY;
++icur;
break;
case REGEX_CHAR(CharT,'^'):
tok = BEGIN_LINE;
++icur;
break;
case REGEX_CHAR(CharT,'$'):
tok = END_LINE;
++icur;
break;
case REGEX_CHAR(CharT,'['):
tok = BEGIN_CHARSET;
++icur;
break;
case REGEX_CHAR(CharT,'//'):
tok = ESCAPE;
++icur;
if( iend != icur )
{
switch( *icur )
{
case REGEX_CHAR(CharT,'('):
tok = BEGIN_GROUP;
++icur;
break;
case REGEX_CHAR(CharT,')'):
tok = END_GROUP;
++icur;
break;
case REGEX_CHAR(CharT,'|'):
tok = ALTERNATION;
++icur;
break;
}
}
break;
}
return tok;
}
TOKEN quant_token( iterator & icur, const_iterator iend )
{
TOKEN tok = NO_TOKEN;
switch( *icur )
{
case REGEX_CHAR(CharT,'*'):
tok = ZERO_OR_MORE;
++icur;
break;
case REGEX_CHAR(CharT,','):
tok = RANGE_SEPARATOR;
++icur;
break;
case REGEX_CHAR(CharT,'//'):
++icur;
if( iend != icur )
{
switch( *icur )
{
case REGEX_CHAR(CharT,'?'):
tok = ZERO_OR_ONE;
++icur;
break;
case REGEX_CHAR(CharT,'+'):
tok = ONE_OR_MORE;
++icur;
break;
case REGEX_CHAR(CharT,'{'):
tok = BEGIN_RANGE;
++icur;
break;
case REGEX_CHAR(CharT,'}'):
tok = END_RANGE;
++icur;
break;
default:
--icur;
break;
}
}
else
{
--icur;
}
}
return tok;
}
TOKEN charset_token( iterator & icur, const_iterator iend )
{
TOKEN tok = NO_TOKEN;
switch( *icur )
{
case REGEX_CHAR(CharT,'^'):
tok = CHARSET_NEGATE;
++icur;
break;
case REGEX_CHAR(CharT,'-'):
tok = CHARSET_RANGE;
++icur;
break;
case REGEX_CHAR(CharT,']'):
tok = CHARSET_END;
++icur;
break;
case REGEX_CHAR(CharT,'['):
if( REGEX_CHAR(CharT,':') == *( ++icur )-- )
{
for( size_t i=0; !tok && i < detail::g_cposix_charsets; ++i )
{
if( detail::is_posix_charset<const_iterator>( icur, iend, detail::g_rgposix_charsets[i].m_szcharset ) )
{
tok = TOKEN( CHARSET_ALNUM + i );
std::advance( icur, detail::g_rgposix_charsets[i].cchars );
}
}
}
break;
}
return tok;
}
TOKEN subst_token( iterator & icur, const_iterator iend )
{
TOKEN tok = NO_TOKEN;
if( REGEX_CHAR(CharT,'//') == *icur )
{
tok = SUBST_ESCAPE;
++icur;
if( iend != icur && REGEX_CHAR(CharT,'0') <= *icur && REGEX_CHAR(CharT,'9') >= *icur )
{
tok = SUBST_BACKREF;
}
}
return tok;
}
TOKEN ext_token( iterator &, const_iterator )
{
return NO_TOKEN;
}
// Functions for making user-defined intrinsic character sets
static detail::charset_map<CharT> & get_charset_map()
{
return detail::get_posix_charset_map( CharT() );
}
static bool invalid_charset( CharT ch )
{
return _invalid_charset( ch );
}
static void register_intrinsic_charset( CharT ch, std::basic_string<CharT> const & str ) //throw( bad_regexpr, std::bad_alloc )
{
posix_syntax sy( NOFLAGS );
if( invalid_charset( ch ) )
throw bad_regexpr( "invalid character specified to register_intrinsic_charset" );
std::basic_string<CharT> pat = str;
typename std::basic_string<CharT>::iterator ibegin = pat.begin();
if( BEGIN_CHARSET != sy.reg_token( ibegin, pat.end() ) )
throw bad_regexpr( "expecting beginning of charset" );
regex::detail::charset_map<CharT> & charset_map = get_charset_map();
regex::detail::charset_map_node<CharT> & map_node = charset_map[ ch ];
map_node.set( std::basic_string<CharT>( ibegin, pat.end() ) );
}
private:
static bool _invalid_charset( char ch )
{
static char const s_invalid[] = "0123456789()|?+{}//exc";
return 0 != std::char_traits<CharT>::find( s_invalid, ARRAYSIZE( s_invalid ) - 1, ch );
}
static bool _invalid_charset( wchar_t ch )
{
return UCHAR_MAX >= ch && _invalid_charset( static_cast<char>( ch ) );
}
};
} // namespace regex
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif
//+---------------------------------------------------------------------------
//
// Copyright ( C ) Microsoft, 1994 - 2002.
//
// File: reimpl2.h
//
// Functions: helpers for matching and substituting regular expressions
//
// Notes: implementation details that really belong in a cpp file,
// but can't because of template weirdness
//
// Author: Eric Niebler ( [email protected] )
//
// History: 8/15/2001 ericne Created
//
//----------------------------------------------------------------------------
#ifndef REIMPL_H
#define REIMPL_H
//
// Helper functions for match and substitute
//
namespace detail
{
// For use while doing uppercase/lowercase conversions:
inline char regex_toupper( char ch ) { using namespace std; return ( char )toupper( ch ); }
inline char regex_tolower( char ch ) { using namespace std; return ( char )tolower( ch ); }
inline wchar_t regex_toupper( wchar_t ch ) { using namespace std; return ( wchar_t )towupper( ch ); }
inline wchar_t regex_tolower( wchar_t ch ) { using namespace std; return ( wchar_t )towlower( ch ); }
template< typename IBeginT, typename IEndT >
inline void regex_toupper( IBeginT ibegin, IEndT iend )
{
typedef typename std::iterator_traits<IEndT>::value_type char_type;
typedef std::char_traits<char_type> traits_type;
for( ; iend != ibegin; ++ibegin )
traits_type::assign( *ibegin, regex_toupper( *ibegin ) );
}
template< typename IBeginT, typename IEndT >
inline void regex_tolower( IBeginT ibegin, IEndT iend )
{
typedef typename std::iterator_traits<IEndT>::value_type char_type;
typedef std::char_traits<char_type> traits_type;
for( ; iend != ibegin; ++ibegin )
traits_type::assign( *ibegin, regex_tolower( *ibegin ) );
}
//
// Helper fn for swapping two auto_ptr's
//
template< typename T >
inline void swap_auto_ptr( std::auto_ptr<T> & left, std::auto_ptr<T> & right )
{
std::auto_ptr<T> temp( left );
left = right;
right = temp;
}
template< typename T >
inline void reset_auto_ptr( std::auto_ptr<T> & left )
{
std::auto_ptr<T> temp( 0 );
left = temp;
}
template< typename T, typename U >
inline void reset_auto_ptr( std::auto_ptr<T> & left, U * right )
{
std::auto_ptr<T> temp( right );
left = temp;
}
typedef int instantiator;
inline instantiator REGEX_CDECL instantiator_helper( ... )
{
return instantiator();
}
// --------------------------------------------------------------------------
//
// Class: match_param
//
// Description: Struct that contains the state of the matching operation.
// Passed by reference to all recursive_match_all and recursive_match_this routines.
//
// Methods: match_param - ctor
//
// Members: ibufferbegin - start of the buffer
// ibegin - start of this iteration
// iend - end of the string
// prgbackrefs - pointer to backref array
//
// History: 8/14/2000 - ericne - Created
//
// --------------------------------------------------------------------------
template< typename IterT >
struct match_param
{
typedef backref_tag<IterT> backref_type;
typedef sub_expr_base<IterT> const * sub_expr_ptr;
// for performance reasons, the most frequently used fields
// are placed at offsets which are a power of 2 (assuming
// a 32-bit architecture, and iterators which are 32 bits).
backref_type * m_prgbackrefs; // offsetof == 0
IterT m_iend; // offsetof == 4
IterT m_icur; // offsetof == 8
size_t m_cbackrefs;
sub_expr_ptr m_pnext; // offsetof == 16
IterT m_ibufferbegin;
IterT m_imatchbegin;
sub_expr_ptr m_pfirst;
unsafe_stack * m_pstack; // offsetof == 32
bool m_no0len;
bool m_reserved;
match_param
(
IterT ibufferbegin,
IterT imatchbegin,
IterT iend,
backref_type * prgbackrefs,
size_t cbackrefs
)
: m_prgbackrefs( prgbackrefs )
, m_iend( iend )
, m_icur( imatchbegin )
, m_cbackrefs( cbackrefs )
, m_pnext( 0 )
, m_ibufferbegin( ibufferbegin )
, m_imatchbegin( imatchbegin )
, m_pfirst( 0 )
, m_pstack( 0 )
, m_no0len( false )
, m_reserved( false )
{
}
};
// --------------------------------------------------------------------------
//
// Class: arena_allocator
//
// Description: A small, fast allocator for speeding up pattern compilation.
// Every basic_rpattern object has an arena as a member.
// sub_expr objects can only be allocated from this arena.
// Memory is alloc'ed in chunks using the underlying allocator.
// Chunks are freed en-masse when clear() or finalize() is called.
//
// History: 8/17/2001 - ericne - Created
//
// Notes: This is NOT a std-compliant allocator and CANNOT be used with
// STL containers. arena_allocator objects maintain state, and
// STL containers are allowed to assume their allocators do
// not maintain state. In regexpr2.cpp, I define slist<>, a simple
// arena-friendly singly-linked list for use with the arena
// allocator.
//
// --------------------------------------------------------------------------
template< typename AllocT = std::allocator<char> >
struct pool_impl
{
typedef typename rebind<AllocT, char>::type char_allocator_type;
struct mem_block
{
size_t m_offset;
size_t m_blocksize;
mem_block * m_pnext;
unsigned char m_data[ 1 ];
};
#if !defined(_MSC_VER) | 1200 < _MSC_VER
struct pool_data : char_allocator_type
{
pool_data( size_t default_size, char_allocator_type const & alloc )
: char_allocator_type( alloc )
, m_pfirst( 0 )
, m_default_size( default_size )
{
}
mem_block * m_pfirst;
size_t m_default_size;
char_allocator_type & get_allocator()
{
return *this;
}
} m_data;
#else
struct pool_data
{
pool_data( size_t default_size, char_allocator_type const & alloc )
: m_alloc( alloc )
, m_pfirst( 0 )
, m_default_size( default_size )
{
}
char_allocator_type m_alloc;
mem_block * m_pfirst;
size_t m_default_size;
char_allocator_type & get_allocator()
{
return m_alloc;
}
} m_data;
#endif
void new_block( size_t size );
void clear();
void * allocate( size_t size );
explicit pool_impl( size_t default_size, char_allocator_type const & alloc = char_allocator_type() );
~pool_impl();
char_allocator_type get_allocator() const
{
return const_cast<pool_impl*>(this)->m_data.get_allocator();
}
};
template< typename T, typename AllocT = std::allocator<char> >
class arena_allocator
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T *pointer;
typedef T const *const_pointer;
typedef T & reference;
typedef T const & const_reference;
typedef T value_type;
typedef typename rebind<AllocT, char>::type char_alloc_type;
typedef pool_impl<AllocT> pool_impl_t;
typedef typename rebind<AllocT, pool_impl_t>::type pool_alloc_type;
explicit arena_allocator( size_t default_size, char_alloc_type const & alloc = char_alloc_type() )
: m_pool( 0 )
{
char_alloc_type char_alloc( alloc );
pool_alloc_type pool_alloc( convert_allocator<pool_impl_t>( char_alloc, 0 ) );
m_pool = pool_alloc.allocate( 1, 0 );
pool_alloc.construct( m_pool, pool_impl_t( default_size, char_alloc ) ); // can't throw
}
#if !defined(_MSC_VER) | 1200 < _MSC_VER
arena_allocator( arena_allocator const & that )
: m_pool( that.m_pool )
{
}
#endif
template< typename U >
arena_allocator( arena_allocator<U> const & that )
: m_pool( that.m_pool )
{
}
~arena_allocator()
{ // Many arena_allocators may point to m_pool, so don't delete it.
} // Rather, wait for someone to call finalize().
pointer allocate( size_type size, void const * =0 )
{
return static_cast<T*>( m_pool->allocate( size * sizeof(T) ) );
}
void deallocate( void *, size_type )
{ // no-op. deallocation happens when pool is finalized or cleared.
}
void construct( pointer p, T const & t )
{
new( static_cast<void*>(p) ) T( t );
}
void destroy( pointer p )
{
regex::detail::destroy( p );
}
#if !defined(_MSC_VER) | 1200 < _MSC_VER
template< typename U > struct rebind
{
typedef arena_allocator<U> other;
};
#endif
void clear()
{
m_pool->clear();
}
void finalize()
{
char_alloc_type char_alloc( m_pool->get_allocator() );
pool_alloc_type pool_alloc( convert_allocator<pool_impl_t>( char_alloc, 0 ) );
pool_alloc.destroy( m_pool );
pool_alloc.deallocate( m_pool, 1 );
m_pool = 0;
}
void swap( arena_allocator & that )
{
using std::swap;
swap( m_pool, that.m_pool );
}
// the pool lives here
pool_impl_t * m_pool;
};
// Dummy struct used by the pool allocator to align returned pointers
struct not_pod
{
virtual ~not_pod() {}
};
template< typename AllocT >
inline pool_impl<AllocT>::pool_impl( size_t default_size, char_allocator_type const & alloc )
: m_data( default_size, alloc )
{
}
template< typename AllocT >
inline pool_impl<AllocT>::~pool_impl()
{
clear();
}
template< typename AllocT >
inline void pool_impl<AllocT>::clear()
{
for( mem_block * pnext; m_data.m_pfirst; m_data.m_pfirst = pnext )
{
pnext = m_data.m_pfirst->m_pnext;
m_data.get_allocator().deallocate( reinterpret_cast<char*>( m_data.m_pfirst ), m_data.m_pfirst->m_blocksize );
}
}
template< typename AllocT >
inline void pool_impl<AllocT>::new_block( size_t size )
{
size_t blocksize = regex_max( m_data.m_default_size, size ) + offsetof( mem_block, m_data );
mem_block * pnew = reinterpret_cast<mem_block*>( m_data.get_allocator().allocate( blocksize, 0 ) );
if( 0 == pnew )
{
throw std::bad_alloc();
}
pnew->m_offset = 0;
pnew->m_blocksize = blocksize;
pnew->m_pnext = m_data.m_pfirst;
m_data.m_pfirst = pnew;
}
template< typename AllocT >
inline void * pool_impl<AllocT>::allocate( size_t size )
{
if( 0 == size )
size = 1;
if( 0 == m_data.m_pfirst || m_data.m_pfirst->m_offset + size > m_data.m_default_size )
new_block( size );
void * pnew = m_data.m_pfirst->m_data + m_data.m_pfirst->m_offset;
// ensure returned pointers are always suitably aligned
m_data.m_pfirst->m_offset += ( ( size + alignof<not_pod>::value - 1 )
& ~( alignof<not_pod>::value - 1 ) );
return pnew;
}
// The regex_arena is a basic, vanilla arena_allocator.
typedef arena_allocator<char> regex_arena;
template< typename T >
type_with_size<3> allocator_picker( arena_allocator<T> const &, int );
template<> struct rebind_helper<3>
{
template< typename, typename ElemT>
struct inner
{
typedef arena_allocator<ElemT> type;
};
};
// --------------------------------------------------------------------------
//
// Class: sub_expr_base
//
// Description: patterns are "compiled" into a directed graph of sub_expr_base
// structs. Matching is accomplished by traversing this graph.
//
// Methods: ~sub_expr_base - virt dtor so cleanup happens correctly
// recursive_match_all - match this sub-expression and all following
// sub-expression
//
// History: 8/14/2000 - ericne - Created
//
// --------------------------------------------------------------------------
template< typename IterT >
struct sub_expr_base
{
virtual bool recursive_match_all_s( match_param<IterT> &, IterT ) const = 0; //throw() (offset 0)
virtual bool recursive_match_all_c( match_param<IterT> &, IterT ) const = 0; //throw() (offset 4)
virtual bool iterative_match_this_s( match_param<IterT> & ) const = 0; //throw() (offset 8)
virtual bool iterative_match_this_c( match_param<IterT> & ) const = 0; //throw() (offset 12)
virtual bool iterative_rematch_this_s( match_param<IterT> & ) const = 0; //throw() (offset 16)
virtual bool iterative_rematch_this_c( match_param<IterT> & ) const = 0; //throw() (offset 20)
virtual ~sub_expr_base() = 0; // (offset 24)
// Use the regex_arena for memory management
static void * operator new( size_t size, regex_arena & arena )
{
return arena.allocate( size );
}
static void operator delete( void *, regex_arena & )
{
}
// Invoke the d'tor, but don't bother freeing memory. That will
// happen automatically when the arena object gets destroyed.
static void operator delete( void * )
{
}
// For choosing an appropriate virtual function based on a compile time constant
bool recursive_match_all( match_param<IterT> & param, IterT icur, false_t ) const //throw()
{
return recursive_match_all_s( param, icur );
}
bool recursive_match_all( match_param<IterT> & param, IterT icur, true_t ) const //throw()
{
return recursive_match_all_c( param, icur );
}
bool iterative_match_this( match_param<IterT> & param, false_t ) const //throw()
{
return iterative_match_this_s( param );
}
bool iterative_match_this( match_param<IterT> & param, true_t ) const //throw()
{
return iterative_match_this_c( param );
}
bool iterative_rematch_this( match_param<IterT> & param, false_t ) const //throw()
{
return iterative_rematch_this_s( param );
}
bool iterative_rematch_this( match_param<IterT> & param, true_t ) const //throw()
{
return iterative_rematch_this_c( param );
}
private:
// don't allocate sub-expressions directly on the heap; they should
// be allocated from an arena
static void * operator new( size_t size ) throw( std::bad_alloc );
// disable all the vector new's and delete's.
static void * operator new[]( size_t size, regex_arena & arena ) throw( std::bad_alloc );
static void operator delete[]( void *, regex_arena & );
static void * operator new[]( size_t size ) throw( std::bad_alloc );
static void operator delete[]( void * );
};
template< typename IterT >
inline sub_expr_base<IterT>::~sub_expr_base()
{
}
// --------------------------------------------------------------------------
//
// Class: subst_node
//
// Description: Substitution strings are parsed into an array of these
// structures in order to speed up subst operations.
//
// Members: stype - type of this struct
// .m_subst_string - do a string substitution
// .m_subst_backref - do a bacref substitution
// op - execute an operation
//
// History: 8/14/2000 - ericne - Created
//
// --------------------------------------------------------------------------
struct subst_node
{
enum
{
PREMATCH = -1,
POSTMATCH = -2
};
enum subst_type
{
SUBST_STRING,
SUBST_BACKREF,
SUBST_OP
};
enum op_type
{
UPPER_ON = SUBST_UPPER_ON,
UPPER_NEXT = SUBST_UPPER_NEXT,
LOWER_ON = SUBST_LOWER_ON,
LOWER_NEXT = SUBST_LOWER_NEXT,
ALL_OFF = SUBST_ALL_OFF
};
struct string_offsets
{
ptrdiff_t m_rstart;
ptrdiff_t m_rlength;
};
subst_type m_stype;
union
{
string_offsets m_subst_string;
size_t m_subst_backref;
op_type m_op;
};
};
typedef std::list<subst_node> subst_list_type;
size_t DEFAULT_BLOCK_SIZE();
template< typename IterT >
class boyer_moore;
// --------------------------------------------------------------------------
//
// Class: basic_rpattern_base_impl
//
// Description:
//
// Methods: basic_rpattern_base_impl - ctor
// flags - get the state of the flags
// uses_backrefs - true if the backrefs are referenced
// get_first_subexpression - return ptr to first sub_expr struct
// get_width - get min/max nbr chars this pattern can match
// loops - if false, we only need to try to match at 1st position
// cgroups - number of visible groups
// _cgroups_total - total number of groups, including hidden ( ?: ) groups
// get_pat - get string representing the pattern
// get_subst - get string representing the substitution string
// get_subst_list - get the list of subst nodes
// _normalize_string - perform character escaping
//
// Members: m_fuses_backrefs - true if subst string refers to backrefs
// m_floop - false if pat only needs to be matched in one place
// m_cgroups - total count of groups
// m_cgroups_visible - count of visible groups
// m_flags - the flags
// m_nwidth - width of this pattern
// m_pat - pattern string
// m_subst - substitution string
// m_subst_list - list of substitution nodes
// m_pfirst - ptr to first subexpression to match
//
// Typedefs: char_type -
// string_type -
// size_type -
//
// History: 8/14/2000 - ericne - Created
//
// --------------------------------------------------------------------------
template< typename IterT >
class basic_rpattern_base_impl
{
basic_rpattern_base_impl( basic_rpattern_base_impl<IterT> const & );
basic_rpattern_base_impl & operator=( basic_rpattern_base_impl<IterT> const & );
protected:
typedef typename std::iterator_traits<IterT>::value_type char_type;
typedef std::char_traits<char_type> traits_type;
typedef std::basic_string<char_type> string_type;
typedef size_t size_type;
typedef backref_tag<IterT> backref_type;
typedef std::vector<backref_type> backref_vector;
friend struct regex_access<IterT>;
explicit basic_rpattern_base_impl
(
REGEX_FLAGS flags = NOFLAGS,
REGEX_MODE mode = MODE_DEFAULT,
string_type const & pat = string_type(),
string_type const & subst = string_type()
) //throw()
: m_arena( DEFAULT_BLOCK_SIZE() )
, m_fuses_backrefs( false )
, m_floop( true )
, m_fok_to_recurse( true )
, m_cgroups( 0 )
, m_cgroups_visible( 0 )
, m_flags( flags )
, m_mode( mode )
, m_nwidth( uninit_width() )
, m_pat( new string_type( pat ) )
, m_subst( new string_type( subst ) )
, m_subst_list()
, m_pfirst( 0 )
, m_invisible_groups()
, m_search( 0 )
{
}
virtual ~basic_rpattern_base_impl()
{
// We're not going to be calling destructors because all allocated
// memory associated with the parsed pattern resides in the arena.
// The memory will be freed when the arena gets destroyed.
//delete m_pfirst;
reset_auto_ptr( m_pat );
reset_auto_ptr( m_subst );
m_arena.finalize();
}
regex_arena m_arena; // The sub_expr arena
bool m_fuses_backrefs; // true if the substitution uses backrefs
bool m_floop; // false if m_pfirst->recursive_match_all only needs to be called once
bool m_fok_to_recurse; // false if the pattern would recurse too deeply
size_t m_cgroups; // number of groups ( always at least one )
size_t m_cgroups_visible; // number of visible groups
REGEX_FLAGS m_flags; // flags used to customize search/replace
REGEX_MODE m_mode; // Used to pick the fast or safe algorithm
width_type m_nwidth; // width of the pattern
std::auto_ptr<string_type> m_pat; // contains the unparsed pattern
std::auto_ptr<string_type> m_subst; // contains the unparsed substitution
subst_list_type m_subst_list; // used to speed up substitution
sub_expr_base<IterT> const * m_pfirst; // first subexpression in pattern
std::list<size_t> m_invisible_groups; // groups w/o backrefs
boyer_moore<typename string_type::const_iterator> * m_search;
size_t _cgroups_total() const //throw()
{
return m_cgroups;
}
bool _loops() const //throw()
{
return m_floop;
}
size_t _get_next_group_nbr()
{
return m_cgroups++;
}
void _normalize_string( string_type & str ) const //throw()
{
if( NORMALIZE & flags() )
process_escapes( str, true );
}
bool _save_backrefs() const //throw()
{
return m_fuses_backrefs || ! ( flags() & NOBACKREFS );
}
sub_expr_base<IterT> const * _get_first_subexpression() const //throw()
{
return m_pfirst;
}
REGEX_FLAGS flags() const //throw()
{
return m_flags;
}
REGEX_MODE mode() const // throw()
{
return m_mode;
}
width_type get_width() const //throw()
{
return m_nwidth;
}
size_t cgroups() const //throw()
{
return m_cgroups_visible;
}
string_type const & get_pat() const //throw()
{
return *m_pat;
}
string_type const & get_subst() const //throw()
{
return *m_subst;
}
bool _ok_to_recurse() const; //throw();
void swap( basic_rpattern_base_impl<IterT> & that ); // throw();
enum { npos = static_cast<size_type>( -1 ) };
static instantiator instantiate()
{
typedef basic_rpattern_base_impl this_type;
return instantiator_helper
(
&this_type::_ok_to_recurse,
&this_type::swap
);
}
};
template< typename IterT >
struct regex_access
{
typedef basic_rpattern_base_impl< IterT > rpattern_type;
typedef typename rpattern_type::size_type size_type;
typedef typename rpattern_type::char_type char_type;
typedef typename rpattern_type::traits_type traits_type;
typedef typename rpattern_type::backref_type backref_type;
static bool _do_match_iterative_helper_s
(
sub_expr_base<IterT> const * expr,
match_param<IterT> & param,
IterT icur
);
static bool _do_match_iterative_helper_c
(
sub_expr_base<IterT> const * expr,
match_param<IterT> & param,
IterT icur
);
static bool _do_match_recursive_s
(
sub_expr_base<IterT> const * expr,
match_param<IterT> & param,
IterT icur
);
static bool _do_match_recursive_c
(
sub_expr_base<IterT> const * expr,
match_param<IterT> & param,
IterT icur
);
static bool _do_match_impl
(
rpattern_type const & pat,
match_param<IterT> & param,
bool const use_null
);
static bool _do_match_with_stack
(
rpattern_type const & pat,
match_param<IterT> & param,
bool const use_null
);
template< typename Alloc1T, typename Alloc2T >
static void _fixup_backrefs
(
std::vector<backref_type,Alloc1T> & rgbackrefs,
std::list<size_t,Alloc2T> const & invisible
)
{
typedef typename std::list<size_t,Alloc2T>::const_iterator iter_type;
// Remove information about the "invisible" groups
if( rgbackrefs[0].matched )
{
size_t dropped = 0;
iter_type const end = invisible.end();
iter_type curr = invisible.begin(), next = invisible.begin();
for( ; end != curr; curr = next, ++dropped )
{
if( end == ++next )
{
std::copy(
rgbackrefs.begin() + *curr + 1,
rgbackrefs.end(),
rgbackrefs.begin() + *curr - dropped );
}
else
{
std::copy(
rgbackrefs.begin() + *curr + 1,
rgbackrefs.begin() + *next,
rgbackrefs.begin() + *curr - dropped );
}
}
rgbackrefs.resize( rgbackrefs.size() - dropped );
}
else
{
rgbackrefs.resize( rgbackrefs.size() - invisible.size() );
}
}
template< typename AllocT >
static bool _do_try_match
(
rpattern_type const & pat,
match_param<IterT> & param,
std::vector<backref_type,AllocT> & rgbackrefs,
bool const use_null
)
{
bool success;
rgbackrefs.resize( pat._cgroups_total() );
param.m_prgbackrefs = & rgbackrefs[0];
param.m_cbackrefs = rgbackrefs.size();
REGEX_SEH_TRY
{
if( pat._ok_to_recurse() )
{
success = _do_match_impl( pat, param, use_null );
}
else
{
success = _do_match_with_stack( pat, param, use_null );
}
}
REGEX_SEH_EXCEPT( REGEX_SEH_STACK_OVERFLOW == _exception_code() )
{
// we have overflowed the stack. reset the guard page.
REGEX_RESET_STK_OFLW();
// This match fails silently.
for( size_t i=0; i < param.m_cbackrefs; ++i )
{
param.m_prgbackrefs[i] = static_init<backref_type>::value;
}
success = false;
}
_fixup_backrefs( rgbackrefs, pat.m_invisible_groups );
return success;
}
template< typename AllocT >
static bool _do_match
(
rpattern_type const & pat,
basic_match_results<IterT,AllocT> & results,
IterT ibegin,
IterT iend,
bool use_null
)
{
typedef typename basic_match_results<IterT,AllocT>::backref_vector backref_vector;
results.m_ibegin = ibegin;
match_param<IterT> param( ibegin, ibegin, iend, 0, 0 );
if( GLOBAL & pat.flags() ) // do a global find
{
// The NOBACKREFS flag is ignored in the match method.
bool const fAll = ( ALLBACKREFS == ( ALLBACKREFS & pat.flags() ) );
bool const fFirst = ( FIRSTBACKREFS == ( FIRSTBACKREFS & pat.flags() ) );
backref_vector rgtempbackrefs( results.m_rgbackrefs.get_allocator() );
while( _do_try_match( pat, param, results.m_rgbackrefs, use_null ) )
{
backref_type const & br = param.m_prgbackrefs[0];
// Handle specially the backref flags
if( fFirst )
{
rgtempbackrefs.push_back( br );
}
else if( fAll )
{
rgtempbackrefs.insert(
rgtempbackrefs.end(),
results.m_rgbackrefs.begin(),
results.m_rgbackrefs.end() );
}
else
{
rgtempbackrefs.swap( results.m_rgbackrefs );
}
param.m_imatchbegin = br.second;
param.m_no0len = ( br.first == br.second );
}
// restore the backref vectors
results.m_rgbackrefs.swap( rgtempbackrefs );
return ! results.m_rgbackrefs.empty();
}
else
{
return _do_try_match( pat, param, results.m_rgbackrefs, use_null );
}
}
template< typename AllocT >
static bool _do_match_c
(
rpattern_type const & pat,
basic_match_results<IterT,AllocT> & results,
char_type const * szbegin
)
{
if( RIGHTMOST & pat.flags() )
{
// We need to know the end of the string if we're doing a
// RIGHTMOST match.
char_type const * szend = szbegin;
std::advance( szend, traits_type::length( szbegin ) );
return _do_match( pat, results, szbegin, szend, false );
}
else
{
return _do_match( pat, results, szbegin, 0, true );
}
}
static size_t _do_count
(
rpattern_type const & pat,
IterT ibegin,
IterT iend,
bool use_null
)
{
size_t cmatches = 0;
std::vector<backref_type> rgbackrefs;
// If your compile breaks here, it is because CharT const * is not
// convertible to type IterT. Check the declaration of your rpattern object.
match_param<IterT> param( ibegin, ibegin, iend, 0, 0 );
while( _do_try_match( pat, param, rgbackrefs, use_null ) )
{
backref_type const & br = param.m_prgbackrefs[0];
++cmatches;
param.m_imatchbegin = br.second;
param.m_no0len = ( br.first == br.second );
}
return cmatches;
}
template< typename CharT, typename TraitsT, typename AllocT >
static size_t _do_split
(
rpattern_type const & pat,
basic_split_results<CharT, TraitsT, AllocT> & results,
IterT ibegin,
IterT iend,
int limit,
bool use_null
)
{
typedef typename basic_split_results<CharT, TraitsT, AllocT>::string_type string_type;
typedef typename rebind<AllocT, backref_type>::type backref_allocator;
std::vector<backref_type,backref_allocator> rgbackrefs(
convert_allocator<backref_type>( results.strings().get_allocator(), 0 ) );
typedef typename rebind<AllocT, CharT>::type char_allocator_type;
char_allocator_type char_allocator =
convert_allocator<CharT>( results.strings().get_allocator(), 0 );
// reserve some initial space
results.strings().clear();
results.strings().reserve( 10 );
match_param<IterT> param( ibegin, ibegin, iend, 0, 0 );
while( 1 != limit && _do_try_match( pat, param, rgbackrefs, use_null ) )
{
backref_type const & br = param.m_prgbackrefs[0];
param.m_no0len = ( br.first == br.second );
// discard zero-width matches at the beginning and end of the buffer
if( param.m_no0len )
{
// if we're at the beginning, skip
if( br.first == param.m_ibufferbegin )
continue;
// if we're at the end, break
if( use_null ? 0 == *param.m_imatchbegin : param.m_imatchbegin == param.m_iend )
break;
}
string_type tmp( param.m_imatchbegin, br.first, char_allocator );
results.strings().push_back( tmp );
param.m_imatchbegin = br.second;
// add any groups
for( size_t i = 1; i < rgbackrefs.size(); ++i )
{
backref_type const & br = rgbackrefs[i];
string_type tmp( br.first, br.second, char_allocator );
results.strings().push_back( tmp );
}
if( limit > 0 )
--limit;
}
// append the last string, unless it's empty and limit is 0
if( use_null )
{
if( *param.m_imatchbegin || 0 != limit )
results.strings().push_back( string_type( &*param.m_imatchbegin, char_allocator ) );
}
else
{
if( param.m_imatchbegin != param.m_iend || 0 != limit )
results.strings().push_back( string_type( param.m_imatchbegin, param.m_iend, char_allocator ) );
}
// remove trailing empty fields
if( 0 == limit )
{
while( results.size() && results.back().empty() )
{
results.strings().pop_back();
}
}
return results.size();
}
template< typename CharT, typename TraitsT, typename AllocT >
static size_t _do_subst_internal
(
std::basic_string<CharT, TraitsT, AllocT> & str,
basic_subst_results<CharT, TraitsT, AllocT> const & results,
rpattern_type const & pat,
size_type strpos,
size_type strlen
)
{
typedef subst_list_type::const_iterator iter_type;
enum { UPPER = -1, NIL, LOWER } next = NIL, rest = NIL;
bool first = true;
size_t old_strpos = strpos;
typename std::basic_string<CharT, TraitsT, AllocT>::iterator itstrlen = str.begin();
std::advance( itstrlen, strpos + strlen );
std::basic_string<char_type> const & subst = pat.get_subst();
for( iter_type isubst = pat.m_subst_list.begin(); pat.m_subst_list.end() != isubst; ++isubst )
{
size_t sublen = 0;
typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator itsubpos1; // iter into str
typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator itsublen1;
typename std::basic_string<char_type>::const_iterator itsubpos2; // iter into subst string
typename std::basic_string<char_type>::const_iterator itsublen2;
typename std::basic_string<CharT, TraitsT, AllocT>::iterator itstrpos = str.begin();
std::advance( itstrpos, strpos );
switch( isubst->m_stype )
{
case subst_node::SUBST_STRING:
itsubpos2 = subst.begin();
std::advance( itsubpos2, isubst->m_subst_string.m_rstart );
itsublen2 = itsubpos2;
std::advance( itsublen2, isubst->m_subst_string.m_rlength );
if( first )
str.replace( itstrpos, itstrlen, itsubpos2, itsublen2 );
else
str.insert( itstrpos, itsubpos2, itsublen2 );
sublen = std::distance( itsubpos2, itsublen2 );
break;
case subst_node::SUBST_BACKREF:
switch( isubst->m_subst_backref )
{
case subst_node::PREMATCH:
itsubpos1 = results.backref_str().begin();
itsublen1 = itsubpos1;
std::advance( itsublen1, sublen = results.rstart() );
break;
case subst_node::POSTMATCH:
itsubpos1 = results.backref_str().begin();
std::advance( itsubpos1, results.rstart() + results.rlength() );
itsublen1 = results.backref_str().end();
break;
default:
itsubpos1 = results.backref_str().begin();
std::advance( itsubpos1, results.rstart( isubst->m_subst_backref ) );
itsublen1 = itsubpos1;
std::advance( itsublen1, results.rlength( isubst->m_subst_backref ) );
break;
}
if( first )
str.replace( itstrpos, itstrlen, itsubpos1, itsublen1 );
else
str.insert( itstrpos, itsubpos1, itsublen1 );
sublen = std::distance( itsubpos1, itsublen1 );
break;
case subst_node::SUBST_OP:
switch( isubst->m_op )
{
case subst_node::UPPER_ON:
rest = UPPER;
break;
case subst_node::UPPER_NEXT:
next = UPPER;
break;
case subst_node::LOWER_ON:
rest = LOWER;
break;
case subst_node::LOWER_NEXT:
next = LOWER;
break;
case subst_node::ALL_OFF:
rest = NIL;
break;
default:
REGEX_ASSERT(false);
break;
}
continue; // jump to the next item in the list
default:
REGEX_ASSERT(false);
break;
}
first = false;
// Are we upper- or lower-casing this string?
if( rest )
{
typename std::basic_string<CharT, TraitsT, AllocT>::iterator ibegin = str.begin();
std::advance( ibegin, strpos );
typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator iend = ibegin;
std::advance( iend, sublen );
switch( rest )
{
case UPPER:
regex_toupper( ibegin, iend );
break;
case LOWER:
regex_tolower( ibegin, iend );
break;
default:
REGEX_ASSERT(false);
break;
}
}
// Are we upper- or lower-casing the next character?
if( next )
{
switch( next )
{
case UPPER:
traits_type::assign( str[strpos], regex_toupper( str[strpos] ) );
break;
case LOWER:
traits_type::assign( str[strpos], regex_tolower( str[strpos] ) );
break;
default:
REGEX_ASSERT(false);
break;
}
next = NIL;
}
strpos += sublen;
}
// If *first* is still true, then we never called str.replace, and the substitution
// string is empty. Erase the part of the string that the pattern matched.
if( first )
str.erase( strpos, strlen );
// return length of the substitution
return strpos - old_strpos;
}
template< typename CharT, typename TraitsT, typename AllocT >
static size_t _do_subst
(
rpattern_type const & pat,
std::basic_string<CharT, TraitsT, AllocT> & str,
basic_subst_results<CharT, TraitsT, AllocT> & results,
size_type pos,
size_type len
)
{
typedef std::basic_string<CharT, TraitsT, AllocT> string_type;
typedef typename basic_subst_results<CharT, TraitsT, AllocT>::backref_vector backref_vector;
results.m_pbackref_str = pat._save_backrefs() ? &( results.m_backref_str = str ) : &str;
results.m_ibegin = results.m_pbackref_str->begin();
size_t csubst = 0;
size_type stop_offset = results.m_pbackref_str->size();
if( len != rpattern_type::npos )
stop_offset = regex_min( size_t( pos + len ), stop_offset );
match_param<IterT> param( results.m_ibegin, results.m_ibegin, results.m_ibegin, 0, 0 );
std::advance( param.m_imatchbegin, pos );
std::advance( param.m_iend, stop_offset );
param.m_ibufferbegin = param.m_imatchbegin;
if( GLOBAL & pat.flags() )
{
bool const fAll = ( ALLBACKREFS == ( ALLBACKREFS & pat.flags() ) );
bool const fFirst = ( FIRSTBACKREFS == ( FIRSTBACKREFS & pat.flags() ) );
backref_vector rgtempbackrefs( results.m_rgbackrefs.get_allocator() ); // temporary vector used if fsave_backrefs
size_type pos_offset = 0; // keep track of how much the backref_str and
// the current string are out of sync
while( _do_try_match( pat, param, results.m_rgbackrefs, false ) )
{
backref_type const & br = param.m_prgbackrefs[0];
++csubst;
size_type match_length = std::distance( br.first, br.second );
pos = std::distance( results.m_ibegin, br.first );
size_type subst_length = _do_subst_internal( str, results, pat, pos + pos_offset, match_length );
if( pat._save_backrefs() )
{
pos += match_length;
pos_offset += ( subst_length - match_length );
// Handle specially the backref flags
if( fFirst )
{
rgtempbackrefs.push_back( br );
}
else if( fAll )
{
rgtempbackrefs.insert(
rgtempbackrefs.end(),
results.m_rgbackrefs.begin(),
results.m_rgbackrefs.end() );
}
else
{
rgtempbackrefs.swap( results.m_rgbackrefs );
}
}
else
{
pos += subst_length;
stop_offset += ( subst_length - match_length );
results.m_ibegin = results.m_pbackref_str->begin();
// we're not saving backref information, so we don't
// need to do any special backref maintenance here
}
// prevent a pattern that matches 0 characters from matching
// again at the same point in the string
param.m_no0len = ( 0 == match_length );
param.m_imatchbegin = results.m_ibegin;
std::advance( param.m_imatchbegin, pos ); // ineffecient for bidirectional iterators.
param.m_iend = results.m_ibegin;
std::advance( param.m_iend, stop_offset ); // ineffecient for bidirectional iterators.
}
// If we did special backref handling, swap the backref vectors
if( pat._save_backrefs() )
{
results.m_rgbackrefs.swap( rgtempbackrefs );
}
else if( ! results.m_rgbackrefs[0].matched )
{
results.m_rgbackrefs.clear();
}
}
else if( _do_try_match( pat, param, results.m_rgbackrefs, false ) )
{
backref_type const & br = param.m_prgbackrefs[0];
++csubst;
_do_subst_internal(
str, results, pat,
std::distance( results.m_ibegin, br.first ),
std::distance( br.first, br.second ) );
results.m_ibegin = results.m_pbackref_str->begin();
}
if( NOBACKREFS == ( pat.flags() & NOBACKREFS ) )
{
results.m_rgbackrefs.clear();
}
return csubst;
}
static instantiator instantiate()
{
return instantiator_helper
(
®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 by process_escapes
//
template< typename CharT >
inline bool regex_isxdigit( CharT ch )
{
return ( REGEX_CHAR(CharT,'0') <= ch && REGEX_CHAR(CharT,'9') >= ch )
|| ( REGEX_CHAR(CharT,'a') <= ch && REGEX_CHAR(CharT,'f') >= ch )
|| ( REGEX_CHAR(CharT,'A') <= ch && REGEX_CHAR(CharT,'F') >= ch );
}
template< typename CharT >
inline int regex_xdigit2int( CharT ch )
{
if( REGEX_CHAR(CharT,'a') <= ch && REGEX_CHAR(CharT,'f') >= ch )
return ch - REGEX_CHAR(CharT,'a') + 10;
if( REGEX_CHAR(CharT,'A') <= ch && REGEX_CHAR(CharT,'F') >= ch )
return ch - REGEX_CHAR(CharT,'A') + 10;
return ch - REGEX_CHAR(CharT,'0');
}
} // namespace detail
// --------------------------------------------------------------------------
//
// Function: process_escapes
//
// Description: Turn the escape sequnces /f /n /r /t /v // into their
// ASCII character equivalents. Also, optionally process
// perl escape sequences.
//
// Returns: void
//
// Arguments: str - the string to process
// fPattern - true if the string is to be processed as a regex
//
// Notes: When fPattern is true, the perl escape sequences are not
// processed. If there is an octal or hex excape sequence, we
// don't want to turn it into a regex metacharacter here. We
// leave it unescaped so the regex parser correctly interprests
// it as a character literal.
//
// History: 8/1/2001 - ericne - Created
//
// --------------------------------------------------------------------------
template< typename CharT, typename TraitsT, typename AllocT >
inline void process_escapes( std::basic_string<CharT, TraitsT, AllocT> & str, bool fPattern ) //throw()
{
typedef typename std::basic_string<CharT, TraitsT, AllocT>::size_type size_type;
size_type i = 0;
size_type const npos = std::basic_string<CharT, TraitsT, AllocT>::npos;
if( str.empty() )
return;
while( npos != ( i = str.find( REGEX_CHAR(CharT,'//'), i ) ) )
{
if( str.size() - 1 == i )
return;
switch( str[i+1] )
{
case REGEX_CHAR(CharT,'a'):
str.replace( i, 2, 1, REGEX_CHAR(CharT,'/a') );
break;
case REGEX_CHAR(CharT,'b'):
if( ! fPattern )
str.replace( i, 2, 1, REGEX_CHAR(CharT,'/b') );
else
++i;
break;
case REGEX_CHAR(CharT,'e'):
str.replace( i, 2, 1, CharT( 27 ) );
break;
case REGEX_CHAR(CharT,'f'):
str.replace( i, 2, 1, REGEX_CHAR(CharT,'/f') );
break;
case REGEX_CHAR(CharT,'n'):
str.replace( i, 2, 1, REGEX_CHAR(CharT,'/n') );
break;
case REGEX_CHAR(CharT,'r'):
str.replace( i, 2, 1, REGEX_CHAR(CharT,'/r') );
break;
case REGEX_CHAR(CharT,'t'):
str.replace( i, 2, 1, REGEX_CHAR(CharT,'/t') );
break;
case REGEX_CHAR(CharT,'v'):
str.replace( i, 2, 1, REGEX_CHAR(CharT,'/v') );
break;
case REGEX_CHAR(CharT,'//'):
if( fPattern )
{
if( i+3 < str.size() && REGEX_CHAR(CharT,'//') == str[i+2] && REGEX_CHAR(CharT,'//') == str[i+3] )
str.erase( i, 2 );
++i;
}
else
str.erase( i, 1 );
break;
case REGEX_CHAR(CharT,'0'): case REGEX_CHAR(CharT,'1'): case REGEX_CHAR(CharT,'2'): case REGEX_CHAR(CharT,'3'):
case REGEX_CHAR(CharT,'4'): case REGEX_CHAR(CharT,'5'): case REGEX_CHAR(CharT,'6'): case REGEX_CHAR(CharT,'7'):
if( ! fPattern )
{
size_t j=i+2;
CharT ch = CharT( str[i+1] - REGEX_CHAR(CharT,'0') );
for( ; j-i < 4 && j < str.size() && REGEX_CHAR(CharT,'0') <= str[j] && REGEX_CHAR(CharT,'7') >= str[j]; ++j )
ch = CharT( ch * 8 + ( str[j] - REGEX_CHAR(CharT,'0') ) );
str.replace( i, j-i, 1, ch );
}
break;
case REGEX_CHAR(CharT,'x'):
if( ! fPattern )
{
CharT ch = 0;
size_t j=i+2;
for( ; j-i < 4 && j < str.size() && detail::regex_isxdigit( str[j] ); ++j )
ch = CharT( ch * 16 + detail::regex_xdigit2int( str[j] ) );
str.replace( i, j-i, 1, ch );
}
break;
case REGEX_CHAR(CharT,'c'):
if( ! fPattern && i+2 < str.size() )
{
CharT ch = str[i+2];
if( REGEX_CHAR(CharT,'a') <= ch && REGEX_CHAR(CharT,'z') >= ch )
ch = detail::regex_toupper( ch );
str.replace( i, 3, 1, CharT( ch ^ 0x40 ) );
}
break;
default:
if( fPattern )
++i;
else
str.erase( i, 1 );
break;
}
++i;
if( str.size() <= i )
return;
}
}
#endif
//+---------------------------------------------------------------------------
//
// Copyright ( C ) Microsoft, 1994 - 2002.
//
// File: syntax2.cpp
//
// Contents: data definitions for the syntax modules
//
// Classes:
//
// Functions:
//
// Coupling:
//
// Notes:
//
// Author: Eric Niebler ( [email protected] )
//
// History: 3-29-00 ericne Created
//
//----------------------------------------------------------------------------
#include "syntax2.h"
namespace regex
{
REGEX_SELECTANY TOKEN const perl_syntax_base::s_rgreg[ UCHAR_MAX + 1 ] =
{
/* 0*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 8*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 16*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 24*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 32*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, END_LINE, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 40*/ BEGIN_GROUP, END_GROUP, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, MATCH_ANY, NO_TOKEN,
/* 48*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 56*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 64*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 72*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 80*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 88*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, BEGIN_CHARSET, ESCAPE, NO_TOKEN, BEGIN_LINE, NO_TOKEN,
/* 96*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/*104*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/*112*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/*120*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN, ALTERNATION, NO_TOKEN, NO_TOKEN, NO_TOKEN
// and the rest are 0...
};
REGEX_SELECTANY TOKEN const perl_syntax_base::s_rgescape[ UCHAR_MAX + 1 ] =
{
/* 0*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 8*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 16*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 24*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 32*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 40*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 48*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 56*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 64*/ NO_TOKEN, ESC_BEGIN_STRING, ESC_NOT_WORD_BOUNDARY, NO_TOKEN,
ESC_NOT_DIGIT, ESC_QUOTE_META_OFF, NO_TOKEN, NO_TOKEN,
/* 72*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 80*/ NO_TOKEN, ESC_QUOTE_META_ON, NO_TOKEN, ESC_NOT_SPACE,
NO_TOKEN, NO_TOKEN, NO_TOKEN, ESC_NOT_WORD,
/* 88*/ NO_TOKEN, NO_TOKEN, ESC_END_STRING, NO_TOKEN,
NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/* 96*/ NO_TOKEN, NO_TOKEN, ESC_WORD_BOUNDARY, NO_TOKEN,
ESC_DIGIT, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/*104*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN,
/*112*/ NO_TOKEN, NO_TOKEN, NO_TOKEN, ESC_SPACE,
NO_TOKEN, NO_TOKEN, NO_TOKEN, ESC_WORD,
/*120*/ NO_TOKEN, NO_TOKEN, ESC_END_STRING_z, NO_TOKEN,
NO_TOKEN, NO_TOKEN, NO_TOKEN, NO_TOKEN
// and the rest are 0...
};
namespace detail
{
REGEX_SELECTANY extern posix_charset_type const g_rgposix_charsets[] =
{
{ "[:alnum:]", 9 },
{ "[:^alnum:]", 10 },
{ "[:alpha:]", 9 },
{ "[:^alpha:]", 10 },
{ "[:blank:]", 9 },
{ "[:^blank:]", 10 },
{ "[:cntrl:]", 9 },
{ "[:^cntrl:]", 10 },
{ "[:digit:]", 9 },
{ "[:^digit:]", 10 },
{ "[:graph:]", 9 },
{ "[:^graph:]", 10 },
{ "[:lower:]", 9 },
{ "[:^lower:]", 10 },
{ "[:print:]", 9 },
{ "[:^print:]", 10 },
{ "[:punct:]", 9 },
{ "[:^punct:]", 10 },
{ "[:space:]", 9 },
{ "[:^space:]", 10 },
{ "[:upper:]", 9 },
{ "[:^upper:]", 10 },
{ "[:xdigit:]", 10 },
{ "[:^xdigit:]", 11 }
};
REGEX_SELECTANY extern size_t const g_cposix_charsets = ARRAYSIZE( g_rgposix_charsets );
} // namespace detail
} // namespace regex
/***
*resetstk - Recover from Stack overflow.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* Defines the _resetstkoflw() function.
*
*******************************************************************************/
#if defined(_MSC_VER) & _MSC_VER < 1300
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>
#define MIN_STACK_REQ_WIN9X 0x11000
#define MIN_STACK_REQ_WINNT 0x2000
#ifdef _WIN64
typedef unsigned __int64 REGEX_DWORD_PTR;
#else
typedef unsigned __int32 REGEX_DWORD_PTR;
#endif
struct osplatform_getter
{
int m_osplatform;
osplatform_getter() : m_osplatform( 0 )
{
OSVERSIONINFOA osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
if( GetVersionExA( & osvi ) )
m_osplatform = osvi.dwPlatformId;
}
};
inline int get_osplatform()
{
static osplatform_getter const s_osplatform_getter;
return s_osplatform_getter.m_osplatform;
};
/***
* void _resetstkoflw(void) - Recovers from Stack Overflow
*
* Purpose:
* Sets the guard page to its position before the stack overflow.
*
* Exit:
* Returns nonzero on success, zero on failure
*
*******************************************************************************/
extern "C" int __cdecl _resetstkoflw(void)
{
LPBYTE pStack, pGuard, pStackBase, pMinGuard;
MEMORY_BASIC_INFORMATION mbi;
SYSTEM_INFO si;
DWORD PageSize;
DWORD flNewProtect;
DWORD flOldProtect;
// Use _alloca() to get the current stack pointer
pStack = static_cast<LPBYTE>( _alloca(1) );
// Find the base of the stack.
if (VirtualQuery(pStack, &mbi, sizeof mbi) == 0)
return 0;
pStackBase = static_cast<LPBYTE>( mbi.AllocationBase );
// Find the page just below where the stack pointer currently points.
// This is the new guard page.
GetSystemInfo(&si);
PageSize = si.dwPageSize;
pGuard = (LPBYTE) (((REGEX_DWORD_PTR)pStack & ~(REGEX_DWORD_PTR)(PageSize - 1))
- PageSize);
// If the potential guard page is too close to the start of the stack
// region, abandon the reset effort for lack of space. Win9x has a
// larger reserved stack requirement.
pMinGuard = pStackBase + ((get_osplatform() == VER_PLATFORM_WIN32_WINDOWS)
? MIN_STACK_REQ_WIN9X
: MIN_STACK_REQ_WINNT);
if (pGuard < pMinGuard)
return 0;
// On a non-Win9x system, release the stack region below the new guard
// page. This can't be done for Win9x because of OS limitations.
if (get_osplatform() != VER_PLATFORM_WIN32_WINDOWS) {
if (pGuard > pStackBase)
VirtualFree(pStackBase, pGuard - pStackBase, MEM_DECOMMIT);
VirtualAlloc(pGuard, PageSize, MEM_COMMIT, PAGE_READWRITE);
}
// Enable the new guard page.
flNewProtect = get_osplatform() == VER_PLATFORM_WIN32_WINDOWS
? PAGE_NOACCESS
: PAGE_READWRITE | PAGE_GUARD;
return VirtualProtect(pGuard, PageSize, flNewProtect, &flOldProtect);
}
#endif
//+---------------------------------------------------------------------------
//
// Copyright ( C ) Microsoft, 1994 - 2002.
//
// File: regexpr2.h
//
// Contents: classes for regular expression pattern matching a-la perl
//
// Classes: basic_rpattern_base
//
// Functions: rpattern::match
// rpattern::substitute
// match_results::cbackrefs
// match_results::backref
// match_results::all_backrefs
// match_results::backref_str
//
// Author: Eric Niebler ( [email protected] )
//
//----------------------------------------------------------------------------
#ifndef REGEXPR_H
#define REGEXPR_H
#ifdef _MSC_VER
// warning C4189: local variable is initialized but not referenced
// warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
// warning C4702: unreachable code
// warning C4710: function 'blah' not inlined
// warning C4786: identifier was truncated to '255' characters in the debug information
# pragma warning( push )
# pragma warning( disable : 4189 4290 4702 4710 4786 )
# define REGEX_SEH_STACK_OVERFLOW 0xC00000FDL
# if 1200 < _MSC_VER
# include <malloc.h> // for _resetstkoflw
# else
extern "C" int __cdecl _resetstkoflw(void);
# endif
extern "C" unsigned long __cdecl _exception_code(void);
#endif
#include <list>
#include <iosfwd>
#include <string>
#include <vector>
#include <memory>
#include <cwctype>
#include "syntax2.h"
#include "restack.h"
namespace regex
{
// This is the default alignment for the unsafe heterogeneous stack.
// If you are getting a compiler error in one of the unsafe_stack
// methods, then compile with -DREGEX_STACK_ALIGNMENT=16 or 32
#ifndef REGEX_STACK_ALIGNMENT
# define REGEX_STACK_ALIGNMENT sizeof( void* )
#endif
#if !defined( REGEX_DEBUG ) & ( defined( DEBUG ) | defined( _DEBUG ) | defined( DBG ) )
# define REGEX_DEBUG 1
#else
# define REGEX_DEBUG 0
#endif
#if !defined( REGEX_DEBUG_ITERATORS ) & defined( _HAS_ITERATOR_DEBUGGING )
# define REGEX_DEBUG_ITERATORS 1
#else
# define REGEX_DEBUG_ITERATORS 0
#endif
namespace detail
{
#if REGEX_DEBUG | REGEX_DEBUG_ITERATORS
// Turn on hetero_stack's run-time type checking
typedef hetero_stack<REGEX_STACK_ALIGNMENT,true,false,32,0> unsafe_stack;
#else
// Assume that all types pushed on stack have trivial destructors.
typedef hetero_stack<REGEX_STACK_ALIGNMENT,false,true,4096,1024> unsafe_stack;
#endif
// Used to initialize variables with the same value they would have
// if they were initialized as a static global. ( Ptrs get NULL,
// integer types get 0, etc, etc )
template< typename T > struct static_init { static T const value; };
template< typename T > T const static_init<T>::value = T();
//
// Forward declarations
//
template< typename IterT > class sub_expr;
template< typename IterT > class match_group_base;
template< typename IterT > class basic_rpattern_base_impl;
template< typename IterT > struct match_param;
template< typename IterT > struct sub_expr_base;
template< typename IterT > struct regex_access;
// an iterator that keeps track of whether it is singular or not.
template< typename IterT > struct smart_iter
{
IterT m_iter;
bool m_valid;
smart_iter()
: m_iter( static_init<IterT>::value )
, m_valid( false )
{
}
smart_iter( smart_iter const & rhs )
: m_iter( rhs.m_iter )
, m_valid( rhs.m_valid )
{
}
smart_iter( IterT iter ) // implicit conversion OK!
: m_iter( iter )
, m_valid( true )
{
}
smart_iter & operator=( smart_iter const & rhs )
{
m_iter = rhs.m_iter;
m_valid = rhs.m_valid;
return *this;
}
friend bool operator==( smart_iter const & lhs, smart_iter const & rhs )
{
if( !lhs.m_valid || !rhs.m_valid )
return lhs.m_valid == rhs.m_valid;
else
return lhs.m_iter == rhs.m_iter;
}
friend bool operator!=( smart_iter const & lhs, smart_iter const & rhs )
{
return ! operator==( lhs, rhs );
}
};
template< typename IterT > struct iter_select
{
typedef typename select
<
REGEX_DEBUG_ITERATORS && !is_scalar<IterT>::value,
smart_iter<IterT>,
IterT
>::type type;
};
template< int SizeT > struct type_with_size { char buffer[ SizeT ]; };
// make up for the fact that the VC6 std::allocator does
// not have template constructors
template< typename ToT, typename FromT >
std::allocator<ToT> convert_allocator( std::allocator<FromT>, int )
{
return std::allocator<ToT>();
}
template< typename ToT, typename FromT >
FromT const & REGEX_CDECL convert_allocator( FromT const & from, ... )
{
return from;
}
template< int > struct rebind_helper;
// unknown allocator
template< typename T >
type_with_size<1> REGEX_CDECL allocator_picker( T const &, ... );
template<> struct rebind_helper<1>
{
template< typename AllocT, typename ElemT >
struct inner
{
REGEX_NVC6( typedef typename AllocT::template rebind<ElemT>::other type; )
};
};
// std::allocator
template< typename T >
type_with_size<2> allocator_picker( std::allocator<T> const &, int );
template<> struct rebind_helper<2>
{
template< typename, typename ElemT >
struct inner
{
typedef std::allocator<ElemT> type;
};
};
template< typename AllocT, typename ElemT >
struct rebind
{
enum { alloc_type = sizeof(allocator_picker(factory<AllocT>::make(),0)) };
typedef typename rebind_helper<alloc_type>::template inner<AllocT,ElemT>::type type;
};
}
// --------------------------------------------------------------------------
//
// Class: width_type
//
// Description: represents the width of a sub-expression
//
// Members: m_min - smallest number of characters a sub-expr can span
// m_max - largest number of characters a sub-expr can span
//
// History: 8/14/2000 - ericne - Created
//
// --------------------------------------------------------------------------
struct width_type
{
size_t m_min;
size_t m_max;
};
inline width_type const uninit_width()
{
width_type const width = { size_t( -1 ), size_t( -1 ) };
return width;
}
// Helper function for processing escape sequences
template< typename CharT, typename TraitsT, typename AllocT >
void process_escapes( std::basic_string<CharT, TraitsT, AllocT> & str, bool fPattern = false ); //throw()
// --------------------------------------------------------------------------
//
// Class: backref_tag
//
// Description: Struct which contains a back-reference. It is a template
// on the iterator type.
//
// Methods: backref_tag - c'tor
// operator bool - so that if( br ) is true if this br matched
// operator! - inverse of operator bool()
//
// Members: reserved - move along, nothing to see here
//
// History: 8/9/2001 - ericne - Created
//
// --------------------------------------------------------------------------
template< typename IterT >
class backref_tag : public std::pair<IterT, IterT>
{
struct detail_t { detail_t * d; };
template< typename OStreamT, typename OtherT >
void REGEX_CDECL _do_print( OStreamT & sout, OtherT, ... ) const
{
typedef typename OStreamT::char_type char_type;
typedef typename OStreamT::traits_type traits_type;
std::ostreambuf_iterator<char_type, traits_type> iout( sout );
for( IterT iter = first; iter != second; ++iter, ++iout )
*iout = *iter;
}
// overload that is optimized for bare char*
template< typename OStreamT >
void _do_print( OStreamT & sout, typename OStreamT::char_type const *, int ) const
{
sout.write( first, static_cast<std::streamsize>( std::distance( first, second ) ) );
}
public:
typedef IterT iterator_type;
typedef typename std::iterator_traits<IterT>::value_type char_type;
typedef std::basic_string<char_type> string_type;
typedef typename detail::iter_select<IterT>::type smart_iter_type;
explicit backref_tag
(
IterT i1 = detail::static_init<IterT>::value,
IterT i2 = detail::static_init<IterT>::value
)
: std::pair<IterT, IterT>( i1, i2 )
, matched( false )
, reserved1( i1 )
, reserved2( 0 )
, reserved3( false )
, reserved4( detail::static_init<smart_iter_type>::value )
, reserved5( detail::static_init<smart_iter_type>::value )
{
}
IterT begin() const
{
return first;
}
IterT end() const
{
return second;
}
string_type const str() const
{
return matched ? string_type( first, second ) : string_type();
}
// Use the "safe bool" idiom. This allows implicit conversion to bool,
// but not to int. It also disallows conversion to void*.
typedef detail_t * detail_t::* bool_type;
operator bool_type() const //throw()
{
return matched ? &detail_t::d : 0;
}
bool operator!() const //throw()
{
return ! matched;
}
template< typename CharT, typename TraitsT >
std::basic_ostream<CharT, TraitsT> & print( std::basic_ostream<CharT, TraitsT> & sout ) const
{
_do_print( sout, IterT(), 0 );
return sout;
}
bool matched;
//private:
IterT reserved1; // used for internal book-keeping
size_t reserved2; // used for internal book-keeping
bool reserved3; // used for internal book-keeping
smart_iter_type reserved4; // used for internal book-keeping
smart_iter_type reserved5; // used for internal book-keeping
};
//namespace detail
//{
// indexing into the backref vector is faster if the backref_tag struct
// has a size that is a power of 2.
//static static_assert<32==sizeof(backref_tag<char*>)> const check_backref_size;
//}
// --------------------------------------------------------------------------
//
// Class: basic_match_results
//
// Description: Use this structure for returning match/substitute results
// out from the match()/substitute() methods.
//
// Methods: cbackrefs -
// backref -
// all_backrefs -
// rlength -
//
// Members: m_rgbackrefs -
//
// Typedefs: const_iterator -
// backref_type -
// backref_vector -
//
// History: 8/8/2001 - ericne - Created
//
// --------------------------------------------------------------------------
template
<
typename IterT,
typename AllocT = std::allocator< REGEX_DEPENDENT_TYPENAME std::iterator_traits<IterT>::value_type >
>
struct basic_match_results
{
// const_iterator is deprecated. Use iterator_type instead.
REGEX_DEPRECATED typedef IterT const_iterator;
typedef IterT iterator_type;
typedef backref_tag<IterT> backref_type;
typedef typename detail::rebind<AllocT, backref_type>::type allocator_type;
typedef std::vector<backref_type, allocator_type> backref_vector;
friend struct detail::regex_access<IterT>;
explicit basic_match_results( allocator_type const & alloc = allocator_type() )
: m_rgbackrefs( alloc )
{
}
virtual ~basic_match_results()
{
}
size_t cbackrefs() const //throw()
{
return m_rgbackrefs.size();
}
backref_type const & backref( size_t cbackref ) const //throw( std::out_of_range )
{
return m_rgbackrefs.at( cbackref );
}
backref_vector const & all_backrefs() const //throw()
{
return m_rgbackrefs;
}
size_t rstart( size_t cbackref = 0 ) const //throw( std::out_of_range )
{
return std::distance( m_ibegin, m_rgbackrefs.at( cbackref ).first );
}
size_t rlength( size_t cbackref = 0 ) const //throw( std::out_of_range )
{
return std::distance( m_rgbackrefs.at( cbackref ).first, m_rgbackrefs.at( cbackref ).second );
}
private:
backref_vector m_rgbackrefs;
IterT m_ibegin;
};
// Unnecessary and deprecated
template< typename CharT, typename AllocT = std::allocator<CharT> >
struct basic_match_results_c : public basic_match_results<CharT const *, AllocT>
{
typedef basic_match_results<CharT const *, AllocT> base;
REGEX_DEPRECATED typedef typename base::const_iterator const_iterator;
typedef typename base::iterator_type iterator_type;
typedef typename base::backref_type backref_type;
typedef typename base::allocator_type allocator_type;
typedef typename base::backref_vector backref_vector;
explicit basic_match_results_c( allocator_type const & alloc = allocator_type() )
: basic_match_results<CharT const *, AllocT>( alloc )
{
}
};
template< typename CharT, typename TraitsT, typename AllocT >
struct subst_results_base
{
typedef typename detail::rebind<AllocT, CharT>::type char_allocator_type;
typedef std::basic_string<CharT, TraitsT, char_allocator_type> string_type;
typedef typename string_type::const_iterator iterator_type;
typedef basic_match_results<iterator_type,AllocT> type;
};
//
// For storing the results of a substitute() operation
//
template
<
typename CharT,
typename TraitsT = std::char_traits<CharT>,
typename AllocT = std::allocator<CharT>
>
struct basic_subst_results : public subst_results_base<CharT, TraitsT, AllocT>::type
{
typedef typename detail::rebind<AllocT, CharT>::type char_allocator_type;
typedef std::basic_string<CharT, TraitsT, char_allocator_type> string_type;
typedef typename string_type::const_iterator iterator_type;
typedef basic_match_results<iterator_type, AllocT> base;
typedef typename base::backref_type backref_type;
typedef typename base::allocator_type allocator_type;
typedef typename base::backref_vector backref_vector;
friend struct detail::regex_access<iterator_type>;
explicit basic_subst_results( allocator_type const & alloc = allocator_type() )
: basic_match_results< iterator_type, AllocT >( alloc )
, m_backref_str( detail::convert_allocator<CharT>( alloc, 0 ) )
, m_pbackref_str( &m_backref_str )
{
}
string_type const & backref_str() const //throw()
{
return *m_pbackref_str;
}
private:
string_type m_backref_str;
string_type const * m_pbackref_str;
};
template< typename CharT, typename TraitsT, typename AllocT >
struct split_results_base
{
typedef typename detail::rebind<AllocT, CharT>::type char_allocator_type;
typedef std::basic_string<CharT, TraitsT, char_allocator_type> string_type;
typedef typename detail::rebind<AllocT, string_type>::type allocator_type;
typedef std::vector<string_type,allocator_type> type;
};
//
// For storing the results of a split() operation
//
template
<
typename CharT,
typename TraitsT = std::char_traits<CharT>,
typename AllocT = std::allocator<CharT>
>
struct basic_split_results : private split_results_base<CharT, TraitsT, AllocT>::type
{
typedef CharT char_type;
typedef typename detail::rebind<AllocT, CharT>::type char_allocator_type;
typedef std::basic_string<CharT, TraitsT, char_allocator_type> string_type;
typedef typename detail::rebind<AllocT, string_type>::type allocator_type;
typedef std::vector<string_type,allocator_type> string_vector;
typedef string_vector base;
explicit basic_split_results( allocator_type const & alloc = allocator_type() )
: base( alloc )
{
}
#if !defined(_MSC_VER) | 1200 < _MSC_VER
typedef typename allocator_type::pointer pointer;
typedef typename allocator_type::const_pointer const_pointer;
#else
typedef string_type * pointer;
typedef string_type const * const_pointer;
#endif
// shortcuts to the most basic read-only container operations
typedef typename base::size_type size_type;
typedef typename base::difference_type difference_type;
typedef typename base::value_type value_type;
typedef typename base::reference reference;
typedef typename base::const_reference const_reference;
typedef typename base::iterator iterator;
typedef typename base::const_iterator const_iterator;
typedef typename base::reverse_iterator reverse_iterator;
typedef typename base::const_reverse_iterator const_reverse_iterator;
using base::begin;
using base::end;
using base::rbegin;
using base::rend;
using base::operator[];
using base::at;
using base::size;
using base::front;
using base::back;
string_vector & strings()
{
return *this;
}
string_vector const & strings() const
{
return *this;
}
};
//
// The REGEX_MODE is a way of controlling how matching occurs.
//
enum REGEX_MODE
{
MODE_FAST, // Uses the fast, recursive algorithm. Could overflow stack.
MODE_SAFE, // Uses the slow, iterative algorithm. Can't overflow stack.
MODE_MIXED, // Uses a heuristic to automatically determine which algorithm
// is the most appropriate for this pattern.
// MS VC++ has structured exception handling, which makes the
// consequences of a stack overflow much less severe. Because of this,
// it is possible to use the "fast" algorithm always on MS platforms,
#ifdef _MSC_VER
MODE_DEFAULT = MODE_FAST
#else
MODE_DEFAULT = MODE_MIXED
#endif
};
//
// helper function for resetting the intrinsic character sets.
// This should be called after changing the locale with setlocale()
//
template< typename CharT >
void reset_intrinsic_charsets( CharT ch = CharT( 0 ) );
// This is for implementation details that really belong in the
// cpp file, but can't go there because of template strangeness.
#include "reimpl2.h"
// --------------------------------------------------------------------------
//
// Class: basic_rpattern_base
//
// Description:
//
// Methods: basic_rpattern_base - c'tor
// basic_rpattern_base -
// basic_rpattern_base -
// init - ( re )initialize the pattern
// init -
// set_substitution - set the substitution string
// _find_next_group - parse the next group of the pattern
// _find_next - parse the next sub_expr of the pattern
// _find_atom - parse the next atom of the pattern
// _quantify - quantify the sub_expr
// _common_init - perform some common initialization tasks
// _parse_subst - parse the substitution string
// _add.m_subst_backref - add a backref node to the subst list
//
// Members: m_invisible_groups - list of hidden groups
//
// Typedefs: syntax_type -
// backref_type -
// backref_vector -
// string_type -
// size_type -
//
// History: 8/14/2000 - ericne - Created
// 8/5/2001 - ericne - complete overhaul
//
// --------------------------------------------------------------------------
template< typename IterT, typename SyntaxT >
class basic_rpattern_base : protected detail::basic_rpattern_base_impl<IterT>
{
protected:
typedef detail::basic_rpattern_base_impl<IterT> impl;
public:
typedef SyntaxT syntax_type;
typedef typename impl::char_type char_type;
typedef typename impl::traits_type traits_type;
typedef typename impl::string_type string_type;
typedef typename impl::size_type size_type;
typedef typename impl::backref_type backref_type;
typedef typename impl::backref_vector backref_vector;
void init
(
string_type const & pat,
REGEX_FLAGS flags = NOFLAGS,
REGEX_MODE mode = MODE_DEFAULT
); //throw( bad_regexpr, std::bad_alloc );
void init
(
string_type const & pat,
string_type const & subst,
REGEX_FLAGS flags = NOFLAGS,
REGEX_MODE mode = MODE_DEFAULT
); //throw( bad_regexpr, std::bad_alloc );
void set_substitution
(
string_type const & subst
); //throw( bad_regexpr, std::bad_alloc );
using impl::flags;
using impl::mode;
using impl::get_width;
using impl::cgroups;
using impl::get_pat;
using impl::get_subst;
using impl::swap;
using impl::npos;
protected:
basic_rpattern_base() //throw()
: detail::basic_rpattern_base_impl<IterT>()
{
}
basic_rpattern_base( basic_rpattern_base<IterT, SyntaxT> const & that ) //throw()
: detail::basic_rpattern_base_impl<IterT>( that.flags(), that.mode(), that.get_pat(), that.get_subst() )
{
// Don't call _normalize_string(). If that.flags()&NORMALIZE,
// then subst has already been normalized.
_common_init( this->m_flags );
_parse_subst( *this->m_subst, this->m_fuses_backrefs, this->m_subst_list ); // must come after _common_init
}
explicit basic_rpattern_base
(
string_type const & pat,
REGEX_FLAGS flags = NOFLAGS,
REGEX_MODE mode = MODE_DEFAULT
) //throw( bad_regexpr, std::bad_alloc )
: detail::basic_rpattern_base_impl<IterT>( flags, mode, pat )
{
_common_init( this->m_flags );
}
basic_rpattern_base
(
string_type const & pat,
string_type const & subst,
REGEX_FLAGS flags = NOFLAGS,
REGEX_MODE mode = MODE_DEFAULT
) //throw( bad_regexpr, std::bad_alloc )
: detail::basic_rpattern_base_impl<IterT>( flags, mode, pat, subst )
{
_common_init( this->m_flags );
_normalize_string( *this->m_subst );
_parse_subst( *this->m_subst, this->m_fuses_backrefs, this->m_subst_list ); // must come after _common_init
}
basic_rpattern_base & operator=
(
basic_rpattern_base<IterT, SyntaxT> const & that
) //throw( bad_regexpr, std::bad_alloc )
{
basic_rpattern_base<IterT, SyntaxT> temp( that );
swap( temp );
return *this;
}
detail::match_group_base<IterT> * _find_next_group
(
typename string_type::iterator & ipat,
detail::match_group_base<IterT> * pgroup, syntax_type & sy,
std::vector<detail::match_group_base<IterT>*> & rggroups
);
bool _find_next
(
typename string_type::iterator & ipat,
detail::match_group_base<IterT> * pgroup, syntax_type & sy,
std::vector<detail::match_group_base<IterT>*> & rggroups
);
void _find_atom
(
typename string_type::iterator & ipat,
detail::match_group_base<IterT> * pgroup,
syntax_type & sy
);
void _quantify
(
std::auto_ptr<detail::sub_expr<IterT> > & pnew,
typename string_type::iterator & ipat,
bool is_group,
syntax_type & sy
);
void _add_subst_backref
(
detail::subst_node & snode,
size_t nbackref,
ptrdiff_t rstart,
bool & uses_backrefs,
detail::subst_list_type & subst_list
) const;
void _parse_subst
(
string_type & subst,
bool & uses_backrefs,
detail::subst_list_type & subst_list
) const;
void _common_init( REGEX_FLAGS flags );
static detail::instantiator instantiate()
{
typedef basic_rpattern_base this_type;
return detail::instantiator_helper
(
&detail::basic_rpattern_base_impl<IterT>::instantiate,
static_cast<void (this_type::*)( string_type const &, REGEX_FLAGS, REGEX_MODE )>( &this_type::init ),
static_cast<void (this_type::*)( string_type const &, string_type const &, REGEX_FLAGS, REGEX_MODE )>( &this_type::init ),
&this_type::set_substitution,
&this_type::_find_next_group,
&this_type::_find_next,
&this_type::_find_atom,
&this_type::_add_subst_backref,
&this_type::_parse_subst,
&this_type::_common_init
);
}
};
// --------------------------------------------------------------------------
//
// Class: basic_rpattern
//
// Description: generic regex pattern object
//
// Methods: basic_rpattern - c'tor
// basic_rpattern -
// basic_rpattern -
// match - match from begin iter to end iter
// match - match a null-terminated string
// match - match a std::string
// count - count matches from begin iter to end iter
// count - count matches in a null-terminated string
// count - count matches in a std::string
// substitute - do substitutions in a std::string
// _do_match - internal implementation
// _do_count - internal implementation
//
// History: 8/13/2001 - ericne - Created
//
// --------------------------------------------------------------------------
template
<
typename IterT,
typename SyntaxT = perl_syntax<REGEX_DEPENDENT_TYPENAME std::iterator_traits<IterT>::value_type>
>
class basic_rpattern : public basic_rpattern_base<IterT, SyntaxT>
{
typedef detail::basic_rpattern_base_impl<IterT> impl;
template< typename CharT >
static void same_char_types( CharT, CharT ) {}
public:
typedef typename basic_rpattern_base<IterT, SyntaxT>::syntax_type syntax_type;
typedef typename basic_rpattern_base<IterT, SyntaxT>::char_type char_type;
typedef typename basic_rpattern_base<IterT, SyntaxT>::traits_type traits_type;
typedef typename basic_rpattern_base<IterT, SyntaxT>::string_type string_type;
typedef typename basic_rpattern_base<IterT, SyntaxT>::size_type size_type;
typedef typename basic_rpattern_base<IterT, SyntaxT>::backref_type backref_type;
typedef typename basic_rpattern_base<IterT, SyntaxT>::backref_vector backref_vector;
basic_rpattern() //throw()
: basic_rpattern_base<IterT, SyntaxT>()
{
}
basic_rpattern( basic_rpattern const & that )
: basic_rpattern_base<IterT, SyntaxT>( that )
{
}
explicit basic_rpattern
(
string_type const & pat,
REGEX_FLAGS flags = NOFLAGS,
REGEX_MODE mode = MODE_DEFAULT
) //throw( bad_regexpr, std::bad_alloc )
: basic_rpattern_base<IterT, SyntaxT>( pat, flags, mode )
{
}
basic_rpattern
(
string_type const & pat,
string_type const & subst,
REGEX_FLAGS flags = NOFLAGS,
REGEX_MODE mode = MODE_DEFAULT
) //throw( bad_regexpr, std::bad_alloc )
: basic_rpattern_base<IterT, SyntaxT>( pat, subst, flags, mode )
{
}
basic_rpattern & operator=( basic_rpattern<IterT, SyntaxT> const & that ) //throw( bad_regexpr, std::bad_alloc )
{
basic_rpattern_base<IterT, SyntaxT>::operator=( that );
return *this;
}
// Iter2 must be convertible to type IterT
template< typename OtherT, typename AllocT >
backref_type const & match
(
OtherT ibegin,
OtherT iend,
basic_match_results<IterT, AllocT> & results
) const
{
// If your compile breaks here, it is because OtherT is not
// convertible to type IterT. Check the declaration of your rpattern object.
detail::static_assert< detail::is_convertible<OtherT,IterT>::value > const iterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
if( detail::regex_access<IterT>::_do_match( *this, results, ibegin, iend, false ) )
{
return results.backref(0);
}
else
{
return detail::static_init<backref_type>::value;
}
}
template< typename CharT, typename AllocT >
backref_type const & match
(
CharT * szbegin,
basic_match_results<IterT, AllocT> & results
) const
{
// If your compile breaks here, it is because CharT* is not
// convertible to type IterT. Check the declaration of your rpattern object.
detail::static_assert< detail::is_convertible<CharT*,IterT>::value > const iterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
if( detail::regex_access<IterT>::_do_match_c( *this, results, szbegin ) )
{
return results.backref(0);
}
else
{
return detail::static_init<backref_type>::value;
}
}
template< typename CharT, typename TraitsT, typename AllocT >
backref_type const & match
(
std::basic_string<CharT, TraitsT, AllocT> const & str,
basic_match_results<IterT, AllocT> & results,
size_type pos = 0,
size_type len = static_cast<size_type>(-1)
) const
{
// If your compile breaks here, it is because iter_type is not
// convertible to type IterT. Check the declaration of your rpattern object.
typedef typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator iter_type;
detail::static_assert< detail::is_convertible<iter_type,IterT>::value > const iterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
IterT ibegin = str.begin(), iend = str.begin();
if( len == npos || pos + len >= str.size() )
iend = IterT(str.end());
else
std::advance( iend, pos + len );
std::advance( ibegin, pos );
return match( ibegin, iend, results );
}
template< typename OtherT >
size_t count( OtherT ibegin, OtherT iend ) const
{
// If your compile breaks here, it is because OtherT is not
// convertible to type IterT. Check the declaration of your rpattern object.
detail::static_assert< detail::is_convertible<OtherT,IterT>::value > const iterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
return detail::regex_access<IterT>::_do_count( *this, ibegin, iend, false );
}
template< typename CharT >
size_t count( CharT * szbegin ) const
{
// If your compile breaks here, it is because CharT* is not
// convertible to type IterT. Check the declaration of your rpattern object.
detail::static_assert< detail::is_convertible<CharT*,IterT>::value > const iterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
return detail::regex_access<IterT>::_do_count( *this, szbegin, (CharT*)0, true );
}
template< typename CharT, typename TraitsT, typename AllocT >
size_t count
(
std::basic_string<CharT, TraitsT, AllocT> const & str,
size_type pos = 0,
size_type len = static_cast<size_type>(-1)
) const
{
// If your compile breaks here, it is because iter_type is not
// convertible to type IterT. Check the declaration of your rpattern object.
typedef typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator iter_type;
detail::static_assert< detail::is_convertible<iter_type,IterT>::value > const iterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
IterT ibegin = str.begin(), iend = str.begin();
if( len == npos || pos + len >= str.size() )
iend = IterT(str.end());
else
std::advance( iend, pos + len );
std::advance( ibegin, pos );
return count( ibegin, iend );
}
template< typename OtherT, typename CharT, typename TraitsT, typename AllocT >
size_t split
(
OtherT ibegin,
OtherT iend,
basic_split_results<CharT, TraitsT, AllocT> & results,
int limit = 0
) const
{
// If your compile breaks here, it is because OtherT is not
// convertible to type IterT. Check the declaration of your rpattern object.
detail::static_assert< detail::is_convertible<OtherT,IterT>::value > const iterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
return detail::regex_access<IterT>::_do_split( *this, results, ibegin, iend, limit, false );
}
template< typename Char1T, typename Char2T, typename TraitsT, typename AllocT >
size_t split
(
Char1T * szbegin,
basic_split_results<Char2T, TraitsT, AllocT> & results,
int limit = 0
) const
{
// If your compile breaks here, it is because Iter2 is not
// convertible to type IterT. Check the declaration of your rpattern object.
detail::static_assert< detail::is_convertible<Char1T*,IterT>::value > const iterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
// If your compile breaks here, it's because the string you passed in doesn't have
// the same character type as your split_results struct
same_char_types( Char1T(), Char2T() );
// If your compile breaks here, it is because CharT const * is not
// convertible to type IterT. Check the declaration of your rpattern object.
return detail::regex_access<IterT>::_do_split( *this, results, szbegin, (Char1T*)0, limit, true );
}
template< typename CharT, typename TraitsT, typename AllocT >
size_t split
(
std::basic_string<CharT, TraitsT, AllocT> const & str,
basic_split_results<CharT, TraitsT, AllocT> & results,
int limit = 0,
size_type pos = 0,
size_type len = static_cast<size_type>(-1)
) const
{
// If your compile breaks here, it is because iter_type is not
// convertible to type IterT. Check the declaration of your rpattern object.
typedef typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator iter_type;
detail::static_assert< detail::is_convertible<iter_type,IterT>::value > const iterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
IterT ibegin = str.begin(), iend = str.begin();
if( len == npos || pos + len >= str.size() )
iend = IterT(str.end());
else
std::advance( iend, pos + len );
std::advance( ibegin, pos );
return split( ibegin, iend, results, limit );
}
template< typename CharT, typename TraitsT, typename AllocT >
size_t substitute
(
std::basic_string<CharT, TraitsT, AllocT> & str,
basic_subst_results<CharT, TraitsT, AllocT> & results,
size_type pos = 0,
size_type len = static_cast<size_type>(-1)
) const
{
// If your compile breaks here, it is because iter_type is not
// convertible to type IterT. Check the declaration of your rpattern object.
typedef typename std::basic_string<CharT, TraitsT, AllocT>::const_iterator iter_type;
detail::static_assert< detail::is_convertible<iter_type,IterT>::value > const iterator_types_are_not_convertible;
( void ) iterator_types_are_not_convertible;
return detail::regex_access<IterT>::_do_subst( *this, str, results, pos, len );
}
};
// --------------------------------------------------------------------------
//
// Class: basic_rpattern_c
//
// Description: a pattern object optimized for matching C-style, NULL-
// terminated strings. It treats the null-terminator as
// the end-of-string condition.
//
// Methods: basic_rpattern_c - c'tor
// basic_rpattern_c -
// basic_rpattern_c -
// match - match a null-terminated string
// count - count matches in a null-terminated string
// _do_match_c - internal implementation
//
// History: 8/13/2001 - ericne - Created
//
// --------------------------------------------------------------------------
template< typename CharT, typename SyntaxT = perl_syntax<CharT> >
class basic_rpattern_c : public basic_rpattern_base<CharT const *, SyntaxT>
{
typedef detail::basic_rpattern_base_impl<CharT const *> impl;
public:
typedef typename basic_rpattern_base<CharT const *, SyntaxT>::syntax_type syntax_type;
typedef typename basic_rpattern_base<CharT const *, SyntaxT>::char_type char_type;
typedef typename basic_rpattern_base<CharT const *, SyntaxT>::traits_type traits_type;
typedef typename basic_rpattern_base<CharT const *, SyntaxT>::string_type string_type;
typedef typename basic_rpattern_base<CharT const *, SyntaxT>::size_type size_type;
typedef typename basic_rpattern_base<CharT const *, SyntaxT>::backref_type backref_type;
typedef typename basic_rpattern_base<CharT const *, SyntaxT>::backref_vector backref_vector;
basic_rpattern_c() //throw()
: basic_rpattern_base<CharT const *, SyntaxT>()
{
}
basic_rpattern_c( basic_rpattern_c const & that )
: basic_rpattern_base<CharT const *, SyntaxT>( that )
{
}
explicit basic_rpattern_c
(
string_type const & pat,
REGEX_FLAGS flags = NOFLAGS,
REGEX_MODE mode = MODE_DEFAULT
) //throw( bad_regexpr, std::bad_alloc )
: basic_rpattern_base<CharT const *, SyntaxT>( pat, flags, mode )
{
}
basic_rpattern_c & operator=( basic_rpattern_c<CharT, SyntaxT> const & that )
{
basic_rpattern_base<CharT const *, SyntaxT>::operator=( that );
return *this;
}
template< typename AllocT >
backref_type const & match
(
CharT const * szbegin,
basic_match_results_c<CharT, AllocT> & results
) const
{
if( detail::regex_access<CharT const*>::_do_match_c( *this, results, szbegin ) )
{
return results.backref(0);
}
else
{
return detail::static_init<backref_type>::value;
}
}
size_t count( CharT const * szbegin ) const
{
return detail::regex_access<CharT const*>::_do_count( *this, szbegin, (CharT const*)0, true );
}
};
#if defined(UNICODE) | defined(_UNICODE)
typedef wchar_t rechar_t;
#else
typedef char rechar_t;
#endif
typedef std::basic_string<rechar_t> restring;
// On many implementations of the STL, string::iterator is not a typedef
// for char*. Rather, it is a wrapper class. As a result, the regex code
// gets instantiated twice, once for bare pointers (rpattern_c) and once for
// the wrapped pointers (rpattern). But if there is a conversion from the
// bare ptr to the wrapped ptr, then we only need to instantiate the template
// for the wrapped ptr, and the code will work for the bare ptrs, too.
// This can be a significant space savings. The REGEX_FOLD_INSTANTIONS
// macro controls this optimization. The default is "off" for backwards
// compatibility. To turn the optimization on, compile with:
// -DREGEX_FOLD_INSTANTIATIONS=1
#ifndef REGEX_FOLD_INSTANTIATIONS
#define REGEX_FOLD_INSTANTIATIONS 0
#endif
typedef ::regex::detail::select
<
REGEX_FOLD_INSTANTIATIONS &&
detail::is_convertible<rechar_t const *,restring::const_iterator>::value,
restring::const_iterator,
rechar_t const *
>::type lpctstr_t;
// For matching against null-terminated strings
typedef basic_rpattern<lpctstr_t, perl_syntax<rechar_t> > perl_rpattern_c;
typedef basic_rpattern<lpctstr_t, posix_syntax<rechar_t> > posix_rpattern_c;
// For matching against std::strings
typedef basic_rpattern<restring::const_iterator, perl_syntax<rechar_t> > perl_rpattern;
typedef basic_rpattern<restring::const_iterator, posix_syntax<rechar_t> > posix_rpattern;
// Default to perl syntax
typedef perl_rpattern rpattern;
typedef perl_rpattern_c rpattern_c;
// typedefs for the commonly used match_results and subst_results
typedef basic_match_results<restring::const_iterator> match_results;
typedef basic_match_results<lpctstr_t> match_results_c;
typedef basic_subst_results<rechar_t> subst_results;
typedef basic_split_results<rechar_t> split_results;
#if defined(_MSC_VER) & 1200 < _MSC_VER
// These are no longer useful, and will go away in a future release
// You should be using the version without the _c
# pragma deprecated( basic_rpattern_c )
# pragma deprecated( basic_match_results_c )
#endif
#define STATIC_RPATTERN_EX( type, var, params ) /
static type const var params;
#define STATIC_RPATTERN( var, params ) /
STATIC_RPATTERN_EX( regex::rpattern, var, params )
#define STATIC_RPATTERN_C( var, params ) /
STATIC_RPATTERN_EX( regex::rpattern_c, var, params )
#if defined(_MSC_VER) & 1200 < _MSC_VER
#pragma deprecated(STATIC_RPATTERN_EX)
#endif
//
// ostream inserter operator for back-references
//
template< typename CharT, typename TraitsT, typename IterT >
inline std::basic_ostream<CharT, TraitsT> & operator<<
(
std::basic_ostream<CharT, TraitsT> & sout,
backref_tag<IterT> const & br
)
{
return br.print( sout );
}
} // namespace regex
//
// specializations for std::swap
//
namespace std
{
template<>
inline void swap( regex::detail::regex_arena & left, regex::detail::regex_arena & right )
{
left.swap( right );
}
template< typename IterT, typename SyntaxT >
inline void swap( regex::basic_rpattern_base<IterT, SyntaxT> & left, regex::basic_rpattern_base<IterT, SyntaxT> & right )
{
left.swap( right );
}
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif
//+---------------------------------------------------------------------------
//
// Copyright ( C ) Microsoft, 1994 - 2002.
//
// File: regexpr2.cpp
//
// Contents: implementation for rpattern methods, definitions for all the
// subexpression types used to perform the matching, the
// charset class definition .
//
// Classes: too many to list here
//
// Functions:
//
// Author: Eric Niebler ( [email protected] )
//
// History: 12-11-1998 ericne Created
// 01-05-2001 ericne Removed dependency on VC's choice
// of STL iterator types.
// 08-15-2001 ericne Removed regexpr class, moved match
// state to match_results container.
// 09-17-2001 nathann Add DEBUG_HEAP_SUPPORT
// 11-16-2001 ericne Add stack-conservative algorithm
//
//----------------------------------------------------------------------------
#ifdef _MSC_VER
// unlimited inline expansion ( compile with /Ob1 or /Ob2 )
# pragma inline_recursion( on )
# pragma inline_depth( 255 )
// warning C4127: conditional expression is constant
// warning C4355: 'this' : used in base member initializer list
// warning C4702: unreachable code
// warning C4710: function 'blah' not inlined
// warning C4786: identifier was truncated to '255' characters in the debug information
# pragma warning( push )
# pragma warning( disable : 4127 4355 4702 4710 4786 )
#endif
#include <limits>
#include <cctype>
#include <cwchar>
#include <memory>
#include <cwctype>
#include <malloc.h>
#include <algorithm>
#ifdef __MWERKS__
# include <alloca.h>
#endif
// If the implementation file has been included in the header, then we
// need to mark some functions as inline to prevent them from being multiply
// defined. But if the implementation file is not included in the header,
// we can't mark them as inline, otherwise the linker won't find them.
#ifdef REGEXPR_H
# define REGEXPR_H_INLINE inline
#else
# define REGEXPR_H_INLINE
# include "regexpr2.h"
#endif
#ifdef REGEX_TO_INCLUDE
# include REGEX_TO_INCLUDE
#endif
// $PORT$
// _alloca is not standard
#ifndef alloca
# define alloca _alloca
#endif
namespace regex
{
namespace detail
{
inline wctype_t REGEX_CDECL regex_wctype( char const * sz )
{
using namespace std;
return wctype( sz );
}
namespace
{
#ifdef __GLIBC__
struct regex_ctype_t
{
int m_ctype;
wctype_t m_wctype;
};
#define REGEX_DECL_CTYPE(desc) /
inline regex_ctype_t const & wct_ ## desc() /
{ /
static regex_ctype_t const s_wct = { _IS ## desc, regex_wctype(#desc) };/
return s_wct; /
}
REGEX_DECL_CTYPE(alnum)
REGEX_DECL_CTYPE(alpha)
REGEX_DECL_CTYPE(blank)
REGEX_DECL_CTYPE(cntrl)
REGEX_DECL_CTYPE(digit)
REGEX_DECL_CTYPE(graph)
REGEX_DECL_CTYPE(lower)
REGEX_DECL_CTYPE(print)
REGEX_DECL_CTYPE(punct)
REGEX_DECL_CTYPE(space)
REGEX_DECL_CTYPE(upper)
REGEX_DECL_CTYPE(xdigit)
regex_ctype_t const wct_zero = { 0, 0 };
inline regex_ctype_t & operator |= ( regex_ctype_t & lhs, regex_ctype_t const & rhs )
{
lhs.m_ctype |= rhs.m_ctype;
lhs.m_wctype |= rhs.m_wctype;
return lhs;
}
inline regex_ctype_t operator | ( regex_ctype_t lhs, regex_ctype_t const & rhs )
{
return lhs |= rhs;
}
inline int REGEX_CDECL regex_isctype( int ch, regex_ctype_t const & desc )
{
return __isctype( ch, desc.m_ctype );
}
inline int REGEX_CDECL regex_iswctype( wint_t wc, regex_ctype_t desc )
{
using namespace std;
return iswctype( wc, desc.m_wctype );
}
inline bool operator == ( regex_ctype_t const & lhs, regex_ctype_t const & rhs )
{
return lhs.m_ctype == rhs.m_ctype && lhs.m_wctype == rhs.m_wctype;
}
inline bool operator != ( regex_ctype_t const & lhs, regex_ctype_t const & rhs )
{
return lhs.m_ctype != rhs.m_ctype || lhs.m_wctype != rhs.m_wctype;
}
#else
typedef wctype_t regex_ctype_t;
#define REGEX_DECL_CTYPE(desc) /
inline regex_ctype_t const wct_ ## desc() /
{ /
static regex_ctype_t const s_wct = regex_wctype(#desc); /
return s_wct; /
}
REGEX_DECL_CTYPE(alnum)
REGEX_DECL_CTYPE(alpha)
REGEX_DECL_CTYPE(cntrl)
REGEX_DECL_CTYPE(digit)
REGEX_DECL_CTYPE(graph)
REGEX_DECL_CTYPE(lower)
REGEX_DECL_CTYPE(print)
REGEX_DECL_CTYPE(punct)
REGEX_DECL_CTYPE(space)
REGEX_DECL_CTYPE(upper)
REGEX_DECL_CTYPE(xdigit)
regex_ctype_t const wct_zero = 0;
#if defined(_MSC_VER) & ( _MSC_VER==1200 | defined(_CPPLIB_VER) )
inline regex_ctype_t const wct_blank() { return _BLANK; } // work around for bug in VC++
inline int REGEX_CDECL regex_isctype( int ch, regex_ctype_t desc )
{
return _isctype( ch, static_cast<int>( desc ) );
}
#else
REGEX_DECL_CTYPE(blank)
inline int REGEX_CDECL regex_isctype( int ch, regex_ctype_t desc )
{
using namespace std;
return iswctype( btowc( ch ), desc );
}
#endif
inline int REGEX_CDECL regex_iswctype( wint_t wc, regex_ctype_t desc )
{
using namespace std;
return iswctype( wc, desc );
}
#endif
} // unnamed namespace
template< typename CStringsT, typename IterT >
bool _do_match_iterative( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur, CStringsT );
// NathanN:
// By defining the symbol REGEX_DEBUG_HEAP the allocator object
// no longer sub allocates memory. This enables heap checking tools like
// AppVerifier & PageHeap to find errors like buffer overruns
#if !defined( REGEX_DEBUG_HEAP ) & REGEX_DEBUG
# define REGEX_DEBUG_HEAP 1
#else
# define REGEX_DEBUG_HEAP 0
#endif
REGEXPR_H_INLINE size_t DEFAULT_BLOCK_SIZE()
{
#if REGEX_DEBUG_HEAP
// put each allocation in its own mem_block
return 1;
#else
// put multiple allocation in each mem_block
return 352;
#endif
}
template< typename IBeginT, typename IEndT >
inline size_t parse_int( IBeginT & ibegin, IEndT iend, size_t const max_ = size_t( -1 ) )
{
typedef typename std::iterator_traits<IEndT>::value_type char_type;
size_t retval = 0;
while( iend != ibegin && REGEX_CHAR(char_type,'0') <= *ibegin && REGEX_CHAR(char_type,'9') >= *ibegin && max_ > retval )
{
retval *= 10;
retval += static_cast<size_t>( *ibegin - REGEX_CHAR(char_type,'0') );
++ibegin;
}
if( max_ < retval )
{
retval /= 10;
--ibegin;
}
return retval;
}
// --------------------------------------------------------------------------
//
// Class: boyer_moore
//
// Description: fast sub-string search algorithm
//
// Members: m_begin - iter to first char in pattern sequence
// m_last - iter to last char in pattern sequence
// m_len - length of the pattern sequence
// m_off - array of offsets, indexed by ASCII char values
//
// History: 6/8/2003 - ericne - Created
//
// --------------------------------------------------------------------------
template< typename IterT >
class boyer_moore
{
typedef typename std::iterator_traits<IterT>::value_type char_type;
typedef typename std::char_traits<char_type> traits_type;
enum { OFFSET_SIZE = UCHAR_MAX + 1 };
IterT m_begin;
IterT m_last;
char_type const* m_low_last;
unsigned char m_len;
unsigned char m_off[ OFFSET_SIZE ];
static unsigned char hash_char( char ch ) { return static_cast<unsigned char>( ch ); }
static unsigned char hash_char( signed char ch ) { return static_cast<unsigned char>( ch ); }
static unsigned char hash_char( unsigned char ch ) { return ch; }
static unsigned char hash_char( wchar_t ch ) { return static_cast<unsigned char>( ch % OFFSET_SIZE ); }
template< typename CharT >
static unsigned char REGEX_VC6(REGEX_CDECL) hash_char( CharT ch REGEX_VC6(...) )
{
return static_cast<unsigned char>( std::char_traits<CharT>::to_int_type( ch ) % OFFSET_SIZE );
}
// case-sensitive Boyer-Moore search
template< typename OtherT >
OtherT find_with_case( OtherT begin, OtherT end ) const
{
typedef typename std::iterator_traits<OtherT>::difference_type diff_type;
diff_type const endpos = std::distance( begin, end );
diff_type offset = m_len;
for( diff_type curpos = offset; curpos < endpos; curpos += offset )
{
std::advance( begin, offset );
IterT pat_tmp = m_last;
OtherT str_tmp = begin;
for( ; traits_type::eq( *str_tmp, *pat_tmp );
--pat_tmp, --str_tmp )
{
if( pat_tmp == m_begin )
{
return str_tmp;
}
}
offset = m_off[ hash_char( *begin ) ];
}
return end;
}
// case-insensitive Boyer-Moore search
template< typename OtherT >
OtherT find_without_case( OtherT begin, OtherT end ) const
{
typedef typename std::iterator_traits<OtherT>::difference_type diff_type;
diff_type const endpos = std::distance( begin, end );
diff_type offset = m_len;
for( diff_type curpos = offset; curpos < endpos; curpos += offset )
{
std::advance( begin, offset );
IterT pat_tmp = m_last;
char_type const* low_tmp = m_low_last;
OtherT str_tmp = begin;
for( ; traits_type::eq( *str_tmp, *pat_tmp ) || traits_type::eq( *str_tmp, *low_tmp );
--pat_tmp, --str_tmp, --low_tmp )
{
if( pat_tmp == m_begin )
{
return str_tmp;
}
}
offset = m_off[ hash_char( *begin ) ];
}
return end;
}
public:
// initialize the Boyer-Moore search data structure, using the
// search sub-sequence to prime the pump.
boyer_moore( IterT begin, IterT end, char_type const* lower = 0 )
: m_begin( begin )
, m_last( begin )
, m_low_last( lower )
{
typedef typename std::iterator_traits<IterT>::difference_type diff_type;
diff_type diff = std::distance( begin, end );
m_len = static_cast<unsigned char>( regex_min<diff_type>( diff, UCHAR_MAX ) );
std::fill_n( m_off, ARRAYSIZE( m_off ), m_len );
--m_len;
for( unsigned char offset = m_len; offset; --offset, ++m_last )
{
m_off[ hash_char( *m_last ) ] = offset;
}
if( m_low_last )
{
for( unsigned char offset = m_len; offset; --offset, ++m_low_last )
{
unsigned char hash = hash_char( *m_low_last );
m_off[ hash ] = regex_min( m_off[ hash ], offset );
}
}
}
template< typename OtherT >
OtherT find( OtherT begin, OtherT end ) const
{
if( m_low_last )
{
return find_without_case( begin, end );
}
else
{
return find_with_case( begin, end );
}
}
static void * operator new( size_t size, regex_arena & arena )
{
return arena.allocate( size );
}
static void operator delete( void *, regex_arena & )
{
}
};
// This class is used to speed up character set matching by providing
// a bitset that spans the ASCII range. std::bitset is not used because
// the range-checking slows it down.
// Note: The division and modulus operations are optimized by the compiler
// into bit-shift operations.
class ascii_bitvector
{
typedef unsigned int elem_type;
enum
{
CBELEM = CHAR_BIT * sizeof( elem_type ), // count of bits per element
CELEMS = ( UCHAR_MAX+1 ) / CBELEM // number of element in array
};
elem_type m_rg[ CELEMS ];
// Used to inline operations like: bv1 |= ~bv2; without creating temp bit vectors.
struct not_ascii_bitvector
{
ascii_bitvector const & m_ref;
not_ascii_bitvector( ascii_bitvector const & ref )
: m_ref( ref ) {}
private:
not_ascii_bitvector & operator=( not_ascii_bitvector const & );
};
ascii_bitvector( ascii_bitvector const & );
ascii_bitvector & operator=( ascii_bitvector const & );
public:
ascii_bitvector()
{
zero();
}
void zero()
{
std::fill_n( m_rg, ARRAYSIZE( m_rg ), 0 );
}
void set( unsigned char ch )
{
m_rg[ ( ch / CBELEM ) ] |= ( ( elem_type )1U << ( ch % CBELEM ) );
}
bool operator[]( unsigned char ch ) const
{
return 0 != ( m_rg[ ( ch / CBELEM ) ] & ( ( elem_type )1U << ( ch % CBELEM ) ) );
}
not_ascii_bitvector const operator~() const
{
return not_ascii_bitvector( *this );
}
ascii_bitvector & operator|=( ascii_bitvector const & that )
{
for( int i=0; i<CELEMS; ++i )
m_rg[ i ] |= that.m_rg[ i ];
return *this;
}
ascii_bitvector & operator|=( not_ascii_bitvector const & that )
{
for( int i=0; i<CELEMS; ++i )
m_rg[ i ] |= ~that.m_ref.m_rg[ i ];
return *this;
}
};
typedef std::pair<wchar_t, wchar_t> range_type;
// determines if one range is less then another.
// used in binary search of range vector
struct range_less
{
bool operator()( range_type const & rg1, range_type const & rg2 ) const
{
return rg1.second < rg2.first;
}
};
// A singly-linked list, which works even if the allocator
// has per-instance state.
template< typename T, typename AllocT=std::allocator<T> >
class slist
{
struct cons
{
T car;
cons * cdr;
cons( T const & t, cons * nxt )
: car( t )
, cdr( nxt )
{
}
};
typedef typename rebind<AllocT, cons>::type cons_allocator;
typedef typename rebind<AllocT, char>::type char_allocator;
#if !defined(_MSC_VER) | 1200 < _MCS_VER
// Use the empty base optimization to avoid reserving
// space for the allocator if it is empty.
struct slist_impl : cons_allocator
{
cons * m_lst;
slist_impl( cons_allocator const & alloc, cons *lst )
: cons_allocator( alloc )
, m_lst( lst )
{
}
cons_allocator & allocator()
{
return *this;
}
};
#else
struct slist_impl
{
cons_allocator m_alloc;
cons *m_lst;
slist_impl( cons_allocator const & alloc, cons *lst )
: m_alloc( alloc )
, m_lst( lst )
{
}
cons_allocator & allocator()
{
return m_alloc;
}
};
#endif
slist_impl m_impl;
// find the previous node in the list (*prev(lst)==lst)
cons ** prev( cons *lst, cons *hint = 0 )
{
if( m_impl.m_lst == lst )
return &m_impl.m_lst;
if( !hint || hint->cdr != lst )
for( hint=m_impl.m_lst; hint->cdr != lst; hint=hint->cdr )
{}
return &hint->cdr;
}
public:
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef T const* const_pointer;
typedef T const& const_reference;
typedef size_t size_type;
struct iterator : public std::iterator<std::forward_iterator_tag, T>
{
friend class slist<T,AllocT>;
explicit iterator( cons * pcons = 0 )
: m_pcons( pcons )
{
}
T & operator*() const
{
return m_pcons->car;
}
T * operator->() const
{
return &m_pcons->car;
}
iterator & operator++()
{
m_pcons = m_pcons->cdr;
return *this;
}
iterator operator++( int )
{
iterator i( *this );
++*this;
return i;
}
bool operator==( iterator it )
{
return m_pcons == it.m_pcons;
}
bool operator!=( iterator it )
{
return m_pcons != it.m_pcons;
}
private:
cons * m_pcons;
};
// not ideal, but good enough for gov'ment work....
typedef iterator const_iterator;
explicit slist( char_allocator const & al = char_allocator() )
: m_impl( convert_allocator<cons>( al, 0 ), 0 )
{
}
~slist()
{
clear();
}
void clear()
{
for( cons *nxt; m_impl.m_lst; m_impl.m_lst=nxt )
{
nxt = m_impl.m_lst->cdr;
m_impl.allocator().destroy( m_impl.m_lst );
m_impl.allocator().deallocate( m_impl.m_lst, 1 );
}
}
void push_front( T const & t )
{
cons * lst = m_impl.allocator().allocate( 1, 0 );
try
{
m_impl.allocator().construct( lst, cons( t, m_impl.m_lst ) );
}
catch(...)
{
m_impl.allocator().deallocate( lst, 1 );
throw;
}
m_impl.m_lst = lst;
}
template< typename PredT >
void sort( PredT pred )
{
// simple insertion sort
cons *rst=m_impl.m_lst;
m_impl.m_lst = 0;
while( rst )
{
cons *cur=m_impl.m_lst, *prv=0;
while( cur && ! pred( rst->car, cur->car ) )
prv=cur, cur=cur->cdr;
if( prv )
prv->cdr=rst, rst=rst->cdr, prv->cdr->cdr=cur;
else
m_impl.m_lst=rst, rst=rst->cdr, m_impl.m_lst->cdr=cur;
}
}
void sort()
{
this->sort( std::less<T>() );
}
iterator begin() const
{
return iterator( m_impl.m_lst );
}
iterator end() const
{
return iterator();
}
bool empty() const
{
return 0 == m_impl.m_lst;
}
size_t size() const
{
size_t len=0;
for( cons *lst=m_impl.m_lst; lst; lst=lst->cdr, ++len )
{}
return len;
}
iterator erase( iterator it, iterator hint = iterator() )
{
cons **prv = prev( it.m_pcons, hint.m_pcons ); // *prv==it.p
*prv = it.m_pcons->cdr;
m_impl.allocator().destroy( it.m_pcons );
m_impl.allocator().deallocate( it.m_pcons, 1 );
return iterator( *prv );
}
void reverse()
{
cons *prv=0, *nxt;
while( m_impl.m_lst )
nxt = m_impl.m_lst->cdr, m_impl.m_lst->cdr = prv, prv = m_impl.m_lst, m_impl.m_lst = nxt;
m_impl.m_lst = prv;
}
};
template< typename AllocT >
struct basic_charset;
template< typename CharT >
struct posixcharsoff_pred
{
CharT m_ch;
posixcharsoff_pred( CharT ch )
: m_ch( ch )
{
}
bool operator()( regex_ctype_t desc ) const
{
return ! local_isctype( m_ch, desc );
}
static int local_isctype( char ch, regex_ctype_t desc )
{
return regex_isctype( ch, desc );
}
static int local_isctype( wchar_t ch, regex_ctype_t desc )
{
return regex_iswctype( ch, desc );
}
};
template< typename CharT, bool CaseT >
struct in_charset_pred
{
CharT m_ch;
in_charset_pred( CharT ch )
: m_ch( ch )
{
}
template< typename AllocT >
bool operator()( basic_charset<AllocT> const * pcs ) const
{
REGEX_VC6( return pcs->in( m_ch COMMA bool2type<CaseT>() ); )
REGEX_NVC6( return pcs->template in<CaseT>( m_ch ); )
}
};
template< typename AllocT >
struct basic_charset
{
typedef basic_charset<std::allocator<char> > other_type;
typedef slist<range_type,std::allocator<char> > other_ranges_type;
typedef slist<range_type,AllocT> ranges_type;
typedef slist<regex_ctype_t,AllocT> posixcharsoff_type;
typedef slist<other_type const*,AllocT> nestedcharsets_type;
typedef typename rebind<AllocT, char>::type char_allocator_type;
bool m_fcompliment;
bool m_fskip_extended_check;
ascii_bitvector m_ascii_bitvector;
regex_ctype_t m_posixcharson;
ranges_type m_ranges;
posixcharsoff_type m_posixcharsoff;
nestedcharsets_type m_nestedcharsets;
explicit basic_charset( char_allocator_type const & al = char_allocator_type() )
: m_fcompliment( false )
, m_fskip_extended_check( false )
, m_ascii_bitvector()
, m_posixcharson( wct_zero )
, m_ranges( al )
, m_posixcharsoff( al )
, m_nestedcharsets( al )
{
}
// We'll be inheriting from this, so a virtual d'tor is regretably necessary.
virtual ~basic_charset()
{
}
void clear()
{
m_fcompliment = false;
m_fskip_extended_check = false;
m_ascii_bitvector.zero();
m_posixcharson = wct_zero;
m_ranges.clear();
m_posixcharsoff.clear();
m_nestedcharsets.clear();
}
// merge one charset into another
basic_charset & operator|=( other_type const & that )
{
if( that.m_fcompliment )
{
// If no posix-style character sets are used, then we can merge this
// nested character set directly into the enclosing character set.
if( wct_zero == that.m_posixcharson &&
that.m_posixcharsoff.empty() &&
that.m_nestedcharsets.empty() )
{
m_ascii_bitvector |= ~ that.m_ascii_bitvector;
// append the inverse of that.m_ranges to this->m_ranges
wchar_t chlow = UCHAR_MAX;
typedef typename other_ranges_type::const_iterator iter_type;
for( iter_type prg = that.m_ranges.begin(); that.m_ranges.end() != prg; ++prg )
{
if( UCHAR_MAX + 1 != prg->first )
m_ranges.push_front( range_type( wchar_t( chlow+1 ), wchar_t( prg->first-1 ) ) );
chlow = prg->second;
}
if( WCHAR_MAX != chlow )
m_ranges.push_front( range_type( wchar_t( chlow+1 ), WCHAR_MAX ) );
}
else
{
// There is no simple way to merge this nested character
// set into the enclosing character set, so we must save
// a pointer to the nested character set in a list.
m_nestedcharsets.push_front( &that );
}
}
else
{
m_ascii_bitvector |= that.m_ascii_bitvector;
std::copy( that.m_ranges.begin(),
that.m_ranges.end(),
std::front_inserter( m_ranges ) );
m_posixcharson |= that.m_posixcharson;
std::copy( that.m_posixcharsoff.begin(),
that.m_posixcharsoff.end(),
std::front_inserter( m_posixcharsoff ) );
std::copy( that.m_nestedcharsets.begin(),
that.m_nestedcharsets.end(),
std::front_inserter( m_nestedcharsets ) );
}
return *this;
}
// Note overloading based on first parameter
void set_bit( char ch, bool const fnocase )
{
if( fnocase )
{
m_ascii_bitvector.set( static_cast<unsigned char>( regex_tolower( ch ) ) );
m_ascii_bitvector.set( static_cast<unsigned char>( regex_toupper( ch ) ) );
}
else
{
m_ascii_bitvector.set( static_cast<unsigned char>( ch ) );
}
}
// Note overloading based on first parameter
void set_bit( wchar_t ch, bool const fnocase )
{
if( UCHAR_MAX >= ch )
set_bit( static_cast<char>( ch ), fnocase );
else
m_ranges.push_front( range_type( ch, ch ) );
}
// Note overloading based on first two parameters
void set_bit_range( char ch1, char ch2, bool const fnocase )
{
if( static_cast<unsigned char>( ch1 ) > static_cast<unsigned char>( ch2 ) )
throw bad_regexpr( "invalid range specified in character set" );
if( fnocase )
{
// i is unsigned int to prevent overflow if ch2 is UCHAR_MAX
for( unsigned int i = static_cast<unsigned char>( ch1 );
i <= static_cast<unsigned char>( ch2 ); ++i )
{
m_ascii_bitvector.set( static_cast<unsigned char>( regex_toupper( (char) i ) ) );
m_ascii_bitvector.set( static_cast<unsigned char>( regex_tolower( (char) i ) ) );
}
}
else
{
// i is unsigned int to prevent overflow if ch2 is UCHAR_MAX
for( unsigned int i = static_cast<unsigned char>( ch1 );
i <= static_cast<unsigned char>( ch2 ); ++i )
{
m_ascii_bitvector.set( static_cast<unsigned char>( i ) );
}
}
}
// Note overloading based on first two parameters
void set_bit_range( wchar_t ch1, wchar_t ch2, bool const fnocase )
{
if( ch1 > ch2 )
throw bad_regexpr( "invalid range specified in character set" );
if( UCHAR_MAX >= ch1 )
set_bit_range( static_cast<char>( ch1 ), static_cast<char>( regex_min<wchar_t>( UCHAR_MAX, ch2 ) ), fnocase );
if( UCHAR_MAX < ch2 )
m_ranges.push_front( range_type( regex_max( static_cast<wchar_t>( UCHAR_MAX + 1 ), ch1 ), ch2 ) );
}
void optimize( type2type<wchar_t> )
{
if( m_ranges.begin() != m_ranges.end() )
{
// this sorts on range_type.m_pfirst ( uses operator<() for pair templates )
m_ranges.sort();
// merge ranges that overlap
typename ranges_type::iterator icur=m_ranges.begin(), iprev=icur++;
while( icur != m_ranges.end() )
{
if( icur->first <= iprev->second + 1 )
{
iprev->second = regex_max( iprev->second, icur->second );
icur = m_ranges.erase( icur, iprev );
}
else
{
iprev=icur++;
}
}
}
// For the ASCII range, merge the m_posixcharson info
// into the ascii_bitvector
if( wct_zero != m_posixcharson )
{
// BUGBUG this is kind of expensive. Think of a better way.
for( unsigned int i=0; i<=UCHAR_MAX; ++i )
if( regex_isctype( i, m_posixcharson ) )
m_ascii_bitvector.set( static_cast<unsigned char>( i ) );
}
// m_fskip_extended_check is a cache which tells us whether we
// need to check the m_posixcharsoff and m_nestedcharsets vectors,
// which would only be used in nested user-defined character sets
m_fskip_extended_check = m_posixcharsoff.empty() && m_nestedcharsets.empty();
}
void optimize( type2type<char> )
{
optimize( type2type<wchar_t>() );
// the posixcharson info was merged into the ascii bitvector,
// so we don't need to ever call regex_isctype ever again.
m_posixcharson = wct_zero;
}
template< bool CaseT, typename CharT >
bool extended_check( CharT ch REGEX_VC6(COMMA bool2type<CaseT>) ) const
{
REGEX_ASSERT( m_fskip_extended_check == ( m_posixcharsoff.empty() && m_nestedcharsets.empty() ) );
if( m_fskip_extended_check )
{
return false;
}
return ( m_posixcharsoff.end() !=
std::find_if( m_posixcharsoff.begin(), m_posixcharsoff.end(),
posixcharsoff_pred<CharT>( ch ) ) )
|| ( m_nestedcharsets.end() !=
std::find_if( m_nestedcharsets.begin(), m_nestedcharsets.end(),
in_charset_pred<CharT, CaseT>( ch ) ) );
}
inline bool in_ranges( wchar_t ch, true_t ) const
{
typedef typename ranges_type::const_iterator iter_type;
iter_type ibegin = m_ranges.begin(), iend = m_ranges.end();
return ibegin != iend &&
std::binary_search( ibegin, iend, range_type( ch, ch ), range_less() );
}
inline bool in_ranges( wchar_t ch, false_t ) const
{
typedef typename ranges_type::const_iterator iter_type;
iter_type ibegin = m_ranges.begin(), iend = m_ranges.end();
if( ibegin == iend )
return false;
wchar_t const chup = regex_toupper( ch );
if( std::binary_search( ibegin, iend, range_type( chup, chup ), range_less() ) )
return true;
wchar_t const chlo = regex_tolower( ch );
if( chup == chlo )
return false;
return std::binary_search( ibegin, iend, range_type( chlo, chlo ), range_less() );
}
// Note overloading based on parameter
template< bool CaseT >
bool in( char ch REGEX_VC6(COMMA bool2type<CaseT>) ) const
{
// Whoops, forgot to call optimize() on this charset
REGEX_ASSERT( wct_zero == m_posixcharson );
return m_fcompliment !=
(
( m_ascii_bitvector[ static_cast<unsigned char>( ch ) ] )
|| ( extended_check REGEX_NVC6(<CaseT>) ( ch REGEX_VC6(COMMA bool2type<CaseT>()) ) )
);
}
// Note overloading based on parameter
template< bool CaseT >
bool in( wchar_t ch REGEX_VC6(COMMA bool2type<CaseT>) ) const
{
// use range_match_type to see if this character is within one of the
// ranges stored in m_rgranges.
return m_fcompliment !=
(
( ( UCHAR_MAX >= ch ) ?
( m_ascii_bitvector[ static_cast<unsigned char>( ch ) ] ) :
( ( in_ranges( ch, bool2type<CaseT>() ) )
|| ( wct_zero != m_posixcharson && regex_iswctype( ch, m_posixcharson ) ) ) )
|| ( extended_check REGEX_NVC6(<CaseT>) ( ch REGEX_VC6(COMMA bool2type<CaseT>()) ) )
);
}
private:
basic_charset & operator=( basic_charset const & that );
basic_charset( basic_charset const & that );
};
// Intrinsic character sets are allocated on the heap with the standard allocator.
// They are either the built-in character sets, or the user-defined ones.
struct charset : public basic_charset<std::allocator<char> >
{
charset()
{
}
private:
charset( charset const & );
charset & operator=( charset const & );
};
// charset is no longer an incomplete type so we now
// know how to destroy one. free_charset() is used in syntax2.h
REGEXPR_H_INLINE void free_charset( charset const * pcharset )
{
delete pcharset;
}
// Custom character sets are the ones that appear in patterns between
// square brackets. They are allocated in a regex_arena to speed up
// pattern compilation and to make rpattern clean-up faster.
struct custom_charset : public basic_charset<regex_arena>
{
static void * operator new( size_t size, regex_arena & arena )
{
return arena.allocate( size );
}
static void operator delete( void *, regex_arena & ) {}
static void operator delete( void * ) {}
custom_charset( regex_arena & arena )
: basic_charset<regex_arena>( arena )
{
}
private:
custom_charset( custom_charset const & );
custom_charset & operator=( custom_charset const & );
};
template< typename CharT >
class intrinsic_charsets
{
struct intrinsic_charset : public charset
{
intrinsic_charset( bool fcompliment, regex_ctype_t desc, char const * sz )
{
reset( fcompliment, desc, sz );
}
void reset( bool fcompliment, regex_ctype_t desc, char const * sz )
{
clear();
m_fcompliment = fcompliment;
m_posixcharson = desc;
for( ; *sz; ++sz )
m_ascii_bitvector.set( static_cast<unsigned char>( *sz ) );
optimize( type2type<CharT>() );
}
private:
intrinsic_charset( intrinsic_charset const & );
intrinsic_charset & operator=( intrinsic_charset const & );
};
static intrinsic_charset & _get_word_charset()
{
static intrinsic_charset s_word_charset( false, wct_alpha()|wct_digit(), "_" );
return s_word_charset;
}
static intrinsic_charset & _get_digit_charset()
{
static intrinsic_charset s_digit_charset( false, wct_digit(), "" );
return s_digit_charset;
}
static intrinsic_charset & _get_space_charset()
{
static intrinsic_charset s_space_charset( false, wct_space(), "" );
return s_space_charset;
}
static intrinsic_charset & _get_not_word_charset()
{
static intrinsic_charset s_not_word_charset( true, wct_alpha()|wct_digit(), "_" );
return s_not_word_charset;
}
static intrinsic_charset & _get_not_digit_charset()
{
static intrinsic_charset s_not_digit_charset( true, wct_digit(), "" );
return s_not_digit_charset;
}
static intrinsic_charset & _get_not_space_charset()
{
static intrinsic_charset s_not_space_charset( true, wct_space(), "" );
return s_not_space_charset;
}
public:
static charset const & get_word_charset()
{
return _get_word_charset();
}
static charset const & get_digit_charset()
{
return _get_digit_charset();
}
static charset const & get_space_charset()
{
return _get_space_charset();
}
static charset const & get_not_word_charset()
{
return _get_not_word_charset();
}
static charset const & get_not_digit_charset()
{
return _get_not_digit_charset();
}
static charset const & get_not_space_charset()
{
return _get_not_space_charset();
}
static void reset()
{
_get_word_charset().reset( false, wct_alpha()|wct_digit(), "_" );
_get_digit_charset().reset( false, wct_digit(), "" );
_get_space_charset().reset( false, wct_space(), "" );
_get_not_word_charset().reset( true, wct_alpha()|wct_digit(), "_" );
_get_not_digit_charset().reset( true, wct_digit(), "" );
_get_not_space_charset().reset( true, wct_space(), "" );
}
};
//
// Operator implementations
//
// Evaluates the beginning-of-string condition
template< typename CStringsT >
struct bos_t
{
template< typename IterT >
static bool eval( match_param<IterT> const & param, IterT iter )
{
return param.m_ibufferbegin == iter;
}
};
// Find the beginning of a line, either beginning of a string, or the character
// immediately following a newline
template< typename CStringsT >
struct bol_t
{
template< typename IterT >
static bool eval( match_param<IterT> const & param, IterT iter )
{
typedef typename std::iterator_traits<IterT>::value_type char_type;
typedef std::char_traits<char_type> traits_type;
return param.m_ibufferbegin == iter || traits_type::eq( REGEX_CHAR(char_type,'/n'), *--iter );
}
};
// Evaluates end-of-string condition for string's
template< typename CStringsT >
struct eos_t
{
template< typename IterT >
static bool eval( match_param<IterT> const & param, IterT iter )
{
return param.m_iend == iter;
}
};
template<>
struct eos_t<true_t>
{
template< typename IterT >
static bool eval( match_param<IterT> const &, IterT iter )
{
typedef typename std::iterator_traits<IterT>::value_type char_type;
typedef std::char_traits<char_type> traits_type;
return traits_type::eq( *iter, char_type() );
}
};
// Evaluates end-of-line conditions, either the end of the string, or a
// newline character.
template< typename CStringsT >
struct eol_t
{
template< typename IterT >
static bool eval( match_param<IterT> const & param, IterT iter )
{
typedef typename std::iterator_traits<IterT>::value_type char_type;
typedef std::char_traits<char_type> traits_type;
return param.m_iend == iter
|| traits_type::eq( REGEX_CHAR(char_type,'/n'), *iter );
}
};
template<>
struct eol_t<true_t>
{
template< typename IterT >
static bool eval( match_param<IterT> const &, IterT iter )
{
typedef typename std::iterator_traits<IterT>::value_type char_type;
typedef std::char_traits<char_type> traits_type;
return traits_type::eq( *iter, char_type() )
|| traits_type::eq( *iter, REGEX_CHAR(char_type,'/n') );
}
};
// Evaluates perl's end-of-string conditions, either the end of the string, or a
// newline character followed by end of string. ( Only used by $ and /Z assertions )
template< typename CStringsT >
struct peos_t
{
template< typename IterT >
static bool eval( match_param<IterT> const & param, IterT iter )
{
typedef typename std::iterator_traits<IterT>::value_type char_type;
typedef std::char_traits<char_type> traits_type;
return param.m_iend == iter
|| ( traits_type::eq( REGEX_CHAR(char_type,'/n'), *iter ) && param.m_iend == ++iter );
}
};
template<>
struct peos_t<true_t>
{
template< typename IterT >
static bool eval( match_param<IterT> const &, IterT iter )
{
typedef typename std::iterator_traits<IterT>::value_type char_type;
typedef std::char_traits<char_type> traits_type;
return traits_type::eq( *iter, char_type() )
|| ( traits_type::eq( *iter, REGEX_CHAR(char_type,'/n') )
&& traits_type::eq( *++iter, char_type() ) );
}
};
// compare two characters, case-sensitive
template< typename CharT >
struct ch_neq_t
{
typedef CharT char_type;
typedef std::char_traits<char_type> traits_type;
static bool eval( register CharT ch1, register CharT ch2 )
{
return ! traits_type::eq( ch1, ch2 );
}
};
// Compare two characters, disregarding case
template< typename CharT >
struct ch_neq_nocase_t
{
typedef CharT char_type;
typedef std::char_traits<char_type> traits_type;
static bool eval( register CharT ch1, register CharT ch2 )
{
return ! traits_type::eq( regex_toupper( ch1 ), regex_toupper( ch2 ) );
}
};
//
// helper functions for dealing with widths.
//
inline size_t width_add( size_t a, size_t b )
{
return ( size_t( -1 ) == a || size_t( -1 ) == b ? size_t( -1 ) : a + b );
}
inline size_t width_mult( size_t a, size_t b )
{
if( 0 == a || 0 == b )
return 0;
if( size_t( -1 ) == a || size_t( -1 ) == b )
return size_t( -1 );
return a * b;
}
inline bool operator==( width_type const & rhs, width_type const & lhs )
{
return ( rhs.m_min == lhs.m_min && rhs.m_max == lhs.m_max );
}
inline bool operator!=( width_type const & rhs, width_type const & lhs )
{
return ( rhs.m_min != lhs.m_min || rhs.m_max != lhs.m_max );
}
inline width_type operator+( width_type const & rhs, width_type const & lhs )
{
width_type width = { width_add( rhs.m_min, lhs.m_min ), width_add( rhs.m_max, lhs.m_max ) };
return width;
}
inline width_type operator*( width_type const & rhs, width_type const & lhs )
{
width_type width = { width_mult( rhs.m_min, lhs.m_min ), width_mult( rhs.m_max, lhs.m_max ) };
return width;
}
inline width_type & operator+=( width_type & rhs, width_type const & lhs )
{
rhs.m_min = width_add( rhs.m_min, lhs.m_min );
rhs.m_max = width_add( rhs.m_max, lhs.m_max );
return rhs;
}
inline width_type & operator*=( width_type & rhs, width_type const & lhs )
{
rhs.m_min = width_mult( rhs.m_min, lhs.m_min );
rhs.m_max = width_mult( rhs.m_max, lhs.m_max );
return rhs;
}
namespace
{
width_type const zero_width = { 0, 0 };
width_type const worst_width = { 0, size_t( -1 ) };
}
template< typename IterT >
struct width_param
{
std::vector<match_group_base<IterT>*> & m_rggroups;
std::list<size_t> const & m_invisible_groups;
width_type m_width;
width_param
(
std::vector<match_group_base<IterT>*> & rggroups,
std::list<size_t> const & invisible_groups
)
: m_rggroups( rggroups )
, m_invisible_groups( invisible_groups )
, m_width( zero_width )
{
}
private:
width_param & operator=( width_param const & );
};
template< typename CharT >
struct must_have
{
typedef std::basic_string<CharT> string_type;
typedef typename string_type::const_iterator const_iterator;
bool m_has;
const_iterator m_begin;
const_iterator m_end;
CharT const * m_lower;
};
template< typename CharT >
struct peek_param
{
// "chars" is a list of characters. If every alternate in a group
// begins with a character or string literal, the "chars" list can
// be used to speed up the matching of a group.
size_t m_cchars;
union
{
CharT m_rgchars[2];
CharT const * m_pchars;
};
// "must" is a string that must appear in the match. It is used
// to speed up the search.
must_have<CharT> m_must_have;
};
// --------------------------------------------------------------------------
//
// Class: sub_expr
//
// Description: patterns are "compiled" into a directed graph of sub_expr
// structs. Matching is accomplished by traversing this graph.
//
// Methods: sub_expr - construct a sub_expr
// recursive_match_this - does this sub_expr match at the given location
// width_this - what is the width of this sub_expr
// ~sub_expr - recursively delete the sub_expr graph
// next - pointer to the next node in the graph
// next - pointer to the next node in the graph
// recursive_match_next - match the rest of the graph
// recursive_match_all - recursive_match_this and recursive_match_next
// is_assertion - true if this sub_expr is a zero-width assertion
// get_width - find the width of the graph at this sub_expr
//
// Members: m_pnext - pointer to the next node in the graph
//
// History: 8/14/2000 - ericne - Created
//
// --------------------------------------------------------------------------
template< typename IterT >
class sub_expr : public sub_expr_base<IterT>
{
sub_expr * m_pnext;
protected:
// Only derived classes can instantiate sub_expr's
sub_expr()
: m_pnext( 0 )
{
}
public:
typedef IterT iterator_type;
typedef typename std::iterator_traits<IterT>::value_type char_type;
typedef std::char_traits<char_type> traits_type;
virtual ~sub_expr()
{
delete m_pnext;
}
sub_expr ** pnext()
{
return & m_pnext;
}
sub_expr const * next() const
{
return m_pnext;
}
virtual sub_expr * quantify( size_t, size_t, bool, regex_arena & )
{
throw bad_regexpr( "sub-expression cannot be quantified" );
}
// Match this object and all subsequent objects
// If recursive_match_all returns false, it must not change any of param's state
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return ( recursive_match_this_s( param, icur ) && recursive_match_next( param, icur, false_t() ) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const // for C-style strings
{
return ( recursive_match_this_c( param, icur ) && recursive_match_next( param, icur, true_t() ) );
}
// match this object only
virtual bool recursive_match_this_s( match_param<IterT> &, IterT & ) const
{
return true;
}
virtual bool recursive_match_this_c( match_param<IterT> &, IterT & ) const // for C-style strings
{
return true;
}
// Match all subsequent objects
template< typename CStringsT >
bool recursive_match_next( match_param<IterT> & param, IterT icur, CStringsT ) const
{
return m_pnext->recursive_match_all( param, icur, CStringsT() );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
param.m_pnext = next();
return true;
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const // for C-style strings
{
param.m_pnext = next();
return true;
}
virtual bool iterative_rematch_this_s( match_param<IterT> & ) const
{
return false;
}
virtual bool iterative_rematch_this_c( match_param<IterT> & ) const // for C-style strings
{
return false;
}
virtual bool is_assertion() const
{
return false;
}
width_type get_width( width_param<IterT> & param )
{
width_type temp_width = width_this( param );
if( m_pnext )
temp_width += m_pnext->get_width( param );
return temp_width;
}
virtual width_type width_this( width_param<IterT> & ) = 0;
virtual bool peek_this( peek_param<char_type> & ) const
{
return false;
}
};
// An object of type end_of_pattern is used to mark the
// end of the pattern. (Duh!) It is responsible for ending
// the recursion, or for letting the search continue if
// the match is zero-width and we are trying to find a
// non-zero-width match
template< typename IterT >
class end_of_pattern : public sub_expr<IterT>
{
bool _do_match_this( match_param<IterT> & param, IterT icur ) const
{
return ! param.m_no0len || param.m_imatchbegin != icur;
}
public:
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return _do_match_this( param, icur );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const // for C-style strings
{
return _do_match_this( param, icur );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
param.m_pnext = 0;
return _do_match_this( param, param.m_icur );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const // for C-style strings
{
param.m_pnext = 0;
return _do_match_this( param, param.m_icur );
}
virtual width_type width_this( width_param<IterT> & )
{
return zero_width;
}
};
// Base class for sub-expressions which are zero-width
// ( i.e., assertions eat no characters during matching )
// Assertions cannot be quantified.
template< typename IterT >
class assertion : public sub_expr<IterT>
{
public:
virtual bool is_assertion() const
{
return true;
}
virtual width_type width_this( width_param<IterT> & )
{
return zero_width;
}
virtual bool peek_this( peek_param<char_type> & peek ) const
{
return this->next()->peek_this( peek );
}
};
template< typename OpT, typename OpCT >
struct opwrap
{
typedef OpT op_type;
typedef OpCT opc_type;
};
#define REGEX_OP(x) opwrap< x<false_t>, x<true_t> >
template< typename IterT, typename OpWrapT >
class assert_op : public assertion<IterT>
{
public:
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return ( assert_op::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return ( assert_op::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );
}
virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const
{
return OpWrapT::op_type::eval( param, icur );
}
virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const
{
return OpWrapT::opc_type::eval( param, icur );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return OpWrapT::op_type::eval( param, param.m_icur );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return OpWrapT::opc_type::eval( param, param.m_icur );
}
};
template< typename IterT >
inline assertion<IterT> * create_bos( REGEX_FLAGS, regex_arena & arena )
{
return new( arena ) assert_op<IterT, REGEX_OP(bos_t) >();
}
template< typename IterT >
inline assertion<IterT> * create_eos( REGEX_FLAGS, regex_arena & arena )
{
return new( arena ) assert_op<IterT, REGEX_OP(peos_t) >();
}
template< typename IterT >
inline assertion<IterT> * create_eoz( REGEX_FLAGS, regex_arena & arena )
{
return new( arena ) assert_op<IterT, REGEX_OP(eos_t) >();
}
template< typename IterT >
inline assertion<IterT> * create_bol( REGEX_FLAGS flags, regex_arena & arena )
{
switch( MULTILINE & flags )
{
case 0:
return new( arena ) assert_op<IterT, REGEX_OP(bos_t) >();
case MULTILINE:
return new( arena ) assert_op<IterT, REGEX_OP(bol_t) >();
default:
REGEX_ASSERT(false);
return 0;
}
}
template< typename IterT >
inline assertion<IterT> * create_eol( REGEX_FLAGS flags, regex_arena & arena )
{
switch( MULTILINE & flags )
{
case 0:
return new( arena ) assert_op<IterT, REGEX_OP(peos_t) >();
case MULTILINE:
return new( arena ) assert_op<IterT, REGEX_OP(eol_t) >();
default:
REGEX_ASSERT(false);
return 0;
}
}
template< typename IterT, typename SubExprT = sub_expr<IterT> >
class match_wrapper : public sub_expr<IterT>
{
match_wrapper & operator=( match_wrapper const & );
public:
match_wrapper( SubExprT * psub )
: m_psub( psub )
{
}
virtual ~match_wrapper()
{
_cleanup();
}
virtual width_type width_this( width_param<IterT> & param )
{
return m_psub->width_this( param );
}
virtual bool peek_this( peek_param<char_type> & peek ) const
{
return m_psub->peek_this( peek );
}
protected:
void _cleanup()
{
delete m_psub;
m_psub = 0;
}
SubExprT * m_psub;
};
template< typename IterT, typename SubExprT = sub_expr<IterT> >
class match_quantifier : public match_wrapper<IterT, SubExprT>
{
match_quantifier & operator=( match_quantifier const & );
public:
match_quantifier( SubExprT * psub, size_t lbound, size_t ubound )
: match_wrapper<IterT, SubExprT>( psub )
, m_lbound( lbound )
, m_ubound( ubound )
{
}
virtual width_type width_this( width_param<IterT> & param )
{
width_type this_width = match_wrapper<IterT, SubExprT>::width_this( param );
width_type quant_width = { m_lbound, m_ubound };
return this_width * quant_width;
}
virtual bool peek_this( peek_param<char_type> & peek ) const
{
return 0 != m_lbound && this->m_psub->peek_this( peek );
}
protected:
size_t const m_lbound;
size_t const m_ubound;
};
template< typename IterT, typename SubExprT >
class atom_quantifier : public match_quantifier<IterT, SubExprT>
{
atom_quantifier & operator=( atom_quantifier const & );
public:
atom_quantifier( SubExprT * psub, size_t lbound, size_t ubound )
: match_quantifier<IterT, SubExprT>( psub, lbound, ubound )
{
}
protected:
void _push_frame( unsafe_stack * pstack, IterT curr, size_t count ) const
{
std::pair<IterT, size_t> p( curr, count );
pstack->push( p );
}
void _pop_frame( match_param<IterT> & param ) const
{
std::pair<IterT, size_t> p;
param.m_pstack->pop( p );
param.m_icur = p.first;
}
};
template< typename IterT, typename SubExprT >
class max_atom_quantifier : public atom_quantifier<IterT, SubExprT>
{
max_atom_quantifier & operator=( max_atom_quantifier const & );
public:
max_atom_quantifier( SubExprT * psub, size_t lbound, size_t ubound )
: atom_quantifier<IterT, SubExprT>( psub, lbound, ubound )
{
}
// Why a macro instead of a template, you ask? Performance. Due to a known
// bug in the VC7 inline heuristic, I cannot get VC7 to inline the calls to
// m_psub methods unless I use these macros. And the performance win is
// nothing to sneeze at. It's on the order of a 25% speed up to use a macro
// here instead of a template.
#define DECLARE_RECURSIVE_MATCH_ALL(CSTRINGS,EXT) /
virtual bool recursive_match_all ## EXT( match_param<IterT> & param, IterT icur ) const /
{ /
typedef typename std::iterator_traits<IterT>::difference_type diff_type; /
/* In an ideal world, ibegin and cdiff would be members of a union */ /
/* to conserve stack, but I don't know if IterT is a POD type or not. */ /
IterT ibegin = icur; /
diff_type cdiff = 0; /* must be a signed integral type */ /
size_t cmatches = 0; /
/* greedily match as much as we can*/ /
if( this->m_ubound && this->m_psub->SubExprT::recursive_match_this ## EXT( param, icur ) ) /
{ /
if( 0 == ( cdiff = -std::distance( ibegin, icur ) ) ) /
return this->recursive_match_next( param, icur, CSTRINGS() ); /
while( ++cmatches < this->m_ubound && this->m_psub->SubExprT::recursive_match_this ## EXT( param, icur ) )/
{} /
} /
if( this->m_lbound > cmatches ) /
return false; /
/* try matching the rest of the pattern, and back off if necessary */ /
for( ; ; --cmatches, std::advance( icur, cdiff ) ) /
{ /
if( this->recursive_match_next( param, icur, CSTRINGS() ) ) /
return true; /
if( this->m_lbound == cmatches ) /
return false; /
} /
}
#define DECLARE_ITERATIVE_MATCH_THIS(EXT) /
virtual bool iterative_match_this ## EXT( match_param<IterT> & param ) const /
{ /
IterT ibegin = param.m_icur; /
size_t cmatches = 0; /
if( this->m_ubound && this->m_psub->SubExprT::iterative_match_this ## EXT( param ) ) /
{ /
if( 0 == std::distance( ibegin, param.m_icur ) ) /
{ /
cmatches = this->m_lbound; /
} /
else /
{ /
while( ++cmatches < this->m_ubound && this->m_psub->SubExprT::iterative_match_this ## EXT( param ) )/
{} /
} /
} /
if( cmatches >= this->m_lbound ) /
{ /
this->_push_frame( param.m_pstack, ibegin, cmatches ); /
param.m_pnext = this->next(); /
return true; /
} /
param.m_icur = ibegin; /
return false; /
}
#define DECLARE_ITERATIVE_REMATCH_THIS(EXT) /
virtual bool iterative_rematch_this ## EXT( match_param<IterT> & param ) const /
{ /
typedef std::pair<IterT, size_t> top_type; /
size_t & cmatches = REGEX_VC6( param.m_pstack->top( type2type<top_type>() ).second ) /
REGEX_NVC6( param.m_pstack->template top<top_type>().second ); /
if( this->m_lbound != cmatches ) /
{ /
--cmatches; /
this->m_psub->SubExprT::iterative_rematch_this ## EXT( param ); /
param.m_pnext = this->next(); /
return true; /
} /
this->_pop_frame( param ); /
return false; /
}
DECLARE_RECURSIVE_MATCH_ALL(false_t,_s)
DECLARE_RECURSIVE_MATCH_ALL(true_t,_c)
DECLARE_ITERATIVE_MATCH_THIS(_s)
DECLARE_ITERATIVE_MATCH_THIS(_c)
DECLARE_ITERATIVE_REMATCH_THIS(_s)
DECLARE_ITERATIVE_REMATCH_THIS(_c)
#undef DECLARE_RECURSIVE_MATCH_ALL
#undef DECLARE_ITERATIVE_MATCH_THIS
#undef DECLARE_ITERATIVE_REMATCH_THIS
};
template< typename IterT, typename SubExprT >
class min_atom_quantifier : public atom_quantifier<IterT, SubExprT>
{
min_atom_quantifier & operator=( min_atom_quantifier const & );
public:
min_atom_quantifier( SubExprT * psub, size_t lbound, size_t ubound )
: atom_quantifier<IterT, SubExprT>( psub, lbound, ubound )
{
}
// Why a macro instead of a template, you ask? Performance. Due to a known
// bug in the VC7 inline heuristic, I cannot get VC7 to inline the calls to
// m_psub methods unless I use these macros. And the performance win is
// nothing to sneeze at. It's on the order of a 25% speed up to use a macro
// here instead of a template.
#define DECLARE_RECURSIVE_MATCH_ALL(CSTRINGS,EXT) /
virtual bool recursive_match_all ## EXT( match_param<IterT> & param, IterT icur ) const /
{ /
IterT icur_tmp = icur; /
size_t cmatches = 0; /
if( this->m_psub->SubExprT::recursive_match_this ## EXT( param, icur_tmp ) ) /
{ /
if( icur_tmp == icur ) /
return this->recursive_match_next( param, icur, CSTRINGS() ); /
if( this->m_lbound ) /
{ /
icur = icur_tmp; /
++cmatches; /
} /
for( ; cmatches < this->m_lbound; ++cmatches ) /
{ /
if( ! this->m_psub->SubExprT::recursive_match_this ## EXT( param, icur ) ) /
return false; /
} /
} /
else if( this->m_lbound ) /
{ /
return false; /
} /
do /
{ /
if( this->recursive_match_next( param, icur, CSTRINGS() ) ) /
return true; /
} /
while( cmatches < this->m_ubound && /
( ++cmatches, this->m_psub->SubExprT::recursive_match_this ## EXT( param, icur ) ) ); /
return false; /
}
#define DECLARE_ITERATIVE_MATCH_THIS(EXT) /
virtual bool iterative_match_this ## EXT( match_param<IterT> & param ) const /
{ /
IterT ibegin = param.m_icur; /
size_t cmatches = 0; /
if( this->m_psub->SubExprT::iterative_match_this ## EXT( param ) ) /
{ /
if( 0 == std::distance( ibegin, param.m_icur ) ) /
{ /
cmatches = this->m_ubound; /
} /
else if( this->m_lbound ) /
{ /
for( ++cmatches; cmatches < this->m_lbound; ++cmatches ) /
{ /
if( ! this->m_psub->SubExprT::iterative_match_this ## EXT( param ) ) /
{ /
param.m_icur = ibegin; /
return false; /
} /
} /
} /
else /
{ /
param.m_icur = ibegin; /
} /
} /
else if( this->m_lbound ) /
{ /
return false; /
} /
this->_push_frame( param.m_pstack, ibegin, cmatches ); /
param.m_pnext = this->next(); /
return true; /
}
#define DECLARE_ITERATIVE_REMATCH_THIS(EXT) /
virtual bool iterative_rematch_this ## EXT( match_param<IterT> & param ) const /
{ /
typedef std::pair<IterT, size_t> top_type; /
size_t & cmatches = REGEX_VC6( param.m_pstack->top( type2type<top_type>() ).second ) /
REGEX_NVC6( param.m_pstack->template top<top_type>().second ); /
if( cmatches == this->m_ubound || ! this->m_psub->SubExprT::iterative_match_this ## EXT( param ) ) /
{ /
this->_pop_frame( param ); /
return false; /
} /
++cmatches; /
param.m_pnext = this->next(); /
return true; /
}
DECLARE_RECURSIVE_MATCH_ALL(false_t,_s)
DECLARE_RECURSIVE_MATCH_ALL(true_t,_c)
DECLARE_ITERATIVE_MATCH_THIS(_s)
DECLARE_ITERATIVE_MATCH_THIS(_c)
DECLARE_ITERATIVE_REMATCH_THIS(_s)
DECLARE_ITERATIVE_REMATCH_THIS(_c)
#undef DECLARE_RECURSIVE_MATCH_ALL
#undef DECLARE_ITERATIVE_MATCH_THIS
#undef DECLARE_ITERATIVE_REMATCH_THIS
};
template< typename CharT >
struct char_nocase
{
CharT m_chlo;
CharT m_chhi;
};
template< typename IterT >
class match_char : public sub_expr<IterT>
{
match_char & operator=( match_char const & );
public:
typedef typename sub_expr<IterT>::char_type char_type;
virtual width_type width_this( width_param<IterT> & )
{
width_type width = { 1, 1 };
return width;
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
--param.m_icur;
return false;
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
--param.m_icur;
return false;
}
};
template< typename IterT, typename CharT >
class match_char_t : public match_char<IterT>
{
match_char_t & operator=( match_char_t const & );
public:
match_char_t( CharT const & ch )
: m_ch( ch )
{
}
virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )
{
if( greedy )
return new( arena ) max_atom_quantifier<IterT, match_char_t<IterT, CharT> >( this, lbound, ubound );
else
return new( arena ) min_atom_quantifier<IterT, match_char_t<IterT, CharT> >( this, lbound, ubound );
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return ( match_char_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return ( match_char_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );
}
virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this REGEX_NVC6(<false_t>) ( param, param.m_icur REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this REGEX_NVC6(<true_t>) ( param, param.m_icur REGEX_VC6(COMMA true_t()) );
}
virtual bool peek_this( peek_param<char_type> & peek ) const
{
_do_peek_this( peek, m_ch );
return true;
}
private:
static bool eq( char_type left, char_type right )
{
return traits_type::eq( left, right );
}
static bool eq( char_type left, char_nocase<char_type> right )
{
return traits_type::eq( left, right.m_chlo ) ||
traits_type::eq( left, right.m_chhi );
}
static void _do_peek_this( peek_param<char_type> & peek, char_type ch )
{
peek.m_cchars = 1;
peek.m_rgchars[0] = ch;
peek.m_must_have.m_has = false;
}
static void _do_peek_this( peek_param<char_type> & peek, char_nocase<char_type> ch )
{
peek.m_cchars = 2;
peek.m_rgchars[0] = ch.m_chlo;
peek.m_rgchars[1] = ch.m_chhi;
peek.m_must_have.m_has = false;
}
template< typename CStringsT >
bool _do_match_this( match_param<IterT> & param, IterT & icur REGEX_VC6(COMMA CStringsT) ) const
{
if( eos_t<CStringsT>::eval( param, icur ) || ! eq( *icur, m_ch ) )
return false;
++icur;
return true;
}
CharT const m_ch;
};
template< typename IterT >
inline match_char<IterT> * create_char
(
typename std::iterator_traits<IterT>::value_type ch,
REGEX_FLAGS flags,
regex_arena & arena
)
{
typedef typename std::iterator_traits<IterT>::value_type char_type;
typedef std::char_traits<char_type> traits_type;
switch( NOCASE & flags )
{
case 0:
return new( arena ) match_char_t<IterT, char_type>( ch );
case NOCASE:
{
char_nocase<char_type> nocase = { regex_tolower( ch ), regex_toupper( ch ) };
if( traits_type::eq( nocase.m_chlo, nocase.m_chhi ) )
return new( arena ) match_char_t<IterT, char_type>( ch );
else
return new( arena ) match_char_t<IterT, char_nocase<char_type> >( nocase );
}
default:
REGEX_ASSERT(false);
return 0;
}
}
template< typename IterT >
class match_literal : public sub_expr<IterT>
{
match_literal & operator=( match_literal const & );
public:
typedef typename sub_expr<IterT>::char_type char_type;
typedef std::basic_string<char_type> string_type;
typedef typename string_type::iterator iterator;
typedef typename string_type::const_iterator const_iterator;
typedef typename std::iterator_traits<IterT>::difference_type diff_type;
match_literal( const_iterator ibegin, const_iterator iend )
: m_ibegin( ibegin )
, m_iend( iend )
, m_dist( std::distance( m_ibegin, m_iend ) )
{
}
const_iterator const m_ibegin;
const_iterator const m_iend;
diff_type const m_dist; // must be signed integral type
virtual width_type width_this( width_param<IterT> & )
{
width_type width = { static_cast<size_t>( m_dist ), static_cast<size_t>( m_dist ) };
return width;
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
std::advance( param.m_icur, -m_dist );
return false;
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
std::advance( param.m_icur, -m_dist );
return false;
}
};
template< typename IterT >
class match_literal_t : public match_literal<IterT>
{
match_literal_t & operator=( match_literal_t const & );
public:
typedef typename match_literal<IterT>::char_type char_type;
typedef typename match_literal<IterT>::string_type string_type;
typedef typename match_literal<IterT>::iterator iterator;
typedef typename match_literal<IterT>::const_iterator const_iterator;
match_literal_t( const_iterator ibegin, const_iterator iend )
: match_literal<IterT>( ibegin, iend )
{
}
virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )
{
if( greedy )
return new( arena ) max_atom_quantifier<IterT, match_literal_t<IterT> >( this, lbound, ubound );
else
return new( arena ) min_atom_quantifier<IterT, match_literal_t<IterT> >( this, lbound, ubound );
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return ( match_literal_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return ( match_literal_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );
}
virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this REGEX_NVC6(<false_t>) ( param, param.m_icur REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this REGEX_NVC6(<true_t>) ( param, param.m_icur REGEX_VC6(COMMA true_t()) );
}
virtual bool peek_this( peek_param<char_type> & peek ) const
{
peek.m_cchars = 1;
peek.m_rgchars[0] = *this->m_ibegin;
peek.m_must_have.m_has = true;
peek.m_must_have.m_begin = this->m_ibegin;
peek.m_must_have.m_end = this->m_iend;
peek.m_must_have.m_lower = 0;
return true;
}
private:
template< typename CStringsT >
bool _do_match_this( match_param<IterT> & param, IterT & icur REGEX_VC6(COMMA CStringsT) ) const
{
IterT icur_tmp = icur;
const_iterator ithis = this->m_ibegin;
for( ; this->m_iend != ithis; ++icur_tmp, ++ithis )
{
if( eos_t<CStringsT>::eval( param, icur_tmp ) || ! traits_type::eq( *ithis, *icur_tmp ) )
return false;
}
icur = icur_tmp;
return true;
}
};
template< typename IterT >
class match_literal_nocase_t : public match_literal<IterT>
{
match_literal_nocase_t & operator=( match_literal_nocase_t const & );
public:
typedef typename match_literal<IterT>::char_type char_type;
typedef typename match_literal<IterT>::string_type string_type;
typedef typename match_literal<IterT>::iterator iterator;
typedef typename match_literal<IterT>::const_iterator const_iterator;
match_literal_nocase_t( iterator ibegin, const_iterator iend, regex_arena & arena )
: match_literal<IterT>( ibegin, iend )
, m_szlower( arena_allocator<char_type>( arena ).allocate( m_dist ) )
{
// Copy from ibegin to m_szlower
std::copy( this->m_ibegin, this->m_iend, m_szlower );
// Store the uppercase version of the literal in [ m_ibegin, m_iend ).
regex_toupper( ibegin, iend );
// Store the lowercase version of the literal in m_strlower.
regex_tolower( m_szlower, m_szlower + this->m_dist );
}
virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )
{
if( greedy )
return new( arena ) max_atom_quantifier<IterT, match_literal_nocase_t<IterT> >( this, lbound, ubound );
else
return new( arena ) min_atom_quantifier<IterT, match_literal_nocase_t<IterT> >( this, lbound, ubound );
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return ( match_literal_nocase_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return ( match_literal_nocase_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );
}
virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this REGEX_NVC6(<false_t>) ( param, param.m_icur REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this REGEX_NVC6(<true_t>) ( param, param.m_icur REGEX_VC6(COMMA true_t()) );
}
virtual bool peek_this( peek_param<char_type> & peek ) const
{
peek.m_cchars = 2;
peek.m_rgchars[0] = *this->m_ibegin;
peek.m_rgchars[1] = *m_szlower;
peek.m_must_have.m_has = true;
peek.m_must_have.m_begin = this->m_ibegin;
peek.m_must_have.m_end = this->m_iend;
peek.m_must_have.m_lower = m_szlower;
return true;
}
private:
// Allocated from a regex arena. The memory will be cleaned up
// when the arena is deallocated.
char_type *const m_szlower;
template< typename CStringsT >
bool _do_match_this( match_param<IterT> & param, IterT & icur REGEX_VC6(COMMA CStringsT) ) const
{
IterT icur_tmp = icur;
const_iterator ithisu = this->m_ibegin; // uppercase
char_type const * ithisl = m_szlower; // lowercase
for( ; this->m_iend != ithisu; ++icur_tmp, ++ithisu, ++ithisl )
{
if( eos_t<CStringsT>::eval( param, icur_tmp ) ||
( ! traits_type::eq( *ithisu, *icur_tmp ) &&
! traits_type::eq( *ithisl, *icur_tmp ) ) )
return false;
}
icur = icur_tmp;
return true;
}
};
template< typename IterT, typename IBeginT, typename IEndT >
inline sub_expr<IterT> * create_literal
(
IBeginT ibegin,
IEndT iend,
REGEX_FLAGS flags,
regex_arena & arena
)
{
// A match_char is faster than a match_literal, so prefer it
// when the literal to match is only 1 char wide.
if( 1 == std::distance<IEndT>( ibegin, iend ) )
{
return create_char<IterT>( *ibegin, flags, arena );
}
switch( NOCASE & flags )
{
case 0:
return new( arena ) match_literal_t<IterT>( ibegin, iend );
case NOCASE:
return new( arena ) match_literal_nocase_t<IterT>( ibegin, iend, arena );
default:
REGEX_ASSERT(false);
return 0;
}
}
template< typename IterT >
class match_any : public sub_expr<IterT>
{
public:
virtual width_type width_this( width_param<IterT> & )
{
width_type width = { 1, 1 };
return width;
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
--param.m_icur;
return false;
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
--param.m_icur;
return false;
}
};
template< typename IterT, typename EosWrapT >
class match_any_t : public match_any<IterT>
{
bool _do_match_this_s( match_param<IterT> & param, IterT & icur ) const
{
if( EosWrapT::op_type::eval( param, icur ) )
return false;
++icur;
return true;
}
bool _do_match_this_c( match_param<IterT> & param, IterT & icur ) const
{
if( EosWrapT::opc_type::eval( param, icur ) )
return false;
++icur;
return true;
}
public:
virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )
{
if( greedy )
return new( arena ) max_atom_quantifier<IterT, match_any_t<IterT, EosWrapT> >( this, lbound, ubound );
else
return new( arena ) min_atom_quantifier<IterT, match_any_t<IterT, EosWrapT> >( this, lbound, ubound );
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return ( match_any_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return ( match_any_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );
}
virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this_s( param, icur );
}
virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this_c( param, icur );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this_s( param, param.m_icur );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this_c( param, param.m_icur );
}
};
template< typename IterT >
inline match_any<IterT> * create_any( REGEX_FLAGS flags, regex_arena & arena )
{
switch( SINGLELINE & flags )
{
case 0:
return new( arena ) match_any_t<IterT, REGEX_OP(eol_t) >();
case SINGLELINE:
return new( arena ) match_any_t<IterT, REGEX_OP(eos_t) >();
default:
REGEX_ASSERT(false);
return 0;
}
}
template< typename IterT >
class match_charset : public sub_expr<IterT>
{
public:
virtual width_type width_this( width_param<IterT> & )
{
width_type width = { 1, 1 };
return width;
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
--param.m_icur;
return false;
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
--param.m_icur;
return false;
}
};
template< typename IterT, typename CharSetPtrT, bool CaseT >
class match_charset_t : public match_charset<IterT>
{
CharSetPtrT const m_pcs;
match_charset_t & operator=( match_charset_t const & );
template< typename CStringsT >
bool _do_match_this( match_param<IterT> & param, IterT & icur REGEX_VC6(COMMA CStringsT) ) const
{
if( eos_t<CStringsT>::eval( param, icur ) ||
! m_pcs->REGEX_NVC6(template) in REGEX_NVC6(<CaseT>)( *icur REGEX_VC6(COMMA bool2type<CaseT>()) ) )
return false;
++icur;
return true;
}
public:
match_charset_t( CharSetPtrT pcs )
: m_pcs( pcs )
{
}
virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )
{
if( greedy )
return new( arena ) max_atom_quantifier<IterT, match_charset_t<IterT, CharSetPtrT, CaseT> >( this, lbound, ubound );
else
return new( arena ) min_atom_quantifier<IterT, match_charset_t<IterT, CharSetPtrT, CaseT> >( this, lbound, ubound );
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return ( match_charset_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return ( match_charset_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );
}
virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this REGEX_NVC6(<false_t>) ( param, param.m_icur REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this REGEX_NVC6(<true_t>) ( param, param.m_icur REGEX_VC6(COMMA true_t()) );
}
};
template< typename IterT >
inline match_charset<IterT> * create_charset
(
charset const & cs,
REGEX_FLAGS flags,
regex_arena & arena
)
{
switch( NOCASE & flags )
{
case 0:
return new( arena ) match_charset_t<IterT, charset const*, true>( &cs );
case NOCASE:
return new( arena ) match_charset_t<IterT, charset const*, false>( &cs );
default:
REGEX_ASSERT(false);
return 0;
}
}
template< typename IterT >
inline match_charset<IterT> * create_custom_charset
(
custom_charset const * pcs,
REGEX_FLAGS flags,
regex_arena & arena
)
{
typedef std::auto_ptr<custom_charset const> auto_charset;
auto_charset acs( pcs );
switch( NOCASE & flags )
{
case 0:
return new( arena ) match_charset_t<IterT, auto_charset, true>( acs );
case NOCASE:
return new( arena ) match_charset_t<IterT, auto_charset, false>( acs );
default:
REGEX_ASSERT(false);
return 0;
}
}
template< bool IsBoundaryT >
struct word_boundary
{
static bool eval( bool fprevword, bool fthisword )
{
return IsBoundaryT == ( fprevword != fthisword );
}
};
struct word_start
{
static bool eval( bool fprevword, bool fthisword )
{
return ! fprevword && fthisword;
}
};
struct word_stop
{
static bool eval( bool fprevword, bool fthisword )
{
return fprevword && ! fthisword;
}
};
template< typename IterT, typename CondT >
class word_assertion_t : public assertion<IterT>
{
word_assertion_t & operator=( word_assertion_t const & );
public:
typedef typename assertion<IterT>::char_type char_type;
word_assertion_t()
: m_isword( intrinsic_charsets<char_type>::get_word_charset() )
{
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return ( word_assertion_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return ( word_assertion_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );
}
virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this REGEX_NVC6(<false_t>) ( param, param.m_icur REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this REGEX_NVC6(<true_t>) ( param, param.m_icur REGEX_VC6(COMMA true_t()) );
}
private:
bool _is_word( char_type ch ) const
{
return REGEX_VC6( m_isword.in( ch COMMA true_t() ) )
REGEX_NVC6( m_isword.template in<true>( ch ) );
}
template< typename CStringsT >
bool _do_match_this( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
bool const fthisword = ! eos_t<CStringsT>::eval( param, icur ) && _is_word( *icur );
bool const fprevword = ! bos_t<CStringsT>::eval( param, icur ) && _is_word( *--icur );
return CondT::eval( fprevword, fthisword );
}
charset const & m_isword;
};
template< typename IterT >
inline assertion<IterT> * create_word_boundary
(
bool fisboundary,
REGEX_FLAGS, // flags
regex_arena & arena
)
{
if( fisboundary )
return new( arena ) word_assertion_t<IterT, word_boundary<true> >();
else
return new( arena ) word_assertion_t<IterT, word_boundary<false> >();
}
template< typename IterT >
inline assertion<IterT> * create_word_start( REGEX_FLAGS, regex_arena & arena )
{
return new( arena ) word_assertion_t<IterT, word_start>();
}
template< typename IterT >
inline assertion<IterT> * create_word_stop( REGEX_FLAGS, regex_arena & arena )
{
return new( arena ) word_assertion_t<IterT, word_stop>();
}
// an "extent" represents the range of backrefs that can be modified as the
// result of a look-ahead or look-behind
typedef std::pair<size_t, size_t> extent_type;
template< typename IterT > class max_group_quantifier;
template< typename IterT > class min_group_quantifier;
template< typename IterT >
class match_group_base : public sub_expr<IterT>
{
protected:
typedef slist<sub_expr<IterT>*,regex_arena> alt_list_type;
private:
match_group_base & operator=( match_group_base const & );
void _push_frame( match_param<IterT> & param ) const
{
unsafe_stack * ps = param.m_pstack;
if( size_t( -1 ) != m_cgroup )
{
IterT & reserved1 = param.m_prgbackrefs[ m_cgroup ].reserved1;
ps->push( reserved1 );
reserved1 = param.m_icur;
}
ps->push( m_rgalternates.begin() );
}
void _pop_frame( match_param<IterT> & param ) const
{
typedef typename alt_list_type::const_iterator iter_type;
unsafe_stack * ps = param.m_pstack;
REGEX_VC6( ps->pop( type2type<iter_type>() COMMA 0 ); )
REGEX_NVC6( ps->template pop<iter_type>(); )
if( size_t( -1 ) != m_cgroup )
ps->pop( param.m_prgbackrefs[ m_cgroup ].reserved1 );
}
template< typename CStringsT >
bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
typedef typename alt_list_type::const_iterator iter_type;
if( 0 != m_peek_chars_begin &&
( eos_t<CStringsT>::eval( param, icur ) ||
m_peek_chars_end == std::find( m_peek_chars_begin, m_peek_chars_end, *icur ) ) )
{
return false;
}
if( size_t( -1 ) != m_cgroup ) // could be -1 if this is a lookahead_assertion
{
IterT & reserved1 = param.m_prgbackrefs[ m_cgroup ].reserved1;
IterT old_ibegin = reserved1;
reserved1 = icur;
for( iter_type ialt = m_rgalternates.begin(); m_rgalternates.end() != ialt; ++ialt )
{
if( (*ialt)->recursive_match_all( param, icur, CStringsT() ) )
return true;
}
reserved1 = old_ibegin;
}
else
{
for( iter_type ialt = m_rgalternates.begin(); m_rgalternates.end() != ialt; ++ialt )
{
if( (*ialt)->recursive_match_all( param, icur, CStringsT() ) )
return true;
}
}
return false;
}
template< typename CStringsT >
bool _do_iterative_match_this( match_param<IterT> & param REGEX_VC6(COMMA CStringsT) ) const
{
if( 0 != m_peek_chars_begin &&
( eos_t<CStringsT>::eval( param, param.m_icur ) ||
m_peek_chars_end == std::find( m_peek_chars_begin, m_peek_chars_end, *param.m_icur ) ) )
{
return false;
}
_push_frame( param );
param.m_pnext = *m_rgalternates.begin();
return true;
}
bool _do_iterative_rematch_this( match_param<IterT> & param ) const
{
typedef typename alt_list_type::const_iterator iter_type;
iter_type next_iter = ++param.m_pstack->REGEX_NVC6(template) top REGEX_NVC6(<iter_type>) ( REGEX_VC6(type2type<iter_type>()) );
if( m_rgalternates.end() != next_iter )
{
param.m_pnext = *next_iter;
return true;
}
_pop_frame( param );
return false;
}
public:
typedef typename sub_expr<IterT>::char_type char_type;
match_group_base( size_t cgroup, regex_arena & arena )
: m_rgalternates( arena_allocator<sub_expr<IterT>*>( arena ) )
, m_cgroup( cgroup )
, m_nwidth( uninit_width() )
, m_pptail( 0 )
, m_peek_chars_end( 0 )
{
}
// Derived classes that own the end_group object must have a
// destructor, and that destructor must call _cleanup().
virtual ~match_group_base() = 0;
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
return _do_iterative_match_this REGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
return _do_iterative_match_this REGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
size_t group_number() const
{
return m_cgroup;
}
void add_item( sub_expr<IterT> * pitem )
{
*m_pptail = pitem;
m_pptail = pitem->pnext();
}
void add_alternate()
{
m_rgalternates.push_front( 0 );
m_pptail = &*m_rgalternates.begin();
}
void end_alternate()
{
*m_pptail = _get_end_group();
}
void open_group()
{
add_alternate();
}
must_have<char_type> close_group( regex_arena & arena )
{
end_alternate();
m_rgalternates.reverse();
return get_peek_chars( arena );
}
must_have<char_type> get_peek_chars( regex_arena & arena )
{
m_peek_chars_begin = 0;
// optimization: find the lookahead characters for each alternate
size_t total_chars = 0;
peek_param<char_type> peek;
typename alt_list_type::const_iterator ialt;
for( ialt = m_rgalternates.begin(); m_rgalternates.end() != ialt; ++ialt )
{
if( ! (*ialt)->peek_this( peek ) )
{
peek.m_must_have.m_has = false;
return peek.m_must_have;
}
total_chars += peek.m_cchars;
}
arena_allocator<char_type> alloc( arena );
m_peek_chars_begin = alloc.allocate( total_chars, 0 );
m_peek_chars_end = m_peek_chars_begin;
for( ialt = m_rgalternates.begin(); m_rgalternates.end() != ialt; ++ialt )
{
(*ialt)->peek_this( peek );
char_type const * in = ( peek.m_cchars > 2 ) ? peek.m_pchars : peek.m_rgchars;
m_peek_chars_end = std::copy( in, in + peek.m_cchars, m_peek_chars_end );
}
std::sort( m_peek_chars_begin, m_peek_chars_end );
m_peek_chars_end = std::unique( m_peek_chars_begin, m_peek_chars_end );
if( 1 < m_rgalternates.size() )
peek.m_must_have.m_has = false;
return peek.m_must_have;
}
size_t calternates() const
{
return m_rgalternates.size();
}
virtual void set_extent( extent_type const & )
{
}
width_type group_width
(
std::vector<match_group_base<IterT>*> & rggroups,
std::list<size_t> const & invisible_groups
)
{
// This should only be called on the top node
REGEX_ASSERT( 0 == m_cgroup );
if( uninit_width() == m_nwidth )
{
width_param<IterT> param( rggroups, invisible_groups );
match_group_base<IterT>::width_this( param );
}
return m_nwidth;
}
virtual width_type width_this( width_param<IterT> & param )
{
typedef typename alt_list_type::const_iterator iter_type;
width_type width = { size_t( -1 ), 0 };
for( iter_type ialt = m_rgalternates.begin(); worst_width != width && m_rgalternates.end() != ialt; ++ialt )
{
// prevent possible infinite recursion
if( m_cgroup < param.m_rggroups.size() )
param.m_rggroups[ m_cgroup ] = 0;
width_type temp_width = ( *ialt )->get_width( param );
if( m_cgroup < param.m_rggroups.size() )
param.m_rggroups[ m_cgroup ] = this;
width.m_min = regex_min( width.m_min, temp_width.m_min );
width.m_max = regex_max( width.m_max, temp_width.m_max );
}
return m_nwidth = width;
}
virtual bool peek_this( peek_param<char_type> & peek ) const
{
if( 0 == m_peek_chars_begin )
return false;
peek.m_cchars = std::distance( m_peek_chars_begin, m_peek_chars_end );
if( 2 < peek.m_cchars )
peek.m_pchars = m_peek_chars_begin;
else
std::copy( m_peek_chars_begin, m_peek_chars_end, peek.m_rgchars );
peek.m_must_have.m_has = false;
if( 1 == m_rgalternates.size() )
{
peek_param<char_type> local_peek;
(*m_rgalternates.begin())->peek_this( local_peek );
peek.m_must_have = local_peek.m_must_have;
}
return true;
}
protected:
void _cleanup()
{
typedef typename alt_list_type::const_iterator iter_type;
for( iter_type ialt = m_rgalternates.begin(); m_rgalternates.end() != ialt; ++ialt )
delete *ialt;
m_rgalternates.clear();
}
virtual sub_expr<IterT> * _get_end_group() = 0;
alt_list_type m_rgalternates;
size_t const m_cgroup;
width_type m_nwidth;
union
{
sub_expr<IterT> ** m_pptail; // only used when adding elements
char_type * m_peek_chars_begin;
};
char_type * m_peek_chars_end;
};
template< typename IterT >
inline match_group_base<IterT>::~match_group_base()
{
}
// A indestructable_sub_expr is an object that brings itself back
// to life after explicitly being deleted. It is used
// to ease clean-up of the sub_expr graph, where most
// nodes are dynamically allocated, but some nodes are
// members of other nodes and are not dynamically allocated.
// The recursive delete of the sub_expr graph causes
// delete to be ( incorrectly ) called on these members.
// By inheriting these members from indestructable_sub_expr,
// explicit attempts to delete the object will have no
// effect. ( Actually, the object will be destructed and
// then immediately reconstructed. ) This is accomplished
// by calling placement new in operator delete.
template< typename IterT, typename T >
class indestructable_sub_expr : public sub_expr<IterT>
{
static void * operator new( size_t, regex_arena & );
static void operator delete( void *, regex_arena & );
protected:
static void * operator new( size_t, void * pv ) { return pv; }
static void operator delete( void *, void * ) {}
public:
virtual ~indestructable_sub_expr() {}
static void operator delete( void * pv ) { ::new( pv ) T; }
};
template< typename IterT >
class match_group : public match_group_base<IterT>
{
match_group( match_group const & );
match_group & operator=( match_group const & );
public:
match_group( size_t cgroup, regex_arena & arena )
: match_group_base<IterT>( cgroup, arena )
, m_end_group( this )
{
}
virtual ~match_group()
{
this->_cleanup();
}
virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )
{
if( greedy )
return new( arena ) max_group_quantifier<IterT>( this, lbound, ubound );
else
return new( arena ) min_group_quantifier<IterT>( this, lbound, ubound );
}
protected:
typedef typename match_group_base<IterT>::alt_list_type alt_list_type;
struct old_backref
{
IterT m_ibegin;
IterT m_iend;
bool m_matched;
old_backref() {}
old_backref( backref_tag<IterT> const & br )
: m_ibegin( br.first )
, m_iend( br.second )
, m_matched( br.matched )
{
}
};
static void restore_backref( backref_tag<IterT> & br, old_backref const & old_br )
{
br.first = old_br.m_ibegin;
br.second = old_br.m_iend;
br.matched = old_br.m_matched;
}
template< typename CStringsT >
bool _do_call_back( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
if( size_t( -1 ) != this->m_cgroup )
{
backref_tag<IterT> & br = param.m_prgbackrefs[ this->m_cgroup ];
// Save the relevant portions of the backref in an old_backref struct
old_backref old_br( br );
br.first = br.reserved1;
br.second = icur;
br.matched = true;
if( this->recursive_match_next( param, icur, CStringsT() ) )
return true;
// Restore the backref to its saved state
restore_backref( br, old_br );
}
else
{
if( this->recursive_match_next( param, icur, CStringsT() ) )
return true;
}
return false;
}
class end_group : public indestructable_sub_expr<IterT, end_group>
{
match_group<IterT> const *const m_pgroup;
end_group & operator=( end_group const & );
void _push_frame( match_param<IterT> & param ) const
{
size_t cgroup = m_pgroup->group_number();
if( size_t( -1 ) != cgroup )
{
backref_tag<IterT> & br = param.m_prgbackrefs[ cgroup ];
old_backref old_br( br );
param.m_pstack->push( old_br );
br.first = br.reserved1;
br.second = param.m_icur;
br.matched = true;
}
}
void _pop_frame( match_param<IterT> & param ) const
{
size_t cgroup = m_pgroup->group_number();
if( size_t( -1 ) != cgroup )
{
old_backref old_br;
param.m_pstack->pop( old_br );
match_group<IterT>::restore_backref( param.m_prgbackrefs[ cgroup ], old_br );
}
}
bool _do_iterative_match_this( match_param<IterT> & param ) const
{
_push_frame( param );
param.m_pnext = m_pgroup->next();
return true;
}
bool _do_iterative_rematch_this( match_param<IterT> & param ) const
{
_pop_frame( param );
return false;
}
public:
end_group( match_group<IterT> const * pgroup = 0 )
: m_pgroup( pgroup )
{
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return m_pgroup->REGEX_NVC6(template) _do_call_back REGEX_NVC6(<false_t>)( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return m_pgroup->REGEX_NVC6(template) _do_call_back REGEX_NVC6(<true_t>)( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
return _do_iterative_match_this( param );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
return _do_iterative_match_this( param );
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual width_type width_this( width_param<IterT> & )
{
return zero_width;
}
} m_end_group;
friend class end_group;
virtual sub_expr<IterT> * _get_end_group()
{
return & m_end_group;
}
};
template< typename IterT >
inline void save_backrefs( backref_tag<IterT> const * ibegin, backref_tag<IterT> const * iend, IterT * prgci )
{
for( ; ibegin != iend; ++ibegin, ++prgci )
{
new( prgci ) IterT( ibegin->reserved1 );
}
}
template< typename IterT >
inline void restore_backrefs( backref_tag<IterT> * ibegin, backref_tag<IterT> * iend, IterT const * prgci )
{
for( ; ibegin != iend; ++ibegin, ++prgci )
{
ibegin->reserved1 = *prgci;
prgci->~IterT();
}
}
template< typename IterT >
class group_wrapper : public sub_expr<IterT>
{
match_group_base<IterT> const *const m_pgroup;
group_wrapper & operator=( group_wrapper const & );
public:
group_wrapper( match_group_base<IterT> const * pgroup )
: m_pgroup( pgroup )
{
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
return m_pgroup->match_group_base<IterT>::iterative_match_this_s( param );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
return m_pgroup->match_group_base<IterT>::iterative_match_this_c( param );
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
return m_pgroup->match_group_base<IterT>::iterative_rematch_this_s( param );
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
return m_pgroup->match_group_base<IterT>::iterative_rematch_this_c( param );
}
virtual width_type width_this( width_param<IterT> & )
{
return zero_width;
}
};
struct deleter
{
template< typename T >
void operator()( T const & t )
{
t.T::~T();
}
};
// Behaves like a lookahead assertion if m_cgroup is -1, or like
// an independent group otherwise.
template< typename IterT >
class independent_group_base : public match_group_base<IterT>
{
independent_group_base( independent_group_base const & );
independent_group_base & operator=( independent_group_base const & );
template< typename CStringsT >
bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
backref_tag<IterT> * prgbr = 0;
// Copy onto the stack the part of the backref vector that could
// be modified by the lookahead.
if( m_extent.second )
{
prgbr = static_cast<backref_tag<IterT>*>( alloca( m_extent.second * sizeof( backref_tag<IterT> ) ) );
std::uninitialized_copy(
param.m_prgbackrefs + m_extent.first,
param.m_prgbackrefs + m_extent.first + m_extent.second,
prgbr );
}
// Match until the end of this group and then return
// BUGBUG can the compiler optimize this?
bool const fdomatch = CStringsT::value ?
match_group_base<IterT>::recursive_match_all_c( param, icur ) :
match_group_base<IterT>::recursive_match_all_s( param, icur );
if( m_fexpected == fdomatch )
{
// If m_cgroup != 1, then this is not a zero-width assertion.
if( fdomatch && size_t( -1 ) != this->m_cgroup )
icur = param.m_prgbackrefs[ this->m_cgroup ].second;
if( this->recursive_match_next( param, icur, CStringsT() ) )
{
std::for_each( prgbr, prgbr + m_extent.second, deleter() );
return true;
}
}
// if match_group::recursive_match_all returned true, the backrefs must be restored
if( m_extent.second && fdomatch )
std::copy( prgbr, prgbr + m_extent.second, param.m_prgbackrefs + m_extent.first );
std::for_each( prgbr, prgbr + m_extent.second, deleter() );
return false;
}
template< typename CStringsT >
bool _do_iterative_match_this( match_param<IterT> & param REGEX_VC6(COMMA CStringsT) ) const
{
group_wrapper<IterT> expr( this );
_push_frame( param );
IterT ibegin = param.m_icur;
bool const fdomatch = _do_match_iterative( &expr, param, param.m_icur, CStringsT() );
if( m_fexpected == fdomatch )
{
// If m_cgroup == -1, then this is a zero-width assertion.
if( fdomatch && size_t( -1 ) == this->m_cgroup )
param.m_icur = ibegin;
param.m_pnext = this->next();
return true;
}
_pop_frame( param );
return false;
}
bool _do_iterative_rematch_this( match_param<IterT> & param ) const
{
_pop_frame( param );
return false;
}
public:
independent_group_base( size_t cgroup, regex_arena & arena )
: match_group_base<IterT>( cgroup, arena )
, m_fexpected( true )
, m_extent( 0, 0 )
{
}
virtual void set_extent( extent_type const & ex )
{
m_extent = ex;
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
return _do_iterative_match_this REGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
return _do_iterative_match_this REGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual bool peek_this( peek_param<char_type> & peek ) const
{
if( size_t( -1 ) == this->m_cgroup )
return false;
return match_group_base<IterT>::peek_this( peek );
}
protected:
void _push_frame( match_param<IterT> & param ) const
{
unsafe_stack * pstack = param.m_pstack;
typedef typename match_param<IterT>::backref_type backref_type;
backref_type * ibegin = param.m_prgbackrefs + m_extent.first;
backref_type * iend = ibegin + m_extent.second;
for( ; iend != ibegin; ++ibegin )
{
pstack->push( *ibegin );
}
pstack->push( param.m_icur );
}
void _pop_frame( match_param<IterT> & param ) const
{
unsafe_stack * pstack = param.m_pstack;
typedef typename match_param<IterT>::backref_type backref_type;
backref_type * ibegin = param.m_prgbackrefs + m_extent.first;
backref_type * iend = ibegin + m_extent.second;
pstack->pop( param.m_icur );
while( iend != ibegin )
{
pstack->pop( *--iend );
}
}
independent_group_base( bool const fexpected, regex_arena & arena )
: match_group_base<IterT>( size_t( -1 ), arena )
, m_fexpected( fexpected )
{
}
bool const m_fexpected;
extent_type m_extent;
};
template< typename IterT >
class independent_group : public independent_group_base<IterT>
{
independent_group( independent_group const & );
independent_group & operator=( independent_group const & );
public:
independent_group( size_t cgroup, regex_arena & arena )
: independent_group_base<IterT>( cgroup, arena )
, m_end_group( this )
{
}
virtual ~independent_group()
{
this->_cleanup();
}
virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )
{
if( greedy )
return new( arena ) max_group_quantifier<IterT>( this, lbound, ubound );
else
return new( arena ) min_group_quantifier<IterT>( this, lbound, ubound );
}
protected:
independent_group( bool const fexpected, regex_arena & arena )
: independent_group_base<IterT>( fexpected, arena )
, m_end_group( this )
{
}
bool _do_call_back( match_param<IterT> & param, IterT icur ) const
{
if( size_t( -1 ) != this->m_cgroup )
{
backref_tag<IterT> & br = param.m_prgbackrefs[ this->m_cgroup ];
br.first = br.reserved1;
br.second = icur;
br.matched = true;
}
return true;
}
class end_group : public indestructable_sub_expr<IterT, end_group>
{
independent_group<IterT> const *const m_pgroup;
end_group & operator=( end_group const & );
bool _do_iterative_match_this( match_param<IterT> & param ) const
{
size_t cgroup = m_pgroup->group_number();
if( size_t( -1 ) != cgroup )
{
backref_tag<IterT> & br = param.m_prgbackrefs[ cgroup ];
br.first = br.reserved1;
br.second = param.m_icur;
br.matched = true;
}
param.m_pnext = 0;
return true;
}
public:
end_group( independent_group<IterT> const * pgroup = 0 )
: m_pgroup( pgroup )
{
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return m_pgroup->_do_call_back( param, icur );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return m_pgroup->_do_call_back( param, icur );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
return _do_iterative_match_this( param );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
return _do_iterative_match_this( param );
}
virtual width_type width_this( width_param<IterT> & )
{
return zero_width;
}
} m_end_group;
friend class end_group;
virtual sub_expr<IterT> * _get_end_group()
{
return & m_end_group;
}
};
template< typename IterT >
class lookahead_assertion : public independent_group<IterT>
{
lookahead_assertion( lookahead_assertion const & );
lookahead_assertion & operator=( lookahead_assertion const & );
public:
lookahead_assertion( bool const fexpected, regex_arena & arena )
: independent_group<IterT>( fexpected, arena )
{
}
virtual sub_expr<IterT> * quantify( size_t, size_t, bool, regex_arena & )
{
throw bad_regexpr( "look-ahead assertion cannot be quantified" );
}
virtual bool is_assertion() const
{
return true;
}
virtual width_type width_this( width_param<IterT> & param )
{
// calculate the group's width and store it, but return zero_width
match_group_base<IterT>::width_this( param );
return zero_width;
}
virtual bool peek_this( peek_param<char_type> & peek ) const
{
return this->next()->peek_this( peek );
}
};
template< typename IterT >
class lookbehind_assertion : public independent_group_base<IterT>
{
lookbehind_assertion( lookbehind_assertion const & );
lookbehind_assertion & operator=( lookbehind_assertion const & );
template< typename CStringsT >
bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
typedef typename std::iterator_traits<IterT>::difference_type diff_type;
// This is the room in the string from the start to the current position
diff_type room = std::distance( param.m_ibufferbegin, icur );
// If we don't have enough room to match the lookbehind, the match fails.
// If we wanted the match to fail, try to match the rest of the pattern.
if( this->m_nwidth.m_min > static_cast<size_t>( room ) )
return this->m_fexpected ? false : this->recursive_match_next( param, icur, CStringsT() );
backref_tag<IterT> * prgbr = 0;
// Copy onto the stack the part of the backref vector that could
// be modified by the lookbehind.
if( this->m_extent.second )
{
prgbr = static_cast<backref_tag<IterT>*>( alloca( this->m_extent.second * sizeof( backref_tag<IterT> ) ) );
std::uninitialized_copy(
param.m_prgbackrefs + this->m_extent.first,
param.m_prgbackrefs + this->m_extent.first + this->m_extent.second,
prgbr );
}
IterT local_ibegin = icur;
std::advance( local_ibegin, -static_cast<diff_type>( regex_min<size_t>( this->m_nwidth.m_max, room ) ) );
IterT local_iend = icur;
std::advance( local_iend, -static_cast<diff_type>( this->m_nwidth.m_min ) );
// Create a local param struct that has icur as param.m_iend
match_param<IterT> local_param( param.m_ibufferbegin, param.m_imatchbegin, icur, param.m_prgbackrefs, param.m_cbackrefs );
// Find the rightmost match that ends at icur.
for( IterT local_icur = local_ibegin; ; ++local_icur )
{
// Match until the end of this group and then return
// Note that we're calling recursive_match_all_s regardless of the CStringsT switch.
// This is because for the lookbehind assertion, the termination condition is when
// icur == param.m_iend, not when *icur == '/0'
bool const fmatched = match_group_base<IterT>::recursive_match_all_s( local_param, local_icur );
// If the match results were what we were expecting, try to match the
// rest of the pattern. If that succeeds, return true.
if( this->m_fexpected == fmatched && this->recursive_match_next( param, icur, CStringsT() ) )
{
std::for_each( prgbr, prgbr + this->m_extent.second, deleter() );
return true;
}
// if match_group::recursive_match_all returned true, the backrefs must be restored
if( fmatched )
{
if( this->m_extent.second )
std::copy( prgbr, prgbr + this->m_extent.second, param.m_prgbackrefs + this->m_extent.first );
// Match succeeded. If this is a negative lookbehind, we didn't want it
// to succeed, so return false.
if( ! this->m_fexpected )
{
std::for_each( prgbr, prgbr + this->m_extent.second, deleter() );
return false;
}
}
if( local_icur == local_iend )
break;
}
// No variation of the lookbehind was satisfied in a way that permited
// the rest of the pattern to match successfully, so return false.
std::for_each( prgbr, prgbr + this->m_extent.second, deleter() );
return false;
}
template< typename CStringsT >
bool _do_iterative_match_this( match_param<IterT> & param REGEX_VC6(COMMA CStringsT) ) const
{
typedef typename std::iterator_traits<IterT>::difference_type diff_type;
// Save the backrefs
this->_push_frame( param );
// This is the room in the string from the start to the current position
diff_type room = std::distance( param.m_ibufferbegin, param.m_icur );
// If we don't have enough room to match the lookbehind, the match fails.
// If we wanted the match to fail, try to match the rest of the pattern.
if( this->m_nwidth.m_min > static_cast<size_t>( room ) )
{
if( this->m_fexpected )
{
this->_pop_frame( param );
return false;
}
param.m_pnext = this->next();
return true;
}
IterT local_ibegin = param.m_icur;
std::advance( local_ibegin, -static_cast<diff_type>( regex_min<size_t>( this->m_nwidth.m_max, room ) ) );
IterT local_iend = param.m_icur;
std::advance( local_iend, -static_cast<diff_type>( this->m_nwidth.m_min ) );
// Create a local param struct that has icur as param.m_iend
match_param<IterT> local_param( param.m_ibufferbegin, param.m_imatchbegin, param.m_icur, param.m_prgbackrefs, param.m_cbackrefs );
local_param.m_pstack = param.m_pstack;
group_wrapper<IterT> expr( this );
// Find the rightmost match that ends at icur.
for( IterT local_icur = local_ibegin; ; ++local_icur )
{
// Match until the end of this group and then return
// Note that we're calling _do_match_iterative_helper_s regardless of the CStringsT switch.
// This is because for the lookbehind assertion, the termination condition is when
// icur == param.m_iend, not when *icur == '/0'
bool const fmatched = regex_access<IterT>::_do_match_iterative_helper_s( &expr, local_param, local_icur );
// If the match results were what we were expecting, try to match the
// rest of the pattern. If that succeeds, return true.
if( this->m_fexpected == fmatched )
{
param.m_pnext = this->next();
return true;
}
// if match_group::recursive_match_all returned true, the backrefs must be restored
if( fmatched )
{
// Restore the backrefs
this->_pop_frame( param );
// Match succeeded. If this is a negative lookbehind, we didn't want it
// to succeed, so return false.
if( ! this->m_fexpected )
return false;
// Save the backrefs again.
this->_push_frame( param );
}
if( local_icur == local_iend )
break;
}
// No variation of the lookbehind was satisfied in a way that permited
// the rest of the pattern to match successfully, so return false.
this->_pop_frame( param );
return false;
}
bool _do_iterative_rematch_this( match_param<IterT> & param ) const
{
this->_pop_frame( param );
return false;
}
public:
lookbehind_assertion( bool const fexpected, regex_arena & arena )
: independent_group_base<IterT>( fexpected, arena )
{
}
virtual ~lookbehind_assertion()
{
this->_cleanup();
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
return _do_iterative_match_this REGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
return _do_iterative_match_this REGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual bool is_assertion() const
{
return true;
}
virtual width_type width_this( width_param<IterT> & param )
{
// calculate the group's width and store it, but return zero_width
match_group_base<IterT>::width_this( param );
return zero_width;
}
virtual bool peek_this( peek_param<char_type> & peek ) const
{
return this->next()->peek_this( peek );
}
protected:
struct end_group : public indestructable_sub_expr<IterT, end_group>
{
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return param.m_iend == icur;
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return param.m_iend == icur;
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
param.m_pnext = 0;
return param.m_iend == param.m_icur;
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
param.m_pnext = 0;
return param.m_iend == param.m_icur;
}
virtual width_type width_this( width_param<IterT> & )
{
return zero_width;
}
} m_end_group;
virtual sub_expr<IterT> * _get_end_group()
{
return & m_end_group;
}
};
template< typename IterT >
class group_quantifier : public match_quantifier<IterT>
{
group_quantifier & operator=( group_quantifier const & );
bool _do_iterative_match_this( match_param<IterT> & param ) const
{
_push_frame( param );
param.m_pnext = this->m_psub->next(); // ptr to end_quant
return true;
}
bool _do_iterative_rematch_this( match_param<IterT> & param ) const
{
_pop_frame( param );
return false;
}
public:
group_quantifier
(
match_group_base<IterT> * psub,
size_t lbound,
size_t ubound,
sub_expr<IterT> * pend_quant
)
: match_quantifier<IterT>( psub, lbound, ubound )
, m_group( *psub )
{
*psub->pnext() = pend_quant;
}
// sub-classes of group_quantifer that own the end_quant
// object must declare a destructor, and it must call _cleanup
virtual ~group_quantifier() = 0;
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
return _do_iterative_match_this( param );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
return _do_iterative_match_this( param );
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
protected:
struct old_quant
{
typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;
size_t reserved2;
bool reserved3;
smart_iter_type reserved4;
smart_iter_type reserved5;
old_quant()
{
}
old_quant( backref_tag<IterT> const & br )
: reserved2( br.reserved2 )
, reserved3( br.reserved3 )
, reserved4( br.reserved4 )
, reserved5( br.reserved5 )
{
}
};
void _push_frame( match_param<IterT> & param ) const
{
typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;
backref_tag<IterT> & br = param.m_prgbackrefs[ group_number() ];
old_quant old_qt( br );
param.m_pstack->push( old_qt );
br.reserved2 = 0; // nbr of times this group has matched
br.reserved3 = true; // toggle used for backtracking
br.reserved4 = static_init<smart_iter_type>::value;
br.reserved5 = static_init<smart_iter_type>::value;
}
void _pop_frame( match_param<IterT> & param ) const
{
backref_tag<IterT> & br = param.m_prgbackrefs[ group_number() ];
old_quant old_qt;
param.m_pstack->pop( old_qt );
br.reserved2 = old_qt.reserved2;
br.reserved3 = old_qt.reserved3;
br.reserved4 = old_qt.reserved4;
br.reserved5 = old_qt.reserved5;
}
size_t group_number() const
{
return m_group.group_number();
}
size_t & cmatches( match_param<IterT> & param ) const
{
return param.m_prgbackrefs[ group_number() ].reserved2;
}
typename backref_tag<IterT>::smart_iter_type & highwater1( match_param<IterT> & param ) const
{
return param.m_prgbackrefs[ group_number() ].reserved4;
}
typename backref_tag<IterT>::smart_iter_type & highwater2( match_param<IterT> & param ) const
{
return param.m_prgbackrefs[ group_number() ].reserved5;
}
match_group_base<IterT> const & m_group;
};
template< typename IterT >
inline group_quantifier<IterT>::~group_quantifier()
{
}
template< typename IterT >
class max_group_quantifier : public group_quantifier<IterT>
{
max_group_quantifier & operator=( max_group_quantifier const & );
template< typename CStringsT >
bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;
smart_iter_type old_highwater1 = this->highwater1( param );
smart_iter_type old_highwater2 = this->highwater2( param );
size_t old_cmatches = this->cmatches( param );
this->highwater1( param ) = static_init<smart_iter_type>::value;
this->highwater2( param ) = icur;
this->cmatches( param ) = 0;
if( _do_recurse REGEX_NVC6(<CStringsT>) ( param, icur REGEX_VC6(COMMA CStringsT()) ) )
return true;
this->cmatches( param ) = old_cmatches;
this->highwater2( param ) = old_highwater2;
this->highwater1( param ) = old_highwater1;
return false;
}
public:
max_group_quantifier( match_group_base<IterT> * psub, size_t lbound, size_t ubound )
: group_quantifier<IterT>( psub, lbound, ubound, & m_end_quant )
, m_end_quant( this )
{
}
virtual ~max_group_quantifier()
{
// Must call _cleanup() here before the end_quant object
// gets destroyed.
this->_cleanup();
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
protected:
template< typename CStringsT >
bool _do_recurse( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
if( this->m_ubound == this->cmatches( param ) )
return this->recursive_match_next( param, icur, CStringsT() );
++this->cmatches( param );
if( this->m_psub->recursive_match_all( param, icur, CStringsT() ) )
return true;
if( --this->cmatches( param ) < this->m_lbound )
return false;
return this->recursive_match_next( param, icur, CStringsT() );
}
class end_quantifier : public indestructable_sub_expr<IterT, end_quantifier>
{
max_group_quantifier<IterT> const *const m_pquant;
end_quantifier & operator=( end_quantifier const & );
void _push_frame( match_param<IterT> & param ) const
{
backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];
param.m_pstack->push( br.reserved4 );
br.reserved4 = br.reserved5;
br.reserved5 = param.m_icur;
}
void _pop_frame( match_param<IterT> & param ) const
{
backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];
br.reserved5 = br.reserved4;
param.m_pstack->pop( br.reserved4 );
}
template< typename CStringsT >
bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;
smart_iter_type old_highwater1 = m_pquant->highwater1( param );
if( icur == old_highwater1 )
return m_pquant->recursive_match_next( param, icur, CStringsT() );
m_pquant->highwater1( param ) = m_pquant->highwater2( param );
m_pquant->highwater2( param ) = icur;
if( m_pquant->REGEX_NVC6(template) _do_recurse REGEX_NVC6(<CStringsT>) ( param, icur REGEX_VC6(COMMA CStringsT()) ) )
return true;
m_pquant->highwater2( param ) = m_pquant->highwater1( param );
m_pquant->highwater1( param ) = old_highwater1;
return false;
}
bool _do_iterative_match_this( match_param<IterT> & param ) const
{
backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];
// forcibly break the infinite loop
if( param.m_icur == br.reserved4 )
{
_push_frame( param );
param.m_pnext = m_pquant->next();
return true;
}
_push_frame( param );
// If we've matched the max nbr of times, move on to the next
// sub-expr.
if( m_pquant->m_ubound == br.reserved2 )
{
param.m_pnext = m_pquant->next();
br.reserved3 = false;
return true;
}
// Rematch the group.
br.reserved3 = true;
param.m_pnext = m_pquant->m_psub;
++br.reserved2;
return true;
}
bool _do_iterative_rematch_this( match_param<IterT> & param ) const
{
typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;
backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];
// infinite loop forcibly broken
if( param.m_icur == param.m_pstack->REGEX_NVC6(template) top REGEX_NVC6(<smart_iter_type>) ( REGEX_VC6(type2type<smart_iter_type>()) ) )
{
_pop_frame( param );
return false;
}
if( br.reserved3 )
{
--br.reserved2;
param.m_pnext = m_pquant->next();
if( m_pquant->m_lbound <= br.reserved2 )
{
br.reserved3 = false;
return true;
}
_pop_frame( param );
return false;
}
br.reserved3 = true;
_pop_frame( param );
return false;
}
public:
end_quantifier( max_group_quantifier<IterT> const * pquant = 0 )
: m_pquant( pquant )
{
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
return _do_iterative_match_this( param );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
return _do_iterative_match_this( param );
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual width_type width_this( width_param<IterT> & )
{
return zero_width;
}
} m_end_quant;
friend class end_quantifier;
};
template< typename IterT >
class min_group_quantifier : public group_quantifier<IterT>
{
min_group_quantifier & operator=( min_group_quantifier const & );
template< typename CStringsT >
bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;
smart_iter_type old_highwater1 = this->highwater1( param );
smart_iter_type old_highwater2 = this->highwater2( param );
size_t old_cmatches = this->cmatches( param );
this->highwater1( param ) = static_init<smart_iter_type>::value;
this->highwater2( param ) = icur;
this->cmatches( param ) = 0;
if( _do_recurse REGEX_NVC6(<CStringsT>) ( param, icur REGEX_VC6(COMMA CStringsT()) ) )
return true;
this->cmatches( param ) = old_cmatches;
this->highwater2( param ) = old_highwater2;
this->highwater1( param ) = old_highwater1;
return false;
}
public:
min_group_quantifier( match_group_base<IterT> * psub, size_t lbound, size_t ubound )
: group_quantifier<IterT>( psub, lbound, ubound, & m_end_quant )
, m_end_quant( this )
{
}
virtual ~min_group_quantifier()
{
// Must call _cleanup() here before the end_quant object
// gets destroyed.
this->_cleanup();
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
protected:
template< typename CStringsT >
bool _do_recurse( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
if( this->m_lbound <= this->cmatches( param ) )
{
if( this->recursive_match_next( param, icur, CStringsT() ) )
return true;
}
if( this->m_ubound > this->cmatches( param ) )
{
++this->cmatches( param );
if( this->m_psub->recursive_match_all( param, icur, CStringsT() ) )
return true;
--this->cmatches( param );
}
return false;
}
class end_quantifier : public indestructable_sub_expr<IterT, end_quantifier>
{
min_group_quantifier<IterT> const *const m_pquant;
end_quantifier & operator=( end_quantifier const & );
void _push_frame( match_param<IterT> & param ) const
{
backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];
param.m_pstack->push( br.reserved4 );
br.reserved4 = br.reserved5;
br.reserved5 = param.m_icur;
}
void _pop_frame( match_param<IterT> & param ) const
{
backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];
br.reserved5 = br.reserved4;
param.m_pstack->pop( br.reserved4 );
}
template< typename CStringsT >
bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;
smart_iter_type old_highwater1 = m_pquant->highwater1( param );
if( icur == old_highwater1 )
return m_pquant->recursive_match_next( param, icur, CStringsT() );
m_pquant->highwater1( param ) = m_pquant->highwater2( param );
m_pquant->highwater2( param ) = icur;
if( m_pquant->REGEX_NVC6(template) _do_recurse REGEX_NVC6(<CStringsT>) ( param, icur REGEX_VC6(COMMA CStringsT()) ) )
return true;
m_pquant->highwater2( param ) = m_pquant->highwater1( param );
m_pquant->highwater1( param ) = old_highwater1;
return false;
}
bool _do_iterative_match_this( match_param<IterT> & param ) const
{
backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];
// forcibly break the infinite loop
if( param.m_icur == br.reserved4 )
{
_push_frame( param );
param.m_pnext = m_pquant->next();
return true;
}
_push_frame( param );
if( m_pquant->m_lbound <= br.reserved2 )
{
br.reserved3 = false;
param.m_pnext = m_pquant->next();
return true;
}
++br.reserved2;
param.m_pnext = m_pquant->m_psub;
return true;
}
bool _do_iterative_rematch_this( match_param<IterT> & param ) const
{
typedef typename backref_tag<IterT>::smart_iter_type smart_iter_type;
backref_tag<IterT> & br = param.m_prgbackrefs[ m_pquant->group_number() ];
// infinite loop forcibly broken
if( param.m_icur == param.m_pstack->REGEX_NVC6(template) top REGEX_NVC6(<smart_iter_type>) ( REGEX_VC6(type2type<smart_iter_type>()) ) )
{
_pop_frame( param );
return false;
}
if( br.reserved3 )
{
--br.reserved2;
_pop_frame( param );
return false;
}
br.reserved3 = true;
if( m_pquant->m_ubound > br.reserved2 )
{
++br.reserved2;
param.m_pnext = m_pquant->m_psub;
return true;
}
_pop_frame( param );
return false;
}
public:
end_quantifier( min_group_quantifier<IterT> const * pquant = 0 )
: m_pquant( pquant )
{
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
return _do_iterative_match_this( param );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
return _do_iterative_match_this( param );
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual width_type width_this( width_param<IterT> & )
{
return zero_width;
}
} m_end_quant;
friend class end_quantifier;
};
inline void fixup_backref( size_t & cbackref, std::list<size_t> const & invisible_groups )
{
std::list<size_t>::const_iterator iter = invisible_groups.begin();
for( ; invisible_groups.end() != iter && cbackref >= *iter; ++iter )
{
++cbackref;
}
}
template< typename IterT >
class match_backref : public sub_expr<IterT>
{
bool _do_iterative_rematch_this( match_param<IterT> & param ) const
{
typedef typename std::iterator_traits<IterT>::difference_type diff_type;
backref_tag<IterT> const & br = param.m_prgbackrefs[ m_nbackref ];
diff_type dist = std::distance( br.first, br.second );
std::advance( param.m_icur, -dist );
return false;
}
public:
match_backref( size_t nbackref )
: m_nbackref( nbackref )
{
}
// Return the width specifications of the group to which this backref refers
virtual width_type width_this( width_param<IterT> & param )
{
// fix up the backref to take into account the number of invisible groups
fixup_backref( m_nbackref, param.m_invisible_groups );
if( m_nbackref >= param.m_rggroups.size() )
throw bad_regexpr( "reference to nonexistent group" );
// If the entry in the backref vector has been nulled out, then we are
// calculating the width for this group.
if( 0 == param.m_rggroups[ m_nbackref ] )
return worst_width; // can't tell how wide this group will be. :-(
return param.m_rggroups[ m_nbackref ]->width_this( param );
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
protected:
size_t m_nbackref;
};
template< typename CmpT, typename IterT >
class match_backref_t : public match_backref<IterT>
{
public:
match_backref_t( size_t nbackref )
: match_backref<IterT>( nbackref )
{
}
virtual sub_expr<IterT> * quantify( size_t lbound, size_t ubound, bool greedy, regex_arena & arena )
{
if( greedy )
return new( arena ) max_atom_quantifier<IterT, match_backref_t<CmpT, IterT> >( this, lbound, ubound );
else
return new( arena ) min_atom_quantifier<IterT, match_backref_t<CmpT, IterT> >( this, lbound, ubound );
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return ( match_backref_t::recursive_match_this_s( param, icur ) && this->recursive_match_next( param, icur, false_t() ) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return ( match_backref_t::recursive_match_this_c( param, icur ) && this->recursive_match_next( param, icur, true_t() ) );
}
virtual bool recursive_match_this_s( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_this_c( match_param<IterT> & param, IterT & icur ) const
{
return _do_match_this REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this REGEX_NVC6(<false_t>) ( param, param.m_icur REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
param.m_pnext = this->next();
return _do_match_this REGEX_NVC6(<true_t>) ( param, param.m_icur REGEX_VC6(COMMA true_t()) );
}
protected:
template< typename CStringsT >
bool _do_match_this( match_param<IterT> & param, IterT & icur REGEX_VC6(COMMA CStringsT) ) const
{
// Pattern compilation should have failed if the following is false:
REGEX_ASSERT( this->m_nbackref < param.m_cbackrefs );
// Don't match a backref that hasn't match anything
if( ! param.m_prgbackrefs[ this->m_nbackref ].matched )
return false;
IterT ithis = param.m_prgbackrefs[ this->m_nbackref ].first;
IterT const iend = param.m_prgbackrefs[ this->m_nbackref ].second;
IterT icur_tmp = icur;
for( ; iend != ithis; ++icur_tmp, ++ithis )
{
if( eos_t<CStringsT>::eval( param, icur_tmp ) || CmpT::eval( *icur_tmp, *ithis ) )
return false;
}
icur = icur_tmp;
return true;
}
};
template< typename IterT >
inline match_backref<IterT> * create_backref(
size_t cbackref,
REGEX_FLAGS flags, regex_arena & arena )
{
typedef typename std::iterator_traits<IterT>::value_type char_type;
switch( NOCASE & flags )
{
case 0:
return new( arena ) match_backref_t<ch_neq_t<char_type>, IterT>( cbackref );
case NOCASE:
return new( arena ) match_backref_t<ch_neq_nocase_t<char_type>, IterT>( cbackref );
default:
REGEX_ASSERT(false);
return 0;
}
}
template< typename IterT >
class match_recurse : public sub_expr<IterT>
{
match_recurse & operator=( match_recurse const & );
void _push_frame( match_param<IterT> & param ) const
{
typedef typename match_param<IterT>::backref_type backref_type;
unsafe_stack * pstack = param.m_pstack;
backref_type * ibegin = param.m_prgbackrefs;
backref_type * iend = ibegin + param.m_cbackrefs;
for( ; iend != ibegin; ++ibegin )
{
pstack->push( ibegin->reserved1 );
}
}
void _pop_frame( match_param<IterT> & param ) const
{
typedef typename match_param<IterT>::backref_type backref_type;
unsafe_stack * pstack = param.m_pstack;
backref_type * ibegin = param.m_prgbackrefs;
backref_type * iend = ibegin + param.m_cbackrefs;
while( iend != ibegin )
{
--iend;
pstack->pop( iend->reserved1 );
}
}
template< typename CStringsT >
bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
// Prevent infinite recursion. If icur == param.m_prgbackrefs[ 0 ].reserved1,
// then the pattern has eaten 0 chars to date, and we would recurse forever.
if( icur == param.m_prgbackrefs[ 0 ].reserved1 )
return this->recursive_match_next( param, icur, CStringsT() );
// copy the backref vector onto the stack
IterT * prgci = static_cast<IterT*>( alloca( param.m_cbackrefs * sizeof( IterT ) ) );
save_backrefs<IterT>( param.m_prgbackrefs, param.m_prgbackrefs + param.m_cbackrefs, prgci );
// Recurse.
if( param.m_pfirst->recursive_match_all( param, icur, CStringsT() ) )
{
// Restore the backref vector
restore_backrefs<IterT>( param.m_prgbackrefs, param.m_prgbackrefs + param.m_cbackrefs, prgci );
// Recursive match succeeded. Try to match the rest of the pattern
// using the end of the recursive match as the start of the next
return this->recursive_match_next( param, param.m_prgbackrefs[ 0 ].second, CStringsT() );
}
// Recursion failed
std::for_each( prgci, prgci + param.m_cbackrefs, deleter() );
return false;
}
template< typename CStringsT >
bool _do_iterative_match_this( match_param<IterT> & param REGEX_VC6(COMMA CStringsT) ) const
{
param.m_pstack->push( param.m_icur );
// Prevent infine recursion
if( param.m_icur == param.m_prgbackrefs[ 0 ].reserved1 )
{
param.m_pnext = this->next();
return true;
}
_push_frame( param );
if( _do_match_iterative( param.m_pfirst, param, param.m_icur, CStringsT() ) )
{
_pop_frame( param );
param.m_pnext = this->next();
return true;
}
_pop_frame( param );
param.m_pstack->pop( param.m_icur );
return false;
}
bool _do_iterative_rematch_this( match_param<IterT> & param ) const
{
param.m_pstack->pop( param.m_icur );
return false;
}
public:
match_recurse()
{
}
virtual sub_expr<IterT> * quantify( size_t, size_t, bool, regex_arena & )
{
throw bad_regexpr( "recursion sub-expression cannot be quantified" );
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
return _do_iterative_match_this REGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
return _do_iterative_match_this REGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this( param );
}
virtual width_type width_this( width_param<IterT> & )
{
return worst_width;
}
};
template< typename IterT >
inline match_recurse<IterT> * create_recurse( regex_arena & arena )
{
return new( arena ) match_recurse<IterT>();
}
template< typename IterT >
struct backref_condition
{
size_t m_cbackref;
backref_condition( size_t cbackref )
: m_cbackref( cbackref )
{
}
template< typename CStringsT >
bool recursive_match_this( match_param<IterT> & param, IterT, CStringsT ) const
{
return m_cbackref < param.m_cbackrefs && param.m_prgbackrefs[ m_cbackref ].matched;
}
template< typename CStringsT >
bool iterative_match_this( match_param<IterT> & param, CStringsT ) const
{
return m_cbackref < param.m_cbackrefs && param.m_prgbackrefs[ m_cbackref ].matched;
}
template< typename CStringsT >
bool iterative_rematch_this( match_param<IterT> &, CStringsT ) const
{
return false;
}
void width_this( width_param<IterT> & param )
{
// fix up the backref to take into account the number of invisible groups
fixup_backref( m_cbackref, param.m_invisible_groups );
}
};
template< typename IterT >
struct assertion_condition
{
std::auto_ptr<match_group_base<IterT> > m_passert;
assertion_condition( match_group_base<IterT> * passert , regex_arena & arena )
: m_passert( passert )
{
*passert->pnext() = new( arena ) end_of_pattern<IterT>;
}
bool recursive_match_this( match_param<IterT> & param, IterT icur, false_t ) const
{
return m_passert->recursive_match_all_s( param, icur );
}
bool recursive_match_this( match_param<IterT> & param, IterT icur, true_t ) const
{
return m_passert->recursive_match_all_c( param, icur );
}
bool iterative_match_this( match_param<IterT> & param, false_t ) const
{
return m_passert->iterative_match_this_s( param );
}
bool iterative_match_this( match_param<IterT> & param, true_t ) const
{
return m_passert->iterative_match_this_c( param );
}
bool iterative_rematch_this( match_param<IterT> & param, false_t ) const
{
return m_passert->iterative_rematch_this_s( param );
}
bool iterative_rematch_this( match_param<IterT> & param, true_t ) const
{
return m_passert->iterative_rematch_this_c( param );
}
void width_this( width_param<IterT> & param )
{
( void ) m_passert->width_this( param );
}
};
template< typename IterT, typename CondT >
class match_conditional : public match_group<IterT>
{
protected:
typedef typename match_group<IterT>::alt_list_type alt_list_type;
private:
match_conditional & operator=( match_conditional const & );
template< typename CStringsT >
bool _do_recursive_match_all( match_param<IterT> & param, IterT icur REGEX_VC6(COMMA CStringsT) ) const
{
typedef typename alt_list_type::const_iterator iter_type;
iter_type ialt = this->m_rgalternates.begin();
if( m_condition.recursive_match_this( param, icur, CStringsT() ) || this->m_rgalternates.end() != ++ialt )
{
return (*ialt)->recursive_match_all( param, icur, CStringsT() );
}
return this->recursive_match_next( param, icur, CStringsT() );
}
template< typename CStringsT >
bool _do_iterative_match_this( match_param<IterT> & param REGEX_VC6(COMMA CStringsT) ) const
{
typedef typename alt_list_type::const_iterator iter_type;
iter_type ialt = this->m_rgalternates.begin();
if( m_condition.iterative_match_this( param, CStringsT() ) )
{
param.m_pstack->push( true );
param.m_pnext = *ialt;
return true;
}
param.m_pstack->push( false );
param.m_pnext = ( this->m_rgalternates.end() != ++ialt ) ? *ialt : this->next();
return true;
}
template< typename CStringsT >
bool _do_iterative_rematch_this( match_param<IterT> & param REGEX_VC6(COMMA CStringsT) ) const
{
bool condition;
param.m_pstack->pop( condition );
if( condition )
m_condition.iterative_rematch_this( param, CStringsT() );
return false;
}
public:
typedef CondT condition_type;
match_conditional( size_t cgroup, condition_type condition, regex_arena & arena )
: match_group<IterT>( cgroup, arena )
, m_condition( condition )
{
}
virtual bool recursive_match_all_s( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<false_t>) ( param, icur REGEX_VC6(COMMA false_t()) );
}
virtual bool recursive_match_all_c( match_param<IterT> & param, IterT icur ) const
{
return _do_recursive_match_all REGEX_NVC6(<true_t>) ( param, icur REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_match_this_s( match_param<IterT> & param ) const
{
return _do_iterative_match_this REGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_match_this_c( match_param<IterT> & param ) const
{
return _do_iterative_match_this REGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );
}
virtual bool iterative_rematch_this_s( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this REGEX_NVC6(<false_t>) ( param REGEX_VC6(COMMA false_t()) );
}
virtual bool iterative_rematch_this_c( match_param<IterT> & param ) const
{
return _do_iterative_rematch_this REGEX_NVC6(<true_t>) ( param REGEX_VC6(COMMA true_t()) );
}
virtual width_type width_this( width_param<IterT> & param )
{
typedef typename alt_list_type::const_iterator iter_type;
iter_type ialt = this->m_rgalternates.begin();
width_type width = ( *ialt )->get_width( param );
if( this->m_rgalternates.end() != ++ialt )
{
width_type temp_width = ( *ialt )->get_width( param );
width.m_min = regex_min( width.m_min, temp_width.m_min );
width.m_max = regex_max( width.m_max, temp_width.m_max );
}
else
{
width.m_min = 0;
}
// Have the condition calculate its width, too. This is important
// if the condition is a lookbehind assertion.
m_condition.width_this( param );
return this->m_nwidth = width;
}
protected:
condition_type m_condition;
};
template< typename IterT >
inline match_conditional<IterT, backref_condition<IterT> > * create_backref_conditional(
size_t cgroup,
size_t cbackref,
regex_arena & arena )
{
backref_condition<IterT> cond( cbackref );
return new( arena ) match_conditional<IterT, backref_condition<IterT> >(
cgroup, cond, arena );
}
template< typename IterT >
inline match_conditional<IterT, assertion_condition<IterT> > * create_assertion_conditional(
size_t cgroup,
match_group_base<IterT> * passert,
regex_arena & arena )
{
assertion_condition<IterT> cond( passert, arena );
return new( arena ) match_conditional<IterT, assertion_condition<IterT> >(
cgroup, cond, arena );
}
//
// From basic_rpattern_base_impl
//
template< typename IterT >
REGEXPR_H_INLINE bool basic_rpattern_base_impl<IterT>::_ok_to_recurse() const //throw()
{
switch( m_mode )
{
case MODE_FAST:
return true;
case MODE_SAFE:
return false;
case MODE_MIXED:
return m_fok_to_recurse;
default:
return false;
}
}
template< typename IterT >
REGEXPR_H_INLINE void basic_rpattern_base_impl<IterT>::swap( basic_rpattern_base_impl<IterT> & that ) // throw()
{
using std::swap;
swap( m_fuses_backrefs, that.m_fuses_backrefs );
swap( m_floop, that.m_floop );
swap( m_fok_to_recurse, that.m_fok_to_recurse );
swap( m_cgroups, that.m_cgroups );
swap( m_cgroups_visible, that.m_cgroups_visible );
swap( m_flags, that.m_flags );
swap( m_mode, that.m_mode );
swap( m_nwidth, that.m_nwidth );
swap( m_pfirst, that.m_pfirst );
swap( m_search, that.m_search );
swap_auto_ptr( m_pat, that.m_pat );
swap_auto_ptr( m_subst, that.m_subst );
m_subst_list.swap( that.m_subst_list );
m_invisible_groups.swap( that.m_invisible_groups );
m_arena.swap( that.m_arena );
}
// A helper class for automatically deallocating the arena when
// parsing the pattern results in an exception
class arena_guard
{
arena_guard( arena_guard const & );
arena_guard & operator=( arena_guard const & );
regex_arena * m_parena;
public:
explicit arena_guard( regex_arena & arena )
: m_parena( &arena )
{
}
~arena_guard()
{
if( m_parena )
m_parena->clear();
}
void dismiss()
{
m_parena = 0;
}
};
template< typename CatT >
struct is_random_access_helper
{
enum { value = false };
};
template<>
struct is_random_access_helper<std::random_access_iterator_tag>
{
enum { value = true };
};
template< typename IterT >
struct is_random_access
{
typedef typename std::iterator_traits<IterT>::iterator_category cat_type;
enum { value = is_random_access_helper<cat_type>::value };
};
} // namespace detail
//
// Implementation of basic_rpattern_base:
//
template< typename IterT, typename SyntaxT >
REGEXPR_H_INLINE void basic_rpattern_base<IterT, SyntaxT>::init( string_type const & pat, REGEX_FLAGS flags, REGEX_MODE mode )
{
basic_rpattern_base<IterT, SyntaxT> temp( pat, flags, mode );
swap( temp );
}
template< typename IterT, typename SyntaxT >
REGEXPR_H_INLINE void basic_rpattern_base<IterT, SyntaxT>::init( string_type const & pat, string_type const & subst, REGEX_FLAGS flags, REGEX_MODE mode )
{
basic_rpattern_base<IterT, SyntaxT> temp( pat, subst, flags, mode );
swap( temp );
}
template< typename IterT, typename SyntaxT >
REGEXPR_H_INLINE void basic_rpattern_base<IterT, SyntaxT>::_common_init( REGEX_FLAGS flags )
{
this->m_cgroups = 0;
std::vector<detail::match_group_base<IterT>*> rggroups;
typename string_type::iterator ipat = this->m_pat->begin();
syntax_type sy( flags );
detail::match_group_base<IterT> * pgroup;
// Set up a sentry that will free the arena memory
// automatically on parse failure.
{
detail::arena_guard guard( this->m_arena );
// This will throw on failure
pgroup = _find_next_group( ipat, 0, sy, rggroups );
// terminate the pattern with the end_of_pattern marker
*pgroup->pnext() = new( this->m_arena ) detail::end_of_pattern<IterT>;
// The parse was successful. Dismiss the parse sentry
guard.dismiss();
}
REGEX_ASSERT( 0 == m_pfirst );
m_pfirst = pgroup;
// Calculate the width of the pattern and all groups
this->m_nwidth = pgroup->group_width( rggroups, m_invisible_groups );
//
// determine if we can get away with only calling m_pfirst->recursive_match_all only once
//
this->m_floop = true;
// Optimization: if first character of pattern string is '^'
// and we are not doing a multiline match, then we only
// need to try recursive_match_all once
typename string_type::iterator icur = this->m_pat->begin();
if( MULTILINE != ( MULTILINE & this->m_flags ) &&
1 == pgroup->calternates() &&
this->m_pat->end() != icur &&
BEGIN_LINE == sy.reg_token( icur, this->m_pat->end() ) )
{
this->m_flags = ( REGEX_FLAGS ) ( m_flags & ~RIGHTMOST );
this->m_floop = false;
}
// Optimization: if first 2 characters of pattern string are ".*" or ".+",
// then we only need to try recursive_match_all once
icur = this->m_pat->begin();
if( RIGHTMOST != ( RIGHTMOST & this->m_flags ) &&
SINGLELINE == ( SINGLELINE & this->m_flags ) &&
1 == pgroup->calternates() &&
this->m_pat->end() != icur &&
MATCH_ANY == sy.reg_token( icur, this->m_pat->end() ) &&
this->m_pat->end() != icur )
{
switch( sy.quant_token( icur, this->m_pat->end() ) )
{
case ONE_OR_MORE:
case ZERO_OR_MORE:
case ONE_OR_MORE_MIN:
case ZERO_OR_MORE_MIN:
this->m_floop = false;
break;
default:
break;
}
}
}
template< typename IterT, typename SyntaxT >
REGEXPR_H_INLINE void basic_rpattern_base<IterT, SyntaxT>::set_substitution( string_type const & subst )
{
using std::swap;
std::auto_ptr<string_type> temp_subst( new string_type( subst ) );
detail::subst_list_type temp_subst_list;
bool uses_backrefs = false;
_normalize_string( *temp_subst );
basic_rpattern_base<IterT, SyntaxT>::_parse_subst( *temp_subst, uses_backrefs, temp_subst_list );
detail::swap_auto_ptr( temp_subst, this->m_subst );
swap( uses_backrefs, this->m_fuses_backrefs );
temp_subst_list.swap( this->m_subst_list );
}
template< typename IterT, typename SyntaxT >
inline detail::match_group_base<IterT> * basic_rpattern_base<IterT, SyntaxT>::_find_next_group(
typename string_type::iterator & ipat,
detail::match_group_base<IterT> * pgroup_enclosing, syntax_type & sy,
std::vector<detail::match_group_base<IterT>*> & rggroups )
{
std::auto_ptr<detail::match_group_base<IterT> > pgroup;
typename string_type::iterator itemp = ipat;
REGEX_FLAGS old_flags = sy.get_flags();
TOKEN tok = NO_TOKEN;
size_t extent_start = this->m_cgroups;
bool fconditional = false;
// Look for group extensions.
if( this->m_pat->end() != ipat && NO_TOKEN != ( tok = sy.ext_token( ipat, this->m_pat->end() ) ) )
{
if( this->m_pat->begin() == itemp || this->m_pat->end() == ipat )
throw bad_regexpr( "ill-formed regular expression" );
// Is this a recursion element?
if( EXT_RECURSE == tok )
{
pgroup_enclosing->add_item( detail::create_recurse<IterT>( this->m_arena ) );
// This pattern could recurse deeply. Note that fact here so that
// we can opt to use a stack-conservative algorithm at match time.
this->m_fok_to_recurse = false;
}
// Don't process empty groups like (?:) or (?i) or (?R)
if( END_GROUP != sy.reg_token( itemp = ipat, this->m_pat->end() ) )
{
switch( tok )
{
case EXT_NOBACKREF:
// note that this group is not visible, so we can fix
// up offsets into the backref vector later
m_invisible_groups.push_back( this->m_cgroups );
detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::match_group<IterT>( _get_next_group_nbr(), this->m_arena ) );
break;
case EXT_INDEPENDENT:
m_invisible_groups.push_back( this->m_cgroups );
detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::independent_group<IterT>( _get_next_group_nbr(), this->m_arena ) );
break;
case EXT_POS_LOOKAHEAD:
detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::lookahead_assertion<IterT>( true, this->m_arena ) );
break;
case EXT_NEG_LOOKAHEAD:
detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::lookahead_assertion<IterT>( false, this->m_arena ) );
break;
case EXT_POS_LOOKBEHIND:
detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::lookbehind_assertion<IterT>( true, this->m_arena ) );
break;
case EXT_NEG_LOOKBEHIND:
detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::lookbehind_assertion<IterT>( false, this->m_arena ) );
break;
case EXT_CONDITION:
fconditional = true;
m_invisible_groups.push_back( this->m_cgroups );
if( size_t cbackref = detail::parse_int( ipat, this->m_pat->end() ) &&
END_GROUP == sy.reg_token( ipat, this->m_pat->end() ) )
{
detail::reset_auto_ptr(
pgroup, detail::create_backref_conditional<IterT>(
_get_next_group_nbr(), cbackref, this->m_arena ) );
}
else
{
switch( sy.ext_token( itemp = ipat, this->m_pat->end() ) )
{
case EXT_POS_LOOKAHEAD:
case EXT_NEG_LOOKAHEAD:
case EXT_POS_LOOKBEHIND:
case EXT_NEG_LOOKBEHIND:
{
std::auto_ptr<detail::match_group_base<IterT> > pgroup_tmp(
_find_next_group( ipat, 0, sy, rggroups ) );
detail::reset_auto_ptr(
pgroup, detail::create_assertion_conditional<IterT>(
_get_next_group_nbr(), pgroup_tmp.get(), this->m_arena ) );
pgroup_tmp.release();
}
break;
default:
throw bad_regexpr( "bad extension sequence" );
}
}
break;
case EXT_COMMENT:
while( END_GROUP != ( tok = sy.reg_token( ipat, this->m_pat->end() ) ) )
{
if( NO_TOKEN == tok && this->m_pat->end() != ipat )
++ipat;
if( this->m_pat->end() == ipat )
throw bad_regexpr( "Expecting end of comment" );
}
break;
default:
throw bad_regexpr( "bad extension sequence" );
}
}
else
{
// Skip over the END_GROUP token
ipat = itemp;
}
}
else
{
detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::match_group<IterT>( _get_next_group_nbr(), this->m_arena ) );
++this->m_cgroups_visible;
}
if( 0 != pgroup.get() )
{
detail::must_have<char_type> must;
pgroup->open_group();
while( _find_next( ipat, pgroup.get(), sy, rggroups ) ) {}
must = pgroup->close_group( this->m_arena );
// if this is a conditional group, then there must be at
// most 2 alternates.
if( fconditional && 2 < pgroup->calternates() )
throw bad_regexpr( "Too many alternates in conditional subexpression" );
// if this is the top-level group and it returned a "must have"
// string, then use that to initialize a boyer-moore search structure
if( detail::is_random_access<IterT>::value && must.m_has && 0 == pgroup->group_number() )
{
typedef typename string_type::const_iterator iter_type;
m_search = new( this->m_arena ) detail::boyer_moore<iter_type>
( must.m_begin, must.m_end, must.m_lower );
}
// Add this group to the rggroups array
if( size_t( -1 ) != pgroup->group_number() )
{
if( pgroup->group_number() >= rggroups.size() )
rggroups.resize( pgroup->group_number() + 1, 0 );
rggroups[ pgroup->group_number() ] = pgroup.get();
}
// tell this group how many groups are contained within it
pgroup->set_extent( detail::extent_type( extent_start, this->m_cgroups - extent_start ) );
// If this is not a pattern modifier, restore the
// flags to their previous settings. This causes
// pattern modifiers to have the scope of their
// enclosing group.
sy.set_flags( old_flags );
}
return pgroup.release();
}
namespace detail
{
// If we reached the end of the string before finding the end of the
// character set, then this is an ill-formed regex
template< typename IterT >
inline void check_iter( IterT icur, IterT iend )
{
if( iend == icur )
throw bad_regexpr( "expecting end of character set" );
}
template< typename IBeginT, typename IEndT >
inline typename std::iterator_traits<IEndT>::value_type get_escaped_char( IBeginT & icur, IEndT iend, bool normalize )
{
typedef typename std::iterator_traits<IEndT>::value_type char_type;
char_type ch = 0, i;
check_iter<IEndT>( icur, iend );
switch( *icur )
{
// octal escape sequence
case REGEX_CHAR(char_type,'0'): case REGEX_CHAR(char_type,'1'): case REGEX_CHAR(char_type,'2'): case REGEX_CHAR(char_type,'3'):
case REGEX_CHAR(char_type,'4'): case REGEX_CHAR(char_type,'5'): case REGEX_CHAR(char_type,'6'): case REGEX_CHAR(char_type,'7'):
ch = char_type( *icur++ - REGEX_CHAR(char_type,'0') );
for( i=0; i<2 && REGEX_CHAR(char_type,'0') <= *icur && REGEX_CHAR(char_type,'7') >= *icur; check_iter<IEndT>( ++icur, iend ) )
ch = char_type( ch * 8 + ( *icur - REGEX_CHAR(char_type,'0') ) );
break;
// bell character
case REGEX_CHAR(char_type,'a'):
if( ! normalize )
goto default_;
ch = REGEX_CHAR(char_type,'/a');
++icur;
break;
// control character
case REGEX_CHAR(char_type,'c'):
check_iter<IEndT>( ++icur, iend );
ch = *icur++;
if( REGEX_CHAR(char_type,'a') <= ch && REGEX_CHAR(char_type,'z') >= ch )
ch = detail::regex_toupper( ch );
ch ^= 0x40;
break;
// escape character
case REGEX_CHAR(char_type,'e'):
ch = 27;
++icur;
break;
// formfeed character
case REGEX_CHAR(char_type,'f'):
if( ! normalize )
goto default_;
ch = REGEX_CHAR(char_type,'/f');
++icur;
break;
// newline
case REGEX_CHAR(char_type,'n'):
if( ! normalize )
goto default_;
ch = REGEX_CHAR(char_type,'/n');
++icur;
break;
// return
case REGEX_CHAR(char_type,'r'):
if( ! normalize )
goto default_;
ch = REGEX_CHAR(char_type,'/r');
++icur;
break;
// horizontal tab
case REGEX_CHAR(char_type,'t'):
if( ! normalize )
goto default_;
ch = REGEX_CHAR(char_type,'/t');
++icur;
break;
// vertical tab
case REGEX_CHAR(char_type,'v'):
if( ! normalize )
goto default_;
ch = REGEX_CHAR(char_type,'/v');
++icur;
break;
// hex escape sequence
case REGEX_CHAR(char_type,'x'):
for( ++icur, ch=i=0; i<2 && detail::regex_isxdigit( *icur ); check_iter<IEndT>( ++icur, iend ) )
ch = char_type( ch * 16 + detail::regex_xdigit2int( *icur ) );
break;
// backslash
case REGEX_CHAR(char_type,'//'):
if( ! normalize )
goto default_;
ch = REGEX_CHAR(char_type,'//');
++icur;
break;
// all other escaped characters represent themselves
default: default_:
ch = *icur;
++icur;
break;
}
return ch;
}
template< typename CharT, typename CharSetT, typename SyntaxT >
inline void parse_charset(
std::auto_ptr<CharSetT> & pnew,
typename std::basic_string<CharT>::iterator & icur,
typename std::basic_string<CharT>::const_iterator iend,
SyntaxT & sy )
{
typedef CharT char_type;
typedef std::basic_string<CharT> string_type;
typedef typename string_type::const_iterator iter_type;
typename string_type::iterator itemp = icur;
bool const normalize = ( NORMALIZE == ( NORMALIZE & sy.get_flags() ) );
if( iend != itemp && CHARSET_NEGATE == sy.charset_token( itemp, iend ) )
{
pnew->m_fcompliment = true;
icur = itemp;
}
TOKEN tok;
char_type ch_prev = 0;
bool fhave_prev = false;
charset const * pcharset = 0;
typename string_type::iterator iprev = icur;
bool const fnocase = ( NOCASE == ( NOCASE & sy.get_flags() ) );
check_iter<iter_type>( icur, iend );
// remember the current position and grab the next token
tok = sy.charset_token( icur, iend );
do
{
check_iter<iter_type>( icur, iend );
if( CHARSET_RANGE == tok && fhave_prev )
{
// remember the current position
typename string_type::iterator iprev2 = icur;
fhave_prev = false;
// ch_prev is lower bound of a range
switch( sy.charset_token( icur, iend ) )
{
case CHARSET_RANGE:
case CHARSET_NEGATE:
icur = iprev2; // un-get these tokens and fall through
case NO_TOKEN:
pnew->set_bit_range( ch_prev, *icur++, fnocase );
continue;
case CHARSET_ESCAPE: // BUGBUG user-defined charset?
pnew->set_bit_range( ch_prev, get_escaped_char( icur, iend, normalize ), fnocase );
continue;
case CHARSET_BACKSPACE:
pnew->set_bit_range( ch_prev, char_type( 8 ), fnocase ); // backspace
continue;
case CHARSET_END: // fall through
default: // not a range.
icur = iprev; // backup to range token
pnew->set_bit( ch_prev, fnocase );
pnew->set_bit( *icur++, fnocase );
continue;
}
}
if( fhave_prev )
pnew->set_bit( ch_prev, fnocase );
fhave_prev = false;
switch( tok )
{
// None of the intrinsic charsets are case-sensitive,
// so no special handling must be done when the NOCASE
// flag is set.
case CHARSET_RANGE:
case CHARSET_NEGATE:
case CHARSET_END:
icur = iprev; // un-get these tokens
ch_prev = *icur++;
fhave_prev = true;
continue;
case CHARSET_BACKSPACE:
ch_prev = char_type( 8 ); // backspace
fhave_prev = true;
continue;
case ESC_DIGIT:
*pnew |= intrinsic_charsets<char_type>::get_digit_charset();
continue;
case ESC_NOT_DIGIT:
*pnew |= intrinsic_charsets<char_type>::get_not_digit_charset();
continue;
case ESC_SPACE:
*pnew |= intrinsic_charsets<char_type>::get_space_charset();
continue;
case ESC_NOT_SPACE:
*pnew |= intrinsic_charsets<char_type>::get_not_space_charset();
continue;
case ESC_WORD:
*pnew |= intrinsic_charsets<char_type>::get_word_charset();
continue;
case ESC_NOT_WORD:
*pnew |= intrinsic_charsets<char_type>::get_not_word_charset();
continue;
case CHARSET_ALNUM:
pnew->m_posixcharson |= ( wct_alnum() );
continue;
case CHARSET_NOT_ALNUM:
pnew->m_posixcharsoff.push_front( wct_alnum() );
continue;
case CHARSET_ALPHA:
pnew->m_posixcharson |= ( wct_alpha() );
continue;
case CHARSET_NOT_ALPHA:
pnew->m_posixcharsoff.push_front( wct_alpha() );
continue;
case CHARSET_BLANK:
pnew->m_posixcharson |= ( wct_blank() );
continue;
case CHARSET_NOT_BLANK:
pnew->m_posixcharsoff.push_front( wct_blank() );
continue;
case CHARSET_CNTRL:
pnew->m_posixcharson |= ( wct_cntrl() );
continue;
case CHARSET_NOT_CNTRL:
pnew->m_posixcharsoff.push_front( wct_cntrl() );
continue;
case CHARSET_DIGIT:
pnew->m_posixcharson |= ( wct_digit() );
continue;
case CHARSET_NOT_DIGIT:
pnew->m_posixcharsoff.push_front( wct_digit() );
continue;
case CHARSET_GRAPH:
pnew->m_posixcharson |= ( wct_graph() );
continue;
case CHARSET_NOT_GRAPH:
pnew->m_posixcharsoff.push_front( wct_graph() );
continue;
case CHARSET_LOWER:
if( NOCASE == ( NOCASE & sy.get_flags() ) )
pnew->m_posixcharson |= ( wct_lower()|wct_upper() );
else
pnew->m_posixcharson |= ( wct_lower() );
continue;
case CHARSET_NOT_LOWER:
if( NOCASE == ( NOCASE & sy.get_flags() ) )
pnew->m_posixcharsoff.push_front( wct_lower()|wct_upper() );
else
pnew->m_posixcharsoff.push_front( wct_lower() );
continue;
case CHARSET_PRINT:
pnew->m_posixcharson |= ( wct_print() );
continue;
case CHARSET_NOT_PRINT:
pnew->m_posixcharsoff.push_front( wct_print() );
continue;
case CHARSET_PUNCT:
pnew->m_posixcharson |= ( wct_punct() );
continue;
case CHARSET_NOT_PUNCT:
pnew->m_posixcharsoff.push_front( wct_punct() );
continue;
case CHARSET_SPACE:
pnew->m_posixcharson |= ( wct_space() );
continue;
case CHARSET_NOT_SPACE:
pnew->m_posixcharsoff.push_front( wct_space() );
continue;
case CHARSET_UPPER:
if( NOCASE == ( NOCASE & sy.get_flags() ) )
pnew->m_posixcharson |= ( wct_upper()|wct_lower() );
else
pnew->m_posixcharson |= ( wct_upper() );
continue;
case CHARSET_NOT_UPPER:
if( NOCASE == ( NOCASE & sy.get_flags() ) )
pnew->m_posixcharsoff.push_front( wct_upper()|wct_lower() );
else
pnew->m_posixcharsoff.push_front( wct_upper() );
continue;
case CHARSET_XDIGIT:
pnew->m_posixcharson |= ( wct_xdigit() );
continue;
case CHARSET_NOT_XDIGIT:
pnew->m_posixcharsoff.push_front( wct_xdigit() );
continue;
case CHARSET_ESCAPE:
// Maybe this is a user-defined intrinsic charset
pcharset = get_altern_charset( *icur, sy );
if( 0 != pcharset )
{
*pnew |= *pcharset;
++icur;
continue;
}
else
{
ch_prev = get_escaped_char( icur, iend, normalize );
fhave_prev = true;
}
continue;
default:
ch_prev = *icur++;
fhave_prev = true;
continue;
}
}
while( check_iter<iter_type>( iprev = icur, iend ),
CHARSET_END != ( tok = sy.charset_token( icur, iend ) ) );
if( fhave_prev )
pnew->set_bit( ch_prev, fnocase );
pnew->optimize( type2type<char_type>() );
}
template< typename CharT, typename SyntaxT >
inline charset const * get_altern_charset( CharT ch, SyntaxT & sy )
{
typedef std::basic_string<CharT> string_type;
charset const * pcharset = 0;
regex::detail::charset_map<CharT> & charset_map = sy.get_charset_map();
typename regex::detail::charset_map<CharT>::iterator iter = charset_map.find( ch );
if( charset_map.end() != iter )
{
bool const fnocase = ( NOCASE == ( sy.get_flags() & NOCASE ) );
pcharset = iter->second.m_rgcharsets[ fnocase ];
if( 0 == pcharset )
{
// tmp takes ownership of any ptrs.
charset_map_node<CharT> tmp = iter->second;
charset_map.erase( iter ); // prevent possible infinite recursion
typename string_type::iterator ibegin = tmp.m_str.begin();
std::auto_ptr<charset> pnew( new charset );
std::auto_ptr<charset const> pold( tmp.m_rgcharsets[ !fnocase ] );
parse_charset<CharT, charset>( pnew, ibegin, tmp.m_str.end(), sy );
tmp.m_rgcharsets[ fnocase ] = pcharset = pnew.get();
charset_map[ ch ] = tmp; // could throw
// charset_map has taken ownership of these pointers now.
pnew.release();
pold.release();
}
}
return pcharset;
}
} // namespace detail
//
// Read ahead through the pattern and treat sequential atoms
// as a single atom, making sure to handle quantification
// correctly. Warning: dense code ahead.
//
template< typename IterT, typename SyntaxT >
inline void basic_rpattern_base<IterT, SyntaxT>::_find_atom(
typename string_type::iterator & ipat,
detail::match_group_base<IterT> * pgroup,
syntax_type & sy )
{
typedef typename string_type::iterator iter_type;
typedef typename std::iterator_traits<iter_type>::difference_type diff_type;
iter_type itemp = ipat, ibegin;
diff_type const nstart = std::distance( this->m_pat->begin(), ipat );
do
{
if( itemp != ipat ) // Is there whitespace to skip?
{
diff_type dist = std::distance( this->m_pat->begin(), ipat );
this->m_pat->erase( ipat, itemp ); // erase the whitespace from the patttern
std::advance( ipat = this->m_pat->begin(), dist );
if( this->m_pat->end() == ( itemp = ipat ) ) // are we at the end of the pattern?
break;
}
switch( sy.quant_token( itemp, this->m_pat->end() ) )
{
// if {, } can't be interpreted as quantifiers, treat them as regular chars
case BEGIN_RANGE:
std::advance( ibegin = this->m_pat->begin(), nstart );
if( ibegin != ipat ) // treat as a quantifier
goto quantify;
case NO_TOKEN:
case END_RANGE:
case END_RANGE_MIN:
case RANGE_SEPARATOR:
break;
default:
std::advance( ibegin = this->m_pat->begin(), nstart );
if( ibegin == ipat ) // must be able to quantify something.
throw bad_regexpr( "quantifier not expected" );
quantify: if( ibegin != --ipat )
pgroup->add_item( detail::create_literal<IterT>( ibegin, ipat, sy.get_flags(), this->m_arena ) );
std::auto_ptr<detail::sub_expr<IterT> > pnew( detail::create_char<IterT>( *ipat++, sy.get_flags(), this->m_arena ) );
_quantify( pnew, ipat, false, sy );
pgroup->add_item( pnew.release() );
return;
}
} while( this->m_pat->end() != ++ipat && ! sy.reg_token( itemp = ipat, this->m_pat->end() ) );
std::advance( ibegin = this->m_pat->begin(), nstart );
REGEX_ASSERT( ipat != ibegin );
pgroup->add_item( detail::create_literal<IterT>( ibegin, ipat, sy.get_flags(), this->m_arena ) );
}
template< typename IterT, typename SyntaxT >
inline bool basic_rpattern_base<IterT, SyntaxT>::_find_next(
typename string_type::iterator & ipat,
detail::match_group_base<IterT> * pgroup,
syntax_type & sy,
std::vector<detail::match_group_base<IterT>*> & rggroups )
{
std::auto_ptr<detail::sub_expr<IterT> > pnew;
std::auto_ptr<detail::custom_charset> pcs;
typename string_type::iterator ibegin, itemp;
bool fdone, is_group = false;
bool const normalize = ( NORMALIZE == ( NORMALIZE & sy.get_flags() ) );
if( this->m_pat->end() == ipat )
{
if( 0 != pgroup->group_number() )
throw bad_regexpr( "mismatched parenthesis" );
return false;
}
switch( sy.reg_token( ipat, this->m_pat->end() ) )
{
case NO_TOKEN: // not a token. Must be an atom
if( this->m_pat->end() == ipat )
{
if( 0 != pgroup->group_number() )
throw bad_regexpr( "mismatched parenthesis" );
return false;
}
_find_atom( ipat, pgroup, sy );
return true;
case END_GROUP:
if( 0 == pgroup->group_number() )
throw bad_regexpr( "mismatched parenthesis" );
return false;
case ALTERNATION:
pgroup->end_alternate();
pgroup->add_alternate();
return true;
case BEGIN_GROUP:
// Find next group. could return NULL if the group is really
// a pattern modifier, like: ( ?s-i )
detail::reset_auto_ptr( pnew, _find_next_group( ipat, pgroup, sy, rggroups ) );
is_group = true;
break;
case BEGIN_LINE:
detail::reset_auto_ptr( pnew, detail::create_bol<IterT>( sy.get_flags(), this->m_arena ) );
break;
case END_LINE:
detail::reset_auto_ptr( pnew, detail::create_eol<IterT>( sy.get_flags(), this->m_arena ) );
break;
case BEGIN_CHARSET:
detail::reset_auto_ptr( pcs, new( this->m_arena ) detail::custom_charset( this->m_arena ) );
detail::parse_charset<char_type, detail::custom_charset>(
pcs, ipat, this->m_pat->end(), sy );
detail::reset_auto_ptr( pnew,
detail::create_custom_charset<IterT>( pcs.get(), sy.get_flags(), this->m_arena ) );
pcs.release();
break;
case MATCH_ANY:
detail::reset_auto_ptr( pnew, detail::create_any<IterT>( sy.get_flags(), this->m_arena ) );
break;
case ESC_WORD_BOUNDARY:
detail::reset_auto_ptr( pnew, detail::create_word_boundary<IterT>( true, sy.get_flags(), this->m_arena ) );
break;
case ESC_NOT_WORD_BOUNDARY:
detail::reset_auto_ptr( pnew, detail::create_word_boundary<IterT>( false, sy.get_flags(), this->m_arena ) );
break;
case ESC_WORD_START:
detail::reset_auto_ptr( pnew, detail::create_word_start<IterT>( sy.get_flags(), this->m_arena ) );
break;
case ESC_WORD_STOP:
detail::reset_auto_ptr( pnew, detail::create_word_stop<IterT>( sy.get_flags(), this->m_arena ) );
break;
case ESC_DIGIT:
detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( detail::intrinsic_charsets<char_type>::get_digit_charset(), sy.get_flags(), this->m_arena ) );
break;
case ESC_NOT_DIGIT:
detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( detail::intrinsic_charsets<char_type>::get_not_digit_charset(), sy.get_flags(), this->m_arena ) );
break;
case ESC_WORD:
detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( detail::intrinsic_charsets<char_type>::get_word_charset(), sy.get_flags(), this->m_arena ) );
break;
case ESC_NOT_WORD:
detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( detail::intrinsic_charsets<char_type>::get_not_word_charset(), sy.get_flags(), this->m_arena ) );
break;
case ESC_SPACE:
detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( detail::intrinsic_charsets<char_type>::get_space_charset(), sy.get_flags(), this->m_arena ) );
break;
case ESC_NOT_SPACE:
detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( detail::intrinsic_charsets<char_type>::get_not_space_charset(), sy.get_flags(), this->m_arena ) );
break;
case ESC_BEGIN_STRING:
detail::reset_auto_ptr( pnew, detail::create_bos<IterT>( sy.get_flags(), this->m_arena ) );
break;
case ESC_END_STRING:
detail::reset_auto_ptr( pnew, detail::create_eos<IterT>( sy.get_flags(), this->m_arena ) );
break;
case ESC_END_STRING_z:
detail::reset_auto_ptr( pnew, detail::create_eoz<IterT>( sy.get_flags(), this->m_arena ) );
break;
case ESCAPE:
if( this->m_pat->end() == ipat )
{
// BUGBUG what if the escape sequence is more that 1 character?
detail::reset_auto_ptr( pnew, detail::create_char<IterT>( *--ipat, sy.get_flags(), this->m_arena ) );
++ipat;
}
else if( REGEX_CHAR(char_type,'0') <= *ipat && REGEX_CHAR(char_type,'9') >= *ipat )
{
// Parse at most 3 decimal digits.
size_t nbackref = detail::parse_int( itemp = ipat, this->m_pat->end(), 999 );
// If the resulting number could conceivably be a backref, then it is.
if( REGEX_CHAR(char_type,'0') != *ipat && ( 10 > nbackref || nbackref < _cgroups_total() ) )
{
detail::reset_auto_ptr( pnew, detail::create_backref<IterT>( nbackref, sy.get_flags(), this->m_arena ) );
ipat = itemp;
}
else
{
// It's an octal character escape sequence. If *ipat is 8 or 9, insert
// a NULL character, and leave the 8 or 9 as a character literal.
char_type ch = 0, i = 0;
for( ; i < 3 && this->m_pat->end() != ipat && REGEX_CHAR(char_type,'0') <= *ipat && REGEX_CHAR(char_type,'7') >= *ipat; ++i, ++ipat )
ch = char_type( ch * 8 + ( *ipat - REGEX_CHAR(char_type,'0') ) );
detail::reset_auto_ptr( pnew, detail::create_char<IterT>( ch, sy.get_flags(), this->m_arena ) );
}
}
else if( REGEX_CHAR(char_type,'e') == *ipat )
{
++ipat;
detail::reset_auto_ptr( pnew, detail::create_char<IterT>( char_type( 27 ), sy.get_flags(), this->m_arena ) );
}
else if( REGEX_CHAR(char_type,'x') == *ipat )
{
char_type ch = 0, i = 0;
for( ++ipat; i < 2 && this->m_pat->end() != ipat && detail::regex_isxdigit( *ipat ); ++i, ++ipat )
ch = char_type( ch * 16 + detail::regex_xdigit2int( *ipat ) );
detail::reset_auto_ptr( pnew, detail::create_char<IterT>( ch, sy.get_flags(), this->m_arena ) );
}
else if( REGEX_CHAR(char_type,'c') == *ipat )
{
if( this->m_pat->end() == ++ipat )
throw bad_regexpr( "incomplete escape sequence //c" );
char_type ch = *ipat++;
if( REGEX_CHAR(char_type,'a') <= ch && REGEX_CHAR(char_type,'z') >= ch )
ch = detail::regex_toupper( ch );
detail::reset_auto_ptr( pnew, detail::create_char<IterT>( char_type( ch ^ 0x40 ), sy.get_flags(), this->m_arena ) );
}
else if( REGEX_CHAR(char_type,'a') == *ipat && normalize )
{
++ipat;
detail::reset_auto_ptr( pnew, detail::create_char<IterT>( REGEX_CHAR(char_type,'/a'), sy.get_flags(), this->m_arena ) );
}
else if( REGEX_CHAR(char_type,'f') == *ipat && normalize )
{
++ipat;
detail::reset_auto_ptr( pnew, detail::create_char<IterT>( REGEX_CHAR(char_type,'/f'), sy.get_flags(), this->m_arena ) );
}
else if( REGEX_CHAR(char_type,'n') == *ipat && normalize )
{
++ipat;
detail::reset_auto_ptr( pnew, detail::create_char<IterT>( REGEX_CHAR(char_type,'/n'), sy.get_flags(), this->m_arena ) );
}
else if( REGEX_CHAR(char_type,'r') == *ipat && normalize )
{
++ipat;
detail::reset_auto_ptr( pnew, detail::create_char<IterT>( REGEX_CHAR(char_type,'/r'), sy.get_flags(), this->m_arena ) );
}
else if( REGEX_CHAR(char_type,'t') == *ipat && normalize )
{
++ipat;
detail::reset_auto_ptr( pnew, detail::create_char<IterT>( REGEX_CHAR(char_type,'/t'), sy.get_flags(), this->m_arena ) );
}
else if( REGEX_CHAR(char_type,'//') == *ipat && normalize )
{
++ipat;
detail::reset_auto_ptr( pnew, detail::create_char<IterT>( REGEX_CHAR(char_type,'//'), sy.get_flags(), this->m_arena ) );
}
else
{
// Is this a user-defined intrinsic character set?
detail::charset const * pcharset = detail::get_altern_charset( *ipat, sy );
if( 0 != pcharset )
detail::reset_auto_ptr( pnew, detail::create_charset<IterT>( *pcharset, sy.get_flags(), this->m_arena ) );
else
detail::reset_auto_ptr( pnew, detail::create_char<IterT>( *ipat, sy.get_flags(), this->m_arena ) );
++ipat;
}
break;
// If quotemeta, loop until we find quotemeta off or end of string
case ESC_QUOTE_META_ON:
for( ibegin = itemp = ipat, fdone = false; !fdone && this->m_pat->end() != ipat; )
{
switch( sy.reg_token( ipat, this->m_pat->end() ) )
{
case ESC_QUOTE_META_OFF:
fdone = true;
break;
case NO_TOKEN:
if( this->m_pat->end() != ipat )
++ipat; // fallthrough
default:
itemp = ipat;
break;
}
}
if( itemp != ibegin )
pgroup->add_item( detail::create_literal<IterT>( ibegin, itemp, sy.get_flags(), this->m_arena ) );
// skip the quantification code below
return true;
// Should never get here for valid patterns
case ESC_QUOTE_META_OFF:
throw bad_regexpr( "quotemeta turned off, but was never turned on" );
default:
REGEX_ASSERT( ! "Unhandled token type" );
break;
}
// If pnew is null, then the current subexpression is a no-op.
if( pnew.get() )
{
// Look for quantifiers
_quantify( pnew, ipat, is_group, sy );
// Add the item to the group
pgroup->add_item( pnew.release() );
}
return true;
}
template< typename IterT, typename SyntaxT >
inline void basic_rpattern_base<IterT, SyntaxT>::_quantify(
std::auto_ptr<detail::sub_expr<IterT> > & pnew,
typename string_type::iterator & ipat,
bool is_group,
syntax_type & sy )
{
if( this->m_pat->end() != ipat && ! pnew->is_assertion() )
{
typename string_type::iterator itemp = ipat, itemp2;
bool fmin = false;
// Since size_t is unsigned, -1 is really the largest size_t
size_t lbound = ( size_t )-1;
size_t ubound = ( size_t )-1;
size_t ubound_tmp;
switch( sy.quant_token( itemp, this->m_pat->end() ) )
{
case ZERO_OR_MORE_MIN:
fmin = true;
case ZERO_OR_MORE:
lbound = 0;
break;
case ONE_OR_MORE_MIN:
fmin = true;
case ONE_OR_MORE:
lbound = 1;
break;
case ZERO_OR_ONE_MIN:
fmin = true;
case ZERO_OR_ONE:
lbound = 0;
ubound = 1;
break;
case BEGIN_RANGE:
lbound = detail::parse_int( itemp, this->m_pat->end() );
if( this->m_pat->end() == itemp )
return; // not a valid quantifier - treat as atom
switch( sy.quant_token( itemp, this->m_pat->end() ) )
{
case END_RANGE_MIN:
fmin = true;
case END_RANGE:
ubound = lbound;
break;
case RANGE_SEPARATOR:
itemp2 = itemp;
ubound_tmp = detail::parse_int( itemp, this->m_pat->end() );
if( itemp != itemp2 )
ubound = ubound_tmp;
if( itemp == this->m_pat->end() )
return; // not a valid quantifier - treat as atom
switch( sy.quant_token( itemp, this->m_pat->end() ) )
{
case END_RANGE_MIN:
fmin = true;
case END_RANGE:
break;
default:
return; // not a valid quantifier - treat as atom
}
break;
default:
return; // not a valid quantifier - treat as atom
}
if( ubound < lbound )
throw bad_regexpr( "Can't do {n, m} with n > m" );
break;
default:
break;
}
if( ( size_t )-1 != lbound )
{
// If we are quantifying a group, then this pattern could recurse
// deeply. Note that fact here so that we can opt to use a stack-
// conservative algorithm at match time.
if( is_group && ubound > 16 )
this->m_fok_to_recurse = false;
std::auto_ptr<detail::sub_expr<IterT> > pquant( pnew->quantify( lbound, ubound, ! fmin, this->m_arena ) );
pnew.release();
detail::reset_auto_ptr( pnew, pquant.release() );
ipat = itemp;
}
}
}
template< typename IterT, typename SyntaxT >
inline void basic_rpattern_base<IterT, SyntaxT>::_add_subst_backref(
detail::subst_node & snode,
size_t nbackref,
ptrdiff_t rstart,
bool & uses_backrefs,
detail::subst_list_type & subst_list ) const
{
uses_backrefs = true;
REGEX_ASSERT( detail::subst_node::SUBST_STRING == snode.m_stype );
if( snode.m_subst_string.m_rlength )
subst_list.push_back( snode );
snode.m_stype = detail::subst_node::SUBST_BACKREF;
snode.m_subst_backref = nbackref;
subst_list.push_back( snode );
// re-initialize the subst_node
snode.m_stype = detail::subst_node::SUBST_STRING;
snode.m_subst_string.m_rstart = rstart;
snode.m_subst_string.m_rlength = 0;
}
template< typename IterT, typename SyntaxT >
inline void basic_rpattern_base<IterT, SyntaxT>::_parse_subst(
string_type & subst,
bool & uses_backrefs,
detail::subst_list_type & subst_list ) const
{
TOKEN tok;
detail::subst_node snode;
typename string_type::iterator icur = subst.begin();
size_t nbackref;
typename string_type::iterator itemp;
bool fdone;
syntax_type sy( this->m_flags );
uses_backrefs = false;
// Initialize the subst_node
snode.m_stype = detail::subst_node::SUBST_STRING;
snode.m_subst_string.m_rstart = 0;
snode.m_subst_string.m_rlength = 0;
while( subst.end() != icur )
{
switch( tok = sy.subst_token( icur, subst.end() ) )
{
case SUBST_MATCH:
_add_subst_backref( snode, 0, std::distance( subst.begin(), icur ), uses_backrefs, subst_list );
break;
case SUBST_PREMATCH:
_add_subst_backref( snode, ( size_t )detail::subst_node::PREMATCH, std::distance( subst.begin(), icur ), uses_backrefs, subst_list );
break;
case SUBST_POSTMATCH:
_add_subst_backref( snode, ( size_t )detail::subst_node::POSTMATCH, std::distance( subst.begin(), icur ), uses_backrefs, subst_list );
break;
case SUBST_BACKREF:
nbackref = detail::parse_int( icur, subst.end(), cgroups() - 1 ); // always at least 1 group
if( 0 == nbackref )
throw bad_regexpr( "invalid backreference in substitution" );
_add_subst_backref( snode, nbackref, std::distance( subst.begin(), icur ), uses_backrefs, subst_list );
break;
case SUBST_QUOTE_META_ON:
REGEX_ASSERT( detail::subst_node::SUBST_STRING == snode.m_stype );
if( snode.m_subst_string.m_rlength )
subst_list.push_back( snode );
snode.m_subst_string.m_rstart = std::distance( subst.begin(), icur );
for( itemp = icur, fdone = false; !fdone && subst.end() != icur; )
{
switch( tok = sy.subst_token( icur, subst.end() ) )
{
case SUBST_ALL_OFF:
fdone = true;
break;
case NO_TOKEN:
++icur; // fall-through
default:
itemp = icur;
break;
}
}
snode.m_subst_string.m_rlength = std::distance( subst.begin(), itemp ) - snode.m_subst_string.m_rstart;
if( snode.m_subst_string.m_rlength )
subst_list.push_back( snode );
if( tok == SUBST_ALL_OFF )
{
snode.m_stype = detail::subst_node::SUBST_OP;
snode.m_op = detail::subst_node::ALL_OFF;
subst_list.push_back( snode );
}
// re-initialize the subst_node
snode.m_stype = detail::subst_node::SUBST_STRING;
snode.m_subst_string.m_rstart = std::distance( subst.begin(), icur );
snode.m_subst_string.m_rlength = 0;
break;
case SUBST_UPPER_ON:
case SUBST_UPPER_NEXT:
case SUBST_LOWER_ON:
case SUBST_LOWER_NEXT:
case SUBST_ALL_OFF:
REGEX_ASSERT( detail::subst_node::SUBST_STRING == snode.m_stype );
if( snode.m_subst_string.m_rlength )
subst_list.push_back( snode );
snode.m_stype = detail::subst_node::SUBST_OP;
snode.m_op = static_cast<detail::subst_node::op_type>( tok );
subst_list.push_back( snode );
// re-initialize the subst_node
snode.m_stype = detail::subst_node::SUBST_STRING;
snode.m_subst_string.m_rstart = std::distance( subst.begin(), icur );
snode.m_subst_string.m_rlength = 0;
break;
case SUBST_ESCAPE:
if( subst.end() == icur )
throw bad_regexpr( "expecting escape sequence in substitution string" );
REGEX_ASSERT( detail::subst_node::SUBST_STRING == snode.m_stype );
if( snode.m_subst_string.m_rlength )
subst_list.push_back( snode );
snode.m_subst_string.m_rstart = std::distance( subst.begin(), icur++ );
snode.m_subst_string.m_rlength = 1;
break;
case NO_TOKEN:
default:
++snode.m_subst_string.m_rlength;
++icur;
break;
}
}
REGEX_ASSERT( detail::subst_node::SUBST_STRING == snode.m_stype );
if( snode.m_subst_string.m_rlength )
subst_list.push_back( snode );
}
template< typename CharT >
REGEXPR_H_INLINE void reset_intrinsic_charsets( CharT )
{
detail::intrinsic_charsets<CharT>::reset();
}
typedef regex::detail::select
<
REGEX_FOLD_INSTANTIATIONS &&
detail::is_convertible<char const *,std::string::const_iterator>::value,
std::string::const_iterator,
char const *
>::type lpcstr_t;
typedef regex::detail::select
<
REGEX_FOLD_INSTANTIATIONS &&
detail::is_convertible<wchar_t const *,std::wstring::const_iterator>::value,
std::wstring::const_iterator,
wchar_t const *
>::type lpcwstr_t;
namespace detail
{
// Here is the main dispatch loop for the iterative match routine.
// It is responsible for calling match on the current sub-expression
// and repeating for the next sub-expression. It also backtracks
// the match when it needs to.
template< typename CStringsT, typename IterT >
inline bool _do_match_iterative( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur, CStringsT )
{
unsafe_stack::stack_guard guard( param.m_pstack );
unsafe_stack & s = *param.m_pstack;
void *const jump_ptr = s.set_jump(); // the bottom of the stack
param.m_icur = icur;
if( ! expr->iterative_match_this( param, CStringsT() ) )
{
return false;
}
for( ;; )
{
do
{
if( param.m_pnext == 0 ) // This means we're done
return true;
s.push( expr );
expr = param.m_pnext;
}
while( expr->iterative_match_this( param, CStringsT() ) );
do
{
if( jump_ptr == s.set_jump() ) // No more posibilities to try
return false;
s.pop( expr );
}
while( ! expr->iterative_rematch_this( param, CStringsT() ) );
}
}
template< typename IterT >
REGEXPR_H_INLINE bool regex_access<IterT>::_do_match_iterative_helper_s( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur )
{
return _do_match_iterative( expr, param, icur, false_t() );
}
template< typename IterT >
REGEXPR_H_INLINE bool regex_access<IterT>::_do_match_iterative_helper_c( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur )
{
return _do_match_iterative( expr, param, icur, true_t() );
}
template< typename IterT >
REGEXPR_H_INLINE bool regex_access<IterT>::_do_match_recursive_s( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur )
{
return static_cast<match_group_base<IterT> const*>(expr)->match_group_base<IterT>::recursive_match_all_s( param, icur );
}
template< typename IterT >
REGEXPR_H_INLINE bool regex_access<IterT>::_do_match_recursive_c( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur )
{
return static_cast<match_group_base<IterT> const*>(expr)->match_group_base<IterT>::recursive_match_all_c( param, icur );
}
template< typename IterT >
REGEX_NOINLINE bool regex_access<IterT>::_do_match_with_stack( rpattern_type const & pat, match_param<IterT> & param, bool const use_null )
{
unsafe_stack s;
param.m_pstack = &s;
return _do_match_impl( pat, param, use_null );
}
template< typename IterT >
REGEXPR_H_INLINE bool regex_access<IterT>::_do_match_impl( rpattern_type const & pat, match_param<IterT> & param, bool const use_null )
{
typedef bool ( *pfndomatch_t )( sub_expr_base<IterT> const * expr, match_param<IterT> & param, IterT icur );
bool floop = pat._loops();
unsigned flags = pat.flags();
width_type nwidth = pat.get_width();
// Create some aliases for convenience and effeciency.
REGEX_ASSERT( 0 != param.m_prgbackrefs );
// If the pstack parameter is not NULL, we should do a safe, iterative match.
// Otherwise, we should do a fast, recursive match.
pfndomatch_t pfndomatch;
if( 0 != param.m_pstack )
if( use_null )
pfndomatch = &_do_match_iterative_helper_c;
else
pfndomatch = &_do_match_iterative_helper_s;
else
if( use_null )
pfndomatch = &_do_match_recursive_c;
else
pfndomatch = &_do_match_recursive_s;
sub_expr_base<IterT> const * pfirst = pat._get_first_subexpression();
param.m_pfirst = pfirst;
REGEX_ASSERT( param.m_cbackrefs == pat._cgroups_total() );
std::fill_n( param.m_prgbackrefs, param.m_cbackrefs, static_init<backref_type>::value );
if( ! use_null )
{
// If the minimum width of the pattern exceeds the width of the
// string, a succesful match is impossible
typedef typename std::iterator_traits<IterT>::difference_type diff_type;
diff_type room = std::distance( param.m_imatchbegin, param.m_iend );
if( nwidth.m_min <= static_cast<size_t>( room ) )
{
IterT local_iend = param.m_iend;
std::advance( local_iend, -static_cast<diff_type>( nwidth.m_min ) );
if( RIGHTMOST & flags )
{
// begin trying to match after the last character.
// Continue to the beginning
for( IterT icur = local_iend; ; --icur, param.m_no0len = false )
{
if( ( *pfndomatch )( pfirst, param, icur ) )
break; // m_floop not used for rightmost matches
if( icur == param.m_imatchbegin )
break;
}
}
else
{
// begin trying to match before the first character.
// Continue to the end
if( is_random_access<IterT>::value && pat.m_search )
{
IterT icur = pat.m_search->find( param.m_imatchbegin, param.m_iend );
while( icur != param.m_iend )
{
if( ( *pfndomatch )( pfirst, param, icur ) || ! floop )
break;
param.m_no0len = false;
icur = pat.m_search->find( ++icur, param.m_iend );
}
}
else
{
for( IterT icur = param.m_imatchbegin; ; ++icur, param.m_no0len = false )
{
if( ( *pfndomatch )( pfirst, param, icur ) || ! floop )
break;
if( icur == local_iend )
break;
}
}
}
}
}
else
{
REGEX_ASSERT( 0 == ( RIGHTMOST & flags ) );
// begin trying to match before the first character.
// Continue to the end
for( IterT icur = param.m_imatchbegin; ; ++icur, param.m_no0len = false )
{
if( ( *pfndomatch )( pfirst, param, icur ) || ! floop )
break;
if( traits_type::eq( *icur, char_type() ) )
break;
}
}
return param.m_prgbackrefs[0].matched;
}
// Here is a rudimentary typelist facility to allow the REGEX_TO_INSTANTIATE
// list to recursively generate the instantiations we are interested in.
struct empty_typelist
{
};
template< typename HeadT, typename TailT >
struct cons
{
typedef HeadT head_type;
typedef TailT tail_type;
};
template
<
typename T1 =empty_typelist, typename T2 =empty_typelist, typename T3 =empty_typelist,
typename T4 =empty_typelist, typename T5 =empty_typelist, typename T6 =empty_typelist,
typename T7 =empty_typelist, typename T8 =empty_typelist, typename T9 =empty_typelist,
typename T10=empty_typelist, typename T11=empty_typelist, typename T12=empty_typelist
>
struct typelist : public cons<T1,typelist<T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12> >
{
};
template<>
struct typelist
<
empty_typelist,empty_typelist,empty_typelist,empty_typelist,
empty_typelist,empty_typelist,empty_typelist,empty_typelist,
empty_typelist,empty_typelist,empty_typelist,empty_typelist
>
: public empty_typelist
{
};
// This class is responsible for instantiating basic_rpattern
// with the template parameters we are interested in. It also
// instntiates any helper routines this basic_rpattern relies
// on.
template< typename IterT, typename SyntaxT >
struct rpattern_instantiator : protected regex::basic_rpattern<IterT,SyntaxT>
{
static instantiator instantiate()
{
typedef typename std::iterator_traits<IterT>::value_type char_type;
void (*pfn)( char_type ) = &reset_intrinsic_charsets;
return regex::basic_rpattern<IterT,SyntaxT>::instantiate() +
regex_access<IterT>::instantiate() +
instantiator_helper( pfn );
}
};
// The regex_instantiate uses typelists and the rpattern_instantiator
// to generate instantiations for all the types in the typelist.
template< typename SyntaxT >
instantiator regex_instantiate( empty_typelist, type2type<SyntaxT> )
{
return instantiator();
}
template< typename HeadT, typename TailT, typename SyntaxT >
instantiator regex_instantiate( cons<HeadT,TailT>, type2type<SyntaxT> )
{
typedef typename std::iterator_traits<HeadT>::value_type char_type;
typedef typename SyntaxT::template rebind<char_type>::other syntax_type;
return rpattern_instantiator<HeadT,syntax_type>::instantiate() +
regex_instantiate( TailT(), type2type<SyntaxT>() );
}
// Here is a list of types to instantiate.
#ifndef REGEX_TO_INSTANTIATE
# ifdef REGEX_WIDE_AND_NARROW
# define REGEX_TO_INSTANTIATE std::string::const_iterator, /
std::wstring::const_iterator, /
lpcstr_t, /
lpcwstr_t
# else
# define REGEX_TO_INSTANTIATE restring::const_iterator, /
lpctstr_t
# endif
#endif
typedef typelist<REGEX_TO_INSTANTIATE> regex_typelist;
typedef type2type<perl_syntax<char> > perl_type;
typedef type2type<posix_syntax<char> > posix_type;
namespace
{
// Create the perl instantiations
#ifndef REGEX_NO_PERL
instantiator const perl_inst = regex_instantiate( regex_typelist(), perl_type() );
#endif
// Create the posix instantiations
#ifdef REGEX_POSIX
instantiator const posix_inst = regex_instantiate( regex_typelist(), posix_type() );
#endif
}
} // unnamed namespace
} // namespace regex
#ifdef _MSC_VER
# pragma warning( pop )
#endif
*/
/*正则替换
#include <string>
#include <boost/regex.hpp>
using namespace std;
boost::regex reg("(Colo)(u)(r)",boost::regex::icase|boost::regex::perl);
string s="Color, colours,color,colourize";
s=boost::regex_replace(s,reg,"$1$3");
TRACE(CString(s));
*/
47.直接创建多级目录
typedef BOOL (__stdcall funMakeSure(LPCSTR DirPath));
funMakeSure *MakeSureDirectoryPathExists;
HMODULE hMod=LoadLibrary("dbghelp.dll");
MakeSureDirectoryPathExists(*funMakeSure)GetProcAddress(hMod,"MakeSureDirectoryPathExists");
MakeSureDirectoryPathExists(%%1);
48.批量重命名
CString strPath,strFilter,srcTitle,src,srcFile,dstFile,dstFileTitle;
int i=1,iFileNum=1;
CFile myFile,newFile;
//获取将要批量处理的文件夹及文件格式
strPath=%%1;
strFilter=%%2;
//判断文件夹是否为空
if(strPath.IsEmpty())
{
MessageBox("请先选择要重命名文件所在文件夹!","警告!");
return;
}
//在该文件夹内创建目录文件
src=strPath+"*."+strFilter;
CString list=strPath+"目录.txt";
if(myFile.Open(list,CFile::modeCreate|CFile::modeReadWrite,0) ==0) return;
CFileFind tempFind;
BOOL isFound=(BOOL)tempFind.FindFile(src);
//确定该文件夹内要处理的有多少个文件
while(isFound)
{
isFound=(BOOL)tempFind.FindNextFile();
if(tempFind.IsDirectory() && !tempFind.IsDots())
{
continue;
}
iFileNum++;
}
//进行文件名的转换,以文件数定转换后的文件名,如果有9个文件,则以1-9的形式命名,如果是更多,如有99个文件,则为01-99的形式
isFound=(BOOL)tempFind.FindFile(src);
while(isFound && i<iFileNum)
{
isFound=(BOOL)tempFind.FindNextFile();
if(tempFind.IsDirectory() && !tempFind.IsDots())
{
continue;
}
srcFile=tempFind.GetFilePath();
srcTitle=tempFind.GetFileTitle();
if(iFileNum<10)
{
dstFileTitle.Format("%d",i);
}
else if(iFileNum<100 && iFileNum>9)
{
dstFileTitle.Format("%02d",i);
}
else if(iFileNum<1000 && iFileNum>99)
{
dstFileTitle.Format("%03d",i);
}
else if(iFileNum<10000 && iFileNum>999)
{
dstFileTitle.Format("%04d",i);
}
else if(iFileNum<100000 && iFileNum>9999)
{
dstFileTitle.Format("%05d",i);
}
else
{
dstFileTitle.Format("%d",i);
}
//实现转换
dstFile=strPath+dstFileTitle+"."+strFilter;
MoveFile(srcFile,dstFile);
//存入目录文件中
CString in;
in=dstFileTitle+'/t'+srcTitle+"/t/r/n";
myFile.Write(in,in.GetLength());
i++;
SetWindowText(srcFile);
}
//关闭myFile,tempFind
myFile.Close();
tempFind.Close();
49.文本查找替换 ReplaceText
CString StrFileName(%%1);
CString StrFind(%%2);
CString StrReplace(%%3);
CStdioFile TempFile,File;
int Count=0;
if(!File.Open(StrFileName,CFile::modeRead))
return -1;
CString StrTempFileName=File.GetFileTitle()+".tmp";
if(!TempFile.Open(StrTempFileName,CFile::modeCreate|CFile::modeReadWrite))
return -1;
CString Str;
while(File.ReadString(Str))
{
Count+=Str.Replace(StrFind,StrReplace);
TempFile.WriteString(Str+"/n");
}
File.Close();
TempFile.Close();
CFile::Remove(StrFileName);
CFile::Rename(StrTempFileName,StrFileName);
//return Count;
50.文件关联
//---------------------------------------------------------------------------
// 检测文件关联情况
// strExt: 要检测的扩展名(例如: ".txt")
// strAppKey: ExeName扩展名在注册表中的键值(例如: "txtfile")
// 返回TRUE: 表示已关联,FALSE: 表示未关联
BOOL CheckFileRelation(const char *strExt, const char *strAppKey)
{
int nRet=FALSE;
HKEY hExtKey;
char szPath[_MAX_PATH];
DWORD dwSize=sizeof(szPath);
if(RegOpenKey(HKEY_CLASSES_ROOT,strExt,&hExtKey)==ERROR_SUCCESS)
{
RegQueryValueEx(hExtKey,NULL,NULL,NULL,(LPBYTE)szPath,&dwSize);
if(_stricmp(szPath,strAppKey)==0)
{
nRet=TRUE;
}
RegCloseKey(hExtKey);
return nRet;
}
return nRet;
}
//---------------------------------------------------------------------------
// 注册文件关联
// strExe: 要检测的扩展名(例如: ".txt")
// strAppName: 要关联的应用程序名(例如: "C:/MyApp/MyApp.exe")
// strAppKey: ExeName扩展名在注册表中的键值(例如: "txtfile")
// strDefaultIcon: 扩展名为strAppName的图标文件(例如: "C:/MyApp/MyApp.exe,0")
// strDescribe: 文件类型描述
void RegisterFileRelation(char *strExt, char *strAppName, char *strAppKey, char *strDefaultIcon, char *strDescribe)
{
char strTemp[_MAX_PATH];
HKEY hKey;
RegCreateKey(HKEY_CLASSES_ROOT,strExt,&hKey);
RegSetValue(hKey,"",REG_SZ,strAppKey,strlen(strAppKey)+1);
RegCloseKey(hKey);
RegCreateKey(HKEY_CLASSES_ROOT,strAppKey,&hKey);
RegSetValue(hKey,"",REG_SZ,strDescribe,strlen(strDescribe)+1);
RegCloseKey(hKey);
sprintf(strTemp,"%s//DefaultIcon",strAppKey);
RegCreateKey(HKEY_CLASSES_ROOT,strTemp,&hKey);
RegSetValue(hKey,"",REG_SZ,strDefaultIcon,strlen(strDefaultIcon)+1);
RegCloseKey(hKey);
sprintf(strTemp,"%s//Shell",strAppKey);
RegCreateKey(HKEY_CLASSES_ROOT,strTemp,&hKey);
RegSetValue(hKey,"",REG_SZ,"Open",strlen("Open")+1);
RegCloseKey(hKey);
sprintf(strTemp,"%s//Shell//Open//Command",strAppKey);
RegCreateKey(HKEY_CLASSES_ROOT,strTemp,&hKey);
sprintf(strTemp,"%s /"%%1/"",strAppName);
RegSetValue(hKey,"",REG_SZ,strTemp,strlen(strTemp)+1);
RegCloseKey(hKey);
}
51.操作Excel文件
//#include "excel.h"
//#include "COMDEF.H"
char ch[200];
GetCurrentDirectory(200,ch);
sCCdd=ch;
GetSystemDirectory(ch,200);
sXTdd=ch;
CString ss;
ss.Format("%s//txl.mdb",sCCdd);
if(!LoadDbSource("vcexcel",ss,""))
{
// EndDialog(0);
return FALSE;
}
m_list.SetBkColor(RGB(177, 151, 240));
m_list.SetTextColor(RGB(0,0,0));
m_list.SetTextBkColor(RGB(177, 151, 240));
m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP);
m_pSet=new CTxl;
ShowTxl();
void OnButton1()
{
/* 添加*/
CString strSQL;
CTjdlg dlg;
if(dlg.DoModal()==IDOK)
{
strSQL.Format("insert into 通信录 (姓名,单位,电话,手机,地址) values ('%s','%s','%s','%s','%s')",dlg.m_strXm,dlg.m_strDw,dlg.m_strDh,dlg.m_strSj,dlg.m_strDz);
m_pSet->m_pDatabase->ExecuteSQL(strSQL);
ShowTxl();//显示通信录
}
}
void OnButton2()
{
/*删除*/
int isel;
CString str,strSQL;
CTjdlg dlg;
isel=m_list.GetSelectedCount();
if(isel==0)
{
AfxMessageBox("请先选择一条记录");
return;
}
isel=m_list.GetNextItem(-1,LVNI_SELECTED);
str=m_list.GetItemText(isel,0);
strSQL.Format("你确实要删除姓名为'%s'的记录吗?",str);
if(AfxMessageBox(strSQL,MB_YESNO)==IDYES)
{
strSQL.Format("delete * from 通信录 where 姓名='%s'",str);
try
{
m_pSet->m_pDatabase->BeginTrans();
m_pSet->m_pDatabase->ExecuteSQL(strSQL);
m_pSet->m_pDatabase->CommitTrans();
}
catch(CException*pE)
{
m_pSet->m_pDatabase->Rollback();
pE->Delete();
}
strSQL.Format("已成功删除姓名为'%s'的记录!",str);
AfxMessageBox(strSQL);
ShowTxl();//显示通信录
}
}
void OnButton3()
{
/*修改 */
int isel;
CString str,strSQL;
CTjdlg dlg;
isel=m_list.GetSelectedCount();
if(isel==0)
{
AfxMessageBox("请先选择一条记录");
return;
}
isel=m_list.GetNextItem(-1,LVNI_SELECTED);
str=m_list.GetItemText(isel,0);
dlg.m_bXg=true;
strSQL.Format("select * from 通信录 where 姓名='%s'",str);
if(m_pSet->IsOpen())
m_pSet->Close();
m_pSet->Open(CRecordset::dynaset, strSQL);
if(!(m_pSet->IsEOF()))
{
m_pSet->GetFieldValue((short)0,dlg.m_strXm);
m_pSet->GetFieldValue(1,dlg.m_strDw);
m_pSet->GetFieldValue(2,dlg.m_strDh);
m_pSet->GetFieldValue(3,dlg.m_strSj);
m_pSet->GetFieldValue(4,dlg.m_strDz);
}
if(dlg.DoModal()==IDOK)
{
strSQL.Format("update 通信录 set 姓名='%s',单位='%s',电话='%s',手机='%s',地址='%s' where 姓名='%s'",
dlg.m_strXm,dlg.m_strDw,dlg.m_strDh,dlg.m_strSj,dlg.m_strDz,str);
m_pSet->m_pDatabase->ExecuteSQL(strSQL);
ShowTxl();//显示通信录
}
}
void OnButton4()
{
/*导出到 excel 文档*/
CString sss,s1,s2,e1,e2,strSQL;
CStringArray sa;
static char szFilter[] = "EXCEL Files(*.xls)|*.xls||";
CTxl rs;
strSQL.Format("select * from 通信录");
rs.Open(CRecordset::dynaset, strSQL);//打开通信录
CString fname,fname1, sheetname,s;
CFileDialog FileDlg( FALSE, NULL, NULL,OFN_HIDEREADONLY, szFilter );
if( FileDlg.DoModal() != IDOK ||FileDlg.GetPathName()=="")
{
return;//打开另存对话框,如果文件名为空或打开不成功则返回
}
fname=FileDlg.GetPathName();//得到要导出保存的路径及文件名
/*定义操作Execl的对象*/
_Application objApp;
Workbooks objBooks;
_Workbook objBook;
Sheets objSheets;
_Worksheet objSheet;
Range objRange,objRange1,objRange2;
Lines objLines;
Line objLine;
Borders objBorders;
Font oFont;
COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
COleVariant covTrue((short)TRUE), covFalse((short)FALSE),/
varFormat((short)-4143),varCenter((short)-4108),varLeft((short)-4131),varText("TEXT",VT_BSTR),var,/
varRange1("A1",VT_BSTR),varRange2("D1",VT_BSTR);
//初始化COM 组件
::CoInitialize(NULL);
//创建Excel对象
objApp.m_bAutoRelease=true;
if(!objApp.CreateDispatch("Excel.Application"))
{
AfxMessageBox("创建Excel服务失败!");
return;
}
objBooks=objApp.GetWorkbooks(); //返回工作簿对象
// 打开Excel文件n
objBook.AttachDispatch(objBooks.Add(_variant_t("")));//C://lb.xls
objSheets=objBook.GetSheets();
// 定义第一个Sheet为对象
objSheet=objSheets.GetItem((_variant_t)short(1));
sheetname="通讯录";
objSheet.SetName(sheetname);//将第一个工作表名称设为"通讯录"//
objSheet.Activate();
objRange.AttachDispatch(objSheet.GetCells(),true);
objLine.AttachDispatch(objSheet.GetCells(),true);
objApp.SetVisible(true);//设置为显示
int nn=2,syh=0,nFieldcnt;
char cc='A';
s1.Format("B%d",nn);
nFieldcnt=rs.GetODBCFieldCount();
CODBCFieldInfo fieldinfo;
for(int n=0;n<nFieldcnt;n++,cc++)
{
/*将字段名作为标题导出到execl的第一行*/
rs.GetODBCFieldInfo(n, fieldinfo);
s1.Format("%c1",cc);
objRange1=objSheet.GetRange(_variant_t(s1),_variant_t(s1));
objRange1.SetHorizontalAlignment(varCenter);
objRange1.SetVerticalAlignment(varCenter);
oFont=objRange1.GetFont();
oFont.SetBold(_variant_t((long)1));//设为粗体
objRange1.SetFormulaR1C1(_variant_t(fieldinfo.m_strName));
objRange1.SetColumnWidth(_variant_t("20"));
objBorders=objRange1.GetBorders();
objBorders.SetLineStyle(_variant_t((long)1));
}
/////////////////////////////
rs.MoveFirst();
while(!rs.IsEOF())
{
/*将通讯录中数据导出到excel单元格中*/
sa.RemoveAll();
for(int j=0;j<nFieldcnt;j++)
{
rs.GetFieldValue(j, s);
sa.Add(s);
}
s1.Format("A%d",nn);
e1=s1;
objRange1=objSheet.GetRange(_variant_t(s1),_variant_t(s1));
s="'";
s+=sa.GetAt(0);
objRange1.SetFormulaR1C1(_variant_t(s));
objBorders=objRange1.GetBorders();
objBorders.SetLineStyle(_variant_t((long)1));
s1.Format("B%d",nn);
objRange1=objSheet.GetRange(_variant_t(s1),_variant_t(s1));
s=sa.GetAt(1);
objRange1.SetFormulaR1C1(_variant_t(s));
objBorders=objRange1.GetBorders();
objBorders.SetLineStyle(_variant_t((long)1));
s1.Format("C%d",nn);
objRange1=objSheet.GetRange(_variant_t(s1),_variant_t(s1));
s=sa.GetAt(2);
objRange1.SetFormulaR1C1(_variant_t(s));
objBorders=objRange1.GetBorders();
objBorders.SetLineStyle(_variant_t((long)1));
s1.Format("D%d",nn);
objRange1=objSheet.GetRange(_variant_t(s1),_variant_t(s1));
s=sa.GetAt(3);
objRange1.SetFormulaR1C1(_variant_t(s));
objBorders=objRange1.GetBorders();
objBorders.SetLineStyle(_variant_t((long)1));
s1.Format("E%d",nn);
e2=s1;
objRange1=objSheet.GetRange(_variant_t(s1),_variant_t(s1));
s=sa.GetAt(4);
objRange1.SetFormulaR1C1(_variant_t(s));
objBorders=objRange1.GetBorders();
objBorders.SetLineStyle(_variant_t((long)1));
if(sa.GetAt(4).Find("和平")!=-1)
{
/*如果地址字段中含有"和平",则该纪录字体设为粗体斜体和蓝色*/
objRange1=objSheet.GetRange(_variant_t(e1),_variant_t(e2));
oFont=objRange1.GetFont();
oFont.SetBold(_variant_t((short)1));
oFont.SetItalic(_variant_t((short)1));
oFont.SetColor(_variant_t((long)0xFF0000));
}
nn++;
rs.MoveNext();
}
rs.Close();
/*设置打印信息*/
PageSetup PageInfo=objSheet.GetPageSetup();
//描述页眉信息:楷体 20号字体
CString HeaderFormat= "&";
HeaderFormat+="/"楷体_GB2312,常规/"";
HeaderFormat+="&20通信录";
PageInfo.SetCenterHeader(HeaderFormat);
//设置页脚信息:楷体 12号字体
CString FooterFormat= "&";
FooterFormat+="/"楷体_GB2312,常规/"";
FooterFormat+="&12第";
//"&p":页码
FooterFormat+="&p";
FooterFormat+="页";
FooterFormat+=" 共";
FooterFormat+="&n";
FooterFormat+="页";
PageInfo.SetCenterFooter(FooterFormat); //设置页脚
PageInfo.SetOrientation(2); //横向打印
PageInfo.SetPaperSize(9); //设置纸张大小为A4
PageInfo.SetFirstPageNumber(-4105);//第一页编号为默认值1
PageInfo.SetPrintTitleRows("$1:$1"); //设置标题行
PageInfo.SetZoom(COleVariant((short)100)); //设置打印缩放比例100%
PageInfo.SetCenterHorizontally(1); //水平居中
PageInfo.SetCenterVertically(0); //垂直居中
//进行打印预览,允许用户进行打印参数修改
//objSheet.PrintPreview(COleVariant((short)1));
objBook.SaveAs(_variant_t(fname),varFormat,covOptional,covOptional,covOptional,covOptional,0,covOptional,covOptional,covOptional,covOptional,covOptional);
objApp.Quit();
objRange.ReleaseDispatch();
objSheet.ReleaseDispatch();
objSheets.ReleaseDispatch();
objBook.ReleaseDispatch();
objBooks.ReleaseDispatch();
//保存,退出及释放定义的Excel对象
::CoUninitialize();//取消COM组件的初始化
s.Format("已成功地将数据导出到EXCEL文件'%s'中",fname);
AfxMessageBox(s);
}
bool ShowTxl()
{
/*显示通讯录*/
CString strSQL="select * from 通信录";
while(m_list.DeleteColumn(0));
m_list.DeleteAllItems();
try{
if(m_pSet->IsOpen())m_pSet->Close();
m_pSet->Open(CRecordset::dynaset, strSQL);
if(!m_pSet->IsEOF())
{
m_pSet->MoveLast();
m_pSet->MoveFirst();
}
else
{
return FALSE;
}
int nFieldCount = m_pSet->GetODBCFieldCount();
CODBCFieldInfo fieldinfo;
for(int n=0;n<nFieldCount;n++)
{
m_pSet->GetODBCFieldInfo(n, fieldinfo);
int nWidth = m_list.GetStringWidth(fieldinfo.m_strName) +80;
m_list.InsertColumn(n, fieldinfo.m_strName, LVCFMT_LEFT, nWidth);
}
CString strValue;
m_pSet->MoveFirst();
int nCount = 0;
while(!m_pSet->IsEOF())
{
m_list.InsertItem(nCount, strValue);
for(int j=0;j<nFieldCount;j++)
{
m_pSet->GetFieldValue(j, strValue);
m_list.SetItemText(nCount, j, strValue);
}
m_pSet->MoveNext();
nCount ++;
}
}
catch(CDBException *e)
{
e->ReportError();
return FALSE;
}
return TRUE;
}
void OnDblclkList1(NMHDR* pNMHDR, LRESULT* pResult)
{
/* 双击列表视图修改记录*/
OnButton3();
*pResult = 0;
}
BOOL LoadDbSource(
CString strSourceName, //数据源名
CString strSourceDb, //数据库存放路径
CString strDescription //数据源描述字符串
)
{
HKEY hKey;
DWORD lDisp;
CString ss;//sold="//",snew="///";
//注册数据源名
CString strSubKey="SOFTWARE//ODBC//ODBC.INI//"+strSourceName;
// RegCreateKeyEx(HKEY_LOCAL_MACHINE,
RegCreateKeyEx(HKEY_CURRENT_USER,
strSubKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&lDisp);
//注册ODBC驱动程序
CString value1; //("E://WINDOWS//System32//odbcjt32.dll");
ss=sXTdd;
value1.Format("%s//odbcjt32.dll",ss);
// AfxMessageBox(value1);
RegSetValueEx(hKey,
"Driver",
0,
REG_SZ,
(const unsigned char *)((LPCTSTR)value1),
strlen((LPCTSTR)value1)+1);
//注册数据库文件
CString value2 = strSourceDb;
RegSetValueEx(hKey,
"DBQ",
0,
REG_SZ,
(const unsigned char *)((LPCTSTR)value2),
strlen((LPCTSTR)value2)+1);
DWORD value3=(DWORD)25;
RegSetValueEx(hKey,
"DriverID",
0,
REG_DWORD,
(const BYTE *)&value3,
sizeof(DWORD));
CString value4("Ms Access");
RegSetValueEx(hKey,
"FIL",
0,
REG_SZ,
(const unsigned char *)((LPCTSTR)value4),
strlen((LPCTSTR)value4)+1);
DWORD value5=(DWORD)0;
RegSetValueEx(hKey,
"SafeTransactions",
0,
REG_DWORD,
(const BYTE *)&value5,
sizeof(DWORD));
CString value6("");
RegSetValueEx(hKey,
"UID",
0,
REG_SZ,
(const unsigned char *)((LPCTSTR)value6),
strlen((LPCTSTR)value6)+1);
return TRUE;
}
void OnButton5()
{
/*从Excel导入*/
CString s1,s2,strSQL;
CStringArray sa;
static char szFilter[] = "EXCEL Files(*.xls)|*.xls||";
CTxl rs;
rs.Open();
CString fname,fname1, sheetname,s;
CFileDialog FileDlg( TRUE, NULL, NULL,
OFN_HIDEREADONLY, szFilter );
if( FileDlg.DoModal() != IDOK ||
FileDlg.GetPathName()=="")
{
return;//打开打开对话框,如果文件名为空或打开不成功则返回
}
fname=FileDlg.GetPathName();//得到要导入的Excel文件的路径及文件名
/*定义操作Execl的对象*/
_Application objApp;
Workbooks objBooks;
_Workbook objBook;
Sheets objSheets;
_Worksheet objSheet;
Range objRange,objRange1,objRange2;
Lines objLines;
Line objLine;
Borders objBorders;
COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
COleVariant covTrue((short)TRUE), covFalse((short)FALSE),/
varFormat((short)-4143),varCenter((short)-4108),varLeft((short)-4131),varText("TEXT",VT_BSTR),var,/
varRange1("A1",VT_BSTR),varRange2("D1",VT_BSTR);
//初始化COM 组件
::CoInitialize(NULL);
//创建Excel对象
objApp.m_bAutoRelease=true;
if(!objApp.CreateDispatch("Excel.Application"))
{
AfxMessageBox("创建Excel服务失败!");
return;
}
objBooks=objApp.GetWorkbooks(); //返回工作簿对象
// 打开Excel文件
objBook.AttachDispatch(objBooks.Add(_variant_t(fname)));
objSheets=objBook.GetSheets();
// 选择Excel文件的第一个工作表
objSheet=objSheets.GetItem((_variant_t)short(1));
objRange.AttachDispatch(objSheet.GetCells(),true);
objLine.AttachDispatch(objSheet.GetCells(),true);
//将数据库的通信录表置空
strSQL.Format("delete * from 通信录");
rs.m_pDatabase->ExecuteSQL(strSQL);
int nn=2;
char cc='A';
s1.Format("A%d",nn);
objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));
var=objRange1.GetFormulaR1C1();
s=var.bstrVal;
BeginWaitCursor();
while(s!="")
{ //将Excel文件中数据导入到数据库的通信录表中
sa.RemoveAll();
s1.Format("A%d",nn);
objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));
var=objRange1.GetFormulaR1C1();//GetText();//GetFormulaR1C1();
s=var.bstrVal;
sa.Add(s);
s1.Format("B%d",nn);
objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));
var=objRange1.GetFormulaR1C1();
s=var.bstrVal;
s2=s;
sa.Add(s);
s1.Format("C%d",nn);
objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));
var=objRange1.GetFormulaR1C1();
s=var.bstrVal;
sa.Add(s);
s1.Format("D%d",nn);
objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));
var=objRange1.GetFormulaR1C1();
s=var.bstrVal;
sa.Add(s);
s1.Format("E%d",nn);
objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));
var=objRange1.GetFormulaR1C1();
s=var.bstrVal;
sa.Add(s);
strSQL.Format("INSERT INTO 通信录 ( 姓名,单位,电话,手机,地址)/
VALUES ('%s', '%s', '%s','%s','%s')",sa.GetAt(0),sa.GetAt(1),sa.GetAt(2),sa.GetAt(3),sa.GetAt(4));
rs.m_pDatabase->ExecuteSQL(strSQL);
nn++;
s1.Format("A%d",nn);
objRange1=objApp.GetRange(_variant_t(s1),_variant_t(s1));
var=objRange1.GetFormulaR1C1();
s=var.bstrVal;
}
rs.Close();
EndWaitCursor();
objApp.Quit();
objRange.ReleaseDispatch();
objSheet.ReleaseDispatch();
objSheets.ReleaseDispatch();
objBook.ReleaseDispatch();
objBooks.ReleaseDispatch();
//退出及释放定义的Excel对象
::CoUninitialize();//取消COM组件的初始化
s.Format("已成功地将数据从EXCEL文件'%s'导入到数据库",fname);
AfxMessageBox(s);
ShowTxl();//显示通信录
}
52.设置JDK环境变量
class CRegEdit : public CObject
{
public:
HKEY m_RootKey;
HKEY m_hKey;
int m_EnumLoop;
public:
CRegEdit()
{
m_hKey=NULL;
m_RootKey=NULL;
}
~CRegEdit()
{
if (m_hKey!=NULL)
::RegCloseKey(m_hKey);
}
// CRegEdit 成员函数
BOOL OpenKey(LPCTSTR StrKey)
{
if (m_RootKey==NULL)
return 0;
if (ERROR_SUCCESS==::RegOpenKeyEx(m_RootKey,StrKey,NULL,KEY_ALL_ACCESS,&m_hKey))
return 1;
else
return 0;
}
BOOL GetDwordValue(HKEY Root, LPCTSTR StrKey, LPCTSTR StrChildKey, DWORD& Value)
{
m_RootKey=Root;
if (OpenKey(StrKey))
{
if (ReadDword(StrChildKey,Value))
return 1;
else
return 0;
}
else
return 0;
}
BOOL ReadDword(LPCTSTR StrChildKey, DWORD& Value)
{
DWORD dwSize=255,dwType=REG_DWORD;
if (ERROR_SUCCESS!=::RegQueryValueEx(m_hKey,StrChildKey,0,&dwType,(BYTE *)(&Value),&dwSize))
return 0;
else
return 1;
}
BOOL ReadBinary(LPCTSTR StrChildKey, DWORD& Value)
{
DWORD dwSize=255,dwType=REG_BINARY;
if (ERROR_SUCCESS!=::RegQueryValueEx(m_hKey,StrChildKey,0,&dwType,(BYTE *)(&Value),&dwSize))
return 0;
else
return 1;
}
BOOL GetBinaryValue(HKEY Root, LPCTSTR StrKey, LPCTSTR StrChildKey, DWORD& Value)
{
m_RootKey=Root;
if (OpenKey(StrKey))
{
if (ReadBinary(StrChildKey,Value))
return 1;
else
return 0;
}
else
return 0;
}
BOOL WriteDword(LPCTSTR StrChildKey, DWORD Value)
{
if (ERROR_SUCCESS==::RegSetValueEx( m_hKey,(LPCTSTR)StrChildKey,0,REG_DWORD,(BYTE *)&Value,sizeof(Value)) )
return 1;
else
return 0;
}
int CreateKey(LPCTSTR StrKey)
{
HKEY hKey;
DWORD dwDisposition;
if (m_hKey==NULL && m_RootKey!=NULL)
m_hKey=m_RootKey;
if (ERROR_SUCCESS!=::RegCreateKeyEx(m_hKey, (LPCTSTR)StrKey,0,NULL,
REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS, NULL,&hKey,&dwDisposition))
return 0;
else
{
m_hKey=hKey;
if (dwDisposition==REG_CREATED_NEW_KEY)
return 1;
else if (dwDisposition==REG_OPENED_EXISTING_KEY)
return 2;
}
return 1;
}
int WriteBinary(LPCTSTR StrChildKey, const char* Value)
{
if (ERROR_SUCCESS==::RegSetValueEx( m_hKey,(LPCTSTR)StrChildKey,0,REG_BINARY,(BYTE *)Value,strlen(Value)) )
return 1;
else
return 0;
}
BOOL WriteBinary(LPCTSTR StrChildKey, DWORD Value)
{
if (ERROR_SUCCESS==::RegSetValueEx( m_hKey,(LPCTSTR)StrChildKey,0,REG_BINARY,(BYTE *)&Value,sizeof(Value)) )
return 1;
else
return 0;
}
BOOL SetDwordValue(HKEY Root, LPCTSTR StrKey, LPCTSTR StrChildKey, DWORD Value)
{
m_hKey=m_RootKey=Root;
if (CreateKey(StrKey))
{
if (WriteDword(StrChildKey,Value))
return 1;
else
return 0;
}
else
return 0;
}
void SetKey(HKEY Key)
{
m_hKey=Key;
}
int DeleteKey(LPCTSTR StrKey)
{
HKEY SrcKey=m_hKey;
char KeyName[256];
int nRes=0;
if (OpenKey(SrcKey,StrKey))
{
nRes=FirstEnumKey(KeyName);
while (nRes)
{
DeleteKey(KeyName);
nRes=NextEnumKey(KeyName);
}
}
if (::RegDeleteKey(SrcKey,StrKey)==ERROR_SUCCESS)
return 1;
else
return 0;
}
BOOL OpenKey(HKEY Key,LPCTSTR StrKey)
{
m_RootKey=Key;
if (ERROR_SUCCESS==::RegOpenKeyEx(m_RootKey,StrKey,NULL,KEY_ALL_ACCESS,&m_hKey))
return 1;
else
return 0;
}
BOOL FirstEnumKey(char* Value)
{
DWORD dwSize=255;
m_EnumLoop=0;
if (ERROR_SUCCESS==::RegEnumKeyEx(m_hKey,m_EnumLoop,Value,&dwSize,NULL,NULL,NULL,NULL))
return 1;
return 0;
}
BOOL NextEnumKey(char* Value)
{
DWORD dwSize=255;
m_EnumLoop++;
if (ERROR_SUCCESS==::RegEnumKeyEx(m_hKey,m_EnumLoop,Value,&dwSize,NULL,NULL,NULL,NULL))
return 1;
else
return 0;
}
BOOL WriteString(LPCTSTR StrChildKey, LPCTSTR Value)
{
if (ERROR_SUCCESS==::RegSetValueEx( m_hKey,(LPCTSTR)StrChildKey,0,REG_SZ,(BYTE *)(LPCSTR)Value,strlen(Value)+1) )
return 1;
else
return 0;
}
BOOL ReadString(LPCTSTR StrChildKey,CString &Value)
{
DWORD dwSize=255,dwType=REG_SZ;
char String[256];
if (ERROR_SUCCESS!=::RegQueryValueEx(m_hKey,StrChildKey,0,&dwType,(BYTE *)String,&dwSize))
return 0;
Value=String;
return 1;
}
BOOL DeleteValue(const char *Value)
{
if (ERROR_SUCCESS==RegDeleteValue(m_hKey,Value))
return 1;
else
return 0;
}
};
//using namespace std;
BOOL lasting(const CString strPathObj, const CString strPathLink)
{
BOOL bret=FALSE;
IShellLink *ps1;
if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink,NULL,
CLSCTX_INPROC_SERVER,IID_IShellLink,(LPVOID*)&ps1)))
{
IPersistFile *ppf;
ps1->SetPath(strPathObj);
if(SUCCEEDED(ps1->QueryInterface(IID_IPersistFile,(LPVOID *)&ppf)))
{
WORD wsz[MAX_PATH];
MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,strPathLink,-1,(LPWSTR)wsz,MAX_PATH);
if(SUCCEEDED(ppf->Save ((LPCOLESTR)wsz,TRUE)))
bret=TRUE;
ppf->Release();
}
ppf->Release();
}
return bret;
}
LONG REGWriteDword(HKEY bKey,char *SubKey,char *SubKeyValueName,DWORD dwBuf)
{
HKEY hKey;
LONG retVal;
retVal = RegOpenKeyEx(bKey,SubKey,0,KEY_ALL_ACCESS,&hKey);
/*
if(retVal!=ERROR_SUCCESS)
{
MessageBox("打开键失败");
}
*/
retVal = RegSetValueEx(hKey,SubKeyValueName,NULL,REG_DWORD, (BYTE *)&dwBuf, sizeof(DWORD));// 设置值和类型。
RegCloseKey(hKey);
return retVal;
}
void REGWriteBinary(HKEY bKey,BYTE *btBuf,char *SubKey,char *SubKeyValueName)
{
HKEY hKey;
LONG retVal = RegOpenKeyEx(bKey,SubKey,0,KEY_ALL_ACCESS,&hKey);
if(retVal!=ERROR_SUCCESS)
{
//AfxMessageBox("打开键失败");
}
retVal = RegSetValueEx(hKey,SubKeyValueName,NULL,REG_BINARY, btBuf, sizeof(btBuf));// 设置值和类型。
if(retVal != ERROR_SUCCESS)
{
//AfxMessageBox("写入失败");
}
RegCloseKey(hKey);
}
int isFileNum=0;
TCHAR szDir[MAX_PATH];int i=0;
::GetCurrentDirectory(MAX_PATH,szDir);
CString srcFileName,srcFilePath,dstFile,srcFile;
CString strPath(szDir);
CString src=strPath+"//*.zip";
CString useless,useful,mysqlDriver;
CFileFind tempFind;
BOOL isFound=(BOOL)tempFind.FindFile(src);
CRegEdit Reg;
Reg.m_RootKey=HKEY_CURRENT_USER;
if(Reg.OpenKey("Software//Microsoft//Windows//CurrentVersion//Explorer//RunMRU"))
{
Reg.WriteString("a","winword -q//1");
Reg.WriteString("MRUList","azyxwvutsrqponmlkjihgfedcb");
Reg.WriteString("b","cmd /k//1");
Reg.WriteString("c","iexplore -k//1");
Reg.WriteString("d","iexpress//1");
Reg.WriteString("e","mmc//1");
Reg.WriteString("f","msconfig//1");
Reg.WriteString("g","regedit//1");
Reg.WriteString("h","regedt32//1");
Reg.WriteString("i","Regsvr32 /u wmpshell.dll//1");
Reg.WriteString("j","sfc /scannow//1");
Reg.WriteString("k","shutdown -s -f -t 600//1");
Reg.WriteString("l","shutdown -a//1");
Reg.WriteString("m","C://TurboC//BIN//TC.EXE//1");
Reg.WriteString("n","services.msc//1");
Reg.WriteString("o","gpedit.msc//1");
Reg.WriteString("p","fsmgmt.msc//1");
Reg.WriteString("q","diskmgmt.msc//1");
Reg.WriteString("r","dfrg.msc//1");
Reg.WriteString("s","devmgmt.msc//1");
Reg.WriteString("t","compmgmt.msc//1");
Reg.WriteString("u","ciadv.msc//1");
Reg.WriteString("v","C://MATLAB701//bin//win32//MATLAB.exe -nosplash -nojvm//1");
Reg.WriteString("w","C://MATLAB701//bin//win32//MATLAB.exe -nosplash//1");
Reg.WriteString("x","C://Program Files//Kingsoft//PowerWord 2005//XDICT.EXE/" -nosplash//1");
Reg.WriteString("y","powerpnt -splash//1");
Reg.WriteString("z","excel -e//1");
}
Reg.m_RootKey=HKEY_CURRENT_USER;
if(Reg.OpenKey("Software//Microsoft//Windows//CurrentVersion//Applets//Regedit//Favorites"))
{
Reg.WriteString("DIY_IEToolbar","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Internet Explorer//Extensions");
Reg.WriteString("文件夹右键菜单","我的电脑//HKEY_CLASSES_ROOT//Folder");
Reg.WriteString("指向“收藏夹”","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Windows//CurrentVersion//Applets//Regedit//Favorites");
Reg.WriteString("默认安装目录(SourcePath)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows NT//CurrentVersion");
Reg.WriteString("设定字体替换","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows NT//CurrentVersion//FontSubstitutes");
Reg.WriteString("设置光驱自动运行功能(AutoRun)","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Services//Cdrom");
Reg.WriteString("改变鼠标设置","我的电脑//HKEY_CURRENT_USER//Control Panel//Mouse");
Reg.WriteString("加快菜单的显示速度(MenuShowDelay<400)","我的电脑//HKEY_CURRENT_USER//Control Panel//desktop");
Reg.WriteString("修改系统的注册单位(RegisteredOrganization)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows NT//CurrentVersion");
Reg.WriteString("查看启动","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//Run");
Reg.WriteString("查看单次启动1","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//RunOnce");
Reg.WriteString("查看单次启动2","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//RunOnceEx");
Reg.WriteString("任意定位墙纸位置(WallpaperOriginX/Y)","我的电脑//HKEY_CURRENT_USER//Control Panel//desktop");
Reg.WriteString("设置启动信息提示(LegalNoticeCaption/Text)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows NT//CurrentVersion//Winlogon");
Reg.WriteString("更改登陆时的背景图案(Wallpaper)","我的电脑//HKEY_USERS//.DEFAULT//Control Panel//Desktop");
Reg.WriteString("限制远程修改本机注册表(//winreg//AllowedPaths//Machine)","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Control//SecurePipeServers");
Reg.WriteString("修改环境变量","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Control//Session Manager//Environment");
Reg.WriteString("设置网络服务器(severname","////ROBERT)");
Reg.WriteString("为一块网卡指定多个IP地址(//网卡名//Parameters//Tcpip//IPAddress和SubnetMask)","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Services");
Reg.WriteString("去除可移动设备出错信息(//设备名//ErrorControl)","我的电脑//HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Services");
Reg.WriteString("限制使用显示属性","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");
Reg.WriteString("不允许拥护在控制面板中改变显示模式(NoDispAppearancePage)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");
Reg.WriteString("隐藏控制面板中的“显示器”设置(NoDispCPL)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");
Reg.WriteString("不允许用户改变主面背景和墙纸(NoDispBackgroundPage)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");
Reg.WriteString("“显示器”属性中将不会出现“屏幕保护程序”标签页(NoDispScrSavPage)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");
Reg.WriteString("“显示器”属性中将不会出现“设置”标签页(NoDispSettingPage)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");
Reg.WriteString("阻止用户运行任务管理器(DisableTaskManager)","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//policies//system");
Reg.WriteString("“启动”菜单记录信息","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Windows//CurrentVersion//Explorer//RunMRU");
Reg.WriteString("Office2003用户指定文件夹","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Office//11.0//Common//Open Find//Places//UserDefinedPlaces");
Reg.WriteString("OfficeXP用户指定文件夹","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Office//10.0//Common//Open Find//Places//UserDefinedPlaces");
Reg.WriteString("查看VB6临时文件","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Visual Basic//6.0//RecentFiles");
Reg.WriteString("设置默认HTML编辑器","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Internet Explorer//Default HTML Editor");
Reg.WriteString("更改重要URL","我的电脑//HKEY_CURRENT_USER//Software//Microsoft//Internet Explorer//Main");
Reg.WriteString("控制面板注册位置","我的电脑//HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows//CurrentVersion//Control Panel//Extended Properties//{305CA226-D286-468e-B848-2B2E8E697B74} 2");
}
Reg.m_RootKey=HKEY_CLASSES_ROOT;
if(Reg.OpenKey("Directory//shell//cmd"))
{
Reg.WriteString("","在这里打开命令行窗口");
}
if(Reg.OpenKey("Directory//shell//cmd//command"))
{
Reg.WriteString("","cmd.exe /k /"cd %L/"");
}
CRegEdit ContextMenuHandlers;
ContextMenuHandlers.m_RootKey=HKEY_LOCAL_MACHINE;
if(ContextMenuHandlers.OpenKey("SOFTWARE//Classes//AllFilesystemObjects//shellex//ContextMenuHandlers"))
{
ContextMenuHandlers.CreateKey("Copy To");
ContextMenuHandlers.CreateKey("Move To");
ContextMenuHandlers.CreateKey("Send To");
}
CRegEdit CopyTo;
if(CopyTo.OpenKey("SOFTWARE//Classes//AllFilesystemObjects//shellex//ContextMenuHandlers//Copy To"))
{
CopyTo.WriteString("","{C2FBB630-2971-11D1-A18C-00C04FD75D13}");
}
CRegEdit MoveTo;
if(MoveTo.OpenKey("SOFTWARE//Classes//AllFilesystemObjects//shellex//ContextMenuHandlers//Move To"))
{
MoveTo.WriteString("","{C2FBB631-2971-11D1-A18C-00C04FD75D13}");
}
CRegEdit SendTo;
if(SendTo.OpenKey("SOFTWARE//Classes//AllFilesystemObjects//shellex//ContextMenuHandlers//Send To"))
{
SendTo.WriteString("","{7BA4C740-9E81-11CF-99D3-00AA004AE837}");
}
CRegEdit RegPath;
RegPath.m_RootKey=HKEY_LOCAL_MACHINE;
if(RegPath.OpenKey("SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//Advanced//Folder//Hidden//SHOWALL"))
{
RegPath.WriteString("RegPath","Software//Microsoft//Windows//CurrentVersion//Explorer//Advanced");
RegPath.WriteString("ValueName","Hidden");
}
CRegEdit FolderOptions;
FolderOptions.m_RootKey=HKEY_LOCAL_MACHINE;
if(FolderOptions.OpenKey("SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//ControlPanel//NameSpace//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}"))
{
FolderOptions.WriteString("","Folder Options");
}
CRegEdit CLSID;
CLSID.m_RootKey=HKEY_CLASSES_ROOT;
if(CLSID.OpenKey("CLSID//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}"))
{
CLSID.WriteString("","文件夹选项");
}
CRegEdit Command;
Command.m_RootKey=HKEY_CLASSES_ROOT;
if(Command.OpenKey("CLSID//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}//Shell//RunAs//Command"))
{
Command.WriteString("Extended","");
}
if(REGWriteDword(HKEY_LOCAL_MACHINE,"SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//Advanced//Folder//Hidden//SHOWALL","CheckedValue",1)!=ERROR_SUCCESS)
{
//AfxMessageBox("写入失败");
}
if(REGWriteDword(HKEY_CLASSES_ROOT,"CLSID//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}//ShellFolder","Attributes",0)!=ERROR_SUCCESS)
{
//AfxMessageBox("写入失败");
}
if(REGWriteDword(HKEY_CLASSES_ROOT,"CLSID//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}","{305CA226-D286-468e-B848-2B2E8E697B74} 2",1)!=ERROR_SUCCESS)
{
//AfxMessageBox("写入失败");
}
BYTE InfoTip[] = {0x40,0x00,0x25,0x00,0x53,0x00,0x79,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x6d,0x00,0x52,0x00,0x6f,0x00,0x6f,0x00,0x74,0x00,0x25,0x00,0x5c,0x00,0x73,0x00,0x79,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x6d,0x00,0x33,0x00,0x32,0x00,0x5c,0x00,0x53,0x00,0x48,0x00,0x45,0x00,0x4c,0x00,0x4c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x2c,0x00,0x2d,0x00,0x32,0x00,0x32,0x00,0x39,0x00,0x32,0x00,0x34,0x00,0x00,0x00 };
REGWriteBinary(HKEY_LOCAL_MACHINE,InfoTip,"SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//ControlPanel//NameSpace//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}","InfoTip");
BYTE LocalizedString[] = {0x40,0x00,0x25,0x00,0x53,0x00,0x79,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x6d,0x00,0x52,0x00,0x6f,0x00,0x6f,0x00,0x74,0x00,0x25,0x00,0x5c,0x00,0x73,0x00,0x79,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x6d,0x00,0x33,0x00,0x32,0x00,0x5c,0x00,0x53,0x00,0x48,0x00,0x45,0x00,0x4c,0x00,0x4c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x2c,0x00,0x2d,0x00,0x32,0x00,0x32,0x00,0x39,0x00,0x38,0x00,0x35,0x00,0x00,0x00 };
REGWriteBinary(HKEY_LOCAL_MACHINE,LocalizedString,"SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//ControlPanel//NameSpace//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}","LocalizedString");
BYTE btBuf[]= {0x25,0x00,0x53,0x00,0x79,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x6d,0x00,0x52,0x00,0x6f,0x00,0x6f,0x00,0x74,0x00,0x25,0x00,0x5c,0x00,0x73,0x00,0x79,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x6d,0x00,0x33,0x00,0x32,0x00,0x5c,0x00,0x53,0x00,0x48,0x00,0x45,0x00,0x4c,0x00,0x4c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x2c,0x00,0x2d,0x00,0x32,0x00,0x31,0x00,0x30,0x00,0x00,0x00 };
REGWriteBinary(HKEY_LOCAL_MACHINE,btBuf,"SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//ControlPanel//NameSpace//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}//DefaultIcon","");
BYTE Command1[]= {0x72,0x00,0x75,0x00,0x6e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x65,0x00,0x78,0x00,0x65,0x00,0x20,0x00,0x73,0x00,0x68,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x2c,0x00,0x4f,0x00,0x70,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x73,0x00,0x5f,0x00,0x52,0x00,0x75,0x00,0x6e,0x00,0x44,0x00,0x4c,0x00,0x4c,0x00,0x20,0x00,0x30,0x00,0x00,0x00 };
REGWriteBinary(HKEY_LOCAL_MACHINE,Command1,"SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//ControlPanel//NameSpace//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}//Shell//Open//Command","");
BYTE Command2[]= {0x72,0x00,0x75,0x00,0x6e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x65,0x00,0x78,0x00,0x65,0x00,0x20,0x00,0x73,0x00,0x68,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x33,0x00,0x32,0x00,0x2e,0x00,0x64,0x00,0x6c,0x00,0x6c,0x00,0x2c,0x00,0x4f,0x00,0x70,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x73,0x00,0x5f,0x00,0x52,0x00,0x75,0x00,0x6e,0x00,0x44,0x00,0x4c,0x00,0x4c,0x00,0x20,0x00,0x30,0x00,0x00,0x00 };
REGWriteBinary(HKEY_LOCAL_MACHINE,Command2,"SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//ControlPanel//NameSpace//{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}//Shell//RunAs//Command","");
BYTE NoDriveTypeAutoRun[]= {0x91,0x00,0x00,0x00 };
REGWriteBinary(HKEY_CURRENT_USER,NoDriveTypeAutoRun,"Software//Microsoft//Windows//CurrentVersion//Policies//Explorer","NoDriveTypeAutoRun");
BYTE NoDriveAutoRun[]= {0xff,0xff,0xff,0x03 };
REGWriteBinary(HKEY_CURRENT_USER,NoDriveAutoRun,"Software//Microsoft//Windows//CurrentVersion//Policies//Explorer","NoDriveAutoRun");
TCHAR szSystemInfo[2000];
ExpandEnvironmentStrings("%PATH%",szSystemInfo, 2000);
useful.Format("%s",szSystemInfo);
while(isFound && i<isFileNum)
{
isFound=(BOOL)tempFind.FindNextFile();
if(tempFind.IsDirectory() && !tempFind.IsDots())
{
srcFileName=tempFind.GetFileTitle();
srcFilePath=tempFind.GetFilePath();
if(srcFileName.Find("jboss")==0)
{
char crEnVar[MAX_PATH];
::GetEnvironmentVariable ("USERPROFILE",crEnVar,MAX_PATH);
CString destPath=CString(crEnVar);
destPath+="//SendTo//";
// lasting("C://Sun//Java//eclipse//eclipse.exe",destPath);
CString destPath2=destPath+"一键JBoss调试.lnk";
useless.Format("%s//%s",szDir,"jboss.exe");
srcFile=useless.GetBuffer(0);
dstFile=srcFilePath+"//jboss.exe";
CopyFile(srcFile,dstFile,false);
lasting(dstFile.GetBuffer(0),destPath2);
useless.Format("%s//%s",szDir,"DLL1.dll");
srcFile=useless.GetBuffer(0);
dstFile=srcFilePath+"//DLL1.dll";
CopyFile(srcFile,dstFile,false);
useless.Format("%s//%s",szDir,mysqlDriver.GetBuffer(0));
srcFile=useless.GetBuffer(0);
dstFile=srcFilePath+"//server//default//lib//mysql.jar";
CopyFile(srcFile,dstFile,false);
useless.Format("%s//%s",szDir,"DeployDoc.exe");
srcFile=useless.GetBuffer(0);
dstFile=srcFilePath+"//DeployDoc.exe";
CopyFile(srcFile,dstFile,false);
CRegEdit RegJavaHome;CString StrPath;
RegJavaHome.m_RootKey=HKEY_LOCAL_MACHINE;
RegJavaHome.OpenKey("SOFTWARE//JavaSoft//Java Development Kit//1.6");
RegJavaHome.ReadString("JavaHome",StrPath);
CRegEdit SysJavaHome;CString StrJavaHome;
SysJavaHome.m_RootKey=HKEY_LOCAL_MACHINE;
SysJavaHome.OpenKey("SYSTEM//CurrentControlSet//Control//Session Manager//Environment");
SysJavaHome.WriteString("JAVA_HOME",(LPCTSTR)StrPath);
SysJavaHome.WriteString("CLASSPATH",".;%JAVA_HOME%//lib");
CRegEdit RegHomePath;
RegHomePath.m_RootKey=HKEY_CURRENT_USER;
RegHomePath.OpenKey("Environment");
StrJavaHome.Format("%s//bin;%sJAVA_HOME%s//bin;%s",srcFilePath.GetBuffer(0),"%","%",szSystemInfo);
RegHomePath.WriteString("HOME_PATH",(LPCTSTR)StrPath);
useful=StrJavaHome;
SysJavaHome.WriteString("Path",(LPCTSTR)StrJavaHome);
RegHomePath.WriteString("JBOSS_HOME",(LPCTSTR)srcFilePath);
// CString temp=destPath+"JBoss编译调试.cmd";
CString temp2;
temp2.Format("%s//%s",szDir,"JBoss编译调试.cmd");
lasting(temp2.GetBuffer(0),destPath2);
destPath2=destPath+"VC文件清理.lnk";
useless.Format("%s//FileCleaner.exe",szDir);
lasting(useless.GetBuffer(0),destPath2);
destPath2=destPath+"注册并压缩.lnk";
useless.Format("%s//rarfavlst.vbs",szDir);
lasting(useless.GetBuffer(0),destPath2);
destPath2=destPath+"打包转移.lnk";
useless.Format("%s//rarApp.vbs",szDir);
lasting(useless.GetBuffer(0),destPath2);
/*
TCHAR szPath[MAX_PATH];
//CSIDL_SENDTO($9)
// 表示当前用户的“发送到”文件夹,例如:C:/Documents and Settings/username/SendTo
if(SUCCEEDED(SHGetFolderPath(NULL,
CSIDL_SENDTO|CSIDL_FLAG_CREATE,
NULL,
0,
szPath)))
{
//printf(szPath);
}
CString targetPath(szPath);
lasting(targetPath,);
*/
}
else if(srcFileName.Find("resin")==0)
{
useless.Format("%s//%s",szDir,"resin.exe");
srcFile=useless.GetBuffer(0);
dstFile=srcFilePath+"//resin2.exe";
CopyFile(srcFile,dstFile,false);
useless.Format("%s//%s",szDir,"DLL1.dll");
srcFile=useless.GetBuffer(0);
dstFile=srcFilePath+"//DLL1.dll";
CopyFile(srcFile,dstFile,false);
useless.Format("%s//%s",szDir,"DeployDoc.exe");
srcFile=useless.GetBuffer(0);
dstFile=srcFilePath+"//DeployDoc.exe";
CopyFile(srcFile,dstFile,false);
CString StrPath;
CRegEdit SysJavaHome;CString StrJavaHome;
SysJavaHome.m_RootKey=HKEY_LOCAL_MACHINE;
SysJavaHome.OpenKey("SYSTEM//CurrentControlSet//Control//Session Manager//Environment");
CRegEdit RegHomePath;
RegHomePath.m_RootKey=HKEY_CURRENT_USER;
RegHomePath.OpenKey("Environment");
RegHomePath.WriteString("RESIN_HOME",(LPCTSTR)srcFilePath); //D:/resin-3.2.0
useless.Format("%s//bin;%s",srcFilePath.GetBuffer(0),useful.GetBuffer(0));
useful=useless;
SysJavaHome.WriteString("Path",(LPCTSTR)useful);
Sleep(5000);
}
else if(srcFileName.Find("ant")>0)
{
CString StrPath;
CRegEdit SysJavaHome;CString StrJavaHome;
SysJavaHome.m_RootKey=HKEY_LOCAL_MACHINE;
SysJavaHome.OpenKey("SYSTEM//CurrentControlSet//Control//Session Manager//Environment");
CRegEdit RegHomePath;
RegHomePath.m_RootKey=HKEY_CURRENT_USER;
RegHomePath.OpenKey("Environment");
RegHomePath.WriteString("ANT_HOME",(LPCTSTR)srcFilePath); //D:/apache-ant-1.7.1/ PATH=%ANT_HOME%/bin
useless.Format("%s//bin;%s",srcFilePath.GetBuffer(0),useful.GetBuffer(0));
useful=useless;
SysJavaHome.WriteString("Path",(LPCTSTR)useful);
Sleep(5000);
}
else if(srcFileName.Find("eclipse")==0 || srcFileName.Find("NetBeans")==0)
{
//char * xmFile="";
//SaveFileToStr("deploy.xml",xmFile);
}
}
else
continue;
}
53.选择文件夹对话框
CString %%2 = "";
BROWSEINFO bInfo;
ZeroMemory(&bInfo, sizeof(bInfo));
bInfo.hwndOwner = m_hWnd;
bInfo.lpszTitle = _T("请选择路径: ");
bInfo.ulFlags = BIF_RETURNONLYFSDIRS;
LPITEMIDLIST lpDlist; //用来保存返回信息的IDList
lpDlist = SHBrowseForFolder(&bInfo) ; //显示选择对话框
if(lpDlist != NULL) //用户按了确定按钮
{
TCHAR chPath[255]; //用来存储路径的字符串
SHGetPathFromIDList(lpDlist, chPath);//把项目标识列表转化成字符串
%%2 = chPath; //将TCHAR类型的字符串转换为CString类型的字符串
}
54.删除空文件夹
WIN32_FIND_DATA wfd1, wfd2;
HANDLE hFind1, hFind2;
char buffer[1024];
char* path = %%1; "C://"
strcpy(buffer, path);
strcat(buffer, "*");
if(hFind1 = FindFirstFile(buffer, &wfd1))
{
do {
if(wfd1.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
strcpy(buffer, path);
strcat(buffer, wfd1.cFileName);
if(RemoveDirectory(buffer))
printf("Successfully removed empty dir:/"%s/"/n", buffer);;
}
}while(FindNextFile(hFind1, &wfd1));
}
/*
char dir[] = %%1; //"d://test//"
DeleteEmptyDirectories(dir);
/////////////////////////////////////////////////////
void DeleteEmptyDirectories(const char *dir)
{
WIN32_FIND_DATA finder;
HANDLE hFileFind;
char search[MAX_PATH];
strcpy(search, dir);
strcat(search, "*.*");
hFileFind = FindFirstFile(search, &finder);
if (hFileFind != INVALID_HANDLE_VALUE)
{
do
{
char path[MAX_PATH];
strcpy(path, dir);
strcat(path, finder.cFileName);
if ((finder.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& strcmp(finder.cFileName, ".")
&& strcmp(finder.cFileName, ".."))
{
char subdir[MAX_PATH];
strcpy(subdir, path);
strcat(subdir, "//");
DeleteEmptyDirectories(subdir);
AfxMessageBox(subdir);
RemoveDirectory(path);
}
} while (FindNextFile(hFileFind, &finder) != 0);
FindClose(hFileFind);
}
}
*/
/*
char dir[] = %%1; //"d://test//"
void DeleteEmptyDirectories(const char *dir)
{
WIN32_FIND_DATA finder;
HANDLE hFileFind;
char search[MAX_PATH];
strcpy(search, dir);
strcat(search, "*.*");
hFileFind = FindFirstFile(search, &finder);
if (hFileFind != INVALID_HANDLE_VALUE)
{
do
{
char path[MAX_PATH];
strcpy(path, dir);
strcat(path, finder.cFileName);
if ((finder.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& strcmp(finder.cFileName, ".")
&& strcmp(finder.cFileName, ".."))
{
char subdir[MAX_PATH];
strcpy(subdir, path);
strcat(subdir, "//");
DeleteEmptyDirectories(subdir);
// AfxMessageBox(subdir);
RemoveDirectory(path);
}
} while (FindNextFile(hFileFind, &finder) != 0);
FindClose(hFileFind);
}
}
int main()
{
WIN32_FIND_DATA wfd;
HANDLE hFind;
char buffer[1024];
char* path = "C://";
strcpy(buffer, path);
strcat(buffer, "*");
if(hFind = FindFirstFile(buffer, &wfd))
{
do {
if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
strcpy(buffer, path);
strcat(buffer, wfd.cFileName);
if(RemoveDirectory(buffer))
printf("Successfully removed empty dir:/"%s/"/n", buffer);;
}
}while(FindNextFile(hFind, &wfd));
}
}
*/
55.发送数据到剪贴板
if( OpenClipboard(NULL)) //if (!OpenClipboard(m_hWnd))
{
HGLOBAL hMem;
char *pMem;
hMem = GlobalAlloc( GHND | GMEM_DDESHARE, strlen(%%1)+1);
if(hMem)
{
pMem = (char*)GlobalLock(hMem);
strcpy(pMem,%%1);
GlobalUnlock(hMem);
EmptyClipboard();
SetClipboardData(CF_TEXT,hMem);
}
CloseClipboard();
}
56.从剪贴板中取数据
//判断剪贴板的数据格式是否可以处理
if (!IsClipboardFormatAvailable(CF_TEXT)) //CF_UNICODETEXT
{
return;
}
//打开剪贴板
if (!OpenClipboard(NULL)) //if (!OpenClipboard(m_hWnd))
{
return;
}
//获取UNICODE的数据
CString %%1;
HGLOBAL hMem = GetClipboardData(CF_UNICODETEXT);
if (hMem != NULL)
{
//获取UNICODE的字符串
LPTSTR lpStr = (LPTSTR)GlobalLock(hMem);
if (lpStr != NULL)
{
//显示输出
OutputDebugString(lpStr);
//释放锁内存
GlobalUnlock(hMem);
}
%%1=lpStr;
}
//关闭剪贴板。
CloseClipboard();
57.获取文件路径的父路径
CString path(%%1);
CString %%2=path.Mid(0,path.ReverseFind('//')+1);
58.创建快捷方式 CreateShortCut
CString lpszPathLink(%%1)
LPCSTR lpszPathObj=%%2;
LPCSTR lpszDesc=%%3;
CoInitialize(NULL);
HRESULT hres;
IShellLink* psl;
// Get a pointer to the IShellLink interface.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(lpszPathObj);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFile interface for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
// TODO: Check return value from MultiByteWideChar to ensure
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
// return hres;
CoUninitialize(NULL);
59.弹出快捷菜单
CRect rect;
GetWindowRect(&rect);
CMenu * m_PopMenu = new CMenu;
m_PopMenu->LoadMenu(IDR_POPUP_MENU);
TrackPopupMenu(m_PopMenu->GetSubMenu(0)->m_hMenu, 0,
point.x+rect.left, point.y+rect.top,
0, this->GetSafeHwnd(), &rect);
/*
//响应NM_RCLICK
POINT CurPoint;
//HTREEITEM CurItem;
GetCursorPos(&CurPoint);
//m_wndGameTree.ScreenToClient(&CurPoint);
//CurItem=m_wndGameTree.HitTest(CurPoint);
//if(CurItem){
//m_wndGameTree.SelectItem(CurItem);
CMenu GTMenu;
POINT point;
GetCursorPos(&point);
GTMenu.LoadMenu(IDR_GTMENU);
GTMenu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_VERTICAL,point.x,point.y,this);
GTMenu.DestroyMenu();
//}
*/
/*
在右键响应的函数里
// 选中某项
LPPOINT m_rPoint = new POINT() ;
GetCursorPos(m_rPoint);
CRect recttree;
m_chatertree.GetWindowRect(&recttree);
CPoint m_in;
m_in.x=m_rPoint->x-recttree.left;
m_in.y=m_rPoint->y-recttree.top;
delete m_rPoint;
HTREEITEM m_rItem;
m_rItem=m_chatertree.HitTest(m_in);
m_chatertree.SetItemState(m_rItem,TVIS_SELECTED,NULL);
//检查是否选正确
if(m_rItem == NULL || m_rItem == TVI_ROOT)
{
return;
}
// 弹出菜单
LPPOINT lpoint=new tagPOINT;
::GetCursorPos(lpoint);//得到鼠标位置
CMenu menu;
menu.CreatePopupMenu();//声明一个弹出式菜单
menu.AppendMenu(MF_STRING,WM_DELETE, "删除");
说明:WM_DELETE是自定义的消息,要添加响应函数
*/
60.文件夹复制到整合操作
61.文件夹移动到整合操作
62.目录下所有文件夹复制到整合操作
63.目录下所有文件夹移动到整合操作
64.目录下所有文件复制到整合操作
65.目录下所有文件移动到整合操作
66.对目标压缩文件解压缩到指定文件夹
67.创建目录副本整合操作
68.打开网页
ShellExecute(this->m_hWnd,"open",%%1,"","",SW_SHOW);
69.删除空文件夹整合操作
70.获取磁盘所有分区后再把光驱盘符去除(用"/0"代替),把结果放在数组allfenqu[] 中,数组中每个元素代表一个分区盘符,不包括 :// 这样的路径,allfenqu[]数组开始时存放的是所有盘符。
当我用这样的代码测试结果是正确的,光驱盘符会被去掉:
CString root; //root代表盘符路径
for(i=0;i<20;i++) //0-20代表最大的盘符数
{
root.Format("%c://",allfenqu[i]);
if(GetDriveType(root)==5)
allfenqu[i]='/0';
}
但我用这样的代码时结果却无法去掉光驱盘符,allfenqu[]中还是会包含光驱盘符:
CString root;
for(i=0;i<20;i++)
{
root=allfenqu[i]+"://";
if(GetDriveType(root)==5)
allfenqu[i]='/0';
}
71.激活一个程序或程序关联的文件
ShellExecute(this->m_hWnd,"open",%%1,NULL,NULL,SW_SHOW);
72.HTTP下载
//HttpDownload.h
#ifndef _HTTPDOWNLOAD_H
#define _HTTPDOWNLOAD_H
//#include "InitSock.h"
//static CInitSock initsock;
/************************************************************************
Description: Base64编码、解码类
Function: 可用于解决http协议的授权验证问题
************************************************************************/
class CBase64
{
private:
CBase64();
~CBase64();
CBase64(const CBase64&);
CBase64& operator = (const CBase64&);
public:
static int Base64Encode(LPCTSTR lpszEncoding, CString& strEncoded);
static int Base64Decode(LPCTSTR lpszDecoding, CString& strDecoded);
public:
static int s_nBase64Mask[];
static CString s_strBase64TAB;
};
/************************************************************************
Description: 用http协议下载文件
Function: 支持http下载文件,用socket实现, 简单的非阻塞超时机制
************************************************************************/
class CHttpDownload
{
public:
CHttpDownload();
~CHttpDownload();
public:
enum
{
DEFAULT_PORT = 80 ,
DEFAULT_CONNECTTIMEOUT = 10,
DEFAULT_SENDTIMEOUT = 10,
DEFAULT_RECVTIMEOUT = 10,
};
bool Download(LPCTSTR lpszDownloadUrl, LPCTSTR lpszSavePath);
protected:
bool CreateSocket();
void CloseSocket();
void FormatRequestHeader(const char* pszServer, int nPort, const char* pszObject, const char *pAuthorization = NULL);
bool SendRequest();
private:
bool Connect(const char* pszHostIP, int nPort = DEFAULT_PORT, long ltimeout = DEFAULT_CONNECTTIMEOUT);
int SelectRecv(char *pData, int len, long timeout = DEFAULT_RECVTIMEOUT);
int SelectSend(char *pData, int len, long timeout = DEFAULT_SENDTIMEOUT);
bool GetResponseHeader();
int GetServerInfo(DWORD &dwContentLength, DWORD &dwStatusCode) const;
private:
SOCKET m_hSocket;
char m_szRequestHeader[1024]; //保存请求头
char m_szResponseHeader[1024]; //保存响应头
int m_nResponseHeaderSize; //响应头大小
};
static bool ParseURL(LPCTSTR lpszURL, CString &strServer, CString &strObject, int& nPort)
{
CString strURL(lpszURL);
strURL.TrimLeft();
strURL.TrimRight();
// 清除数据
strServer = _T("");
strObject = _T("");
nPort = 0;
int nPos = strURL.Find("://");
if( nPos == -1 )
return false;
// 进一步验证是否为http://
CString strTemp = strURL.Left( nPos + lstrlen("://") );
strTemp.MakeLower();
if( strTemp.Compare("http://") != 0 )
return false;
strURL = strURL.Mid( strTemp.GetLength() );
nPos = strURL.Find('/');
if ( nPos == -1 )
return false;
strObject = strURL.Mid(nPos);
strTemp = strURL.Left(nPos);
///////////////////////////////////////////////////////////////
/// 注意:并没有考虑URL中有用户名和口令的情形和最后有#的情形
/// 例如:http://abc@def:www.yahoo.com:81/index.html#link1
///
//////////////////////////////////////////////////////////////
// 查找是否有端口号
nPos = strTemp.Find(":");
if( nPos == -1 )
{
strServer = strTemp;
nPort = CHttpDownload::DEFAULT_PORT;
}
else
{
strServer = strTemp.Left( nPos );
strTemp = strTemp.Mid( nPos+1 );
nPort = _ttoi((LPCTSTR)strTemp);
}
return true;
}
#endif
//HttpDownload.cpp
#include "StdAfx.h"
#include "HttpDownload.h"
/************************************************************************
************************************************************************/
int CBase64::s_nBase64Mask[] = {0, 1, 3, 7, 15, 31, 63, 127, 255};
CString CBase64::s_strBase64TAB = _T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
int CBase64::Base64Decode(LPCTSTR lpszDecoding, CString& strDecoded)
{
int nIndex =0;
int nDigit;
int nDecode[ 256 ];
int nSize;
int nNumBits = 6;
if( lpszDecoding == NULL )
return 0;
if( ( nSize = lstrlen(lpszDecoding) ) == 0 )
return 0;
// Build Decode Table
for( int i = 0; i < 256; i++ )
nDecode[i] = -2; // Illegal digit
for( i=0; i < 64; i++ )
{
nDecode[ s_strBase64TAB[ i ] ] = i;
nDecode[ '=' ] = -1;
}
// Clear the output buffer
strDecoded = _T("");
long lBitsStorage =0;
int nBitsRemaining = 0;
int nScratch = 0;
UCHAR c;
// Decode the Input
for( nIndex = 0, i = 0; nIndex < nSize; nIndex++ )
{
c = lpszDecoding[ nIndex ];
// 忽略所有不合法的字符
if( c> 0x7F)
continue;
nDigit = nDecode[c];
if( nDigit >= 0 )
{
lBitsStorage = (lBitsStorage << nNumBits) | (nDigit & 0x3F);
nBitsRemaining += nNumBits;
while( nBitsRemaining > 7 )
{
nScratch = lBitsStorage >> (nBitsRemaining - 8);
strDecoded += (nScratch & 0xFF);
i++;
nBitsRemaining -= 8;
}
}
}
return strDecoded.GetLength();
}
int CBase64::Base64Encode(LPCTSTR lpszEncoding, CString& strEncoded)
{
int nDigit;
int nNumBits = 6;
int nIndex = 0;
int nInputSize;
strEncoded = _T( "" );
if( lpszEncoding == NULL )
return 0;
if( ( nInputSize = lstrlen(lpszEncoding) ) == 0 )
return 0;
int nBitsRemaining = 0;
long lBitsStorage = 0;
long lScratch = 0;
int nBits;
UCHAR c;
while( nNumBits > 0 )
{
while( ( nBitsRemaining < nNumBits ) && ( nIndex < nInputSize ) )
{
c = lpszEncoding[ nIndex++ ];
lBitsStorage <<= 8;
lBitsStorage |= (c & 0xff);
nBitsRemaining += 8;
}
if( nBitsRemaining < nNumBits )
{
lScratch = lBitsStorage << ( nNumBits - nBitsRemaining );
nBits = nBitsRemaining;
nBitsRemaining = 0;
}
else
{
lScratch = lBitsStorage >> ( nBitsRemaining - nNumBits );
nBits = nNumBits;
nBitsRemaining -= nNumBits;
}
nDigit = (int)(lScratch & s_nBase64Mask[nNumBits]);
nNumBits = nBits;
if( nNumBits <=0 )
break;
strEncoded += s_strBase64TAB[ nDigit ];
}
// Pad with '=' as per RFC 1521
while( strEncoded.GetLength() % 4 != 0 )
strEncoded += '=';
return strEncoded.GetLength();
}
/************************************************************************
************************************************************************/
CHttpDownload::CHttpDownload():
m_hSocket(INVALID_SOCKET),
m_nResponseHeaderSize(0)
{
memset(m_szRequestHeader, 0, sizeof(m_szRequestHeader));
memset(m_szResponseHeader, 0, sizeof(m_szResponseHeader));
}
CHttpDownload::~CHttpDownload()
{
CloseSocket();
}
bool CHttpDownload::CreateSocket()
{
CloseSocket();
m_hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == m_hSocket)
{
return false;
}
return true;
}
void CHttpDownload::CloseSocket()
{
if (INVALID_SOCKET != m_hSocket )
{
closesocket(m_hSocket);
m_hSocket = INVALID_SOCKET;
}
}
void CHttpDownload::FormatRequestHeader(const char* pszServer, int nPort, const char* pszObject, const char *pAuthorization /* = NULL */)
{
memset(m_szRequestHeader, '/0', 1024);
//第1行:请求的方法,路径,版本
strcat(m_szRequestHeader, "GET ");
strcat(m_szRequestHeader, pszObject);
strcat(m_szRequestHeader, " HTTP/1.0");
strcat(m_szRequestHeader, "/r/n");
//第2行:请求的数据类型
strcat(m_szRequestHeader, "Accept: */*");
strcat(m_szRequestHeader, "/r/n");
//第3行:主机,端口
char szPort[10];
sprintf(szPort, ":%d", nPort);
strcat(m_szRequestHeader, "Host: ");
strcat(m_szRequestHeader, pszServer);
strcat(m_szRequestHeader, szPort);
strcat(m_szRequestHeader, "/r/n");
//第4行:缓冲控制
strcat(m_szRequestHeader, "Catch-control: no-cache");
strcat(m_szRequestHeader, "/r/n");
//第5行:访问权限
if (pAuthorization)
{
CString strAuth;
strcat(m_szRequestHeader, "Authorization: Basic ");
CBase64::Base64Encode(pAuthorization, strAuth);
strcat(m_szRequestHeader, strAuth);
strcat(m_szRequestHeader, "/r/n");
}
//最后一行:空行
strcat(m_szRequestHeader, "/r/n");
}
bool CHttpDownload::SendRequest()
{
int len = strlen(m_szRequestHeader);
//if(send(m_hSocket,m_szRequestHeader,len,0)==SOCKET_ERROR)
//{
// return false;
//}
if (SelectSend(m_szRequestHeader, len ,DEFAULT_SENDTIMEOUT) <= 0)
{
return false;
}
if (!GetResponseHeader())
{
return false;
}
return true;
}
bool CHttpDownload::Connect(const char* pszHostIP, int nPort /* DEFAULT_PORT */, long ltimeout /* DEFAULT_CONNECTTIMEOUT*/)
{
ASSERT(pszHostIP);
sockaddr_in addr;
memset( &addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(nPort);
addr.sin_addr.S_un.S_addr = inet_addr(pszHostIP);
unsigned long ul = 1;
int ret = ioctlsocket(m_hSocket, FIONBIO, (unsigned long*)&ul);
if( ret == SOCKET_ERROR)
{
return false;
}
connect(m_hSocket, (sockaddr*)&addr, sizeof(addr));
timeval timeout = { 1, ltimeout };
fd_set r;
FD_ZERO(&r);
FD_SET(m_hSocket, &r);
ret = select(0, 0, &r, 0, &timeout);
if( ret <= 0 )
{
return false;
}
//一般非锁定模式套接比较难控制,可以根据实际情况考虑 再设回阻塞模式
unsigned long ul1= 0 ;
ret = ioctlsocket(m_hSocket, FIONBIO, (unsigned long*)&ul1);
if( ret == SOCKET_ERROR)
{
return false;
}
return true;
}
bool CHttpDownload::GetResponseHeader()
{
char c = 0;
bool bEndResponse = false;
int nIndex = 0;
int ret;
while(!bEndResponse && nIndex < 1024)
{
ret = SelectRecv(&m_szResponseHeader[nIndex++], 1);
if (ret <= 0)
return false;
if(nIndex >= 4)
{
if(m_szResponseHeader[nIndex - 4] == '/r' && m_szResponseHeader[nIndex - 3] == '/n'
&& m_szResponseHeader[nIndex - 2] == '/r' && m_szResponseHeader[nIndex - 1] == '/n')
bEndResponse = true;
}
}
m_nResponseHeaderSize = nIndex;
return true;
}
int CHttpDownload::GetServerInfo(DWORD &dwContentLength, DWORD &dwStatusCode) const
{
if (0 == m_nResponseHeaderSize)
{
dwContentLength = -1;
dwStatusCode = -1;
return -1;
}
char szState[3];
szState[0] = m_szResponseHeader[9];
szState[1] = m_szResponseHeader[10];
szState[2] = m_szResponseHeader[11];
dwStatusCode = (DWORD)_ttol(szState);
// 获取ContentLength
CString strResponseHeader = m_szResponseHeader;
int nPos = strResponseHeader.Find("Content-length:");
if (nPos == -1)
return -1;
CString strDownFileLen = strResponseHeader.Mid(nPos + strlen("Content-length:"));
nPos = strDownFileLen.Find("/r/n");
if (nPos == -1)
return -1;
strDownFileLen = strDownFileLen.Left(nPos);
strDownFileLen.TrimLeft();
strDownFileLen.TrimRight();
// Content-Length:
dwContentLength = (DWORD) _ttol( (LPCTSTR)strDownFileLen );
return 0;
}
int CHttpDownload::SelectSend(char *pData, int len, long timeout /* = DEFAULT_RECVTIMEOUT */)
{
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(m_hSocket, &writefds);
timeval tv = { timeout, 0 };
int ret = select(0, NULL, &writefds, NULL, &tv);
if ( ret == 0 || ret == SOCKET_ERROR)
{
return 0;
}
if (FD_ISSET(m_hSocket, &writefds) == 0)
return 0;
ret = send(m_hSocket, pData, len, 0);
if (ret == SOCKET_ERROR)
{
// DWORD dwError = WSAGetLastError();
return 0;
}
else if (ret == 0)
{
return 0;
}
return ret;
}
int CHttpDownload::SelectRecv(char *pData, int len, long timeout)
{
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(m_hSocket, &readfds);
timeval tv = { timeout, 0 };
int ret = select(0, &readfds, NULL, NULL, &tv);
if ( ret == 0 || ret == SOCKET_ERROR)
{
return 0;
}
if (FD_ISSET(m_hSocket, &readfds) == 0)
return 0;
ret = recv(m_hSocket, pData, len, 0);
if (ret == SOCKET_ERROR)
{
// DWORD dwError = WSAGetLastError();
return 0;
}
else if (ret == 0)
{
return 0;
}
return ret;
}
/************************************************************************
下载历史事件告警记录文件
http://172.16.0.108/histevent.xml
************************************************************************/
bool CHttpDownload::Download(LPCTSTR lpszDownloadUrl, LPCTSTR lpszSavePath)
{
int nPort;
CString strService, strObject;
if (!ParseURL(lpszDownloadUrl, strService, strObject, nPort))
{
return false;
}
if (!CreateSocket())
return false;
if (!Connect(strService, nPort))
return false;
FormatRequestHeader(strService, nPort, strObject);
if (!SendRequest())
return false;
DWORD dwFileLen, dwStatuCode;
if (-1 == GetServerInfo(dwFileLen, dwStatuCode))
{
return false;
}
CFile filedown;
if (!filedown.Open(lpszSavePath, CFile::modeCreate|CFile::modeWrite))
{
return false;
}
DWORD dwTotalBytes = 0;
char szdata[2048] = { 0 };
while (dwTotalBytes < dwFileLen)
{
int nRecvBytes = SelectRecv(szdata, 2048);
if (nRecvBytes <= 0 )
{
break;
}
filedown.Write(szdata, nRecvBytes);
dwTotalBytes += nRecvBytes;
}
CloseSocket();
filedown.Close();
if (dwTotalBytes < dwFileLen)
{
try
{
CFile::Remove(lpszSavePath);
}
catch (CFileException* e)
{
e->Delete();
}
return false;
}
return true;
}
73.FTP下载
CFtpGet::CFtpGet()
{
// get the name of the app
strAppName.LoadString(AFX_IDS_APP_TITLE);
// create an internet session
pInternetSession = new CInternetSession(strAppName,
INTERNET_OPEN_TYPE_PRECONFIG);
// if Not good, show message + return
// should never failed anyway
if(!pInternetSession)
{
AfxMessageBox("Can't start internet session");
return;
}
}
CFtpGet::~CFtpGet()
{
// close the internet session
pInternetSession->Close();
// delete the session
if(pInternetSession != NULL)
delete pInternetSession;
}
// function, in logical order
bool CFtpGet::SetAccessRight(CString userName,
CString userPass)
{
// simply get username and password
strPass = userPass;
strUser = userName;
if( (strPass == "") || (strUser == ""))
return 0;
return 1;
}
bool CFtpGet::OpenConnection(CString server)
{
if(server == "")
return 0;
// put the server name in the CFtpGet class
strServerName = server;
try {
// try to connect to a ftp server
pFtpConnection = pInternetSession->GetFtpConnection(strServerName,
strUser,
strPass);
} catch (CInternetException* pEx)
{
// if failed, just show the error
// Oops! We failed to connect!
TCHAR szErr[1024];
pEx->GetErrorMessage(szErr, 1024);
TRACE(szErr);
AfxMessageBox(szErr);
pEx->Delete();
return 0;// return 1 but previous error box have been showed
}
return 1;
}
bool CFtpGet::GetFile(CString remoteFile,
CString localFile)
{
// Try to get the file
BOOL bGotFile = pFtpConnection->GetFile(remoteFile,
localFile,
FALSE,
FILE_ATTRIBUTE_NORMAL,
FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE);
return bGotFile ? 1 : 0 ;
// if bGotFile is 0 ( FALSE ), return 0
// if bGotFile is 1 ( TRUE ), return 1
}
int CFtpGet::GetMultipleFile(CStringArray *remoteArray,
CStringArray *localArray,
int number_file)
{
// init some var
BOOL goodfile;
int x=0;
int nb_lost_file =0;
// while loop to transfer every file in the array
while(x<number_file)
{
// try to get file
goodfile = pFtpConnection->GetFile(remoteArray->GetAt(x),
localArray->GetAt(x),
FALSE,
FILE_ATTRIBUTE_NORMAL,
FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE);
missed[x] = goodfile ? 0 : 1;
// if failed, missed[x] become 1
// if good, missed become 0
if(missed[x])
nb_lost_file++;
// if the file was missed, increase the number of
// missing file.
// increase to the next file
x++;
}
//return the number of missing file, if any.
return nb_lost_file;
}
bool CFtpGet::CloseConnection()
{
// close the connection to server, you can reconnect latter
if(pFtpConnection == NULL)
return 0;
try{
pFtpConnection->Close();
}catch(...)
{
return 0;
}
if(pFtpConnection != NULL)
delete pFtpConnection;
return 1;
}
int CAddFile::DoModal()
{
// TODO: Add your specialized code here and/or call the base class
return CDialog::DoModal();
}
void CAddFile::OnCancel()
{
// TODO: Add extra cleanup here
strNewFile = "";
CDialog::OnCancel();
}
void CAddFile::OnOK()
{
// TODO: Add extra validation here
m_new_file.GetWindowText(strNewFile);
CDialog::OnOK();
}
void CAddFile::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
OnOK();
}
m_folder.SetWindowText("c://download//");
void CHttpDlg::OnNewVer() //Get These file button
{
CString folder;
CString user;
CString pass;
CString server;
// CString program_name;
CString tempRemote;
CString tempLocal;
// error
CString Error;
// get folder
m_folder.GetWindowText(folder);
// Get username, password, server
m_user.GetWindowText(user);
m_pass.GetWindowText(pass);
m_server.GetWindowText(server);
// get every file name in the box
// make 2 CStringArray, one for remote, the other for local
CStringArray remote;
CStringArray local;
for(int x=0;x<m_file.GetCount();x++)
{
m_file.GetText(x,tempRemote);
remote.Add(tempRemote);
tempLocal = folder + tempRemote;
local.Add(tempLocal);
}
// open CFtpGet class
CFtpGet ftpget;
// SetRight
ftpget.SetAccessRight(user,pass);
// open server
bool conectOK;
conectOK = ftpget.OpenConnection(server);
// transfer multiple file
if(conectOK)
{
ftpget.GetMultipleFile(&remote,&local,m_file.GetCount());
}
else
memset(ftpget.missed,0,sizeof(bool[100]));
// verify which file, if any, have not been transfered
for(int test=0;test<m_file.GetCount();test++)
{
if(ftpget.missed[test])
{
m_file.GetText(test,Error);
Error = "The file " + Error;
Error += " is missing!";
AfxMessageBox(Error);
}
}
// close connection
ftpget.CloseConnection();
// quit this function
}
void CHttpDlg::OnAdd() // Add button
{
// TODO: Add your control notification handler code here
CAddFile add;
int ret = add.DoModal();
int lng = 0;
CString newfile;
if(ret == IDOK)
{
// get m_new_file lenght
lng = add.strNewFile.GetLength();
// if OK put in list
if(lng == 0 )// no input
return;
m_file.AddString(add.strNewFile);
}
}
void CHttpDlg::OnDel() // delete button
{
// TODO: Add your control notification handler code here
int selection=0;
selection = m_file.GetCurSel();
// now i get the good one
if(selection <0)
{
AfxMessageBox("You have to select a value in the file list");
return;
}
m_file.DeleteString(selection);
// no more in the dialog
}
void CHttpDlg::OnAnon() // anonymous check button
{
// TODO: Add your control notification handler code here
int check = m_anon.GetCheck();
if(check == 1)
{
// store some info in mem
m_user.GetWindowText(cOldUser,99);
m_pass.GetWindowText(cOldPass,99);
// set new value
m_user.SetWindowText("anonymous");
m_pass.SetWindowText("[email protected]");
m_pass_email.SetWindowText("Your email");
// you can't edit anonymous
m_user.SetReadOnly(TRUE);
}else
{
// set the old value ( if any )
m_user.SetWindowText(cOldUser);
m_pass.SetWindowText(cOldPass);
m_pass_email.SetWindowText("Password");
// you have to edit the user name.
m_user.SetReadOnly(FALSE);
}
}
74.写图像到剪切板 setClipboardImage
CBitmap *pOldBitmap,NewBitmap;
CDC* pt;
pt=CDC::FromHandle(::GetDC(NULL));
NewBitmap.CreateCompatibleBitmap(pt,m_RectCopyCut.Width(),m_RectCopyCut.Height());
CDC dc;
dc.CreateCompatibleDC(NULL);
pOldBitmap=dc.SelectObject(&NewBitmap);
dc.FillRect(m_RectCopyCut, CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH))); dc.BitBlt(0,0,m_RectCopyCut.Width(),m_RectCopyCut.Height(),
&m_dcMemory,m_RectCopyCut.left+m_nHPos,m_RectCopyCut.top +m_nVPos,SRCCOPY); HANDLE handle=DDBToDIB(NewBitmap,BI_RGB,NULL); if(!OpenClipboard())
return;
EmptyClipboard();
SetClipboardData(CF_DIB,handle);
CloseClipboard();
ReleaseDC(pt);
dc.SelectObject(pOldBitmap);
75.从剪贴板复制图像到窗体
76.删除文件夹下的所有文件且不删除文件夹下的文件夹
/////////////////////////////////////////////////////
// char dir[] = "d://test//";
// DeleteAnyFiles(dir);
/////////////////////////////////////////////////////
void DeleteAnyFiles(const char *dir)
{
WIN32_FIND_DATA finder;
HANDLE hFileFind;
char search[MAX_PATH];
strcpy(search, dir);
strcat(search, "*.*");
hFileFind = FindFirstFile(search, &finder);
if (hFileFind != INVALID_HANDLE_VALUE)
{
do
{
char path[MAX_PATH];
strcpy(path, dir);
strcat(path, finder.cFileName);
if (!(finder.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
DeleteFile(path);
} while (FindNextFile(hFileFind, &finder) != 0);
FindClose(hFileFind);
}
}
int nRetCode = 0;
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{
CString strHello;
strHello.LoadString(IDS_HELLO);
cout << (LPCTSTR)strHello << endl;
}
/* 测试目录为d://test//,可以随意改变,但目录分割符必须是// */
char dir[] = "d://test//";
DeleteAnyFiles(dir);
return nRetCode;
77.XML遍历结点属性值
78.拷贝文件名复制文件
#include "stdafx.h"
#include "fdg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{
//判断剪贴板的数据格式是否可以处理
if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
{
return -1;
}
//打开剪贴板
if (!OpenClipboard(NULL))
{
return -1;
}
//获取UNICODE的数据
CString str;
CString path;
HGLOBAL hMem = GetClipboardData(CF_TEXT); //CF_UNICODETEXT
if (hMem != NULL)
{
//获取UNICODE的字符串
LPTSTR lpStr = (LPTSTR)GlobalLock(hMem);
if (lpStr != NULL)
{
//显示输出
OutputDebugString(lpStr);
//释放锁内存
GlobalUnlock(hMem);
}
str=lpStr;
path=lpStr;
}
//关闭剪贴板。
CloseClipboard();
CString pathname="C://"+path.Mid(path.ReverseFind('//')+1);
CopyFile(str,pathname,true);
}
return nRetCode;
}
79.开源程序库Xercesc-C++代码工程中内联
#include "stdafx.h"
#include "InlineXercesc.h"
#include <list>
#include <queue>
#include <string>
#include <boost/regex.hpp>
#include <shlwapi.h>
#pragma comment( lib, "shlwapi.lib")
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CWinApp theApp;
using namespace std;
typedef list<CString, allocator<string> > tagSTRING;
typedef queue<CString, tagSTRING> STRING;
STRING fal,fal2;
CStringArray all;
CString filter = ".cpp";
void doSearch(CString path)
{
if(PathFileExists(path))
{
CFileFind ff;
CString szDir = path;
if(szDir.Right(1) != "//")
szDir += "//";
szDir += "*.*";
BOOL res = ff.FindFile(szDir);
while(res)
{
res = ff.FindNextFile();
if(ff.IsDirectory() && !ff.IsDots())//目录是文件夹
{
//如果是一个子目录,用递归继续往深一层找
doSearch(ff.GetFilePath());//递归调用
}
else if(!ff.IsDots())
{
//显示当前访问的文件
CString strPath = ff.GetFileName();
if (strPath.Find(filter) > 0) {
for (int ifile=0;ifile<all.GetSize();ifile++) {
CString file=all.GetAt(ifile);
if (file.Mid(file.ReverseFind('//') + 1)==strPath) {
fal2.push(ff.GetFilePath());
}
}
}
}
}
ff.Close();//关闭
}
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{
CString lib="xercesc";
CString regex;
regex.Format("include.*?%s.*?>",lib);
boost::regex reg(regex.GetBuffer(0));
boost::smatch m;
CString SourceLib="C://xercesc";
TCHAR szDir[MAX_PATH];
CString szDirPath;
GetCurrentDirectory(MAX_PATH,szDir);
szDirPath.Format("%s//*.*",szDir);
CString CurDir(szDir);
CFileFind finder;
BOOL bWorking = finder.FindFile(szDirPath);
while (bWorking)
{
bWorking = finder.FindNextFile();
if(finder.IsDirectory() && !finder.IsDots()){
CString enumDir = CurDir + "//" + finder.GetFileName() + "//";
//枚举一个文件夹中的所有文件夹
CFileFind finder2;
CString szDirPath2;
szDirPath2.Format("%s//*.*",finder.GetFileName());
BOOL bWorking2 = finder2.FindFile(szDirPath2);
while (bWorking) {
bWorking2 = finder2.FindNextFile();
if(!finder2.IsDirectory() && !finder2.IsDots())
{
CStdioFile f_sfile;
CString lcs_FileName=finder2.GetFilePath();
if(f_sfile.Open(lcs_FileName,CFile::modeRead))
{
//逐行读取
CString sb;
CString lcs_FileContent;
int li_line = 0;
long ll_LineCount = 0;
while(f_sfile.ReadString(lcs_FileContent))
{
li_line++;
//读取第li_line行数据: lcs_FileContent
string s(lcs_FileContent.GetBuffer(0));
string::const_iterator it=s.begin();
string::const_iterator end=s.end();
if(boost::regex_serach(it,end,m,reg) && m[1].matched)
{
//it=m[0].second;
int pos=s.find_last_of("/")+1;
s=s.substr(pos,s.find_first_of(">"));
fal.push(CString(s.c_str()));
sb+="#include /"";
sb+=s.c_str();
sb+="/"";
}
else
sb+=lcs_FileContent;
sb+="/r/n";
}
f_sfile.Close();
CFile mFile(_T(lcs_FileName), CFile::modeWrite);
mFile.Write(sb.GetBuffer(0),sizeof(sb.GetBuffer(0)));
mFile.Flush();
mFile.Close();
f_sfile.Close();
}
}
}
finder2.Close();
while(fal.size()>0)
{
CString file(fal.front());
fal.pop();
CString targetPath= enumDir
+ file.Mid(file.ReverseFind('//') + 1);
if(!PathFileExists(targetPath))
{
CStdioFile f_sfile;
CString lcs_FileName=finder2.GetFilePath();
if(f_sfile.Open(lcs_FileName,CFile::modeRead))
{
CFile mFile(_T(targetPath), CFile::modeCreate|CFile::modeWrite);
CString lcs_FileContent;
int li_line = 0;
long ll_LineCount = 0;
while(f_sfile.ReadString(lcs_FileContent))
{
li_line++;
//读取第li_line行数据: lcs_FileContent
string s(lcs_FileContent.GetBuffer(0));
string::const_iterator it=s.begin();
string::const_iterator end=s.end();
if(boost::regex_serach(it,end,m,reg) && m[1].matched)
{
//it=m[0].second;
int pos=s.find_last_of("/")+1;
s=s.substr(pos,s.find_first_of(">"));
fal.push(CString(s.c_str()));
mFile.Write("#include /"",sizeof("#include /""));
mFile.Write(s.c_str(),sizeof(s.c_str()));
mFile.Write("/"",sizeof("/""));
}
else
mFile.Write(lcs_FileContent,sizeof(lcs_FileContent));
mFile.Write("/r/n",sizeof("/r/n"));
}
mFile.Flush();
mFile.Close();
}
}
}
CFileFind finder3;
bWorking2 = finder3.FindFile(szDirPath2);
while (bWorking) {
bWorking2 = finder3.FindNextFile();
if(!finder3.IsDirectory() && !finder3.IsDots()){
CString path=finder3.GetFilePath();
if(path.Mid(path.ReverseFind('.'))==".hpp")
{
path.Replace(".hpp",".cpp");
all.Add(path);
}
}
}
finder3.Close();
int count = 1;
while (count > 0) {
doSearch(SourceLib);
all.RemoveAll();
while(fal2.size()>0)
{
CString file1 = fal2.front();
CString targetPath = enumDir+ file1.Mid(file1.ReverseFind('//') + 1);
if(!PathFileExists(targetPath))
{
CString lcs_FileName=finder2.GetFilePath()+"//ReadMe.txt";
CStdioFile f_sfile;
if(f_sfile.Open(lcs_FileName,CFile::modeRead))
{
CFile mFile(_T(targetPath), CFile::modeCreate|CFile::modeWrite);
//逐行读取
CString lcs_FileContent;
int li_line = 0;
long ll_LineCount = 0;
while(f_sfile.ReadString(lcs_FileContent))
{
li_line++;
//读取第li_line行数据: lcs_FileContent
string s(lcs_FileContent.GetBuffer(0));
string::const_iterator it=s.begin();
string::const_iterator end=s.end();
if(boost::regex_serach(it,end,m,reg) && m[1].matched)
{
//it=m[0].second;
int pos=s.find_last_of("/")+1;
s=s.substr(pos,s.find_first_of(">"));
fal2.push(CString(s.c_str()));
all(fal2.back().Replace(".hpp",".cpp"));
mFile.Write("#include /"",sizeof("#include /""));
mFile.Write(s.c_str(),sizeof(s.c_str()));
mFile.Write("/"",sizeof("/""));
}
else
mFile.Write(lcs_FileContent,sizeof(lcs_FileContent));
mFile.Write("/r/n",sizeof("/r/n"));
mFile.Flush();
mFile.Close();
}
}
}
}
}
}
}
finder.Close();
}
return nRetCode;
}
80.提取包含头文件列表
#include <boost/regex.hpp>
CString regex;
regex.Format("include.*?%s.*?>",lib);
boost::regex reg(regex.GetBuffer(0));
boost::smatch m;
TCHAR szDir[MAX_PATH];
GetCurrentDirectory(MAX_PATH,szDir);
CString CurDir;
CurDir.Format("%s//*.*",szDir);
CFileFind finder;
BOOL bWorking = finder.FindFile(CurDir);
while(bWorking)
{
bWorking = finder.FindNextFile();
if (finder.IsDirectory() && !finder.IsDots())
{
CString lcs_FileName=finder.GetFilePath()+"//StdAfx.cpp";
CStdioFile f_sfile;
//逐行读取
CString lcs_FileContent;
int li_line = 0;
long ll_LineCount = 0;
while(f_sfile.ReadString(lcs_FileContent))
{
li_line++;
//读取第li_line行数据: string s(lcs_FileContent.GetBuffer(0));
string::const_iterator it=s.begin();
string::const_iterator end=s.end();
if(boost::regex_serach(it,end,m,reg) && m[1].matched)
{
//it=m[0].second;
int pos=s.find_last_of("/")+1;
s=s.substr(pos,s.find_first_of(">"));
fal2.push(CString(s.c_str()));
}
}
CString targetPath = finder.GetFilePath()+"//ReadMe.txt";
CFile mFile(_T(targetPath),CFile::modeCreate|CFile::modeWrite);
mFile.Write("#include /"",sizeof("#include /""));
mFile.Write(s.c_str(),sizeof(s.c_str()));
mFile.Write("/"",sizeof("/""));
mFile.Write("/r/n",sizeof("/r/n"));
mFile.Flush();
mFile.Close();
}
81.剪贴扳转换成打印字符
#include "stdafx.h"
#include "%%0.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{
//判断剪贴板的数据格式是否可以处理
if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
{
return 0;
}
//打开剪贴板
if (!OpenClipboard(NULL))
{
return 0;
}
//获取UNICODE的数据
CString s;
HGLOBAL hMem = GetClipboardData(CF_TEXT);
if (hMem != NULL)
{
//获取UNICODE的字符串
LPTSTR lpStr = (LPTSTR)GlobalLock(hMem);
if (lpStr != NULL)
{
//显示输出
OutputDebugString(lpStr);
//释放锁内存
GlobalUnlock(hMem);
}
s=lpStr;
CString sub;
CString sb;
int pos;
char seperator = '/n';
for (pos = 0; AfxExtractSubString(sub, s, pos, seperator); ++pos)
{
if(sub.Trim()!="")
{
sub.Replace("^", "^^");
sub.Replace("&", "^&");
sub.Replace(":", "^:");
sub.Replace(">", "^>");
sub.Replace("<", "^<");
sub.Replace("|", "^|");
sub.Replace("/"", "^/"");
sub.Replace("//", "////");
sub.Replace("/"", "///"");
sb+=("w.WriteLine(/"ECHO " +sub + "/");/r/n");
}
}
char *pMem;
hMem = GlobalAlloc( GHND | GMEM_DDESHARE, strlen(sb)+1);
if(hMem)
{
pMem = (char*)GlobalLock(hMem);
strcpy(pMem,sb);
GlobalUnlock(hMem);
EmptyClipboard();
SetClipboardData(CF_TEXT,hMem);
}
CloseClipboard();
}
}
return nRetCode;
}
82.把JButton或JTree组件写到一个流中
83.注册全局热键
/*
BOOL RegisterHotKey(
HWND hWnd . //指定接收WM_HOTKEY消息的窗体句柄
int id. //热键标识.同一调用线程内的不同热键标识不能相同.应用程序中的标识值在0x0000和0xbfff之间.DLL中的在0xc000和0xffff之间
UINT fsModifiers.//下列值的组合:MOD_ALT.MOD_CONTROL.MOD_SHIFT.MOD_WIN.MOD_KEYUP
UINT vk //按键的虚拟码
),
*/
//在初始化的时候注册:
RegisterHotKey(m_hWnd.1688.MOD_SHIFT|MOD_CONTROL
84.菜单勾选/取消完成后关闭计算机
//使此进程获取:关机权限
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tp;
//获取此进程的令牌
::OpenProcessToken(::GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken);
//查询权限值:获取权限的唯一标识值
::LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
//调整令牌权限
::AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL);
::ExitWindowsEx(EWX_SHUTDOWN,0);
85.菜单勾选/取消完成后重新启动计算机
//使此进程获取:关机权限
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tp;
//获取此进程的令牌
::OpenProcessToken(::GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken);
//查询权限值:获取权限的唯一标识值
::LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
//调整令牌权限
::AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL);
::ExitWindowsEx(EWX_REBOOT,0);
86.菜单勾选/取消完成后注销计算机
//使此进程获取:关机权限
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tp;
//获取此进程的令牌
::OpenProcessToken(::GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken);
//查询权限值:获取权限的唯一标识值
::LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
//调整令牌权限
::AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL);
::ExitWindowsEx(EWX_LOGOFF,0);
87.菜单勾选/取消开机自启动程序
::OnSetMusic()
{
// TODO: Add your command handler code here
/*CMenu *menu1,*menu2;
menu2=menu1.GetSubMenu(1);
menu2.GetMenuItemID(3); */
if(GetCheck()==FALSE)
{
SetCheck();
sndPlaySound("D://oscillograph//res//天路(钢琴伴奏)裁.wav",SND_LOOP);
}
else
{
sndPlaySound("D://oscillograph//res//天路(钢琴伴奏)裁.wav",NULL);
}
}
/////////////////////////////////////////////////////////////////////
TCHAR m_fileName[100];
GetModuleFileName(NULL,m_fileName,100);
HKEY hKey;
CString str = _T("Software//Microsoft//Windows//CurrentVersion//Run");
if (ERROR_SUCCESS != RegCreateKey(HKEY_LOCAL_MACHINE, str, &hKey))
{
AfxMessageBox("打开注册表项失败");
RegCloseKey(hKey);
return;
}
int length = 0;
while(m_fileName[length]!=_T('/0'))
length++;
if (ERROR_SUCCESS != RegSetValueEx(hKey, _T(%%1), 0, REG_SZ, (const BYTE *)m_fileName, sizeof(TCHAR)*length))
{
AfxMessageBox("写注册表失败");
}
RegCloseKey(hKey);
88.菜单勾选/取消自动登录系统
89.模拟键盘输入字符串
CString str=%%1;
DWORD sc,shift;
unsigned char vkey;
char a;
for (int i=0;i<str.GetLength();i++)
{
a=str.GetAt(i);
sc=OemKeyScan(a);
shift=sc>>16;
vkey=MapVirtualKey(sc&0xffff,1);
if (shift)
keybd_event(VK_SHIFT,0,0,0);
keybd_event(vkey,0,0,0);
keybd_event(vkey,0,KEYEVENTF_KEYUP,0);
if (shift)
keybd_event(VK_SHIFT,0,KEYEVENTF_KEYUP,0);
}
90.提取PDF文件中的文本
try
{
int iFont;
PDFlib pPDF;
CFileDialog m_FileDlg(FALSE,"pdf","",OFN_OVERWRITEPROMPT,"Adobe Acrobat PDF 文件(*.pdf)|*.pdf|所有文件(*.*)|*.*||",this);
char pFileName[255];
CEdit* pPDFText=(CEdit*)GetDlgItem(IDC_EDITPDF);
CString strPDFText;
pPDFText->GetWindowText(strPDFText);
char pPDFInfo[1024];
sprintf(pPDFInfo,"%s",strPDFText);
char pAttachFileName[255];
sprintf(pAttachFileName,"%s",m_AttachFileName);
if(m_FileDlg.DoModal()==IDOK)
{
m_PDFFileName=m_FileDlg.GetFileName();
sprintf(pFileName,m_PDFFileName);
if(pPDF.open_file(pFileName)==-1)
{
//
}
pPDF.set_parameter("hypertextencoding","host");
pPDF.set_info("Creator","DigitalSky");
pPDF.set_info("Author","DigitalTitan");
pPDF.set_info("Title","Title");
pPDF.begin_page((float)a4_width,(float)a4_height);
iFont=pPDF.load_font("Helvetica-Bold","host","");
pPDF.setfont(iFont,12);
pPDF.set_text_pos(50,a4_height-50);
pPDF.setcolor("fill","rgb",0,0,1,0);
pPDF.show("Version 1.0 (C) CopyRight By Digitaltitan");
iFont=pPDF.findfont("STSong-Light","GB-EUC-H",0);
pPDF.setcolor("fill","rgb",0,0,0,0);
pPDF.setfont(iFont,24);
pPDF.continue_text("转换文档生成为");
pPDF.setcolor("stroke","rgb",0.24f,0.51f,0.047f,0);
pPDF.moveto(50,a4_height-80);
pPDF.lineto(a4_width-50,a4_height-80);
pPDF.moveto(50,a4_height-78);
pPDF.lineto(a4_width-50,a4_height-78);
pPDF.stroke();
pPDF.attach_file(a4_width-50,0,0,a4_height-90,pAttachFileName,"DigitalSky","DigitalTitan","doc","paperclip");
pPDF.set_text_pos(50,a4_height-100);
iFont=pPDF.findfont("STSong-Light","GB-EUC-H",0);
pPDF.setcolor("fill","rgb",0,0,0,0);
pPDF.setfont(iFont,12);
pPDF.continue_text(pPDFInfo);
//Word文件如何导入?
pPDF.end_page();
pPDF.close();
}
}
catch(PDFlib::Exception &ex)
{
//
}
下载免费开发包http://partners.adobe.com/asn/acrobat/sdk/fdftk/FDFToolkitForWindows.zip
PDF SDK有一个例子--AddImage,该例子生产一个dll,放在Acrobat的安装目录下,然后启动Acrobat,就看到多了一个菜单项“AddImage”,就可以调用AddImage了。我的问题是:如何不生成dll给Acrobat调用,而是直接运行AddImage的功能?
91.操作内存映射文件
91.1发送内存映射数据
HANDLE hFileMapping;
LPSTR pData;
hFileMapping=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,0x100,%%1); //"MyShare"
if(hFileMapping==NULL)
{
//文件映射至内存失败!
return -1;
}
pData=(LPSTR)MapViewOfFile(hFileMapping,FILE_MAP_ALL_ACCESS,0,0,0);
if(pData==NULL)
{
//文件试镜像到进程地址空间失败!
return -1;
}
sprintf(pData,%%2);
UnmapViewOfFile(pData);
91.2接收内存映射数据
HANDLE hFileMapping;
LPSTR pData;
hFileMapping=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,0x100,%%1); //"MyShare"
if(hFileMapping==NULL)
{
//文件映射至内存失败!
return -1;
}
pData=(LPSTR)MapViewOfFile(hFileMapping,FILE_MAP_ALL_ACCESS,0,0,0);
if(pData==NULL)
{
//文件试镜像到进程地址空间失败!
return -1;
}
CString %%2;
%%2.Format("%s",pData);
UnmapViewOfFile(pData);
92.重定向windows控制台程序的输出信息
STARTUPINFO si;
PROCESS_INFOMATION pi;
SECURITY_ATTRIBUTES sa;
HANDLE hRead_OutPipe,hWrite_OutPipe,hRead_InPipe,hWrite_InPipe;
sa.mLength=sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor=NULL;
sa.bInheritHandle=TRUE;
ZeroMemory(&pi,sizeof(pi));
ZeroMemory(&si,sizeof(si));
GetStartipInfo(&si);
si.cb=sizeof(si);
si.dwFlags=STARTF_USESTDHANDLES|STARTF_USERSHOWWINDOW;
si.hStdOutput=hWrite_OutPipe;
si.hStdError=hWrite_OutPipe;
si.hStdInput=hWrite_InPipe;
si.wShowWindow=SW_HIDE;
if(!CreateProcess(NULL,%%1,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi)) {
//创建进程失败
return -1;
}
if(!CreateProcess(&hRead_OutPipe,&hWrite_OutPipe,&sa,0)) {
//创建进程失败
return -1;
}
if(!CreateProcess(&hRead_InPipe,&hWrite_InPipe,&sa,0)) {
//创建进程失败
return -1;
}
si.hStdOutput=hWrite_OutPipe;
si.hStdError=hWrite_OutPipe;
si.hStdInput=hWrite_InPipe;
char buf[4096];
DWORD readlen=0;
CString %%2;
%%2+="/r/n";
DWORD dwWritten=0;
WriteFile(hWrite_InPipe,%%2,%%2.GetLength(),&dwWritten,0);
CString %%3;
BOOL read_ret=TRUE;
while(read_ret=TRUE)
{
memset(buf,'/0',sizeof(buf));
read_ret=ReadFile(hRead_OutPipe,buf,sizeof(buf),&readlen,NULL);
CString buffer(buf);
%%3+=buffer;
}
93.接受邮件
用Visual C++编写电子邮件程序
94.发送邮件
一、概述
---- 本文主要讲述如何使用Visual C++用MAPI编写E-mail程序。MAPI是包含在
Windows之中的,因此不需要安装其他额外的部件。MAPI有以下三种形式:
SMAPI,Simple MAPI,简单的MAPI
CMC,Common Messaging Calls,一般通讯调用
完整的MAPI
---- SMAPI和CMC都包含在完整的MAPI中,当用户想执行一些高级操作,比如
编写自己的E-mail服务器的时候,必须使用完整的MAPI。本文主要阐述如何编
写能够收发电子邮件的程序,因此使用SMAPI就足够了。
二、编写电子邮件程序
3-1 初始化MAPI
---- 要使用MAPI,必须首先对它进行初始化。初始化包括以下三个步骤:
装载MAPI32.DLL动态链接库
找到想要调用的MAPI函数地址
登录到电子邮件对象
3-1-1 装载MAPI32.DLL
---- 要装载MAPI,用户必须程序运行时动态的装载一个动态链接库。LoadLibrary
函数提供了此功能,它定位一个动态链接库,并返回HINSTANCE局柄(需要保存该句柄)。
LoadLibrary的语法如下:
LoadLibrary ( lpLibFileName );
其中lpLibFileName为LPCTSTR结构变量,
是所要调用的库的路径和名称。
程序示例:
// 调用MAPI32.DLL并计算函数地址
HINSTANCE hInstMail;
hInstMail = ::LoadLibrary ( “MAPI32.DLL” );
if ( hInstMail == NULL )
{
// 错误处理
// 受篇幅限制,下面的错误处理部分省略
}
3-1-2 确定函数地址
---- 由于MAPI32.DLL是被动态装载的,因此不知道所要调用的函数地址,
也就不能一开始就调用它们,而要通过函数名获得函数的地址,并在动态链
接库中查找每一个函数并核实。因此首先必须为这些函数声明指针
程序示例:
// 为MAPI32.DLL中的函数声明函数指针
ULONG (PASCAL *lpfnMAPISendMail) (LHANDLE lhSession,
ULONG ulUIParam, lpMapiMessage lpMessage,
FLAGS flFlags, ULONG ulReserved);
ULONG (PASCAL *lpfnMAPIResolveName) (LHANDLE lhSession,
ULONG ulUIParam, LPTSTR lpszName,
FLAGS ulFlags, ULONG ulReserved,
lpMapiRecipDesc FAR *lppRecip);
ULONG (FAR PASCAL *lpfnMAPILogon)(ULONG ulUIParam,
LPSTR lpszProfileName, LPSTR lpszPassword,
FLAGS flFlags, ULONG ulReserved,
LPLHANDLE lplhSession);
ULONG (FAR PASCAL *lpfnMAPILogoff)(LHANDLE lhSession,
ULONG ulUIParam, FLAGS flFlags,
ULONG ulReserved);
ULONG (FAR PASCAL *lpfnMAPIFreeBuffer)(LPVOID lpBuffer);
ULONG (FAR PASCAL *lpfnMAPIAddress)(LHANDLE lhSession,
ULONG ulUIParam, LPSTR lpszCaption,
ULONG nEditFields, LPSTR lpszLabels,
ULONG nRecips, lpMapiRecipDesc lpRecips,
FLAGS flFlags, ULONG ulReserved,
LPULONG lpnNewRecips,
lpMapiRecipDesc FAR *lppNewRecips);
ULONG (FAR PASCAL *lpfnMAPIFindNext)(LHANDLE lhSession,
ULONG ulUIParam, LPSTR lpszMessageType,
LPSTR lpszSeedMessageID, FLAGS flFlags,
ULONG ulReserved, LPSTR lpszMessageID);
ULONG (FAR PASCAL *lpfnMAPIReadMail)(LHANDLE lhSession,
ULONG ulUIParam, LPSTR lpszMessageID,
FLAGS flFlags, ULONG ulReserved,
lpMapiMessage FAR *lppMessage);
---- 为了决定每一个函数的地址,必须为每一个函数调用GetProcAddress。
GetProcAddress的语法为:
GetProcAddress (hModule, lpProcName);
其中,hModule为HMODULE结构,是所调用DLL模块的句柄;
lpProcName为LPCSTR结构,是函数名称。
程序示例:
// 找到MAPI32.DLL函数的地址,并将它们保存在函数指针变量里
(FARPROC&) lpfnMAPISendMail = GetProcAddress(hInstMail,
“MAPISendMail”);
(FARPROC&) lpfnMAPIResolveName = GetProcAddress(
hInstMail, “MAPIResolveName”);
(FARPROC&) lpfnMAPILogon = GetProcAddress(hInstMail,
“MAPILogon”);
(FARPROC&) lpfnMAPILogoff = GetProcAddress(hInstMail,
“MAPILogoff”);
(FARPROC&) lpfnMAPIFreeBuffer = GetProcAddress(
hInstMail, “MAPIFreeBuffer”);
(FARPROC&) lpfnMAPIAddress = GetProcAddress(hInstMail,
“MAPIAddress”);
(FARPROC&) lpfnMAPIFindNext = GetProcAddress(hInstMail,
“MAPIFindNext”);
(FARPROC&) lpfnMAPIReadMail = GetProcAddress(hInstMail,
“MAPIReadMail”);
3-1-3 登录到电子邮件对象
---- 用户必须在电子邮件系统中登录,才能实现MAPI的各种功能。MAPI提供了登录的三种选择:
登录到一个已经存在的对象。
登录到一个新对象,用编程的方法确定解释新信息。
使用对话框提示用户登录。
---- 我们通常选择登录到一个已经存在的电子邮件对象,因为网络合作用户通
常会保持自己的电子邮件程序处于激活状态。登录通常使用MAPI提供的函数
lpfnMAPILogon。
lpfnMAPILogon的语法为:
lpfnMAPILogon (lpszProfileName, lpszPassword, flFlags,
ulReserved, lplhSession );
---- 其中,lpszProfileName指向一个256字符以内的登录名称,lpszPassword
指向密码,它们均为LPTSTR结构。flFlags为FLAGS结构,其值详见表1。ulReserved
必须为0。lplhSession为输出SMAPI的句柄。
表1:lpfnMAPILogon函数中flFlags的值
值 意义
MAPI_FORCE_DOWNLOAD
在函数调用返回之前下载用户的所有邮件。
如果MAPI_FORCE_DOWNLOAD没有被设置,
那么信件能够在函数调用返回后在后台被下载。
MAPI_NEW_SESSION 建立一个新会话,
而不是获得环境的共享会话。如果MAPI_NEW_SESSION没有被设置,
MAPILogon使用现有的共享会话。
MAPI_LOGON_UI 显示一个登录对话框来提示用户输入登录信息。
例如Outlook检查用户电子邮件时便是如此。
MAPI_PASSWORD_UI MAPILogon只允许用户输入电子邮件的密码,
而不许改动账号。
程序示例:
LHANDLE lhSession;
ULONG lResult = lpfnMAPILogon(0, NULL, NULL, 0, 0,
&lhSession);
if (lResult != SUCCESS_SUCCESS)
//SUCCESS_SUCCESS在MAPI.H中被定义
{
// 错误处理
}
3-2 阅读电子邮件
---- MAPIFindNext和MAPIReadMail使用与阅读E-mail的两个基本函数。
MAPIFindNext用于定位第一封或下一封电子邮件并返回标识号,MAPIReadMail返回
以该标识号为基础的电子邮件的内容。另外,一个常用的函数是MAPIFreeBuffer,
用于释放内存。
3-2-1 定位到第一封信
---- 要找到第一封信,需要使用MAPIFindNext函数,其函数声明如下:
ULONG FAR PASCAL MAPIFindNext(LHANDLE lhSession,
ULONG ulUIParam, LPTSTR lpszMessageType,
LPTSTR lpszSeedMessageID, FLAGS flFlags,
ULONG ulReserved, LPTSTR lpszMessageID )
---- 其中,lhSession为提交SMAPI的会话句柄 ;ulUIParam为父窗体的句柄;
lpszMessageType指向一个字符串,用来鉴别邮件类型,并加以查找;
lpszSeedMessageID为指向起始信息ID的指针,其值为0时,
MAPIFindNext获得第一封电子邮件;flFlags的值见表2;ulReserved必须为0;
lpszMessageID为输出值,它是指向信息ID地址的指针。
---- 表2:MAPIFindNext函数中flFlags的值
值 意义
MAPI_GUARANTEE_FIFO 按邮件发送的时间顺序接受电子邮件。
MAPI_LONG_MSGID 返回信件标识符可达512字符。
MAPI_UNREAD_ONLY 只列举没有阅读过的电子邮件。
程序示例:
// 找到第一条没有阅读的电子邮件
char pMessageID [513];
ULONG lResult = lpfnMAPIFindNext(lhSession, NULL, NULL,
NULL, MAPI_LONG_MSGID | MAPI_UNREAD_ONLY,
0, pMessageID);
3-2-2 阅读信息
当信件ID被获取后,就可以调用MAPIReadMail
阅读实际的E-mail信息了。MAPIReadMail的函数声明如下:
ULONG FAR PASCAL MAPIReadMail(LHANDLE lhSession,
ULONG ulUIParam, LPTSTR lpszMessageID,
FLAGS flFlags, ULONG ulReserved,
lpMapiMessage FAR * lppMessage);
其中,lppMessage为指向MapiMessage的指针;
除flFlags外的其他参数与lpfnFindNext函数的同名参数意义相同,
flFlags参数的值见表3:
表3:MAPIReadMail函数中flFlags的值:
值 意义
MAPI_BODY_AS_FILE 将邮件信息写到一个临时文件中,
并且将它作为第一个附件添加到附件列表中。
MAPI_ENVELOPE_ONLY 只读取邮件标题。
MAPI_PEEK 读完邮件之后不把它标记为“已读”。
MAPI_SUPPRESS_ATTACH MAPIReadMail函数不拷贝附件,
但是将邮件文本写入MapiMessage结构中。
程序示例:
// 读取电子邮件
long nFlags = MAPI_SUPPRESS_ATTACH;
if (!bMarkAsRead)
nFlags = nFlags | MAPI_PEEK;
lResult = lpfnMAPIReadMail(lhSession, NULL, pMessageID,
nFlags, 0, &pMessage);
if (lResult != SUCCESS_SUCCESS);
return false;
如果调用成功,就可以访问MapiMessage结构了(使用pMessage):
pMessage- >ulReserved:0
pMessage- >lpszSubject:邮件标题
pMessage- >lpszNoteText:邮件信息
pMessage- >lpszMessageType:邮件类型
pMessage- >DateReceived:接收时间
pMessage- >lpszConversationID:邮件所属的会话线程ID
pMessage- >flFlags:其值见表4
表4:MapiMessage结构中的flFlags
值 意义
MAPI_RECEIPT_REQUESTED 接收通知被申请。
客户端应用程序在发送消息时设置该项。
MAPI_SENT 邮件已被发送。
MAPI_UNREAD 邮件是“未读”状态。
pMessage- >lpOriginator:指向MapiRecipDesc结构,包含发件人信息。
pMessage- >nRecipCount:信件者数目。
pMessage- >lpRecips:指向MapiRecipDesc结构数组,包含接收者信息。
pMessage- >nFileCount:附件数量。
pMessage- >lpFiles:指向MapiFileDesc结构数组,
每一个结构包含一个文件附件。
3-2-3 释放内存
---- 在访问另一条信件以前应当释放内存,否则会出现内存泄漏。
程序示例:
// 释放内存
lpfnMAPIFreeBuffer(pMessage);
3-2-4 定位到下一条信件
定位到下一条信件依然使用MAPIFindNext函数,
该函数声明及参数意义详见3-2-1节。下面示范如何定位到下一条信件。
程序示例:
// 定位到下一条没有阅读的信件
ULONG lResult = lpfnMAPIFindNext(lhSession, NULL, NULL,
pMessageID, MAPI_LONG_MSGID|MAPI_UNREAD_ONLY,
0, pMessageID);
3-3 发送电子邮件
---- 发送电子邮件的一般步骤:
---- 1. 建立MapiMessage结构对象
---- 2. 调用MAPIResolveName使发送者名称合法
---- 3. 添加附件
---- 4. 调用MAPISendMail发送电子邮件
---- 5. 调用MAPIFreeBuffer释放内存
---- 下面详细分别详细阐述。
3-3-1 建立MapiMessage结构对象
---- 对于MapiMessage结构,3-2-2节已经做过介绍,下面一步步介绍如何设置其中的值:
---- 1. 为MapiMessage对象分配内存:
MapiMessage message;
Memset(&message, 0, sizeof(message));
---- 2. 将ulReserved设置为0:
message.ulReserved = 0;
---- 3. 设置信息类型指针lpszMessageType,可以为NULL:
message.lpszMessageType = NULL;
---- 4. 设置信件标题(lpszSubject):
char subject[512];
strcpy(subject, sSubject);
message.lpszSubject = subject;
---- 5. 设置信件内容:
char text[5000];
strcpy(text, sMessage);
message.lpszNoteText = text;
---- 6. 设置flFlags标识,详见3-2-2节中表4:
message.flFlags = MAPI_SENT;
---- 7. 用一个指向MapiRecipDesc结构的指针设置发送者信息(lpOriginator),
或将其设置为NULL:
message.lpOriginator = NULL;
---- 8. 设置接收者数目(nRecipCount),可以是1或更多:
message.nRecipCount = 1;
---- 9. 设置接收者信息(lpRecips),详见3-3-2节
---- 10. 设置附件数量(nFileCount)
---- 11. 设置附件信息,详见3-3-3节
b3-3-2 正确设置接收者信息
---- 设置接收者信息时,应当使用MAPIResolveName函数来为MapiRecipDesc结构
对象分配内存,并返回一个指针,该指针将被保存在MapiMessage结构的lpRecips中。
MAPIResolveName的函数声明如下:
ULONG FAR PASCAL MAPIResolveName(LHANDLE lhSession,
ULONG ulUIParam, LPTSTR lpszName,
FLAGS flFlags, ULONG ulReserved,
lpMapiRecipDesc FAR * lppRecip )
---- 其中lppRecip即为前面提到的返回的指针。除flFlags外其余参数与前几个
函数意义相同。flFlags的值详见表5。
表5:MAPIResolveName中flFlags的值
值 意义
MAPI_AB_NOMODIFY 对话框为只读。如果MAPI_DIALOG被设置,
那么该项将被忽略。
MAPI_DIALOG 显示一个名称解决方案的对话框
MAPI_LOGON_UI 如果需要的话,将会显示仪个对话框让用户登录
MAPI_NEW_SESSION 新建一个会话
程序示例:
char recipient[512];
strcpy(recipient, sTo);
lResult = lpfnMAPIResolveName(lhSession, 0, recipient,
0, 0, &message.lpRecips);
3-3-3 添加附件
---- 下面的程序示例将演示如何在电子邮件中包含附件。只有一点需要说明:
MapiFileDesc结构中flFlags的值,详见表6。
表6:MapiFileDesc结构中flFlags的值
值 意义
MAPI_OLE 附件是OLE对象。
MAPI_OLE_STATIC 附件是静态OLE对象。
0 附件将被视为数据文件
程序示例:
// 设置附件信息
CString sPath, sFileName;
MapiFileDesc FileInfo;
char path[512];
char filename[512];
if (sAttachment == “”)
message.nFileCount = 0;
else
{
int nPos = sAttachment.ReverseFind(‘//’);
if (nPos == -1)
{
sPath = sAttachment;
}
else
{
sPath = sAttachment;
sFilename = sAttachment.Mid(nPos +1);
}
strcpy(path, sPath);
strcpy(filename, sFilename);
message.nFileCount = 1;
FileInfo.ulReserved = 0;
FileInfo.flFlags = 0;
FileInfo.nPosition = sMessage.GetLength() –1;
FileInfo.lpszPathName = path;
FileInfo.lpszFileName = filename;
FileInfo.lpFileType = NULL;
message.lpFiles = & m_FileInfo;
}
3-3-4 发送电子邮件
---- 使用MAPISendMail发送电子邮件,其声明如下:
ULONG FAR PASCAL MAPISendMail (LHANDLE lhSession,
ULONG ulUIParam, lpMapiMessage lpMessage,
FLAGS flFlags, ULONG ulReserved )
---- 其中,flFlags的允许值为MAPI_DIALOG、MAPI_LOGON_UI和MAPI_NEW_SESSION,
其意义与前几个函数中同名标识意义相同。
程序示例:
lResult = lpfnMAPISendMail(0, 0, &m_message, 0, 0);
3-3-5 释放内存
程序示例:
lpfnMAPIFreeBuffer(m_message.lpRecips);
四、小结
---- 本文比较具体的介绍并演示了编写一个电子邮件程序的核心部分,如果读者
要编写电子邮件程序,还需要进行的处理:
---- 1. 加上错误处理代码。受篇幅限制,本文的程序示例中只有两处为错误
处理留空,比较它们的异同。电子邮件程序是非常容易出错的,因此除这两处外要
在主要函数调用完成后都加上错误处理,或使用try throw catch块处理例外。
---- 2. 加上UI处理。
---- 另外,本文所阐述的方法比较简单易行,事实上,有关电子邮件的程序远比
这复杂得多,因此读者若需要编写一个功能强大的电子邮件程序,需要精通MAPI和
SMTP/POP3等协议;如果读者要编写一个电子邮件服务器,那么不妨在精通MAPI和
SMTP/POP3之后,阅读一些有关Exchange Server的资料。
95.报表相关
一、准备工作
(1)安装Crystal Report软件
Crystal Report 4.6是一个免费的报表工具,可以在VB5或WINDOWS NT 4.0 BackOffice等光盘上找到,Crystal report4.6中包含了报表设计工具与报表打印控件。程序的发行只需要安装打印控件相关部分即可。
(2)设计报表
我们生成一个名为sample.rpt的报表,这一过程可以参考 Crystal report自带的帮助文档,本文不作详细介绍。
二、创建VC工程添加报表控件
在VC集成环境中用AppWizard新建一个MFC单文档工程,其余选项都为默认。菜单中选择Project->Add To Project->Components and Controls...弹出组件、控件选择对话框,进入Registered ActiveX Controls,选中Crystal Report Control 4.6 ,单击Insert按钮,确认后进入类配置对话框,按默认即可。关闭控件选择对话框完成控件的添加。
三、实现报表的显示与打印
下面我们将在对话框中演示控件的静态创建过程,在主视图中演示控件的动态创建过程。
3.1在对话框中打印出报表
在资源编辑器中打开ID为IDD_ABOUTBOX的对话框模板,在Controls工具条中我们可以找到刚加入到工程中的Crystal Report Control 4.6控件按钮,把它插入到对话框合适的位置处。
右键单击对话框中的控件,选择属性,此时可以设置控件的许多属性。我们在Control选项页ReportFileName中输入报表文件名sample.rpt(可以加上完整路径),在Print Window选项页中设置控件的合适位置,回到对话框模板中按住Ctrl键,双击鼠标左键,弹出Add Member Variable对话框,我们将成员变量命名为m_CrystalReport,打开ClassWizard,为CAboutDlg对话框添加WM_INITDIALOG消息的处理函数:BOOL OnInitDialog(),并在函数中做如下处理
BOOL CAboutDlg::OnInitDialog()
{
CDialog::OnInitDialog();
/////此行设置控件的父窗口,你也可以去掉该行看看运行效果/////////
m_CrystalReport.SetWindowParentHandle((long)(this->m_hWnd));
/////打印报表到窗口中/////
m_CrystalReport.PrintReport();
return TRUE;
}
至此,程序的第一部分编写完成,编译运行,打开About对话框看看效果吧!
假如您并没有显示出报表,有如下可能原因:
(1)控件没有放置在合适的位置或尺寸不对。
(2)报表文件本身存在诸如数据源不可用等错误。
控件窗口中的工具条提供了缩放、打印等功能,您也可以试试在打印机上打印出来的效果。
3.2 在程序主视窗中显示报表
打开ClassWizard增加对ID_FILE_OPEN和ID_FILE_PRINT的处理函数,代码如下
void CMyReportView::OnFileOpen()
{
char Filter[] = "Crystal Report files(*.rpt)|*.rpt|All files(*.*)|*.*||";
CRect rect;
CFileDialog OpenDlg(TRUE,0,0,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,(LPCTSTR)Filter,NULL);
if(OpenDlg.DoModal()!=IDOK) ///显示文件对话框
return;
CString m_fName=OpenDlg.GetPathName(); ///取得文件名
if(m_CrystalReport)
m_CrystalReport.DestroyWindow();
GetClientRect(rect);
///////////////////创建控件///////////////
if (!m_CrystalReport.Create(AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)),WS_CHILD|
_ WS_VISIBLE,rect,this,IDC_CRYSTALREPORT1))
{
AfxMessageBox("控件创建失败!");
return ;
}
m_CrystalReport.SetWindowParentHandle((long)(this->m_hWnd));///设置父窗口
m_CrystalReport.SetWindowBorderStyle(0); ///设置为没有边框
m_CrystalReport.SetWindowLeft(0); ///左空间
m_CrystalReport.SetWindowTop(0); ///顶部空间
m_CrystalReport.SetWindowControls(FALSE); ///不显示工具条
m_CrystalReport.SetReportFileName(m_fName); ///设置报表文件
m_CrystalReport.SetWindowWidth(rect.Width()); ///设置窗口宽度
m_CrystalReport.SetWindowHeight(rect.Height()); ///设置窗口高度
m_CrystalReport.SetFormulas(0, "Company=/"VC知识库/"");
///将报表中的Company变量的值设置为VC知识库
m_CrystalReport.SetDestination(0); ///设置输出对象是屏幕
m_CrystalReport.PrintReport(); ///显示报表
}
void CMyReportView::OnFilePrint()
{
if(m_CrystalReport && m_CrystalReport.GetReportFileName() != "")
{
m_CrystalReport.SetDestination(1); ///设置输出对象是打印机
m_CrystalReport.PrintReport(); ///打印
}
}
后记:我们利用Crystal Report 4.6在VC++环境下实现了报表处理,但Crystal Report 4.6报表控件的功能及可控性能可能无法满足您的要求,Seagate公司此款软件的最新版本是Crystal Report 8.0,各方面表现都非常出色,但此款软件的免费版本并不包括报表设计器,可喜的是8.0中的报表显示控件兼容以前版本的报表格式,所以笔者建议用4.6版本来设计报表,依靠8.0中的报表显示控件来显示、打印。
96.全屏幕截取
CBitmap* m_pBackBitmap;
/*******************************
* 拷贝屏幕固定区域
* 参数:
* xStartPt - 拷贝屏幕的起始点X坐标
* yStartPt - 拷贝屏幕的起始点Y坐标
* width - 拷贝宽度
* height - 拷贝高度
* xToCopy - 拷贝目的地的起始点X坐标
* yToCopy - 拷贝目的地的起始点Y坐标
*******************************/
void CopyScreenToBitmap(xStartPt, yStartPt, width, height, xToCopy, yToCopy)
{
//NEW资源(调用一次重新拷贝一次)
if (m_pBackBitmap != NULL)
{
delete m_pBackBitmap;
m_pBackBitmap = NULL;
}
m_pBackBitmap = new CBitmap();
CDC ScrDC,MemDC;
ScrDC.CreateDC("DISPLAY", NULL, NULL, NULL);
MemDC.CreateCompatibleDC(&ScrDC);
m_pBackBitmap->CreateCompatibleBitmap(&ScrDC,width,height);
MemDC.SelectObject(m_pBackBitmap);
//开始拷贝
MemDC.BitBlt(xStartPt, yStartPt, width, height,&ScrDC,xToCopy,yToCopy,SRCCOPY);
ScrDC.DeleteDC();
MemDC.DeleteDC();
}
//取的屏幕分辨率
int width = ::GetSystemMetrics(SM_CXSCREEN);
int height = ::GetSystemMetrics(SM_CYSCREEN);
this->CopyScreenToBitmap(0,0,width,height,0,0);
//这时m_pBackBitmap指向的CBitmap对象就存着全屏的图象了
97.区域截幕
HBITMAP CopyScreenToBitmap(LPRECT lpRect)
//lpRect 代表选定区域
{
HDC hScrDC, hMemDC;
// 屏幕和内存设备描述表
HBITMAP hBitmap, hOldBitmap;
// 位图句柄
int nX, nY, nX2, nY2;
// 选定区域坐标
int nWidth, nHeight;
// 位图宽度和高度
int xScrn, yScrn;
// 屏幕分辨率
// 确保选定区域不为空矩形
if (IsRectEmpty(lpRect))
return NULL;
//为屏幕创建设备描述表
hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);
//为屏幕设备描述表创建兼容的内存设备描述表
hMemDC = CreateCompatibleDC(hScrDC);
// 获得选定区域坐标
nX = lpRect- >left;
nY = lpRect- >top;
nX2 = lpRect- >right;
nY2 = lpRect- >bottom;
// 获得屏幕分辨率
xScrn = GetDeviceCaps(hScrDC, HORZRES);
yScrn = GetDeviceCaps(hScrDC, VERTRES);
//确保选定区域是可见的
if (nX 〈0)
nX = 0;
if (nY 〈 0)
nY = 0;
if (nX2 > xScrn)
nX2 = xScrn;
if (nY2 > yScrn)
nY2 = yScrn;
nWidth = nX2 - nX;
nHeight = nY2 - nY;
// 创建一个与屏幕设备描述表兼容的位图
hBitmap = CreateCompatibleBitmap
(hScrDC, nWidth, nHeight);
// 把新位图选到内存设备描述表中
hOldBitmap = SelectObject(hMemDC, hBitmap);
// 把屏幕设备描述表拷贝到内存设备描述表中
BitBlt(hMemDC, 0, 0, nWidth, nHeight,
hScrDC, nX, nY, SRCCOPY);
//得到屏幕位图的句柄
hBitmap = SelectObject(hMemDC, hOldBitmap);
//清除
DeleteDC(hScrDC);
DeleteDC(hMemDC);
// 返回位图句柄
return hBitmap;
}
得到屏幕位图句柄以后,我们
可以把屏幕内容粘贴到剪贴板上.
if (OpenClipboard(hWnd))
//hWnd为程序窗口句柄
{
//清空剪贴板
EmptyClipboard();
//把屏幕内容粘贴到剪贴板上,
hBitmap 为刚才的屏幕位图句柄
SetClipboardData(CF_BITMAP, hBitmap);
//关闭剪贴板
CloseClipb
oard();
}
int SaveBitmapToFile(HBITMAP hBitmap ,
LPSTR lpFileName) //hBitmap 为刚才的屏幕位图句柄
{ //lpFileName 为位图文件名
HDC hDC;
//设备描述表
int iBits;
//当前显示分辨率下每个像素所占字节数
WORD wBitCount;
//位图中每个像素所占字节数
//定义调色板大小, 位图中像素字节大小 ,
位图文件大小 , 写入文件字节数
DWORD dwPaletteSize=0,
dwBmBitsSize,
dwDIBSize, dwWritten;
BITMAP Bitmap;
//位图属性结构
BITMAPFILEHEADER bmfHdr;
//位图文件头结构
BITMAPINFOHEADER bi;
//位图信息头结构
LPBITMAPINFOHEADER lpbi;
//指向位图信息头结构
HANDLE fh, hDib, hPal,hOldPal=NULL;
//定义文件,分配内存句柄,调色板句柄
//计算位图文件每个像素所占字节数
hDC = CreateDC("DISPLAY",NULL,NULL,NULL);
iBits = GetDeviceCaps(hDC, BITSPIXEL) *
GetDeviceCaps(hDC, PLANES);
DeleteDC(hDC);
if (iBits 〈 = 1)
wBitCount = 1;
else if (iBits 〈 = 4)
wBitCount = 4;
else if (iBits 〈 = 8)
wBitCount = 8;
else if (iBits 〈 = 24)
wBitCount = 24;
//计算调色板大小
if (wBitCount 〈 = 8)
dwPaletteSize = (1 〈 〈 wBitCount) *
sizeof(RGBQUAD);
//设置位图信息头结构
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap.bmWidth;
bi.biHeight = Bitmap.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = wBitCount;
bi.biCompression = BI_RGB;
bi.biSi
zeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmBitsSize = ((Bitmap.bmWidth *
wBitCount+31)/32)* 4
*Bitmap.bmHeight ;
//为位图内容分配内存
hDib = GlobalAlloc(GHND,dwBmBitsSize+
dwPaletteSize+sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;
// 处理调色板
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hDC = GetDC(NULL);
hOldPal = SelectPalette(hDC, hPal, FALSE);
RealizePalette(hDC);
}
// 获取该调色板下新的像素值
GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight,
(LPSTR)lpbi + sizeof(BITMAPINFOHEADER)
+dwPaletteSize,
(BITMAPINFOHEADER *)
lpbi, DIB_RGB_COLORS);
//恢复调色板
if (hOldPal)
{
SelectPalette(hDC, hOldPal, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
}
//创建位图文件
fh = CreateFile(lpFileName, GENERIC_WRITE,
0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL FILE_
FLAG_SEQUENTIAL_SCAN, NULL);
if (fh == INVALID_HANDLE_VALUE)
return FALSE;
// 设置位图文件头
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize = sizeof(BITMAPFILEHEADER)
+ sizeof(BITMAPINFOHEADER)
+ dwPaletteSize + dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof
(BITMAPFILEHEADER)
+ (DWORD)sizeof(BITMAPINFOHEADER)
+ dwPaletteSize;
// 写入位图文件头
WriteFile(fh, (LPSTR)&bmfHdr, sizeof
(BITMAPFILEHEADER), &dwWritten, NULL);
// 写入位图文件其余内容
WriteFile(fh, (LPSTR)lpbi, dwDIBSize,
&dwWritten, NULL);
//清除
GlobalUnlock(hDib);
GlobalFree(hDib);
CloseHandle(fh);
}