// ScanGenView.cpp : implementation of the CScanGenView class
//
#include "stdafx.h"
#include "ScanGen.h"
#include "ScanGenDoc.h"
#include "ScanGenView.h"
#include "direct.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CScanGenView
IMPLEMENT_DYNCREATE(CScanGenView, CFormView)
BEGIN_MESSAGE_MAP(CScanGenView, CFormView)
//{{AFX_MSG_MAP(CScanGenView)
ON_WM_SIZE()
ON_BN_CLICKED(IDC_BUTTON_OPEN, OnButtonOpen)
ON_BN_CLICKED(IDC_BUTTON_RUN, OnButtonRun)
ON_BN_CLICKED(IDC_BUTTON_FINAL, OnButtonFinal)
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CFormView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CFormView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CFormView::OnFilePrintPreview)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CScanGenView construction/destruction
CScanGenView::CScanGenView()
: CFormView(CScanGenView::IDD)
{
//{{AFX_DATA_INIT(CScanGenView)
m_strTokens = _T("");
m_bIgnoreCase = FALSE;
m_strTestSrc = _T("");
m_strSkip = _T("[ \\t\\v\\r\\n]*");
m_strTestOutput = _T("");
//}}AFX_DATA_INIT
// TODO: add construction code here
}
CScanGenView::~CScanGenView()
{
}
void CScanGenView::DoDataExchange(CDataExchange* pDX)
{
CFormView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CScanGenView)
DDX_Control(pDX, IDC_EDIT_SKIP, m_btnSkip);
DDX_Control(pDX, IDC_BUTTON_RUN, m_btnRun);
DDX_Control(pDX, IDC_BUTTON_OPEN, m_btnOpen);
DDX_Control(pDX, IDC_BUTTON_FINAL, m_btnFinal);
DDX_Control(pDX, IDC_EDIT_TEST_OUTPUT, m_editTestOutput);
DDX_Control(pDX, IDC_EDIT_TEST_SRC, m_editTestSrc);
DDX_Control(pDX, IDC_EDIT_SOURCE, m_editTokens);
DDX_Text(pDX, IDC_EDIT_SOURCE, m_strTokens);
DDX_Check(pDX, IDC_CHECK_IGNORECASE, m_bIgnoreCase);
DDX_Text(pDX, IDC_EDIT_TEST_SRC, m_strTestSrc);
DDX_Text(pDX, IDC_EDIT_SKIP, m_strSkip);
DDX_Text(pDX, IDC_EDIT_TEST_OUTPUT, m_strTestOutput);
//}}AFX_DATA_MAP
}
BOOL CScanGenView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CFormView::PreCreateWindow(cs);
}
void CScanGenView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit();
}
void CScanGenView::SetInitialExample()
{
static CString s_strTokens=
"AVAILABLE\tCANCELLED\tORDERED\tOUT-OF-PRINT\t,\t\\n\r\n"
"#T_ISBN= [0-9]\\-[0-9]+\\-[0-9]+\\-[0-9]\t"
"#T_TITLE= \"( [^\"\\n] | \\\\\" )* \"\r\n"
"#T_ERR_TITLE= \"( [^\"\\n\\0] | \\\\\" )* [\\n\\0] \r\n"
"$Int= [0-9]+\t##T_PRICE= $Int (\\. $Int)?";
static CString s_strHelp=
"THIS IS THE HELP: Next Line contains all supported constructs:\r\n"
"if\t#T_Quote= '[^']'\t$Int= [0-9]+\t##T_FLOAT= $Int (\\. $Int)?\r\n"
"Above line contains 3 tokens and one helper-definition, each separated by tabs (necessary)\r\n"
"1. Token (if):\t\t\tThe scanner searches for exactly the word 'if' and automagically creates a constant T_if for the token\r\n"
"2. Token (#T_Quote= '[^']'):\tThe leading # means: The next identifier up to the = is the name of the token constant, after the = the token definition follows.\r\n"
"3. Helper ($Int= [0-9]+):\t Defines a helper definition, which can be used later.\r\n"
"4. Token (##T_FLOAT= $Int (\\. $Int)?):\t The leading ## means: Same as # but do postprocessing after recognizing this token.";
if( ::IsWindow(m_editTokens.m_hWnd)){
UpdateData();
}
if( s_strTokens==m_strTokens ){
m_strTokens="";
m_strTestSrc= "";
m_bIgnoreCase= false;
m_strSkip= "[ \\t\\v\\r\\n]*";
}else{
m_strTokens= s_strTokens;
m_strTestSrc= "3-8272-5737-9,AVAILABLE, 72.50,\t\"XML praxis und referenz\"\r\n"
"0-201-05866-9,cancelled,150.75,\t\"Parallel Program Design\"\r\n"
"0-13-637331-3,ORDERED,50.00,\t\"Operating Systems\r\n"
"7-9423-4342-1,OUT-OF-PRINT,100,\"Witchcraft and Computing\"\r\n";
m_strTestOutput= s_strHelp;
m_bIgnoreCase= true;
m_strSkip= "[ \\t\\v\\r]*";
}
UpdateData(false);
}
/////////////////////////////////////////////////////////////////////////////
// CScanGenView printing
BOOL CScanGenView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
void CScanGenView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void CScanGenView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
void CScanGenView::OnPrint(CDC* pDC, CPrintInfo* /*pInfo*/)
{
// TODO: add customized printing code here
}
/////////////////////////////////////////////////////////////////////////////
// CScanGenView diagnostics
#ifdef _DEBUG
void CScanGenView::AssertValid() const
{
CFormView::AssertValid();
}
void CScanGenView::Dump(CDumpContext& dc) const
{
CFormView::Dump(dc);
}
CScanGenDoc* CScanGenView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CScanGenDoc)));
return (CScanGenDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CScanGenView message handlers
void CScanGenView::OnSize(UINT nType, int cx, int cy)
{
CFormView::OnSize(nType, cx, cy);
if( cx>0 && cy>0 && ::IsWindow(m_editTokens.m_hWnd)){
SetScrollSizes(MM_TEXT, CSize(cx,cy));
CRect rect;
m_editTokens.GetWindowRect(rect);
ScreenToClient(&rect);
m_editTokens.SetWindowPos(NULL,0,0, cx-10-rect.left,cy/2-10,
SWP_NOMOVE|SWP_NOZORDER);
m_btnOpen.SetWindowPos(NULL,rect.left,cy/2+20,0,0,SWP_NOSIZE|SWP_NOZORDER);
m_btnRun.SetWindowPos(NULL,cx/2+10,cy/2+20,0,0,SWP_NOSIZE|SWP_NOZORDER);
m_editTestSrc.SetWindowPos(NULL,rect.left,cy/2+45,cx/2-10-rect.left,cy/2-45,SWP_NOZORDER);
m_editTestOutput.SetWindowPos(NULL,cx/2+10,cy/2+45,cx/2-10-rect.left,cy/2-45,SWP_NOZORDER);
}
}
void CScanGenView::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
UpdateData();
ar << m_strTokens;
ar << m_strSkip;
ar << m_bIgnoreCase;
}
else
{
ar >> m_strTokens;
ar >> m_strSkip;
ar >> m_bIgnoreCase;
UpdateData(false);
}
}
void CScanGenView::OnButtonOpen()
{
CFileDialog dlg(true);
if( dlg.DoModal()==IDOK ){
CFile file;
if( file.Open(dlg.GetPathName(),CFile::modeRead) ){
CString str;
file.Read(str.GetBufferSetLength(file.GetLength()),file.GetLength());
m_editTestSrc.SetWindowText(str);
}
}
}
bool CScanGenView::HasError(REXI_DefErr err)
{
if( err.eErrCode!= REXI_DefErr::eNoErr ){
AfxMessageBox(err.strErrMsg.c_str());
m_editTokens.SetFocus();
m_editTokens.SetSel(err.nErrOffset,err.nErrOffset);
return true;
}
return false;
}
void CScanGenView::OnButtonRun()
{
CWaitCursor wait;
UpdateData();
pair<REXI_DefErr,CScanGeneratedScanner> res;
CString strTokens= m_strTokens+"\n\n";
CString strSkip= m_strSkip+"\n\n";
res= m_scanGenAlgo.GenScanner(strTokens,strSkip,m_bIgnoreCase?true:false);
if( HasError(res.first) ){
return;
}
m_btnFinal.EnableWindow(true);
GetDlgItem(IDC_EDIT_TEST_OUTPUT)->SetWindowText("");
REXI_DefErr err= res.second.InitScanner(m_strTestSrc);
if( HasError(err) ){
return;
}
string strTokenId;
int nOfLineBreaksBefore,nNofLineBreaksIn;
string strOutput;
int nAnswer;
while((nAnswer=res.second.Scan(strTokenId,nOfLineBreaksBefore,nNofLineBreaksIn))!=REXA_DFAState::eEos){
int i;
for(i=0;i<nOfLineBreaksBefore;i++){
strOutput+= "\r\n";
}
strOutput+= strTokenId + " ";
for(i=0;i<nNofLineBreaksIn;i++){
strOutput+= "\r\n";
}
}
m_strTestOutput= strOutput.c_str();
UpdateData(false);
}
string CScanGenView::GetScannerName()
{
m_strScannerName= GetDocument()->GetTitle();
string::size_type n;
if((n=m_strScannerName.rfind('.'))!=string::npos ){
m_strScannerName= m_strScannerName.substr(0,n);
}
for(int i=0;i<m_strScannerName.size();i++){
if(!isalnum(m_strScannerName[i])){
m_strScannerName[i]= '_';
}
}
return m_strScannerName;
}
string CScanGenView::CreateScannerDir(string strScannerName)
{
char aFileName[1024];
unsigned nRes= GetModuleFileName(NULL,aFileName,sizeof(aFileName)-1);
string strDir(aFileName);
string::size_type nPos;
if( (nPos=strDir.rfind('\\')) != string::npos ){
strDir= strDir.substr(0,nPos);
if( (nPos=strDir.rfind('\\')) != string::npos
&& strDir.substr(0,nPos).rfind('\\')!=string::npos ){
strDir= strDir.substr(0,nPos);
}
}
strDir+= "\\"+strScannerName;
mkdir(strDir.c_str());
return strDir;
}
void CScanGenView::SaveToFile(string strFileName,string strFileContent)
{
CFile file;
if( file.Open(strFileName.c_str(),CFile::modeCreate|CFile::modeWrite) ){
file.Write(strFileContent.c_str(),strFileContent.size());
}
}
bool CScanGenView::FindThis(string s, string sToFind,string& sVers)
{
string::size_type n= s.find(sToFind);
if( n!=string::npos && n+sToFind.size()+2 < s.size() ){
string sFound= s.substr(n+sToFind.size(),2);
if( isdigit(sFound[0])&&isdigit(sFound[1]) ){
sVers= sFound;
return true;
}
}
return false;
}
bool CScanGenView::GetVersionInfo(string strFileName,string& sMajor,string& sMinor)
{
bool bFound= false;
CFile file;
if( file.Open(strFileName.c_str(),CFile::modeRead) ){
const string sToFind("::m_pcszVersMajor[3]=\"");
string s(file.GetLength()+1,'\0');
file.Read((void*)s.c_str(),file.GetLength());
bFound= FindThis(s,"::m_pcszVersMajor[3]=\"",sMajor)
&& FindThis(s,"::m_pcszVersMinor[3]=\"",sMinor);
}
return bFound;
}
bool CScanGenView::ExistsFile(string strFileName)
{
CFile file;
return file.Open(strFileName.c_str(),CFile::modeRead)!=0;
}
void CScanGenView::GenSourceFiles(CScanGeneratedScanner& rScanner)
{
Sources sources;
string sMinor="00",sMajor="01";
string strScannerDir= CreateScannerDir(m_strScannerName);
string strBaseFileName= strScannerDir+"\\"+m_strScannerName;
if( GetVersionInfo(strBaseFileName+".cpp",sMajor,sMinor) ){
if( sMinor[1]=='9' ){
sMinor[0]= (sMinor[0]-'0')+1+'0';
sMinor[1]= '0';
}else{
sMinor[1]= (sMinor[1]-'0')+1+'0';
}
}
if( rScanner.GenSourceCode(m_strScannerName.c_str(),sMajor,sMinor,sources) ){
SaveToFile(strBaseFileName+".h",sources.m_headerCpp.first);
SaveToFile(strBaseFileName+".cpp",sources.m_headerCpp.second);
SaveToFile(strBaseFileName+"Main.cpp",sources.m_strMain);
if( !ExistsFile(strBaseFileName+".dsp") ){
SaveToFile(strBaseFileName+".dsp",sources.m_strDsp);
}
}
}
void CScanGenView::OnButtonFinal()
{
UpdateData();
CWaitCursor wait;
pair<REXI_DefErr,CScanGeneratedScanner> res;
CString strTokens= m_strTokens+"\n\n";
CString strSkip= m_strSkip+ "\n\n";
res= m_scanGenAlgo.GenScanner(strTokens,strSkip,m_bIgnoreCase?true:false);
if( HasError(res.first) ){
return;
}
GetScannerName();
GenSourceFiles(res.second);
}