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
using namespace std;
*/
deque
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
using namespace std;
*/
deque
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
using namespace std;
*/
deque
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
using namespace std;
*/
deque
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
using namespace std;
*/
deque
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
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
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
#include
#include
#include
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
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 break; nCount++; } m_File.Close(); } else AfxMessageBox("不能打开文件"); 30.文件合并 //#include 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 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 { 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 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 { 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 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 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("<%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 { 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 #include #include #include #include #include #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) # include # include # 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 #include */ using namespace std; using namespace xercesc; try { // Initialize Xerces and obtain a SAX2 parser XercesInitializer init; auto_ptr 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 #include #include Handy definitions of constants. #include 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 #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 #include #include #include #include #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 // 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 typedef bool2type #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 { 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 }; 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::check(factory }; template< size_t N > struct is_power_of_two { enum { value = 1==N || 0==(N%2) && is_power_of_two }; 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 }; template< typename T > struct has_trivial_copy { enum { value = is_scalar }; template< typename T > struct has_trivial_assignment { enum { value = is_scalar }; template< typename T > struct has_trivial_destructor { enum { value = is_scalar }; template< bool > struct destroyer_helper { template< typename T > static void destroy( T const * pT ) { pT, pT->~T(); } }; template<> struct destroyer_helper { template< typename T > static void destroy( T const * ) { } }; template< typename T > void destroy( T const * pT ) { destroyer_helper } 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 regex::detail::destroy( pT ); (void)pv; (void)pT; } static void copy( void * dst, void const * src ) { new ( dst ) T( *static_cast } 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 { &typeid(T), sizeof(T), ( sizeof(T) + AlignmentT - 1 ) & ~( AlignmentT - 1 ), has_trivial_destructor &type_info_ex }; template< typename T > inline T & to_type( void * pv ) { return *static_cast } } // 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 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 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 }; // 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 } }; enum { DYNAMIC_BLOCK_SIZE = DynamicBlockSizeT > sizeof( stack_node ) ? DynamicBlockSizeT : sizeof( stack_node ) }; union { stack_node m_node; byte_t m_buf[ aligned_sizeof } 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 ::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 stack_node * new_node = static_cast ::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 { // 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 { safe_long_jump( jump_ptr ); } void long_jump_impl( void * jump_ptr, detail::bool2type { 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 // 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 } } 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 static_cast // 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 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 // 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 new ( pb ) T( t ); // Could throw if ! has_trivial_copy // 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 } // ok, everything succeeded -- dismiss the guard guard.dismiss(); } template< typename T > inline void pop( T & t ) // throw(...) { detail::static_assert<( AlignmentT >= detail::alignof static_cast // 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 if( ! detail::type_info_ex throw type_error( typeid( T ), *detail::to_type } // Don't change state yet because assignment op could throw! byte_t * pT = m_current - aligned_sizeof t = detail::to_type T const & ref = detail::to_type 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 { detail::static_assert<( AlignmentT >= detail::alignof static_cast // 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 if( ! detail::type_info_ex throw type_error( typeid( T ), *detail::to_type } byte_t * pv = unwind( aligned_sizeof T const & ref = detail::to_type 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 static_cast // 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 if( ! detail::type_info_ex return false; // type error, can't throw so bail. } byte_t * pv = unwind( aligned_sizeof T const & ref = detail::to_type regex::detail::destroy( &ref ); return true; } template< typename T > inline T & top( REGEX_VC6(detail::type2type { detail::static_assert<( AlignmentT >= detail::alignof static_cast 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 if( ! detail::type_info_ex throw type_error( typeid( T ), *detail::to_type } byte_t * pT = m_current - aligned_sizeof return detail::to_type } // 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 byte_t * pti = m_current - aligned_sizeof return *detail::to_type } // 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 std::less { 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 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 while( m_current != jump_ptr ) { // The top of the stack is a pointer to a type_vtable struct. m_current -= aligned_sizeof vtable_ptr pvtable = detail::to_type // 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 } 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 } }; template< typename T > scoped_pop_t { return scoped_pop_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 #include #include #include #include #include #include #include #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 # 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 # 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 #define REGEX_CHAR(CharT,ch) (static_cast #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 { 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 { 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 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 { clear(); m_str = str; } void clear() { std::basic_string 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 public: typedef typename std::map ~charset_map() { for( iterator iter = m_map.begin(); m_map.end() != iter; ++iter ) iter->second.clear(); } charset_map_node 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 { static detail::charset_map return s_charset_map; } inline detail::charset_map { static detail::charset_map return s_charset_map; } inline detail::charset_map { static detail::charset_map return s_charset_map; } inline detail::charset_map { static detail::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 } static TOKEN look_up( wchar_t ch, TOKEN const rg[] ) { return UCHAR_MAX < ch ? NO_TOKEN : rg[ static_cast } }; // -------------------------------------------------------------------------- // // 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 typedef typename std::basic_string typedef CharT char_type; template< typename OtherT > struct rebind { typedef perl_syntax 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 : 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 { 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 { 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 { perl_syntax sy( NOFLAGS ); if( invalid_charset( ch ) ) throw bad_regexpr( "invalid character specified to register_intrinsic_charset" ); std::basic_string typename std::basic_string if( BEGIN_CHARSET != sy.reg_token( ibegin, pat.end() ) ) throw bad_regexpr( "expecting beginning of charset" ); regex::detail::charset_map regex::detail::charset_map_node map_node.set( std::basic_string } private: static bool _invalid_charset( char ch ) { using namespace std; return NO_TOKEN != s_rgescape[ static_cast || isdigit( ch ) || 'e' == ch || 'x' == ch || 'c' == ch; } static bool _invalid_charset( wchar_t ch ) { return UCHAR_MAX >= ch && _invalid_charset( static_cast } }; // -------------------------------------------------------------------------- // // 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 typedef typename std::basic_string typedef CharT char_type; template< typename OtherT > struct rebind { typedef posix_syntax posix_syntax( REGEX_FLAGS flags ) : m_flags( flags ) { } posix_syntax( posix_syntax : 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 { 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 { 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 { posix_syntax sy( NOFLAGS ); if( invalid_charset( ch ) ) throw bad_regexpr( "invalid character specified to register_intrinsic_charset" ); std::basic_string typename std::basic_string if( BEGIN_CHARSET != sy.reg_token( ibegin, pat.end() ) ) throw bad_regexpr( "expecting beginning of charset" ); regex::detail::charset_map regex::detail::charset_map_node map_node.set( std::basic_string } private: static bool _invalid_charset( char ch ) { static char const s_invalid[] = "0123456789()|?+{}//exc"; return 0 != std::char_traits } static bool _invalid_charset( wchar_t ch ) { return UCHAR_MAX >= ch && _invalid_charset( static_cast } }; } // 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 typedef std::char_traits 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 typedef std::char_traits 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 { std::auto_ptr left = right; right = temp; } template< typename T > inline void reset_auto_ptr( std::auto_ptr { std::auto_ptr left = temp; } template< typename T, typename U > inline void reset_auto_ptr( std::auto_ptr { std::auto_ptr 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 typedef sub_expr_base // 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 struct pool_impl { typedef typename rebind 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 } }; template< typename T, typename AllocT = std::allocator 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 typedef pool_impl typedef typename rebind 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 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 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 } 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 destroy( pointer p ) { regex::detail::destroy( p ); } #if !defined(_MSC_VER) | 1200 < _MSC_VER template< typename U > struct rebind { typedef arena_allocator 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_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 : m_data( default_size, alloc ) { } template< typename AllocT > inline pool_impl { clear(); } template< typename AllocT > inline void pool_impl { 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 } } template< typename AllocT > inline void pool_impl { size_t blocksize = regex_max( m_data.m_default_size, size ) + offsetof( mem_block, m_data ); mem_block * pnew = reinterpret_cast 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 { 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 & ~( alignof return pnew; } // The regex_arena is a basic, vanilla arena_allocator. typedef arena_allocator template< typename T > type_with_size<3> allocator_picker( arena_allocator template<> struct rebind_helper<3> { template< typename, typename ElemT> struct inner { typedef arena_allocator }; }; // -------------------------------------------------------------------------- // // 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 virtual bool recursive_match_all_c( match_param virtual bool iterative_match_this_s( match_param virtual bool iterative_match_this_c( match_param virtual bool iterative_rematch_this_s( match_param virtual bool iterative_rematch_this_c( match_param 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 { return recursive_match_all_s( param, icur ); } bool recursive_match_all( match_param { return recursive_match_all_c( param, icur ); } bool iterative_match_this( match_param { return iterative_match_this_s( param ); } bool iterative_match_this( match_param { return iterative_match_this_c( param ); } bool iterative_rematch_this( match_param { return iterative_rematch_this_s( param ); } bool iterative_rematch_this( match_param { 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 { } // -------------------------------------------------------------------------- // // 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 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 basic_rpattern_base_impl & operator=( basic_rpattern_base_impl protected: typedef typename std::iterator_traits typedef std::char_traits typedef std::basic_string typedef size_t size_type; typedef backref_tag typedef std::vector friend struct regex_access 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 std::auto_ptr subst_list_type m_subst_list; // used to speed up substitution sub_expr_base std::list boyer_moore 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 { 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 enum { npos = static_cast 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 match_param IterT icur ); static bool _do_match_iterative_helper_c ( sub_expr_base match_param IterT icur ); static bool _do_match_recursive_s ( sub_expr_base match_param IterT icur ); static bool _do_match_recursive_c ( sub_expr_base match_param IterT icur ); static bool _do_match_impl ( rpattern_type const & pat, match_param bool const use_null ); static bool _do_match_with_stack ( rpattern_type const & pat, match_param bool const use_null ); template< typename Alloc1T, typename Alloc2T > static void _fixup_backrefs ( std::vector std::list ) { typedef typename std::list // 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 std::vector 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 } 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 ibegin, IterT iend, bool use_null ) { typedef typename basic_match_results results.m_ibegin = ibegin; match_param 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 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 // 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 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 IterT ibegin, IterT iend, int limit, bool use_null ) { typedef typename basic_split_results typedef typename rebind std::vector convert_allocator typedef typename rebind char_allocator_type char_allocator = convert_allocator // reserve some initial space results.strings().clear(); results.strings().reserve( 10 ); match_param 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 basic_subst_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 std::advance( itstrlen, strpos + strlen ); std::basic_string for( iter_type isubst = pat.m_subst_list.begin(); pat.m_subst_list.end() != isubst; ++isubst ) { size_t sublen = 0; typename std::basic_string typename std::basic_string typename std::basic_string typename std::basic_string typename std::basic_string 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 std::advance( ibegin, strpos ); typename std::basic_string 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 basic_subst_results size_type pos, size_type len ) { typedef std::basic_string typedef typename basic_subst_results 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 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 { typedef typename std::basic_string size_type i = 0; size_type const npos = std::basic_string 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 #include #include #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 // Find the base of the stack. if (VirtualQuery(pStack, &mbi, sizeof mbi) == 0) return 0; pStackBase = static_cast // 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 # else extern "C" int __cdecl _resetstkoflw(void); # endif extern "C" unsigned long __cdecl _exception_code(void); #endif #include #include #include #include #include #include #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 #else // Assume that all types pushed on stack have trivial destructors. typedef hetero_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 // // 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 , 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 smart_iter 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 { return std::allocator } 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 }; }; // std::allocator template< typename T > type_with_size<2> allocator_picker( std::allocator template<> struct rebind_helper<2> { template< typename, typename ElemT > struct inner { typedef std::allocator }; }; template< typename AllocT, typename ElemT > struct rebind { enum { alloc_type = sizeof(allocator_picker(factory typedef typename rebind_helper }; } // -------------------------------------------------------------------------- // // 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 // -------------------------------------------------------------------------- // // 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 { 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 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 } public: typedef IterT iterator_type; typedef typename std::iterator_traits typedef std::basic_string typedef typename detail::iter_select explicit backref_tag ( IterT i1 = detail::static_init IterT i2 = detail::static_init ) : std::pair , matched( false ) , reserved1( i1 ) , reserved2( 0 ) , reserved3( false ) , reserved4( detail::static_init , reserved5( detail::static_init { } 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 { _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 //} // -------------------------------------------------------------------------- // // 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 > 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 typedef typename detail::rebind typedef std::vector friend struct detail::regex_access 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 struct basic_match_results_c : public basic_match_results { typedef basic_match_results 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 { } }; template< typename CharT, typename TraitsT, typename AllocT > struct subst_results_base { typedef typename detail::rebind typedef std::basic_string typedef typename string_type::const_iterator iterator_type; typedef basic_match_results }; // // For storing the results of a substitute() operation // template < typename CharT, typename TraitsT = std::char_traits typename AllocT = std::allocator > struct basic_subst_results : public subst_results_base { typedef typename detail::rebind typedef std::basic_string typedef typename string_type::const_iterator iterator_type; typedef basic_match_results 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 explicit basic_subst_results( allocator_type const & alloc = allocator_type() ) : basic_match_results< iterator_type, AllocT >( alloc ) , m_backref_str( detail::convert_allocator , 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 typedef std::basic_string typedef typename detail::rebind typedef std::vector }; // // For storing the results of a split() operation // template < typename CharT, typename TraitsT = std::char_traits typename AllocT = std::allocator > struct basic_split_results : private split_results_base { typedef CharT char_type; typedef typename detail::rebind typedef std::basic_string typedef typename detail::rebind typedef std::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 { protected: typedef detail::basic_rpattern_base_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 { } basic_rpattern_base( basic_rpattern_base : detail::basic_rpattern_base_impl { // 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 { _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 { _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 ) //throw( bad_regexpr, std::bad_alloc ) { basic_rpattern_base swap( temp ); return *this; } detail::match_group_base ( typename string_type::iterator & ipat, detail::match_group_base std::vector ); bool _find_next ( typename string_type::iterator & ipat, detail::match_group_base std::vector ); void _find_atom ( typename string_type::iterator & ipat, detail::match_group_base syntax_type & sy ); void _quantify ( std::auto_ptr 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 static_cast static_cast &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 > class basic_rpattern : public basic_rpattern_base { typedef detail::basic_rpattern_base_impl template< typename CharT > static void same_char_types( CharT, CharT ) {} public: typedef typename basic_rpattern_base typedef typename basic_rpattern_base typedef typename basic_rpattern_base typedef typename basic_rpattern_base typedef typename basic_rpattern_base typedef typename basic_rpattern_base typedef typename basic_rpattern_base basic_rpattern() //throw() : basic_rpattern_base { } basic_rpattern( basic_rpattern const & that ) : basic_rpattern_base { } 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 { } 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 { } basic_rpattern & operator=( basic_rpattern { basic_rpattern_base 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 ) 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 ( void ) iterator_types_are_not_convertible; if( detail::regex_access { return results.backref(0); } else { return detail::static_init } } template< typename CharT, typename AllocT > backref_type const & match ( CharT * szbegin, basic_match_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 ( void ) iterator_types_are_not_convertible; if( detail::regex_access { return results.backref(0); } else { return detail::static_init } } template< typename CharT, typename TraitsT, typename AllocT > backref_type const & match ( std::basic_string basic_match_results size_type pos = 0, size_type len = static_cast ) 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 detail::static_assert< detail::is_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 ( void ) iterator_types_are_not_convertible; return detail::regex_access } 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 ( void ) iterator_types_are_not_convertible; return detail::regex_access } template< typename CharT, typename TraitsT, typename AllocT > size_t count ( std::basic_string size_type pos = 0, size_type len = static_cast ) 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 detail::static_assert< detail::is_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 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 ( void ) iterator_types_are_not_convertible; return detail::regex_access } template< typename Char1T, typename Char2T, typename TraitsT, typename AllocT > size_t split ( Char1T * szbegin, basic_split_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 ( 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 } template< typename CharT, typename TraitsT, typename AllocT > size_t split ( std::basic_string basic_split_results int limit = 0, size_type pos = 0, size_type len = static_cast ) 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 detail::static_assert< detail::is_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 basic_subst_results size_type pos = 0, size_type len = static_cast ) 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 detail::static_assert< detail::is_convertible ( void ) iterator_types_are_not_convertible; return detail::regex_access } }; // -------------------------------------------------------------------------- // // 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 class basic_rpattern_c : public basic_rpattern_base { typedef detail::basic_rpattern_base_impl public: typedef typename basic_rpattern_base typedef typename basic_rpattern_base typedef typename basic_rpattern_base typedef typename basic_rpattern_base typedef typename basic_rpattern_base typedef typename basic_rpattern_base typedef typename basic_rpattern_base basic_rpattern_c() //throw() : basic_rpattern_base { } basic_rpattern_c( basic_rpattern_c const & that ) : basic_rpattern_base { } 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 { } basic_rpattern_c & operator=( basic_rpattern_c { basic_rpattern_base return *this; } template< typename AllocT > backref_type const & match ( CharT const * szbegin, basic_match_results_c ) const { if( detail::regex_access { return results.backref(0); } else { return detail::static_init } } size_t count( CharT const * szbegin ) const { return detail::regex_access } }; #if defined(UNICODE) | defined(_UNICODE) typedef wchar_t rechar_t; #else typedef char rechar_t; #endif typedef std::basic_string // 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 restring::const_iterator, rechar_t const * >::type lpctstr_t; // For matching against null-terminated strings typedef basic_rpattern typedef basic_rpattern // For matching against std::strings typedef basic_rpattern typedef basic_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 typedef basic_match_results typedef basic_subst_results typedef basic_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 ( std::basic_ostream backref_tag ) { 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 { 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 #include #include #include #include #include #include #ifdef __MWERKS__ # include #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 } #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 // 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 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 ++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 typedef typename std::char_traits 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 static unsigned char hash_char( signed char ch ) { return static_cast static unsigned char hash_char( unsigned char ch ) { return ch; } static unsigned char hash_char( wchar_t ch ) { return static_cast template< typename CharT > static unsigned char REGEX_VC6(REGEX_CDECL) hash_char( CharT ch REGEX_VC6(...) ) { return static_cast } // case-sensitive Boyer-Moore search template< typename OtherT > OtherT find_with_case( OtherT begin, OtherT end ) const { typedef typename std::iterator_traits 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 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 diff_type diff = std::distance( begin, end ); m_len = static_cast 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 m_rg[ i ] |= that.m_rg[ i ]; return *this; } ascii_bitvector & operator|=( not_ascii_bitvector const & that ) { for( int i=0; i m_rg[ i ] |= ~that.m_ref.m_rg[ i ]; return *this; } }; typedef std::pair // 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 class slist { struct cons { T car; cons * cdr; cons( T const & t, cons * nxt ) : car( t ) , cdr( nxt ) { } }; typedef typename rebind typedef typename rebind #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 { friend class slist 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 { } ~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 } 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 { REGEX_VC6( return pcs->in( m_ch COMMA bool2type REGEX_NVC6( return pcs->template in } }; template< typename AllocT > struct basic_charset { typedef basic_charset typedef slist typedef slist typedef slist typedef slist typedef typename rebind 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 m_ascii_bitvector.set( static_cast } else { m_ascii_bitvector.set( static_cast } } // Note overloading based on first parameter void set_bit( wchar_t ch, bool const fnocase ) { if( UCHAR_MAX >= ch ) set_bit( static_cast 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 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 i <= static_cast { m_ascii_bitvector.set( static_cast m_ascii_bitvector.set( static_cast } } else { // i is unsigned int to prevent overflow if ch2 is UCHAR_MAX for( unsigned int i = static_cast i <= static_cast { m_ascii_bitvector.set( static_cast } } } // 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 if( UCHAR_MAX < ch2 ) m_ranges.push_front( range_type( regex_max( static_cast } void optimize( type2type { 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 } // 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 { optimize( type2type // 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 { 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 || ( m_nestedcharsets.end() != std::find_if( m_nestedcharsets.begin(), m_nestedcharsets.end(), in_charset_pred } 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 { // Whoops, forgot to call optimize() on this charset REGEX_ASSERT( wct_zero == m_posixcharson ); return m_fcompliment != ( ( m_ascii_bitvector[ static_cast || ( extended_check REGEX_NVC6( ); } // Note overloading based on parameter template< bool CaseT > bool in( wchar_t ch REGEX_VC6(COMMA bool2type { // 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 ( ( in_ranges( ch, bool2type || ( wct_zero != m_posixcharson && regex_iswctype( ch, m_posixcharson ) ) ) ) || ( extended_check REGEX_NVC6( ); } 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 { 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 { 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 { } 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 optimize( type2type } 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 { 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 { typedef typename std::iterator_traits typedef std::char_traits 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 { return param.m_iend == iter; } }; template<> struct eos_t { template< typename IterT > static bool eval( match_param { typedef typename std::iterator_traits typedef std::char_traits 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 { typedef typename std::iterator_traits typedef std::char_traits return param.m_iend == iter || traits_type::eq( REGEX_CHAR(char_type,'/n'), *iter ); } }; template<> struct eol_t { template< typename IterT > static bool eval( match_param { typedef typename std::iterator_traits typedef std::char_traits 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 { typedef typename std::iterator_traits typedef std::char_traits return param.m_iend == iter || ( traits_type::eq( REGEX_CHAR(char_type,'/n'), *iter ) && param.m_iend == ++iter ); } }; template<> struct peos_t { template< typename IterT > static bool eval( match_param { typedef typename std::iterator_traits typedef std::char_traits 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 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 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 std::list width_type m_width; width_param ( std::vector std::list ) : 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 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 }; // -------------------------------------------------------------------------- // // 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 { 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 typedef std::char_traits 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 { return ( recursive_match_this_s( param, icur ) && recursive_match_next( param, icur, false_t() ) ); } virtual bool recursive_match_all_c( match_param { 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 { return true; } virtual bool recursive_match_this_c( match_param { return true; } // Match all subsequent objects template< typename CStringsT > bool recursive_match_next( match_param { return m_pnext->recursive_match_all( param, icur, CStringsT() ); } virtual bool iterative_match_this_s( match_param { param.m_pnext = next(); return true; } virtual bool iterative_match_this_c( match_param { param.m_pnext = next(); return true; } virtual bool iterative_rematch_this_s( match_param { return false; } virtual bool iterative_rematch_this_c( match_param { return false; } virtual bool is_assertion() const { return false; } width_type get_width( width_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 virtual bool peek_this( peek_param { 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 { bool _do_match_this( match_param { return ! param.m_no0len || param.m_imatchbegin != icur; } public: virtual bool recursive_match_all_s( match_param { return _do_match_this( param, icur ); } virtual bool recursive_match_all_c( match_param { return _do_match_this( param, icur ); } virtual bool iterative_match_this_s( match_param { param.m_pnext = 0; return _do_match_this( param, param.m_icur ); } virtual bool iterative_match_this_c( match_param { param.m_pnext = 0; return _do_match_this( param, param.m_icur ); } virtual width_type width_this( width_param { 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 { public: virtual bool is_assertion() const { return true; } virtual width_type width_this( width_param { return zero_width; } virtual bool peek_this( peek_param { 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 template< typename IterT, typename OpWrapT > class assert_op : public assertion { public: virtual bool recursive_match_all_s( match_param { 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 { 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 { return OpWrapT::op_type::eval( param, icur ); } virtual bool recursive_match_this_c( match_param { return OpWrapT::opc_type::eval( param, icur ); } virtual bool iterative_match_this_s( match_param { param.m_pnext = this->next(); return OpWrapT::op_type::eval( param, param.m_icur ); } virtual bool iterative_match_this_c( match_param { param.m_pnext = this->next(); return OpWrapT::opc_type::eval( param, param.m_icur ); } }; template< typename IterT > inline assertion { return new( arena ) assert_op } template< typename IterT > inline assertion { return new( arena ) assert_op } template< typename IterT > inline assertion { return new( arena ) assert_op } template< typename IterT > inline assertion { switch( MULTILINE & flags ) { case 0: return new( arena ) assert_op case MULTILINE: return new( arena ) assert_op default: REGEX_ASSERT(false); return 0; } } template< typename IterT > inline assertion { switch( MULTILINE & flags ) { case 0: return new( arena ) assert_op case MULTILINE: return new( arena ) assert_op default: REGEX_ASSERT(false); return 0; } } template< typename IterT, typename SubExprT = sub_expr class match_wrapper : public sub_expr { 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 { return m_psub->width_this( param ); } virtual bool peek_this( peek_param { 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 class match_quantifier : public match_wrapper { match_quantifier & operator=( match_quantifier const & ); public: match_quantifier( SubExprT * psub, size_t lbound, size_t ubound ) : match_wrapper , m_lbound( lbound ) , m_ubound( ubound ) { } virtual width_type width_this( width_param { width_type this_width = match_wrapper width_type quant_width = { m_lbound, m_ubound }; return this_width * quant_width; } virtual bool peek_this( peek_param { 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 { atom_quantifier & operator=( atom_quantifier const & ); public: atom_quantifier( SubExprT * psub, size_t lbound, size_t ubound ) : match_quantifier { } protected: void _push_frame( unsafe_stack * pstack, IterT curr, size_t count ) const { std::pair pstack->push( p ); } void _pop_frame( match_param { std::pair param.m_pstack->pop( p ); param.m_icur = p.first; } }; template< typename IterT, typename SubExprT > class max_atom_quantifier : public atom_quantifier { max_atom_quantifier & operator=( max_atom_quantifier const & ); public: max_atom_quantifier( SubExprT * psub, size_t lbound, size_t ubound ) : atom_quantifier { } // 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 { / typedef typename std::iterator_traits /* 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 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 { / typedef std::pair size_t & cmatches = REGEX_VC6( param.m_pstack->top( type2type REGEX_NVC6( param.m_pstack->template top 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 { min_atom_quantifier & operator=( min_atom_quantifier const & ); public: min_atom_quantifier( SubExprT * psub, size_t lbound, size_t ubound ) : atom_quantifier { } // 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 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 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 { / typedef std::pair size_t & cmatches = REGEX_VC6( param.m_pstack->top( type2type REGEX_NVC6( param.m_pstack->template top 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 { match_char & operator=( match_char const & ); public: typedef typename sub_expr virtual width_type width_this( width_param { width_type width = { 1, 1 }; return width; } virtual bool iterative_rematch_this_s( match_param { --param.m_icur; return false; } virtual bool iterative_rematch_this_c( match_param { --param.m_icur; return false; } }; template< typename IterT, typename CharT > class match_char_t : public match_char { match_char_t & operator=( match_char_t const & ); public: match_char_t( CharT const & ch ) : m_ch( ch ) { } virtual sub_expr { if( greedy ) return new( arena ) max_atom_quantifier else return new( arena ) min_atom_quantifier } virtual bool recursive_match_all_s( match_param { 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 { 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 { return _do_match_this REGEX_NVC6( } virtual bool recursive_match_this_c( match_param { return _do_match_this REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { param.m_pnext = this->next(); return _do_match_this REGEX_NVC6( } virtual bool iterative_match_this_c( match_param { param.m_pnext = this->next(); return _do_match_this REGEX_NVC6( } virtual bool peek_this( peek_param { _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 { return traits_type::eq( left, right.m_chlo ) || traits_type::eq( left, right.m_chhi ); } static void _do_peek_this( peek_param { peek.m_cchars = 1; peek.m_rgchars[0] = ch; peek.m_must_have.m_has = false; } static void _do_peek_this( peek_param { 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 { if( eos_t return false; ++icur; return true; } CharT const m_ch; }; template< typename IterT > inline match_char ( typename std::iterator_traits REGEX_FLAGS flags, regex_arena & arena ) { typedef typename std::iterator_traits typedef std::char_traits switch( NOCASE & flags ) { case 0: return new( arena ) match_char_t case NOCASE: { char_nocase if( traits_type::eq( nocase.m_chlo, nocase.m_chhi ) ) return new( arena ) match_char_t else return new( arena ) match_char_t } default: REGEX_ASSERT(false); return 0; } } template< typename IterT > class match_literal : public sub_expr { match_literal & operator=( match_literal const & ); public: typedef typename sub_expr typedef std::basic_string typedef typename string_type::iterator iterator; typedef typename string_type::const_iterator const_iterator; typedef typename std::iterator_traits 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 { width_type width = { static_cast return width; } virtual bool iterative_rematch_this_s( match_param { std::advance( param.m_icur, -m_dist ); return false; } virtual bool iterative_rematch_this_c( match_param { std::advance( param.m_icur, -m_dist ); return false; } }; template< typename IterT > class match_literal_t : public match_literal { match_literal_t & operator=( match_literal_t const & ); public: typedef typename match_literal typedef typename match_literal typedef typename match_literal typedef typename match_literal match_literal_t( const_iterator ibegin, const_iterator iend ) : match_literal { } virtual sub_expr { if( greedy ) return new( arena ) max_atom_quantifier else return new( arena ) min_atom_quantifier } virtual bool recursive_match_all_s( match_param { 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 { 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 { return _do_match_this REGEX_NVC6( } virtual bool recursive_match_this_c( match_param { return _do_match_this REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { param.m_pnext = this->next(); return _do_match_this REGEX_NVC6( } virtual bool iterative_match_this_c( match_param { param.m_pnext = this->next(); return _do_match_this REGEX_NVC6( } virtual bool peek_this( peek_param { 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 icur_tmp = icur; const_iterator ithis = this->m_ibegin; for( ; this->m_iend != ithis; ++icur_tmp, ++ithis ) { if( eos_t return false; } icur = icur_tmp; return true; } }; template< typename IterT > class match_literal_nocase_t : public match_literal { match_literal_nocase_t & operator=( match_literal_nocase_t const & ); public: typedef typename match_literal typedef typename match_literal typedef typename match_literal typedef typename match_literal match_literal_nocase_t( iterator ibegin, const_iterator iend, regex_arena & arena ) : match_literal , m_szlower( arena_allocator { // 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 { if( greedy ) return new( arena ) max_atom_quantifier else return new( arena ) min_atom_quantifier } virtual bool recursive_match_all_s( match_param { 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 { 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 { return _do_match_this REGEX_NVC6( } virtual bool recursive_match_this_c( match_param { return _do_match_this REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { param.m_pnext = this->next(); return _do_match_this REGEX_NVC6( } virtual bool iterative_match_this_c( match_param { param.m_pnext = this->next(); return _do_match_this REGEX_NVC6( } virtual bool peek_this( peek_param { 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 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 ( ! 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 ( 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 { return create_char } switch( NOCASE & flags ) { case 0: return new( arena ) match_literal_t case NOCASE: return new( arena ) match_literal_nocase_t default: REGEX_ASSERT(false); return 0; } } template< typename IterT > class match_any : public sub_expr { public: virtual width_type width_this( width_param { width_type width = { 1, 1 }; return width; } virtual bool iterative_rematch_this_s( match_param { --param.m_icur; return false; } virtual bool iterative_rematch_this_c( match_param { --param.m_icur; return false; } }; template< typename IterT, typename EosWrapT > class match_any_t : public match_any { bool _do_match_this_s( match_param { if( EosWrapT::op_type::eval( param, icur ) ) return false; ++icur; return true; } bool _do_match_this_c( match_param { if( EosWrapT::opc_type::eval( param, icur ) ) return false; ++icur; return true; } public: virtual sub_expr { if( greedy ) return new( arena ) max_atom_quantifier else return new( arena ) min_atom_quantifier } virtual bool recursive_match_all_s( match_param { 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 { 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 { return _do_match_this_s( param, icur ); } virtual bool recursive_match_this_c( match_param { return _do_match_this_c( param, icur ); } virtual bool iterative_match_this_s( match_param { param.m_pnext = this->next(); return _do_match_this_s( param, param.m_icur ); } virtual bool iterative_match_this_c( match_param { param.m_pnext = this->next(); return _do_match_this_c( param, param.m_icur ); } }; template< typename IterT > inline match_any { switch( SINGLELINE & flags ) { case 0: return new( arena ) match_any_t case SINGLELINE: return new( arena ) match_any_t default: REGEX_ASSERT(false); return 0; } } template< typename IterT > class match_charset : public sub_expr { public: virtual width_type width_this( width_param { width_type width = { 1, 1 }; return width; } virtual bool iterative_rematch_this_s( match_param { --param.m_icur; return false; } virtual bool iterative_rematch_this_c( match_param { --param.m_icur; return false; } }; template< typename IterT, typename CharSetPtrT, bool CaseT > class match_charset_t : public match_charset { CharSetPtrT const m_pcs; match_charset_t & operator=( match_charset_t const & ); template< typename CStringsT > bool _do_match_this( match_param { if( eos_t ! m_pcs->REGEX_NVC6(template) in REGEX_NVC6( return false; ++icur; return true; } public: match_charset_t( CharSetPtrT pcs ) : m_pcs( pcs ) { } virtual sub_expr { if( greedy ) return new( arena ) max_atom_quantifier else return new( arena ) min_atom_quantifier } virtual bool recursive_match_all_s( match_param { 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 { 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 { return _do_match_this REGEX_NVC6( } virtual bool recursive_match_this_c( match_param { return _do_match_this REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { param.m_pnext = this->next(); return _do_match_this REGEX_NVC6( } virtual bool iterative_match_this_c( match_param { param.m_pnext = this->next(); return _do_match_this REGEX_NVC6( } }; template< typename IterT > inline match_charset ( charset const & cs, REGEX_FLAGS flags, regex_arena & arena ) { switch( NOCASE & flags ) { case 0: return new( arena ) match_charset_t case NOCASE: return new( arena ) match_charset_t default: REGEX_ASSERT(false); return 0; } } template< typename IterT > inline match_charset ( custom_charset const * pcs, REGEX_FLAGS flags, regex_arena & arena ) { typedef std::auto_ptr auto_charset acs( pcs ); switch( NOCASE & flags ) { case 0: return new( arena ) match_charset_t case NOCASE: return new( arena ) match_charset_t 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 { word_assertion_t & operator=( word_assertion_t const & ); public: typedef typename assertion word_assertion_t() : m_isword( intrinsic_charsets { } virtual bool recursive_match_all_s( match_param { 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 { 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 { return _do_match_this REGEX_NVC6( } virtual bool recursive_match_this_c( match_param { return _do_match_this REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { param.m_pnext = this->next(); return _do_match_this REGEX_NVC6( } virtual bool iterative_match_this_c( match_param { param.m_pnext = this->next(); return _do_match_this REGEX_NVC6( } private: bool _is_word( char_type ch ) const { return REGEX_VC6( m_isword.in( ch COMMA true_t() ) ) REGEX_NVC6( m_isword.template in } template< typename CStringsT > bool _do_match_this( match_param { bool const fthisword = ! eos_t bool const fprevword = ! bos_t return CondT::eval( fprevword, fthisword ); } charset const & m_isword; }; template< typename IterT > inline assertion ( bool fisboundary, REGEX_FLAGS, // flags regex_arena & arena ) { if( fisboundary ) return new( arena ) word_assertion_t else return new( arena ) word_assertion_t } template< typename IterT > inline assertion { return new( arena ) word_assertion_t } template< typename IterT > inline assertion { return new( arena ) word_assertion_t } // an "extent" represents the range of backrefs that can be modified as the // result of a look-ahead or look-behind typedef std::pair template< typename IterT > class max_group_quantifier; template< typename IterT > class min_group_quantifier; template< typename IterT > class match_group_base : public sub_expr { protected: typedef slist private: match_group_base & operator=( match_group_base const & ); void _push_frame( match_param { 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 { typedef typename alt_list_type::const_iterator iter_type; unsafe_stack * ps = param.m_pstack; REGEX_VC6( ps->pop( type2type REGEX_NVC6( ps->template pop if( size_t( -1 ) != m_cgroup ) ps->pop( param.m_prgbackrefs[ m_cgroup ].reserved1 ); } template< typename CStringsT > bool _do_recursive_match_all( match_param { typedef typename alt_list_type::const_iterator iter_type; if( 0 != m_peek_chars_begin && ( eos_t 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 { if( 0 != m_peek_chars_begin && ( eos_t 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 { typedef typename alt_list_type::const_iterator iter_type; iter_type next_iter = ++param.m_pstack->REGEX_NVC6(template) top REGEX_NVC6( if( m_rgalternates.end() != next_iter ) { param.m_pnext = *next_iter; return true; } _pop_frame( param ); return false; } public: typedef typename sub_expr match_group_base( size_t cgroup, regex_arena & arena ) : m_rgalternates( arena_allocator , 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 { return _do_recursive_match_all REGEX_NVC6( } virtual bool recursive_match_all_c( match_param { return _do_recursive_match_all REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { return _do_iterative_match_this REGEX_NVC6( } virtual bool iterative_match_this_c( match_param { return _do_iterative_match_this REGEX_NVC6( } virtual bool iterative_rematch_this_s( match_param { return _do_iterative_rematch_this( param ); } virtual bool iterative_rematch_this_c( match_param { return _do_iterative_rematch_this( param ); } size_t group_number() const { return m_cgroup; } void add_item( sub_expr { *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 { end_alternate(); m_rgalternates.reverse(); return get_peek_chars( arena ); } must_have { m_peek_chars_begin = 0; // optimization: find the lookahead characters for each alternate size_t total_chars = 0; peek_param 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 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 std::list ) { // This should only be called on the top node REGEX_ASSERT( 0 == m_cgroup ); if( uninit_width() == m_nwidth ) { width_param match_group_base } return m_nwidth; } virtual width_type width_this( width_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 { 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 (*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 alt_list_type m_rgalternates; size_t const m_cgroup; width_type m_nwidth; union { sub_expr char_type * m_peek_chars_begin; }; char_type * m_peek_chars_end; }; template< typename IterT > inline 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 { 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 { match_group( match_group const & ); match_group & operator=( match_group const & ); public: match_group( size_t cgroup, regex_arena & arena ) : match_group_base , m_end_group( this ) { } virtual ~match_group() { this->_cleanup(); } virtual sub_expr { if( greedy ) return new( arena ) max_group_quantifier else return new( arena ) min_group_quantifier } protected: typedef typename match_group_base struct old_backref { IterT m_ibegin; IterT m_iend; bool m_matched; old_backref() {} old_backref( backref_tag : m_ibegin( br.first ) , m_iend( br.second ) , m_matched( br.matched ) { } }; static void restore_backref( backref_tag { 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 { if( size_t( -1 ) != this->m_cgroup ) { backref_tag // 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 { match_group end_group & operator=( end_group const & ); void _push_frame( match_param { size_t cgroup = m_pgroup->group_number(); if( size_t( -1 ) != cgroup ) { backref_tag 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 { size_t cgroup = m_pgroup->group_number(); if( size_t( -1 ) != cgroup ) { old_backref old_br; param.m_pstack->pop( old_br ); match_group } } bool _do_iterative_match_this( match_param { _push_frame( param ); param.m_pnext = m_pgroup->next(); return true; } bool _do_iterative_rematch_this( match_param { _pop_frame( param ); return false; } public: end_group( match_group : m_pgroup( pgroup ) { } virtual bool recursive_match_all_s( match_param { return m_pgroup->REGEX_NVC6(template) _do_call_back REGEX_NVC6( } virtual bool recursive_match_all_c( match_param { return m_pgroup->REGEX_NVC6(template) _do_call_back REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { return _do_iterative_match_this( param ); } virtual bool iterative_match_this_c( match_param { return _do_iterative_match_this( param ); } virtual bool iterative_rematch_this_s( match_param { return _do_iterative_rematch_this( param ); } virtual bool iterative_rematch_this_c( match_param { return _do_iterative_rematch_this( param ); } virtual width_type width_this( width_param { return zero_width; } } m_end_group; friend class end_group; virtual sub_expr { return & m_end_group; } }; template< typename IterT > inline void save_backrefs( backref_tag { for( ; ibegin != iend; ++ibegin, ++prgci ) { new( prgci ) IterT( ibegin->reserved1 ); } } template< typename IterT > inline void restore_backrefs( backref_tag { for( ; ibegin != iend; ++ibegin, ++prgci ) { ibegin->reserved1 = *prgci; prgci->~IterT(); } } template< typename IterT > class group_wrapper : public sub_expr { match_group_base group_wrapper & operator=( group_wrapper const & ); public: group_wrapper( match_group_base : m_pgroup( pgroup ) { } virtual bool iterative_match_this_s( match_param { return m_pgroup->match_group_base } virtual bool iterative_match_this_c( match_param { return m_pgroup->match_group_base } virtual bool iterative_rematch_this_s( match_param { return m_pgroup->match_group_base } virtual bool iterative_rematch_this_c( match_param { return m_pgroup->match_group_base } virtual width_type width_this( width_param { 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 { 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 { backref_tag // Copy onto the stack the part of the backref vector that could // be modified by the lookahead. if( m_extent.second ) { prgbr = static_cast 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 match_group_base 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 { group_wrapper _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 { _pop_frame( param ); return false; } public: independent_group_base( size_t cgroup, regex_arena & arena ) : match_group_base , 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 { return _do_recursive_match_all REGEX_NVC6( } virtual bool recursive_match_all_c( match_param { return _do_recursive_match_all REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { return _do_iterative_match_this REGEX_NVC6( } virtual bool iterative_match_this_c( match_param { return _do_iterative_match_this REGEX_NVC6( } virtual bool iterative_rematch_this_s( match_param { return _do_iterative_rematch_this( param ); } virtual bool iterative_rematch_this_c( match_param { return _do_iterative_rematch_this( param ); } virtual bool peek_this( peek_param { if( size_t( -1 ) == this->m_cgroup ) return false; return match_group_base } protected: void _push_frame( match_param { unsafe_stack * pstack = param.m_pstack; typedef typename match_param 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 { unsafe_stack * pstack = param.m_pstack; typedef typename match_param 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 , m_fexpected( fexpected ) { } bool const m_fexpected; extent_type m_extent; }; template< typename IterT > class independent_group : public independent_group_base { independent_group( independent_group const & ); independent_group & operator=( independent_group const & ); public: independent_group( size_t cgroup, regex_arena & arena ) : independent_group_base , m_end_group( this ) { } virtual ~independent_group() { this->_cleanup(); } virtual sub_expr { if( greedy ) return new( arena ) max_group_quantifier else return new( arena ) min_group_quantifier } protected: independent_group( bool const fexpected, regex_arena & arena ) : independent_group_base , m_end_group( this ) { } bool _do_call_back( match_param { if( size_t( -1 ) != this->m_cgroup ) { backref_tag br.first = br.reserved1; br.second = icur; br.matched = true; } return true; } class end_group : public indestructable_sub_expr { independent_group end_group & operator=( end_group const & ); bool _do_iterative_match_this( match_param { size_t cgroup = m_pgroup->group_number(); if( size_t( -1 ) != cgroup ) { backref_tag br.first = br.reserved1; br.second = param.m_icur; br.matched = true; } param.m_pnext = 0; return true; } public: end_group( independent_group : m_pgroup( pgroup ) { } virtual bool recursive_match_all_s( match_param { return m_pgroup->_do_call_back( param, icur ); } virtual bool recursive_match_all_c( match_param { return m_pgroup->_do_call_back( param, icur ); } virtual bool iterative_match_this_s( match_param { return _do_iterative_match_this( param ); } virtual bool iterative_match_this_c( match_param { return _do_iterative_match_this( param ); } virtual width_type width_this( width_param { return zero_width; } } m_end_group; friend class end_group; virtual sub_expr { return & m_end_group; } }; template< typename IterT > class lookahead_assertion : public independent_group { lookahead_assertion( lookahead_assertion const & ); lookahead_assertion & operator=( lookahead_assertion const & ); public: lookahead_assertion( bool const fexpected, regex_arena & arena ) : independent_group { } virtual sub_expr { throw bad_regexpr( "look-ahead assertion cannot be quantified" ); } virtual bool is_assertion() const { return true; } virtual width_type width_this( width_param { // calculate the group's width and store it, but return zero_width match_group_base return zero_width; } virtual bool peek_this( peek_param { return this->next()->peek_this( peek ); } }; template< typename IterT > class lookbehind_assertion : public independent_group_base { lookbehind_assertion( lookbehind_assertion const & ); lookbehind_assertion & operator=( lookbehind_assertion const & ); template< typename CStringsT > bool _do_recursive_match_all( match_param { typedef typename std::iterator_traits // 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 return this->m_fexpected ? false : this->recursive_match_next( param, icur, CStringsT() ); backref_tag // 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 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 IterT local_iend = icur; std::advance( local_iend, -static_cast // Create a local param struct that has icur as param.m_iend match_param // 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 // 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 { typedef typename std::iterator_traits // 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 { 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 IterT local_iend = param.m_icur; std::advance( local_iend, -static_cast // Create a local param struct that has icur as param.m_iend match_param local_param.m_pstack = param.m_pstack; group_wrapper // 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 // 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 { this->_pop_frame( param ); return false; } public: lookbehind_assertion( bool const fexpected, regex_arena & arena ) : independent_group_base { } virtual ~lookbehind_assertion() { this->_cleanup(); } virtual bool recursive_match_all_s( match_param { return _do_recursive_match_all REGEX_NVC6( } virtual bool recursive_match_all_c( match_param { return _do_recursive_match_all REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { return _do_iterative_match_this REGEX_NVC6( } virtual bool iterative_match_this_c( match_param { return _do_iterative_match_this REGEX_NVC6( } virtual bool iterative_rematch_this_s( match_param { return _do_iterative_rematch_this( param ); } virtual bool iterative_rematch_this_c( match_param { return _do_iterative_rematch_this( param ); } virtual bool is_assertion() const { return true; } virtual width_type width_this( width_param { // calculate the group's width and store it, but return zero_width match_group_base return zero_width; } virtual bool peek_this( peek_param { return this->next()->peek_this( peek ); } protected: struct end_group : public indestructable_sub_expr { virtual bool recursive_match_all_s( match_param { return param.m_iend == icur; } virtual bool recursive_match_all_c( match_param { return param.m_iend == icur; } virtual bool iterative_match_this_s( match_param { param.m_pnext = 0; return param.m_iend == param.m_icur; } virtual bool iterative_match_this_c( match_param { param.m_pnext = 0; return param.m_iend == param.m_icur; } virtual width_type width_this( width_param { return zero_width; } } m_end_group; virtual sub_expr { return & m_end_group; } }; template< typename IterT > class group_quantifier : public match_quantifier { group_quantifier & operator=( group_quantifier const & ); bool _do_iterative_match_this( match_param { _push_frame( param ); param.m_pnext = this->m_psub->next(); // ptr to end_quant return true; } bool _do_iterative_rematch_this( match_param { _pop_frame( param ); return false; } public: group_quantifier ( match_group_base size_t lbound, size_t ubound, sub_expr ) : match_quantifier , 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 { return _do_iterative_match_this( param ); } virtual bool iterative_match_this_c( match_param { return _do_iterative_match_this( param ); } virtual bool iterative_rematch_this_s( match_param { return _do_iterative_rematch_this( param ); } virtual bool iterative_rematch_this_c( match_param { return _do_iterative_rematch_this( param ); } protected: struct old_quant { typedef typename backref_tag size_t reserved2; bool reserved3; smart_iter_type reserved4; smart_iter_type reserved5; old_quant() { } old_quant( backref_tag : reserved2( br.reserved2 ) , reserved3( br.reserved3 ) , reserved4( br.reserved4 ) , reserved5( br.reserved5 ) { } }; void _push_frame( match_param { typedef typename backref_tag backref_tag 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 br.reserved5 = static_init } void _pop_frame( match_param { backref_tag 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 { return param.m_prgbackrefs[ group_number() ].reserved2; } typename backref_tag { return param.m_prgbackrefs[ group_number() ].reserved4; } typename backref_tag { return param.m_prgbackrefs[ group_number() ].reserved5; } match_group_base }; template< typename IterT > inline group_quantifier { } template< typename IterT > class max_group_quantifier : public group_quantifier { max_group_quantifier & operator=( max_group_quantifier const & ); template< typename CStringsT > bool _do_recursive_match_all( match_param { typedef typename backref_tag 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 this->highwater2( param ) = icur; this->cmatches( param ) = 0; if( _do_recurse REGEX_NVC6( 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 : group_quantifier , 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 { return _do_recursive_match_all REGEX_NVC6( } virtual bool recursive_match_all_c( match_param { return _do_recursive_match_all REGEX_NVC6( } protected: template< typename CStringsT > bool _do_recurse( match_param { 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 { max_group_quantifier end_quantifier & operator=( end_quantifier const & ); void _push_frame( match_param { backref_tag param.m_pstack->push( br.reserved4 ); br.reserved4 = br.reserved5; br.reserved5 = param.m_icur; } void _pop_frame( match_param { backref_tag br.reserved5 = br.reserved4; param.m_pstack->pop( br.reserved4 ); } template< typename CStringsT > bool _do_recursive_match_all( match_param { typedef typename backref_tag 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( 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 { backref_tag // 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 { typedef typename backref_tag backref_tag // infinite loop forcibly broken if( param.m_icur == param.m_pstack->REGEX_NVC6(template) top REGEX_NVC6( { _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 : m_pquant( pquant ) { } virtual bool recursive_match_all_s( match_param { return _do_recursive_match_all REGEX_NVC6( } virtual bool recursive_match_all_c( match_param { return _do_recursive_match_all REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { return _do_iterative_match_this( param ); } virtual bool iterative_match_this_c( match_param { return _do_iterative_match_this( param ); } virtual bool iterative_rematch_this_s( match_param { return _do_iterative_rematch_this( param ); } virtual bool iterative_rematch_this_c( match_param { return _do_iterative_rematch_this( param ); } virtual width_type width_this( width_param { return zero_width; } } m_end_quant; friend class end_quantifier; }; template< typename IterT > class min_group_quantifier : public group_quantifier { min_group_quantifier & operator=( min_group_quantifier const & ); template< typename CStringsT > bool _do_recursive_match_all( match_param { typedef typename backref_tag 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 this->highwater2( param ) = icur; this->cmatches( param ) = 0; if( _do_recurse REGEX_NVC6( 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 : group_quantifier , 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 { return _do_recursive_match_all REGEX_NVC6( } virtual bool recursive_match_all_c( match_param { return _do_recursive_match_all REGEX_NVC6( } protected: template< typename CStringsT > bool _do_recurse( match_param { 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 { min_group_quantifier end_quantifier & operator=( end_quantifier const & ); void _push_frame( match_param { backref_tag param.m_pstack->push( br.reserved4 ); br.reserved4 = br.reserved5; br.reserved5 = param.m_icur; } void _pop_frame( match_param { backref_tag br.reserved5 = br.reserved4; param.m_pstack->pop( br.reserved4 ); } template< typename CStringsT > bool _do_recursive_match_all( match_param { typedef typename backref_tag 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( 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 { backref_tag // 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 { typedef typename backref_tag backref_tag // infinite loop forcibly broken if( param.m_icur == param.m_pstack->REGEX_NVC6(template) top REGEX_NVC6( { _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 : m_pquant( pquant ) { } virtual bool recursive_match_all_s( match_param { return _do_recursive_match_all REGEX_NVC6( } virtual bool recursive_match_all_c( match_param { return _do_recursive_match_all REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { return _do_iterative_match_this( param ); } virtual bool iterative_match_this_c( match_param { return _do_iterative_match_this( param ); } virtual bool iterative_rematch_this_s( match_param { return _do_iterative_rematch_this( param ); } virtual bool iterative_rematch_this_c( match_param { return _do_iterative_rematch_this( param ); } virtual width_type width_this( width_param { return zero_width; } } m_end_quant; friend class end_quantifier; }; inline void fixup_backref( size_t & cbackref, std::list { std::list for( ; invisible_groups.end() != iter && cbackref >= *iter; ++iter ) { ++cbackref; } } template< typename IterT > class match_backref : public sub_expr { bool _do_iterative_rematch_this( match_param { typedef typename std::iterator_traits backref_tag 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 { // 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 { return _do_iterative_rematch_this( param ); } virtual bool iterative_rematch_this_c( match_param { return _do_iterative_rematch_this( param ); } protected: size_t m_nbackref; }; template< typename CmpT, typename IterT > class match_backref_t : public match_backref { public: match_backref_t( size_t nbackref ) : match_backref { } virtual sub_expr { if( greedy ) return new( arena ) max_atom_quantifier else return new( arena ) min_atom_quantifier } virtual bool recursive_match_all_s( match_param { 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 { 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 { return _do_match_this REGEX_NVC6( } virtual bool recursive_match_this_c( match_param { return _do_match_this REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { param.m_pnext = this->next(); return _do_match_this REGEX_NVC6( } virtual bool iterative_match_this_c( match_param { param.m_pnext = this->next(); return _do_match_this REGEX_NVC6( } protected: template< typename CStringsT > bool _do_match_this( match_param { // 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 return false; } icur = icur_tmp; return true; } }; template< typename IterT > inline match_backref size_t cbackref, REGEX_FLAGS flags, regex_arena & arena ) { typedef typename std::iterator_traits switch( NOCASE & flags ) { case 0: return new( arena ) match_backref_t case NOCASE: return new( arena ) match_backref_t default: REGEX_ASSERT(false); return 0; } } template< typename IterT > class match_recurse : public sub_expr { match_recurse & operator=( match_recurse const & ); void _push_frame( match_param { typedef typename match_param 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 { typedef typename match_param 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 { // 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 save_backrefs // Recurse. if( param.m_pfirst->recursive_match_all( param, icur, CStringsT() ) ) { // Restore the backref vector restore_backrefs // 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 { 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 { param.m_pstack->pop( param.m_icur ); return false; } public: match_recurse() { } virtual sub_expr { throw bad_regexpr( "recursion sub-expression cannot be quantified" ); } virtual bool recursive_match_all_s( match_param { return _do_recursive_match_all REGEX_NVC6( } virtual bool recursive_match_all_c( match_param { return _do_recursive_match_all REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { return _do_iterative_match_this REGEX_NVC6( } virtual bool iterative_match_this_c( match_param { return _do_iterative_match_this REGEX_NVC6( } virtual bool iterative_rematch_this_s( match_param { return _do_iterative_rematch_this( param ); } virtual bool iterative_rematch_this_c( match_param { return _do_iterative_rematch_this( param ); } virtual width_type width_this( width_param { return worst_width; } }; template< typename IterT > inline match_recurse { return new( arena ) match_recurse } 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 { return m_cbackref < param.m_cbackrefs && param.m_prgbackrefs[ m_cbackref ].matched; } template< typename CStringsT > bool iterative_match_this( match_param { return m_cbackref < param.m_cbackrefs && param.m_prgbackrefs[ m_cbackref ].matched; } template< typename CStringsT > bool iterative_rematch_this( match_param { return false; } void width_this( width_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 assertion_condition( match_group_base : m_passert( passert ) { *passert->pnext() = new( arena ) end_of_pattern } bool recursive_match_this( match_param { return m_passert->recursive_match_all_s( param, icur ); } bool recursive_match_this( match_param { return m_passert->recursive_match_all_c( param, icur ); } bool iterative_match_this( match_param { return m_passert->iterative_match_this_s( param ); } bool iterative_match_this( match_param { return m_passert->iterative_match_this_c( param ); } bool iterative_rematch_this( match_param { return m_passert->iterative_rematch_this_s( param ); } bool iterative_rematch_this( match_param { return m_passert->iterative_rematch_this_c( param ); } void width_this( width_param { ( void ) m_passert->width_this( param ); } }; template< typename IterT, typename CondT > class match_conditional : public match_group { protected: typedef typename match_group private: match_conditional & operator=( match_conditional const & ); template< typename CStringsT > bool _do_recursive_match_all( match_param { 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 { 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 { 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 , m_condition( condition ) { } virtual bool recursive_match_all_s( match_param { return _do_recursive_match_all REGEX_NVC6( } virtual bool recursive_match_all_c( match_param { return _do_recursive_match_all REGEX_NVC6( } virtual bool iterative_match_this_s( match_param { return _do_iterative_match_this REGEX_NVC6( } virtual bool iterative_match_this_c( match_param { return _do_iterative_match_this REGEX_NVC6( } virtual bool iterative_rematch_this_s( match_param { return _do_iterative_rematch_this REGEX_NVC6( } virtual bool iterative_rematch_this_c( match_param { return _do_iterative_rematch_this REGEX_NVC6( } virtual width_type width_this( width_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 size_t cgroup, size_t cbackref, regex_arena & arena ) { backref_condition return new( arena ) match_conditional cgroup, cond, arena ); } template< typename IterT > inline match_conditional size_t cgroup, match_group_base regex_arena & arena ) { assertion_condition return new( arena ) match_conditional cgroup, cond, arena ); } // // From basic_rpattern_base_impl // template< typename IterT > REGEXPR_H_INLINE bool basic_rpattern_base_impl { 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 { 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 { enum { value = true }; }; template< typename IterT > struct is_random_access { typedef typename std::iterator_traits enum { value = is_random_access_helper }; } // namespace detail // // Implementation of basic_rpattern_base: // template< typename IterT, typename SyntaxT > REGEXPR_H_INLINE void basic_rpattern_base { basic_rpattern_base swap( temp ); } template< typename IterT, typename SyntaxT > REGEXPR_H_INLINE void basic_rpattern_base { basic_rpattern_base swap( temp ); } template< typename IterT, typename SyntaxT > REGEXPR_H_INLINE void basic_rpattern_base { this->m_cgroups = 0; std::vector typename string_type::iterator ipat = this->m_pat->begin(); syntax_type sy( flags ); detail::match_group_base // 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 // 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 { using std::swap; std::auto_ptr detail::subst_list_type temp_subst_list; bool uses_backrefs = false; _normalize_string( *temp_subst ); basic_rpattern_base 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 typename string_type::iterator & ipat, detail::match_group_base std::vector { std::auto_ptr 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 // 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 break; case EXT_INDEPENDENT: m_invisible_groups.push_back( this->m_cgroups ); detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::independent_group break; case EXT_POS_LOOKAHEAD: detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::lookahead_assertion break; case EXT_NEG_LOOKAHEAD: detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::lookahead_assertion break; case EXT_POS_LOOKBEHIND: detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::lookbehind_assertion break; case EXT_NEG_LOOKBEHIND: detail::reset_auto_ptr( pgroup, new( this->m_arena ) detail::lookbehind_assertion 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 _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 _find_next_group( ipat, 0, sy, rggroups ) ); detail::reset_auto_ptr( pgroup, detail::create_assertion_conditional _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 ++this->m_cgroups_visible; } if( 0 != pgroup.get() ) { detail::must_have 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 { typedef typename string_type::const_iterator iter_type; m_search = new( this->m_arena ) detail::boyer_moore ( 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 { typedef typename std::iterator_traits char_type ch = 0, i; check_iter 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 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 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 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 typename std::basic_string typename std::basic_string SyntaxT & sy ) { typedef CharT char_type; typedef std::basic_string 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 // remember the current position and grab the next token tok = sy.charset_token( icur, iend ); do { check_iter 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 continue; case ESC_NOT_DIGIT: *pnew |= intrinsic_charsets continue; case ESC_SPACE: *pnew |= intrinsic_charsets continue; case ESC_NOT_SPACE: *pnew |= intrinsic_charsets continue; case ESC_WORD: *pnew |= intrinsic_charsets continue; case ESC_NOT_WORD: *pnew |= intrinsic_charsets 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 CHARSET_END != ( tok = sy.charset_token( icur, iend ) ) ); if( fhave_prev ) pnew->set_bit( ch_prev, fnocase ); pnew->optimize( type2type } template< typename CharT, typename SyntaxT > inline charset const * get_altern_charset( CharT ch, SyntaxT & sy ) { typedef std::basic_string charset const * pcharset = 0; regex::detail::charset_map typename regex::detail::charset_map 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 charset_map.erase( iter ); // prevent possible infinite recursion typename string_type::iterator ibegin = tmp.m_str.begin(); std::auto_ptr std::auto_ptr parse_charset 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 typename string_type::iterator & ipat, detail::match_group_base syntax_type & sy ) { typedef typename string_type::iterator iter_type; typedef typename std::iterator_traits 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 std::auto_ptr _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 } template< typename IterT, typename SyntaxT > inline bool basic_rpattern_base typename string_type::iterator & ipat, detail::match_group_base syntax_type & sy, std::vector { std::auto_ptr std::auto_ptr 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 break; case END_LINE: detail::reset_auto_ptr( pnew, detail::create_eol break; case BEGIN_CHARSET: detail::reset_auto_ptr( pcs, new( this->m_arena ) detail::custom_charset( this->m_arena ) ); detail::parse_charset pcs, ipat, this->m_pat->end(), sy ); detail::reset_auto_ptr( pnew, detail::create_custom_charset pcs.release(); break; case MATCH_ANY: detail::reset_auto_ptr( pnew, detail::create_any break; case ESC_WORD_BOUNDARY: detail::reset_auto_ptr( pnew, detail::create_word_boundary break; case ESC_NOT_WORD_BOUNDARY: detail::reset_auto_ptr( pnew, detail::create_word_boundary break; case ESC_WORD_START: detail::reset_auto_ptr( pnew, detail::create_word_start break; case ESC_WORD_STOP: detail::reset_auto_ptr( pnew, detail::create_word_stop break; case ESC_DIGIT: detail::reset_auto_ptr( pnew, detail::create_charset break; case ESC_NOT_DIGIT: detail::reset_auto_ptr( pnew, detail::create_charset break; case ESC_WORD: detail::reset_auto_ptr( pnew, detail::create_charset break; case ESC_NOT_WORD: detail::reset_auto_ptr( pnew, detail::create_charset break; case ESC_SPACE: detail::reset_auto_ptr( pnew, detail::create_charset break; case ESC_NOT_SPACE: detail::reset_auto_ptr( pnew, detail::create_charset break; case ESC_BEGIN_STRING: detail::reset_auto_ptr( pnew, detail::create_bos break; case ESC_END_STRING: detail::reset_auto_ptr( pnew, detail::create_eos break; case ESC_END_STRING_z: detail::reset_auto_ptr( pnew, detail::create_eoz 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 ++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 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 } } else if( REGEX_CHAR(char_type,'e') == *ipat ) { ++ipat; detail::reset_auto_ptr( pnew, detail::create_char } 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 } 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 } else if( REGEX_CHAR(char_type,'a') == *ipat && normalize ) { ++ipat; detail::reset_auto_ptr( pnew, detail::create_char } else if( REGEX_CHAR(char_type,'f') == *ipat && normalize ) { ++ipat; detail::reset_auto_ptr( pnew, detail::create_char } else if( REGEX_CHAR(char_type,'n') == *ipat && normalize ) { ++ipat; detail::reset_auto_ptr( pnew, detail::create_char } else if( REGEX_CHAR(char_type,'r') == *ipat && normalize ) { ++ipat; detail::reset_auto_ptr( pnew, detail::create_char } else if( REGEX_CHAR(char_type,'t') == *ipat && normalize ) { ++ipat; detail::reset_auto_ptr( pnew, detail::create_char } else if( REGEX_CHAR(char_type,'//') == *ipat && normalize ) { ++ipat; detail::reset_auto_ptr( pnew, detail::create_char } 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 else detail::reset_auto_ptr( pnew, detail::create_char ++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 // 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 std::auto_ptr 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 pnew.release(); detail::reset_auto_ptr( pnew, pquant.release() ); ipat = itemp; } } } template< typename IterT, typename SyntaxT > inline void basic_rpattern_base 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 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 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 } typedef regex::detail::select < REGEX_FOLD_INSTANTIATIONS && detail::is_convertible std::string::const_iterator, char const * >::type lpcstr_t; typedef regex::detail::select < REGEX_FOLD_INSTANTIATIONS && detail::is_convertible 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 { 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 { return _do_match_iterative( expr, param, icur, false_t() ); } template< typename IterT > REGEXPR_H_INLINE bool regex_access { return _do_match_iterative( expr, param, icur, true_t() ); } template< typename IterT > REGEXPR_H_INLINE bool regex_access { return static_cast } template< typename IterT > REGEXPR_H_INLINE bool regex_access { return static_cast } template< typename IterT > REGEX_NOINLINE bool regex_access { unsafe_stack s; param.m_pstack = &s; return _do_match_impl( pat, param, use_null ); } template< typename IterT > REGEXPR_H_INLINE bool regex_access { typedef bool ( *pfndomatch_t )( sub_expr_base 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 param.m_pfirst = pfirst; REGEX_ASSERT( param.m_cbackrefs == pat._cgroups_total() ); std::fill_n( param.m_prgbackrefs, param.m_cbackrefs, static_init 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 diff_type room = std::distance( param.m_imatchbegin, param.m_iend ); if( nwidth.m_min <= static_cast { IterT local_iend = param.m_iend; std::advance( local_iend, -static_cast 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 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 { }; 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 { static instantiator instantiate() { typedef typename std::iterator_traits void (*pfn)( char_type ) = &reset_intrinsic_charsets; return regex::basic_rpattern regex_access 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 { return instantiator(); } template< typename HeadT, typename TailT, typename SyntaxT > instantiator regex_instantiate( cons { typedef typename std::iterator_traits typedef typename SyntaxT::template rebind return rpattern_instantiator regex_instantiate( TailT(), type2type } // 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 typedef type2type typedef type2type 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 #include 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 { 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 { /*将字段名作为标题导出到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 { 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 { 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 { 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 { 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 { // 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.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 { 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 #include #include #include #include #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 typedef queue 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 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 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 { 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)