mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-30 20:27:39 +00:00
This change rename the test files for Developer according to the discussion at the Keyman conference in November 2024.
212 lines
6.4 KiB
C++
212 lines
6.4 KiB
C++
/*
|
|
* Keyman is copyright (C) SIL International. MIT License.
|
|
*
|
|
* Tiny frame console app to compile a .kmx from a .kmn
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include <locale>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <kmcmplibapi.h>
|
|
#include <kmx_file.h>
|
|
#include "util_filesystem.h"
|
|
#include "util_callbacks.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#else
|
|
#include <unistd.h>
|
|
#include <cstring>
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
if(argc < 4) {
|
|
puts("Usage: kmcompxtest source.kmn output.kmx fixture.kmx");
|
|
return __LINE__;
|
|
}
|
|
|
|
char* kmn_file = argv[1];
|
|
char* kmx_file = argv[2];
|
|
char* reference_kmx = argv[3];
|
|
|
|
// Replace \ with /
|
|
for(char *p = kmn_file; *p; p++) {
|
|
if(*p == '\\') *p = '/';
|
|
}
|
|
|
|
for(char *p = kmx_file; *p; p++) {
|
|
if(*p == '\\') *p = '/';
|
|
}
|
|
|
|
for(char *p = reference_kmx; *p; p++) {
|
|
if(*p == '\\') *p = '/';
|
|
}
|
|
|
|
const char* first5 = "CERR_";
|
|
|
|
KMCMP_COMPILER_RESULT result;
|
|
KMCMP_COMPILER_OPTIONS options;
|
|
options.saveDebug = true;
|
|
options.compilerWarningsAsErrors = false;
|
|
options.warnDeprecatedCode = true;
|
|
options.shouldAddCompilerVersion = false;
|
|
options.target = CKF_KEYMAN;
|
|
|
|
if(kmcmp_CompileKeyboard(kmn_file, options, msgproc, loadfileProc, nullptr, result)) {
|
|
char* testname = strrchr( (char*) kmn_file, '/') + 1;
|
|
if(strncmp(testname, first5, strlen(first5)) == 0){
|
|
return __LINE__; // exit code: CERR_ in Name + no Error found
|
|
}
|
|
|
|
// On non-win32 platforms, we cannot get kmcmpdll.dll to build keyboards
|
|
// legacy-mode, so we'll compare to a hopefully existing file that we've
|
|
// been passed
|
|
FILE* fp1 = Open_File(kmx_file, "wb");
|
|
if(!fp1) return __LINE__;
|
|
|
|
// Write out for reference
|
|
fwrite(result.kmx, 1, result.kmxSize, fp1);
|
|
fclose(fp1);
|
|
|
|
FILE* fp2 = Open_File(reference_kmx, "rb");
|
|
if(!fp2) return __LINE__; // exit code: fail if no reference kmx file in build-folder
|
|
|
|
fseek(fp2, 0, SEEK_END);
|
|
auto sz2 = ftell(fp2);
|
|
fseek(fp2, 0, SEEK_SET);
|
|
if (result.kmxSize != (size_t)sz2) return __LINE__; // exit code: size of kmx-file in build differs from size of kmx-file in source folder
|
|
|
|
char* buf2 = new char[result.kmxSize];
|
|
auto sz3 = fread(buf2, 1, result.kmxSize, fp2);
|
|
if (result.kmxSize != sz3) return __LINE__; // exit code: when not able to read the build into the buffer
|
|
return memcmp(result.kmx, buf2, result.kmxSize) ? __LINE__ : 0; // exit code: when contents of kmx-file in build differs from contents of kmx-file in source folder
|
|
// success: when contents of kmx-file in build and source folder are the same
|
|
}
|
|
else { /*if Errors found: check number (e.g. CERR_4061_balochi_phonetic.kmn should produce Error 4061)*/
|
|
int error_val = 0;
|
|
char* testname = strrchr( (char*) kmn_file, '/') + 1;
|
|
|
|
// Does testname contain CERR_ && contains '_' on pos 9 ? -> Get ErrorValue
|
|
if ((strncmp(testname, first5, strlen(first5)) == 0) && (testname[9] == '_')) {
|
|
char* ErrNr = strchr(testname, '_') +1 ;
|
|
std::istringstream(ErrNr) >> std::hex >> error_val;
|
|
|
|
// check if error_val is in Array of Errors; if it is found return 0 (it's not an error)
|
|
for (size_t i = 0; i < error_vec.size() ; i++) {
|
|
if (error_vec[i] == error_val) {
|
|
return 0; // success: CERR_ in Name + Error (specified in CERR_Name) IS found
|
|
}
|
|
}
|
|
return __LINE__; // exit code: CERR_ in Name + Error (specified in CERR_Name) is NOT found
|
|
}
|
|
return __LINE__; // exit code: no correct CERR_ in Name + CompileKeyboardFile failed (i.e. test config is invalid)
|
|
}
|
|
}
|
|
|
|
|
|
bool equalIgnoreCase(const string& a, const string& b)
|
|
{
|
|
return std::equal(
|
|
a.begin(), a.end(),
|
|
b.begin(), b.end(),
|
|
[](char a, char b) {
|
|
return tolower(a) == tolower(b);
|
|
}
|
|
);
|
|
}
|
|
|
|
// Returns TRUE if the keyboard has a &TARGETS store with
|
|
// 'any', 'windows', 'macosx', 'linux', or 'desktop' targets,
|
|
// or if no &TARGETS store exists (which is equivalent to
|
|
// 'windows').
|
|
bool isDesktopKeyboard(FILE* fp) {
|
|
COMP_KEYBOARD fk;
|
|
|
|
if(fseek(fp, 0, SEEK_SET) != 0) {
|
|
printf("isDesktopKeyboard: fseek(0) failed\n");
|
|
exit(1);
|
|
}
|
|
|
|
if(!fread(&fk, sizeof(fk), 1, fp)) {
|
|
printf("isDesktopKeyboard failed: could not read COMP_KEYBOARD\n");
|
|
exit(1);
|
|
}
|
|
|
|
// Note: this code assumes a valid .kmx. This is okay for a unit test
|
|
if(fseek(fp, fk.dpStoreArray, SEEK_SET) != 0) {
|
|
printf("isDesktopKeyboard failed: could not locate fk.dpStoreArray=%x\n", fk.dpStoreArray);
|
|
exit(1);
|
|
}
|
|
|
|
PCOMP_STORE pfs = new COMP_STORE[fk.cxStoreArray];
|
|
if(fread(pfs, sizeof(COMP_STORE), fk.cxStoreArray, fp) != fk.cxStoreArray) {
|
|
printf("isDesktopKeyboard failed: could not read fk.dpStoreArray=%x [%x]\n", fk.dpStoreArray, fk.cxStoreArray);
|
|
exit(1);
|
|
}
|
|
|
|
PCOMP_STORE s = pfs;
|
|
|
|
for(KMX_DWORD i = 0; i < fk.cxStoreArray; i++, s++) {
|
|
if(s->dwSystemID != TSS_TARGETS) {
|
|
continue;
|
|
}
|
|
|
|
// Read targets store
|
|
if(fseek(fp, s->dpString, SEEK_SET) != 0) {
|
|
printf("isDesktopKeyboard: could not seek to TSS_TARGETS.dpString %x\n", s->dpString);
|
|
exit(1);
|
|
}
|
|
|
|
KMX_WCHAR buf[256];
|
|
if(fread(buf, sizeof(KMX_WCHAR), 256, fp) == 0) {
|
|
printf("isDesktopKeyboard: could not read TSS_TARGETS.dpString %x\n", s->dpString);
|
|
exit(1);
|
|
}
|
|
buf[255] = 0; // sanity
|
|
|
|
if(fseek(fp, 0, SEEK_SET) != 0) {
|
|
printf("isDesktopKeyboard: fseek(0) failed\n");
|
|
exit(1);
|
|
}
|
|
|
|
std::string targets1 = string_from_u16string(buf);
|
|
std::stringstream targets(targets1);
|
|
std::string target;
|
|
|
|
printf("isDesktopKeyboard: TSS_TARGETS: %s\n", targets1.c_str());
|
|
|
|
delete[] pfs;
|
|
|
|
while(targets >> target) {
|
|
//Matches KMXKeymanTargets from UKeymanTargets.pas
|
|
if(equalIgnoreCase(target, "any") ||
|
|
equalIgnoreCase(target, "windows") ||
|
|
equalIgnoreCase(target, "macosx") ||
|
|
equalIgnoreCase(target, "linux") ||
|
|
equalIgnoreCase(target, "desktop")
|
|
) {
|
|
printf("isDesktopKeyboard: TSS_TARGETS does contain desktop target %s\n", target.c_str());
|
|
return true;
|
|
}
|
|
}
|
|
|
|
printf("isDesktopKeyboard: TSS_TARGETS does not contain desktop target\n");
|
|
return false;
|
|
}
|
|
|
|
delete[] pfs;
|
|
|
|
if(fseek(fp, 0, SEEK_SET) != 0) {
|
|
printf("isDesktopKeyboard: fseek(0) failed\n");
|
|
exit(1);
|
|
}
|
|
|
|
printf("isDesktopKeyboard: TSS_TARGETS does not exist\n");
|
|
return true;
|
|
}
|