Unicode support for !define /file and !searchparse /file

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6329 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
anders_k 2013-04-10 02:51:33 +00:00
parent 936244da8d
commit 5fb2e9e166
2 changed files with 79 additions and 51 deletions

View file

@ -52,6 +52,31 @@ using namespace std;
#define MAX_INCLUDEDEPTH 10 #define MAX_INCLUDEDEPTH 10
static UINT read_line_helper(NStreamLineReader&lr, TCHAR*buf, UINT cch)
{
// Helper function for reading lines from text files. buf MUST be valid and cch MUST be > 1!
// Returns 0 on error or the number of characters read including the first \n, \r or \0.
// When it returns 0, buf[0] is 0 for EOF and NStream::ERR_* for errors.
UINT lrr = lr.ReadLine(buf, cch), eof = 0;
if (NStream::OK != lrr)
{
++eof;
if (!lr.IsEOF())
{
buf[0] = (TCHAR) lrr;
return 0;
}
}
const bool unicode = lr.IsUnicode();
for(cch = 0;; ++cch)
{
TCHAR ch = buf[cch];
if (!ch || NStream::IsNewline(ch, unicode)) break;
}
if (cch) eof = 0; // Read something, postpone EOF
return ++cch - eof;
}
#ifdef NSIS_SUPPORT_STANDARD_PREDEFINES #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES
// Added by Sunil Kamath 11 June 2003 // Added by Sunil Kamath 11 June 2003
TCHAR *CEXEBuild::set_file_predefine(const TCHAR *filename) TCHAR *CEXEBuild::set_file_predefine(const TCHAR *filename)
@ -3064,34 +3089,33 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
} else if (!_tcsicmp(define,_T("/file")) || !_tcsicmp(define,_T("/file_noerr"))) { } else if (!_tcsicmp(define,_T("/file")) || !_tcsicmp(define,_T("/file_noerr"))) {
if (line.getnumtokens()!=4) PRINTHELP() if (line.getnumtokens()!=4) PRINTHELP()
const TCHAR *const filename=line.gettoken_str(3), *const swit=define;
define=line.gettoken_str(2); NIStream filestrm;
const TCHAR *filename=line.gettoken_str(3); if (!filestrm.OpenFileForReading(filename)) {
FILE *fp=FOPENTEXT(filename,"r"); if (!swit[5]) { // "/file" vs "/file_noerr"
ERROR_MSG(_T("!define /file: file not found (\"%s\")\n"),filename);
if (!fp && _tcsicmp(define,_T("/file_noerr"))) { return PS_ERROR;
ERROR_MSG(_T("!define /file: file not found (\"%s\")\n"),filename); }
return PS_ERROR; } else {
} NStreamLineReader lr(filestrm);
TCHAR *str=m_templinebuf;
if (fp) { for (UINT linnum = 0;;) {
TCHAR *str=m_templinebuf; ++linnum;
for (;;) { UINT cch=read_line_helper(lr,str,MAX_LINELENGTH);
TCHAR *p=str; if (!cch) {
*p=0; if (*str) {
_fgetts(str,MAX_LINELENGTH,fp); tstring lrmsg=lr.GetErrorMessage((UINT)*str,filename,linnum);
linecnt++; ERROR_MSG(_T("!define %s: %s"),swit,lrmsg.c_str());
if (feof(fp)&&!str[0]) break; return PS_ERROR;
}
while (*p) p++; break; // EOF
if (p > str) p--; }
while (p >= str && (*p == _T('\r') || *p == _T('\n'))) p--; str[--cch]=_T('\0'); // Remove \r or \n, we always append \n
*++p=0; if (file_buf.getlen()) file_buf.add(_T("\n"),sizeof(TCHAR));
if (file_buf.getlen()) file_buf.add(_T("\n"),1); file_buf.add(str,cch*sizeof(TCHAR));
file_buf.add(str,_tcslen(str));
} }
fclose(fp);
} }
define = line.gettoken_str(2);
file_buf.add(_T("\0"),1); file_buf.add(_T("\0"),1);
value = (TCHAR *)file_buf.get(); value = (TCHAR *)file_buf.get();
@ -3359,9 +3383,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
return PS_OK; return PS_OK;
case TOK_P_SEARCHPARSESTRING: case TOK_P_SEARCHPARSESTRING:
{ {
bool ignCase=false; bool ignCase=false, noErrors=false, isFile=false;
bool noErrors=false;
bool isFile=false;
int parmOffs=1; int parmOffs=1;
while (parmOffs < line.getnumtokens()) while (parmOffs < line.getnumtokens())
{ {
@ -3381,34 +3403,40 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
if (isFile) if (isFile)
{ {
FILE *fp=FOPENTEXT(source_string,"r"); const TCHAR *const filename = source_string;
if (!fp) NIStream filestrm;
if (!filestrm.OpenFileForReading(filename))
{ {
ERROR_MSG(_T("!searchparse /file: error opening \"%s\"\n"),source_string); ERROR_MSG(_T("!searchparse /file: error opening \"%s\"\n"),filename);
return PS_ERROR; return PS_ERROR;
} }
int req_parm = (line.getnumtokens() - parmOffs)/2; int req_parm = (line.getnumtokens() - parmOffs)/2;
NStreamLineReader lr(filestrm);
GrowBuf tmpstr; GrowBuf tmpstr;
TCHAR *str=m_templinebuf; TCHAR *str=m_templinebuf;
UINT linnum=0;
for (;;) for (;;)
{ {
tmpstr.resize(0); tmpstr.resize(0);
for (;;) for (;;)
{ {
str[0]=0; ++linnum;
_fgetts(str,MAX_LINELENGTH,fp); UINT cch=read_line_helper(lr,str,MAX_LINELENGTH);
if (!str[0]) break; // eof if (!cch)
{
if (*str)
{
tstring lrmsg=lr.GetErrorMessage((UINT)*str,filename,linnum);
ERROR_MSG(_T("!searchparse: %s"),lrmsg.c_str());
return PS_ERROR;
}
break; // EOF
}
str[--cch]=_T('\0'); // remove newline
TCHAR *p=str; const bool endSlash = cch && _T('\\') == str[cch-1];
while (*p) p++; if (endSlash) --cch; // don't include the slash character
if (p > str) p--; if (tmpstr.getlen() || endSlash) tmpstr.add(str,cch*sizeof(TCHAR));
while (p >= str && (*p == _T('\r') || *p == _T('\n'))) p--;
*++p=0;
bool endSlash = (str[0] && str[_tcslen(str)-1] == _T('\\'));
if (tmpstr.getlen() || endSlash) tmpstr.add(str,sizeof(TCHAR)*_tcslen(str));
// if we have valid contents and not ending on slash, then done // if we have valid contents and not ending on slash, then done
if (!endSlash && (str[0] || tmpstr.getlen())) break; if (!endSlash && (str[0] || tmpstr.getlen())) break;
@ -3436,7 +3464,6 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
} }
// parse line // parse line
} }
fclose(fp);
if (!noErrors) if (!noErrors)
{ {
if (!list) if (!list)

View file

@ -387,23 +387,24 @@ tstring NStreamLineReader::GetErrorMessage(UINT Error, const TCHAR*Filename, UIN
switch(Error) switch(Error)
{ {
case NStream::ERR_BUFFEROVERFLOW: case NStream::ERR_BUFFEROVERFLOW:
msg = _T("Line too long: "); msg = _T("Line too long");
break; break;
case NStream::ERR_IOERROR: case NStream::ERR_IOERROR:
msg = _T("I/O error"), Filename = 0; msg = _T("I/O error"), Filename = 0;
break; break;
case NStream::ERR_UNSUPPORTEDENCODING: case NStream::ERR_UNSUPPORTEDENCODING:
StreamEncoding().GetCPDisplayName(buf); StreamEncoding().GetCPDisplayName(buf);
msg = tstring(buf) + _T(" is not supported"), Filename = 0; msg = tstring(buf) + _T(" is not supported"), Filename = 0;
break; break;
default: default:
msg = _T("Bad text encoding: "); msg = _T("Bad text encoding");
break; break;
} }
if (Filename) if (Filename)
{ {
_stprintf(buf,_T("%u"),Line); const TCHAR *filelinesep = *Filename ? _T(":") : _T("");
msg = msg + Filename + _T(":") + buf; _stprintf(buf,_T("%s%u"),filelinesep,Line);
msg = msg + _T(": ") + Filename + buf;
} }
return msg + _T("\n"); return msg + _T("\n");
} }