Merge pull request #8571 from keymanapp/chore/developer/8570-SetError

chore(developer): AddWarning and SetError cleanup
This commit is contained in:
Marc Durdin 2023-04-11 13:06:18 +10:00 committed by GitHub
commit bb717346cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 545 additions and 415 deletions

View file

@ -2,7 +2,7 @@
#include <string>
#include <iostream>
#include "../test_assert.h"
#include <test_assert.h>
namespace
{

View file

@ -18,7 +18,7 @@
#include "action_items.hpp"
#include "debug_items.hpp"
#include "../test_assert.h"
#include <test_assert.h>
#include "../emscripten_filesystem.h"
using namespace km::kbp::kmx;

View file

@ -4,7 +4,7 @@
#include "kmx/kmx_base.h"
#include "kmx/kmx_xstring.h"
#include "../test_assert.h"
#include <test_assert.h>
using namespace km::kbp::kmx;

View file

@ -15,7 +15,7 @@
#include "state.hpp"
#include "action_items.hpp"
#include "../test_assert.h"
#include <test_assert.h>
#if defined(__GNUC__) || defined(__clang__)
#define PRAGMA(X) _Pragma(#X)

View file

@ -13,7 +13,7 @@
#include "../../../src/kmx/kmx_context.h"
#include "../../../src/kmx/kmx_processevent.h" // for Debug_UnicodeString
#include "../../../src/kmx/kmx_xstring.h"
#include "../test_assert.h"
#include <test_assert.h>
using namespace km::kbp::kmx;
using namespace std;

View file

@ -19,7 +19,7 @@
#include <string>
#include "../../../src/kmx/kmx_xstring.h"
#include <kmx_file.h>
#include "../test_assert.h"
#include <test_assert.h>
using namespace km::kbp::kmx;
using namespace std;

View file

@ -24,8 +24,8 @@
#include "state.hpp"
#include "utfcodec.hpp"
#include "../test_assert.h"
#include "../test_color.h"
#include <test_assert.h>
#include <test_color.h>
#include "../emscripten_filesystem.h"
#include "kmx_test_source.hpp"

View file

@ -11,8 +11,8 @@
#include "path.hpp"
#include "state.hpp"
#include "../kmnkbd/action_items.hpp"
#include "../test_assert.h"
#include "../test_color.h"
#include <test_assert.h>
#include <test_color.h>
#include "../emscripten_filesystem.h"
#include <map>

View file

@ -12,8 +12,8 @@
#include "state.hpp"
#include <map>
#include "../test_assert.h"
#include "../test_color.h"
#include <test_assert.h>
#include <test_color.h>
#include "../emscripten_filesystem.h"
using namespace km::kbp::kmx;

View file

@ -21,8 +21,8 @@
#include "state.hpp"
#include "utfcodec.hpp"
#include "../test_assert.h"
#include "../test_color.h"
#include <test_assert.h>
#include <test_color.h>
#include <kmx/kmx_xstring.h> // for surrogate pair macros

View file

@ -45,7 +45,7 @@
namespace km {
namespace tests {
#include "../test_color.h"
#include <test_color.h>
LdmlTestSource::LdmlTestSource() {

View file

@ -1,4 +1,4 @@
#include "../test_assert.h"
#include <test_assert.h>
#include "kmx/kmx_plus.h"
#include "kmx/kmx_xstring.h"
#include "../../../src/ldml/ldml_vkeys.hpp"

View file

@ -1,7 +1,7 @@
/*
TODO: implement additional interfaces:
extern "C" uint32_t kmcmp_CompileKeyboardFileToBuffer(
extern "C" bool kmcmp_CompileKeyboardFileToBuffer(
char* pszInfile,
void* pfkBuffer,
bool ACompilerWarningsAsErrors,

View file

@ -90,19 +90,7 @@
#include "UnreachableRules.h"
#include "CheckForDuplicates.h"
/*
Following kmcmplib definitions are translated to Windows types
because we can't import the kmcmplib headers. The structure
sizes and alignments have been manually verified.
*/
#include "../kmcmplib/include/kmcmplibapi.h"
/*typedef int (*kmcmp_CompilerMessageProc)(int line, KMX_DWORD dwMsgCode, PKMX_STR szText, void* context);
extern "C" BOOL kmcmp_CompileKeyboardFile(PSTR pszInfile, PSTR pszOutfile, BOOL FSaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgProc, void* context); // I4865 // I4866
extern "C" BOOL kmcmp_CompileKeyboardFileToBuffer(PSTR pszInfile, void* pfkBuffer, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgProc, void* context, int Target); // I4865 // I4866
extern "C" void kmcmp_Keyman_Diagnostic(int mode) ;
extern "C" BOOL kmcmp_SetCompilerOptions(PCOMPILER_OPTIONS options);*/
int xatoi(PWSTR *p);
int atoiW(PWSTR p);

View file

@ -52,7 +52,6 @@ Libraries will be built in 'build/<target>/<configuration>/src'.
"build" \
"test" \
"${archtargets[@]}" \
"--debug,-d configuration is 'debug', not 'release'" \
"--test=opt_tests,-t test[s] to run (space separated)"
builder_parse "$@"

View file

@ -25,7 +25,7 @@ EXTERN bool kmcmp_SetCompilerOptions(
typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, char* szText, void* context);
EXTERN uint32_t kmcmp_CompileKeyboardFile(
EXTERN bool kmcmp_CompileKeyboardFile(
char* pszInfile,
char* pszOutfile,
bool ASaveDebug,
@ -35,7 +35,12 @@ EXTERN uint32_t kmcmp_CompileKeyboardFile(
void* AmsgprocContext
);
EXTERN uint32_t kmcmp_CompileKeyboardFileToBuffer(
/* Compile target */
#define CKF_KEYMAN 0
#define CKF_KEYMANWEB 1
EXTERN bool kmcmp_CompileKeyboardFileToBuffer(
char* pszInfile,
void* pfkBuffer,
bool ACompilerWarningsAsErrors,

View file

@ -87,7 +87,7 @@ bool CheckNCapsConsistency(PFILE_KEYBOARD fk) {
if (caps_ncaps_usage[i].neither_line && (caps_ncaps_usage[i].caps_line || caps_ncaps_usage[i].ncaps_line)) {
// We set the current line to one needing work: the developer should add the NCAPS flag
kmcmp::currentLine = caps_ncaps_usage[i].neither_line;
AddWarning(CWARN_KeyShouldIncludeNCaps);
AddWarningBool(CWARN_KeyShouldIncludeNCaps);
}
}

View file

@ -94,7 +94,6 @@
#include "CasedKeys.h"
#include <vector>
#include <xstring.h>
#include "CheckNCapsConsistency.h"
#include "CheckFilenameConsistency.h"
#include "UnreachableRules.h"
#include "CheckForDuplicates.h"
@ -126,11 +125,9 @@ namespace kmcmp{
int BeginLine[4];
KMX_BOOL IsValidCallStore(PFILE_STORE fs);
void RecordDeadkeyNames(PFILE_KEYBOARD fk);
KMX_DWORD AddCompilerVersionStore(PFILE_KEYBOARD fk);
KMX_BOOL CheckStoreUsage(PFILE_KEYBOARD fk, int storeIndex, KMX_BOOL fIsStore, KMX_BOOL fIsOption, KMX_BOOL fIsCall);
int UTF32ToUTF16(int n, int *n1, int *n2);
int CheckUTF16(int n);
KMX_DWORD UTF32ToUTF16(int n, int *n1, int *n2);
KMX_DWORD CheckUTF16(int n);
int cmpkeys(const void *key, const void *elem);
}
@ -145,13 +142,7 @@ PKMX_WCHAR GetDelimitedString(PKMX_WCHAR *p, KMX_WCHAR const * Delimiters, KMX_W
KMX_DWORD GetXString(PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX_WCHAR const * token, PKMX_WCHAR output, int max, int offset, PKMX_WCHAR *newp, int isVKey, int isUnicode);
int GetGroupNum(PFILE_KEYBOARD fk, PKMX_WCHAR p);
int LineTokenType(PKMX_WCHAR *str);
KMX_DWORD ParseLine(PFILE_KEYBOARD fk, PKMX_WCHAR str);
KMX_DWORD ProcessGroupFinish(PFILE_KEYBOARD fk);
KMX_DWORD ProcessGroupLine(PFILE_KEYBOARD fk, PKMX_WCHAR p);
KMX_DWORD ProcessStoreLine(PFILE_KEYBOARD fk, PKMX_WCHAR p);
KMX_DWORD AddDebugStore(PFILE_KEYBOARD fk, KMX_WCHAR const * str);
KMX_DWORD ProcessKeyLine(PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX_BOOL IsUnicode);
KMX_DWORD ProcessEthnologueStore(PKMX_WCHAR p); // I2646
@ -160,14 +151,7 @@ KMX_DWORD ImportBitmapFile(PFILE_KEYBOARD fk, PKMX_WCHAR szName, PKMX_DWORD File
KMX_DWORD ExpandKp(PFILE_KEYBOARD fk, PFILE_KEY kpp, KMX_DWORD storeIndex);
KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess);
KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, FILE* fp_out);
KMX_BOOL CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk);
int GetVKCode(PFILE_KEYBOARD fk, PKMX_WCHAR p); // I3438 // TODO: Consolidate GetDeadKey and GetVKCode?
KMX_DWORD BuildVKDictionary(PFILE_KEYBOARD fk); // I3438
KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, KMX_WCHAR const * str, KMX_DWORD *dwStoreID= NULL);
KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE sp);
KMX_DWORD process_if(PFILE_KEYBOARD fk, PKMX_WCHAR q, PKMX_WCHAR tstr, int *mx);
@ -181,8 +165,6 @@ KMX_DWORD process_expansion(PFILE_KEYBOARD fk, PKMX_WCHAR q, PKMX_WCHAR tstr, in
KMX_BOOL IsValidKeyboardVersion(KMX_WCHAR *dpString);
FILE* UTF16TempFromUTF8(FILE* fp_in , KMX_BOOL hasPreamble);
const KMX_WCHAR * LineTokens[] = {
u"SVNBHBGMNSCCLLCMLB", u"store", u"VERSION ", u"NAME ",
u"BITMAP ", u"HOTKEY ", u"begin", u"group", u"match", u"nomatch",
@ -251,12 +233,7 @@ void* msgprocContext = NULL;
int kmcmp::currentLine = 0;
kmcmp::NamedCodeConstants *CodeConstants = NULL;
/* Compile target */
#define CKF_KEYMAN 0
#define CKF_KEYMANWEB 1
kmcmp::NamedCodeConstants *kmcmp::CodeConstants = NULL;
PKMX_WCHAR strtowstr(PKMX_STR in)
{
@ -322,342 +299,6 @@ KMX_BOOL AddCompileError(KMX_DWORD msg)
return FALSE;
}
EXTERN bool kmcmp_SetCompilerOptions(KMCMP_COMPILER_OPTIONS* options) {
//printf("°°-> changed to SetCompilerOptions() of kmcmplib \n");
if(!options || options->dwSize < sizeof(KMCMP_COMPILER_OPTIONS)) {
return FALSE;
}
kmcmp::FShouldAddCompilerVersion = options->ShouldAddCompilerVersion;
return TRUE;
}
#ifdef __EMSCRIPTEN__
/*
WASM interface for compiler message callback
*/
EM_JS(int, wasm_msgproc, (int line, int msgcode, char* text, char* context), {
const proc = globalThis[context];
if(!proc || typeof proc != 'function') {
console.log(`[${line}: ${msgcode}: ${UTF8ToString(text)}]`);
return 0;
} else {
return proc(line, msgcode, UTF8ToString(text));
}
});
int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, char* szText, void* context) {
char* msgProc = static_cast<char*>(context);
return wasm_msgproc(line, dwMsgCode, szText, msgProc);
}
EXTERN uint32_t kmcmp_Wasm_SetCompilerOptions(int ShouldAddCompilerVersion) {
KMCMP_COMPILER_OPTIONS options;
options.dwSize = sizeof(KMCMP_COMPILER_OPTIONS);
options.ShouldAddCompilerVersion = ShouldAddCompilerVersion;
return kmcmp_SetCompilerOptions(&options);
}
EXTERN uint32_t kmcmp_Wasm_CompileKeyboardFile(char* pszInfile,
char* pszOutfile, int ASaveDebug, int ACompilerWarningsAsErrors,
int AWarnDeprecatedCode, char* msgProc
) {
return kmcmp_CompileKeyboardFile(
pszInfile,
pszOutfile,
ASaveDebug,
ACompilerWarningsAsErrors,
AWarnDeprecatedCode,
wasm_CompilerMessageProc,
msgProc
);
}
#endif
EXTERN uint32_t kmcmp_CompileKeyboardFile(char* pszInfile,
char* pszOutfile, bool ASaveDebug, bool ACompilerWarningsAsErrors,
bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext
) {
FILE* fp_in = NULL;
FILE* fp_out = NULL;
KMX_BOOL err;
KMX_CHAR str[260];
//printf("°°-> changed to CompileKeyboardFile() of kmcmplib \n");
kmcmp::FSaveDebug = ASaveDebug;
kmcmp::FCompilerWarningsAsErrors = ACompilerWarningsAsErrors; // I4865
AWarnDeprecatedCode_GLOBAL_LIB = AWarnDeprecatedCode;
kmcmp::CompileTarget = CKF_KEYMAN;
if (!pMsgproc || !pszInfile || !pszOutfile) SetError(CERR_BadCallParams);
PKMX_STR p;
if ((p = strrchr_slash(pszInfile)) != nullptr)
{
strncpy(kmcmp::CompileDir, pszInfile, (int)(p - pszInfile + 1)); // I3481
kmcmp::CompileDir[(int)(p - pszInfile + 1)] = 0;
}
else
kmcmp::CompileDir[0] = 0;
msgproc = pMsgproc;
msgprocContext = AmsgprocContext;
kmcmp::currentLine = 0;
kmcmp::nErrors = 0;
fp_in = Open_File(pszInfile, "rb");
if (fp_in == NULL) SetError(CERR_InfileNotExist);
// Transfer the file to a memory stream for processing UTF-8 or ANSI to UTF-16?
// What about really large files? Transfer to a temp file...
if (!fread(str, 1, 3, fp_in))
{
fclose(fp_in);
return CERR_CannotReadInfile;
}
fseek(fp_in, 0, SEEK_SET);
if (str[0] == UTF8Sig[0] && str[1] == UTF8Sig[1] && str[2] == UTF8Sig[2])
fp_in = UTF16TempFromUTF8(fp_in, TRUE);
else if (str[0] == UTF16Sig[0] && str[1] == UTF16Sig[1])
fseek(fp_in, 2, SEEK_SET);
else
fp_in = UTF16TempFromUTF8(fp_in, FALSE);
if (fp_in == NULL)
{
return CERR_CannotCreateTempfile;
}
fp_out = Open_File(pszOutfile, "wb");
if (fp_out == NULL) SetError(CERR_CannotCreateOutfile);
KMX_DWORD msg;
FILE_KEYBOARD fk;
CodeConstants = new kmcmp::NamedCodeConstants;
err = CompileKeyboardHandle(fp_in, &fk);
if (err)
{
if ((msg = WriteCompiledKeyboard(&fk, fp_out)) != CERR_None)
AddCompileError(msg);
}
else
AddCompileError(CERR_InvalidValue);
fclose(fp_in);
fclose(fp_out);
delete CodeConstants;
if (kmcmp::nErrors > 0)
{
remove(pszOutfile);
return FALSE;
}
return err;
}
EXTERN uint32_t kmcmp_CompileKeyboardFileToBuffer(char* pszInfile, void* pfkBuffer, bool ACompilerWarningsAsErrors, bool AWarnDeprecatedCode,
kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext, int Target) // I4865 // I4866
{
//printf("°°-> changed to CompileKeyboardFileToBuffer() of kmcmplib \n");
FILE* fp_in = NULL;
KMX_BOOL err;
KMX_CHAR str[260];
kmcmp::FSaveDebug = TRUE; // I3681
kmcmp::FCompilerWarningsAsErrors = ACompilerWarningsAsErrors; // I4865
AWarnDeprecatedCode_GLOBAL_LIB = AWarnDeprecatedCode;
kmcmp::CompileTarget = Target;
if (!pMsgproc || !pszInfile || !pfkBuffer) SetError(CERR_BadCallParams);
PKMX_STR p;
if ((p = strrchr_slash(pszInfile)) != nullptr)
{
strncpy(kmcmp::CompileDir, pszInfile, (int)(p - pszInfile + 1)); // I3481
kmcmp::CompileDir[(int)(p - pszInfile + 1)] = 0;
}
else
kmcmp::CompileDir[0] = 0;
msgproc = pMsgproc;
msgprocContext = AmsgprocContext;
kmcmp::currentLine = 0;
kmcmp::nErrors = 0;
fp_in = Open_File(pszInfile,"rb");
if (fp_in == NULL) SetError(CERR_InfileNotExist);
// Transfer the file to a memory stream for processing UTF-8 or ANSI to UTF-16?
// What about really large files? Transfer to a temp file...
if( !fread(str,1,3,fp_in))
{
fclose(fp_in);
return CERR_CannotReadInfile;
}
fseek( fp_in,0,SEEK_SET);
if (str[0] == UTF8Sig[0] && str[1] == UTF8Sig[1] && str[2] == UTF8Sig[2])
fp_in = UTF16TempFromUTF8(fp_in, TRUE);
else if (str[0] == UTF16Sig[0] && str[1] == UTF16Sig[1])
fseek( fp_in,2,SEEK_SET);
else
fp_in = UTF16TempFromUTF8(fp_in, FALSE);
CodeConstants = new kmcmp::NamedCodeConstants;
err = CompileKeyboardHandle(fp_in, static_cast<PFILE_KEYBOARD>(pfkBuffer));
delete CodeConstants;
fclose(fp_in);
if (kmcmp::nErrors > 0)
return FALSE;
return err;
}
KMX_BOOL CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk)
{
PKMX_WCHAR str, p;
KMX_DWORD msg;
kmcmp::FMnemonicLayout = FALSE;
if (!fk) {
SetError(CERR_SomewhereIGotItWrong);
}
str = new KMX_WCHAR[LINESIZE];
if (!str) {
SetError(CERR_CannotAllocateMemory);
}
fk->KeyboardID = 0;
fk->version = 0;
fk->dpStoreArray = NULL;
fk->dpGroupArray = NULL;
fk->cxStoreArray = 0;
fk->cxGroupArray = 0;
fk->StartGroup[0] = fk->StartGroup[1] = -1;
fk->szName[0] = 0;
fk->szCopyright[0] = 0;
fk->dwFlags = KF_AUTOMATICVERSION;
fk->currentGroup = 0xFFFFFFFF;
fk->currentStore = 0;
fk->cxDeadKeyArray = 0;
fk->dpDeadKeyArray = NULL;
fk->cxVKDictionary = 0; // I3438
fk->dpVKDictionary = NULL; // I3438
/* fk->szMessage[0] = 0;
fk->szLanguageName[0] = 0;*/
fk->dwBitmapSize = 0;
fk->dwHotKey = 0;
kmcmp::BeginLine[BEGIN_ANSI] = -1;
kmcmp::BeginLine[BEGIN_UNICODE] = -1;
kmcmp::BeginLine[BEGIN_NEWCONTEXT] = -1;
kmcmp::BeginLine[BEGIN_POSTKEYSTROKE] = -1;
/* Add a store for the Keyman 6.0 copyright information string */
if(kmcmp::FShouldAddCompilerVersion) {
u16sprintf(str,LINESIZE, L"Created with Keyman Developer version %d.%d.%d.%d", KEYMAN_VersionMajor, KEYMAN_VersionMinor, KEYMAN_VersionPatch, 0);
AddStore(fk, TSS_KEYMANCOPYRIGHT, str);
}
/* Add a system store for the Keyman edition number */
u16sprintf(str, LINESIZE, L"%d", 0); // I3481
AddStore(fk, TSS_CUSTOMKEYMANEDITION, str);
PKMX_WCHAR tbuf = strtowstr((KMX_CHAR*) "Keyman");
AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, tbuf);
delete tbuf;
// must preprocess for group and store names -> this isn't really necessary, but never mind!
while ((msg = ReadLine(fp_in, str, TRUE)) == CERR_None)
{
p = str;
switch (LineTokenType(&p))
{
case T_VERSION:
*(p + 4) = 0;
if ((msg = AddStore(fk, TSS_VERSION, p)) != CERR_None) SetError(msg);
break;
case T_GROUP:
if ((msg = ProcessGroupLine(fk, p)) != CERR_None) SetError(msg);
break;
case T_STORE:
if ((msg = ProcessStoreLine(fk, p)) != CERR_None) SetError(msg);
break;
default:
break;
}
}
if (msg != CERR_EndOfFile) SetError(msg);
fseek( fp_in,2,SEEK_SET);
kmcmp::currentLine = 0;
/* Reindex the list of codeconstants after stores added */
CodeConstants->reindex();
/* ReadLine will automatically skip over $Keyman lines, and parse wrapped lines */
while ((msg = ReadLine(fp_in, str, FALSE)) == CERR_None)
{
msg = ParseLine(fk, str);
if (msg != CERR_None) SetError(msg);
}
if (msg != CERR_EndOfFile) SetError(msg);
ProcessGroupFinish(fk);
if (kmcmp::FSaveDebug) kmcmp::RecordDeadkeyNames(fk);
/* Add the compiler version as a system store */
if ((msg = kmcmp::AddCompilerVersionStore(fk)) != CERR_None) SetError(msg);
if ((msg = BuildVKDictionary(fk)) != CERR_None) SetError(msg); // I3438
if ((msg = CheckFilenameConsistencyForCalls(fk)) != CERR_None) SetError(msg);
delete str;
if (!kmcmp::CheckKeyboardFinalVersion(fk)) {
return FALSE;
}
/* Warn on inconsistent use of NCAPS */
if (!kmcmp::FMnemonicLayout) {
CheckNCapsConsistency(fk);
}
/* Flag presence of deprecated features */
kmcmp::CheckForDeprecatedFeatures(fk);
return TRUE;
}
KMX_DWORD ProcessBeginLine(PFILE_KEYBOARD fk, PKMX_WCHAR p)
{
KMX_WCHAR tstr[128];
@ -1126,10 +767,10 @@ KMX_DWORD ProcessStoreLine(PFILE_KEYBOARD fk, PKMX_WCHAR p)
VERIFY_KEYBOARD_VERSION(fk, VERSION_60, CERR_60FeatureOnly_NamedCodes);
// Add a single char store as a defined character constant
if (Uni_IsSurrogate1(*sp->dpString))
CodeConstants->AddCode(Uni_SurrogateToUTF32(sp->dpString[0], sp->dpString[1]), sp->szName, fk->cxStoreArray);
kmcmp::CodeConstants->AddCode(Uni_SurrogateToUTF32(sp->dpString[0], sp->dpString[1]), sp->szName, fk->cxStoreArray);
else
CodeConstants->AddCode(sp->dpString[0], sp->szName, fk->cxStoreArray);
CodeConstants->reindex(); // has to be done after every character add due to possible use in another store. // I4982
kmcmp::CodeConstants->AddCode(sp->dpString[0], sp->szName, fk->cxStoreArray);
kmcmp::CodeConstants->reindex(); // has to be done after every character add due to possible use in another store. // I4982
}
fk->cxStoreArray++; // increment now, because GetXString refers to stores
@ -1269,13 +910,13 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE
case TSS_INCLUDECODES:
VERIFY_KEYBOARD_VERSION(fk, VERSION_60, CERR_60FeatureOnly_NamedCodes);
pp = wstrtostr(sp->dpString);
if (!CodeConstants->LoadFile(pp))
if (!kmcmp::CodeConstants->LoadFile(pp))
{
delete[] pp;
return CERR_CannotLoadIncludeFile;
}
delete[] pp;
CodeConstants->reindex(); // I4982
kmcmp::CodeConstants->reindex(); // I4982
break;
case TSS_LANGUAGE:
@ -1606,13 +1247,13 @@ KMX_BOOL CheckContextStatementPositions(PKMX_WCHAR context) {
switch (*(p + 1)) {
case CODE_NUL:
if (p > context) {
AddWarning(CWARN_NulNotFirstStatementInContext);
AddWarningBool(CWARN_NulNotFirstStatementInContext);
}
break;
case CODE_IFOPT:
case CODE_IFSYSTEMSTORE:
if (hadContextChar) {
AddWarning(CWARN_IfShouldBeAtStartOfContext);
AddWarningBool(CWARN_IfShouldBeAtStartOfContext);
}
break;
default:
@ -2648,7 +2289,7 @@ KMX_DWORD GetXStringImpl(PKMX_WCHAR tstr, PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX
q = p + 1;
while (*q && !iswspace(*q)) q++;
c = *q; *q = 0;
n = CodeConstants->GetCode(p + 1, &i);
n = kmcmp::CodeConstants->GetCode(p + 1, &i);
*q = c;
if (n == 0) return CERR_InvalidNamedCode;
if (i < 0xFFFFFFFFL) kmcmp::CheckStoreUsage(fk, i, TRUE, FALSE, FALSE); // I2993
@ -3225,19 +2866,19 @@ KMX_BOOL kmcmp::CheckStoreUsage(PFILE_KEYBOARD fk, int storeIndex, KMX_BOOL fIsS
if (fIsStore && !sp->fIsStore)
{
if (sp->fIsDebug || sp->fIsOption || sp->fIsReserved || sp->fIsCall)
AddWarning(CWARN_StoreAlreadyUsedAsOptionOrCall);
AddWarningBool(CWARN_StoreAlreadyUsedAsOptionOrCall);
sp->fIsStore = TRUE;
}
else if (fIsOption && !sp->fIsOption)
{
if (sp->fIsDebug || sp->fIsStore || sp->fIsReserved || sp->fIsCall)
AddWarning(CWARN_StoreAlreadyUsedAsStoreOrCall);
AddWarningBool(CWARN_StoreAlreadyUsedAsStoreOrCall);
sp->fIsOption = TRUE;
}
else if (fIsCall && !sp->fIsCall)
{
if (sp->fIsDebug || sp->fIsStore || sp->fIsReserved || sp->fIsOption)
AddWarning(CWARN_StoreAlreadyUsedAsStoreOrOption);
AddWarningBool(CWARN_StoreAlreadyUsedAsStoreOrOption);
sp->fIsCall = TRUE;
}
@ -3645,7 +3286,7 @@ int atoiW(PKMX_WCHAR p)
return i;
}
int kmcmp::CheckUTF16(int n)
KMX_DWORD kmcmp::CheckUTF16(int n)
{
const int res[] = {
0xFDD0, 0xFDD1, 0xFDD2, 0xFDD3, 0xFDD4, 0xFDD5, 0xFDD6, 0xFDD7,
@ -3664,7 +3305,7 @@ int kmcmp::CheckUTF16(int n)
return CERR_None;
}
int kmcmp::UTF32ToUTF16(int n, int *n1, int *n2)
KMX_DWORD kmcmp::UTF32ToUTF16(int n, int *n1, int *n2)
{
*n2 = -1;
if (n <= 0xFFFF)
@ -3679,7 +3320,8 @@ int kmcmp::UTF32ToUTF16(int n, int *n1, int *n2)
n = n - 0x10000;
*n1 = (n / 0x400) + 0xD800;
*n2 = (n % 0x400) + 0xDC00;
if ((n = kmcmp::CheckUTF16(*n1)) != CERR_None) return n;
KMX_DWORD msg;
if ((msg = kmcmp::CheckUTF16(*n1)) != CERR_None) return msg;
return kmcmp::CheckUTF16(*n2);
}

View file

@ -0,0 +1,368 @@
#include "pch.h"
#include <kmcmplibapi.h>
#include <comperr.h>
#include "kmcmplib.h"
#include "filesystem.h"
#include "CheckFilenameConsistency.h"
#include "CheckNCapsConsistency.h"
#include "DeprecationChecks.h"
#include "versioning.h"
#include "../../../../common/windows/cpp/include/ConvertUTF.h"
#include "../../../../common/windows/cpp/include/keymanversion.h"
#define SetError(err) { if(AddCompileError(err) || (err & CERR_FATAL)) return FALSE; }
bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk);
EXTERN bool kmcmp_SetCompilerOptions(KMCMP_COMPILER_OPTIONS* options) {
//printf("°°-> changed to SetCompilerOptions() of kmcmplib \n");
if(!options || options->dwSize < sizeof(KMCMP_COMPILER_OPTIONS)) {
return FALSE;
}
kmcmp::FShouldAddCompilerVersion = options->ShouldAddCompilerVersion;
return TRUE;
}
#ifdef __EMSCRIPTEN__
/*
WASM interface for compiler message callback
*/
EM_JS(int, wasm_msgproc, (int line, int msgcode, char* text, char* context), {
const proc = globalThis[context];
if(!proc || typeof proc != 'function') {
console.log(`[${line}: ${msgcode}: ${UTF8ToString(text)}]`);
return 0;
} else {
return proc(line, msgcode, UTF8ToString(text));
}
});
int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, char* szText, void* context) {
char* msgProc = static_cast<char*>(context);
return wasm_msgproc(line, dwMsgCode, szText, msgProc);
}
EXTERN bool kmcmp_Wasm_SetCompilerOptions(int ShouldAddCompilerVersion) {
KMCMP_COMPILER_OPTIONS options;
options.dwSize = sizeof(KMCMP_COMPILER_OPTIONS);
options.ShouldAddCompilerVersion = ShouldAddCompilerVersion;
return kmcmp_SetCompilerOptions(&options);
}
EXTERN bool kmcmp_Wasm_CompileKeyboardFile(char* pszInfile,
char* pszOutfile, int ASaveDebug, int ACompilerWarningsAsErrors,
int AWarnDeprecatedCode, char* msgProc
) {
return kmcmp_CompileKeyboardFile(
pszInfile,
pszOutfile,
ASaveDebug,
ACompilerWarningsAsErrors,
AWarnDeprecatedCode,
wasm_CompilerMessageProc,
msgProc
);
}
#endif
EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile,
char* pszOutfile, bool ASaveDebug, bool ACompilerWarningsAsErrors,
bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext
) {
FILE* fp_in = NULL;
FILE* fp_out = NULL;
KMX_CHAR str[260];
//printf("°°-> changed to CompileKeyboardFile() of kmcmplib \n");
kmcmp::FSaveDebug = ASaveDebug;
kmcmp::FCompilerWarningsAsErrors = ACompilerWarningsAsErrors; // I4865
AWarnDeprecatedCode_GLOBAL_LIB = AWarnDeprecatedCode;
kmcmp::CompileTarget = CKF_KEYMAN;
if (!pMsgproc || !pszInfile || !pszOutfile) SetError(CERR_BadCallParams);
PKMX_STR p;
if ((p = strrchr_slash(pszInfile)) != nullptr)
{
strncpy(kmcmp::CompileDir, pszInfile, (int)(p - pszInfile + 1)); // I3481
kmcmp::CompileDir[(int)(p - pszInfile + 1)] = 0;
}
else
kmcmp::CompileDir[0] = 0;
msgproc = pMsgproc;
msgprocContext = AmsgprocContext;
kmcmp::currentLine = 0;
kmcmp::nErrors = 0;
fp_in = Open_File(pszInfile, "rb");
if (fp_in == NULL) {
SetError(CERR_InfileNotExist);
}
// Transfer the file to a memory stream for processing UTF-8 or ANSI to UTF-16?
// What about really large files? Transfer to a temp file...
if (!fread(str, 1, 3, fp_in)) {
fclose(fp_in);
SetError(CERR_CannotReadInfile);
}
fseek(fp_in, 0, SEEK_SET);
if (str[0] == UTF8Sig[0] && str[1] == UTF8Sig[1] && str[2] == UTF8Sig[2])
fp_in = UTF16TempFromUTF8(fp_in, TRUE);
else if (str[0] == UTF16Sig[0] && str[1] == UTF16Sig[1])
fseek(fp_in, 2, SEEK_SET);
else
fp_in = UTF16TempFromUTF8(fp_in, FALSE);
if (fp_in == NULL) {
SetError(CERR_CannotCreateTempfile);
}
fp_out = Open_File(pszOutfile, "wb");
if (fp_out == NULL) {
SetError(CERR_CannotCreateOutfile);
}
FILE_KEYBOARD fk;
kmcmp::CodeConstants = new kmcmp::NamedCodeConstants;
bool result = CompileKeyboardHandle(fp_in, &fk);
if(result) {
KMX_DWORD msg;
if ((msg = WriteCompiledKeyboard(&fk, fp_out)) != CERR_None) {
result = FALSE;
AddCompileError(msg);
}
} else {
AddCompileError(CERR_InvalidValue);
}
fclose(fp_in);
fclose(fp_out);
delete kmcmp::CodeConstants;
if (kmcmp::nErrors > 0)
{
remove(pszOutfile);
return FALSE;
}
return result;
}
EXTERN bool kmcmp_CompileKeyboardFileToBuffer(char* pszInfile, void* pfkBuffer, bool ACompilerWarningsAsErrors, bool AWarnDeprecatedCode,
kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext, int Target) // I4865 // I4866
{
//printf("°°-> changed to CompileKeyboardFileToBuffer() of kmcmplib \n");
FILE* fp_in = NULL;
KMX_CHAR str[260];
kmcmp::FSaveDebug = TRUE; // I3681
kmcmp::FCompilerWarningsAsErrors = ACompilerWarningsAsErrors; // I4865
AWarnDeprecatedCode_GLOBAL_LIB = AWarnDeprecatedCode;
kmcmp::CompileTarget = Target;
if (!pMsgproc || !pszInfile || !pfkBuffer) {
SetError(CERR_BadCallParams);
}
PKMX_STR p;
if ((p = strrchr_slash(pszInfile)) != nullptr) {
strncpy(kmcmp::CompileDir, pszInfile, (int)(p - pszInfile + 1)); // I3481
kmcmp::CompileDir[(int)(p - pszInfile + 1)] = 0;
}
else {
kmcmp::CompileDir[0] = 0;
}
msgproc = pMsgproc;
msgprocContext = AmsgprocContext;
kmcmp::currentLine = 0;
kmcmp::nErrors = 0;
fp_in = Open_File(pszInfile,"rb");
if (fp_in == NULL) {
SetError(CERR_InfileNotExist);
}
// Transfer the file to a memory stream for processing UTF-8 or ANSI to UTF-16?
// What about really large files? Transfer to a temp file...
if( !fread(str,1,3,fp_in))
{
fclose(fp_in);
SetError(CERR_CannotReadInfile);
}
fseek( fp_in,0,SEEK_SET);
if (str[0] == UTF8Sig[0] && str[1] == UTF8Sig[1] && str[2] == UTF8Sig[2])
fp_in = UTF16TempFromUTF8(fp_in, TRUE);
else if (str[0] == UTF16Sig[0] && str[1] == UTF16Sig[1])
fseek( fp_in,2,SEEK_SET);
else
fp_in = UTF16TempFromUTF8(fp_in, FALSE);
kmcmp::CodeConstants = new kmcmp::NamedCodeConstants;
bool result = CompileKeyboardHandle(fp_in, static_cast<PFILE_KEYBOARD>(pfkBuffer));
delete kmcmp::CodeConstants;
fclose(fp_in);
if (kmcmp::nErrors > 0) {
return FALSE;
}
return result;
}
bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk)
{
PKMX_WCHAR str, p;
KMX_DWORD msg;
kmcmp::FMnemonicLayout = FALSE;
if (!fk) {
SetError(CERR_SomewhereIGotItWrong);
}
str = new KMX_WCHAR[LINESIZE];
if (!str) {
SetError(CERR_CannotAllocateMemory);
}
fk->KeyboardID = 0;
fk->version = 0;
fk->dpStoreArray = NULL;
fk->dpGroupArray = NULL;
fk->cxStoreArray = 0;
fk->cxGroupArray = 0;
fk->StartGroup[0] = fk->StartGroup[1] = -1;
fk->szName[0] = 0;
fk->szCopyright[0] = 0;
fk->dwFlags = KF_AUTOMATICVERSION;
fk->currentGroup = 0xFFFFFFFF;
fk->currentStore = 0;
fk->cxDeadKeyArray = 0;
fk->dpDeadKeyArray = NULL;
fk->cxVKDictionary = 0; // I3438
fk->dpVKDictionary = NULL; // I3438
/* fk->szMessage[0] = 0;
fk->szLanguageName[0] = 0;*/
fk->dwBitmapSize = 0;
fk->dwHotKey = 0;
kmcmp::BeginLine[BEGIN_ANSI] = -1;
kmcmp::BeginLine[BEGIN_UNICODE] = -1;
kmcmp::BeginLine[BEGIN_NEWCONTEXT] = -1;
kmcmp::BeginLine[BEGIN_POSTKEYSTROKE] = -1;
/* Add a store for the Keyman 6.0 copyright information string */
if(kmcmp::FShouldAddCompilerVersion) {
u16sprintf(str,LINESIZE, L"Created with Keyman Developer version %d.%d.%d.%d", KEYMAN_VersionMajor, KEYMAN_VersionMinor, KEYMAN_VersionPatch, 0);
AddStore(fk, TSS_KEYMANCOPYRIGHT, str);
}
/* Add a system store for the Keyman edition number */
u16sprintf(str, LINESIZE, L"%d", 0); // I3481
AddStore(fk, TSS_CUSTOMKEYMANEDITION, str);
PKMX_WCHAR tbuf = strtowstr((KMX_CHAR*) "Keyman");
AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, tbuf);
delete tbuf;
// must preprocess for group and store names -> this isn't really necessary, but never mind!
while ((msg = ReadLine(fp_in, str, TRUE)) == CERR_None)
{
p = str;
switch (LineTokenType(&p))
{
case T_VERSION:
*(p + 4) = 0;
if ((msg = AddStore(fk, TSS_VERSION, p)) != CERR_None) SetError(msg);
break;
case T_GROUP:
if ((msg = ProcessGroupLine(fk, p)) != CERR_None) SetError(msg);
break;
case T_STORE:
if ((msg = ProcessStoreLine(fk, p)) != CERR_None) SetError(msg);
break;
default:
break;
}
}
if (msg != CERR_EndOfFile) {
SetError(msg);
}
fseek( fp_in,2,SEEK_SET);
kmcmp::currentLine = 0;
/* Reindex the list of codeconstants after stores added */
kmcmp::CodeConstants->reindex();
/* ReadLine will automatically skip over $Keyman lines, and parse wrapped lines */
while ((msg = ReadLine(fp_in, str, FALSE)) == CERR_None)
{
msg = ParseLine(fk, str);
if (msg != CERR_None) {
SetError(msg);
}
}
if (msg != CERR_EndOfFile) {
SetError(msg);
}
ProcessGroupFinish(fk);
if (kmcmp::FSaveDebug) kmcmp::RecordDeadkeyNames(fk);
/* Add the compiler version as a system store */
if ((msg = kmcmp::AddCompilerVersionStore(fk)) != CERR_None) {
SetError(msg);
}
if ((msg = BuildVKDictionary(fk)) != CERR_None) {
SetError(msg); // I3438
}
if ((msg = CheckFilenameConsistencyForCalls(fk)) != CERR_None) {
SetError(msg);
}
delete str;
if (!kmcmp::CheckKeyboardFinalVersion(fk)) {
return FALSE;
}
/* Warn on inconsistent use of NCAPS */
if (!kmcmp::FMnemonicLayout) {
CheckNCapsConsistency(fk);
}
/* Flag presence of deprecated features */
kmcmp::CheckForDeprecatedFeatures(fk);
return TRUE;
}

View file

@ -8,7 +8,7 @@
KMX_BOOL kmcmp::WarnDeprecatedHeader() { // I4866
if( AWarnDeprecatedCode_GLOBAL_LIB){
AddWarning(CWARN_HeaderStatementIsDeprecated);
AddWarningBool(CWARN_HeaderStatementIsDeprecated);
}
return TRUE;
}
@ -42,7 +42,7 @@ KMX_BOOL kmcmp::CheckForDeprecatedFeatures(PFILE_KEYBOARD fk) {
sp->dwSystemID == TSS_ETHNOLOGUECODE ||
sp->dwSystemID == TSS_WINDOWSLANGUAGES) {
kmcmp::currentLine = sp->line;
AddWarning(CWARN_LanguageHeadersDeprecatedInKeyman10);
AddWarningBool(CWARN_LanguageHeadersDeprecatedInKeyman10);
}
}
}

View file

@ -1,21 +1,50 @@
#pragma once
#include <kmcmplibapi.h>
#include "compfile.h"
#include "NamedCodeConstants.h"
namespace kmcmp {
KMX_BOOL AddCompileWarning(char* buf);
extern int currentLine;
extern KMX_BOOL FShouldAddCompilerVersion;
extern KMX_BOOL FSaveDebug, FCompilerWarningsAsErrors; // I4865 // I4866
extern int ErrChr;
extern int nErrors;
extern KMX_BOOL FMnemonicLayout;
extern KMX_BOOL FOldCharPosMatching;
extern int CompileTarget;
extern KMX_CHAR CompileDir[260]; // TODO: this should not be a fixed buffer
extern int BeginLine[4];
extern int currentLine;
extern NamedCodeConstants *CodeConstants;
void RecordDeadkeyNames(PFILE_KEYBOARD fk);
KMX_DWORD AddCompilerVersionStore(PFILE_KEYBOARD fk);
}
extern kmcmp_CompilerMessageProc msgproc;
extern void* msgprocContext;
extern KMX_BOOL AWarnDeprecatedCode_GLOBAL_LIB;
extern char ErrExtraLIB[256];
extern KMX_WCHAR ErrExtraW[256];
KMX_BOOL AddCompileError(KMX_DWORD msg);
// TODO: These macros can return FALSE in functions that expect a DWORD CERR_x
// return value type. This is just plain wrong!
#define SetError(err) { if(AddCompileError(err) || (err & CERR_FATAL)) return FALSE; }
#define AddWarning(warn) { if(AddCompileError(warn)) return FALSE; }
/// Use AddWarningBool for functions that return bool or KMX_BOOL
#define AddWarningBool(warn) { if(AddCompileError(warn)) return FALSE; }
/// Use AddWarning for functions that return KMX_DWORD
#define AddWarning(warn) { if(AddCompileError(warn)) return CERR_Break; }
PKMX_WCHAR strtowstr(PKMX_STR in);
PFILE_STORE FindSystemStore(PFILE_KEYBOARD fk, KMX_DWORD dwSystemID);
FILE* UTF16TempFromUTF8(FILE* fp_in , KMX_BOOL hasPreamble);
KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, FILE* fp_out);
KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, KMX_WCHAR const * str, KMX_DWORD *dwStoreID= NULL);
KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess);
KMX_DWORD ParseLine(PFILE_KEYBOARD fk, PKMX_WCHAR str);
KMX_DWORD ProcessGroupLine(PFILE_KEYBOARD fk, PKMX_WCHAR p);
KMX_DWORD ProcessGroupFinish(PFILE_KEYBOARD fk);
KMX_DWORD ProcessStoreLine(PFILE_KEYBOARD fk, PKMX_WCHAR p);
int LineTokenType(PKMX_WCHAR *str);
KMX_DWORD BuildVKDictionary(PFILE_KEYBOARD fk); // I3438

View file

@ -37,6 +37,7 @@ lib = library('kmcmplib',
'CasedKeys.cpp',
'CharToKeyConversion.cpp',
'Compiler.cpp',
'CompilerInterfaces.cpp',
'DeprecationChecks.cpp',
'Edition.cpp',
'filesystem.cpp',

View file

@ -0,0 +1,89 @@
/*
* Keyman is copyright (C) SIL International. MIT License.
*
* API endpoint unit tests for kmcmplib
*/
#include <stdio.h>
#ifdef _MSC_VER
#include <io.h>
#else
#include <unistd.h>
#endif
#include <vector>
#include <string>
#include <kmcmplibapi.h>
#include "../src/comperr.h"
#include "../src/compfile.h"
#include <test_assert.h>
void setup();
void test_kmcmp_CompileKeyboardFile();
void test_kmcmp_CompileKeyboardFileToBuffer();
std::vector<int> error_vec;
int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) {
error_vec.push_back(dwMsgCode);
const char*t = "unknown";
switch(dwMsgCode & 0xF000) {
case CERR_HINT: t=" hint"; break;
case CERR_WARNING: t="warning"; break;
case CERR_ERROR: t=" error"; break;
case CERR_FATAL: t=" fatal"; break;
}
printf("line %d %s %04.4x: %s\n", line, t, (unsigned int)dwMsgCode, szText);
return 1;
}
int main(int argc, char *argv[]) {
setup();
test_kmcmp_CompileKeyboardFile();
setup();
test_kmcmp_CompileKeyboardFileToBuffer();
return 0;
}
void setup() {
error_vec.clear();
}
void test_kmcmp_CompileKeyboardFile() {
char kmn_file[L_tmpnam], kmx_file[L_tmpnam];
tmpnam(kmn_file);
tmpnam(kmx_file);
// Create an empty file
FILE *fp = fopen(kmn_file, "w");
fclose(fp);
// It should fail when a zero-byte file is passed in
assert(!kmcmp_CompileKeyboardFile(kmn_file, kmx_file, true, false, true, msgproc, nullptr));
assert(error_vec.size() == 1);
assert(error_vec[0] == CERR_CannotReadInfile);
unlink(kmn_file);
}
void test_kmcmp_CompileKeyboardFileToBuffer() {
char kmn_file[L_tmpnam], kmx_file[L_tmpnam];
tmpnam(kmn_file);
tmpnam(kmx_file);
// Create an empty file
FILE *fp = fopen(kmn_file, "w");
fclose(fp);
FILE_KEYBOARD fk;
// It should fail when a zero-byte file is passed in
assert(!kmcmp_CompileKeyboardFileToBuffer(kmn_file, &fk, true, false, msgproc, nullptr, CKF_KEYMAN));
assert(error_vec.size() == 1);
assert(error_vec[0] == CERR_CannotReadInfile);
unlink(kmn_file);
}

View file

@ -98,3 +98,12 @@ foreach kbd : tests
endif
endforeach
apitest = executable('api-test', 'api-test.cpp',
cpp_args: defns,
include_directories: inc,
name_suffix: name_suffix,
link_args: links + tests_flags,
objects: lib.extract_all_objects())
test('api-test', apitest)