diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..295b05f --- /dev/null +++ b/.clang-format @@ -0,0 +1,184 @@ +--- +Language: Cpp +# BasedOnStyle: WebKit +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +#AlignAfterOpenBracket: DontAlign +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Right +AlignOperands: DontAlign +AlignTrailingComments: false +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: TopLevelDefinitions +#AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: All +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: WebKit +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeComma +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 0 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 8 +#ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: true +#ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: false +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: Inner +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 4 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +PPIndentWidth: -1 +ReferenceAlignment: Pointer +ReflowComments: false +#ReflowComments: true +ShortNamespaceLines: 1 +SortIncludes: false +#SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... + diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml new file mode 100644 index 0000000..914c76c --- /dev/null +++ b/.github/workflows/ccpp.yml @@ -0,0 +1,61 @@ +name: C/C++ CI + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "*" ] + +jobs: + check-formatting: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: check-format + run: | + echo "Checking format of sourcecode..." + find . -type f \( -name '*.c' -o -name '*.h' \) -print0 | xargs -r0 clang-format -i + git diff --color # --exit-code + + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: install dependencies + run: sudo apt install autopoint check intltool libexpat1-dev pkg-config + - name: configure + run: | + test -f config.rpath || touch config.rpath + sh ./autogen.sh + ./configure + - name: make + run: make + - name: make check + run: make check + - name: make distcheck + run: make distcheck + + build-windows: + env: + SOLUTION_FILE_PATH: . + BUILD_CONFIGURATION: Release + + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + + - name: Add MSBuild to PATH + uses: microsoft/setup-msbuild@v1.0.2 + + - name: Restore NuGet packages + working-directory: ${{env.GITHUB_WORKSPACE}} + run: nuget restore ${{env.SOLUTION_FILE_PATH}} + + - name: Build + working-directory: ${{env.GITHUB_WORKSPACE}} + run: | + msbuild /m /p:platform=x64 /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} + msbuild /m /p:platform=x86 /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} diff --git a/CMakeLists.txt b/CMakeLists.txt index 8adbdb8..8aafe38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ option(ENABLE_UNIT_TEST include(CTest) include(GNUInstallDirs) +include(CheckIncludeFiles) set(LIBHANGUL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}/hangul-1.0") set(LIBHANGUL_LIBRARY_DIR "${CMAKE_INSTALL_LIBDIR}") @@ -56,6 +57,12 @@ if(BUILD_TESTING) add_subdirectory(test EXCLUDE_FROM_ALL) endif() +check_include_files(glob.h HAVE_GLOB_H) +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/config.h" +) + include(CMakePackageConfigHelpers) configure_package_config_file(hangul-config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/hangul-config.cmake" diff --git a/Libhangul.sln b/Libhangul.sln new file mode 100644 index 0000000..76341c6 --- /dev/null +++ b/Libhangul.sln @@ -0,0 +1,35 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.960 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2DA4F60C-0EED-4AE9-823D-C8BC15FA46ED}") = "Libhangul", "libhangul.vcxproj", "{83381EEE-8813-47E6-BDCB-4F9882E81882}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {83381EEE-8813-47E6-BDCB-4F9882E81882}.Debug|x64.ActiveCfg = Debug|x64 + {83381EEE-8813-47E6-BDCB-4F9882E81882}.Debug|x64.Build.0 = Debug|x64 + {83381EEE-8813-47E6-BDCB-4F9882E81882}.Debug|x64.Deploy.0 = Debug|x64 + {83381EEE-8813-47E6-BDCB-4F9882E81882}.Debug|x86.ActiveCfg = Debug|Win32 + {83381EEE-8813-47E6-BDCB-4F9882E81882}.Debug|x86.Build.0 = Debug|Win32 + {83381EEE-8813-47E6-BDCB-4F9882E81882}.Debug|x86.Deploy.0 = Debug|Win32 + {83381EEE-8813-47E6-BDCB-4F9882E81882}.Release|x64.ActiveCfg = Release|x64 + {83381EEE-8813-47E6-BDCB-4F9882E81882}.Release|x64.Build.0 = Release|x64 + {83381EEE-8813-47E6-BDCB-4F9882E81882}.Release|x64.Deploy.0 = Release|x64 + {83381EEE-8813-47E6-BDCB-4F9882E81882}.Release|x86.ActiveCfg = Release|Win32 + {83381EEE-8813-47E6-BDCB-4F9882E81882}.Release|x86.Build.0 = Release|Win32 + {83381EEE-8813-47E6-BDCB-4F9882E81882}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3DA4F60C-0EED-4AE9-823D-C8BC15FA46ED} + EndGlobalSection +EndGlobal diff --git a/config.h.cmake.in b/config.h.cmake.in new file mode 100644 index 0000000..6ef3caa --- /dev/null +++ b/config.h.cmake.in @@ -0,0 +1 @@ +#cmakedefine HAVE_GLOB_H 1 diff --git a/configure.ac b/configure.ac index f1e85b9..65d13b9 100644 --- a/configure.ac +++ b/configure.ac @@ -41,6 +41,7 @@ AC_PROG_INSTALL AC_HEADER_STDC AC_CHECK_HEADERS([stdlib.h string.h limits.h]) AC_CHECK_HEADERS([langinfo.h]) +AC_CHECK_HEADERS([glob.h]) # Checks for typedefs, structures, and compiler characteristics. AC_HEADER_STDBOOL diff --git a/hangul/CMakeLists.txt b/hangul/CMakeLists.txt index 93f7fb4..14fde95 100644 --- a/hangul/CMakeLists.txt +++ b/hangul/CMakeLists.txt @@ -44,12 +44,17 @@ add_library(hangul ) target_compile_definitions(hangul + PRIVATE -DHAVE_CONFIG_H PRIVATE -DLOCALEDIR=\"${CMAKE_INSTALL_FULL_LOCALEDIR}\" PRIVATE -DLIBHANGUL_DEFAULT_HANJA_DIC=\"${CMAKE_INSTALL_FULL_DATADIR}/${CMAKE_PROJECT_NAME}/hanja/hanja.txt\" PRIVATE -DLIBHANGUL_DATA_DIR=\"${CMAKE_INSTALL_FULL_DATADIR}/${CMAKE_PROJECT_NAME}\" PRIVATE -DTOP_SRCDIR=\"${CMAKE_SOURCE_DIR}\" ) +target_include_directories(hangul + PRIVATE "${CMAKE_BINARY_DIR}" +) + if(ENABLE_EXTERNAL_KEYBOARDS) target_compile_definitions(hangul PRIVATE -DENABLE_EXTERNAL_KEYBOARDS=1 diff --git a/hangul/hangulkeyboard.c b/hangul/hangulkeyboard.c index 9e1e599..97be149 100644 --- a/hangul/hangulkeyboard.c +++ b/hangul/hangulkeyboard.c @@ -26,8 +26,9 @@ #if ENABLE_EXTERNAL_KEYBOARDS #include +#ifdef HAVE_GLOB_H #include -#include +#endif /* HAVE_GLOB_H */ #include #endif /* ENABLE_EXTERNAL_KEYBOARDS */ @@ -36,8 +37,11 @@ #include "hangulinternals.h" #ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include #define strdup _strdup -#endif +#endif /* _WIN32 */ /** * @file hangulkeyboard.c @@ -674,8 +678,11 @@ on_element_start(void* data, const XML_Char* element, const XML_Char** attr) strncpy(path, file, n); } else { char* orig_path = strdup(context->path_stack[top]); - char* dir = dirname(orig_path); - snprintf(path, n, "%s/%s", dir, file); + char* last_slash = strrchr(orig_path, '/'); + if (last_slash) + last_slash[0] = '\0'; + + snprintf(path, n, "%s/%s", orig_path, file); free(orig_path); } @@ -798,6 +805,7 @@ hangul_keyboard_list_load_dir(const char* path) snprintf(pattern, len, "%s%s", path, subpattern); +#ifdef HAVE_GLOB_H glob_t result; int res = glob(pattern, GLOB_ERR, NULL, &result); if (res != 0) { @@ -815,6 +823,54 @@ hangul_keyboard_list_load_dir(const char* path) globfree(&result); free(pattern); +#else /* _WIN32 */ + WIN32_FIND_DATAW findFileData; + HANDLE hFind; + int n = (strlen(pattern) + 1) * sizeof(WCHAR); + + LPWSTR wpattern = (LPWSTR)malloc(n); + if (wpattern == NULL) { + free(pattern); + return 0; + } + + MultiByteToWideChar(CP_ACP, 0, pattern, -1, wpattern, n); + + hFind = FindFirstFileW(wpattern, &findFileData); + if (hFind == INVALID_HANDLE_VALUE) { + free(wpattern); + free(pattern); + return 0; + } + + do { + n = WideCharToMultiByte(CP_ACP, 0, findFileData.cFileName, -1, NULL, 0, NULL, NULL); + if (n == 0) + continue; + + int path_len = strlen(path); + len = path_len + n + 2; + char* file = (char*)malloc(len); + if (file == NULL) + continue; + + memcpy(file, path, path_len); + file[path_len] = '/'; + char* pfile = &file[path_len + 1]; + WideCharToMultiByte(CP_ACP, 0, findFileData.cFileName, -1, pfile, n, NULL, NULL); + + HangulKeyboard* keyboard = hangul_keyboard_new_from_file(file); + free(file); + + if (keyboard == NULL) + continue; + hangul_keyboard_list_append(keyboard); + } while(FindNextFileW(hFind, &findFileData)); + + FindClose(hFind); + free(wpattern); + free(pattern); +#endif /* HAVE_GLOB_H */ return hangul_keyboards.n; } @@ -845,6 +901,38 @@ hangul_keyboard_get_default_keyboard_path() /* default LIBHANGUL_KEYBOARD_PATH is * SYSTEM_KEYBOARD_DIR:USER_KEYBOARD_DIR */ +#ifdef _WIN32 + /* system default dir */ + char* system_dir = NULL; + const char* data_dir = getenv("APPDATA"); + if (data_dir != NULL) { + const char* subdir = "/libhangul/keyboards"; + size_t system_dir_len = strlen(data_dir) + strlen(subdir) + 1; + system_dir = (char*)malloc(system_dir_len); + if (system_dir != NULL) { + snprintf(system_dir, system_dir_len, "%s%s", data_dir, subdir); + keyboard_path_len += strlen(system_dir); + } + } + /* user default dir */ + char* home_dir = getenv("USERPROFILE"); + if (home_dir == NULL) { + /* no user data dir */ + return system_dir; + } else { + const char* subdir = "/.libhangul/keyboards"; + keyboard_path_len += strlen(home_dir) + strlen(subdir); + keyboard_path = (char*)malloc(keyboard_path_len); + if (keyboard_path != NULL) { + if (system_dir != NULL) { + keyboard_path_len++; + snprintf(keyboard_path, keyboard_path_len, "%s;%s%s", system_dir, home_dir, subdir); + } else { + snprintf(keyboard_path, keyboard_path_len, "%s%s", home_dir, subdir); + } + } + } +#else /* system default dir */ const char* system_dir = LIBHANGUL_KEYBOARD_DIR; keyboard_path_len += strlen(system_dir); @@ -875,6 +963,7 @@ hangul_keyboard_get_default_keyboard_path() snprintf(keyboard_path, keyboard_path_len, "%s:%s%s", system_dir, xdg_data_home, subdir); } } +#endif /* _WIN32 */ return keyboard_path; } @@ -914,8 +1003,13 @@ hangul_keyboard_list_init() unsigned n = 0; char* dir = libhangul_keyboard_path; +#ifdef _WIN32 + char sep = ';'; +#else + char sep = ':'; +#endif /* _WIN32 */ while (dir != NULL && dir[0] != '\0') { - char* next = strchr(dir, ':'); + char* next = strchr(dir, sep); if (next != NULL) { next[0] = '\0'; ++next; diff --git a/libhangul.vcxproj b/libhangul.vcxproj index 906a374..aa261dc 100644 --- a/libhangul.vcxproj +++ b/libhangul.vcxproj @@ -25,6 +25,9 @@ libhangul 10.0.17763.0 + + NO + StaticLibrary @@ -36,7 +39,6 @@ StaticLibrary false v141 - true Unicode false @@ -50,7 +52,6 @@ StaticLibrary false v141 - true Unicode @@ -73,27 +74,34 @@ true + $(ProjectDir)libexpat\x86;$(LibraryPath) true + $(ProjectDir)libexpat\x64;$(LibraryPath) true + $(ProjectDir)libexpat\x86;$(LibraryPath) true + $(ProjectDir)libexpat\x64;$(LibraryPath) Level3 Disabled .;.\win32;%(AdditionalIncludeDirectories) + .\libexpat\expat\lib;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_LIB;ENABLE_EXTERNAL_KEYBOARDS=0;%(PreprocessorDefinitions);_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS + %(PreprocessorDefinitions);ENABLE_EXTERNAL_KEYBOARDS=1 /utf-8 Windows true + libexpatd.lib;%(AdditionalDependencies) @@ -101,12 +109,15 @@ Level3 Disabled .;.\win32;%(AdditionalIncludeDirectories) + .\libexpat\expat\lib;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_LIB;ENABLE_EXTERNAL_KEYBOARDS=0;%(PreprocessorDefinitions);_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS + %(PreprocessorDefinitions);ENABLE_EXTERNAL_KEYBOARDS=1 /utf-8 Windows true + libexpatd.lib;%(AdditionalDependencies) @@ -115,13 +126,16 @@ MaxSpeed true .;.\win32;%(AdditionalIncludeDirectories) + .\libexpat\expat\lib;%(AdditionalIncludeDirectories) WIN32;_LIB;ENABLE_EXTERNAL_KEYBOARDS=0;%(PreprocessorDefinitions);_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS + %(PreprocessorDefinitions);ENABLE_EXTERNAL_KEYBOARDS=1 /utf-8 Windows true true + libexpat.lib;%(AdditionalDependencies) @@ -130,13 +144,16 @@ MaxSpeed true .;.\win32;%(AdditionalIncludeDirectories) + .\libexpat\expat\lib;%(AdditionalIncludeDirectories) WIN32;_LIB;ENABLE_EXTERNAL_KEYBOARDS=0;%(PreprocessorDefinitions);_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS + %(PreprocessorDefinitions);ENABLE_EXTERNAL_KEYBOARDS=1 /utf-8 Windows true true + libexpat.lib;%(AdditionalDependencies)