JSMin是一個很好的JS壓縮工具,只是使用時比較不方便,于是,我給它加了個GUI,增加了多線程支持,這樣,可以盡量提高JSMin的操作性。
//核心代碼
void JSMinDialog::DoOK(const wxString& srcPath,const wxString& destPath)
{
if(srcPath == destPath)
{
wxLog::OnLog(wxLOG_Error,wxT("源文件目錄下輸出目錄不能是同一個"),time(NULL));
return;
}
wxDir srcDir(srcPath);
wxDir destDir(destPath);
wxArrayString fiels;
size_t srcs = srcDir.GetAllFiles(srcPath, &fiels, wxT("*.js"));
wxString srcFileName;
wxString destFileName;
wxString destFilePath;
for(int i=0; i {
srcFileName = fiels.Item(i);
destFileName = srcFileName;
destFilePath = ::wxPathOnly(destFileName);
destFilePath.Replace(srcPath,destPath);
if(!::wxDirExists(destFilePath))
{
if(!::wxMkdir(destFilePath))
{
continue;
}
}
destFileName.Replace(srcPath,destPath);
CJSMin* js = new CJSMin(srcFileName,destFileName,wxT(""));
CJSMinThread* pThread = new CJSMinThread(js);
if(pThread->Create() != wxTHREAD_NO_ERROR)
{
delete js;
wxLog::OnLog(wxLOG_Error,wxT("生成") + destFileName + wxT("錯誤"),wxDateTime::GetTimeNow());
}
else
{
wxLog::OnLog(wxLOG_Message,wxT("處理")+srcFileName+wxT(" > ") + destFileName,wxDateTime::GetTimeNow());
pThread->Run();
}
}
}
#ifndef WXJSMIN_H_INCLUDED
#define WXJSMIN_H_INCLUDED
#include
#define INLINE inline
class CJSMin
{
private:
static const int eof = EOF;
private:
wxFile inf;
wxFile outf;
int theA;
int theB;
int theLookahead;
private:
INLINE void action(int d);
INLINE int isAlphanum(int c);
INLINE int get();
INLINE int next();
INLINE int peek();
public:
INLINE void jsmin();
public:
CJSMin(wxString src,wxString dest,wxString copyRiht):inf(src),outf(dest,wxFile::write),theLookahead(EOF){}
virtual ~CJSMin();
};
INLINE int CJSMin::isAlphanum(int c)
{
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
c > 126);
}
/* get -- return the next character from stdin. Watch out for lookahead. If
the character is a control character, translate it to a space or
linefeed.
*/
INLINE int CJSMin::get()
{
int c = theLookahead;
theLookahead = eof;
if (c == eof) {
char t = 0;
//c = getc(stdin);
if(!inf.Eof())
{
inf.Read(&t,1);
c = t;
}
else
{
c = eof;
}
}
if (c >= ' ' || c == '\n' || c == eof) {
return c;
}
if (c == '\r') {
return '\n';
}
return ' ';
}
/* peek -- get the next character without getting it.
*/
INLINE int CJSMin::peek()
{
theLookahead = get();
return theLookahead;
}
/* next -- get the next character, excluding comments. peek() is used to see
if a '/' is followed by a '/' or '*'.
*/
INLINE int CJSMin::next()
{
int c = get();
if (c == '/') {
switch (peek()) {
case '/':
for (;;) {
c = get();
if (c <= '\n') {
return c;
}
}
case '*':
get();
for (;;) {
switch (get()) {
case '*':
if (peek() == '/') {
get();
return ' ';
}
break;
case eof:
fprintf(stderr, "Error: JSMIN Unterminated comment.\n");
exit(1);
}
}
default:
return c;
}
}
return c;
}
/* action -- do something! What you do is determined by the argument:
1 Output A. Copy B to A. Get the next B.
2 Copy B to A. Get the next B. (Delete A).
3 Get the next B. (Delete B).
action treats a string as a single character. Wow!
action recognizes a regular expression if it is preceded by ( or , or =.
*/INLINE void CJSMin::action(int d)
{
switch (d) {
case 1:
//putc(theA, stdout);
outf.Write(&theA,1);
case 2:
theA = theB;
if (theA == '\'' || theA == '"') {
for (;;) {
//putc(theA, stdout);
outf.Write(&theA,1);
theA = get();
if (theA == theB) {
break;
}
if (theA == '\\') {
//putc(theA, stdout);
outf.Write(&theA,1);
theA = get();
}
if (theA == eof) {
fprintf(stderr, "Error: JSMIN unterminated string literal.");
exit(1);
}
}
}
case 3:
theB = next();
if (theB == '/' && (theA == '(' || theA == ',' || theA == '=' ||
theA == ':' || theA == '[' || theA == '!' ||
theA == '&' || theA == '|' || theA == '?' ||
theA == '{' || theA == '}' || theA == ';' ||
theA == '\n')) {
//putc(theA, stdout);
//putc(theB, stdout);
outf.Write(&theA,1);
outf.Write(&theB,1);
for (;;) {
theA = get();
if (theA == '/') {
break;
}
if (theA =='\\') {
//putc(theA, stdout);
outf.Write(&theA,1);
theA = get();
}
if (theA == eof) {
fprintf(stderr,
"Error: JSMIN unterminated Regular Expression literal.\n");
exit(1);
}
//putc(theA, stdout);
outf.Write(&theA,1);
}
theB = next();
}
}
}
/* jsmin -- Copy the input to the output, deleting the characters which are
insignificant to JavaScript. Comments will be removed. Tabs will be
replaced with spaces. Carriage returns will be replaced with linefeeds.
Most spaces and linefeeds will be removed.
*/
INLINE void CJSMin::jsmin()
{
theA = '\n';
action(3);
while (theA != eof) {
switch (theA) {
case ' ':
if (isAlphanum(theB)) {
action(1);
} else {
action(2);
}
break;
case '\n':
switch (theB) {
case '{':
case '[':
case '(':
case '+':
case '-':
action(1);
break;
case ' ':
action(3);
break;
default:
if (isAlphanum(theB)) {
action(1);
} else {
action(2);
}
}
break;
default:
switch (theB) {
case ' ':
if (isAlphanum(theA)) {
action(1);
break;
}
action(3);
break;
case '\n':
switch (theA) {
case '}':
case ']':
case ')':
case '+':
case '-':
case '"':
case '\'':
action(1);
break;
default:
if (isAlphanum(theA)) {
action(1);
} else {
action(3);
}
}
break;
default:
action(1);
break;
}
}
}
}
#endif // WXJSMIN_H_INCLUDED
#ifndef THREAD_H_INCLUDED
#define THREAD_H_INCLUDED
#include "wx/thread.h"
class CJSMin;
class CJSMinThread : public wxThread
{
CJSMin* m_jsmin;
public:
CJSMinThread(CJSMin* jsmin):m_jsmin(jsmin){}
public:
virtual void* Entry();
};
#endif // THREAD_H_INCLUDED
#include "../thread/thread.h"
#include "../jsmin/wxjsmin.h"
void* CJSMinThread::Entry()
{
m_jsmin->jsmin();
delete m_jsmin;
return NULL;
}
//核心代碼
void JSMinDialog::DoOK(const wxString& srcPath,const wxString& destPath)
{
if(srcPath == destPath)
{
wxLog::OnLog(wxLOG_Error,wxT("源文件目錄下輸出目錄不能是同一個"),time(NULL));
return;
}
wxDir srcDir(srcPath);
wxDir destDir(destPath);
wxArrayString fiels;
size_t srcs = srcDir.GetAllFiles(srcPath, &fiels, wxT("*.js"));
wxString srcFileName;
wxString destFileName;
wxString destFilePath;
for(int i=0; i
srcFileName = fiels.Item(i);
destFileName = srcFileName;
destFilePath = ::wxPathOnly(destFileName);
destFilePath.Replace(srcPath,destPath);
if(!::wxDirExists(destFilePath))
{
if(!::wxMkdir(destFilePath))
{
continue;
}
}
destFileName.Replace(srcPath,destPath);
CJSMin* js = new CJSMin(srcFileName,destFileName,wxT(""));
CJSMinThread* pThread = new CJSMinThread(js);
if(pThread->Create() != wxTHREAD_NO_ERROR)
{
delete js;
wxLog::OnLog(wxLOG_Error,wxT("生成") + destFileName + wxT("錯誤"),wxDateTime::GetTimeNow());
}
else
{
wxLog::OnLog(wxLOG_Message,wxT("處理")+srcFileName+wxT(" > ") + destFileName,wxDateTime::GetTimeNow());
pThread->Run();
}
}
}
#ifndef WXJSMIN_H_INCLUDED
#define WXJSMIN_H_INCLUDED
#include
#define INLINE inline
class CJSMin
{
private:
static const int eof = EOF;
private:
wxFile inf;
wxFile outf;
int theA;
int theB;
int theLookahead;
private:
INLINE void action(int d);
INLINE int isAlphanum(int c);
INLINE int get();
INLINE int next();
INLINE int peek();
public:
INLINE void jsmin();
public:
CJSMin(wxString src,wxString dest,wxString copyRiht):inf(src),outf(dest,wxFile::write),theLookahead(EOF){}
virtual ~CJSMin();
};
INLINE int CJSMin::isAlphanum(int c)
{
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
c > 126);
}
/* get -- return the next character from stdin. Watch out for lookahead. If
the character is a control character, translate it to a space or
linefeed.
*/
INLINE int CJSMin::get()
{
int c = theLookahead;
theLookahead = eof;
if (c == eof) {
char t = 0;
//c = getc(stdin);
if(!inf.Eof())
{
inf.Read(&t,1);
c = t;
}
else
{
c = eof;
}
}
if (c >= ' ' || c == '\n' || c == eof) {
return c;
}
if (c == '\r') {
return '\n';
}
return ' ';
}
/* peek -- get the next character without getting it.
*/
INLINE int CJSMin::peek()
{
theLookahead = get();
return theLookahead;
}
/* next -- get the next character, excluding comments. peek() is used to see
if a '/' is followed by a '/' or '*'.
*/
INLINE int CJSMin::next()
{
int c = get();
if (c == '/') {
switch (peek()) {
case '/':
for (;;) {
c = get();
if (c <= '\n') {
return c;
}
}
case '*':
get();
for (;;) {
switch (get()) {
case '*':
if (peek() == '/') {
get();
return ' ';
}
break;
case eof:
fprintf(stderr, "Error: JSMIN Unterminated comment.\n");
exit(1);
}
}
default:
return c;
}
}
return c;
}
/* action -- do something! What you do is determined by the argument:
1 Output A. Copy B to A. Get the next B.
2 Copy B to A. Get the next B. (Delete A).
3 Get the next B. (Delete B).
action treats a string as a single character. Wow!
action recognizes a regular expression if it is preceded by ( or , or =.
*/INLINE void CJSMin::action(int d)
{
switch (d) {
case 1:
//putc(theA, stdout);
outf.Write(&theA,1);
case 2:
theA = theB;
if (theA == '\'' || theA == '"') {
for (;;) {
//putc(theA, stdout);
outf.Write(&theA,1);
theA = get();
if (theA == theB) {
break;
}
if (theA == '\\') {
//putc(theA, stdout);
outf.Write(&theA,1);
theA = get();
}
if (theA == eof) {
fprintf(stderr, "Error: JSMIN unterminated string literal.");
exit(1);
}
}
}
case 3:
theB = next();
if (theB == '/' && (theA == '(' || theA == ',' || theA == '=' ||
theA == ':' || theA == '[' || theA == '!' ||
theA == '&' || theA == '|' || theA == '?' ||
theA == '{' || theA == '}' || theA == ';' ||
theA == '\n')) {
//putc(theA, stdout);
//putc(theB, stdout);
outf.Write(&theA,1);
outf.Write(&theB,1);
for (;;) {
theA = get();
if (theA == '/') {
break;
}
if (theA =='\\') {
//putc(theA, stdout);
outf.Write(&theA,1);
theA = get();
}
if (theA == eof) {
fprintf(stderr,
"Error: JSMIN unterminated Regular Expression literal.\n");
exit(1);
}
//putc(theA, stdout);
outf.Write(&theA,1);
}
theB = next();
}
}
}
/* jsmin -- Copy the input to the output, deleting the characters which are
insignificant to JavaScript. Comments will be removed. Tabs will be
replaced with spaces. Carriage returns will be replaced with linefeeds.
Most spaces and linefeeds will be removed.
*/
INLINE void CJSMin::jsmin()
{
theA = '\n';
action(3);
while (theA != eof) {
switch (theA) {
case ' ':
if (isAlphanum(theB)) {
action(1);
} else {
action(2);
}
break;
case '\n':
switch (theB) {
case '{':
case '[':
case '(':
case '+':
case '-':
action(1);
break;
case ' ':
action(3);
break;
default:
if (isAlphanum(theB)) {
action(1);
} else {
action(2);
}
}
break;
default:
switch (theB) {
case ' ':
if (isAlphanum(theA)) {
action(1);
break;
}
action(3);
break;
case '\n':
switch (theA) {
case '}':
case ']':
case ')':
case '+':
case '-':
case '"':
case '\'':
action(1);
break;
default:
if (isAlphanum(theA)) {
action(1);
} else {
action(3);
}
}
break;
default:
action(1);
break;
}
}
}
}
#endif // WXJSMIN_H_INCLUDED
#ifndef THREAD_H_INCLUDED
#define THREAD_H_INCLUDED
#include "wx/thread.h"
class CJSMin;
class CJSMinThread : public wxThread
{
CJSMin* m_jsmin;
public:
CJSMinThread(CJSMin* jsmin):m_jsmin(jsmin){}
public:
virtual void* Entry();
};
#endif // THREAD_H_INCLUDED
#include "../thread/thread.h"
#include "../jsmin/wxjsmin.h"
void* CJSMinThread::Entry()
{
m_jsmin->jsmin();
delete m_jsmin;
return NULL;
}