diff --git a/Ide/CMakeLists.txt b/Ide/CMakeLists.txt --- a/Ide/CMakeLists.txt +++ b/Ide/CMakeLists.txt @@ -1,161 +1,160 @@ cmake_minimum_required (VERSION 3.18) set(CMAKE_CXX_STANDARD 14) project (LgiIde) if (NOT DEFINED LIBPNG_TARGET OR NOT TARGET ${LIBPNG_TARGET}) message(FATAL_ERROR "Find the libpng target (see parent folder cmake)") endif() if (APPLE) set(CMAKE_OSX_ARCHITECTURES "x86_64") set(GUI_TYPE MACOSX_BUNDLE) find_library(COCOA_LIBRARY Cocoa) mark_as_advanced(COCOA_LIBRARY) set(EXTRA_LIBS ${COCOA_LIBRARY}) elseif (LINUX) add_definitions("-fPIC -w -fno-inline -fpermissive") elseif (MSVC) set(ResourceFiles ../src/win/General/Lgi.manifest Resources/Script1.rc) if (NOT EXISTS ${OPENSSL_INCLUDE_DIR}) message(FATAL_ERROR "OpenSSL not found: '${OPENSSL_INCLUDE_DIR}'") endif() if (NOT EXISTS ${CODELIB}) message(FATAL_ERROR "Codelib not found: '${CODELIB}'") endif() if (${MSVC_VERSION} GREATER_EQUAL 1900) set(VS_VER 14) elseif (${MSVC_VERSION} EQUAL 1800) set(VS_VER 12) else() message(FATAL_ERROR "Unknown Visual Studio version: ${MSVC_VERSION}") endif() endif () if (NOT MSVC) find_package(ZLIB REQUIRED) set(ZLIB_TARGET ZLIB::ZLIB) else() set(ZLIB_TARGET zlib) endif() set (CommonSource - Code/SimpleCppParser.cpp - Code/WebFldDlg.cpp - Code/IdeCommon.cpp - Code/AddFtpFile.cpp - Code/ProjectNode.cpp - Code/IdeDoc.cpp - Code/IdeProject.cpp - Code/IdeProjectSettings.cpp - Code/LgiIde.cpp - Code/LgiUtils.cpp - Code/MemDumpViewer.cpp - Code/SpaceTabConv.cpp - Code/SysCharSupport.cpp - Code/DebugContext.cpp - Code/Debugger.cpp - Code/History.cpp - Code/FindInFiles.cpp - Code/FindSymbol.cpp - Code/FtpThread.cpp - Code/DocEdit.cpp - Code/PythonParser.cpp - Code/MissingFiles.cpp - Code/DocEditStyling.cpp - Code/levenshtein.c - Code/JavascriptParser.cpp - Code/NewProjectFromTemplate.cpp + src/SimpleCppParser.cpp + src/WebFldDlg.cpp + src/IdeCommon.cpp + src/AddFtpFile.cpp + src/ProjectNode.cpp + src/IdeDoc.cpp + src/IdeProject.cpp + src/IdeProjectSettings.cpp + src/LgiIde.cpp + src/LgiUtils.cpp + src/MemDumpViewer.cpp + src/SpaceTabConv.cpp + src/SysCharSupport.cpp + src/DebugContext.cpp + src/Debugger.cpp + src/History.cpp + src/FindInFiles.cpp + src/FindSymbol.cpp + src/FtpThread.cpp + src/DocEdit.cpp + src/PythonParser.cpp + src/MissingFiles.cpp + src/DocEditStyling.cpp + src/JavascriptParser.cpp + src/NewProjectFromTemplate.cpp ../src/common/Net/OpenSSLSocket.cpp ../src/common/Net/Http.cpp ../src/common/Net/Ftp.cpp ../src/common/Gdc2/Filters/Png.cpp ../src/common/Lgi/About.cpp ../src/common/Lgi/Mdi.cpp ../src/common/Lgi/LgiMain.cpp ../src/common/Widgets/ControlTree.cpp ../src/common/Coding/ParseCpp.cpp ../src/common/Coding/LexCpp.cpp ) list(APPEND ResourceFiles Resources/cmds-32px.png Resources/icons.png Resources/cmds-16px.png Resources/LgiIde.lr8 Resources/icon64.png ) if (APPLE) set(MacResourceFiles MacCocoa/Info.plist Resources/mac-icon.icns) set(APP_TYPE MACOSX_BUNDLE) set_source_files_properties(${MacResourceFiles} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") list(APPEND ResourceFiles ${MacResourceFiles}) elseif (MSVC) set(APP_TYPE WIN32) endif () add_executable(LgiIde ${APP_TYPE} ${CommonSource} ${ResourceFiles}) target_link_libraries(LgiIde lgi ${LIBPNG_TARGET} ${ZLIB_TARGET}) target_include_directories(LgiIde PRIVATE Code Resources) if (APPLE) target_link_libraries(LgiIde ${EXTRA_LIBS}) set_target_properties(LgiIde PROPERTIES MACOSX_BUNDLE TRUE MACOSX_FRAMEWORK_IDENTIFIER com.memecode.LgiIde RESOURCE "${ResourceFiles}" ) message("macBundlePostBuild(LgiIde)") macBundlePostBuild(LgiIde) elseif (MSVC) target_link_libraries(LgiIde ComCtl32.lib Ws2_32.lib UxTheme.lib imm32.lib) add_custom_command(TARGET LgiIde POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy "$" "$/$" COMMENT "Copying Lgi to output directory") if (EXISTS ${PNG_DLL}) add_custom_command(TARGET LgiIde POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy "${PNG_DLL}" "$/libpng${VS_VER}x${WORDSIZE}.dll" COMMENT "Copying Lgi to output directory") endif() endif () if (NOT MSVC) target_compile_definitions(LgiIde PRIVATE LIBPNG_SHARED=0) endif() # Create a resources sub-folder and copy over the resource files (images and lr8) file(COPY ${CMAKE_CURRENT_LIST_DIR}/Resources DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories (LgiIde PUBLIC Code "Resources" ${PNG_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} "${CODELIB}/libiconv-1.14/include") set_target_properties(LgiIde PROPERTIES EXCLUDE_FROM_ALL TRUE) diff --git a/Ide/LgiIdeProj.xml b/Ide/LgiIdeProj.xml --- a/Ide/LgiIdeProj.xml +++ b/Ide/LgiIdeProj.xml @@ -1,280 +1,278 @@ - - .\win\Makefile.windows ./linux/Makefile.linux ./MacCocoa/LgiIde.xcodeproj Makefile.haiku ./lgiide ./lgiide LgiIde.exe LgiIde.exe WINDOWS WINNATIVE WINDOWS WINNATIVE POSIX POSIX LIBPNG_VERSION=\"1.2\" LIBPNG_VERSION=\"1.2\" MingW /home/matthew/Code/Lgi/trunk/Ide/Code/IdeProjectSettings.cpp ./src ./resources ../include ./src ./resources ../include ..\include\lgi\win ..\include\lgi\win ../include/lgi/linux ../include/lgi/linux/Gtk ../../../../codelib/openssl/include ../include/lgi/linux ../include/lgi/linux/Gtk ../../../../codelib/openssl/include ../include/lgi/haiku ../include/lgi/haiku ../include/lgi/mac/cocoa ../include/lgi/mac/cocoa imm32 imm32 magic pthread `pkg-config --libs gtk+-3.0` -static-libgcc magic pthread `pkg-config --libs gtk+-3.0` -static-libgcc -static-libgcc gnu network be -static-libgcc gnu network be Executable lgiide lgiide LgiIde.exe LgiIde.exe lgiide lgiide `pkg-config --cflags gtk+-3.0` `pkg-config --cflags gtk+-3.0` POSIX _GNU_SOURCE POSIX _GNU_SOURCE 4 4 0 1 SOME_TEST=testing diff --git a/Ide/linux/Makefile.linux b/Ide/linux/Makefile.linux --- a/Ide/linux/Makefile.linux +++ b/Ide/linux/Makefile.linux @@ -1,396 +1,395 @@ #!/usr/bin/make # # This makefile generated by LgiIde # http://www.memecode.com/lgi.php # .SILENT : CC = gcc CPP = g++ Target = ../lgiide ifndef Build Build = Debug endif BuildDir = $(Build) MakeDir := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) Flags = -fPIC -w -fno-inline -fpermissive ifeq ($(Build),Debug) Flags += -MMD -MP -g -std=c++14 Tag = d Defs = -D_DEBUG -DLINUX -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DPOSIX Libs = \ -lmagic \ -lpthread \ `pkg-config --libs gtk+-3.0` \ -static-libgcc \ -llgi-gtk3$(Tag) \ -L../../$(BuildDir) Inc = \ `pkg-config --cflags gtk+-3.0` \ -I$(MakeDir)/../src \ -I$(MakeDir)/../resources \ -I$(MakeDir)/../../include/lgi/linux/Gtk \ -I$(MakeDir)/../../include/lgi/linux \ -I$(MakeDir)/../../include \ -I$(MakeDir)/../../../../../codelib/openssl/include else Flags += -MMD -MP -s -Os -std=c++14 Defs = -DLINUX -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DPOSIX Libs = \ -lmagic \ -lpthread \ `pkg-config --libs gtk+-3.0` \ -static-libgcc \ -llgi-gtk3$(Tag) \ -L../$(BuildDir) Inc = \ `pkg-config --cflags gtk+-3.0` \ -I./src \ -I./resources \ -I../include/lgi/linux/Gtk \ -I../include/lgi/linux \ -I../include \ -I../../../../codelib/openssl/include endif # Dependencies Source = ../src/WebFldDlg.cpp \ ../src/SysCharSupport.cpp \ ../src/SpaceTabConv.cpp \ ../src/SimpleCppParser.cpp \ ../src/PythonParser.cpp \ ../src/ProjectNode.cpp \ ../src/NewProjectFromTemplate.cpp \ ../src/MissingFiles.cpp \ ../src/MemDumpViewer.cpp \ ../src/LgiUtils.cpp \ ../src/LgiIde.cpp \ - ../src/levenshtein.c \ ../src/JavascriptParser.cpp \ ../src/IdeProjectSettings.cpp \ ../src/IdeProject.cpp \ ../src/IdeDoc.cpp \ ../src/IdeCommon.cpp \ ../src/History.cpp \ ../src/FtpThread.cpp \ ../src/FindSymbol.cpp \ ../src/FindInFiles.cpp \ ../src/DocEditStyling.cpp \ ../src/DocEdit.cpp \ ../src/Debugger.cpp \ ../src/DebugContext.cpp \ ../src/AddFtpFile.cpp \ ../../src/common/Text/TextConvert.cpp \ ../../src/common/Text/HtmlParser.cpp \ ../../src/common/Text/HtmlCommon.cpp \ ../../src/common/Text/Html.cpp \ ../../src/common/Text/Homoglyphs/HomoglyphsTable.cpp \ ../../src/common/Text/Homoglyphs/Homoglyphs.cpp \ ../../src/common/Text/DocView.cpp \ ../../src/common/Net/OpenSSLSocket.cpp \ ../../src/common/Net/Http.cpp \ ../../src/common/Net/Ftp.cpp \ ../../src/common/Lgi/Mdi.cpp \ ../../src/common/Lgi/LgiMain.cpp \ ../../src/common/Lgi/About.cpp \ ../../src/common/Gdc2/Filters/Png.cpp \ ../../src/common/Coding/ParseCpp.cpp \ ../../src/common/Coding/LexCpp.cpp # https://stackoverflow.com/questions/49667011/compiling-both-c-and-cpp-source-in-a-single-makefile-target SourceC := $(filter %.c,$(Source)) ObjectsC := $(SourceC:.c=.o) SourceCpp := $(filter %.cpp,$(Source)) ObjectsCpp := $(SourceCpp:.cpp=.o) Objects := $(notdir $(ObjectsC) $(ObjectsCpp)) Objects := $(addprefix $(BuildDir)/,$(Objects)) Deps := $(patsubst %.o,%.d,$(Objects)) # Target # Executable target $(Target) : ../../$(BuildDir)/liblgi-gtk3$(Tag).so $(Objects) mkdir -p $(BuildDir) @echo Linking $(Target) [$(Build)]... $(CPP) -Wl,-export-dynamic,-R. -o \ $(Target) $(Objects) $(Libs) @echo Done. $(BuildDir)/%.o: %.c mkdir -p $(@D) echo $(notdir $<) [$(Build)] $(CC) $(Inc) $(Flags) $(Defs) -c $< -o $@ $(BuildDir)/%.o: %.cpp mkdir -p $(@D) echo $(notdir $<) [$(Build)] $(CPP) $(Inc) $(Flags) $(Defs) -c $< -o $@ VPATH=$(BuildDir) \ ../src \ ../../src/common/Text \ ../../src/common/Text/Homoglyphs \ ../../src/common/Net \ ../../src/common/Lgi \ ../../src/common/Gdc2/Filters \ ../../src/common/Coding ../../$(BuildDir)/liblgi-gtk3$(Tag).so : ../../include/lgi/common/App.h \ ../../include/lgi/common/Array.h \ ../../include/lgi/common/AutoPtr.h \ ../../include/lgi/common/Box.h \ ../../include/lgi/common/Button.h \ ../../include/lgi/common/Cancel.h \ ../../include/lgi/common/CheckBox.h \ ../../include/lgi/common/ClipBoard.h \ ../../include/lgi/common/Colour.h \ ../../include/lgi/common/ColourSpace.h \ ../../include/lgi/common/Com.h \ ../../include/lgi/common/Combo.h \ ../../include/lgi/common/Containers.h \ ../../include/lgi/common/Css.h \ ../../include/lgi/common/CssTools.h \ ../../include/lgi/common/DataDlg.h \ ../../include/lgi/common/DateTime.h \ ../../include/lgi/common/Dialog.h \ ../../include/lgi/common/DisplayString.h \ ../../include/lgi/common/DocView.h \ ../../include/lgi/common/Dom.h \ ../../include/lgi/common/DragAndDrop.h \ ../../include/lgi/common/DropFiles.h \ ../../include/lgi/common/Edit.h \ ../../include/lgi/common/Error.h \ ../../include/lgi/common/EventTargetThread.h \ ../../include/lgi/common/File.h \ ../../include/lgi/common/FileSelect.h \ ../../include/lgi/common/Filter.h \ ../../include/lgi/common/FindReplaceDlg.h \ ../../include/lgi/common/Font.h \ ../../include/lgi/common/FontCache.h \ ../../include/lgi/common/FontSelect.h \ ../../include/lgi/common/Gdc2.h \ ../../include/lgi/common/GdcTools.h \ ../../include/lgi/common/GdiLeak.h \ ../../include/lgi/common/HashTable.h \ ../../include/lgi/common/Input.h \ ../../include/lgi/common/ItemContainer.h \ ../../include/lgi/common/Json.h \ ../../include/lgi/common/Layout.h \ ../../include/lgi/common/Lgi.h \ ../../include/lgi/common/LgiClasses.h \ ../../include/lgi/common/LgiCommon.h \ ../../include/lgi/common/LgiDefs.h \ ../../include/lgi/common/LgiInc.h \ ../../include/lgi/common/LgiInterfaces.h \ ../../include/lgi/common/LgiMsgs.h \ ../../include/lgi/common/LgiNetInc.h \ ../../include/lgi/common/LgiRes.h \ ../../include/lgi/common/LgiString.h \ ../../include/lgi/common/LgiUiBase.h \ ../../include/lgi/common/Library.h \ ../../include/lgi/common/List.h \ ../../include/lgi/common/ListItemCheckBox.h \ ../../include/lgi/common/ListItemRadioBtn.h \ ../../include/lgi/common/Mem.h \ ../../include/lgi/common/Menu.h \ ../../include/lgi/common/Message.h \ ../../include/lgi/common/Mime.h \ ../../include/lgi/common/Mru.h \ ../../include/lgi/common/Mutex.h \ ../../include/lgi/common/Net.h \ ../../include/lgi/common/NetTools.h \ ../../include/lgi/common/Notifications.h \ ../../include/lgi/common/OptionsFile.h \ ../../include/lgi/common/Password.h \ ../../include/lgi/common/PixelRops.h \ ../../include/lgi/common/Point.h \ ../../include/lgi/common/Popup.h \ ../../include/lgi/common/PopupList.h \ ../../include/lgi/common/PopupNotification.h \ ../../include/lgi/common/Printer.h \ ../../include/lgi/common/Progress.h \ ../../include/lgi/common/ProgressDlg.h \ ../../include/lgi/common/ProgressView.h \ ../../include/lgi/common/Properties.h \ ../../include/lgi/common/RadioGroup.h \ ../../include/lgi/common/Rect.h \ ../../include/lgi/common/RefCount.h \ ../../include/lgi/common/Res.h \ ../../include/lgi/common/ScrollBar.h \ ../../include/lgi/common/Slider.h \ ../../include/lgi/common/Stream.h \ ../../include/lgi/common/StringClass.h \ ../../include/lgi/common/StringLayout.h \ ../../include/lgi/common/StructuredIo.h \ ../../include/lgi/common/StructuredLog.h \ ../../include/lgi/common/SubProcess.h \ ../../include/lgi/common/TableLayout.h \ ../../include/lgi/common/TabView.h \ ../../include/lgi/common/TextFile.h \ ../../include/lgi/common/TextLabel.h \ ../../include/lgi/common/TextLog.h \ ../../include/lgi/common/TextView3.h \ ../../include/lgi/common/Thread.h \ ../../include/lgi/common/ThreadEvent.h \ ../../include/lgi/common/Token.h \ ../../include/lgi/common/ToolBar.h \ ../../include/lgi/common/ToolTip.h \ ../../include/lgi/common/Tree.h \ ../../include/lgi/common/Unicode.h \ ../../include/lgi/common/UnrolledList.h \ ../../include/lgi/common/Variant.h \ ../../include/lgi/common/View.h \ ../../include/lgi/common/Widgets.h \ ../../include/lgi/common/Window.h \ ../../include/lgi/common/XmlTree.h \ ../../include/lgi/linux/Gtk/LgiOsClasses.h \ ../../include/lgi/linux/Gtk/LgiOsDefs.h \ ../../include/lgi/linux/Gtk/LgiWidget.h \ ../../include/lgi/linux/Gtk/LgiWinManGlue.h \ ../../include/lgi/linux/SymLookup.h \ ../../include/lgi/mac/cocoa/LCocoaView.h \ ../../include/lgi/mac/cocoa/LgiMac.h \ ../../include/lgi/mac/cocoa/LgiOs.h \ ../../include/lgi/mac/cocoa/LgiOsClasses.h \ ../../include/lgi/mac/cocoa/LgiOsDefs.h \ ../../include/lgi/mac/cocoa/ObjCWrapper.h \ ../../include/lgi/mac/cocoa/SymLookup.h \ ../../private/common/FontPriv.h \ ../../private/common/ViewPriv.h \ ../../private/linux/AppPriv.h \ ../../src/common/Gdc2/15Bit.cpp \ ../../src/common/Gdc2/16Bit.cpp \ ../../src/common/Gdc2/24Bit.cpp \ ../../src/common/Gdc2/32Bit.cpp \ ../../src/common/Gdc2/8Bit.cpp \ ../../src/common/Gdc2/Alpha.cpp \ ../../src/common/Gdc2/Colour.cpp \ ../../src/common/Gdc2/Filters/Filter.cpp \ ../../src/common/Gdc2/Font/Charset.cpp \ ../../src/common/Gdc2/Font/DisplayString.cpp \ ../../src/common/Gdc2/Font/Font.cpp \ ../../src/common/Gdc2/Font/FontSystem.cpp \ ../../src/common/Gdc2/Font/FontType.cpp \ ../../src/common/Gdc2/Font/StringLayout.cpp \ ../../src/common/Gdc2/Font/TypeFace.cpp \ ../../src/common/Gdc2/GdcCommon.cpp \ ../../src/common/Gdc2/Path/Path.cpp \ ../../src/common/Gdc2/Rect.cpp \ ../../src/common/Gdc2/RopsCases.cpp \ ../../src/common/Gdc2/Surface.cpp \ ../../src/common/Gdc2/Tools/ColourReduce.cpp \ ../../src/common/Gdc2/Tools/GdcTools.cpp \ ../../src/common/General/Containers.cpp \ ../../src/common/General/DateTime.cpp \ ../../src/common/General/ExeCheck.cpp \ ../../src/common/General/FileCommon.cpp \ ../../src/common/General/Password.cpp \ ../../src/common/General/Properties.cpp \ ../../src/common/Hash/md5/md5.c \ ../../src/common/Hash/md5/md5.h \ ../../src/common/Hash/sha1/sha1.c \ ../../src/common/Hash/sha1/sha1.h \ ../../src/common/Lgi/Alert.cpp \ ../../src/common/Lgi/AppCommon.cpp \ ../../src/common/Lgi/Css.cpp \ ../../src/common/Lgi/CssTools.cpp \ ../../src/common/Lgi/DataDlg.cpp \ ../../src/common/Lgi/DragAndDropCommon.cpp \ ../../src/common/Lgi/FileSelect.cpp \ ../../src/common/Lgi/FindReplace.cpp \ ../../src/common/Lgi/FontSelect.cpp \ ../../src/common/Lgi/GuiUtils.cpp \ ../../src/common/Lgi/Input.cpp \ ../../src/common/Lgi/LgiCommon.cpp \ ../../src/common/Lgi/Library.cpp \ ../../src/common/Lgi/LMsg.cpp \ ../../src/common/Lgi/MemStream.cpp \ ../../src/common/Lgi/MenuCommon.cpp \ ../../src/common/Lgi/Mru.cpp \ ../../src/common/Lgi/Mutex.cpp \ ../../src/common/Lgi/Object.cpp \ ../../src/common/Lgi/OptionsFile.cpp \ ../../src/common/Lgi/Rand.cpp \ ../../src/common/Lgi/Stream.cpp \ ../../src/common/Lgi/SubProcess.cpp \ ../../src/common/Lgi/ThreadCommon.cpp \ ../../src/common/Lgi/ThreadEvent.cpp \ ../../src/common/Lgi/ToolTip.cpp \ ../../src/common/Lgi/TrayIcon.cpp \ ../../src/common/Lgi/Variant.cpp \ ../../src/common/Lgi/ViewCommon.cpp \ ../../src/common/Lgi/WindowCommon.cpp \ ../../src/common/Net/Base64.cpp \ ../../src/common/Net/MDStringToDigest.cpp \ ../../src/common/Net/Net.cpp \ ../../src/common/Net/NetTools.cpp \ ../../src/common/Net/Uri.cpp \ ../../src/common/Resource/LgiRes.cpp \ ../../src/common/Resource/Res.cpp \ ../../src/common/Skins/Gel/Gel.cpp \ ../../src/common/Text/DocView.cpp \ ../../src/common/Text/String.cpp \ ../../src/common/Text/TextView3.cpp \ ../../src/common/Text/Token.cpp \ ../../src/common/Text/Unicode.cpp \ ../../src/common/Text/Utf8.cpp \ ../../src/common/Text/XmlTree.cpp \ ../../src/common/Widgets/Bitmap.cpp \ ../../src/common/Widgets/Box.cpp \ ../../src/common/Widgets/Button.cpp \ ../../src/common/Widgets/CheckBox.cpp \ ../../src/common/Widgets/Combo.cpp \ ../../src/common/Widgets/Edit.cpp \ ../../src/common/Widgets/ItemContainer.cpp \ ../../src/common/Widgets/List.cpp \ ../../src/common/Widgets/Panel.cpp \ ../../src/common/Widgets/Popup.cpp \ ../../src/common/Widgets/Progress.cpp \ ../../src/common/Widgets/ProgressDlg.cpp \ ../../src/common/Widgets/RadioGroup.cpp \ ../../src/common/Widgets/ScrollBar.cpp \ ../../src/common/Widgets/Slider.cpp \ ../../src/common/Widgets/Splitter.cpp \ ../../src/common/Widgets/StatusBar.cpp \ ../../src/common/Widgets/TableLayout.cpp \ ../../src/common/Widgets/TabView.cpp \ ../../src/common/Widgets/TextLabel.cpp \ ../../src/common/Widgets/ToolBar.cpp \ ../../src/common/Widgets/Tree.cpp \ ../../src/linux/General/File.cpp \ ../../src/linux/General/Mem.cpp \ ../../src/linux/General/ShowFileProp_Linux.cpp \ ../../src/linux/Gtk/Gdc2.cpp \ ../../src/linux/Gtk/LgiWidget.cpp \ ../../src/linux/Gtk/MemDC.cpp \ ../../src/linux/Gtk/PrintDC.cpp \ ../../src/linux/Gtk/ScreenDC.cpp \ ../../src/linux/Lgi/App.cpp \ ../../src/linux/Lgi/ClipBoard.cpp \ ../../src/linux/Lgi/DragAndDrop.cpp \ ../../src/linux/Lgi/General.cpp \ ../../src/linux/Lgi/Layout.cpp \ ../../src/linux/Lgi/Menu.cpp \ ../../src/linux/Lgi/Printer.cpp \ ../../src/linux/Lgi/Thread.cpp \ ../../src/linux/Lgi/View.cpp \ ../../src/linux/Lgi/Widgets.cpp \ ../../src/linux/Lgi/Window.cpp export Build=$(Build); \ $(MAKE) -C ../../ -f Makefile.linux -include $(Objects:.o=.d) # Clean just this target clean : rm -rf $(BuildDir) $(Target) @echo Cleaned $(BuildDir) $(Target) # Clean all targets cleanall : rm -rf $(BuildDir) $(Target) @echo Cleaned $(BuildDir) $(Target) -make -C "../.." -f "Makefile.linux" clean diff --git a/Ide/src/levenshtein.c b/Ide/src/levenshtein.c deleted file mode 100755 --- a/Ide/src/levenshtein.c +++ /dev/null @@ -1,67 +0,0 @@ -/* `levenshtein.c` - levenshtein - * MIT licensed. - * Copyright (c) 2015 Titus Wormer */ - -#include -#include - -/* Returns an unsigned integer, depicting - * the difference between `a` and `b`. - * See http://en.wikipedia.org/wiki/Levenshtein_distance - * for more information. */ - -size_t -levenshtein(const char *a, const char *b) { - size_t length = strlen(a); - size_t bLength = strlen(b); - unsigned int *cache = calloc(length, sizeof(unsigned int)); - unsigned int index = 0; - unsigned int bIndex = 0; - unsigned int distance; - unsigned int bDistance; - unsigned int result = 10000; - char code; - - /* Shortcut optimizations / degenerate cases. */ - if (a == b || cache == NULL) { - return 0; - } - - if (length == 0) { - return bLength; - } - - if (bLength == 0) { - return length; - } - - /* initialize the vector. */ - while (index < length) { - cache[index] = index + 1; - index++; - } - - /* Loop. */ - while (bIndex < bLength) { - code = b[bIndex]; - result = distance = bIndex++; - index = -1; - - while (++index < length) { - bDistance = code == a[index] ? distance : distance + 1; - distance = cache[index]; - - cache[index] = result = distance > result - ? bDistance > result - ? result + 1 - : bDistance - : bDistance > distance - ? distance + 1 - : bDistance; - } - } - - free(cache); - - return result; -} diff --git a/Ide/src/levenshtein.h b/Ide/src/levenshtein.h deleted file mode 100644 --- a/Ide/src/levenshtein.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef LEVENSHTEIN_H -#define LEVENSHTEIN_H - -/* `levenshtein.h` - levenshtein - * MIT licensed. - * Copyright (c) 2015 Titus Wormer */ - -/* Returns an unsigned integer, depicting - * the difference between `a` and `b`. - * See http://en.wikipedia.org/wiki/Levenshtein_distance - * for more information. - */ -#ifdef __cplusplus -extern "C" { -#endif - -size_t -levenshtein(const char *a, const char *b); - -#ifdef __cplusplus -} -#endif - -#endif // LEVENSHTEIN_H \ No newline at end of file diff --git a/include/lgi/common/Array.h b/include/lgi/common/Array.h --- a/include/lgi/common/Array.h +++ b/include/lgi/common/Array.h @@ -1,930 +1,931 @@ /// \file /// \author Matthew Allen /// \brief Growable, type-safe array. #pragma once #include #include #include #include #include #define GARRAY_MIN_SIZE 16 #if defined(LGI_CHECK_MALLOC) && !defined(LGI_MEM_DEBUG) #error "Include GMem.h first" #endif #if defined(PLATFORM_MINGW) #ifdef __cplusplus extern "C" { #endif #ifndef _QSORT_S_DEFINED #define _QSORT_S_DEFINED _CRTIMP void __cdecl qsort_s(void *_Base, size_t _NumOfElements, size_t _SizeOfElements, int (__cdecl *_PtFuncCompare)(void *,const void *,const void *), void *_Context); #endif #ifdef __cplusplus } #endif #endif #include "lgi/common/Range.h" /// \brief Growable type-safe array. /// \ingroup Base /// /// You can store simple objects inline in this array, but all their contents are initialized /// to the octet 0x00. Which limits use to objects that don't have a virtual table and /// don't need construction (constructors are not called). /// /// The objects are copied around during use so you can't assume their pointer /// will remain the same over time either. However when objects are deleted from the /// array their destructors WILL be called. This allows you to have simple objects that /// have dynamically allocated pointers that are freed properly. A good example of this /// type of object is the LVariant or LAutoString class. /// /// If you want to store objects with a virtual table, or that need their constructor /// to be called then you should create the LArray with pointers to the objects instead /// of inline objects. And to clean up the memory you can call LArray::DeleteObjects or /// LArray::DeleteArrays. template class LArray { Type *p; size_t len; size_t alloc; #ifdef _DEBUG public: size_t GetAlloc() { return alloc; } #endif protected: bool fixed = false; bool warnResize = true; public: typedef Type ItemType; /// Constructor LArray(size_t PreAlloc = 0) { p = 0; alloc = len = PreAlloc; fixed = false; if (alloc) { size_t Bytes = sizeof(Type) * alloc; p = (Type*) malloc(Bytes); if (p) { memset(p, 0, Bytes); } else { alloc = len = 0; } } } LArray(std::initializer_list il) { p = NULL; alloc = len = 0; fixed = false; if (Length(il.size())) { size_t n = 0; for (auto i: il) p[n++] = i; } } LArray(const LArray &c) { p = 0; alloc = len = 0; fixed = false; *this = c; } /// Destructor ~LArray() { Length(0); } /// This frees the memory without calling the destructor of the elements. /// Useful if you're storing large amounts of plain data types, like char or int. void Free() { if (p) { free(p); p = NULL; } len = alloc = 0; } /// Does a range check on a pointer... /// \returns true if the pointer is pointing to a valid object /// in this array. bool PtrCheck(void *Ptr) { return p != NULL && Ptr >= p && Ptr < &p[len]; } /// Does a range check on an index... bool IdxCheck(ssize_t i) const { return i >= 0 && i < (ssize_t)len; } /// Returns the number of used entries size_t Length() const { return len; } /// Makes the length fixed.. - void SetFixedLength(bool fix = true) + void SetFixedLength(bool fix = true, bool warn = true) { fixed = fix; + warnResize = warn; } /// Emtpies the array of all objects. bool Empty() { return Length(0); } /// Sets the length of available entries bool Length(size_t i) { if (i > 0) { if (i > len && fixed) { assert(!"Attempt to enlarged fixed array."); return false; } size_t nalloc = alloc; if (i < len) { // Shrinking } else { // Expanding nalloc = 0x10; while (nalloc < i) nalloc <<= 1; assert(nalloc >= i); } if (nalloc != alloc) { Type *np = (Type*)malloc(sizeof(Type) * nalloc); if (!np) { return false; } memset(np + len, 0, (nalloc - len) * sizeof(Type)); if (p) { // copy across common elements memcpy(np, p, MIN(len, i) * sizeof(Type)); free(p); } p = np; alloc = nalloc; } if (i > len) { // zero new elements memset(p + len, 0, sizeof(Type) * (nalloc - len)); } else if (i < len) { for (size_t n=i; n &a) const { if (Length() != a.Length()) return false; for (size_t i=0; i &a) const { return !(*this == a); } LArray &operator =(const LArray &a) { Length(a.Length()); if (p && a.p) { for (size_t i=0; i= 0 && (uint32_t)i < len) return p[i]; static Type t; return t; } // Returns the address of an item or NULL if index is out of range Type *AddressOf(size_t i = 0) { return i < len ? p + i : NULL; } /// \brief Returns a reference a given entry. /// /// If the entry is off the end of the array and "fixed" is false, /// it will grow to make it valid. Type &operator [](size_t i) { static Type t; if ( (fixed && (uint32_t)i >= len) ) { if (warnResize) assert(!"Attempt to enlarged fixed array."); return t; } if (i >= (int)alloc) { // increase array length size_t nalloc = MAX(alloc, GARRAY_MIN_SIZE); while (nalloc <= (uint32_t)i) { nalloc <<= 1; } #if 0 if (nalloc > 1<<30) { #if defined(_DEBUG) && defined(_MSC_VER) LAssert(0); #endif ZeroObj(t); return t; } #endif // alloc new array Type *np = (Type*) malloc(sizeof(Type) * nalloc); if (np) { // clear new cells memset(np + len, 0, (nalloc - len) * sizeof(Type)); if (p) { // copy across old cells memcpy(np, p, len * sizeof(Type)); // clear old array free(p); } // new values p = np; alloc = nalloc; } else { static Type *t = 0; return *t; } } // adjust length of the the array if ((uint32_t)i + 1 > len) { len = i + 1; } return p[i]; } /// Delete all the entries as if they are pointers to objects void DeleteObjects() { if (len > 0) { size_t InitialLen = len; delete p[0]; if (InitialLen == len) { // Non self deleting for (uint i=1; i= 0; } /// Removes last element bool PopLast() { if (len <= 0) return false; return Length(len - 1); } /// Deletes an entry bool DeleteAt ( /// The index of the entry to delete size_t Index, /// true if the order of the array matters, otherwise false. bool Ordered = false ) { if (p && Index < len) { // Delete the object p[Index].~Type(); // Move the memory up if (Index < len - 1) { if (Ordered) { memmove(p + Index, p + Index + 1, (len - Index - 1) * sizeof(Type) ); } else { p[Index] = p[len-1]; } } // Adjust length len--; // Kill the element at the end... otherwise New() returns non-zero data. memset(p + len, 0, sizeof(Type)); return true; } return false; } /// Deletes a range. /// This operation always maintains order. /// \returns the number of removed elements ssize_t DeleteRange(LRange r) { // Truncate range to the size of this array if (r.Start < 0) r.Start = 0; if (r.End() >= (ssize_t)len) r.Len = len - r.Start; // Delete all the elements we are removing for (ssize_t i=r.Start; i 0) memmove(&p[r.Start], &p[r.End()], sizeof(Type)*Remain); len = r.Start + Remain; return r.Len; } /// Deletes the entry 'n' bool Delete ( /// The value of the entry to delete Type n, /// true if the order of the array matters, otherwise false. bool Ordered = false ) { ssize_t i = IndexOf(n); if (p && i >= 0) { return DeleteAt(i, Ordered); } return false; } /// Appends an element void Add ( /// Item to insert const Type &n ) { (*this)[len] = n; } /// Appends multiple elements bool Add ( /// Items to insert const Type *s, /// Length of array ssize_t count ) { if (!s || count < 1) return false; ssize_t i = len; if (!Length(len + count)) return false; Type *d = p + i; while (count--) { *d++ = *s++; } return true; } /// Appends an array of elements bool Add ( /// Array to insert const LArray &a ) { ssize_t old = len; if (Length(len + a.Length())) { for (unsigned i=0; i operator +(const LArray &b) { LArray a = *this; a.Add(b); return a; } LArray &operator +=(const LArray &b) { Add(b); return *this; } /// Inserts an element into the array bool AddAt ( /// Item to insert before size_t Index, /// Item to insert Type n ) { // Make room if (!Length(len + 1)) return false; if (Index < len - 1) // Shift elements after insert point up one memmove(p + Index + 1, p + Index, (len - Index - 1) * sizeof(Type) ); else // Add at the end, not after the end... Index = len - 1; // Insert item memset(p + Index, 0, sizeof(*p)); p[Index] = n; return true; } /// Inserts an array into the array at a position bool AddAt ( /// Item to insert before size_t Index, /// Array to insert const LArray &a ) { // Make room if (!Length(len + a.Length())) return false; if (Index < len - 1) // Shift elements after insert point up one memmove(p + Index + a.Length(), p + Index, (len - Index - a.Length()) * sizeof(Type) ); else // Add at the end, not after the end... Index = len - 1; // Insert items memset(p + Index, 0, a.Length() * sizeof(*p)); for (size_t i=0; i 0) return 1; return r < 0 ? -1 : 0; }); } /// Sorts the array via a callback. void Sort(std::function Compare) { #if !defined(WINDOWS) && !defined(HAIKU) && !defined(LINUX) #define USER_DATA_FIRST 1 #else #define USER_DATA_FIRST 0 #endif #if defined(WINDOWS) /* _ACRTIMP void __cdecl qsort_s(void* _Base, rsize_t _NumOfElements, rsize_t _SizeOfElements, int (__cdecl* _PtFuncCompare)(void*, void const*, void const*), void* _Context); */ qsort_s #else qsort_r #endif ( p, len, sizeof(Type), #if USER_DATA_FIRST &Compare, #endif #if defined(HAIKU) || defined(LINUX) // typedef int (*_compare_function_qsort_r)(const void*, const void*, void*); // extern void qsort_r(void* base, size_t numElements, size_t sizeOfElement, _compare_function_qsort_r, void* cookie); [](const void *a, const void *b, void *ud) -> int #else [](void *ud, const void *a, const void *b) -> int #endif { return (*( (std::function*)ud ))((Type*)a, (Type*)b); } #if !USER_DATA_FIRST , &Compare #endif ); } /// \returns a reference to a new object on the end of the array /// /// Never assign this to an existing variable. e.g: /// LArray a; /// MyObject &o = a.New(); /// o.Type = something; /// o = a.New(); /// o.Type = something else; /// /// This causes the first object to be overwritten with a blank copy. Type &New() { return (*this)[len]; } /// Returns the memory held by the array and sets itself to empty Type *Release() { Type *Ptr = p; p = 0; len = alloc = 0; return Ptr; } void Swap(LArray &other) { LSwap(p, other.p); LSwap(len, other.len); LSwap(alloc, other.alloc); } /// Swaps a range of elements between this array and 'b' bool SwapRange ( // The range of 'this' to swap out LRange aRange, // The other array to swap with LArray &b, // The range of 'b' to swap with this array LRange bRange ) { LArray Tmp; // Store entries in this that will be swapped Tmp.Add(AddressOf(aRange.Start), aRange.Len); // Copy b's range into this ssize_t Common = MIN(bRange.Len, aRange.Len); ssize_t aIdx = aRange.Start; ssize_t bIdx = bRange.Start; for (int i=0; i bRange.Len) { // Shrink the range in this to fit 'b' ssize_t Del = aRange.Len - bRange.Len; for (ssize_t i=0; i bRange.Len) { // Grow range to fit this ssize_t Add = aRange.Len - bRange.Len; for (ssize_t i=0; i class Iter { friend class ::LArray; ssize_t i; char each_dir; LArray *a; public: Iter(LArray *arr) // 'End' constructor { i = -1; a = arr; each_dir = 0; } Iter(LArray *arr, size_t pos) { i = pos; a = arr; each_dir = 0; } bool operator ==(const Iter &it) const { int x = (int)In() + (int)it.In(); if (x == 2) return (a == it.a) && (i == it.i); return x == 0; } bool operator !=(const Iter &it) const { return !(*this == it); } operator bool() const { return In(); } bool In() const { return i >= 0 && i < (ssize_t)a->Length(); } bool End() const { return i < 0 || i >= a->Length(); } T &operator *() { return (*a)[i]; } Iter &operator ++() { i++; return *this; } Iter &operator --() { i--; return *this; } Iter &operator ++(int) { i++; return *this; } Iter &operator --(int) { i--; return *this; } }; typedef Iter I; I begin(size_t start = 0) { return I(this, start); } I rbegin() { return I(this, len-1); } I end() { return I(this); } bool Delete(I &It) { return DeleteAt(It.i, true); } LArray Slice(ssize_t Start, ssize_t End = -1) { LArray a; // Range limit the inputs... if (Start < 0) Start = len + Start; if (Start > (ssize_t)len) Start = len; if (End < 0) End = len + End + 1; if (End > (ssize_t)len) End = len; if (End > Start) { a.Length(End - Start); for (size_t i=0; i Reverse() { LArray r; r.Length(len); for (size_t i=0, k=len-1; i Compare) { static Type Empty; if (!Compare) return Empty; for (size_t s = 0, e = len - 1; s <= e; ) { if (e - s < 2) { if (Compare(p[s]) == 0) return p[s]; if (e > s && Compare(p[e]) == 0) return p[e]; break; // Not found } size_t mid = s + ((e - s) >> 1); int result = Compare(p[mid]); if (result == 0) return p[mid]; if (result < 0) s = mid + 1; // search after the mid point else e = mid - 1; // search before } return Empty; } }; diff --git a/include/lgi/common/Levenshtein.h b/include/lgi/common/Levenshtein.h new file mode 100644 --- /dev/null +++ b/include/lgi/common/Levenshtein.h @@ -0,0 +1,73 @@ +/* Levenshtein.h - levenshtein algorithm. + * MIT licensed. + * Copyright (c) 2015 Titus Wormer + * + * Returns an unsigned integer, depicting + * the difference between `a` and `b`. + * See http://en.wikipedia.org/wiki/Levenshtein_distance + * for more information. + */ + +#pragma once + +inline +size_t +LLevenshtein(const char *a, const char *b) +{ + size_t aLen = Strlen(a); + auto cache = (size_t*)calloc(aLen, sizeof(size_t)); + size_t result = 10000; + + /* Shortcut optimizations / degenerate cases. */ + if (a == b || cache == NULL) + return 0; + + size_t bLen = Strlen(b); + if (aLen == 0) + { + result = bLen; + goto onComplete; + } + if (bLen == 0) + { + result = aLen; + goto onComplete; + } + + size_t aIndex = 0; + size_t bIndex = 0; + size_t distance; + + /* initialize the vector. */ + while (aIndex < aLen) + { + cache[aIndex] = aIndex + 1; + aIndex++; + } + + /* Loop. */ + while (bIndex < bLen) + { + auto code = b[bIndex]; + result = distance = bIndex++; + aIndex = -1; + + while (++aIndex < aLen) + { + auto bDistance = code == a[aIndex] ? distance : distance + 1; + distance = cache[aIndex]; + + cache[aIndex] = result = distance > result + ? bDistance > result + ? result + 1 + : bDistance + : bDistance > distance + ? distance + 1 + : bDistance; + } + } + +onComplete: + free(cache); + return result; +} diff --git a/include/lgi/common/StringClass.h b/include/lgi/common/StringClass.h --- a/include/lgi/common/StringClass.h +++ b/include/lgi/common/StringClass.h @@ -1,1255 +1,1255 @@ /* * A mis-guided attempt to make a string class look and feel like a python string. * * Author: Matthew Allen * Email: fret@memecode.com * Created: 16 Sept 2014 */ #pragma once #include #include #include #if defined(_MSC_VER) || defined(__GTK_H__) // This fixes compile errors in VS2008/Gtk #undef _SIGN_DEFINED #undef abs #endif #include #if defined(_MSC_VER) && _MSC_VER < 1800/*_MSC_VER_VS2013*/ #include #define PRId64 "I64i" #else #define __STDC_FORMAT_MACROS 1 #include #include #ifndef PRId64 #warning "PRId64 not defined." #define PRId64 "Ld" #endif #endif #include "LgiOsDefs.h" #include "lgi/common/Unicode.h" #include "lgi/common/Array.h" #ifndef IsDigit #define IsDigit(ch) ((ch) >= '0' && (ch) <= '9') #endif LgiExtern int LPrintf(class LString &Str, const char *Format, va_list &Arg); /// A pythonic string class. class LString { protected: /// This structure holds the string's data itself and is shared /// between one or more LString instances. struct RefStr { /// A reference count int32 Refs; /// The bytes in 'Str' not including the NULL terminator size_t Len; /// The first byte of the string. Further bytes are allocated /// off the end of the structure using malloc. This must always /// be the last element in the struct. char Str[1]; } *Str; inline void _strip(LString &ret, const char *set, bool left, bool right) { if (!Str) return; char *s = Str->Str; char *e = s + Str->Len; if (!set) set = " \t\r\n"; if (left) { while (s < e && strchr(set, *s)) s++; } if (right) { while (e > s && strchr(set, e[-1])) e--; } if (e > s) ret.Set(s, e - s); } public: #ifdef LGI_UNIT_TESTS static int32 RefStrCount; #endif /// A copyable array of strings class Array : public LArray { public: Array(size_t PreAlloc = 0) : LArray(PreAlloc) { // This allows the parent array to return an empty // string without asserting if the caller requests an // out of range index warnResize = false; } Array(const Array &a) { *this = (Array&)a; } Array &operator =(const Array &a) { SetFixedLength(false); *((LArray*)this) = a; SetFixedLength(true); return *this; } Array &operator +=(const Array &a) { SetFixedLength(false); Add(a); SetFixedLength(true); return *this; } Array &operator +=(const LArray &a) { SetFixedLength(false); Add(a); SetFixedLength(true); return *this; } }; /// Empty constructor LString() { Str = NULL; } // This odd looking constructor allows the object to be used as the value type // in a GHashTable, where the initialiser is '0', an integer. LString(int i) { Str = NULL; } #ifndef _MSC_VER // This odd looking constructor allows the object to be used as the value type // in a GHashTable, where the initialiser is '0', an integer. LString(long int i) { Str = NULL; } #endif /// String constructor LString(const char *str, ptrdiff_t bytes) { Str = NULL; Set(str, bytes); } /// const char* constructor LString(const char *str) { Str = NULL; Set(str); } /// const char16* constructor LString(const wchar_t *str, ptrdiff_t wchars = -1) { Str = NULL; SetW(str, wchars); } #if defined(_WIN32) || defined(MAC) /// const uint32* constructor LString(const uint32_t *str, ptrdiff_t chars = -1) { Str = NULL; if (chars < 0) chars = Strlen(str); ptrdiff_t utf_len = 0; const uint32_t *end = str + chars; const uint32_t *c = str; while (c < end) { uint8_t utf[6], *u = utf; ssize_t len = sizeof(utf); if (!LgiUtf32To8(*c++, u, len)) break; utf_len += u - utf; } if (Length((uint32_t)utf_len)) { c = str; uint8_t *u = (uint8_t*)Str->Str; ssize_t len = Str->Len; while (c < end) { if (!LgiUtf32To8(*c++, u, len)) break; } *u++ = 0; } } #endif /// LString constructor LString(const LString &s) { Str = s.Str; if (Str) Str->Refs++; } ~LString() { Empty(); } /// Removes a reference to the string and deletes if needed void Empty() { if (!Str) return; Str->Refs--; if (Str->Refs < 0) { assert(!"Invalid refs"); } if (Str->Refs == 0) { free(Str); #ifdef LGI_UNIT_TESTS RefStrCount--; #endif } Str = NULL; } /// Returns the pointer to the string data char *Get() const { return Str ? Str->Str : NULL; } /// Sets the string to a new value bool Set ( /// Can be a pointer to string data or NULL to create an empty buffer (requires valid length) const char *str, /// Byte length of input string or -1 to copy till the NULL terminator. ptrdiff_t bytes = -1 ) { Empty(); if (bytes < 0) { if (str) bytes = strlen(str); else return false; } Str = (RefStr*)malloc(sizeof(RefStr) + bytes); if (!Str) return false; Str->Refs = 1; Str->Len = (uint32_t)bytes; #ifdef LGI_UNIT_TESTS RefStrCount++; #endif if (str) memcpy(Str->Str, str, bytes); Str->Str[bytes] = 0; return true; } /// Sets the string to a new value bool SetW ( /// Can be a pointer to string data or NULL to create an empty buffer (requires valid length) const wchar_t *str, /// Number of 'char16' values in the input string or -1 to copy till the NULL terminator. ptrdiff_t wchars = -1 ) { size_t Sz = WideToUtf8Len(str, wchars); if (Length(Sz)) { #ifdef _MSC_VER const uint16 *i = (const uint16*) str; ssize_t InLen = wchars >= 0 ? wchars << 1 : 0x7fffffff; assert(sizeof(*i) == sizeof(*str)); uint8_t *o = (uint8_t*)Str->Str; ssize_t OutLen = Str->Len; for (uint32_t ch; ch = LgiUtf16To32(i, InLen); ) { if (!LgiUtf32To8(ch, o, OutLen)) { *o = 0; break; } } #else uint8_t *o = (uint8_t*)Str->Str; ssize_t OutLen = Str->Len; if (wchars >= 0) { const wchar_t *end = str + wchars; for (const wchar_t *ch = str; ch < end; ch++) { if (!LgiUtf32To8(*ch, o, OutLen)) { *o = 0; break; } } } else { for (const wchar_t *ch = str; *ch; ch++) { if (!LgiUtf32To8(*ch, o, OutLen)) { *o = 0; break; } } } #endif *o = 0; } return true; } /// Equality operator (case sensitive) bool operator ==(const LString &s) { const char *a = Get(); const char *b = s.Get(); if (!a && !b) return true; if (!a || !b) return false; return !strcmp(a, b); } bool operator !=(const LString &s) { return !(*this == s); } // Equality function (default: case insensitive, as the operator== is case sensitive) bool Equals(const char *b, bool CaseInsensitive = true) const { const char *a = Get(); if (!a && !b) return true; if (!a || !b) return false; return !(CaseInsensitive ? _stricmp(a, b) : strcmp(a, b)); } // Equality function (default: case insensitive, as the operator== is case sensitive) bool Equals(const LString &s, bool CaseInsensitive = true) const { const char *a = Get(); const char *b = s.Get(); if (!a && !b) return true; if (!a || !b) return false; return !(CaseInsensitive ? _stricmp(a, b) : strcmp(a, b)); } /// Assignment operator to copy one string to another LString &operator =(const LString &s) { if (this != &s) { Empty(); Str = s.Str; if (Str) Str->Refs++; } return *this; } /// Equality with a C string (case sensitive) bool operator ==(const char *b) { const char *a = Get(); if (!a && !b) return true; if (!a || !b) return false; return !strcmp(a, b); } bool operator !=(const char *b) { return !(*this == b); } /// Assignment operators LString &operator =(const char *s) { if (Str == NULL || s < Str->Str || s > Str->Str + Str->Len) { Empty(); Set(s); } else if (s != Str->Str) { // Special case for setting it to part of itself // If you try and set a string to the start, it's a NOP ptrdiff_t Off = s - Str->Str; memmove(Str->Str, s, Str->Len - Off + 1); Str->Len -= (uint32_t)Off; } return *this; } LString &operator =(const wchar_t *s) { SetW(s); return *this; } LString &operator =(int val) { char n[32]; sprintf_s(n, sizeof(n), "%i", val); Set(n); return *this; } LString &operator =(int64 val) { char n[32]; sprintf_s(n, sizeof(n), "%" PRId64, (int64_t)val); Set(n); return *this; } /// Cast to C string operator operator char *() const { return Str && Str->Len > 0 ? Str->Str : NULL; } int operator -(const LString &s) const { return Stricmp(Get(), s.Get()); } /// Concatenation operator LString operator +(const LString &s) { LString Ret; size_t Len = Length() + s.Length(); if (Ret.Set(NULL, Len)) { char *p = Ret.Get(); if (p) { if (Str) { memcpy(p, Str->Str, Str->Len); p += Str->Len; } if (s.Str) { memcpy(p, s.Str->Str, s.Str->Len); p += s.Str->Len; } *p++ = 0; } } return Ret; } /// Concatenation / assignment operator LString &operator +=(const LString &s) { ssize_t Len = Length() + s.Length(); ssize_t Alloc = sizeof(RefStr) + Len; RefStr *rs = (RefStr*)malloc(Alloc); if (rs) { rs->Refs = 1; rs->Len = Len; #ifdef LGI_UNIT_TESTS RefStrCount++; #endif char *p = rs->Str; if (Str) { memcpy(p, Str->Str, Str->Len); p += Str->Len; } if (s.Str) { memcpy(p, s.Str->Str, s.Str->Len); p += s.Str->Len; } *p++ = 0; assert(p - (char*)rs <= Alloc); Empty(); Str = rs; } return *this; } LString operator *(ssize_t mul) { LString s; if (Str) { s.Length(Str->Len * mul); char *out = s.Get(); for (ssize_t i=0; iLen) memcpy(out, Str->Str, Str->Len); *out = 0; } return s; } /// Gets the length in bytes size_t Length() const { return Str ? Str->Len : 0; } size_t Length(ssize_t NewLen) { if (NewLen < 0) { LAssert(!"No negative string len."); Empty(); } else if (Str) { if (NewLen <= (ssize_t)Str->Len) { Str->Len = NewLen; Str->Str[NewLen] = 0; } else { RefStr *n = (RefStr*)malloc(sizeof(RefStr) + NewLen); if (n) { n->Len = NewLen; n->Refs = 1; memcpy(n->Str, Str->Str, Str->Len); n->Str[Str->Len] = 0; // NULL terminate... Empty(); // Deref the old string... Str = n; } else return 0; } } else { Str = (RefStr*)malloc(sizeof(RefStr) + NewLen); if (Str) { Str->Len = NewLen; Str->Refs = 1; Str->Str[0] = 0; // NULL terminate... } else return 0; } return Str ? Str->Len : 0; } /// Splits the string into parts using a separator Array Split(const char *Sep, int Count = -1, bool CaseSen = false) { Array a; if (Str && Sep) { const char *s = Str->Str, *Prev = s; const char *end = s + Str->Len; size_t SepLen = strlen(Sep); if (s[Str->Len] == 0) { while ((s = CaseSen ? strstr(s, Sep) : Stristr(s, Sep))) { if (s > Prev) a.New().Set(Prev, s - Prev); s += SepLen; Prev = s; if (Count > 0 && a.Length() >= (uint32_t)Count) break; } if (Prev < end) a.New().Set(Prev, end - Prev); a.SetFixedLength(); } else assert(!"String not NULL terminated."); } return a; } /// Splits the string into parts using a separator Array RSplit(const char *Sep, int Count = -1, bool CaseSen = false) { Array a; if (Str && Sep) { const char *s = Get(); size_t SepLen = strlen(Sep); LArray seps; while ((s = CaseSen ? strstr(s, Sep) : Stristr(s, Sep))) { seps.Add(s); s += SepLen; } ssize_t i, Last = seps.Length() - 1; LString p; for (i=Last; i>=0; i--) { const char *part = seps[i] + SepLen; if (i == Last) p.Set(part); else p.Set(part, seps[i+1]-part); a.AddAt(0, p); if (Count > 0 && a.Length() >= (uint32_t)Count) break; } const char *End = seps[i > 0 ? i : 0]; p.Set(Get(), End - Get()); a.AddAt(0, p); } - a.SetFixedLength(); + a.SetFixedLength(true, false); return a; } /// Splits the string into parts using delimiter chars Array SplitDelimit(const char *Delimiters = NULL, int Count = -1, bool GroupDelimiters = true) const { Array a; if (Str) { const char *delim = Delimiters ? Delimiters : " \t\r\n"; const char *s = Get(), *end = s + Length(); while (s < end) { // Skip over non-delimiters const char *e = s; while (e < end && !strchr(delim, *e)) e++; if (e > s || !GroupDelimiters) a.New().Set(s, e - s); s = e; if (*s) s++; if (GroupDelimiters) { // Skip any delimiters while (s < end && strchr(delim, *s)) s++; } // Create the string if (Count > 0 && a.Length() >= (uint32_t)Count) break; } if ( s < end || ( !GroupDelimiters && s > Get() && strchr(delim, s[-1]) ) ) a.New().Set(s); } - a.SetFixedLength(); + a.SetFixedLength(true, false); return a; } /// Joins an array of strings using a separator LString Join(const LArray &a) { LString ret; if (a.Length() == 0) return ret; char *Sep = Get(); size_t SepLen = Sep ? strlen(Sep) : 0; size_t Bytes = SepLen * (a.Length() - 1); LArray ALen; for (unsigned i=0; iStr; LArray Matches; while ((Match = (CaseSen ? strstr(Match, Old) : Stristr(Match, Old)))) { Matches.Add(Match); if (Count >= 0 && (int)Matches.Length() >= Count) break; Match += OldLen; } size_t NewSize = Str->Len + (Matches.Length() * (NewLen - OldLen)); s.Length((uint32_t)NewSize); char *Out = s.Get(); char *In = Str->Str; // For each match... for (unsigned i=0; iStr + Str->Len; if (In < End) { ptrdiff_t Bytes = End - In; memcpy(Out, In, Bytes); Out += Bytes; } assert(Out - s.Get() == NewSize); // Check we got the size right... *Out = 0; // Null terminate } else { s = *this; } return s; } /// Convert string to double double Float() { return Str ? atof(Str->Str) : NAN; } /// Convert to integer int64 Int(int Base = 10) { if (!Str) return -1; if ( Str->Len > 2 && Str->Str[0] == '0' && ( Str->Str[1] == 'x' || Str->Str[1] == 'X' ) ) { return Atoi(Str->Str+2, 16); } return Atoi(Str->Str, Base); } /// Checks if the string is a number bool IsNumeric() { if (!Str) return false; for (char *s = Str->Str; *s; s++) { if (!IsDigit(*s) && !strchr("e-+.", *s)) return false; } return true; } /// Check for non whitespace bool IsEmpty() { if (!Str) return true; for (char *s = Str->Str; *s; s++) { if (*s != ' ' && *s != '\t' && *s != '\r' && *s != '\n') return false; } return true; } /// Reverses all the characters in the string LString Reverse() { LString s; if (Length() > 0) { s = Str->Str; for (auto *a = s.Get(), *b = s.Get() + s.Length() - 1; a < b; a++, b--) { char t = *a; *a = *b; *b = t; } } return s; } /// Find a sub-string ssize_t Find(const char *needle, ssize_t start = 0, ssize_t end = -1) { if (!needle) return -1; char *c = Get(); if (!c) return -1; char *pos = c + start; while (c < pos) { if (!*c) return -1; c++; } char *found = (end > 0) ? Strnstr(c, needle, end - start) : strstr(c, needle); return (found) ? found - Get() : -1; } /// Reverse find a string (starting from the end) ssize_t RFind(const char *needle, int start = 0, ssize_t end = -1) { if (!needle) return -1; char *c = Get(); if (!c) return -1; char *pos = c + start; while (c < pos) { if (!*c) return -1; c++; } char *found, *prev = NULL; size_t str_len = strlen(needle); while (( found = ( (end > 0) ? Strnstr(c, needle, end - start) : strstr(c, needle) ) )) { prev = found; c = found + str_len; } return (prev) ? prev - Get() : -1; } /// Returns a copy of the string with all the characters converted to lower case LString Lower() { LString s; if (Str && s.Set(Str->Str, Str->Len)) Strlwr(s.Get()); return s; } /// Returns a copy of the string with all the characters converted to upper case LString Upper() { LString s; if (Str && s.Set(Str->Str, Str->Len)) Strupr(s.Get()); return s; } void Swap(LString &s) { LSwap(Str, s.Str); } /// Gets the character at 'index' int operator() (ssize_t index) const { if (!Str) return 0; char *c = Str->Str; if (index < 0) { size_t idx = Str->Len + index; return c[idx]; } else if (index < (int)Str->Len) { return c[index]; } return 0; } /// Gets the string between at 'start' and 'end' (not including the end'th character) LString operator() (ptrdiff_t start, ptrdiff_t end) { LString s; if (Str) { ptrdiff_t start_idx = start < 0 ? Str->Len + start + 1 : start; if (start_idx >= 0 && (uint32_t)start_idx < Str->Len) { ptrdiff_t end_idx = end < 0 ? Str->Len + end + 1 : end; if (end_idx >= start_idx && (uint32_t)end_idx <= Str->Len) s.Set(Str->Str + start_idx, end_idx - start_idx); } } return s; } /// Strip off any leading and trailing characters from 'set' (or whitespace if NULL) LString Strip(const char *set = NULL) { LString ret; _strip(ret, set, true, true); return ret; } /// Strip off any leading characters from 'set' (or whitespace if NULL) LString LStrip(const char *set = NULL) { LString ret; _strip(ret, set, true, false); return ret; } /// Strip off any trailing characters from 'set' (or whitespace if NULL) LString RStrip(const char *set = NULL) { LString ret; _strip(ret, set, false, true); return ret; } /// Prints a formatted string to this object int Printf(const char *Fmt, ...) { Empty(); va_list Arg; va_start(Arg, Fmt); int Bytes = Printf(Arg, Fmt); va_end(Arg); return Bytes; } /// Prints a varargs string int Printf(va_list &Arg, const char *Fmt) { Empty(); return LPrintf(*this, Fmt, Arg); } static LString Escape(const char *In, ssize_t Len = -1, const char *Chars = "\r\n\b\\\'\"") { LString s; if (In && Chars) { char Buf[256]; int Ch = 0; if (Len < 0) Len = strlen(In); while (Len-- > 0) { if (Ch > sizeof(Buf)-4) { // Buffer full, add substring to 's' Buf[Ch] = 0; s += Buf; Ch = 0; } if (strchr(Chars, *In)) { Buf[Ch++] = '\\'; switch (*In) { #undef EscChar #define EscChar(from, to) \ case from: Buf[Ch++] = to; break EscChar('\n', 'n'); EscChar('\r', 'r'); EscChar('\\', '\\'); EscChar('\b', 'b'); EscChar('\a', 'a'); EscChar('\t', 't'); EscChar('\v', 'v'); EscChar('\'', '\''); EscChar('\"', '\"'); EscChar('&', '&'); EscChar('?', '?'); #undef EscChar default: Ch += sprintf_s(Buf+Ch, sizeof(Buf)-Ch, "x%02x", *In); break; } } else Buf[Ch++] = *In; In++; } if (Ch > 0) { Buf[Ch] = 0; s += Buf; } } return s; } template static LString UnEscape(const T *In, ssize_t Len = -1) { if (!In) return LString(); LString s; if (Len < 0) // As memory allocation/copying around data is far slower then // just scanning the string for size... don't try and chunk the // processing. Len = Strlen(In); if (!s.Length(Len)) return LString(); auto *Out = s.Get(); auto *End = In + Len; while (In < End) { if (*In == '\\') { In++; switch (*In) { case 'n': case 'N': *Out++ = '\n'; break; case 'r': case 'R': *Out++ = '\r'; break; case 'b': case 'B': *Out++ = '\b'; break; case 't': case 'T': *Out++ = '\t'; break; default: *Out++ = *In; break; case 0: break; } if (*In) In++; else break; } else *Out++ = *In++; } // Trim excess size off string s.Length(Out - s.Get()); return s; } static LString UnEscape(LString s) { return UnEscape(s.Get(), s.Length()); } #if defined(__GTK_H__) #elif defined(MAC) // && __COREFOUNDATION_CFBASE__ LString(const CFStringRef r) { Str = NULL; *this = r; } LString &operator =(CFStringRef r) { if (r) { CFIndex length = CFStringGetLength(r); CFRange range = CFRangeMake(0, length); CFIndex usedBufLen = 0; CFIndex slen = CFStringGetBytes(r, range, kCFStringEncodingUTF8, '?', false, NULL, 0, &usedBufLen); if (Set(NULL, usedBufLen)) { slen = CFStringGetBytes( r, range, kCFStringEncodingUTF8, '?', false, (UInt8*)Str->Str, Str->Len, &usedBufLen); Str->Str[usedBufLen] = 0; // NULL terminate } } return *this; } CFStringRef CreateStringRef() { char *s = Get(); if (!s) return NULL; return CFStringCreateWithCString(kCFAllocatorDefault, s, kCFStringEncodingUTF8); } #ifdef __OBJC__ NSString *NsStr() { if (Str) return [[NSString alloc] initWithBytes:Str->Str length:Str->Len encoding:NSUTF8StringEncoding]; return nil; } bool operator=(NSString *const s) { *this = [s UTF8String]; return !IsEmpty(); } LString(NSString *const s) { Str = NULL; *this = [s UTF8String]; } #endif #endif };